Commit 9a4b33d4 authored by Jiaxun Yang's avatar Jiaxun Yang Committed by Andy Shevchenko
Browse files

platform/x86: thinkpad_acpi: Read EC information on newer models



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: default avatarJiaxun Yang <jiaxun.yang@flygoat.com>
Signed-off-by: default avatarAndy Shevchenko <andriy.shevchenko@linux.intel.com>
parent f7db839f
Loading
Loading
Loading
Loading
+49 −13
Original line number Diff line number Diff line
@@ -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,7 +10036,15 @@ 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;
		}
	}

	/* Newer ThinkPads have different EC program info table */
	if (!ec_fw_string[0])
		dmi_walk(find_new_ec_fwstr, &ec_fw_string);

	if (ec_fw_string[0]) {
		tp->ec_version_str = kstrdup(ec_fw_string, GFP_KERNEL);
		if (!tp->ec_version_str)
			return -ENOMEM;
@@ -10015,10 +10054,7 @@ static int __must_check __init get_thinkpad_model_data(
		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;
			pr_notice("please report this to %s\n", TPACPI_MAIL);
		}
	}