2  * Windfarm PowerMac thermal control. Core
 
   4  * (c) Copyright 2005 Benjamin Herrenschmidt, IBM Corp.
 
   5  *                    <benh@kernel.crashing.org>
 
   7  * Released under the term of the GNU GPL v2.
 
   9  * This core code tracks the list of sensors & controls, register
 
  10  * clients, and holds the kernel thread used for control.
 
  14  * Add some information about sensor/control type and data format to
 
  15  * sensors/controls, and have the sysfs attribute stuff be moved
 
  16  * generically here instead of hard coded in the platform specific
 
  17  * driver as it us currently
 
  19  * This however requires solving some annoying lifetime issues with
 
  20  * sysfs which doesn't seem to have lifetime rules for struct attribute,
 
  21  * I may have to create full features kobjects for every sensor/control
 
  22  * instead which is a bit of an overkill imho
 
  25 #include <linux/types.h>
 
  26 #include <linux/errno.h>
 
  27 #include <linux/kernel.h>
 
  28 #include <linux/init.h>
 
  29 #include <linux/spinlock.h>
 
  30 #include <linux/kthread.h>
 
  31 #include <linux/jiffies.h>
 
  32 #include <linux/reboot.h>
 
  33 #include <linux/device.h>
 
  34 #include <linux/platform_device.h>
 
  35 #include <linux/mutex.h>
 
  36 #include <linux/freezer.h>
 
  47 #define DBG(args...)    printk(args)
 
  49 #define DBG(args...)    do { } while(0)
 
  52 static LIST_HEAD(wf_controls);
 
  53 static LIST_HEAD(wf_sensors);
 
  54 static DEFINE_MUTEX(wf_lock);
 
  55 static BLOCKING_NOTIFIER_HEAD(wf_client_list);
 
  56 static int wf_client_count;
 
  57 static unsigned int wf_overtemp;
 
  58 static unsigned int wf_overtemp_counter;
 
  59 struct task_struct *wf_thread;
 
  61 static struct platform_device wf_platform_device = {
 
  66  * Utilities & tick thread
 
  69 static inline void wf_notify(int event, void *param)
 
  71         blocking_notifier_call_chain(&wf_client_list, event, param);
 
  74 int wf_critical_overtemp(void)
 
  76         static char * critical_overtemp_path = "/sbin/critical_overtemp";
 
  77         char *argv[] = { critical_overtemp_path, NULL };
 
  78         static char *envp[] = { "HOME=/",
 
  80                                 "PATH=/sbin:/usr/sbin:/bin:/usr/bin",
 
  83         return call_usermodehelper(critical_overtemp_path,
 
  84                                    argv, envp, UMH_WAIT_EXEC);
 
  86 EXPORT_SYMBOL_GPL(wf_critical_overtemp);
 
  88 static int wf_thread_func(void *data)
 
  90         unsigned long next, delay;
 
  94         DBG("wf: thread started\n");
 
  97         while (!kthread_should_stop()) {
 
 100                 if (time_after_eq(jiffies, next)) {
 
 101                         wf_notify(WF_EVENT_TICK, NULL);
 
 103                                 wf_overtemp_counter++;
 
 104                                 /* 10 seconds overtemp, notify userland */
 
 105                                 if (wf_overtemp_counter > 10)
 
 106                                         wf_critical_overtemp();
 
 107                                 /* 30 seconds, shutdown */
 
 108                                 if (wf_overtemp_counter > 30) {
 
 109                                         printk(KERN_ERR "windfarm: Overtemp "
 
 111                                                " seconds, shutting down\n");
 
 118                 delay = next - jiffies;
 
 120                         schedule_timeout_interruptible(delay);
 
 123         DBG("wf: thread stopped\n");
 
 128 static void wf_start_thread(void)
 
 130         wf_thread = kthread_run(wf_thread_func, NULL, "kwindfarm");
 
 131         if (IS_ERR(wf_thread)) {
 
 132                 printk(KERN_ERR "windfarm: failed to create thread,err %ld\n",
 
 139 static void wf_stop_thread(void)
 
 142                 kthread_stop(wf_thread);
 
 150 static void wf_control_release(struct kref *kref)
 
 152         struct wf_control *ct = container_of(kref, struct wf_control, ref);
 
 154         DBG("wf: Deleting control %s\n", ct->name);
 
 156         if (ct->ops && ct->ops->release)
 
 157                 ct->ops->release(ct);
 
 162 static ssize_t wf_show_control(struct device *dev,
 
 163                                struct device_attribute *attr, char *buf)
 
 165         struct wf_control *ctrl = container_of(attr, struct wf_control, attr);
 
 169         err = ctrl->ops->get_value(ctrl, &val);
 
 172         return sprintf(buf, "%d\n", val);
 
 175 /* This is really only for debugging... */
 
 176 static ssize_t wf_store_control(struct device *dev,
 
 177                                 struct device_attribute *attr,
 
 178                                 const char *buf, size_t count)
 
 180         struct wf_control *ctrl = container_of(attr, struct wf_control, attr);
 
 185         val = simple_strtoul(buf, &endp, 0);
 
 186         while (endp < buf + count && (*endp == ' ' || *endp == '\n'))
 
 188         if (endp - buf < count)
 
 190         err = ctrl->ops->set_value(ctrl, val);
 
 196 int wf_register_control(struct wf_control *new_ct)
 
 198         struct wf_control *ct;
 
 200         mutex_lock(&wf_lock);
 
 201         list_for_each_entry(ct, &wf_controls, link) {
 
 202                 if (!strcmp(ct->name, new_ct->name)) {
 
 203                         printk(KERN_WARNING "windfarm: trying to register"
 
 204                                " duplicate control %s\n", ct->name);
 
 205                         mutex_unlock(&wf_lock);
 
 209         kref_init(&new_ct->ref);
 
 210         list_add(&new_ct->link, &wf_controls);
 
 212         new_ct->attr.attr.name = new_ct->name;
 
 213         new_ct->attr.attr.mode = 0644;
 
 214         new_ct->attr.show = wf_show_control;
 
 215         new_ct->attr.store = wf_store_control;
 
 216         if (device_create_file(&wf_platform_device.dev, &new_ct->attr))
 
 217                 printk(KERN_WARNING "windfarm: device_create_file failed"
 
 218                         " for %s\n", new_ct->name);
 
 219                 /* the subsystem still does useful work without the file */
 
 221         DBG("wf: Registered control %s\n", new_ct->name);
 
 223         wf_notify(WF_EVENT_NEW_CONTROL, new_ct);
 
 224         mutex_unlock(&wf_lock);
 
 228 EXPORT_SYMBOL_GPL(wf_register_control);
 
 230 void wf_unregister_control(struct wf_control *ct)
 
 232         mutex_lock(&wf_lock);
 
 234         mutex_unlock(&wf_lock);
 
 236         DBG("wf: Unregistered control %s\n", ct->name);
 
 238         kref_put(&ct->ref, wf_control_release);
 
 240 EXPORT_SYMBOL_GPL(wf_unregister_control);
 
 242 struct wf_control * wf_find_control(const char *name)
 
 244         struct wf_control *ct;
 
 246         mutex_lock(&wf_lock);
 
 247         list_for_each_entry(ct, &wf_controls, link) {
 
 248                 if (!strcmp(ct->name, name)) {
 
 249                         if (wf_get_control(ct))
 
 251                         mutex_unlock(&wf_lock);
 
 255         mutex_unlock(&wf_lock);
 
 258 EXPORT_SYMBOL_GPL(wf_find_control);
 
 260 int wf_get_control(struct wf_control *ct)
 
 262         if (!try_module_get(ct->ops->owner))
 
 267 EXPORT_SYMBOL_GPL(wf_get_control);
 
 269 void wf_put_control(struct wf_control *ct)
 
 271         struct module *mod = ct->ops->owner;
 
 272         kref_put(&ct->ref, wf_control_release);
 
 275 EXPORT_SYMBOL_GPL(wf_put_control);
 
 283 static void wf_sensor_release(struct kref *kref)
 
 285         struct wf_sensor *sr = container_of(kref, struct wf_sensor, ref);
 
 287         DBG("wf: Deleting sensor %s\n", sr->name);
 
 289         if (sr->ops && sr->ops->release)
 
 290                 sr->ops->release(sr);
 
 295 static ssize_t wf_show_sensor(struct device *dev,
 
 296                               struct device_attribute *attr, char *buf)
 
 298         struct wf_sensor *sens = container_of(attr, struct wf_sensor, attr);
 
 302         err = sens->ops->get_value(sens, &val);
 
 305         return sprintf(buf, "%d.%03d\n", FIX32TOPRINT(val));
 
 308 int wf_register_sensor(struct wf_sensor *new_sr)
 
 310         struct wf_sensor *sr;
 
 312         mutex_lock(&wf_lock);
 
 313         list_for_each_entry(sr, &wf_sensors, link) {
 
 314                 if (!strcmp(sr->name, new_sr->name)) {
 
 315                         printk(KERN_WARNING "windfarm: trying to register"
 
 316                                " duplicate sensor %s\n", sr->name);
 
 317                         mutex_unlock(&wf_lock);
 
 321         kref_init(&new_sr->ref);
 
 322         list_add(&new_sr->link, &wf_sensors);
 
 324         new_sr->attr.attr.name = new_sr->name;
 
 325         new_sr->attr.attr.mode = 0444;
 
 326         new_sr->attr.show = wf_show_sensor;
 
 327         new_sr->attr.store = NULL;
 
 328         if (device_create_file(&wf_platform_device.dev, &new_sr->attr))
 
 329                 printk(KERN_WARNING "windfarm: device_create_file failed"
 
 330                         " for %s\n", new_sr->name);
 
 331                 /* the subsystem still does useful work without the file */
 
 333         DBG("wf: Registered sensor %s\n", new_sr->name);
 
 335         wf_notify(WF_EVENT_NEW_SENSOR, new_sr);
 
 336         mutex_unlock(&wf_lock);
 
 340 EXPORT_SYMBOL_GPL(wf_register_sensor);
 
 342 void wf_unregister_sensor(struct wf_sensor *sr)
 
 344         mutex_lock(&wf_lock);
 
 346         mutex_unlock(&wf_lock);
 
 348         DBG("wf: Unregistered sensor %s\n", sr->name);
 
 352 EXPORT_SYMBOL_GPL(wf_unregister_sensor);
 
 354 struct wf_sensor * wf_find_sensor(const char *name)
 
 356         struct wf_sensor *sr;
 
 358         mutex_lock(&wf_lock);
 
 359         list_for_each_entry(sr, &wf_sensors, link) {
 
 360                 if (!strcmp(sr->name, name)) {
 
 361                         if (wf_get_sensor(sr))
 
 363                         mutex_unlock(&wf_lock);
 
 367         mutex_unlock(&wf_lock);
 
 370 EXPORT_SYMBOL_GPL(wf_find_sensor);
 
 372 int wf_get_sensor(struct wf_sensor *sr)
 
 374         if (!try_module_get(sr->ops->owner))
 
 379 EXPORT_SYMBOL_GPL(wf_get_sensor);
 
 381 void wf_put_sensor(struct wf_sensor *sr)
 
 383         struct module *mod = sr->ops->owner;
 
 384         kref_put(&sr->ref, wf_sensor_release);
 
 387 EXPORT_SYMBOL_GPL(wf_put_sensor);
 
 391  * Client & notification
 
 394 int wf_register_client(struct notifier_block *nb)
 
 397         struct wf_control *ct;
 
 398         struct wf_sensor *sr;
 
 400         mutex_lock(&wf_lock);
 
 401         rc = blocking_notifier_chain_register(&wf_client_list, nb);
 
 405         list_for_each_entry(ct, &wf_controls, link)
 
 406                 wf_notify(WF_EVENT_NEW_CONTROL, ct);
 
 407         list_for_each_entry(sr, &wf_sensors, link)
 
 408                 wf_notify(WF_EVENT_NEW_SENSOR, sr);
 
 409         if (wf_client_count == 1)
 
 412         mutex_unlock(&wf_lock);
 
 415 EXPORT_SYMBOL_GPL(wf_register_client);
 
 417 int wf_unregister_client(struct notifier_block *nb)
 
 419         mutex_lock(&wf_lock);
 
 420         blocking_notifier_chain_unregister(&wf_client_list, nb);
 
 422         if (wf_client_count == 0)
 
 424         mutex_unlock(&wf_lock);
 
 428 EXPORT_SYMBOL_GPL(wf_unregister_client);
 
 430 void wf_set_overtemp(void)
 
 432         mutex_lock(&wf_lock);
 
 434         if (wf_overtemp == 1) {
 
 435                 printk(KERN_WARNING "windfarm: Overtemp condition detected !\n");
 
 436                 wf_overtemp_counter = 0;
 
 437                 wf_notify(WF_EVENT_OVERTEMP, NULL);
 
 439         mutex_unlock(&wf_lock);
 
 441 EXPORT_SYMBOL_GPL(wf_set_overtemp);
 
 443 void wf_clear_overtemp(void)
 
 445         mutex_lock(&wf_lock);
 
 446         WARN_ON(wf_overtemp == 0);
 
 447         if (wf_overtemp == 0) {
 
 448                 mutex_unlock(&wf_lock);
 
 452         if (wf_overtemp == 0) {
 
 453                 printk(KERN_WARNING "windfarm: Overtemp condition cleared !\n");
 
 454                 wf_notify(WF_EVENT_NORMALTEMP, NULL);
 
 456         mutex_unlock(&wf_lock);
 
 458 EXPORT_SYMBOL_GPL(wf_clear_overtemp);
 
 460 int wf_is_overtemp(void)
 
 462         return (wf_overtemp != 0);
 
 464 EXPORT_SYMBOL_GPL(wf_is_overtemp);
 
 466 static int __init windfarm_core_init(void)
 
 468         DBG("wf: core loaded\n");
 
 470         /* Don't register on old machines that use therm_pm72 for now */
 
 471         if (machine_is_compatible("PowerMac7,2") ||
 
 472             machine_is_compatible("PowerMac7,3") ||
 
 473             machine_is_compatible("RackMac3,1"))
 
 475         platform_device_register(&wf_platform_device);
 
 479 static void __exit windfarm_core_exit(void)
 
 481         BUG_ON(wf_client_count != 0);
 
 483         DBG("wf: core unloaded\n");
 
 485         platform_device_unregister(&wf_platform_device);
 
 489 module_init(windfarm_core_init);
 
 490 module_exit(windfarm_core_exit);
 
 492 MODULE_AUTHOR("Benjamin Herrenschmidt <benh@kernel.crashing.org>");
 
 493 MODULE_DESCRIPTION("Core component of PowerMac thermal control");
 
 494 MODULE_LICENSE("GPL");