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 default: 98 return -1; 99 } 100 } 101 102 static void thermal_events_ops_init(struct thermal_events_ops *ops) 103 { 104 enabled_ops[THERMAL_GENL_EVENT_TZ_CREATE] = !!ops->tz_create; 105 enabled_ops[THERMAL_GENL_EVENT_TZ_DELETE] = !!ops->tz_delete; 106 enabled_ops[THERMAL_GENL_EVENT_TZ_DISABLE] = !!ops->tz_disable; 107 enabled_ops[THERMAL_GENL_EVENT_TZ_ENABLE] = !!ops->tz_enable; 108 enabled_ops[THERMAL_GENL_EVENT_TZ_TRIP_UP] = !!ops->trip_high; 109 enabled_ops[THERMAL_GENL_EVENT_TZ_TRIP_DOWN] = !!ops->trip_low; 110 enabled_ops[THERMAL_GENL_EVENT_TZ_TRIP_CHANGE] = !!ops->trip_change; 111 enabled_ops[THERMAL_GENL_EVENT_TZ_TRIP_ADD] = !!ops->trip_add; 112 enabled_ops[THERMAL_GENL_EVENT_TZ_TRIP_DELETE] = !!ops->trip_delete; 113 enabled_ops[THERMAL_GENL_EVENT_CDEV_ADD] = !!ops->cdev_add; 114 enabled_ops[THERMAL_GENL_EVENT_CDEV_DELETE] = !!ops->cdev_delete; 115 enabled_ops[THERMAL_GENL_EVENT_CDEV_STATE_UPDATE] = !!ops->cdev_update; 116 enabled_ops[THERMAL_GENL_EVENT_TZ_GOV_CHANGE] = !!ops->gov_change; 117 } 118 119 thermal_error_t thermal_events_handle(struct thermal_handler *th, void *arg) 120 { 121 struct thermal_handler_param thp = { .th = th, .arg = arg }; 122 123 if (!th) 124 return THERMAL_ERROR; 125 126 if (nl_cb_set(th->cb_event, NL_CB_VALID, NL_CB_CUSTOM, 127 handle_thermal_event, &thp)) 128 return THERMAL_ERROR; 129 130 return nl_recvmsgs(th->sk_event, th->cb_event); 131 } 132 133 int thermal_events_fd(struct thermal_handler *th) 134 { 135 if (!th) 136 return -1; 137 138 return nl_socket_get_fd(th->sk_event); 139 } 140 141 thermal_error_t thermal_events_exit(struct thermal_handler *th) 142 { 143 if (nl_unsubscribe_thermal(th->sk_event, th->cb_event, 144 THERMAL_GENL_EVENT_GROUP_NAME)) 145 return THERMAL_ERROR; 146 147 nl_thermal_disconnect(th->sk_event, th->cb_event); 148 149 return THERMAL_SUCCESS; 150 } 151 152 thermal_error_t thermal_events_init(struct thermal_handler *th) 153 { 154 thermal_events_ops_init(&th->ops->events); 155 156 if (nl_thermal_connect(&th->sk_event, &th->cb_event)) 157 return THERMAL_ERROR; 158 159 if (nl_subscribe_thermal(th->sk_event, th->cb_event, 160 THERMAL_GENL_EVENT_GROUP_NAME)) 161 return THERMAL_ERROR; 162 163 return THERMAL_SUCCESS; 164 } 165