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/notifier.h> 11 #include <linux/kernel.h> 12 #include <net/sock.h> 13 #include <net/genetlink.h> 14 #include <uapi/linux/thermal.h> 15 16 #include "thermal_core.h" 17 18 static const struct genl_multicast_group thermal_genl_mcgrps[] = { 19 [THERMAL_GENL_SAMPLING_GROUP] = { .name = THERMAL_GENL_SAMPLING_GROUP_NAME, }, 20 [THERMAL_GENL_EVENT_GROUP] = { .name = THERMAL_GENL_EVENT_GROUP_NAME, }, 21 }; 22 23 static const struct nla_policy thermal_genl_policy[THERMAL_GENL_ATTR_MAX + 1] = { 24 /* Thermal zone */ 25 [THERMAL_GENL_ATTR_TZ] = { .type = NLA_NESTED }, 26 [THERMAL_GENL_ATTR_TZ_ID] = { .type = NLA_U32 }, 27 [THERMAL_GENL_ATTR_TZ_TEMP] = { .type = NLA_U32 }, 28 [THERMAL_GENL_ATTR_TZ_TRIP] = { .type = NLA_NESTED }, 29 [THERMAL_GENL_ATTR_TZ_TRIP_ID] = { .type = NLA_U32 }, 30 [THERMAL_GENL_ATTR_TZ_TRIP_TEMP] = { .type = NLA_U32 }, 31 [THERMAL_GENL_ATTR_TZ_TRIP_TYPE] = { .type = NLA_U32 }, 32 [THERMAL_GENL_ATTR_TZ_TRIP_HYST] = { .type = NLA_U32 }, 33 [THERMAL_GENL_ATTR_TZ_MODE] = { .type = NLA_U32 }, 34 [THERMAL_GENL_ATTR_TZ_CDEV_WEIGHT] = { .type = NLA_U32 }, 35 [THERMAL_GENL_ATTR_TZ_NAME] = { .type = NLA_STRING, 36 .len = THERMAL_NAME_LENGTH }, 37 /* Governor(s) */ 38 [THERMAL_GENL_ATTR_TZ_GOV] = { .type = NLA_NESTED }, 39 [THERMAL_GENL_ATTR_TZ_GOV_NAME] = { .type = NLA_STRING, 40 .len = THERMAL_NAME_LENGTH }, 41 /* Cooling devices */ 42 [THERMAL_GENL_ATTR_CDEV] = { .type = NLA_NESTED }, 43 [THERMAL_GENL_ATTR_CDEV_ID] = { .type = NLA_U32 }, 44 [THERMAL_GENL_ATTR_CDEV_CUR_STATE] = { .type = NLA_U32 }, 45 [THERMAL_GENL_ATTR_CDEV_MAX_STATE] = { .type = NLA_U32 }, 46 [THERMAL_GENL_ATTR_CDEV_NAME] = { .type = NLA_STRING, 47 .len = THERMAL_NAME_LENGTH }, 48 /* CPU capabilities */ 49 [THERMAL_GENL_ATTR_CPU_CAPABILITY] = { .type = NLA_NESTED }, 50 [THERMAL_GENL_ATTR_CPU_CAPABILITY_ID] = { .type = NLA_U32 }, 51 [THERMAL_GENL_ATTR_CPU_CAPABILITY_PERFORMANCE] = { .type = NLA_U32 }, 52 [THERMAL_GENL_ATTR_CPU_CAPABILITY_EFFICIENCY] = { .type = NLA_U32 }, 53 54 /* Thresholds */ 55 [THERMAL_GENL_ATTR_THRESHOLD] = { .type = NLA_NESTED }, 56 [THERMAL_GENL_ATTR_THRESHOLD_TEMP] = { .type = NLA_U32 }, 57 [THERMAL_GENL_ATTR_THRESHOLD_DIRECTION] = { .type = NLA_U32 }, 58 }; 59 60 struct param { 61 struct nlattr **attrs; 62 struct sk_buff *msg; 63 const char *name; 64 int tz_id; 65 int cdev_id; 66 int trip_id; 67 int trip_temp; 68 int trip_type; 69 int trip_hyst; 70 int temp; 71 int prev_temp; 72 int direction; 73 int cdev_state; 74 int cdev_max_state; 75 struct thermal_genl_cpu_caps *cpu_capabilities; 76 int cpu_capabilities_count; 77 }; 78 79 typedef int (*cb_t)(struct param *); 80 81 static struct genl_family thermal_genl_family; 82 static BLOCKING_NOTIFIER_HEAD(thermal_genl_chain); 83 84 static int thermal_group_has_listeners(enum thermal_genl_multicast_groups group) 85 { 86 return genl_has_listeners(&thermal_genl_family, &init_net, group); 87 } 88 89 /************************** Sampling encoding *******************************/ 90 91 int thermal_genl_sampling_temp(int id, int temp) 92 { 93 struct sk_buff *skb; 94 void *hdr; 95 96 if (!thermal_group_has_listeners(THERMAL_GENL_SAMPLING_GROUP)) 97 return 0; 98 99 skb = genlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL); 100 if (!skb) 101 return -ENOMEM; 102 103 hdr = genlmsg_put(skb, 0, 0, &thermal_genl_family, 0, 104 THERMAL_GENL_SAMPLING_TEMP); 105 if (!hdr) 106 goto out_free; 107 108 if (nla_put_u32(skb, THERMAL_GENL_ATTR_TZ_ID, id)) 109 goto out_cancel; 110 111 if (nla_put_u32(skb, THERMAL_GENL_ATTR_TZ_TEMP, temp)) 112 goto out_cancel; 113 114 genlmsg_end(skb, hdr); 115 116 genlmsg_multicast(&thermal_genl_family, skb, 0, THERMAL_GENL_SAMPLING_GROUP, GFP_KERNEL); 117 118 return 0; 119 out_cancel: 120 genlmsg_cancel(skb, hdr); 121 out_free: 122 nlmsg_free(skb); 123 124 return -EMSGSIZE; 125 } 126 127 /**************************** Event encoding *********************************/ 128 129 static int thermal_genl_event_tz_create(struct param *p) 130 { 131 if (nla_put_u32(p->msg, THERMAL_GENL_ATTR_TZ_ID, p->tz_id) || 132 nla_put_string(p->msg, THERMAL_GENL_ATTR_TZ_NAME, p->name)) 133 return -EMSGSIZE; 134 135 return 0; 136 } 137 138 static int thermal_genl_event_tz(struct param *p) 139 { 140 if (nla_put_u32(p->msg, THERMAL_GENL_ATTR_TZ_ID, p->tz_id)) 141 return -EMSGSIZE; 142 143 return 0; 144 } 145 146 static int thermal_genl_event_tz_trip_up(struct param *p) 147 { 148 if (nla_put_u32(p->msg, THERMAL_GENL_ATTR_TZ_ID, p->tz_id) || 149 nla_put_u32(p->msg, THERMAL_GENL_ATTR_TZ_TRIP_ID, p->trip_id) || 150 nla_put_u32(p->msg, THERMAL_GENL_ATTR_TZ_TEMP, p->temp)) 151 return -EMSGSIZE; 152 153 return 0; 154 } 155 156 static int thermal_genl_event_tz_trip_change(struct param *p) 157 { 158 if (nla_put_u32(p->msg, THERMAL_GENL_ATTR_TZ_ID, p->tz_id) || 159 nla_put_u32(p->msg, THERMAL_GENL_ATTR_TZ_TRIP_ID, p->trip_id) || 160 nla_put_u32(p->msg, THERMAL_GENL_ATTR_TZ_TRIP_TYPE, p->trip_type) || 161 nla_put_u32(p->msg, THERMAL_GENL_ATTR_TZ_TRIP_TEMP, p->trip_temp) || 162 nla_put_u32(p->msg, THERMAL_GENL_ATTR_TZ_TRIP_HYST, p->trip_hyst)) 163 return -EMSGSIZE; 164 165 return 0; 166 } 167 168 static int thermal_genl_event_cdev_add(struct param *p) 169 { 170 if (nla_put_string(p->msg, THERMAL_GENL_ATTR_CDEV_NAME, 171 p->name) || 172 nla_put_u32(p->msg, THERMAL_GENL_ATTR_CDEV_ID, 173 p->cdev_id) || 174 nla_put_u32(p->msg, THERMAL_GENL_ATTR_CDEV_MAX_STATE, 175 p->cdev_max_state)) 176 return -EMSGSIZE; 177 178 return 0; 179 } 180 181 static int thermal_genl_event_cdev_delete(struct param *p) 182 { 183 if (nla_put_u32(p->msg, THERMAL_GENL_ATTR_CDEV_ID, p->cdev_id)) 184 return -EMSGSIZE; 185 186 return 0; 187 } 188 189 static int thermal_genl_event_cdev_state_update(struct param *p) 190 { 191 if (nla_put_u32(p->msg, THERMAL_GENL_ATTR_CDEV_ID, 192 p->cdev_id) || 193 nla_put_u32(p->msg, THERMAL_GENL_ATTR_CDEV_CUR_STATE, 194 p->cdev_state)) 195 return -EMSGSIZE; 196 197 return 0; 198 } 199 200 static int thermal_genl_event_gov_change(struct param *p) 201 { 202 if (nla_put_u32(p->msg, THERMAL_GENL_ATTR_TZ_ID, p->tz_id) || 203 nla_put_string(p->msg, THERMAL_GENL_ATTR_GOV_NAME, p->name)) 204 return -EMSGSIZE; 205 206 return 0; 207 } 208 209 static int thermal_genl_event_cpu_capability_change(struct param *p) 210 { 211 struct thermal_genl_cpu_caps *cpu_cap = p->cpu_capabilities; 212 struct sk_buff *msg = p->msg; 213 struct nlattr *start_cap; 214 int i; 215 216 start_cap = nla_nest_start(msg, THERMAL_GENL_ATTR_CPU_CAPABILITY); 217 if (!start_cap) 218 return -EMSGSIZE; 219 220 for (i = 0; i < p->cpu_capabilities_count; ++i) { 221 if (nla_put_u32(msg, THERMAL_GENL_ATTR_CPU_CAPABILITY_ID, 222 cpu_cap->cpu)) 223 goto out_cancel_nest; 224 225 if (nla_put_u32(msg, THERMAL_GENL_ATTR_CPU_CAPABILITY_PERFORMANCE, 226 cpu_cap->performance)) 227 goto out_cancel_nest; 228 229 if (nla_put_u32(msg, THERMAL_GENL_ATTR_CPU_CAPABILITY_EFFICIENCY, 230 cpu_cap->efficiency)) 231 goto out_cancel_nest; 232 233 ++cpu_cap; 234 } 235 236 nla_nest_end(msg, start_cap); 237 238 return 0; 239 out_cancel_nest: 240 nla_nest_cancel(msg, start_cap); 241 242 return -EMSGSIZE; 243 } 244 245 static int thermal_genl_event_threshold_add(struct param *p) 246 { 247 if (nla_put_u32(p->msg, THERMAL_GENL_ATTR_TZ_ID, p->tz_id) || 248 nla_put_u32(p->msg, THERMAL_GENL_ATTR_THRESHOLD_TEMP, p->temp) || 249 nla_put_u32(p->msg, THERMAL_GENL_ATTR_THRESHOLD_DIRECTION, p->direction)) 250 return -EMSGSIZE; 251 252 return 0; 253 } 254 255 static int thermal_genl_event_threshold_flush(struct param *p) 256 { 257 if (nla_put_u32(p->msg, THERMAL_GENL_ATTR_TZ_ID, p->tz_id)) 258 return -EMSGSIZE; 259 260 return 0; 261 } 262 263 static int thermal_genl_event_threshold_up(struct param *p) 264 { 265 if (nla_put_u32(p->msg, THERMAL_GENL_ATTR_TZ_ID, p->tz_id) || 266 nla_put_u32(p->msg, THERMAL_GENL_ATTR_TZ_PREV_TEMP, p->prev_temp) || 267 nla_put_u32(p->msg, THERMAL_GENL_ATTR_TZ_TEMP, p->temp)) 268 return -EMSGSIZE; 269 270 return 0; 271 } 272 273 int thermal_genl_event_tz_delete(struct param *p) 274 __attribute__((alias("thermal_genl_event_tz"))); 275 276 int thermal_genl_event_tz_enable(struct param *p) 277 __attribute__((alias("thermal_genl_event_tz"))); 278 279 int thermal_genl_event_tz_disable(struct param *p) 280 __attribute__((alias("thermal_genl_event_tz"))); 281 282 int thermal_genl_event_tz_trip_down(struct param *p) 283 __attribute__((alias("thermal_genl_event_tz_trip_up"))); 284 285 int thermal_genl_event_threshold_delete(struct param *p) 286 __attribute__((alias("thermal_genl_event_threshold_add"))); 287 288 int thermal_genl_event_threshold_down(struct param *p) 289 __attribute__((alias("thermal_genl_event_threshold_up"))); 290 291 static cb_t event_cb[] = { 292 [THERMAL_GENL_EVENT_TZ_CREATE] = thermal_genl_event_tz_create, 293 [THERMAL_GENL_EVENT_TZ_DELETE] = thermal_genl_event_tz_delete, 294 [THERMAL_GENL_EVENT_TZ_ENABLE] = thermal_genl_event_tz_enable, 295 [THERMAL_GENL_EVENT_TZ_DISABLE] = thermal_genl_event_tz_disable, 296 [THERMAL_GENL_EVENT_TZ_TRIP_UP] = thermal_genl_event_tz_trip_up, 297 [THERMAL_GENL_EVENT_TZ_TRIP_DOWN] = thermal_genl_event_tz_trip_down, 298 [THERMAL_GENL_EVENT_TZ_TRIP_CHANGE] = thermal_genl_event_tz_trip_change, 299 [THERMAL_GENL_EVENT_CDEV_ADD] = thermal_genl_event_cdev_add, 300 [THERMAL_GENL_EVENT_CDEV_DELETE] = thermal_genl_event_cdev_delete, 301 [THERMAL_GENL_EVENT_CDEV_STATE_UPDATE] = thermal_genl_event_cdev_state_update, 302 [THERMAL_GENL_EVENT_TZ_GOV_CHANGE] = thermal_genl_event_gov_change, 303 [THERMAL_GENL_EVENT_CPU_CAPABILITY_CHANGE] = thermal_genl_event_cpu_capability_change, 304 [THERMAL_GENL_EVENT_THRESHOLD_ADD] = thermal_genl_event_threshold_add, 305 [THERMAL_GENL_EVENT_THRESHOLD_DELETE] = thermal_genl_event_threshold_delete, 306 [THERMAL_GENL_EVENT_THRESHOLD_FLUSH] = thermal_genl_event_threshold_flush, 307 [THERMAL_GENL_EVENT_THRESHOLD_DOWN] = thermal_genl_event_threshold_down, 308 [THERMAL_GENL_EVENT_THRESHOLD_UP] = thermal_genl_event_threshold_up, 309 }; 310 311 /* 312 * Generic netlink event encoding 313 */ 314 static int thermal_genl_send_event(enum thermal_genl_event event, 315 struct param *p) 316 { 317 struct sk_buff *msg; 318 int ret = -EMSGSIZE; 319 void *hdr; 320 321 if (!thermal_group_has_listeners(THERMAL_GENL_EVENT_GROUP)) 322 return 0; 323 324 msg = genlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL); 325 if (!msg) 326 return -ENOMEM; 327 p->msg = msg; 328 329 hdr = genlmsg_put(msg, 0, 0, &thermal_genl_family, 0, event); 330 if (!hdr) 331 goto out_free_msg; 332 333 ret = event_cb[event](p); 334 if (ret) 335 goto out_cancel_msg; 336 337 genlmsg_end(msg, hdr); 338 339 genlmsg_multicast(&thermal_genl_family, msg, 0, THERMAL_GENL_EVENT_GROUP, GFP_KERNEL); 340 341 return 0; 342 343 out_cancel_msg: 344 genlmsg_cancel(msg, hdr); 345 out_free_msg: 346 nlmsg_free(msg); 347 348 return ret; 349 } 350 351 int thermal_notify_tz_create(const struct thermal_zone_device *tz) 352 { 353 struct param p = { .tz_id = tz->id, .name = tz->type }; 354 355 return thermal_genl_send_event(THERMAL_GENL_EVENT_TZ_CREATE, &p); 356 } 357 358 int thermal_notify_tz_delete(const struct thermal_zone_device *tz) 359 { 360 struct param p = { .tz_id = tz->id }; 361 362 return thermal_genl_send_event(THERMAL_GENL_EVENT_TZ_DELETE, &p); 363 } 364 365 int thermal_notify_tz_enable(const struct thermal_zone_device *tz) 366 { 367 struct param p = { .tz_id = tz->id }; 368 369 return thermal_genl_send_event(THERMAL_GENL_EVENT_TZ_ENABLE, &p); 370 } 371 372 int thermal_notify_tz_disable(const struct thermal_zone_device *tz) 373 { 374 struct param p = { .tz_id = tz->id }; 375 376 return thermal_genl_send_event(THERMAL_GENL_EVENT_TZ_DISABLE, &p); 377 } 378 379 int thermal_notify_tz_trip_down(const struct thermal_zone_device *tz, 380 const struct thermal_trip *trip) 381 { 382 struct param p = { .tz_id = tz->id, 383 .trip_id = thermal_zone_trip_id(tz, trip), 384 .temp = tz->temperature }; 385 386 return thermal_genl_send_event(THERMAL_GENL_EVENT_TZ_TRIP_DOWN, &p); 387 } 388 389 int thermal_notify_tz_trip_up(const struct thermal_zone_device *tz, 390 const struct thermal_trip *trip) 391 { 392 struct param p = { .tz_id = tz->id, 393 .trip_id = thermal_zone_trip_id(tz, trip), 394 .temp = tz->temperature }; 395 396 return thermal_genl_send_event(THERMAL_GENL_EVENT_TZ_TRIP_UP, &p); 397 } 398 399 int thermal_notify_tz_trip_change(const struct thermal_zone_device *tz, 400 const struct thermal_trip *trip) 401 { 402 struct param p = { .tz_id = tz->id, 403 .trip_id = thermal_zone_trip_id(tz, trip), 404 .trip_type = trip->type, 405 .trip_temp = trip->temperature, 406 .trip_hyst = trip->hysteresis }; 407 408 return thermal_genl_send_event(THERMAL_GENL_EVENT_TZ_TRIP_CHANGE, &p); 409 } 410 411 int thermal_notify_cdev_state_update(const struct thermal_cooling_device *cdev, 412 int state) 413 { 414 struct param p = { .cdev_id = cdev->id, .cdev_state = state }; 415 416 return thermal_genl_send_event(THERMAL_GENL_EVENT_CDEV_STATE_UPDATE, &p); 417 } 418 419 int thermal_notify_cdev_add(const struct thermal_cooling_device *cdev) 420 { 421 struct param p = { .cdev_id = cdev->id, .name = cdev->type, 422 .cdev_max_state = cdev->max_state }; 423 424 return thermal_genl_send_event(THERMAL_GENL_EVENT_CDEV_ADD, &p); 425 } 426 427 int thermal_notify_cdev_delete(const struct thermal_cooling_device *cdev) 428 { 429 struct param p = { .cdev_id = cdev->id }; 430 431 return thermal_genl_send_event(THERMAL_GENL_EVENT_CDEV_DELETE, &p); 432 } 433 434 int thermal_notify_tz_gov_change(const struct thermal_zone_device *tz, 435 const char *name) 436 { 437 struct param p = { .tz_id = tz->id, .name = name }; 438 439 return thermal_genl_send_event(THERMAL_GENL_EVENT_TZ_GOV_CHANGE, &p); 440 } 441 442 int thermal_genl_cpu_capability_event(int count, 443 struct thermal_genl_cpu_caps *caps) 444 { 445 struct param p = { .cpu_capabilities_count = count, .cpu_capabilities = caps }; 446 447 return thermal_genl_send_event(THERMAL_GENL_EVENT_CPU_CAPABILITY_CHANGE, &p); 448 } 449 EXPORT_SYMBOL_GPL(thermal_genl_cpu_capability_event); 450 451 int thermal_notify_threshold_add(const struct thermal_zone_device *tz, 452 int temperature, int direction) 453 { 454 struct param p = { .tz_id = tz->id, .temp = temperature, .direction = direction }; 455 456 return thermal_genl_send_event(THERMAL_GENL_EVENT_THRESHOLD_ADD, &p); 457 } 458 459 int thermal_notify_threshold_delete(const struct thermal_zone_device *tz, 460 int temperature, int direction) 461 { 462 struct param p = { .tz_id = tz->id, .temp = temperature, .direction = direction }; 463 464 return thermal_genl_send_event(THERMAL_GENL_EVENT_THRESHOLD_DELETE, &p); 465 } 466 467 int thermal_notify_threshold_flush(const struct thermal_zone_device *tz) 468 { 469 struct param p = { .tz_id = tz->id }; 470 471 return thermal_genl_send_event(THERMAL_GENL_EVENT_THRESHOLD_FLUSH, &p); 472 } 473 474 int thermal_notify_threshold_down(const struct thermal_zone_device *tz) 475 { 476 struct param p = { .tz_id = tz->id, .temp = tz->temperature, .prev_temp = tz->last_temperature }; 477 478 return thermal_genl_send_event(THERMAL_GENL_EVENT_THRESHOLD_DOWN, &p); 479 } 480 481 int thermal_notify_threshold_up(const struct thermal_zone_device *tz) 482 { 483 struct param p = { .tz_id = tz->id, .temp = tz->temperature, .prev_temp = tz->last_temperature }; 484 485 return thermal_genl_send_event(THERMAL_GENL_EVENT_THRESHOLD_UP, &p); 486 } 487 488 /*************************** Command encoding ********************************/ 489 490 static int __thermal_genl_cmd_tz_get_id(struct thermal_zone_device *tz, 491 void *data) 492 { 493 struct sk_buff *msg = data; 494 495 if (nla_put_u32(msg, THERMAL_GENL_ATTR_TZ_ID, tz->id) || 496 nla_put_string(msg, THERMAL_GENL_ATTR_TZ_NAME, tz->type)) 497 return -EMSGSIZE; 498 499 return 0; 500 } 501 502 static int thermal_genl_cmd_tz_get_id(struct param *p) 503 { 504 struct sk_buff *msg = p->msg; 505 struct nlattr *start_tz; 506 int ret; 507 508 start_tz = nla_nest_start(msg, THERMAL_GENL_ATTR_TZ); 509 if (!start_tz) 510 return -EMSGSIZE; 511 512 ret = for_each_thermal_zone(__thermal_genl_cmd_tz_get_id, msg); 513 if (ret) 514 goto out_cancel_nest; 515 516 nla_nest_end(msg, start_tz); 517 518 return 0; 519 520 out_cancel_nest: 521 nla_nest_cancel(msg, start_tz); 522 523 return ret; 524 } 525 526 static int thermal_genl_cmd_tz_get_trip(struct param *p) 527 { 528 struct sk_buff *msg = p->msg; 529 const struct thermal_trip_desc *td; 530 struct nlattr *start_trip; 531 int id; 532 533 if (!p->attrs[THERMAL_GENL_ATTR_TZ_ID]) 534 return -EINVAL; 535 536 id = nla_get_u32(p->attrs[THERMAL_GENL_ATTR_TZ_ID]); 537 538 CLASS(thermal_zone_get_by_id, tz)(id); 539 if (!tz) 540 return -EINVAL; 541 542 start_trip = nla_nest_start(msg, THERMAL_GENL_ATTR_TZ_TRIP); 543 if (!start_trip) 544 return -EMSGSIZE; 545 546 guard(thermal_zone)(tz); 547 548 for_each_trip_desc(tz, td) { 549 const struct thermal_trip *trip = &td->trip; 550 551 if (nla_put_u32(msg, THERMAL_GENL_ATTR_TZ_TRIP_ID, 552 thermal_zone_trip_id(tz, trip)) || 553 nla_put_u32(msg, THERMAL_GENL_ATTR_TZ_TRIP_TYPE, trip->type) || 554 nla_put_u32(msg, THERMAL_GENL_ATTR_TZ_TRIP_TEMP, trip->temperature) || 555 nla_put_u32(msg, THERMAL_GENL_ATTR_TZ_TRIP_HYST, trip->hysteresis)) 556 return -EMSGSIZE; 557 } 558 559 nla_nest_end(msg, start_trip); 560 561 return 0; 562 } 563 564 static int thermal_genl_cmd_tz_get_temp(struct param *p) 565 { 566 struct sk_buff *msg = p->msg; 567 int temp, ret, id; 568 569 if (!p->attrs[THERMAL_GENL_ATTR_TZ_ID]) 570 return -EINVAL; 571 572 id = nla_get_u32(p->attrs[THERMAL_GENL_ATTR_TZ_ID]); 573 574 CLASS(thermal_zone_get_by_id, tz)(id); 575 if (!tz) 576 return -EINVAL; 577 578 ret = thermal_zone_get_temp(tz, &temp); 579 if (ret) 580 return ret; 581 582 if (nla_put_u32(msg, THERMAL_GENL_ATTR_TZ_ID, id) || 583 nla_put_u32(msg, THERMAL_GENL_ATTR_TZ_TEMP, temp)) 584 return -EMSGSIZE; 585 586 return 0; 587 } 588 589 static int thermal_genl_cmd_tz_get_gov(struct param *p) 590 { 591 struct sk_buff *msg = p->msg; 592 int id; 593 594 if (!p->attrs[THERMAL_GENL_ATTR_TZ_ID]) 595 return -EINVAL; 596 597 id = nla_get_u32(p->attrs[THERMAL_GENL_ATTR_TZ_ID]); 598 599 CLASS(thermal_zone_get_by_id, tz)(id); 600 if (!tz) 601 return -EINVAL; 602 603 guard(thermal_zone)(tz); 604 605 if (nla_put_u32(msg, THERMAL_GENL_ATTR_TZ_ID, id) || 606 nla_put_string(msg, THERMAL_GENL_ATTR_TZ_GOV_NAME, 607 tz->governor->name)) 608 return -EMSGSIZE; 609 610 return 0; 611 } 612 613 static int __thermal_genl_cmd_cdev_get(struct thermal_cooling_device *cdev, 614 void *data) 615 { 616 struct sk_buff *msg = data; 617 618 if (nla_put_u32(msg, THERMAL_GENL_ATTR_CDEV_ID, cdev->id)) 619 return -EMSGSIZE; 620 621 if (nla_put_string(msg, THERMAL_GENL_ATTR_CDEV_NAME, cdev->type)) 622 return -EMSGSIZE; 623 624 return 0; 625 } 626 627 static int thermal_genl_cmd_cdev_get(struct param *p) 628 { 629 struct sk_buff *msg = p->msg; 630 struct nlattr *start_cdev; 631 int ret; 632 633 start_cdev = nla_nest_start(msg, THERMAL_GENL_ATTR_CDEV); 634 if (!start_cdev) 635 return -EMSGSIZE; 636 637 ret = for_each_thermal_cooling_device(__thermal_genl_cmd_cdev_get, msg); 638 if (ret) 639 goto out_cancel_nest; 640 641 nla_nest_end(msg, start_cdev); 642 643 return 0; 644 out_cancel_nest: 645 nla_nest_cancel(msg, start_cdev); 646 647 return ret; 648 } 649 650 static int __thermal_genl_cmd_threshold_get(struct user_threshold *threshold, void *arg) 651 { 652 struct sk_buff *msg = arg; 653 654 if (nla_put_u32(msg, THERMAL_GENL_ATTR_THRESHOLD_TEMP, threshold->temperature) || 655 nla_put_u32(msg, THERMAL_GENL_ATTR_THRESHOLD_DIRECTION, threshold->direction)) 656 return -1; 657 658 return 0; 659 } 660 661 static int thermal_genl_cmd_threshold_get(struct param *p) 662 { 663 struct sk_buff *msg = p->msg; 664 struct nlattr *start_trip; 665 int id, ret; 666 667 if (!p->attrs[THERMAL_GENL_ATTR_TZ_ID]) 668 return -EINVAL; 669 670 id = nla_get_u32(p->attrs[THERMAL_GENL_ATTR_TZ_ID]); 671 672 CLASS(thermal_zone_get_by_id, tz)(id); 673 if (!tz) 674 return -EINVAL; 675 676 start_trip = nla_nest_start(msg, THERMAL_GENL_ATTR_THRESHOLD); 677 if (!start_trip) 678 return -EMSGSIZE; 679 680 ret = thermal_thresholds_for_each(tz, __thermal_genl_cmd_threshold_get, msg); 681 if (ret) 682 return -EMSGSIZE; 683 684 nla_nest_end(msg, start_trip); 685 686 return 0; 687 } 688 689 static int thermal_genl_cmd_threshold_add(struct param *p) 690 { 691 int id, temp, direction; 692 693 if (!capable(CAP_SYS_ADMIN)) 694 return -EPERM; 695 696 if (!p->attrs[THERMAL_GENL_ATTR_TZ_ID] || 697 !p->attrs[THERMAL_GENL_ATTR_THRESHOLD_TEMP] || 698 !p->attrs[THERMAL_GENL_ATTR_THRESHOLD_DIRECTION]) 699 return -EINVAL; 700 701 id = nla_get_u32(p->attrs[THERMAL_GENL_ATTR_TZ_ID]); 702 temp = nla_get_u32(p->attrs[THERMAL_GENL_ATTR_THRESHOLD_TEMP]); 703 direction = nla_get_u32(p->attrs[THERMAL_GENL_ATTR_THRESHOLD_DIRECTION]); 704 705 CLASS(thermal_zone_get_by_id, tz)(id); 706 if (!tz) 707 return -EINVAL; 708 709 guard(thermal_zone)(tz); 710 711 return thermal_thresholds_add(tz, temp, direction); 712 } 713 714 static int thermal_genl_cmd_threshold_delete(struct param *p) 715 { 716 int id, temp, direction; 717 718 if (!capable(CAP_SYS_ADMIN)) 719 return -EPERM; 720 721 if (!p->attrs[THERMAL_GENL_ATTR_TZ_ID] || 722 !p->attrs[THERMAL_GENL_ATTR_THRESHOLD_TEMP] || 723 !p->attrs[THERMAL_GENL_ATTR_THRESHOLD_DIRECTION]) 724 return -EINVAL; 725 726 id = nla_get_u32(p->attrs[THERMAL_GENL_ATTR_TZ_ID]); 727 temp = nla_get_u32(p->attrs[THERMAL_GENL_ATTR_THRESHOLD_TEMP]); 728 direction = nla_get_u32(p->attrs[THERMAL_GENL_ATTR_THRESHOLD_DIRECTION]); 729 730 CLASS(thermal_zone_get_by_id, tz)(id); 731 if (!tz) 732 return -EINVAL; 733 734 guard(thermal_zone)(tz); 735 736 return thermal_thresholds_delete(tz, temp, direction); 737 } 738 739 static int thermal_genl_cmd_threshold_flush(struct param *p) 740 { 741 int id; 742 743 if (!capable(CAP_SYS_ADMIN)) 744 return -EPERM; 745 746 if (!p->attrs[THERMAL_GENL_ATTR_TZ_ID]) 747 return -EINVAL; 748 749 id = nla_get_u32(p->attrs[THERMAL_GENL_ATTR_TZ_ID]); 750 751 CLASS(thermal_zone_get_by_id, tz)(id); 752 if (!tz) 753 return -EINVAL; 754 755 guard(thermal_zone)(tz); 756 757 thermal_thresholds_flush(tz); 758 759 return 0; 760 } 761 762 static cb_t cmd_cb[] = { 763 [THERMAL_GENL_CMD_TZ_GET_ID] = thermal_genl_cmd_tz_get_id, 764 [THERMAL_GENL_CMD_TZ_GET_TRIP] = thermal_genl_cmd_tz_get_trip, 765 [THERMAL_GENL_CMD_TZ_GET_TEMP] = thermal_genl_cmd_tz_get_temp, 766 [THERMAL_GENL_CMD_TZ_GET_GOV] = thermal_genl_cmd_tz_get_gov, 767 [THERMAL_GENL_CMD_CDEV_GET] = thermal_genl_cmd_cdev_get, 768 [THERMAL_GENL_CMD_THRESHOLD_GET] = thermal_genl_cmd_threshold_get, 769 [THERMAL_GENL_CMD_THRESHOLD_ADD] = thermal_genl_cmd_threshold_add, 770 [THERMAL_GENL_CMD_THRESHOLD_DELETE] = thermal_genl_cmd_threshold_delete, 771 [THERMAL_GENL_CMD_THRESHOLD_FLUSH] = thermal_genl_cmd_threshold_flush, 772 }; 773 774 static int thermal_genl_cmd_dumpit(struct sk_buff *skb, 775 struct netlink_callback *cb) 776 { 777 struct param p = { .msg = skb }; 778 const struct genl_dumpit_info *info = genl_dumpit_info(cb); 779 int cmd = info->op.cmd; 780 int ret; 781 void *hdr; 782 783 hdr = genlmsg_put(skb, 0, 0, &thermal_genl_family, 0, cmd); 784 if (!hdr) 785 return -EMSGSIZE; 786 787 ret = cmd_cb[cmd](&p); 788 if (ret) 789 goto out_cancel_msg; 790 791 genlmsg_end(skb, hdr); 792 793 return 0; 794 795 out_cancel_msg: 796 genlmsg_cancel(skb, hdr); 797 798 return ret; 799 } 800 801 static int thermal_genl_cmd_doit(struct sk_buff *skb, 802 struct genl_info *info) 803 { 804 struct param p = { .attrs = info->attrs }; 805 struct sk_buff *msg; 806 void *hdr; 807 int cmd = info->genlhdr->cmd; 808 int ret = -EMSGSIZE; 809 810 msg = genlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL); 811 if (!msg) 812 return -ENOMEM; 813 p.msg = msg; 814 815 hdr = genlmsg_put_reply(msg, info, &thermal_genl_family, 0, cmd); 816 if (!hdr) 817 goto out_free_msg; 818 819 ret = cmd_cb[cmd](&p); 820 if (ret) 821 goto out_cancel_msg; 822 823 genlmsg_end(msg, hdr); 824 825 return genlmsg_reply(msg, info); 826 827 out_cancel_msg: 828 genlmsg_cancel(msg, hdr); 829 out_free_msg: 830 nlmsg_free(msg); 831 832 return ret; 833 } 834 835 static int thermal_genl_bind(int mcgrp) 836 { 837 struct thermal_genl_notify n = { .mcgrp = mcgrp }; 838 839 if (WARN_ON_ONCE(mcgrp > THERMAL_GENL_MAX_GROUP)) 840 return -EINVAL; 841 842 blocking_notifier_call_chain(&thermal_genl_chain, THERMAL_NOTIFY_BIND, &n); 843 return 0; 844 } 845 846 static void thermal_genl_unbind(int mcgrp) 847 { 848 struct thermal_genl_notify n = { .mcgrp = mcgrp }; 849 850 if (WARN_ON_ONCE(mcgrp > THERMAL_GENL_MAX_GROUP)) 851 return; 852 853 blocking_notifier_call_chain(&thermal_genl_chain, THERMAL_NOTIFY_UNBIND, &n); 854 } 855 856 static const struct genl_small_ops thermal_genl_ops[] = { 857 { 858 .cmd = THERMAL_GENL_CMD_TZ_GET_ID, 859 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP, 860 .dumpit = thermal_genl_cmd_dumpit, 861 }, 862 { 863 .cmd = THERMAL_GENL_CMD_TZ_GET_TRIP, 864 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP, 865 .doit = thermal_genl_cmd_doit, 866 }, 867 { 868 .cmd = THERMAL_GENL_CMD_TZ_GET_TEMP, 869 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP, 870 .doit = thermal_genl_cmd_doit, 871 }, 872 { 873 .cmd = THERMAL_GENL_CMD_TZ_GET_GOV, 874 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP, 875 .doit = thermal_genl_cmd_doit, 876 }, 877 { 878 .cmd = THERMAL_GENL_CMD_CDEV_GET, 879 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP, 880 .dumpit = thermal_genl_cmd_dumpit, 881 }, 882 { 883 .cmd = THERMAL_GENL_CMD_THRESHOLD_GET, 884 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP, 885 .doit = thermal_genl_cmd_doit, 886 }, 887 { 888 .cmd = THERMAL_GENL_CMD_THRESHOLD_ADD, 889 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP, 890 .doit = thermal_genl_cmd_doit, 891 }, 892 { 893 .cmd = THERMAL_GENL_CMD_THRESHOLD_DELETE, 894 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP, 895 .doit = thermal_genl_cmd_doit, 896 }, 897 { 898 .cmd = THERMAL_GENL_CMD_THRESHOLD_FLUSH, 899 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP, 900 .doit = thermal_genl_cmd_doit, 901 }, 902 }; 903 904 static struct genl_family thermal_genl_family __ro_after_init = { 905 .hdrsize = 0, 906 .name = THERMAL_GENL_FAMILY_NAME, 907 .version = THERMAL_GENL_VERSION, 908 .maxattr = THERMAL_GENL_ATTR_MAX, 909 .policy = thermal_genl_policy, 910 .bind = thermal_genl_bind, 911 .unbind = thermal_genl_unbind, 912 .small_ops = thermal_genl_ops, 913 .n_small_ops = ARRAY_SIZE(thermal_genl_ops), 914 .resv_start_op = __THERMAL_GENL_CMD_MAX, 915 .mcgrps = thermal_genl_mcgrps, 916 .n_mcgrps = ARRAY_SIZE(thermal_genl_mcgrps), 917 }; 918 919 int thermal_genl_register_notifier(struct notifier_block *nb) 920 { 921 return blocking_notifier_chain_register(&thermal_genl_chain, nb); 922 } 923 924 int thermal_genl_unregister_notifier(struct notifier_block *nb) 925 { 926 return blocking_notifier_chain_unregister(&thermal_genl_chain, nb); 927 } 928 929 int __init thermal_netlink_init(void) 930 { 931 return genl_register_family(&thermal_genl_family); 932 } 933 934 void __init thermal_netlink_exit(void) 935 { 936 genl_unregister_family(&thermal_genl_family); 937 } 938