[PATCH 2/3] MAINTAINERS: Add missing section for alienware-wmi driver
This driver is maintained by Dell, but it was missing in MAINTAINERS. Signed-off-by: Mario Limonciello --- MAINTAINERS | 5 + drivers/platform/x86/dell/alienware-wmi.c | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/MAINTAINERS b/MAINTAINERS index 46c8fadb59c3..3649e04c3b73 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -697,6 +697,11 @@ S: Maintained F: Documentation/i2c/busses/i2c-ali1563.rst F: drivers/i2c/busses/i2c-ali1563.c +ALIENWARE WMI DRIVER +L: dell.client.ker...@dell.com +S: Maintained +F: drivers/platform/x86/dell/alienware-wmi.c + ALL SENSORS DLH SERIES PRESSURE SENSORS DRIVER M: Tomislav Denis L: linux-...@vger.kernel.org diff --git a/drivers/platform/x86/dell/alienware-wmi.c b/drivers/platform/x86/dell/alienware-wmi.c index 5bb2859c8285..0d03e6b7b40c 100644 --- a/drivers/platform/x86/dell/alienware-wmi.c +++ b/drivers/platform/x86/dell/alienware-wmi.c @@ -2,7 +2,7 @@ /* * Alienware AlienFX control * - * Copyright (C) 2014 Dell Inc + * Copyright (C) 2014 Dell Inc */ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt -- 2.25.1
[PATCH 1/3] MAINTAINERS: Adjust Dell drivers to email alias
A team of engineers will be helping to service these drivers in the future rather than just one person. Signed-off-by: Mario Limonciello --- MAINTAINERS | 12 ++-- 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/MAINTAINERS b/MAINTAINERS index 6e91994b8d3b..46c8fadb59c3 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -5034,19 +5034,19 @@ F: drivers/platform/x86/dell/dell_rbu.c DELL SMBIOS DRIVER M: Pali Rohár -M: Mario Limonciello +L: dell.client.ker...@dell.com L: platform-driver-...@vger.kernel.org S: Maintained F: drivers/platform/x86/dell/dell-smbios.* DELL SMBIOS SMM DRIVER -M: Mario Limonciello +L: dell.client.ker...@dell.com L: platform-driver-...@vger.kernel.org S: Maintained F: drivers/platform/x86/dell/dell-smbios-smm.c DELL SMBIOS WMI DRIVER -M: Mario Limonciello +L: dell.client.ker...@dell.com L: platform-driver-...@vger.kernel.org S: Maintained F: drivers/platform/x86/dell/dell-smbios-wmi.c @@ -5060,14 +5060,14 @@ F: Documentation/driver-api/dcdbas.rst F: drivers/platform/x86/dell/dcdbas.* DELL WMI DESCRIPTOR DRIVER -M: Mario Limonciello +L: dell.client.ker...@dell.com S: Maintained F: drivers/platform/x86/dell/dell-wmi-descriptor.c DELL WMI SYSMAN DRIVER M: Divya Bharathi -M: Mario Limonciello M: Prasanth Ksr +L: dell.client.ker...@dell.com L: platform-driver-...@vger.kernel.org S: Maintained F: Documentation/ABI/testing/sysfs-class-firmware-attributes @@ -9242,7 +9242,7 @@ W: https://slimbootloader.github.io/security/firmware-update.html F: drivers/platform/x86/intel-wmi-sbl-fw-update.c INTEL WMI THUNDERBOLT FORCE POWER DRIVER -M: Mario Limonciello +L: dell.client.ker...@dell.com S: Maintained F: drivers/platform/x86/intel-wmi-thunderbolt.c -- 2.25.1
[PATCH 0/3] Adjust contacts for Dell drivers
The Dell drivers I'm involved with all have me as an author and/or maintainer. In the future these will be maintained as a team effort. Adjust the contact addresses accordingly. Mario Limonciello (3): MAINTAINERS: Adjust Dell drivers to email alias MAINTAINERS: Add missing section for alienware-wmi driver platform/x86: Adjust Dell drivers to a personal email address MAINTAINERS | 17 +++-- drivers/platform/x86/dell/alienware-wmi.c | 4 ++-- drivers/platform/x86/dell/dell-smbios-base.c| 2 +- drivers/platform/x86/dell/dell-wmi-descriptor.c | 2 +- .../platform/x86/dell/dell-wmi-sysman/sysman.c | 2 +- 5 files changed, 16 insertions(+), 11 deletions(-) -- 2.25.1
[PATCH 3/3] platform/x86: Adjust Dell drivers to a personal email address
So that I can always be reached in the future if necessary, add a personal email address. Signed-off-by: Mario Limonciello --- drivers/platform/x86/dell/alienware-wmi.c | 2 +- drivers/platform/x86/dell/dell-smbios-base.c | 2 +- drivers/platform/x86/dell/dell-wmi-descriptor.c| 2 +- drivers/platform/x86/dell/dell-wmi-sysman/sysman.c | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/platform/x86/dell/alienware-wmi.c b/drivers/platform/x86/dell/alienware-wmi.c index 0d03e6b7b40c..f21248255529 100644 --- a/drivers/platform/x86/dell/alienware-wmi.c +++ b/drivers/platform/x86/dell/alienware-wmi.c @@ -26,7 +26,7 @@ #define WMAX_METHOD_DEEP_SLEEP_CONTROL 0x0B #define WMAX_METHOD_DEEP_SLEEP_STATUS 0x0C -MODULE_AUTHOR("Mario Limonciello "); +MODULE_AUTHOR("Mario Limonciello "); MODULE_DESCRIPTION("Alienware special feature control"); MODULE_LICENSE("GPL"); MODULE_ALIAS("wmi:" LEGACY_CONTROL_GUID); diff --git a/drivers/platform/x86/dell/dell-smbios-base.c b/drivers/platform/x86/dell/dell-smbios-base.c index 3a1dbf199441..fc086b66f70b 100644 --- a/drivers/platform/x86/dell/dell-smbios-base.c +++ b/drivers/platform/x86/dell/dell-smbios-base.c @@ -647,6 +647,6 @@ module_exit(dell_smbios_exit); MODULE_AUTHOR("Matthew Garrett "); MODULE_AUTHOR("Gabriele Mazzotta "); MODULE_AUTHOR("Pali Rohár "); -MODULE_AUTHOR("Mario Limonciello "); +MODULE_AUTHOR("Mario Limonciello "); MODULE_DESCRIPTION("Common functions for kernel modules using Dell SMBIOS"); MODULE_LICENSE("GPL"); diff --git a/drivers/platform/x86/dell/dell-wmi-descriptor.c b/drivers/platform/x86/dell/dell-wmi-descriptor.c index a068900ae8a1..91637c4a03b3 100644 --- a/drivers/platform/x86/dell/dell-wmi-descriptor.c +++ b/drivers/platform/x86/dell/dell-wmi-descriptor.c @@ -201,6 +201,6 @@ static struct wmi_driver dell_wmi_descriptor_driver = { module_wmi_driver(dell_wmi_descriptor_driver); MODULE_DEVICE_TABLE(wmi, dell_wmi_descriptor_id_table); -MODULE_AUTHOR("Mario Limonciello "); +MODULE_AUTHOR("Mario Limonciello "); MODULE_DESCRIPTION("Dell WMI descriptor driver"); MODULE_LICENSE("GPL"); diff --git a/drivers/platform/x86/dell/dell-wmi-sysman/sysman.c b/drivers/platform/x86/dell/dell-wmi-sysman/sysman.c index 7410ccae650c..98f2b6ba3916 100644 --- a/drivers/platform/x86/dell/dell-wmi-sysman/sysman.c +++ b/drivers/platform/x86/dell/dell-wmi-sysman/sysman.c @@ -604,7 +604,7 @@ static void __exit sysman_exit(void) module_init(sysman_init); module_exit(sysman_exit); -MODULE_AUTHOR("Mario Limonciello "); +MODULE_AUTHOR("Mario Limonciello "); MODULE_AUTHOR("Prasanth Ksr "); MODULE_AUTHOR("Divya Bharathi "); MODULE_DESCRIPTION("Dell platform setting control interface"); -- 2.25.1
[PATCH] platform/x86: dell-wmi-sysman: correct an initialization failure
On Dell systems that don't support this interface the module is mistakingly returning error code "0", when it should be returning -ENODEV. Correct a logic error to guarantee the correct return code. Cc: Divya Bharathi Reported-by: Alexander Naumann Signed-off-by: Mario Limonciello --- drivers/platform/x86/dell-wmi-sysman/biosattr-interface.c | 4 +++- drivers/platform/x86/dell-wmi-sysman/passwordattr-interface.c | 4 +++- drivers/platform/x86/dell-wmi-sysman/sysman.c | 4 ++-- 3 files changed, 8 insertions(+), 4 deletions(-) diff --git a/drivers/platform/x86/dell-wmi-sysman/biosattr-interface.c b/drivers/platform/x86/dell-wmi-sysman/biosattr-interface.c index f95d8ddace5a..8d59f81f9db4 100644 --- a/drivers/platform/x86/dell-wmi-sysman/biosattr-interface.c +++ b/drivers/platform/x86/dell-wmi-sysman/biosattr-interface.c @@ -175,7 +175,9 @@ static struct wmi_driver bios_attr_set_interface_driver = { int init_bios_attr_set_interface(void) { - return wmi_driver_register(&bios_attr_set_interface_driver); + int ret = wmi_driver_register(&bios_attr_set_interface_driver); + + return wmi_priv.bios_attr_wdev ? ret : -ENODEV; } void exit_bios_attr_set_interface(void) diff --git a/drivers/platform/x86/dell-wmi-sysman/passwordattr-interface.c b/drivers/platform/x86/dell-wmi-sysman/passwordattr-interface.c index 5780b4d94759..bf449dc5ff47 100644 --- a/drivers/platform/x86/dell-wmi-sysman/passwordattr-interface.c +++ b/drivers/platform/x86/dell-wmi-sysman/passwordattr-interface.c @@ -142,7 +142,9 @@ static struct wmi_driver bios_attr_pass_interface_driver = { int init_bios_attr_pass_interface(void) { - return wmi_driver_register(&bios_attr_pass_interface_driver); + int ret = wmi_driver_register(&bios_attr_pass_interface_driver); + + return wmi_priv.password_attr_wdev ? ret : -ENODEV; } void exit_bios_attr_pass_interface(void) diff --git a/drivers/platform/x86/dell-wmi-sysman/sysman.c b/drivers/platform/x86/dell-wmi-sysman/sysman.c index cb81010ba1a2..d9ad0e83b66f 100644 --- a/drivers/platform/x86/dell-wmi-sysman/sysman.c +++ b/drivers/platform/x86/dell-wmi-sysman/sysman.c @@ -513,13 +513,13 @@ static int __init sysman_init(void) } ret = init_bios_attr_set_interface(); - if (ret || !wmi_priv.bios_attr_wdev) { + if (ret) { pr_debug("failed to initialize set interface\n"); goto fail_set_interface; } ret = init_bios_attr_pass_interface(); - if (ret || !wmi_priv.password_attr_wdev) { + if (ret) { pr_debug("failed to initialize pass interface\n"); goto fail_pass_interface; } -- 2.25.1
[RFC 0/2] Split out firmware upgrade from CAP_SYS_ADMIN
Currently NVME (and probably other drivers) require CAP_SYS_ADMIN to send all commands to the device. This means that software running in userspace needs the stronger CAP_SYS_ADMIN permission when realistically a more limited subset of functionality is actually needed. To allow software that performs firmware upgrades to run without CAP_SYS_ADMIN, create a new capability CAP_FIRMWARE_UPGRADE that software can run with. For the RFC, only include NVME. Other drivers can be added if suggested. Mario Limonciello (2): capability: Introduce CAP_FIRMWARE_UPGRADE nvme: Use CAP_FIRMWARE_UPGRADE to check user commands drivers/nvme/host/core.c| 28 include/linux/capability.h | 5 + include/uapi/linux/capability.h | 7 ++- security/selinux/include/classmap.h | 4 ++-- 4 files changed, 37 insertions(+), 7 deletions(-) -- 2.25.1
[RFC 2/2] nvme: Use CAP_FIRMWARE_UPGRADE to check user commands
Software that is running with CAP_FIRMWARE_UPGRADE needs a limited set of opcode access: * Identify the disk * Download firmware to the disk * Commit the firmwware to the disk Signed-off-by: Mario Limonciello --- drivers/nvme/host/core.c | 28 1 file changed, 24 insertions(+), 4 deletions(-) diff --git a/drivers/nvme/host/core.c b/drivers/nvme/host/core.c index f13eb4ded95f..80be3d6b7437 100644 --- a/drivers/nvme/host/core.c +++ b/drivers/nvme/host/core.c @@ -1593,13 +1593,23 @@ static int nvme_user_cmd(struct nvme_ctrl *ctrl, struct nvme_ns *ns, u64 result; int status; - if (!capable(CAP_SYS_ADMIN)) - return -EACCES; if (copy_from_user(&cmd, ucmd, sizeof(cmd))) return -EFAULT; if (cmd.flags) return -EINVAL; + switch (cmd.opcode) { + case nvme_admin_identify: + case nvme_admin_activate_fw: + case nvme_admin_download_fw: + if (!firmware_upgrade_capable()) + return -EACCES; + break; + default: + if (!capable(CAP_SYS_ADMIN)) + return -EACCES; + } + memset(&c, 0, sizeof(c)); c.common.opcode = cmd.opcode; c.common.flags = cmd.flags; @@ -1637,13 +1647,23 @@ static int nvme_user_cmd64(struct nvme_ctrl *ctrl, struct nvme_ns *ns, unsigned timeout = 0; int status; - if (!capable(CAP_SYS_ADMIN)) - return -EACCES; if (copy_from_user(&cmd, ucmd, sizeof(cmd))) return -EFAULT; if (cmd.flags) return -EINVAL; + switch (cmd.opcode) { + case nvme_admin_identify: + case nvme_admin_activate_fw: + case nvme_admin_download_fw: + if (!firmware_upgrade_capable()) + return -EACCES; + break; + default: + if (!capable(CAP_SYS_ADMIN)) + return -EACCES; + } + memset(&c, 0, sizeof(c)); c.common.opcode = cmd.opcode; c.common.flags = cmd.flags; -- 2.25.1
[RFC 1/2] capability: Introduce CAP_FIRMWARE_UPGRADE
Split out permissions specifically for firmware upgrades from CAP_SYS_ADMIN to a new separate capability. This will allow userspace applications that would traditionally have needed CAP_SYS_ADMIN to perform firmware upgrades to have a reduced permission set. Signed-off-by: Mario Limonciello --- include/linux/capability.h | 5 + include/uapi/linux/capability.h | 7 ++- security/selinux/include/classmap.h | 4 ++-- 3 files changed, 13 insertions(+), 3 deletions(-) diff --git a/include/linux/capability.h b/include/linux/capability.h index b2f698915c0f..e9233e217402 100644 --- a/include/linux/capability.h +++ b/include/linux/capability.h @@ -267,6 +267,11 @@ static inline bool checkpoint_restore_ns_capable(struct user_namespace *ns) ns_capable(ns, CAP_SYS_ADMIN); } +static inline bool firmware_upgrade_capable(void) +{ + return capable(CAP_FIRMWARE_UPGRADE) || capable(CAP_SYS_ADMIN); +} + /* audit system wants to get cap info from files as well */ extern int get_vfs_caps_from_disk(const struct dentry *dentry, struct cpu_vfs_cap_data *cpu_caps); diff --git a/include/uapi/linux/capability.h b/include/uapi/linux/capability.h index c6ca33034147..0f204c6a1c0b 100644 --- a/include/uapi/linux/capability.h +++ b/include/uapi/linux/capability.h @@ -275,6 +275,7 @@ struct vfs_ns_cap_data { /* Allow setting encryption key on loopback filesystem */ /* Allow setting zone reclaim policy */ /* Allow everything under CAP_BPF and CAP_PERFMON for backward compatibility */ +/* Allow everything under CAP_FIRMWARE_UPGRADE for backward compatibility */ #define CAP_SYS_ADMIN21 @@ -417,7 +418,11 @@ struct vfs_ns_cap_data { #define CAP_CHECKPOINT_RESTORE 40 -#define CAP_LAST_CAP CAP_CHECKPOINT_RESTORE +/* Allow a device firmware upgrade */ + +#define CAP_FIRMWARE_UPGRADE 41 + +#define CAP_LAST_CAP CAP_FIRMWARE_UPGRADE #define cap_valid(x) ((x) >= 0 && (x) <= CAP_LAST_CAP) diff --git a/security/selinux/include/classmap.h b/security/selinux/include/classmap.h index 40cebde62856..188318eefb41 100644 --- a/security/selinux/include/classmap.h +++ b/security/selinux/include/classmap.h @@ -28,9 +28,9 @@ #define COMMON_CAP2_PERMS "mac_override", "mac_admin", "syslog", \ "wake_alarm", "block_suspend", "audit_read", "perfmon", "bpf", \ - "checkpoint_restore" + "checkpoint_restore", "firmware_upgrade" -#if CAP_LAST_CAP > CAP_CHECKPOINT_RESTORE +#if CAP_LAST_CAP > CAP_FIRMWARE_UPGRADE #error New capability defined, please update COMMON_CAP2_PERMS. #endif -- 2.25.1
[PATCH v2] platform/x86: Move all dell drivers to their own subdirectory
A user without a Dell system doesn't need to pick any of these drivers. Users with a Dell system can enable this submenu and all drivers behind it will be enabled. Suggested-by: Andy Shevchenko Signed-off-by: Mario Limonciello --- Changes from v1->v2: - Rename menu per Andy's suggestion - Move if/endif for menu into subdirectory - Set default for menu to "n" but individual modules to "m" Should be same defaults as previous, but allow an "easy" switch MAINTAINERS | 22 +- drivers/platform/x86/Kconfig | 176 +-- drivers/platform/x86/Makefile | 16 +- drivers/platform/x86/dell/Kconfig | 207 ++ drivers/platform/x86/dell/Makefile| 21 ++ .../platform/x86/{ => dell}/alienware-wmi.c | 0 drivers/platform/x86/{ => dell}/dcdbas.c | 0 drivers/platform/x86/{ => dell}/dcdbas.h | 0 drivers/platform/x86/{ => dell}/dell-laptop.c | 0 drivers/platform/x86/{ => dell}/dell-rbtn.c | 0 drivers/platform/x86/{ => dell}/dell-rbtn.h | 0 .../x86/{ => dell}/dell-smbios-base.c | 0 .../platform/x86/{ => dell}/dell-smbios-smm.c | 0 .../platform/x86/{ => dell}/dell-smbios-wmi.c | 0 drivers/platform/x86/{ => dell}/dell-smbios.h | 0 .../platform/x86/{ => dell}/dell-smo8800.c| 0 .../platform/x86/{ => dell}/dell-wmi-aio.c| 0 .../x86/{ => dell}/dell-wmi-descriptor.c | 0 .../x86/{ => dell}/dell-wmi-descriptor.h | 0 .../platform/x86/{ => dell}/dell-wmi-led.c| 0 .../x86/{ => dell}/dell-wmi-sysman/Makefile | 0 .../dell-wmi-sysman/biosattr-interface.c | 0 .../dell-wmi-sysman/dell-wmi-sysman.h | 0 .../dell-wmi-sysman/enum-attributes.c | 0 .../dell-wmi-sysman/int-attributes.c | 0 .../dell-wmi-sysman/passobj-attributes.c | 0 .../dell-wmi-sysman/passwordattr-interface.c | 0 .../dell-wmi-sysman/string-attributes.c | 0 .../x86/{ => dell}/dell-wmi-sysman/sysman.c | 0 drivers/platform/x86/{ => dell}/dell-wmi.c| 0 drivers/platform/x86/{ => dell}/dell_rbu.c| 0 31 files changed, 241 insertions(+), 201 deletions(-) create mode 100644 drivers/platform/x86/dell/Kconfig create mode 100644 drivers/platform/x86/dell/Makefile rename drivers/platform/x86/{ => dell}/alienware-wmi.c (100%) rename drivers/platform/x86/{ => dell}/dcdbas.c (100%) rename drivers/platform/x86/{ => dell}/dcdbas.h (100%) rename drivers/platform/x86/{ => dell}/dell-laptop.c (100%) rename drivers/platform/x86/{ => dell}/dell-rbtn.c (100%) rename drivers/platform/x86/{ => dell}/dell-rbtn.h (100%) rename drivers/platform/x86/{ => dell}/dell-smbios-base.c (100%) rename drivers/platform/x86/{ => dell}/dell-smbios-smm.c (100%) rename drivers/platform/x86/{ => dell}/dell-smbios-wmi.c (100%) rename drivers/platform/x86/{ => dell}/dell-smbios.h (100%) rename drivers/platform/x86/{ => dell}/dell-smo8800.c (100%) rename drivers/platform/x86/{ => dell}/dell-wmi-aio.c (100%) rename drivers/platform/x86/{ => dell}/dell-wmi-descriptor.c (100%) rename drivers/platform/x86/{ => dell}/dell-wmi-descriptor.h (100%) rename drivers/platform/x86/{ => dell}/dell-wmi-led.c (100%) rename drivers/platform/x86/{ => dell}/dell-wmi-sysman/Makefile (100%) rename drivers/platform/x86/{ => dell}/dell-wmi-sysman/biosattr-interface.c (100%) rename drivers/platform/x86/{ => dell}/dell-wmi-sysman/dell-wmi-sysman.h (100%) rename drivers/platform/x86/{ => dell}/dell-wmi-sysman/enum-attributes.c (100%) rename drivers/platform/x86/{ => dell}/dell-wmi-sysman/int-attributes.c (100%) rename drivers/platform/x86/{ => dell}/dell-wmi-sysman/passobj-attributes.c (100%) rename drivers/platform/x86/{ => dell}/dell-wmi-sysman/passwordattr-interface.c (100%) rename drivers/platform/x86/{ => dell}/dell-wmi-sysman/string-attributes.c (100%) rename drivers/platform/x86/{ => dell}/dell-wmi-sysman/sysman.c (100%) rename drivers/platform/x86/{ => dell}/dell-wmi.c (100%) rename drivers/platform/x86/{ => dell}/dell_rbu.c (100%) diff --git a/MAINTAINERS b/MAINTAINERS index d3e847f7f3dc..ae83c6cff843 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -4970,17 +4970,17 @@ M: Matthew Garrett M: Pali Rohár L: platform-driver-...@vger.kernel.org S: Maintained -F: drivers/platform/x86/dell-laptop.c +F: drivers/platform/x86/dell/dell-laptop.c DELL LAPTOP FREEFALL DRIVER M: Pali Rohár S: Maintained -F: drivers/platform/x86/dell-smo8800.c +F: drivers/platform/x86/dell/dell-smo8800.c DELL LAPTOP RBTN DRIVER M: Pali Rohár S: Maintained -F: drivers/platform/x86/dell-rbtn.* +F: drivers/platform/x86/dell/dell-rbtn.* DELL LAPTOP SMM DRIVER M: Pali Rohár @@ -4992,26 +4992
[PATCH] platform/x86: Move all dell drivers to their own subdirectory
A user without a Dell system doesn't need to pick any of these drivers. Suggested-by: Andy Shevchenko Signed-off-by: Mario Limonciello --- MAINTAINERS | 22 +-- drivers/platform/x86/Kconfig | 182 +- drivers/platform/x86/Makefile | 16 +- drivers/platform/x86/dell/Kconfig | 180 + drivers/platform/x86/dell/Makefile| 21 ++ .../platform/x86/{ => dell}/alienware-wmi.c | 0 drivers/platform/x86/{ => dell}/dcdbas.c | 0 drivers/platform/x86/{ => dell}/dcdbas.h | 0 drivers/platform/x86/{ => dell}/dell-laptop.c | 0 drivers/platform/x86/{ => dell}/dell-rbtn.c | 0 drivers/platform/x86/{ => dell}/dell-rbtn.h | 0 .../x86/{ => dell}/dell-smbios-base.c | 0 .../platform/x86/{ => dell}/dell-smbios-smm.c | 0 .../platform/x86/{ => dell}/dell-smbios-wmi.c | 0 drivers/platform/x86/{ => dell}/dell-smbios.h | 0 .../platform/x86/{ => dell}/dell-smo8800.c| 0 .../platform/x86/{ => dell}/dell-wmi-aio.c| 0 .../x86/{ => dell}/dell-wmi-descriptor.c | 0 .../x86/{ => dell}/dell-wmi-descriptor.h | 0 .../platform/x86/{ => dell}/dell-wmi-led.c| 0 .../x86/{ => dell}/dell-wmi-sysman/Makefile | 0 .../dell-wmi-sysman/biosattr-interface.c | 0 .../dell-wmi-sysman/dell-wmi-sysman.h | 0 .../dell-wmi-sysman/enum-attributes.c | 0 .../dell-wmi-sysman/int-attributes.c | 0 .../dell-wmi-sysman/passobj-attributes.c | 0 .../dell-wmi-sysman/passwordattr-interface.c | 0 .../dell-wmi-sysman/string-attributes.c | 0 .../x86/{ => dell}/dell-wmi-sysman/sysman.c | 0 drivers/platform/x86/{ => dell}/dell-wmi.c| 0 drivers/platform/x86/{ => dell}/dell_rbu.c| 0 31 files changed, 223 insertions(+), 198 deletions(-) create mode 100644 drivers/platform/x86/dell/Kconfig create mode 100644 drivers/platform/x86/dell/Makefile rename drivers/platform/x86/{ => dell}/alienware-wmi.c (100%) rename drivers/platform/x86/{ => dell}/dcdbas.c (100%) rename drivers/platform/x86/{ => dell}/dcdbas.h (100%) rename drivers/platform/x86/{ => dell}/dell-laptop.c (100%) rename drivers/platform/x86/{ => dell}/dell-rbtn.c (100%) rename drivers/platform/x86/{ => dell}/dell-rbtn.h (100%) rename drivers/platform/x86/{ => dell}/dell-smbios-base.c (100%) rename drivers/platform/x86/{ => dell}/dell-smbios-smm.c (100%) rename drivers/platform/x86/{ => dell}/dell-smbios-wmi.c (100%) rename drivers/platform/x86/{ => dell}/dell-smbios.h (100%) rename drivers/platform/x86/{ => dell}/dell-smo8800.c (100%) rename drivers/platform/x86/{ => dell}/dell-wmi-aio.c (100%) rename drivers/platform/x86/{ => dell}/dell-wmi-descriptor.c (100%) rename drivers/platform/x86/{ => dell}/dell-wmi-descriptor.h (100%) rename drivers/platform/x86/{ => dell}/dell-wmi-led.c (100%) rename drivers/platform/x86/{ => dell}/dell-wmi-sysman/Makefile (100%) rename drivers/platform/x86/{ => dell}/dell-wmi-sysman/biosattr-interface.c (100%) rename drivers/platform/x86/{ => dell}/dell-wmi-sysman/dell-wmi-sysman.h (100%) rename drivers/platform/x86/{ => dell}/dell-wmi-sysman/enum-attributes.c (100%) rename drivers/platform/x86/{ => dell}/dell-wmi-sysman/int-attributes.c (100%) rename drivers/platform/x86/{ => dell}/dell-wmi-sysman/passobj-attributes.c (100%) rename drivers/platform/x86/{ => dell}/dell-wmi-sysman/passwordattr-interface.c (100%) rename drivers/platform/x86/{ => dell}/dell-wmi-sysman/string-attributes.c (100%) rename drivers/platform/x86/{ => dell}/dell-wmi-sysman/sysman.c (100%) rename drivers/platform/x86/{ => dell}/dell-wmi.c (100%) rename drivers/platform/x86/{ => dell}/dell_rbu.c (100%) diff --git a/MAINTAINERS b/MAINTAINERS index d3e847f7f3dc..ae83c6cff843 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -4970,17 +4970,17 @@ M: Matthew Garrett M: Pali Rohár L: platform-driver-...@vger.kernel.org S: Maintained -F: drivers/platform/x86/dell-laptop.c +F: drivers/platform/x86/dell/dell-laptop.c DELL LAPTOP FREEFALL DRIVER M: Pali Rohár S: Maintained -F: drivers/platform/x86/dell-smo8800.c +F: drivers/platform/x86/dell/dell-smo8800.c DELL LAPTOP RBTN DRIVER M: Pali Rohár S: Maintained -F: drivers/platform/x86/dell-rbtn.* +F: drivers/platform/x86/dell/dell-rbtn.* DELL LAPTOP SMM DRIVER M: Pali Rohár @@ -4992,26 +4992,26 @@ DELL REMOTE BIOS UPDATE DRIVER M: Stuart Hayes L: platform-driver-...@vger.kernel.org S: Maintained -F: drivers/platform/x86/dell_rbu.c +F: drivers/platform/x86/dell/dell_rbu.c DELL SMBIOS DRIVER M: Pali Rohár M: Mario Limonciello L: platform-driver-...@vger.kernel.org S: Maintained -F: drivers/plat
[PATCH] platform/x86: dell-wmi-sysman: fix a NULL pointer dereference
An upcoming Dell platform is causing a NULL pointer dereference in dell-wmi-sysman initialization. Validate that the input from BIOS matches correct ACPI types and abort module initialization if it fails. This leads to a memory leak that needs to be cleaned up properly. Signed-off-by: Mario Limonciello --- drivers/platform/x86/dell-wmi-sysman/sysman.c | 8 +++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/drivers/platform/x86/dell-wmi-sysman/sysman.c b/drivers/platform/x86/dell-wmi-sysman/sysman.c index dc6dd531c996..38b497991071 100644 --- a/drivers/platform/x86/dell-wmi-sysman/sysman.c +++ b/drivers/platform/x86/dell-wmi-sysman/sysman.c @@ -419,13 +419,19 @@ static int init_bios_attributes(int attr_type, const char *guid) return retval; /* need to use specific instance_id and guid combination to get right data */ obj = get_wmiobj_pointer(instance_id, guid); - if (!obj) + if (!obj || obj->type != ACPI_TYPE_PACKAGE) { + release_attributes_data(); return -ENODEV; + } elements = obj->package.elements; mutex_lock(&wmi_priv.mutex); while (elements) { /* sanity checking */ + if (elements[ATTR_NAME].type != ACPI_TYPE_STRING) { + pr_debug("incorrect element type\n"); + goto nextobj; + } if (strlen(elements[ATTR_NAME].string.pointer) == 0) { pr_debug("empty attribute found\n"); goto nextobj; -- 2.25.1
[PATCH v5 2/4] e1000e: bump up timeout to wait when ME un-configures ULP mode
Per guidance from Intel ethernet architecture team, it may take up to 1 second for unconfiguring ULP mode. However in practice this seems to be taking up to 2 seconds on some Lenovo machines. Detect scenarios that take more than 1 second but less than 2.5 seconds and emit a warning on resume for those scenarios. Suggested-by: Aaron Ma Suggested-by: Sasha Netfin Suggested-by: Hans de Goede CC: Mark Pearson Fixes: f15bb6dde738cc8fa0 ("e1000e: Add support for S0ix") BugLink: https://bugs.launchpad.net/bugs/1865570 Link: https://patchwork.ozlabs.org/project/intel-wired-lan/patch/20200323191639.48826-1-aaron...@canonical.com/ Link: https://lkml.org/lkml/2020/12/13/15 Link: https://lkml.org/lkml/2020/12/14/708 Signed-off-by: Mario Limonciello --- drivers/net/ethernet/intel/e1000e/ich8lan.c | 16 +--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/drivers/net/ethernet/intel/e1000e/ich8lan.c b/drivers/net/ethernet/intel/e1000e/ich8lan.c index 9aa6fad8ed47..fdf23d20c954 100644 --- a/drivers/net/ethernet/intel/e1000e/ich8lan.c +++ b/drivers/net/ethernet/intel/e1000e/ich8lan.c @@ -1240,6 +1240,9 @@ static s32 e1000_disable_ulp_lpt_lp(struct e1000_hw *hw, bool force) return 0; if (er32(FWSM) & E1000_ICH_FWSM_FW_VALID) { + struct e1000_adapter *adapter = hw->adapter; + bool firmware_bug = false; + if (force) { /* Request ME un-configure ULP mode in the PHY */ mac_reg = er32(H2ME); @@ -1248,16 +1251,23 @@ static s32 e1000_disable_ulp_lpt_lp(struct e1000_hw *hw, bool force) ew32(H2ME, mac_reg); } - /* Poll up to 300msec for ME to clear ULP_CFG_DONE. */ + /* Poll up to 2.5 seconds for ME to clear ULP_CFG_DONE. +* If this takes more than 1 second, show a warning indicating a firmware +* bug */ while (er32(FWSM) & E1000_FWSM_ULP_CFG_DONE) { - if (i++ == 30) { + if (i++ == 250) { ret_val = -E1000_ERR_PHY; goto out; } + if (i > 100 && !firmware_bug) + firmware_bug = true; usleep_range(1, 11000); } - e_dbg("ULP_CONFIG_DONE cleared after %dmsec\n", i * 10); + if (firmware_bug) + e_warn("ULP_CONFIG_DONE took %dmsec. This is a firmware bug\n", i * 10); + else + e_dbg("ULP_CONFIG_DONE cleared after %dmsec\n", i * 10); if (force) { mac_reg = er32(H2ME); -- 2.25.1
[PATCH v5 3/4] Revert "e1000e: disable s0ix entry and exit flows for ME systems"
commit e086ba2fccda ("e1000e: disable s0ix entry and exit flows for ME systems") disabled s0ix flows for systems that have various incarnations of the i219-LM ethernet controller. This changed caused power consumption regressions on the following shipping Dell Comet Lake based laptops: * Latitude 5310 * Latitude 5410 * Latitude 5410 * Latitude 5510 * Precision 3550 * Latitude 5411 * Latitude 5511 * Precision 3551 * Precision 7550 * Precision 7750 This commit was introduced because of some regressions on certain Thinkpad laptops. This comment was potentially caused by an earlier commit 632fbd5eb5b0e ("e1000e: fix S0ix flows for cable connected case"). or it was possibly caused by a system not meeting platform architectural requirements for low power consumption. Other changes made in the driver with extended timeouts are expected to make the driver more impervious to platform firmware behavior. Fixes: e086ba2fccda ("e1000e: disable s0ix entry and exit flows for ME systems") Reviewed-by: Alexander Duyck Signed-off-by: Mario Limonciello --- drivers/net/ethernet/intel/e1000e/netdev.c | 45 +- 1 file changed, 2 insertions(+), 43 deletions(-) diff --git a/drivers/net/ethernet/intel/e1000e/netdev.c b/drivers/net/ethernet/intel/e1000e/netdev.c index 6588f5d4a2be..b9800ba2006c 100644 --- a/drivers/net/ethernet/intel/e1000e/netdev.c +++ b/drivers/net/ethernet/intel/e1000e/netdev.c @@ -103,45 +103,6 @@ static const struct e1000_reg_info e1000_reg_info_tbl[] = { {0, NULL} }; -struct e1000e_me_supported { - u16 device_id; /* supported device ID */ -}; - -static const struct e1000e_me_supported me_supported[] = { - {E1000_DEV_ID_PCH_LPT_I217_LM}, - {E1000_DEV_ID_PCH_LPTLP_I218_LM}, - {E1000_DEV_ID_PCH_I218_LM2}, - {E1000_DEV_ID_PCH_I218_LM3}, - {E1000_DEV_ID_PCH_SPT_I219_LM}, - {E1000_DEV_ID_PCH_SPT_I219_LM2}, - {E1000_DEV_ID_PCH_LBG_I219_LM3}, - {E1000_DEV_ID_PCH_SPT_I219_LM4}, - {E1000_DEV_ID_PCH_SPT_I219_LM5}, - {E1000_DEV_ID_PCH_CNP_I219_LM6}, - {E1000_DEV_ID_PCH_CNP_I219_LM7}, - {E1000_DEV_ID_PCH_ICP_I219_LM8}, - {E1000_DEV_ID_PCH_ICP_I219_LM9}, - {E1000_DEV_ID_PCH_CMP_I219_LM10}, - {E1000_DEV_ID_PCH_CMP_I219_LM11}, - {E1000_DEV_ID_PCH_CMP_I219_LM12}, - {E1000_DEV_ID_PCH_TGP_I219_LM13}, - {E1000_DEV_ID_PCH_TGP_I219_LM14}, - {E1000_DEV_ID_PCH_TGP_I219_LM15}, - {0} -}; - -static bool e1000e_check_me(u16 device_id) -{ - struct e1000e_me_supported *id; - - for (id = (struct e1000e_me_supported *)me_supported; -id->device_id; id++) - if (device_id == id->device_id) - return true; - - return false; -} - /** * __ew32_prepare - prepare to write to MAC CSR register on certain parts * @hw: pointer to the HW structure @@ -6974,8 +6935,7 @@ static __maybe_unused int e1000e_pm_suspend(struct device *dev) e1000e_pm_thaw(dev); } else { /* Introduce S0ix implementation */ - if (hw->mac.type >= e1000_pch_cnp && - !e1000e_check_me(hw->adapter->pdev->device)) + if (hw->mac.type >= e1000_pch_cnp) e1000e_s0ix_entry_flow(adapter); } @@ -6991,8 +6951,7 @@ static __maybe_unused int e1000e_pm_resume(struct device *dev) int rc; /* Introduce S0ix implementation */ - if (hw->mac.type >= e1000_pch_cnp && - !e1000e_check_me(hw->adapter->pdev->device)) + if (hw->mac.type >= e1000_pch_cnp) e1000e_s0ix_exit_flow(adapter); rc = __e1000_resume(pdev); -- 2.25.1
[PATCH v5 1/4] e1000e: Only run S0ix flows if shutdown succeeded
If the shutdown failed, the part will be thawed and running S0ix flows will put it into an undefined state. Reported-by: Alexander Duyck Reviewed-by: Alexander Duyck Signed-off-by: Mario Limonciello --- drivers/net/ethernet/intel/e1000e/netdev.c | 13 +++-- 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/drivers/net/ethernet/intel/e1000e/netdev.c b/drivers/net/ethernet/intel/e1000e/netdev.c index 128ab6898070..6588f5d4a2be 100644 --- a/drivers/net/ethernet/intel/e1000e/netdev.c +++ b/drivers/net/ethernet/intel/e1000e/netdev.c @@ -6970,13 +6970,14 @@ static __maybe_unused int e1000e_pm_suspend(struct device *dev) e1000e_pm_freeze(dev); rc = __e1000_shutdown(pdev, false); - if (rc) + if (rc) { e1000e_pm_thaw(dev); - - /* Introduce S0ix implementation */ - if (hw->mac.type >= e1000_pch_cnp && - !e1000e_check_me(hw->adapter->pdev->device)) - e1000e_s0ix_entry_flow(adapter); + } else { + /* Introduce S0ix implementation */ + if (hw->mac.type >= e1000_pch_cnp && + !e1000e_check_me(hw->adapter->pdev->device)) + e1000e_s0ix_entry_flow(adapter); + } return rc; } -- 2.25.1
[PATCH v5 4/4] e1000e: Export S0ix flags to ethtool
This flag can be used by an end user to disable S0ix flows on a buggy system or by an OEM for development purposes. If you need this flag to be persisted across reboots, it's suggested to use a udev rule to call adjust it until the kernel could have your configuration in a disallow list. Signed-off-by: Mario Limonciello --- drivers/net/ethernet/intel/e1000e/e1000.h | 1 + drivers/net/ethernet/intel/e1000e/ethtool.c | 46 + drivers/net/ethernet/intel/e1000e/netdev.c | 9 ++-- 3 files changed, 52 insertions(+), 4 deletions(-) diff --git a/drivers/net/ethernet/intel/e1000e/e1000.h b/drivers/net/ethernet/intel/e1000e/e1000.h index ba7a0f8f6937..5b2143f4b1f8 100644 --- a/drivers/net/ethernet/intel/e1000e/e1000.h +++ b/drivers/net/ethernet/intel/e1000e/e1000.h @@ -436,6 +436,7 @@ s32 e1000e_get_base_timinca(struct e1000_adapter *adapter, u32 *timinca); #define FLAG2_DFLT_CRC_STRIPPING BIT(12) #define FLAG2_CHECK_RX_HWTSTAMP BIT(13) #define FLAG2_CHECK_SYSTIM_OVERFLOW BIT(14) +#define FLAG2_ENABLE_S0IX_FLOWS BIT(15) #define E1000_RX_DESC_PS(R, i) \ (&(((union e1000_rx_desc_packet_split *)((R).desc))[i])) diff --git a/drivers/net/ethernet/intel/e1000e/ethtool.c b/drivers/net/ethernet/intel/e1000e/ethtool.c index 03215b0aee4b..06442e6bef73 100644 --- a/drivers/net/ethernet/intel/e1000e/ethtool.c +++ b/drivers/net/ethernet/intel/e1000e/ethtool.c @@ -23,6 +23,13 @@ struct e1000_stats { int stat_offset; }; +static const char e1000e_priv_flags_strings[][ETH_GSTRING_LEN] = { +#define E1000E_PRIV_FLAGS_S0IX_ENABLED BIT(0) + "s0ix-enabled", +}; + +#define E1000E_PRIV_FLAGS_STR_LEN ARRAY_SIZE(e1000e_priv_flags_strings) + #define E1000_STAT(str, m) { \ .stat_string = str, \ .type = E1000_STATS, \ @@ -1776,6 +1783,8 @@ static int e1000e_get_sset_count(struct net_device __always_unused *netdev, return E1000_TEST_LEN; case ETH_SS_STATS: return E1000_STATS_LEN; + case ETH_SS_PRIV_FLAGS: + return E1000E_PRIV_FLAGS_STR_LEN; default: return -EOPNOTSUPP; } @@ -2097,6 +2106,10 @@ static void e1000_get_strings(struct net_device __always_unused *netdev, p += ETH_GSTRING_LEN; } break; + case ETH_SS_PRIV_FLAGS: + memcpy(data, e1000e_priv_flags_strings, + E1000E_PRIV_FLAGS_STR_LEN * ETH_GSTRING_LEN); + break; } } @@ -2305,6 +2318,37 @@ static int e1000e_get_ts_info(struct net_device *netdev, return 0; } +static u32 e1000e_get_priv_flags(struct net_device *netdev) +{ + struct e1000_adapter *adapter = netdev_priv(netdev); + u32 priv_flags = 0; + + if (adapter->flags2 & FLAG2_ENABLE_S0IX_FLOWS) + priv_flags |= E1000E_PRIV_FLAGS_S0IX_ENABLED; + + return priv_flags; +} + +static int e1000e_set_priv_flags(struct net_device *netdev, u32 priv_flags) +{ + struct e1000_adapter *adapter = netdev_priv(netdev); + unsigned int flags2 = adapter->flags2; + + flags2 &= ~FLAG2_ENABLE_S0IX_FLOWS; + if (priv_flags & E1000E_PRIV_FLAGS_S0IX_ENABLED) { + struct e1000_hw *hw = &adapter->hw; + + if (hw->mac.type < e1000_pch_cnp) + return -EINVAL; + flags2 |= FLAG2_ENABLE_S0IX_FLOWS; + } + + if (flags2 != adapter->flags2) + adapter->flags2 = flags2; + + return 0; +} + static const struct ethtool_ops e1000_ethtool_ops = { .supported_coalesce_params = ETHTOOL_COALESCE_RX_USECS, .get_drvinfo= e1000_get_drvinfo, @@ -2336,6 +2380,8 @@ static const struct ethtool_ops e1000_ethtool_ops = { .set_eee= e1000e_set_eee, .get_link_ksettings = e1000_get_link_ksettings, .set_link_ksettings = e1000_set_link_ksettings, + .get_priv_flags = e1000e_get_priv_flags, + .set_priv_flags = e1000e_set_priv_flags, }; void e1000e_set_ethtool_ops(struct net_device *netdev) diff --git a/drivers/net/ethernet/intel/e1000e/netdev.c b/drivers/net/ethernet/intel/e1000e/netdev.c index b9800ba2006c..e9b82c209c2d 100644 --- a/drivers/net/ethernet/intel/e1000e/netdev.c +++ b/drivers/net/ethernet/intel/e1000e/netdev.c @@ -6923,7 +6923,6 @@ static __maybe_unused int e1000e_pm_suspend(struct device *dev) struct net_device *netdev = pci_get_drvdata(to_pci_dev(dev)); struct e1000_adapter *adapter = netdev_priv(netdev); struct pci_dev *pdev = to_pci_dev(dev); - struct e1000_hw *hw = &adapter->hw; int rc; e1000e_flush_lpic(pdev); @@ -6935,7 +6934,7 @@ static __maybe_unused int e1000e_pm_suspend(struct device *dev) e1000e_pm_thaw(dev); } else {
[PATCH v5 0/4] Improve s0ix flows for systems i219LM
commit e086ba2fccda ("e1000e: disable s0ix entry and exit flows for ME systems") disabled s0ix flows for systems that have various incarnations of the i219-LM ethernet controller. This was done because of some regressions caused by an earlier commit 632fbd5eb5b0e ("e1000e: fix S0ix flows for cable connected case") with i219-LM controller. Per discussion with Intel architecture team this direction should be changed and allow S0ix flows to be used by default. This patch series includes directional changes for their conclusions in https://lkml.org/lkml/2020/12/13/15. Changes from v4 to v5: - If setting S0ix to enabled in ethtool examine the hardware generation. If running on hardware older than Cannon Point return an error. - Increase ULP timeout to 2.5 seconds, but show a warning after 1 second. Changes from v3 to v4: - Drop patch 1 for proper s0i3.2 entry, it was separated and is now merged in kernel - Add patch to only run S0ix flows if shutdown succeeded which was suggested in thread - Adjust series for guidance from https://lkml.org/lkml/2020/12/13/15 * Revert i219-LM disallow-list. * Drop all patches for systems tested by Dell in an allow list * Increase ULP timeout to 1000ms Changes from v2 to v3: - Correct some grammar and spelling issues caught by Bjorn H. * s/s0ix/S0ix/ in all commit messages * Fix a typo in commit message * Fix capitalization of proper nouns - Add more pre-release systems that pass - Re-order the series to add systems only at the end of the series - Add Fixes tag to a patch in series. Changes from v1 to v2: - Directly incorporate Vitaly's dependency patch in the series - Split out s0ix code into it's own file - Adjust from DMI matching to PCI subsystem vendor ID/device matching - Remove module parameter and sysfs, use ethtool flag instead. - Export s0ix flag to ethtool private flags - Include more people and lists directly in this submission chain. Mario Limonciello (4): e1000e: Only run S0ix flows if shutdown succeeded e1000e: bump up timeout to wait when ME un-configures ULP mode Revert "e1000e: disable s0ix entry and exit flows for ME systems" e1000e: Export S0ix flags to ethtool drivers/net/ethernet/intel/e1000e/e1000.h | 1 + drivers/net/ethernet/intel/e1000e/ethtool.c | 46 drivers/net/ethernet/intel/e1000e/ich8lan.c | 16 -- drivers/net/ethernet/intel/e1000e/netdev.c | 59 - 4 files changed, 70 insertions(+), 52 deletions(-) -- 2.25.1
[PATCH 3/4] Revert "e1000e: disable s0ix entry and exit flows for ME systems"
commit e086ba2fccda ("e1000e: disable s0ix entry and exit flows for ME systems") disabled s0ix flows for systems that have various incarnations of the i219-LM ethernet controller. This changed caused power consumption regressions on the following shipping Dell Comet Lake based laptops: * Latitude 5310 * Latitude 5410 * Latitude 5410 * Latitude 5510 * Precision 3550 * Latitude 5411 * Latitude 5511 * Precision 3551 * Precision 7550 * Precision 7750 This commit was introduced because of some regressions on certain Thinkpad laptops. This comment was potentially caused by an earlier commit 632fbd5eb5b0e ("e1000e: fix S0ix flows for cable connected case"). or it was possibly caused by a system not meeting platform architectural requirements for low power consumption. Other changes made in the driver with extended timeouts are expected to make the driver more impervious to platform firmware behavior. Fixes: e086ba2fccda ("e1000e: disable s0ix entry and exit flows for ME systems") Signed-off-by: Mario Limonciello --- drivers/net/ethernet/intel/e1000e/netdev.c | 45 +- 1 file changed, 2 insertions(+), 43 deletions(-) diff --git a/drivers/net/ethernet/intel/e1000e/netdev.c b/drivers/net/ethernet/intel/e1000e/netdev.c index 6588f5d4a2be..b9800ba2006c 100644 --- a/drivers/net/ethernet/intel/e1000e/netdev.c +++ b/drivers/net/ethernet/intel/e1000e/netdev.c @@ -103,45 +103,6 @@ static const struct e1000_reg_info e1000_reg_info_tbl[] = { {0, NULL} }; -struct e1000e_me_supported { - u16 device_id; /* supported device ID */ -}; - -static const struct e1000e_me_supported me_supported[] = { - {E1000_DEV_ID_PCH_LPT_I217_LM}, - {E1000_DEV_ID_PCH_LPTLP_I218_LM}, - {E1000_DEV_ID_PCH_I218_LM2}, - {E1000_DEV_ID_PCH_I218_LM3}, - {E1000_DEV_ID_PCH_SPT_I219_LM}, - {E1000_DEV_ID_PCH_SPT_I219_LM2}, - {E1000_DEV_ID_PCH_LBG_I219_LM3}, - {E1000_DEV_ID_PCH_SPT_I219_LM4}, - {E1000_DEV_ID_PCH_SPT_I219_LM5}, - {E1000_DEV_ID_PCH_CNP_I219_LM6}, - {E1000_DEV_ID_PCH_CNP_I219_LM7}, - {E1000_DEV_ID_PCH_ICP_I219_LM8}, - {E1000_DEV_ID_PCH_ICP_I219_LM9}, - {E1000_DEV_ID_PCH_CMP_I219_LM10}, - {E1000_DEV_ID_PCH_CMP_I219_LM11}, - {E1000_DEV_ID_PCH_CMP_I219_LM12}, - {E1000_DEV_ID_PCH_TGP_I219_LM13}, - {E1000_DEV_ID_PCH_TGP_I219_LM14}, - {E1000_DEV_ID_PCH_TGP_I219_LM15}, - {0} -}; - -static bool e1000e_check_me(u16 device_id) -{ - struct e1000e_me_supported *id; - - for (id = (struct e1000e_me_supported *)me_supported; -id->device_id; id++) - if (device_id == id->device_id) - return true; - - return false; -} - /** * __ew32_prepare - prepare to write to MAC CSR register on certain parts * @hw: pointer to the HW structure @@ -6974,8 +6935,7 @@ static __maybe_unused int e1000e_pm_suspend(struct device *dev) e1000e_pm_thaw(dev); } else { /* Introduce S0ix implementation */ - if (hw->mac.type >= e1000_pch_cnp && - !e1000e_check_me(hw->adapter->pdev->device)) + if (hw->mac.type >= e1000_pch_cnp) e1000e_s0ix_entry_flow(adapter); } @@ -6991,8 +6951,7 @@ static __maybe_unused int e1000e_pm_resume(struct device *dev) int rc; /* Introduce S0ix implementation */ - if (hw->mac.type >= e1000_pch_cnp && - !e1000e_check_me(hw->adapter->pdev->device)) + if (hw->mac.type >= e1000_pch_cnp) e1000e_s0ix_exit_flow(adapter); rc = __e1000_resume(pdev); -- 2.25.1
[PATCH v4 0/4] Improve s0ix flows for systems i219LM
commit e086ba2fccda ("e1000e: disable s0ix entry and exit flows for ME systems") disabled s0ix flows for systems that have various incarnations of the i219-LM ethernet controller. This was done because of some regressions caused by an earlier commit 632fbd5eb5b0e ("e1000e: fix S0ix flows for cable connected case") with i219-LM controller. Per discussion with Intel architecture team this direction should be changed and allow S0ix flows to be used by default. This patch series includes directional changes for their conclusions in https://lkml.org/lkml/2020/12/13/15. Changes from v3 to v4: - Drop patch 1 for proper s0i3.2 entry, it was separated and is now merged in kernel - Add patch to only run S0ix flows if shutdown succeeded which was suggested in thread - Adjust series for guidance from https://lkml.org/lkml/2020/12/13/15 * Revert i219-LM disallow-list. * Drop all patches for systems tested by Dell in an allow list * Increase ULP timeout to 1000ms Changes from v2 to v3: - Correct some grammar and spelling issues caught by Bjorn H. * s/s0ix/S0ix/ in all commit messages * Fix a typo in commit message * Fix capitalization of proper nouns - Add more pre-release systems that pass - Re-order the series to add systems only at the end of the series - Add Fixes tag to a patch in series. Changes from v1 to v2: - Directly incorporate Vitaly's dependency patch in the series - Split out s0ix code into it's own file - Adjust from DMI matching to PCI subsystem vendor ID/device matching - Remove module parameter and sysfs, use ethtool flag instead. - Export s0ix flag to ethtool private flags - Include more people and lists directly in this submission chain. Mario Limonciello (4): e1000e: Only run S0ix flows if shutdown succeeded e1000e: bump up timeout to wait when ME un-configure ULP mode Revert "e1000e: disable s0ix entry and exit flows for ME systems" e1000e: Export S0ix flags to ethtool drivers/net/ethernet/intel/e1000e/e1000.h | 1 + drivers/net/ethernet/intel/e1000e/ethtool.c | 40 ++ drivers/net/ethernet/intel/e1000e/ich8lan.c | 4 +- drivers/net/ethernet/intel/e1000e/netdev.c | 59 - 4 files changed, 53 insertions(+), 51 deletions(-) -- 2.25.1
[PATCH 1/4] e1000e: Only run S0ix flows if shutdown succeeded
If the shutdown failed, the part will be thawed and running S0ix flows will put it into an undefined state. Reported-by: Alexander Duyck Signed-off-by: Mario Limonciello --- drivers/net/ethernet/intel/e1000e/netdev.c | 13 +++-- 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/drivers/net/ethernet/intel/e1000e/netdev.c b/drivers/net/ethernet/intel/e1000e/netdev.c index 128ab6898070..6588f5d4a2be 100644 --- a/drivers/net/ethernet/intel/e1000e/netdev.c +++ b/drivers/net/ethernet/intel/e1000e/netdev.c @@ -6970,13 +6970,14 @@ static __maybe_unused int e1000e_pm_suspend(struct device *dev) e1000e_pm_freeze(dev); rc = __e1000_shutdown(pdev, false); - if (rc) + if (rc) { e1000e_pm_thaw(dev); - - /* Introduce S0ix implementation */ - if (hw->mac.type >= e1000_pch_cnp && - !e1000e_check_me(hw->adapter->pdev->device)) - e1000e_s0ix_entry_flow(adapter); + } else { + /* Introduce S0ix implementation */ + if (hw->mac.type >= e1000_pch_cnp && + !e1000e_check_me(hw->adapter->pdev->device)) + e1000e_s0ix_entry_flow(adapter); + } return rc; } -- 2.25.1
[PATCH 2/4] e1000e: bump up timeout to wait when ME un-configure ULP mode
Per guidance from Intel ethernet architecture team, it may take up to 1 second for unconfiguring ULP mode. Suggested-by: Aaron Ma Suggested-by: Sasha Netfin Fixes: f15bb6dde738cc8fa0 ("e1000e: Add support for S0ix") BugLink: https://bugs.launchpad.net/bugs/1865570 Link: https://patchwork.ozlabs.org/project/intel-wired-lan/patch/20200323191639.48826-1-aaron...@canonical.com/ Link: https://lkml.org/lkml/2020/12/13/15 Signed-off-by: Mario Limonciello --- drivers/net/ethernet/intel/e1000e/ich8lan.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/intel/e1000e/ich8lan.c b/drivers/net/ethernet/intel/e1000e/ich8lan.c index 9aa6fad8ed47..4621d01e8a24 100644 --- a/drivers/net/ethernet/intel/e1000e/ich8lan.c +++ b/drivers/net/ethernet/intel/e1000e/ich8lan.c @@ -1248,9 +1248,9 @@ static s32 e1000_disable_ulp_lpt_lp(struct e1000_hw *hw, bool force) ew32(H2ME, mac_reg); } - /* Poll up to 300msec for ME to clear ULP_CFG_DONE. */ + /* Poll up to 1 second for ME to clear ULP_CFG_DONE. */ while (er32(FWSM) & E1000_FWSM_ULP_CFG_DONE) { - if (i++ == 30) { + if (i++ == 100) { ret_val = -E1000_ERR_PHY; goto out; } -- 2.25.1
[PATCH 4/4] e1000e: Export S0ix flags to ethtool
This flag can be used by an end user to disable S0ix flows on a buggy system or by an OEM for development purposes. If you need this flag to be persisted across reboots, it's suggested to use a udev rule to call adjust it until the kernel could have your configuration in a disallow list. Signed-off-by: Mario Limonciello --- drivers/net/ethernet/intel/e1000e/e1000.h | 1 + drivers/net/ethernet/intel/e1000e/ethtool.c | 40 + drivers/net/ethernet/intel/e1000e/netdev.c | 9 ++--- 3 files changed, 46 insertions(+), 4 deletions(-) diff --git a/drivers/net/ethernet/intel/e1000e/e1000.h b/drivers/net/ethernet/intel/e1000e/e1000.h index ba7a0f8f6937..5b2143f4b1f8 100644 --- a/drivers/net/ethernet/intel/e1000e/e1000.h +++ b/drivers/net/ethernet/intel/e1000e/e1000.h @@ -436,6 +436,7 @@ s32 e1000e_get_base_timinca(struct e1000_adapter *adapter, u32 *timinca); #define FLAG2_DFLT_CRC_STRIPPING BIT(12) #define FLAG2_CHECK_RX_HWTSTAMP BIT(13) #define FLAG2_CHECK_SYSTIM_OVERFLOW BIT(14) +#define FLAG2_ENABLE_S0IX_FLOWS BIT(15) #define E1000_RX_DESC_PS(R, i) \ (&(((union e1000_rx_desc_packet_split *)((R).desc))[i])) diff --git a/drivers/net/ethernet/intel/e1000e/ethtool.c b/drivers/net/ethernet/intel/e1000e/ethtool.c index 03215b0aee4b..eb683949ebfe 100644 --- a/drivers/net/ethernet/intel/e1000e/ethtool.c +++ b/drivers/net/ethernet/intel/e1000e/ethtool.c @@ -23,6 +23,13 @@ struct e1000_stats { int stat_offset; }; +static const char e1000e_priv_flags_strings[][ETH_GSTRING_LEN] = { +#define E1000E_PRIV_FLAGS_S0IX_ENABLED BIT(0) + "s0ix-enabled", +}; + +#define E1000E_PRIV_FLAGS_STR_LEN ARRAY_SIZE(e1000e_priv_flags_strings) + #define E1000_STAT(str, m) { \ .stat_string = str, \ .type = E1000_STATS, \ @@ -1776,6 +1783,8 @@ static int e1000e_get_sset_count(struct net_device __always_unused *netdev, return E1000_TEST_LEN; case ETH_SS_STATS: return E1000_STATS_LEN; + case ETH_SS_PRIV_FLAGS: + return E1000E_PRIV_FLAGS_STR_LEN; default: return -EOPNOTSUPP; } @@ -2097,6 +2106,10 @@ static void e1000_get_strings(struct net_device __always_unused *netdev, p += ETH_GSTRING_LEN; } break; + case ETH_SS_PRIV_FLAGS: + memcpy(data, e1000e_priv_flags_strings, + E1000E_PRIV_FLAGS_STR_LEN * ETH_GSTRING_LEN); + break; } } @@ -2305,6 +2318,31 @@ static int e1000e_get_ts_info(struct net_device *netdev, return 0; } +static u32 e1000e_get_priv_flags(struct net_device *netdev) +{ + struct e1000_adapter *adapter = netdev_priv(netdev); + u32 priv_flags = 0; + + if (adapter->flags2 & FLAG2_ENABLE_S0IX_FLOWS) + priv_flags |= E1000E_PRIV_FLAGS_S0IX_ENABLED; + + return priv_flags; +} + +static int e1000e_set_priv_flags(struct net_device *netdev, u32 priv_flags) +{ + struct e1000_adapter *adapter = netdev_priv(netdev); + unsigned int flags2 = adapter->flags2; + + flags2 &= ~FLAG2_ENABLE_S0IX_FLOWS; + if (priv_flags & E1000E_PRIV_FLAGS_S0IX_ENABLED) + flags2 |= FLAG2_ENABLE_S0IX_FLOWS; + if (flags2 != adapter->flags2) + adapter->flags2 = flags2; + + return 0; +} + static const struct ethtool_ops e1000_ethtool_ops = { .supported_coalesce_params = ETHTOOL_COALESCE_RX_USECS, .get_drvinfo= e1000_get_drvinfo, @@ -2336,6 +2374,8 @@ static const struct ethtool_ops e1000_ethtool_ops = { .set_eee= e1000e_set_eee, .get_link_ksettings = e1000_get_link_ksettings, .set_link_ksettings = e1000_set_link_ksettings, + .get_priv_flags = e1000e_get_priv_flags, + .set_priv_flags = e1000e_set_priv_flags, }; void e1000e_set_ethtool_ops(struct net_device *netdev) diff --git a/drivers/net/ethernet/intel/e1000e/netdev.c b/drivers/net/ethernet/intel/e1000e/netdev.c index b9800ba2006c..e9b82c209c2d 100644 --- a/drivers/net/ethernet/intel/e1000e/netdev.c +++ b/drivers/net/ethernet/intel/e1000e/netdev.c @@ -6923,7 +6923,6 @@ static __maybe_unused int e1000e_pm_suspend(struct device *dev) struct net_device *netdev = pci_get_drvdata(to_pci_dev(dev)); struct e1000_adapter *adapter = netdev_priv(netdev); struct pci_dev *pdev = to_pci_dev(dev); - struct e1000_hw *hw = &adapter->hw; int rc; e1000e_flush_lpic(pdev); @@ -6935,7 +6934,7 @@ static __maybe_unused int e1000e_pm_suspend(struct device *dev) e1000e_pm_thaw(dev); } else { /* Introduce S0ix implementation */ - if (hw->mac.type >= e1000_pch_cnp) + if (adapter->flags2 & FLAG2_ENABLE_S0I
[PATCH RESEND] e1000e: fix S0ix flow to allow S0i3.2 subset entry
From: Vitaly Lifshits Changed a configuration in the flows to align with architecture requirements to achieve S0i3.2 substate. This helps both i219V and i219LM configurations. Also fixed a typo in the previous commit 632fbd5eb5b0 ("e1000e: fix S0ix flows for cable connected case"). Fixes: 632fbd5eb5b0 ("e1000e: fix S0ix flows for cable connected case"). Signed-off-by: Vitaly Lifshits Tested-by: Aaron Brown Signed-off-by: Tony Nguyen Reviewed-by: Alexander Duyck Signed-off-by: Mario Limonciello --- This patch was originally part of https://marc.info/?l=linux-netdev&m=160677194809564&w=2 which requested fixes. It was then resubmitted as part of: https://patchwork.ozlabs.org/project/netdev/list/?series=218712 However there is discussion on the other patches of the series. As it fixes existing hardware that is not blocked by ME check (i219V) resubmit it separately to at least fix that hardware. drivers/net/ethernet/intel/e1000e/netdev.c | 8 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/net/ethernet/intel/e1000e/netdev.c b/drivers/net/ethernet/intel/e1000e/netdev.c index 3ecd05b28fe6..6588f5d4a2be 100644 --- a/drivers/net/ethernet/intel/e1000e/netdev.c +++ b/drivers/net/ethernet/intel/e1000e/netdev.c @@ -6475,13 +6475,13 @@ static void e1000e_s0ix_entry_flow(struct e1000_adapter *adapter) /* Ungate PGCB clock */ mac_data = er32(FEXTNVM9); - mac_data |= BIT(28); + mac_data &= ~BIT(28); ew32(FEXTNVM9, mac_data); /* Enable K1 off to enable mPHY Power Gating */ mac_data = er32(FEXTNVM6); mac_data |= BIT(31); - ew32(FEXTNVM12, mac_data); + ew32(FEXTNVM6, mac_data); /* Enable mPHY power gating for any link and speed */ mac_data = er32(FEXTNVM8); @@ -6525,11 +6525,11 @@ static void e1000e_s0ix_exit_flow(struct e1000_adapter *adapter) /* Disable K1 off */ mac_data = er32(FEXTNVM6); mac_data &= ~BIT(31); - ew32(FEXTNVM12, mac_data); + ew32(FEXTNVM6, mac_data); /* Disable Ungate PGCB clock */ mac_data = er32(FEXTNVM9); - mac_data &= ~BIT(28); + mac_data |= BIT(28); ew32(FEXTNVM9, mac_data); /* Cancel not waking from dynamic -- 2.25.1
Re: [PATCH v3 1/7] e1000e: fix S0ix flow to allow S0i3.2 subset entry
On 12/4/20 2:09 PM, Mario Limonciello wrote: From: Vitaly Lifshits Changed a configuration in the flows to align with architecture requirements to achieve S0i3.2 substate. Also fixed a typo in the previous commit 632fbd5eb5b0 ("e1000e: fix S0ix flows for cable connected case"). Signed-off-by: Vitaly Lifshits Tested-by: Aaron Brown Signed-off-by: Tony Nguyen --- drivers/net/ethernet/intel/e1000e/netdev.c | 8 1 file changed, 4 insertions(+), 4 deletions(-) I realize that the series is still under discussion, but I intentionally moved this patch to the front of the series so it can be pulled in even if the others are still discussed. @David Miller: This particular patch is more important than the rest. It actually fixes issues on the non-ME i219V as well. Can this one be queued up and we can keep discussing the rest? diff --git a/drivers/net/ethernet/intel/e1000e/netdev.c b/drivers/net/ethernet/intel/e1000e/netdev.c index b30f00891c03..128ab6898070 100644 --- a/drivers/net/ethernet/intel/e1000e/netdev.c +++ b/drivers/net/ethernet/intel/e1000e/netdev.c @@ -6475,13 +6475,13 @@ static void e1000e_s0ix_entry_flow(struct e1000_adapter *adapter) /* Ungate PGCB clock */ mac_data = er32(FEXTNVM9); - mac_data |= BIT(28); + mac_data &= ~BIT(28); ew32(FEXTNVM9, mac_data); /* Enable K1 off to enable mPHY Power Gating */ mac_data = er32(FEXTNVM6); mac_data |= BIT(31); - ew32(FEXTNVM12, mac_data); + ew32(FEXTNVM6, mac_data); /* Enable mPHY power gating for any link and speed */ mac_data = er32(FEXTNVM8); @@ -6525,11 +6525,11 @@ static void e1000e_s0ix_exit_flow(struct e1000_adapter *adapter) /* Disable K1 off */ mac_data = er32(FEXTNVM6); mac_data &= ~BIT(31); - ew32(FEXTNVM12, mac_data); + ew32(FEXTNVM6, mac_data); /* Disable Ungate PGCB clock */ mac_data = er32(FEXTNVM9); - mac_data &= ~BIT(28); + mac_data |= BIT(28); ew32(FEXTNVM9, mac_data); /* Cancel not waking from dynamic -- *Mario Limonciello* *Dell*| CPG Software Engineering *office*+1 512 723 0582
[PATCH v3 6/7] e1000e: Add Dell TGL desktop systems into S0ix heuristics
These Tiger Lake systems are not yet released, but have been validated on pre-release hardware. This is being submitted separately from released hardware in case of a regression between pre-release and release hardware so this commit can be reverted alone. Signed-off-by: Mario Limonciello --- drivers/net/ethernet/intel/e1000e/s0ix.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/net/ethernet/intel/e1000e/s0ix.c b/drivers/net/ethernet/intel/e1000e/s0ix.c index 0dd2e2702ebb..cc04aeaa2292 100644 --- a/drivers/net/ethernet/intel/e1000e/s0ix.c +++ b/drivers/net/ethernet/intel/e1000e/s0ix.c @@ -63,6 +63,8 @@ static bool e1000e_check_subsystem_allowlist(struct pci_dev *dev) case 0x0a40: /* Notebook 0x0a40 */ case 0x0a41: /* Notebook 0x0a41 */ case 0x0a42: /* Notebook 0x0a42 */ + case 0x0a2e: /* Desktop 0x0a2e */ + case 0x0a30: /* Desktop 0x0a30 */ return true; } } -- 2.25.1
[PATCH v3 0/7] Improve s0ix flows for systems i219LM
commit e086ba2fccda ("e1000e: disable s0ix entry and exit flows for ME systems") disabled s0ix flows for systems that have various incarnations of the i219-LM ethernet controller. This was done because of some regressions caused by an earlier commit 632fbd5eb5b0e ("e1000e: fix S0ix flows for cable connected case") with i219-LM controller. Performing suspend to idle with these ethernet controllers requires a properly configured system. To make enabling such systems easier, this patch series allows determining if enabled and turning on using ethtool. The flows have also been confirmed to be configured correctly on Dell's Latitude and Precision CML systems containing the i219-LM controller, when the kernel also contains the fix for s0i3.2 entry previously submitted here and now part of this series. https://marc.info/?l=linux-netdev&m=160677194809564&w=2 Patches 4 through 7 will turn the behavior on by default for some of Dell's CML and TGL systems. Changes from v2 to v3: - Correct some grammar and spelling issues caught by Bjorn H. * s/s0ix/S0ix/ in all commit messages * Fix a typo in commit message * Fix capitalization of proper nouns - Add more pre-release systems that pass - Re-order the series to add systems only at the end of the series - Add Fixes tag to a patch in series. Changes from v1 to v2: - Directly incorporate Vitaly's dependency patch in the series - Split out s0ix code into it's own file - Adjust from DMI matching to PCI subsystem vendor ID/device matching - Remove module parameter and sysfs, use ethtool flag instead. - Export s0ix flag to ethtool private flags - Include more people and lists directly in this submission chain. Mario Limonciello (6): e1000e: Move all S0ix related code into its own source file e1000e: Export S0ix flags to ethtool e1000e: Add Dell's Comet Lake systems into S0ix heuristics e1000e: Add more Dell CML systems into S0ix heuristics e1000e: Add Dell TGL desktop systems into S0ix heuristics e1000e: Add another Dell TGL notebook system into S0ix heuristics Vitaly Lifshits (1): e1000e: fix S0ix flow to allow S0i3.2 subset entry drivers/net/ethernet/intel/e1000e/Makefile | 2 +- drivers/net/ethernet/intel/e1000e/e1000.h | 4 + drivers/net/ethernet/intel/e1000e/ethtool.c | 40 +++ drivers/net/ethernet/intel/e1000e/netdev.c | 272 + drivers/net/ethernet/intel/e1000e/s0ix.c| 311 5 files changed, 361 insertions(+), 268 deletions(-) create mode 100644 drivers/net/ethernet/intel/e1000e/s0ix.c -- 2.25.1
[PATCH v3 1/7] e1000e: fix S0ix flow to allow S0i3.2 subset entry
From: Vitaly Lifshits Changed a configuration in the flows to align with architecture requirements to achieve S0i3.2 substate. Also fixed a typo in the previous commit 632fbd5eb5b0 ("e1000e: fix S0ix flows for cable connected case"). Signed-off-by: Vitaly Lifshits Tested-by: Aaron Brown Signed-off-by: Tony Nguyen --- drivers/net/ethernet/intel/e1000e/netdev.c | 8 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/net/ethernet/intel/e1000e/netdev.c b/drivers/net/ethernet/intel/e1000e/netdev.c index b30f00891c03..128ab6898070 100644 --- a/drivers/net/ethernet/intel/e1000e/netdev.c +++ b/drivers/net/ethernet/intel/e1000e/netdev.c @@ -6475,13 +6475,13 @@ static void e1000e_s0ix_entry_flow(struct e1000_adapter *adapter) /* Ungate PGCB clock */ mac_data = er32(FEXTNVM9); - mac_data |= BIT(28); + mac_data &= ~BIT(28); ew32(FEXTNVM9, mac_data); /* Enable K1 off to enable mPHY Power Gating */ mac_data = er32(FEXTNVM6); mac_data |= BIT(31); - ew32(FEXTNVM12, mac_data); + ew32(FEXTNVM6, mac_data); /* Enable mPHY power gating for any link and speed */ mac_data = er32(FEXTNVM8); @@ -6525,11 +6525,11 @@ static void e1000e_s0ix_exit_flow(struct e1000_adapter *adapter) /* Disable K1 off */ mac_data = er32(FEXTNVM6); mac_data &= ~BIT(31); - ew32(FEXTNVM12, mac_data); + ew32(FEXTNVM6, mac_data); /* Disable Ungate PGCB clock */ mac_data = er32(FEXTNVM9); - mac_data &= ~BIT(28); + mac_data |= BIT(28); ew32(FEXTNVM9, mac_data); /* Cancel not waking from dynamic -- 2.25.1
[PATCH v3 5/7] e1000e: Add more Dell CML systems into S0ix heuristics
These Comet Lake systems are not yet released, but have been validated on pre-release hardware. This is being submitted separately from released hardware in case of a regression between pre-release and release hardware so this commit can be reverted alone. Tested-by: Yijun Shen Signed-off-by: Mario Limonciello --- drivers/net/ethernet/intel/e1000e/s0ix.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/net/ethernet/intel/e1000e/s0ix.c b/drivers/net/ethernet/intel/e1000e/s0ix.c index 74043e80c32f..0dd2e2702ebb 100644 --- a/drivers/net/ethernet/intel/e1000e/s0ix.c +++ b/drivers/net/ethernet/intel/e1000e/s0ix.c @@ -60,6 +60,9 @@ static bool e1000e_check_subsystem_allowlist(struct pci_dev *dev) case 0x09c2: /* Precision 3551 */ case 0x09c3: /* Precision 7550 */ case 0x09c4: /* Precision 7750 */ + case 0x0a40: /* Notebook 0x0a40 */ + case 0x0a41: /* Notebook 0x0a41 */ + case 0x0a42: /* Notebook 0x0a42 */ return true; } } -- 2.25.1
[PATCH v3 2/7] e1000e: Move all S0ix related code into its own source file
Introduce a flag to indicate the device should be using the S0ix flows and use this flag to run those functions. Splitting the code to it's own file will make future heuristics more self contained. Tested-by: Yijun Shen Signed-off-by: Mario Limonciello --- drivers/net/ethernet/intel/e1000e/Makefile | 2 +- drivers/net/ethernet/intel/e1000e/e1000.h | 4 + drivers/net/ethernet/intel/e1000e/netdev.c | 272 +--- drivers/net/ethernet/intel/e1000e/s0ix.c | 280 + 4 files changed, 290 insertions(+), 268 deletions(-) create mode 100644 drivers/net/ethernet/intel/e1000e/s0ix.c diff --git a/drivers/net/ethernet/intel/e1000e/Makefile b/drivers/net/ethernet/intel/e1000e/Makefile index 44e58b6e7660..f2332c01f86c 100644 --- a/drivers/net/ethernet/intel/e1000e/Makefile +++ b/drivers/net/ethernet/intel/e1000e/Makefile @@ -9,5 +9,5 @@ obj-$(CONFIG_E1000E) += e1000e.o e1000e-objs := 82571.o ich8lan.o 80003es2lan.o \ mac.o manage.o nvm.o phy.o \ - param.o ethtool.o netdev.o ptp.o + param.o ethtool.o netdev.o s0ix.o ptp.o diff --git a/drivers/net/ethernet/intel/e1000e/e1000.h b/drivers/net/ethernet/intel/e1000e/e1000.h index ba7a0f8f6937..b13f956285ae 100644 --- a/drivers/net/ethernet/intel/e1000e/e1000.h +++ b/drivers/net/ethernet/intel/e1000e/e1000.h @@ -436,6 +436,7 @@ s32 e1000e_get_base_timinca(struct e1000_adapter *adapter, u32 *timinca); #define FLAG2_DFLT_CRC_STRIPPING BIT(12) #define FLAG2_CHECK_RX_HWTSTAMP BIT(13) #define FLAG2_CHECK_SYSTIM_OVERFLOW BIT(14) +#define FLAG2_ENABLE_S0IX_FLOWS BIT(15) #define E1000_RX_DESC_PS(R, i) \ (&(((union e1000_rx_desc_packet_split *)((R).desc))[i])) @@ -462,6 +463,9 @@ enum latency_range { extern char e1000e_driver_name[]; void e1000e_check_options(struct e1000_adapter *adapter); +void e1000e_s0ix_entry_flow(struct e1000_adapter *adapter); +void e1000e_s0ix_exit_flow(struct e1000_adapter *adapter); +void e1000e_maybe_enable_s0ix(struct e1000_adapter *adapter); void e1000e_set_ethtool_ops(struct net_device *netdev); int e1000e_open(struct net_device *netdev); diff --git a/drivers/net/ethernet/intel/e1000e/netdev.c b/drivers/net/ethernet/intel/e1000e/netdev.c index 128ab6898070..cd9839e86615 100644 --- a/drivers/net/ethernet/intel/e1000e/netdev.c +++ b/drivers/net/ethernet/intel/e1000e/netdev.c @@ -103,45 +103,6 @@ static const struct e1000_reg_info e1000_reg_info_tbl[] = { {0, NULL} }; -struct e1000e_me_supported { - u16 device_id; /* supported device ID */ -}; - -static const struct e1000e_me_supported me_supported[] = { - {E1000_DEV_ID_PCH_LPT_I217_LM}, - {E1000_DEV_ID_PCH_LPTLP_I218_LM}, - {E1000_DEV_ID_PCH_I218_LM2}, - {E1000_DEV_ID_PCH_I218_LM3}, - {E1000_DEV_ID_PCH_SPT_I219_LM}, - {E1000_DEV_ID_PCH_SPT_I219_LM2}, - {E1000_DEV_ID_PCH_LBG_I219_LM3}, - {E1000_DEV_ID_PCH_SPT_I219_LM4}, - {E1000_DEV_ID_PCH_SPT_I219_LM5}, - {E1000_DEV_ID_PCH_CNP_I219_LM6}, - {E1000_DEV_ID_PCH_CNP_I219_LM7}, - {E1000_DEV_ID_PCH_ICP_I219_LM8}, - {E1000_DEV_ID_PCH_ICP_I219_LM9}, - {E1000_DEV_ID_PCH_CMP_I219_LM10}, - {E1000_DEV_ID_PCH_CMP_I219_LM11}, - {E1000_DEV_ID_PCH_CMP_I219_LM12}, - {E1000_DEV_ID_PCH_TGP_I219_LM13}, - {E1000_DEV_ID_PCH_TGP_I219_LM14}, - {E1000_DEV_ID_PCH_TGP_I219_LM15}, - {0} -}; - -static bool e1000e_check_me(u16 device_id) -{ - struct e1000e_me_supported *id; - - for (id = (struct e1000e_me_supported *)me_supported; -id->device_id; id++) - if (device_id == id->device_id) - return true; - - return false; -} - /** * __ew32_prepare - prepare to write to MAC CSR register on certain parts * @hw: pointer to the HW structure @@ -6368,228 +6329,6 @@ static void e1000e_flush_lpic(struct pci_dev *pdev) pm_runtime_put_sync(netdev->dev.parent); } -/* S0ix implementation */ -static void e1000e_s0ix_entry_flow(struct e1000_adapter *adapter) -{ - struct e1000_hw *hw = &adapter->hw; - u32 mac_data; - u16 phy_data; - - /* Disable the periodic inband message, -* don't request PCIe clock in K1 page770_17[10:9] = 10b -*/ - e1e_rphy(hw, HV_PM_CTRL, &phy_data); - phy_data &= ~HV_PM_CTRL_K1_CLK_REQ; - phy_data |= BIT(10); - e1e_wphy(hw, HV_PM_CTRL, phy_data); - - /* Make sure we don't exit K1 every time a new packet arrives -* 772_29[5] = 1 CS_Mode_Stay_In_K1 -*/ - e1e_rphy(hw, I217_CGFREG, &phy_data); - phy_data |= BIT(5); - e1e_wphy(hw, I217_CGFREG, phy_data); - - /* Change the MAC/PHY interface to SMBus -* Force the SMBus in PHY page769_23[0] = 1 -* Force the SMBus in MAC CTRL_EXT[11] = 1 -*/ - e1e_rphy(hw, CV_SMB_CTRL, &phy
[PATCH v3 7/7] e1000e: Add another Dell TGL notebook system into S0ix heuristics
This Tiger Lake system is not yet released, but has been validated on pre-release hardware. This is being submitted separately from released hardware in case of a regression between pre-release and release hardware so this commit can be reverted alone. Signed-off-by: Mario Limonciello --- drivers/net/ethernet/intel/e1000e/s0ix.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/net/ethernet/intel/e1000e/s0ix.c b/drivers/net/ethernet/intel/e1000e/s0ix.c index cc04aeaa2292..3f2985fac67c 100644 --- a/drivers/net/ethernet/intel/e1000e/s0ix.c +++ b/drivers/net/ethernet/intel/e1000e/s0ix.c @@ -63,6 +63,7 @@ static bool e1000e_check_subsystem_allowlist(struct pci_dev *dev) case 0x0a40: /* Notebook 0x0a40 */ case 0x0a41: /* Notebook 0x0a41 */ case 0x0a42: /* Notebook 0x0a42 */ + case 0x0a22: /* Notebook 0x0a22 */ case 0x0a2e: /* Desktop 0x0a2e */ case 0x0a30: /* Desktop 0x0a30 */ return true; -- 2.25.1
[PATCH v3 4/7] e1000e: Add Dell's Comet Lake systems into S0ix heuristics
Dell's shipping Comet Lake Latitude and Precision systems containing i219LM are properly configured and should use the S0ix flows. Disabling s0ix entry and exit flows caused a regression in power consumption over suspend to idle on these systems. Fixes: e086ba2fccda ("e1000e: disable s0ix entry and exit flows for ME systems") Tested-by: Yijun Shen Signed-off-by: Mario Limonciello --- drivers/net/ethernet/intel/e1000e/s0ix.c | 33 +--- 1 file changed, 29 insertions(+), 4 deletions(-) diff --git a/drivers/net/ethernet/intel/e1000e/s0ix.c b/drivers/net/ethernet/intel/e1000e/s0ix.c index c3013edbd9e4..74043e80c32f 100644 --- a/drivers/net/ethernet/intel/e1000e/s0ix.c +++ b/drivers/net/ethernet/intel/e1000e/s0ix.c @@ -1,5 +1,7 @@ // SPDX-License-Identifier: GPL-2.0 -/* Copyright(c) 1999 - 2018 Intel Corporation. */ +/* Copyright(c) 1999 - 2018 Intel Corporation. + * Copyright(c) 2020 Dell Inc. + */ #include @@ -44,6 +46,26 @@ static bool e1000e_check_me(u16 device_id) return false; } +static bool e1000e_check_subsystem_allowlist(struct pci_dev *dev) +{ + if (dev->subsystem_vendor == PCI_VENDOR_ID_DELL) { + switch (dev->subsystem_device) { + case 0x099f: /* Latitude 5310 */ + case 0x09a0: /* Latitude 5410 */ + case 0x09c9: /* Latitude 5410 */ + case 0x09a1: /* Latitude 5510 */ + case 0x09a2: /* Precision 3550 */ + case 0x09c0: /* Latitude 5411 */ + case 0x09c1: /* Latitude 5511 */ + case 0x09c2: /* Precision 3551 */ + case 0x09c3: /* Precision 7550 */ + case 0x09c4: /* Precision 7750 */ + return true; + } + } + return false; +} + void e1000e_s0ix_entry_flow(struct e1000_adapter *adapter) { struct e1000_hw *hw = &adapter->hw; @@ -273,8 +295,11 @@ void e1000e_maybe_enable_s0ix(struct e1000_adapter *adapter) /* require cannon point or later */ if (hw->mac.type < e1000_pch_cnp) return; - /* turn off on ME configurations */ - if (e1000e_check_me(pdev->device)) - return; + /* check for allowlist of systems */ + if (!e1000e_check_subsystem_allowlist(pdev)) { + /* turn off on ME configurations */ + if (e1000e_check_me(pdev->device)) + return; + } adapter->flags2 |= FLAG2_ENABLE_S0IX_FLOWS; } -- 2.25.1
[PATCH v3 3/7] e1000e: Export S0ix flags to ethtool
This flag can be used for debugging and development purposes including determining if S0ix flows work properly for a system not currently recognized by heuristics. Tested-by: Yijun Shen Signed-off-by: Mario Limonciello --- drivers/net/ethernet/intel/e1000e/ethtool.c | 40 + 1 file changed, 40 insertions(+) diff --git a/drivers/net/ethernet/intel/e1000e/ethtool.c b/drivers/net/ethernet/intel/e1000e/ethtool.c index 03215b0aee4b..eb683949ebfe 100644 --- a/drivers/net/ethernet/intel/e1000e/ethtool.c +++ b/drivers/net/ethernet/intel/e1000e/ethtool.c @@ -23,6 +23,13 @@ struct e1000_stats { int stat_offset; }; +static const char e1000e_priv_flags_strings[][ETH_GSTRING_LEN] = { +#define E1000E_PRIV_FLAGS_S0IX_ENABLED BIT(0) + "s0ix-enabled", +}; + +#define E1000E_PRIV_FLAGS_STR_LEN ARRAY_SIZE(e1000e_priv_flags_strings) + #define E1000_STAT(str, m) { \ .stat_string = str, \ .type = E1000_STATS, \ @@ -1776,6 +1783,8 @@ static int e1000e_get_sset_count(struct net_device __always_unused *netdev, return E1000_TEST_LEN; case ETH_SS_STATS: return E1000_STATS_LEN; + case ETH_SS_PRIV_FLAGS: + return E1000E_PRIV_FLAGS_STR_LEN; default: return -EOPNOTSUPP; } @@ -2097,6 +2106,10 @@ static void e1000_get_strings(struct net_device __always_unused *netdev, p += ETH_GSTRING_LEN; } break; + case ETH_SS_PRIV_FLAGS: + memcpy(data, e1000e_priv_flags_strings, + E1000E_PRIV_FLAGS_STR_LEN * ETH_GSTRING_LEN); + break; } } @@ -2305,6 +2318,31 @@ static int e1000e_get_ts_info(struct net_device *netdev, return 0; } +static u32 e1000e_get_priv_flags(struct net_device *netdev) +{ + struct e1000_adapter *adapter = netdev_priv(netdev); + u32 priv_flags = 0; + + if (adapter->flags2 & FLAG2_ENABLE_S0IX_FLOWS) + priv_flags |= E1000E_PRIV_FLAGS_S0IX_ENABLED; + + return priv_flags; +} + +static int e1000e_set_priv_flags(struct net_device *netdev, u32 priv_flags) +{ + struct e1000_adapter *adapter = netdev_priv(netdev); + unsigned int flags2 = adapter->flags2; + + flags2 &= ~FLAG2_ENABLE_S0IX_FLOWS; + if (priv_flags & E1000E_PRIV_FLAGS_S0IX_ENABLED) + flags2 |= FLAG2_ENABLE_S0IX_FLOWS; + if (flags2 != adapter->flags2) + adapter->flags2 = flags2; + + return 0; +} + static const struct ethtool_ops e1000_ethtool_ops = { .supported_coalesce_params = ETHTOOL_COALESCE_RX_USECS, .get_drvinfo= e1000_get_drvinfo, @@ -2336,6 +2374,8 @@ static const struct ethtool_ops e1000_ethtool_ops = { .set_eee= e1000e_set_eee, .get_link_ksettings = e1000_get_link_ksettings, .set_link_ksettings = e1000_set_link_ksettings, + .get_priv_flags = e1000e_get_priv_flags, + .set_priv_flags = e1000e_set_priv_flags, }; void e1000e_set_ethtool_ops(struct net_device *netdev) -- 2.25.1
[PATCH v2 1/5] e1000e: fix S0ix flow to allow S0i3.2 subset entry
From: Vitaly Lifshits Changed a configuration in the flows to align with architecture requirements to achieve S0i3.2 substate. Also fixed a typo in the previous commit 632fbd5eb5b0 ("e1000e: fix S0ix flows for cable connected case"). Signed-off-by: Vitaly Lifshits Tested-by: Aaron Brown Signed-off-by: Tony Nguyen --- drivers/net/ethernet/intel/e1000e/netdev.c | 8 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/net/ethernet/intel/e1000e/netdev.c b/drivers/net/ethernet/intel/e1000e/netdev.c index b30f00891c03..128ab6898070 100644 --- a/drivers/net/ethernet/intel/e1000e/netdev.c +++ b/drivers/net/ethernet/intel/e1000e/netdev.c @@ -6475,13 +6475,13 @@ static void e1000e_s0ix_entry_flow(struct e1000_adapter *adapter) /* Ungate PGCB clock */ mac_data = er32(FEXTNVM9); - mac_data |= BIT(28); + mac_data &= ~BIT(28); ew32(FEXTNVM9, mac_data); /* Enable K1 off to enable mPHY Power Gating */ mac_data = er32(FEXTNVM6); mac_data |= BIT(31); - ew32(FEXTNVM12, mac_data); + ew32(FEXTNVM6, mac_data); /* Enable mPHY power gating for any link and speed */ mac_data = er32(FEXTNVM8); @@ -6525,11 +6525,11 @@ static void e1000e_s0ix_exit_flow(struct e1000_adapter *adapter) /* Disable K1 off */ mac_data = er32(FEXTNVM6); mac_data &= ~BIT(31); - ew32(FEXTNVM12, mac_data); + ew32(FEXTNVM6, mac_data); /* Disable Ungate PGCB clock */ mac_data = er32(FEXTNVM9); - mac_data &= ~BIT(28); + mac_data |= BIT(28); ew32(FEXTNVM9, mac_data); /* Cancel not waking from dynamic -- 2.25.1
[PATCH v2 3/5] e1000e: Add Dell's Comet Lake systems into s0ix heuristics
Dell's Comet Lake Latitude and Precision systems containing i219LM are properly configured and should use the s0ix flows. Tested-by: Yijun Shen Signed-off-by: Mario Limonciello --- drivers/net/ethernet/intel/e1000e/s0ix.c | 33 +--- 1 file changed, 29 insertions(+), 4 deletions(-) diff --git a/drivers/net/ethernet/intel/e1000e/s0ix.c b/drivers/net/ethernet/intel/e1000e/s0ix.c index c3013edbd9e4..74043e80c32f 100644 --- a/drivers/net/ethernet/intel/e1000e/s0ix.c +++ b/drivers/net/ethernet/intel/e1000e/s0ix.c @@ -1,5 +1,7 @@ // SPDX-License-Identifier: GPL-2.0 -/* Copyright(c) 1999 - 2018 Intel Corporation. */ +/* Copyright(c) 1999 - 2018 Intel Corporation. + * Copyright(c) 2020 Dell Inc. + */ #include @@ -44,6 +46,26 @@ static bool e1000e_check_me(u16 device_id) return false; } +static bool e1000e_check_subsystem_allowlist(struct pci_dev *dev) +{ + if (dev->subsystem_vendor == PCI_VENDOR_ID_DELL) { + switch (dev->subsystem_device) { + case 0x099f: /* Latitude 5310 */ + case 0x09a0: /* Latitude 5410 */ + case 0x09c9: /* Latitude 5410 */ + case 0x09a1: /* Latitude 5510 */ + case 0x09a2: /* Precision 3550 */ + case 0x09c0: /* Latitude 5411 */ + case 0x09c1: /* Latitude 5511 */ + case 0x09c2: /* Precision 3551 */ + case 0x09c3: /* Precision 7550 */ + case 0x09c4: /* Precision 7750 */ + return true; + } + } + return false; +} + void e1000e_s0ix_entry_flow(struct e1000_adapter *adapter) { struct e1000_hw *hw = &adapter->hw; @@ -273,8 +295,11 @@ void e1000e_maybe_enable_s0ix(struct e1000_adapter *adapter) /* require cannon point or later */ if (hw->mac.type < e1000_pch_cnp) return; - /* turn off on ME configurations */ - if (e1000e_check_me(pdev->device)) - return; + /* check for allowlist of systems */ + if (!e1000e_check_subsystem_allowlist(pdev)) { + /* turn off on ME configurations */ + if (e1000e_check_me(pdev->device)) + return; + } adapter->flags2 |= FLAG2_ENABLE_S0IX_FLOWS; } -- 2.25.1
[PATCH v2 0/5] Improve s0ix flows for systems i219LM
commit e086ba2fccda ("e1000e: disable s0ix entry and exit flows for ME systems") disabled s0ix flows for systems that have various incarnations of the i219-LM ethernet controller. This was done because of some regressions caused by an earlier commit 632fbd5eb5b0e ("e1000e: fix S0ix flows for cable connected case") with i219-LM controller. Performing suspend to idle with these ethernet controllers requires a properly configured system. To make enabling such systems easier, this patch series allows turning on using ethtool. The flows have also been confirmed to be configured correctly on Dell's Latitude and Precision CML systems containing the i219-LM controller, when the kernel also contains the fix for s0i3.2 entry previously submitted here: https://marc.info/?l=linux-netdev&m=160677194809564&w=2 Patches 3 and 4 will turn the behavior on by default for Dell's CML systems. Patch 5 allows accessing the value of the flags via ethtool to tell if the heuristics have turned on s0ix flows, as well as for development purposes to determine if a system should be added to the heuristics list. Changes from v1 to v2: - Directly incorporate Vitaly's dependency patch in the series - Split out s0ix code into it's own file - Adjust from DMI matching to PCI subsystem vendor ID/device matching - Remove module parameter and sysfs, use ethtool flag instead. - Export s0ix flag to ethtool private flags - Include more people and lists directly in this submission chain. Mario Limonciello (4): e1000e: Move all s0ix related code into it's own source file e1000e: Add Dell's Comet Lake systems into s0ix heuristics e1000e: Add more Dell CML systems into s0ix heuristics e1000e: Export adapter flags to ethtool Vitaly Lifshits (1): e1000e: fix S0ix flow to allow S0i3.2 subset entry drivers/net/ethernet/intel/e1000e/Makefile | 2 +- drivers/net/ethernet/intel/e1000e/e1000.h | 4 + drivers/net/ethernet/intel/e1000e/ethtool.c | 23 ++ drivers/net/ethernet/intel/e1000e/netdev.c | 272 + drivers/net/ethernet/intel/e1000e/s0ix.c| 308 5 files changed, 341 insertions(+), 268 deletions(-) create mode 100644 drivers/net/ethernet/intel/e1000e/s0ix.c -- 2.25.1
[PATCH v2 5/5] e1000e: Export s0ix flags to ethtool
This flag can be used for debugging and development purposes including determining if s0ix flows work properly for a system not currently recognized by heuristics. Tested-by: Yijun Shen Signed-off-by: Mario Limonciello --- drivers/net/ethernet/intel/e1000e/ethtool.c | 40 + 1 file changed, 40 insertions(+) diff --git a/drivers/net/ethernet/intel/e1000e/ethtool.c b/drivers/net/ethernet/intel/e1000e/ethtool.c index 03215b0aee4b..eb683949ebfe 100644 --- a/drivers/net/ethernet/intel/e1000e/ethtool.c +++ b/drivers/net/ethernet/intel/e1000e/ethtool.c @@ -23,6 +23,13 @@ struct e1000_stats { int stat_offset; }; +static const char e1000e_priv_flags_strings[][ETH_GSTRING_LEN] = { +#define E1000E_PRIV_FLAGS_S0IX_ENABLED BIT(0) + "s0ix-enabled", +}; + +#define E1000E_PRIV_FLAGS_STR_LEN ARRAY_SIZE(e1000e_priv_flags_strings) + #define E1000_STAT(str, m) { \ .stat_string = str, \ .type = E1000_STATS, \ @@ -1776,6 +1783,8 @@ static int e1000e_get_sset_count(struct net_device __always_unused *netdev, return E1000_TEST_LEN; case ETH_SS_STATS: return E1000_STATS_LEN; + case ETH_SS_PRIV_FLAGS: + return E1000E_PRIV_FLAGS_STR_LEN; default: return -EOPNOTSUPP; } @@ -2097,6 +2106,10 @@ static void e1000_get_strings(struct net_device __always_unused *netdev, p += ETH_GSTRING_LEN; } break; + case ETH_SS_PRIV_FLAGS: + memcpy(data, e1000e_priv_flags_strings, + E1000E_PRIV_FLAGS_STR_LEN * ETH_GSTRING_LEN); + break; } } @@ -2305,6 +2318,31 @@ static int e1000e_get_ts_info(struct net_device *netdev, return 0; } +static u32 e1000e_get_priv_flags(struct net_device *netdev) +{ + struct e1000_adapter *adapter = netdev_priv(netdev); + u32 priv_flags = 0; + + if (adapter->flags2 & FLAG2_ENABLE_S0IX_FLOWS) + priv_flags |= E1000E_PRIV_FLAGS_S0IX_ENABLED; + + return priv_flags; +} + +static int e1000e_set_priv_flags(struct net_device *netdev, u32 priv_flags) +{ + struct e1000_adapter *adapter = netdev_priv(netdev); + unsigned int flags2 = adapter->flags2; + + flags2 &= ~FLAG2_ENABLE_S0IX_FLOWS; + if (priv_flags & E1000E_PRIV_FLAGS_S0IX_ENABLED) + flags2 |= FLAG2_ENABLE_S0IX_FLOWS; + if (flags2 != adapter->flags2) + adapter->flags2 = flags2; + + return 0; +} + static const struct ethtool_ops e1000_ethtool_ops = { .supported_coalesce_params = ETHTOOL_COALESCE_RX_USECS, .get_drvinfo= e1000_get_drvinfo, @@ -2336,6 +2374,8 @@ static const struct ethtool_ops e1000_ethtool_ops = { .set_eee= e1000e_set_eee, .get_link_ksettings = e1000_get_link_ksettings, .set_link_ksettings = e1000_set_link_ksettings, + .get_priv_flags = e1000e_get_priv_flags, + .set_priv_flags = e1000e_set_priv_flags, }; void e1000e_set_ethtool_ops(struct net_device *netdev) -- 2.25.1
[PATCH v2 2/5] e1000e: Move all s0ix related code into it's own source file
Introduce a flag to indicate the device should be using the s0ix flows and use this flag to run those functions. Splitting the code to it's own file will make future heuristics more self containted. Tested-by: Yijun Shen Signed-off-by: Mario Limonciello --- drivers/net/ethernet/intel/e1000e/Makefile | 2 +- drivers/net/ethernet/intel/e1000e/e1000.h | 4 + drivers/net/ethernet/intel/e1000e/netdev.c | 272 +--- drivers/net/ethernet/intel/e1000e/s0ix.c | 280 + 4 files changed, 290 insertions(+), 268 deletions(-) create mode 100644 drivers/net/ethernet/intel/e1000e/s0ix.c diff --git a/drivers/net/ethernet/intel/e1000e/Makefile b/drivers/net/ethernet/intel/e1000e/Makefile index 44e58b6e7660..f2332c01f86c 100644 --- a/drivers/net/ethernet/intel/e1000e/Makefile +++ b/drivers/net/ethernet/intel/e1000e/Makefile @@ -9,5 +9,5 @@ obj-$(CONFIG_E1000E) += e1000e.o e1000e-objs := 82571.o ich8lan.o 80003es2lan.o \ mac.o manage.o nvm.o phy.o \ - param.o ethtool.o netdev.o ptp.o + param.o ethtool.o netdev.o s0ix.o ptp.o diff --git a/drivers/net/ethernet/intel/e1000e/e1000.h b/drivers/net/ethernet/intel/e1000e/e1000.h index ba7a0f8f6937..b13f956285ae 100644 --- a/drivers/net/ethernet/intel/e1000e/e1000.h +++ b/drivers/net/ethernet/intel/e1000e/e1000.h @@ -436,6 +436,7 @@ s32 e1000e_get_base_timinca(struct e1000_adapter *adapter, u32 *timinca); #define FLAG2_DFLT_CRC_STRIPPING BIT(12) #define FLAG2_CHECK_RX_HWTSTAMP BIT(13) #define FLAG2_CHECK_SYSTIM_OVERFLOW BIT(14) +#define FLAG2_ENABLE_S0IX_FLOWS BIT(15) #define E1000_RX_DESC_PS(R, i) \ (&(((union e1000_rx_desc_packet_split *)((R).desc))[i])) @@ -462,6 +463,9 @@ enum latency_range { extern char e1000e_driver_name[]; void e1000e_check_options(struct e1000_adapter *adapter); +void e1000e_s0ix_entry_flow(struct e1000_adapter *adapter); +void e1000e_s0ix_exit_flow(struct e1000_adapter *adapter); +void e1000e_maybe_enable_s0ix(struct e1000_adapter *adapter); void e1000e_set_ethtool_ops(struct net_device *netdev); int e1000e_open(struct net_device *netdev); diff --git a/drivers/net/ethernet/intel/e1000e/netdev.c b/drivers/net/ethernet/intel/e1000e/netdev.c index 128ab6898070..cd9839e86615 100644 --- a/drivers/net/ethernet/intel/e1000e/netdev.c +++ b/drivers/net/ethernet/intel/e1000e/netdev.c @@ -103,45 +103,6 @@ static const struct e1000_reg_info e1000_reg_info_tbl[] = { {0, NULL} }; -struct e1000e_me_supported { - u16 device_id; /* supported device ID */ -}; - -static const struct e1000e_me_supported me_supported[] = { - {E1000_DEV_ID_PCH_LPT_I217_LM}, - {E1000_DEV_ID_PCH_LPTLP_I218_LM}, - {E1000_DEV_ID_PCH_I218_LM2}, - {E1000_DEV_ID_PCH_I218_LM3}, - {E1000_DEV_ID_PCH_SPT_I219_LM}, - {E1000_DEV_ID_PCH_SPT_I219_LM2}, - {E1000_DEV_ID_PCH_LBG_I219_LM3}, - {E1000_DEV_ID_PCH_SPT_I219_LM4}, - {E1000_DEV_ID_PCH_SPT_I219_LM5}, - {E1000_DEV_ID_PCH_CNP_I219_LM6}, - {E1000_DEV_ID_PCH_CNP_I219_LM7}, - {E1000_DEV_ID_PCH_ICP_I219_LM8}, - {E1000_DEV_ID_PCH_ICP_I219_LM9}, - {E1000_DEV_ID_PCH_CMP_I219_LM10}, - {E1000_DEV_ID_PCH_CMP_I219_LM11}, - {E1000_DEV_ID_PCH_CMP_I219_LM12}, - {E1000_DEV_ID_PCH_TGP_I219_LM13}, - {E1000_DEV_ID_PCH_TGP_I219_LM14}, - {E1000_DEV_ID_PCH_TGP_I219_LM15}, - {0} -}; - -static bool e1000e_check_me(u16 device_id) -{ - struct e1000e_me_supported *id; - - for (id = (struct e1000e_me_supported *)me_supported; -id->device_id; id++) - if (device_id == id->device_id) - return true; - - return false; -} - /** * __ew32_prepare - prepare to write to MAC CSR register on certain parts * @hw: pointer to the HW structure @@ -6368,228 +6329,6 @@ static void e1000e_flush_lpic(struct pci_dev *pdev) pm_runtime_put_sync(netdev->dev.parent); } -/* S0ix implementation */ -static void e1000e_s0ix_entry_flow(struct e1000_adapter *adapter) -{ - struct e1000_hw *hw = &adapter->hw; - u32 mac_data; - u16 phy_data; - - /* Disable the periodic inband message, -* don't request PCIe clock in K1 page770_17[10:9] = 10b -*/ - e1e_rphy(hw, HV_PM_CTRL, &phy_data); - phy_data &= ~HV_PM_CTRL_K1_CLK_REQ; - phy_data |= BIT(10); - e1e_wphy(hw, HV_PM_CTRL, phy_data); - - /* Make sure we don't exit K1 every time a new packet arrives -* 772_29[5] = 1 CS_Mode_Stay_In_K1 -*/ - e1e_rphy(hw, I217_CGFREG, &phy_data); - phy_data |= BIT(5); - e1e_wphy(hw, I217_CGFREG, phy_data); - - /* Change the MAC/PHY interface to SMBus -* Force the SMBus in PHY page769_23[0] = 1 -* Force the SMBus in MAC CTRL_EXT[11] = 1 -*/ - e1e_rphy(hw, CV_SMB_CTRL, &phy
[PATCH v2 4/5] e1000e: Add more Dell CML systems into s0ix heuristics
These comet lake systems are not yet released, but have been validated on pre-release hardware. This is being submitted separately from released hardware in case of a regression between pre-release and release hardware so this commit can be reverted alone. Tested-by: Yijun Shen Signed-off-by: Mario Limonciello --- drivers/net/ethernet/intel/e1000e/s0ix.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/net/ethernet/intel/e1000e/s0ix.c b/drivers/net/ethernet/intel/e1000e/s0ix.c index 74043e80c32f..0dd2e2702ebb 100644 --- a/drivers/net/ethernet/intel/e1000e/s0ix.c +++ b/drivers/net/ethernet/intel/e1000e/s0ix.c @@ -60,6 +60,9 @@ static bool e1000e_check_subsystem_allowlist(struct pci_dev *dev) case 0x09c2: /* Precision 3551 */ case 0x09c3: /* Precision 7550 */ case 0x09c4: /* Precision 7750 */ + case 0x0a40: /* Notebook 0x0a40 */ + case 0x0a41: /* Notebook 0x0a41 */ + case 0x0a42: /* Notebook 0x0a42 */ return true; } } -- 2.25.1
[PATCH 3/3] e1000e: Add more Dell CML systems into s0ix heuristics
These comet lake systems are not yet released, but have been validated on pre-release hardware. This is being submitted separately from released hardware in case of a regression between pre-release and release hardware so this commit can be reverted alone. Signed-off-by: Mario Limonciello --- drivers/net/ethernet/intel/e1000e/param.c | 21 + 1 file changed, 21 insertions(+) diff --git a/drivers/net/ethernet/intel/e1000e/param.c b/drivers/net/ethernet/intel/e1000e/param.c index 58e6718c4f75..fe3157c8aa4a 100644 --- a/drivers/net/ethernet/intel/e1000e/param.c +++ b/drivers/net/ethernet/intel/e1000e/param.c @@ -273,6 +273,27 @@ static const struct dmi_system_id s0ix_supported_systems[] = { DMI_MATCH(DMI_PRODUCT_SKU, "09C4"), }, }, + { + /* Dell Notebook 0x0A40 */ + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), + DMI_MATCH(DMI_PRODUCT_SKU, "0A40"), + }, + }, + { + /* Dell Notebook 0x0A41 */ + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), + DMI_MATCH(DMI_PRODUCT_SKU, "0A41"), + }, + }, + { + /* Dell Notebook 0x0A42 */ + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), + DMI_MATCH(DMI_PRODUCT_SKU, "0A42"), + }, + }, { } }; -- 2.25.1
[PATCH 1/3] e1000e: allow turning s0ix flows on for systems with ME
S0ix for GBE flows are needed for allowing the system to get into deepest power state, but these require coordination of components outside of control of Linux kernel. For systems that have confirmed to coordinate this properly, allow turning on the s0ix flows at load time or runtime. Fixes: e086ba2fccda ("e1000e: disable s0ix entry and exit flows for ME systems") Signed-off-by: Mario Limonciello --- .../device_drivers/ethernet/intel/e1000e.rst | 23 drivers/net/ethernet/intel/e1000e/e1000.h | 7 ++ drivers/net/ethernet/intel/e1000e/netdev.c| 64 +- drivers/net/ethernet/intel/e1000e/param.c | 110 ++ 4 files changed, 166 insertions(+), 38 deletions(-) diff --git a/Documentation/networking/device_drivers/ethernet/intel/e1000e.rst b/Documentation/networking/device_drivers/ethernet/intel/e1000e.rst index f49cd370e7bf..da029b703573 100644 --- a/Documentation/networking/device_drivers/ethernet/intel/e1000e.rst +++ b/Documentation/networking/device_drivers/ethernet/intel/e1000e.rst @@ -249,6 +249,29 @@ Debug This parameter adjusts the level of debug messages displayed in the system logs. +EnableS0ix +-- +:Valid Range: 0, 1, 2 +:Default Value: 1 (Use Heuristics) + + +---++ + | Value |EnableS0ix | + +===++ + | 0 |Disabled| + +---++ + | 1 | Use Heuristics | + +---++ + | 2 |Enabled | + +---++ + +Controls whether the e1000e driver will attempt s0ix flows. S0ix flows require +correct platform configuration. By default the e1000e driver will use some heuristics +to decide whether to enable s0ix. This parameter can be used to override heuristics. + +Additionally a sysfs file "enable_s0ix" will be present that can change the value at +runtime. + +Note: This option is only effective on Cannon Point or later hardware. Additional Features and Configurations == diff --git a/drivers/net/ethernet/intel/e1000e/e1000.h b/drivers/net/ethernet/intel/e1000e/e1000.h index ba7a0f8f6937..32262fa7e085 100644 --- a/drivers/net/ethernet/intel/e1000e/e1000.h +++ b/drivers/net/ethernet/intel/e1000e/e1000.h @@ -436,6 +436,7 @@ s32 e1000e_get_base_timinca(struct e1000_adapter *adapter, u32 *timinca); #define FLAG2_DFLT_CRC_STRIPPING BIT(12) #define FLAG2_CHECK_RX_HWTSTAMP BIT(13) #define FLAG2_CHECK_SYSTIM_OVERFLOW BIT(14) +#define FLAG2_ENABLE_S0IX_FLOWS BIT(15) #define E1000_RX_DESC_PS(R, i) \ (&(((union e1000_rx_desc_packet_split *)((R).desc))[i])) @@ -462,6 +463,12 @@ enum latency_range { extern char e1000e_driver_name[]; void e1000e_check_options(struct e1000_adapter *adapter); +ssize_t enable_s0ix_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count); +ssize_t enable_s0ix_show(struct device *dev, +struct device_attribute *attr, +char *buf); void e1000e_set_ethtool_ops(struct net_device *netdev); int e1000e_open(struct net_device *netdev); diff --git a/drivers/net/ethernet/intel/e1000e/netdev.c b/drivers/net/ethernet/intel/e1000e/netdev.c index 664e8ccc88d2..4359e809d684 100644 --- a/drivers/net/ethernet/intel/e1000e/netdev.c +++ b/drivers/net/ethernet/intel/e1000e/netdev.c @@ -103,44 +103,16 @@ static const struct e1000_reg_info e1000_reg_info_tbl[] = { {0, NULL} }; -struct e1000e_me_supported { - u16 device_id; /* supported device ID */ -}; +static DEVICE_ATTR_RW(enable_s0ix); -static const struct e1000e_me_supported me_supported[] = { - {E1000_DEV_ID_PCH_LPT_I217_LM}, - {E1000_DEV_ID_PCH_LPTLP_I218_LM}, - {E1000_DEV_ID_PCH_I218_LM2}, - {E1000_DEV_ID_PCH_I218_LM3}, - {E1000_DEV_ID_PCH_SPT_I219_LM}, - {E1000_DEV_ID_PCH_SPT_I219_LM2}, - {E1000_DEV_ID_PCH_LBG_I219_LM3}, - {E1000_DEV_ID_PCH_SPT_I219_LM4}, - {E1000_DEV_ID_PCH_SPT_I219_LM5}, - {E1000_DEV_ID_PCH_CNP_I219_LM6}, - {E1000_DEV_ID_PCH_CNP_I219_LM7}, - {E1000_DEV_ID_PCH_ICP_I219_LM8}, - {E1000_DEV_ID_PCH_ICP_I219_LM9}, - {E1000_DEV_ID_PCH_CMP_I219_LM10}, - {E1000_DEV_ID_PCH_CMP_I219_LM11}, - {E1000_DEV_ID_PCH_CMP_I219_LM12}, - {E1000_DEV_ID_PCH_TGP_I219_LM13}, - {E1000_DEV_ID_PCH_TGP_I219_LM14}, - {E1000_DEV_ID_PCH_TGP_I219_LM15}, - {0} +static struct attribute *e1000e_attrs[] = { + &dev_attr_enable_s0ix.attr, + NULL, }; -static bool e1000e_check_me(u16 device_id) -{ - struct e1000e_me_supported *id; - - for (id = (struct e1000e_me_supported *)me_supported; -id->device_id; id++) - if (device_id == id->device_id) - return true; - - return false; -} +static s
[PATCH 0/3] Improve s0ix flows for systems i219LM
commit e086ba2fccda ("e1000e: disable s0ix entry and exit flows for ME systems") disabled s0ix flows for systems that have various incarnations of the i219-LM ethernet controller. This was done because of some regressions caused by an earlier commit 632fbd5eb5b0e ("e1000e: fix S0ix flows for cable connected case") with i219-LM controller. Performing suspend to idle with these ethernet controllers requires a properly configured system. To make enabling such systems easier, this patch series offers configuration options to enable/disable the flows. The flows have also been confirmed to be configured correctly on Dell's Latitude and Precision CML systems containing the i219-LM controller, when the kernel also contains the fix for s0i3.2 entry here: https://lists.osuosl.org/pipermail/intel-wired-lan/Week-of-Mon-20200914/021361.html Patches 2 and 3 will turn the behavior on by default for Dell's CML systems. These patches should only be carried if that patch linked above is also applied. Mario Limonciello (3): e1000e: allow turning s0ix flows on for systems with ME e1000e: Add Dell's Comet Lake systems into s0ix heuristics e1000e: Add more Dell CML systems into s0ix heuristics .../device_drivers/ethernet/intel/e1000e.rst | 23 ++ drivers/net/ethernet/intel/Kconfig| 1 + drivers/net/ethernet/intel/e1000e/e1000.h | 7 + drivers/net/ethernet/intel/e1000e/netdev.c| 64 +++--- drivers/net/ethernet/intel/e1000e/param.c | 209 ++ 5 files changed, 266 insertions(+), 38 deletions(-) -- 2.25.1
[PATCH 2/3] e1000e: Add Dell's Comet Lake systems into s0ix heuristics
Dell's Comet Lake Latitude and Precision systems containing i219LM are properly configured and should use the s0ix flows. Signed-off-by: Mario Limonciello --- drivers/net/ethernet/intel/Kconfig| 1 + drivers/net/ethernet/intel/e1000e/param.c | 80 ++- 2 files changed, 80 insertions(+), 1 deletion(-) diff --git a/drivers/net/ethernet/intel/Kconfig b/drivers/net/ethernet/intel/Kconfig index 5aa86318ed3e..280af47d74d2 100644 --- a/drivers/net/ethernet/intel/Kconfig +++ b/drivers/net/ethernet/intel/Kconfig @@ -58,6 +58,7 @@ config E1000 config E1000E tristate "Intel(R) PRO/1000 PCI-Express Gigabit Ethernet support" depends on PCI && (!SPARC32 || BROKEN) + depends on DMI select CRC32 imply PTP_1588_CLOCK help diff --git a/drivers/net/ethernet/intel/e1000e/param.c b/drivers/net/ethernet/intel/e1000e/param.c index e66b222c824b..58e6718c4f75 100644 --- a/drivers/net/ethernet/intel/e1000e/param.c +++ b/drivers/net/ethernet/intel/e1000e/param.c @@ -1,6 +1,7 @@ // SPDX-License-Identifier: GPL-2.0 /* Copyright(c) 1999 - 2018 Intel Corporation. */ +#include #include #include #include @@ -201,6 +202,80 @@ static const struct e1000e_me_supported me_supported[] = { {0} }; +static const struct dmi_system_id s0ix_supported_systems[] = { + { + /* Dell Latitude 5310 */ + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), + DMI_MATCH(DMI_PRODUCT_SKU, "099F"), + }, + }, + { + /* Dell Latitude 5410 */ + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), + DMI_MATCH(DMI_PRODUCT_SKU, "09A0"), + }, + }, + { + /* Dell Latitude 5410 */ + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), + DMI_MATCH(DMI_PRODUCT_SKU, "09C9"), + }, + }, + { + /* Dell Latitude 5510 */ + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), + DMI_MATCH(DMI_PRODUCT_SKU, "09A1"), + }, + }, + { + /* Dell Precision 3550 */ + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), + DMI_MATCH(DMI_PRODUCT_SKU, "09A2"), + }, + }, + { + /* Dell Latitude 5411 */ + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), + DMI_MATCH(DMI_PRODUCT_SKU, "09C0"), + }, + }, + { + /* Dell Latitude 5511 */ + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), + DMI_MATCH(DMI_PRODUCT_SKU, "09C1"), + }, + }, + { + /* Dell Precision 3551 */ + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), + DMI_MATCH(DMI_PRODUCT_SKU, "09C2"), + }, + }, + { + /* Dell Precision 7550 */ + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), + DMI_MATCH(DMI_PRODUCT_SKU, "09C3"), + }, + }, + { + /* Dell Precision 7750 */ + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), + DMI_MATCH(DMI_PRODUCT_SKU, "09C4"), + }, + }, + { } +}; + static bool e1000e_check_me(u16 device_id) { struct e1000e_me_supported *id; @@ -599,8 +674,11 @@ void e1000e_check_options(struct e1000_adapter *adapter) } if (enabled == S0IX_HEURISTICS) { + /* check for allowlist of systems */ + if (dmi_check_system(s0ix_supported_systems)) + enabled = S0IX_FORCE_ON; /* default to off for ME configurations */ - if (e1000e_check_me(hw->adapter->pdev->device)) + else if (e1000e_check_me(hw->adapter->pdev->device)) enabled = S0IX_FORCE_OFF; } -- 2.25.1
[PATCH v3 0/2] Allow breaking up Thunderbolt/USB4 updates
Currently updates to Thunderbolt and USB4 controllers are fully atomic actions. When writing into the non-active NVM nothing gets flushed to the hardware until authenticate is sent. There has been some desire to improve the perceived performance of these updates, particularly for userland that may perform the update upon a performance sensitive time like logging out. So allow userland to flush the image to hardware at runtime, and then allow authenticating the image at another time. For the Dell WD19TB some specific hardware capability exists that allows extending this to automatically complete the update when unplugged. Export that functionality to userspace as well. Changes from v2 to v3: - Correct some whitespace and kernel-doc comments - Add another missing 'const' - For a quirk: (1<<1) -> BIT(0) Changes from v1 to v2: - Improve documentation - Drop tb-quirks.h - Adjust function and parameter names to Mika's preferences - Rebase onto thunderbolt.git/bleeding-edge to move on top of retimer work Mario Limonciello (2): thunderbolt: Add support for separating the flush to SPI and authenticate thunderbolt: Add support for authenticate on disconnect .../ABI/testing/sysfs-bus-thunderbolt | 24 +- drivers/thunderbolt/Makefile | 1 + drivers/thunderbolt/eeprom.c | 2 + drivers/thunderbolt/lc.c | 14 drivers/thunderbolt/quirks.c | 38 + drivers/thunderbolt/switch.c | 81 +++ drivers/thunderbolt/tb-quirks.h | 16 drivers/thunderbolt/tb.h | 4 + drivers/thunderbolt/tb_regs.h | 1 + 9 files changed, 162 insertions(+), 19 deletions(-) create mode 100644 drivers/thunderbolt/quirks.c create mode 100644 drivers/thunderbolt/tb-quirks.h -- 2.25.1
[PATCH v3 2/2] thunderbolt: Add support for authenticate on disconnect
Some external devices can support completing thunderbolt authentication when they are unplugged. For this to work though, the link controller must remain operational. The only device known to support this right now is the Dell WD19TB, so add a quirk for this. Signed-off-by: Mario Limonciello --- .../ABI/testing/sysfs-bus-thunderbolt | 13 ++ drivers/thunderbolt/Makefile | 2 +- drivers/thunderbolt/eeprom.c | 1 + drivers/thunderbolt/lc.c | 14 +++ drivers/thunderbolt/quirks.c | 42 +++ drivers/thunderbolt/switch.c | 40 -- drivers/thunderbolt/tb.h | 9 drivers/thunderbolt/tb_regs.h | 1 + 8 files changed, 117 insertions(+), 5 deletions(-) create mode 100644 drivers/thunderbolt/quirks.c diff --git a/Documentation/ABI/testing/sysfs-bus-thunderbolt b/Documentation/ABI/testing/sysfs-bus-thunderbolt index 7d0500b4d58a..dd565c378b40 100644 --- a/Documentation/ABI/testing/sysfs-bus-thunderbolt +++ b/Documentation/ABI/testing/sysfs-bus-thunderbolt @@ -276,3 +276,16 @@ Date: Oct 2020 KernelVersion: v5.9 Contact: Mika Westerberg Description: Retimer vendor identifier read from the hardware. + +What: /sys/bus/thunderbolt/devices/.../nvm_authenticate_on_disconnect +Date: Oct 2020 +KernelVersion: v5.9 +Contact: Mario Limonciello +Description: For supported devices, automatically authenticate the new Thunderbolt + image when the device is disconnected from the host system. + + This file will accept writing values "1" or "2" + - Writing "1" will flush the image to the storage + area and prepare the device for authentication on disconnect. + - Writing "2" will run some basic validation on the image + and flush it to the storage area. diff --git a/drivers/thunderbolt/Makefile b/drivers/thunderbolt/Makefile index cf7e1b42f4ad..4ab5bfad7bfd 100644 --- a/drivers/thunderbolt/Makefile +++ b/drivers/thunderbolt/Makefile @@ -2,6 +2,6 @@ obj-${CONFIG_USB4} := thunderbolt.o thunderbolt-objs := nhi.o nhi_ops.o ctl.o tb.o switch.o cap.o path.o tunnel.o eeprom.o thunderbolt-objs += domain.o dma_port.o icm.o property.o xdomain.o lc.o tmu.o usb4.o -thunderbolt-objs += nvm.o retimer.o +thunderbolt-objs += nvm.o retimer.o quirks.o obj-${CONFIG_USB4_KUNIT_TEST} += test.o diff --git a/drivers/thunderbolt/eeprom.c b/drivers/thunderbolt/eeprom.c index b451a5aa90b5..3ebca44ab3fa 100644 --- a/drivers/thunderbolt/eeprom.c +++ b/drivers/thunderbolt/eeprom.c @@ -599,6 +599,7 @@ int tb_drom_read(struct tb_switch *sw) sw->uid = header->uid; sw->vendor = header->vendor_id; sw->device = header->model_id; + tb_check_quirks(sw); crc = tb_crc32(sw->drom + TB_DROM_DATA_START, header->data_len); if (crc != header->data_crc32) { diff --git a/drivers/thunderbolt/lc.c b/drivers/thunderbolt/lc.c index bd44d50246d2..19be627d090f 100644 --- a/drivers/thunderbolt/lc.c +++ b/drivers/thunderbolt/lc.c @@ -366,3 +366,17 @@ int tb_lc_dp_sink_dealloc(struct tb_switch *sw, struct tb_port *in) tb_port_dbg(in, "sink %d de-allocated\n", sink); return 0; } + +/** + * tb_lc_force_power() - Forces LC to be powered on + * @sw: Thunderbolt switch + * + * This is useful to let authentication cycle pass even without + * a Thunderbolt link present. + */ +int tb_lc_force_power(struct tb_switch *sw) +{ + u32 in = 0x; + + return tb_sw_write(sw, &in, TB_CFG_SWITCH, TB_LC_POWER, 1); +} diff --git a/drivers/thunderbolt/quirks.c b/drivers/thunderbolt/quirks.c new file mode 100644 index ..0525f59220ae --- /dev/null +++ b/drivers/thunderbolt/quirks.c @@ -0,0 +1,42 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Thunderbolt driver - quirks + * + * Copyright (c) 2020 Mario Limonciello + */ + +#include "tb.h" + +static void quirk_force_power_link(struct tb_switch *sw) +{ + sw->quirks |= QUIRK_FORCE_POWER_LINK_CONTROLLER; +} + +struct tb_quirk { + u16 vendor; + u16 device; + void (*hook)(struct tb_switch *sw); +}; + +const static struct tb_quirk tb_quirks[] = { + /* Dell WD19TB supports self-authentication on unplug */ + { 0x00d4, 0xb070, quirk_force_power_link }, +}; + +/** + * tb_check_quirks() - Check for quirks to apply + * @sw: Thunderbolt switch + * + * Apply any quirks for the Thunderbolt controller + */ +void tb_check_quirks(struct tb_switch *sw) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(tb_quirks); i++) { + const struct tb_quirk *q = &tb_quirks[i]; + + if (sw->device == q->device && sw->vendor == q->vendor) + q->hook(sw); +
[PATCH v3 1/2] thunderbolt: Add support for separating the flush to SPI and authenticate
This allows userspace to have a shorter period of time that the device is unusable and to call it at a more convenient time. For example flushing the image may happen while the user is using the machine and authenticating/rebooting may happen while logging out. Signed-off-by: Mario Limonciello --- .../ABI/testing/sysfs-bus-thunderbolt | 11 - drivers/thunderbolt/nvm.c | 1 + drivers/thunderbolt/switch.c | 42 --- drivers/thunderbolt/tb.h | 2 + 4 files changed, 39 insertions(+), 17 deletions(-) diff --git a/Documentation/ABI/testing/sysfs-bus-thunderbolt b/Documentation/ABI/testing/sysfs-bus-thunderbolt index bd504ed323e8..7d0500b4d58a 100644 --- a/Documentation/ABI/testing/sysfs-bus-thunderbolt +++ b/Documentation/ABI/testing/sysfs-bus-thunderbolt @@ -178,11 +178,18 @@ KernelVersion:4.13 Contact: thunderbolt-softw...@lists.01.org Description: When new NVM image is written to the non-active NVM area (through non_activeX NVMem device), the - authentication procedure is started by writing 1 to - this file. If everything goes well, the device is + authentication procedure is started by writing to + this file. + If everything goes well, the device is restarted with the new NVM firmware. If the image verification fails an error code is returned instead. + This file will accept writing values "1" or "2" + - Writing "1" will flush the image to the storage + area and authenticate the image in one action. + - Writing "2" will run some basic validation on the image + and flush it to the storage area. + When read holds status of the last authentication operation if an error occurred during the process. This is directly the status value from the DMA configuration diff --git a/drivers/thunderbolt/nvm.c b/drivers/thunderbolt/nvm.c index 4c6aa06ab3d5..29de6d95c6e7 100644 --- a/drivers/thunderbolt/nvm.c +++ b/drivers/thunderbolt/nvm.c @@ -100,6 +100,7 @@ int tb_nvm_write_buf(struct tb_nvm *nvm, unsigned int offset, void *val, return -ENOMEM; } + nvm->flushed = false; nvm->buf_data_size = offset + bytes; memcpy(nvm->buf + offset, val, bytes); return 0; diff --git a/drivers/thunderbolt/switch.c b/drivers/thunderbolt/switch.c index 817c66c7adcf..bbfbfebeee7f 100644 --- a/drivers/thunderbolt/switch.c +++ b/drivers/thunderbolt/switch.c @@ -26,6 +26,11 @@ struct nvm_auth_status { u32 status; }; +enum nvm_write_ops { + WRITE_AND_AUTHENTICATE = 1, + WRITE_ONLY = 2, +}; + /* * Hold NVM authentication failure status per switch This information * needs to stay around even when the switch gets power cycled so we @@ -155,8 +160,12 @@ static int nvm_validate_and_write(struct tb_switch *sw) } if (tb_switch_is_usb4(sw)) - return usb4_switch_nvm_write(sw, 0, buf, image_size); - return dma_port_flash_write(sw->dma_port, 0, buf, image_size); + ret = usb4_switch_nvm_write(sw, 0, buf, image_size); + else + ret = dma_port_flash_write(sw->dma_port, 0, buf, image_size); + if (!ret) + sw->nvm->flushed = true; + return ret; } static int nvm_authenticate_host_dma_port(struct tb_switch *sw) @@ -1488,7 +1497,7 @@ static ssize_t nvm_authenticate_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct tb_switch *sw = tb_to_switch(dev); - bool val; + int val; int ret; pm_runtime_get_sync(&sw->dev); @@ -1504,25 +1513,28 @@ static ssize_t nvm_authenticate_store(struct device *dev, goto exit_unlock; } - ret = kstrtobool(buf, &val); + ret = kstrtoint(buf, 10, &val); if (ret) goto exit_unlock; /* Always clear the authentication status */ nvm_clear_auth_status(sw); - if (val) { - if (!sw->nvm->buf) { - ret = -EINVAL; - goto exit_unlock; - } - - ret = nvm_validate_and_write(sw); - if (ret) - goto exit_unlock; + if (val > 0) { + if (!sw->nvm->flushed) { + if (!sw->nvm->buf) { + ret = -EINVAL; + goto exit_unlock; + } - sw->nvm->authenticating = true; - ret = nvm_authenticate(sw); + ret = nvm_validate_and_write(sw); + if (ret || val ==
[PATCH v2 0/2] Allow breaking up Thunderbolt/USB4 updates
Currently updates to Thunderbolt and USB4 controllers are fully atomic actions. When writing into the non-active NVM nothing gets flushed to the hardware until authenticate is sent. There has been some desire to improve the perceived performance of these updates, particularly for userland that may perform the update upon a performance sensitive time like logging out. So allow userland to flush the image to hardware at runtime, and then allow authenticating the image at another time. For the Dell WD19TB some specific hardware capability exists that allows extending this to automatically complete the update when unplugged. Export that functionality to userspace as well. Changes from v1 to v2: - Improve documentation - Drop tb-quirks.h - Adjust function and parameter names to Mika's preferences - Rebase onto thunderbolt.git/bleeding-edge to move on top of retimer work Mario Limonciello (2): thunderbolt: Add support for separating the flush to SPI and authenticate thunderbolt: Add support for authenticate on disconnect .../ABI/testing/sysfs-bus-thunderbolt | 24 +- drivers/thunderbolt/Makefile | 1 + drivers/thunderbolt/eeprom.c | 2 + drivers/thunderbolt/lc.c | 14 drivers/thunderbolt/quirks.c | 38 + drivers/thunderbolt/switch.c | 81 +++ drivers/thunderbolt/tb-quirks.h | 16 drivers/thunderbolt/tb.h | 4 + drivers/thunderbolt/tb_regs.h | 1 + 9 files changed, 162 insertions(+), 19 deletions(-) create mode 100644 drivers/thunderbolt/quirks.c create mode 100644 drivers/thunderbolt/tb-quirks.h -- 2.25.1
[PATCH v2 2/2] thunderbolt: Add support for authenticate on disconnect
Some external devices can support completing thunderbolt authentication when they are unplugged. For this to work though, the link controller must remain operational. The only device known to support this right now is the Dell WD19TB, so add a quirk for this. Signed-off-by: Mario Limonciello --- .../ABI/testing/sysfs-bus-thunderbolt | 13 ++ drivers/thunderbolt/Makefile | 2 +- drivers/thunderbolt/eeprom.c | 1 + drivers/thunderbolt/lc.c | 14 +++ drivers/thunderbolt/quirks.c | 36 + drivers/thunderbolt/switch.c | 40 +-- drivers/thunderbolt/tb.h | 7 drivers/thunderbolt/tb_regs.h | 1 + 8 files changed, 109 insertions(+), 5 deletions(-) create mode 100644 drivers/thunderbolt/quirks.c diff --git a/Documentation/ABI/testing/sysfs-bus-thunderbolt b/Documentation/ABI/testing/sysfs-bus-thunderbolt index 7d0500b4d58a..dd565c378b40 100644 --- a/Documentation/ABI/testing/sysfs-bus-thunderbolt +++ b/Documentation/ABI/testing/sysfs-bus-thunderbolt @@ -276,3 +276,16 @@ Date: Oct 2020 KernelVersion: v5.9 Contact: Mika Westerberg Description: Retimer vendor identifier read from the hardware. + +What: /sys/bus/thunderbolt/devices/.../nvm_authenticate_on_disconnect +Date: Oct 2020 +KernelVersion: v5.9 +Contact: Mario Limonciello +Description: For supported devices, automatically authenticate the new Thunderbolt + image when the device is disconnected from the host system. + + This file will accept writing values "1" or "2" + - Writing "1" will flush the image to the storage + area and prepare the device for authentication on disconnect. + - Writing "2" will run some basic validation on the image + and flush it to the storage area. diff --git a/drivers/thunderbolt/Makefile b/drivers/thunderbolt/Makefile index cf7e1b42f4ad..4ab5bfad7bfd 100644 --- a/drivers/thunderbolt/Makefile +++ b/drivers/thunderbolt/Makefile @@ -2,6 +2,6 @@ obj-${CONFIG_USB4} := thunderbolt.o thunderbolt-objs := nhi.o nhi_ops.o ctl.o tb.o switch.o cap.o path.o tunnel.o eeprom.o thunderbolt-objs += domain.o dma_port.o icm.o property.o xdomain.o lc.o tmu.o usb4.o -thunderbolt-objs += nvm.o retimer.o +thunderbolt-objs += nvm.o retimer.o quirks.o obj-${CONFIG_USB4_KUNIT_TEST} += test.o diff --git a/drivers/thunderbolt/eeprom.c b/drivers/thunderbolt/eeprom.c index b451a5aa90b5..3ebca44ab3fa 100644 --- a/drivers/thunderbolt/eeprom.c +++ b/drivers/thunderbolt/eeprom.c @@ -599,6 +599,7 @@ int tb_drom_read(struct tb_switch *sw) sw->uid = header->uid; sw->vendor = header->vendor_id; sw->device = header->model_id; + tb_check_quirks(sw); crc = tb_crc32(sw->drom + TB_DROM_DATA_START, header->data_len); if (crc != header->data_crc32) { diff --git a/drivers/thunderbolt/lc.c b/drivers/thunderbolt/lc.c index bd44d50246d2..828b4655d6a1 100644 --- a/drivers/thunderbolt/lc.c +++ b/drivers/thunderbolt/lc.c @@ -366,3 +366,17 @@ int tb_lc_dp_sink_dealloc(struct tb_switch *sw, struct tb_port *in) tb_port_dbg(in, "sink %d de-allocated\n", sink); return 0; } + +/** + * tb_lc_force_power() - Forces LC to be powered on + * @sw: thunderbolt switch + * + * This is useful to let authentication cycle pass even without + * a Thunderbolt link present. + */ +int tb_lc_force_power(struct tb_switch *sw) +{ + u32 in = 0x; + + return tb_sw_write(sw, &in, TB_CFG_SWITCH, TB_LC_POWER, 1); +} diff --git a/drivers/thunderbolt/quirks.c b/drivers/thunderbolt/quirks.c new file mode 100644 index ..e8eace99bfcb --- /dev/null +++ b/drivers/thunderbolt/quirks.c @@ -0,0 +1,36 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Thunderbolt driver - quirks + * + * Copyright (c) 2020 Mario Limonciello + */ + +#include "tb.h" + +static void quirk_force_power_link(struct tb_switch *sw) +{ + sw->quirks |= QUIRK_FORCE_POWER_LINK_CONTROLLER; +} + +struct tb_quirk { + u16 vendor; + u16 device; + void (*hook)(struct tb_switch *sw); +}; + +static struct tb_quirk tb_quirks[] = { + /* Dell WD19TB supports self-authentication on unplug */ + { 0x00d4, 0xb070, quirk_force_power_link }, +}; + +void tb_check_quirks(struct tb_switch *sw) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(tb_quirks); i++) { + const struct tb_quirk *q = &tb_quirks[i]; + + if (sw->device == q->device && sw->vendor == q->vendor) + q->hook(sw); + } +} diff --git a/drivers/thunderbolt/switch.c b/drivers/thunderbolt/switch.c index bbfbfebeee7f..712395f518b8 100644 --- a/drivers/thunderbo
[PATCH v2 1/2] thunderbolt: Add support for separating the flush to SPI and authenticate
This allows userspace to have a shorter period of time that the device is unusable and to call it at a more convenient time. For example flushing the image may happen while the user is using the machine and authenticating/rebooting may happen while logging out. Signed-off-by: Mario Limonciello --- .../ABI/testing/sysfs-bus-thunderbolt | 11 - drivers/thunderbolt/nvm.c | 1 + drivers/thunderbolt/switch.c | 42 --- drivers/thunderbolt/tb.h | 2 + 4 files changed, 39 insertions(+), 17 deletions(-) diff --git a/Documentation/ABI/testing/sysfs-bus-thunderbolt b/Documentation/ABI/testing/sysfs-bus-thunderbolt index bd504ed323e8..7d0500b4d58a 100644 --- a/Documentation/ABI/testing/sysfs-bus-thunderbolt +++ b/Documentation/ABI/testing/sysfs-bus-thunderbolt @@ -178,11 +178,18 @@ KernelVersion:4.13 Contact: thunderbolt-softw...@lists.01.org Description: When new NVM image is written to the non-active NVM area (through non_activeX NVMem device), the - authentication procedure is started by writing 1 to - this file. If everything goes well, the device is + authentication procedure is started by writing to + this file. + If everything goes well, the device is restarted with the new NVM firmware. If the image verification fails an error code is returned instead. + This file will accept writing values "1" or "2" + - Writing "1" will flush the image to the storage + area and authenticate the image in one action. + - Writing "2" will run some basic validation on the image + and flush it to the storage area. + When read holds status of the last authentication operation if an error occurred during the process. This is directly the status value from the DMA configuration diff --git a/drivers/thunderbolt/nvm.c b/drivers/thunderbolt/nvm.c index 4c6aa06ab3d5..29de6d95c6e7 100644 --- a/drivers/thunderbolt/nvm.c +++ b/drivers/thunderbolt/nvm.c @@ -100,6 +100,7 @@ int tb_nvm_write_buf(struct tb_nvm *nvm, unsigned int offset, void *val, return -ENOMEM; } + nvm->flushed = false; nvm->buf_data_size = offset + bytes; memcpy(nvm->buf + offset, val, bytes); return 0; diff --git a/drivers/thunderbolt/switch.c b/drivers/thunderbolt/switch.c index 817c66c7adcf..bbfbfebeee7f 100644 --- a/drivers/thunderbolt/switch.c +++ b/drivers/thunderbolt/switch.c @@ -26,6 +26,11 @@ struct nvm_auth_status { u32 status; }; +enum nvm_write_ops { + WRITE_AND_AUTHENTICATE = 1, + WRITE_ONLY = 2, +}; + /* * Hold NVM authentication failure status per switch This information * needs to stay around even when the switch gets power cycled so we @@ -155,8 +160,12 @@ static int nvm_validate_and_write(struct tb_switch *sw) } if (tb_switch_is_usb4(sw)) - return usb4_switch_nvm_write(sw, 0, buf, image_size); - return dma_port_flash_write(sw->dma_port, 0, buf, image_size); + ret = usb4_switch_nvm_write(sw, 0, buf, image_size); + else + ret = dma_port_flash_write(sw->dma_port, 0, buf, image_size); + if (!ret) + sw->nvm->flushed = true; + return ret; } static int nvm_authenticate_host_dma_port(struct tb_switch *sw) @@ -1488,7 +1497,7 @@ static ssize_t nvm_authenticate_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct tb_switch *sw = tb_to_switch(dev); - bool val; + int val; int ret; pm_runtime_get_sync(&sw->dev); @@ -1504,25 +1513,28 @@ static ssize_t nvm_authenticate_store(struct device *dev, goto exit_unlock; } - ret = kstrtobool(buf, &val); + ret = kstrtoint(buf, 10, &val); if (ret) goto exit_unlock; /* Always clear the authentication status */ nvm_clear_auth_status(sw); - if (val) { - if (!sw->nvm->buf) { - ret = -EINVAL; - goto exit_unlock; - } - - ret = nvm_validate_and_write(sw); - if (ret) - goto exit_unlock; + if (val > 0) { + if (!sw->nvm->flushed) { + if (!sw->nvm->buf) { + ret = -EINVAL; + goto exit_unlock; + } - sw->nvm->authenticating = true; - ret = nvm_authenticate(sw); + ret = nvm_validate_and_write(sw); + if (ret || val ==
[PATCH 2/2] thunderbolt: Add support for authenticate on disconnect
Some external devices can support completing thunderbolt authentication when they are unplugged. For this to work though, the link controller must remain operational. The only device known to support this right now is the Dell WD19TB, so add a quirk for this. Signed-off-by: Mario Limonciello --- .../ABI/testing/sysfs-bus-thunderbolt | 13 ++ drivers/thunderbolt/Makefile | 1 + drivers/thunderbolt/eeprom.c | 2 + drivers/thunderbolt/lc.c | 14 +++ drivers/thunderbolt/quirks.c | 38 + drivers/thunderbolt/switch.c | 42 +-- drivers/thunderbolt/tb-quirks.h | 16 +++ drivers/thunderbolt/tb.h | 3 ++ drivers/thunderbolt/tb_regs.h | 1 + 9 files changed, 126 insertions(+), 4 deletions(-) create mode 100644 drivers/thunderbolt/quirks.c create mode 100644 drivers/thunderbolt/tb-quirks.h diff --git a/Documentation/ABI/testing/sysfs-bus-thunderbolt b/Documentation/ABI/testing/sysfs-bus-thunderbolt index 26b15cbc9881..30798f9a8f59 100644 --- a/Documentation/ABI/testing/sysfs-bus-thunderbolt +++ b/Documentation/ABI/testing/sysfs-bus-thunderbolt @@ -243,3 +243,16 @@ KernelVersion: 4.15 Contact: thunderbolt-softw...@lists.01.org Description: This contains XDomain service specific settings as bitmask. Format: %x + +What: /sys/bus/thunderbolt/devices/.../nvm_authenticate_on_disconnect +Date: August 2020 +KernelVersion: 5.9 +Contact: thunderbolt-softw...@lists.01.org +Description: For supported devices, automatically authenticate the new Thunderbolt + image when the device is disconnected from the host system. + + This file will accept writing values "1" or "2" + - Writing "1" will flush the image to the storage + area and prepare the device for authentication on disconnect. + - Writing "2" will only flush the image to the storage + area. diff --git a/drivers/thunderbolt/Makefile b/drivers/thunderbolt/Makefile index eae28dd45250..013c5564565a 100644 --- a/drivers/thunderbolt/Makefile +++ b/drivers/thunderbolt/Makefile @@ -2,3 +2,4 @@ obj-${CONFIG_USB4} := thunderbolt.o thunderbolt-objs := nhi.o nhi_ops.o ctl.o tb.o switch.o cap.o path.o tunnel.o eeprom.o thunderbolt-objs += domain.o dma_port.o icm.o property.o xdomain.o lc.o tmu.o usb4.o +thunderbolt-objs += quirks.o diff --git a/drivers/thunderbolt/eeprom.c b/drivers/thunderbolt/eeprom.c index b451a5aa90b5..32838c016c4f 100644 --- a/drivers/thunderbolt/eeprom.c +++ b/drivers/thunderbolt/eeprom.c @@ -10,6 +10,7 @@ #include #include #include "tb.h" +#include "tb-quirks.h" /** * tb_eeprom_ctl_write() - write control word @@ -599,6 +600,7 @@ int tb_drom_read(struct tb_switch *sw) sw->uid = header->uid; sw->vendor = header->vendor_id; sw->device = header->model_id; + check_tbt_quirks(sw); crc = tb_crc32(sw->drom + TB_DROM_DATA_START, header->data_len); if (crc != header->data_crc32) { diff --git a/drivers/thunderbolt/lc.c b/drivers/thunderbolt/lc.c index bd44d50246d2..45d2a1de2069 100644 --- a/drivers/thunderbolt/lc.c +++ b/drivers/thunderbolt/lc.c @@ -366,3 +366,17 @@ int tb_lc_dp_sink_dealloc(struct tb_switch *sw, struct tb_port *in) tb_port_dbg(in, "sink %d de-allocated\n", sink); return 0; } + +/** + * lc_force_power() - Force powers a ridge + * @sw: thunderbolt switch + * + * This is useful to let authentication cycle pass even without + * a Thunderbolt link present + */ +int lc_force_power(struct tb_switch *sw) +{ + u32 in = 0x; + + return tb_sw_write(sw, &in, TB_CFG_SWITCH, TB_LC_POWER, 1); +} diff --git a/drivers/thunderbolt/quirks.c b/drivers/thunderbolt/quirks.c new file mode 100644 index ..b9c5cfb97645 --- /dev/null +++ b/drivers/thunderbolt/quirks.c @@ -0,0 +1,38 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Thunderbolt driver - quirks + * + * Copyright (c) 2020 Mario Limonciello + */ + +#include "tb.h" +#include "tb-quirks.h" + +static void quirk_force_power_link(struct tb_switch *sw) +{ + sw->quirks |= QUIRK_FORCE_POWER_LINK_CONTROLLER; +} + +struct tbt_quirk { + u16 vendor; + u16 device; + void (*hook)(struct tb_switch *sw); +}; + +static struct tbt_quirk tbt_quirks[] = { + /* Dell WD19TB supports self-authentication on unplug */ + { 0x00d4, 0xb070, quirk_force_power_link }, +}; + +void check_tbt_quirks(struct tb_switch *sw) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(tbt_quirks); i++) { + struct tbt_quirk *q = &tbt_quirks[i]; + + if (sw->device == q->device && + sw->v
[PATCH 1/2] thunderbolt: Add support for separating the flush to SPI and authenticate
This allows userspace to have a shorter period of time that the device is unusable and to call it at a more convenient time. For example flushing the image may happen while the user is using the machine and authenticating/rebooting may happen while logging out. Signed-off-by: Mario Limonciello --- .../ABI/testing/sysfs-bus-thunderbolt | 11 - drivers/thunderbolt/switch.c | 43 --- drivers/thunderbolt/tb.h | 1 + 3 files changed, 38 insertions(+), 17 deletions(-) diff --git a/Documentation/ABI/testing/sysfs-bus-thunderbolt b/Documentation/ABI/testing/sysfs-bus-thunderbolt index 82e80de78dd0..26b15cbc9881 100644 --- a/Documentation/ABI/testing/sysfs-bus-thunderbolt +++ b/Documentation/ABI/testing/sysfs-bus-thunderbolt @@ -178,11 +178,18 @@ KernelVersion:4.13 Contact: thunderbolt-softw...@lists.01.org Description: When new NVM image is written to the non-active NVM area (through non_activeX NVMem device), the - authentication procedure is started by writing 1 to - this file. If everything goes well, the device is + authentication procedure is started by writing to + this file. + If everything goes well, the device is restarted with the new NVM firmware. If the image verification fails an error code is returned instead. + This file will accept writing values "1" or "2" + - Writing "1" will flush the image to the storage + area and authenticate the image in one action. + - Writing "2" will only flush the image to the storage + area. + When read holds status of the last authentication operation if an error occurred during the process. This is directly the status value from the DMA configuration diff --git a/drivers/thunderbolt/switch.c b/drivers/thunderbolt/switch.c index d7d60cd9226f..4c476a58db38 100644 --- a/drivers/thunderbolt/switch.c +++ b/drivers/thunderbolt/switch.c @@ -27,6 +27,11 @@ #define NVM_MIN_SIZE SZ_32K #define NVM_MAX_SIZE SZ_512K +enum nvm_write_ops { + WRITE_AND_AUTHENTICATE = 1, + WRITE_ONLY = 2, +}; + static DEFINE_IDA(nvm_ida); struct nvm_auth_status { @@ -164,8 +169,12 @@ static int nvm_validate_and_write(struct tb_switch *sw) } if (tb_switch_is_usb4(sw)) - return usb4_switch_nvm_write(sw, 0, buf, image_size); - return dma_port_flash_write(sw->dma_port, 0, buf, image_size); + ret = usb4_switch_nvm_write(sw, 0, buf, image_size); + else + ret = dma_port_flash_write(sw->dma_port, 0, buf, image_size); + if (!ret) + sw->nvm->flushed = true; + return ret; } static int nvm_authenticate_host_dma_port(struct tb_switch *sw) @@ -371,6 +380,7 @@ static int tb_switch_nvm_write(void *priv, unsigned int offset, void *val, } } + sw->nvm->flushed = false; sw->nvm->buf_data_size = offset + bytes; memcpy(sw->nvm->buf + offset, val, bytes); @@ -1536,7 +1546,7 @@ static ssize_t nvm_authenticate_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct tb_switch *sw = tb_to_switch(dev); - bool val; + int val; int ret; pm_runtime_get_sync(&sw->dev); @@ -1552,25 +1562,28 @@ static ssize_t nvm_authenticate_store(struct device *dev, goto exit_unlock; } - ret = kstrtobool(buf, &val); + ret = kstrtoint(buf, 10, &val); if (ret) goto exit_unlock; /* Always clear the authentication status */ nvm_clear_auth_status(sw); - if (val) { - if (!sw->nvm->buf) { - ret = -EINVAL; - goto exit_unlock; - } - - ret = nvm_validate_and_write(sw); - if (ret) - goto exit_unlock; + if (val > 0) { + if (!sw->nvm->flushed) { + if (!sw->nvm->buf) { + ret = -EINVAL; + goto exit_unlock; + } - sw->nvm->authenticating = true; - ret = nvm_authenticate(sw); + ret = nvm_validate_and_write(sw); + if (ret || val == WRITE_ONLY) + goto exit_unlock; + } + if (val == WRITE_AND_AUTHENTICATE) { + sw->nvm->authenticating = true; + ret = nvm_authenticate(sw); + } } exit_unlock: diff --git a/drivers/thunderbolt/tb.h b/dri
[PATCH 0/2] Allow breaking up Thunderbolt/USB4 updates
Currently updates to Thunderbolt and USB4 controllers are fully atomic actions. When writing into the non-active NVM nothing gets flushed to the hardware until authenticate is sent. There has been some desire to improve the perceived performance of these updates, particularly for userland that may perform the update upon a performance sensitive time like logging out. So allow userland to flush the image to hardware at runtime, and then allow authenticating the image at another time. For the Dell WD19TB some specific hardware capability exists that allows extending this to automatically complete the update when unplugged. Export that functionality to userspace as well. This patch series is done relative thunderbolt.git/next. Mario Limonciello (2): thunderbolt: Add support for separating the flush to SPI and authenticate thunderbolt: Add support for authenticate on disconnect .../ABI/testing/sysfs-bus-thunderbolt | 24 +- drivers/thunderbolt/Makefile | 1 + drivers/thunderbolt/eeprom.c | 2 + drivers/thunderbolt/lc.c | 14 drivers/thunderbolt/quirks.c | 38 + drivers/thunderbolt/switch.c | 81 +++ drivers/thunderbolt/tb-quirks.h | 16 drivers/thunderbolt/tb.h | 4 + drivers/thunderbolt/tb_regs.h | 1 + 9 files changed, 162 insertions(+), 19 deletions(-) create mode 100644 drivers/thunderbolt/quirks.c create mode 100644 drivers/thunderbolt/tb-quirks.h -- 2.25.1
[PATCH] tpm: Revert "tpm: fix invalid locking in NONBLOCKING mode"
This reverts commit d23d12484307b40eea549b8a858f5fffad913897. This commit has caused regressions for the XPS 9560 containing a Nuvoton TPM. As mentioned by the reporter all TPM2 commands are failing with: ERROR:tcti:src/tss2-tcti/tcti-device.c:290:tcti_device_receive() Failed to read response from fd 3, got errno 1: Operation not permitted The reporter bisected this issue back to this commit which was backported to stable as commit 4d6ebc4. Cc: Jeffrin Jose T BugLink: https://bugzilla.kernel.org/show_bug.cgi?id=206275 Fixes: d23d124 ("tpm: fix invalid locking in NONBLOCKING mode") Reported-by: Alex Guzman Signed-off-by: Mario Limonciello --- drivers/char/tpm/tpm-dev-common.c | 8 1 file changed, 8 deletions(-) diff --git a/drivers/char/tpm/tpm-dev-common.c b/drivers/char/tpm/tpm-dev-common.c index 87f449340202..bc9d7c7ddc01 100644 --- a/drivers/char/tpm/tpm-dev-common.c +++ b/drivers/char/tpm/tpm-dev-common.c @@ -61,12 +61,6 @@ static void tpm_dev_async_work(struct work_struct *work) mutex_lock(&priv->buffer_mutex); priv->command_enqueued = false; - ret = tpm_try_get_ops(priv->chip); - if (ret) { - priv->response_length = ret; - goto out; - } - ret = tpm_dev_transmit(priv->chip, priv->space, priv->data_buffer, sizeof(priv->data_buffer)); tpm_put_ops(priv->chip); @@ -74,7 +68,6 @@ static void tpm_dev_async_work(struct work_struct *work) priv->response_length = ret; mod_timer(&priv->user_read_timer, jiffies + (120 * HZ)); } -out: mutex_unlock(&priv->buffer_mutex); wake_up_interruptible(&priv->async_wait); } @@ -211,7 +204,6 @@ ssize_t tpm_common_write(struct file *file, const char __user *buf, if (file->f_flags & O_NONBLOCK) { priv->command_enqueued = true; queue_work(tpm_dev_wq, &priv->async_work); - tpm_put_ops(priv->chip); mutex_unlock(&priv->buffer_mutex); return size; } -- 2.25.1
[PATCH] ACPI: PM: Revert "ACPI / PM: Blacklist Low Power S0 Idle _DSM for Dell XPS13 9360"
This reverts part of commit 71630b7a832f ("ACPI / PM: Blacklist Low Power S0 Idle _DSM for Dell XPS13 9360") to remove the S0ix blacklist for the XPS 9360. The problems with this system occurred in one possible NVME SSD when putting system into s0ix. As the NVME sleep behavior has been adjusted in d916b1be this is expected to be now resolved. Cc: 'Paul Menzel ' BugLink: https://bugzilla.kernel.org/show_bug.cgi?id=196907 Signed-off-by: Mario Limonciello --- The particular failing configuration was reported by only ever failed for Paul Menzel, so hopefully he can test on his failing system. drivers/acpi/sleep.c | 13 - 1 file changed, 13 deletions(-) diff --git a/drivers/acpi/sleep.c b/drivers/acpi/sleep.c index 9fa77d7..2af937a 100644 --- a/drivers/acpi/sleep.c +++ b/drivers/acpi/sleep.c @@ -362,19 +362,6 @@ static const struct dmi_system_id acpisleep_dmi_table[] __initconst = { }, }, /* -* https://bugzilla.kernel.org/show_bug.cgi?id=196907 -* Some Dell XPS13 9360 cannot do suspend-to-idle using the Low Power -* S0 Idle firmware interface. -*/ - { - .callback = init_default_s3, - .ident = "Dell XPS13 9360", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), - DMI_MATCH(DMI_PRODUCT_NAME, "XPS 13 9360"), - }, - }, - /* * ThinkPad X1 Tablet(2016) cannot do suspend-to-idle using * the Low Power S0 Idle firmware interface (see * https://bugzilla.kernel.org/show_bug.cgi?id=199057). -- 2.7.4
[PATCH v2] nvme-pci: Save PCI state before putting drive into deepest state
The action of saving the PCI state will cause numerous PCI configuration space reads which depending upon the vendor implementation may cause the drive to exit the deepest NVMe state. In these cases ASPM will typically resolve the PCIe link state and APST may resolve the NVMe power state. However it has also been observed that this register access after quiesced will cause PC10 failure on some device combinations. To resolve this, move the PCI state saving to before SetFeatures has been called. This has been proven to resolve the issue across a 5000 sample test on previously failing disk/system combinations. Signed-off-by: Mario Limonciello --- drivers/nvme/host/pci.c | 17 ++--- 1 file changed, 10 insertions(+), 7 deletions(-) Changes from v1: * Discard saved state in error scenario * Removed unneeded goto statement in error scenario diff --git a/drivers/nvme/host/pci.c b/drivers/nvme/host/pci.c index 732d5b6..ef69013 100644 --- a/drivers/nvme/host/pci.c +++ b/drivers/nvme/host/pci.c @@ -2894,11 +2894,21 @@ static int nvme_suspend(struct device *dev) if (ret < 0) goto unfreeze; + /* +* A saved state prevents pci pm from generically controlling the +* device's power. If we're using protocol specific settings, we don't +* want pci interfering. +*/ + pci_save_state(pdev); + ret = nvme_set_power_state(ctrl, ctrl->npss); if (ret < 0) goto unfreeze; if (ret) { + /* discard the saved state */ + pci_load_saved_state(pdev, NULL); + /* * Clearing npss forces a controller reset on resume. The * correct value will be resdicovered then. @@ -2906,14 +2916,7 @@ static int nvme_suspend(struct device *dev) nvme_dev_disable(ndev, true); ctrl->npss = 0; ret = 0; - goto unfreeze; } - /* -* A saved state prevents pci pm from generically controlling the -* device's power. If we're using protocol specific settings, we don't -* want pci interfering. -*/ - pci_save_state(pdev); unfreeze: nvme_unfreeze(ctrl); return ret; -- 2.7.4
[PATCH] nvme-pci: Save PCI state before putting drive into deepest state
The action of saving the PCI state will cause numerous PCI configuration space reads which depending upon the vendor implementation may cause the drive to exit the deepest NVMe state. In these cases ASPM will typically resolve the PCIe link state and APST may resolve the NVMe power state. However it has also been observed that this register access after quiesced will cause PC10 failure on some device combinations. To resolve this, move the PCI state saving to before SetFeatures has been called. This has been proven to resolve the issue across a 5000 sample test on previously failing disk/system combinations. Signed-off-by: Mario Limonciello --- drivers/nvme/host/pci.c | 13 +++-- 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/drivers/nvme/host/pci.c b/drivers/nvme/host/pci.c index 732d5b6..9b3fed4 100644 --- a/drivers/nvme/host/pci.c +++ b/drivers/nvme/host/pci.c @@ -2894,6 +2894,13 @@ static int nvme_suspend(struct device *dev) if (ret < 0) goto unfreeze; + /* +* A saved state prevents pci pm from generically controlling the +* device's power. If we're using protocol specific settings, we don't +* want pci interfering. +*/ + pci_save_state(pdev); + ret = nvme_set_power_state(ctrl, ctrl->npss); if (ret < 0) goto unfreeze; @@ -2908,12 +2915,6 @@ static int nvme_suspend(struct device *dev) ret = 0; goto unfreeze; } - /* -* A saved state prevents pci pm from generically controlling the -* device's power. If we're using protocol specific settings, we don't -* want pci interfering. -*/ - pci_save_state(pdev); unfreeze: nvme_unfreeze(ctrl); return ret; -- 2.7.4
[PATCH] Revert "Bluetooth: btusb: driver to enable the usb-wakeup feature"
This reverts commit a0085f2510e8976614ad8f766b209448b385492f. This commit has caused regressions in notebooks that support suspend to idle such as the XPS 9360, XPS 9370 and XPS 9380. These notebooks will wakeup from suspend to idle from an unsolicited advertising packet from an unpaired BLE device. In a bug report it was sugggested that this is caused by a generic lack of LE privacy support. Revert this commit until that behavior can be avoided by the kernel. Fixes: a0085f2510e8 ("Bluetooth: btusb: driver to enable the usb-wakeup feature") BugLink: https://bugzilla.kernel.org/show_bug.cgi?id=200039 Link: https://marc.info/?l=linux-bluetooth&m=156441081612627&w=2 Link: https://chromium-review.googlesource.com/c/chromiumos/third_party/kernel/+/750073/ CC: Bastien Nocera CC: Christian Kellner CC: Sukumar Ghorai Signed-off-by: Mario Limonciello --- drivers/bluetooth/btusb.c | 5 - 1 file changed, 5 deletions(-) diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c index 3876fee6..33c3873 100644 --- a/drivers/bluetooth/btusb.c +++ b/drivers/bluetooth/btusb.c @@ -1170,10 +1170,6 @@ static int btusb_open(struct hci_dev *hdev) } data->intf->needs_remote_wakeup = 1; - /* device specific wakeup source enabled and required for USB -* remote wakeup while host is suspended -*/ - device_wakeup_enable(&data->udev->dev); if (test_and_set_bit(BTUSB_INTR_RUNNING, &data->flags)) goto done; @@ -1238,7 +1234,6 @@ static int btusb_close(struct hci_dev *hdev) goto failed; data->intf->needs_remote_wakeup = 0; - device_wakeup_disable(&data->udev->dev); usb_autopm_put_interface(data->intf); failed: -- 2.7.4
[PATCH v3] nvme: Add quirk for LiteON CL1 devices running FW 22301111
One of the components in LiteON CL1 device has limitations that can be encountered based upon boundary race conditions using the nvme bus specific suspend to idle flow. When this situation occurs the drive doesn't resume properly from suspend-to-idle. LiteON has confirmed this problem and fixed in the next firmware version. As this firmware is already in the field, avoid running nvme specific suspend to idle flow. Fixes: d916b1be94b6 ("nvme-pci: use host managed power state for suspend") Link: http://lists.infradead.org/pipermail/linux-nvme/2019-July/thread.html Signed-off-by: Mario Limonciello Signed-off-by: Charles Hyde --- drivers/nvme/host/core.c | 10 ++ drivers/nvme/host/nvme.h | 5 + drivers/nvme/host/pci.c | 3 ++- 3 files changed, 17 insertions(+), 1 deletion(-) This patch is the spiritual successor to the previously submitted patch "[PATCH] drivers/nvme: save/restore HMB on suspend/resume". After discussion with LiteON, they agreed to resolve the issue in their next firmware release. This patch is dependent upon commit 4eaefe8c621c6195c91044396ed8060c179f7aae which is currently in Linus' tree for the next 5.3-rcX but not yet in nvme-5.4. changes from v2: * Fix whitespace to match other nearby code changes from v1: * Group all 3 possible CL1 strings together * Remove the resume code because it's already implied by ndev->last_ps = U32_MAX diff --git a/drivers/nvme/host/core.c b/drivers/nvme/host/core.c index 8f3fbe5..a1c8c19 100644 --- a/drivers/nvme/host/core.c +++ b/drivers/nvme/host/core.c @@ -2251,6 +2251,16 @@ static const struct nvme_core_quirk_entry core_quirks[] = { .vid = 0x1179, .mn = "THNSF5256GPUK TOSHIBA", .quirks = NVME_QUIRK_NO_APST, + }, + { + /* +* This LiteON CL1-3D*-Q11 firmware version has a race +* condition associated with actions related to suspend to idle +* LiteON has resolved the problem in future firmware +*/ + .vid = 0x14a4, + .fr = "2230", + .quirks = NVME_QUIRK_SIMPLE_SUSPEND, } }; diff --git a/drivers/nvme/host/nvme.h b/drivers/nvme/host/nvme.h index 26b563f..fe1ca0d 100644 --- a/drivers/nvme/host/nvme.h +++ b/drivers/nvme/host/nvme.h @@ -92,6 +92,11 @@ enum nvme_quirks { * Broken Write Zeroes. */ NVME_QUIRK_DISABLE_WRITE_ZEROES = (1 << 9), + + /* +* Force simple suspend/resume path. +*/ + NVME_QUIRK_SIMPLE_SUSPEND = (1 << 10), }; /* diff --git a/drivers/nvme/host/pci.c b/drivers/nvme/host/pci.c index 108e109..b366f54 100644 --- a/drivers/nvme/host/pci.c +++ b/drivers/nvme/host/pci.c @@ -2875,7 +2875,8 @@ static int nvme_suspend(struct device *dev) * state (which may not be possible if the link is up). */ if (pm_suspend_via_firmware() || !ctrl->npss || - !pcie_aspm_enabled(pdev)) { + !pcie_aspm_enabled(pdev) || + (ndev->ctrl.quirks & NVME_QUIRK_SIMPLE_SUSPEND)) { nvme_dev_disable(ndev, true); return 0; } -- 2.7.4
[PATCH v2] nvme: Add quirk for LiteON CL1 devices running FW 22301111
One of the components in LiteON CL1 device has limitations that can be encountered based upon boundary race conditions using the nvme bus specific suspend to idle flow. When this situation occurs the drive doesn't resume properly from suspend-to-idle. LiteON has confirmed this problem and fixed in the next firmware version. As this firmware is already in the field, avoid running nvme specific suspend to idle flow. Fixes: d916b1be94b6 ("nvme-pci: use host managed power state for suspend") Link: http://lists.infradead.org/pipermail/linux-nvme/2019-July/thread.html Signed-off-by: Mario Limonciello Signed-off-by: Charles Hyde --- drivers/nvme/host/core.c | 10 ++ drivers/nvme/host/nvme.h | 5 + drivers/nvme/host/pci.c | 3 ++- 3 files changed, 17 insertions(+), 1 deletion(-) This patch is the spiritual successor to the previously submitted patch "[PATCH] drivers/nvme: save/restore HMB on suspend/resume". After discussion with LiteON, they agreed to resolve the issue in their next firmware release. changes from v1: * Group all 3 possible CL1 strings together * Remove the resume code because it's already implied by ndev->last_ps = U32_MAX diff --git a/drivers/nvme/host/core.c b/drivers/nvme/host/core.c index 8f3fbe5..02770d6 100644 --- a/drivers/nvme/host/core.c +++ b/drivers/nvme/host/core.c @@ -2251,6 +2251,16 @@ static const struct nvme_core_quirk_entry core_quirks[] = { .vid = 0x1179, .mn = "THNSF5256GPUK TOSHIBA", .quirks = NVME_QUIRK_NO_APST, + }, + /* +* This LiteON CL1-3D*-Q11 firmware version has a race condition +* associated with actions related to suspend to idle. LiteON has +* resolved the problem in future firmware. +*/ + { + .vid = 0x14a4, + .fr = "2230", + .quirks = NVME_QUIRK_SIMPLE_SUSPEND, } }; diff --git a/drivers/nvme/host/nvme.h b/drivers/nvme/host/nvme.h index 26b563f..fe1ca0d 100644 --- a/drivers/nvme/host/nvme.h +++ b/drivers/nvme/host/nvme.h @@ -92,6 +92,11 @@ enum nvme_quirks { * Broken Write Zeroes. */ NVME_QUIRK_DISABLE_WRITE_ZEROES = (1 << 9), + + /* +* Force simple suspend/resume path. +*/ + NVME_QUIRK_SIMPLE_SUSPEND = (1 << 10), }; /* diff --git a/drivers/nvme/host/pci.c b/drivers/nvme/host/pci.c index 108e109..b366f54 100644 --- a/drivers/nvme/host/pci.c +++ b/drivers/nvme/host/pci.c @@ -2875,7 +2875,8 @@ static int nvme_suspend(struct device *dev) * state (which may not be possible if the link is up). */ if (pm_suspend_via_firmware() || !ctrl->npss || - !pcie_aspm_enabled(pdev)) { + !pcie_aspm_enabled(pdev) || + (ndev->ctrl.quirks & NVME_QUIRK_SIMPLE_SUSPEND)) { nvme_dev_disable(ndev, true); return 0; } -- 2.7.4
[PATCH] nvme: Add quirk for LiteON CL1 devices running FW 22301111
One of the components in LiteON CL1 device has limitations that can be encountered based upon boundary race conditions using the nvme bus specific suspend to idle flow. When this situation occurs the drive doesn't resume properly from suspend-to-idle. LiteON has confirmed this problem and fixed in the next firmware version. As this firmware is already in the field, avoid running nvme specific suspend to idle flow. Fixes: d916b1be94b6 ("nvme-pci: use host managed power state for suspend") Link: http://lists.infradead.org/pipermail/linux-nvme/2019-July/thread.html Signed-off-by: Mario Limonciello Signed-off-by: Charles Hyde --- drivers/nvme/host/core.c | 23 +++ drivers/nvme/host/nvme.h | 5 + drivers/nvme/host/pci.c | 4 +++- 3 files changed, 31 insertions(+), 1 deletion(-) This patch is the spiritual successor to the previously submitted patch "[PATCH] drivers/nvme: save/restore HMB on suspend/resume". After discussion with LiteON, they agreed to resolve the issue in their next firwmare release. diff --git a/drivers/nvme/host/core.c b/drivers/nvme/host/core.c index 8f3fbe5..47c7754 100644 --- a/drivers/nvme/host/core.c +++ b/drivers/nvme/host/core.c @@ -2251,6 +2251,29 @@ static const struct nvme_core_quirk_entry core_quirks[] = { .vid = 0x1179, .mn = "THNSF5256GPUK TOSHIBA", .quirks = NVME_QUIRK_NO_APST, + }, + /* +* This LiteON CL1 firmware version has a race condition associated with +* actions related to suspend to idle. LiteON has resolved the problem +* in future firmware. +*/ + { + .vid = 0x14a4, + .mn = "CL1-3D128-Q11 NVMe LITEON 128GB", + .fr = "2230", + .quirks = NVME_QUIRK_SIMPLE_SUSPEND, + }, + { + .vid = 0x14a4, + .mn = "CL1-3D256-Q11 NVMe LITEON 256GB", + .fr = "2230", + .quirks = NVME_QUIRK_SIMPLE_SUSPEND, + }, + { + .vid = 0x14a4, + .mn = "CL1-3D512-Q11 NVMe LITEON 512GB", + .fr = "2230", + .quirks = NVME_QUIRK_SIMPLE_SUSPEND, } }; diff --git a/drivers/nvme/host/nvme.h b/drivers/nvme/host/nvme.h index 26b563f..fe1ca0d 100644 --- a/drivers/nvme/host/nvme.h +++ b/drivers/nvme/host/nvme.h @@ -92,6 +92,11 @@ enum nvme_quirks { * Broken Write Zeroes. */ NVME_QUIRK_DISABLE_WRITE_ZEROES = (1 << 9), + + /* +* Force simple suspend/resume path. +*/ + NVME_QUIRK_SIMPLE_SUSPEND = (1 << 10), }; /* diff --git a/drivers/nvme/host/pci.c b/drivers/nvme/host/pci.c index 108e109..55effb5 100644 --- a/drivers/nvme/host/pci.c +++ b/drivers/nvme/host/pci.c @@ -2847,6 +2847,7 @@ static int nvme_resume(struct device *dev) struct nvme_ctrl *ctrl = &ndev->ctrl; if (ndev->last_ps == U32_MAX || + (ndev->ctrl.quirks & NVME_QUIRK_SIMPLE_SUSPEND) || nvme_set_power_state(ctrl, ndev->last_ps) != 0) nvme_reset_ctrl(ctrl); return 0; @@ -2875,7 +2876,8 @@ static int nvme_suspend(struct device *dev) * state (which may not be possible if the link is up). */ if (pm_suspend_via_firmware() || !ctrl->npss || - !pcie_aspm_enabled(pdev)) { + !pcie_aspm_enabled(pdev) || + (ndev->ctrl.quirks & NVME_QUIRK_SIMPLE_SUSPEND)) { nvme_dev_disable(ndev, true); return 0; } -- 2.7.4
[PATCH] platform/x86: dell-laptop: fix rfkill functionality
When converting the driver two arguments were transposed leading to rfkill not working. BugLink: https://bugzilla.kernel.org/show_bug.cgi?id=201427 Reported-by: Pepijn de Vos Fixes: 549b49 ("platform/x86: dell-smbios: Introduce dispatcher for SMM calls") Signed-off-by: Mario Limonciello Acked-by: Pali Rohár --- drivers/platform/x86/dell-laptop.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/platform/x86/dell-laptop.c b/drivers/platform/x86/dell-laptop.c index 95e6ca1..a561f65 100644 --- a/drivers/platform/x86/dell-laptop.c +++ b/drivers/platform/x86/dell-laptop.c @@ -531,7 +531,7 @@ static void dell_rfkill_query(struct rfkill *rfkill, void *data) return; } - dell_fill_request(&buffer, 0, 0x2, 0, 0); + dell_fill_request(&buffer, 0x2, 0, 0, 0); ret = dell_send_request(&buffer, CLASS_INFO, SELECT_RFKILL); hwswitch = buffer.output[1]; @@ -562,7 +562,7 @@ static int dell_debugfs_show(struct seq_file *s, void *data) return ret; status = buffer.output[1]; - dell_fill_request(&buffer, 0, 0x2, 0, 0); + dell_fill_request(&buffer, 0x2, 0, 0, 0); hwswitch_ret = dell_send_request(&buffer, CLASS_INFO, SELECT_RFKILL); if (hwswitch_ret) return hwswitch_ret; @@ -647,7 +647,7 @@ static void dell_update_rfkill(struct work_struct *ignored) if (ret != 0) return; - dell_fill_request(&buffer, 0, 0x2, 0, 0); + dell_fill_request(&buffer, 0x2, 0, 0, 0); ret = dell_send_request(&buffer, CLASS_INFO, SELECT_RFKILL); if (ret == 0 && (status & BIT(0))) -- 2.7.4
[PATCH] r8152: Add support for MAC address pass through on RTL8153-BND
All previous docks and dongles that have supported this feature use the RTL8153-AD chip. RTL8153-BND is a new chip that will be used in upcoming Dell type-C docks. It should be added to the whitelist of devices to activate MAC address pass through. Per confirming with Realtek all devices containing RTL8153-BND should activate MAC pass through and there won't use pass through bit on efuse like in RTL8153-AD. Signed-off-by: Mario Limonciello --- drivers/net/usb/r8152.c | 33 ++--- 1 file changed, 22 insertions(+), 11 deletions(-) diff --git a/drivers/net/usb/r8152.c b/drivers/net/usb/r8152.c index f1b5201..60dd1ec 100644 --- a/drivers/net/usb/r8152.c +++ b/drivers/net/usb/r8152.c @@ -129,6 +129,7 @@ #define USB_UPS_CTRL 0xd800 #define USB_POWER_CUT 0xd80a #define USB_MISC_0 0xd81a +#define USB_MISC_1 0xd81f #define USB_AFE_CTRL2 0xd824 #define USB_UPS_CFG0xd842 #define USB_UPS_FLAGS 0xd848 @@ -555,6 +556,7 @@ enum spd_duplex { /* MAC PASSTHRU */ #define AD_MASK0xfee0 +#define BND_MASK 0x0004 #define EFUSE 0xcfdb #define PASS_THRU_MASK 0x1 @@ -1150,7 +1152,7 @@ static int rtl8152_set_mac_address(struct net_device *netdev, void *p) return ret; } -/* Devices containing RTL8153-AD can support a persistent +/* Devices containing proper chips can support a persistent * host system provided MAC address. * Examples of this are Dell TB15 and Dell WD15 docks */ @@ -1165,13 +1167,23 @@ static int vendor_mac_passthru_addr_read(struct r8152 *tp, struct sockaddr *sa) /* test for -AD variant of RTL8153 */ ocp_data = ocp_read_word(tp, MCU_TYPE_USB, USB_MISC_0); - if ((ocp_data & AD_MASK) != 0x1000) - return -ENODEV; - - /* test for MAC address pass-through bit */ - ocp_data = ocp_read_byte(tp, MCU_TYPE_USB, EFUSE); - if ((ocp_data & PASS_THRU_MASK) != 1) - return -ENODEV; + if ((ocp_data & AD_MASK) == 0x1000) { + /* test for MAC address pass-through bit */ + ocp_data = ocp_read_byte(tp, MCU_TYPE_USB, EFUSE); + if ((ocp_data & PASS_THRU_MASK) != 1) { + netif_dbg(tp, probe, tp->netdev, + "No efuse for RTL8153-AD MAC pass through\n"); + return -ENODEV; + } + } else { + /* test for RTL8153-BND */ + ocp_data = ocp_read_byte(tp, MCU_TYPE_USB, USB_MISC_1); + if ((ocp_data & BND_MASK) == 0) { + netif_dbg(tp, probe, tp->netdev, + "Invalid variant for MAC pass through\n"); + return -ENODEV; + } + } /* returns _AUXMAC_#AABBCCDDEEFF# */ status = acpi_evaluate_object(NULL, "\\_SB.AMAC", NULL, &buffer); @@ -1217,9 +1229,8 @@ static int set_ethernet_addr(struct r8152 *tp) if (tp->version == RTL_VER_01) { ret = pla_ocp_read(tp, PLA_IDR, 8, sa.sa_data); } else { - /* if this is not an RTL8153-AD, no eFuse mac pass thru set, -* or system doesn't provide valid _SB.AMAC this will be -* be expected to non-zero + /* if device doesn't support MAC pass through this will +* be expected to be non-zero */ ret = vendor_mac_passthru_addr_read(tp, &sa); if (ret < 0) -- 2.7.4
[PATCH] platform/x86: intel-wmi-thunderbolt: Add dynamic debugging
Some users have been reporting issues with thunderbolt being turned off before fully initialized. This is suspected to be caused by userspace turning off the Thunderbolt controller using intel-wmi-thunderbolt prematurely. Details are available here: https://bugzilla.kernel.org/show_bug.cgi?id=201227 https://bugzilla.kernel.org/show_bug.cgi?id=199631 Userspace has already made some mitigiations for this situation: https://github.com/hughsie/fwupd/commit/ef6f1d76983c9b66 https://github.com/hughsie/fwupd/commit/c07ce5b4889a5384 To allow easier debugging of this situation add output that can be turned on with dynamic debugging to better root cause this problem. Suggested-by: Mika Westerberg Signed-off-by: Mario Limonciello --- drivers/platform/x86/intel-wmi-thunderbolt.c | 6 +- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/drivers/platform/x86/intel-wmi-thunderbolt.c b/drivers/platform/x86/intel-wmi-thunderbolt.c index c2257bd..ce5fbf0 100644 --- a/drivers/platform/x86/intel-wmi-thunderbolt.c +++ b/drivers/platform/x86/intel-wmi-thunderbolt.c @@ -38,12 +38,16 @@ static ssize_t force_power_store(struct device *dev, input.length = sizeof(u8); input.pointer = &mode; mode = hex_to_bin(buf[0]); + dev_dbg(dev, "force_power: storing %#x\n", mode); if (mode == 0 || mode == 1) { status = wmi_evaluate_method(INTEL_WMI_THUNDERBOLT_GUID, 0, 1, &input, NULL); - if (ACPI_FAILURE(status)) + if (ACPI_FAILURE(status)) { + dev_dbg(dev, "force_power: failed to evaluate ACPI method\n"); return -ENODEV; + } } else { + dev_dbg(dev, "force_power: unsupported mode\n"); return -EINVAL; } return count; -- 2.7.4
[PATCH 1/2] platform/x86: dell-smbios-wmi: Correct a memory leak
ACPI buffers were being allocated but never freed. Reported-by: Pinzhen Xu Signed-off-by: Mario Limonciello Cc: sta...@vger.kernel.org --- drivers/platform/x86/dell-smbios-wmi.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/platform/x86/dell-smbios-wmi.c b/drivers/platform/x86/dell-smbios-wmi.c index 88afe56..cf2229e 100644 --- a/drivers/platform/x86/dell-smbios-wmi.c +++ b/drivers/platform/x86/dell-smbios-wmi.c @@ -78,6 +78,7 @@ static int run_smbios_call(struct wmi_device *wdev) dev_dbg(&wdev->dev, "result: [%08x,%08x,%08x,%08x]\n", priv->buf->std.output[0], priv->buf->std.output[1], priv->buf->std.output[2], priv->buf->std.output[3]); + kfree(output.pointer); return 0; } -- 2.7.4
[PATCH 2/2] platform/x86: alienware-wmi: Correct a memory leak
An ACPI buffer that was allocated was not being freed after use. Signed-off-by: Mario Limonciello Cc: sta...@vger.kernel.org --- drivers/platform/x86/alienware-wmi.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/platform/x86/alienware-wmi.c b/drivers/platform/x86/alienware-wmi.c index d975462..f10af5c 100644 --- a/drivers/platform/x86/alienware-wmi.c +++ b/drivers/platform/x86/alienware-wmi.c @@ -536,6 +536,7 @@ static acpi_status alienware_wmax_command(struct wmax_basic_args *in_args, if (obj && obj->type == ACPI_TYPE_INTEGER) *out_data = (u32) obj->integer.value; } + kfree(output.pointer); return status; } -- 2.7.4
[PATCH] platform/x86: dell-smbios-base: Support systems without tokens
Some Dell servers can use dell-smbios but they don't support the token interface. Make it optional. Signed-off-by: Mario Limonciello --- drivers/platform/x86/dell-smbios-base.c | 35 - 1 file changed, 21 insertions(+), 14 deletions(-) diff --git a/drivers/platform/x86/dell-smbios-base.c b/drivers/platform/x86/dell-smbios-base.c index 446dbff..ac88032 100644 --- a/drivers/platform/x86/dell-smbios-base.c +++ b/drivers/platform/x86/dell-smbios-base.c @@ -212,6 +212,12 @@ int dell_smbios_call_filter(struct device *d, if ((buffer->cmd_class == CLASS_TOKEN_READ || buffer->cmd_class == CLASS_TOKEN_WRITE) && buffer->cmd_select < 3) { + /* tokens enabled ? */ + if (!da_tokens) { + dev_dbg(d, "no token support on this system\n"); + return -EINVAL; + } + /* find the matching token ID */ for (i = 0; i < da_num_tokens; i++) { if (da_tokens[i].location != buffer->input[0]) @@ -315,6 +321,9 @@ struct calling_interface_token *dell_smbios_find_token(int tokenid) { int i; + if (!da_tokens) + return NULL; + for (i = 0; i < da_num_tokens; i++) { if (da_tokens[i].tokenID == tokenid) return &da_tokens[i]; @@ -570,11 +579,6 @@ static int __init dell_smbios_init(void) dmi_walk(find_tokens, NULL); - if (!da_tokens) { - pr_info("Unable to find dmi tokens\n"); - return -ENODEV; - } - ret = platform_driver_register(&platform_driver); if (ret) goto fail_platform_driver; @@ -588,13 +592,6 @@ static int __init dell_smbios_init(void) if (ret) goto fail_platform_device_add; - /* duplicate tokens will cause problems building sysfs files */ - zero_duplicates(&platform_device->dev); - - ret = build_tokens_sysfs(platform_device); - if (ret) - goto fail_create_group; - /* register backends */ wmi = init_dell_smbios_wmi(); if (wmi) @@ -605,7 +602,16 @@ static int __init dell_smbios_init(void) if (wmi && smm) { pr_err("No SMBIOS backends available (wmi: %d, smm: %d)\n", wmi, smm); - goto fail_sysfs; + goto fail_create_group; + } + + if (da_tokens) { + /* duplicate tokens will cause problems building sysfs files */ + zero_duplicates(&platform_device->dev); + + ret = build_tokens_sysfs(platform_device); + if (ret) + goto fail_sysfs; } return 0; @@ -633,7 +639,8 @@ static void __exit dell_smbios_exit(void) exit_dell_smbios_smm(); mutex_lock(&smbios_mutex); if (platform_device) { - free_group(platform_device); + if (da_tokens) + free_group(platform_device); platform_device_unregister(platform_device); platform_driver_unregister(&platform_driver); } -- 2.7.4
[PATCH] platform/x86: Kconfig: Fix dell-laptop dependency chain.
As reported by Randy Dunlap: >> WARNING: unmet direct dependencies detected for DELL_SMBIOS >> Depends on [m]: X86 [=y] && X86_PLATFORM_DEVICES [=y] >> && (DCDBAS [=m] || >> DCDBAS [=m]=n) && (ACPI_WMI [=n] || ACPI_WMI [=n]=n) >> Selected by [y]: >> - DELL_LAPTOP [=y] && X86 [=y] && X86_PLATFORM_DEVICES [=y] >> && DMI [=y] >> && BACKLIGHT_CLASS_DEVICE [=y] && (ACPI_VIDEO [=n] || >> ACPI_VIDEO [=n]=n) >> && (RFKILL [=n] || RFKILL [=n]=n) && SERIO_I8042 [=y] >> Right now it's possible to set dell laptop to compile in but this causes dell-smbios to compile in which breaks if dcdbas is a module. Dell laptop shouldn't select dell-smbios anymore, but depend on it. Fixes: 32d7b19 (platform/x86: dell-smbios: Resolve dependency error on DCDBAS) Reported-by: Randy Dunlap Signed-off-by: Mario Limonciello --- drivers/platform/x86/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig index 39d06dd..bc309c5 100644 --- a/drivers/platform/x86/Kconfig +++ b/drivers/platform/x86/Kconfig @@ -154,7 +154,7 @@ config DELL_LAPTOP depends on ACPI_VIDEO || ACPI_VIDEO = n depends on RFKILL || RFKILL = n depends on SERIO_I8042 - select DELL_SMBIOS + depends on DELL_SMBIOS select POWER_SUPPLY select LEDS_CLASS select NEW_LEDS -- 2.7.4
[PATCH] platform/x86: dell-smbios: Match on www.dell.com in OEM strings too
Sergey reported that some much older Dell systems don't support the OEM string "Dell System" but instead supported www.dell.com in OEM strings. Match both of these to indicate that this driver is running on a Dell system. Reported-by: Sergey Kubushyn Signed-off-by: Mario Limonciello Tested-by: Sergey Kubushyn --- drivers/platform/x86/dell-smbios-base.c | 10 +++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/drivers/platform/x86/dell-smbios-base.c b/drivers/platform/x86/dell-smbios-base.c index 2485c80..fbd6557 100644 --- a/drivers/platform/x86/dell-smbios-base.c +++ b/drivers/platform/x86/dell-smbios-base.c @@ -555,11 +555,15 @@ static void free_group(struct platform_device *pdev) static int __init dell_smbios_init(void) { - const struct dmi_device *valid; + const struct dmi_device *valid_dell_system; + const struct dmi_device *valid_www; int ret, wmi, smm; - valid = dmi_find_device(DMI_DEV_TYPE_OEM_STRING, "Dell System", NULL); - if (!valid) { + valid_dell_system = + dmi_find_device(DMI_DEV_TYPE_OEM_STRING, "Dell System", NULL); + valid_www = + dmi_find_device(DMI_DEV_TYPE_OEM_STRING, "www.dell.com", NULL); + if (!valid_dell_system && !valid_www) { pr_err("Unable to run on non-Dell system\n"); return -ENODEV; } -- 2.7.4
[PATCH v3 2/2] power/hibernate: Change message when writing to /sys/power/resume
This file is used both for setting the wakeup device without kernel command line as well as for actually waking the system (when appropriate swap header is in place). To avoid confusion on incorrect logs in system log downgrade the message to debug and make it clearer. Signed-off-by: Mario Limonciello --- kernel/power/hibernate.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kernel/power/hibernate.c b/kernel/power/hibernate.c index d58fad3d..1028ecb 100644 --- a/kernel/power/hibernate.c +++ b/kernel/power/hibernate.c @@ -1053,7 +1053,7 @@ static ssize_t resume_store(struct kobject *kobj, struct kobj_attribute *attr, lock_system_sleep(); swsusp_resume_device = res; unlock_system_sleep(); - pr_info("Starting manual resume from disk\n"); + pm_pr_dbg("Configured resume from disk to %u\n", swsusp_resume_device); noresume = 0; software_resume(); return n; -- 2.7.4
[PATCH v3 1/2] power/hibernate: Make passing hibernate offsets more friendly
Currently the only way to specify a hibernate offset for a swap file is on the kernel command line. Add a new /sys/power/resume_offset that lets userspace specify the offset and disk to use when initiating a hibernate cycle. Signed-off-by: Mario Limonciello --- Changes from v2: * Cast the output for sector_t when printing * Fix a compilation problem with i386 due to different size of sector_t Documentation/ABI/testing/sysfs-power | 14 ++ Documentation/power/swsusp.txt| 10 +- kernel/power/hibernate.c | 24 3 files changed, 47 insertions(+), 1 deletion(-) diff --git a/Documentation/ABI/testing/sysfs-power b/Documentation/ABI/testing/sysfs-power index 1e0d1da..2f813d6 100644 --- a/Documentation/ABI/testing/sysfs-power +++ b/Documentation/ABI/testing/sysfs-power @@ -287,3 +287,17 @@ Description: Writing a "1" to this file enables the debug messages and writing a "0" (default) to it disables them. Reads from this file return the current value. + +What: /sys/power/resume_offset +Date: April 2018 +Contact: Mario Limonciello +Description: + This file is used for telling the kernel an offset into a disk + to use when hibernating the system such as with a swap file. + + Reads from this file will display the current offset + the kernel will be using on the next hibernation + attempt. + + Using this sysfs file will override any values that were + set using the kernel command line for disk offset. \ No newline at end of file diff --git a/Documentation/power/swsusp.txt b/Documentation/power/swsusp.txt index 9f2f942..cc87adf 100644 --- a/Documentation/power/swsusp.txt +++ b/Documentation/power/swsusp.txt @@ -24,8 +24,16 @@ Some warnings, first. * see the FAQ below for details. (This is not true for more traditional * power states like "standby", which normally don't turn USB off.) +Swap partition: You need to append resume=/dev/your_swap_partition to kernel command -line. Then you suspend by +line or specify it using /sys/power/resume. + +Swap file: +If using a swapfile you can also specify a resume offset using +resume_offset= on the kernel command line or specify it +in /sys/power/resume_offset. + +After preparing then you suspend by echo shutdown > /sys/power/disk; echo disk > /sys/power/state diff --git a/kernel/power/hibernate.c b/kernel/power/hibernate.c index a5c36e9..d58fad3d 100644 --- a/kernel/power/hibernate.c +++ b/kernel/power/hibernate.c @@ -1061,6 +1061,29 @@ static ssize_t resume_store(struct kobject *kobj, struct kobj_attribute *attr, power_attr(resume); +static ssize_t resume_offset_show(struct kobject *kobj, + struct kobj_attribute *attr, char *buf) +{ + return sprintf(buf, "%llu\n", (unsigned long long)swsusp_resume_block); +} + +static ssize_t resume_offset_store(struct kobject *kobj, + struct kobj_attribute *attr, const char *buf, + size_t n) +{ + unsigned long long offset; + int rc; + + rc = kstrtoull(buf, 0, &offset); + if (rc) + return rc; + swsusp_resume_block = offset; + + return n; +} + +power_attr(resume_offset); + static ssize_t image_size_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf) { @@ -1106,6 +1129,7 @@ power_attr(reserved_size); static struct attribute * g[] = { &disk_attr.attr, + &resume_offset_attr.attr, &resume_attr.attr, &image_size_attr.attr, &reserved_size_attr.attr, -- 2.7.4
[PATCH v2 2/2] power/hibernate: Change message when writing to /sys/power/resume
This file is used both for setting the wakeup device without kernel command line as well as for actually waking the system (when appropriate swap header is in place). To avoid confusion on incorrect logs in system log downgrade the message to debug and make it clearer. Signed-off-by: Mario Limonciello --- kernel/power/hibernate.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kernel/power/hibernate.c b/kernel/power/hibernate.c index 16e8645..15bc3cd 100644 --- a/kernel/power/hibernate.c +++ b/kernel/power/hibernate.c @@ -1053,7 +1053,7 @@ static ssize_t resume_store(struct kobject *kobj, struct kobj_attribute *attr, lock_system_sleep(); swsusp_resume_device = res; unlock_system_sleep(); - pr_info("Starting manual resume from disk\n"); + pm_pr_dbg("Configured resume from disk to %u\n", swsusp_resume_device); noresume = 0; software_resume(); return n; -- 2.7.4
[PATCH v2 1/2] power/hibernate: Make passing hibernate offsets more friendly
Currently the only way to specify a hibernate offset for a swap file is on the kernel command line. Add a new /sys/power/resume_offset that lets userspace specify the offset and disk to use when initiating a hibernate cycle. Signed-off-by: Mario Limonciello --- Documentation/ABI/testing/sysfs-power | 14 ++ Documentation/power/swsusp.txt| 10 +- kernel/power/hibernate.c | 21 + 3 files changed, 44 insertions(+), 1 deletion(-) diff --git a/Documentation/ABI/testing/sysfs-power b/Documentation/ABI/testing/sysfs-power index 1e0d1da..2f813d6 100644 --- a/Documentation/ABI/testing/sysfs-power +++ b/Documentation/ABI/testing/sysfs-power @@ -287,3 +287,17 @@ Description: Writing a "1" to this file enables the debug messages and writing a "0" (default) to it disables them. Reads from this file return the current value. + +What: /sys/power/resume_offset +Date: April 2018 +Contact: Mario Limonciello +Description: + This file is used for telling the kernel an offset into a disk + to use when hibernating the system such as with a swap file. + + Reads from this file will display the current offset + the kernel will be using on the next hibernation + attempt. + + Using this sysfs file will override any values that were + set using the kernel command line for disk offset. \ No newline at end of file diff --git a/Documentation/power/swsusp.txt b/Documentation/power/swsusp.txt index 9f2f942..cc87adf 100644 --- a/Documentation/power/swsusp.txt +++ b/Documentation/power/swsusp.txt @@ -24,8 +24,16 @@ Some warnings, first. * see the FAQ below for details. (This is not true for more traditional * power states like "standby", which normally don't turn USB off.) +Swap partition: You need to append resume=/dev/your_swap_partition to kernel command -line. Then you suspend by +line or specify it using /sys/power/resume. + +Swap file: +If using a swapfile you can also specify a resume offset using +resume_offset= on the kernel command line or specify it +in /sys/power/resume_offset. + +After preparing then you suspend by echo shutdown > /sys/power/disk; echo disk > /sys/power/state diff --git a/kernel/power/hibernate.c b/kernel/power/hibernate.c index a5c36e9..16e8645 100644 --- a/kernel/power/hibernate.c +++ b/kernel/power/hibernate.c @@ -1061,6 +1061,26 @@ static ssize_t resume_store(struct kobject *kobj, struct kobj_attribute *attr, power_attr(resume); +static ssize_t resume_offset_show(struct kobject *kobj, + struct kobj_attribute *attr, char *buf) +{ + return sprintf(buf, "%lu\n", swsusp_resume_block); +} + +static ssize_t resume_offset_store(struct kobject *kobj, + struct kobj_attribute *attr, const char *buf, + size_t n) +{ + int rc = kstrtoul(buf, 0, &swsusp_resume_block); + + if (rc) + return rc; + + return n; +} + +power_attr(resume_offset); + static ssize_t image_size_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf) { @@ -1106,6 +1126,7 @@ power_attr(reserved_size); static struct attribute * g[] = { &disk_attr.attr, + &resume_offset_attr.attr, &resume_attr.attr, &image_size_attr.attr, &reserved_size_attr.attr, -- 2.7.4
[PATCH] power/hibernate: Make passing hibernate offsets more friendly
Currently the only way to specify a hibernate offset for a swap file is on the kernel command line. Add a new /sys/power/disk_offset that lets userspace specify the offset and disk to use when initiating a hibernate cycle. Also split up the parsing routine to re-use the same code for the /sys/power/resume and /sys/power/disk_offset parsing. Signed-off-by: Mario Limonciello --- Documentation/ABI/testing/sysfs-power | 43 + Documentation/power/swsusp.txt| 10 +++- kernel/power/hibernate.c | 88 +-- 3 files changed, 125 insertions(+), 16 deletions(-) diff --git a/Documentation/ABI/testing/sysfs-power b/Documentation/ABI/testing/sysfs-power index 1e0d1da..9b66cd6 100644 --- a/Documentation/ABI/testing/sysfs-power +++ b/Documentation/ABI/testing/sysfs-power @@ -287,3 +287,46 @@ Description: Writing a "1" to this file enables the debug messages and writing a "0" (default) to it disables them. Reads from this file return the current value. + +What: /sys/power/disk_offset +Date: April 2018 +Contact: Mario Limonciello +Description: + This file is used for telling the kernel which disk partiion + and offset to use when hibernating the system. + + Reads from this file will display the current disk and + offset the kernel will be using on the next hibernation + attempt. + + Using this sysfs file will override any values that were + set using the kernel command line for resume disk or offset. + + Swap partition + -- + You can write the partition to this file with no offset. + + For example to use a swap partition you may write: + - "8:2" into the file. + or + - "/dev/sda2" into the file. + or + - "PARTUUID=a1386b9c-0d2a-41dd-bcf5-b9b19a863bfb" into the file + + Note: writing a partition with no offset will also reset the + offset to zero. + + Swap file + - + To use a swapfile you will need to write the partition + containing the swapfile along with a ";" and offset within + the partition that points to that file. + + For example to use a swapfile located in the disk you + may write: + - "8:2;38416" into the file. + or + - "/dev/sda2;38416" into the file + or + - "PARTUUID=a1386b9c-0d2a-41dd-bcf5-b9b19a863bfb;38416" into + the file diff --git a/Documentation/power/swsusp.txt b/Documentation/power/swsusp.txt index 9f2f942..539bb0b 100644 --- a/Documentation/power/swsusp.txt +++ b/Documentation/power/swsusp.txt @@ -24,8 +24,16 @@ Some warnings, first. * see the FAQ below for details. (This is not true for more traditional * power states like "standby", which normally don't turn USB off.) +Swap partition: You need to append resume=/dev/your_swap_partition to kernel command -line. Then you suspend by +line or specify it using /sys/power/disk_offset. + +Swap file: +If using a swapfile you can also specify a resume offset usin +resume_offset= on the kernel command line or specify it after +the disk with a ";" in /sys/power/disk_offset. + +After preparing then you suspend by echo shutdown > /sys/power/disk; echo disk > /sys/power/state diff --git a/kernel/power/hibernate.c b/kernel/power/hibernate.c index a5c36e9..fc9dc7a 100644 --- a/kernel/power/hibernate.c +++ b/kernel/power/hibernate.c @@ -1025,33 +1025,69 @@ static ssize_t disk_store(struct kobject *kobj, struct kobj_attribute *attr, power_attr(disk); +static int parse_device_input(const char *buf, size_t n, bool update_offset) +{ + char *start, *tok, *end; + int ret = -EINVAL; + dev_t res = 0; + int len = n; + + if (!len) + return ret; + if (buf[len-1] == '\n') + len--; + start = end = kstrndup(buf, len, GFP_KERNEL); + if (!end) + return -ENOMEM; + + tok = strsep(&end, ";"); + if (!tok) + goto out; + + res = name_to_dev_t(tok); + if (!res) + goto out; + ret = 0; + + /* keep behavior for /sys/power/resume */ + if (!update_offset) + goto out_name; + + /* If no offset specified, reset it */ + tok = strsep(&end, ";"); + if (!tok) { + swsusp_resume_block = 0; + goto out_name; + } + + ret = kstrtoull(tok, 0, (unsigned long long *) &swsusp_resume_block); + if (ret)
[RFC] power/hibernate: Make passing hibernate offsets more friendly
Currently the only way to specify a hibernate offset for a swap file is on the kernel command line. This makes some changes to improve: 1) Add a new /sys/power/disk_offset that lets userspace specify the offset and disk to use when initiating a hibernate cycle. 2) Adjust /sys/power/resume interpretation to also read in an offset. Actually klibc's /bin/resume has supported passing a hibernate offset in since 20695264e21dcbde309cd81f73cfe2cea42e779d. The kernel was just lobbing anything after the device specified off the string. Instead parse that and populate hibernate offset with it. Signed-off-by: Mario Limonciello --- An alternative to introducing a new sysfs parameter may be to document setting these values via /sys/power/resume. If the wrong signature is found on the swapfile/swap partition by the kernel it does show an error but it updates the values and they'll work when actually invoked later. In that case it may make sense to adjust that error and make it level info and explain the situation. kernel/power/hibernate.c | 59 ++-- 1 file changed, 47 insertions(+), 12 deletions(-) diff --git a/kernel/power/hibernate.c b/kernel/power/hibernate.c index a5c36e9..f606ed6 100644 --- a/kernel/power/hibernate.c +++ b/kernel/power/hibernate.c @@ -1025,33 +1025,68 @@ static ssize_t disk_store(struct kobject *kobj, struct kobj_attribute *attr, power_attr(disk); -static ssize_t resume_show(struct kobject *kobj, struct kobj_attribute *attr, - char *buf) -{ - return sprintf(buf,"%d:%d\n", MAJOR(swsusp_resume_device), - MINOR(swsusp_resume_device)); -} - -static ssize_t resume_store(struct kobject *kobj, struct kobj_attribute *attr, - const char *buf, size_t n) +static int parse_device_input(const char *buf, size_t n) { + unsigned long long offset; dev_t res; int len = n; char *name; + char *last; if (len && buf[len-1] == '\n') len--; name = kstrndup(buf, len, GFP_KERNEL); if (!name) return -ENOMEM; - + last = strrchr(name, ':'); + printk("%lu %s %s %d", last-name, name, last, len); + if (last != NULL && + (last-name) != len-1 && + sscanf(last+1, "%llu", &offset) == 1) +swsusp_resume_block = offset; res = name_to_dev_t(name); kfree(name); if (!res) return -EINVAL; + swsusp_resume_device = res; + + return 1; +} + +static ssize_t disk_offset_show(struct kobject *kobj, struct kobj_attribute *attr, + char *buf) +{ + return sprintf(buf,"%d:%d:%lu\n", MAJOR(swsusp_resume_device), + MINOR(swsusp_resume_device), swsusp_resume_block); +} + +static ssize_t disk_offset_store(struct kobject *kobj, struct kobj_attribute *attr, +const char *buf, size_t n) +{ + ssize_t rc = parse_device_input(buf, n); + if (rc < 0) + return rc; + + return n; +} + +power_attr(disk_offset); + +static ssize_t resume_show(struct kobject *kobj, struct kobj_attribute *attr, + char *buf) +{ + return sprintf(buf,"%d:%d\n", MAJOR(swsusp_resume_device), + MINOR(swsusp_resume_device)); +} + +static ssize_t resume_store(struct kobject *kobj, struct kobj_attribute *attr, + const char *buf, size_t n) +{ + ssize_t rc = parse_device_input(buf, n); + if (rc < 0) + return rc; lock_system_sleep(); - swsusp_resume_device = res; unlock_system_sleep(); pr_info("Starting manual resume from disk\n"); noresume = 0; @@ -1106,6 +1141,7 @@ power_attr(reserved_size); static struct attribute * g[] = { &disk_attr.attr, + &disk_offset_attr.attr, &resume_attr.attr, &image_size_attr.attr, &reserved_size_attr.attr, @@ -1125,7 +1161,6 @@ static int __init pm_disk_init(void) core_initcall(pm_disk_init); - static int __init resume_setup(char *str) { if (noresume) -- 2.7.4
[PATCH v3 1/3] platform/x86: dell-smbios: Correct some style warnings
WARNING: function definition argument 'struct calling_interface_buffer *' should also have an identifier name + int (*call_fn)(struct calling_interface_buffer *); WARNING: Block comments use * on subsequent lines + /* 4 bytes of table header, plus 7 bytes of Dell header, plus at least + 6 bytes of entry */ WARNING: Block comments use a trailing */ on a separate line + 6 bytes of entry */ Signed-off-by: Mario Limonciello --- drivers/platform/x86/dell-smbios.c | 8 +--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/drivers/platform/x86/dell-smbios.c b/drivers/platform/x86/dell-smbios.c index 8541cde..76b9d75 100644 --- a/drivers/platform/x86/dell-smbios.c +++ b/drivers/platform/x86/dell-smbios.c @@ -36,7 +36,7 @@ static DEFINE_MUTEX(smbios_mutex); struct smbios_device { struct list_head list; struct device *device; - int (*call_fn)(struct calling_interface_buffer *); + int (*call_fn)(struct calling_interface_buffer *arg); }; struct smbios_call { @@ -352,8 +352,10 @@ static void __init parse_da_table(const struct dmi_header *dm) struct calling_interface_structure *table = container_of(dm, struct calling_interface_structure, header); - /* 4 bytes of table header, plus 7 bytes of Dell header, plus at least - 6 bytes of entry */ + /* +* 4 bytes of table header, plus 7 bytes of Dell header +* plus at least 6 bytes of entry +*/ if (dm->length < 17) return; -- 2.7.4
[PATCH v3 3/3] platform/x86: dell-smbios: Link all dell-smbios-* modules together
Some race conditions were raised due to dell-smbios and its backends not being ready by the time that a consumer would call one of the exported methods. To avoid this problem, guarantee that all initialization has been done by linking them all together and running init for them all. As part of this change the Kconfig needs to be adjusted so that CONFIG_DELL_SMBIOS_SMM and CONFIG_DELL_SMBIOS_WMI are boolean rather than modules. CONFIG_DELL_SMBIOS is a visually selectable option again and both CONFIG_DELL_SMBIOS_WMI and CONFIG_DELL_SMBIOS_SMM are optional. Signed-off-by: Mario Limonciello --- Changes from v2: * Move rest of #ifdef out of source files * Only compile units as necessary drivers/platform/x86/Kconfig| 11 --- drivers/platform/x86/Makefile | 4 ++-- drivers/platform/x86/dell-smbios-base.c | 21 - drivers/platform/x86/dell-smbios-smm.c | 18 -- drivers/platform/x86/dell-smbios-wmi.c | 14 -- drivers/platform/x86/dell-smbios.h | 27 ++- 6 files changed, 64 insertions(+), 31 deletions(-) diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig index 9a8f964..0c0897e 100644 --- a/drivers/platform/x86/Kconfig +++ b/drivers/platform/x86/Kconfig @@ -106,10 +106,15 @@ config ASUS_LAPTOP If you have an ACPI-compatible ASUS laptop, say Y or M here. config DELL_SMBIOS - tristate + tristate "Dell SMBIOS driver" + ---help--- + This provides support for the Dell SMBIOS calling interface. + If you have a Dell computer you should enable this option. + + Be sure to select at least one backend for it to work properly. config DELL_SMBIOS_WMI - tristate "Dell SMBIOS calling interface (WMI implementation)" + bool "Dell SMBIOS driver WMI support" depends on ACPI_WMI select DELL_WMI_DESCRIPTOR select DELL_SMBIOS @@ -122,7 +127,7 @@ config DELL_SMBIOS_WMI it just won't load. config DELL_SMBIOS_SMM - tristate "Dell SMBIOS calling interface (SMM implementation)" + bool "Dell SMBIOS driver SMM support" depends on DCDBAS select DELL_SMBIOS ---help--- diff --git a/drivers/platform/x86/Makefile b/drivers/platform/x86/Makefile index 940b118..2ba6cb7 100644 --- a/drivers/platform/x86/Makefile +++ b/drivers/platform/x86/Makefile @@ -14,8 +14,8 @@ obj-$(CONFIG_ACPI_CMPC) += classmate-laptop.o obj-$(CONFIG_COMPAL_LAPTOP)+= compal-laptop.o obj-$(CONFIG_DELL_SMBIOS) += dell-smbios.o dell-smbios-objs := dell-smbios-base.o -obj-$(CONFIG_DELL_SMBIOS_WMI) += dell-smbios-wmi.o -obj-$(CONFIG_DELL_SMBIOS_SMM) += dell-smbios-smm.o +dell-smbios-$(CONFIG_DELL_SMBIOS_WMI) += dell-smbios-wmi.o +dell-smbios-$(CONFIG_DELL_SMBIOS_SMM) += dell-smbios-smm.o obj-$(CONFIG_DELL_LAPTOP) += dell-laptop.o obj-$(CONFIG_DELL_WMI) += dell-wmi.o obj-$(CONFIG_DELL_WMI_DESCRIPTOR) += dell-wmi-descriptor.o diff --git a/drivers/platform/x86/dell-smbios-base.c b/drivers/platform/x86/dell-smbios-base.c index 76b9d75..5bcf8a1 100644 --- a/drivers/platform/x86/dell-smbios-base.c +++ b/drivers/platform/x86/dell-smbios-base.c @@ -556,7 +556,7 @@ static void free_group(struct platform_device *pdev) static int __init dell_smbios_init(void) { const struct dmi_device *valid; - int ret; + int ret, wmi, smm; valid = dmi_find_device(DMI_DEV_TYPE_OEM_STRING, "Dell System", NULL); if (!valid) { @@ -591,8 +591,24 @@ static int __init dell_smbios_init(void) if (ret) goto fail_create_group; + /* register backends */ + wmi = init_dell_smbios_wmi(); + if (wmi) + pr_debug("Failed to initialize WMI backend: %d\n", wmi); + smm = init_dell_smbios_smm(); + if (smm) + pr_debug("Failed to initialize SMM backend: %d\n", smm); + if (wmi && smm) { + pr_err("No SMBIOS backends available (wmi: %d, smm: %d)\n", + wmi, smm); + goto fail_sysfs; + } + return 0; +fail_sysfs: + free_group(platform_device); + fail_create_group: platform_device_del(platform_device); @@ -609,6 +625,8 @@ static int __init dell_smbios_init(void) static void __exit dell_smbios_exit(void) { + exit_dell_smbios_wmi(); + exit_dell_smbios_smm(); mutex_lock(&smbios_mutex); if (platform_device) { free_group(platform_device); @@ -625,5 +643,6 @@ module_exit(dell_smbios_exit); MODULE_AUTHOR("Matthew Garrett "); MODULE_AUTHOR("Gabriele Mazzotta "); MODULE_AUTHOR("Pali Rohár "); +MODULE_AUTHOR("Mario Limonciello "); MODULE_DESCRIPTION("Common functions for kernel modules using Dell SMBIOS"
[PATCH v3 2/3] platform/x86: dell-smbios: Rename dell-smbios source to dell-smbios-base
This is being done to faciliate a later change to link all the dell-smbios drivers together. Signed-off-by: Mario Limonciello --- drivers/platform/x86/Makefile | 1 + drivers/platform/x86/{dell-smbios.c => dell-smbios-base.c} | 0 2 files changed, 1 insertion(+) rename drivers/platform/x86/{dell-smbios.c => dell-smbios-base.c} (100%) diff --git a/drivers/platform/x86/Makefile b/drivers/platform/x86/Makefile index c388608..940b118 100644 --- a/drivers/platform/x86/Makefile +++ b/drivers/platform/x86/Makefile @@ -13,6 +13,7 @@ obj-$(CONFIG_MSI_LAPTOP) += msi-laptop.o obj-$(CONFIG_ACPI_CMPC)+= classmate-laptop.o obj-$(CONFIG_COMPAL_LAPTOP)+= compal-laptop.o obj-$(CONFIG_DELL_SMBIOS) += dell-smbios.o +dell-smbios-objs := dell-smbios-base.o obj-$(CONFIG_DELL_SMBIOS_WMI) += dell-smbios-wmi.o obj-$(CONFIG_DELL_SMBIOS_SMM) += dell-smbios-smm.o obj-$(CONFIG_DELL_LAPTOP) += dell-laptop.o diff --git a/drivers/platform/x86/dell-smbios.c b/drivers/platform/x86/dell-smbios-base.c similarity index 100% rename from drivers/platform/x86/dell-smbios.c rename to drivers/platform/x86/dell-smbios-base.c -- 2.7.4
[PATCH v2 3/3] platform/x86: dell-smbios: Link all dell-smbios-* modules together
Some race conditions were raised due to dell-smbios and its backends not being ready by the time that a consumer would call one of the exported methods. To avoid this problem, guarantee that all initialization has been done by linking them all together and running init for them all. As part of this change the Kconfig needs to be adjusted so that CONFIG_DELL_SMBIOS_SMM and CONFIG_DELL_SMBIOS_WMI are boolean rather than modules. CONFIG_DELL_SMBIOS is a visually selectable option again and both CONFIG_DELL_SMBIOS_WMI and CONFIG_DELL_SMBIOS_SMM are optional. Signed-off-by: Mario Limonciello --- changes from v1: * Move #ifdefs into dell-smbios.h and use static inline functions drivers/platform/x86/Kconfig| 11 --- drivers/platform/x86/Makefile | 6 +++--- drivers/platform/x86/dell-smbios-base.c | 21 - drivers/platform/x86/dell-smbios-smm.c | 19 ++- drivers/platform/x86/dell-smbios-wmi.c | 16 ++-- drivers/platform/x86/dell-smbios.h | 27 ++- 6 files changed, 69 insertions(+), 31 deletions(-) diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig index 9a8f964..0c0897e 100644 --- a/drivers/platform/x86/Kconfig +++ b/drivers/platform/x86/Kconfig @@ -106,10 +106,15 @@ config ASUS_LAPTOP If you have an ACPI-compatible ASUS laptop, say Y or M here. config DELL_SMBIOS - tristate + tristate "Dell SMBIOS driver" + ---help--- + This provides support for the Dell SMBIOS calling interface. + If you have a Dell computer you should enable this option. + + Be sure to select at least one backend for it to work properly. config DELL_SMBIOS_WMI - tristate "Dell SMBIOS calling interface (WMI implementation)" + bool "Dell SMBIOS driver WMI support" depends on ACPI_WMI select DELL_WMI_DESCRIPTOR select DELL_SMBIOS @@ -122,7 +127,7 @@ config DELL_SMBIOS_WMI it just won't load. config DELL_SMBIOS_SMM - tristate "Dell SMBIOS calling interface (SMM implementation)" + bool "Dell SMBIOS driver SMM support" depends on DCDBAS select DELL_SMBIOS ---help--- diff --git a/drivers/platform/x86/Makefile b/drivers/platform/x86/Makefile index 940b118..0e242bd 100644 --- a/drivers/platform/x86/Makefile +++ b/drivers/platform/x86/Makefile @@ -13,9 +13,9 @@ obj-$(CONFIG_MSI_LAPTOP) += msi-laptop.o obj-$(CONFIG_ACPI_CMPC)+= classmate-laptop.o obj-$(CONFIG_COMPAL_LAPTOP)+= compal-laptop.o obj-$(CONFIG_DELL_SMBIOS) += dell-smbios.o -dell-smbios-objs := dell-smbios-base.o -obj-$(CONFIG_DELL_SMBIOS_WMI) += dell-smbios-wmi.o -obj-$(CONFIG_DELL_SMBIOS_SMM) += dell-smbios-smm.o +dell-smbios-objs := dell-smbios-base.o \ + dell-smbios-smm.o\ + dell-smbios-wmi.o obj-$(CONFIG_DELL_LAPTOP) += dell-laptop.o obj-$(CONFIG_DELL_WMI) += dell-wmi.o obj-$(CONFIG_DELL_WMI_DESCRIPTOR) += dell-wmi-descriptor.o diff --git a/drivers/platform/x86/dell-smbios-base.c b/drivers/platform/x86/dell-smbios-base.c index 76b9d75..5bcf8a1 100644 --- a/drivers/platform/x86/dell-smbios-base.c +++ b/drivers/platform/x86/dell-smbios-base.c @@ -556,7 +556,7 @@ static void free_group(struct platform_device *pdev) static int __init dell_smbios_init(void) { const struct dmi_device *valid; - int ret; + int ret, wmi, smm; valid = dmi_find_device(DMI_DEV_TYPE_OEM_STRING, "Dell System", NULL); if (!valid) { @@ -591,8 +591,24 @@ static int __init dell_smbios_init(void) if (ret) goto fail_create_group; + /* register backends */ + wmi = init_dell_smbios_wmi(); + if (wmi) + pr_debug("Failed to initialize WMI backend: %d\n", wmi); + smm = init_dell_smbios_smm(); + if (smm) + pr_debug("Failed to initialize SMM backend: %d\n", smm); + if (wmi && smm) { + pr_err("No SMBIOS backends available (wmi: %d, smm: %d)\n", + wmi, smm); + goto fail_sysfs; + } + return 0; +fail_sysfs: + free_group(platform_device); + fail_create_group: platform_device_del(platform_device); @@ -609,6 +625,8 @@ static int __init dell_smbios_init(void) static void __exit dell_smbios_exit(void) { + exit_dell_smbios_wmi(); + exit_dell_smbios_smm(); mutex_lock(&smbios_mutex); if (platform_device) { free_group(platform_device); @@ -625,5 +643,6 @@ module_exit(dell_smbios_exit); MODULE_AUTHOR("Matthew Garrett "); MODULE_AUTHOR("Gabriele Mazzotta "); MODULE_AUTHOR("Pali Rohár "); +MODULE_AUTHOR("Mario Limonciello &q
[PATCH v2 2/3] platform/x86: dell-smbios: Rename dell-smbios source to dell-smbios-base
This is being done to faciliate a later change to link all the dell-smbios drivers together. Signed-off-by: Mario Limonciello --- drivers/platform/x86/Makefile | 1 + drivers/platform/x86/{dell-smbios.c => dell-smbios-base.c} | 0 2 files changed, 1 insertion(+) rename drivers/platform/x86/{dell-smbios.c => dell-smbios-base.c} (100%) diff --git a/drivers/platform/x86/Makefile b/drivers/platform/x86/Makefile index c388608..940b118 100644 --- a/drivers/platform/x86/Makefile +++ b/drivers/platform/x86/Makefile @@ -13,6 +13,7 @@ obj-$(CONFIG_MSI_LAPTOP) += msi-laptop.o obj-$(CONFIG_ACPI_CMPC)+= classmate-laptop.o obj-$(CONFIG_COMPAL_LAPTOP)+= compal-laptop.o obj-$(CONFIG_DELL_SMBIOS) += dell-smbios.o +dell-smbios-objs := dell-smbios-base.o obj-$(CONFIG_DELL_SMBIOS_WMI) += dell-smbios-wmi.o obj-$(CONFIG_DELL_SMBIOS_SMM) += dell-smbios-smm.o obj-$(CONFIG_DELL_LAPTOP) += dell-laptop.o diff --git a/drivers/platform/x86/dell-smbios.c b/drivers/platform/x86/dell-smbios-base.c similarity index 100% rename from drivers/platform/x86/dell-smbios.c rename to drivers/platform/x86/dell-smbios-base.c -- 2.7.4
[PATCH v2 1/3] platform/x86: dell-smbios: Correct some style warnings
WARNING: function definition argument 'struct calling_interface_buffer *' should also have an identifier name + int (*call_fn)(struct calling_interface_buffer *); WARNING: Block comments use * on subsequent lines + /* 4 bytes of table header, plus 7 bytes of Dell header, plus at least + 6 bytes of entry */ WARNING: Block comments use a trailing */ on a separate line + 6 bytes of entry */ Signed-off-by: Mario Limonciello --- changes from v1: * Adjust comment style drivers/platform/x86/dell-smbios.c | 8 +--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/drivers/platform/x86/dell-smbios.c b/drivers/platform/x86/dell-smbios.c index 8541cde..76b9d75 100644 --- a/drivers/platform/x86/dell-smbios.c +++ b/drivers/platform/x86/dell-smbios.c @@ -36,7 +36,7 @@ static DEFINE_MUTEX(smbios_mutex); struct smbios_device { struct list_head list; struct device *device; - int (*call_fn)(struct calling_interface_buffer *); + int (*call_fn)(struct calling_interface_buffer *arg); }; struct smbios_call { @@ -352,8 +352,10 @@ static void __init parse_da_table(const struct dmi_header *dm) struct calling_interface_structure *table = container_of(dm, struct calling_interface_structure, header); - /* 4 bytes of table header, plus 7 bytes of Dell header, plus at least - 6 bytes of entry */ + /* +* 4 bytes of table header, plus 7 bytes of Dell header +* plus at least 6 bytes of entry +*/ if (dm->length < 17) return; -- 2.7.4
[PATCH 3/3] platform/x86: dell-smbios: Link all dell-smbios-* modules together
Some race conditions were raised due to dell-smbios and its backends not being ready by the time that a consumer would call one of the exported methods. To avoid this problem, guarantee that all initialization has been done by linking them all together and running init for them all. As part of this change the Kconfig needs to be adjusted so that CONFIG_DELL_SMBIOS_SMM and CONFIG_DELL_SMBIOS_WMI are boolean rather than modules. CONFIG_DELL_SMBIOS is a visually selectable option again and both CONFIG_DELL_SMBIOS_WMI and CONFIG_DELL_SMBIOS_SMM are optional. Signed-off-by: Mario Limonciello --- drivers/platform/x86/Kconfig| 11 --- drivers/platform/x86/Makefile | 6 +++--- drivers/platform/x86/dell-smbios-base.c | 21 - drivers/platform/x86/dell-smbios-smm.c | 25 + drivers/platform/x86/dell-smbios-wmi.c | 24 ++-- drivers/platform/x86/dell-smbios.h | 6 ++ 6 files changed, 64 insertions(+), 29 deletions(-) diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig index 9a8f964..0c0897e 100644 --- a/drivers/platform/x86/Kconfig +++ b/drivers/platform/x86/Kconfig @@ -106,10 +106,15 @@ config ASUS_LAPTOP If you have an ACPI-compatible ASUS laptop, say Y or M here. config DELL_SMBIOS - tristate + tristate "Dell SMBIOS driver" + ---help--- + This provides support for the Dell SMBIOS calling interface. + If you have a Dell computer you should enable this option. + + Be sure to select at least one backend for it to work properly. config DELL_SMBIOS_WMI - tristate "Dell SMBIOS calling interface (WMI implementation)" + bool "Dell SMBIOS driver WMI support" depends on ACPI_WMI select DELL_WMI_DESCRIPTOR select DELL_SMBIOS @@ -122,7 +127,7 @@ config DELL_SMBIOS_WMI it just won't load. config DELL_SMBIOS_SMM - tristate "Dell SMBIOS calling interface (SMM implementation)" + bool "Dell SMBIOS driver SMM support" depends on DCDBAS select DELL_SMBIOS ---help--- diff --git a/drivers/platform/x86/Makefile b/drivers/platform/x86/Makefile index 940b118..0e242bd 100644 --- a/drivers/platform/x86/Makefile +++ b/drivers/platform/x86/Makefile @@ -13,9 +13,9 @@ obj-$(CONFIG_MSI_LAPTOP) += msi-laptop.o obj-$(CONFIG_ACPI_CMPC)+= classmate-laptop.o obj-$(CONFIG_COMPAL_LAPTOP)+= compal-laptop.o obj-$(CONFIG_DELL_SMBIOS) += dell-smbios.o -dell-smbios-objs := dell-smbios-base.o -obj-$(CONFIG_DELL_SMBIOS_WMI) += dell-smbios-wmi.o -obj-$(CONFIG_DELL_SMBIOS_SMM) += dell-smbios-smm.o +dell-smbios-objs := dell-smbios-base.o \ + dell-smbios-smm.o\ + dell-smbios-wmi.o obj-$(CONFIG_DELL_LAPTOP) += dell-laptop.o obj-$(CONFIG_DELL_WMI) += dell-wmi.o obj-$(CONFIG_DELL_WMI_DESCRIPTOR) += dell-wmi-descriptor.o diff --git a/drivers/platform/x86/dell-smbios-base.c b/drivers/platform/x86/dell-smbios-base.c index 4850658..fdb1044 100644 --- a/drivers/platform/x86/dell-smbios-base.c +++ b/drivers/platform/x86/dell-smbios-base.c @@ -555,7 +555,7 @@ static void free_group(struct platform_device *pdev) static int __init dell_smbios_init(void) { const struct dmi_device *valid; - int ret; + int ret, wmi, smm; valid = dmi_find_device(DMI_DEV_TYPE_OEM_STRING, "Dell System", NULL); if (!valid) { @@ -590,8 +590,24 @@ static int __init dell_smbios_init(void) if (ret) goto fail_create_group; + /* register backends */ + wmi = init_dell_smbios_wmi(); + if (wmi) + pr_debug("Failed to initialize WMI backend: %d\n", wmi); + smm = init_dell_smbios_smm(); + if (smm) + pr_debug("Failed to initialize SMM backend: %d\n", smm); + if (wmi && smm) { + pr_err("No SMBIOS backends available (wmi: %d, smm: %d)\n", + wmi, smm); + goto fail_sysfs; + } + return 0; +fail_sysfs: + free_group(platform_device); + fail_create_group: platform_device_del(platform_device); @@ -608,6 +624,8 @@ static int __init dell_smbios_init(void) static void __exit dell_smbios_exit(void) { + exit_dell_smbios_wmi(); + exit_dell_smbios_smm(); mutex_lock(&smbios_mutex); if (platform_device) { free_group(platform_device); @@ -624,5 +642,6 @@ module_exit(dell_smbios_exit); MODULE_AUTHOR("Matthew Garrett "); MODULE_AUTHOR("Gabriele Mazzotta "); MODULE_AUTHOR("Pali Rohár "); +MODULE_AUTHOR("Mario Limonciello "); MODULE_DESCRIPTION("Common functions for kernel modules using Dell SMBIOS"
[PATCH 1/3] platform/x86: dell-smbios: Correct some style warnings
WARNING: function definition argument 'struct calling_interface_buffer *' should also have an identifier name + int (*call_fn)(struct calling_interface_buffer *); WARNING: Block comments use * on subsequent lines + /* 4 bytes of table header, plus 7 bytes of Dell header, plus at least + 6 bytes of entry */ WARNING: Block comments use a trailing */ on a separate line + 6 bytes of entry */ Signed-off-by: Mario Limonciello --- drivers/platform/x86/dell-smbios.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/platform/x86/dell-smbios.c b/drivers/platform/x86/dell-smbios.c index 8541cde..4850658 100644 --- a/drivers/platform/x86/dell-smbios.c +++ b/drivers/platform/x86/dell-smbios.c @@ -36,7 +36,7 @@ static DEFINE_MUTEX(smbios_mutex); struct smbios_device { struct list_head list; struct device *device; - int (*call_fn)(struct calling_interface_buffer *); + int (*call_fn)(struct calling_interface_buffer *arg); }; struct smbios_call { @@ -353,7 +353,8 @@ static void __init parse_da_table(const struct dmi_header *dm) container_of(dm, struct calling_interface_structure, header); /* 4 bytes of table header, plus 7 bytes of Dell header, plus at least - 6 bytes of entry */ +* 6 bytes of entry +*/ if (dm->length < 17) return; -- 2.7.4
[PATCH 2/3] platform/x86: dell-smbios: Rename dell-smbios source to dell-smbios-base
This is being done to faciliate a later change to link all the dell-smbios drivers together. Signed-off-by: Mario Limonciello --- drivers/platform/x86/Makefile | 1 + drivers/platform/x86/{dell-smbios.c => dell-smbios-base.c} | 0 2 files changed, 1 insertion(+) rename drivers/platform/x86/{dell-smbios.c => dell-smbios-base.c} (100%) diff --git a/drivers/platform/x86/Makefile b/drivers/platform/x86/Makefile index c388608..940b118 100644 --- a/drivers/platform/x86/Makefile +++ b/drivers/platform/x86/Makefile @@ -13,6 +13,7 @@ obj-$(CONFIG_MSI_LAPTOP) += msi-laptop.o obj-$(CONFIG_ACPI_CMPC)+= classmate-laptop.o obj-$(CONFIG_COMPAL_LAPTOP)+= compal-laptop.o obj-$(CONFIG_DELL_SMBIOS) += dell-smbios.o +dell-smbios-objs := dell-smbios-base.o obj-$(CONFIG_DELL_SMBIOS_WMI) += dell-smbios-wmi.o obj-$(CONFIG_DELL_SMBIOS_SMM) += dell-smbios-smm.o obj-$(CONFIG_DELL_LAPTOP) += dell-laptop.o diff --git a/drivers/platform/x86/dell-smbios.c b/drivers/platform/x86/dell-smbios-base.c similarity index 100% rename from drivers/platform/x86/dell-smbios.c rename to drivers/platform/x86/dell-smbios-base.c -- 2.7.4
[PATCH] platform/x86: Only activate tablet mode switch on 2-in-1's
Some laptops such as the XPS 9360 support the intel-vbtn INT33D6 interface but don't initialize the bit that intel-vbtn uses to represent switching tablet mode. By running this only on real 2-in-1's it shouldn't cause false positives. Fixes: 30323fb6d5 ("Support tablet mode switch") Reported-by: Jeremy Cline Signed-off-by: Mario Limonciello --- Note: I also moved the code for detecting tablet into it's own function. To keep things under 80 lines with if statements was making the code very unreadable otherwise. drivers/platform/x86/intel-vbtn.c | 46 --- 1 file changed, 29 insertions(+), 17 deletions(-) diff --git a/drivers/platform/x86/intel-vbtn.c b/drivers/platform/x86/intel-vbtn.c index b703d6f..8173307 100644 --- a/drivers/platform/x86/intel-vbtn.c +++ b/drivers/platform/x86/intel-vbtn.c @@ -7,6 +7,7 @@ */ #include +#include #include #include #include @@ -97,9 +98,35 @@ static void notify_handler(acpi_handle handle, u32 event, void *context) dev_dbg(&device->dev, "unknown event index 0x%x\n", event); } -static int intel_vbtn_probe(struct platform_device *device) +static void detect_tablet_mode(struct platform_device *device) { + const char *chassis_type = dmi_get_system_info(DMI_CHASSIS_TYPE); + struct intel_vbtn_priv *priv = dev_get_drvdata(&device->dev); + acpi_handle handle = ACPI_HANDLE(&device->dev); struct acpi_buffer vgbs_output = { ACPI_ALLOCATE_BUFFER, NULL }; + union acpi_object *obj; + acpi_status status; + int m; + + if (!(chassis_type && strcmp(chassis_type, "31") == 0)) + goto out; + + status = acpi_evaluate_object(handle, "VGBS", NULL, &vgbs_output); + if (ACPI_FAILURE(status)) + goto out; + + obj = vgbs_output.pointer; + if (!(obj && obj->type == ACPI_TYPE_INTEGER)) + goto out; + + m = !(obj->integer.value & TABLET_MODE_FLAG); + input_report_switch(priv->input_dev, SW_TABLET_MODE, m); +out: + kfree(vgbs_output.pointer); +} + +static int intel_vbtn_probe(struct platform_device *device) +{ acpi_handle handle = ACPI_HANDLE(&device->dev); struct intel_vbtn_priv *priv; acpi_status status; @@ -122,22 +149,7 @@ static int intel_vbtn_probe(struct platform_device *device) return err; } - /* -* VGBS being present and returning something means we have -* a tablet mode switch. -*/ - status = acpi_evaluate_object(handle, "VGBS", NULL, &vgbs_output); - if (ACPI_SUCCESS(status)) { - union acpi_object *obj = vgbs_output.pointer; - - if (obj && obj->type == ACPI_TYPE_INTEGER) { - int m = !(obj->integer.value & TABLET_MODE_FLAG); - - input_report_switch(priv->input_dev, SW_TABLET_MODE, m); - } - } - - kfree(vgbs_output.pointer); + detect_tablet_mode(device); status = acpi_install_notify_handler(handle, ACPI_DEVICE_NOTIFY, -- 2.7.4
[PATCH v2] platform/x86: dell-laptop: Allocate buffer on heap rather than globally
There is no longer a need for the buffer to be defined in first 4GB physical address space. Furthermore there may be race conditions with multiple different functions working on a module wide buffer causing incorrect results. Fixes: 549b4930f057658dc50d8010e66219233119a4d8 Suggested-by: Pali Rohar Signed-off-by: Mario Limonciello --- drivers/platform/x86/dell-laptop.c | 188 - 1 file changed, 103 insertions(+), 85 deletions(-) diff --git a/drivers/platform/x86/dell-laptop.c b/drivers/platform/x86/dell-laptop.c index fc2dfc8..a7b1419 100644 --- a/drivers/platform/x86/dell-laptop.c +++ b/drivers/platform/x86/dell-laptop.c @@ -78,7 +78,6 @@ static struct platform_driver platform_driver = { } }; -static struct calling_interface_buffer *buffer; static struct platform_device *platform_device; static struct backlight_device *dell_backlight_device; static struct rfkill *wifi_rfkill; @@ -322,7 +321,8 @@ static const struct dmi_system_id dell_quirks[] __initconst = { { } }; -static void dell_set_arguments(u32 arg0, u32 arg1, u32 arg2, u32 arg3) +static void dell_fill_request(struct calling_interface_buffer *buffer, + u32 arg0, u32 arg1, u32 arg2, u32 arg3) { memset(buffer, 0, sizeof(struct calling_interface_buffer)); buffer->input[0] = arg0; @@ -331,7 +331,8 @@ static void dell_set_arguments(u32 arg0, u32 arg1, u32 arg2, u32 arg3) buffer->input[3] = arg3; } -static int dell_send_request(u16 class, u16 select) +static int dell_send_request(struct calling_interface_buffer *buffer, +u16 class, u16 select) { int ret; @@ -468,21 +469,22 @@ static int dell_rfkill_set(void *data, bool blocked) int disable = blocked ? 1 : 0; unsigned long radio = (unsigned long)data; int hwswitch_bit = (unsigned long)data - 1; + struct calling_interface_buffer buffer; int hwswitch; int status; int ret; - dell_set_arguments(0, 0, 0, 0); - ret = dell_send_request(CLASS_INFO, SELECT_RFKILL); + dell_fill_request(&buffer, 0, 0, 0, 0); + ret = dell_send_request(&buffer, CLASS_INFO, SELECT_RFKILL); if (ret) return ret; - status = buffer->output[1]; + status = buffer.output[1]; - dell_set_arguments(0x2, 0, 0, 0); - ret = dell_send_request(CLASS_INFO, SELECT_RFKILL); + dell_fill_request(&buffer, 0x2, 0, 0, 0); + ret = dell_send_request(&buffer, CLASS_INFO, SELECT_RFKILL); if (ret) return ret; - hwswitch = buffer->output[1]; + hwswitch = buffer.output[1]; /* If the hardware switch controls this radio, and the hardware switch is disabled, always disable the radio */ @@ -490,8 +492,8 @@ static int dell_rfkill_set(void *data, bool blocked) (status & BIT(0)) && !(status & BIT(16))) disable = 1; - dell_set_arguments(1 | (radio<<8) | (disable << 16), 0, 0, 0); - ret = dell_send_request(CLASS_INFO, SELECT_RFKILL); + dell_fill_request(&buffer, 1 | (radio<<8) | (disable << 16), 0, 0, 0); + ret = dell_send_request(&buffer, CLASS_INFO, SELECT_RFKILL); return ret; } @@ -500,9 +502,11 @@ static void dell_rfkill_update_sw_state(struct rfkill *rfkill, int radio, { if (status & BIT(0)) { /* Has hw-switch, sync sw_state to BIOS */ + struct calling_interface_buffer buffer; int block = rfkill_blocked(rfkill); - dell_set_arguments(1 | (radio << 8) | (block << 16), 0, 0, 0); - dell_send_request(CLASS_INFO, SELECT_RFKILL); + dell_fill_request(&buffer, + 1 | (radio << 8) | (block << 16), 0, 0, 0); + dell_send_request(&buffer, CLASS_INFO, SELECT_RFKILL); } else { /* No hw-switch, sync BIOS state to sw_state */ rfkill_set_sw_state(rfkill, !!(status & BIT(radio + 16))); @@ -519,21 +523,22 @@ static void dell_rfkill_update_hw_state(struct rfkill *rfkill, int radio, static void dell_rfkill_query(struct rfkill *rfkill, void *data) { int radio = ((unsigned long)data & 0xF); + struct calling_interface_buffer buffer; int hwswitch; int status; int ret; - dell_set_arguments(0, 0, 0, 0); - ret = dell_send_request(CLASS_INFO, SELECT_RFKILL); - status = buffer->output[1]; + dell_fill_request(&buffer, 0, 0, 0, 0); + ret = dell_send_request(&buffer, CLASS_INFO, SELECT_RFKILL); + status = buffer.output[1]; if (ret != 0 || !(status & BIT(0))) { return; } - dell_set_arguments(0, 0x2, 0, 0); - ret = dell_send_request(CLASS_INFO,
[PATCH] platform/x86: dell-laptop: Allocate buffer on heap rather than globally
There may be race conditions with multiple different functions working on a module wide buffer causing one function to get the wrong results. Suggested-by: Pali Rohar Signed-off-by: Mario Limonciello --- drivers/platform/x86/dell-laptop.c | 188 - 1 file changed, 103 insertions(+), 85 deletions(-) diff --git a/drivers/platform/x86/dell-laptop.c b/drivers/platform/x86/dell-laptop.c index fc2dfc8..ab58373 100644 --- a/drivers/platform/x86/dell-laptop.c +++ b/drivers/platform/x86/dell-laptop.c @@ -78,7 +78,6 @@ static struct platform_driver platform_driver = { } }; -static struct calling_interface_buffer *buffer; static struct platform_device *platform_device; static struct backlight_device *dell_backlight_device; static struct rfkill *wifi_rfkill; @@ -322,7 +321,8 @@ static const struct dmi_system_id dell_quirks[] __initconst = { { } }; -static void dell_set_arguments(u32 arg0, u32 arg1, u32 arg2, u32 arg3) +static void dell_set_arguments(struct calling_interface_buffer *buffer, + u32 arg0, u32 arg1, u32 arg2, u32 arg3) { memset(buffer, 0, sizeof(struct calling_interface_buffer)); buffer->input[0] = arg0; @@ -331,7 +331,8 @@ static void dell_set_arguments(u32 arg0, u32 arg1, u32 arg2, u32 arg3) buffer->input[3] = arg3; } -static int dell_send_request(u16 class, u16 select) +static int dell_send_request(struct calling_interface_buffer *buffer, +u16 class, u16 select) { int ret; @@ -468,21 +469,22 @@ static int dell_rfkill_set(void *data, bool blocked) int disable = blocked ? 1 : 0; unsigned long radio = (unsigned long)data; int hwswitch_bit = (unsigned long)data - 1; + struct calling_interface_buffer buffer; int hwswitch; int status; int ret; - dell_set_arguments(0, 0, 0, 0); - ret = dell_send_request(CLASS_INFO, SELECT_RFKILL); + dell_set_arguments(&buffer, 0, 0, 0, 0); + ret = dell_send_request(&buffer, CLASS_INFO, SELECT_RFKILL); if (ret) return ret; - status = buffer->output[1]; + status = buffer.output[1]; - dell_set_arguments(0x2, 0, 0, 0); - ret = dell_send_request(CLASS_INFO, SELECT_RFKILL); + dell_set_arguments(&buffer, 0x2, 0, 0, 0); + ret = dell_send_request(&buffer, CLASS_INFO, SELECT_RFKILL); if (ret) return ret; - hwswitch = buffer->output[1]; + hwswitch = buffer.output[1]; /* If the hardware switch controls this radio, and the hardware switch is disabled, always disable the radio */ @@ -490,8 +492,8 @@ static int dell_rfkill_set(void *data, bool blocked) (status & BIT(0)) && !(status & BIT(16))) disable = 1; - dell_set_arguments(1 | (radio<<8) | (disable << 16), 0, 0, 0); - ret = dell_send_request(CLASS_INFO, SELECT_RFKILL); + dell_set_arguments(&buffer, 1 | (radio<<8) | (disable << 16), 0, 0, 0); + ret = dell_send_request(&buffer, CLASS_INFO, SELECT_RFKILL); return ret; } @@ -500,9 +502,11 @@ static void dell_rfkill_update_sw_state(struct rfkill *rfkill, int radio, { if (status & BIT(0)) { /* Has hw-switch, sync sw_state to BIOS */ + struct calling_interface_buffer buffer; int block = rfkill_blocked(rfkill); - dell_set_arguments(1 | (radio << 8) | (block << 16), 0, 0, 0); - dell_send_request(CLASS_INFO, SELECT_RFKILL); + dell_set_arguments(&buffer, + 1 | (radio << 8) | (block << 16), 0, 0, 0); + dell_send_request(&buffer, CLASS_INFO, SELECT_RFKILL); } else { /* No hw-switch, sync BIOS state to sw_state */ rfkill_set_sw_state(rfkill, !!(status & BIT(radio + 16))); @@ -519,21 +523,22 @@ static void dell_rfkill_update_hw_state(struct rfkill *rfkill, int radio, static void dell_rfkill_query(struct rfkill *rfkill, void *data) { int radio = ((unsigned long)data & 0xF); + struct calling_interface_buffer buffer; int hwswitch; int status; int ret; - dell_set_arguments(0, 0, 0, 0); - ret = dell_send_request(CLASS_INFO, SELECT_RFKILL); - status = buffer->output[1]; + dell_set_arguments(&buffer, 0, 0, 0, 0); + ret = dell_send_request(&buffer, CLASS_INFO, SELECT_RFKILL); + status = buffer.output[1]; if (ret != 0 || !(status & BIT(0))) { return; } - dell_set_arguments(0, 0x2, 0, 0); - ret = dell_send_request(CLASS_INFO, SELECT_RFKILL); - hwswitch = buffer->output[1]; + dell_set_arguments(&buffer, 0, 0x2, 0, 0); + re
[PATCH] platform/x86: dell-laptop: Guard SMBIOS calls with a mutex
Suggested-by: Pali Rohar Signed-off-by: Mario Limonciello --- drivers/platform/x86/dell-laptop.c | 67 ++ 1 file changed, 53 insertions(+), 14 deletions(-) diff --git a/drivers/platform/x86/dell-laptop.c b/drivers/platform/x86/dell-laptop.c index fc2dfc8..f8e2bd8 100644 --- a/drivers/platform/x86/dell-laptop.c +++ b/drivers/platform/x86/dell-laptop.c @@ -85,6 +85,7 @@ static struct rfkill *wifi_rfkill; static struct rfkill *bluetooth_rfkill; static struct rfkill *wwan_rfkill; static bool force_rfkill; +static DEFINE_MUTEX(buffer_mutex); module_param(force_rfkill, bool, 0444); MODULE_PARM_DESC(force_rfkill, "enable rfkill on non whitelisted models"); @@ -472,16 +473,17 @@ static int dell_rfkill_set(void *data, bool blocked) int status; int ret; + mutex_lock(&buffer_mutex); dell_set_arguments(0, 0, 0, 0); ret = dell_send_request(CLASS_INFO, SELECT_RFKILL); if (ret) - return ret; + goto out; status = buffer->output[1]; dell_set_arguments(0x2, 0, 0, 0); ret = dell_send_request(CLASS_INFO, SELECT_RFKILL); if (ret) - return ret; + goto out; hwswitch = buffer->output[1]; /* If the hardware switch controls this radio, and the hardware @@ -492,6 +494,9 @@ static int dell_rfkill_set(void *data, bool blocked) dell_set_arguments(1 | (radio<<8) | (disable << 16), 0, 0, 0); ret = dell_send_request(CLASS_INFO, SELECT_RFKILL); + +out: + mutex_unlock(&buffer_mutex); return ret; } @@ -501,8 +506,10 @@ static void dell_rfkill_update_sw_state(struct rfkill *rfkill, int radio, if (status & BIT(0)) { /* Has hw-switch, sync sw_state to BIOS */ int block = rfkill_blocked(rfkill); + mutex_lock(&buffer_mutex); dell_set_arguments(1 | (radio << 8) | (block << 16), 0, 0, 0); dell_send_request(CLASS_INFO, SELECT_RFKILL); + mutex_unlock(&buffer_mutex); } else { /* No hw-switch, sync BIOS state to sw_state */ rfkill_set_sw_state(rfkill, !!(status & BIT(radio + 16))); @@ -523,22 +530,24 @@ static void dell_rfkill_query(struct rfkill *rfkill, void *data) int status; int ret; + mutex_lock(&buffer_mutex); dell_set_arguments(0, 0, 0, 0); ret = dell_send_request(CLASS_INFO, SELECT_RFKILL); status = buffer->output[1]; - if (ret != 0 || !(status & BIT(0))) { - return; - } + if (ret != 0 || !(status & BIT(0))) + goto out; dell_set_arguments(0, 0x2, 0, 0); ret = dell_send_request(CLASS_INFO, SELECT_RFKILL); hwswitch = buffer->output[1]; if (ret != 0) - return; + goto out; dell_rfkill_update_hw_state(rfkill, radio, status, hwswitch); +out: + mutex_unlock(&buffer_mutex); } static const struct rfkill_ops dell_rfkill_ops = { @@ -555,16 +564,19 @@ static int dell_debugfs_show(struct seq_file *s, void *data) int status; int ret; + mutex_lock(&buffer_mutex); dell_set_arguments(0, 0, 0, 0); ret = dell_send_request(CLASS_INFO, SELECT_RFKILL); if (ret) - return ret; + goto out; status = buffer->output[1]; dell_set_arguments(0, 0x2, 0, 0); hwswitch_ret = dell_send_request(CLASS_INFO, SELECT_RFKILL); - if (hwswitch_ret) - return hwswitch_ret; + if (hwswitch_ret) { + ret = hwswitch_ret; + goto out; + } hwswitch_state = buffer->output[1]; seq_printf(s, "return:\t%d\n", ret); @@ -628,7 +640,9 @@ static int dell_debugfs_show(struct seq_file *s, void *data) seq_printf(s, "Bit 15: Wifi locator setting locked:%lu\n", (hwswitch_state & BIT(15)) >> 15); - return 0; +out: + mutex_unlock(&buffer_mutex); + return ret; } static int dell_debugfs_open(struct inode *inode, struct file *file) @@ -650,12 +664,13 @@ static void dell_update_rfkill(struct work_struct *ignored) int status; int ret; + mutex_lock(&buffer_mutex); dell_set_arguments(0, 0, 0, 0); ret = dell_send_request(CLASS_INFO, SELECT_RFKILL); status = buffer->output[1]; if (ret != 0) - return; + goto out; dell_set_arguments(0, 0x2, 0, 0); ret = dell_send_request(CLASS_INFO, SELECT_RFKILL); @@ -676,6 +691,8 @@ static void dell_update_rfkill(struct work_struct *ignored) dell_rfkill_update_hw_state(wwan_rfkill, 3, status, hwswitch); dell_rfkill_updat
[PATCH] platform/x86: dell-smbios: Correct notation for filtering
The class/select were mistakingly put into octal notation but intended to be in decimal notation. Suggest-by: Pali Rohar Signed-off-by: Mario Limonciello --- drivers/platform/x86/dell-smbios.c | 8 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/platform/x86/dell-smbios.c b/drivers/platform/x86/dell-smbios.c index 6a60db5..8541cde 100644 --- a/drivers/platform/x86/dell-smbios.c +++ b/drivers/platform/x86/dell-smbios.c @@ -65,10 +65,10 @@ static struct smbios_call call_whitelist[] = { /* calls that are explicitly blacklisted */ static struct smbios_call call_blacklist[] = { - {0x, 01, 07}, /* manufacturing use */ - {0x, 06, 05}, /* manufacturing use */ - {0x, 11, 03}, /* write once */ - {0x, 11, 07}, /* write once */ + {0x, 1, 7}, /* manufacturing use */ + {0x, 6, 5}, /* manufacturing use */ + {0x, 11, 3}, /* write once */ + {0x, 11, 7}, /* write once */ {0x, 11, 11}, /* write once */ {0x, 19, -1}, /* diagnostics */ /* handled by kernel: dell-laptop */ -- 2.7.4
[PATCH 2/2] platform/x86: wmi: Allow creating WMI devices with the same GUID
In: commit d1f9e4970742 ("ACPI: WMI: Survive BIOS with duplicate GUIDs") parsing two of the same GUID was prevented in the WMI bus driver. At the time no one understood why GUID 05901221-D566-11D1-B2F0-00A0C9062910 was being duplicated. It's now known that GUID is used for the binary MOF file of a _WDG entry in the ASL. It's entirely possible for multiple _WDG entries and for multiple instances to bind in a given driver. NOTE: The only known instance of duplicated GUID's is the WMI BMOF GUID above, but it is possible that other vendors may duplicate GUIDs as well. It would be better for drivers to not interact with the WMI bus by GUID string but by the struct wmi_device provided by the WMI bus during probing. Signed-off-by: Mario Limonciello --- drivers/platform/x86/wmi.c | 31 --- 1 file changed, 31 deletions(-) diff --git a/drivers/platform/x86/wmi.c b/drivers/platform/x86/wmi.c index 45d9010aafcf..5ac17e360fa2 100644 --- a/drivers/platform/x86/wmi.c +++ b/drivers/platform/x86/wmi.c @@ -1102,28 +1102,6 @@ static void wmi_free_devices(struct acpi_device *device) } } -static bool guid_already_parsed(struct acpi_device *device, - const u8 *guid) -{ - struct wmi_block *wblock; - - list_for_each_entry(wblock, &wmi_block_list, list) { - if (memcmp(wblock->gblock.guid, guid, 16) == 0) { - /* -* Because we historically didn't track the relationship -* between GUIDs and ACPI nodes, we don't know whether -* we need to suppress GUIDs that are unique on a -* given node but duplicated across nodes. -*/ - dev_warn(&device->dev, "duplicate WMI GUID %pUL (first instance was on %s)\n", -guid, dev_name(&wblock->acpi_device->dev)); - return true; - } - } - - return false; -} - /* * Parse the _WDG method for the GUID data blocks */ @@ -1157,15 +1135,6 @@ static int parse_wdg(struct device *wmi_bus_dev, struct acpi_device *device) if (debug_dump_wdg) wmi_dump_wdg(&gblock[i]); - /* -* Some WMI devices, like those for nVidia hooks, have a -* duplicate GUID. It's not clear what we should do in this -* case yet, so for now, we'll just ignore the duplicate -* for device creation. -*/ - if (guid_already_parsed(device, gblock[i].guid)) - continue; - wblock = kzalloc(sizeof(struct wmi_block), GFP_KERNEL); if (!wblock) { retval = -ENOMEM; -- 2.14.1
[PATCH 1/2] platform/x86: wmi: prefix sysfs files in /sys/bus/wmi with the ACPI device
It's possible for the same GUID to show up on as system twice. This means using solely the GUID for identify the file will not be sufficient. Signed-off-by: Mario Limonciello --- drivers/platform/x86/wmi.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/platform/x86/wmi.c b/drivers/platform/x86/wmi.c index 791449a2370f..45d9010aafcf 100644 --- a/drivers/platform/x86/wmi.c +++ b/drivers/platform/x86/wmi.c @@ -1081,7 +1081,8 @@ static int wmi_create_device(struct device *wmi_bus_dev, wblock->dev.dev.bus = &wmi_bus_type; wblock->dev.dev.parent = wmi_bus_dev; - dev_set_name(&wblock->dev.dev, "%pUL", gblock->guid); + dev_set_name(&wblock->dev.dev, "%s-%pUL", +dev_name(&wblock->acpi_device->dev), gblock->guid); device_initialize(&wblock->dev.dev); -- 2.14.1
[PATCH 0/2] Parse multiple duplicate WMI GUIDs
I recently discovered that multiple instances of the WMI BMOF GUID are present on some machines with more advanced WMI implementations. Only the first found instance is parsed today with the rest ignored. The rest of the instances should be readable by the wmi-bmof driver (and userspace) to allow improving any parsing implementations. Andy L. indicated he thought fixing this should require changing the WMI driver to no longer track a block list of devices, but I don't think that's necessary. The only significant change is that the WMI bus will need to build the symlinks in /sys/bus/wmi/devices in a way to prevent clashes with multiple devices sharing the same GUID. The most obvious solution (and that which I implemented) is to include the ACPI device associated with the GUID. Since this is a symlink and the actual path remains stable I don't know if that's considered changing a userspace interface. If so, then an alternative would be to append a number when a second instance of a GUID has been discovered and keep the "old" symlink path for the first instance stable. Mario Limonciello (2): platform/x86: wmi: prefix sysfs files in /sys/bus/wmi with the ACPI device platform/x86: wmi: Allow creating WMI devices with the same GUID drivers/platform/x86/wmi.c | 34 ++ 1 file changed, 2 insertions(+), 32 deletions(-) -- 2.14.1
[PATCH v2] platform/x86: dell-smbios-wmi: Disable userspace interface if missing hotfix
The Dell SMBIOS WMI interface will fail for some more complex calls unless a WMI hotfix has been included. Most platforms have this fix available in a maintenance BIOS release. In the case the driver is loaded on a platform without this fix, disable the userspace interface. A hotfix indicator is present in the dell-wmi-descriptor that represents whether or not more complex calls will work properly. "Simple" calls such as those used by dell-laptop and dell-wmi will continue to work properly so dell-smbios-wmi should not be blocked from binding and being used as the dell-smbios dispatcher. Suggested-by: Girish Prakash Signed-off-by: Mario Limonciello --- drivers/platform/x86/dell-smbios-wmi.c | 13 + drivers/platform/x86/dell-wmi-descriptor.c | 26 -- drivers/platform/x86/dell-wmi-descriptor.h | 1 + 3 files changed, 38 insertions(+), 2 deletions(-) diff --git a/drivers/platform/x86/dell-smbios-wmi.c b/drivers/platform/x86/dell-smbios-wmi.c index 8ad11ef..044a104 100644 --- a/drivers/platform/x86/dell-smbios-wmi.c +++ b/drivers/platform/x86/dell-smbios-wmi.c @@ -147,7 +147,10 @@ static long dell_smbios_wmi_filter(struct wmi_device *wdev, unsigned int cmd, static int dell_smbios_wmi_probe(struct wmi_device *wdev) { + struct wmi_driver *wdriver = + container_of(wdev->dev.driver, struct wmi_driver, driver); struct wmi_smbios_priv *priv; + u32 hotfix; int count; int ret; @@ -167,6 +170,16 @@ static int dell_smbios_wmi_probe(struct wmi_device *wdev) if (!dell_wmi_get_size(&priv->req_buf_size)) return -EPROBE_DEFER; + /* some SMBIOS calls fail unless BIOS contains hotfix */ + if (!dell_wmi_get_hotfix(&hotfix)) + return -EPROBE_DEFER; + if (!hotfix) { + dev_warn(&wdev->dev, + "WMI SMBIOS userspace interface not supported(%u), try upgrading to a newer BIOS\n", + hotfix); + wdriver->filter_callback = NULL; + } + /* add in the length object we will use internally with ioctl */ priv->req_buf_size += sizeof(u64); ret = set_required_buffer_size(wdev, priv->req_buf_size); diff --git a/drivers/platform/x86/dell-wmi-descriptor.c b/drivers/platform/x86/dell-wmi-descriptor.c index e7f4c3a..5083ce0 100644 --- a/drivers/platform/x86/dell-wmi-descriptor.c +++ b/drivers/platform/x86/dell-wmi-descriptor.c @@ -25,6 +25,7 @@ struct descriptor_priv { struct list_head list; u32 interface_version; u32 size; + u32 hotfix; }; static int descriptor_valid = -EPROBE_DEFER; static LIST_HEAD(wmi_list); @@ -72,6 +73,24 @@ bool dell_wmi_get_size(u32 *size) } EXPORT_SYMBOL_GPL(dell_wmi_get_size); +bool dell_wmi_get_hotfix(u32 *hotfix) +{ + struct descriptor_priv *priv; + bool ret = false; + + mutex_lock(&list_mutex); + priv = list_first_entry_or_null(&wmi_list, + struct descriptor_priv, + list); + if (priv) { + *hotfix = priv->hotfix; + ret = true; + } + mutex_unlock(&list_mutex); + return ret; +} +EXPORT_SYMBOL_GPL(dell_wmi_get_hotfix); + /* * Descriptor buffer is 128 byte long and contains: * @@ -80,6 +99,7 @@ EXPORT_SYMBOL_GPL(dell_wmi_get_size); * Object Signature 4 4" WMI" * WMI Interface Version 8 4 * WMI buffer length12 4 + * WMI hotfix number16 4 */ static int dell_wmi_descriptor_probe(struct wmi_device *wdev) { @@ -139,15 +159,17 @@ static int dell_wmi_descriptor_probe(struct wmi_device *wdev) priv->interface_version = buffer[2]; priv->size = buffer[3]; + priv->hotfix = buffer[4]; ret = 0; dev_set_drvdata(&wdev->dev, priv); mutex_lock(&list_mutex); list_add_tail(&priv->list, &wmi_list); mutex_unlock(&list_mutex); - dev_dbg(&wdev->dev, "Detected Dell WMI interface version %lu and buffer size %lu\n", + dev_dbg(&wdev->dev, "Detected Dell WMI interface version %lu, buffer size %lu, hotfix %lu\n", (unsigned long) priv->interface_version, - (unsigned long) priv->size); + (unsigned long) priv->size, + (unsigned long) priv->hotfix); out: kfree(obj); diff --git a/drivers/platform/x86/dell-wmi-descriptor.h b/drivers/platform/x86/dell-wmi-descriptor.h index 776cddd..217b833 100644 --- a/drivers/platform/x86/dell-wmi-descriptor.h +++ b/drivers/platform/x86/dell-wmi-descriptor.h @@ -24,5 +24,6 @@ int dell_wmi_get_descriptor_valid(void); bool dell_wmi_get_interface_version(u32 *version); bool dell_wmi_get_size(u32 *size); +bool dell_wmi_get_hotfix(u32 *hotfix); #endif -- 2.7.4
[PATCH] platform/x86: dell-smbios-wmi: Disable userspace interface if missing hotfix
The Dell SMBIOS WMI interface will fail for some more complex calls unless a WMI hotfix has been included. Most platforms have this fix available in a maintenance BIOS release. In the case the driver is loaded on a platform without this fix, disable the userspace interface. A hotfix indicator is present in the dell-wmi-descriptor that represents whether or not more complex calls will work properly. "Simple" calls such as those used by dell-laptop and dell-wmi will continue to work properly so dell-smbios-wmi should not be blocked from binding and being used as the dell-smbios dispatcher. Suggested-by: Girish Prakash Signed-off-by: Mario Limonciello --- drivers/platform/x86/dell-smbios-wmi.c | 14 ++ drivers/platform/x86/dell-wmi-descriptor.c | 26 -- drivers/platform/x86/dell-wmi-descriptor.h | 1 + 3 files changed, 39 insertions(+), 2 deletions(-) diff --git a/drivers/platform/x86/dell-smbios-wmi.c b/drivers/platform/x86/dell-smbios-wmi.c index 8ad11ef..a296551 100644 --- a/drivers/platform/x86/dell-smbios-wmi.c +++ b/drivers/platform/x86/dell-smbios-wmi.c @@ -147,9 +147,12 @@ static long dell_smbios_wmi_filter(struct wmi_device *wdev, unsigned int cmd, static int dell_smbios_wmi_probe(struct wmi_device *wdev) { + struct wmi_driver *wdriver = + container_of(wdev->dev.driver, struct wmi_driver, driver); struct wmi_smbios_priv *priv; int count; int ret; + u32 hotfix; if (!wmi_has_guid(DELL_WMI_DESCRIPTOR_GUID)) return -ENODEV; @@ -167,6 +170,16 @@ static int dell_smbios_wmi_probe(struct wmi_device *wdev) if (!dell_wmi_get_size(&priv->req_buf_size)) return -EPROBE_DEFER; + /* some SMBIOS calls fail unless BIOS contains hotfix */ + if (!dell_wmi_get_hotfix(&hotfix)) + return -EPROBE_DEFER; + if (!hotfix) { + dev_warn(&wdev->dev, + "WMI SMBIOS userspace interface not supported (%u)\n", + hotfix); + wdriver->filter_callback = NULL; + } + /* add in the length object we will use internally with ioctl */ priv->req_buf_size += sizeof(u64); ret = set_required_buffer_size(wdev, priv->req_buf_size); @@ -184,6 +197,7 @@ static int dell_smbios_wmi_probe(struct wmi_device *wdev) if (ret) goto fail_register; + priv->wdev = wdev; dev_set_drvdata(&wdev->dev, priv); mutex_lock(&list_mutex); diff --git a/drivers/platform/x86/dell-wmi-descriptor.c b/drivers/platform/x86/dell-wmi-descriptor.c index e7f4c3a..5083ce0 100644 --- a/drivers/platform/x86/dell-wmi-descriptor.c +++ b/drivers/platform/x86/dell-wmi-descriptor.c @@ -25,6 +25,7 @@ struct descriptor_priv { struct list_head list; u32 interface_version; u32 size; + u32 hotfix; }; static int descriptor_valid = -EPROBE_DEFER; static LIST_HEAD(wmi_list); @@ -72,6 +73,24 @@ bool dell_wmi_get_size(u32 *size) } EXPORT_SYMBOL_GPL(dell_wmi_get_size); +bool dell_wmi_get_hotfix(u32 *hotfix) +{ + struct descriptor_priv *priv; + bool ret = false; + + mutex_lock(&list_mutex); + priv = list_first_entry_or_null(&wmi_list, + struct descriptor_priv, + list); + if (priv) { + *hotfix = priv->hotfix; + ret = true; + } + mutex_unlock(&list_mutex); + return ret; +} +EXPORT_SYMBOL_GPL(dell_wmi_get_hotfix); + /* * Descriptor buffer is 128 byte long and contains: * @@ -80,6 +99,7 @@ EXPORT_SYMBOL_GPL(dell_wmi_get_size); * Object Signature 4 4" WMI" * WMI Interface Version 8 4 * WMI buffer length12 4 + * WMI hotfix number16 4 */ static int dell_wmi_descriptor_probe(struct wmi_device *wdev) { @@ -139,15 +159,17 @@ static int dell_wmi_descriptor_probe(struct wmi_device *wdev) priv->interface_version = buffer[2]; priv->size = buffer[3]; + priv->hotfix = buffer[4]; ret = 0; dev_set_drvdata(&wdev->dev, priv); mutex_lock(&list_mutex); list_add_tail(&priv->list, &wmi_list); mutex_unlock(&list_mutex); - dev_dbg(&wdev->dev, "Detected Dell WMI interface version %lu and buffer size %lu\n", + dev_dbg(&wdev->dev, "Detected Dell WMI interface version %lu, buffer size %lu, hotfix %lu\n", (unsigned long) priv->interface_version, - (unsigned long) priv->size); + (unsigned long) priv->size, + (unsigned long) priv->hotfix); out: kfree(obj); diff --git a/drivers/platform/x86/dell-wmi-descriptor.h b/
[PATCH] platform/x86: dell-laptop: Allocate buffer before rfkill use
On machines using rfkill interface the buffer needs to have been allocated before the initial use (memset) of it. Reported-by: Valdis Kletnieks Signed-off-by: Mario Limonciello --- drivers/platform/x86/dell-laptop.c | 9 + 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/drivers/platform/x86/dell-laptop.c b/drivers/platform/x86/dell-laptop.c index c4903c5..2d70436 100644 --- a/drivers/platform/x86/dell-laptop.c +++ b/drivers/platform/x86/dell-laptop.c @@ -2073,6 +2073,11 @@ static int __init dell_init(void) if (ret) goto fail_platform_device2; + buffer = kzalloc(sizeof(struct calling_interface_buffer), GFP_KERNEL); + if (!buffer) + goto fail_buffer; + + ret = dell_setup_rfkill(); if (ret) { @@ -2080,10 +2085,6 @@ static int __init dell_init(void) goto fail_rfkill; } - buffer = kzalloc(sizeof(struct calling_interface_buffer), GFP_KERNEL); - if (!buffer) - goto fail_buffer; - if (quirks && quirks->touchpad_led) touchpad_led_init(&platform_device->dev); -- 2.7.4
[PATCH v2 2/2] platform/x86: dell-*wmi*: Relay failed initial probe to dependent drivers
dell-wmi and dell-smbios-wmi are dependent upon dell-wmi-descriptor finishing probe successfully to probe themselves. Currently if dell-wmi-descriptor fails probing in a non-recoverable way (such as invalid header) dell-wmi and dell-smbios-wmi will continue to try to redo probing due to deferred probing. To solve this have the dependent drivers query the dell-wmi-descriptor driver whether the descriptor has been determined valid. The possible results are: -ENODEV: Descriptor GUID missing from WMI bus -EPROBE_DEFER: Descriptor not yet probed, dependent driver should wait and use deferred probing < 0: Descriptor probed, invalid. Dependent driver should return an error. 0: Successful descriptor probe, dependent driver can continue Successful descriptor probe still doesn't mean that the descriptor driver is necessarily bound at the time of initialization of dependent driver. Userspace can unbind the driver, so all methods used from driver should still be verified to return success values otherwise deferred probing be used. Signed-off-by: Mario Limonciello --- drivers/platform/x86/dell-smbios-wmi.c | 5 +++-- drivers/platform/x86/dell-wmi-descriptor.c | 16 drivers/platform/x86/dell-wmi-descriptor.h | 8 +++- drivers/platform/x86/dell-wmi.c| 6 -- 4 files changed, 30 insertions(+), 5 deletions(-) diff --git a/drivers/platform/x86/dell-smbios-wmi.c b/drivers/platform/x86/dell-smbios-wmi.c index 35c13815b24c..ca556803c8c9 100644 --- a/drivers/platform/x86/dell-smbios-wmi.c +++ b/drivers/platform/x86/dell-smbios-wmi.c @@ -148,8 +148,9 @@ static int dell_smbios_wmi_probe(struct wmi_device *wdev) int count; int ret; - if (!wmi_has_guid(DELL_WMI_DESCRIPTOR_GUID)) - return -ENODEV; + ret = dell_wmi_get_descriptor_valid(); + if (ret) + return ret; priv = devm_kzalloc(&wdev->dev, sizeof(struct wmi_smbios_priv), GFP_KERNEL); diff --git a/drivers/platform/x86/dell-wmi-descriptor.c b/drivers/platform/x86/dell-wmi-descriptor.c index 28ef5f37cfbf..4dfef1f53481 100644 --- a/drivers/platform/x86/dell-wmi-descriptor.c +++ b/drivers/platform/x86/dell-wmi-descriptor.c @@ -21,14 +21,26 @@ #include #include "dell-wmi-descriptor.h" +#define DELL_WMI_DESCRIPTOR_GUID "8D9DDCBC-A997-11DA-B012-B622A1EF5492" + struct descriptor_priv { struct list_head list; u32 interface_version; u32 size; }; +static int descriptor_valid = -EPROBE_DEFER; static LIST_HEAD(wmi_list); static DEFINE_MUTEX(list_mutex); +int dell_wmi_get_descriptor_valid(void) +{ + if (!wmi_has_guid(DELL_WMI_DESCRIPTOR_GUID)) + return -ENODEV; + + return descriptor_valid; +} +EXPORT_SYMBOL_GPL(dell_wmi_get_descriptor_valid); + bool dell_wmi_get_interface_version(u32 *version) { struct descriptor_priv *priv; @@ -91,6 +103,7 @@ static int dell_wmi_descriptor_probe(struct wmi_device *wdev) if (obj->type != ACPI_TYPE_BUFFER) { dev_err(&wdev->dev, "Dell descriptor has wrong type\n"); ret = -EINVAL; + descriptor_valid = ret; goto out; } @@ -102,6 +115,7 @@ static int dell_wmi_descriptor_probe(struct wmi_device *wdev) "Dell descriptor buffer has unexpected length (%d)\n", obj->buffer.length); ret = -EINVAL; + descriptor_valid = ret; goto out; } @@ -111,8 +125,10 @@ static int dell_wmi_descriptor_probe(struct wmi_device *wdev) dev_err(&wdev->dev, "Dell descriptor buffer has invalid signature (%8ph)\n", buffer); ret = -EINVAL; + descriptor_valid = ret; goto out; } + descriptor_valid = 0; if (buffer[2] != 0 && buffer[2] != 1) dev_warn(&wdev->dev, "Dell descriptor buffer has unknown version (%lu)\n", diff --git a/drivers/platform/x86/dell-wmi-descriptor.h b/drivers/platform/x86/dell-wmi-descriptor.h index 5f7b69c2c83a..1e8cb96ffd78 100644 --- a/drivers/platform/x86/dell-wmi-descriptor.h +++ b/drivers/platform/x86/dell-wmi-descriptor.h @@ -13,7 +13,13 @@ #include -#define DELL_WMI_DESCRIPTOR_GUID "8D9DDCBC-A997-11DA-B012-B622A1EF5492" +/* possible return values: + * -ENODEV: Descriptor GUID missing from WMI bus + * -EPROBE_DEFER: probing for dell-wmi-descriptor not yet run + * 0: valid descriptor, successfully probed + * < 0: invalid descriptor, don't probe dependent devices + */ +int dell_wmi_get_descriptor_valid(void); bool dell_wmi_get_interface_version(u32 *version); bool dell_wmi_get_size(u32 *size); diff --git a/drivers/platform/x86/dell-wmi.c b/drivers/platform/x86/dell-wmi.c index 54321080a30d.
[PATCH v2 0/2] Account for uncorrectable failures in probing
Pali raised some concerns around corner case scenarios that probing may fail on dell-wmi-descriptor causing dell-wmi and dell-smbios-wmi to be stuck in infinite deferred probing loops. This patch series accounts for that corner case. changes from v1 to v2: - Add Reviewed by from Pali for patch 1 - Move wmi_has_guid check into dell-wmi-descriptor.c instead of dependent drivers. Mario Limonciello (2): platform/x86: dell-wmi-descriptor: check if memory was allocated platform/x86: dell-*wmi*: Relay failed initial probe to dependent drivers drivers/platform/x86/dell-smbios-wmi.c | 5 +++-- drivers/platform/x86/dell-wmi-descriptor.c | 21 + drivers/platform/x86/dell-wmi-descriptor.h | 8 +++- drivers/platform/x86/dell-wmi.c| 6 -- 4 files changed, 35 insertions(+), 5 deletions(-) -- 2.14.1
[PATCH v2 1/2] platform/x86: dell-wmi-descriptor: check if memory was allocated
devm_kzalloc will return NULL pointer if no memory was allocated. This should be checked. This problem also existed when the driver was dell-wmi.c. Signed-off-by: Mario Limonciello Reviewed-by: Pali Rohár --- drivers/platform/x86/dell-wmi-descriptor.c | 5 + 1 file changed, 5 insertions(+) diff --git a/drivers/platform/x86/dell-wmi-descriptor.c b/drivers/platform/x86/dell-wmi-descriptor.c index 3204c408e261..28ef5f37cfbf 100644 --- a/drivers/platform/x86/dell-wmi-descriptor.c +++ b/drivers/platform/x86/dell-wmi-descriptor.c @@ -121,6 +121,11 @@ static int dell_wmi_descriptor_probe(struct wmi_device *wdev) priv = devm_kzalloc(&wdev->dev, sizeof(struct descriptor_priv), GFP_KERNEL); + if (!priv) { + ret = -ENOMEM; + goto out; + } + priv->interface_version = buffer[2]; priv->size = buffer[3]; ret = 0; -- 2.14.1
[PATCH 2/2] platform/x86: dell-smbios-wmi: release mutex lock on WMI call failure
Unbound devices may race with calling this function causing the mutex to stay locked. This failure mode should have released the mutex too. Signed-off-by: Mario Limonciello --- drivers/platform/x86/dell-smbios-wmi.c | 7 +-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/drivers/platform/x86/dell-smbios-wmi.c b/drivers/platform/x86/dell-smbios-wmi.c index 35c13815..5cf9b13 100644 --- a/drivers/platform/x86/dell-smbios-wmi.c +++ b/drivers/platform/x86/dell-smbios-wmi.c @@ -91,8 +91,10 @@ int dell_smbios_wmi_call(struct calling_interface_buffer *buffer) mutex_lock(&call_mutex); priv = get_first_smbios_priv(); - if (!priv) - return -ENODEV; + if (!priv) { + ret = -ENODEV; + goto out_wmi_call; + } size = sizeof(struct calling_interface_buffer); difference = priv->req_buf_size - sizeof(u64) - size; @@ -101,6 +103,7 @@ int dell_smbios_wmi_call(struct calling_interface_buffer *buffer) memcpy(&priv->buf->std, buffer, size); ret = run_smbios_call(priv->wdev); memcpy(buffer, &priv->buf->std, size); +out_wmi_call: mutex_unlock(&call_mutex); return ret; -- 2.7.4
[PATCH 1/2] platform/x86: wmi: release mutex on module acquistion failure
This failure mode should have also released the mutex. Signed-off-by: Mario Limonciello --- drivers/platform/x86/wmi.c | 6 -- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/platform/x86/wmi.c b/drivers/platform/x86/wmi.c index 8c31ed4..791449a 100644 --- a/drivers/platform/x86/wmi.c +++ b/drivers/platform/x86/wmi.c @@ -868,8 +868,10 @@ static long wmi_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) /* let the driver do any filtering and do the call */ wdriver = container_of(wblock->dev.dev.driver, struct wmi_driver, driver); - if (!try_module_get(wdriver->driver.owner)) - return -EBUSY; + if (!try_module_get(wdriver->driver.owner)) { + ret = -EBUSY; + goto out_ioctl; + } ret = wdriver->filter_callback(&wblock->dev, cmd, buf); module_put(wdriver->driver.owner); if (ret) -- 2.7.4
[PATCH 0/2] Correct some errors caught by buildbot
Some of the failure scenarios weren't releasing acquired mutexes. Here are some patches that correct them. Mario Limonciello (2): platform/x86: wmi: release mutex on module acquistion failure platform/x86: dell-smbios-wmi: release mutex lock on WMI call failure drivers/platform/x86/dell-smbios-wmi.c | 7 +-- drivers/platform/x86/wmi.c | 6 -- 2 files changed, 9 insertions(+), 4 deletions(-) -- 2.7.4
[PATCH 1/2] platform/x86: dell-wmi-descriptor: check if memory was allocated
devm_kzalloc will return NULL pointer if no memory was allocated. This should be checked. This problem also existed when the driver was dell-wmi.c. Signed-off-by: Mario Limonciello --- drivers/platform/x86/dell-wmi-descriptor.c | 5 + 1 file changed, 5 insertions(+) diff --git a/drivers/platform/x86/dell-wmi-descriptor.c b/drivers/platform/x86/dell-wmi-descriptor.c index 3204c408e261..28ef5f37cfbf 100644 --- a/drivers/platform/x86/dell-wmi-descriptor.c +++ b/drivers/platform/x86/dell-wmi-descriptor.c @@ -121,6 +121,11 @@ static int dell_wmi_descriptor_probe(struct wmi_device *wdev) priv = devm_kzalloc(&wdev->dev, sizeof(struct descriptor_priv), GFP_KERNEL); + if (!priv) { + ret = -ENOMEM; + goto out; + } + priv->interface_version = buffer[2]; priv->size = buffer[3]; ret = 0; -- 2.14.1
[PATCH 0/2] Account for uncorrectable failures in probing
Pali raised some concerns around corner case scenarios that probing may fail on dell-wmi-descriptor causing dell-wmi and dell-smbios-wmi to be stuck in infinite deferred probing loops. This patch series accounts for that corner case. Changes since original submission: - Add as second patch that catches potential NULL pointer - Avoid potential race condition between driver init and calling check for if validation successful Mario Limonciello (2): platform/x86: dell-wmi-descriptor: check if memory was allocated platform/x86: dell-*wmi*: Relay failed initial probe to dependent drivers drivers/platform/x86/dell-smbios-wmi.c | 4 drivers/platform/x86/dell-wmi-descriptor.c | 16 drivers/platform/x86/dell-wmi-descriptor.h | 7 +++ drivers/platform/x86/dell-wmi.c| 5 + 4 files changed, 32 insertions(+) -- 2.14.1