diff options
author | Henrique de Moraes Holschuh <hmh@hmh.eng.br> | 2006-11-24 08:47:08 -0500 |
---|---|---|
committer | Len Brown <len.brown@intel.com> | 2006-12-07 01:38:38 -0500 |
commit | 60eb0b35a9cc3400251cb4028d100e350649cf8a (patch) | |
tree | 2f655a273572e46b6c4f662071d027e57cad1bcf | |
parent | a26f878abcd0491906b5bbac8dd174f27019e907 (diff) |
ACPI: ibm-acpi: Implement direct-ec-access thermal reading modes for up to 16 sensors
This patch extends ibm-acpi to support reading thermal sensors directly
through ACPI EC register access. It uses a DMI match to detect ThinkPads
with a new-style embedded controller, that are known to have forward-
compatible register maps and use 0x00 to fill in non-used registers and
export thermal sensors at EC offsets 0x78-7F and 0xC0-C7.
Direct ACPI EC register access is implemented for 8-sensor and 16-sensor
new-style ThinkPad controller firmwares as an experimental feature. The
code does some limited sanity checks on the temperatures read through EC
access, and will default to the old ACPI TMP0-7 mode if anything is amiss.
Userspace ABI is not changed for 8 sensors, but /proc/acpi/ibm/thermal is
extended for 16 sensors if the firmware supports 16 sensors.
A documentation update is also provided.
The information about the ThinkPad register map was determined by studying
ibm-acpi "ecdump" output from various ThinkPad models, submitted by
subscribers of the linux-thinkpad mailinglist. Futher information was
gathered from the DSDT tables, as they describe the EC register map in
recent ThinkPads.
DSDT source shows that TMP0-7 access and direct register access are
actually the same thing on these firmwares, but unfortunately IBM never
did update their DSDT EC register map to export TMP8-TMP15 for the second
range of sensors.
Signed-off-by: Henrique de Moraes Holschuh <hmh@hmh.eng.br>
-rw-r--r-- | Documentation/ibm-acpi.txt | 55 | ||||
-rw-r--r-- | drivers/acpi/ibm_acpi.c | 93 |
2 files changed, 134 insertions, 14 deletions
diff --git a/Documentation/ibm-acpi.txt b/Documentation/ibm-acpi.txt index e50595bfd8ea..30f09e7a423e 100644 --- a/Documentation/ibm-acpi.txt +++ b/Documentation/ibm-acpi.txt | |||
@@ -398,25 +398,56 @@ Temperature sensors -- /proc/acpi/ibm/thermal | |||
398 | 398 | ||
399 | Most ThinkPads include six or more separate temperature sensors but | 399 | Most ThinkPads include six or more separate temperature sensors but |
400 | only expose the CPU temperature through the standard ACPI methods. | 400 | only expose the CPU temperature through the standard ACPI methods. |
401 | This feature shows readings from up to eight different sensors. Some | 401 | This feature shows readings from up to eight different sensors on older |
402 | readings may not be valid, e.g. may show large negative values. For | 402 | ThinkPads, and it has experimental support for up to sixteen different |
403 | example, on the X40, a typical output may be: | 403 | sensors on newer ThinkPads. Readings from sensors that are not available |
404 | return -128. | ||
404 | 405 | ||
406 | No commands can be written to this file. | ||
407 | |||
408 | EXPERIMENTAL: The 16-sensors feature is marked EXPERIMENTAL because the | ||
409 | implementation directly accesses hardware registers and may not work as | ||
410 | expected. USE WITH CAUTION! To use this feature, you need to supply the | ||
411 | experimental=1 parameter when loading the module. When EXPERIMENTAL | ||
412 | mode is enabled, reading the first 8 sensors on newer ThinkPads will | ||
413 | also use an new experimental thermal sensor access mode. | ||
414 | |||
415 | For example, on the X40, a typical output may be: | ||
405 | temperatures: 42 42 45 41 36 -128 33 -128 | 416 | temperatures: 42 42 45 41 36 -128 33 -128 |
406 | 417 | ||
407 | Thomas Gruber took his R51 apart and traced all six active sensors in | 418 | EXPERIMENTAL: On the T43/p, a typical output may be: |
408 | his laptop (the location of sensors may vary on other models): | 419 | temperatures: 48 48 36 52 38 -128 31 -128 48 52 48 -128 -128 -128 -128 -128 |
420 | |||
421 | The mapping of thermal sensors to physical locations varies depending on | ||
422 | system-board model (and thus, on ThinkPad model). | ||
423 | |||
424 | http://thinkwiki.org/wiki/Thermal_Sensors is a public wiki page that | ||
425 | tries to track down these locations for various models. | ||
426 | |||
427 | Most (newer?) models seem to follow this pattern: | ||
409 | 428 | ||
410 | 1: CPU | 429 | 1: CPU |
411 | 2: Mini PCI Module | 430 | 2: (depends on model) |
412 | 3: HDD | 431 | 3: (depends on model) |
413 | 4: GPU | 432 | 4: GPU |
414 | 5: Battery | 433 | 5: Main battery: main sensor |
415 | 6: N/A | 434 | 6: Bay battery: main sensor |
416 | 7: Battery | 435 | 7: Main battery: secondary sensor |
417 | 8: N/A | 436 | 8: Bay battery: secondary sensor |
437 | 9-15: (depends on model) | ||
438 | |||
439 | For the R51 (source: Thomas Gruber): | ||
440 | 2: Mini-PCI | ||
441 | 3: Internal HDD | ||
442 | |||
443 | For the T43, T43/p (source: Shmidoax/Thinkwiki.org) | ||
444 | http://thinkwiki.org/wiki/Thermal_Sensors#ThinkPad_T43.2C_T43p | ||
445 | 2: System board, left side (near PCMCIA slot), reported as HDAPS temp | ||
446 | 3: PCMCIA slot | ||
447 | 9: MCH (northbridge) to DRAM Bus | ||
448 | 10: ICH (southbridge), under Mini-PCI card, under touchpad | ||
449 | 11: Power regulator, underside of system board, below F2 key | ||
418 | 450 | ||
419 | No commands can be written to this file. | ||
420 | 451 | ||
421 | EXPERIMENTAL: Embedded controller register dump -- /proc/acpi/ibm/ecdump | 452 | EXPERIMENTAL: Embedded controller register dump -- /proc/acpi/ibm/ecdump |
422 | ------------------------------------------------------------------------ | 453 | ------------------------------------------------------------------------ |
diff --git a/drivers/acpi/ibm_acpi.c b/drivers/acpi/ibm_acpi.c index baf9492f0a79..1703c617c0e8 100644 --- a/drivers/acpi/ibm_acpi.c +++ b/drivers/acpi/ibm_acpi.c | |||
@@ -80,6 +80,7 @@ | |||
80 | #include <linux/proc_fs.h> | 80 | #include <linux/proc_fs.h> |
81 | #include <linux/backlight.h> | 81 | #include <linux/backlight.h> |
82 | #include <asm/uaccess.h> | 82 | #include <asm/uaccess.h> |
83 | #include <linux/dmi.h> | ||
83 | 84 | ||
84 | #include <acpi/acpi_drivers.h> | 85 | #include <acpi/acpi_drivers.h> |
85 | #include <acpi/acnamesp.h> | 86 | #include <acpi/acnamesp.h> |
@@ -221,13 +222,17 @@ enum thermal_access_mode { | |||
221 | IBMACPI_THERMAL_NONE = 0, /* No thermal support */ | 222 | IBMACPI_THERMAL_NONE = 0, /* No thermal support */ |
222 | IBMACPI_THERMAL_ACPI_TMP07, /* Use ACPI TMP0-7 */ | 223 | IBMACPI_THERMAL_ACPI_TMP07, /* Use ACPI TMP0-7 */ |
223 | IBMACPI_THERMAL_ACPI_UPDT, /* Use ACPI TMP0-7 with UPDT */ | 224 | IBMACPI_THERMAL_ACPI_UPDT, /* Use ACPI TMP0-7 with UPDT */ |
225 | IBMACPI_THERMAL_TPEC_8, /* Use ACPI EC regs, 8 sensors */ | ||
226 | IBMACPI_THERMAL_TPEC_16, /* Use ACPI EC regs, 16 sensors */ | ||
224 | }; | 227 | }; |
225 | 228 | ||
226 | #define IBMACPI_MAX_THERMAL_SENSORS 8 /* Max thermal sensors supported */ | 229 | #define IBMACPI_MAX_THERMAL_SENSORS 16 /* Max thermal sensors supported */ |
227 | struct ibm_thermal_sensors_struct { | 230 | struct ibm_thermal_sensors_struct { |
228 | s32 temp[IBMACPI_MAX_THERMAL_SENSORS]; | 231 | s32 temp[IBMACPI_MAX_THERMAL_SENSORS]; |
229 | }; | 232 | }; |
230 | 233 | ||
234 | static int ibm_thinkpad_ec_found; | ||
235 | |||
231 | struct ibm_struct { | 236 | struct ibm_struct { |
232 | char *name; | 237 | char *name; |
233 | char param[32]; | 238 | char param[32]; |
@@ -1290,7 +1295,52 @@ static enum thermal_access_mode thermal_read_mode; | |||
1290 | 1295 | ||
1291 | static int thermal_init(void) | 1296 | static int thermal_init(void) |
1292 | { | 1297 | { |
1293 | if (acpi_evalf(ec_handle, NULL, "TMP7", "qv")) { | 1298 | u8 t, ta1, ta2; |
1299 | int i; | ||
1300 | int acpi_tmp7 = acpi_evalf(ec_handle, NULL, "TMP7", "qv"); | ||
1301 | |||
1302 | if (ibm_thinkpad_ec_found && experimental) { | ||
1303 | /* | ||
1304 | * Direct EC access mode: sensors at registers | ||
1305 | * 0x78-0x7F, 0xC0-0xC7. Registers return 0x00 for | ||
1306 | * non-implemented, thermal sensors return 0x80 when | ||
1307 | * not available | ||
1308 | */ | ||
1309 | |||
1310 | ta1 = ta2 = 0; | ||
1311 | for (i = 0; i < 8; i++) { | ||
1312 | if (likely(acpi_ec_read(0x78 + i, &t))) { | ||
1313 | ta1 |= t; | ||
1314 | } else { | ||
1315 | ta1 = 0; | ||
1316 | break; | ||
1317 | } | ||
1318 | if (likely(acpi_ec_read(0xC0 + i, &t))) { | ||
1319 | ta2 |= t; | ||
1320 | } else { | ||
1321 | ta1 = 0; | ||
1322 | break; | ||
1323 | } | ||
1324 | } | ||
1325 | if (ta1 == 0) { | ||
1326 | /* This is sheer paranoia, but we handle it anyway */ | ||
1327 | if (acpi_tmp7) { | ||
1328 | printk(IBM_ERR | ||
1329 | "ThinkPad ACPI EC access misbehaving, " | ||
1330 | "falling back to ACPI TMPx access mode\n"); | ||
1331 | thermal_read_mode = IBMACPI_THERMAL_ACPI_TMP07; | ||
1332 | } else { | ||
1333 | printk(IBM_ERR | ||
1334 | "ThinkPad ACPI EC access misbehaving, " | ||
1335 | "disabling thermal sensors access\n"); | ||
1336 | thermal_read_mode = IBMACPI_THERMAL_NONE; | ||
1337 | } | ||
1338 | } else { | ||
1339 | thermal_read_mode = | ||
1340 | (ta2 != 0) ? | ||
1341 | IBMACPI_THERMAL_TPEC_16 : IBMACPI_THERMAL_TPEC_8; | ||
1342 | } | ||
1343 | } else if (acpi_tmp7) { | ||
1294 | if (acpi_evalf(ec_handle, NULL, "UPDT", "qv")) { | 1344 | if (acpi_evalf(ec_handle, NULL, "UPDT", "qv")) { |
1295 | /* 600e/x, 770e, 770x */ | 1345 | /* 600e/x, 770e, 770x */ |
1296 | thermal_read_mode = IBMACPI_THERMAL_ACPI_UPDT; | 1346 | thermal_read_mode = IBMACPI_THERMAL_ACPI_UPDT; |
@@ -1309,12 +1359,30 @@ static int thermal_init(void) | |||
1309 | static int thermal_get_sensors(struct ibm_thermal_sensors_struct *s) | 1359 | static int thermal_get_sensors(struct ibm_thermal_sensors_struct *s) |
1310 | { | 1360 | { |
1311 | int i, t; | 1361 | int i, t; |
1362 | s8 tmp; | ||
1312 | char tmpi[] = "TMPi"; | 1363 | char tmpi[] = "TMPi"; |
1313 | 1364 | ||
1314 | if (!s) | 1365 | if (!s) |
1315 | return -EINVAL; | 1366 | return -EINVAL; |
1316 | 1367 | ||
1317 | switch (thermal_read_mode) { | 1368 | switch (thermal_read_mode) { |
1369 | #if IBMACPI_MAX_THERMAL_SENSORS >= 16 | ||
1370 | case IBMACPI_THERMAL_TPEC_16: | ||
1371 | for (i = 0; i < 8; i++) { | ||
1372 | if (!acpi_ec_read(0xC0 + i, &tmp)) | ||
1373 | return -EIO; | ||
1374 | s->temp[i + 8] = tmp * 1000; | ||
1375 | } | ||
1376 | /* fallthrough */ | ||
1377 | #endif | ||
1378 | case IBMACPI_THERMAL_TPEC_8: | ||
1379 | for (i = 0; i < 8; i++) { | ||
1380 | if (!acpi_ec_read(0x78 + i, &tmp)) | ||
1381 | return -EIO; | ||
1382 | s->temp[i] = tmp * 1000; | ||
1383 | } | ||
1384 | return (thermal_read_mode == IBMACPI_THERMAL_TPEC_16) ? 16 : 8; | ||
1385 | |||
1318 | case IBMACPI_THERMAL_ACPI_UPDT: | 1386 | case IBMACPI_THERMAL_ACPI_UPDT: |
1319 | if (!acpi_evalf(ec_handle, NULL, "UPDT", "v")) | 1387 | if (!acpi_evalf(ec_handle, NULL, "UPDT", "v")) |
1320 | return -EIO; | 1388 | return -EIO; |
@@ -2052,6 +2120,24 @@ static void acpi_ibm_exit(void) | |||
2052 | remove_proc_entry(IBM_DIR, acpi_root_dir); | 2120 | remove_proc_entry(IBM_DIR, acpi_root_dir); |
2053 | } | 2121 | } |
2054 | 2122 | ||
2123 | static int __init check_dmi_for_ec(void) | ||
2124 | { | ||
2125 | struct dmi_device *dev = NULL; | ||
2126 | |||
2127 | /* | ||
2128 | * ThinkPad T23 or newer, A31 or newer, R50e or newer, | ||
2129 | * X32 or newer, all Z series; Some models must have an | ||
2130 | * up-to-date BIOS or they will not be detected. | ||
2131 | * | ||
2132 | * See http://thinkwiki.org/wiki/List_of_DMI_IDs | ||
2133 | */ | ||
2134 | while ((dev = dmi_find_device(DMI_DEV_TYPE_OEM_STRING, NULL, dev))) { | ||
2135 | if (strstr(dev->name, "IBM ThinkPad Embedded Controller")) | ||
2136 | return 1; | ||
2137 | } | ||
2138 | return 0; | ||
2139 | } | ||
2140 | |||
2055 | static int __init acpi_ibm_init(void) | 2141 | static int __init acpi_ibm_init(void) |
2056 | { | 2142 | { |
2057 | int ret, i; | 2143 | int ret, i; |
@@ -2071,6 +2157,9 @@ static int __init acpi_ibm_init(void) | |||
2071 | return -ENODEV; | 2157 | return -ENODEV; |
2072 | } | 2158 | } |
2073 | 2159 | ||
2160 | /* Models with newer firmware report the EC in DMI */ | ||
2161 | ibm_thinkpad_ec_found = check_dmi_for_ec(); | ||
2162 | |||
2074 | /* these handles are not required */ | 2163 | /* these handles are not required */ |
2075 | IBM_HANDLE_INIT(vid); | 2164 | IBM_HANDLE_INIT(vid); |
2076 | IBM_HANDLE_INIT(vid2); | 2165 | IBM_HANDLE_INIT(vid2); |