blob: 75e245c4235e97809dc0df3841c13087d353e62a [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
Barry Grussling19b2f972013-01-08 16:05:54 +000014#include <linux/delay.h>
Guenter Roeckdefb05b2015-03-26 18:36:38 -070015#include <linux/etherdevice.h>
Andrew Lunndea87022015-08-31 15:56:47 +020016#include <linux/ethtool.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>
Andrew Lunnc8c1b39a2015-11-20 03:56:24 +010022#include <linux/gpio/consumer.h>
Lennert Buytenhek91da11f2008-10-07 13:44:02 +000023#include <linux/phy.h>
Ben Hutchingsc8f0b862011-11-27 17:06:08 +000024#include <net/dsa.h>
Vivien Didelot1f36faf2015-10-08 11:35:13 -040025#include <net/switchdev.h>
Lennert Buytenhek91da11f2008-10-07 13:44:02 +000026#include "mv88e6xxx.h"
27
Vivien Didelot3996a4f2015-10-30 18:56:45 -040028static void assert_smi_lock(struct dsa_switch *ds)
29{
30 struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
31
32 if (unlikely(!mutex_is_locked(&ps->smi_mutex))) {
33 dev_err(ds->master_dev, "SMI lock not held!\n");
34 dump_stack();
35 }
36}
37
Barry Grussling3675c8d2013-01-08 16:05:53 +000038/* If the switch's ADDR[4:0] strap pins are strapped to zero, it will
Lennert Buytenhek91da11f2008-10-07 13:44:02 +000039 * use all 32 SMI bus addresses on its SMI bus, and all switch registers
40 * will be directly accessible on some {device address,register address}
41 * pair. If the ADDR[4:0] pins are not strapped to zero, the switch
42 * will only respond to SMI transactions to that specific address, and
43 * an indirect addressing mechanism needs to be used to access its
44 * registers.
45 */
46static int mv88e6xxx_reg_wait_ready(struct mii_bus *bus, int sw_addr)
47{
48 int ret;
49 int i;
50
51 for (i = 0; i < 16; i++) {
Neil Armstrong6e899e62015-10-22 10:37:53 +020052 ret = mdiobus_read_nested(bus, sw_addr, SMI_CMD);
Lennert Buytenhek91da11f2008-10-07 13:44:02 +000053 if (ret < 0)
54 return ret;
55
Andrew Lunncca8b132015-04-02 04:06:39 +020056 if ((ret & SMI_CMD_BUSY) == 0)
Lennert Buytenhek91da11f2008-10-07 13:44:02 +000057 return 0;
58 }
59
60 return -ETIMEDOUT;
61}
62
Vivien Didelotb9b37712015-10-30 19:39:48 -040063static int __mv88e6xxx_reg_read(struct mii_bus *bus, int sw_addr, int addr,
64 int reg)
Lennert Buytenhek91da11f2008-10-07 13:44:02 +000065{
66 int ret;
67
68 if (sw_addr == 0)
Neil Armstrong6e899e62015-10-22 10:37:53 +020069 return mdiobus_read_nested(bus, addr, reg);
Lennert Buytenhek91da11f2008-10-07 13:44:02 +000070
Barry Grussling3675c8d2013-01-08 16:05:53 +000071 /* Wait for the bus to become free. */
Lennert Buytenhek91da11f2008-10-07 13:44:02 +000072 ret = mv88e6xxx_reg_wait_ready(bus, sw_addr);
73 if (ret < 0)
74 return ret;
75
Barry Grussling3675c8d2013-01-08 16:05:53 +000076 /* Transmit the read command. */
Neil Armstrong6e899e62015-10-22 10:37:53 +020077 ret = mdiobus_write_nested(bus, sw_addr, SMI_CMD,
78 SMI_CMD_OP_22_READ | (addr << 5) | reg);
Lennert Buytenhek91da11f2008-10-07 13:44:02 +000079 if (ret < 0)
80 return ret;
81
Barry Grussling3675c8d2013-01-08 16:05:53 +000082 /* Wait for the read command to complete. */
Lennert Buytenhek91da11f2008-10-07 13:44:02 +000083 ret = mv88e6xxx_reg_wait_ready(bus, sw_addr);
84 if (ret < 0)
85 return ret;
86
Barry Grussling3675c8d2013-01-08 16:05:53 +000087 /* Read the data. */
Neil Armstrong6e899e62015-10-22 10:37:53 +020088 ret = mdiobus_read_nested(bus, sw_addr, SMI_DATA);
Lennert Buytenhek91da11f2008-10-07 13:44:02 +000089 if (ret < 0)
90 return ret;
91
92 return ret & 0xffff;
93}
94
Guenter Roeck8d6d09e2015-03-26 18:36:31 -070095static int _mv88e6xxx_reg_read(struct dsa_switch *ds, int addr, int reg)
Lennert Buytenhek91da11f2008-10-07 13:44:02 +000096{
Guenter Roeckb184e492014-10-17 12:30:58 -070097 struct mii_bus *bus = dsa_host_dev_to_mii_bus(ds->master_dev);
Lennert Buytenhek91da11f2008-10-07 13:44:02 +000098 int ret;
99
Vivien Didelot3996a4f2015-10-30 18:56:45 -0400100 assert_smi_lock(ds);
101
Guenter Roeckb184e492014-10-17 12:30:58 -0700102 if (bus == NULL)
103 return -EINVAL;
104
Guenter Roeckb184e492014-10-17 12:30:58 -0700105 ret = __mv88e6xxx_reg_read(bus, ds->pd->sw_addr, addr, reg);
Vivien Didelotbb92ea52015-01-23 16:10:36 -0500106 if (ret < 0)
107 return ret;
108
109 dev_dbg(ds->master_dev, "<- addr: 0x%.2x reg: 0x%.2x val: 0x%.4x\n",
110 addr, reg, ret);
111
Lennert Buytenhek91da11f2008-10-07 13:44:02 +0000112 return ret;
113}
114
Guenter Roeck8d6d09e2015-03-26 18:36:31 -0700115int mv88e6xxx_reg_read(struct dsa_switch *ds, int addr, int reg)
116{
117 struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
118 int ret;
119
120 mutex_lock(&ps->smi_mutex);
121 ret = _mv88e6xxx_reg_read(ds, addr, reg);
122 mutex_unlock(&ps->smi_mutex);
123
124 return ret;
125}
126
Vivien Didelotb9b37712015-10-30 19:39:48 -0400127static int __mv88e6xxx_reg_write(struct mii_bus *bus, int sw_addr, int addr,
128 int reg, u16 val)
Lennert Buytenhek91da11f2008-10-07 13:44:02 +0000129{
130 int ret;
131
132 if (sw_addr == 0)
Neil Armstrong6e899e62015-10-22 10:37:53 +0200133 return mdiobus_write_nested(bus, addr, reg, val);
Lennert Buytenhek91da11f2008-10-07 13:44:02 +0000134
Barry Grussling3675c8d2013-01-08 16:05:53 +0000135 /* Wait for the bus to become free. */
Lennert Buytenhek91da11f2008-10-07 13:44:02 +0000136 ret = mv88e6xxx_reg_wait_ready(bus, sw_addr);
137 if (ret < 0)
138 return ret;
139
Barry Grussling3675c8d2013-01-08 16:05:53 +0000140 /* Transmit the data to write. */
Neil Armstrong6e899e62015-10-22 10:37:53 +0200141 ret = mdiobus_write_nested(bus, sw_addr, SMI_DATA, val);
Lennert Buytenhek91da11f2008-10-07 13:44:02 +0000142 if (ret < 0)
143 return ret;
144
Barry Grussling3675c8d2013-01-08 16:05:53 +0000145 /* Transmit the write command. */
Neil Armstrong6e899e62015-10-22 10:37:53 +0200146 ret = mdiobus_write_nested(bus, sw_addr, SMI_CMD,
147 SMI_CMD_OP_22_WRITE | (addr << 5) | reg);
Lennert Buytenhek91da11f2008-10-07 13:44:02 +0000148 if (ret < 0)
149 return ret;
150
Barry Grussling3675c8d2013-01-08 16:05:53 +0000151 /* Wait for the write command to complete. */
Lennert Buytenhek91da11f2008-10-07 13:44:02 +0000152 ret = mv88e6xxx_reg_wait_ready(bus, sw_addr);
153 if (ret < 0)
154 return ret;
155
156 return 0;
157}
158
Guenter Roeck8d6d09e2015-03-26 18:36:31 -0700159static int _mv88e6xxx_reg_write(struct dsa_switch *ds, int addr, int reg,
160 u16 val)
Lennert Buytenhek91da11f2008-10-07 13:44:02 +0000161{
Guenter Roeckb184e492014-10-17 12:30:58 -0700162 struct mii_bus *bus = dsa_host_dev_to_mii_bus(ds->master_dev);
Lennert Buytenhek91da11f2008-10-07 13:44:02 +0000163
Vivien Didelot3996a4f2015-10-30 18:56:45 -0400164 assert_smi_lock(ds);
165
Guenter Roeckb184e492014-10-17 12:30:58 -0700166 if (bus == NULL)
167 return -EINVAL;
168
Vivien Didelotbb92ea52015-01-23 16:10:36 -0500169 dev_dbg(ds->master_dev, "-> addr: 0x%.2x reg: 0x%.2x val: 0x%.4x\n",
170 addr, reg, val);
171
Guenter Roeck8d6d09e2015-03-26 18:36:31 -0700172 return __mv88e6xxx_reg_write(bus, ds->pd->sw_addr, addr, reg, val);
173}
174
175int mv88e6xxx_reg_write(struct dsa_switch *ds, int addr, int reg, u16 val)
176{
177 struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
178 int ret;
179
Lennert Buytenhek91da11f2008-10-07 13:44:02 +0000180 mutex_lock(&ps->smi_mutex);
Guenter Roeck8d6d09e2015-03-26 18:36:31 -0700181 ret = _mv88e6xxx_reg_write(ds, addr, reg, val);
Lennert Buytenhek91da11f2008-10-07 13:44:02 +0000182 mutex_unlock(&ps->smi_mutex);
183
184 return ret;
185}
186
Lennert Buytenhek2e5f0322008-10-07 13:45:18 +0000187int mv88e6xxx_set_addr_direct(struct dsa_switch *ds, u8 *addr)
188{
Andrew Lunncca8b132015-04-02 04:06:39 +0200189 REG_WRITE(REG_GLOBAL, GLOBAL_MAC_01, (addr[0] << 8) | addr[1]);
190 REG_WRITE(REG_GLOBAL, GLOBAL_MAC_23, (addr[2] << 8) | addr[3]);
191 REG_WRITE(REG_GLOBAL, GLOBAL_MAC_45, (addr[4] << 8) | addr[5]);
Lennert Buytenhek2e5f0322008-10-07 13:45:18 +0000192
193 return 0;
194}
195
Lennert Buytenhek91da11f2008-10-07 13:44:02 +0000196int mv88e6xxx_set_addr_indirect(struct dsa_switch *ds, u8 *addr)
197{
198 int i;
199 int ret;
200
201 for (i = 0; i < 6; i++) {
202 int j;
203
Barry Grussling3675c8d2013-01-08 16:05:53 +0000204 /* Write the MAC address byte. */
Andrew Lunncca8b132015-04-02 04:06:39 +0200205 REG_WRITE(REG_GLOBAL2, GLOBAL2_SWITCH_MAC,
206 GLOBAL2_SWITCH_MAC_BUSY | (i << 8) | addr[i]);
Lennert Buytenhek91da11f2008-10-07 13:44:02 +0000207
Barry Grussling3675c8d2013-01-08 16:05:53 +0000208 /* Wait for the write to complete. */
Lennert Buytenhek91da11f2008-10-07 13:44:02 +0000209 for (j = 0; j < 16; j++) {
Andrew Lunncca8b132015-04-02 04:06:39 +0200210 ret = REG_READ(REG_GLOBAL2, GLOBAL2_SWITCH_MAC);
211 if ((ret & GLOBAL2_SWITCH_MAC_BUSY) == 0)
Lennert Buytenhek91da11f2008-10-07 13:44:02 +0000212 break;
213 }
214 if (j == 16)
215 return -ETIMEDOUT;
216 }
217
218 return 0;
219}
220
Andrew Lunnfd3a0ee2015-04-02 04:06:36 +0200221static int _mv88e6xxx_phy_read(struct dsa_switch *ds, int addr, int regnum)
Lennert Buytenhek91da11f2008-10-07 13:44:02 +0000222{
223 if (addr >= 0)
Andrew Lunn3898c142015-05-06 01:09:53 +0200224 return _mv88e6xxx_reg_read(ds, addr, regnum);
Lennert Buytenhek91da11f2008-10-07 13:44:02 +0000225 return 0xffff;
226}
227
Andrew Lunnfd3a0ee2015-04-02 04:06:36 +0200228static int _mv88e6xxx_phy_write(struct dsa_switch *ds, int addr, int regnum,
229 u16 val)
Lennert Buytenhek91da11f2008-10-07 13:44:02 +0000230{
231 if (addr >= 0)
Andrew Lunn3898c142015-05-06 01:09:53 +0200232 return _mv88e6xxx_reg_write(ds, addr, regnum, val);
Lennert Buytenhek91da11f2008-10-07 13:44:02 +0000233 return 0;
234}
235
Lennert Buytenhek2e5f0322008-10-07 13:45:18 +0000236#ifdef CONFIG_NET_DSA_MV88E6XXX_NEED_PPU
237static int mv88e6xxx_ppu_disable(struct dsa_switch *ds)
238{
239 int ret;
Barry Grussling19b2f972013-01-08 16:05:54 +0000240 unsigned long timeout;
Lennert Buytenhek2e5f0322008-10-07 13:45:18 +0000241
Andrew Lunncca8b132015-04-02 04:06:39 +0200242 ret = REG_READ(REG_GLOBAL, GLOBAL_CONTROL);
243 REG_WRITE(REG_GLOBAL, GLOBAL_CONTROL,
244 ret & ~GLOBAL_CONTROL_PPU_ENABLE);
Lennert Buytenhek2e5f0322008-10-07 13:45:18 +0000245
Barry Grussling19b2f972013-01-08 16:05:54 +0000246 timeout = jiffies + 1 * HZ;
247 while (time_before(jiffies, timeout)) {
Andrew Lunncca8b132015-04-02 04:06:39 +0200248 ret = REG_READ(REG_GLOBAL, GLOBAL_STATUS);
Barry Grussling19b2f972013-01-08 16:05:54 +0000249 usleep_range(1000, 2000);
Andrew Lunncca8b132015-04-02 04:06:39 +0200250 if ((ret & GLOBAL_STATUS_PPU_MASK) !=
251 GLOBAL_STATUS_PPU_POLLING)
Barry Grussling85686582013-01-08 16:05:56 +0000252 return 0;
Lennert Buytenhek2e5f0322008-10-07 13:45:18 +0000253 }
254
255 return -ETIMEDOUT;
256}
257
258static int mv88e6xxx_ppu_enable(struct dsa_switch *ds)
259{
260 int ret;
Barry Grussling19b2f972013-01-08 16:05:54 +0000261 unsigned long timeout;
Lennert Buytenhek2e5f0322008-10-07 13:45:18 +0000262
Andrew Lunncca8b132015-04-02 04:06:39 +0200263 ret = REG_READ(REG_GLOBAL, GLOBAL_CONTROL);
264 REG_WRITE(REG_GLOBAL, GLOBAL_CONTROL, ret | GLOBAL_CONTROL_PPU_ENABLE);
Lennert Buytenhek2e5f0322008-10-07 13:45:18 +0000265
Barry Grussling19b2f972013-01-08 16:05:54 +0000266 timeout = jiffies + 1 * HZ;
267 while (time_before(jiffies, timeout)) {
Andrew Lunncca8b132015-04-02 04:06:39 +0200268 ret = REG_READ(REG_GLOBAL, GLOBAL_STATUS);
Barry Grussling19b2f972013-01-08 16:05:54 +0000269 usleep_range(1000, 2000);
Andrew Lunncca8b132015-04-02 04:06:39 +0200270 if ((ret & GLOBAL_STATUS_PPU_MASK) ==
271 GLOBAL_STATUS_PPU_POLLING)
Barry Grussling85686582013-01-08 16:05:56 +0000272 return 0;
Lennert Buytenhek2e5f0322008-10-07 13:45:18 +0000273 }
274
275 return -ETIMEDOUT;
276}
277
278static void mv88e6xxx_ppu_reenable_work(struct work_struct *ugly)
279{
280 struct mv88e6xxx_priv_state *ps;
281
282 ps = container_of(ugly, struct mv88e6xxx_priv_state, ppu_work);
283 if (mutex_trylock(&ps->ppu_mutex)) {
Barry Grussling85686582013-01-08 16:05:56 +0000284 struct dsa_switch *ds = ((struct dsa_switch *)ps) - 1;
Lennert Buytenhek2e5f0322008-10-07 13:45:18 +0000285
Barry Grussling85686582013-01-08 16:05:56 +0000286 if (mv88e6xxx_ppu_enable(ds) == 0)
287 ps->ppu_disabled = 0;
288 mutex_unlock(&ps->ppu_mutex);
Lennert Buytenhek2e5f0322008-10-07 13:45:18 +0000289 }
290}
291
292static void mv88e6xxx_ppu_reenable_timer(unsigned long _ps)
293{
294 struct mv88e6xxx_priv_state *ps = (void *)_ps;
295
296 schedule_work(&ps->ppu_work);
297}
298
299static int mv88e6xxx_ppu_access_get(struct dsa_switch *ds)
300{
Florian Fainellia22adce2014-04-28 11:14:28 -0700301 struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
Lennert Buytenhek2e5f0322008-10-07 13:45:18 +0000302 int ret;
303
304 mutex_lock(&ps->ppu_mutex);
305
Barry Grussling3675c8d2013-01-08 16:05:53 +0000306 /* If the PHY polling unit is enabled, disable it so that
Lennert Buytenhek2e5f0322008-10-07 13:45:18 +0000307 * we can access the PHY registers. If it was already
308 * disabled, cancel the timer that is going to re-enable
309 * it.
310 */
311 if (!ps->ppu_disabled) {
Barry Grussling85686582013-01-08 16:05:56 +0000312 ret = mv88e6xxx_ppu_disable(ds);
313 if (ret < 0) {
314 mutex_unlock(&ps->ppu_mutex);
315 return ret;
316 }
317 ps->ppu_disabled = 1;
Lennert Buytenhek2e5f0322008-10-07 13:45:18 +0000318 } else {
Barry Grussling85686582013-01-08 16:05:56 +0000319 del_timer(&ps->ppu_timer);
320 ret = 0;
Lennert Buytenhek2e5f0322008-10-07 13:45:18 +0000321 }
322
323 return ret;
324}
325
326static void mv88e6xxx_ppu_access_put(struct dsa_switch *ds)
327{
Florian Fainellia22adce2014-04-28 11:14:28 -0700328 struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
Lennert Buytenhek2e5f0322008-10-07 13:45:18 +0000329
Barry Grussling3675c8d2013-01-08 16:05:53 +0000330 /* Schedule a timer to re-enable the PHY polling unit. */
Lennert Buytenhek2e5f0322008-10-07 13:45:18 +0000331 mod_timer(&ps->ppu_timer, jiffies + msecs_to_jiffies(10));
332 mutex_unlock(&ps->ppu_mutex);
333}
334
335void mv88e6xxx_ppu_state_init(struct dsa_switch *ds)
336{
Florian Fainellia22adce2014-04-28 11:14:28 -0700337 struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
Lennert Buytenhek2e5f0322008-10-07 13:45:18 +0000338
339 mutex_init(&ps->ppu_mutex);
340 INIT_WORK(&ps->ppu_work, mv88e6xxx_ppu_reenable_work);
341 init_timer(&ps->ppu_timer);
342 ps->ppu_timer.data = (unsigned long)ps;
343 ps->ppu_timer.function = mv88e6xxx_ppu_reenable_timer;
344}
345
346int mv88e6xxx_phy_read_ppu(struct dsa_switch *ds, int addr, int regnum)
347{
348 int ret;
349
350 ret = mv88e6xxx_ppu_access_get(ds);
351 if (ret >= 0) {
Barry Grussling85686582013-01-08 16:05:56 +0000352 ret = mv88e6xxx_reg_read(ds, addr, regnum);
353 mv88e6xxx_ppu_access_put(ds);
Lennert Buytenhek2e5f0322008-10-07 13:45:18 +0000354 }
355
356 return ret;
357}
358
359int mv88e6xxx_phy_write_ppu(struct dsa_switch *ds, int addr,
360 int regnum, u16 val)
361{
362 int ret;
363
364 ret = mv88e6xxx_ppu_access_get(ds);
365 if (ret >= 0) {
Barry Grussling85686582013-01-08 16:05:56 +0000366 ret = mv88e6xxx_reg_write(ds, addr, regnum, val);
367 mv88e6xxx_ppu_access_put(ds);
Lennert Buytenhek2e5f0322008-10-07 13:45:18 +0000368 }
369
370 return ret;
371}
372#endif
373
Andrew Lunn54d792f2015-05-06 01:09:47 +0200374static bool mv88e6xxx_6065_family(struct dsa_switch *ds)
375{
376 struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
377
378 switch (ps->id) {
379 case PORT_SWITCH_ID_6031:
380 case PORT_SWITCH_ID_6061:
381 case PORT_SWITCH_ID_6035:
382 case PORT_SWITCH_ID_6065:
383 return true;
384 }
385 return false;
386}
387
388static bool mv88e6xxx_6095_family(struct dsa_switch *ds)
389{
390 struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
391
392 switch (ps->id) {
393 case PORT_SWITCH_ID_6092:
394 case PORT_SWITCH_ID_6095:
395 return true;
396 }
397 return false;
398}
399
400static bool mv88e6xxx_6097_family(struct dsa_switch *ds)
401{
402 struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
403
404 switch (ps->id) {
405 case PORT_SWITCH_ID_6046:
406 case PORT_SWITCH_ID_6085:
407 case PORT_SWITCH_ID_6096:
408 case PORT_SWITCH_ID_6097:
409 return true;
410 }
411 return false;
412}
413
414static bool mv88e6xxx_6165_family(struct dsa_switch *ds)
415{
416 struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
417
418 switch (ps->id) {
419 case PORT_SWITCH_ID_6123:
420 case PORT_SWITCH_ID_6161:
421 case PORT_SWITCH_ID_6165:
422 return true;
423 }
424 return false;
425}
426
427static bool mv88e6xxx_6185_family(struct dsa_switch *ds)
428{
429 struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
430
431 switch (ps->id) {
432 case PORT_SWITCH_ID_6121:
433 case PORT_SWITCH_ID_6122:
434 case PORT_SWITCH_ID_6152:
435 case PORT_SWITCH_ID_6155:
436 case PORT_SWITCH_ID_6182:
437 case PORT_SWITCH_ID_6185:
438 case PORT_SWITCH_ID_6108:
439 case PORT_SWITCH_ID_6131:
440 return true;
441 }
442 return false;
443}
444
Guenter Roeckc22995c2015-07-25 09:42:28 -0700445static bool mv88e6xxx_6320_family(struct dsa_switch *ds)
Aleksey S. Kazantsev7c3d0d62015-07-07 20:38:15 -0700446{
447 struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
448
449 switch (ps->id) {
450 case PORT_SWITCH_ID_6320:
451 case PORT_SWITCH_ID_6321:
452 return true;
453 }
454 return false;
455}
456
Andrew Lunn54d792f2015-05-06 01:09:47 +0200457static bool mv88e6xxx_6351_family(struct dsa_switch *ds)
458{
459 struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
460
461 switch (ps->id) {
462 case PORT_SWITCH_ID_6171:
463 case PORT_SWITCH_ID_6175:
464 case PORT_SWITCH_ID_6350:
465 case PORT_SWITCH_ID_6351:
466 return true;
467 }
468 return false;
469}
470
Andrew Lunnf3a8b6b2015-04-02 04:06:40 +0200471static bool mv88e6xxx_6352_family(struct dsa_switch *ds)
472{
473 struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
474
475 switch (ps->id) {
Andrew Lunnf3a8b6b2015-04-02 04:06:40 +0200476 case PORT_SWITCH_ID_6172:
477 case PORT_SWITCH_ID_6176:
Andrew Lunn54d792f2015-05-06 01:09:47 +0200478 case PORT_SWITCH_ID_6240:
479 case PORT_SWITCH_ID_6352:
Andrew Lunnf3a8b6b2015-04-02 04:06:40 +0200480 return true;
481 }
482 return false;
483}
484
Andrew Lunndea87022015-08-31 15:56:47 +0200485/* We expect the switch to perform auto negotiation if there is a real
486 * phy. However, in the case of a fixed link phy, we force the port
487 * settings from the fixed link settings.
488 */
489void mv88e6xxx_adjust_link(struct dsa_switch *ds, int port,
490 struct phy_device *phydev)
491{
492 struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
Andrew Lunn49052872015-09-29 01:53:48 +0200493 u32 reg;
494 int ret;
Andrew Lunndea87022015-08-31 15:56:47 +0200495
496 if (!phy_is_pseudo_fixed_link(phydev))
497 return;
498
499 mutex_lock(&ps->smi_mutex);
500
501 ret = _mv88e6xxx_reg_read(ds, REG_PORT(port), PORT_PCS_CTRL);
502 if (ret < 0)
503 goto out;
504
505 reg = ret & ~(PORT_PCS_CTRL_LINK_UP |
506 PORT_PCS_CTRL_FORCE_LINK |
507 PORT_PCS_CTRL_DUPLEX_FULL |
508 PORT_PCS_CTRL_FORCE_DUPLEX |
509 PORT_PCS_CTRL_UNFORCED);
510
511 reg |= PORT_PCS_CTRL_FORCE_LINK;
512 if (phydev->link)
513 reg |= PORT_PCS_CTRL_LINK_UP;
514
515 if (mv88e6xxx_6065_family(ds) && phydev->speed > SPEED_100)
516 goto out;
517
518 switch (phydev->speed) {
519 case SPEED_1000:
520 reg |= PORT_PCS_CTRL_1000;
521 break;
522 case SPEED_100:
523 reg |= PORT_PCS_CTRL_100;
524 break;
525 case SPEED_10:
526 reg |= PORT_PCS_CTRL_10;
527 break;
528 default:
529 pr_info("Unknown speed");
530 goto out;
531 }
532
533 reg |= PORT_PCS_CTRL_FORCE_DUPLEX;
534 if (phydev->duplex == DUPLEX_FULL)
535 reg |= PORT_PCS_CTRL_DUPLEX_FULL;
536
Andrew Lunne7e72ac2015-08-31 15:56:51 +0200537 if ((mv88e6xxx_6352_family(ds) || mv88e6xxx_6351_family(ds)) &&
538 (port >= ps->num_ports - 2)) {
539 if (phydev->interface == PHY_INTERFACE_MODE_RGMII_RXID)
540 reg |= PORT_PCS_CTRL_RGMII_DELAY_RXCLK;
541 if (phydev->interface == PHY_INTERFACE_MODE_RGMII_TXID)
542 reg |= PORT_PCS_CTRL_RGMII_DELAY_TXCLK;
543 if (phydev->interface == PHY_INTERFACE_MODE_RGMII_ID)
544 reg |= (PORT_PCS_CTRL_RGMII_DELAY_RXCLK |
545 PORT_PCS_CTRL_RGMII_DELAY_TXCLK);
546 }
Andrew Lunndea87022015-08-31 15:56:47 +0200547 _mv88e6xxx_reg_write(ds, REG_PORT(port), PORT_PCS_CTRL, reg);
548
549out:
550 mutex_unlock(&ps->smi_mutex);
551}
552
Andrew Lunn31888232015-05-06 01:09:54 +0200553static int _mv88e6xxx_stats_wait(struct dsa_switch *ds)
Lennert Buytenhek91da11f2008-10-07 13:44:02 +0000554{
555 int ret;
556 int i;
557
558 for (i = 0; i < 10; i++) {
Andrew Lunn31888232015-05-06 01:09:54 +0200559 ret = _mv88e6xxx_reg_read(ds, REG_GLOBAL, GLOBAL_STATS_OP);
Andrew Lunncca8b132015-04-02 04:06:39 +0200560 if ((ret & GLOBAL_STATS_OP_BUSY) == 0)
Lennert Buytenhek91da11f2008-10-07 13:44:02 +0000561 return 0;
562 }
563
564 return -ETIMEDOUT;
565}
566
Andrew Lunn31888232015-05-06 01:09:54 +0200567static int _mv88e6xxx_stats_snapshot(struct dsa_switch *ds, int port)
Lennert Buytenhek91da11f2008-10-07 13:44:02 +0000568{
569 int ret;
570
Aleksey S. Kazantsev7c3d0d62015-07-07 20:38:15 -0700571 if (mv88e6xxx_6320_family(ds) || mv88e6xxx_6352_family(ds))
Andrew Lunnf3a8b6b2015-04-02 04:06:40 +0200572 port = (port + 1) << 5;
573
Barry Grussling3675c8d2013-01-08 16:05:53 +0000574 /* Snapshot the hardware statistics counters for this port. */
Andrew Lunn31888232015-05-06 01:09:54 +0200575 ret = _mv88e6xxx_reg_write(ds, REG_GLOBAL, GLOBAL_STATS_OP,
576 GLOBAL_STATS_OP_CAPTURE_PORT |
577 GLOBAL_STATS_OP_HIST_RX_TX | port);
578 if (ret < 0)
579 return ret;
Lennert Buytenhek91da11f2008-10-07 13:44:02 +0000580
Barry Grussling3675c8d2013-01-08 16:05:53 +0000581 /* Wait for the snapshotting to complete. */
Andrew Lunn31888232015-05-06 01:09:54 +0200582 ret = _mv88e6xxx_stats_wait(ds);
Lennert Buytenhek91da11f2008-10-07 13:44:02 +0000583 if (ret < 0)
584 return ret;
585
586 return 0;
587}
588
Andrew Lunn31888232015-05-06 01:09:54 +0200589static void _mv88e6xxx_stats_read(struct dsa_switch *ds, int stat, u32 *val)
Lennert Buytenhek91da11f2008-10-07 13:44:02 +0000590{
591 u32 _val;
592 int ret;
593
594 *val = 0;
595
Andrew Lunn31888232015-05-06 01:09:54 +0200596 ret = _mv88e6xxx_reg_write(ds, REG_GLOBAL, GLOBAL_STATS_OP,
597 GLOBAL_STATS_OP_READ_CAPTURED |
598 GLOBAL_STATS_OP_HIST_RX_TX | stat);
Lennert Buytenhek91da11f2008-10-07 13:44:02 +0000599 if (ret < 0)
600 return;
601
Andrew Lunn31888232015-05-06 01:09:54 +0200602 ret = _mv88e6xxx_stats_wait(ds);
Lennert Buytenhek91da11f2008-10-07 13:44:02 +0000603 if (ret < 0)
604 return;
605
Andrew Lunn31888232015-05-06 01:09:54 +0200606 ret = _mv88e6xxx_reg_read(ds, REG_GLOBAL, GLOBAL_STATS_COUNTER_32);
Lennert Buytenhek91da11f2008-10-07 13:44:02 +0000607 if (ret < 0)
608 return;
609
610 _val = ret << 16;
611
Andrew Lunn31888232015-05-06 01:09:54 +0200612 ret = _mv88e6xxx_reg_read(ds, REG_GLOBAL, GLOBAL_STATS_COUNTER_01);
Lennert Buytenhek91da11f2008-10-07 13:44:02 +0000613 if (ret < 0)
614 return;
615
616 *val = _val | ret;
617}
618
Andrew Lunne413e7e2015-04-02 04:06:38 +0200619static struct mv88e6xxx_hw_stat mv88e6xxx_hw_stats[] = {
620 { "in_good_octets", 8, 0x00, },
621 { "in_bad_octets", 4, 0x02, },
622 { "in_unicast", 4, 0x04, },
623 { "in_broadcasts", 4, 0x06, },
624 { "in_multicasts", 4, 0x07, },
625 { "in_pause", 4, 0x16, },
626 { "in_undersize", 4, 0x18, },
627 { "in_fragments", 4, 0x19, },
628 { "in_oversize", 4, 0x1a, },
629 { "in_jabber", 4, 0x1b, },
630 { "in_rx_error", 4, 0x1c, },
631 { "in_fcs_error", 4, 0x1d, },
632 { "out_octets", 8, 0x0e, },
633 { "out_unicast", 4, 0x10, },
634 { "out_broadcasts", 4, 0x13, },
635 { "out_multicasts", 4, 0x12, },
636 { "out_pause", 4, 0x15, },
637 { "excessive", 4, 0x11, },
638 { "collisions", 4, 0x1e, },
639 { "deferred", 4, 0x05, },
640 { "single", 4, 0x14, },
641 { "multiple", 4, 0x17, },
642 { "out_fcs_error", 4, 0x03, },
643 { "late", 4, 0x1f, },
644 { "hist_64bytes", 4, 0x08, },
645 { "hist_65_127bytes", 4, 0x09, },
646 { "hist_128_255bytes", 4, 0x0a, },
647 { "hist_256_511bytes", 4, 0x0b, },
648 { "hist_512_1023bytes", 4, 0x0c, },
649 { "hist_1024_max_bytes", 4, 0x0d, },
650 /* Not all devices have the following counters */
651 { "sw_in_discards", 4, 0x110, },
652 { "sw_in_filtered", 2, 0x112, },
653 { "sw_out_filtered", 2, 0x113, },
654
655};
656
657static bool have_sw_in_discards(struct dsa_switch *ds)
658{
659 struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
660
661 switch (ps->id) {
Andrew Lunncca8b132015-04-02 04:06:39 +0200662 case PORT_SWITCH_ID_6095: case PORT_SWITCH_ID_6161:
663 case PORT_SWITCH_ID_6165: case PORT_SWITCH_ID_6171:
664 case PORT_SWITCH_ID_6172: case PORT_SWITCH_ID_6176:
665 case PORT_SWITCH_ID_6182: case PORT_SWITCH_ID_6185:
666 case PORT_SWITCH_ID_6352:
Andrew Lunne413e7e2015-04-02 04:06:38 +0200667 return true;
668 default:
669 return false;
670 }
671}
672
673static void _mv88e6xxx_get_strings(struct dsa_switch *ds,
674 int nr_stats,
675 struct mv88e6xxx_hw_stat *stats,
676 int port, uint8_t *data)
Lennert Buytenhek91da11f2008-10-07 13:44:02 +0000677{
678 int i;
679
680 for (i = 0; i < nr_stats; i++) {
681 memcpy(data + i * ETH_GSTRING_LEN,
682 stats[i].string, ETH_GSTRING_LEN);
683 }
684}
685
Andrew Lunn80c46272015-06-20 18:42:30 +0200686static uint64_t _mv88e6xxx_get_ethtool_stat(struct dsa_switch *ds,
687 int stat,
688 struct mv88e6xxx_hw_stat *stats,
689 int port)
690{
691 struct mv88e6xxx_hw_stat *s = stats + stat;
692 u32 low;
693 u32 high = 0;
694 int ret;
695 u64 value;
696
697 if (s->reg >= 0x100) {
698 ret = _mv88e6xxx_reg_read(ds, REG_PORT(port),
699 s->reg - 0x100);
700 if (ret < 0)
701 return UINT64_MAX;
702
703 low = ret;
704 if (s->sizeof_stat == 4) {
705 ret = _mv88e6xxx_reg_read(ds, REG_PORT(port),
706 s->reg - 0x100 + 1);
707 if (ret < 0)
708 return UINT64_MAX;
709 high = ret;
710 }
711 } else {
712 _mv88e6xxx_stats_read(ds, s->reg, &low);
713 if (s->sizeof_stat == 8)
714 _mv88e6xxx_stats_read(ds, s->reg + 1, &high);
715 }
716 value = (((u64)high) << 16) | low;
717 return value;
718}
719
Andrew Lunne413e7e2015-04-02 04:06:38 +0200720static void _mv88e6xxx_get_ethtool_stats(struct dsa_switch *ds,
721 int nr_stats,
722 struct mv88e6xxx_hw_stat *stats,
723 int port, uint64_t *data)
Lennert Buytenhek91da11f2008-10-07 13:44:02 +0000724{
Florian Fainellia22adce2014-04-28 11:14:28 -0700725 struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
Lennert Buytenhek91da11f2008-10-07 13:44:02 +0000726 int ret;
727 int i;
728
Andrew Lunn31888232015-05-06 01:09:54 +0200729 mutex_lock(&ps->smi_mutex);
Lennert Buytenhek91da11f2008-10-07 13:44:02 +0000730
Andrew Lunn31888232015-05-06 01:09:54 +0200731 ret = _mv88e6xxx_stats_snapshot(ds, port);
Lennert Buytenhek91da11f2008-10-07 13:44:02 +0000732 if (ret < 0) {
Andrew Lunn31888232015-05-06 01:09:54 +0200733 mutex_unlock(&ps->smi_mutex);
Lennert Buytenhek91da11f2008-10-07 13:44:02 +0000734 return;
735 }
736
Barry Grussling3675c8d2013-01-08 16:05:53 +0000737 /* Read each of the counters. */
Andrew Lunn80c46272015-06-20 18:42:30 +0200738 for (i = 0; i < nr_stats; i++)
739 data[i] = _mv88e6xxx_get_ethtool_stat(ds, i, stats, port);
Lennert Buytenhek91da11f2008-10-07 13:44:02 +0000740
Andrew Lunn31888232015-05-06 01:09:54 +0200741 mutex_unlock(&ps->smi_mutex);
Lennert Buytenhek91da11f2008-10-07 13:44:02 +0000742}
Ben Hutchings98e67302011-11-25 14:36:19 +0000743
Andrew Lunne413e7e2015-04-02 04:06:38 +0200744/* All the statistics in the table */
745void
746mv88e6xxx_get_strings(struct dsa_switch *ds, int port, uint8_t *data)
747{
748 if (have_sw_in_discards(ds))
749 _mv88e6xxx_get_strings(ds, ARRAY_SIZE(mv88e6xxx_hw_stats),
750 mv88e6xxx_hw_stats, port, data);
751 else
752 _mv88e6xxx_get_strings(ds, ARRAY_SIZE(mv88e6xxx_hw_stats) - 3,
753 mv88e6xxx_hw_stats, port, data);
754}
755
756int mv88e6xxx_get_sset_count(struct dsa_switch *ds)
757{
758 if (have_sw_in_discards(ds))
759 return ARRAY_SIZE(mv88e6xxx_hw_stats);
760 return ARRAY_SIZE(mv88e6xxx_hw_stats) - 3;
761}
762
763void
764mv88e6xxx_get_ethtool_stats(struct dsa_switch *ds,
765 int port, uint64_t *data)
766{
767 if (have_sw_in_discards(ds))
768 _mv88e6xxx_get_ethtool_stats(
769 ds, ARRAY_SIZE(mv88e6xxx_hw_stats),
770 mv88e6xxx_hw_stats, port, data);
771 else
772 _mv88e6xxx_get_ethtool_stats(
773 ds, ARRAY_SIZE(mv88e6xxx_hw_stats) - 3,
774 mv88e6xxx_hw_stats, port, data);
775}
776
Guenter Roecka1ab91f2014-10-29 10:45:05 -0700777int mv88e6xxx_get_regs_len(struct dsa_switch *ds, int port)
778{
779 return 32 * sizeof(u16);
780}
781
782void mv88e6xxx_get_regs(struct dsa_switch *ds, int port,
783 struct ethtool_regs *regs, void *_p)
784{
785 u16 *p = _p;
786 int i;
787
788 regs->version = 0;
789
790 memset(p, 0xff, 32 * sizeof(u16));
791
792 for (i = 0; i < 32; i++) {
793 int ret;
794
795 ret = mv88e6xxx_reg_read(ds, REG_PORT(port), i);
796 if (ret >= 0)
797 p[i] = ret;
798 }
799}
800
Andrew Lunn3898c142015-05-06 01:09:53 +0200801static int _mv88e6xxx_wait(struct dsa_switch *ds, int reg, int offset,
802 u16 mask)
Guenter Roeckfacd95b2015-03-26 18:36:35 -0700803{
804 unsigned long timeout = jiffies + HZ / 10;
805
806 while (time_before(jiffies, timeout)) {
807 int ret;
808
809 ret = _mv88e6xxx_reg_read(ds, reg, offset);
810 if (ret < 0)
811 return ret;
812 if (!(ret & mask))
813 return 0;
814
815 usleep_range(1000, 2000);
816 }
817 return -ETIMEDOUT;
818}
819
Andrew Lunn3898c142015-05-06 01:09:53 +0200820static int mv88e6xxx_wait(struct dsa_switch *ds, int reg, int offset, u16 mask)
821{
822 struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
823 int ret;
824
825 mutex_lock(&ps->smi_mutex);
826 ret = _mv88e6xxx_wait(ds, reg, offset, mask);
827 mutex_unlock(&ps->smi_mutex);
828
829 return ret;
830}
831
832static int _mv88e6xxx_phy_wait(struct dsa_switch *ds)
833{
834 return _mv88e6xxx_wait(ds, REG_GLOBAL2, GLOBAL2_SMI_OP,
835 GLOBAL2_SMI_OP_BUSY);
836}
837
838int mv88e6xxx_eeprom_load_wait(struct dsa_switch *ds)
839{
840 return mv88e6xxx_wait(ds, REG_GLOBAL2, GLOBAL2_EEPROM_OP,
841 GLOBAL2_EEPROM_OP_LOAD);
842}
843
844int mv88e6xxx_eeprom_busy_wait(struct dsa_switch *ds)
845{
846 return mv88e6xxx_wait(ds, REG_GLOBAL2, GLOBAL2_EEPROM_OP,
847 GLOBAL2_EEPROM_OP_BUSY);
848}
849
Guenter Roeckfacd95b2015-03-26 18:36:35 -0700850static int _mv88e6xxx_atu_wait(struct dsa_switch *ds)
851{
Andrew Lunncca8b132015-04-02 04:06:39 +0200852 return _mv88e6xxx_wait(ds, REG_GLOBAL, GLOBAL_ATU_OP,
853 GLOBAL_ATU_OP_BUSY);
Guenter Roeckfacd95b2015-03-26 18:36:35 -0700854}
855
Andrew Lunnfd3a0ee2015-04-02 04:06:36 +0200856static int _mv88e6xxx_phy_read_indirect(struct dsa_switch *ds, int addr,
857 int regnum)
Andrew Lunnf3044682015-02-14 19:17:50 +0100858{
859 int ret;
860
Andrew Lunn3898c142015-05-06 01:09:53 +0200861 ret = _mv88e6xxx_reg_write(ds, REG_GLOBAL2, GLOBAL2_SMI_OP,
862 GLOBAL2_SMI_OP_22_READ | (addr << 5) |
863 regnum);
Andrew Lunnf3044682015-02-14 19:17:50 +0100864 if (ret < 0)
865 return ret;
866
Andrew Lunn3898c142015-05-06 01:09:53 +0200867 ret = _mv88e6xxx_phy_wait(ds);
868 if (ret < 0)
869 return ret;
870
871 return _mv88e6xxx_reg_read(ds, REG_GLOBAL2, GLOBAL2_SMI_DATA);
Andrew Lunnf3044682015-02-14 19:17:50 +0100872}
873
Andrew Lunnfd3a0ee2015-04-02 04:06:36 +0200874static int _mv88e6xxx_phy_write_indirect(struct dsa_switch *ds, int addr,
875 int regnum, u16 val)
Andrew Lunnf3044682015-02-14 19:17:50 +0100876{
Andrew Lunn3898c142015-05-06 01:09:53 +0200877 int ret;
Andrew Lunnf3044682015-02-14 19:17:50 +0100878
Andrew Lunn3898c142015-05-06 01:09:53 +0200879 ret = _mv88e6xxx_reg_write(ds, REG_GLOBAL2, GLOBAL2_SMI_DATA, val);
880 if (ret < 0)
881 return ret;
882
883 ret = _mv88e6xxx_reg_write(ds, REG_GLOBAL2, GLOBAL2_SMI_OP,
884 GLOBAL2_SMI_OP_22_WRITE | (addr << 5) |
885 regnum);
886
887 return _mv88e6xxx_phy_wait(ds);
Andrew Lunnf3044682015-02-14 19:17:50 +0100888}
889
Guenter Roeck11b3b452015-03-06 22:23:51 -0800890int mv88e6xxx_get_eee(struct dsa_switch *ds, int port, struct ethtool_eee *e)
891{
Andrew Lunn2f40c692015-04-02 04:06:37 +0200892 struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
Guenter Roeck11b3b452015-03-06 22:23:51 -0800893 int reg;
894
Andrew Lunn3898c142015-05-06 01:09:53 +0200895 mutex_lock(&ps->smi_mutex);
Andrew Lunn2f40c692015-04-02 04:06:37 +0200896
897 reg = _mv88e6xxx_phy_read_indirect(ds, port, 16);
Guenter Roeck11b3b452015-03-06 22:23:51 -0800898 if (reg < 0)
Andrew Lunn2f40c692015-04-02 04:06:37 +0200899 goto out;
Guenter Roeck11b3b452015-03-06 22:23:51 -0800900
901 e->eee_enabled = !!(reg & 0x0200);
902 e->tx_lpi_enabled = !!(reg & 0x0100);
903
Andrew Lunn3898c142015-05-06 01:09:53 +0200904 reg = _mv88e6xxx_reg_read(ds, REG_PORT(port), PORT_STATUS);
Guenter Roeck11b3b452015-03-06 22:23:51 -0800905 if (reg < 0)
Andrew Lunn2f40c692015-04-02 04:06:37 +0200906 goto out;
Guenter Roeck11b3b452015-03-06 22:23:51 -0800907
Andrew Lunncca8b132015-04-02 04:06:39 +0200908 e->eee_active = !!(reg & PORT_STATUS_EEE);
Andrew Lunn2f40c692015-04-02 04:06:37 +0200909 reg = 0;
Guenter Roeck11b3b452015-03-06 22:23:51 -0800910
Andrew Lunn2f40c692015-04-02 04:06:37 +0200911out:
Andrew Lunn3898c142015-05-06 01:09:53 +0200912 mutex_unlock(&ps->smi_mutex);
Andrew Lunn2f40c692015-04-02 04:06:37 +0200913 return reg;
Guenter Roeck11b3b452015-03-06 22:23:51 -0800914}
915
916int mv88e6xxx_set_eee(struct dsa_switch *ds, int port,
917 struct phy_device *phydev, struct ethtool_eee *e)
918{
Andrew Lunn2f40c692015-04-02 04:06:37 +0200919 struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
920 int reg;
Guenter Roeck11b3b452015-03-06 22:23:51 -0800921 int ret;
922
Andrew Lunn3898c142015-05-06 01:09:53 +0200923 mutex_lock(&ps->smi_mutex);
Guenter Roeck11b3b452015-03-06 22:23:51 -0800924
Andrew Lunn2f40c692015-04-02 04:06:37 +0200925 ret = _mv88e6xxx_phy_read_indirect(ds, port, 16);
926 if (ret < 0)
927 goto out;
928
929 reg = ret & ~0x0300;
930 if (e->eee_enabled)
931 reg |= 0x0200;
932 if (e->tx_lpi_enabled)
933 reg |= 0x0100;
934
935 ret = _mv88e6xxx_phy_write_indirect(ds, port, 16, reg);
936out:
Andrew Lunn3898c142015-05-06 01:09:53 +0200937 mutex_unlock(&ps->smi_mutex);
Andrew Lunn2f40c692015-04-02 04:06:37 +0200938
939 return ret;
Guenter Roeck11b3b452015-03-06 22:23:51 -0800940}
941
Vivien Didelot70cc99d2015-09-04 14:34:10 -0400942static int _mv88e6xxx_atu_cmd(struct dsa_switch *ds, u16 cmd)
Guenter Roeckfacd95b2015-03-26 18:36:35 -0700943{
944 int ret;
945
Andrew Lunncca8b132015-04-02 04:06:39 +0200946 ret = _mv88e6xxx_reg_write(ds, REG_GLOBAL, GLOBAL_ATU_OP, cmd);
Guenter Roeckfacd95b2015-03-26 18:36:35 -0700947 if (ret < 0)
948 return ret;
949
950 return _mv88e6xxx_atu_wait(ds);
951}
952
Vivien Didelot37705b72015-09-04 14:34:11 -0400953static int _mv88e6xxx_atu_data_write(struct dsa_switch *ds,
954 struct mv88e6xxx_atu_entry *entry)
955{
956 u16 data = entry->state & GLOBAL_ATU_DATA_STATE_MASK;
957
958 if (entry->state != GLOBAL_ATU_DATA_STATE_UNUSED) {
959 unsigned int mask, shift;
960
961 if (entry->trunk) {
962 data |= GLOBAL_ATU_DATA_TRUNK;
963 mask = GLOBAL_ATU_DATA_TRUNK_ID_MASK;
964 shift = GLOBAL_ATU_DATA_TRUNK_ID_SHIFT;
965 } else {
966 mask = GLOBAL_ATU_DATA_PORT_VECTOR_MASK;
967 shift = GLOBAL_ATU_DATA_PORT_VECTOR_SHIFT;
968 }
969
970 data |= (entry->portv_trunkid << shift) & mask;
971 }
972
973 return _mv88e6xxx_reg_write(ds, REG_GLOBAL, GLOBAL_ATU_DATA, data);
974}
975
Vivien Didelot7fb5e752015-09-04 14:34:12 -0400976static int _mv88e6xxx_atu_flush_move(struct dsa_switch *ds,
977 struct mv88e6xxx_atu_entry *entry,
978 bool static_too)
979{
980 int op;
981 int err;
982
983 err = _mv88e6xxx_atu_wait(ds);
984 if (err)
985 return err;
986
987 err = _mv88e6xxx_atu_data_write(ds, entry);
988 if (err)
989 return err;
990
991 if (entry->fid) {
992 err = _mv88e6xxx_reg_write(ds, REG_GLOBAL, GLOBAL_ATU_FID,
993 entry->fid);
994 if (err)
995 return err;
996
997 op = static_too ? GLOBAL_ATU_OP_FLUSH_MOVE_ALL_DB :
998 GLOBAL_ATU_OP_FLUSH_MOVE_NON_STATIC_DB;
999 } else {
1000 op = static_too ? GLOBAL_ATU_OP_FLUSH_MOVE_ALL :
1001 GLOBAL_ATU_OP_FLUSH_MOVE_NON_STATIC;
1002 }
1003
1004 return _mv88e6xxx_atu_cmd(ds, op);
1005}
1006
1007static int _mv88e6xxx_atu_flush(struct dsa_switch *ds, u16 fid, bool static_too)
1008{
1009 struct mv88e6xxx_atu_entry entry = {
1010 .fid = fid,
1011 .state = 0, /* EntryState bits must be 0 */
1012 };
1013
1014 return _mv88e6xxx_atu_flush_move(ds, &entry, static_too);
1015}
1016
Vivien Didelot9f4d55d2015-09-04 14:34:15 -04001017static int _mv88e6xxx_atu_move(struct dsa_switch *ds, u16 fid, int from_port,
1018 int to_port, bool static_too)
1019{
1020 struct mv88e6xxx_atu_entry entry = {
1021 .trunk = false,
1022 .fid = fid,
1023 };
1024
1025 /* EntryState bits must be 0xF */
1026 entry.state = GLOBAL_ATU_DATA_STATE_MASK;
1027
1028 /* ToPort and FromPort are respectively in PortVec bits 7:4 and 3:0 */
1029 entry.portv_trunkid = (to_port & 0x0f) << 4;
1030 entry.portv_trunkid |= from_port & 0x0f;
1031
1032 return _mv88e6xxx_atu_flush_move(ds, &entry, static_too);
1033}
1034
1035static int _mv88e6xxx_atu_remove(struct dsa_switch *ds, u16 fid, int port,
1036 bool static_too)
1037{
1038 /* Destination port 0xF means remove the entries */
1039 return _mv88e6xxx_atu_move(ds, fid, port, 0x0f, static_too);
1040}
1041
Guenter Roeckfacd95b2015-03-26 18:36:35 -07001042static int mv88e6xxx_set_port_state(struct dsa_switch *ds, int port, u8 state)
1043{
1044 struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
Geert Uytterhoevenc3ffe6d2015-04-16 20:49:14 +02001045 int reg, ret = 0;
Guenter Roeckfacd95b2015-03-26 18:36:35 -07001046 u8 oldstate;
1047
1048 mutex_lock(&ps->smi_mutex);
1049
Andrew Lunncca8b132015-04-02 04:06:39 +02001050 reg = _mv88e6xxx_reg_read(ds, REG_PORT(port), PORT_CONTROL);
Guenter Roeck538cc282015-04-15 22:12:42 -07001051 if (reg < 0) {
1052 ret = reg;
Guenter Roeckfacd95b2015-03-26 18:36:35 -07001053 goto abort;
Guenter Roeck538cc282015-04-15 22:12:42 -07001054 }
Guenter Roeckfacd95b2015-03-26 18:36:35 -07001055
Andrew Lunncca8b132015-04-02 04:06:39 +02001056 oldstate = reg & PORT_CONTROL_STATE_MASK;
Guenter Roeckfacd95b2015-03-26 18:36:35 -07001057 if (oldstate != state) {
1058 /* Flush forwarding database if we're moving a port
1059 * from Learning or Forwarding state to Disabled or
1060 * Blocking or Listening state.
1061 */
Andrew Lunncca8b132015-04-02 04:06:39 +02001062 if (oldstate >= PORT_CONTROL_STATE_LEARNING &&
1063 state <= PORT_CONTROL_STATE_BLOCKING) {
Vivien Didelot2b8157b2015-09-04 14:34:16 -04001064 ret = _mv88e6xxx_atu_remove(ds, 0, port, false);
Guenter Roeckfacd95b2015-03-26 18:36:35 -07001065 if (ret)
1066 goto abort;
1067 }
Andrew Lunncca8b132015-04-02 04:06:39 +02001068 reg = (reg & ~PORT_CONTROL_STATE_MASK) | state;
1069 ret = _mv88e6xxx_reg_write(ds, REG_PORT(port), PORT_CONTROL,
1070 reg);
Guenter Roeckfacd95b2015-03-26 18:36:35 -07001071 }
1072
1073abort:
1074 mutex_unlock(&ps->smi_mutex);
1075 return ret;
1076}
1077
Vivien Didelotede80982015-10-11 18:08:35 -04001078static int _mv88e6xxx_port_vlan_map_set(struct dsa_switch *ds, int port,
1079 u16 output_ports)
Guenter Roeckfacd95b2015-03-26 18:36:35 -07001080{
1081 struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
Vivien Didelotede80982015-10-11 18:08:35 -04001082 const u16 mask = (1 << ps->num_ports) - 1;
1083 int reg;
Guenter Roeckfacd95b2015-03-26 18:36:35 -07001084
Vivien Didelotede80982015-10-11 18:08:35 -04001085 reg = _mv88e6xxx_reg_read(ds, REG_PORT(port), PORT_BASE_VLAN);
1086 if (reg < 0)
1087 return reg;
1088
1089 reg &= ~mask;
1090 reg |= output_ports & mask;
Guenter Roeckfacd95b2015-03-26 18:36:35 -07001091
Andrew Lunncca8b132015-04-02 04:06:39 +02001092 return _mv88e6xxx_reg_write(ds, REG_PORT(port), PORT_BASE_VLAN, reg);
Guenter Roeckfacd95b2015-03-26 18:36:35 -07001093}
1094
Guenter Roeckfacd95b2015-03-26 18:36:35 -07001095int mv88e6xxx_port_stp_update(struct dsa_switch *ds, int port, u8 state)
1096{
1097 struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
1098 int stp_state;
1099
1100 switch (state) {
1101 case BR_STATE_DISABLED:
Andrew Lunncca8b132015-04-02 04:06:39 +02001102 stp_state = PORT_CONTROL_STATE_DISABLED;
Guenter Roeckfacd95b2015-03-26 18:36:35 -07001103 break;
1104 case BR_STATE_BLOCKING:
1105 case BR_STATE_LISTENING:
Andrew Lunncca8b132015-04-02 04:06:39 +02001106 stp_state = PORT_CONTROL_STATE_BLOCKING;
Guenter Roeckfacd95b2015-03-26 18:36:35 -07001107 break;
1108 case BR_STATE_LEARNING:
Andrew Lunncca8b132015-04-02 04:06:39 +02001109 stp_state = PORT_CONTROL_STATE_LEARNING;
Guenter Roeckfacd95b2015-03-26 18:36:35 -07001110 break;
1111 case BR_STATE_FORWARDING:
1112 default:
Andrew Lunncca8b132015-04-02 04:06:39 +02001113 stp_state = PORT_CONTROL_STATE_FORWARDING;
Guenter Roeckfacd95b2015-03-26 18:36:35 -07001114 break;
1115 }
1116
1117 netdev_dbg(ds->ports[port], "port state %d [%d]\n", state, stp_state);
1118
1119 /* mv88e6xxx_port_stp_update may be called with softirqs disabled,
1120 * so we can not update the port state directly but need to schedule it.
1121 */
1122 ps->port_state[port] = stp_state;
1123 set_bit(port, &ps->port_state_update_mask);
1124 schedule_work(&ps->bridge_work);
1125
1126 return 0;
1127}
1128
Vivien Didelot76e398a2015-11-01 12:33:55 -05001129static int _mv88e6xxx_port_pvid_get(struct dsa_switch *ds, int port, u16 *pvid)
1130{
1131 int ret;
1132
1133 ret = _mv88e6xxx_reg_read(ds, REG_PORT(port), PORT_DEFAULT_VLAN);
1134 if (ret < 0)
1135 return ret;
1136
1137 *pvid = ret & PORT_DEFAULT_VLAN_MASK;
1138
1139 return 0;
1140}
1141
Vivien Didelotb8fee952015-08-13 12:52:19 -04001142int mv88e6xxx_port_pvid_get(struct dsa_switch *ds, int port, u16 *pvid)
1143{
1144 int ret;
1145
1146 ret = mv88e6xxx_reg_read(ds, REG_PORT(port), PORT_DEFAULT_VLAN);
1147 if (ret < 0)
1148 return ret;
1149
1150 *pvid = ret & PORT_DEFAULT_VLAN_MASK;
1151
1152 return 0;
1153}
1154
Vivien Didelot76e398a2015-11-01 12:33:55 -05001155static int _mv88e6xxx_port_pvid_set(struct dsa_switch *ds, int port, u16 pvid)
Vivien Didelot0d3b33e2015-08-13 12:52:22 -04001156{
Vivien Didelot76e398a2015-11-01 12:33:55 -05001157 return _mv88e6xxx_reg_write(ds, REG_PORT(port), PORT_DEFAULT_VLAN,
Vivien Didelot0d3b33e2015-08-13 12:52:22 -04001158 pvid & PORT_DEFAULT_VLAN_MASK);
1159}
1160
Vivien Didelot6b17e862015-08-13 12:52:18 -04001161static int _mv88e6xxx_vtu_wait(struct dsa_switch *ds)
1162{
1163 return _mv88e6xxx_wait(ds, REG_GLOBAL, GLOBAL_VTU_OP,
1164 GLOBAL_VTU_OP_BUSY);
1165}
1166
1167static int _mv88e6xxx_vtu_cmd(struct dsa_switch *ds, u16 op)
1168{
1169 int ret;
1170
1171 ret = _mv88e6xxx_reg_write(ds, REG_GLOBAL, GLOBAL_VTU_OP, op);
1172 if (ret < 0)
1173 return ret;
1174
1175 return _mv88e6xxx_vtu_wait(ds);
1176}
1177
1178static int _mv88e6xxx_vtu_stu_flush(struct dsa_switch *ds)
1179{
1180 int ret;
1181
1182 ret = _mv88e6xxx_vtu_wait(ds);
1183 if (ret < 0)
1184 return ret;
1185
1186 return _mv88e6xxx_vtu_cmd(ds, GLOBAL_VTU_OP_FLUSH_ALL);
1187}
1188
Vivien Didelotb8fee952015-08-13 12:52:19 -04001189static int _mv88e6xxx_vtu_stu_data_read(struct dsa_switch *ds,
1190 struct mv88e6xxx_vtu_stu_entry *entry,
1191 unsigned int nibble_offset)
1192{
1193 struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
1194 u16 regs[3];
1195 int i;
1196 int ret;
1197
1198 for (i = 0; i < 3; ++i) {
1199 ret = _mv88e6xxx_reg_read(ds, REG_GLOBAL,
1200 GLOBAL_VTU_DATA_0_3 + i);
1201 if (ret < 0)
1202 return ret;
1203
1204 regs[i] = ret;
1205 }
1206
1207 for (i = 0; i < ps->num_ports; ++i) {
1208 unsigned int shift = (i % 4) * 4 + nibble_offset;
1209 u16 reg = regs[i / 4];
1210
1211 entry->data[i] = (reg >> shift) & GLOBAL_VTU_STU_DATA_MASK;
1212 }
1213
1214 return 0;
1215}
1216
Vivien Didelot7dad08d2015-08-13 12:52:21 -04001217static int _mv88e6xxx_vtu_stu_data_write(struct dsa_switch *ds,
1218 struct mv88e6xxx_vtu_stu_entry *entry,
1219 unsigned int nibble_offset)
1220{
1221 struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
1222 u16 regs[3] = { 0 };
1223 int i;
1224 int ret;
1225
1226 for (i = 0; i < ps->num_ports; ++i) {
1227 unsigned int shift = (i % 4) * 4 + nibble_offset;
1228 u8 data = entry->data[i];
1229
1230 regs[i / 4] |= (data & GLOBAL_VTU_STU_DATA_MASK) << shift;
1231 }
1232
1233 for (i = 0; i < 3; ++i) {
1234 ret = _mv88e6xxx_reg_write(ds, REG_GLOBAL,
1235 GLOBAL_VTU_DATA_0_3 + i, regs[i]);
1236 if (ret < 0)
1237 return ret;
1238 }
1239
1240 return 0;
1241}
1242
Vivien Didelot36d04ba2015-10-22 09:34:39 -04001243static int _mv88e6xxx_vtu_vid_write(struct dsa_switch *ds, u16 vid)
1244{
1245 return _mv88e6xxx_reg_write(ds, REG_GLOBAL, GLOBAL_VTU_VID,
1246 vid & GLOBAL_VTU_VID_MASK);
1247}
1248
1249static int _mv88e6xxx_vtu_getnext(struct dsa_switch *ds,
Vivien Didelotb8fee952015-08-13 12:52:19 -04001250 struct mv88e6xxx_vtu_stu_entry *entry)
1251{
1252 struct mv88e6xxx_vtu_stu_entry next = { 0 };
1253 int ret;
1254
1255 ret = _mv88e6xxx_vtu_wait(ds);
1256 if (ret < 0)
1257 return ret;
1258
Vivien Didelotb8fee952015-08-13 12:52:19 -04001259 ret = _mv88e6xxx_vtu_cmd(ds, GLOBAL_VTU_OP_VTU_GET_NEXT);
1260 if (ret < 0)
1261 return ret;
1262
1263 ret = _mv88e6xxx_reg_read(ds, REG_GLOBAL, GLOBAL_VTU_VID);
1264 if (ret < 0)
1265 return ret;
1266
1267 next.vid = ret & GLOBAL_VTU_VID_MASK;
1268 next.valid = !!(ret & GLOBAL_VTU_VID_VALID);
1269
1270 if (next.valid) {
1271 ret = _mv88e6xxx_vtu_stu_data_read(ds, &next, 0);
1272 if (ret < 0)
1273 return ret;
1274
1275 if (mv88e6xxx_6097_family(ds) || mv88e6xxx_6165_family(ds) ||
1276 mv88e6xxx_6351_family(ds) || mv88e6xxx_6352_family(ds)) {
1277 ret = _mv88e6xxx_reg_read(ds, REG_GLOBAL,
1278 GLOBAL_VTU_FID);
1279 if (ret < 0)
1280 return ret;
1281
1282 next.fid = ret & GLOBAL_VTU_FID_MASK;
1283
1284 ret = _mv88e6xxx_reg_read(ds, REG_GLOBAL,
1285 GLOBAL_VTU_SID);
1286 if (ret < 0)
1287 return ret;
1288
1289 next.sid = ret & GLOBAL_VTU_SID_MASK;
1290 }
1291 }
1292
1293 *entry = next;
1294 return 0;
1295}
1296
Vivien Didelot7dad08d2015-08-13 12:52:21 -04001297static int _mv88e6xxx_vtu_loadpurge(struct dsa_switch *ds,
1298 struct mv88e6xxx_vtu_stu_entry *entry)
1299{
1300 u16 reg = 0;
1301 int ret;
1302
1303 ret = _mv88e6xxx_vtu_wait(ds);
1304 if (ret < 0)
1305 return ret;
1306
1307 if (!entry->valid)
1308 goto loadpurge;
1309
1310 /* Write port member tags */
1311 ret = _mv88e6xxx_vtu_stu_data_write(ds, entry, 0);
1312 if (ret < 0)
1313 return ret;
1314
1315 if (mv88e6xxx_6097_family(ds) || mv88e6xxx_6165_family(ds) ||
1316 mv88e6xxx_6351_family(ds) || mv88e6xxx_6352_family(ds)) {
1317 reg = entry->sid & GLOBAL_VTU_SID_MASK;
1318 ret = _mv88e6xxx_reg_write(ds, REG_GLOBAL, GLOBAL_VTU_SID, reg);
1319 if (ret < 0)
1320 return ret;
1321
1322 reg = entry->fid & GLOBAL_VTU_FID_MASK;
1323 ret = _mv88e6xxx_reg_write(ds, REG_GLOBAL, GLOBAL_VTU_FID, reg);
1324 if (ret < 0)
1325 return ret;
1326 }
1327
1328 reg = GLOBAL_VTU_VID_VALID;
1329loadpurge:
1330 reg |= entry->vid & GLOBAL_VTU_VID_MASK;
1331 ret = _mv88e6xxx_reg_write(ds, REG_GLOBAL, GLOBAL_VTU_VID, reg);
1332 if (ret < 0)
1333 return ret;
1334
1335 return _mv88e6xxx_vtu_cmd(ds, GLOBAL_VTU_OP_VTU_LOAD_PURGE);
1336}
1337
Vivien Didelot0d3b33e2015-08-13 12:52:22 -04001338static int _mv88e6xxx_stu_getnext(struct dsa_switch *ds, u8 sid,
1339 struct mv88e6xxx_vtu_stu_entry *entry)
1340{
1341 struct mv88e6xxx_vtu_stu_entry next = { 0 };
1342 int ret;
1343
1344 ret = _mv88e6xxx_vtu_wait(ds);
1345 if (ret < 0)
1346 return ret;
1347
1348 ret = _mv88e6xxx_reg_write(ds, REG_GLOBAL, GLOBAL_VTU_SID,
1349 sid & GLOBAL_VTU_SID_MASK);
1350 if (ret < 0)
1351 return ret;
1352
1353 ret = _mv88e6xxx_vtu_cmd(ds, GLOBAL_VTU_OP_STU_GET_NEXT);
1354 if (ret < 0)
1355 return ret;
1356
1357 ret = _mv88e6xxx_reg_read(ds, REG_GLOBAL, GLOBAL_VTU_SID);
1358 if (ret < 0)
1359 return ret;
1360
1361 next.sid = ret & GLOBAL_VTU_SID_MASK;
1362
1363 ret = _mv88e6xxx_reg_read(ds, REG_GLOBAL, GLOBAL_VTU_VID);
1364 if (ret < 0)
1365 return ret;
1366
1367 next.valid = !!(ret & GLOBAL_VTU_VID_VALID);
1368
1369 if (next.valid) {
1370 ret = _mv88e6xxx_vtu_stu_data_read(ds, &next, 2);
1371 if (ret < 0)
1372 return ret;
1373 }
1374
1375 *entry = next;
1376 return 0;
1377}
1378
1379static int _mv88e6xxx_stu_loadpurge(struct dsa_switch *ds,
1380 struct mv88e6xxx_vtu_stu_entry *entry)
1381{
1382 u16 reg = 0;
1383 int ret;
1384
1385 ret = _mv88e6xxx_vtu_wait(ds);
1386 if (ret < 0)
1387 return ret;
1388
1389 if (!entry->valid)
1390 goto loadpurge;
1391
1392 /* Write port states */
1393 ret = _mv88e6xxx_vtu_stu_data_write(ds, entry, 2);
1394 if (ret < 0)
1395 return ret;
1396
1397 reg = GLOBAL_VTU_VID_VALID;
1398loadpurge:
1399 ret = _mv88e6xxx_reg_write(ds, REG_GLOBAL, GLOBAL_VTU_VID, reg);
1400 if (ret < 0)
1401 return ret;
1402
1403 reg = entry->sid & GLOBAL_VTU_SID_MASK;
1404 ret = _mv88e6xxx_reg_write(ds, REG_GLOBAL, GLOBAL_VTU_SID, reg);
1405 if (ret < 0)
1406 return ret;
1407
1408 return _mv88e6xxx_vtu_cmd(ds, GLOBAL_VTU_OP_STU_LOAD_PURGE);
1409}
1410
1411static int _mv88e6xxx_vlan_init(struct dsa_switch *ds, u16 vid,
1412 struct mv88e6xxx_vtu_stu_entry *entry)
1413{
1414 struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
1415 struct mv88e6xxx_vtu_stu_entry vlan = {
1416 .valid = true,
1417 .vid = vid,
Vivien Didelotf02bdff2015-10-11 18:08:36 -04001418 .fid = vid, /* We use one FID per VLAN */
Vivien Didelot0d3b33e2015-08-13 12:52:22 -04001419 };
1420 int i;
1421
Vivien Didelot3d131f02015-11-03 10:52:52 -05001422 /* exclude all ports except the CPU and DSA ports */
Vivien Didelot0d3b33e2015-08-13 12:52:22 -04001423 for (i = 0; i < ps->num_ports; ++i)
Vivien Didelot3d131f02015-11-03 10:52:52 -05001424 vlan.data[i] = dsa_is_cpu_port(ds, i) || dsa_is_dsa_port(ds, i)
1425 ? GLOBAL_VTU_DATA_MEMBER_TAG_UNMODIFIED
1426 : GLOBAL_VTU_DATA_MEMBER_TAG_NON_MEMBER;
Vivien Didelot0d3b33e2015-08-13 12:52:22 -04001427
1428 if (mv88e6xxx_6097_family(ds) || mv88e6xxx_6165_family(ds) ||
1429 mv88e6xxx_6351_family(ds) || mv88e6xxx_6352_family(ds)) {
1430 struct mv88e6xxx_vtu_stu_entry vstp;
1431 int err;
1432
1433 /* Adding a VTU entry requires a valid STU entry. As VSTP is not
1434 * implemented, only one STU entry is needed to cover all VTU
1435 * entries. Thus, validate the SID 0.
1436 */
1437 vlan.sid = 0;
1438 err = _mv88e6xxx_stu_getnext(ds, GLOBAL_VTU_SID_MASK, &vstp);
1439 if (err)
1440 return err;
1441
1442 if (vstp.sid != vlan.sid || !vstp.valid) {
1443 memset(&vstp, 0, sizeof(vstp));
1444 vstp.valid = true;
1445 vstp.sid = vlan.sid;
1446
1447 err = _mv88e6xxx_stu_loadpurge(ds, &vstp);
1448 if (err)
1449 return err;
1450 }
1451
Vivien Didelot7c400012015-09-04 14:34:14 -04001452 /* Clear all MAC addresses from the new database */
1453 err = _mv88e6xxx_atu_flush(ds, vlan.fid, true);
Vivien Didelot0d3b33e2015-08-13 12:52:22 -04001454 if (err)
1455 return err;
Vivien Didelot0d3b33e2015-08-13 12:52:22 -04001456 }
1457
1458 *entry = vlan;
1459 return 0;
1460}
1461
Vivien Didelot76e398a2015-11-01 12:33:55 -05001462int mv88e6xxx_port_vlan_prepare(struct dsa_switch *ds, int port,
1463 const struct switchdev_obj_port_vlan *vlan,
1464 struct switchdev_trans *trans)
Vivien Didelot0d3b33e2015-08-13 12:52:22 -04001465{
Vivien Didelote79a8bc2015-11-04 17:23:40 -05001466 /* We reserve a few VLANs to isolate unbridged ports */
1467 if (vlan->vid_end >= 4000)
1468 return -EOPNOTSUPP;
1469
Vivien Didelot76e398a2015-11-01 12:33:55 -05001470 /* We don't need any dynamic resource from the kernel (yet),
1471 * so skip the prepare phase.
1472 */
1473 return 0;
1474}
1475
1476static int _mv88e6xxx_port_vlan_add(struct dsa_switch *ds, int port, u16 vid,
1477 bool untagged)
1478{
Vivien Didelot0d3b33e2015-08-13 12:52:22 -04001479 struct mv88e6xxx_vtu_stu_entry vlan;
1480 int err;
1481
Vivien Didelot36d04ba2015-10-22 09:34:39 -04001482 err = _mv88e6xxx_vtu_vid_write(ds, vid - 1);
1483 if (err)
Vivien Didelot76e398a2015-11-01 12:33:55 -05001484 return err;
Vivien Didelot36d04ba2015-10-22 09:34:39 -04001485
1486 err = _mv88e6xxx_vtu_getnext(ds, &vlan);
Vivien Didelot0d3b33e2015-08-13 12:52:22 -04001487 if (err)
Vivien Didelot76e398a2015-11-01 12:33:55 -05001488 return err;
Vivien Didelot0d3b33e2015-08-13 12:52:22 -04001489
1490 if (vlan.vid != vid || !vlan.valid) {
1491 err = _mv88e6xxx_vlan_init(ds, vid, &vlan);
1492 if (err)
Vivien Didelot76e398a2015-11-01 12:33:55 -05001493 return err;
Vivien Didelot0d3b33e2015-08-13 12:52:22 -04001494 }
1495
1496 vlan.data[port] = untagged ?
1497 GLOBAL_VTU_DATA_MEMBER_TAG_UNTAGGED :
1498 GLOBAL_VTU_DATA_MEMBER_TAG_TAGGED;
1499
Vivien Didelot76e398a2015-11-01 12:33:55 -05001500 return _mv88e6xxx_vtu_loadpurge(ds, &vlan);
1501}
1502
1503int mv88e6xxx_port_vlan_add(struct dsa_switch *ds, int port,
1504 const struct switchdev_obj_port_vlan *vlan,
1505 struct switchdev_trans *trans)
1506{
1507 struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
1508 bool untagged = vlan->flags & BRIDGE_VLAN_INFO_UNTAGGED;
1509 bool pvid = vlan->flags & BRIDGE_VLAN_INFO_PVID;
1510 u16 vid;
1511 int err = 0;
1512
1513 mutex_lock(&ps->smi_mutex);
1514
1515 for (vid = vlan->vid_begin; vid <= vlan->vid_end; ++vid) {
1516 err = _mv88e6xxx_port_vlan_add(ds, port, vid, untagged);
1517 if (err)
1518 goto unlock;
1519 }
1520
1521 /* no PVID with ranges, otherwise it's a bug */
1522 if (pvid)
1523 err = _mv88e6xxx_port_pvid_set(ds, port, vid);
Vivien Didelot0d3b33e2015-08-13 12:52:22 -04001524unlock:
1525 mutex_unlock(&ps->smi_mutex);
1526
1527 return err;
1528}
1529
Vivien Didelot76e398a2015-11-01 12:33:55 -05001530static int _mv88e6xxx_port_vlan_del(struct dsa_switch *ds, int port, u16 vid)
Vivien Didelot7dad08d2015-08-13 12:52:21 -04001531{
1532 struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
1533 struct mv88e6xxx_vtu_stu_entry vlan;
Vivien Didelot7dad08d2015-08-13 12:52:21 -04001534 int i, err;
1535
Vivien Didelot36d04ba2015-10-22 09:34:39 -04001536 err = _mv88e6xxx_vtu_vid_write(ds, vid - 1);
1537 if (err)
Vivien Didelot76e398a2015-11-01 12:33:55 -05001538 return err;
Vivien Didelot36d04ba2015-10-22 09:34:39 -04001539
1540 err = _mv88e6xxx_vtu_getnext(ds, &vlan);
Vivien Didelot7dad08d2015-08-13 12:52:21 -04001541 if (err)
Vivien Didelot76e398a2015-11-01 12:33:55 -05001542 return err;
Vivien Didelot7dad08d2015-08-13 12:52:21 -04001543
1544 if (vlan.vid != vid || !vlan.valid ||
Vivien Didelot76e398a2015-11-01 12:33:55 -05001545 vlan.data[port] == GLOBAL_VTU_DATA_MEMBER_TAG_NON_MEMBER)
1546 return -ENOENT;
Vivien Didelot7dad08d2015-08-13 12:52:21 -04001547
1548 vlan.data[port] = GLOBAL_VTU_DATA_MEMBER_TAG_NON_MEMBER;
1549
1550 /* keep the VLAN unless all ports are excluded */
Vivien Didelotf02bdff2015-10-11 18:08:36 -04001551 vlan.valid = false;
Vivien Didelot7dad08d2015-08-13 12:52:21 -04001552 for (i = 0; i < ps->num_ports; ++i) {
Vivien Didelot3d131f02015-11-03 10:52:52 -05001553 if (dsa_is_cpu_port(ds, i) || dsa_is_dsa_port(ds, i))
Vivien Didelot7dad08d2015-08-13 12:52:21 -04001554 continue;
1555
1556 if (vlan.data[i] != GLOBAL_VTU_DATA_MEMBER_TAG_NON_MEMBER) {
Vivien Didelotf02bdff2015-10-11 18:08:36 -04001557 vlan.valid = true;
Vivien Didelot7dad08d2015-08-13 12:52:21 -04001558 break;
1559 }
1560 }
1561
Vivien Didelot7dad08d2015-08-13 12:52:21 -04001562 err = _mv88e6xxx_vtu_loadpurge(ds, &vlan);
1563 if (err)
Vivien Didelot76e398a2015-11-01 12:33:55 -05001564 return err;
1565
1566 return _mv88e6xxx_atu_remove(ds, vlan.fid, port, false);
1567}
1568
1569int mv88e6xxx_port_vlan_del(struct dsa_switch *ds, int port,
1570 const struct switchdev_obj_port_vlan *vlan)
1571{
1572 struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
1573 u16 pvid, vid;
1574 int err = 0;
1575
1576 mutex_lock(&ps->smi_mutex);
1577
1578 err = _mv88e6xxx_port_pvid_get(ds, port, &pvid);
1579 if (err)
Vivien Didelot7dad08d2015-08-13 12:52:21 -04001580 goto unlock;
1581
Vivien Didelot76e398a2015-11-01 12:33:55 -05001582 for (vid = vlan->vid_begin; vid <= vlan->vid_end; ++vid) {
1583 err = _mv88e6xxx_port_vlan_del(ds, port, vid);
1584 if (err)
1585 goto unlock;
1586
1587 if (vid == pvid) {
1588 err = _mv88e6xxx_port_pvid_set(ds, port, 0);
1589 if (err)
1590 goto unlock;
1591 }
1592 }
1593
Vivien Didelot7dad08d2015-08-13 12:52:21 -04001594unlock:
1595 mutex_unlock(&ps->smi_mutex);
1596
1597 return err;
1598}
1599
Vivien Didelotb8fee952015-08-13 12:52:19 -04001600int mv88e6xxx_vlan_getnext(struct dsa_switch *ds, u16 *vid,
1601 unsigned long *ports, unsigned long *untagged)
1602{
1603 struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
1604 struct mv88e6xxx_vtu_stu_entry next;
1605 int port;
1606 int err;
1607
1608 if (*vid == 4095)
1609 return -ENOENT;
1610
1611 mutex_lock(&ps->smi_mutex);
Vivien Didelot36d04ba2015-10-22 09:34:39 -04001612 err = _mv88e6xxx_vtu_vid_write(ds, *vid);
1613 if (err)
1614 goto unlock;
1615
1616 err = _mv88e6xxx_vtu_getnext(ds, &next);
1617unlock:
Vivien Didelotb8fee952015-08-13 12:52:19 -04001618 mutex_unlock(&ps->smi_mutex);
1619
1620 if (err)
1621 return err;
1622
1623 if (!next.valid)
1624 return -ENOENT;
1625
1626 *vid = next.vid;
1627
1628 for (port = 0; port < ps->num_ports; ++port) {
1629 clear_bit(port, ports);
1630 clear_bit(port, untagged);
1631
Vivien Didelot3d131f02015-11-03 10:52:52 -05001632 if (dsa_is_cpu_port(ds, port) || dsa_is_dsa_port(ds, port))
Vivien Didelotb8fee952015-08-13 12:52:19 -04001633 continue;
1634
1635 if (next.data[port] == GLOBAL_VTU_DATA_MEMBER_TAG_TAGGED ||
1636 next.data[port] == GLOBAL_VTU_DATA_MEMBER_TAG_UNTAGGED)
1637 set_bit(port, ports);
1638
1639 if (next.data[port] == GLOBAL_VTU_DATA_MEMBER_TAG_UNTAGGED)
1640 set_bit(port, untagged);
1641 }
1642
1643 return 0;
1644}
1645
Vivien Didelotc5723ac2015-08-10 09:09:48 -04001646static int _mv88e6xxx_atu_mac_write(struct dsa_switch *ds,
1647 const unsigned char *addr)
Guenter Roeckdefb05b2015-03-26 18:36:38 -07001648{
1649 int i, ret;
1650
1651 for (i = 0; i < 3; i++) {
Andrew Lunncca8b132015-04-02 04:06:39 +02001652 ret = _mv88e6xxx_reg_write(
1653 ds, REG_GLOBAL, GLOBAL_ATU_MAC_01 + i,
1654 (addr[i * 2] << 8) | addr[i * 2 + 1]);
Guenter Roeckdefb05b2015-03-26 18:36:38 -07001655 if (ret < 0)
1656 return ret;
1657 }
1658
1659 return 0;
1660}
1661
Vivien Didelotc5723ac2015-08-10 09:09:48 -04001662static int _mv88e6xxx_atu_mac_read(struct dsa_switch *ds, unsigned char *addr)
Guenter Roeckdefb05b2015-03-26 18:36:38 -07001663{
1664 int i, ret;
1665
1666 for (i = 0; i < 3; i++) {
Andrew Lunncca8b132015-04-02 04:06:39 +02001667 ret = _mv88e6xxx_reg_read(ds, REG_GLOBAL,
1668 GLOBAL_ATU_MAC_01 + i);
Guenter Roeckdefb05b2015-03-26 18:36:38 -07001669 if (ret < 0)
1670 return ret;
1671 addr[i * 2] = ret >> 8;
1672 addr[i * 2 + 1] = ret & 0xff;
1673 }
1674
1675 return 0;
1676}
1677
Vivien Didelotfd231c82015-08-10 09:09:50 -04001678static int _mv88e6xxx_atu_load(struct dsa_switch *ds,
1679 struct mv88e6xxx_atu_entry *entry)
Guenter Roeckdefb05b2015-03-26 18:36:38 -07001680{
Guenter Roeckdefb05b2015-03-26 18:36:38 -07001681 int ret;
1682
1683 ret = _mv88e6xxx_atu_wait(ds);
1684 if (ret < 0)
1685 return ret;
1686
Vivien Didelotfd231c82015-08-10 09:09:50 -04001687 ret = _mv88e6xxx_atu_mac_write(ds, entry->mac);
Guenter Roeckdefb05b2015-03-26 18:36:38 -07001688 if (ret < 0)
1689 return ret;
1690
Vivien Didelot37705b72015-09-04 14:34:11 -04001691 ret = _mv88e6xxx_atu_data_write(ds, entry);
Vivien Didelotfd231c82015-08-10 09:09:50 -04001692 if (ret < 0)
Guenter Roeckdefb05b2015-03-26 18:36:38 -07001693 return ret;
1694
Vivien Didelot70cc99d2015-09-04 14:34:10 -04001695 ret = _mv88e6xxx_reg_write(ds, REG_GLOBAL, GLOBAL_ATU_FID, entry->fid);
1696 if (ret < 0)
1697 return ret;
1698
1699 return _mv88e6xxx_atu_cmd(ds, GLOBAL_ATU_OP_LOAD_DB);
Vivien Didelotfd231c82015-08-10 09:09:50 -04001700}
David S. Millercdf09692015-08-11 12:00:37 -07001701
Vivien Didelotfd231c82015-08-10 09:09:50 -04001702static int _mv88e6xxx_port_fdb_load(struct dsa_switch *ds, int port,
1703 const unsigned char *addr, u16 vid,
1704 u8 state)
1705{
1706 struct mv88e6xxx_atu_entry entry = { 0 };
Vivien Didelotfd231c82015-08-10 09:09:50 -04001707
Vivien Didelotf02bdff2015-10-11 18:08:36 -04001708 entry.fid = vid; /* We use one FID per VLAN */
Vivien Didelotfd231c82015-08-10 09:09:50 -04001709 entry.state = state;
1710 ether_addr_copy(entry.mac, addr);
1711 if (state != GLOBAL_ATU_DATA_STATE_UNUSED) {
1712 entry.trunk = false;
1713 entry.portv_trunkid = BIT(port);
1714 }
1715
1716 return _mv88e6xxx_atu_load(ds, &entry);
Guenter Roeckdefb05b2015-03-26 18:36:38 -07001717}
1718
Vivien Didelot146a3202015-10-08 11:35:12 -04001719int mv88e6xxx_port_fdb_prepare(struct dsa_switch *ds, int port,
1720 const struct switchdev_obj_port_fdb *fdb,
1721 struct switchdev_trans *trans)
1722{
Vivien Didelotf02bdff2015-10-11 18:08:36 -04001723 /* We don't use per-port FDB */
1724 if (fdb->vid == 0)
1725 return -EOPNOTSUPP;
1726
Vivien Didelot146a3202015-10-08 11:35:12 -04001727 /* We don't need any dynamic resource from the kernel (yet),
1728 * so skip the prepare phase.
1729 */
1730 return 0;
1731}
1732
David S. Millercdf09692015-08-11 12:00:37 -07001733int mv88e6xxx_port_fdb_add(struct dsa_switch *ds, int port,
Vivien Didelot1f36faf2015-10-08 11:35:13 -04001734 const struct switchdev_obj_port_fdb *fdb,
1735 struct switchdev_trans *trans)
Guenter Roeckdefb05b2015-03-26 18:36:38 -07001736{
Vivien Didelot1f36faf2015-10-08 11:35:13 -04001737 int state = is_multicast_ether_addr(fdb->addr) ?
David S. Millercdf09692015-08-11 12:00:37 -07001738 GLOBAL_ATU_DATA_STATE_MC_STATIC :
1739 GLOBAL_ATU_DATA_STATE_UC_STATIC;
1740 struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
Vivien Didelot6630e232015-08-06 01:44:07 -04001741 int ret;
1742
David S. Millercdf09692015-08-11 12:00:37 -07001743 mutex_lock(&ps->smi_mutex);
Vivien Didelot1f36faf2015-10-08 11:35:13 -04001744 ret = _mv88e6xxx_port_fdb_load(ds, port, fdb->addr, fdb->vid, state);
David S. Millercdf09692015-08-11 12:00:37 -07001745 mutex_unlock(&ps->smi_mutex);
1746
1747 return ret;
1748}
1749
1750int mv88e6xxx_port_fdb_del(struct dsa_switch *ds, int port,
Vivien Didelot8057b3e2015-10-08 11:35:14 -04001751 const struct switchdev_obj_port_fdb *fdb)
David S. Millercdf09692015-08-11 12:00:37 -07001752{
1753 struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
1754 int ret;
1755
1756 mutex_lock(&ps->smi_mutex);
Vivien Didelot8057b3e2015-10-08 11:35:14 -04001757 ret = _mv88e6xxx_port_fdb_load(ds, port, fdb->addr, fdb->vid,
David S. Millercdf09692015-08-11 12:00:37 -07001758 GLOBAL_ATU_DATA_STATE_UNUSED);
1759 mutex_unlock(&ps->smi_mutex);
1760
1761 return ret;
1762}
1763
Vivien Didelot1d194042015-08-10 09:09:51 -04001764static int _mv88e6xxx_atu_getnext(struct dsa_switch *ds, u16 fid,
Vivien Didelot1d194042015-08-10 09:09:51 -04001765 struct mv88e6xxx_atu_entry *entry)
David S. Millercdf09692015-08-11 12:00:37 -07001766{
Vivien Didelot1d194042015-08-10 09:09:51 -04001767 struct mv88e6xxx_atu_entry next = { 0 };
1768 int ret;
1769
1770 next.fid = fid;
Guenter Roeckdefb05b2015-03-26 18:36:38 -07001771
1772 ret = _mv88e6xxx_atu_wait(ds);
1773 if (ret < 0)
1774 return ret;
1775
Vivien Didelot70cc99d2015-09-04 14:34:10 -04001776 ret = _mv88e6xxx_reg_write(ds, REG_GLOBAL, GLOBAL_ATU_FID, fid);
1777 if (ret < 0)
1778 return ret;
1779
1780 ret = _mv88e6xxx_atu_cmd(ds, GLOBAL_ATU_OP_GET_NEXT_DB);
Guenter Roeckdefb05b2015-03-26 18:36:38 -07001781 if (ret < 0)
1782 return ret;
1783
Vivien Didelot1d194042015-08-10 09:09:51 -04001784 ret = _mv88e6xxx_atu_mac_read(ds, next.mac);
1785 if (ret < 0)
1786 return ret;
Guenter Roeckdefb05b2015-03-26 18:36:38 -07001787
Vivien Didelot1d194042015-08-10 09:09:51 -04001788 ret = _mv88e6xxx_reg_read(ds, REG_GLOBAL, GLOBAL_ATU_DATA);
1789 if (ret < 0)
1790 return ret;
1791
1792 next.state = ret & GLOBAL_ATU_DATA_STATE_MASK;
1793 if (next.state != GLOBAL_ATU_DATA_STATE_UNUSED) {
1794 unsigned int mask, shift;
1795
1796 if (ret & GLOBAL_ATU_DATA_TRUNK) {
1797 next.trunk = true;
1798 mask = GLOBAL_ATU_DATA_TRUNK_ID_MASK;
1799 shift = GLOBAL_ATU_DATA_TRUNK_ID_SHIFT;
1800 } else {
1801 next.trunk = false;
1802 mask = GLOBAL_ATU_DATA_PORT_VECTOR_MASK;
1803 shift = GLOBAL_ATU_DATA_PORT_VECTOR_SHIFT;
1804 }
1805
1806 next.portv_trunkid = (ret & mask) >> shift;
1807 }
1808
1809 *entry = next;
Guenter Roeckdefb05b2015-03-26 18:36:38 -07001810 return 0;
1811}
1812
Vivien Didelotf33475b2015-10-22 09:34:41 -04001813int mv88e6xxx_port_fdb_dump(struct dsa_switch *ds, int port,
1814 struct switchdev_obj_port_fdb *fdb,
1815 int (*cb)(struct switchdev_obj *obj))
1816{
1817 struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
1818 struct mv88e6xxx_vtu_stu_entry vlan = {
1819 .vid = GLOBAL_VTU_VID_MASK, /* all ones */
1820 };
1821 int err;
1822
1823 mutex_lock(&ps->smi_mutex);
1824
1825 err = _mv88e6xxx_vtu_vid_write(ds, vlan.vid);
1826 if (err)
1827 goto unlock;
1828
1829 do {
1830 struct mv88e6xxx_atu_entry addr = {
1831 .mac = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff },
1832 };
1833
1834 err = _mv88e6xxx_vtu_getnext(ds, &vlan);
1835 if (err)
1836 goto unlock;
1837
1838 if (!vlan.valid)
1839 break;
1840
1841 err = _mv88e6xxx_atu_mac_write(ds, addr.mac);
1842 if (err)
1843 goto unlock;
1844
1845 do {
1846 err = _mv88e6xxx_atu_getnext(ds, vlan.fid, &addr);
1847 if (err)
1848 goto unlock;
1849
1850 if (addr.state == GLOBAL_ATU_DATA_STATE_UNUSED)
1851 break;
1852
1853 if (!addr.trunk && addr.portv_trunkid & BIT(port)) {
1854 bool is_static = addr.state ==
1855 (is_multicast_ether_addr(addr.mac) ?
1856 GLOBAL_ATU_DATA_STATE_MC_STATIC :
1857 GLOBAL_ATU_DATA_STATE_UC_STATIC);
1858
1859 fdb->vid = vlan.vid;
1860 ether_addr_copy(fdb->addr, addr.mac);
1861 fdb->ndm_state = is_static ? NUD_NOARP :
1862 NUD_REACHABLE;
1863
1864 err = cb(&fdb->obj);
1865 if (err)
1866 goto unlock;
1867 }
1868 } while (!is_broadcast_ether_addr(addr.mac));
1869
1870 } while (vlan.vid < GLOBAL_VTU_VID_MASK);
1871
1872unlock:
1873 mutex_unlock(&ps->smi_mutex);
1874
1875 return err;
1876}
1877
Vivien Didelote79a8bc2015-11-04 17:23:40 -05001878int mv88e6xxx_port_bridge_join(struct dsa_switch *ds, int port, u32 members)
1879{
1880 struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
1881 const u16 pvid = 4000 + ds->index * DSA_MAX_PORTS + port;
1882 int err;
1883
1884 /* The port joined a bridge, so leave its reserved VLAN */
1885 mutex_lock(&ps->smi_mutex);
1886 err = _mv88e6xxx_port_vlan_del(ds, port, pvid);
1887 if (!err)
1888 err = _mv88e6xxx_port_pvid_set(ds, port, 0);
1889 mutex_unlock(&ps->smi_mutex);
1890 return err;
1891}
1892
1893int mv88e6xxx_port_bridge_leave(struct dsa_switch *ds, int port, u32 members)
1894{
1895 struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
1896 const u16 pvid = 4000 + ds->index * DSA_MAX_PORTS + port;
1897 int err;
1898
1899 /* The port left the bridge, so join its reserved VLAN */
1900 mutex_lock(&ps->smi_mutex);
1901 err = _mv88e6xxx_port_vlan_add(ds, port, pvid, true);
1902 if (!err)
1903 err = _mv88e6xxx_port_pvid_set(ds, port, pvid);
1904 mutex_unlock(&ps->smi_mutex);
1905 return err;
1906}
1907
Guenter Roeckfacd95b2015-03-26 18:36:35 -07001908static void mv88e6xxx_bridge_work(struct work_struct *work)
1909{
1910 struct mv88e6xxx_priv_state *ps;
1911 struct dsa_switch *ds;
1912 int port;
1913
1914 ps = container_of(work, struct mv88e6xxx_priv_state, bridge_work);
1915 ds = ((struct dsa_switch *)ps) - 1;
1916
1917 while (ps->port_state_update_mask) {
1918 port = __ffs(ps->port_state_update_mask);
1919 clear_bit(port, &ps->port_state_update_mask);
1920 mv88e6xxx_set_port_state(ds, port, ps->port_state[port]);
1921 }
1922}
1923
Andrew Lunndbde9e62015-05-06 01:09:48 +02001924static int mv88e6xxx_setup_port(struct dsa_switch *ds, int port)
Guenter Roeckd827e882015-03-26 18:36:29 -07001925{
1926 struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
Vivien Didelotf02bdff2015-10-11 18:08:36 -04001927 int ret;
Andrew Lunn54d792f2015-05-06 01:09:47 +02001928 u16 reg;
Guenter Roeckd827e882015-03-26 18:36:29 -07001929
1930 mutex_lock(&ps->smi_mutex);
1931
Andrew Lunn54d792f2015-05-06 01:09:47 +02001932 if (mv88e6xxx_6352_family(ds) || mv88e6xxx_6351_family(ds) ||
1933 mv88e6xxx_6165_family(ds) || mv88e6xxx_6097_family(ds) ||
1934 mv88e6xxx_6185_family(ds) || mv88e6xxx_6095_family(ds) ||
Aleksey S. Kazantsev7c3d0d62015-07-07 20:38:15 -07001935 mv88e6xxx_6065_family(ds) || mv88e6xxx_6320_family(ds)) {
Andrew Lunn54d792f2015-05-06 01:09:47 +02001936 /* MAC Forcing register: don't force link, speed,
1937 * duplex or flow control state to any particular
1938 * values on physical ports, but force the CPU port
1939 * and all DSA ports to their maximum bandwidth and
1940 * full duplex.
1941 */
1942 reg = _mv88e6xxx_reg_read(ds, REG_PORT(port), PORT_PCS_CTRL);
Andrew Lunn60045cb2015-08-17 23:52:51 +02001943 if (dsa_is_cpu_port(ds, port) || dsa_is_dsa_port(ds, port)) {
Russell King53adc9e2015-09-21 21:42:59 +01001944 reg &= ~PORT_PCS_CTRL_UNFORCED;
Andrew Lunn54d792f2015-05-06 01:09:47 +02001945 reg |= PORT_PCS_CTRL_FORCE_LINK |
1946 PORT_PCS_CTRL_LINK_UP |
1947 PORT_PCS_CTRL_DUPLEX_FULL |
1948 PORT_PCS_CTRL_FORCE_DUPLEX;
1949 if (mv88e6xxx_6065_family(ds))
1950 reg |= PORT_PCS_CTRL_100;
1951 else
1952 reg |= PORT_PCS_CTRL_1000;
1953 } else {
1954 reg |= PORT_PCS_CTRL_UNFORCED;
1955 }
1956
1957 ret = _mv88e6xxx_reg_write(ds, REG_PORT(port),
1958 PORT_PCS_CTRL, reg);
1959 if (ret)
1960 goto abort;
1961 }
1962
1963 /* Port Control: disable Drop-on-Unlock, disable Drop-on-Lock,
1964 * disable Header mode, enable IGMP/MLD snooping, disable VLAN
1965 * tunneling, determine priority by looking at 802.1p and IP
1966 * priority fields (IP prio has precedence), and set STP state
1967 * to Forwarding.
1968 *
1969 * If this is the CPU link, use DSA or EDSA tagging depending
1970 * on which tagging mode was configured.
1971 *
1972 * If this is a link to another switch, use DSA tagging mode.
1973 *
1974 * If this is the upstream port for this switch, enable
1975 * forwarding of unknown unicasts and multicasts.
1976 */
1977 reg = 0;
1978 if (mv88e6xxx_6352_family(ds) || mv88e6xxx_6351_family(ds) ||
1979 mv88e6xxx_6165_family(ds) || mv88e6xxx_6097_family(ds) ||
1980 mv88e6xxx_6095_family(ds) || mv88e6xxx_6065_family(ds) ||
Aleksey S. Kazantsev7c3d0d62015-07-07 20:38:15 -07001981 mv88e6xxx_6185_family(ds) || mv88e6xxx_6320_family(ds))
Andrew Lunn54d792f2015-05-06 01:09:47 +02001982 reg = PORT_CONTROL_IGMP_MLD_SNOOP |
1983 PORT_CONTROL_USE_TAG | PORT_CONTROL_USE_IP |
1984 PORT_CONTROL_STATE_FORWARDING;
1985 if (dsa_is_cpu_port(ds, port)) {
1986 if (mv88e6xxx_6095_family(ds) || mv88e6xxx_6185_family(ds))
1987 reg |= PORT_CONTROL_DSA_TAG;
1988 if (mv88e6xxx_6352_family(ds) || mv88e6xxx_6351_family(ds) ||
Aleksey S. Kazantsev7c3d0d62015-07-07 20:38:15 -07001989 mv88e6xxx_6165_family(ds) || mv88e6xxx_6097_family(ds) ||
1990 mv88e6xxx_6320_family(ds)) {
Andrew Lunn54d792f2015-05-06 01:09:47 +02001991 if (ds->dst->tag_protocol == DSA_TAG_PROTO_EDSA)
1992 reg |= PORT_CONTROL_FRAME_ETHER_TYPE_DSA;
1993 else
1994 reg |= PORT_CONTROL_FRAME_MODE_DSA;
Andrew Lunnc047a1f2015-09-29 01:50:56 +02001995 reg |= PORT_CONTROL_FORWARD_UNKNOWN |
1996 PORT_CONTROL_FORWARD_UNKNOWN_MC;
Andrew Lunn54d792f2015-05-06 01:09:47 +02001997 }
1998
1999 if (mv88e6xxx_6352_family(ds) || mv88e6xxx_6351_family(ds) ||
2000 mv88e6xxx_6165_family(ds) || mv88e6xxx_6097_family(ds) ||
2001 mv88e6xxx_6095_family(ds) || mv88e6xxx_6065_family(ds) ||
Aleksey S. Kazantsev7c3d0d62015-07-07 20:38:15 -07002002 mv88e6xxx_6185_family(ds) || mv88e6xxx_6320_family(ds)) {
Andrew Lunn54d792f2015-05-06 01:09:47 +02002003 if (ds->dst->tag_protocol == DSA_TAG_PROTO_EDSA)
2004 reg |= PORT_CONTROL_EGRESS_ADD_TAG;
2005 }
2006 }
Andrew Lunn6083ce72015-08-17 23:52:52 +02002007 if (dsa_is_dsa_port(ds, port)) {
2008 if (mv88e6xxx_6095_family(ds) || mv88e6xxx_6185_family(ds))
2009 reg |= PORT_CONTROL_DSA_TAG;
2010 if (mv88e6xxx_6352_family(ds) || mv88e6xxx_6351_family(ds) ||
2011 mv88e6xxx_6165_family(ds) || mv88e6xxx_6097_family(ds) ||
2012 mv88e6xxx_6320_family(ds)) {
Andrew Lunn54d792f2015-05-06 01:09:47 +02002013 reg |= PORT_CONTROL_FRAME_MODE_DSA;
Andrew Lunn6083ce72015-08-17 23:52:52 +02002014 }
2015
Andrew Lunn54d792f2015-05-06 01:09:47 +02002016 if (port == dsa_upstream_port(ds))
2017 reg |= PORT_CONTROL_FORWARD_UNKNOWN |
2018 PORT_CONTROL_FORWARD_UNKNOWN_MC;
2019 }
2020 if (reg) {
2021 ret = _mv88e6xxx_reg_write(ds, REG_PORT(port),
2022 PORT_CONTROL, reg);
2023 if (ret)
2024 goto abort;
2025 }
2026
Vivien Didelot8efdda42015-08-13 12:52:23 -04002027 /* Port Control 2: don't force a good FCS, set the maximum frame size to
2028 * 10240 bytes, enable secure 802.1q tags, don't discard tagged or
2029 * untagged frames on this port, do a destination address lookup on all
2030 * received packets as usual, disable ARP mirroring and don't send a
2031 * copy of all transmitted/received frames on this port to the CPU.
Andrew Lunn54d792f2015-05-06 01:09:47 +02002032 */
2033 reg = 0;
2034 if (mv88e6xxx_6352_family(ds) || mv88e6xxx_6351_family(ds) ||
2035 mv88e6xxx_6165_family(ds) || mv88e6xxx_6097_family(ds) ||
Aleksey S. Kazantsev7c3d0d62015-07-07 20:38:15 -07002036 mv88e6xxx_6095_family(ds) || mv88e6xxx_6320_family(ds))
Andrew Lunn54d792f2015-05-06 01:09:47 +02002037 reg = PORT_CONTROL_2_MAP_DA;
2038
2039 if (mv88e6xxx_6352_family(ds) || mv88e6xxx_6351_family(ds) ||
Aleksey S. Kazantsev7c3d0d62015-07-07 20:38:15 -07002040 mv88e6xxx_6165_family(ds) || mv88e6xxx_6320_family(ds))
Andrew Lunn54d792f2015-05-06 01:09:47 +02002041 reg |= PORT_CONTROL_2_JUMBO_10240;
2042
2043 if (mv88e6xxx_6095_family(ds) || mv88e6xxx_6185_family(ds)) {
2044 /* Set the upstream port this port should use */
2045 reg |= dsa_upstream_port(ds);
2046 /* enable forwarding of unknown multicast addresses to
2047 * the upstream port
2048 */
2049 if (port == dsa_upstream_port(ds))
2050 reg |= PORT_CONTROL_2_FORWARD_UNKNOWN;
2051 }
2052
Vivien Didelot5fe7f682015-10-11 18:08:38 -04002053 reg |= PORT_CONTROL_2_8021Q_SECURE;
Vivien Didelot8efdda42015-08-13 12:52:23 -04002054
Andrew Lunn54d792f2015-05-06 01:09:47 +02002055 if (reg) {
2056 ret = _mv88e6xxx_reg_write(ds, REG_PORT(port),
2057 PORT_CONTROL_2, reg);
2058 if (ret)
2059 goto abort;
2060 }
2061
2062 /* Port Association Vector: when learning source addresses
2063 * of packets, add the address to the address database using
2064 * a port bitmap that has only the bit for this port set and
2065 * the other bits clear.
2066 */
Andrew Lunn4c7ea3c2015-11-03 10:52:36 -05002067 reg = 1 << port;
2068 /* Disable learning for DSA and CPU ports */
2069 if (dsa_is_cpu_port(ds, port) || dsa_is_dsa_port(ds, port))
2070 reg = PORT_ASSOC_VECTOR_LOCKED_PORT;
2071
2072 ret = _mv88e6xxx_reg_write(ds, REG_PORT(port), PORT_ASSOC_VECTOR, reg);
Andrew Lunn54d792f2015-05-06 01:09:47 +02002073 if (ret)
2074 goto abort;
2075
2076 /* Egress rate control 2: disable egress rate control. */
2077 ret = _mv88e6xxx_reg_write(ds, REG_PORT(port), PORT_RATE_CONTROL_2,
2078 0x0000);
2079 if (ret)
2080 goto abort;
2081
2082 if (mv88e6xxx_6352_family(ds) || mv88e6xxx_6351_family(ds) ||
Aleksey S. Kazantsev7c3d0d62015-07-07 20:38:15 -07002083 mv88e6xxx_6165_family(ds) || mv88e6xxx_6097_family(ds) ||
2084 mv88e6xxx_6320_family(ds)) {
Andrew Lunn54d792f2015-05-06 01:09:47 +02002085 /* Do not limit the period of time that this port can
2086 * be paused for by the remote end or the period of
2087 * time that this port can pause the remote end.
2088 */
2089 ret = _mv88e6xxx_reg_write(ds, REG_PORT(port),
2090 PORT_PAUSE_CTRL, 0x0000);
2091 if (ret)
2092 goto abort;
2093
2094 /* Port ATU control: disable limiting the number of
2095 * address database entries that this port is allowed
2096 * to use.
2097 */
2098 ret = _mv88e6xxx_reg_write(ds, REG_PORT(port),
2099 PORT_ATU_CONTROL, 0x0000);
2100 /* Priority Override: disable DA, SA and VTU priority
2101 * override.
2102 */
2103 ret = _mv88e6xxx_reg_write(ds, REG_PORT(port),
2104 PORT_PRI_OVERRIDE, 0x0000);
2105 if (ret)
2106 goto abort;
2107
2108 /* Port Ethertype: use the Ethertype DSA Ethertype
2109 * value.
2110 */
2111 ret = _mv88e6xxx_reg_write(ds, REG_PORT(port),
2112 PORT_ETH_TYPE, ETH_P_EDSA);
2113 if (ret)
2114 goto abort;
2115 /* Tag Remap: use an identity 802.1p prio -> switch
2116 * prio mapping.
2117 */
2118 ret = _mv88e6xxx_reg_write(ds, REG_PORT(port),
2119 PORT_TAG_REGMAP_0123, 0x3210);
2120 if (ret)
2121 goto abort;
2122
2123 /* Tag Remap 2: use an identity 802.1p prio -> switch
2124 * prio mapping.
2125 */
2126 ret = _mv88e6xxx_reg_write(ds, REG_PORT(port),
2127 PORT_TAG_REGMAP_4567, 0x7654);
2128 if (ret)
2129 goto abort;
2130 }
2131
2132 if (mv88e6xxx_6352_family(ds) || mv88e6xxx_6351_family(ds) ||
2133 mv88e6xxx_6165_family(ds) || mv88e6xxx_6097_family(ds) ||
Aleksey S. Kazantsev7c3d0d62015-07-07 20:38:15 -07002134 mv88e6xxx_6185_family(ds) || mv88e6xxx_6095_family(ds) ||
2135 mv88e6xxx_6320_family(ds)) {
Andrew Lunn54d792f2015-05-06 01:09:47 +02002136 /* Rate Control: disable ingress rate limiting. */
2137 ret = _mv88e6xxx_reg_write(ds, REG_PORT(port),
2138 PORT_RATE_CONTROL, 0x0001);
2139 if (ret)
2140 goto abort;
2141 }
2142
Guenter Roeck366f0a02015-03-26 18:36:30 -07002143 /* Port Control 1: disable trunking, disable sending
2144 * learning messages to this port.
Guenter Roeckd827e882015-03-26 18:36:29 -07002145 */
Vivien Didelot614f03f2015-04-20 17:19:23 -04002146 ret = _mv88e6xxx_reg_write(ds, REG_PORT(port), PORT_CONTROL_1, 0x0000);
Guenter Roeckd827e882015-03-26 18:36:29 -07002147 if (ret)
2148 goto abort;
2149
Vivien Didelotf02bdff2015-10-11 18:08:36 -04002150 /* Port based VLAN map: do not give each port its own address
Vivien Didelot5fe7f682015-10-11 18:08:38 -04002151 * database, and allow every port to egress frames on all other ports.
Guenter Roeckd827e882015-03-26 18:36:29 -07002152 */
Vivien Didelot5fe7f682015-10-11 18:08:38 -04002153 reg = BIT(ps->num_ports) - 1; /* all ports */
Vivien Didelotede80982015-10-11 18:08:35 -04002154 ret = _mv88e6xxx_port_vlan_map_set(ds, port, reg & ~port);
Guenter Roeckd827e882015-03-26 18:36:29 -07002155 if (ret)
2156 goto abort;
2157
2158 /* Default VLAN ID and priority: don't set a default VLAN
2159 * ID, and set the default packet priority to zero.
2160 */
Vivien Didelot47cf1e652015-04-20 17:43:26 -04002161 ret = _mv88e6xxx_reg_write(ds, REG_PORT(port), PORT_DEFAULT_VLAN,
2162 0x0000);
Guenter Roeckd827e882015-03-26 18:36:29 -07002163abort:
2164 mutex_unlock(&ps->smi_mutex);
2165 return ret;
2166}
2167
Andrew Lunndbde9e62015-05-06 01:09:48 +02002168int mv88e6xxx_setup_ports(struct dsa_switch *ds)
2169{
2170 struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
2171 int ret;
2172 int i;
2173
2174 for (i = 0; i < ps->num_ports; i++) {
2175 ret = mv88e6xxx_setup_port(ds, i);
2176 if (ret < 0)
2177 return ret;
Vivien Didelote79a8bc2015-11-04 17:23:40 -05002178
2179 if (dsa_is_cpu_port(ds, i) || dsa_is_dsa_port(ds, i))
2180 continue;
2181
2182 /* setup the unbridged state */
2183 ret = mv88e6xxx_port_bridge_leave(ds, i, 0);
2184 if (ret < 0)
2185 return ret;
Andrew Lunndbde9e62015-05-06 01:09:48 +02002186 }
2187 return 0;
2188}
2189
Guenter Roeckacdaffc2015-03-26 18:36:28 -07002190int mv88e6xxx_setup_common(struct dsa_switch *ds)
2191{
2192 struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
2193
2194 mutex_init(&ps->smi_mutex);
Guenter Roeckacdaffc2015-03-26 18:36:28 -07002195
Andrew Lunncca8b132015-04-02 04:06:39 +02002196 ps->id = REG_READ(REG_PORT(0), PORT_SWITCH_ID) & 0xfff0;
Andrew Lunna8f064c2015-03-26 18:36:40 -07002197
Guenter Roeckfacd95b2015-03-26 18:36:35 -07002198 INIT_WORK(&ps->bridge_work, mv88e6xxx_bridge_work);
2199
Guenter Roeckacdaffc2015-03-26 18:36:28 -07002200 return 0;
2201}
2202
Andrew Lunn54d792f2015-05-06 01:09:47 +02002203int mv88e6xxx_setup_global(struct dsa_switch *ds)
2204{
2205 struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
Vivien Didelot24751e22015-08-03 09:17:44 -04002206 int ret;
Andrew Lunn54d792f2015-05-06 01:09:47 +02002207 int i;
2208
2209 /* Set the default address aging time to 5 minutes, and
2210 * enable address learn messages to be sent to all message
2211 * ports.
2212 */
2213 REG_WRITE(REG_GLOBAL, GLOBAL_ATU_CONTROL,
2214 0x0140 | GLOBAL_ATU_CONTROL_LEARN2ALL);
2215
2216 /* Configure the IP ToS mapping registers. */
2217 REG_WRITE(REG_GLOBAL, GLOBAL_IP_PRI_0, 0x0000);
2218 REG_WRITE(REG_GLOBAL, GLOBAL_IP_PRI_1, 0x0000);
2219 REG_WRITE(REG_GLOBAL, GLOBAL_IP_PRI_2, 0x5555);
2220 REG_WRITE(REG_GLOBAL, GLOBAL_IP_PRI_3, 0x5555);
2221 REG_WRITE(REG_GLOBAL, GLOBAL_IP_PRI_4, 0xaaaa);
2222 REG_WRITE(REG_GLOBAL, GLOBAL_IP_PRI_5, 0xaaaa);
2223 REG_WRITE(REG_GLOBAL, GLOBAL_IP_PRI_6, 0xffff);
2224 REG_WRITE(REG_GLOBAL, GLOBAL_IP_PRI_7, 0xffff);
2225
2226 /* Configure the IEEE 802.1p priority mapping register. */
2227 REG_WRITE(REG_GLOBAL, GLOBAL_IEEE_PRI, 0xfa41);
2228
2229 /* Send all frames with destination addresses matching
2230 * 01:80:c2:00:00:0x to the CPU port.
2231 */
2232 REG_WRITE(REG_GLOBAL2, GLOBAL2_MGMT_EN_0X, 0xffff);
2233
2234 /* Ignore removed tag data on doubly tagged packets, disable
2235 * flow control messages, force flow control priority to the
2236 * highest, and send all special multicast frames to the CPU
2237 * port at the highest priority.
2238 */
2239 REG_WRITE(REG_GLOBAL2, GLOBAL2_SWITCH_MGMT,
2240 0x7 | GLOBAL2_SWITCH_MGMT_RSVD2CPU | 0x70 |
2241 GLOBAL2_SWITCH_MGMT_FORCE_FLOW_CTRL_PRI);
2242
2243 /* Program the DSA routing table. */
2244 for (i = 0; i < 32; i++) {
2245 int nexthop = 0x1f;
2246
2247 if (ds->pd->rtable &&
2248 i != ds->index && i < ds->dst->pd->nr_chips)
2249 nexthop = ds->pd->rtable[i] & 0x1f;
2250
2251 REG_WRITE(REG_GLOBAL2, GLOBAL2_DEVICE_MAPPING,
2252 GLOBAL2_DEVICE_MAPPING_UPDATE |
2253 (i << GLOBAL2_DEVICE_MAPPING_TARGET_SHIFT) |
2254 nexthop);
2255 }
2256
2257 /* Clear all trunk masks. */
2258 for (i = 0; i < 8; i++)
2259 REG_WRITE(REG_GLOBAL2, GLOBAL2_TRUNK_MASK,
2260 0x8000 | (i << GLOBAL2_TRUNK_MASK_NUM_SHIFT) |
2261 ((1 << ps->num_ports) - 1));
2262
2263 /* Clear all trunk mappings. */
2264 for (i = 0; i < 16; i++)
2265 REG_WRITE(REG_GLOBAL2, GLOBAL2_TRUNK_MAPPING,
2266 GLOBAL2_TRUNK_MAPPING_UPDATE |
2267 (i << GLOBAL2_TRUNK_MAPPING_ID_SHIFT));
2268
2269 if (mv88e6xxx_6352_family(ds) || mv88e6xxx_6351_family(ds) ||
Aleksey S. Kazantsev7c3d0d62015-07-07 20:38:15 -07002270 mv88e6xxx_6165_family(ds) || mv88e6xxx_6097_family(ds) ||
2271 mv88e6xxx_6320_family(ds)) {
Andrew Lunn54d792f2015-05-06 01:09:47 +02002272 /* Send all frames with destination addresses matching
2273 * 01:80:c2:00:00:2x to the CPU port.
2274 */
2275 REG_WRITE(REG_GLOBAL2, GLOBAL2_MGMT_EN_2X, 0xffff);
2276
2277 /* Initialise cross-chip port VLAN table to reset
2278 * defaults.
2279 */
2280 REG_WRITE(REG_GLOBAL2, GLOBAL2_PVT_ADDR, 0x9000);
2281
2282 /* Clear the priority override table. */
2283 for (i = 0; i < 16; i++)
2284 REG_WRITE(REG_GLOBAL2, GLOBAL2_PRIO_OVERRIDE,
2285 0x8000 | (i << 8));
2286 }
2287
2288 if (mv88e6xxx_6352_family(ds) || mv88e6xxx_6351_family(ds) ||
2289 mv88e6xxx_6165_family(ds) || mv88e6xxx_6097_family(ds) ||
Aleksey S. Kazantsev7c3d0d62015-07-07 20:38:15 -07002290 mv88e6xxx_6185_family(ds) || mv88e6xxx_6095_family(ds) ||
2291 mv88e6xxx_6320_family(ds)) {
Andrew Lunn54d792f2015-05-06 01:09:47 +02002292 /* Disable ingress rate limiting by resetting all
2293 * ingress rate limit registers to their initial
2294 * state.
2295 */
2296 for (i = 0; i < ps->num_ports; i++)
2297 REG_WRITE(REG_GLOBAL2, GLOBAL2_INGRESS_OP,
2298 0x9000 | (i << 8));
2299 }
2300
Andrew Lunndb687a52015-06-20 21:31:29 +02002301 /* Clear the statistics counters for all ports */
2302 REG_WRITE(REG_GLOBAL, GLOBAL_STATS_OP, GLOBAL_STATS_OP_FLUSH_ALL);
2303
2304 /* Wait for the flush to complete. */
Vivien Didelot24751e22015-08-03 09:17:44 -04002305 mutex_lock(&ps->smi_mutex);
2306 ret = _mv88e6xxx_stats_wait(ds);
Vivien Didelot6b17e862015-08-13 12:52:18 -04002307 if (ret < 0)
2308 goto unlock;
2309
Vivien Didelotc161d0a2015-09-04 14:34:13 -04002310 /* Clear all ATU entries */
2311 ret = _mv88e6xxx_atu_flush(ds, 0, true);
2312 if (ret < 0)
2313 goto unlock;
2314
Vivien Didelot6b17e862015-08-13 12:52:18 -04002315 /* Clear all the VTU and STU entries */
2316 ret = _mv88e6xxx_vtu_stu_flush(ds);
2317unlock:
Vivien Didelot24751e22015-08-03 09:17:44 -04002318 mutex_unlock(&ps->smi_mutex);
Andrew Lunndb687a52015-06-20 21:31:29 +02002319
Vivien Didelot24751e22015-08-03 09:17:44 -04002320 return ret;
Andrew Lunn54d792f2015-05-06 01:09:47 +02002321}
2322
Andrew Lunn143a8302015-04-02 04:06:34 +02002323int mv88e6xxx_switch_reset(struct dsa_switch *ds, bool ppu_active)
2324{
2325 struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
2326 u16 is_reset = (ppu_active ? 0x8800 : 0xc800);
Andrew Lunnc8c1b39a2015-11-20 03:56:24 +01002327 struct gpio_desc *gpiod = ds->pd->reset;
Andrew Lunn143a8302015-04-02 04:06:34 +02002328 unsigned long timeout;
2329 int ret;
2330 int i;
2331
2332 /* Set all ports to the disabled state. */
2333 for (i = 0; i < ps->num_ports; i++) {
Andrew Lunncca8b132015-04-02 04:06:39 +02002334 ret = REG_READ(REG_PORT(i), PORT_CONTROL);
2335 REG_WRITE(REG_PORT(i), PORT_CONTROL, ret & 0xfffc);
Andrew Lunn143a8302015-04-02 04:06:34 +02002336 }
2337
2338 /* Wait for transmit queues to drain. */
2339 usleep_range(2000, 4000);
2340
Andrew Lunnc8c1b39a2015-11-20 03:56:24 +01002341 /* If there is a gpio connected to the reset pin, toggle it */
2342 if (gpiod) {
2343 gpiod_set_value_cansleep(gpiod, 1);
2344 usleep_range(10000, 20000);
2345 gpiod_set_value_cansleep(gpiod, 0);
2346 usleep_range(10000, 20000);
2347 }
2348
Andrew Lunn143a8302015-04-02 04:06:34 +02002349 /* Reset the switch. Keep the PPU active if requested. The PPU
2350 * needs to be active to support indirect phy register access
2351 * through global registers 0x18 and 0x19.
2352 */
2353 if (ppu_active)
2354 REG_WRITE(REG_GLOBAL, 0x04, 0xc000);
2355 else
2356 REG_WRITE(REG_GLOBAL, 0x04, 0xc400);
2357
2358 /* Wait up to one second for reset to complete. */
2359 timeout = jiffies + 1 * HZ;
2360 while (time_before(jiffies, timeout)) {
2361 ret = REG_READ(REG_GLOBAL, 0x00);
2362 if ((ret & is_reset) == is_reset)
2363 break;
2364 usleep_range(1000, 2000);
2365 }
2366 if (time_after(jiffies, timeout))
2367 return -ETIMEDOUT;
2368
2369 return 0;
2370}
2371
Andrew Lunn491435852015-04-02 04:06:35 +02002372int mv88e6xxx_phy_page_read(struct dsa_switch *ds, int port, int page, int reg)
2373{
2374 struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
2375 int ret;
2376
Andrew Lunn3898c142015-05-06 01:09:53 +02002377 mutex_lock(&ps->smi_mutex);
Andrew Lunnfd3a0ee2015-04-02 04:06:36 +02002378 ret = _mv88e6xxx_phy_write_indirect(ds, port, 0x16, page);
Andrew Lunn491435852015-04-02 04:06:35 +02002379 if (ret < 0)
2380 goto error;
Andrew Lunnfd3a0ee2015-04-02 04:06:36 +02002381 ret = _mv88e6xxx_phy_read_indirect(ds, port, reg);
Andrew Lunn491435852015-04-02 04:06:35 +02002382error:
Andrew Lunnfd3a0ee2015-04-02 04:06:36 +02002383 _mv88e6xxx_phy_write_indirect(ds, port, 0x16, 0x0);
Andrew Lunn3898c142015-05-06 01:09:53 +02002384 mutex_unlock(&ps->smi_mutex);
Andrew Lunn491435852015-04-02 04:06:35 +02002385 return ret;
2386}
2387
2388int mv88e6xxx_phy_page_write(struct dsa_switch *ds, int port, int page,
2389 int reg, int val)
2390{
2391 struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
2392 int ret;
2393
Andrew Lunn3898c142015-05-06 01:09:53 +02002394 mutex_lock(&ps->smi_mutex);
Andrew Lunnfd3a0ee2015-04-02 04:06:36 +02002395 ret = _mv88e6xxx_phy_write_indirect(ds, port, 0x16, page);
Andrew Lunn491435852015-04-02 04:06:35 +02002396 if (ret < 0)
2397 goto error;
2398
Andrew Lunnfd3a0ee2015-04-02 04:06:36 +02002399 ret = _mv88e6xxx_phy_write_indirect(ds, port, reg, val);
Andrew Lunn491435852015-04-02 04:06:35 +02002400error:
Andrew Lunnfd3a0ee2015-04-02 04:06:36 +02002401 _mv88e6xxx_phy_write_indirect(ds, port, 0x16, 0x0);
Andrew Lunn3898c142015-05-06 01:09:53 +02002402 mutex_unlock(&ps->smi_mutex);
Andrew Lunnfd3a0ee2015-04-02 04:06:36 +02002403 return ret;
2404}
2405
2406static int mv88e6xxx_port_to_phy_addr(struct dsa_switch *ds, int port)
2407{
2408 struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
2409
2410 if (port >= 0 && port < ps->num_ports)
2411 return port;
2412 return -EINVAL;
2413}
2414
2415int
2416mv88e6xxx_phy_read(struct dsa_switch *ds, int port, int regnum)
2417{
2418 struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
2419 int addr = mv88e6xxx_port_to_phy_addr(ds, port);
2420 int ret;
2421
2422 if (addr < 0)
2423 return addr;
2424
Andrew Lunn3898c142015-05-06 01:09:53 +02002425 mutex_lock(&ps->smi_mutex);
Andrew Lunnfd3a0ee2015-04-02 04:06:36 +02002426 ret = _mv88e6xxx_phy_read(ds, addr, regnum);
Andrew Lunn3898c142015-05-06 01:09:53 +02002427 mutex_unlock(&ps->smi_mutex);
Andrew Lunnfd3a0ee2015-04-02 04:06:36 +02002428 return ret;
2429}
2430
2431int
2432mv88e6xxx_phy_write(struct dsa_switch *ds, int port, int regnum, u16 val)
2433{
2434 struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
2435 int addr = mv88e6xxx_port_to_phy_addr(ds, port);
2436 int ret;
2437
2438 if (addr < 0)
2439 return addr;
2440
Andrew Lunn3898c142015-05-06 01:09:53 +02002441 mutex_lock(&ps->smi_mutex);
Andrew Lunnfd3a0ee2015-04-02 04:06:36 +02002442 ret = _mv88e6xxx_phy_write(ds, addr, regnum, val);
Andrew Lunn3898c142015-05-06 01:09:53 +02002443 mutex_unlock(&ps->smi_mutex);
Andrew Lunnfd3a0ee2015-04-02 04:06:36 +02002444 return ret;
2445}
2446
2447int
2448mv88e6xxx_phy_read_indirect(struct dsa_switch *ds, int port, int regnum)
2449{
2450 struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
2451 int addr = mv88e6xxx_port_to_phy_addr(ds, port);
2452 int ret;
2453
2454 if (addr < 0)
2455 return addr;
2456
Andrew Lunn3898c142015-05-06 01:09:53 +02002457 mutex_lock(&ps->smi_mutex);
Andrew Lunnfd3a0ee2015-04-02 04:06:36 +02002458 ret = _mv88e6xxx_phy_read_indirect(ds, addr, regnum);
Andrew Lunn3898c142015-05-06 01:09:53 +02002459 mutex_unlock(&ps->smi_mutex);
Andrew Lunnfd3a0ee2015-04-02 04:06:36 +02002460 return ret;
2461}
2462
2463int
2464mv88e6xxx_phy_write_indirect(struct dsa_switch *ds, int port, int regnum,
2465 u16 val)
2466{
2467 struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
2468 int addr = mv88e6xxx_port_to_phy_addr(ds, port);
2469 int ret;
2470
2471 if (addr < 0)
2472 return addr;
2473
Andrew Lunn3898c142015-05-06 01:09:53 +02002474 mutex_lock(&ps->smi_mutex);
Andrew Lunnfd3a0ee2015-04-02 04:06:36 +02002475 ret = _mv88e6xxx_phy_write_indirect(ds, addr, regnum, val);
Andrew Lunn3898c142015-05-06 01:09:53 +02002476 mutex_unlock(&ps->smi_mutex);
Andrew Lunn491435852015-04-02 04:06:35 +02002477 return ret;
2478}
2479
Guenter Roeckc22995c2015-07-25 09:42:28 -07002480#ifdef CONFIG_NET_DSA_HWMON
2481
2482static int mv88e61xx_get_temp(struct dsa_switch *ds, int *temp)
2483{
2484 struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
2485 int ret;
2486 int val;
2487
2488 *temp = 0;
2489
2490 mutex_lock(&ps->smi_mutex);
2491
2492 ret = _mv88e6xxx_phy_write(ds, 0x0, 0x16, 0x6);
2493 if (ret < 0)
2494 goto error;
2495
2496 /* Enable temperature sensor */
2497 ret = _mv88e6xxx_phy_read(ds, 0x0, 0x1a);
2498 if (ret < 0)
2499 goto error;
2500
2501 ret = _mv88e6xxx_phy_write(ds, 0x0, 0x1a, ret | (1 << 5));
2502 if (ret < 0)
2503 goto error;
2504
2505 /* Wait for temperature to stabilize */
2506 usleep_range(10000, 12000);
2507
2508 val = _mv88e6xxx_phy_read(ds, 0x0, 0x1a);
2509 if (val < 0) {
2510 ret = val;
2511 goto error;
2512 }
2513
2514 /* Disable temperature sensor */
2515 ret = _mv88e6xxx_phy_write(ds, 0x0, 0x1a, ret & ~(1 << 5));
2516 if (ret < 0)
2517 goto error;
2518
2519 *temp = ((val & 0x1f) - 5) * 5;
2520
2521error:
2522 _mv88e6xxx_phy_write(ds, 0x0, 0x16, 0x0);
2523 mutex_unlock(&ps->smi_mutex);
2524 return ret;
2525}
2526
2527static int mv88e63xx_get_temp(struct dsa_switch *ds, int *temp)
2528{
2529 int phy = mv88e6xxx_6320_family(ds) ? 3 : 0;
2530 int ret;
2531
2532 *temp = 0;
2533
2534 ret = mv88e6xxx_phy_page_read(ds, phy, 6, 27);
2535 if (ret < 0)
2536 return ret;
2537
2538 *temp = (ret & 0xff) - 25;
2539
2540 return 0;
2541}
2542
2543int mv88e6xxx_get_temp(struct dsa_switch *ds, int *temp)
2544{
2545 if (mv88e6xxx_6320_family(ds) || mv88e6xxx_6352_family(ds))
2546 return mv88e63xx_get_temp(ds, temp);
2547
2548 return mv88e61xx_get_temp(ds, temp);
2549}
2550
2551int mv88e6xxx_get_temp_limit(struct dsa_switch *ds, int *temp)
2552{
2553 int phy = mv88e6xxx_6320_family(ds) ? 3 : 0;
2554 int ret;
2555
2556 if (!mv88e6xxx_6320_family(ds) && !mv88e6xxx_6352_family(ds))
2557 return -EOPNOTSUPP;
2558
2559 *temp = 0;
2560
2561 ret = mv88e6xxx_phy_page_read(ds, phy, 6, 26);
2562 if (ret < 0)
2563 return ret;
2564
2565 *temp = (((ret >> 8) & 0x1f) * 5) - 25;
2566
2567 return 0;
2568}
2569
2570int mv88e6xxx_set_temp_limit(struct dsa_switch *ds, int temp)
2571{
2572 int phy = mv88e6xxx_6320_family(ds) ? 3 : 0;
2573 int ret;
2574
2575 if (!mv88e6xxx_6320_family(ds) && !mv88e6xxx_6352_family(ds))
2576 return -EOPNOTSUPP;
2577
2578 ret = mv88e6xxx_phy_page_read(ds, phy, 6, 26);
2579 if (ret < 0)
2580 return ret;
2581 temp = clamp_val(DIV_ROUND_CLOSEST(temp, 5) + 5, 0, 0x1f);
2582 return mv88e6xxx_phy_page_write(ds, phy, 6, 26,
2583 (ret & 0xe0ff) | (temp << 8));
2584}
2585
2586int mv88e6xxx_get_temp_alarm(struct dsa_switch *ds, bool *alarm)
2587{
2588 int phy = mv88e6xxx_6320_family(ds) ? 3 : 0;
2589 int ret;
2590
2591 if (!mv88e6xxx_6320_family(ds) && !mv88e6xxx_6352_family(ds))
2592 return -EOPNOTSUPP;
2593
2594 *alarm = false;
2595
2596 ret = mv88e6xxx_phy_page_read(ds, phy, 6, 26);
2597 if (ret < 0)
2598 return ret;
2599
2600 *alarm = !!(ret & 0x40);
2601
2602 return 0;
2603}
2604#endif /* CONFIG_NET_DSA_HWMON */
2605
Vivien Didelotb9b37712015-10-30 19:39:48 -04002606char *mv88e6xxx_lookup_name(struct device *host_dev, int sw_addr,
2607 const struct mv88e6xxx_switch_id *table,
2608 unsigned int num)
2609{
2610 struct mii_bus *bus = dsa_host_dev_to_mii_bus(host_dev);
2611 int i, ret;
2612
2613 if (!bus)
2614 return NULL;
2615
2616 ret = __mv88e6xxx_reg_read(bus, sw_addr, REG_PORT(0), PORT_SWITCH_ID);
2617 if (ret < 0)
2618 return NULL;
2619
2620 /* Look up the exact switch ID */
2621 for (i = 0; i < num; ++i)
2622 if (table[i].id == ret)
2623 return table[i].name;
2624
2625 /* Look up only the product number */
2626 for (i = 0; i < num; ++i) {
2627 if (table[i].id == (ret & PORT_SWITCH_ID_PROD_NUM_MASK)) {
2628 dev_warn(host_dev, "unknown revision %d, using base switch 0x%x\n",
2629 ret & PORT_SWITCH_ID_REV_MASK,
2630 ret & PORT_SWITCH_ID_PROD_NUM_MASK);
2631 return table[i].name;
2632 }
2633 }
2634
2635 return NULL;
2636}
2637
Ben Hutchings98e67302011-11-25 14:36:19 +00002638static int __init mv88e6xxx_init(void)
2639{
2640#if IS_ENABLED(CONFIG_NET_DSA_MV88E6131)
2641 register_switch_driver(&mv88e6131_switch_driver);
2642#endif
2643#if IS_ENABLED(CONFIG_NET_DSA_MV88E6123_61_65)
2644 register_switch_driver(&mv88e6123_61_65_switch_driver);
2645#endif
Guenter Roeck3ad50cc2014-10-29 10:44:56 -07002646#if IS_ENABLED(CONFIG_NET_DSA_MV88E6352)
2647 register_switch_driver(&mv88e6352_switch_driver);
2648#endif
Andrew Lunn42f27252014-09-12 23:58:44 +02002649#if IS_ENABLED(CONFIG_NET_DSA_MV88E6171)
2650 register_switch_driver(&mv88e6171_switch_driver);
2651#endif
Ben Hutchings98e67302011-11-25 14:36:19 +00002652 return 0;
2653}
2654module_init(mv88e6xxx_init);
2655
2656static void __exit mv88e6xxx_cleanup(void)
2657{
Andrew Lunn42f27252014-09-12 23:58:44 +02002658#if IS_ENABLED(CONFIG_NET_DSA_MV88E6171)
2659 unregister_switch_driver(&mv88e6171_switch_driver);
2660#endif
Vivien Didelot4212b542015-05-01 10:43:52 -04002661#if IS_ENABLED(CONFIG_NET_DSA_MV88E6352)
2662 unregister_switch_driver(&mv88e6352_switch_driver);
2663#endif
Ben Hutchings98e67302011-11-25 14:36:19 +00002664#if IS_ENABLED(CONFIG_NET_DSA_MV88E6123_61_65)
2665 unregister_switch_driver(&mv88e6123_61_65_switch_driver);
2666#endif
2667#if IS_ENABLED(CONFIG_NET_DSA_MV88E6131)
2668 unregister_switch_driver(&mv88e6131_switch_driver);
2669#endif
2670}
2671module_exit(mv88e6xxx_cleanup);
Ben Hutchings3d825ed2011-11-25 14:37:16 +00002672
2673MODULE_AUTHOR("Lennert Buytenhek <buytenh@wantstofly.org>");
2674MODULE_DESCRIPTION("Driver for Marvell 88E6XXX ethernet switch chips");
2675MODULE_LICENSE("GPL");