1 // SPDX-License-Identifier: LGPL-2.1+ 2 // Copyright (C) 2022, Linaro Ltd - Daniel Lezcano <daniel.lezcano@linaro.org> 3 #include <linux/netlink.h> 4 #include <stdio.h> 5 #include <stdlib.h> 6 #include <unistd.h> 7 8 9 #include <thermal.h> 10 #include "thermal_nl.h" 11 12 /* 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 17 * with it. 18 */ 19 static int enabled_ops[__THERMAL_GENL_EVENT_MAX]; 20 21 static int handle_thermal_event(struct nl_msg *n, void *arg) 22 { 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; 28 29 genlmsg_parse(nlh, 0, attrs, THERMAL_GENL_ATTR_MAX, NULL); 30 31 arg = thp->arg; 32 33 /* 34 * This is an event we don't care of, bail out. 35 */ 36 if (!enabled_ops[genlhdr->cmd]) 37 return THERMAL_SUCCESS; 38 39 switch (genlhdr->cmd) { 40 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); 44 45 case THERMAL_GENL_EVENT_TZ_DELETE: 46 return ops->tz_delete(nla_get_u32(attrs[THERMAL_GENL_ATTR_TZ_ID]), arg); 47 48 case THERMAL_GENL_EVENT_TZ_ENABLE: 49 return ops->tz_enable(nla_get_u32(attrs[THERMAL_GENL_ATTR_TZ_ID]), arg); 50 51 case THERMAL_GENL_EVENT_TZ_DISABLE: 52 return ops->tz_disable(nla_get_u32(attrs[THERMAL_GENL_ATTR_TZ_ID]), arg); 53 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); 60 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); 67 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); 71 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); 76 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); 81 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); 86 87 case THERMAL_GENL_EVENT_CDEV_DELETE: 88 return ops->cdev_delete(nla_get_u32(attrs[THERMAL_GENL_ATTR_CDEV_ID]), arg); 89 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); 93 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); 97 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); 102 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); 107 108 case THERMAL_GENL_EVENT_THRESHOLD_FLUSH: 109 return ops->threshold_flush(nla_get_u32(attrs[THERMAL_GENL_ATTR_TZ_ID]), arg); 110 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); 115 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); 120 121 default: 122 return -1; 123 } 124 } 125 126 static void thermal_events_ops_init(struct thermal_events_ops *ops) 127 { 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; 146 } 147 148 thermal_error_t thermal_events_handle(struct thermal_handler *th, void *arg) 149 { 150 struct thermal_handler_param thp = { .th = th, .arg = arg }; 151 152 if (!th) 153 return THERMAL_ERROR; 154 155 if (nl_cb_set(th->cb_event, NL_CB_VALID, NL_CB_CUSTOM, 156 handle_thermal_event, &thp)) 157 return THERMAL_ERROR; 158 159 return nl_recvmsgs(th->sk_event, th->cb_event); 160 } 161 162 int thermal_events_fd(struct thermal_handler *th) 163 { 164 if (!th) 165 return -1; 166 167 return nl_socket_get_fd(th->sk_event); 168 } 169 170 thermal_error_t thermal_events_exit(struct thermal_handler *th) 171 { 172 if (nl_unsubscribe_thermal(th->sk_event, th->cb_event, 173 THERMAL_GENL_EVENT_GROUP_NAME)) 174 return THERMAL_ERROR; 175 176 nl_thermal_disconnect(th->sk_event, th->cb_event); 177 178 return THERMAL_SUCCESS; 179 } 180 181 thermal_error_t thermal_events_init(struct thermal_handler *th) 182 { 183 thermal_events_ops_init(&th->ops->events); 184 185 if (nl_thermal_connect(&th->sk_event, &th->cb_event)) 186 return THERMAL_ERROR; 187 188 if (nl_subscribe_thermal(th->sk_event, th->cb_event, 189 THERMAL_GENL_EVENT_GROUP_NAME)) 190 return THERMAL_ERROR; 191 192 return THERMAL_SUCCESS; 193 } 194