2019-05-27 06:55:01 +00:00
|
|
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
net: Distributed Switch Architecture protocol support
Distributed Switch Architecture is a protocol for managing hardware
switch chips. It consists of a set of MII management registers and
commands to configure the switch, and an ethernet header format to
signal which of the ports of the switch a packet was received from
or is intended to be sent to.
The switches that this driver supports are typically embedded in
access points and routers, and a typical setup with a DSA switch
looks something like this:
+-----------+ +-----------+
| | RGMII | |
| +-------+ +------ 1000baseT MDI ("WAN")
| | | 6-port +------ 1000baseT MDI ("LAN1")
| CPU | | ethernet +------ 1000baseT MDI ("LAN2")
| |MIImgmt| switch +------ 1000baseT MDI ("LAN3")
| +-------+ w/5 PHYs +------ 1000baseT MDI ("LAN4")
| | | |
+-----------+ +-----------+
The switch driver presents each port on the switch as a separate
network interface to Linux, polls the switch to maintain software
link state of those ports, forwards MII management interface
accesses to those network interfaces (e.g. as done by ethtool) to
the switch, and exposes the switch's hardware statistics counters
via the appropriate Linux kernel interfaces.
This initial patch supports the MII management interface register
layout of the Marvell 88E6123, 88E6161 and 88E6165 switch chips, and
supports the "Ethertype DSA" packet tagging format.
(There is no officially registered ethertype for the Ethertype DSA
packet format, so we just grab a random one. The ethertype to use
is programmed into the switch, and the switch driver uses the value
of ETH_P_EDSA for this, so this define can be changed at any time in
the future if the one we chose is allocated to another protocol or
if Ethertype DSA gets its own officially registered ethertype, and
everything will continue to work.)
Signed-off-by: Lennert Buytenhek <buytenh@marvell.com>
Tested-by: Nicolas Pitre <nico@marvell.com>
Tested-by: Byron Bradley <byron.bbradley@gmail.com>
Tested-by: Tim Ellis <tim.ellis@mac.com>
Tested-by: Peter van Valderen <linux@ddcrew.com>
Tested-by: Dirk Teurlings <dirk@upexia.nl>
Signed-off-by: David S. Miller <davem@davemloft.net>
2008-10-07 13:44:02 +00:00
|
|
|
/*
|
|
|
|
* net/dsa/dsa.c - Hardware switch handling
|
dsa: add switch chip cascading support
The initial version of the DSA driver only supported a single switch
chip per network interface, while DSA-capable switch chips can be
interconnected to form a tree of switch chips. This patch adds support
for multiple switch chips on a network interface.
An example topology for a 16-port device with an embedded CPU is as
follows:
+-----+ +--------+ +--------+
| |eth0 10| switch |9 10| switch |
| CPU +----------+ +-------+ |
| | | chip 0 | | chip 1 |
+-----+ +---++---+ +---++---+
|| ||
|| ||
||1000baseT ||1000baseT
||ports 1-8 ||ports 9-16
This requires a couple of interdependent changes in the DSA layer:
- The dsa platform driver data needs to be extended: there is still
only one netdevice per DSA driver instance (eth0 in the example
above), but each of the switch chips in the tree needs its own
mii_bus device pointer, MII management bus address, and port name
array. (include/net/dsa.h) The existing in-tree dsa users need
some small changes to deal with this. (arch/arm)
- The DSA and Ethertype DSA tagging modules need to be extended to
use the DSA device ID field on receive and demultiplex the packet
accordingly, and fill in the DSA device ID field on transmit
according to which switch chip the packet is heading to.
(net/dsa/tag_{dsa,edsa}.c)
- The concept of "CPU port", which is the switch chip port that the
CPU is connected to (port 10 on switch chip 0 in the example), needs
to be extended with the concept of "upstream port", which is the
port on the switch chip that will bring us one hop closer to the CPU
(port 10 for both switch chips in the example above).
- The dsa platform data needs to specify which ports on which switch
chips are links to other switch chips, so that we can enable DSA
tagging mode on them. (For inter-switch links, we always use
non-EtherType DSA tagging, since it has lower overhead. The CPU
link uses dsa or edsa tagging depending on what the 'root' switch
chip supports.) This is done by specifying "dsa" for the given
port in the port array.
- The dsa platform data needs to be extended with information on via
which port to reach any given switch chip from any given switch chip.
This info is specified via the per-switch chip data struct ->rtable[]
array, which gives the nexthop ports for each of the other switches
in the tree.
For the example topology above, the dsa platform data would look
something like this:
static struct dsa_chip_data sw[2] = {
{
.mii_bus = &foo,
.sw_addr = 1,
.port_names[0] = "p1",
.port_names[1] = "p2",
.port_names[2] = "p3",
.port_names[3] = "p4",
.port_names[4] = "p5",
.port_names[5] = "p6",
.port_names[6] = "p7",
.port_names[7] = "p8",
.port_names[9] = "dsa",
.port_names[10] = "cpu",
.rtable = (s8 []){ -1, 9, },
}, {
.mii_bus = &foo,
.sw_addr = 2,
.port_names[0] = "p9",
.port_names[1] = "p10",
.port_names[2] = "p11",
.port_names[3] = "p12",
.port_names[4] = "p13",
.port_names[5] = "p14",
.port_names[6] = "p15",
.port_names[7] = "p16",
.port_names[10] = "dsa",
.rtable = (s8 []){ 10, -1, },
},
},
static struct dsa_platform_data pd = {
.netdev = &foo,
.nr_switches = 2,
.sw = sw,
};
Signed-off-by: Lennert Buytenhek <buytenh@marvell.com>
Tested-by: Gary Thomas <gary@mlbassoc.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
2009-03-20 09:52:09 +00:00
|
|
|
* Copyright (c) 2008-2009 Marvell Semiconductor
|
2013-03-22 10:50:50 +00:00
|
|
|
* Copyright (c) 2013 Florian Fainelli <florian@openwrt.org>
|
net: Distributed Switch Architecture protocol support
Distributed Switch Architecture is a protocol for managing hardware
switch chips. It consists of a set of MII management registers and
commands to configure the switch, and an ethernet header format to
signal which of the ports of the switch a packet was received from
or is intended to be sent to.
The switches that this driver supports are typically embedded in
access points and routers, and a typical setup with a DSA switch
looks something like this:
+-----------+ +-----------+
| | RGMII | |
| +-------+ +------ 1000baseT MDI ("WAN")
| | | 6-port +------ 1000baseT MDI ("LAN1")
| CPU | | ethernet +------ 1000baseT MDI ("LAN2")
| |MIImgmt| switch +------ 1000baseT MDI ("LAN3")
| +-------+ w/5 PHYs +------ 1000baseT MDI ("LAN4")
| | | |
+-----------+ +-----------+
The switch driver presents each port on the switch as a separate
network interface to Linux, polls the switch to maintain software
link state of those ports, forwards MII management interface
accesses to those network interfaces (e.g. as done by ethtool) to
the switch, and exposes the switch's hardware statistics counters
via the appropriate Linux kernel interfaces.
This initial patch supports the MII management interface register
layout of the Marvell 88E6123, 88E6161 and 88E6165 switch chips, and
supports the "Ethertype DSA" packet tagging format.
(There is no officially registered ethertype for the Ethertype DSA
packet format, so we just grab a random one. The ethertype to use
is programmed into the switch, and the switch driver uses the value
of ETH_P_EDSA for this, so this define can be changed at any time in
the future if the one we chose is allocated to another protocol or
if Ethertype DSA gets its own officially registered ethertype, and
everything will continue to work.)
Signed-off-by: Lennert Buytenhek <buytenh@marvell.com>
Tested-by: Nicolas Pitre <nico@marvell.com>
Tested-by: Byron Bradley <byron.bbradley@gmail.com>
Tested-by: Tim Ellis <tim.ellis@mac.com>
Tested-by: Peter van Valderen <linux@ddcrew.com>
Tested-by: Dirk Teurlings <dirk@upexia.nl>
Signed-off-by: David S. Miller <davem@davemloft.net>
2008-10-07 13:44:02 +00:00
|
|
|
*/
|
|
|
|
|
2014-10-29 17:44:58 +00:00
|
|
|
#include <linux/device.h>
|
net: Distributed Switch Architecture protocol support
Distributed Switch Architecture is a protocol for managing hardware
switch chips. It consists of a set of MII management registers and
commands to configure the switch, and an ethernet header format to
signal which of the ports of the switch a packet was received from
or is intended to be sent to.
The switches that this driver supports are typically embedded in
access points and routers, and a typical setup with a DSA switch
looks something like this:
+-----------+ +-----------+
| | RGMII | |
| +-------+ +------ 1000baseT MDI ("WAN")
| | | 6-port +------ 1000baseT MDI ("LAN1")
| CPU | | ethernet +------ 1000baseT MDI ("LAN2")
| |MIImgmt| switch +------ 1000baseT MDI ("LAN3")
| +-------+ w/5 PHYs +------ 1000baseT MDI ("LAN4")
| | | |
+-----------+ +-----------+
The switch driver presents each port on the switch as a separate
network interface to Linux, polls the switch to maintain software
link state of those ports, forwards MII management interface
accesses to those network interfaces (e.g. as done by ethtool) to
the switch, and exposes the switch's hardware statistics counters
via the appropriate Linux kernel interfaces.
This initial patch supports the MII management interface register
layout of the Marvell 88E6123, 88E6161 and 88E6165 switch chips, and
supports the "Ethertype DSA" packet tagging format.
(There is no officially registered ethertype for the Ethertype DSA
packet format, so we just grab a random one. The ethertype to use
is programmed into the switch, and the switch driver uses the value
of ETH_P_EDSA for this, so this define can be changed at any time in
the future if the one we chose is allocated to another protocol or
if Ethertype DSA gets its own officially registered ethertype, and
everything will continue to work.)
Signed-off-by: Lennert Buytenhek <buytenh@marvell.com>
Tested-by: Nicolas Pitre <nico@marvell.com>
Tested-by: Byron Bradley <byron.bbradley@gmail.com>
Tested-by: Tim Ellis <tim.ellis@mac.com>
Tested-by: Peter van Valderen <linux@ddcrew.com>
Tested-by: Dirk Teurlings <dirk@upexia.nl>
Signed-off-by: David S. Miller <davem@davemloft.net>
2008-10-07 13:44:02 +00:00
|
|
|
#include <linux/list.h>
|
|
|
|
#include <linux/platform_device.h>
|
include cleanup: Update gfp.h and slab.h includes to prepare for breaking implicit slab.h inclusion from percpu.h
percpu.h is included by sched.h and module.h and thus ends up being
included when building most .c files. percpu.h includes slab.h which
in turn includes gfp.h making everything defined by the two files
universally available and complicating inclusion dependencies.
percpu.h -> slab.h dependency is about to be removed. Prepare for
this change by updating users of gfp and slab facilities include those
headers directly instead of assuming availability. As this conversion
needs to touch large number of source files, the following script is
used as the basis of conversion.
http://userweb.kernel.org/~tj/misc/slabh-sweep.py
The script does the followings.
* Scan files for gfp and slab usages and update includes such that
only the necessary includes are there. ie. if only gfp is used,
gfp.h, if slab is used, slab.h.
* When the script inserts a new include, it looks at the include
blocks and try to put the new include such that its order conforms
to its surrounding. It's put in the include block which contains
core kernel includes, in the same order that the rest are ordered -
alphabetical, Christmas tree, rev-Xmas-tree or at the end if there
doesn't seem to be any matching order.
* If the script can't find a place to put a new include (mostly
because the file doesn't have fitting include block), it prints out
an error message indicating which .h file needs to be added to the
file.
The conversion was done in the following steps.
1. The initial automatic conversion of all .c files updated slightly
over 4000 files, deleting around 700 includes and adding ~480 gfp.h
and ~3000 slab.h inclusions. The script emitted errors for ~400
files.
2. Each error was manually checked. Some didn't need the inclusion,
some needed manual addition while adding it to implementation .h or
embedding .c file was more appropriate for others. This step added
inclusions to around 150 files.
3. The script was run again and the output was compared to the edits
from #2 to make sure no file was left behind.
4. Several build tests were done and a couple of problems were fixed.
e.g. lib/decompress_*.c used malloc/free() wrappers around slab
APIs requiring slab.h to be added manually.
5. The script was run on all .h files but without automatically
editing them as sprinkling gfp.h and slab.h inclusions around .h
files could easily lead to inclusion dependency hell. Most gfp.h
inclusion directives were ignored as stuff from gfp.h was usually
wildly available and often used in preprocessor macros. Each
slab.h inclusion directive was examined and added manually as
necessary.
6. percpu.h was updated not to include slab.h.
7. Build test were done on the following configurations and failures
were fixed. CONFIG_GCOV_KERNEL was turned off for all tests (as my
distributed build env didn't work with gcov compiles) and a few
more options had to be turned off depending on archs to make things
build (like ipr on powerpc/64 which failed due to missing writeq).
* x86 and x86_64 UP and SMP allmodconfig and a custom test config.
* powerpc and powerpc64 SMP allmodconfig
* sparc and sparc64 SMP allmodconfig
* ia64 SMP allmodconfig
* s390 SMP allmodconfig
* alpha SMP allmodconfig
* um on x86_64 SMP allmodconfig
8. percpu.h modifications were reverted so that it could be applied as
a separate patch and serve as bisection point.
Given the fact that I had only a couple of failures from tests on step
6, I'm fairly confident about the coverage of this conversion patch.
If there is a breakage, it's likely to be something in one of the arch
headers which should be easily discoverable easily on most builds of
the specific arch.
Signed-off-by: Tejun Heo <tj@kernel.org>
Guess-its-ok-by: Christoph Lameter <cl@linux-foundation.org>
Cc: Ingo Molnar <mingo@redhat.com>
Cc: Lee Schermerhorn <Lee.Schermerhorn@hp.com>
2010-03-24 08:04:11 +00:00
|
|
|
#include <linux/slab.h>
|
2011-05-27 13:12:25 +00:00
|
|
|
#include <linux/module.h>
|
2017-10-11 17:57:48 +00:00
|
|
|
#include <linux/notifier.h>
|
2013-03-22 10:50:50 +00:00
|
|
|
#include <linux/of.h>
|
|
|
|
#include <linux/of_mdio.h>
|
|
|
|
#include <linux/of_platform.h>
|
2015-03-09 21:31:21 +00:00
|
|
|
#include <linux/of_net.h>
|
2017-03-28 21:45:06 +00:00
|
|
|
#include <linux/netdevice.h>
|
2014-10-29 17:44:58 +00:00
|
|
|
#include <linux/sysfs.h>
|
2015-10-06 14:40:32 +00:00
|
|
|
#include <linux/phy_fixed.h>
|
2018-02-14 00:07:49 +00:00
|
|
|
#include <linux/ptp_classify.h>
|
2017-04-08 15:55:23 +00:00
|
|
|
#include <linux/etherdevice.h>
|
2017-05-17 19:46:03 +00:00
|
|
|
|
net: Distributed Switch Architecture protocol support
Distributed Switch Architecture is a protocol for managing hardware
switch chips. It consists of a set of MII management registers and
commands to configure the switch, and an ethernet header format to
signal which of the ports of the switch a packet was received from
or is intended to be sent to.
The switches that this driver supports are typically embedded in
access points and routers, and a typical setup with a DSA switch
looks something like this:
+-----------+ +-----------+
| | RGMII | |
| +-------+ +------ 1000baseT MDI ("WAN")
| | | 6-port +------ 1000baseT MDI ("LAN1")
| CPU | | ethernet +------ 1000baseT MDI ("LAN2")
| |MIImgmt| switch +------ 1000baseT MDI ("LAN3")
| +-------+ w/5 PHYs +------ 1000baseT MDI ("LAN4")
| | | |
+-----------+ +-----------+
The switch driver presents each port on the switch as a separate
network interface to Linux, polls the switch to maintain software
link state of those ports, forwards MII management interface
accesses to those network interfaces (e.g. as done by ethtool) to
the switch, and exposes the switch's hardware statistics counters
via the appropriate Linux kernel interfaces.
This initial patch supports the MII management interface register
layout of the Marvell 88E6123, 88E6161 and 88E6165 switch chips, and
supports the "Ethertype DSA" packet tagging format.
(There is no officially registered ethertype for the Ethertype DSA
packet format, so we just grab a random one. The ethertype to use
is programmed into the switch, and the switch driver uses the value
of ETH_P_EDSA for this, so this define can be changed at any time in
the future if the one we chose is allocated to another protocol or
if Ethertype DSA gets its own officially registered ethertype, and
everything will continue to work.)
Signed-off-by: Lennert Buytenhek <buytenh@marvell.com>
Tested-by: Nicolas Pitre <nico@marvell.com>
Tested-by: Byron Bradley <byron.bbradley@gmail.com>
Tested-by: Tim Ellis <tim.ellis@mac.com>
Tested-by: Peter van Valderen <linux@ddcrew.com>
Tested-by: Dirk Teurlings <dirk@upexia.nl>
Signed-off-by: David S. Miller <davem@davemloft.net>
2008-10-07 13:44:02 +00:00
|
|
|
#include "dsa_priv.h"
|
|
|
|
|
2019-04-28 17:37:16 +00:00
|
|
|
static LIST_HEAD(dsa_tag_drivers_list);
|
|
|
|
static DEFINE_MUTEX(dsa_tag_drivers_lock);
|
|
|
|
|
2016-06-04 19:17:03 +00:00
|
|
|
static struct sk_buff *dsa_slave_notag_xmit(struct sk_buff *skb,
|
|
|
|
struct net_device *dev)
|
|
|
|
{
|
|
|
|
/* Just return the original SKB */
|
|
|
|
return skb;
|
|
|
|
}
|
|
|
|
|
|
|
|
static const struct dsa_device_ops none_ops = {
|
2019-04-28 17:37:11 +00:00
|
|
|
.name = "none",
|
2019-04-28 17:37:14 +00:00
|
|
|
.proto = DSA_TAG_PROTO_NONE,
|
2016-06-04 19:17:03 +00:00
|
|
|
.xmit = dsa_slave_notag_xmit,
|
|
|
|
.rcv = NULL,
|
|
|
|
};
|
|
|
|
|
2019-04-28 17:37:17 +00:00
|
|
|
DSA_TAG_DRIVER(none_ops);
|
|
|
|
|
2019-04-28 17:37:16 +00:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
2019-04-28 17:37:15 +00:00
|
|
|
void dsa_tag_drivers_register(struct dsa_tag_driver *dsa_tag_driver_array[],
|
|
|
|
unsigned int count, struct module *owner)
|
|
|
|
{
|
2019-04-28 17:37:16 +00:00
|
|
|
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);
|
2019-04-28 17:37:15 +00:00
|
|
|
}
|
|
|
|
EXPORT_SYMBOL_GPL(dsa_tag_drivers_register);
|
|
|
|
|
|
|
|
void dsa_tag_drivers_unregister(struct dsa_tag_driver *dsa_tag_driver_array[],
|
|
|
|
unsigned int count)
|
|
|
|
{
|
2019-04-28 17:37:16 +00:00
|
|
|
unsigned int i;
|
|
|
|
|
|
|
|
for (i = 0; i < count; i++)
|
|
|
|
dsa_tag_driver_unregister(dsa_tag_driver_array[i]);
|
2019-04-28 17:37:15 +00:00
|
|
|
}
|
|
|
|
EXPORT_SYMBOL_GPL(dsa_tag_drivers_unregister);
|
|
|
|
|
2018-09-07 18:09:02 +00:00
|
|
|
const char *dsa_tag_protocol_to_str(const struct dsa_device_ops *ops)
|
|
|
|
{
|
2019-04-28 17:37:11 +00:00
|
|
|
return ops->name;
|
2018-09-07 18:09:02 +00:00
|
|
|
};
|
|
|
|
|
net: dsa: allow changing the tag protocol via the "tagging" device attribute
Currently DSA exposes the following sysfs:
$ cat /sys/class/net/eno2/dsa/tagging
ocelot
which is a read-only device attribute, introduced in the kernel as
commit 98cdb4807123 ("net: dsa: Expose tagging protocol to user-space"),
and used by libpcap since its commit 993db3800d7d ("Add support for DSA
link-layer types").
It would be nice if we could extend this device attribute by making it
writable:
$ echo ocelot-8021q > /sys/class/net/eno2/dsa/tagging
This is useful with DSA switches that can make use of more than one
tagging protocol. It may be useful in dsa_loop in the future too, to
perform offline testing of various taggers, or for changing between dsa
and edsa on Marvell switches, if that is desirable.
In terms of implementation, drivers can support this feature by
implementing .change_tag_protocol, which should always leave the switch
in a consistent state: either with the new protocol if things went well,
or with the old one if something failed. Teardown of the old protocol,
if necessary, must be handled by the driver.
Some things remain as before:
- The .get_tag_protocol is currently only called at probe time, to load
the initial tagging protocol driver. Nonetheless, new drivers should
report the tagging protocol in current use now.
- The driver should manage by itself the initial setup of tagging
protocol, no later than the .setup() method, as well as destroying
resources used by the last tagger in use, no earlier than the
.teardown() method.
For multi-switch DSA trees, error handling is a bit more complicated,
since e.g. the 5th out of 7 switches may fail to change the tag
protocol. When that happens, a revert to the original tag protocol is
attempted, but that may fail too, leaving the tree in an inconsistent
state despite each individual switch implementing .change_tag_protocol
transactionally. Since the intersection between drivers that implement
.change_tag_protocol and drivers that support D in DSA is currently the
empty set, the possibility for this error to happen is ignored for now.
Testing:
$ insmod mscc_felix.ko
[ 79.549784] mscc_felix 0000:00:00.5: Adding to iommu group 14
[ 79.565712] mscc_felix 0000:00:00.5: Failed to register DSA switch: -517
$ insmod tag_ocelot.ko
$ rmmod mscc_felix.ko
$ insmod mscc_felix.ko
[ 97.261724] libphy: VSC9959 internal MDIO bus: probed
[ 97.267363] mscc_felix 0000:00:00.5: Found PCS at internal MDIO address 0
[ 97.274998] mscc_felix 0000:00:00.5: Found PCS at internal MDIO address 1
[ 97.282561] mscc_felix 0000:00:00.5: Found PCS at internal MDIO address 2
[ 97.289700] mscc_felix 0000:00:00.5: Found PCS at internal MDIO address 3
[ 97.599163] mscc_felix 0000:00:00.5 swp0 (uninitialized): PHY [0000:00:00.3:10] driver [Microsemi GE VSC8514 SyncE] (irq=POLL)
[ 97.862034] mscc_felix 0000:00:00.5 swp1 (uninitialized): PHY [0000:00:00.3:11] driver [Microsemi GE VSC8514 SyncE] (irq=POLL)
[ 97.950731] mscc_felix 0000:00:00.5 swp0: configuring for inband/qsgmii link mode
[ 97.964278] 8021q: adding VLAN 0 to HW filter on device swp0
[ 98.146161] mscc_felix 0000:00:00.5 swp2 (uninitialized): PHY [0000:00:00.3:12] driver [Microsemi GE VSC8514 SyncE] (irq=POLL)
[ 98.238649] mscc_felix 0000:00:00.5 swp1: configuring for inband/qsgmii link mode
[ 98.251845] 8021q: adding VLAN 0 to HW filter on device swp1
[ 98.433916] mscc_felix 0000:00:00.5 swp3 (uninitialized): PHY [0000:00:00.3:13] driver [Microsemi GE VSC8514 SyncE] (irq=POLL)
[ 98.485542] mscc_felix 0000:00:00.5: configuring for fixed/internal link mode
[ 98.503584] mscc_felix 0000:00:00.5: Link is Up - 2.5Gbps/Full - flow control rx/tx
[ 98.527948] device eno2 entered promiscuous mode
[ 98.544755] DSA: tree 0 setup
$ ping 10.0.0.1
PING 10.0.0.1 (10.0.0.1): 56 data bytes
64 bytes from 10.0.0.1: seq=0 ttl=64 time=2.337 ms
64 bytes from 10.0.0.1: seq=1 ttl=64 time=0.754 ms
^C
- 10.0.0.1 ping statistics -
2 packets transmitted, 2 packets received, 0% packet loss
round-trip min/avg/max = 0.754/1.545/2.337 ms
$ cat /sys/class/net/eno2/dsa/tagging
ocelot
$ cat ./test_ocelot_8021q.sh
#!/bin/bash
ip link set swp0 down
ip link set swp1 down
ip link set swp2 down
ip link set swp3 down
ip link set swp5 down
ip link set eno2 down
echo ocelot-8021q > /sys/class/net/eno2/dsa/tagging
ip link set eno2 up
ip link set swp0 up
ip link set swp1 up
ip link set swp2 up
ip link set swp3 up
ip link set swp5 up
$ ./test_ocelot_8021q.sh
./test_ocelot_8021q.sh: line 9: echo: write error: Protocol not available
$ rmmod tag_ocelot.ko
rmmod: can't unload module 'tag_ocelot': Resource temporarily unavailable
$ insmod tag_ocelot_8021q.ko
$ ./test_ocelot_8021q.sh
$ cat /sys/class/net/eno2/dsa/tagging
ocelot-8021q
$ rmmod tag_ocelot.ko
$ rmmod tag_ocelot_8021q.ko
rmmod: can't unload module 'tag_ocelot_8021q': Resource temporarily unavailable
$ ping 10.0.0.1
PING 10.0.0.1 (10.0.0.1): 56 data bytes
64 bytes from 10.0.0.1: seq=0 ttl=64 time=0.953 ms
64 bytes from 10.0.0.1: seq=1 ttl=64 time=0.787 ms
64 bytes from 10.0.0.1: seq=2 ttl=64 time=0.771 ms
$ rmmod mscc_felix.ko
[ 645.544426] mscc_felix 0000:00:00.5: Link is Down
[ 645.838608] DSA: tree 0 torn down
$ rmmod tag_ocelot_8021q.ko
Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
2021-01-29 01:00:06 +00:00
|
|
|
/* Function takes a reference on the module owning the tagger,
|
|
|
|
* so dsa_tag_driver_put must be called afterwards.
|
|
|
|
*/
|
|
|
|
const struct dsa_device_ops *dsa_find_tagger_by_name(const char *buf)
|
|
|
|
{
|
|
|
|
const struct dsa_device_ops *ops = ERR_PTR(-ENOPROTOOPT);
|
|
|
|
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) {
|
|
|
|
const struct dsa_device_ops *tmp = dsa_tag_driver->ops;
|
|
|
|
|
|
|
|
if (!sysfs_streq(buf, tmp->name))
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if (!try_module_get(dsa_tag_driver->owner))
|
|
|
|
break;
|
|
|
|
|
|
|
|
ops = tmp;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
mutex_unlock(&dsa_tag_drivers_lock);
|
|
|
|
|
|
|
|
return ops;
|
|
|
|
}
|
|
|
|
|
2019-04-28 17:37:18 +00:00
|
|
|
const struct dsa_device_ops *dsa_tag_driver_get(int tag_protocol)
|
2016-06-04 19:17:03 +00:00
|
|
|
{
|
2019-04-28 17:37:20 +00:00
|
|
|
struct dsa_tag_driver *dsa_tag_driver;
|
2016-06-04 19:17:03 +00:00
|
|
|
const struct dsa_device_ops *ops;
|
2019-04-28 17:37:20 +00:00
|
|
|
bool found = false;
|
2016-06-04 19:17:03 +00:00
|
|
|
|
2020-03-28 09:53:09 +00:00
|
|
|
request_module("%s%d", DSA_TAG_DRIVER_ALIAS, tag_protocol);
|
2019-04-28 17:37:20 +00:00
|
|
|
|
|
|
|
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);
|
2016-06-04 19:17:03 +00:00
|
|
|
|
|
|
|
return ops;
|
|
|
|
}
|
|
|
|
|
2019-04-28 17:37:19 +00:00
|
|
|
void dsa_tag_driver_put(const struct dsa_device_ops *ops)
|
|
|
|
{
|
2019-04-28 17:37:20 +00:00
|
|
|
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);
|
2019-04-28 17:37:19 +00:00
|
|
|
}
|
|
|
|
|
net: Distributed Switch Architecture protocol support
Distributed Switch Architecture is a protocol for managing hardware
switch chips. It consists of a set of MII management registers and
commands to configure the switch, and an ethernet header format to
signal which of the ports of the switch a packet was received from
or is intended to be sent to.
The switches that this driver supports are typically embedded in
access points and routers, and a typical setup with a DSA switch
looks something like this:
+-----------+ +-----------+
| | RGMII | |
| +-------+ +------ 1000baseT MDI ("WAN")
| | | 6-port +------ 1000baseT MDI ("LAN1")
| CPU | | ethernet +------ 1000baseT MDI ("LAN2")
| |MIImgmt| switch +------ 1000baseT MDI ("LAN3")
| +-------+ w/5 PHYs +------ 1000baseT MDI ("LAN4")
| | | |
+-----------+ +-----------+
The switch driver presents each port on the switch as a separate
network interface to Linux, polls the switch to maintain software
link state of those ports, forwards MII management interface
accesses to those network interfaces (e.g. as done by ethtool) to
the switch, and exposes the switch's hardware statistics counters
via the appropriate Linux kernel interfaces.
This initial patch supports the MII management interface register
layout of the Marvell 88E6123, 88E6161 and 88E6165 switch chips, and
supports the "Ethertype DSA" packet tagging format.
(There is no officially registered ethertype for the Ethertype DSA
packet format, so we just grab a random one. The ethertype to use
is programmed into the switch, and the switch driver uses the value
of ETH_P_EDSA for this, so this define can be changed at any time in
the future if the one we chose is allocated to another protocol or
if Ethertype DSA gets its own officially registered ethertype, and
everything will continue to work.)
Signed-off-by: Lennert Buytenhek <buytenh@marvell.com>
Tested-by: Nicolas Pitre <nico@marvell.com>
Tested-by: Byron Bradley <byron.bbradley@gmail.com>
Tested-by: Tim Ellis <tim.ellis@mac.com>
Tested-by: Peter van Valderen <linux@ddcrew.com>
Tested-by: Dirk Teurlings <dirk@upexia.nl>
Signed-off-by: David S. Miller <davem@davemloft.net>
2008-10-07 13:44:02 +00:00
|
|
|
static int dev_is_class(struct device *dev, void *class)
|
|
|
|
{
|
|
|
|
if (dev->class != NULL && !strcmp(dev->class->name, class))
|
|
|
|
return 1;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static struct device *dev_find_class(struct device *parent, char *class)
|
|
|
|
{
|
|
|
|
if (dev_is_class(parent, class)) {
|
|
|
|
get_device(parent);
|
|
|
|
return parent;
|
|
|
|
}
|
|
|
|
|
|
|
|
return device_find_child(parent, class, dev_is_class);
|
|
|
|
}
|
|
|
|
|
2017-02-04 21:02:42 +00:00
|
|
|
struct net_device *dsa_dev_to_net_device(struct device *dev)
|
net: Distributed Switch Architecture protocol support
Distributed Switch Architecture is a protocol for managing hardware
switch chips. It consists of a set of MII management registers and
commands to configure the switch, and an ethernet header format to
signal which of the ports of the switch a packet was received from
or is intended to be sent to.
The switches that this driver supports are typically embedded in
access points and routers, and a typical setup with a DSA switch
looks something like this:
+-----------+ +-----------+
| | RGMII | |
| +-------+ +------ 1000baseT MDI ("WAN")
| | | 6-port +------ 1000baseT MDI ("LAN1")
| CPU | | ethernet +------ 1000baseT MDI ("LAN2")
| |MIImgmt| switch +------ 1000baseT MDI ("LAN3")
| +-------+ w/5 PHYs +------ 1000baseT MDI ("LAN4")
| | | |
+-----------+ +-----------+
The switch driver presents each port on the switch as a separate
network interface to Linux, polls the switch to maintain software
link state of those ports, forwards MII management interface
accesses to those network interfaces (e.g. as done by ethtool) to
the switch, and exposes the switch's hardware statistics counters
via the appropriate Linux kernel interfaces.
This initial patch supports the MII management interface register
layout of the Marvell 88E6123, 88E6161 and 88E6165 switch chips, and
supports the "Ethertype DSA" packet tagging format.
(There is no officially registered ethertype for the Ethertype DSA
packet format, so we just grab a random one. The ethertype to use
is programmed into the switch, and the switch driver uses the value
of ETH_P_EDSA for this, so this define can be changed at any time in
the future if the one we chose is allocated to another protocol or
if Ethertype DSA gets its own officially registered ethertype, and
everything will continue to work.)
Signed-off-by: Lennert Buytenhek <buytenh@marvell.com>
Tested-by: Nicolas Pitre <nico@marvell.com>
Tested-by: Byron Bradley <byron.bbradley@gmail.com>
Tested-by: Tim Ellis <tim.ellis@mac.com>
Tested-by: Peter van Valderen <linux@ddcrew.com>
Tested-by: Dirk Teurlings <dirk@upexia.nl>
Signed-off-by: David S. Miller <davem@davemloft.net>
2008-10-07 13:44:02 +00:00
|
|
|
{
|
|
|
|
struct device *d;
|
|
|
|
|
|
|
|
d = dev_find_class(dev, "net");
|
|
|
|
if (d != NULL) {
|
|
|
|
struct net_device *nd;
|
|
|
|
|
|
|
|
nd = to_net_dev(d);
|
|
|
|
dev_hold(nd);
|
|
|
|
put_device(d);
|
|
|
|
|
|
|
|
return nd;
|
|
|
|
}
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
2017-02-04 21:02:42 +00:00
|
|
|
EXPORT_SYMBOL_GPL(dsa_dev_to_net_device);
|
net: Distributed Switch Architecture protocol support
Distributed Switch Architecture is a protocol for managing hardware
switch chips. It consists of a set of MII management registers and
commands to configure the switch, and an ethernet header format to
signal which of the ports of the switch a packet was received from
or is intended to be sent to.
The switches that this driver supports are typically embedded in
access points and routers, and a typical setup with a DSA switch
looks something like this:
+-----------+ +-----------+
| | RGMII | |
| +-------+ +------ 1000baseT MDI ("WAN")
| | | 6-port +------ 1000baseT MDI ("LAN1")
| CPU | | ethernet +------ 1000baseT MDI ("LAN2")
| |MIImgmt| switch +------ 1000baseT MDI ("LAN3")
| +-------+ w/5 PHYs +------ 1000baseT MDI ("LAN4")
| | | |
+-----------+ +-----------+
The switch driver presents each port on the switch as a separate
network interface to Linux, polls the switch to maintain software
link state of those ports, forwards MII management interface
accesses to those network interfaces (e.g. as done by ethtool) to
the switch, and exposes the switch's hardware statistics counters
via the appropriate Linux kernel interfaces.
This initial patch supports the MII management interface register
layout of the Marvell 88E6123, 88E6161 and 88E6165 switch chips, and
supports the "Ethertype DSA" packet tagging format.
(There is no officially registered ethertype for the Ethertype DSA
packet format, so we just grab a random one. The ethertype to use
is programmed into the switch, and the switch driver uses the value
of ETH_P_EDSA for this, so this define can be changed at any time in
the future if the one we chose is allocated to another protocol or
if Ethertype DSA gets its own officially registered ethertype, and
everything will continue to work.)
Signed-off-by: Lennert Buytenhek <buytenh@marvell.com>
Tested-by: Nicolas Pitre <nico@marvell.com>
Tested-by: Byron Bradley <byron.bbradley@gmail.com>
Tested-by: Tim Ellis <tim.ellis@mac.com>
Tested-by: Peter van Valderen <linux@ddcrew.com>
Tested-by: Dirk Teurlings <dirk@upexia.nl>
Signed-off-by: David S. Miller <davem@davemloft.net>
2008-10-07 13:44:02 +00:00
|
|
|
|
2018-02-14 00:07:49 +00:00
|
|
|
/* Determine if we should defer delivery of skb until we have a rx timestamp.
|
|
|
|
*
|
|
|
|
* Called from dsa_switch_rcv. For now, this will only work if tagging is
|
|
|
|
* enabled on the switch. Normally the MAC driver would retrieve the hardware
|
|
|
|
* timestamp when it reads the packet out of the hardware. However in a DSA
|
|
|
|
* switch, the DSA driver owning the interface to which the packet is
|
|
|
|
* delivered is never notified unless we do so here.
|
|
|
|
*/
|
|
|
|
static bool dsa_skb_defer_rx_timestamp(struct dsa_slave_priv *p,
|
|
|
|
struct sk_buff *skb)
|
|
|
|
{
|
|
|
|
struct dsa_switch *ds = p->dp->ds;
|
|
|
|
unsigned int type;
|
|
|
|
|
|
|
|
if (skb_headroom(skb) < ETH_HLEN)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
__skb_push(skb, ETH_HLEN);
|
|
|
|
|
|
|
|
type = ptp_classify_raw(skb);
|
|
|
|
|
|
|
|
__skb_pull(skb, ETH_HLEN);
|
|
|
|
|
|
|
|
if (type == PTP_CLASS_NONE)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
if (likely(ds->ops->port_rxtstamp))
|
|
|
|
return ds->ops->port_rxtstamp(ds, p->dp->index, skb, type);
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2014-08-28 00:04:46 +00:00
|
|
|
static int dsa_switch_rcv(struct sk_buff *skb, struct net_device *dev,
|
2017-08-17 14:47:00 +00:00
|
|
|
struct packet_type *pt, struct net_device *unused)
|
2014-08-28 00:04:46 +00:00
|
|
|
{
|
2017-09-29 21:19:20 +00:00
|
|
|
struct dsa_port *cpu_dp = dev->dsa_ptr;
|
2017-04-08 15:55:23 +00:00
|
|
|
struct sk_buff *nskb = NULL;
|
2017-08-01 22:00:36 +00:00
|
|
|
struct dsa_slave_priv *p;
|
2014-08-28 00:04:46 +00:00
|
|
|
|
2017-09-29 21:19:20 +00:00
|
|
|
if (unlikely(!cpu_dp)) {
|
2014-08-28 00:04:46 +00:00
|
|
|
kfree_skb(skb);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2017-04-08 15:55:22 +00:00
|
|
|
skb = skb_unshare(skb, GFP_ATOMIC);
|
|
|
|
if (!skb)
|
|
|
|
return 0;
|
|
|
|
|
2021-07-31 14:14:32 +00:00
|
|
|
nskb = cpu_dp->rcv(skb, dev);
|
2017-04-08 15:55:23 +00:00
|
|
|
if (!nskb) {
|
|
|
|
kfree_skb(skb);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
skb = nskb;
|
|
|
|
skb_push(skb, ETH_HLEN);
|
|
|
|
skb->pkt_type = PACKET_HOST;
|
|
|
|
skb->protocol = eth_type_trans(skb, skb->dev);
|
|
|
|
|
2021-01-13 08:42:55 +00:00
|
|
|
if (unlikely(!dsa_slave_dev_check(skb->dev))) {
|
|
|
|
/* Packet is to be injected directly on an upper
|
|
|
|
* device, e.g. a team/bond, so skip all DSA-port
|
|
|
|
* specific actions.
|
|
|
|
*/
|
|
|
|
netif_rx(skb);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
p = netdev_priv(skb->dev);
|
|
|
|
|
2020-10-02 02:42:12 +00:00
|
|
|
if (unlikely(cpu_dp->ds->untag_bridge_pvid)) {
|
|
|
|
nskb = dsa_untag_bridge_pvid(skb);
|
|
|
|
if (!nskb) {
|
|
|
|
kfree_skb(skb);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
skb = nskb;
|
|
|
|
}
|
|
|
|
|
2020-11-07 20:49:46 +00:00
|
|
|
dev_sw_netstats_rx_add(skb->dev, skb->len);
|
2017-04-08 15:55:23 +00:00
|
|
|
|
2018-02-14 00:07:49 +00:00
|
|
|
if (dsa_skb_defer_rx_timestamp(p, skb))
|
|
|
|
return 0;
|
|
|
|
|
2020-04-21 13:41:08 +00:00
|
|
|
gro_cells_receive(&p->gcells, skb);
|
2017-04-08 15:55:23 +00:00
|
|
|
|
|
|
|
return 0;
|
2014-08-28 00:04:46 +00:00
|
|
|
}
|
|
|
|
|
2017-06-02 02:53:04 +00:00
|
|
|
#ifdef CONFIG_PM_SLEEP
|
2021-10-20 17:49:50 +00:00
|
|
|
static bool dsa_port_is_initialized(const struct dsa_port *dp)
|
2017-07-18 20:23:56 +00:00
|
|
|
{
|
2019-10-21 20:51:15 +00:00
|
|
|
return dp->type == DSA_PORT_TYPE_USER && dp->slave;
|
2017-07-18 20:23:56 +00:00
|
|
|
}
|
|
|
|
|
2017-06-02 02:53:04 +00:00
|
|
|
int dsa_switch_suspend(struct dsa_switch *ds)
|
|
|
|
{
|
2021-10-20 17:49:50 +00:00
|
|
|
struct dsa_port *dp;
|
|
|
|
int ret = 0;
|
2017-06-02 02:53:04 +00:00
|
|
|
|
|
|
|
/* Suspend slave network devices */
|
2021-10-20 17:49:50 +00:00
|
|
|
dsa_switch_for_each_port(dp, ds) {
|
|
|
|
if (!dsa_port_is_initialized(dp))
|
2017-06-02 02:53:04 +00:00
|
|
|
continue;
|
|
|
|
|
2021-10-20 17:49:50 +00:00
|
|
|
ret = dsa_slave_suspend(dp->slave);
|
2017-06-02 02:53:04 +00:00
|
|
|
if (ret)
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (ds->ops->suspend)
|
|
|
|
ret = ds->ops->suspend(ds);
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
EXPORT_SYMBOL_GPL(dsa_switch_suspend);
|
|
|
|
|
|
|
|
int dsa_switch_resume(struct dsa_switch *ds)
|
|
|
|
{
|
2021-10-20 17:49:50 +00:00
|
|
|
struct dsa_port *dp;
|
|
|
|
int ret = 0;
|
2017-06-02 02:53:04 +00:00
|
|
|
|
|
|
|
if (ds->ops->resume)
|
|
|
|
ret = ds->ops->resume(ds);
|
|
|
|
|
|
|
|
if (ret)
|
|
|
|
return ret;
|
|
|
|
|
|
|
|
/* Resume slave network devices */
|
2021-10-20 17:49:50 +00:00
|
|
|
dsa_switch_for_each_port(dp, ds) {
|
|
|
|
if (!dsa_port_is_initialized(dp))
|
2017-06-02 02:53:04 +00:00
|
|
|
continue;
|
|
|
|
|
2021-10-20 17:49:50 +00:00
|
|
|
ret = dsa_slave_resume(dp->slave);
|
2017-06-02 02:53:04 +00:00
|
|
|
if (ret)
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
EXPORT_SYMBOL_GPL(dsa_switch_resume);
|
|
|
|
#endif
|
|
|
|
|
2014-08-29 19:42:07 +00:00
|
|
|
static struct packet_type dsa_pack_type __read_mostly = {
|
2014-08-28 00:04:46 +00:00
|
|
|
.type = cpu_to_be16(ETH_P_XDSA),
|
|
|
|
.func = dsa_switch_rcv,
|
|
|
|
};
|
|
|
|
|
2017-08-06 13:15:42 +00:00
|
|
|
static struct workqueue_struct *dsa_owq;
|
|
|
|
|
|
|
|
bool dsa_schedule_work(struct work_struct *work)
|
|
|
|
{
|
|
|
|
return queue_work(dsa_owq, work);
|
|
|
|
}
|
|
|
|
|
net: dsa: flush switchdev workqueue before tearing down CPU/DSA ports
Sometimes when unbinding the mv88e6xxx driver on Turris MOX, these error
messages appear:
mv88e6085 d0032004.mdio-mii:12: port 1 failed to delete be:79:b4:9e:9e:96 vid 1 from fdb: -2
mv88e6085 d0032004.mdio-mii:12: port 1 failed to delete be:79:b4:9e:9e:96 vid 0 from fdb: -2
mv88e6085 d0032004.mdio-mii:12: port 1 failed to delete d8:58:d7:00:ca:6d vid 100 from fdb: -2
mv88e6085 d0032004.mdio-mii:12: port 1 failed to delete d8:58:d7:00:ca:6d vid 1 from fdb: -2
mv88e6085 d0032004.mdio-mii:12: port 1 failed to delete d8:58:d7:00:ca:6d vid 0 from fdb: -2
(and similarly for other ports)
What happens is that DSA has a policy "even if there are bugs, let's at
least not leak memory" and dsa_port_teardown() clears the dp->fdbs and
dp->mdbs lists, which are supposed to be empty.
But deleting that cleanup code, the warnings go away.
=> the FDB and MDB lists (used for refcounting on shared ports, aka CPU
and DSA ports) will eventually be empty, but are not empty by the time
we tear down those ports. Aka we are deleting them too soon.
The addresses that DSA complains about are host-trapped addresses: the
local addresses of the ports, and the MAC address of the bridge device.
The problem is that offloading those entries happens from a deferred
work item scheduled by the SWITCHDEV_FDB_DEL_TO_DEVICE handler, and this
races with the teardown of the CPU and DSA ports where the refcounting
is kept.
In fact, not only it races, but fundamentally speaking, if we iterate
through the port list linearly, we might end up tearing down the shared
ports even before we delete a DSA user port which has a bridge upper.
So as it turns out, we need to first tear down the user ports (and the
unused ones, for no better place of doing that), then the shared ports
(the CPU and DSA ports). In between, we need to ensure that all work
items scheduled by our switchdev handlers (which only run for user
ports, hence the reason why we tear them down first) have finished.
Fixes: 161ca59d39e9 ("net: dsa: reference count the MDB entries at the cross-chip notifier level")
Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>
Reviewed-by: Florian Fainelli <f.fainelli@gmail.com>
Link: https://lore.kernel.org/r/20210914134726.2305133-1-vladimir.oltean@nxp.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
2021-09-14 13:47:26 +00:00
|
|
|
void dsa_flush_workqueue(void)
|
|
|
|
{
|
|
|
|
flush_workqueue(dsa_owq);
|
|
|
|
}
|
2022-02-11 17:45:06 +00:00
|
|
|
EXPORT_SYMBOL_GPL(dsa_flush_workqueue);
|
net: dsa: flush switchdev workqueue before tearing down CPU/DSA ports
Sometimes when unbinding the mv88e6xxx driver on Turris MOX, these error
messages appear:
mv88e6085 d0032004.mdio-mii:12: port 1 failed to delete be:79:b4:9e:9e:96 vid 1 from fdb: -2
mv88e6085 d0032004.mdio-mii:12: port 1 failed to delete be:79:b4:9e:9e:96 vid 0 from fdb: -2
mv88e6085 d0032004.mdio-mii:12: port 1 failed to delete d8:58:d7:00:ca:6d vid 100 from fdb: -2
mv88e6085 d0032004.mdio-mii:12: port 1 failed to delete d8:58:d7:00:ca:6d vid 1 from fdb: -2
mv88e6085 d0032004.mdio-mii:12: port 1 failed to delete d8:58:d7:00:ca:6d vid 0 from fdb: -2
(and similarly for other ports)
What happens is that DSA has a policy "even if there are bugs, let's at
least not leak memory" and dsa_port_teardown() clears the dp->fdbs and
dp->mdbs lists, which are supposed to be empty.
But deleting that cleanup code, the warnings go away.
=> the FDB and MDB lists (used for refcounting on shared ports, aka CPU
and DSA ports) will eventually be empty, but are not empty by the time
we tear down those ports. Aka we are deleting them too soon.
The addresses that DSA complains about are host-trapped addresses: the
local addresses of the ports, and the MAC address of the bridge device.
The problem is that offloading those entries happens from a deferred
work item scheduled by the SWITCHDEV_FDB_DEL_TO_DEVICE handler, and this
races with the teardown of the CPU and DSA ports where the refcounting
is kept.
In fact, not only it races, but fundamentally speaking, if we iterate
through the port list linearly, we might end up tearing down the shared
ports even before we delete a DSA user port which has a bridge upper.
So as it turns out, we need to first tear down the user ports (and the
unused ones, for no better place of doing that), then the shared ports
(the CPU and DSA ports). In between, we need to ensure that all work
items scheduled by our switchdev handlers (which only run for user
ports, hence the reason why we tear them down first) have finished.
Fixes: 161ca59d39e9 ("net: dsa: reference count the MDB entries at the cross-chip notifier level")
Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>
Reviewed-by: Florian Fainelli <f.fainelli@gmail.com>
Link: https://lore.kernel.org/r/20210914134726.2305133-1-vladimir.oltean@nxp.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
2021-09-14 13:47:26 +00:00
|
|
|
|
2019-10-24 23:03:51 +00:00
|
|
|
int dsa_devlink_param_get(struct devlink *dl, u32 id,
|
|
|
|
struct devlink_param_gset_ctx *ctx)
|
|
|
|
{
|
2020-09-18 19:11:03 +00:00
|
|
|
struct dsa_switch *ds = dsa_devlink_to_ds(dl);
|
2019-10-24 23:03:51 +00:00
|
|
|
|
|
|
|
if (!ds->ops->devlink_param_get)
|
|
|
|
return -EOPNOTSUPP;
|
|
|
|
|
|
|
|
return ds->ops->devlink_param_get(ds, id, ctx);
|
|
|
|
}
|
|
|
|
EXPORT_SYMBOL_GPL(dsa_devlink_param_get);
|
|
|
|
|
|
|
|
int dsa_devlink_param_set(struct devlink *dl, u32 id,
|
|
|
|
struct devlink_param_gset_ctx *ctx)
|
|
|
|
{
|
2020-09-18 19:11:03 +00:00
|
|
|
struct dsa_switch *ds = dsa_devlink_to_ds(dl);
|
2019-10-24 23:03:51 +00:00
|
|
|
|
|
|
|
if (!ds->ops->devlink_param_set)
|
|
|
|
return -EOPNOTSUPP;
|
|
|
|
|
|
|
|
return ds->ops->devlink_param_set(ds, id, ctx);
|
|
|
|
}
|
|
|
|
EXPORT_SYMBOL_GPL(dsa_devlink_param_set);
|
|
|
|
|
|
|
|
int dsa_devlink_params_register(struct dsa_switch *ds,
|
|
|
|
const struct devlink_param *params,
|
|
|
|
size_t params_count)
|
|
|
|
{
|
|
|
|
return devlink_params_register(ds->devlink, params, params_count);
|
|
|
|
}
|
|
|
|
EXPORT_SYMBOL_GPL(dsa_devlink_params_register);
|
|
|
|
|
|
|
|
void dsa_devlink_params_unregister(struct dsa_switch *ds,
|
|
|
|
const struct devlink_param *params,
|
|
|
|
size_t params_count)
|
|
|
|
{
|
|
|
|
devlink_params_unregister(ds->devlink, params, params_count);
|
|
|
|
}
|
|
|
|
EXPORT_SYMBOL_GPL(dsa_devlink_params_unregister);
|
|
|
|
|
2019-11-05 00:12:57 +00:00
|
|
|
int dsa_devlink_resource_register(struct dsa_switch *ds,
|
|
|
|
const char *resource_name,
|
|
|
|
u64 resource_size,
|
|
|
|
u64 resource_id,
|
|
|
|
u64 parent_resource_id,
|
|
|
|
const struct devlink_resource_size_params *size_params)
|
|
|
|
{
|
|
|
|
return devlink_resource_register(ds->devlink, resource_name,
|
|
|
|
resource_size, resource_id,
|
|
|
|
parent_resource_id,
|
|
|
|
size_params);
|
|
|
|
}
|
|
|
|
EXPORT_SYMBOL_GPL(dsa_devlink_resource_register);
|
|
|
|
|
|
|
|
void dsa_devlink_resources_unregister(struct dsa_switch *ds)
|
|
|
|
{
|
2021-11-30 10:16:20 +00:00
|
|
|
devlink_resources_unregister(ds->devlink);
|
2019-11-05 00:12:57 +00:00
|
|
|
}
|
|
|
|
EXPORT_SYMBOL_GPL(dsa_devlink_resources_unregister);
|
|
|
|
|
|
|
|
void dsa_devlink_resource_occ_get_register(struct dsa_switch *ds,
|
|
|
|
u64 resource_id,
|
|
|
|
devlink_resource_occ_get_t *occ_get,
|
|
|
|
void *occ_get_priv)
|
|
|
|
{
|
|
|
|
return devlink_resource_occ_get_register(ds->devlink, resource_id,
|
|
|
|
occ_get, occ_get_priv);
|
|
|
|
}
|
|
|
|
EXPORT_SYMBOL_GPL(dsa_devlink_resource_occ_get_register);
|
|
|
|
|
|
|
|
void dsa_devlink_resource_occ_get_unregister(struct dsa_switch *ds,
|
|
|
|
u64 resource_id)
|
|
|
|
{
|
|
|
|
devlink_resource_occ_get_unregister(ds->devlink, resource_id);
|
|
|
|
}
|
|
|
|
EXPORT_SYMBOL_GPL(dsa_devlink_resource_occ_get_unregister);
|
|
|
|
|
2020-09-18 19:11:04 +00:00
|
|
|
struct devlink_region *
|
|
|
|
dsa_devlink_region_create(struct dsa_switch *ds,
|
|
|
|
const struct devlink_region_ops *ops,
|
|
|
|
u32 region_max_snapshots, u64 region_size)
|
|
|
|
{
|
|
|
|
return devlink_region_create(ds->devlink, ops, region_max_snapshots,
|
|
|
|
region_size);
|
|
|
|
}
|
|
|
|
EXPORT_SYMBOL_GPL(dsa_devlink_region_create);
|
|
|
|
|
2020-10-04 16:12:55 +00:00
|
|
|
struct devlink_region *
|
|
|
|
dsa_devlink_port_region_create(struct dsa_switch *ds,
|
|
|
|
int port,
|
|
|
|
const struct devlink_port_region_ops *ops,
|
|
|
|
u32 region_max_snapshots, u64 region_size)
|
|
|
|
{
|
|
|
|
struct dsa_port *dp = dsa_to_port(ds, port);
|
|
|
|
|
|
|
|
return devlink_port_region_create(&dp->devlink_port, ops,
|
|
|
|
region_max_snapshots,
|
|
|
|
region_size);
|
|
|
|
}
|
|
|
|
EXPORT_SYMBOL_GPL(dsa_devlink_port_region_create);
|
|
|
|
|
2020-09-18 19:11:04 +00:00
|
|
|
void dsa_devlink_region_destroy(struct devlink_region *region)
|
|
|
|
{
|
|
|
|
devlink_region_destroy(region);
|
|
|
|
}
|
|
|
|
EXPORT_SYMBOL_GPL(dsa_devlink_region_destroy);
|
|
|
|
|
net: dsa: introduce a dsa_port_from_netdev public helper
As its implementation shows, this is synonimous with calling
dsa_slave_dev_check followed by dsa_slave_to_port, so it is quite simple
already and provides functionality which is already there.
However there is now a need for these functions outside dsa_priv.h, for
example in drivers that perform mirroring and redirection through
tc-flower offloads (they are given raw access to the flow_cls_offload
structure), where they need to call this function on act->dev.
But simply exporting dsa_slave_to_port would make it non-inline and
would result in an extra function call in the hotpath, as can be seen
for example in sja1105:
Before:
000006dc <sja1105_xmit>:
{
6dc: e92d4ff0 push {r4, r5, r6, r7, r8, r9, sl, fp, lr}
6e0: e1a04000 mov r4, r0
6e4: e591958c ldr r9, [r1, #1420] ; 0x58c <- Inline dsa_slave_to_port
6e8: e1a05001 mov r5, r1
6ec: e24dd004 sub sp, sp, #4
u16 tx_vid = dsa_8021q_tx_vid(dp->ds, dp->index);
6f0: e1c901d8 ldrd r0, [r9, #24]
6f4: ebfffffe bl 0 <dsa_8021q_tx_vid>
6f4: R_ARM_CALL dsa_8021q_tx_vid
u8 pcp = netdev_txq_to_tc(netdev, queue_mapping);
6f8: e1d416b0 ldrh r1, [r4, #96] ; 0x60
u16 tx_vid = dsa_8021q_tx_vid(dp->ds, dp->index);
6fc: e1a08000 mov r8, r0
After:
000006e4 <sja1105_xmit>:
{
6e4: e92d4ff0 push {r4, r5, r6, r7, r8, r9, sl, fp, lr}
6e8: e1a04000 mov r4, r0
6ec: e24dd004 sub sp, sp, #4
struct dsa_port *dp = dsa_slave_to_port(netdev);
6f0: e1a00001 mov r0, r1
{
6f4: e1a05001 mov r5, r1
struct dsa_port *dp = dsa_slave_to_port(netdev);
6f8: ebfffffe bl 0 <dsa_slave_to_port>
6f8: R_ARM_CALL dsa_slave_to_port
6fc: e1a09000 mov r9, r0
u16 tx_vid = dsa_8021q_tx_vid(dp->ds, dp->index);
700: e1c001d8 ldrd r0, [r0, #24]
704: ebfffffe bl 0 <dsa_8021q_tx_vid>
704: R_ARM_CALL dsa_8021q_tx_vid
Because we want to avoid possible performance regressions, introduce
this new function which is designed to be public.
Suggested-by: Vivien Didelot <vivien.didelot@gmail.com>
Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>
Reviewed-by: Vivien Didelot <vivien.didelot@gmail.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
2020-05-05 19:20:52 +00:00
|
|
|
struct dsa_port *dsa_port_from_netdev(struct net_device *netdev)
|
|
|
|
{
|
|
|
|
if (!netdev || !dsa_slave_dev_check(netdev))
|
|
|
|
return ERR_PTR(-ENODEV);
|
|
|
|
|
|
|
|
return dsa_slave_to_port(netdev);
|
|
|
|
}
|
|
|
|
EXPORT_SYMBOL_GPL(dsa_port_from_netdev);
|
|
|
|
|
2022-03-02 19:14:13 +00:00
|
|
|
int dsa_port_walk_fdbs(struct dsa_switch *ds, int port, dsa_fdb_walk_cb_t cb)
|
|
|
|
{
|
|
|
|
struct dsa_port *dp = dsa_to_port(ds, port);
|
|
|
|
struct dsa_mac_addr *a;
|
2022-03-05 17:14:48 +00:00
|
|
|
int err = 0;
|
2022-03-02 19:14:13 +00:00
|
|
|
|
|
|
|
mutex_lock(&dp->addr_lists_lock);
|
|
|
|
|
|
|
|
list_for_each_entry(a, &dp->fdbs, list) {
|
|
|
|
err = cb(ds, port, a->addr, a->vid, a->db);
|
|
|
|
if (err)
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
mutex_unlock(&dp->addr_lists_lock);
|
|
|
|
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
EXPORT_SYMBOL_GPL(dsa_port_walk_fdbs);
|
|
|
|
|
|
|
|
int dsa_port_walk_mdbs(struct dsa_switch *ds, int port, dsa_fdb_walk_cb_t cb)
|
|
|
|
{
|
|
|
|
struct dsa_port *dp = dsa_to_port(ds, port);
|
|
|
|
struct dsa_mac_addr *a;
|
2022-03-05 17:14:48 +00:00
|
|
|
int err = 0;
|
2022-03-02 19:14:13 +00:00
|
|
|
|
|
|
|
mutex_lock(&dp->addr_lists_lock);
|
|
|
|
|
|
|
|
list_for_each_entry(a, &dp->mdbs, list) {
|
|
|
|
err = cb(ds, port, a->addr, a->vid, a->db);
|
|
|
|
if (err)
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
mutex_unlock(&dp->addr_lists_lock);
|
|
|
|
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
EXPORT_SYMBOL_GPL(dsa_port_walk_mdbs);
|
|
|
|
|
net: dsa: felix: avoid early deletion of host FDB entries
The Felix driver declares FDB isolation but puts all standalone ports in
VID 0. This is mostly problem-free as discussed with Alvin here:
https://patchwork.kernel.org/project/netdevbpf/cover/20220302191417.1288145-1-vladimir.oltean@nxp.com/#24763870
however there is one catch. DSA still thinks that FDB entries are
installed on the CPU port as many times as there are user ports, and
this is problematic when multiple user ports share the same MAC address.
Consider the default case where all user ports inherit their MAC address
from the DSA master, and then the user runs:
ip link set swp0 address 00:01:02:03:04:05
The above will make dsa_slave_set_mac_address() call
dsa_port_standalone_host_fdb_add() for 00:01:02:03:04:05 in port 0's
standalone database, and dsa_port_standalone_host_fdb_del() for the old
address of swp0, again in swp0's standalone database.
Both the ->port_fdb_add() and ->port_fdb_del() will be propagated down
to the felix driver, which will end up deleting the old MAC address from
the CPU port. But this is still in use by other user ports, so we end up
breaking unicast termination for them.
There isn't a problem in the fact that DSA keeps track of host
standalone addresses in the individual database of each user port: some
drivers like sja1105 need this. There also isn't a problem in the fact
that some drivers choose the same VID/FID for all standalone ports.
It is just that the deletion of these host addresses must be delayed
until they are known to not be in use any longer, and only the driver
has this knowledge. Since DSA keeps these addresses in &cpu_dp->fdbs and
&cpu_db->mdbs, it is just a matter of walking over those lists and see
whether the same MAC address is present on the CPU port in the port db
of another user port.
I have considered reusing the generic dsa_port_walk_fdbs() and
dsa_port_walk_mdbs() schemes for this, but locking makes it difficult.
In the ->port_fdb_add() method and co, &dp->addr_lists_lock is held, but
dsa_port_walk_fdbs() also acquires that lock. Also, even assuming that
we introduce an unlocked variant of the address iterator, we'd still
need some relatively complex data structures, and a void *ctx in the
dsa_fdb_walk_cb_t which we don't currently pass, such that drivers are
able to figure out, after iterating, whether the same MAC address is or
isn't present in the port db of another port.
All the above, plus the fact that I expect other drivers to follow the
same model as felix where all standalone ports use the same FID, made me
conclude that a generic method provided by DSA is necessary:
dsa_fdb_present_in_other_db() and the mdb equivalent. Felix calls this
from the ->port_fdb_del() handler for the CPU port, when the database
was classified to either a port db, or a LAG db.
For symmetry, we also call this from ->port_fdb_add(), because if the
address was installed once, then installing it a second time serves no
purpose: it's already in hardware in VID 0 and it affects all standalone
ports.
This change moves dsa_db_equal() from switch.c to dsa.c, since it now
has one more caller.
Fixes: 54c319846086 ("net: mscc: ocelot: enforce FDB isolation when VLAN-unaware")
Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
2022-03-08 09:15:15 +00:00
|
|
|
bool dsa_db_equal(const struct dsa_db *a, const struct dsa_db *b)
|
|
|
|
{
|
|
|
|
if (a->type != b->type)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
switch (a->type) {
|
|
|
|
case DSA_DB_PORT:
|
|
|
|
return a->dp == b->dp;
|
|
|
|
case DSA_DB_LAG:
|
|
|
|
return a->lag.dev == b->lag.dev;
|
|
|
|
case DSA_DB_BRIDGE:
|
|
|
|
return a->bridge.num == b->bridge.num;
|
|
|
|
default:
|
|
|
|
WARN_ON(1);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
bool dsa_fdb_present_in_other_db(struct dsa_switch *ds, int port,
|
|
|
|
const unsigned char *addr, u16 vid,
|
|
|
|
struct dsa_db db)
|
|
|
|
{
|
|
|
|
struct dsa_port *dp = dsa_to_port(ds, port);
|
|
|
|
struct dsa_mac_addr *a;
|
|
|
|
|
|
|
|
lockdep_assert_held(&dp->addr_lists_lock);
|
|
|
|
|
|
|
|
list_for_each_entry(a, &dp->fdbs, list) {
|
|
|
|
if (!ether_addr_equal(a->addr, addr) || a->vid != vid)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if (a->db.type == db.type && !dsa_db_equal(&a->db, &db))
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
EXPORT_SYMBOL_GPL(dsa_fdb_present_in_other_db);
|
|
|
|
|
|
|
|
bool dsa_mdb_present_in_other_db(struct dsa_switch *ds, int port,
|
|
|
|
const struct switchdev_obj_port_mdb *mdb,
|
|
|
|
struct dsa_db db)
|
|
|
|
{
|
|
|
|
struct dsa_port *dp = dsa_to_port(ds, port);
|
|
|
|
struct dsa_mac_addr *a;
|
|
|
|
|
|
|
|
lockdep_assert_held(&dp->addr_lists_lock);
|
|
|
|
|
|
|
|
list_for_each_entry(a, &dp->mdbs, list) {
|
|
|
|
if (!ether_addr_equal(a->addr, mdb->addr) || a->vid != mdb->vid)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if (a->db.type == db.type && !dsa_db_equal(&a->db, &db))
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
EXPORT_SYMBOL_GPL(dsa_mdb_present_in_other_db);
|
|
|
|
|
net: Distributed Switch Architecture protocol support
Distributed Switch Architecture is a protocol for managing hardware
switch chips. It consists of a set of MII management registers and
commands to configure the switch, and an ethernet header format to
signal which of the ports of the switch a packet was received from
or is intended to be sent to.
The switches that this driver supports are typically embedded in
access points and routers, and a typical setup with a DSA switch
looks something like this:
+-----------+ +-----------+
| | RGMII | |
| +-------+ +------ 1000baseT MDI ("WAN")
| | | 6-port +------ 1000baseT MDI ("LAN1")
| CPU | | ethernet +------ 1000baseT MDI ("LAN2")
| |MIImgmt| switch +------ 1000baseT MDI ("LAN3")
| +-------+ w/5 PHYs +------ 1000baseT MDI ("LAN4")
| | | |
+-----------+ +-----------+
The switch driver presents each port on the switch as a separate
network interface to Linux, polls the switch to maintain software
link state of those ports, forwards MII management interface
accesses to those network interfaces (e.g. as done by ethtool) to
the switch, and exposes the switch's hardware statistics counters
via the appropriate Linux kernel interfaces.
This initial patch supports the MII management interface register
layout of the Marvell 88E6123, 88E6161 and 88E6165 switch chips, and
supports the "Ethertype DSA" packet tagging format.
(There is no officially registered ethertype for the Ethertype DSA
packet format, so we just grab a random one. The ethertype to use
is programmed into the switch, and the switch driver uses the value
of ETH_P_EDSA for this, so this define can be changed at any time in
the future if the one we chose is allocated to another protocol or
if Ethertype DSA gets its own officially registered ethertype, and
everything will continue to work.)
Signed-off-by: Lennert Buytenhek <buytenh@marvell.com>
Tested-by: Nicolas Pitre <nico@marvell.com>
Tested-by: Byron Bradley <byron.bbradley@gmail.com>
Tested-by: Tim Ellis <tim.ellis@mac.com>
Tested-by: Peter van Valderen <linux@ddcrew.com>
Tested-by: Dirk Teurlings <dirk@upexia.nl>
Signed-off-by: David S. Miller <davem@davemloft.net>
2008-10-07 13:44:02 +00:00
|
|
|
static int __init dsa_init_module(void)
|
|
|
|
{
|
2011-11-25 14:35:02 +00:00
|
|
|
int rc;
|
|
|
|
|
2017-08-06 13:15:42 +00:00
|
|
|
dsa_owq = alloc_ordered_workqueue("dsa_ordered",
|
|
|
|
WQ_MEM_RECLAIM);
|
|
|
|
if (!dsa_owq)
|
|
|
|
return -ENOMEM;
|
|
|
|
|
2017-02-03 18:20:16 +00:00
|
|
|
rc = dsa_slave_register_notifier();
|
|
|
|
if (rc)
|
2019-05-06 15:25:29 +00:00
|
|
|
goto register_notifier_fail;
|
2015-02-24 21:15:33 +00:00
|
|
|
|
2014-08-28 00:04:46 +00:00
|
|
|
dev_add_pack(&dsa_pack_type);
|
|
|
|
|
2019-04-28 17:37:17 +00:00
|
|
|
dsa_tag_driver_register(&DSA_TAG_DRIVER_NAME(none_ops),
|
|
|
|
THIS_MODULE);
|
|
|
|
|
2011-11-25 14:35:02 +00:00
|
|
|
return 0;
|
2019-05-06 15:25:29 +00:00
|
|
|
|
|
|
|
register_notifier_fail:
|
|
|
|
destroy_workqueue(dsa_owq);
|
|
|
|
|
|
|
|
return rc;
|
net: Distributed Switch Architecture protocol support
Distributed Switch Architecture is a protocol for managing hardware
switch chips. It consists of a set of MII management registers and
commands to configure the switch, and an ethernet header format to
signal which of the ports of the switch a packet was received from
or is intended to be sent to.
The switches that this driver supports are typically embedded in
access points and routers, and a typical setup with a DSA switch
looks something like this:
+-----------+ +-----------+
| | RGMII | |
| +-------+ +------ 1000baseT MDI ("WAN")
| | | 6-port +------ 1000baseT MDI ("LAN1")
| CPU | | ethernet +------ 1000baseT MDI ("LAN2")
| |MIImgmt| switch +------ 1000baseT MDI ("LAN3")
| +-------+ w/5 PHYs +------ 1000baseT MDI ("LAN4")
| | | |
+-----------+ +-----------+
The switch driver presents each port on the switch as a separate
network interface to Linux, polls the switch to maintain software
link state of those ports, forwards MII management interface
accesses to those network interfaces (e.g. as done by ethtool) to
the switch, and exposes the switch's hardware statistics counters
via the appropriate Linux kernel interfaces.
This initial patch supports the MII management interface register
layout of the Marvell 88E6123, 88E6161 and 88E6165 switch chips, and
supports the "Ethertype DSA" packet tagging format.
(There is no officially registered ethertype for the Ethertype DSA
packet format, so we just grab a random one. The ethertype to use
is programmed into the switch, and the switch driver uses the value
of ETH_P_EDSA for this, so this define can be changed at any time in
the future if the one we chose is allocated to another protocol or
if Ethertype DSA gets its own officially registered ethertype, and
everything will continue to work.)
Signed-off-by: Lennert Buytenhek <buytenh@marvell.com>
Tested-by: Nicolas Pitre <nico@marvell.com>
Tested-by: Byron Bradley <byron.bbradley@gmail.com>
Tested-by: Tim Ellis <tim.ellis@mac.com>
Tested-by: Peter van Valderen <linux@ddcrew.com>
Tested-by: Dirk Teurlings <dirk@upexia.nl>
Signed-off-by: David S. Miller <davem@davemloft.net>
2008-10-07 13:44:02 +00:00
|
|
|
}
|
|
|
|
module_init(dsa_init_module);
|
|
|
|
|
|
|
|
static void __exit dsa_cleanup_module(void)
|
|
|
|
{
|
2019-04-28 17:37:17 +00:00
|
|
|
dsa_tag_driver_unregister(&DSA_TAG_DRIVER_NAME(none_ops));
|
|
|
|
|
2017-02-03 18:20:16 +00:00
|
|
|
dsa_slave_unregister_notifier();
|
2014-08-28 00:04:46 +00:00
|
|
|
dev_remove_pack(&dsa_pack_type);
|
2017-08-06 13:15:42 +00:00
|
|
|
destroy_workqueue(dsa_owq);
|
net: Distributed Switch Architecture protocol support
Distributed Switch Architecture is a protocol for managing hardware
switch chips. It consists of a set of MII management registers and
commands to configure the switch, and an ethernet header format to
signal which of the ports of the switch a packet was received from
or is intended to be sent to.
The switches that this driver supports are typically embedded in
access points and routers, and a typical setup with a DSA switch
looks something like this:
+-----------+ +-----------+
| | RGMII | |
| +-------+ +------ 1000baseT MDI ("WAN")
| | | 6-port +------ 1000baseT MDI ("LAN1")
| CPU | | ethernet +------ 1000baseT MDI ("LAN2")
| |MIImgmt| switch +------ 1000baseT MDI ("LAN3")
| +-------+ w/5 PHYs +------ 1000baseT MDI ("LAN4")
| | | |
+-----------+ +-----------+
The switch driver presents each port on the switch as a separate
network interface to Linux, polls the switch to maintain software
link state of those ports, forwards MII management interface
accesses to those network interfaces (e.g. as done by ethtool) to
the switch, and exposes the switch's hardware statistics counters
via the appropriate Linux kernel interfaces.
This initial patch supports the MII management interface register
layout of the Marvell 88E6123, 88E6161 and 88E6165 switch chips, and
supports the "Ethertype DSA" packet tagging format.
(There is no officially registered ethertype for the Ethertype DSA
packet format, so we just grab a random one. The ethertype to use
is programmed into the switch, and the switch driver uses the value
of ETH_P_EDSA for this, so this define can be changed at any time in
the future if the one we chose is allocated to another protocol or
if Ethertype DSA gets its own officially registered ethertype, and
everything will continue to work.)
Signed-off-by: Lennert Buytenhek <buytenh@marvell.com>
Tested-by: Nicolas Pitre <nico@marvell.com>
Tested-by: Byron Bradley <byron.bbradley@gmail.com>
Tested-by: Tim Ellis <tim.ellis@mac.com>
Tested-by: Peter van Valderen <linux@ddcrew.com>
Tested-by: Dirk Teurlings <dirk@upexia.nl>
Signed-off-by: David S. Miller <davem@davemloft.net>
2008-10-07 13:44:02 +00:00
|
|
|
}
|
|
|
|
module_exit(dsa_cleanup_module);
|
|
|
|
|
2011-01-24 20:32:52 +00:00
|
|
|
MODULE_AUTHOR("Lennert Buytenhek <buytenh@wantstofly.org>");
|
net: Distributed Switch Architecture protocol support
Distributed Switch Architecture is a protocol for managing hardware
switch chips. It consists of a set of MII management registers and
commands to configure the switch, and an ethernet header format to
signal which of the ports of the switch a packet was received from
or is intended to be sent to.
The switches that this driver supports are typically embedded in
access points and routers, and a typical setup with a DSA switch
looks something like this:
+-----------+ +-----------+
| | RGMII | |
| +-------+ +------ 1000baseT MDI ("WAN")
| | | 6-port +------ 1000baseT MDI ("LAN1")
| CPU | | ethernet +------ 1000baseT MDI ("LAN2")
| |MIImgmt| switch +------ 1000baseT MDI ("LAN3")
| +-------+ w/5 PHYs +------ 1000baseT MDI ("LAN4")
| | | |
+-----------+ +-----------+
The switch driver presents each port on the switch as a separate
network interface to Linux, polls the switch to maintain software
link state of those ports, forwards MII management interface
accesses to those network interfaces (e.g. as done by ethtool) to
the switch, and exposes the switch's hardware statistics counters
via the appropriate Linux kernel interfaces.
This initial patch supports the MII management interface register
layout of the Marvell 88E6123, 88E6161 and 88E6165 switch chips, and
supports the "Ethertype DSA" packet tagging format.
(There is no officially registered ethertype for the Ethertype DSA
packet format, so we just grab a random one. The ethertype to use
is programmed into the switch, and the switch driver uses the value
of ETH_P_EDSA for this, so this define can be changed at any time in
the future if the one we chose is allocated to another protocol or
if Ethertype DSA gets its own officially registered ethertype, and
everything will continue to work.)
Signed-off-by: Lennert Buytenhek <buytenh@marvell.com>
Tested-by: Nicolas Pitre <nico@marvell.com>
Tested-by: Byron Bradley <byron.bbradley@gmail.com>
Tested-by: Tim Ellis <tim.ellis@mac.com>
Tested-by: Peter van Valderen <linux@ddcrew.com>
Tested-by: Dirk Teurlings <dirk@upexia.nl>
Signed-off-by: David S. Miller <davem@davemloft.net>
2008-10-07 13:44:02 +00:00
|
|
|
MODULE_DESCRIPTION("Driver for Distributed Switch Architecture switch chips");
|
|
|
|
MODULE_LICENSE("GPL");
|
|
|
|
MODULE_ALIAS("platform:dsa");
|