aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLennert Buytenhek <buytenh@wantstofly.org>2009-03-20 05:52:09 -0400
committerDavid S. Miller <davem@davemloft.net>2009-03-21 22:06:54 -0400
commite84665c9cb4db963393fafad6fefe5efdd7e4a09 (patch)
tree545c4a2a63a77b853e3f34609d86b346fe61baf4
parent076d3e10a54caa2c148de5732c126c7a31381d48 (diff)
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>
-rw-r--r--arch/arm/mach-kirkwood/common.c5
-rw-r--r--arch/arm/mach-kirkwood/rd88f6281-setup.c13
-rw-r--r--arch/arm/mach-orion5x/common.c5
-rw-r--r--arch/arm/mach-orion5x/rd88f5181l-fxo-setup.c9
-rw-r--r--arch/arm/mach-orion5x/rd88f5181l-ge-setup.c10
-rw-r--r--arch/arm/mach-orion5x/rd88f6183ap-ge-setup.c10
-rw-r--r--arch/arm/mach-orion5x/wrt350n-v2-setup.c9
-rw-r--r--include/net/dsa.h42
-rw-r--r--net/dsa/dsa.c177
-rw-r--r--net/dsa/dsa_priv.h97
-rw-r--r--net/dsa/mv88e6060.c12
-rw-r--r--net/dsa/mv88e6123_61_65.c92
-rw-r--r--net/dsa/mv88e6131.c78
-rw-r--r--net/dsa/slave.c25
-rw-r--r--net/dsa/tag_dsa.c30
-rw-r--r--net/dsa/tag_edsa.c30
-rw-r--r--net/dsa/tag_trailer.c10
17 files changed, 443 insertions, 211 deletions
diff --git a/arch/arm/mach-kirkwood/common.c b/arch/arm/mach-kirkwood/common.c
index b3404b7775b3..0d2074f51a59 100644
--- a/arch/arm/mach-kirkwood/common.c
+++ b/arch/arm/mach-kirkwood/common.c
@@ -231,14 +231,17 @@ static struct platform_device kirkwood_switch_device = {
231 231
232void __init kirkwood_ge00_switch_init(struct dsa_platform_data *d, int irq) 232void __init kirkwood_ge00_switch_init(struct dsa_platform_data *d, int irq)
233{ 233{
234 int i;
235
234 if (irq != NO_IRQ) { 236 if (irq != NO_IRQ) {
235 kirkwood_switch_resources[0].start = irq; 237 kirkwood_switch_resources[0].start = irq;
236 kirkwood_switch_resources[0].end = irq; 238 kirkwood_switch_resources[0].end = irq;
237 kirkwood_switch_device.num_resources = 1; 239 kirkwood_switch_device.num_resources = 1;
238 } 240 }
239 241
240 d->mii_bus = &kirkwood_ge00_shared.dev;
241 d->netdev = &kirkwood_ge00.dev; 242 d->netdev = &kirkwood_ge00.dev;
243 for (i = 0; i < d->nr_chips; i++)
244 d->chip[i].mii_bus = &kirkwood_ge00_shared.dev;
242 kirkwood_switch_device.dev.platform_data = d; 245 kirkwood_switch_device.dev.platform_data = d;
243 246
244 platform_device_register(&kirkwood_switch_device); 247 platform_device_register(&kirkwood_switch_device);
diff --git a/arch/arm/mach-kirkwood/rd88f6281-setup.c b/arch/arm/mach-kirkwood/rd88f6281-setup.c
index 9a0e905d10cd..e1c0516c4df3 100644
--- a/arch/arm/mach-kirkwood/rd88f6281-setup.c
+++ b/arch/arm/mach-kirkwood/rd88f6281-setup.c
@@ -75,7 +75,7 @@ static struct mv643xx_eth_platform_data rd88f6281_ge00_data = {
75 .duplex = DUPLEX_FULL, 75 .duplex = DUPLEX_FULL,
76}; 76};
77 77
78static struct dsa_platform_data rd88f6281_switch_data = { 78static struct dsa_chip_data rd88f6281_switch_chip_data = {
79 .port_names[0] = "lan1", 79 .port_names[0] = "lan1",
80 .port_names[1] = "lan2", 80 .port_names[1] = "lan2",
81 .port_names[2] = "lan3", 81 .port_names[2] = "lan3",
@@ -83,6 +83,11 @@ static struct dsa_platform_data rd88f6281_switch_data = {
83 .port_names[5] = "cpu", 83 .port_names[5] = "cpu",
84}; 84};
85 85
86static struct dsa_platform_data rd88f6281_switch_plat_data = {
87 .nr_chips = 1,
88 .chip = &rd88f6281_switch_chip_data,
89};
90
86static struct mv643xx_eth_platform_data rd88f6281_ge01_data = { 91static struct mv643xx_eth_platform_data rd88f6281_ge01_data = {
87 .phy_addr = MV643XX_ETH_PHY_ADDR(11), 92 .phy_addr = MV643XX_ETH_PHY_ADDR(11),
88}; 93};
@@ -105,12 +110,12 @@ static void __init rd88f6281_init(void)
105 kirkwood_ge00_init(&rd88f6281_ge00_data); 110 kirkwood_ge00_init(&rd88f6281_ge00_data);
106 kirkwood_pcie_id(&dev, &rev); 111 kirkwood_pcie_id(&dev, &rev);
107 if (rev == MV88F6281_REV_A0) { 112 if (rev == MV88F6281_REV_A0) {
108 rd88f6281_switch_data.sw_addr = 10; 113 rd88f6281_switch_chip_data.sw_addr = 10;
109 kirkwood_ge01_init(&rd88f6281_ge01_data); 114 kirkwood_ge01_init(&rd88f6281_ge01_data);
110 } else { 115 } else {
111 rd88f6281_switch_data.port_names[4] = "wan"; 116 rd88f6281_switch_chip_data.port_names[4] = "wan";
112 } 117 }
113 kirkwood_ge00_switch_init(&rd88f6281_switch_data, NO_IRQ); 118 kirkwood_ge00_switch_init(&rd88f6281_switch_plat_data, NO_IRQ);
114 119
115 kirkwood_rtc_init(); 120 kirkwood_rtc_init();
116 kirkwood_sata_init(&rd88f6281_sata_data); 121 kirkwood_sata_init(&rd88f6281_sata_data);
diff --git a/arch/arm/mach-orion5x/common.c b/arch/arm/mach-orion5x/common.c
index 0a623379789f..a4ecf625981e 100644
--- a/arch/arm/mach-orion5x/common.c
+++ b/arch/arm/mach-orion5x/common.c
@@ -219,14 +219,17 @@ static struct platform_device orion5x_switch_device = {
219 219
220void __init orion5x_eth_switch_init(struct dsa_platform_data *d, int irq) 220void __init orion5x_eth_switch_init(struct dsa_platform_data *d, int irq)
221{ 221{
222 int i;
223
222 if (irq != NO_IRQ) { 224 if (irq != NO_IRQ) {
223 orion5x_switch_resources[0].start = irq; 225 orion5x_switch_resources[0].start = irq;
224 orion5x_switch_resources[0].end = irq; 226 orion5x_switch_resources[0].end = irq;
225 orion5x_switch_device.num_resources = 1; 227 orion5x_switch_device.num_resources = 1;
226 } 228 }
227 229
228 d->mii_bus = &orion5x_eth_shared.dev;
229 d->netdev = &orion5x_eth.dev; 230 d->netdev = &orion5x_eth.dev;
231 for (i = 0; i < d->nr_chips; i++)
232 d->chip[i].mii_bus = &orion5x_eth_shared.dev;
230 orion5x_switch_device.dev.platform_data = d; 233 orion5x_switch_device.dev.platform_data = d;
231 234
232 platform_device_register(&orion5x_switch_device); 235 platform_device_register(&orion5x_switch_device);
diff --git a/arch/arm/mach-orion5x/rd88f5181l-fxo-setup.c b/arch/arm/mach-orion5x/rd88f5181l-fxo-setup.c
index 15f53235ee30..9c1ca41730ba 100644
--- a/arch/arm/mach-orion5x/rd88f5181l-fxo-setup.c
+++ b/arch/arm/mach-orion5x/rd88f5181l-fxo-setup.c
@@ -94,7 +94,7 @@ static struct mv643xx_eth_platform_data rd88f5181l_fxo_eth_data = {
94 .duplex = DUPLEX_FULL, 94 .duplex = DUPLEX_FULL,
95}; 95};
96 96
97static struct dsa_platform_data rd88f5181l_fxo_switch_data = { 97static struct dsa_chip_data rd88f5181l_fxo_switch_chip_data = {
98 .port_names[0] = "lan2", 98 .port_names[0] = "lan2",
99 .port_names[1] = "lan1", 99 .port_names[1] = "lan1",
100 .port_names[2] = "wan", 100 .port_names[2] = "wan",
@@ -103,6 +103,11 @@ static struct dsa_platform_data rd88f5181l_fxo_switch_data = {
103 .port_names[7] = "lan3", 103 .port_names[7] = "lan3",
104}; 104};
105 105
106static struct dsa_platform_data rd88f5181l_fxo_switch_plat_data = {
107 .nr_chips = 1,
108 .chip = &rd88f5181l_fxo_switch_chip_data,
109};
110
106static void __init rd88f5181l_fxo_init(void) 111static void __init rd88f5181l_fxo_init(void)
107{ 112{
108 /* 113 /*
@@ -117,7 +122,7 @@ static void __init rd88f5181l_fxo_init(void)
117 */ 122 */
118 orion5x_ehci0_init(); 123 orion5x_ehci0_init();
119 orion5x_eth_init(&rd88f5181l_fxo_eth_data); 124 orion5x_eth_init(&rd88f5181l_fxo_eth_data);
120 orion5x_eth_switch_init(&rd88f5181l_fxo_switch_data, NO_IRQ); 125 orion5x_eth_switch_init(&rd88f5181l_fxo_switch_plat_data, NO_IRQ);
121 orion5x_uart0_init(); 126 orion5x_uart0_init();
122 127
123 orion5x_setup_dev_boot_win(RD88F5181L_FXO_NOR_BOOT_BASE, 128 orion5x_setup_dev_boot_win(RD88F5181L_FXO_NOR_BOOT_BASE,
diff --git a/arch/arm/mach-orion5x/rd88f5181l-ge-setup.c b/arch/arm/mach-orion5x/rd88f5181l-ge-setup.c
index 8ad3934399d4..ee1399ff0ced 100644
--- a/arch/arm/mach-orion5x/rd88f5181l-ge-setup.c
+++ b/arch/arm/mach-orion5x/rd88f5181l-ge-setup.c
@@ -95,7 +95,7 @@ static struct mv643xx_eth_platform_data rd88f5181l_ge_eth_data = {
95 .duplex = DUPLEX_FULL, 95 .duplex = DUPLEX_FULL,
96}; 96};
97 97
98static struct dsa_platform_data rd88f5181l_ge_switch_data = { 98static struct dsa_chip_data rd88f5181l_ge_switch_chip_data = {
99 .port_names[0] = "lan2", 99 .port_names[0] = "lan2",
100 .port_names[1] = "lan1", 100 .port_names[1] = "lan1",
101 .port_names[2] = "wan", 101 .port_names[2] = "wan",
@@ -104,6 +104,11 @@ static struct dsa_platform_data rd88f5181l_ge_switch_data = {
104 .port_names[7] = "lan3", 104 .port_names[7] = "lan3",
105}; 105};
106 106
107static struct dsa_platform_data rd88f5181l_ge_switch_plat_data = {
108 .nr_chips = 1,
109 .chip = &rd88f5181l_ge_switch_chip_data,
110};
111
107static struct i2c_board_info __initdata rd88f5181l_ge_i2c_rtc = { 112static struct i2c_board_info __initdata rd88f5181l_ge_i2c_rtc = {
108 I2C_BOARD_INFO("ds1338", 0x68), 113 I2C_BOARD_INFO("ds1338", 0x68),
109}; 114};
@@ -122,7 +127,8 @@ static void __init rd88f5181l_ge_init(void)
122 */ 127 */
123 orion5x_ehci0_init(); 128 orion5x_ehci0_init();
124 orion5x_eth_init(&rd88f5181l_ge_eth_data); 129 orion5x_eth_init(&rd88f5181l_ge_eth_data);
125 orion5x_eth_switch_init(&rd88f5181l_ge_switch_data, gpio_to_irq(8)); 130 orion5x_eth_switch_init(&rd88f5181l_ge_switch_plat_data,
131 gpio_to_irq(8));
126 orion5x_i2c_init(); 132 orion5x_i2c_init();
127 orion5x_uart0_init(); 133 orion5x_uart0_init();
128 134
diff --git a/arch/arm/mach-orion5x/rd88f6183ap-ge-setup.c b/arch/arm/mach-orion5x/rd88f6183ap-ge-setup.c
index 262e25e4dace..7737cf9a8f50 100644
--- a/arch/arm/mach-orion5x/rd88f6183ap-ge-setup.c
+++ b/arch/arm/mach-orion5x/rd88f6183ap-ge-setup.c
@@ -35,7 +35,7 @@ static struct mv643xx_eth_platform_data rd88f6183ap_ge_eth_data = {
35 .duplex = DUPLEX_FULL, 35 .duplex = DUPLEX_FULL,
36}; 36};
37 37
38static struct dsa_platform_data rd88f6183ap_ge_switch_data = { 38static struct dsa_chip_data rd88f6183ap_ge_switch_chip_data = {
39 .port_names[0] = "lan1", 39 .port_names[0] = "lan1",
40 .port_names[1] = "lan2", 40 .port_names[1] = "lan2",
41 .port_names[2] = "lan3", 41 .port_names[2] = "lan3",
@@ -44,6 +44,11 @@ static struct dsa_platform_data rd88f6183ap_ge_switch_data = {
44 .port_names[5] = "cpu", 44 .port_names[5] = "cpu",
45}; 45};
46 46
47static struct dsa_platform_data rd88f6183ap_ge_switch_plat_data = {
48 .nr_chips = 1,
49 .chip = &rd88f6183ap_ge_switch_chip_data,
50};
51
47static struct mtd_partition rd88f6183ap_ge_partitions[] = { 52static struct mtd_partition rd88f6183ap_ge_partitions[] = {
48 { 53 {
49 .name = "kernel", 54 .name = "kernel",
@@ -89,7 +94,8 @@ static void __init rd88f6183ap_ge_init(void)
89 */ 94 */
90 orion5x_ehci0_init(); 95 orion5x_ehci0_init();
91 orion5x_eth_init(&rd88f6183ap_ge_eth_data); 96 orion5x_eth_init(&rd88f6183ap_ge_eth_data);
92 orion5x_eth_switch_init(&rd88f6183ap_ge_switch_data, gpio_to_irq(3)); 97 orion5x_eth_switch_init(&rd88f6183ap_ge_switch_plat_data,
98 gpio_to_irq(3));
93 spi_register_board_info(rd88f6183ap_ge_spi_slave_info, 99 spi_register_board_info(rd88f6183ap_ge_spi_slave_info,
94 ARRAY_SIZE(rd88f6183ap_ge_spi_slave_info)); 100 ARRAY_SIZE(rd88f6183ap_ge_spi_slave_info));
95 orion5x_spi_init(); 101 orion5x_spi_init();
diff --git a/arch/arm/mach-orion5x/wrt350n-v2-setup.c b/arch/arm/mach-orion5x/wrt350n-v2-setup.c
index cc8f89200865..1b4ad9d5e2eb 100644
--- a/arch/arm/mach-orion5x/wrt350n-v2-setup.c
+++ b/arch/arm/mach-orion5x/wrt350n-v2-setup.c
@@ -106,7 +106,7 @@ static struct mv643xx_eth_platform_data wrt350n_v2_eth_data = {
106 .duplex = DUPLEX_FULL, 106 .duplex = DUPLEX_FULL,
107}; 107};
108 108
109static struct dsa_platform_data wrt350n_v2_switch_data = { 109static struct dsa_chip_data wrt350n_v2_switch_chip_data = {
110 .port_names[0] = "lan2", 110 .port_names[0] = "lan2",
111 .port_names[1] = "lan1", 111 .port_names[1] = "lan1",
112 .port_names[2] = "wan", 112 .port_names[2] = "wan",
@@ -115,6 +115,11 @@ static struct dsa_platform_data wrt350n_v2_switch_data = {
115 .port_names[7] = "lan4", 115 .port_names[7] = "lan4",
116}; 116};
117 117
118static struct dsa_platform_data wrt350n_v2_switch_plat_data = {
119 .nr_chips = 1,
120 .chip = &wrt350n_v2_switch_chip_data,
121};
122
118static void __init wrt350n_v2_init(void) 123static void __init wrt350n_v2_init(void)
119{ 124{
120 /* 125 /*
@@ -129,7 +134,7 @@ static void __init wrt350n_v2_init(void)
129 */ 134 */
130 orion5x_ehci0_init(); 135 orion5x_ehci0_init();
131 orion5x_eth_init(&wrt350n_v2_eth_data); 136 orion5x_eth_init(&wrt350n_v2_eth_data);
132 orion5x_eth_switch_init(&wrt350n_v2_switch_data, NO_IRQ); 137 orion5x_eth_switch_init(&wrt350n_v2_switch_plat_data, NO_IRQ);
133 orion5x_uart0_init(); 138 orion5x_uart0_init();
134 139
135 orion5x_setup_dev_boot_win(WRT350N_V2_NOR_BOOT_BASE, 140 orion5x_setup_dev_boot_win(WRT350N_V2_NOR_BOOT_BASE,
diff --git a/include/net/dsa.h b/include/net/dsa.h
index 52e97bfca5a1..839f768f9e35 100644
--- a/include/net/dsa.h
+++ b/include/net/dsa.h
@@ -1,6 +1,6 @@
1/* 1/*
2 * include/net/dsa.h - Driver for Distributed Switch Architecture switch chips 2 * include/net/dsa.h - Driver for Distributed Switch Architecture switch chips
3 * Copyright (c) 2008 Marvell Semiconductor 3 * Copyright (c) 2008-2009 Marvell Semiconductor
4 * 4 *
5 * This program is free software; you can redistribute it and/or modify 5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by 6 * it under the terms of the GNU General Public License as published by
@@ -11,23 +11,47 @@
11#ifndef __LINUX_NET_DSA_H 11#ifndef __LINUX_NET_DSA_H
12#define __LINUX_NET_DSA_H 12#define __LINUX_NET_DSA_H
13 13
14#define DSA_MAX_PORTS 12 14#define DSA_MAX_SWITCHES 4
15#define DSA_MAX_PORTS 12
16
17struct dsa_chip_data {
18 /*
19 * How to access the switch configuration registers.
20 */
21 struct device *mii_bus;
22 int sw_addr;
23
24 /*
25 * The names of the switch's ports. Use "cpu" to
26 * designate the switch port that the cpu is connected to,
27 * "dsa" to indicate that this port is a DSA link to
28 * another switch, NULL to indicate the port is unused,
29 * or any other string to indicate this is a physical port.
30 */
31 char *port_names[DSA_MAX_PORTS];
32
33 /*
34 * An array (with nr_chips elements) of which element [a]
35 * indicates which port on this switch should be used to
36 * send packets to that are destined for switch a. Can be
37 * NULL if there is only one switch chip.
38 */
39 s8 *rtable;
40};
15 41
16struct dsa_platform_data { 42struct dsa_platform_data {
17 /* 43 /*
18 * Reference to a Linux network interface that connects 44 * Reference to a Linux network interface that connects
19 * to the switch chip. 45 * to the root switch chip of the tree.
20 */ 46 */
21 struct device *netdev; 47 struct device *netdev;
22 48
23 /* 49 /*
24 * How to access the switch configuration registers, and 50 * Info structs describing each of the switch chips
25 * the names of the switch ports (use "cpu" to designate 51 * connected via this network interface.
26 * the switch port that the cpu is connected to).
27 */ 52 */
28 struct device *mii_bus; 53 int nr_chips;
29 int sw_addr; 54 struct dsa_chip_data *chip;
30 char *port_names[DSA_MAX_PORTS];
31}; 55};
32 56
33extern bool dsa_uses_dsa_tags(void *dsa_ptr); 57extern bool dsa_uses_dsa_tags(void *dsa_ptr);
diff --git a/net/dsa/dsa.c b/net/dsa/dsa.c
index 33e99462023a..71489f69a42c 100644
--- a/net/dsa/dsa.c
+++ b/net/dsa/dsa.c
@@ -1,6 +1,6 @@
1/* 1/*
2 * net/dsa/dsa.c - Hardware switch handling 2 * net/dsa/dsa.c - Hardware switch handling
3 * Copyright (c) 2008 Marvell Semiconductor 3 * Copyright (c) 2008-2009 Marvell Semiconductor
4 * 4 *
5 * This program is free software; you can redistribute it and/or modify 5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by 6 * it under the terms of the GNU General Public License as published by
@@ -67,12 +67,13 @@ dsa_switch_probe(struct mii_bus *bus, int sw_addr, char **_name)
67 67
68/* basic switch operations **************************************************/ 68/* basic switch operations **************************************************/
69static struct dsa_switch * 69static struct dsa_switch *
70dsa_switch_setup(struct device *parent, struct dsa_platform_data *pd, 70dsa_switch_setup(struct dsa_switch_tree *dst, int index,
71 struct mii_bus *bus, struct net_device *dev) 71 struct device *parent, struct mii_bus *bus)
72{ 72{
73 struct dsa_chip_data *pd = dst->pd->chip + index;
74 struct dsa_switch_driver *drv;
73 struct dsa_switch *ds; 75 struct dsa_switch *ds;
74 int ret; 76 int ret;
75 struct dsa_switch_driver *drv;
76 char *name; 77 char *name;
77 int i; 78 int i;
78 79
@@ -81,11 +82,12 @@ dsa_switch_setup(struct device *parent, struct dsa_platform_data *pd,
81 */ 82 */
82 drv = dsa_switch_probe(bus, pd->sw_addr, &name); 83 drv = dsa_switch_probe(bus, pd->sw_addr, &name);
83 if (drv == NULL) { 84 if (drv == NULL) {
84 printk(KERN_ERR "%s: could not detect attached switch\n", 85 printk(KERN_ERR "%s[%d]: could not detect attached switch\n",
85 dev->name); 86 dst->master_netdev->name, index);
86 return ERR_PTR(-EINVAL); 87 return ERR_PTR(-EINVAL);
87 } 88 }
88 printk(KERN_INFO "%s: detected a %s switch\n", dev->name, name); 89 printk(KERN_INFO "%s[%d]: detected a %s switch\n",
90 dst->master_netdev->name, index, name);
89 91
90 92
91 /* 93 /*
@@ -95,18 +97,16 @@ dsa_switch_setup(struct device *parent, struct dsa_platform_data *pd,
95 if (ds == NULL) 97 if (ds == NULL)
96 return ERR_PTR(-ENOMEM); 98 return ERR_PTR(-ENOMEM);
97 99
98 ds->pd = pd; 100 ds->dst = dst;
99 ds->master_netdev = dev; 101 ds->index = index;
100 ds->master_mii_bus = bus; 102 ds->pd = dst->pd->chip + index;
101
102 ds->drv = drv; 103 ds->drv = drv;
103 ds->tag_protocol = drv->tag_protocol; 104 ds->master_mii_bus = bus;
104 105
105 106
106 /* 107 /*
107 * Validate supplied switch configuration. 108 * Validate supplied switch configuration.
108 */ 109 */
109 ds->cpu_port = -1;
110 for (i = 0; i < DSA_MAX_PORTS; i++) { 110 for (i = 0; i < DSA_MAX_PORTS; i++) {
111 char *name; 111 char *name;
112 112
@@ -115,32 +115,28 @@ dsa_switch_setup(struct device *parent, struct dsa_platform_data *pd,
115 continue; 115 continue;
116 116
117 if (!strcmp(name, "cpu")) { 117 if (!strcmp(name, "cpu")) {
118 if (ds->cpu_port != -1) { 118 if (dst->cpu_switch != -1) {
119 printk(KERN_ERR "multiple cpu ports?!\n"); 119 printk(KERN_ERR "multiple cpu ports?!\n");
120 ret = -EINVAL; 120 ret = -EINVAL;
121 goto out; 121 goto out;
122 } 122 }
123 ds->cpu_port = i; 123 dst->cpu_switch = index;
124 dst->cpu_port = i;
125 } else if (!strcmp(name, "dsa")) {
126 ds->dsa_port_mask |= 1 << i;
124 } else { 127 } else {
125 ds->valid_port_mask |= 1 << i; 128 ds->phys_port_mask |= 1 << i;
126 } 129 }
127 } 130 }
128 131
129 if (ds->cpu_port == -1) {
130 printk(KERN_ERR "no cpu port?!\n");
131 ret = -EINVAL;
132 goto out;
133 }
134
135 132
136 /* 133 /*
137 * If we use a tagging format that doesn't have an ethertype 134 * If the CPU connects to this switch, set the switch tree
138 * field, make sure that all packets from this point on get 135 * tagging protocol to the preferred tagging format of this
139 * sent to the tag format's receive function. (Which will 136 * switch.
140 * discard received packets until we set ds->ports[] below.)
141 */ 137 */
142 wmb(); 138 if (ds->dst->cpu_switch == index)
143 dev->dsa_ptr = (void *)ds; 139 ds->dst->tag_protocol = drv->tag_protocol;
144 140
145 141
146 /* 142 /*
@@ -150,7 +146,7 @@ dsa_switch_setup(struct device *parent, struct dsa_platform_data *pd,
150 if (ret < 0) 146 if (ret < 0)
151 goto out; 147 goto out;
152 148
153 ret = drv->set_addr(ds, dev->dev_addr); 149 ret = drv->set_addr(ds, dst->master_netdev->dev_addr);
154 if (ret < 0) 150 if (ret < 0)
155 goto out; 151 goto out;
156 152
@@ -169,18 +165,18 @@ dsa_switch_setup(struct device *parent, struct dsa_platform_data *pd,
169 /* 165 /*
170 * Create network devices for physical switch ports. 166 * Create network devices for physical switch ports.
171 */ 167 */
172 wmb();
173 for (i = 0; i < DSA_MAX_PORTS; i++) { 168 for (i = 0; i < DSA_MAX_PORTS; i++) {
174 struct net_device *slave_dev; 169 struct net_device *slave_dev;
175 170
176 if (!(ds->valid_port_mask & (1 << i))) 171 if (!(ds->phys_port_mask & (1 << i)))
177 continue; 172 continue;
178 173
179 slave_dev = dsa_slave_create(ds, parent, i, pd->port_names[i]); 174 slave_dev = dsa_slave_create(ds, parent, i, pd->port_names[i]);
180 if (slave_dev == NULL) { 175 if (slave_dev == NULL) {
181 printk(KERN_ERR "%s: can't create dsa slave " 176 printk(KERN_ERR "%s[%d]: can't create dsa "
182 "device for port %d(%s)\n", 177 "slave device for port %d(%s)\n",
183 dev->name, i, pd->port_names[i]); 178 dst->master_netdev->name,
179 index, i, pd->port_names[i]);
184 continue; 180 continue;
185 } 181 }
186 182
@@ -192,7 +188,6 @@ dsa_switch_setup(struct device *parent, struct dsa_platform_data *pd,
192out_free: 188out_free:
193 mdiobus_free(ds->slave_mii_bus); 189 mdiobus_free(ds->slave_mii_bus);
194out: 190out:
195 dev->dsa_ptr = NULL;
196 kfree(ds); 191 kfree(ds);
197 return ERR_PTR(ret); 192 return ERR_PTR(ret);
198} 193}
@@ -212,35 +207,42 @@ static void dsa_switch_destroy(struct dsa_switch *ds)
212 */ 207 */
213bool dsa_uses_dsa_tags(void *dsa_ptr) 208bool dsa_uses_dsa_tags(void *dsa_ptr)
214{ 209{
215 struct dsa_switch *ds = dsa_ptr; 210 struct dsa_switch_tree *dst = dsa_ptr;
216 211
217 return !!(ds->tag_protocol == htons(ETH_P_DSA)); 212 return !!(dst->tag_protocol == htons(ETH_P_DSA));
218} 213}
219 214
220bool dsa_uses_trailer_tags(void *dsa_ptr) 215bool dsa_uses_trailer_tags(void *dsa_ptr)
221{ 216{
222 struct dsa_switch *ds = dsa_ptr; 217 struct dsa_switch_tree *dst = dsa_ptr;
223 218
224 return !!(ds->tag_protocol == htons(ETH_P_TRAILER)); 219 return !!(dst->tag_protocol == htons(ETH_P_TRAILER));
225} 220}
226 221
227 222
228/* link polling *************************************************************/ 223/* link polling *************************************************************/
229static void dsa_link_poll_work(struct work_struct *ugly) 224static void dsa_link_poll_work(struct work_struct *ugly)
230{ 225{
231 struct dsa_switch *ds; 226 struct dsa_switch_tree *dst;
227 int i;
228
229 dst = container_of(ugly, struct dsa_switch_tree, link_poll_work);
232 230
233 ds = container_of(ugly, struct dsa_switch, link_poll_work); 231 for (i = 0; i < dst->pd->nr_chips; i++) {
232 struct dsa_switch *ds = dst->ds[i];
234 233
235 ds->drv->poll_link(ds); 234 if (ds != NULL && ds->drv->poll_link != NULL)
236 mod_timer(&ds->link_poll_timer, round_jiffies(jiffies + HZ)); 235 ds->drv->poll_link(ds);
236 }
237
238 mod_timer(&dst->link_poll_timer, round_jiffies(jiffies + HZ));
237} 239}
238 240
239static void dsa_link_poll_timer(unsigned long _ds) 241static void dsa_link_poll_timer(unsigned long _dst)
240{ 242{
241 struct dsa_switch *ds = (void *)_ds; 243 struct dsa_switch_tree *dst = (void *)_dst;
242 244
243 schedule_work(&ds->link_poll_work); 245 schedule_work(&dst->link_poll_work);
244} 246}
245 247
246 248
@@ -303,18 +305,14 @@ static int dsa_probe(struct platform_device *pdev)
303 static int dsa_version_printed; 305 static int dsa_version_printed;
304 struct dsa_platform_data *pd = pdev->dev.platform_data; 306 struct dsa_platform_data *pd = pdev->dev.platform_data;
305 struct net_device *dev; 307 struct net_device *dev;
306 struct mii_bus *bus; 308 struct dsa_switch_tree *dst;
307 struct dsa_switch *ds; 309 int i;
308 310
309 if (!dsa_version_printed++) 311 if (!dsa_version_printed++)
310 printk(KERN_NOTICE "Distributed Switch Architecture " 312 printk(KERN_NOTICE "Distributed Switch Architecture "
311 "driver version %s\n", dsa_driver_version); 313 "driver version %s\n", dsa_driver_version);
312 314
313 if (pd == NULL || pd->mii_bus == NULL || pd->netdev == NULL) 315 if (pd == NULL || pd->netdev == NULL)
314 return -EINVAL;
315
316 bus = dev_to_mii_bus(pd->mii_bus);
317 if (bus == NULL)
318 return -EINVAL; 316 return -EINVAL;
319 317
320 dev = dev_to_net_device(pd->netdev); 318 dev = dev_to_net_device(pd->netdev);
@@ -326,36 +324,79 @@ static int dsa_probe(struct platform_device *pdev)
326 return -EEXIST; 324 return -EEXIST;
327 } 325 }
328 326
329 ds = dsa_switch_setup(&pdev->dev, pd, bus, dev); 327 dst = kzalloc(sizeof(*dst), GFP_KERNEL);
330 if (IS_ERR(ds)) { 328 if (dst == NULL) {
331 dev_put(dev); 329 dev_put(dev);
332 return PTR_ERR(ds); 330 return -ENOMEM;
333 } 331 }
334 332
335 if (ds->drv->poll_link != NULL) { 333 platform_set_drvdata(pdev, dst);
336 INIT_WORK(&ds->link_poll_work, dsa_link_poll_work); 334
337 init_timer(&ds->link_poll_timer); 335 dst->pd = pd;
338 ds->link_poll_timer.data = (unsigned long)ds; 336 dst->master_netdev = dev;
339 ds->link_poll_timer.function = dsa_link_poll_timer; 337 dst->cpu_switch = -1;
340 ds->link_poll_timer.expires = round_jiffies(jiffies + HZ); 338 dst->cpu_port = -1;
341 add_timer(&ds->link_poll_timer); 339
340 for (i = 0; i < pd->nr_chips; i++) {
341 struct mii_bus *bus;
342 struct dsa_switch *ds;
343
344 bus = dev_to_mii_bus(pd->chip[i].mii_bus);
345 if (bus == NULL) {
346 printk(KERN_ERR "%s[%d]: no mii bus found for "
347 "dsa switch\n", dev->name, i);
348 continue;
349 }
350
351 ds = dsa_switch_setup(dst, i, &pdev->dev, bus);
352 if (IS_ERR(ds)) {
353 printk(KERN_ERR "%s[%d]: couldn't create dsa switch "
354 "instance (error %ld)\n", dev->name, i,
355 PTR_ERR(ds));
356 continue;
357 }
358
359 dst->ds[i] = ds;
360 if (ds->drv->poll_link != NULL)
361 dst->link_poll_needed = 1;
342 } 362 }
343 363
344 platform_set_drvdata(pdev, ds); 364 /*
365 * If we use a tagging format that doesn't have an ethertype
366 * field, make sure that all packets from this point on get
367 * sent to the tag format's receive function.
368 */
369 wmb();
370 dev->dsa_ptr = (void *)dst;
371
372 if (dst->link_poll_needed) {
373 INIT_WORK(&dst->link_poll_work, dsa_link_poll_work);
374 init_timer(&dst->link_poll_timer);
375 dst->link_poll_timer.data = (unsigned long)dst;
376 dst->link_poll_timer.function = dsa_link_poll_timer;
377 dst->link_poll_timer.expires = round_jiffies(jiffies + HZ);
378 add_timer(&dst->link_poll_timer);
379 }
345 380
346 return 0; 381 return 0;
347} 382}
348 383
349static int dsa_remove(struct platform_device *pdev) 384static int dsa_remove(struct platform_device *pdev)
350{ 385{
351 struct dsa_switch *ds = platform_get_drvdata(pdev); 386 struct dsa_switch_tree *dst = platform_get_drvdata(pdev);
387 int i;
352 388
353 if (ds->drv->poll_link != NULL) 389 if (dst->link_poll_needed)
354 del_timer_sync(&ds->link_poll_timer); 390 del_timer_sync(&dst->link_poll_timer);
355 391
356 flush_scheduled_work(); 392 flush_scheduled_work();
357 393
358 dsa_switch_destroy(ds); 394 for (i = 0; i < dst->pd->nr_chips; i++) {
395 struct dsa_switch *ds = dst->ds[i];
396
397 if (ds != NULL)
398 dsa_switch_destroy(ds);
399 }
359 400
360 return 0; 401 return 0;
361} 402}
diff --git a/net/dsa/dsa_priv.h b/net/dsa/dsa_priv.h
index 7063378a1ebf..41055f33d28a 100644
--- a/net/dsa/dsa_priv.h
+++ b/net/dsa/dsa_priv.h
@@ -1,6 +1,6 @@
1/* 1/*
2 * net/dsa/dsa_priv.h - Hardware switch handling 2 * net/dsa/dsa_priv.h - Hardware switch handling
3 * Copyright (c) 2008 Marvell Semiconductor 3 * Copyright (c) 2008-2009 Marvell Semiconductor
4 * 4 *
5 * This program is free software; you can redistribute it and/or modify 5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by 6 * it under the terms of the GNU General Public License as published by
@@ -19,42 +19,107 @@
19 19
20struct dsa_switch { 20struct dsa_switch {
21 /* 21 /*
22 * Configuration data for the platform device that owns 22 * Parent switch tree, and switch index.
23 * this dsa switch instance.
24 */ 23 */
25 struct dsa_platform_data *pd; 24 struct dsa_switch_tree *dst;
25 int index;
26 26
27 /* 27 /*
28 * References to network device and mii bus to use. 28 * Configuration data for this switch.
29 */ 29 */
30 struct net_device *master_netdev; 30 struct dsa_chip_data *pd;
31 struct mii_bus *master_mii_bus;
32 31
33 /* 32 /*
34 * The used switch driver and frame tagging type. 33 * The used switch driver.
35 */ 34 */
36 struct dsa_switch_driver *drv; 35 struct dsa_switch_driver *drv;
37 __be16 tag_protocol; 36
37 /*
38 * Reference to mii bus to use.
39 */
40 struct mii_bus *master_mii_bus;
38 41
39 /* 42 /*
40 * Slave mii_bus and devices for the individual ports. 43 * Slave mii_bus and devices for the individual ports.
41 */ 44 */
42 int cpu_port; 45 u32 dsa_port_mask;
43 u32 valid_port_mask; 46 u32 phys_port_mask;
44 struct mii_bus *slave_mii_bus; 47 struct mii_bus *slave_mii_bus;
45 struct net_device *ports[DSA_MAX_PORTS]; 48 struct net_device *ports[DSA_MAX_PORTS];
49};
50
51struct dsa_switch_tree {
52 /*
53 * Configuration data for the platform device that owns
54 * this dsa switch tree instance.
55 */
56 struct dsa_platform_data *pd;
57
58 /*
59 * Reference to network device to use, and which tagging
60 * protocol to use.
61 */
62 struct net_device *master_netdev;
63 __be16 tag_protocol;
64
65 /*
66 * The switch and port to which the CPU is attached.
67 */
68 s8 cpu_switch;
69 s8 cpu_port;
46 70
47 /* 71 /*
48 * Link state polling. 72 * Link state polling.
49 */ 73 */
50 struct work_struct link_poll_work; 74 int link_poll_needed;
51 struct timer_list link_poll_timer; 75 struct work_struct link_poll_work;
76 struct timer_list link_poll_timer;
77
78 /*
79 * Data for the individual switch chips.
80 */
81 struct dsa_switch *ds[DSA_MAX_SWITCHES];
52}; 82};
53 83
84static inline bool dsa_is_cpu_port(struct dsa_switch *ds, int p)
85{
86 return !!(ds->index == ds->dst->cpu_switch && p == ds->dst->cpu_port);
87}
88
89static inline u8 dsa_upstream_port(struct dsa_switch *ds)
90{
91 struct dsa_switch_tree *dst = ds->dst;
92
93 /*
94 * If this is the root switch (i.e. the switch that connects
95 * to the CPU), return the cpu port number on this switch.
96 * Else return the (DSA) port number that connects to the
97 * switch that is one hop closer to the cpu.
98 */
99 if (dst->cpu_switch == ds->index)
100 return dst->cpu_port;
101 else
102 return ds->pd->rtable[dst->cpu_switch];
103}
104
54struct dsa_slave_priv { 105struct dsa_slave_priv {
106 /*
107 * The linux network interface corresponding to this
108 * switch port.
109 */
55 struct net_device *dev; 110 struct net_device *dev;
111
112 /*
113 * Which switch this port is a part of, and the port index
114 * for this port.
115 */
56 struct dsa_switch *parent; 116 struct dsa_switch *parent;
57 int port; 117 u8 port;
118
119 /*
120 * The phylib phy_device pointer for the PHY connected
121 * to this port.
122 */
58 struct phy_device *phy; 123 struct phy_device *phy;
59}; 124};
60 125
diff --git a/net/dsa/mv88e6060.c b/net/dsa/mv88e6060.c
index 85081ae9fe89..83277f463af7 100644
--- a/net/dsa/mv88e6060.c
+++ b/net/dsa/mv88e6060.c
@@ -1,6 +1,6 @@
1/* 1/*
2 * net/dsa/mv88e6060.c - Driver for Marvell 88e6060 switch chips 2 * net/dsa/mv88e6060.c - Driver for Marvell 88e6060 switch chips
3 * Copyright (c) 2008 Marvell Semiconductor 3 * Copyright (c) 2008-2009 Marvell Semiconductor
4 * 4 *
5 * This program is free software; you can redistribute it and/or modify 5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by 6 * it under the terms of the GNU General Public License as published by
@@ -81,7 +81,7 @@ static int mv88e6060_switch_reset(struct dsa_switch *ds)
81 /* 81 /*
82 * Reset the switch. 82 * Reset the switch.
83 */ 83 */
84 REG_WRITE(REG_GLOBAL, 0x0A, 0xa130); 84 REG_WRITE(REG_GLOBAL, 0x0a, 0xa130);
85 85
86 /* 86 /*
87 * Wait up to one second for reset to complete. 87 * Wait up to one second for reset to complete.
@@ -128,7 +128,7 @@ static int mv88e6060_setup_port(struct dsa_switch *ds, int p)
128 * state to Forwarding. Additionally, if this is the CPU 128 * state to Forwarding. Additionally, if this is the CPU
129 * port, enable Ingress and Egress Trailer tagging mode. 129 * port, enable Ingress and Egress Trailer tagging mode.
130 */ 130 */
131 REG_WRITE(addr, 0x04, (p == ds->cpu_port) ? 0x4103 : 0x0003); 131 REG_WRITE(addr, 0x04, dsa_is_cpu_port(ds, p) ? 0x4103 : 0x0003);
132 132
133 /* 133 /*
134 * Port based VLAN map: give each port its own address 134 * Port based VLAN map: give each port its own address
@@ -138,9 +138,9 @@ static int mv88e6060_setup_port(struct dsa_switch *ds, int p)
138 */ 138 */
139 REG_WRITE(addr, 0x06, 139 REG_WRITE(addr, 0x06,
140 ((p & 0xf) << 12) | 140 ((p & 0xf) << 12) |
141 ((p == ds->cpu_port) ? 141 (dsa_is_cpu_port(ds, p) ?
142 ds->valid_port_mask : 142 ds->phys_port_mask :
143 (1 << ds->cpu_port))); 143 (1 << ds->dst->cpu_port)));
144 144
145 /* 145 /*
146 * Port Association Vector: when learning source addresses 146 * Port Association Vector: when learning source addresses
diff --git a/net/dsa/mv88e6123_61_65.c b/net/dsa/mv88e6123_61_65.c
index 100318722214..52faaa21a4d9 100644
--- a/net/dsa/mv88e6123_61_65.c
+++ b/net/dsa/mv88e6123_61_65.c
@@ -1,6 +1,6 @@
1/* 1/*
2 * net/dsa/mv88e6123_61_65.c - Marvell 88e6123/6161/6165 switch chip support 2 * net/dsa/mv88e6123_61_65.c - Marvell 88e6123/6161/6165 switch chip support
3 * Copyright (c) 2008 Marvell Semiconductor 3 * Copyright (c) 2008-2009 Marvell Semiconductor
4 * 4 *
5 * This program is free software; you can redistribute it and/or modify 5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by 6 * it under the terms of the GNU General Public License as published by
@@ -98,17 +98,17 @@ static int mv88e6123_61_65_setup_global(struct dsa_switch *ds)
98 return ret; 98 return ret;
99 99
100 /* 100 /*
101 * Configure the cpu port, and configure the cpu port as the 101 * Configure the upstream port, and configure the upstream
102 * port to which ingress and egress monitor frames are to be 102 * port as the port to which ingress and egress monitor frames
103 * sent. 103 * are to be sent.
104 */ 104 */
105 REG_WRITE(REG_GLOBAL, 0x1a, (ds->cpu_port * 0x1110)); 105 REG_WRITE(REG_GLOBAL, 0x1a, (dsa_upstream_port(ds) * 0x1110));
106 106
107 /* 107 /*
108 * Disable remote management for now, and set the switch's 108 * Disable remote management for now, and set the switch's
109 * DSA device number to zero. 109 * DSA device number.
110 */ 110 */
111 REG_WRITE(REG_GLOBAL, 0x1c, 0x0000); 111 REG_WRITE(REG_GLOBAL, 0x1c, ds->index & 0x1f);
112 112
113 /* 113 /*
114 * Send all frames with destination addresses matching 114 * Send all frames with destination addresses matching
@@ -133,10 +133,17 @@ static int mv88e6123_61_65_setup_global(struct dsa_switch *ds)
133 REG_WRITE(REG_GLOBAL2, 0x05, 0x00ff); 133 REG_WRITE(REG_GLOBAL2, 0x05, 0x00ff);
134 134
135 /* 135 /*
136 * Map all DSA device IDs to the CPU port. 136 * Program the DSA routing table.
137 */ 137 */
138 for (i = 0; i < 32; i++) 138 for (i = 0; i < 32; i++) {
139 REG_WRITE(REG_GLOBAL2, 0x06, 0x8000 | (i << 8) | ds->cpu_port); 139 int nexthop;
140
141 nexthop = 0x1f;
142 if (i != ds->index && i < ds->dst->pd->nr_chips)
143 nexthop = ds->pd->rtable[i] & 0x1f;
144
145 REG_WRITE(REG_GLOBAL2, 0x06, 0x8000 | (i << 8) | nexthop);
146 }
140 147
141 /* 148 /*
142 * Clear all trunk masks. 149 * Clear all trunk masks.
@@ -176,12 +183,18 @@ static int mv88e6123_61_65_setup_global(struct dsa_switch *ds)
176static int mv88e6123_61_65_setup_port(struct dsa_switch *ds, int p) 183static int mv88e6123_61_65_setup_port(struct dsa_switch *ds, int p)
177{ 184{
178 int addr = REG_PORT(p); 185 int addr = REG_PORT(p);
186 u16 val;
179 187
180 /* 188 /*
181 * MAC Forcing register: don't force link, speed, duplex 189 * MAC Forcing register: don't force link, speed, duplex
182 * or flow control state to any particular values. 190 * or flow control state to any particular values on physical
191 * ports, but force the CPU port and all DSA ports to 1000 Mb/s
192 * full duplex.
183 */ 193 */
184 REG_WRITE(addr, 0x01, 0x0003); 194 if (dsa_is_cpu_port(ds, p) || ds->dsa_port_mask & (1 << p))
195 REG_WRITE(addr, 0x01, 0x003e);
196 else
197 REG_WRITE(addr, 0x01, 0x0003);
185 198
186 /* 199 /*
187 * Do not limit the period of time that this port can be 200 * Do not limit the period of time that this port can be
@@ -192,37 +205,50 @@ static int mv88e6123_61_65_setup_port(struct dsa_switch *ds, int p)
192 205
193 /* 206 /*
194 * Port Control: disable Drop-on-Unlock, disable Drop-on-Lock, 207 * Port Control: disable Drop-on-Unlock, disable Drop-on-Lock,
195 * configure the requested (DSA/EDSA) tagging mode if this is 208 * disable Header mode, enable IGMP/MLD snooping, disable VLAN
196 * the CPU port, disable Header mode, enable IGMP/MLD snooping, 209 * tunneling, determine priority by looking at 802.1p and IP
197 * disable VLAN tunneling, determine priority by looking at 210 * priority fields (IP prio has precedence), and set STP state
198 * 802.1p and IP priority fields (IP prio has precedence), and 211 * to Forwarding.
199 * set STP state to Forwarding. Finally, if this is the CPU 212 *
200 * port, additionally enable forwarding of unknown unicast and 213 * If this is the CPU link, use DSA or EDSA tagging depending
201 * multicast addresses. 214 * on which tagging mode was configured.
202 */ 215 *
203 REG_WRITE(addr, 0x04, 216 * If this is a link to another switch, use DSA tagging mode.
204 (p == ds->cpu_port) ? 217 *
205 (ds->tag_protocol == htons(ETH_P_DSA)) ? 218 * If this is the upstream port for this switch, enable
206 0x053f : 0x373f : 219 * forwarding of unknown unicasts and multicasts.
207 0x0433); 220 */
221 val = 0x0433;
222 if (dsa_is_cpu_port(ds, p)) {
223 if (ds->dst->tag_protocol == htons(ETH_P_EDSA))
224 val |= 0x3300;
225 else
226 val |= 0x0100;
227 }
228 if (ds->dsa_port_mask & (1 << p))
229 val |= 0x0100;
230 if (p == dsa_upstream_port(ds))
231 val |= 0x000c;
232 REG_WRITE(addr, 0x04, val);
208 233
209 /* 234 /*
210 * Port Control 1: disable trunking. Also, if this is the 235 * Port Control 1: disable trunking. Also, if this is the
211 * CPU port, enable learn messages to be sent to this port. 236 * CPU port, enable learn messages to be sent to this port.
212 */ 237 */
213 REG_WRITE(addr, 0x05, (p == ds->cpu_port) ? 0x8000 : 0x0000); 238 REG_WRITE(addr, 0x05, dsa_is_cpu_port(ds, p) ? 0x8000 : 0x0000);
214 239
215 /* 240 /*
216 * Port based VLAN map: give each port its own address 241 * Port based VLAN map: give each port its own address
217 * database, allow the CPU port to talk to each of the 'real' 242 * database, allow the CPU port to talk to each of the 'real'
218 * ports, and allow each of the 'real' ports to only talk to 243 * ports, and allow each of the 'real' ports to only talk to
219 * the CPU port. 244 * the upstream port.
220 */ 245 */
221 REG_WRITE(addr, 0x06, 246 val = (p & 0xf) << 12;
222 ((p & 0xf) << 12) | 247 if (dsa_is_cpu_port(ds, p))
223 ((p == ds->cpu_port) ? 248 val |= ds->phys_port_mask;
224 ds->valid_port_mask : 249 else
225 (1 << ds->cpu_port))); 250 val |= 1 << dsa_upstream_port(ds);
251 REG_WRITE(addr, 0x06, val);
226 252
227 /* 253 /*
228 * Default VLAN ID and priority: don't set a default VLAN 254 * Default VLAN ID and priority: don't set a default VLAN
diff --git a/net/dsa/mv88e6131.c b/net/dsa/mv88e6131.c
index 002995721ecf..bb2b41bc854e 100644
--- a/net/dsa/mv88e6131.c
+++ b/net/dsa/mv88e6131.c
@@ -102,17 +102,17 @@ static int mv88e6131_setup_global(struct dsa_switch *ds)
102 REG_WRITE(REG_GLOBAL, 0x19, 0x8100); 102 REG_WRITE(REG_GLOBAL, 0x19, 0x8100);
103 103
104 /* 104 /*
105 * Disable ARP mirroring, and configure the cpu port as the 105 * Disable ARP mirroring, and configure the upstream port as
106 * port to which ingress and egress monitor frames are to be 106 * the port to which ingress and egress monitor frames are to
107 * sent. 107 * be sent.
108 */ 108 */
109 REG_WRITE(REG_GLOBAL, 0x1a, (ds->cpu_port * 0x1100) | 0x00f0); 109 REG_WRITE(REG_GLOBAL, 0x1a, (dsa_upstream_port(ds) * 0x1100) | 0x00f0);
110 110
111 /* 111 /*
112 * Disable cascade port functionality, and set the switch's 112 * Disable cascade port functionality, and set the switch's
113 * DSA device number to zero. 113 * DSA device number.
114 */ 114 */
115 REG_WRITE(REG_GLOBAL, 0x1c, 0xe000); 115 REG_WRITE(REG_GLOBAL, 0x1c, 0xe000 | (ds->index & 0x1f));
116 116
117 /* 117 /*
118 * Send all frames with destination addresses matching 118 * Send all frames with destination addresses matching
@@ -129,10 +129,17 @@ static int mv88e6131_setup_global(struct dsa_switch *ds)
129 REG_WRITE(REG_GLOBAL2, 0x05, 0x00ff); 129 REG_WRITE(REG_GLOBAL2, 0x05, 0x00ff);
130 130
131 /* 131 /*
132 * Map all DSA device IDs to the CPU port. 132 * Program the DSA routing table.
133 */ 133 */
134 for (i = 0; i < 32; i++) 134 for (i = 0; i < 32; i++) {
135 REG_WRITE(REG_GLOBAL2, 0x06, 0x8000 | (i << 8) | ds->cpu_port); 135 int nexthop;
136
137 nexthop = 0x1f;
138 if (i != ds->index && i < ds->dst->pd->nr_chips)
139 nexthop = ds->pd->rtable[i] & 0x1f;
140
141 REG_WRITE(REG_GLOBAL2, 0x06, 0x8000 | (i << 8) | nexthop);
142 }
136 143
137 /* 144 /*
138 * Clear all trunk masks. 145 * Clear all trunk masks.
@@ -158,13 +165,15 @@ static int mv88e6131_setup_global(struct dsa_switch *ds)
158static int mv88e6131_setup_port(struct dsa_switch *ds, int p) 165static int mv88e6131_setup_port(struct dsa_switch *ds, int p)
159{ 166{
160 int addr = REG_PORT(p); 167 int addr = REG_PORT(p);
168 u16 val;
161 169
162 /* 170 /*
163 * MAC Forcing register: don't force link, speed, duplex 171 * MAC Forcing register: don't force link, speed, duplex
164 * or flow control state to any particular values on physical 172 * or flow control state to any particular values on physical
165 * ports, but force the CPU port to 1000 Mb/s full duplex. 173 * ports, but force the CPU port and all DSA ports to 1000 Mb/s
174 * full duplex.
166 */ 175 */
167 if (p == ds->cpu_port) 176 if (dsa_is_cpu_port(ds, p) || ds->dsa_port_mask & (1 << p))
168 REG_WRITE(addr, 0x01, 0x003e); 177 REG_WRITE(addr, 0x01, 0x003e);
169 else 178 else
170 REG_WRITE(addr, 0x01, 0x0003); 179 REG_WRITE(addr, 0x01, 0x0003);
@@ -175,29 +184,40 @@ static int mv88e6131_setup_port(struct dsa_switch *ds, int p)
175 * enable IGMP/MLD snoop, disable DoubleTag, disable VLAN 184 * enable IGMP/MLD snoop, disable DoubleTag, disable VLAN
176 * tunneling, determine priority by looking at 802.1p and 185 * tunneling, determine priority by looking at 802.1p and
177 * IP priority fields (IP prio has precedence), and set STP 186 * IP priority fields (IP prio has precedence), and set STP
178 * state to Forwarding. Finally, if this is the CPU port, 187 * state to Forwarding.
179 * additionally enable DSA tagging and forwarding of unknown 188 *
180 * unicast addresses. 189 * If this is the upstream port for this switch, enable
190 * forwarding of unknown unicasts, and enable DSA tagging
191 * mode.
192 *
193 * If this is the link to another switch, use DSA tagging
194 * mode, but do not enable forwarding of unknown unicasts.
181 */ 195 */
182 REG_WRITE(addr, 0x04, (p == ds->cpu_port) ? 0x0537 : 0x0433); 196 val = 0x0433;
197 if (p == dsa_upstream_port(ds))
198 val |= 0x0104;
199 if (ds->dsa_port_mask & (1 << p))
200 val |= 0x0100;
201 REG_WRITE(addr, 0x04, val);
183 202
184 /* 203 /*
185 * Port Control 1: disable trunking. Also, if this is the 204 * Port Control 1: disable trunking. Also, if this is the
186 * CPU port, enable learn messages to be sent to this port. 205 * CPU port, enable learn messages to be sent to this port.
187 */ 206 */
188 REG_WRITE(addr, 0x05, (p == ds->cpu_port) ? 0x8000 : 0x0000); 207 REG_WRITE(addr, 0x05, dsa_is_cpu_port(ds, p) ? 0x8000 : 0x0000);
189 208
190 /* 209 /*
191 * Port based VLAN map: give each port its own address 210 * Port based VLAN map: give each port its own address
192 * database, allow the CPU port to talk to each of the 'real' 211 * database, allow the CPU port to talk to each of the 'real'
193 * ports, and allow each of the 'real' ports to only talk to 212 * ports, and allow each of the 'real' ports to only talk to
194 * the CPU port. 213 * the upstream port.
195 */ 214 */
196 REG_WRITE(addr, 0x06, 215 val = (p & 0xf) << 12;
197 ((p & 0xf) << 12) | 216 if (dsa_is_cpu_port(ds, p))
198 ((p == ds->cpu_port) ? 217 val |= ds->phys_port_mask;
199 ds->valid_port_mask : 218 else
200 (1 << ds->cpu_port))); 219 val |= 1 << dsa_upstream_port(ds);
220 REG_WRITE(addr, 0x06, val);
201 221
202 /* 222 /*
203 * Default VLAN ID and priority: don't set a default VLAN 223 * Default VLAN ID and priority: don't set a default VLAN
@@ -213,13 +233,15 @@ static int mv88e6131_setup_port(struct dsa_switch *ds, int p)
213 * untagged frames on this port, do a destination address 233 * untagged frames on this port, do a destination address
214 * lookup on received packets as usual, don't send a copy 234 * lookup on received packets as usual, don't send a copy
215 * of all transmitted/received frames on this port to the 235 * of all transmitted/received frames on this port to the
216 * CPU, and configure the CPU port number. Also, if this 236 * CPU, and configure the upstream port number.
217 * is the CPU port, enable forwarding of unknown multicast 237 *
218 * addresses. 238 * If this is the upstream port for this switch, enable
239 * forwarding of unknown multicast addresses.
219 */ 240 */
220 REG_WRITE(addr, 0x08, 241 val = 0x0080 | dsa_upstream_port(ds);
221 ((p == ds->cpu_port) ? 0x00c0 : 0x0080) | 242 if (p == dsa_upstream_port(ds))
222 ds->cpu_port); 243 val |= 0x0040;
244 REG_WRITE(addr, 0x08, val);
223 245
224 /* 246 /*
225 * Rate Control: disable ingress rate limiting. 247 * Rate Control: disable ingress rate limiting.
diff --git a/net/dsa/slave.c b/net/dsa/slave.c
index 99114e5b32e4..ed131181215d 100644
--- a/net/dsa/slave.c
+++ b/net/dsa/slave.c
@@ -1,6 +1,6 @@
1/* 1/*
2 * net/dsa/slave.c - Slave device handling 2 * net/dsa/slave.c - Slave device handling
3 * Copyright (c) 2008 Marvell Semiconductor 3 * Copyright (c) 2008-2009 Marvell Semiconductor
4 * 4 *
5 * This program is free software; you can redistribute it and/or modify 5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by 6 * it under the terms of the GNU General Public License as published by
@@ -19,7 +19,7 @@ static int dsa_slave_phy_read(struct mii_bus *bus, int addr, int reg)
19{ 19{
20 struct dsa_switch *ds = bus->priv; 20 struct dsa_switch *ds = bus->priv;
21 21
22 if (ds->valid_port_mask & (1 << addr)) 22 if (ds->phys_port_mask & (1 << addr))
23 return ds->drv->phy_read(ds, addr, reg); 23 return ds->drv->phy_read(ds, addr, reg);
24 24
25 return 0xffff; 25 return 0xffff;
@@ -29,7 +29,7 @@ static int dsa_slave_phy_write(struct mii_bus *bus, int addr, int reg, u16 val)
29{ 29{
30 struct dsa_switch *ds = bus->priv; 30 struct dsa_switch *ds = bus->priv;
31 31
32 if (ds->valid_port_mask & (1 << addr)) 32 if (ds->phys_port_mask & (1 << addr))
33 return ds->drv->phy_write(ds, addr, reg, val); 33 return ds->drv->phy_write(ds, addr, reg, val);
34 34
35 return 0; 35 return 0;
@@ -43,7 +43,7 @@ void dsa_slave_mii_bus_init(struct dsa_switch *ds)
43 ds->slave_mii_bus->write = dsa_slave_phy_write; 43 ds->slave_mii_bus->write = dsa_slave_phy_write;
44 snprintf(ds->slave_mii_bus->id, MII_BUS_ID_SIZE, "%s:%.2x", 44 snprintf(ds->slave_mii_bus->id, MII_BUS_ID_SIZE, "%s:%.2x",
45 ds->master_mii_bus->id, ds->pd->sw_addr); 45 ds->master_mii_bus->id, ds->pd->sw_addr);
46 ds->slave_mii_bus->parent = &(ds->master_mii_bus->dev); 46 ds->slave_mii_bus->parent = &ds->master_mii_bus->dev;
47} 47}
48 48
49 49
@@ -51,9 +51,8 @@ void dsa_slave_mii_bus_init(struct dsa_switch *ds)
51static int dsa_slave_init(struct net_device *dev) 51static int dsa_slave_init(struct net_device *dev)
52{ 52{
53 struct dsa_slave_priv *p = netdev_priv(dev); 53 struct dsa_slave_priv *p = netdev_priv(dev);
54 struct net_device *master = p->parent->master_netdev;
55 54
56 dev->iflink = master->ifindex; 55 dev->iflink = p->parent->dst->master_netdev->ifindex;
57 56
58 return 0; 57 return 0;
59} 58}
@@ -61,7 +60,7 @@ static int dsa_slave_init(struct net_device *dev)
61static int dsa_slave_open(struct net_device *dev) 60static int dsa_slave_open(struct net_device *dev)
62{ 61{
63 struct dsa_slave_priv *p = netdev_priv(dev); 62 struct dsa_slave_priv *p = netdev_priv(dev);
64 struct net_device *master = p->parent->master_netdev; 63 struct net_device *master = p->parent->dst->master_netdev;
65 int err; 64 int err;
66 65
67 if (!(master->flags & IFF_UP)) 66 if (!(master->flags & IFF_UP))
@@ -99,7 +98,7 @@ out:
99static int dsa_slave_close(struct net_device *dev) 98static int dsa_slave_close(struct net_device *dev)
100{ 99{
101 struct dsa_slave_priv *p = netdev_priv(dev); 100 struct dsa_slave_priv *p = netdev_priv(dev);
102 struct net_device *master = p->parent->master_netdev; 101 struct net_device *master = p->parent->dst->master_netdev;
103 102
104 dev_mc_unsync(master, dev); 103 dev_mc_unsync(master, dev);
105 dev_unicast_unsync(master, dev); 104 dev_unicast_unsync(master, dev);
@@ -117,7 +116,7 @@ static int dsa_slave_close(struct net_device *dev)
117static void dsa_slave_change_rx_flags(struct net_device *dev, int change) 116static void dsa_slave_change_rx_flags(struct net_device *dev, int change)
118{ 117{
119 struct dsa_slave_priv *p = netdev_priv(dev); 118 struct dsa_slave_priv *p = netdev_priv(dev);
120 struct net_device *master = p->parent->master_netdev; 119 struct net_device *master = p->parent->dst->master_netdev;
121 120
122 if (change & IFF_ALLMULTI) 121 if (change & IFF_ALLMULTI)
123 dev_set_allmulti(master, dev->flags & IFF_ALLMULTI ? 1 : -1); 122 dev_set_allmulti(master, dev->flags & IFF_ALLMULTI ? 1 : -1);
@@ -128,7 +127,7 @@ static void dsa_slave_change_rx_flags(struct net_device *dev, int change)
128static void dsa_slave_set_rx_mode(struct net_device *dev) 127static void dsa_slave_set_rx_mode(struct net_device *dev)
129{ 128{
130 struct dsa_slave_priv *p = netdev_priv(dev); 129 struct dsa_slave_priv *p = netdev_priv(dev);
131 struct net_device *master = p->parent->master_netdev; 130 struct net_device *master = p->parent->dst->master_netdev;
132 131
133 dev_mc_sync(master, dev); 132 dev_mc_sync(master, dev);
134 dev_unicast_sync(master, dev); 133 dev_unicast_sync(master, dev);
@@ -137,7 +136,7 @@ static void dsa_slave_set_rx_mode(struct net_device *dev)
137static int dsa_slave_set_mac_address(struct net_device *dev, void *a) 136static int dsa_slave_set_mac_address(struct net_device *dev, void *a)
138{ 137{
139 struct dsa_slave_priv *p = netdev_priv(dev); 138 struct dsa_slave_priv *p = netdev_priv(dev);
140 struct net_device *master = p->parent->master_netdev; 139 struct net_device *master = p->parent->dst->master_netdev;
141 struct sockaddr *addr = a; 140 struct sockaddr *addr = a;
142 int err; 141 int err;
143 142
@@ -341,7 +340,7 @@ struct net_device *
341dsa_slave_create(struct dsa_switch *ds, struct device *parent, 340dsa_slave_create(struct dsa_switch *ds, struct device *parent,
342 int port, char *name) 341 int port, char *name)
343{ 342{
344 struct net_device *master = ds->master_netdev; 343 struct net_device *master = ds->dst->master_netdev;
345 struct net_device *slave_dev; 344 struct net_device *slave_dev;
346 struct dsa_slave_priv *p; 345 struct dsa_slave_priv *p;
347 int ret; 346 int ret;
@@ -356,7 +355,7 @@ dsa_slave_create(struct dsa_switch *ds, struct device *parent,
356 memcpy(slave_dev->dev_addr, master->dev_addr, ETH_ALEN); 355 memcpy(slave_dev->dev_addr, master->dev_addr, ETH_ALEN);
357 slave_dev->tx_queue_len = 0; 356 slave_dev->tx_queue_len = 0;
358 357
359 switch (ds->tag_protocol) { 358 switch (ds->dst->tag_protocol) {
360#ifdef CONFIG_NET_DSA_TAG_DSA 359#ifdef CONFIG_NET_DSA_TAG_DSA
361 case htons(ETH_P_DSA): 360 case htons(ETH_P_DSA):
362 slave_dev->netdev_ops = &dsa_netdev_ops; 361 slave_dev->netdev_ops = &dsa_netdev_ops;
diff --git a/net/dsa/tag_dsa.c b/net/dsa/tag_dsa.c
index 0b8a91ddff44..8fa25bafe6ca 100644
--- a/net/dsa/tag_dsa.c
+++ b/net/dsa/tag_dsa.c
@@ -1,6 +1,6 @@
1/* 1/*
2 * net/dsa/tag_dsa.c - (Non-ethertype) DSA tagging 2 * net/dsa/tag_dsa.c - (Non-ethertype) DSA tagging
3 * Copyright (c) 2008 Marvell Semiconductor 3 * Copyright (c) 2008-2009 Marvell Semiconductor
4 * 4 *
5 * This program is free software; you can redistribute it and/or modify 5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by 6 * it under the terms of the GNU General Public License as published by
@@ -36,7 +36,7 @@ int dsa_xmit(struct sk_buff *skb, struct net_device *dev)
36 * Construct tagged FROM_CPU DSA tag from 802.1q tag. 36 * Construct tagged FROM_CPU DSA tag from 802.1q tag.
37 */ 37 */
38 dsa_header = skb->data + 2 * ETH_ALEN; 38 dsa_header = skb->data + 2 * ETH_ALEN;
39 dsa_header[0] = 0x60; 39 dsa_header[0] = 0x60 | p->parent->index;
40 dsa_header[1] = p->port << 3; 40 dsa_header[1] = p->port << 3;
41 41
42 /* 42 /*
@@ -57,7 +57,7 @@ int dsa_xmit(struct sk_buff *skb, struct net_device *dev)
57 * Construct untagged FROM_CPU DSA tag. 57 * Construct untagged FROM_CPU DSA tag.
58 */ 58 */
59 dsa_header = skb->data + 2 * ETH_ALEN; 59 dsa_header = skb->data + 2 * ETH_ALEN;
60 dsa_header[0] = 0x40; 60 dsa_header[0] = 0x40 | p->parent->index;
61 dsa_header[1] = p->port << 3; 61 dsa_header[1] = p->port << 3;
62 dsa_header[2] = 0x00; 62 dsa_header[2] = 0x00;
63 dsa_header[3] = 0x00; 63 dsa_header[3] = 0x00;
@@ -65,7 +65,7 @@ int dsa_xmit(struct sk_buff *skb, struct net_device *dev)
65 65
66 skb->protocol = htons(ETH_P_DSA); 66 skb->protocol = htons(ETH_P_DSA);
67 67
68 skb->dev = p->parent->master_netdev; 68 skb->dev = p->parent->dst->master_netdev;
69 dev_queue_xmit(skb); 69 dev_queue_xmit(skb);
70 70
71 return NETDEV_TX_OK; 71 return NETDEV_TX_OK;
@@ -78,11 +78,13 @@ out_free:
78static int dsa_rcv(struct sk_buff *skb, struct net_device *dev, 78static int dsa_rcv(struct sk_buff *skb, struct net_device *dev,
79 struct packet_type *pt, struct net_device *orig_dev) 79 struct packet_type *pt, struct net_device *orig_dev)
80{ 80{
81 struct dsa_switch *ds = dev->dsa_ptr; 81 struct dsa_switch_tree *dst = dev->dsa_ptr;
82 struct dsa_switch *ds;
82 u8 *dsa_header; 83 u8 *dsa_header;
84 int source_device;
83 int source_port; 85 int source_port;
84 86
85 if (unlikely(ds == NULL)) 87 if (unlikely(dst == NULL))
86 goto out_drop; 88 goto out_drop;
87 89
88 skb = skb_unshare(skb, GFP_ATOMIC); 90 skb = skb_unshare(skb, GFP_ATOMIC);
@@ -98,16 +100,24 @@ static int dsa_rcv(struct sk_buff *skb, struct net_device *dev,
98 dsa_header = skb->data - 2; 100 dsa_header = skb->data - 2;
99 101
100 /* 102 /*
101 * Check that frame type is either TO_CPU or FORWARD, and 103 * Check that frame type is either TO_CPU or FORWARD.
102 * that the source device is zero.
103 */ 104 */
104 if ((dsa_header[0] & 0xdf) != 0x00 && (dsa_header[0] & 0xdf) != 0xc0) 105 if ((dsa_header[0] & 0xc0) != 0x00 && (dsa_header[0] & 0xc0) != 0xc0)
105 goto out_drop; 106 goto out_drop;
106 107
107 /* 108 /*
108 * Check that the source port is a registered DSA port. 109 * Determine source device and port.
109 */ 110 */
111 source_device = dsa_header[0] & 0x1f;
110 source_port = (dsa_header[1] >> 3) & 0x1f; 112 source_port = (dsa_header[1] >> 3) & 0x1f;
113
114 /*
115 * Check that the source device exists and that the source
116 * port is a registered DSA port.
117 */
118 if (source_device >= dst->pd->nr_chips)
119 goto out_drop;
120 ds = dst->ds[source_device];
111 if (source_port >= DSA_MAX_PORTS || ds->ports[source_port] == NULL) 121 if (source_port >= DSA_MAX_PORTS || ds->ports[source_port] == NULL)
112 goto out_drop; 122 goto out_drop;
113 123
diff --git a/net/dsa/tag_edsa.c b/net/dsa/tag_edsa.c
index 16fcb6d196d4..815607bd286f 100644
--- a/net/dsa/tag_edsa.c
+++ b/net/dsa/tag_edsa.c
@@ -1,6 +1,6 @@
1/* 1/*
2 * net/dsa/tag_edsa.c - Ethertype DSA tagging 2 * net/dsa/tag_edsa.c - Ethertype DSA tagging
3 * Copyright (c) 2008 Marvell Semiconductor 3 * Copyright (c) 2008-2009 Marvell Semiconductor
4 * 4 *
5 * This program is free software; you can redistribute it and/or modify 5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by 6 * it under the terms of the GNU General Public License as published by
@@ -45,7 +45,7 @@ int edsa_xmit(struct sk_buff *skb, struct net_device *dev)
45 edsa_header[1] = ETH_P_EDSA & 0xff; 45 edsa_header[1] = ETH_P_EDSA & 0xff;
46 edsa_header[2] = 0x00; 46 edsa_header[2] = 0x00;
47 edsa_header[3] = 0x00; 47 edsa_header[3] = 0x00;
48 edsa_header[4] = 0x60; 48 edsa_header[4] = 0x60 | p->parent->index;
49 edsa_header[5] = p->port << 3; 49 edsa_header[5] = p->port << 3;
50 50
51 /* 51 /*
@@ -70,7 +70,7 @@ int edsa_xmit(struct sk_buff *skb, struct net_device *dev)
70 edsa_header[1] = ETH_P_EDSA & 0xff; 70 edsa_header[1] = ETH_P_EDSA & 0xff;
71 edsa_header[2] = 0x00; 71 edsa_header[2] = 0x00;
72 edsa_header[3] = 0x00; 72 edsa_header[3] = 0x00;
73 edsa_header[4] = 0x40; 73 edsa_header[4] = 0x40 | p->parent->index;
74 edsa_header[5] = p->port << 3; 74 edsa_header[5] = p->port << 3;
75 edsa_header[6] = 0x00; 75 edsa_header[6] = 0x00;
76 edsa_header[7] = 0x00; 76 edsa_header[7] = 0x00;
@@ -78,7 +78,7 @@ int edsa_xmit(struct sk_buff *skb, struct net_device *dev)
78 78
79 skb->protocol = htons(ETH_P_EDSA); 79 skb->protocol = htons(ETH_P_EDSA);
80 80
81 skb->dev = p->parent->master_netdev; 81 skb->dev = p->parent->dst->master_netdev;
82 dev_queue_xmit(skb); 82 dev_queue_xmit(skb);
83 83
84 return NETDEV_TX_OK; 84 return NETDEV_TX_OK;
@@ -91,11 +91,13 @@ out_free:
91static int edsa_rcv(struct sk_buff *skb, struct net_device *dev, 91static int edsa_rcv(struct sk_buff *skb, struct net_device *dev,
92 struct packet_type *pt, struct net_device *orig_dev) 92 struct packet_type *pt, struct net_device *orig_dev)
93{ 93{
94 struct dsa_switch *ds = dev->dsa_ptr; 94 struct dsa_switch_tree *dst = dev->dsa_ptr;
95 struct dsa_switch *ds;
95 u8 *edsa_header; 96 u8 *edsa_header;
97 int source_device;
96 int source_port; 98 int source_port;
97 99
98 if (unlikely(ds == NULL)) 100 if (unlikely(dst == NULL))
99 goto out_drop; 101 goto out_drop;
100 102
101 skb = skb_unshare(skb, GFP_ATOMIC); 103 skb = skb_unshare(skb, GFP_ATOMIC);
@@ -111,16 +113,24 @@ static int edsa_rcv(struct sk_buff *skb, struct net_device *dev,
111 edsa_header = skb->data + 2; 113 edsa_header = skb->data + 2;
112 114
113 /* 115 /*
114 * Check that frame type is either TO_CPU or FORWARD, and 116 * Check that frame type is either TO_CPU or FORWARD.
115 * that the source device is zero.
116 */ 117 */
117 if ((edsa_header[0] & 0xdf) != 0x00 && (edsa_header[0] & 0xdf) != 0xc0) 118 if ((edsa_header[0] & 0xc0) != 0x00 && (edsa_header[0] & 0xc0) != 0xc0)
118 goto out_drop; 119 goto out_drop;
119 120
120 /* 121 /*
121 * Check that the source port is a registered DSA port. 122 * Determine source device and port.
122 */ 123 */
124 source_device = edsa_header[0] & 0x1f;
123 source_port = (edsa_header[1] >> 3) & 0x1f; 125 source_port = (edsa_header[1] >> 3) & 0x1f;
126
127 /*
128 * Check that the source device exists and that the source
129 * port is a registered DSA port.
130 */
131 if (source_device >= dst->pd->nr_chips)
132 goto out_drop;
133 ds = dst->ds[source_device];
124 if (source_port >= DSA_MAX_PORTS || ds->ports[source_port] == NULL) 134 if (source_port >= DSA_MAX_PORTS || ds->ports[source_port] == NULL)
125 goto out_drop; 135 goto out_drop;
126 136
diff --git a/net/dsa/tag_trailer.c b/net/dsa/tag_trailer.c
index a6d959da6784..1c3e30c38b86 100644
--- a/net/dsa/tag_trailer.c
+++ b/net/dsa/tag_trailer.c
@@ -1,6 +1,6 @@
1/* 1/*
2 * net/dsa/tag_trailer.c - Trailer tag format handling 2 * net/dsa/tag_trailer.c - Trailer tag format handling
3 * Copyright (c) 2008 Marvell Semiconductor 3 * Copyright (c) 2008-2009 Marvell Semiconductor
4 * 4 *
5 * This program is free software; you can redistribute it and/or modify 5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by 6 * it under the terms of the GNU General Public License as published by
@@ -59,7 +59,7 @@ int trailer_xmit(struct sk_buff *skb, struct net_device *dev)
59 59
60 nskb->protocol = htons(ETH_P_TRAILER); 60 nskb->protocol = htons(ETH_P_TRAILER);
61 61
62 nskb->dev = p->parent->master_netdev; 62 nskb->dev = p->parent->dst->master_netdev;
63 dev_queue_xmit(nskb); 63 dev_queue_xmit(nskb);
64 64
65 return NETDEV_TX_OK; 65 return NETDEV_TX_OK;
@@ -68,12 +68,14 @@ int trailer_xmit(struct sk_buff *skb, struct net_device *dev)
68static int trailer_rcv(struct sk_buff *skb, struct net_device *dev, 68static int trailer_rcv(struct sk_buff *skb, struct net_device *dev,
69 struct packet_type *pt, struct net_device *orig_dev) 69 struct packet_type *pt, struct net_device *orig_dev)
70{ 70{
71 struct dsa_switch *ds = dev->dsa_ptr; 71 struct dsa_switch_tree *dst = dev->dsa_ptr;
72 struct dsa_switch *ds;
72 u8 *trailer; 73 u8 *trailer;
73 int source_port; 74 int source_port;
74 75
75 if (unlikely(ds == NULL)) 76 if (unlikely(dst == NULL))
76 goto out_drop; 77 goto out_drop;
78 ds = dst->ds[0];
77 79
78 skb = skb_unshare(skb, GFP_ATOMIC); 80 skb = skb_unshare(skb, GFP_ATOMIC);
79 if (skb == NULL) 81 if (skb == NULL)