Hi Arjan, I m submitting the medfield thermal driver patch series.
This one, the first one in the series, adds event notification support to the generic thermal sysfs framework in the kernel. I have also added a documentation for the same in Documentation/thermal/sysfs-api.txt ------------------------------------------------------------ Signed-off-by: <[email protected]> Index: ac_kernel/kernel/Documentation/ABI/stable/thermal-notification =================================================================== --- /dev/null +++ ac_kernel/kernel/Documentation/ABI/stable/thermal-notification @@ -0,0 +1,4 @@ +What: A notification mechanism for thermal related events +Description: + This interface enables notification for thermal related events. + The notification is in the form of a netlink event. Index: ac_kernel/kernel/Documentation/thermal/sysfs-api.txt =================================================================== --- ac_kernel.orig/kernel/Documentation/thermal/sysfs-api.txt +++ ac_kernel/kernel/Documentation/thermal/sysfs-api.txt @@ -278,3 +278,15 @@ method, the sys I/F structure will be bu |---name: acpitz |---temp1_input: 37000 |---temp1_crit: 100000 + +4. Event Notification + +The framework includes a simple notification mechanism, in the form of a +netlink event. Netlink socket initialization is done during the _init_ +of the framework. Drivers which intend to use the notification mechanism +just need to call generate_netlink_event() with two arguments viz +(originator, event). Typically the originator will be an integer assigned +to a thermal_zone_device when it registers itself with the framework. The +event will be one of:{THERMAL_AUX0, THERMAL_AUX1, THERMAL_CRITICAL, +THERMAL_DEV_FAULT}. Notification can be sent when the current temperature +crosses any of the configured thresholds. Index: ac_kernel/kernel/drivers/thermal/thermal_sys.c =================================================================== --- ac_kernel.orig/kernel/drivers/thermal/thermal_sys.c +++ ac_kernel/kernel/drivers/thermal/thermal_sys.c @@ -32,6 +32,8 @@ #include <linux/thermal.h> #include <linux/spinlock.h> #include <linux/reboot.h> +#include <net/netlink.h> +#include <net/genetlink.h> MODULE_AUTHOR("Zhang Rui"); MODULE_DESCRIPTION("Generic thermal management sysfs support"); @@ -58,6 +60,23 @@ static LIST_HEAD(thermal_tz_list); static LIST_HEAD(thermal_cdev_list); static DEFINE_MUTEX(thermal_list_lock); +static DEFINE_MUTEX(thermal_trip_lock); +static unsigned int thermal_event_seqnum; + +static struct genl_family thermal_event_genl_family = { + .id = GENL_ID_GENERATE, + .name = THERMAL_GENL_FAMILY_NAME, + .version = THERMAL_GENL_VERSION, + .maxattr = THERMAL_GENL_ATTR_MAX, +}; + +static struct genl_multicast_group thermal_event_mcgrp = { + .name = THERMAL_GENL_MCAST_GROUP_NAME, +}; + +static int genetlink_init(void); +static void genetlink_exit(void); + static int get_idr(struct idr *idr, struct mutex *lock, int *id) { int err; @@ -216,6 +235,30 @@ trip_point_temp_show(struct device *dev, } static ssize_t +trip_point_temp_store(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + struct thermal_zone_device *tz = to_thermal_zone(dev); + int trip, result; + long temperature; + + if (!tz->ops->set_trip_temp) + return -EPERM; + + if (!sscanf(attr->attr.name, "trip_point_%d_type", &trip)) + return -EINVAL; + + if (strict_strtoul(buf, 10, &temperature)) + return -EINVAL; + + mutex_lock(&thermal_trip_lock); + result = tz->ops->set_trip_temp(tz, trip, temperature); + mutex_unlock(&thermal_trip_lock); + + return (result == 0) ? count : -EINVAL; +} + +static ssize_t passive_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { @@ -282,31 +325,55 @@ static DEVICE_ATTR(mode, 0644, mode_show static DEVICE_ATTR(passive, S_IRUGO | S_IWUSR, passive_show, \ passive_store); +/* trip point temperatures may be configurable */ static struct device_attribute trip_point_attrs[] = { - __ATTR(trip_point_0_type, 0444, trip_point_type_show, NULL), - __ATTR(trip_point_0_temp, 0444, trip_point_temp_show, NULL), - __ATTR(trip_point_1_type, 0444, trip_point_type_show, NULL), - __ATTR(trip_point_1_temp, 0444, trip_point_temp_show, NULL), - __ATTR(trip_point_2_type, 0444, trip_point_type_show, NULL), - __ATTR(trip_point_2_temp, 0444, trip_point_temp_show, NULL), - __ATTR(trip_point_3_type, 0444, trip_point_type_show, NULL), - __ATTR(trip_point_3_temp, 0444, trip_point_temp_show, NULL), - __ATTR(trip_point_4_type, 0444, trip_point_type_show, NULL), - __ATTR(trip_point_4_temp, 0444, trip_point_temp_show, NULL), - __ATTR(trip_point_5_type, 0444, trip_point_type_show, NULL), - __ATTR(trip_point_5_temp, 0444, trip_point_temp_show, NULL), - __ATTR(trip_point_6_type, 0444, trip_point_type_show, NULL), - __ATTR(trip_point_6_temp, 0444, trip_point_temp_show, NULL), - __ATTR(trip_point_7_type, 0444, trip_point_type_show, NULL), - __ATTR(trip_point_7_temp, 0444, trip_point_temp_show, NULL), - __ATTR(trip_point_8_type, 0444, trip_point_type_show, NULL), - __ATTR(trip_point_8_temp, 0444, trip_point_temp_show, NULL), - __ATTR(trip_point_9_type, 0444, trip_point_type_show, NULL), - __ATTR(trip_point_9_temp, 0444, trip_point_temp_show, NULL), - __ATTR(trip_point_10_type, 0444, trip_point_type_show, NULL), - __ATTR(trip_point_10_temp, 0444, trip_point_temp_show, NULL), - __ATTR(trip_point_11_type, 0444, trip_point_type_show, NULL), - __ATTR(trip_point_11_temp, 0444, trip_point_temp_show, NULL), + __ATTR(trip_point_0_type, S_IRUGO, trip_point_type_show, NULL), + __ATTR(trip_point_0_temp, S_IRUGO | S_IWUSR, trip_point_temp_show, + trip_point_temp_store), + + __ATTR(trip_point_1_type, S_IRUGO, trip_point_type_show, NULL), + __ATTR(trip_point_1_temp, S_IRUGO | S_IWUSR, trip_point_temp_show, + trip_point_temp_store), + + __ATTR(trip_point_2_type, S_IRUGO, trip_point_type_show, NULL), + __ATTR(trip_point_2_temp, S_IRUGO | S_IWUSR, trip_point_temp_show, + trip_point_temp_store), + + __ATTR(trip_point_3_type, S_IRUGO, trip_point_type_show, NULL), + __ATTR(trip_point_3_temp, S_IRUGO | S_IWUSR, trip_point_temp_show, + trip_point_temp_store), + + __ATTR(trip_point_4_type, S_IRUGO, trip_point_type_show, NULL), + __ATTR(trip_point_4_temp, S_IRUGO | S_IWUSR, trip_point_temp_show, + trip_point_temp_store), + + __ATTR(trip_point_5_type, S_IRUGO, trip_point_type_show, NULL), + __ATTR(trip_point_5_temp, S_IRUGO | S_IWUSR, trip_point_temp_show, + trip_point_temp_store), + + __ATTR(trip_point_6_type, S_IRUGO, trip_point_type_show, NULL), + __ATTR(trip_point_6_temp, S_IRUGO | S_IWUSR, trip_point_temp_show, + trip_point_temp_store), + + __ATTR(trip_point_7_type, S_IRUGO, trip_point_type_show, NULL), + __ATTR(trip_point_7_temp, S_IRUGO | S_IWUSR, trip_point_temp_show, + trip_point_temp_store), + + __ATTR(trip_point_8_type, S_IRUGO, trip_point_type_show, NULL), + __ATTR(trip_point_8_temp, S_IRUGO | S_IWUSR, trip_point_temp_show, + trip_point_temp_store), + + __ATTR(trip_point_9_type, S_IRUGO, trip_point_type_show, NULL), + __ATTR(trip_point_9_temp, S_IRUGO | S_IWUSR, trip_point_temp_show, + trip_point_temp_store), + + __ATTR(trip_point_10_type, S_IRUGO, trip_point_type_show, NULL), + __ATTR(trip_point_10_temp, S_IRUGO | S_IWUSR, trip_point_temp_show, + trip_point_temp_store), + + __ATTR(trip_point_11_type, S_IRUGO, trip_point_type_show, NULL), + __ATTR(trip_point_11_temp, S_IRUGO | S_IWUSR, trip_point_temp_show, + trip_point_temp_store), }; #define TRIP_POINT_ATTR_ADD(_dev, _index, result) \ @@ -584,7 +651,7 @@ thermal_remove_hwmon_sysfs(struct therma } #endif -static void thermal_zone_device_set_polling(struct thermal_zone_device *tz, +void thermal_zone_device_set_polling(struct thermal_zone_device *tz, int delay) { cancel_delayed_work(&(tz->poll_queue)); @@ -609,6 +676,13 @@ static void thermal_zone_device_passive( long state, max_state; /* + * For polling mechanisms, call the notify method. + * Interrupts will have their own handlers. + */ + if (tz->ops->notify && tz->polling_delay) + tz->ops->notify(tz, trip, THERMAL_TRIP_PASSIVE); + + /* * Above Trip? * ----------- * Calculate the thermal trend (using the passive cooling equation) @@ -1214,28 +1288,117 @@ void thermal_zone_device_unregister(stru EXPORT_SYMBOL(thermal_zone_device_unregister); -static int __init thermal_init(void) +int generate_netlink_event(u32 orig, enum events event) +{ + struct sk_buff *skb; + struct nlattr *attr; + struct thermal_genl_event *thermal_event; + void *msg_header; + int size; + int result; + + /* allocate memory */ + size = nla_total_size(sizeof(struct thermal_genl_event)) + \ + nla_total_size(0); + + skb = genlmsg_new(size, GFP_ATOMIC); + if (!skb) + return -ENOMEM; + + /* add the genetlink message header */ + msg_header = genlmsg_put(skb, 0, thermal_event_seqnum++, + &thermal_event_genl_family, 0, + THERMAL_GENL_CMD_EVENT); + if (!msg_header) { + nlmsg_free(skb); + return -ENOMEM; + } + + /* fill the data */ + attr = nla_reserve(skb, THERMAL_GENL_ATTR_EVENT, \ + sizeof(struct thermal_genl_event)); + + if (!attr) { + nlmsg_free(skb); + return -EINVAL; + } + + thermal_event = nla_data(attr); + if (!thermal_event) { + nlmsg_free(skb); + return -EINVAL; + } + + memset(thermal_event, 0, sizeof(struct thermal_genl_event)); + + thermal_event->orig = orig; + thermal_event->event = event; + + /* send multicast genetlink message */ + result = genlmsg_end(skb, msg_header); + if (result < 0) { + nlmsg_free(skb); + return result; + } + + printk(KERN_INFO "netlink event: orig:%d event:%d", orig, event); + + result = genlmsg_multicast(skb, 0, thermal_event_mcgrp.id, GFP_ATOMIC); + + if (result) + printk(KERN_INFO "failed to send netlink event:%d", result); + + return result; +} +EXPORT_SYMBOL(generate_netlink_event); + +static int genetlink_init(void) { - int result = 0; + int result; + result = genl_register_family(&thermal_event_genl_family); + if (result) + return result; + + result = genl_register_mc_group(&thermal_event_genl_family, + &thermal_event_mcgrp); + if (result) + genl_unregister_family(&thermal_event_genl_family); + return result; +} + + +static void genetlink_exit(void) +{ + genl_unregister_family(&thermal_event_genl_family); +} + +static int __init thermal_init(void) +{ + int result = 0; result = class_register(&thermal_class); if (result) { idr_destroy(&thermal_tz_idr); idr_destroy(&thermal_cdev_idr); mutex_destroy(&thermal_idr_lock); mutex_destroy(&thermal_list_lock); + mutex_destroy(&thermal_trip_lock); } + result = genetlink_init(); return result; } static void __exit thermal_exit(void) { + class_unregister(&thermal_class); idr_destroy(&thermal_tz_idr); idr_destroy(&thermal_cdev_idr); mutex_destroy(&thermal_idr_lock); mutex_destroy(&thermal_list_lock); + mutex_destroy(&thermal_trip_lock); + genetlink_exit(); } -subsys_initcall(thermal_init); +fs_initcall(thermal_init); module_exit(thermal_exit); Index: ac_kernel/kernel/include/linux/thermal.h =================================================================== --- ac_kernel.orig/kernel/include/linux/thermal.h +++ ac_kernel/kernel/include/linux/thermal.h @@ -29,8 +29,45 @@ #include <linux/device.h> #include <linux/workqueue.h> -struct thermal_zone_device; -struct thermal_cooling_device; +#define THERMAL_GENL_FAMILY_NAME "thermal_event" +#define THERMAL_GENL_VERSION 0x01 +#define THERMAL_GENL_MCAST_GROUP_NAME "thermal_mc_group" + +#define THERMAL_TRIPS_NONE -1 +#define THERMAL_MAX_TRIPS 12 +#define THERMAL_NAME_LENGTH 20 + +#define KELVIN_TO_CELSIUS(t) (long)(((long)t-2732 >= 0) ? \ + ((long)t-2732+5)/10 : ((long)t-2732-5)/10) +#define CELSIUS_TO_KELVIN(t) ((t)*10+2732) + +enum events { + THERMAL_AUX0, + THERMAL_AUX1, + THERMAL_CRITICAL, + THERMAL_DEV_FAULT, +}; + +struct thermal_genl_event { + u32 orig; + enum events event; +}; + +/* attributes of thermal_genl_family */ +enum { + THERMAL_GENL_ATTR_UNSPEC, + THERMAL_GENL_ATTR_EVENT, + __THERMAL_GENL_ATTR_MAX, +}; +#define THERMAL_GENL_ATTR_MAX (__THERMAL_GENL_ATTR_MAX - 1) + +/* commands supported by the thermal_genl_family */ +enum { + THERMAL_GENL_CMD_UNSPEC, + THERMAL_GENL_CMD_EVENT, + __THERMAL_GENL_CMD_MAX, +}; +#define THERMAL_GENL_CMD_MAX (__THERMAL_GENL_CMD_MAX - 1) enum thermal_device_mode { THERMAL_DEVICE_DISABLED = 0, @@ -44,20 +81,23 @@ enum thermal_trip_type { THERMAL_TRIP_CRITICAL, }; +struct thermal_zone_device; +struct thermal_cooling_device; + struct thermal_zone_device_ops { int (*bind) (struct thermal_zone_device *, struct thermal_cooling_device *); int (*unbind) (struct thermal_zone_device *, struct thermal_cooling_device *); - int (*get_temp) (struct thermal_zone_device *, unsigned long *); + int (*get_temp) (struct thermal_zone_device *, long *); int (*get_mode) (struct thermal_zone_device *, enum thermal_device_mode *); int (*set_mode) (struct thermal_zone_device *, enum thermal_device_mode); int (*get_trip_type) (struct thermal_zone_device *, int, enum thermal_trip_type *); - int (*get_trip_temp) (struct thermal_zone_device *, int, - unsigned long *); + int (*get_trip_temp) (struct thermal_zone_device *, int, long *); + int (*set_trip_temp) (struct thermal_zone_device *, int, long); int (*get_crit_temp) (struct thermal_zone_device *, unsigned long *); int (*notify) (struct thermal_zone_device *, int, enum thermal_trip_type); @@ -69,9 +109,6 @@ struct thermal_cooling_device_ops { int (*set_cur_state) (struct thermal_cooling_device *, unsigned long); }; -#define THERMAL_TRIPS_NONE -1 -#define THERMAL_MAX_TRIPS 12 -#define THERMAL_NAME_LENGTH 20 struct thermal_cooling_device { int id; char type[THERMAL_NAME_LENGTH]; @@ -81,9 +118,6 @@ struct thermal_cooling_device { struct list_head node; }; -#define KELVIN_TO_CELSIUS(t) (long)(((long)t-2732 >= 0) ? \ - ((long)t-2732+5)/10 : ((long)t-2732-5)/10) -#define CELSIUS_TO_KELVIN(t) ((t)*10+2732) #if defined(CONFIG_THERMAL_HWMON) /* thermal zone devices with the same type share one hwmon device */ @@ -129,11 +163,10 @@ struct thermal_zone_device { }; struct thermal_zone_device *thermal_zone_device_register(char *, int, void *, - struct - thermal_zone_device_ops - *, int tc1, int tc2, - int passive_freq, - int polling_freq); + struct thermal_zone_device_ops *, + int tc1, int tc2, + int passive_freq, + int polling_freq); void thermal_zone_device_unregister(struct thermal_zone_device *); int thermal_zone_bind_cooling_device(struct thermal_zone_device *, int, @@ -142,9 +175,9 @@ int thermal_zone_unbind_cooling_device(s struct thermal_cooling_device *); void thermal_zone_device_update(struct thermal_zone_device *); struct thermal_cooling_device *thermal_cooling_device_register(char *, void *, - struct - thermal_cooling_device_ops - *); + struct thermal_cooling_device_ops *); void thermal_cooling_device_unregister(struct thermal_cooling_device *); +void thermal_zone_device_set_polling(struct thermal_zone_device *, int); +extern int generate_netlink_event(u32 orig, enum events event); #endif /* __THERMAL_H__ */
Adding_notification_support_to_thermal_framework.patch
Description: Adding_notification_support_to_thermal_framework.patch
_______________________________________________ Meego-kernel mailing list [email protected] http://lists.meego.com/listinfo/meego-kernel
