aboutsummaryrefslogtreecommitdiffstats
path: root/net/dsa/mv88e6131.c
diff options
context:
space:
mode:
authorLennert Buytenhek <buytenh@wantstofly.org>2009-03-20 05:52:09 -0400
committerDavid S. Miller <davem@davemloft.net>2009-03-21 22:06:54 -0400
commite84665c9cb4db963393fafad6fefe5efdd7e4a09 (patch)
tree545c4a2a63a77b853e3f34609d86b346fe61baf4 /net/dsa/mv88e6131.c
parent076d3e10a54caa2c148de5732c126c7a31381d48 (diff)
dsa: add switch chip cascading support
The initial version of the DSA driver only supported a single switch chip per network interface, while DSA-capable switch chips can be interconnected to form a tree of switch chips. This patch adds support for multiple switch chips on a network interface. An example topology for a 16-port device with an embedded CPU is as follows: +-----+ +--------+ +--------+ | |eth0 10| switch |9 10| switch | | CPU +----------+ +-------+ | | | | chip 0 | | chip 1 | +-----+ +---++---+ +---++---+ || || || || ||1000baseT ||1000baseT ||ports 1-8 ||ports 9-16 This requires a couple of interdependent changes in the DSA layer: - The dsa platform driver data needs to be extended: there is still only one netdevice per DSA driver instance (eth0 in the example above), but each of the switch chips in the tree needs its own mii_bus device pointer, MII management bus address, and port name array. (include/net/dsa.h) The existing in-tree dsa users need some small changes to deal with this. (arch/arm) - The DSA and Ethertype DSA tagging modules need to be extended to use the DSA device ID field on receive and demultiplex the packet accordingly, and fill in the DSA device ID field on transmit according to which switch chip the packet is heading to. (net/dsa/tag_{dsa,edsa}.c) - The concept of "CPU port", which is the switch chip port that the CPU is connected to (port 10 on switch chip 0 in the example), needs to be extended with the concept of "upstream port", which is the port on the switch chip that will bring us one hop closer to the CPU (port 10 for both switch chips in the example above). - The dsa platform data needs to specify which ports on which switch chips are links to other switch chips, so that we can enable DSA tagging mode on them. (For inter-switch links, we always use non-EtherType DSA tagging, since it has lower overhead. The CPU link uses dsa or edsa tagging depending on what the 'root' switch chip supports.) This is done by specifying "dsa" for the given port in the port array. - The dsa platform data needs to be extended with information on via which port to reach any given switch chip from any given switch chip. This info is specified via the per-switch chip data struct ->rtable[] array, which gives the nexthop ports for each of the other switches in the tree. For the example topology above, the dsa platform data would look something like this: static struct dsa_chip_data sw[2] = { { .mii_bus = &foo, .sw_addr = 1, .port_names[0] = "p1", .port_names[1] = "p2", .port_names[2] = "p3", .port_names[3] = "p4", .port_names[4] = "p5", .port_names[5] = "p6", .port_names[6] = "p7", .port_names[7] = "p8", .port_names[9] = "dsa", .port_names[10] = "cpu", .rtable = (s8 []){ -1, 9, }, }, { .mii_bus = &foo, .sw_addr = 2, .port_names[0] = "p9", .port_names[1] = "p10", .port_names[2] = "p11", .port_names[3] = "p12", .port_names[4] = "p13", .port_names[5] = "p14", .port_names[6] = "p15", .port_names[7] = "p16", .port_names[10] = "dsa", .rtable = (s8 []){ 10, -1, }, }, }, static struct dsa_platform_data pd = { .netdev = &foo, .nr_switches = 2, .sw = sw, }; Signed-off-by: Lennert Buytenhek <buytenh@marvell.com> Tested-by: Gary Thomas <gary@mlbassoc.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/dsa/mv88e6131.c')
-rw-r--r--net/dsa/mv88e6131.c78
1 files changed, 50 insertions, 28 deletions
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.