platform/x86: thinkpad_acpi: Read EC information on newer models
authorJiaxun Yang <jiaxun.yang@flygoat.com>
Fri, 8 Mar 2019 13:14:26 +0000 (21:14 +0800)
committerAndy Shevchenko <andriy.shevchenko@linux.intel.com>
Mon, 8 Apr 2019 17:12:13 +0000 (20:12 +0300)
Newer ThinkPads have a totally different EC program information DMI
table. And thermal subdriver can't work without correct EC version.

Read from this entry if the old method failed to get EC information.

Signed-off-by: Jiaxun Yang <jiaxun.yang@flygoat.com>
Signed-off-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
drivers/platform/x86/thinkpad_acpi.c

index 89ce14b..57d9ae9 100644 (file)
@@ -9958,6 +9958,37 @@ invalid:
        return '\0';
 }
 
+static void find_new_ec_fwstr(const struct dmi_header *dm, void *private)
+{
+       char *ec_fw_string = (char *) private;
+       const char *dmi_data = (const char *)dm;
+       /*
+        * ThinkPad Embedded Controller Program Table on newer models
+        *
+        * Offset |  Name                | Width  | Description
+        * ----------------------------------------------------
+        *  0x00  | Type                 | BYTE   | 0x8C
+        *  0x01  | Length               | BYTE   |
+        *  0x02  | Handle               | WORD   | Varies
+        *  0x04  | Signature            | BYTEx6 | ASCII for "LENOVO"
+        *  0x0A  | OEM struct offset    | BYTE   | 0x0B
+        *  0x0B  | OEM struct number    | BYTE   | 0x07, for this structure
+        *  0x0C  | OEM struct revision  | BYTE   | 0x01, for this format
+        *  0x0D  | ECP version ID       | STR ID |
+        *  0x0E  | ECP release date     | STR ID |
+        */
+
+       /* Return if data structure not match */
+       if (dm->type != 140 || dm->length < 0x0F ||
+       memcmp(dmi_data + 4, "LENOVO", 6) != 0 ||
+       dmi_data[0x0A] != 0x0B || dmi_data[0x0B] != 0x07 ||
+       dmi_data[0x0C] != 0x01)
+               return;
+
+       /* fwstr is the first 8byte string  */
+       strncpy(ec_fw_string, dmi_data + 0x0F, 8);
+}
+
 /* returns 0 - probe ok, or < 0 - probe error.
  * Probe ok doesn't mean thinkpad found.
  * On error, kfree() cleanup on tp->* is not performed, caller must do it */
@@ -9965,7 +9996,7 @@ static int __must_check __init get_thinkpad_model_data(
                                                struct thinkpad_id_data *tp)
 {
        const struct dmi_device *dev = NULL;
-       char ec_fw_string[18];
+       char ec_fw_string[18] = {0};
        char const *s;
        char t;
 
@@ -10005,20 +10036,25 @@ static int __must_check __init get_thinkpad_model_data(
                           ec_fw_string) == 1) {
                        ec_fw_string[sizeof(ec_fw_string) - 1] = 0;
                        ec_fw_string[strcspn(ec_fw_string, " ]")] = 0;
+                       break;
+               }
+       }
 
-                       tp->ec_version_str = kstrdup(ec_fw_string, GFP_KERNEL);
-                       if (!tp->ec_version_str)
-                               return -ENOMEM;
+       /* Newer ThinkPads have different EC program info table */
+       if (!ec_fw_string[0])
+               dmi_walk(find_new_ec_fwstr, &ec_fw_string);
 
-                       t = tpacpi_parse_fw_id(ec_fw_string,
-                                              &tp->ec_model, &tp->ec_release);
-                       if (t != 'H') {
-                               pr_notice("ThinkPad firmware release %s doesn't match the known patterns\n",
-                                         ec_fw_string);
-                               pr_notice("please report this to %s\n",
-                                         TPACPI_MAIL);
-                       }
-                       break;
+       if (ec_fw_string[0]) {
+               tp->ec_version_str = kstrdup(ec_fw_string, GFP_KERNEL);
+               if (!tp->ec_version_str)
+                       return -ENOMEM;
+
+               t = tpacpi_parse_fw_id(ec_fw_string,
+                        &tp->ec_model, &tp->ec_release);
+               if (t != 'H') {
+                       pr_notice("ThinkPad firmware release %s doesn't match the known patterns\n",
+                                 ec_fw_string);
+                       pr_notice("please report this to %s\n", TPACPI_MAIL);
                }
        }