提交 846a416b 编写于 作者: J Jouke Witteveen 提交者: Andy Shevchenko

platform/x86: thinkpad_acpi: Proper model/release matching

Modern Thinkpads have three character model designators. Previously, they
would be accepted, but recorded incompletely. Revision matching extracted
the wrong bytes from the ID string. This made the use of quirks for modern
machines impossible.

Fixes: 1b0eb5bcSigned-off-by: NJouke Witteveen <j.witteveen@gmail.com>
Signed-off-by: NAndy Shevchenko <andriy.shevchenko@linux.intel.com>
上级 309dca51
...@@ -358,9 +358,9 @@ struct thinkpad_id_data { ...@@ -358,9 +358,9 @@ struct thinkpad_id_data {
char *bios_version_str; /* Something like 1ZET51WW (1.03z) */ char *bios_version_str; /* Something like 1ZET51WW (1.03z) */
char *ec_version_str; /* Something like 1ZHT51WW-1.04a */ char *ec_version_str; /* Something like 1ZHT51WW-1.04a */
u16 bios_model; /* 1Y = 0x5931, 0 = unknown */ u32 bios_model; /* 1Y = 0x3159, 0 = unknown */
u16 ec_model; u32 ec_model;
u16 bios_release; /* 1ZETK1WW = 0x314b, 0 = unknown */ u16 bios_release; /* 1ZETK1WW = 0x4b31, 0 = unknown */
u16 ec_release; u16 ec_release;
char *model_str; /* ThinkPad T43 */ char *model_str; /* ThinkPad T43 */
...@@ -444,17 +444,20 @@ do { \ ...@@ -444,17 +444,20 @@ do { \
/* /*
* Quirk handling helpers * Quirk handling helpers
* *
* ThinkPad IDs and versions seen in the field so far * ThinkPad IDs and versions seen in the field so far are
* are two-characters from the set [0-9A-Z], i.e. base 36. * two or three characters from the set [0-9A-Z], i.e. base 36.
* *
* We use values well outside that range as specials. * We use values well outside that range as specials.
*/ */
#define TPACPI_MATCH_ANY 0xffffU #define TPACPI_MATCH_ANY 0xffffffffU
#define TPACPI_MATCH_ANY_VERSION 0xffffU
#define TPACPI_MATCH_UNKNOWN 0U #define TPACPI_MATCH_UNKNOWN 0U
/* TPID('1', 'Y') == 0x5931 */ /* TPID('1', 'Y') == 0x3159 */
#define TPID(__c1, __c2) (((__c2) << 8) | (__c1)) #define TPID(__c1, __c2) (((__c1) << 8) | (__c2))
#define TPID3(__c1, __c2, __c3) (((__c1) << 16) | ((__c2) << 8) | (__c3))
#define TPVER TPID
#define TPACPI_Q_IBM(__id1, __id2, __quirk) \ #define TPACPI_Q_IBM(__id1, __id2, __quirk) \
{ .vendor = PCI_VENDOR_ID_IBM, \ { .vendor = PCI_VENDOR_ID_IBM, \
...@@ -476,8 +479,8 @@ do { \ ...@@ -476,8 +479,8 @@ do { \
struct tpacpi_quirk { struct tpacpi_quirk {
unsigned int vendor; unsigned int vendor;
u16 bios; u32 bios;
u16 ec; u32 ec;
unsigned long quirks; unsigned long quirks;
}; };
...@@ -1647,16 +1650,16 @@ static void tpacpi_remove_driver_attributes(struct device_driver *drv) ...@@ -1647,16 +1650,16 @@ static void tpacpi_remove_driver_attributes(struct device_driver *drv)
{ .vendor = (__v), \ { .vendor = (__v), \
.bios = TPID(__id1, __id2), \ .bios = TPID(__id1, __id2), \
.ec = TPACPI_MATCH_ANY, \ .ec = TPACPI_MATCH_ANY, \
.quirks = TPACPI_MATCH_ANY << 16 \ .quirks = TPACPI_MATCH_ANY_VERSION << 16 \
| (__bv1) << 8 | (__bv2) } | TPVER(__bv1, __bv2) }
#define TPV_Q_X(__v, __bid1, __bid2, __bv1, __bv2, \ #define TPV_Q_X(__v, __bid1, __bid2, __bv1, __bv2, \
__eid, __ev1, __ev2) \ __eid, __ev1, __ev2) \
{ .vendor = (__v), \ { .vendor = (__v), \
.bios = TPID(__bid1, __bid2), \ .bios = TPID(__bid1, __bid2), \
.ec = __eid, \ .ec = __eid, \
.quirks = (__ev1) << 24 | (__ev2) << 16 \ .quirks = TPVER(__ev1, __ev2) << 16 \
| (__bv1) << 8 | (__bv2) } | TPVER(__bv1, __bv2) }
#define TPV_QI0(__id1, __id2, __bv1, __bv2) \ #define TPV_QI0(__id1, __id2, __bv1, __bv2) \
TPV_Q(PCI_VENDOR_ID_IBM, __id1, __id2, __bv1, __bv2) TPV_Q(PCI_VENDOR_ID_IBM, __id1, __id2, __bv1, __bv2)
...@@ -1798,7 +1801,7 @@ static void __init tpacpi_check_outdated_fw(void) ...@@ -1798,7 +1801,7 @@ static void __init tpacpi_check_outdated_fw(void)
/* note that unknown versions are set to 0x0000 and we use that */ /* note that unknown versions are set to 0x0000 and we use that */
if ((bios_version > thinkpad_id.bios_release) || if ((bios_version > thinkpad_id.bios_release) ||
(ec_version > thinkpad_id.ec_release && (ec_version > thinkpad_id.ec_release &&
ec_version != TPACPI_MATCH_ANY)) { ec_version != TPACPI_MATCH_ANY_VERSION)) {
/* /*
* The changelogs would let us track down the exact * The changelogs would let us track down the exact
* reason, but it is just too much of a pain to track * reason, but it is just too much of a pain to track
...@@ -9808,36 +9811,37 @@ static int __init ibm_init(struct ibm_init_struct *iibm) ...@@ -9808,36 +9811,37 @@ static int __init ibm_init(struct ibm_init_struct *iibm)
/* Probing */ /* Probing */
static bool __pure __init tpacpi_is_fw_digit(const char c) static char __init tpacpi_parse_fw_id(const char * const s,
u32 *model, u16 *release)
{ {
return (c >= '0' && c <= '9') || (c >= 'A' && c <= 'Z'); int i;
}
if (!s || strlen(s) < 8)
goto invalid;
for (i = 0; i < 8; i++)
if (!((s[i] >= '0' && s[i] <= '9') ||
(s[i] >= 'A' && s[i] <= 'Z')))
goto invalid;
static bool __pure __init tpacpi_is_valid_fw_id(const char * const s,
const char t)
{
/* /*
* Most models: xxyTkkWW (#.##c) * Most models: xxyTkkWW (#.##c)
* Ancient 570/600 and -SL lacks (#.##c) * Ancient 570/600 and -SL lacks (#.##c)
*/ */
if (s && strlen(s) >= 8 && if (s[3] == 'T' || s[3] == 'N') {
tpacpi_is_fw_digit(s[0]) && *model = TPID(s[0], s[1]);
tpacpi_is_fw_digit(s[1]) && *release = TPVER(s[4], s[5]);
s[2] == t && return s[2];
(s[3] == 'T' || s[3] == 'N') &&
tpacpi_is_fw_digit(s[4]) &&
tpacpi_is_fw_digit(s[5]))
return true;
/* New models: xxxyTkkW (#.##c); T550 and some others */ /* New models: xxxyTkkW (#.##c); T550 and some others */
return s && strlen(s) >= 8 && } else if (s[4] == 'T' || s[4] == 'N') {
tpacpi_is_fw_digit(s[0]) && *model = TPID3(s[0], s[1], s[2]);
tpacpi_is_fw_digit(s[1]) && *release = TPVER(s[5], s[6]);
tpacpi_is_fw_digit(s[2]) && return s[3];
s[3] == t && }
(s[4] == 'T' || s[4] == 'N') &&
tpacpi_is_fw_digit(s[5]) && invalid:
tpacpi_is_fw_digit(s[6]); return '\0';
} }
/* returns 0 - probe ok, or < 0 - probe error. /* returns 0 - probe ok, or < 0 - probe error.
...@@ -9849,6 +9853,7 @@ static int __must_check __init get_thinkpad_model_data( ...@@ -9849,6 +9853,7 @@ static int __must_check __init get_thinkpad_model_data(
const struct dmi_device *dev = NULL; const struct dmi_device *dev = NULL;
char ec_fw_string[18]; char ec_fw_string[18];
char const *s; char const *s;
char t;
if (!tp) if (!tp)
return -EINVAL; return -EINVAL;
...@@ -9868,15 +9873,11 @@ static int __must_check __init get_thinkpad_model_data( ...@@ -9868,15 +9873,11 @@ static int __must_check __init get_thinkpad_model_data(
return -ENOMEM; return -ENOMEM;
/* Really ancient ThinkPad 240X will fail this, which is fine */ /* Really ancient ThinkPad 240X will fail this, which is fine */
if (!(tpacpi_is_valid_fw_id(tp->bios_version_str, 'E') || t = tpacpi_parse_fw_id(tp->bios_version_str,
tpacpi_is_valid_fw_id(tp->bios_version_str, 'C'))) &tp->bios_model, &tp->bios_release);
if (t != 'E' && t != 'C')
return 0; return 0;
tp->bios_model = tp->bios_version_str[0]
| (tp->bios_version_str[1] << 8);
tp->bios_release = (tp->bios_version_str[4] << 8)
| tp->bios_version_str[5];
/* /*
* ThinkPad T23 or newer, A31 or newer, R50e or newer, * ThinkPad T23 or newer, A31 or newer, R50e or newer,
* X32 or newer, all Z series; Some models must have an * X32 or newer, all Z series; Some models must have an
...@@ -9895,12 +9896,9 @@ static int __must_check __init get_thinkpad_model_data( ...@@ -9895,12 +9896,9 @@ static int __must_check __init get_thinkpad_model_data(
if (!tp->ec_version_str) if (!tp->ec_version_str)
return -ENOMEM; return -ENOMEM;
if (tpacpi_is_valid_fw_id(ec_fw_string, 'H')) { t = tpacpi_parse_fw_id(ec_fw_string,
tp->ec_model = ec_fw_string[0] &tp->ec_model, &tp->ec_release);
| (ec_fw_string[1] << 8); if (t != 'H') {
tp->ec_release = (ec_fw_string[4] << 8)
| ec_fw_string[5];
} else {
pr_notice("ThinkPad firmware release %s doesn't match the known patterns\n", pr_notice("ThinkPad firmware release %s doesn't match the known patterns\n",
ec_fw_string); ec_fw_string);
pr_notice("please report this to %s\n", pr_notice("please report this to %s\n",
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册