diff options
Diffstat (limited to 'drivers/thermal/thermal_netlink.c')
| -rw-r--r-- | drivers/thermal/thermal_netlink.c | 445 |
1 files changed, 338 insertions, 107 deletions
diff --git a/drivers/thermal/thermal_netlink.c b/drivers/thermal/thermal_netlink.c index 08bc46c3ec7b..315a76b01f6a 100644 --- a/drivers/thermal/thermal_netlink.c +++ b/drivers/thermal/thermal_netlink.c @@ -7,15 +7,17 @@ * Generic netlink for thermal management framework */ #include <linux/module.h> +#include <linux/notifier.h> #include <linux/kernel.h> +#include <net/sock.h> #include <net/genetlink.h> #include <uapi/linux/thermal.h> #include "thermal_core.h" static const struct genl_multicast_group thermal_genl_mcgrps[] = { - { .name = THERMAL_GENL_SAMPLING_GROUP_NAME, }, - { .name = THERMAL_GENL_EVENT_GROUP_NAME, }, + [THERMAL_GENL_SAMPLING_GROUP] = { .name = THERMAL_GENL_SAMPLING_GROUP_NAME, }, + [THERMAL_GENL_EVENT_GROUP] = { .name = THERMAL_GENL_EVENT_GROUP_NAME, }, }; static const struct nla_policy thermal_genl_policy[THERMAL_GENL_ATTR_MAX + 1] = { @@ -48,6 +50,11 @@ static const struct nla_policy thermal_genl_policy[THERMAL_GENL_ATTR_MAX + 1] = [THERMAL_GENL_ATTR_CPU_CAPABILITY_ID] = { .type = NLA_U32 }, [THERMAL_GENL_ATTR_CPU_CAPABILITY_PERFORMANCE] = { .type = NLA_U32 }, [THERMAL_GENL_ATTR_CPU_CAPABILITY_EFFICIENCY] = { .type = NLA_U32 }, + + /* Thresholds */ + [THERMAL_GENL_ATTR_THRESHOLD] = { .type = NLA_NESTED }, + [THERMAL_GENL_ATTR_THRESHOLD_TEMP] = { .type = NLA_U32 }, + [THERMAL_GENL_ATTR_THRESHOLD_DIRECTION] = { .type = NLA_U32 }, }; struct param { @@ -61,6 +68,8 @@ struct param { int trip_type; int trip_hyst; int temp; + int prev_temp; + int direction; int cdev_state; int cdev_max_state; struct thermal_genl_cpu_caps *cpu_capabilities; @@ -69,7 +78,13 @@ struct param { typedef int (*cb_t)(struct param *); -static struct genl_family thermal_gnl_family; +static struct genl_family thermal_genl_family; +static BLOCKING_NOTIFIER_HEAD(thermal_genl_chain); + +static int thermal_group_has_listeners(enum thermal_genl_multicast_groups group) +{ + return genl_has_listeners(&thermal_genl_family, &init_net, group); +} /************************** Sampling encoding *******************************/ @@ -78,11 +93,14 @@ int thermal_genl_sampling_temp(int id, int temp) struct sk_buff *skb; void *hdr; + if (!thermal_group_has_listeners(THERMAL_GENL_SAMPLING_GROUP)) + return 0; + skb = genlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL); if (!skb) return -ENOMEM; - hdr = genlmsg_put(skb, 0, 0, &thermal_gnl_family, 0, + hdr = genlmsg_put(skb, 0, 0, &thermal_genl_family, 0, THERMAL_GENL_SAMPLING_TEMP); if (!hdr) goto out_free; @@ -95,7 +113,7 @@ int thermal_genl_sampling_temp(int id, int temp) genlmsg_end(skb, hdr); - genlmsg_multicast(&thermal_gnl_family, skb, 0, 0, GFP_KERNEL); + genlmsg_multicast(&thermal_genl_family, skb, 0, THERMAL_GENL_SAMPLING_GROUP, GFP_KERNEL); return 0; out_cancel: @@ -135,7 +153,7 @@ static int thermal_genl_event_tz_trip_up(struct param *p) return 0; } -static int thermal_genl_event_tz_trip_add(struct param *p) +static int thermal_genl_event_tz_trip_change(struct param *p) { if (nla_put_u32(p->msg, THERMAL_GENL_ATTR_TZ_ID, p->tz_id) || nla_put_u32(p->msg, THERMAL_GENL_ATTR_TZ_TRIP_ID, p->trip_id) || @@ -147,15 +165,6 @@ static int thermal_genl_event_tz_trip_add(struct param *p) return 0; } -static int thermal_genl_event_tz_trip_delete(struct param *p) -{ - if (nla_put_u32(p->msg, THERMAL_GENL_ATTR_TZ_ID, p->tz_id) || - nla_put_u32(p->msg, THERMAL_GENL_ATTR_TZ_TRIP_ID, p->trip_id)) - return -EMSGSIZE; - - return 0; -} - static int thermal_genl_event_cdev_add(struct param *p) { if (nla_put_string(p->msg, THERMAL_GENL_ATTR_CDEV_NAME, @@ -233,6 +242,34 @@ out_cancel_nest: return -EMSGSIZE; } +static int thermal_genl_event_threshold_add(struct param *p) +{ + if (nla_put_u32(p->msg, THERMAL_GENL_ATTR_TZ_ID, p->tz_id) || + nla_put_u32(p->msg, THERMAL_GENL_ATTR_THRESHOLD_TEMP, p->temp) || + nla_put_u32(p->msg, THERMAL_GENL_ATTR_THRESHOLD_DIRECTION, p->direction)) + return -EMSGSIZE; + + return 0; +} + +static int thermal_genl_event_threshold_flush(struct param *p) +{ + if (nla_put_u32(p->msg, THERMAL_GENL_ATTR_TZ_ID, p->tz_id)) + return -EMSGSIZE; + + return 0; +} + +static int thermal_genl_event_threshold_up(struct param *p) +{ + if (nla_put_u32(p->msg, THERMAL_GENL_ATTR_TZ_ID, p->tz_id) || + nla_put_u32(p->msg, THERMAL_GENL_ATTR_TZ_PREV_TEMP, p->prev_temp) || + nla_put_u32(p->msg, THERMAL_GENL_ATTR_TZ_TEMP, p->temp)) + return -EMSGSIZE; + + return 0; +} + int thermal_genl_event_tz_delete(struct param *p) __attribute__((alias("thermal_genl_event_tz"))); @@ -245,8 +282,11 @@ int thermal_genl_event_tz_disable(struct param *p) int thermal_genl_event_tz_trip_down(struct param *p) __attribute__((alias("thermal_genl_event_tz_trip_up"))); -int thermal_genl_event_tz_trip_change(struct param *p) - __attribute__((alias("thermal_genl_event_tz_trip_add"))); +int thermal_genl_event_threshold_delete(struct param *p) + __attribute__((alias("thermal_genl_event_threshold_add"))); + +int thermal_genl_event_threshold_down(struct param *p) + __attribute__((alias("thermal_genl_event_threshold_up"))); static cb_t event_cb[] = { [THERMAL_GENL_EVENT_TZ_CREATE] = thermal_genl_event_tz_create, @@ -256,13 +296,16 @@ static cb_t event_cb[] = { [THERMAL_GENL_EVENT_TZ_TRIP_UP] = thermal_genl_event_tz_trip_up, [THERMAL_GENL_EVENT_TZ_TRIP_DOWN] = thermal_genl_event_tz_trip_down, [THERMAL_GENL_EVENT_TZ_TRIP_CHANGE] = thermal_genl_event_tz_trip_change, - [THERMAL_GENL_EVENT_TZ_TRIP_ADD] = thermal_genl_event_tz_trip_add, - [THERMAL_GENL_EVENT_TZ_TRIP_DELETE] = thermal_genl_event_tz_trip_delete, [THERMAL_GENL_EVENT_CDEV_ADD] = thermal_genl_event_cdev_add, [THERMAL_GENL_EVENT_CDEV_DELETE] = thermal_genl_event_cdev_delete, [THERMAL_GENL_EVENT_CDEV_STATE_UPDATE] = thermal_genl_event_cdev_state_update, [THERMAL_GENL_EVENT_TZ_GOV_CHANGE] = thermal_genl_event_gov_change, [THERMAL_GENL_EVENT_CPU_CAPABILITY_CHANGE] = thermal_genl_event_cpu_capability_change, + [THERMAL_GENL_EVENT_THRESHOLD_ADD] = thermal_genl_event_threshold_add, + [THERMAL_GENL_EVENT_THRESHOLD_DELETE] = thermal_genl_event_threshold_delete, + [THERMAL_GENL_EVENT_THRESHOLD_FLUSH] = thermal_genl_event_threshold_flush, + [THERMAL_GENL_EVENT_THRESHOLD_DOWN] = thermal_genl_event_threshold_down, + [THERMAL_GENL_EVENT_THRESHOLD_UP] = thermal_genl_event_threshold_up, }; /* @@ -275,12 +318,15 @@ static int thermal_genl_send_event(enum thermal_genl_event event, int ret = -EMSGSIZE; void *hdr; + if (!thermal_group_has_listeners(THERMAL_GENL_EVENT_GROUP)) + return 0; + msg = genlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL); if (!msg) return -ENOMEM; p->msg = msg; - hdr = genlmsg_put(msg, 0, 0, &thermal_gnl_family, 0, event); + hdr = genlmsg_put(msg, 0, 0, &thermal_genl_family, 0, event); if (!hdr) goto out_free_msg; @@ -290,7 +336,7 @@ static int thermal_genl_send_event(enum thermal_genl_event event, genlmsg_end(msg, hdr); - genlmsg_multicast(&thermal_gnl_family, msg, 0, 1, GFP_KERNEL); + genlmsg_multicast(&thermal_genl_family, msg, 0, THERMAL_GENL_EVENT_GROUP, GFP_KERNEL); return 0; @@ -302,100 +348,93 @@ out_free_msg: return ret; } -int thermal_notify_tz_create(int tz_id, const char *name) +int thermal_notify_tz_create(const struct thermal_zone_device *tz) { - struct param p = { .tz_id = tz_id, .name = name }; + struct param p = { .tz_id = tz->id, .name = tz->type }; return thermal_genl_send_event(THERMAL_GENL_EVENT_TZ_CREATE, &p); } -int thermal_notify_tz_delete(int tz_id) +int thermal_notify_tz_delete(const struct thermal_zone_device *tz) { - struct param p = { .tz_id = tz_id }; + struct param p = { .tz_id = tz->id }; return thermal_genl_send_event(THERMAL_GENL_EVENT_TZ_DELETE, &p); } -int thermal_notify_tz_enable(int tz_id) +int thermal_notify_tz_enable(const struct thermal_zone_device *tz) { - struct param p = { .tz_id = tz_id }; + struct param p = { .tz_id = tz->id }; return thermal_genl_send_event(THERMAL_GENL_EVENT_TZ_ENABLE, &p); } -int thermal_notify_tz_disable(int tz_id) +int thermal_notify_tz_disable(const struct thermal_zone_device *tz) { - struct param p = { .tz_id = tz_id }; + struct param p = { .tz_id = tz->id }; return thermal_genl_send_event(THERMAL_GENL_EVENT_TZ_DISABLE, &p); } -int thermal_notify_tz_trip_down(int tz_id, int trip_id, int temp) +int thermal_notify_tz_trip_down(const struct thermal_zone_device *tz, + const struct thermal_trip *trip) { - struct param p = { .tz_id = tz_id, .trip_id = trip_id, .temp = temp }; + struct param p = { .tz_id = tz->id, + .trip_id = thermal_zone_trip_id(tz, trip), + .temp = tz->temperature }; return thermal_genl_send_event(THERMAL_GENL_EVENT_TZ_TRIP_DOWN, &p); } -int thermal_notify_tz_trip_up(int tz_id, int trip_id, int temp) +int thermal_notify_tz_trip_up(const struct thermal_zone_device *tz, + const struct thermal_trip *trip) { - struct param p = { .tz_id = tz_id, .trip_id = trip_id, .temp = temp }; + struct param p = { .tz_id = tz->id, + .trip_id = thermal_zone_trip_id(tz, trip), + .temp = tz->temperature }; return thermal_genl_send_event(THERMAL_GENL_EVENT_TZ_TRIP_UP, &p); } -int thermal_notify_tz_trip_add(int tz_id, int trip_id, int trip_type, - int trip_temp, int trip_hyst) -{ - struct param p = { .tz_id = tz_id, .trip_id = trip_id, - .trip_type = trip_type, .trip_temp = trip_temp, - .trip_hyst = trip_hyst }; - - return thermal_genl_send_event(THERMAL_GENL_EVENT_TZ_TRIP_ADD, &p); -} - -int thermal_notify_tz_trip_delete(int tz_id, int trip_id) +int thermal_notify_tz_trip_change(const struct thermal_zone_device *tz, + const struct thermal_trip *trip) { - struct param p = { .tz_id = tz_id, .trip_id = trip_id }; - - return thermal_genl_send_event(THERMAL_GENL_EVENT_TZ_TRIP_DELETE, &p); -} - -int thermal_notify_tz_trip_change(int tz_id, int trip_id, int trip_type, - int trip_temp, int trip_hyst) -{ - struct param p = { .tz_id = tz_id, .trip_id = trip_id, - .trip_type = trip_type, .trip_temp = trip_temp, - .trip_hyst = trip_hyst }; + struct param p = { .tz_id = tz->id, + .trip_id = thermal_zone_trip_id(tz, trip), + .trip_type = trip->type, + .trip_temp = trip->temperature, + .trip_hyst = trip->hysteresis }; return thermal_genl_send_event(THERMAL_GENL_EVENT_TZ_TRIP_CHANGE, &p); } -int thermal_notify_cdev_state_update(int cdev_id, int cdev_state) +int thermal_notify_cdev_state_update(const struct thermal_cooling_device *cdev, + int state) { - struct param p = { .cdev_id = cdev_id, .cdev_state = cdev_state }; + struct param p = { .cdev_id = cdev->id, .cdev_state = state }; return thermal_genl_send_event(THERMAL_GENL_EVENT_CDEV_STATE_UPDATE, &p); } -int thermal_notify_cdev_add(int cdev_id, const char *name, int cdev_max_state) +int thermal_notify_cdev_add(const struct thermal_cooling_device *cdev) { - struct param p = { .cdev_id = cdev_id, .name = name, - .cdev_max_state = cdev_max_state }; + struct param p = { .cdev_id = cdev->id, .name = cdev->type, + .cdev_max_state = cdev->max_state }; return thermal_genl_send_event(THERMAL_GENL_EVENT_CDEV_ADD, &p); } -int thermal_notify_cdev_delete(int cdev_id) +int thermal_notify_cdev_delete(const struct thermal_cooling_device *cdev) { - struct param p = { .cdev_id = cdev_id }; + struct param p = { .cdev_id = cdev->id }; return thermal_genl_send_event(THERMAL_GENL_EVENT_CDEV_DELETE, &p); } -int thermal_notify_tz_gov_change(int tz_id, const char *name) +int thermal_notify_tz_gov_change(const struct thermal_zone_device *tz, + const char *name) { - struct param p = { .tz_id = tz_id, .name = name }; + struct param p = { .tz_id = tz->id, .name = name }; return thermal_genl_send_event(THERMAL_GENL_EVENT_TZ_GOV_CHANGE, &p); } @@ -409,6 +448,43 @@ int thermal_genl_cpu_capability_event(int count, } EXPORT_SYMBOL_GPL(thermal_genl_cpu_capability_event); +int thermal_notify_threshold_add(const struct thermal_zone_device *tz, + int temperature, int direction) +{ + struct param p = { .tz_id = tz->id, .temp = temperature, .direction = direction }; + + return thermal_genl_send_event(THERMAL_GENL_EVENT_THRESHOLD_ADD, &p); +} + +int thermal_notify_threshold_delete(const struct thermal_zone_device *tz, + int temperature, int direction) +{ + struct param p = { .tz_id = tz->id, .temp = temperature, .direction = direction }; + + return thermal_genl_send_event(THERMAL_GENL_EVENT_THRESHOLD_DELETE, &p); +} + +int thermal_notify_threshold_flush(const struct thermal_zone_device *tz) +{ + struct param p = { .tz_id = tz->id }; + + return thermal_genl_send_event(THERMAL_GENL_EVENT_THRESHOLD_FLUSH, &p); +} + +int thermal_notify_threshold_down(const struct thermal_zone_device *tz) +{ + struct param p = { .tz_id = tz->id, .temp = tz->temperature, .prev_temp = tz->last_temperature }; + + return thermal_genl_send_event(THERMAL_GENL_EVENT_THRESHOLD_DOWN, &p); +} + +int thermal_notify_threshold_up(const struct thermal_zone_device *tz) +{ + struct param p = { .tz_id = tz->id, .temp = tz->temperature, .prev_temp = tz->last_temperature }; + + return thermal_genl_send_event(THERMAL_GENL_EVENT_THRESHOLD_UP, &p); +} + /*************************** Command encoding ********************************/ static int __thermal_genl_cmd_tz_get_id(struct thermal_zone_device *tz, @@ -450,17 +526,16 @@ out_cancel_nest: static int thermal_genl_cmd_tz_get_trip(struct param *p) { struct sk_buff *msg = p->msg; - struct thermal_zone_device *tz; + const struct thermal_trip_desc *td; struct nlattr *start_trip; - struct thermal_trip trip; - int ret, i, id; + int id; if (!p->attrs[THERMAL_GENL_ATTR_TZ_ID]) return -EINVAL; id = nla_get_u32(p->attrs[THERMAL_GENL_ATTR_TZ_ID]); - tz = thermal_zone_get_by_id(id); + CLASS(thermal_zone_get_by_id, tz)(id); if (!tz) return -EINVAL; @@ -468,37 +543,27 @@ static int thermal_genl_cmd_tz_get_trip(struct param *p) if (!start_trip) return -EMSGSIZE; - mutex_lock(&tz->lock); + guard(thermal_zone)(tz); - for (i = 0; i < tz->num_trips; i++) { + for_each_trip_desc(tz, td) { + const struct thermal_trip *trip = &td->trip; - ret = __thermal_zone_get_trip(tz, i, &trip); - if (ret) - goto out_cancel_nest; - - if (nla_put_u32(msg, THERMAL_GENL_ATTR_TZ_TRIP_ID, i) || - nla_put_u32(msg, THERMAL_GENL_ATTR_TZ_TRIP_TYPE, trip.type) || - nla_put_u32(msg, THERMAL_GENL_ATTR_TZ_TRIP_TEMP, trip.temperature) || - nla_put_u32(msg, THERMAL_GENL_ATTR_TZ_TRIP_HYST, trip.hysteresis)) - goto out_cancel_nest; + if (nla_put_u32(msg, THERMAL_GENL_ATTR_TZ_TRIP_ID, + thermal_zone_trip_id(tz, trip)) || + nla_put_u32(msg, THERMAL_GENL_ATTR_TZ_TRIP_TYPE, trip->type) || + nla_put_u32(msg, THERMAL_GENL_ATTR_TZ_TRIP_TEMP, trip->temperature) || + nla_put_u32(msg, THERMAL_GENL_ATTR_TZ_TRIP_HYST, trip->hysteresis)) + return -EMSGSIZE; } - mutex_unlock(&tz->lock); - nla_nest_end(msg, start_trip); return 0; - -out_cancel_nest: - mutex_unlock(&tz->lock); - - return -EMSGSIZE; } static int thermal_genl_cmd_tz_get_temp(struct param *p) { struct sk_buff *msg = p->msg; - struct thermal_zone_device *tz; int temp, ret, id; if (!p->attrs[THERMAL_GENL_ATTR_TZ_ID]) @@ -506,7 +571,7 @@ static int thermal_genl_cmd_tz_get_temp(struct param *p) id = nla_get_u32(p->attrs[THERMAL_GENL_ATTR_TZ_ID]); - tz = thermal_zone_get_by_id(id); + CLASS(thermal_zone_get_by_id, tz)(id); if (!tz) return -EINVAL; @@ -524,28 +589,25 @@ static int thermal_genl_cmd_tz_get_temp(struct param *p) static int thermal_genl_cmd_tz_get_gov(struct param *p) { struct sk_buff *msg = p->msg; - struct thermal_zone_device *tz; - int id, ret = 0; + int id; if (!p->attrs[THERMAL_GENL_ATTR_TZ_ID]) return -EINVAL; id = nla_get_u32(p->attrs[THERMAL_GENL_ATTR_TZ_ID]); - tz = thermal_zone_get_by_id(id); + CLASS(thermal_zone_get_by_id, tz)(id); if (!tz) return -EINVAL; - mutex_lock(&tz->lock); + guard(thermal_zone)(tz); if (nla_put_u32(msg, THERMAL_GENL_ATTR_TZ_ID, id) || nla_put_string(msg, THERMAL_GENL_ATTR_TZ_GOV_NAME, tz->governor->name)) - ret = -EMSGSIZE; - - mutex_unlock(&tz->lock); + return -EMSGSIZE; - return ret; + return 0; } static int __thermal_genl_cmd_cdev_get(struct thermal_cooling_device *cdev, @@ -585,12 +647,128 @@ out_cancel_nest: return ret; } +static int __thermal_genl_cmd_threshold_get(struct user_threshold *threshold, void *arg) +{ + struct sk_buff *msg = arg; + + if (nla_put_u32(msg, THERMAL_GENL_ATTR_THRESHOLD_TEMP, threshold->temperature) || + nla_put_u32(msg, THERMAL_GENL_ATTR_THRESHOLD_DIRECTION, threshold->direction)) + return -1; + + return 0; +} + +static int thermal_genl_cmd_threshold_get(struct param *p) +{ + struct sk_buff *msg = p->msg; + struct nlattr *start_trip; + int id, ret; + + if (!p->attrs[THERMAL_GENL_ATTR_TZ_ID]) + return -EINVAL; + + id = nla_get_u32(p->attrs[THERMAL_GENL_ATTR_TZ_ID]); + + CLASS(thermal_zone_get_by_id, tz)(id); + if (!tz) + return -EINVAL; + + start_trip = nla_nest_start(msg, THERMAL_GENL_ATTR_THRESHOLD); + if (!start_trip) + return -EMSGSIZE; + + ret = thermal_thresholds_for_each(tz, __thermal_genl_cmd_threshold_get, msg); + if (ret) + return -EMSGSIZE; + + nla_nest_end(msg, start_trip); + + return 0; +} + +static int thermal_genl_cmd_threshold_add(struct param *p) +{ + int id, temp, direction; + + if (!capable(CAP_SYS_ADMIN)) + return -EPERM; + + if (!p->attrs[THERMAL_GENL_ATTR_TZ_ID] || + !p->attrs[THERMAL_GENL_ATTR_THRESHOLD_TEMP] || + !p->attrs[THERMAL_GENL_ATTR_THRESHOLD_DIRECTION]) + return -EINVAL; + + id = nla_get_u32(p->attrs[THERMAL_GENL_ATTR_TZ_ID]); + temp = nla_get_u32(p->attrs[THERMAL_GENL_ATTR_THRESHOLD_TEMP]); + direction = nla_get_u32(p->attrs[THERMAL_GENL_ATTR_THRESHOLD_DIRECTION]); + + CLASS(thermal_zone_get_by_id, tz)(id); + if (!tz) + return -EINVAL; + + guard(thermal_zone)(tz); + + return thermal_thresholds_add(tz, temp, direction); +} + +static int thermal_genl_cmd_threshold_delete(struct param *p) +{ + int id, temp, direction; + + if (!capable(CAP_SYS_ADMIN)) + return -EPERM; + + if (!p->attrs[THERMAL_GENL_ATTR_TZ_ID] || + !p->attrs[THERMAL_GENL_ATTR_THRESHOLD_TEMP] || + !p->attrs[THERMAL_GENL_ATTR_THRESHOLD_DIRECTION]) + return -EINVAL; + + id = nla_get_u32(p->attrs[THERMAL_GENL_ATTR_TZ_ID]); + temp = nla_get_u32(p->attrs[THERMAL_GENL_ATTR_THRESHOLD_TEMP]); + direction = nla_get_u32(p->attrs[THERMAL_GENL_ATTR_THRESHOLD_DIRECTION]); + + CLASS(thermal_zone_get_by_id, tz)(id); + if (!tz) + return -EINVAL; + + guard(thermal_zone)(tz); + + return thermal_thresholds_delete(tz, temp, direction); +} + +static int thermal_genl_cmd_threshold_flush(struct param *p) +{ + int id; + + if (!capable(CAP_SYS_ADMIN)) + return -EPERM; + + if (!p->attrs[THERMAL_GENL_ATTR_TZ_ID]) + return -EINVAL; + + id = nla_get_u32(p->attrs[THERMAL_GENL_ATTR_TZ_ID]); + + CLASS(thermal_zone_get_by_id, tz)(id); + if (!tz) + return -EINVAL; + + guard(thermal_zone)(tz); + + thermal_thresholds_flush(tz); + + return 0; +} + static cb_t cmd_cb[] = { - [THERMAL_GENL_CMD_TZ_GET_ID] = thermal_genl_cmd_tz_get_id, - [THERMAL_GENL_CMD_TZ_GET_TRIP] = thermal_genl_cmd_tz_get_trip, - [THERMAL_GENL_CMD_TZ_GET_TEMP] = thermal_genl_cmd_tz_get_temp, - [THERMAL_GENL_CMD_TZ_GET_GOV] = thermal_genl_cmd_tz_get_gov, - [THERMAL_GENL_CMD_CDEV_GET] = thermal_genl_cmd_cdev_get, + [THERMAL_GENL_CMD_TZ_GET_ID] = thermal_genl_cmd_tz_get_id, + [THERMAL_GENL_CMD_TZ_GET_TRIP] = thermal_genl_cmd_tz_get_trip, + [THERMAL_GENL_CMD_TZ_GET_TEMP] = thermal_genl_cmd_tz_get_temp, + [THERMAL_GENL_CMD_TZ_GET_GOV] = thermal_genl_cmd_tz_get_gov, + [THERMAL_GENL_CMD_CDEV_GET] = thermal_genl_cmd_cdev_get, + [THERMAL_GENL_CMD_THRESHOLD_GET] = thermal_genl_cmd_threshold_get, + [THERMAL_GENL_CMD_THRESHOLD_ADD] = thermal_genl_cmd_threshold_add, + [THERMAL_GENL_CMD_THRESHOLD_DELETE] = thermal_genl_cmd_threshold_delete, + [THERMAL_GENL_CMD_THRESHOLD_FLUSH] = thermal_genl_cmd_threshold_flush, }; static int thermal_genl_cmd_dumpit(struct sk_buff *skb, @@ -602,7 +780,7 @@ static int thermal_genl_cmd_dumpit(struct sk_buff *skb, int ret; void *hdr; - hdr = genlmsg_put(skb, 0, 0, &thermal_gnl_family, 0, cmd); + hdr = genlmsg_put(skb, 0, 0, &thermal_genl_family, 0, cmd); if (!hdr) return -EMSGSIZE; @@ -634,7 +812,7 @@ static int thermal_genl_cmd_doit(struct sk_buff *skb, return -ENOMEM; p.msg = msg; - hdr = genlmsg_put_reply(msg, info, &thermal_gnl_family, 0, cmd); + hdr = genlmsg_put_reply(msg, info, &thermal_genl_family, 0, cmd); if (!hdr) goto out_free_msg; @@ -654,6 +832,27 @@ out_free_msg: return ret; } +static int thermal_genl_bind(int mcgrp) +{ + struct thermal_genl_notify n = { .mcgrp = mcgrp }; + + if (WARN_ON_ONCE(mcgrp > THERMAL_GENL_MAX_GROUP)) + return -EINVAL; + + blocking_notifier_call_chain(&thermal_genl_chain, THERMAL_NOTIFY_BIND, &n); + return 0; +} + +static void thermal_genl_unbind(int mcgrp) +{ + struct thermal_genl_notify n = { .mcgrp = mcgrp }; + + if (WARN_ON_ONCE(mcgrp > THERMAL_GENL_MAX_GROUP)) + return; + + blocking_notifier_call_chain(&thermal_genl_chain, THERMAL_NOTIFY_UNBIND, &n); +} + static const struct genl_small_ops thermal_genl_ops[] = { { .cmd = THERMAL_GENL_CMD_TZ_GET_ID, @@ -680,27 +879,59 @@ static const struct genl_small_ops thermal_genl_ops[] = { .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP, .dumpit = thermal_genl_cmd_dumpit, }, + { + .cmd = THERMAL_GENL_CMD_THRESHOLD_GET, + .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP, + .doit = thermal_genl_cmd_doit, + }, + { + .cmd = THERMAL_GENL_CMD_THRESHOLD_ADD, + .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP, + .doit = thermal_genl_cmd_doit, + }, + { + .cmd = THERMAL_GENL_CMD_THRESHOLD_DELETE, + .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP, + .doit = thermal_genl_cmd_doit, + }, + { + .cmd = THERMAL_GENL_CMD_THRESHOLD_FLUSH, + .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP, + .doit = thermal_genl_cmd_doit, + }, }; -static struct genl_family thermal_gnl_family __ro_after_init = { +static struct genl_family thermal_genl_family __ro_after_init = { .hdrsize = 0, .name = THERMAL_GENL_FAMILY_NAME, .version = THERMAL_GENL_VERSION, .maxattr = THERMAL_GENL_ATTR_MAX, .policy = thermal_genl_policy, + .bind = thermal_genl_bind, + .unbind = thermal_genl_unbind, .small_ops = thermal_genl_ops, .n_small_ops = ARRAY_SIZE(thermal_genl_ops), - .resv_start_op = THERMAL_GENL_CMD_CDEV_GET + 1, + .resv_start_op = __THERMAL_GENL_CMD_MAX, .mcgrps = thermal_genl_mcgrps, .n_mcgrps = ARRAY_SIZE(thermal_genl_mcgrps), }; +int thermal_genl_register_notifier(struct notifier_block *nb) +{ + return blocking_notifier_chain_register(&thermal_genl_chain, nb); +} + +int thermal_genl_unregister_notifier(struct notifier_block *nb) +{ + return blocking_notifier_chain_unregister(&thermal_genl_chain, nb); +} + int __init thermal_netlink_init(void) { - return genl_register_family(&thermal_gnl_family); + return genl_register_family(&thermal_genl_family); } void __init thermal_netlink_exit(void) { - genl_unregister_family(&thermal_gnl_family); + genl_unregister_family(&thermal_genl_family); } |
