.. | .. |
---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-or-later |
---|
1 | 2 | /* |
---|
2 | 3 | * net/dsa/dsa.c - Hardware switch handling |
---|
3 | 4 | * Copyright (c) 2008-2009 Marvell Semiconductor |
---|
4 | 5 | * Copyright (c) 2013 Florian Fainelli <florian@openwrt.org> |
---|
5 | | - * |
---|
6 | | - * This program is free software; you can redistribute it and/or modify |
---|
7 | | - * it under the terms of the GNU General Public License as published by |
---|
8 | | - * the Free Software Foundation; either version 2 of the License, or |
---|
9 | | - * (at your option) any later version. |
---|
10 | 6 | */ |
---|
11 | 7 | |
---|
12 | 8 | #include <linux/device.h> |
---|
.. | .. |
---|
27 | 23 | |
---|
28 | 24 | #include "dsa_priv.h" |
---|
29 | 25 | |
---|
| 26 | +static LIST_HEAD(dsa_tag_drivers_list); |
---|
| 27 | +static DEFINE_MUTEX(dsa_tag_drivers_lock); |
---|
| 28 | + |
---|
30 | 29 | static struct sk_buff *dsa_slave_notag_xmit(struct sk_buff *skb, |
---|
31 | 30 | struct net_device *dev) |
---|
32 | 31 | { |
---|
.. | .. |
---|
35 | 34 | } |
---|
36 | 35 | |
---|
37 | 36 | static const struct dsa_device_ops none_ops = { |
---|
| 37 | + .name = "none", |
---|
| 38 | + .proto = DSA_TAG_PROTO_NONE, |
---|
38 | 39 | .xmit = dsa_slave_notag_xmit, |
---|
39 | 40 | .rcv = NULL, |
---|
40 | 41 | }; |
---|
41 | 42 | |
---|
42 | | -const struct dsa_device_ops *dsa_device_ops[DSA_TAG_LAST] = { |
---|
43 | | -#ifdef CONFIG_NET_DSA_TAG_BRCM |
---|
44 | | - [DSA_TAG_PROTO_BRCM] = &brcm_netdev_ops, |
---|
45 | | -#endif |
---|
46 | | -#ifdef CONFIG_NET_DSA_TAG_BRCM_PREPEND |
---|
47 | | - [DSA_TAG_PROTO_BRCM_PREPEND] = &brcm_prepend_netdev_ops, |
---|
48 | | -#endif |
---|
49 | | -#ifdef CONFIG_NET_DSA_TAG_DSA |
---|
50 | | - [DSA_TAG_PROTO_DSA] = &dsa_netdev_ops, |
---|
51 | | -#endif |
---|
52 | | -#ifdef CONFIG_NET_DSA_TAG_EDSA |
---|
53 | | - [DSA_TAG_PROTO_EDSA] = &edsa_netdev_ops, |
---|
54 | | -#endif |
---|
55 | | -#ifdef CONFIG_NET_DSA_TAG_KSZ |
---|
56 | | - [DSA_TAG_PROTO_KSZ] = &ksz_netdev_ops, |
---|
57 | | -#endif |
---|
58 | | -#ifdef CONFIG_NET_DSA_TAG_LAN9303 |
---|
59 | | - [DSA_TAG_PROTO_LAN9303] = &lan9303_netdev_ops, |
---|
60 | | -#endif |
---|
61 | | -#ifdef CONFIG_NET_DSA_TAG_MTK |
---|
62 | | - [DSA_TAG_PROTO_MTK] = &mtk_netdev_ops, |
---|
63 | | -#endif |
---|
64 | | -#ifdef CONFIG_NET_DSA_TAG_QCA |
---|
65 | | - [DSA_TAG_PROTO_QCA] = &qca_netdev_ops, |
---|
66 | | -#endif |
---|
67 | | -#ifdef CONFIG_NET_DSA_TAG_TRAILER |
---|
68 | | - [DSA_TAG_PROTO_TRAILER] = &trailer_netdev_ops, |
---|
69 | | -#endif |
---|
70 | | - [DSA_TAG_PROTO_NONE] = &none_ops, |
---|
| 43 | +DSA_TAG_DRIVER(none_ops); |
---|
| 44 | + |
---|
| 45 | +static void dsa_tag_driver_register(struct dsa_tag_driver *dsa_tag_driver, |
---|
| 46 | + struct module *owner) |
---|
| 47 | +{ |
---|
| 48 | + dsa_tag_driver->owner = owner; |
---|
| 49 | + |
---|
| 50 | + mutex_lock(&dsa_tag_drivers_lock); |
---|
| 51 | + list_add_tail(&dsa_tag_driver->list, &dsa_tag_drivers_list); |
---|
| 52 | + mutex_unlock(&dsa_tag_drivers_lock); |
---|
| 53 | +} |
---|
| 54 | + |
---|
| 55 | +void dsa_tag_drivers_register(struct dsa_tag_driver *dsa_tag_driver_array[], |
---|
| 56 | + unsigned int count, struct module *owner) |
---|
| 57 | +{ |
---|
| 58 | + unsigned int i; |
---|
| 59 | + |
---|
| 60 | + for (i = 0; i < count; i++) |
---|
| 61 | + dsa_tag_driver_register(dsa_tag_driver_array[i], owner); |
---|
| 62 | +} |
---|
| 63 | + |
---|
| 64 | +static void dsa_tag_driver_unregister(struct dsa_tag_driver *dsa_tag_driver) |
---|
| 65 | +{ |
---|
| 66 | + mutex_lock(&dsa_tag_drivers_lock); |
---|
| 67 | + list_del(&dsa_tag_driver->list); |
---|
| 68 | + mutex_unlock(&dsa_tag_drivers_lock); |
---|
| 69 | +} |
---|
| 70 | +EXPORT_SYMBOL_GPL(dsa_tag_drivers_register); |
---|
| 71 | + |
---|
| 72 | +void dsa_tag_drivers_unregister(struct dsa_tag_driver *dsa_tag_driver_array[], |
---|
| 73 | + unsigned int count) |
---|
| 74 | +{ |
---|
| 75 | + unsigned int i; |
---|
| 76 | + |
---|
| 77 | + for (i = 0; i < count; i++) |
---|
| 78 | + dsa_tag_driver_unregister(dsa_tag_driver_array[i]); |
---|
| 79 | +} |
---|
| 80 | +EXPORT_SYMBOL_GPL(dsa_tag_drivers_unregister); |
---|
| 81 | + |
---|
| 82 | +const char *dsa_tag_protocol_to_str(const struct dsa_device_ops *ops) |
---|
| 83 | +{ |
---|
| 84 | + return ops->name; |
---|
71 | 85 | }; |
---|
72 | 86 | |
---|
73 | | -const struct dsa_device_ops *dsa_resolve_tag_protocol(int tag_protocol) |
---|
| 87 | +const struct dsa_device_ops *dsa_tag_driver_get(int tag_protocol) |
---|
74 | 88 | { |
---|
| 89 | + struct dsa_tag_driver *dsa_tag_driver; |
---|
75 | 90 | const struct dsa_device_ops *ops; |
---|
| 91 | + bool found = false; |
---|
76 | 92 | |
---|
77 | | - if (tag_protocol >= DSA_TAG_LAST) |
---|
78 | | - return ERR_PTR(-EINVAL); |
---|
79 | | - ops = dsa_device_ops[tag_protocol]; |
---|
| 93 | + request_module("%s%d", DSA_TAG_DRIVER_ALIAS, tag_protocol); |
---|
80 | 94 | |
---|
81 | | - if (!ops) |
---|
82 | | - return ERR_PTR(-ENOPROTOOPT); |
---|
| 95 | + mutex_lock(&dsa_tag_drivers_lock); |
---|
| 96 | + list_for_each_entry(dsa_tag_driver, &dsa_tag_drivers_list, list) { |
---|
| 97 | + ops = dsa_tag_driver->ops; |
---|
| 98 | + if (ops->proto == tag_protocol) { |
---|
| 99 | + found = true; |
---|
| 100 | + break; |
---|
| 101 | + } |
---|
| 102 | + } |
---|
| 103 | + |
---|
| 104 | + if (found) { |
---|
| 105 | + if (!try_module_get(dsa_tag_driver->owner)) |
---|
| 106 | + ops = ERR_PTR(-ENOPROTOOPT); |
---|
| 107 | + } else { |
---|
| 108 | + ops = ERR_PTR(-ENOPROTOOPT); |
---|
| 109 | + } |
---|
| 110 | + |
---|
| 111 | + mutex_unlock(&dsa_tag_drivers_lock); |
---|
83 | 112 | |
---|
84 | 113 | return ops; |
---|
| 114 | +} |
---|
| 115 | + |
---|
| 116 | +void dsa_tag_driver_put(const struct dsa_device_ops *ops) |
---|
| 117 | +{ |
---|
| 118 | + struct dsa_tag_driver *dsa_tag_driver; |
---|
| 119 | + |
---|
| 120 | + mutex_lock(&dsa_tag_drivers_lock); |
---|
| 121 | + list_for_each_entry(dsa_tag_driver, &dsa_tag_drivers_list, list) { |
---|
| 122 | + if (dsa_tag_driver->ops == ops) { |
---|
| 123 | + module_put(dsa_tag_driver->owner); |
---|
| 124 | + break; |
---|
| 125 | + } |
---|
| 126 | + } |
---|
| 127 | + mutex_unlock(&dsa_tag_drivers_lock); |
---|
85 | 128 | } |
---|
86 | 129 | |
---|
87 | 130 | static int dev_is_class(struct device *dev, void *class) |
---|
.. | .. |
---|
182 | 225 | skb->pkt_type = PACKET_HOST; |
---|
183 | 226 | skb->protocol = eth_type_trans(skb, skb->dev); |
---|
184 | 227 | |
---|
| 228 | + if (unlikely(cpu_dp->ds->untag_bridge_pvid)) { |
---|
| 229 | + nskb = dsa_untag_bridge_pvid(skb); |
---|
| 230 | + if (!nskb) { |
---|
| 231 | + kfree_skb(skb); |
---|
| 232 | + return 0; |
---|
| 233 | + } |
---|
| 234 | + skb = nskb; |
---|
| 235 | + } |
---|
| 236 | + |
---|
185 | 237 | s = this_cpu_ptr(p->stats64); |
---|
186 | 238 | u64_stats_update_begin(&s->syncp); |
---|
187 | 239 | s->rx_packets++; |
---|
.. | .. |
---|
199 | 251 | #ifdef CONFIG_PM_SLEEP |
---|
200 | 252 | static bool dsa_is_port_initialized(struct dsa_switch *ds, int p) |
---|
201 | 253 | { |
---|
202 | | - return dsa_is_user_port(ds, p) && ds->ports[p].slave; |
---|
| 254 | + const struct dsa_port *dp = dsa_to_port(ds, p); |
---|
| 255 | + |
---|
| 256 | + return dp->type == DSA_PORT_TYPE_USER && dp->slave; |
---|
203 | 257 | } |
---|
204 | 258 | |
---|
205 | 259 | int dsa_switch_suspend(struct dsa_switch *ds) |
---|
.. | .. |
---|
211 | 265 | if (!dsa_is_port_initialized(ds, i)) |
---|
212 | 266 | continue; |
---|
213 | 267 | |
---|
214 | | - ret = dsa_slave_suspend(ds->ports[i].slave); |
---|
| 268 | + ret = dsa_slave_suspend(dsa_to_port(ds, i)->slave); |
---|
215 | 269 | if (ret) |
---|
216 | 270 | return ret; |
---|
217 | 271 | } |
---|
.. | .. |
---|
238 | 292 | if (!dsa_is_port_initialized(ds, i)) |
---|
239 | 293 | continue; |
---|
240 | 294 | |
---|
241 | | - ret = dsa_slave_resume(ds->ports[i].slave); |
---|
| 295 | + ret = dsa_slave_resume(dsa_to_port(ds, i)->slave); |
---|
242 | 296 | if (ret) |
---|
243 | 297 | return ret; |
---|
244 | 298 | } |
---|
.. | .. |
---|
282 | 336 | } |
---|
283 | 337 | EXPORT_SYMBOL_GPL(call_dsa_notifiers); |
---|
284 | 338 | |
---|
| 339 | +int dsa_devlink_param_get(struct devlink *dl, u32 id, |
---|
| 340 | + struct devlink_param_gset_ctx *ctx) |
---|
| 341 | +{ |
---|
| 342 | + struct dsa_switch *ds = dsa_devlink_to_ds(dl); |
---|
| 343 | + |
---|
| 344 | + if (!ds->ops->devlink_param_get) |
---|
| 345 | + return -EOPNOTSUPP; |
---|
| 346 | + |
---|
| 347 | + return ds->ops->devlink_param_get(ds, id, ctx); |
---|
| 348 | +} |
---|
| 349 | +EXPORT_SYMBOL_GPL(dsa_devlink_param_get); |
---|
| 350 | + |
---|
| 351 | +int dsa_devlink_param_set(struct devlink *dl, u32 id, |
---|
| 352 | + struct devlink_param_gset_ctx *ctx) |
---|
| 353 | +{ |
---|
| 354 | + struct dsa_switch *ds = dsa_devlink_to_ds(dl); |
---|
| 355 | + |
---|
| 356 | + if (!ds->ops->devlink_param_set) |
---|
| 357 | + return -EOPNOTSUPP; |
---|
| 358 | + |
---|
| 359 | + return ds->ops->devlink_param_set(ds, id, ctx); |
---|
| 360 | +} |
---|
| 361 | +EXPORT_SYMBOL_GPL(dsa_devlink_param_set); |
---|
| 362 | + |
---|
| 363 | +int dsa_devlink_params_register(struct dsa_switch *ds, |
---|
| 364 | + const struct devlink_param *params, |
---|
| 365 | + size_t params_count) |
---|
| 366 | +{ |
---|
| 367 | + return devlink_params_register(ds->devlink, params, params_count); |
---|
| 368 | +} |
---|
| 369 | +EXPORT_SYMBOL_GPL(dsa_devlink_params_register); |
---|
| 370 | + |
---|
| 371 | +void dsa_devlink_params_unregister(struct dsa_switch *ds, |
---|
| 372 | + const struct devlink_param *params, |
---|
| 373 | + size_t params_count) |
---|
| 374 | +{ |
---|
| 375 | + devlink_params_unregister(ds->devlink, params, params_count); |
---|
| 376 | +} |
---|
| 377 | +EXPORT_SYMBOL_GPL(dsa_devlink_params_unregister); |
---|
| 378 | + |
---|
| 379 | +int dsa_devlink_resource_register(struct dsa_switch *ds, |
---|
| 380 | + const char *resource_name, |
---|
| 381 | + u64 resource_size, |
---|
| 382 | + u64 resource_id, |
---|
| 383 | + u64 parent_resource_id, |
---|
| 384 | + const struct devlink_resource_size_params *size_params) |
---|
| 385 | +{ |
---|
| 386 | + return devlink_resource_register(ds->devlink, resource_name, |
---|
| 387 | + resource_size, resource_id, |
---|
| 388 | + parent_resource_id, |
---|
| 389 | + size_params); |
---|
| 390 | +} |
---|
| 391 | +EXPORT_SYMBOL_GPL(dsa_devlink_resource_register); |
---|
| 392 | + |
---|
| 393 | +void dsa_devlink_resources_unregister(struct dsa_switch *ds) |
---|
| 394 | +{ |
---|
| 395 | + devlink_resources_unregister(ds->devlink, NULL); |
---|
| 396 | +} |
---|
| 397 | +EXPORT_SYMBOL_GPL(dsa_devlink_resources_unregister); |
---|
| 398 | + |
---|
| 399 | +void dsa_devlink_resource_occ_get_register(struct dsa_switch *ds, |
---|
| 400 | + u64 resource_id, |
---|
| 401 | + devlink_resource_occ_get_t *occ_get, |
---|
| 402 | + void *occ_get_priv) |
---|
| 403 | +{ |
---|
| 404 | + return devlink_resource_occ_get_register(ds->devlink, resource_id, |
---|
| 405 | + occ_get, occ_get_priv); |
---|
| 406 | +} |
---|
| 407 | +EXPORT_SYMBOL_GPL(dsa_devlink_resource_occ_get_register); |
---|
| 408 | + |
---|
| 409 | +void dsa_devlink_resource_occ_get_unregister(struct dsa_switch *ds, |
---|
| 410 | + u64 resource_id) |
---|
| 411 | +{ |
---|
| 412 | + devlink_resource_occ_get_unregister(ds->devlink, resource_id); |
---|
| 413 | +} |
---|
| 414 | +EXPORT_SYMBOL_GPL(dsa_devlink_resource_occ_get_unregister); |
---|
| 415 | + |
---|
| 416 | +struct devlink_region * |
---|
| 417 | +dsa_devlink_region_create(struct dsa_switch *ds, |
---|
| 418 | + const struct devlink_region_ops *ops, |
---|
| 419 | + u32 region_max_snapshots, u64 region_size) |
---|
| 420 | +{ |
---|
| 421 | + return devlink_region_create(ds->devlink, ops, region_max_snapshots, |
---|
| 422 | + region_size); |
---|
| 423 | +} |
---|
| 424 | +EXPORT_SYMBOL_GPL(dsa_devlink_region_create); |
---|
| 425 | + |
---|
| 426 | +struct devlink_region * |
---|
| 427 | +dsa_devlink_port_region_create(struct dsa_switch *ds, |
---|
| 428 | + int port, |
---|
| 429 | + const struct devlink_port_region_ops *ops, |
---|
| 430 | + u32 region_max_snapshots, u64 region_size) |
---|
| 431 | +{ |
---|
| 432 | + struct dsa_port *dp = dsa_to_port(ds, port); |
---|
| 433 | + |
---|
| 434 | + return devlink_port_region_create(&dp->devlink_port, ops, |
---|
| 435 | + region_max_snapshots, |
---|
| 436 | + region_size); |
---|
| 437 | +} |
---|
| 438 | +EXPORT_SYMBOL_GPL(dsa_devlink_port_region_create); |
---|
| 439 | + |
---|
| 440 | +void dsa_devlink_region_destroy(struct devlink_region *region) |
---|
| 441 | +{ |
---|
| 442 | + devlink_region_destroy(region); |
---|
| 443 | +} |
---|
| 444 | +EXPORT_SYMBOL_GPL(dsa_devlink_region_destroy); |
---|
| 445 | + |
---|
| 446 | +struct dsa_port *dsa_port_from_netdev(struct net_device *netdev) |
---|
| 447 | +{ |
---|
| 448 | + if (!netdev || !dsa_slave_dev_check(netdev)) |
---|
| 449 | + return ERR_PTR(-ENODEV); |
---|
| 450 | + |
---|
| 451 | + return dsa_slave_to_port(netdev); |
---|
| 452 | +} |
---|
| 453 | +EXPORT_SYMBOL_GPL(dsa_port_from_netdev); |
---|
| 454 | + |
---|
285 | 455 | static int __init dsa_init_module(void) |
---|
286 | 456 | { |
---|
287 | 457 | int rc; |
---|
.. | .. |
---|
295 | 465 | if (rc) |
---|
296 | 466 | goto register_notifier_fail; |
---|
297 | 467 | |
---|
298 | | - rc = dsa_legacy_register(); |
---|
299 | | - if (rc) |
---|
300 | | - goto legacy_register_fail; |
---|
301 | | - |
---|
302 | 468 | dev_add_pack(&dsa_pack_type); |
---|
| 469 | + |
---|
| 470 | + dsa_tag_driver_register(&DSA_TAG_DRIVER_NAME(none_ops), |
---|
| 471 | + THIS_MODULE); |
---|
303 | 472 | |
---|
304 | 473 | return 0; |
---|
305 | 474 | |
---|
306 | | -legacy_register_fail: |
---|
307 | | - dsa_slave_unregister_notifier(); |
---|
308 | 475 | register_notifier_fail: |
---|
309 | 476 | destroy_workqueue(dsa_owq); |
---|
310 | 477 | |
---|
.. | .. |
---|
314 | 481 | |
---|
315 | 482 | static void __exit dsa_cleanup_module(void) |
---|
316 | 483 | { |
---|
| 484 | + dsa_tag_driver_unregister(&DSA_TAG_DRIVER_NAME(none_ops)); |
---|
| 485 | + |
---|
317 | 486 | dsa_slave_unregister_notifier(); |
---|
318 | 487 | dev_remove_pack(&dsa_pack_type); |
---|
319 | | - dsa_legacy_unregister(); |
---|
320 | 488 | destroy_workqueue(dsa_owq); |
---|
321 | 489 | } |
---|
322 | 490 | module_exit(dsa_cleanup_module); |
---|