802.3ad: remove typedef around ad_system
[linux-2.6] / net / dsa / mv88e6131.c
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
17 static 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
31 static 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
70 static 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
156 static 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
251 static 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
280 static 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
287 static int
288 mv88e6131_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
294 static int
295 mv88e6131_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
302 static 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
335 static void
336 mv88e6131_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
342 static void
343 mv88e6131_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
350 static int mv88e6131_get_sset_count(struct dsa_switch *ds)
351 {
352         return ARRAY_SIZE(mv88e6131_hw_stats);
353 }
354
355 static 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
369 static int __init mv88e6131_init(void)
370 {
371         register_switch_driver(&mv88e6131_switch_driver);
372         return 0;
373 }
374 module_init(mv88e6131_init);
375
376 static void __exit mv88e6131_cleanup(void)
377 {
378         unregister_switch_driver(&mv88e6131_switch_driver);
379 }
380 module_exit(mv88e6131_cleanup);