1 /* 2 * Windfarm PowerMac thermal control. Core 3 * 4 * (c) Copyright 2005 Benjamin Herrenschmidt, IBM Corp. 5 * <benh@kernel.crashing.org> 6 * 7 * Released under the term of the GNU GPL v2. 8 * 9 * This core code tracks the list of sensors & controls, register 10 * clients, and holds the kernel thread used for control. 11 * 12 * TODO: 13 * 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 18 * 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 23 */ 24 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> 37 38 #include <asm/prom.h> 39 40 #include "windfarm.h" 41 42 #define VERSION "0.2" 43 44 #undef DEBUG 45 46 #ifdef DEBUG 47 #define DBG(args...) printk(args) 48 #else 49 #define DBG(args...) do { } while(0) 50 #endif 51 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; 60 61 static struct platform_device wf_platform_device = { 62 .name = "windfarm", 63 }; 64 65 /* 66 * Utilities & tick thread 67 */ 68 69 static inline void wf_notify(int event, void *param) 70 { 71 blocking_notifier_call_chain(&wf_client_list, event, param); 72 } 73 74 int wf_critical_overtemp(void) 75 { 76 static char * critical_overtemp_path = "/sbin/critical_overtemp"; 77 char *argv[] = { critical_overtemp_path, NULL }; 78 static char *envp[] = { "HOME=/", 79 "TERM=linux", 80 "PATH=/sbin:/usr/sbin:/bin:/usr/bin", 81 NULL }; 82 83 return call_usermodehelper(critical_overtemp_path, argv, envp, 0); 84 } 85 EXPORT_SYMBOL_GPL(wf_critical_overtemp); 86 87 static int wf_thread_func(void *data) 88 { 89 unsigned long next, delay; 90 91 next = jiffies; 92 93 DBG("wf: thread started\n"); 94 95 while(!kthread_should_stop()) { 96 if (time_after_eq(jiffies, next)) { 97 wf_notify(WF_EVENT_TICK, NULL); 98 if (wf_overtemp) { 99 wf_overtemp_counter++; 100 /* 10 seconds overtemp, notify userland */ 101 if (wf_overtemp_counter > 10) 102 wf_critical_overtemp(); 103 /* 30 seconds, shutdown */ 104 if (wf_overtemp_counter > 30) { 105 printk(KERN_ERR "windfarm: Overtemp " 106 "for more than 30" 107 " seconds, shutting down\n"); 108 machine_power_off(); 109 } 110 } 111 next += HZ; 112 } 113 114 delay = next - jiffies; 115 if (delay <= HZ) 116 schedule_timeout_interruptible(delay); 117 118 /* there should be no non-suspend signal, but oh well */ 119 if (signal_pending(current) && !try_to_freeze()) { 120 printk(KERN_WARNING "windfarm: thread got sigl !\n"); 121 break; 122 } 123 } 124 125 DBG("wf: thread stopped\n"); 126 127 return 0; 128 } 129 130 static void wf_start_thread(void) 131 { 132 wf_thread = kthread_run(wf_thread_func, NULL, "kwindfarm"); 133 if (IS_ERR(wf_thread)) { 134 printk(KERN_ERR "windfarm: failed to create thread,err %ld\n", 135 PTR_ERR(wf_thread)); 136 wf_thread = NULL; 137 } 138 } 139 140 141 static void wf_stop_thread(void) 142 { 143 if (wf_thread) 144 kthread_stop(wf_thread); 145 wf_thread = NULL; 146 } 147 148 /* 149 * Controls 150 */ 151 152 static void wf_control_release(struct kref *kref) 153 { 154 struct wf_control *ct = container_of(kref, struct wf_control, ref); 155 156 DBG("wf: Deleting control %s\n", ct->name); 157 158 if (ct->ops && ct->ops->release) 159 ct->ops->release(ct); 160 else 161 kfree(ct); 162 } 163 164 static ssize_t wf_show_control(struct device *dev, 165 struct device_attribute *attr, char *buf) 166 { 167 struct wf_control *ctrl = container_of(attr, struct wf_control, attr); 168 s32 val = 0; 169 int err; 170 171 err = ctrl->ops->get_value(ctrl, &val); 172 if (err < 0) 173 return err; 174 return sprintf(buf, "%d\n", val); 175 } 176 177 /* This is really only for debugging... */ 178 static ssize_t wf_store_control(struct device *dev, 179 struct device_attribute *attr, 180 const char *buf, size_t count) 181 { 182 struct wf_control *ctrl = container_of(attr, struct wf_control, attr); 183 int val; 184 int err; 185 char *endp; 186 187 val = simple_strtoul(buf, &endp, 0); 188 while (endp < buf + count && (*endp == ' ' || *endp == '\n')) 189 ++endp; 190 if (endp - buf < count) 191 return -EINVAL; 192 err = ctrl->ops->set_value(ctrl, val); 193 if (err < 0) 194 return err; 195 return count; 196 } 197 198 int wf_register_control(struct wf_control *new_ct) 199 { 200 struct wf_control *ct; 201 202 mutex_lock(&wf_lock); 203 list_for_each_entry(ct, &wf_controls, link) { 204 if (!strcmp(ct->name, new_ct->name)) { 205 printk(KERN_WARNING "windfarm: trying to register" 206 " duplicate control %s\n", ct->name); 207 mutex_unlock(&wf_lock); 208 return -EEXIST; 209 } 210 } 211 kref_init(&new_ct->ref); 212 list_add(&new_ct->link, &wf_controls); 213 214 new_ct->attr.attr.name = new_ct->name; 215 new_ct->attr.attr.owner = THIS_MODULE; 216 new_ct->attr.attr.mode = 0644; 217 new_ct->attr.show = wf_show_control; 218 new_ct->attr.store = wf_store_control; 219 if (device_create_file(&wf_platform_device.dev, &new_ct->attr)) 220 printk(KERN_WARNING "windfarm: device_create_file failed" 221 " for %s\n", new_ct->name); 222 /* the subsystem still does useful work without the file */ 223 224 DBG("wf: Registered control %s\n", new_ct->name); 225 226 wf_notify(WF_EVENT_NEW_CONTROL, new_ct); 227 mutex_unlock(&wf_lock); 228 229 return 0; 230 } 231 EXPORT_SYMBOL_GPL(wf_register_control); 232 233 void wf_unregister_control(struct wf_control *ct) 234 { 235 mutex_lock(&wf_lock); 236 list_del(&ct->link); 237 mutex_unlock(&wf_lock); 238 239 DBG("wf: Unregistered control %s\n", ct->name); 240 241 kref_put(&ct->ref, wf_control_release); 242 } 243 EXPORT_SYMBOL_GPL(wf_unregister_control); 244 245 struct wf_control * wf_find_control(const char *name) 246 { 247 struct wf_control *ct; 248 249 mutex_lock(&wf_lock); 250 list_for_each_entry(ct, &wf_controls, link) { 251 if (!strcmp(ct->name, name)) { 252 if (wf_get_control(ct)) 253 ct = NULL; 254 mutex_unlock(&wf_lock); 255 return ct; 256 } 257 } 258 mutex_unlock(&wf_lock); 259 return NULL; 260 } 261 EXPORT_SYMBOL_GPL(wf_find_control); 262 263 int wf_get_control(struct wf_control *ct) 264 { 265 if (!try_module_get(ct->ops->owner)) 266 return -ENODEV; 267 kref_get(&ct->ref); 268 return 0; 269 } 270 EXPORT_SYMBOL_GPL(wf_get_control); 271 272 void wf_put_control(struct wf_control *ct) 273 { 274 struct module *mod = ct->ops->owner; 275 kref_put(&ct->ref, wf_control_release); 276 module_put(mod); 277 } 278 EXPORT_SYMBOL_GPL(wf_put_control); 279 280 281 /* 282 * Sensors 283 */ 284 285 286 static void wf_sensor_release(struct kref *kref) 287 { 288 struct wf_sensor *sr = container_of(kref, struct wf_sensor, ref); 289 290 DBG("wf: Deleting sensor %s\n", sr->name); 291 292 if (sr->ops && sr->ops->release) 293 sr->ops->release(sr); 294 else 295 kfree(sr); 296 } 297 298 static ssize_t wf_show_sensor(struct device *dev, 299 struct device_attribute *attr, char *buf) 300 { 301 struct wf_sensor *sens = container_of(attr, struct wf_sensor, attr); 302 s32 val = 0; 303 int err; 304 305 err = sens->ops->get_value(sens, &val); 306 if (err < 0) 307 return err; 308 return sprintf(buf, "%d.%03d\n", FIX32TOPRINT(val)); 309 } 310 311 int wf_register_sensor(struct wf_sensor *new_sr) 312 { 313 struct wf_sensor *sr; 314 315 mutex_lock(&wf_lock); 316 list_for_each_entry(sr, &wf_sensors, link) { 317 if (!strcmp(sr->name, new_sr->name)) { 318 printk(KERN_WARNING "windfarm: trying to register" 319 " duplicate sensor %s\n", sr->name); 320 mutex_unlock(&wf_lock); 321 return -EEXIST; 322 } 323 } 324 kref_init(&new_sr->ref); 325 list_add(&new_sr->link, &wf_sensors); 326 327 new_sr->attr.attr.name = new_sr->name; 328 new_sr->attr.attr.owner = THIS_MODULE; 329 new_sr->attr.attr.mode = 0444; 330 new_sr->attr.show = wf_show_sensor; 331 new_sr->attr.store = NULL; 332 if (device_create_file(&wf_platform_device.dev, &new_sr->attr)) 333 printk(KERN_WARNING "windfarm: device_create_file failed" 334 " for %s\n", new_sr->name); 335 /* the subsystem still does useful work without the file */ 336 337 DBG("wf: Registered sensor %s\n", new_sr->name); 338 339 wf_notify(WF_EVENT_NEW_SENSOR, new_sr); 340 mutex_unlock(&wf_lock); 341 342 return 0; 343 } 344 EXPORT_SYMBOL_GPL(wf_register_sensor); 345 346 void wf_unregister_sensor(struct wf_sensor *sr) 347 { 348 mutex_lock(&wf_lock); 349 list_del(&sr->link); 350 mutex_unlock(&wf_lock); 351 352 DBG("wf: Unregistered sensor %s\n", sr->name); 353 354 wf_put_sensor(sr); 355 } 356 EXPORT_SYMBOL_GPL(wf_unregister_sensor); 357 358 struct wf_sensor * wf_find_sensor(const char *name) 359 { 360 struct wf_sensor *sr; 361 362 mutex_lock(&wf_lock); 363 list_for_each_entry(sr, &wf_sensors, link) { 364 if (!strcmp(sr->name, name)) { 365 if (wf_get_sensor(sr)) 366 sr = NULL; 367 mutex_unlock(&wf_lock); 368 return sr; 369 } 370 } 371 mutex_unlock(&wf_lock); 372 return NULL; 373 } 374 EXPORT_SYMBOL_GPL(wf_find_sensor); 375 376 int wf_get_sensor(struct wf_sensor *sr) 377 { 378 if (!try_module_get(sr->ops->owner)) 379 return -ENODEV; 380 kref_get(&sr->ref); 381 return 0; 382 } 383 EXPORT_SYMBOL_GPL(wf_get_sensor); 384 385 void wf_put_sensor(struct wf_sensor *sr) 386 { 387 struct module *mod = sr->ops->owner; 388 kref_put(&sr->ref, wf_sensor_release); 389 module_put(mod); 390 } 391 EXPORT_SYMBOL_GPL(wf_put_sensor); 392 393 394 /* 395 * Client & notification 396 */ 397 398 int wf_register_client(struct notifier_block *nb) 399 { 400 int rc; 401 struct wf_control *ct; 402 struct wf_sensor *sr; 403 404 mutex_lock(&wf_lock); 405 rc = blocking_notifier_chain_register(&wf_client_list, nb); 406 if (rc != 0) 407 goto bail; 408 wf_client_count++; 409 list_for_each_entry(ct, &wf_controls, link) 410 wf_notify(WF_EVENT_NEW_CONTROL, ct); 411 list_for_each_entry(sr, &wf_sensors, link) 412 wf_notify(WF_EVENT_NEW_SENSOR, sr); 413 if (wf_client_count == 1) 414 wf_start_thread(); 415 bail: 416 mutex_unlock(&wf_lock); 417 return rc; 418 } 419 EXPORT_SYMBOL_GPL(wf_register_client); 420 421 int wf_unregister_client(struct notifier_block *nb) 422 { 423 mutex_lock(&wf_lock); 424 blocking_notifier_chain_unregister(&wf_client_list, nb); 425 wf_client_count++; 426 if (wf_client_count == 0) 427 wf_stop_thread(); 428 mutex_unlock(&wf_lock); 429 430 return 0; 431 } 432 EXPORT_SYMBOL_GPL(wf_unregister_client); 433 434 void wf_set_overtemp(void) 435 { 436 mutex_lock(&wf_lock); 437 wf_overtemp++; 438 if (wf_overtemp == 1) { 439 printk(KERN_WARNING "windfarm: Overtemp condition detected !\n"); 440 wf_overtemp_counter = 0; 441 wf_notify(WF_EVENT_OVERTEMP, NULL); 442 } 443 mutex_unlock(&wf_lock); 444 } 445 EXPORT_SYMBOL_GPL(wf_set_overtemp); 446 447 void wf_clear_overtemp(void) 448 { 449 mutex_lock(&wf_lock); 450 WARN_ON(wf_overtemp == 0); 451 if (wf_overtemp == 0) { 452 mutex_unlock(&wf_lock); 453 return; 454 } 455 wf_overtemp--; 456 if (wf_overtemp == 0) { 457 printk(KERN_WARNING "windfarm: Overtemp condition cleared !\n"); 458 wf_notify(WF_EVENT_NORMALTEMP, NULL); 459 } 460 mutex_unlock(&wf_lock); 461 } 462 EXPORT_SYMBOL_GPL(wf_clear_overtemp); 463 464 int wf_is_overtemp(void) 465 { 466 return (wf_overtemp != 0); 467 } 468 EXPORT_SYMBOL_GPL(wf_is_overtemp); 469 470 static int __init windfarm_core_init(void) 471 { 472 DBG("wf: core loaded\n"); 473 474 /* Don't register on old machines that use therm_pm72 for now */ 475 if (machine_is_compatible("PowerMac7,2") || 476 machine_is_compatible("PowerMac7,3") || 477 machine_is_compatible("RackMac3,1")) 478 return -ENODEV; 479 platform_device_register(&wf_platform_device); 480 return 0; 481 } 482 483 static void __exit windfarm_core_exit(void) 484 { 485 BUG_ON(wf_client_count != 0); 486 487 DBG("wf: core unloaded\n"); 488 489 platform_device_unregister(&wf_platform_device); 490 } 491 492 493 module_init(windfarm_core_init); 494 module_exit(windfarm_core_exit); 495 496 MODULE_AUTHOR("Benjamin Herrenschmidt <benh@kernel.crashing.org>"); 497 MODULE_DESCRIPTION("Core component of PowerMac thermal control"); 498 MODULE_LICENSE("GPL"); 499 500