11ce50e7dSDaniel Lezcano // SPDX-License-Identifier: GPL-2.0
21ce50e7dSDaniel Lezcano /*
31ce50e7dSDaniel Lezcano * Copyright 2020 Linaro Limited
41ce50e7dSDaniel Lezcano *
51ce50e7dSDaniel Lezcano * Author: Daniel Lezcano <daniel.lezcano@linaro.org>
61ce50e7dSDaniel Lezcano *
71ce50e7dSDaniel Lezcano * Generic netlink for thermal management framework
81ce50e7dSDaniel Lezcano */
91ce50e7dSDaniel Lezcano #include <linux/module.h>
101ce50e7dSDaniel Lezcano #include <linux/kernel.h>
111ce50e7dSDaniel Lezcano #include <net/genetlink.h>
121ce50e7dSDaniel Lezcano #include <uapi/linux/thermal.h>
131ce50e7dSDaniel Lezcano
141ce50e7dSDaniel Lezcano #include "thermal_core.h"
151ce50e7dSDaniel Lezcano
161ce50e7dSDaniel Lezcano static const struct genl_multicast_group thermal_genl_mcgrps[] = {
171ce50e7dSDaniel Lezcano { .name = THERMAL_GENL_SAMPLING_GROUP_NAME, },
181ce50e7dSDaniel Lezcano { .name = THERMAL_GENL_EVENT_GROUP_NAME, },
191ce50e7dSDaniel Lezcano };
201ce50e7dSDaniel Lezcano
211ce50e7dSDaniel Lezcano static const struct nla_policy thermal_genl_policy[THERMAL_GENL_ATTR_MAX + 1] = {
221ce50e7dSDaniel Lezcano /* Thermal zone */
231ce50e7dSDaniel Lezcano [THERMAL_GENL_ATTR_TZ] = { .type = NLA_NESTED },
241ce50e7dSDaniel Lezcano [THERMAL_GENL_ATTR_TZ_ID] = { .type = NLA_U32 },
251ce50e7dSDaniel Lezcano [THERMAL_GENL_ATTR_TZ_TEMP] = { .type = NLA_U32 },
261ce50e7dSDaniel Lezcano [THERMAL_GENL_ATTR_TZ_TRIP] = { .type = NLA_NESTED },
271ce50e7dSDaniel Lezcano [THERMAL_GENL_ATTR_TZ_TRIP_ID] = { .type = NLA_U32 },
281ce50e7dSDaniel Lezcano [THERMAL_GENL_ATTR_TZ_TRIP_TEMP] = { .type = NLA_U32 },
291ce50e7dSDaniel Lezcano [THERMAL_GENL_ATTR_TZ_TRIP_TYPE] = { .type = NLA_U32 },
301ce50e7dSDaniel Lezcano [THERMAL_GENL_ATTR_TZ_TRIP_HYST] = { .type = NLA_U32 },
311ce50e7dSDaniel Lezcano [THERMAL_GENL_ATTR_TZ_MODE] = { .type = NLA_U32 },
321ce50e7dSDaniel Lezcano [THERMAL_GENL_ATTR_TZ_CDEV_WEIGHT] = { .type = NLA_U32 },
331ce50e7dSDaniel Lezcano [THERMAL_GENL_ATTR_TZ_NAME] = { .type = NLA_STRING,
341ce50e7dSDaniel Lezcano .len = THERMAL_NAME_LENGTH },
351ce50e7dSDaniel Lezcano /* Governor(s) */
361ce50e7dSDaniel Lezcano [THERMAL_GENL_ATTR_TZ_GOV] = { .type = NLA_NESTED },
371ce50e7dSDaniel Lezcano [THERMAL_GENL_ATTR_TZ_GOV_NAME] = { .type = NLA_STRING,
381ce50e7dSDaniel Lezcano .len = THERMAL_NAME_LENGTH },
391ce50e7dSDaniel Lezcano /* Cooling devices */
401ce50e7dSDaniel Lezcano [THERMAL_GENL_ATTR_CDEV] = { .type = NLA_NESTED },
411ce50e7dSDaniel Lezcano [THERMAL_GENL_ATTR_CDEV_ID] = { .type = NLA_U32 },
421ce50e7dSDaniel Lezcano [THERMAL_GENL_ATTR_CDEV_CUR_STATE] = { .type = NLA_U32 },
431ce50e7dSDaniel Lezcano [THERMAL_GENL_ATTR_CDEV_MAX_STATE] = { .type = NLA_U32 },
441ce50e7dSDaniel Lezcano [THERMAL_GENL_ATTR_CDEV_NAME] = { .type = NLA_STRING,
451ce50e7dSDaniel Lezcano .len = THERMAL_NAME_LENGTH },
46e4b1eb24SSrinivas Pandruvada /* CPU capabilities */
47e4b1eb24SSrinivas Pandruvada [THERMAL_GENL_ATTR_CPU_CAPABILITY] = { .type = NLA_NESTED },
48e4b1eb24SSrinivas Pandruvada [THERMAL_GENL_ATTR_CPU_CAPABILITY_ID] = { .type = NLA_U32 },
49e4b1eb24SSrinivas Pandruvada [THERMAL_GENL_ATTR_CPU_CAPABILITY_PERFORMANCE] = { .type = NLA_U32 },
50e4b1eb24SSrinivas Pandruvada [THERMAL_GENL_ATTR_CPU_CAPABILITY_EFFICIENCY] = { .type = NLA_U32 },
511ce50e7dSDaniel Lezcano };
521ce50e7dSDaniel Lezcano
531ce50e7dSDaniel Lezcano struct param {
541ce50e7dSDaniel Lezcano struct nlattr **attrs;
551ce50e7dSDaniel Lezcano struct sk_buff *msg;
561ce50e7dSDaniel Lezcano const char *name;
571ce50e7dSDaniel Lezcano int tz_id;
581ce50e7dSDaniel Lezcano int cdev_id;
591ce50e7dSDaniel Lezcano int trip_id;
601ce50e7dSDaniel Lezcano int trip_temp;
611ce50e7dSDaniel Lezcano int trip_type;
621ce50e7dSDaniel Lezcano int trip_hyst;
631ce50e7dSDaniel Lezcano int temp;
641ce50e7dSDaniel Lezcano int cdev_state;
651ce50e7dSDaniel Lezcano int cdev_max_state;
66e4b1eb24SSrinivas Pandruvada struct thermal_genl_cpu_caps *cpu_capabilities;
67e4b1eb24SSrinivas Pandruvada int cpu_capabilities_count;
681ce50e7dSDaniel Lezcano };
691ce50e7dSDaniel Lezcano
701ce50e7dSDaniel Lezcano typedef int (*cb_t)(struct param *);
711ce50e7dSDaniel Lezcano
721ce50e7dSDaniel Lezcano static struct genl_family thermal_gnl_family;
731ce50e7dSDaniel Lezcano
741ce50e7dSDaniel Lezcano /************************** Sampling encoding *******************************/
751ce50e7dSDaniel Lezcano
thermal_genl_sampling_temp(int id,int temp)761ce50e7dSDaniel Lezcano int thermal_genl_sampling_temp(int id, int temp)
771ce50e7dSDaniel Lezcano {
781ce50e7dSDaniel Lezcano struct sk_buff *skb;
791ce50e7dSDaniel Lezcano void *hdr;
801ce50e7dSDaniel Lezcano
811ce50e7dSDaniel Lezcano skb = genlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL);
821ce50e7dSDaniel Lezcano if (!skb)
831ce50e7dSDaniel Lezcano return -ENOMEM;
841ce50e7dSDaniel Lezcano
851ce50e7dSDaniel Lezcano hdr = genlmsg_put(skb, 0, 0, &thermal_gnl_family, 0,
861ce50e7dSDaniel Lezcano THERMAL_GENL_SAMPLING_TEMP);
871ce50e7dSDaniel Lezcano if (!hdr)
8848b45859SJing Xiangfeng goto out_free;
891ce50e7dSDaniel Lezcano
901ce50e7dSDaniel Lezcano if (nla_put_u32(skb, THERMAL_GENL_ATTR_TZ_ID, id))
911ce50e7dSDaniel Lezcano goto out_cancel;
921ce50e7dSDaniel Lezcano
931ce50e7dSDaniel Lezcano if (nla_put_u32(skb, THERMAL_GENL_ATTR_TZ_TEMP, temp))
941ce50e7dSDaniel Lezcano goto out_cancel;
951ce50e7dSDaniel Lezcano
961ce50e7dSDaniel Lezcano genlmsg_end(skb, hdr);
971ce50e7dSDaniel Lezcano
981ce50e7dSDaniel Lezcano genlmsg_multicast(&thermal_gnl_family, skb, 0, 0, GFP_KERNEL);
991ce50e7dSDaniel Lezcano
1001ce50e7dSDaniel Lezcano return 0;
1011ce50e7dSDaniel Lezcano out_cancel:
1021ce50e7dSDaniel Lezcano genlmsg_cancel(skb, hdr);
10348b45859SJing Xiangfeng out_free:
1041ce50e7dSDaniel Lezcano nlmsg_free(skb);
1051ce50e7dSDaniel Lezcano
1061ce50e7dSDaniel Lezcano return -EMSGSIZE;
1071ce50e7dSDaniel Lezcano }
1081ce50e7dSDaniel Lezcano
1091ce50e7dSDaniel Lezcano /**************************** Event encoding *********************************/
1101ce50e7dSDaniel Lezcano
thermal_genl_event_tz_create(struct param * p)1111ce50e7dSDaniel Lezcano static int thermal_genl_event_tz_create(struct param *p)
1121ce50e7dSDaniel Lezcano {
1131ce50e7dSDaniel Lezcano if (nla_put_u32(p->msg, THERMAL_GENL_ATTR_TZ_ID, p->tz_id) ||
1141ce50e7dSDaniel Lezcano nla_put_string(p->msg, THERMAL_GENL_ATTR_TZ_NAME, p->name))
1151ce50e7dSDaniel Lezcano return -EMSGSIZE;
1161ce50e7dSDaniel Lezcano
1171ce50e7dSDaniel Lezcano return 0;
1181ce50e7dSDaniel Lezcano }
1191ce50e7dSDaniel Lezcano
thermal_genl_event_tz(struct param * p)1201ce50e7dSDaniel Lezcano static int thermal_genl_event_tz(struct param *p)
1211ce50e7dSDaniel Lezcano {
1221ce50e7dSDaniel Lezcano if (nla_put_u32(p->msg, THERMAL_GENL_ATTR_TZ_ID, p->tz_id))
1231ce50e7dSDaniel Lezcano return -EMSGSIZE;
1241ce50e7dSDaniel Lezcano
1251ce50e7dSDaniel Lezcano return 0;
1261ce50e7dSDaniel Lezcano }
1271ce50e7dSDaniel Lezcano
thermal_genl_event_tz_trip_up(struct param * p)1281ce50e7dSDaniel Lezcano static int thermal_genl_event_tz_trip_up(struct param *p)
1291ce50e7dSDaniel Lezcano {
1301ce50e7dSDaniel Lezcano if (nla_put_u32(p->msg, THERMAL_GENL_ATTR_TZ_ID, p->tz_id) ||
131fc656fa1SDaniel Lezcano nla_put_u32(p->msg, THERMAL_GENL_ATTR_TZ_TRIP_ID, p->trip_id) ||
132fc656fa1SDaniel Lezcano nla_put_u32(p->msg, THERMAL_GENL_ATTR_TZ_TEMP, p->temp))
1331ce50e7dSDaniel Lezcano return -EMSGSIZE;
1341ce50e7dSDaniel Lezcano
1351ce50e7dSDaniel Lezcano return 0;
1361ce50e7dSDaniel Lezcano }
1371ce50e7dSDaniel Lezcano
thermal_genl_event_tz_trip_add(struct param * p)1381ce50e7dSDaniel Lezcano static int thermal_genl_event_tz_trip_add(struct param *p)
1391ce50e7dSDaniel Lezcano {
1401ce50e7dSDaniel Lezcano if (nla_put_u32(p->msg, THERMAL_GENL_ATTR_TZ_ID, p->tz_id) ||
1411ce50e7dSDaniel Lezcano nla_put_u32(p->msg, THERMAL_GENL_ATTR_TZ_TRIP_ID, p->trip_id) ||
1421ce50e7dSDaniel Lezcano nla_put_u32(p->msg, THERMAL_GENL_ATTR_TZ_TRIP_TYPE, p->trip_type) ||
1431ce50e7dSDaniel Lezcano nla_put_u32(p->msg, THERMAL_GENL_ATTR_TZ_TRIP_TEMP, p->trip_temp) ||
1441ce50e7dSDaniel Lezcano nla_put_u32(p->msg, THERMAL_GENL_ATTR_TZ_TRIP_HYST, p->trip_hyst))
1451ce50e7dSDaniel Lezcano return -EMSGSIZE;
1461ce50e7dSDaniel Lezcano
1471ce50e7dSDaniel Lezcano return 0;
1481ce50e7dSDaniel Lezcano }
1491ce50e7dSDaniel Lezcano
thermal_genl_event_tz_trip_delete(struct param * p)1501ce50e7dSDaniel Lezcano static int thermal_genl_event_tz_trip_delete(struct param *p)
1511ce50e7dSDaniel Lezcano {
1521ce50e7dSDaniel Lezcano if (nla_put_u32(p->msg, THERMAL_GENL_ATTR_TZ_ID, p->tz_id) ||
1531ce50e7dSDaniel Lezcano nla_put_u32(p->msg, THERMAL_GENL_ATTR_TZ_TRIP_ID, p->trip_id))
1541ce50e7dSDaniel Lezcano return -EMSGSIZE;
1551ce50e7dSDaniel Lezcano
1561ce50e7dSDaniel Lezcano return 0;
1571ce50e7dSDaniel Lezcano }
1581ce50e7dSDaniel Lezcano
thermal_genl_event_cdev_add(struct param * p)1591ce50e7dSDaniel Lezcano static int thermal_genl_event_cdev_add(struct param *p)
1601ce50e7dSDaniel Lezcano {
1611ce50e7dSDaniel Lezcano if (nla_put_string(p->msg, THERMAL_GENL_ATTR_CDEV_NAME,
1621ce50e7dSDaniel Lezcano p->name) ||
1631ce50e7dSDaniel Lezcano nla_put_u32(p->msg, THERMAL_GENL_ATTR_CDEV_ID,
1641ce50e7dSDaniel Lezcano p->cdev_id) ||
1651ce50e7dSDaniel Lezcano nla_put_u32(p->msg, THERMAL_GENL_ATTR_CDEV_MAX_STATE,
1661ce50e7dSDaniel Lezcano p->cdev_max_state))
1671ce50e7dSDaniel Lezcano return -EMSGSIZE;
1681ce50e7dSDaniel Lezcano
1691ce50e7dSDaniel Lezcano return 0;
1701ce50e7dSDaniel Lezcano }
1711ce50e7dSDaniel Lezcano
thermal_genl_event_cdev_delete(struct param * p)1721ce50e7dSDaniel Lezcano static int thermal_genl_event_cdev_delete(struct param *p)
1731ce50e7dSDaniel Lezcano {
1741ce50e7dSDaniel Lezcano if (nla_put_u32(p->msg, THERMAL_GENL_ATTR_CDEV_ID, p->cdev_id))
1751ce50e7dSDaniel Lezcano return -EMSGSIZE;
1761ce50e7dSDaniel Lezcano
1771ce50e7dSDaniel Lezcano return 0;
1781ce50e7dSDaniel Lezcano }
1791ce50e7dSDaniel Lezcano
thermal_genl_event_cdev_state_update(struct param * p)1801ce50e7dSDaniel Lezcano static int thermal_genl_event_cdev_state_update(struct param *p)
1811ce50e7dSDaniel Lezcano {
1821ce50e7dSDaniel Lezcano if (nla_put_u32(p->msg, THERMAL_GENL_ATTR_CDEV_ID,
1831ce50e7dSDaniel Lezcano p->cdev_id) ||
1841ce50e7dSDaniel Lezcano nla_put_u32(p->msg, THERMAL_GENL_ATTR_CDEV_CUR_STATE,
1851ce50e7dSDaniel Lezcano p->cdev_state))
1861ce50e7dSDaniel Lezcano return -EMSGSIZE;
1871ce50e7dSDaniel Lezcano
1881ce50e7dSDaniel Lezcano return 0;
1891ce50e7dSDaniel Lezcano }
1901ce50e7dSDaniel Lezcano
thermal_genl_event_gov_change(struct param * p)1911ce50e7dSDaniel Lezcano static int thermal_genl_event_gov_change(struct param *p)
1921ce50e7dSDaniel Lezcano {
1931ce50e7dSDaniel Lezcano if (nla_put_u32(p->msg, THERMAL_GENL_ATTR_TZ_ID, p->tz_id) ||
1941ce50e7dSDaniel Lezcano nla_put_string(p->msg, THERMAL_GENL_ATTR_GOV_NAME, p->name))
1951ce50e7dSDaniel Lezcano return -EMSGSIZE;
1961ce50e7dSDaniel Lezcano
1971ce50e7dSDaniel Lezcano return 0;
1981ce50e7dSDaniel Lezcano }
1991ce50e7dSDaniel Lezcano
thermal_genl_event_cpu_capability_change(struct param * p)200e4b1eb24SSrinivas Pandruvada static int thermal_genl_event_cpu_capability_change(struct param *p)
201e4b1eb24SSrinivas Pandruvada {
202e4b1eb24SSrinivas Pandruvada struct thermal_genl_cpu_caps *cpu_cap = p->cpu_capabilities;
203e4b1eb24SSrinivas Pandruvada struct sk_buff *msg = p->msg;
204e4b1eb24SSrinivas Pandruvada struct nlattr *start_cap;
205e4b1eb24SSrinivas Pandruvada int i;
206e4b1eb24SSrinivas Pandruvada
207e4b1eb24SSrinivas Pandruvada start_cap = nla_nest_start(msg, THERMAL_GENL_ATTR_CPU_CAPABILITY);
208e4b1eb24SSrinivas Pandruvada if (!start_cap)
209e4b1eb24SSrinivas Pandruvada return -EMSGSIZE;
210e4b1eb24SSrinivas Pandruvada
211e4b1eb24SSrinivas Pandruvada for (i = 0; i < p->cpu_capabilities_count; ++i) {
212e4b1eb24SSrinivas Pandruvada if (nla_put_u32(msg, THERMAL_GENL_ATTR_CPU_CAPABILITY_ID,
213e4b1eb24SSrinivas Pandruvada cpu_cap->cpu))
214e4b1eb24SSrinivas Pandruvada goto out_cancel_nest;
215e4b1eb24SSrinivas Pandruvada
216e4b1eb24SSrinivas Pandruvada if (nla_put_u32(msg, THERMAL_GENL_ATTR_CPU_CAPABILITY_PERFORMANCE,
217e4b1eb24SSrinivas Pandruvada cpu_cap->performance))
218e4b1eb24SSrinivas Pandruvada goto out_cancel_nest;
219e4b1eb24SSrinivas Pandruvada
220e4b1eb24SSrinivas Pandruvada if (nla_put_u32(msg, THERMAL_GENL_ATTR_CPU_CAPABILITY_EFFICIENCY,
221e4b1eb24SSrinivas Pandruvada cpu_cap->efficiency))
222e4b1eb24SSrinivas Pandruvada goto out_cancel_nest;
223e4b1eb24SSrinivas Pandruvada
224e4b1eb24SSrinivas Pandruvada ++cpu_cap;
225e4b1eb24SSrinivas Pandruvada }
226e4b1eb24SSrinivas Pandruvada
227e4b1eb24SSrinivas Pandruvada nla_nest_end(msg, start_cap);
228e4b1eb24SSrinivas Pandruvada
229e4b1eb24SSrinivas Pandruvada return 0;
230e4b1eb24SSrinivas Pandruvada out_cancel_nest:
231e4b1eb24SSrinivas Pandruvada nla_nest_cancel(msg, start_cap);
232e4b1eb24SSrinivas Pandruvada
233e4b1eb24SSrinivas Pandruvada return -EMSGSIZE;
234e4b1eb24SSrinivas Pandruvada }
235e4b1eb24SSrinivas Pandruvada
2361ce50e7dSDaniel Lezcano int thermal_genl_event_tz_delete(struct param *p)
2371ce50e7dSDaniel Lezcano __attribute__((alias("thermal_genl_event_tz")));
2381ce50e7dSDaniel Lezcano
2391ce50e7dSDaniel Lezcano int thermal_genl_event_tz_enable(struct param *p)
2401ce50e7dSDaniel Lezcano __attribute__((alias("thermal_genl_event_tz")));
2411ce50e7dSDaniel Lezcano
2421ce50e7dSDaniel Lezcano int thermal_genl_event_tz_disable(struct param *p)
2431ce50e7dSDaniel Lezcano __attribute__((alias("thermal_genl_event_tz")));
2441ce50e7dSDaniel Lezcano
2451ce50e7dSDaniel Lezcano int thermal_genl_event_tz_trip_down(struct param *p)
2461ce50e7dSDaniel Lezcano __attribute__((alias("thermal_genl_event_tz_trip_up")));
2471ce50e7dSDaniel Lezcano
2481ce50e7dSDaniel Lezcano int thermal_genl_event_tz_trip_change(struct param *p)
2491ce50e7dSDaniel Lezcano __attribute__((alias("thermal_genl_event_tz_trip_add")));
2501ce50e7dSDaniel Lezcano
2511ce50e7dSDaniel Lezcano static cb_t event_cb[] = {
2521ce50e7dSDaniel Lezcano [THERMAL_GENL_EVENT_TZ_CREATE] = thermal_genl_event_tz_create,
2531ce50e7dSDaniel Lezcano [THERMAL_GENL_EVENT_TZ_DELETE] = thermal_genl_event_tz_delete,
2541ce50e7dSDaniel Lezcano [THERMAL_GENL_EVENT_TZ_ENABLE] = thermal_genl_event_tz_enable,
2551ce50e7dSDaniel Lezcano [THERMAL_GENL_EVENT_TZ_DISABLE] = thermal_genl_event_tz_disable,
2561ce50e7dSDaniel Lezcano [THERMAL_GENL_EVENT_TZ_TRIP_UP] = thermal_genl_event_tz_trip_up,
2571ce50e7dSDaniel Lezcano [THERMAL_GENL_EVENT_TZ_TRIP_DOWN] = thermal_genl_event_tz_trip_down,
2581ce50e7dSDaniel Lezcano [THERMAL_GENL_EVENT_TZ_TRIP_CHANGE] = thermal_genl_event_tz_trip_change,
2591ce50e7dSDaniel Lezcano [THERMAL_GENL_EVENT_TZ_TRIP_ADD] = thermal_genl_event_tz_trip_add,
2601ce50e7dSDaniel Lezcano [THERMAL_GENL_EVENT_TZ_TRIP_DELETE] = thermal_genl_event_tz_trip_delete,
2611ce50e7dSDaniel Lezcano [THERMAL_GENL_EVENT_CDEV_ADD] = thermal_genl_event_cdev_add,
2621ce50e7dSDaniel Lezcano [THERMAL_GENL_EVENT_CDEV_DELETE] = thermal_genl_event_cdev_delete,
2631ce50e7dSDaniel Lezcano [THERMAL_GENL_EVENT_CDEV_STATE_UPDATE] = thermal_genl_event_cdev_state_update,
2641ce50e7dSDaniel Lezcano [THERMAL_GENL_EVENT_TZ_GOV_CHANGE] = thermal_genl_event_gov_change,
265e4b1eb24SSrinivas Pandruvada [THERMAL_GENL_EVENT_CPU_CAPABILITY_CHANGE] = thermal_genl_event_cpu_capability_change,
2661ce50e7dSDaniel Lezcano };
2671ce50e7dSDaniel Lezcano
2681ce50e7dSDaniel Lezcano /*
2691ce50e7dSDaniel Lezcano * Generic netlink event encoding
2701ce50e7dSDaniel Lezcano */
thermal_genl_send_event(enum thermal_genl_event event,struct param * p)2711ce50e7dSDaniel Lezcano static int thermal_genl_send_event(enum thermal_genl_event event,
2721ce50e7dSDaniel Lezcano struct param *p)
2731ce50e7dSDaniel Lezcano {
2741ce50e7dSDaniel Lezcano struct sk_buff *msg;
2751ce50e7dSDaniel Lezcano int ret = -EMSGSIZE;
2761ce50e7dSDaniel Lezcano void *hdr;
2771ce50e7dSDaniel Lezcano
2781ce50e7dSDaniel Lezcano msg = genlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL);
2791ce50e7dSDaniel Lezcano if (!msg)
2801ce50e7dSDaniel Lezcano return -ENOMEM;
2811ce50e7dSDaniel Lezcano p->msg = msg;
2821ce50e7dSDaniel Lezcano
2831ce50e7dSDaniel Lezcano hdr = genlmsg_put(msg, 0, 0, &thermal_gnl_family, 0, event);
2841ce50e7dSDaniel Lezcano if (!hdr)
2851ce50e7dSDaniel Lezcano goto out_free_msg;
2861ce50e7dSDaniel Lezcano
2871ce50e7dSDaniel Lezcano ret = event_cb[event](p);
2881ce50e7dSDaniel Lezcano if (ret)
2891ce50e7dSDaniel Lezcano goto out_cancel_msg;
2901ce50e7dSDaniel Lezcano
2911ce50e7dSDaniel Lezcano genlmsg_end(msg, hdr);
2921ce50e7dSDaniel Lezcano
2931ce50e7dSDaniel Lezcano genlmsg_multicast(&thermal_gnl_family, msg, 0, 1, GFP_KERNEL);
2941ce50e7dSDaniel Lezcano
2951ce50e7dSDaniel Lezcano return 0;
2961ce50e7dSDaniel Lezcano
2971ce50e7dSDaniel Lezcano out_cancel_msg:
2981ce50e7dSDaniel Lezcano genlmsg_cancel(msg, hdr);
2991ce50e7dSDaniel Lezcano out_free_msg:
3001ce50e7dSDaniel Lezcano nlmsg_free(msg);
3011ce50e7dSDaniel Lezcano
3021ce50e7dSDaniel Lezcano return ret;
3031ce50e7dSDaniel Lezcano }
3041ce50e7dSDaniel Lezcano
thermal_notify_tz_create(int tz_id,const char * name)3051ce50e7dSDaniel Lezcano int thermal_notify_tz_create(int tz_id, const char *name)
3061ce50e7dSDaniel Lezcano {
3071ce50e7dSDaniel Lezcano struct param p = { .tz_id = tz_id, .name = name };
3081ce50e7dSDaniel Lezcano
3091ce50e7dSDaniel Lezcano return thermal_genl_send_event(THERMAL_GENL_EVENT_TZ_CREATE, &p);
3101ce50e7dSDaniel Lezcano }
3111ce50e7dSDaniel Lezcano
thermal_notify_tz_delete(int tz_id)3121ce50e7dSDaniel Lezcano int thermal_notify_tz_delete(int tz_id)
3131ce50e7dSDaniel Lezcano {
3141ce50e7dSDaniel Lezcano struct param p = { .tz_id = tz_id };
3151ce50e7dSDaniel Lezcano
3161ce50e7dSDaniel Lezcano return thermal_genl_send_event(THERMAL_GENL_EVENT_TZ_DELETE, &p);
3171ce50e7dSDaniel Lezcano }
3181ce50e7dSDaniel Lezcano
thermal_notify_tz_enable(int tz_id)3191ce50e7dSDaniel Lezcano int thermal_notify_tz_enable(int tz_id)
3201ce50e7dSDaniel Lezcano {
3211ce50e7dSDaniel Lezcano struct param p = { .tz_id = tz_id };
3221ce50e7dSDaniel Lezcano
3231ce50e7dSDaniel Lezcano return thermal_genl_send_event(THERMAL_GENL_EVENT_TZ_ENABLE, &p);
3241ce50e7dSDaniel Lezcano }
3251ce50e7dSDaniel Lezcano
thermal_notify_tz_disable(int tz_id)3261ce50e7dSDaniel Lezcano int thermal_notify_tz_disable(int tz_id)
3271ce50e7dSDaniel Lezcano {
3281ce50e7dSDaniel Lezcano struct param p = { .tz_id = tz_id };
3291ce50e7dSDaniel Lezcano
3301ce50e7dSDaniel Lezcano return thermal_genl_send_event(THERMAL_GENL_EVENT_TZ_DISABLE, &p);
3311ce50e7dSDaniel Lezcano }
3321ce50e7dSDaniel Lezcano
thermal_notify_tz_trip_down(int tz_id,int trip_id,int temp)333fc656fa1SDaniel Lezcano int thermal_notify_tz_trip_down(int tz_id, int trip_id, int temp)
3341ce50e7dSDaniel Lezcano {
335fc656fa1SDaniel Lezcano struct param p = { .tz_id = tz_id, .trip_id = trip_id, .temp = temp };
3361ce50e7dSDaniel Lezcano
3371ce50e7dSDaniel Lezcano return thermal_genl_send_event(THERMAL_GENL_EVENT_TZ_TRIP_DOWN, &p);
3381ce50e7dSDaniel Lezcano }
3391ce50e7dSDaniel Lezcano
thermal_notify_tz_trip_up(int tz_id,int trip_id,int temp)340fc656fa1SDaniel Lezcano int thermal_notify_tz_trip_up(int tz_id, int trip_id, int temp)
3411ce50e7dSDaniel Lezcano {
342fc656fa1SDaniel Lezcano struct param p = { .tz_id = tz_id, .trip_id = trip_id, .temp = temp };
3431ce50e7dSDaniel Lezcano
3441ce50e7dSDaniel Lezcano return thermal_genl_send_event(THERMAL_GENL_EVENT_TZ_TRIP_UP, &p);
3451ce50e7dSDaniel Lezcano }
3461ce50e7dSDaniel Lezcano
thermal_notify_tz_trip_add(int tz_id,int trip_id,int trip_type,int trip_temp,int trip_hyst)3471ce50e7dSDaniel Lezcano int thermal_notify_tz_trip_add(int tz_id, int trip_id, int trip_type,
3481ce50e7dSDaniel Lezcano int trip_temp, int trip_hyst)
3491ce50e7dSDaniel Lezcano {
3501ce50e7dSDaniel Lezcano struct param p = { .tz_id = tz_id, .trip_id = trip_id,
3511ce50e7dSDaniel Lezcano .trip_type = trip_type, .trip_temp = trip_temp,
3521ce50e7dSDaniel Lezcano .trip_hyst = trip_hyst };
3531ce50e7dSDaniel Lezcano
3541ce50e7dSDaniel Lezcano return thermal_genl_send_event(THERMAL_GENL_EVENT_TZ_TRIP_ADD, &p);
3551ce50e7dSDaniel Lezcano }
3561ce50e7dSDaniel Lezcano
thermal_notify_tz_trip_delete(int tz_id,int trip_id)3571ce50e7dSDaniel Lezcano int thermal_notify_tz_trip_delete(int tz_id, int trip_id)
3581ce50e7dSDaniel Lezcano {
3591ce50e7dSDaniel Lezcano struct param p = { .tz_id = tz_id, .trip_id = trip_id };
3601ce50e7dSDaniel Lezcano
3611ce50e7dSDaniel Lezcano return thermal_genl_send_event(THERMAL_GENL_EVENT_TZ_TRIP_DELETE, &p);
3621ce50e7dSDaniel Lezcano }
3631ce50e7dSDaniel Lezcano
thermal_notify_tz_trip_change(int tz_id,int trip_id,int trip_type,int trip_temp,int trip_hyst)3641ce50e7dSDaniel Lezcano int thermal_notify_tz_trip_change(int tz_id, int trip_id, int trip_type,
3651ce50e7dSDaniel Lezcano int trip_temp, int trip_hyst)
3661ce50e7dSDaniel Lezcano {
3671ce50e7dSDaniel Lezcano struct param p = { .tz_id = tz_id, .trip_id = trip_id,
3681ce50e7dSDaniel Lezcano .trip_type = trip_type, .trip_temp = trip_temp,
3691ce50e7dSDaniel Lezcano .trip_hyst = trip_hyst };
3701ce50e7dSDaniel Lezcano
3711ce50e7dSDaniel Lezcano return thermal_genl_send_event(THERMAL_GENL_EVENT_TZ_TRIP_CHANGE, &p);
3721ce50e7dSDaniel Lezcano }
3731ce50e7dSDaniel Lezcano
thermal_notify_cdev_state_update(int cdev_id,int cdev_state)3741ce50e7dSDaniel Lezcano int thermal_notify_cdev_state_update(int cdev_id, int cdev_state)
3751ce50e7dSDaniel Lezcano {
3761ce50e7dSDaniel Lezcano struct param p = { .cdev_id = cdev_id, .cdev_state = cdev_state };
3771ce50e7dSDaniel Lezcano
3781ce50e7dSDaniel Lezcano return thermal_genl_send_event(THERMAL_GENL_EVENT_CDEV_STATE_UPDATE, &p);
3791ce50e7dSDaniel Lezcano }
3801ce50e7dSDaniel Lezcano
thermal_notify_cdev_add(int cdev_id,const char * name,int cdev_max_state)3811ce50e7dSDaniel Lezcano int thermal_notify_cdev_add(int cdev_id, const char *name, int cdev_max_state)
3821ce50e7dSDaniel Lezcano {
3831ce50e7dSDaniel Lezcano struct param p = { .cdev_id = cdev_id, .name = name,
3841ce50e7dSDaniel Lezcano .cdev_max_state = cdev_max_state };
3851ce50e7dSDaniel Lezcano
3861ce50e7dSDaniel Lezcano return thermal_genl_send_event(THERMAL_GENL_EVENT_CDEV_ADD, &p);
3871ce50e7dSDaniel Lezcano }
3881ce50e7dSDaniel Lezcano
thermal_notify_cdev_delete(int cdev_id)3891ce50e7dSDaniel Lezcano int thermal_notify_cdev_delete(int cdev_id)
3901ce50e7dSDaniel Lezcano {
3911ce50e7dSDaniel Lezcano struct param p = { .cdev_id = cdev_id };
3921ce50e7dSDaniel Lezcano
3931ce50e7dSDaniel Lezcano return thermal_genl_send_event(THERMAL_GENL_EVENT_CDEV_DELETE, &p);
3941ce50e7dSDaniel Lezcano }
3951ce50e7dSDaniel Lezcano
thermal_notify_tz_gov_change(int tz_id,const char * name)3961ce50e7dSDaniel Lezcano int thermal_notify_tz_gov_change(int tz_id, const char *name)
3971ce50e7dSDaniel Lezcano {
3981ce50e7dSDaniel Lezcano struct param p = { .tz_id = tz_id, .name = name };
3991ce50e7dSDaniel Lezcano
4001ce50e7dSDaniel Lezcano return thermal_genl_send_event(THERMAL_GENL_EVENT_TZ_GOV_CHANGE, &p);
4011ce50e7dSDaniel Lezcano }
4021ce50e7dSDaniel Lezcano
thermal_genl_cpu_capability_event(int count,struct thermal_genl_cpu_caps * caps)403e4b1eb24SSrinivas Pandruvada int thermal_genl_cpu_capability_event(int count,
404e4b1eb24SSrinivas Pandruvada struct thermal_genl_cpu_caps *caps)
405e4b1eb24SSrinivas Pandruvada {
406e4b1eb24SSrinivas Pandruvada struct param p = { .cpu_capabilities_count = count, .cpu_capabilities = caps };
407e4b1eb24SSrinivas Pandruvada
408e4b1eb24SSrinivas Pandruvada return thermal_genl_send_event(THERMAL_GENL_EVENT_CPU_CAPABILITY_CHANGE, &p);
409e4b1eb24SSrinivas Pandruvada }
410e4b1eb24SSrinivas Pandruvada EXPORT_SYMBOL_GPL(thermal_genl_cpu_capability_event);
411e4b1eb24SSrinivas Pandruvada
4121ce50e7dSDaniel Lezcano /*************************** Command encoding ********************************/
4131ce50e7dSDaniel Lezcano
__thermal_genl_cmd_tz_get_id(struct thermal_zone_device * tz,void * data)4141ce50e7dSDaniel Lezcano static int __thermal_genl_cmd_tz_get_id(struct thermal_zone_device *tz,
4151ce50e7dSDaniel Lezcano void *data)
4161ce50e7dSDaniel Lezcano {
4171ce50e7dSDaniel Lezcano struct sk_buff *msg = data;
4181ce50e7dSDaniel Lezcano
4191ce50e7dSDaniel Lezcano if (nla_put_u32(msg, THERMAL_GENL_ATTR_TZ_ID, tz->id) ||
4201ce50e7dSDaniel Lezcano nla_put_string(msg, THERMAL_GENL_ATTR_TZ_NAME, tz->type))
4211ce50e7dSDaniel Lezcano return -EMSGSIZE;
4221ce50e7dSDaniel Lezcano
4231ce50e7dSDaniel Lezcano return 0;
4241ce50e7dSDaniel Lezcano }
4251ce50e7dSDaniel Lezcano
thermal_genl_cmd_tz_get_id(struct param * p)4261ce50e7dSDaniel Lezcano static int thermal_genl_cmd_tz_get_id(struct param *p)
4271ce50e7dSDaniel Lezcano {
4281ce50e7dSDaniel Lezcano struct sk_buff *msg = p->msg;
4291ce50e7dSDaniel Lezcano struct nlattr *start_tz;
4301ce50e7dSDaniel Lezcano int ret;
4311ce50e7dSDaniel Lezcano
4321ce50e7dSDaniel Lezcano start_tz = nla_nest_start(msg, THERMAL_GENL_ATTR_TZ);
4331ce50e7dSDaniel Lezcano if (!start_tz)
4341ce50e7dSDaniel Lezcano return -EMSGSIZE;
4351ce50e7dSDaniel Lezcano
4361ce50e7dSDaniel Lezcano ret = for_each_thermal_zone(__thermal_genl_cmd_tz_get_id, msg);
4371ce50e7dSDaniel Lezcano if (ret)
4381ce50e7dSDaniel Lezcano goto out_cancel_nest;
4391ce50e7dSDaniel Lezcano
4401ce50e7dSDaniel Lezcano nla_nest_end(msg, start_tz);
4411ce50e7dSDaniel Lezcano
4421ce50e7dSDaniel Lezcano return 0;
4431ce50e7dSDaniel Lezcano
4441ce50e7dSDaniel Lezcano out_cancel_nest:
4451ce50e7dSDaniel Lezcano nla_nest_cancel(msg, start_tz);
4461ce50e7dSDaniel Lezcano
4471ce50e7dSDaniel Lezcano return ret;
4481ce50e7dSDaniel Lezcano }
4491ce50e7dSDaniel Lezcano
thermal_genl_cmd_tz_get_trip(struct param * p)4501ce50e7dSDaniel Lezcano static int thermal_genl_cmd_tz_get_trip(struct param *p)
4511ce50e7dSDaniel Lezcano {
4521ce50e7dSDaniel Lezcano struct sk_buff *msg = p->msg;
4531ce50e7dSDaniel Lezcano struct thermal_zone_device *tz;
4541ce50e7dSDaniel Lezcano struct nlattr *start_trip;
4557c3d5c20SDaniel Lezcano struct thermal_trip trip;
4567c3d5c20SDaniel Lezcano int ret, i, id;
4571ce50e7dSDaniel Lezcano
4581ce50e7dSDaniel Lezcano if (!p->attrs[THERMAL_GENL_ATTR_TZ_ID])
4591ce50e7dSDaniel Lezcano return -EINVAL;
4601ce50e7dSDaniel Lezcano
4611ce50e7dSDaniel Lezcano id = nla_get_u32(p->attrs[THERMAL_GENL_ATTR_TZ_ID]);
4621ce50e7dSDaniel Lezcano
4631ce50e7dSDaniel Lezcano tz = thermal_zone_get_by_id(id);
4641ce50e7dSDaniel Lezcano if (!tz)
4651ce50e7dSDaniel Lezcano return -EINVAL;
4661ce50e7dSDaniel Lezcano
4671ce50e7dSDaniel Lezcano start_trip = nla_nest_start(msg, THERMAL_GENL_ATTR_TZ_TRIP);
4681ce50e7dSDaniel Lezcano if (!start_trip)
4691ce50e7dSDaniel Lezcano return -EMSGSIZE;
4701ce50e7dSDaniel Lezcano
4711ce50e7dSDaniel Lezcano mutex_lock(&tz->lock);
4721ce50e7dSDaniel Lezcano
473e5bfcd30SDaniel Lezcano for (i = 0; i < tz->num_trips; i++) {
4741ce50e7dSDaniel Lezcano
4757c3d5c20SDaniel Lezcano ret = __thermal_zone_get_trip(tz, i, &trip);
4767c3d5c20SDaniel Lezcano if (ret)
4777c3d5c20SDaniel Lezcano goto out_cancel_nest;
4781ce50e7dSDaniel Lezcano
4791ce50e7dSDaniel Lezcano if (nla_put_u32(msg, THERMAL_GENL_ATTR_TZ_TRIP_ID, i) ||
4807c3d5c20SDaniel Lezcano nla_put_u32(msg, THERMAL_GENL_ATTR_TZ_TRIP_TYPE, trip.type) ||
4817c3d5c20SDaniel Lezcano nla_put_u32(msg, THERMAL_GENL_ATTR_TZ_TRIP_TEMP, trip.temperature) ||
4827c3d5c20SDaniel Lezcano nla_put_u32(msg, THERMAL_GENL_ATTR_TZ_TRIP_HYST, trip.hysteresis))
4831ce50e7dSDaniel Lezcano goto out_cancel_nest;
4841ce50e7dSDaniel Lezcano }
4851ce50e7dSDaniel Lezcano
4861ce50e7dSDaniel Lezcano mutex_unlock(&tz->lock);
4871ce50e7dSDaniel Lezcano
4881ce50e7dSDaniel Lezcano nla_nest_end(msg, start_trip);
4891ce50e7dSDaniel Lezcano
4901ce50e7dSDaniel Lezcano return 0;
4911ce50e7dSDaniel Lezcano
4921ce50e7dSDaniel Lezcano out_cancel_nest:
4931ce50e7dSDaniel Lezcano mutex_unlock(&tz->lock);
4941ce50e7dSDaniel Lezcano
4951ce50e7dSDaniel Lezcano return -EMSGSIZE;
4961ce50e7dSDaniel Lezcano }
4971ce50e7dSDaniel Lezcano
thermal_genl_cmd_tz_get_temp(struct param * p)4981ce50e7dSDaniel Lezcano static int thermal_genl_cmd_tz_get_temp(struct param *p)
4991ce50e7dSDaniel Lezcano {
5001ce50e7dSDaniel Lezcano struct sk_buff *msg = p->msg;
5011ce50e7dSDaniel Lezcano struct thermal_zone_device *tz;
5021ce50e7dSDaniel Lezcano int temp, ret, id;
5031ce50e7dSDaniel Lezcano
5041ce50e7dSDaniel Lezcano if (!p->attrs[THERMAL_GENL_ATTR_TZ_ID])
5051ce50e7dSDaniel Lezcano return -EINVAL;
5061ce50e7dSDaniel Lezcano
5071ce50e7dSDaniel Lezcano id = nla_get_u32(p->attrs[THERMAL_GENL_ATTR_TZ_ID]);
5081ce50e7dSDaniel Lezcano
5091ce50e7dSDaniel Lezcano tz = thermal_zone_get_by_id(id);
5101ce50e7dSDaniel Lezcano if (!tz)
5111ce50e7dSDaniel Lezcano return -EINVAL;
5121ce50e7dSDaniel Lezcano
5131ce50e7dSDaniel Lezcano ret = thermal_zone_get_temp(tz, &temp);
5141ce50e7dSDaniel Lezcano if (ret)
5151ce50e7dSDaniel Lezcano return ret;
5161ce50e7dSDaniel Lezcano
5171ce50e7dSDaniel Lezcano if (nla_put_u32(msg, THERMAL_GENL_ATTR_TZ_ID, id) ||
5181ce50e7dSDaniel Lezcano nla_put_u32(msg, THERMAL_GENL_ATTR_TZ_TEMP, temp))
5191ce50e7dSDaniel Lezcano return -EMSGSIZE;
5201ce50e7dSDaniel Lezcano
5211ce50e7dSDaniel Lezcano return 0;
5221ce50e7dSDaniel Lezcano }
5231ce50e7dSDaniel Lezcano
thermal_genl_cmd_tz_get_gov(struct param * p)5241ce50e7dSDaniel Lezcano static int thermal_genl_cmd_tz_get_gov(struct param *p)
5251ce50e7dSDaniel Lezcano {
5261ce50e7dSDaniel Lezcano struct sk_buff *msg = p->msg;
5271ce50e7dSDaniel Lezcano struct thermal_zone_device *tz;
5281ce50e7dSDaniel Lezcano int id, ret = 0;
5291ce50e7dSDaniel Lezcano
5301ce50e7dSDaniel Lezcano if (!p->attrs[THERMAL_GENL_ATTR_TZ_ID])
5311ce50e7dSDaniel Lezcano return -EINVAL;
5321ce50e7dSDaniel Lezcano
5331ce50e7dSDaniel Lezcano id = nla_get_u32(p->attrs[THERMAL_GENL_ATTR_TZ_ID]);
5341ce50e7dSDaniel Lezcano
5351ce50e7dSDaniel Lezcano tz = thermal_zone_get_by_id(id);
5361ce50e7dSDaniel Lezcano if (!tz)
5371ce50e7dSDaniel Lezcano return -EINVAL;
5381ce50e7dSDaniel Lezcano
5391ce50e7dSDaniel Lezcano mutex_lock(&tz->lock);
5401ce50e7dSDaniel Lezcano
5411ce50e7dSDaniel Lezcano if (nla_put_u32(msg, THERMAL_GENL_ATTR_TZ_ID, id) ||
5421ce50e7dSDaniel Lezcano nla_put_string(msg, THERMAL_GENL_ATTR_TZ_GOV_NAME,
5431ce50e7dSDaniel Lezcano tz->governor->name))
5441ce50e7dSDaniel Lezcano ret = -EMSGSIZE;
5451ce50e7dSDaniel Lezcano
5461ce50e7dSDaniel Lezcano mutex_unlock(&tz->lock);
5471ce50e7dSDaniel Lezcano
5481ce50e7dSDaniel Lezcano return ret;
5491ce50e7dSDaniel Lezcano }
5501ce50e7dSDaniel Lezcano
__thermal_genl_cmd_cdev_get(struct thermal_cooling_device * cdev,void * data)5511ce50e7dSDaniel Lezcano static int __thermal_genl_cmd_cdev_get(struct thermal_cooling_device *cdev,
5521ce50e7dSDaniel Lezcano void *data)
5531ce50e7dSDaniel Lezcano {
5541ce50e7dSDaniel Lezcano struct sk_buff *msg = data;
5551ce50e7dSDaniel Lezcano
5561ce50e7dSDaniel Lezcano if (nla_put_u32(msg, THERMAL_GENL_ATTR_CDEV_ID, cdev->id))
5571ce50e7dSDaniel Lezcano return -EMSGSIZE;
5581ce50e7dSDaniel Lezcano
5591ce50e7dSDaniel Lezcano if (nla_put_string(msg, THERMAL_GENL_ATTR_CDEV_NAME, cdev->type))
5601ce50e7dSDaniel Lezcano return -EMSGSIZE;
5611ce50e7dSDaniel Lezcano
5621ce50e7dSDaniel Lezcano return 0;
5631ce50e7dSDaniel Lezcano }
5641ce50e7dSDaniel Lezcano
thermal_genl_cmd_cdev_get(struct param * p)5651ce50e7dSDaniel Lezcano static int thermal_genl_cmd_cdev_get(struct param *p)
5661ce50e7dSDaniel Lezcano {
5671ce50e7dSDaniel Lezcano struct sk_buff *msg = p->msg;
5681ce50e7dSDaniel Lezcano struct nlattr *start_cdev;
5691ce50e7dSDaniel Lezcano int ret;
5701ce50e7dSDaniel Lezcano
5711ce50e7dSDaniel Lezcano start_cdev = nla_nest_start(msg, THERMAL_GENL_ATTR_CDEV);
5721ce50e7dSDaniel Lezcano if (!start_cdev)
5731ce50e7dSDaniel Lezcano return -EMSGSIZE;
5741ce50e7dSDaniel Lezcano
5751ce50e7dSDaniel Lezcano ret = for_each_thermal_cooling_device(__thermal_genl_cmd_cdev_get, msg);
5761ce50e7dSDaniel Lezcano if (ret)
5771ce50e7dSDaniel Lezcano goto out_cancel_nest;
5781ce50e7dSDaniel Lezcano
5791ce50e7dSDaniel Lezcano nla_nest_end(msg, start_cdev);
5801ce50e7dSDaniel Lezcano
5811ce50e7dSDaniel Lezcano return 0;
5821ce50e7dSDaniel Lezcano out_cancel_nest:
5831ce50e7dSDaniel Lezcano nla_nest_cancel(msg, start_cdev);
5841ce50e7dSDaniel Lezcano
5851ce50e7dSDaniel Lezcano return ret;
5861ce50e7dSDaniel Lezcano }
5871ce50e7dSDaniel Lezcano
5881ce50e7dSDaniel Lezcano static cb_t cmd_cb[] = {
5891ce50e7dSDaniel Lezcano [THERMAL_GENL_CMD_TZ_GET_ID] = thermal_genl_cmd_tz_get_id,
5901ce50e7dSDaniel Lezcano [THERMAL_GENL_CMD_TZ_GET_TRIP] = thermal_genl_cmd_tz_get_trip,
5911ce50e7dSDaniel Lezcano [THERMAL_GENL_CMD_TZ_GET_TEMP] = thermal_genl_cmd_tz_get_temp,
5921ce50e7dSDaniel Lezcano [THERMAL_GENL_CMD_TZ_GET_GOV] = thermal_genl_cmd_tz_get_gov,
5931ce50e7dSDaniel Lezcano [THERMAL_GENL_CMD_CDEV_GET] = thermal_genl_cmd_cdev_get,
5941ce50e7dSDaniel Lezcano };
5951ce50e7dSDaniel Lezcano
thermal_genl_cmd_dumpit(struct sk_buff * skb,struct netlink_callback * cb)5961ce50e7dSDaniel Lezcano static int thermal_genl_cmd_dumpit(struct sk_buff *skb,
5971ce50e7dSDaniel Lezcano struct netlink_callback *cb)
5981ce50e7dSDaniel Lezcano {
5991ce50e7dSDaniel Lezcano struct param p = { .msg = skb };
6001ce50e7dSDaniel Lezcano const struct genl_dumpit_info *info = genl_dumpit_info(cb);
6010b588afdSJakub Kicinski int cmd = info->op.cmd;
60252674f56SColin Ian King int ret;
6031ce50e7dSDaniel Lezcano void *hdr;
6041ce50e7dSDaniel Lezcano
6051ce50e7dSDaniel Lezcano hdr = genlmsg_put(skb, 0, 0, &thermal_gnl_family, 0, cmd);
6061ce50e7dSDaniel Lezcano if (!hdr)
6071ce50e7dSDaniel Lezcano return -EMSGSIZE;
6081ce50e7dSDaniel Lezcano
6091ce50e7dSDaniel Lezcano ret = cmd_cb[cmd](&p);
6101ce50e7dSDaniel Lezcano if (ret)
6111ce50e7dSDaniel Lezcano goto out_cancel_msg;
6121ce50e7dSDaniel Lezcano
6131ce50e7dSDaniel Lezcano genlmsg_end(skb, hdr);
6141ce50e7dSDaniel Lezcano
6151ce50e7dSDaniel Lezcano return 0;
6161ce50e7dSDaniel Lezcano
6171ce50e7dSDaniel Lezcano out_cancel_msg:
6181ce50e7dSDaniel Lezcano genlmsg_cancel(skb, hdr);
6191ce50e7dSDaniel Lezcano
6201ce50e7dSDaniel Lezcano return ret;
6211ce50e7dSDaniel Lezcano }
6221ce50e7dSDaniel Lezcano
thermal_genl_cmd_doit(struct sk_buff * skb,struct genl_info * info)6231ce50e7dSDaniel Lezcano static int thermal_genl_cmd_doit(struct sk_buff *skb,
6241ce50e7dSDaniel Lezcano struct genl_info *info)
6251ce50e7dSDaniel Lezcano {
6261ce50e7dSDaniel Lezcano struct param p = { .attrs = info->attrs };
6271ce50e7dSDaniel Lezcano struct sk_buff *msg;
6281ce50e7dSDaniel Lezcano void *hdr;
6291ce50e7dSDaniel Lezcano int cmd = info->genlhdr->cmd;
6301ce50e7dSDaniel Lezcano int ret = -EMSGSIZE;
6311ce50e7dSDaniel Lezcano
6321ce50e7dSDaniel Lezcano msg = genlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL);
6331ce50e7dSDaniel Lezcano if (!msg)
6341ce50e7dSDaniel Lezcano return -ENOMEM;
6351ce50e7dSDaniel Lezcano p.msg = msg;
6361ce50e7dSDaniel Lezcano
6371ce50e7dSDaniel Lezcano hdr = genlmsg_put_reply(msg, info, &thermal_gnl_family, 0, cmd);
6381ce50e7dSDaniel Lezcano if (!hdr)
6391ce50e7dSDaniel Lezcano goto out_free_msg;
6401ce50e7dSDaniel Lezcano
6411ce50e7dSDaniel Lezcano ret = cmd_cb[cmd](&p);
6421ce50e7dSDaniel Lezcano if (ret)
6431ce50e7dSDaniel Lezcano goto out_cancel_msg;
6441ce50e7dSDaniel Lezcano
6451ce50e7dSDaniel Lezcano genlmsg_end(msg, hdr);
6461ce50e7dSDaniel Lezcano
6471ce50e7dSDaniel Lezcano return genlmsg_reply(msg, info);
6481ce50e7dSDaniel Lezcano
6491ce50e7dSDaniel Lezcano out_cancel_msg:
6501ce50e7dSDaniel Lezcano genlmsg_cancel(msg, hdr);
6511ce50e7dSDaniel Lezcano out_free_msg:
6521ce50e7dSDaniel Lezcano nlmsg_free(msg);
6531ce50e7dSDaniel Lezcano
6541ce50e7dSDaniel Lezcano return ret;
6551ce50e7dSDaniel Lezcano }
6561ce50e7dSDaniel Lezcano
65766a9b928SJakub Kicinski static const struct genl_small_ops thermal_genl_ops[] = {
6581ce50e7dSDaniel Lezcano {
6591ce50e7dSDaniel Lezcano .cmd = THERMAL_GENL_CMD_TZ_GET_ID,
6601ce50e7dSDaniel Lezcano .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
6611ce50e7dSDaniel Lezcano .dumpit = thermal_genl_cmd_dumpit,
6621ce50e7dSDaniel Lezcano },
6631ce50e7dSDaniel Lezcano {
6641ce50e7dSDaniel Lezcano .cmd = THERMAL_GENL_CMD_TZ_GET_TRIP,
6651ce50e7dSDaniel Lezcano .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
6661ce50e7dSDaniel Lezcano .doit = thermal_genl_cmd_doit,
6671ce50e7dSDaniel Lezcano },
6681ce50e7dSDaniel Lezcano {
6691ce50e7dSDaniel Lezcano .cmd = THERMAL_GENL_CMD_TZ_GET_TEMP,
6701ce50e7dSDaniel Lezcano .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
6711ce50e7dSDaniel Lezcano .doit = thermal_genl_cmd_doit,
6721ce50e7dSDaniel Lezcano },
6731ce50e7dSDaniel Lezcano {
6741ce50e7dSDaniel Lezcano .cmd = THERMAL_GENL_CMD_TZ_GET_GOV,
6751ce50e7dSDaniel Lezcano .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
6761ce50e7dSDaniel Lezcano .doit = thermal_genl_cmd_doit,
6771ce50e7dSDaniel Lezcano },
6781ce50e7dSDaniel Lezcano {
6791ce50e7dSDaniel Lezcano .cmd = THERMAL_GENL_CMD_CDEV_GET,
6801ce50e7dSDaniel Lezcano .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
6811ce50e7dSDaniel Lezcano .dumpit = thermal_genl_cmd_dumpit,
6821ce50e7dSDaniel Lezcano },
6831ce50e7dSDaniel Lezcano };
6841ce50e7dSDaniel Lezcano
6851ce50e7dSDaniel Lezcano static struct genl_family thermal_gnl_family __ro_after_init = {
6861ce50e7dSDaniel Lezcano .hdrsize = 0,
6871ce50e7dSDaniel Lezcano .name = THERMAL_GENL_FAMILY_NAME,
6881ce50e7dSDaniel Lezcano .version = THERMAL_GENL_VERSION,
6891ce50e7dSDaniel Lezcano .maxattr = THERMAL_GENL_ATTR_MAX,
6901ce50e7dSDaniel Lezcano .policy = thermal_genl_policy,
69166a9b928SJakub Kicinski .small_ops = thermal_genl_ops,
69266a9b928SJakub Kicinski .n_small_ops = ARRAY_SIZE(thermal_genl_ops),
6939c5d03d3SJakub Kicinski .resv_start_op = THERMAL_GENL_CMD_CDEV_GET + 1,
6941ce50e7dSDaniel Lezcano .mcgrps = thermal_genl_mcgrps,
6951ce50e7dSDaniel Lezcano .n_mcgrps = ARRAY_SIZE(thermal_genl_mcgrps),
6961ce50e7dSDaniel Lezcano };
6971ce50e7dSDaniel Lezcano
thermal_netlink_init(void)698d2a89b52SDaniel Lezcano int __init thermal_netlink_init(void)
6991ce50e7dSDaniel Lezcano {
7001ce50e7dSDaniel Lezcano return genl_register_family(&thermal_gnl_family);
7011ce50e7dSDaniel Lezcano }
702*58d1c9fdSDaniel Lezcano
thermal_netlink_exit(void)703*58d1c9fdSDaniel Lezcano void __init thermal_netlink_exit(void)
704*58d1c9fdSDaniel Lezcano {
705*58d1c9fdSDaniel Lezcano genl_unregister_family(&thermal_gnl_family);
706*58d1c9fdSDaniel Lezcano }
707