File Index
Files and directories
Sign in
FILE

devlink.c

File preview with syntax highlighting.

linux-6.19.14/net/dsa/devlink.c C
  1// SPDX-License-Identifier: GPL-2.0-or-later
  2/*
  3 * DSA devlink handling
  4 */
  5
  6#include <net/dsa.h>
  7#include <net/devlink.h>
  8
  9#include "devlink.h"
 10
 11static int dsa_devlink_info_get(struct devlink *dl,
 12				struct devlink_info_req *req,
 13				struct netlink_ext_ack *extack)
 14{
 15	struct dsa_switch *ds = dsa_devlink_to_ds(dl);
 16
 17	if (ds->ops->devlink_info_get)
 18		return ds->ops->devlink_info_get(ds, req, extack);
 19
 20	return -EOPNOTSUPP;
 21}
 22
 23static int dsa_devlink_sb_pool_get(struct devlink *dl,
 24				   unsigned int sb_index, u16 pool_index,
 25				   struct devlink_sb_pool_info *pool_info)
 26{
 27	struct dsa_switch *ds = dsa_devlink_to_ds(dl);
 28
 29	if (!ds->ops->devlink_sb_pool_get)
 30		return -EOPNOTSUPP;
 31
 32	return ds->ops->devlink_sb_pool_get(ds, sb_index, pool_index,
 33					    pool_info);
 34}
 35
 36static int dsa_devlink_sb_pool_set(struct devlink *dl, unsigned int sb_index,
 37				   u16 pool_index, u32 size,
 38				   enum devlink_sb_threshold_type threshold_type,
 39				   struct netlink_ext_ack *extack)
 40{
 41	struct dsa_switch *ds = dsa_devlink_to_ds(dl);
 42
 43	if (!ds->ops->devlink_sb_pool_set)
 44		return -EOPNOTSUPP;
 45
 46	return ds->ops->devlink_sb_pool_set(ds, sb_index, pool_index, size,
 47					    threshold_type, extack);
 48}
 49
 50static int dsa_devlink_sb_port_pool_get(struct devlink_port *dlp,
 51					unsigned int sb_index, u16 pool_index,
 52					u32 *p_threshold)
 53{
 54	struct dsa_switch *ds = dsa_devlink_port_to_ds(dlp);
 55	int port = dsa_devlink_port_to_port(dlp);
 56
 57	if (!ds->ops->devlink_sb_port_pool_get)
 58		return -EOPNOTSUPP;
 59
 60	return ds->ops->devlink_sb_port_pool_get(ds, port, sb_index,
 61						 pool_index, p_threshold);
 62}
 63
 64static int dsa_devlink_sb_port_pool_set(struct devlink_port *dlp,
 65					unsigned int sb_index, u16 pool_index,
 66					u32 threshold,
 67					struct netlink_ext_ack *extack)
 68{
 69	struct dsa_switch *ds = dsa_devlink_port_to_ds(dlp);
 70	int port = dsa_devlink_port_to_port(dlp);
 71
 72	if (!ds->ops->devlink_sb_port_pool_set)
 73		return -EOPNOTSUPP;
 74
 75	return ds->ops->devlink_sb_port_pool_set(ds, port, sb_index,
 76						 pool_index, threshold, extack);
 77}
 78
 79static int
 80dsa_devlink_sb_tc_pool_bind_get(struct devlink_port *dlp,
 81				unsigned int sb_index, u16 tc_index,
 82				enum devlink_sb_pool_type pool_type,
 83				u16 *p_pool_index, u32 *p_threshold)
 84{
 85	struct dsa_switch *ds = dsa_devlink_port_to_ds(dlp);
 86	int port = dsa_devlink_port_to_port(dlp);
 87
 88	if (!ds->ops->devlink_sb_tc_pool_bind_get)
 89		return -EOPNOTSUPP;
 90
 91	return ds->ops->devlink_sb_tc_pool_bind_get(ds, port, sb_index,
 92						    tc_index, pool_type,
 93						    p_pool_index, p_threshold);
 94}
 95
 96static int
 97dsa_devlink_sb_tc_pool_bind_set(struct devlink_port *dlp,
 98				unsigned int sb_index, u16 tc_index,
 99				enum devlink_sb_pool_type pool_type,
100				u16 pool_index, u32 threshold,
101				struct netlink_ext_ack *extack)
102{
103	struct dsa_switch *ds = dsa_devlink_port_to_ds(dlp);
104	int port = dsa_devlink_port_to_port(dlp);
105
106	if (!ds->ops->devlink_sb_tc_pool_bind_set)
107		return -EOPNOTSUPP;
108
109	return ds->ops->devlink_sb_tc_pool_bind_set(ds, port, sb_index,
110						    tc_index, pool_type,
111						    pool_index, threshold,
112						    extack);
113}
114
115static int dsa_devlink_sb_occ_snapshot(struct devlink *dl,
116				       unsigned int sb_index)
117{
118	struct dsa_switch *ds = dsa_devlink_to_ds(dl);
119
120	if (!ds->ops->devlink_sb_occ_snapshot)
121		return -EOPNOTSUPP;
122
123	return ds->ops->devlink_sb_occ_snapshot(ds, sb_index);
124}
125
126static int dsa_devlink_sb_occ_max_clear(struct devlink *dl,
127					unsigned int sb_index)
128{
129	struct dsa_switch *ds = dsa_devlink_to_ds(dl);
130
131	if (!ds->ops->devlink_sb_occ_max_clear)
132		return -EOPNOTSUPP;
133
134	return ds->ops->devlink_sb_occ_max_clear(ds, sb_index);
135}
136
137static int dsa_devlink_sb_occ_port_pool_get(struct devlink_port *dlp,
138					    unsigned int sb_index,
139					    u16 pool_index, u32 *p_cur,
140					    u32 *p_max)
141{
142	struct dsa_switch *ds = dsa_devlink_port_to_ds(dlp);
143	int port = dsa_devlink_port_to_port(dlp);
144
145	if (!ds->ops->devlink_sb_occ_port_pool_get)
146		return -EOPNOTSUPP;
147
148	return ds->ops->devlink_sb_occ_port_pool_get(ds, port, sb_index,
149						     pool_index, p_cur, p_max);
150}
151
152static int
153dsa_devlink_sb_occ_tc_port_bind_get(struct devlink_port *dlp,
154				    unsigned int sb_index, u16 tc_index,
155				    enum devlink_sb_pool_type pool_type,
156				    u32 *p_cur, u32 *p_max)
157{
158	struct dsa_switch *ds = dsa_devlink_port_to_ds(dlp);
159	int port = dsa_devlink_port_to_port(dlp);
160
161	if (!ds->ops->devlink_sb_occ_tc_port_bind_get)
162		return -EOPNOTSUPP;
163
164	return ds->ops->devlink_sb_occ_tc_port_bind_get(ds, port,
165							sb_index, tc_index,
166							pool_type, p_cur,
167							p_max);
168}
169
170static const struct devlink_ops dsa_devlink_ops = {
171	.info_get			= dsa_devlink_info_get,
172	.sb_pool_get			= dsa_devlink_sb_pool_get,
173	.sb_pool_set			= dsa_devlink_sb_pool_set,
174	.sb_port_pool_get		= dsa_devlink_sb_port_pool_get,
175	.sb_port_pool_set		= dsa_devlink_sb_port_pool_set,
176	.sb_tc_pool_bind_get		= dsa_devlink_sb_tc_pool_bind_get,
177	.sb_tc_pool_bind_set		= dsa_devlink_sb_tc_pool_bind_set,
178	.sb_occ_snapshot		= dsa_devlink_sb_occ_snapshot,
179	.sb_occ_max_clear		= dsa_devlink_sb_occ_max_clear,
180	.sb_occ_port_pool_get		= dsa_devlink_sb_occ_port_pool_get,
181	.sb_occ_tc_port_bind_get	= dsa_devlink_sb_occ_tc_port_bind_get,
182};
183
184int dsa_devlink_param_get(struct devlink *dl, u32 id,
185			  struct devlink_param_gset_ctx *ctx,
186			  struct netlink_ext_ack *extack)
187{
188	struct dsa_switch *ds = dsa_devlink_to_ds(dl);
189
190	if (!ds->ops->devlink_param_get)
191		return -EOPNOTSUPP;
192
193	return ds->ops->devlink_param_get(ds, id, ctx);
194}
195EXPORT_SYMBOL_GPL(dsa_devlink_param_get);
196
197int dsa_devlink_param_set(struct devlink *dl, u32 id,
198			  struct devlink_param_gset_ctx *ctx,
199			  struct netlink_ext_ack *extack)
200{
201	struct dsa_switch *ds = dsa_devlink_to_ds(dl);
202
203	if (!ds->ops->devlink_param_set)
204		return -EOPNOTSUPP;
205
206	return ds->ops->devlink_param_set(ds, id, ctx);
207}
208EXPORT_SYMBOL_GPL(dsa_devlink_param_set);
209
210int dsa_devlink_params_register(struct dsa_switch *ds,
211				const struct devlink_param *params,
212				size_t params_count)
213{
214	return devlink_params_register(ds->devlink, params, params_count);
215}
216EXPORT_SYMBOL_GPL(dsa_devlink_params_register);
217
218void dsa_devlink_params_unregister(struct dsa_switch *ds,
219				   const struct devlink_param *params,
220				   size_t params_count)
221{
222	devlink_params_unregister(ds->devlink, params, params_count);
223}
224EXPORT_SYMBOL_GPL(dsa_devlink_params_unregister);
225
226int dsa_devlink_resource_register(struct dsa_switch *ds,
227				  const char *resource_name,
228				  u64 resource_size,
229				  u64 resource_id,
230				  u64 parent_resource_id,
231				  const struct devlink_resource_size_params *size_params)
232{
233	int ret;
234
235	devl_lock(ds->devlink);
236	ret = devl_resource_register(ds->devlink, resource_name, resource_size,
237				     resource_id, parent_resource_id,
238				     size_params);
239	devl_unlock(ds->devlink);
240
241	return ret;
242}
243EXPORT_SYMBOL_GPL(dsa_devlink_resource_register);
244
245void dsa_devlink_resources_unregister(struct dsa_switch *ds)
246{
247	devlink_resources_unregister(ds->devlink);
248}
249EXPORT_SYMBOL_GPL(dsa_devlink_resources_unregister);
250
251void dsa_devlink_resource_occ_get_register(struct dsa_switch *ds,
252					   u64 resource_id,
253					   devlink_resource_occ_get_t *occ_get,
254					   void *occ_get_priv)
255{
256	devl_lock(ds->devlink);
257	devl_resource_occ_get_register(ds->devlink, resource_id, occ_get,
258				       occ_get_priv);
259	devl_unlock(ds->devlink);
260}
261EXPORT_SYMBOL_GPL(dsa_devlink_resource_occ_get_register);
262
263void dsa_devlink_resource_occ_get_unregister(struct dsa_switch *ds,
264					     u64 resource_id)
265{
266	devl_lock(ds->devlink);
267	devl_resource_occ_get_unregister(ds->devlink, resource_id);
268	devl_unlock(ds->devlink);
269}
270EXPORT_SYMBOL_GPL(dsa_devlink_resource_occ_get_unregister);
271
272struct devlink_region *
273dsa_devlink_region_create(struct dsa_switch *ds,
274			  const struct devlink_region_ops *ops,
275			  u32 region_max_snapshots, u64 region_size)
276{
277	return devlink_region_create(ds->devlink, ops, region_max_snapshots,
278				     region_size);
279}
280EXPORT_SYMBOL_GPL(dsa_devlink_region_create);
281
282struct devlink_region *
283dsa_devlink_port_region_create(struct dsa_switch *ds,
284			       int port,
285			       const struct devlink_port_region_ops *ops,
286			       u32 region_max_snapshots, u64 region_size)
287{
288	struct dsa_port *dp = dsa_to_port(ds, port);
289
290	return devlink_port_region_create(&dp->devlink_port, ops,
291					  region_max_snapshots,
292					  region_size);
293}
294EXPORT_SYMBOL_GPL(dsa_devlink_port_region_create);
295
296void dsa_devlink_region_destroy(struct devlink_region *region)
297{
298	devlink_region_destroy(region);
299}
300EXPORT_SYMBOL_GPL(dsa_devlink_region_destroy);
301
302int dsa_port_devlink_setup(struct dsa_port *dp)
303{
304	struct devlink_port *dlp = &dp->devlink_port;
305	struct dsa_switch_tree *dst = dp->ds->dst;
306	struct devlink_port_attrs attrs = {};
307	struct devlink *dl = dp->ds->devlink;
308	struct dsa_switch *ds = dp->ds;
309	const unsigned char *id;
310	unsigned char len;
311	int err;
312
313	memset(dlp, 0, sizeof(*dlp));
314	devlink_port_init(dl, dlp);
315
316	if (ds->ops->port_setup) {
317		err = ds->ops->port_setup(ds, dp->index);
318		if (err)
319			return err;
320	}
321
322	id = (const unsigned char *)&dst->index;
323	len = sizeof(dst->index);
324
325	attrs.phys.port_number = dp->index;
326	memcpy(attrs.switch_id.id, id, len);
327	attrs.switch_id.id_len = len;
328
329	switch (dp->type) {
330	case DSA_PORT_TYPE_UNUSED:
331		attrs.flavour = DEVLINK_PORT_FLAVOUR_UNUSED;
332		break;
333	case DSA_PORT_TYPE_CPU:
334		attrs.flavour = DEVLINK_PORT_FLAVOUR_CPU;
335		break;
336	case DSA_PORT_TYPE_DSA:
337		attrs.flavour = DEVLINK_PORT_FLAVOUR_DSA;
338		break;
339	case DSA_PORT_TYPE_USER:
340		attrs.flavour = DEVLINK_PORT_FLAVOUR_PHYSICAL;
341		break;
342	}
343
344	devlink_port_attrs_set(dlp, &attrs);
345	err = devlink_port_register(dl, dlp, dp->index);
346	if (err) {
347		if (ds->ops->port_teardown)
348			ds->ops->port_teardown(ds, dp->index);
349		return err;
350	}
351
352	return 0;
353}
354
355void dsa_port_devlink_teardown(struct dsa_port *dp)
356{
357	struct devlink_port *dlp = &dp->devlink_port;
358	struct dsa_switch *ds = dp->ds;
359
360	devlink_port_unregister(dlp);
361
362	if (ds->ops->port_teardown)
363		ds->ops->port_teardown(ds, dp->index);
364
365	devlink_port_fini(dlp);
366}
367
368void dsa_switch_devlink_register(struct dsa_switch *ds)
369{
370	devlink_register(ds->devlink);
371}
372
373void dsa_switch_devlink_unregister(struct dsa_switch *ds)
374{
375	devlink_unregister(ds->devlink);
376}
377
378int dsa_switch_devlink_alloc(struct dsa_switch *ds)
379{
380	struct dsa_devlink_priv *dl_priv;
381	struct devlink *dl;
382
383	/* Add the switch to devlink before calling setup, so that setup can
384	 * add dpipe tables
385	 */
386	dl = devlink_alloc(&dsa_devlink_ops, sizeof(*dl_priv), ds->dev);
387	if (!dl)
388		return -ENOMEM;
389
390	ds->devlink = dl;
391
392	dl_priv = devlink_priv(ds->devlink);
393	dl_priv->ds = ds;
394
395	return 0;
396}
397
398void dsa_switch_devlink_free(struct dsa_switch *ds)
399{
400	devlink_free(ds->devlink);
401	ds->devlink = NULL;
402}
~/ Read-only file preview.