1 // SPDX-License-Identifier: LGPL-2.1+
2 // Copyright (C) 2022, Linaro Ltd - Daniel Lezcano <daniel.lezcano@linaro.org>
3 #include <linux/netlink.h>
10 #include "thermal_nl.h"
13 * Optimization: fill this array to tell which event we do want to pay
14 * attention to. That happens at init time with the ops
15 * structure. Each ops will enable the event and the general handler
16 * will be able to discard the event if there is not ops associated
19 static int enabled_ops
[__THERMAL_GENL_EVENT_MAX
];
21 static int handle_thermal_event(struct nl_msg
*n
, void *arg
)
23 struct nlmsghdr
*nlh
= nlmsg_hdr(n
);
24 struct genlmsghdr
*genlhdr
= genlmsg_hdr(nlh
);
25 struct nlattr
*attrs
[THERMAL_GENL_ATTR_MAX
+ 1];
26 struct thermal_handler_param
*thp
= arg
;
27 struct thermal_events_ops
*ops
= &thp
->th
->ops
->events
;
29 genlmsg_parse(nlh
, 0, attrs
, THERMAL_GENL_ATTR_MAX
, NULL
);
34 * This is an event we don't care of, bail out.
36 if (!enabled_ops
[genlhdr
->cmd
])
37 return THERMAL_SUCCESS
;
39 switch (genlhdr
->cmd
) {
41 case THERMAL_GENL_EVENT_TZ_CREATE
:
42 return ops
->tz_create(nla_get_string(attrs
[THERMAL_GENL_ATTR_TZ_NAME
]),
43 nla_get_u32(attrs
[THERMAL_GENL_ATTR_TZ_ID
]), arg
);
45 case THERMAL_GENL_EVENT_TZ_DELETE
:
46 return ops
->tz_delete(nla_get_u32(attrs
[THERMAL_GENL_ATTR_TZ_ID
]), arg
);
48 case THERMAL_GENL_EVENT_TZ_ENABLE
:
49 return ops
->tz_enable(nla_get_u32(attrs
[THERMAL_GENL_ATTR_TZ_ID
]), arg
);
51 case THERMAL_GENL_EVENT_TZ_DISABLE
:
52 return ops
->tz_disable(nla_get_u32(attrs
[THERMAL_GENL_ATTR_TZ_ID
]), arg
);
54 case THERMAL_GENL_EVENT_TZ_TRIP_CHANGE
:
55 return ops
->trip_change(nla_get_u32(attrs
[THERMAL_GENL_ATTR_TZ_ID
]),
56 nla_get_u32(attrs
[THERMAL_GENL_ATTR_TZ_TRIP_ID
]),
57 nla_get_u32(attrs
[THERMAL_GENL_ATTR_TZ_TRIP_TYPE
]),
58 nla_get_u32(attrs
[THERMAL_GENL_ATTR_TZ_TRIP_TEMP
]),
59 nla_get_u32(attrs
[THERMAL_GENL_ATTR_TZ_TRIP_HYST
]), arg
);
61 case THERMAL_GENL_EVENT_TZ_TRIP_ADD
:
62 return ops
->trip_add(nla_get_u32(attrs
[THERMAL_GENL_ATTR_TZ_ID
]),
63 nla_get_u32(attrs
[THERMAL_GENL_ATTR_TZ_TRIP_ID
]),
64 nla_get_u32(attrs
[THERMAL_GENL_ATTR_TZ_TRIP_TYPE
]),
65 nla_get_u32(attrs
[THERMAL_GENL_ATTR_TZ_TRIP_TEMP
]),
66 nla_get_u32(attrs
[THERMAL_GENL_ATTR_TZ_TRIP_HYST
]), arg
);
68 case THERMAL_GENL_EVENT_TZ_TRIP_DELETE
:
69 return ops
->trip_delete(nla_get_u32(attrs
[THERMAL_GENL_ATTR_TZ_ID
]),
70 nla_get_u32(attrs
[THERMAL_GENL_ATTR_TZ_TRIP_ID
]), arg
);
72 case THERMAL_GENL_EVENT_TZ_TRIP_UP
:
73 return ops
->trip_high(nla_get_u32(attrs
[THERMAL_GENL_ATTR_TZ_ID
]),
74 nla_get_u32(attrs
[THERMAL_GENL_ATTR_TZ_TRIP_ID
]),
75 nla_get_u32(attrs
[THERMAL_GENL_ATTR_TZ_TEMP
]), arg
);
77 case THERMAL_GENL_EVENT_TZ_TRIP_DOWN
:
78 return ops
->trip_low(nla_get_u32(attrs
[THERMAL_GENL_ATTR_TZ_ID
]),
79 nla_get_u32(attrs
[THERMAL_GENL_ATTR_TZ_TRIP_ID
]),
80 nla_get_u32(attrs
[THERMAL_GENL_ATTR_TZ_TEMP
]), arg
);
82 case THERMAL_GENL_EVENT_CDEV_ADD
:
83 return ops
->cdev_add(nla_get_string(attrs
[THERMAL_GENL_ATTR_CDEV_NAME
]),
84 nla_get_u32(attrs
[THERMAL_GENL_ATTR_CDEV_ID
]),
85 nla_get_u32(attrs
[THERMAL_GENL_ATTR_CDEV_MAX_STATE
]), arg
);
87 case THERMAL_GENL_EVENT_CDEV_DELETE
:
88 return ops
->cdev_delete(nla_get_u32(attrs
[THERMAL_GENL_ATTR_CDEV_ID
]), arg
);
90 case THERMAL_GENL_EVENT_CDEV_STATE_UPDATE
:
91 return ops
->cdev_update(nla_get_u32(attrs
[THERMAL_GENL_ATTR_CDEV_ID
]),
92 nla_get_u32(attrs
[THERMAL_GENL_ATTR_CDEV_CUR_STATE
]), arg
);
94 case THERMAL_GENL_EVENT_TZ_GOV_CHANGE
:
95 return ops
->gov_change(nla_get_u32(attrs
[THERMAL_GENL_ATTR_TZ_ID
]),
96 nla_get_string(attrs
[THERMAL_GENL_ATTR_GOV_NAME
]), arg
);
98 case THERMAL_GENL_EVENT_THRESHOLD_ADD
:
99 return ops
->threshold_add(nla_get_u32(attrs
[THERMAL_GENL_ATTR_TZ_ID
]),
100 nla_get_u32(attrs
[THERMAL_GENL_ATTR_THRESHOLD_TEMP
]),
101 nla_get_u32(attrs
[THERMAL_GENL_ATTR_THRESHOLD_DIRECTION
]), arg
);
103 case THERMAL_GENL_EVENT_THRESHOLD_DELETE
:
104 return ops
->threshold_delete(nla_get_u32(attrs
[THERMAL_GENL_ATTR_TZ_ID
]),
105 nla_get_u32(attrs
[THERMAL_GENL_ATTR_THRESHOLD_TEMP
]),
106 nla_get_u32(attrs
[THERMAL_GENL_ATTR_THRESHOLD_DIRECTION
]), arg
);
108 case THERMAL_GENL_EVENT_THRESHOLD_FLUSH
:
109 return ops
->threshold_flush(nla_get_u32(attrs
[THERMAL_GENL_ATTR_TZ_ID
]), arg
);
111 case THERMAL_GENL_EVENT_THRESHOLD_UP
:
112 return ops
->threshold_up(nla_get_u32(attrs
[THERMAL_GENL_ATTR_TZ_ID
]),
113 nla_get_u32(attrs
[THERMAL_GENL_ATTR_TZ_TEMP
]),
114 nla_get_u32(attrs
[THERMAL_GENL_ATTR_TZ_PREV_TEMP
]), arg
);
116 case THERMAL_GENL_EVENT_THRESHOLD_DOWN
:
117 return ops
->threshold_down(nla_get_u32(attrs
[THERMAL_GENL_ATTR_TZ_ID
]),
118 nla_get_u32(attrs
[THERMAL_GENL_ATTR_TZ_TEMP
]),
119 nla_get_u32(attrs
[THERMAL_GENL_ATTR_TZ_PREV_TEMP
]), arg
);
126 static void thermal_events_ops_init(struct thermal_events_ops
*ops
)
128 enabled_ops
[THERMAL_GENL_EVENT_TZ_CREATE
] = !!ops
->tz_create
;
129 enabled_ops
[THERMAL_GENL_EVENT_TZ_DELETE
] = !!ops
->tz_delete
;
130 enabled_ops
[THERMAL_GENL_EVENT_TZ_DISABLE
] = !!ops
->tz_disable
;
131 enabled_ops
[THERMAL_GENL_EVENT_TZ_ENABLE
] = !!ops
->tz_enable
;
132 enabled_ops
[THERMAL_GENL_EVENT_TZ_TRIP_UP
] = !!ops
->trip_high
;
133 enabled_ops
[THERMAL_GENL_EVENT_TZ_TRIP_DOWN
] = !!ops
->trip_low
;
134 enabled_ops
[THERMAL_GENL_EVENT_TZ_TRIP_CHANGE
] = !!ops
->trip_change
;
135 enabled_ops
[THERMAL_GENL_EVENT_TZ_TRIP_ADD
] = !!ops
->trip_add
;
136 enabled_ops
[THERMAL_GENL_EVENT_TZ_TRIP_DELETE
] = !!ops
->trip_delete
;
137 enabled_ops
[THERMAL_GENL_EVENT_CDEV_ADD
] = !!ops
->cdev_add
;
138 enabled_ops
[THERMAL_GENL_EVENT_CDEV_DELETE
] = !!ops
->cdev_delete
;
139 enabled_ops
[THERMAL_GENL_EVENT_CDEV_STATE_UPDATE
] = !!ops
->cdev_update
;
140 enabled_ops
[THERMAL_GENL_EVENT_TZ_GOV_CHANGE
] = !!ops
->gov_change
;
141 enabled_ops
[THERMAL_GENL_EVENT_THRESHOLD_ADD
] = !!ops
->threshold_add
;
142 enabled_ops
[THERMAL_GENL_EVENT_THRESHOLD_DELETE
] = !!ops
->threshold_delete
;
143 enabled_ops
[THERMAL_GENL_EVENT_THRESHOLD_FLUSH
] = !!ops
->threshold_flush
;
144 enabled_ops
[THERMAL_GENL_EVENT_THRESHOLD_UP
] = !!ops
->threshold_up
;
145 enabled_ops
[THERMAL_GENL_EVENT_THRESHOLD_DOWN
] = !!ops
->threshold_down
;
148 thermal_error_t
thermal_events_handle(struct thermal_handler
*th
, void *arg
)
150 struct thermal_handler_param thp
= { .th
= th
, .arg
= arg
};
153 return THERMAL_ERROR
;
155 if (nl_cb_set(th
->cb_event
, NL_CB_VALID
, NL_CB_CUSTOM
,
156 handle_thermal_event
, &thp
))
157 return THERMAL_ERROR
;
159 return nl_recvmsgs(th
->sk_event
, th
->cb_event
);
162 int thermal_events_fd(struct thermal_handler
*th
)
167 return nl_socket_get_fd(th
->sk_event
);
170 thermal_error_t
thermal_events_exit(struct thermal_handler
*th
)
172 if (nl_unsubscribe_thermal(th
->sk_event
, th
->cb_event
,
173 THERMAL_GENL_EVENT_GROUP_NAME
))
174 return THERMAL_ERROR
;
176 nl_thermal_disconnect(th
->sk_event
, th
->cb_event
);
178 return THERMAL_SUCCESS
;
181 thermal_error_t
thermal_events_init(struct thermal_handler
*th
)
183 thermal_events_ops_init(&th
->ops
->events
);
185 if (nl_thermal_connect(&th
->sk_event
, &th
->cb_event
))
186 return THERMAL_ERROR
;
188 if (nl_subscribe_thermal(th
->sk_event
, th
->cb_event
,
189 THERMAL_GENL_EVENT_GROUP_NAME
))
190 return THERMAL_ERROR
;
192 return THERMAL_SUCCESS
;