aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/acpi
diff options
context:
space:
mode:
authorHenrique de Moraes Holschuh <hmh@hmh.eng.br>2006-11-24 08:47:14 -0500
committerLen Brown <len.brown@intel.com>2006-12-07 01:38:44 -0500
commit778b4d742b210b9cac31f223527f30f1fc70312b (patch)
tree6b31cfefb71b7b748296a184d3a06d9b7e334b66 /drivers/acpi
parent49a13cd6a2acd284ee106eaea7eeea8f2cc6796a (diff)
ACPI: ibm-acpi: workaround for EC 0x2f initialization bug
A few ThinkPads fail to initialize EC register 0x2f both in the EC firmware and ACPI DSDT. If the BIOS and the ACPI DSDT also do not initialize it, then the initial status of that register does not correspond to reality. On all reported buggy machines, EC 0x2f will read 0x07 (fan level 7) upon cold boot, when the EC is actually in mode 0x80 (auto mode). Since returning a text string ("unknown") would break a number of userspace programs, instead we correct the reading for the most probably correct answer, and return it is in auto mode. The workaround flags the status and level as unknown on module load/kernel boot, until we are certain at least one fan control command was issued, either by us, or by something else. We don't work around the bug by doing a "fan enable" at module load/startup (which would initialize the EC register) because it is not known if these ThinkPad ACPI DSDT might have set the fan to level 7 instead of "auto" (we don't know if they can do this or not) due to a thermal condition, and we don't want to override that, should they be capable of it. We should be setting the workaround flag to "status known" upon resume, as both reports and a exaustive search on the DSDT tables at acpi.sf.net show that the DSDTs always enable the fan on resume, thus working around the bug. But since we don't have suspend/resume handlers in ibm-acpi yet and the "EC register 0x2f was modified" logic is likely to catch the change anyway, we don't. Signed-off-by: Henrique de Moraes Holschuh <hmh@hmh.eng.br>
Diffstat (limited to 'drivers/acpi')
-rw-r--r--drivers/acpi/ibm_acpi.c53
1 files changed, 49 insertions, 4 deletions
diff --git a/drivers/acpi/ibm_acpi.c b/drivers/acpi/ibm_acpi.c
index 3c091c4b461f..56743c5a0439 100644
--- a/drivers/acpi/ibm_acpi.c
+++ b/drivers/acpi/ibm_acpi.c
@@ -362,7 +362,7 @@ enum { /* Fan control constants */
362 * control */ 362 * control */
363}; 363};
364 364
365static char* ibm_thinkpad_ec_found = NULL; 365static char *ibm_thinkpad_ec_found = NULL;
366 366
367struct ibm_struct { 367struct ibm_struct {
368 char *name; 368 char *name;
@@ -1794,13 +1794,15 @@ static enum fan_status_access_mode fan_status_access_mode;
1794static enum fan_control_access_mode fan_control_access_mode; 1794static enum fan_control_access_mode fan_control_access_mode;
1795static enum fan_control_commands fan_control_commands; 1795static enum fan_control_commands fan_control_commands;
1796 1796
1797static int fan_control_status_known;
1798static u8 fan_control_initial_status;
1799
1797static int fan_init(void) 1800static int fan_init(void)
1798{ 1801{
1799 u8 status;
1800
1801 fan_status_access_mode = IBMACPI_FAN_NONE; 1802 fan_status_access_mode = IBMACPI_FAN_NONE;
1802 fan_control_access_mode = IBMACPI_FAN_WR_NONE; 1803 fan_control_access_mode = IBMACPI_FAN_WR_NONE;
1803 fan_control_commands = 0; 1804 fan_control_commands = 0;
1805 fan_control_status_known = 1;
1804 1806
1805 if (gfan_handle) { 1807 if (gfan_handle) {
1806 /* 570, 600e/x, 770e, 770x */ 1808 /* 570, 600e/x, 770e, 770x */
@@ -1808,8 +1810,33 @@ static int fan_init(void)
1808 } else { 1810 } else {
1809 /* all other ThinkPads: note that even old-style 1811 /* all other ThinkPads: note that even old-style
1810 * ThinkPad ECs supports the fan control register */ 1812 * ThinkPad ECs supports the fan control register */
1811 if (likely(acpi_ec_read(fan_status_offset, &status))) { 1813 if (likely(acpi_ec_read(fan_status_offset,
1814 &fan_control_initial_status))) {
1812 fan_status_access_mode = IBMACPI_FAN_RD_TPEC; 1815 fan_status_access_mode = IBMACPI_FAN_RD_TPEC;
1816
1817 /* In some ThinkPads, neither the EC nor the ACPI
1818 * DSDT initialize the fan status, and it ends up
1819 * being set to 0x07 when it *could* be either
1820 * 0x07 or 0x80.
1821 *
1822 * Enable for TP-1Y (T43), TP-78 (R51e),
1823 * TP-76 (R52), TP-70 (T43, R52), which are known
1824 * to be buggy. */
1825 if (fan_control_initial_status == 0x07 &&
1826 ibm_thinkpad_ec_found &&
1827 ((ibm_thinkpad_ec_found[0] == '1' &&
1828 ibm_thinkpad_ec_found[1] == 'Y') ||
1829 (ibm_thinkpad_ec_found[0] == '7' &&
1830 (ibm_thinkpad_ec_found[1] == '6' ||
1831 ibm_thinkpad_ec_found[1] == '8' ||
1832 ibm_thinkpad_ec_found[1] == '0'))
1833 )) {
1834 printk(IBM_NOTICE
1835 "fan_init: initial fan status is "
1836 "unknown, assuming it is in auto "
1837 "mode\n");
1838 fan_control_status_known = 0;
1839 }
1813 } else { 1840 } else {
1814 printk(IBM_ERR 1841 printk(IBM_ERR
1815 "ThinkPad ACPI EC access misbehaving, " 1842 "ThinkPad ACPI EC access misbehaving, "
@@ -1930,9 +1957,21 @@ static int fan_read(char *p)
1930 if ((rc = fan_get_status(&status)) < 0) 1957 if ((rc = fan_get_status(&status)) < 0)
1931 return rc; 1958 return rc;
1932 1959
1960 if (unlikely(!fan_control_status_known)) {
1961 if (status != fan_control_initial_status)
1962 fan_control_status_known = 1;
1963 else
1964 /* Return most likely status. In fact, it
1965 * might be the only possible status */
1966 status = IBMACPI_FAN_EC_AUTO;
1967 }
1968
1933 len += sprintf(p + len, "status:\t\t%s\n", 1969 len += sprintf(p + len, "status:\t\t%s\n",
1934 (status != 0) ? "enabled" : "disabled"); 1970 (status != 0) ? "enabled" : "disabled");
1935 1971
1972 /* No ThinkPad boots on disengaged mode, we can safely
1973 * assume the tachometer is online if fan control status
1974 * was unknown */
1936 if ((rc = fan_get_speed(&speed)) < 0) 1975 if ((rc = fan_get_speed(&speed)) < 0)
1937 return rc; 1976 return rc;
1938 1977
@@ -1997,6 +2036,8 @@ static int fan_set_level(int level)
1997 2036
1998 if (!acpi_ec_write(fan_status_offset, level)) 2037 if (!acpi_ec_write(fan_status_offset, level))
1999 return -EIO; 2038 return -EIO;
2039 else
2040 fan_control_status_known = 1;
2000 break; 2041 break;
2001 2042
2002 default: 2043 default:
@@ -2022,6 +2063,8 @@ static int fan_set_enable(void)
2022 2063
2023 if (!acpi_ec_write(fan_status_offset, s)) 2064 if (!acpi_ec_write(fan_status_offset, s))
2024 return -EIO; 2065 return -EIO;
2066 else
2067 fan_control_status_known = 1;
2025 break; 2068 break;
2026 2069
2027 case IBMACPI_FAN_WR_ACPI_SFAN: 2070 case IBMACPI_FAN_WR_ACPI_SFAN:
@@ -2051,6 +2094,8 @@ static int fan_set_disable(void)
2051 case IBMACPI_FAN_WR_TPEC: 2094 case IBMACPI_FAN_WR_TPEC:
2052 if (!acpi_ec_write(fan_status_offset, 0x00)) 2095 if (!acpi_ec_write(fan_status_offset, 0x00))
2053 return -EIO; 2096 return -EIO;
2097 else
2098 fan_control_status_known = 1;
2054 break; 2099 break;
2055 2100
2056 case IBMACPI_FAN_WR_ACPI_SFAN: 2101 case IBMACPI_FAN_WR_ACPI_SFAN: