aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
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
commit16663a87ad1df7022661bc8813b7a2e84e7f5e66 (patch)
treed78d869332bdfa8a5859134114eb145eb41b5dd3 /drivers
parent778b4d742b210b9cac31f223527f30f1fc70312b (diff)
ACPI: ibm-acpi: implement fan watchdog command
This patch implements a fan control safety watchdog, by request of the authors of userspace fan control scripts. When the watchdog timer expires, the equivalent action of a "fan enable" command is executed. The watchdog timer is reset at every reception of a fan control command that could change the state of the fan itself. This command is meant to be used by userspace fan control daemons, to make sure the fan is never left set to an unsafe level because of userspace problems. Users of the X31/X40/X41 "speed" command are on their own, the current implementation of "speed" is just too incomplete to be used safely, anyway. Better to never use it, and just use the "level" command instead. The watchdog is programmed using echo "watchdog <number>" > fan, where number is the number of seconds to wait before doing an "enable", and zero disables the watchdog. Signed-off-by: Henrique de Moraes Holschuh <hmh@hmh.eng.br>
Diffstat (limited to 'drivers')
-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};