aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Documentation/ABI/stable/thermal-notification4
-rw-r--r--Documentation/thermal/sysfs-api.txt12
-rw-r--r--drivers/thermal/Kconfig1
-rw-r--r--drivers/thermal/thermal_sys.c103
-rw-r--r--include/linux/thermal.h32
5 files changed, 151 insertions, 1 deletions
diff --git a/Documentation/ABI/stable/thermal-notification b/Documentation/ABI/stable/thermal-notification
new file mode 100644
index 000000000000..9723e8b7aeb3
--- /dev/null
+++ b/Documentation/ABI/stable/thermal-notification
@@ -0,0 +1,4 @@
1What: A notification mechanism for thermal related events
2Description:
3 This interface enables notification for thermal related events.
4 The notification is in the form of a netlink event.
diff --git a/Documentation/thermal/sysfs-api.txt b/Documentation/thermal/sysfs-api.txt
index cb3d15bc1aeb..b61e46f449aa 100644
--- a/Documentation/thermal/sysfs-api.txt
+++ b/Documentation/thermal/sysfs-api.txt
@@ -278,3 +278,15 @@ method, the sys I/F structure will be built like this:
278 |---name: acpitz 278 |---name: acpitz
279 |---temp1_input: 37000 279 |---temp1_input: 37000
280 |---temp1_crit: 100000 280 |---temp1_crit: 100000
281
2824. Event Notification
283
284The framework includes a simple notification mechanism, in the form of a
285netlink event. Netlink socket initialization is done during the _init_
286of the framework. Drivers which intend to use the notification mechanism
287just need to call generate_netlink_event() with two arguments viz
288(originator, event). Typically the originator will be an integer assigned
289to a thermal_zone_device when it registers itself with the framework. The
290event will be one of:{THERMAL_AUX0, THERMAL_AUX1, THERMAL_CRITICAL,
291THERMAL_DEV_FAULT}. Notification can be sent when the current temperature
292crosses any of the configured thresholds.
diff --git a/drivers/thermal/Kconfig b/drivers/thermal/Kconfig
index bf7c687519ef..f7a5dba3ca23 100644
--- a/drivers/thermal/Kconfig
+++ b/drivers/thermal/Kconfig
@@ -4,6 +4,7 @@
4 4
5menuconfig THERMAL 5menuconfig THERMAL
6 tristate "Generic Thermal sysfs driver" 6 tristate "Generic Thermal sysfs driver"
7 depends on NET
7 help 8 help
8 Generic Thermal Sysfs driver offers a generic mechanism for 9 Generic Thermal Sysfs driver offers a generic mechanism for
9 thermal management. Usually it's made up of one or more thermal 10 thermal management. Usually it's made up of one or more thermal
diff --git a/drivers/thermal/thermal_sys.c b/drivers/thermal/thermal_sys.c
index 13c72c629329..760e045c93c8 100644
--- a/drivers/thermal/thermal_sys.c
+++ b/drivers/thermal/thermal_sys.c
@@ -32,6 +32,8 @@
32#include <linux/thermal.h> 32#include <linux/thermal.h>
33#include <linux/spinlock.h> 33#include <linux/spinlock.h>
34#include <linux/reboot.h> 34#include <linux/reboot.h>
35#include <net/netlink.h>
36#include <net/genetlink.h>
35 37
36MODULE_AUTHOR("Zhang Rui"); 38MODULE_AUTHOR("Zhang Rui");
37MODULE_DESCRIPTION("Generic thermal management sysfs support"); 39MODULE_DESCRIPTION("Generic thermal management sysfs support");
@@ -58,6 +60,22 @@ static LIST_HEAD(thermal_tz_list);
58static LIST_HEAD(thermal_cdev_list); 60static LIST_HEAD(thermal_cdev_list);
59static DEFINE_MUTEX(thermal_list_lock); 61static DEFINE_MUTEX(thermal_list_lock);
60 62
63static unsigned int thermal_event_seqnum;
64
65static struct genl_family thermal_event_genl_family = {
66 .id = GENL_ID_GENERATE,
67 .name = THERMAL_GENL_FAMILY_NAME,
68 .version = THERMAL_GENL_VERSION,
69 .maxattr = THERMAL_GENL_ATTR_MAX,
70};
71
72static struct genl_multicast_group thermal_event_mcgrp = {
73 .name = THERMAL_GENL_MCAST_GROUP_NAME,
74};
75
76static int genetlink_init(void);
77static void genetlink_exit(void);
78
61static int get_idr(struct idr *idr, struct mutex *lock, int *id) 79static int get_idr(struct idr *idr, struct mutex *lock, int *id)
62{ 80{
63 int err; 81 int err;
@@ -1214,6 +1232,82 @@ void thermal_zone_device_unregister(struct thermal_zone_device *tz)
1214 1232
1215EXPORT_SYMBOL(thermal_zone_device_unregister); 1233EXPORT_SYMBOL(thermal_zone_device_unregister);
1216 1234
1235int generate_netlink_event(u32 orig, enum events event)
1236{
1237 struct sk_buff *skb;
1238 struct nlattr *attr;
1239 struct thermal_genl_event *thermal_event;
1240 void *msg_header;
1241 int size;
1242 int result;
1243
1244 /* allocate memory */
1245 size = nla_total_size(sizeof(struct thermal_genl_event)) + \
1246 nla_total_size(0);
1247
1248 skb = genlmsg_new(size, GFP_ATOMIC);
1249 if (!skb)
1250 return -ENOMEM;
1251
1252 /* add the genetlink message header */
1253 msg_header = genlmsg_put(skb, 0, thermal_event_seqnum++,
1254 &thermal_event_genl_family, 0,
1255 THERMAL_GENL_CMD_EVENT);
1256 if (!msg_header) {
1257 nlmsg_free(skb);
1258 return -ENOMEM;
1259 }
1260
1261 /* fill the data */
1262 attr = nla_reserve(skb, THERMAL_GENL_ATTR_EVENT, \
1263 sizeof(struct thermal_genl_event));
1264
1265 if (!attr) {
1266 nlmsg_free(skb);
1267 return -EINVAL;
1268 }
1269
1270 thermal_event = nla_data(attr);
1271 if (!thermal_event) {
1272 nlmsg_free(skb);
1273 return -EINVAL;
1274 }
1275
1276 memset(thermal_event, 0, sizeof(struct thermal_genl_event));
1277
1278 thermal_event->orig = orig;
1279 thermal_event->event = event;
1280
1281 /* send multicast genetlink message */
1282 result = genlmsg_end(skb, msg_header);
1283 if (result < 0) {
1284 nlmsg_free(skb);
1285 return result;
1286 }
1287
1288 result = genlmsg_multicast(skb, 0, thermal_event_mcgrp.id, GFP_ATOMIC);
1289 if (result)
1290 printk(KERN_INFO "failed to send netlink event:%d", result);
1291
1292 return result;
1293}
1294EXPORT_SYMBOL(generate_netlink_event);
1295
1296static int genetlink_init(void)
1297{
1298 int result;
1299
1300 result = genl_register_family(&thermal_event_genl_family);
1301 if (result)
1302 return result;
1303
1304 result = genl_register_mc_group(&thermal_event_genl_family,
1305 &thermal_event_mcgrp);
1306 if (result)
1307 genl_unregister_family(&thermal_event_genl_family);
1308 return result;
1309}
1310
1217static int __init thermal_init(void) 1311static int __init thermal_init(void)
1218{ 1312{
1219 int result = 0; 1313 int result = 0;
@@ -1225,9 +1319,15 @@ static int __init thermal_init(void)
1225 mutex_destroy(&thermal_idr_lock); 1319 mutex_destroy(&thermal_idr_lock);
1226 mutex_destroy(&thermal_list_lock); 1320 mutex_destroy(&thermal_list_lock);
1227 } 1321 }
1322 result = genetlink_init();
1228 return result; 1323 return result;
1229} 1324}
1230 1325
1326static void genetlink_exit(void)
1327{
1328 genl_unregister_family(&thermal_event_genl_family);
1329}
1330
1231static void __exit thermal_exit(void) 1331static void __exit thermal_exit(void)
1232{ 1332{
1233 class_unregister(&thermal_class); 1333 class_unregister(&thermal_class);
@@ -1235,7 +1335,8 @@ static void __exit thermal_exit(void)
1235 idr_destroy(&thermal_cdev_idr); 1335 idr_destroy(&thermal_cdev_idr);
1236 mutex_destroy(&thermal_idr_lock); 1336 mutex_destroy(&thermal_idr_lock);
1237 mutex_destroy(&thermal_list_lock); 1337 mutex_destroy(&thermal_list_lock);
1338 genetlink_exit();
1238} 1339}
1239 1340
1240subsys_initcall(thermal_init); 1341fs_initcall(thermal_init);
1241module_exit(thermal_exit); 1342module_exit(thermal_exit);
diff --git a/include/linux/thermal.h b/include/linux/thermal.h
index 1de8b9eb841b..784644961279 100644
--- a/include/linux/thermal.h
+++ b/include/linux/thermal.h
@@ -127,6 +127,37 @@ struct thermal_zone_device {
127 struct thermal_hwmon_attr temp_crit; /* hwmon sys attr */ 127 struct thermal_hwmon_attr temp_crit; /* hwmon sys attr */
128#endif 128#endif
129}; 129};
130/* Adding event notification support elements */
131#define THERMAL_GENL_FAMILY_NAME "thermal_event"
132#define THERMAL_GENL_VERSION 0x01
133#define THERMAL_GENL_MCAST_GROUP_NAME "thermal_mc_group"
134
135enum events {
136 THERMAL_AUX0,
137 THERMAL_AUX1,
138 THERMAL_CRITICAL,
139 THERMAL_DEV_FAULT,
140};
141
142struct thermal_genl_event {
143 u32 orig;
144 enum events event;
145};
146/* attributes of thermal_genl_family */
147enum {
148 THERMAL_GENL_ATTR_UNSPEC,
149 THERMAL_GENL_ATTR_EVENT,
150 __THERMAL_GENL_ATTR_MAX,
151};
152#define THERMAL_GENL_ATTR_MAX (__THERMAL_GENL_ATTR_MAX - 1)
153
154/* commands supported by the thermal_genl_family */
155enum {
156 THERMAL_GENL_CMD_UNSPEC,
157 THERMAL_GENL_CMD_EVENT,
158 __THERMAL_GENL_CMD_MAX,
159};
160#define THERMAL_GENL_CMD_MAX (__THERMAL_GENL_CMD_MAX - 1)
130 161
131struct thermal_zone_device *thermal_zone_device_register(char *, int, void *, 162struct thermal_zone_device *thermal_zone_device_register(char *, int, void *,
132 struct 163 struct
@@ -146,5 +177,6 @@ struct thermal_cooling_device *thermal_cooling_device_register(char *, void *,
146 thermal_cooling_device_ops 177 thermal_cooling_device_ops
147 *); 178 *);
148void thermal_cooling_device_unregister(struct thermal_cooling_device *); 179void thermal_cooling_device_unregister(struct thermal_cooling_device *);
180extern int generate_netlink_event(u32 orig, enum events event);
149 181
150#endif /* __THERMAL_H__ */ 182#endif /* __THERMAL_H__ */