Skip to content

Commit

Permalink
thermal: Add event notification to thermal framework
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
durgadoss authored and lenb committed Jan 12, 2011
1 parent e8a7e48 commit 4cb1872
Show file tree
Hide file tree
Showing 5 changed files with 151 additions and 1 deletion.
4 changes: 4 additions & 0 deletions 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.
12 changes: 12 additions & 0 deletions Documentation/thermal/sysfs-api.txt
Expand Up @@ -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.
1 change: 1 addition & 0 deletions drivers/thermal/Kconfig
Expand Up @@ -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
Expand Down
103 changes: 102 additions & 1 deletion drivers/thermal/thermal_sys.c
Expand Up @@ -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");
Expand All @@ -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;
Expand Down Expand Up @@ -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;
Expand All @@ -1225,17 +1319,24 @@ 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);
idr_destroy(&thermal_tz_idr);
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);
32 changes: 32 additions & 0 deletions include/linux/thermal.h
Expand Up @@ -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
Expand All @@ -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__ */

0 comments on commit 4cb1872

Please sign in to comment.