Merge branch 'dsa-tag-modules'
Andrew Lunn says: ==================== Make DSA tag drivers kernel modules Historically, DSA tag drivers have been compiled into the kernel as part of the DSA core. With the growing number of tag drivers, it makes sense to allow this driver code to be compiled as a module, and loaded on demand. v2 -- Move name to end of structure, keeping the hot entries at the beginning. More tag protocol to end of structure to keep hot members at the beginning. Fix indent of #endif Rewrite to move list pointer into a new structure void functions, since there cannot be errors Fix fall-through comment Reorder patch for unused symbols to before tag drivers can be modules tab/space cleanup Help text wording NET_DSA_TAG_BRCM_COMMON and NET_DSA_TAG_KZS_COMMON hidden v3 -- boilerplate: Move kdoc next to macro boilerplate: Fix THIS_MODULE indentation Kconfig: More tabification Kconfig: Punctuation v4 -- Cover note {H}istorically Kconfig: trailer ==================== Tested-by: Vivien Didelot <vivien.didelot@gmail.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
Коммит
c1a92c0a6c
|
@ -30,20 +30,32 @@ struct phy_device;
|
|||
struct fixed_phy_status;
|
||||
struct phylink_link_state;
|
||||
|
||||
#define DSA_TAG_PROTO_NONE_VALUE 0
|
||||
#define DSA_TAG_PROTO_BRCM_VALUE 1
|
||||
#define DSA_TAG_PROTO_BRCM_PREPEND_VALUE 2
|
||||
#define DSA_TAG_PROTO_DSA_VALUE 3
|
||||
#define DSA_TAG_PROTO_EDSA_VALUE 4
|
||||
#define DSA_TAG_PROTO_GSWIP_VALUE 5
|
||||
#define DSA_TAG_PROTO_KSZ9477_VALUE 6
|
||||
#define DSA_TAG_PROTO_KSZ9893_VALUE 7
|
||||
#define DSA_TAG_PROTO_LAN9303_VALUE 8
|
||||
#define DSA_TAG_PROTO_MTK_VALUE 9
|
||||
#define DSA_TAG_PROTO_QCA_VALUE 10
|
||||
#define DSA_TAG_PROTO_TRAILER_VALUE 11
|
||||
|
||||
enum dsa_tag_protocol {
|
||||
DSA_TAG_PROTO_NONE = 0,
|
||||
DSA_TAG_PROTO_BRCM,
|
||||
DSA_TAG_PROTO_BRCM_PREPEND,
|
||||
DSA_TAG_PROTO_DSA,
|
||||
DSA_TAG_PROTO_EDSA,
|
||||
DSA_TAG_PROTO_GSWIP,
|
||||
DSA_TAG_PROTO_KSZ9477,
|
||||
DSA_TAG_PROTO_KSZ9893,
|
||||
DSA_TAG_PROTO_LAN9303,
|
||||
DSA_TAG_PROTO_MTK,
|
||||
DSA_TAG_PROTO_QCA,
|
||||
DSA_TAG_PROTO_TRAILER,
|
||||
DSA_TAG_LAST, /* MUST BE LAST */
|
||||
DSA_TAG_PROTO_NONE = DSA_TAG_PROTO_NONE_VALUE,
|
||||
DSA_TAG_PROTO_BRCM = DSA_TAG_PROTO_BRCM_VALUE,
|
||||
DSA_TAG_PROTO_BRCM_PREPEND = DSA_TAG_PROTO_BRCM_PREPEND_VALUE,
|
||||
DSA_TAG_PROTO_DSA = DSA_TAG_PROTO_DSA_VALUE,
|
||||
DSA_TAG_PROTO_EDSA = DSA_TAG_PROTO_EDSA_VALUE,
|
||||
DSA_TAG_PROTO_GSWIP = DSA_TAG_PROTO_GSWIP_VALUE,
|
||||
DSA_TAG_PROTO_KSZ9477 = DSA_TAG_PROTO_KSZ9477_VALUE,
|
||||
DSA_TAG_PROTO_KSZ9893 = DSA_TAG_PROTO_KSZ9893_VALUE,
|
||||
DSA_TAG_PROTO_LAN9303 = DSA_TAG_PROTO_LAN9303_VALUE,
|
||||
DSA_TAG_PROTO_MTK = DSA_TAG_PROTO_MTK_VALUE,
|
||||
DSA_TAG_PROTO_QCA = DSA_TAG_PROTO_QCA_VALUE,
|
||||
DSA_TAG_PROTO_TRAILER = DSA_TAG_PROTO_TRAILER_VALUE,
|
||||
};
|
||||
|
||||
struct packet_type;
|
||||
|
@ -56,8 +68,14 @@ struct dsa_device_ops {
|
|||
int (*flow_dissect)(const struct sk_buff *skb, __be16 *proto,
|
||||
int *offset);
|
||||
unsigned int overhead;
|
||||
const char *name;
|
||||
enum dsa_tag_protocol proto;
|
||||
};
|
||||
|
||||
#define DSA_TAG_DRIVER_ALIAS "dsa_tag-"
|
||||
#define MODULE_ALIAS_DSA_TAG_DRIVER(__proto) \
|
||||
MODULE_ALIAS(DSA_TAG_DRIVER_ALIAS __stringify(__proto##_VALUE))
|
||||
|
||||
struct dsa_switch_tree {
|
||||
struct list_head list;
|
||||
|
||||
|
@ -575,4 +593,70 @@ int dsa_port_get_ethtool_phy_stats(struct dsa_port *dp, uint64_t *data);
|
|||
int dsa_port_get_phy_sset_count(struct dsa_port *dp);
|
||||
void dsa_port_phylink_mac_change(struct dsa_switch *ds, int port, bool up);
|
||||
|
||||
struct dsa_tag_driver {
|
||||
const struct dsa_device_ops *ops;
|
||||
struct list_head list;
|
||||
struct module *owner;
|
||||
};
|
||||
|
||||
void dsa_tag_drivers_register(struct dsa_tag_driver *dsa_tag_driver_array[],
|
||||
unsigned int count,
|
||||
struct module *owner);
|
||||
void dsa_tag_drivers_unregister(struct dsa_tag_driver *dsa_tag_driver_array[],
|
||||
unsigned int count);
|
||||
|
||||
#define dsa_tag_driver_module_drivers(__dsa_tag_drivers_array, __count) \
|
||||
static int __init dsa_tag_driver_module_init(void) \
|
||||
{ \
|
||||
dsa_tag_drivers_register(__dsa_tag_drivers_array, __count, \
|
||||
THIS_MODULE); \
|
||||
return 0; \
|
||||
} \
|
||||
module_init(dsa_tag_driver_module_init); \
|
||||
\
|
||||
static void __exit dsa_tag_driver_module_exit(void) \
|
||||
{ \
|
||||
dsa_tag_drivers_unregister(__dsa_tag_drivers_array, __count); \
|
||||
} \
|
||||
module_exit(dsa_tag_driver_module_exit)
|
||||
|
||||
/**
|
||||
* module_dsa_tag_drivers() - Helper macro for registering DSA tag
|
||||
* drivers
|
||||
* @__ops_array: Array of tag driver strucutres
|
||||
*
|
||||
* Helper macro for DSA tag drivers which do not do anything special
|
||||
* in module init/exit. Each module may only use this macro once, and
|
||||
* calling it replaces module_init() and module_exit().
|
||||
*/
|
||||
#define module_dsa_tag_drivers(__ops_array) \
|
||||
dsa_tag_driver_module_drivers(__ops_array, ARRAY_SIZE(__ops_array))
|
||||
|
||||
#define DSA_TAG_DRIVER_NAME(__ops) dsa_tag_driver ## _ ## __ops
|
||||
|
||||
/* Create a static structure we can build a linked list of dsa_tag
|
||||
* drivers
|
||||
*/
|
||||
#define DSA_TAG_DRIVER(__ops) \
|
||||
static struct dsa_tag_driver DSA_TAG_DRIVER_NAME(__ops) = { \
|
||||
.ops = &__ops, \
|
||||
}
|
||||
|
||||
/**
|
||||
* module_dsa_tag_driver() - Helper macro for registering a single DSA tag
|
||||
* driver
|
||||
* @__ops: Single tag driver structures
|
||||
*
|
||||
* Helper macro for DSA tag drivers which do not do anything special
|
||||
* in module init/exit. Each module may only use this macro once, and
|
||||
* calling it replaces module_init() and module_exit().
|
||||
*/
|
||||
#define module_dsa_tag_driver(__ops) \
|
||||
DSA_TAG_DRIVER(__ops); \
|
||||
\
|
||||
static struct dsa_tag_driver *dsa_tag_driver_array[] = { \
|
||||
&DSA_TAG_DRIVER_NAME(__ops) \
|
||||
}; \
|
||||
module_dsa_tag_drivers(dsa_tag_driver_array)
|
||||
#endif
|
||||
|
||||
|
|
|
@ -4,7 +4,7 @@ config HAVE_NET_DSA
|
|||
|
||||
# Drivers must select NET_DSA and the appropriate tagging format
|
||||
|
||||
config NET_DSA
|
||||
menuconfig NET_DSA
|
||||
tristate "Distributed Switch Architecture"
|
||||
depends on HAVE_NET_DSA
|
||||
depends on BRIDGE || BRIDGE=n
|
||||
|
@ -26,39 +26,84 @@ config NET_DSA_LEGACY
|
|||
|
||||
This feature is scheduled for removal in 4.17.
|
||||
|
||||
# tagging formats
|
||||
config NET_DSA_TAG_BRCM_COMMON
|
||||
tristate
|
||||
default n
|
||||
|
||||
config NET_DSA_TAG_BRCM
|
||||
bool
|
||||
tristate "Tag driver for Broadcom switches using in-frame headers"
|
||||
select NET_DSA_TAG_BRCM_COMMON
|
||||
help
|
||||
Say Y if you want to enable support for tagging frames for the
|
||||
Broadcom switches which place the tag after the MAC source address.
|
||||
|
||||
|
||||
config NET_DSA_TAG_BRCM_PREPEND
|
||||
bool
|
||||
|
||||
config NET_DSA_TAG_DSA
|
||||
bool
|
||||
|
||||
config NET_DSA_TAG_EDSA
|
||||
bool
|
||||
tristate "Tag driver for Broadcom switches using prepended headers"
|
||||
select NET_DSA_TAG_BRCM_COMMON
|
||||
help
|
||||
Say Y if you want to enable support for tagging frames for the
|
||||
Broadcom switches which places the tag before the Ethernet header
|
||||
(prepended).
|
||||
|
||||
config NET_DSA_TAG_GSWIP
|
||||
bool
|
||||
tristate "Tag driver for Lantiq / Intel GSWIP switches"
|
||||
help
|
||||
Say Y or M if you want to enable support for tagging frames for the
|
||||
Lantiq / Intel GSWIP switches.
|
||||
|
||||
config NET_DSA_TAG_KSZ
|
||||
bool
|
||||
config NET_DSA_TAG_DSA
|
||||
tristate "Tag driver for Marvell switches using DSA headers"
|
||||
help
|
||||
Say Y or M if you want to enable support for tagging frames for the
|
||||
Marvell switches which use DSA headers.
|
||||
|
||||
config NET_DSA_TAG_KSZ9477
|
||||
bool
|
||||
select NET_DSA_TAG_KSZ
|
||||
|
||||
config NET_DSA_TAG_LAN9303
|
||||
bool
|
||||
config NET_DSA_TAG_EDSA
|
||||
tristate "Tag driver for Marvell switches using EtherType DSA headers"
|
||||
help
|
||||
Say Y or M if you want to enable support for tagging frames for the
|
||||
Marvell switches which use EtherType DSA headers.
|
||||
|
||||
config NET_DSA_TAG_MTK
|
||||
bool
|
||||
tristate "Tag driver for Mediatek switches"
|
||||
help
|
||||
Say Y or M if you want to enable support for tagging frames for
|
||||
Mediatek switches.
|
||||
|
||||
config NET_DSA_TAG_TRAILER
|
||||
bool
|
||||
config NET_DSA_TAG_KSZ_COMMON
|
||||
tristate
|
||||
default n
|
||||
|
||||
config NET_DSA_TAG_KSZ
|
||||
tristate "Tag driver for Microchip 9893 family of switches"
|
||||
select NET_DSA_TAG_KSZ_COMMON
|
||||
help
|
||||
Say Y if you want to enable support for tagging frames for the
|
||||
Microchip 9893 family of switches.
|
||||
|
||||
config NET_DSA_TAG_KSZ9477
|
||||
tristate "Tag driver for Microchip 9477 family of switches"
|
||||
select NET_DSA_TAG_KSZ_COMMON
|
||||
help
|
||||
Say Y if you want to enable support for tagging frames for the
|
||||
Microchip 9477 family of switches.
|
||||
|
||||
config NET_DSA_TAG_QCA
|
||||
bool
|
||||
tristate "Tag driver for Qualcomm Atheros QCA8K switches"
|
||||
help
|
||||
Say Y or M if you want to enable support for tagging frames for
|
||||
the Qualcomm Atheros QCA8K switches.
|
||||
|
||||
config NET_DSA_TAG_LAN9303
|
||||
tristate "Tag driver for SMSC/Microchip LAN9303 family of switches"
|
||||
help
|
||||
Say Y or M if you want to enable support for tagging frames for the
|
||||
SMSC/Microchip LAN9303 family of switches.
|
||||
|
||||
config NET_DSA_TAG_TRAILER
|
||||
tristate "Tag driver for switches using a trailer tag"
|
||||
help
|
||||
Say Y or M if you want to enable support for tagging frames at
|
||||
with a trailed. e.g. Marvell 88E6060.
|
||||
|
||||
endif
|
||||
|
|
|
@ -5,13 +5,12 @@ dsa_core-y += dsa.o dsa2.o master.o port.o slave.o switch.o
|
|||
dsa_core-$(CONFIG_NET_DSA_LEGACY) += legacy.o
|
||||
|
||||
# tagging formats
|
||||
dsa_core-$(CONFIG_NET_DSA_TAG_BRCM) += tag_brcm.o
|
||||
dsa_core-$(CONFIG_NET_DSA_TAG_BRCM_PREPEND) += tag_brcm.o
|
||||
dsa_core-$(CONFIG_NET_DSA_TAG_DSA) += tag_dsa.o
|
||||
dsa_core-$(CONFIG_NET_DSA_TAG_EDSA) += tag_edsa.o
|
||||
dsa_core-$(CONFIG_NET_DSA_TAG_GSWIP) += tag_gswip.o
|
||||
dsa_core-$(CONFIG_NET_DSA_TAG_KSZ) += tag_ksz.o
|
||||
dsa_core-$(CONFIG_NET_DSA_TAG_LAN9303) += tag_lan9303.o
|
||||
dsa_core-$(CONFIG_NET_DSA_TAG_MTK) += tag_mtk.o
|
||||
dsa_core-$(CONFIG_NET_DSA_TAG_QCA) += tag_qca.o
|
||||
dsa_core-$(CONFIG_NET_DSA_TAG_TRAILER) += tag_trailer.o
|
||||
obj-$(CONFIG_NET_DSA_TAG_BRCM_COMMON) += tag_brcm.o
|
||||
obj-$(CONFIG_NET_DSA_TAG_DSA) += tag_dsa.o
|
||||
obj-$(CONFIG_NET_DSA_TAG_EDSA) += tag_edsa.o
|
||||
obj-$(CONFIG_NET_DSA_TAG_GSWIP) += tag_gswip.o
|
||||
obj-$(CONFIG_NET_DSA_TAG_KSZ_COMMON) += tag_ksz.o
|
||||
obj-$(CONFIG_NET_DSA_TAG_LAN9303) += tag_lan9303.o
|
||||
obj-$(CONFIG_NET_DSA_TAG_MTK) += tag_mtk.o
|
||||
obj-$(CONFIG_NET_DSA_TAG_QCA) += tag_qca.o
|
||||
obj-$(CONFIG_NET_DSA_TAG_TRAILER) += tag_trailer.o
|
||||
|
|
171
net/dsa/dsa.c
171
net/dsa/dsa.c
|
@ -27,6 +27,9 @@
|
|||
|
||||
#include "dsa_priv.h"
|
||||
|
||||
static LIST_HEAD(dsa_tag_drivers_list);
|
||||
static DEFINE_MUTEX(dsa_tag_drivers_lock);
|
||||
|
||||
static struct sk_buff *dsa_slave_notag_xmit(struct sk_buff *skb,
|
||||
struct net_device *dev)
|
||||
{
|
||||
|
@ -35,106 +38,103 @@ static struct sk_buff *dsa_slave_notag_xmit(struct sk_buff *skb,
|
|||
}
|
||||
|
||||
static const struct dsa_device_ops none_ops = {
|
||||
.name = "none",
|
||||
.proto = DSA_TAG_PROTO_NONE,
|
||||
.xmit = dsa_slave_notag_xmit,
|
||||
.rcv = NULL,
|
||||
};
|
||||
|
||||
const struct dsa_device_ops *dsa_device_ops[DSA_TAG_LAST] = {
|
||||
#ifdef CONFIG_NET_DSA_TAG_BRCM
|
||||
[DSA_TAG_PROTO_BRCM] = &brcm_netdev_ops,
|
||||
#endif
|
||||
#ifdef CONFIG_NET_DSA_TAG_BRCM_PREPEND
|
||||
[DSA_TAG_PROTO_BRCM_PREPEND] = &brcm_prepend_netdev_ops,
|
||||
#endif
|
||||
#ifdef CONFIG_NET_DSA_TAG_DSA
|
||||
[DSA_TAG_PROTO_DSA] = &dsa_netdev_ops,
|
||||
#endif
|
||||
#ifdef CONFIG_NET_DSA_TAG_EDSA
|
||||
[DSA_TAG_PROTO_EDSA] = &edsa_netdev_ops,
|
||||
#endif
|
||||
#ifdef CONFIG_NET_DSA_TAG_GSWIP
|
||||
[DSA_TAG_PROTO_GSWIP] = &gswip_netdev_ops,
|
||||
#endif
|
||||
#ifdef CONFIG_NET_DSA_TAG_KSZ9477
|
||||
[DSA_TAG_PROTO_KSZ9477] = &ksz9477_netdev_ops,
|
||||
[DSA_TAG_PROTO_KSZ9893] = &ksz9893_netdev_ops,
|
||||
#endif
|
||||
#ifdef CONFIG_NET_DSA_TAG_LAN9303
|
||||
[DSA_TAG_PROTO_LAN9303] = &lan9303_netdev_ops,
|
||||
#endif
|
||||
#ifdef CONFIG_NET_DSA_TAG_MTK
|
||||
[DSA_TAG_PROTO_MTK] = &mtk_netdev_ops,
|
||||
#endif
|
||||
#ifdef CONFIG_NET_DSA_TAG_QCA
|
||||
[DSA_TAG_PROTO_QCA] = &qca_netdev_ops,
|
||||
#endif
|
||||
#ifdef CONFIG_NET_DSA_TAG_TRAILER
|
||||
[DSA_TAG_PROTO_TRAILER] = &trailer_netdev_ops,
|
||||
#endif
|
||||
[DSA_TAG_PROTO_NONE] = &none_ops,
|
||||
};
|
||||
DSA_TAG_DRIVER(none_ops);
|
||||
|
||||
static void dsa_tag_driver_register(struct dsa_tag_driver *dsa_tag_driver,
|
||||
struct module *owner)
|
||||
{
|
||||
dsa_tag_driver->owner = owner;
|
||||
|
||||
mutex_lock(&dsa_tag_drivers_lock);
|
||||
list_add_tail(&dsa_tag_driver->list, &dsa_tag_drivers_list);
|
||||
mutex_unlock(&dsa_tag_drivers_lock);
|
||||
}
|
||||
|
||||
void dsa_tag_drivers_register(struct dsa_tag_driver *dsa_tag_driver_array[],
|
||||
unsigned int count, struct module *owner)
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
for (i = 0; i < count; i++)
|
||||
dsa_tag_driver_register(dsa_tag_driver_array[i], owner);
|
||||
}
|
||||
|
||||
static void dsa_tag_driver_unregister(struct dsa_tag_driver *dsa_tag_driver)
|
||||
{
|
||||
mutex_lock(&dsa_tag_drivers_lock);
|
||||
list_del(&dsa_tag_driver->list);
|
||||
mutex_unlock(&dsa_tag_drivers_lock);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(dsa_tag_drivers_register);
|
||||
|
||||
void dsa_tag_drivers_unregister(struct dsa_tag_driver *dsa_tag_driver_array[],
|
||||
unsigned int count)
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
for (i = 0; i < count; i++)
|
||||
dsa_tag_driver_unregister(dsa_tag_driver_array[i]);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(dsa_tag_drivers_unregister);
|
||||
|
||||
const char *dsa_tag_protocol_to_str(const struct dsa_device_ops *ops)
|
||||
{
|
||||
const char *protocol_name[DSA_TAG_LAST] = {
|
||||
#ifdef CONFIG_NET_DSA_TAG_BRCM
|
||||
[DSA_TAG_PROTO_BRCM] = "brcm",
|
||||
#endif
|
||||
#ifdef CONFIG_NET_DSA_TAG_BRCM_PREPEND
|
||||
[DSA_TAG_PROTO_BRCM_PREPEND] = "brcm-prepend",
|
||||
#endif
|
||||
#ifdef CONFIG_NET_DSA_TAG_DSA
|
||||
[DSA_TAG_PROTO_DSA] = "dsa",
|
||||
#endif
|
||||
#ifdef CONFIG_NET_DSA_TAG_EDSA
|
||||
[DSA_TAG_PROTO_EDSA] = "edsa",
|
||||
#endif
|
||||
#ifdef CONFIG_NET_DSA_TAG_GSWIP
|
||||
[DSA_TAG_PROTO_GSWIP] = "gswip",
|
||||
#endif
|
||||
#ifdef CONFIG_NET_DSA_TAG_KSZ9477
|
||||
[DSA_TAG_PROTO_KSZ9477] = "ksz9477",
|
||||
[DSA_TAG_PROTO_KSZ9893] = "ksz9893",
|
||||
#endif
|
||||
#ifdef CONFIG_NET_DSA_TAG_LAN9303
|
||||
[DSA_TAG_PROTO_LAN9303] = "lan9303",
|
||||
#endif
|
||||
#ifdef CONFIG_NET_DSA_TAG_MTK
|
||||
[DSA_TAG_PROTO_MTK] = "mtk",
|
||||
#endif
|
||||
#ifdef CONFIG_NET_DSA_TAG_QCA
|
||||
[DSA_TAG_PROTO_QCA] = "qca",
|
||||
#endif
|
||||
#ifdef CONFIG_NET_DSA_TAG_TRAILER
|
||||
[DSA_TAG_PROTO_TRAILER] = "trailer",
|
||||
#endif
|
||||
[DSA_TAG_PROTO_NONE] = "none",
|
||||
};
|
||||
unsigned int i;
|
||||
|
||||
BUILD_BUG_ON(ARRAY_SIZE(protocol_name) != DSA_TAG_LAST);
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(dsa_device_ops); i++)
|
||||
if (ops == dsa_device_ops[i])
|
||||
return protocol_name[i];
|
||||
|
||||
return protocol_name[DSA_TAG_PROTO_NONE];
|
||||
return ops->name;
|
||||
};
|
||||
|
||||
const struct dsa_device_ops *dsa_resolve_tag_protocol(int tag_protocol)
|
||||
const struct dsa_device_ops *dsa_tag_driver_get(int tag_protocol)
|
||||
{
|
||||
struct dsa_tag_driver *dsa_tag_driver;
|
||||
const struct dsa_device_ops *ops;
|
||||
char module_name[128];
|
||||
bool found = false;
|
||||
|
||||
if (tag_protocol >= DSA_TAG_LAST)
|
||||
return ERR_PTR(-EINVAL);
|
||||
ops = dsa_device_ops[tag_protocol];
|
||||
snprintf(module_name, 127, "%s%d", DSA_TAG_DRIVER_ALIAS,
|
||||
tag_protocol);
|
||||
|
||||
if (!ops)
|
||||
return ERR_PTR(-ENOPROTOOPT);
|
||||
request_module(module_name);
|
||||
|
||||
mutex_lock(&dsa_tag_drivers_lock);
|
||||
list_for_each_entry(dsa_tag_driver, &dsa_tag_drivers_list, list) {
|
||||
ops = dsa_tag_driver->ops;
|
||||
if (ops->proto == tag_protocol) {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (found) {
|
||||
if (!try_module_get(dsa_tag_driver->owner))
|
||||
ops = ERR_PTR(-ENOPROTOOPT);
|
||||
} else {
|
||||
ops = ERR_PTR(-ENOPROTOOPT);
|
||||
}
|
||||
|
||||
mutex_unlock(&dsa_tag_drivers_lock);
|
||||
|
||||
return ops;
|
||||
}
|
||||
|
||||
void dsa_tag_driver_put(const struct dsa_device_ops *ops)
|
||||
{
|
||||
struct dsa_tag_driver *dsa_tag_driver;
|
||||
|
||||
mutex_lock(&dsa_tag_drivers_lock);
|
||||
list_for_each_entry(dsa_tag_driver, &dsa_tag_drivers_list, list) {
|
||||
if (dsa_tag_driver->ops == ops) {
|
||||
module_put(dsa_tag_driver->owner);
|
||||
break;
|
||||
}
|
||||
}
|
||||
mutex_unlock(&dsa_tag_drivers_lock);
|
||||
}
|
||||
|
||||
static int dev_is_class(struct device *dev, void *class)
|
||||
{
|
||||
if (dev->class != NULL && !strcmp(dev->class->name, class))
|
||||
|
@ -352,12 +352,17 @@ static int __init dsa_init_module(void)
|
|||
|
||||
dev_add_pack(&dsa_pack_type);
|
||||
|
||||
dsa_tag_driver_register(&DSA_TAG_DRIVER_NAME(none_ops),
|
||||
THIS_MODULE);
|
||||
|
||||
return 0;
|
||||
}
|
||||
module_init(dsa_init_module);
|
||||
|
||||
static void __exit dsa_cleanup_module(void)
|
||||
{
|
||||
dsa_tag_driver_unregister(&DSA_TAG_DRIVER_NAME(none_ops));
|
||||
|
||||
dsa_slave_unregister_notifier();
|
||||
dev_remove_pack(&dsa_pack_type);
|
||||
dsa_legacy_unregister();
|
||||
|
|
|
@ -335,6 +335,8 @@ static void dsa_port_teardown(struct dsa_port *dp)
|
|||
case DSA_PORT_TYPE_UNUSED:
|
||||
break;
|
||||
case DSA_PORT_TYPE_CPU:
|
||||
dsa_tag_driver_put(dp->tag_ops);
|
||||
/* fall-through */
|
||||
case DSA_PORT_TYPE_DSA:
|
||||
dsa_port_link_unregister_of(dp);
|
||||
break;
|
||||
|
@ -577,7 +579,7 @@ static int dsa_port_parse_cpu(struct dsa_port *dp, struct net_device *master)
|
|||
enum dsa_tag_protocol tag_protocol;
|
||||
|
||||
tag_protocol = ds->ops->get_tag_protocol(ds, dp->index);
|
||||
tag_ops = dsa_resolve_tag_protocol(tag_protocol);
|
||||
tag_ops = dsa_tag_driver_get(tag_protocol);
|
||||
if (IS_ERR(tag_ops)) {
|
||||
dev_warn(ds->dev, "No tagger for this switch\n");
|
||||
return PTR_ERR(tag_ops);
|
||||
|
|
|
@ -84,7 +84,9 @@ struct dsa_slave_priv {
|
|||
};
|
||||
|
||||
/* dsa.c */
|
||||
const struct dsa_device_ops *dsa_resolve_tag_protocol(int tag_protocol);
|
||||
const struct dsa_device_ops *dsa_tag_driver_get(int tag_protocol);
|
||||
void dsa_tag_driver_put(const struct dsa_device_ops *ops);
|
||||
|
||||
bool dsa_schedule_work(struct work_struct *work);
|
||||
const char *dsa_tag_protocol_to_str(const struct dsa_device_ops *ops);
|
||||
|
||||
|
@ -200,34 +202,4 @@ dsa_slave_to_master(const struct net_device *dev)
|
|||
/* switch.c */
|
||||
int dsa_switch_register_notifier(struct dsa_switch *ds);
|
||||
void dsa_switch_unregister_notifier(struct dsa_switch *ds);
|
||||
|
||||
/* tag_brcm.c */
|
||||
extern const struct dsa_device_ops brcm_netdev_ops;
|
||||
extern const struct dsa_device_ops brcm_prepend_netdev_ops;
|
||||
|
||||
/* tag_dsa.c */
|
||||
extern const struct dsa_device_ops dsa_netdev_ops;
|
||||
|
||||
/* tag_edsa.c */
|
||||
extern const struct dsa_device_ops edsa_netdev_ops;
|
||||
|
||||
/* tag_gswip.c */
|
||||
extern const struct dsa_device_ops gswip_netdev_ops;
|
||||
|
||||
/* tag_ksz.c */
|
||||
extern const struct dsa_device_ops ksz9477_netdev_ops;
|
||||
extern const struct dsa_device_ops ksz9893_netdev_ops;
|
||||
|
||||
/* tag_lan9303.c */
|
||||
extern const struct dsa_device_ops lan9303_netdev_ops;
|
||||
|
||||
/* tag_mtk.c */
|
||||
extern const struct dsa_device_ops mtk_netdev_ops;
|
||||
|
||||
/* tag_qca.c */
|
||||
extern const struct dsa_device_ops qca_netdev_ops;
|
||||
|
||||
/* tag_trailer.c */
|
||||
extern const struct dsa_device_ops trailer_netdev_ops;
|
||||
|
||||
#endif
|
||||
|
|
|
@ -152,7 +152,7 @@ static int dsa_switch_setup_one(struct dsa_switch *ds,
|
|||
enum dsa_tag_protocol tag_protocol;
|
||||
|
||||
tag_protocol = ops->get_tag_protocol(ds, dst->cpu_dp->index);
|
||||
tag_ops = dsa_resolve_tag_protocol(tag_protocol);
|
||||
tag_ops = dsa_tag_driver_get(tag_protocol);
|
||||
if (IS_ERR(tag_ops))
|
||||
return PTR_ERR(tag_ops);
|
||||
|
||||
|
@ -163,6 +163,8 @@ static int dsa_switch_setup_one(struct dsa_switch *ds,
|
|||
dst->cpu_dp->dst = dst;
|
||||
}
|
||||
|
||||
dsa_tag_driver_put(dst->cpu_dp->tag_ops);
|
||||
|
||||
memcpy(ds->rtable, cd->rtable, sizeof(ds->rtable));
|
||||
|
||||
/*
|
||||
|
|
|
@ -1,12 +1,8 @@
|
|||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* Broadcom tag support
|
||||
*
|
||||
* Copyright (C) 2014 Broadcom Corporation
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*/
|
||||
|
||||
#include <linux/etherdevice.h>
|
||||
|
@ -59,6 +55,9 @@
|
|||
#define BRCM_EG_TC_MASK 0x7
|
||||
#define BRCM_EG_PID_MASK 0x1f
|
||||
|
||||
#if IS_ENABLED(CONFIG_NET_DSA_TAG_BRCM) || \
|
||||
IS_ENABLED(CONFIG_NET_DSA_TAG_BRCM_PREPEND)
|
||||
|
||||
static struct sk_buff *brcm_tag_xmit_ll(struct sk_buff *skb,
|
||||
struct net_device *dev,
|
||||
unsigned int offset)
|
||||
|
@ -143,8 +142,9 @@ static struct sk_buff *brcm_tag_rcv_ll(struct sk_buff *skb,
|
|||
|
||||
return skb;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_NET_DSA_TAG_BRCM
|
||||
#if IS_ENABLED(CONFIG_NET_DSA_TAG_BRCM)
|
||||
static struct sk_buff *brcm_tag_xmit(struct sk_buff *skb,
|
||||
struct net_device *dev)
|
||||
{
|
||||
|
@ -171,14 +171,19 @@ static struct sk_buff *brcm_tag_rcv(struct sk_buff *skb, struct net_device *dev,
|
|||
return nskb;
|
||||
}
|
||||
|
||||
const struct dsa_device_ops brcm_netdev_ops = {
|
||||
static const struct dsa_device_ops brcm_netdev_ops = {
|
||||
.name = "brcm",
|
||||
.proto = DSA_TAG_PROTO_BRCM,
|
||||
.xmit = brcm_tag_xmit,
|
||||
.rcv = brcm_tag_rcv,
|
||||
.overhead = BRCM_TAG_LEN,
|
||||
};
|
||||
|
||||
DSA_TAG_DRIVER(brcm_netdev_ops);
|
||||
MODULE_ALIAS_DSA_TAG_DRIVER(DSA_TAG_PROTO_BRCM);
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_NET_DSA_TAG_BRCM_PREPEND
|
||||
#if IS_ENABLED(CONFIG_NET_DSA_TAG_BRCM_PREPEND)
|
||||
static struct sk_buff *brcm_tag_xmit_prepend(struct sk_buff *skb,
|
||||
struct net_device *dev)
|
||||
{
|
||||
|
@ -194,9 +199,27 @@ static struct sk_buff *brcm_tag_rcv_prepend(struct sk_buff *skb,
|
|||
return brcm_tag_rcv_ll(skb, dev, pt, ETH_HLEN);
|
||||
}
|
||||
|
||||
const struct dsa_device_ops brcm_prepend_netdev_ops = {
|
||||
static const struct dsa_device_ops brcm_prepend_netdev_ops = {
|
||||
.name = "brcm-prepend",
|
||||
.proto = DSA_TAG_PROTO_BRCM_PREPEND,
|
||||
.xmit = brcm_tag_xmit_prepend,
|
||||
.rcv = brcm_tag_rcv_prepend,
|
||||
.overhead = BRCM_TAG_LEN,
|
||||
};
|
||||
#endif
|
||||
|
||||
DSA_TAG_DRIVER(brcm_prepend_netdev_ops);
|
||||
MODULE_ALIAS_DSA_TAG_DRIVER(DSA_TAG_PROTO_BRCM_PREPEND);
|
||||
|
||||
static struct dsa_tag_driver *dsa_tag_driver_array[] = {
|
||||
#if IS_ENABLED(CONFIG_NET_DSA_TAG_BRCM)
|
||||
&DSA_TAG_DRIVER_NAME(brcm_netdev_ops),
|
||||
#endif
|
||||
#if IS_ENABLED(CONFIG_NET_DSA_TAG_BRCM_PREPEND)
|
||||
&DSA_TAG_DRIVER_NAME(brcm_prepend_netdev_ops),
|
||||
#endif
|
||||
};
|
||||
|
||||
module_dsa_tag_drivers(dsa_tag_driver_array);
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
|
|
|
@ -1,11 +1,7 @@
|
|||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* net/dsa/tag_dsa.c - (Non-ethertype) DSA tagging
|
||||
* Copyright (c) 2008-2009 Marvell Semiconductor
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*/
|
||||
|
||||
#include <linux/etherdevice.h>
|
||||
|
@ -154,9 +150,16 @@ static int dsa_tag_flow_dissect(const struct sk_buff *skb, __be16 *proto,
|
|||
return 0;
|
||||
}
|
||||
|
||||
const struct dsa_device_ops dsa_netdev_ops = {
|
||||
static const struct dsa_device_ops dsa_netdev_ops = {
|
||||
.name = "dsa",
|
||||
.proto = DSA_TAG_PROTO_DSA,
|
||||
.xmit = dsa_xmit,
|
||||
.rcv = dsa_rcv,
|
||||
.flow_dissect = dsa_tag_flow_dissect,
|
||||
.overhead = DSA_HLEN,
|
||||
};
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_ALIAS_DSA_TAG_DRIVER(DSA_TAG_PROTO_DSA);
|
||||
|
||||
module_dsa_tag_driver(dsa_netdev_ops);
|
||||
|
|
|
@ -1,11 +1,7 @@
|
|||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* net/dsa/tag_edsa.c - Ethertype DSA tagging
|
||||
* Copyright (c) 2008-2009 Marvell Semiconductor
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*/
|
||||
|
||||
#include <linux/etherdevice.h>
|
||||
|
@ -173,9 +169,16 @@ static int edsa_tag_flow_dissect(const struct sk_buff *skb, __be16 *proto,
|
|||
return 0;
|
||||
}
|
||||
|
||||
const struct dsa_device_ops edsa_netdev_ops = {
|
||||
static const struct dsa_device_ops edsa_netdev_ops = {
|
||||
.name = "edsa",
|
||||
.proto = DSA_TAG_PROTO_EDSA,
|
||||
.xmit = edsa_xmit,
|
||||
.rcv = edsa_rcv,
|
||||
.flow_dissect = edsa_tag_flow_dissect,
|
||||
.overhead = EDSA_HLEN,
|
||||
};
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_ALIAS_DSA_TAG_DRIVER(DSA_TAG_PROTO_EDSA);
|
||||
|
||||
module_dsa_tag_driver(edsa_netdev_ops);
|
||||
|
|
|
@ -103,8 +103,15 @@ static struct sk_buff *gswip_tag_rcv(struct sk_buff *skb,
|
|||
return skb;
|
||||
}
|
||||
|
||||
const struct dsa_device_ops gswip_netdev_ops = {
|
||||
static const struct dsa_device_ops gswip_netdev_ops = {
|
||||
.name = "gwsip",
|
||||
.proto = DSA_TAG_PROTO_GSWIP,
|
||||
.xmit = gswip_tag_xmit,
|
||||
.rcv = gswip_tag_rcv,
|
||||
.overhead = GSWIP_RX_HEADER_LEN,
|
||||
};
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_ALIAS_DSA_TAG_DRIVER(DSA_TAG_PROTO_GSWIP);
|
||||
|
||||
module_dsa_tag_driver(gswip_netdev_ops);
|
||||
|
|
|
@ -1,11 +1,7 @@
|
|||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* net/dsa/tag_ksz.c - Microchip KSZ Switch tag format handling
|
||||
* Copyright (c) 2017 Microchip Technology
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*/
|
||||
|
||||
#include <linux/etherdevice.h>
|
||||
|
@ -137,12 +133,17 @@ static struct sk_buff *ksz9477_rcv(struct sk_buff *skb, struct net_device *dev,
|
|||
return ksz_common_rcv(skb, dev, port, len);
|
||||
}
|
||||
|
||||
const struct dsa_device_ops ksz9477_netdev_ops = {
|
||||
static const struct dsa_device_ops ksz9477_netdev_ops = {
|
||||
.name = "ksz9477",
|
||||
.proto = DSA_TAG_PROTO_KSZ9477,
|
||||
.xmit = ksz9477_xmit,
|
||||
.rcv = ksz9477_rcv,
|
||||
.overhead = KSZ9477_INGRESS_TAG_LEN,
|
||||
};
|
||||
|
||||
DSA_TAG_DRIVER(ksz9477_netdev_ops);
|
||||
MODULE_ALIAS_DSA_TAG_DRIVER(DSA_TAG_PROTO_KSZ9477);
|
||||
|
||||
#define KSZ9893_TAIL_TAG_OVERRIDE BIT(5)
|
||||
#define KSZ9893_TAIL_TAG_LOOKUP BIT(6)
|
||||
|
||||
|
@ -170,8 +171,22 @@ static struct sk_buff *ksz9893_xmit(struct sk_buff *skb,
|
|||
return nskb;
|
||||
}
|
||||
|
||||
const struct dsa_device_ops ksz9893_netdev_ops = {
|
||||
static const struct dsa_device_ops ksz9893_netdev_ops = {
|
||||
.name = "ksz9893",
|
||||
.proto = DSA_TAG_PROTO_KSZ9893,
|
||||
.xmit = ksz9893_xmit,
|
||||
.rcv = ksz9477_rcv,
|
||||
.overhead = KSZ_INGRESS_TAG_LEN,
|
||||
};
|
||||
|
||||
DSA_TAG_DRIVER(ksz9893_netdev_ops);
|
||||
MODULE_ALIAS_DSA_TAG_DRIVER(DSA_TAG_PROTO_KSZ9893);
|
||||
|
||||
static struct dsa_tag_driver *dsa_tag_driver_array[] = {
|
||||
&DSA_TAG_DRIVER_NAME(ksz9477_netdev_ops),
|
||||
&DSA_TAG_DRIVER_NAME(ksz9893_netdev_ops),
|
||||
};
|
||||
|
||||
module_dsa_tag_drivers(dsa_tag_driver_array);
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
|
|
|
@ -1,15 +1,6 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* Copyright (C) 2017 Pengutronix, Juergen Borleis <jbe@pengutronix.de>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
*/
|
||||
#include <linux/dsa/lan9303.h>
|
||||
#include <linux/etherdevice.h>
|
||||
|
@ -137,8 +128,15 @@ static struct sk_buff *lan9303_rcv(struct sk_buff *skb, struct net_device *dev,
|
|||
return skb;
|
||||
}
|
||||
|
||||
const struct dsa_device_ops lan9303_netdev_ops = {
|
||||
static const struct dsa_device_ops lan9303_netdev_ops = {
|
||||
.name = "lan9303",
|
||||
.proto = DSA_TAG_PROTO_LAN9303,
|
||||
.xmit = lan9303_xmit,
|
||||
.rcv = lan9303_rcv,
|
||||
.overhead = LAN9303_TAG_LEN,
|
||||
};
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_ALIAS_DSA_TAG_DRIVER(DSA_TAG_PROTO_LAN9303);
|
||||
|
||||
module_dsa_tag_driver(lan9303_netdev_ops);
|
||||
|
|
|
@ -1,15 +1,8 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* Mediatek DSA Tag support
|
||||
* Copyright (C) 2017 Landen Chao <landen.chao@mediatek.com>
|
||||
* Sean Wang <sean.wang@mediatek.com>
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 and
|
||||
* only version 2 as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#include <linux/etherdevice.h>
|
||||
|
@ -105,9 +98,16 @@ static int mtk_tag_flow_dissect(const struct sk_buff *skb, __be16 *proto,
|
|||
return 0;
|
||||
}
|
||||
|
||||
const struct dsa_device_ops mtk_netdev_ops = {
|
||||
static const struct dsa_device_ops mtk_netdev_ops = {
|
||||
.name = "mtk",
|
||||
.proto = DSA_TAG_PROTO_MTK,
|
||||
.xmit = mtk_tag_xmit,
|
||||
.rcv = mtk_tag_rcv,
|
||||
.flow_dissect = mtk_tag_flow_dissect,
|
||||
.overhead = MTK_HDR_LEN,
|
||||
};
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_ALIAS_DSA_TAG_DRIVER(DSA_TAG_PROTO_MTK);
|
||||
|
||||
module_dsa_tag_driver(mtk_netdev_ops);
|
||||
|
|
|
@ -1,14 +1,6 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* Copyright (c) 2015, The Linux Foundation. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 and
|
||||
* only version 2 as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#include <linux/etherdevice.h>
|
||||
|
@ -107,9 +99,16 @@ static int qca_tag_flow_dissect(const struct sk_buff *skb, __be16 *proto,
|
|||
return 0;
|
||||
}
|
||||
|
||||
const struct dsa_device_ops qca_netdev_ops = {
|
||||
static const struct dsa_device_ops qca_netdev_ops = {
|
||||
.name = "qca",
|
||||
.proto = DSA_TAG_PROTO_QCA,
|
||||
.xmit = qca_tag_xmit,
|
||||
.rcv = qca_tag_rcv,
|
||||
.flow_dissect = qca_tag_flow_dissect,
|
||||
.overhead = QCA_HDR_LEN,
|
||||
};
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_ALIAS_DSA_TAG_DRIVER(DSA_TAG_PROTO_QCA);
|
||||
|
||||
module_dsa_tag_driver(qca_netdev_ops);
|
||||
|
|
|
@ -1,11 +1,7 @@
|
|||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* net/dsa/tag_trailer.c - Trailer tag format handling
|
||||
* Copyright (c) 2008-2009 Marvell Semiconductor
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*/
|
||||
|
||||
#include <linux/etherdevice.h>
|
||||
|
@ -81,8 +77,15 @@ static struct sk_buff *trailer_rcv(struct sk_buff *skb, struct net_device *dev,
|
|||
return skb;
|
||||
}
|
||||
|
||||
const struct dsa_device_ops trailer_netdev_ops = {
|
||||
static const struct dsa_device_ops trailer_netdev_ops = {
|
||||
.name = "trailer",
|
||||
.proto = DSA_TAG_PROTO_TRAILER,
|
||||
.xmit = trailer_xmit,
|
||||
.rcv = trailer_rcv,
|
||||
.overhead = 4,
|
||||
};
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_ALIAS_DSA_TAG_DRIVER(DSA_TAG_PROTO_TRAILER);
|
||||
|
||||
module_dsa_tag_driver(trailer_netdev_ops);
|
||||
|
|
Загрузка…
Ссылка в новой задаче