blob: f38d8dfa934a929433fe736d8f15488e9131d3f5 [file] [log] [blame]
Lennert Buytenhek91da11f2008-10-07 13:44:02 +00001/*
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
Barry Grussling19b2f972013-01-08 16:05:54 +000011#include <linux/delay.h>
Guenter Roeckdefb05b2015-03-26 18:36:38 -070012#include <linux/etherdevice.h>
Guenter Roeckfacd95b2015-03-26 18:36:35 -070013#include <linux/if_bridge.h>
Barry Grussling19b2f972013-01-08 16:05:54 +000014#include <linux/jiffies.h>
Lennert Buytenhek91da11f2008-10-07 13:44:02 +000015#include <linux/list.h>
Paul Gortmaker2bbba272012-01-24 10:41:40 +000016#include <linux/module.h>
Lennert Buytenhek91da11f2008-10-07 13:44:02 +000017#include <linux/netdevice.h>
18#include <linux/phy.h>
Ben Hutchingsc8f0b862011-11-27 17:06:08 +000019#include <net/dsa.h>
Lennert Buytenhek91da11f2008-10-07 13:44:02 +000020#include "mv88e6xxx.h"
21
Barry Grussling3675c8d2013-01-08 16:05:53 +000022/* If the switch's ADDR[4:0] strap pins are strapped to zero, it will
Lennert Buytenhek91da11f2008-10-07 13:44:02 +000023 * use all 32 SMI bus addresses on its SMI bus, and all switch registers
24 * will be directly accessible on some {device address,register address}
25 * pair. If the ADDR[4:0] pins are not strapped to zero, the switch
26 * will only respond to SMI transactions to that specific address, and
27 * an indirect addressing mechanism needs to be used to access its
28 * registers.
29 */
30static int mv88e6xxx_reg_wait_ready(struct mii_bus *bus, int sw_addr)
31{
32 int ret;
33 int i;
34
35 for (i = 0; i < 16; i++) {
Andrew Lunncca8b132015-04-02 04:06:39 +020036 ret = mdiobus_read(bus, sw_addr, SMI_CMD);
Lennert Buytenhek91da11f2008-10-07 13:44:02 +000037 if (ret < 0)
38 return ret;
39
Andrew Lunncca8b132015-04-02 04:06:39 +020040 if ((ret & SMI_CMD_BUSY) == 0)
Lennert Buytenhek91da11f2008-10-07 13:44:02 +000041 return 0;
42 }
43
44 return -ETIMEDOUT;
45}
46
47int __mv88e6xxx_reg_read(struct mii_bus *bus, int sw_addr, int addr, int reg)
48{
49 int ret;
50
51 if (sw_addr == 0)
52 return mdiobus_read(bus, addr, reg);
53
Barry Grussling3675c8d2013-01-08 16:05:53 +000054 /* Wait for the bus to become free. */
Lennert Buytenhek91da11f2008-10-07 13:44:02 +000055 ret = mv88e6xxx_reg_wait_ready(bus, sw_addr);
56 if (ret < 0)
57 return ret;
58
Barry Grussling3675c8d2013-01-08 16:05:53 +000059 /* Transmit the read command. */
Andrew Lunncca8b132015-04-02 04:06:39 +020060 ret = mdiobus_write(bus, sw_addr, SMI_CMD,
61 SMI_CMD_OP_22_READ | (addr << 5) | reg);
Lennert Buytenhek91da11f2008-10-07 13:44:02 +000062 if (ret < 0)
63 return ret;
64
Barry Grussling3675c8d2013-01-08 16:05:53 +000065 /* Wait for the read command to complete. */
Lennert Buytenhek91da11f2008-10-07 13:44:02 +000066 ret = mv88e6xxx_reg_wait_ready(bus, sw_addr);
67 if (ret < 0)
68 return ret;
69
Barry Grussling3675c8d2013-01-08 16:05:53 +000070 /* Read the data. */
Andrew Lunncca8b132015-04-02 04:06:39 +020071 ret = mdiobus_read(bus, sw_addr, SMI_DATA);
Lennert Buytenhek91da11f2008-10-07 13:44:02 +000072 if (ret < 0)
73 return ret;
74
75 return ret & 0xffff;
76}
77
Guenter Roeck8d6d09e2015-03-26 18:36:31 -070078/* Must be called with SMI mutex held */
79static int _mv88e6xxx_reg_read(struct dsa_switch *ds, int addr, int reg)
Lennert Buytenhek91da11f2008-10-07 13:44:02 +000080{
Guenter Roeckb184e492014-10-17 12:30:58 -070081 struct mii_bus *bus = dsa_host_dev_to_mii_bus(ds->master_dev);
Lennert Buytenhek91da11f2008-10-07 13:44:02 +000082 int ret;
83
Guenter Roeckb184e492014-10-17 12:30:58 -070084 if (bus == NULL)
85 return -EINVAL;
86
Guenter Roeckb184e492014-10-17 12:30:58 -070087 ret = __mv88e6xxx_reg_read(bus, ds->pd->sw_addr, addr, reg);
Vivien Didelotbb92ea52015-01-23 16:10:36 -050088 if (ret < 0)
89 return ret;
90
91 dev_dbg(ds->master_dev, "<- addr: 0x%.2x reg: 0x%.2x val: 0x%.4x\n",
92 addr, reg, ret);
93
Lennert Buytenhek91da11f2008-10-07 13:44:02 +000094 return ret;
95}
96
Guenter Roeck8d6d09e2015-03-26 18:36:31 -070097int mv88e6xxx_reg_read(struct dsa_switch *ds, int addr, int reg)
98{
99 struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
100 int ret;
101
102 mutex_lock(&ps->smi_mutex);
103 ret = _mv88e6xxx_reg_read(ds, addr, reg);
104 mutex_unlock(&ps->smi_mutex);
105
106 return ret;
107}
108
Lennert Buytenhek91da11f2008-10-07 13:44:02 +0000109int __mv88e6xxx_reg_write(struct mii_bus *bus, int sw_addr, int addr,
110 int reg, u16 val)
111{
112 int ret;
113
114 if (sw_addr == 0)
115 return mdiobus_write(bus, addr, reg, val);
116
Barry Grussling3675c8d2013-01-08 16:05:53 +0000117 /* Wait for the bus to become free. */
Lennert Buytenhek91da11f2008-10-07 13:44:02 +0000118 ret = mv88e6xxx_reg_wait_ready(bus, sw_addr);
119 if (ret < 0)
120 return ret;
121
Barry Grussling3675c8d2013-01-08 16:05:53 +0000122 /* Transmit the data to write. */
Andrew Lunncca8b132015-04-02 04:06:39 +0200123 ret = mdiobus_write(bus, sw_addr, SMI_DATA, val);
Lennert Buytenhek91da11f2008-10-07 13:44:02 +0000124 if (ret < 0)
125 return ret;
126
Barry Grussling3675c8d2013-01-08 16:05:53 +0000127 /* Transmit the write command. */
Andrew Lunncca8b132015-04-02 04:06:39 +0200128 ret = mdiobus_write(bus, sw_addr, SMI_CMD,
129 SMI_CMD_OP_22_WRITE | (addr << 5) | reg);
Lennert Buytenhek91da11f2008-10-07 13:44:02 +0000130 if (ret < 0)
131 return ret;
132
Barry Grussling3675c8d2013-01-08 16:05:53 +0000133 /* Wait for the write command to complete. */
Lennert Buytenhek91da11f2008-10-07 13:44:02 +0000134 ret = mv88e6xxx_reg_wait_ready(bus, sw_addr);
135 if (ret < 0)
136 return ret;
137
138 return 0;
139}
140
Guenter Roeck8d6d09e2015-03-26 18:36:31 -0700141/* Must be called with SMI mutex held */
142static int _mv88e6xxx_reg_write(struct dsa_switch *ds, int addr, int reg,
143 u16 val)
Lennert Buytenhek91da11f2008-10-07 13:44:02 +0000144{
Guenter Roeckb184e492014-10-17 12:30:58 -0700145 struct mii_bus *bus = dsa_host_dev_to_mii_bus(ds->master_dev);
Lennert Buytenhek91da11f2008-10-07 13:44:02 +0000146
Guenter Roeckb184e492014-10-17 12:30:58 -0700147 if (bus == NULL)
148 return -EINVAL;
149
Vivien Didelotbb92ea52015-01-23 16:10:36 -0500150 dev_dbg(ds->master_dev, "-> addr: 0x%.2x reg: 0x%.2x val: 0x%.4x\n",
151 addr, reg, val);
152
Guenter Roeck8d6d09e2015-03-26 18:36:31 -0700153 return __mv88e6xxx_reg_write(bus, ds->pd->sw_addr, addr, reg, val);
154}
155
156int mv88e6xxx_reg_write(struct dsa_switch *ds, int addr, int reg, u16 val)
157{
158 struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
159 int ret;
160
Lennert Buytenhek91da11f2008-10-07 13:44:02 +0000161 mutex_lock(&ps->smi_mutex);
Guenter Roeck8d6d09e2015-03-26 18:36:31 -0700162 ret = _mv88e6xxx_reg_write(ds, addr, reg, val);
Lennert Buytenhek91da11f2008-10-07 13:44:02 +0000163 mutex_unlock(&ps->smi_mutex);
164
165 return ret;
166}
167
Lennert Buytenhek2e5f0322008-10-07 13:45:18 +0000168int mv88e6xxx_set_addr_direct(struct dsa_switch *ds, u8 *addr)
169{
Andrew Lunncca8b132015-04-02 04:06:39 +0200170 REG_WRITE(REG_GLOBAL, GLOBAL_MAC_01, (addr[0] << 8) | addr[1]);
171 REG_WRITE(REG_GLOBAL, GLOBAL_MAC_23, (addr[2] << 8) | addr[3]);
172 REG_WRITE(REG_GLOBAL, GLOBAL_MAC_45, (addr[4] << 8) | addr[5]);
Lennert Buytenhek2e5f0322008-10-07 13:45:18 +0000173
174 return 0;
175}
176
Lennert Buytenhek91da11f2008-10-07 13:44:02 +0000177int 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
Barry Grussling3675c8d2013-01-08 16:05:53 +0000185 /* Write the MAC address byte. */
Andrew Lunncca8b132015-04-02 04:06:39 +0200186 REG_WRITE(REG_GLOBAL2, GLOBAL2_SWITCH_MAC,
187 GLOBAL2_SWITCH_MAC_BUSY | (i << 8) | addr[i]);
Lennert Buytenhek91da11f2008-10-07 13:44:02 +0000188
Barry Grussling3675c8d2013-01-08 16:05:53 +0000189 /* Wait for the write to complete. */
Lennert Buytenhek91da11f2008-10-07 13:44:02 +0000190 for (j = 0; j < 16; j++) {
Andrew Lunncca8b132015-04-02 04:06:39 +0200191 ret = REG_READ(REG_GLOBAL2, GLOBAL2_SWITCH_MAC);
192 if ((ret & GLOBAL2_SWITCH_MAC_BUSY) == 0)
Lennert Buytenhek91da11f2008-10-07 13:44:02 +0000193 break;
194 }
195 if (j == 16)
196 return -ETIMEDOUT;
197 }
198
199 return 0;
200}
201
Andrew Lunnfd3a0ee2015-04-02 04:06:36 +0200202/* Must be called with phy mutex held */
203static int _mv88e6xxx_phy_read(struct dsa_switch *ds, int addr, int regnum)
Lennert Buytenhek91da11f2008-10-07 13:44:02 +0000204{
205 if (addr >= 0)
206 return mv88e6xxx_reg_read(ds, addr, regnum);
207 return 0xffff;
208}
209
Andrew Lunnfd3a0ee2015-04-02 04:06:36 +0200210/* Must be called with phy mutex held */
211static int _mv88e6xxx_phy_write(struct dsa_switch *ds, int addr, int regnum,
212 u16 val)
Lennert Buytenhek91da11f2008-10-07 13:44:02 +0000213{
214 if (addr >= 0)
215 return mv88e6xxx_reg_write(ds, addr, regnum, val);
216 return 0;
217}
218
Lennert Buytenhek2e5f0322008-10-07 13:45:18 +0000219#ifdef CONFIG_NET_DSA_MV88E6XXX_NEED_PPU
220static int mv88e6xxx_ppu_disable(struct dsa_switch *ds)
221{
222 int ret;
Barry Grussling19b2f972013-01-08 16:05:54 +0000223 unsigned long timeout;
Lennert Buytenhek2e5f0322008-10-07 13:45:18 +0000224
Andrew Lunncca8b132015-04-02 04:06:39 +0200225 ret = REG_READ(REG_GLOBAL, GLOBAL_CONTROL);
226 REG_WRITE(REG_GLOBAL, GLOBAL_CONTROL,
227 ret & ~GLOBAL_CONTROL_PPU_ENABLE);
Lennert Buytenhek2e5f0322008-10-07 13:45:18 +0000228
Barry Grussling19b2f972013-01-08 16:05:54 +0000229 timeout = jiffies + 1 * HZ;
230 while (time_before(jiffies, timeout)) {
Andrew Lunncca8b132015-04-02 04:06:39 +0200231 ret = REG_READ(REG_GLOBAL, GLOBAL_STATUS);
Barry Grussling19b2f972013-01-08 16:05:54 +0000232 usleep_range(1000, 2000);
Andrew Lunncca8b132015-04-02 04:06:39 +0200233 if ((ret & GLOBAL_STATUS_PPU_MASK) !=
234 GLOBAL_STATUS_PPU_POLLING)
Barry Grussling85686582013-01-08 16:05:56 +0000235 return 0;
Lennert Buytenhek2e5f0322008-10-07 13:45:18 +0000236 }
237
238 return -ETIMEDOUT;
239}
240
241static int mv88e6xxx_ppu_enable(struct dsa_switch *ds)
242{
243 int ret;
Barry Grussling19b2f972013-01-08 16:05:54 +0000244 unsigned long timeout;
Lennert Buytenhek2e5f0322008-10-07 13:45:18 +0000245
Andrew Lunncca8b132015-04-02 04:06:39 +0200246 ret = REG_READ(REG_GLOBAL, GLOBAL_CONTROL);
247 REG_WRITE(REG_GLOBAL, GLOBAL_CONTROL, ret | GLOBAL_CONTROL_PPU_ENABLE);
Lennert Buytenhek2e5f0322008-10-07 13:45:18 +0000248
Barry Grussling19b2f972013-01-08 16:05:54 +0000249 timeout = jiffies + 1 * HZ;
250 while (time_before(jiffies, timeout)) {
Andrew Lunncca8b132015-04-02 04:06:39 +0200251 ret = REG_READ(REG_GLOBAL, GLOBAL_STATUS);
Barry Grussling19b2f972013-01-08 16:05:54 +0000252 usleep_range(1000, 2000);
Andrew Lunncca8b132015-04-02 04:06:39 +0200253 if ((ret & GLOBAL_STATUS_PPU_MASK) ==
254 GLOBAL_STATUS_PPU_POLLING)
Barry Grussling85686582013-01-08 16:05:56 +0000255 return 0;
Lennert Buytenhek2e5f0322008-10-07 13:45:18 +0000256 }
257
258 return -ETIMEDOUT;
259}
260
261static void mv88e6xxx_ppu_reenable_work(struct work_struct *ugly)
262{
263 struct mv88e6xxx_priv_state *ps;
264
265 ps = container_of(ugly, struct mv88e6xxx_priv_state, ppu_work);
266 if (mutex_trylock(&ps->ppu_mutex)) {
Barry Grussling85686582013-01-08 16:05:56 +0000267 struct dsa_switch *ds = ((struct dsa_switch *)ps) - 1;
Lennert Buytenhek2e5f0322008-10-07 13:45:18 +0000268
Barry Grussling85686582013-01-08 16:05:56 +0000269 if (mv88e6xxx_ppu_enable(ds) == 0)
270 ps->ppu_disabled = 0;
271 mutex_unlock(&ps->ppu_mutex);
Lennert Buytenhek2e5f0322008-10-07 13:45:18 +0000272 }
273}
274
275static void mv88e6xxx_ppu_reenable_timer(unsigned long _ps)
276{
277 struct mv88e6xxx_priv_state *ps = (void *)_ps;
278
279 schedule_work(&ps->ppu_work);
280}
281
282static int mv88e6xxx_ppu_access_get(struct dsa_switch *ds)
283{
Florian Fainellia22adce2014-04-28 11:14:28 -0700284 struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
Lennert Buytenhek2e5f0322008-10-07 13:45:18 +0000285 int ret;
286
287 mutex_lock(&ps->ppu_mutex);
288
Barry Grussling3675c8d2013-01-08 16:05:53 +0000289 /* If the PHY polling unit is enabled, disable it so that
Lennert Buytenhek2e5f0322008-10-07 13:45:18 +0000290 * we can access the PHY registers. If it was already
291 * disabled, cancel the timer that is going to re-enable
292 * it.
293 */
294 if (!ps->ppu_disabled) {
Barry Grussling85686582013-01-08 16:05:56 +0000295 ret = mv88e6xxx_ppu_disable(ds);
296 if (ret < 0) {
297 mutex_unlock(&ps->ppu_mutex);
298 return ret;
299 }
300 ps->ppu_disabled = 1;
Lennert Buytenhek2e5f0322008-10-07 13:45:18 +0000301 } else {
Barry Grussling85686582013-01-08 16:05:56 +0000302 del_timer(&ps->ppu_timer);
303 ret = 0;
Lennert Buytenhek2e5f0322008-10-07 13:45:18 +0000304 }
305
306 return ret;
307}
308
309static void mv88e6xxx_ppu_access_put(struct dsa_switch *ds)
310{
Florian Fainellia22adce2014-04-28 11:14:28 -0700311 struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
Lennert Buytenhek2e5f0322008-10-07 13:45:18 +0000312
Barry Grussling3675c8d2013-01-08 16:05:53 +0000313 /* Schedule a timer to re-enable the PHY polling unit. */
Lennert Buytenhek2e5f0322008-10-07 13:45:18 +0000314 mod_timer(&ps->ppu_timer, jiffies + msecs_to_jiffies(10));
315 mutex_unlock(&ps->ppu_mutex);
316}
317
318void mv88e6xxx_ppu_state_init(struct dsa_switch *ds)
319{
Florian Fainellia22adce2014-04-28 11:14:28 -0700320 struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
Lennert Buytenhek2e5f0322008-10-07 13:45:18 +0000321
322 mutex_init(&ps->ppu_mutex);
323 INIT_WORK(&ps->ppu_work, mv88e6xxx_ppu_reenable_work);
324 init_timer(&ps->ppu_timer);
325 ps->ppu_timer.data = (unsigned long)ps;
326 ps->ppu_timer.function = mv88e6xxx_ppu_reenable_timer;
327}
328
329int mv88e6xxx_phy_read_ppu(struct dsa_switch *ds, int addr, int regnum)
330{
331 int ret;
332
333 ret = mv88e6xxx_ppu_access_get(ds);
334 if (ret >= 0) {
Barry Grussling85686582013-01-08 16:05:56 +0000335 ret = mv88e6xxx_reg_read(ds, addr, regnum);
336 mv88e6xxx_ppu_access_put(ds);
Lennert Buytenhek2e5f0322008-10-07 13:45:18 +0000337 }
338
339 return ret;
340}
341
342int mv88e6xxx_phy_write_ppu(struct dsa_switch *ds, int addr,
343 int regnum, u16 val)
344{
345 int ret;
346
347 ret = mv88e6xxx_ppu_access_get(ds);
348 if (ret >= 0) {
Barry Grussling85686582013-01-08 16:05:56 +0000349 ret = mv88e6xxx_reg_write(ds, addr, regnum, val);
350 mv88e6xxx_ppu_access_put(ds);
Lennert Buytenhek2e5f0322008-10-07 13:45:18 +0000351 }
352
353 return ret;
354}
355#endif
356
Lennert Buytenhek91da11f2008-10-07 13:44:02 +0000357void mv88e6xxx_poll_link(struct dsa_switch *ds)
358{
359 int i;
360
361 for (i = 0; i < DSA_MAX_PORTS; i++) {
362 struct net_device *dev;
Ingo Molnar2a9e7972008-11-25 16:50:49 -0800363 int uninitialized_var(port_status);
Lennert Buytenhek91da11f2008-10-07 13:44:02 +0000364 int link;
365 int speed;
366 int duplex;
367 int fc;
368
369 dev = ds->ports[i];
370 if (dev == NULL)
371 continue;
372
373 link = 0;
374 if (dev->flags & IFF_UP) {
Andrew Lunncca8b132015-04-02 04:06:39 +0200375 port_status = mv88e6xxx_reg_read(ds, REG_PORT(i),
376 PORT_STATUS);
Lennert Buytenhek91da11f2008-10-07 13:44:02 +0000377 if (port_status < 0)
378 continue;
379
Andrew Lunncca8b132015-04-02 04:06:39 +0200380 link = !!(port_status & PORT_STATUS_LINK);
Lennert Buytenhek91da11f2008-10-07 13:44:02 +0000381 }
382
383 if (!link) {
384 if (netif_carrier_ok(dev)) {
Barry Grusslingab381a92013-01-08 16:05:55 +0000385 netdev_info(dev, "link down\n");
Lennert Buytenhek91da11f2008-10-07 13:44:02 +0000386 netif_carrier_off(dev);
387 }
388 continue;
389 }
390
Andrew Lunncca8b132015-04-02 04:06:39 +0200391 switch (port_status & PORT_STATUS_SPEED_MASK) {
392 case PORT_STATUS_SPEED_10:
Lennert Buytenhek91da11f2008-10-07 13:44:02 +0000393 speed = 10;
394 break;
Andrew Lunncca8b132015-04-02 04:06:39 +0200395 case PORT_STATUS_SPEED_100:
Lennert Buytenhek91da11f2008-10-07 13:44:02 +0000396 speed = 100;
397 break;
Andrew Lunncca8b132015-04-02 04:06:39 +0200398 case PORT_STATUS_SPEED_1000:
Lennert Buytenhek91da11f2008-10-07 13:44:02 +0000399 speed = 1000;
400 break;
401 default:
402 speed = -1;
403 break;
404 }
Andrew Lunncca8b132015-04-02 04:06:39 +0200405 duplex = (port_status & PORT_STATUS_DUPLEX) ? 1 : 0;
406 fc = (port_status & PORT_STATUS_PAUSE_EN) ? 1 : 0;
Lennert Buytenhek91da11f2008-10-07 13:44:02 +0000407
408 if (!netif_carrier_ok(dev)) {
Barry Grusslingab381a92013-01-08 16:05:55 +0000409 netdev_info(dev,
410 "link up, %d Mb/s, %s duplex, flow control %sabled\n",
411 speed,
412 duplex ? "full" : "half",
413 fc ? "en" : "dis");
Lennert Buytenhek91da11f2008-10-07 13:44:02 +0000414 netif_carrier_on(dev);
415 }
416 }
417}
418
Andrew Lunn54d792f2015-05-06 01:09:47 +0200419static bool mv88e6xxx_6065_family(struct dsa_switch *ds)
420{
421 struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
422
423 switch (ps->id) {
424 case PORT_SWITCH_ID_6031:
425 case PORT_SWITCH_ID_6061:
426 case PORT_SWITCH_ID_6035:
427 case PORT_SWITCH_ID_6065:
428 return true;
429 }
430 return false;
431}
432
433static bool mv88e6xxx_6095_family(struct dsa_switch *ds)
434{
435 struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
436
437 switch (ps->id) {
438 case PORT_SWITCH_ID_6092:
439 case PORT_SWITCH_ID_6095:
440 return true;
441 }
442 return false;
443}
444
445static bool mv88e6xxx_6097_family(struct dsa_switch *ds)
446{
447 struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
448
449 switch (ps->id) {
450 case PORT_SWITCH_ID_6046:
451 case PORT_SWITCH_ID_6085:
452 case PORT_SWITCH_ID_6096:
453 case PORT_SWITCH_ID_6097:
454 return true;
455 }
456 return false;
457}
458
459static bool mv88e6xxx_6165_family(struct dsa_switch *ds)
460{
461 struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
462
463 switch (ps->id) {
464 case PORT_SWITCH_ID_6123:
465 case PORT_SWITCH_ID_6161:
466 case PORT_SWITCH_ID_6165:
467 return true;
468 }
469 return false;
470}
471
472static bool mv88e6xxx_6185_family(struct dsa_switch *ds)
473{
474 struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
475
476 switch (ps->id) {
477 case PORT_SWITCH_ID_6121:
478 case PORT_SWITCH_ID_6122:
479 case PORT_SWITCH_ID_6152:
480 case PORT_SWITCH_ID_6155:
481 case PORT_SWITCH_ID_6182:
482 case PORT_SWITCH_ID_6185:
483 case PORT_SWITCH_ID_6108:
484 case PORT_SWITCH_ID_6131:
485 return true;
486 }
487 return false;
488}
489
490static bool mv88e6xxx_6351_family(struct dsa_switch *ds)
491{
492 struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
493
494 switch (ps->id) {
495 case PORT_SWITCH_ID_6171:
496 case PORT_SWITCH_ID_6175:
497 case PORT_SWITCH_ID_6350:
498 case PORT_SWITCH_ID_6351:
499 return true;
500 }
501 return false;
502}
503
Andrew Lunnf3a8b6b2015-04-02 04:06:40 +0200504static bool mv88e6xxx_6352_family(struct dsa_switch *ds)
505{
506 struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
507
508 switch (ps->id) {
Andrew Lunnf3a8b6b2015-04-02 04:06:40 +0200509 case PORT_SWITCH_ID_6172:
510 case PORT_SWITCH_ID_6176:
Andrew Lunn54d792f2015-05-06 01:09:47 +0200511 case PORT_SWITCH_ID_6240:
512 case PORT_SWITCH_ID_6352:
Andrew Lunnf3a8b6b2015-04-02 04:06:40 +0200513 return true;
514 }
515 return false;
516}
517
Lennert Buytenhek91da11f2008-10-07 13:44:02 +0000518static int mv88e6xxx_stats_wait(struct dsa_switch *ds)
519{
520 int ret;
521 int i;
522
523 for (i = 0; i < 10; i++) {
Andrew Lunncca8b132015-04-02 04:06:39 +0200524 ret = REG_READ(REG_GLOBAL, GLOBAL_STATS_OP);
525 if ((ret & GLOBAL_STATS_OP_BUSY) == 0)
Lennert Buytenhek91da11f2008-10-07 13:44:02 +0000526 return 0;
527 }
528
529 return -ETIMEDOUT;
530}
531
532static int mv88e6xxx_stats_snapshot(struct dsa_switch *ds, int port)
533{
534 int ret;
535
Andrew Lunnf3a8b6b2015-04-02 04:06:40 +0200536 if (mv88e6xxx_6352_family(ds))
537 port = (port + 1) << 5;
538
Barry Grussling3675c8d2013-01-08 16:05:53 +0000539 /* Snapshot the hardware statistics counters for this port. */
Andrew Lunncca8b132015-04-02 04:06:39 +0200540 REG_WRITE(REG_GLOBAL, GLOBAL_STATS_OP,
541 GLOBAL_STATS_OP_CAPTURE_PORT |
542 GLOBAL_STATS_OP_HIST_RX_TX | port);
Lennert Buytenhek91da11f2008-10-07 13:44:02 +0000543
Barry Grussling3675c8d2013-01-08 16:05:53 +0000544 /* Wait for the snapshotting to complete. */
Lennert Buytenhek91da11f2008-10-07 13:44:02 +0000545 ret = mv88e6xxx_stats_wait(ds);
546 if (ret < 0)
547 return ret;
548
549 return 0;
550}
551
552static void mv88e6xxx_stats_read(struct dsa_switch *ds, int stat, u32 *val)
553{
554 u32 _val;
555 int ret;
556
557 *val = 0;
558
Andrew Lunncca8b132015-04-02 04:06:39 +0200559 ret = mv88e6xxx_reg_write(ds, REG_GLOBAL, GLOBAL_STATS_OP,
560 GLOBAL_STATS_OP_READ_CAPTURED |
561 GLOBAL_STATS_OP_HIST_RX_TX | stat);
Lennert Buytenhek91da11f2008-10-07 13:44:02 +0000562 if (ret < 0)
563 return;
564
565 ret = mv88e6xxx_stats_wait(ds);
566 if (ret < 0)
567 return;
568
Andrew Lunncca8b132015-04-02 04:06:39 +0200569 ret = mv88e6xxx_reg_read(ds, REG_GLOBAL, GLOBAL_STATS_COUNTER_32);
Lennert Buytenhek91da11f2008-10-07 13:44:02 +0000570 if (ret < 0)
571 return;
572
573 _val = ret << 16;
574
Andrew Lunncca8b132015-04-02 04:06:39 +0200575 ret = mv88e6xxx_reg_read(ds, REG_GLOBAL, GLOBAL_STATS_COUNTER_01);
Lennert Buytenhek91da11f2008-10-07 13:44:02 +0000576 if (ret < 0)
577 return;
578
579 *val = _val | ret;
580}
581
Andrew Lunne413e7e2015-04-02 04:06:38 +0200582static struct mv88e6xxx_hw_stat mv88e6xxx_hw_stats[] = {
583 { "in_good_octets", 8, 0x00, },
584 { "in_bad_octets", 4, 0x02, },
585 { "in_unicast", 4, 0x04, },
586 { "in_broadcasts", 4, 0x06, },
587 { "in_multicasts", 4, 0x07, },
588 { "in_pause", 4, 0x16, },
589 { "in_undersize", 4, 0x18, },
590 { "in_fragments", 4, 0x19, },
591 { "in_oversize", 4, 0x1a, },
592 { "in_jabber", 4, 0x1b, },
593 { "in_rx_error", 4, 0x1c, },
594 { "in_fcs_error", 4, 0x1d, },
595 { "out_octets", 8, 0x0e, },
596 { "out_unicast", 4, 0x10, },
597 { "out_broadcasts", 4, 0x13, },
598 { "out_multicasts", 4, 0x12, },
599 { "out_pause", 4, 0x15, },
600 { "excessive", 4, 0x11, },
601 { "collisions", 4, 0x1e, },
602 { "deferred", 4, 0x05, },
603 { "single", 4, 0x14, },
604 { "multiple", 4, 0x17, },
605 { "out_fcs_error", 4, 0x03, },
606 { "late", 4, 0x1f, },
607 { "hist_64bytes", 4, 0x08, },
608 { "hist_65_127bytes", 4, 0x09, },
609 { "hist_128_255bytes", 4, 0x0a, },
610 { "hist_256_511bytes", 4, 0x0b, },
611 { "hist_512_1023bytes", 4, 0x0c, },
612 { "hist_1024_max_bytes", 4, 0x0d, },
613 /* Not all devices have the following counters */
614 { "sw_in_discards", 4, 0x110, },
615 { "sw_in_filtered", 2, 0x112, },
616 { "sw_out_filtered", 2, 0x113, },
617
618};
619
620static bool have_sw_in_discards(struct dsa_switch *ds)
621{
622 struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
623
624 switch (ps->id) {
Andrew Lunncca8b132015-04-02 04:06:39 +0200625 case PORT_SWITCH_ID_6095: case PORT_SWITCH_ID_6161:
626 case PORT_SWITCH_ID_6165: case PORT_SWITCH_ID_6171:
627 case PORT_SWITCH_ID_6172: case PORT_SWITCH_ID_6176:
628 case PORT_SWITCH_ID_6182: case PORT_SWITCH_ID_6185:
629 case PORT_SWITCH_ID_6352:
Andrew Lunne413e7e2015-04-02 04:06:38 +0200630 return true;
631 default:
632 return false;
633 }
634}
635
636static void _mv88e6xxx_get_strings(struct dsa_switch *ds,
637 int nr_stats,
638 struct mv88e6xxx_hw_stat *stats,
639 int port, uint8_t *data)
Lennert Buytenhek91da11f2008-10-07 13:44:02 +0000640{
641 int i;
642
643 for (i = 0; i < nr_stats; i++) {
644 memcpy(data + i * ETH_GSTRING_LEN,
645 stats[i].string, ETH_GSTRING_LEN);
646 }
647}
648
Andrew Lunne413e7e2015-04-02 04:06:38 +0200649static void _mv88e6xxx_get_ethtool_stats(struct dsa_switch *ds,
650 int nr_stats,
651 struct mv88e6xxx_hw_stat *stats,
652 int port, uint64_t *data)
Lennert Buytenhek91da11f2008-10-07 13:44:02 +0000653{
Florian Fainellia22adce2014-04-28 11:14:28 -0700654 struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
Lennert Buytenhek91da11f2008-10-07 13:44:02 +0000655 int ret;
656 int i;
657
658 mutex_lock(&ps->stats_mutex);
659
660 ret = mv88e6xxx_stats_snapshot(ds, port);
661 if (ret < 0) {
662 mutex_unlock(&ps->stats_mutex);
663 return;
664 }
665
Barry Grussling3675c8d2013-01-08 16:05:53 +0000666 /* Read each of the counters. */
Lennert Buytenhek91da11f2008-10-07 13:44:02 +0000667 for (i = 0; i < nr_stats; i++) {
668 struct mv88e6xxx_hw_stat *s = stats + i;
669 u32 low;
Guenter Roeck17ee3e02014-10-29 10:45:07 -0700670 u32 high = 0;
Lennert Buytenhek91da11f2008-10-07 13:44:02 +0000671
Guenter Roeck17ee3e02014-10-29 10:45:07 -0700672 if (s->reg >= 0x100) {
Guenter Roeck17ee3e02014-10-29 10:45:07 -0700673 ret = mv88e6xxx_reg_read(ds, REG_PORT(port),
674 s->reg - 0x100);
675 if (ret < 0)
676 goto error;
677 low = ret;
678 if (s->sizeof_stat == 4) {
679 ret = mv88e6xxx_reg_read(ds, REG_PORT(port),
680 s->reg - 0x100 + 1);
681 if (ret < 0)
682 goto error;
683 high = ret;
684 }
685 data[i] = (((u64)high) << 16) | low;
686 continue;
687 }
Lennert Buytenhek91da11f2008-10-07 13:44:02 +0000688 mv88e6xxx_stats_read(ds, s->reg, &low);
689 if (s->sizeof_stat == 8)
690 mv88e6xxx_stats_read(ds, s->reg + 1, &high);
Lennert Buytenhek91da11f2008-10-07 13:44:02 +0000691
692 data[i] = (((u64)high) << 32) | low;
693 }
Guenter Roeck17ee3e02014-10-29 10:45:07 -0700694error:
Lennert Buytenhek91da11f2008-10-07 13:44:02 +0000695 mutex_unlock(&ps->stats_mutex);
696}
Ben Hutchings98e67302011-11-25 14:36:19 +0000697
Andrew Lunne413e7e2015-04-02 04:06:38 +0200698/* All the statistics in the table */
699void
700mv88e6xxx_get_strings(struct dsa_switch *ds, int port, uint8_t *data)
701{
702 if (have_sw_in_discards(ds))
703 _mv88e6xxx_get_strings(ds, ARRAY_SIZE(mv88e6xxx_hw_stats),
704 mv88e6xxx_hw_stats, port, data);
705 else
706 _mv88e6xxx_get_strings(ds, ARRAY_SIZE(mv88e6xxx_hw_stats) - 3,
707 mv88e6xxx_hw_stats, port, data);
708}
709
710int mv88e6xxx_get_sset_count(struct dsa_switch *ds)
711{
712 if (have_sw_in_discards(ds))
713 return ARRAY_SIZE(mv88e6xxx_hw_stats);
714 return ARRAY_SIZE(mv88e6xxx_hw_stats) - 3;
715}
716
717void
718mv88e6xxx_get_ethtool_stats(struct dsa_switch *ds,
719 int port, uint64_t *data)
720{
721 if (have_sw_in_discards(ds))
722 _mv88e6xxx_get_ethtool_stats(
723 ds, ARRAY_SIZE(mv88e6xxx_hw_stats),
724 mv88e6xxx_hw_stats, port, data);
725 else
726 _mv88e6xxx_get_ethtool_stats(
727 ds, ARRAY_SIZE(mv88e6xxx_hw_stats) - 3,
728 mv88e6xxx_hw_stats, port, data);
729}
730
Guenter Roecka1ab91f2014-10-29 10:45:05 -0700731int mv88e6xxx_get_regs_len(struct dsa_switch *ds, int port)
732{
733 return 32 * sizeof(u16);
734}
735
736void mv88e6xxx_get_regs(struct dsa_switch *ds, int port,
737 struct ethtool_regs *regs, void *_p)
738{
739 u16 *p = _p;
740 int i;
741
742 regs->version = 0;
743
744 memset(p, 0xff, 32 * sizeof(u16));
745
746 for (i = 0; i < 32; i++) {
747 int ret;
748
749 ret = mv88e6xxx_reg_read(ds, REG_PORT(port), i);
750 if (ret >= 0)
751 p[i] = ret;
752 }
753}
754
Andrew Lunneaa23762014-11-15 22:24:51 +0100755#ifdef CONFIG_NET_DSA_HWMON
756
757int mv88e6xxx_get_temp(struct dsa_switch *ds, int *temp)
758{
759 struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
760 int ret;
761 int val;
762
763 *temp = 0;
764
765 mutex_lock(&ps->phy_mutex);
766
Andrew Lunnfd3a0ee2015-04-02 04:06:36 +0200767 ret = _mv88e6xxx_phy_write(ds, 0x0, 0x16, 0x6);
Andrew Lunneaa23762014-11-15 22:24:51 +0100768 if (ret < 0)
769 goto error;
770
771 /* Enable temperature sensor */
Andrew Lunnfd3a0ee2015-04-02 04:06:36 +0200772 ret = _mv88e6xxx_phy_read(ds, 0x0, 0x1a);
Andrew Lunneaa23762014-11-15 22:24:51 +0100773 if (ret < 0)
774 goto error;
775
Andrew Lunnfd3a0ee2015-04-02 04:06:36 +0200776 ret = _mv88e6xxx_phy_write(ds, 0x0, 0x1a, ret | (1 << 5));
Andrew Lunneaa23762014-11-15 22:24:51 +0100777 if (ret < 0)
778 goto error;
779
780 /* Wait for temperature to stabilize */
781 usleep_range(10000, 12000);
782
Andrew Lunnfd3a0ee2015-04-02 04:06:36 +0200783 val = _mv88e6xxx_phy_read(ds, 0x0, 0x1a);
Andrew Lunneaa23762014-11-15 22:24:51 +0100784 if (val < 0) {
785 ret = val;
786 goto error;
787 }
788
789 /* Disable temperature sensor */
Andrew Lunnfd3a0ee2015-04-02 04:06:36 +0200790 ret = _mv88e6xxx_phy_write(ds, 0x0, 0x1a, ret & ~(1 << 5));
Andrew Lunneaa23762014-11-15 22:24:51 +0100791 if (ret < 0)
792 goto error;
793
794 *temp = ((val & 0x1f) - 5) * 5;
795
796error:
Andrew Lunnfd3a0ee2015-04-02 04:06:36 +0200797 _mv88e6xxx_phy_write(ds, 0x0, 0x16, 0x0);
Andrew Lunneaa23762014-11-15 22:24:51 +0100798 mutex_unlock(&ps->phy_mutex);
799 return ret;
800}
801#endif /* CONFIG_NET_DSA_HWMON */
802
Andrew Lunnf3044682015-02-14 19:17:50 +0100803static int mv88e6xxx_wait(struct dsa_switch *ds, int reg, int offset, u16 mask)
804{
805 unsigned long timeout = jiffies + HZ / 10;
806
807 while (time_before(jiffies, timeout)) {
808 int ret;
809
810 ret = REG_READ(reg, offset);
811 if (!(ret & mask))
812 return 0;
813
814 usleep_range(1000, 2000);
815 }
816 return -ETIMEDOUT;
817}
818
819int mv88e6xxx_phy_wait(struct dsa_switch *ds)
820{
Andrew Lunncca8b132015-04-02 04:06:39 +0200821 return mv88e6xxx_wait(ds, REG_GLOBAL2, GLOBAL2_SMI_OP,
822 GLOBAL2_SMI_OP_BUSY);
Andrew Lunnf3044682015-02-14 19:17:50 +0100823}
824
825int mv88e6xxx_eeprom_load_wait(struct dsa_switch *ds)
826{
Andrew Lunncca8b132015-04-02 04:06:39 +0200827 return mv88e6xxx_wait(ds, REG_GLOBAL2, GLOBAL2_EEPROM_OP,
828 GLOBAL2_EEPROM_OP_LOAD);
Andrew Lunnf3044682015-02-14 19:17:50 +0100829}
830
831int mv88e6xxx_eeprom_busy_wait(struct dsa_switch *ds)
832{
Andrew Lunncca8b132015-04-02 04:06:39 +0200833 return mv88e6xxx_wait(ds, REG_GLOBAL2, GLOBAL2_EEPROM_OP,
834 GLOBAL2_EEPROM_OP_BUSY);
Andrew Lunnf3044682015-02-14 19:17:50 +0100835}
836
Guenter Roeckfacd95b2015-03-26 18:36:35 -0700837/* Must be called with SMI lock held */
838static int _mv88e6xxx_wait(struct dsa_switch *ds, int reg, int offset, u16 mask)
839{
840 unsigned long timeout = jiffies + HZ / 10;
841
842 while (time_before(jiffies, timeout)) {
843 int ret;
844
845 ret = _mv88e6xxx_reg_read(ds, reg, offset);
846 if (ret < 0)
847 return ret;
848 if (!(ret & mask))
849 return 0;
850
851 usleep_range(1000, 2000);
852 }
853 return -ETIMEDOUT;
854}
855
856/* Must be called with SMI lock held */
857static int _mv88e6xxx_atu_wait(struct dsa_switch *ds)
858{
Andrew Lunncca8b132015-04-02 04:06:39 +0200859 return _mv88e6xxx_wait(ds, REG_GLOBAL, GLOBAL_ATU_OP,
860 GLOBAL_ATU_OP_BUSY);
Guenter Roeckfacd95b2015-03-26 18:36:35 -0700861}
862
Andrew Lunnfd3a0ee2015-04-02 04:06:36 +0200863/* Must be called with phy mutex held */
864static int _mv88e6xxx_phy_read_indirect(struct dsa_switch *ds, int addr,
865 int regnum)
Andrew Lunnf3044682015-02-14 19:17:50 +0100866{
867 int ret;
868
Andrew Lunncca8b132015-04-02 04:06:39 +0200869 REG_WRITE(REG_GLOBAL2, GLOBAL2_SMI_OP,
870 GLOBAL2_SMI_OP_22_READ | (addr << 5) | regnum);
Andrew Lunnf3044682015-02-14 19:17:50 +0100871
872 ret = mv88e6xxx_phy_wait(ds);
873 if (ret < 0)
874 return ret;
875
Andrew Lunncca8b132015-04-02 04:06:39 +0200876 return REG_READ(REG_GLOBAL2, GLOBAL2_SMI_DATA);
Andrew Lunnf3044682015-02-14 19:17:50 +0100877}
878
Andrew Lunnfd3a0ee2015-04-02 04:06:36 +0200879/* Must be called with phy mutex held */
880static int _mv88e6xxx_phy_write_indirect(struct dsa_switch *ds, int addr,
881 int regnum, u16 val)
Andrew Lunnf3044682015-02-14 19:17:50 +0100882{
Andrew Lunncca8b132015-04-02 04:06:39 +0200883 REG_WRITE(REG_GLOBAL2, GLOBAL2_SMI_DATA, val);
884 REG_WRITE(REG_GLOBAL2, GLOBAL2_SMI_OP,
885 GLOBAL2_SMI_OP_22_WRITE | (addr << 5) | regnum);
Andrew Lunnf3044682015-02-14 19:17:50 +0100886
887 return mv88e6xxx_phy_wait(ds);
888}
889
Guenter Roeck11b3b452015-03-06 22:23:51 -0800890int mv88e6xxx_get_eee(struct dsa_switch *ds, int port, struct ethtool_eee *e)
891{
Andrew Lunn2f40c692015-04-02 04:06:37 +0200892 struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
Guenter Roeck11b3b452015-03-06 22:23:51 -0800893 int reg;
894
Andrew Lunn2f40c692015-04-02 04:06:37 +0200895 mutex_lock(&ps->phy_mutex);
896
897 reg = _mv88e6xxx_phy_read_indirect(ds, port, 16);
Guenter Roeck11b3b452015-03-06 22:23:51 -0800898 if (reg < 0)
Andrew Lunn2f40c692015-04-02 04:06:37 +0200899 goto out;
Guenter Roeck11b3b452015-03-06 22:23:51 -0800900
901 e->eee_enabled = !!(reg & 0x0200);
902 e->tx_lpi_enabled = !!(reg & 0x0100);
903
Andrew Lunncca8b132015-04-02 04:06:39 +0200904 reg = mv88e6xxx_reg_read(ds, REG_PORT(port), PORT_STATUS);
Guenter Roeck11b3b452015-03-06 22:23:51 -0800905 if (reg < 0)
Andrew Lunn2f40c692015-04-02 04:06:37 +0200906 goto out;
Guenter Roeck11b3b452015-03-06 22:23:51 -0800907
Andrew Lunncca8b132015-04-02 04:06:39 +0200908 e->eee_active = !!(reg & PORT_STATUS_EEE);
Andrew Lunn2f40c692015-04-02 04:06:37 +0200909 reg = 0;
Guenter Roeck11b3b452015-03-06 22:23:51 -0800910
Andrew Lunn2f40c692015-04-02 04:06:37 +0200911out:
912 mutex_unlock(&ps->phy_mutex);
913 return reg;
Guenter Roeck11b3b452015-03-06 22:23:51 -0800914}
915
916int mv88e6xxx_set_eee(struct dsa_switch *ds, int port,
917 struct phy_device *phydev, struct ethtool_eee *e)
918{
Andrew Lunn2f40c692015-04-02 04:06:37 +0200919 struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
920 int reg;
Guenter Roeck11b3b452015-03-06 22:23:51 -0800921 int ret;
922
Andrew Lunn2f40c692015-04-02 04:06:37 +0200923 mutex_lock(&ps->phy_mutex);
Guenter Roeck11b3b452015-03-06 22:23:51 -0800924
Andrew Lunn2f40c692015-04-02 04:06:37 +0200925 ret = _mv88e6xxx_phy_read_indirect(ds, port, 16);
926 if (ret < 0)
927 goto out;
928
929 reg = ret & ~0x0300;
930 if (e->eee_enabled)
931 reg |= 0x0200;
932 if (e->tx_lpi_enabled)
933 reg |= 0x0100;
934
935 ret = _mv88e6xxx_phy_write_indirect(ds, port, 16, reg);
936out:
937 mutex_unlock(&ps->phy_mutex);
938
939 return ret;
Guenter Roeck11b3b452015-03-06 22:23:51 -0800940}
941
Guenter Roeckfacd95b2015-03-26 18:36:35 -0700942static int _mv88e6xxx_atu_cmd(struct dsa_switch *ds, int fid, u16 cmd)
943{
944 int ret;
945
946 ret = _mv88e6xxx_reg_write(ds, REG_GLOBAL, 0x01, fid);
947 if (ret < 0)
948 return ret;
949
Andrew Lunncca8b132015-04-02 04:06:39 +0200950 ret = _mv88e6xxx_reg_write(ds, REG_GLOBAL, GLOBAL_ATU_OP, cmd);
Guenter Roeckfacd95b2015-03-26 18:36:35 -0700951 if (ret < 0)
952 return ret;
953
954 return _mv88e6xxx_atu_wait(ds);
955}
956
957static int _mv88e6xxx_flush_fid(struct dsa_switch *ds, int fid)
958{
959 int ret;
960
961 ret = _mv88e6xxx_atu_wait(ds);
962 if (ret < 0)
963 return ret;
964
Andrew Lunncca8b132015-04-02 04:06:39 +0200965 return _mv88e6xxx_atu_cmd(ds, fid, GLOBAL_ATU_OP_FLUSH_NON_STATIC_DB);
Guenter Roeckfacd95b2015-03-26 18:36:35 -0700966}
967
968static int mv88e6xxx_set_port_state(struct dsa_switch *ds, int port, u8 state)
969{
970 struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
Geert Uytterhoevenc3ffe6d2015-04-16 20:49:14 +0200971 int reg, ret = 0;
Guenter Roeckfacd95b2015-03-26 18:36:35 -0700972 u8 oldstate;
973
974 mutex_lock(&ps->smi_mutex);
975
Andrew Lunncca8b132015-04-02 04:06:39 +0200976 reg = _mv88e6xxx_reg_read(ds, REG_PORT(port), PORT_CONTROL);
Guenter Roeck538cc282015-04-15 22:12:42 -0700977 if (reg < 0) {
978 ret = reg;
Guenter Roeckfacd95b2015-03-26 18:36:35 -0700979 goto abort;
Guenter Roeck538cc282015-04-15 22:12:42 -0700980 }
Guenter Roeckfacd95b2015-03-26 18:36:35 -0700981
Andrew Lunncca8b132015-04-02 04:06:39 +0200982 oldstate = reg & PORT_CONTROL_STATE_MASK;
Guenter Roeckfacd95b2015-03-26 18:36:35 -0700983 if (oldstate != state) {
984 /* Flush forwarding database if we're moving a port
985 * from Learning or Forwarding state to Disabled or
986 * Blocking or Listening state.
987 */
Andrew Lunncca8b132015-04-02 04:06:39 +0200988 if (oldstate >= PORT_CONTROL_STATE_LEARNING &&
989 state <= PORT_CONTROL_STATE_BLOCKING) {
Guenter Roeckfacd95b2015-03-26 18:36:35 -0700990 ret = _mv88e6xxx_flush_fid(ds, ps->fid[port]);
991 if (ret)
992 goto abort;
993 }
Andrew Lunncca8b132015-04-02 04:06:39 +0200994 reg = (reg & ~PORT_CONTROL_STATE_MASK) | state;
995 ret = _mv88e6xxx_reg_write(ds, REG_PORT(port), PORT_CONTROL,
996 reg);
Guenter Roeckfacd95b2015-03-26 18:36:35 -0700997 }
998
999abort:
1000 mutex_unlock(&ps->smi_mutex);
1001 return ret;
1002}
1003
1004/* Must be called with smi lock held */
1005static int _mv88e6xxx_update_port_config(struct dsa_switch *ds, int port)
1006{
1007 struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
1008 u8 fid = ps->fid[port];
1009 u16 reg = fid << 12;
1010
1011 if (dsa_is_cpu_port(ds, port))
1012 reg |= ds->phys_port_mask;
1013 else
1014 reg |= (ps->bridge_mask[fid] |
1015 (1 << dsa_upstream_port(ds))) & ~(1 << port);
1016
Andrew Lunncca8b132015-04-02 04:06:39 +02001017 return _mv88e6xxx_reg_write(ds, REG_PORT(port), PORT_BASE_VLAN, reg);
Guenter Roeckfacd95b2015-03-26 18:36:35 -07001018}
1019
1020/* Must be called with smi lock held */
1021static int _mv88e6xxx_update_bridge_config(struct dsa_switch *ds, int fid)
1022{
1023 struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
1024 int port;
1025 u32 mask;
1026 int ret;
1027
1028 mask = ds->phys_port_mask;
1029 while (mask) {
1030 port = __ffs(mask);
1031 mask &= ~(1 << port);
1032 if (ps->fid[port] != fid)
1033 continue;
1034
1035 ret = _mv88e6xxx_update_port_config(ds, port);
1036 if (ret)
1037 return ret;
1038 }
1039
1040 return _mv88e6xxx_flush_fid(ds, fid);
1041}
1042
1043/* Bridge handling functions */
1044
1045int mv88e6xxx_join_bridge(struct dsa_switch *ds, int port, u32 br_port_mask)
1046{
1047 struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
1048 int ret = 0;
1049 u32 nmask;
1050 int fid;
1051
1052 /* If the bridge group is not empty, join that group.
1053 * Otherwise create a new group.
1054 */
1055 fid = ps->fid[port];
1056 nmask = br_port_mask & ~(1 << port);
1057 if (nmask)
1058 fid = ps->fid[__ffs(nmask)];
1059
1060 nmask = ps->bridge_mask[fid] | (1 << port);
1061 if (nmask != br_port_mask) {
1062 netdev_err(ds->ports[port],
1063 "join: Bridge port mask mismatch fid=%d mask=0x%x expected 0x%x\n",
1064 fid, br_port_mask, nmask);
1065 return -EINVAL;
1066 }
1067
1068 mutex_lock(&ps->smi_mutex);
1069
1070 ps->bridge_mask[fid] = br_port_mask;
1071
1072 if (fid != ps->fid[port]) {
1073 ps->fid_mask |= 1 << ps->fid[port];
1074 ps->fid[port] = fid;
1075 ret = _mv88e6xxx_update_bridge_config(ds, fid);
1076 }
1077
1078 mutex_unlock(&ps->smi_mutex);
1079
1080 return ret;
1081}
1082
1083int mv88e6xxx_leave_bridge(struct dsa_switch *ds, int port, u32 br_port_mask)
1084{
1085 struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
1086 u8 fid, newfid;
1087 int ret;
1088
1089 fid = ps->fid[port];
1090
1091 if (ps->bridge_mask[fid] != br_port_mask) {
1092 netdev_err(ds->ports[port],
1093 "leave: Bridge port mask mismatch fid=%d mask=0x%x expected 0x%x\n",
1094 fid, br_port_mask, ps->bridge_mask[fid]);
1095 return -EINVAL;
1096 }
1097
1098 /* If the port was the last port of a bridge, we are done.
1099 * Otherwise assign a new fid to the port, and fix up
1100 * the bridge configuration.
1101 */
1102 if (br_port_mask == (1 << port))
1103 return 0;
1104
1105 mutex_lock(&ps->smi_mutex);
1106
1107 newfid = __ffs(ps->fid_mask);
1108 ps->fid[port] = newfid;
1109 ps->fid_mask &= (1 << newfid);
1110 ps->bridge_mask[fid] &= ~(1 << port);
1111 ps->bridge_mask[newfid] = 1 << port;
1112
1113 ret = _mv88e6xxx_update_bridge_config(ds, fid);
1114 if (!ret)
1115 ret = _mv88e6xxx_update_bridge_config(ds, newfid);
1116
1117 mutex_unlock(&ps->smi_mutex);
1118
1119 return ret;
1120}
1121
1122int mv88e6xxx_port_stp_update(struct dsa_switch *ds, int port, u8 state)
1123{
1124 struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
1125 int stp_state;
1126
1127 switch (state) {
1128 case BR_STATE_DISABLED:
Andrew Lunncca8b132015-04-02 04:06:39 +02001129 stp_state = PORT_CONTROL_STATE_DISABLED;
Guenter Roeckfacd95b2015-03-26 18:36:35 -07001130 break;
1131 case BR_STATE_BLOCKING:
1132 case BR_STATE_LISTENING:
Andrew Lunncca8b132015-04-02 04:06:39 +02001133 stp_state = PORT_CONTROL_STATE_BLOCKING;
Guenter Roeckfacd95b2015-03-26 18:36:35 -07001134 break;
1135 case BR_STATE_LEARNING:
Andrew Lunncca8b132015-04-02 04:06:39 +02001136 stp_state = PORT_CONTROL_STATE_LEARNING;
Guenter Roeckfacd95b2015-03-26 18:36:35 -07001137 break;
1138 case BR_STATE_FORWARDING:
1139 default:
Andrew Lunncca8b132015-04-02 04:06:39 +02001140 stp_state = PORT_CONTROL_STATE_FORWARDING;
Guenter Roeckfacd95b2015-03-26 18:36:35 -07001141 break;
1142 }
1143
1144 netdev_dbg(ds->ports[port], "port state %d [%d]\n", state, stp_state);
1145
1146 /* mv88e6xxx_port_stp_update may be called with softirqs disabled,
1147 * so we can not update the port state directly but need to schedule it.
1148 */
1149 ps->port_state[port] = stp_state;
1150 set_bit(port, &ps->port_state_update_mask);
1151 schedule_work(&ps->bridge_work);
1152
1153 return 0;
1154}
1155
Guenter Roeckdefb05b2015-03-26 18:36:38 -07001156static int __mv88e6xxx_write_addr(struct dsa_switch *ds,
1157 const unsigned char *addr)
1158{
1159 int i, ret;
1160
1161 for (i = 0; i < 3; i++) {
Andrew Lunncca8b132015-04-02 04:06:39 +02001162 ret = _mv88e6xxx_reg_write(
1163 ds, REG_GLOBAL, GLOBAL_ATU_MAC_01 + i,
1164 (addr[i * 2] << 8) | addr[i * 2 + 1]);
Guenter Roeckdefb05b2015-03-26 18:36:38 -07001165 if (ret < 0)
1166 return ret;
1167 }
1168
1169 return 0;
1170}
1171
1172static int __mv88e6xxx_read_addr(struct dsa_switch *ds, unsigned char *addr)
1173{
1174 int i, ret;
1175
1176 for (i = 0; i < 3; i++) {
Andrew Lunncca8b132015-04-02 04:06:39 +02001177 ret = _mv88e6xxx_reg_read(ds, REG_GLOBAL,
1178 GLOBAL_ATU_MAC_01 + i);
Guenter Roeckdefb05b2015-03-26 18:36:38 -07001179 if (ret < 0)
1180 return ret;
1181 addr[i * 2] = ret >> 8;
1182 addr[i * 2 + 1] = ret & 0xff;
1183 }
1184
1185 return 0;
1186}
1187
1188static int __mv88e6xxx_port_fdb_cmd(struct dsa_switch *ds, int port,
1189 const unsigned char *addr, int state)
1190{
1191 struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
1192 u8 fid = ps->fid[port];
1193 int ret;
1194
1195 ret = _mv88e6xxx_atu_wait(ds);
1196 if (ret < 0)
1197 return ret;
1198
1199 ret = __mv88e6xxx_write_addr(ds, addr);
1200 if (ret < 0)
1201 return ret;
1202
Andrew Lunncca8b132015-04-02 04:06:39 +02001203 ret = _mv88e6xxx_reg_write(ds, REG_GLOBAL, GLOBAL_ATU_DATA,
Guenter Roeckdefb05b2015-03-26 18:36:38 -07001204 (0x10 << port) | state);
1205 if (ret)
1206 return ret;
1207
Andrew Lunncca8b132015-04-02 04:06:39 +02001208 ret = _mv88e6xxx_atu_cmd(ds, fid, GLOBAL_ATU_OP_LOAD_DB);
Guenter Roeckdefb05b2015-03-26 18:36:38 -07001209
1210 return ret;
1211}
1212
1213int mv88e6xxx_port_fdb_add(struct dsa_switch *ds, int port,
1214 const unsigned char *addr, u16 vid)
1215{
1216 int state = is_multicast_ether_addr(addr) ?
Andrew Lunncca8b132015-04-02 04:06:39 +02001217 GLOBAL_ATU_DATA_STATE_MC_STATIC :
1218 GLOBAL_ATU_DATA_STATE_UC_STATIC;
Guenter Roeckdefb05b2015-03-26 18:36:38 -07001219 struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
1220 int ret;
1221
1222 mutex_lock(&ps->smi_mutex);
1223 ret = __mv88e6xxx_port_fdb_cmd(ds, port, addr, state);
1224 mutex_unlock(&ps->smi_mutex);
1225
1226 return ret;
1227}
1228
1229int mv88e6xxx_port_fdb_del(struct dsa_switch *ds, int port,
1230 const unsigned char *addr, u16 vid)
1231{
1232 struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
1233 int ret;
1234
1235 mutex_lock(&ps->smi_mutex);
Andrew Lunncca8b132015-04-02 04:06:39 +02001236 ret = __mv88e6xxx_port_fdb_cmd(ds, port, addr,
1237 GLOBAL_ATU_DATA_STATE_UNUSED);
Guenter Roeckdefb05b2015-03-26 18:36:38 -07001238 mutex_unlock(&ps->smi_mutex);
1239
1240 return ret;
1241}
1242
1243static int __mv88e6xxx_port_getnext(struct dsa_switch *ds, int port,
1244 unsigned char *addr, bool *is_static)
1245{
1246 struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
1247 u8 fid = ps->fid[port];
1248 int ret, state;
1249
1250 ret = _mv88e6xxx_atu_wait(ds);
1251 if (ret < 0)
1252 return ret;
1253
1254 ret = __mv88e6xxx_write_addr(ds, addr);
1255 if (ret < 0)
1256 return ret;
1257
1258 do {
Andrew Lunncca8b132015-04-02 04:06:39 +02001259 ret = _mv88e6xxx_atu_cmd(ds, fid, GLOBAL_ATU_OP_GET_NEXT_DB);
Guenter Roeckdefb05b2015-03-26 18:36:38 -07001260 if (ret < 0)
1261 return ret;
1262
Andrew Lunncca8b132015-04-02 04:06:39 +02001263 ret = _mv88e6xxx_reg_read(ds, REG_GLOBAL, GLOBAL_ATU_DATA);
Guenter Roeckdefb05b2015-03-26 18:36:38 -07001264 if (ret < 0)
1265 return ret;
Andrew Lunncca8b132015-04-02 04:06:39 +02001266 state = ret & GLOBAL_ATU_DATA_STATE_MASK;
1267 if (state == GLOBAL_ATU_DATA_STATE_UNUSED)
Guenter Roeckdefb05b2015-03-26 18:36:38 -07001268 return -ENOENT;
1269 } while (!(((ret >> 4) & 0xff) & (1 << port)));
1270
1271 ret = __mv88e6xxx_read_addr(ds, addr);
1272 if (ret < 0)
1273 return ret;
1274
1275 *is_static = state == (is_multicast_ether_addr(addr) ?
Andrew Lunncca8b132015-04-02 04:06:39 +02001276 GLOBAL_ATU_DATA_STATE_MC_STATIC :
1277 GLOBAL_ATU_DATA_STATE_UC_STATIC);
Guenter Roeckdefb05b2015-03-26 18:36:38 -07001278
1279 return 0;
1280}
1281
1282/* get next entry for port */
1283int mv88e6xxx_port_fdb_getnext(struct dsa_switch *ds, int port,
1284 unsigned char *addr, bool *is_static)
1285{
1286 struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
1287 int ret;
1288
1289 mutex_lock(&ps->smi_mutex);
1290 ret = __mv88e6xxx_port_getnext(ds, port, addr, is_static);
1291 mutex_unlock(&ps->smi_mutex);
1292
1293 return ret;
1294}
1295
Guenter Roeckfacd95b2015-03-26 18:36:35 -07001296static void mv88e6xxx_bridge_work(struct work_struct *work)
1297{
1298 struct mv88e6xxx_priv_state *ps;
1299 struct dsa_switch *ds;
1300 int port;
1301
1302 ps = container_of(work, struct mv88e6xxx_priv_state, bridge_work);
1303 ds = ((struct dsa_switch *)ps) - 1;
1304
1305 while (ps->port_state_update_mask) {
1306 port = __ffs(ps->port_state_update_mask);
1307 clear_bit(port, &ps->port_state_update_mask);
1308 mv88e6xxx_set_port_state(ds, port, ps->port_state[port]);
1309 }
1310}
1311
Andrew Lunndbde9e62015-05-06 01:09:48 +02001312static int mv88e6xxx_setup_port(struct dsa_switch *ds, int port)
Guenter Roeckd827e882015-03-26 18:36:29 -07001313{
1314 struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
Guenter Roeckfacd95b2015-03-26 18:36:35 -07001315 int ret, fid;
Andrew Lunn54d792f2015-05-06 01:09:47 +02001316 u16 reg;
Guenter Roeckd827e882015-03-26 18:36:29 -07001317
1318 mutex_lock(&ps->smi_mutex);
1319
Andrew Lunn54d792f2015-05-06 01:09:47 +02001320 if (mv88e6xxx_6352_family(ds) || mv88e6xxx_6351_family(ds) ||
1321 mv88e6xxx_6165_family(ds) || mv88e6xxx_6097_family(ds) ||
1322 mv88e6xxx_6185_family(ds) || mv88e6xxx_6095_family(ds) ||
1323 mv88e6xxx_6065_family(ds)) {
1324 /* MAC Forcing register: don't force link, speed,
1325 * duplex or flow control state to any particular
1326 * values on physical ports, but force the CPU port
1327 * and all DSA ports to their maximum bandwidth and
1328 * full duplex.
1329 */
1330 reg = _mv88e6xxx_reg_read(ds, REG_PORT(port), PORT_PCS_CTRL);
1331 if (dsa_is_cpu_port(ds, port) ||
1332 ds->dsa_port_mask & (1 << port)) {
1333 reg |= PORT_PCS_CTRL_FORCE_LINK |
1334 PORT_PCS_CTRL_LINK_UP |
1335 PORT_PCS_CTRL_DUPLEX_FULL |
1336 PORT_PCS_CTRL_FORCE_DUPLEX;
1337 if (mv88e6xxx_6065_family(ds))
1338 reg |= PORT_PCS_CTRL_100;
1339 else
1340 reg |= PORT_PCS_CTRL_1000;
1341 } else {
1342 reg |= PORT_PCS_CTRL_UNFORCED;
1343 }
1344
1345 ret = _mv88e6xxx_reg_write(ds, REG_PORT(port),
1346 PORT_PCS_CTRL, reg);
1347 if (ret)
1348 goto abort;
1349 }
1350
1351 /* Port Control: disable Drop-on-Unlock, disable Drop-on-Lock,
1352 * disable Header mode, enable IGMP/MLD snooping, disable VLAN
1353 * tunneling, determine priority by looking at 802.1p and IP
1354 * priority fields (IP prio has precedence), and set STP state
1355 * to Forwarding.
1356 *
1357 * If this is the CPU link, use DSA or EDSA tagging depending
1358 * on which tagging mode was configured.
1359 *
1360 * If this is a link to another switch, use DSA tagging mode.
1361 *
1362 * If this is the upstream port for this switch, enable
1363 * forwarding of unknown unicasts and multicasts.
1364 */
1365 reg = 0;
1366 if (mv88e6xxx_6352_family(ds) || mv88e6xxx_6351_family(ds) ||
1367 mv88e6xxx_6165_family(ds) || mv88e6xxx_6097_family(ds) ||
1368 mv88e6xxx_6095_family(ds) || mv88e6xxx_6065_family(ds) ||
1369 mv88e6xxx_6185_family(ds))
1370 reg = PORT_CONTROL_IGMP_MLD_SNOOP |
1371 PORT_CONTROL_USE_TAG | PORT_CONTROL_USE_IP |
1372 PORT_CONTROL_STATE_FORWARDING;
1373 if (dsa_is_cpu_port(ds, port)) {
1374 if (mv88e6xxx_6095_family(ds) || mv88e6xxx_6185_family(ds))
1375 reg |= PORT_CONTROL_DSA_TAG;
1376 if (mv88e6xxx_6352_family(ds) || mv88e6xxx_6351_family(ds) ||
1377 mv88e6xxx_6165_family(ds) || mv88e6xxx_6097_family(ds)) {
1378 if (ds->dst->tag_protocol == DSA_TAG_PROTO_EDSA)
1379 reg |= PORT_CONTROL_FRAME_ETHER_TYPE_DSA;
1380 else
1381 reg |= PORT_CONTROL_FRAME_MODE_DSA;
1382 }
1383
1384 if (mv88e6xxx_6352_family(ds) || mv88e6xxx_6351_family(ds) ||
1385 mv88e6xxx_6165_family(ds) || mv88e6xxx_6097_family(ds) ||
1386 mv88e6xxx_6095_family(ds) || mv88e6xxx_6065_family(ds) ||
1387 mv88e6xxx_6185_family(ds)) {
1388 if (ds->dst->tag_protocol == DSA_TAG_PROTO_EDSA)
1389 reg |= PORT_CONTROL_EGRESS_ADD_TAG;
1390 }
1391 }
1392 if (mv88e6xxx_6352_family(ds) || mv88e6xxx_6351_family(ds) ||
1393 mv88e6xxx_6165_family(ds) || mv88e6xxx_6097_family(ds) ||
1394 mv88e6xxx_6095_family(ds) || mv88e6xxx_6065_family(ds)) {
1395 if (ds->dsa_port_mask & (1 << port))
1396 reg |= PORT_CONTROL_FRAME_MODE_DSA;
1397 if (port == dsa_upstream_port(ds))
1398 reg |= PORT_CONTROL_FORWARD_UNKNOWN |
1399 PORT_CONTROL_FORWARD_UNKNOWN_MC;
1400 }
1401 if (reg) {
1402 ret = _mv88e6xxx_reg_write(ds, REG_PORT(port),
1403 PORT_CONTROL, reg);
1404 if (ret)
1405 goto abort;
1406 }
1407
1408 /* Port Control 2: don't force a good FCS, set the maximum
1409 * frame size to 10240 bytes, don't let the switch add or
1410 * strip 802.1q tags, don't discard tagged or untagged frames
1411 * on this port, do a destination address lookup on all
1412 * received packets as usual, disable ARP mirroring and don't
1413 * send a copy of all transmitted/received frames on this port
1414 * to the CPU.
1415 */
1416 reg = 0;
1417 if (mv88e6xxx_6352_family(ds) || mv88e6xxx_6351_family(ds) ||
1418 mv88e6xxx_6165_family(ds) || mv88e6xxx_6097_family(ds) ||
1419 mv88e6xxx_6095_family(ds))
1420 reg = PORT_CONTROL_2_MAP_DA;
1421
1422 if (mv88e6xxx_6352_family(ds) || mv88e6xxx_6351_family(ds) ||
1423 mv88e6xxx_6165_family(ds))
1424 reg |= PORT_CONTROL_2_JUMBO_10240;
1425
1426 if (mv88e6xxx_6095_family(ds) || mv88e6xxx_6185_family(ds)) {
1427 /* Set the upstream port this port should use */
1428 reg |= dsa_upstream_port(ds);
1429 /* enable forwarding of unknown multicast addresses to
1430 * the upstream port
1431 */
1432 if (port == dsa_upstream_port(ds))
1433 reg |= PORT_CONTROL_2_FORWARD_UNKNOWN;
1434 }
1435
1436 if (reg) {
1437 ret = _mv88e6xxx_reg_write(ds, REG_PORT(port),
1438 PORT_CONTROL_2, reg);
1439 if (ret)
1440 goto abort;
1441 }
1442
1443 /* Port Association Vector: when learning source addresses
1444 * of packets, add the address to the address database using
1445 * a port bitmap that has only the bit for this port set and
1446 * the other bits clear.
1447 */
1448 ret = _mv88e6xxx_reg_write(ds, REG_PORT(port), PORT_ASSOC_VECTOR,
1449 1 << port);
1450 if (ret)
1451 goto abort;
1452
1453 /* Egress rate control 2: disable egress rate control. */
1454 ret = _mv88e6xxx_reg_write(ds, REG_PORT(port), PORT_RATE_CONTROL_2,
1455 0x0000);
1456 if (ret)
1457 goto abort;
1458
1459 if (mv88e6xxx_6352_family(ds) || mv88e6xxx_6351_family(ds) ||
1460 mv88e6xxx_6165_family(ds) || mv88e6xxx_6097_family(ds)) {
1461 /* Do not limit the period of time that this port can
1462 * be paused for by the remote end or the period of
1463 * time that this port can pause the remote end.
1464 */
1465 ret = _mv88e6xxx_reg_write(ds, REG_PORT(port),
1466 PORT_PAUSE_CTRL, 0x0000);
1467 if (ret)
1468 goto abort;
1469
1470 /* Port ATU control: disable limiting the number of
1471 * address database entries that this port is allowed
1472 * to use.
1473 */
1474 ret = _mv88e6xxx_reg_write(ds, REG_PORT(port),
1475 PORT_ATU_CONTROL, 0x0000);
1476 /* Priority Override: disable DA, SA and VTU priority
1477 * override.
1478 */
1479 ret = _mv88e6xxx_reg_write(ds, REG_PORT(port),
1480 PORT_PRI_OVERRIDE, 0x0000);
1481 if (ret)
1482 goto abort;
1483
1484 /* Port Ethertype: use the Ethertype DSA Ethertype
1485 * value.
1486 */
1487 ret = _mv88e6xxx_reg_write(ds, REG_PORT(port),
1488 PORT_ETH_TYPE, ETH_P_EDSA);
1489 if (ret)
1490 goto abort;
1491 /* Tag Remap: use an identity 802.1p prio -> switch
1492 * prio mapping.
1493 */
1494 ret = _mv88e6xxx_reg_write(ds, REG_PORT(port),
1495 PORT_TAG_REGMAP_0123, 0x3210);
1496 if (ret)
1497 goto abort;
1498
1499 /* Tag Remap 2: use an identity 802.1p prio -> switch
1500 * prio mapping.
1501 */
1502 ret = _mv88e6xxx_reg_write(ds, REG_PORT(port),
1503 PORT_TAG_REGMAP_4567, 0x7654);
1504 if (ret)
1505 goto abort;
1506 }
1507
1508 if (mv88e6xxx_6352_family(ds) || mv88e6xxx_6351_family(ds) ||
1509 mv88e6xxx_6165_family(ds) || mv88e6xxx_6097_family(ds) ||
1510 mv88e6xxx_6185_family(ds) || mv88e6xxx_6095_family(ds)) {
1511 /* Rate Control: disable ingress rate limiting. */
1512 ret = _mv88e6xxx_reg_write(ds, REG_PORT(port),
1513 PORT_RATE_CONTROL, 0x0001);
1514 if (ret)
1515 goto abort;
1516 }
1517
Guenter Roeck366f0a02015-03-26 18:36:30 -07001518 /* Port Control 1: disable trunking, disable sending
1519 * learning messages to this port.
Guenter Roeckd827e882015-03-26 18:36:29 -07001520 */
Vivien Didelot614f03f2015-04-20 17:19:23 -04001521 ret = _mv88e6xxx_reg_write(ds, REG_PORT(port), PORT_CONTROL_1, 0x0000);
Guenter Roeckd827e882015-03-26 18:36:29 -07001522 if (ret)
1523 goto abort;
1524
1525 /* Port based VLAN map: give each port its own address
1526 * database, allow the CPU port to talk to each of the 'real'
1527 * ports, and allow each of the 'real' ports to only talk to
1528 * the upstream port.
1529 */
Guenter Roeckfacd95b2015-03-26 18:36:35 -07001530 fid = __ffs(ps->fid_mask);
1531 ps->fid[port] = fid;
1532 ps->fid_mask &= ~(1 << fid);
Guenter Roeckd827e882015-03-26 18:36:29 -07001533
Guenter Roeckfacd95b2015-03-26 18:36:35 -07001534 if (!dsa_is_cpu_port(ds, port))
1535 ps->bridge_mask[fid] = 1 << port;
1536
1537 ret = _mv88e6xxx_update_port_config(ds, port);
Guenter Roeckd827e882015-03-26 18:36:29 -07001538 if (ret)
1539 goto abort;
1540
1541 /* Default VLAN ID and priority: don't set a default VLAN
1542 * ID, and set the default packet priority to zero.
1543 */
Vivien Didelot47cf1e62015-04-20 17:43:26 -04001544 ret = _mv88e6xxx_reg_write(ds, REG_PORT(port), PORT_DEFAULT_VLAN,
1545 0x0000);
Guenter Roeckd827e882015-03-26 18:36:29 -07001546abort:
1547 mutex_unlock(&ps->smi_mutex);
1548 return ret;
1549}
1550
Andrew Lunndbde9e62015-05-06 01:09:48 +02001551int mv88e6xxx_setup_ports(struct dsa_switch *ds)
1552{
1553 struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
1554 int ret;
1555 int i;
1556
1557 for (i = 0; i < ps->num_ports; i++) {
1558 ret = mv88e6xxx_setup_port(ds, i);
1559 if (ret < 0)
1560 return ret;
1561 }
1562 return 0;
1563}
1564
Guenter Roeckacdaffc2015-03-26 18:36:28 -07001565int mv88e6xxx_setup_common(struct dsa_switch *ds)
1566{
1567 struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
1568
1569 mutex_init(&ps->smi_mutex);
1570 mutex_init(&ps->stats_mutex);
1571 mutex_init(&ps->phy_mutex);
1572
Andrew Lunncca8b132015-04-02 04:06:39 +02001573 ps->id = REG_READ(REG_PORT(0), PORT_SWITCH_ID) & 0xfff0;
Andrew Lunna8f064c2015-03-26 18:36:40 -07001574
Guenter Roeckfacd95b2015-03-26 18:36:35 -07001575 ps->fid_mask = (1 << DSA_MAX_PORTS) - 1;
1576
1577 INIT_WORK(&ps->bridge_work, mv88e6xxx_bridge_work);
1578
Guenter Roeckacdaffc2015-03-26 18:36:28 -07001579 return 0;
1580}
1581
Andrew Lunn54d792f2015-05-06 01:09:47 +02001582int mv88e6xxx_setup_global(struct dsa_switch *ds)
1583{
1584 struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
1585 int i;
1586
1587 /* Set the default address aging time to 5 minutes, and
1588 * enable address learn messages to be sent to all message
1589 * ports.
1590 */
1591 REG_WRITE(REG_GLOBAL, GLOBAL_ATU_CONTROL,
1592 0x0140 | GLOBAL_ATU_CONTROL_LEARN2ALL);
1593
1594 /* Configure the IP ToS mapping registers. */
1595 REG_WRITE(REG_GLOBAL, GLOBAL_IP_PRI_0, 0x0000);
1596 REG_WRITE(REG_GLOBAL, GLOBAL_IP_PRI_1, 0x0000);
1597 REG_WRITE(REG_GLOBAL, GLOBAL_IP_PRI_2, 0x5555);
1598 REG_WRITE(REG_GLOBAL, GLOBAL_IP_PRI_3, 0x5555);
1599 REG_WRITE(REG_GLOBAL, GLOBAL_IP_PRI_4, 0xaaaa);
1600 REG_WRITE(REG_GLOBAL, GLOBAL_IP_PRI_5, 0xaaaa);
1601 REG_WRITE(REG_GLOBAL, GLOBAL_IP_PRI_6, 0xffff);
1602 REG_WRITE(REG_GLOBAL, GLOBAL_IP_PRI_7, 0xffff);
1603
1604 /* Configure the IEEE 802.1p priority mapping register. */
1605 REG_WRITE(REG_GLOBAL, GLOBAL_IEEE_PRI, 0xfa41);
1606
1607 /* Send all frames with destination addresses matching
1608 * 01:80:c2:00:00:0x to the CPU port.
1609 */
1610 REG_WRITE(REG_GLOBAL2, GLOBAL2_MGMT_EN_0X, 0xffff);
1611
1612 /* Ignore removed tag data on doubly tagged packets, disable
1613 * flow control messages, force flow control priority to the
1614 * highest, and send all special multicast frames to the CPU
1615 * port at the highest priority.
1616 */
1617 REG_WRITE(REG_GLOBAL2, GLOBAL2_SWITCH_MGMT,
1618 0x7 | GLOBAL2_SWITCH_MGMT_RSVD2CPU | 0x70 |
1619 GLOBAL2_SWITCH_MGMT_FORCE_FLOW_CTRL_PRI);
1620
1621 /* Program the DSA routing table. */
1622 for (i = 0; i < 32; i++) {
1623 int nexthop = 0x1f;
1624
1625 if (ds->pd->rtable &&
1626 i != ds->index && i < ds->dst->pd->nr_chips)
1627 nexthop = ds->pd->rtable[i] & 0x1f;
1628
1629 REG_WRITE(REG_GLOBAL2, GLOBAL2_DEVICE_MAPPING,
1630 GLOBAL2_DEVICE_MAPPING_UPDATE |
1631 (i << GLOBAL2_DEVICE_MAPPING_TARGET_SHIFT) |
1632 nexthop);
1633 }
1634
1635 /* Clear all trunk masks. */
1636 for (i = 0; i < 8; i++)
1637 REG_WRITE(REG_GLOBAL2, GLOBAL2_TRUNK_MASK,
1638 0x8000 | (i << GLOBAL2_TRUNK_MASK_NUM_SHIFT) |
1639 ((1 << ps->num_ports) - 1));
1640
1641 /* Clear all trunk mappings. */
1642 for (i = 0; i < 16; i++)
1643 REG_WRITE(REG_GLOBAL2, GLOBAL2_TRUNK_MAPPING,
1644 GLOBAL2_TRUNK_MAPPING_UPDATE |
1645 (i << GLOBAL2_TRUNK_MAPPING_ID_SHIFT));
1646
1647 if (mv88e6xxx_6352_family(ds) || mv88e6xxx_6351_family(ds) ||
1648 mv88e6xxx_6165_family(ds) || mv88e6xxx_6097_family(ds)) {
1649 /* Send all frames with destination addresses matching
1650 * 01:80:c2:00:00:2x to the CPU port.
1651 */
1652 REG_WRITE(REG_GLOBAL2, GLOBAL2_MGMT_EN_2X, 0xffff);
1653
1654 /* Initialise cross-chip port VLAN table to reset
1655 * defaults.
1656 */
1657 REG_WRITE(REG_GLOBAL2, GLOBAL2_PVT_ADDR, 0x9000);
1658
1659 /* Clear the priority override table. */
1660 for (i = 0; i < 16; i++)
1661 REG_WRITE(REG_GLOBAL2, GLOBAL2_PRIO_OVERRIDE,
1662 0x8000 | (i << 8));
1663 }
1664
1665 if (mv88e6xxx_6352_family(ds) || mv88e6xxx_6351_family(ds) ||
1666 mv88e6xxx_6165_family(ds) || mv88e6xxx_6097_family(ds) ||
1667 mv88e6xxx_6185_family(ds) || mv88e6xxx_6095_family(ds)) {
1668 /* Disable ingress rate limiting by resetting all
1669 * ingress rate limit registers to their initial
1670 * state.
1671 */
1672 for (i = 0; i < ps->num_ports; i++)
1673 REG_WRITE(REG_GLOBAL2, GLOBAL2_INGRESS_OP,
1674 0x9000 | (i << 8));
1675 }
1676
1677 return 0;
1678}
1679
Andrew Lunn143a8302015-04-02 04:06:34 +02001680int mv88e6xxx_switch_reset(struct dsa_switch *ds, bool ppu_active)
1681{
1682 struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
1683 u16 is_reset = (ppu_active ? 0x8800 : 0xc800);
1684 unsigned long timeout;
1685 int ret;
1686 int i;
1687
1688 /* Set all ports to the disabled state. */
1689 for (i = 0; i < ps->num_ports; i++) {
Andrew Lunncca8b132015-04-02 04:06:39 +02001690 ret = REG_READ(REG_PORT(i), PORT_CONTROL);
1691 REG_WRITE(REG_PORT(i), PORT_CONTROL, ret & 0xfffc);
Andrew Lunn143a8302015-04-02 04:06:34 +02001692 }
1693
1694 /* Wait for transmit queues to drain. */
1695 usleep_range(2000, 4000);
1696
1697 /* Reset the switch. Keep the PPU active if requested. The PPU
1698 * needs to be active to support indirect phy register access
1699 * through global registers 0x18 and 0x19.
1700 */
1701 if (ppu_active)
1702 REG_WRITE(REG_GLOBAL, 0x04, 0xc000);
1703 else
1704 REG_WRITE(REG_GLOBAL, 0x04, 0xc400);
1705
1706 /* Wait up to one second for reset to complete. */
1707 timeout = jiffies + 1 * HZ;
1708 while (time_before(jiffies, timeout)) {
1709 ret = REG_READ(REG_GLOBAL, 0x00);
1710 if ((ret & is_reset) == is_reset)
1711 break;
1712 usleep_range(1000, 2000);
1713 }
1714 if (time_after(jiffies, timeout))
1715 return -ETIMEDOUT;
1716
1717 return 0;
1718}
1719
Andrew Lunn491435852015-04-02 04:06:35 +02001720int mv88e6xxx_phy_page_read(struct dsa_switch *ds, int port, int page, int reg)
1721{
1722 struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
1723 int ret;
1724
1725 mutex_lock(&ps->phy_mutex);
Andrew Lunnfd3a0ee2015-04-02 04:06:36 +02001726 ret = _mv88e6xxx_phy_write_indirect(ds, port, 0x16, page);
Andrew Lunn491435852015-04-02 04:06:35 +02001727 if (ret < 0)
1728 goto error;
Andrew Lunnfd3a0ee2015-04-02 04:06:36 +02001729 ret = _mv88e6xxx_phy_read_indirect(ds, port, reg);
Andrew Lunn491435852015-04-02 04:06:35 +02001730error:
Andrew Lunnfd3a0ee2015-04-02 04:06:36 +02001731 _mv88e6xxx_phy_write_indirect(ds, port, 0x16, 0x0);
Andrew Lunn491435852015-04-02 04:06:35 +02001732 mutex_unlock(&ps->phy_mutex);
1733 return ret;
1734}
1735
1736int mv88e6xxx_phy_page_write(struct dsa_switch *ds, int port, int page,
1737 int reg, int val)
1738{
1739 struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
1740 int ret;
1741
1742 mutex_lock(&ps->phy_mutex);
Andrew Lunnfd3a0ee2015-04-02 04:06:36 +02001743 ret = _mv88e6xxx_phy_write_indirect(ds, port, 0x16, page);
Andrew Lunn491435852015-04-02 04:06:35 +02001744 if (ret < 0)
1745 goto error;
1746
Andrew Lunnfd3a0ee2015-04-02 04:06:36 +02001747 ret = _mv88e6xxx_phy_write_indirect(ds, port, reg, val);
Andrew Lunn491435852015-04-02 04:06:35 +02001748error:
Andrew Lunnfd3a0ee2015-04-02 04:06:36 +02001749 _mv88e6xxx_phy_write_indirect(ds, port, 0x16, 0x0);
1750 mutex_unlock(&ps->phy_mutex);
1751 return ret;
1752}
1753
1754static int mv88e6xxx_port_to_phy_addr(struct dsa_switch *ds, int port)
1755{
1756 struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
1757
1758 if (port >= 0 && port < ps->num_ports)
1759 return port;
1760 return -EINVAL;
1761}
1762
1763int
1764mv88e6xxx_phy_read(struct dsa_switch *ds, int port, int regnum)
1765{
1766 struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
1767 int addr = mv88e6xxx_port_to_phy_addr(ds, port);
1768 int ret;
1769
1770 if (addr < 0)
1771 return addr;
1772
1773 mutex_lock(&ps->phy_mutex);
1774 ret = _mv88e6xxx_phy_read(ds, addr, regnum);
1775 mutex_unlock(&ps->phy_mutex);
1776 return ret;
1777}
1778
1779int
1780mv88e6xxx_phy_write(struct dsa_switch *ds, int port, int regnum, u16 val)
1781{
1782 struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
1783 int addr = mv88e6xxx_port_to_phy_addr(ds, port);
1784 int ret;
1785
1786 if (addr < 0)
1787 return addr;
1788
1789 mutex_lock(&ps->phy_mutex);
1790 ret = _mv88e6xxx_phy_write(ds, addr, regnum, val);
1791 mutex_unlock(&ps->phy_mutex);
1792 return ret;
1793}
1794
1795int
1796mv88e6xxx_phy_read_indirect(struct dsa_switch *ds, int port, int regnum)
1797{
1798 struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
1799 int addr = mv88e6xxx_port_to_phy_addr(ds, port);
1800 int ret;
1801
1802 if (addr < 0)
1803 return addr;
1804
1805 mutex_lock(&ps->phy_mutex);
1806 ret = _mv88e6xxx_phy_read_indirect(ds, addr, regnum);
1807 mutex_unlock(&ps->phy_mutex);
1808 return ret;
1809}
1810
1811int
1812mv88e6xxx_phy_write_indirect(struct dsa_switch *ds, int port, int regnum,
1813 u16 val)
1814{
1815 struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
1816 int addr = mv88e6xxx_port_to_phy_addr(ds, port);
1817 int ret;
1818
1819 if (addr < 0)
1820 return addr;
1821
1822 mutex_lock(&ps->phy_mutex);
1823 ret = _mv88e6xxx_phy_write_indirect(ds, addr, regnum, val);
Andrew Lunn491435852015-04-02 04:06:35 +02001824 mutex_unlock(&ps->phy_mutex);
1825 return ret;
1826}
1827
Ben Hutchings98e67302011-11-25 14:36:19 +00001828static int __init mv88e6xxx_init(void)
1829{
1830#if IS_ENABLED(CONFIG_NET_DSA_MV88E6131)
1831 register_switch_driver(&mv88e6131_switch_driver);
1832#endif
1833#if IS_ENABLED(CONFIG_NET_DSA_MV88E6123_61_65)
1834 register_switch_driver(&mv88e6123_61_65_switch_driver);
1835#endif
Guenter Roeck3ad50cc2014-10-29 10:44:56 -07001836#if IS_ENABLED(CONFIG_NET_DSA_MV88E6352)
1837 register_switch_driver(&mv88e6352_switch_driver);
1838#endif
Andrew Lunn42f27252014-09-12 23:58:44 +02001839#if IS_ENABLED(CONFIG_NET_DSA_MV88E6171)
1840 register_switch_driver(&mv88e6171_switch_driver);
1841#endif
Ben Hutchings98e67302011-11-25 14:36:19 +00001842 return 0;
1843}
1844module_init(mv88e6xxx_init);
1845
1846static void __exit mv88e6xxx_cleanup(void)
1847{
Andrew Lunn42f27252014-09-12 23:58:44 +02001848#if IS_ENABLED(CONFIG_NET_DSA_MV88E6171)
1849 unregister_switch_driver(&mv88e6171_switch_driver);
1850#endif
Ben Hutchings98e67302011-11-25 14:36:19 +00001851#if IS_ENABLED(CONFIG_NET_DSA_MV88E6123_61_65)
1852 unregister_switch_driver(&mv88e6123_61_65_switch_driver);
1853#endif
1854#if IS_ENABLED(CONFIG_NET_DSA_MV88E6131)
1855 unregister_switch_driver(&mv88e6131_switch_driver);
1856#endif
1857}
1858module_exit(mv88e6xxx_cleanup);
Ben Hutchings3d825ed2011-11-25 14:37:16 +00001859
1860MODULE_AUTHOR("Lennert Buytenhek <buytenh@wantstofly.org>");
1861MODULE_DESCRIPTION("Driver for Marvell 88E6XXX ethernet switch chips");
1862MODULE_LICENSE("GPL");