diff options
-rw-r--r-- | drivers/net/dsa/mv88e6123_61_65.c | 170 | ||||
-rw-r--r-- | drivers/net/dsa/mv88e6131.c | 182 | ||||
-rw-r--r-- | drivers/net/dsa/mv88e6171.c | 166 | ||||
-rw-r--r-- | drivers/net/dsa/mv88e6352.c | 205 | ||||
-rw-r--r-- | drivers/net/dsa/mv88e6xxx.c | 531 | ||||
-rw-r--r-- | drivers/net/dsa/mv88e6xxx.h | 238 |
6 files changed, 728 insertions, 764 deletions
diff --git a/drivers/net/dsa/mv88e6123_61_65.c b/drivers/net/dsa/mv88e6123_61_65.c index 2d7e1ffe9fdc..b4af6d5aff7c 100644 --- a/drivers/net/dsa/mv88e6123_61_65.c +++ b/drivers/net/dsa/mv88e6123_61_65.c | |||
@@ -25,66 +25,33 @@ static char *mv88e6123_61_65_probe(struct device *host_dev, int sw_addr) | |||
25 | if (bus == NULL) | 25 | if (bus == NULL) |
26 | return NULL; | 26 | return NULL; |
27 | 27 | ||
28 | ret = __mv88e6xxx_reg_read(bus, sw_addr, REG_PORT(0), 0x03); | 28 | ret = __mv88e6xxx_reg_read(bus, sw_addr, REG_PORT(0), PORT_SWITCH_ID); |
29 | if (ret >= 0) { | 29 | if (ret >= 0) { |
30 | if (ret == 0x1212) | 30 | if (ret == PORT_SWITCH_ID_6123_A1) |
31 | return "Marvell 88E6123 (A1)"; | 31 | return "Marvell 88E6123 (A1)"; |
32 | if (ret == 0x1213) | 32 | if (ret == PORT_SWITCH_ID_6123_A2) |
33 | return "Marvell 88E6123 (A2)"; | 33 | return "Marvell 88E6123 (A2)"; |
34 | if ((ret & 0xfff0) == 0x1210) | 34 | if ((ret & 0xfff0) == PORT_SWITCH_ID_6123) |
35 | return "Marvell 88E6123"; | 35 | return "Marvell 88E6123"; |
36 | 36 | ||
37 | if (ret == 0x1612) | 37 | if (ret == PORT_SWITCH_ID_6161_A1) |
38 | return "Marvell 88E6161 (A1)"; | 38 | return "Marvell 88E6161 (A1)"; |
39 | if (ret == 0x1613) | 39 | if (ret == PORT_SWITCH_ID_6161_A2) |
40 | return "Marvell 88E6161 (A2)"; | 40 | return "Marvell 88E6161 (A2)"; |
41 | if ((ret & 0xfff0) == 0x1610) | 41 | if ((ret & 0xfff0) == PORT_SWITCH_ID_6161) |
42 | return "Marvell 88E6161"; | 42 | return "Marvell 88E6161"; |
43 | 43 | ||
44 | if (ret == 0x1652) | 44 | if (ret == PORT_SWITCH_ID_6165_A1) |
45 | return "Marvell 88E6165 (A1)"; | 45 | return "Marvell 88E6165 (A1)"; |
46 | if (ret == 0x1653) | 46 | if (ret == PORT_SWITCH_ID_6165_A2) |
47 | return "Marvell 88e6165 (A2)"; | 47 | return "Marvell 88e6165 (A2)"; |
48 | if ((ret & 0xfff0) == 0x1650) | 48 | if ((ret & 0xfff0) == PORT_SWITCH_ID_6165) |
49 | return "Marvell 88E6165"; | 49 | return "Marvell 88E6165"; |
50 | } | 50 | } |
51 | 51 | ||
52 | return NULL; | 52 | return NULL; |
53 | } | 53 | } |
54 | 54 | ||
55 | static int mv88e6123_61_65_switch_reset(struct dsa_switch *ds) | ||
56 | { | ||
57 | int i; | ||
58 | int ret; | ||
59 | unsigned long timeout; | ||
60 | |||
61 | /* Set all ports to the disabled state. */ | ||
62 | for (i = 0; i < 8; i++) { | ||
63 | ret = REG_READ(REG_PORT(i), 0x04); | ||
64 | REG_WRITE(REG_PORT(i), 0x04, ret & 0xfffc); | ||
65 | } | ||
66 | |||
67 | /* Wait for transmit queues to drain. */ | ||
68 | usleep_range(2000, 4000); | ||
69 | |||
70 | /* Reset the switch. */ | ||
71 | REG_WRITE(REG_GLOBAL, 0x04, 0xc400); | ||
72 | |||
73 | /* Wait up to one second for reset to complete. */ | ||
74 | timeout = jiffies + 1 * HZ; | ||
75 | while (time_before(jiffies, timeout)) { | ||
76 | ret = REG_READ(REG_GLOBAL, 0x00); | ||
77 | if ((ret & 0xc800) == 0xc800) | ||
78 | break; | ||
79 | |||
80 | usleep_range(1000, 2000); | ||
81 | } | ||
82 | if (time_after(jiffies, timeout)) | ||
83 | return -ETIMEDOUT; | ||
84 | |||
85 | return 0; | ||
86 | } | ||
87 | |||
88 | static int mv88e6123_61_65_setup_global(struct dsa_switch *ds) | 55 | static int mv88e6123_61_65_setup_global(struct dsa_switch *ds) |
89 | { | 56 | { |
90 | int ret; | 57 | int ret; |
@@ -271,6 +238,7 @@ static int mv88e6123_61_65_setup_port(struct dsa_switch *ds, int p) | |||
271 | 238 | ||
272 | static int mv88e6123_61_65_setup(struct dsa_switch *ds) | 239 | static int mv88e6123_61_65_setup(struct dsa_switch *ds) |
273 | { | 240 | { |
241 | struct mv88e6xxx_priv_state *ps = ds_to_priv(ds); | ||
274 | int i; | 242 | int i; |
275 | int ret; | 243 | int ret; |
276 | 244 | ||
@@ -278,7 +246,19 @@ static int mv88e6123_61_65_setup(struct dsa_switch *ds) | |||
278 | if (ret < 0) | 246 | if (ret < 0) |
279 | return ret; | 247 | return ret; |
280 | 248 | ||
281 | ret = mv88e6123_61_65_switch_reset(ds); | 249 | switch (ps->id) { |
250 | case PORT_SWITCH_ID_6123: | ||
251 | ps->num_ports = 3; | ||
252 | break; | ||
253 | case PORT_SWITCH_ID_6161: | ||
254 | case PORT_SWITCH_ID_6165: | ||
255 | ps->num_ports = 6; | ||
256 | break; | ||
257 | default: | ||
258 | return -ENODEV; | ||
259 | } | ||
260 | |||
261 | ret = mv88e6xxx_switch_reset(ds, false); | ||
282 | if (ret < 0) | 262 | if (ret < 0) |
283 | return ret; | 263 | return ret; |
284 | 264 | ||
@@ -288,7 +268,7 @@ static int mv88e6123_61_65_setup(struct dsa_switch *ds) | |||
288 | if (ret < 0) | 268 | if (ret < 0) |
289 | return ret; | 269 | return ret; |
290 | 270 | ||
291 | for (i = 0; i < 6; i++) { | 271 | for (i = 0; i < ps->num_ports; i++) { |
292 | ret = mv88e6123_61_65_setup_port(ds, i); | 272 | ret = mv88e6123_61_65_setup_port(ds, i); |
293 | if (ret < 0) | 273 | if (ret < 0) |
294 | return ret; | 274 | return ret; |
@@ -297,108 +277,18 @@ static int mv88e6123_61_65_setup(struct dsa_switch *ds) | |||
297 | return 0; | 277 | return 0; |
298 | } | 278 | } |
299 | 279 | ||
300 | static int mv88e6123_61_65_port_to_phy_addr(int port) | ||
301 | { | ||
302 | if (port >= 0 && port <= 4) | ||
303 | return port; | ||
304 | return -1; | ||
305 | } | ||
306 | |||
307 | static int | ||
308 | mv88e6123_61_65_phy_read(struct dsa_switch *ds, int port, int regnum) | ||
309 | { | ||
310 | struct mv88e6xxx_priv_state *ps = ds_to_priv(ds); | ||
311 | int addr = mv88e6123_61_65_port_to_phy_addr(port); | ||
312 | int ret; | ||
313 | |||
314 | mutex_lock(&ps->phy_mutex); | ||
315 | ret = mv88e6xxx_phy_read(ds, addr, regnum); | ||
316 | mutex_unlock(&ps->phy_mutex); | ||
317 | return ret; | ||
318 | } | ||
319 | |||
320 | static int | ||
321 | mv88e6123_61_65_phy_write(struct dsa_switch *ds, | ||
322 | int port, int regnum, u16 val) | ||
323 | { | ||
324 | struct mv88e6xxx_priv_state *ps = ds_to_priv(ds); | ||
325 | int addr = mv88e6123_61_65_port_to_phy_addr(port); | ||
326 | int ret; | ||
327 | |||
328 | mutex_lock(&ps->phy_mutex); | ||
329 | ret = mv88e6xxx_phy_write(ds, addr, regnum, val); | ||
330 | mutex_unlock(&ps->phy_mutex); | ||
331 | return ret; | ||
332 | } | ||
333 | |||
334 | static struct mv88e6xxx_hw_stat mv88e6123_61_65_hw_stats[] = { | ||
335 | { "in_good_octets", 8, 0x00, }, | ||
336 | { "in_bad_octets", 4, 0x02, }, | ||
337 | { "in_unicast", 4, 0x04, }, | ||
338 | { "in_broadcasts", 4, 0x06, }, | ||
339 | { "in_multicasts", 4, 0x07, }, | ||
340 | { "in_pause", 4, 0x16, }, | ||
341 | { "in_undersize", 4, 0x18, }, | ||
342 | { "in_fragments", 4, 0x19, }, | ||
343 | { "in_oversize", 4, 0x1a, }, | ||
344 | { "in_jabber", 4, 0x1b, }, | ||
345 | { "in_rx_error", 4, 0x1c, }, | ||
346 | { "in_fcs_error", 4, 0x1d, }, | ||
347 | { "out_octets", 8, 0x0e, }, | ||
348 | { "out_unicast", 4, 0x10, }, | ||
349 | { "out_broadcasts", 4, 0x13, }, | ||
350 | { "out_multicasts", 4, 0x12, }, | ||
351 | { "out_pause", 4, 0x15, }, | ||
352 | { "excessive", 4, 0x11, }, | ||
353 | { "collisions", 4, 0x1e, }, | ||
354 | { "deferred", 4, 0x05, }, | ||
355 | { "single", 4, 0x14, }, | ||
356 | { "multiple", 4, 0x17, }, | ||
357 | { "out_fcs_error", 4, 0x03, }, | ||
358 | { "late", 4, 0x1f, }, | ||
359 | { "hist_64bytes", 4, 0x08, }, | ||
360 | { "hist_65_127bytes", 4, 0x09, }, | ||
361 | { "hist_128_255bytes", 4, 0x0a, }, | ||
362 | { "hist_256_511bytes", 4, 0x0b, }, | ||
363 | { "hist_512_1023bytes", 4, 0x0c, }, | ||
364 | { "hist_1024_max_bytes", 4, 0x0d, }, | ||
365 | { "sw_in_discards", 4, 0x110, }, | ||
366 | { "sw_in_filtered", 2, 0x112, }, | ||
367 | { "sw_out_filtered", 2, 0x113, }, | ||
368 | }; | ||
369 | |||
370 | static void | ||
371 | mv88e6123_61_65_get_strings(struct dsa_switch *ds, int port, uint8_t *data) | ||
372 | { | ||
373 | mv88e6xxx_get_strings(ds, ARRAY_SIZE(mv88e6123_61_65_hw_stats), | ||
374 | mv88e6123_61_65_hw_stats, port, data); | ||
375 | } | ||
376 | |||
377 | static void | ||
378 | mv88e6123_61_65_get_ethtool_stats(struct dsa_switch *ds, | ||
379 | int port, uint64_t *data) | ||
380 | { | ||
381 | mv88e6xxx_get_ethtool_stats(ds, ARRAY_SIZE(mv88e6123_61_65_hw_stats), | ||
382 | mv88e6123_61_65_hw_stats, port, data); | ||
383 | } | ||
384 | |||
385 | static int mv88e6123_61_65_get_sset_count(struct dsa_switch *ds) | ||
386 | { | ||
387 | return ARRAY_SIZE(mv88e6123_61_65_hw_stats); | ||
388 | } | ||
389 | |||
390 | struct dsa_switch_driver mv88e6123_61_65_switch_driver = { | 280 | struct dsa_switch_driver mv88e6123_61_65_switch_driver = { |
391 | .tag_protocol = DSA_TAG_PROTO_EDSA, | 281 | .tag_protocol = DSA_TAG_PROTO_EDSA, |
392 | .priv_size = sizeof(struct mv88e6xxx_priv_state), | 282 | .priv_size = sizeof(struct mv88e6xxx_priv_state), |
393 | .probe = mv88e6123_61_65_probe, | 283 | .probe = mv88e6123_61_65_probe, |
394 | .setup = mv88e6123_61_65_setup, | 284 | .setup = mv88e6123_61_65_setup, |
395 | .set_addr = mv88e6xxx_set_addr_indirect, | 285 | .set_addr = mv88e6xxx_set_addr_indirect, |
396 | .phy_read = mv88e6123_61_65_phy_read, | 286 | .phy_read = mv88e6xxx_phy_read, |
397 | .phy_write = mv88e6123_61_65_phy_write, | 287 | .phy_write = mv88e6xxx_phy_write, |
398 | .poll_link = mv88e6xxx_poll_link, | 288 | .poll_link = mv88e6xxx_poll_link, |
399 | .get_strings = mv88e6123_61_65_get_strings, | 289 | .get_strings = mv88e6xxx_get_strings, |
400 | .get_ethtool_stats = mv88e6123_61_65_get_ethtool_stats, | 290 | .get_ethtool_stats = mv88e6xxx_get_ethtool_stats, |
401 | .get_sset_count = mv88e6123_61_65_get_sset_count, | 291 | .get_sset_count = mv88e6xxx_get_sset_count, |
402 | #ifdef CONFIG_NET_DSA_HWMON | 292 | #ifdef CONFIG_NET_DSA_HWMON |
403 | .get_temp = mv88e6xxx_get_temp, | 293 | .get_temp = mv88e6xxx_get_temp, |
404 | #endif | 294 | #endif |
diff --git a/drivers/net/dsa/mv88e6131.c b/drivers/net/dsa/mv88e6131.c index 2540ef0142af..e54824fa0d95 100644 --- a/drivers/net/dsa/mv88e6131.c +++ b/drivers/net/dsa/mv88e6131.c | |||
@@ -17,12 +17,6 @@ | |||
17 | #include <net/dsa.h> | 17 | #include <net/dsa.h> |
18 | #include "mv88e6xxx.h" | 18 | #include "mv88e6xxx.h" |
19 | 19 | ||
20 | /* Switch product IDs */ | ||
21 | #define ID_6085 0x04a0 | ||
22 | #define ID_6095 0x0950 | ||
23 | #define ID_6131 0x1060 | ||
24 | #define ID_6131_B2 0x1066 | ||
25 | |||
26 | static char *mv88e6131_probe(struct device *host_dev, int sw_addr) | 20 | static char *mv88e6131_probe(struct device *host_dev, int sw_addr) |
27 | { | 21 | { |
28 | struct mii_bus *bus = dsa_host_dev_to_mii_bus(host_dev); | 22 | struct mii_bus *bus = dsa_host_dev_to_mii_bus(host_dev); |
@@ -31,56 +25,23 @@ static char *mv88e6131_probe(struct device *host_dev, int sw_addr) | |||
31 | if (bus == NULL) | 25 | if (bus == NULL) |
32 | return NULL; | 26 | return NULL; |
33 | 27 | ||
34 | ret = __mv88e6xxx_reg_read(bus, sw_addr, REG_PORT(0), 0x03); | 28 | ret = __mv88e6xxx_reg_read(bus, sw_addr, REG_PORT(0), PORT_SWITCH_ID); |
35 | if (ret >= 0) { | 29 | if (ret >= 0) { |
36 | int ret_masked = ret & 0xfff0; | 30 | int ret_masked = ret & 0xfff0; |
37 | 31 | ||
38 | if (ret_masked == ID_6085) | 32 | if (ret_masked == PORT_SWITCH_ID_6085) |
39 | return "Marvell 88E6085"; | 33 | return "Marvell 88E6085"; |
40 | if (ret_masked == ID_6095) | 34 | if (ret_masked == PORT_SWITCH_ID_6095) |
41 | return "Marvell 88E6095/88E6095F"; | 35 | return "Marvell 88E6095/88E6095F"; |
42 | if (ret == ID_6131_B2) | 36 | if (ret == PORT_SWITCH_ID_6131_B2) |
43 | return "Marvell 88E6131 (B2)"; | 37 | return "Marvell 88E6131 (B2)"; |
44 | if (ret_masked == ID_6131) | 38 | if (ret_masked == PORT_SWITCH_ID_6131) |
45 | return "Marvell 88E6131"; | 39 | return "Marvell 88E6131"; |
46 | } | 40 | } |
47 | 41 | ||
48 | return NULL; | 42 | return NULL; |
49 | } | 43 | } |
50 | 44 | ||
51 | static int mv88e6131_switch_reset(struct dsa_switch *ds) | ||
52 | { | ||
53 | int i; | ||
54 | int ret; | ||
55 | unsigned long timeout; | ||
56 | |||
57 | /* Set all ports to the disabled state. */ | ||
58 | for (i = 0; i < 11; i++) { | ||
59 | ret = REG_READ(REG_PORT(i), 0x04); | ||
60 | REG_WRITE(REG_PORT(i), 0x04, ret & 0xfffc); | ||
61 | } | ||
62 | |||
63 | /* Wait for transmit queues to drain. */ | ||
64 | usleep_range(2000, 4000); | ||
65 | |||
66 | /* Reset the switch. */ | ||
67 | REG_WRITE(REG_GLOBAL, 0x04, 0xc400); | ||
68 | |||
69 | /* Wait up to one second for reset to complete. */ | ||
70 | timeout = jiffies + 1 * HZ; | ||
71 | while (time_before(jiffies, timeout)) { | ||
72 | ret = REG_READ(REG_GLOBAL, 0x00); | ||
73 | if ((ret & 0xc800) == 0xc800) | ||
74 | break; | ||
75 | |||
76 | usleep_range(1000, 2000); | ||
77 | } | ||
78 | if (time_after(jiffies, timeout)) | ||
79 | return -ETIMEDOUT; | ||
80 | |||
81 | return 0; | ||
82 | } | ||
83 | |||
84 | static int mv88e6131_setup_global(struct dsa_switch *ds) | 45 | static int mv88e6131_setup_global(struct dsa_switch *ds) |
85 | { | 46 | { |
86 | int ret; | 47 | int ret; |
@@ -174,7 +135,7 @@ static int mv88e6131_setup_port(struct dsa_switch *ds, int p) | |||
174 | * (100 Mb/s on 6085) full duplex. | 135 | * (100 Mb/s on 6085) full duplex. |
175 | */ | 136 | */ |
176 | if (dsa_is_cpu_port(ds, p) || ds->dsa_port_mask & (1 << p)) | 137 | if (dsa_is_cpu_port(ds, p) || ds->dsa_port_mask & (1 << p)) |
177 | if (ps->id == ID_6085) | 138 | if (ps->id == PORT_SWITCH_ID_6085) |
178 | REG_WRITE(addr, 0x01, 0x003d); /* 100 Mb/s */ | 139 | REG_WRITE(addr, 0x01, 0x003d); /* 100 Mb/s */ |
179 | else | 140 | else |
180 | REG_WRITE(addr, 0x01, 0x003e); /* 1000 Mb/s */ | 141 | REG_WRITE(addr, 0x01, 0x003e); /* 1000 Mb/s */ |
@@ -201,35 +162,13 @@ static int mv88e6131_setup_port(struct dsa_switch *ds, int p) | |||
201 | /* On 6085, unknown multicast forward is controlled | 162 | /* On 6085, unknown multicast forward is controlled |
202 | * here rather than in Port Control 2 register. | 163 | * here rather than in Port Control 2 register. |
203 | */ | 164 | */ |
204 | if (ps->id == ID_6085) | 165 | if (ps->id == PORT_SWITCH_ID_6085) |
205 | val |= 0x0008; | 166 | val |= 0x0008; |
206 | } | 167 | } |
207 | if (ds->dsa_port_mask & (1 << p)) | 168 | if (ds->dsa_port_mask & (1 << p)) |
208 | val |= 0x0100; | 169 | val |= 0x0100; |
209 | REG_WRITE(addr, 0x04, val); | 170 | REG_WRITE(addr, 0x04, val); |
210 | 171 | ||
211 | /* Port Control 1: disable trunking. Also, if this is the | ||
212 | * CPU port, enable learn messages to be sent to this port. | ||
213 | */ | ||
214 | REG_WRITE(addr, 0x05, dsa_is_cpu_port(ds, p) ? 0x8000 : 0x0000); | ||
215 | |||
216 | /* Port based VLAN map: give each port its own address | ||
217 | * 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 | ||
219 | * the upstream port. | ||
220 | */ | ||
221 | val = (p & 0xf) << 12; | ||
222 | if (dsa_is_cpu_port(ds, p)) | ||
223 | val |= ds->phys_port_mask; | ||
224 | else | ||
225 | val |= 1 << dsa_upstream_port(ds); | ||
226 | REG_WRITE(addr, 0x06, val); | ||
227 | |||
228 | /* Default VLAN ID and priority: don't set a default VLAN | ||
229 | * ID, and set the default packet priority to zero. | ||
230 | */ | ||
231 | REG_WRITE(addr, 0x07, 0x0000); | ||
232 | |||
233 | /* Port Control 2: don't force a good FCS, don't use | 172 | /* Port Control 2: don't force a good FCS, don't use |
234 | * VLAN-based, source address-based or destination | 173 | * VLAN-based, source address-based or destination |
235 | * address-based priority overrides, don't let the switch | 174 | * address-based priority overrides, don't let the switch |
@@ -242,7 +181,7 @@ static int mv88e6131_setup_port(struct dsa_switch *ds, int p) | |||
242 | * If this is the upstream port for this switch, enable | 181 | * If this is the upstream port for this switch, enable |
243 | * forwarding of unknown multicast addresses. | 182 | * forwarding of unknown multicast addresses. |
244 | */ | 183 | */ |
245 | if (ps->id == ID_6085) | 184 | if (ps->id == PORT_SWITCH_ID_6085) |
246 | /* on 6085, bits 3:0 are reserved, bit 6 control ARP | 185 | /* on 6085, bits 3:0 are reserved, bit 6 control ARP |
247 | * mirroring, and multicast forward is handled in | 186 | * mirroring, and multicast forward is handled in |
248 | * Port Control register. | 187 | * Port Control register. |
@@ -278,7 +217,7 @@ static int mv88e6131_setup_port(struct dsa_switch *ds, int p) | |||
278 | */ | 217 | */ |
279 | REG_WRITE(addr, 0x19, 0x7654); | 218 | REG_WRITE(addr, 0x19, 0x7654); |
280 | 219 | ||
281 | return 0; | 220 | return mv88e6xxx_setup_port_common(ds, p); |
282 | } | 221 | } |
283 | 222 | ||
284 | static int mv88e6131_setup(struct dsa_switch *ds) | 223 | static int mv88e6131_setup(struct dsa_switch *ds) |
@@ -287,13 +226,28 @@ static int mv88e6131_setup(struct dsa_switch *ds) | |||
287 | int i; | 226 | int i; |
288 | int ret; | 227 | int ret; |
289 | 228 | ||
290 | mutex_init(&ps->smi_mutex); | 229 | ret = mv88e6xxx_setup_common(ds); |
230 | if (ret < 0) | ||
231 | return ret; | ||
232 | |||
291 | mv88e6xxx_ppu_state_init(ds); | 233 | mv88e6xxx_ppu_state_init(ds); |
292 | mutex_init(&ps->stats_mutex); | ||
293 | 234 | ||
294 | ps->id = REG_READ(REG_PORT(0), 0x03) & 0xfff0; | 235 | switch (ps->id) { |
236 | case PORT_SWITCH_ID_6085: | ||
237 | ps->num_ports = 10; | ||
238 | break; | ||
239 | case PORT_SWITCH_ID_6095: | ||
240 | ps->num_ports = 11; | ||
241 | break; | ||
242 | case PORT_SWITCH_ID_6131: | ||
243 | case PORT_SWITCH_ID_6131_B2: | ||
244 | ps->num_ports = 8; | ||
245 | break; | ||
246 | default: | ||
247 | return -ENODEV; | ||
248 | } | ||
295 | 249 | ||
296 | ret = mv88e6131_switch_reset(ds); | 250 | ret = mv88e6xxx_switch_reset(ds, false); |
297 | if (ret < 0) | 251 | if (ret < 0) |
298 | return ret; | 252 | return ret; |
299 | 253 | ||
@@ -303,7 +257,7 @@ static int mv88e6131_setup(struct dsa_switch *ds) | |||
303 | if (ret < 0) | 257 | if (ret < 0) |
304 | return ret; | 258 | return ret; |
305 | 259 | ||
306 | for (i = 0; i < 11; i++) { | 260 | for (i = 0; i < ps->num_ports; i++) { |
307 | ret = mv88e6131_setup_port(ds, i); | 261 | ret = mv88e6131_setup_port(ds, i); |
308 | if (ret < 0) | 262 | if (ret < 0) |
309 | return ret; | 263 | return ret; |
@@ -312,17 +266,24 @@ static int mv88e6131_setup(struct dsa_switch *ds) | |||
312 | return 0; | 266 | return 0; |
313 | } | 267 | } |
314 | 268 | ||
315 | static int mv88e6131_port_to_phy_addr(int port) | 269 | static int mv88e6131_port_to_phy_addr(struct dsa_switch *ds, int port) |
316 | { | 270 | { |
317 | if (port >= 0 && port <= 11) | 271 | struct mv88e6xxx_priv_state *ps = ds_to_priv(ds); |
272 | |||
273 | if (port >= 0 && port < ps->num_ports) | ||
318 | return port; | 274 | return port; |
319 | return -1; | 275 | |
276 | return -EINVAL; | ||
320 | } | 277 | } |
321 | 278 | ||
322 | static int | 279 | static int |
323 | mv88e6131_phy_read(struct dsa_switch *ds, int port, int regnum) | 280 | mv88e6131_phy_read(struct dsa_switch *ds, int port, int regnum) |
324 | { | 281 | { |
325 | int addr = mv88e6131_port_to_phy_addr(port); | 282 | int addr = mv88e6131_port_to_phy_addr(ds, port); |
283 | |||
284 | if (addr < 0) | ||
285 | return addr; | ||
286 | |||
326 | return mv88e6xxx_phy_read_ppu(ds, addr, regnum); | 287 | return mv88e6xxx_phy_read_ppu(ds, addr, regnum); |
327 | } | 288 | } |
328 | 289 | ||
@@ -330,61 +291,12 @@ static int | |||
330 | mv88e6131_phy_write(struct dsa_switch *ds, | 291 | mv88e6131_phy_write(struct dsa_switch *ds, |
331 | int port, int regnum, u16 val) | 292 | int port, int regnum, u16 val) |
332 | { | 293 | { |
333 | int addr = mv88e6131_port_to_phy_addr(port); | 294 | int addr = mv88e6131_port_to_phy_addr(ds, port); |
334 | return mv88e6xxx_phy_write_ppu(ds, addr, regnum, val); | ||
335 | } | ||
336 | |||
337 | static struct mv88e6xxx_hw_stat mv88e6131_hw_stats[] = { | ||
338 | { "in_good_octets", 8, 0x00, }, | ||
339 | { "in_bad_octets", 4, 0x02, }, | ||
340 | { "in_unicast", 4, 0x04, }, | ||
341 | { "in_broadcasts", 4, 0x06, }, | ||
342 | { "in_multicasts", 4, 0x07, }, | ||
343 | { "in_pause", 4, 0x16, }, | ||
344 | { "in_undersize", 4, 0x18, }, | ||
345 | { "in_fragments", 4, 0x19, }, | ||
346 | { "in_oversize", 4, 0x1a, }, | ||
347 | { "in_jabber", 4, 0x1b, }, | ||
348 | { "in_rx_error", 4, 0x1c, }, | ||
349 | { "in_fcs_error", 4, 0x1d, }, | ||
350 | { "out_octets", 8, 0x0e, }, | ||
351 | { "out_unicast", 4, 0x10, }, | ||
352 | { "out_broadcasts", 4, 0x13, }, | ||
353 | { "out_multicasts", 4, 0x12, }, | ||
354 | { "out_pause", 4, 0x15, }, | ||
355 | { "excessive", 4, 0x11, }, | ||
356 | { "collisions", 4, 0x1e, }, | ||
357 | { "deferred", 4, 0x05, }, | ||
358 | { "single", 4, 0x14, }, | ||
359 | { "multiple", 4, 0x17, }, | ||
360 | { "out_fcs_error", 4, 0x03, }, | ||
361 | { "late", 4, 0x1f, }, | ||
362 | { "hist_64bytes", 4, 0x08, }, | ||
363 | { "hist_65_127bytes", 4, 0x09, }, | ||
364 | { "hist_128_255bytes", 4, 0x0a, }, | ||
365 | { "hist_256_511bytes", 4, 0x0b, }, | ||
366 | { "hist_512_1023bytes", 4, 0x0c, }, | ||
367 | { "hist_1024_max_bytes", 4, 0x0d, }, | ||
368 | }; | ||
369 | |||
370 | static void | ||
371 | mv88e6131_get_strings(struct dsa_switch *ds, int port, uint8_t *data) | ||
372 | { | ||
373 | mv88e6xxx_get_strings(ds, ARRAY_SIZE(mv88e6131_hw_stats), | ||
374 | mv88e6131_hw_stats, port, data); | ||
375 | } | ||
376 | 295 | ||
377 | static void | 296 | if (addr < 0) |
378 | mv88e6131_get_ethtool_stats(struct dsa_switch *ds, | 297 | return addr; |
379 | int port, uint64_t *data) | ||
380 | { | ||
381 | mv88e6xxx_get_ethtool_stats(ds, ARRAY_SIZE(mv88e6131_hw_stats), | ||
382 | mv88e6131_hw_stats, port, data); | ||
383 | } | ||
384 | 298 | ||
385 | static int mv88e6131_get_sset_count(struct dsa_switch *ds) | 299 | return mv88e6xxx_phy_write_ppu(ds, addr, regnum, val); |
386 | { | ||
387 | return ARRAY_SIZE(mv88e6131_hw_stats); | ||
388 | } | 300 | } |
389 | 301 | ||
390 | struct dsa_switch_driver mv88e6131_switch_driver = { | 302 | struct dsa_switch_driver mv88e6131_switch_driver = { |
@@ -396,9 +308,9 @@ struct dsa_switch_driver mv88e6131_switch_driver = { | |||
396 | .phy_read = mv88e6131_phy_read, | 308 | .phy_read = mv88e6131_phy_read, |
397 | .phy_write = mv88e6131_phy_write, | 309 | .phy_write = mv88e6131_phy_write, |
398 | .poll_link = mv88e6xxx_poll_link, | 310 | .poll_link = mv88e6xxx_poll_link, |
399 | .get_strings = mv88e6131_get_strings, | 311 | .get_strings = mv88e6xxx_get_strings, |
400 | .get_ethtool_stats = mv88e6131_get_ethtool_stats, | 312 | .get_ethtool_stats = mv88e6xxx_get_ethtool_stats, |
401 | .get_sset_count = mv88e6131_get_sset_count, | 313 | .get_sset_count = mv88e6xxx_get_sset_count, |
402 | }; | 314 | }; |
403 | 315 | ||
404 | MODULE_ALIAS("platform:mv88e6085"); | 316 | MODULE_ALIAS("platform:mv88e6085"); |
diff --git a/drivers/net/dsa/mv88e6171.c b/drivers/net/dsa/mv88e6171.c index 18cfead83dc9..9104efea0e3e 100644 --- a/drivers/net/dsa/mv88e6171.c +++ b/drivers/net/dsa/mv88e6171.c | |||
@@ -17,10 +17,6 @@ | |||
17 | #include <net/dsa.h> | 17 | #include <net/dsa.h> |
18 | #include "mv88e6xxx.h" | 18 | #include "mv88e6xxx.h" |
19 | 19 | ||
20 | /* Switch product IDs */ | ||
21 | #define ID_6171 0x1710 | ||
22 | #define ID_6172 0x1720 | ||
23 | |||
24 | static char *mv88e6171_probe(struct device *host_dev, int sw_addr) | 20 | static char *mv88e6171_probe(struct device *host_dev, int sw_addr) |
25 | { | 21 | { |
26 | struct mii_bus *bus = dsa_host_dev_to_mii_bus(host_dev); | 22 | struct mii_bus *bus = dsa_host_dev_to_mii_bus(host_dev); |
@@ -29,64 +25,20 @@ static char *mv88e6171_probe(struct device *host_dev, int sw_addr) | |||
29 | if (bus == NULL) | 25 | if (bus == NULL) |
30 | return NULL; | 26 | return NULL; |
31 | 27 | ||
32 | ret = __mv88e6xxx_reg_read(bus, sw_addr, REG_PORT(0), 0x03); | 28 | ret = __mv88e6xxx_reg_read(bus, sw_addr, REG_PORT(0), PORT_SWITCH_ID); |
33 | if (ret >= 0) { | 29 | if (ret >= 0) { |
34 | if ((ret & 0xfff0) == ID_6171) | 30 | if ((ret & 0xfff0) == PORT_SWITCH_ID_6171) |
35 | return "Marvell 88E6171"; | 31 | return "Marvell 88E6171"; |
36 | if ((ret & 0xfff0) == ID_6172) | 32 | if ((ret & 0xfff0) == PORT_SWITCH_ID_6172) |
37 | return "Marvell 88E6172"; | 33 | return "Marvell 88E6172"; |
38 | } | 34 | } |
39 | 35 | ||
40 | return NULL; | 36 | return NULL; |
41 | } | 37 | } |
42 | 38 | ||
43 | static int mv88e6171_switch_reset(struct dsa_switch *ds) | ||
44 | { | ||
45 | int i; | ||
46 | int ret; | ||
47 | unsigned long timeout; | ||
48 | |||
49 | /* Set all ports to the disabled state. */ | ||
50 | for (i = 0; i < 8; i++) { | ||
51 | ret = REG_READ(REG_PORT(i), 0x04); | ||
52 | REG_WRITE(REG_PORT(i), 0x04, ret & 0xfffc); | ||
53 | } | ||
54 | |||
55 | /* Wait for transmit queues to drain. */ | ||
56 | usleep_range(2000, 4000); | ||
57 | |||
58 | /* Reset the switch. Keep PPU active. The PPU needs to be | ||
59 | * active to support indirect phy register accesses through | ||
60 | * global registers 0x18 and 0x19. | ||
61 | */ | ||
62 | REG_WRITE(REG_GLOBAL, 0x04, 0xc000); | ||
63 | |||
64 | /* Wait up to one second for reset to complete. */ | ||
65 | timeout = jiffies + 1 * HZ; | ||
66 | while (time_before(jiffies, timeout)) { | ||
67 | ret = REG_READ(REG_GLOBAL, 0x00); | ||
68 | if ((ret & 0xc800) == 0xc800) | ||
69 | break; | ||
70 | |||
71 | usleep_range(1000, 2000); | ||
72 | } | ||
73 | if (time_after(jiffies, timeout)) | ||
74 | return -ETIMEDOUT; | ||
75 | |||
76 | /* Enable ports not under DSA, e.g. WAN port */ | ||
77 | for (i = 0; i < 8; i++) { | ||
78 | if (dsa_is_cpu_port(ds, i) || ds->phys_port_mask & (1 << i)) | ||
79 | continue; | ||
80 | |||
81 | ret = REG_READ(REG_PORT(i), 0x04); | ||
82 | REG_WRITE(REG_PORT(i), 0x04, ret | 0x03); | ||
83 | } | ||
84 | |||
85 | return 0; | ||
86 | } | ||
87 | |||
88 | static int mv88e6171_setup_global(struct dsa_switch *ds) | 39 | static int mv88e6171_setup_global(struct dsa_switch *ds) |
89 | { | 40 | { |
41 | struct mv88e6xxx_priv_state *ps = ds_to_priv(ds); | ||
90 | int ret; | 42 | int ret; |
91 | int i; | 43 | int i; |
92 | 44 | ||
@@ -151,7 +103,7 @@ static int mv88e6171_setup_global(struct dsa_switch *ds) | |||
151 | } | 103 | } |
152 | 104 | ||
153 | /* Clear all trunk masks. */ | 105 | /* Clear all trunk masks. */ |
154 | for (i = 0; i < 8; i++) | 106 | for (i = 0; i < ps->num_ports; i++) |
155 | REG_WRITE(REG_GLOBAL2, 0x07, 0x8000 | (i << 12) | 0xff); | 107 | REG_WRITE(REG_GLOBAL2, 0x07, 0x8000 | (i << 12) | 0xff); |
156 | 108 | ||
157 | /* Clear all trunk mappings. */ | 109 | /* Clear all trunk mappings. */ |
@@ -274,6 +226,7 @@ static int mv88e6171_setup_port(struct dsa_switch *ds, int p) | |||
274 | 226 | ||
275 | static int mv88e6171_setup(struct dsa_switch *ds) | 227 | static int mv88e6171_setup(struct dsa_switch *ds) |
276 | { | 228 | { |
229 | struct mv88e6xxx_priv_state *ps = ds_to_priv(ds); | ||
277 | int i; | 230 | int i; |
278 | int ret; | 231 | int ret; |
279 | 232 | ||
@@ -281,7 +234,9 @@ static int mv88e6171_setup(struct dsa_switch *ds) | |||
281 | if (ret < 0) | 234 | if (ret < 0) |
282 | return ret; | 235 | return ret; |
283 | 236 | ||
284 | ret = mv88e6171_switch_reset(ds); | 237 | ps->num_ports = 7; |
238 | |||
239 | ret = mv88e6xxx_switch_reset(ds, true); | ||
285 | if (ret < 0) | 240 | if (ret < 0) |
286 | return ret; | 241 | return ret; |
287 | 242 | ||
@@ -291,7 +246,7 @@ static int mv88e6171_setup(struct dsa_switch *ds) | |||
291 | if (ret < 0) | 246 | if (ret < 0) |
292 | return ret; | 247 | return ret; |
293 | 248 | ||
294 | for (i = 0; i < 8; i++) { | 249 | for (i = 0; i < ps->num_ports; i++) { |
295 | if (!(dsa_is_cpu_port(ds, i) || ds->phys_port_mask & (1 << i))) | 250 | if (!(dsa_is_cpu_port(ds, i) || ds->phys_port_mask & (1 << i))) |
296 | continue; | 251 | continue; |
297 | 252 | ||
@@ -303,99 +258,12 @@ static int mv88e6171_setup(struct dsa_switch *ds) | |||
303 | return 0; | 258 | return 0; |
304 | } | 259 | } |
305 | 260 | ||
306 | static int mv88e6171_port_to_phy_addr(int port) | ||
307 | { | ||
308 | if (port >= 0 && port <= 4) | ||
309 | return port; | ||
310 | return -1; | ||
311 | } | ||
312 | |||
313 | static int | ||
314 | mv88e6171_phy_read(struct dsa_switch *ds, int port, int regnum) | ||
315 | { | ||
316 | struct mv88e6xxx_priv_state *ps = ds_to_priv(ds); | ||
317 | int addr = mv88e6171_port_to_phy_addr(port); | ||
318 | int ret; | ||
319 | |||
320 | mutex_lock(&ps->phy_mutex); | ||
321 | ret = mv88e6xxx_phy_read_indirect(ds, addr, regnum); | ||
322 | mutex_unlock(&ps->phy_mutex); | ||
323 | return ret; | ||
324 | } | ||
325 | |||
326 | static int | ||
327 | mv88e6171_phy_write(struct dsa_switch *ds, | ||
328 | int port, int regnum, u16 val) | ||
329 | { | ||
330 | struct mv88e6xxx_priv_state *ps = ds_to_priv(ds); | ||
331 | int addr = mv88e6171_port_to_phy_addr(port); | ||
332 | int ret; | ||
333 | |||
334 | mutex_lock(&ps->phy_mutex); | ||
335 | ret = mv88e6xxx_phy_write_indirect(ds, addr, regnum, val); | ||
336 | mutex_unlock(&ps->phy_mutex); | ||
337 | return ret; | ||
338 | } | ||
339 | |||
340 | static struct mv88e6xxx_hw_stat mv88e6171_hw_stats[] = { | ||
341 | { "in_good_octets", 8, 0x00, }, | ||
342 | { "in_bad_octets", 4, 0x02, }, | ||
343 | { "in_unicast", 4, 0x04, }, | ||
344 | { "in_broadcasts", 4, 0x06, }, | ||
345 | { "in_multicasts", 4, 0x07, }, | ||
346 | { "in_pause", 4, 0x16, }, | ||
347 | { "in_undersize", 4, 0x18, }, | ||
348 | { "in_fragments", 4, 0x19, }, | ||
349 | { "in_oversize", 4, 0x1a, }, | ||
350 | { "in_jabber", 4, 0x1b, }, | ||
351 | { "in_rx_error", 4, 0x1c, }, | ||
352 | { "in_fcs_error", 4, 0x1d, }, | ||
353 | { "out_octets", 8, 0x0e, }, | ||
354 | { "out_unicast", 4, 0x10, }, | ||
355 | { "out_broadcasts", 4, 0x13, }, | ||
356 | { "out_multicasts", 4, 0x12, }, | ||
357 | { "out_pause", 4, 0x15, }, | ||
358 | { "excessive", 4, 0x11, }, | ||
359 | { "collisions", 4, 0x1e, }, | ||
360 | { "deferred", 4, 0x05, }, | ||
361 | { "single", 4, 0x14, }, | ||
362 | { "multiple", 4, 0x17, }, | ||
363 | { "out_fcs_error", 4, 0x03, }, | ||
364 | { "late", 4, 0x1f, }, | ||
365 | { "hist_64bytes", 4, 0x08, }, | ||
366 | { "hist_65_127bytes", 4, 0x09, }, | ||
367 | { "hist_128_255bytes", 4, 0x0a, }, | ||
368 | { "hist_256_511bytes", 4, 0x0b, }, | ||
369 | { "hist_512_1023bytes", 4, 0x0c, }, | ||
370 | { "hist_1024_max_bytes", 4, 0x0d, }, | ||
371 | }; | ||
372 | |||
373 | static void | ||
374 | mv88e6171_get_strings(struct dsa_switch *ds, int port, uint8_t *data) | ||
375 | { | ||
376 | mv88e6xxx_get_strings(ds, ARRAY_SIZE(mv88e6171_hw_stats), | ||
377 | mv88e6171_hw_stats, port, data); | ||
378 | } | ||
379 | |||
380 | static void | ||
381 | mv88e6171_get_ethtool_stats(struct dsa_switch *ds, | ||
382 | int port, uint64_t *data) | ||
383 | { | ||
384 | mv88e6xxx_get_ethtool_stats(ds, ARRAY_SIZE(mv88e6171_hw_stats), | ||
385 | mv88e6171_hw_stats, port, data); | ||
386 | } | ||
387 | |||
388 | static int mv88e6171_get_sset_count(struct dsa_switch *ds) | ||
389 | { | ||
390 | return ARRAY_SIZE(mv88e6171_hw_stats); | ||
391 | } | ||
392 | |||
393 | static int mv88e6171_get_eee(struct dsa_switch *ds, int port, | 261 | static int mv88e6171_get_eee(struct dsa_switch *ds, int port, |
394 | struct ethtool_eee *e) | 262 | struct ethtool_eee *e) |
395 | { | 263 | { |
396 | struct mv88e6xxx_priv_state *ps = ds_to_priv(ds); | 264 | struct mv88e6xxx_priv_state *ps = ds_to_priv(ds); |
397 | 265 | ||
398 | if (ps->id == ID_6172) | 266 | if (ps->id == PORT_SWITCH_ID_6172) |
399 | return mv88e6xxx_get_eee(ds, port, e); | 267 | return mv88e6xxx_get_eee(ds, port, e); |
400 | 268 | ||
401 | return -EOPNOTSUPP; | 269 | return -EOPNOTSUPP; |
@@ -406,7 +274,7 @@ static int mv88e6171_set_eee(struct dsa_switch *ds, int port, | |||
406 | { | 274 | { |
407 | struct mv88e6xxx_priv_state *ps = ds_to_priv(ds); | 275 | struct mv88e6xxx_priv_state *ps = ds_to_priv(ds); |
408 | 276 | ||
409 | if (ps->id == ID_6172) | 277 | if (ps->id == PORT_SWITCH_ID_6172) |
410 | return mv88e6xxx_set_eee(ds, port, phydev, e); | 278 | return mv88e6xxx_set_eee(ds, port, phydev, e); |
411 | 279 | ||
412 | return -EOPNOTSUPP; | 280 | return -EOPNOTSUPP; |
@@ -418,12 +286,12 @@ struct dsa_switch_driver mv88e6171_switch_driver = { | |||
418 | .probe = mv88e6171_probe, | 286 | .probe = mv88e6171_probe, |
419 | .setup = mv88e6171_setup, | 287 | .setup = mv88e6171_setup, |
420 | .set_addr = mv88e6xxx_set_addr_indirect, | 288 | .set_addr = mv88e6xxx_set_addr_indirect, |
421 | .phy_read = mv88e6171_phy_read, | 289 | .phy_read = mv88e6xxx_phy_read_indirect, |
422 | .phy_write = mv88e6171_phy_write, | 290 | .phy_write = mv88e6xxx_phy_write_indirect, |
423 | .poll_link = mv88e6xxx_poll_link, | 291 | .poll_link = mv88e6xxx_poll_link, |
424 | .get_strings = mv88e6171_get_strings, | 292 | .get_strings = mv88e6xxx_get_strings, |
425 | .get_ethtool_stats = mv88e6171_get_ethtool_stats, | 293 | .get_ethtool_stats = mv88e6xxx_get_ethtool_stats, |
426 | .get_sset_count = mv88e6171_get_sset_count, | 294 | .get_sset_count = mv88e6xxx_get_sset_count, |
427 | .set_eee = mv88e6171_set_eee, | 295 | .set_eee = mv88e6171_set_eee, |
428 | .get_eee = mv88e6171_get_eee, | 296 | .get_eee = mv88e6171_get_eee, |
429 | #ifdef CONFIG_NET_DSA_HWMON | 297 | #ifdef CONFIG_NET_DSA_HWMON |
diff --git a/drivers/net/dsa/mv88e6352.c b/drivers/net/dsa/mv88e6352.c index 41fe3a6a72d1..126c11b81e75 100644 --- a/drivers/net/dsa/mv88e6352.c +++ b/drivers/net/dsa/mv88e6352.c | |||
@@ -30,58 +30,24 @@ static char *mv88e6352_probe(struct device *host_dev, int sw_addr) | |||
30 | if (bus == NULL) | 30 | if (bus == NULL) |
31 | return NULL; | 31 | return NULL; |
32 | 32 | ||
33 | ret = __mv88e6xxx_reg_read(bus, sw_addr, REG_PORT(0), 0x03); | 33 | ret = __mv88e6xxx_reg_read(bus, sw_addr, REG_PORT(0), PORT_SWITCH_ID); |
34 | if (ret >= 0) { | 34 | if (ret >= 0) { |
35 | if ((ret & 0xfff0) == 0x1760) | 35 | if ((ret & 0xfff0) == PORT_SWITCH_ID_6176) |
36 | return "Marvell 88E6176"; | 36 | return "Marvell 88E6176"; |
37 | if (ret == 0x3521) | 37 | if (ret == PORT_SWITCH_ID_6352_A0) |
38 | return "Marvell 88E6352 (A0)"; | 38 | return "Marvell 88E6352 (A0)"; |
39 | if (ret == 0x3522) | 39 | if (ret == PORT_SWITCH_ID_6352_A1) |
40 | return "Marvell 88E6352 (A1)"; | 40 | return "Marvell 88E6352 (A1)"; |
41 | if ((ret & 0xfff0) == 0x3520) | 41 | if ((ret & 0xfff0) == PORT_SWITCH_ID_6352) |
42 | return "Marvell 88E6352"; | 42 | return "Marvell 88E6352"; |
43 | } | 43 | } |
44 | 44 | ||
45 | return NULL; | 45 | return NULL; |
46 | } | 46 | } |
47 | 47 | ||
48 | static int mv88e6352_switch_reset(struct dsa_switch *ds) | ||
49 | { | ||
50 | unsigned long timeout; | ||
51 | int ret; | ||
52 | int i; | ||
53 | |||
54 | /* Set all ports to the disabled state. */ | ||
55 | for (i = 0; i < 7; i++) { | ||
56 | ret = REG_READ(REG_PORT(i), 0x04); | ||
57 | REG_WRITE(REG_PORT(i), 0x04, ret & 0xfffc); | ||
58 | } | ||
59 | |||
60 | /* Wait for transmit queues to drain. */ | ||
61 | usleep_range(2000, 4000); | ||
62 | |||
63 | /* Reset the switch. Keep PPU active (bit 14, undocumented). | ||
64 | * The PPU needs to be active to support indirect phy register | ||
65 | * accesses through global registers 0x18 and 0x19. | ||
66 | */ | ||
67 | REG_WRITE(REG_GLOBAL, 0x04, 0xc000); | ||
68 | |||
69 | /* Wait up to one second for reset to complete. */ | ||
70 | timeout = jiffies + 1 * HZ; | ||
71 | while (time_before(jiffies, timeout)) { | ||
72 | ret = REG_READ(REG_GLOBAL, 0x00); | ||
73 | if ((ret & 0x8800) == 0x8800) | ||
74 | break; | ||
75 | usleep_range(1000, 2000); | ||
76 | } | ||
77 | if (time_after(jiffies, timeout)) | ||
78 | return -ETIMEDOUT; | ||
79 | |||
80 | return 0; | ||
81 | } | ||
82 | |||
83 | static int mv88e6352_setup_global(struct dsa_switch *ds) | 48 | static int mv88e6352_setup_global(struct dsa_switch *ds) |
84 | { | 49 | { |
50 | struct mv88e6xxx_priv_state *ps = ds_to_priv(ds); | ||
85 | int ret; | 51 | int ret; |
86 | int i; | 52 | int i; |
87 | 53 | ||
@@ -152,7 +118,7 @@ static int mv88e6352_setup_global(struct dsa_switch *ds) | |||
152 | /* Disable ingress rate limiting by resetting all ingress | 118 | /* Disable ingress rate limiting by resetting all ingress |
153 | * rate limit registers to their initial state. | 119 | * rate limit registers to their initial state. |
154 | */ | 120 | */ |
155 | for (i = 0; i < 7; i++) | 121 | for (i = 0; i < ps->num_ports; i++) |
156 | REG_WRITE(REG_GLOBAL2, 0x09, 0x9000 | (i << 8)); | 122 | REG_WRITE(REG_GLOBAL2, 0x09, 0x9000 | (i << 8)); |
157 | 123 | ||
158 | /* Initialise cross-chip port VLAN table to reset defaults. */ | 124 | /* Initialise cross-chip port VLAN table to reset defaults. */ |
@@ -264,48 +230,13 @@ static int mv88e6352_setup_port(struct dsa_switch *ds, int p) | |||
264 | 230 | ||
265 | #ifdef CONFIG_NET_DSA_HWMON | 231 | #ifdef CONFIG_NET_DSA_HWMON |
266 | 232 | ||
267 | static int mv88e6352_phy_page_read(struct dsa_switch *ds, | ||
268 | int port, int page, int reg) | ||
269 | { | ||
270 | struct mv88e6xxx_priv_state *ps = ds_to_priv(ds); | ||
271 | int ret; | ||
272 | |||
273 | mutex_lock(&ps->phy_mutex); | ||
274 | ret = mv88e6xxx_phy_write_indirect(ds, port, 0x16, page); | ||
275 | if (ret < 0) | ||
276 | goto error; | ||
277 | ret = mv88e6xxx_phy_read_indirect(ds, port, reg); | ||
278 | error: | ||
279 | mv88e6xxx_phy_write_indirect(ds, port, 0x16, 0x0); | ||
280 | mutex_unlock(&ps->phy_mutex); | ||
281 | return ret; | ||
282 | } | ||
283 | |||
284 | static int mv88e6352_phy_page_write(struct dsa_switch *ds, | ||
285 | int port, int page, int reg, int val) | ||
286 | { | ||
287 | struct mv88e6xxx_priv_state *ps = ds_to_priv(ds); | ||
288 | int ret; | ||
289 | |||
290 | mutex_lock(&ps->phy_mutex); | ||
291 | ret = mv88e6xxx_phy_write_indirect(ds, port, 0x16, page); | ||
292 | if (ret < 0) | ||
293 | goto error; | ||
294 | |||
295 | ret = mv88e6xxx_phy_write_indirect(ds, port, reg, val); | ||
296 | error: | ||
297 | mv88e6xxx_phy_write_indirect(ds, port, 0x16, 0x0); | ||
298 | mutex_unlock(&ps->phy_mutex); | ||
299 | return ret; | ||
300 | } | ||
301 | |||
302 | static int mv88e6352_get_temp(struct dsa_switch *ds, int *temp) | 233 | static int mv88e6352_get_temp(struct dsa_switch *ds, int *temp) |
303 | { | 234 | { |
304 | int ret; | 235 | int ret; |
305 | 236 | ||
306 | *temp = 0; | 237 | *temp = 0; |
307 | 238 | ||
308 | ret = mv88e6352_phy_page_read(ds, 0, 6, 27); | 239 | ret = mv88e6xxx_phy_page_read(ds, 0, 6, 27); |
309 | if (ret < 0) | 240 | if (ret < 0) |
310 | return ret; | 241 | return ret; |
311 | 242 | ||
@@ -320,7 +251,7 @@ static int mv88e6352_get_temp_limit(struct dsa_switch *ds, int *temp) | |||
320 | 251 | ||
321 | *temp = 0; | 252 | *temp = 0; |
322 | 253 | ||
323 | ret = mv88e6352_phy_page_read(ds, 0, 6, 26); | 254 | ret = mv88e6xxx_phy_page_read(ds, 0, 6, 26); |
324 | if (ret < 0) | 255 | if (ret < 0) |
325 | return ret; | 256 | return ret; |
326 | 257 | ||
@@ -333,11 +264,11 @@ static int mv88e6352_set_temp_limit(struct dsa_switch *ds, int temp) | |||
333 | { | 264 | { |
334 | int ret; | 265 | int ret; |
335 | 266 | ||
336 | ret = mv88e6352_phy_page_read(ds, 0, 6, 26); | 267 | ret = mv88e6xxx_phy_page_read(ds, 0, 6, 26); |
337 | if (ret < 0) | 268 | if (ret < 0) |
338 | return ret; | 269 | return ret; |
339 | temp = clamp_val(DIV_ROUND_CLOSEST(temp, 5) + 5, 0, 0x1f); | 270 | temp = clamp_val(DIV_ROUND_CLOSEST(temp, 5) + 5, 0, 0x1f); |
340 | return mv88e6352_phy_page_write(ds, 0, 6, 26, | 271 | return mv88e6xxx_phy_page_write(ds, 0, 6, 26, |
341 | (ret & 0xe0ff) | (temp << 8)); | 272 | (ret & 0xe0ff) | (temp << 8)); |
342 | } | 273 | } |
343 | 274 | ||
@@ -347,7 +278,7 @@ static int mv88e6352_get_temp_alarm(struct dsa_switch *ds, bool *alarm) | |||
347 | 278 | ||
348 | *alarm = false; | 279 | *alarm = false; |
349 | 280 | ||
350 | ret = mv88e6352_phy_page_read(ds, 0, 6, 26); | 281 | ret = mv88e6xxx_phy_page_read(ds, 0, 6, 26); |
351 | if (ret < 0) | 282 | if (ret < 0) |
352 | return ret; | 283 | return ret; |
353 | 284 | ||
@@ -367,9 +298,11 @@ static int mv88e6352_setup(struct dsa_switch *ds) | |||
367 | if (ret < 0) | 298 | if (ret < 0) |
368 | return ret; | 299 | return ret; |
369 | 300 | ||
301 | ps->num_ports = 7; | ||
302 | |||
370 | mutex_init(&ps->eeprom_mutex); | 303 | mutex_init(&ps->eeprom_mutex); |
371 | 304 | ||
372 | ret = mv88e6352_switch_reset(ds); | 305 | ret = mv88e6xxx_switch_reset(ds, true); |
373 | if (ret < 0) | 306 | if (ret < 0) |
374 | return ret; | 307 | return ret; |
375 | 308 | ||
@@ -379,7 +312,7 @@ static int mv88e6352_setup(struct dsa_switch *ds) | |||
379 | if (ret < 0) | 312 | if (ret < 0) |
380 | return ret; | 313 | return ret; |
381 | 314 | ||
382 | for (i = 0; i < 7; i++) { | 315 | for (i = 0; i < ps->num_ports; i++) { |
383 | ret = mv88e6352_setup_port(ds, i); | 316 | ret = mv88e6352_setup_port(ds, i); |
384 | if (ret < 0) | 317 | if (ret < 0) |
385 | return ret; | 318 | return ret; |
@@ -388,83 +321,6 @@ static int mv88e6352_setup(struct dsa_switch *ds) | |||
388 | return 0; | 321 | return 0; |
389 | } | 322 | } |
390 | 323 | ||
391 | static int mv88e6352_port_to_phy_addr(int port) | ||
392 | { | ||
393 | if (port >= 0 && port <= 4) | ||
394 | return port; | ||
395 | return -EINVAL; | ||
396 | } | ||
397 | |||
398 | static int | ||
399 | mv88e6352_phy_read(struct dsa_switch *ds, int port, int regnum) | ||
400 | { | ||
401 | struct mv88e6xxx_priv_state *ps = ds_to_priv(ds); | ||
402 | int addr = mv88e6352_port_to_phy_addr(port); | ||
403 | int ret; | ||
404 | |||
405 | if (addr < 0) | ||
406 | return addr; | ||
407 | |||
408 | mutex_lock(&ps->phy_mutex); | ||
409 | ret = mv88e6xxx_phy_read_indirect(ds, addr, regnum); | ||
410 | mutex_unlock(&ps->phy_mutex); | ||
411 | |||
412 | return ret; | ||
413 | } | ||
414 | |||
415 | static int | ||
416 | mv88e6352_phy_write(struct dsa_switch *ds, int port, int regnum, u16 val) | ||
417 | { | ||
418 | struct mv88e6xxx_priv_state *ps = ds_to_priv(ds); | ||
419 | int addr = mv88e6352_port_to_phy_addr(port); | ||
420 | int ret; | ||
421 | |||
422 | if (addr < 0) | ||
423 | return addr; | ||
424 | |||
425 | mutex_lock(&ps->phy_mutex); | ||
426 | ret = mv88e6xxx_phy_write_indirect(ds, addr, regnum, val); | ||
427 | mutex_unlock(&ps->phy_mutex); | ||
428 | |||
429 | return ret; | ||
430 | } | ||
431 | |||
432 | static struct mv88e6xxx_hw_stat mv88e6352_hw_stats[] = { | ||
433 | { "in_good_octets", 8, 0x00, }, | ||
434 | { "in_bad_octets", 4, 0x02, }, | ||
435 | { "in_unicast", 4, 0x04, }, | ||
436 | { "in_broadcasts", 4, 0x06, }, | ||
437 | { "in_multicasts", 4, 0x07, }, | ||
438 | { "in_pause", 4, 0x16, }, | ||
439 | { "in_undersize", 4, 0x18, }, | ||
440 | { "in_fragments", 4, 0x19, }, | ||
441 | { "in_oversize", 4, 0x1a, }, | ||
442 | { "in_jabber", 4, 0x1b, }, | ||
443 | { "in_rx_error", 4, 0x1c, }, | ||
444 | { "in_fcs_error", 4, 0x1d, }, | ||
445 | { "out_octets", 8, 0x0e, }, | ||
446 | { "out_unicast", 4, 0x10, }, | ||
447 | { "out_broadcasts", 4, 0x13, }, | ||
448 | { "out_multicasts", 4, 0x12, }, | ||
449 | { "out_pause", 4, 0x15, }, | ||
450 | { "excessive", 4, 0x11, }, | ||
451 | { "collisions", 4, 0x1e, }, | ||
452 | { "deferred", 4, 0x05, }, | ||
453 | { "single", 4, 0x14, }, | ||
454 | { "multiple", 4, 0x17, }, | ||
455 | { "out_fcs_error", 4, 0x03, }, | ||
456 | { "late", 4, 0x1f, }, | ||
457 | { "hist_64bytes", 4, 0x08, }, | ||
458 | { "hist_65_127bytes", 4, 0x09, }, | ||
459 | { "hist_128_255bytes", 4, 0x0a, }, | ||
460 | { "hist_256_511bytes", 4, 0x0b, }, | ||
461 | { "hist_512_1023bytes", 4, 0x0c, }, | ||
462 | { "hist_1024_max_bytes", 4, 0x0d, }, | ||
463 | { "sw_in_discards", 4, 0x110, }, | ||
464 | { "sw_in_filtered", 2, 0x112, }, | ||
465 | { "sw_out_filtered", 2, 0x113, }, | ||
466 | }; | ||
467 | |||
468 | static int mv88e6352_read_eeprom_word(struct dsa_switch *ds, int addr) | 324 | static int mv88e6352_read_eeprom_word(struct dsa_switch *ds, int addr) |
469 | { | 325 | { |
470 | struct mv88e6xxx_priv_state *ps = ds_to_priv(ds); | 326 | struct mv88e6xxx_priv_state *ps = ds_to_priv(ds); |
@@ -663,37 +519,18 @@ static int mv88e6352_set_eeprom(struct dsa_switch *ds, | |||
663 | return 0; | 519 | return 0; |
664 | } | 520 | } |
665 | 521 | ||
666 | static void | ||
667 | mv88e6352_get_strings(struct dsa_switch *ds, int port, uint8_t *data) | ||
668 | { | ||
669 | mv88e6xxx_get_strings(ds, ARRAY_SIZE(mv88e6352_hw_stats), | ||
670 | mv88e6352_hw_stats, port, data); | ||
671 | } | ||
672 | |||
673 | static void | ||
674 | mv88e6352_get_ethtool_stats(struct dsa_switch *ds, int port, uint64_t *data) | ||
675 | { | ||
676 | mv88e6xxx_get_ethtool_stats(ds, ARRAY_SIZE(mv88e6352_hw_stats), | ||
677 | mv88e6352_hw_stats, port, data); | ||
678 | } | ||
679 | |||
680 | static int mv88e6352_get_sset_count(struct dsa_switch *ds) | ||
681 | { | ||
682 | return ARRAY_SIZE(mv88e6352_hw_stats); | ||
683 | } | ||
684 | |||
685 | struct dsa_switch_driver mv88e6352_switch_driver = { | 522 | struct dsa_switch_driver mv88e6352_switch_driver = { |
686 | .tag_protocol = DSA_TAG_PROTO_EDSA, | 523 | .tag_protocol = DSA_TAG_PROTO_EDSA, |
687 | .priv_size = sizeof(struct mv88e6xxx_priv_state), | 524 | .priv_size = sizeof(struct mv88e6xxx_priv_state), |
688 | .probe = mv88e6352_probe, | 525 | .probe = mv88e6352_probe, |
689 | .setup = mv88e6352_setup, | 526 | .setup = mv88e6352_setup, |
690 | .set_addr = mv88e6xxx_set_addr_indirect, | 527 | .set_addr = mv88e6xxx_set_addr_indirect, |
691 | .phy_read = mv88e6352_phy_read, | 528 | .phy_read = mv88e6xxx_phy_read_indirect, |
692 | .phy_write = mv88e6352_phy_write, | 529 | .phy_write = mv88e6xxx_phy_write_indirect, |
693 | .poll_link = mv88e6xxx_poll_link, | 530 | .poll_link = mv88e6xxx_poll_link, |
694 | .get_strings = mv88e6352_get_strings, | 531 | .get_strings = mv88e6xxx_get_strings, |
695 | .get_ethtool_stats = mv88e6352_get_ethtool_stats, | 532 | .get_ethtool_stats = mv88e6xxx_get_ethtool_stats, |
696 | .get_sset_count = mv88e6352_get_sset_count, | 533 | .get_sset_count = mv88e6xxx_get_sset_count, |
697 | .set_eee = mv88e6xxx_set_eee, | 534 | .set_eee = mv88e6xxx_set_eee, |
698 | .get_eee = mv88e6xxx_get_eee, | 535 | .get_eee = mv88e6xxx_get_eee, |
699 | #ifdef CONFIG_NET_DSA_HWMON | 536 | #ifdef CONFIG_NET_DSA_HWMON |
diff --git a/drivers/net/dsa/mv88e6xxx.c b/drivers/net/dsa/mv88e6xxx.c index 13572cc24c6d..fc8d3b6ffe8e 100644 --- a/drivers/net/dsa/mv88e6xxx.c +++ b/drivers/net/dsa/mv88e6xxx.c | |||
@@ -33,11 +33,11 @@ static int mv88e6xxx_reg_wait_ready(struct mii_bus *bus, int sw_addr) | |||
33 | int i; | 33 | int i; |
34 | 34 | ||
35 | for (i = 0; i < 16; i++) { | 35 | for (i = 0; i < 16; i++) { |
36 | ret = mdiobus_read(bus, sw_addr, 0); | 36 | ret = mdiobus_read(bus, sw_addr, SMI_CMD); |
37 | if (ret < 0) | 37 | if (ret < 0) |
38 | return ret; | 38 | return ret; |
39 | 39 | ||
40 | if ((ret & 0x8000) == 0) | 40 | if ((ret & SMI_CMD_BUSY) == 0) |
41 | return 0; | 41 | return 0; |
42 | } | 42 | } |
43 | 43 | ||
@@ -57,7 +57,8 @@ int __mv88e6xxx_reg_read(struct mii_bus *bus, int sw_addr, int addr, int reg) | |||
57 | return ret; | 57 | return ret; |
58 | 58 | ||
59 | /* Transmit the read command. */ | 59 | /* Transmit the read command. */ |
60 | ret = mdiobus_write(bus, sw_addr, 0, 0x9800 | (addr << 5) | reg); | 60 | ret = mdiobus_write(bus, sw_addr, SMI_CMD, |
61 | SMI_CMD_OP_22_READ | (addr << 5) | reg); | ||
61 | if (ret < 0) | 62 | if (ret < 0) |
62 | return ret; | 63 | return ret; |
63 | 64 | ||
@@ -67,7 +68,7 @@ int __mv88e6xxx_reg_read(struct mii_bus *bus, int sw_addr, int addr, int reg) | |||
67 | return ret; | 68 | return ret; |
68 | 69 | ||
69 | /* Read the data. */ | 70 | /* Read the data. */ |
70 | ret = mdiobus_read(bus, sw_addr, 1); | 71 | ret = mdiobus_read(bus, sw_addr, SMI_DATA); |
71 | if (ret < 0) | 72 | if (ret < 0) |
72 | return ret; | 73 | return ret; |
73 | 74 | ||
@@ -119,12 +120,13 @@ int __mv88e6xxx_reg_write(struct mii_bus *bus, int sw_addr, int addr, | |||
119 | return ret; | 120 | return ret; |
120 | 121 | ||
121 | /* Transmit the data to write. */ | 122 | /* Transmit the data to write. */ |
122 | ret = mdiobus_write(bus, sw_addr, 1, val); | 123 | ret = mdiobus_write(bus, sw_addr, SMI_DATA, val); |
123 | if (ret < 0) | 124 | if (ret < 0) |
124 | return ret; | 125 | return ret; |
125 | 126 | ||
126 | /* Transmit the write command. */ | 127 | /* Transmit the write command. */ |
127 | ret = mdiobus_write(bus, sw_addr, 0, 0x9400 | (addr << 5) | reg); | 128 | ret = mdiobus_write(bus, sw_addr, SMI_CMD, |
129 | SMI_CMD_OP_22_WRITE | (addr << 5) | reg); | ||
128 | if (ret < 0) | 130 | if (ret < 0) |
129 | return ret; | 131 | return ret; |
130 | 132 | ||
@@ -166,26 +168,26 @@ int mv88e6xxx_reg_write(struct dsa_switch *ds, int addr, int reg, u16 val) | |||
166 | int mv88e6xxx_config_prio(struct dsa_switch *ds) | 168 | int mv88e6xxx_config_prio(struct dsa_switch *ds) |
167 | { | 169 | { |
168 | /* Configure the IP ToS mapping registers. */ | 170 | /* Configure the IP ToS mapping registers. */ |
169 | REG_WRITE(REG_GLOBAL, 0x10, 0x0000); | 171 | REG_WRITE(REG_GLOBAL, GLOBAL_IP_PRI_0, 0x0000); |
170 | REG_WRITE(REG_GLOBAL, 0x11, 0x0000); | 172 | REG_WRITE(REG_GLOBAL, GLOBAL_IP_PRI_1, 0x0000); |
171 | REG_WRITE(REG_GLOBAL, 0x12, 0x5555); | 173 | REG_WRITE(REG_GLOBAL, GLOBAL_IP_PRI_2, 0x5555); |
172 | REG_WRITE(REG_GLOBAL, 0x13, 0x5555); | 174 | REG_WRITE(REG_GLOBAL, GLOBAL_IP_PRI_3, 0x5555); |
173 | REG_WRITE(REG_GLOBAL, 0x14, 0xaaaa); | 175 | REG_WRITE(REG_GLOBAL, GLOBAL_IP_PRI_4, 0xaaaa); |
174 | REG_WRITE(REG_GLOBAL, 0x15, 0xaaaa); | 176 | REG_WRITE(REG_GLOBAL, GLOBAL_IP_PRI_5, 0xaaaa); |
175 | REG_WRITE(REG_GLOBAL, 0x16, 0xffff); | 177 | REG_WRITE(REG_GLOBAL, GLOBAL_IP_PRI_6, 0xffff); |
176 | REG_WRITE(REG_GLOBAL, 0x17, 0xffff); | 178 | REG_WRITE(REG_GLOBAL, GLOBAL_IP_PRI_7, 0xffff); |
177 | 179 | ||
178 | /* Configure the IEEE 802.1p priority mapping register. */ | 180 | /* Configure the IEEE 802.1p priority mapping register. */ |
179 | REG_WRITE(REG_GLOBAL, 0x18, 0xfa41); | 181 | REG_WRITE(REG_GLOBAL, GLOBAL_IEEE_PRI, 0xfa41); |
180 | 182 | ||
181 | return 0; | 183 | return 0; |
182 | } | 184 | } |
183 | 185 | ||
184 | int mv88e6xxx_set_addr_direct(struct dsa_switch *ds, u8 *addr) | 186 | int mv88e6xxx_set_addr_direct(struct dsa_switch *ds, u8 *addr) |
185 | { | 187 | { |
186 | REG_WRITE(REG_GLOBAL, 0x01, (addr[0] << 8) | addr[1]); | 188 | REG_WRITE(REG_GLOBAL, GLOBAL_MAC_01, (addr[0] << 8) | addr[1]); |
187 | REG_WRITE(REG_GLOBAL, 0x02, (addr[2] << 8) | addr[3]); | 189 | REG_WRITE(REG_GLOBAL, GLOBAL_MAC_23, (addr[2] << 8) | addr[3]); |
188 | REG_WRITE(REG_GLOBAL, 0x03, (addr[4] << 8) | addr[5]); | 190 | REG_WRITE(REG_GLOBAL, GLOBAL_MAC_45, (addr[4] << 8) | addr[5]); |
189 | 191 | ||
190 | return 0; | 192 | return 0; |
191 | } | 193 | } |
@@ -199,12 +201,13 @@ int mv88e6xxx_set_addr_indirect(struct dsa_switch *ds, u8 *addr) | |||
199 | int j; | 201 | int j; |
200 | 202 | ||
201 | /* Write the MAC address byte. */ | 203 | /* Write the MAC address byte. */ |
202 | REG_WRITE(REG_GLOBAL2, 0x0d, 0x8000 | (i << 8) | addr[i]); | 204 | REG_WRITE(REG_GLOBAL2, GLOBAL2_SWITCH_MAC, |
205 | GLOBAL2_SWITCH_MAC_BUSY | (i << 8) | addr[i]); | ||
203 | 206 | ||
204 | /* Wait for the write to complete. */ | 207 | /* Wait for the write to complete. */ |
205 | for (j = 0; j < 16; j++) { | 208 | for (j = 0; j < 16; j++) { |
206 | ret = REG_READ(REG_GLOBAL2, 0x0d); | 209 | ret = REG_READ(REG_GLOBAL2, GLOBAL2_SWITCH_MAC); |
207 | if ((ret & 0x8000) == 0) | 210 | if ((ret & GLOBAL2_SWITCH_MAC_BUSY) == 0) |
208 | break; | 211 | break; |
209 | } | 212 | } |
210 | if (j == 16) | 213 | if (j == 16) |
@@ -214,14 +217,17 @@ int mv88e6xxx_set_addr_indirect(struct dsa_switch *ds, u8 *addr) | |||
214 | return 0; | 217 | return 0; |
215 | } | 218 | } |
216 | 219 | ||
217 | int mv88e6xxx_phy_read(struct dsa_switch *ds, int addr, int regnum) | 220 | /* Must be called with phy mutex held */ |
221 | static int _mv88e6xxx_phy_read(struct dsa_switch *ds, int addr, int regnum) | ||
218 | { | 222 | { |
219 | if (addr >= 0) | 223 | if (addr >= 0) |
220 | return mv88e6xxx_reg_read(ds, addr, regnum); | 224 | return mv88e6xxx_reg_read(ds, addr, regnum); |
221 | return 0xffff; | 225 | return 0xffff; |
222 | } | 226 | } |
223 | 227 | ||
224 | int mv88e6xxx_phy_write(struct dsa_switch *ds, int addr, int regnum, u16 val) | 228 | /* Must be called with phy mutex held */ |
229 | static int _mv88e6xxx_phy_write(struct dsa_switch *ds, int addr, int regnum, | ||
230 | u16 val) | ||
225 | { | 231 | { |
226 | if (addr >= 0) | 232 | if (addr >= 0) |
227 | return mv88e6xxx_reg_write(ds, addr, regnum, val); | 233 | return mv88e6xxx_reg_write(ds, addr, regnum, val); |
@@ -234,14 +240,16 @@ static int mv88e6xxx_ppu_disable(struct dsa_switch *ds) | |||
234 | int ret; | 240 | int ret; |
235 | unsigned long timeout; | 241 | unsigned long timeout; |
236 | 242 | ||
237 | ret = REG_READ(REG_GLOBAL, 0x04); | 243 | ret = REG_READ(REG_GLOBAL, GLOBAL_CONTROL); |
238 | REG_WRITE(REG_GLOBAL, 0x04, ret & ~0x4000); | 244 | REG_WRITE(REG_GLOBAL, GLOBAL_CONTROL, |
245 | ret & ~GLOBAL_CONTROL_PPU_ENABLE); | ||
239 | 246 | ||
240 | timeout = jiffies + 1 * HZ; | 247 | timeout = jiffies + 1 * HZ; |
241 | while (time_before(jiffies, timeout)) { | 248 | while (time_before(jiffies, timeout)) { |
242 | ret = REG_READ(REG_GLOBAL, 0x00); | 249 | ret = REG_READ(REG_GLOBAL, GLOBAL_STATUS); |
243 | usleep_range(1000, 2000); | 250 | usleep_range(1000, 2000); |
244 | if ((ret & 0xc000) != 0xc000) | 251 | if ((ret & GLOBAL_STATUS_PPU_MASK) != |
252 | GLOBAL_STATUS_PPU_POLLING) | ||
245 | return 0; | 253 | return 0; |
246 | } | 254 | } |
247 | 255 | ||
@@ -253,14 +261,15 @@ static int mv88e6xxx_ppu_enable(struct dsa_switch *ds) | |||
253 | int ret; | 261 | int ret; |
254 | unsigned long timeout; | 262 | unsigned long timeout; |
255 | 263 | ||
256 | ret = REG_READ(REG_GLOBAL, 0x04); | 264 | ret = REG_READ(REG_GLOBAL, GLOBAL_CONTROL); |
257 | REG_WRITE(REG_GLOBAL, 0x04, ret | 0x4000); | 265 | REG_WRITE(REG_GLOBAL, GLOBAL_CONTROL, ret | GLOBAL_CONTROL_PPU_ENABLE); |
258 | 266 | ||
259 | timeout = jiffies + 1 * HZ; | 267 | timeout = jiffies + 1 * HZ; |
260 | while (time_before(jiffies, timeout)) { | 268 | while (time_before(jiffies, timeout)) { |
261 | ret = REG_READ(REG_GLOBAL, 0x00); | 269 | ret = REG_READ(REG_GLOBAL, GLOBAL_STATUS); |
262 | usleep_range(1000, 2000); | 270 | usleep_range(1000, 2000); |
263 | if ((ret & 0xc000) == 0xc000) | 271 | if ((ret & GLOBAL_STATUS_PPU_MASK) == |
272 | GLOBAL_STATUS_PPU_POLLING) | ||
264 | return 0; | 273 | return 0; |
265 | } | 274 | } |
266 | 275 | ||
@@ -381,11 +390,12 @@ void mv88e6xxx_poll_link(struct dsa_switch *ds) | |||
381 | 390 | ||
382 | link = 0; | 391 | link = 0; |
383 | if (dev->flags & IFF_UP) { | 392 | if (dev->flags & IFF_UP) { |
384 | port_status = mv88e6xxx_reg_read(ds, REG_PORT(i), 0x00); | 393 | port_status = mv88e6xxx_reg_read(ds, REG_PORT(i), |
394 | PORT_STATUS); | ||
385 | if (port_status < 0) | 395 | if (port_status < 0) |
386 | continue; | 396 | continue; |
387 | 397 | ||
388 | link = !!(port_status & 0x0800); | 398 | link = !!(port_status & PORT_STATUS_LINK); |
389 | } | 399 | } |
390 | 400 | ||
391 | if (!link) { | 401 | if (!link) { |
@@ -396,22 +406,22 @@ void mv88e6xxx_poll_link(struct dsa_switch *ds) | |||
396 | continue; | 406 | continue; |
397 | } | 407 | } |
398 | 408 | ||
399 | switch (port_status & 0x0300) { | 409 | switch (port_status & PORT_STATUS_SPEED_MASK) { |
400 | case 0x0000: | 410 | case PORT_STATUS_SPEED_10: |
401 | speed = 10; | 411 | speed = 10; |
402 | break; | 412 | break; |
403 | case 0x0100: | 413 | case PORT_STATUS_SPEED_100: |
404 | speed = 100; | 414 | speed = 100; |
405 | break; | 415 | break; |
406 | case 0x0200: | 416 | case PORT_STATUS_SPEED_1000: |
407 | speed = 1000; | 417 | speed = 1000; |
408 | break; | 418 | break; |
409 | default: | 419 | default: |
410 | speed = -1; | 420 | speed = -1; |
411 | break; | 421 | break; |
412 | } | 422 | } |
413 | duplex = (port_status & 0x0400) ? 1 : 0; | 423 | duplex = (port_status & PORT_STATUS_DUPLEX) ? 1 : 0; |
414 | fc = (port_status & 0x8000) ? 1 : 0; | 424 | fc = (port_status & PORT_STATUS_PAUSE_EN) ? 1 : 0; |
415 | 425 | ||
416 | if (!netif_carrier_ok(dev)) { | 426 | if (!netif_carrier_ok(dev)) { |
417 | netdev_info(dev, | 427 | netdev_info(dev, |
@@ -424,14 +434,27 @@ void mv88e6xxx_poll_link(struct dsa_switch *ds) | |||
424 | } | 434 | } |
425 | } | 435 | } |
426 | 436 | ||
437 | static bool mv88e6xxx_6352_family(struct dsa_switch *ds) | ||
438 | { | ||
439 | struct mv88e6xxx_priv_state *ps = ds_to_priv(ds); | ||
440 | |||
441 | switch (ps->id) { | ||
442 | case PORT_SWITCH_ID_6352: | ||
443 | case PORT_SWITCH_ID_6172: | ||
444 | case PORT_SWITCH_ID_6176: | ||
445 | return true; | ||
446 | } | ||
447 | return false; | ||
448 | } | ||
449 | |||
427 | static int mv88e6xxx_stats_wait(struct dsa_switch *ds) | 450 | static int mv88e6xxx_stats_wait(struct dsa_switch *ds) |
428 | { | 451 | { |
429 | int ret; | 452 | int ret; |
430 | int i; | 453 | int i; |
431 | 454 | ||
432 | for (i = 0; i < 10; i++) { | 455 | for (i = 0; i < 10; i++) { |
433 | ret = REG_READ(REG_GLOBAL, 0x1d); | 456 | ret = REG_READ(REG_GLOBAL, GLOBAL_STATS_OP); |
434 | if ((ret & 0x8000) == 0) | 457 | if ((ret & GLOBAL_STATS_OP_BUSY) == 0) |
435 | return 0; | 458 | return 0; |
436 | } | 459 | } |
437 | 460 | ||
@@ -442,8 +465,13 @@ static int mv88e6xxx_stats_snapshot(struct dsa_switch *ds, int port) | |||
442 | { | 465 | { |
443 | int ret; | 466 | int ret; |
444 | 467 | ||
468 | if (mv88e6xxx_6352_family(ds)) | ||
469 | port = (port + 1) << 5; | ||
470 | |||
445 | /* Snapshot the hardware statistics counters for this port. */ | 471 | /* Snapshot the hardware statistics counters for this port. */ |
446 | REG_WRITE(REG_GLOBAL, 0x1d, 0xdc00 | port); | 472 | REG_WRITE(REG_GLOBAL, GLOBAL_STATS_OP, |
473 | GLOBAL_STATS_OP_CAPTURE_PORT | | ||
474 | GLOBAL_STATS_OP_HIST_RX_TX | port); | ||
447 | 475 | ||
448 | /* Wait for the snapshotting to complete. */ | 476 | /* Wait for the snapshotting to complete. */ |
449 | ret = mv88e6xxx_stats_wait(ds); | 477 | ret = mv88e6xxx_stats_wait(ds); |
@@ -460,7 +488,9 @@ static void mv88e6xxx_stats_read(struct dsa_switch *ds, int stat, u32 *val) | |||
460 | 488 | ||
461 | *val = 0; | 489 | *val = 0; |
462 | 490 | ||
463 | ret = mv88e6xxx_reg_write(ds, REG_GLOBAL, 0x1d, 0xcc00 | stat); | 491 | ret = mv88e6xxx_reg_write(ds, REG_GLOBAL, GLOBAL_STATS_OP, |
492 | GLOBAL_STATS_OP_READ_CAPTURED | | ||
493 | GLOBAL_STATS_OP_HIST_RX_TX | stat); | ||
464 | if (ret < 0) | 494 | if (ret < 0) |
465 | return; | 495 | return; |
466 | 496 | ||
@@ -468,22 +498,77 @@ static void mv88e6xxx_stats_read(struct dsa_switch *ds, int stat, u32 *val) | |||
468 | if (ret < 0) | 498 | if (ret < 0) |
469 | return; | 499 | return; |
470 | 500 | ||
471 | ret = mv88e6xxx_reg_read(ds, REG_GLOBAL, 0x1e); | 501 | ret = mv88e6xxx_reg_read(ds, REG_GLOBAL, GLOBAL_STATS_COUNTER_32); |
472 | if (ret < 0) | 502 | if (ret < 0) |
473 | return; | 503 | return; |
474 | 504 | ||
475 | _val = ret << 16; | 505 | _val = ret << 16; |
476 | 506 | ||
477 | ret = mv88e6xxx_reg_read(ds, REG_GLOBAL, 0x1f); | 507 | ret = mv88e6xxx_reg_read(ds, REG_GLOBAL, GLOBAL_STATS_COUNTER_01); |
478 | if (ret < 0) | 508 | if (ret < 0) |
479 | return; | 509 | return; |
480 | 510 | ||
481 | *val = _val | ret; | 511 | *val = _val | ret; |
482 | } | 512 | } |
483 | 513 | ||
484 | void mv88e6xxx_get_strings(struct dsa_switch *ds, | 514 | static struct mv88e6xxx_hw_stat mv88e6xxx_hw_stats[] = { |
485 | int nr_stats, struct mv88e6xxx_hw_stat *stats, | 515 | { "in_good_octets", 8, 0x00, }, |
486 | int port, uint8_t *data) | 516 | { "in_bad_octets", 4, 0x02, }, |
517 | { "in_unicast", 4, 0x04, }, | ||
518 | { "in_broadcasts", 4, 0x06, }, | ||
519 | { "in_multicasts", 4, 0x07, }, | ||
520 | { "in_pause", 4, 0x16, }, | ||
521 | { "in_undersize", 4, 0x18, }, | ||
522 | { "in_fragments", 4, 0x19, }, | ||
523 | { "in_oversize", 4, 0x1a, }, | ||
524 | { "in_jabber", 4, 0x1b, }, | ||
525 | { "in_rx_error", 4, 0x1c, }, | ||
526 | { "in_fcs_error", 4, 0x1d, }, | ||
527 | { "out_octets", 8, 0x0e, }, | ||
528 | { "out_unicast", 4, 0x10, }, | ||
529 | { "out_broadcasts", 4, 0x13, }, | ||
530 | { "out_multicasts", 4, 0x12, }, | ||
531 | { "out_pause", 4, 0x15, }, | ||
532 | { "excessive", 4, 0x11, }, | ||
533 | { "collisions", 4, 0x1e, }, | ||
534 | { "deferred", 4, 0x05, }, | ||
535 | { "single", 4, 0x14, }, | ||
536 | { "multiple", 4, 0x17, }, | ||
537 | { "out_fcs_error", 4, 0x03, }, | ||
538 | { "late", 4, 0x1f, }, | ||
539 | { "hist_64bytes", 4, 0x08, }, | ||
540 | { "hist_65_127bytes", 4, 0x09, }, | ||
541 | { "hist_128_255bytes", 4, 0x0a, }, | ||
542 | { "hist_256_511bytes", 4, 0x0b, }, | ||
543 | { "hist_512_1023bytes", 4, 0x0c, }, | ||
544 | { "hist_1024_max_bytes", 4, 0x0d, }, | ||
545 | /* Not all devices have the following counters */ | ||
546 | { "sw_in_discards", 4, 0x110, }, | ||
547 | { "sw_in_filtered", 2, 0x112, }, | ||
548 | { "sw_out_filtered", 2, 0x113, }, | ||
549 | |||
550 | }; | ||
551 | |||
552 | static bool have_sw_in_discards(struct dsa_switch *ds) | ||
553 | { | ||
554 | struct mv88e6xxx_priv_state *ps = ds_to_priv(ds); | ||
555 | |||
556 | switch (ps->id) { | ||
557 | case PORT_SWITCH_ID_6095: case PORT_SWITCH_ID_6161: | ||
558 | case PORT_SWITCH_ID_6165: case PORT_SWITCH_ID_6171: | ||
559 | case PORT_SWITCH_ID_6172: case PORT_SWITCH_ID_6176: | ||
560 | case PORT_SWITCH_ID_6182: case PORT_SWITCH_ID_6185: | ||
561 | case PORT_SWITCH_ID_6352: | ||
562 | return true; | ||
563 | default: | ||
564 | return false; | ||
565 | } | ||
566 | } | ||
567 | |||
568 | static void _mv88e6xxx_get_strings(struct dsa_switch *ds, | ||
569 | int nr_stats, | ||
570 | struct mv88e6xxx_hw_stat *stats, | ||
571 | int port, uint8_t *data) | ||
487 | { | 572 | { |
488 | int i; | 573 | int i; |
489 | 574 | ||
@@ -493,9 +578,10 @@ void mv88e6xxx_get_strings(struct dsa_switch *ds, | |||
493 | } | 578 | } |
494 | } | 579 | } |
495 | 580 | ||
496 | void mv88e6xxx_get_ethtool_stats(struct dsa_switch *ds, | 581 | static void _mv88e6xxx_get_ethtool_stats(struct dsa_switch *ds, |
497 | int nr_stats, struct mv88e6xxx_hw_stat *stats, | 582 | int nr_stats, |
498 | int port, uint64_t *data) | 583 | struct mv88e6xxx_hw_stat *stats, |
584 | int port, uint64_t *data) | ||
499 | { | 585 | { |
500 | struct mv88e6xxx_priv_state *ps = ds_to_priv(ds); | 586 | struct mv88e6xxx_priv_state *ps = ds_to_priv(ds); |
501 | int ret; | 587 | int ret; |
@@ -543,6 +629,39 @@ error: | |||
543 | mutex_unlock(&ps->stats_mutex); | 629 | mutex_unlock(&ps->stats_mutex); |
544 | } | 630 | } |
545 | 631 | ||
632 | /* All the statistics in the table */ | ||
633 | void | ||
634 | mv88e6xxx_get_strings(struct dsa_switch *ds, int port, uint8_t *data) | ||
635 | { | ||
636 | if (have_sw_in_discards(ds)) | ||
637 | _mv88e6xxx_get_strings(ds, ARRAY_SIZE(mv88e6xxx_hw_stats), | ||
638 | mv88e6xxx_hw_stats, port, data); | ||
639 | else | ||
640 | _mv88e6xxx_get_strings(ds, ARRAY_SIZE(mv88e6xxx_hw_stats) - 3, | ||
641 | mv88e6xxx_hw_stats, port, data); | ||
642 | } | ||
643 | |||
644 | int mv88e6xxx_get_sset_count(struct dsa_switch *ds) | ||
645 | { | ||
646 | if (have_sw_in_discards(ds)) | ||
647 | return ARRAY_SIZE(mv88e6xxx_hw_stats); | ||
648 | return ARRAY_SIZE(mv88e6xxx_hw_stats) - 3; | ||
649 | } | ||
650 | |||
651 | void | ||
652 | mv88e6xxx_get_ethtool_stats(struct dsa_switch *ds, | ||
653 | int port, uint64_t *data) | ||
654 | { | ||
655 | if (have_sw_in_discards(ds)) | ||
656 | _mv88e6xxx_get_ethtool_stats( | ||
657 | ds, ARRAY_SIZE(mv88e6xxx_hw_stats), | ||
658 | mv88e6xxx_hw_stats, port, data); | ||
659 | else | ||
660 | _mv88e6xxx_get_ethtool_stats( | ||
661 | ds, ARRAY_SIZE(mv88e6xxx_hw_stats) - 3, | ||
662 | mv88e6xxx_hw_stats, port, data); | ||
663 | } | ||
664 | |||
546 | int mv88e6xxx_get_regs_len(struct dsa_switch *ds, int port) | 665 | int mv88e6xxx_get_regs_len(struct dsa_switch *ds, int port) |
547 | { | 666 | { |
548 | return 32 * sizeof(u16); | 667 | return 32 * sizeof(u16); |
@@ -579,37 +698,37 @@ int mv88e6xxx_get_temp(struct dsa_switch *ds, int *temp) | |||
579 | 698 | ||
580 | mutex_lock(&ps->phy_mutex); | 699 | mutex_lock(&ps->phy_mutex); |
581 | 700 | ||
582 | ret = mv88e6xxx_phy_write(ds, 0x0, 0x16, 0x6); | 701 | ret = _mv88e6xxx_phy_write(ds, 0x0, 0x16, 0x6); |
583 | if (ret < 0) | 702 | if (ret < 0) |
584 | goto error; | 703 | goto error; |
585 | 704 | ||
586 | /* Enable temperature sensor */ | 705 | /* Enable temperature sensor */ |
587 | ret = mv88e6xxx_phy_read(ds, 0x0, 0x1a); | 706 | ret = _mv88e6xxx_phy_read(ds, 0x0, 0x1a); |
588 | if (ret < 0) | 707 | if (ret < 0) |
589 | goto error; | 708 | goto error; |
590 | 709 | ||
591 | ret = mv88e6xxx_phy_write(ds, 0x0, 0x1a, ret | (1 << 5)); | 710 | ret = _mv88e6xxx_phy_write(ds, 0x0, 0x1a, ret | (1 << 5)); |
592 | if (ret < 0) | 711 | if (ret < 0) |
593 | goto error; | 712 | goto error; |
594 | 713 | ||
595 | /* Wait for temperature to stabilize */ | 714 | /* Wait for temperature to stabilize */ |
596 | usleep_range(10000, 12000); | 715 | usleep_range(10000, 12000); |
597 | 716 | ||
598 | val = mv88e6xxx_phy_read(ds, 0x0, 0x1a); | 717 | val = _mv88e6xxx_phy_read(ds, 0x0, 0x1a); |
599 | if (val < 0) { | 718 | if (val < 0) { |
600 | ret = val; | 719 | ret = val; |
601 | goto error; | 720 | goto error; |
602 | } | 721 | } |
603 | 722 | ||
604 | /* Disable temperature sensor */ | 723 | /* Disable temperature sensor */ |
605 | ret = mv88e6xxx_phy_write(ds, 0x0, 0x1a, ret & ~(1 << 5)); | 724 | ret = _mv88e6xxx_phy_write(ds, 0x0, 0x1a, ret & ~(1 << 5)); |
606 | if (ret < 0) | 725 | if (ret < 0) |
607 | goto error; | 726 | goto error; |
608 | 727 | ||
609 | *temp = ((val & 0x1f) - 5) * 5; | 728 | *temp = ((val & 0x1f) - 5) * 5; |
610 | 729 | ||
611 | error: | 730 | error: |
612 | mv88e6xxx_phy_write(ds, 0x0, 0x16, 0x0); | 731 | _mv88e6xxx_phy_write(ds, 0x0, 0x16, 0x0); |
613 | mutex_unlock(&ps->phy_mutex); | 732 | mutex_unlock(&ps->phy_mutex); |
614 | return ret; | 733 | return ret; |
615 | } | 734 | } |
@@ -633,17 +752,20 @@ static int mv88e6xxx_wait(struct dsa_switch *ds, int reg, int offset, u16 mask) | |||
633 | 752 | ||
634 | int mv88e6xxx_phy_wait(struct dsa_switch *ds) | 753 | int mv88e6xxx_phy_wait(struct dsa_switch *ds) |
635 | { | 754 | { |
636 | return mv88e6xxx_wait(ds, REG_GLOBAL2, 0x18, 0x8000); | 755 | return mv88e6xxx_wait(ds, REG_GLOBAL2, GLOBAL2_SMI_OP, |
756 | GLOBAL2_SMI_OP_BUSY); | ||
637 | } | 757 | } |
638 | 758 | ||
639 | int mv88e6xxx_eeprom_load_wait(struct dsa_switch *ds) | 759 | int mv88e6xxx_eeprom_load_wait(struct dsa_switch *ds) |
640 | { | 760 | { |
641 | return mv88e6xxx_wait(ds, REG_GLOBAL2, 0x14, 0x0800); | 761 | return mv88e6xxx_wait(ds, REG_GLOBAL2, GLOBAL2_EEPROM_OP, |
762 | GLOBAL2_EEPROM_OP_LOAD); | ||
642 | } | 763 | } |
643 | 764 | ||
644 | int mv88e6xxx_eeprom_busy_wait(struct dsa_switch *ds) | 765 | int mv88e6xxx_eeprom_busy_wait(struct dsa_switch *ds) |
645 | { | 766 | { |
646 | return mv88e6xxx_wait(ds, REG_GLOBAL2, 0x14, 0x8000); | 767 | return mv88e6xxx_wait(ds, REG_GLOBAL2, GLOBAL2_EEPROM_OP, |
768 | GLOBAL2_EEPROM_OP_BUSY); | ||
647 | } | 769 | } |
648 | 770 | ||
649 | /* Must be called with SMI lock held */ | 771 | /* Must be called with SMI lock held */ |
@@ -668,80 +790,87 @@ static int _mv88e6xxx_wait(struct dsa_switch *ds, int reg, int offset, u16 mask) | |||
668 | /* Must be called with SMI lock held */ | 790 | /* Must be called with SMI lock held */ |
669 | static int _mv88e6xxx_atu_wait(struct dsa_switch *ds) | 791 | static int _mv88e6xxx_atu_wait(struct dsa_switch *ds) |
670 | { | 792 | { |
671 | return _mv88e6xxx_wait(ds, REG_GLOBAL, 0x0b, ATU_BUSY); | 793 | return _mv88e6xxx_wait(ds, REG_GLOBAL, GLOBAL_ATU_OP, |
794 | GLOBAL_ATU_OP_BUSY); | ||
672 | } | 795 | } |
673 | 796 | ||
674 | int mv88e6xxx_phy_read_indirect(struct dsa_switch *ds, int addr, int regnum) | 797 | /* Must be called with phy mutex held */ |
798 | static int _mv88e6xxx_phy_read_indirect(struct dsa_switch *ds, int addr, | ||
799 | int regnum) | ||
675 | { | 800 | { |
676 | int ret; | 801 | int ret; |
677 | 802 | ||
678 | REG_WRITE(REG_GLOBAL2, 0x18, 0x9800 | (addr << 5) | regnum); | 803 | REG_WRITE(REG_GLOBAL2, GLOBAL2_SMI_OP, |
804 | GLOBAL2_SMI_OP_22_READ | (addr << 5) | regnum); | ||
679 | 805 | ||
680 | ret = mv88e6xxx_phy_wait(ds); | 806 | ret = mv88e6xxx_phy_wait(ds); |
681 | if (ret < 0) | 807 | if (ret < 0) |
682 | return ret; | 808 | return ret; |
683 | 809 | ||
684 | return REG_READ(REG_GLOBAL2, 0x19); | 810 | return REG_READ(REG_GLOBAL2, GLOBAL2_SMI_DATA); |
685 | } | 811 | } |
686 | 812 | ||
687 | int mv88e6xxx_phy_write_indirect(struct dsa_switch *ds, int addr, int regnum, | 813 | /* Must be called with phy mutex held */ |
688 | u16 val) | 814 | static int _mv88e6xxx_phy_write_indirect(struct dsa_switch *ds, int addr, |
815 | int regnum, u16 val) | ||
689 | { | 816 | { |
690 | REG_WRITE(REG_GLOBAL2, 0x19, val); | 817 | REG_WRITE(REG_GLOBAL2, GLOBAL2_SMI_DATA, val); |
691 | REG_WRITE(REG_GLOBAL2, 0x18, 0x9400 | (addr << 5) | regnum); | 818 | REG_WRITE(REG_GLOBAL2, GLOBAL2_SMI_OP, |
819 | GLOBAL2_SMI_OP_22_WRITE | (addr << 5) | regnum); | ||
692 | 820 | ||
693 | return mv88e6xxx_phy_wait(ds); | 821 | return mv88e6xxx_phy_wait(ds); |
694 | } | 822 | } |
695 | 823 | ||
696 | int mv88e6xxx_get_eee(struct dsa_switch *ds, int port, struct ethtool_eee *e) | 824 | int mv88e6xxx_get_eee(struct dsa_switch *ds, int port, struct ethtool_eee *e) |
697 | { | 825 | { |
826 | struct mv88e6xxx_priv_state *ps = ds_to_priv(ds); | ||
698 | int reg; | 827 | int reg; |
699 | 828 | ||
700 | reg = mv88e6xxx_phy_read_indirect(ds, port, 16); | 829 | mutex_lock(&ps->phy_mutex); |
830 | |||
831 | reg = _mv88e6xxx_phy_read_indirect(ds, port, 16); | ||
701 | if (reg < 0) | 832 | if (reg < 0) |
702 | return -EOPNOTSUPP; | 833 | goto out; |
703 | 834 | ||
704 | e->eee_enabled = !!(reg & 0x0200); | 835 | e->eee_enabled = !!(reg & 0x0200); |
705 | e->tx_lpi_enabled = !!(reg & 0x0100); | 836 | e->tx_lpi_enabled = !!(reg & 0x0100); |
706 | 837 | ||
707 | reg = REG_READ(REG_PORT(port), 0); | 838 | reg = mv88e6xxx_reg_read(ds, REG_PORT(port), PORT_STATUS); |
708 | e->eee_active = !!(reg & 0x0040); | ||
709 | |||
710 | return 0; | ||
711 | } | ||
712 | |||
713 | static int mv88e6xxx_eee_enable_set(struct dsa_switch *ds, int port, | ||
714 | bool eee_enabled, bool tx_lpi_enabled) | ||
715 | { | ||
716 | int reg, nreg; | ||
717 | |||
718 | reg = mv88e6xxx_phy_read_indirect(ds, port, 16); | ||
719 | if (reg < 0) | 839 | if (reg < 0) |
720 | return reg; | 840 | goto out; |
721 | |||
722 | nreg = reg & ~0x0300; | ||
723 | if (eee_enabled) | ||
724 | nreg |= 0x0200; | ||
725 | if (tx_lpi_enabled) | ||
726 | nreg |= 0x0100; | ||
727 | 841 | ||
728 | if (nreg != reg) | 842 | e->eee_active = !!(reg & PORT_STATUS_EEE); |
729 | return mv88e6xxx_phy_write_indirect(ds, port, 16, nreg); | 843 | reg = 0; |
730 | 844 | ||
731 | return 0; | 845 | out: |
846 | mutex_unlock(&ps->phy_mutex); | ||
847 | return reg; | ||
732 | } | 848 | } |
733 | 849 | ||
734 | int mv88e6xxx_set_eee(struct dsa_switch *ds, int port, | 850 | int mv88e6xxx_set_eee(struct dsa_switch *ds, int port, |
735 | struct phy_device *phydev, struct ethtool_eee *e) | 851 | struct phy_device *phydev, struct ethtool_eee *e) |
736 | { | 852 | { |
853 | struct mv88e6xxx_priv_state *ps = ds_to_priv(ds); | ||
854 | int reg; | ||
737 | int ret; | 855 | int ret; |
738 | 856 | ||
739 | ret = mv88e6xxx_eee_enable_set(ds, port, e->eee_enabled, | 857 | mutex_lock(&ps->phy_mutex); |
740 | e->tx_lpi_enabled); | ||
741 | if (ret) | ||
742 | return -EOPNOTSUPP; | ||
743 | 858 | ||
744 | return 0; | 859 | ret = _mv88e6xxx_phy_read_indirect(ds, port, 16); |
860 | if (ret < 0) | ||
861 | goto out; | ||
862 | |||
863 | reg = ret & ~0x0300; | ||
864 | if (e->eee_enabled) | ||
865 | reg |= 0x0200; | ||
866 | if (e->tx_lpi_enabled) | ||
867 | reg |= 0x0100; | ||
868 | |||
869 | ret = _mv88e6xxx_phy_write_indirect(ds, port, 16, reg); | ||
870 | out: | ||
871 | mutex_unlock(&ps->phy_mutex); | ||
872 | |||
873 | return ret; | ||
745 | } | 874 | } |
746 | 875 | ||
747 | static int _mv88e6xxx_atu_cmd(struct dsa_switch *ds, int fid, u16 cmd) | 876 | static int _mv88e6xxx_atu_cmd(struct dsa_switch *ds, int fid, u16 cmd) |
@@ -752,7 +881,7 @@ static int _mv88e6xxx_atu_cmd(struct dsa_switch *ds, int fid, u16 cmd) | |||
752 | if (ret < 0) | 881 | if (ret < 0) |
753 | return ret; | 882 | return ret; |
754 | 883 | ||
755 | ret = _mv88e6xxx_reg_write(ds, REG_GLOBAL, 0x0b, cmd); | 884 | ret = _mv88e6xxx_reg_write(ds, REG_GLOBAL, GLOBAL_ATU_OP, cmd); |
756 | if (ret < 0) | 885 | if (ret < 0) |
757 | return ret; | 886 | return ret; |
758 | 887 | ||
@@ -767,7 +896,7 @@ static int _mv88e6xxx_flush_fid(struct dsa_switch *ds, int fid) | |||
767 | if (ret < 0) | 896 | if (ret < 0) |
768 | return ret; | 897 | return ret; |
769 | 898 | ||
770 | return _mv88e6xxx_atu_cmd(ds, fid, ATU_CMD_FLUSH_NONSTATIC_FID); | 899 | return _mv88e6xxx_atu_cmd(ds, fid, GLOBAL_ATU_OP_FLUSH_NON_STATIC_DB); |
771 | } | 900 | } |
772 | 901 | ||
773 | static int mv88e6xxx_set_port_state(struct dsa_switch *ds, int port, u8 state) | 902 | static int mv88e6xxx_set_port_state(struct dsa_switch *ds, int port, u8 state) |
@@ -778,23 +907,25 @@ static int mv88e6xxx_set_port_state(struct dsa_switch *ds, int port, u8 state) | |||
778 | 907 | ||
779 | mutex_lock(&ps->smi_mutex); | 908 | mutex_lock(&ps->smi_mutex); |
780 | 909 | ||
781 | reg = _mv88e6xxx_reg_read(ds, REG_PORT(port), 0x04); | 910 | reg = _mv88e6xxx_reg_read(ds, REG_PORT(port), PORT_CONTROL); |
782 | if (reg < 0) | 911 | if (reg < 0) |
783 | goto abort; | 912 | goto abort; |
784 | 913 | ||
785 | oldstate = reg & PSTATE_MASK; | 914 | oldstate = reg & PORT_CONTROL_STATE_MASK; |
786 | if (oldstate != state) { | 915 | if (oldstate != state) { |
787 | /* Flush forwarding database if we're moving a port | 916 | /* Flush forwarding database if we're moving a port |
788 | * from Learning or Forwarding state to Disabled or | 917 | * from Learning or Forwarding state to Disabled or |
789 | * Blocking or Listening state. | 918 | * Blocking or Listening state. |
790 | */ | 919 | */ |
791 | if (oldstate >= PSTATE_LEARNING && state <= PSTATE_BLOCKING) { | 920 | if (oldstate >= PORT_CONTROL_STATE_LEARNING && |
921 | state <= PORT_CONTROL_STATE_BLOCKING) { | ||
792 | ret = _mv88e6xxx_flush_fid(ds, ps->fid[port]); | 922 | ret = _mv88e6xxx_flush_fid(ds, ps->fid[port]); |
793 | if (ret) | 923 | if (ret) |
794 | goto abort; | 924 | goto abort; |
795 | } | 925 | } |
796 | reg = (reg & ~PSTATE_MASK) | state; | 926 | reg = (reg & ~PORT_CONTROL_STATE_MASK) | state; |
797 | ret = _mv88e6xxx_reg_write(ds, REG_PORT(port), 0x04, reg); | 927 | ret = _mv88e6xxx_reg_write(ds, REG_PORT(port), PORT_CONTROL, |
928 | reg); | ||
798 | } | 929 | } |
799 | 930 | ||
800 | abort: | 931 | abort: |
@@ -815,7 +946,7 @@ static int _mv88e6xxx_update_port_config(struct dsa_switch *ds, int port) | |||
815 | reg |= (ps->bridge_mask[fid] | | 946 | reg |= (ps->bridge_mask[fid] | |
816 | (1 << dsa_upstream_port(ds))) & ~(1 << port); | 947 | (1 << dsa_upstream_port(ds))) & ~(1 << port); |
817 | 948 | ||
818 | return _mv88e6xxx_reg_write(ds, REG_PORT(port), 0x06, reg); | 949 | return _mv88e6xxx_reg_write(ds, REG_PORT(port), PORT_BASE_VLAN, reg); |
819 | } | 950 | } |
820 | 951 | ||
821 | /* Must be called with smi lock held */ | 952 | /* Must be called with smi lock held */ |
@@ -927,18 +1058,18 @@ int mv88e6xxx_port_stp_update(struct dsa_switch *ds, int port, u8 state) | |||
927 | 1058 | ||
928 | switch (state) { | 1059 | switch (state) { |
929 | case BR_STATE_DISABLED: | 1060 | case BR_STATE_DISABLED: |
930 | stp_state = PSTATE_DISABLED; | 1061 | stp_state = PORT_CONTROL_STATE_DISABLED; |
931 | break; | 1062 | break; |
932 | case BR_STATE_BLOCKING: | 1063 | case BR_STATE_BLOCKING: |
933 | case BR_STATE_LISTENING: | 1064 | case BR_STATE_LISTENING: |
934 | stp_state = PSTATE_BLOCKING; | 1065 | stp_state = PORT_CONTROL_STATE_BLOCKING; |
935 | break; | 1066 | break; |
936 | case BR_STATE_LEARNING: | 1067 | case BR_STATE_LEARNING: |
937 | stp_state = PSTATE_LEARNING; | 1068 | stp_state = PORT_CONTROL_STATE_LEARNING; |
938 | break; | 1069 | break; |
939 | case BR_STATE_FORWARDING: | 1070 | case BR_STATE_FORWARDING: |
940 | default: | 1071 | default: |
941 | stp_state = PSTATE_FORWARDING; | 1072 | stp_state = PORT_CONTROL_STATE_FORWARDING; |
942 | break; | 1073 | break; |
943 | } | 1074 | } |
944 | 1075 | ||
@@ -960,8 +1091,9 @@ static int __mv88e6xxx_write_addr(struct dsa_switch *ds, | |||
960 | int i, ret; | 1091 | int i, ret; |
961 | 1092 | ||
962 | for (i = 0; i < 3; i++) { | 1093 | for (i = 0; i < 3; i++) { |
963 | ret = _mv88e6xxx_reg_write(ds, REG_GLOBAL, 0x0d + i, | 1094 | ret = _mv88e6xxx_reg_write( |
964 | (addr[i * 2] << 8) | addr[i * 2 + 1]); | 1095 | ds, REG_GLOBAL, GLOBAL_ATU_MAC_01 + i, |
1096 | (addr[i * 2] << 8) | addr[i * 2 + 1]); | ||
965 | if (ret < 0) | 1097 | if (ret < 0) |
966 | return ret; | 1098 | return ret; |
967 | } | 1099 | } |
@@ -974,7 +1106,8 @@ static int __mv88e6xxx_read_addr(struct dsa_switch *ds, unsigned char *addr) | |||
974 | int i, ret; | 1106 | int i, ret; |
975 | 1107 | ||
976 | for (i = 0; i < 3; i++) { | 1108 | for (i = 0; i < 3; i++) { |
977 | ret = _mv88e6xxx_reg_read(ds, REG_GLOBAL, 0x0d + i); | 1109 | ret = _mv88e6xxx_reg_read(ds, REG_GLOBAL, |
1110 | GLOBAL_ATU_MAC_01 + i); | ||
978 | if (ret < 0) | 1111 | if (ret < 0) |
979 | return ret; | 1112 | return ret; |
980 | addr[i * 2] = ret >> 8; | 1113 | addr[i * 2] = ret >> 8; |
@@ -999,12 +1132,12 @@ static int __mv88e6xxx_port_fdb_cmd(struct dsa_switch *ds, int port, | |||
999 | if (ret < 0) | 1132 | if (ret < 0) |
1000 | return ret; | 1133 | return ret; |
1001 | 1134 | ||
1002 | ret = _mv88e6xxx_reg_write(ds, REG_GLOBAL, 0x0c, | 1135 | ret = _mv88e6xxx_reg_write(ds, REG_GLOBAL, GLOBAL_ATU_DATA, |
1003 | (0x10 << port) | state); | 1136 | (0x10 << port) | state); |
1004 | if (ret) | 1137 | if (ret) |
1005 | return ret; | 1138 | return ret; |
1006 | 1139 | ||
1007 | ret = _mv88e6xxx_atu_cmd(ds, fid, ATU_CMD_LOAD_FID); | 1140 | ret = _mv88e6xxx_atu_cmd(ds, fid, GLOBAL_ATU_OP_LOAD_DB); |
1008 | 1141 | ||
1009 | return ret; | 1142 | return ret; |
1010 | } | 1143 | } |
@@ -1013,7 +1146,8 @@ int mv88e6xxx_port_fdb_add(struct dsa_switch *ds, int port, | |||
1013 | const unsigned char *addr, u16 vid) | 1146 | const unsigned char *addr, u16 vid) |
1014 | { | 1147 | { |
1015 | int state = is_multicast_ether_addr(addr) ? | 1148 | int state = is_multicast_ether_addr(addr) ? |
1016 | FDB_STATE_MC_STATIC : FDB_STATE_STATIC; | 1149 | GLOBAL_ATU_DATA_STATE_MC_STATIC : |
1150 | GLOBAL_ATU_DATA_STATE_UC_STATIC; | ||
1017 | struct mv88e6xxx_priv_state *ps = ds_to_priv(ds); | 1151 | struct mv88e6xxx_priv_state *ps = ds_to_priv(ds); |
1018 | int ret; | 1152 | int ret; |
1019 | 1153 | ||
@@ -1031,7 +1165,8 @@ int mv88e6xxx_port_fdb_del(struct dsa_switch *ds, int port, | |||
1031 | int ret; | 1165 | int ret; |
1032 | 1166 | ||
1033 | mutex_lock(&ps->smi_mutex); | 1167 | mutex_lock(&ps->smi_mutex); |
1034 | ret = __mv88e6xxx_port_fdb_cmd(ds, port, addr, FDB_STATE_UNUSED); | 1168 | ret = __mv88e6xxx_port_fdb_cmd(ds, port, addr, |
1169 | GLOBAL_ATU_DATA_STATE_UNUSED); | ||
1035 | mutex_unlock(&ps->smi_mutex); | 1170 | mutex_unlock(&ps->smi_mutex); |
1036 | 1171 | ||
1037 | return ret; | 1172 | return ret; |
@@ -1053,15 +1188,15 @@ static int __mv88e6xxx_port_getnext(struct dsa_switch *ds, int port, | |||
1053 | return ret; | 1188 | return ret; |
1054 | 1189 | ||
1055 | do { | 1190 | do { |
1056 | ret = _mv88e6xxx_atu_cmd(ds, fid, ATU_CMD_GETNEXT_FID); | 1191 | ret = _mv88e6xxx_atu_cmd(ds, fid, GLOBAL_ATU_OP_GET_NEXT_DB); |
1057 | if (ret < 0) | 1192 | if (ret < 0) |
1058 | return ret; | 1193 | return ret; |
1059 | 1194 | ||
1060 | ret = _mv88e6xxx_reg_read(ds, REG_GLOBAL, 0x0c); | 1195 | ret = _mv88e6xxx_reg_read(ds, REG_GLOBAL, GLOBAL_ATU_DATA); |
1061 | if (ret < 0) | 1196 | if (ret < 0) |
1062 | return ret; | 1197 | return ret; |
1063 | state = ret & FDB_STATE_MASK; | 1198 | state = ret & GLOBAL_ATU_DATA_STATE_MASK; |
1064 | if (state == FDB_STATE_UNUSED) | 1199 | if (state == GLOBAL_ATU_DATA_STATE_UNUSED) |
1065 | return -ENOENT; | 1200 | return -ENOENT; |
1066 | } while (!(((ret >> 4) & 0xff) & (1 << port))); | 1201 | } while (!(((ret >> 4) & 0xff) & (1 << port))); |
1067 | 1202 | ||
@@ -1070,7 +1205,8 @@ static int __mv88e6xxx_port_getnext(struct dsa_switch *ds, int port, | |||
1070 | return ret; | 1205 | return ret; |
1071 | 1206 | ||
1072 | *is_static = state == (is_multicast_ether_addr(addr) ? | 1207 | *is_static = state == (is_multicast_ether_addr(addr) ? |
1073 | FDB_STATE_MC_STATIC : FDB_STATE_STATIC); | 1208 | GLOBAL_ATU_DATA_STATE_MC_STATIC : |
1209 | GLOBAL_ATU_DATA_STATE_UC_STATIC); | ||
1074 | 1210 | ||
1075 | return 0; | 1211 | return 0; |
1076 | } | 1212 | } |
@@ -1115,7 +1251,8 @@ int mv88e6xxx_setup_port_common(struct dsa_switch *ds, int port) | |||
1115 | /* Port Control 1: disable trunking, disable sending | 1251 | /* Port Control 1: disable trunking, disable sending |
1116 | * learning messages to this port. | 1252 | * learning messages to this port. |
1117 | */ | 1253 | */ |
1118 | ret = _mv88e6xxx_reg_write(ds, REG_PORT(port), 0x05, 0x0000); | 1254 | ret = _mv88e6xxx_reg_write(ds, REG_PORT(port), PORT_DEFAULT_VLAN, |
1255 | 0x0000); | ||
1119 | if (ret) | 1256 | if (ret) |
1120 | goto abort; | 1257 | goto abort; |
1121 | 1258 | ||
@@ -1152,7 +1289,7 @@ int mv88e6xxx_setup_common(struct dsa_switch *ds) | |||
1152 | mutex_init(&ps->stats_mutex); | 1289 | mutex_init(&ps->stats_mutex); |
1153 | mutex_init(&ps->phy_mutex); | 1290 | mutex_init(&ps->phy_mutex); |
1154 | 1291 | ||
1155 | ps->id = REG_READ(REG_PORT(0), 0x03) & 0xfff0; | 1292 | ps->id = REG_READ(REG_PORT(0), PORT_SWITCH_ID) & 0xfff0; |
1156 | 1293 | ||
1157 | ps->fid_mask = (1 << DSA_MAX_PORTS) - 1; | 1294 | ps->fid_mask = (1 << DSA_MAX_PORTS) - 1; |
1158 | 1295 | ||
@@ -1161,6 +1298,154 @@ int mv88e6xxx_setup_common(struct dsa_switch *ds) | |||
1161 | return 0; | 1298 | return 0; |
1162 | } | 1299 | } |
1163 | 1300 | ||
1301 | int mv88e6xxx_switch_reset(struct dsa_switch *ds, bool ppu_active) | ||
1302 | { | ||
1303 | struct mv88e6xxx_priv_state *ps = ds_to_priv(ds); | ||
1304 | u16 is_reset = (ppu_active ? 0x8800 : 0xc800); | ||
1305 | unsigned long timeout; | ||
1306 | int ret; | ||
1307 | int i; | ||
1308 | |||
1309 | /* Set all ports to the disabled state. */ | ||
1310 | for (i = 0; i < ps->num_ports; i++) { | ||
1311 | ret = REG_READ(REG_PORT(i), PORT_CONTROL); | ||
1312 | REG_WRITE(REG_PORT(i), PORT_CONTROL, ret & 0xfffc); | ||
1313 | } | ||
1314 | |||
1315 | /* Wait for transmit queues to drain. */ | ||
1316 | usleep_range(2000, 4000); | ||
1317 | |||
1318 | /* Reset the switch. Keep the PPU active if requested. The PPU | ||
1319 | * needs to be active to support indirect phy register access | ||
1320 | * through global registers 0x18 and 0x19. | ||
1321 | */ | ||
1322 | if (ppu_active) | ||
1323 | REG_WRITE(REG_GLOBAL, 0x04, 0xc000); | ||
1324 | else | ||
1325 | REG_WRITE(REG_GLOBAL, 0x04, 0xc400); | ||
1326 | |||
1327 | /* Wait up to one second for reset to complete. */ | ||
1328 | timeout = jiffies + 1 * HZ; | ||
1329 | while (time_before(jiffies, timeout)) { | ||
1330 | ret = REG_READ(REG_GLOBAL, 0x00); | ||
1331 | if ((ret & is_reset) == is_reset) | ||
1332 | break; | ||
1333 | usleep_range(1000, 2000); | ||
1334 | } | ||
1335 | if (time_after(jiffies, timeout)) | ||
1336 | return -ETIMEDOUT; | ||
1337 | |||
1338 | return 0; | ||
1339 | } | ||
1340 | |||
1341 | int mv88e6xxx_phy_page_read(struct dsa_switch *ds, int port, int page, int reg) | ||
1342 | { | ||
1343 | struct mv88e6xxx_priv_state *ps = ds_to_priv(ds); | ||
1344 | int ret; | ||
1345 | |||
1346 | mutex_lock(&ps->phy_mutex); | ||
1347 | ret = _mv88e6xxx_phy_write_indirect(ds, port, 0x16, page); | ||
1348 | if (ret < 0) | ||
1349 | goto error; | ||
1350 | ret = _mv88e6xxx_phy_read_indirect(ds, port, reg); | ||
1351 | error: | ||
1352 | _mv88e6xxx_phy_write_indirect(ds, port, 0x16, 0x0); | ||
1353 | mutex_unlock(&ps->phy_mutex); | ||
1354 | return ret; | ||
1355 | } | ||
1356 | |||
1357 | int mv88e6xxx_phy_page_write(struct dsa_switch *ds, int port, int page, | ||
1358 | int reg, int val) | ||
1359 | { | ||
1360 | struct mv88e6xxx_priv_state *ps = ds_to_priv(ds); | ||
1361 | int ret; | ||
1362 | |||
1363 | mutex_lock(&ps->phy_mutex); | ||
1364 | ret = _mv88e6xxx_phy_write_indirect(ds, port, 0x16, page); | ||
1365 | if (ret < 0) | ||
1366 | goto error; | ||
1367 | |||
1368 | ret = _mv88e6xxx_phy_write_indirect(ds, port, reg, val); | ||
1369 | error: | ||
1370 | _mv88e6xxx_phy_write_indirect(ds, port, 0x16, 0x0); | ||
1371 | mutex_unlock(&ps->phy_mutex); | ||
1372 | return ret; | ||
1373 | } | ||
1374 | |||
1375 | static int mv88e6xxx_port_to_phy_addr(struct dsa_switch *ds, int port) | ||
1376 | { | ||
1377 | struct mv88e6xxx_priv_state *ps = ds_to_priv(ds); | ||
1378 | |||
1379 | if (port >= 0 && port < ps->num_ports) | ||
1380 | return port; | ||
1381 | return -EINVAL; | ||
1382 | } | ||
1383 | |||
1384 | int | ||
1385 | mv88e6xxx_phy_read(struct dsa_switch *ds, int port, int regnum) | ||
1386 | { | ||
1387 | struct mv88e6xxx_priv_state *ps = ds_to_priv(ds); | ||
1388 | int addr = mv88e6xxx_port_to_phy_addr(ds, port); | ||
1389 | int ret; | ||
1390 | |||
1391 | if (addr < 0) | ||
1392 | return addr; | ||
1393 | |||
1394 | mutex_lock(&ps->phy_mutex); | ||
1395 | ret = _mv88e6xxx_phy_read(ds, addr, regnum); | ||
1396 | mutex_unlock(&ps->phy_mutex); | ||
1397 | return ret; | ||
1398 | } | ||
1399 | |||
1400 | int | ||
1401 | mv88e6xxx_phy_write(struct dsa_switch *ds, int port, int regnum, u16 val) | ||
1402 | { | ||
1403 | struct mv88e6xxx_priv_state *ps = ds_to_priv(ds); | ||
1404 | int addr = mv88e6xxx_port_to_phy_addr(ds, port); | ||
1405 | int ret; | ||
1406 | |||
1407 | if (addr < 0) | ||
1408 | return addr; | ||
1409 | |||
1410 | mutex_lock(&ps->phy_mutex); | ||
1411 | ret = _mv88e6xxx_phy_write(ds, addr, regnum, val); | ||
1412 | mutex_unlock(&ps->phy_mutex); | ||
1413 | return ret; | ||
1414 | } | ||
1415 | |||
1416 | int | ||
1417 | mv88e6xxx_phy_read_indirect(struct dsa_switch *ds, int port, int regnum) | ||
1418 | { | ||
1419 | struct mv88e6xxx_priv_state *ps = ds_to_priv(ds); | ||
1420 | int addr = mv88e6xxx_port_to_phy_addr(ds, port); | ||
1421 | int ret; | ||
1422 | |||
1423 | if (addr < 0) | ||
1424 | return addr; | ||
1425 | |||
1426 | mutex_lock(&ps->phy_mutex); | ||
1427 | ret = _mv88e6xxx_phy_read_indirect(ds, addr, regnum); | ||
1428 | mutex_unlock(&ps->phy_mutex); | ||
1429 | return ret; | ||
1430 | } | ||
1431 | |||
1432 | int | ||
1433 | mv88e6xxx_phy_write_indirect(struct dsa_switch *ds, int port, int regnum, | ||
1434 | u16 val) | ||
1435 | { | ||
1436 | struct mv88e6xxx_priv_state *ps = ds_to_priv(ds); | ||
1437 | int addr = mv88e6xxx_port_to_phy_addr(ds, port); | ||
1438 | int ret; | ||
1439 | |||
1440 | if (addr < 0) | ||
1441 | return addr; | ||
1442 | |||
1443 | mutex_lock(&ps->phy_mutex); | ||
1444 | ret = _mv88e6xxx_phy_write_indirect(ds, addr, regnum, val); | ||
1445 | mutex_unlock(&ps->phy_mutex); | ||
1446 | return ret; | ||
1447 | } | ||
1448 | |||
1164 | static int __init mv88e6xxx_init(void) | 1449 | static int __init mv88e6xxx_init(void) |
1165 | { | 1450 | { |
1166 | #if IS_ENABLED(CONFIG_NET_DSA_MV88E6131) | 1451 | #if IS_ENABLED(CONFIG_NET_DSA_MV88E6131) |
diff --git a/drivers/net/dsa/mv88e6xxx.h b/drivers/net/dsa/mv88e6xxx.h index aaf239aba726..e045154f3364 100644 --- a/drivers/net/dsa/mv88e6xxx.h +++ b/drivers/net/dsa/mv88e6xxx.h | |||
@@ -11,33 +11,199 @@ | |||
11 | #ifndef __MV88E6XXX_H | 11 | #ifndef __MV88E6XXX_H |
12 | #define __MV88E6XXX_H | 12 | #define __MV88E6XXX_H |
13 | 13 | ||
14 | #define REG_PORT(p) (0x10 + (p)) | 14 | #define SMI_CMD 0x00 |
15 | #define REG_GLOBAL 0x1b | 15 | #define SMI_CMD_BUSY BIT(15) |
16 | #define REG_GLOBAL2 0x1c | 16 | #define SMI_CMD_CLAUSE_22 BIT(12) |
17 | 17 | #define SMI_CMD_OP_22_WRITE ((1 << 10) | SMI_CMD_BUSY | SMI_CMD_CLAUSE_22) | |
18 | /* ATU commands */ | 18 | #define SMI_CMD_OP_22_READ ((2 << 10) | SMI_CMD_BUSY | SMI_CMD_CLAUSE_22) |
19 | 19 | #define SMI_CMD_OP_45_WRITE_ADDR ((0 << 10) | SMI_CMD_BUSY) | |
20 | #define ATU_BUSY 0x8000 | 20 | #define SMI_CMD_OP_45_WRITE_DATA ((1 << 10) | SMI_CMD_BUSY) |
21 | 21 | #define SMI_CMD_OP_45_READ_DATA ((2 << 10) | SMI_CMD_BUSY) | |
22 | #define ATU_CMD_LOAD_FID (ATU_BUSY | 0x3000) | 22 | #define SMI_CMD_OP_45_READ_DATA_INC ((3 << 10) | SMI_CMD_BUSY) |
23 | #define ATU_CMD_GETNEXT_FID (ATU_BUSY | 0x4000) | 23 | #define SMI_DATA 0x01 |
24 | #define ATU_CMD_FLUSH_NONSTATIC_FID (ATU_BUSY | 0x6000) | ||
25 | |||
26 | /* port states */ | ||
27 | 24 | ||
28 | #define PSTATE_MASK 0x03 | 25 | #define REG_PORT(p) (0x10 + (p)) |
29 | #define PSTATE_DISABLED 0x00 | 26 | #define PORT_STATUS 0x00 |
30 | #define PSTATE_BLOCKING 0x01 | 27 | #define PORT_STATUS_PAUSE_EN BIT(15) |
31 | #define PSTATE_LEARNING 0x02 | 28 | #define PORT_STATUS_MY_PAUSE BIT(14) |
32 | #define PSTATE_FORWARDING 0x03 | 29 | #define PORT_STATUS_HD_FLOW BIT(13) |
33 | 30 | #define PORT_STATUS_PHY_DETECT BIT(12) | |
34 | /* FDB states */ | 31 | #define PORT_STATUS_LINK BIT(11) |
32 | #define PORT_STATUS_DUPLEX BIT(10) | ||
33 | #define PORT_STATUS_SPEED_MASK 0x0300 | ||
34 | #define PORT_STATUS_SPEED_10 0x0000 | ||
35 | #define PORT_STATUS_SPEED_100 0x0100 | ||
36 | #define PORT_STATUS_SPEED_1000 0x0200 | ||
37 | #define PORT_STATUS_EEE BIT(6) /* 6352 */ | ||
38 | #define PORT_STATUS_AM_DIS BIT(6) /* 6165 */ | ||
39 | #define PORT_STATUS_MGMII BIT(6) /* 6185 */ | ||
40 | #define PORT_STATUS_TX_PAUSED BIT(5) | ||
41 | #define PORT_STATUS_FLOW_CTRL BIT(4) | ||
42 | #define PORT_PCS_CTRL 0x01 | ||
43 | #define PORT_SWITCH_ID 0x03 | ||
44 | #define PORT_SWITCH_ID_6085 0x04a0 | ||
45 | #define PORT_SWITCH_ID_6095 0x0950 | ||
46 | #define PORT_SWITCH_ID_6123 0x1210 | ||
47 | #define PORT_SWITCH_ID_6123_A1 0x1212 | ||
48 | #define PORT_SWITCH_ID_6123_A2 0x1213 | ||
49 | #define PORT_SWITCH_ID_6131 0x1060 | ||
50 | #define PORT_SWITCH_ID_6131_B2 0x1066 | ||
51 | #define PORT_SWITCH_ID_6152 0x1a40 | ||
52 | #define PORT_SWITCH_ID_6155 0x1a50 | ||
53 | #define PORT_SWITCH_ID_6161 0x1610 | ||
54 | #define PORT_SWITCH_ID_6161_A1 0x1612 | ||
55 | #define PORT_SWITCH_ID_6161_A2 0x1613 | ||
56 | #define PORT_SWITCH_ID_6165 0x1650 | ||
57 | #define PORT_SWITCH_ID_6165_A1 0x1652 | ||
58 | #define PORT_SWITCH_ID_6165_A2 0x1653 | ||
59 | #define PORT_SWITCH_ID_6171 0x1710 | ||
60 | #define PORT_SWITCH_ID_6172 0x1720 | ||
61 | #define PORT_SWITCH_ID_6176 0x1760 | ||
62 | #define PORT_SWITCH_ID_6182 0x1a60 | ||
63 | #define PORT_SWITCH_ID_6185 0x1a70 | ||
64 | #define PORT_SWITCH_ID_6352 0x3520 | ||
65 | #define PORT_SWITCH_ID_6352_A0 0x3521 | ||
66 | #define PORT_SWITCH_ID_6352_A1 0x3522 | ||
67 | #define PORT_CONTROL 0x04 | ||
68 | #define PORT_CONTROL_STATE_MASK 0x03 | ||
69 | #define PORT_CONTROL_STATE_DISABLED 0x00 | ||
70 | #define PORT_CONTROL_STATE_BLOCKING 0x01 | ||
71 | #define PORT_CONTROL_STATE_LEARNING 0x02 | ||
72 | #define PORT_CONTROL_STATE_FORWARDING 0x03 | ||
73 | #define PORT_CONTROL_1 0x05 | ||
74 | #define PORT_BASE_VLAN 0x06 | ||
75 | #define PORT_DEFAULT_VLAN 0x07 | ||
76 | #define PORT_CONTROL_2 0x08 | ||
77 | #define PORT_RATE_CONTROL 0x09 | ||
78 | #define PORT_RATE_CONTROL_2 0x0a | ||
79 | #define PORT_ASSOC_VECTOR 0x0b | ||
80 | #define PORT_IN_DISCARD_LO 0x10 | ||
81 | #define PORT_IN_DISCARD_HI 0x11 | ||
82 | #define PORT_IN_FILTERED 0x12 | ||
83 | #define PORT_OUT_FILTERED 0x13 | ||
84 | #define PORT_TAG_REGMAP_0123 0x19 | ||
85 | #define PORT_TAG_REGMAP_4567 0x1a | ||
35 | 86 | ||
36 | #define FDB_STATE_MASK 0x0f | 87 | #define REG_GLOBAL 0x1b |
88 | #define GLOBAL_STATUS 0x00 | ||
89 | #define GLOBAL_STATUS_PPU_STATE BIT(15) /* 6351 and 6171 */ | ||
90 | /* Two bits for 6165, 6185 etc */ | ||
91 | #define GLOBAL_STATUS_PPU_MASK (0x3 << 14) | ||
92 | #define GLOBAL_STATUS_PPU_DISABLED_RST (0x0 << 14) | ||
93 | #define GLOBAL_STATUS_PPU_INITIALIZING (0x1 << 14) | ||
94 | #define GLOBAL_STATUS_PPU_DISABLED (0x2 << 14) | ||
95 | #define GLOBAL_STATUS_PPU_POLLING (0x3 << 14) | ||
96 | #define GLOBAL_MAC_01 0x01 | ||
97 | #define GLOBAL_MAC_23 0x02 | ||
98 | #define GLOBAL_MAC_45 0x03 | ||
99 | #define GLOBAL_CONTROL 0x04 | ||
100 | #define GLOBAL_CONTROL_SW_RESET BIT(15) | ||
101 | #define GLOBAL_CONTROL_PPU_ENABLE BIT(14) | ||
102 | #define GLOBAL_CONTROL_DISCARD_EXCESS BIT(13) /* 6352 */ | ||
103 | #define GLOBAL_CONTROL_SCHED_PRIO BIT(11) /* 6152 */ | ||
104 | #define GLOBAL_CONTROL_MAX_FRAME_1632 BIT(10) /* 6152 */ | ||
105 | #define GLOBAL_CONTROL_RELOAD_EEPROM BIT(9) /* 6152 */ | ||
106 | #define GLOBAL_CONTROL_DEVICE_EN BIT(7) | ||
107 | #define GLOBAL_CONTROL_STATS_DONE_EN BIT(6) | ||
108 | #define GLOBAL_CONTROL_VTU_PROBLEM_EN BIT(5) | ||
109 | #define GLOBAL_CONTROL_VTU_DONE_EN BIT(4) | ||
110 | #define GLOBAL_CONTROL_ATU_PROBLEM_EN BIT(3) | ||
111 | #define GLOBAL_CONTROL_ATU_DONE_EN BIT(2) | ||
112 | #define GLOBAL_CONTROL_TCAM_EN BIT(1) | ||
113 | #define GLOBAL_CONTROL_EEPROM_DONE_EN BIT(0) | ||
114 | #define GLOBAL_VTU_OP 0x05 | ||
115 | #define GLOBAL_VTU_VID 0x06 | ||
116 | #define GLOBAL_VTU_DATA_0_3 0x07 | ||
117 | #define GLOBAL_VTU_DATA_4_7 0x08 | ||
118 | #define GLOBAL_VTU_DATA_8_11 0x09 | ||
119 | #define GLOBAL_ATU_CONTROL 0x0a | ||
120 | #define GLOBAL_ATU_OP 0x0b | ||
121 | #define GLOBAL_ATU_OP_BUSY BIT(15) | ||
122 | #define GLOBAL_ATU_OP_NOP (0 << 12) | ||
123 | #define GLOBAL_ATU_OP_FLUSH_ALL ((1 << 12) | GLOBAL_ATU_OP_BUSY) | ||
124 | #define GLOBAL_ATU_OP_FLUSH_NON_STATIC ((2 << 12) | GLOBAL_ATU_OP_BUSY) | ||
125 | #define GLOBAL_ATU_OP_LOAD_DB ((3 << 12) | GLOBAL_ATU_OP_BUSY) | ||
126 | #define GLOBAL_ATU_OP_GET_NEXT_DB ((4 << 12) | GLOBAL_ATU_OP_BUSY) | ||
127 | #define GLOBAL_ATU_OP_FLUSH_DB ((5 << 12) | GLOBAL_ATU_OP_BUSY) | ||
128 | #define GLOBAL_ATU_OP_FLUSH_NON_STATIC_DB ((6 << 12) | GLOBAL_ATU_OP_BUSY) | ||
129 | #define GLOBAL_ATU_OP_GET_CLR_VIOLATION ((7 << 12) | GLOBAL_ATU_OP_BUSY) | ||
130 | #define GLOBAL_ATU_DATA 0x0c | ||
131 | #define GLOBAL_ATU_DATA_STATE_MASK 0x0f | ||
132 | #define GLOBAL_ATU_DATA_STATE_UNUSED 0x00 | ||
133 | #define GLOBAL_ATU_DATA_STATE_UC_MGMT 0x0d | ||
134 | #define GLOBAL_ATU_DATA_STATE_UC_STATIC 0x0e | ||
135 | #define GLOBAL_ATU_DATA_STATE_UC_PRIO_OVER 0x0f | ||
136 | #define GLOBAL_ATU_DATA_STATE_MC_NONE_RATE 0x05 | ||
137 | #define GLOBAL_ATU_DATA_STATE_MC_STATIC 0x07 | ||
138 | #define GLOBAL_ATU_DATA_STATE_MC_MGMT 0x0e | ||
139 | #define GLOBAL_ATU_DATA_STATE_MC_PRIO_OVER 0x0f | ||
140 | #define GLOBAL_ATU_MAC_01 0x0d | ||
141 | #define GLOBAL_ATU_MAC_23 0x0e | ||
142 | #define GLOBAL_ATU_MAC_45 0x0f | ||
143 | #define GLOBAL_IP_PRI_0 0x10 | ||
144 | #define GLOBAL_IP_PRI_1 0x11 | ||
145 | #define GLOBAL_IP_PRI_2 0x12 | ||
146 | #define GLOBAL_IP_PRI_3 0x13 | ||
147 | #define GLOBAL_IP_PRI_4 0x14 | ||
148 | #define GLOBAL_IP_PRI_5 0x15 | ||
149 | #define GLOBAL_IP_PRI_6 0x16 | ||
150 | #define GLOBAL_IP_PRI_7 0x17 | ||
151 | #define GLOBAL_IEEE_PRI 0x18 | ||
152 | #define GLOBAL_CORE_TAG_TYPE 0x19 | ||
153 | #define GLOBAL_MONITOR_CONTROL 0x1a | ||
154 | #define GLOBAL_CONTROL_2 0x1c | ||
155 | #define GLOBAL_STATS_OP 0x1d | ||
156 | #define GLOBAL_STATS_OP_BUSY BIT(15) | ||
157 | #define GLOBAL_STATS_OP_NOP (0 << 12) | ||
158 | #define GLOBAL_STATS_OP_FLUSH_ALL ((1 << 12) | GLOBAL_STATS_OP_BUSY) | ||
159 | #define GLOBAL_STATS_OP_FLUSH_PORT ((2 << 12) | GLOBAL_STATS_OP_BUSY) | ||
160 | #define GLOBAL_STATS_OP_READ_CAPTURED ((4 << 12) | GLOBAL_STATS_OP_BUSY) | ||
161 | #define GLOBAL_STATS_OP_CAPTURE_PORT ((5 << 12) | GLOBAL_STATS_OP_BUSY) | ||
162 | #define GLOBAL_STATS_OP_HIST_RX ((1 << 10) | GLOBAL_STATS_OP_BUSY) | ||
163 | #define GLOBAL_STATS_OP_HIST_TX ((2 << 10) | GLOBAL_STATS_OP_BUSY) | ||
164 | #define GLOBAL_STATS_OP_HIST_RX_TX ((3 << 10) | GLOBAL_STATS_OP_BUSY) | ||
165 | #define GLOBAL_STATS_COUNTER_32 0x1e | ||
166 | #define GLOBAL_STATS_COUNTER_01 0x1f | ||
37 | 167 | ||
38 | #define FDB_STATE_UNUSED 0x00 | 168 | #define REG_GLOBAL2 0x1c |
39 | #define FDB_STATE_MC_STATIC 0x07 /* static multicast */ | 169 | #define GLOBAL2_INT_SOURCE 0x00 |
40 | #define FDB_STATE_STATIC 0x0e /* static unicast */ | 170 | #define GLOBAL2_INT_MASK 0x01 |
171 | #define GLOBAL2_MGMT_EN_2X 0x02 | ||
172 | #define GLOBAL2_MGMT_EN_0X 0x03 | ||
173 | #define GLOBAL2_FLOW_CONTROL 0x04 | ||
174 | #define GLOBAL2_SWITCH_MGMT 0x05 | ||
175 | #define GLOBAL2_DEVICE_MAPPING 0x06 | ||
176 | #define GLOBAL2_TRUNK_MASK 0x07 | ||
177 | #define GLOBAL2_TRUNK_MAPPING 0x08 | ||
178 | #define GLOBAL2_INGRESS_OP 0x09 | ||
179 | #define GLOBAL2_INGRESS_DATA 0x0a | ||
180 | #define GLOBAL2_PVT_ADDR 0x0b | ||
181 | #define GLOBAL2_PVT_DATA 0x0c | ||
182 | #define GLOBAL2_SWITCH_MAC 0x0d | ||
183 | #define GLOBAL2_SWITCH_MAC_BUSY BIT(15) | ||
184 | #define GLOBAL2_ATU_STATS 0x0e | ||
185 | #define GLOBAL2_PRIO_OVERRIDE 0x0f | ||
186 | #define GLOBAL2_EEPROM_OP 0x14 | ||
187 | #define GLOBAL2_EEPROM_OP_BUSY BIT(15) | ||
188 | #define GLOBAL2_EEPROM_OP_LOAD BIT(11) | ||
189 | #define GLOBAL2_EEPROM_DATA 0x15 | ||
190 | #define GLOBAL2_PTP_AVB_OP 0x16 | ||
191 | #define GLOBAL2_PTP_AVB_DATA 0x17 | ||
192 | #define GLOBAL2_SMI_OP 0x18 | ||
193 | #define GLOBAL2_SMI_OP_BUSY BIT(15) | ||
194 | #define GLOBAL2_SMI_OP_CLAUSE_22 BIT(12) | ||
195 | #define GLOBAL2_SMI_OP_22_WRITE ((1 << 10) | GLOBAL2_SMI_OP_BUSY | \ | ||
196 | GLOBAL2_SMI_OP_CLAUSE_22) | ||
197 | #define GLOBAL2_SMI_OP_22_READ ((2 << 10) | GLOBAL2_SMI_OP_BUSY | \ | ||
198 | GLOBAL2_SMI_OP_CLAUSE_22) | ||
199 | #define GLOBAL2_SMI_OP_45_WRITE_ADDR ((0 << 10) | GLOBAL2_SMI_OP_BUSY) | ||
200 | #define GLOBAL2_SMI_OP_45_WRITE_DATA ((1 << 10) | GLOBAL2_SMI_OP_BUSY) | ||
201 | #define GLOBAL2_SMI_OP_45_READ_DATA ((2 << 10) | GLOBAL2_SMI_OP_BUSY) | ||
202 | #define GLOBAL2_SMI_DATA 0x19 | ||
203 | #define GLOBAL2_SCRATCH_MISC 0x1a | ||
204 | #define GLOBAL2_WDOG_CONTROL 0x1b | ||
205 | #define GLOBAL2_QOS_WEIGHT 0x1c | ||
206 | #define GLOBAL2_MISC 0x1d | ||
41 | 207 | ||
42 | struct mv88e6xxx_priv_state { | 208 | struct mv88e6xxx_priv_state { |
43 | /* When using multi-chip addressing, this mutex protects | 209 | /* When using multi-chip addressing, this mutex protects |
@@ -73,6 +239,7 @@ struct mv88e6xxx_priv_state { | |||
73 | struct mutex eeprom_mutex; | 239 | struct mutex eeprom_mutex; |
74 | 240 | ||
75 | int id; /* switch product id */ | 241 | int id; /* switch product id */ |
242 | int num_ports; /* number of switch ports */ | ||
76 | 243 | ||
77 | /* hw bridging */ | 244 | /* hw bridging */ |
78 | 245 | ||
@@ -92,6 +259,7 @@ struct mv88e6xxx_hw_stat { | |||
92 | int reg; | 259 | int reg; |
93 | }; | 260 | }; |
94 | 261 | ||
262 | int mv88e6xxx_switch_reset(struct dsa_switch *ds, bool ppu_active); | ||
95 | int mv88e6xxx_setup_port_common(struct dsa_switch *ds, int port); | 263 | int mv88e6xxx_setup_port_common(struct dsa_switch *ds, int port); |
96 | int mv88e6xxx_setup_common(struct dsa_switch *ds); | 264 | int mv88e6xxx_setup_common(struct dsa_switch *ds); |
97 | int __mv88e6xxx_reg_read(struct mii_bus *bus, int sw_addr, int addr, int reg); | 265 | int __mv88e6xxx_reg_read(struct mii_bus *bus, int sw_addr, int addr, int reg); |
@@ -102,19 +270,21 @@ int mv88e6xxx_reg_write(struct dsa_switch *ds, int addr, int reg, u16 val); | |||
102 | int mv88e6xxx_config_prio(struct dsa_switch *ds); | 270 | int mv88e6xxx_config_prio(struct dsa_switch *ds); |
103 | int mv88e6xxx_set_addr_direct(struct dsa_switch *ds, u8 *addr); | 271 | int mv88e6xxx_set_addr_direct(struct dsa_switch *ds, u8 *addr); |
104 | int mv88e6xxx_set_addr_indirect(struct dsa_switch *ds, u8 *addr); | 272 | int mv88e6xxx_set_addr_indirect(struct dsa_switch *ds, u8 *addr); |
105 | int mv88e6xxx_phy_read(struct dsa_switch *ds, int addr, int regnum); | 273 | int mv88e6xxx_phy_read(struct dsa_switch *ds, int port, int regnum); |
106 | int mv88e6xxx_phy_write(struct dsa_switch *ds, int addr, int regnum, u16 val); | 274 | int mv88e6xxx_phy_write(struct dsa_switch *ds, int port, int regnum, u16 val); |
275 | int mv88e6xxx_phy_read_indirect(struct dsa_switch *ds, int port, int regnum); | ||
276 | int mv88e6xxx_phy_write_indirect(struct dsa_switch *ds, int port, int regnum, | ||
277 | u16 val); | ||
107 | void mv88e6xxx_ppu_state_init(struct dsa_switch *ds); | 278 | void mv88e6xxx_ppu_state_init(struct dsa_switch *ds); |
108 | int mv88e6xxx_phy_read_ppu(struct dsa_switch *ds, int addr, int regnum); | 279 | int mv88e6xxx_phy_read_ppu(struct dsa_switch *ds, int addr, int regnum); |
109 | int mv88e6xxx_phy_write_ppu(struct dsa_switch *ds, int addr, | 280 | int mv88e6xxx_phy_write_ppu(struct dsa_switch *ds, int addr, |
110 | int regnum, u16 val); | 281 | int regnum, u16 val); |
111 | void mv88e6xxx_poll_link(struct dsa_switch *ds); | 282 | void mv88e6xxx_poll_link(struct dsa_switch *ds); |
112 | void mv88e6xxx_get_strings(struct dsa_switch *ds, | 283 | void mv88e6xxx_get_strings(struct dsa_switch *ds, int port, uint8_t *data); |
113 | int nr_stats, struct mv88e6xxx_hw_stat *stats, | 284 | void mv88e6xxx_get_ethtool_stats(struct dsa_switch *ds, int port, |
114 | int port, uint8_t *data); | 285 | uint64_t *data); |
115 | void mv88e6xxx_get_ethtool_stats(struct dsa_switch *ds, | 286 | int mv88e6xxx_get_sset_count(struct dsa_switch *ds); |
116 | int nr_stats, struct mv88e6xxx_hw_stat *stats, | 287 | int mv88e6xxx_get_sset_count_basic(struct dsa_switch *ds); |
117 | int port, uint64_t *data); | ||
118 | int mv88e6xxx_get_regs_len(struct dsa_switch *ds, int port); | 288 | int mv88e6xxx_get_regs_len(struct dsa_switch *ds, int port); |
119 | void mv88e6xxx_get_regs(struct dsa_switch *ds, int port, | 289 | void mv88e6xxx_get_regs(struct dsa_switch *ds, int port, |
120 | struct ethtool_regs *regs, void *_p); | 290 | struct ethtool_regs *regs, void *_p); |
@@ -137,7 +307,9 @@ int mv88e6xxx_port_fdb_del(struct dsa_switch *ds, int port, | |||
137 | const unsigned char *addr, u16 vid); | 307 | const unsigned char *addr, u16 vid); |
138 | int mv88e6xxx_port_fdb_getnext(struct dsa_switch *ds, int port, | 308 | int mv88e6xxx_port_fdb_getnext(struct dsa_switch *ds, int port, |
139 | unsigned char *addr, bool *is_static); | 309 | unsigned char *addr, bool *is_static); |
140 | 310 | int mv88e6xxx_phy_page_read(struct dsa_switch *ds, int port, int page, int reg); | |
311 | int mv88e6xxx_phy_page_write(struct dsa_switch *ds, int port, int page, | ||
312 | int reg, int val); | ||
141 | extern struct dsa_switch_driver mv88e6131_switch_driver; | 313 | extern struct dsa_switch_driver mv88e6131_switch_driver; |
142 | extern struct dsa_switch_driver mv88e6123_61_65_switch_driver; | 314 | extern struct dsa_switch_driver mv88e6123_61_65_switch_driver; |
143 | extern struct dsa_switch_driver mv88e6352_switch_driver; | 315 | extern struct dsa_switch_driver mv88e6352_switch_driver; |