mirror of https://gitee.com/openkylin/linux.git
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:
parent
e8a7e48bb2
commit
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
|
|---name: acpitz
|
||||||
|---temp1_input: 37000
|
|---temp1_input: 37000
|
||||||
|---temp1_crit: 100000
|
|---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
|
menuconfig THERMAL
|
||||||
tristate "Generic Thermal sysfs driver"
|
tristate "Generic Thermal sysfs driver"
|
||||||
|
depends on NET
|
||||||
help
|
help
|
||||||
Generic Thermal Sysfs driver offers a generic mechanism for
|
Generic Thermal Sysfs driver offers a generic mechanism for
|
||||||
thermal management. Usually it's made up of one or more thermal
|
thermal management. Usually it's made up of one or more thermal
|
||||||
|
|
|
@ -32,6 +32,8 @@
|
||||||
#include <linux/thermal.h>
|
#include <linux/thermal.h>
|
||||||
#include <linux/spinlock.h>
|
#include <linux/spinlock.h>
|
||||||
#include <linux/reboot.h>
|
#include <linux/reboot.h>
|
||||||
|
#include <net/netlink.h>
|
||||||
|
#include <net/genetlink.h>
|
||||||
|
|
||||||
MODULE_AUTHOR("Zhang Rui");
|
MODULE_AUTHOR("Zhang Rui");
|
||||||
MODULE_DESCRIPTION("Generic thermal management sysfs support");
|
MODULE_DESCRIPTION("Generic thermal management sysfs support");
|
||||||
|
@ -58,6 +60,22 @@ static LIST_HEAD(thermal_tz_list);
|
||||||
static LIST_HEAD(thermal_cdev_list);
|
static LIST_HEAD(thermal_cdev_list);
|
||||||
static DEFINE_MUTEX(thermal_list_lock);
|
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)
|
static int get_idr(struct idr *idr, struct mutex *lock, int *id)
|
||||||
{
|
{
|
||||||
int err;
|
int err;
|
||||||
|
@ -1214,6 +1232,82 @@ void thermal_zone_device_unregister(struct thermal_zone_device *tz)
|
||||||
|
|
||||||
EXPORT_SYMBOL(thermal_zone_device_unregister);
|
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)
|
static int __init thermal_init(void)
|
||||||
{
|
{
|
||||||
int result = 0;
|
int result = 0;
|
||||||
|
@ -1225,9 +1319,15 @@ static int __init thermal_init(void)
|
||||||
mutex_destroy(&thermal_idr_lock);
|
mutex_destroy(&thermal_idr_lock);
|
||||||
mutex_destroy(&thermal_list_lock);
|
mutex_destroy(&thermal_list_lock);
|
||||||
}
|
}
|
||||||
|
result = genetlink_init();
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void genetlink_exit(void)
|
||||||
|
{
|
||||||
|
genl_unregister_family(&thermal_event_genl_family);
|
||||||
|
}
|
||||||
|
|
||||||
static void __exit thermal_exit(void)
|
static void __exit thermal_exit(void)
|
||||||
{
|
{
|
||||||
class_unregister(&thermal_class);
|
class_unregister(&thermal_class);
|
||||||
|
@ -1235,7 +1335,8 @@ static void __exit thermal_exit(void)
|
||||||
idr_destroy(&thermal_cdev_idr);
|
idr_destroy(&thermal_cdev_idr);
|
||||||
mutex_destroy(&thermal_idr_lock);
|
mutex_destroy(&thermal_idr_lock);
|
||||||
mutex_destroy(&thermal_list_lock);
|
mutex_destroy(&thermal_list_lock);
|
||||||
|
genetlink_exit();
|
||||||
}
|
}
|
||||||
|
|
||||||
subsys_initcall(thermal_init);
|
fs_initcall(thermal_init);
|
||||||
module_exit(thermal_exit);
|
module_exit(thermal_exit);
|
||||||
|
|
|
@ -127,6 +127,37 @@ struct thermal_zone_device {
|
||||||
struct thermal_hwmon_attr temp_crit; /* hwmon sys attr */
|
struct thermal_hwmon_attr temp_crit; /* hwmon sys attr */
|
||||||
#endif
|
#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 thermal_zone_device *thermal_zone_device_register(char *, int, void *,
|
||||||
struct
|
struct
|
||||||
|
@ -146,5 +177,6 @@ struct thermal_cooling_device *thermal_cooling_device_register(char *, void *,
|
||||||
thermal_cooling_device_ops
|
thermal_cooling_device_ops
|
||||||
*);
|
*);
|
||||||
void thermal_cooling_device_unregister(struct thermal_cooling_device *);
|
void thermal_cooling_device_unregister(struct thermal_cooling_device *);
|
||||||
|
extern int generate_netlink_event(u32 orig, enum events event);
|
||||||
|
|
||||||
#endif /* __THERMAL_H__ */
|
#endif /* __THERMAL_H__ */
|
||||||
|
|
Loading…
Reference in New Issue