xref: /linux/drivers/thermal/thermal_netlink.c (revision c4101e55974cc7d835fbd2d8e01553a3f61e9e75)
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/kernel.h>
11 #include <net/genetlink.h>
12 #include <uapi/linux/thermal.h>
13 
14 #include "thermal_core.h"
15 
16 enum thermal_genl_multicast_groups {
17 	THERMAL_GENL_SAMPLING_GROUP = 0,
18 	THERMAL_GENL_EVENT_GROUP = 1,
19 };
20 
21 static const struct genl_multicast_group thermal_genl_mcgrps[] = {
22 	[THERMAL_GENL_SAMPLING_GROUP] = { .name = THERMAL_GENL_SAMPLING_GROUP_NAME, },
23 	[THERMAL_GENL_EVENT_GROUP]  = { .name = THERMAL_GENL_EVENT_GROUP_NAME,  },
24 };
25 
26 static const struct nla_policy thermal_genl_policy[THERMAL_GENL_ATTR_MAX + 1] = {
27 	/* Thermal zone */
28 	[THERMAL_GENL_ATTR_TZ]			= { .type = NLA_NESTED },
29 	[THERMAL_GENL_ATTR_TZ_ID]		= { .type = NLA_U32 },
30 	[THERMAL_GENL_ATTR_TZ_TEMP]		= { .type = NLA_U32 },
31 	[THERMAL_GENL_ATTR_TZ_TRIP]		= { .type = NLA_NESTED },
32 	[THERMAL_GENL_ATTR_TZ_TRIP_ID]		= { .type = NLA_U32 },
33 	[THERMAL_GENL_ATTR_TZ_TRIP_TEMP]	= { .type = NLA_U32 },
34 	[THERMAL_GENL_ATTR_TZ_TRIP_TYPE]	= { .type = NLA_U32 },
35 	[THERMAL_GENL_ATTR_TZ_TRIP_HYST]	= { .type = NLA_U32 },
36 	[THERMAL_GENL_ATTR_TZ_MODE]		= { .type = NLA_U32 },
37 	[THERMAL_GENL_ATTR_TZ_CDEV_WEIGHT]	= { .type = NLA_U32 },
38 	[THERMAL_GENL_ATTR_TZ_NAME]		= { .type = NLA_STRING,
39 						    .len = THERMAL_NAME_LENGTH },
40 	/* Governor(s) */
41 	[THERMAL_GENL_ATTR_TZ_GOV]		= { .type = NLA_NESTED },
42 	[THERMAL_GENL_ATTR_TZ_GOV_NAME]		= { .type = NLA_STRING,
43 						    .len = THERMAL_NAME_LENGTH },
44 	/* Cooling devices */
45 	[THERMAL_GENL_ATTR_CDEV]		= { .type = NLA_NESTED },
46 	[THERMAL_GENL_ATTR_CDEV_ID]		= { .type = NLA_U32 },
47 	[THERMAL_GENL_ATTR_CDEV_CUR_STATE]	= { .type = NLA_U32 },
48 	[THERMAL_GENL_ATTR_CDEV_MAX_STATE]	= { .type = NLA_U32 },
49 	[THERMAL_GENL_ATTR_CDEV_NAME]		= { .type = NLA_STRING,
50 						    .len = THERMAL_NAME_LENGTH },
51 	/* CPU capabilities */
52 	[THERMAL_GENL_ATTR_CPU_CAPABILITY]		= { .type = NLA_NESTED },
53 	[THERMAL_GENL_ATTR_CPU_CAPABILITY_ID]		= { .type = NLA_U32 },
54 	[THERMAL_GENL_ATTR_CPU_CAPABILITY_PERFORMANCE]	= { .type = NLA_U32 },
55 	[THERMAL_GENL_ATTR_CPU_CAPABILITY_EFFICIENCY]	= { .type = NLA_U32 },
56 };
57 
58 struct param {
59 	struct nlattr **attrs;
60 	struct sk_buff *msg;
61 	const char *name;
62 	int tz_id;
63 	int cdev_id;
64 	int trip_id;
65 	int trip_temp;
66 	int trip_type;
67 	int trip_hyst;
68 	int temp;
69 	int cdev_state;
70 	int cdev_max_state;
71 	struct thermal_genl_cpu_caps *cpu_capabilities;
72 	int cpu_capabilities_count;
73 };
74 
75 typedef int (*cb_t)(struct param *);
76 
77 static struct genl_family thermal_gnl_family;
78 
79 static int thermal_group_has_listeners(enum thermal_genl_multicast_groups group)
80 {
81 	return genl_has_listeners(&thermal_gnl_family, &init_net, group);
82 }
83 
84 /************************** Sampling encoding *******************************/
85 
86 int thermal_genl_sampling_temp(int id, int temp)
87 {
88 	struct sk_buff *skb;
89 	void *hdr;
90 
91 	if (!thermal_group_has_listeners(THERMAL_GENL_SAMPLING_GROUP))
92 		return 0;
93 
94 	skb = genlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL);
95 	if (!skb)
96 		return -ENOMEM;
97 
98 	hdr = genlmsg_put(skb, 0, 0, &thermal_gnl_family, 0,
99 			  THERMAL_GENL_SAMPLING_TEMP);
100 	if (!hdr)
101 		goto out_free;
102 
103 	if (nla_put_u32(skb, THERMAL_GENL_ATTR_TZ_ID, id))
104 		goto out_cancel;
105 
106 	if (nla_put_u32(skb, THERMAL_GENL_ATTR_TZ_TEMP, temp))
107 		goto out_cancel;
108 
109 	genlmsg_end(skb, hdr);
110 
111 	genlmsg_multicast(&thermal_gnl_family, skb, 0, THERMAL_GENL_SAMPLING_GROUP, GFP_KERNEL);
112 
113 	return 0;
114 out_cancel:
115 	genlmsg_cancel(skb, hdr);
116 out_free:
117 	nlmsg_free(skb);
118 
119 	return -EMSGSIZE;
120 }
121 
122 /**************************** Event encoding *********************************/
123 
124 static int thermal_genl_event_tz_create(struct param *p)
125 {
126 	if (nla_put_u32(p->msg, THERMAL_GENL_ATTR_TZ_ID, p->tz_id) ||
127 	    nla_put_string(p->msg, THERMAL_GENL_ATTR_TZ_NAME, p->name))
128 		return -EMSGSIZE;
129 
130 	return 0;
131 }
132 
133 static int thermal_genl_event_tz(struct param *p)
134 {
135 	if (nla_put_u32(p->msg, THERMAL_GENL_ATTR_TZ_ID, p->tz_id))
136 		return -EMSGSIZE;
137 
138 	return 0;
139 }
140 
141 static int thermal_genl_event_tz_trip_up(struct param *p)
142 {
143 	if (nla_put_u32(p->msg, THERMAL_GENL_ATTR_TZ_ID, p->tz_id) ||
144 	    nla_put_u32(p->msg, THERMAL_GENL_ATTR_TZ_TRIP_ID, p->trip_id) ||
145 	    nla_put_u32(p->msg, THERMAL_GENL_ATTR_TZ_TEMP, p->temp))
146 		return -EMSGSIZE;
147 
148 	return 0;
149 }
150 
151 static int thermal_genl_event_tz_trip_add(struct param *p)
152 {
153 	if (nla_put_u32(p->msg, THERMAL_GENL_ATTR_TZ_ID, p->tz_id) ||
154 	    nla_put_u32(p->msg, THERMAL_GENL_ATTR_TZ_TRIP_ID, p->trip_id) ||
155 	    nla_put_u32(p->msg, THERMAL_GENL_ATTR_TZ_TRIP_TYPE, p->trip_type) ||
156 	    nla_put_u32(p->msg, THERMAL_GENL_ATTR_TZ_TRIP_TEMP, p->trip_temp) ||
157 	    nla_put_u32(p->msg, THERMAL_GENL_ATTR_TZ_TRIP_HYST, p->trip_hyst))
158 		return -EMSGSIZE;
159 
160 	return 0;
161 }
162 
163 static int thermal_genl_event_tz_trip_delete(struct param *p)
164 {
165 	if (nla_put_u32(p->msg, THERMAL_GENL_ATTR_TZ_ID, p->tz_id) ||
166 	    nla_put_u32(p->msg, THERMAL_GENL_ATTR_TZ_TRIP_ID, p->trip_id))
167 		return -EMSGSIZE;
168 
169 	return 0;
170 }
171 
172 static int thermal_genl_event_cdev_add(struct param *p)
173 {
174 	if (nla_put_string(p->msg, THERMAL_GENL_ATTR_CDEV_NAME,
175 			   p->name) ||
176 	    nla_put_u32(p->msg, THERMAL_GENL_ATTR_CDEV_ID,
177 			p->cdev_id) ||
178 	    nla_put_u32(p->msg, THERMAL_GENL_ATTR_CDEV_MAX_STATE,
179 			p->cdev_max_state))
180 		return -EMSGSIZE;
181 
182 	return 0;
183 }
184 
185 static int thermal_genl_event_cdev_delete(struct param *p)
186 {
187 	if (nla_put_u32(p->msg, THERMAL_GENL_ATTR_CDEV_ID, p->cdev_id))
188 		return -EMSGSIZE;
189 
190 	return 0;
191 }
192 
193 static int thermal_genl_event_cdev_state_update(struct param *p)
194 {
195 	if (nla_put_u32(p->msg, THERMAL_GENL_ATTR_CDEV_ID,
196 			p->cdev_id) ||
197 	    nla_put_u32(p->msg, THERMAL_GENL_ATTR_CDEV_CUR_STATE,
198 			p->cdev_state))
199 		return -EMSGSIZE;
200 
201 	return 0;
202 }
203 
204 static int thermal_genl_event_gov_change(struct param *p)
205 {
206 	if (nla_put_u32(p->msg, THERMAL_GENL_ATTR_TZ_ID, p->tz_id) ||
207 	    nla_put_string(p->msg, THERMAL_GENL_ATTR_GOV_NAME, p->name))
208 		return -EMSGSIZE;
209 
210 	return 0;
211 }
212 
213 static int thermal_genl_event_cpu_capability_change(struct param *p)
214 {
215 	struct thermal_genl_cpu_caps *cpu_cap = p->cpu_capabilities;
216 	struct sk_buff *msg = p->msg;
217 	struct nlattr *start_cap;
218 	int i;
219 
220 	start_cap = nla_nest_start(msg, THERMAL_GENL_ATTR_CPU_CAPABILITY);
221 	if (!start_cap)
222 		return -EMSGSIZE;
223 
224 	for (i = 0; i < p->cpu_capabilities_count; ++i) {
225 		if (nla_put_u32(msg, THERMAL_GENL_ATTR_CPU_CAPABILITY_ID,
226 				cpu_cap->cpu))
227 			goto out_cancel_nest;
228 
229 		if (nla_put_u32(msg, THERMAL_GENL_ATTR_CPU_CAPABILITY_PERFORMANCE,
230 				cpu_cap->performance))
231 			goto out_cancel_nest;
232 
233 		if (nla_put_u32(msg, THERMAL_GENL_ATTR_CPU_CAPABILITY_EFFICIENCY,
234 				cpu_cap->efficiency))
235 			goto out_cancel_nest;
236 
237 		++cpu_cap;
238 	}
239 
240 	nla_nest_end(msg, start_cap);
241 
242 	return 0;
243 out_cancel_nest:
244 	nla_nest_cancel(msg, start_cap);
245 
246 	return -EMSGSIZE;
247 }
248 
249 int thermal_genl_event_tz_delete(struct param *p)
250 	__attribute__((alias("thermal_genl_event_tz")));
251 
252 int thermal_genl_event_tz_enable(struct param *p)
253 	__attribute__((alias("thermal_genl_event_tz")));
254 
255 int thermal_genl_event_tz_disable(struct param *p)
256 	__attribute__((alias("thermal_genl_event_tz")));
257 
258 int thermal_genl_event_tz_trip_down(struct param *p)
259 	__attribute__((alias("thermal_genl_event_tz_trip_up")));
260 
261 int thermal_genl_event_tz_trip_change(struct param *p)
262 	__attribute__((alias("thermal_genl_event_tz_trip_add")));
263 
264 static cb_t event_cb[] = {
265 	[THERMAL_GENL_EVENT_TZ_CREATE]		= thermal_genl_event_tz_create,
266 	[THERMAL_GENL_EVENT_TZ_DELETE]		= thermal_genl_event_tz_delete,
267 	[THERMAL_GENL_EVENT_TZ_ENABLE]		= thermal_genl_event_tz_enable,
268 	[THERMAL_GENL_EVENT_TZ_DISABLE]		= thermal_genl_event_tz_disable,
269 	[THERMAL_GENL_EVENT_TZ_TRIP_UP]		= thermal_genl_event_tz_trip_up,
270 	[THERMAL_GENL_EVENT_TZ_TRIP_DOWN]	= thermal_genl_event_tz_trip_down,
271 	[THERMAL_GENL_EVENT_TZ_TRIP_CHANGE]	= thermal_genl_event_tz_trip_change,
272 	[THERMAL_GENL_EVENT_TZ_TRIP_ADD]	= thermal_genl_event_tz_trip_add,
273 	[THERMAL_GENL_EVENT_TZ_TRIP_DELETE]	= thermal_genl_event_tz_trip_delete,
274 	[THERMAL_GENL_EVENT_CDEV_ADD]		= thermal_genl_event_cdev_add,
275 	[THERMAL_GENL_EVENT_CDEV_DELETE]	= thermal_genl_event_cdev_delete,
276 	[THERMAL_GENL_EVENT_CDEV_STATE_UPDATE]	= thermal_genl_event_cdev_state_update,
277 	[THERMAL_GENL_EVENT_TZ_GOV_CHANGE]	= thermal_genl_event_gov_change,
278 	[THERMAL_GENL_EVENT_CPU_CAPABILITY_CHANGE] = thermal_genl_event_cpu_capability_change,
279 };
280 
281 /*
282  * Generic netlink event encoding
283  */
284 static int thermal_genl_send_event(enum thermal_genl_event event,
285 				   struct param *p)
286 {
287 	struct sk_buff *msg;
288 	int ret = -EMSGSIZE;
289 	void *hdr;
290 
291 	if (!thermal_group_has_listeners(THERMAL_GENL_EVENT_GROUP))
292 		return 0;
293 
294 	msg = genlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL);
295 	if (!msg)
296 		return -ENOMEM;
297 	p->msg = msg;
298 
299 	hdr = genlmsg_put(msg, 0, 0, &thermal_gnl_family, 0, event);
300 	if (!hdr)
301 		goto out_free_msg;
302 
303 	ret = event_cb[event](p);
304 	if (ret)
305 		goto out_cancel_msg;
306 
307 	genlmsg_end(msg, hdr);
308 
309 	genlmsg_multicast(&thermal_gnl_family, msg, 0, THERMAL_GENL_EVENT_GROUP, GFP_KERNEL);
310 
311 	return 0;
312 
313 out_cancel_msg:
314 	genlmsg_cancel(msg, hdr);
315 out_free_msg:
316 	nlmsg_free(msg);
317 
318 	return ret;
319 }
320 
321 int thermal_notify_tz_create(int tz_id, const char *name)
322 {
323 	struct param p = { .tz_id = tz_id, .name = name };
324 
325 	return thermal_genl_send_event(THERMAL_GENL_EVENT_TZ_CREATE, &p);
326 }
327 
328 int thermal_notify_tz_delete(int tz_id)
329 {
330 	struct param p = { .tz_id = tz_id };
331 
332 	return thermal_genl_send_event(THERMAL_GENL_EVENT_TZ_DELETE, &p);
333 }
334 
335 int thermal_notify_tz_enable(int tz_id)
336 {
337 	struct param p = { .tz_id = tz_id };
338 
339 	return thermal_genl_send_event(THERMAL_GENL_EVENT_TZ_ENABLE, &p);
340 }
341 
342 int thermal_notify_tz_disable(int tz_id)
343 {
344 	struct param p = { .tz_id = tz_id };
345 
346 	return thermal_genl_send_event(THERMAL_GENL_EVENT_TZ_DISABLE, &p);
347 }
348 
349 int thermal_notify_tz_trip_down(int tz_id, int trip_id, int temp)
350 {
351 	struct param p = { .tz_id = tz_id, .trip_id = trip_id, .temp = temp };
352 
353 	return thermal_genl_send_event(THERMAL_GENL_EVENT_TZ_TRIP_DOWN, &p);
354 }
355 
356 int thermal_notify_tz_trip_up(int tz_id, int trip_id, int temp)
357 {
358 	struct param p = { .tz_id = tz_id, .trip_id = trip_id, .temp = temp };
359 
360 	return thermal_genl_send_event(THERMAL_GENL_EVENT_TZ_TRIP_UP, &p);
361 }
362 
363 int thermal_notify_tz_trip_add(int tz_id, int trip_id, int trip_type,
364 			       int trip_temp, int trip_hyst)
365 {
366 	struct param p = { .tz_id = tz_id, .trip_id = trip_id,
367 			   .trip_type = trip_type, .trip_temp = trip_temp,
368 			   .trip_hyst = trip_hyst };
369 
370 	return thermal_genl_send_event(THERMAL_GENL_EVENT_TZ_TRIP_ADD, &p);
371 }
372 
373 int thermal_notify_tz_trip_delete(int tz_id, int trip_id)
374 {
375 	struct param p = { .tz_id = tz_id, .trip_id = trip_id };
376 
377 	return thermal_genl_send_event(THERMAL_GENL_EVENT_TZ_TRIP_DELETE, &p);
378 }
379 
380 int thermal_notify_tz_trip_change(int tz_id, int trip_id, int trip_type,
381 				  int trip_temp, int trip_hyst)
382 {
383 	struct param p = { .tz_id = tz_id, .trip_id = trip_id,
384 			   .trip_type = trip_type, .trip_temp = trip_temp,
385 			   .trip_hyst = trip_hyst };
386 
387 	return thermal_genl_send_event(THERMAL_GENL_EVENT_TZ_TRIP_CHANGE, &p);
388 }
389 
390 int thermal_notify_cdev_state_update(int cdev_id, int cdev_state)
391 {
392 	struct param p = { .cdev_id = cdev_id, .cdev_state = cdev_state };
393 
394 	return thermal_genl_send_event(THERMAL_GENL_EVENT_CDEV_STATE_UPDATE, &p);
395 }
396 
397 int thermal_notify_cdev_add(int cdev_id, const char *name, int cdev_max_state)
398 {
399 	struct param p = { .cdev_id = cdev_id, .name = name,
400 			   .cdev_max_state = cdev_max_state };
401 
402 	return thermal_genl_send_event(THERMAL_GENL_EVENT_CDEV_ADD, &p);
403 }
404 
405 int thermal_notify_cdev_delete(int cdev_id)
406 {
407 	struct param p = { .cdev_id = cdev_id };
408 
409 	return thermal_genl_send_event(THERMAL_GENL_EVENT_CDEV_DELETE, &p);
410 }
411 
412 int thermal_notify_tz_gov_change(int tz_id, const char *name)
413 {
414 	struct param p = { .tz_id = tz_id, .name = name };
415 
416 	return thermal_genl_send_event(THERMAL_GENL_EVENT_TZ_GOV_CHANGE, &p);
417 }
418 
419 int thermal_genl_cpu_capability_event(int count,
420 				      struct thermal_genl_cpu_caps *caps)
421 {
422 	struct param p = { .cpu_capabilities_count = count, .cpu_capabilities = caps };
423 
424 	return thermal_genl_send_event(THERMAL_GENL_EVENT_CPU_CAPABILITY_CHANGE, &p);
425 }
426 EXPORT_SYMBOL_GPL(thermal_genl_cpu_capability_event);
427 
428 /*************************** Command encoding ********************************/
429 
430 static int __thermal_genl_cmd_tz_get_id(struct thermal_zone_device *tz,
431 					void *data)
432 {
433 	struct sk_buff *msg = data;
434 
435 	if (nla_put_u32(msg, THERMAL_GENL_ATTR_TZ_ID, tz->id) ||
436 	    nla_put_string(msg, THERMAL_GENL_ATTR_TZ_NAME, tz->type))
437 		return -EMSGSIZE;
438 
439 	return 0;
440 }
441 
442 static int thermal_genl_cmd_tz_get_id(struct param *p)
443 {
444 	struct sk_buff *msg = p->msg;
445 	struct nlattr *start_tz;
446 	int ret;
447 
448 	start_tz = nla_nest_start(msg, THERMAL_GENL_ATTR_TZ);
449 	if (!start_tz)
450 		return -EMSGSIZE;
451 
452 	ret = for_each_thermal_zone(__thermal_genl_cmd_tz_get_id, msg);
453 	if (ret)
454 		goto out_cancel_nest;
455 
456 	nla_nest_end(msg, start_tz);
457 
458 	return 0;
459 
460 out_cancel_nest:
461 	nla_nest_cancel(msg, start_tz);
462 
463 	return ret;
464 }
465 
466 static int thermal_genl_cmd_tz_get_trip(struct param *p)
467 {
468 	struct sk_buff *msg = p->msg;
469 	const struct thermal_trip *trip;
470 	struct thermal_zone_device *tz;
471 	struct nlattr *start_trip;
472 	int id;
473 
474 	if (!p->attrs[THERMAL_GENL_ATTR_TZ_ID])
475 		return -EINVAL;
476 
477 	id = nla_get_u32(p->attrs[THERMAL_GENL_ATTR_TZ_ID]);
478 
479 	tz = thermal_zone_get_by_id(id);
480 	if (!tz)
481 		return -EINVAL;
482 
483 	start_trip = nla_nest_start(msg, THERMAL_GENL_ATTR_TZ_TRIP);
484 	if (!start_trip)
485 		return -EMSGSIZE;
486 
487 	mutex_lock(&tz->lock);
488 
489 	for_each_trip(tz, trip) {
490 		if (nla_put_u32(msg, THERMAL_GENL_ATTR_TZ_TRIP_ID,
491 				thermal_zone_trip_id(tz, trip)) ||
492 		    nla_put_u32(msg, THERMAL_GENL_ATTR_TZ_TRIP_TYPE, trip->type) ||
493 		    nla_put_u32(msg, THERMAL_GENL_ATTR_TZ_TRIP_TEMP, trip->temperature) ||
494 		    nla_put_u32(msg, THERMAL_GENL_ATTR_TZ_TRIP_HYST, trip->hysteresis))
495 			goto out_cancel_nest;
496 	}
497 
498 	mutex_unlock(&tz->lock);
499 
500 	nla_nest_end(msg, start_trip);
501 
502 	return 0;
503 
504 out_cancel_nest:
505 	mutex_unlock(&tz->lock);
506 
507 	return -EMSGSIZE;
508 }
509 
510 static int thermal_genl_cmd_tz_get_temp(struct param *p)
511 {
512 	struct sk_buff *msg = p->msg;
513 	struct thermal_zone_device *tz;
514 	int temp, ret, id;
515 
516 	if (!p->attrs[THERMAL_GENL_ATTR_TZ_ID])
517 		return -EINVAL;
518 
519 	id = nla_get_u32(p->attrs[THERMAL_GENL_ATTR_TZ_ID]);
520 
521 	tz = thermal_zone_get_by_id(id);
522 	if (!tz)
523 		return -EINVAL;
524 
525 	ret = thermal_zone_get_temp(tz, &temp);
526 	if (ret)
527 		return ret;
528 
529 	if (nla_put_u32(msg, THERMAL_GENL_ATTR_TZ_ID, id) ||
530 	    nla_put_u32(msg, THERMAL_GENL_ATTR_TZ_TEMP, temp))
531 		return -EMSGSIZE;
532 
533 	return 0;
534 }
535 
536 static int thermal_genl_cmd_tz_get_gov(struct param *p)
537 {
538 	struct sk_buff *msg = p->msg;
539 	struct thermal_zone_device *tz;
540 	int id, ret = 0;
541 
542 	if (!p->attrs[THERMAL_GENL_ATTR_TZ_ID])
543 		return -EINVAL;
544 
545 	id = nla_get_u32(p->attrs[THERMAL_GENL_ATTR_TZ_ID]);
546 
547 	tz = thermal_zone_get_by_id(id);
548 	if (!tz)
549 		return -EINVAL;
550 
551 	mutex_lock(&tz->lock);
552 
553 	if (nla_put_u32(msg, THERMAL_GENL_ATTR_TZ_ID, id) ||
554 	    nla_put_string(msg, THERMAL_GENL_ATTR_TZ_GOV_NAME,
555 			   tz->governor->name))
556 		ret = -EMSGSIZE;
557 
558 	mutex_unlock(&tz->lock);
559 
560 	return ret;
561 }
562 
563 static int __thermal_genl_cmd_cdev_get(struct thermal_cooling_device *cdev,
564 				       void *data)
565 {
566 	struct sk_buff *msg = data;
567 
568 	if (nla_put_u32(msg, THERMAL_GENL_ATTR_CDEV_ID, cdev->id))
569 		return -EMSGSIZE;
570 
571 	if (nla_put_string(msg, THERMAL_GENL_ATTR_CDEV_NAME, cdev->type))
572 		return -EMSGSIZE;
573 
574 	return 0;
575 }
576 
577 static int thermal_genl_cmd_cdev_get(struct param *p)
578 {
579 	struct sk_buff *msg = p->msg;
580 	struct nlattr *start_cdev;
581 	int ret;
582 
583 	start_cdev = nla_nest_start(msg, THERMAL_GENL_ATTR_CDEV);
584 	if (!start_cdev)
585 		return -EMSGSIZE;
586 
587 	ret = for_each_thermal_cooling_device(__thermal_genl_cmd_cdev_get, msg);
588 	if (ret)
589 		goto out_cancel_nest;
590 
591 	nla_nest_end(msg, start_cdev);
592 
593 	return 0;
594 out_cancel_nest:
595 	nla_nest_cancel(msg, start_cdev);
596 
597 	return ret;
598 }
599 
600 static cb_t cmd_cb[] = {
601 	[THERMAL_GENL_CMD_TZ_GET_ID]	= thermal_genl_cmd_tz_get_id,
602 	[THERMAL_GENL_CMD_TZ_GET_TRIP]	= thermal_genl_cmd_tz_get_trip,
603 	[THERMAL_GENL_CMD_TZ_GET_TEMP]	= thermal_genl_cmd_tz_get_temp,
604 	[THERMAL_GENL_CMD_TZ_GET_GOV]	= thermal_genl_cmd_tz_get_gov,
605 	[THERMAL_GENL_CMD_CDEV_GET]	= thermal_genl_cmd_cdev_get,
606 };
607 
608 static int thermal_genl_cmd_dumpit(struct sk_buff *skb,
609 				   struct netlink_callback *cb)
610 {
611 	struct param p = { .msg = skb };
612 	const struct genl_dumpit_info *info = genl_dumpit_info(cb);
613 	int cmd = info->op.cmd;
614 	int ret;
615 	void *hdr;
616 
617 	hdr = genlmsg_put(skb, 0, 0, &thermal_gnl_family, 0, cmd);
618 	if (!hdr)
619 		return -EMSGSIZE;
620 
621 	ret = cmd_cb[cmd](&p);
622 	if (ret)
623 		goto out_cancel_msg;
624 
625 	genlmsg_end(skb, hdr);
626 
627 	return 0;
628 
629 out_cancel_msg:
630 	genlmsg_cancel(skb, hdr);
631 
632 	return ret;
633 }
634 
635 static int thermal_genl_cmd_doit(struct sk_buff *skb,
636 				 struct genl_info *info)
637 {
638 	struct param p = { .attrs = info->attrs };
639 	struct sk_buff *msg;
640 	void *hdr;
641 	int cmd = info->genlhdr->cmd;
642 	int ret = -EMSGSIZE;
643 
644 	msg = genlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL);
645 	if (!msg)
646 		return -ENOMEM;
647 	p.msg = msg;
648 
649 	hdr = genlmsg_put_reply(msg, info, &thermal_gnl_family, 0, cmd);
650 	if (!hdr)
651 		goto out_free_msg;
652 
653 	ret = cmd_cb[cmd](&p);
654 	if (ret)
655 		goto out_cancel_msg;
656 
657 	genlmsg_end(msg, hdr);
658 
659 	return genlmsg_reply(msg, info);
660 
661 out_cancel_msg:
662 	genlmsg_cancel(msg, hdr);
663 out_free_msg:
664 	nlmsg_free(msg);
665 
666 	return ret;
667 }
668 
669 static const struct genl_small_ops thermal_genl_ops[] = {
670 	{
671 		.cmd = THERMAL_GENL_CMD_TZ_GET_ID,
672 		.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
673 		.dumpit = thermal_genl_cmd_dumpit,
674 	},
675 	{
676 		.cmd = THERMAL_GENL_CMD_TZ_GET_TRIP,
677 		.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
678 		.doit = thermal_genl_cmd_doit,
679 	},
680 	{
681 		.cmd = THERMAL_GENL_CMD_TZ_GET_TEMP,
682 		.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
683 		.doit = thermal_genl_cmd_doit,
684 	},
685 	{
686 		.cmd = THERMAL_GENL_CMD_TZ_GET_GOV,
687 		.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
688 		.doit = thermal_genl_cmd_doit,
689 	},
690 	{
691 		.cmd = THERMAL_GENL_CMD_CDEV_GET,
692 		.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
693 		.dumpit = thermal_genl_cmd_dumpit,
694 	},
695 };
696 
697 static struct genl_family thermal_gnl_family __ro_after_init = {
698 	.hdrsize	= 0,
699 	.name		= THERMAL_GENL_FAMILY_NAME,
700 	.version	= THERMAL_GENL_VERSION,
701 	.maxattr	= THERMAL_GENL_ATTR_MAX,
702 	.policy		= thermal_genl_policy,
703 	.small_ops	= thermal_genl_ops,
704 	.n_small_ops	= ARRAY_SIZE(thermal_genl_ops),
705 	.resv_start_op	= THERMAL_GENL_CMD_CDEV_GET + 1,
706 	.mcgrps		= thermal_genl_mcgrps,
707 	.n_mcgrps	= ARRAY_SIZE(thermal_genl_mcgrps),
708 };
709 
710 int __init thermal_netlink_init(void)
711 {
712 	return genl_register_family(&thermal_gnl_family);
713 }
714 
715 void __init thermal_netlink_exit(void)
716 {
717 	genl_unregister_family(&thermal_gnl_family);
718 }
719