xref: /linux/drivers/thermal/thermal_netlink.c (revision ec8c17e5ecb4a5a74069687ccb6d2cfe1851302e)
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * Copyright 2020 Linaro Limited
4  *
5  * Author: Daniel Lezcano <daniel.lezcano@linaro.org>
6  *
7  * Generic netlink for thermal management framework
8  */
9 #include <linux/module.h>
10 #include <linux/notifier.h>
11 #include <linux/kernel.h>
12 #include <net/sock.h>
13 #include <net/genetlink.h>
14 #include <uapi/linux/thermal.h>
15 
16 #include "thermal_core.h"
17 
18 static const struct genl_multicast_group thermal_genl_mcgrps[] = {
19 	[THERMAL_GENL_SAMPLING_GROUP] = { .name = THERMAL_GENL_SAMPLING_GROUP_NAME, },
20 	[THERMAL_GENL_EVENT_GROUP]  = { .name = THERMAL_GENL_EVENT_GROUP_NAME,  },
21 };
22 
23 static const struct nla_policy thermal_genl_policy[THERMAL_GENL_ATTR_MAX + 1] = {
24 	/* Thermal zone */
25 	[THERMAL_GENL_ATTR_TZ]			= { .type = NLA_NESTED },
26 	[THERMAL_GENL_ATTR_TZ_ID]		= { .type = NLA_U32 },
27 	[THERMAL_GENL_ATTR_TZ_TEMP]		= { .type = NLA_U32 },
28 	[THERMAL_GENL_ATTR_TZ_TRIP]		= { .type = NLA_NESTED },
29 	[THERMAL_GENL_ATTR_TZ_TRIP_ID]		= { .type = NLA_U32 },
30 	[THERMAL_GENL_ATTR_TZ_TRIP_TEMP]	= { .type = NLA_U32 },
31 	[THERMAL_GENL_ATTR_TZ_TRIP_TYPE]	= { .type = NLA_U32 },
32 	[THERMAL_GENL_ATTR_TZ_TRIP_HYST]	= { .type = NLA_U32 },
33 	[THERMAL_GENL_ATTR_TZ_MODE]		= { .type = NLA_U32 },
34 	[THERMAL_GENL_ATTR_TZ_CDEV_WEIGHT]	= { .type = NLA_U32 },
35 	[THERMAL_GENL_ATTR_TZ_NAME]		= { .type = NLA_STRING,
36 						    .len = THERMAL_NAME_LENGTH },
37 	/* Governor(s) */
38 	[THERMAL_GENL_ATTR_TZ_GOV]		= { .type = NLA_NESTED },
39 	[THERMAL_GENL_ATTR_TZ_GOV_NAME]		= { .type = NLA_STRING,
40 						    .len = THERMAL_NAME_LENGTH },
41 	/* Cooling devices */
42 	[THERMAL_GENL_ATTR_CDEV]		= { .type = NLA_NESTED },
43 	[THERMAL_GENL_ATTR_CDEV_ID]		= { .type = NLA_U32 },
44 	[THERMAL_GENL_ATTR_CDEV_CUR_STATE]	= { .type = NLA_U32 },
45 	[THERMAL_GENL_ATTR_CDEV_MAX_STATE]	= { .type = NLA_U32 },
46 	[THERMAL_GENL_ATTR_CDEV_NAME]		= { .type = NLA_STRING,
47 						    .len = THERMAL_NAME_LENGTH },
48 	/* CPU capabilities */
49 	[THERMAL_GENL_ATTR_CPU_CAPABILITY]		= { .type = NLA_NESTED },
50 	[THERMAL_GENL_ATTR_CPU_CAPABILITY_ID]		= { .type = NLA_U32 },
51 	[THERMAL_GENL_ATTR_CPU_CAPABILITY_PERFORMANCE]	= { .type = NLA_U32 },
52 	[THERMAL_GENL_ATTR_CPU_CAPABILITY_EFFICIENCY]	= { .type = NLA_U32 },
53 
54 	/* Thresholds */
55 	[THERMAL_GENL_ATTR_THRESHOLD]		= { .type = NLA_NESTED },
56 	[THERMAL_GENL_ATTR_THRESHOLD_TEMP]	= { .type = NLA_U32 },
57 	[THERMAL_GENL_ATTR_THRESHOLD_DIRECTION]	= { .type = NLA_U32 },
58 };
59 
60 struct param {
61 	struct nlattr **attrs;
62 	struct sk_buff *msg;
63 	const char *name;
64 	int tz_id;
65 	int cdev_id;
66 	int trip_id;
67 	int trip_temp;
68 	int trip_type;
69 	int trip_hyst;
70 	int temp;
71 	int prev_temp;
72 	int direction;
73 	int cdev_state;
74 	int cdev_max_state;
75 	struct thermal_genl_cpu_caps *cpu_capabilities;
76 	int cpu_capabilities_count;
77 };
78 
79 typedef int (*cb_t)(struct param *);
80 
81 static struct genl_family thermal_genl_family;
82 static BLOCKING_NOTIFIER_HEAD(thermal_genl_chain);
83 
thermal_group_has_listeners(enum thermal_genl_multicast_groups group)84 static int thermal_group_has_listeners(enum thermal_genl_multicast_groups group)
85 {
86 	return genl_has_listeners(&thermal_genl_family, &init_net, group);
87 }
88 
89 /************************** Sampling encoding *******************************/
90 
thermal_genl_sampling_temp(int id,int temp)91 int thermal_genl_sampling_temp(int id, int temp)
92 {
93 	struct sk_buff *skb;
94 	void *hdr;
95 
96 	if (!thermal_group_has_listeners(THERMAL_GENL_SAMPLING_GROUP))
97 		return 0;
98 
99 	skb = genlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL);
100 	if (!skb)
101 		return -ENOMEM;
102 
103 	hdr = genlmsg_put(skb, 0, 0, &thermal_genl_family, 0,
104 			  THERMAL_GENL_SAMPLING_TEMP);
105 	if (!hdr)
106 		goto out_free;
107 
108 	if (nla_put_u32(skb, THERMAL_GENL_ATTR_TZ_ID, id))
109 		goto out_cancel;
110 
111 	if (nla_put_u32(skb, THERMAL_GENL_ATTR_TZ_TEMP, temp))
112 		goto out_cancel;
113 
114 	genlmsg_end(skb, hdr);
115 
116 	genlmsg_multicast(&thermal_genl_family, skb, 0, THERMAL_GENL_SAMPLING_GROUP, GFP_KERNEL);
117 
118 	return 0;
119 out_cancel:
120 	genlmsg_cancel(skb, hdr);
121 out_free:
122 	nlmsg_free(skb);
123 
124 	return -EMSGSIZE;
125 }
126 
127 /**************************** Event encoding *********************************/
128 
thermal_genl_event_tz_create(struct param * p)129 static int thermal_genl_event_tz_create(struct param *p)
130 {
131 	if (nla_put_u32(p->msg, THERMAL_GENL_ATTR_TZ_ID, p->tz_id) ||
132 	    nla_put_string(p->msg, THERMAL_GENL_ATTR_TZ_NAME, p->name))
133 		return -EMSGSIZE;
134 
135 	return 0;
136 }
137 
thermal_genl_event_tz(struct param * p)138 static int thermal_genl_event_tz(struct param *p)
139 {
140 	if (nla_put_u32(p->msg, THERMAL_GENL_ATTR_TZ_ID, p->tz_id))
141 		return -EMSGSIZE;
142 
143 	return 0;
144 }
145 
thermal_genl_event_tz_trip_up(struct param * p)146 static int thermal_genl_event_tz_trip_up(struct param *p)
147 {
148 	if (nla_put_u32(p->msg, THERMAL_GENL_ATTR_TZ_ID, p->tz_id) ||
149 	    nla_put_u32(p->msg, THERMAL_GENL_ATTR_TZ_TRIP_ID, p->trip_id) ||
150 	    nla_put_u32(p->msg, THERMAL_GENL_ATTR_TZ_TEMP, p->temp))
151 		return -EMSGSIZE;
152 
153 	return 0;
154 }
155 
thermal_genl_event_tz_trip_change(struct param * p)156 static int thermal_genl_event_tz_trip_change(struct param *p)
157 {
158 	if (nla_put_u32(p->msg, THERMAL_GENL_ATTR_TZ_ID, p->tz_id) ||
159 	    nla_put_u32(p->msg, THERMAL_GENL_ATTR_TZ_TRIP_ID, p->trip_id) ||
160 	    nla_put_u32(p->msg, THERMAL_GENL_ATTR_TZ_TRIP_TYPE, p->trip_type) ||
161 	    nla_put_u32(p->msg, THERMAL_GENL_ATTR_TZ_TRIP_TEMP, p->trip_temp) ||
162 	    nla_put_u32(p->msg, THERMAL_GENL_ATTR_TZ_TRIP_HYST, p->trip_hyst))
163 		return -EMSGSIZE;
164 
165 	return 0;
166 }
167 
thermal_genl_event_cdev_add(struct param * p)168 static int thermal_genl_event_cdev_add(struct param *p)
169 {
170 	if (nla_put_string(p->msg, THERMAL_GENL_ATTR_CDEV_NAME,
171 			   p->name) ||
172 	    nla_put_u32(p->msg, THERMAL_GENL_ATTR_CDEV_ID,
173 			p->cdev_id) ||
174 	    nla_put_u32(p->msg, THERMAL_GENL_ATTR_CDEV_MAX_STATE,
175 			p->cdev_max_state))
176 		return -EMSGSIZE;
177 
178 	return 0;
179 }
180 
thermal_genl_event_cdev_delete(struct param * p)181 static int thermal_genl_event_cdev_delete(struct param *p)
182 {
183 	if (nla_put_u32(p->msg, THERMAL_GENL_ATTR_CDEV_ID, p->cdev_id))
184 		return -EMSGSIZE;
185 
186 	return 0;
187 }
188 
thermal_genl_event_cdev_state_update(struct param * p)189 static int thermal_genl_event_cdev_state_update(struct param *p)
190 {
191 	if (nla_put_u32(p->msg, THERMAL_GENL_ATTR_CDEV_ID,
192 			p->cdev_id) ||
193 	    nla_put_u32(p->msg, THERMAL_GENL_ATTR_CDEV_CUR_STATE,
194 			p->cdev_state))
195 		return -EMSGSIZE;
196 
197 	return 0;
198 }
199 
thermal_genl_event_gov_change(struct param * p)200 static int thermal_genl_event_gov_change(struct param *p)
201 {
202 	if (nla_put_u32(p->msg, THERMAL_GENL_ATTR_TZ_ID, p->tz_id) ||
203 	    nla_put_string(p->msg, THERMAL_GENL_ATTR_GOV_NAME, p->name))
204 		return -EMSGSIZE;
205 
206 	return 0;
207 }
208 
thermal_genl_event_cpu_capability_change(struct param * p)209 static int thermal_genl_event_cpu_capability_change(struct param *p)
210 {
211 	struct thermal_genl_cpu_caps *cpu_cap = p->cpu_capabilities;
212 	struct sk_buff *msg = p->msg;
213 	struct nlattr *start_cap;
214 	int i;
215 
216 	start_cap = nla_nest_start(msg, THERMAL_GENL_ATTR_CPU_CAPABILITY);
217 	if (!start_cap)
218 		return -EMSGSIZE;
219 
220 	for (i = 0; i < p->cpu_capabilities_count; ++i) {
221 		if (nla_put_u32(msg, THERMAL_GENL_ATTR_CPU_CAPABILITY_ID,
222 				cpu_cap->cpu))
223 			goto out_cancel_nest;
224 
225 		if (nla_put_u32(msg, THERMAL_GENL_ATTR_CPU_CAPABILITY_PERFORMANCE,
226 				cpu_cap->performance))
227 			goto out_cancel_nest;
228 
229 		if (nla_put_u32(msg, THERMAL_GENL_ATTR_CPU_CAPABILITY_EFFICIENCY,
230 				cpu_cap->efficiency))
231 			goto out_cancel_nest;
232 
233 		++cpu_cap;
234 	}
235 
236 	nla_nest_end(msg, start_cap);
237 
238 	return 0;
239 out_cancel_nest:
240 	nla_nest_cancel(msg, start_cap);
241 
242 	return -EMSGSIZE;
243 }
244 
thermal_genl_event_threshold_add(struct param * p)245 static int thermal_genl_event_threshold_add(struct param *p)
246 {
247 	if (nla_put_u32(p->msg, THERMAL_GENL_ATTR_TZ_ID, p->tz_id) ||
248 	    nla_put_u32(p->msg, THERMAL_GENL_ATTR_THRESHOLD_TEMP, p->temp) ||
249 	    nla_put_u32(p->msg, THERMAL_GENL_ATTR_THRESHOLD_DIRECTION, p->direction))
250 		return -EMSGSIZE;
251 
252 	return 0;
253 }
254 
thermal_genl_event_threshold_flush(struct param * p)255 static int thermal_genl_event_threshold_flush(struct param *p)
256 {
257 	if (nla_put_u32(p->msg, THERMAL_GENL_ATTR_TZ_ID, p->tz_id))
258 		return -EMSGSIZE;
259 
260 	return 0;
261 }
262 
thermal_genl_event_threshold_up(struct param * p)263 static int thermal_genl_event_threshold_up(struct param *p)
264 {
265 	if (nla_put_u32(p->msg, THERMAL_GENL_ATTR_TZ_ID, p->tz_id) ||
266 	    nla_put_u32(p->msg, THERMAL_GENL_ATTR_TZ_PREV_TEMP, p->prev_temp) ||
267 	    nla_put_u32(p->msg, THERMAL_GENL_ATTR_TZ_TEMP, p->temp))
268 		return -EMSGSIZE;
269 
270 	return 0;
271 }
272 
273 int thermal_genl_event_tz_delete(struct param *p)
274 	__attribute__((alias("thermal_genl_event_tz")));
275 
276 int thermal_genl_event_tz_enable(struct param *p)
277 	__attribute__((alias("thermal_genl_event_tz")));
278 
279 int thermal_genl_event_tz_disable(struct param *p)
280 	__attribute__((alias("thermal_genl_event_tz")));
281 
282 int thermal_genl_event_tz_trip_down(struct param *p)
283 	__attribute__((alias("thermal_genl_event_tz_trip_up")));
284 
285 int thermal_genl_event_threshold_delete(struct param *p)
286 	__attribute__((alias("thermal_genl_event_threshold_add")));
287 
288 int thermal_genl_event_threshold_down(struct param *p)
289 	__attribute__((alias("thermal_genl_event_threshold_up")));
290 
291 static cb_t event_cb[] = {
292 	[THERMAL_GENL_EVENT_TZ_CREATE]		= thermal_genl_event_tz_create,
293 	[THERMAL_GENL_EVENT_TZ_DELETE]		= thermal_genl_event_tz_delete,
294 	[THERMAL_GENL_EVENT_TZ_ENABLE]		= thermal_genl_event_tz_enable,
295 	[THERMAL_GENL_EVENT_TZ_DISABLE]		= thermal_genl_event_tz_disable,
296 	[THERMAL_GENL_EVENT_TZ_TRIP_UP]		= thermal_genl_event_tz_trip_up,
297 	[THERMAL_GENL_EVENT_TZ_TRIP_DOWN]	= thermal_genl_event_tz_trip_down,
298 	[THERMAL_GENL_EVENT_TZ_TRIP_CHANGE]	= thermal_genl_event_tz_trip_change,
299 	[THERMAL_GENL_EVENT_CDEV_ADD]		= thermal_genl_event_cdev_add,
300 	[THERMAL_GENL_EVENT_CDEV_DELETE]	= thermal_genl_event_cdev_delete,
301 	[THERMAL_GENL_EVENT_CDEV_STATE_UPDATE]	= thermal_genl_event_cdev_state_update,
302 	[THERMAL_GENL_EVENT_TZ_GOV_CHANGE]	= thermal_genl_event_gov_change,
303 	[THERMAL_GENL_EVENT_CPU_CAPABILITY_CHANGE] = thermal_genl_event_cpu_capability_change,
304 	[THERMAL_GENL_EVENT_THRESHOLD_ADD]	= thermal_genl_event_threshold_add,
305 	[THERMAL_GENL_EVENT_THRESHOLD_DELETE]	= thermal_genl_event_threshold_delete,
306 	[THERMAL_GENL_EVENT_THRESHOLD_FLUSH]	= thermal_genl_event_threshold_flush,
307 	[THERMAL_GENL_EVENT_THRESHOLD_DOWN]	= thermal_genl_event_threshold_down,
308 	[THERMAL_GENL_EVENT_THRESHOLD_UP]	= thermal_genl_event_threshold_up,
309 };
310 
311 /*
312  * Generic netlink event encoding
313  */
thermal_genl_send_event(enum thermal_genl_event event,struct param * p)314 static int thermal_genl_send_event(enum thermal_genl_event event,
315 				   struct param *p)
316 {
317 	struct sk_buff *msg;
318 	int ret = -EMSGSIZE;
319 	void *hdr;
320 
321 	if (!thermal_group_has_listeners(THERMAL_GENL_EVENT_GROUP))
322 		return 0;
323 
324 	msg = genlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL);
325 	if (!msg)
326 		return -ENOMEM;
327 	p->msg = msg;
328 
329 	hdr = genlmsg_put(msg, 0, 0, &thermal_genl_family, 0, event);
330 	if (!hdr)
331 		goto out_free_msg;
332 
333 	ret = event_cb[event](p);
334 	if (ret)
335 		goto out_cancel_msg;
336 
337 	genlmsg_end(msg, hdr);
338 
339 	genlmsg_multicast(&thermal_genl_family, msg, 0, THERMAL_GENL_EVENT_GROUP, GFP_KERNEL);
340 
341 	return 0;
342 
343 out_cancel_msg:
344 	genlmsg_cancel(msg, hdr);
345 out_free_msg:
346 	nlmsg_free(msg);
347 
348 	return ret;
349 }
350 
thermal_notify_tz_create(const struct thermal_zone_device * tz)351 int thermal_notify_tz_create(const struct thermal_zone_device *tz)
352 {
353 	struct param p = { .tz_id = tz->id, .name = tz->type };
354 
355 	return thermal_genl_send_event(THERMAL_GENL_EVENT_TZ_CREATE, &p);
356 }
357 
thermal_notify_tz_delete(const struct thermal_zone_device * tz)358 int thermal_notify_tz_delete(const struct thermal_zone_device *tz)
359 {
360 	struct param p = { .tz_id = tz->id };
361 
362 	return thermal_genl_send_event(THERMAL_GENL_EVENT_TZ_DELETE, &p);
363 }
364 
thermal_notify_tz_enable(const struct thermal_zone_device * tz)365 int thermal_notify_tz_enable(const struct thermal_zone_device *tz)
366 {
367 	struct param p = { .tz_id = tz->id };
368 
369 	return thermal_genl_send_event(THERMAL_GENL_EVENT_TZ_ENABLE, &p);
370 }
371 
thermal_notify_tz_disable(const struct thermal_zone_device * tz)372 int thermal_notify_tz_disable(const struct thermal_zone_device *tz)
373 {
374 	struct param p = { .tz_id = tz->id };
375 
376 	return thermal_genl_send_event(THERMAL_GENL_EVENT_TZ_DISABLE, &p);
377 }
378 
thermal_notify_tz_trip_down(const struct thermal_zone_device * tz,const struct thermal_trip * trip)379 int thermal_notify_tz_trip_down(const struct thermal_zone_device *tz,
380 				const struct thermal_trip *trip)
381 {
382 	struct param p = { .tz_id = tz->id,
383 			   .trip_id = thermal_zone_trip_id(tz, trip),
384 			   .temp = tz->temperature };
385 
386 	return thermal_genl_send_event(THERMAL_GENL_EVENT_TZ_TRIP_DOWN, &p);
387 }
388 
thermal_notify_tz_trip_up(const struct thermal_zone_device * tz,const struct thermal_trip * trip)389 int thermal_notify_tz_trip_up(const struct thermal_zone_device *tz,
390 			      const struct thermal_trip *trip)
391 {
392 	struct param p = { .tz_id = tz->id,
393 			   .trip_id = thermal_zone_trip_id(tz, trip),
394 			   .temp = tz->temperature };
395 
396 	return thermal_genl_send_event(THERMAL_GENL_EVENT_TZ_TRIP_UP, &p);
397 }
398 
thermal_notify_tz_trip_change(const struct thermal_zone_device * tz,const struct thermal_trip * trip)399 int thermal_notify_tz_trip_change(const struct thermal_zone_device *tz,
400 				  const struct thermal_trip *trip)
401 {
402 	struct param p = { .tz_id = tz->id,
403 			   .trip_id = thermal_zone_trip_id(tz, trip),
404 			   .trip_type = trip->type,
405 			   .trip_temp = trip->temperature,
406 			   .trip_hyst = trip->hysteresis };
407 
408 	return thermal_genl_send_event(THERMAL_GENL_EVENT_TZ_TRIP_CHANGE, &p);
409 }
410 
thermal_notify_cdev_state_update(const struct thermal_cooling_device * cdev,int state)411 int thermal_notify_cdev_state_update(const struct thermal_cooling_device *cdev,
412 				     int state)
413 {
414 	struct param p = { .cdev_id = cdev->id, .cdev_state = state };
415 
416 	return thermal_genl_send_event(THERMAL_GENL_EVENT_CDEV_STATE_UPDATE, &p);
417 }
418 
thermal_notify_cdev_add(const struct thermal_cooling_device * cdev)419 int thermal_notify_cdev_add(const struct thermal_cooling_device *cdev)
420 {
421 	struct param p = { .cdev_id = cdev->id, .name = cdev->type,
422 			   .cdev_max_state = cdev->max_state };
423 
424 	return thermal_genl_send_event(THERMAL_GENL_EVENT_CDEV_ADD, &p);
425 }
426 
thermal_notify_cdev_delete(const struct thermal_cooling_device * cdev)427 int thermal_notify_cdev_delete(const struct thermal_cooling_device *cdev)
428 {
429 	struct param p = { .cdev_id = cdev->id };
430 
431 	return thermal_genl_send_event(THERMAL_GENL_EVENT_CDEV_DELETE, &p);
432 }
433 
thermal_notify_tz_gov_change(const struct thermal_zone_device * tz,const char * name)434 int thermal_notify_tz_gov_change(const struct thermal_zone_device *tz,
435 				 const char *name)
436 {
437 	struct param p = { .tz_id = tz->id, .name = name };
438 
439 	return thermal_genl_send_event(THERMAL_GENL_EVENT_TZ_GOV_CHANGE, &p);
440 }
441 
thermal_genl_cpu_capability_event(int count,struct thermal_genl_cpu_caps * caps)442 int thermal_genl_cpu_capability_event(int count,
443 				      struct thermal_genl_cpu_caps *caps)
444 {
445 	struct param p = { .cpu_capabilities_count = count, .cpu_capabilities = caps };
446 
447 	return thermal_genl_send_event(THERMAL_GENL_EVENT_CPU_CAPABILITY_CHANGE, &p);
448 }
449 EXPORT_SYMBOL_GPL(thermal_genl_cpu_capability_event);
450 
thermal_notify_threshold_add(const struct thermal_zone_device * tz,int temperature,int direction)451 int thermal_notify_threshold_add(const struct thermal_zone_device *tz,
452 				 int temperature, int direction)
453 {
454 	struct param p = { .tz_id = tz->id, .temp = temperature, .direction = direction };
455 
456 	return thermal_genl_send_event(THERMAL_GENL_EVENT_THRESHOLD_ADD, &p);
457 }
458 
thermal_notify_threshold_delete(const struct thermal_zone_device * tz,int temperature,int direction)459 int thermal_notify_threshold_delete(const struct thermal_zone_device *tz,
460 				    int temperature, int direction)
461 {
462 	struct param p = { .tz_id = tz->id, .temp = temperature, .direction = direction };
463 
464 	return thermal_genl_send_event(THERMAL_GENL_EVENT_THRESHOLD_DELETE, &p);
465 }
466 
thermal_notify_threshold_flush(const struct thermal_zone_device * tz)467 int thermal_notify_threshold_flush(const struct thermal_zone_device *tz)
468 {
469 	struct param p = { .tz_id = tz->id };
470 
471 	return thermal_genl_send_event(THERMAL_GENL_EVENT_THRESHOLD_FLUSH, &p);
472 }
473 
thermal_notify_threshold_down(const struct thermal_zone_device * tz)474 int thermal_notify_threshold_down(const struct thermal_zone_device *tz)
475 {
476 	struct param p = { .tz_id = tz->id, .temp = tz->temperature, .prev_temp = tz->last_temperature };
477 
478 	return thermal_genl_send_event(THERMAL_GENL_EVENT_THRESHOLD_DOWN, &p);
479 }
480 
thermal_notify_threshold_up(const struct thermal_zone_device * tz)481 int thermal_notify_threshold_up(const struct thermal_zone_device *tz)
482 {
483 	struct param p = { .tz_id = tz->id, .temp = tz->temperature, .prev_temp = tz->last_temperature };
484 
485 	return thermal_genl_send_event(THERMAL_GENL_EVENT_THRESHOLD_UP, &p);
486 }
487 
488 /*************************** Command encoding ********************************/
489 
__thermal_genl_cmd_tz_get_id(struct thermal_zone_device * tz,void * data)490 static int __thermal_genl_cmd_tz_get_id(struct thermal_zone_device *tz,
491 					void *data)
492 {
493 	struct sk_buff *msg = data;
494 
495 	if (nla_put_u32(msg, THERMAL_GENL_ATTR_TZ_ID, tz->id) ||
496 	    nla_put_string(msg, THERMAL_GENL_ATTR_TZ_NAME, tz->type))
497 		return -EMSGSIZE;
498 
499 	return 0;
500 }
501 
thermal_genl_cmd_tz_get_id(struct param * p)502 static int thermal_genl_cmd_tz_get_id(struct param *p)
503 {
504 	struct sk_buff *msg = p->msg;
505 	struct nlattr *start_tz;
506 	int ret;
507 
508 	start_tz = nla_nest_start(msg, THERMAL_GENL_ATTR_TZ);
509 	if (!start_tz)
510 		return -EMSGSIZE;
511 
512 	ret = for_each_thermal_zone(__thermal_genl_cmd_tz_get_id, msg);
513 	if (ret)
514 		goto out_cancel_nest;
515 
516 	nla_nest_end(msg, start_tz);
517 
518 	return 0;
519 
520 out_cancel_nest:
521 	nla_nest_cancel(msg, start_tz);
522 
523 	return ret;
524 }
525 
thermal_genl_cmd_tz_get_trip(struct param * p)526 static int thermal_genl_cmd_tz_get_trip(struct param *p)
527 {
528 	struct sk_buff *msg = p->msg;
529 	const struct thermal_trip_desc *td;
530 	struct nlattr *start_trip;
531 	int id;
532 
533 	if (!p->attrs[THERMAL_GENL_ATTR_TZ_ID])
534 		return -EINVAL;
535 
536 	id = nla_get_u32(p->attrs[THERMAL_GENL_ATTR_TZ_ID]);
537 
538 	CLASS(thermal_zone_get_by_id, tz)(id);
539 	if (!tz)
540 		return -EINVAL;
541 
542 	start_trip = nla_nest_start(msg, THERMAL_GENL_ATTR_TZ_TRIP);
543 	if (!start_trip)
544 		return -EMSGSIZE;
545 
546 	guard(thermal_zone)(tz);
547 
548 	for_each_trip_desc(tz, td) {
549 		const struct thermal_trip *trip = &td->trip;
550 
551 		if (nla_put_u32(msg, THERMAL_GENL_ATTR_TZ_TRIP_ID,
552 				thermal_zone_trip_id(tz, trip)) ||
553 		    nla_put_u32(msg, THERMAL_GENL_ATTR_TZ_TRIP_TYPE, trip->type) ||
554 		    nla_put_u32(msg, THERMAL_GENL_ATTR_TZ_TRIP_TEMP, trip->temperature) ||
555 		    nla_put_u32(msg, THERMAL_GENL_ATTR_TZ_TRIP_HYST, trip->hysteresis))
556 			return -EMSGSIZE;
557 	}
558 
559 	nla_nest_end(msg, start_trip);
560 
561 	return 0;
562 }
563 
thermal_genl_cmd_tz_get_temp(struct param * p)564 static int thermal_genl_cmd_tz_get_temp(struct param *p)
565 {
566 	struct sk_buff *msg = p->msg;
567 	int temp, ret, id;
568 
569 	if (!p->attrs[THERMAL_GENL_ATTR_TZ_ID])
570 		return -EINVAL;
571 
572 	id = nla_get_u32(p->attrs[THERMAL_GENL_ATTR_TZ_ID]);
573 
574 	CLASS(thermal_zone_get_by_id, tz)(id);
575 	if (!tz)
576 		return -EINVAL;
577 
578 	ret = thermal_zone_get_temp(tz, &temp);
579 	if (ret)
580 		return ret;
581 
582 	if (nla_put_u32(msg, THERMAL_GENL_ATTR_TZ_ID, id) ||
583 	    nla_put_u32(msg, THERMAL_GENL_ATTR_TZ_TEMP, temp))
584 		return -EMSGSIZE;
585 
586 	return 0;
587 }
588 
thermal_genl_cmd_tz_get_gov(struct param * p)589 static int thermal_genl_cmd_tz_get_gov(struct param *p)
590 {
591 	struct sk_buff *msg = p->msg;
592 	int id;
593 
594 	if (!p->attrs[THERMAL_GENL_ATTR_TZ_ID])
595 		return -EINVAL;
596 
597 	id = nla_get_u32(p->attrs[THERMAL_GENL_ATTR_TZ_ID]);
598 
599 	CLASS(thermal_zone_get_by_id, tz)(id);
600 	if (!tz)
601 		return -EINVAL;
602 
603 	guard(thermal_zone)(tz);
604 
605 	if (nla_put_u32(msg, THERMAL_GENL_ATTR_TZ_ID, id) ||
606 	    nla_put_string(msg, THERMAL_GENL_ATTR_TZ_GOV_NAME,
607 			   tz->governor->name))
608 		return -EMSGSIZE;
609 
610 	return 0;
611 }
612 
__thermal_genl_cmd_cdev_get(struct thermal_cooling_device * cdev,void * data)613 static int __thermal_genl_cmd_cdev_get(struct thermal_cooling_device *cdev,
614 				       void *data)
615 {
616 	struct sk_buff *msg = data;
617 
618 	if (nla_put_u32(msg, THERMAL_GENL_ATTR_CDEV_ID, cdev->id))
619 		return -EMSGSIZE;
620 
621 	if (nla_put_string(msg, THERMAL_GENL_ATTR_CDEV_NAME, cdev->type))
622 		return -EMSGSIZE;
623 
624 	return 0;
625 }
626 
thermal_genl_cmd_cdev_get(struct param * p)627 static int thermal_genl_cmd_cdev_get(struct param *p)
628 {
629 	struct sk_buff *msg = p->msg;
630 	struct nlattr *start_cdev;
631 	int ret;
632 
633 	start_cdev = nla_nest_start(msg, THERMAL_GENL_ATTR_CDEV);
634 	if (!start_cdev)
635 		return -EMSGSIZE;
636 
637 	ret = for_each_thermal_cooling_device(__thermal_genl_cmd_cdev_get, msg);
638 	if (ret)
639 		goto out_cancel_nest;
640 
641 	nla_nest_end(msg, start_cdev);
642 
643 	return 0;
644 out_cancel_nest:
645 	nla_nest_cancel(msg, start_cdev);
646 
647 	return ret;
648 }
649 
__thermal_genl_cmd_threshold_get(struct user_threshold * threshold,void * arg)650 static int __thermal_genl_cmd_threshold_get(struct user_threshold *threshold, void *arg)
651 {
652 	struct sk_buff *msg = arg;
653 
654 	if (nla_put_u32(msg, THERMAL_GENL_ATTR_THRESHOLD_TEMP, threshold->temperature) ||
655 	    nla_put_u32(msg, THERMAL_GENL_ATTR_THRESHOLD_DIRECTION, threshold->direction))
656 		return -1;
657 
658 	return 0;
659 }
660 
thermal_genl_cmd_threshold_get(struct param * p)661 static int thermal_genl_cmd_threshold_get(struct param *p)
662 {
663 	struct sk_buff *msg = p->msg;
664 	struct nlattr *start_trip;
665 	int id, ret;
666 
667 	if (!p->attrs[THERMAL_GENL_ATTR_TZ_ID])
668 		return -EINVAL;
669 
670 	id = nla_get_u32(p->attrs[THERMAL_GENL_ATTR_TZ_ID]);
671 
672 	CLASS(thermal_zone_get_by_id, tz)(id);
673 	if (!tz)
674 		return -EINVAL;
675 
676 	start_trip = nla_nest_start(msg, THERMAL_GENL_ATTR_THRESHOLD);
677 	if (!start_trip)
678 		return -EMSGSIZE;
679 
680 	ret = thermal_thresholds_for_each(tz, __thermal_genl_cmd_threshold_get, msg);
681 	if (ret)
682 		return -EMSGSIZE;
683 
684 	nla_nest_end(msg, start_trip);
685 
686 	return 0;
687 }
688 
thermal_genl_cmd_threshold_add(struct param * p)689 static int thermal_genl_cmd_threshold_add(struct param *p)
690 {
691 	int id, temp, direction;
692 
693 	if (!capable(CAP_SYS_ADMIN))
694 		return -EPERM;
695 
696 	if (!p->attrs[THERMAL_GENL_ATTR_TZ_ID] ||
697 	    !p->attrs[THERMAL_GENL_ATTR_THRESHOLD_TEMP] ||
698 	    !p->attrs[THERMAL_GENL_ATTR_THRESHOLD_DIRECTION])
699 		return -EINVAL;
700 
701 	id = nla_get_u32(p->attrs[THERMAL_GENL_ATTR_TZ_ID]);
702 	temp = nla_get_u32(p->attrs[THERMAL_GENL_ATTR_THRESHOLD_TEMP]);
703 	direction = nla_get_u32(p->attrs[THERMAL_GENL_ATTR_THRESHOLD_DIRECTION]);
704 
705 	CLASS(thermal_zone_get_by_id, tz)(id);
706 	if (!tz)
707 		return -EINVAL;
708 
709 	guard(thermal_zone)(tz);
710 
711 	return thermal_thresholds_add(tz, temp, direction);
712 }
713 
thermal_genl_cmd_threshold_delete(struct param * p)714 static int thermal_genl_cmd_threshold_delete(struct param *p)
715 {
716 	int id, temp, direction;
717 
718 	if (!capable(CAP_SYS_ADMIN))
719 		return -EPERM;
720 
721 	if (!p->attrs[THERMAL_GENL_ATTR_TZ_ID] ||
722 	    !p->attrs[THERMAL_GENL_ATTR_THRESHOLD_TEMP] ||
723 	    !p->attrs[THERMAL_GENL_ATTR_THRESHOLD_DIRECTION])
724 		return -EINVAL;
725 
726 	id = nla_get_u32(p->attrs[THERMAL_GENL_ATTR_TZ_ID]);
727 	temp = nla_get_u32(p->attrs[THERMAL_GENL_ATTR_THRESHOLD_TEMP]);
728 	direction = nla_get_u32(p->attrs[THERMAL_GENL_ATTR_THRESHOLD_DIRECTION]);
729 
730 	CLASS(thermal_zone_get_by_id, tz)(id);
731 	if (!tz)
732 		return -EINVAL;
733 
734 	guard(thermal_zone)(tz);
735 
736 	return thermal_thresholds_delete(tz, temp, direction);
737 }
738 
thermal_genl_cmd_threshold_flush(struct param * p)739 static int thermal_genl_cmd_threshold_flush(struct param *p)
740 {
741 	int id;
742 
743 	if (!capable(CAP_SYS_ADMIN))
744 		return -EPERM;
745 
746 	if (!p->attrs[THERMAL_GENL_ATTR_TZ_ID])
747 		return -EINVAL;
748 
749 	id = nla_get_u32(p->attrs[THERMAL_GENL_ATTR_TZ_ID]);
750 
751 	CLASS(thermal_zone_get_by_id, tz)(id);
752 	if (!tz)
753 		return -EINVAL;
754 
755 	guard(thermal_zone)(tz);
756 
757 	thermal_thresholds_flush(tz);
758 
759 	return 0;
760 }
761 
762 static cb_t cmd_cb[] = {
763 	[THERMAL_GENL_CMD_TZ_GET_ID]		= thermal_genl_cmd_tz_get_id,
764 	[THERMAL_GENL_CMD_TZ_GET_TRIP]		= thermal_genl_cmd_tz_get_trip,
765 	[THERMAL_GENL_CMD_TZ_GET_TEMP]		= thermal_genl_cmd_tz_get_temp,
766 	[THERMAL_GENL_CMD_TZ_GET_GOV]		= thermal_genl_cmd_tz_get_gov,
767 	[THERMAL_GENL_CMD_CDEV_GET]		= thermal_genl_cmd_cdev_get,
768 	[THERMAL_GENL_CMD_THRESHOLD_GET]	= thermal_genl_cmd_threshold_get,
769 	[THERMAL_GENL_CMD_THRESHOLD_ADD]	= thermal_genl_cmd_threshold_add,
770 	[THERMAL_GENL_CMD_THRESHOLD_DELETE]	= thermal_genl_cmd_threshold_delete,
771 	[THERMAL_GENL_CMD_THRESHOLD_FLUSH]	= thermal_genl_cmd_threshold_flush,
772 };
773 
thermal_genl_cmd_dumpit(struct sk_buff * skb,struct netlink_callback * cb)774 static int thermal_genl_cmd_dumpit(struct sk_buff *skb,
775 				   struct netlink_callback *cb)
776 {
777 	struct param p = { .msg = skb };
778 	const struct genl_dumpit_info *info = genl_dumpit_info(cb);
779 	int cmd = info->op.cmd;
780 	int ret;
781 	void *hdr;
782 
783 	hdr = genlmsg_put(skb, 0, 0, &thermal_genl_family, 0, cmd);
784 	if (!hdr)
785 		return -EMSGSIZE;
786 
787 	ret = cmd_cb[cmd](&p);
788 	if (ret)
789 		goto out_cancel_msg;
790 
791 	genlmsg_end(skb, hdr);
792 
793 	return 0;
794 
795 out_cancel_msg:
796 	genlmsg_cancel(skb, hdr);
797 
798 	return ret;
799 }
800 
thermal_genl_cmd_doit(struct sk_buff * skb,struct genl_info * info)801 static int thermal_genl_cmd_doit(struct sk_buff *skb,
802 				 struct genl_info *info)
803 {
804 	struct param p = { .attrs = info->attrs };
805 	struct sk_buff *msg;
806 	void *hdr;
807 	int cmd = info->genlhdr->cmd;
808 	int ret = -EMSGSIZE;
809 
810 	msg = genlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL);
811 	if (!msg)
812 		return -ENOMEM;
813 	p.msg = msg;
814 
815 	hdr = genlmsg_put_reply(msg, info, &thermal_genl_family, 0, cmd);
816 	if (!hdr)
817 		goto out_free_msg;
818 
819 	ret = cmd_cb[cmd](&p);
820 	if (ret)
821 		goto out_cancel_msg;
822 
823 	genlmsg_end(msg, hdr);
824 
825 	return genlmsg_reply(msg, info);
826 
827 out_cancel_msg:
828 	genlmsg_cancel(msg, hdr);
829 out_free_msg:
830 	nlmsg_free(msg);
831 
832 	return ret;
833 }
834 
thermal_genl_bind(int mcgrp)835 static int thermal_genl_bind(int mcgrp)
836 {
837 	struct thermal_genl_notify n = { .mcgrp = mcgrp };
838 
839 	if (WARN_ON_ONCE(mcgrp > THERMAL_GENL_MAX_GROUP))
840 		return -EINVAL;
841 
842 	blocking_notifier_call_chain(&thermal_genl_chain, THERMAL_NOTIFY_BIND, &n);
843 	return 0;
844 }
845 
thermal_genl_unbind(int mcgrp)846 static void thermal_genl_unbind(int mcgrp)
847 {
848 	struct thermal_genl_notify n = { .mcgrp = mcgrp };
849 
850 	if (WARN_ON_ONCE(mcgrp > THERMAL_GENL_MAX_GROUP))
851 		return;
852 
853 	blocking_notifier_call_chain(&thermal_genl_chain, THERMAL_NOTIFY_UNBIND, &n);
854 }
855 
856 static const struct genl_small_ops thermal_genl_ops[] = {
857 	{
858 		.cmd = THERMAL_GENL_CMD_TZ_GET_ID,
859 		.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
860 		.dumpit = thermal_genl_cmd_dumpit,
861 	},
862 	{
863 		.cmd = THERMAL_GENL_CMD_TZ_GET_TRIP,
864 		.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
865 		.doit = thermal_genl_cmd_doit,
866 	},
867 	{
868 		.cmd = THERMAL_GENL_CMD_TZ_GET_TEMP,
869 		.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
870 		.doit = thermal_genl_cmd_doit,
871 	},
872 	{
873 		.cmd = THERMAL_GENL_CMD_TZ_GET_GOV,
874 		.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
875 		.doit = thermal_genl_cmd_doit,
876 	},
877 	{
878 		.cmd = THERMAL_GENL_CMD_CDEV_GET,
879 		.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
880 		.dumpit = thermal_genl_cmd_dumpit,
881 	},
882 	{
883 		.cmd = THERMAL_GENL_CMD_THRESHOLD_GET,
884 		.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
885 		.doit = thermal_genl_cmd_doit,
886 	},
887 	{
888 		.cmd = THERMAL_GENL_CMD_THRESHOLD_ADD,
889 		.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
890 		.doit = thermal_genl_cmd_doit,
891 	},
892 	{
893 		.cmd = THERMAL_GENL_CMD_THRESHOLD_DELETE,
894 		.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
895 		.doit = thermal_genl_cmd_doit,
896 	},
897 	{
898 		.cmd = THERMAL_GENL_CMD_THRESHOLD_FLUSH,
899 		.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
900 		.doit = thermal_genl_cmd_doit,
901 	},
902 };
903 
904 static struct genl_family thermal_genl_family __ro_after_init = {
905 	.hdrsize	= 0,
906 	.name		= THERMAL_GENL_FAMILY_NAME,
907 	.version	= THERMAL_GENL_VERSION,
908 	.maxattr	= THERMAL_GENL_ATTR_MAX,
909 	.policy		= thermal_genl_policy,
910 	.bind		= thermal_genl_bind,
911 	.unbind		= thermal_genl_unbind,
912 	.small_ops	= thermal_genl_ops,
913 	.n_small_ops	= ARRAY_SIZE(thermal_genl_ops),
914 	.resv_start_op	= __THERMAL_GENL_CMD_MAX,
915 	.mcgrps		= thermal_genl_mcgrps,
916 	.n_mcgrps	= ARRAY_SIZE(thermal_genl_mcgrps),
917 };
918 
thermal_genl_register_notifier(struct notifier_block * nb)919 int thermal_genl_register_notifier(struct notifier_block *nb)
920 {
921 	return blocking_notifier_chain_register(&thermal_genl_chain, nb);
922 }
923 
thermal_genl_unregister_notifier(struct notifier_block * nb)924 int thermal_genl_unregister_notifier(struct notifier_block *nb)
925 {
926 	return blocking_notifier_chain_unregister(&thermal_genl_chain, nb);
927 }
928 
thermal_netlink_init(void)929 int __init thermal_netlink_init(void)
930 {
931 	return genl_register_family(&thermal_genl_family);
932 }
933 
thermal_netlink_exit(void)934 void __init thermal_netlink_exit(void)
935 {
936 	genl_unregister_family(&thermal_genl_family);
937 }
938