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.

dpll: Add reference count tracking support

Add support for the REF_TRACKER infrastructure to the DPLL subsystem.

When enabled, this allows developers to track and debug reference counting
leaks or imbalances for dpll_device and dpll_pin objects. It records stack
traces for every get/put operation and exposes this information via
debugfs at:
/sys/kernel/debug/ref_tracker/dpll_device_*
/sys/kernel/debug/ref_tracker/dpll_pin_*

The following API changes are made to support this:
1. dpll_device_get() / dpll_device_put() now accept a 'dpll_tracker *'
(which is a typedef to 'struct ref_tracker *' when enabled, or an empty
struct otherwise).
2. dpll_pin_get() / dpll_pin_put() and fwnode_dpll_pin_find() similarly
accept the tracker argument.
3. Internal registration structures now hold a tracker to associate the
reference held by the registration with the specific owner.

All existing in-tree drivers (ice, mlx5, ptp_ocp, zl3073x) are updated
to pass NULL for the new tracker argument, maintaining current behavior
while enabling future debugging capabilities.

Reviewed-by: Aleksandr Loktionov <aleksandr.loktionov@intel.com>
Co-developed-by: Petr Oros <poros@redhat.com>
Signed-off-by: Petr Oros <poros@redhat.com>
Signed-off-by: Ivan Vecera <ivecera@redhat.com>
Reviewed-by: Arkadiusz Kubalewski <arkadiusz.kubalewski@intel.com>
Link: https://patch.msgid.link/20260203174002.705176-8-ivecera@redhat.com
Signed-off-by: Paolo Abeni <pabeni@redhat.com>

authored by

Ivan Vecera and committed by
Paolo Abeni
3c0da103 729f5e01

+139 -54
+15
drivers/dpll/Kconfig
··· 8 8 config DPLL 9 9 bool 10 10 11 + config DPLL_REFCNT_TRACKER 12 + bool "DPLL reference count tracking" 13 + depends on DEBUG_KERNEL && STACKTRACE_SUPPORT && DPLL 14 + select REF_TRACKER 15 + help 16 + Enable reference count tracking for DPLL devices and pins. 17 + This helps debugging reference leaks and use-after-free bugs 18 + by recording stack traces for each get/put operation. 19 + 20 + The tracking information is exposed via debugfs at: 21 + /sys/kernel/debug/ref_tracker/dpll_device_* 22 + /sys/kernel/debug/ref_tracker/dpll_pin_* 23 + 24 + If unsure, say N. 25 + 11 26 source "drivers/dpll/zl3073x/Kconfig" 12 27 13 28 endmenu
+76 -22
drivers/dpll/dpll_core.c
··· 41 41 struct list_head list; 42 42 const struct dpll_device_ops *ops; 43 43 void *priv; 44 + dpll_tracker tracker; 44 45 }; 45 46 46 47 struct dpll_pin_registration { ··· 49 48 const struct dpll_pin_ops *ops; 50 49 void *priv; 51 50 void *cookie; 51 + dpll_tracker tracker; 52 52 }; 53 53 54 54 static int call_dpll_notifiers(unsigned long action, void *info) ··· 85 83 call_dpll_notifiers(action, &info); 86 84 } 87 85 88 - static void __dpll_device_hold(struct dpll_device *dpll) 86 + static void dpll_device_tracker_alloc(struct dpll_device *dpll, 87 + dpll_tracker *tracker) 89 88 { 89 + #ifdef CONFIG_DPLL_REFCNT_TRACKER 90 + ref_tracker_alloc(&dpll->refcnt_tracker, tracker, GFP_KERNEL); 91 + #endif 92 + } 93 + 94 + static void dpll_device_tracker_free(struct dpll_device *dpll, 95 + dpll_tracker *tracker) 96 + { 97 + #ifdef CONFIG_DPLL_REFCNT_TRACKER 98 + ref_tracker_free(&dpll->refcnt_tracker, tracker); 99 + #endif 100 + } 101 + 102 + static void __dpll_device_hold(struct dpll_device *dpll, dpll_tracker *tracker) 103 + { 104 + dpll_device_tracker_alloc(dpll, tracker); 90 105 refcount_inc(&dpll->refcount); 91 106 } 92 107 93 - static void __dpll_device_put(struct dpll_device *dpll) 108 + static void __dpll_device_put(struct dpll_device *dpll, dpll_tracker *tracker) 94 109 { 110 + dpll_device_tracker_free(dpll, tracker); 95 111 if (refcount_dec_and_test(&dpll->refcount)) { 96 112 ASSERT_DPLL_NOT_REGISTERED(dpll); 97 113 WARN_ON_ONCE(!xa_empty(&dpll->pin_refs)); 98 114 xa_destroy(&dpll->pin_refs); 99 115 xa_erase(&dpll_device_xa, dpll->id); 100 116 WARN_ON(!list_empty(&dpll->registration_list)); 117 + ref_tracker_dir_exit(&dpll->refcnt_tracker); 101 118 kfree(dpll); 102 119 } 103 120 } 104 121 105 - static void __dpll_pin_hold(struct dpll_pin *pin) 122 + static void dpll_pin_tracker_alloc(struct dpll_pin *pin, dpll_tracker *tracker) 106 123 { 124 + #ifdef CONFIG_DPLL_REFCNT_TRACKER 125 + ref_tracker_alloc(&pin->refcnt_tracker, tracker, GFP_KERNEL); 126 + #endif 127 + } 128 + 129 + static void dpll_pin_tracker_free(struct dpll_pin *pin, dpll_tracker *tracker) 130 + { 131 + #ifdef CONFIG_DPLL_REFCNT_TRACKER 132 + ref_tracker_free(&pin->refcnt_tracker, tracker); 133 + #endif 134 + } 135 + 136 + static void __dpll_pin_hold(struct dpll_pin *pin, dpll_tracker *tracker) 137 + { 138 + dpll_pin_tracker_alloc(pin, tracker); 107 139 refcount_inc(&pin->refcount); 108 140 } 109 141 110 142 static void dpll_pin_idx_free(u32 pin_idx); 111 143 static void dpll_pin_prop_free(struct dpll_pin_properties *prop); 112 144 113 - static void __dpll_pin_put(struct dpll_pin *pin) 145 + static void __dpll_pin_put(struct dpll_pin *pin, dpll_tracker *tracker) 114 146 { 147 + dpll_pin_tracker_free(pin, tracker); 115 148 if (refcount_dec_and_test(&pin->refcount)) { 116 149 xa_erase(&dpll_pin_xa, pin->id); 117 150 xa_destroy(&pin->dpll_refs); ··· 155 118 dpll_pin_prop_free(&pin->prop); 156 119 fwnode_handle_put(pin->fwnode); 157 120 dpll_pin_idx_free(pin->pin_idx); 121 + ref_tracker_dir_exit(&pin->refcnt_tracker); 158 122 kfree_rcu(pin, rcu); 159 123 } 160 124 } ··· 229 191 reg->ops = ops; 230 192 reg->priv = priv; 231 193 reg->cookie = cookie; 232 - __dpll_pin_hold(pin); 194 + __dpll_pin_hold(pin, &reg->tracker); 233 195 if (ref_exists) 234 196 refcount_inc(&ref->refcount); 235 197 list_add_tail(&reg->list, &ref->registration_list); ··· 252 214 if (WARN_ON(!reg)) 253 215 return -EINVAL; 254 216 list_del(&reg->list); 255 - __dpll_pin_put(pin); 217 + __dpll_pin_put(pin, &reg->tracker); 256 218 kfree(reg); 257 219 if (refcount_dec_and_test(&ref->refcount)) { 258 220 xa_erase(xa_pins, i); ··· 310 272 reg->ops = ops; 311 273 reg->priv = priv; 312 274 reg->cookie = cookie; 313 - __dpll_device_hold(dpll); 275 + __dpll_device_hold(dpll, &reg->tracker); 314 276 if (ref_exists) 315 277 refcount_inc(&ref->refcount); 316 278 list_add_tail(&reg->list, &ref->registration_list); ··· 333 295 if (WARN_ON(!reg)) 334 296 return; 335 297 list_del(&reg->list); 336 - __dpll_device_put(dpll); 298 + __dpll_device_put(dpll, &reg->tracker); 337 299 kfree(reg); 338 300 if (refcount_dec_and_test(&ref->refcount)) { 339 301 xa_erase(xa_dplls, i); ··· 375 337 return ERR_PTR(ret); 376 338 } 377 339 xa_init_flags(&dpll->pin_refs, XA_FLAGS_ALLOC); 340 + ref_tracker_dir_init(&dpll->refcnt_tracker, 128, "dpll_device"); 378 341 379 342 return dpll; 380 343 } ··· 385 346 * @clock_id: clock_id of creator 386 347 * @device_idx: idx given by device driver 387 348 * @module: reference to registering module 349 + * @tracker: tracking object for the acquired reference 388 350 * 389 351 * Get existing object of a dpll device, unique for given arguments. 390 352 * Create new if doesn't exist yet. ··· 396 356 * * ERR_PTR(X) - error 397 357 */ 398 358 struct dpll_device * 399 - dpll_device_get(u64 clock_id, u32 device_idx, struct module *module) 359 + dpll_device_get(u64 clock_id, u32 device_idx, struct module *module, 360 + dpll_tracker *tracker) 400 361 { 401 362 struct dpll_device *dpll, *ret = NULL; 402 363 unsigned long index; ··· 407 366 if (dpll->clock_id == clock_id && 408 367 dpll->device_idx == device_idx && 409 368 dpll->module == module) { 410 - __dpll_device_hold(dpll); 369 + __dpll_device_hold(dpll, tracker); 411 370 ret = dpll; 412 371 break; 413 372 } 414 373 } 415 - if (!ret) 374 + if (!ret) { 416 375 ret = dpll_device_alloc(clock_id, device_idx, module); 376 + if (!IS_ERR(ret)) 377 + dpll_device_tracker_alloc(ret, tracker); 378 + } 379 + 417 380 mutex_unlock(&dpll_lock); 418 381 419 382 return ret; ··· 427 382 /** 428 383 * dpll_device_put - decrease the refcount and free memory if possible 429 384 * @dpll: dpll_device struct pointer 385 + * @tracker: tracking object for the acquired reference 430 386 * 431 387 * Context: Acquires a lock (dpll_lock) 432 388 * Drop reference for a dpll device, if all references are gone, delete 433 389 * dpll device object. 434 390 */ 435 - void dpll_device_put(struct dpll_device *dpll) 391 + void dpll_device_put(struct dpll_device *dpll, dpll_tracker *tracker) 436 392 { 437 393 mutex_lock(&dpll_lock); 438 - __dpll_device_put(dpll); 394 + __dpll_device_put(dpll, tracker); 439 395 mutex_unlock(&dpll_lock); 440 396 } 441 397 EXPORT_SYMBOL_GPL(dpll_device_put); ··· 498 452 reg->ops = ops; 499 453 reg->priv = priv; 500 454 dpll->type = type; 501 - __dpll_device_hold(dpll); 455 + __dpll_device_hold(dpll, &reg->tracker); 502 456 first_registration = list_empty(&dpll->registration_list); 503 457 list_add_tail(&reg->list, &dpll->registration_list); 504 458 if (!first_registration) { ··· 538 492 return; 539 493 } 540 494 list_del(&reg->list); 541 - __dpll_device_put(dpll); 495 + __dpll_device_put(dpll, &reg->tracker); 542 496 kfree(reg); 543 497 544 498 if (!list_empty(&dpll->registration_list)) { ··· 668 622 &dpll_pin_xa_id, GFP_KERNEL); 669 623 if (ret < 0) 670 624 goto err_xa_alloc; 625 + ref_tracker_dir_init(&pin->refcnt_tracker, 128, "dpll_pin"); 671 626 return pin; 672 627 err_xa_alloc: 673 628 xa_destroy(&pin->dpll_refs); ··· 730 683 * @pin_idx: idx given by dev driver 731 684 * @module: reference to registering module 732 685 * @prop: dpll pin properties 686 + * @tracker: tracking object for the acquired reference 733 687 * 734 688 * Get existing object of a pin (unique for given arguments) or create new 735 689 * if doesn't exist yet. ··· 742 694 */ 743 695 struct dpll_pin * 744 696 dpll_pin_get(u64 clock_id, u32 pin_idx, struct module *module, 745 - const struct dpll_pin_properties *prop) 697 + const struct dpll_pin_properties *prop, dpll_tracker *tracker) 746 698 { 747 699 struct dpll_pin *pos, *ret = NULL; 748 700 unsigned long i; ··· 752 704 if (pos->clock_id == clock_id && 753 705 pos->pin_idx == pin_idx && 754 706 pos->module == module) { 755 - __dpll_pin_hold(pos); 707 + __dpll_pin_hold(pos, tracker); 756 708 ret = pos; 757 709 break; 758 710 } 759 711 } 760 - if (!ret) 712 + if (!ret) { 761 713 ret = dpll_pin_alloc(clock_id, pin_idx, module, prop); 714 + if (!IS_ERR(ret)) 715 + dpll_pin_tracker_alloc(ret, tracker); 716 + } 762 717 mutex_unlock(&dpll_lock); 763 718 764 719 return ret; ··· 771 720 /** 772 721 * dpll_pin_put - decrease the refcount and free memory if possible 773 722 * @pin: pointer to a pin to be put 723 + * @tracker: tracking object for the acquired reference 774 724 * 775 725 * Drop reference for a pin, if all references are gone, delete pin object. 776 726 * 777 727 * Context: Acquires a lock (dpll_lock) 778 728 */ 779 - void dpll_pin_put(struct dpll_pin *pin) 729 + void dpll_pin_put(struct dpll_pin *pin, dpll_tracker *tracker) 780 730 { 781 731 mutex_lock(&dpll_lock); 782 - __dpll_pin_put(pin); 732 + __dpll_pin_put(pin, tracker); 783 733 mutex_unlock(&dpll_lock); 784 734 } 785 735 EXPORT_SYMBOL_GPL(dpll_pin_put); ··· 804 752 /** 805 753 * fwnode_dpll_pin_find - find dpll pin by firmware node reference 806 754 * @fwnode: reference to firmware node 755 + * @tracker: tracking object for the acquired reference 807 756 * 808 757 * Get existing object of a pin that is associated with given firmware node 809 758 * reference. ··· 814 761 * * valid dpll_pin pointer on success 815 762 * * NULL when no such pin exists 816 763 */ 817 - struct dpll_pin *fwnode_dpll_pin_find(struct fwnode_handle *fwnode) 764 + struct dpll_pin *fwnode_dpll_pin_find(struct fwnode_handle *fwnode, 765 + dpll_tracker *tracker) 818 766 { 819 767 struct dpll_pin *pin, *ret = NULL; 820 768 unsigned long index; ··· 823 769 mutex_lock(&dpll_lock); 824 770 xa_for_each(&dpll_pin_xa, index, pin) { 825 771 if (pin->fwnode == fwnode) { 826 - __dpll_pin_hold(pin); 772 + __dpll_pin_hold(pin, tracker); 827 773 ret = pin; 828 774 break; 829 775 }
+5
drivers/dpll/dpll_core.h
··· 10 10 #include <linux/dpll.h> 11 11 #include <linux/list.h> 12 12 #include <linux/refcount.h> 13 + #include <linux/ref_tracker.h> 13 14 #include "dpll_nl.h" 14 15 15 16 #define DPLL_REGISTERED XA_MARK_1 ··· 24 23 * @type: type of a dpll 25 24 * @pin_refs: stores pins registered within a dpll 26 25 * @refcount: refcount 26 + * @refcnt_tracker: ref_tracker directory for debugging reference leaks 27 27 * @registration_list: list of registered ops and priv data of dpll owners 28 28 **/ 29 29 struct dpll_device { ··· 35 33 enum dpll_type type; 36 34 struct xarray pin_refs; 37 35 refcount_t refcount; 36 + struct ref_tracker_dir refcnt_tracker; 38 37 struct list_head registration_list; 39 38 }; 40 39 ··· 51 48 * @ref_sync_pins: hold references to pins for Reference SYNC feature 52 49 * @prop: pin properties copied from the registerer 53 50 * @refcount: refcount 51 + * @refcnt_tracker: ref_tracker directory for debugging reference leaks 54 52 * @rcu: rcu_head for kfree_rcu() 55 53 **/ 56 54 struct dpll_pin { ··· 65 61 struct xarray ref_sync_pins; 66 62 struct dpll_pin_properties prop; 67 63 refcount_t refcount; 64 + struct ref_tracker_dir refcnt_tracker; 68 65 struct rcu_head rcu; 69 66 }; 70 67
+6 -6
drivers/dpll/zl3073x/dpll.c
··· 1480 1480 1481 1481 /* Create or get existing DPLL pin */ 1482 1482 pin->dpll_pin = dpll_pin_get(zldpll->dev->clock_id, index, THIS_MODULE, 1483 - &props->dpll_props); 1483 + &props->dpll_props, NULL); 1484 1484 if (IS_ERR(pin->dpll_pin)) { 1485 1485 rc = PTR_ERR(pin->dpll_pin); 1486 1486 goto err_pin_get; ··· 1503 1503 return 0; 1504 1504 1505 1505 err_register: 1506 - dpll_pin_put(pin->dpll_pin); 1506 + dpll_pin_put(pin->dpll_pin, NULL); 1507 1507 err_prio_get: 1508 1508 pin->dpll_pin = NULL; 1509 1509 err_pin_get: ··· 1534 1534 /* Unregister the pin */ 1535 1535 dpll_pin_unregister(zldpll->dpll_dev, pin->dpll_pin, ops, pin); 1536 1536 1537 - dpll_pin_put(pin->dpll_pin); 1537 + dpll_pin_put(pin->dpll_pin, NULL); 1538 1538 pin->dpll_pin = NULL; 1539 1539 } 1540 1540 ··· 1708 1708 dpll_mode_refsel); 1709 1709 1710 1710 zldpll->dpll_dev = dpll_device_get(zldev->clock_id, zldpll->id, 1711 - THIS_MODULE); 1711 + THIS_MODULE, NULL); 1712 1712 if (IS_ERR(zldpll->dpll_dev)) { 1713 1713 rc = PTR_ERR(zldpll->dpll_dev); 1714 1714 zldpll->dpll_dev = NULL; ··· 1720 1720 zl3073x_prop_dpll_type_get(zldev, zldpll->id), 1721 1721 &zl3073x_dpll_device_ops, zldpll); 1722 1722 if (rc) { 1723 - dpll_device_put(zldpll->dpll_dev); 1723 + dpll_device_put(zldpll->dpll_dev, NULL); 1724 1724 zldpll->dpll_dev = NULL; 1725 1725 } 1726 1726 ··· 1743 1743 1744 1744 dpll_device_unregister(zldpll->dpll_dev, &zl3073x_dpll_device_ops, 1745 1745 zldpll); 1746 - dpll_device_put(zldpll->dpll_dev); 1746 + dpll_device_put(zldpll->dpll_dev, NULL); 1747 1747 zldpll->dpll_dev = NULL; 1748 1748 } 1749 1749
+7 -7
drivers/net/ethernet/intel/ice/ice_dpll.c
··· 2814 2814 int i; 2815 2815 2816 2816 for (i = 0; i < count; i++) 2817 - dpll_pin_put(pins[i].pin); 2817 + dpll_pin_put(pins[i].pin, NULL); 2818 2818 } 2819 2819 2820 2820 /** ··· 2840 2840 2841 2841 for (i = 0; i < count; i++) { 2842 2842 pins[i].pin = dpll_pin_get(clock_id, i + start_idx, THIS_MODULE, 2843 - &pins[i].prop); 2843 + &pins[i].prop, NULL); 2844 2844 if (IS_ERR(pins[i].pin)) { 2845 2845 ret = PTR_ERR(pins[i].pin); 2846 2846 goto release_pins; ··· 2851 2851 2852 2852 release_pins: 2853 2853 while (--i >= 0) 2854 - dpll_pin_put(pins[i].pin); 2854 + dpll_pin_put(pins[i].pin, NULL); 2855 2855 return ret; 2856 2856 } 2857 2857 ··· 3037 3037 if (WARN_ON_ONCE(!vsi || !vsi->netdev)) 3038 3038 return; 3039 3039 dpll_netdev_pin_clear(vsi->netdev); 3040 - dpll_pin_put(rclk->pin); 3040 + dpll_pin_put(rclk->pin, NULL); 3041 3041 } 3042 3042 3043 3043 /** ··· 3247 3247 { 3248 3248 if (cgu) 3249 3249 dpll_device_unregister(d->dpll, d->ops, d); 3250 - dpll_device_put(d->dpll); 3250 + dpll_device_put(d->dpll, NULL); 3251 3251 } 3252 3252 3253 3253 /** ··· 3271 3271 u64 clock_id = pf->dplls.clock_id; 3272 3272 int ret; 3273 3273 3274 - d->dpll = dpll_device_get(clock_id, d->dpll_idx, THIS_MODULE); 3274 + d->dpll = dpll_device_get(clock_id, d->dpll_idx, THIS_MODULE, NULL); 3275 3275 if (IS_ERR(d->dpll)) { 3276 3276 ret = PTR_ERR(d->dpll); 3277 3277 dev_err(ice_pf_to_dev(pf), ··· 3287 3287 ice_dpll_update_state(pf, d, true); 3288 3288 ret = dpll_device_register(d->dpll, type, ops, d); 3289 3289 if (ret) { 3290 - dpll_device_put(d->dpll); 3290 + dpll_device_put(d->dpll, NULL); 3291 3291 return ret; 3292 3292 } 3293 3293 d->ops = ops;
+7 -6
drivers/net/ethernet/mellanox/mlx5/core/dpll.c
··· 438 438 auxiliary_set_drvdata(adev, mdpll); 439 439 440 440 /* Multiple mdev instances might share one DPLL device. */ 441 - mdpll->dpll = dpll_device_get(clock_id, 0, THIS_MODULE); 441 + mdpll->dpll = dpll_device_get(clock_id, 0, THIS_MODULE, NULL); 442 442 if (IS_ERR(mdpll->dpll)) { 443 443 err = PTR_ERR(mdpll->dpll); 444 444 goto err_free_mdpll; ··· 451 451 452 452 /* Multiple mdev instances might share one DPLL pin. */ 453 453 mdpll->dpll_pin = dpll_pin_get(clock_id, mlx5_get_dev_index(mdev), 454 - THIS_MODULE, &mlx5_dpll_pin_properties); 454 + THIS_MODULE, &mlx5_dpll_pin_properties, 455 + NULL); 455 456 if (IS_ERR(mdpll->dpll_pin)) { 456 457 err = PTR_ERR(mdpll->dpll_pin); 457 458 goto err_unregister_dpll_device; ··· 480 479 dpll_pin_unregister(mdpll->dpll, mdpll->dpll_pin, 481 480 &mlx5_dpll_pins_ops, mdpll); 482 481 err_put_dpll_pin: 483 - dpll_pin_put(mdpll->dpll_pin); 482 + dpll_pin_put(mdpll->dpll_pin, NULL); 484 483 err_unregister_dpll_device: 485 484 dpll_device_unregister(mdpll->dpll, &mlx5_dpll_device_ops, mdpll); 486 485 err_put_dpll_device: 487 - dpll_device_put(mdpll->dpll); 486 + dpll_device_put(mdpll->dpll, NULL); 488 487 err_free_mdpll: 489 488 kfree(mdpll); 490 489 return err; ··· 500 499 destroy_workqueue(mdpll->wq); 501 500 dpll_pin_unregister(mdpll->dpll, mdpll->dpll_pin, 502 501 &mlx5_dpll_pins_ops, mdpll); 503 - dpll_pin_put(mdpll->dpll_pin); 502 + dpll_pin_put(mdpll->dpll_pin, NULL); 504 503 dpll_device_unregister(mdpll->dpll, &mlx5_dpll_device_ops, mdpll); 505 - dpll_device_put(mdpll->dpll); 504 + dpll_device_put(mdpll->dpll, NULL); 506 505 kfree(mdpll); 507 506 508 507 mlx5_dpll_synce_status_set(mdev,
+8 -7
drivers/ptp/ptp_ocp.c
··· 4788 4788 devlink_register(devlink); 4789 4789 4790 4790 clkid = pci_get_dsn(pdev); 4791 - bp->dpll = dpll_device_get(clkid, 0, THIS_MODULE); 4791 + bp->dpll = dpll_device_get(clkid, 0, THIS_MODULE, NULL); 4792 4792 if (IS_ERR(bp->dpll)) { 4793 4793 err = PTR_ERR(bp->dpll); 4794 4794 dev_err(&pdev->dev, "dpll_device_alloc failed\n"); ··· 4800 4800 goto out; 4801 4801 4802 4802 for (i = 0; i < OCP_SMA_NUM; i++) { 4803 - bp->sma[i].dpll_pin = dpll_pin_get(clkid, i, THIS_MODULE, &bp->sma[i].dpll_prop); 4803 + bp->sma[i].dpll_pin = dpll_pin_get(clkid, i, THIS_MODULE, 4804 + &bp->sma[i].dpll_prop, NULL); 4804 4805 if (IS_ERR(bp->sma[i].dpll_pin)) { 4805 4806 err = PTR_ERR(bp->sma[i].dpll_pin); 4806 4807 goto out_dpll; ··· 4810 4809 err = dpll_pin_register(bp->dpll, bp->sma[i].dpll_pin, &dpll_pins_ops, 4811 4810 &bp->sma[i]); 4812 4811 if (err) { 4813 - dpll_pin_put(bp->sma[i].dpll_pin); 4812 + dpll_pin_put(bp->sma[i].dpll_pin, NULL); 4814 4813 goto out_dpll; 4815 4814 } 4816 4815 } ··· 4820 4819 out_dpll: 4821 4820 while (i--) { 4822 4821 dpll_pin_unregister(bp->dpll, bp->sma[i].dpll_pin, &dpll_pins_ops, &bp->sma[i]); 4823 - dpll_pin_put(bp->sma[i].dpll_pin); 4822 + dpll_pin_put(bp->sma[i].dpll_pin, NULL); 4824 4823 } 4825 - dpll_device_put(bp->dpll); 4824 + dpll_device_put(bp->dpll, NULL); 4826 4825 out: 4827 4826 ptp_ocp_detach(bp); 4828 4827 out_disable: ··· 4843 4842 for (i = 0; i < OCP_SMA_NUM; i++) { 4844 4843 if (bp->sma[i].dpll_pin) { 4845 4844 dpll_pin_unregister(bp->dpll, bp->sma[i].dpll_pin, &dpll_pins_ops, &bp->sma[i]); 4846 - dpll_pin_put(bp->sma[i].dpll_pin); 4845 + dpll_pin_put(bp->sma[i].dpll_pin, NULL); 4847 4846 } 4848 4847 } 4849 4848 dpll_device_unregister(bp->dpll, &dpll_ops, bp); 4850 - dpll_device_put(bp->dpll); 4849 + dpll_device_put(bp->dpll, NULL); 4851 4850 devlink_unregister(devlink); 4852 4851 ptp_ocp_detach(bp); 4853 4852 pci_disable_device(pdev);
+15 -6
include/linux/dpll.h
··· 18 18 struct dpll_pin; 19 19 struct dpll_pin_esync; 20 20 struct fwnode_handle; 21 + struct ref_tracker; 21 22 22 23 struct dpll_device_ops { 23 24 int (*mode_get)(const struct dpll_device *dpll, void *dpll_priv, ··· 174 173 u32 phase_gran; 175 174 }; 176 175 176 + #ifdef CONFIG_DPLL_REFCNT_TRACKER 177 + typedef struct ref_tracker *dpll_tracker; 178 + #else 179 + typedef struct {} dpll_tracker; 180 + #endif 181 + 177 182 #define DPLL_DEVICE_CREATED 1 178 183 #define DPLL_DEVICE_DELETED 2 179 184 #define DPLL_DEVICE_CHANGED 3 ··· 212 205 int dpll_netdev_add_pin_handle(struct sk_buff *msg, 213 206 const struct net_device *dev); 214 207 215 - struct dpll_pin *fwnode_dpll_pin_find(struct fwnode_handle *fwnode); 208 + struct dpll_pin *fwnode_dpll_pin_find(struct fwnode_handle *fwnode, 209 + dpll_tracker *tracker); 216 210 #else 217 211 static inline void 218 212 dpll_netdev_pin_set(struct net_device *dev, struct dpll_pin *dpll_pin) { } ··· 231 223 } 232 224 233 225 static inline struct dpll_pin * 234 - fwnode_dpll_pin_find(struct fwnode_handle *fwnode) 226 + fwnode_dpll_pin_find(struct fwnode_handle *fwnode, dpll_tracker *tracker) 235 227 { 236 228 return NULL; 237 229 } 238 230 #endif 239 231 240 232 struct dpll_device * 241 - dpll_device_get(u64 clock_id, u32 dev_driver_id, struct module *module); 233 + dpll_device_get(u64 clock_id, u32 dev_driver_id, struct module *module, 234 + dpll_tracker *tracker); 242 235 243 - void dpll_device_put(struct dpll_device *dpll); 236 + void dpll_device_put(struct dpll_device *dpll, dpll_tracker *tracker); 244 237 245 238 int dpll_device_register(struct dpll_device *dpll, enum dpll_type type, 246 239 const struct dpll_device_ops *ops, void *priv); ··· 253 244 254 245 struct dpll_pin * 255 246 dpll_pin_get(u64 clock_id, u32 dev_driver_id, struct module *module, 256 - const struct dpll_pin_properties *prop); 247 + const struct dpll_pin_properties *prop, dpll_tracker *tracker); 257 248 258 249 int dpll_pin_register(struct dpll_device *dpll, struct dpll_pin *pin, 259 250 const struct dpll_pin_ops *ops, void *priv); ··· 261 252 void dpll_pin_unregister(struct dpll_device *dpll, struct dpll_pin *pin, 262 253 const struct dpll_pin_ops *ops, void *priv); 263 254 264 - void dpll_pin_put(struct dpll_pin *pin); 255 + void dpll_pin_put(struct dpll_pin *pin, dpll_tracker *tracker); 265 256 266 257 void dpll_pin_fwnode_set(struct dpll_pin *pin, struct fwnode_handle *fwnode); 267 258