xref: /openbmc/linux/drivers/thermal/thermal_netlink.c (revision 66a9b9287d2447a91cef2fafc648dee32186f708)
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 },
461ce50e7dSDaniel Lezcano };
471ce50e7dSDaniel Lezcano 
481ce50e7dSDaniel Lezcano struct param {
491ce50e7dSDaniel Lezcano 	struct nlattr **attrs;
501ce50e7dSDaniel Lezcano 	struct sk_buff *msg;
511ce50e7dSDaniel Lezcano 	const char *name;
521ce50e7dSDaniel Lezcano 	int tz_id;
531ce50e7dSDaniel Lezcano 	int cdev_id;
541ce50e7dSDaniel Lezcano 	int trip_id;
551ce50e7dSDaniel Lezcano 	int trip_temp;
561ce50e7dSDaniel Lezcano 	int trip_type;
571ce50e7dSDaniel Lezcano 	int trip_hyst;
581ce50e7dSDaniel Lezcano 	int temp;
591ce50e7dSDaniel Lezcano 	int cdev_state;
601ce50e7dSDaniel Lezcano 	int cdev_max_state;
611ce50e7dSDaniel Lezcano };
621ce50e7dSDaniel Lezcano 
631ce50e7dSDaniel Lezcano typedef int (*cb_t)(struct param *);
641ce50e7dSDaniel Lezcano 
651ce50e7dSDaniel Lezcano static struct genl_family thermal_gnl_family;
661ce50e7dSDaniel Lezcano 
671ce50e7dSDaniel Lezcano /************************** Sampling encoding *******************************/
681ce50e7dSDaniel Lezcano 
691ce50e7dSDaniel Lezcano int thermal_genl_sampling_temp(int id, int temp)
701ce50e7dSDaniel Lezcano {
711ce50e7dSDaniel Lezcano 	struct sk_buff *skb;
721ce50e7dSDaniel Lezcano 	void *hdr;
731ce50e7dSDaniel Lezcano 
741ce50e7dSDaniel Lezcano 	skb = genlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL);
751ce50e7dSDaniel Lezcano 	if (!skb)
761ce50e7dSDaniel Lezcano 		return -ENOMEM;
771ce50e7dSDaniel Lezcano 
781ce50e7dSDaniel Lezcano 	hdr = genlmsg_put(skb, 0, 0, &thermal_gnl_family, 0,
791ce50e7dSDaniel Lezcano 			  THERMAL_GENL_SAMPLING_TEMP);
801ce50e7dSDaniel Lezcano 	if (!hdr)
811ce50e7dSDaniel Lezcano 		return -EMSGSIZE;
821ce50e7dSDaniel Lezcano 
831ce50e7dSDaniel Lezcano 	if (nla_put_u32(skb, THERMAL_GENL_ATTR_TZ_ID, id))
841ce50e7dSDaniel Lezcano 		goto out_cancel;
851ce50e7dSDaniel Lezcano 
861ce50e7dSDaniel Lezcano 	if (nla_put_u32(skb, THERMAL_GENL_ATTR_TZ_TEMP, temp))
871ce50e7dSDaniel Lezcano 		goto out_cancel;
881ce50e7dSDaniel Lezcano 
891ce50e7dSDaniel Lezcano 	genlmsg_end(skb, hdr);
901ce50e7dSDaniel Lezcano 
911ce50e7dSDaniel Lezcano 	genlmsg_multicast(&thermal_gnl_family, skb, 0, 0, GFP_KERNEL);
921ce50e7dSDaniel Lezcano 
931ce50e7dSDaniel Lezcano 	return 0;
941ce50e7dSDaniel Lezcano out_cancel:
951ce50e7dSDaniel Lezcano 	genlmsg_cancel(skb, hdr);
961ce50e7dSDaniel Lezcano 	nlmsg_free(skb);
971ce50e7dSDaniel Lezcano 
981ce50e7dSDaniel Lezcano 	return -EMSGSIZE;
991ce50e7dSDaniel Lezcano }
1001ce50e7dSDaniel Lezcano 
1011ce50e7dSDaniel Lezcano /**************************** Event encoding *********************************/
1021ce50e7dSDaniel Lezcano 
1031ce50e7dSDaniel Lezcano static int thermal_genl_event_tz_create(struct param *p)
1041ce50e7dSDaniel Lezcano {
1051ce50e7dSDaniel Lezcano 	if (nla_put_u32(p->msg, THERMAL_GENL_ATTR_TZ_ID, p->tz_id) ||
1061ce50e7dSDaniel Lezcano 	    nla_put_string(p->msg, THERMAL_GENL_ATTR_TZ_NAME, p->name))
1071ce50e7dSDaniel Lezcano 		return -EMSGSIZE;
1081ce50e7dSDaniel Lezcano 
1091ce50e7dSDaniel Lezcano 	return 0;
1101ce50e7dSDaniel Lezcano }
1111ce50e7dSDaniel Lezcano 
1121ce50e7dSDaniel Lezcano static int thermal_genl_event_tz(struct param *p)
1131ce50e7dSDaniel Lezcano {
1141ce50e7dSDaniel Lezcano 	if (nla_put_u32(p->msg, THERMAL_GENL_ATTR_TZ_ID, p->tz_id))
1151ce50e7dSDaniel Lezcano 		return -EMSGSIZE;
1161ce50e7dSDaniel Lezcano 
1171ce50e7dSDaniel Lezcano 	return 0;
1181ce50e7dSDaniel Lezcano }
1191ce50e7dSDaniel Lezcano 
1201ce50e7dSDaniel Lezcano static int thermal_genl_event_tz_trip_up(struct param *p)
1211ce50e7dSDaniel Lezcano {
1221ce50e7dSDaniel Lezcano 	if (nla_put_u32(p->msg, THERMAL_GENL_ATTR_TZ_ID, p->tz_id) ||
1231ce50e7dSDaniel Lezcano 	    nla_put_u32(p->msg, THERMAL_GENL_ATTR_TZ_TRIP_ID, p->trip_id))
1241ce50e7dSDaniel Lezcano 		return -EMSGSIZE;
1251ce50e7dSDaniel Lezcano 
1261ce50e7dSDaniel Lezcano 	return 0;
1271ce50e7dSDaniel Lezcano }
1281ce50e7dSDaniel Lezcano 
1291ce50e7dSDaniel Lezcano static int thermal_genl_event_tz_trip_add(struct param *p)
1301ce50e7dSDaniel Lezcano {
1311ce50e7dSDaniel Lezcano 	if (nla_put_u32(p->msg, THERMAL_GENL_ATTR_TZ_ID, p->tz_id) ||
1321ce50e7dSDaniel Lezcano 	    nla_put_u32(p->msg, THERMAL_GENL_ATTR_TZ_TRIP_ID, p->trip_id) ||
1331ce50e7dSDaniel Lezcano 	    nla_put_u32(p->msg, THERMAL_GENL_ATTR_TZ_TRIP_TYPE, p->trip_type) ||
1341ce50e7dSDaniel Lezcano 	    nla_put_u32(p->msg, THERMAL_GENL_ATTR_TZ_TRIP_TEMP, p->trip_temp) ||
1351ce50e7dSDaniel Lezcano 	    nla_put_u32(p->msg, THERMAL_GENL_ATTR_TZ_TRIP_HYST, p->trip_hyst))
1361ce50e7dSDaniel Lezcano 		return -EMSGSIZE;
1371ce50e7dSDaniel Lezcano 
1381ce50e7dSDaniel Lezcano 	return 0;
1391ce50e7dSDaniel Lezcano }
1401ce50e7dSDaniel Lezcano 
1411ce50e7dSDaniel Lezcano static int thermal_genl_event_tz_trip_delete(struct param *p)
1421ce50e7dSDaniel Lezcano {
1431ce50e7dSDaniel Lezcano 	if (nla_put_u32(p->msg, THERMAL_GENL_ATTR_TZ_ID, p->tz_id) ||
1441ce50e7dSDaniel Lezcano 	    nla_put_u32(p->msg, THERMAL_GENL_ATTR_TZ_TRIP_ID, p->trip_id))
1451ce50e7dSDaniel Lezcano 		return -EMSGSIZE;
1461ce50e7dSDaniel Lezcano 
1471ce50e7dSDaniel Lezcano 	return 0;
1481ce50e7dSDaniel Lezcano }
1491ce50e7dSDaniel Lezcano 
1501ce50e7dSDaniel Lezcano static int thermal_genl_event_cdev_add(struct param *p)
1511ce50e7dSDaniel Lezcano {
1521ce50e7dSDaniel Lezcano 	if (nla_put_string(p->msg, THERMAL_GENL_ATTR_CDEV_NAME,
1531ce50e7dSDaniel Lezcano 			   p->name) ||
1541ce50e7dSDaniel Lezcano 	    nla_put_u32(p->msg, THERMAL_GENL_ATTR_CDEV_ID,
1551ce50e7dSDaniel Lezcano 			p->cdev_id) ||
1561ce50e7dSDaniel Lezcano 	    nla_put_u32(p->msg, THERMAL_GENL_ATTR_CDEV_MAX_STATE,
1571ce50e7dSDaniel Lezcano 			p->cdev_max_state))
1581ce50e7dSDaniel Lezcano 		return -EMSGSIZE;
1591ce50e7dSDaniel Lezcano 
1601ce50e7dSDaniel Lezcano 	return 0;
1611ce50e7dSDaniel Lezcano }
1621ce50e7dSDaniel Lezcano 
1631ce50e7dSDaniel Lezcano static int thermal_genl_event_cdev_delete(struct param *p)
1641ce50e7dSDaniel Lezcano {
1651ce50e7dSDaniel Lezcano 	if (nla_put_u32(p->msg, THERMAL_GENL_ATTR_CDEV_ID, p->cdev_id))
1661ce50e7dSDaniel Lezcano 		return -EMSGSIZE;
1671ce50e7dSDaniel Lezcano 
1681ce50e7dSDaniel Lezcano 	return 0;
1691ce50e7dSDaniel Lezcano }
1701ce50e7dSDaniel Lezcano 
1711ce50e7dSDaniel Lezcano static int thermal_genl_event_cdev_state_update(struct param *p)
1721ce50e7dSDaniel Lezcano {
1731ce50e7dSDaniel Lezcano 	if (nla_put_u32(p->msg, THERMAL_GENL_ATTR_CDEV_ID,
1741ce50e7dSDaniel Lezcano 			p->cdev_id) ||
1751ce50e7dSDaniel Lezcano 	    nla_put_u32(p->msg, THERMAL_GENL_ATTR_CDEV_CUR_STATE,
1761ce50e7dSDaniel Lezcano 			p->cdev_state))
1771ce50e7dSDaniel Lezcano 		return -EMSGSIZE;
1781ce50e7dSDaniel Lezcano 
1791ce50e7dSDaniel Lezcano 	return 0;
1801ce50e7dSDaniel Lezcano }
1811ce50e7dSDaniel Lezcano 
1821ce50e7dSDaniel Lezcano static int thermal_genl_event_gov_change(struct param *p)
1831ce50e7dSDaniel Lezcano {
1841ce50e7dSDaniel Lezcano 	if (nla_put_u32(p->msg, THERMAL_GENL_ATTR_TZ_ID, p->tz_id) ||
1851ce50e7dSDaniel Lezcano 	    nla_put_string(p->msg, THERMAL_GENL_ATTR_GOV_NAME, p->name))
1861ce50e7dSDaniel Lezcano 		return -EMSGSIZE;
1871ce50e7dSDaniel Lezcano 
1881ce50e7dSDaniel Lezcano 	return 0;
1891ce50e7dSDaniel Lezcano }
1901ce50e7dSDaniel Lezcano 
1911ce50e7dSDaniel Lezcano int thermal_genl_event_tz_delete(struct param *p)
1921ce50e7dSDaniel Lezcano 	__attribute__((alias("thermal_genl_event_tz")));
1931ce50e7dSDaniel Lezcano 
1941ce50e7dSDaniel Lezcano int thermal_genl_event_tz_enable(struct param *p)
1951ce50e7dSDaniel Lezcano 	__attribute__((alias("thermal_genl_event_tz")));
1961ce50e7dSDaniel Lezcano 
1971ce50e7dSDaniel Lezcano int thermal_genl_event_tz_disable(struct param *p)
1981ce50e7dSDaniel Lezcano 	__attribute__((alias("thermal_genl_event_tz")));
1991ce50e7dSDaniel Lezcano 
2001ce50e7dSDaniel Lezcano int thermal_genl_event_tz_trip_down(struct param *p)
2011ce50e7dSDaniel Lezcano 	__attribute__((alias("thermal_genl_event_tz_trip_up")));
2021ce50e7dSDaniel Lezcano 
2031ce50e7dSDaniel Lezcano int thermal_genl_event_tz_trip_change(struct param *p)
2041ce50e7dSDaniel Lezcano 	__attribute__((alias("thermal_genl_event_tz_trip_add")));
2051ce50e7dSDaniel Lezcano 
2061ce50e7dSDaniel Lezcano static cb_t event_cb[] = {
2071ce50e7dSDaniel Lezcano 	[THERMAL_GENL_EVENT_TZ_CREATE]		= thermal_genl_event_tz_create,
2081ce50e7dSDaniel Lezcano 	[THERMAL_GENL_EVENT_TZ_DELETE]		= thermal_genl_event_tz_delete,
2091ce50e7dSDaniel Lezcano 	[THERMAL_GENL_EVENT_TZ_ENABLE]		= thermal_genl_event_tz_enable,
2101ce50e7dSDaniel Lezcano 	[THERMAL_GENL_EVENT_TZ_DISABLE]		= thermal_genl_event_tz_disable,
2111ce50e7dSDaniel Lezcano 	[THERMAL_GENL_EVENT_TZ_TRIP_UP]		= thermal_genl_event_tz_trip_up,
2121ce50e7dSDaniel Lezcano 	[THERMAL_GENL_EVENT_TZ_TRIP_DOWN]	= thermal_genl_event_tz_trip_down,
2131ce50e7dSDaniel Lezcano 	[THERMAL_GENL_EVENT_TZ_TRIP_CHANGE]	= thermal_genl_event_tz_trip_change,
2141ce50e7dSDaniel Lezcano 	[THERMAL_GENL_EVENT_TZ_TRIP_ADD]	= thermal_genl_event_tz_trip_add,
2151ce50e7dSDaniel Lezcano 	[THERMAL_GENL_EVENT_TZ_TRIP_DELETE]	= thermal_genl_event_tz_trip_delete,
2161ce50e7dSDaniel Lezcano 	[THERMAL_GENL_EVENT_CDEV_ADD]		= thermal_genl_event_cdev_add,
2171ce50e7dSDaniel Lezcano 	[THERMAL_GENL_EVENT_CDEV_DELETE]	= thermal_genl_event_cdev_delete,
2181ce50e7dSDaniel Lezcano 	[THERMAL_GENL_EVENT_CDEV_STATE_UPDATE]	= thermal_genl_event_cdev_state_update,
2191ce50e7dSDaniel Lezcano 	[THERMAL_GENL_EVENT_TZ_GOV_CHANGE]	= thermal_genl_event_gov_change,
2201ce50e7dSDaniel Lezcano };
2211ce50e7dSDaniel Lezcano 
2221ce50e7dSDaniel Lezcano /*
2231ce50e7dSDaniel Lezcano  * Generic netlink event encoding
2241ce50e7dSDaniel Lezcano  */
2251ce50e7dSDaniel Lezcano static int thermal_genl_send_event(enum thermal_genl_event event,
2261ce50e7dSDaniel Lezcano 				   struct param *p)
2271ce50e7dSDaniel Lezcano {
2281ce50e7dSDaniel Lezcano 	struct sk_buff *msg;
2291ce50e7dSDaniel Lezcano 	int ret = -EMSGSIZE;
2301ce50e7dSDaniel Lezcano 	void *hdr;
2311ce50e7dSDaniel Lezcano 
2321ce50e7dSDaniel Lezcano 	msg = genlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL);
2331ce50e7dSDaniel Lezcano 	if (!msg)
2341ce50e7dSDaniel Lezcano 		return -ENOMEM;
2351ce50e7dSDaniel Lezcano 	p->msg = msg;
2361ce50e7dSDaniel Lezcano 
2371ce50e7dSDaniel Lezcano 	hdr = genlmsg_put(msg, 0, 0, &thermal_gnl_family, 0, event);
2381ce50e7dSDaniel Lezcano 	if (!hdr)
2391ce50e7dSDaniel Lezcano 		goto out_free_msg;
2401ce50e7dSDaniel Lezcano 
2411ce50e7dSDaniel Lezcano 	ret = event_cb[event](p);
2421ce50e7dSDaniel Lezcano 	if (ret)
2431ce50e7dSDaniel Lezcano 		goto out_cancel_msg;
2441ce50e7dSDaniel Lezcano 
2451ce50e7dSDaniel Lezcano 	genlmsg_end(msg, hdr);
2461ce50e7dSDaniel Lezcano 
2471ce50e7dSDaniel Lezcano 	genlmsg_multicast(&thermal_gnl_family, msg, 0, 1, GFP_KERNEL);
2481ce50e7dSDaniel Lezcano 
2491ce50e7dSDaniel Lezcano 	return 0;
2501ce50e7dSDaniel Lezcano 
2511ce50e7dSDaniel Lezcano out_cancel_msg:
2521ce50e7dSDaniel Lezcano 	genlmsg_cancel(msg, hdr);
2531ce50e7dSDaniel Lezcano out_free_msg:
2541ce50e7dSDaniel Lezcano 	nlmsg_free(msg);
2551ce50e7dSDaniel Lezcano 
2561ce50e7dSDaniel Lezcano 	return ret;
2571ce50e7dSDaniel Lezcano }
2581ce50e7dSDaniel Lezcano 
2591ce50e7dSDaniel Lezcano int thermal_notify_tz_create(int tz_id, const char *name)
2601ce50e7dSDaniel Lezcano {
2611ce50e7dSDaniel Lezcano 	struct param p = { .tz_id = tz_id, .name = name };
2621ce50e7dSDaniel Lezcano 
2631ce50e7dSDaniel Lezcano 	return thermal_genl_send_event(THERMAL_GENL_EVENT_TZ_CREATE, &p);
2641ce50e7dSDaniel Lezcano }
2651ce50e7dSDaniel Lezcano 
2661ce50e7dSDaniel Lezcano int thermal_notify_tz_delete(int tz_id)
2671ce50e7dSDaniel Lezcano {
2681ce50e7dSDaniel Lezcano 	struct param p = { .tz_id = tz_id };
2691ce50e7dSDaniel Lezcano 
2701ce50e7dSDaniel Lezcano 	return thermal_genl_send_event(THERMAL_GENL_EVENT_TZ_DELETE, &p);
2711ce50e7dSDaniel Lezcano }
2721ce50e7dSDaniel Lezcano 
2731ce50e7dSDaniel Lezcano int thermal_notify_tz_enable(int tz_id)
2741ce50e7dSDaniel Lezcano {
2751ce50e7dSDaniel Lezcano 	struct param p = { .tz_id = tz_id };
2761ce50e7dSDaniel Lezcano 
2771ce50e7dSDaniel Lezcano 	return thermal_genl_send_event(THERMAL_GENL_EVENT_TZ_ENABLE, &p);
2781ce50e7dSDaniel Lezcano }
2791ce50e7dSDaniel Lezcano 
2801ce50e7dSDaniel Lezcano int thermal_notify_tz_disable(int tz_id)
2811ce50e7dSDaniel Lezcano {
2821ce50e7dSDaniel Lezcano 	struct param p = { .tz_id = tz_id };
2831ce50e7dSDaniel Lezcano 
2841ce50e7dSDaniel Lezcano 	return thermal_genl_send_event(THERMAL_GENL_EVENT_TZ_DISABLE, &p);
2851ce50e7dSDaniel Lezcano }
2861ce50e7dSDaniel Lezcano 
2871ce50e7dSDaniel Lezcano int thermal_notify_tz_trip_down(int tz_id, int trip_id)
2881ce50e7dSDaniel Lezcano {
2891ce50e7dSDaniel Lezcano 	struct param p = { .tz_id = tz_id, .trip_id = trip_id };
2901ce50e7dSDaniel Lezcano 
2911ce50e7dSDaniel Lezcano 	return thermal_genl_send_event(THERMAL_GENL_EVENT_TZ_TRIP_DOWN, &p);
2921ce50e7dSDaniel Lezcano }
2931ce50e7dSDaniel Lezcano 
2941ce50e7dSDaniel Lezcano int thermal_notify_tz_trip_up(int tz_id, int trip_id)
2951ce50e7dSDaniel Lezcano {
2961ce50e7dSDaniel Lezcano 	struct param p = { .tz_id = tz_id, .trip_id = trip_id };
2971ce50e7dSDaniel Lezcano 
2981ce50e7dSDaniel Lezcano 	return thermal_genl_send_event(THERMAL_GENL_EVENT_TZ_TRIP_UP, &p);
2991ce50e7dSDaniel Lezcano }
3001ce50e7dSDaniel Lezcano 
3011ce50e7dSDaniel Lezcano int thermal_notify_tz_trip_add(int tz_id, int trip_id, int trip_type,
3021ce50e7dSDaniel Lezcano 			       int trip_temp, int trip_hyst)
3031ce50e7dSDaniel Lezcano {
3041ce50e7dSDaniel Lezcano 	struct param p = { .tz_id = tz_id, .trip_id = trip_id,
3051ce50e7dSDaniel Lezcano 			   .trip_type = trip_type, .trip_temp = trip_temp,
3061ce50e7dSDaniel Lezcano 			   .trip_hyst = trip_hyst };
3071ce50e7dSDaniel Lezcano 
3081ce50e7dSDaniel Lezcano 	return thermal_genl_send_event(THERMAL_GENL_EVENT_TZ_TRIP_ADD, &p);
3091ce50e7dSDaniel Lezcano }
3101ce50e7dSDaniel Lezcano 
3111ce50e7dSDaniel Lezcano int thermal_notify_tz_trip_delete(int tz_id, int trip_id)
3121ce50e7dSDaniel Lezcano {
3131ce50e7dSDaniel Lezcano 	struct param p = { .tz_id = tz_id, .trip_id = trip_id };
3141ce50e7dSDaniel Lezcano 
3151ce50e7dSDaniel Lezcano 	return thermal_genl_send_event(THERMAL_GENL_EVENT_TZ_TRIP_DELETE, &p);
3161ce50e7dSDaniel Lezcano }
3171ce50e7dSDaniel Lezcano 
3181ce50e7dSDaniel Lezcano int thermal_notify_tz_trip_change(int tz_id, int trip_id, int trip_type,
3191ce50e7dSDaniel Lezcano 				  int trip_temp, int trip_hyst)
3201ce50e7dSDaniel Lezcano {
3211ce50e7dSDaniel Lezcano 	struct param p = { .tz_id = tz_id, .trip_id = trip_id,
3221ce50e7dSDaniel Lezcano 			   .trip_type = trip_type, .trip_temp = trip_temp,
3231ce50e7dSDaniel Lezcano 			   .trip_hyst = trip_hyst };
3241ce50e7dSDaniel Lezcano 
3251ce50e7dSDaniel Lezcano 	return thermal_genl_send_event(THERMAL_GENL_EVENT_TZ_TRIP_CHANGE, &p);
3261ce50e7dSDaniel Lezcano }
3271ce50e7dSDaniel Lezcano 
3281ce50e7dSDaniel Lezcano int thermal_notify_cdev_state_update(int cdev_id, int cdev_state)
3291ce50e7dSDaniel Lezcano {
3301ce50e7dSDaniel Lezcano 	struct param p = { .cdev_id = cdev_id, .cdev_state = cdev_state };
3311ce50e7dSDaniel Lezcano 
3321ce50e7dSDaniel Lezcano 	return thermal_genl_send_event(THERMAL_GENL_EVENT_CDEV_STATE_UPDATE, &p);
3331ce50e7dSDaniel Lezcano }
3341ce50e7dSDaniel Lezcano 
3351ce50e7dSDaniel Lezcano int thermal_notify_cdev_add(int cdev_id, const char *name, int cdev_max_state)
3361ce50e7dSDaniel Lezcano {
3371ce50e7dSDaniel Lezcano 	struct param p = { .cdev_id = cdev_id, .name = name,
3381ce50e7dSDaniel Lezcano 			   .cdev_max_state = cdev_max_state };
3391ce50e7dSDaniel Lezcano 
3401ce50e7dSDaniel Lezcano 	return thermal_genl_send_event(THERMAL_GENL_EVENT_CDEV_ADD, &p);
3411ce50e7dSDaniel Lezcano }
3421ce50e7dSDaniel Lezcano 
3431ce50e7dSDaniel Lezcano int thermal_notify_cdev_delete(int cdev_id)
3441ce50e7dSDaniel Lezcano {
3451ce50e7dSDaniel Lezcano 	struct param p = { .cdev_id = cdev_id };
3461ce50e7dSDaniel Lezcano 
3471ce50e7dSDaniel Lezcano 	return thermal_genl_send_event(THERMAL_GENL_EVENT_CDEV_DELETE, &p);
3481ce50e7dSDaniel Lezcano }
3491ce50e7dSDaniel Lezcano 
3501ce50e7dSDaniel Lezcano int thermal_notify_tz_gov_change(int tz_id, const char *name)
3511ce50e7dSDaniel Lezcano {
3521ce50e7dSDaniel Lezcano 	struct param p = { .tz_id = tz_id, .name = name };
3531ce50e7dSDaniel Lezcano 
3541ce50e7dSDaniel Lezcano 	return thermal_genl_send_event(THERMAL_GENL_EVENT_TZ_GOV_CHANGE, &p);
3551ce50e7dSDaniel Lezcano }
3561ce50e7dSDaniel Lezcano 
3571ce50e7dSDaniel Lezcano /*************************** Command encoding ********************************/
3581ce50e7dSDaniel Lezcano 
3591ce50e7dSDaniel Lezcano static int __thermal_genl_cmd_tz_get_id(struct thermal_zone_device *tz,
3601ce50e7dSDaniel Lezcano 					void *data)
3611ce50e7dSDaniel Lezcano {
3621ce50e7dSDaniel Lezcano 	struct sk_buff *msg = data;
3631ce50e7dSDaniel Lezcano 
3641ce50e7dSDaniel Lezcano 	if (nla_put_u32(msg, THERMAL_GENL_ATTR_TZ_ID, tz->id) ||
3651ce50e7dSDaniel Lezcano 	    nla_put_string(msg, THERMAL_GENL_ATTR_TZ_NAME, tz->type))
3661ce50e7dSDaniel Lezcano 		return -EMSGSIZE;
3671ce50e7dSDaniel Lezcano 
3681ce50e7dSDaniel Lezcano 	return 0;
3691ce50e7dSDaniel Lezcano }
3701ce50e7dSDaniel Lezcano 
3711ce50e7dSDaniel Lezcano static int thermal_genl_cmd_tz_get_id(struct param *p)
3721ce50e7dSDaniel Lezcano {
3731ce50e7dSDaniel Lezcano 	struct sk_buff *msg = p->msg;
3741ce50e7dSDaniel Lezcano 	struct nlattr *start_tz;
3751ce50e7dSDaniel Lezcano 	int ret;
3761ce50e7dSDaniel Lezcano 
3771ce50e7dSDaniel Lezcano 	start_tz = nla_nest_start(msg, THERMAL_GENL_ATTR_TZ);
3781ce50e7dSDaniel Lezcano 	if (!start_tz)
3791ce50e7dSDaniel Lezcano 		return -EMSGSIZE;
3801ce50e7dSDaniel Lezcano 
3811ce50e7dSDaniel Lezcano 	ret = for_each_thermal_zone(__thermal_genl_cmd_tz_get_id, msg);
3821ce50e7dSDaniel Lezcano 	if (ret)
3831ce50e7dSDaniel Lezcano 		goto out_cancel_nest;
3841ce50e7dSDaniel Lezcano 
3851ce50e7dSDaniel Lezcano 	nla_nest_end(msg, start_tz);
3861ce50e7dSDaniel Lezcano 
3871ce50e7dSDaniel Lezcano 	return 0;
3881ce50e7dSDaniel Lezcano 
3891ce50e7dSDaniel Lezcano out_cancel_nest:
3901ce50e7dSDaniel Lezcano 	nla_nest_cancel(msg, start_tz);
3911ce50e7dSDaniel Lezcano 
3921ce50e7dSDaniel Lezcano 	return ret;
3931ce50e7dSDaniel Lezcano }
3941ce50e7dSDaniel Lezcano 
3951ce50e7dSDaniel Lezcano static int thermal_genl_cmd_tz_get_trip(struct param *p)
3961ce50e7dSDaniel Lezcano {
3971ce50e7dSDaniel Lezcano 	struct sk_buff *msg = p->msg;
3981ce50e7dSDaniel Lezcano 	struct thermal_zone_device *tz;
3991ce50e7dSDaniel Lezcano 	struct nlattr *start_trip;
4001ce50e7dSDaniel Lezcano 	int i, id;
4011ce50e7dSDaniel Lezcano 
4021ce50e7dSDaniel Lezcano 	if (!p->attrs[THERMAL_GENL_ATTR_TZ_ID])
4031ce50e7dSDaniel Lezcano 		return -EINVAL;
4041ce50e7dSDaniel Lezcano 
4051ce50e7dSDaniel Lezcano 	id = nla_get_u32(p->attrs[THERMAL_GENL_ATTR_TZ_ID]);
4061ce50e7dSDaniel Lezcano 
4071ce50e7dSDaniel Lezcano 	tz = thermal_zone_get_by_id(id);
4081ce50e7dSDaniel Lezcano 	if (!tz)
4091ce50e7dSDaniel Lezcano 		return -EINVAL;
4101ce50e7dSDaniel Lezcano 
4111ce50e7dSDaniel Lezcano 	start_trip = nla_nest_start(msg, THERMAL_GENL_ATTR_TZ_TRIP);
4121ce50e7dSDaniel Lezcano 	if (!start_trip)
4131ce50e7dSDaniel Lezcano 		return -EMSGSIZE;
4141ce50e7dSDaniel Lezcano 
4151ce50e7dSDaniel Lezcano 	mutex_lock(&tz->lock);
4161ce50e7dSDaniel Lezcano 
4171ce50e7dSDaniel Lezcano 	for (i = 0; i < tz->trips; i++) {
4181ce50e7dSDaniel Lezcano 
4191ce50e7dSDaniel Lezcano 		enum thermal_trip_type type;
4201ce50e7dSDaniel Lezcano 		int temp, hyst;
4211ce50e7dSDaniel Lezcano 
4221ce50e7dSDaniel Lezcano 		tz->ops->get_trip_type(tz, i, &type);
4231ce50e7dSDaniel Lezcano 		tz->ops->get_trip_temp(tz, i, &temp);
4241ce50e7dSDaniel Lezcano 		tz->ops->get_trip_hyst(tz, i, &hyst);
4251ce50e7dSDaniel Lezcano 
4261ce50e7dSDaniel Lezcano 		if (nla_put_u32(msg, THERMAL_GENL_ATTR_TZ_TRIP_ID, i) ||
4271ce50e7dSDaniel Lezcano 		    nla_put_u32(msg, THERMAL_GENL_ATTR_TZ_TRIP_TYPE, type) ||
4281ce50e7dSDaniel Lezcano 		    nla_put_u32(msg, THERMAL_GENL_ATTR_TZ_TRIP_TEMP, temp) ||
4291ce50e7dSDaniel Lezcano 		    nla_put_u32(msg, THERMAL_GENL_ATTR_TZ_TRIP_HYST, hyst))
4301ce50e7dSDaniel Lezcano 			goto out_cancel_nest;
4311ce50e7dSDaniel Lezcano 	}
4321ce50e7dSDaniel Lezcano 
4331ce50e7dSDaniel Lezcano 	mutex_unlock(&tz->lock);
4341ce50e7dSDaniel Lezcano 
4351ce50e7dSDaniel Lezcano 	nla_nest_end(msg, start_trip);
4361ce50e7dSDaniel Lezcano 
4371ce50e7dSDaniel Lezcano 	return 0;
4381ce50e7dSDaniel Lezcano 
4391ce50e7dSDaniel Lezcano out_cancel_nest:
4401ce50e7dSDaniel Lezcano 	mutex_unlock(&tz->lock);
4411ce50e7dSDaniel Lezcano 
4421ce50e7dSDaniel Lezcano 	return -EMSGSIZE;
4431ce50e7dSDaniel Lezcano }
4441ce50e7dSDaniel Lezcano 
4451ce50e7dSDaniel Lezcano static int thermal_genl_cmd_tz_get_temp(struct param *p)
4461ce50e7dSDaniel Lezcano {
4471ce50e7dSDaniel Lezcano 	struct sk_buff *msg = p->msg;
4481ce50e7dSDaniel Lezcano 	struct thermal_zone_device *tz;
4491ce50e7dSDaniel Lezcano 	int temp, ret, id;
4501ce50e7dSDaniel Lezcano 
4511ce50e7dSDaniel Lezcano 	if (!p->attrs[THERMAL_GENL_ATTR_TZ_ID])
4521ce50e7dSDaniel Lezcano 		return -EINVAL;
4531ce50e7dSDaniel Lezcano 
4541ce50e7dSDaniel Lezcano 	id = nla_get_u32(p->attrs[THERMAL_GENL_ATTR_TZ_ID]);
4551ce50e7dSDaniel Lezcano 
4561ce50e7dSDaniel Lezcano 	tz = thermal_zone_get_by_id(id);
4571ce50e7dSDaniel Lezcano 	if (!tz)
4581ce50e7dSDaniel Lezcano 		return -EINVAL;
4591ce50e7dSDaniel Lezcano 
4601ce50e7dSDaniel Lezcano 	ret = thermal_zone_get_temp(tz, &temp);
4611ce50e7dSDaniel Lezcano 	if (ret)
4621ce50e7dSDaniel Lezcano 		return ret;
4631ce50e7dSDaniel Lezcano 
4641ce50e7dSDaniel Lezcano 	if (nla_put_u32(msg, THERMAL_GENL_ATTR_TZ_ID, id) ||
4651ce50e7dSDaniel Lezcano 	    nla_put_u32(msg, THERMAL_GENL_ATTR_TZ_TEMP, temp))
4661ce50e7dSDaniel Lezcano 		return -EMSGSIZE;
4671ce50e7dSDaniel Lezcano 
4681ce50e7dSDaniel Lezcano 	return 0;
4691ce50e7dSDaniel Lezcano }
4701ce50e7dSDaniel Lezcano 
4711ce50e7dSDaniel Lezcano static int thermal_genl_cmd_tz_get_gov(struct param *p)
4721ce50e7dSDaniel Lezcano {
4731ce50e7dSDaniel Lezcano 	struct sk_buff *msg = p->msg;
4741ce50e7dSDaniel Lezcano 	struct thermal_zone_device *tz;
4751ce50e7dSDaniel Lezcano 	int id, ret = 0;
4761ce50e7dSDaniel Lezcano 
4771ce50e7dSDaniel Lezcano 	if (!p->attrs[THERMAL_GENL_ATTR_TZ_ID])
4781ce50e7dSDaniel Lezcano 		return -EINVAL;
4791ce50e7dSDaniel Lezcano 
4801ce50e7dSDaniel Lezcano 	id = nla_get_u32(p->attrs[THERMAL_GENL_ATTR_TZ_ID]);
4811ce50e7dSDaniel Lezcano 
4821ce50e7dSDaniel Lezcano 	tz = thermal_zone_get_by_id(id);
4831ce50e7dSDaniel Lezcano 	if (!tz)
4841ce50e7dSDaniel Lezcano 		return -EINVAL;
4851ce50e7dSDaniel Lezcano 
4861ce50e7dSDaniel Lezcano 	mutex_lock(&tz->lock);
4871ce50e7dSDaniel Lezcano 
4881ce50e7dSDaniel Lezcano 	if (nla_put_u32(msg, THERMAL_GENL_ATTR_TZ_ID, id) ||
4891ce50e7dSDaniel Lezcano 	    nla_put_string(msg, THERMAL_GENL_ATTR_TZ_GOV_NAME,
4901ce50e7dSDaniel Lezcano 			   tz->governor->name))
4911ce50e7dSDaniel Lezcano 		ret = -EMSGSIZE;
4921ce50e7dSDaniel Lezcano 
4931ce50e7dSDaniel Lezcano 	mutex_unlock(&tz->lock);
4941ce50e7dSDaniel Lezcano 
4951ce50e7dSDaniel Lezcano 	return ret;
4961ce50e7dSDaniel Lezcano }
4971ce50e7dSDaniel Lezcano 
4981ce50e7dSDaniel Lezcano static int __thermal_genl_cmd_cdev_get(struct thermal_cooling_device *cdev,
4991ce50e7dSDaniel Lezcano 				       void *data)
5001ce50e7dSDaniel Lezcano {
5011ce50e7dSDaniel Lezcano 	struct sk_buff *msg = data;
5021ce50e7dSDaniel Lezcano 
5031ce50e7dSDaniel Lezcano 	if (nla_put_u32(msg, THERMAL_GENL_ATTR_CDEV_ID, cdev->id))
5041ce50e7dSDaniel Lezcano 		return -EMSGSIZE;
5051ce50e7dSDaniel Lezcano 
5061ce50e7dSDaniel Lezcano 	if (nla_put_string(msg, THERMAL_GENL_ATTR_CDEV_NAME, cdev->type))
5071ce50e7dSDaniel Lezcano 		return -EMSGSIZE;
5081ce50e7dSDaniel Lezcano 
5091ce50e7dSDaniel Lezcano 	return 0;
5101ce50e7dSDaniel Lezcano }
5111ce50e7dSDaniel Lezcano 
5121ce50e7dSDaniel Lezcano static int thermal_genl_cmd_cdev_get(struct param *p)
5131ce50e7dSDaniel Lezcano {
5141ce50e7dSDaniel Lezcano 	struct sk_buff *msg = p->msg;
5151ce50e7dSDaniel Lezcano 	struct nlattr *start_cdev;
5161ce50e7dSDaniel Lezcano 	int ret;
5171ce50e7dSDaniel Lezcano 
5181ce50e7dSDaniel Lezcano 	start_cdev = nla_nest_start(msg, THERMAL_GENL_ATTR_CDEV);
5191ce50e7dSDaniel Lezcano 	if (!start_cdev)
5201ce50e7dSDaniel Lezcano 		return -EMSGSIZE;
5211ce50e7dSDaniel Lezcano 
5221ce50e7dSDaniel Lezcano 	ret = for_each_thermal_cooling_device(__thermal_genl_cmd_cdev_get, msg);
5231ce50e7dSDaniel Lezcano 	if (ret)
5241ce50e7dSDaniel Lezcano 		goto out_cancel_nest;
5251ce50e7dSDaniel Lezcano 
5261ce50e7dSDaniel Lezcano 	nla_nest_end(msg, start_cdev);
5271ce50e7dSDaniel Lezcano 
5281ce50e7dSDaniel Lezcano 	return 0;
5291ce50e7dSDaniel Lezcano out_cancel_nest:
5301ce50e7dSDaniel Lezcano 	nla_nest_cancel(msg, start_cdev);
5311ce50e7dSDaniel Lezcano 
5321ce50e7dSDaniel Lezcano 	return ret;
5331ce50e7dSDaniel Lezcano }
5341ce50e7dSDaniel Lezcano 
5351ce50e7dSDaniel Lezcano static cb_t cmd_cb[] = {
5361ce50e7dSDaniel Lezcano 	[THERMAL_GENL_CMD_TZ_GET_ID]	= thermal_genl_cmd_tz_get_id,
5371ce50e7dSDaniel Lezcano 	[THERMAL_GENL_CMD_TZ_GET_TRIP]	= thermal_genl_cmd_tz_get_trip,
5381ce50e7dSDaniel Lezcano 	[THERMAL_GENL_CMD_TZ_GET_TEMP]	= thermal_genl_cmd_tz_get_temp,
5391ce50e7dSDaniel Lezcano 	[THERMAL_GENL_CMD_TZ_GET_GOV]	= thermal_genl_cmd_tz_get_gov,
5401ce50e7dSDaniel Lezcano 	[THERMAL_GENL_CMD_CDEV_GET]	= thermal_genl_cmd_cdev_get,
5411ce50e7dSDaniel Lezcano };
5421ce50e7dSDaniel Lezcano 
5431ce50e7dSDaniel Lezcano static int thermal_genl_cmd_dumpit(struct sk_buff *skb,
5441ce50e7dSDaniel Lezcano 				   struct netlink_callback *cb)
5451ce50e7dSDaniel Lezcano {
5461ce50e7dSDaniel Lezcano 	struct param p = { .msg = skb };
5471ce50e7dSDaniel Lezcano 	const struct genl_dumpit_info *info = genl_dumpit_info(cb);
5480b588afdSJakub Kicinski 	int cmd = info->op.cmd;
54952674f56SColin Ian King 	int ret;
5501ce50e7dSDaniel Lezcano 	void *hdr;
5511ce50e7dSDaniel Lezcano 
5521ce50e7dSDaniel Lezcano 	hdr = genlmsg_put(skb, 0, 0, &thermal_gnl_family, 0, cmd);
5531ce50e7dSDaniel Lezcano 	if (!hdr)
5541ce50e7dSDaniel Lezcano 		return -EMSGSIZE;
5551ce50e7dSDaniel Lezcano 
5561ce50e7dSDaniel Lezcano 	ret = cmd_cb[cmd](&p);
5571ce50e7dSDaniel Lezcano 	if (ret)
5581ce50e7dSDaniel Lezcano 		goto out_cancel_msg;
5591ce50e7dSDaniel Lezcano 
5601ce50e7dSDaniel Lezcano 	genlmsg_end(skb, hdr);
5611ce50e7dSDaniel Lezcano 
5621ce50e7dSDaniel Lezcano 	return 0;
5631ce50e7dSDaniel Lezcano 
5641ce50e7dSDaniel Lezcano out_cancel_msg:
5651ce50e7dSDaniel Lezcano 	genlmsg_cancel(skb, hdr);
5661ce50e7dSDaniel Lezcano 
5671ce50e7dSDaniel Lezcano 	return ret;
5681ce50e7dSDaniel Lezcano }
5691ce50e7dSDaniel Lezcano 
5701ce50e7dSDaniel Lezcano static int thermal_genl_cmd_doit(struct sk_buff *skb,
5711ce50e7dSDaniel Lezcano 				 struct genl_info *info)
5721ce50e7dSDaniel Lezcano {
5731ce50e7dSDaniel Lezcano 	struct param p = { .attrs = info->attrs };
5741ce50e7dSDaniel Lezcano 	struct sk_buff *msg;
5751ce50e7dSDaniel Lezcano 	void *hdr;
5761ce50e7dSDaniel Lezcano 	int cmd = info->genlhdr->cmd;
5771ce50e7dSDaniel Lezcano 	int ret = -EMSGSIZE;
5781ce50e7dSDaniel Lezcano 
5791ce50e7dSDaniel Lezcano 	msg = genlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL);
5801ce50e7dSDaniel Lezcano 	if (!msg)
5811ce50e7dSDaniel Lezcano 		return -ENOMEM;
5821ce50e7dSDaniel Lezcano 	p.msg = msg;
5831ce50e7dSDaniel Lezcano 
5841ce50e7dSDaniel Lezcano 	hdr = genlmsg_put_reply(msg, info, &thermal_gnl_family, 0, cmd);
5851ce50e7dSDaniel Lezcano 	if (!hdr)
5861ce50e7dSDaniel Lezcano 		goto out_free_msg;
5871ce50e7dSDaniel Lezcano 
5881ce50e7dSDaniel Lezcano 	ret = cmd_cb[cmd](&p);
5891ce50e7dSDaniel Lezcano 	if (ret)
5901ce50e7dSDaniel Lezcano 		goto out_cancel_msg;
5911ce50e7dSDaniel Lezcano 
5921ce50e7dSDaniel Lezcano 	genlmsg_end(msg, hdr);
5931ce50e7dSDaniel Lezcano 
5941ce50e7dSDaniel Lezcano 	return genlmsg_reply(msg, info);
5951ce50e7dSDaniel Lezcano 
5961ce50e7dSDaniel Lezcano out_cancel_msg:
5971ce50e7dSDaniel Lezcano 	genlmsg_cancel(msg, hdr);
5981ce50e7dSDaniel Lezcano out_free_msg:
5991ce50e7dSDaniel Lezcano 	nlmsg_free(msg);
6001ce50e7dSDaniel Lezcano 
6011ce50e7dSDaniel Lezcano 	return ret;
6021ce50e7dSDaniel Lezcano }
6031ce50e7dSDaniel Lezcano 
604*66a9b928SJakub Kicinski static const struct genl_small_ops thermal_genl_ops[] = {
6051ce50e7dSDaniel Lezcano 	{
6061ce50e7dSDaniel Lezcano 		.cmd = THERMAL_GENL_CMD_TZ_GET_ID,
6071ce50e7dSDaniel Lezcano 		.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
6081ce50e7dSDaniel Lezcano 		.dumpit = thermal_genl_cmd_dumpit,
6091ce50e7dSDaniel Lezcano 	},
6101ce50e7dSDaniel Lezcano 	{
6111ce50e7dSDaniel Lezcano 		.cmd = THERMAL_GENL_CMD_TZ_GET_TRIP,
6121ce50e7dSDaniel Lezcano 		.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
6131ce50e7dSDaniel Lezcano 		.doit = thermal_genl_cmd_doit,
6141ce50e7dSDaniel Lezcano 	},
6151ce50e7dSDaniel Lezcano 	{
6161ce50e7dSDaniel Lezcano 		.cmd = THERMAL_GENL_CMD_TZ_GET_TEMP,
6171ce50e7dSDaniel Lezcano 		.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
6181ce50e7dSDaniel Lezcano 		.doit = thermal_genl_cmd_doit,
6191ce50e7dSDaniel Lezcano 	},
6201ce50e7dSDaniel Lezcano 	{
6211ce50e7dSDaniel Lezcano 		.cmd = THERMAL_GENL_CMD_TZ_GET_GOV,
6221ce50e7dSDaniel Lezcano 		.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
6231ce50e7dSDaniel Lezcano 		.doit = thermal_genl_cmd_doit,
6241ce50e7dSDaniel Lezcano 	},
6251ce50e7dSDaniel Lezcano 	{
6261ce50e7dSDaniel Lezcano 		.cmd = THERMAL_GENL_CMD_CDEV_GET,
6271ce50e7dSDaniel Lezcano 		.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
6281ce50e7dSDaniel Lezcano 		.dumpit = thermal_genl_cmd_dumpit,
6291ce50e7dSDaniel Lezcano 	},
6301ce50e7dSDaniel Lezcano };
6311ce50e7dSDaniel Lezcano 
6321ce50e7dSDaniel Lezcano static struct genl_family thermal_gnl_family __ro_after_init = {
6331ce50e7dSDaniel Lezcano 	.hdrsize	= 0,
6341ce50e7dSDaniel Lezcano 	.name		= THERMAL_GENL_FAMILY_NAME,
6351ce50e7dSDaniel Lezcano 	.version	= THERMAL_GENL_VERSION,
6361ce50e7dSDaniel Lezcano 	.maxattr	= THERMAL_GENL_ATTR_MAX,
6371ce50e7dSDaniel Lezcano 	.policy		= thermal_genl_policy,
638*66a9b928SJakub Kicinski 	.small_ops	= thermal_genl_ops,
639*66a9b928SJakub Kicinski 	.n_small_ops	= ARRAY_SIZE(thermal_genl_ops),
6401ce50e7dSDaniel Lezcano 	.mcgrps		= thermal_genl_mcgrps,
6411ce50e7dSDaniel Lezcano 	.n_mcgrps	= ARRAY_SIZE(thermal_genl_mcgrps),
6421ce50e7dSDaniel Lezcano };
6431ce50e7dSDaniel Lezcano 
644d2a89b52SDaniel Lezcano int __init thermal_netlink_init(void)
6451ce50e7dSDaniel Lezcano {
6461ce50e7dSDaniel Lezcano 	return genl_register_family(&thermal_gnl_family);
6471ce50e7dSDaniel Lezcano }
648