[PATCH 2/3] MAINTAINERS: Add missing section for alienware-wmi driver

2021-04-01 Thread Mario Limonciello
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

2021-04-01 Thread Mario Limonciello
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

2021-04-01 Thread Mario Limonciello
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

2021-04-01 Thread Mario Limonciello
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

2021-02-18 Thread Mario Limonciello
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

2021-02-18 Thread Mario Limonciello
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

2021-02-18 Thread Mario Limonciello
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

2021-02-18 Thread Mario Limonciello
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

2021-02-03 Thread Mario Limonciello
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

2021-02-03 Thread Mario Limonciello
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

2021-01-29 Thread Mario Limonciello
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

2020-12-14 Thread Mario Limonciello
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"

2020-12-14 Thread Mario Limonciello
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

2020-12-14 Thread Mario Limonciello
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

2020-12-14 Thread Mario Limonciello
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

2020-12-14 Thread Mario Limonciello
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"

2020-12-14 Thread Mario Limonciello
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

2020-12-14 Thread Mario Limonciello
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

2020-12-14 Thread Mario Limonciello
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

2020-12-14 Thread Mario Limonciello
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

2020-12-14 Thread Mario Limonciello
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

2020-12-08 Thread Mario Limonciello
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

2020-12-08 Thread Mario Limonciello



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

2020-12-04 Thread Mario Limonciello
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

2020-12-04 Thread Mario Limonciello
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

2020-12-04 Thread Mario Limonciello
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

2020-12-04 Thread Mario Limonciello
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

2020-12-04 Thread Mario Limonciello
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

2020-12-04 Thread Mario Limonciello
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

2020-12-04 Thread Mario Limonciello
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

2020-12-04 Thread Mario Limonciello
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

2020-12-02 Thread Mario Limonciello
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

2020-12-02 Thread Mario Limonciello
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

2020-12-02 Thread Mario Limonciello
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

2020-12-02 Thread Mario Limonciello
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

2020-12-02 Thread Mario Limonciello
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

2020-12-02 Thread Mario Limonciello
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

2020-09-27 Thread Mario Limonciello
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

2020-09-27 Thread Mario Limonciello
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

2020-09-27 Thread Mario Limonciello
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

2020-09-27 Thread Mario Limonciello
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

2020-06-23 Thread Mario Limonciello
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

2020-06-23 Thread Mario Limonciello
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

2020-06-23 Thread Mario Limonciello
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

2020-06-22 Thread Mario Limonciello
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

2020-06-22 Thread Mario Limonciello
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

2020-06-22 Thread Mario Limonciello
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

2020-06-22 Thread Mario Limonciello
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

2020-06-22 Thread Mario Limonciello
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

2020-06-22 Thread Mario Limonciello
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"

2020-05-26 Thread Mario Limonciello
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"

2019-09-26 Thread Mario Limonciello
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

2019-09-18 Thread Mario Limonciello
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

2019-09-11 Thread Mario Limonciello
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"

2019-08-19 Thread Mario Limonciello
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

2019-08-16 Thread Mario Limonciello
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

2019-08-14 Thread Mario Limonciello
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

2019-08-14 Thread Mario Limonciello
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

2019-03-27 Thread Mario Limonciello
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

2018-12-11 Thread Mario Limonciello
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

2018-09-26 Thread Mario Limonciello
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

2018-09-10 Thread Mario Limonciello
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

2018-09-10 Thread Mario Limonciello
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

2018-06-15 Thread Mario Limonciello
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.

2018-04-20 Thread Mario Limonciello
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

2018-04-17 Thread Mario Limonciello
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

2018-03-28 Thread Mario Limonciello
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

2018-03-28 Thread Mario Limonciello
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

2018-03-27 Thread Mario Limonciello
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

2018-03-27 Thread Mario Limonciello
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

2018-03-06 Thread Mario Limonciello
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

2018-02-28 Thread Mario Limonciello
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

2018-02-27 Thread Mario Limonciello
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

2018-02-27 Thread Mario Limonciello
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

2018-02-27 Thread Mario Limonciello
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

2018-02-27 Thread Mario Limonciello
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

2018-02-27 Thread Mario Limonciello
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

2018-02-27 Thread Mario Limonciello
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

2018-02-27 Thread Mario Limonciello
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

2018-02-27 Thread Mario Limonciello
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

2018-02-27 Thread Mario Limonciello
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

2018-02-22 Thread Mario Limonciello
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

2018-01-31 Thread Mario Limonciello
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

2018-01-30 Thread Mario Limonciello
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

2018-01-29 Thread Mario Limonciello
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

2018-01-05 Thread Mario Limonciello
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

2017-12-08 Thread Mario Limonciello
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

2017-12-08 Thread Mario Limonciello
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

2017-12-08 Thread Mario Limonciello
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

2017-11-16 Thread Mario Limonciello
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

2017-11-16 Thread Mario Limonciello
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

2017-11-15 Thread Mario Limonciello
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

2017-11-09 Thread Mario Limonciello
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

2017-11-09 Thread Mario Limonciello
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

2017-11-09 Thread Mario Limonciello
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

2017-11-05 Thread Mario Limonciello
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

2017-11-05 Thread Mario Limonciello
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

2017-11-05 Thread Mario Limonciello
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

2017-11-03 Thread Mario Limonciello
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

2017-11-03 Thread Mario Limonciello
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



  1   2   3   4   >