From 890f658c101df5842ce8aaec1b0833cf1ba37eb3 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Wed, 19 Jul 2017 16:07:19 +0300 Subject: [PATCH 01/23] platform/x86: peaq-wmi: silence a static checker warning There is a harmless static checker warning here that unsigned values are always >= 0. The code looks like: if (peaq_ignore_events_counter && --peaq_ignore_events_counter >= 0) The first part of the condition ensures that we never wrap around so the code works as intended. I've tweaked it slightly to avoid the warning. Signed-off-by: Dan Carpenter Signed-off-by: Andy Shevchenko --- drivers/platform/x86/peaq-wmi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/platform/x86/peaq-wmi.c b/drivers/platform/x86/peaq-wmi.c index 77d1f90b0794..c68bd76954fd 100644 --- a/drivers/platform/x86/peaq-wmi.c +++ b/drivers/platform/x86/peaq-wmi.c @@ -51,7 +51,7 @@ static void peaq_wmi_poll(struct input_polled_dev *dev) return; } - if (peaq_ignore_events_counter && --peaq_ignore_events_counter >= 0) + if (peaq_ignore_events_counter && peaq_ignore_events_counter--) return; if (obj.integer.value) { From 6d8d556262965bf7133b2540f293eaa1bc1e40d1 Mon Sep 17 00:00:00 2001 From: "Gustavo A. R. Silva" Date: Tue, 18 Jul 2017 16:49:37 -0500 Subject: [PATCH 02/23] platform/x86: msi-wmi: remove unnecessary static in msi_wmi_notify() Remove unnecessary static on local variable _key_. Such variable is initialized before being used, on every execution path throughout the function. The static has no benefit and, removing it reduces the object file size. This issue was detected using Coccinelle and the following semantic patch: https://github.com/GustavoARSilva/coccinelle/blob/master/static/static_unused.cocci In the following log you can see a significant difference in the object file size. Also, there is a significant difference in the bss segment. This log is the output of the size command, before and after the code change: before: text data bss dec hex filename 6530 3736 320 10586 295a drivers/platform/x86/msi-wmi.o after: text data bss dec hex filename 6494 3648 256 10398 289e drivers/platform/x86/msi-wmi.o Signed-off-by: Gustavo A. R. Silva Signed-off-by: Andy Shevchenko --- drivers/platform/x86/msi-wmi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/platform/x86/msi-wmi.c b/drivers/platform/x86/msi-wmi.c index f6209b739ec0..620138236c89 100644 --- a/drivers/platform/x86/msi-wmi.c +++ b/drivers/platform/x86/msi-wmi.c @@ -184,7 +184,7 @@ static const struct backlight_ops msi_backlight_ops = { static void msi_wmi_notify(u32 value, void *context) { struct acpi_buffer response = { ACPI_ALLOCATE_BUFFER, NULL }; - static struct key_entry *key; + struct key_entry *key; union acpi_object *obj; acpi_status status; From cd0223c64c604b2aff2aa7b7576ef7693b0b10ae Mon Sep 17 00:00:00 2001 From: "Gustavo A. R. Silva" Date: Tue, 18 Jul 2017 17:01:45 -0500 Subject: [PATCH 03/23] platform/x86: ibm_rtl: remove unnecessary static in ibm_rtl_write() Remove unnecessary static on local variable cmd_port_val. Such variable is initialized before being used, on every execution path throughout the function. The static has no benefit and, removing it reduces the object file size. This issue was detected using Coccinelle and the following semantic patch: https://github.com/GustavoARSilva/coccinelle/blob/master/static/static_unused.cocci In the following log you can see a difference in the object file size. This log is the output of the size command, before and after the code change: before: text data bss dec hex filename 3932 3440 512 7884 1ecc drivers/platform/x86/ibm_rtl.o after: text data bss dec hex filename 3887 3384 448 7719 1e27 drivers/platform/x86/ibm_rtl.o Signed-off-by: Gustavo A. R. Silva Signed-off-by: Andy Shevchenko --- drivers/platform/x86/ibm_rtl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/platform/x86/ibm_rtl.c b/drivers/platform/x86/ibm_rtl.c index c62e5e11ca4b..610ac8391caa 100644 --- a/drivers/platform/x86/ibm_rtl.c +++ b/drivers/platform/x86/ibm_rtl.c @@ -103,7 +103,7 @@ static void rtl_port_unmap(void __iomem *addr) static int ibm_rtl_write(u8 value) { int ret = 0, count = 0; - static u32 cmd_port_val; + u32 cmd_port_val; RTL_DEBUG("%s(%d)\n", __func__, value); From 22ff1a362df262dcc56ce282d9d658350c1fc036 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Thu, 20 Jul 2017 18:00:51 +0200 Subject: [PATCH 04/23] platform/x86: alienware-wmi: fix format string overflow warning gcc points out a possible format string overflow for a large value of 'zone': drivers/platform/x86/alienware-wmi.c: In function 'alienware_wmi_init': drivers/platform/x86/alienware-wmi.c:461:24: error: '%02X' directive writing between 2 and 8 bytes into a region of size 6 [-Werror=format-overflow=] sprintf(buffer, "zone%02X", i); ^~~~ drivers/platform/x86/alienware-wmi.c:461:19: note: directive argument in the range [0, 2147483646] sprintf(buffer, "zone%02X", i); ^~~~~~~~~~ drivers/platform/x86/alienware-wmi.c:461:3: note: 'sprintf' output between 7 and 13 bytes into a destination of size 10 This replaces the 'int' variable with an 'u8' to make sure it always fits, renaming the variable to 'zone' for clarity. Unfortunately, gcc-7.1.1 still warns about it with that change, which seems to be unintended by the gcc developers. I have opened a bug against gcc with a reduced test case. As a workaround, I also change the format string to use "%02hhX", which shuts up the warning in that version. Link: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=81483 Link: https://patchwork.ozlabs.org/patch/788415/ Suggested-by: Andy Shevchenko Signed-off-by: Arnd Bergmann [andy: added empty lines after u8 zone; definitions] Signed-off-by: Andy Shevchenko --- drivers/platform/x86/alienware-wmi.c | 40 +++++++++++++++------------- 1 file changed, 21 insertions(+), 19 deletions(-) diff --git a/drivers/platform/x86/alienware-wmi.c b/drivers/platform/x86/alienware-wmi.c index 0831b428c217..4eb8e1a472b2 100644 --- a/drivers/platform/x86/alienware-wmi.c +++ b/drivers/platform/x86/alienware-wmi.c @@ -255,12 +255,13 @@ static int parse_rgb(const char *buf, struct platform_zone *zone) static struct platform_zone *match_zone(struct device_attribute *attr) { - int i; - for (i = 0; i < quirks->num_zones; i++) { - if ((struct device_attribute *)zone_data[i].attr == attr) { + u8 zone; + + for (zone = 0; zone < quirks->num_zones; zone++) { + if ((struct device_attribute *)zone_data[zone].attr == attr) { pr_debug("alienware-wmi: matched zone location: %d\n", - zone_data[i].location); - return &zone_data[i]; + zone_data[zone].location); + return &zone_data[zone]; } } return NULL; @@ -420,7 +421,7 @@ static DEVICE_ATTR(lighting_control_state, 0644, show_control_state, static int alienware_zone_init(struct platform_device *dev) { - int i; + u8 zone; char buffer[10]; char *name; @@ -457,19 +458,19 @@ static int alienware_zone_init(struct platform_device *dev) if (!zone_data) return -ENOMEM; - for (i = 0; i < quirks->num_zones; i++) { - sprintf(buffer, "zone%02X", i); + for (zone = 0; zone < quirks->num_zones; zone++) { + sprintf(buffer, "zone%02hhX", zone); name = kstrdup(buffer, GFP_KERNEL); if (name == NULL) return 1; - sysfs_attr_init(&zone_dev_attrs[i].attr); - zone_dev_attrs[i].attr.name = name; - zone_dev_attrs[i].attr.mode = 0644; - zone_dev_attrs[i].show = zone_show; - zone_dev_attrs[i].store = zone_set; - zone_data[i].location = i; - zone_attrs[i] = &zone_dev_attrs[i].attr; - zone_data[i].attr = &zone_dev_attrs[i]; + sysfs_attr_init(&zone_dev_attrs[zone].attr); + zone_dev_attrs[zone].attr.name = name; + zone_dev_attrs[zone].attr.mode = 0644; + zone_dev_attrs[zone].show = zone_show; + zone_dev_attrs[zone].store = zone_set; + zone_data[zone].location = zone; + zone_attrs[zone] = &zone_dev_attrs[zone].attr; + zone_data[zone].attr = &zone_dev_attrs[zone]; } zone_attrs[quirks->num_zones] = &dev_attr_lighting_control_state.attr; zone_attribute_group.attrs = zone_attrs; @@ -481,12 +482,13 @@ static int alienware_zone_init(struct platform_device *dev) static void alienware_zone_exit(struct platform_device *dev) { + u8 zone; + sysfs_remove_group(&dev->dev.kobj, &zone_attribute_group); led_classdev_unregister(&global_led); if (zone_dev_attrs) { - int i; - for (i = 0; i < quirks->num_zones; i++) - kfree(zone_dev_attrs[i].attr.name); + for (zone = 0; zone < quirks->num_zones; zone++) + kfree(zone_dev_attrs[zone].attr.name); } kfree(zone_dev_attrs); kfree(zone_data); From 54949a606cd74c9d6cbeb3198dc05b937b2500bf Mon Sep 17 00:00:00 2001 From: Rajneesh Bhardwaj Date: Thu, 20 Jul 2017 19:51:13 +0530 Subject: [PATCH 05/23] platform/x86: intel_telemetry: Add GLK PSS Event Table Some of the Primary Subsystem events differ on Gemini Lake but the IOSS events remain same. This patch adds the updated PSS event table to enable Telemetry driver on Gemini Lake. Signed-off-by: Shanth Murthy Signed-off-by: Rajneesh Bhardwaj Reviewed-by: Souvik K Chakravarty Signed-off-by: Andy Shevchenko --- .../platform/x86/intel_telemetry_debugfs.c | 1 + drivers/platform/x86/intel_telemetry_pltdrv.c | 35 +++++++++++++++++++ 2 files changed, 36 insertions(+) diff --git a/drivers/platform/x86/intel_telemetry_debugfs.c b/drivers/platform/x86/intel_telemetry_debugfs.c index cd21df982abd..d4fc42b4cbeb 100644 --- a/drivers/platform/x86/intel_telemetry_debugfs.c +++ b/drivers/platform/x86/intel_telemetry_debugfs.c @@ -331,6 +331,7 @@ static struct telemetry_debugfs_conf telem_apl_debugfs_conf = { static const struct x86_cpu_id telemetry_debugfs_cpu_ids[] = { TELEM_DEBUGFS_CPU(INTEL_FAM6_ATOM_GOLDMONT, telem_apl_debugfs_conf), + TELEM_DEBUGFS_CPU(INTEL_FAM6_ATOM_GEMINI_LAKE, telem_apl_debugfs_conf), {} }; diff --git a/drivers/platform/x86/intel_telemetry_pltdrv.c b/drivers/platform/x86/intel_telemetry_pltdrv.c index 6ebdbd2b04fc..6393b3b1d5a6 100644 --- a/drivers/platform/x86/intel_telemetry_pltdrv.c +++ b/drivers/platform/x86/intel_telemetry_pltdrv.c @@ -153,6 +153,30 @@ static struct telemetry_evtmap {"PC2_AND_MEM_SHALLOW_IDLE_RES", 0x1D40}, }; +static struct telemetry_evtmap + telemetry_glk_pss_default_events[TELEM_MAX_OS_ALLOCATED_EVENTS] = { + {"IA_CORE0_C6_RES", 0x0400}, + {"IA_CORE0_C6_CTR", 0x0000}, + {"IA_MODULE0_C7_RES", 0x0410}, + {"IA_MODULE0_C7_CTR", 0x000C}, + {"IA_C0_RES", 0x0805}, + {"PCS_LTR", 0x2801}, + {"PSTATES", 0x2802}, + {"SOC_S0I3_RES", 0x0407}, + {"SOC_S0I3_CTR", 0x0008}, + {"PCS_S0I3_CTR", 0x0007}, + {"PCS_C1E_RES", 0x0414}, + {"PCS_IDLE_STATUS", 0x2806}, + {"IA_PERF_LIMITS", 0x280B}, + {"GT_PERF_LIMITS", 0x280C}, + {"PCS_WAKEUP_S0IX_CTR", 0x0025}, + {"PCS_IDLE_BLOCKED", 0x2C00}, + {"PCS_S0IX_BLOCKED", 0x2C01}, + {"PCS_S0IX_WAKE_REASONS", 0x2C02}, + {"PCS_LTR_BLOCKING", 0x2C03}, + {"PC2_AND_MEM_SHALLOW_IDLE_RES", 0x1D40}, +}; + /* APL specific Data */ static struct telemetry_plt_config telem_apl_config = { .pss_config = { @@ -163,8 +187,19 @@ static struct telemetry_plt_config telem_apl_config = { }, }; +/* GLK specific Data */ +static struct telemetry_plt_config telem_glk_config = { + .pss_config = { + .telem_evts = telemetry_glk_pss_default_events, + }, + .ioss_config = { + .telem_evts = telemetry_apl_ioss_default_events, + }, +}; + static const struct x86_cpu_id telemetry_cpu_ids[] = { TELEM_CPU(INTEL_FAM6_ATOM_GOLDMONT, telem_apl_config), + TELEM_CPU(INTEL_FAM6_ATOM_GEMINI_LAKE, telem_glk_config), {} }; From 95a5af1838129aeb1678775928a1d714b62b4c1a Mon Sep 17 00:00:00 2001 From: Rajneesh Bhardwaj Date: Thu, 20 Jul 2017 19:51:14 +0530 Subject: [PATCH 06/23] platform/x86: intel_telemetry: remove redundant macro definition Telemetry driver includes intel_telemetry.h which defines TELEM_MAX_OS_ALLOCATED_EVENTS already. Signed-off-by: Rajneesh Bhardwaj Reviewed-by: Souvik K Chakravarty Signed-off-by: Andy Shevchenko --- drivers/platform/x86/intel_telemetry_pltdrv.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/platform/x86/intel_telemetry_pltdrv.c b/drivers/platform/x86/intel_telemetry_pltdrv.c index 6393b3b1d5a6..e0424d5a795a 100644 --- a/drivers/platform/x86/intel_telemetry_pltdrv.c +++ b/drivers/platform/x86/intel_telemetry_pltdrv.c @@ -46,7 +46,6 @@ #define TELEM_SAMPLING_DEFAULT_PERIOD 0xD #define TELEM_MAX_EVENTS_SRAM 28 -#define TELEM_MAX_OS_ALLOCATED_EVENTS 20 #define TELEM_SSRAM_STARTTIME_OFFSET 8 #define TELEM_SSRAM_EVTLOG_OFFSET 16 From baa5480b0509d8af06c37fff03edbb5a6815cef1 Mon Sep 17 00:00:00 2001 From: Andy Lutomirski Date: Tue, 1 Aug 2017 08:37:26 -0700 Subject: [PATCH 07/23] platform/x86: dell-wmi: Fix driver interface version query MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When I converted dell-wmi to the new bus infrastructure, I left the call to dell_wmi_check_descriptor_buffer() in dell_wmi_init(). This could cause two problems: - An error message when loading the driver on a system without dell-wmi. We'd try to read the event descriptor even if the WMI GUID wasn't there. - A possible race if dell-wmi was loaded manually before wmi was fully initialized. Fix it by moving the call to the probe function where it belongs. Fixes: bff589be59c5 ("platform/x86: dell-wmi: Convert to the WMI bus infrastructure") Signed-off-by: Andy Lutomirski Reviewed-by: Pali Rohár Signed-off-by: Darren Hart (VMware) --- drivers/platform/x86/dell-wmi.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/drivers/platform/x86/dell-wmi.c b/drivers/platform/x86/dell-wmi.c index f8978464df31..dad8f4afa17c 100644 --- a/drivers/platform/x86/dell-wmi.c +++ b/drivers/platform/x86/dell-wmi.c @@ -626,7 +626,7 @@ static void dell_wmi_input_destroy(struct wmi_device *wdev) * WMI Interface Version 8 4 * WMI buffer length 12 4 4096 */ -static int __init dell_wmi_check_descriptor_buffer(void) +static int dell_wmi_check_descriptor_buffer(void) { struct acpi_buffer out = { ACPI_ALLOCATE_BUFFER, NULL }; union acpi_object *obj; @@ -717,9 +717,15 @@ static int dell_wmi_events_set_enabled(bool enable) static int dell_wmi_probe(struct wmi_device *wdev) { + int err; + struct dell_wmi_priv *priv = devm_kzalloc( &wdev->dev, sizeof(struct dell_wmi_priv), GFP_KERNEL); + err = dell_wmi_check_descriptor_buffer(); + if (err) + return err; + dev_set_drvdata(&wdev->dev, priv); return dell_wmi_input_setup(wdev); @@ -749,10 +755,6 @@ static int __init dell_wmi_init(void) { int err; - err = dell_wmi_check_descriptor_buffer(); - if (err) - return err; - dmi_check_system(dell_wmi_smbios_list); if (wmi_requires_smbios_request) { From c801603e6d0c1bf87930402462d2e4185b1e9264 Mon Sep 17 00:00:00 2001 From: Mario Limonciello Date: Fri, 4 Aug 2017 12:00:06 -0500 Subject: [PATCH 08/23] platform/x86: intel-vbtn: match power button on press rather than release This fixes a problem where the system gets stuck in a loop unable to wakeup via power button in s2idle. The problem happens because: - press power button: - system emits 0xc0 (power press), event ignored - system emits 0xc1 (power release), event processed, emited as KEY_POWER - set wakeup_mode to true - system goes to s2idle - press power button - system emits 0xc0 (power press), wakeup_mode is true, system wakes - system emits 0xc1 (power release), event processed, emited as KEY_POWER - system goes to s2idle again To avoid this situation, process the presses (which matches what intel-hid does too). Verified on an Dell XPS 9365 Signed-off-by: Mario Limonciello Acked-by: Rafael J. Wysocki Signed-off-by: Darren Hart (VMware) --- drivers/platform/x86/intel-vbtn.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/platform/x86/intel-vbtn.c b/drivers/platform/x86/intel-vbtn.c index 61f106377661..480926786cb8 100644 --- a/drivers/platform/x86/intel-vbtn.c +++ b/drivers/platform/x86/intel-vbtn.c @@ -36,8 +36,8 @@ static const struct acpi_device_id intel_vbtn_ids[] = { /* In theory, these are HID usages. */ static const struct key_entry intel_vbtn_keymap[] = { - { KE_IGNORE, 0xC0, { KEY_POWER } }, /* power key press */ - { KE_KEY, 0xC1, { KEY_POWER } }, /* power key release */ + { KE_KEY, 0xC0, { KEY_POWER } }, /* power key press */ + { KE_IGNORE, 0xC1, { KEY_POWER } }, /* power key release */ { KE_KEY, 0xC4, { KEY_VOLUMEUP } }, /* volume-up key press */ { KE_IGNORE, 0xC5, { KEY_VOLUMEUP } }, /* volume-up key release */ { KE_KEY, 0xC6, { KEY_VOLUMEDOWN } }, /* volume-down key press */ From fbcb4a578bc29cfad82f838247ff1c2869433759 Mon Sep 17 00:00:00 2001 From: Paulo Alcantara Date: Sun, 30 Jul 2017 09:47:55 -0300 Subject: [PATCH 09/23] platform/x86: hp-wmi: Correctly determine method id in WMI calls The WMI queries are performed by evaluating the WMPV() method from ACPI DSDT tables, and it takes three arguments: instance index, method id and input data (buffer). Currently the method id is hard-coded to 0x3 in hp_wmi_perform_query() which means that it will perform WMI calls that expect an output data of size 0x80 (128). The output size is usually OK for the WMI queries we perform, however it would be better to pick the correct one before evaluating the WMI method. Which correct method id to choose can be figured out by looking at the following ASL code from WVPI() method: ... Name (PVSZ, Package (0x05) { Zero, 0x04, 0x80, 0x0400, 0x1000 }) Store (Zero, Local0) If (LAnd (LGreaterEqual (Arg1, One), LLessEqual (Arg1, 0x05))) { Store (DerefOf (Index (PVSZ, Subtract (Arg1, One))), Local0) } ... Arg1 is the method id and PVSZ is the package used to index the corresponding output size; 1 -> 0, 2 -> 4, 3 -> 128, 4 -> 1024, 5 -> 4096. This patch maps the output size passed in hp_wmi_perform_query() to the correct method id before evaluating the WMI method. Signed-off-by: Paulo Alcantara Signed-off-by: Andy Shevchenko --- drivers/platform/x86/hp-wmi.c | 23 ++++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/drivers/platform/x86/hp-wmi.c b/drivers/platform/x86/hp-wmi.c index 0df4209648d1..c2ca5c22f8d2 100644 --- a/drivers/platform/x86/hp-wmi.c +++ b/drivers/platform/x86/hp-wmi.c @@ -188,6 +188,22 @@ struct rfkill2_device { static int rfkill2_count; static struct rfkill2_device rfkill2[HPWMI_MAX_RFKILL2_DEVICES]; +/* map output size to the corresponding WMI method id */ +static inline int encode_outsize_for_pvsz(int outsize) +{ + if (outsize > 4096) + return -EINVAL; + if (outsize > 1024) + return 5; + if (outsize > 128) + return 4; + if (outsize > 4) + return 3; + if (outsize > 0) + return 2; + return 1; +} + /* * hp_wmi_perform_query * @@ -211,6 +227,7 @@ static struct rfkill2_device rfkill2[HPWMI_MAX_RFKILL2_DEVICES]; static int hp_wmi_perform_query(int query, enum hp_wmi_command command, void *buffer, int insize, int outsize) { + int mid; struct bios_return *bios_return; int actual_outsize; union acpi_object *obj; @@ -225,11 +242,15 @@ static int hp_wmi_perform_query(int query, enum hp_wmi_command command, struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL }; int ret = 0; + mid = encode_outsize_for_pvsz(outsize); + if (WARN_ON(mid < 0)) + return mid; + if (WARN_ON(insize > sizeof(args.data))) return -EINVAL; memcpy(&args.data, buffer, insize); - wmi_evaluate_method(HPWMI_BIOS_GUID, 0, 0x3, &input, &output); + wmi_evaluate_method(HPWMI_BIOS_GUID, 0, mid, &input, &output); obj = output.pointer; From 50c55168d78eac9ef49a0953155b216bc685062a Mon Sep 17 00:00:00 2001 From: Paulo Alcantara Date: Sun, 30 Jul 2017 12:40:50 -0300 Subject: [PATCH 10/23] platform/x86: hp-wmi: Remove unused macro helper The commit d8193cff3390 ("platform/x86: hp-wmi: Standardize enum usage for constants") introduced a macro that had been never used. Remove it. Signed-off-by: Paulo Alcantara [andy wrote commit message] Signed-off-by: Andy Shevchenko --- drivers/platform/x86/hp-wmi.c | 7 ------- 1 file changed, 7 deletions(-) diff --git a/drivers/platform/x86/hp-wmi.c b/drivers/platform/x86/hp-wmi.c index c2ca5c22f8d2..b4ed3dc983d5 100644 --- a/drivers/platform/x86/hp-wmi.c +++ b/drivers/platform/x86/hp-wmi.c @@ -107,13 +107,6 @@ enum hp_wmi_hardware_mask { HPWMI_TABLET_MASK = 0x04, }; -#define BIOS_ARGS_INIT(write, ctype, size) \ - (struct bios_args) { .signature = 0x55434553, \ - .command = (write) ? 0x2 : 0x1, \ - .commandtype = (ctype), \ - .datasize = (size), \ - .data = 0 } - struct bios_return { u32 sigpass; u32 return_code; From fe4e8d0910540db28e457ce792ae2b29ee66ab8a Mon Sep 17 00:00:00 2001 From: "Gustavo A. R. Silva" Date: Wed, 9 Aug 2017 11:00:54 -0500 Subject: [PATCH 11/23] platform/x86: intel_mid_powerbtn: fix error return code in mid_pb_probe() platform_get_irq() returns an error code, but the intel_mid_powerbtn driver ignores it and always returns -EINVAL. This is not correct and, prevents -EPROBE_DEFER from being propagated properly. Print error message and propagate the return value of platform_get_irq on failure. This issue was detected with the help of Coccinelle. Signed-off-by: Gustavo A. R. Silva Signed-off-by: Andy Shevchenko --- drivers/platform/x86/intel_mid_powerbtn.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/platform/x86/intel_mid_powerbtn.c b/drivers/platform/x86/intel_mid_powerbtn.c index 871cfa682519..854a16df485d 100644 --- a/drivers/platform/x86/intel_mid_powerbtn.c +++ b/drivers/platform/x86/intel_mid_powerbtn.c @@ -142,8 +142,10 @@ static int mid_pb_probe(struct platform_device *pdev) if (!id) return -ENODEV; - if (irq < 0) - return -EINVAL; + if (irq < 0) { + dev_err(&pdev->dev, "Failed to get IRQ: %d\n", irq); + return irq; + } input = devm_input_allocate_device(&pdev->dev); if (!input) From c94a8ff14de377ab8f24657b27cece4637051fe2 Mon Sep 17 00:00:00 2001 From: Bhumika Goyal Date: Fri, 11 Aug 2017 19:50:00 +0530 Subject: [PATCH 12/23] platform/x86: intel_mid_powerbtn: make mid_pb_ddata const Make these const as they are only used during a copy operation. Done using Coccinelle. Signed-off-by: Bhumika Goyal Signed-off-by: Andy Shevchenko --- drivers/platform/x86/intel_mid_powerbtn.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/platform/x86/intel_mid_powerbtn.c b/drivers/platform/x86/intel_mid_powerbtn.c index 854a16df485d..d79fbf924b13 100644 --- a/drivers/platform/x86/intel_mid_powerbtn.c +++ b/drivers/platform/x86/intel_mid_powerbtn.c @@ -108,13 +108,13 @@ static irqreturn_t mid_pb_isr(int irq, void *dev_id) return IRQ_HANDLED; } -static struct mid_pb_ddata mfld_ddata = { +static const struct mid_pb_ddata mfld_ddata = { .mirqlvl1_addr = INTEL_MSIC_IRQLVL1MSK, .pbstat_addr = INTEL_MSIC_PBSTATUS, .pbstat_mask = MSIC_PB_LEVEL, }; -static struct mid_pb_ddata mrfld_ddata = { +static const struct mid_pb_ddata mrfld_ddata = { .mirqlvl1_addr = BCOVE_IRQLVL1MSK, .pbstat_addr = BCOVE_PBSTATUS, .pbstat_mask = BCOVE_PB_LEVEL, From 9a862ed5f945843f86a58659a2a50642baec7ae6 Mon Sep 17 00:00:00 2001 From: Bhumika Goyal Date: Fri, 11 Aug 2017 18:49:11 +0530 Subject: [PATCH 13/23] platform/x86: intel_scu_ipc: make intel_scu_ipc_pdata_t const Make these const as they are only used during a copy operation. Done using Coccinelle. Signed-off-by: Bhumika Goyal Signed-off-by: Andy Shevchenko --- drivers/platform/x86/intel_scu_ipc.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/platform/x86/intel_scu_ipc.c b/drivers/platform/x86/intel_scu_ipc.c index f7cf981502cd..2c85f75e32b0 100644 --- a/drivers/platform/x86/intel_scu_ipc.c +++ b/drivers/platform/x86/intel_scu_ipc.c @@ -72,20 +72,20 @@ struct intel_scu_ipc_pdata_t { u8 irq_mode; }; -static struct intel_scu_ipc_pdata_t intel_scu_ipc_lincroft_pdata = { +static const struct intel_scu_ipc_pdata_t intel_scu_ipc_lincroft_pdata = { .i2c_base = 0xff12b000, .i2c_len = 0x10, .irq_mode = 0, }; /* Penwell and Cloverview */ -static struct intel_scu_ipc_pdata_t intel_scu_ipc_penwell_pdata = { +static const struct intel_scu_ipc_pdata_t intel_scu_ipc_penwell_pdata = { .i2c_base = 0xff12b000, .i2c_len = 0x10, .irq_mode = 1, }; -static struct intel_scu_ipc_pdata_t intel_scu_ipc_tangier_pdata = { +static const struct intel_scu_ipc_pdata_t intel_scu_ipc_tangier_pdata = { .i2c_base = 0xff00d000, .i2c_len = 0x10, .irq_mode = 0, From 0fe57261214bcc866ef0233444a395b5fdfb5ac3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pali=20Roh=C3=A1r?= Date: Sat, 12 Aug 2017 09:44:16 +0200 Subject: [PATCH 14/23] platform/x86: asus-wmi: Evaluate wmi method with instance number 0x0 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit According to available DSDT dump from Asus machine, there is the only one instance of the WMI GUID 97845ED0-4E6D-11DE-8A39-0800200C9A66 and so it is 0x0. Moreover corresponding method WMBC does not check Arg0 (instance number) at all. DSDT dump is available at: https://lwn.net/Articles/391249/ _WDG dump: 0xD0, 0x5E, 0x84, 0x97, 0x6D, 0x4E, 0xDE, 0x11, 0x8A, 0x39, 0x08, 0x00, 0x20, 0x0C, 0x9A, 0x66, 0x42, 0x43, // Object ID "BC" = method "WMBC" 0x01, // Instance count 0x02, // Flags Signed-off-by: Pali Rohár Signed-off-by: Andy Shevchenko --- drivers/platform/x86/asus-wmi.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/platform/x86/asus-wmi.c b/drivers/platform/x86/asus-wmi.c index 709e3a67391a..48e1541dc8d4 100644 --- a/drivers/platform/x86/asus-wmi.c +++ b/drivers/platform/x86/asus-wmi.c @@ -299,7 +299,7 @@ static int asus_wmi_evaluate_method(u32 method_id, u32 arg0, u32 arg1, union acpi_object *obj; u32 tmp = 0; - status = wmi_evaluate_method(ASUS_WMI_MGMT_GUID, 1, method_id, + status = wmi_evaluate_method(ASUS_WMI_MGMT_GUID, 0, method_id, &input, &output); if (ACPI_FAILURE(status)) @@ -1946,7 +1946,7 @@ static int show_call(struct seq_file *m, void *data) acpi_status status; status = wmi_evaluate_method(ASUS_WMI_MGMT_GUID, - 1, asus->debug.method_id, + 0, asus->debug.method_id, &input, &output); if (ACPI_FAILURE(status)) From f85a43b907ec90fb370e7d1061248cf9d25aa2c3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pali=20Roh=C3=A1r?= Date: Sat, 12 Aug 2017 09:44:15 +0200 Subject: [PATCH 15/23] platform/x86: mxm-wmi: Evaluate wmi method with instance number 0x0 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit According to MXM 2.1 specification, there is the only one instance of the WMI GUID F6CB5C3C-9CAE-4EBD-B577-931EA32A2CC0 and so it is instance 0x0. MXM 2.1 specification: https://lekensteyn.nl/files/docs/mxm-2.1-software-spec.pdf _WDG dump: // Methods GUID {F6CB5C3C-9CAE-4EBD-B577-931EA32A2CC0} 0x3C, 0x5C, 0xCB, 0xF6, 0xAE, 0x9C, 0xBD, 0x4E, 0xB5, 0x77, 0x93, 0x1E, 0xA3, 0x2A, 0x2C, 0xC0, 0x4D, 0x58, // Object ID "MX" = method "WMMX" 1, // Instance Count 0x02, // Flags (WMIACPI_REGFLAG_METHOD) Signed-off-by: Pali Rohár Signed-off-by: Andy Shevchenko --- drivers/platform/x86/mxm-wmi.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/platform/x86/mxm-wmi.c b/drivers/platform/x86/mxm-wmi.c index f4bad83053a9..35d8b9a939f9 100644 --- a/drivers/platform/x86/mxm-wmi.c +++ b/drivers/platform/x86/mxm-wmi.c @@ -53,7 +53,7 @@ int mxm_wmi_call_mxds(int adapter) printk("calling mux switch %d\n", adapter); - status = wmi_evaluate_method(MXM_WMMX_GUID, 0x1, adapter, &input, + status = wmi_evaluate_method(MXM_WMMX_GUID, 0x0, adapter, &input, &output); if (ACPI_FAILURE(status)) @@ -78,7 +78,7 @@ int mxm_wmi_call_mxmx(int adapter) printk("calling mux switch %d\n", adapter); - status = wmi_evaluate_method(MXM_WMMX_GUID, 0x1, adapter, &input, + status = wmi_evaluate_method(MXM_WMMX_GUID, 0x0, adapter, &input, &output); if (ACPI_FAILURE(status)) From 2cf7bdec2db81730610edb2631252b39375024a0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pali=20Roh=C3=A1r?= Date: Sat, 12 Aug 2017 09:44:17 +0200 Subject: [PATCH 16/23] platform/x86: peaq-wmi: Evaluate wmi method with instance number 0x0 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit According to Hans de Goede, WMI interface of thh peaq-wmi module has 10 instances but corresponding ACPI WMBC method does not check Arg0 (instance number) at all. Therefore evaluate WMI method with first instance number (0x0) instead of second (0x1). Signed-off-by: Pali Rohár Cc: Hans de Goede Acked-by: Hans de Goede Signed-off-by: Andy Shevchenko --- drivers/platform/x86/peaq-wmi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/platform/x86/peaq-wmi.c b/drivers/platform/x86/peaq-wmi.c index c68bd76954fd..bc98ef95514a 100644 --- a/drivers/platform/x86/peaq-wmi.c +++ b/drivers/platform/x86/peaq-wmi.c @@ -39,7 +39,7 @@ static void peaq_wmi_poll(struct input_polled_dev *dev) struct acpi_buffer input = { sizeof(dummy), &dummy }; struct acpi_buffer output = { sizeof(obj), &obj }; - status = wmi_evaluate_method(PEAQ_DOLBY_BUTTON_GUID, 1, + status = wmi_evaluate_method(PEAQ_DOLBY_BUTTON_GUID, 0, PEAQ_DOLBY_BUTTON_METHOD_ID, &input, &output); if (ACPI_FAILURE(status)) From c977b98bbef5898ed3d30b08ea67622e9e82082a Mon Sep 17 00:00:00 2001 From: Srinivas Pandruvada Date: Sat, 12 Aug 2017 09:50:09 -0700 Subject: [PATCH 17/23] platform/x86: intel_pmc_core: Make the driver PCH family agnostic Although this driver did pretty good job in abstracting PCH specific interfaces, but still there are some loose ends. For example SLP_S0 counter (for reading SLP_S0 residency), PM config offset (for checking permissions to read XRAM) and PPFEAR offset (for reading IP status) is still hardcoded for a specific family of PCH. This change extended the struct pmc_reg_map to allow per family configuration of offsets and bits. No functional change is expected with this change. This change allows seamless additions to new PCH and create a baseline for other platform specific extensions. Signed-off-by: Srinivas Pandruvada Signed-off-by: Andy Shevchenko --- drivers/platform/x86/intel_pmc_core.c | 31 ++++++++++++++++++--------- drivers/platform/x86/intel_pmc_core.h | 30 +++++++++++++++++++++++++- 2 files changed, 50 insertions(+), 11 deletions(-) diff --git a/drivers/platform/x86/intel_pmc_core.c b/drivers/platform/x86/intel_pmc_core.c index 914bcd2edbde..17e08b42b0a9 100644 --- a/drivers/platform/x86/intel_pmc_core.c +++ b/drivers/platform/x86/intel_pmc_core.c @@ -110,6 +110,13 @@ static const struct pmc_reg_map spt_reg_map = { .pfear_sts = spt_pfear_map, .mphy_sts = spt_mphy_map, .pll_sts = spt_pll_map, + .slp_s0_offset = SPT_PMC_SLP_S0_RES_COUNTER_OFFSET, + .ltr_ignore_offset = SPT_PMC_LTR_IGNORE_OFFSET, + .regmap_length = SPT_PMC_MMIO_REG_LEN, + .ppfear0_offset = SPT_PMC_XRAM_PPFEAR0A, + .ppfear_buckets = SPT_PPFEAR_NUM_ENTRIES, + .pm_cfg_offset = SPT_PMC_PM_CFG_OFFSET, + .pm_read_disable_bit = SPT_PMC_READ_DISABLE_BIT, }; static const struct pci_device_id pmc_pci_ids[] = { @@ -157,12 +164,13 @@ static inline u32 pmc_core_adjust_slp_s0_step(u32 value) int intel_pmc_slp_s0_counter_read(u32 *data) { struct pmc_dev *pmcdev = &pmc; + const struct pmc_reg_map *map = pmcdev->map; u32 value; if (!pmcdev->has_slp_s0_res) return -EACCES; - value = pmc_core_reg_read(pmcdev, SPT_PMC_SLP_S0_RES_COUNTER_OFFSET); + value = pmc_core_reg_read(pmcdev, map->slp_s0_offset); *data = pmc_core_adjust_slp_s0_step(value); return 0; @@ -172,9 +180,10 @@ EXPORT_SYMBOL_GPL(intel_pmc_slp_s0_counter_read); static int pmc_core_dev_state_get(void *data, u64 *val) { struct pmc_dev *pmcdev = data; + const struct pmc_reg_map *map = pmcdev->map; u32 value; - value = pmc_core_reg_read(pmcdev, SPT_PMC_SLP_S0_RES_COUNTER_OFFSET); + value = pmc_core_reg_read(pmcdev, map->slp_s0_offset); *val = pmc_core_adjust_slp_s0_step(value); return 0; @@ -187,8 +196,8 @@ static int pmc_core_check_read_lock_bit(void) struct pmc_dev *pmcdev = &pmc; u32 value; - value = pmc_core_reg_read(pmcdev, SPT_PMC_PM_CFG_OFFSET); - return value & BIT(SPT_PMC_READ_DISABLE_BIT); + value = pmc_core_reg_read(pmcdev, pmcdev->map->pm_cfg_offset); + return value & BIT(pmcdev->map->pm_read_disable_bit); } #if IS_ENABLED(CONFIG_DEBUG_FS) @@ -204,12 +213,13 @@ static int pmc_core_ppfear_sts_show(struct seq_file *s, void *unused) { struct pmc_dev *pmcdev = s->private; const struct pmc_bit_map *map = pmcdev->map->pfear_sts; - u8 pf_regs[NUM_ENTRIES]; + u8 pf_regs[PPFEAR_MAX_NUM_ENTRIES]; int index, iter; - iter = SPT_PMC_XRAM_PPFEAR0A; + iter = pmcdev->map->ppfear0_offset; - for (index = 0; index < NUM_ENTRIES; index++, iter++) + for (index = 0; index < pmcdev->map->ppfear_buckets && + index < PPFEAR_MAX_NUM_ENTRIES; index++, iter++) pf_regs[index] = pmc_core_reg_read_byte(pmcdev, iter); for (index = 0; map[index].name; index++) @@ -376,6 +386,7 @@ static ssize_t pmc_core_ltr_ignore_write(struct file *file, const char __user *userbuf, size_t count, loff_t *ppos) { struct pmc_dev *pmcdev = &pmc; + const struct pmc_reg_map *map = pmcdev->map; u32 val, buf_size, fd; int err = 0; @@ -392,9 +403,9 @@ static ssize_t pmc_core_ltr_ignore_write(struct file *file, const char __user goto out_unlock; } - fd = pmc_core_reg_read(pmcdev, SPT_PMC_LTR_IGNORE_OFFSET); + fd = pmc_core_reg_read(pmcdev, map->ltr_ignore_offset); fd |= (1U << val); - pmc_core_reg_write(pmcdev, SPT_PMC_LTR_IGNORE_OFFSET, fd); + pmc_core_reg_write(pmcdev, map->ltr_ignore_offset, fd); out_unlock: mutex_unlock(&pmcdev->lock); @@ -530,8 +541,8 @@ static int pmc_core_probe(struct pci_dev *dev, const struct pci_device_id *id) } mutex_init(&pmcdev->lock); - pmcdev->pmc_xram_read_bit = pmc_core_check_read_lock_bit(); pmcdev->map = map; + pmcdev->pmc_xram_read_bit = pmc_core_check_read_lock_bit(); err = pmc_core_dbgfs_register(pmcdev); if (err < 0) diff --git a/drivers/platform/x86/intel_pmc_core.h b/drivers/platform/x86/intel_pmc_core.h index 5a48e7728479..3d225a9cc09f 100644 --- a/drivers/platform/x86/intel_pmc_core.h +++ b/drivers/platform/x86/intel_pmc_core.h @@ -38,7 +38,8 @@ #define SPT_PMC_SLP_S0_RES_COUNTER_STEP 0x64 #define PMC_BASE_ADDR_MASK ~(SPT_PMC_MMIO_REG_LEN - 1) #define MTPMC_MASK 0xffff0000 -#define NUM_ENTRIES 5 +#define PPFEAR_MAX_NUM_ENTRIES 5 +#define SPT_PPFEAR_NUM_ENTRIES 5 #define SPT_PMC_READ_DISABLE_BIT 0x16 #define SPT_PMC_MSG_FULL_STS_BIT 0x18 #define NUM_RETRIES 100 @@ -126,10 +127,37 @@ struct pmc_bit_map { u32 bit_mask; }; +/** + * struct pmc_reg_map - Structure used to define parameter unique to a + PCH family + * @pfear_sts: Maps name of IP block to PPFEAR* bit + * @mphy_sts: Maps name of MPHY lane to MPHY status lane status bit + * @pll_sts: Maps name of PLL to corresponding bit status + * @slp_s0_offset: PWRMBASE offset to read SLP_S0 residency + * @ltr_ignore_offset: PWRMBASE offset to read/write LTR ignore bit + * @base_address: Base address of PWRMBASE defined in BIOS writer guide + * @regmap_length: Length of memory to map from PWRMBASE address to access + * @ppfear0_offset: PWRMBASE offset to to read PPFEAR* + * @ppfear_buckets: Number of 8 bits blocks to read all IP blocks from + * PPFEAR + * @pm_cfg_offset: PWRMBASE offset to PM_CFG register + * @pm_read_disable_bit: Bit index to read PMC_READ_DISABLE + * + * Each PCH has unique set of register offsets and bit indexes. This structure + * captures them to have a common implementation. + */ struct pmc_reg_map { const struct pmc_bit_map *pfear_sts; const struct pmc_bit_map *mphy_sts; const struct pmc_bit_map *pll_sts; + const u32 slp_s0_offset; + const u32 ltr_ignore_offset; + const u32 base_address; + const int regmap_length; + const u32 ppfear0_offset; + const int ppfear_buckets; + const u32 pm_cfg_offset; + const int pm_read_disable_bit; }; /** From ade50296186a1c45311d05a06117a2bd112d37fd Mon Sep 17 00:00:00 2001 From: Hao Wei Tee Date: Tue, 15 Aug 2017 00:13:51 +0800 Subject: [PATCH 18/23] platform/x86: ideapad-laptop: Expose conservation mode switch This exposes the battery conservation mode present on some (?) IdeaPads. The mode is set by calling ACPI method SBMC with argument 3 (on) or 5 (off). Status is reported in bit 5 of the return value of ACPI method GBMD. Signed-off-by: Hao Wei Tee Signed-off-by: Andy Shevchenko --- drivers/platform/x86/ideapad-laptop.c | 69 +++++++++++++++++++++++++++ 1 file changed, 69 insertions(+) diff --git a/drivers/platform/x86/ideapad-laptop.c b/drivers/platform/x86/ideapad-laptop.c index 603fc6050971..fe98d4ac0df3 100644 --- a/drivers/platform/x86/ideapad-laptop.c +++ b/drivers/platform/x86/ideapad-laptop.c @@ -42,6 +42,8 @@ #define IDEAPAD_RFKILL_DEV_NUM (3) +#define BM_CONSERVATION_BIT (5) + #define CFG_BT_BIT (16) #define CFG_3G_BIT (17) #define CFG_WIFI_BIT (18) @@ -54,6 +56,11 @@ static const char *const ideapad_wmi_fnesc_events[] = { }; #endif +enum { + BMCMD_CONSERVATION_ON = 3, + BMCMD_CONSERVATION_OFF = 5, +}; + enum { VPCCMD_R_VPC1 = 0x10, VPCCMD_R_BL_MAX, @@ -123,6 +130,23 @@ static int read_method_int(acpi_handle handle, const char *method, int *val) } } +static int method_gbmd(acpi_handle handle, unsigned long *ret) +{ + int result, val; + + result = read_method_int(handle, "GBMD", &val); + *ret = val; + return result; +} + +static int method_sbmc(acpi_handle handle, int cmd) +{ + acpi_status status; + + status = acpi_execute_simple_method(handle, "SBMC", cmd); + return ACPI_FAILURE(status) ? -1 : 0; +} + static int method_vpcr(acpi_handle handle, int cmd, int *ret) { acpi_status status; @@ -250,6 +274,13 @@ static int debugfs_status_show(struct seq_file *s, void *data) if (!read_ec_data(priv->adev->handle, VPCCMD_R_CAMERA, &value)) seq_printf(s, "Camera status:\t%s(%lu)\n", value ? "On" : "Off", value); + seq_puts(s, "=====================\n"); + + if (!method_gbmd(priv->adev->handle, &value)) { + seq_printf(s, "Conservation mode:\t%s(%lu)\n", + test_bit(BM_CONSERVATION_BIT, &value) ? "On" : "Off", + value); + } return 0; } @@ -456,10 +487,45 @@ static ssize_t __maybe_unused touchpad_store(struct device *dev, static DEVICE_ATTR_RO(touchpad); +static ssize_t conservation_mode_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct ideapad_private *priv = dev_get_drvdata(dev); + unsigned long result; + + if (method_gbmd(priv->adev->handle, &result)) + return sprintf(buf, "-1\n"); + return sprintf(buf, "%u\n", test_bit(BM_CONSERVATION_BIT, &result)); +} + +static ssize_t conservation_mode_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct ideapad_private *priv = dev_get_drvdata(dev); + bool state; + int ret; + + ret = kstrtobool(buf, &state); + if (ret) + return ret; + + ret = method_sbmc(priv->adev->handle, state ? + BMCMD_CONSERVATION_ON : + BMCMD_CONSERVATION_OFF); + if (ret < 0) + return -EIO; + return count; +} + +static DEVICE_ATTR_RW(conservation_mode); + static struct attribute *ideapad_attributes[] = { &dev_attr_camera_power.attr, &dev_attr_fan_mode.attr, &dev_attr_touchpad.attr, + &dev_attr_conservation_mode.attr, NULL }; @@ -477,6 +543,9 @@ static umode_t ideapad_is_visible(struct kobject *kobj, unsigned long value; supported = !read_ec_data(priv->adev->handle, VPCCMD_R_FAN, &value); + } else if (attr == &dev_attr_conservation_mode.attr) { + supported = acpi_has_method(priv->adev->handle, "GBMD") && + acpi_has_method(priv->adev->handle, "SBMC"); } else supported = true; From 6afa1e2a32f4bd28df4cbe75454fde837dad4c09 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pali=20Roh=C3=A1r?= Date: Sat, 12 Aug 2017 09:44:18 +0200 Subject: [PATCH 19/23] platform/x86: wmi: Fix check for method instance number MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit instance_count defines number of instances of data block and instance itself is indexed from zero, which means first instance has number 0. Therefore check for invalid instance should be non-strict inequality. Signed-off-by: Pali Rohár Reviewed-by: Darren Hart (VMware) Signed-off-by: Andy Shevchenko --- drivers/platform/x86/wmi.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/platform/x86/wmi.c b/drivers/platform/x86/wmi.c index e32ba575e8d9..0765b1797d4c 100644 --- a/drivers/platform/x86/wmi.c +++ b/drivers/platform/x86/wmi.c @@ -218,7 +218,7 @@ u32 method_id, const struct acpi_buffer *in, struct acpi_buffer *out) if (!(block->flags & ACPI_WMI_METHOD)) return AE_BAD_DATA; - if (block->instance_count < instance) + if (block->instance_count <= instance) return AE_BAD_PARAMETER; input.count = 2; @@ -265,7 +265,7 @@ static acpi_status __query_block(struct wmi_block *wblock, u8 instance, block = &wblock->gblock; handle = wblock->acpi_device->handle; - if (block->instance_count < instance) + if (block->instance_count <= instance) return AE_BAD_PARAMETER; /* Check GUID is a data block */ @@ -392,7 +392,7 @@ acpi_status wmi_set_block(const char *guid_string, u8 instance, block = &wblock->gblock; handle = wblock->acpi_device->handle; - if (block->instance_count < instance) + if (block->instance_count <= instance) return AE_BAD_PARAMETER; /* Check GUID is a data block */ From 6b99e3569ba17b9fd38514d66591ae728b778e3b Mon Sep 17 00:00:00 2001 From: Stanislav Fomichev Date: Tue, 20 Jun 2017 20:45:13 -0700 Subject: [PATCH 20/23] platform/x86: thinkpad_acpi: Fix warning about deprecated hwmon_device_register Use hwmon_device_register_with_groups instead of deprecated hwmon_device_register and fix a dmesg warning. This patch however changes the userspace API. hwmon_device_register_with_groups takes `hwmon' name as an argument and creates a name file in the `hwmon' device, not in the `platform_device'. This allows us to remove custom `name' device attribute, but in order to make lm-sensors happy we also have to move fans and thermal attributes to the `hwmon' device. Even though this patch changes userspace API, it's still compatible with the lm-sensors. Starting with lm-sensors 3.0 (circa 2007), it looks at both hwmon and the backing device for the name and other attributes. before: $ cat /sys/devices/platform/thinkpad_hwmon/{name,fan1_input} thinkpad 2007 $ cat /sys/devices/platform/thinkpad_hwmon/hwmon/hwmon1/{name,fan1_input} cat: /sys/devices/platform/thinkpad_hwmon/hwmon/hwmon1/name: No such file or directory cat: /sys/devices/platform/thinkpad_hwmon/hwmon/hwmon1/fan1_input: No such file or directory $ cat /sys/class/hwmon/hwmon1/{name,fan1_input} cat: /sys/class/hwmon/hwmon1/name: No such file or directory cat: /sys/class/hwmon/hwmon1/fan1_input: No such file or directory $ sensors thinkpad-isa-0000 Adapter: ISA adapter fan1: 3533 RPM after: $ cat /sys/devices/platform/thinkpad_hwmon/{name,fan1_input} cat: /sys/devices/platform/thinkpad_hwmon/name: No such file or directory cat: /sys/devices/platform/thinkpad_hwmon/fan1_input: No such file or directory $ cat /sys/devices/platform/thinkpad_hwmon/hwmon/hwmon1/{name,fan1_input} thinkpad 3478 $ cat /sys/class/hwmon/hwmon1/{name,fan1_input} thinkpad 3478 $ sensors thinkpad-isa-0000 Adapter: ISA adapter fan1: 3489 RPM $ sensors -v sensors version 3.4.0 with libsensors version 3.4.0 Signed-off-by: Stanislav Fomichev [dvhart: cleaned up commit log, bumped version to 4.14 in the doc change] Signed-off-by: Darren Hart (VMware) --- Documentation/laptops/thinkpad-acpi.txt | 9 ++++-- drivers/platform/x86/thinkpad_acpi.c | 38 +++++++------------------ 2 files changed, 18 insertions(+), 29 deletions(-) diff --git a/Documentation/laptops/thinkpad-acpi.txt b/Documentation/laptops/thinkpad-acpi.txt index ba2e7d254842..00b6dfed573c 100644 --- a/Documentation/laptops/thinkpad-acpi.txt +++ b/Documentation/laptops/thinkpad-acpi.txt @@ -121,8 +121,9 @@ space, for 2.6.23+ this is /sys/devices/platform/thinkpad_acpi/. Sysfs device attributes for the sensors and fan are on the thinkpad_hwmon device's sysfs attribute space, but you should locate it looking for a hwmon device with the name attribute of "thinkpad", or -better yet, through libsensors. - +better yet, through libsensors. For 4.14+ sysfs attributes were moved to the +hwmon device (/sys/bus/platform/devices/thinkpad_hwmon/hwmon/hwmon? or +/sys/class/hwmon/hwmon?). Driver version -------------- @@ -1478,3 +1479,7 @@ Sysfs interface changelog: 0x020700: Support for mute-only mixers. Volume control in read-only mode by default. Marker for ALSA mixer support. + +0x030000: Thermal and fan sysfs attributes were moved to the hwmon + device instead of being attached to the backing platform + device. diff --git a/drivers/platform/x86/thinkpad_acpi.c b/drivers/platform/x86/thinkpad_acpi.c index b22573131e53..2242d6035d9e 100644 --- a/drivers/platform/x86/thinkpad_acpi.c +++ b/drivers/platform/x86/thinkpad_acpi.c @@ -24,7 +24,7 @@ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt #define TPACPI_VERSION "0.25" -#define TPACPI_SYSFS_VERSION 0x020700 +#define TPACPI_SYSFS_VERSION 0x030000 /* * Changelog: @@ -6342,7 +6342,7 @@ static int __init thermal_init(struct ibm_init_struct *iibm) switch (thermal_read_mode) { case TPACPI_THERMAL_TPEC_16: - res = sysfs_create_group(&tpacpi_sensors_pdev->dev.kobj, + res = sysfs_create_group(&tpacpi_hwmon->kobj, &thermal_temp_input16_group); if (res) return res; @@ -6350,7 +6350,7 @@ static int __init thermal_init(struct ibm_init_struct *iibm) case TPACPI_THERMAL_TPEC_8: case TPACPI_THERMAL_ACPI_TMP07: case TPACPI_THERMAL_ACPI_UPDT: - res = sysfs_create_group(&tpacpi_sensors_pdev->dev.kobj, + res = sysfs_create_group(&tpacpi_hwmon->kobj, &thermal_temp_input8_group); if (res) return res; @@ -6367,13 +6367,13 @@ static void thermal_exit(void) { switch (thermal_read_mode) { case TPACPI_THERMAL_TPEC_16: - sysfs_remove_group(&tpacpi_sensors_pdev->dev.kobj, + sysfs_remove_group(&tpacpi_hwmon->kobj, &thermal_temp_input16_group); break; case TPACPI_THERMAL_TPEC_8: case TPACPI_THERMAL_ACPI_TMP07: case TPACPI_THERMAL_ACPI_UPDT: - sysfs_remove_group(&tpacpi_sensors_pdev->dev.kobj, + sysfs_remove_group(&tpacpi_hwmon->kobj, &thermal_temp_input8_group); break; case TPACPI_THERMAL_NONE: @@ -8696,7 +8696,7 @@ static int __init fan_init(struct ibm_init_struct *iibm) fan_attributes[ARRAY_SIZE(fan_attributes)-2] = &dev_attr_fan2_input.attr; } - rc = sysfs_create_group(&tpacpi_sensors_pdev->dev.kobj, + rc = sysfs_create_group(&tpacpi_hwmon->kobj, &fan_attr_group); if (rc < 0) return rc; @@ -8704,7 +8704,7 @@ static int __init fan_init(struct ibm_init_struct *iibm) rc = driver_create_file(&tpacpi_hwmon_pdriver.driver, &driver_attr_fan_watchdog); if (rc < 0) { - sysfs_remove_group(&tpacpi_sensors_pdev->dev.kobj, + sysfs_remove_group(&tpacpi_hwmon->kobj, &fan_attr_group); return rc; } @@ -8719,7 +8719,7 @@ static void fan_exit(void) "cancelling any pending fan watchdog tasks\n"); /* FIXME: can we really do this unconditionally? */ - sysfs_remove_group(&tpacpi_sensors_pdev->dev.kobj, &fan_attr_group); + sysfs_remove_group(&tpacpi_hwmon->kobj, &fan_attr_group); driver_remove_file(&tpacpi_hwmon_pdriver.driver, &driver_attr_fan_watchdog); @@ -9149,16 +9149,6 @@ static void hotkey_driver_event(const unsigned int scancode) tpacpi_driver_event(TP_HKEY_EV_HOTKEY_BASE + scancode); } -/* sysfs name ---------------------------------------------------------- */ -static ssize_t thinkpad_acpi_pdev_name_show(struct device *dev, - struct device_attribute *attr, - char *buf) -{ - return snprintf(buf, PAGE_SIZE, "%s\n", TPACPI_NAME); -} - -static DEVICE_ATTR(name, S_IRUGO, thinkpad_acpi_pdev_name_show, NULL); - /* --------------------------------------------------------------------- */ /* /proc support */ @@ -9696,8 +9686,6 @@ static void thinkpad_acpi_module_exit(void) if (tpacpi_hwmon) hwmon_device_unregister(tpacpi_hwmon); - if (tp_features.sensors_pdev_attrs_registered) - device_remove_file(&tpacpi_sensors_pdev->dev, &dev_attr_name); if (tpacpi_sensors_pdev) platform_device_unregister(tpacpi_sensors_pdev); if (tpacpi_pdev) @@ -9818,14 +9806,10 @@ static int __init thinkpad_acpi_module_init(void) thinkpad_acpi_module_exit(); return ret; } - ret = device_create_file(&tpacpi_sensors_pdev->dev, &dev_attr_name); - if (ret) { - pr_err("unable to create sysfs hwmon device attributes\n"); - thinkpad_acpi_module_exit(); - return ret; - } tp_features.sensors_pdev_attrs_registered = 1; - tpacpi_hwmon = hwmon_device_register(&tpacpi_sensors_pdev->dev); + tpacpi_hwmon = hwmon_device_register_with_groups( + &tpacpi_sensors_pdev->dev, TPACPI_NAME, NULL, NULL); + if (IS_ERR(tpacpi_hwmon)) { ret = PTR_ERR(tpacpi_hwmon); tpacpi_hwmon = NULL; From d496c8750f6f1ac61c7ecca8cb442ea40e67077e Mon Sep 17 00:00:00 2001 From: Alex Hung Date: Thu, 20 Jul 2017 20:58:08 -0700 Subject: [PATCH 21/23] platform/x86: intel-hid: reduce unnecessary messages for normal users Unsupported events is only useful for developers and does not meaningful for users. Using dev_dbg makes more sense and reduces noise in kernel messages. Signed-off-by: Alex Hung Signed-off-by: Darren Hart (VMware) --- drivers/platform/x86/intel-hid.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/platform/x86/intel-hid.c b/drivers/platform/x86/intel-hid.c index 8519e0f97bdd..4f70b8219850 100644 --- a/drivers/platform/x86/intel-hid.c +++ b/drivers/platform/x86/intel-hid.c @@ -219,7 +219,7 @@ static void notify_handler(acpi_handle handle, u32 event, void *context) if (event != 0xc0) { if (!priv->array || !sparse_keymap_report_event(priv->array, event, 1, true)) - dev_info(&device->dev, "unknown event 0x%x\n", event); + dev_dbg(&device->dev, "unknown event 0x%x\n", event); return; } @@ -230,7 +230,7 @@ static void notify_handler(acpi_handle handle, u32 event, void *context) } if (!sparse_keymap_report_event(priv->input_dev, ev_index, 1, true)) - dev_info(&device->dev, "unknown event index 0x%llx\n", + dev_dbg(&device->dev, "unknown event index 0x%llx\n", ev_index); } From a9c37b74fd0242f3c8ce4221bb7a61cb14ccd59b Mon Sep 17 00:00:00 2001 From: Alex Hung Date: Thu, 20 Jul 2017 20:56:48 -0700 Subject: [PATCH 22/23] platform/x86: intel-vbtn: reduce unnecessary messages for normal users Unsupported events is only useful for developers and does not meaningful for users. Using dev_dbg makes more sense and reduces noise in kernel messages. Signed-off-by: Alex Hung Signed-off-by: Darren Hart (VMware) --- drivers/platform/x86/intel-vbtn.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/platform/x86/intel-vbtn.c b/drivers/platform/x86/intel-vbtn.c index 480926786cb8..58c5ff36523a 100644 --- a/drivers/platform/x86/intel-vbtn.c +++ b/drivers/platform/x86/intel-vbtn.c @@ -83,7 +83,7 @@ static void notify_handler(acpi_handle handle, u32 event, void *context) } else if (sparse_keymap_report_event(priv->input_dev, event, 1, true)) { return; } - dev_info(&device->dev, "unknown event index 0x%x\n", event); + dev_dbg(&device->dev, "unknown event index 0x%x\n", event); } static int intel_vbtn_probe(struct platform_device *device) From 00ebbeb39b70072cc0d0acad32c47e4660eb84e7 Mon Sep 17 00:00:00 2001 From: Andy Lutomirski Date: Tue, 1 Aug 2017 08:37:27 -0700 Subject: [PATCH 23/23] platform/x86: dell-wmi: Update dell_wmi_check_descriptor_buffer() to new model MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This converts dell_wmi_check_descriptor_buffer() to the new driver model interface and puts the interface version in dell_wmi_priv where it belongs. Signed-off-by: Andy Lutomirski Reviewed-by: Pali Rohár Signed-off-by: Darren Hart (VMware) --- drivers/platform/x86/dell-wmi.c | 69 +++++++++++++++++++-------------- 1 file changed, 39 insertions(+), 30 deletions(-) diff --git a/drivers/platform/x86/dell-wmi.c b/drivers/platform/x86/dell-wmi.c index dad8f4afa17c..28d9f8696081 100644 --- a/drivers/platform/x86/dell-wmi.c +++ b/drivers/platform/x86/dell-wmi.c @@ -48,7 +48,6 @@ MODULE_LICENSE("GPL"); #define DELL_EVENT_GUID "9DBB5994-A997-11DA-B012-B622A1EF5492" #define DELL_DESCRIPTOR_GUID "8D9DDCBC-A997-11DA-B012-B622A1EF5492" -static u32 dell_wmi_interface_version; static bool wmi_requires_smbios_request; MODULE_ALIAS("wmi:"DELL_EVENT_GUID); @@ -56,6 +55,7 @@ MODULE_ALIAS("wmi:"DELL_DESCRIPTOR_GUID); struct dell_wmi_priv { struct input_dev *input_dev; + u32 interface_version; }; static int __init dmi_matched(const struct dmi_system_id *dmi) @@ -348,6 +348,7 @@ static void dell_wmi_process_key(struct wmi_device *wdev, int type, int code) static void dell_wmi_notify(struct wmi_device *wdev, union acpi_object *obj) { + struct dell_wmi_priv *priv = dev_get_drvdata(&wdev->dev); u16 *buffer_entry, *buffer_end; acpi_size buffer_size; int len, i; @@ -376,7 +377,7 @@ static void dell_wmi_notify(struct wmi_device *wdev, * So to prevent reading garbage from buffer we will process only first * one event on devices with WMI interface version 0. */ - if (dell_wmi_interface_version == 0 && buffer_entry < buffer_end) + if (priv->interface_version == 0 && buffer_entry < buffer_end) if (buffer_end > buffer_entry + buffer_entry[0] + 1) buffer_end = buffer_entry + buffer_entry[0] + 1; @@ -626,61 +627,67 @@ static void dell_wmi_input_destroy(struct wmi_device *wdev) * WMI Interface Version 8 4 * WMI buffer length 12 4 4096 */ -static int dell_wmi_check_descriptor_buffer(void) +static int dell_wmi_check_descriptor_buffer(struct wmi_device *wdev) { - struct acpi_buffer out = { ACPI_ALLOCATE_BUFFER, NULL }; - union acpi_object *obj; - acpi_status status; + struct dell_wmi_priv *priv = dev_get_drvdata(&wdev->dev); + union acpi_object *obj = NULL; + struct wmi_device *desc_dev; u32 *buffer; + int ret; - status = wmi_query_block(DELL_DESCRIPTOR_GUID, 0, &out); - if (ACPI_FAILURE(status)) { - pr_err("Cannot read Dell descriptor buffer - %d\n", status); - return status; + desc_dev = wmidev_get_other_guid(wdev, DELL_DESCRIPTOR_GUID); + if (!desc_dev) { + dev_err(&wdev->dev, "Dell WMI descriptor does not exist\n"); + return -ENODEV; } - obj = (union acpi_object *)out.pointer; + obj = wmidev_block_query(desc_dev, 0); if (!obj) { - pr_err("Dell descriptor buffer is empty\n"); - return -EINVAL; + dev_err(&wdev->dev, "failed to read Dell WMI descriptor\n"); + ret = -EIO; + goto out; } if (obj->type != ACPI_TYPE_BUFFER) { - pr_err("Cannot read Dell descriptor buffer\n"); - kfree(obj); - return -EINVAL; + dev_err(&wdev->dev, "Dell descriptor has wrong type\n"); + ret = -EINVAL; + goto out; } if (obj->buffer.length != 128) { - pr_err("Dell descriptor buffer has invalid length (%d)\n", + dev_err(&wdev->dev, + "Dell descriptor buffer has invalid length (%d)\n", obj->buffer.length); if (obj->buffer.length < 16) { - kfree(obj); - return -EINVAL; + ret = -EINVAL; + goto out; } } buffer = (u32 *)obj->buffer.pointer; if (buffer[0] != 0x4C4C4544 && buffer[1] != 0x494D5720) - pr_warn("Dell descriptor buffer has invalid signature (%*ph)\n", + dev_warn(&wdev->dev, "Dell descriptor buffer has invalid signature (%*ph)\n", 8, buffer); if (buffer[2] != 0 && buffer[2] != 1) - pr_warn("Dell descriptor buffer has unknown version (%d)\n", + dev_warn(&wdev->dev, "Dell descriptor buffer has unknown version (%d)\n", buffer[2]); if (buffer[3] != 4096) - pr_warn("Dell descriptor buffer has invalid buffer length (%d)\n", + dev_warn(&wdev->dev, "Dell descriptor buffer has invalid buffer length (%d)\n", buffer[3]); - dell_wmi_interface_version = buffer[2]; + priv->interface_version = buffer[2]; + ret = 0; - pr_info("Detected Dell WMI interface version %u\n", - dell_wmi_interface_version); + dev_info(&wdev->dev, "Detected Dell WMI interface version %u\n", + priv->interface_version); +out: kfree(obj); - return 0; + put_device(&desc_dev->dev); + return ret; } /* @@ -717,17 +724,19 @@ static int dell_wmi_events_set_enabled(bool enable) static int dell_wmi_probe(struct wmi_device *wdev) { + struct dell_wmi_priv *priv; int err; - struct dell_wmi_priv *priv = devm_kzalloc( + priv = devm_kzalloc( &wdev->dev, sizeof(struct dell_wmi_priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + dev_set_drvdata(&wdev->dev, priv); - err = dell_wmi_check_descriptor_buffer(); + err = dell_wmi_check_descriptor_buffer(wdev); if (err) return err; - dev_set_drvdata(&wdev->dev, priv); - return dell_wmi_input_setup(wdev); }