blob: 332f2c8090d0f1ce9030774a424123b1c47f1515 [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);
1929 if (dsa_is_cpu_port(ds, port) ||
1930 ds->dsa_port_mask & (1 << port)) {
1931 reg |= PORT_PCS_CTRL_FORCE_LINK |
1932 PORT_PCS_CTRL_LINK_UP |
1933 PORT_PCS_CTRL_DUPLEX_FULL |
1934 PORT_PCS_CTRL_FORCE_DUPLEX;
1935 if (mv88e6xxx_6065_family(ds))
1936 reg |= PORT_PCS_CTRL_100;
1937 else
1938 reg |= PORT_PCS_CTRL_1000;
1939 } else {
1940 reg |= PORT_PCS_CTRL_UNFORCED;
1941 }
1942
1943 ret = _mv88e6xxx_reg_write(ds, REG_PORT(port),
1944 PORT_PCS_CTRL, reg);
1945 if (ret)
1946 goto abort;
1947 }
1948
1949 /* Port Control: disable Drop-on-Unlock, disable Drop-on-Lock,
1950 * disable Header mode, enable IGMP/MLD snooping, disable VLAN
1951 * tunneling, determine priority by looking at 802.1p and IP
1952 * priority fields (IP prio has precedence), and set STP state
1953 * to Forwarding.
1954 *
1955 * If this is the CPU link, use DSA or EDSA tagging depending
1956 * on which tagging mode was configured.
1957 *
1958 * If this is a link to another switch, use DSA tagging mode.
1959 *
1960 * If this is the upstream port for this switch, enable
1961 * forwarding of unknown unicasts and multicasts.
1962 */
1963 reg = 0;
1964 if (mv88e6xxx_6352_family(ds) || mv88e6xxx_6351_family(ds) ||
1965 mv88e6xxx_6165_family(ds) || mv88e6xxx_6097_family(ds) ||
1966 mv88e6xxx_6095_family(ds) || mv88e6xxx_6065_family(ds) ||
Aleksey S. Kazantsev7c3d0d62015-07-07 20:38:15 -07001967 mv88e6xxx_6185_family(ds) || mv88e6xxx_6320_family(ds))
Andrew Lunn54d792f2015-05-06 01:09:47 +02001968 reg = PORT_CONTROL_IGMP_MLD_SNOOP |
1969 PORT_CONTROL_USE_TAG | PORT_CONTROL_USE_IP |
1970 PORT_CONTROL_STATE_FORWARDING;
1971 if (dsa_is_cpu_port(ds, port)) {
1972 if (mv88e6xxx_6095_family(ds) || mv88e6xxx_6185_family(ds))
1973 reg |= PORT_CONTROL_DSA_TAG;
1974 if (mv88e6xxx_6352_family(ds) || mv88e6xxx_6351_family(ds) ||
Aleksey S. Kazantsev7c3d0d62015-07-07 20:38:15 -07001975 mv88e6xxx_6165_family(ds) || mv88e6xxx_6097_family(ds) ||
1976 mv88e6xxx_6320_family(ds)) {
Andrew Lunn54d792f2015-05-06 01:09:47 +02001977 if (ds->dst->tag_protocol == DSA_TAG_PROTO_EDSA)
1978 reg |= PORT_CONTROL_FRAME_ETHER_TYPE_DSA;
1979 else
1980 reg |= PORT_CONTROL_FRAME_MODE_DSA;
1981 }
1982
1983 if (mv88e6xxx_6352_family(ds) || mv88e6xxx_6351_family(ds) ||
1984 mv88e6xxx_6165_family(ds) || mv88e6xxx_6097_family(ds) ||
1985 mv88e6xxx_6095_family(ds) || mv88e6xxx_6065_family(ds) ||
Aleksey S. Kazantsev7c3d0d62015-07-07 20:38:15 -07001986 mv88e6xxx_6185_family(ds) || mv88e6xxx_6320_family(ds)) {
Andrew Lunn54d792f2015-05-06 01:09:47 +02001987 if (ds->dst->tag_protocol == DSA_TAG_PROTO_EDSA)
1988 reg |= PORT_CONTROL_EGRESS_ADD_TAG;
1989 }
1990 }
1991 if (mv88e6xxx_6352_family(ds) || mv88e6xxx_6351_family(ds) ||
1992 mv88e6xxx_6165_family(ds) || mv88e6xxx_6097_family(ds) ||
Aleksey S. Kazantsev7c3d0d62015-07-07 20:38:15 -07001993 mv88e6xxx_6095_family(ds) || mv88e6xxx_6065_family(ds) ||
1994 mv88e6xxx_6320_family(ds)) {
Andrew Lunn54d792f2015-05-06 01:09:47 +02001995 if (ds->dsa_port_mask & (1 << port))
1996 reg |= PORT_CONTROL_FRAME_MODE_DSA;
1997 if (port == dsa_upstream_port(ds))
1998 reg |= PORT_CONTROL_FORWARD_UNKNOWN |
1999 PORT_CONTROL_FORWARD_UNKNOWN_MC;
2000 }
2001 if (reg) {
2002 ret = _mv88e6xxx_reg_write(ds, REG_PORT(port),
2003 PORT_CONTROL, reg);
2004 if (ret)
2005 goto abort;
2006 }
2007
Vivien Didelot8efdda42015-08-13 12:52:23 -04002008 /* Port Control 2: don't force a good FCS, set the maximum frame size to
2009 * 10240 bytes, enable secure 802.1q tags, don't discard tagged or
2010 * untagged frames on this port, do a destination address lookup on all
2011 * received packets as usual, disable ARP mirroring and don't send a
2012 * copy of all transmitted/received frames on this port to the CPU.
Andrew Lunn54d792f2015-05-06 01:09:47 +02002013 */
2014 reg = 0;
2015 if (mv88e6xxx_6352_family(ds) || mv88e6xxx_6351_family(ds) ||
2016 mv88e6xxx_6165_family(ds) || mv88e6xxx_6097_family(ds) ||
Aleksey S. Kazantsev7c3d0d62015-07-07 20:38:15 -07002017 mv88e6xxx_6095_family(ds) || mv88e6xxx_6320_family(ds))
Andrew Lunn54d792f2015-05-06 01:09:47 +02002018 reg = PORT_CONTROL_2_MAP_DA;
2019
2020 if (mv88e6xxx_6352_family(ds) || mv88e6xxx_6351_family(ds) ||
Aleksey S. Kazantsev7c3d0d62015-07-07 20:38:15 -07002021 mv88e6xxx_6165_family(ds) || mv88e6xxx_6320_family(ds))
Andrew Lunn54d792f2015-05-06 01:09:47 +02002022 reg |= PORT_CONTROL_2_JUMBO_10240;
2023
2024 if (mv88e6xxx_6095_family(ds) || mv88e6xxx_6185_family(ds)) {
2025 /* Set the upstream port this port should use */
2026 reg |= dsa_upstream_port(ds);
2027 /* enable forwarding of unknown multicast addresses to
2028 * the upstream port
2029 */
2030 if (port == dsa_upstream_port(ds))
2031 reg |= PORT_CONTROL_2_FORWARD_UNKNOWN;
2032 }
2033
Vivien Didelot8efdda42015-08-13 12:52:23 -04002034 reg |= PORT_CONTROL_2_8021Q_SECURE;
2035
Andrew Lunn54d792f2015-05-06 01:09:47 +02002036 if (reg) {
2037 ret = _mv88e6xxx_reg_write(ds, REG_PORT(port),
2038 PORT_CONTROL_2, reg);
2039 if (ret)
2040 goto abort;
2041 }
2042
2043 /* Port Association Vector: when learning source addresses
2044 * of packets, add the address to the address database using
2045 * a port bitmap that has only the bit for this port set and
2046 * the other bits clear.
2047 */
2048 ret = _mv88e6xxx_reg_write(ds, REG_PORT(port), PORT_ASSOC_VECTOR,
2049 1 << port);
2050 if (ret)
2051 goto abort;
2052
2053 /* Egress rate control 2: disable egress rate control. */
2054 ret = _mv88e6xxx_reg_write(ds, REG_PORT(port), PORT_RATE_CONTROL_2,
2055 0x0000);
2056 if (ret)
2057 goto abort;
2058
2059 if (mv88e6xxx_6352_family(ds) || mv88e6xxx_6351_family(ds) ||
Aleksey S. Kazantsev7c3d0d62015-07-07 20:38:15 -07002060 mv88e6xxx_6165_family(ds) || mv88e6xxx_6097_family(ds) ||
2061 mv88e6xxx_6320_family(ds)) {
Andrew Lunn54d792f2015-05-06 01:09:47 +02002062 /* Do not limit the period of time that this port can
2063 * be paused for by the remote end or the period of
2064 * time that this port can pause the remote end.
2065 */
2066 ret = _mv88e6xxx_reg_write(ds, REG_PORT(port),
2067 PORT_PAUSE_CTRL, 0x0000);
2068 if (ret)
2069 goto abort;
2070
2071 /* Port ATU control: disable limiting the number of
2072 * address database entries that this port is allowed
2073 * to use.
2074 */
2075 ret = _mv88e6xxx_reg_write(ds, REG_PORT(port),
2076 PORT_ATU_CONTROL, 0x0000);
2077 /* Priority Override: disable DA, SA and VTU priority
2078 * override.
2079 */
2080 ret = _mv88e6xxx_reg_write(ds, REG_PORT(port),
2081 PORT_PRI_OVERRIDE, 0x0000);
2082 if (ret)
2083 goto abort;
2084
2085 /* Port Ethertype: use the Ethertype DSA Ethertype
2086 * value.
2087 */
2088 ret = _mv88e6xxx_reg_write(ds, REG_PORT(port),
2089 PORT_ETH_TYPE, ETH_P_EDSA);
2090 if (ret)
2091 goto abort;
2092 /* Tag Remap: use an identity 802.1p prio -> switch
2093 * prio mapping.
2094 */
2095 ret = _mv88e6xxx_reg_write(ds, REG_PORT(port),
2096 PORT_TAG_REGMAP_0123, 0x3210);
2097 if (ret)
2098 goto abort;
2099
2100 /* Tag Remap 2: use an identity 802.1p prio -> switch
2101 * prio mapping.
2102 */
2103 ret = _mv88e6xxx_reg_write(ds, REG_PORT(port),
2104 PORT_TAG_REGMAP_4567, 0x7654);
2105 if (ret)
2106 goto abort;
2107 }
2108
2109 if (mv88e6xxx_6352_family(ds) || mv88e6xxx_6351_family(ds) ||
2110 mv88e6xxx_6165_family(ds) || mv88e6xxx_6097_family(ds) ||
Aleksey S. Kazantsev7c3d0d62015-07-07 20:38:15 -07002111 mv88e6xxx_6185_family(ds) || mv88e6xxx_6095_family(ds) ||
2112 mv88e6xxx_6320_family(ds)) {
Andrew Lunn54d792f2015-05-06 01:09:47 +02002113 /* Rate Control: disable ingress rate limiting. */
2114 ret = _mv88e6xxx_reg_write(ds, REG_PORT(port),
2115 PORT_RATE_CONTROL, 0x0001);
2116 if (ret)
2117 goto abort;
2118 }
2119
Guenter Roeck366f0a02015-03-26 18:36:30 -07002120 /* Port Control 1: disable trunking, disable sending
2121 * learning messages to this port.
Guenter Roeckd827e882015-03-26 18:36:29 -07002122 */
Vivien Didelot614f03f2015-04-20 17:19:23 -04002123 ret = _mv88e6xxx_reg_write(ds, REG_PORT(port), PORT_CONTROL_1, 0x0000);
Guenter Roeckd827e882015-03-26 18:36:29 -07002124 if (ret)
2125 goto abort;
2126
2127 /* Port based VLAN map: give each port its own address
2128 * database, allow the CPU port to talk to each of the 'real'
2129 * ports, and allow each of the 'real' ports to only talk to
2130 * the upstream port.
2131 */
Vivien Didelot194fea72015-08-10 09:09:47 -04002132 fid = port + 1;
Guenter Roeckfacd95b2015-03-26 18:36:35 -07002133 ps->fid[port] = fid;
Vivien Didelot194fea72015-08-10 09:09:47 -04002134 set_bit(fid, ps->fid_bitmap);
Guenter Roeckd827e882015-03-26 18:36:29 -07002135
Guenter Roeckfacd95b2015-03-26 18:36:35 -07002136 if (!dsa_is_cpu_port(ds, port))
2137 ps->bridge_mask[fid] = 1 << port;
2138
2139 ret = _mv88e6xxx_update_port_config(ds, port);
Guenter Roeckd827e882015-03-26 18:36:29 -07002140 if (ret)
2141 goto abort;
2142
2143 /* Default VLAN ID and priority: don't set a default VLAN
2144 * ID, and set the default packet priority to zero.
2145 */
Vivien Didelot47cf1e652015-04-20 17:43:26 -04002146 ret = _mv88e6xxx_reg_write(ds, REG_PORT(port), PORT_DEFAULT_VLAN,
2147 0x0000);
Guenter Roeckd827e882015-03-26 18:36:29 -07002148abort:
2149 mutex_unlock(&ps->smi_mutex);
2150 return ret;
2151}
2152
Andrew Lunndbde9e62015-05-06 01:09:48 +02002153int mv88e6xxx_setup_ports(struct dsa_switch *ds)
2154{
2155 struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
2156 int ret;
2157 int i;
2158
2159 for (i = 0; i < ps->num_ports; i++) {
2160 ret = mv88e6xxx_setup_port(ds, i);
2161 if (ret < 0)
2162 return ret;
2163 }
2164 return 0;
2165}
2166
Andrew Lunn87c8cef2015-06-20 18:42:28 +02002167static int mv88e6xxx_regs_show(struct seq_file *s, void *p)
2168{
2169 struct dsa_switch *ds = s->private;
2170
2171 struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
2172 int reg, port;
2173
2174 seq_puts(s, " GLOBAL GLOBAL2 ");
2175 for (port = 0 ; port < ps->num_ports; port++)
2176 seq_printf(s, " %2d ", port);
2177 seq_puts(s, "\n");
2178
2179 for (reg = 0; reg < 32; reg++) {
2180 seq_printf(s, "%2x: ", reg);
2181 seq_printf(s, " %4x %4x ",
2182 mv88e6xxx_reg_read(ds, REG_GLOBAL, reg),
2183 mv88e6xxx_reg_read(ds, REG_GLOBAL2, reg));
2184
2185 for (port = 0 ; port < ps->num_ports; port++)
2186 seq_printf(s, "%4x ",
2187 mv88e6xxx_reg_read(ds, REG_PORT(port), reg));
2188 seq_puts(s, "\n");
2189 }
2190
2191 return 0;
2192}
2193
2194static int mv88e6xxx_regs_open(struct inode *inode, struct file *file)
2195{
2196 return single_open(file, mv88e6xxx_regs_show, inode->i_private);
2197}
2198
2199static const struct file_operations mv88e6xxx_regs_fops = {
2200 .open = mv88e6xxx_regs_open,
2201 .read = seq_read,
2202 .llseek = no_llseek,
2203 .release = single_release,
2204 .owner = THIS_MODULE,
2205};
2206
Andrew Lunn8a0a2652015-06-20 18:42:29 +02002207static void mv88e6xxx_atu_show_header(struct seq_file *s)
2208{
2209 seq_puts(s, "DB T/P Vec State Addr\n");
2210}
2211
2212static void mv88e6xxx_atu_show_entry(struct seq_file *s, int dbnum,
2213 unsigned char *addr, int data)
2214{
2215 bool trunk = !!(data & GLOBAL_ATU_DATA_TRUNK);
2216 int portvec = ((data & GLOBAL_ATU_DATA_PORT_VECTOR_MASK) >>
2217 GLOBAL_ATU_DATA_PORT_VECTOR_SHIFT);
2218 int state = data & GLOBAL_ATU_DATA_STATE_MASK;
2219
2220 seq_printf(s, "%03x %5s %10pb %x %pM\n",
2221 dbnum, (trunk ? "Trunk" : "Port"), &portvec, state, addr);
2222}
2223
2224static int mv88e6xxx_atu_show_db(struct seq_file *s, struct dsa_switch *ds,
2225 int dbnum)
2226{
2227 unsigned char bcast[] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
2228 unsigned char addr[6];
2229 int ret, data, state;
2230
Vivien Didelotc5723ac2015-08-10 09:09:48 -04002231 ret = _mv88e6xxx_atu_mac_write(ds, bcast);
Andrew Lunn8a0a2652015-06-20 18:42:29 +02002232 if (ret < 0)
2233 return ret;
2234
2235 do {
2236 ret = _mv88e6xxx_atu_cmd(ds, dbnum, GLOBAL_ATU_OP_GET_NEXT_DB);
2237 if (ret < 0)
2238 return ret;
2239 data = _mv88e6xxx_reg_read(ds, REG_GLOBAL, GLOBAL_ATU_DATA);
2240 if (data < 0)
2241 return data;
2242
2243 state = data & GLOBAL_ATU_DATA_STATE_MASK;
2244 if (state == GLOBAL_ATU_DATA_STATE_UNUSED)
2245 break;
Vivien Didelotc5723ac2015-08-10 09:09:48 -04002246 ret = _mv88e6xxx_atu_mac_read(ds, addr);
Andrew Lunn8a0a2652015-06-20 18:42:29 +02002247 if (ret < 0)
2248 return ret;
2249 mv88e6xxx_atu_show_entry(s, dbnum, addr, data);
2250 } while (state != GLOBAL_ATU_DATA_STATE_UNUSED);
2251
2252 return 0;
2253}
2254
2255static int mv88e6xxx_atu_show(struct seq_file *s, void *p)
2256{
2257 struct dsa_switch *ds = s->private;
2258 struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
2259 int dbnum;
2260
2261 mv88e6xxx_atu_show_header(s);
2262
2263 for (dbnum = 0; dbnum < 255; dbnum++) {
2264 mutex_lock(&ps->smi_mutex);
2265 mv88e6xxx_atu_show_db(s, ds, dbnum);
2266 mutex_unlock(&ps->smi_mutex);
2267 }
2268
2269 return 0;
2270}
2271
2272static int mv88e6xxx_atu_open(struct inode *inode, struct file *file)
2273{
2274 return single_open(file, mv88e6xxx_atu_show, inode->i_private);
2275}
2276
2277static const struct file_operations mv88e6xxx_atu_fops = {
2278 .open = mv88e6xxx_atu_open,
2279 .read = seq_read,
2280 .llseek = no_llseek,
2281 .release = single_release,
2282 .owner = THIS_MODULE,
2283};
2284
Andrew Lunn532c7a32015-06-20 18:42:31 +02002285static void mv88e6xxx_stats_show_header(struct seq_file *s,
2286 struct mv88e6xxx_priv_state *ps)
2287{
2288 int port;
2289
2290 seq_puts(s, " Statistic ");
2291 for (port = 0 ; port < ps->num_ports; port++)
2292 seq_printf(s, "Port %2d ", port);
2293 seq_puts(s, "\n");
2294}
2295
2296static int mv88e6xxx_stats_show(struct seq_file *s, void *p)
2297{
2298 struct dsa_switch *ds = s->private;
2299 struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
2300 struct mv88e6xxx_hw_stat *stats = mv88e6xxx_hw_stats;
2301 int port, stat, max_stats;
2302 uint64_t value;
2303
2304 if (have_sw_in_discards(ds))
2305 max_stats = ARRAY_SIZE(mv88e6xxx_hw_stats);
2306 else
2307 max_stats = ARRAY_SIZE(mv88e6xxx_hw_stats) - 3;
2308
2309 mv88e6xxx_stats_show_header(s, ps);
2310
2311 mutex_lock(&ps->smi_mutex);
2312
2313 for (stat = 0; stat < max_stats; stat++) {
2314 seq_printf(s, "%19s: ", stats[stat].string);
2315 for (port = 0 ; port < ps->num_ports; port++) {
2316 _mv88e6xxx_stats_snapshot(ds, port);
2317 value = _mv88e6xxx_get_ethtool_stat(ds, stat, stats,
2318 port);
2319 seq_printf(s, "%8llu ", value);
2320 }
2321 seq_puts(s, "\n");
2322 }
2323 mutex_unlock(&ps->smi_mutex);
2324
2325 return 0;
2326}
2327
2328static int mv88e6xxx_stats_open(struct inode *inode, struct file *file)
2329{
2330 return single_open(file, mv88e6xxx_stats_show, inode->i_private);
2331}
2332
2333static const struct file_operations mv88e6xxx_stats_fops = {
2334 .open = mv88e6xxx_stats_open,
2335 .read = seq_read,
2336 .llseek = no_llseek,
2337 .release = single_release,
2338 .owner = THIS_MODULE,
2339};
2340
Andrew Lunnd35bd872015-06-20 18:42:32 +02002341static int mv88e6xxx_device_map_show(struct seq_file *s, void *p)
2342{
2343 struct dsa_switch *ds = s->private;
2344 struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
2345 int target, ret;
2346
2347 seq_puts(s, "Target Port\n");
2348
2349 mutex_lock(&ps->smi_mutex);
2350 for (target = 0; target < 32; target++) {
2351 ret = _mv88e6xxx_reg_write(
2352 ds, REG_GLOBAL2, GLOBAL2_DEVICE_MAPPING,
2353 target << GLOBAL2_DEVICE_MAPPING_TARGET_SHIFT);
2354 if (ret < 0)
2355 goto out;
2356 ret = _mv88e6xxx_reg_read(ds, REG_GLOBAL2,
2357 GLOBAL2_DEVICE_MAPPING);
2358 seq_printf(s, " %2d %2d\n", target,
2359 ret & GLOBAL2_DEVICE_MAPPING_PORT_MASK);
2360 }
2361out:
2362 mutex_unlock(&ps->smi_mutex);
2363
2364 return 0;
2365}
2366
2367static int mv88e6xxx_device_map_open(struct inode *inode, struct file *file)
2368{
2369 return single_open(file, mv88e6xxx_device_map_show, inode->i_private);
2370}
2371
2372static const struct file_operations mv88e6xxx_device_map_fops = {
2373 .open = mv88e6xxx_device_map_open,
2374 .read = seq_read,
2375 .llseek = no_llseek,
2376 .release = single_release,
2377 .owner = THIS_MODULE,
2378};
2379
Andrew Lunn56d95e22015-06-20 18:42:33 +02002380static int mv88e6xxx_scratch_show(struct seq_file *s, void *p)
2381{
2382 struct dsa_switch *ds = s->private;
2383 struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
2384 int reg, ret;
2385
2386 seq_puts(s, "Register Value\n");
2387
2388 mutex_lock(&ps->smi_mutex);
2389 for (reg = 0; reg < 0x80; reg++) {
2390 ret = _mv88e6xxx_reg_write(
2391 ds, REG_GLOBAL2, GLOBAL2_SCRATCH_MISC,
2392 reg << GLOBAL2_SCRATCH_REGISTER_SHIFT);
2393 if (ret < 0)
2394 goto out;
2395
2396 ret = _mv88e6xxx_scratch_wait(ds);
2397 if (ret < 0)
2398 goto out;
2399
2400 ret = _mv88e6xxx_reg_read(ds, REG_GLOBAL2,
2401 GLOBAL2_SCRATCH_MISC);
2402 seq_printf(s, " %2x %2x\n", reg,
2403 ret & GLOBAL2_SCRATCH_VALUE_MASK);
2404 }
2405out:
2406 mutex_unlock(&ps->smi_mutex);
2407
2408 return 0;
2409}
2410
2411static int mv88e6xxx_scratch_open(struct inode *inode, struct file *file)
2412{
2413 return single_open(file, mv88e6xxx_scratch_show, inode->i_private);
2414}
2415
2416static const struct file_operations mv88e6xxx_scratch_fops = {
2417 .open = mv88e6xxx_scratch_open,
2418 .read = seq_read,
2419 .llseek = no_llseek,
2420 .release = single_release,
2421 .owner = THIS_MODULE,
2422};
2423
Guenter Roeckacdaffc2015-03-26 18:36:28 -07002424int mv88e6xxx_setup_common(struct dsa_switch *ds)
2425{
2426 struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
Andrew Lunn87c8cef2015-06-20 18:42:28 +02002427 char *name;
Guenter Roeckacdaffc2015-03-26 18:36:28 -07002428
2429 mutex_init(&ps->smi_mutex);
Guenter Roeckacdaffc2015-03-26 18:36:28 -07002430
Andrew Lunncca8b132015-04-02 04:06:39 +02002431 ps->id = REG_READ(REG_PORT(0), PORT_SWITCH_ID) & 0xfff0;
Andrew Lunna8f064c2015-03-26 18:36:40 -07002432
Guenter Roeckfacd95b2015-03-26 18:36:35 -07002433 INIT_WORK(&ps->bridge_work, mv88e6xxx_bridge_work);
2434
Andrew Lunn87c8cef2015-06-20 18:42:28 +02002435 name = kasprintf(GFP_KERNEL, "dsa%d", ds->index);
2436 ps->dbgfs = debugfs_create_dir(name, NULL);
2437 kfree(name);
2438
2439 debugfs_create_file("regs", S_IRUGO, ps->dbgfs, ds,
2440 &mv88e6xxx_regs_fops);
2441
Andrew Lunn8a0a2652015-06-20 18:42:29 +02002442 debugfs_create_file("atu", S_IRUGO, ps->dbgfs, ds,
2443 &mv88e6xxx_atu_fops);
2444
Andrew Lunn532c7a32015-06-20 18:42:31 +02002445 debugfs_create_file("stats", S_IRUGO, ps->dbgfs, ds,
2446 &mv88e6xxx_stats_fops);
2447
Andrew Lunnd35bd872015-06-20 18:42:32 +02002448 debugfs_create_file("device_map", S_IRUGO, ps->dbgfs, ds,
2449 &mv88e6xxx_device_map_fops);
Andrew Lunn56d95e22015-06-20 18:42:33 +02002450
2451 debugfs_create_file("scratch", S_IRUGO, ps->dbgfs, ds,
2452 &mv88e6xxx_scratch_fops);
Guenter Roeckacdaffc2015-03-26 18:36:28 -07002453 return 0;
2454}
2455
Andrew Lunn54d792f2015-05-06 01:09:47 +02002456int mv88e6xxx_setup_global(struct dsa_switch *ds)
2457{
2458 struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
Vivien Didelot24751e22015-08-03 09:17:44 -04002459 int ret;
Andrew Lunn54d792f2015-05-06 01:09:47 +02002460 int i;
2461
2462 /* Set the default address aging time to 5 minutes, and
2463 * enable address learn messages to be sent to all message
2464 * ports.
2465 */
2466 REG_WRITE(REG_GLOBAL, GLOBAL_ATU_CONTROL,
2467 0x0140 | GLOBAL_ATU_CONTROL_LEARN2ALL);
2468
2469 /* Configure the IP ToS mapping registers. */
2470 REG_WRITE(REG_GLOBAL, GLOBAL_IP_PRI_0, 0x0000);
2471 REG_WRITE(REG_GLOBAL, GLOBAL_IP_PRI_1, 0x0000);
2472 REG_WRITE(REG_GLOBAL, GLOBAL_IP_PRI_2, 0x5555);
2473 REG_WRITE(REG_GLOBAL, GLOBAL_IP_PRI_3, 0x5555);
2474 REG_WRITE(REG_GLOBAL, GLOBAL_IP_PRI_4, 0xaaaa);
2475 REG_WRITE(REG_GLOBAL, GLOBAL_IP_PRI_5, 0xaaaa);
2476 REG_WRITE(REG_GLOBAL, GLOBAL_IP_PRI_6, 0xffff);
2477 REG_WRITE(REG_GLOBAL, GLOBAL_IP_PRI_7, 0xffff);
2478
2479 /* Configure the IEEE 802.1p priority mapping register. */
2480 REG_WRITE(REG_GLOBAL, GLOBAL_IEEE_PRI, 0xfa41);
2481
2482 /* Send all frames with destination addresses matching
2483 * 01:80:c2:00:00:0x to the CPU port.
2484 */
2485 REG_WRITE(REG_GLOBAL2, GLOBAL2_MGMT_EN_0X, 0xffff);
2486
2487 /* Ignore removed tag data on doubly tagged packets, disable
2488 * flow control messages, force flow control priority to the
2489 * highest, and send all special multicast frames to the CPU
2490 * port at the highest priority.
2491 */
2492 REG_WRITE(REG_GLOBAL2, GLOBAL2_SWITCH_MGMT,
2493 0x7 | GLOBAL2_SWITCH_MGMT_RSVD2CPU | 0x70 |
2494 GLOBAL2_SWITCH_MGMT_FORCE_FLOW_CTRL_PRI);
2495
2496 /* Program the DSA routing table. */
2497 for (i = 0; i < 32; i++) {
2498 int nexthop = 0x1f;
2499
2500 if (ds->pd->rtable &&
2501 i != ds->index && i < ds->dst->pd->nr_chips)
2502 nexthop = ds->pd->rtable[i] & 0x1f;
2503
2504 REG_WRITE(REG_GLOBAL2, GLOBAL2_DEVICE_MAPPING,
2505 GLOBAL2_DEVICE_MAPPING_UPDATE |
2506 (i << GLOBAL2_DEVICE_MAPPING_TARGET_SHIFT) |
2507 nexthop);
2508 }
2509
2510 /* Clear all trunk masks. */
2511 for (i = 0; i < 8; i++)
2512 REG_WRITE(REG_GLOBAL2, GLOBAL2_TRUNK_MASK,
2513 0x8000 | (i << GLOBAL2_TRUNK_MASK_NUM_SHIFT) |
2514 ((1 << ps->num_ports) - 1));
2515
2516 /* Clear all trunk mappings. */
2517 for (i = 0; i < 16; i++)
2518 REG_WRITE(REG_GLOBAL2, GLOBAL2_TRUNK_MAPPING,
2519 GLOBAL2_TRUNK_MAPPING_UPDATE |
2520 (i << GLOBAL2_TRUNK_MAPPING_ID_SHIFT));
2521
2522 if (mv88e6xxx_6352_family(ds) || mv88e6xxx_6351_family(ds) ||
Aleksey S. Kazantsev7c3d0d62015-07-07 20:38:15 -07002523 mv88e6xxx_6165_family(ds) || mv88e6xxx_6097_family(ds) ||
2524 mv88e6xxx_6320_family(ds)) {
Andrew Lunn54d792f2015-05-06 01:09:47 +02002525 /* Send all frames with destination addresses matching
2526 * 01:80:c2:00:00:2x to the CPU port.
2527 */
2528 REG_WRITE(REG_GLOBAL2, GLOBAL2_MGMT_EN_2X, 0xffff);
2529
2530 /* Initialise cross-chip port VLAN table to reset
2531 * defaults.
2532 */
2533 REG_WRITE(REG_GLOBAL2, GLOBAL2_PVT_ADDR, 0x9000);
2534
2535 /* Clear the priority override table. */
2536 for (i = 0; i < 16; i++)
2537 REG_WRITE(REG_GLOBAL2, GLOBAL2_PRIO_OVERRIDE,
2538 0x8000 | (i << 8));
2539 }
2540
2541 if (mv88e6xxx_6352_family(ds) || mv88e6xxx_6351_family(ds) ||
2542 mv88e6xxx_6165_family(ds) || mv88e6xxx_6097_family(ds) ||
Aleksey S. Kazantsev7c3d0d62015-07-07 20:38:15 -07002543 mv88e6xxx_6185_family(ds) || mv88e6xxx_6095_family(ds) ||
2544 mv88e6xxx_6320_family(ds)) {
Andrew Lunn54d792f2015-05-06 01:09:47 +02002545 /* Disable ingress rate limiting by resetting all
2546 * ingress rate limit registers to their initial
2547 * state.
2548 */
2549 for (i = 0; i < ps->num_ports; i++)
2550 REG_WRITE(REG_GLOBAL2, GLOBAL2_INGRESS_OP,
2551 0x9000 | (i << 8));
2552 }
2553
Andrew Lunndb687a52015-06-20 21:31:29 +02002554 /* Clear the statistics counters for all ports */
2555 REG_WRITE(REG_GLOBAL, GLOBAL_STATS_OP, GLOBAL_STATS_OP_FLUSH_ALL);
2556
2557 /* Wait for the flush to complete. */
Vivien Didelot24751e22015-08-03 09:17:44 -04002558 mutex_lock(&ps->smi_mutex);
2559 ret = _mv88e6xxx_stats_wait(ds);
Vivien Didelot6b17e862015-08-13 12:52:18 -04002560 if (ret < 0)
2561 goto unlock;
2562
2563 /* Clear all the VTU and STU entries */
2564 ret = _mv88e6xxx_vtu_stu_flush(ds);
2565unlock:
Vivien Didelot24751e22015-08-03 09:17:44 -04002566 mutex_unlock(&ps->smi_mutex);
Andrew Lunndb687a52015-06-20 21:31:29 +02002567
Vivien Didelot24751e22015-08-03 09:17:44 -04002568 return ret;
Andrew Lunn54d792f2015-05-06 01:09:47 +02002569}
2570
Andrew Lunn143a8302015-04-02 04:06:34 +02002571int mv88e6xxx_switch_reset(struct dsa_switch *ds, bool ppu_active)
2572{
2573 struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
2574 u16 is_reset = (ppu_active ? 0x8800 : 0xc800);
2575 unsigned long timeout;
2576 int ret;
2577 int i;
2578
2579 /* Set all ports to the disabled state. */
2580 for (i = 0; i < ps->num_ports; i++) {
Andrew Lunncca8b132015-04-02 04:06:39 +02002581 ret = REG_READ(REG_PORT(i), PORT_CONTROL);
2582 REG_WRITE(REG_PORT(i), PORT_CONTROL, ret & 0xfffc);
Andrew Lunn143a8302015-04-02 04:06:34 +02002583 }
2584
2585 /* Wait for transmit queues to drain. */
2586 usleep_range(2000, 4000);
2587
2588 /* Reset the switch. Keep the PPU active if requested. The PPU
2589 * needs to be active to support indirect phy register access
2590 * through global registers 0x18 and 0x19.
2591 */
2592 if (ppu_active)
2593 REG_WRITE(REG_GLOBAL, 0x04, 0xc000);
2594 else
2595 REG_WRITE(REG_GLOBAL, 0x04, 0xc400);
2596
2597 /* Wait up to one second for reset to complete. */
2598 timeout = jiffies + 1 * HZ;
2599 while (time_before(jiffies, timeout)) {
2600 ret = REG_READ(REG_GLOBAL, 0x00);
2601 if ((ret & is_reset) == is_reset)
2602 break;
2603 usleep_range(1000, 2000);
2604 }
2605 if (time_after(jiffies, timeout))
2606 return -ETIMEDOUT;
2607
2608 return 0;
2609}
2610
Andrew Lunn491435852015-04-02 04:06:35 +02002611int mv88e6xxx_phy_page_read(struct dsa_switch *ds, int port, int page, int reg)
2612{
2613 struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
2614 int ret;
2615
Andrew Lunn3898c142015-05-06 01:09:53 +02002616 mutex_lock(&ps->smi_mutex);
Andrew Lunnfd3a0ee2015-04-02 04:06:36 +02002617 ret = _mv88e6xxx_phy_write_indirect(ds, port, 0x16, page);
Andrew Lunn491435852015-04-02 04:06:35 +02002618 if (ret < 0)
2619 goto error;
Andrew Lunnfd3a0ee2015-04-02 04:06:36 +02002620 ret = _mv88e6xxx_phy_read_indirect(ds, port, reg);
Andrew Lunn491435852015-04-02 04:06:35 +02002621error:
Andrew Lunnfd3a0ee2015-04-02 04:06:36 +02002622 _mv88e6xxx_phy_write_indirect(ds, port, 0x16, 0x0);
Andrew Lunn3898c142015-05-06 01:09:53 +02002623 mutex_unlock(&ps->smi_mutex);
Andrew Lunn491435852015-04-02 04:06:35 +02002624 return ret;
2625}
2626
2627int mv88e6xxx_phy_page_write(struct dsa_switch *ds, int port, int page,
2628 int reg, int val)
2629{
2630 struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
2631 int ret;
2632
Andrew Lunn3898c142015-05-06 01:09:53 +02002633 mutex_lock(&ps->smi_mutex);
Andrew Lunnfd3a0ee2015-04-02 04:06:36 +02002634 ret = _mv88e6xxx_phy_write_indirect(ds, port, 0x16, page);
Andrew Lunn491435852015-04-02 04:06:35 +02002635 if (ret < 0)
2636 goto error;
2637
Andrew Lunnfd3a0ee2015-04-02 04:06:36 +02002638 ret = _mv88e6xxx_phy_write_indirect(ds, port, reg, val);
Andrew Lunn491435852015-04-02 04:06:35 +02002639error:
Andrew Lunnfd3a0ee2015-04-02 04:06:36 +02002640 _mv88e6xxx_phy_write_indirect(ds, port, 0x16, 0x0);
Andrew Lunn3898c142015-05-06 01:09:53 +02002641 mutex_unlock(&ps->smi_mutex);
Andrew Lunnfd3a0ee2015-04-02 04:06:36 +02002642 return ret;
2643}
2644
2645static int mv88e6xxx_port_to_phy_addr(struct dsa_switch *ds, int port)
2646{
2647 struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
2648
2649 if (port >= 0 && port < ps->num_ports)
2650 return port;
2651 return -EINVAL;
2652}
2653
2654int
2655mv88e6xxx_phy_read(struct dsa_switch *ds, int port, int regnum)
2656{
2657 struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
2658 int addr = mv88e6xxx_port_to_phy_addr(ds, port);
2659 int ret;
2660
2661 if (addr < 0)
2662 return addr;
2663
Andrew Lunn3898c142015-05-06 01:09:53 +02002664 mutex_lock(&ps->smi_mutex);
Andrew Lunnfd3a0ee2015-04-02 04:06:36 +02002665 ret = _mv88e6xxx_phy_read(ds, addr, regnum);
Andrew Lunn3898c142015-05-06 01:09:53 +02002666 mutex_unlock(&ps->smi_mutex);
Andrew Lunnfd3a0ee2015-04-02 04:06:36 +02002667 return ret;
2668}
2669
2670int
2671mv88e6xxx_phy_write(struct dsa_switch *ds, int port, int regnum, u16 val)
2672{
2673 struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
2674 int addr = mv88e6xxx_port_to_phy_addr(ds, port);
2675 int ret;
2676
2677 if (addr < 0)
2678 return addr;
2679
Andrew Lunn3898c142015-05-06 01:09:53 +02002680 mutex_lock(&ps->smi_mutex);
Andrew Lunnfd3a0ee2015-04-02 04:06:36 +02002681 ret = _mv88e6xxx_phy_write(ds, addr, regnum, val);
Andrew Lunn3898c142015-05-06 01:09:53 +02002682 mutex_unlock(&ps->smi_mutex);
Andrew Lunnfd3a0ee2015-04-02 04:06:36 +02002683 return ret;
2684}
2685
2686int
2687mv88e6xxx_phy_read_indirect(struct dsa_switch *ds, int port, int regnum)
2688{
2689 struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
2690 int addr = mv88e6xxx_port_to_phy_addr(ds, port);
2691 int ret;
2692
2693 if (addr < 0)
2694 return addr;
2695
Andrew Lunn3898c142015-05-06 01:09:53 +02002696 mutex_lock(&ps->smi_mutex);
Andrew Lunnfd3a0ee2015-04-02 04:06:36 +02002697 ret = _mv88e6xxx_phy_read_indirect(ds, addr, regnum);
Andrew Lunn3898c142015-05-06 01:09:53 +02002698 mutex_unlock(&ps->smi_mutex);
Andrew Lunnfd3a0ee2015-04-02 04:06:36 +02002699 return ret;
2700}
2701
2702int
2703mv88e6xxx_phy_write_indirect(struct dsa_switch *ds, int port, int regnum,
2704 u16 val)
2705{
2706 struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
2707 int addr = mv88e6xxx_port_to_phy_addr(ds, port);
2708 int ret;
2709
2710 if (addr < 0)
2711 return addr;
2712
Andrew Lunn3898c142015-05-06 01:09:53 +02002713 mutex_lock(&ps->smi_mutex);
Andrew Lunnfd3a0ee2015-04-02 04:06:36 +02002714 ret = _mv88e6xxx_phy_write_indirect(ds, addr, regnum, val);
Andrew Lunn3898c142015-05-06 01:09:53 +02002715 mutex_unlock(&ps->smi_mutex);
Andrew Lunn491435852015-04-02 04:06:35 +02002716 return ret;
2717}
2718
Guenter Roeckc22995c2015-07-25 09:42:28 -07002719#ifdef CONFIG_NET_DSA_HWMON
2720
2721static int mv88e61xx_get_temp(struct dsa_switch *ds, int *temp)
2722{
2723 struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
2724 int ret;
2725 int val;
2726
2727 *temp = 0;
2728
2729 mutex_lock(&ps->smi_mutex);
2730
2731 ret = _mv88e6xxx_phy_write(ds, 0x0, 0x16, 0x6);
2732 if (ret < 0)
2733 goto error;
2734
2735 /* Enable temperature sensor */
2736 ret = _mv88e6xxx_phy_read(ds, 0x0, 0x1a);
2737 if (ret < 0)
2738 goto error;
2739
2740 ret = _mv88e6xxx_phy_write(ds, 0x0, 0x1a, ret | (1 << 5));
2741 if (ret < 0)
2742 goto error;
2743
2744 /* Wait for temperature to stabilize */
2745 usleep_range(10000, 12000);
2746
2747 val = _mv88e6xxx_phy_read(ds, 0x0, 0x1a);
2748 if (val < 0) {
2749 ret = val;
2750 goto error;
2751 }
2752
2753 /* Disable temperature sensor */
2754 ret = _mv88e6xxx_phy_write(ds, 0x0, 0x1a, ret & ~(1 << 5));
2755 if (ret < 0)
2756 goto error;
2757
2758 *temp = ((val & 0x1f) - 5) * 5;
2759
2760error:
2761 _mv88e6xxx_phy_write(ds, 0x0, 0x16, 0x0);
2762 mutex_unlock(&ps->smi_mutex);
2763 return ret;
2764}
2765
2766static int mv88e63xx_get_temp(struct dsa_switch *ds, int *temp)
2767{
2768 int phy = mv88e6xxx_6320_family(ds) ? 3 : 0;
2769 int ret;
2770
2771 *temp = 0;
2772
2773 ret = mv88e6xxx_phy_page_read(ds, phy, 6, 27);
2774 if (ret < 0)
2775 return ret;
2776
2777 *temp = (ret & 0xff) - 25;
2778
2779 return 0;
2780}
2781
2782int mv88e6xxx_get_temp(struct dsa_switch *ds, int *temp)
2783{
2784 if (mv88e6xxx_6320_family(ds) || mv88e6xxx_6352_family(ds))
2785 return mv88e63xx_get_temp(ds, temp);
2786
2787 return mv88e61xx_get_temp(ds, temp);
2788}
2789
2790int mv88e6xxx_get_temp_limit(struct dsa_switch *ds, int *temp)
2791{
2792 int phy = mv88e6xxx_6320_family(ds) ? 3 : 0;
2793 int ret;
2794
2795 if (!mv88e6xxx_6320_family(ds) && !mv88e6xxx_6352_family(ds))
2796 return -EOPNOTSUPP;
2797
2798 *temp = 0;
2799
2800 ret = mv88e6xxx_phy_page_read(ds, phy, 6, 26);
2801 if (ret < 0)
2802 return ret;
2803
2804 *temp = (((ret >> 8) & 0x1f) * 5) - 25;
2805
2806 return 0;
2807}
2808
2809int mv88e6xxx_set_temp_limit(struct dsa_switch *ds, int temp)
2810{
2811 int phy = mv88e6xxx_6320_family(ds) ? 3 : 0;
2812 int ret;
2813
2814 if (!mv88e6xxx_6320_family(ds) && !mv88e6xxx_6352_family(ds))
2815 return -EOPNOTSUPP;
2816
2817 ret = mv88e6xxx_phy_page_read(ds, phy, 6, 26);
2818 if (ret < 0)
2819 return ret;
2820 temp = clamp_val(DIV_ROUND_CLOSEST(temp, 5) + 5, 0, 0x1f);
2821 return mv88e6xxx_phy_page_write(ds, phy, 6, 26,
2822 (ret & 0xe0ff) | (temp << 8));
2823}
2824
2825int mv88e6xxx_get_temp_alarm(struct dsa_switch *ds, bool *alarm)
2826{
2827 int phy = mv88e6xxx_6320_family(ds) ? 3 : 0;
2828 int ret;
2829
2830 if (!mv88e6xxx_6320_family(ds) && !mv88e6xxx_6352_family(ds))
2831 return -EOPNOTSUPP;
2832
2833 *alarm = false;
2834
2835 ret = mv88e6xxx_phy_page_read(ds, phy, 6, 26);
2836 if (ret < 0)
2837 return ret;
2838
2839 *alarm = !!(ret & 0x40);
2840
2841 return 0;
2842}
2843#endif /* CONFIG_NET_DSA_HWMON */
2844
Ben Hutchings98e67302011-11-25 14:36:19 +00002845static int __init mv88e6xxx_init(void)
2846{
2847#if IS_ENABLED(CONFIG_NET_DSA_MV88E6131)
2848 register_switch_driver(&mv88e6131_switch_driver);
2849#endif
2850#if IS_ENABLED(CONFIG_NET_DSA_MV88E6123_61_65)
2851 register_switch_driver(&mv88e6123_61_65_switch_driver);
2852#endif
Guenter Roeck3ad50cc2014-10-29 10:44:56 -07002853#if IS_ENABLED(CONFIG_NET_DSA_MV88E6352)
2854 register_switch_driver(&mv88e6352_switch_driver);
2855#endif
Andrew Lunn42f27252014-09-12 23:58:44 +02002856#if IS_ENABLED(CONFIG_NET_DSA_MV88E6171)
2857 register_switch_driver(&mv88e6171_switch_driver);
2858#endif
Ben Hutchings98e67302011-11-25 14:36:19 +00002859 return 0;
2860}
2861module_init(mv88e6xxx_init);
2862
2863static void __exit mv88e6xxx_cleanup(void)
2864{
Andrew Lunn42f27252014-09-12 23:58:44 +02002865#if IS_ENABLED(CONFIG_NET_DSA_MV88E6171)
2866 unregister_switch_driver(&mv88e6171_switch_driver);
2867#endif
Vivien Didelot4212b542015-05-01 10:43:52 -04002868#if IS_ENABLED(CONFIG_NET_DSA_MV88E6352)
2869 unregister_switch_driver(&mv88e6352_switch_driver);
2870#endif
Ben Hutchings98e67302011-11-25 14:36:19 +00002871#if IS_ENABLED(CONFIG_NET_DSA_MV88E6123_61_65)
2872 unregister_switch_driver(&mv88e6123_61_65_switch_driver);
2873#endif
2874#if IS_ENABLED(CONFIG_NET_DSA_MV88E6131)
2875 unregister_switch_driver(&mv88e6131_switch_driver);
2876#endif
2877}
2878module_exit(mv88e6xxx_cleanup);
Ben Hutchings3d825ed2011-11-25 14:37:16 +00002879
2880MODULE_AUTHOR("Lennert Buytenhek <buytenh@wantstofly.org>");
2881MODULE_DESCRIPTION("Driver for Marvell 88E6XXX ethernet switch chips");
2882MODULE_LICENSE("GPL");