1*47c4b0deSDaniel Lezcano // SPDX-License-Identifier: LGPL-2.1+ 2*47c4b0deSDaniel Lezcano // Copyright (C) 2022, Linaro Ltd - Daniel Lezcano <daniel.lezcano@linaro.org> 3*47c4b0deSDaniel Lezcano #include <linux/netlink.h> 4*47c4b0deSDaniel Lezcano #include <stdio.h> 5*47c4b0deSDaniel Lezcano #include <stdlib.h> 6*47c4b0deSDaniel Lezcano #include <unistd.h> 7*47c4b0deSDaniel Lezcano 8*47c4b0deSDaniel Lezcano 9*47c4b0deSDaniel Lezcano #include <thermal.h> 10*47c4b0deSDaniel Lezcano #include "thermal_nl.h" 11*47c4b0deSDaniel Lezcano 12*47c4b0deSDaniel Lezcano /* 13*47c4b0deSDaniel Lezcano * Optimization: fill this array to tell which event we do want to pay 14*47c4b0deSDaniel Lezcano * attention to. That happens at init time with the ops 15*47c4b0deSDaniel Lezcano * structure. Each ops will enable the event and the general handler 16*47c4b0deSDaniel Lezcano * will be able to discard the event if there is not ops associated 17*47c4b0deSDaniel Lezcano * with it. 18*47c4b0deSDaniel Lezcano */ 19*47c4b0deSDaniel Lezcano static int enabled_ops[__THERMAL_GENL_EVENT_MAX]; 20*47c4b0deSDaniel Lezcano 21*47c4b0deSDaniel Lezcano static int handle_thermal_event(struct nl_msg *n, void *arg) 22*47c4b0deSDaniel Lezcano { 23*47c4b0deSDaniel Lezcano struct nlmsghdr *nlh = nlmsg_hdr(n); 24*47c4b0deSDaniel Lezcano struct genlmsghdr *genlhdr = genlmsg_hdr(nlh); 25*47c4b0deSDaniel Lezcano struct nlattr *attrs[THERMAL_GENL_ATTR_MAX + 1]; 26*47c4b0deSDaniel Lezcano struct thermal_handler_param *thp = arg; 27*47c4b0deSDaniel Lezcano struct thermal_events_ops *ops = &thp->th->ops->events; 28*47c4b0deSDaniel Lezcano 29*47c4b0deSDaniel Lezcano genlmsg_parse(nlh, 0, attrs, THERMAL_GENL_ATTR_MAX, NULL); 30*47c4b0deSDaniel Lezcano 31*47c4b0deSDaniel Lezcano arg = thp->arg; 32*47c4b0deSDaniel Lezcano 33*47c4b0deSDaniel Lezcano /* 34*47c4b0deSDaniel Lezcano * This is an event we don't care of, bail out. 35*47c4b0deSDaniel Lezcano */ 36*47c4b0deSDaniel Lezcano if (!enabled_ops[genlhdr->cmd]) 37*47c4b0deSDaniel Lezcano return THERMAL_SUCCESS; 38*47c4b0deSDaniel Lezcano 39*47c4b0deSDaniel Lezcano switch (genlhdr->cmd) { 40*47c4b0deSDaniel Lezcano 41*47c4b0deSDaniel Lezcano case THERMAL_GENL_EVENT_TZ_CREATE: 42*47c4b0deSDaniel Lezcano return ops->tz_create(nla_get_string(attrs[THERMAL_GENL_ATTR_TZ_NAME]), 43*47c4b0deSDaniel Lezcano nla_get_u32(attrs[THERMAL_GENL_ATTR_TZ_ID]), arg); 44*47c4b0deSDaniel Lezcano 45*47c4b0deSDaniel Lezcano case THERMAL_GENL_EVENT_TZ_DELETE: 46*47c4b0deSDaniel Lezcano return ops->tz_delete(nla_get_u32(attrs[THERMAL_GENL_ATTR_TZ_ID]), arg); 47*47c4b0deSDaniel Lezcano 48*47c4b0deSDaniel Lezcano case THERMAL_GENL_EVENT_TZ_ENABLE: 49*47c4b0deSDaniel Lezcano return ops->tz_enable(nla_get_u32(attrs[THERMAL_GENL_ATTR_TZ_ID]), arg); 50*47c4b0deSDaniel Lezcano 51*47c4b0deSDaniel Lezcano case THERMAL_GENL_EVENT_TZ_DISABLE: 52*47c4b0deSDaniel Lezcano return ops->tz_disable(nla_get_u32(attrs[THERMAL_GENL_ATTR_TZ_ID]), arg); 53*47c4b0deSDaniel Lezcano 54*47c4b0deSDaniel Lezcano case THERMAL_GENL_EVENT_TZ_TRIP_CHANGE: 55*47c4b0deSDaniel Lezcano return ops->trip_change(nla_get_u32(attrs[THERMAL_GENL_ATTR_TZ_ID]), 56*47c4b0deSDaniel Lezcano nla_get_u32(attrs[THERMAL_GENL_ATTR_TZ_TRIP_ID]), 57*47c4b0deSDaniel Lezcano nla_get_u32(attrs[THERMAL_GENL_ATTR_TZ_TRIP_TYPE]), 58*47c4b0deSDaniel Lezcano nla_get_u32(attrs[THERMAL_GENL_ATTR_TZ_TRIP_TEMP]), 59*47c4b0deSDaniel Lezcano nla_get_u32(attrs[THERMAL_GENL_ATTR_TZ_TRIP_HYST]), arg); 60*47c4b0deSDaniel Lezcano 61*47c4b0deSDaniel Lezcano case THERMAL_GENL_EVENT_TZ_TRIP_ADD: 62*47c4b0deSDaniel Lezcano return ops->trip_add(nla_get_u32(attrs[THERMAL_GENL_ATTR_TZ_ID]), 63*47c4b0deSDaniel Lezcano nla_get_u32(attrs[THERMAL_GENL_ATTR_TZ_TRIP_ID]), 64*47c4b0deSDaniel Lezcano nla_get_u32(attrs[THERMAL_GENL_ATTR_TZ_TRIP_TYPE]), 65*47c4b0deSDaniel Lezcano nla_get_u32(attrs[THERMAL_GENL_ATTR_TZ_TRIP_TEMP]), 66*47c4b0deSDaniel Lezcano nla_get_u32(attrs[THERMAL_GENL_ATTR_TZ_TRIP_HYST]), arg); 67*47c4b0deSDaniel Lezcano 68*47c4b0deSDaniel Lezcano case THERMAL_GENL_EVENT_TZ_TRIP_DELETE: 69*47c4b0deSDaniel Lezcano return ops->trip_delete(nla_get_u32(attrs[THERMAL_GENL_ATTR_TZ_ID]), 70*47c4b0deSDaniel Lezcano nla_get_u32(attrs[THERMAL_GENL_ATTR_TZ_TRIP_ID]), arg); 71*47c4b0deSDaniel Lezcano 72*47c4b0deSDaniel Lezcano case THERMAL_GENL_EVENT_TZ_TRIP_UP: 73*47c4b0deSDaniel Lezcano return ops->trip_high(nla_get_u32(attrs[THERMAL_GENL_ATTR_TZ_ID]), 74*47c4b0deSDaniel Lezcano nla_get_u32(attrs[THERMAL_GENL_ATTR_TZ_TRIP_ID]), 75*47c4b0deSDaniel Lezcano nla_get_u32(attrs[THERMAL_GENL_ATTR_TZ_TEMP]), arg); 76*47c4b0deSDaniel Lezcano 77*47c4b0deSDaniel Lezcano case THERMAL_GENL_EVENT_TZ_TRIP_DOWN: 78*47c4b0deSDaniel Lezcano return ops->trip_low(nla_get_u32(attrs[THERMAL_GENL_ATTR_TZ_ID]), 79*47c4b0deSDaniel Lezcano nla_get_u32(attrs[THERMAL_GENL_ATTR_TZ_TRIP_ID]), 80*47c4b0deSDaniel Lezcano nla_get_u32(attrs[THERMAL_GENL_ATTR_TZ_TEMP]), arg); 81*47c4b0deSDaniel Lezcano 82*47c4b0deSDaniel Lezcano case THERMAL_GENL_EVENT_CDEV_ADD: 83*47c4b0deSDaniel Lezcano return ops->cdev_add(nla_get_string(attrs[THERMAL_GENL_ATTR_CDEV_NAME]), 84*47c4b0deSDaniel Lezcano nla_get_u32(attrs[THERMAL_GENL_ATTR_CDEV_ID]), 85*47c4b0deSDaniel Lezcano nla_get_u32(attrs[THERMAL_GENL_ATTR_CDEV_MAX_STATE]), arg); 86*47c4b0deSDaniel Lezcano 87*47c4b0deSDaniel Lezcano case THERMAL_GENL_EVENT_CDEV_DELETE: 88*47c4b0deSDaniel Lezcano return ops->cdev_delete(nla_get_u32(attrs[THERMAL_GENL_ATTR_CDEV_ID]), arg); 89*47c4b0deSDaniel Lezcano 90*47c4b0deSDaniel Lezcano case THERMAL_GENL_EVENT_CDEV_STATE_UPDATE: 91*47c4b0deSDaniel Lezcano return ops->cdev_update(nla_get_u32(attrs[THERMAL_GENL_ATTR_CDEV_ID]), 92*47c4b0deSDaniel Lezcano nla_get_u32(attrs[THERMAL_GENL_ATTR_CDEV_CUR_STATE]), arg); 93*47c4b0deSDaniel Lezcano 94*47c4b0deSDaniel Lezcano case THERMAL_GENL_EVENT_TZ_GOV_CHANGE: 95*47c4b0deSDaniel Lezcano return ops->gov_change(nla_get_u32(attrs[THERMAL_GENL_ATTR_TZ_ID]), 96*47c4b0deSDaniel Lezcano nla_get_string(attrs[THERMAL_GENL_ATTR_GOV_NAME]), arg); 97*47c4b0deSDaniel Lezcano default: 98*47c4b0deSDaniel Lezcano return -1; 99*47c4b0deSDaniel Lezcano } 100*47c4b0deSDaniel Lezcano } 101*47c4b0deSDaniel Lezcano 102*47c4b0deSDaniel Lezcano static void thermal_events_ops_init(struct thermal_events_ops *ops) 103*47c4b0deSDaniel Lezcano { 104*47c4b0deSDaniel Lezcano enabled_ops[THERMAL_GENL_EVENT_TZ_CREATE] = !!ops->tz_create; 105*47c4b0deSDaniel Lezcano enabled_ops[THERMAL_GENL_EVENT_TZ_DELETE] = !!ops->tz_delete; 106*47c4b0deSDaniel Lezcano enabled_ops[THERMAL_GENL_EVENT_TZ_DISABLE] = !!ops->tz_disable; 107*47c4b0deSDaniel Lezcano enabled_ops[THERMAL_GENL_EVENT_TZ_ENABLE] = !!ops->tz_enable; 108*47c4b0deSDaniel Lezcano enabled_ops[THERMAL_GENL_EVENT_TZ_TRIP_UP] = !!ops->trip_high; 109*47c4b0deSDaniel Lezcano enabled_ops[THERMAL_GENL_EVENT_TZ_TRIP_DOWN] = !!ops->trip_low; 110*47c4b0deSDaniel Lezcano enabled_ops[THERMAL_GENL_EVENT_TZ_TRIP_CHANGE] = !!ops->trip_change; 111*47c4b0deSDaniel Lezcano enabled_ops[THERMAL_GENL_EVENT_TZ_TRIP_ADD] = !!ops->trip_add; 112*47c4b0deSDaniel Lezcano enabled_ops[THERMAL_GENL_EVENT_TZ_TRIP_DELETE] = !!ops->trip_delete; 113*47c4b0deSDaniel Lezcano enabled_ops[THERMAL_GENL_EVENT_CDEV_ADD] = !!ops->cdev_add; 114*47c4b0deSDaniel Lezcano enabled_ops[THERMAL_GENL_EVENT_CDEV_DELETE] = !!ops->cdev_delete; 115*47c4b0deSDaniel Lezcano enabled_ops[THERMAL_GENL_EVENT_CDEV_STATE_UPDATE] = !!ops->cdev_update; 116*47c4b0deSDaniel Lezcano enabled_ops[THERMAL_GENL_EVENT_TZ_GOV_CHANGE] = !!ops->gov_change; 117*47c4b0deSDaniel Lezcano } 118*47c4b0deSDaniel Lezcano 119*47c4b0deSDaniel Lezcano thermal_error_t thermal_events_handle(struct thermal_handler *th, void *arg) 120*47c4b0deSDaniel Lezcano { 121*47c4b0deSDaniel Lezcano struct thermal_handler_param thp = { .th = th, .arg = arg }; 122*47c4b0deSDaniel Lezcano 123*47c4b0deSDaniel Lezcano if (!th) 124*47c4b0deSDaniel Lezcano return THERMAL_ERROR; 125*47c4b0deSDaniel Lezcano 126*47c4b0deSDaniel Lezcano if (nl_cb_set(th->cb_event, NL_CB_VALID, NL_CB_CUSTOM, 127*47c4b0deSDaniel Lezcano handle_thermal_event, &thp)) 128*47c4b0deSDaniel Lezcano return THERMAL_ERROR; 129*47c4b0deSDaniel Lezcano 130*47c4b0deSDaniel Lezcano return nl_recvmsgs(th->sk_event, th->cb_event); 131*47c4b0deSDaniel Lezcano } 132*47c4b0deSDaniel Lezcano 133*47c4b0deSDaniel Lezcano int thermal_events_fd(struct thermal_handler *th) 134*47c4b0deSDaniel Lezcano { 135*47c4b0deSDaniel Lezcano if (!th) 136*47c4b0deSDaniel Lezcano return -1; 137*47c4b0deSDaniel Lezcano 138*47c4b0deSDaniel Lezcano return nl_socket_get_fd(th->sk_event); 139*47c4b0deSDaniel Lezcano } 140*47c4b0deSDaniel Lezcano 141*47c4b0deSDaniel Lezcano thermal_error_t thermal_events_exit(struct thermal_handler *th) 142*47c4b0deSDaniel Lezcano { 143*47c4b0deSDaniel Lezcano if (nl_unsubscribe_thermal(th->sk_event, th->cb_event, 144*47c4b0deSDaniel Lezcano THERMAL_GENL_EVENT_GROUP_NAME)) 145*47c4b0deSDaniel Lezcano return THERMAL_ERROR; 146*47c4b0deSDaniel Lezcano 147*47c4b0deSDaniel Lezcano nl_thermal_disconnect(th->sk_event, th->cb_event); 148*47c4b0deSDaniel Lezcano 149*47c4b0deSDaniel Lezcano return THERMAL_SUCCESS; 150*47c4b0deSDaniel Lezcano } 151*47c4b0deSDaniel Lezcano 152*47c4b0deSDaniel Lezcano thermal_error_t thermal_events_init(struct thermal_handler *th) 153*47c4b0deSDaniel Lezcano { 154*47c4b0deSDaniel Lezcano thermal_events_ops_init(&th->ops->events); 155*47c4b0deSDaniel Lezcano 156*47c4b0deSDaniel Lezcano if (nl_thermal_connect(&th->sk_event, &th->cb_event)) 157*47c4b0deSDaniel Lezcano return THERMAL_ERROR; 158*47c4b0deSDaniel Lezcano 159*47c4b0deSDaniel Lezcano if (nl_subscribe_thermal(th->sk_event, th->cb_event, 160*47c4b0deSDaniel Lezcano THERMAL_GENL_EVENT_GROUP_NAME)) 161*47c4b0deSDaniel Lezcano return THERMAL_ERROR; 162*47c4b0deSDaniel Lezcano 163*47c4b0deSDaniel Lezcano return THERMAL_SUCCESS; 164*47c4b0deSDaniel Lezcano } 165