blob: 3774f53d28d781aaec7f5150352a944ba505d974 [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 *
Vivien Didelotb8fee952015-08-13 12:52:19 -04005 * Copyright (c) 2015 CMC Electronics, Inc.
6 * Added support for VLAN Table Unit operations
7 *
Lennert Buytenhek91da11f2008-10-07 13:44:02 +00008 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 */
13
Andrew Lunn87c8cef2015-06-20 18:42:28 +020014#include <linux/debugfs.h>
Barry Grussling19b2f972013-01-08 16:05:54 +000015#include <linux/delay.h>
Guenter Roeckdefb05b2015-03-26 18:36:38 -070016#include <linux/etherdevice.h>
Guenter Roeckfacd95b2015-03-26 18:36:35 -070017#include <linux/if_bridge.h>
Barry Grussling19b2f972013-01-08 16:05:54 +000018#include <linux/jiffies.h>
Lennert Buytenhek91da11f2008-10-07 13:44:02 +000019#include <linux/list.h>
Paul Gortmaker2bbba272012-01-24 10:41:40 +000020#include <linux/module.h>
Lennert Buytenhek91da11f2008-10-07 13:44:02 +000021#include <linux/netdevice.h>
22#include <linux/phy.h>
Andrew Lunn87c8cef2015-06-20 18:42:28 +020023#include <linux/seq_file.h>
Ben Hutchingsc8f0b862011-11-27 17:06:08 +000024#include <net/dsa.h>
Lennert Buytenhek91da11f2008-10-07 13:44:02 +000025#include "mv88e6xxx.h"
26
Andrew Lunn16fe24f2015-05-06 01:09:55 +020027/* MDIO bus access can be nested in the case of PHYs connected to the
28 * internal MDIO bus of the switch, which is accessed via MDIO bus of
29 * the Ethernet interface. Avoid lockdep false positives by using
30 * mutex_lock_nested().
31 */
32static int mv88e6xxx_mdiobus_read(struct mii_bus *bus, int addr, u32 regnum)
33{
34 int ret;
35
36 mutex_lock_nested(&bus->mdio_lock, SINGLE_DEPTH_NESTING);
37 ret = bus->read(bus, addr, regnum);
38 mutex_unlock(&bus->mdio_lock);
39
40 return ret;
41}
42
43static int mv88e6xxx_mdiobus_write(struct mii_bus *bus, int addr, u32 regnum,
44 u16 val)
45{
46 int ret;
47
48 mutex_lock_nested(&bus->mdio_lock, SINGLE_DEPTH_NESTING);
49 ret = bus->write(bus, addr, regnum, val);
50 mutex_unlock(&bus->mdio_lock);
51
52 return ret;
53}
54
Barry Grussling3675c8d2013-01-08 16:05:53 +000055/* If the switch's ADDR[4:0] strap pins are strapped to zero, it will
Lennert Buytenhek91da11f2008-10-07 13:44:02 +000056 * use all 32 SMI bus addresses on its SMI bus, and all switch registers
57 * will be directly accessible on some {device address,register address}
58 * pair. If the ADDR[4:0] pins are not strapped to zero, the switch
59 * will only respond to SMI transactions to that specific address, and
60 * an indirect addressing mechanism needs to be used to access its
61 * registers.
62 */
63static int mv88e6xxx_reg_wait_ready(struct mii_bus *bus, int sw_addr)
64{
65 int ret;
66 int i;
67
68 for (i = 0; i < 16; i++) {
Andrew Lunn16fe24f2015-05-06 01:09:55 +020069 ret = mv88e6xxx_mdiobus_read(bus, sw_addr, SMI_CMD);
Lennert Buytenhek91da11f2008-10-07 13:44:02 +000070 if (ret < 0)
71 return ret;
72
Andrew Lunncca8b132015-04-02 04:06:39 +020073 if ((ret & SMI_CMD_BUSY) == 0)
Lennert Buytenhek91da11f2008-10-07 13:44:02 +000074 return 0;
75 }
76
77 return -ETIMEDOUT;
78}
79
80int __mv88e6xxx_reg_read(struct mii_bus *bus, int sw_addr, int addr, int reg)
81{
82 int ret;
83
84 if (sw_addr == 0)
Andrew Lunn16fe24f2015-05-06 01:09:55 +020085 return mv88e6xxx_mdiobus_read(bus, addr, reg);
Lennert Buytenhek91da11f2008-10-07 13:44:02 +000086
Barry Grussling3675c8d2013-01-08 16:05:53 +000087 /* Wait for the bus to become free. */
Lennert Buytenhek91da11f2008-10-07 13:44:02 +000088 ret = mv88e6xxx_reg_wait_ready(bus, sw_addr);
89 if (ret < 0)
90 return ret;
91
Barry Grussling3675c8d2013-01-08 16:05:53 +000092 /* Transmit the read command. */
Andrew Lunn16fe24f2015-05-06 01:09:55 +020093 ret = mv88e6xxx_mdiobus_write(bus, sw_addr, SMI_CMD,
94 SMI_CMD_OP_22_READ | (addr << 5) | reg);
Lennert Buytenhek91da11f2008-10-07 13:44:02 +000095 if (ret < 0)
96 return ret;
97
Barry Grussling3675c8d2013-01-08 16:05:53 +000098 /* Wait for the read command to complete. */
Lennert Buytenhek91da11f2008-10-07 13:44:02 +000099 ret = mv88e6xxx_reg_wait_ready(bus, sw_addr);
100 if (ret < 0)
101 return ret;
102
Barry Grussling3675c8d2013-01-08 16:05:53 +0000103 /* Read the data. */
Andrew Lunn16fe24f2015-05-06 01:09:55 +0200104 ret = mv88e6xxx_mdiobus_read(bus, sw_addr, SMI_DATA);
Lennert Buytenhek91da11f2008-10-07 13:44:02 +0000105 if (ret < 0)
106 return ret;
107
108 return ret & 0xffff;
109}
110
Guenter Roeck8d6d09e2015-03-26 18:36:31 -0700111/* Must be called with SMI mutex held */
112static int _mv88e6xxx_reg_read(struct dsa_switch *ds, int addr, int reg)
Lennert Buytenhek91da11f2008-10-07 13:44:02 +0000113{
Guenter Roeckb184e492014-10-17 12:30:58 -0700114 struct mii_bus *bus = dsa_host_dev_to_mii_bus(ds->master_dev);
Lennert Buytenhek91da11f2008-10-07 13:44:02 +0000115 int ret;
116
Guenter Roeckb184e492014-10-17 12:30:58 -0700117 if (bus == NULL)
118 return -EINVAL;
119
Guenter Roeckb184e492014-10-17 12:30:58 -0700120 ret = __mv88e6xxx_reg_read(bus, ds->pd->sw_addr, addr, reg);
Vivien Didelotbb92ea52015-01-23 16:10:36 -0500121 if (ret < 0)
122 return ret;
123
124 dev_dbg(ds->master_dev, "<- addr: 0x%.2x reg: 0x%.2x val: 0x%.4x\n",
125 addr, reg, ret);
126
Lennert Buytenhek91da11f2008-10-07 13:44:02 +0000127 return ret;
128}
129
Guenter Roeck8d6d09e2015-03-26 18:36:31 -0700130int mv88e6xxx_reg_read(struct dsa_switch *ds, int addr, int reg)
131{
132 struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
133 int ret;
134
135 mutex_lock(&ps->smi_mutex);
136 ret = _mv88e6xxx_reg_read(ds, addr, reg);
137 mutex_unlock(&ps->smi_mutex);
138
139 return ret;
140}
141
Lennert Buytenhek91da11f2008-10-07 13:44:02 +0000142int __mv88e6xxx_reg_write(struct mii_bus *bus, int sw_addr, int addr,
143 int reg, u16 val)
144{
145 int ret;
146
147 if (sw_addr == 0)
Andrew Lunn16fe24f2015-05-06 01:09:55 +0200148 return mv88e6xxx_mdiobus_write(bus, addr, reg, val);
Lennert Buytenhek91da11f2008-10-07 13:44:02 +0000149
Barry Grussling3675c8d2013-01-08 16:05:53 +0000150 /* Wait for the bus to become free. */
Lennert Buytenhek91da11f2008-10-07 13:44:02 +0000151 ret = mv88e6xxx_reg_wait_ready(bus, sw_addr);
152 if (ret < 0)
153 return ret;
154
Barry Grussling3675c8d2013-01-08 16:05:53 +0000155 /* Transmit the data to write. */
Andrew Lunn16fe24f2015-05-06 01:09:55 +0200156 ret = mv88e6xxx_mdiobus_write(bus, sw_addr, SMI_DATA, val);
Lennert Buytenhek91da11f2008-10-07 13:44:02 +0000157 if (ret < 0)
158 return ret;
159
Barry Grussling3675c8d2013-01-08 16:05:53 +0000160 /* Transmit the write command. */
Andrew Lunn16fe24f2015-05-06 01:09:55 +0200161 ret = mv88e6xxx_mdiobus_write(bus, sw_addr, SMI_CMD,
162 SMI_CMD_OP_22_WRITE | (addr << 5) | reg);
Lennert Buytenhek91da11f2008-10-07 13:44:02 +0000163 if (ret < 0)
164 return ret;
165
Barry Grussling3675c8d2013-01-08 16:05:53 +0000166 /* Wait for the write command to complete. */
Lennert Buytenhek91da11f2008-10-07 13:44:02 +0000167 ret = mv88e6xxx_reg_wait_ready(bus, sw_addr);
168 if (ret < 0)
169 return ret;
170
171 return 0;
172}
173
Guenter Roeck8d6d09e2015-03-26 18:36:31 -0700174/* Must be called with SMI mutex held */
175static int _mv88e6xxx_reg_write(struct dsa_switch *ds, int addr, int reg,
176 u16 val)
Lennert Buytenhek91da11f2008-10-07 13:44:02 +0000177{
Guenter Roeckb184e492014-10-17 12:30:58 -0700178 struct mii_bus *bus = dsa_host_dev_to_mii_bus(ds->master_dev);
Lennert Buytenhek91da11f2008-10-07 13:44:02 +0000179
Guenter Roeckb184e492014-10-17 12:30:58 -0700180 if (bus == NULL)
181 return -EINVAL;
182
Vivien Didelotbb92ea52015-01-23 16:10:36 -0500183 dev_dbg(ds->master_dev, "-> addr: 0x%.2x reg: 0x%.2x val: 0x%.4x\n",
184 addr, reg, val);
185
Guenter Roeck8d6d09e2015-03-26 18:36:31 -0700186 return __mv88e6xxx_reg_write(bus, ds->pd->sw_addr, addr, reg, val);
187}
188
189int mv88e6xxx_reg_write(struct dsa_switch *ds, int addr, int reg, u16 val)
190{
191 struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
192 int ret;
193
Lennert Buytenhek91da11f2008-10-07 13:44:02 +0000194 mutex_lock(&ps->smi_mutex);
Guenter Roeck8d6d09e2015-03-26 18:36:31 -0700195 ret = _mv88e6xxx_reg_write(ds, addr, reg, val);
Lennert Buytenhek91da11f2008-10-07 13:44:02 +0000196 mutex_unlock(&ps->smi_mutex);
197
198 return ret;
199}
200
Lennert Buytenhek2e5f0322008-10-07 13:45:18 +0000201int mv88e6xxx_set_addr_direct(struct dsa_switch *ds, u8 *addr)
202{
Andrew Lunncca8b132015-04-02 04:06:39 +0200203 REG_WRITE(REG_GLOBAL, GLOBAL_MAC_01, (addr[0] << 8) | addr[1]);
204 REG_WRITE(REG_GLOBAL, GLOBAL_MAC_23, (addr[2] << 8) | addr[3]);
205 REG_WRITE(REG_GLOBAL, GLOBAL_MAC_45, (addr[4] << 8) | addr[5]);
Lennert Buytenhek2e5f0322008-10-07 13:45:18 +0000206
207 return 0;
208}
209
Lennert Buytenhek91da11f2008-10-07 13:44:02 +0000210int mv88e6xxx_set_addr_indirect(struct dsa_switch *ds, u8 *addr)
211{
212 int i;
213 int ret;
214
215 for (i = 0; i < 6; i++) {
216 int j;
217
Barry Grussling3675c8d2013-01-08 16:05:53 +0000218 /* Write the MAC address byte. */
Andrew Lunncca8b132015-04-02 04:06:39 +0200219 REG_WRITE(REG_GLOBAL2, GLOBAL2_SWITCH_MAC,
220 GLOBAL2_SWITCH_MAC_BUSY | (i << 8) | addr[i]);
Lennert Buytenhek91da11f2008-10-07 13:44:02 +0000221
Barry Grussling3675c8d2013-01-08 16:05:53 +0000222 /* Wait for the write to complete. */
Lennert Buytenhek91da11f2008-10-07 13:44:02 +0000223 for (j = 0; j < 16; j++) {
Andrew Lunncca8b132015-04-02 04:06:39 +0200224 ret = REG_READ(REG_GLOBAL2, GLOBAL2_SWITCH_MAC);
225 if ((ret & GLOBAL2_SWITCH_MAC_BUSY) == 0)
Lennert Buytenhek91da11f2008-10-07 13:44:02 +0000226 break;
227 }
228 if (j == 16)
229 return -ETIMEDOUT;
230 }
231
232 return 0;
233}
234
Andrew Lunn3898c142015-05-06 01:09:53 +0200235/* Must be called with SMI mutex held */
Andrew Lunnfd3a0ee2015-04-02 04:06:36 +0200236static int _mv88e6xxx_phy_read(struct dsa_switch *ds, int addr, int regnum)
Lennert Buytenhek91da11f2008-10-07 13:44:02 +0000237{
238 if (addr >= 0)
Andrew Lunn3898c142015-05-06 01:09:53 +0200239 return _mv88e6xxx_reg_read(ds, addr, regnum);
Lennert Buytenhek91da11f2008-10-07 13:44:02 +0000240 return 0xffff;
241}
242
Andrew Lunn3898c142015-05-06 01:09:53 +0200243/* Must be called with SMI mutex held */
Andrew Lunnfd3a0ee2015-04-02 04:06:36 +0200244static int _mv88e6xxx_phy_write(struct dsa_switch *ds, int addr, int regnum,
245 u16 val)
Lennert Buytenhek91da11f2008-10-07 13:44:02 +0000246{
247 if (addr >= 0)
Andrew Lunn3898c142015-05-06 01:09:53 +0200248 return _mv88e6xxx_reg_write(ds, addr, regnum, val);
Lennert Buytenhek91da11f2008-10-07 13:44:02 +0000249 return 0;
250}
251
Lennert Buytenhek2e5f0322008-10-07 13:45:18 +0000252#ifdef CONFIG_NET_DSA_MV88E6XXX_NEED_PPU
253static int mv88e6xxx_ppu_disable(struct dsa_switch *ds)
254{
255 int ret;
Barry Grussling19b2f972013-01-08 16:05:54 +0000256 unsigned long timeout;
Lennert Buytenhek2e5f0322008-10-07 13:45:18 +0000257
Andrew Lunncca8b132015-04-02 04:06:39 +0200258 ret = REG_READ(REG_GLOBAL, GLOBAL_CONTROL);
259 REG_WRITE(REG_GLOBAL, GLOBAL_CONTROL,
260 ret & ~GLOBAL_CONTROL_PPU_ENABLE);
Lennert Buytenhek2e5f0322008-10-07 13:45:18 +0000261
Barry Grussling19b2f972013-01-08 16:05:54 +0000262 timeout = jiffies + 1 * HZ;
263 while (time_before(jiffies, timeout)) {
Andrew Lunncca8b132015-04-02 04:06:39 +0200264 ret = REG_READ(REG_GLOBAL, GLOBAL_STATUS);
Barry Grussling19b2f972013-01-08 16:05:54 +0000265 usleep_range(1000, 2000);
Andrew Lunncca8b132015-04-02 04:06:39 +0200266 if ((ret & GLOBAL_STATUS_PPU_MASK) !=
267 GLOBAL_STATUS_PPU_POLLING)
Barry Grussling85686582013-01-08 16:05:56 +0000268 return 0;
Lennert Buytenhek2e5f0322008-10-07 13:45:18 +0000269 }
270
271 return -ETIMEDOUT;
272}
273
274static int mv88e6xxx_ppu_enable(struct dsa_switch *ds)
275{
276 int ret;
Barry Grussling19b2f972013-01-08 16:05:54 +0000277 unsigned long timeout;
Lennert Buytenhek2e5f0322008-10-07 13:45:18 +0000278
Andrew Lunncca8b132015-04-02 04:06:39 +0200279 ret = REG_READ(REG_GLOBAL, GLOBAL_CONTROL);
280 REG_WRITE(REG_GLOBAL, GLOBAL_CONTROL, ret | GLOBAL_CONTROL_PPU_ENABLE);
Lennert Buytenhek2e5f0322008-10-07 13:45:18 +0000281
Barry Grussling19b2f972013-01-08 16:05:54 +0000282 timeout = jiffies + 1 * HZ;
283 while (time_before(jiffies, timeout)) {
Andrew Lunncca8b132015-04-02 04:06:39 +0200284 ret = REG_READ(REG_GLOBAL, GLOBAL_STATUS);
Barry Grussling19b2f972013-01-08 16:05:54 +0000285 usleep_range(1000, 2000);
Andrew Lunncca8b132015-04-02 04:06:39 +0200286 if ((ret & GLOBAL_STATUS_PPU_MASK) ==
287 GLOBAL_STATUS_PPU_POLLING)
Barry Grussling85686582013-01-08 16:05:56 +0000288 return 0;
Lennert Buytenhek2e5f0322008-10-07 13:45:18 +0000289 }
290
291 return -ETIMEDOUT;
292}
293
294static void mv88e6xxx_ppu_reenable_work(struct work_struct *ugly)
295{
296 struct mv88e6xxx_priv_state *ps;
297
298 ps = container_of(ugly, struct mv88e6xxx_priv_state, ppu_work);
299 if (mutex_trylock(&ps->ppu_mutex)) {
Barry Grussling85686582013-01-08 16:05:56 +0000300 struct dsa_switch *ds = ((struct dsa_switch *)ps) - 1;
Lennert Buytenhek2e5f0322008-10-07 13:45:18 +0000301
Barry Grussling85686582013-01-08 16:05:56 +0000302 if (mv88e6xxx_ppu_enable(ds) == 0)
303 ps->ppu_disabled = 0;
304 mutex_unlock(&ps->ppu_mutex);
Lennert Buytenhek2e5f0322008-10-07 13:45:18 +0000305 }
306}
307
308static void mv88e6xxx_ppu_reenable_timer(unsigned long _ps)
309{
310 struct mv88e6xxx_priv_state *ps = (void *)_ps;
311
312 schedule_work(&ps->ppu_work);
313}
314
315static int mv88e6xxx_ppu_access_get(struct dsa_switch *ds)
316{
Florian Fainellia22adce2014-04-28 11:14:28 -0700317 struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
Lennert Buytenhek2e5f0322008-10-07 13:45:18 +0000318 int ret;
319
320 mutex_lock(&ps->ppu_mutex);
321
Barry Grussling3675c8d2013-01-08 16:05:53 +0000322 /* If the PHY polling unit is enabled, disable it so that
Lennert Buytenhek2e5f0322008-10-07 13:45:18 +0000323 * we can access the PHY registers. If it was already
324 * disabled, cancel the timer that is going to re-enable
325 * it.
326 */
327 if (!ps->ppu_disabled) {
Barry Grussling85686582013-01-08 16:05:56 +0000328 ret = mv88e6xxx_ppu_disable(ds);
329 if (ret < 0) {
330 mutex_unlock(&ps->ppu_mutex);
331 return ret;
332 }
333 ps->ppu_disabled = 1;
Lennert Buytenhek2e5f0322008-10-07 13:45:18 +0000334 } else {
Barry Grussling85686582013-01-08 16:05:56 +0000335 del_timer(&ps->ppu_timer);
336 ret = 0;
Lennert Buytenhek2e5f0322008-10-07 13:45:18 +0000337 }
338
339 return ret;
340}
341
342static void mv88e6xxx_ppu_access_put(struct dsa_switch *ds)
343{
Florian Fainellia22adce2014-04-28 11:14:28 -0700344 struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
Lennert Buytenhek2e5f0322008-10-07 13:45:18 +0000345
Barry Grussling3675c8d2013-01-08 16:05:53 +0000346 /* Schedule a timer to re-enable the PHY polling unit. */
Lennert Buytenhek2e5f0322008-10-07 13:45:18 +0000347 mod_timer(&ps->ppu_timer, jiffies + msecs_to_jiffies(10));
348 mutex_unlock(&ps->ppu_mutex);
349}
350
351void mv88e6xxx_ppu_state_init(struct dsa_switch *ds)
352{
Florian Fainellia22adce2014-04-28 11:14:28 -0700353 struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
Lennert Buytenhek2e5f0322008-10-07 13:45:18 +0000354
355 mutex_init(&ps->ppu_mutex);
356 INIT_WORK(&ps->ppu_work, mv88e6xxx_ppu_reenable_work);
357 init_timer(&ps->ppu_timer);
358 ps->ppu_timer.data = (unsigned long)ps;
359 ps->ppu_timer.function = mv88e6xxx_ppu_reenable_timer;
360}
361
362int mv88e6xxx_phy_read_ppu(struct dsa_switch *ds, int addr, int regnum)
363{
364 int ret;
365
366 ret = mv88e6xxx_ppu_access_get(ds);
367 if (ret >= 0) {
Barry Grussling85686582013-01-08 16:05:56 +0000368 ret = mv88e6xxx_reg_read(ds, addr, regnum);
369 mv88e6xxx_ppu_access_put(ds);
Lennert Buytenhek2e5f0322008-10-07 13:45:18 +0000370 }
371
372 return ret;
373}
374
375int mv88e6xxx_phy_write_ppu(struct dsa_switch *ds, int addr,
376 int regnum, u16 val)
377{
378 int ret;
379
380 ret = mv88e6xxx_ppu_access_get(ds);
381 if (ret >= 0) {
Barry Grussling85686582013-01-08 16:05:56 +0000382 ret = mv88e6xxx_reg_write(ds, addr, regnum, val);
383 mv88e6xxx_ppu_access_put(ds);
Lennert Buytenhek2e5f0322008-10-07 13:45:18 +0000384 }
385
386 return ret;
387}
388#endif
389
Lennert Buytenhek91da11f2008-10-07 13:44:02 +0000390void mv88e6xxx_poll_link(struct dsa_switch *ds)
391{
392 int i;
393
394 for (i = 0; i < DSA_MAX_PORTS; i++) {
395 struct net_device *dev;
Ingo Molnar2a9e7972008-11-25 16:50:49 -0800396 int uninitialized_var(port_status);
Lennert Buytenhek91da11f2008-10-07 13:44:02 +0000397 int link;
398 int speed;
399 int duplex;
400 int fc;
401
402 dev = ds->ports[i];
403 if (dev == NULL)
404 continue;
405
406 link = 0;
407 if (dev->flags & IFF_UP) {
Andrew Lunncca8b132015-04-02 04:06:39 +0200408 port_status = mv88e6xxx_reg_read(ds, REG_PORT(i),
409 PORT_STATUS);
Lennert Buytenhek91da11f2008-10-07 13:44:02 +0000410 if (port_status < 0)
411 continue;
412
Andrew Lunncca8b132015-04-02 04:06:39 +0200413 link = !!(port_status & PORT_STATUS_LINK);
Lennert Buytenhek91da11f2008-10-07 13:44:02 +0000414 }
415
416 if (!link) {
417 if (netif_carrier_ok(dev)) {
Barry Grusslingab381a92013-01-08 16:05:55 +0000418 netdev_info(dev, "link down\n");
Lennert Buytenhek91da11f2008-10-07 13:44:02 +0000419 netif_carrier_off(dev);
420 }
421 continue;
422 }
423
Andrew Lunncca8b132015-04-02 04:06:39 +0200424 switch (port_status & PORT_STATUS_SPEED_MASK) {
425 case PORT_STATUS_SPEED_10:
Lennert Buytenhek91da11f2008-10-07 13:44:02 +0000426 speed = 10;
427 break;
Andrew Lunncca8b132015-04-02 04:06:39 +0200428 case PORT_STATUS_SPEED_100:
Lennert Buytenhek91da11f2008-10-07 13:44:02 +0000429 speed = 100;
430 break;
Andrew Lunncca8b132015-04-02 04:06:39 +0200431 case PORT_STATUS_SPEED_1000:
Lennert Buytenhek91da11f2008-10-07 13:44:02 +0000432 speed = 1000;
433 break;
434 default:
435 speed = -1;
436 break;
437 }
Andrew Lunncca8b132015-04-02 04:06:39 +0200438 duplex = (port_status & PORT_STATUS_DUPLEX) ? 1 : 0;
439 fc = (port_status & PORT_STATUS_PAUSE_EN) ? 1 : 0;
Lennert Buytenhek91da11f2008-10-07 13:44:02 +0000440
441 if (!netif_carrier_ok(dev)) {
Barry Grusslingab381a92013-01-08 16:05:55 +0000442 netdev_info(dev,
443 "link up, %d Mb/s, %s duplex, flow control %sabled\n",
444 speed,
445 duplex ? "full" : "half",
446 fc ? "en" : "dis");
Lennert Buytenhek91da11f2008-10-07 13:44:02 +0000447 netif_carrier_on(dev);
448 }
449 }
450}
451
Andrew Lunn54d792f2015-05-06 01:09:47 +0200452static bool mv88e6xxx_6065_family(struct dsa_switch *ds)
453{
454 struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
455
456 switch (ps->id) {
457 case PORT_SWITCH_ID_6031:
458 case PORT_SWITCH_ID_6061:
459 case PORT_SWITCH_ID_6035:
460 case PORT_SWITCH_ID_6065:
461 return true;
462 }
463 return false;
464}
465
466static bool mv88e6xxx_6095_family(struct dsa_switch *ds)
467{
468 struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
469
470 switch (ps->id) {
471 case PORT_SWITCH_ID_6092:
472 case PORT_SWITCH_ID_6095:
473 return true;
474 }
475 return false;
476}
477
478static bool mv88e6xxx_6097_family(struct dsa_switch *ds)
479{
480 struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
481
482 switch (ps->id) {
483 case PORT_SWITCH_ID_6046:
484 case PORT_SWITCH_ID_6085:
485 case PORT_SWITCH_ID_6096:
486 case PORT_SWITCH_ID_6097:
487 return true;
488 }
489 return false;
490}
491
492static bool mv88e6xxx_6165_family(struct dsa_switch *ds)
493{
494 struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
495
496 switch (ps->id) {
497 case PORT_SWITCH_ID_6123:
498 case PORT_SWITCH_ID_6161:
499 case PORT_SWITCH_ID_6165:
500 return true;
501 }
502 return false;
503}
504
505static bool mv88e6xxx_6185_family(struct dsa_switch *ds)
506{
507 struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
508
509 switch (ps->id) {
510 case PORT_SWITCH_ID_6121:
511 case PORT_SWITCH_ID_6122:
512 case PORT_SWITCH_ID_6152:
513 case PORT_SWITCH_ID_6155:
514 case PORT_SWITCH_ID_6182:
515 case PORT_SWITCH_ID_6185:
516 case PORT_SWITCH_ID_6108:
517 case PORT_SWITCH_ID_6131:
518 return true;
519 }
520 return false;
521}
522
Guenter Roeckc22995c2015-07-25 09:42:28 -0700523static bool mv88e6xxx_6320_family(struct dsa_switch *ds)
Aleksey S. Kazantsev7c3d0d62015-07-07 20:38:15 -0700524{
525 struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
526
527 switch (ps->id) {
528 case PORT_SWITCH_ID_6320:
529 case PORT_SWITCH_ID_6321:
530 return true;
531 }
532 return false;
533}
534
Andrew Lunn54d792f2015-05-06 01:09:47 +0200535static bool mv88e6xxx_6351_family(struct dsa_switch *ds)
536{
537 struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
538
539 switch (ps->id) {
540 case PORT_SWITCH_ID_6171:
541 case PORT_SWITCH_ID_6175:
542 case PORT_SWITCH_ID_6350:
543 case PORT_SWITCH_ID_6351:
544 return true;
545 }
546 return false;
547}
548
Andrew Lunnf3a8b6b2015-04-02 04:06:40 +0200549static bool mv88e6xxx_6352_family(struct dsa_switch *ds)
550{
551 struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
552
553 switch (ps->id) {
Andrew Lunnf3a8b6b2015-04-02 04:06:40 +0200554 case PORT_SWITCH_ID_6172:
555 case PORT_SWITCH_ID_6176:
Andrew Lunn54d792f2015-05-06 01:09:47 +0200556 case PORT_SWITCH_ID_6240:
557 case PORT_SWITCH_ID_6352:
Andrew Lunnf3a8b6b2015-04-02 04:06:40 +0200558 return true;
559 }
560 return false;
561}
562
Andrew Lunn31888232015-05-06 01:09:54 +0200563/* Must be called with SMI mutex held */
564static int _mv88e6xxx_stats_wait(struct dsa_switch *ds)
Lennert Buytenhek91da11f2008-10-07 13:44:02 +0000565{
566 int ret;
567 int i;
568
569 for (i = 0; i < 10; i++) {
Andrew Lunn31888232015-05-06 01:09:54 +0200570 ret = _mv88e6xxx_reg_read(ds, REG_GLOBAL, GLOBAL_STATS_OP);
Andrew Lunncca8b132015-04-02 04:06:39 +0200571 if ((ret & GLOBAL_STATS_OP_BUSY) == 0)
Lennert Buytenhek91da11f2008-10-07 13:44:02 +0000572 return 0;
573 }
574
575 return -ETIMEDOUT;
576}
577
Andrew Lunn31888232015-05-06 01:09:54 +0200578/* Must be called with SMI mutex held */
579static int _mv88e6xxx_stats_snapshot(struct dsa_switch *ds, int port)
Lennert Buytenhek91da11f2008-10-07 13:44:02 +0000580{
581 int ret;
582
Aleksey S. Kazantsev7c3d0d62015-07-07 20:38:15 -0700583 if (mv88e6xxx_6320_family(ds) || mv88e6xxx_6352_family(ds))
Andrew Lunnf3a8b6b2015-04-02 04:06:40 +0200584 port = (port + 1) << 5;
585
Barry Grussling3675c8d2013-01-08 16:05:53 +0000586 /* Snapshot the hardware statistics counters for this port. */
Andrew Lunn31888232015-05-06 01:09:54 +0200587 ret = _mv88e6xxx_reg_write(ds, REG_GLOBAL, GLOBAL_STATS_OP,
588 GLOBAL_STATS_OP_CAPTURE_PORT |
589 GLOBAL_STATS_OP_HIST_RX_TX | port);
590 if (ret < 0)
591 return ret;
Lennert Buytenhek91da11f2008-10-07 13:44:02 +0000592
Barry Grussling3675c8d2013-01-08 16:05:53 +0000593 /* Wait for the snapshotting to complete. */
Andrew Lunn31888232015-05-06 01:09:54 +0200594 ret = _mv88e6xxx_stats_wait(ds);
Lennert Buytenhek91da11f2008-10-07 13:44:02 +0000595 if (ret < 0)
596 return ret;
597
598 return 0;
599}
600
Andrew Lunn31888232015-05-06 01:09:54 +0200601/* Must be called with SMI mutex held */
602static void _mv88e6xxx_stats_read(struct dsa_switch *ds, int stat, u32 *val)
Lennert Buytenhek91da11f2008-10-07 13:44:02 +0000603{
604 u32 _val;
605 int ret;
606
607 *val = 0;
608
Andrew Lunn31888232015-05-06 01:09:54 +0200609 ret = _mv88e6xxx_reg_write(ds, REG_GLOBAL, GLOBAL_STATS_OP,
610 GLOBAL_STATS_OP_READ_CAPTURED |
611 GLOBAL_STATS_OP_HIST_RX_TX | stat);
Lennert Buytenhek91da11f2008-10-07 13:44:02 +0000612 if (ret < 0)
613 return;
614
Andrew Lunn31888232015-05-06 01:09:54 +0200615 ret = _mv88e6xxx_stats_wait(ds);
Lennert Buytenhek91da11f2008-10-07 13:44:02 +0000616 if (ret < 0)
617 return;
618
Andrew Lunn31888232015-05-06 01:09:54 +0200619 ret = _mv88e6xxx_reg_read(ds, REG_GLOBAL, GLOBAL_STATS_COUNTER_32);
Lennert Buytenhek91da11f2008-10-07 13:44:02 +0000620 if (ret < 0)
621 return;
622
623 _val = ret << 16;
624
Andrew Lunn31888232015-05-06 01:09:54 +0200625 ret = _mv88e6xxx_reg_read(ds, REG_GLOBAL, GLOBAL_STATS_COUNTER_01);
Lennert Buytenhek91da11f2008-10-07 13:44:02 +0000626 if (ret < 0)
627 return;
628
629 *val = _val | ret;
630}
631
Andrew Lunne413e7e2015-04-02 04:06:38 +0200632static struct mv88e6xxx_hw_stat mv88e6xxx_hw_stats[] = {
633 { "in_good_octets", 8, 0x00, },
634 { "in_bad_octets", 4, 0x02, },
635 { "in_unicast", 4, 0x04, },
636 { "in_broadcasts", 4, 0x06, },
637 { "in_multicasts", 4, 0x07, },
638 { "in_pause", 4, 0x16, },
639 { "in_undersize", 4, 0x18, },
640 { "in_fragments", 4, 0x19, },
641 { "in_oversize", 4, 0x1a, },
642 { "in_jabber", 4, 0x1b, },
643 { "in_rx_error", 4, 0x1c, },
644 { "in_fcs_error", 4, 0x1d, },
645 { "out_octets", 8, 0x0e, },
646 { "out_unicast", 4, 0x10, },
647 { "out_broadcasts", 4, 0x13, },
648 { "out_multicasts", 4, 0x12, },
649 { "out_pause", 4, 0x15, },
650 { "excessive", 4, 0x11, },
651 { "collisions", 4, 0x1e, },
652 { "deferred", 4, 0x05, },
653 { "single", 4, 0x14, },
654 { "multiple", 4, 0x17, },
655 { "out_fcs_error", 4, 0x03, },
656 { "late", 4, 0x1f, },
657 { "hist_64bytes", 4, 0x08, },
658 { "hist_65_127bytes", 4, 0x09, },
659 { "hist_128_255bytes", 4, 0x0a, },
660 { "hist_256_511bytes", 4, 0x0b, },
661 { "hist_512_1023bytes", 4, 0x0c, },
662 { "hist_1024_max_bytes", 4, 0x0d, },
663 /* Not all devices have the following counters */
664 { "sw_in_discards", 4, 0x110, },
665 { "sw_in_filtered", 2, 0x112, },
666 { "sw_out_filtered", 2, 0x113, },
667
668};
669
670static bool have_sw_in_discards(struct dsa_switch *ds)
671{
672 struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
673
674 switch (ps->id) {
Andrew Lunncca8b132015-04-02 04:06:39 +0200675 case PORT_SWITCH_ID_6095: case PORT_SWITCH_ID_6161:
676 case PORT_SWITCH_ID_6165: case PORT_SWITCH_ID_6171:
677 case PORT_SWITCH_ID_6172: case PORT_SWITCH_ID_6176:
678 case PORT_SWITCH_ID_6182: case PORT_SWITCH_ID_6185:
679 case PORT_SWITCH_ID_6352:
Andrew Lunne413e7e2015-04-02 04:06:38 +0200680 return true;
681 default:
682 return false;
683 }
684}
685
686static void _mv88e6xxx_get_strings(struct dsa_switch *ds,
687 int nr_stats,
688 struct mv88e6xxx_hw_stat *stats,
689 int port, uint8_t *data)
Lennert Buytenhek91da11f2008-10-07 13:44:02 +0000690{
691 int i;
692
693 for (i = 0; i < nr_stats; i++) {
694 memcpy(data + i * ETH_GSTRING_LEN,
695 stats[i].string, ETH_GSTRING_LEN);
696 }
697}
698
Andrew Lunn80c46272015-06-20 18:42:30 +0200699static uint64_t _mv88e6xxx_get_ethtool_stat(struct dsa_switch *ds,
700 int stat,
701 struct mv88e6xxx_hw_stat *stats,
702 int port)
703{
704 struct mv88e6xxx_hw_stat *s = stats + stat;
705 u32 low;
706 u32 high = 0;
707 int ret;
708 u64 value;
709
710 if (s->reg >= 0x100) {
711 ret = _mv88e6xxx_reg_read(ds, REG_PORT(port),
712 s->reg - 0x100);
713 if (ret < 0)
714 return UINT64_MAX;
715
716 low = ret;
717 if (s->sizeof_stat == 4) {
718 ret = _mv88e6xxx_reg_read(ds, REG_PORT(port),
719 s->reg - 0x100 + 1);
720 if (ret < 0)
721 return UINT64_MAX;
722 high = ret;
723 }
724 } else {
725 _mv88e6xxx_stats_read(ds, s->reg, &low);
726 if (s->sizeof_stat == 8)
727 _mv88e6xxx_stats_read(ds, s->reg + 1, &high);
728 }
729 value = (((u64)high) << 16) | low;
730 return value;
731}
732
Andrew Lunne413e7e2015-04-02 04:06:38 +0200733static void _mv88e6xxx_get_ethtool_stats(struct dsa_switch *ds,
734 int nr_stats,
735 struct mv88e6xxx_hw_stat *stats,
736 int port, uint64_t *data)
Lennert Buytenhek91da11f2008-10-07 13:44:02 +0000737{
Florian Fainellia22adce2014-04-28 11:14:28 -0700738 struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
Lennert Buytenhek91da11f2008-10-07 13:44:02 +0000739 int ret;
740 int i;
741
Andrew Lunn31888232015-05-06 01:09:54 +0200742 mutex_lock(&ps->smi_mutex);
Lennert Buytenhek91da11f2008-10-07 13:44:02 +0000743
Andrew Lunn31888232015-05-06 01:09:54 +0200744 ret = _mv88e6xxx_stats_snapshot(ds, port);
Lennert Buytenhek91da11f2008-10-07 13:44:02 +0000745 if (ret < 0) {
Andrew Lunn31888232015-05-06 01:09:54 +0200746 mutex_unlock(&ps->smi_mutex);
Lennert Buytenhek91da11f2008-10-07 13:44:02 +0000747 return;
748 }
749
Barry Grussling3675c8d2013-01-08 16:05:53 +0000750 /* Read each of the counters. */
Andrew Lunn80c46272015-06-20 18:42:30 +0200751 for (i = 0; i < nr_stats; i++)
752 data[i] = _mv88e6xxx_get_ethtool_stat(ds, i, stats, port);
Lennert Buytenhek91da11f2008-10-07 13:44:02 +0000753
Andrew Lunn31888232015-05-06 01:09:54 +0200754 mutex_unlock(&ps->smi_mutex);
Lennert Buytenhek91da11f2008-10-07 13:44:02 +0000755}
Ben Hutchings98e67302011-11-25 14:36:19 +0000756
Andrew Lunne413e7e2015-04-02 04:06:38 +0200757/* All the statistics in the table */
758void
759mv88e6xxx_get_strings(struct dsa_switch *ds, int port, uint8_t *data)
760{
761 if (have_sw_in_discards(ds))
762 _mv88e6xxx_get_strings(ds, ARRAY_SIZE(mv88e6xxx_hw_stats),
763 mv88e6xxx_hw_stats, port, data);
764 else
765 _mv88e6xxx_get_strings(ds, ARRAY_SIZE(mv88e6xxx_hw_stats) - 3,
766 mv88e6xxx_hw_stats, port, data);
767}
768
769int mv88e6xxx_get_sset_count(struct dsa_switch *ds)
770{
771 if (have_sw_in_discards(ds))
772 return ARRAY_SIZE(mv88e6xxx_hw_stats);
773 return ARRAY_SIZE(mv88e6xxx_hw_stats) - 3;
774}
775
776void
777mv88e6xxx_get_ethtool_stats(struct dsa_switch *ds,
778 int port, uint64_t *data)
779{
780 if (have_sw_in_discards(ds))
781 _mv88e6xxx_get_ethtool_stats(
782 ds, ARRAY_SIZE(mv88e6xxx_hw_stats),
783 mv88e6xxx_hw_stats, port, data);
784 else
785 _mv88e6xxx_get_ethtool_stats(
786 ds, ARRAY_SIZE(mv88e6xxx_hw_stats) - 3,
787 mv88e6xxx_hw_stats, port, data);
788}
789
Guenter Roecka1ab91f2014-10-29 10:45:05 -0700790int mv88e6xxx_get_regs_len(struct dsa_switch *ds, int port)
791{
792 return 32 * sizeof(u16);
793}
794
795void mv88e6xxx_get_regs(struct dsa_switch *ds, int port,
796 struct ethtool_regs *regs, void *_p)
797{
798 u16 *p = _p;
799 int i;
800
801 regs->version = 0;
802
803 memset(p, 0xff, 32 * sizeof(u16));
804
805 for (i = 0; i < 32; i++) {
806 int ret;
807
808 ret = mv88e6xxx_reg_read(ds, REG_PORT(port), i);
809 if (ret >= 0)
810 p[i] = ret;
811 }
812}
813
Guenter Roeckfacd95b2015-03-26 18:36:35 -0700814/* Must be called with SMI lock held */
Andrew Lunn3898c142015-05-06 01:09:53 +0200815static int _mv88e6xxx_wait(struct dsa_switch *ds, int reg, int offset,
816 u16 mask)
Guenter Roeckfacd95b2015-03-26 18:36:35 -0700817{
818 unsigned long timeout = jiffies + HZ / 10;
819
820 while (time_before(jiffies, timeout)) {
821 int ret;
822
823 ret = _mv88e6xxx_reg_read(ds, reg, offset);
824 if (ret < 0)
825 return ret;
826 if (!(ret & mask))
827 return 0;
828
829 usleep_range(1000, 2000);
830 }
831 return -ETIMEDOUT;
832}
833
Andrew Lunn3898c142015-05-06 01:09:53 +0200834static int mv88e6xxx_wait(struct dsa_switch *ds, int reg, int offset, u16 mask)
835{
836 struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
837 int ret;
838
839 mutex_lock(&ps->smi_mutex);
840 ret = _mv88e6xxx_wait(ds, reg, offset, mask);
841 mutex_unlock(&ps->smi_mutex);
842
843 return ret;
844}
845
846static int _mv88e6xxx_phy_wait(struct dsa_switch *ds)
847{
848 return _mv88e6xxx_wait(ds, REG_GLOBAL2, GLOBAL2_SMI_OP,
849 GLOBAL2_SMI_OP_BUSY);
850}
851
852int mv88e6xxx_eeprom_load_wait(struct dsa_switch *ds)
853{
854 return mv88e6xxx_wait(ds, REG_GLOBAL2, GLOBAL2_EEPROM_OP,
855 GLOBAL2_EEPROM_OP_LOAD);
856}
857
858int mv88e6xxx_eeprom_busy_wait(struct dsa_switch *ds)
859{
860 return mv88e6xxx_wait(ds, REG_GLOBAL2, GLOBAL2_EEPROM_OP,
861 GLOBAL2_EEPROM_OP_BUSY);
862}
863
Guenter Roeckfacd95b2015-03-26 18:36:35 -0700864/* Must be called with SMI lock held */
865static int _mv88e6xxx_atu_wait(struct dsa_switch *ds)
866{
Andrew Lunncca8b132015-04-02 04:06:39 +0200867 return _mv88e6xxx_wait(ds, REG_GLOBAL, GLOBAL_ATU_OP,
868 GLOBAL_ATU_OP_BUSY);
Guenter Roeckfacd95b2015-03-26 18:36:35 -0700869}
870
Andrew Lunn56d95e22015-06-20 18:42:33 +0200871/* Must be called with SMI lock held */
872static int _mv88e6xxx_scratch_wait(struct dsa_switch *ds)
873{
874 return _mv88e6xxx_wait(ds, REG_GLOBAL2, GLOBAL2_SCRATCH_MISC,
875 GLOBAL2_SCRATCH_BUSY);
876}
877
Andrew Lunn3898c142015-05-06 01:09:53 +0200878/* Must be called with SMI mutex held */
Andrew Lunnfd3a0ee2015-04-02 04:06:36 +0200879static int _mv88e6xxx_phy_read_indirect(struct dsa_switch *ds, int addr,
880 int regnum)
Andrew Lunnf3044682015-02-14 19:17:50 +0100881{
882 int ret;
883
Andrew Lunn3898c142015-05-06 01:09:53 +0200884 ret = _mv88e6xxx_reg_write(ds, REG_GLOBAL2, GLOBAL2_SMI_OP,
885 GLOBAL2_SMI_OP_22_READ | (addr << 5) |
886 regnum);
Andrew Lunnf3044682015-02-14 19:17:50 +0100887 if (ret < 0)
888 return ret;
889
Andrew Lunn3898c142015-05-06 01:09:53 +0200890 ret = _mv88e6xxx_phy_wait(ds);
891 if (ret < 0)
892 return ret;
893
894 return _mv88e6xxx_reg_read(ds, REG_GLOBAL2, GLOBAL2_SMI_DATA);
Andrew Lunnf3044682015-02-14 19:17:50 +0100895}
896
Andrew Lunn3898c142015-05-06 01:09:53 +0200897/* Must be called with SMI mutex held */
Andrew Lunnfd3a0ee2015-04-02 04:06:36 +0200898static int _mv88e6xxx_phy_write_indirect(struct dsa_switch *ds, int addr,
899 int regnum, u16 val)
Andrew Lunnf3044682015-02-14 19:17:50 +0100900{
Andrew Lunn3898c142015-05-06 01:09:53 +0200901 int ret;
Andrew Lunnf3044682015-02-14 19:17:50 +0100902
Andrew Lunn3898c142015-05-06 01:09:53 +0200903 ret = _mv88e6xxx_reg_write(ds, REG_GLOBAL2, GLOBAL2_SMI_DATA, val);
904 if (ret < 0)
905 return ret;
906
907 ret = _mv88e6xxx_reg_write(ds, REG_GLOBAL2, GLOBAL2_SMI_OP,
908 GLOBAL2_SMI_OP_22_WRITE | (addr << 5) |
909 regnum);
910
911 return _mv88e6xxx_phy_wait(ds);
Andrew Lunnf3044682015-02-14 19:17:50 +0100912}
913
Guenter Roeck11b3b452015-03-06 22:23:51 -0800914int mv88e6xxx_get_eee(struct dsa_switch *ds, int port, struct ethtool_eee *e)
915{
Andrew Lunn2f40c692015-04-02 04:06:37 +0200916 struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
Guenter Roeck11b3b452015-03-06 22:23:51 -0800917 int reg;
918
Andrew Lunn3898c142015-05-06 01:09:53 +0200919 mutex_lock(&ps->smi_mutex);
Andrew Lunn2f40c692015-04-02 04:06:37 +0200920
921 reg = _mv88e6xxx_phy_read_indirect(ds, port, 16);
Guenter Roeck11b3b452015-03-06 22:23:51 -0800922 if (reg < 0)
Andrew Lunn2f40c692015-04-02 04:06:37 +0200923 goto out;
Guenter Roeck11b3b452015-03-06 22:23:51 -0800924
925 e->eee_enabled = !!(reg & 0x0200);
926 e->tx_lpi_enabled = !!(reg & 0x0100);
927
Andrew Lunn3898c142015-05-06 01:09:53 +0200928 reg = _mv88e6xxx_reg_read(ds, REG_PORT(port), PORT_STATUS);
Guenter Roeck11b3b452015-03-06 22:23:51 -0800929 if (reg < 0)
Andrew Lunn2f40c692015-04-02 04:06:37 +0200930 goto out;
Guenter Roeck11b3b452015-03-06 22:23:51 -0800931
Andrew Lunncca8b132015-04-02 04:06:39 +0200932 e->eee_active = !!(reg & PORT_STATUS_EEE);
Andrew Lunn2f40c692015-04-02 04:06:37 +0200933 reg = 0;
Guenter Roeck11b3b452015-03-06 22:23:51 -0800934
Andrew Lunn2f40c692015-04-02 04:06:37 +0200935out:
Andrew Lunn3898c142015-05-06 01:09:53 +0200936 mutex_unlock(&ps->smi_mutex);
Andrew Lunn2f40c692015-04-02 04:06:37 +0200937 return reg;
Guenter Roeck11b3b452015-03-06 22:23:51 -0800938}
939
940int mv88e6xxx_set_eee(struct dsa_switch *ds, int port,
941 struct phy_device *phydev, struct ethtool_eee *e)
942{
Andrew Lunn2f40c692015-04-02 04:06:37 +0200943 struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
944 int reg;
Guenter Roeck11b3b452015-03-06 22:23:51 -0800945 int ret;
946
Andrew Lunn3898c142015-05-06 01:09:53 +0200947 mutex_lock(&ps->smi_mutex);
Guenter Roeck11b3b452015-03-06 22:23:51 -0800948
Andrew Lunn2f40c692015-04-02 04:06:37 +0200949 ret = _mv88e6xxx_phy_read_indirect(ds, port, 16);
950 if (ret < 0)
951 goto out;
952
953 reg = ret & ~0x0300;
954 if (e->eee_enabled)
955 reg |= 0x0200;
956 if (e->tx_lpi_enabled)
957 reg |= 0x0100;
958
959 ret = _mv88e6xxx_phy_write_indirect(ds, port, 16, reg);
960out:
Andrew Lunn3898c142015-05-06 01:09:53 +0200961 mutex_unlock(&ps->smi_mutex);
Andrew Lunn2f40c692015-04-02 04:06:37 +0200962
963 return ret;
Guenter Roeck11b3b452015-03-06 22:23:51 -0800964}
965
Guenter Roeckfacd95b2015-03-26 18:36:35 -0700966static int _mv88e6xxx_atu_cmd(struct dsa_switch *ds, int fid, u16 cmd)
967{
968 int ret;
969
Vivien Didelota08df0f2015-08-10 09:09:46 -0400970 ret = _mv88e6xxx_reg_write(ds, REG_GLOBAL, GLOBAL_ATU_FID, fid);
Guenter Roeckfacd95b2015-03-26 18:36:35 -0700971 if (ret < 0)
972 return ret;
973
Andrew Lunncca8b132015-04-02 04:06:39 +0200974 ret = _mv88e6xxx_reg_write(ds, REG_GLOBAL, GLOBAL_ATU_OP, cmd);
Guenter Roeckfacd95b2015-03-26 18:36:35 -0700975 if (ret < 0)
976 return ret;
977
978 return _mv88e6xxx_atu_wait(ds);
979}
980
981static int _mv88e6xxx_flush_fid(struct dsa_switch *ds, int fid)
982{
983 int ret;
984
985 ret = _mv88e6xxx_atu_wait(ds);
986 if (ret < 0)
987 return ret;
988
Andrew Lunncca8b132015-04-02 04:06:39 +0200989 return _mv88e6xxx_atu_cmd(ds, fid, GLOBAL_ATU_OP_FLUSH_NON_STATIC_DB);
Guenter Roeckfacd95b2015-03-26 18:36:35 -0700990}
991
992static int mv88e6xxx_set_port_state(struct dsa_switch *ds, int port, u8 state)
993{
994 struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
Geert Uytterhoevenc3ffe6d2015-04-16 20:49:14 +0200995 int reg, ret = 0;
Guenter Roeckfacd95b2015-03-26 18:36:35 -0700996 u8 oldstate;
997
998 mutex_lock(&ps->smi_mutex);
999
Andrew Lunncca8b132015-04-02 04:06:39 +02001000 reg = _mv88e6xxx_reg_read(ds, REG_PORT(port), PORT_CONTROL);
Guenter Roeck538cc282015-04-15 22:12:42 -07001001 if (reg < 0) {
1002 ret = reg;
Guenter Roeckfacd95b2015-03-26 18:36:35 -07001003 goto abort;
Guenter Roeck538cc282015-04-15 22:12:42 -07001004 }
Guenter Roeckfacd95b2015-03-26 18:36:35 -07001005
Andrew Lunncca8b132015-04-02 04:06:39 +02001006 oldstate = reg & PORT_CONTROL_STATE_MASK;
Guenter Roeckfacd95b2015-03-26 18:36:35 -07001007 if (oldstate != state) {
1008 /* Flush forwarding database if we're moving a port
1009 * from Learning or Forwarding state to Disabled or
1010 * Blocking or Listening state.
1011 */
Andrew Lunncca8b132015-04-02 04:06:39 +02001012 if (oldstate >= PORT_CONTROL_STATE_LEARNING &&
1013 state <= PORT_CONTROL_STATE_BLOCKING) {
Guenter Roeckfacd95b2015-03-26 18:36:35 -07001014 ret = _mv88e6xxx_flush_fid(ds, ps->fid[port]);
1015 if (ret)
1016 goto abort;
1017 }
Andrew Lunncca8b132015-04-02 04:06:39 +02001018 reg = (reg & ~PORT_CONTROL_STATE_MASK) | state;
1019 ret = _mv88e6xxx_reg_write(ds, REG_PORT(port), PORT_CONTROL,
1020 reg);
Guenter Roeckfacd95b2015-03-26 18:36:35 -07001021 }
1022
1023abort:
1024 mutex_unlock(&ps->smi_mutex);
1025 return ret;
1026}
1027
1028/* Must be called with smi lock held */
1029static int _mv88e6xxx_update_port_config(struct dsa_switch *ds, int port)
1030{
1031 struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
1032 u8 fid = ps->fid[port];
1033 u16 reg = fid << 12;
1034
1035 if (dsa_is_cpu_port(ds, port))
1036 reg |= ds->phys_port_mask;
1037 else
1038 reg |= (ps->bridge_mask[fid] |
1039 (1 << dsa_upstream_port(ds))) & ~(1 << port);
1040
Andrew Lunncca8b132015-04-02 04:06:39 +02001041 return _mv88e6xxx_reg_write(ds, REG_PORT(port), PORT_BASE_VLAN, reg);
Guenter Roeckfacd95b2015-03-26 18:36:35 -07001042}
1043
1044/* Must be called with smi lock held */
1045static int _mv88e6xxx_update_bridge_config(struct dsa_switch *ds, int fid)
1046{
1047 struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
1048 int port;
1049 u32 mask;
1050 int ret;
1051
1052 mask = ds->phys_port_mask;
1053 while (mask) {
1054 port = __ffs(mask);
1055 mask &= ~(1 << port);
1056 if (ps->fid[port] != fid)
1057 continue;
1058
1059 ret = _mv88e6xxx_update_port_config(ds, port);
1060 if (ret)
1061 return ret;
1062 }
1063
1064 return _mv88e6xxx_flush_fid(ds, fid);
1065}
1066
1067/* Bridge handling functions */
1068
1069int mv88e6xxx_join_bridge(struct dsa_switch *ds, int port, u32 br_port_mask)
1070{
1071 struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
1072 int ret = 0;
1073 u32 nmask;
1074 int fid;
1075
1076 /* If the bridge group is not empty, join that group.
1077 * Otherwise create a new group.
1078 */
1079 fid = ps->fid[port];
1080 nmask = br_port_mask & ~(1 << port);
1081 if (nmask)
1082 fid = ps->fid[__ffs(nmask)];
1083
1084 nmask = ps->bridge_mask[fid] | (1 << port);
1085 if (nmask != br_port_mask) {
1086 netdev_err(ds->ports[port],
1087 "join: Bridge port mask mismatch fid=%d mask=0x%x expected 0x%x\n",
1088 fid, br_port_mask, nmask);
1089 return -EINVAL;
1090 }
1091
1092 mutex_lock(&ps->smi_mutex);
1093
1094 ps->bridge_mask[fid] = br_port_mask;
1095
1096 if (fid != ps->fid[port]) {
Vivien Didelot194fea72015-08-10 09:09:47 -04001097 clear_bit(ps->fid[port], ps->fid_bitmap);
Guenter Roeckfacd95b2015-03-26 18:36:35 -07001098 ps->fid[port] = fid;
1099 ret = _mv88e6xxx_update_bridge_config(ds, fid);
1100 }
1101
1102 mutex_unlock(&ps->smi_mutex);
1103
1104 return ret;
1105}
1106
1107int mv88e6xxx_leave_bridge(struct dsa_switch *ds, int port, u32 br_port_mask)
1108{
1109 struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
1110 u8 fid, newfid;
1111 int ret;
1112
1113 fid = ps->fid[port];
1114
1115 if (ps->bridge_mask[fid] != br_port_mask) {
1116 netdev_err(ds->ports[port],
1117 "leave: Bridge port mask mismatch fid=%d mask=0x%x expected 0x%x\n",
1118 fid, br_port_mask, ps->bridge_mask[fid]);
1119 return -EINVAL;
1120 }
1121
1122 /* If the port was the last port of a bridge, we are done.
1123 * Otherwise assign a new fid to the port, and fix up
1124 * the bridge configuration.
1125 */
1126 if (br_port_mask == (1 << port))
1127 return 0;
1128
1129 mutex_lock(&ps->smi_mutex);
1130
Vivien Didelot194fea72015-08-10 09:09:47 -04001131 newfid = find_next_zero_bit(ps->fid_bitmap, VLAN_N_VID, 1);
1132 if (unlikely(newfid > ps->num_ports)) {
1133 netdev_err(ds->ports[port], "all first %d FIDs are used\n",
1134 ps->num_ports);
1135 ret = -ENOSPC;
1136 goto unlock;
1137 }
1138
Guenter Roeckfacd95b2015-03-26 18:36:35 -07001139 ps->fid[port] = newfid;
Vivien Didelot194fea72015-08-10 09:09:47 -04001140 set_bit(newfid, ps->fid_bitmap);
Guenter Roeckfacd95b2015-03-26 18:36:35 -07001141 ps->bridge_mask[fid] &= ~(1 << port);
1142 ps->bridge_mask[newfid] = 1 << port;
1143
1144 ret = _mv88e6xxx_update_bridge_config(ds, fid);
1145 if (!ret)
1146 ret = _mv88e6xxx_update_bridge_config(ds, newfid);
1147
Vivien Didelot194fea72015-08-10 09:09:47 -04001148unlock:
Guenter Roeckfacd95b2015-03-26 18:36:35 -07001149 mutex_unlock(&ps->smi_mutex);
1150
1151 return ret;
1152}
1153
1154int mv88e6xxx_port_stp_update(struct dsa_switch *ds, int port, u8 state)
1155{
1156 struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
1157 int stp_state;
1158
1159 switch (state) {
1160 case BR_STATE_DISABLED:
Andrew Lunncca8b132015-04-02 04:06:39 +02001161 stp_state = PORT_CONTROL_STATE_DISABLED;
Guenter Roeckfacd95b2015-03-26 18:36:35 -07001162 break;
1163 case BR_STATE_BLOCKING:
1164 case BR_STATE_LISTENING:
Andrew Lunncca8b132015-04-02 04:06:39 +02001165 stp_state = PORT_CONTROL_STATE_BLOCKING;
Guenter Roeckfacd95b2015-03-26 18:36:35 -07001166 break;
1167 case BR_STATE_LEARNING:
Andrew Lunncca8b132015-04-02 04:06:39 +02001168 stp_state = PORT_CONTROL_STATE_LEARNING;
Guenter Roeckfacd95b2015-03-26 18:36:35 -07001169 break;
1170 case BR_STATE_FORWARDING:
1171 default:
Andrew Lunncca8b132015-04-02 04:06:39 +02001172 stp_state = PORT_CONTROL_STATE_FORWARDING;
Guenter Roeckfacd95b2015-03-26 18:36:35 -07001173 break;
1174 }
1175
1176 netdev_dbg(ds->ports[port], "port state %d [%d]\n", state, stp_state);
1177
1178 /* mv88e6xxx_port_stp_update may be called with softirqs disabled,
1179 * so we can not update the port state directly but need to schedule it.
1180 */
1181 ps->port_state[port] = stp_state;
1182 set_bit(port, &ps->port_state_update_mask);
1183 schedule_work(&ps->bridge_work);
1184
1185 return 0;
1186}
1187
Vivien Didelotb8fee952015-08-13 12:52:19 -04001188int mv88e6xxx_port_pvid_get(struct dsa_switch *ds, int port, u16 *pvid)
1189{
1190 int ret;
1191
1192 ret = mv88e6xxx_reg_read(ds, REG_PORT(port), PORT_DEFAULT_VLAN);
1193 if (ret < 0)
1194 return ret;
1195
1196 *pvid = ret & PORT_DEFAULT_VLAN_MASK;
1197
1198 return 0;
1199}
1200
Vivien Didelot0d3b33e2015-08-13 12:52:22 -04001201int mv88e6xxx_port_pvid_set(struct dsa_switch *ds, int port, u16 pvid)
1202{
1203 return mv88e6xxx_reg_write(ds, REG_PORT(port), PORT_DEFAULT_VLAN,
1204 pvid & PORT_DEFAULT_VLAN_MASK);
1205}
1206
Vivien Didelot6b17e862015-08-13 12:52:18 -04001207static int _mv88e6xxx_vtu_wait(struct dsa_switch *ds)
1208{
1209 return _mv88e6xxx_wait(ds, REG_GLOBAL, GLOBAL_VTU_OP,
1210 GLOBAL_VTU_OP_BUSY);
1211}
1212
1213static int _mv88e6xxx_vtu_cmd(struct dsa_switch *ds, u16 op)
1214{
1215 int ret;
1216
1217 ret = _mv88e6xxx_reg_write(ds, REG_GLOBAL, GLOBAL_VTU_OP, op);
1218 if (ret < 0)
1219 return ret;
1220
1221 return _mv88e6xxx_vtu_wait(ds);
1222}
1223
1224static int _mv88e6xxx_vtu_stu_flush(struct dsa_switch *ds)
1225{
1226 int ret;
1227
1228 ret = _mv88e6xxx_vtu_wait(ds);
1229 if (ret < 0)
1230 return ret;
1231
1232 return _mv88e6xxx_vtu_cmd(ds, GLOBAL_VTU_OP_FLUSH_ALL);
1233}
1234
Vivien Didelotb8fee952015-08-13 12:52:19 -04001235static int _mv88e6xxx_vtu_stu_data_read(struct dsa_switch *ds,
1236 struct mv88e6xxx_vtu_stu_entry *entry,
1237 unsigned int nibble_offset)
1238{
1239 struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
1240 u16 regs[3];
1241 int i;
1242 int ret;
1243
1244 for (i = 0; i < 3; ++i) {
1245 ret = _mv88e6xxx_reg_read(ds, REG_GLOBAL,
1246 GLOBAL_VTU_DATA_0_3 + i);
1247 if (ret < 0)
1248 return ret;
1249
1250 regs[i] = ret;
1251 }
1252
1253 for (i = 0; i < ps->num_ports; ++i) {
1254 unsigned int shift = (i % 4) * 4 + nibble_offset;
1255 u16 reg = regs[i / 4];
1256
1257 entry->data[i] = (reg >> shift) & GLOBAL_VTU_STU_DATA_MASK;
1258 }
1259
1260 return 0;
1261}
1262
Vivien Didelot7dad08d2015-08-13 12:52:21 -04001263static int _mv88e6xxx_vtu_stu_data_write(struct dsa_switch *ds,
1264 struct mv88e6xxx_vtu_stu_entry *entry,
1265 unsigned int nibble_offset)
1266{
1267 struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
1268 u16 regs[3] = { 0 };
1269 int i;
1270 int ret;
1271
1272 for (i = 0; i < ps->num_ports; ++i) {
1273 unsigned int shift = (i % 4) * 4 + nibble_offset;
1274 u8 data = entry->data[i];
1275
1276 regs[i / 4] |= (data & GLOBAL_VTU_STU_DATA_MASK) << shift;
1277 }
1278
1279 for (i = 0; i < 3; ++i) {
1280 ret = _mv88e6xxx_reg_write(ds, REG_GLOBAL,
1281 GLOBAL_VTU_DATA_0_3 + i, regs[i]);
1282 if (ret < 0)
1283 return ret;
1284 }
1285
1286 return 0;
1287}
1288
Vivien Didelotb8fee952015-08-13 12:52:19 -04001289static int _mv88e6xxx_vtu_getnext(struct dsa_switch *ds, u16 vid,
1290 struct mv88e6xxx_vtu_stu_entry *entry)
1291{
1292 struct mv88e6xxx_vtu_stu_entry next = { 0 };
1293 int ret;
1294
1295 ret = _mv88e6xxx_vtu_wait(ds);
1296 if (ret < 0)
1297 return ret;
1298
1299 ret = _mv88e6xxx_reg_write(ds, REG_GLOBAL, GLOBAL_VTU_VID,
1300 vid & GLOBAL_VTU_VID_MASK);
1301 if (ret < 0)
1302 return ret;
1303
1304 ret = _mv88e6xxx_vtu_cmd(ds, GLOBAL_VTU_OP_VTU_GET_NEXT);
1305 if (ret < 0)
1306 return ret;
1307
1308 ret = _mv88e6xxx_reg_read(ds, REG_GLOBAL, GLOBAL_VTU_VID);
1309 if (ret < 0)
1310 return ret;
1311
1312 next.vid = ret & GLOBAL_VTU_VID_MASK;
1313 next.valid = !!(ret & GLOBAL_VTU_VID_VALID);
1314
1315 if (next.valid) {
1316 ret = _mv88e6xxx_vtu_stu_data_read(ds, &next, 0);
1317 if (ret < 0)
1318 return ret;
1319
1320 if (mv88e6xxx_6097_family(ds) || mv88e6xxx_6165_family(ds) ||
1321 mv88e6xxx_6351_family(ds) || mv88e6xxx_6352_family(ds)) {
1322 ret = _mv88e6xxx_reg_read(ds, REG_GLOBAL,
1323 GLOBAL_VTU_FID);
1324 if (ret < 0)
1325 return ret;
1326
1327 next.fid = ret & GLOBAL_VTU_FID_MASK;
1328
1329 ret = _mv88e6xxx_reg_read(ds, REG_GLOBAL,
1330 GLOBAL_VTU_SID);
1331 if (ret < 0)
1332 return ret;
1333
1334 next.sid = ret & GLOBAL_VTU_SID_MASK;
1335 }
1336 }
1337
1338 *entry = next;
1339 return 0;
1340}
1341
Vivien Didelot7dad08d2015-08-13 12:52:21 -04001342static int _mv88e6xxx_vtu_loadpurge(struct dsa_switch *ds,
1343 struct mv88e6xxx_vtu_stu_entry *entry)
1344{
1345 u16 reg = 0;
1346 int ret;
1347
1348 ret = _mv88e6xxx_vtu_wait(ds);
1349 if (ret < 0)
1350 return ret;
1351
1352 if (!entry->valid)
1353 goto loadpurge;
1354
1355 /* Write port member tags */
1356 ret = _mv88e6xxx_vtu_stu_data_write(ds, entry, 0);
1357 if (ret < 0)
1358 return ret;
1359
1360 if (mv88e6xxx_6097_family(ds) || mv88e6xxx_6165_family(ds) ||
1361 mv88e6xxx_6351_family(ds) || mv88e6xxx_6352_family(ds)) {
1362 reg = entry->sid & GLOBAL_VTU_SID_MASK;
1363 ret = _mv88e6xxx_reg_write(ds, REG_GLOBAL, GLOBAL_VTU_SID, reg);
1364 if (ret < 0)
1365 return ret;
1366
1367 reg = entry->fid & GLOBAL_VTU_FID_MASK;
1368 ret = _mv88e6xxx_reg_write(ds, REG_GLOBAL, GLOBAL_VTU_FID, reg);
1369 if (ret < 0)
1370 return ret;
1371 }
1372
1373 reg = GLOBAL_VTU_VID_VALID;
1374loadpurge:
1375 reg |= entry->vid & GLOBAL_VTU_VID_MASK;
1376 ret = _mv88e6xxx_reg_write(ds, REG_GLOBAL, GLOBAL_VTU_VID, reg);
1377 if (ret < 0)
1378 return ret;
1379
1380 return _mv88e6xxx_vtu_cmd(ds, GLOBAL_VTU_OP_VTU_LOAD_PURGE);
1381}
1382
Vivien Didelot0d3b33e2015-08-13 12:52:22 -04001383static int _mv88e6xxx_stu_getnext(struct dsa_switch *ds, u8 sid,
1384 struct mv88e6xxx_vtu_stu_entry *entry)
1385{
1386 struct mv88e6xxx_vtu_stu_entry next = { 0 };
1387 int ret;
1388
1389 ret = _mv88e6xxx_vtu_wait(ds);
1390 if (ret < 0)
1391 return ret;
1392
1393 ret = _mv88e6xxx_reg_write(ds, REG_GLOBAL, GLOBAL_VTU_SID,
1394 sid & GLOBAL_VTU_SID_MASK);
1395 if (ret < 0)
1396 return ret;
1397
1398 ret = _mv88e6xxx_vtu_cmd(ds, GLOBAL_VTU_OP_STU_GET_NEXT);
1399 if (ret < 0)
1400 return ret;
1401
1402 ret = _mv88e6xxx_reg_read(ds, REG_GLOBAL, GLOBAL_VTU_SID);
1403 if (ret < 0)
1404 return ret;
1405
1406 next.sid = ret & GLOBAL_VTU_SID_MASK;
1407
1408 ret = _mv88e6xxx_reg_read(ds, REG_GLOBAL, GLOBAL_VTU_VID);
1409 if (ret < 0)
1410 return ret;
1411
1412 next.valid = !!(ret & GLOBAL_VTU_VID_VALID);
1413
1414 if (next.valid) {
1415 ret = _mv88e6xxx_vtu_stu_data_read(ds, &next, 2);
1416 if (ret < 0)
1417 return ret;
1418 }
1419
1420 *entry = next;
1421 return 0;
1422}
1423
1424static int _mv88e6xxx_stu_loadpurge(struct dsa_switch *ds,
1425 struct mv88e6xxx_vtu_stu_entry *entry)
1426{
1427 u16 reg = 0;
1428 int ret;
1429
1430 ret = _mv88e6xxx_vtu_wait(ds);
1431 if (ret < 0)
1432 return ret;
1433
1434 if (!entry->valid)
1435 goto loadpurge;
1436
1437 /* Write port states */
1438 ret = _mv88e6xxx_vtu_stu_data_write(ds, entry, 2);
1439 if (ret < 0)
1440 return ret;
1441
1442 reg = GLOBAL_VTU_VID_VALID;
1443loadpurge:
1444 ret = _mv88e6xxx_reg_write(ds, REG_GLOBAL, GLOBAL_VTU_VID, reg);
1445 if (ret < 0)
1446 return ret;
1447
1448 reg = entry->sid & GLOBAL_VTU_SID_MASK;
1449 ret = _mv88e6xxx_reg_write(ds, REG_GLOBAL, GLOBAL_VTU_SID, reg);
1450 if (ret < 0)
1451 return ret;
1452
1453 return _mv88e6xxx_vtu_cmd(ds, GLOBAL_VTU_OP_STU_LOAD_PURGE);
1454}
1455
1456static int _mv88e6xxx_vlan_init(struct dsa_switch *ds, u16 vid,
1457 struct mv88e6xxx_vtu_stu_entry *entry)
1458{
1459 struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
1460 struct mv88e6xxx_vtu_stu_entry vlan = {
1461 .valid = true,
1462 .vid = vid,
1463 };
1464 int i;
1465
1466 /* exclude all ports except the CPU */
1467 for (i = 0; i < ps->num_ports; ++i)
1468 vlan.data[i] = dsa_is_cpu_port(ds, i) ?
1469 GLOBAL_VTU_DATA_MEMBER_TAG_TAGGED :
1470 GLOBAL_VTU_DATA_MEMBER_TAG_NON_MEMBER;
1471
1472 if (mv88e6xxx_6097_family(ds) || mv88e6xxx_6165_family(ds) ||
1473 mv88e6xxx_6351_family(ds) || mv88e6xxx_6352_family(ds)) {
1474 struct mv88e6xxx_vtu_stu_entry vstp;
1475 int err;
1476
1477 /* Adding a VTU entry requires a valid STU entry. As VSTP is not
1478 * implemented, only one STU entry is needed to cover all VTU
1479 * entries. Thus, validate the SID 0.
1480 */
1481 vlan.sid = 0;
1482 err = _mv88e6xxx_stu_getnext(ds, GLOBAL_VTU_SID_MASK, &vstp);
1483 if (err)
1484 return err;
1485
1486 if (vstp.sid != vlan.sid || !vstp.valid) {
1487 memset(&vstp, 0, sizeof(vstp));
1488 vstp.valid = true;
1489 vstp.sid = vlan.sid;
1490
1491 err = _mv88e6xxx_stu_loadpurge(ds, &vstp);
1492 if (err)
1493 return err;
1494 }
1495
1496 /* Non-bridged ports and bridge groups use FIDs from 1 to
1497 * num_ports; VLANs use FIDs from num_ports+1 to 4095.
1498 */
1499 vlan.fid = find_next_zero_bit(ps->fid_bitmap, VLAN_N_VID,
1500 ps->num_ports + 1);
1501 if (unlikely(vlan.fid == VLAN_N_VID)) {
1502 pr_err("no more FID available for VLAN %d\n", vid);
1503 return -ENOSPC;
1504 }
1505
1506 err = _mv88e6xxx_flush_fid(ds, vlan.fid);
1507 if (err)
1508 return err;
1509
1510 set_bit(vlan.fid, ps->fid_bitmap);
1511 }
1512
1513 *entry = vlan;
1514 return 0;
1515}
1516
1517int mv88e6xxx_port_vlan_add(struct dsa_switch *ds, int port, u16 vid,
1518 bool untagged)
1519{
1520 struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
1521 struct mv88e6xxx_vtu_stu_entry vlan;
1522 int err;
1523
1524 mutex_lock(&ps->smi_mutex);
1525 err = _mv88e6xxx_vtu_getnext(ds, vid - 1, &vlan);
1526 if (err)
1527 goto unlock;
1528
1529 if (vlan.vid != vid || !vlan.valid) {
1530 err = _mv88e6xxx_vlan_init(ds, vid, &vlan);
1531 if (err)
1532 goto unlock;
1533 }
1534
1535 vlan.data[port] = untagged ?
1536 GLOBAL_VTU_DATA_MEMBER_TAG_UNTAGGED :
1537 GLOBAL_VTU_DATA_MEMBER_TAG_TAGGED;
1538
1539 err = _mv88e6xxx_vtu_loadpurge(ds, &vlan);
1540unlock:
1541 mutex_unlock(&ps->smi_mutex);
1542
1543 return err;
1544}
1545
Vivien Didelot7dad08d2015-08-13 12:52:21 -04001546int mv88e6xxx_port_vlan_del(struct dsa_switch *ds, int port, u16 vid)
1547{
1548 struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
1549 struct mv88e6xxx_vtu_stu_entry vlan;
1550 bool keep = false;
1551 int i, err;
1552
1553 mutex_lock(&ps->smi_mutex);
1554
1555 err = _mv88e6xxx_vtu_getnext(ds, vid - 1, &vlan);
1556 if (err)
1557 goto unlock;
1558
1559 if (vlan.vid != vid || !vlan.valid ||
1560 vlan.data[port] == GLOBAL_VTU_DATA_MEMBER_TAG_NON_MEMBER) {
1561 err = -ENOENT;
1562 goto unlock;
1563 }
1564
1565 vlan.data[port] = GLOBAL_VTU_DATA_MEMBER_TAG_NON_MEMBER;
1566
1567 /* keep the VLAN unless all ports are excluded */
1568 for (i = 0; i < ps->num_ports; ++i) {
1569 if (dsa_is_cpu_port(ds, i))
1570 continue;
1571
1572 if (vlan.data[i] != GLOBAL_VTU_DATA_MEMBER_TAG_NON_MEMBER) {
1573 keep = true;
1574 break;
1575 }
1576 }
1577
1578 vlan.valid = keep;
1579 err = _mv88e6xxx_vtu_loadpurge(ds, &vlan);
1580 if (err)
1581 goto unlock;
1582
1583 if (!keep)
1584 clear_bit(vlan.fid, ps->fid_bitmap);
1585
1586unlock:
1587 mutex_unlock(&ps->smi_mutex);
1588
1589 return err;
1590}
1591
Vivien Didelot02512b62015-08-13 12:52:20 -04001592static int _mv88e6xxx_port_vtu_getnext(struct dsa_switch *ds, int port, u16 vid,
1593 struct mv88e6xxx_vtu_stu_entry *entry)
1594{
1595 int err;
1596
1597 do {
1598 if (vid == 4095)
1599 return -ENOENT;
1600
1601 err = _mv88e6xxx_vtu_getnext(ds, vid, entry);
1602 if (err)
1603 return err;
1604
1605 if (!entry->valid)
1606 return -ENOENT;
1607
1608 vid = entry->vid;
1609 } while (entry->data[port] != GLOBAL_VTU_DATA_MEMBER_TAG_TAGGED &&
1610 entry->data[port] != GLOBAL_VTU_DATA_MEMBER_TAG_UNTAGGED);
1611
1612 return 0;
1613}
1614
Vivien Didelotb8fee952015-08-13 12:52:19 -04001615int mv88e6xxx_vlan_getnext(struct dsa_switch *ds, u16 *vid,
1616 unsigned long *ports, unsigned long *untagged)
1617{
1618 struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
1619 struct mv88e6xxx_vtu_stu_entry next;
1620 int port;
1621 int err;
1622
1623 if (*vid == 4095)
1624 return -ENOENT;
1625
1626 mutex_lock(&ps->smi_mutex);
1627 err = _mv88e6xxx_vtu_getnext(ds, *vid, &next);
1628 mutex_unlock(&ps->smi_mutex);
1629
1630 if (err)
1631 return err;
1632
1633 if (!next.valid)
1634 return -ENOENT;
1635
1636 *vid = next.vid;
1637
1638 for (port = 0; port < ps->num_ports; ++port) {
1639 clear_bit(port, ports);
1640 clear_bit(port, untagged);
1641
1642 if (dsa_is_cpu_port(ds, port))
1643 continue;
1644
1645 if (next.data[port] == GLOBAL_VTU_DATA_MEMBER_TAG_TAGGED ||
1646 next.data[port] == GLOBAL_VTU_DATA_MEMBER_TAG_UNTAGGED)
1647 set_bit(port, ports);
1648
1649 if (next.data[port] == GLOBAL_VTU_DATA_MEMBER_TAG_UNTAGGED)
1650 set_bit(port, untagged);
1651 }
1652
1653 return 0;
1654}
1655
Vivien Didelotc5723ac2015-08-10 09:09:48 -04001656static int _mv88e6xxx_atu_mac_write(struct dsa_switch *ds,
1657 const unsigned char *addr)
Guenter Roeckdefb05b2015-03-26 18:36:38 -07001658{
1659 int i, ret;
1660
1661 for (i = 0; i < 3; i++) {
Andrew Lunncca8b132015-04-02 04:06:39 +02001662 ret = _mv88e6xxx_reg_write(
1663 ds, REG_GLOBAL, GLOBAL_ATU_MAC_01 + i,
1664 (addr[i * 2] << 8) | addr[i * 2 + 1]);
Guenter Roeckdefb05b2015-03-26 18:36:38 -07001665 if (ret < 0)
1666 return ret;
1667 }
1668
1669 return 0;
1670}
1671
Vivien Didelotc5723ac2015-08-10 09:09:48 -04001672static int _mv88e6xxx_atu_mac_read(struct dsa_switch *ds, unsigned char *addr)
Guenter Roeckdefb05b2015-03-26 18:36:38 -07001673{
1674 int i, ret;
1675
1676 for (i = 0; i < 3; i++) {
Andrew Lunncca8b132015-04-02 04:06:39 +02001677 ret = _mv88e6xxx_reg_read(ds, REG_GLOBAL,
1678 GLOBAL_ATU_MAC_01 + i);
Guenter Roeckdefb05b2015-03-26 18:36:38 -07001679 if (ret < 0)
1680 return ret;
1681 addr[i * 2] = ret >> 8;
1682 addr[i * 2 + 1] = ret & 0xff;
1683 }
1684
1685 return 0;
1686}
1687
Vivien Didelotfd231c82015-08-10 09:09:50 -04001688static int _mv88e6xxx_atu_load(struct dsa_switch *ds,
1689 struct mv88e6xxx_atu_entry *entry)
Guenter Roeckdefb05b2015-03-26 18:36:38 -07001690{
Vivien Didelotfd231c82015-08-10 09:09:50 -04001691 u16 reg = 0;
Guenter Roeckdefb05b2015-03-26 18:36:38 -07001692 int ret;
1693
1694 ret = _mv88e6xxx_atu_wait(ds);
1695 if (ret < 0)
1696 return ret;
1697
Vivien Didelotfd231c82015-08-10 09:09:50 -04001698 ret = _mv88e6xxx_atu_mac_write(ds, entry->mac);
Guenter Roeckdefb05b2015-03-26 18:36:38 -07001699 if (ret < 0)
1700 return ret;
1701
Vivien Didelotfd231c82015-08-10 09:09:50 -04001702 if (entry->state != GLOBAL_ATU_DATA_STATE_UNUSED) {
1703 unsigned int mask, shift;
1704
1705 if (entry->trunk) {
1706 reg |= GLOBAL_ATU_DATA_TRUNK;
1707 mask = GLOBAL_ATU_DATA_TRUNK_ID_MASK;
1708 shift = GLOBAL_ATU_DATA_TRUNK_ID_SHIFT;
1709 } else {
1710 mask = GLOBAL_ATU_DATA_PORT_VECTOR_MASK;
1711 shift = GLOBAL_ATU_DATA_PORT_VECTOR_SHIFT;
1712 }
1713
1714 reg |= (entry->portv_trunkid << shift) & mask;
1715 }
1716
1717 reg |= entry->state & GLOBAL_ATU_DATA_STATE_MASK;
1718
1719 ret = _mv88e6xxx_reg_write(ds, REG_GLOBAL, GLOBAL_ATU_DATA, reg);
1720 if (ret < 0)
Guenter Roeckdefb05b2015-03-26 18:36:38 -07001721 return ret;
1722
Vivien Didelotfd231c82015-08-10 09:09:50 -04001723 return _mv88e6xxx_atu_cmd(ds, entry->fid, GLOBAL_ATU_OP_LOAD_DB);
1724}
David S. Millercdf09692015-08-11 12:00:37 -07001725
Vivien Didelotfd231c82015-08-10 09:09:50 -04001726static int _mv88e6xxx_port_vid_to_fid(struct dsa_switch *ds, int port, u16 vid)
1727{
1728 struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
Vivien Didelot02512b62015-08-13 12:52:20 -04001729 struct mv88e6xxx_vtu_stu_entry vlan;
1730 int err;
Vivien Didelotfd231c82015-08-10 09:09:50 -04001731
1732 if (vid == 0)
1733 return ps->fid[port];
1734
Vivien Didelot02512b62015-08-13 12:52:20 -04001735 err = _mv88e6xxx_port_vtu_getnext(ds, port, vid - 1, &vlan);
1736 if (err)
1737 return err;
1738
1739 if (vlan.vid == vid)
1740 return vlan.fid;
1741
Vivien Didelotfd231c82015-08-10 09:09:50 -04001742 return -ENOENT;
1743}
1744
1745static int _mv88e6xxx_port_fdb_load(struct dsa_switch *ds, int port,
1746 const unsigned char *addr, u16 vid,
1747 u8 state)
1748{
1749 struct mv88e6xxx_atu_entry entry = { 0 };
1750 int ret;
1751
1752 ret = _mv88e6xxx_port_vid_to_fid(ds, port, vid);
1753 if (ret < 0)
1754 return ret;
1755
1756 entry.fid = ret;
1757 entry.state = state;
1758 ether_addr_copy(entry.mac, addr);
1759 if (state != GLOBAL_ATU_DATA_STATE_UNUSED) {
1760 entry.trunk = false;
1761 entry.portv_trunkid = BIT(port);
1762 }
1763
1764 return _mv88e6xxx_atu_load(ds, &entry);
Guenter Roeckdefb05b2015-03-26 18:36:38 -07001765}
1766
David S. Millercdf09692015-08-11 12:00:37 -07001767int mv88e6xxx_port_fdb_add(struct dsa_switch *ds, int port,
1768 const unsigned char *addr, u16 vid)
Guenter Roeckdefb05b2015-03-26 18:36:38 -07001769{
David S. Millercdf09692015-08-11 12:00:37 -07001770 int state = is_multicast_ether_addr(addr) ?
1771 GLOBAL_ATU_DATA_STATE_MC_STATIC :
1772 GLOBAL_ATU_DATA_STATE_UC_STATIC;
1773 struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
Vivien Didelot6630e232015-08-06 01:44:07 -04001774 int ret;
1775
David S. Millercdf09692015-08-11 12:00:37 -07001776 mutex_lock(&ps->smi_mutex);
Vivien Didelotfd231c82015-08-10 09:09:50 -04001777 ret = _mv88e6xxx_port_fdb_load(ds, port, addr, vid, state);
David S. Millercdf09692015-08-11 12:00:37 -07001778 mutex_unlock(&ps->smi_mutex);
1779
1780 return ret;
1781}
1782
1783int mv88e6xxx_port_fdb_del(struct dsa_switch *ds, int port,
1784 const unsigned char *addr, u16 vid)
1785{
1786 struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
1787 int ret;
1788
1789 mutex_lock(&ps->smi_mutex);
Vivien Didelotfd231c82015-08-10 09:09:50 -04001790 ret = _mv88e6xxx_port_fdb_load(ds, port, addr, vid,
David S. Millercdf09692015-08-11 12:00:37 -07001791 GLOBAL_ATU_DATA_STATE_UNUSED);
1792 mutex_unlock(&ps->smi_mutex);
1793
1794 return ret;
1795}
1796
Vivien Didelot1d194042015-08-10 09:09:51 -04001797static int _mv88e6xxx_atu_getnext(struct dsa_switch *ds, u16 fid,
1798 const unsigned char *addr,
1799 struct mv88e6xxx_atu_entry *entry)
David S. Millercdf09692015-08-11 12:00:37 -07001800{
Vivien Didelot1d194042015-08-10 09:09:51 -04001801 struct mv88e6xxx_atu_entry next = { 0 };
1802 int ret;
1803
1804 next.fid = fid;
Guenter Roeckdefb05b2015-03-26 18:36:38 -07001805
1806 ret = _mv88e6xxx_atu_wait(ds);
1807 if (ret < 0)
1808 return ret;
1809
Vivien Didelotc5723ac2015-08-10 09:09:48 -04001810 ret = _mv88e6xxx_atu_mac_write(ds, addr);
Guenter Roeckdefb05b2015-03-26 18:36:38 -07001811 if (ret < 0)
1812 return ret;
1813
Vivien Didelot1d194042015-08-10 09:09:51 -04001814 ret = _mv88e6xxx_atu_cmd(ds, fid, GLOBAL_ATU_OP_GET_NEXT_DB);
Guenter Roeckdefb05b2015-03-26 18:36:38 -07001815 if (ret < 0)
1816 return ret;
1817
Vivien Didelot1d194042015-08-10 09:09:51 -04001818 ret = _mv88e6xxx_atu_mac_read(ds, next.mac);
1819 if (ret < 0)
1820 return ret;
Guenter Roeckdefb05b2015-03-26 18:36:38 -07001821
Vivien Didelot1d194042015-08-10 09:09:51 -04001822 ret = _mv88e6xxx_reg_read(ds, REG_GLOBAL, GLOBAL_ATU_DATA);
1823 if (ret < 0)
1824 return ret;
1825
1826 next.state = ret & GLOBAL_ATU_DATA_STATE_MASK;
1827 if (next.state != GLOBAL_ATU_DATA_STATE_UNUSED) {
1828 unsigned int mask, shift;
1829
1830 if (ret & GLOBAL_ATU_DATA_TRUNK) {
1831 next.trunk = true;
1832 mask = GLOBAL_ATU_DATA_TRUNK_ID_MASK;
1833 shift = GLOBAL_ATU_DATA_TRUNK_ID_SHIFT;
1834 } else {
1835 next.trunk = false;
1836 mask = GLOBAL_ATU_DATA_PORT_VECTOR_MASK;
1837 shift = GLOBAL_ATU_DATA_PORT_VECTOR_SHIFT;
1838 }
1839
1840 next.portv_trunkid = (ret & mask) >> shift;
1841 }
1842
1843 *entry = next;
Guenter Roeckdefb05b2015-03-26 18:36:38 -07001844 return 0;
1845}
1846
David S. Millercdf09692015-08-11 12:00:37 -07001847/* get next entry for port */
1848int mv88e6xxx_port_fdb_getnext(struct dsa_switch *ds, int port,
Vivien Didelot2a778e12015-08-10 09:09:49 -04001849 unsigned char *addr, u16 *vid, bool *is_static)
Guenter Roeckdefb05b2015-03-26 18:36:38 -07001850{
1851 struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
Vivien Didelot1d194042015-08-10 09:09:51 -04001852 struct mv88e6xxx_atu_entry next;
1853 u16 fid;
Vivien Didelot87820512015-08-06 01:44:08 -04001854 int ret;
1855
1856 mutex_lock(&ps->smi_mutex);
Vivien Didelot1d194042015-08-10 09:09:51 -04001857
1858 ret = _mv88e6xxx_port_vid_to_fid(ds, port, *vid);
1859 if (ret < 0)
1860 goto unlock;
1861 fid = ret;
1862
1863 do {
1864 if (is_broadcast_ether_addr(addr)) {
Vivien Didelot02512b62015-08-13 12:52:20 -04001865 struct mv88e6xxx_vtu_stu_entry vtu;
1866
1867 ret = _mv88e6xxx_port_vtu_getnext(ds, port, *vid, &vtu);
1868 if (ret < 0)
1869 goto unlock;
1870
1871 *vid = vtu.vid;
1872 fid = vtu.fid;
Vivien Didelot1d194042015-08-10 09:09:51 -04001873 }
1874
1875 ret = _mv88e6xxx_atu_getnext(ds, fid, addr, &next);
1876 if (ret < 0)
1877 goto unlock;
1878
1879 ether_addr_copy(addr, next.mac);
1880
1881 if (next.state == GLOBAL_ATU_DATA_STATE_UNUSED)
1882 continue;
1883 } while (next.trunk || (next.portv_trunkid & BIT(port)) == 0);
1884
1885 *is_static = next.state == (is_multicast_ether_addr(addr) ?
1886 GLOBAL_ATU_DATA_STATE_MC_STATIC :
1887 GLOBAL_ATU_DATA_STATE_UC_STATIC);
1888unlock:
Guenter Roeckdefb05b2015-03-26 18:36:38 -07001889 mutex_unlock(&ps->smi_mutex);
1890
1891 return ret;
1892}
1893
Guenter Roeckfacd95b2015-03-26 18:36:35 -07001894static void mv88e6xxx_bridge_work(struct work_struct *work)
1895{
1896 struct mv88e6xxx_priv_state *ps;
1897 struct dsa_switch *ds;
1898 int port;
1899
1900 ps = container_of(work, struct mv88e6xxx_priv_state, bridge_work);
1901 ds = ((struct dsa_switch *)ps) - 1;
1902
1903 while (ps->port_state_update_mask) {
1904 port = __ffs(ps->port_state_update_mask);
1905 clear_bit(port, &ps->port_state_update_mask);
1906 mv88e6xxx_set_port_state(ds, port, ps->port_state[port]);
1907 }
1908}
1909
Andrew Lunndbde9e62015-05-06 01:09:48 +02001910static int mv88e6xxx_setup_port(struct dsa_switch *ds, int port)
Guenter Roeckd827e882015-03-26 18:36:29 -07001911{
1912 struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
Guenter Roeckfacd95b2015-03-26 18:36:35 -07001913 int ret, fid;
Andrew Lunn54d792f2015-05-06 01:09:47 +02001914 u16 reg;
Guenter Roeckd827e882015-03-26 18:36:29 -07001915
1916 mutex_lock(&ps->smi_mutex);
1917
Andrew Lunn54d792f2015-05-06 01:09:47 +02001918 if (mv88e6xxx_6352_family(ds) || mv88e6xxx_6351_family(ds) ||
1919 mv88e6xxx_6165_family(ds) || mv88e6xxx_6097_family(ds) ||
1920 mv88e6xxx_6185_family(ds) || mv88e6xxx_6095_family(ds) ||
Aleksey S. Kazantsev7c3d0d62015-07-07 20:38:15 -07001921 mv88e6xxx_6065_family(ds) || mv88e6xxx_6320_family(ds)) {
Andrew Lunn54d792f2015-05-06 01:09:47 +02001922 /* MAC Forcing register: don't force link, speed,
1923 * duplex or flow control state to any particular
1924 * values on physical ports, but force the CPU port
1925 * and all DSA ports to their maximum bandwidth and
1926 * full duplex.
1927 */
1928 reg = _mv88e6xxx_reg_read(ds, REG_PORT(port), PORT_PCS_CTRL);
Andrew Lunn60045cb2015-08-17 23:52:51 +02001929 if (dsa_is_cpu_port(ds, port) || dsa_is_dsa_port(ds, port)) {
Andrew Lunn54d792f2015-05-06 01:09:47 +02001930 reg |= PORT_PCS_CTRL_FORCE_LINK |
1931 PORT_PCS_CTRL_LINK_UP |
1932 PORT_PCS_CTRL_DUPLEX_FULL |
1933 PORT_PCS_CTRL_FORCE_DUPLEX;
1934 if (mv88e6xxx_6065_family(ds))
1935 reg |= PORT_PCS_CTRL_100;
1936 else
1937 reg |= PORT_PCS_CTRL_1000;
1938 } else {
1939 reg |= PORT_PCS_CTRL_UNFORCED;
1940 }
1941
1942 ret = _mv88e6xxx_reg_write(ds, REG_PORT(port),
1943 PORT_PCS_CTRL, reg);
1944 if (ret)
1945 goto abort;
1946 }
1947
1948 /* Port Control: disable Drop-on-Unlock, disable Drop-on-Lock,
1949 * disable Header mode, enable IGMP/MLD snooping, disable VLAN
1950 * tunneling, determine priority by looking at 802.1p and IP
1951 * priority fields (IP prio has precedence), and set STP state
1952 * to Forwarding.
1953 *
1954 * If this is the CPU link, use DSA or EDSA tagging depending
1955 * on which tagging mode was configured.
1956 *
1957 * If this is a link to another switch, use DSA tagging mode.
1958 *
1959 * If this is the upstream port for this switch, enable
1960 * forwarding of unknown unicasts and multicasts.
1961 */
1962 reg = 0;
1963 if (mv88e6xxx_6352_family(ds) || mv88e6xxx_6351_family(ds) ||
1964 mv88e6xxx_6165_family(ds) || mv88e6xxx_6097_family(ds) ||
1965 mv88e6xxx_6095_family(ds) || mv88e6xxx_6065_family(ds) ||
Aleksey S. Kazantsev7c3d0d62015-07-07 20:38:15 -07001966 mv88e6xxx_6185_family(ds) || mv88e6xxx_6320_family(ds))
Andrew Lunn54d792f2015-05-06 01:09:47 +02001967 reg = PORT_CONTROL_IGMP_MLD_SNOOP |
1968 PORT_CONTROL_USE_TAG | PORT_CONTROL_USE_IP |
1969 PORT_CONTROL_STATE_FORWARDING;
1970 if (dsa_is_cpu_port(ds, port)) {
1971 if (mv88e6xxx_6095_family(ds) || mv88e6xxx_6185_family(ds))
1972 reg |= PORT_CONTROL_DSA_TAG;
1973 if (mv88e6xxx_6352_family(ds) || mv88e6xxx_6351_family(ds) ||
Aleksey S. Kazantsev7c3d0d62015-07-07 20:38:15 -07001974 mv88e6xxx_6165_family(ds) || mv88e6xxx_6097_family(ds) ||
1975 mv88e6xxx_6320_family(ds)) {
Andrew Lunn54d792f2015-05-06 01:09:47 +02001976 if (ds->dst->tag_protocol == DSA_TAG_PROTO_EDSA)
1977 reg |= PORT_CONTROL_FRAME_ETHER_TYPE_DSA;
1978 else
1979 reg |= PORT_CONTROL_FRAME_MODE_DSA;
1980 }
1981
1982 if (mv88e6xxx_6352_family(ds) || mv88e6xxx_6351_family(ds) ||
1983 mv88e6xxx_6165_family(ds) || mv88e6xxx_6097_family(ds) ||
1984 mv88e6xxx_6095_family(ds) || mv88e6xxx_6065_family(ds) ||
Aleksey S. Kazantsev7c3d0d62015-07-07 20:38:15 -07001985 mv88e6xxx_6185_family(ds) || mv88e6xxx_6320_family(ds)) {
Andrew Lunn54d792f2015-05-06 01:09:47 +02001986 if (ds->dst->tag_protocol == DSA_TAG_PROTO_EDSA)
1987 reg |= PORT_CONTROL_EGRESS_ADD_TAG;
1988 }
1989 }
Andrew Lunn6083ce72015-08-17 23:52:52 +02001990 if (dsa_is_dsa_port(ds, port)) {
1991 if (mv88e6xxx_6095_family(ds) || mv88e6xxx_6185_family(ds))
1992 reg |= PORT_CONTROL_DSA_TAG;
1993 if (mv88e6xxx_6352_family(ds) || mv88e6xxx_6351_family(ds) ||
1994 mv88e6xxx_6165_family(ds) || mv88e6xxx_6097_family(ds) ||
1995 mv88e6xxx_6320_family(ds)) {
Andrew Lunn54d792f2015-05-06 01:09:47 +02001996 reg |= PORT_CONTROL_FRAME_MODE_DSA;
Andrew Lunn6083ce72015-08-17 23:52:52 +02001997 }
1998
Andrew Lunn54d792f2015-05-06 01:09:47 +02001999 if (port == dsa_upstream_port(ds))
2000 reg |= PORT_CONTROL_FORWARD_UNKNOWN |
2001 PORT_CONTROL_FORWARD_UNKNOWN_MC;
2002 }
2003 if (reg) {
2004 ret = _mv88e6xxx_reg_write(ds, REG_PORT(port),
2005 PORT_CONTROL, reg);
2006 if (ret)
2007 goto abort;
2008 }
2009
Vivien Didelot8efdda42015-08-13 12:52:23 -04002010 /* Port Control 2: don't force a good FCS, set the maximum frame size to
2011 * 10240 bytes, enable secure 802.1q tags, don't discard tagged or
2012 * untagged frames on this port, do a destination address lookup on all
2013 * received packets as usual, disable ARP mirroring and don't send a
2014 * copy of all transmitted/received frames on this port to the CPU.
Andrew Lunn54d792f2015-05-06 01:09:47 +02002015 */
2016 reg = 0;
2017 if (mv88e6xxx_6352_family(ds) || mv88e6xxx_6351_family(ds) ||
2018 mv88e6xxx_6165_family(ds) || mv88e6xxx_6097_family(ds) ||
Aleksey S. Kazantsev7c3d0d62015-07-07 20:38:15 -07002019 mv88e6xxx_6095_family(ds) || mv88e6xxx_6320_family(ds))
Andrew Lunn54d792f2015-05-06 01:09:47 +02002020 reg = PORT_CONTROL_2_MAP_DA;
2021
2022 if (mv88e6xxx_6352_family(ds) || mv88e6xxx_6351_family(ds) ||
Aleksey S. Kazantsev7c3d0d62015-07-07 20:38:15 -07002023 mv88e6xxx_6165_family(ds) || mv88e6xxx_6320_family(ds))
Andrew Lunn54d792f2015-05-06 01:09:47 +02002024 reg |= PORT_CONTROL_2_JUMBO_10240;
2025
2026 if (mv88e6xxx_6095_family(ds) || mv88e6xxx_6185_family(ds)) {
2027 /* Set the upstream port this port should use */
2028 reg |= dsa_upstream_port(ds);
2029 /* enable forwarding of unknown multicast addresses to
2030 * the upstream port
2031 */
2032 if (port == dsa_upstream_port(ds))
2033 reg |= PORT_CONTROL_2_FORWARD_UNKNOWN;
2034 }
2035
Vivien Didelotf5117ce2015-08-19 18:54:55 -04002036 reg |= PORT_CONTROL_2_8021Q_FALLBACK;
Vivien Didelot8efdda42015-08-13 12:52:23 -04002037
Andrew Lunn54d792f2015-05-06 01:09:47 +02002038 if (reg) {
2039 ret = _mv88e6xxx_reg_write(ds, REG_PORT(port),
2040 PORT_CONTROL_2, reg);
2041 if (ret)
2042 goto abort;
2043 }
2044
2045 /* Port Association Vector: when learning source addresses
2046 * of packets, add the address to the address database using
2047 * a port bitmap that has only the bit for this port set and
2048 * the other bits clear.
2049 */
2050 ret = _mv88e6xxx_reg_write(ds, REG_PORT(port), PORT_ASSOC_VECTOR,
2051 1 << port);
2052 if (ret)
2053 goto abort;
2054
2055 /* Egress rate control 2: disable egress rate control. */
2056 ret = _mv88e6xxx_reg_write(ds, REG_PORT(port), PORT_RATE_CONTROL_2,
2057 0x0000);
2058 if (ret)
2059 goto abort;
2060
2061 if (mv88e6xxx_6352_family(ds) || mv88e6xxx_6351_family(ds) ||
Aleksey S. Kazantsev7c3d0d62015-07-07 20:38:15 -07002062 mv88e6xxx_6165_family(ds) || mv88e6xxx_6097_family(ds) ||
2063 mv88e6xxx_6320_family(ds)) {
Andrew Lunn54d792f2015-05-06 01:09:47 +02002064 /* Do not limit the period of time that this port can
2065 * be paused for by the remote end or the period of
2066 * time that this port can pause the remote end.
2067 */
2068 ret = _mv88e6xxx_reg_write(ds, REG_PORT(port),
2069 PORT_PAUSE_CTRL, 0x0000);
2070 if (ret)
2071 goto abort;
2072
2073 /* Port ATU control: disable limiting the number of
2074 * address database entries that this port is allowed
2075 * to use.
2076 */
2077 ret = _mv88e6xxx_reg_write(ds, REG_PORT(port),
2078 PORT_ATU_CONTROL, 0x0000);
2079 /* Priority Override: disable DA, SA and VTU priority
2080 * override.
2081 */
2082 ret = _mv88e6xxx_reg_write(ds, REG_PORT(port),
2083 PORT_PRI_OVERRIDE, 0x0000);
2084 if (ret)
2085 goto abort;
2086
2087 /* Port Ethertype: use the Ethertype DSA Ethertype
2088 * value.
2089 */
2090 ret = _mv88e6xxx_reg_write(ds, REG_PORT(port),
2091 PORT_ETH_TYPE, ETH_P_EDSA);
2092 if (ret)
2093 goto abort;
2094 /* Tag Remap: use an identity 802.1p prio -> switch
2095 * prio mapping.
2096 */
2097 ret = _mv88e6xxx_reg_write(ds, REG_PORT(port),
2098 PORT_TAG_REGMAP_0123, 0x3210);
2099 if (ret)
2100 goto abort;
2101
2102 /* Tag Remap 2: use an identity 802.1p prio -> switch
2103 * prio mapping.
2104 */
2105 ret = _mv88e6xxx_reg_write(ds, REG_PORT(port),
2106 PORT_TAG_REGMAP_4567, 0x7654);
2107 if (ret)
2108 goto abort;
2109 }
2110
2111 if (mv88e6xxx_6352_family(ds) || mv88e6xxx_6351_family(ds) ||
2112 mv88e6xxx_6165_family(ds) || mv88e6xxx_6097_family(ds) ||
Aleksey S. Kazantsev7c3d0d62015-07-07 20:38:15 -07002113 mv88e6xxx_6185_family(ds) || mv88e6xxx_6095_family(ds) ||
2114 mv88e6xxx_6320_family(ds)) {
Andrew Lunn54d792f2015-05-06 01:09:47 +02002115 /* Rate Control: disable ingress rate limiting. */
2116 ret = _mv88e6xxx_reg_write(ds, REG_PORT(port),
2117 PORT_RATE_CONTROL, 0x0001);
2118 if (ret)
2119 goto abort;
2120 }
2121
Guenter Roeck366f0a02015-03-26 18:36:30 -07002122 /* Port Control 1: disable trunking, disable sending
2123 * learning messages to this port.
Guenter Roeckd827e882015-03-26 18:36:29 -07002124 */
Vivien Didelot614f03f2015-04-20 17:19:23 -04002125 ret = _mv88e6xxx_reg_write(ds, REG_PORT(port), PORT_CONTROL_1, 0x0000);
Guenter Roeckd827e882015-03-26 18:36:29 -07002126 if (ret)
2127 goto abort;
2128
2129 /* Port based VLAN map: give each port its own address
2130 * database, allow the CPU port to talk to each of the 'real'
2131 * ports, and allow each of the 'real' ports to only talk to
2132 * the upstream port.
2133 */
Vivien Didelot194fea72015-08-10 09:09:47 -04002134 fid = port + 1;
Guenter Roeckfacd95b2015-03-26 18:36:35 -07002135 ps->fid[port] = fid;
Vivien Didelot194fea72015-08-10 09:09:47 -04002136 set_bit(fid, ps->fid_bitmap);
Guenter Roeckd827e882015-03-26 18:36:29 -07002137
Guenter Roeckfacd95b2015-03-26 18:36:35 -07002138 if (!dsa_is_cpu_port(ds, port))
2139 ps->bridge_mask[fid] = 1 << port;
2140
2141 ret = _mv88e6xxx_update_port_config(ds, port);
Guenter Roeckd827e882015-03-26 18:36:29 -07002142 if (ret)
2143 goto abort;
2144
2145 /* Default VLAN ID and priority: don't set a default VLAN
2146 * ID, and set the default packet priority to zero.
2147 */
Vivien Didelot47cf1e652015-04-20 17:43:26 -04002148 ret = _mv88e6xxx_reg_write(ds, REG_PORT(port), PORT_DEFAULT_VLAN,
2149 0x0000);
Guenter Roeckd827e882015-03-26 18:36:29 -07002150abort:
2151 mutex_unlock(&ps->smi_mutex);
2152 return ret;
2153}
2154
Andrew Lunndbde9e62015-05-06 01:09:48 +02002155int mv88e6xxx_setup_ports(struct dsa_switch *ds)
2156{
2157 struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
2158 int ret;
2159 int i;
2160
2161 for (i = 0; i < ps->num_ports; i++) {
2162 ret = mv88e6xxx_setup_port(ds, i);
2163 if (ret < 0)
2164 return ret;
2165 }
2166 return 0;
2167}
2168
Andrew Lunn87c8cef2015-06-20 18:42:28 +02002169static int mv88e6xxx_regs_show(struct seq_file *s, void *p)
2170{
2171 struct dsa_switch *ds = s->private;
2172
2173 struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
2174 int reg, port;
2175
2176 seq_puts(s, " GLOBAL GLOBAL2 ");
2177 for (port = 0 ; port < ps->num_ports; port++)
2178 seq_printf(s, " %2d ", port);
2179 seq_puts(s, "\n");
2180
2181 for (reg = 0; reg < 32; reg++) {
2182 seq_printf(s, "%2x: ", reg);
2183 seq_printf(s, " %4x %4x ",
2184 mv88e6xxx_reg_read(ds, REG_GLOBAL, reg),
2185 mv88e6xxx_reg_read(ds, REG_GLOBAL2, reg));
2186
2187 for (port = 0 ; port < ps->num_ports; port++)
2188 seq_printf(s, "%4x ",
2189 mv88e6xxx_reg_read(ds, REG_PORT(port), reg));
2190 seq_puts(s, "\n");
2191 }
2192
2193 return 0;
2194}
2195
2196static int mv88e6xxx_regs_open(struct inode *inode, struct file *file)
2197{
2198 return single_open(file, mv88e6xxx_regs_show, inode->i_private);
2199}
2200
2201static const struct file_operations mv88e6xxx_regs_fops = {
2202 .open = mv88e6xxx_regs_open,
2203 .read = seq_read,
2204 .llseek = no_llseek,
2205 .release = single_release,
2206 .owner = THIS_MODULE,
2207};
2208
Andrew Lunn8a0a2652015-06-20 18:42:29 +02002209static void mv88e6xxx_atu_show_header(struct seq_file *s)
2210{
2211 seq_puts(s, "DB T/P Vec State Addr\n");
2212}
2213
2214static void mv88e6xxx_atu_show_entry(struct seq_file *s, int dbnum,
2215 unsigned char *addr, int data)
2216{
2217 bool trunk = !!(data & GLOBAL_ATU_DATA_TRUNK);
2218 int portvec = ((data & GLOBAL_ATU_DATA_PORT_VECTOR_MASK) >>
2219 GLOBAL_ATU_DATA_PORT_VECTOR_SHIFT);
2220 int state = data & GLOBAL_ATU_DATA_STATE_MASK;
2221
2222 seq_printf(s, "%03x %5s %10pb %x %pM\n",
2223 dbnum, (trunk ? "Trunk" : "Port"), &portvec, state, addr);
2224}
2225
2226static int mv88e6xxx_atu_show_db(struct seq_file *s, struct dsa_switch *ds,
2227 int dbnum)
2228{
2229 unsigned char bcast[] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
2230 unsigned char addr[6];
2231 int ret, data, state;
2232
Vivien Didelotc5723ac2015-08-10 09:09:48 -04002233 ret = _mv88e6xxx_atu_mac_write(ds, bcast);
Andrew Lunn8a0a2652015-06-20 18:42:29 +02002234 if (ret < 0)
2235 return ret;
2236
2237 do {
2238 ret = _mv88e6xxx_atu_cmd(ds, dbnum, GLOBAL_ATU_OP_GET_NEXT_DB);
2239 if (ret < 0)
2240 return ret;
2241 data = _mv88e6xxx_reg_read(ds, REG_GLOBAL, GLOBAL_ATU_DATA);
2242 if (data < 0)
2243 return data;
2244
2245 state = data & GLOBAL_ATU_DATA_STATE_MASK;
2246 if (state == GLOBAL_ATU_DATA_STATE_UNUSED)
2247 break;
Vivien Didelotc5723ac2015-08-10 09:09:48 -04002248 ret = _mv88e6xxx_atu_mac_read(ds, addr);
Andrew Lunn8a0a2652015-06-20 18:42:29 +02002249 if (ret < 0)
2250 return ret;
2251 mv88e6xxx_atu_show_entry(s, dbnum, addr, data);
2252 } while (state != GLOBAL_ATU_DATA_STATE_UNUSED);
2253
2254 return 0;
2255}
2256
2257static int mv88e6xxx_atu_show(struct seq_file *s, void *p)
2258{
2259 struct dsa_switch *ds = s->private;
2260 struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
2261 int dbnum;
2262
2263 mv88e6xxx_atu_show_header(s);
2264
2265 for (dbnum = 0; dbnum < 255; dbnum++) {
2266 mutex_lock(&ps->smi_mutex);
2267 mv88e6xxx_atu_show_db(s, ds, dbnum);
2268 mutex_unlock(&ps->smi_mutex);
2269 }
2270
2271 return 0;
2272}
2273
2274static int mv88e6xxx_atu_open(struct inode *inode, struct file *file)
2275{
2276 return single_open(file, mv88e6xxx_atu_show, inode->i_private);
2277}
2278
2279static const struct file_operations mv88e6xxx_atu_fops = {
2280 .open = mv88e6xxx_atu_open,
2281 .read = seq_read,
2282 .llseek = no_llseek,
2283 .release = single_release,
2284 .owner = THIS_MODULE,
2285};
2286
Andrew Lunn532c7a32015-06-20 18:42:31 +02002287static void mv88e6xxx_stats_show_header(struct seq_file *s,
2288 struct mv88e6xxx_priv_state *ps)
2289{
2290 int port;
2291
2292 seq_puts(s, " Statistic ");
2293 for (port = 0 ; port < ps->num_ports; port++)
2294 seq_printf(s, "Port %2d ", port);
2295 seq_puts(s, "\n");
2296}
2297
2298static int mv88e6xxx_stats_show(struct seq_file *s, void *p)
2299{
2300 struct dsa_switch *ds = s->private;
2301 struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
2302 struct mv88e6xxx_hw_stat *stats = mv88e6xxx_hw_stats;
2303 int port, stat, max_stats;
2304 uint64_t value;
2305
2306 if (have_sw_in_discards(ds))
2307 max_stats = ARRAY_SIZE(mv88e6xxx_hw_stats);
2308 else
2309 max_stats = ARRAY_SIZE(mv88e6xxx_hw_stats) - 3;
2310
2311 mv88e6xxx_stats_show_header(s, ps);
2312
2313 mutex_lock(&ps->smi_mutex);
2314
2315 for (stat = 0; stat < max_stats; stat++) {
2316 seq_printf(s, "%19s: ", stats[stat].string);
2317 for (port = 0 ; port < ps->num_ports; port++) {
2318 _mv88e6xxx_stats_snapshot(ds, port);
2319 value = _mv88e6xxx_get_ethtool_stat(ds, stat, stats,
2320 port);
2321 seq_printf(s, "%8llu ", value);
2322 }
2323 seq_puts(s, "\n");
2324 }
2325 mutex_unlock(&ps->smi_mutex);
2326
2327 return 0;
2328}
2329
2330static int mv88e6xxx_stats_open(struct inode *inode, struct file *file)
2331{
2332 return single_open(file, mv88e6xxx_stats_show, inode->i_private);
2333}
2334
2335static const struct file_operations mv88e6xxx_stats_fops = {
2336 .open = mv88e6xxx_stats_open,
2337 .read = seq_read,
2338 .llseek = no_llseek,
2339 .release = single_release,
2340 .owner = THIS_MODULE,
2341};
2342
Andrew Lunnd35bd872015-06-20 18:42:32 +02002343static int mv88e6xxx_device_map_show(struct seq_file *s, void *p)
2344{
2345 struct dsa_switch *ds = s->private;
2346 struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
2347 int target, ret;
2348
2349 seq_puts(s, "Target Port\n");
2350
2351 mutex_lock(&ps->smi_mutex);
2352 for (target = 0; target < 32; target++) {
2353 ret = _mv88e6xxx_reg_write(
2354 ds, REG_GLOBAL2, GLOBAL2_DEVICE_MAPPING,
2355 target << GLOBAL2_DEVICE_MAPPING_TARGET_SHIFT);
2356 if (ret < 0)
2357 goto out;
2358 ret = _mv88e6xxx_reg_read(ds, REG_GLOBAL2,
2359 GLOBAL2_DEVICE_MAPPING);
2360 seq_printf(s, " %2d %2d\n", target,
2361 ret & GLOBAL2_DEVICE_MAPPING_PORT_MASK);
2362 }
2363out:
2364 mutex_unlock(&ps->smi_mutex);
2365
2366 return 0;
2367}
2368
2369static int mv88e6xxx_device_map_open(struct inode *inode, struct file *file)
2370{
2371 return single_open(file, mv88e6xxx_device_map_show, inode->i_private);
2372}
2373
2374static const struct file_operations mv88e6xxx_device_map_fops = {
2375 .open = mv88e6xxx_device_map_open,
2376 .read = seq_read,
2377 .llseek = no_llseek,
2378 .release = single_release,
2379 .owner = THIS_MODULE,
2380};
2381
Andrew Lunn56d95e22015-06-20 18:42:33 +02002382static int mv88e6xxx_scratch_show(struct seq_file *s, void *p)
2383{
2384 struct dsa_switch *ds = s->private;
2385 struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
2386 int reg, ret;
2387
2388 seq_puts(s, "Register Value\n");
2389
2390 mutex_lock(&ps->smi_mutex);
2391 for (reg = 0; reg < 0x80; reg++) {
2392 ret = _mv88e6xxx_reg_write(
2393 ds, REG_GLOBAL2, GLOBAL2_SCRATCH_MISC,
2394 reg << GLOBAL2_SCRATCH_REGISTER_SHIFT);
2395 if (ret < 0)
2396 goto out;
2397
2398 ret = _mv88e6xxx_scratch_wait(ds);
2399 if (ret < 0)
2400 goto out;
2401
2402 ret = _mv88e6xxx_reg_read(ds, REG_GLOBAL2,
2403 GLOBAL2_SCRATCH_MISC);
2404 seq_printf(s, " %2x %2x\n", reg,
2405 ret & GLOBAL2_SCRATCH_VALUE_MASK);
2406 }
2407out:
2408 mutex_unlock(&ps->smi_mutex);
2409
2410 return 0;
2411}
2412
2413static int mv88e6xxx_scratch_open(struct inode *inode, struct file *file)
2414{
2415 return single_open(file, mv88e6xxx_scratch_show, inode->i_private);
2416}
2417
2418static const struct file_operations mv88e6xxx_scratch_fops = {
2419 .open = mv88e6xxx_scratch_open,
2420 .read = seq_read,
2421 .llseek = no_llseek,
2422 .release = single_release,
2423 .owner = THIS_MODULE,
2424};
2425
Guenter Roeckacdaffc2015-03-26 18:36:28 -07002426int mv88e6xxx_setup_common(struct dsa_switch *ds)
2427{
2428 struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
Andrew Lunn87c8cef2015-06-20 18:42:28 +02002429 char *name;
Guenter Roeckacdaffc2015-03-26 18:36:28 -07002430
2431 mutex_init(&ps->smi_mutex);
Guenter Roeckacdaffc2015-03-26 18:36:28 -07002432
Andrew Lunncca8b132015-04-02 04:06:39 +02002433 ps->id = REG_READ(REG_PORT(0), PORT_SWITCH_ID) & 0xfff0;
Andrew Lunna8f064c2015-03-26 18:36:40 -07002434
Guenter Roeckfacd95b2015-03-26 18:36:35 -07002435 INIT_WORK(&ps->bridge_work, mv88e6xxx_bridge_work);
2436
Andrew Lunn87c8cef2015-06-20 18:42:28 +02002437 name = kasprintf(GFP_KERNEL, "dsa%d", ds->index);
2438 ps->dbgfs = debugfs_create_dir(name, NULL);
2439 kfree(name);
2440
2441 debugfs_create_file("regs", S_IRUGO, ps->dbgfs, ds,
2442 &mv88e6xxx_regs_fops);
2443
Andrew Lunn8a0a2652015-06-20 18:42:29 +02002444 debugfs_create_file("atu", S_IRUGO, ps->dbgfs, ds,
2445 &mv88e6xxx_atu_fops);
2446
Andrew Lunn532c7a32015-06-20 18:42:31 +02002447 debugfs_create_file("stats", S_IRUGO, ps->dbgfs, ds,
2448 &mv88e6xxx_stats_fops);
2449
Andrew Lunnd35bd872015-06-20 18:42:32 +02002450 debugfs_create_file("device_map", S_IRUGO, ps->dbgfs, ds,
2451 &mv88e6xxx_device_map_fops);
Andrew Lunn56d95e22015-06-20 18:42:33 +02002452
2453 debugfs_create_file("scratch", S_IRUGO, ps->dbgfs, ds,
2454 &mv88e6xxx_scratch_fops);
Guenter Roeckacdaffc2015-03-26 18:36:28 -07002455 return 0;
2456}
2457
Andrew Lunn54d792f2015-05-06 01:09:47 +02002458int mv88e6xxx_setup_global(struct dsa_switch *ds)
2459{
2460 struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
Vivien Didelot24751e22015-08-03 09:17:44 -04002461 int ret;
Andrew Lunn54d792f2015-05-06 01:09:47 +02002462 int i;
2463
2464 /* Set the default address aging time to 5 minutes, and
2465 * enable address learn messages to be sent to all message
2466 * ports.
2467 */
2468 REG_WRITE(REG_GLOBAL, GLOBAL_ATU_CONTROL,
2469 0x0140 | GLOBAL_ATU_CONTROL_LEARN2ALL);
2470
2471 /* Configure the IP ToS mapping registers. */
2472 REG_WRITE(REG_GLOBAL, GLOBAL_IP_PRI_0, 0x0000);
2473 REG_WRITE(REG_GLOBAL, GLOBAL_IP_PRI_1, 0x0000);
2474 REG_WRITE(REG_GLOBAL, GLOBAL_IP_PRI_2, 0x5555);
2475 REG_WRITE(REG_GLOBAL, GLOBAL_IP_PRI_3, 0x5555);
2476 REG_WRITE(REG_GLOBAL, GLOBAL_IP_PRI_4, 0xaaaa);
2477 REG_WRITE(REG_GLOBAL, GLOBAL_IP_PRI_5, 0xaaaa);
2478 REG_WRITE(REG_GLOBAL, GLOBAL_IP_PRI_6, 0xffff);
2479 REG_WRITE(REG_GLOBAL, GLOBAL_IP_PRI_7, 0xffff);
2480
2481 /* Configure the IEEE 802.1p priority mapping register. */
2482 REG_WRITE(REG_GLOBAL, GLOBAL_IEEE_PRI, 0xfa41);
2483
2484 /* Send all frames with destination addresses matching
2485 * 01:80:c2:00:00:0x to the CPU port.
2486 */
2487 REG_WRITE(REG_GLOBAL2, GLOBAL2_MGMT_EN_0X, 0xffff);
2488
2489 /* Ignore removed tag data on doubly tagged packets, disable
2490 * flow control messages, force flow control priority to the
2491 * highest, and send all special multicast frames to the CPU
2492 * port at the highest priority.
2493 */
2494 REG_WRITE(REG_GLOBAL2, GLOBAL2_SWITCH_MGMT,
2495 0x7 | GLOBAL2_SWITCH_MGMT_RSVD2CPU | 0x70 |
2496 GLOBAL2_SWITCH_MGMT_FORCE_FLOW_CTRL_PRI);
2497
2498 /* Program the DSA routing table. */
2499 for (i = 0; i < 32; i++) {
2500 int nexthop = 0x1f;
2501
2502 if (ds->pd->rtable &&
2503 i != ds->index && i < ds->dst->pd->nr_chips)
2504 nexthop = ds->pd->rtable[i] & 0x1f;
2505
2506 REG_WRITE(REG_GLOBAL2, GLOBAL2_DEVICE_MAPPING,
2507 GLOBAL2_DEVICE_MAPPING_UPDATE |
2508 (i << GLOBAL2_DEVICE_MAPPING_TARGET_SHIFT) |
2509 nexthop);
2510 }
2511
2512 /* Clear all trunk masks. */
2513 for (i = 0; i < 8; i++)
2514 REG_WRITE(REG_GLOBAL2, GLOBAL2_TRUNK_MASK,
2515 0x8000 | (i << GLOBAL2_TRUNK_MASK_NUM_SHIFT) |
2516 ((1 << ps->num_ports) - 1));
2517
2518 /* Clear all trunk mappings. */
2519 for (i = 0; i < 16; i++)
2520 REG_WRITE(REG_GLOBAL2, GLOBAL2_TRUNK_MAPPING,
2521 GLOBAL2_TRUNK_MAPPING_UPDATE |
2522 (i << GLOBAL2_TRUNK_MAPPING_ID_SHIFT));
2523
2524 if (mv88e6xxx_6352_family(ds) || mv88e6xxx_6351_family(ds) ||
Aleksey S. Kazantsev7c3d0d62015-07-07 20:38:15 -07002525 mv88e6xxx_6165_family(ds) || mv88e6xxx_6097_family(ds) ||
2526 mv88e6xxx_6320_family(ds)) {
Andrew Lunn54d792f2015-05-06 01:09:47 +02002527 /* Send all frames with destination addresses matching
2528 * 01:80:c2:00:00:2x to the CPU port.
2529 */
2530 REG_WRITE(REG_GLOBAL2, GLOBAL2_MGMT_EN_2X, 0xffff);
2531
2532 /* Initialise cross-chip port VLAN table to reset
2533 * defaults.
2534 */
2535 REG_WRITE(REG_GLOBAL2, GLOBAL2_PVT_ADDR, 0x9000);
2536
2537 /* Clear the priority override table. */
2538 for (i = 0; i < 16; i++)
2539 REG_WRITE(REG_GLOBAL2, GLOBAL2_PRIO_OVERRIDE,
2540 0x8000 | (i << 8));
2541 }
2542
2543 if (mv88e6xxx_6352_family(ds) || mv88e6xxx_6351_family(ds) ||
2544 mv88e6xxx_6165_family(ds) || mv88e6xxx_6097_family(ds) ||
Aleksey S. Kazantsev7c3d0d62015-07-07 20:38:15 -07002545 mv88e6xxx_6185_family(ds) || mv88e6xxx_6095_family(ds) ||
2546 mv88e6xxx_6320_family(ds)) {
Andrew Lunn54d792f2015-05-06 01:09:47 +02002547 /* Disable ingress rate limiting by resetting all
2548 * ingress rate limit registers to their initial
2549 * state.
2550 */
2551 for (i = 0; i < ps->num_ports; i++)
2552 REG_WRITE(REG_GLOBAL2, GLOBAL2_INGRESS_OP,
2553 0x9000 | (i << 8));
2554 }
2555
Andrew Lunndb687a52015-06-20 21:31:29 +02002556 /* Clear the statistics counters for all ports */
2557 REG_WRITE(REG_GLOBAL, GLOBAL_STATS_OP, GLOBAL_STATS_OP_FLUSH_ALL);
2558
2559 /* Wait for the flush to complete. */
Vivien Didelot24751e22015-08-03 09:17:44 -04002560 mutex_lock(&ps->smi_mutex);
2561 ret = _mv88e6xxx_stats_wait(ds);
Vivien Didelot6b17e862015-08-13 12:52:18 -04002562 if (ret < 0)
2563 goto unlock;
2564
2565 /* Clear all the VTU and STU entries */
2566 ret = _mv88e6xxx_vtu_stu_flush(ds);
2567unlock:
Vivien Didelot24751e22015-08-03 09:17:44 -04002568 mutex_unlock(&ps->smi_mutex);
Andrew Lunndb687a52015-06-20 21:31:29 +02002569
Vivien Didelot24751e22015-08-03 09:17:44 -04002570 return ret;
Andrew Lunn54d792f2015-05-06 01:09:47 +02002571}
2572
Andrew Lunn143a8302015-04-02 04:06:34 +02002573int mv88e6xxx_switch_reset(struct dsa_switch *ds, bool ppu_active)
2574{
2575 struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
2576 u16 is_reset = (ppu_active ? 0x8800 : 0xc800);
2577 unsigned long timeout;
2578 int ret;
2579 int i;
2580
2581 /* Set all ports to the disabled state. */
2582 for (i = 0; i < ps->num_ports; i++) {
Andrew Lunncca8b132015-04-02 04:06:39 +02002583 ret = REG_READ(REG_PORT(i), PORT_CONTROL);
2584 REG_WRITE(REG_PORT(i), PORT_CONTROL, ret & 0xfffc);
Andrew Lunn143a8302015-04-02 04:06:34 +02002585 }
2586
2587 /* Wait for transmit queues to drain. */
2588 usleep_range(2000, 4000);
2589
2590 /* Reset the switch. Keep the PPU active if requested. The PPU
2591 * needs to be active to support indirect phy register access
2592 * through global registers 0x18 and 0x19.
2593 */
2594 if (ppu_active)
2595 REG_WRITE(REG_GLOBAL, 0x04, 0xc000);
2596 else
2597 REG_WRITE(REG_GLOBAL, 0x04, 0xc400);
2598
2599 /* Wait up to one second for reset to complete. */
2600 timeout = jiffies + 1 * HZ;
2601 while (time_before(jiffies, timeout)) {
2602 ret = REG_READ(REG_GLOBAL, 0x00);
2603 if ((ret & is_reset) == is_reset)
2604 break;
2605 usleep_range(1000, 2000);
2606 }
2607 if (time_after(jiffies, timeout))
2608 return -ETIMEDOUT;
2609
2610 return 0;
2611}
2612
Andrew Lunn491435852015-04-02 04:06:35 +02002613int mv88e6xxx_phy_page_read(struct dsa_switch *ds, int port, int page, int reg)
2614{
2615 struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
2616 int ret;
2617
Andrew Lunn3898c142015-05-06 01:09:53 +02002618 mutex_lock(&ps->smi_mutex);
Andrew Lunnfd3a0ee2015-04-02 04:06:36 +02002619 ret = _mv88e6xxx_phy_write_indirect(ds, port, 0x16, page);
Andrew Lunn491435852015-04-02 04:06:35 +02002620 if (ret < 0)
2621 goto error;
Andrew Lunnfd3a0ee2015-04-02 04:06:36 +02002622 ret = _mv88e6xxx_phy_read_indirect(ds, port, reg);
Andrew Lunn491435852015-04-02 04:06:35 +02002623error:
Andrew Lunnfd3a0ee2015-04-02 04:06:36 +02002624 _mv88e6xxx_phy_write_indirect(ds, port, 0x16, 0x0);
Andrew Lunn3898c142015-05-06 01:09:53 +02002625 mutex_unlock(&ps->smi_mutex);
Andrew Lunn491435852015-04-02 04:06:35 +02002626 return ret;
2627}
2628
2629int mv88e6xxx_phy_page_write(struct dsa_switch *ds, int port, int page,
2630 int reg, int val)
2631{
2632 struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
2633 int ret;
2634
Andrew Lunn3898c142015-05-06 01:09:53 +02002635 mutex_lock(&ps->smi_mutex);
Andrew Lunnfd3a0ee2015-04-02 04:06:36 +02002636 ret = _mv88e6xxx_phy_write_indirect(ds, port, 0x16, page);
Andrew Lunn491435852015-04-02 04:06:35 +02002637 if (ret < 0)
2638 goto error;
2639
Andrew Lunnfd3a0ee2015-04-02 04:06:36 +02002640 ret = _mv88e6xxx_phy_write_indirect(ds, port, reg, val);
Andrew Lunn491435852015-04-02 04:06:35 +02002641error:
Andrew Lunnfd3a0ee2015-04-02 04:06:36 +02002642 _mv88e6xxx_phy_write_indirect(ds, port, 0x16, 0x0);
Andrew Lunn3898c142015-05-06 01:09:53 +02002643 mutex_unlock(&ps->smi_mutex);
Andrew Lunnfd3a0ee2015-04-02 04:06:36 +02002644 return ret;
2645}
2646
2647static int mv88e6xxx_port_to_phy_addr(struct dsa_switch *ds, int port)
2648{
2649 struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
2650
2651 if (port >= 0 && port < ps->num_ports)
2652 return port;
2653 return -EINVAL;
2654}
2655
2656int
2657mv88e6xxx_phy_read(struct dsa_switch *ds, int port, int regnum)
2658{
2659 struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
2660 int addr = mv88e6xxx_port_to_phy_addr(ds, port);
2661 int ret;
2662
2663 if (addr < 0)
2664 return addr;
2665
Andrew Lunn3898c142015-05-06 01:09:53 +02002666 mutex_lock(&ps->smi_mutex);
Andrew Lunnfd3a0ee2015-04-02 04:06:36 +02002667 ret = _mv88e6xxx_phy_read(ds, addr, regnum);
Andrew Lunn3898c142015-05-06 01:09:53 +02002668 mutex_unlock(&ps->smi_mutex);
Andrew Lunnfd3a0ee2015-04-02 04:06:36 +02002669 return ret;
2670}
2671
2672int
2673mv88e6xxx_phy_write(struct dsa_switch *ds, int port, int regnum, u16 val)
2674{
2675 struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
2676 int addr = mv88e6xxx_port_to_phy_addr(ds, port);
2677 int ret;
2678
2679 if (addr < 0)
2680 return addr;
2681
Andrew Lunn3898c142015-05-06 01:09:53 +02002682 mutex_lock(&ps->smi_mutex);
Andrew Lunnfd3a0ee2015-04-02 04:06:36 +02002683 ret = _mv88e6xxx_phy_write(ds, addr, regnum, val);
Andrew Lunn3898c142015-05-06 01:09:53 +02002684 mutex_unlock(&ps->smi_mutex);
Andrew Lunnfd3a0ee2015-04-02 04:06:36 +02002685 return ret;
2686}
2687
2688int
2689mv88e6xxx_phy_read_indirect(struct dsa_switch *ds, int port, int regnum)
2690{
2691 struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
2692 int addr = mv88e6xxx_port_to_phy_addr(ds, port);
2693 int ret;
2694
2695 if (addr < 0)
2696 return addr;
2697
Andrew Lunn3898c142015-05-06 01:09:53 +02002698 mutex_lock(&ps->smi_mutex);
Andrew Lunnfd3a0ee2015-04-02 04:06:36 +02002699 ret = _mv88e6xxx_phy_read_indirect(ds, addr, regnum);
Andrew Lunn3898c142015-05-06 01:09:53 +02002700 mutex_unlock(&ps->smi_mutex);
Andrew Lunnfd3a0ee2015-04-02 04:06:36 +02002701 return ret;
2702}
2703
2704int
2705mv88e6xxx_phy_write_indirect(struct dsa_switch *ds, int port, int regnum,
2706 u16 val)
2707{
2708 struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
2709 int addr = mv88e6xxx_port_to_phy_addr(ds, port);
2710 int ret;
2711
2712 if (addr < 0)
2713 return addr;
2714
Andrew Lunn3898c142015-05-06 01:09:53 +02002715 mutex_lock(&ps->smi_mutex);
Andrew Lunnfd3a0ee2015-04-02 04:06:36 +02002716 ret = _mv88e6xxx_phy_write_indirect(ds, addr, regnum, val);
Andrew Lunn3898c142015-05-06 01:09:53 +02002717 mutex_unlock(&ps->smi_mutex);
Andrew Lunn491435852015-04-02 04:06:35 +02002718 return ret;
2719}
2720
Guenter Roeckc22995c2015-07-25 09:42:28 -07002721#ifdef CONFIG_NET_DSA_HWMON
2722
2723static int mv88e61xx_get_temp(struct dsa_switch *ds, int *temp)
2724{
2725 struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
2726 int ret;
2727 int val;
2728
2729 *temp = 0;
2730
2731 mutex_lock(&ps->smi_mutex);
2732
2733 ret = _mv88e6xxx_phy_write(ds, 0x0, 0x16, 0x6);
2734 if (ret < 0)
2735 goto error;
2736
2737 /* Enable temperature sensor */
2738 ret = _mv88e6xxx_phy_read(ds, 0x0, 0x1a);
2739 if (ret < 0)
2740 goto error;
2741
2742 ret = _mv88e6xxx_phy_write(ds, 0x0, 0x1a, ret | (1 << 5));
2743 if (ret < 0)
2744 goto error;
2745
2746 /* Wait for temperature to stabilize */
2747 usleep_range(10000, 12000);
2748
2749 val = _mv88e6xxx_phy_read(ds, 0x0, 0x1a);
2750 if (val < 0) {
2751 ret = val;
2752 goto error;
2753 }
2754
2755 /* Disable temperature sensor */
2756 ret = _mv88e6xxx_phy_write(ds, 0x0, 0x1a, ret & ~(1 << 5));
2757 if (ret < 0)
2758 goto error;
2759
2760 *temp = ((val & 0x1f) - 5) * 5;
2761
2762error:
2763 _mv88e6xxx_phy_write(ds, 0x0, 0x16, 0x0);
2764 mutex_unlock(&ps->smi_mutex);
2765 return ret;
2766}
2767
2768static int mv88e63xx_get_temp(struct dsa_switch *ds, int *temp)
2769{
2770 int phy = mv88e6xxx_6320_family(ds) ? 3 : 0;
2771 int ret;
2772
2773 *temp = 0;
2774
2775 ret = mv88e6xxx_phy_page_read(ds, phy, 6, 27);
2776 if (ret < 0)
2777 return ret;
2778
2779 *temp = (ret & 0xff) - 25;
2780
2781 return 0;
2782}
2783
2784int mv88e6xxx_get_temp(struct dsa_switch *ds, int *temp)
2785{
2786 if (mv88e6xxx_6320_family(ds) || mv88e6xxx_6352_family(ds))
2787 return mv88e63xx_get_temp(ds, temp);
2788
2789 return mv88e61xx_get_temp(ds, temp);
2790}
2791
2792int mv88e6xxx_get_temp_limit(struct dsa_switch *ds, int *temp)
2793{
2794 int phy = mv88e6xxx_6320_family(ds) ? 3 : 0;
2795 int ret;
2796
2797 if (!mv88e6xxx_6320_family(ds) && !mv88e6xxx_6352_family(ds))
2798 return -EOPNOTSUPP;
2799
2800 *temp = 0;
2801
2802 ret = mv88e6xxx_phy_page_read(ds, phy, 6, 26);
2803 if (ret < 0)
2804 return ret;
2805
2806 *temp = (((ret >> 8) & 0x1f) * 5) - 25;
2807
2808 return 0;
2809}
2810
2811int mv88e6xxx_set_temp_limit(struct dsa_switch *ds, int temp)
2812{
2813 int phy = mv88e6xxx_6320_family(ds) ? 3 : 0;
2814 int ret;
2815
2816 if (!mv88e6xxx_6320_family(ds) && !mv88e6xxx_6352_family(ds))
2817 return -EOPNOTSUPP;
2818
2819 ret = mv88e6xxx_phy_page_read(ds, phy, 6, 26);
2820 if (ret < 0)
2821 return ret;
2822 temp = clamp_val(DIV_ROUND_CLOSEST(temp, 5) + 5, 0, 0x1f);
2823 return mv88e6xxx_phy_page_write(ds, phy, 6, 26,
2824 (ret & 0xe0ff) | (temp << 8));
2825}
2826
2827int mv88e6xxx_get_temp_alarm(struct dsa_switch *ds, bool *alarm)
2828{
2829 int phy = mv88e6xxx_6320_family(ds) ? 3 : 0;
2830 int ret;
2831
2832 if (!mv88e6xxx_6320_family(ds) && !mv88e6xxx_6352_family(ds))
2833 return -EOPNOTSUPP;
2834
2835 *alarm = false;
2836
2837 ret = mv88e6xxx_phy_page_read(ds, phy, 6, 26);
2838 if (ret < 0)
2839 return ret;
2840
2841 *alarm = !!(ret & 0x40);
2842
2843 return 0;
2844}
2845#endif /* CONFIG_NET_DSA_HWMON */
2846
Ben Hutchings98e67302011-11-25 14:36:19 +00002847static int __init mv88e6xxx_init(void)
2848{
2849#if IS_ENABLED(CONFIG_NET_DSA_MV88E6131)
2850 register_switch_driver(&mv88e6131_switch_driver);
2851#endif
2852#if IS_ENABLED(CONFIG_NET_DSA_MV88E6123_61_65)
2853 register_switch_driver(&mv88e6123_61_65_switch_driver);
2854#endif
Guenter Roeck3ad50cc2014-10-29 10:44:56 -07002855#if IS_ENABLED(CONFIG_NET_DSA_MV88E6352)
2856 register_switch_driver(&mv88e6352_switch_driver);
2857#endif
Andrew Lunn42f27252014-09-12 23:58:44 +02002858#if IS_ENABLED(CONFIG_NET_DSA_MV88E6171)
2859 register_switch_driver(&mv88e6171_switch_driver);
2860#endif
Ben Hutchings98e67302011-11-25 14:36:19 +00002861 return 0;
2862}
2863module_init(mv88e6xxx_init);
2864
2865static void __exit mv88e6xxx_cleanup(void)
2866{
Andrew Lunn42f27252014-09-12 23:58:44 +02002867#if IS_ENABLED(CONFIG_NET_DSA_MV88E6171)
2868 unregister_switch_driver(&mv88e6171_switch_driver);
2869#endif
Vivien Didelot4212b542015-05-01 10:43:52 -04002870#if IS_ENABLED(CONFIG_NET_DSA_MV88E6352)
2871 unregister_switch_driver(&mv88e6352_switch_driver);
2872#endif
Ben Hutchings98e67302011-11-25 14:36:19 +00002873#if IS_ENABLED(CONFIG_NET_DSA_MV88E6123_61_65)
2874 unregister_switch_driver(&mv88e6123_61_65_switch_driver);
2875#endif
2876#if IS_ENABLED(CONFIG_NET_DSA_MV88E6131)
2877 unregister_switch_driver(&mv88e6131_switch_driver);
2878#endif
2879}
2880module_exit(mv88e6xxx_cleanup);
Ben Hutchings3d825ed2011-11-25 14:37:16 +00002881
2882MODULE_AUTHOR("Lennert Buytenhek <buytenh@wantstofly.org>");
2883MODULE_DESCRIPTION("Driver for Marvell 88E6XXX ethernet switch chips");
2884MODULE_LICENSE("GPL");