diff options
Diffstat (limited to 'drivers/platform/x86/thinkpad_acpi.c')
-rw-r--r-- | drivers/platform/x86/thinkpad_acpi.c | 119 |
1 files changed, 98 insertions, 21 deletions
diff --git a/drivers/platform/x86/thinkpad_acpi.c b/drivers/platform/x86/thinkpad_acpi.c index d2a0ef83fbb5..3981b060b7d5 100644 --- a/drivers/platform/x86/thinkpad_acpi.c +++ b/drivers/platform/x86/thinkpad_acpi.c | |||
@@ -364,6 +364,73 @@ static void tpacpi_log_usertask(const char * const what) | |||
364 | } \ | 364 | } \ |
365 | } while (0) | 365 | } while (0) |
366 | 366 | ||
367 | /* | ||
368 | * Quirk handling helpers | ||
369 | * | ||
370 | * ThinkPad IDs and versions seen in the field so far | ||
371 | * are two-characters from the set [0-9A-Z], i.e. base 36. | ||
372 | * | ||
373 | * We use values well outside that range as specials. | ||
374 | */ | ||
375 | |||
376 | #define TPACPI_MATCH_ANY 0xffffU | ||
377 | #define TPACPI_MATCH_UNKNOWN 0U | ||
378 | |||
379 | /* TPID('1', 'Y') == 0x5931 */ | ||
380 | #define TPID(__c1, __c2) (((__c2) << 8) | (__c1)) | ||
381 | |||
382 | #define TPACPI_Q_IBM(__id1, __id2, __quirk) \ | ||
383 | { .vendor = PCI_VENDOR_ID_IBM, \ | ||
384 | .bios = TPID(__id1, __id2), \ | ||
385 | .ec = TPACPI_MATCH_ANY, \ | ||
386 | .quirks = (__quirk) } | ||
387 | |||
388 | #define TPACPI_Q_LNV(__id1, __id2, __quirk) \ | ||
389 | { .vendor = PCI_VENDOR_ID_LENOVO, \ | ||
390 | .bios = TPID(__id1, __id2), \ | ||
391 | .ec = TPACPI_MATCH_ANY, \ | ||
392 | .quirks = (__quirk) } | ||
393 | |||
394 | struct tpacpi_quirk { | ||
395 | unsigned int vendor; | ||
396 | u16 bios; | ||
397 | u16 ec; | ||
398 | unsigned long quirks; | ||
399 | }; | ||
400 | |||
401 | /** | ||
402 | * tpacpi_check_quirks() - search BIOS/EC version on a list | ||
403 | * @qlist: array of &struct tpacpi_quirk | ||
404 | * @qlist_size: number of elements in @qlist | ||
405 | * | ||
406 | * Iterates over a quirks list until one is found that matches the | ||
407 | * ThinkPad's vendor, BIOS and EC model. | ||
408 | * | ||
409 | * Returns 0 if nothing matches, otherwise returns the quirks field of | ||
410 | * the matching &struct tpacpi_quirk entry. | ||
411 | * | ||
412 | * The match criteria is: vendor, ec and bios much match. | ||
413 | */ | ||
414 | static unsigned long __init tpacpi_check_quirks( | ||
415 | const struct tpacpi_quirk *qlist, | ||
416 | unsigned int qlist_size) | ||
417 | { | ||
418 | while (qlist_size) { | ||
419 | if ((qlist->vendor == thinkpad_id.vendor || | ||
420 | qlist->vendor == TPACPI_MATCH_ANY) && | ||
421 | (qlist->bios == thinkpad_id.bios_model || | ||
422 | qlist->bios == TPACPI_MATCH_ANY) && | ||
423 | (qlist->ec == thinkpad_id.ec_model || | ||
424 | qlist->ec == TPACPI_MATCH_ANY)) | ||
425 | return qlist->quirks; | ||
426 | |||
427 | qlist_size--; | ||
428 | qlist++; | ||
429 | } | ||
430 | return 0; | ||
431 | } | ||
432 | |||
433 | |||
367 | /**************************************************************************** | 434 | /**************************************************************************** |
368 | **************************************************************************** | 435 | **************************************************************************** |
369 | * | 436 | * |
@@ -6223,30 +6290,18 @@ TPACPI_HANDLE(sfan, ec, "SFAN", /* 570 */ | |||
6223 | * We assume 0x07 really means auto mode while this quirk is active, | 6290 | * We assume 0x07 really means auto mode while this quirk is active, |
6224 | * as this is far more likely than the ThinkPad being in level 7, | 6291 | * as this is far more likely than the ThinkPad being in level 7, |
6225 | * which is only used by the firmware during thermal emergencies. | 6292 | * which is only used by the firmware during thermal emergencies. |
6293 | * | ||
6294 | * Enable for TP-1Y (T43), TP-78 (R51e), TP-76 (R52), | ||
6295 | * TP-70 (T43, R52), which are known to be buggy. | ||
6226 | */ | 6296 | */ |
6227 | 6297 | ||
6228 | static void fan_quirk1_detect(void) | 6298 | static void fan_quirk1_setup(void) |
6229 | { | 6299 | { |
6230 | /* In some ThinkPads, neither the EC nor the ACPI | ||
6231 | * DSDT initialize the HFSP register, and it ends up | ||
6232 | * being initially set to 0x07 when it *could* be | ||
6233 | * either 0x07 or 0x80. | ||
6234 | * | ||
6235 | * Enable for TP-1Y (T43), TP-78 (R51e), | ||
6236 | * TP-76 (R52), TP-70 (T43, R52), which are known | ||
6237 | * to be buggy. */ | ||
6238 | if (fan_control_initial_status == 0x07) { | 6300 | if (fan_control_initial_status == 0x07) { |
6239 | switch (thinkpad_id.ec_model) { | 6301 | printk(TPACPI_NOTICE |
6240 | case 0x5931: /* TP-1Y */ | 6302 | "fan_init: initial fan status is unknown, " |
6241 | case 0x3837: /* TP-78 */ | 6303 | "assuming it is in auto mode\n"); |
6242 | case 0x3637: /* TP-76 */ | 6304 | tp_features.fan_ctrl_status_undef = 1; |
6243 | case 0x3037: /* TP-70 */ | ||
6244 | printk(TPACPI_NOTICE | ||
6245 | "fan_init: initial fan status is unknown, " | ||
6246 | "assuming it is in auto mode\n"); | ||
6247 | tp_features.fan_ctrl_status_undef = 1; | ||
6248 | ;; | ||
6249 | } | ||
6250 | } | 6305 | } |
6251 | } | 6306 | } |
6252 | 6307 | ||
@@ -6804,9 +6859,27 @@ static const struct attribute_group fan_attr_group = { | |||
6804 | .attrs = fan_attributes, | 6859 | .attrs = fan_attributes, |
6805 | }; | 6860 | }; |
6806 | 6861 | ||
6862 | #define TPACPI_FAN_Q1 0x0001 | ||
6863 | |||
6864 | #define TPACPI_FAN_QI(__id1, __id2, __quirks) \ | ||
6865 | { .vendor = PCI_VENDOR_ID_IBM, \ | ||
6866 | .bios = TPACPI_MATCH_ANY, \ | ||
6867 | .ec = TPID(__id1, __id2), \ | ||
6868 | .quirks = __quirks } | ||
6869 | |||
6870 | static const struct tpacpi_quirk fan_quirk_table[] __initconst = { | ||
6871 | TPACPI_FAN_QI('1', 'Y', TPACPI_FAN_Q1), | ||
6872 | TPACPI_FAN_QI('7', '8', TPACPI_FAN_Q1), | ||
6873 | TPACPI_FAN_QI('7', '6', TPACPI_FAN_Q1), | ||
6874 | TPACPI_FAN_QI('7', '0', TPACPI_FAN_Q1), | ||
6875 | }; | ||
6876 | |||
6877 | #undef TPACPI_FAN_QI | ||
6878 | |||
6807 | static int __init fan_init(struct ibm_init_struct *iibm) | 6879 | static int __init fan_init(struct ibm_init_struct *iibm) |
6808 | { | 6880 | { |
6809 | int rc; | 6881 | int rc; |
6882 | unsigned long quirks; | ||
6810 | 6883 | ||
6811 | vdbg_printk(TPACPI_DBG_INIT | TPACPI_DBG_FAN, | 6884 | vdbg_printk(TPACPI_DBG_INIT | TPACPI_DBG_FAN, |
6812 | "initializing fan subdriver\n"); | 6885 | "initializing fan subdriver\n"); |
@@ -6823,6 +6896,9 @@ static int __init fan_init(struct ibm_init_struct *iibm) | |||
6823 | TPACPI_ACPIHANDLE_INIT(gfan); | 6896 | TPACPI_ACPIHANDLE_INIT(gfan); |
6824 | TPACPI_ACPIHANDLE_INIT(sfan); | 6897 | TPACPI_ACPIHANDLE_INIT(sfan); |
6825 | 6898 | ||
6899 | quirks = tpacpi_check_quirks(fan_quirk_table, | ||
6900 | ARRAY_SIZE(fan_quirk_table)); | ||
6901 | |||
6826 | if (gfan_handle) { | 6902 | if (gfan_handle) { |
6827 | /* 570, 600e/x, 770e, 770x */ | 6903 | /* 570, 600e/x, 770e, 770x */ |
6828 | fan_status_access_mode = TPACPI_FAN_RD_ACPI_GFAN; | 6904 | fan_status_access_mode = TPACPI_FAN_RD_ACPI_GFAN; |
@@ -6832,7 +6908,8 @@ static int __init fan_init(struct ibm_init_struct *iibm) | |||
6832 | if (likely(acpi_ec_read(fan_status_offset, | 6908 | if (likely(acpi_ec_read(fan_status_offset, |
6833 | &fan_control_initial_status))) { | 6909 | &fan_control_initial_status))) { |
6834 | fan_status_access_mode = TPACPI_FAN_RD_TPEC; | 6910 | fan_status_access_mode = TPACPI_FAN_RD_TPEC; |
6835 | fan_quirk1_detect(); | 6911 | if (quirks & TPACPI_FAN_Q1) |
6912 | fan_quirk1_setup(); | ||
6836 | } else { | 6913 | } else { |
6837 | printk(TPACPI_ERR | 6914 | printk(TPACPI_ERR |
6838 | "ThinkPad ACPI EC access misbehaving, " | 6915 | "ThinkPad ACPI EC access misbehaving, " |