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