11ce50e7dSDaniel Lezcano // SPDX-License-Identifier: GPL-2.0 21ce50e7dSDaniel Lezcano /* 31ce50e7dSDaniel Lezcano * Copyright 2020 Linaro Limited 41ce50e7dSDaniel Lezcano * 51ce50e7dSDaniel Lezcano * Author: Daniel Lezcano <daniel.lezcano@linaro.org> 61ce50e7dSDaniel Lezcano * 71ce50e7dSDaniel Lezcano * Generic netlink for thermal management framework 81ce50e7dSDaniel Lezcano */ 91ce50e7dSDaniel Lezcano #include <linux/module.h> 101ce50e7dSDaniel Lezcano #include <linux/kernel.h> 111ce50e7dSDaniel Lezcano #include <net/genetlink.h> 121ce50e7dSDaniel Lezcano #include <uapi/linux/thermal.h> 131ce50e7dSDaniel Lezcano 141ce50e7dSDaniel Lezcano #include "thermal_core.h" 151ce50e7dSDaniel Lezcano 161ce50e7dSDaniel Lezcano static const struct genl_multicast_group thermal_genl_mcgrps[] = { 171ce50e7dSDaniel Lezcano { .name = THERMAL_GENL_SAMPLING_GROUP_NAME, }, 181ce50e7dSDaniel Lezcano { .name = THERMAL_GENL_EVENT_GROUP_NAME, }, 191ce50e7dSDaniel Lezcano }; 201ce50e7dSDaniel Lezcano 211ce50e7dSDaniel Lezcano static const struct nla_policy thermal_genl_policy[THERMAL_GENL_ATTR_MAX + 1] = { 221ce50e7dSDaniel Lezcano /* Thermal zone */ 231ce50e7dSDaniel Lezcano [THERMAL_GENL_ATTR_TZ] = { .type = NLA_NESTED }, 241ce50e7dSDaniel Lezcano [THERMAL_GENL_ATTR_TZ_ID] = { .type = NLA_U32 }, 251ce50e7dSDaniel Lezcano [THERMAL_GENL_ATTR_TZ_TEMP] = { .type = NLA_U32 }, 261ce50e7dSDaniel Lezcano [THERMAL_GENL_ATTR_TZ_TRIP] = { .type = NLA_NESTED }, 271ce50e7dSDaniel Lezcano [THERMAL_GENL_ATTR_TZ_TRIP_ID] = { .type = NLA_U32 }, 281ce50e7dSDaniel Lezcano [THERMAL_GENL_ATTR_TZ_TRIP_TEMP] = { .type = NLA_U32 }, 291ce50e7dSDaniel Lezcano [THERMAL_GENL_ATTR_TZ_TRIP_TYPE] = { .type = NLA_U32 }, 301ce50e7dSDaniel Lezcano [THERMAL_GENL_ATTR_TZ_TRIP_HYST] = { .type = NLA_U32 }, 311ce50e7dSDaniel Lezcano [THERMAL_GENL_ATTR_TZ_MODE] = { .type = NLA_U32 }, 321ce50e7dSDaniel Lezcano [THERMAL_GENL_ATTR_TZ_CDEV_WEIGHT] = { .type = NLA_U32 }, 331ce50e7dSDaniel Lezcano [THERMAL_GENL_ATTR_TZ_NAME] = { .type = NLA_STRING, 341ce50e7dSDaniel Lezcano .len = THERMAL_NAME_LENGTH }, 351ce50e7dSDaniel Lezcano /* Governor(s) */ 361ce50e7dSDaniel Lezcano [THERMAL_GENL_ATTR_TZ_GOV] = { .type = NLA_NESTED }, 371ce50e7dSDaniel Lezcano [THERMAL_GENL_ATTR_TZ_GOV_NAME] = { .type = NLA_STRING, 381ce50e7dSDaniel Lezcano .len = THERMAL_NAME_LENGTH }, 391ce50e7dSDaniel Lezcano /* Cooling devices */ 401ce50e7dSDaniel Lezcano [THERMAL_GENL_ATTR_CDEV] = { .type = NLA_NESTED }, 411ce50e7dSDaniel Lezcano [THERMAL_GENL_ATTR_CDEV_ID] = { .type = NLA_U32 }, 421ce50e7dSDaniel Lezcano [THERMAL_GENL_ATTR_CDEV_CUR_STATE] = { .type = NLA_U32 }, 431ce50e7dSDaniel Lezcano [THERMAL_GENL_ATTR_CDEV_MAX_STATE] = { .type = NLA_U32 }, 441ce50e7dSDaniel Lezcano [THERMAL_GENL_ATTR_CDEV_NAME] = { .type = NLA_STRING, 451ce50e7dSDaniel Lezcano .len = THERMAL_NAME_LENGTH }, 461ce50e7dSDaniel Lezcano }; 471ce50e7dSDaniel Lezcano 481ce50e7dSDaniel Lezcano struct param { 491ce50e7dSDaniel Lezcano struct nlattr **attrs; 501ce50e7dSDaniel Lezcano struct sk_buff *msg; 511ce50e7dSDaniel Lezcano const char *name; 521ce50e7dSDaniel Lezcano int tz_id; 531ce50e7dSDaniel Lezcano int cdev_id; 541ce50e7dSDaniel Lezcano int trip_id; 551ce50e7dSDaniel Lezcano int trip_temp; 561ce50e7dSDaniel Lezcano int trip_type; 571ce50e7dSDaniel Lezcano int trip_hyst; 581ce50e7dSDaniel Lezcano int temp; 591ce50e7dSDaniel Lezcano int cdev_state; 601ce50e7dSDaniel Lezcano int cdev_max_state; 611ce50e7dSDaniel Lezcano }; 621ce50e7dSDaniel Lezcano 631ce50e7dSDaniel Lezcano typedef int (*cb_t)(struct param *); 641ce50e7dSDaniel Lezcano 651ce50e7dSDaniel Lezcano static struct genl_family thermal_gnl_family; 661ce50e7dSDaniel Lezcano 671ce50e7dSDaniel Lezcano /************************** Sampling encoding *******************************/ 681ce50e7dSDaniel Lezcano 691ce50e7dSDaniel Lezcano int thermal_genl_sampling_temp(int id, int temp) 701ce50e7dSDaniel Lezcano { 711ce50e7dSDaniel Lezcano struct sk_buff *skb; 721ce50e7dSDaniel Lezcano void *hdr; 731ce50e7dSDaniel Lezcano 741ce50e7dSDaniel Lezcano skb = genlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL); 751ce50e7dSDaniel Lezcano if (!skb) 761ce50e7dSDaniel Lezcano return -ENOMEM; 771ce50e7dSDaniel Lezcano 781ce50e7dSDaniel Lezcano hdr = genlmsg_put(skb, 0, 0, &thermal_gnl_family, 0, 791ce50e7dSDaniel Lezcano THERMAL_GENL_SAMPLING_TEMP); 801ce50e7dSDaniel Lezcano if (!hdr) 811ce50e7dSDaniel Lezcano return -EMSGSIZE; 821ce50e7dSDaniel Lezcano 831ce50e7dSDaniel Lezcano if (nla_put_u32(skb, THERMAL_GENL_ATTR_TZ_ID, id)) 841ce50e7dSDaniel Lezcano goto out_cancel; 851ce50e7dSDaniel Lezcano 861ce50e7dSDaniel Lezcano if (nla_put_u32(skb, THERMAL_GENL_ATTR_TZ_TEMP, temp)) 871ce50e7dSDaniel Lezcano goto out_cancel; 881ce50e7dSDaniel Lezcano 891ce50e7dSDaniel Lezcano genlmsg_end(skb, hdr); 901ce50e7dSDaniel Lezcano 911ce50e7dSDaniel Lezcano genlmsg_multicast(&thermal_gnl_family, skb, 0, 0, GFP_KERNEL); 921ce50e7dSDaniel Lezcano 931ce50e7dSDaniel Lezcano return 0; 941ce50e7dSDaniel Lezcano out_cancel: 951ce50e7dSDaniel Lezcano genlmsg_cancel(skb, hdr); 961ce50e7dSDaniel Lezcano nlmsg_free(skb); 971ce50e7dSDaniel Lezcano 981ce50e7dSDaniel Lezcano return -EMSGSIZE; 991ce50e7dSDaniel Lezcano } 1001ce50e7dSDaniel Lezcano 1011ce50e7dSDaniel Lezcano /**************************** Event encoding *********************************/ 1021ce50e7dSDaniel Lezcano 1031ce50e7dSDaniel Lezcano static int thermal_genl_event_tz_create(struct param *p) 1041ce50e7dSDaniel Lezcano { 1051ce50e7dSDaniel Lezcano if (nla_put_u32(p->msg, THERMAL_GENL_ATTR_TZ_ID, p->tz_id) || 1061ce50e7dSDaniel Lezcano nla_put_string(p->msg, THERMAL_GENL_ATTR_TZ_NAME, p->name)) 1071ce50e7dSDaniel Lezcano return -EMSGSIZE; 1081ce50e7dSDaniel Lezcano 1091ce50e7dSDaniel Lezcano return 0; 1101ce50e7dSDaniel Lezcano } 1111ce50e7dSDaniel Lezcano 1121ce50e7dSDaniel Lezcano static int thermal_genl_event_tz(struct param *p) 1131ce50e7dSDaniel Lezcano { 1141ce50e7dSDaniel Lezcano if (nla_put_u32(p->msg, THERMAL_GENL_ATTR_TZ_ID, p->tz_id)) 1151ce50e7dSDaniel Lezcano return -EMSGSIZE; 1161ce50e7dSDaniel Lezcano 1171ce50e7dSDaniel Lezcano return 0; 1181ce50e7dSDaniel Lezcano } 1191ce50e7dSDaniel Lezcano 1201ce50e7dSDaniel Lezcano static int thermal_genl_event_tz_trip_up(struct param *p) 1211ce50e7dSDaniel Lezcano { 1221ce50e7dSDaniel Lezcano if (nla_put_u32(p->msg, THERMAL_GENL_ATTR_TZ_ID, p->tz_id) || 1231ce50e7dSDaniel Lezcano nla_put_u32(p->msg, THERMAL_GENL_ATTR_TZ_TRIP_ID, p->trip_id)) 1241ce50e7dSDaniel Lezcano return -EMSGSIZE; 1251ce50e7dSDaniel Lezcano 1261ce50e7dSDaniel Lezcano return 0; 1271ce50e7dSDaniel Lezcano } 1281ce50e7dSDaniel Lezcano 1291ce50e7dSDaniel Lezcano static int thermal_genl_event_tz_trip_add(struct param *p) 1301ce50e7dSDaniel Lezcano { 1311ce50e7dSDaniel Lezcano if (nla_put_u32(p->msg, THERMAL_GENL_ATTR_TZ_ID, p->tz_id) || 1321ce50e7dSDaniel Lezcano nla_put_u32(p->msg, THERMAL_GENL_ATTR_TZ_TRIP_ID, p->trip_id) || 1331ce50e7dSDaniel Lezcano nla_put_u32(p->msg, THERMAL_GENL_ATTR_TZ_TRIP_TYPE, p->trip_type) || 1341ce50e7dSDaniel Lezcano nla_put_u32(p->msg, THERMAL_GENL_ATTR_TZ_TRIP_TEMP, p->trip_temp) || 1351ce50e7dSDaniel Lezcano nla_put_u32(p->msg, THERMAL_GENL_ATTR_TZ_TRIP_HYST, p->trip_hyst)) 1361ce50e7dSDaniel Lezcano return -EMSGSIZE; 1371ce50e7dSDaniel Lezcano 1381ce50e7dSDaniel Lezcano return 0; 1391ce50e7dSDaniel Lezcano } 1401ce50e7dSDaniel Lezcano 1411ce50e7dSDaniel Lezcano static int thermal_genl_event_tz_trip_delete(struct param *p) 1421ce50e7dSDaniel Lezcano { 1431ce50e7dSDaniel Lezcano if (nla_put_u32(p->msg, THERMAL_GENL_ATTR_TZ_ID, p->tz_id) || 1441ce50e7dSDaniel Lezcano nla_put_u32(p->msg, THERMAL_GENL_ATTR_TZ_TRIP_ID, p->trip_id)) 1451ce50e7dSDaniel Lezcano return -EMSGSIZE; 1461ce50e7dSDaniel Lezcano 1471ce50e7dSDaniel Lezcano return 0; 1481ce50e7dSDaniel Lezcano } 1491ce50e7dSDaniel Lezcano 1501ce50e7dSDaniel Lezcano static int thermal_genl_event_cdev_add(struct param *p) 1511ce50e7dSDaniel Lezcano { 1521ce50e7dSDaniel Lezcano if (nla_put_string(p->msg, THERMAL_GENL_ATTR_CDEV_NAME, 1531ce50e7dSDaniel Lezcano p->name) || 1541ce50e7dSDaniel Lezcano nla_put_u32(p->msg, THERMAL_GENL_ATTR_CDEV_ID, 1551ce50e7dSDaniel Lezcano p->cdev_id) || 1561ce50e7dSDaniel Lezcano nla_put_u32(p->msg, THERMAL_GENL_ATTR_CDEV_MAX_STATE, 1571ce50e7dSDaniel Lezcano p->cdev_max_state)) 1581ce50e7dSDaniel Lezcano return -EMSGSIZE; 1591ce50e7dSDaniel Lezcano 1601ce50e7dSDaniel Lezcano return 0; 1611ce50e7dSDaniel Lezcano } 1621ce50e7dSDaniel Lezcano 1631ce50e7dSDaniel Lezcano static int thermal_genl_event_cdev_delete(struct param *p) 1641ce50e7dSDaniel Lezcano { 1651ce50e7dSDaniel Lezcano if (nla_put_u32(p->msg, THERMAL_GENL_ATTR_CDEV_ID, p->cdev_id)) 1661ce50e7dSDaniel Lezcano return -EMSGSIZE; 1671ce50e7dSDaniel Lezcano 1681ce50e7dSDaniel Lezcano return 0; 1691ce50e7dSDaniel Lezcano } 1701ce50e7dSDaniel Lezcano 1711ce50e7dSDaniel Lezcano static int thermal_genl_event_cdev_state_update(struct param *p) 1721ce50e7dSDaniel Lezcano { 1731ce50e7dSDaniel Lezcano if (nla_put_u32(p->msg, THERMAL_GENL_ATTR_CDEV_ID, 1741ce50e7dSDaniel Lezcano p->cdev_id) || 1751ce50e7dSDaniel Lezcano nla_put_u32(p->msg, THERMAL_GENL_ATTR_CDEV_CUR_STATE, 1761ce50e7dSDaniel Lezcano p->cdev_state)) 1771ce50e7dSDaniel Lezcano return -EMSGSIZE; 1781ce50e7dSDaniel Lezcano 1791ce50e7dSDaniel Lezcano return 0; 1801ce50e7dSDaniel Lezcano } 1811ce50e7dSDaniel Lezcano 1821ce50e7dSDaniel Lezcano static int thermal_genl_event_gov_change(struct param *p) 1831ce50e7dSDaniel Lezcano { 1841ce50e7dSDaniel Lezcano if (nla_put_u32(p->msg, THERMAL_GENL_ATTR_TZ_ID, p->tz_id) || 1851ce50e7dSDaniel Lezcano nla_put_string(p->msg, THERMAL_GENL_ATTR_GOV_NAME, p->name)) 1861ce50e7dSDaniel Lezcano return -EMSGSIZE; 1871ce50e7dSDaniel Lezcano 1881ce50e7dSDaniel Lezcano return 0; 1891ce50e7dSDaniel Lezcano } 1901ce50e7dSDaniel Lezcano 1911ce50e7dSDaniel Lezcano int thermal_genl_event_tz_delete(struct param *p) 1921ce50e7dSDaniel Lezcano __attribute__((alias("thermal_genl_event_tz"))); 1931ce50e7dSDaniel Lezcano 1941ce50e7dSDaniel Lezcano int thermal_genl_event_tz_enable(struct param *p) 1951ce50e7dSDaniel Lezcano __attribute__((alias("thermal_genl_event_tz"))); 1961ce50e7dSDaniel Lezcano 1971ce50e7dSDaniel Lezcano int thermal_genl_event_tz_disable(struct param *p) 1981ce50e7dSDaniel Lezcano __attribute__((alias("thermal_genl_event_tz"))); 1991ce50e7dSDaniel Lezcano 2001ce50e7dSDaniel Lezcano int thermal_genl_event_tz_trip_down(struct param *p) 2011ce50e7dSDaniel Lezcano __attribute__((alias("thermal_genl_event_tz_trip_up"))); 2021ce50e7dSDaniel Lezcano 2031ce50e7dSDaniel Lezcano int thermal_genl_event_tz_trip_change(struct param *p) 2041ce50e7dSDaniel Lezcano __attribute__((alias("thermal_genl_event_tz_trip_add"))); 2051ce50e7dSDaniel Lezcano 2061ce50e7dSDaniel Lezcano static cb_t event_cb[] = { 2071ce50e7dSDaniel Lezcano [THERMAL_GENL_EVENT_TZ_CREATE] = thermal_genl_event_tz_create, 2081ce50e7dSDaniel Lezcano [THERMAL_GENL_EVENT_TZ_DELETE] = thermal_genl_event_tz_delete, 2091ce50e7dSDaniel Lezcano [THERMAL_GENL_EVENT_TZ_ENABLE] = thermal_genl_event_tz_enable, 2101ce50e7dSDaniel Lezcano [THERMAL_GENL_EVENT_TZ_DISABLE] = thermal_genl_event_tz_disable, 2111ce50e7dSDaniel Lezcano [THERMAL_GENL_EVENT_TZ_TRIP_UP] = thermal_genl_event_tz_trip_up, 2121ce50e7dSDaniel Lezcano [THERMAL_GENL_EVENT_TZ_TRIP_DOWN] = thermal_genl_event_tz_trip_down, 2131ce50e7dSDaniel Lezcano [THERMAL_GENL_EVENT_TZ_TRIP_CHANGE] = thermal_genl_event_tz_trip_change, 2141ce50e7dSDaniel Lezcano [THERMAL_GENL_EVENT_TZ_TRIP_ADD] = thermal_genl_event_tz_trip_add, 2151ce50e7dSDaniel Lezcano [THERMAL_GENL_EVENT_TZ_TRIP_DELETE] = thermal_genl_event_tz_trip_delete, 2161ce50e7dSDaniel Lezcano [THERMAL_GENL_EVENT_CDEV_ADD] = thermal_genl_event_cdev_add, 2171ce50e7dSDaniel Lezcano [THERMAL_GENL_EVENT_CDEV_DELETE] = thermal_genl_event_cdev_delete, 2181ce50e7dSDaniel Lezcano [THERMAL_GENL_EVENT_CDEV_STATE_UPDATE] = thermal_genl_event_cdev_state_update, 2191ce50e7dSDaniel Lezcano [THERMAL_GENL_EVENT_TZ_GOV_CHANGE] = thermal_genl_event_gov_change, 2201ce50e7dSDaniel Lezcano }; 2211ce50e7dSDaniel Lezcano 2221ce50e7dSDaniel Lezcano /* 2231ce50e7dSDaniel Lezcano * Generic netlink event encoding 2241ce50e7dSDaniel Lezcano */ 2251ce50e7dSDaniel Lezcano static int thermal_genl_send_event(enum thermal_genl_event event, 2261ce50e7dSDaniel Lezcano struct param *p) 2271ce50e7dSDaniel Lezcano { 2281ce50e7dSDaniel Lezcano struct sk_buff *msg; 2291ce50e7dSDaniel Lezcano int ret = -EMSGSIZE; 2301ce50e7dSDaniel Lezcano void *hdr; 2311ce50e7dSDaniel Lezcano 2321ce50e7dSDaniel Lezcano msg = genlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL); 2331ce50e7dSDaniel Lezcano if (!msg) 2341ce50e7dSDaniel Lezcano return -ENOMEM; 2351ce50e7dSDaniel Lezcano p->msg = msg; 2361ce50e7dSDaniel Lezcano 2371ce50e7dSDaniel Lezcano hdr = genlmsg_put(msg, 0, 0, &thermal_gnl_family, 0, event); 2381ce50e7dSDaniel Lezcano if (!hdr) 2391ce50e7dSDaniel Lezcano goto out_free_msg; 2401ce50e7dSDaniel Lezcano 2411ce50e7dSDaniel Lezcano ret = event_cb[event](p); 2421ce50e7dSDaniel Lezcano if (ret) 2431ce50e7dSDaniel Lezcano goto out_cancel_msg; 2441ce50e7dSDaniel Lezcano 2451ce50e7dSDaniel Lezcano genlmsg_end(msg, hdr); 2461ce50e7dSDaniel Lezcano 2471ce50e7dSDaniel Lezcano genlmsg_multicast(&thermal_gnl_family, msg, 0, 1, GFP_KERNEL); 2481ce50e7dSDaniel Lezcano 2491ce50e7dSDaniel Lezcano return 0; 2501ce50e7dSDaniel Lezcano 2511ce50e7dSDaniel Lezcano out_cancel_msg: 2521ce50e7dSDaniel Lezcano genlmsg_cancel(msg, hdr); 2531ce50e7dSDaniel Lezcano out_free_msg: 2541ce50e7dSDaniel Lezcano nlmsg_free(msg); 2551ce50e7dSDaniel Lezcano 2561ce50e7dSDaniel Lezcano return ret; 2571ce50e7dSDaniel Lezcano } 2581ce50e7dSDaniel Lezcano 2591ce50e7dSDaniel Lezcano int thermal_notify_tz_create(int tz_id, const char *name) 2601ce50e7dSDaniel Lezcano { 2611ce50e7dSDaniel Lezcano struct param p = { .tz_id = tz_id, .name = name }; 2621ce50e7dSDaniel Lezcano 2631ce50e7dSDaniel Lezcano return thermal_genl_send_event(THERMAL_GENL_EVENT_TZ_CREATE, &p); 2641ce50e7dSDaniel Lezcano } 2651ce50e7dSDaniel Lezcano 2661ce50e7dSDaniel Lezcano int thermal_notify_tz_delete(int tz_id) 2671ce50e7dSDaniel Lezcano { 2681ce50e7dSDaniel Lezcano struct param p = { .tz_id = tz_id }; 2691ce50e7dSDaniel Lezcano 2701ce50e7dSDaniel Lezcano return thermal_genl_send_event(THERMAL_GENL_EVENT_TZ_DELETE, &p); 2711ce50e7dSDaniel Lezcano } 2721ce50e7dSDaniel Lezcano 2731ce50e7dSDaniel Lezcano int thermal_notify_tz_enable(int tz_id) 2741ce50e7dSDaniel Lezcano { 2751ce50e7dSDaniel Lezcano struct param p = { .tz_id = tz_id }; 2761ce50e7dSDaniel Lezcano 2771ce50e7dSDaniel Lezcano return thermal_genl_send_event(THERMAL_GENL_EVENT_TZ_ENABLE, &p); 2781ce50e7dSDaniel Lezcano } 2791ce50e7dSDaniel Lezcano 2801ce50e7dSDaniel Lezcano int thermal_notify_tz_disable(int tz_id) 2811ce50e7dSDaniel Lezcano { 2821ce50e7dSDaniel Lezcano struct param p = { .tz_id = tz_id }; 2831ce50e7dSDaniel Lezcano 2841ce50e7dSDaniel Lezcano return thermal_genl_send_event(THERMAL_GENL_EVENT_TZ_DISABLE, &p); 2851ce50e7dSDaniel Lezcano } 2861ce50e7dSDaniel Lezcano 2871ce50e7dSDaniel Lezcano int thermal_notify_tz_trip_down(int tz_id, int trip_id) 2881ce50e7dSDaniel Lezcano { 2891ce50e7dSDaniel Lezcano struct param p = { .tz_id = tz_id, .trip_id = trip_id }; 2901ce50e7dSDaniel Lezcano 2911ce50e7dSDaniel Lezcano return thermal_genl_send_event(THERMAL_GENL_EVENT_TZ_TRIP_DOWN, &p); 2921ce50e7dSDaniel Lezcano } 2931ce50e7dSDaniel Lezcano 2941ce50e7dSDaniel Lezcano int thermal_notify_tz_trip_up(int tz_id, int trip_id) 2951ce50e7dSDaniel Lezcano { 2961ce50e7dSDaniel Lezcano struct param p = { .tz_id = tz_id, .trip_id = trip_id }; 2971ce50e7dSDaniel Lezcano 2981ce50e7dSDaniel Lezcano return thermal_genl_send_event(THERMAL_GENL_EVENT_TZ_TRIP_UP, &p); 2991ce50e7dSDaniel Lezcano } 3001ce50e7dSDaniel Lezcano 3011ce50e7dSDaniel Lezcano int thermal_notify_tz_trip_add(int tz_id, int trip_id, int trip_type, 3021ce50e7dSDaniel Lezcano int trip_temp, int trip_hyst) 3031ce50e7dSDaniel Lezcano { 3041ce50e7dSDaniel Lezcano struct param p = { .tz_id = tz_id, .trip_id = trip_id, 3051ce50e7dSDaniel Lezcano .trip_type = trip_type, .trip_temp = trip_temp, 3061ce50e7dSDaniel Lezcano .trip_hyst = trip_hyst }; 3071ce50e7dSDaniel Lezcano 3081ce50e7dSDaniel Lezcano return thermal_genl_send_event(THERMAL_GENL_EVENT_TZ_TRIP_ADD, &p); 3091ce50e7dSDaniel Lezcano } 3101ce50e7dSDaniel Lezcano 3111ce50e7dSDaniel Lezcano int thermal_notify_tz_trip_delete(int tz_id, int trip_id) 3121ce50e7dSDaniel Lezcano { 3131ce50e7dSDaniel Lezcano struct param p = { .tz_id = tz_id, .trip_id = trip_id }; 3141ce50e7dSDaniel Lezcano 3151ce50e7dSDaniel Lezcano return thermal_genl_send_event(THERMAL_GENL_EVENT_TZ_TRIP_DELETE, &p); 3161ce50e7dSDaniel Lezcano } 3171ce50e7dSDaniel Lezcano 3181ce50e7dSDaniel Lezcano int thermal_notify_tz_trip_change(int tz_id, int trip_id, int trip_type, 3191ce50e7dSDaniel Lezcano int trip_temp, int trip_hyst) 3201ce50e7dSDaniel Lezcano { 3211ce50e7dSDaniel Lezcano struct param p = { .tz_id = tz_id, .trip_id = trip_id, 3221ce50e7dSDaniel Lezcano .trip_type = trip_type, .trip_temp = trip_temp, 3231ce50e7dSDaniel Lezcano .trip_hyst = trip_hyst }; 3241ce50e7dSDaniel Lezcano 3251ce50e7dSDaniel Lezcano return thermal_genl_send_event(THERMAL_GENL_EVENT_TZ_TRIP_CHANGE, &p); 3261ce50e7dSDaniel Lezcano } 3271ce50e7dSDaniel Lezcano 3281ce50e7dSDaniel Lezcano int thermal_notify_cdev_state_update(int cdev_id, int cdev_state) 3291ce50e7dSDaniel Lezcano { 3301ce50e7dSDaniel Lezcano struct param p = { .cdev_id = cdev_id, .cdev_state = cdev_state }; 3311ce50e7dSDaniel Lezcano 3321ce50e7dSDaniel Lezcano return thermal_genl_send_event(THERMAL_GENL_EVENT_CDEV_STATE_UPDATE, &p); 3331ce50e7dSDaniel Lezcano } 3341ce50e7dSDaniel Lezcano 3351ce50e7dSDaniel Lezcano int thermal_notify_cdev_add(int cdev_id, const char *name, int cdev_max_state) 3361ce50e7dSDaniel Lezcano { 3371ce50e7dSDaniel Lezcano struct param p = { .cdev_id = cdev_id, .name = name, 3381ce50e7dSDaniel Lezcano .cdev_max_state = cdev_max_state }; 3391ce50e7dSDaniel Lezcano 3401ce50e7dSDaniel Lezcano return thermal_genl_send_event(THERMAL_GENL_EVENT_CDEV_ADD, &p); 3411ce50e7dSDaniel Lezcano } 3421ce50e7dSDaniel Lezcano 3431ce50e7dSDaniel Lezcano int thermal_notify_cdev_delete(int cdev_id) 3441ce50e7dSDaniel Lezcano { 3451ce50e7dSDaniel Lezcano struct param p = { .cdev_id = cdev_id }; 3461ce50e7dSDaniel Lezcano 3471ce50e7dSDaniel Lezcano return thermal_genl_send_event(THERMAL_GENL_EVENT_CDEV_DELETE, &p); 3481ce50e7dSDaniel Lezcano } 3491ce50e7dSDaniel Lezcano 3501ce50e7dSDaniel Lezcano int thermal_notify_tz_gov_change(int tz_id, const char *name) 3511ce50e7dSDaniel Lezcano { 3521ce50e7dSDaniel Lezcano struct param p = { .tz_id = tz_id, .name = name }; 3531ce50e7dSDaniel Lezcano 3541ce50e7dSDaniel Lezcano return thermal_genl_send_event(THERMAL_GENL_EVENT_TZ_GOV_CHANGE, &p); 3551ce50e7dSDaniel Lezcano } 3561ce50e7dSDaniel Lezcano 3571ce50e7dSDaniel Lezcano /*************************** Command encoding ********************************/ 3581ce50e7dSDaniel Lezcano 3591ce50e7dSDaniel Lezcano static int __thermal_genl_cmd_tz_get_id(struct thermal_zone_device *tz, 3601ce50e7dSDaniel Lezcano void *data) 3611ce50e7dSDaniel Lezcano { 3621ce50e7dSDaniel Lezcano struct sk_buff *msg = data; 3631ce50e7dSDaniel Lezcano 3641ce50e7dSDaniel Lezcano if (nla_put_u32(msg, THERMAL_GENL_ATTR_TZ_ID, tz->id) || 3651ce50e7dSDaniel Lezcano nla_put_string(msg, THERMAL_GENL_ATTR_TZ_NAME, tz->type)) 3661ce50e7dSDaniel Lezcano return -EMSGSIZE; 3671ce50e7dSDaniel Lezcano 3681ce50e7dSDaniel Lezcano return 0; 3691ce50e7dSDaniel Lezcano } 3701ce50e7dSDaniel Lezcano 3711ce50e7dSDaniel Lezcano static int thermal_genl_cmd_tz_get_id(struct param *p) 3721ce50e7dSDaniel Lezcano { 3731ce50e7dSDaniel Lezcano struct sk_buff *msg = p->msg; 3741ce50e7dSDaniel Lezcano struct nlattr *start_tz; 3751ce50e7dSDaniel Lezcano int ret; 3761ce50e7dSDaniel Lezcano 3771ce50e7dSDaniel Lezcano start_tz = nla_nest_start(msg, THERMAL_GENL_ATTR_TZ); 3781ce50e7dSDaniel Lezcano if (!start_tz) 3791ce50e7dSDaniel Lezcano return -EMSGSIZE; 3801ce50e7dSDaniel Lezcano 3811ce50e7dSDaniel Lezcano ret = for_each_thermal_zone(__thermal_genl_cmd_tz_get_id, msg); 3821ce50e7dSDaniel Lezcano if (ret) 3831ce50e7dSDaniel Lezcano goto out_cancel_nest; 3841ce50e7dSDaniel Lezcano 3851ce50e7dSDaniel Lezcano nla_nest_end(msg, start_tz); 3861ce50e7dSDaniel Lezcano 3871ce50e7dSDaniel Lezcano return 0; 3881ce50e7dSDaniel Lezcano 3891ce50e7dSDaniel Lezcano out_cancel_nest: 3901ce50e7dSDaniel Lezcano nla_nest_cancel(msg, start_tz); 3911ce50e7dSDaniel Lezcano 3921ce50e7dSDaniel Lezcano return ret; 3931ce50e7dSDaniel Lezcano } 3941ce50e7dSDaniel Lezcano 3951ce50e7dSDaniel Lezcano static int thermal_genl_cmd_tz_get_trip(struct param *p) 3961ce50e7dSDaniel Lezcano { 3971ce50e7dSDaniel Lezcano struct sk_buff *msg = p->msg; 3981ce50e7dSDaniel Lezcano struct thermal_zone_device *tz; 3991ce50e7dSDaniel Lezcano struct nlattr *start_trip; 4001ce50e7dSDaniel Lezcano int i, id; 4011ce50e7dSDaniel Lezcano 4021ce50e7dSDaniel Lezcano if (!p->attrs[THERMAL_GENL_ATTR_TZ_ID]) 4031ce50e7dSDaniel Lezcano return -EINVAL; 4041ce50e7dSDaniel Lezcano 4051ce50e7dSDaniel Lezcano id = nla_get_u32(p->attrs[THERMAL_GENL_ATTR_TZ_ID]); 4061ce50e7dSDaniel Lezcano 4071ce50e7dSDaniel Lezcano tz = thermal_zone_get_by_id(id); 4081ce50e7dSDaniel Lezcano if (!tz) 4091ce50e7dSDaniel Lezcano return -EINVAL; 4101ce50e7dSDaniel Lezcano 4111ce50e7dSDaniel Lezcano start_trip = nla_nest_start(msg, THERMAL_GENL_ATTR_TZ_TRIP); 4121ce50e7dSDaniel Lezcano if (!start_trip) 4131ce50e7dSDaniel Lezcano return -EMSGSIZE; 4141ce50e7dSDaniel Lezcano 4151ce50e7dSDaniel Lezcano mutex_lock(&tz->lock); 4161ce50e7dSDaniel Lezcano 4171ce50e7dSDaniel Lezcano for (i = 0; i < tz->trips; i++) { 4181ce50e7dSDaniel Lezcano 4191ce50e7dSDaniel Lezcano enum thermal_trip_type type; 4201ce50e7dSDaniel Lezcano int temp, hyst; 4211ce50e7dSDaniel Lezcano 4221ce50e7dSDaniel Lezcano tz->ops->get_trip_type(tz, i, &type); 4231ce50e7dSDaniel Lezcano tz->ops->get_trip_temp(tz, i, &temp); 4241ce50e7dSDaniel Lezcano tz->ops->get_trip_hyst(tz, i, &hyst); 4251ce50e7dSDaniel Lezcano 4261ce50e7dSDaniel Lezcano if (nla_put_u32(msg, THERMAL_GENL_ATTR_TZ_TRIP_ID, i) || 4271ce50e7dSDaniel Lezcano nla_put_u32(msg, THERMAL_GENL_ATTR_TZ_TRIP_TYPE, type) || 4281ce50e7dSDaniel Lezcano nla_put_u32(msg, THERMAL_GENL_ATTR_TZ_TRIP_TEMP, temp) || 4291ce50e7dSDaniel Lezcano nla_put_u32(msg, THERMAL_GENL_ATTR_TZ_TRIP_HYST, hyst)) 4301ce50e7dSDaniel Lezcano goto out_cancel_nest; 4311ce50e7dSDaniel Lezcano } 4321ce50e7dSDaniel Lezcano 4331ce50e7dSDaniel Lezcano mutex_unlock(&tz->lock); 4341ce50e7dSDaniel Lezcano 4351ce50e7dSDaniel Lezcano nla_nest_end(msg, start_trip); 4361ce50e7dSDaniel Lezcano 4371ce50e7dSDaniel Lezcano return 0; 4381ce50e7dSDaniel Lezcano 4391ce50e7dSDaniel Lezcano out_cancel_nest: 4401ce50e7dSDaniel Lezcano mutex_unlock(&tz->lock); 4411ce50e7dSDaniel Lezcano 4421ce50e7dSDaniel Lezcano return -EMSGSIZE; 4431ce50e7dSDaniel Lezcano } 4441ce50e7dSDaniel Lezcano 4451ce50e7dSDaniel Lezcano static int thermal_genl_cmd_tz_get_temp(struct param *p) 4461ce50e7dSDaniel Lezcano { 4471ce50e7dSDaniel Lezcano struct sk_buff *msg = p->msg; 4481ce50e7dSDaniel Lezcano struct thermal_zone_device *tz; 4491ce50e7dSDaniel Lezcano int temp, ret, id; 4501ce50e7dSDaniel Lezcano 4511ce50e7dSDaniel Lezcano if (!p->attrs[THERMAL_GENL_ATTR_TZ_ID]) 4521ce50e7dSDaniel Lezcano return -EINVAL; 4531ce50e7dSDaniel Lezcano 4541ce50e7dSDaniel Lezcano id = nla_get_u32(p->attrs[THERMAL_GENL_ATTR_TZ_ID]); 4551ce50e7dSDaniel Lezcano 4561ce50e7dSDaniel Lezcano tz = thermal_zone_get_by_id(id); 4571ce50e7dSDaniel Lezcano if (!tz) 4581ce50e7dSDaniel Lezcano return -EINVAL; 4591ce50e7dSDaniel Lezcano 4601ce50e7dSDaniel Lezcano ret = thermal_zone_get_temp(tz, &temp); 4611ce50e7dSDaniel Lezcano if (ret) 4621ce50e7dSDaniel Lezcano return ret; 4631ce50e7dSDaniel Lezcano 4641ce50e7dSDaniel Lezcano if (nla_put_u32(msg, THERMAL_GENL_ATTR_TZ_ID, id) || 4651ce50e7dSDaniel Lezcano nla_put_u32(msg, THERMAL_GENL_ATTR_TZ_TEMP, temp)) 4661ce50e7dSDaniel Lezcano return -EMSGSIZE; 4671ce50e7dSDaniel Lezcano 4681ce50e7dSDaniel Lezcano return 0; 4691ce50e7dSDaniel Lezcano } 4701ce50e7dSDaniel Lezcano 4711ce50e7dSDaniel Lezcano static int thermal_genl_cmd_tz_get_gov(struct param *p) 4721ce50e7dSDaniel Lezcano { 4731ce50e7dSDaniel Lezcano struct sk_buff *msg = p->msg; 4741ce50e7dSDaniel Lezcano struct thermal_zone_device *tz; 4751ce50e7dSDaniel Lezcano int id, ret = 0; 4761ce50e7dSDaniel Lezcano 4771ce50e7dSDaniel Lezcano if (!p->attrs[THERMAL_GENL_ATTR_TZ_ID]) 4781ce50e7dSDaniel Lezcano return -EINVAL; 4791ce50e7dSDaniel Lezcano 4801ce50e7dSDaniel Lezcano id = nla_get_u32(p->attrs[THERMAL_GENL_ATTR_TZ_ID]); 4811ce50e7dSDaniel Lezcano 4821ce50e7dSDaniel Lezcano tz = thermal_zone_get_by_id(id); 4831ce50e7dSDaniel Lezcano if (!tz) 4841ce50e7dSDaniel Lezcano return -EINVAL; 4851ce50e7dSDaniel Lezcano 4861ce50e7dSDaniel Lezcano mutex_lock(&tz->lock); 4871ce50e7dSDaniel Lezcano 4881ce50e7dSDaniel Lezcano if (nla_put_u32(msg, THERMAL_GENL_ATTR_TZ_ID, id) || 4891ce50e7dSDaniel Lezcano nla_put_string(msg, THERMAL_GENL_ATTR_TZ_GOV_NAME, 4901ce50e7dSDaniel Lezcano tz->governor->name)) 4911ce50e7dSDaniel Lezcano ret = -EMSGSIZE; 4921ce50e7dSDaniel Lezcano 4931ce50e7dSDaniel Lezcano mutex_unlock(&tz->lock); 4941ce50e7dSDaniel Lezcano 4951ce50e7dSDaniel Lezcano return ret; 4961ce50e7dSDaniel Lezcano } 4971ce50e7dSDaniel Lezcano 4981ce50e7dSDaniel Lezcano static int __thermal_genl_cmd_cdev_get(struct thermal_cooling_device *cdev, 4991ce50e7dSDaniel Lezcano void *data) 5001ce50e7dSDaniel Lezcano { 5011ce50e7dSDaniel Lezcano struct sk_buff *msg = data; 5021ce50e7dSDaniel Lezcano 5031ce50e7dSDaniel Lezcano if (nla_put_u32(msg, THERMAL_GENL_ATTR_CDEV_ID, cdev->id)) 5041ce50e7dSDaniel Lezcano return -EMSGSIZE; 5051ce50e7dSDaniel Lezcano 5061ce50e7dSDaniel Lezcano if (nla_put_string(msg, THERMAL_GENL_ATTR_CDEV_NAME, cdev->type)) 5071ce50e7dSDaniel Lezcano return -EMSGSIZE; 5081ce50e7dSDaniel Lezcano 5091ce50e7dSDaniel Lezcano return 0; 5101ce50e7dSDaniel Lezcano } 5111ce50e7dSDaniel Lezcano 5121ce50e7dSDaniel Lezcano static int thermal_genl_cmd_cdev_get(struct param *p) 5131ce50e7dSDaniel Lezcano { 5141ce50e7dSDaniel Lezcano struct sk_buff *msg = p->msg; 5151ce50e7dSDaniel Lezcano struct nlattr *start_cdev; 5161ce50e7dSDaniel Lezcano int ret; 5171ce50e7dSDaniel Lezcano 5181ce50e7dSDaniel Lezcano start_cdev = nla_nest_start(msg, THERMAL_GENL_ATTR_CDEV); 5191ce50e7dSDaniel Lezcano if (!start_cdev) 5201ce50e7dSDaniel Lezcano return -EMSGSIZE; 5211ce50e7dSDaniel Lezcano 5221ce50e7dSDaniel Lezcano ret = for_each_thermal_cooling_device(__thermal_genl_cmd_cdev_get, msg); 5231ce50e7dSDaniel Lezcano if (ret) 5241ce50e7dSDaniel Lezcano goto out_cancel_nest; 5251ce50e7dSDaniel Lezcano 5261ce50e7dSDaniel Lezcano nla_nest_end(msg, start_cdev); 5271ce50e7dSDaniel Lezcano 5281ce50e7dSDaniel Lezcano return 0; 5291ce50e7dSDaniel Lezcano out_cancel_nest: 5301ce50e7dSDaniel Lezcano nla_nest_cancel(msg, start_cdev); 5311ce50e7dSDaniel Lezcano 5321ce50e7dSDaniel Lezcano return ret; 5331ce50e7dSDaniel Lezcano } 5341ce50e7dSDaniel Lezcano 5351ce50e7dSDaniel Lezcano static cb_t cmd_cb[] = { 5361ce50e7dSDaniel Lezcano [THERMAL_GENL_CMD_TZ_GET_ID] = thermal_genl_cmd_tz_get_id, 5371ce50e7dSDaniel Lezcano [THERMAL_GENL_CMD_TZ_GET_TRIP] = thermal_genl_cmd_tz_get_trip, 5381ce50e7dSDaniel Lezcano [THERMAL_GENL_CMD_TZ_GET_TEMP] = thermal_genl_cmd_tz_get_temp, 5391ce50e7dSDaniel Lezcano [THERMAL_GENL_CMD_TZ_GET_GOV] = thermal_genl_cmd_tz_get_gov, 5401ce50e7dSDaniel Lezcano [THERMAL_GENL_CMD_CDEV_GET] = thermal_genl_cmd_cdev_get, 5411ce50e7dSDaniel Lezcano }; 5421ce50e7dSDaniel Lezcano 5431ce50e7dSDaniel Lezcano static int thermal_genl_cmd_dumpit(struct sk_buff *skb, 5441ce50e7dSDaniel Lezcano struct netlink_callback *cb) 5451ce50e7dSDaniel Lezcano { 5461ce50e7dSDaniel Lezcano struct param p = { .msg = skb }; 5471ce50e7dSDaniel Lezcano const struct genl_dumpit_info *info = genl_dumpit_info(cb); 5480b588afdSJakub Kicinski int cmd = info->op.cmd; 54952674f56SColin Ian King int ret; 5501ce50e7dSDaniel Lezcano void *hdr; 5511ce50e7dSDaniel Lezcano 5521ce50e7dSDaniel Lezcano hdr = genlmsg_put(skb, 0, 0, &thermal_gnl_family, 0, cmd); 5531ce50e7dSDaniel Lezcano if (!hdr) 5541ce50e7dSDaniel Lezcano return -EMSGSIZE; 5551ce50e7dSDaniel Lezcano 5561ce50e7dSDaniel Lezcano ret = cmd_cb[cmd](&p); 5571ce50e7dSDaniel Lezcano if (ret) 5581ce50e7dSDaniel Lezcano goto out_cancel_msg; 5591ce50e7dSDaniel Lezcano 5601ce50e7dSDaniel Lezcano genlmsg_end(skb, hdr); 5611ce50e7dSDaniel Lezcano 5621ce50e7dSDaniel Lezcano return 0; 5631ce50e7dSDaniel Lezcano 5641ce50e7dSDaniel Lezcano out_cancel_msg: 5651ce50e7dSDaniel Lezcano genlmsg_cancel(skb, hdr); 5661ce50e7dSDaniel Lezcano 5671ce50e7dSDaniel Lezcano return ret; 5681ce50e7dSDaniel Lezcano } 5691ce50e7dSDaniel Lezcano 5701ce50e7dSDaniel Lezcano static int thermal_genl_cmd_doit(struct sk_buff *skb, 5711ce50e7dSDaniel Lezcano struct genl_info *info) 5721ce50e7dSDaniel Lezcano { 5731ce50e7dSDaniel Lezcano struct param p = { .attrs = info->attrs }; 5741ce50e7dSDaniel Lezcano struct sk_buff *msg; 5751ce50e7dSDaniel Lezcano void *hdr; 5761ce50e7dSDaniel Lezcano int cmd = info->genlhdr->cmd; 5771ce50e7dSDaniel Lezcano int ret = -EMSGSIZE; 5781ce50e7dSDaniel Lezcano 5791ce50e7dSDaniel Lezcano msg = genlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL); 5801ce50e7dSDaniel Lezcano if (!msg) 5811ce50e7dSDaniel Lezcano return -ENOMEM; 5821ce50e7dSDaniel Lezcano p.msg = msg; 5831ce50e7dSDaniel Lezcano 5841ce50e7dSDaniel Lezcano hdr = genlmsg_put_reply(msg, info, &thermal_gnl_family, 0, cmd); 5851ce50e7dSDaniel Lezcano if (!hdr) 5861ce50e7dSDaniel Lezcano goto out_free_msg; 5871ce50e7dSDaniel Lezcano 5881ce50e7dSDaniel Lezcano ret = cmd_cb[cmd](&p); 5891ce50e7dSDaniel Lezcano if (ret) 5901ce50e7dSDaniel Lezcano goto out_cancel_msg; 5911ce50e7dSDaniel Lezcano 5921ce50e7dSDaniel Lezcano genlmsg_end(msg, hdr); 5931ce50e7dSDaniel Lezcano 5941ce50e7dSDaniel Lezcano return genlmsg_reply(msg, info); 5951ce50e7dSDaniel Lezcano 5961ce50e7dSDaniel Lezcano out_cancel_msg: 5971ce50e7dSDaniel Lezcano genlmsg_cancel(msg, hdr); 5981ce50e7dSDaniel Lezcano out_free_msg: 5991ce50e7dSDaniel Lezcano nlmsg_free(msg); 6001ce50e7dSDaniel Lezcano 6011ce50e7dSDaniel Lezcano return ret; 6021ce50e7dSDaniel Lezcano } 6031ce50e7dSDaniel Lezcano 604*66a9b928SJakub Kicinski static const struct genl_small_ops thermal_genl_ops[] = { 6051ce50e7dSDaniel Lezcano { 6061ce50e7dSDaniel Lezcano .cmd = THERMAL_GENL_CMD_TZ_GET_ID, 6071ce50e7dSDaniel Lezcano .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP, 6081ce50e7dSDaniel Lezcano .dumpit = thermal_genl_cmd_dumpit, 6091ce50e7dSDaniel Lezcano }, 6101ce50e7dSDaniel Lezcano { 6111ce50e7dSDaniel Lezcano .cmd = THERMAL_GENL_CMD_TZ_GET_TRIP, 6121ce50e7dSDaniel Lezcano .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP, 6131ce50e7dSDaniel Lezcano .doit = thermal_genl_cmd_doit, 6141ce50e7dSDaniel Lezcano }, 6151ce50e7dSDaniel Lezcano { 6161ce50e7dSDaniel Lezcano .cmd = THERMAL_GENL_CMD_TZ_GET_TEMP, 6171ce50e7dSDaniel Lezcano .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP, 6181ce50e7dSDaniel Lezcano .doit = thermal_genl_cmd_doit, 6191ce50e7dSDaniel Lezcano }, 6201ce50e7dSDaniel Lezcano { 6211ce50e7dSDaniel Lezcano .cmd = THERMAL_GENL_CMD_TZ_GET_GOV, 6221ce50e7dSDaniel Lezcano .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP, 6231ce50e7dSDaniel Lezcano .doit = thermal_genl_cmd_doit, 6241ce50e7dSDaniel Lezcano }, 6251ce50e7dSDaniel Lezcano { 6261ce50e7dSDaniel Lezcano .cmd = THERMAL_GENL_CMD_CDEV_GET, 6271ce50e7dSDaniel Lezcano .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP, 6281ce50e7dSDaniel Lezcano .dumpit = thermal_genl_cmd_dumpit, 6291ce50e7dSDaniel Lezcano }, 6301ce50e7dSDaniel Lezcano }; 6311ce50e7dSDaniel Lezcano 6321ce50e7dSDaniel Lezcano static struct genl_family thermal_gnl_family __ro_after_init = { 6331ce50e7dSDaniel Lezcano .hdrsize = 0, 6341ce50e7dSDaniel Lezcano .name = THERMAL_GENL_FAMILY_NAME, 6351ce50e7dSDaniel Lezcano .version = THERMAL_GENL_VERSION, 6361ce50e7dSDaniel Lezcano .maxattr = THERMAL_GENL_ATTR_MAX, 6371ce50e7dSDaniel Lezcano .policy = thermal_genl_policy, 638*66a9b928SJakub Kicinski .small_ops = thermal_genl_ops, 639*66a9b928SJakub Kicinski .n_small_ops = ARRAY_SIZE(thermal_genl_ops), 6401ce50e7dSDaniel Lezcano .mcgrps = thermal_genl_mcgrps, 6411ce50e7dSDaniel Lezcano .n_mcgrps = ARRAY_SIZE(thermal_genl_mcgrps), 6421ce50e7dSDaniel Lezcano }; 6431ce50e7dSDaniel Lezcano 644d2a89b52SDaniel Lezcano int __init thermal_netlink_init(void) 6451ce50e7dSDaniel Lezcano { 6461ce50e7dSDaniel Lezcano return genl_register_family(&thermal_gnl_family); 6471ce50e7dSDaniel Lezcano } 648