1 // SPDX-License-Identifier: GPL-2.0
3 * Copyright 2020 Linaro Limited
5 * Author: Daniel Lezcano <daniel.lezcano@linaro.org>
7 * Generic netlink for thermal management framework
9 #include <linux/module.h>
10 #include <linux/notifier.h>
11 #include <linux/kernel.h>
13 #include <net/genetlink.h>
14 #include <uapi/linux/thermal.h>
16 #include "thermal_core.h"
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
, },
23 static const struct nla_policy thermal_genl_policy
[THERMAL_GENL_ATTR_MAX
+ 1] = {
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
},
38 [THERMAL_GENL_ATTR_TZ_GOV
] = { .type
= NLA_NESTED
},
39 [THERMAL_GENL_ATTR_TZ_GOV_NAME
] = { .type
= NLA_STRING
,
40 .len
= THERMAL_NAME_LENGTH
},
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
},
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
},
61 struct nlattr
**attrs
;
75 struct thermal_genl_cpu_caps
*cpu_capabilities
;
76 int cpu_capabilities_count
;
79 typedef int (*cb_t
)(struct param
*);
81 static struct genl_family thermal_genl_family
;
82 static BLOCKING_NOTIFIER_HEAD(thermal_genl_chain
);
84 static int thermal_group_has_listeners(enum thermal_genl_multicast_groups group
)
86 return genl_has_listeners(&thermal_genl_family
, &init_net
, group
);
89 /************************** Sampling encoding *******************************/
91 int thermal_genl_sampling_temp(int id
, int temp
)
96 if (!thermal_group_has_listeners(THERMAL_GENL_SAMPLING_GROUP
))
99 skb
= genlmsg_new(NLMSG_GOODSIZE
, GFP_KERNEL
);
103 hdr
= genlmsg_put(skb
, 0, 0, &thermal_genl_family
, 0,
104 THERMAL_GENL_SAMPLING_TEMP
);
108 if (nla_put_u32(skb
, THERMAL_GENL_ATTR_TZ_ID
, id
))
111 if (nla_put_u32(skb
, THERMAL_GENL_ATTR_TZ_TEMP
, temp
))
114 genlmsg_end(skb
, hdr
);
116 genlmsg_multicast(&thermal_genl_family
, skb
, 0, THERMAL_GENL_SAMPLING_GROUP
, GFP_KERNEL
);
120 genlmsg_cancel(skb
, hdr
);
127 /**************************** Event encoding *********************************/
129 static int thermal_genl_event_tz_create(struct param
*p
)
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
))
138 static int thermal_genl_event_tz(struct param
*p
)
140 if (nla_put_u32(p
->msg
, THERMAL_GENL_ATTR_TZ_ID
, p
->tz_id
))
146 static int thermal_genl_event_tz_trip_up(struct param
*p
)
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
))
156 static int thermal_genl_event_tz_trip_change(struct param
*p
)
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
))
168 static int thermal_genl_event_cdev_add(struct param
*p
)
170 if (nla_put_string(p
->msg
, THERMAL_GENL_ATTR_CDEV_NAME
,
172 nla_put_u32(p
->msg
, THERMAL_GENL_ATTR_CDEV_ID
,
174 nla_put_u32(p
->msg
, THERMAL_GENL_ATTR_CDEV_MAX_STATE
,
181 static int thermal_genl_event_cdev_delete(struct param
*p
)
183 if (nla_put_u32(p
->msg
, THERMAL_GENL_ATTR_CDEV_ID
, p
->cdev_id
))
189 static int thermal_genl_event_cdev_state_update(struct param
*p
)
191 if (nla_put_u32(p
->msg
, THERMAL_GENL_ATTR_CDEV_ID
,
193 nla_put_u32(p
->msg
, THERMAL_GENL_ATTR_CDEV_CUR_STATE
,
200 static int thermal_genl_event_gov_change(struct param
*p
)
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
))
209 static int thermal_genl_event_cpu_capability_change(struct param
*p
)
211 struct thermal_genl_cpu_caps
*cpu_cap
= p
->cpu_capabilities
;
212 struct sk_buff
*msg
= p
->msg
;
213 struct nlattr
*start_cap
;
216 start_cap
= nla_nest_start(msg
, THERMAL_GENL_ATTR_CPU_CAPABILITY
);
220 for (i
= 0; i
< p
->cpu_capabilities_count
; ++i
) {
221 if (nla_put_u32(msg
, THERMAL_GENL_ATTR_CPU_CAPABILITY_ID
,
223 goto out_cancel_nest
;
225 if (nla_put_u32(msg
, THERMAL_GENL_ATTR_CPU_CAPABILITY_PERFORMANCE
,
226 cpu_cap
->performance
))
227 goto out_cancel_nest
;
229 if (nla_put_u32(msg
, THERMAL_GENL_ATTR_CPU_CAPABILITY_EFFICIENCY
,
230 cpu_cap
->efficiency
))
231 goto out_cancel_nest
;
236 nla_nest_end(msg
, start_cap
);
240 nla_nest_cancel(msg
, start_cap
);
245 static int thermal_genl_event_threshold_add(struct param
*p
)
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
))
255 static int thermal_genl_event_threshold_flush(struct param
*p
)
257 if (nla_put_u32(p
->msg
, THERMAL_GENL_ATTR_TZ_ID
, p
->tz_id
))
263 static int thermal_genl_event_threshold_up(struct param
*p
)
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
))
273 int thermal_genl_event_tz_delete(struct param
*p
)
274 __attribute__((alias("thermal_genl_event_tz")));
276 int thermal_genl_event_tz_enable(struct param
*p
)
277 __attribute__((alias("thermal_genl_event_tz")));
279 int thermal_genl_event_tz_disable(struct param
*p
)
280 __attribute__((alias("thermal_genl_event_tz")));
282 int thermal_genl_event_tz_trip_down(struct param
*p
)
283 __attribute__((alias("thermal_genl_event_tz_trip_up")));
285 int thermal_genl_event_threshold_delete(struct param
*p
)
286 __attribute__((alias("thermal_genl_event_threshold_add")));
288 int thermal_genl_event_threshold_down(struct param
*p
)
289 __attribute__((alias("thermal_genl_event_threshold_up")));
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
,
312 * Generic netlink event encoding
314 static int thermal_genl_send_event(enum thermal_genl_event event
,
321 if (!thermal_group_has_listeners(THERMAL_GENL_EVENT_GROUP
))
324 msg
= genlmsg_new(NLMSG_GOODSIZE
, GFP_KERNEL
);
329 hdr
= genlmsg_put(msg
, 0, 0, &thermal_genl_family
, 0, event
);
333 ret
= event_cb
[event
](p
);
337 genlmsg_end(msg
, hdr
);
339 genlmsg_multicast(&thermal_genl_family
, msg
, 0, THERMAL_GENL_EVENT_GROUP
, GFP_KERNEL
);
344 genlmsg_cancel(msg
, hdr
);
351 int thermal_notify_tz_create(const struct thermal_zone_device
*tz
)
353 struct param p
= { .tz_id
= tz
->id
, .name
= tz
->type
};
355 return thermal_genl_send_event(THERMAL_GENL_EVENT_TZ_CREATE
, &p
);
358 int thermal_notify_tz_delete(const struct thermal_zone_device
*tz
)
360 struct param p
= { .tz_id
= tz
->id
};
362 return thermal_genl_send_event(THERMAL_GENL_EVENT_TZ_DELETE
, &p
);
365 int thermal_notify_tz_enable(const struct thermal_zone_device
*tz
)
367 struct param p
= { .tz_id
= tz
->id
};
369 return thermal_genl_send_event(THERMAL_GENL_EVENT_TZ_ENABLE
, &p
);
372 int thermal_notify_tz_disable(const struct thermal_zone_device
*tz
)
374 struct param p
= { .tz_id
= tz
->id
};
376 return thermal_genl_send_event(THERMAL_GENL_EVENT_TZ_DISABLE
, &p
);
379 int thermal_notify_tz_trip_down(const struct thermal_zone_device
*tz
,
380 const struct thermal_trip
*trip
)
382 struct param p
= { .tz_id
= tz
->id
,
383 .trip_id
= thermal_zone_trip_id(tz
, trip
),
384 .temp
= tz
->temperature
};
386 return thermal_genl_send_event(THERMAL_GENL_EVENT_TZ_TRIP_DOWN
, &p
);
389 int thermal_notify_tz_trip_up(const struct thermal_zone_device
*tz
,
390 const struct thermal_trip
*trip
)
392 struct param p
= { .tz_id
= tz
->id
,
393 .trip_id
= thermal_zone_trip_id(tz
, trip
),
394 .temp
= tz
->temperature
};
396 return thermal_genl_send_event(THERMAL_GENL_EVENT_TZ_TRIP_UP
, &p
);
399 int thermal_notify_tz_trip_change(const struct thermal_zone_device
*tz
,
400 const struct thermal_trip
*trip
)
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
};
408 return thermal_genl_send_event(THERMAL_GENL_EVENT_TZ_TRIP_CHANGE
, &p
);
411 int thermal_notify_cdev_state_update(const struct thermal_cooling_device
*cdev
,
414 struct param p
= { .cdev_id
= cdev
->id
, .cdev_state
= state
};
416 return thermal_genl_send_event(THERMAL_GENL_EVENT_CDEV_STATE_UPDATE
, &p
);
419 int thermal_notify_cdev_add(const struct thermal_cooling_device
*cdev
)
421 struct param p
= { .cdev_id
= cdev
->id
, .name
= cdev
->type
,
422 .cdev_max_state
= cdev
->max_state
};
424 return thermal_genl_send_event(THERMAL_GENL_EVENT_CDEV_ADD
, &p
);
427 int thermal_notify_cdev_delete(const struct thermal_cooling_device
*cdev
)
429 struct param p
= { .cdev_id
= cdev
->id
};
431 return thermal_genl_send_event(THERMAL_GENL_EVENT_CDEV_DELETE
, &p
);
434 int thermal_notify_tz_gov_change(const struct thermal_zone_device
*tz
,
437 struct param p
= { .tz_id
= tz
->id
, .name
= name
};
439 return thermal_genl_send_event(THERMAL_GENL_EVENT_TZ_GOV_CHANGE
, &p
);
442 int thermal_genl_cpu_capability_event(int count
,
443 struct thermal_genl_cpu_caps
*caps
)
445 struct param p
= { .cpu_capabilities_count
= count
, .cpu_capabilities
= caps
};
447 return thermal_genl_send_event(THERMAL_GENL_EVENT_CPU_CAPABILITY_CHANGE
, &p
);
449 EXPORT_SYMBOL_GPL(thermal_genl_cpu_capability_event
);
451 int thermal_notify_threshold_add(const struct thermal_zone_device
*tz
,
452 int temperature
, int direction
)
454 struct param p
= { .tz_id
= tz
->id
, .temp
= temperature
, .direction
= direction
};
456 return thermal_genl_send_event(THERMAL_GENL_EVENT_THRESHOLD_ADD
, &p
);
459 int thermal_notify_threshold_delete(const struct thermal_zone_device
*tz
,
460 int temperature
, int direction
)
462 struct param p
= { .tz_id
= tz
->id
, .temp
= temperature
, .direction
= direction
};
464 return thermal_genl_send_event(THERMAL_GENL_EVENT_THRESHOLD_DELETE
, &p
);
467 int thermal_notify_threshold_flush(const struct thermal_zone_device
*tz
)
469 struct param p
= { .tz_id
= tz
->id
};
471 return thermal_genl_send_event(THERMAL_GENL_EVENT_THRESHOLD_FLUSH
, &p
);
474 int thermal_notify_threshold_down(const struct thermal_zone_device
*tz
)
476 struct param p
= { .tz_id
= tz
->id
, .temp
= tz
->temperature
, .prev_temp
= tz
->last_temperature
};
478 return thermal_genl_send_event(THERMAL_GENL_EVENT_THRESHOLD_DOWN
, &p
);
481 int thermal_notify_threshold_up(const struct thermal_zone_device
*tz
)
483 struct param p
= { .tz_id
= tz
->id
, .temp
= tz
->temperature
, .prev_temp
= tz
->last_temperature
};
485 return thermal_genl_send_event(THERMAL_GENL_EVENT_THRESHOLD_UP
, &p
);
488 /*************************** Command encoding ********************************/
490 static int __thermal_genl_cmd_tz_get_id(struct thermal_zone_device
*tz
,
493 struct sk_buff
*msg
= data
;
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
))
502 static int thermal_genl_cmd_tz_get_id(struct param
*p
)
504 struct sk_buff
*msg
= p
->msg
;
505 struct nlattr
*start_tz
;
508 start_tz
= nla_nest_start(msg
, THERMAL_GENL_ATTR_TZ
);
512 ret
= for_each_thermal_zone(__thermal_genl_cmd_tz_get_id
, msg
);
514 goto out_cancel_nest
;
516 nla_nest_end(msg
, start_tz
);
521 nla_nest_cancel(msg
, start_tz
);
526 static int thermal_genl_cmd_tz_get_trip(struct param
*p
)
528 struct sk_buff
*msg
= p
->msg
;
529 const struct thermal_trip_desc
*td
;
530 struct nlattr
*start_trip
;
533 if (!p
->attrs
[THERMAL_GENL_ATTR_TZ_ID
])
536 id
= nla_get_u32(p
->attrs
[THERMAL_GENL_ATTR_TZ_ID
]);
538 CLASS(thermal_zone_get_by_id
, tz
)(id
);
542 start_trip
= nla_nest_start(msg
, THERMAL_GENL_ATTR_TZ_TRIP
);
546 guard(thermal_zone
)(tz
);
548 for_each_trip_desc(tz
, td
) {
549 const struct thermal_trip
*trip
= &td
->trip
;
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
))
559 nla_nest_end(msg
, start_trip
);
564 static int thermal_genl_cmd_tz_get_temp(struct param
*p
)
566 struct sk_buff
*msg
= p
->msg
;
569 if (!p
->attrs
[THERMAL_GENL_ATTR_TZ_ID
])
572 id
= nla_get_u32(p
->attrs
[THERMAL_GENL_ATTR_TZ_ID
]);
574 CLASS(thermal_zone_get_by_id
, tz
)(id
);
578 ret
= thermal_zone_get_temp(tz
, &temp
);
582 if (nla_put_u32(msg
, THERMAL_GENL_ATTR_TZ_ID
, id
) ||
583 nla_put_u32(msg
, THERMAL_GENL_ATTR_TZ_TEMP
, temp
))
589 static int thermal_genl_cmd_tz_get_gov(struct param
*p
)
591 struct sk_buff
*msg
= p
->msg
;
594 if (!p
->attrs
[THERMAL_GENL_ATTR_TZ_ID
])
597 id
= nla_get_u32(p
->attrs
[THERMAL_GENL_ATTR_TZ_ID
]);
599 CLASS(thermal_zone_get_by_id
, tz
)(id
);
603 guard(thermal_zone
)(tz
);
605 if (nla_put_u32(msg
, THERMAL_GENL_ATTR_TZ_ID
, id
) ||
606 nla_put_string(msg
, THERMAL_GENL_ATTR_TZ_GOV_NAME
,
613 static int __thermal_genl_cmd_cdev_get(struct thermal_cooling_device
*cdev
,
616 struct sk_buff
*msg
= data
;
618 if (nla_put_u32(msg
, THERMAL_GENL_ATTR_CDEV_ID
, cdev
->id
))
621 if (nla_put_string(msg
, THERMAL_GENL_ATTR_CDEV_NAME
, cdev
->type
))
627 static int thermal_genl_cmd_cdev_get(struct param
*p
)
629 struct sk_buff
*msg
= p
->msg
;
630 struct nlattr
*start_cdev
;
633 start_cdev
= nla_nest_start(msg
, THERMAL_GENL_ATTR_CDEV
);
637 ret
= for_each_thermal_cooling_device(__thermal_genl_cmd_cdev_get
, msg
);
639 goto out_cancel_nest
;
641 nla_nest_end(msg
, start_cdev
);
645 nla_nest_cancel(msg
, start_cdev
);
650 static int __thermal_genl_cmd_threshold_get(struct user_threshold
*threshold
, void *arg
)
652 struct sk_buff
*msg
= arg
;
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
))
661 static int thermal_genl_cmd_threshold_get(struct param
*p
)
663 struct sk_buff
*msg
= p
->msg
;
664 struct nlattr
*start_trip
;
667 if (!p
->attrs
[THERMAL_GENL_ATTR_TZ_ID
])
670 id
= nla_get_u32(p
->attrs
[THERMAL_GENL_ATTR_TZ_ID
]);
672 CLASS(thermal_zone_get_by_id
, tz
)(id
);
676 start_trip
= nla_nest_start(msg
, THERMAL_GENL_ATTR_THRESHOLD
);
680 ret
= thermal_thresholds_for_each(tz
, __thermal_genl_cmd_threshold_get
, msg
);
684 nla_nest_end(msg
, start_trip
);
689 static int thermal_genl_cmd_threshold_add(struct param
*p
)
691 int id
, temp
, direction
;
693 if (!capable(CAP_SYS_ADMIN
))
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
])
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
]);
705 CLASS(thermal_zone_get_by_id
, tz
)(id
);
709 guard(thermal_zone
)(tz
);
711 return thermal_thresholds_add(tz
, temp
, direction
);
714 static int thermal_genl_cmd_threshold_delete(struct param
*p
)
716 int id
, temp
, direction
;
718 if (!capable(CAP_SYS_ADMIN
))
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
])
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
]);
730 CLASS(thermal_zone_get_by_id
, tz
)(id
);
734 guard(thermal_zone
)(tz
);
736 return thermal_thresholds_delete(tz
, temp
, direction
);
739 static int thermal_genl_cmd_threshold_flush(struct param
*p
)
743 if (!capable(CAP_SYS_ADMIN
))
746 if (!p
->attrs
[THERMAL_GENL_ATTR_TZ_ID
])
749 id
= nla_get_u32(p
->attrs
[THERMAL_GENL_ATTR_TZ_ID
]);
751 CLASS(thermal_zone_get_by_id
, tz
)(id
);
755 guard(thermal_zone
)(tz
);
757 thermal_thresholds_flush(tz
);
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
,
774 static int thermal_genl_cmd_dumpit(struct sk_buff
*skb
,
775 struct netlink_callback
*cb
)
777 struct param p
= { .msg
= skb
};
778 const struct genl_dumpit_info
*info
= genl_dumpit_info(cb
);
779 int cmd
= info
->op
.cmd
;
783 hdr
= genlmsg_put(skb
, 0, 0, &thermal_genl_family
, 0, cmd
);
787 ret
= cmd_cb
[cmd
](&p
);
791 genlmsg_end(skb
, hdr
);
796 genlmsg_cancel(skb
, hdr
);
801 static int thermal_genl_cmd_doit(struct sk_buff
*skb
,
802 struct genl_info
*info
)
804 struct param p
= { .attrs
= info
->attrs
};
807 int cmd
= info
->genlhdr
->cmd
;
810 msg
= genlmsg_new(NLMSG_GOODSIZE
, GFP_KERNEL
);
815 hdr
= genlmsg_put_reply(msg
, info
, &thermal_genl_family
, 0, cmd
);
819 ret
= cmd_cb
[cmd
](&p
);
823 genlmsg_end(msg
, hdr
);
825 return genlmsg_reply(msg
, info
);
828 genlmsg_cancel(msg
, hdr
);
835 static int thermal_genl_bind(int mcgrp
)
837 struct thermal_genl_notify n
= { .mcgrp
= mcgrp
};
839 if (WARN_ON_ONCE(mcgrp
> THERMAL_GENL_MAX_GROUP
))
842 blocking_notifier_call_chain(&thermal_genl_chain
, THERMAL_NOTIFY_BIND
, &n
);
846 static void thermal_genl_unbind(int mcgrp
)
848 struct thermal_genl_notify n
= { .mcgrp
= mcgrp
};
850 if (WARN_ON_ONCE(mcgrp
> THERMAL_GENL_MAX_GROUP
))
853 blocking_notifier_call_chain(&thermal_genl_chain
, THERMAL_NOTIFY_UNBIND
, &n
);
856 static const struct genl_small_ops thermal_genl_ops
[] = {
858 .cmd
= THERMAL_GENL_CMD_TZ_GET_ID
,
859 .validate
= GENL_DONT_VALIDATE_STRICT
| GENL_DONT_VALIDATE_DUMP
,
860 .dumpit
= thermal_genl_cmd_dumpit
,
863 .cmd
= THERMAL_GENL_CMD_TZ_GET_TRIP
,
864 .validate
= GENL_DONT_VALIDATE_STRICT
| GENL_DONT_VALIDATE_DUMP
,
865 .doit
= thermal_genl_cmd_doit
,
868 .cmd
= THERMAL_GENL_CMD_TZ_GET_TEMP
,
869 .validate
= GENL_DONT_VALIDATE_STRICT
| GENL_DONT_VALIDATE_DUMP
,
870 .doit
= thermal_genl_cmd_doit
,
873 .cmd
= THERMAL_GENL_CMD_TZ_GET_GOV
,
874 .validate
= GENL_DONT_VALIDATE_STRICT
| GENL_DONT_VALIDATE_DUMP
,
875 .doit
= thermal_genl_cmd_doit
,
878 .cmd
= THERMAL_GENL_CMD_CDEV_GET
,
879 .validate
= GENL_DONT_VALIDATE_STRICT
| GENL_DONT_VALIDATE_DUMP
,
880 .dumpit
= thermal_genl_cmd_dumpit
,
883 .cmd
= THERMAL_GENL_CMD_THRESHOLD_GET
,
884 .validate
= GENL_DONT_VALIDATE_STRICT
| GENL_DONT_VALIDATE_DUMP
,
885 .doit
= thermal_genl_cmd_doit
,
888 .cmd
= THERMAL_GENL_CMD_THRESHOLD_ADD
,
889 .validate
= GENL_DONT_VALIDATE_STRICT
| GENL_DONT_VALIDATE_DUMP
,
890 .doit
= thermal_genl_cmd_doit
,
893 .cmd
= THERMAL_GENL_CMD_THRESHOLD_DELETE
,
894 .validate
= GENL_DONT_VALIDATE_STRICT
| GENL_DONT_VALIDATE_DUMP
,
895 .doit
= thermal_genl_cmd_doit
,
898 .cmd
= THERMAL_GENL_CMD_THRESHOLD_FLUSH
,
899 .validate
= GENL_DONT_VALIDATE_STRICT
| GENL_DONT_VALIDATE_DUMP
,
900 .doit
= thermal_genl_cmd_doit
,
904 static struct genl_family thermal_genl_family __ro_after_init
= {
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
),
919 int thermal_genl_register_notifier(struct notifier_block
*nb
)
921 return blocking_notifier_chain_register(&thermal_genl_chain
, nb
);
924 int thermal_genl_unregister_notifier(struct notifier_block
*nb
)
926 return blocking_notifier_chain_unregister(&thermal_genl_chain
, nb
);
929 int __init
thermal_netlink_init(void)
931 return genl_register_family(&thermal_genl_family
);
934 void __init
thermal_netlink_exit(void)
936 genl_unregister_family(&thermal_genl_family
);