IB/ipath: Remove unused MDIO interface code
[safe/jmp/linux-2.6] / drivers / acpi / thermal.c
index 57d05ff..5f79b44 100644 (file)
@@ -33,6 +33,7 @@
 
 #include <linux/kernel.h>
 #include <linux/module.h>
+#include <linux/dmi.h>
 #include <linux/init.h>
 #include <linux/types.h>
 #include <linux/proc_fs.h>
@@ -74,21 +75,29 @@ MODULE_AUTHOR("Paul Diefenbaugh");
 MODULE_DESCRIPTION("ACPI Thermal Zone Driver");
 MODULE_LICENSE("GPL");
 
+static int act;
+module_param(act, int, 0644);
+MODULE_PARM_DESC(act, "Disable or override all lowest active trip points.");
+
+static int crt;
+module_param(crt, int, 0644);
+MODULE_PARM_DESC(crt, "Disable or lower all critical trip points.");
+
 static int tzp;
 module_param(tzp, int, 0444);
-MODULE_PARM_DESC(tzp, "Thermal zone polling frequency, in 1/10 seconds.\n");
+MODULE_PARM_DESC(tzp, "Thermal zone polling frequency, in 1/10 seconds.");
 
 static int nocrt;
 module_param(nocrt, int, 0);
-MODULE_PARM_DESC(nocrt, "Set to disable action on ACPI thermal zone critical and hot trips.\n");
+MODULE_PARM_DESC(nocrt, "Set to take no action upon ACPI thermal zone critical trips points.");
 
 static int off;
 module_param(off, int, 0);
-MODULE_PARM_DESC(off, "Set to disable ACPI thermal support.\n");
+MODULE_PARM_DESC(off, "Set to disable ACPI thermal support.");
 
 static int psv;
 module_param(psv, int, 0644);
-MODULE_PARM_DESC(psv, "Disable or override all passive trip points.\n");
+MODULE_PARM_DESC(psv, "Disable or override all passive trip points.");
 
 static int acpi_thermal_add(struct acpi_device *device);
 static int acpi_thermal_remove(struct acpi_device *device, int type);
@@ -186,6 +195,7 @@ struct acpi_thermal {
        struct acpi_thermal_trips trips;
        struct acpi_handle_list devices;
        struct timer_list timer;
+       struct mutex lock;
 };
 
 static const struct file_operations acpi_thermal_state_fops = {
@@ -335,6 +345,20 @@ static int acpi_thermal_get_trip_points(struct acpi_thermal *tz)
                                  tz->trips.critical.temperature));
        }
 
+       if (tz->trips.critical.flags.valid == 1) {
+               if (crt == -1) {
+                       tz->trips.critical.flags.valid = 0;
+               } else if (crt > 0) {
+                       unsigned long crt_k = CELSIUS_TO_KELVIN(crt);
+
+                       /*
+                        * Allow override to lower critical threshold
+                        */
+                       if (crt_k < tz->trips.critical.temperature)
+                               tz->trips.critical.temperature = crt_k;
+               }
+       }
+
        /* Critical Sleep (optional) */
 
        status =
@@ -405,11 +429,33 @@ static int acpi_thermal_get_trip_points(struct acpi_thermal *tz)
 
                char name[5] = { '_', 'A', 'C', ('0' + i), '\0' };
 
-               status =
-                   acpi_evaluate_integer(tz->device->handle, name, NULL,
-                                         &tz->trips.active[i].temperature);
-               if (ACPI_FAILURE(status))
+               if (act == -1)
+                       break;  /* disable all active trip points */
+
+               status = acpi_evaluate_integer(tz->device->handle,
+                       name, NULL, &tz->trips.active[i].temperature);
+
+               if (ACPI_FAILURE(status)) {
+                       if (i == 0)     /* no active trip points */
+                               break;
+                       if (act <= 0)   /* no override requested */
+                               break;
+                       if (i == 1) {   /* 1 trip point */
+                               tz->trips.active[0].temperature =
+                                       CELSIUS_TO_KELVIN(act);
+                       } else {        /* multiple trips */
+                               /*
+                                * Don't allow override higher than
+                                * the next higher trip point
+                                */
+                               tz->trips.active[i - 1].temperature =
+                                   (tz->trips.active[i - 2].temperature <
+                                       CELSIUS_TO_KELVIN(act) ?
+                                       tz->trips.active[i - 2].temperature :
+                                       CELSIUS_TO_KELVIN(act));
+                       }
                        break;
+               }
 
                name[2] = 'L';
                status =
@@ -458,8 +504,12 @@ static int acpi_thermal_critical(struct acpi_thermal *tz)
        printk(KERN_EMERG
               "Critical temperature reached (%ld C), shutting down.\n",
               KELVIN_TO_CELSIUS(tz->temperature));
-       acpi_bus_generate_event(tz->device, ACPI_THERMAL_NOTIFY_CRITICAL,
+       acpi_bus_generate_proc_event(tz->device, ACPI_THERMAL_NOTIFY_CRITICAL,
                                tz->trips.critical.flags.enabled);
+       acpi_bus_generate_netlink_event(tz->device->pnp.device_class,
+                                         tz->device->dev.bus_id,
+                                         ACPI_THERMAL_NOTIFY_CRITICAL,
+                                         tz->trips.critical.flags.enabled);
 
        orderly_poweroff(true);
 
@@ -477,8 +527,12 @@ static int acpi_thermal_hot(struct acpi_thermal *tz)
        } else if (tz->trips.hot.flags.enabled)
                tz->trips.hot.flags.enabled = 0;
 
-       acpi_bus_generate_event(tz->device, ACPI_THERMAL_NOTIFY_HOT,
+       acpi_bus_generate_proc_event(tz->device, ACPI_THERMAL_NOTIFY_HOT,
                                tz->trips.hot.flags.enabled);
+       acpi_bus_generate_netlink_event(tz->device->pnp.device_class,
+                                         tz->device->dev.bus_id,
+                                         ACPI_THERMAL_NOTIFY_HOT,
+                                         tz->trips.hot.flags.enabled);
 
        /* TBD: Call user-mode "sleep(S4)" function */
 
@@ -658,6 +712,7 @@ static void acpi_thermal_check(void *data)
        int result = 0;
        struct acpi_thermal *tz = data;
        unsigned long sleep_time = 0;
+       unsigned long timeout_jiffies = 0;
        int i = 0;
        struct acpi_thermal_state state;
 
@@ -667,11 +722,15 @@ static void acpi_thermal_check(void *data)
                return;
        }
 
+       /* Check if someone else is already running */
+       if (!mutex_trylock(&tz->lock))
+               return;
+
        state = tz->state;
 
        result = acpi_thermal_get_temperature(tz);
        if (result)
-               return;
+               goto unlock;
 
        memset(&tz->state, 0, sizeof(tz->state));
 
@@ -734,10 +793,13 @@ static void acpi_thermal_check(void *data)
         * a thermal event occurs).  Note that _TSP and _TZD values are
         * given in 1/10th seconds (we must covert to milliseconds).
         */
-       if (tz->state.passive)
+       if (tz->state.passive) {
                sleep_time = tz->trips.passive.tsp * 100;
-       else if (tz->polling_frequency > 0)
+               timeout_jiffies =  jiffies + (HZ * sleep_time) / 1000;
+       } else if (tz->polling_frequency > 0) {
                sleep_time = tz->polling_frequency * 100;
+               timeout_jiffies =  round_jiffies(jiffies + (HZ * sleep_time) / 1000);
+       }
 
        ACPI_DEBUG_PRINT((ACPI_DB_INFO, "%s: temperature[%lu] sleep[%lu]\n",
                          tz->name, tz->temperature, sleep_time));
@@ -751,17 +813,16 @@ static void acpi_thermal_check(void *data)
                        del_timer(&(tz->timer));
        } else {
                if (timer_pending(&(tz->timer)))
-                       mod_timer(&(tz->timer),
-                                       jiffies + (HZ * sleep_time) / 1000);
+                       mod_timer(&(tz->timer), timeout_jiffies);
                else {
                        tz->timer.data = (unsigned long)tz;
                        tz->timer.function = acpi_thermal_run;
-                       tz->timer.expires = jiffies + (HZ * sleep_time) / 1000;
+                       tz->timer.expires = timeout_jiffies;
                        add_timer(&(tz->timer));
                }
        }
-
-       return;
+      unlock:
+       mutex_unlock(&tz->lock);
 }
 
 /* --------------------------------------------------------------------------
@@ -1040,9 +1101,9 @@ static int acpi_thermal_add_fs(struct acpi_device *device)
                entry->owner = THIS_MODULE;
        }
 
-       /* 'trip_points' [R/W] */
+       /* 'trip_points' [R] */
        entry = create_proc_entry(ACPI_THERMAL_FILE_TRIP_POINTS,
-                                 S_IFREG | S_IRUGO | S_IWUSR,
+                                 S_IRUGO,
                                  acpi_device_dir(device));
        if (!entry)
                return -ENODEV;
@@ -1122,12 +1183,16 @@ static void acpi_thermal_notify(acpi_handle handle, u32 event, void *data)
        case ACPI_THERMAL_NOTIFY_THRESHOLDS:
                acpi_thermal_get_trip_points(tz);
                acpi_thermal_check(tz);
-               acpi_bus_generate_event(device, event, 0);
+               acpi_bus_generate_proc_event(device, event, 0);
+               acpi_bus_generate_netlink_event(device->pnp.device_class,
+                                                 device->dev.bus_id, event, 0);
                break;
        case ACPI_THERMAL_NOTIFY_DEVICES:
                if (tz->flags.devices)
                        acpi_thermal_get_devices(tz);
-               acpi_bus_generate_event(device, event, 0);
+               acpi_bus_generate_proc_event(device, event, 0);
+               acpi_bus_generate_netlink_event(device->pnp.device_class,
+                                                 device->dev.bus_id, event, 0);
                break;
        default:
                ACPI_DEBUG_PRINT((ACPI_DB_INFO,
@@ -1194,7 +1259,7 @@ static int acpi_thermal_add(struct acpi_device *device)
        strcpy(acpi_device_name(device), ACPI_THERMAL_DEVICE_NAME);
        strcpy(acpi_device_class(device), ACPI_THERMAL_CLASS);
        acpi_driver_data(device) = tz;
-
+       mutex_init(&tz->lock);
        result = acpi_thermal_get_info(tz);
        if (result)
                goto end;
@@ -1264,7 +1329,7 @@ static int acpi_thermal_remove(struct acpi_device *device, int type)
        }
 
        acpi_thermal_remove_fs(device);
-
+       mutex_destroy(&tz->lock);
        kfree(tz);
        return 0;
 }
@@ -1302,10 +1367,89 @@ static int acpi_thermal_resume(struct acpi_device *device)
        return AE_OK;
 }
 
+#ifdef CONFIG_DMI
+static int thermal_act(const struct dmi_system_id *d) {
+
+       if (act == 0) {
+               printk(KERN_NOTICE "ACPI: %s detected: "
+                       "disabling all active thermal trip points\n", d->ident);
+               act = -1;
+       }
+       return 0;
+}
+static int thermal_nocrt(const struct dmi_system_id *d) {
+
+       printk(KERN_NOTICE "ACPI: %s detected: "
+               "disabling all critical thermal trip point actions.\n", d->ident);
+       nocrt = 1;
+       return 0;
+}
+static int thermal_tzp(const struct dmi_system_id *d) {
+
+       if (tzp == 0) {
+               printk(KERN_NOTICE "ACPI: %s detected: "
+                       "enabling thermal zone polling\n", d->ident);
+               tzp = 300;      /* 300 dS = 30 Seconds */
+       }
+       return 0;
+}
+static int thermal_psv(const struct dmi_system_id *d) {
+
+       if (psv == 0) {
+               printk(KERN_NOTICE "ACPI: %s detected: "
+                       "disabling all passive thermal trip points\n", d->ident);
+               psv = -1;
+       }
+       return 0;
+}
+
+static struct dmi_system_id thermal_dmi_table[] __initdata = {
+       /*
+        * Award BIOS on this AOpen makes thermal control almost worthless.
+        * http://bugzilla.kernel.org/show_bug.cgi?id=8842
+        */
+       {
+        .callback = thermal_act,
+        .ident = "AOpen i915GMm-HFS",
+        .matches = {
+               DMI_MATCH(DMI_BOARD_VENDOR, "AOpen"),
+               DMI_MATCH(DMI_BOARD_NAME, "i915GMm-HFS"),
+               },
+       },
+       {
+        .callback = thermal_psv,
+        .ident = "AOpen i915GMm-HFS",
+        .matches = {
+               DMI_MATCH(DMI_BOARD_VENDOR, "AOpen"),
+               DMI_MATCH(DMI_BOARD_NAME, "i915GMm-HFS"),
+               },
+       },
+       {
+        .callback = thermal_tzp,
+        .ident = "AOpen i915GMm-HFS",
+        .matches = {
+               DMI_MATCH(DMI_BOARD_VENDOR, "AOpen"),
+               DMI_MATCH(DMI_BOARD_NAME, "i915GMm-HFS"),
+               },
+       },
+       {
+        .callback = thermal_nocrt,
+        .ident = "Gigabyte GA-7ZX",
+        .matches = {
+               DMI_MATCH(DMI_BOARD_VENDOR, "Gigabyte Technology Co., Ltd."),
+               DMI_MATCH(DMI_BOARD_NAME, "7ZX"),
+               },
+       },
+       {}
+};
+#endif /* CONFIG_DMI */
+
 static int __init acpi_thermal_init(void)
 {
        int result = 0;
 
+       dmi_check_system(thermal_dmi_table);
+
        if (off) {
                printk(KERN_NOTICE "ACPI: thermal control disabled\n");
                return -ENODEV;