From baa18b6ed4200aff869e78f2650123572b6a9ad6 Mon Sep 17 00:00:00 2001 From: Thorsten Blum Date: Wed, 26 Feb 2025 00:21:27 +0100 Subject: [PATCH 01/16] platform/x86: hp-bioscfg: Replace deprecated strncpy() with strscpy() MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit Since kstrtol() requires a NUL-terminated string as input and strncpy() is deprecated for NUL-terminated destination buffers, use strscpy() instead. Compile-tested only. Link: https://github.com/KSPP/linux/issues/90 Cc: linux-hardening@vger.kernel.org Signed-off-by: Thorsten Blum Link: https://lore.kernel.org/r/20250225232126.356274-2-thorsten.blum@linux.dev Reviewed-by: Ilpo Järvinen Signed-off-by: Ilpo Järvinen --- drivers/platform/x86/hp/hp-bioscfg/bioscfg.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/platform/x86/hp/hp-bioscfg/bioscfg.c b/drivers/platform/x86/hp/hp-bioscfg/bioscfg.c index 63c78b4d8258..13237890fc92 100644 --- a/drivers/platform/x86/hp/hp-bioscfg/bioscfg.c +++ b/drivers/platform/x86/hp/hp-bioscfg/bioscfg.c @@ -445,7 +445,7 @@ int hp_convert_hexstr_to_str(const char *input, u32 input_len, char **str, int * return -ENOMEM; for (i = 0; i < input_len; i += 5) { - strncpy(tmp, input + i, strlen(tmp)); + strscpy(tmp, input + i); if (kstrtol(tmp, 16, &ch) == 0) { // escape char if (ch == '\\' || -- 2.51.0 From 61250669eaa9fd480e0f1c3cec107924b6a06b46 Mon Sep 17 00:00:00 2001 From: Jackie Dong Date: Sat, 22 Feb 2025 19:45:31 +0800 Subject: [PATCH 02/16] platform/x86:lenovo-wmi-hotkey-utilities.c: Support for mic and audio mute LEDs MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit Implement Lenovo utility data WMI calls needed to make LEDs work on Ideapads that support this GUID. This enables the mic and audio LEDs to be updated correctly. Tested on below samples. ThinkBook 13X Gen4 IMH ThinkBook 14 G6 ABP ThinkBook 16p Gen4-21J8 ThinkBook 16 G8 IRL ThinkBook 16 G7+ ASP Signed-off-by: Jackie Dong Suggested-by: Mark Pearson Reviewed-by: Kurt Borja Reviewed-by: Ilpo Järvinen Reviewed-by: Armin Wolf Link: https://lore.kernel.org/r/20250222114532.4105-1-xy-jackie@139.com Signed-off-by: Ilpo Järvinen --- MAINTAINERS | 6 + drivers/platform/x86/Kconfig | 11 + drivers/platform/x86/Makefile | 1 + .../x86/lenovo-wmi-hotkey-utilities.c | 212 ++++++++++++++++++ 4 files changed, 230 insertions(+) create mode 100644 drivers/platform/x86/lenovo-wmi-hotkey-utilities.c diff --git a/MAINTAINERS b/MAINTAINERS index 0669b6433b1a..1afd30d00aec 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -13158,6 +13158,12 @@ S: Maintained W: http://legousb.sourceforge.net/ F: drivers/usb/misc/legousbtower.c +LENOVO WMI HOTKEY UTILITIES DRIVER +M: Jackie Dong +L: platform-driver-x86@vger.kernel.org +S: Maintained +F: drivers/platform/x86/lenovo-wmi-hotkey-utilities.c + LETSKETCH HID TABLET DRIVER M: Hans de Goede L: linux-input@vger.kernel.org diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig index 7e20a58861eb..43407e76476b 100644 --- a/drivers/platform/x86/Kconfig +++ b/drivers/platform/x86/Kconfig @@ -475,6 +475,17 @@ config IDEAPAD_LAPTOP This is a driver for Lenovo IdeaPad netbooks contains drivers for rfkill switch, hotkey, fan control and backlight control. +config LENOVO_WMI_HOTKEY_UTILITIES + tristate "Lenovo Hotkey Utility WMI extras driver" + depends on ACPI_WMI + select NEW_LEDS + select LEDS_CLASS + imply IDEAPAD_LAPTOP + help + This driver provides WMI support for Lenovo customized hotkeys function, + such as LED control for audio/mic mute event for Ideapad, YOGA, XiaoXin, + Gaming, ThinkBook and so on. + config LENOVO_YMC tristate "Lenovo Yoga Tablet Mode Control" depends on ACPI_WMI diff --git a/drivers/platform/x86/Makefile b/drivers/platform/x86/Makefile index 5f6307246e69..650dfbebb6c8 100644 --- a/drivers/platform/x86/Makefile +++ b/drivers/platform/x86/Makefile @@ -61,6 +61,7 @@ obj-$(CONFIG_UV_SYSFS) += uv_sysfs.o # IBM Thinkpad and Lenovo obj-$(CONFIG_IBM_RTL) += ibm_rtl.o obj-$(CONFIG_IDEAPAD_LAPTOP) += ideapad-laptop.o +obj-$(CONFIG_LENOVO_WMI_HOTKEY_UTILITIES) += lenovo-wmi-hotkey-utilities.o obj-$(CONFIG_LENOVO_YMC) += lenovo-ymc.o obj-$(CONFIG_SENSORS_HDAPS) += hdaps.o obj-$(CONFIG_THINKPAD_ACPI) += thinkpad_acpi.o diff --git a/drivers/platform/x86/lenovo-wmi-hotkey-utilities.c b/drivers/platform/x86/lenovo-wmi-hotkey-utilities.c new file mode 100644 index 000000000000..89153afd7015 --- /dev/null +++ b/drivers/platform/x86/lenovo-wmi-hotkey-utilities.c @@ -0,0 +1,212 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Lenovo Super Hotkey Utility WMI extras driver for Ideapad laptop + * + * Copyright (C) 2025 Lenovo + */ + +#include +#include +#include +#include +#include +#include + +/* Lenovo Super Hotkey WMI GUIDs */ +#define LUD_WMI_METHOD_GUID "CE6C0974-0407-4F50-88BA-4FC3B6559AD8" + +/* Lenovo Utility Data WMI method_id */ +#define WMI_LUD_GET_SUPPORT 1 +#define WMI_LUD_SET_FEATURE 2 + +#define WMI_LUD_GET_MICMUTE_LED_VER 20 +#define WMI_LUD_GET_AUDIOMUTE_LED_VER 26 + +#define WMI_LUD_SUPPORT_MICMUTE_LED_VER 25 +#define WMI_LUD_SUPPORT_AUDIOMUTE_LED_VER 27 + +/* Input parameters to mute/unmute audio LED and Mic LED */ +struct wmi_led_args { + u8 id; + u8 subid; + u16 value; +}; + +/* Values of input parameters to SetFeature of audio LED and Mic LED */ +enum hotkey_set_feature { + MIC_MUTE_LED_ON = 1, + MIC_MUTE_LED_OFF = 2, + AUDIO_MUTE_LED_ON = 4, + AUDIO_MUTE_LED_OFF = 5, +}; + +#define LSH_ACPI_LED_MAX 2 + +struct lenovo_super_hotkey_wmi_private { + struct led_classdev cdev[LSH_ACPI_LED_MAX]; + struct wmi_device *led_wdev; +}; + +enum mute_led_type { + MIC_MUTE, + AUDIO_MUTE, +}; + +static int lsh_wmi_mute_led_set(enum mute_led_type led_type, struct led_classdev *led_cdev, + enum led_brightness brightness) + +{ + struct lenovo_super_hotkey_wmi_private *wpriv = container_of(led_cdev, + struct lenovo_super_hotkey_wmi_private, cdev[led_type]); + struct wmi_led_args led_arg = {0, 0, 0}; + struct acpi_buffer input; + acpi_status status; + + switch (led_type) { + case MIC_MUTE: + led_arg.id = brightness == LED_ON ? MIC_MUTE_LED_ON : MIC_MUTE_LED_OFF; + break; + case AUDIO_MUTE: + led_arg.id = brightness == LED_ON ? AUDIO_MUTE_LED_ON : AUDIO_MUTE_LED_OFF; + break; + default: + return -EINVAL; + } + + input.length = sizeof(led_arg); + input.pointer = &led_arg; + status = wmidev_evaluate_method(wpriv->led_wdev, 0, WMI_LUD_SET_FEATURE, &input, NULL); + if (ACPI_FAILURE(status)) + return -EIO; + + return 0; +} + +static int lsh_wmi_audiomute_led_set(struct led_classdev *led_cdev, + enum led_brightness brightness) + +{ + return lsh_wmi_mute_led_set(AUDIO_MUTE, led_cdev, brightness); +} + +static int lsh_wmi_micmute_led_set(struct led_classdev *led_cdev, + enum led_brightness brightness) +{ + return lsh_wmi_mute_led_set(MIC_MUTE, led_cdev, brightness); +} + +static int lenovo_super_hotkey_wmi_led_init(enum mute_led_type led_type, struct device *dev) +{ + struct lenovo_super_hotkey_wmi_private *wpriv = dev_get_drvdata(dev); + struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL }; + struct acpi_buffer input; + int led_version, err = 0; + unsigned int wmiarg; + acpi_status status; + + switch (led_type) { + case MIC_MUTE: + wmiarg = WMI_LUD_GET_MICMUTE_LED_VER; + break; + case AUDIO_MUTE: + wmiarg = WMI_LUD_GET_AUDIOMUTE_LED_VER; + break; + default: + return -EINVAL; + } + + input.length = sizeof(wmiarg); + input.pointer = &wmiarg; + status = wmidev_evaluate_method(wpriv->led_wdev, 0, WMI_LUD_GET_SUPPORT, &input, &output); + if (ACPI_FAILURE(status)) + return -EIO; + + union acpi_object *obj __free(kfree) = output.pointer; + if (obj && obj->type == ACPI_TYPE_INTEGER) + led_version = obj->integer.value; + else + return -EIO; + + wpriv->cdev[led_type].max_brightness = LED_ON; + wpriv->cdev[led_type].flags = LED_CORE_SUSPENDRESUME; + + switch (led_type) { + case MIC_MUTE: + if (led_version != WMI_LUD_SUPPORT_MICMUTE_LED_VER) + return -EIO; + + wpriv->cdev[led_type].name = "platform::micmute"; + wpriv->cdev[led_type].brightness_set_blocking = &lsh_wmi_micmute_led_set; + wpriv->cdev[led_type].default_trigger = "audio-micmute"; + break; + case AUDIO_MUTE: + if (led_version != WMI_LUD_SUPPORT_AUDIOMUTE_LED_VER) + return -EIO; + + wpriv->cdev[led_type].name = "platform::mute"; + wpriv->cdev[led_type].brightness_set_blocking = &lsh_wmi_audiomute_led_set; + wpriv->cdev[led_type].default_trigger = "audio-mute"; + break; + default: + dev_err(dev, "Unknown LED type %d\n", led_type); + return -EINVAL; + } + + err = devm_led_classdev_register(dev, &wpriv->cdev[led_type]); + if (err < 0) { + dev_err(dev, "Could not register mute LED %d : %d\n", led_type, err); + return err; + } + return 0; +} + +static int lenovo_super_hotkey_wmi_leds_setup(struct device *dev) +{ + int err; + + err = lenovo_super_hotkey_wmi_led_init(MIC_MUTE, dev); + if (err) + return err; + + err = lenovo_super_hotkey_wmi_led_init(AUDIO_MUTE, dev); + if (err) + return err; + + return 0; +} + +static int lenovo_super_hotkey_wmi_probe(struct wmi_device *wdev, const void *context) +{ + struct lenovo_super_hotkey_wmi_private *wpriv; + + wpriv = devm_kzalloc(&wdev->dev, sizeof(*wpriv), GFP_KERNEL); + if (!wpriv) + return -ENOMEM; + + dev_set_drvdata(&wdev->dev, wpriv); + wpriv->led_wdev = wdev; + return lenovo_super_hotkey_wmi_leds_setup(&wdev->dev); +} + +static const struct wmi_device_id lenovo_super_hotkey_wmi_id_table[] = { + { LUD_WMI_METHOD_GUID, NULL }, /* Utility data */ + { } +}; + +MODULE_DEVICE_TABLE(wmi, lenovo_super_hotkey_wmi_id_table); + +static struct wmi_driver lenovo_wmi_hotkey_utilities_driver = { + .driver = { + .name = "lenovo_wmi_hotkey_utilities", + .probe_type = PROBE_PREFER_ASYNCHRONOUS + }, + .id_table = lenovo_super_hotkey_wmi_id_table, + .probe = lenovo_super_hotkey_wmi_probe, + .no_singleton = true, +}; + +module_wmi_driver(lenovo_wmi_hotkey_utilities_driver); + +MODULE_AUTHOR("Jackie Dong "); +MODULE_DESCRIPTION("Lenovo Super Hotkey Utility WMI extras driver"); +MODULE_LICENSE("GPL"); -- 2.51.0 From 886ca11a0c70efe5627a18557062e8a44370d78f Mon Sep 17 00:00:00 2001 From: =?utf8?q?Ilpo=20J=C3=A4rvinen?= Date: Tue, 4 Mar 2025 18:06:38 +0200 Subject: [PATCH 03/16] platform/x86: lenovo-yoga-tab2-pro-1380-fastcharger: Make symbol static MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit Sparse reports: lenovo-yoga-tab2-pro-1380-fastcharger.c:222:29: warning: symbol 'yt2_1380_fc_serdev_driver' was not declared. Should it be static? Fix that by making the symbol static. Fixes: b2ed33e8d486a ("platform/x86: Add lenovo-yoga-tab2-pro-1380-fastcharger driver") Reviewed-by: Mario Limonciello Reviewed-by: Hans de Goede Link: https://lore.kernel.org/r/20250304160639.4295-1-ilpo.jarvinen@linux.intel.com Signed-off-by: Ilpo Järvinen Reviewed-by: Ilpo Järvinen --- drivers/platform/x86/lenovo-yoga-tab2-pro-1380-fastcharger.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/platform/x86/lenovo-yoga-tab2-pro-1380-fastcharger.c b/drivers/platform/x86/lenovo-yoga-tab2-pro-1380-fastcharger.c index a96b215cd2c5..25933cd018d1 100644 --- a/drivers/platform/x86/lenovo-yoga-tab2-pro-1380-fastcharger.c +++ b/drivers/platform/x86/lenovo-yoga-tab2-pro-1380-fastcharger.c @@ -219,7 +219,7 @@ static int yt2_1380_fc_serdev_probe(struct serdev_device *serdev) return 0; } -struct serdev_device_driver yt2_1380_fc_serdev_driver = { +static struct serdev_device_driver yt2_1380_fc_serdev_driver = { .probe = yt2_1380_fc_serdev_probe, .driver = { .name = KBUILD_MODNAME, -- 2.51.0 From 4878e0b14c3e31a87ab147bd2dae443394cb5a2c Mon Sep 17 00:00:00 2001 From: =?utf8?q?Ilpo=20J=C3=A4rvinen?= Date: Tue, 4 Mar 2025 18:06:39 +0200 Subject: [PATCH 04/16] platform/x86: dell-uart-backlight: Make dell_uart_bl_serdev_driver static MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit Sparse reports: dell-uart-backlight.c:328:29: warning: symbol 'dell_uart_bl_serdev_driver' was not declared. Should it be static? Fix it by making the symbol static. Fixes: 484bae9e4d6ac ("platform/x86: Add new Dell UART backlight driver") Reviewed-by: Mario Limonciello Reviewed-by: Hans de Goede Link: https://lore.kernel.org/r/20250304160639.4295-2-ilpo.jarvinen@linux.intel.com Signed-off-by: Ilpo Järvinen Reviewed-by: Ilpo Järvinen --- drivers/platform/x86/dell/dell-uart-backlight.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/platform/x86/dell/dell-uart-backlight.c b/drivers/platform/x86/dell/dell-uart-backlight.c index 50002ef13d5d..8f868f845350 100644 --- a/drivers/platform/x86/dell/dell-uart-backlight.c +++ b/drivers/platform/x86/dell/dell-uart-backlight.c @@ -325,7 +325,7 @@ static int dell_uart_bl_serdev_probe(struct serdev_device *serdev) return PTR_ERR_OR_ZERO(dell_bl->bl); } -struct serdev_device_driver dell_uart_bl_serdev_driver = { +static struct serdev_device_driver dell_uart_bl_serdev_driver = { .probe = dell_uart_bl_serdev_probe, .driver = { .name = KBUILD_MODNAME, -- 2.51.0 From 7bb84ca9b8d0cfff76a6108636aec1a5a8cdcd49 Mon Sep 17 00:00:00 2001 From: Joshua Grisham Date: Mon, 3 Mar 2025 14:24:32 +0100 Subject: [PATCH 05/16] platform/x86: samsung-galaxybook: Fix block_recording not supported logic MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit Fixes logic error when block_recording is not supported but the fw attr was being added anyway (reported by GitHub user bbregeault). Tested myself on a Samsung Galaxy Book2 Pro (has block_recording) and by bbregeault on a Galaxy Book2 Business (does not have block_recording). Fixes: 56f529ce4370 ("platform/x86: samsung-galaxybook: Add samsung-galaxybook driver") Signed-off-by: Joshua Grisham Reviewed-by: Armin Wolf Link: https://lore.kernel.org/r/20250303132433.348653-1-josh@joshuagrisham.com Reviewed-by: Ilpo Järvinen Signed-off-by: Ilpo Järvinen --- drivers/platform/x86/samsung-galaxybook.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/drivers/platform/x86/samsung-galaxybook.c b/drivers/platform/x86/samsung-galaxybook.c index de1ed2dc6cca..5878a351993e 100644 --- a/drivers/platform/x86/samsung-galaxybook.c +++ b/drivers/platform/x86/samsung-galaxybook.c @@ -1100,11 +1100,13 @@ static int galaxybook_fw_attrs_init(struct samsung_galaxybook *galaxybook) } err = galaxybook_block_recording_init(galaxybook); - if (!err) - galaxybook->has_block_recording = true; - else if (err != GB_NOT_SUPPORTED) + if (err == GB_NOT_SUPPORTED) + return 0; + else if (err) return err; + galaxybook->has_block_recording = true; + return galaxybook_fw_attr_init(galaxybook, GB_ATTR_BLOCK_RECORDING, &block_recording_acpi_get, -- 2.51.0 From e57eabe2fb044950e6ffdfe01803895043dec0b7 Mon Sep 17 00:00:00 2001 From: Bartosz Golaszewski Date: Wed, 5 Mar 2025 11:31:46 +0100 Subject: [PATCH 06/16] platform/x86: thinkpad_acpi: check the return value of devm_mutex_init() MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit devm_mutex_init() can fail so check its return value. Fixes: 38b9ab80db31 ("platform/x86: thinkpad_acpi: Move subdriver initialization to tpacpi_pdriver's probe.") Signed-off-by: Bartosz Golaszewski Link: https://lore.kernel.org/r/20250305103146.53221-1-brgl@bgdev.pl Reviewed-by: Ilpo Järvinen Signed-off-by: Ilpo Järvinen --- drivers/platform/x86/thinkpad_acpi.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/platform/x86/thinkpad_acpi.c b/drivers/platform/x86/thinkpad_acpi.c index a7e82157bd67..4a581a6d6677 100644 --- a/drivers/platform/x86/thinkpad_acpi.c +++ b/drivers/platform/x86/thinkpad_acpi.c @@ -11849,7 +11849,9 @@ static int __init tpacpi_pdriver_probe(struct platform_device *pdev) { int ret; - devm_mutex_init(&pdev->dev, &tpacpi_inputdev_send_mutex); + ret = devm_mutex_init(&pdev->dev, &tpacpi_inputdev_send_mutex); + if (ret) + return ret; tpacpi_inputdev = devm_input_allocate_device(&pdev->dev); if (!tpacpi_inputdev) -- 2.51.0 From 7a248294a3145bc65eb0d8980a0a8edbb1b92db4 Mon Sep 17 00:00:00 2001 From: Armin Wolf Date: Wed, 5 Mar 2025 06:30:07 +0100 Subject: [PATCH 07/16] platform/x86: dell-ddv: Fix temperature calculation MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit On the Dell Inspiron 3505 the battery temperature is always 0.1 degrees larger than the temperature show inside the OEM application. Emulate this behaviour to avoid showing strange looking values like 29.1 degrees. Fixes: 0331b1b0ba653 ("platform/x86: dell-ddv: Fix temperature scaling") Signed-off-by: Armin Wolf Reviewed-by: Sebastian Reichel Link: https://lore.kernel.org/r/20250305053009.378609-2-W_Armin@gmx.de Reviewed-by: Ilpo Järvinen Signed-off-by: Ilpo Järvinen --- drivers/platform/x86/dell/dell-wmi-ddv.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/platform/x86/dell/dell-wmi-ddv.c b/drivers/platform/x86/dell/dell-wmi-ddv.c index e75cd6e1efe6..ab5f7d3ab824 100644 --- a/drivers/platform/x86/dell/dell-wmi-ddv.c +++ b/drivers/platform/x86/dell/dell-wmi-ddv.c @@ -665,8 +665,10 @@ static ssize_t temp_show(struct device *dev, struct device_attribute *attr, char if (ret < 0) return ret; - /* Use 2731 instead of 2731.5 to avoid unnecessary rounding */ - return sysfs_emit(buf, "%d\n", value - 2731); + /* Use 2732 instead of 2731.5 to avoid unnecessary rounding and to emulate + * the behaviour of the OEM application which seems to round down the result. + */ + return sysfs_emit(buf, "%d\n", value - 2732); } static ssize_t eppid_show(struct device *dev, struct device_attribute *attr, char *buf) -- 2.51.0 From 8dc3f0161e35d6ceb12de4a70cbed593e5b0583f Mon Sep 17 00:00:00 2001 From: Armin Wolf Date: Wed, 5 Mar 2025 06:30:08 +0100 Subject: [PATCH 08/16] platform/x86: dell-ddv: Use devm_battery_hook_register MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit Use devm_battery_hook_register() instead of manually calling devm_add_action_or_reset() to simplify the code. Signed-off-by: Armin Wolf Reviewed-by: Sebastian Reichel Link: https://lore.kernel.org/r/20250305053009.378609-3-W_Armin@gmx.de Reviewed-by: Ilpo Järvinen Signed-off-by: Ilpo Järvinen --- drivers/platform/x86/dell/dell-wmi-ddv.c | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/drivers/platform/x86/dell/dell-wmi-ddv.c b/drivers/platform/x86/dell/dell-wmi-ddv.c index ab5f7d3ab824..811cddab57fc 100644 --- a/drivers/platform/x86/dell/dell-wmi-ddv.c +++ b/drivers/platform/x86/dell/dell-wmi-ddv.c @@ -732,13 +732,6 @@ static int dell_wmi_ddv_remove_battery(struct power_supply *battery, struct acpi return 0; } -static void dell_wmi_ddv_battery_remove(void *data) -{ - struct acpi_battery_hook *hook = data; - - battery_hook_unregister(hook); -} - static int dell_wmi_ddv_battery_add(struct dell_wmi_ddv_data *data) { data->hook.name = "Dell DDV Battery Extension"; @@ -755,9 +748,7 @@ static int dell_wmi_ddv_battery_add(struct dell_wmi_ddv_data *data) data->eppid_attr.attr.mode = 0444; data->eppid_attr.show = eppid_show; - battery_hook_register(&data->hook); - - return devm_add_action_or_reset(&data->wdev->dev, dell_wmi_ddv_battery_remove, &data->hook); + return devm_battery_hook_register(&data->wdev->dev, &data->hook); } static int dell_wmi_ddv_buffer_read(struct seq_file *seq, enum dell_ddv_method method) -- 2.51.0 From 99923a0df7852311fa3d01eaddb430c958780143 Mon Sep 17 00:00:00 2001 From: Armin Wolf Date: Wed, 5 Mar 2025 06:30:09 +0100 Subject: [PATCH 09/16] platform/x86: dell-ddv: Use the power supply extension mechanism MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit Use the power supply extension mechanism for registering the battery temperature properties so that they can show up in the hwmon device associated with the ACPI battery. Signed-off-by: Armin Wolf Reviewed-by: Sebastian Reichel Link: https://lore.kernel.org/r/20250305053009.378609-4-W_Armin@gmx.de Reviewed-by: Ilpo Järvinen Signed-off-by: Ilpo Järvinen --- drivers/platform/x86/dell/dell-wmi-ddv.c | 75 ++++++++++++++---------- 1 file changed, 45 insertions(+), 30 deletions(-) diff --git a/drivers/platform/x86/dell/dell-wmi-ddv.c b/drivers/platform/x86/dell/dell-wmi-ddv.c index 811cddab57fc..f27739da380f 100644 --- a/drivers/platform/x86/dell/dell-wmi-ddv.c +++ b/drivers/platform/x86/dell/dell-wmi-ddv.c @@ -104,7 +104,6 @@ struct dell_wmi_ddv_sensors { struct dell_wmi_ddv_data { struct acpi_battery_hook hook; - struct device_attribute temp_attr; struct device_attribute eppid_attr; struct dell_wmi_ddv_sensors fans; struct dell_wmi_ddv_sensors temps; @@ -651,26 +650,6 @@ static int dell_wmi_ddv_battery_index(struct acpi_device *acpi_dev, u32 *index) return kstrtou32(uid_str, 10, index); } -static ssize_t temp_show(struct device *dev, struct device_attribute *attr, char *buf) -{ - struct dell_wmi_ddv_data *data = container_of(attr, struct dell_wmi_ddv_data, temp_attr); - u32 index, value; - int ret; - - ret = dell_wmi_ddv_battery_index(to_acpi_device(dev->parent), &index); - if (ret < 0) - return ret; - - ret = dell_wmi_ddv_query_integer(data->wdev, DELL_DDV_BATTERY_TEMPERATURE, index, &value); - if (ret < 0) - return ret; - - /* Use 2732 instead of 2731.5 to avoid unnecessary rounding and to emulate - * the behaviour of the OEM application which seems to round down the result. - */ - return sysfs_emit(buf, "%d\n", value - 2732); -} - static ssize_t eppid_show(struct device *dev, struct device_attribute *attr, char *buf) { struct dell_wmi_ddv_data *data = container_of(attr, struct dell_wmi_ddv_data, eppid_attr); @@ -697,6 +676,46 @@ static ssize_t eppid_show(struct device *dev, struct device_attribute *attr, cha return ret; } +static int dell_wmi_ddv_get_property(struct power_supply *psy, const struct power_supply_ext *ext, + void *drvdata, enum power_supply_property psp, + union power_supply_propval *val) +{ + struct dell_wmi_ddv_data *data = drvdata; + u32 index, value; + int ret; + + ret = dell_wmi_ddv_battery_index(to_acpi_device(psy->dev.parent), &index); + if (ret < 0) + return ret; + + switch (psp) { + case POWER_SUPPLY_PROP_TEMP: + ret = dell_wmi_ddv_query_integer(data->wdev, DELL_DDV_BATTERY_TEMPERATURE, index, + &value); + if (ret < 0) + return ret; + + /* Use 2732 instead of 2731.5 to avoid unnecessary rounding and to emulate + * the behaviour of the OEM application which seems to round down the result. + */ + val->intval = value - 2732; + return 0; + default: + return -EINVAL; + } +} + +static const enum power_supply_property dell_wmi_ddv_properties[] = { + POWER_SUPPLY_PROP_TEMP, +}; + +static const struct power_supply_ext dell_wmi_ddv_extension = { + .name = DRIVER_NAME, + .properties = dell_wmi_ddv_properties, + .num_properties = ARRAY_SIZE(dell_wmi_ddv_properties), + .get_property = dell_wmi_ddv_get_property, +}; + static int dell_wmi_ddv_add_battery(struct power_supply *battery, struct acpi_battery_hook *hook) { struct dell_wmi_ddv_data *data = container_of(hook, struct dell_wmi_ddv_data, hook); @@ -708,13 +727,14 @@ static int dell_wmi_ddv_add_battery(struct power_supply *battery, struct acpi_ba if (ret < 0) return 0; - ret = device_create_file(&battery->dev, &data->temp_attr); + ret = device_create_file(&battery->dev, &data->eppid_attr); if (ret < 0) return ret; - ret = device_create_file(&battery->dev, &data->eppid_attr); + ret = power_supply_register_extension(battery, &dell_wmi_ddv_extension, &data->wdev->dev, + data); if (ret < 0) { - device_remove_file(&battery->dev, &data->temp_attr); + device_remove_file(&battery->dev, &data->eppid_attr); return ret; } @@ -726,8 +746,8 @@ static int dell_wmi_ddv_remove_battery(struct power_supply *battery, struct acpi { struct dell_wmi_ddv_data *data = container_of(hook, struct dell_wmi_ddv_data, hook); - device_remove_file(&battery->dev, &data->temp_attr); device_remove_file(&battery->dev, &data->eppid_attr); + power_supply_unregister_extension(battery, &dell_wmi_ddv_extension); return 0; } @@ -738,11 +758,6 @@ static int dell_wmi_ddv_battery_add(struct dell_wmi_ddv_data *data) data->hook.add_battery = dell_wmi_ddv_add_battery; data->hook.remove_battery = dell_wmi_ddv_remove_battery; - sysfs_attr_init(&data->temp_attr.attr); - data->temp_attr.attr.name = "temp"; - data->temp_attr.attr.mode = 0444; - data->temp_attr.show = temp_show; - sysfs_attr_init(&data->eppid_attr.attr); data->eppid_attr.attr.name = "eppid"; data->eppid_attr.attr.mode = 0444; -- 2.51.0 From 351f3d9a05504a5c6d6be39eee8e17fbafa89df7 Mon Sep 17 00:00:00 2001 From: Shyam Sundar S K Date: Wed, 5 Mar 2025 19:56:12 +0530 Subject: [PATCH 10/16] platform/x86/amd/pmc: Notify user when platform does not support s0ix transition MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit Some of the AMD platforms do not support modern standby, so when such CPU ID is detected, a warning message will be displayed to the user. Reviewed-by: Mario Limonciello Co-developed-by: Sanket Goswami Signed-off-by: Sanket Goswami Signed-off-by: Shyam Sundar S K Link: https://lore.kernel.org/r/20250305142615.410178-1-Shyam-sundar.S-k@amd.com Reviewed-by: Ilpo Järvinen Signed-off-by: Ilpo Järvinen --- drivers/platform/x86/amd/pmc/pmc.c | 3 ++- drivers/platform/x86/amd/pmc/pmc.h | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/platform/x86/amd/pmc/pmc.c b/drivers/platform/x86/amd/pmc/pmc.c index e6124498b195..c7c7afb8a431 100644 --- a/drivers/platform/x86/amd/pmc/pmc.c +++ b/drivers/platform/x86/amd/pmc/pmc.c @@ -808,6 +808,7 @@ static const struct pci_device_id pmc_pci_ids[] = { { PCI_DEVICE(PCI_VENDOR_ID_AMD, AMD_CPU_ID_PCO) }, { PCI_DEVICE(PCI_VENDOR_ID_AMD, AMD_CPU_ID_RV) }, { PCI_DEVICE(PCI_VENDOR_ID_AMD, AMD_CPU_ID_SP) }, + { PCI_DEVICE(PCI_VENDOR_ID_AMD, AMD_CPU_ID_SHP) }, { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_1AH_M20H_ROOT) }, { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_1AH_M60H_ROOT) }, { } @@ -832,7 +833,7 @@ static int amd_pmc_probe(struct platform_device *pdev) dev->cpu_id = rdev->device; - if (dev->cpu_id == AMD_CPU_ID_SP) { + if (dev->cpu_id == AMD_CPU_ID_SP || dev->cpu_id == AMD_CPU_ID_SHP) { dev_warn_once(dev->dev, "S0i3 is not supported on this hardware\n"); err = -ENODEV; goto err_pci_dev_put; diff --git a/drivers/platform/x86/amd/pmc/pmc.h b/drivers/platform/x86/amd/pmc/pmc.h index f43f0253b0f5..8f39988ce7a3 100644 --- a/drivers/platform/x86/amd/pmc/pmc.h +++ b/drivers/platform/x86/amd/pmc/pmc.h @@ -79,6 +79,7 @@ void amd_mp2_stb_deinit(struct amd_pmc_dev *dev); #define AMD_CPU_ID_CB 0x14D8 #define AMD_CPU_ID_PS 0x14E8 #define AMD_CPU_ID_SP 0x14A4 +#define AMD_CPU_ID_SHP 0x153A #define PCI_DEVICE_ID_AMD_1AH_M20H_ROOT 0x1507 #define PCI_DEVICE_ID_AMD_1AH_M60H_ROOT 0x1122 #define PCI_DEVICE_ID_AMD_MP2_STB 0x172c -- 2.51.0 From e3f1fe98983ea801ac509f7bf3fb5da4a17e29b4 Mon Sep 17 00:00:00 2001 From: Shyam Sundar S K Date: Wed, 5 Mar 2025 19:56:13 +0530 Subject: [PATCH 11/16] platform/x86/amd/pmc: Move macros and structures to the PMC header file MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit To improve the code organization and readability, move the macros and structures from the AMD PMC driver to the PMC header file. Co-developed-by: Sanket Goswami Signed-off-by: Sanket Goswami Signed-off-by: Shyam Sundar S K Link: https://lore.kernel.org/r/20250305142615.410178-2-Shyam-sundar.S-k@amd.com Reviewed-by: Ilpo Järvinen Signed-off-by: Ilpo Järvinen --- drivers/platform/x86/amd/pmc/pmc.c | 81 ------------------------------ drivers/platform/x86/amd/pmc/pmc.h | 81 ++++++++++++++++++++++++++++++ 2 files changed, 81 insertions(+), 81 deletions(-) diff --git a/drivers/platform/x86/amd/pmc/pmc.c b/drivers/platform/x86/amd/pmc/pmc.c index c7c7afb8a431..742920530987 100644 --- a/drivers/platform/x86/amd/pmc/pmc.c +++ b/drivers/platform/x86/amd/pmc/pmc.c @@ -32,70 +32,6 @@ #include "pmc.h" -/* SMU communication registers */ -#define AMD_PMC_REGISTER_RESPONSE 0x980 -#define AMD_PMC_REGISTER_ARGUMENT 0x9BC - -/* PMC Scratch Registers */ -#define AMD_PMC_SCRATCH_REG_CZN 0x94 -#define AMD_PMC_SCRATCH_REG_YC 0xD14 -#define AMD_PMC_SCRATCH_REG_1AH 0xF14 - -/* STB Registers */ -#define AMD_PMC_STB_S2IDLE_PREPARE 0xC6000001 -#define AMD_PMC_STB_S2IDLE_RESTORE 0xC6000002 -#define AMD_PMC_STB_S2IDLE_CHECK 0xC6000003 - -/* Base address of SMU for mapping physical address to virtual address */ -#define AMD_PMC_MAPPING_SIZE 0x01000 -#define AMD_PMC_BASE_ADDR_OFFSET 0x10000 -#define AMD_PMC_BASE_ADDR_LO 0x13B102E8 -#define AMD_PMC_BASE_ADDR_HI 0x13B102EC -#define AMD_PMC_BASE_ADDR_LO_MASK GENMASK(15, 0) -#define AMD_PMC_BASE_ADDR_HI_MASK GENMASK(31, 20) - -/* SMU Response Codes */ -#define AMD_PMC_RESULT_OK 0x01 -#define AMD_PMC_RESULT_CMD_REJECT_BUSY 0xFC -#define AMD_PMC_RESULT_CMD_REJECT_PREREQ 0xFD -#define AMD_PMC_RESULT_CMD_UNKNOWN 0xFE -#define AMD_PMC_RESULT_FAILED 0xFF - -/* FCH SSC Registers */ -#define FCH_S0I3_ENTRY_TIME_L_OFFSET 0x30 -#define FCH_S0I3_ENTRY_TIME_H_OFFSET 0x34 -#define FCH_S0I3_EXIT_TIME_L_OFFSET 0x38 -#define FCH_S0I3_EXIT_TIME_H_OFFSET 0x3C -#define FCH_SSC_MAPPING_SIZE 0x800 -#define FCH_BASE_PHY_ADDR_LOW 0xFED81100 -#define FCH_BASE_PHY_ADDR_HIGH 0x00000000 - -/* SMU Message Definations */ -#define SMU_MSG_GETSMUVERSION 0x02 -#define SMU_MSG_LOG_GETDRAM_ADDR_HI 0x04 -#define SMU_MSG_LOG_GETDRAM_ADDR_LO 0x05 -#define SMU_MSG_LOG_START 0x06 -#define SMU_MSG_LOG_RESET 0x07 -#define SMU_MSG_LOG_DUMP_DATA 0x08 -#define SMU_MSG_GET_SUP_CONSTRAINTS 0x09 - -#define PMC_MSG_DELAY_MIN_US 50 -#define RESPONSE_REGISTER_LOOP_MAX 20000 - -#define DELAY_MIN_US 2000 -#define DELAY_MAX_US 3000 - -enum amd_pmc_def { - MSG_TEST = 0x01, - MSG_OS_HINT_PCO, - MSG_OS_HINT_RN, -}; - -struct amd_pmc_bit_map { - const char *name; - u32 bit_mask; -}; - static const struct amd_pmc_bit_map soc15_ip_blk_v2[] = { {"DISPLAY", BIT(0)}, {"CPU", BIT(1)}, @@ -165,23 +101,6 @@ static inline void amd_pmc_reg_write(struct amd_pmc_dev *dev, int reg_offset, u3 iowrite32(val, dev->regbase + reg_offset); } -struct smu_metrics { - u32 table_version; - u32 hint_count; - u32 s0i3_last_entry_status; - u32 timein_s0i2; - u64 timeentering_s0i3_lastcapture; - u64 timeentering_s0i3_totaltime; - u64 timeto_resume_to_os_lastcapture; - u64 timeto_resume_to_os_totaltime; - u64 timein_s0i3_lastcapture; - u64 timein_s0i3_totaltime; - u64 timein_swdrips_lastcapture; - u64 timein_swdrips_totaltime; - u64 timecondition_notmet_lastcapture[32]; - u64 timecondition_notmet_totaltime[32]; -} __packed; - static void amd_pmc_get_ip_info(struct amd_pmc_dev *dev) { switch (dev->cpu_id) { diff --git a/drivers/platform/x86/amd/pmc/pmc.h b/drivers/platform/x86/amd/pmc/pmc.h index 8f39988ce7a3..62f3e51020fd 100644 --- a/drivers/platform/x86/amd/pmc/pmc.h +++ b/drivers/platform/x86/amd/pmc/pmc.h @@ -14,6 +14,59 @@ #include #include +/* SMU communication registers */ +#define AMD_PMC_REGISTER_RESPONSE 0x980 +#define AMD_PMC_REGISTER_ARGUMENT 0x9BC + +/* PMC Scratch Registers */ +#define AMD_PMC_SCRATCH_REG_CZN 0x94 +#define AMD_PMC_SCRATCH_REG_YC 0xD14 +#define AMD_PMC_SCRATCH_REG_1AH 0xF14 + +/* STB Registers */ +#define AMD_PMC_STB_S2IDLE_PREPARE 0xC6000001 +#define AMD_PMC_STB_S2IDLE_RESTORE 0xC6000002 +#define AMD_PMC_STB_S2IDLE_CHECK 0xC6000003 + +/* Base address of SMU for mapping physical address to virtual address */ +#define AMD_PMC_MAPPING_SIZE 0x01000 +#define AMD_PMC_BASE_ADDR_OFFSET 0x10000 +#define AMD_PMC_BASE_ADDR_LO 0x13B102E8 +#define AMD_PMC_BASE_ADDR_HI 0x13B102EC +#define AMD_PMC_BASE_ADDR_LO_MASK GENMASK(15, 0) +#define AMD_PMC_BASE_ADDR_HI_MASK GENMASK(31, 20) + +/* SMU Response Codes */ +#define AMD_PMC_RESULT_OK 0x01 +#define AMD_PMC_RESULT_CMD_REJECT_BUSY 0xFC +#define AMD_PMC_RESULT_CMD_REJECT_PREREQ 0xFD +#define AMD_PMC_RESULT_CMD_UNKNOWN 0xFE +#define AMD_PMC_RESULT_FAILED 0xFF + +/* FCH SSC Registers */ +#define FCH_S0I3_ENTRY_TIME_L_OFFSET 0x30 +#define FCH_S0I3_ENTRY_TIME_H_OFFSET 0x34 +#define FCH_S0I3_EXIT_TIME_L_OFFSET 0x38 +#define FCH_S0I3_EXIT_TIME_H_OFFSET 0x3C +#define FCH_SSC_MAPPING_SIZE 0x800 +#define FCH_BASE_PHY_ADDR_LOW 0xFED81100 +#define FCH_BASE_PHY_ADDR_HIGH 0x00000000 + +/* SMU Message Definations */ +#define SMU_MSG_GETSMUVERSION 0x02 +#define SMU_MSG_LOG_GETDRAM_ADDR_HI 0x04 +#define SMU_MSG_LOG_GETDRAM_ADDR_LO 0x05 +#define SMU_MSG_LOG_START 0x06 +#define SMU_MSG_LOG_RESET 0x07 +#define SMU_MSG_LOG_DUMP_DATA 0x08 +#define SMU_MSG_GET_SUP_CONSTRAINTS 0x09 + +#define PMC_MSG_DELAY_MIN_US 50 +#define RESPONSE_REGISTER_LOOP_MAX 20000 + +#define DELAY_MIN_US 2000 +#define DELAY_MAX_US 3000 + enum s2d_msg_port { MSG_PORT_PMC, MSG_PORT_S2D, @@ -65,6 +118,34 @@ struct amd_pmc_dev { struct stb_arg stb_arg; }; +struct amd_pmc_bit_map { + const char *name; + u32 bit_mask; +}; + +struct smu_metrics { + u32 table_version; + u32 hint_count; + u32 s0i3_last_entry_status; + u32 timein_s0i2; + u64 timeentering_s0i3_lastcapture; + u64 timeentering_s0i3_totaltime; + u64 timeto_resume_to_os_lastcapture; + u64 timeto_resume_to_os_totaltime; + u64 timein_s0i3_lastcapture; + u64 timein_s0i3_totaltime; + u64 timein_swdrips_lastcapture; + u64 timein_swdrips_totaltime; + u64 timecondition_notmet_lastcapture[32]; + u64 timecondition_notmet_totaltime[32]; +} __packed; + +enum amd_pmc_def { + MSG_TEST = 0x01, + MSG_OS_HINT_PCO, + MSG_OS_HINT_RN, +}; + void amd_pmc_process_restore_quirks(struct amd_pmc_dev *dev); void amd_pmc_quirks_init(struct amd_pmc_dev *dev); void amd_mp2_stb_init(struct amd_pmc_dev *dev); -- 2.51.0 From c183cf6c5398f7b31b4fb67a5326f045c51d783a Mon Sep 17 00:00:00 2001 From: Shyam Sundar S K Date: Wed, 5 Mar 2025 19:56:14 +0530 Subject: [PATCH 12/16] platform/x86/amd/pmc: Remove unnecessary line breaks MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit Enhance code readability by fixing line break and blank line inconsistencies. Also make the return variable "rc" as function level local. Co-developed-by: Sanket Goswami Signed-off-by: Sanket Goswami Signed-off-by: Shyam Sundar S K Link: https://lore.kernel.org/r/20250305142615.410178-3-Shyam-sundar.S-k@amd.com Reviewed-by: Ilpo Järvinen Signed-off-by: Ilpo Järvinen --- drivers/platform/x86/amd/pmc/pmc.c | 24 +++++++++++------------- 1 file changed, 11 insertions(+), 13 deletions(-) diff --git a/drivers/platform/x86/amd/pmc/pmc.c b/drivers/platform/x86/amd/pmc/pmc.c index 742920530987..1ad3eb935404 100644 --- a/drivers/platform/x86/amd/pmc/pmc.c +++ b/drivers/platform/x86/amd/pmc/pmc.c @@ -166,11 +166,12 @@ static int amd_pmc_setup_smu_logging(struct amd_pmc_dev *dev) static int get_metrics_table(struct amd_pmc_dev *pdev, struct smu_metrics *table) { - if (!pdev->smu_virt_addr) { - int ret = amd_pmc_setup_smu_logging(pdev); + int rc; - if (ret) - return ret; + if (!pdev->smu_virt_addr) { + rc = amd_pmc_setup_smu_logging(pdev); + if (rc) + return rc; } if (pdev->cpu_id == AMD_CPU_ID_PCO) @@ -219,10 +220,10 @@ static ssize_t smu_fw_version_show(struct device *d, struct device_attribute *at char *buf) { struct amd_pmc_dev *dev = dev_get_drvdata(d); + int rc; if (!dev->major) { - int rc = amd_pmc_get_smu_version(dev); - + rc = amd_pmc_get_smu_version(dev); if (rc) return rc; } @@ -233,10 +234,10 @@ static ssize_t smu_program_show(struct device *d, struct device_attribute *attr, char *buf) { struct amd_pmc_dev *dev = dev_get_drvdata(d); + int rc; if (!dev->major) { - int rc = amd_pmc_get_smu_version(dev); - + rc = amd_pmc_get_smu_version(dev); if (rc) return rc; } @@ -697,14 +698,14 @@ static struct acpi_s2idle_dev_ops amd_pmc_s2idle_dev_ops = { static int amd_pmc_suspend_handler(struct device *dev) { struct amd_pmc_dev *pdev = dev_get_drvdata(dev); + int rc; /* * Must be called only from the same set of dev_pm_ops handlers * as i8042_pm_suspend() is called: currently just from .suspend. */ if (pdev->disable_8042_wakeup && !disable_workarounds) { - int rc = amd_pmc_wa_irq1(pdev); - + rc = amd_pmc_wa_irq1(pdev); if (rc) { dev_err(pdev->dev, "failed to adjust keyboard wakeup: %d\n", rc); return rc; @@ -743,7 +744,6 @@ static int amd_pmc_probe(struct platform_device *pdev) u32 val; dev->dev = &pdev->dev; - rdev = pci_get_domain_bus_and_slot(0, 0, PCI_DEVFN(0, 0)); if (!rdev || !pci_match_id(pmc_pci_ids, rdev)) { err = -ENODEV; @@ -751,7 +751,6 @@ static int amd_pmc_probe(struct platform_device *pdev) } dev->cpu_id = rdev->device; - if (dev->cpu_id == AMD_CPU_ID_SP || dev->cpu_id == AMD_CPU_ID_SHP) { dev_warn_once(dev->dev, "S0i3 is not supported on this hardware\n"); err = -ENODEV; @@ -767,7 +766,6 @@ static int amd_pmc_probe(struct platform_device *pdev) } base_addr_lo = val & AMD_PMC_BASE_ADDR_HI_MASK; - err = amd_smn_read(0, AMD_PMC_BASE_ADDR_HI, &val); if (err) { dev_err(dev->dev, "error reading 0x%x\n", AMD_PMC_BASE_ADDR_HI); -- 2.51.0 From 6ad1b2dc0f2a76b23a31fc7a52ed4ec06e4344a3 Mon Sep 17 00:00:00 2001 From: Shyam Sundar S K Date: Wed, 5 Mar 2025 19:56:15 +0530 Subject: [PATCH 13/16] platform/x86/amd/pmc: Use managed APIs for mutex MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit Adopt managed devm_* APIs for handling mutex creation and deletion, facilitating automatic resource cleanup. Co-developed-by: Sanket Goswami Signed-off-by: Sanket Goswami Signed-off-by: Shyam Sundar S K Link: https://lore.kernel.org/r/20250305142615.410178-4-Shyam-sundar.S-k@amd.com Reviewed-by: Ilpo Järvinen Signed-off-by: Ilpo Järvinen --- drivers/platform/x86/amd/pmc/pmc.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/platform/x86/amd/pmc/pmc.c b/drivers/platform/x86/amd/pmc/pmc.c index 1ad3eb935404..84bc47009e5f 100644 --- a/drivers/platform/x86/amd/pmc/pmc.c +++ b/drivers/platform/x86/amd/pmc/pmc.c @@ -783,7 +783,9 @@ static int amd_pmc_probe(struct platform_device *pdev) goto err_pci_dev_put; } - mutex_init(&dev->lock); + err = devm_mutex_init(dev->dev, &dev->lock); + if (err) + return err; /* Get num of IP blocks within the SoC */ amd_pmc_get_ip_info(dev); @@ -822,7 +824,6 @@ static void amd_pmc_remove(struct platform_device *pdev) pci_dev_put(dev->rdev); if (IS_ENABLED(CONFIG_AMD_MP2_STB)) amd_mp2_stb_deinit(dev); - mutex_destroy(&dev->lock); } static const struct acpi_device_id amd_pmc_acpi_ids[] = { -- 2.51.0 From d74e6e29d2b29919253f625f0c560f4ca2606900 Mon Sep 17 00:00:00 2001 From: Srinivas Pandruvada Date: Wed, 5 Mar 2025 10:53:53 -0800 Subject: [PATCH 14/16] tools/power/x86/intel-speed-select: Prevent increasing MAX_DIE_PER_PACKAGE In the function for_each_online_power_domain_in_set() to pick one CPU from each power domain a three-dimensional array is used, which assumes that a package contains multiple dies, that means the die_id from /sys/devices/system/cpu/cpu0/topology/die_id is only local to package. If it is not unique, still there will be no functional issues in the current generation of products, but the MAX_DIE_PER_PACKAGE will need to be increased for future products with many packages. After kernel version 6.9 die ID is unique system wide not per package. Even if the CPU topology has no dies, the ID will still increment across package. In this case the die_id in package 0 will be 0 and die_id in package 1 will be 1 in a 2-package system. Since the die count must be same for packages, just count the number of dies in package 0 and calculate die index from /sys/devices/system/cpu/cpu0/topology/die_id which is only unique within a package. In this way the array size "int cpus[MAX_PACKAGE_COUNT][MAX_DIE_PER_PACKAGE][MAX_PUNIT_PER_DIE]" doesn't have to increase with increasing package count. No functional change is expected. Signed-off-by: Srinivas Pandruvada --- tools/power/x86/intel-speed-select/isst-config.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/tools/power/x86/intel-speed-select/isst-config.c b/tools/power/x86/intel-speed-select/isst-config.c index fadfb02b8611..c319bfc3b7cb 100644 --- a/tools/power/x86/intel-speed-select/isst-config.c +++ b/tools/power/x86/intel-speed-select/isst-config.c @@ -48,6 +48,7 @@ static int fact_enable_fail; static int cgroupv2; static int max_die_id; static int max_punit_id; +static int max_die_id_package_0; /* clos related */ static int current_clos = -1; @@ -557,6 +558,8 @@ void for_each_online_power_domain_in_set(void (*callback)(struct isst_id *, void if (id.pkg < 0 || id.die < 0 || id.punit < 0) continue; + id.die = id.die % (max_die_id_package_0 + 1); + valid_mask[id.pkg][id.die] = 1; if (cpus[id.pkg][id.die][id.punit] == -1) @@ -568,7 +571,7 @@ void for_each_online_power_domain_in_set(void (*callback)(struct isst_id *, void for (k = 0; k < MAX_PUNIT_PER_DIE && k < MAX_DIE_PER_PACKAGE; k++) { id.cpu = cpus[i][k][k]; id.pkg = i; - id.die = k; + id.die = get_physical_die_id(id.cpu); id.punit = k; if (isst_is_punit_valid(&id)) callback(&id, arg1, arg2, arg3, arg4); @@ -586,7 +589,10 @@ void for_each_online_power_domain_in_set(void (*callback)(struct isst_id *, void for (k = 0; k < MAX_PUNIT_PER_DIE; k++) { id.cpu = cpus[i][j][k]; id.pkg = i; - id.die = j; + if (id.cpu >= 0) + id.die = get_physical_die_id(id.cpu); + else + id.die = id.pkg; id.punit = k; if (isst_is_punit_valid(&id)) callback(&id, arg1, arg2, arg3, arg4); @@ -815,6 +821,9 @@ static void create_cpu_map(void) if (max_punit_id < cpu_map[i].punit_id) max_punit_id = cpu_map[i].punit_id; + if (!pkg_id && max_die_id_package_0 < die_id) + max_die_id_package_0 = die_id; + debug_printf( "map logical_cpu:%d core: %d die:%d pkg:%d punit:%d punit_cpu:%d punit_core:%d\n", i, cpu_map[i].core_id, cpu_map[i].die_id, -- 2.51.0 From c49e805db30674293d6a595db52549addd9d611f Mon Sep 17 00:00:00 2001 From: Srinivas Pandruvada Date: Wed, 5 Mar 2025 11:01:56 -0800 Subject: [PATCH 15/16] tools/power/x86/intel-speed-select: Fix the condition to check multi die system Even when there is no die exported by CPUID leaf 0x1F, the kernel version after 6.9 will show non zero die_id in the sysfs. In that case maximum die_id can still match maximum power domain ID. So the condition to check if the power domain ID is same a die_id to prevent duplicate display doesn't hold true. The better condition is to check if the maximum die_id is more than the maximum package_id. If the die_id is exposed by CPUID leaf 0x1F, the maximum die_id will be more than maximum package_id. With this change tracking of max_punit_id is not used, so remove storing max_punit_id. Signed-off-by: Srinivas Pandruvada --- tools/power/x86/intel-speed-select/isst-config.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/tools/power/x86/intel-speed-select/isst-config.c b/tools/power/x86/intel-speed-select/isst-config.c index c319bfc3b7cb..545e9e88f998 100644 --- a/tools/power/x86/intel-speed-select/isst-config.c +++ b/tools/power/x86/intel-speed-select/isst-config.c @@ -46,8 +46,8 @@ static int force_online_offline; static int auto_mode; static int fact_enable_fail; static int cgroupv2; +static int max_pkg_id; static int max_die_id; -static int max_punit_id; static int max_die_id_package_0; /* clos related */ @@ -567,7 +567,7 @@ void for_each_online_power_domain_in_set(void (*callback)(struct isst_id *, void } for (i = 0; i < MAX_PACKAGE_COUNT; i++) { - if (max_die_id == max_punit_id) { + if (max_die_id > max_pkg_id) { for (k = 0; k < MAX_PUNIT_PER_DIE && k < MAX_DIE_PER_PACKAGE; k++) { id.cpu = cpus[i][k][k]; id.pkg = i; @@ -794,6 +794,8 @@ static void create_cpu_map(void) cpu_map[i].die_id = die_id; cpu_map[i].core_id = core_id; + if (max_pkg_id < pkg_id) + max_pkg_id = pkg_id; punit_id = 0; @@ -818,9 +820,6 @@ static void create_cpu_map(void) if (max_die_id < die_id) max_die_id = die_id; - if (max_punit_id < cpu_map[i].punit_id) - max_punit_id = cpu_map[i].punit_id; - if (!pkg_id && max_die_id_package_0 < die_id) max_die_id_package_0 = die_id; -- 2.51.0 From 7ad93737ddf355d57cbdd2e769fc6a0802019b46 Mon Sep 17 00:00:00 2001 From: Srinivas Pandruvada Date: Wed, 5 Mar 2025 11:03:15 -0800 Subject: [PATCH 16/16] tools/power/x86/intel-speed-select: Die ID for IO dies Instead of displaying "-1" for IO dies, display "IO". Signed-off-by: Srinivas Pandruvada --- tools/power/x86/intel-speed-select/isst-display.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/tools/power/x86/intel-speed-select/isst-display.c b/tools/power/x86/intel-speed-select/isst-display.c index 07ebd08f3202..da5a59a4c545 100644 --- a/tools/power/x86/intel-speed-select/isst-display.c +++ b/tools/power/x86/intel-speed-select/isst-display.c @@ -173,7 +173,11 @@ static int print_package_info(struct isst_id *id, FILE *outf) if (out_format_is_json()) { if (api_version() > 1) { - if (id->cpu < 0) + if (id->die < 0 && id->cpu < 0) + snprintf(header, sizeof(header), + "package-%d:die-IO:powerdomain-%d:cpu-None", + id->pkg, id->punit); + else if (id->cpu < 0) snprintf(header, sizeof(header), "package-%d:die-%d:powerdomain-%d:cpu-None", id->pkg, id->die, id->punit); @@ -190,7 +194,10 @@ static int print_package_info(struct isst_id *id, FILE *outf) } snprintf(header, sizeof(header), "package-%d", id->pkg); format_and_print(outf, level++, header, NULL); - snprintf(header, sizeof(header), "die-%d", id->die); + if (id->die < 0) + snprintf(header, sizeof(header), "die-IO"); + else + snprintf(header, sizeof(header), "die-%d", id->die); format_and_print(outf, level++, header, NULL); if (api_version() > 1) { snprintf(header, sizeof(header), "powerdomain-%d", id->punit); -- 2.51.0