1*1850e76bSJiri Pirko // SPDX-License-Identifier: GPL-2.0-or-later 2*1850e76bSJiri Pirko /* Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. */ 3*1850e76bSJiri Pirko 4*1850e76bSJiri Pirko #include <net/devlink.h> 5*1850e76bSJiri Pirko 6*1850e76bSJiri Pirko #include "devl_internal.h" 7*1850e76bSJiri Pirko 8*1850e76bSJiri Pirko static LIST_HEAD(shd_list); 9*1850e76bSJiri Pirko static DEFINE_MUTEX(shd_mutex); /* Protects shd_list and shd->list */ 10*1850e76bSJiri Pirko 11*1850e76bSJiri Pirko /* This structure represents a shared devlink instance, 12*1850e76bSJiri Pirko * there is one created per identifier (e.g., serial number). 13*1850e76bSJiri Pirko */ 14*1850e76bSJiri Pirko struct devlink_shd { 15*1850e76bSJiri Pirko struct list_head list; /* Node in shd list */ 16*1850e76bSJiri Pirko const char *id; /* Identifier string (e.g., serial number) */ 17*1850e76bSJiri Pirko refcount_t refcount; /* Reference count */ 18*1850e76bSJiri Pirko size_t priv_size; /* Size of driver private data */ 19*1850e76bSJiri Pirko char priv[] __aligned(NETDEV_ALIGN) __counted_by(priv_size); 20*1850e76bSJiri Pirko }; 21*1850e76bSJiri Pirko 22*1850e76bSJiri Pirko static struct devlink_shd *devlink_shd_lookup(const char *id) 23*1850e76bSJiri Pirko { 24*1850e76bSJiri Pirko struct devlink_shd *shd; 25*1850e76bSJiri Pirko 26*1850e76bSJiri Pirko list_for_each_entry(shd, &shd_list, list) { 27*1850e76bSJiri Pirko if (!strcmp(shd->id, id)) 28*1850e76bSJiri Pirko return shd; 29*1850e76bSJiri Pirko } 30*1850e76bSJiri Pirko 31*1850e76bSJiri Pirko return NULL; 32*1850e76bSJiri Pirko } 33*1850e76bSJiri Pirko 34*1850e76bSJiri Pirko static struct devlink_shd *devlink_shd_create(const char *id, 35*1850e76bSJiri Pirko const struct devlink_ops *ops, 36*1850e76bSJiri Pirko size_t priv_size, 37*1850e76bSJiri Pirko const struct device_driver *driver) 38*1850e76bSJiri Pirko { 39*1850e76bSJiri Pirko struct devlink_shd *shd; 40*1850e76bSJiri Pirko struct devlink *devlink; 41*1850e76bSJiri Pirko 42*1850e76bSJiri Pirko devlink = __devlink_alloc(ops, sizeof(struct devlink_shd) + priv_size, 43*1850e76bSJiri Pirko &init_net, NULL, driver); 44*1850e76bSJiri Pirko if (!devlink) 45*1850e76bSJiri Pirko return NULL; 46*1850e76bSJiri Pirko shd = devlink_priv(devlink); 47*1850e76bSJiri Pirko 48*1850e76bSJiri Pirko shd->id = kstrdup(id, GFP_KERNEL); 49*1850e76bSJiri Pirko if (!shd->id) 50*1850e76bSJiri Pirko goto err_devlink_free; 51*1850e76bSJiri Pirko shd->priv_size = priv_size; 52*1850e76bSJiri Pirko refcount_set(&shd->refcount, 1); 53*1850e76bSJiri Pirko 54*1850e76bSJiri Pirko devl_lock(devlink); 55*1850e76bSJiri Pirko devl_register(devlink); 56*1850e76bSJiri Pirko devl_unlock(devlink); 57*1850e76bSJiri Pirko 58*1850e76bSJiri Pirko list_add_tail(&shd->list, &shd_list); 59*1850e76bSJiri Pirko 60*1850e76bSJiri Pirko return shd; 61*1850e76bSJiri Pirko 62*1850e76bSJiri Pirko err_devlink_free: 63*1850e76bSJiri Pirko devlink_free(devlink); 64*1850e76bSJiri Pirko return NULL; 65*1850e76bSJiri Pirko } 66*1850e76bSJiri Pirko 67*1850e76bSJiri Pirko static void devlink_shd_destroy(struct devlink_shd *shd) 68*1850e76bSJiri Pirko { 69*1850e76bSJiri Pirko struct devlink *devlink = priv_to_devlink(shd); 70*1850e76bSJiri Pirko 71*1850e76bSJiri Pirko list_del(&shd->list); 72*1850e76bSJiri Pirko devl_lock(devlink); 73*1850e76bSJiri Pirko devl_unregister(devlink); 74*1850e76bSJiri Pirko devl_unlock(devlink); 75*1850e76bSJiri Pirko kfree(shd->id); 76*1850e76bSJiri Pirko devlink_free(devlink); 77*1850e76bSJiri Pirko } 78*1850e76bSJiri Pirko 79*1850e76bSJiri Pirko /** 80*1850e76bSJiri Pirko * devlink_shd_get - Get or create a shared devlink instance 81*1850e76bSJiri Pirko * @id: Identifier string (e.g., serial number) for the shared instance 82*1850e76bSJiri Pirko * @ops: Devlink operations structure 83*1850e76bSJiri Pirko * @priv_size: Size of private data structure 84*1850e76bSJiri Pirko * @driver: Driver associated with the shared devlink instance 85*1850e76bSJiri Pirko * 86*1850e76bSJiri Pirko * Get an existing shared devlink instance identified by @id, or create 87*1850e76bSJiri Pirko * a new one if it doesn't exist. Return the devlink instance with a 88*1850e76bSJiri Pirko * reference held. The caller must call devlink_shd_put() when done. 89*1850e76bSJiri Pirko * 90*1850e76bSJiri Pirko * All callers sharing the same @id must pass identical @ops, @priv_size 91*1850e76bSJiri Pirko * and @driver. A mismatch triggers a warning and returns NULL. 92*1850e76bSJiri Pirko * 93*1850e76bSJiri Pirko * Return: Pointer to the shared devlink instance on success, 94*1850e76bSJiri Pirko * NULL on failure 95*1850e76bSJiri Pirko */ 96*1850e76bSJiri Pirko struct devlink *devlink_shd_get(const char *id, 97*1850e76bSJiri Pirko const struct devlink_ops *ops, 98*1850e76bSJiri Pirko size_t priv_size, 99*1850e76bSJiri Pirko const struct device_driver *driver) 100*1850e76bSJiri Pirko { 101*1850e76bSJiri Pirko struct devlink *devlink; 102*1850e76bSJiri Pirko struct devlink_shd *shd; 103*1850e76bSJiri Pirko 104*1850e76bSJiri Pirko mutex_lock(&shd_mutex); 105*1850e76bSJiri Pirko 106*1850e76bSJiri Pirko shd = devlink_shd_lookup(id); 107*1850e76bSJiri Pirko if (!shd) { 108*1850e76bSJiri Pirko shd = devlink_shd_create(id, ops, priv_size, driver); 109*1850e76bSJiri Pirko goto unlock; 110*1850e76bSJiri Pirko } 111*1850e76bSJiri Pirko 112*1850e76bSJiri Pirko devlink = priv_to_devlink(shd); 113*1850e76bSJiri Pirko if (WARN_ON_ONCE(devlink->ops != ops || 114*1850e76bSJiri Pirko shd->priv_size != priv_size || 115*1850e76bSJiri Pirko devlink->dev_driver != driver)) { 116*1850e76bSJiri Pirko shd = NULL; 117*1850e76bSJiri Pirko goto unlock; 118*1850e76bSJiri Pirko } 119*1850e76bSJiri Pirko refcount_inc(&shd->refcount); 120*1850e76bSJiri Pirko 121*1850e76bSJiri Pirko unlock: 122*1850e76bSJiri Pirko mutex_unlock(&shd_mutex); 123*1850e76bSJiri Pirko return shd ? priv_to_devlink(shd) : NULL; 124*1850e76bSJiri Pirko } 125*1850e76bSJiri Pirko EXPORT_SYMBOL_GPL(devlink_shd_get); 126*1850e76bSJiri Pirko 127*1850e76bSJiri Pirko /** 128*1850e76bSJiri Pirko * devlink_shd_put - Release a reference on a shared devlink instance 129*1850e76bSJiri Pirko * @devlink: Shared devlink instance 130*1850e76bSJiri Pirko * 131*1850e76bSJiri Pirko * Release a reference on a shared devlink instance obtained via 132*1850e76bSJiri Pirko * devlink_shd_get(). 133*1850e76bSJiri Pirko */ 134*1850e76bSJiri Pirko void devlink_shd_put(struct devlink *devlink) 135*1850e76bSJiri Pirko { 136*1850e76bSJiri Pirko struct devlink_shd *shd; 137*1850e76bSJiri Pirko 138*1850e76bSJiri Pirko mutex_lock(&shd_mutex); 139*1850e76bSJiri Pirko shd = devlink_priv(devlink); 140*1850e76bSJiri Pirko if (refcount_dec_and_test(&shd->refcount)) 141*1850e76bSJiri Pirko devlink_shd_destroy(shd); 142*1850e76bSJiri Pirko mutex_unlock(&shd_mutex); 143*1850e76bSJiri Pirko } 144*1850e76bSJiri Pirko EXPORT_SYMBOL_GPL(devlink_shd_put); 145*1850e76bSJiri Pirko 146*1850e76bSJiri Pirko /** 147*1850e76bSJiri Pirko * devlink_shd_get_priv - Get private data from shared devlink instance 148*1850e76bSJiri Pirko * @devlink: Devlink instance 149*1850e76bSJiri Pirko * 150*1850e76bSJiri Pirko * Returns a pointer to the driver's private data structure within 151*1850e76bSJiri Pirko * the shared devlink instance. 152*1850e76bSJiri Pirko * 153*1850e76bSJiri Pirko * Return: Pointer to private data 154*1850e76bSJiri Pirko */ 155*1850e76bSJiri Pirko void *devlink_shd_get_priv(struct devlink *devlink) 156*1850e76bSJiri Pirko { 157*1850e76bSJiri Pirko struct devlink_shd *shd = devlink_priv(devlink); 158*1850e76bSJiri Pirko 159*1850e76bSJiri Pirko return shd->priv; 160*1850e76bSJiri Pirko } 161*1850e76bSJiri Pirko EXPORT_SYMBOL_GPL(devlink_shd_get_priv); 162