1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * Windfarm PowerMac thermal control. Core 4 * 5 * (c) Copyright 2005 Benjamin Herrenschmidt, IBM Corp. 6 * <benh@kernel.crashing.org> 7 * 8 * This core code tracks the list of sensors & controls, register 9 * clients, and holds the kernel thread used for control. 10 * 11 * TODO: 12 * 13 * Add some information about sensor/control type and data format to 14 * sensors/controls, and have the sysfs attribute stuff be moved 15 * generically here instead of hard coded in the platform specific 16 * driver as it us currently 17 * 18 * This however requires solving some annoying lifetime issues with 19 * sysfs which doesn't seem to have lifetime rules for struct attribute, 20 * I may have to create full features kobjects for every sensor/control 21 * instead which is a bit of an overkill imho 22 */ 23 24 #include <linux/types.h> 25 #include <linux/errno.h> 26 #include <linux/kernel.h> 27 #include <linux/slab.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 static 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 static int wf_critical_overtemp(void) 75 { 76 static char const critical_overtemp_path[] = "/sbin/critical_overtemp"; 77 char *argv[] = { (char *)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, 84 argv, envp, UMH_WAIT_EXEC); 85 } 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 set_freezable(); 96 while (!kthread_should_stop()) { 97 try_to_freeze(); 98 99 if (time_after_eq(jiffies, next)) { 100 wf_notify(WF_EVENT_TICK, NULL); 101 if (wf_overtemp) { 102 wf_overtemp_counter++; 103 /* 10 seconds overtemp, notify userland */ 104 if (wf_overtemp_counter > 10) 105 wf_critical_overtemp(); 106 /* 30 seconds, shutdown */ 107 if (wf_overtemp_counter > 30) { 108 printk(KERN_ERR "windfarm: Overtemp " 109 "for more than 30" 110 " seconds, shutting down\n"); 111 machine_power_off(); 112 } 113 } 114 next += HZ; 115 } 116 117 delay = next - jiffies; 118 if (delay <= HZ) 119 schedule_timeout_interruptible(delay); 120 } 121 122 DBG("wf: thread stopped\n"); 123 124 return 0; 125 } 126 127 static void wf_start_thread(void) 128 { 129 wf_thread = kthread_run(wf_thread_func, NULL, "kwindfarm"); 130 if (IS_ERR(wf_thread)) { 131 printk(KERN_ERR "windfarm: failed to create thread,err %ld\n", 132 PTR_ERR(wf_thread)); 133 wf_thread = NULL; 134 } 135 } 136 137 138 static void wf_stop_thread(void) 139 { 140 if (wf_thread) 141 kthread_stop(wf_thread); 142 wf_thread = NULL; 143 } 144 145 /* 146 * Controls 147 */ 148 149 static void wf_control_release(struct kref *kref) 150 { 151 struct wf_control *ct = container_of(kref, struct wf_control, ref); 152 153 DBG("wf: Deleting control %s\n", ct->name); 154 155 if (ct->ops && ct->ops->release) 156 ct->ops->release(ct); 157 else 158 kfree(ct); 159 } 160 161 static ssize_t wf_show_control(struct device *dev, 162 struct device_attribute *attr, char *buf) 163 { 164 struct wf_control *ctrl = container_of(attr, struct wf_control, attr); 165 const char *typestr; 166 s32 val = 0; 167 int err; 168 169 err = ctrl->ops->get_value(ctrl, &val); 170 if (err < 0) { 171 if (err == -EFAULT) 172 return sprintf(buf, "<HW FAULT>\n"); 173 return err; 174 } 175 switch(ctrl->type) { 176 case WF_CONTROL_RPM_FAN: 177 typestr = " RPM"; 178 break; 179 case WF_CONTROL_PWM_FAN: 180 typestr = " %"; 181 break; 182 default: 183 typestr = ""; 184 } 185 return sprintf(buf, "%d%s\n", val, typestr); 186 } 187 188 /* This is really only for debugging... */ 189 static ssize_t wf_store_control(struct device *dev, 190 struct device_attribute *attr, 191 const char *buf, size_t count) 192 { 193 struct wf_control *ctrl = container_of(attr, struct wf_control, attr); 194 int val; 195 int err; 196 char *endp; 197 198 val = simple_strtoul(buf, &endp, 0); 199 while (endp < buf + count && (*endp == ' ' || *endp == '\n')) 200 ++endp; 201 if (endp - buf < count) 202 return -EINVAL; 203 err = ctrl->ops->set_value(ctrl, val); 204 if (err < 0) 205 return err; 206 return count; 207 } 208 209 int wf_register_control(struct wf_control *new_ct) 210 { 211 struct wf_control *ct; 212 213 mutex_lock(&wf_lock); 214 list_for_each_entry(ct, &wf_controls, link) { 215 if (!strcmp(ct->name, new_ct->name)) { 216 printk(KERN_WARNING "windfarm: trying to register" 217 " duplicate control %s\n", ct->name); 218 mutex_unlock(&wf_lock); 219 return -EEXIST; 220 } 221 } 222 kref_init(&new_ct->ref); 223 list_add(&new_ct->link, &wf_controls); 224 225 sysfs_attr_init(&new_ct->attr.attr); 226 new_ct->attr.attr.name = new_ct->name; 227 new_ct->attr.attr.mode = 0644; 228 new_ct->attr.show = wf_show_control; 229 new_ct->attr.store = wf_store_control; 230 if (device_create_file(&wf_platform_device.dev, &new_ct->attr)) 231 printk(KERN_WARNING "windfarm: device_create_file failed" 232 " for %s\n", new_ct->name); 233 /* the subsystem still does useful work without the file */ 234 235 DBG("wf: Registered control %s\n", new_ct->name); 236 237 wf_notify(WF_EVENT_NEW_CONTROL, new_ct); 238 mutex_unlock(&wf_lock); 239 240 return 0; 241 } 242 EXPORT_SYMBOL_GPL(wf_register_control); 243 244 void wf_unregister_control(struct wf_control *ct) 245 { 246 mutex_lock(&wf_lock); 247 list_del(&ct->link); 248 mutex_unlock(&wf_lock); 249 250 DBG("wf: Unregistered control %s\n", ct->name); 251 252 kref_put(&ct->ref, wf_control_release); 253 } 254 EXPORT_SYMBOL_GPL(wf_unregister_control); 255 256 int wf_get_control(struct wf_control *ct) 257 { 258 if (!try_module_get(ct->ops->owner)) 259 return -ENODEV; 260 kref_get(&ct->ref); 261 return 0; 262 } 263 EXPORT_SYMBOL_GPL(wf_get_control); 264 265 void wf_put_control(struct wf_control *ct) 266 { 267 struct module *mod = ct->ops->owner; 268 kref_put(&ct->ref, wf_control_release); 269 module_put(mod); 270 } 271 EXPORT_SYMBOL_GPL(wf_put_control); 272 273 274 /* 275 * Sensors 276 */ 277 278 279 static void wf_sensor_release(struct kref *kref) 280 { 281 struct wf_sensor *sr = container_of(kref, struct wf_sensor, ref); 282 283 DBG("wf: Deleting sensor %s\n", sr->name); 284 285 if (sr->ops && sr->ops->release) 286 sr->ops->release(sr); 287 else 288 kfree(sr); 289 } 290 291 static ssize_t wf_show_sensor(struct device *dev, 292 struct device_attribute *attr, char *buf) 293 { 294 struct wf_sensor *sens = container_of(attr, struct wf_sensor, attr); 295 s32 val = 0; 296 int err; 297 298 err = sens->ops->get_value(sens, &val); 299 if (err < 0) 300 return err; 301 return sprintf(buf, "%d.%03d\n", FIX32TOPRINT(val)); 302 } 303 304 int wf_register_sensor(struct wf_sensor *new_sr) 305 { 306 struct wf_sensor *sr; 307 308 mutex_lock(&wf_lock); 309 list_for_each_entry(sr, &wf_sensors, link) { 310 if (!strcmp(sr->name, new_sr->name)) { 311 printk(KERN_WARNING "windfarm: trying to register" 312 " duplicate sensor %s\n", sr->name); 313 mutex_unlock(&wf_lock); 314 return -EEXIST; 315 } 316 } 317 kref_init(&new_sr->ref); 318 list_add(&new_sr->link, &wf_sensors); 319 320 sysfs_attr_init(&new_sr->attr.attr); 321 new_sr->attr.attr.name = new_sr->name; 322 new_sr->attr.attr.mode = 0444; 323 new_sr->attr.show = wf_show_sensor; 324 new_sr->attr.store = NULL; 325 if (device_create_file(&wf_platform_device.dev, &new_sr->attr)) 326 printk(KERN_WARNING "windfarm: device_create_file failed" 327 " for %s\n", new_sr->name); 328 /* the subsystem still does useful work without the file */ 329 330 DBG("wf: Registered sensor %s\n", new_sr->name); 331 332 wf_notify(WF_EVENT_NEW_SENSOR, new_sr); 333 mutex_unlock(&wf_lock); 334 335 return 0; 336 } 337 EXPORT_SYMBOL_GPL(wf_register_sensor); 338 339 void wf_unregister_sensor(struct wf_sensor *sr) 340 { 341 mutex_lock(&wf_lock); 342 list_del(&sr->link); 343 mutex_unlock(&wf_lock); 344 345 DBG("wf: Unregistered sensor %s\n", sr->name); 346 347 wf_put_sensor(sr); 348 } 349 EXPORT_SYMBOL_GPL(wf_unregister_sensor); 350 351 int wf_get_sensor(struct wf_sensor *sr) 352 { 353 if (!try_module_get(sr->ops->owner)) 354 return -ENODEV; 355 kref_get(&sr->ref); 356 return 0; 357 } 358 EXPORT_SYMBOL_GPL(wf_get_sensor); 359 360 void wf_put_sensor(struct wf_sensor *sr) 361 { 362 struct module *mod = sr->ops->owner; 363 kref_put(&sr->ref, wf_sensor_release); 364 module_put(mod); 365 } 366 EXPORT_SYMBOL_GPL(wf_put_sensor); 367 368 369 /* 370 * Client & notification 371 */ 372 373 int wf_register_client(struct notifier_block *nb) 374 { 375 int rc; 376 struct wf_control *ct; 377 struct wf_sensor *sr; 378 379 mutex_lock(&wf_lock); 380 rc = blocking_notifier_chain_register(&wf_client_list, nb); 381 if (rc != 0) 382 goto bail; 383 wf_client_count++; 384 list_for_each_entry(ct, &wf_controls, link) 385 wf_notify(WF_EVENT_NEW_CONTROL, ct); 386 list_for_each_entry(sr, &wf_sensors, link) 387 wf_notify(WF_EVENT_NEW_SENSOR, sr); 388 if (wf_client_count == 1) 389 wf_start_thread(); 390 bail: 391 mutex_unlock(&wf_lock); 392 return rc; 393 } 394 EXPORT_SYMBOL_GPL(wf_register_client); 395 396 int wf_unregister_client(struct notifier_block *nb) 397 { 398 mutex_lock(&wf_lock); 399 blocking_notifier_chain_unregister(&wf_client_list, nb); 400 wf_client_count--; 401 if (wf_client_count == 0) 402 wf_stop_thread(); 403 mutex_unlock(&wf_lock); 404 405 return 0; 406 } 407 EXPORT_SYMBOL_GPL(wf_unregister_client); 408 409 void wf_set_overtemp(void) 410 { 411 mutex_lock(&wf_lock); 412 wf_overtemp++; 413 if (wf_overtemp == 1) { 414 printk(KERN_WARNING "windfarm: Overtemp condition detected !\n"); 415 wf_overtemp_counter = 0; 416 wf_notify(WF_EVENT_OVERTEMP, NULL); 417 } 418 mutex_unlock(&wf_lock); 419 } 420 EXPORT_SYMBOL_GPL(wf_set_overtemp); 421 422 void wf_clear_overtemp(void) 423 { 424 mutex_lock(&wf_lock); 425 WARN_ON(wf_overtemp == 0); 426 if (wf_overtemp == 0) { 427 mutex_unlock(&wf_lock); 428 return; 429 } 430 wf_overtemp--; 431 if (wf_overtemp == 0) { 432 printk(KERN_WARNING "windfarm: Overtemp condition cleared !\n"); 433 wf_notify(WF_EVENT_NORMALTEMP, NULL); 434 } 435 mutex_unlock(&wf_lock); 436 } 437 EXPORT_SYMBOL_GPL(wf_clear_overtemp); 438 439 static int __init windfarm_core_init(void) 440 { 441 DBG("wf: core loaded\n"); 442 443 platform_device_register(&wf_platform_device); 444 return 0; 445 } 446 447 static void __exit windfarm_core_exit(void) 448 { 449 BUG_ON(wf_client_count != 0); 450 451 DBG("wf: core unloaded\n"); 452 453 platform_device_unregister(&wf_platform_device); 454 } 455 456 457 module_init(windfarm_core_init); 458 module_exit(windfarm_core_exit); 459 460 MODULE_AUTHOR("Benjamin Herrenschmidt <benh@kernel.crashing.org>"); 461 MODULE_DESCRIPTION("Core component of PowerMac thermal control"); 462 MODULE_LICENSE("GPL"); 463 464