1*1ce50e7dSDaniel Lezcano // SPDX-License-Identifier: GPL-2.0 2*1ce50e7dSDaniel Lezcano /* 3*1ce50e7dSDaniel Lezcano * Copyright 2020 Linaro Limited 4*1ce50e7dSDaniel Lezcano * 5*1ce50e7dSDaniel Lezcano * Author: Daniel Lezcano <daniel.lezcano@linaro.org> 6*1ce50e7dSDaniel Lezcano * 7*1ce50e7dSDaniel Lezcano * Generic netlink for thermal management framework 8*1ce50e7dSDaniel Lezcano */ 9*1ce50e7dSDaniel Lezcano #include <linux/module.h> 10*1ce50e7dSDaniel Lezcano #include <linux/kernel.h> 11*1ce50e7dSDaniel Lezcano #include <net/genetlink.h> 12*1ce50e7dSDaniel Lezcano #include <uapi/linux/thermal.h> 13*1ce50e7dSDaniel Lezcano 14*1ce50e7dSDaniel Lezcano #include "thermal_core.h" 15*1ce50e7dSDaniel Lezcano 16*1ce50e7dSDaniel Lezcano static const struct genl_multicast_group thermal_genl_mcgrps[] = { 17*1ce50e7dSDaniel Lezcano { .name = THERMAL_GENL_SAMPLING_GROUP_NAME, }, 18*1ce50e7dSDaniel Lezcano { .name = THERMAL_GENL_EVENT_GROUP_NAME, }, 19*1ce50e7dSDaniel Lezcano }; 20*1ce50e7dSDaniel Lezcano 21*1ce50e7dSDaniel Lezcano static const struct nla_policy thermal_genl_policy[THERMAL_GENL_ATTR_MAX + 1] = { 22*1ce50e7dSDaniel Lezcano /* Thermal zone */ 23*1ce50e7dSDaniel Lezcano [THERMAL_GENL_ATTR_TZ] = { .type = NLA_NESTED }, 24*1ce50e7dSDaniel Lezcano [THERMAL_GENL_ATTR_TZ_ID] = { .type = NLA_U32 }, 25*1ce50e7dSDaniel Lezcano [THERMAL_GENL_ATTR_TZ_TEMP] = { .type = NLA_U32 }, 26*1ce50e7dSDaniel Lezcano [THERMAL_GENL_ATTR_TZ_TRIP] = { .type = NLA_NESTED }, 27*1ce50e7dSDaniel Lezcano [THERMAL_GENL_ATTR_TZ_TRIP_ID] = { .type = NLA_U32 }, 28*1ce50e7dSDaniel Lezcano [THERMAL_GENL_ATTR_TZ_TRIP_TEMP] = { .type = NLA_U32 }, 29*1ce50e7dSDaniel Lezcano [THERMAL_GENL_ATTR_TZ_TRIP_TYPE] = { .type = NLA_U32 }, 30*1ce50e7dSDaniel Lezcano [THERMAL_GENL_ATTR_TZ_TRIP_HYST] = { .type = NLA_U32 }, 31*1ce50e7dSDaniel Lezcano [THERMAL_GENL_ATTR_TZ_MODE] = { .type = NLA_U32 }, 32*1ce50e7dSDaniel Lezcano [THERMAL_GENL_ATTR_TZ_CDEV_WEIGHT] = { .type = NLA_U32 }, 33*1ce50e7dSDaniel Lezcano [THERMAL_GENL_ATTR_TZ_NAME] = { .type = NLA_STRING, 34*1ce50e7dSDaniel Lezcano .len = THERMAL_NAME_LENGTH }, 35*1ce50e7dSDaniel Lezcano /* Governor(s) */ 36*1ce50e7dSDaniel Lezcano [THERMAL_GENL_ATTR_TZ_GOV] = { .type = NLA_NESTED }, 37*1ce50e7dSDaniel Lezcano [THERMAL_GENL_ATTR_TZ_GOV_NAME] = { .type = NLA_STRING, 38*1ce50e7dSDaniel Lezcano .len = THERMAL_NAME_LENGTH }, 39*1ce50e7dSDaniel Lezcano /* Cooling devices */ 40*1ce50e7dSDaniel Lezcano [THERMAL_GENL_ATTR_CDEV] = { .type = NLA_NESTED }, 41*1ce50e7dSDaniel Lezcano [THERMAL_GENL_ATTR_CDEV_ID] = { .type = NLA_U32 }, 42*1ce50e7dSDaniel Lezcano [THERMAL_GENL_ATTR_CDEV_CUR_STATE] = { .type = NLA_U32 }, 43*1ce50e7dSDaniel Lezcano [THERMAL_GENL_ATTR_CDEV_MAX_STATE] = { .type = NLA_U32 }, 44*1ce50e7dSDaniel Lezcano [THERMAL_GENL_ATTR_CDEV_NAME] = { .type = NLA_STRING, 45*1ce50e7dSDaniel Lezcano .len = THERMAL_NAME_LENGTH }, 46*1ce50e7dSDaniel Lezcano }; 47*1ce50e7dSDaniel Lezcano 48*1ce50e7dSDaniel Lezcano struct param { 49*1ce50e7dSDaniel Lezcano struct nlattr **attrs; 50*1ce50e7dSDaniel Lezcano struct sk_buff *msg; 51*1ce50e7dSDaniel Lezcano const char *name; 52*1ce50e7dSDaniel Lezcano int tz_id; 53*1ce50e7dSDaniel Lezcano int cdev_id; 54*1ce50e7dSDaniel Lezcano int trip_id; 55*1ce50e7dSDaniel Lezcano int trip_temp; 56*1ce50e7dSDaniel Lezcano int trip_type; 57*1ce50e7dSDaniel Lezcano int trip_hyst; 58*1ce50e7dSDaniel Lezcano int temp; 59*1ce50e7dSDaniel Lezcano int cdev_state; 60*1ce50e7dSDaniel Lezcano int cdev_max_state; 61*1ce50e7dSDaniel Lezcano }; 62*1ce50e7dSDaniel Lezcano 63*1ce50e7dSDaniel Lezcano typedef int (*cb_t)(struct param *); 64*1ce50e7dSDaniel Lezcano 65*1ce50e7dSDaniel Lezcano static struct genl_family thermal_gnl_family; 66*1ce50e7dSDaniel Lezcano 67*1ce50e7dSDaniel Lezcano /************************** Sampling encoding *******************************/ 68*1ce50e7dSDaniel Lezcano 69*1ce50e7dSDaniel Lezcano int thermal_genl_sampling_temp(int id, int temp) 70*1ce50e7dSDaniel Lezcano { 71*1ce50e7dSDaniel Lezcano struct sk_buff *skb; 72*1ce50e7dSDaniel Lezcano void *hdr; 73*1ce50e7dSDaniel Lezcano 74*1ce50e7dSDaniel Lezcano skb = genlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL); 75*1ce50e7dSDaniel Lezcano if (!skb) 76*1ce50e7dSDaniel Lezcano return -ENOMEM; 77*1ce50e7dSDaniel Lezcano 78*1ce50e7dSDaniel Lezcano hdr = genlmsg_put(skb, 0, 0, &thermal_gnl_family, 0, 79*1ce50e7dSDaniel Lezcano THERMAL_GENL_SAMPLING_TEMP); 80*1ce50e7dSDaniel Lezcano if (!hdr) 81*1ce50e7dSDaniel Lezcano return -EMSGSIZE; 82*1ce50e7dSDaniel Lezcano 83*1ce50e7dSDaniel Lezcano if (nla_put_u32(skb, THERMAL_GENL_ATTR_TZ_ID, id)) 84*1ce50e7dSDaniel Lezcano goto out_cancel; 85*1ce50e7dSDaniel Lezcano 86*1ce50e7dSDaniel Lezcano if (nla_put_u32(skb, THERMAL_GENL_ATTR_TZ_TEMP, temp)) 87*1ce50e7dSDaniel Lezcano goto out_cancel; 88*1ce50e7dSDaniel Lezcano 89*1ce50e7dSDaniel Lezcano genlmsg_end(skb, hdr); 90*1ce50e7dSDaniel Lezcano 91*1ce50e7dSDaniel Lezcano genlmsg_multicast(&thermal_gnl_family, skb, 0, 0, GFP_KERNEL); 92*1ce50e7dSDaniel Lezcano 93*1ce50e7dSDaniel Lezcano return 0; 94*1ce50e7dSDaniel Lezcano out_cancel: 95*1ce50e7dSDaniel Lezcano genlmsg_cancel(skb, hdr); 96*1ce50e7dSDaniel Lezcano nlmsg_free(skb); 97*1ce50e7dSDaniel Lezcano 98*1ce50e7dSDaniel Lezcano return -EMSGSIZE; 99*1ce50e7dSDaniel Lezcano } 100*1ce50e7dSDaniel Lezcano 101*1ce50e7dSDaniel Lezcano /**************************** Event encoding *********************************/ 102*1ce50e7dSDaniel Lezcano 103*1ce50e7dSDaniel Lezcano static int thermal_genl_event_tz_create(struct param *p) 104*1ce50e7dSDaniel Lezcano { 105*1ce50e7dSDaniel Lezcano if (nla_put_u32(p->msg, THERMAL_GENL_ATTR_TZ_ID, p->tz_id) || 106*1ce50e7dSDaniel Lezcano nla_put_string(p->msg, THERMAL_GENL_ATTR_TZ_NAME, p->name)) 107*1ce50e7dSDaniel Lezcano return -EMSGSIZE; 108*1ce50e7dSDaniel Lezcano 109*1ce50e7dSDaniel Lezcano return 0; 110*1ce50e7dSDaniel Lezcano } 111*1ce50e7dSDaniel Lezcano 112*1ce50e7dSDaniel Lezcano static int thermal_genl_event_tz(struct param *p) 113*1ce50e7dSDaniel Lezcano { 114*1ce50e7dSDaniel Lezcano if (nla_put_u32(p->msg, THERMAL_GENL_ATTR_TZ_ID, p->tz_id)) 115*1ce50e7dSDaniel Lezcano return -EMSGSIZE; 116*1ce50e7dSDaniel Lezcano 117*1ce50e7dSDaniel Lezcano return 0; 118*1ce50e7dSDaniel Lezcano } 119*1ce50e7dSDaniel Lezcano 120*1ce50e7dSDaniel Lezcano static int thermal_genl_event_tz_trip_up(struct param *p) 121*1ce50e7dSDaniel Lezcano { 122*1ce50e7dSDaniel Lezcano if (nla_put_u32(p->msg, THERMAL_GENL_ATTR_TZ_ID, p->tz_id) || 123*1ce50e7dSDaniel Lezcano nla_put_u32(p->msg, THERMAL_GENL_ATTR_TZ_TRIP_ID, p->trip_id)) 124*1ce50e7dSDaniel Lezcano return -EMSGSIZE; 125*1ce50e7dSDaniel Lezcano 126*1ce50e7dSDaniel Lezcano return 0; 127*1ce50e7dSDaniel Lezcano } 128*1ce50e7dSDaniel Lezcano 129*1ce50e7dSDaniel Lezcano static int thermal_genl_event_tz_trip_add(struct param *p) 130*1ce50e7dSDaniel Lezcano { 131*1ce50e7dSDaniel Lezcano if (nla_put_u32(p->msg, THERMAL_GENL_ATTR_TZ_ID, p->tz_id) || 132*1ce50e7dSDaniel Lezcano nla_put_u32(p->msg, THERMAL_GENL_ATTR_TZ_TRIP_ID, p->trip_id) || 133*1ce50e7dSDaniel Lezcano nla_put_u32(p->msg, THERMAL_GENL_ATTR_TZ_TRIP_TYPE, p->trip_type) || 134*1ce50e7dSDaniel Lezcano nla_put_u32(p->msg, THERMAL_GENL_ATTR_TZ_TRIP_TEMP, p->trip_temp) || 135*1ce50e7dSDaniel Lezcano nla_put_u32(p->msg, THERMAL_GENL_ATTR_TZ_TRIP_HYST, p->trip_hyst)) 136*1ce50e7dSDaniel Lezcano return -EMSGSIZE; 137*1ce50e7dSDaniel Lezcano 138*1ce50e7dSDaniel Lezcano return 0; 139*1ce50e7dSDaniel Lezcano } 140*1ce50e7dSDaniel Lezcano 141*1ce50e7dSDaniel Lezcano static int thermal_genl_event_tz_trip_delete(struct param *p) 142*1ce50e7dSDaniel Lezcano { 143*1ce50e7dSDaniel Lezcano if (nla_put_u32(p->msg, THERMAL_GENL_ATTR_TZ_ID, p->tz_id) || 144*1ce50e7dSDaniel Lezcano nla_put_u32(p->msg, THERMAL_GENL_ATTR_TZ_TRIP_ID, p->trip_id)) 145*1ce50e7dSDaniel Lezcano return -EMSGSIZE; 146*1ce50e7dSDaniel Lezcano 147*1ce50e7dSDaniel Lezcano return 0; 148*1ce50e7dSDaniel Lezcano } 149*1ce50e7dSDaniel Lezcano 150*1ce50e7dSDaniel Lezcano static int thermal_genl_event_cdev_add(struct param *p) 151*1ce50e7dSDaniel Lezcano { 152*1ce50e7dSDaniel Lezcano if (nla_put_string(p->msg, THERMAL_GENL_ATTR_CDEV_NAME, 153*1ce50e7dSDaniel Lezcano p->name) || 154*1ce50e7dSDaniel Lezcano nla_put_u32(p->msg, THERMAL_GENL_ATTR_CDEV_ID, 155*1ce50e7dSDaniel Lezcano p->cdev_id) || 156*1ce50e7dSDaniel Lezcano nla_put_u32(p->msg, THERMAL_GENL_ATTR_CDEV_MAX_STATE, 157*1ce50e7dSDaniel Lezcano p->cdev_max_state)) 158*1ce50e7dSDaniel Lezcano return -EMSGSIZE; 159*1ce50e7dSDaniel Lezcano 160*1ce50e7dSDaniel Lezcano return 0; 161*1ce50e7dSDaniel Lezcano } 162*1ce50e7dSDaniel Lezcano 163*1ce50e7dSDaniel Lezcano static int thermal_genl_event_cdev_delete(struct param *p) 164*1ce50e7dSDaniel Lezcano { 165*1ce50e7dSDaniel Lezcano if (nla_put_u32(p->msg, THERMAL_GENL_ATTR_CDEV_ID, p->cdev_id)) 166*1ce50e7dSDaniel Lezcano return -EMSGSIZE; 167*1ce50e7dSDaniel Lezcano 168*1ce50e7dSDaniel Lezcano return 0; 169*1ce50e7dSDaniel Lezcano } 170*1ce50e7dSDaniel Lezcano 171*1ce50e7dSDaniel Lezcano static int thermal_genl_event_cdev_state_update(struct param *p) 172*1ce50e7dSDaniel Lezcano { 173*1ce50e7dSDaniel Lezcano if (nla_put_u32(p->msg, THERMAL_GENL_ATTR_CDEV_ID, 174*1ce50e7dSDaniel Lezcano p->cdev_id) || 175*1ce50e7dSDaniel Lezcano nla_put_u32(p->msg, THERMAL_GENL_ATTR_CDEV_CUR_STATE, 176*1ce50e7dSDaniel Lezcano p->cdev_state)) 177*1ce50e7dSDaniel Lezcano return -EMSGSIZE; 178*1ce50e7dSDaniel Lezcano 179*1ce50e7dSDaniel Lezcano return 0; 180*1ce50e7dSDaniel Lezcano } 181*1ce50e7dSDaniel Lezcano 182*1ce50e7dSDaniel Lezcano static int thermal_genl_event_gov_change(struct param *p) 183*1ce50e7dSDaniel Lezcano { 184*1ce50e7dSDaniel Lezcano if (nla_put_u32(p->msg, THERMAL_GENL_ATTR_TZ_ID, p->tz_id) || 185*1ce50e7dSDaniel Lezcano nla_put_string(p->msg, THERMAL_GENL_ATTR_GOV_NAME, p->name)) 186*1ce50e7dSDaniel Lezcano return -EMSGSIZE; 187*1ce50e7dSDaniel Lezcano 188*1ce50e7dSDaniel Lezcano return 0; 189*1ce50e7dSDaniel Lezcano } 190*1ce50e7dSDaniel Lezcano 191*1ce50e7dSDaniel Lezcano int thermal_genl_event_tz_delete(struct param *p) 192*1ce50e7dSDaniel Lezcano __attribute__((alias("thermal_genl_event_tz"))); 193*1ce50e7dSDaniel Lezcano 194*1ce50e7dSDaniel Lezcano int thermal_genl_event_tz_enable(struct param *p) 195*1ce50e7dSDaniel Lezcano __attribute__((alias("thermal_genl_event_tz"))); 196*1ce50e7dSDaniel Lezcano 197*1ce50e7dSDaniel Lezcano int thermal_genl_event_tz_disable(struct param *p) 198*1ce50e7dSDaniel Lezcano __attribute__((alias("thermal_genl_event_tz"))); 199*1ce50e7dSDaniel Lezcano 200*1ce50e7dSDaniel Lezcano int thermal_genl_event_tz_trip_down(struct param *p) 201*1ce50e7dSDaniel Lezcano __attribute__((alias("thermal_genl_event_tz_trip_up"))); 202*1ce50e7dSDaniel Lezcano 203*1ce50e7dSDaniel Lezcano int thermal_genl_event_tz_trip_change(struct param *p) 204*1ce50e7dSDaniel Lezcano __attribute__((alias("thermal_genl_event_tz_trip_add"))); 205*1ce50e7dSDaniel Lezcano 206*1ce50e7dSDaniel Lezcano static cb_t event_cb[] = { 207*1ce50e7dSDaniel Lezcano [THERMAL_GENL_EVENT_TZ_CREATE] = thermal_genl_event_tz_create, 208*1ce50e7dSDaniel Lezcano [THERMAL_GENL_EVENT_TZ_DELETE] = thermal_genl_event_tz_delete, 209*1ce50e7dSDaniel Lezcano [THERMAL_GENL_EVENT_TZ_ENABLE] = thermal_genl_event_tz_enable, 210*1ce50e7dSDaniel Lezcano [THERMAL_GENL_EVENT_TZ_DISABLE] = thermal_genl_event_tz_disable, 211*1ce50e7dSDaniel Lezcano [THERMAL_GENL_EVENT_TZ_TRIP_UP] = thermal_genl_event_tz_trip_up, 212*1ce50e7dSDaniel Lezcano [THERMAL_GENL_EVENT_TZ_TRIP_DOWN] = thermal_genl_event_tz_trip_down, 213*1ce50e7dSDaniel Lezcano [THERMAL_GENL_EVENT_TZ_TRIP_CHANGE] = thermal_genl_event_tz_trip_change, 214*1ce50e7dSDaniel Lezcano [THERMAL_GENL_EVENT_TZ_TRIP_ADD] = thermal_genl_event_tz_trip_add, 215*1ce50e7dSDaniel Lezcano [THERMAL_GENL_EVENT_TZ_TRIP_DELETE] = thermal_genl_event_tz_trip_delete, 216*1ce50e7dSDaniel Lezcano [THERMAL_GENL_EVENT_CDEV_ADD] = thermal_genl_event_cdev_add, 217*1ce50e7dSDaniel Lezcano [THERMAL_GENL_EVENT_CDEV_DELETE] = thermal_genl_event_cdev_delete, 218*1ce50e7dSDaniel Lezcano [THERMAL_GENL_EVENT_CDEV_STATE_UPDATE] = thermal_genl_event_cdev_state_update, 219*1ce50e7dSDaniel Lezcano [THERMAL_GENL_EVENT_TZ_GOV_CHANGE] = thermal_genl_event_gov_change, 220*1ce50e7dSDaniel Lezcano }; 221*1ce50e7dSDaniel Lezcano 222*1ce50e7dSDaniel Lezcano /* 223*1ce50e7dSDaniel Lezcano * Generic netlink event encoding 224*1ce50e7dSDaniel Lezcano */ 225*1ce50e7dSDaniel Lezcano static int thermal_genl_send_event(enum thermal_genl_event event, 226*1ce50e7dSDaniel Lezcano struct param *p) 227*1ce50e7dSDaniel Lezcano { 228*1ce50e7dSDaniel Lezcano struct sk_buff *msg; 229*1ce50e7dSDaniel Lezcano int ret = -EMSGSIZE; 230*1ce50e7dSDaniel Lezcano void *hdr; 231*1ce50e7dSDaniel Lezcano 232*1ce50e7dSDaniel Lezcano msg = genlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL); 233*1ce50e7dSDaniel Lezcano if (!msg) 234*1ce50e7dSDaniel Lezcano return -ENOMEM; 235*1ce50e7dSDaniel Lezcano p->msg = msg; 236*1ce50e7dSDaniel Lezcano 237*1ce50e7dSDaniel Lezcano hdr = genlmsg_put(msg, 0, 0, &thermal_gnl_family, 0, event); 238*1ce50e7dSDaniel Lezcano if (!hdr) 239*1ce50e7dSDaniel Lezcano goto out_free_msg; 240*1ce50e7dSDaniel Lezcano 241*1ce50e7dSDaniel Lezcano ret = event_cb[event](p); 242*1ce50e7dSDaniel Lezcano if (ret) 243*1ce50e7dSDaniel Lezcano goto out_cancel_msg; 244*1ce50e7dSDaniel Lezcano 245*1ce50e7dSDaniel Lezcano genlmsg_end(msg, hdr); 246*1ce50e7dSDaniel Lezcano 247*1ce50e7dSDaniel Lezcano genlmsg_multicast(&thermal_gnl_family, msg, 0, 1, GFP_KERNEL); 248*1ce50e7dSDaniel Lezcano 249*1ce50e7dSDaniel Lezcano return 0; 250*1ce50e7dSDaniel Lezcano 251*1ce50e7dSDaniel Lezcano out_cancel_msg: 252*1ce50e7dSDaniel Lezcano genlmsg_cancel(msg, hdr); 253*1ce50e7dSDaniel Lezcano out_free_msg: 254*1ce50e7dSDaniel Lezcano nlmsg_free(msg); 255*1ce50e7dSDaniel Lezcano 256*1ce50e7dSDaniel Lezcano return ret; 257*1ce50e7dSDaniel Lezcano } 258*1ce50e7dSDaniel Lezcano 259*1ce50e7dSDaniel Lezcano int thermal_notify_tz_create(int tz_id, const char *name) 260*1ce50e7dSDaniel Lezcano { 261*1ce50e7dSDaniel Lezcano struct param p = { .tz_id = tz_id, .name = name }; 262*1ce50e7dSDaniel Lezcano 263*1ce50e7dSDaniel Lezcano return thermal_genl_send_event(THERMAL_GENL_EVENT_TZ_CREATE, &p); 264*1ce50e7dSDaniel Lezcano } 265*1ce50e7dSDaniel Lezcano 266*1ce50e7dSDaniel Lezcano int thermal_notify_tz_delete(int tz_id) 267*1ce50e7dSDaniel Lezcano { 268*1ce50e7dSDaniel Lezcano struct param p = { .tz_id = tz_id }; 269*1ce50e7dSDaniel Lezcano 270*1ce50e7dSDaniel Lezcano return thermal_genl_send_event(THERMAL_GENL_EVENT_TZ_DELETE, &p); 271*1ce50e7dSDaniel Lezcano } 272*1ce50e7dSDaniel Lezcano 273*1ce50e7dSDaniel Lezcano int thermal_notify_tz_enable(int tz_id) 274*1ce50e7dSDaniel Lezcano { 275*1ce50e7dSDaniel Lezcano struct param p = { .tz_id = tz_id }; 276*1ce50e7dSDaniel Lezcano 277*1ce50e7dSDaniel Lezcano return thermal_genl_send_event(THERMAL_GENL_EVENT_TZ_ENABLE, &p); 278*1ce50e7dSDaniel Lezcano } 279*1ce50e7dSDaniel Lezcano 280*1ce50e7dSDaniel Lezcano int thermal_notify_tz_disable(int tz_id) 281*1ce50e7dSDaniel Lezcano { 282*1ce50e7dSDaniel Lezcano struct param p = { .tz_id = tz_id }; 283*1ce50e7dSDaniel Lezcano 284*1ce50e7dSDaniel Lezcano return thermal_genl_send_event(THERMAL_GENL_EVENT_TZ_DISABLE, &p); 285*1ce50e7dSDaniel Lezcano } 286*1ce50e7dSDaniel Lezcano 287*1ce50e7dSDaniel Lezcano int thermal_notify_tz_trip_down(int tz_id, int trip_id) 288*1ce50e7dSDaniel Lezcano { 289*1ce50e7dSDaniel Lezcano struct param p = { .tz_id = tz_id, .trip_id = trip_id }; 290*1ce50e7dSDaniel Lezcano 291*1ce50e7dSDaniel Lezcano return thermal_genl_send_event(THERMAL_GENL_EVENT_TZ_TRIP_DOWN, &p); 292*1ce50e7dSDaniel Lezcano } 293*1ce50e7dSDaniel Lezcano 294*1ce50e7dSDaniel Lezcano int thermal_notify_tz_trip_up(int tz_id, int trip_id) 295*1ce50e7dSDaniel Lezcano { 296*1ce50e7dSDaniel Lezcano struct param p = { .tz_id = tz_id, .trip_id = trip_id }; 297*1ce50e7dSDaniel Lezcano 298*1ce50e7dSDaniel Lezcano return thermal_genl_send_event(THERMAL_GENL_EVENT_TZ_TRIP_UP, &p); 299*1ce50e7dSDaniel Lezcano } 300*1ce50e7dSDaniel Lezcano 301*1ce50e7dSDaniel Lezcano int thermal_notify_tz_trip_add(int tz_id, int trip_id, int trip_type, 302*1ce50e7dSDaniel Lezcano int trip_temp, int trip_hyst) 303*1ce50e7dSDaniel Lezcano { 304*1ce50e7dSDaniel Lezcano struct param p = { .tz_id = tz_id, .trip_id = trip_id, 305*1ce50e7dSDaniel Lezcano .trip_type = trip_type, .trip_temp = trip_temp, 306*1ce50e7dSDaniel Lezcano .trip_hyst = trip_hyst }; 307*1ce50e7dSDaniel Lezcano 308*1ce50e7dSDaniel Lezcano return thermal_genl_send_event(THERMAL_GENL_EVENT_TZ_TRIP_ADD, &p); 309*1ce50e7dSDaniel Lezcano } 310*1ce50e7dSDaniel Lezcano 311*1ce50e7dSDaniel Lezcano int thermal_notify_tz_trip_delete(int tz_id, int trip_id) 312*1ce50e7dSDaniel Lezcano { 313*1ce50e7dSDaniel Lezcano struct param p = { .tz_id = tz_id, .trip_id = trip_id }; 314*1ce50e7dSDaniel Lezcano 315*1ce50e7dSDaniel Lezcano return thermal_genl_send_event(THERMAL_GENL_EVENT_TZ_TRIP_DELETE, &p); 316*1ce50e7dSDaniel Lezcano } 317*1ce50e7dSDaniel Lezcano 318*1ce50e7dSDaniel Lezcano int thermal_notify_tz_trip_change(int tz_id, int trip_id, int trip_type, 319*1ce50e7dSDaniel Lezcano int trip_temp, int trip_hyst) 320*1ce50e7dSDaniel Lezcano { 321*1ce50e7dSDaniel Lezcano struct param p = { .tz_id = tz_id, .trip_id = trip_id, 322*1ce50e7dSDaniel Lezcano .trip_type = trip_type, .trip_temp = trip_temp, 323*1ce50e7dSDaniel Lezcano .trip_hyst = trip_hyst }; 324*1ce50e7dSDaniel Lezcano 325*1ce50e7dSDaniel Lezcano return thermal_genl_send_event(THERMAL_GENL_EVENT_TZ_TRIP_CHANGE, &p); 326*1ce50e7dSDaniel Lezcano } 327*1ce50e7dSDaniel Lezcano 328*1ce50e7dSDaniel Lezcano int thermal_notify_cdev_state_update(int cdev_id, int cdev_state) 329*1ce50e7dSDaniel Lezcano { 330*1ce50e7dSDaniel Lezcano struct param p = { .cdev_id = cdev_id, .cdev_state = cdev_state }; 331*1ce50e7dSDaniel Lezcano 332*1ce50e7dSDaniel Lezcano return thermal_genl_send_event(THERMAL_GENL_EVENT_CDEV_STATE_UPDATE, &p); 333*1ce50e7dSDaniel Lezcano } 334*1ce50e7dSDaniel Lezcano 335*1ce50e7dSDaniel Lezcano int thermal_notify_cdev_add(int cdev_id, const char *name, int cdev_max_state) 336*1ce50e7dSDaniel Lezcano { 337*1ce50e7dSDaniel Lezcano struct param p = { .cdev_id = cdev_id, .name = name, 338*1ce50e7dSDaniel Lezcano .cdev_max_state = cdev_max_state }; 339*1ce50e7dSDaniel Lezcano 340*1ce50e7dSDaniel Lezcano return thermal_genl_send_event(THERMAL_GENL_EVENT_CDEV_ADD, &p); 341*1ce50e7dSDaniel Lezcano } 342*1ce50e7dSDaniel Lezcano 343*1ce50e7dSDaniel Lezcano int thermal_notify_cdev_delete(int cdev_id) 344*1ce50e7dSDaniel Lezcano { 345*1ce50e7dSDaniel Lezcano struct param p = { .cdev_id = cdev_id }; 346*1ce50e7dSDaniel Lezcano 347*1ce50e7dSDaniel Lezcano return thermal_genl_send_event(THERMAL_GENL_EVENT_CDEV_DELETE, &p); 348*1ce50e7dSDaniel Lezcano } 349*1ce50e7dSDaniel Lezcano 350*1ce50e7dSDaniel Lezcano int thermal_notify_tz_gov_change(int tz_id, const char *name) 351*1ce50e7dSDaniel Lezcano { 352*1ce50e7dSDaniel Lezcano struct param p = { .tz_id = tz_id, .name = name }; 353*1ce50e7dSDaniel Lezcano 354*1ce50e7dSDaniel Lezcano return thermal_genl_send_event(THERMAL_GENL_EVENT_TZ_GOV_CHANGE, &p); 355*1ce50e7dSDaniel Lezcano } 356*1ce50e7dSDaniel Lezcano 357*1ce50e7dSDaniel Lezcano /*************************** Command encoding ********************************/ 358*1ce50e7dSDaniel Lezcano 359*1ce50e7dSDaniel Lezcano static int __thermal_genl_cmd_tz_get_id(struct thermal_zone_device *tz, 360*1ce50e7dSDaniel Lezcano void *data) 361*1ce50e7dSDaniel Lezcano { 362*1ce50e7dSDaniel Lezcano struct sk_buff *msg = data; 363*1ce50e7dSDaniel Lezcano 364*1ce50e7dSDaniel Lezcano if (nla_put_u32(msg, THERMAL_GENL_ATTR_TZ_ID, tz->id) || 365*1ce50e7dSDaniel Lezcano nla_put_string(msg, THERMAL_GENL_ATTR_TZ_NAME, tz->type)) 366*1ce50e7dSDaniel Lezcano return -EMSGSIZE; 367*1ce50e7dSDaniel Lezcano 368*1ce50e7dSDaniel Lezcano return 0; 369*1ce50e7dSDaniel Lezcano } 370*1ce50e7dSDaniel Lezcano 371*1ce50e7dSDaniel Lezcano static int thermal_genl_cmd_tz_get_id(struct param *p) 372*1ce50e7dSDaniel Lezcano { 373*1ce50e7dSDaniel Lezcano struct sk_buff *msg = p->msg; 374*1ce50e7dSDaniel Lezcano struct nlattr *start_tz; 375*1ce50e7dSDaniel Lezcano int ret; 376*1ce50e7dSDaniel Lezcano 377*1ce50e7dSDaniel Lezcano start_tz = nla_nest_start(msg, THERMAL_GENL_ATTR_TZ); 378*1ce50e7dSDaniel Lezcano if (!start_tz) 379*1ce50e7dSDaniel Lezcano return -EMSGSIZE; 380*1ce50e7dSDaniel Lezcano 381*1ce50e7dSDaniel Lezcano ret = for_each_thermal_zone(__thermal_genl_cmd_tz_get_id, msg); 382*1ce50e7dSDaniel Lezcano if (ret) 383*1ce50e7dSDaniel Lezcano goto out_cancel_nest; 384*1ce50e7dSDaniel Lezcano 385*1ce50e7dSDaniel Lezcano nla_nest_end(msg, start_tz); 386*1ce50e7dSDaniel Lezcano 387*1ce50e7dSDaniel Lezcano return 0; 388*1ce50e7dSDaniel Lezcano 389*1ce50e7dSDaniel Lezcano out_cancel_nest: 390*1ce50e7dSDaniel Lezcano nla_nest_cancel(msg, start_tz); 391*1ce50e7dSDaniel Lezcano 392*1ce50e7dSDaniel Lezcano return ret; 393*1ce50e7dSDaniel Lezcano } 394*1ce50e7dSDaniel Lezcano 395*1ce50e7dSDaniel Lezcano static int thermal_genl_cmd_tz_get_trip(struct param *p) 396*1ce50e7dSDaniel Lezcano { 397*1ce50e7dSDaniel Lezcano struct sk_buff *msg = p->msg; 398*1ce50e7dSDaniel Lezcano struct thermal_zone_device *tz; 399*1ce50e7dSDaniel Lezcano struct nlattr *start_trip; 400*1ce50e7dSDaniel Lezcano int i, id; 401*1ce50e7dSDaniel Lezcano 402*1ce50e7dSDaniel Lezcano if (!p->attrs[THERMAL_GENL_ATTR_TZ_ID]) 403*1ce50e7dSDaniel Lezcano return -EINVAL; 404*1ce50e7dSDaniel Lezcano 405*1ce50e7dSDaniel Lezcano id = nla_get_u32(p->attrs[THERMAL_GENL_ATTR_TZ_ID]); 406*1ce50e7dSDaniel Lezcano 407*1ce50e7dSDaniel Lezcano tz = thermal_zone_get_by_id(id); 408*1ce50e7dSDaniel Lezcano if (!tz) 409*1ce50e7dSDaniel Lezcano return -EINVAL; 410*1ce50e7dSDaniel Lezcano 411*1ce50e7dSDaniel Lezcano start_trip = nla_nest_start(msg, THERMAL_GENL_ATTR_TZ_TRIP); 412*1ce50e7dSDaniel Lezcano if (!start_trip) 413*1ce50e7dSDaniel Lezcano return -EMSGSIZE; 414*1ce50e7dSDaniel Lezcano 415*1ce50e7dSDaniel Lezcano mutex_lock(&tz->lock); 416*1ce50e7dSDaniel Lezcano 417*1ce50e7dSDaniel Lezcano for (i = 0; i < tz->trips; i++) { 418*1ce50e7dSDaniel Lezcano 419*1ce50e7dSDaniel Lezcano enum thermal_trip_type type; 420*1ce50e7dSDaniel Lezcano int temp, hyst; 421*1ce50e7dSDaniel Lezcano 422*1ce50e7dSDaniel Lezcano tz->ops->get_trip_type(tz, i, &type); 423*1ce50e7dSDaniel Lezcano tz->ops->get_trip_temp(tz, i, &temp); 424*1ce50e7dSDaniel Lezcano tz->ops->get_trip_hyst(tz, i, &hyst); 425*1ce50e7dSDaniel Lezcano 426*1ce50e7dSDaniel Lezcano if (nla_put_u32(msg, THERMAL_GENL_ATTR_TZ_TRIP_ID, i) || 427*1ce50e7dSDaniel Lezcano nla_put_u32(msg, THERMAL_GENL_ATTR_TZ_TRIP_TYPE, type) || 428*1ce50e7dSDaniel Lezcano nla_put_u32(msg, THERMAL_GENL_ATTR_TZ_TRIP_TEMP, temp) || 429*1ce50e7dSDaniel Lezcano nla_put_u32(msg, THERMAL_GENL_ATTR_TZ_TRIP_HYST, hyst)) 430*1ce50e7dSDaniel Lezcano goto out_cancel_nest; 431*1ce50e7dSDaniel Lezcano } 432*1ce50e7dSDaniel Lezcano 433*1ce50e7dSDaniel Lezcano mutex_unlock(&tz->lock); 434*1ce50e7dSDaniel Lezcano 435*1ce50e7dSDaniel Lezcano nla_nest_end(msg, start_trip); 436*1ce50e7dSDaniel Lezcano 437*1ce50e7dSDaniel Lezcano return 0; 438*1ce50e7dSDaniel Lezcano 439*1ce50e7dSDaniel Lezcano out_cancel_nest: 440*1ce50e7dSDaniel Lezcano mutex_unlock(&tz->lock); 441*1ce50e7dSDaniel Lezcano 442*1ce50e7dSDaniel Lezcano return -EMSGSIZE; 443*1ce50e7dSDaniel Lezcano } 444*1ce50e7dSDaniel Lezcano 445*1ce50e7dSDaniel Lezcano static int thermal_genl_cmd_tz_get_temp(struct param *p) 446*1ce50e7dSDaniel Lezcano { 447*1ce50e7dSDaniel Lezcano struct sk_buff *msg = p->msg; 448*1ce50e7dSDaniel Lezcano struct thermal_zone_device *tz; 449*1ce50e7dSDaniel Lezcano int temp, ret, id; 450*1ce50e7dSDaniel Lezcano 451*1ce50e7dSDaniel Lezcano if (!p->attrs[THERMAL_GENL_ATTR_TZ_ID]) 452*1ce50e7dSDaniel Lezcano return -EINVAL; 453*1ce50e7dSDaniel Lezcano 454*1ce50e7dSDaniel Lezcano id = nla_get_u32(p->attrs[THERMAL_GENL_ATTR_TZ_ID]); 455*1ce50e7dSDaniel Lezcano 456*1ce50e7dSDaniel Lezcano tz = thermal_zone_get_by_id(id); 457*1ce50e7dSDaniel Lezcano if (!tz) 458*1ce50e7dSDaniel Lezcano return -EINVAL; 459*1ce50e7dSDaniel Lezcano 460*1ce50e7dSDaniel Lezcano ret = thermal_zone_get_temp(tz, &temp); 461*1ce50e7dSDaniel Lezcano if (ret) 462*1ce50e7dSDaniel Lezcano return ret; 463*1ce50e7dSDaniel Lezcano 464*1ce50e7dSDaniel Lezcano if (nla_put_u32(msg, THERMAL_GENL_ATTR_TZ_ID, id) || 465*1ce50e7dSDaniel Lezcano nla_put_u32(msg, THERMAL_GENL_ATTR_TZ_TEMP, temp)) 466*1ce50e7dSDaniel Lezcano return -EMSGSIZE; 467*1ce50e7dSDaniel Lezcano 468*1ce50e7dSDaniel Lezcano return 0; 469*1ce50e7dSDaniel Lezcano } 470*1ce50e7dSDaniel Lezcano 471*1ce50e7dSDaniel Lezcano static int thermal_genl_cmd_tz_get_gov(struct param *p) 472*1ce50e7dSDaniel Lezcano { 473*1ce50e7dSDaniel Lezcano struct sk_buff *msg = p->msg; 474*1ce50e7dSDaniel Lezcano struct thermal_zone_device *tz; 475*1ce50e7dSDaniel Lezcano int id, ret = 0; 476*1ce50e7dSDaniel Lezcano 477*1ce50e7dSDaniel Lezcano if (!p->attrs[THERMAL_GENL_ATTR_TZ_ID]) 478*1ce50e7dSDaniel Lezcano return -EINVAL; 479*1ce50e7dSDaniel Lezcano 480*1ce50e7dSDaniel Lezcano id = nla_get_u32(p->attrs[THERMAL_GENL_ATTR_TZ_ID]); 481*1ce50e7dSDaniel Lezcano 482*1ce50e7dSDaniel Lezcano tz = thermal_zone_get_by_id(id); 483*1ce50e7dSDaniel Lezcano if (!tz) 484*1ce50e7dSDaniel Lezcano return -EINVAL; 485*1ce50e7dSDaniel Lezcano 486*1ce50e7dSDaniel Lezcano mutex_lock(&tz->lock); 487*1ce50e7dSDaniel Lezcano 488*1ce50e7dSDaniel Lezcano if (nla_put_u32(msg, THERMAL_GENL_ATTR_TZ_ID, id) || 489*1ce50e7dSDaniel Lezcano nla_put_string(msg, THERMAL_GENL_ATTR_TZ_GOV_NAME, 490*1ce50e7dSDaniel Lezcano tz->governor->name)) 491*1ce50e7dSDaniel Lezcano ret = -EMSGSIZE; 492*1ce50e7dSDaniel Lezcano 493*1ce50e7dSDaniel Lezcano mutex_unlock(&tz->lock); 494*1ce50e7dSDaniel Lezcano 495*1ce50e7dSDaniel Lezcano return ret; 496*1ce50e7dSDaniel Lezcano } 497*1ce50e7dSDaniel Lezcano 498*1ce50e7dSDaniel Lezcano static int __thermal_genl_cmd_cdev_get(struct thermal_cooling_device *cdev, 499*1ce50e7dSDaniel Lezcano void *data) 500*1ce50e7dSDaniel Lezcano { 501*1ce50e7dSDaniel Lezcano struct sk_buff *msg = data; 502*1ce50e7dSDaniel Lezcano 503*1ce50e7dSDaniel Lezcano if (nla_put_u32(msg, THERMAL_GENL_ATTR_CDEV_ID, cdev->id)) 504*1ce50e7dSDaniel Lezcano return -EMSGSIZE; 505*1ce50e7dSDaniel Lezcano 506*1ce50e7dSDaniel Lezcano if (nla_put_string(msg, THERMAL_GENL_ATTR_CDEV_NAME, cdev->type)) 507*1ce50e7dSDaniel Lezcano return -EMSGSIZE; 508*1ce50e7dSDaniel Lezcano 509*1ce50e7dSDaniel Lezcano return 0; 510*1ce50e7dSDaniel Lezcano } 511*1ce50e7dSDaniel Lezcano 512*1ce50e7dSDaniel Lezcano static int thermal_genl_cmd_cdev_get(struct param *p) 513*1ce50e7dSDaniel Lezcano { 514*1ce50e7dSDaniel Lezcano struct sk_buff *msg = p->msg; 515*1ce50e7dSDaniel Lezcano struct nlattr *start_cdev; 516*1ce50e7dSDaniel Lezcano int ret; 517*1ce50e7dSDaniel Lezcano 518*1ce50e7dSDaniel Lezcano start_cdev = nla_nest_start(msg, THERMAL_GENL_ATTR_CDEV); 519*1ce50e7dSDaniel Lezcano if (!start_cdev) 520*1ce50e7dSDaniel Lezcano return -EMSGSIZE; 521*1ce50e7dSDaniel Lezcano 522*1ce50e7dSDaniel Lezcano ret = for_each_thermal_cooling_device(__thermal_genl_cmd_cdev_get, msg); 523*1ce50e7dSDaniel Lezcano if (ret) 524*1ce50e7dSDaniel Lezcano goto out_cancel_nest; 525*1ce50e7dSDaniel Lezcano 526*1ce50e7dSDaniel Lezcano nla_nest_end(msg, start_cdev); 527*1ce50e7dSDaniel Lezcano 528*1ce50e7dSDaniel Lezcano return 0; 529*1ce50e7dSDaniel Lezcano out_cancel_nest: 530*1ce50e7dSDaniel Lezcano nla_nest_cancel(msg, start_cdev); 531*1ce50e7dSDaniel Lezcano 532*1ce50e7dSDaniel Lezcano return ret; 533*1ce50e7dSDaniel Lezcano } 534*1ce50e7dSDaniel Lezcano 535*1ce50e7dSDaniel Lezcano static cb_t cmd_cb[] = { 536*1ce50e7dSDaniel Lezcano [THERMAL_GENL_CMD_TZ_GET_ID] = thermal_genl_cmd_tz_get_id, 537*1ce50e7dSDaniel Lezcano [THERMAL_GENL_CMD_TZ_GET_TRIP] = thermal_genl_cmd_tz_get_trip, 538*1ce50e7dSDaniel Lezcano [THERMAL_GENL_CMD_TZ_GET_TEMP] = thermal_genl_cmd_tz_get_temp, 539*1ce50e7dSDaniel Lezcano [THERMAL_GENL_CMD_TZ_GET_GOV] = thermal_genl_cmd_tz_get_gov, 540*1ce50e7dSDaniel Lezcano [THERMAL_GENL_CMD_CDEV_GET] = thermal_genl_cmd_cdev_get, 541*1ce50e7dSDaniel Lezcano }; 542*1ce50e7dSDaniel Lezcano 543*1ce50e7dSDaniel Lezcano static int thermal_genl_cmd_dumpit(struct sk_buff *skb, 544*1ce50e7dSDaniel Lezcano struct netlink_callback *cb) 545*1ce50e7dSDaniel Lezcano { 546*1ce50e7dSDaniel Lezcano struct param p = { .msg = skb }; 547*1ce50e7dSDaniel Lezcano const struct genl_dumpit_info *info = genl_dumpit_info(cb); 548*1ce50e7dSDaniel Lezcano int cmd = info->ops->cmd; 549*1ce50e7dSDaniel Lezcano int ret = -EMSGSIZE; 550*1ce50e7dSDaniel Lezcano void *hdr; 551*1ce50e7dSDaniel Lezcano 552*1ce50e7dSDaniel Lezcano hdr = genlmsg_put(skb, 0, 0, &thermal_gnl_family, 0, cmd); 553*1ce50e7dSDaniel Lezcano if (!hdr) 554*1ce50e7dSDaniel Lezcano return -EMSGSIZE; 555*1ce50e7dSDaniel Lezcano 556*1ce50e7dSDaniel Lezcano ret = cmd_cb[cmd](&p); 557*1ce50e7dSDaniel Lezcano if (ret) 558*1ce50e7dSDaniel Lezcano goto out_cancel_msg; 559*1ce50e7dSDaniel Lezcano 560*1ce50e7dSDaniel Lezcano genlmsg_end(skb, hdr); 561*1ce50e7dSDaniel Lezcano 562*1ce50e7dSDaniel Lezcano return 0; 563*1ce50e7dSDaniel Lezcano 564*1ce50e7dSDaniel Lezcano out_cancel_msg: 565*1ce50e7dSDaniel Lezcano genlmsg_cancel(skb, hdr); 566*1ce50e7dSDaniel Lezcano 567*1ce50e7dSDaniel Lezcano return ret; 568*1ce50e7dSDaniel Lezcano } 569*1ce50e7dSDaniel Lezcano 570*1ce50e7dSDaniel Lezcano static int thermal_genl_cmd_doit(struct sk_buff *skb, 571*1ce50e7dSDaniel Lezcano struct genl_info *info) 572*1ce50e7dSDaniel Lezcano { 573*1ce50e7dSDaniel Lezcano struct param p = { .attrs = info->attrs }; 574*1ce50e7dSDaniel Lezcano struct sk_buff *msg; 575*1ce50e7dSDaniel Lezcano void *hdr; 576*1ce50e7dSDaniel Lezcano int cmd = info->genlhdr->cmd; 577*1ce50e7dSDaniel Lezcano int ret = -EMSGSIZE; 578*1ce50e7dSDaniel Lezcano 579*1ce50e7dSDaniel Lezcano msg = genlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL); 580*1ce50e7dSDaniel Lezcano if (!msg) 581*1ce50e7dSDaniel Lezcano return -ENOMEM; 582*1ce50e7dSDaniel Lezcano p.msg = msg; 583*1ce50e7dSDaniel Lezcano 584*1ce50e7dSDaniel Lezcano hdr = genlmsg_put_reply(msg, info, &thermal_gnl_family, 0, cmd); 585*1ce50e7dSDaniel Lezcano if (!hdr) 586*1ce50e7dSDaniel Lezcano goto out_free_msg; 587*1ce50e7dSDaniel Lezcano 588*1ce50e7dSDaniel Lezcano ret = cmd_cb[cmd](&p); 589*1ce50e7dSDaniel Lezcano if (ret) 590*1ce50e7dSDaniel Lezcano goto out_cancel_msg; 591*1ce50e7dSDaniel Lezcano 592*1ce50e7dSDaniel Lezcano genlmsg_end(msg, hdr); 593*1ce50e7dSDaniel Lezcano 594*1ce50e7dSDaniel Lezcano return genlmsg_reply(msg, info); 595*1ce50e7dSDaniel Lezcano 596*1ce50e7dSDaniel Lezcano out_cancel_msg: 597*1ce50e7dSDaniel Lezcano genlmsg_cancel(msg, hdr); 598*1ce50e7dSDaniel Lezcano out_free_msg: 599*1ce50e7dSDaniel Lezcano nlmsg_free(msg); 600*1ce50e7dSDaniel Lezcano 601*1ce50e7dSDaniel Lezcano return ret; 602*1ce50e7dSDaniel Lezcano } 603*1ce50e7dSDaniel Lezcano 604*1ce50e7dSDaniel Lezcano static const struct genl_ops thermal_genl_ops[] = { 605*1ce50e7dSDaniel Lezcano { 606*1ce50e7dSDaniel Lezcano .cmd = THERMAL_GENL_CMD_TZ_GET_ID, 607*1ce50e7dSDaniel Lezcano .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP, 608*1ce50e7dSDaniel Lezcano .dumpit = thermal_genl_cmd_dumpit, 609*1ce50e7dSDaniel Lezcano }, 610*1ce50e7dSDaniel Lezcano { 611*1ce50e7dSDaniel Lezcano .cmd = THERMAL_GENL_CMD_TZ_GET_TRIP, 612*1ce50e7dSDaniel Lezcano .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP, 613*1ce50e7dSDaniel Lezcano .doit = thermal_genl_cmd_doit, 614*1ce50e7dSDaniel Lezcano }, 615*1ce50e7dSDaniel Lezcano { 616*1ce50e7dSDaniel Lezcano .cmd = THERMAL_GENL_CMD_TZ_GET_TEMP, 617*1ce50e7dSDaniel Lezcano .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP, 618*1ce50e7dSDaniel Lezcano .doit = thermal_genl_cmd_doit, 619*1ce50e7dSDaniel Lezcano }, 620*1ce50e7dSDaniel Lezcano { 621*1ce50e7dSDaniel Lezcano .cmd = THERMAL_GENL_CMD_TZ_GET_GOV, 622*1ce50e7dSDaniel Lezcano .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP, 623*1ce50e7dSDaniel Lezcano .doit = thermal_genl_cmd_doit, 624*1ce50e7dSDaniel Lezcano }, 625*1ce50e7dSDaniel Lezcano { 626*1ce50e7dSDaniel Lezcano .cmd = THERMAL_GENL_CMD_CDEV_GET, 627*1ce50e7dSDaniel Lezcano .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP, 628*1ce50e7dSDaniel Lezcano .dumpit = thermal_genl_cmd_dumpit, 629*1ce50e7dSDaniel Lezcano }, 630*1ce50e7dSDaniel Lezcano }; 631*1ce50e7dSDaniel Lezcano 632*1ce50e7dSDaniel Lezcano static struct genl_family thermal_gnl_family __ro_after_init = { 633*1ce50e7dSDaniel Lezcano .hdrsize = 0, 634*1ce50e7dSDaniel Lezcano .name = THERMAL_GENL_FAMILY_NAME, 635*1ce50e7dSDaniel Lezcano .version = THERMAL_GENL_VERSION, 636*1ce50e7dSDaniel Lezcano .maxattr = THERMAL_GENL_ATTR_MAX, 637*1ce50e7dSDaniel Lezcano .policy = thermal_genl_policy, 638*1ce50e7dSDaniel Lezcano .ops = thermal_genl_ops, 639*1ce50e7dSDaniel Lezcano .n_ops = ARRAY_SIZE(thermal_genl_ops), 640*1ce50e7dSDaniel Lezcano .mcgrps = thermal_genl_mcgrps, 641*1ce50e7dSDaniel Lezcano .n_mcgrps = ARRAY_SIZE(thermal_genl_mcgrps), 642*1ce50e7dSDaniel Lezcano }; 643*1ce50e7dSDaniel Lezcano 644*1ce50e7dSDaniel Lezcano static int __init thermal_netlink_init(void) 645*1ce50e7dSDaniel Lezcano { 646*1ce50e7dSDaniel Lezcano return genl_register_family(&thermal_gnl_family); 647*1ce50e7dSDaniel Lezcano } 648*1ce50e7dSDaniel Lezcano core_initcall(thermal_netlink_init); 649