aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLennert Buytenhek <buytenh@wantstofly.org>2008-10-07 09:45:18 -0400
committerDavid S. Miller <davem@davemloft.net>2008-10-08 20:24:09 -0400
commit2e5f032095ff101274dfb03d5fd5e06d9aeb83cd (patch)
treeeeb61cf6665452288a25434c54bc8d4ff8031cef
parentcf85d08fdf4548ee46657ccfb7f9949a85145db5 (diff)
dsa: add support for the Marvell 88E6131 switch chip
Add support for the Marvell 88E6131 switch chip. This chip only supports the original (ethertype-less) DSA tagging format. On the 88E6131, there is a PHY Polling Unit (PPU) which has exclusive access to each of the PHYs's MII management registers. If we want to talk to the PHYs from software, we have to disable the PPU and wait for it to complete its current transaction before we can do so, and we need to re-enable the PPU afterwards to make sure that the switch will notice changes in link state and speed on the individual ports as they occur. Since disabling the PPU is rather slow, and since MII management accesses are typically done in bursts, this patch keeps the PPU disabled for 10ms after a software access completes. This makes handling the PPU slightly more complex, but speeds up something like running ethtool on one of the switch slave interfaces from ~300ms to ~30ms on typical hardware. Signed-off-by: Lennert Buytenhek <buytenh@marvell.com> Tested-by: Nicolas Pitre <nico@marvell.com> Tested-by: Peter van Valderen <linux@ddcrew.com> Tested-by: Dirk Teurlings <dirk@upexia.nl> Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--net/dsa/Kconfig13
-rw-r--r--net/dsa/Makefile1
-rw-r--r--net/dsa/mv88e6131.c380
-rw-r--r--net/dsa/mv88e6xxx.c145
-rw-r--r--net/dsa/mv88e6xxx.h16
5 files changed, 555 insertions, 0 deletions
diff --git a/net/dsa/Kconfig b/net/dsa/Kconfig
index 6b68016827da..79bcd76d3f10 100644
--- a/net/dsa/Kconfig
+++ b/net/dsa/Kconfig
@@ -24,6 +24,19 @@ config NET_DSA_MV88E6XXX
24 bool 24 bool
25 default n 25 default n
26 26
27config NET_DSA_MV88E6XXX_NEED_PPU
28 bool
29 default n
30
31config NET_DSA_MV88E6131
32 bool "Marvell 88E6131 ethernet switch chip support"
33 select NET_DSA_MV88E6XXX
34 select NET_DSA_MV88E6XXX_NEED_PPU
35 select NET_DSA_TAG_DSA
36 ---help---
37 This enables support for the Marvell 88E6131 ethernet switch
38 chip.
39
27config NET_DSA_MV88E6123_61_65 40config NET_DSA_MV88E6123_61_65
28 bool "Marvell 88E6123/6161/6165 ethernet switch chip support" 41 bool "Marvell 88E6123/6161/6165 ethernet switch chip support"
29 select NET_DSA_MV88E6XXX 42 select NET_DSA_MV88E6XXX
diff --git a/net/dsa/Makefile b/net/dsa/Makefile
index 8b92123315b8..7fb6f85a69ed 100644
--- a/net/dsa/Makefile
+++ b/net/dsa/Makefile
@@ -5,6 +5,7 @@ obj-$(CONFIG_NET_DSA_TAG_EDSA) += tag_edsa.o
5# switch drivers 5# switch drivers
6obj-$(CONFIG_NET_DSA_MV88E6XXX) += mv88e6xxx.o 6obj-$(CONFIG_NET_DSA_MV88E6XXX) += mv88e6xxx.o
7obj-$(CONFIG_NET_DSA_MV88E6123_61_65) += mv88e6123_61_65.o 7obj-$(CONFIG_NET_DSA_MV88E6123_61_65) += mv88e6123_61_65.o
8obj-$(CONFIG_NET_DSA_MV88E6131) += mv88e6131.o
8 9
9# the core 10# the core
10obj-$(CONFIG_NET_DSA) += dsa.o slave.o 11obj-$(CONFIG_NET_DSA) += dsa.o slave.o
diff --git a/net/dsa/mv88e6131.c b/net/dsa/mv88e6131.c
new file mode 100644
index 000000000000..36e01eb863a0
--- /dev/null
+++ b/net/dsa/mv88e6131.c
@@ -0,0 +1,380 @@
1/*
2 * net/dsa/mv88e6131.c - Marvell 88e6131 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 "dsa_priv.h"
15#include "mv88e6xxx.h"
16
17static char *mv88e6131_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 == 0x1060)
25 return "Marvell 88E6131";
26 }
27
28 return NULL;
29}
30
31static int mv88e6131_switch_reset(struct dsa_switch *ds)
32{
33 int i;
34 int ret;
35
36 /*
37 * Set all ports to the disabled state.
38 */
39 for (i = 0; i < 8; i++) {
40 ret = REG_READ(REG_PORT(i), 0x04);
41 REG_WRITE(REG_PORT(i), 0x04, ret & 0xfffc);
42 }
43
44 /*
45 * Wait for transmit queues to drain.
46 */
47 msleep(2);
48
49 /*
50 * Reset the switch.
51 */
52 REG_WRITE(REG_GLOBAL, 0x04, 0xc400);
53
54 /*
55 * Wait up to one second for reset to complete.
56 */
57 for (i = 0; i < 1000; i++) {
58 ret = REG_READ(REG_GLOBAL, 0x00);
59 if ((ret & 0xc800) == 0xc800)
60 break;
61
62 msleep(1);
63 }
64 if (i == 1000)
65 return -ETIMEDOUT;
66
67 return 0;
68}
69
70static int mv88e6131_setup_global(struct dsa_switch *ds)
71{
72 int ret;
73 int i;
74
75 /*
76 * Enable the PHY polling unit, don't discard packets with
77 * excessive collisions, use a weighted fair queueing scheme
78 * to arbitrate between packet queues, set the maximum frame
79 * size to 1632, and mask all interrupt sources.
80 */
81 REG_WRITE(REG_GLOBAL, 0x04, 0x4400);
82
83 /*
84 * Set the default address aging time to 5 minutes, and
85 * enable address learn messages to be sent to all message
86 * ports.
87 */
88 REG_WRITE(REG_GLOBAL, 0x0a, 0x0148);
89
90 /*
91 * Configure the priority mapping registers.
92 */
93 ret = mv88e6xxx_config_prio(ds);
94 if (ret < 0)
95 return ret;
96
97 /*
98 * Set the VLAN ethertype to 0x8100.
99 */
100 REG_WRITE(REG_GLOBAL, 0x19, 0x8100);
101
102 /*
103 * Disable ARP mirroring, and configure the cpu port as the
104 * port to which ingress and egress monitor frames are to be
105 * sent.
106 */
107 REG_WRITE(REG_GLOBAL, 0x1a, (ds->cpu_port * 0x1100) | 0x00f0);
108
109 /*
110 * Disable cascade port functionality, and set the switch's
111 * DSA device number to zero.
112 */
113 REG_WRITE(REG_GLOBAL, 0x1c, 0xe000);
114
115 /*
116 * Send all frames with destination addresses matching
117 * 01:80:c2:00:00:0x to the CPU port.
118 */
119 REG_WRITE(REG_GLOBAL2, 0x03, 0xffff);
120
121 /*
122 * Ignore removed tag data on doubly tagged packets, disable
123 * flow control messages, force flow control priority to the
124 * highest, and send all special multicast frames to the CPU
125 * port at the higest priority.
126 */
127 REG_WRITE(REG_GLOBAL2, 0x05, 0x00ff);
128
129 /*
130 * Map all DSA device IDs to the CPU port.
131 */
132 for (i = 0; i < 32; i++)
133 REG_WRITE(REG_GLOBAL2, 0x06, 0x8000 | (i << 8) | ds->cpu_port);
134
135 /*
136 * Clear all trunk masks.
137 */
138 for (i = 0; i < 8; i++)
139 REG_WRITE(REG_GLOBAL2, 0x07, 0x8000 | (i << 12) | 0xff);
140
141 /*
142 * Clear all trunk mappings.
143 */
144 for (i = 0; i < 16; i++)
145 REG_WRITE(REG_GLOBAL2, 0x08, 0x8000 | (i << 11));
146
147 /*
148 * Force the priority of IGMP/MLD snoop frames and ARP frames
149 * to the highest setting.
150 */
151 REG_WRITE(REG_GLOBAL2, 0x0f, 0x00ff);
152
153 return 0;
154}
155
156static int mv88e6131_setup_port(struct dsa_switch *ds, int p)
157{
158 int addr = REG_PORT(p);
159
160 /*
161 * MAC Forcing register: don't force link, speed, duplex
162 * or flow control state to any particular values.
163 */
164 REG_WRITE(addr, 0x01, 0x0003);
165
166 /*
167 * Port Control: disable Core Tag, disable Drop-on-Lock,
168 * transmit frames unmodified, disable Header mode,
169 * enable IGMP/MLD snoop, disable DoubleTag, disable VLAN
170 * tunneling, determine priority by looking at 802.1p and
171 * IP priority fields (IP prio has precedence), and set STP
172 * state to Forwarding. Finally, if this is the CPU port,
173 * additionally enable DSA tagging and forwarding of unknown
174 * unicast addresses.
175 */
176 REG_WRITE(addr, 0x04, (p == ds->cpu_port) ? 0x0537 : 0x0433);
177
178 /*
179 * Port Control 1: disable trunking. Also, if this is the
180 * CPU port, enable learn messages to be sent to this port.
181 */
182 REG_WRITE(addr, 0x05, (p == ds->cpu_port) ? 0x8000 : 0x0000);
183
184 /*
185 * Port based VLAN map: give each port its own address
186 * database, allow the CPU port to talk to each of the 'real'
187 * ports, and allow each of the 'real' ports to only talk to
188 * the CPU port.
189 */
190 REG_WRITE(addr, 0x06,
191 ((p & 0xf) << 12) |
192 ((p == ds->cpu_port) ?
193 ds->valid_port_mask :
194 (1 << ds->cpu_port)));
195
196 /*
197 * Default VLAN ID and priority: don't set a default VLAN
198 * ID, and set the default packet priority to zero.
199 */
200 REG_WRITE(addr, 0x07, 0x0000);
201
202 /*
203 * Port Control 2: don't force a good FCS, don't use
204 * VLAN-based, source address-based or destination
205 * address-based priority overrides, don't let the switch
206 * add or strip 802.1q tags, don't discard tagged or
207 * untagged frames on this port, do a destination address
208 * lookup on received packets as usual, don't send a copy
209 * of all transmitted/received frames on this port to the
210 * CPU, and configure the CPU port number. Also, if this
211 * is the CPU port, enable forwarding of unknown multicast
212 * addresses.
213 */
214 REG_WRITE(addr, 0x08,
215 ((p == ds->cpu_port) ? 0x00c0 : 0x0080) |
216 ds->cpu_port);
217
218 /*
219 * Rate Control: disable ingress rate limiting.
220 */
221 REG_WRITE(addr, 0x09, 0x0000);
222
223 /*
224 * Rate Control 2: disable egress rate limiting.
225 */
226 REG_WRITE(addr, 0x0a, 0x0000);
227
228 /*
229 * Port Association Vector: when learning source addresses
230 * of packets, add the address to the address database using
231 * a port bitmap that has only the bit for this port set and
232 * the other bits clear.
233 */
234 REG_WRITE(addr, 0x0b, 1 << p);
235
236 /*
237 * Tag Remap: use an identity 802.1p prio -> switch prio
238 * mapping.
239 */
240 REG_WRITE(addr, 0x18, 0x3210);
241
242 /*
243 * Tag Remap 2: use an identity 802.1p prio -> switch prio
244 * mapping.
245 */
246 REG_WRITE(addr, 0x19, 0x7654);
247
248 return 0;
249}
250
251static int mv88e6131_setup(struct dsa_switch *ds)
252{
253 struct mv88e6xxx_priv_state *ps = (void *)(ds + 1);
254 int i;
255 int ret;
256
257 mutex_init(&ps->smi_mutex);
258 mv88e6xxx_ppu_state_init(ds);
259 mutex_init(&ps->stats_mutex);
260
261 ret = mv88e6131_switch_reset(ds);
262 if (ret < 0)
263 return ret;
264
265 /* @@@ initialise vtu and atu */
266
267 ret = mv88e6131_setup_global(ds);
268 if (ret < 0)
269 return ret;
270
271 for (i = 0; i < 6; i++) {
272 ret = mv88e6131_setup_port(ds, i);
273 if (ret < 0)
274 return ret;
275 }
276
277 return 0;
278}
279
280static int mv88e6131_port_to_phy_addr(int port)
281{
282 if (port >= 0 && port != 3 && port <= 7)
283 return port;
284 return -1;
285}
286
287static int
288mv88e6131_phy_read(struct dsa_switch *ds, int port, int regnum)
289{
290 int addr = mv88e6131_port_to_phy_addr(port);
291 return mv88e6xxx_phy_read_ppu(ds, addr, regnum);
292}
293
294static int
295mv88e6131_phy_write(struct dsa_switch *ds,
296 int port, int regnum, u16 val)
297{
298 int addr = mv88e6131_port_to_phy_addr(port);
299 return mv88e6xxx_phy_write_ppu(ds, addr, regnum, val);
300}
301
302static struct mv88e6xxx_hw_stat mv88e6131_hw_stats[] = {
303 { "in_good_octets", 8, 0x00, },
304 { "in_bad_octets", 4, 0x02, },
305 { "in_unicast", 4, 0x04, },
306 { "in_broadcasts", 4, 0x06, },
307 { "in_multicasts", 4, 0x07, },
308 { "in_pause", 4, 0x16, },
309 { "in_undersize", 4, 0x18, },
310 { "in_fragments", 4, 0x19, },
311 { "in_oversize", 4, 0x1a, },
312 { "in_jabber", 4, 0x1b, },
313 { "in_rx_error", 4, 0x1c, },
314 { "in_fcs_error", 4, 0x1d, },
315 { "out_octets", 8, 0x0e, },
316 { "out_unicast", 4, 0x10, },
317 { "out_broadcasts", 4, 0x13, },
318 { "out_multicasts", 4, 0x12, },
319 { "out_pause", 4, 0x15, },
320 { "excessive", 4, 0x11, },
321 { "collisions", 4, 0x1e, },
322 { "deferred", 4, 0x05, },
323 { "single", 4, 0x14, },
324 { "multiple", 4, 0x17, },
325 { "out_fcs_error", 4, 0x03, },
326 { "late", 4, 0x1f, },
327 { "hist_64bytes", 4, 0x08, },
328 { "hist_65_127bytes", 4, 0x09, },
329 { "hist_128_255bytes", 4, 0x0a, },
330 { "hist_256_511bytes", 4, 0x0b, },
331 { "hist_512_1023bytes", 4, 0x0c, },
332 { "hist_1024_max_bytes", 4, 0x0d, },
333};
334
335static void
336mv88e6131_get_strings(struct dsa_switch *ds, int port, uint8_t *data)
337{
338 mv88e6xxx_get_strings(ds, ARRAY_SIZE(mv88e6131_hw_stats),
339 mv88e6131_hw_stats, port, data);
340}
341
342static void
343mv88e6131_get_ethtool_stats(struct dsa_switch *ds,
344 int port, uint64_t *data)
345{
346 mv88e6xxx_get_ethtool_stats(ds, ARRAY_SIZE(mv88e6131_hw_stats),
347 mv88e6131_hw_stats, port, data);
348}
349
350static int mv88e6131_get_sset_count(struct dsa_switch *ds)
351{
352 return ARRAY_SIZE(mv88e6131_hw_stats);
353}
354
355static struct dsa_switch_driver mv88e6131_switch_driver = {
356 .tag_protocol = __constant_htons(ETH_P_DSA),
357 .priv_size = sizeof(struct mv88e6xxx_priv_state),
358 .probe = mv88e6131_probe,
359 .setup = mv88e6131_setup,
360 .set_addr = mv88e6xxx_set_addr_direct,
361 .phy_read = mv88e6131_phy_read,
362 .phy_write = mv88e6131_phy_write,
363 .poll_link = mv88e6xxx_poll_link,
364 .get_strings = mv88e6131_get_strings,
365 .get_ethtool_stats = mv88e6131_get_ethtool_stats,
366 .get_sset_count = mv88e6131_get_sset_count,
367};
368
369int __init mv88e6131_init(void)
370{
371 register_switch_driver(&mv88e6131_switch_driver);
372 return 0;
373}
374module_init(mv88e6131_init);
375
376void __exit mv88e6131_cleanup(void)
377{
378 unregister_switch_driver(&mv88e6131_switch_driver);
379}
380module_exit(mv88e6131_cleanup);
diff --git a/net/dsa/mv88e6xxx.c b/net/dsa/mv88e6xxx.c
index 13d2328a2406..aa6c609c59f2 100644
--- a/net/dsa/mv88e6xxx.c
+++ b/net/dsa/mv88e6xxx.c
@@ -165,6 +165,15 @@ int mv88e6xxx_config_prio(struct dsa_switch *ds)
165 return 0; 165 return 0;
166} 166}
167 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
168int mv88e6xxx_set_addr_indirect(struct dsa_switch *ds, u8 *addr) 177int mv88e6xxx_set_addr_indirect(struct dsa_switch *ds, u8 *addr)
169{ 178{
170 int i; 179 int i;
@@ -207,6 +216,142 @@ int mv88e6xxx_phy_write(struct dsa_switch *ds, int addr, int regnum, u16 val)
207 return 0; 216 return 0;
208} 217}
209 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
210void mv88e6xxx_poll_link(struct dsa_switch *ds) 355void mv88e6xxx_poll_link(struct dsa_switch *ds)
211{ 356{
212 int i; 357 int i;
diff --git a/net/dsa/mv88e6xxx.h b/net/dsa/mv88e6xxx.h
index a004d4d02081..eb0e0aaa9f1b 100644
--- a/net/dsa/mv88e6xxx.h
+++ b/net/dsa/mv88e6xxx.h
@@ -23,6 +23,17 @@ struct mv88e6xxx_priv_state {
23 */ 23 */
24 struct mutex smi_mutex; 24 struct mutex smi_mutex;
25 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
26 /* 37 /*
27 * This mutex serialises access to the statistics unit. 38 * This mutex serialises access to the statistics unit.
28 * Hold this mutex over snapshot + dump sequences. 39 * Hold this mutex over snapshot + dump sequences.
@@ -42,9 +53,14 @@ int __mv88e6xxx_reg_write(struct mii_bus *bus, int sw_addr, int addr,
42 int reg, u16 val); 53 int reg, u16 val);
43int mv88e6xxx_reg_write(struct dsa_switch *ds, int addr, int reg, u16 val); 54int mv88e6xxx_reg_write(struct dsa_switch *ds, int addr, int reg, u16 val);
44int mv88e6xxx_config_prio(struct dsa_switch *ds); 55int mv88e6xxx_config_prio(struct dsa_switch *ds);
56int mv88e6xxx_set_addr_direct(struct dsa_switch *ds, u8 *addr);
45int mv88e6xxx_set_addr_indirect(struct dsa_switch *ds, u8 *addr); 57int mv88e6xxx_set_addr_indirect(struct dsa_switch *ds, u8 *addr);
46int mv88e6xxx_phy_read(struct dsa_switch *ds, int addr, int regnum); 58int mv88e6xxx_phy_read(struct dsa_switch *ds, int addr, int regnum);
47int mv88e6xxx_phy_write(struct dsa_switch *ds, int addr, int regnum, u16 val); 59int mv88e6xxx_phy_write(struct dsa_switch *ds, int addr, int regnum, u16 val);
60void mv88e6xxx_ppu_state_init(struct dsa_switch *ds);
61int mv88e6xxx_phy_read_ppu(struct dsa_switch *ds, int addr, int regnum);
62int mv88e6xxx_phy_write_ppu(struct dsa_switch *ds, int addr,
63 int regnum, u16 val);
48void mv88e6xxx_poll_link(struct dsa_switch *ds); 64void mv88e6xxx_poll_link(struct dsa_switch *ds);
49void mv88e6xxx_get_strings(struct dsa_switch *ds, 65void mv88e6xxx_get_strings(struct dsa_switch *ds,
50 int nr_stats, struct mv88e6xxx_hw_stat *stats, 66 int nr_stats, struct mv88e6xxx_hw_stat *stats,