99#include <linux/module.h>
1010#include <linux/notifier.h>
1111#include <linux/kernel.h>
12+ #include <net/sock.h>
1213#include <net/genetlink.h>
1314#include <uapi/linux/thermal.h>
1415
@@ -49,6 +50,11 @@ static const struct nla_policy thermal_genl_policy[THERMAL_GENL_ATTR_MAX + 1] =
4950 [THERMAL_GENL_ATTR_CPU_CAPABILITY_ID ] = { .type = NLA_U32 },
5051 [THERMAL_GENL_ATTR_CPU_CAPABILITY_PERFORMANCE ] = { .type = NLA_U32 },
5152 [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 },
5258};
5359
5460struct param {
@@ -62,6 +68,8 @@ struct param {
6268 int trip_type ;
6369 int trip_hyst ;
6470 int temp ;
71+ int prev_temp ;
72+ int direction ;
6573 int cdev_state ;
6674 int cdev_max_state ;
6775 struct thermal_genl_cpu_caps * cpu_capabilities ;
@@ -234,6 +242,34 @@ static int thermal_genl_event_cpu_capability_change(struct param *p)
234242 return - EMSGSIZE ;
235243}
236244
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+
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+
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+
237273int thermal_genl_event_tz_delete (struct param * p )
238274 __attribute__((alias ("thermal_genl_event_tz" )));
239275
@@ -246,6 +282,12 @@ int thermal_genl_event_tz_disable(struct param *p)
246282int thermal_genl_event_tz_trip_down (struct param * p )
247283 __attribute__((alias ("thermal_genl_event_tz_trip_up" )));
248284
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+
249291static cb_t event_cb [] = {
250292 [THERMAL_GENL_EVENT_TZ_CREATE ] = thermal_genl_event_tz_create ,
251293 [THERMAL_GENL_EVENT_TZ_DELETE ] = thermal_genl_event_tz_delete ,
@@ -259,6 +301,11 @@ static cb_t event_cb[] = {
259301 [THERMAL_GENL_EVENT_CDEV_STATE_UPDATE ] = thermal_genl_event_cdev_state_update ,
260302 [THERMAL_GENL_EVENT_TZ_GOV_CHANGE ] = thermal_genl_event_gov_change ,
261303 [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 ,
262309};
263310
264311/*
@@ -401,6 +448,43 @@ int thermal_genl_cpu_capability_event(int count,
401448}
402449EXPORT_SYMBOL_GPL (thermal_genl_cpu_capability_event );
403450
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+
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+
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+
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+
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+
404488/*************************** Command encoding ********************************/
405489
406490static int __thermal_genl_cmd_tz_get_id (struct thermal_zone_device * tz ,
@@ -563,12 +647,128 @@ static int thermal_genl_cmd_cdev_get(struct param *p)
563647 return ret ;
564648}
565649
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+
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+
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+
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+
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+
566762static cb_t cmd_cb [] = {
567- [THERMAL_GENL_CMD_TZ_GET_ID ] = thermal_genl_cmd_tz_get_id ,
568- [THERMAL_GENL_CMD_TZ_GET_TRIP ] = thermal_genl_cmd_tz_get_trip ,
569- [THERMAL_GENL_CMD_TZ_GET_TEMP ] = thermal_genl_cmd_tz_get_temp ,
570- [THERMAL_GENL_CMD_TZ_GET_GOV ] = thermal_genl_cmd_tz_get_gov ,
571- [THERMAL_GENL_CMD_CDEV_GET ] = thermal_genl_cmd_cdev_get ,
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 ,
572772};
573773
574774static int thermal_genl_cmd_dumpit (struct sk_buff * skb ,
@@ -679,6 +879,26 @@ static const struct genl_small_ops thermal_genl_ops[] = {
679879 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP ,
680880 .dumpit = thermal_genl_cmd_dumpit ,
681881 },
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+ },
682902};
683903
684904static struct genl_family thermal_genl_family __ro_after_init = {
@@ -691,7 +911,7 @@ static struct genl_family thermal_genl_family __ro_after_init = {
691911 .unbind = thermal_genl_unbind ,
692912 .small_ops = thermal_genl_ops ,
693913 .n_small_ops = ARRAY_SIZE (thermal_genl_ops ),
694- .resv_start_op = THERMAL_GENL_CMD_CDEV_GET + 1 ,
914+ .resv_start_op = __THERMAL_GENL_CMD_MAX ,
695915 .mcgrps = thermal_genl_mcgrps ,
696916 .n_mcgrps = ARRAY_SIZE (thermal_genl_mcgrps ),
697917};
0 commit comments