diff options
Diffstat (limited to 'net/dsa/mv88e6131.c')
-rw-r--r-- | net/dsa/mv88e6131.c | 98 |
1 files changed, 63 insertions, 35 deletions
diff --git a/net/dsa/mv88e6131.c b/net/dsa/mv88e6131.c index 374d46a01265..bb2b41bc854e 100644 --- a/net/dsa/mv88e6131.c +++ b/net/dsa/mv88e6131.c | |||
@@ -1,6 +1,6 @@ | |||
1 | /* | 1 | /* |
2 | * net/dsa/mv88e6131.c - Marvell 88e6131 switch chip support | 2 | * net/dsa/mv88e6131.c - Marvell 88e6095/6095f/6131 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 |
@@ -21,6 +21,8 @@ static char *mv88e6131_probe(struct mii_bus *bus, int sw_addr) | |||
21 | ret = __mv88e6xxx_reg_read(bus, sw_addr, REG_PORT(0), 0x03); | 21 | ret = __mv88e6xxx_reg_read(bus, sw_addr, REG_PORT(0), 0x03); |
22 | if (ret >= 0) { | 22 | if (ret >= 0) { |
23 | ret &= 0xfff0; | 23 | ret &= 0xfff0; |
24 | if (ret == 0x0950) | ||
25 | return "Marvell 88E6095/88E6095F"; | ||
24 | if (ret == 0x1060) | 26 | if (ret == 0x1060) |
25 | return "Marvell 88E6131"; | 27 | return "Marvell 88E6131"; |
26 | } | 28 | } |
@@ -36,7 +38,7 @@ static int mv88e6131_switch_reset(struct dsa_switch *ds) | |||
36 | /* | 38 | /* |
37 | * Set all ports to the disabled state. | 39 | * Set all ports to the disabled state. |
38 | */ | 40 | */ |
39 | for (i = 0; i < 8; i++) { | 41 | for (i = 0; i < 11; i++) { |
40 | ret = REG_READ(REG_PORT(i), 0x04); | 42 | ret = REG_READ(REG_PORT(i), 0x04); |
41 | REG_WRITE(REG_PORT(i), 0x04, ret & 0xfffc); | 43 | REG_WRITE(REG_PORT(i), 0x04, ret & 0xfffc); |
42 | } | 44 | } |
@@ -100,17 +102,17 @@ static int mv88e6131_setup_global(struct dsa_switch *ds) | |||
100 | REG_WRITE(REG_GLOBAL, 0x19, 0x8100); | 102 | REG_WRITE(REG_GLOBAL, 0x19, 0x8100); |
101 | 103 | ||
102 | /* | 104 | /* |
103 | * Disable ARP mirroring, and configure the cpu port as the | 105 | * Disable ARP mirroring, and configure the upstream port as |
104 | * port to which ingress and egress monitor frames are to be | 106 | * the port to which ingress and egress monitor frames are to |
105 | * sent. | 107 | * be sent. |
106 | */ | 108 | */ |
107 | REG_WRITE(REG_GLOBAL, 0x1a, (ds->cpu_port * 0x1100) | 0x00f0); | 109 | REG_WRITE(REG_GLOBAL, 0x1a, (dsa_upstream_port(ds) * 0x1100) | 0x00f0); |
108 | 110 | ||
109 | /* | 111 | /* |
110 | * Disable cascade port functionality, and set the switch's | 112 | * Disable cascade port functionality, and set the switch's |
111 | * DSA device number to zero. | 113 | * DSA device number. |
112 | */ | 114 | */ |
113 | REG_WRITE(REG_GLOBAL, 0x1c, 0xe000); | 115 | REG_WRITE(REG_GLOBAL, 0x1c, 0xe000 | (ds->index & 0x1f)); |
114 | 116 | ||
115 | /* | 117 | /* |
116 | * Send all frames with destination addresses matching | 118 | * Send all frames with destination addresses matching |
@@ -127,16 +129,23 @@ static int mv88e6131_setup_global(struct dsa_switch *ds) | |||
127 | REG_WRITE(REG_GLOBAL2, 0x05, 0x00ff); | 129 | REG_WRITE(REG_GLOBAL2, 0x05, 0x00ff); |
128 | 130 | ||
129 | /* | 131 | /* |
130 | * Map all DSA device IDs to the CPU port. | 132 | * Program the DSA routing table. |
131 | */ | 133 | */ |
132 | for (i = 0; i < 32; i++) | 134 | for (i = 0; i < 32; i++) { |
133 | 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 | } | ||
134 | 143 | ||
135 | /* | 144 | /* |
136 | * Clear all trunk masks. | 145 | * Clear all trunk masks. |
137 | */ | 146 | */ |
138 | for (i = 0; i < 8; i++) | 147 | for (i = 0; i < 8; i++) |
139 | REG_WRITE(REG_GLOBAL2, 0x07, 0x8000 | (i << 12) | 0xff); | 148 | REG_WRITE(REG_GLOBAL2, 0x07, 0x8000 | (i << 12) | 0x7ff); |
140 | 149 | ||
141 | /* | 150 | /* |
142 | * Clear all trunk mappings. | 151 | * Clear all trunk mappings. |
@@ -156,12 +165,18 @@ static int mv88e6131_setup_global(struct dsa_switch *ds) | |||
156 | static int mv88e6131_setup_port(struct dsa_switch *ds, int p) | 165 | static int mv88e6131_setup_port(struct dsa_switch *ds, int p) |
157 | { | 166 | { |
158 | int addr = REG_PORT(p); | 167 | int addr = REG_PORT(p); |
168 | u16 val; | ||
159 | 169 | ||
160 | /* | 170 | /* |
161 | * MAC Forcing register: don't force link, speed, duplex | 171 | * MAC Forcing register: don't force link, speed, duplex |
162 | * or flow control state to any particular values. | 172 | * or flow control state to any particular values on physical |
173 | * ports, but force the CPU port and all DSA ports to 1000 Mb/s | ||
174 | * full duplex. | ||
163 | */ | 175 | */ |
164 | REG_WRITE(addr, 0x01, 0x0003); | 176 | if (dsa_is_cpu_port(ds, p) || ds->dsa_port_mask & (1 << p)) |
177 | REG_WRITE(addr, 0x01, 0x003e); | ||
178 | else | ||
179 | REG_WRITE(addr, 0x01, 0x0003); | ||
165 | 180 | ||
166 | /* | 181 | /* |
167 | * Port Control: disable Core Tag, disable Drop-on-Lock, | 182 | * Port Control: disable Core Tag, disable Drop-on-Lock, |
@@ -169,29 +184,40 @@ static int mv88e6131_setup_port(struct dsa_switch *ds, int p) | |||
169 | * enable IGMP/MLD snoop, disable DoubleTag, disable VLAN | 184 | * enable IGMP/MLD snoop, disable DoubleTag, disable VLAN |
170 | * tunneling, determine priority by looking at 802.1p and | 185 | * tunneling, determine priority by looking at 802.1p and |
171 | * IP priority fields (IP prio has precedence), and set STP | 186 | * IP priority fields (IP prio has precedence), and set STP |
172 | * state to Forwarding. Finally, if this is the CPU port, | 187 | * state to Forwarding. |
173 | * additionally enable DSA tagging and forwarding of unknown | 188 | * |
174 | * 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. | ||
175 | */ | 195 | */ |
176 | 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); | ||
177 | 202 | ||
178 | /* | 203 | /* |
179 | * Port Control 1: disable trunking. Also, if this is the | 204 | * Port Control 1: disable trunking. Also, if this is the |
180 | * CPU port, enable learn messages to be sent to this port. | 205 | * CPU port, enable learn messages to be sent to this port. |
181 | */ | 206 | */ |
182 | REG_WRITE(addr, 0x05, (p == ds->cpu_port) ? 0x8000 : 0x0000); | 207 | REG_WRITE(addr, 0x05, dsa_is_cpu_port(ds, p) ? 0x8000 : 0x0000); |
183 | 208 | ||
184 | /* | 209 | /* |
185 | * Port based VLAN map: give each port its own address | 210 | * Port based VLAN map: give each port its own address |
186 | * 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' |
187 | * 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 |
188 | * the CPU port. | 213 | * the upstream port. |
189 | */ | 214 | */ |
190 | REG_WRITE(addr, 0x06, | 215 | val = (p & 0xf) << 12; |
191 | ((p & 0xf) << 12) | | 216 | if (dsa_is_cpu_port(ds, p)) |
192 | ((p == ds->cpu_port) ? | 217 | val |= ds->phys_port_mask; |
193 | ds->valid_port_mask : | 218 | else |
194 | (1 << ds->cpu_port))); | 219 | val |= 1 << dsa_upstream_port(ds); |
220 | REG_WRITE(addr, 0x06, val); | ||
195 | 221 | ||
196 | /* | 222 | /* |
197 | * Default VLAN ID and priority: don't set a default VLAN | 223 | * Default VLAN ID and priority: don't set a default VLAN |
@@ -207,13 +233,15 @@ static int mv88e6131_setup_port(struct dsa_switch *ds, int p) | |||
207 | * untagged frames on this port, do a destination address | 233 | * untagged frames on this port, do a destination address |
208 | * lookup on received packets as usual, don't send a copy | 234 | * lookup on received packets as usual, don't send a copy |
209 | * of all transmitted/received frames on this port to the | 235 | * of all transmitted/received frames on this port to the |
210 | * CPU, and configure the CPU port number. Also, if this | 236 | * CPU, and configure the upstream port number. |
211 | * is the CPU port, enable forwarding of unknown multicast | 237 | * |
212 | * addresses. | 238 | * If this is the upstream port for this switch, enable |
239 | * forwarding of unknown multicast addresses. | ||
213 | */ | 240 | */ |
214 | REG_WRITE(addr, 0x08, | 241 | val = 0x0080 | dsa_upstream_port(ds); |
215 | ((p == ds->cpu_port) ? 0x00c0 : 0x0080) | | 242 | if (p == dsa_upstream_port(ds)) |
216 | ds->cpu_port); | 243 | val |= 0x0040; |
244 | REG_WRITE(addr, 0x08, val); | ||
217 | 245 | ||
218 | /* | 246 | /* |
219 | * Rate Control: disable ingress rate limiting. | 247 | * Rate Control: disable ingress rate limiting. |
@@ -268,7 +296,7 @@ static int mv88e6131_setup(struct dsa_switch *ds) | |||
268 | if (ret < 0) | 296 | if (ret < 0) |
269 | return ret; | 297 | return ret; |
270 | 298 | ||
271 | for (i = 0; i < 6; i++) { | 299 | for (i = 0; i < 11; i++) { |
272 | ret = mv88e6131_setup_port(ds, i); | 300 | ret = mv88e6131_setup_port(ds, i); |
273 | if (ret < 0) | 301 | if (ret < 0) |
274 | return ret; | 302 | return ret; |
@@ -279,7 +307,7 @@ static int mv88e6131_setup(struct dsa_switch *ds) | |||
279 | 307 | ||
280 | static int mv88e6131_port_to_phy_addr(int port) | 308 | static int mv88e6131_port_to_phy_addr(int port) |
281 | { | 309 | { |
282 | if (port >= 0 && port != 3 && port <= 7) | 310 | if (port >= 0 && port <= 11) |
283 | return port; | 311 | return port; |
284 | return -1; | 312 | return -1; |
285 | } | 313 | } |
@@ -353,7 +381,7 @@ static int mv88e6131_get_sset_count(struct dsa_switch *ds) | |||
353 | } | 381 | } |
354 | 382 | ||
355 | static struct dsa_switch_driver mv88e6131_switch_driver = { | 383 | static struct dsa_switch_driver mv88e6131_switch_driver = { |
356 | .tag_protocol = __constant_htons(ETH_P_DSA), | 384 | .tag_protocol = cpu_to_be16(ETH_P_DSA), |
357 | .priv_size = sizeof(struct mv88e6xxx_priv_state), | 385 | .priv_size = sizeof(struct mv88e6xxx_priv_state), |
358 | .probe = mv88e6131_probe, | 386 | .probe = mv88e6131_probe, |
359 | .setup = mv88e6131_setup, | 387 | .setup = mv88e6131_setup, |