aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/acpi/ibm_acpi.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/acpi/ibm_acpi.c')
-rw-r--r--drivers/acpi/ibm_acpi.c70
1 files changed, 67 insertions, 3 deletions
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 {
348enum fan_control_commands { 350enum 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
354enum { /* Fan control constants */ 357enum { /* Fan control constants */
@@ -1797,12 +1800,17 @@ static enum fan_control_commands fan_control_commands;
1797static int fan_control_status_known; 1800static int fan_control_status_known;
1798static u8 fan_control_initial_status; 1801static u8 fan_control_initial_status;
1799 1802
1803static void fan_watchdog_fire(void *ignored);
1804static int fan_watchdog_maxinterval;
1805static DECLARE_WORK(fan_watchdog_task, fan_watchdog_fire, NULL);
1806
1800static int fan_init(void) 1807static 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
1945static void fan_exit(void)
1946{
1947 cancel_delayed_work(&fan_watchdog_task);
1948 flush_scheduled_work();
1949}
1950
1951static 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
1937static int fan_read(char *p) 1970static 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
2224static 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
2189static int fan_write(char *buf) 2239static 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
2262static 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
2209static struct ibm_struct ibms[] = { 2272static 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};