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