Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

authored by

Lennert Buytenhek and committed by
David S. Miller
e84665c9 076d3e10

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