aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHenrique de Moraes Holschuh <hmh@hmh.eng.br>2009-05-30 12:25:06 -0400
committerLen Brown <len.brown@intel.com>2009-06-17 22:46:42 -0400
commit7d95a3d564901e88ed42810f054e579874151999 (patch)
treed8dfc33b4ed235b24c1090dfa484b9b259f1e7a0
parent050df107c408a3df048524b3783a5fc6d4dccfdb (diff)
thinkpad-acpi: add quirklist engine
Add a quirklist engine suitable for matching ThinkPad firmware, and change the code to use it. Signed-off-by: Henrique de Moraes Holschuh <hmh@hmh.eng.br> Signed-off-by: Len Brown <len.brown@intel.com>
-rw-r--r--drivers/platform/x86/thinkpad_acpi.c119
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
394struct 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 */
414static 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
6228static void fan_quirk1_detect(void) 6298static 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
6870static 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
6807static int __init fan_init(struct ibm_init_struct *iibm) 6879static 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, "