thermal: Add event notification to thermal framework
This patch adds event notification support to the generic thermal sysfs framework in the kernel. The notification is in the form of a netlink event. Signed-off-by: R.Durgadoss <durgadoss.r@intel.com> Signed-off-by: Len Brown <len.brown@intel.com>
This commit is contained in:
Родитель
e8a7e48bb2
Коммит
4cb1872870
|
@ -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.
|
|
@ -278,3 +278,15 @@ method, the sys I/F structure will be built like this:
|
|||
|---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.
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
|
||||
menuconfig THERMAL
|
||||
tristate "Generic Thermal sysfs driver"
|
||||
depends on NET
|
||||
help
|
||||
Generic Thermal Sysfs driver offers a generic mechanism for
|
||||
thermal management. Usually it's made up of one or more thermal
|
||||
|
|
|
@ -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,22 @@ static LIST_HEAD(thermal_tz_list);
|
|||
static LIST_HEAD(thermal_cdev_list);
|
||||
static DEFINE_MUTEX(thermal_list_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;
|
||||
|
@ -1214,6 +1232,82 @@ void thermal_zone_device_unregister(struct thermal_zone_device *tz)
|
|||
|
||||
EXPORT_SYMBOL(thermal_zone_device_unregister);
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
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 int __init thermal_init(void)
|
||||
{
|
||||
int result = 0;
|
||||
|
@ -1225,9 +1319,15 @@ static int __init thermal_init(void)
|
|||
mutex_destroy(&thermal_idr_lock);
|
||||
mutex_destroy(&thermal_list_lock);
|
||||
}
|
||||
result = genetlink_init();
|
||||
return result;
|
||||
}
|
||||
|
||||
static void genetlink_exit(void)
|
||||
{
|
||||
genl_unregister_family(&thermal_event_genl_family);
|
||||
}
|
||||
|
||||
static void __exit thermal_exit(void)
|
||||
{
|
||||
class_unregister(&thermal_class);
|
||||
|
@ -1235,7 +1335,8 @@ static void __exit thermal_exit(void)
|
|||
idr_destroy(&thermal_cdev_idr);
|
||||
mutex_destroy(&thermal_idr_lock);
|
||||
mutex_destroy(&thermal_list_lock);
|
||||
genetlink_exit();
|
||||
}
|
||||
|
||||
subsys_initcall(thermal_init);
|
||||
fs_initcall(thermal_init);
|
||||
module_exit(thermal_exit);
|
||||
|
|
|
@ -127,6 +127,37 @@ struct thermal_zone_device {
|
|||
struct thermal_hwmon_attr temp_crit; /* hwmon sys attr */
|
||||
#endif
|
||||
};
|
||||
/* Adding event notification support elements */
|
||||
#define THERMAL_GENL_FAMILY_NAME "thermal_event"
|
||||
#define THERMAL_GENL_VERSION 0x01
|
||||
#define THERMAL_GENL_MCAST_GROUP_NAME "thermal_mc_group"
|
||||
|
||||
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)
|
||||
|
||||
struct thermal_zone_device *thermal_zone_device_register(char *, int, void *,
|
||||
struct
|
||||
|
@ -146,5 +177,6 @@ struct thermal_cooling_device *thermal_cooling_device_register(char *, void *,
|
|||
thermal_cooling_device_ops
|
||||
*);
|
||||
void thermal_cooling_device_unregister(struct thermal_cooling_device *);
|
||||
extern int generate_netlink_event(u32 orig, enum events event);
|
||||
|
||||
#endif /* __THERMAL_H__ */
|
||||
|
|
Загрузка…
Ссылка в новой задаче