aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-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)