diff options
-rw-r--r-- | Documentation/ibm-acpi.txt | 20 | ||||
-rw-r--r-- | drivers/acpi/ibm_acpi.c | 70 |
2 files changed, 87 insertions, 3 deletions
diff --git a/Documentation/ibm-acpi.txt b/Documentation/ibm-acpi.txt index cbd3a603a7ef..0132d363feb5 100644 --- a/Documentation/ibm-acpi.txt +++ b/Documentation/ibm-acpi.txt | |||
@@ -670,6 +670,26 @@ example: | |||
670 | 670 | ||
671 | modprobe ibm_acpi hotkey=enable,0xffff video=auto_disable | 671 | modprobe ibm_acpi hotkey=enable,0xffff video=auto_disable |
672 | 672 | ||
673 | The ibm-acpi kernel driver can be programmed to revert the fan level | ||
674 | to a safe setting if userspace does not issue one of the fan commands: | ||
675 | "enable", "disable", "level" or "watchdog" within a configurable | ||
676 | ammount of time. To do this, use the "watchdog" command. | ||
677 | |||
678 | echo 'watchdog <interval>' > /proc/acpi/ibm/fan | ||
679 | |||
680 | Interval is the ammount of time in seconds to wait for one of the | ||
681 | above mentioned fan commands before reseting the fan level to a safe | ||
682 | one. If set to zero, the watchdog is disabled (default). When the | ||
683 | watchdog timer runs out, it does the exact equivalent of the "enable" | ||
684 | fan command. | ||
685 | |||
686 | Note that the watchdog timer stops after it enables the fan. It will | ||
687 | be rearmed again automatically (using the same interval) when one of | ||
688 | the above mentioned fan commands is received. The fan watchdog is, | ||
689 | therefore, not suitable to protect against fan mode changes made | ||
690 | through means other than the "enable", "disable", and "level" fan | ||
691 | commands. | ||
692 | |||
673 | 693 | ||
674 | Example Configuration | 694 | Example Configuration |
675 | --------------------- | 695 | --------------------- |
diff --git a/drivers/acpi/ibm_acpi.c b/drivers/acpi/ibm_acpi.c index 56743c5a0439..e5b8745b9070 100644 --- a/drivers/acpi/ibm_acpi.c +++ b/drivers/acpi/ibm_acpi.c | |||
@@ -82,6 +82,8 @@ | |||
82 | #include <linux/backlight.h> | 82 | #include <linux/backlight.h> |
83 | #include <asm/uaccess.h> | 83 | #include <asm/uaccess.h> |
84 | #include <linux/dmi.h> | 84 | #include <linux/dmi.h> |
85 | #include <linux/jiffies.h> | ||
86 | #include <linux/workqueue.h> | ||
85 | 87 | ||
86 | #include <acpi/acpi_drivers.h> | 88 | #include <acpi/acpi_drivers.h> |
87 | #include <acpi/acnamesp.h> | 89 | #include <acpi/acnamesp.h> |
@@ -348,7 +350,8 @@ enum fan_control_access_mode { | |||
348 | enum fan_control_commands { | 350 | enum fan_control_commands { |
349 | IBMACPI_FAN_CMD_SPEED = 0x0001, /* speed command */ | 351 | IBMACPI_FAN_CMD_SPEED = 0x0001, /* speed command */ |
350 | IBMACPI_FAN_CMD_LEVEL = 0x0002, /* level command */ | 352 | IBMACPI_FAN_CMD_LEVEL = 0x0002, /* level command */ |
351 | IBMACPI_FAN_CMD_ENABLE = 0x0004, /* enable/disable cmd */ | 353 | IBMACPI_FAN_CMD_ENABLE = 0x0004, /* enable/disable cmd, |
354 | * and also watchdog cmd */ | ||
352 | }; | 355 | }; |
353 | 356 | ||
354 | enum { /* Fan control constants */ | 357 | enum { /* Fan control constants */ |
@@ -1797,12 +1800,17 @@ static enum fan_control_commands fan_control_commands; | |||
1797 | static int fan_control_status_known; | 1800 | static int fan_control_status_known; |
1798 | static u8 fan_control_initial_status; | 1801 | static u8 fan_control_initial_status; |
1799 | 1802 | ||
1803 | static void fan_watchdog_fire(void *ignored); | ||
1804 | static int fan_watchdog_maxinterval; | ||
1805 | static DECLARE_WORK(fan_watchdog_task, fan_watchdog_fire, NULL); | ||
1806 | |||
1800 | static int fan_init(void) | 1807 | static int fan_init(void) |
1801 | { | 1808 | { |
1802 | fan_status_access_mode = IBMACPI_FAN_NONE; | 1809 | fan_status_access_mode = IBMACPI_FAN_NONE; |
1803 | fan_control_access_mode = IBMACPI_FAN_WR_NONE; | 1810 | fan_control_access_mode = IBMACPI_FAN_WR_NONE; |
1804 | fan_control_commands = 0; | 1811 | fan_control_commands = 0; |
1805 | fan_control_status_known = 1; | 1812 | fan_control_status_known = 1; |
1813 | fan_watchdog_maxinterval = 0; | ||
1806 | 1814 | ||
1807 | if (gfan_handle) { | 1815 | if (gfan_handle) { |
1808 | /* 570, 600e/x, 770e, 770x */ | 1816 | /* 570, 600e/x, 770e, 770x */ |
@@ -1934,6 +1942,31 @@ static int fan_get_speed(unsigned int *speed) | |||
1934 | return 0; | 1942 | return 0; |
1935 | } | 1943 | } |
1936 | 1944 | ||
1945 | static void fan_exit(void) | ||
1946 | { | ||
1947 | cancel_delayed_work(&fan_watchdog_task); | ||
1948 | flush_scheduled_work(); | ||
1949 | } | ||
1950 | |||
1951 | static void fan_watchdog_reset(void) | ||
1952 | { | ||
1953 | static int fan_watchdog_active = 0; | ||
1954 | |||
1955 | if (fan_watchdog_active) | ||
1956 | cancel_delayed_work(&fan_watchdog_task); | ||
1957 | |||
1958 | if (fan_watchdog_maxinterval > 0) { | ||
1959 | fan_watchdog_active = 1; | ||
1960 | if (!schedule_delayed_work(&fan_watchdog_task, | ||
1961 | msecs_to_jiffies(fan_watchdog_maxinterval | ||
1962 | * 1000))) { | ||
1963 | printk(IBM_ERR "failed to schedule the fan watchdog, " | ||
1964 | "watchdog will not trigger\n"); | ||
1965 | } | ||
1966 | } else | ||
1967 | fan_watchdog_active = 0; | ||
1968 | } | ||
1969 | |||
1937 | static int fan_read(char *p) | 1970 | static int fan_read(char *p) |
1938 | { | 1971 | { |
1939 | int len = 0; | 1972 | int len = 0; |
@@ -2007,7 +2040,9 @@ static int fan_read(char *p) | |||
2007 | } | 2040 | } |
2008 | 2041 | ||
2009 | if (fan_control_commands & IBMACPI_FAN_CMD_ENABLE) | 2042 | if (fan_control_commands & IBMACPI_FAN_CMD_ENABLE) |
2010 | len += sprintf(p + len, "commands:\tenable, disable\n"); | 2043 | len += sprintf(p + len, "commands:\tenable, disable\n" |
2044 | "commands:\twatchdog <timeout> (<timeout> is 0 (off), " | ||
2045 | "1-120 (seconds))\n"); | ||
2011 | 2046 | ||
2012 | if (fan_control_commands & IBMACPI_FAN_CMD_SPEED) | 2047 | if (fan_control_commands & IBMACPI_FAN_CMD_SPEED) |
2013 | len += sprintf(p + len, "commands:\tspeed <speed>" | 2048 | len += sprintf(p + len, "commands:\tspeed <speed>" |
@@ -2186,6 +2221,21 @@ static int fan_write_cmd_speed(const char *cmd, int *rc) | |||
2186 | return 1; | 2221 | return 1; |
2187 | } | 2222 | } |
2188 | 2223 | ||
2224 | static int fan_write_cmd_watchdog(const char *cmd, int *rc) | ||
2225 | { | ||
2226 | int interval; | ||
2227 | |||
2228 | if (sscanf(cmd, "watchdog %d", &interval) != 1) | ||
2229 | return 0; | ||
2230 | |||
2231 | if (interval < 0 || interval > 120) | ||
2232 | *rc = -EINVAL; | ||
2233 | else | ||
2234 | fan_watchdog_maxinterval = interval; | ||
2235 | |||
2236 | return 1; | ||
2237 | } | ||
2238 | |||
2189 | static int fan_write(char *buf) | 2239 | static int fan_write(char *buf) |
2190 | { | 2240 | { |
2191 | char *cmd; | 2241 | char *cmd; |
@@ -2196,16 +2246,29 @@ static int fan_write(char *buf) | |||
2196 | fan_write_cmd_level(cmd, &rc)) && | 2246 | fan_write_cmd_level(cmd, &rc)) && |
2197 | !((fan_control_commands & IBMACPI_FAN_CMD_ENABLE) && | 2247 | !((fan_control_commands & IBMACPI_FAN_CMD_ENABLE) && |
2198 | (fan_write_cmd_enable(cmd, &rc) || | 2248 | (fan_write_cmd_enable(cmd, &rc) || |
2199 | fan_write_cmd_disable(cmd, &rc))) && | 2249 | fan_write_cmd_disable(cmd, &rc) || |
2250 | fan_write_cmd_watchdog(cmd, &rc))) && | ||
2200 | !((fan_control_commands & IBMACPI_FAN_CMD_SPEED) && | 2251 | !((fan_control_commands & IBMACPI_FAN_CMD_SPEED) && |
2201 | fan_write_cmd_speed(cmd, &rc)) | 2252 | fan_write_cmd_speed(cmd, &rc)) |
2202 | ) | 2253 | ) |
2203 | rc = -EINVAL; | 2254 | rc = -EINVAL; |
2255 | else if (!rc) | ||
2256 | fan_watchdog_reset(); | ||
2204 | } | 2257 | } |
2205 | 2258 | ||
2206 | return rc; | 2259 | return rc; |
2207 | } | 2260 | } |
2208 | 2261 | ||
2262 | static void fan_watchdog_fire(void *ignored) | ||
2263 | { | ||
2264 | printk(IBM_NOTICE "fan watchdog: enabling fan\n"); | ||
2265 | if (fan_set_enable()) { | ||
2266 | printk(IBM_ERR "fan watchdog: error while enabling fan\n"); | ||
2267 | /* reschedule for later */ | ||
2268 | fan_watchdog_reset(); | ||
2269 | } | ||
2270 | } | ||
2271 | |||
2209 | static struct ibm_struct ibms[] = { | 2272 | static struct ibm_struct ibms[] = { |
2210 | { | 2273 | { |
2211 | .name = "driver", | 2274 | .name = "driver", |
@@ -2317,6 +2380,7 @@ static struct ibm_struct ibms[] = { | |||
2317 | .read = fan_read, | 2380 | .read = fan_read, |
2318 | .write = fan_write, | 2381 | .write = fan_write, |
2319 | .init = fan_init, | 2382 | .init = fan_init, |
2383 | .exit = fan_exit, | ||
2320 | .experimental = 1, | 2384 | .experimental = 1, |
2321 | }, | 2385 | }, |
2322 | }; | 2386 | }; |