• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
mv88e6131_probe(struct mii_bus * bus,int sw_addr)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 
mv88e6131_switch_reset(struct dsa_switch * ds)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 
mv88e6131_setup_global(struct dsa_switch * ds)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 
mv88e6131_setup_port(struct dsa_switch * ds,int p)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 
mv88e6131_setup(struct dsa_switch * ds)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 
mv88e6131_port_to_phy_addr(int port)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
mv88e6131_phy_read(struct dsa_switch * ds,int port,int regnum)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
mv88e6131_phy_write(struct dsa_switch * ds,int port,int regnum,u16 val)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
mv88e6131_get_strings(struct dsa_switch * ds,int port,uint8_t * data)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
mv88e6131_get_ethtool_stats(struct dsa_switch * ds,int port,uint64_t * data)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 
mv88e6131_get_sset_count(struct dsa_switch * ds)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 
mv88e6131_init(void)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 
mv88e6131_cleanup(void)376 static void __exit mv88e6131_cleanup(void)
377 {
378 	unregister_switch_driver(&mv88e6131_switch_driver);
379 }
380 module_exit(mv88e6131_cleanup);
381