1 // SPDX-License-Identifier: GPL-2.0-only
3 * Windfarm PowerMac thermal control. Core
5 * (c) Copyright 2005 Benjamin Herrenschmidt, IBM Corp.
6 * <benh@kernel.crashing.org>
8 * This core code tracks the list of sensors & controls, register
9 * clients, and holds the kernel thread used for control.
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
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
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>
45 #define DBG(args...) printk(args)
47 #define DBG(args...) do { } while(0)
50 static LIST_HEAD(wf_controls
);
51 static LIST_HEAD(wf_sensors
);
52 static DEFINE_MUTEX(wf_lock
);
53 static BLOCKING_NOTIFIER_HEAD(wf_client_list
);
54 static int wf_client_count
;
55 static unsigned int wf_overtemp
;
56 static unsigned int wf_overtemp_counter
;
57 static struct task_struct
*wf_thread
;
59 static struct platform_device wf_platform_device
= {
64 * Utilities & tick thread
67 static inline void wf_notify(int event
, void *param
)
69 blocking_notifier_call_chain(&wf_client_list
, event
, param
);
72 static int wf_critical_overtemp(void)
74 static char const critical_overtemp_path
[] = "/sbin/critical_overtemp";
75 char *argv
[] = { (char *)critical_overtemp_path
, NULL
};
76 static char *envp
[] = { "HOME=/",
78 "PATH=/sbin:/usr/sbin:/bin:/usr/bin",
81 return call_usermodehelper(critical_overtemp_path
,
82 argv
, envp
, UMH_WAIT_EXEC
);
85 static int wf_thread_func(void *data
)
87 unsigned long next
, delay
;
91 DBG("wf: thread started\n");
94 while (!kthread_should_stop()) {
97 if (time_after_eq(jiffies
, next
)) {
98 wf_notify(WF_EVENT_TICK
, NULL
);
100 wf_overtemp_counter
++;
101 /* 10 seconds overtemp, notify userland */
102 if (wf_overtemp_counter
> 10)
103 wf_critical_overtemp();
104 /* 30 seconds, shutdown */
105 if (wf_overtemp_counter
> 30) {
106 printk(KERN_ERR
"windfarm: Overtemp "
108 " seconds, shutting down\n");
115 delay
= next
- jiffies
;
117 schedule_timeout_interruptible(delay
);
120 DBG("wf: thread stopped\n");
125 static void wf_start_thread(void)
127 wf_thread
= kthread_run(wf_thread_func
, NULL
, "kwindfarm");
128 if (IS_ERR(wf_thread
)) {
129 printk(KERN_ERR
"windfarm: failed to create thread,err %ld\n",
136 static void wf_stop_thread(void)
139 kthread_stop(wf_thread
);
147 static void wf_control_release(struct kref
*kref
)
149 struct wf_control
*ct
= container_of(kref
, struct wf_control
, ref
);
151 DBG("wf: Deleting control %s\n", ct
->name
);
153 if (ct
->ops
&& ct
->ops
->release
)
154 ct
->ops
->release(ct
);
159 static ssize_t
wf_show_control(struct device
*dev
,
160 struct device_attribute
*attr
, char *buf
)
162 struct wf_control
*ctrl
= container_of(attr
, struct wf_control
, attr
);
167 err
= ctrl
->ops
->get_value(ctrl
, &val
);
170 return sprintf(buf
, "<HW FAULT>\n");
174 case WF_CONTROL_RPM_FAN
:
177 case WF_CONTROL_PWM_FAN
:
183 return sprintf(buf
, "%d%s\n", val
, typestr
);
186 /* This is really only for debugging... */
187 static ssize_t
wf_store_control(struct device
*dev
,
188 struct device_attribute
*attr
,
189 const char *buf
, size_t count
)
191 struct wf_control
*ctrl
= container_of(attr
, struct wf_control
, attr
);
196 val
= simple_strtoul(buf
, &endp
, 0);
197 while (endp
< buf
+ count
&& (*endp
== ' ' || *endp
== '\n'))
199 if (endp
- buf
< count
)
201 err
= ctrl
->ops
->set_value(ctrl
, val
);
207 int wf_register_control(struct wf_control
*new_ct
)
209 struct wf_control
*ct
;
211 mutex_lock(&wf_lock
);
212 list_for_each_entry(ct
, &wf_controls
, link
) {
213 if (!strcmp(ct
->name
, new_ct
->name
)) {
214 printk(KERN_WARNING
"windfarm: trying to register"
215 " duplicate control %s\n", ct
->name
);
216 mutex_unlock(&wf_lock
);
220 kref_init(&new_ct
->ref
);
221 list_add(&new_ct
->link
, &wf_controls
);
223 sysfs_attr_init(&new_ct
->attr
.attr
);
224 new_ct
->attr
.attr
.name
= new_ct
->name
;
225 new_ct
->attr
.attr
.mode
= 0644;
226 new_ct
->attr
.show
= wf_show_control
;
227 new_ct
->attr
.store
= wf_store_control
;
228 if (device_create_file(&wf_platform_device
.dev
, &new_ct
->attr
))
229 printk(KERN_WARNING
"windfarm: device_create_file failed"
230 " for %s\n", new_ct
->name
);
231 /* the subsystem still does useful work without the file */
233 DBG("wf: Registered control %s\n", new_ct
->name
);
235 wf_notify(WF_EVENT_NEW_CONTROL
, new_ct
);
236 mutex_unlock(&wf_lock
);
240 EXPORT_SYMBOL_GPL(wf_register_control
);
242 void wf_unregister_control(struct wf_control
*ct
)
244 mutex_lock(&wf_lock
);
246 mutex_unlock(&wf_lock
);
248 DBG("wf: Unregistered control %s\n", ct
->name
);
250 kref_put(&ct
->ref
, wf_control_release
);
252 EXPORT_SYMBOL_GPL(wf_unregister_control
);
254 int wf_get_control(struct wf_control
*ct
)
256 if (!try_module_get(ct
->ops
->owner
))
261 EXPORT_SYMBOL_GPL(wf_get_control
);
263 void wf_put_control(struct wf_control
*ct
)
265 struct module
*mod
= ct
->ops
->owner
;
266 kref_put(&ct
->ref
, wf_control_release
);
269 EXPORT_SYMBOL_GPL(wf_put_control
);
277 static void wf_sensor_release(struct kref
*kref
)
279 struct wf_sensor
*sr
= container_of(kref
, struct wf_sensor
, ref
);
281 DBG("wf: Deleting sensor %s\n", sr
->name
);
283 if (sr
->ops
&& sr
->ops
->release
)
284 sr
->ops
->release(sr
);
289 static ssize_t
wf_show_sensor(struct device
*dev
,
290 struct device_attribute
*attr
, char *buf
)
292 struct wf_sensor
*sens
= container_of(attr
, struct wf_sensor
, attr
);
296 err
= sens
->ops
->get_value(sens
, &val
);
299 return sprintf(buf
, "%d.%03d\n", FIX32TOPRINT(val
));
302 int wf_register_sensor(struct wf_sensor
*new_sr
)
304 struct wf_sensor
*sr
;
306 mutex_lock(&wf_lock
);
307 list_for_each_entry(sr
, &wf_sensors
, link
) {
308 if (!strcmp(sr
->name
, new_sr
->name
)) {
309 printk(KERN_WARNING
"windfarm: trying to register"
310 " duplicate sensor %s\n", sr
->name
);
311 mutex_unlock(&wf_lock
);
315 kref_init(&new_sr
->ref
);
316 list_add(&new_sr
->link
, &wf_sensors
);
318 sysfs_attr_init(&new_sr
->attr
.attr
);
319 new_sr
->attr
.attr
.name
= new_sr
->name
;
320 new_sr
->attr
.attr
.mode
= 0444;
321 new_sr
->attr
.show
= wf_show_sensor
;
322 new_sr
->attr
.store
= NULL
;
323 if (device_create_file(&wf_platform_device
.dev
, &new_sr
->attr
))
324 printk(KERN_WARNING
"windfarm: device_create_file failed"
325 " for %s\n", new_sr
->name
);
326 /* the subsystem still does useful work without the file */
328 DBG("wf: Registered sensor %s\n", new_sr
->name
);
330 wf_notify(WF_EVENT_NEW_SENSOR
, new_sr
);
331 mutex_unlock(&wf_lock
);
335 EXPORT_SYMBOL_GPL(wf_register_sensor
);
337 void wf_unregister_sensor(struct wf_sensor
*sr
)
339 mutex_lock(&wf_lock
);
341 mutex_unlock(&wf_lock
);
343 DBG("wf: Unregistered sensor %s\n", sr
->name
);
347 EXPORT_SYMBOL_GPL(wf_unregister_sensor
);
349 int wf_get_sensor(struct wf_sensor
*sr
)
351 if (!try_module_get(sr
->ops
->owner
))
356 EXPORT_SYMBOL_GPL(wf_get_sensor
);
358 void wf_put_sensor(struct wf_sensor
*sr
)
360 struct module
*mod
= sr
->ops
->owner
;
361 kref_put(&sr
->ref
, wf_sensor_release
);
364 EXPORT_SYMBOL_GPL(wf_put_sensor
);
368 * Client & notification
371 int wf_register_client(struct notifier_block
*nb
)
374 struct wf_control
*ct
;
375 struct wf_sensor
*sr
;
377 mutex_lock(&wf_lock
);
378 rc
= blocking_notifier_chain_register(&wf_client_list
, nb
);
382 list_for_each_entry(ct
, &wf_controls
, link
)
383 wf_notify(WF_EVENT_NEW_CONTROL
, ct
);
384 list_for_each_entry(sr
, &wf_sensors
, link
)
385 wf_notify(WF_EVENT_NEW_SENSOR
, sr
);
386 if (wf_client_count
== 1)
389 mutex_unlock(&wf_lock
);
392 EXPORT_SYMBOL_GPL(wf_register_client
);
394 int wf_unregister_client(struct notifier_block
*nb
)
396 mutex_lock(&wf_lock
);
397 blocking_notifier_chain_unregister(&wf_client_list
, nb
);
399 if (wf_client_count
== 0)
401 mutex_unlock(&wf_lock
);
405 EXPORT_SYMBOL_GPL(wf_unregister_client
);
407 void wf_set_overtemp(void)
409 mutex_lock(&wf_lock
);
411 if (wf_overtemp
== 1) {
412 printk(KERN_WARNING
"windfarm: Overtemp condition detected !\n");
413 wf_overtemp_counter
= 0;
414 wf_notify(WF_EVENT_OVERTEMP
, NULL
);
416 mutex_unlock(&wf_lock
);
418 EXPORT_SYMBOL_GPL(wf_set_overtemp
);
420 void wf_clear_overtemp(void)
422 mutex_lock(&wf_lock
);
423 WARN_ON(wf_overtemp
== 0);
424 if (wf_overtemp
== 0) {
425 mutex_unlock(&wf_lock
);
429 if (wf_overtemp
== 0) {
430 printk(KERN_WARNING
"windfarm: Overtemp condition cleared !\n");
431 wf_notify(WF_EVENT_NORMALTEMP
, NULL
);
433 mutex_unlock(&wf_lock
);
435 EXPORT_SYMBOL_GPL(wf_clear_overtemp
);
437 static int __init
windfarm_core_init(void)
439 DBG("wf: core loaded\n");
441 platform_device_register(&wf_platform_device
);
445 static void __exit
windfarm_core_exit(void)
447 BUG_ON(wf_client_count
!= 0);
449 DBG("wf: core unloaded\n");
451 platform_device_unregister(&wf_platform_device
);
455 module_init(windfarm_core_init
);
456 module_exit(windfarm_core_exit
);
458 MODULE_AUTHOR("Benjamin Herrenschmidt <benh@kernel.crashing.org>");
459 MODULE_DESCRIPTION("Core component of PowerMac thermal control");
460 MODULE_LICENSE("GPL");