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