Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at v6.9-rc2 869 lines 21 kB view raw
1// SPDX-License-Identifier: GPL-2.0 2/* 3 * dpll_core.c - DPLL subsystem kernel-space interface implementation. 4 * 5 * Copyright (c) 2023 Meta Platforms, Inc. and affiliates 6 * Copyright (c) 2023 Intel Corporation. 7 */ 8 9#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 10 11#include <linux/device.h> 12#include <linux/err.h> 13#include <linux/slab.h> 14#include <linux/string.h> 15 16#include "dpll_core.h" 17#include "dpll_netlink.h" 18 19/* Mutex lock to protect DPLL subsystem devices and pins */ 20DEFINE_MUTEX(dpll_lock); 21 22DEFINE_XARRAY_FLAGS(dpll_device_xa, XA_FLAGS_ALLOC); 23DEFINE_XARRAY_FLAGS(dpll_pin_xa, XA_FLAGS_ALLOC); 24 25static u32 dpll_device_xa_id; 26static u32 dpll_pin_xa_id; 27 28#define ASSERT_DPLL_REGISTERED(d) \ 29 WARN_ON_ONCE(!xa_get_mark(&dpll_device_xa, (d)->id, DPLL_REGISTERED)) 30#define ASSERT_DPLL_NOT_REGISTERED(d) \ 31 WARN_ON_ONCE(xa_get_mark(&dpll_device_xa, (d)->id, DPLL_REGISTERED)) 32#define ASSERT_DPLL_PIN_REGISTERED(p) \ 33 WARN_ON_ONCE(!xa_get_mark(&dpll_pin_xa, (p)->id, DPLL_REGISTERED)) 34 35struct dpll_device_registration { 36 struct list_head list; 37 const struct dpll_device_ops *ops; 38 void *priv; 39}; 40 41struct dpll_pin_registration { 42 struct list_head list; 43 const struct dpll_pin_ops *ops; 44 void *priv; 45}; 46 47struct dpll_device *dpll_device_get_by_id(int id) 48{ 49 if (xa_get_mark(&dpll_device_xa, id, DPLL_REGISTERED)) 50 return xa_load(&dpll_device_xa, id); 51 52 return NULL; 53} 54 55static struct dpll_pin_registration * 56dpll_pin_registration_find(struct dpll_pin_ref *ref, 57 const struct dpll_pin_ops *ops, void *priv) 58{ 59 struct dpll_pin_registration *reg; 60 61 list_for_each_entry(reg, &ref->registration_list, list) { 62 if (reg->ops == ops && reg->priv == priv) 63 return reg; 64 } 65 return NULL; 66} 67 68static int 69dpll_xa_ref_pin_add(struct xarray *xa_pins, struct dpll_pin *pin, 70 const struct dpll_pin_ops *ops, void *priv) 71{ 72 struct dpll_pin_registration *reg; 73 struct dpll_pin_ref *ref; 74 bool ref_exists = false; 75 unsigned long i; 76 int ret; 77 78 xa_for_each(xa_pins, i, ref) { 79 if (ref->pin != pin) 80 continue; 81 reg = dpll_pin_registration_find(ref, ops, priv); 82 if (reg) { 83 refcount_inc(&ref->refcount); 84 return 0; 85 } 86 ref_exists = true; 87 break; 88 } 89 90 if (!ref_exists) { 91 ref = kzalloc(sizeof(*ref), GFP_KERNEL); 92 if (!ref) 93 return -ENOMEM; 94 ref->pin = pin; 95 INIT_LIST_HEAD(&ref->registration_list); 96 ret = xa_insert(xa_pins, pin->pin_idx, ref, GFP_KERNEL); 97 if (ret) { 98 kfree(ref); 99 return ret; 100 } 101 refcount_set(&ref->refcount, 1); 102 } 103 104 reg = kzalloc(sizeof(*reg), GFP_KERNEL); 105 if (!reg) { 106 if (!ref_exists) { 107 xa_erase(xa_pins, pin->pin_idx); 108 kfree(ref); 109 } 110 return -ENOMEM; 111 } 112 reg->ops = ops; 113 reg->priv = priv; 114 if (ref_exists) 115 refcount_inc(&ref->refcount); 116 list_add_tail(&reg->list, &ref->registration_list); 117 118 return 0; 119} 120 121static int dpll_xa_ref_pin_del(struct xarray *xa_pins, struct dpll_pin *pin, 122 const struct dpll_pin_ops *ops, void *priv) 123{ 124 struct dpll_pin_registration *reg; 125 struct dpll_pin_ref *ref; 126 unsigned long i; 127 128 xa_for_each(xa_pins, i, ref) { 129 if (ref->pin != pin) 130 continue; 131 reg = dpll_pin_registration_find(ref, ops, priv); 132 if (WARN_ON(!reg)) 133 return -EINVAL; 134 list_del(&reg->list); 135 kfree(reg); 136 if (refcount_dec_and_test(&ref->refcount)) { 137 xa_erase(xa_pins, i); 138 WARN_ON(!list_empty(&ref->registration_list)); 139 kfree(ref); 140 } 141 return 0; 142 } 143 144 return -EINVAL; 145} 146 147static int 148dpll_xa_ref_dpll_add(struct xarray *xa_dplls, struct dpll_device *dpll, 149 const struct dpll_pin_ops *ops, void *priv) 150{ 151 struct dpll_pin_registration *reg; 152 struct dpll_pin_ref *ref; 153 bool ref_exists = false; 154 unsigned long i; 155 int ret; 156 157 xa_for_each(xa_dplls, i, ref) { 158 if (ref->dpll != dpll) 159 continue; 160 reg = dpll_pin_registration_find(ref, ops, priv); 161 if (reg) { 162 refcount_inc(&ref->refcount); 163 return 0; 164 } 165 ref_exists = true; 166 break; 167 } 168 169 if (!ref_exists) { 170 ref = kzalloc(sizeof(*ref), GFP_KERNEL); 171 if (!ref) 172 return -ENOMEM; 173 ref->dpll = dpll; 174 INIT_LIST_HEAD(&ref->registration_list); 175 ret = xa_insert(xa_dplls, dpll->id, ref, GFP_KERNEL); 176 if (ret) { 177 kfree(ref); 178 return ret; 179 } 180 refcount_set(&ref->refcount, 1); 181 } 182 183 reg = kzalloc(sizeof(*reg), GFP_KERNEL); 184 if (!reg) { 185 if (!ref_exists) { 186 xa_erase(xa_dplls, dpll->id); 187 kfree(ref); 188 } 189 return -ENOMEM; 190 } 191 reg->ops = ops; 192 reg->priv = priv; 193 if (ref_exists) 194 refcount_inc(&ref->refcount); 195 list_add_tail(&reg->list, &ref->registration_list); 196 197 return 0; 198} 199 200static void 201dpll_xa_ref_dpll_del(struct xarray *xa_dplls, struct dpll_device *dpll, 202 const struct dpll_pin_ops *ops, void *priv) 203{ 204 struct dpll_pin_registration *reg; 205 struct dpll_pin_ref *ref; 206 unsigned long i; 207 208 xa_for_each(xa_dplls, i, ref) { 209 if (ref->dpll != dpll) 210 continue; 211 reg = dpll_pin_registration_find(ref, ops, priv); 212 if (WARN_ON(!reg)) 213 return; 214 list_del(&reg->list); 215 kfree(reg); 216 if (refcount_dec_and_test(&ref->refcount)) { 217 xa_erase(xa_dplls, i); 218 WARN_ON(!list_empty(&ref->registration_list)); 219 kfree(ref); 220 } 221 return; 222 } 223} 224 225struct dpll_pin_ref *dpll_xa_ref_dpll_first(struct xarray *xa_refs) 226{ 227 struct dpll_pin_ref *ref; 228 unsigned long i = 0; 229 230 ref = xa_find(xa_refs, &i, ULONG_MAX, XA_PRESENT); 231 WARN_ON(!ref); 232 return ref; 233} 234 235static struct dpll_device * 236dpll_device_alloc(const u64 clock_id, u32 device_idx, struct module *module) 237{ 238 struct dpll_device *dpll; 239 int ret; 240 241 dpll = kzalloc(sizeof(*dpll), GFP_KERNEL); 242 if (!dpll) 243 return ERR_PTR(-ENOMEM); 244 refcount_set(&dpll->refcount, 1); 245 INIT_LIST_HEAD(&dpll->registration_list); 246 dpll->device_idx = device_idx; 247 dpll->clock_id = clock_id; 248 dpll->module = module; 249 ret = xa_alloc_cyclic(&dpll_device_xa, &dpll->id, dpll, xa_limit_32b, 250 &dpll_device_xa_id, GFP_KERNEL); 251 if (ret < 0) { 252 kfree(dpll); 253 return ERR_PTR(ret); 254 } 255 xa_init_flags(&dpll->pin_refs, XA_FLAGS_ALLOC); 256 257 return dpll; 258} 259 260/** 261 * dpll_device_get - find existing or create new dpll device 262 * @clock_id: clock_id of creator 263 * @device_idx: idx given by device driver 264 * @module: reference to registering module 265 * 266 * Get existing object of a dpll device, unique for given arguments. 267 * Create new if doesn't exist yet. 268 * 269 * Context: Acquires a lock (dpll_lock) 270 * Return: 271 * * valid dpll_device struct pointer if succeeded 272 * * ERR_PTR(X) - error 273 */ 274struct dpll_device * 275dpll_device_get(u64 clock_id, u32 device_idx, struct module *module) 276{ 277 struct dpll_device *dpll, *ret = NULL; 278 unsigned long index; 279 280 mutex_lock(&dpll_lock); 281 xa_for_each(&dpll_device_xa, index, dpll) { 282 if (dpll->clock_id == clock_id && 283 dpll->device_idx == device_idx && 284 dpll->module == module) { 285 ret = dpll; 286 refcount_inc(&ret->refcount); 287 break; 288 } 289 } 290 if (!ret) 291 ret = dpll_device_alloc(clock_id, device_idx, module); 292 mutex_unlock(&dpll_lock); 293 294 return ret; 295} 296EXPORT_SYMBOL_GPL(dpll_device_get); 297 298/** 299 * dpll_device_put - decrease the refcount and free memory if possible 300 * @dpll: dpll_device struct pointer 301 * 302 * Context: Acquires a lock (dpll_lock) 303 * Drop reference for a dpll device, if all references are gone, delete 304 * dpll device object. 305 */ 306void dpll_device_put(struct dpll_device *dpll) 307{ 308 mutex_lock(&dpll_lock); 309 if (refcount_dec_and_test(&dpll->refcount)) { 310 ASSERT_DPLL_NOT_REGISTERED(dpll); 311 WARN_ON_ONCE(!xa_empty(&dpll->pin_refs)); 312 xa_destroy(&dpll->pin_refs); 313 xa_erase(&dpll_device_xa, dpll->id); 314 WARN_ON(!list_empty(&dpll->registration_list)); 315 kfree(dpll); 316 } 317 mutex_unlock(&dpll_lock); 318} 319EXPORT_SYMBOL_GPL(dpll_device_put); 320 321static struct dpll_device_registration * 322dpll_device_registration_find(struct dpll_device *dpll, 323 const struct dpll_device_ops *ops, void *priv) 324{ 325 struct dpll_device_registration *reg; 326 327 list_for_each_entry(reg, &dpll->registration_list, list) { 328 if (reg->ops == ops && reg->priv == priv) 329 return reg; 330 } 331 return NULL; 332} 333 334/** 335 * dpll_device_register - register the dpll device in the subsystem 336 * @dpll: pointer to a dpll 337 * @type: type of a dpll 338 * @ops: ops for a dpll device 339 * @priv: pointer to private information of owner 340 * 341 * Make dpll device available for user space. 342 * 343 * Context: Acquires a lock (dpll_lock) 344 * Return: 345 * * 0 on success 346 * * negative - error value 347 */ 348int dpll_device_register(struct dpll_device *dpll, enum dpll_type type, 349 const struct dpll_device_ops *ops, void *priv) 350{ 351 struct dpll_device_registration *reg; 352 bool first_registration = false; 353 354 if (WARN_ON(!ops)) 355 return -EINVAL; 356 if (WARN_ON(!ops->mode_get)) 357 return -EINVAL; 358 if (WARN_ON(!ops->lock_status_get)) 359 return -EINVAL; 360 if (WARN_ON(type < DPLL_TYPE_PPS || type > DPLL_TYPE_MAX)) 361 return -EINVAL; 362 363 mutex_lock(&dpll_lock); 364 reg = dpll_device_registration_find(dpll, ops, priv); 365 if (reg) { 366 mutex_unlock(&dpll_lock); 367 return -EEXIST; 368 } 369 370 reg = kzalloc(sizeof(*reg), GFP_KERNEL); 371 if (!reg) { 372 mutex_unlock(&dpll_lock); 373 return -ENOMEM; 374 } 375 reg->ops = ops; 376 reg->priv = priv; 377 dpll->type = type; 378 first_registration = list_empty(&dpll->registration_list); 379 list_add_tail(&reg->list, &dpll->registration_list); 380 if (!first_registration) { 381 mutex_unlock(&dpll_lock); 382 return 0; 383 } 384 385 xa_set_mark(&dpll_device_xa, dpll->id, DPLL_REGISTERED); 386 dpll_device_create_ntf(dpll); 387 mutex_unlock(&dpll_lock); 388 389 return 0; 390} 391EXPORT_SYMBOL_GPL(dpll_device_register); 392 393/** 394 * dpll_device_unregister - unregister dpll device 395 * @dpll: registered dpll pointer 396 * @ops: ops for a dpll device 397 * @priv: pointer to private information of owner 398 * 399 * Unregister device, make it unavailable for userspace. 400 * Note: It does not free the memory 401 * Context: Acquires a lock (dpll_lock) 402 */ 403void dpll_device_unregister(struct dpll_device *dpll, 404 const struct dpll_device_ops *ops, void *priv) 405{ 406 struct dpll_device_registration *reg; 407 408 mutex_lock(&dpll_lock); 409 ASSERT_DPLL_REGISTERED(dpll); 410 dpll_device_delete_ntf(dpll); 411 reg = dpll_device_registration_find(dpll, ops, priv); 412 if (WARN_ON(!reg)) { 413 mutex_unlock(&dpll_lock); 414 return; 415 } 416 list_del(&reg->list); 417 kfree(reg); 418 419 if (!list_empty(&dpll->registration_list)) { 420 mutex_unlock(&dpll_lock); 421 return; 422 } 423 xa_clear_mark(&dpll_device_xa, dpll->id, DPLL_REGISTERED); 424 mutex_unlock(&dpll_lock); 425} 426EXPORT_SYMBOL_GPL(dpll_device_unregister); 427 428static void dpll_pin_prop_free(struct dpll_pin_properties *prop) 429{ 430 kfree(prop->package_label); 431 kfree(prop->panel_label); 432 kfree(prop->board_label); 433 kfree(prop->freq_supported); 434} 435 436static int dpll_pin_prop_dup(const struct dpll_pin_properties *src, 437 struct dpll_pin_properties *dst) 438{ 439 memcpy(dst, src, sizeof(*dst)); 440 if (src->freq_supported && src->freq_supported_num) { 441 size_t freq_size = src->freq_supported_num * 442 sizeof(*src->freq_supported); 443 dst->freq_supported = kmemdup(src->freq_supported, 444 freq_size, GFP_KERNEL); 445 if (!src->freq_supported) 446 return -ENOMEM; 447 } 448 if (src->board_label) { 449 dst->board_label = kstrdup(src->board_label, GFP_KERNEL); 450 if (!dst->board_label) 451 goto err_board_label; 452 } 453 if (src->panel_label) { 454 dst->panel_label = kstrdup(src->panel_label, GFP_KERNEL); 455 if (!dst->panel_label) 456 goto err_panel_label; 457 } 458 if (src->package_label) { 459 dst->package_label = kstrdup(src->package_label, GFP_KERNEL); 460 if (!dst->package_label) 461 goto err_package_label; 462 } 463 464 return 0; 465 466err_package_label: 467 kfree(dst->panel_label); 468err_panel_label: 469 kfree(dst->board_label); 470err_board_label: 471 kfree(dst->freq_supported); 472 return -ENOMEM; 473} 474 475static struct dpll_pin * 476dpll_pin_alloc(u64 clock_id, u32 pin_idx, struct module *module, 477 const struct dpll_pin_properties *prop) 478{ 479 struct dpll_pin *pin; 480 int ret; 481 482 pin = kzalloc(sizeof(*pin), GFP_KERNEL); 483 if (!pin) 484 return ERR_PTR(-ENOMEM); 485 pin->pin_idx = pin_idx; 486 pin->clock_id = clock_id; 487 pin->module = module; 488 if (WARN_ON(prop->type < DPLL_PIN_TYPE_MUX || 489 prop->type > DPLL_PIN_TYPE_MAX)) { 490 ret = -EINVAL; 491 goto err_pin_prop; 492 } 493 ret = dpll_pin_prop_dup(prop, &pin->prop); 494 if (ret) 495 goto err_pin_prop; 496 refcount_set(&pin->refcount, 1); 497 xa_init_flags(&pin->dpll_refs, XA_FLAGS_ALLOC); 498 xa_init_flags(&pin->parent_refs, XA_FLAGS_ALLOC); 499 ret = xa_alloc_cyclic(&dpll_pin_xa, &pin->id, pin, xa_limit_32b, 500 &dpll_pin_xa_id, GFP_KERNEL); 501 if (ret) 502 goto err_xa_alloc; 503 return pin; 504err_xa_alloc: 505 xa_destroy(&pin->dpll_refs); 506 xa_destroy(&pin->parent_refs); 507 dpll_pin_prop_free(&pin->prop); 508err_pin_prop: 509 kfree(pin); 510 return ERR_PTR(ret); 511} 512 513static void dpll_netdev_pin_assign(struct net_device *dev, struct dpll_pin *dpll_pin) 514{ 515 rtnl_lock(); 516 rcu_assign_pointer(dev->dpll_pin, dpll_pin); 517 rtnl_unlock(); 518} 519 520void dpll_netdev_pin_set(struct net_device *dev, struct dpll_pin *dpll_pin) 521{ 522 WARN_ON(!dpll_pin); 523 dpll_netdev_pin_assign(dev, dpll_pin); 524} 525EXPORT_SYMBOL(dpll_netdev_pin_set); 526 527void dpll_netdev_pin_clear(struct net_device *dev) 528{ 529 dpll_netdev_pin_assign(dev, NULL); 530} 531EXPORT_SYMBOL(dpll_netdev_pin_clear); 532 533/** 534 * dpll_pin_get - find existing or create new dpll pin 535 * @clock_id: clock_id of creator 536 * @pin_idx: idx given by dev driver 537 * @module: reference to registering module 538 * @prop: dpll pin properties 539 * 540 * Get existing object of a pin (unique for given arguments) or create new 541 * if doesn't exist yet. 542 * 543 * Context: Acquires a lock (dpll_lock) 544 * Return: 545 * * valid allocated dpll_pin struct pointer if succeeded 546 * * ERR_PTR(X) - error 547 */ 548struct dpll_pin * 549dpll_pin_get(u64 clock_id, u32 pin_idx, struct module *module, 550 const struct dpll_pin_properties *prop) 551{ 552 struct dpll_pin *pos, *ret = NULL; 553 unsigned long i; 554 555 mutex_lock(&dpll_lock); 556 xa_for_each(&dpll_pin_xa, i, pos) { 557 if (pos->clock_id == clock_id && 558 pos->pin_idx == pin_idx && 559 pos->module == module) { 560 ret = pos; 561 refcount_inc(&ret->refcount); 562 break; 563 } 564 } 565 if (!ret) 566 ret = dpll_pin_alloc(clock_id, pin_idx, module, prop); 567 mutex_unlock(&dpll_lock); 568 569 return ret; 570} 571EXPORT_SYMBOL_GPL(dpll_pin_get); 572 573/** 574 * dpll_pin_put - decrease the refcount and free memory if possible 575 * @pin: pointer to a pin to be put 576 * 577 * Drop reference for a pin, if all references are gone, delete pin object. 578 * 579 * Context: Acquires a lock (dpll_lock) 580 */ 581void dpll_pin_put(struct dpll_pin *pin) 582{ 583 mutex_lock(&dpll_lock); 584 if (refcount_dec_and_test(&pin->refcount)) { 585 xa_erase(&dpll_pin_xa, pin->id); 586 xa_destroy(&pin->dpll_refs); 587 xa_destroy(&pin->parent_refs); 588 dpll_pin_prop_free(&pin->prop); 589 kfree_rcu(pin, rcu); 590 } 591 mutex_unlock(&dpll_lock); 592} 593EXPORT_SYMBOL_GPL(dpll_pin_put); 594 595static int 596__dpll_pin_register(struct dpll_device *dpll, struct dpll_pin *pin, 597 const struct dpll_pin_ops *ops, void *priv) 598{ 599 int ret; 600 601 ret = dpll_xa_ref_pin_add(&dpll->pin_refs, pin, ops, priv); 602 if (ret) 603 return ret; 604 ret = dpll_xa_ref_dpll_add(&pin->dpll_refs, dpll, ops, priv); 605 if (ret) 606 goto ref_pin_del; 607 xa_set_mark(&dpll_pin_xa, pin->id, DPLL_REGISTERED); 608 dpll_pin_create_ntf(pin); 609 610 return ret; 611 612ref_pin_del: 613 dpll_xa_ref_pin_del(&dpll->pin_refs, pin, ops, priv); 614 return ret; 615} 616 617/** 618 * dpll_pin_register - register the dpll pin in the subsystem 619 * @dpll: pointer to a dpll 620 * @pin: pointer to a dpll pin 621 * @ops: ops for a dpll pin ops 622 * @priv: pointer to private information of owner 623 * 624 * Context: Acquires a lock (dpll_lock) 625 * Return: 626 * * 0 on success 627 * * negative - error value 628 */ 629int 630dpll_pin_register(struct dpll_device *dpll, struct dpll_pin *pin, 631 const struct dpll_pin_ops *ops, void *priv) 632{ 633 int ret; 634 635 if (WARN_ON(!ops) || 636 WARN_ON(!ops->state_on_dpll_get) || 637 WARN_ON(!ops->direction_get)) 638 return -EINVAL; 639 640 mutex_lock(&dpll_lock); 641 if (WARN_ON(!(dpll->module == pin->module && 642 dpll->clock_id == pin->clock_id))) 643 ret = -EINVAL; 644 else 645 ret = __dpll_pin_register(dpll, pin, ops, priv); 646 mutex_unlock(&dpll_lock); 647 648 return ret; 649} 650EXPORT_SYMBOL_GPL(dpll_pin_register); 651 652static void 653__dpll_pin_unregister(struct dpll_device *dpll, struct dpll_pin *pin, 654 const struct dpll_pin_ops *ops, void *priv) 655{ 656 ASSERT_DPLL_PIN_REGISTERED(pin); 657 dpll_xa_ref_pin_del(&dpll->pin_refs, pin, ops, priv); 658 dpll_xa_ref_dpll_del(&pin->dpll_refs, dpll, ops, priv); 659 if (xa_empty(&pin->dpll_refs)) 660 xa_clear_mark(&dpll_pin_xa, pin->id, DPLL_REGISTERED); 661} 662 663/** 664 * dpll_pin_unregister - unregister dpll pin from dpll device 665 * @dpll: registered dpll pointer 666 * @pin: pointer to a pin 667 * @ops: ops for a dpll pin 668 * @priv: pointer to private information of owner 669 * 670 * Note: It does not free the memory 671 * Context: Acquires a lock (dpll_lock) 672 */ 673void dpll_pin_unregister(struct dpll_device *dpll, struct dpll_pin *pin, 674 const struct dpll_pin_ops *ops, void *priv) 675{ 676 if (WARN_ON(xa_empty(&dpll->pin_refs))) 677 return; 678 if (WARN_ON(!xa_empty(&pin->parent_refs))) 679 return; 680 681 mutex_lock(&dpll_lock); 682 dpll_pin_delete_ntf(pin); 683 __dpll_pin_unregister(dpll, pin, ops, priv); 684 mutex_unlock(&dpll_lock); 685} 686EXPORT_SYMBOL_GPL(dpll_pin_unregister); 687 688/** 689 * dpll_pin_on_pin_register - register a pin with a parent pin 690 * @parent: pointer to a parent pin 691 * @pin: pointer to a pin 692 * @ops: ops for a dpll pin 693 * @priv: pointer to private information of owner 694 * 695 * Register a pin with a parent pin, create references between them and 696 * between newly registered pin and dplls connected with a parent pin. 697 * 698 * Context: Acquires a lock (dpll_lock) 699 * Return: 700 * * 0 on success 701 * * negative - error value 702 */ 703int dpll_pin_on_pin_register(struct dpll_pin *parent, struct dpll_pin *pin, 704 const struct dpll_pin_ops *ops, void *priv) 705{ 706 struct dpll_pin_ref *ref; 707 unsigned long i, stop; 708 int ret; 709 710 if (WARN_ON(parent->prop.type != DPLL_PIN_TYPE_MUX)) 711 return -EINVAL; 712 713 if (WARN_ON(!ops) || 714 WARN_ON(!ops->state_on_pin_get) || 715 WARN_ON(!ops->direction_get)) 716 return -EINVAL; 717 718 mutex_lock(&dpll_lock); 719 ret = dpll_xa_ref_pin_add(&pin->parent_refs, parent, ops, priv); 720 if (ret) 721 goto unlock; 722 refcount_inc(&pin->refcount); 723 xa_for_each(&parent->dpll_refs, i, ref) { 724 ret = __dpll_pin_register(ref->dpll, pin, ops, priv); 725 if (ret) { 726 stop = i; 727 goto dpll_unregister; 728 } 729 dpll_pin_create_ntf(pin); 730 } 731 mutex_unlock(&dpll_lock); 732 733 return ret; 734 735dpll_unregister: 736 xa_for_each(&parent->dpll_refs, i, ref) 737 if (i < stop) { 738 __dpll_pin_unregister(ref->dpll, pin, ops, priv); 739 dpll_pin_delete_ntf(pin); 740 } 741 refcount_dec(&pin->refcount); 742 dpll_xa_ref_pin_del(&pin->parent_refs, parent, ops, priv); 743unlock: 744 mutex_unlock(&dpll_lock); 745 return ret; 746} 747EXPORT_SYMBOL_GPL(dpll_pin_on_pin_register); 748 749/** 750 * dpll_pin_on_pin_unregister - unregister dpll pin from a parent pin 751 * @parent: pointer to a parent pin 752 * @pin: pointer to a pin 753 * @ops: ops for a dpll pin 754 * @priv: pointer to private information of owner 755 * 756 * Context: Acquires a lock (dpll_lock) 757 * Note: It does not free the memory 758 */ 759void dpll_pin_on_pin_unregister(struct dpll_pin *parent, struct dpll_pin *pin, 760 const struct dpll_pin_ops *ops, void *priv) 761{ 762 struct dpll_pin_ref *ref; 763 unsigned long i; 764 765 mutex_lock(&dpll_lock); 766 dpll_pin_delete_ntf(pin); 767 dpll_xa_ref_pin_del(&pin->parent_refs, parent, ops, priv); 768 refcount_dec(&pin->refcount); 769 xa_for_each(&pin->dpll_refs, i, ref) 770 __dpll_pin_unregister(ref->dpll, pin, ops, priv); 771 mutex_unlock(&dpll_lock); 772} 773EXPORT_SYMBOL_GPL(dpll_pin_on_pin_unregister); 774 775static struct dpll_device_registration * 776dpll_device_registration_first(struct dpll_device *dpll) 777{ 778 struct dpll_device_registration *reg; 779 780 reg = list_first_entry_or_null((struct list_head *)&dpll->registration_list, 781 struct dpll_device_registration, list); 782 WARN_ON(!reg); 783 return reg; 784} 785 786void *dpll_priv(struct dpll_device *dpll) 787{ 788 struct dpll_device_registration *reg; 789 790 reg = dpll_device_registration_first(dpll); 791 return reg->priv; 792} 793 794const struct dpll_device_ops *dpll_device_ops(struct dpll_device *dpll) 795{ 796 struct dpll_device_registration *reg; 797 798 reg = dpll_device_registration_first(dpll); 799 return reg->ops; 800} 801 802static struct dpll_pin_registration * 803dpll_pin_registration_first(struct dpll_pin_ref *ref) 804{ 805 struct dpll_pin_registration *reg; 806 807 reg = list_first_entry_or_null(&ref->registration_list, 808 struct dpll_pin_registration, list); 809 WARN_ON(!reg); 810 return reg; 811} 812 813void *dpll_pin_on_dpll_priv(struct dpll_device *dpll, 814 struct dpll_pin *pin) 815{ 816 struct dpll_pin_registration *reg; 817 struct dpll_pin_ref *ref; 818 819 ref = xa_load(&dpll->pin_refs, pin->pin_idx); 820 if (!ref) 821 return NULL; 822 reg = dpll_pin_registration_first(ref); 823 return reg->priv; 824} 825 826void *dpll_pin_on_pin_priv(struct dpll_pin *parent, 827 struct dpll_pin *pin) 828{ 829 struct dpll_pin_registration *reg; 830 struct dpll_pin_ref *ref; 831 832 ref = xa_load(&pin->parent_refs, parent->pin_idx); 833 if (!ref) 834 return NULL; 835 reg = dpll_pin_registration_first(ref); 836 return reg->priv; 837} 838 839const struct dpll_pin_ops *dpll_pin_ops(struct dpll_pin_ref *ref) 840{ 841 struct dpll_pin_registration *reg; 842 843 reg = dpll_pin_registration_first(ref); 844 return reg->ops; 845} 846 847static int __init dpll_init(void) 848{ 849 int ret; 850 851 ret = genl_register_family(&dpll_nl_family); 852 if (ret) 853 goto error; 854 855 return 0; 856 857error: 858 mutex_destroy(&dpll_lock); 859 return ret; 860} 861 862static void __exit dpll_exit(void) 863{ 864 genl_unregister_family(&dpll_nl_family); 865 mutex_destroy(&dpll_lock); 866} 867 868subsys_initcall(dpll_init); 869module_exit(dpll_exit);