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