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