1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * Generic netlink for DPLL management framework 4 * 5 * Copyright (c) 2023 Meta Platforms, Inc. and affiliates 6 * Copyright (c) 2023 Intel and affiliates 7 * 8 */ 9 #include <linux/module.h> 10 #include <linux/kernel.h> 11 #include <net/genetlink.h> 12 #include "dpll_core.h" 13 #include "dpll_netlink.h" 14 #include "dpll_nl.h" 15 #include <uapi/linux/dpll.h> 16 17 #define ASSERT_NOT_NULL(ptr) (WARN_ON(!ptr)) 18 19 #define xa_for_each_marked_start(xa, index, entry, filter, start) \ 20 for (index = start, entry = xa_find(xa, &index, ULONG_MAX, filter); \ 21 entry; entry = xa_find_after(xa, &index, ULONG_MAX, filter)) 22 23 struct dpll_dump_ctx { 24 unsigned long idx; 25 }; 26 27 static struct dpll_dump_ctx *dpll_dump_context(struct netlink_callback *cb) 28 { 29 return (struct dpll_dump_ctx *)cb->ctx; 30 } 31 32 static int 33 dpll_msg_add_dev_handle(struct sk_buff *msg, struct dpll_device *dpll) 34 { 35 if (nla_put_u32(msg, DPLL_A_ID, dpll->id)) 36 return -EMSGSIZE; 37 38 return 0; 39 } 40 41 static int 42 dpll_msg_add_dev_parent_handle(struct sk_buff *msg, u32 id) 43 { 44 if (nla_put_u32(msg, DPLL_A_PIN_PARENT_ID, id)) 45 return -EMSGSIZE; 46 47 return 0; 48 } 49 50 /** 51 * dpll_msg_pin_handle_size - get size of pin handle attribute for given pin 52 * @pin: pin pointer 53 * 54 * Return: byte size of pin handle attribute for given pin. 55 */ 56 size_t dpll_msg_pin_handle_size(struct dpll_pin *pin) 57 { 58 return pin ? nla_total_size(4) : 0; /* DPLL_A_PIN_ID */ 59 } 60 EXPORT_SYMBOL_GPL(dpll_msg_pin_handle_size); 61 62 /** 63 * dpll_msg_add_pin_handle - attach pin handle attribute to a given message 64 * @msg: pointer to sk_buff message to attach a pin handle 65 * @pin: pin pointer 66 * 67 * Return: 68 * * 0 - success 69 * * -EMSGSIZE - no space in message to attach pin handle 70 */ 71 int dpll_msg_add_pin_handle(struct sk_buff *msg, struct dpll_pin *pin) 72 { 73 if (!pin) 74 return 0; 75 if (nla_put_u32(msg, DPLL_A_PIN_ID, pin->id)) 76 return -EMSGSIZE; 77 return 0; 78 } 79 EXPORT_SYMBOL_GPL(dpll_msg_add_pin_handle); 80 81 static int 82 dpll_msg_add_mode(struct sk_buff *msg, struct dpll_device *dpll, 83 struct netlink_ext_ack *extack) 84 { 85 const struct dpll_device_ops *ops = dpll_device_ops(dpll); 86 enum dpll_mode mode; 87 int ret; 88 89 ret = ops->mode_get(dpll, dpll_priv(dpll), &mode, extack); 90 if (ret) 91 return ret; 92 if (nla_put_u32(msg, DPLL_A_MODE, mode)) 93 return -EMSGSIZE; 94 95 return 0; 96 } 97 98 static int 99 dpll_msg_add_mode_supported(struct sk_buff *msg, struct dpll_device *dpll, 100 struct netlink_ext_ack *extack) 101 { 102 const struct dpll_device_ops *ops = dpll_device_ops(dpll); 103 enum dpll_mode mode; 104 int ret; 105 106 /* No mode change is supported now, so the only supported mode is the 107 * one obtained by mode_get(). 108 */ 109 110 ret = ops->mode_get(dpll, dpll_priv(dpll), &mode, extack); 111 if (ret) 112 return ret; 113 if (nla_put_u32(msg, DPLL_A_MODE_SUPPORTED, mode)) 114 return -EMSGSIZE; 115 116 return 0; 117 } 118 119 static int 120 dpll_msg_add_lock_status(struct sk_buff *msg, struct dpll_device *dpll, 121 struct netlink_ext_ack *extack) 122 { 123 const struct dpll_device_ops *ops = dpll_device_ops(dpll); 124 enum dpll_lock_status status; 125 int ret; 126 127 ret = ops->lock_status_get(dpll, dpll_priv(dpll), &status, extack); 128 if (ret) 129 return ret; 130 if (nla_put_u32(msg, DPLL_A_LOCK_STATUS, status)) 131 return -EMSGSIZE; 132 133 return 0; 134 } 135 136 static int 137 dpll_msg_add_temp(struct sk_buff *msg, struct dpll_device *dpll, 138 struct netlink_ext_ack *extack) 139 { 140 const struct dpll_device_ops *ops = dpll_device_ops(dpll); 141 s32 temp; 142 int ret; 143 144 if (!ops->temp_get) 145 return 0; 146 ret = ops->temp_get(dpll, dpll_priv(dpll), &temp, extack); 147 if (ret) 148 return ret; 149 if (nla_put_s32(msg, DPLL_A_TEMP, temp)) 150 return -EMSGSIZE; 151 152 return 0; 153 } 154 155 static int 156 dpll_msg_add_pin_prio(struct sk_buff *msg, struct dpll_pin *pin, 157 struct dpll_pin_ref *ref, 158 struct netlink_ext_ack *extack) 159 { 160 const struct dpll_pin_ops *ops = dpll_pin_ops(ref); 161 struct dpll_device *dpll = ref->dpll; 162 u32 prio; 163 int ret; 164 165 if (!ops->prio_get) 166 return 0; 167 ret = ops->prio_get(pin, dpll_pin_on_dpll_priv(dpll, pin), dpll, 168 dpll_priv(dpll), &prio, extack); 169 if (ret) 170 return ret; 171 if (nla_put_u32(msg, DPLL_A_PIN_PRIO, prio)) 172 return -EMSGSIZE; 173 174 return 0; 175 } 176 177 static int 178 dpll_msg_add_pin_on_dpll_state(struct sk_buff *msg, struct dpll_pin *pin, 179 struct dpll_pin_ref *ref, 180 struct netlink_ext_ack *extack) 181 { 182 const struct dpll_pin_ops *ops = dpll_pin_ops(ref); 183 struct dpll_device *dpll = ref->dpll; 184 enum dpll_pin_state state; 185 int ret; 186 187 if (!ops->state_on_dpll_get) 188 return 0; 189 ret = ops->state_on_dpll_get(pin, dpll_pin_on_dpll_priv(dpll, pin), 190 dpll, dpll_priv(dpll), &state, extack); 191 if (ret) 192 return ret; 193 if (nla_put_u32(msg, DPLL_A_PIN_STATE, state)) 194 return -EMSGSIZE; 195 196 return 0; 197 } 198 199 static int 200 dpll_msg_add_pin_direction(struct sk_buff *msg, struct dpll_pin *pin, 201 struct dpll_pin_ref *ref, 202 struct netlink_ext_ack *extack) 203 { 204 const struct dpll_pin_ops *ops = dpll_pin_ops(ref); 205 struct dpll_device *dpll = ref->dpll; 206 enum dpll_pin_direction direction; 207 int ret; 208 209 ret = ops->direction_get(pin, dpll_pin_on_dpll_priv(dpll, pin), dpll, 210 dpll_priv(dpll), &direction, extack); 211 if (ret) 212 return ret; 213 if (nla_put_u32(msg, DPLL_A_PIN_DIRECTION, direction)) 214 return -EMSGSIZE; 215 216 return 0; 217 } 218 219 static int 220 dpll_msg_add_pin_phase_adjust(struct sk_buff *msg, struct dpll_pin *pin, 221 struct dpll_pin_ref *ref, 222 struct netlink_ext_ack *extack) 223 { 224 const struct dpll_pin_ops *ops = dpll_pin_ops(ref); 225 struct dpll_device *dpll = ref->dpll; 226 s32 phase_adjust; 227 int ret; 228 229 if (!ops->phase_adjust_get) 230 return 0; 231 ret = ops->phase_adjust_get(pin, dpll_pin_on_dpll_priv(dpll, pin), 232 dpll, dpll_priv(dpll), 233 &phase_adjust, extack); 234 if (ret) 235 return ret; 236 if (nla_put_s32(msg, DPLL_A_PIN_PHASE_ADJUST, phase_adjust)) 237 return -EMSGSIZE; 238 239 return 0; 240 } 241 242 static int 243 dpll_msg_add_phase_offset(struct sk_buff *msg, struct dpll_pin *pin, 244 struct dpll_pin_ref *ref, 245 struct netlink_ext_ack *extack) 246 { 247 const struct dpll_pin_ops *ops = dpll_pin_ops(ref); 248 struct dpll_device *dpll = ref->dpll; 249 s64 phase_offset; 250 int ret; 251 252 if (!ops->phase_offset_get) 253 return 0; 254 ret = ops->phase_offset_get(pin, dpll_pin_on_dpll_priv(dpll, pin), 255 dpll, dpll_priv(dpll), &phase_offset, 256 extack); 257 if (ret) 258 return ret; 259 if (nla_put_64bit(msg, DPLL_A_PIN_PHASE_OFFSET, sizeof(phase_offset), 260 &phase_offset, DPLL_A_PIN_PAD)) 261 return -EMSGSIZE; 262 263 return 0; 264 } 265 266 static int dpll_msg_add_ffo(struct sk_buff *msg, struct dpll_pin *pin, 267 struct dpll_pin_ref *ref, 268 struct netlink_ext_ack *extack) 269 { 270 const struct dpll_pin_ops *ops = dpll_pin_ops(ref); 271 struct dpll_device *dpll = ref->dpll; 272 s64 ffo; 273 int ret; 274 275 if (!ops->ffo_get) 276 return 0; 277 ret = ops->ffo_get(pin, dpll_pin_on_dpll_priv(dpll, pin), 278 dpll, dpll_priv(dpll), &ffo, extack); 279 if (ret) { 280 if (ret == -ENODATA) 281 return 0; 282 return ret; 283 } 284 return nla_put_sint(msg, DPLL_A_PIN_FRACTIONAL_FREQUENCY_OFFSET, ffo); 285 } 286 287 static int 288 dpll_msg_add_pin_freq(struct sk_buff *msg, struct dpll_pin *pin, 289 struct dpll_pin_ref *ref, struct netlink_ext_ack *extack) 290 { 291 const struct dpll_pin_ops *ops = dpll_pin_ops(ref); 292 struct dpll_device *dpll = ref->dpll; 293 struct nlattr *nest; 294 int fs, ret; 295 u64 freq; 296 297 if (!ops->frequency_get) 298 return 0; 299 ret = ops->frequency_get(pin, dpll_pin_on_dpll_priv(dpll, pin), dpll, 300 dpll_priv(dpll), &freq, extack); 301 if (ret) 302 return ret; 303 if (nla_put_64bit(msg, DPLL_A_PIN_FREQUENCY, sizeof(freq), &freq, 304 DPLL_A_PIN_PAD)) 305 return -EMSGSIZE; 306 for (fs = 0; fs < pin->prop->freq_supported_num; fs++) { 307 nest = nla_nest_start(msg, DPLL_A_PIN_FREQUENCY_SUPPORTED); 308 if (!nest) 309 return -EMSGSIZE; 310 freq = pin->prop->freq_supported[fs].min; 311 if (nla_put_64bit(msg, DPLL_A_PIN_FREQUENCY_MIN, sizeof(freq), 312 &freq, DPLL_A_PIN_PAD)) { 313 nla_nest_cancel(msg, nest); 314 return -EMSGSIZE; 315 } 316 freq = pin->prop->freq_supported[fs].max; 317 if (nla_put_64bit(msg, DPLL_A_PIN_FREQUENCY_MAX, sizeof(freq), 318 &freq, DPLL_A_PIN_PAD)) { 319 nla_nest_cancel(msg, nest); 320 return -EMSGSIZE; 321 } 322 nla_nest_end(msg, nest); 323 } 324 325 return 0; 326 } 327 328 static bool dpll_pin_is_freq_supported(struct dpll_pin *pin, u32 freq) 329 { 330 int fs; 331 332 for (fs = 0; fs < pin->prop->freq_supported_num; fs++) 333 if (freq >= pin->prop->freq_supported[fs].min && 334 freq <= pin->prop->freq_supported[fs].max) 335 return true; 336 return false; 337 } 338 339 static int 340 dpll_msg_add_pin_parents(struct sk_buff *msg, struct dpll_pin *pin, 341 struct dpll_pin_ref *dpll_ref, 342 struct netlink_ext_ack *extack) 343 { 344 enum dpll_pin_state state; 345 struct dpll_pin_ref *ref; 346 struct dpll_pin *ppin; 347 struct nlattr *nest; 348 unsigned long index; 349 int ret; 350 351 xa_for_each(&pin->parent_refs, index, ref) { 352 const struct dpll_pin_ops *ops = dpll_pin_ops(ref); 353 void *parent_priv; 354 355 ppin = ref->pin; 356 parent_priv = dpll_pin_on_dpll_priv(dpll_ref->dpll, ppin); 357 ret = ops->state_on_pin_get(pin, 358 dpll_pin_on_pin_priv(ppin, pin), 359 ppin, parent_priv, &state, extack); 360 if (ret) 361 return ret; 362 nest = nla_nest_start(msg, DPLL_A_PIN_PARENT_PIN); 363 if (!nest) 364 return -EMSGSIZE; 365 ret = dpll_msg_add_dev_parent_handle(msg, ppin->id); 366 if (ret) 367 goto nest_cancel; 368 if (nla_put_u32(msg, DPLL_A_PIN_STATE, state)) { 369 ret = -EMSGSIZE; 370 goto nest_cancel; 371 } 372 nla_nest_end(msg, nest); 373 } 374 375 return 0; 376 377 nest_cancel: 378 nla_nest_cancel(msg, nest); 379 return ret; 380 } 381 382 static int 383 dpll_msg_add_pin_dplls(struct sk_buff *msg, struct dpll_pin *pin, 384 struct netlink_ext_ack *extack) 385 { 386 struct dpll_pin_ref *ref; 387 struct nlattr *attr; 388 unsigned long index; 389 int ret; 390 391 xa_for_each(&pin->dpll_refs, index, ref) { 392 attr = nla_nest_start(msg, DPLL_A_PIN_PARENT_DEVICE); 393 if (!attr) 394 return -EMSGSIZE; 395 ret = dpll_msg_add_dev_parent_handle(msg, ref->dpll->id); 396 if (ret) 397 goto nest_cancel; 398 ret = dpll_msg_add_pin_on_dpll_state(msg, pin, ref, extack); 399 if (ret) 400 goto nest_cancel; 401 ret = dpll_msg_add_pin_prio(msg, pin, ref, extack); 402 if (ret) 403 goto nest_cancel; 404 ret = dpll_msg_add_pin_direction(msg, pin, ref, extack); 405 if (ret) 406 goto nest_cancel; 407 ret = dpll_msg_add_phase_offset(msg, pin, ref, extack); 408 if (ret) 409 goto nest_cancel; 410 nla_nest_end(msg, attr); 411 } 412 413 return 0; 414 415 nest_cancel: 416 nla_nest_end(msg, attr); 417 return ret; 418 } 419 420 static int 421 dpll_cmd_pin_get_one(struct sk_buff *msg, struct dpll_pin *pin, 422 struct netlink_ext_ack *extack) 423 { 424 const struct dpll_pin_properties *prop = pin->prop; 425 struct dpll_pin_ref *ref; 426 int ret; 427 428 ref = dpll_xa_ref_dpll_first(&pin->dpll_refs); 429 ASSERT_NOT_NULL(ref); 430 431 ret = dpll_msg_add_pin_handle(msg, pin); 432 if (ret) 433 return ret; 434 if (nla_put_string(msg, DPLL_A_PIN_MODULE_NAME, 435 module_name(pin->module))) 436 return -EMSGSIZE; 437 if (nla_put_64bit(msg, DPLL_A_PIN_CLOCK_ID, sizeof(pin->clock_id), 438 &pin->clock_id, DPLL_A_PIN_PAD)) 439 return -EMSGSIZE; 440 if (prop->board_label && 441 nla_put_string(msg, DPLL_A_PIN_BOARD_LABEL, prop->board_label)) 442 return -EMSGSIZE; 443 if (prop->panel_label && 444 nla_put_string(msg, DPLL_A_PIN_PANEL_LABEL, prop->panel_label)) 445 return -EMSGSIZE; 446 if (prop->package_label && 447 nla_put_string(msg, DPLL_A_PIN_PACKAGE_LABEL, 448 prop->package_label)) 449 return -EMSGSIZE; 450 if (nla_put_u32(msg, DPLL_A_PIN_TYPE, prop->type)) 451 return -EMSGSIZE; 452 if (nla_put_u32(msg, DPLL_A_PIN_CAPABILITIES, prop->capabilities)) 453 return -EMSGSIZE; 454 ret = dpll_msg_add_pin_freq(msg, pin, ref, extack); 455 if (ret) 456 return ret; 457 if (nla_put_s32(msg, DPLL_A_PIN_PHASE_ADJUST_MIN, 458 prop->phase_range.min)) 459 return -EMSGSIZE; 460 if (nla_put_s32(msg, DPLL_A_PIN_PHASE_ADJUST_MAX, 461 prop->phase_range.max)) 462 return -EMSGSIZE; 463 ret = dpll_msg_add_pin_phase_adjust(msg, pin, ref, extack); 464 if (ret) 465 return ret; 466 ret = dpll_msg_add_ffo(msg, pin, ref, extack); 467 if (ret) 468 return ret; 469 if (xa_empty(&pin->parent_refs)) 470 ret = dpll_msg_add_pin_dplls(msg, pin, extack); 471 else 472 ret = dpll_msg_add_pin_parents(msg, pin, ref, extack); 473 474 return ret; 475 } 476 477 static int 478 dpll_device_get_one(struct dpll_device *dpll, struct sk_buff *msg, 479 struct netlink_ext_ack *extack) 480 { 481 int ret; 482 483 ret = dpll_msg_add_dev_handle(msg, dpll); 484 if (ret) 485 return ret; 486 if (nla_put_string(msg, DPLL_A_MODULE_NAME, module_name(dpll->module))) 487 return -EMSGSIZE; 488 if (nla_put_64bit(msg, DPLL_A_CLOCK_ID, sizeof(dpll->clock_id), 489 &dpll->clock_id, DPLL_A_PAD)) 490 return -EMSGSIZE; 491 ret = dpll_msg_add_temp(msg, dpll, extack); 492 if (ret) 493 return ret; 494 ret = dpll_msg_add_lock_status(msg, dpll, extack); 495 if (ret) 496 return ret; 497 ret = dpll_msg_add_mode(msg, dpll, extack); 498 if (ret) 499 return ret; 500 ret = dpll_msg_add_mode_supported(msg, dpll, extack); 501 if (ret) 502 return ret; 503 if (nla_put_u32(msg, DPLL_A_TYPE, dpll->type)) 504 return -EMSGSIZE; 505 506 return 0; 507 } 508 509 static int 510 dpll_device_event_send(enum dpll_cmd event, struct dpll_device *dpll) 511 { 512 struct sk_buff *msg; 513 int ret = -ENOMEM; 514 void *hdr; 515 516 if (WARN_ON(!xa_get_mark(&dpll_device_xa, dpll->id, DPLL_REGISTERED))) 517 return -ENODEV; 518 msg = genlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL); 519 if (!msg) 520 return -ENOMEM; 521 hdr = genlmsg_put(msg, 0, 0, &dpll_nl_family, 0, event); 522 if (!hdr) 523 goto err_free_msg; 524 ret = dpll_device_get_one(dpll, msg, NULL); 525 if (ret) 526 goto err_cancel_msg; 527 genlmsg_end(msg, hdr); 528 genlmsg_multicast(&dpll_nl_family, msg, 0, 0, GFP_KERNEL); 529 530 return 0; 531 532 err_cancel_msg: 533 genlmsg_cancel(msg, hdr); 534 err_free_msg: 535 nlmsg_free(msg); 536 537 return ret; 538 } 539 540 int dpll_device_create_ntf(struct dpll_device *dpll) 541 { 542 return dpll_device_event_send(DPLL_CMD_DEVICE_CREATE_NTF, dpll); 543 } 544 545 int dpll_device_delete_ntf(struct dpll_device *dpll) 546 { 547 return dpll_device_event_send(DPLL_CMD_DEVICE_DELETE_NTF, dpll); 548 } 549 550 static int 551 __dpll_device_change_ntf(struct dpll_device *dpll) 552 { 553 return dpll_device_event_send(DPLL_CMD_DEVICE_CHANGE_NTF, dpll); 554 } 555 556 /** 557 * dpll_device_change_ntf - notify that the dpll device has been changed 558 * @dpll: registered dpll pointer 559 * 560 * Context: acquires and holds a dpll_lock. 561 * Return: 0 if succeeds, error code otherwise. 562 */ 563 int dpll_device_change_ntf(struct dpll_device *dpll) 564 { 565 int ret; 566 567 mutex_lock(&dpll_lock); 568 ret = __dpll_device_change_ntf(dpll); 569 mutex_unlock(&dpll_lock); 570 571 return ret; 572 } 573 EXPORT_SYMBOL_GPL(dpll_device_change_ntf); 574 575 static int 576 dpll_pin_event_send(enum dpll_cmd event, struct dpll_pin *pin) 577 { 578 struct sk_buff *msg; 579 int ret = -ENOMEM; 580 void *hdr; 581 582 if (WARN_ON(!xa_get_mark(&dpll_pin_xa, pin->id, DPLL_REGISTERED))) 583 return -ENODEV; 584 585 msg = genlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL); 586 if (!msg) 587 return -ENOMEM; 588 589 hdr = genlmsg_put(msg, 0, 0, &dpll_nl_family, 0, event); 590 if (!hdr) 591 goto err_free_msg; 592 ret = dpll_cmd_pin_get_one(msg, pin, NULL); 593 if (ret) 594 goto err_cancel_msg; 595 genlmsg_end(msg, hdr); 596 genlmsg_multicast(&dpll_nl_family, msg, 0, 0, GFP_KERNEL); 597 598 return 0; 599 600 err_cancel_msg: 601 genlmsg_cancel(msg, hdr); 602 err_free_msg: 603 nlmsg_free(msg); 604 605 return ret; 606 } 607 608 int dpll_pin_create_ntf(struct dpll_pin *pin) 609 { 610 return dpll_pin_event_send(DPLL_CMD_PIN_CREATE_NTF, pin); 611 } 612 613 int dpll_pin_delete_ntf(struct dpll_pin *pin) 614 { 615 return dpll_pin_event_send(DPLL_CMD_PIN_DELETE_NTF, pin); 616 } 617 618 static int __dpll_pin_change_ntf(struct dpll_pin *pin) 619 { 620 return dpll_pin_event_send(DPLL_CMD_PIN_CHANGE_NTF, pin); 621 } 622 623 /** 624 * dpll_pin_change_ntf - notify that the pin has been changed 625 * @pin: registered pin pointer 626 * 627 * Context: acquires and holds a dpll_lock. 628 * Return: 0 if succeeds, error code otherwise. 629 */ 630 int dpll_pin_change_ntf(struct dpll_pin *pin) 631 { 632 int ret; 633 634 mutex_lock(&dpll_lock); 635 ret = __dpll_pin_change_ntf(pin); 636 mutex_unlock(&dpll_lock); 637 638 return ret; 639 } 640 EXPORT_SYMBOL_GPL(dpll_pin_change_ntf); 641 642 static int 643 dpll_pin_freq_set(struct dpll_pin *pin, struct nlattr *a, 644 struct netlink_ext_ack *extack) 645 { 646 u64 freq = nla_get_u64(a), old_freq; 647 struct dpll_pin_ref *ref, *failed; 648 const struct dpll_pin_ops *ops; 649 struct dpll_device *dpll; 650 unsigned long i; 651 int ret; 652 653 if (!dpll_pin_is_freq_supported(pin, freq)) { 654 NL_SET_ERR_MSG_ATTR(extack, a, "frequency is not supported by the device"); 655 return -EINVAL; 656 } 657 658 xa_for_each(&pin->dpll_refs, i, ref) { 659 ops = dpll_pin_ops(ref); 660 if (!ops->frequency_set || !ops->frequency_get) { 661 NL_SET_ERR_MSG(extack, "frequency set not supported by the device"); 662 return -EOPNOTSUPP; 663 } 664 } 665 ref = dpll_xa_ref_dpll_first(&pin->dpll_refs); 666 ops = dpll_pin_ops(ref); 667 dpll = ref->dpll; 668 ret = ops->frequency_get(pin, dpll_pin_on_dpll_priv(dpll, pin), dpll, 669 dpll_priv(dpll), &old_freq, extack); 670 if (ret) { 671 NL_SET_ERR_MSG(extack, "unable to get old frequency value"); 672 return ret; 673 } 674 if (freq == old_freq) 675 return 0; 676 677 xa_for_each(&pin->dpll_refs, i, ref) { 678 ops = dpll_pin_ops(ref); 679 dpll = ref->dpll; 680 ret = ops->frequency_set(pin, dpll_pin_on_dpll_priv(dpll, pin), 681 dpll, dpll_priv(dpll), freq, extack); 682 if (ret) { 683 failed = ref; 684 NL_SET_ERR_MSG_FMT(extack, "frequency set failed for dpll_id:%u", 685 dpll->id); 686 goto rollback; 687 } 688 } 689 __dpll_pin_change_ntf(pin); 690 691 return 0; 692 693 rollback: 694 xa_for_each(&pin->dpll_refs, i, ref) { 695 if (ref == failed) 696 break; 697 ops = dpll_pin_ops(ref); 698 dpll = ref->dpll; 699 if (ops->frequency_set(pin, dpll_pin_on_dpll_priv(dpll, pin), 700 dpll, dpll_priv(dpll), old_freq, extack)) 701 NL_SET_ERR_MSG(extack, "set frequency rollback failed"); 702 } 703 return ret; 704 } 705 706 static int 707 dpll_pin_on_pin_state_set(struct dpll_pin *pin, u32 parent_idx, 708 enum dpll_pin_state state, 709 struct netlink_ext_ack *extack) 710 { 711 struct dpll_pin_ref *parent_ref; 712 const struct dpll_pin_ops *ops; 713 struct dpll_pin_ref *dpll_ref; 714 void *pin_priv, *parent_priv; 715 struct dpll_pin *parent; 716 unsigned long i; 717 int ret; 718 719 if (!(DPLL_PIN_CAPABILITIES_STATE_CAN_CHANGE & 720 pin->prop->capabilities)) { 721 NL_SET_ERR_MSG(extack, "state changing is not allowed"); 722 return -EOPNOTSUPP; 723 } 724 parent = xa_load(&dpll_pin_xa, parent_idx); 725 if (!parent) 726 return -EINVAL; 727 parent_ref = xa_load(&pin->parent_refs, parent->pin_idx); 728 if (!parent_ref) 729 return -EINVAL; 730 xa_for_each(&parent->dpll_refs, i, dpll_ref) { 731 ops = dpll_pin_ops(parent_ref); 732 if (!ops->state_on_pin_set) 733 return -EOPNOTSUPP; 734 pin_priv = dpll_pin_on_pin_priv(parent, pin); 735 parent_priv = dpll_pin_on_dpll_priv(dpll_ref->dpll, parent); 736 ret = ops->state_on_pin_set(pin, pin_priv, parent, parent_priv, 737 state, extack); 738 if (ret) 739 return ret; 740 } 741 __dpll_pin_change_ntf(pin); 742 743 return 0; 744 } 745 746 static int 747 dpll_pin_state_set(struct dpll_device *dpll, struct dpll_pin *pin, 748 enum dpll_pin_state state, 749 struct netlink_ext_ack *extack) 750 { 751 const struct dpll_pin_ops *ops; 752 struct dpll_pin_ref *ref; 753 int ret; 754 755 if (!(DPLL_PIN_CAPABILITIES_STATE_CAN_CHANGE & 756 pin->prop->capabilities)) { 757 NL_SET_ERR_MSG(extack, "state changing is not allowed"); 758 return -EOPNOTSUPP; 759 } 760 ref = xa_load(&pin->dpll_refs, dpll->id); 761 ASSERT_NOT_NULL(ref); 762 ops = dpll_pin_ops(ref); 763 if (!ops->state_on_dpll_set) 764 return -EOPNOTSUPP; 765 ret = ops->state_on_dpll_set(pin, dpll_pin_on_dpll_priv(dpll, pin), 766 dpll, dpll_priv(dpll), state, extack); 767 if (ret) 768 return ret; 769 __dpll_pin_change_ntf(pin); 770 771 return 0; 772 } 773 774 static int 775 dpll_pin_prio_set(struct dpll_device *dpll, struct dpll_pin *pin, 776 u32 prio, struct netlink_ext_ack *extack) 777 { 778 const struct dpll_pin_ops *ops; 779 struct dpll_pin_ref *ref; 780 int ret; 781 782 if (!(DPLL_PIN_CAPABILITIES_PRIORITY_CAN_CHANGE & 783 pin->prop->capabilities)) { 784 NL_SET_ERR_MSG(extack, "prio changing is not allowed"); 785 return -EOPNOTSUPP; 786 } 787 ref = xa_load(&pin->dpll_refs, dpll->id); 788 ASSERT_NOT_NULL(ref); 789 ops = dpll_pin_ops(ref); 790 if (!ops->prio_set) 791 return -EOPNOTSUPP; 792 ret = ops->prio_set(pin, dpll_pin_on_dpll_priv(dpll, pin), dpll, 793 dpll_priv(dpll), prio, extack); 794 if (ret) 795 return ret; 796 __dpll_pin_change_ntf(pin); 797 798 return 0; 799 } 800 801 static int 802 dpll_pin_direction_set(struct dpll_pin *pin, struct dpll_device *dpll, 803 enum dpll_pin_direction direction, 804 struct netlink_ext_ack *extack) 805 { 806 const struct dpll_pin_ops *ops; 807 struct dpll_pin_ref *ref; 808 int ret; 809 810 if (!(DPLL_PIN_CAPABILITIES_DIRECTION_CAN_CHANGE & 811 pin->prop->capabilities)) { 812 NL_SET_ERR_MSG(extack, "direction changing is not allowed"); 813 return -EOPNOTSUPP; 814 } 815 ref = xa_load(&pin->dpll_refs, dpll->id); 816 ASSERT_NOT_NULL(ref); 817 ops = dpll_pin_ops(ref); 818 if (!ops->direction_set) 819 return -EOPNOTSUPP; 820 ret = ops->direction_set(pin, dpll_pin_on_dpll_priv(dpll, pin), 821 dpll, dpll_priv(dpll), direction, extack); 822 if (ret) 823 return ret; 824 __dpll_pin_change_ntf(pin); 825 826 return 0; 827 } 828 829 static int 830 dpll_pin_phase_adj_set(struct dpll_pin *pin, struct nlattr *phase_adj_attr, 831 struct netlink_ext_ack *extack) 832 { 833 struct dpll_pin_ref *ref, *failed; 834 const struct dpll_pin_ops *ops; 835 s32 phase_adj, old_phase_adj; 836 struct dpll_device *dpll; 837 unsigned long i; 838 int ret; 839 840 phase_adj = nla_get_s32(phase_adj_attr); 841 if (phase_adj > pin->prop->phase_range.max || 842 phase_adj < pin->prop->phase_range.min) { 843 NL_SET_ERR_MSG_ATTR(extack, phase_adj_attr, 844 "phase adjust value not supported"); 845 return -EINVAL; 846 } 847 848 xa_for_each(&pin->dpll_refs, i, ref) { 849 ops = dpll_pin_ops(ref); 850 if (!ops->phase_adjust_set || !ops->phase_adjust_get) { 851 NL_SET_ERR_MSG(extack, "phase adjust not supported"); 852 return -EOPNOTSUPP; 853 } 854 } 855 ref = dpll_xa_ref_dpll_first(&pin->dpll_refs); 856 ops = dpll_pin_ops(ref); 857 dpll = ref->dpll; 858 ret = ops->phase_adjust_get(pin, dpll_pin_on_dpll_priv(dpll, pin), 859 dpll, dpll_priv(dpll), &old_phase_adj, 860 extack); 861 if (ret) { 862 NL_SET_ERR_MSG(extack, "unable to get old phase adjust value"); 863 return ret; 864 } 865 if (phase_adj == old_phase_adj) 866 return 0; 867 868 xa_for_each(&pin->dpll_refs, i, ref) { 869 ops = dpll_pin_ops(ref); 870 dpll = ref->dpll; 871 ret = ops->phase_adjust_set(pin, 872 dpll_pin_on_dpll_priv(dpll, pin), 873 dpll, dpll_priv(dpll), phase_adj, 874 extack); 875 if (ret) { 876 failed = ref; 877 NL_SET_ERR_MSG_FMT(extack, 878 "phase adjust set failed for dpll_id:%u", 879 dpll->id); 880 goto rollback; 881 } 882 } 883 __dpll_pin_change_ntf(pin); 884 885 return 0; 886 887 rollback: 888 xa_for_each(&pin->dpll_refs, i, ref) { 889 if (ref == failed) 890 break; 891 ops = dpll_pin_ops(ref); 892 dpll = ref->dpll; 893 if (ops->phase_adjust_set(pin, dpll_pin_on_dpll_priv(dpll, pin), 894 dpll, dpll_priv(dpll), old_phase_adj, 895 extack)) 896 NL_SET_ERR_MSG(extack, "set phase adjust rollback failed"); 897 } 898 return ret; 899 } 900 901 static int 902 dpll_pin_parent_device_set(struct dpll_pin *pin, struct nlattr *parent_nest, 903 struct netlink_ext_ack *extack) 904 { 905 struct nlattr *tb[DPLL_A_PIN_MAX + 1]; 906 enum dpll_pin_direction direction; 907 enum dpll_pin_state state; 908 struct dpll_pin_ref *ref; 909 struct dpll_device *dpll; 910 u32 pdpll_idx, prio; 911 int ret; 912 913 nla_parse_nested(tb, DPLL_A_PIN_MAX, parent_nest, 914 dpll_pin_parent_device_nl_policy, extack); 915 if (!tb[DPLL_A_PIN_PARENT_ID]) { 916 NL_SET_ERR_MSG(extack, "device parent id expected"); 917 return -EINVAL; 918 } 919 pdpll_idx = nla_get_u32(tb[DPLL_A_PIN_PARENT_ID]); 920 dpll = xa_load(&dpll_device_xa, pdpll_idx); 921 if (!dpll) { 922 NL_SET_ERR_MSG(extack, "parent device not found"); 923 return -EINVAL; 924 } 925 ref = xa_load(&pin->dpll_refs, dpll->id); 926 if (!ref) { 927 NL_SET_ERR_MSG(extack, "pin not connected to given parent device"); 928 return -EINVAL; 929 } 930 if (tb[DPLL_A_PIN_STATE]) { 931 state = nla_get_u32(tb[DPLL_A_PIN_STATE]); 932 ret = dpll_pin_state_set(dpll, pin, state, extack); 933 if (ret) 934 return ret; 935 } 936 if (tb[DPLL_A_PIN_PRIO]) { 937 prio = nla_get_u32(tb[DPLL_A_PIN_PRIO]); 938 ret = dpll_pin_prio_set(dpll, pin, prio, extack); 939 if (ret) 940 return ret; 941 } 942 if (tb[DPLL_A_PIN_DIRECTION]) { 943 direction = nla_get_u32(tb[DPLL_A_PIN_DIRECTION]); 944 ret = dpll_pin_direction_set(pin, dpll, direction, extack); 945 if (ret) 946 return ret; 947 } 948 return 0; 949 } 950 951 static int 952 dpll_pin_parent_pin_set(struct dpll_pin *pin, struct nlattr *parent_nest, 953 struct netlink_ext_ack *extack) 954 { 955 struct nlattr *tb[DPLL_A_PIN_MAX + 1]; 956 u32 ppin_idx; 957 int ret; 958 959 nla_parse_nested(tb, DPLL_A_PIN_MAX, parent_nest, 960 dpll_pin_parent_pin_nl_policy, extack); 961 if (!tb[DPLL_A_PIN_PARENT_ID]) { 962 NL_SET_ERR_MSG(extack, "device parent id expected"); 963 return -EINVAL; 964 } 965 ppin_idx = nla_get_u32(tb[DPLL_A_PIN_PARENT_ID]); 966 967 if (tb[DPLL_A_PIN_STATE]) { 968 enum dpll_pin_state state = nla_get_u32(tb[DPLL_A_PIN_STATE]); 969 970 ret = dpll_pin_on_pin_state_set(pin, ppin_idx, state, extack); 971 if (ret) 972 return ret; 973 } 974 975 return 0; 976 } 977 978 static int 979 dpll_pin_set_from_nlattr(struct dpll_pin *pin, struct genl_info *info) 980 { 981 struct nlattr *a; 982 int rem, ret; 983 984 nla_for_each_attr(a, genlmsg_data(info->genlhdr), 985 genlmsg_len(info->genlhdr), rem) { 986 switch (nla_type(a)) { 987 case DPLL_A_PIN_FREQUENCY: 988 ret = dpll_pin_freq_set(pin, a, info->extack); 989 if (ret) 990 return ret; 991 break; 992 case DPLL_A_PIN_PHASE_ADJUST: 993 ret = dpll_pin_phase_adj_set(pin, a, info->extack); 994 if (ret) 995 return ret; 996 break; 997 case DPLL_A_PIN_PARENT_DEVICE: 998 ret = dpll_pin_parent_device_set(pin, a, info->extack); 999 if (ret) 1000 return ret; 1001 break; 1002 case DPLL_A_PIN_PARENT_PIN: 1003 ret = dpll_pin_parent_pin_set(pin, a, info->extack); 1004 if (ret) 1005 return ret; 1006 break; 1007 } 1008 } 1009 1010 return 0; 1011 } 1012 1013 static struct dpll_pin * 1014 dpll_pin_find(u64 clock_id, struct nlattr *mod_name_attr, 1015 enum dpll_pin_type type, struct nlattr *board_label, 1016 struct nlattr *panel_label, struct nlattr *package_label, 1017 struct netlink_ext_ack *extack) 1018 { 1019 bool board_match, panel_match, package_match; 1020 struct dpll_pin *pin_match = NULL, *pin; 1021 const struct dpll_pin_properties *prop; 1022 bool cid_match, mod_match, type_match; 1023 unsigned long i; 1024 1025 xa_for_each_marked(&dpll_pin_xa, i, pin, DPLL_REGISTERED) { 1026 prop = pin->prop; 1027 cid_match = clock_id ? pin->clock_id == clock_id : true; 1028 mod_match = mod_name_attr && module_name(pin->module) ? 1029 !nla_strcmp(mod_name_attr, 1030 module_name(pin->module)) : true; 1031 type_match = type ? prop->type == type : true; 1032 board_match = board_label ? (prop->board_label ? 1033 !nla_strcmp(board_label, prop->board_label) : false) : 1034 true; 1035 panel_match = panel_label ? (prop->panel_label ? 1036 !nla_strcmp(panel_label, prop->panel_label) : false) : 1037 true; 1038 package_match = package_label ? (prop->package_label ? 1039 !nla_strcmp(package_label, prop->package_label) : 1040 false) : true; 1041 if (cid_match && mod_match && type_match && board_match && 1042 panel_match && package_match) { 1043 if (pin_match) { 1044 NL_SET_ERR_MSG(extack, "multiple matches"); 1045 return ERR_PTR(-EINVAL); 1046 } 1047 pin_match = pin; 1048 } 1049 } 1050 if (!pin_match) { 1051 NL_SET_ERR_MSG(extack, "not found"); 1052 return ERR_PTR(-ENODEV); 1053 } 1054 return pin_match; 1055 } 1056 1057 static struct dpll_pin *dpll_pin_find_from_nlattr(struct genl_info *info) 1058 { 1059 struct nlattr *attr, *mod_name_attr = NULL, *board_label_attr = NULL, 1060 *panel_label_attr = NULL, *package_label_attr = NULL; 1061 enum dpll_pin_type type = 0; 1062 u64 clock_id = 0; 1063 int rem = 0; 1064 1065 nla_for_each_attr(attr, genlmsg_data(info->genlhdr), 1066 genlmsg_len(info->genlhdr), rem) { 1067 switch (nla_type(attr)) { 1068 case DPLL_A_PIN_CLOCK_ID: 1069 if (clock_id) 1070 goto duplicated_attr; 1071 clock_id = nla_get_u64(attr); 1072 break; 1073 case DPLL_A_PIN_MODULE_NAME: 1074 if (mod_name_attr) 1075 goto duplicated_attr; 1076 mod_name_attr = attr; 1077 break; 1078 case DPLL_A_PIN_TYPE: 1079 if (type) 1080 goto duplicated_attr; 1081 type = nla_get_u32(attr); 1082 break; 1083 case DPLL_A_PIN_BOARD_LABEL: 1084 if (board_label_attr) 1085 goto duplicated_attr; 1086 board_label_attr = attr; 1087 break; 1088 case DPLL_A_PIN_PANEL_LABEL: 1089 if (panel_label_attr) 1090 goto duplicated_attr; 1091 panel_label_attr = attr; 1092 break; 1093 case DPLL_A_PIN_PACKAGE_LABEL: 1094 if (package_label_attr) 1095 goto duplicated_attr; 1096 package_label_attr = attr; 1097 break; 1098 default: 1099 break; 1100 } 1101 } 1102 if (!(clock_id || mod_name_attr || board_label_attr || 1103 panel_label_attr || package_label_attr)) { 1104 NL_SET_ERR_MSG(info->extack, "missing attributes"); 1105 return ERR_PTR(-EINVAL); 1106 } 1107 return dpll_pin_find(clock_id, mod_name_attr, type, board_label_attr, 1108 panel_label_attr, package_label_attr, 1109 info->extack); 1110 duplicated_attr: 1111 NL_SET_ERR_MSG(info->extack, "duplicated attribute"); 1112 return ERR_PTR(-EINVAL); 1113 } 1114 1115 int dpll_nl_pin_id_get_doit(struct sk_buff *skb, struct genl_info *info) 1116 { 1117 struct dpll_pin *pin; 1118 struct sk_buff *msg; 1119 struct nlattr *hdr; 1120 int ret; 1121 1122 msg = genlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL); 1123 if (!msg) 1124 return -ENOMEM; 1125 hdr = genlmsg_put_reply(msg, info, &dpll_nl_family, 0, 1126 DPLL_CMD_PIN_ID_GET); 1127 if (!hdr) { 1128 nlmsg_free(msg); 1129 return -EMSGSIZE; 1130 } 1131 pin = dpll_pin_find_from_nlattr(info); 1132 if (!IS_ERR(pin)) { 1133 ret = dpll_msg_add_pin_handle(msg, pin); 1134 if (ret) { 1135 nlmsg_free(msg); 1136 return ret; 1137 } 1138 } 1139 genlmsg_end(msg, hdr); 1140 1141 return genlmsg_reply(msg, info); 1142 } 1143 1144 int dpll_nl_pin_get_doit(struct sk_buff *skb, struct genl_info *info) 1145 { 1146 struct dpll_pin *pin = info->user_ptr[0]; 1147 struct sk_buff *msg; 1148 struct nlattr *hdr; 1149 int ret; 1150 1151 if (!pin) 1152 return -ENODEV; 1153 msg = genlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL); 1154 if (!msg) 1155 return -ENOMEM; 1156 hdr = genlmsg_put_reply(msg, info, &dpll_nl_family, 0, 1157 DPLL_CMD_PIN_GET); 1158 if (!hdr) { 1159 nlmsg_free(msg); 1160 return -EMSGSIZE; 1161 } 1162 ret = dpll_cmd_pin_get_one(msg, pin, info->extack); 1163 if (ret) { 1164 nlmsg_free(msg); 1165 return ret; 1166 } 1167 genlmsg_end(msg, hdr); 1168 1169 return genlmsg_reply(msg, info); 1170 } 1171 1172 int dpll_nl_pin_get_dumpit(struct sk_buff *skb, struct netlink_callback *cb) 1173 { 1174 struct dpll_dump_ctx *ctx = dpll_dump_context(cb); 1175 struct dpll_pin *pin; 1176 struct nlattr *hdr; 1177 unsigned long i; 1178 int ret = 0; 1179 1180 xa_for_each_marked_start(&dpll_pin_xa, i, pin, DPLL_REGISTERED, 1181 ctx->idx) { 1182 hdr = genlmsg_put(skb, NETLINK_CB(cb->skb).portid, 1183 cb->nlh->nlmsg_seq, 1184 &dpll_nl_family, NLM_F_MULTI, 1185 DPLL_CMD_PIN_GET); 1186 if (!hdr) { 1187 ret = -EMSGSIZE; 1188 break; 1189 } 1190 ret = dpll_cmd_pin_get_one(skb, pin, cb->extack); 1191 if (ret) { 1192 genlmsg_cancel(skb, hdr); 1193 break; 1194 } 1195 genlmsg_end(skb, hdr); 1196 } 1197 if (ret == -EMSGSIZE) { 1198 ctx->idx = i; 1199 return skb->len; 1200 } 1201 return ret; 1202 } 1203 1204 int dpll_nl_pin_set_doit(struct sk_buff *skb, struct genl_info *info) 1205 { 1206 struct dpll_pin *pin = info->user_ptr[0]; 1207 1208 return dpll_pin_set_from_nlattr(pin, info); 1209 } 1210 1211 static struct dpll_device * 1212 dpll_device_find(u64 clock_id, struct nlattr *mod_name_attr, 1213 enum dpll_type type, struct netlink_ext_ack *extack) 1214 { 1215 struct dpll_device *dpll_match = NULL, *dpll; 1216 bool cid_match, mod_match, type_match; 1217 unsigned long i; 1218 1219 xa_for_each_marked(&dpll_device_xa, i, dpll, DPLL_REGISTERED) { 1220 cid_match = clock_id ? dpll->clock_id == clock_id : true; 1221 mod_match = mod_name_attr ? (module_name(dpll->module) ? 1222 !nla_strcmp(mod_name_attr, 1223 module_name(dpll->module)) : false) : true; 1224 type_match = type ? dpll->type == type : true; 1225 if (cid_match && mod_match && type_match) { 1226 if (dpll_match) { 1227 NL_SET_ERR_MSG(extack, "multiple matches"); 1228 return ERR_PTR(-EINVAL); 1229 } 1230 dpll_match = dpll; 1231 } 1232 } 1233 if (!dpll_match) { 1234 NL_SET_ERR_MSG(extack, "not found"); 1235 return ERR_PTR(-ENODEV); 1236 } 1237 1238 return dpll_match; 1239 } 1240 1241 static struct dpll_device * 1242 dpll_device_find_from_nlattr(struct genl_info *info) 1243 { 1244 struct nlattr *attr, *mod_name_attr = NULL; 1245 enum dpll_type type = 0; 1246 u64 clock_id = 0; 1247 int rem = 0; 1248 1249 nla_for_each_attr(attr, genlmsg_data(info->genlhdr), 1250 genlmsg_len(info->genlhdr), rem) { 1251 switch (nla_type(attr)) { 1252 case DPLL_A_CLOCK_ID: 1253 if (clock_id) 1254 goto duplicated_attr; 1255 clock_id = nla_get_u64(attr); 1256 break; 1257 case DPLL_A_MODULE_NAME: 1258 if (mod_name_attr) 1259 goto duplicated_attr; 1260 mod_name_attr = attr; 1261 break; 1262 case DPLL_A_TYPE: 1263 if (type) 1264 goto duplicated_attr; 1265 type = nla_get_u32(attr); 1266 break; 1267 default: 1268 break; 1269 } 1270 } 1271 if (!clock_id && !mod_name_attr && !type) { 1272 NL_SET_ERR_MSG(info->extack, "missing attributes"); 1273 return ERR_PTR(-EINVAL); 1274 } 1275 return dpll_device_find(clock_id, mod_name_attr, type, info->extack); 1276 duplicated_attr: 1277 NL_SET_ERR_MSG(info->extack, "duplicated attribute"); 1278 return ERR_PTR(-EINVAL); 1279 } 1280 1281 int dpll_nl_device_id_get_doit(struct sk_buff *skb, struct genl_info *info) 1282 { 1283 struct dpll_device *dpll; 1284 struct sk_buff *msg; 1285 struct nlattr *hdr; 1286 int ret; 1287 1288 msg = genlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL); 1289 if (!msg) 1290 return -ENOMEM; 1291 hdr = genlmsg_put_reply(msg, info, &dpll_nl_family, 0, 1292 DPLL_CMD_DEVICE_ID_GET); 1293 if (!hdr) { 1294 nlmsg_free(msg); 1295 return -EMSGSIZE; 1296 } 1297 1298 dpll = dpll_device_find_from_nlattr(info); 1299 if (!IS_ERR(dpll)) { 1300 ret = dpll_msg_add_dev_handle(msg, dpll); 1301 if (ret) { 1302 nlmsg_free(msg); 1303 return ret; 1304 } 1305 } 1306 genlmsg_end(msg, hdr); 1307 1308 return genlmsg_reply(msg, info); 1309 } 1310 1311 int dpll_nl_device_get_doit(struct sk_buff *skb, struct genl_info *info) 1312 { 1313 struct dpll_device *dpll = info->user_ptr[0]; 1314 struct sk_buff *msg; 1315 struct nlattr *hdr; 1316 int ret; 1317 1318 msg = genlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL); 1319 if (!msg) 1320 return -ENOMEM; 1321 hdr = genlmsg_put_reply(msg, info, &dpll_nl_family, 0, 1322 DPLL_CMD_DEVICE_GET); 1323 if (!hdr) { 1324 nlmsg_free(msg); 1325 return -EMSGSIZE; 1326 } 1327 1328 ret = dpll_device_get_one(dpll, msg, info->extack); 1329 if (ret) { 1330 nlmsg_free(msg); 1331 return ret; 1332 } 1333 genlmsg_end(msg, hdr); 1334 1335 return genlmsg_reply(msg, info); 1336 } 1337 1338 int dpll_nl_device_set_doit(struct sk_buff *skb, struct genl_info *info) 1339 { 1340 /* placeholder for set command */ 1341 return 0; 1342 } 1343 1344 int dpll_nl_device_get_dumpit(struct sk_buff *skb, struct netlink_callback *cb) 1345 { 1346 struct dpll_dump_ctx *ctx = dpll_dump_context(cb); 1347 struct dpll_device *dpll; 1348 struct nlattr *hdr; 1349 unsigned long i; 1350 int ret = 0; 1351 1352 xa_for_each_marked_start(&dpll_device_xa, i, dpll, DPLL_REGISTERED, 1353 ctx->idx) { 1354 hdr = genlmsg_put(skb, NETLINK_CB(cb->skb).portid, 1355 cb->nlh->nlmsg_seq, &dpll_nl_family, 1356 NLM_F_MULTI, DPLL_CMD_DEVICE_GET); 1357 if (!hdr) { 1358 ret = -EMSGSIZE; 1359 break; 1360 } 1361 ret = dpll_device_get_one(dpll, skb, cb->extack); 1362 if (ret) { 1363 genlmsg_cancel(skb, hdr); 1364 break; 1365 } 1366 genlmsg_end(skb, hdr); 1367 } 1368 if (ret == -EMSGSIZE) { 1369 ctx->idx = i; 1370 return skb->len; 1371 } 1372 return ret; 1373 } 1374 1375 int dpll_pre_doit(const struct genl_split_ops *ops, struct sk_buff *skb, 1376 struct genl_info *info) 1377 { 1378 u32 id; 1379 1380 if (GENL_REQ_ATTR_CHECK(info, DPLL_A_ID)) 1381 return -EINVAL; 1382 1383 mutex_lock(&dpll_lock); 1384 id = nla_get_u32(info->attrs[DPLL_A_ID]); 1385 info->user_ptr[0] = dpll_device_get_by_id(id); 1386 if (!info->user_ptr[0]) { 1387 NL_SET_ERR_MSG(info->extack, "device not found"); 1388 goto unlock; 1389 } 1390 return 0; 1391 unlock: 1392 mutex_unlock(&dpll_lock); 1393 return -ENODEV; 1394 } 1395 1396 void dpll_post_doit(const struct genl_split_ops *ops, struct sk_buff *skb, 1397 struct genl_info *info) 1398 { 1399 mutex_unlock(&dpll_lock); 1400 } 1401 1402 int 1403 dpll_lock_doit(const struct genl_split_ops *ops, struct sk_buff *skb, 1404 struct genl_info *info) 1405 { 1406 mutex_lock(&dpll_lock); 1407 1408 return 0; 1409 } 1410 1411 void 1412 dpll_unlock_doit(const struct genl_split_ops *ops, struct sk_buff *skb, 1413 struct genl_info *info) 1414 { 1415 mutex_unlock(&dpll_lock); 1416 } 1417 1418 int dpll_lock_dumpit(struct netlink_callback *cb) 1419 { 1420 mutex_lock(&dpll_lock); 1421 1422 return 0; 1423 } 1424 1425 int dpll_unlock_dumpit(struct netlink_callback *cb) 1426 { 1427 mutex_unlock(&dpll_lock); 1428 1429 return 0; 1430 } 1431 1432 int dpll_pin_pre_doit(const struct genl_split_ops *ops, struct sk_buff *skb, 1433 struct genl_info *info) 1434 { 1435 int ret; 1436 1437 mutex_lock(&dpll_lock); 1438 if (GENL_REQ_ATTR_CHECK(info, DPLL_A_PIN_ID)) { 1439 ret = -EINVAL; 1440 goto unlock_dev; 1441 } 1442 info->user_ptr[0] = xa_load(&dpll_pin_xa, 1443 nla_get_u32(info->attrs[DPLL_A_PIN_ID])); 1444 if (!info->user_ptr[0]) { 1445 NL_SET_ERR_MSG(info->extack, "pin not found"); 1446 ret = -ENODEV; 1447 goto unlock_dev; 1448 } 1449 1450 return 0; 1451 1452 unlock_dev: 1453 mutex_unlock(&dpll_lock); 1454 return ret; 1455 } 1456 1457 void dpll_pin_post_doit(const struct genl_split_ops *ops, struct sk_buff *skb, 1458 struct genl_info *info) 1459 { 1460 mutex_unlock(&dpll_lock); 1461 } 1462