diff options
-rw-r--r-- | Documentation/ABI/stable/thermal-notification | 4 | ||||
-rw-r--r-- | Documentation/thermal/sysfs-api.txt | 12 | ||||
-rw-r--r-- | drivers/thermal/Kconfig | 1 | ||||
-rw-r--r-- | drivers/thermal/thermal_sys.c | 103 | ||||
-rw-r--r-- | include/linux/thermal.h | 32 |
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 @@ | |||
1 | What: A notification mechanism for thermal related events | ||
2 | Description: | ||
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 | |||
282 | 4. Event Notification | ||
283 | |||
284 | The framework includes a simple notification mechanism, in the form of a | ||
285 | netlink event. Netlink socket initialization is done during the _init_ | ||
286 | of the framework. Drivers which intend to use the notification mechanism | ||
287 | just need to call generate_netlink_event() with two arguments viz | ||
288 | (originator, event). Typically the originator will be an integer assigned | ||
289 | to a thermal_zone_device when it registers itself with the framework. The | ||
290 | event will be one of:{THERMAL_AUX0, THERMAL_AUX1, THERMAL_CRITICAL, | ||
291 | THERMAL_DEV_FAULT}. Notification can be sent when the current temperature | ||
292 | crosses 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 | ||
5 | menuconfig THERMAL | 5 | menuconfig 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 | ||
36 | MODULE_AUTHOR("Zhang Rui"); | 38 | MODULE_AUTHOR("Zhang Rui"); |
37 | MODULE_DESCRIPTION("Generic thermal management sysfs support"); | 39 | MODULE_DESCRIPTION("Generic thermal management sysfs support"); |
@@ -58,6 +60,22 @@ static LIST_HEAD(thermal_tz_list); | |||
58 | static LIST_HEAD(thermal_cdev_list); | 60 | static LIST_HEAD(thermal_cdev_list); |
59 | static DEFINE_MUTEX(thermal_list_lock); | 61 | static DEFINE_MUTEX(thermal_list_lock); |
60 | 62 | ||
63 | static unsigned int thermal_event_seqnum; | ||
64 | |||
65 | static 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 | |||
72 | static struct genl_multicast_group thermal_event_mcgrp = { | ||
73 | .name = THERMAL_GENL_MCAST_GROUP_NAME, | ||
74 | }; | ||
75 | |||
76 | static int genetlink_init(void); | ||
77 | static void genetlink_exit(void); | ||
78 | |||
61 | static int get_idr(struct idr *idr, struct mutex *lock, int *id) | 79 | static 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 | ||
1215 | EXPORT_SYMBOL(thermal_zone_device_unregister); | 1233 | EXPORT_SYMBOL(thermal_zone_device_unregister); |
1216 | 1234 | ||
1235 | int 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 | } | ||
1294 | EXPORT_SYMBOL(generate_netlink_event); | ||
1295 | |||
1296 | static 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 | |||
1217 | static int __init thermal_init(void) | 1311 | static 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 | ||
1326 | static void genetlink_exit(void) | ||
1327 | { | ||
1328 | genl_unregister_family(&thermal_event_genl_family); | ||
1329 | } | ||
1330 | |||
1231 | static void __exit thermal_exit(void) | 1331 | static 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 | ||
1240 | subsys_initcall(thermal_init); | 1341 | fs_initcall(thermal_init); |
1241 | module_exit(thermal_exit); | 1342 | module_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 | |||
135 | enum events { | ||
136 | THERMAL_AUX0, | ||
137 | THERMAL_AUX1, | ||
138 | THERMAL_CRITICAL, | ||
139 | THERMAL_DEV_FAULT, | ||
140 | }; | ||
141 | |||
142 | struct thermal_genl_event { | ||
143 | u32 orig; | ||
144 | enum events event; | ||
145 | }; | ||
146 | /* attributes of thermal_genl_family */ | ||
147 | enum { | ||
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 */ | ||
155 | enum { | ||
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 | ||
131 | struct thermal_zone_device *thermal_zone_device_register(char *, int, void *, | 162 | struct 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 | *); |
148 | void thermal_cooling_device_unregister(struct thermal_cooling_device *); | 179 | void thermal_cooling_device_unregister(struct thermal_cooling_device *); |
180 | extern int generate_netlink_event(u32 orig, enum events event); | ||
149 | 181 | ||
150 | #endif /* __THERMAL_H__ */ | 182 | #endif /* __THERMAL_H__ */ |