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 u32 ppin_idx; 933 int ret; 934 935 nla_parse_nested(tb, DPLL_A_PIN_MAX, parent_nest, 936 dpll_pin_parent_pin_nl_policy, extack); 937 if (!tb[DPLL_A_PIN_PARENT_ID]) { 938 NL_SET_ERR_MSG(extack, "device parent id expected"); 939 return -EINVAL; 940 } 941 ppin_idx = nla_get_u32(tb[DPLL_A_PIN_PARENT_ID]); 942 943 if (tb[DPLL_A_PIN_STATE]) { 944 enum dpll_pin_state state = nla_get_u32(tb[DPLL_A_PIN_STATE]); 945 946 ret = dpll_pin_on_pin_state_set(pin, ppin_idx, state, extack); 947 if (ret) 948 return ret; 949 } 950 951 return 0; 952 } 953 954 static int 955 dpll_pin_set_from_nlattr(struct dpll_pin *pin, struct genl_info *info) 956 { 957 struct nlattr *a; 958 int rem, ret; 959 960 nla_for_each_attr(a, genlmsg_data(info->genlhdr), 961 genlmsg_len(info->genlhdr), rem) { 962 switch (nla_type(a)) { 963 case DPLL_A_PIN_FREQUENCY: 964 ret = dpll_pin_freq_set(pin, a, info->extack); 965 if (ret) 966 return ret; 967 break; 968 case DPLL_A_PIN_PHASE_ADJUST: 969 ret = dpll_pin_phase_adj_set(pin, a, info->extack); 970 if (ret) 971 return ret; 972 break; 973 case DPLL_A_PIN_PARENT_DEVICE: 974 ret = dpll_pin_parent_device_set(pin, a, info->extack); 975 if (ret) 976 return ret; 977 break; 978 case DPLL_A_PIN_PARENT_PIN: 979 ret = dpll_pin_parent_pin_set(pin, a, info->extack); 980 if (ret) 981 return ret; 982 break; 983 } 984 } 985 986 return 0; 987 } 988 989 static struct dpll_pin * 990 dpll_pin_find(u64 clock_id, struct nlattr *mod_name_attr, 991 enum dpll_pin_type type, struct nlattr *board_label, 992 struct nlattr *panel_label, struct nlattr *package_label, 993 struct netlink_ext_ack *extack) 994 { 995 bool board_match, panel_match, package_match; 996 struct dpll_pin *pin_match = NULL, *pin; 997 const struct dpll_pin_properties *prop; 998 bool cid_match, mod_match, type_match; 999 unsigned long i; 1000 1001 xa_for_each_marked(&dpll_pin_xa, i, pin, DPLL_REGISTERED) { 1002 prop = pin->prop; 1003 cid_match = clock_id ? pin->clock_id == clock_id : true; 1004 mod_match = mod_name_attr && module_name(pin->module) ? 1005 !nla_strcmp(mod_name_attr, 1006 module_name(pin->module)) : true; 1007 type_match = type ? prop->type == type : true; 1008 board_match = board_label ? (prop->board_label ? 1009 !nla_strcmp(board_label, prop->board_label) : false) : 1010 true; 1011 panel_match = panel_label ? (prop->panel_label ? 1012 !nla_strcmp(panel_label, prop->panel_label) : false) : 1013 true; 1014 package_match = package_label ? (prop->package_label ? 1015 !nla_strcmp(package_label, prop->package_label) : 1016 false) : true; 1017 if (cid_match && mod_match && type_match && board_match && 1018 panel_match && package_match) { 1019 if (pin_match) { 1020 NL_SET_ERR_MSG(extack, "multiple matches"); 1021 return ERR_PTR(-EINVAL); 1022 } 1023 pin_match = pin; 1024 } 1025 } 1026 if (!pin_match) { 1027 NL_SET_ERR_MSG(extack, "not found"); 1028 return ERR_PTR(-ENODEV); 1029 } 1030 return pin_match; 1031 } 1032 1033 static struct dpll_pin *dpll_pin_find_from_nlattr(struct genl_info *info) 1034 { 1035 struct nlattr *attr, *mod_name_attr = NULL, *board_label_attr = NULL, 1036 *panel_label_attr = NULL, *package_label_attr = NULL; 1037 enum dpll_pin_type type = 0; 1038 u64 clock_id = 0; 1039 int rem = 0; 1040 1041 nla_for_each_attr(attr, genlmsg_data(info->genlhdr), 1042 genlmsg_len(info->genlhdr), rem) { 1043 switch (nla_type(attr)) { 1044 case DPLL_A_PIN_CLOCK_ID: 1045 if (clock_id) 1046 goto duplicated_attr; 1047 clock_id = nla_get_u64(attr); 1048 break; 1049 case DPLL_A_PIN_MODULE_NAME: 1050 if (mod_name_attr) 1051 goto duplicated_attr; 1052 mod_name_attr = attr; 1053 break; 1054 case DPLL_A_PIN_TYPE: 1055 if (type) 1056 goto duplicated_attr; 1057 type = nla_get_u32(attr); 1058 break; 1059 case DPLL_A_PIN_BOARD_LABEL: 1060 if (board_label_attr) 1061 goto duplicated_attr; 1062 board_label_attr = attr; 1063 break; 1064 case DPLL_A_PIN_PANEL_LABEL: 1065 if (panel_label_attr) 1066 goto duplicated_attr; 1067 panel_label_attr = attr; 1068 break; 1069 case DPLL_A_PIN_PACKAGE_LABEL: 1070 if (package_label_attr) 1071 goto duplicated_attr; 1072 package_label_attr = attr; 1073 break; 1074 default: 1075 break; 1076 } 1077 } 1078 if (!(clock_id || mod_name_attr || board_label_attr || 1079 panel_label_attr || package_label_attr)) { 1080 NL_SET_ERR_MSG(info->extack, "missing attributes"); 1081 return ERR_PTR(-EINVAL); 1082 } 1083 return dpll_pin_find(clock_id, mod_name_attr, type, board_label_attr, 1084 panel_label_attr, package_label_attr, 1085 info->extack); 1086 duplicated_attr: 1087 NL_SET_ERR_MSG(info->extack, "duplicated attribute"); 1088 return ERR_PTR(-EINVAL); 1089 } 1090 1091 int dpll_nl_pin_id_get_doit(struct sk_buff *skb, struct genl_info *info) 1092 { 1093 struct dpll_pin *pin; 1094 struct sk_buff *msg; 1095 struct nlattr *hdr; 1096 int ret; 1097 1098 msg = genlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL); 1099 if (!msg) 1100 return -ENOMEM; 1101 hdr = genlmsg_put_reply(msg, info, &dpll_nl_family, 0, 1102 DPLL_CMD_PIN_ID_GET); 1103 if (!hdr) { 1104 nlmsg_free(msg); 1105 return -EMSGSIZE; 1106 } 1107 pin = dpll_pin_find_from_nlattr(info); 1108 if (!IS_ERR(pin)) { 1109 ret = dpll_msg_add_pin_handle(msg, pin); 1110 if (ret) { 1111 nlmsg_free(msg); 1112 return ret; 1113 } 1114 } 1115 genlmsg_end(msg, hdr); 1116 1117 return genlmsg_reply(msg, info); 1118 } 1119 1120 int dpll_nl_pin_get_doit(struct sk_buff *skb, struct genl_info *info) 1121 { 1122 struct dpll_pin *pin = info->user_ptr[0]; 1123 struct sk_buff *msg; 1124 struct nlattr *hdr; 1125 int ret; 1126 1127 if (!pin) 1128 return -ENODEV; 1129 msg = genlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL); 1130 if (!msg) 1131 return -ENOMEM; 1132 hdr = genlmsg_put_reply(msg, info, &dpll_nl_family, 0, 1133 DPLL_CMD_PIN_GET); 1134 if (!hdr) { 1135 nlmsg_free(msg); 1136 return -EMSGSIZE; 1137 } 1138 ret = dpll_cmd_pin_get_one(msg, pin, info->extack); 1139 if (ret) { 1140 nlmsg_free(msg); 1141 return ret; 1142 } 1143 genlmsg_end(msg, hdr); 1144 1145 return genlmsg_reply(msg, info); 1146 } 1147 1148 int dpll_nl_pin_get_dumpit(struct sk_buff *skb, struct netlink_callback *cb) 1149 { 1150 struct dpll_dump_ctx *ctx = dpll_dump_context(cb); 1151 struct dpll_pin *pin; 1152 struct nlattr *hdr; 1153 unsigned long i; 1154 int ret = 0; 1155 1156 xa_for_each_marked_start(&dpll_pin_xa, i, pin, DPLL_REGISTERED, 1157 ctx->idx) { 1158 hdr = genlmsg_put(skb, NETLINK_CB(cb->skb).portid, 1159 cb->nlh->nlmsg_seq, 1160 &dpll_nl_family, NLM_F_MULTI, 1161 DPLL_CMD_PIN_GET); 1162 if (!hdr) { 1163 ret = -EMSGSIZE; 1164 break; 1165 } 1166 ret = dpll_cmd_pin_get_one(skb, pin, cb->extack); 1167 if (ret) { 1168 genlmsg_cancel(skb, hdr); 1169 break; 1170 } 1171 genlmsg_end(skb, hdr); 1172 } 1173 if (ret == -EMSGSIZE) { 1174 ctx->idx = i; 1175 return skb->len; 1176 } 1177 return ret; 1178 } 1179 1180 int dpll_nl_pin_set_doit(struct sk_buff *skb, struct genl_info *info) 1181 { 1182 struct dpll_pin *pin = info->user_ptr[0]; 1183 1184 return dpll_pin_set_from_nlattr(pin, info); 1185 } 1186 1187 static struct dpll_device * 1188 dpll_device_find(u64 clock_id, struct nlattr *mod_name_attr, 1189 enum dpll_type type, struct netlink_ext_ack *extack) 1190 { 1191 struct dpll_device *dpll_match = NULL, *dpll; 1192 bool cid_match, mod_match, type_match; 1193 unsigned long i; 1194 1195 xa_for_each_marked(&dpll_device_xa, i, dpll, DPLL_REGISTERED) { 1196 cid_match = clock_id ? dpll->clock_id == clock_id : true; 1197 mod_match = mod_name_attr ? (module_name(dpll->module) ? 1198 !nla_strcmp(mod_name_attr, 1199 module_name(dpll->module)) : false) : true; 1200 type_match = type ? dpll->type == type : true; 1201 if (cid_match && mod_match && type_match) { 1202 if (dpll_match) { 1203 NL_SET_ERR_MSG(extack, "multiple matches"); 1204 return ERR_PTR(-EINVAL); 1205 } 1206 dpll_match = dpll; 1207 } 1208 } 1209 if (!dpll_match) { 1210 NL_SET_ERR_MSG(extack, "not found"); 1211 return ERR_PTR(-ENODEV); 1212 } 1213 1214 return dpll_match; 1215 } 1216 1217 static struct dpll_device * 1218 dpll_device_find_from_nlattr(struct genl_info *info) 1219 { 1220 struct nlattr *attr, *mod_name_attr = NULL; 1221 enum dpll_type type = 0; 1222 u64 clock_id = 0; 1223 int rem = 0; 1224 1225 nla_for_each_attr(attr, genlmsg_data(info->genlhdr), 1226 genlmsg_len(info->genlhdr), rem) { 1227 switch (nla_type(attr)) { 1228 case DPLL_A_CLOCK_ID: 1229 if (clock_id) 1230 goto duplicated_attr; 1231 clock_id = nla_get_u64(attr); 1232 break; 1233 case DPLL_A_MODULE_NAME: 1234 if (mod_name_attr) 1235 goto duplicated_attr; 1236 mod_name_attr = attr; 1237 break; 1238 case DPLL_A_TYPE: 1239 if (type) 1240 goto duplicated_attr; 1241 type = nla_get_u32(attr); 1242 break; 1243 default: 1244 break; 1245 } 1246 } 1247 if (!clock_id && !mod_name_attr && !type) { 1248 NL_SET_ERR_MSG(info->extack, "missing attributes"); 1249 return ERR_PTR(-EINVAL); 1250 } 1251 return dpll_device_find(clock_id, mod_name_attr, type, info->extack); 1252 duplicated_attr: 1253 NL_SET_ERR_MSG(info->extack, "duplicated attribute"); 1254 return ERR_PTR(-EINVAL); 1255 } 1256 1257 int dpll_nl_device_id_get_doit(struct sk_buff *skb, struct genl_info *info) 1258 { 1259 struct dpll_device *dpll; 1260 struct sk_buff *msg; 1261 struct nlattr *hdr; 1262 int ret; 1263 1264 msg = genlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL); 1265 if (!msg) 1266 return -ENOMEM; 1267 hdr = genlmsg_put_reply(msg, info, &dpll_nl_family, 0, 1268 DPLL_CMD_DEVICE_ID_GET); 1269 if (!hdr) { 1270 nlmsg_free(msg); 1271 return -EMSGSIZE; 1272 } 1273 1274 dpll = dpll_device_find_from_nlattr(info); 1275 if (!IS_ERR(dpll)) { 1276 ret = dpll_msg_add_dev_handle(msg, dpll); 1277 if (ret) { 1278 nlmsg_free(msg); 1279 return ret; 1280 } 1281 } 1282 genlmsg_end(msg, hdr); 1283 1284 return genlmsg_reply(msg, info); 1285 } 1286 1287 int dpll_nl_device_get_doit(struct sk_buff *skb, struct genl_info *info) 1288 { 1289 struct dpll_device *dpll = info->user_ptr[0]; 1290 struct sk_buff *msg; 1291 struct nlattr *hdr; 1292 int ret; 1293 1294 msg = genlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL); 1295 if (!msg) 1296 return -ENOMEM; 1297 hdr = genlmsg_put_reply(msg, info, &dpll_nl_family, 0, 1298 DPLL_CMD_DEVICE_GET); 1299 if (!hdr) { 1300 nlmsg_free(msg); 1301 return -EMSGSIZE; 1302 } 1303 1304 ret = dpll_device_get_one(dpll, msg, info->extack); 1305 if (ret) { 1306 nlmsg_free(msg); 1307 return ret; 1308 } 1309 genlmsg_end(msg, hdr); 1310 1311 return genlmsg_reply(msg, info); 1312 } 1313 1314 int dpll_nl_device_set_doit(struct sk_buff *skb, struct genl_info *info) 1315 { 1316 /* placeholder for set command */ 1317 return 0; 1318 } 1319 1320 int dpll_nl_device_get_dumpit(struct sk_buff *skb, struct netlink_callback *cb) 1321 { 1322 struct dpll_dump_ctx *ctx = dpll_dump_context(cb); 1323 struct dpll_device *dpll; 1324 struct nlattr *hdr; 1325 unsigned long i; 1326 int ret = 0; 1327 1328 xa_for_each_marked_start(&dpll_device_xa, i, dpll, DPLL_REGISTERED, 1329 ctx->idx) { 1330 hdr = genlmsg_put(skb, NETLINK_CB(cb->skb).portid, 1331 cb->nlh->nlmsg_seq, &dpll_nl_family, 1332 NLM_F_MULTI, DPLL_CMD_DEVICE_GET); 1333 if (!hdr) { 1334 ret = -EMSGSIZE; 1335 break; 1336 } 1337 ret = dpll_device_get_one(dpll, skb, cb->extack); 1338 if (ret) { 1339 genlmsg_cancel(skb, hdr); 1340 break; 1341 } 1342 genlmsg_end(skb, hdr); 1343 } 1344 if (ret == -EMSGSIZE) { 1345 ctx->idx = i; 1346 return skb->len; 1347 } 1348 return ret; 1349 } 1350 1351 int dpll_pre_doit(const struct genl_split_ops *ops, struct sk_buff *skb, 1352 struct genl_info *info) 1353 { 1354 u32 id; 1355 1356 if (GENL_REQ_ATTR_CHECK(info, DPLL_A_ID)) 1357 return -EINVAL; 1358 1359 mutex_lock(&dpll_lock); 1360 id = nla_get_u32(info->attrs[DPLL_A_ID]); 1361 info->user_ptr[0] = dpll_device_get_by_id(id); 1362 if (!info->user_ptr[0]) { 1363 NL_SET_ERR_MSG(info->extack, "device not found"); 1364 goto unlock; 1365 } 1366 return 0; 1367 unlock: 1368 mutex_unlock(&dpll_lock); 1369 return -ENODEV; 1370 } 1371 1372 void dpll_post_doit(const struct genl_split_ops *ops, struct sk_buff *skb, 1373 struct genl_info *info) 1374 { 1375 mutex_unlock(&dpll_lock); 1376 } 1377 1378 int 1379 dpll_lock_doit(const struct genl_split_ops *ops, struct sk_buff *skb, 1380 struct genl_info *info) 1381 { 1382 mutex_lock(&dpll_lock); 1383 1384 return 0; 1385 } 1386 1387 void 1388 dpll_unlock_doit(const struct genl_split_ops *ops, struct sk_buff *skb, 1389 struct genl_info *info) 1390 { 1391 mutex_unlock(&dpll_lock); 1392 } 1393 1394 int dpll_lock_dumpit(struct netlink_callback *cb) 1395 { 1396 mutex_lock(&dpll_lock); 1397 1398 return 0; 1399 } 1400 1401 int dpll_unlock_dumpit(struct netlink_callback *cb) 1402 { 1403 mutex_unlock(&dpll_lock); 1404 1405 return 0; 1406 } 1407 1408 int dpll_pin_pre_doit(const struct genl_split_ops *ops, struct sk_buff *skb, 1409 struct genl_info *info) 1410 { 1411 int ret; 1412 1413 mutex_lock(&dpll_lock); 1414 if (GENL_REQ_ATTR_CHECK(info, DPLL_A_PIN_ID)) { 1415 ret = -EINVAL; 1416 goto unlock_dev; 1417 } 1418 info->user_ptr[0] = xa_load(&dpll_pin_xa, 1419 nla_get_u32(info->attrs[DPLL_A_PIN_ID])); 1420 if (!info->user_ptr[0]) { 1421 NL_SET_ERR_MSG(info->extack, "pin not found"); 1422 ret = -ENODEV; 1423 goto unlock_dev; 1424 } 1425 1426 return 0; 1427 1428 unlock_dev: 1429 mutex_unlock(&dpll_lock); 1430 return ret; 1431 } 1432 1433 void dpll_pin_post_doit(const struct genl_split_ops *ops, struct sk_buff *skb, 1434 struct genl_info *info) 1435 { 1436 mutex_unlock(&dpll_lock); 1437 } 1438