xref: /openbmc/linux/tools/lib/thermal/events.c (revision 4f2c0a4acffbec01079c28f839422e64ddeff004)
1*47c4b0deSDaniel Lezcano // SPDX-License-Identifier: LGPL-2.1+
2*47c4b0deSDaniel Lezcano // Copyright (C) 2022, Linaro Ltd - Daniel Lezcano <daniel.lezcano@linaro.org>
3*47c4b0deSDaniel Lezcano #include <linux/netlink.h>
4*47c4b0deSDaniel Lezcano #include <stdio.h>
5*47c4b0deSDaniel Lezcano #include <stdlib.h>
6*47c4b0deSDaniel Lezcano #include <unistd.h>
7*47c4b0deSDaniel Lezcano 
8*47c4b0deSDaniel Lezcano 
9*47c4b0deSDaniel Lezcano #include <thermal.h>
10*47c4b0deSDaniel Lezcano #include "thermal_nl.h"
11*47c4b0deSDaniel Lezcano 
12*47c4b0deSDaniel Lezcano /*
13*47c4b0deSDaniel Lezcano  * Optimization: fill this array to tell which event we do want to pay
14*47c4b0deSDaniel Lezcano  * attention to. That happens at init time with the ops
15*47c4b0deSDaniel Lezcano  * structure. Each ops will enable the event and the general handler
16*47c4b0deSDaniel Lezcano  * will be able to discard the event if there is not ops associated
17*47c4b0deSDaniel Lezcano  * with it.
18*47c4b0deSDaniel Lezcano  */
19*47c4b0deSDaniel Lezcano static int enabled_ops[__THERMAL_GENL_EVENT_MAX];
20*47c4b0deSDaniel Lezcano 
handle_thermal_event(struct nl_msg * n,void * arg)21*47c4b0deSDaniel Lezcano static int handle_thermal_event(struct nl_msg *n, void *arg)
22*47c4b0deSDaniel Lezcano {
23*47c4b0deSDaniel Lezcano 	struct nlmsghdr *nlh = nlmsg_hdr(n);
24*47c4b0deSDaniel Lezcano 	struct genlmsghdr *genlhdr = genlmsg_hdr(nlh);
25*47c4b0deSDaniel Lezcano 	struct nlattr *attrs[THERMAL_GENL_ATTR_MAX + 1];
26*47c4b0deSDaniel Lezcano 	struct thermal_handler_param *thp = arg;
27*47c4b0deSDaniel Lezcano 	struct thermal_events_ops *ops = &thp->th->ops->events;
28*47c4b0deSDaniel Lezcano 
29*47c4b0deSDaniel Lezcano 	genlmsg_parse(nlh, 0, attrs, THERMAL_GENL_ATTR_MAX, NULL);
30*47c4b0deSDaniel Lezcano 
31*47c4b0deSDaniel Lezcano 	arg = thp->arg;
32*47c4b0deSDaniel Lezcano 
33*47c4b0deSDaniel Lezcano 	/*
34*47c4b0deSDaniel Lezcano 	 * This is an event we don't care of, bail out.
35*47c4b0deSDaniel Lezcano 	 */
36*47c4b0deSDaniel Lezcano 	if (!enabled_ops[genlhdr->cmd])
37*47c4b0deSDaniel Lezcano 		return THERMAL_SUCCESS;
38*47c4b0deSDaniel Lezcano 
39*47c4b0deSDaniel Lezcano 	switch (genlhdr->cmd) {
40*47c4b0deSDaniel Lezcano 
41*47c4b0deSDaniel Lezcano 	case THERMAL_GENL_EVENT_TZ_CREATE:
42*47c4b0deSDaniel Lezcano 		return ops->tz_create(nla_get_string(attrs[THERMAL_GENL_ATTR_TZ_NAME]),
43*47c4b0deSDaniel Lezcano 				      nla_get_u32(attrs[THERMAL_GENL_ATTR_TZ_ID]), arg);
44*47c4b0deSDaniel Lezcano 
45*47c4b0deSDaniel Lezcano 	case THERMAL_GENL_EVENT_TZ_DELETE:
46*47c4b0deSDaniel Lezcano 		return ops->tz_delete(nla_get_u32(attrs[THERMAL_GENL_ATTR_TZ_ID]), arg);
47*47c4b0deSDaniel Lezcano 
48*47c4b0deSDaniel Lezcano 	case THERMAL_GENL_EVENT_TZ_ENABLE:
49*47c4b0deSDaniel Lezcano 		return ops->tz_enable(nla_get_u32(attrs[THERMAL_GENL_ATTR_TZ_ID]), arg);
50*47c4b0deSDaniel Lezcano 
51*47c4b0deSDaniel Lezcano 	case THERMAL_GENL_EVENT_TZ_DISABLE:
52*47c4b0deSDaniel Lezcano 		return ops->tz_disable(nla_get_u32(attrs[THERMAL_GENL_ATTR_TZ_ID]), arg);
53*47c4b0deSDaniel Lezcano 
54*47c4b0deSDaniel Lezcano 	case THERMAL_GENL_EVENT_TZ_TRIP_CHANGE:
55*47c4b0deSDaniel Lezcano 		return ops->trip_change(nla_get_u32(attrs[THERMAL_GENL_ATTR_TZ_ID]),
56*47c4b0deSDaniel Lezcano 					nla_get_u32(attrs[THERMAL_GENL_ATTR_TZ_TRIP_ID]),
57*47c4b0deSDaniel Lezcano 					nla_get_u32(attrs[THERMAL_GENL_ATTR_TZ_TRIP_TYPE]),
58*47c4b0deSDaniel Lezcano 					nla_get_u32(attrs[THERMAL_GENL_ATTR_TZ_TRIP_TEMP]),
59*47c4b0deSDaniel Lezcano 					nla_get_u32(attrs[THERMAL_GENL_ATTR_TZ_TRIP_HYST]), arg);
60*47c4b0deSDaniel Lezcano 
61*47c4b0deSDaniel Lezcano 	case THERMAL_GENL_EVENT_TZ_TRIP_ADD:
62*47c4b0deSDaniel Lezcano 		return ops->trip_add(nla_get_u32(attrs[THERMAL_GENL_ATTR_TZ_ID]),
63*47c4b0deSDaniel Lezcano 				     nla_get_u32(attrs[THERMAL_GENL_ATTR_TZ_TRIP_ID]),
64*47c4b0deSDaniel Lezcano 				     nla_get_u32(attrs[THERMAL_GENL_ATTR_TZ_TRIP_TYPE]),
65*47c4b0deSDaniel Lezcano 				     nla_get_u32(attrs[THERMAL_GENL_ATTR_TZ_TRIP_TEMP]),
66*47c4b0deSDaniel Lezcano 				     nla_get_u32(attrs[THERMAL_GENL_ATTR_TZ_TRIP_HYST]), arg);
67*47c4b0deSDaniel Lezcano 
68*47c4b0deSDaniel Lezcano 	case THERMAL_GENL_EVENT_TZ_TRIP_DELETE:
69*47c4b0deSDaniel Lezcano 		return ops->trip_delete(nla_get_u32(attrs[THERMAL_GENL_ATTR_TZ_ID]),
70*47c4b0deSDaniel Lezcano 					nla_get_u32(attrs[THERMAL_GENL_ATTR_TZ_TRIP_ID]), arg);
71*47c4b0deSDaniel Lezcano 
72*47c4b0deSDaniel Lezcano 	case THERMAL_GENL_EVENT_TZ_TRIP_UP:
73*47c4b0deSDaniel Lezcano 		return ops->trip_high(nla_get_u32(attrs[THERMAL_GENL_ATTR_TZ_ID]),
74*47c4b0deSDaniel Lezcano 				      nla_get_u32(attrs[THERMAL_GENL_ATTR_TZ_TRIP_ID]),
75*47c4b0deSDaniel Lezcano 				      nla_get_u32(attrs[THERMAL_GENL_ATTR_TZ_TEMP]), arg);
76*47c4b0deSDaniel Lezcano 
77*47c4b0deSDaniel Lezcano 	case THERMAL_GENL_EVENT_TZ_TRIP_DOWN:
78*47c4b0deSDaniel Lezcano 		return ops->trip_low(nla_get_u32(attrs[THERMAL_GENL_ATTR_TZ_ID]),
79*47c4b0deSDaniel Lezcano 				     nla_get_u32(attrs[THERMAL_GENL_ATTR_TZ_TRIP_ID]),
80*47c4b0deSDaniel Lezcano 				     nla_get_u32(attrs[THERMAL_GENL_ATTR_TZ_TEMP]), arg);
81*47c4b0deSDaniel Lezcano 
82*47c4b0deSDaniel Lezcano 	case THERMAL_GENL_EVENT_CDEV_ADD:
83*47c4b0deSDaniel Lezcano 		return ops->cdev_add(nla_get_string(attrs[THERMAL_GENL_ATTR_CDEV_NAME]),
84*47c4b0deSDaniel Lezcano 				     nla_get_u32(attrs[THERMAL_GENL_ATTR_CDEV_ID]),
85*47c4b0deSDaniel Lezcano 				     nla_get_u32(attrs[THERMAL_GENL_ATTR_CDEV_MAX_STATE]), arg);
86*47c4b0deSDaniel Lezcano 
87*47c4b0deSDaniel Lezcano 	case THERMAL_GENL_EVENT_CDEV_DELETE:
88*47c4b0deSDaniel Lezcano 		return ops->cdev_delete(nla_get_u32(attrs[THERMAL_GENL_ATTR_CDEV_ID]), arg);
89*47c4b0deSDaniel Lezcano 
90*47c4b0deSDaniel Lezcano 	case THERMAL_GENL_EVENT_CDEV_STATE_UPDATE:
91*47c4b0deSDaniel Lezcano 		return ops->cdev_update(nla_get_u32(attrs[THERMAL_GENL_ATTR_CDEV_ID]),
92*47c4b0deSDaniel Lezcano 					nla_get_u32(attrs[THERMAL_GENL_ATTR_CDEV_CUR_STATE]), arg);
93*47c4b0deSDaniel Lezcano 
94*47c4b0deSDaniel Lezcano 	case THERMAL_GENL_EVENT_TZ_GOV_CHANGE:
95*47c4b0deSDaniel Lezcano 		return ops->gov_change(nla_get_u32(attrs[THERMAL_GENL_ATTR_TZ_ID]),
96*47c4b0deSDaniel Lezcano 				       nla_get_string(attrs[THERMAL_GENL_ATTR_GOV_NAME]), arg);
97*47c4b0deSDaniel Lezcano 	default:
98*47c4b0deSDaniel Lezcano 		return -1;
99*47c4b0deSDaniel Lezcano 	}
100*47c4b0deSDaniel Lezcano }
101*47c4b0deSDaniel Lezcano 
thermal_events_ops_init(struct thermal_events_ops * ops)102*47c4b0deSDaniel Lezcano static void thermal_events_ops_init(struct thermal_events_ops *ops)
103*47c4b0deSDaniel Lezcano {
104*47c4b0deSDaniel Lezcano 	enabled_ops[THERMAL_GENL_EVENT_TZ_CREATE]	= !!ops->tz_create;
105*47c4b0deSDaniel Lezcano 	enabled_ops[THERMAL_GENL_EVENT_TZ_DELETE]	= !!ops->tz_delete;
106*47c4b0deSDaniel Lezcano 	enabled_ops[THERMAL_GENL_EVENT_TZ_DISABLE]	= !!ops->tz_disable;
107*47c4b0deSDaniel Lezcano 	enabled_ops[THERMAL_GENL_EVENT_TZ_ENABLE]	= !!ops->tz_enable;
108*47c4b0deSDaniel Lezcano 	enabled_ops[THERMAL_GENL_EVENT_TZ_TRIP_UP]	= !!ops->trip_high;
109*47c4b0deSDaniel Lezcano 	enabled_ops[THERMAL_GENL_EVENT_TZ_TRIP_DOWN]	= !!ops->trip_low;
110*47c4b0deSDaniel Lezcano 	enabled_ops[THERMAL_GENL_EVENT_TZ_TRIP_CHANGE]	= !!ops->trip_change;
111*47c4b0deSDaniel Lezcano 	enabled_ops[THERMAL_GENL_EVENT_TZ_TRIP_ADD]	= !!ops->trip_add;
112*47c4b0deSDaniel Lezcano 	enabled_ops[THERMAL_GENL_EVENT_TZ_TRIP_DELETE]	= !!ops->trip_delete;
113*47c4b0deSDaniel Lezcano 	enabled_ops[THERMAL_GENL_EVENT_CDEV_ADD]	= !!ops->cdev_add;
114*47c4b0deSDaniel Lezcano 	enabled_ops[THERMAL_GENL_EVENT_CDEV_DELETE]	= !!ops->cdev_delete;
115*47c4b0deSDaniel Lezcano 	enabled_ops[THERMAL_GENL_EVENT_CDEV_STATE_UPDATE] = !!ops->cdev_update;
116*47c4b0deSDaniel Lezcano 	enabled_ops[THERMAL_GENL_EVENT_TZ_GOV_CHANGE]	= !!ops->gov_change;
117*47c4b0deSDaniel Lezcano }
118*47c4b0deSDaniel Lezcano 
thermal_events_handle(struct thermal_handler * th,void * arg)119*47c4b0deSDaniel Lezcano thermal_error_t thermal_events_handle(struct thermal_handler *th, void *arg)
120*47c4b0deSDaniel Lezcano {
121*47c4b0deSDaniel Lezcano 	struct thermal_handler_param thp = { .th = th, .arg = arg };
122*47c4b0deSDaniel Lezcano 
123*47c4b0deSDaniel Lezcano 	if (!th)
124*47c4b0deSDaniel Lezcano 		return THERMAL_ERROR;
125*47c4b0deSDaniel Lezcano 
126*47c4b0deSDaniel Lezcano 	if (nl_cb_set(th->cb_event, NL_CB_VALID, NL_CB_CUSTOM,
127*47c4b0deSDaniel Lezcano 		      handle_thermal_event, &thp))
128*47c4b0deSDaniel Lezcano 		return THERMAL_ERROR;
129*47c4b0deSDaniel Lezcano 
130*47c4b0deSDaniel Lezcano 	return nl_recvmsgs(th->sk_event, th->cb_event);
131*47c4b0deSDaniel Lezcano }
132*47c4b0deSDaniel Lezcano 
thermal_events_fd(struct thermal_handler * th)133*47c4b0deSDaniel Lezcano int thermal_events_fd(struct thermal_handler *th)
134*47c4b0deSDaniel Lezcano {
135*47c4b0deSDaniel Lezcano 	if (!th)
136*47c4b0deSDaniel Lezcano 		return -1;
137*47c4b0deSDaniel Lezcano 
138*47c4b0deSDaniel Lezcano 	return nl_socket_get_fd(th->sk_event);
139*47c4b0deSDaniel Lezcano }
140*47c4b0deSDaniel Lezcano 
thermal_events_exit(struct thermal_handler * th)141*47c4b0deSDaniel Lezcano thermal_error_t thermal_events_exit(struct thermal_handler *th)
142*47c4b0deSDaniel Lezcano {
143*47c4b0deSDaniel Lezcano 	if (nl_unsubscribe_thermal(th->sk_event, th->cb_event,
144*47c4b0deSDaniel Lezcano 				   THERMAL_GENL_EVENT_GROUP_NAME))
145*47c4b0deSDaniel Lezcano 		return THERMAL_ERROR;
146*47c4b0deSDaniel Lezcano 
147*47c4b0deSDaniel Lezcano 	nl_thermal_disconnect(th->sk_event, th->cb_event);
148*47c4b0deSDaniel Lezcano 
149*47c4b0deSDaniel Lezcano 	return THERMAL_SUCCESS;
150*47c4b0deSDaniel Lezcano }
151*47c4b0deSDaniel Lezcano 
thermal_events_init(struct thermal_handler * th)152*47c4b0deSDaniel Lezcano thermal_error_t thermal_events_init(struct thermal_handler *th)
153*47c4b0deSDaniel Lezcano {
154*47c4b0deSDaniel Lezcano 	thermal_events_ops_init(&th->ops->events);
155*47c4b0deSDaniel Lezcano 
156*47c4b0deSDaniel Lezcano 	if (nl_thermal_connect(&th->sk_event, &th->cb_event))
157*47c4b0deSDaniel Lezcano 		return THERMAL_ERROR;
158*47c4b0deSDaniel Lezcano 
159*47c4b0deSDaniel Lezcano 	if (nl_subscribe_thermal(th->sk_event, th->cb_event,
160*47c4b0deSDaniel Lezcano 				 THERMAL_GENL_EVENT_GROUP_NAME))
161*47c4b0deSDaniel Lezcano 		return THERMAL_ERROR;
162*47c4b0deSDaniel Lezcano 
163*47c4b0deSDaniel Lezcano 	return THERMAL_SUCCESS;
164*47c4b0deSDaniel Lezcano }
165