windfarm_core.c
来自「linux 内核源代码」· C语言 代码 · 共 496 行
C
496 行
/* * Windfarm PowerMac thermal control. Core * * (c) Copyright 2005 Benjamin Herrenschmidt, IBM Corp. * <benh@kernel.crashing.org> * * Released under the term of the GNU GPL v2. * * This core code tracks the list of sensors & controls, register * clients, and holds the kernel thread used for control. * * TODO: * * Add some information about sensor/control type and data format to * sensors/controls, and have the sysfs attribute stuff be moved * generically here instead of hard coded in the platform specific * driver as it us currently * * This however requires solving some annoying lifetime issues with * sysfs which doesn't seem to have lifetime rules for struct attribute, * I may have to create full features kobjects for every sensor/control * instead which is a bit of an overkill imho */#include <linux/types.h>#include <linux/errno.h>#include <linux/kernel.h>#include <linux/init.h>#include <linux/spinlock.h>#include <linux/kthread.h>#include <linux/jiffies.h>#include <linux/reboot.h>#include <linux/device.h>#include <linux/platform_device.h>#include <linux/mutex.h>#include <linux/freezer.h>#include <asm/prom.h>#include "windfarm.h"#define VERSION "0.2"#undef DEBUG#ifdef DEBUG#define DBG(args...) printk(args)#else#define DBG(args...) do { } while(0)#endifstatic LIST_HEAD(wf_controls);static LIST_HEAD(wf_sensors);static DEFINE_MUTEX(wf_lock);static BLOCKING_NOTIFIER_HEAD(wf_client_list);static int wf_client_count;static unsigned int wf_overtemp;static unsigned int wf_overtemp_counter;struct task_struct *wf_thread;static struct platform_device wf_platform_device = { .name = "windfarm",};/* * Utilities & tick thread */static inline void wf_notify(int event, void *param){ blocking_notifier_call_chain(&wf_client_list, event, param);}int wf_critical_overtemp(void){ static char * critical_overtemp_path = "/sbin/critical_overtemp"; char *argv[] = { critical_overtemp_path, NULL }; static char *envp[] = { "HOME=/", "TERM=linux", "PATH=/sbin:/usr/sbin:/bin:/usr/bin", NULL }; return call_usermodehelper(critical_overtemp_path, argv, envp, UMH_WAIT_EXEC);}EXPORT_SYMBOL_GPL(wf_critical_overtemp);static int wf_thread_func(void *data){ unsigned long next, delay; next = jiffies; DBG("wf: thread started\n"); set_freezable(); while (!kthread_should_stop()) { try_to_freeze(); if (time_after_eq(jiffies, next)) { wf_notify(WF_EVENT_TICK, NULL); if (wf_overtemp) { wf_overtemp_counter++; /* 10 seconds overtemp, notify userland */ if (wf_overtemp_counter > 10) wf_critical_overtemp(); /* 30 seconds, shutdown */ if (wf_overtemp_counter > 30) { printk(KERN_ERR "windfarm: Overtemp " "for more than 30" " seconds, shutting down\n"); machine_power_off(); } } next += HZ; } delay = next - jiffies; if (delay <= HZ) schedule_timeout_interruptible(delay); } DBG("wf: thread stopped\n"); return 0;}static void wf_start_thread(void){ wf_thread = kthread_run(wf_thread_func, NULL, "kwindfarm"); if (IS_ERR(wf_thread)) { printk(KERN_ERR "windfarm: failed to create thread,err %ld\n", PTR_ERR(wf_thread)); wf_thread = NULL; }}static void wf_stop_thread(void){ if (wf_thread) kthread_stop(wf_thread); wf_thread = NULL;}/* * Controls */static void wf_control_release(struct kref *kref){ struct wf_control *ct = container_of(kref, struct wf_control, ref); DBG("wf: Deleting control %s\n", ct->name); if (ct->ops && ct->ops->release) ct->ops->release(ct); else kfree(ct);}static ssize_t wf_show_control(struct device *dev, struct device_attribute *attr, char *buf){ struct wf_control *ctrl = container_of(attr, struct wf_control, attr); s32 val = 0; int err; err = ctrl->ops->get_value(ctrl, &val); if (err < 0) return err; return sprintf(buf, "%d\n", val);}/* This is really only for debugging... */static ssize_t wf_store_control(struct device *dev, struct device_attribute *attr, const char *buf, size_t count){ struct wf_control *ctrl = container_of(attr, struct wf_control, attr); int val; int err; char *endp; val = simple_strtoul(buf, &endp, 0); while (endp < buf + count && (*endp == ' ' || *endp == '\n')) ++endp; if (endp - buf < count) return -EINVAL; err = ctrl->ops->set_value(ctrl, val); if (err < 0) return err; return count;}int wf_register_control(struct wf_control *new_ct){ struct wf_control *ct; mutex_lock(&wf_lock); list_for_each_entry(ct, &wf_controls, link) { if (!strcmp(ct->name, new_ct->name)) { printk(KERN_WARNING "windfarm: trying to register" " duplicate control %s\n", ct->name); mutex_unlock(&wf_lock); return -EEXIST; } } kref_init(&new_ct->ref); list_add(&new_ct->link, &wf_controls); new_ct->attr.attr.name = new_ct->name; new_ct->attr.attr.mode = 0644; new_ct->attr.show = wf_show_control; new_ct->attr.store = wf_store_control; if (device_create_file(&wf_platform_device.dev, &new_ct->attr)) printk(KERN_WARNING "windfarm: device_create_file failed" " for %s\n", new_ct->name); /* the subsystem still does useful work without the file */ DBG("wf: Registered control %s\n", new_ct->name); wf_notify(WF_EVENT_NEW_CONTROL, new_ct); mutex_unlock(&wf_lock); return 0;}EXPORT_SYMBOL_GPL(wf_register_control);void wf_unregister_control(struct wf_control *ct){ mutex_lock(&wf_lock); list_del(&ct->link); mutex_unlock(&wf_lock); DBG("wf: Unregistered control %s\n", ct->name); kref_put(&ct->ref, wf_control_release);}EXPORT_SYMBOL_GPL(wf_unregister_control);struct wf_control * wf_find_control(const char *name){ struct wf_control *ct; mutex_lock(&wf_lock); list_for_each_entry(ct, &wf_controls, link) { if (!strcmp(ct->name, name)) { if (wf_get_control(ct)) ct = NULL; mutex_unlock(&wf_lock); return ct; } } mutex_unlock(&wf_lock); return NULL;}EXPORT_SYMBOL_GPL(wf_find_control);int wf_get_control(struct wf_control *ct){ if (!try_module_get(ct->ops->owner)) return -ENODEV; kref_get(&ct->ref); return 0;}EXPORT_SYMBOL_GPL(wf_get_control);void wf_put_control(struct wf_control *ct){ struct module *mod = ct->ops->owner; kref_put(&ct->ref, wf_control_release); module_put(mod);}EXPORT_SYMBOL_GPL(wf_put_control);/* * Sensors */static void wf_sensor_release(struct kref *kref){ struct wf_sensor *sr = container_of(kref, struct wf_sensor, ref); DBG("wf: Deleting sensor %s\n", sr->name); if (sr->ops && sr->ops->release) sr->ops->release(sr); else kfree(sr);}static ssize_t wf_show_sensor(struct device *dev, struct device_attribute *attr, char *buf){ struct wf_sensor *sens = container_of(attr, struct wf_sensor, attr); s32 val = 0; int err; err = sens->ops->get_value(sens, &val); if (err < 0) return err; return sprintf(buf, "%d.%03d\n", FIX32TOPRINT(val));}int wf_register_sensor(struct wf_sensor *new_sr){ struct wf_sensor *sr; mutex_lock(&wf_lock); list_for_each_entry(sr, &wf_sensors, link) { if (!strcmp(sr->name, new_sr->name)) { printk(KERN_WARNING "windfarm: trying to register" " duplicate sensor %s\n", sr->name); mutex_unlock(&wf_lock); return -EEXIST; } } kref_init(&new_sr->ref); list_add(&new_sr->link, &wf_sensors); new_sr->attr.attr.name = new_sr->name; new_sr->attr.attr.mode = 0444; new_sr->attr.show = wf_show_sensor; new_sr->attr.store = NULL; if (device_create_file(&wf_platform_device.dev, &new_sr->attr)) printk(KERN_WARNING "windfarm: device_create_file failed" " for %s\n", new_sr->name); /* the subsystem still does useful work without the file */ DBG("wf: Registered sensor %s\n", new_sr->name); wf_notify(WF_EVENT_NEW_SENSOR, new_sr); mutex_unlock(&wf_lock); return 0;}EXPORT_SYMBOL_GPL(wf_register_sensor);void wf_unregister_sensor(struct wf_sensor *sr){ mutex_lock(&wf_lock); list_del(&sr->link); mutex_unlock(&wf_lock); DBG("wf: Unregistered sensor %s\n", sr->name); wf_put_sensor(sr);}EXPORT_SYMBOL_GPL(wf_unregister_sensor);struct wf_sensor * wf_find_sensor(const char *name){ struct wf_sensor *sr; mutex_lock(&wf_lock); list_for_each_entry(sr, &wf_sensors, link) { if (!strcmp(sr->name, name)) { if (wf_get_sensor(sr)) sr = NULL; mutex_unlock(&wf_lock); return sr; } } mutex_unlock(&wf_lock); return NULL;}EXPORT_SYMBOL_GPL(wf_find_sensor);int wf_get_sensor(struct wf_sensor *sr){ if (!try_module_get(sr->ops->owner)) return -ENODEV; kref_get(&sr->ref); return 0;}EXPORT_SYMBOL_GPL(wf_get_sensor);void wf_put_sensor(struct wf_sensor *sr){ struct module *mod = sr->ops->owner; kref_put(&sr->ref, wf_sensor_release); module_put(mod);}EXPORT_SYMBOL_GPL(wf_put_sensor);/* * Client & notification */int wf_register_client(struct notifier_block *nb){ int rc; struct wf_control *ct; struct wf_sensor *sr; mutex_lock(&wf_lock); rc = blocking_notifier_chain_register(&wf_client_list, nb); if (rc != 0) goto bail; wf_client_count++; list_for_each_entry(ct, &wf_controls, link) wf_notify(WF_EVENT_NEW_CONTROL, ct); list_for_each_entry(sr, &wf_sensors, link) wf_notify(WF_EVENT_NEW_SENSOR, sr); if (wf_client_count == 1) wf_start_thread(); bail: mutex_unlock(&wf_lock); return rc;}EXPORT_SYMBOL_GPL(wf_register_client);int wf_unregister_client(struct notifier_block *nb){ mutex_lock(&wf_lock); blocking_notifier_chain_unregister(&wf_client_list, nb); wf_client_count++; if (wf_client_count == 0) wf_stop_thread(); mutex_unlock(&wf_lock); return 0;}EXPORT_SYMBOL_GPL(wf_unregister_client);void wf_set_overtemp(void){ mutex_lock(&wf_lock); wf_overtemp++; if (wf_overtemp == 1) { printk(KERN_WARNING "windfarm: Overtemp condition detected !\n"); wf_overtemp_counter = 0; wf_notify(WF_EVENT_OVERTEMP, NULL); } mutex_unlock(&wf_lock);}EXPORT_SYMBOL_GPL(wf_set_overtemp);void wf_clear_overtemp(void){ mutex_lock(&wf_lock); WARN_ON(wf_overtemp == 0); if (wf_overtemp == 0) { mutex_unlock(&wf_lock); return; } wf_overtemp--; if (wf_overtemp == 0) { printk(KERN_WARNING "windfarm: Overtemp condition cleared !\n"); wf_notify(WF_EVENT_NORMALTEMP, NULL); } mutex_unlock(&wf_lock);}EXPORT_SYMBOL_GPL(wf_clear_overtemp);int wf_is_overtemp(void){ return (wf_overtemp != 0);}EXPORT_SYMBOL_GPL(wf_is_overtemp);static int __init windfarm_core_init(void){ DBG("wf: core loaded\n"); /* Don't register on old machines that use therm_pm72 for now */ if (machine_is_compatible("PowerMac7,2") || machine_is_compatible("PowerMac7,3") || machine_is_compatible("RackMac3,1")) return -ENODEV; platform_device_register(&wf_platform_device); return 0;}static void __exit windfarm_core_exit(void){ BUG_ON(wf_client_count != 0); DBG("wf: core unloaded\n"); platform_device_unregister(&wf_platform_device);}module_init(windfarm_core_init);module_exit(windfarm_core_exit);MODULE_AUTHOR("Benjamin Herrenschmidt <benh@kernel.crashing.org>");MODULE_DESCRIPTION("Core component of PowerMac thermal control");MODULE_LICENSE("GPL");
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?