aboutsummaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
Diffstat (limited to 'net')
-rw-r--r--net/dsa/Kconfig36
-rw-r--r--net/dsa/Makefile11
-rw-r--r--net/dsa/mv88e6060.c293
-rw-r--r--net/dsa/mv88e6123_61_65.c438
-rw-r--r--net/dsa/mv88e6131.c435
-rw-r--r--net/dsa/mv88e6xxx.c549
-rw-r--r--net/dsa/mv88e6xxx.h98
7 files changed, 1 insertions, 1859 deletions
diff --git a/net/dsa/Kconfig b/net/dsa/Kconfig
index 7e12303827e8..274791cd7a35 100644
--- a/net/dsa/Kconfig
+++ b/net/dsa/Kconfig
@@ -1,4 +1,4 @@
1menuconfig NET_DSA 1config NET_DSA
2 tristate "Distributed Switch Architecture support" 2 tristate "Distributed Switch Architecture support"
3 default n 3 default n
4 depends on EXPERIMENTAL && NETDEVICES && !S390 4 depends on EXPERIMENTAL && NETDEVICES && !S390
@@ -23,38 +23,4 @@ config NET_DSA_TAG_TRAILER
23 bool 23 bool
24 default n 24 default n
25 25
26
27# switch drivers
28config NET_DSA_MV88E6XXX
29 tristate
30 default n
31
32config NET_DSA_MV88E6060
33 tristate "Marvell 88E6060 ethernet switch chip support"
34 select NET_DSA_TAG_TRAILER
35 ---help---
36 This enables support for the Marvell 88E6060 ethernet switch
37 chip.
38
39config NET_DSA_MV88E6XXX_NEED_PPU
40 bool
41 default n
42
43config NET_DSA_MV88E6131
44 tristate "Marvell 88E6085/6095/6095F/6131 ethernet switch chip support"
45 select NET_DSA_MV88E6XXX
46 select NET_DSA_MV88E6XXX_NEED_PPU
47 select NET_DSA_TAG_DSA
48 ---help---
49 This enables support for the Marvell 88E6085/6095/6095F/6131
50 ethernet switch chips.
51
52config NET_DSA_MV88E6123_61_65
53 tristate "Marvell 88E6123/6161/6165 ethernet switch chip support"
54 select NET_DSA_MV88E6XXX
55 select NET_DSA_TAG_EDSA
56 ---help---
57 This enables support for the Marvell 88E6123/6161/6165
58 ethernet switch chips.
59
60endif 26endif
diff --git a/net/dsa/Makefile b/net/dsa/Makefile
index 191dd482e557..7b9fcbbeda5d 100644
--- a/net/dsa/Makefile
+++ b/net/dsa/Makefile
@@ -6,14 +6,3 @@ dsa_core-y += dsa.o slave.o
6dsa_core-$(CONFIG_NET_DSA_TAG_DSA) += tag_dsa.o 6dsa_core-$(CONFIG_NET_DSA_TAG_DSA) += tag_dsa.o
7dsa_core-$(CONFIG_NET_DSA_TAG_EDSA) += tag_edsa.o 7dsa_core-$(CONFIG_NET_DSA_TAG_EDSA) += tag_edsa.o
8dsa_core-$(CONFIG_NET_DSA_TAG_TRAILER) += tag_trailer.o 8dsa_core-$(CONFIG_NET_DSA_TAG_TRAILER) += tag_trailer.o
9
10# switch drivers
11obj-$(CONFIG_NET_DSA_MV88E6060) += mv88e6060.o
12obj-$(CONFIG_NET_DSA_MV88E6XXX) += mv88e6xxx_drv.o
13mv88e6xxx_drv-y += mv88e6xxx.o
14ifdef CONFIG_NET_DSA_MV88E6123_61_65
15mv88e6xxx_drv-y += mv88e6123_61_65.o
16endif
17ifdef CONFIG_NET_DSA_MV88E6131
18mv88e6xxx_drv-y += mv88e6131.o
19endif
diff --git a/net/dsa/mv88e6060.c b/net/dsa/mv88e6060.c
deleted file mode 100644
index 7fc4e81d4d43..000000000000
--- a/net/dsa/mv88e6060.c
+++ /dev/null
@@ -1,293 +0,0 @@
1/*
2 * net/dsa/mv88e6060.c - Driver for Marvell 88e6060 switch chips
3 * Copyright (c) 2008-2009 Marvell Semiconductor
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 */
10
11#include <linux/list.h>
12#include <linux/netdevice.h>
13#include <linux/phy.h>
14#include <net/dsa.h>
15
16#define REG_PORT(p) (8 + (p))
17#define REG_GLOBAL 0x0f
18
19static int reg_read(struct dsa_switch *ds, int addr, int reg)
20{
21 return mdiobus_read(ds->master_mii_bus, ds->pd->sw_addr + addr, reg);
22}
23
24#define REG_READ(addr, reg) \
25 ({ \
26 int __ret; \
27 \
28 __ret = reg_read(ds, addr, reg); \
29 if (__ret < 0) \
30 return __ret; \
31 __ret; \
32 })
33
34
35static int reg_write(struct dsa_switch *ds, int addr, int reg, u16 val)
36{
37 return mdiobus_write(ds->master_mii_bus, ds->pd->sw_addr + addr,
38 reg, val);
39}
40
41#define REG_WRITE(addr, reg, val) \
42 ({ \
43 int __ret; \
44 \
45 __ret = reg_write(ds, addr, reg, val); \
46 if (__ret < 0) \
47 return __ret; \
48 })
49
50static char *mv88e6060_probe(struct mii_bus *bus, int sw_addr)
51{
52 int ret;
53
54 ret = mdiobus_read(bus, sw_addr + REG_PORT(0), 0x03);
55 if (ret >= 0) {
56 ret &= 0xfff0;
57 if (ret == 0x0600)
58 return "Marvell 88E6060";
59 }
60
61 return NULL;
62}
63
64static int mv88e6060_switch_reset(struct dsa_switch *ds)
65{
66 int i;
67 int ret;
68
69 /*
70 * Set all ports to the disabled state.
71 */
72 for (i = 0; i < 6; i++) {
73 ret = REG_READ(REG_PORT(i), 0x04);
74 REG_WRITE(REG_PORT(i), 0x04, ret & 0xfffc);
75 }
76
77 /*
78 * Wait for transmit queues to drain.
79 */
80 msleep(2);
81
82 /*
83 * Reset the switch.
84 */
85 REG_WRITE(REG_GLOBAL, 0x0a, 0xa130);
86
87 /*
88 * Wait up to one second for reset to complete.
89 */
90 for (i = 0; i < 1000; i++) {
91 ret = REG_READ(REG_GLOBAL, 0x00);
92 if ((ret & 0x8000) == 0x0000)
93 break;
94
95 msleep(1);
96 }
97 if (i == 1000)
98 return -ETIMEDOUT;
99
100 return 0;
101}
102
103static int mv88e6060_setup_global(struct dsa_switch *ds)
104{
105 /*
106 * Disable discarding of frames with excessive collisions,
107 * set the maximum frame size to 1536 bytes, and mask all
108 * interrupt sources.
109 */
110 REG_WRITE(REG_GLOBAL, 0x04, 0x0800);
111
112 /*
113 * Enable automatic address learning, set the address
114 * database size to 1024 entries, and set the default aging
115 * time to 5 minutes.
116 */
117 REG_WRITE(REG_GLOBAL, 0x0a, 0x2130);
118
119 return 0;
120}
121
122static int mv88e6060_setup_port(struct dsa_switch *ds, int p)
123{
124 int addr = REG_PORT(p);
125
126 /*
127 * Do not force flow control, disable Ingress and Egress
128 * Header tagging, disable VLAN tunneling, and set the port
129 * state to Forwarding. Additionally, if this is the CPU
130 * port, enable Ingress and Egress Trailer tagging mode.
131 */
132 REG_WRITE(addr, 0x04, dsa_is_cpu_port(ds, p) ? 0x4103 : 0x0003);
133
134 /*
135 * Port based VLAN map: give each port its own address
136 * database, allow the CPU port to talk to each of the 'real'
137 * ports, and allow each of the 'real' ports to only talk to
138 * the CPU port.
139 */
140 REG_WRITE(addr, 0x06,
141 ((p & 0xf) << 12) |
142 (dsa_is_cpu_port(ds, p) ?
143 ds->phys_port_mask :
144 (1 << ds->dst->cpu_port)));
145
146 /*
147 * Port Association Vector: when learning source addresses
148 * of packets, add the address to the address database using
149 * a port bitmap that has only the bit for this port set and
150 * the other bits clear.
151 */
152 REG_WRITE(addr, 0x0b, 1 << p);
153
154 return 0;
155}
156
157static int mv88e6060_setup(struct dsa_switch *ds)
158{
159 int i;
160 int ret;
161
162 ret = mv88e6060_switch_reset(ds);
163 if (ret < 0)
164 return ret;
165
166 /* @@@ initialise atu */
167
168 ret = mv88e6060_setup_global(ds);
169 if (ret < 0)
170 return ret;
171
172 for (i = 0; i < 6; i++) {
173 ret = mv88e6060_setup_port(ds, i);
174 if (ret < 0)
175 return ret;
176 }
177
178 return 0;
179}
180
181static int mv88e6060_set_addr(struct dsa_switch *ds, u8 *addr)
182{
183 REG_WRITE(REG_GLOBAL, 0x01, (addr[0] << 8) | addr[1]);
184 REG_WRITE(REG_GLOBAL, 0x02, (addr[2] << 8) | addr[3]);
185 REG_WRITE(REG_GLOBAL, 0x03, (addr[4] << 8) | addr[5]);
186
187 return 0;
188}
189
190static int mv88e6060_port_to_phy_addr(int port)
191{
192 if (port >= 0 && port <= 5)
193 return port;
194 return -1;
195}
196
197static int mv88e6060_phy_read(struct dsa_switch *ds, int port, int regnum)
198{
199 int addr;
200
201 addr = mv88e6060_port_to_phy_addr(port);
202 if (addr == -1)
203 return 0xffff;
204
205 return reg_read(ds, addr, regnum);
206}
207
208static int
209mv88e6060_phy_write(struct dsa_switch *ds, int port, int regnum, u16 val)
210{
211 int addr;
212
213 addr = mv88e6060_port_to_phy_addr(port);
214 if (addr == -1)
215 return 0xffff;
216
217 return reg_write(ds, addr, regnum, val);
218}
219
220static void mv88e6060_poll_link(struct dsa_switch *ds)
221{
222 int i;
223
224 for (i = 0; i < DSA_MAX_PORTS; i++) {
225 struct net_device *dev;
226 int uninitialized_var(port_status);
227 int link;
228 int speed;
229 int duplex;
230 int fc;
231
232 dev = ds->ports[i];
233 if (dev == NULL)
234 continue;
235
236 link = 0;
237 if (dev->flags & IFF_UP) {
238 port_status = reg_read(ds, REG_PORT(i), 0x00);
239 if (port_status < 0)
240 continue;
241
242 link = !!(port_status & 0x1000);
243 }
244
245 if (!link) {
246 if (netif_carrier_ok(dev)) {
247 printk(KERN_INFO "%s: link down\n", dev->name);
248 netif_carrier_off(dev);
249 }
250 continue;
251 }
252
253 speed = (port_status & 0x0100) ? 100 : 10;
254 duplex = (port_status & 0x0200) ? 1 : 0;
255 fc = ((port_status & 0xc000) == 0xc000) ? 1 : 0;
256
257 if (!netif_carrier_ok(dev)) {
258 printk(KERN_INFO "%s: link up, %d Mb/s, %s duplex, "
259 "flow control %sabled\n", dev->name,
260 speed, duplex ? "full" : "half",
261 fc ? "en" : "dis");
262 netif_carrier_on(dev);
263 }
264 }
265}
266
267static struct dsa_switch_driver mv88e6060_switch_driver = {
268 .tag_protocol = htons(ETH_P_TRAILER),
269 .probe = mv88e6060_probe,
270 .setup = mv88e6060_setup,
271 .set_addr = mv88e6060_set_addr,
272 .phy_read = mv88e6060_phy_read,
273 .phy_write = mv88e6060_phy_write,
274 .poll_link = mv88e6060_poll_link,
275};
276
277static int __init mv88e6060_init(void)
278{
279 register_switch_driver(&mv88e6060_switch_driver);
280 return 0;
281}
282module_init(mv88e6060_init);
283
284static void __exit mv88e6060_cleanup(void)
285{
286 unregister_switch_driver(&mv88e6060_switch_driver);
287}
288module_exit(mv88e6060_cleanup);
289
290MODULE_AUTHOR("Lennert Buytenhek <buytenh@wantstofly.org>");
291MODULE_DESCRIPTION("Driver for Marvell 88E6060 ethernet switch chip");
292MODULE_LICENSE("GPL");
293MODULE_ALIAS("platform:mv88e6060");
diff --git a/net/dsa/mv88e6123_61_65.c b/net/dsa/mv88e6123_61_65.c
deleted file mode 100644
index c0a458fc698f..000000000000
--- a/net/dsa/mv88e6123_61_65.c
+++ /dev/null
@@ -1,438 +0,0 @@
1/*
2 * net/dsa/mv88e6123_61_65.c - Marvell 88e6123/6161/6165 switch chip support
3 * Copyright (c) 2008-2009 Marvell Semiconductor
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 */
10
11#include <linux/list.h>
12#include <linux/netdevice.h>
13#include <linux/phy.h>
14#include <net/dsa.h>
15#include "mv88e6xxx.h"
16
17static char *mv88e6123_61_65_probe(struct mii_bus *bus, int sw_addr)
18{
19 int ret;
20
21 ret = __mv88e6xxx_reg_read(bus, sw_addr, REG_PORT(0), 0x03);
22 if (ret >= 0) {
23 ret &= 0xfff0;
24 if (ret == 0x1210)
25 return "Marvell 88E6123";
26 if (ret == 0x1610)
27 return "Marvell 88E6161";
28 if (ret == 0x1650)
29 return "Marvell 88E6165";
30 }
31
32 return NULL;
33}
34
35static int mv88e6123_61_65_switch_reset(struct dsa_switch *ds)
36{
37 int i;
38 int ret;
39
40 /*
41 * Set all ports to the disabled state.
42 */
43 for (i = 0; i < 8; i++) {
44 ret = REG_READ(REG_PORT(i), 0x04);
45 REG_WRITE(REG_PORT(i), 0x04, ret & 0xfffc);
46 }
47
48 /*
49 * Wait for transmit queues to drain.
50 */
51 msleep(2);
52
53 /*
54 * Reset the switch.
55 */
56 REG_WRITE(REG_GLOBAL, 0x04, 0xc400);
57
58 /*
59 * Wait up to one second for reset to complete.
60 */
61 for (i = 0; i < 1000; i++) {
62 ret = REG_READ(REG_GLOBAL, 0x00);
63 if ((ret & 0xc800) == 0xc800)
64 break;
65
66 msleep(1);
67 }
68 if (i == 1000)
69 return -ETIMEDOUT;
70
71 return 0;
72}
73
74static int mv88e6123_61_65_setup_global(struct dsa_switch *ds)
75{
76 int ret;
77 int i;
78
79 /*
80 * Disable the PHY polling unit (since there won't be any
81 * external PHYs to poll), don't discard packets with
82 * excessive collisions, and mask all interrupt sources.
83 */
84 REG_WRITE(REG_GLOBAL, 0x04, 0x0000);
85
86 /*
87 * Set the default address aging time to 5 minutes, and
88 * enable address learn messages to be sent to all message
89 * ports.
90 */
91 REG_WRITE(REG_GLOBAL, 0x0a, 0x0148);
92
93 /*
94 * Configure the priority mapping registers.
95 */
96 ret = mv88e6xxx_config_prio(ds);
97 if (ret < 0)
98 return ret;
99
100 /*
101 * Configure the upstream port, and configure the upstream
102 * port as the port to which ingress and egress monitor frames
103 * are to be sent.
104 */
105 REG_WRITE(REG_GLOBAL, 0x1a, (dsa_upstream_port(ds) * 0x1110));
106
107 /*
108 * Disable remote management for now, and set the switch's
109 * DSA device number.
110 */
111 REG_WRITE(REG_GLOBAL, 0x1c, ds->index & 0x1f);
112
113 /*
114 * Send all frames with destination addresses matching
115 * 01:80:c2:00:00:2x to the CPU port.
116 */
117 REG_WRITE(REG_GLOBAL2, 0x02, 0xffff);
118
119 /*
120 * Send all frames with destination addresses matching
121 * 01:80:c2:00:00:0x to the CPU port.
122 */
123 REG_WRITE(REG_GLOBAL2, 0x03, 0xffff);
124
125 /*
126 * Disable the loopback filter, disable flow control
127 * messages, disable flood broadcast override, disable
128 * removing of provider tags, disable ATU age violation
129 * interrupts, disable tag flow control, force flow
130 * control priority to the highest, and send all special
131 * multicast frames to the CPU at the highest priority.
132 */
133 REG_WRITE(REG_GLOBAL2, 0x05, 0x00ff);
134
135 /*
136 * Program the DSA routing table.
137 */
138 for (i = 0; i < 32; i++) {
139 int nexthop;
140
141 nexthop = 0x1f;
142 if (i != ds->index && i < ds->dst->pd->nr_chips)
143 nexthop = ds->pd->rtable[i] & 0x1f;
144
145 REG_WRITE(REG_GLOBAL2, 0x06, 0x8000 | (i << 8) | nexthop);
146 }
147
148 /*
149 * Clear all trunk masks.
150 */
151 for (i = 0; i < 8; i++)
152 REG_WRITE(REG_GLOBAL2, 0x07, 0x8000 | (i << 12) | 0xff);
153
154 /*
155 * Clear all trunk mappings.
156 */
157 for (i = 0; i < 16; i++)
158 REG_WRITE(REG_GLOBAL2, 0x08, 0x8000 | (i << 11));
159
160 /*
161 * Disable ingress rate limiting by resetting all ingress
162 * rate limit registers to their initial state.
163 */
164 for (i = 0; i < 6; i++)
165 REG_WRITE(REG_GLOBAL2, 0x09, 0x9000 | (i << 8));
166
167 /*
168 * Initialise cross-chip port VLAN table to reset defaults.
169 */
170 REG_WRITE(REG_GLOBAL2, 0x0b, 0x9000);
171
172 /*
173 * Clear the priority override table.
174 */
175 for (i = 0; i < 16; i++)
176 REG_WRITE(REG_GLOBAL2, 0x0f, 0x8000 | (i << 8));
177
178 /* @@@ initialise AVB (22/23) watchdog (27) sdet (29) registers */
179
180 return 0;
181}
182
183static int mv88e6123_61_65_setup_port(struct dsa_switch *ds, int p)
184{
185 int addr = REG_PORT(p);
186 u16 val;
187
188 /*
189 * MAC Forcing register: don't force link, speed, duplex
190 * or flow control state to any particular values on physical
191 * ports, but force the CPU port and all DSA ports to 1000 Mb/s
192 * full duplex.
193 */
194 if (dsa_is_cpu_port(ds, p) || ds->dsa_port_mask & (1 << p))
195 REG_WRITE(addr, 0x01, 0x003e);
196 else
197 REG_WRITE(addr, 0x01, 0x0003);
198
199 /*
200 * Do not limit the period of time that this port can be
201 * paused for by the remote end or the period of time that
202 * this port can pause the remote end.
203 */
204 REG_WRITE(addr, 0x02, 0x0000);
205
206 /*
207 * Port Control: disable Drop-on-Unlock, disable Drop-on-Lock,
208 * disable Header mode, enable IGMP/MLD snooping, disable VLAN
209 * tunneling, determine priority by looking at 802.1p and IP
210 * priority fields (IP prio has precedence), and set STP state
211 * to Forwarding.
212 *
213 * If this is the CPU link, use DSA or EDSA tagging depending
214 * on which tagging mode was configured.
215 *
216 * If this is a link to another switch, use DSA tagging mode.
217 *
218 * If this is the upstream port for this switch, enable
219 * forwarding of unknown unicasts and multicasts.
220 */
221 val = 0x0433;
222 if (dsa_is_cpu_port(ds, p)) {
223 if (ds->dst->tag_protocol == htons(ETH_P_EDSA))
224 val |= 0x3300;
225 else
226 val |= 0x0100;
227 }
228 if (ds->dsa_port_mask & (1 << p))
229 val |= 0x0100;
230 if (p == dsa_upstream_port(ds))
231 val |= 0x000c;
232 REG_WRITE(addr, 0x04, val);
233
234 /*
235 * Port Control 1: disable trunking. Also, if this is the
236 * CPU port, enable learn messages to be sent to this port.
237 */
238 REG_WRITE(addr, 0x05, dsa_is_cpu_port(ds, p) ? 0x8000 : 0x0000);
239
240 /*
241 * Port based VLAN map: give each port its own address
242 * database, allow the CPU port to talk to each of the 'real'
243 * ports, and allow each of the 'real' ports to only talk to
244 * the upstream port.
245 */
246 val = (p & 0xf) << 12;
247 if (dsa_is_cpu_port(ds, p))
248 val |= ds->phys_port_mask;
249 else
250 val |= 1 << dsa_upstream_port(ds);
251 REG_WRITE(addr, 0x06, val);
252
253 /*
254 * Default VLAN ID and priority: don't set a default VLAN
255 * ID, and set the default packet priority to zero.
256 */
257 REG_WRITE(addr, 0x07, 0x0000);
258
259 /*
260 * Port Control 2: don't force a good FCS, set the maximum
261 * frame size to 10240 bytes, don't let the switch add or
262 * strip 802.1q tags, don't discard tagged or untagged frames
263 * on this port, do a destination address lookup on all
264 * received packets as usual, disable ARP mirroring and don't
265 * send a copy of all transmitted/received frames on this port
266 * to the CPU.
267 */
268 REG_WRITE(addr, 0x08, 0x2080);
269
270 /*
271 * Egress rate control: disable egress rate control.
272 */
273 REG_WRITE(addr, 0x09, 0x0001);
274
275 /*
276 * Egress rate control 2: disable egress rate control.
277 */
278 REG_WRITE(addr, 0x0a, 0x0000);
279
280 /*
281 * Port Association Vector: when learning source addresses
282 * of packets, add the address to the address database using
283 * a port bitmap that has only the bit for this port set and
284 * the other bits clear.
285 */
286 REG_WRITE(addr, 0x0b, 1 << p);
287
288 /*
289 * Port ATU control: disable limiting the number of address
290 * database entries that this port is allowed to use.
291 */
292 REG_WRITE(addr, 0x0c, 0x0000);
293
294 /*
295 * Priorit Override: disable DA, SA and VTU priority override.
296 */
297 REG_WRITE(addr, 0x0d, 0x0000);
298
299 /*
300 * Port Ethertype: use the Ethertype DSA Ethertype value.
301 */
302 REG_WRITE(addr, 0x0f, ETH_P_EDSA);
303
304 /*
305 * Tag Remap: use an identity 802.1p prio -> switch prio
306 * mapping.
307 */
308 REG_WRITE(addr, 0x18, 0x3210);
309
310 /*
311 * Tag Remap 2: use an identity 802.1p prio -> switch prio
312 * mapping.
313 */
314 REG_WRITE(addr, 0x19, 0x7654);
315
316 return 0;
317}
318
319static int mv88e6123_61_65_setup(struct dsa_switch *ds)
320{
321 struct mv88e6xxx_priv_state *ps = (void *)(ds + 1);
322 int i;
323 int ret;
324
325 mutex_init(&ps->smi_mutex);
326 mutex_init(&ps->stats_mutex);
327
328 ret = mv88e6123_61_65_switch_reset(ds);
329 if (ret < 0)
330 return ret;
331
332 /* @@@ initialise vtu and atu */
333
334 ret = mv88e6123_61_65_setup_global(ds);
335 if (ret < 0)
336 return ret;
337
338 for (i = 0; i < 6; i++) {
339 ret = mv88e6123_61_65_setup_port(ds, i);
340 if (ret < 0)
341 return ret;
342 }
343
344 return 0;
345}
346
347static int mv88e6123_61_65_port_to_phy_addr(int port)
348{
349 if (port >= 0 && port <= 4)
350 return port;
351 return -1;
352}
353
354static int
355mv88e6123_61_65_phy_read(struct dsa_switch *ds, int port, int regnum)
356{
357 int addr = mv88e6123_61_65_port_to_phy_addr(port);
358 return mv88e6xxx_phy_read(ds, addr, regnum);
359}
360
361static int
362mv88e6123_61_65_phy_write(struct dsa_switch *ds,
363 int port, int regnum, u16 val)
364{
365 int addr = mv88e6123_61_65_port_to_phy_addr(port);
366 return mv88e6xxx_phy_write(ds, addr, regnum, val);
367}
368
369static struct mv88e6xxx_hw_stat mv88e6123_61_65_hw_stats[] = {
370 { "in_good_octets", 8, 0x00, },
371 { "in_bad_octets", 4, 0x02, },
372 { "in_unicast", 4, 0x04, },
373 { "in_broadcasts", 4, 0x06, },
374 { "in_multicasts", 4, 0x07, },
375 { "in_pause", 4, 0x16, },
376 { "in_undersize", 4, 0x18, },
377 { "in_fragments", 4, 0x19, },
378 { "in_oversize", 4, 0x1a, },
379 { "in_jabber", 4, 0x1b, },
380 { "in_rx_error", 4, 0x1c, },
381 { "in_fcs_error", 4, 0x1d, },
382 { "out_octets", 8, 0x0e, },
383 { "out_unicast", 4, 0x10, },
384 { "out_broadcasts", 4, 0x13, },
385 { "out_multicasts", 4, 0x12, },
386 { "out_pause", 4, 0x15, },
387 { "excessive", 4, 0x11, },
388 { "collisions", 4, 0x1e, },
389 { "deferred", 4, 0x05, },
390 { "single", 4, 0x14, },
391 { "multiple", 4, 0x17, },
392 { "out_fcs_error", 4, 0x03, },
393 { "late", 4, 0x1f, },
394 { "hist_64bytes", 4, 0x08, },
395 { "hist_65_127bytes", 4, 0x09, },
396 { "hist_128_255bytes", 4, 0x0a, },
397 { "hist_256_511bytes", 4, 0x0b, },
398 { "hist_512_1023bytes", 4, 0x0c, },
399 { "hist_1024_max_bytes", 4, 0x0d, },
400};
401
402static void
403mv88e6123_61_65_get_strings(struct dsa_switch *ds, int port, uint8_t *data)
404{
405 mv88e6xxx_get_strings(ds, ARRAY_SIZE(mv88e6123_61_65_hw_stats),
406 mv88e6123_61_65_hw_stats, port, data);
407}
408
409static void
410mv88e6123_61_65_get_ethtool_stats(struct dsa_switch *ds,
411 int port, uint64_t *data)
412{
413 mv88e6xxx_get_ethtool_stats(ds, ARRAY_SIZE(mv88e6123_61_65_hw_stats),
414 mv88e6123_61_65_hw_stats, port, data);
415}
416
417static int mv88e6123_61_65_get_sset_count(struct dsa_switch *ds)
418{
419 return ARRAY_SIZE(mv88e6123_61_65_hw_stats);
420}
421
422struct dsa_switch_driver mv88e6123_61_65_switch_driver = {
423 .tag_protocol = cpu_to_be16(ETH_P_EDSA),
424 .priv_size = sizeof(struct mv88e6xxx_priv_state),
425 .probe = mv88e6123_61_65_probe,
426 .setup = mv88e6123_61_65_setup,
427 .set_addr = mv88e6xxx_set_addr_indirect,
428 .phy_read = mv88e6123_61_65_phy_read,
429 .phy_write = mv88e6123_61_65_phy_write,
430 .poll_link = mv88e6xxx_poll_link,
431 .get_strings = mv88e6123_61_65_get_strings,
432 .get_ethtool_stats = mv88e6123_61_65_get_ethtool_stats,
433 .get_sset_count = mv88e6123_61_65_get_sset_count,
434};
435
436MODULE_ALIAS("platform:mv88e6123");
437MODULE_ALIAS("platform:mv88e6161");
438MODULE_ALIAS("platform:mv88e6165");
diff --git a/net/dsa/mv88e6131.c b/net/dsa/mv88e6131.c
deleted file mode 100644
index e0eb68243834..000000000000
--- a/net/dsa/mv88e6131.c
+++ /dev/null
@@ -1,435 +0,0 @@
1/*
2 * net/dsa/mv88e6131.c - Marvell 88e6095/6095f/6131 switch chip support
3 * Copyright (c) 2008-2009 Marvell Semiconductor
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 */
10
11#include <linux/list.h>
12#include <linux/netdevice.h>
13#include <linux/phy.h>
14#include <net/dsa.h>
15#include "mv88e6xxx.h"
16
17/*
18 * Switch product IDs
19 */
20#define ID_6085 0x04a0
21#define ID_6095 0x0950
22#define ID_6131 0x1060
23
24static char *mv88e6131_probe(struct mii_bus *bus, int sw_addr)
25{
26 int ret;
27
28 ret = __mv88e6xxx_reg_read(bus, sw_addr, REG_PORT(0), 0x03);
29 if (ret >= 0) {
30 ret &= 0xfff0;
31 if (ret == ID_6085)
32 return "Marvell 88E6085";
33 if (ret == ID_6095)
34 return "Marvell 88E6095/88E6095F";
35 if (ret == ID_6131)
36 return "Marvell 88E6131";
37 }
38
39 return NULL;
40}
41
42static int mv88e6131_switch_reset(struct dsa_switch *ds)
43{
44 int i;
45 int ret;
46
47 /*
48 * Set all ports to the disabled state.
49 */
50 for (i = 0; i < 11; i++) {
51 ret = REG_READ(REG_PORT(i), 0x04);
52 REG_WRITE(REG_PORT(i), 0x04, ret & 0xfffc);
53 }
54
55 /*
56 * Wait for transmit queues to drain.
57 */
58 msleep(2);
59
60 /*
61 * Reset the switch.
62 */
63 REG_WRITE(REG_GLOBAL, 0x04, 0xc400);
64
65 /*
66 * Wait up to one second for reset to complete.
67 */
68 for (i = 0; i < 1000; i++) {
69 ret = REG_READ(REG_GLOBAL, 0x00);
70 if ((ret & 0xc800) == 0xc800)
71 break;
72
73 msleep(1);
74 }
75 if (i == 1000)
76 return -ETIMEDOUT;
77
78 return 0;
79}
80
81static int mv88e6131_setup_global(struct dsa_switch *ds)
82{
83 int ret;
84 int i;
85
86 /*
87 * Enable the PHY polling unit, don't discard packets with
88 * excessive collisions, use a weighted fair queueing scheme
89 * to arbitrate between packet queues, set the maximum frame
90 * size to 1632, and mask all interrupt sources.
91 */
92 REG_WRITE(REG_GLOBAL, 0x04, 0x4400);
93
94 /*
95 * Set the default address aging time to 5 minutes, and
96 * enable address learn messages to be sent to all message
97 * ports.
98 */
99 REG_WRITE(REG_GLOBAL, 0x0a, 0x0148);
100
101 /*
102 * Configure the priority mapping registers.
103 */
104 ret = mv88e6xxx_config_prio(ds);
105 if (ret < 0)
106 return ret;
107
108 /*
109 * Set the VLAN ethertype to 0x8100.
110 */
111 REG_WRITE(REG_GLOBAL, 0x19, 0x8100);
112
113 /*
114 * Disable ARP mirroring, and configure the upstream port as
115 * the port to which ingress and egress monitor frames are to
116 * be sent.
117 */
118 REG_WRITE(REG_GLOBAL, 0x1a, (dsa_upstream_port(ds) * 0x1100) | 0x00f0);
119
120 /*
121 * Disable cascade port functionality unless this device
122 * is used in a cascade configuration, and set the switch's
123 * DSA device number.
124 */
125 if (ds->dst->pd->nr_chips > 1)
126 REG_WRITE(REG_GLOBAL, 0x1c, 0xf000 | (ds->index & 0x1f));
127 else
128 REG_WRITE(REG_GLOBAL, 0x1c, 0xe000 | (ds->index & 0x1f));
129
130 /*
131 * Send all frames with destination addresses matching
132 * 01:80:c2:00:00:0x to the CPU port.
133 */
134 REG_WRITE(REG_GLOBAL2, 0x03, 0xffff);
135
136 /*
137 * Ignore removed tag data on doubly tagged packets, disable
138 * flow control messages, force flow control priority to the
139 * highest, and send all special multicast frames to the CPU
140 * port at the highest priority.
141 */
142 REG_WRITE(REG_GLOBAL2, 0x05, 0x00ff);
143
144 /*
145 * Program the DSA routing table.
146 */
147 for (i = 0; i < 32; i++) {
148 int nexthop;
149
150 nexthop = 0x1f;
151 if (i != ds->index && i < ds->dst->pd->nr_chips)
152 nexthop = ds->pd->rtable[i] & 0x1f;
153
154 REG_WRITE(REG_GLOBAL2, 0x06, 0x8000 | (i << 8) | nexthop);
155 }
156
157 /*
158 * Clear all trunk masks.
159 */
160 for (i = 0; i < 8; i++)
161 REG_WRITE(REG_GLOBAL2, 0x07, 0x8000 | (i << 12) | 0x7ff);
162
163 /*
164 * Clear all trunk mappings.
165 */
166 for (i = 0; i < 16; i++)
167 REG_WRITE(REG_GLOBAL2, 0x08, 0x8000 | (i << 11));
168
169 /*
170 * Force the priority of IGMP/MLD snoop frames and ARP frames
171 * to the highest setting.
172 */
173 REG_WRITE(REG_GLOBAL2, 0x0f, 0x00ff);
174
175 return 0;
176}
177
178static int mv88e6131_setup_port(struct dsa_switch *ds, int p)
179{
180 struct mv88e6xxx_priv_state *ps = (void *)(ds + 1);
181 int addr = REG_PORT(p);
182 u16 val;
183
184 /*
185 * MAC Forcing register: don't force link, speed, duplex
186 * or flow control state to any particular values on physical
187 * ports, but force the CPU port and all DSA ports to 1000 Mb/s
188 * (100 Mb/s on 6085) full duplex.
189 */
190 if (dsa_is_cpu_port(ds, p) || ds->dsa_port_mask & (1 << p))
191 if (ps->id == ID_6085)
192 REG_WRITE(addr, 0x01, 0x003d); /* 100 Mb/s */
193 else
194 REG_WRITE(addr, 0x01, 0x003e); /* 1000 Mb/s */
195 else
196 REG_WRITE(addr, 0x01, 0x0003);
197
198 /*
199 * Port Control: disable Core Tag, disable Drop-on-Lock,
200 * transmit frames unmodified, disable Header mode,
201 * enable IGMP/MLD snoop, disable DoubleTag, disable VLAN
202 * tunneling, determine priority by looking at 802.1p and
203 * IP priority fields (IP prio has precedence), and set STP
204 * state to Forwarding.
205 *
206 * If this is the upstream port for this switch, enable
207 * forwarding of unknown unicasts, and enable DSA tagging
208 * mode.
209 *
210 * If this is the link to another switch, use DSA tagging
211 * mode, but do not enable forwarding of unknown unicasts.
212 */
213 val = 0x0433;
214 if (p == dsa_upstream_port(ds)) {
215 val |= 0x0104;
216 /*
217 * On 6085, unknown multicast forward is controlled
218 * here rather than in Port Control 2 register.
219 */
220 if (ps->id == ID_6085)
221 val |= 0x0008;
222 }
223 if (ds->dsa_port_mask & (1 << p))
224 val |= 0x0100;
225 REG_WRITE(addr, 0x04, val);
226
227 /*
228 * Port Control 1: disable trunking. Also, if this is the
229 * CPU port, enable learn messages to be sent to this port.
230 */
231 REG_WRITE(addr, 0x05, dsa_is_cpu_port(ds, p) ? 0x8000 : 0x0000);
232
233 /*
234 * Port based VLAN map: give each port its own address
235 * database, allow the CPU port to talk to each of the 'real'
236 * ports, and allow each of the 'real' ports to only talk to
237 * the upstream port.
238 */
239 val = (p & 0xf) << 12;
240 if (dsa_is_cpu_port(ds, p))
241 val |= ds->phys_port_mask;
242 else
243 val |= 1 << dsa_upstream_port(ds);
244 REG_WRITE(addr, 0x06, val);
245
246 /*
247 * Default VLAN ID and priority: don't set a default VLAN
248 * ID, and set the default packet priority to zero.
249 */
250 REG_WRITE(addr, 0x07, 0x0000);
251
252 /*
253 * Port Control 2: don't force a good FCS, don't use
254 * VLAN-based, source address-based or destination
255 * address-based priority overrides, don't let the switch
256 * add or strip 802.1q tags, don't discard tagged or
257 * untagged frames on this port, do a destination address
258 * lookup on received packets as usual, don't send a copy
259 * of all transmitted/received frames on this port to the
260 * CPU, and configure the upstream port number.
261 *
262 * If this is the upstream port for this switch, enable
263 * forwarding of unknown multicast addresses.
264 */
265 if (ps->id == ID_6085)
266 /*
267 * on 6085, bits 3:0 are reserved, bit 6 control ARP
268 * mirroring, and multicast forward is handled in
269 * Port Control register.
270 */
271 REG_WRITE(addr, 0x08, 0x0080);
272 else {
273 val = 0x0080 | dsa_upstream_port(ds);
274 if (p == dsa_upstream_port(ds))
275 val |= 0x0040;
276 REG_WRITE(addr, 0x08, val);
277 }
278
279 /*
280 * Rate Control: disable ingress rate limiting.
281 */
282 REG_WRITE(addr, 0x09, 0x0000);
283
284 /*
285 * Rate Control 2: disable egress rate limiting.
286 */
287 REG_WRITE(addr, 0x0a, 0x0000);
288
289 /*
290 * Port Association Vector: when learning source addresses
291 * of packets, add the address to the address database using
292 * a port bitmap that has only the bit for this port set and
293 * the other bits clear.
294 */
295 REG_WRITE(addr, 0x0b, 1 << p);
296
297 /*
298 * Tag Remap: use an identity 802.1p prio -> switch prio
299 * mapping.
300 */
301 REG_WRITE(addr, 0x18, 0x3210);
302
303 /*
304 * Tag Remap 2: use an identity 802.1p prio -> switch prio
305 * mapping.
306 */
307 REG_WRITE(addr, 0x19, 0x7654);
308
309 return 0;
310}
311
312static int mv88e6131_setup(struct dsa_switch *ds)
313{
314 struct mv88e6xxx_priv_state *ps = (void *)(ds + 1);
315 int i;
316 int ret;
317
318 mutex_init(&ps->smi_mutex);
319 mv88e6xxx_ppu_state_init(ds);
320 mutex_init(&ps->stats_mutex);
321
322 ps->id = REG_READ(REG_PORT(0), 0x03) & 0xfff0;
323
324 ret = mv88e6131_switch_reset(ds);
325 if (ret < 0)
326 return ret;
327
328 /* @@@ initialise vtu and atu */
329
330 ret = mv88e6131_setup_global(ds);
331 if (ret < 0)
332 return ret;
333
334 for (i = 0; i < 11; i++) {
335 ret = mv88e6131_setup_port(ds, i);
336 if (ret < 0)
337 return ret;
338 }
339
340 return 0;
341}
342
343static int mv88e6131_port_to_phy_addr(int port)
344{
345 if (port >= 0 && port <= 11)
346 return port;
347 return -1;
348}
349
350static int
351mv88e6131_phy_read(struct dsa_switch *ds, int port, int regnum)
352{
353 int addr = mv88e6131_port_to_phy_addr(port);
354 return mv88e6xxx_phy_read_ppu(ds, addr, regnum);
355}
356
357static int
358mv88e6131_phy_write(struct dsa_switch *ds,
359 int port, int regnum, u16 val)
360{
361 int addr = mv88e6131_port_to_phy_addr(port);
362 return mv88e6xxx_phy_write_ppu(ds, addr, regnum, val);
363}
364
365static struct mv88e6xxx_hw_stat mv88e6131_hw_stats[] = {
366 { "in_good_octets", 8, 0x00, },
367 { "in_bad_octets", 4, 0x02, },
368 { "in_unicast", 4, 0x04, },
369 { "in_broadcasts", 4, 0x06, },
370 { "in_multicasts", 4, 0x07, },
371 { "in_pause", 4, 0x16, },
372 { "in_undersize", 4, 0x18, },
373 { "in_fragments", 4, 0x19, },
374 { "in_oversize", 4, 0x1a, },
375 { "in_jabber", 4, 0x1b, },
376 { "in_rx_error", 4, 0x1c, },
377 { "in_fcs_error", 4, 0x1d, },
378 { "out_octets", 8, 0x0e, },
379 { "out_unicast", 4, 0x10, },
380 { "out_broadcasts", 4, 0x13, },
381 { "out_multicasts", 4, 0x12, },
382 { "out_pause", 4, 0x15, },
383 { "excessive", 4, 0x11, },
384 { "collisions", 4, 0x1e, },
385 { "deferred", 4, 0x05, },
386 { "single", 4, 0x14, },
387 { "multiple", 4, 0x17, },
388 { "out_fcs_error", 4, 0x03, },
389 { "late", 4, 0x1f, },
390 { "hist_64bytes", 4, 0x08, },
391 { "hist_65_127bytes", 4, 0x09, },
392 { "hist_128_255bytes", 4, 0x0a, },
393 { "hist_256_511bytes", 4, 0x0b, },
394 { "hist_512_1023bytes", 4, 0x0c, },
395 { "hist_1024_max_bytes", 4, 0x0d, },
396};
397
398static void
399mv88e6131_get_strings(struct dsa_switch *ds, int port, uint8_t *data)
400{
401 mv88e6xxx_get_strings(ds, ARRAY_SIZE(mv88e6131_hw_stats),
402 mv88e6131_hw_stats, port, data);
403}
404
405static void
406mv88e6131_get_ethtool_stats(struct dsa_switch *ds,
407 int port, uint64_t *data)
408{
409 mv88e6xxx_get_ethtool_stats(ds, ARRAY_SIZE(mv88e6131_hw_stats),
410 mv88e6131_hw_stats, port, data);
411}
412
413static int mv88e6131_get_sset_count(struct dsa_switch *ds)
414{
415 return ARRAY_SIZE(mv88e6131_hw_stats);
416}
417
418struct dsa_switch_driver mv88e6131_switch_driver = {
419 .tag_protocol = cpu_to_be16(ETH_P_DSA),
420 .priv_size = sizeof(struct mv88e6xxx_priv_state),
421 .probe = mv88e6131_probe,
422 .setup = mv88e6131_setup,
423 .set_addr = mv88e6xxx_set_addr_direct,
424 .phy_read = mv88e6131_phy_read,
425 .phy_write = mv88e6131_phy_write,
426 .poll_link = mv88e6xxx_poll_link,
427 .get_strings = mv88e6131_get_strings,
428 .get_ethtool_stats = mv88e6131_get_ethtool_stats,
429 .get_sset_count = mv88e6131_get_sset_count,
430};
431
432MODULE_ALIAS("platform:mv88e6085");
433MODULE_ALIAS("platform:mv88e6095");
434MODULE_ALIAS("platform:mv88e6095f");
435MODULE_ALIAS("platform:mv88e6131");
diff --git a/net/dsa/mv88e6xxx.c b/net/dsa/mv88e6xxx.c
deleted file mode 100644
index 5467c040824a..000000000000
--- a/net/dsa/mv88e6xxx.c
+++ /dev/null
@@ -1,549 +0,0 @@
1/*
2 * net/dsa/mv88e6xxx.c - Marvell 88e6xxx switch chip support
3 * Copyright (c) 2008 Marvell Semiconductor
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 */
10
11#include <linux/list.h>
12#include <linux/netdevice.h>
13#include <linux/phy.h>
14#include <net/dsa.h>
15#include "mv88e6xxx.h"
16
17/*
18 * If the switch's ADDR[4:0] strap pins are strapped to zero, it will
19 * use all 32 SMI bus addresses on its SMI bus, and all switch registers
20 * will be directly accessible on some {device address,register address}
21 * pair. If the ADDR[4:0] pins are not strapped to zero, the switch
22 * will only respond to SMI transactions to that specific address, and
23 * an indirect addressing mechanism needs to be used to access its
24 * registers.
25 */
26static int mv88e6xxx_reg_wait_ready(struct mii_bus *bus, int sw_addr)
27{
28 int ret;
29 int i;
30
31 for (i = 0; i < 16; i++) {
32 ret = mdiobus_read(bus, sw_addr, 0);
33 if (ret < 0)
34 return ret;
35
36 if ((ret & 0x8000) == 0)
37 return 0;
38 }
39
40 return -ETIMEDOUT;
41}
42
43int __mv88e6xxx_reg_read(struct mii_bus *bus, int sw_addr, int addr, int reg)
44{
45 int ret;
46
47 if (sw_addr == 0)
48 return mdiobus_read(bus, addr, reg);
49
50 /*
51 * Wait for the bus to become free.
52 */
53 ret = mv88e6xxx_reg_wait_ready(bus, sw_addr);
54 if (ret < 0)
55 return ret;
56
57 /*
58 * Transmit the read command.
59 */
60 ret = mdiobus_write(bus, sw_addr, 0, 0x9800 | (addr << 5) | reg);
61 if (ret < 0)
62 return ret;
63
64 /*
65 * Wait for the read command to complete.
66 */
67 ret = mv88e6xxx_reg_wait_ready(bus, sw_addr);
68 if (ret < 0)
69 return ret;
70
71 /*
72 * Read the data.
73 */
74 ret = mdiobus_read(bus, sw_addr, 1);
75 if (ret < 0)
76 return ret;
77
78 return ret & 0xffff;
79}
80
81int mv88e6xxx_reg_read(struct dsa_switch *ds, int addr, int reg)
82{
83 struct mv88e6xxx_priv_state *ps = (void *)(ds + 1);
84 int ret;
85
86 mutex_lock(&ps->smi_mutex);
87 ret = __mv88e6xxx_reg_read(ds->master_mii_bus,
88 ds->pd->sw_addr, addr, reg);
89 mutex_unlock(&ps->smi_mutex);
90
91 return ret;
92}
93
94int __mv88e6xxx_reg_write(struct mii_bus *bus, int sw_addr, int addr,
95 int reg, u16 val)
96{
97 int ret;
98
99 if (sw_addr == 0)
100 return mdiobus_write(bus, addr, reg, val);
101
102 /*
103 * Wait for the bus to become free.
104 */
105 ret = mv88e6xxx_reg_wait_ready(bus, sw_addr);
106 if (ret < 0)
107 return ret;
108
109 /*
110 * Transmit the data to write.
111 */
112 ret = mdiobus_write(bus, sw_addr, 1, val);
113 if (ret < 0)
114 return ret;
115
116 /*
117 * Transmit the write command.
118 */
119 ret = mdiobus_write(bus, sw_addr, 0, 0x9400 | (addr << 5) | reg);
120 if (ret < 0)
121 return ret;
122
123 /*
124 * Wait for the write command to complete.
125 */
126 ret = mv88e6xxx_reg_wait_ready(bus, sw_addr);
127 if (ret < 0)
128 return ret;
129
130 return 0;
131}
132
133int mv88e6xxx_reg_write(struct dsa_switch *ds, int addr, int reg, u16 val)
134{
135 struct mv88e6xxx_priv_state *ps = (void *)(ds + 1);
136 int ret;
137
138 mutex_lock(&ps->smi_mutex);
139 ret = __mv88e6xxx_reg_write(ds->master_mii_bus,
140 ds->pd->sw_addr, addr, reg, val);
141 mutex_unlock(&ps->smi_mutex);
142
143 return ret;
144}
145
146int mv88e6xxx_config_prio(struct dsa_switch *ds)
147{
148 /*
149 * Configure the IP ToS mapping registers.
150 */
151 REG_WRITE(REG_GLOBAL, 0x10, 0x0000);
152 REG_WRITE(REG_GLOBAL, 0x11, 0x0000);
153 REG_WRITE(REG_GLOBAL, 0x12, 0x5555);
154 REG_WRITE(REG_GLOBAL, 0x13, 0x5555);
155 REG_WRITE(REG_GLOBAL, 0x14, 0xaaaa);
156 REG_WRITE(REG_GLOBAL, 0x15, 0xaaaa);
157 REG_WRITE(REG_GLOBAL, 0x16, 0xffff);
158 REG_WRITE(REG_GLOBAL, 0x17, 0xffff);
159
160 /*
161 * Configure the IEEE 802.1p priority mapping register.
162 */
163 REG_WRITE(REG_GLOBAL, 0x18, 0xfa41);
164
165 return 0;
166}
167
168int mv88e6xxx_set_addr_direct(struct dsa_switch *ds, u8 *addr)
169{
170 REG_WRITE(REG_GLOBAL, 0x01, (addr[0] << 8) | addr[1]);
171 REG_WRITE(REG_GLOBAL, 0x02, (addr[2] << 8) | addr[3]);
172 REG_WRITE(REG_GLOBAL, 0x03, (addr[4] << 8) | addr[5]);
173
174 return 0;
175}
176
177int mv88e6xxx_set_addr_indirect(struct dsa_switch *ds, u8 *addr)
178{
179 int i;
180 int ret;
181
182 for (i = 0; i < 6; i++) {
183 int j;
184
185 /*
186 * Write the MAC address byte.
187 */
188 REG_WRITE(REG_GLOBAL2, 0x0d, 0x8000 | (i << 8) | addr[i]);
189
190 /*
191 * Wait for the write to complete.
192 */
193 for (j = 0; j < 16; j++) {
194 ret = REG_READ(REG_GLOBAL2, 0x0d);
195 if ((ret & 0x8000) == 0)
196 break;
197 }
198 if (j == 16)
199 return -ETIMEDOUT;
200 }
201
202 return 0;
203}
204
205int mv88e6xxx_phy_read(struct dsa_switch *ds, int addr, int regnum)
206{
207 if (addr >= 0)
208 return mv88e6xxx_reg_read(ds, addr, regnum);
209 return 0xffff;
210}
211
212int mv88e6xxx_phy_write(struct dsa_switch *ds, int addr, int regnum, u16 val)
213{
214 if (addr >= 0)
215 return mv88e6xxx_reg_write(ds, addr, regnum, val);
216 return 0;
217}
218
219#ifdef CONFIG_NET_DSA_MV88E6XXX_NEED_PPU
220static int mv88e6xxx_ppu_disable(struct dsa_switch *ds)
221{
222 int ret;
223 int i;
224
225 ret = REG_READ(REG_GLOBAL, 0x04);
226 REG_WRITE(REG_GLOBAL, 0x04, ret & ~0x4000);
227
228 for (i = 0; i < 1000; i++) {
229 ret = REG_READ(REG_GLOBAL, 0x00);
230 msleep(1);
231 if ((ret & 0xc000) != 0xc000)
232 return 0;
233 }
234
235 return -ETIMEDOUT;
236}
237
238static int mv88e6xxx_ppu_enable(struct dsa_switch *ds)
239{
240 int ret;
241 int i;
242
243 ret = REG_READ(REG_GLOBAL, 0x04);
244 REG_WRITE(REG_GLOBAL, 0x04, ret | 0x4000);
245
246 for (i = 0; i < 1000; i++) {
247 ret = REG_READ(REG_GLOBAL, 0x00);
248 msleep(1);
249 if ((ret & 0xc000) == 0xc000)
250 return 0;
251 }
252
253 return -ETIMEDOUT;
254}
255
256static void mv88e6xxx_ppu_reenable_work(struct work_struct *ugly)
257{
258 struct mv88e6xxx_priv_state *ps;
259
260 ps = container_of(ugly, struct mv88e6xxx_priv_state, ppu_work);
261 if (mutex_trylock(&ps->ppu_mutex)) {
262 struct dsa_switch *ds = ((struct dsa_switch *)ps) - 1;
263
264 if (mv88e6xxx_ppu_enable(ds) == 0)
265 ps->ppu_disabled = 0;
266 mutex_unlock(&ps->ppu_mutex);
267 }
268}
269
270static void mv88e6xxx_ppu_reenable_timer(unsigned long _ps)
271{
272 struct mv88e6xxx_priv_state *ps = (void *)_ps;
273
274 schedule_work(&ps->ppu_work);
275}
276
277static int mv88e6xxx_ppu_access_get(struct dsa_switch *ds)
278{
279 struct mv88e6xxx_priv_state *ps = (void *)(ds + 1);
280 int ret;
281
282 mutex_lock(&ps->ppu_mutex);
283
284 /*
285 * If the PHY polling unit is enabled, disable it so that
286 * we can access the PHY registers. If it was already
287 * disabled, cancel the timer that is going to re-enable
288 * it.
289 */
290 if (!ps->ppu_disabled) {
291 ret = mv88e6xxx_ppu_disable(ds);
292 if (ret < 0) {
293 mutex_unlock(&ps->ppu_mutex);
294 return ret;
295 }
296 ps->ppu_disabled = 1;
297 } else {
298 del_timer(&ps->ppu_timer);
299 ret = 0;
300 }
301
302 return ret;
303}
304
305static void mv88e6xxx_ppu_access_put(struct dsa_switch *ds)
306{
307 struct mv88e6xxx_priv_state *ps = (void *)(ds + 1);
308
309 /*
310 * Schedule a timer to re-enable the PHY polling unit.
311 */
312 mod_timer(&ps->ppu_timer, jiffies + msecs_to_jiffies(10));
313 mutex_unlock(&ps->ppu_mutex);
314}
315
316void mv88e6xxx_ppu_state_init(struct dsa_switch *ds)
317{
318 struct mv88e6xxx_priv_state *ps = (void *)(ds + 1);
319
320 mutex_init(&ps->ppu_mutex);
321 INIT_WORK(&ps->ppu_work, mv88e6xxx_ppu_reenable_work);
322 init_timer(&ps->ppu_timer);
323 ps->ppu_timer.data = (unsigned long)ps;
324 ps->ppu_timer.function = mv88e6xxx_ppu_reenable_timer;
325}
326
327int mv88e6xxx_phy_read_ppu(struct dsa_switch *ds, int addr, int regnum)
328{
329 int ret;
330
331 ret = mv88e6xxx_ppu_access_get(ds);
332 if (ret >= 0) {
333 ret = mv88e6xxx_reg_read(ds, addr, regnum);
334 mv88e6xxx_ppu_access_put(ds);
335 }
336
337 return ret;
338}
339
340int mv88e6xxx_phy_write_ppu(struct dsa_switch *ds, int addr,
341 int regnum, u16 val)
342{
343 int ret;
344
345 ret = mv88e6xxx_ppu_access_get(ds);
346 if (ret >= 0) {
347 ret = mv88e6xxx_reg_write(ds, addr, regnum, val);
348 mv88e6xxx_ppu_access_put(ds);
349 }
350
351 return ret;
352}
353#endif
354
355void mv88e6xxx_poll_link(struct dsa_switch *ds)
356{
357 int i;
358
359 for (i = 0; i < DSA_MAX_PORTS; i++) {
360 struct net_device *dev;
361 int uninitialized_var(port_status);
362 int link;
363 int speed;
364 int duplex;
365 int fc;
366
367 dev = ds->ports[i];
368 if (dev == NULL)
369 continue;
370
371 link = 0;
372 if (dev->flags & IFF_UP) {
373 port_status = mv88e6xxx_reg_read(ds, REG_PORT(i), 0x00);
374 if (port_status < 0)
375 continue;
376
377 link = !!(port_status & 0x0800);
378 }
379
380 if (!link) {
381 if (netif_carrier_ok(dev)) {
382 printk(KERN_INFO "%s: link down\n", dev->name);
383 netif_carrier_off(dev);
384 }
385 continue;
386 }
387
388 switch (port_status & 0x0300) {
389 case 0x0000:
390 speed = 10;
391 break;
392 case 0x0100:
393 speed = 100;
394 break;
395 case 0x0200:
396 speed = 1000;
397 break;
398 default:
399 speed = -1;
400 break;
401 }
402 duplex = (port_status & 0x0400) ? 1 : 0;
403 fc = (port_status & 0x8000) ? 1 : 0;
404
405 if (!netif_carrier_ok(dev)) {
406 printk(KERN_INFO "%s: link up, %d Mb/s, %s duplex, "
407 "flow control %sabled\n", dev->name,
408 speed, duplex ? "full" : "half",
409 fc ? "en" : "dis");
410 netif_carrier_on(dev);
411 }
412 }
413}
414
415static int mv88e6xxx_stats_wait(struct dsa_switch *ds)
416{
417 int ret;
418 int i;
419
420 for (i = 0; i < 10; i++) {
421 ret = REG_READ(REG_GLOBAL, 0x1d);
422 if ((ret & 0x8000) == 0)
423 return 0;
424 }
425
426 return -ETIMEDOUT;
427}
428
429static int mv88e6xxx_stats_snapshot(struct dsa_switch *ds, int port)
430{
431 int ret;
432
433 /*
434 * Snapshot the hardware statistics counters for this port.
435 */
436 REG_WRITE(REG_GLOBAL, 0x1d, 0xdc00 | port);
437
438 /*
439 * Wait for the snapshotting to complete.
440 */
441 ret = mv88e6xxx_stats_wait(ds);
442 if (ret < 0)
443 return ret;
444
445 return 0;
446}
447
448static void mv88e6xxx_stats_read(struct dsa_switch *ds, int stat, u32 *val)
449{
450 u32 _val;
451 int ret;
452
453 *val = 0;
454
455 ret = mv88e6xxx_reg_write(ds, REG_GLOBAL, 0x1d, 0xcc00 | stat);
456 if (ret < 0)
457 return;
458
459 ret = mv88e6xxx_stats_wait(ds);
460 if (ret < 0)
461 return;
462
463 ret = mv88e6xxx_reg_read(ds, REG_GLOBAL, 0x1e);
464 if (ret < 0)
465 return;
466
467 _val = ret << 16;
468
469 ret = mv88e6xxx_reg_read(ds, REG_GLOBAL, 0x1f);
470 if (ret < 0)
471 return;
472
473 *val = _val | ret;
474}
475
476void mv88e6xxx_get_strings(struct dsa_switch *ds,
477 int nr_stats, struct mv88e6xxx_hw_stat *stats,
478 int port, uint8_t *data)
479{
480 int i;
481
482 for (i = 0; i < nr_stats; i++) {
483 memcpy(data + i * ETH_GSTRING_LEN,
484 stats[i].string, ETH_GSTRING_LEN);
485 }
486}
487
488void mv88e6xxx_get_ethtool_stats(struct dsa_switch *ds,
489 int nr_stats, struct mv88e6xxx_hw_stat *stats,
490 int port, uint64_t *data)
491{
492 struct mv88e6xxx_priv_state *ps = (void *)(ds + 1);
493 int ret;
494 int i;
495
496 mutex_lock(&ps->stats_mutex);
497
498 ret = mv88e6xxx_stats_snapshot(ds, port);
499 if (ret < 0) {
500 mutex_unlock(&ps->stats_mutex);
501 return;
502 }
503
504 /*
505 * Read each of the counters.
506 */
507 for (i = 0; i < nr_stats; i++) {
508 struct mv88e6xxx_hw_stat *s = stats + i;
509 u32 low;
510 u32 high;
511
512 mv88e6xxx_stats_read(ds, s->reg, &low);
513 if (s->sizeof_stat == 8)
514 mv88e6xxx_stats_read(ds, s->reg + 1, &high);
515 else
516 high = 0;
517
518 data[i] = (((u64)high) << 32) | low;
519 }
520
521 mutex_unlock(&ps->stats_mutex);
522}
523
524static int __init mv88e6xxx_init(void)
525{
526#if IS_ENABLED(CONFIG_NET_DSA_MV88E6131)
527 register_switch_driver(&mv88e6131_switch_driver);
528#endif
529#if IS_ENABLED(CONFIG_NET_DSA_MV88E6123_61_65)
530 register_switch_driver(&mv88e6123_61_65_switch_driver);
531#endif
532 return 0;
533}
534module_init(mv88e6xxx_init);
535
536static void __exit mv88e6xxx_cleanup(void)
537{
538#if IS_ENABLED(CONFIG_NET_DSA_MV88E6123_61_65)
539 unregister_switch_driver(&mv88e6123_61_65_switch_driver);
540#endif
541#if IS_ENABLED(CONFIG_NET_DSA_MV88E6131)
542 unregister_switch_driver(&mv88e6131_switch_driver);
543#endif
544}
545module_exit(mv88e6xxx_cleanup);
546
547MODULE_AUTHOR("Lennert Buytenhek <buytenh@wantstofly.org>");
548MODULE_DESCRIPTION("Driver for Marvell 88E6XXX ethernet switch chips");
549MODULE_LICENSE("GPL");
diff --git a/net/dsa/mv88e6xxx.h b/net/dsa/mv88e6xxx.h
deleted file mode 100644
index fc2cd7b90e8d..000000000000
--- a/net/dsa/mv88e6xxx.h
+++ /dev/null
@@ -1,98 +0,0 @@
1/*
2 * net/dsa/mv88e6xxx.h - Marvell 88e6xxx switch chip support
3 * Copyright (c) 2008 Marvell Semiconductor
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 */
10
11#ifndef __MV88E6XXX_H
12#define __MV88E6XXX_H
13
14#define REG_PORT(p) (0x10 + (p))
15#define REG_GLOBAL 0x1b
16#define REG_GLOBAL2 0x1c
17
18struct mv88e6xxx_priv_state {
19 /*
20 * When using multi-chip addressing, this mutex protects
21 * access to the indirect access registers. (In single-chip
22 * mode, this mutex is effectively useless.)
23 */
24 struct mutex smi_mutex;
25
26#ifdef CONFIG_NET_DSA_MV88E6XXX_NEED_PPU
27 /*
28 * Handles automatic disabling and re-enabling of the PHY
29 * polling unit.
30 */
31 struct mutex ppu_mutex;
32 int ppu_disabled;
33 struct work_struct ppu_work;
34 struct timer_list ppu_timer;
35#endif
36
37 /*
38 * This mutex serialises access to the statistics unit.
39 * Hold this mutex over snapshot + dump sequences.
40 */
41 struct mutex stats_mutex;
42
43 int id; /* switch product id */
44};
45
46struct mv88e6xxx_hw_stat {
47 char string[ETH_GSTRING_LEN];
48 int sizeof_stat;
49 int reg;
50};
51
52int __mv88e6xxx_reg_read(struct mii_bus *bus, int sw_addr, int addr, int reg);
53int mv88e6xxx_reg_read(struct dsa_switch *ds, int addr, int reg);
54int __mv88e6xxx_reg_write(struct mii_bus *bus, int sw_addr, int addr,
55 int reg, u16 val);
56int mv88e6xxx_reg_write(struct dsa_switch *ds, int addr, int reg, u16 val);
57int mv88e6xxx_config_prio(struct dsa_switch *ds);
58int mv88e6xxx_set_addr_direct(struct dsa_switch *ds, u8 *addr);
59int mv88e6xxx_set_addr_indirect(struct dsa_switch *ds, u8 *addr);
60int mv88e6xxx_phy_read(struct dsa_switch *ds, int addr, int regnum);
61int mv88e6xxx_phy_write(struct dsa_switch *ds, int addr, int regnum, u16 val);
62void mv88e6xxx_ppu_state_init(struct dsa_switch *ds);
63int mv88e6xxx_phy_read_ppu(struct dsa_switch *ds, int addr, int regnum);
64int mv88e6xxx_phy_write_ppu(struct dsa_switch *ds, int addr,
65 int regnum, u16 val);
66void mv88e6xxx_poll_link(struct dsa_switch *ds);
67void mv88e6xxx_get_strings(struct dsa_switch *ds,
68 int nr_stats, struct mv88e6xxx_hw_stat *stats,
69 int port, uint8_t *data);
70void mv88e6xxx_get_ethtool_stats(struct dsa_switch *ds,
71 int nr_stats, struct mv88e6xxx_hw_stat *stats,
72 int port, uint64_t *data);
73
74extern struct dsa_switch_driver mv88e6131_switch_driver;
75extern struct dsa_switch_driver mv88e6123_61_65_switch_driver;
76
77#define REG_READ(addr, reg) \
78 ({ \
79 int __ret; \
80 \
81 __ret = mv88e6xxx_reg_read(ds, addr, reg); \
82 if (__ret < 0) \
83 return __ret; \
84 __ret; \
85 })
86
87#define REG_WRITE(addr, reg, val) \
88 ({ \
89 int __ret; \
90 \
91 __ret = mv88e6xxx_reg_write(ds, addr, reg, val); \
92 if (__ret < 0) \
93 return __ret; \
94 })
95
96
97
98#endif