blob: fc5d4fdfcb02510e50f8297f4700bf46f9679af5 [file] [log] [blame]
Lennert Buytenhek91da11f2008-10-07 13:44:02 +00001/*
2 * net/dsa/mv88e6xxx.c - Marvell 88e6xxx switch chip support
3 * Copyright (c) 2008 Marvell Semiconductor
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 */
10
Andrew Lunn87c8cef2015-06-20 18:42:28 +020011#include <linux/debugfs.h>
Barry Grussling19b2f972013-01-08 16:05:54 +000012#include <linux/delay.h>
Guenter Roeckdefb05b2015-03-26 18:36:38 -070013#include <linux/etherdevice.h>
Guenter Roeckfacd95b2015-03-26 18:36:35 -070014#include <linux/if_bridge.h>
Barry Grussling19b2f972013-01-08 16:05:54 +000015#include <linux/jiffies.h>
Lennert Buytenhek91da11f2008-10-07 13:44:02 +000016#include <linux/list.h>
Paul Gortmaker2bbba272012-01-24 10:41:40 +000017#include <linux/module.h>
Lennert Buytenhek91da11f2008-10-07 13:44:02 +000018#include <linux/netdevice.h>
19#include <linux/phy.h>
Andrew Lunn87c8cef2015-06-20 18:42:28 +020020#include <linux/seq_file.h>
Ben Hutchingsc8f0b862011-11-27 17:06:08 +000021#include <net/dsa.h>
Lennert Buytenhek91da11f2008-10-07 13:44:02 +000022#include "mv88e6xxx.h"
23
Andrew Lunn16fe24f2015-05-06 01:09:55 +020024/* MDIO bus access can be nested in the case of PHYs connected to the
25 * internal MDIO bus of the switch, which is accessed via MDIO bus of
26 * the Ethernet interface. Avoid lockdep false positives by using
27 * mutex_lock_nested().
28 */
29static int mv88e6xxx_mdiobus_read(struct mii_bus *bus, int addr, u32 regnum)
30{
31 int ret;
32
33 mutex_lock_nested(&bus->mdio_lock, SINGLE_DEPTH_NESTING);
34 ret = bus->read(bus, addr, regnum);
35 mutex_unlock(&bus->mdio_lock);
36
37 return ret;
38}
39
40static int mv88e6xxx_mdiobus_write(struct mii_bus *bus, int addr, u32 regnum,
41 u16 val)
42{
43 int ret;
44
45 mutex_lock_nested(&bus->mdio_lock, SINGLE_DEPTH_NESTING);
46 ret = bus->write(bus, addr, regnum, val);
47 mutex_unlock(&bus->mdio_lock);
48
49 return ret;
50}
51
Barry Grussling3675c8d2013-01-08 16:05:53 +000052/* If the switch's ADDR[4:0] strap pins are strapped to zero, it will
Lennert Buytenhek91da11f2008-10-07 13:44:02 +000053 * use all 32 SMI bus addresses on its SMI bus, and all switch registers
54 * will be directly accessible on some {device address,register address}
55 * pair. If the ADDR[4:0] pins are not strapped to zero, the switch
56 * will only respond to SMI transactions to that specific address, and
57 * an indirect addressing mechanism needs to be used to access its
58 * registers.
59 */
60static int mv88e6xxx_reg_wait_ready(struct mii_bus *bus, int sw_addr)
61{
62 int ret;
63 int i;
64
65 for (i = 0; i < 16; i++) {
Andrew Lunn16fe24f2015-05-06 01:09:55 +020066 ret = mv88e6xxx_mdiobus_read(bus, sw_addr, SMI_CMD);
Lennert Buytenhek91da11f2008-10-07 13:44:02 +000067 if (ret < 0)
68 return ret;
69
Andrew Lunncca8b132015-04-02 04:06:39 +020070 if ((ret & SMI_CMD_BUSY) == 0)
Lennert Buytenhek91da11f2008-10-07 13:44:02 +000071 return 0;
72 }
73
74 return -ETIMEDOUT;
75}
76
77int __mv88e6xxx_reg_read(struct mii_bus *bus, int sw_addr, int addr, int reg)
78{
79 int ret;
80
81 if (sw_addr == 0)
Andrew Lunn16fe24f2015-05-06 01:09:55 +020082 return mv88e6xxx_mdiobus_read(bus, addr, reg);
Lennert Buytenhek91da11f2008-10-07 13:44:02 +000083
Barry Grussling3675c8d2013-01-08 16:05:53 +000084 /* Wait for the bus to become free. */
Lennert Buytenhek91da11f2008-10-07 13:44:02 +000085 ret = mv88e6xxx_reg_wait_ready(bus, sw_addr);
86 if (ret < 0)
87 return ret;
88
Barry Grussling3675c8d2013-01-08 16:05:53 +000089 /* Transmit the read command. */
Andrew Lunn16fe24f2015-05-06 01:09:55 +020090 ret = mv88e6xxx_mdiobus_write(bus, sw_addr, SMI_CMD,
91 SMI_CMD_OP_22_READ | (addr << 5) | reg);
Lennert Buytenhek91da11f2008-10-07 13:44:02 +000092 if (ret < 0)
93 return ret;
94
Barry Grussling3675c8d2013-01-08 16:05:53 +000095 /* Wait for the read command to complete. */
Lennert Buytenhek91da11f2008-10-07 13:44:02 +000096 ret = mv88e6xxx_reg_wait_ready(bus, sw_addr);
97 if (ret < 0)
98 return ret;
99
Barry Grussling3675c8d2013-01-08 16:05:53 +0000100 /* Read the data. */
Andrew Lunn16fe24f2015-05-06 01:09:55 +0200101 ret = mv88e6xxx_mdiobus_read(bus, sw_addr, SMI_DATA);
Lennert Buytenhek91da11f2008-10-07 13:44:02 +0000102 if (ret < 0)
103 return ret;
104
105 return ret & 0xffff;
106}
107
Guenter Roeck8d6d09e2015-03-26 18:36:31 -0700108/* Must be called with SMI mutex held */
109static int _mv88e6xxx_reg_read(struct dsa_switch *ds, int addr, int reg)
Lennert Buytenhek91da11f2008-10-07 13:44:02 +0000110{
Guenter Roeckb184e492014-10-17 12:30:58 -0700111 struct mii_bus *bus = dsa_host_dev_to_mii_bus(ds->master_dev);
Lennert Buytenhek91da11f2008-10-07 13:44:02 +0000112 int ret;
113
Guenter Roeckb184e492014-10-17 12:30:58 -0700114 if (bus == NULL)
115 return -EINVAL;
116
Guenter Roeckb184e492014-10-17 12:30:58 -0700117 ret = __mv88e6xxx_reg_read(bus, ds->pd->sw_addr, addr, reg);
Vivien Didelotbb92ea52015-01-23 16:10:36 -0500118 if (ret < 0)
119 return ret;
120
121 dev_dbg(ds->master_dev, "<- addr: 0x%.2x reg: 0x%.2x val: 0x%.4x\n",
122 addr, reg, ret);
123
Lennert Buytenhek91da11f2008-10-07 13:44:02 +0000124 return ret;
125}
126
Guenter Roeck8d6d09e2015-03-26 18:36:31 -0700127int mv88e6xxx_reg_read(struct dsa_switch *ds, int addr, int reg)
128{
129 struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
130 int ret;
131
132 mutex_lock(&ps->smi_mutex);
133 ret = _mv88e6xxx_reg_read(ds, addr, reg);
134 mutex_unlock(&ps->smi_mutex);
135
136 return ret;
137}
138
Lennert Buytenhek91da11f2008-10-07 13:44:02 +0000139int __mv88e6xxx_reg_write(struct mii_bus *bus, int sw_addr, int addr,
140 int reg, u16 val)
141{
142 int ret;
143
144 if (sw_addr == 0)
Andrew Lunn16fe24f2015-05-06 01:09:55 +0200145 return mv88e6xxx_mdiobus_write(bus, addr, reg, val);
Lennert Buytenhek91da11f2008-10-07 13:44:02 +0000146
Barry Grussling3675c8d2013-01-08 16:05:53 +0000147 /* Wait for the bus to become free. */
Lennert Buytenhek91da11f2008-10-07 13:44:02 +0000148 ret = mv88e6xxx_reg_wait_ready(bus, sw_addr);
149 if (ret < 0)
150 return ret;
151
Barry Grussling3675c8d2013-01-08 16:05:53 +0000152 /* Transmit the data to write. */
Andrew Lunn16fe24f2015-05-06 01:09:55 +0200153 ret = mv88e6xxx_mdiobus_write(bus, sw_addr, SMI_DATA, val);
Lennert Buytenhek91da11f2008-10-07 13:44:02 +0000154 if (ret < 0)
155 return ret;
156
Barry Grussling3675c8d2013-01-08 16:05:53 +0000157 /* Transmit the write command. */
Andrew Lunn16fe24f2015-05-06 01:09:55 +0200158 ret = mv88e6xxx_mdiobus_write(bus, sw_addr, SMI_CMD,
159 SMI_CMD_OP_22_WRITE | (addr << 5) | reg);
Lennert Buytenhek91da11f2008-10-07 13:44:02 +0000160 if (ret < 0)
161 return ret;
162
Barry Grussling3675c8d2013-01-08 16:05:53 +0000163 /* Wait for the write command to complete. */
Lennert Buytenhek91da11f2008-10-07 13:44:02 +0000164 ret = mv88e6xxx_reg_wait_ready(bus, sw_addr);
165 if (ret < 0)
166 return ret;
167
168 return 0;
169}
170
Guenter Roeck8d6d09e2015-03-26 18:36:31 -0700171/* Must be called with SMI mutex held */
172static int _mv88e6xxx_reg_write(struct dsa_switch *ds, int addr, int reg,
173 u16 val)
Lennert Buytenhek91da11f2008-10-07 13:44:02 +0000174{
Guenter Roeckb184e492014-10-17 12:30:58 -0700175 struct mii_bus *bus = dsa_host_dev_to_mii_bus(ds->master_dev);
Lennert Buytenhek91da11f2008-10-07 13:44:02 +0000176
Guenter Roeckb184e492014-10-17 12:30:58 -0700177 if (bus == NULL)
178 return -EINVAL;
179
Vivien Didelotbb92ea52015-01-23 16:10:36 -0500180 dev_dbg(ds->master_dev, "-> addr: 0x%.2x reg: 0x%.2x val: 0x%.4x\n",
181 addr, reg, val);
182
Guenter Roeck8d6d09e2015-03-26 18:36:31 -0700183 return __mv88e6xxx_reg_write(bus, ds->pd->sw_addr, addr, reg, val);
184}
185
186int mv88e6xxx_reg_write(struct dsa_switch *ds, int addr, int reg, u16 val)
187{
188 struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
189 int ret;
190
Lennert Buytenhek91da11f2008-10-07 13:44:02 +0000191 mutex_lock(&ps->smi_mutex);
Guenter Roeck8d6d09e2015-03-26 18:36:31 -0700192 ret = _mv88e6xxx_reg_write(ds, addr, reg, val);
Lennert Buytenhek91da11f2008-10-07 13:44:02 +0000193 mutex_unlock(&ps->smi_mutex);
194
195 return ret;
196}
197
Lennert Buytenhek2e5f0322008-10-07 13:45:18 +0000198int mv88e6xxx_set_addr_direct(struct dsa_switch *ds, u8 *addr)
199{
Andrew Lunncca8b132015-04-02 04:06:39 +0200200 REG_WRITE(REG_GLOBAL, GLOBAL_MAC_01, (addr[0] << 8) | addr[1]);
201 REG_WRITE(REG_GLOBAL, GLOBAL_MAC_23, (addr[2] << 8) | addr[3]);
202 REG_WRITE(REG_GLOBAL, GLOBAL_MAC_45, (addr[4] << 8) | addr[5]);
Lennert Buytenhek2e5f0322008-10-07 13:45:18 +0000203
204 return 0;
205}
206
Lennert Buytenhek91da11f2008-10-07 13:44:02 +0000207int mv88e6xxx_set_addr_indirect(struct dsa_switch *ds, u8 *addr)
208{
209 int i;
210 int ret;
211
212 for (i = 0; i < 6; i++) {
213 int j;
214
Barry Grussling3675c8d2013-01-08 16:05:53 +0000215 /* Write the MAC address byte. */
Andrew Lunncca8b132015-04-02 04:06:39 +0200216 REG_WRITE(REG_GLOBAL2, GLOBAL2_SWITCH_MAC,
217 GLOBAL2_SWITCH_MAC_BUSY | (i << 8) | addr[i]);
Lennert Buytenhek91da11f2008-10-07 13:44:02 +0000218
Barry Grussling3675c8d2013-01-08 16:05:53 +0000219 /* Wait for the write to complete. */
Lennert Buytenhek91da11f2008-10-07 13:44:02 +0000220 for (j = 0; j < 16; j++) {
Andrew Lunncca8b132015-04-02 04:06:39 +0200221 ret = REG_READ(REG_GLOBAL2, GLOBAL2_SWITCH_MAC);
222 if ((ret & GLOBAL2_SWITCH_MAC_BUSY) == 0)
Lennert Buytenhek91da11f2008-10-07 13:44:02 +0000223 break;
224 }
225 if (j == 16)
226 return -ETIMEDOUT;
227 }
228
229 return 0;
230}
231
Andrew Lunn3898c142015-05-06 01:09:53 +0200232/* Must be called with SMI mutex held */
Andrew Lunnfd3a0ee2015-04-02 04:06:36 +0200233static int _mv88e6xxx_phy_read(struct dsa_switch *ds, int addr, int regnum)
Lennert Buytenhek91da11f2008-10-07 13:44:02 +0000234{
235 if (addr >= 0)
Andrew Lunn3898c142015-05-06 01:09:53 +0200236 return _mv88e6xxx_reg_read(ds, addr, regnum);
Lennert Buytenhek91da11f2008-10-07 13:44:02 +0000237 return 0xffff;
238}
239
Andrew Lunn3898c142015-05-06 01:09:53 +0200240/* Must be called with SMI mutex held */
Andrew Lunnfd3a0ee2015-04-02 04:06:36 +0200241static int _mv88e6xxx_phy_write(struct dsa_switch *ds, int addr, int regnum,
242 u16 val)
Lennert Buytenhek91da11f2008-10-07 13:44:02 +0000243{
244 if (addr >= 0)
Andrew Lunn3898c142015-05-06 01:09:53 +0200245 return _mv88e6xxx_reg_write(ds, addr, regnum, val);
Lennert Buytenhek91da11f2008-10-07 13:44:02 +0000246 return 0;
247}
248
Lennert Buytenhek2e5f0322008-10-07 13:45:18 +0000249#ifdef CONFIG_NET_DSA_MV88E6XXX_NEED_PPU
250static int mv88e6xxx_ppu_disable(struct dsa_switch *ds)
251{
252 int ret;
Barry Grussling19b2f972013-01-08 16:05:54 +0000253 unsigned long timeout;
Lennert Buytenhek2e5f0322008-10-07 13:45:18 +0000254
Andrew Lunncca8b132015-04-02 04:06:39 +0200255 ret = REG_READ(REG_GLOBAL, GLOBAL_CONTROL);
256 REG_WRITE(REG_GLOBAL, GLOBAL_CONTROL,
257 ret & ~GLOBAL_CONTROL_PPU_ENABLE);
Lennert Buytenhek2e5f0322008-10-07 13:45:18 +0000258
Barry Grussling19b2f972013-01-08 16:05:54 +0000259 timeout = jiffies + 1 * HZ;
260 while (time_before(jiffies, timeout)) {
Andrew Lunncca8b132015-04-02 04:06:39 +0200261 ret = REG_READ(REG_GLOBAL, GLOBAL_STATUS);
Barry Grussling19b2f972013-01-08 16:05:54 +0000262 usleep_range(1000, 2000);
Andrew Lunncca8b132015-04-02 04:06:39 +0200263 if ((ret & GLOBAL_STATUS_PPU_MASK) !=
264 GLOBAL_STATUS_PPU_POLLING)
Barry Grussling85686582013-01-08 16:05:56 +0000265 return 0;
Lennert Buytenhek2e5f0322008-10-07 13:45:18 +0000266 }
267
268 return -ETIMEDOUT;
269}
270
271static int mv88e6xxx_ppu_enable(struct dsa_switch *ds)
272{
273 int ret;
Barry Grussling19b2f972013-01-08 16:05:54 +0000274 unsigned long timeout;
Lennert Buytenhek2e5f0322008-10-07 13:45:18 +0000275
Andrew Lunncca8b132015-04-02 04:06:39 +0200276 ret = REG_READ(REG_GLOBAL, GLOBAL_CONTROL);
277 REG_WRITE(REG_GLOBAL, GLOBAL_CONTROL, ret | GLOBAL_CONTROL_PPU_ENABLE);
Lennert Buytenhek2e5f0322008-10-07 13:45:18 +0000278
Barry Grussling19b2f972013-01-08 16:05:54 +0000279 timeout = jiffies + 1 * HZ;
280 while (time_before(jiffies, timeout)) {
Andrew Lunncca8b132015-04-02 04:06:39 +0200281 ret = REG_READ(REG_GLOBAL, GLOBAL_STATUS);
Barry Grussling19b2f972013-01-08 16:05:54 +0000282 usleep_range(1000, 2000);
Andrew Lunncca8b132015-04-02 04:06:39 +0200283 if ((ret & GLOBAL_STATUS_PPU_MASK) ==
284 GLOBAL_STATUS_PPU_POLLING)
Barry Grussling85686582013-01-08 16:05:56 +0000285 return 0;
Lennert Buytenhek2e5f0322008-10-07 13:45:18 +0000286 }
287
288 return -ETIMEDOUT;
289}
290
291static void mv88e6xxx_ppu_reenable_work(struct work_struct *ugly)
292{
293 struct mv88e6xxx_priv_state *ps;
294
295 ps = container_of(ugly, struct mv88e6xxx_priv_state, ppu_work);
296 if (mutex_trylock(&ps->ppu_mutex)) {
Barry Grussling85686582013-01-08 16:05:56 +0000297 struct dsa_switch *ds = ((struct dsa_switch *)ps) - 1;
Lennert Buytenhek2e5f0322008-10-07 13:45:18 +0000298
Barry Grussling85686582013-01-08 16:05:56 +0000299 if (mv88e6xxx_ppu_enable(ds) == 0)
300 ps->ppu_disabled = 0;
301 mutex_unlock(&ps->ppu_mutex);
Lennert Buytenhek2e5f0322008-10-07 13:45:18 +0000302 }
303}
304
305static void mv88e6xxx_ppu_reenable_timer(unsigned long _ps)
306{
307 struct mv88e6xxx_priv_state *ps = (void *)_ps;
308
309 schedule_work(&ps->ppu_work);
310}
311
312static int mv88e6xxx_ppu_access_get(struct dsa_switch *ds)
313{
Florian Fainellia22adce2014-04-28 11:14:28 -0700314 struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
Lennert Buytenhek2e5f0322008-10-07 13:45:18 +0000315 int ret;
316
317 mutex_lock(&ps->ppu_mutex);
318
Barry Grussling3675c8d2013-01-08 16:05:53 +0000319 /* If the PHY polling unit is enabled, disable it so that
Lennert Buytenhek2e5f0322008-10-07 13:45:18 +0000320 * we can access the PHY registers. If it was already
321 * disabled, cancel the timer that is going to re-enable
322 * it.
323 */
324 if (!ps->ppu_disabled) {
Barry Grussling85686582013-01-08 16:05:56 +0000325 ret = mv88e6xxx_ppu_disable(ds);
326 if (ret < 0) {
327 mutex_unlock(&ps->ppu_mutex);
328 return ret;
329 }
330 ps->ppu_disabled = 1;
Lennert Buytenhek2e5f0322008-10-07 13:45:18 +0000331 } else {
Barry Grussling85686582013-01-08 16:05:56 +0000332 del_timer(&ps->ppu_timer);
333 ret = 0;
Lennert Buytenhek2e5f0322008-10-07 13:45:18 +0000334 }
335
336 return ret;
337}
338
339static void mv88e6xxx_ppu_access_put(struct dsa_switch *ds)
340{
Florian Fainellia22adce2014-04-28 11:14:28 -0700341 struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
Lennert Buytenhek2e5f0322008-10-07 13:45:18 +0000342
Barry Grussling3675c8d2013-01-08 16:05:53 +0000343 /* Schedule a timer to re-enable the PHY polling unit. */
Lennert Buytenhek2e5f0322008-10-07 13:45:18 +0000344 mod_timer(&ps->ppu_timer, jiffies + msecs_to_jiffies(10));
345 mutex_unlock(&ps->ppu_mutex);
346}
347
348void mv88e6xxx_ppu_state_init(struct dsa_switch *ds)
349{
Florian Fainellia22adce2014-04-28 11:14:28 -0700350 struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
Lennert Buytenhek2e5f0322008-10-07 13:45:18 +0000351
352 mutex_init(&ps->ppu_mutex);
353 INIT_WORK(&ps->ppu_work, mv88e6xxx_ppu_reenable_work);
354 init_timer(&ps->ppu_timer);
355 ps->ppu_timer.data = (unsigned long)ps;
356 ps->ppu_timer.function = mv88e6xxx_ppu_reenable_timer;
357}
358
359int mv88e6xxx_phy_read_ppu(struct dsa_switch *ds, int addr, int regnum)
360{
361 int ret;
362
363 ret = mv88e6xxx_ppu_access_get(ds);
364 if (ret >= 0) {
Barry Grussling85686582013-01-08 16:05:56 +0000365 ret = mv88e6xxx_reg_read(ds, addr, regnum);
366 mv88e6xxx_ppu_access_put(ds);
Lennert Buytenhek2e5f0322008-10-07 13:45:18 +0000367 }
368
369 return ret;
370}
371
372int mv88e6xxx_phy_write_ppu(struct dsa_switch *ds, int addr,
373 int regnum, u16 val)
374{
375 int ret;
376
377 ret = mv88e6xxx_ppu_access_get(ds);
378 if (ret >= 0) {
Barry Grussling85686582013-01-08 16:05:56 +0000379 ret = mv88e6xxx_reg_write(ds, addr, regnum, val);
380 mv88e6xxx_ppu_access_put(ds);
Lennert Buytenhek2e5f0322008-10-07 13:45:18 +0000381 }
382
383 return ret;
384}
385#endif
386
Lennert Buytenhek91da11f2008-10-07 13:44:02 +0000387void mv88e6xxx_poll_link(struct dsa_switch *ds)
388{
389 int i;
390
391 for (i = 0; i < DSA_MAX_PORTS; i++) {
392 struct net_device *dev;
Ingo Molnar2a9e7972008-11-25 16:50:49 -0800393 int uninitialized_var(port_status);
Lennert Buytenhek91da11f2008-10-07 13:44:02 +0000394 int link;
395 int speed;
396 int duplex;
397 int fc;
398
399 dev = ds->ports[i];
400 if (dev == NULL)
401 continue;
402
403 link = 0;
404 if (dev->flags & IFF_UP) {
Andrew Lunncca8b132015-04-02 04:06:39 +0200405 port_status = mv88e6xxx_reg_read(ds, REG_PORT(i),
406 PORT_STATUS);
Lennert Buytenhek91da11f2008-10-07 13:44:02 +0000407 if (port_status < 0)
408 continue;
409
Andrew Lunncca8b132015-04-02 04:06:39 +0200410 link = !!(port_status & PORT_STATUS_LINK);
Lennert Buytenhek91da11f2008-10-07 13:44:02 +0000411 }
412
413 if (!link) {
414 if (netif_carrier_ok(dev)) {
Barry Grusslingab381a92013-01-08 16:05:55 +0000415 netdev_info(dev, "link down\n");
Lennert Buytenhek91da11f2008-10-07 13:44:02 +0000416 netif_carrier_off(dev);
417 }
418 continue;
419 }
420
Andrew Lunncca8b132015-04-02 04:06:39 +0200421 switch (port_status & PORT_STATUS_SPEED_MASK) {
422 case PORT_STATUS_SPEED_10:
Lennert Buytenhek91da11f2008-10-07 13:44:02 +0000423 speed = 10;
424 break;
Andrew Lunncca8b132015-04-02 04:06:39 +0200425 case PORT_STATUS_SPEED_100:
Lennert Buytenhek91da11f2008-10-07 13:44:02 +0000426 speed = 100;
427 break;
Andrew Lunncca8b132015-04-02 04:06:39 +0200428 case PORT_STATUS_SPEED_1000:
Lennert Buytenhek91da11f2008-10-07 13:44:02 +0000429 speed = 1000;
430 break;
431 default:
432 speed = -1;
433 break;
434 }
Andrew Lunncca8b132015-04-02 04:06:39 +0200435 duplex = (port_status & PORT_STATUS_DUPLEX) ? 1 : 0;
436 fc = (port_status & PORT_STATUS_PAUSE_EN) ? 1 : 0;
Lennert Buytenhek91da11f2008-10-07 13:44:02 +0000437
438 if (!netif_carrier_ok(dev)) {
Barry Grusslingab381a92013-01-08 16:05:55 +0000439 netdev_info(dev,
440 "link up, %d Mb/s, %s duplex, flow control %sabled\n",
441 speed,
442 duplex ? "full" : "half",
443 fc ? "en" : "dis");
Lennert Buytenhek91da11f2008-10-07 13:44:02 +0000444 netif_carrier_on(dev);
445 }
446 }
447}
448
Andrew Lunn54d792f2015-05-06 01:09:47 +0200449static bool mv88e6xxx_6065_family(struct dsa_switch *ds)
450{
451 struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
452
453 switch (ps->id) {
454 case PORT_SWITCH_ID_6031:
455 case PORT_SWITCH_ID_6061:
456 case PORT_SWITCH_ID_6035:
457 case PORT_SWITCH_ID_6065:
458 return true;
459 }
460 return false;
461}
462
463static bool mv88e6xxx_6095_family(struct dsa_switch *ds)
464{
465 struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
466
467 switch (ps->id) {
468 case PORT_SWITCH_ID_6092:
469 case PORT_SWITCH_ID_6095:
470 return true;
471 }
472 return false;
473}
474
475static bool mv88e6xxx_6097_family(struct dsa_switch *ds)
476{
477 struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
478
479 switch (ps->id) {
480 case PORT_SWITCH_ID_6046:
481 case PORT_SWITCH_ID_6085:
482 case PORT_SWITCH_ID_6096:
483 case PORT_SWITCH_ID_6097:
484 return true;
485 }
486 return false;
487}
488
489static bool mv88e6xxx_6165_family(struct dsa_switch *ds)
490{
491 struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
492
493 switch (ps->id) {
494 case PORT_SWITCH_ID_6123:
495 case PORT_SWITCH_ID_6161:
496 case PORT_SWITCH_ID_6165:
497 return true;
498 }
499 return false;
500}
501
502static bool mv88e6xxx_6185_family(struct dsa_switch *ds)
503{
504 struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
505
506 switch (ps->id) {
507 case PORT_SWITCH_ID_6121:
508 case PORT_SWITCH_ID_6122:
509 case PORT_SWITCH_ID_6152:
510 case PORT_SWITCH_ID_6155:
511 case PORT_SWITCH_ID_6182:
512 case PORT_SWITCH_ID_6185:
513 case PORT_SWITCH_ID_6108:
514 case PORT_SWITCH_ID_6131:
515 return true;
516 }
517 return false;
518}
519
520static bool mv88e6xxx_6351_family(struct dsa_switch *ds)
521{
522 struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
523
524 switch (ps->id) {
525 case PORT_SWITCH_ID_6171:
526 case PORT_SWITCH_ID_6175:
527 case PORT_SWITCH_ID_6350:
528 case PORT_SWITCH_ID_6351:
529 return true;
530 }
531 return false;
532}
533
Andrew Lunnf3a8b6b2015-04-02 04:06:40 +0200534static bool mv88e6xxx_6352_family(struct dsa_switch *ds)
535{
536 struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
537
538 switch (ps->id) {
Andrew Lunnf3a8b6b2015-04-02 04:06:40 +0200539 case PORT_SWITCH_ID_6172:
540 case PORT_SWITCH_ID_6176:
Andrew Lunn54d792f2015-05-06 01:09:47 +0200541 case PORT_SWITCH_ID_6240:
542 case PORT_SWITCH_ID_6352:
Andrew Lunnf3a8b6b2015-04-02 04:06:40 +0200543 return true;
544 }
545 return false;
546}
547
Andrew Lunn31888232015-05-06 01:09:54 +0200548/* Must be called with SMI mutex held */
549static int _mv88e6xxx_stats_wait(struct dsa_switch *ds)
Lennert Buytenhek91da11f2008-10-07 13:44:02 +0000550{
551 int ret;
552 int i;
553
554 for (i = 0; i < 10; i++) {
Andrew Lunn31888232015-05-06 01:09:54 +0200555 ret = _mv88e6xxx_reg_read(ds, REG_GLOBAL, GLOBAL_STATS_OP);
Andrew Lunncca8b132015-04-02 04:06:39 +0200556 if ((ret & GLOBAL_STATS_OP_BUSY) == 0)
Lennert Buytenhek91da11f2008-10-07 13:44:02 +0000557 return 0;
558 }
559
560 return -ETIMEDOUT;
561}
562
Andrew Lunn31888232015-05-06 01:09:54 +0200563/* Must be called with SMI mutex held */
564static int _mv88e6xxx_stats_snapshot(struct dsa_switch *ds, int port)
Lennert Buytenhek91da11f2008-10-07 13:44:02 +0000565{
566 int ret;
567
Andrew Lunnf3a8b6b2015-04-02 04:06:40 +0200568 if (mv88e6xxx_6352_family(ds))
569 port = (port + 1) << 5;
570
Barry Grussling3675c8d2013-01-08 16:05:53 +0000571 /* Snapshot the hardware statistics counters for this port. */
Andrew Lunn31888232015-05-06 01:09:54 +0200572 ret = _mv88e6xxx_reg_write(ds, REG_GLOBAL, GLOBAL_STATS_OP,
573 GLOBAL_STATS_OP_CAPTURE_PORT |
574 GLOBAL_STATS_OP_HIST_RX_TX | port);
575 if (ret < 0)
576 return ret;
Lennert Buytenhek91da11f2008-10-07 13:44:02 +0000577
Barry Grussling3675c8d2013-01-08 16:05:53 +0000578 /* Wait for the snapshotting to complete. */
Andrew Lunn31888232015-05-06 01:09:54 +0200579 ret = _mv88e6xxx_stats_wait(ds);
Lennert Buytenhek91da11f2008-10-07 13:44:02 +0000580 if (ret < 0)
581 return ret;
582
583 return 0;
584}
585
Andrew Lunn31888232015-05-06 01:09:54 +0200586/* Must be called with SMI mutex held */
587static void _mv88e6xxx_stats_read(struct dsa_switch *ds, int stat, u32 *val)
Lennert Buytenhek91da11f2008-10-07 13:44:02 +0000588{
589 u32 _val;
590 int ret;
591
592 *val = 0;
593
Andrew Lunn31888232015-05-06 01:09:54 +0200594 ret = _mv88e6xxx_reg_write(ds, REG_GLOBAL, GLOBAL_STATS_OP,
595 GLOBAL_STATS_OP_READ_CAPTURED |
596 GLOBAL_STATS_OP_HIST_RX_TX | stat);
Lennert Buytenhek91da11f2008-10-07 13:44:02 +0000597 if (ret < 0)
598 return;
599
Andrew Lunn31888232015-05-06 01:09:54 +0200600 ret = _mv88e6xxx_stats_wait(ds);
Lennert Buytenhek91da11f2008-10-07 13:44:02 +0000601 if (ret < 0)
602 return;
603
Andrew Lunn31888232015-05-06 01:09:54 +0200604 ret = _mv88e6xxx_reg_read(ds, REG_GLOBAL, GLOBAL_STATS_COUNTER_32);
Lennert Buytenhek91da11f2008-10-07 13:44:02 +0000605 if (ret < 0)
606 return;
607
608 _val = ret << 16;
609
Andrew Lunn31888232015-05-06 01:09:54 +0200610 ret = _mv88e6xxx_reg_read(ds, REG_GLOBAL, GLOBAL_STATS_COUNTER_01);
Lennert Buytenhek91da11f2008-10-07 13:44:02 +0000611 if (ret < 0)
612 return;
613
614 *val = _val | ret;
615}
616
Andrew Lunne413e7e2015-04-02 04:06:38 +0200617static struct mv88e6xxx_hw_stat mv88e6xxx_hw_stats[] = {
618 { "in_good_octets", 8, 0x00, },
619 { "in_bad_octets", 4, 0x02, },
620 { "in_unicast", 4, 0x04, },
621 { "in_broadcasts", 4, 0x06, },
622 { "in_multicasts", 4, 0x07, },
623 { "in_pause", 4, 0x16, },
624 { "in_undersize", 4, 0x18, },
625 { "in_fragments", 4, 0x19, },
626 { "in_oversize", 4, 0x1a, },
627 { "in_jabber", 4, 0x1b, },
628 { "in_rx_error", 4, 0x1c, },
629 { "in_fcs_error", 4, 0x1d, },
630 { "out_octets", 8, 0x0e, },
631 { "out_unicast", 4, 0x10, },
632 { "out_broadcasts", 4, 0x13, },
633 { "out_multicasts", 4, 0x12, },
634 { "out_pause", 4, 0x15, },
635 { "excessive", 4, 0x11, },
636 { "collisions", 4, 0x1e, },
637 { "deferred", 4, 0x05, },
638 { "single", 4, 0x14, },
639 { "multiple", 4, 0x17, },
640 { "out_fcs_error", 4, 0x03, },
641 { "late", 4, 0x1f, },
642 { "hist_64bytes", 4, 0x08, },
643 { "hist_65_127bytes", 4, 0x09, },
644 { "hist_128_255bytes", 4, 0x0a, },
645 { "hist_256_511bytes", 4, 0x0b, },
646 { "hist_512_1023bytes", 4, 0x0c, },
647 { "hist_1024_max_bytes", 4, 0x0d, },
648 /* Not all devices have the following counters */
649 { "sw_in_discards", 4, 0x110, },
650 { "sw_in_filtered", 2, 0x112, },
651 { "sw_out_filtered", 2, 0x113, },
652
653};
654
655static bool have_sw_in_discards(struct dsa_switch *ds)
656{
657 struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
658
659 switch (ps->id) {
Andrew Lunncca8b132015-04-02 04:06:39 +0200660 case PORT_SWITCH_ID_6095: case PORT_SWITCH_ID_6161:
661 case PORT_SWITCH_ID_6165: case PORT_SWITCH_ID_6171:
662 case PORT_SWITCH_ID_6172: case PORT_SWITCH_ID_6176:
663 case PORT_SWITCH_ID_6182: case PORT_SWITCH_ID_6185:
664 case PORT_SWITCH_ID_6352:
Andrew Lunne413e7e2015-04-02 04:06:38 +0200665 return true;
666 default:
667 return false;
668 }
669}
670
671static void _mv88e6xxx_get_strings(struct dsa_switch *ds,
672 int nr_stats,
673 struct mv88e6xxx_hw_stat *stats,
674 int port, uint8_t *data)
Lennert Buytenhek91da11f2008-10-07 13:44:02 +0000675{
676 int i;
677
678 for (i = 0; i < nr_stats; i++) {
679 memcpy(data + i * ETH_GSTRING_LEN,
680 stats[i].string, ETH_GSTRING_LEN);
681 }
682}
683
Andrew Lunn80c46272015-06-20 18:42:30 +0200684static uint64_t _mv88e6xxx_get_ethtool_stat(struct dsa_switch *ds,
685 int stat,
686 struct mv88e6xxx_hw_stat *stats,
687 int port)
688{
689 struct mv88e6xxx_hw_stat *s = stats + stat;
690 u32 low;
691 u32 high = 0;
692 int ret;
693 u64 value;
694
695 if (s->reg >= 0x100) {
696 ret = _mv88e6xxx_reg_read(ds, REG_PORT(port),
697 s->reg - 0x100);
698 if (ret < 0)
699 return UINT64_MAX;
700
701 low = ret;
702 if (s->sizeof_stat == 4) {
703 ret = _mv88e6xxx_reg_read(ds, REG_PORT(port),
704 s->reg - 0x100 + 1);
705 if (ret < 0)
706 return UINT64_MAX;
707 high = ret;
708 }
709 } else {
710 _mv88e6xxx_stats_read(ds, s->reg, &low);
711 if (s->sizeof_stat == 8)
712 _mv88e6xxx_stats_read(ds, s->reg + 1, &high);
713 }
714 value = (((u64)high) << 16) | low;
715 return value;
716}
717
Andrew Lunne413e7e2015-04-02 04:06:38 +0200718static void _mv88e6xxx_get_ethtool_stats(struct dsa_switch *ds,
719 int nr_stats,
720 struct mv88e6xxx_hw_stat *stats,
721 int port, uint64_t *data)
Lennert Buytenhek91da11f2008-10-07 13:44:02 +0000722{
Florian Fainellia22adce2014-04-28 11:14:28 -0700723 struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
Lennert Buytenhek91da11f2008-10-07 13:44:02 +0000724 int ret;
725 int i;
726
Andrew Lunn31888232015-05-06 01:09:54 +0200727 mutex_lock(&ps->smi_mutex);
Lennert Buytenhek91da11f2008-10-07 13:44:02 +0000728
Andrew Lunn31888232015-05-06 01:09:54 +0200729 ret = _mv88e6xxx_stats_snapshot(ds, port);
Lennert Buytenhek91da11f2008-10-07 13:44:02 +0000730 if (ret < 0) {
Andrew Lunn31888232015-05-06 01:09:54 +0200731 mutex_unlock(&ps->smi_mutex);
Lennert Buytenhek91da11f2008-10-07 13:44:02 +0000732 return;
733 }
734
Barry Grussling3675c8d2013-01-08 16:05:53 +0000735 /* Read each of the counters. */
Andrew Lunn80c46272015-06-20 18:42:30 +0200736 for (i = 0; i < nr_stats; i++)
737 data[i] = _mv88e6xxx_get_ethtool_stat(ds, i, stats, port);
Lennert Buytenhek91da11f2008-10-07 13:44:02 +0000738
Andrew Lunn31888232015-05-06 01:09:54 +0200739 mutex_unlock(&ps->smi_mutex);
Lennert Buytenhek91da11f2008-10-07 13:44:02 +0000740}
Ben Hutchings98e67302011-11-25 14:36:19 +0000741
Andrew Lunne413e7e2015-04-02 04:06:38 +0200742/* All the statistics in the table */
743void
744mv88e6xxx_get_strings(struct dsa_switch *ds, int port, uint8_t *data)
745{
746 if (have_sw_in_discards(ds))
747 _mv88e6xxx_get_strings(ds, ARRAY_SIZE(mv88e6xxx_hw_stats),
748 mv88e6xxx_hw_stats, port, data);
749 else
750 _mv88e6xxx_get_strings(ds, ARRAY_SIZE(mv88e6xxx_hw_stats) - 3,
751 mv88e6xxx_hw_stats, port, data);
752}
753
754int mv88e6xxx_get_sset_count(struct dsa_switch *ds)
755{
756 if (have_sw_in_discards(ds))
757 return ARRAY_SIZE(mv88e6xxx_hw_stats);
758 return ARRAY_SIZE(mv88e6xxx_hw_stats) - 3;
759}
760
761void
762mv88e6xxx_get_ethtool_stats(struct dsa_switch *ds,
763 int port, uint64_t *data)
764{
765 if (have_sw_in_discards(ds))
766 _mv88e6xxx_get_ethtool_stats(
767 ds, ARRAY_SIZE(mv88e6xxx_hw_stats),
768 mv88e6xxx_hw_stats, port, data);
769 else
770 _mv88e6xxx_get_ethtool_stats(
771 ds, ARRAY_SIZE(mv88e6xxx_hw_stats) - 3,
772 mv88e6xxx_hw_stats, port, data);
773}
774
Guenter Roecka1ab91f2014-10-29 10:45:05 -0700775int mv88e6xxx_get_regs_len(struct dsa_switch *ds, int port)
776{
777 return 32 * sizeof(u16);
778}
779
780void mv88e6xxx_get_regs(struct dsa_switch *ds, int port,
781 struct ethtool_regs *regs, void *_p)
782{
783 u16 *p = _p;
784 int i;
785
786 regs->version = 0;
787
788 memset(p, 0xff, 32 * sizeof(u16));
789
790 for (i = 0; i < 32; i++) {
791 int ret;
792
793 ret = mv88e6xxx_reg_read(ds, REG_PORT(port), i);
794 if (ret >= 0)
795 p[i] = ret;
796 }
797}
798
Andrew Lunneaa23762014-11-15 22:24:51 +0100799#ifdef CONFIG_NET_DSA_HWMON
800
801int mv88e6xxx_get_temp(struct dsa_switch *ds, int *temp)
802{
803 struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
804 int ret;
805 int val;
806
807 *temp = 0;
808
Andrew Lunn3898c142015-05-06 01:09:53 +0200809 mutex_lock(&ps->smi_mutex);
Andrew Lunneaa23762014-11-15 22:24:51 +0100810
Andrew Lunnfd3a0ee2015-04-02 04:06:36 +0200811 ret = _mv88e6xxx_phy_write(ds, 0x0, 0x16, 0x6);
Andrew Lunneaa23762014-11-15 22:24:51 +0100812 if (ret < 0)
813 goto error;
814
815 /* Enable temperature sensor */
Andrew Lunnfd3a0ee2015-04-02 04:06:36 +0200816 ret = _mv88e6xxx_phy_read(ds, 0x0, 0x1a);
Andrew Lunneaa23762014-11-15 22:24:51 +0100817 if (ret < 0)
818 goto error;
819
Andrew Lunnfd3a0ee2015-04-02 04:06:36 +0200820 ret = _mv88e6xxx_phy_write(ds, 0x0, 0x1a, ret | (1 << 5));
Andrew Lunneaa23762014-11-15 22:24:51 +0100821 if (ret < 0)
822 goto error;
823
824 /* Wait for temperature to stabilize */
825 usleep_range(10000, 12000);
826
Andrew Lunnfd3a0ee2015-04-02 04:06:36 +0200827 val = _mv88e6xxx_phy_read(ds, 0x0, 0x1a);
Andrew Lunneaa23762014-11-15 22:24:51 +0100828 if (val < 0) {
829 ret = val;
830 goto error;
831 }
832
833 /* Disable temperature sensor */
Andrew Lunnfd3a0ee2015-04-02 04:06:36 +0200834 ret = _mv88e6xxx_phy_write(ds, 0x0, 0x1a, ret & ~(1 << 5));
Andrew Lunneaa23762014-11-15 22:24:51 +0100835 if (ret < 0)
836 goto error;
837
838 *temp = ((val & 0x1f) - 5) * 5;
839
840error:
Andrew Lunnfd3a0ee2015-04-02 04:06:36 +0200841 _mv88e6xxx_phy_write(ds, 0x0, 0x16, 0x0);
Andrew Lunn3898c142015-05-06 01:09:53 +0200842 mutex_unlock(&ps->smi_mutex);
Andrew Lunneaa23762014-11-15 22:24:51 +0100843 return ret;
844}
845#endif /* CONFIG_NET_DSA_HWMON */
846
Guenter Roeckfacd95b2015-03-26 18:36:35 -0700847/* Must be called with SMI lock held */
Andrew Lunn3898c142015-05-06 01:09:53 +0200848static int _mv88e6xxx_wait(struct dsa_switch *ds, int reg, int offset,
849 u16 mask)
Guenter Roeckfacd95b2015-03-26 18:36:35 -0700850{
851 unsigned long timeout = jiffies + HZ / 10;
852
853 while (time_before(jiffies, timeout)) {
854 int ret;
855
856 ret = _mv88e6xxx_reg_read(ds, reg, offset);
857 if (ret < 0)
858 return ret;
859 if (!(ret & mask))
860 return 0;
861
862 usleep_range(1000, 2000);
863 }
864 return -ETIMEDOUT;
865}
866
Andrew Lunn3898c142015-05-06 01:09:53 +0200867static int mv88e6xxx_wait(struct dsa_switch *ds, int reg, int offset, u16 mask)
868{
869 struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
870 int ret;
871
872 mutex_lock(&ps->smi_mutex);
873 ret = _mv88e6xxx_wait(ds, reg, offset, mask);
874 mutex_unlock(&ps->smi_mutex);
875
876 return ret;
877}
878
879static int _mv88e6xxx_phy_wait(struct dsa_switch *ds)
880{
881 return _mv88e6xxx_wait(ds, REG_GLOBAL2, GLOBAL2_SMI_OP,
882 GLOBAL2_SMI_OP_BUSY);
883}
884
885int mv88e6xxx_eeprom_load_wait(struct dsa_switch *ds)
886{
887 return mv88e6xxx_wait(ds, REG_GLOBAL2, GLOBAL2_EEPROM_OP,
888 GLOBAL2_EEPROM_OP_LOAD);
889}
890
891int mv88e6xxx_eeprom_busy_wait(struct dsa_switch *ds)
892{
893 return mv88e6xxx_wait(ds, REG_GLOBAL2, GLOBAL2_EEPROM_OP,
894 GLOBAL2_EEPROM_OP_BUSY);
895}
896
Guenter Roeckfacd95b2015-03-26 18:36:35 -0700897/* Must be called with SMI lock held */
898static int _mv88e6xxx_atu_wait(struct dsa_switch *ds)
899{
Andrew Lunncca8b132015-04-02 04:06:39 +0200900 return _mv88e6xxx_wait(ds, REG_GLOBAL, GLOBAL_ATU_OP,
901 GLOBAL_ATU_OP_BUSY);
Guenter Roeckfacd95b2015-03-26 18:36:35 -0700902}
903
Andrew Lunn3898c142015-05-06 01:09:53 +0200904/* Must be called with SMI mutex held */
Andrew Lunnfd3a0ee2015-04-02 04:06:36 +0200905static int _mv88e6xxx_phy_read_indirect(struct dsa_switch *ds, int addr,
906 int regnum)
Andrew Lunnf3044682015-02-14 19:17:50 +0100907{
908 int ret;
909
Andrew Lunn3898c142015-05-06 01:09:53 +0200910 ret = _mv88e6xxx_reg_write(ds, REG_GLOBAL2, GLOBAL2_SMI_OP,
911 GLOBAL2_SMI_OP_22_READ | (addr << 5) |
912 regnum);
Andrew Lunnf3044682015-02-14 19:17:50 +0100913 if (ret < 0)
914 return ret;
915
Andrew Lunn3898c142015-05-06 01:09:53 +0200916 ret = _mv88e6xxx_phy_wait(ds);
917 if (ret < 0)
918 return ret;
919
920 return _mv88e6xxx_reg_read(ds, REG_GLOBAL2, GLOBAL2_SMI_DATA);
Andrew Lunnf3044682015-02-14 19:17:50 +0100921}
922
Andrew Lunn3898c142015-05-06 01:09:53 +0200923/* Must be called with SMI mutex held */
Andrew Lunnfd3a0ee2015-04-02 04:06:36 +0200924static int _mv88e6xxx_phy_write_indirect(struct dsa_switch *ds, int addr,
925 int regnum, u16 val)
Andrew Lunnf3044682015-02-14 19:17:50 +0100926{
Andrew Lunn3898c142015-05-06 01:09:53 +0200927 int ret;
Andrew Lunnf3044682015-02-14 19:17:50 +0100928
Andrew Lunn3898c142015-05-06 01:09:53 +0200929 ret = _mv88e6xxx_reg_write(ds, REG_GLOBAL2, GLOBAL2_SMI_DATA, val);
930 if (ret < 0)
931 return ret;
932
933 ret = _mv88e6xxx_reg_write(ds, REG_GLOBAL2, GLOBAL2_SMI_OP,
934 GLOBAL2_SMI_OP_22_WRITE | (addr << 5) |
935 regnum);
936
937 return _mv88e6xxx_phy_wait(ds);
Andrew Lunnf3044682015-02-14 19:17:50 +0100938}
939
Guenter Roeck11b3b452015-03-06 22:23:51 -0800940int mv88e6xxx_get_eee(struct dsa_switch *ds, int port, struct ethtool_eee *e)
941{
Andrew Lunn2f40c692015-04-02 04:06:37 +0200942 struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
Guenter Roeck11b3b452015-03-06 22:23:51 -0800943 int reg;
944
Andrew Lunn3898c142015-05-06 01:09:53 +0200945 mutex_lock(&ps->smi_mutex);
Andrew Lunn2f40c692015-04-02 04:06:37 +0200946
947 reg = _mv88e6xxx_phy_read_indirect(ds, port, 16);
Guenter Roeck11b3b452015-03-06 22:23:51 -0800948 if (reg < 0)
Andrew Lunn2f40c692015-04-02 04:06:37 +0200949 goto out;
Guenter Roeck11b3b452015-03-06 22:23:51 -0800950
951 e->eee_enabled = !!(reg & 0x0200);
952 e->tx_lpi_enabled = !!(reg & 0x0100);
953
Andrew Lunn3898c142015-05-06 01:09:53 +0200954 reg = _mv88e6xxx_reg_read(ds, REG_PORT(port), PORT_STATUS);
Guenter Roeck11b3b452015-03-06 22:23:51 -0800955 if (reg < 0)
Andrew Lunn2f40c692015-04-02 04:06:37 +0200956 goto out;
Guenter Roeck11b3b452015-03-06 22:23:51 -0800957
Andrew Lunncca8b132015-04-02 04:06:39 +0200958 e->eee_active = !!(reg & PORT_STATUS_EEE);
Andrew Lunn2f40c692015-04-02 04:06:37 +0200959 reg = 0;
Guenter Roeck11b3b452015-03-06 22:23:51 -0800960
Andrew Lunn2f40c692015-04-02 04:06:37 +0200961out:
Andrew Lunn3898c142015-05-06 01:09:53 +0200962 mutex_unlock(&ps->smi_mutex);
Andrew Lunn2f40c692015-04-02 04:06:37 +0200963 return reg;
Guenter Roeck11b3b452015-03-06 22:23:51 -0800964}
965
966int mv88e6xxx_set_eee(struct dsa_switch *ds, int port,
967 struct phy_device *phydev, struct ethtool_eee *e)
968{
Andrew Lunn2f40c692015-04-02 04:06:37 +0200969 struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
970 int reg;
Guenter Roeck11b3b452015-03-06 22:23:51 -0800971 int ret;
972
Andrew Lunn3898c142015-05-06 01:09:53 +0200973 mutex_lock(&ps->smi_mutex);
Guenter Roeck11b3b452015-03-06 22:23:51 -0800974
Andrew Lunn2f40c692015-04-02 04:06:37 +0200975 ret = _mv88e6xxx_phy_read_indirect(ds, port, 16);
976 if (ret < 0)
977 goto out;
978
979 reg = ret & ~0x0300;
980 if (e->eee_enabled)
981 reg |= 0x0200;
982 if (e->tx_lpi_enabled)
983 reg |= 0x0100;
984
985 ret = _mv88e6xxx_phy_write_indirect(ds, port, 16, reg);
986out:
Andrew Lunn3898c142015-05-06 01:09:53 +0200987 mutex_unlock(&ps->smi_mutex);
Andrew Lunn2f40c692015-04-02 04:06:37 +0200988
989 return ret;
Guenter Roeck11b3b452015-03-06 22:23:51 -0800990}
991
Guenter Roeckfacd95b2015-03-26 18:36:35 -0700992static int _mv88e6xxx_atu_cmd(struct dsa_switch *ds, int fid, u16 cmd)
993{
994 int ret;
995
996 ret = _mv88e6xxx_reg_write(ds, REG_GLOBAL, 0x01, fid);
997 if (ret < 0)
998 return ret;
999
Andrew Lunncca8b132015-04-02 04:06:39 +02001000 ret = _mv88e6xxx_reg_write(ds, REG_GLOBAL, GLOBAL_ATU_OP, cmd);
Guenter Roeckfacd95b2015-03-26 18:36:35 -07001001 if (ret < 0)
1002 return ret;
1003
1004 return _mv88e6xxx_atu_wait(ds);
1005}
1006
1007static int _mv88e6xxx_flush_fid(struct dsa_switch *ds, int fid)
1008{
1009 int ret;
1010
1011 ret = _mv88e6xxx_atu_wait(ds);
1012 if (ret < 0)
1013 return ret;
1014
Andrew Lunncca8b132015-04-02 04:06:39 +02001015 return _mv88e6xxx_atu_cmd(ds, fid, GLOBAL_ATU_OP_FLUSH_NON_STATIC_DB);
Guenter Roeckfacd95b2015-03-26 18:36:35 -07001016}
1017
1018static int mv88e6xxx_set_port_state(struct dsa_switch *ds, int port, u8 state)
1019{
1020 struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
Geert Uytterhoevenc3ffe6d2015-04-16 20:49:14 +02001021 int reg, ret = 0;
Guenter Roeckfacd95b2015-03-26 18:36:35 -07001022 u8 oldstate;
1023
1024 mutex_lock(&ps->smi_mutex);
1025
Andrew Lunncca8b132015-04-02 04:06:39 +02001026 reg = _mv88e6xxx_reg_read(ds, REG_PORT(port), PORT_CONTROL);
Guenter Roeck538cc282015-04-15 22:12:42 -07001027 if (reg < 0) {
1028 ret = reg;
Guenter Roeckfacd95b2015-03-26 18:36:35 -07001029 goto abort;
Guenter Roeck538cc282015-04-15 22:12:42 -07001030 }
Guenter Roeckfacd95b2015-03-26 18:36:35 -07001031
Andrew Lunncca8b132015-04-02 04:06:39 +02001032 oldstate = reg & PORT_CONTROL_STATE_MASK;
Guenter Roeckfacd95b2015-03-26 18:36:35 -07001033 if (oldstate != state) {
1034 /* Flush forwarding database if we're moving a port
1035 * from Learning or Forwarding state to Disabled or
1036 * Blocking or Listening state.
1037 */
Andrew Lunncca8b132015-04-02 04:06:39 +02001038 if (oldstate >= PORT_CONTROL_STATE_LEARNING &&
1039 state <= PORT_CONTROL_STATE_BLOCKING) {
Guenter Roeckfacd95b2015-03-26 18:36:35 -07001040 ret = _mv88e6xxx_flush_fid(ds, ps->fid[port]);
1041 if (ret)
1042 goto abort;
1043 }
Andrew Lunncca8b132015-04-02 04:06:39 +02001044 reg = (reg & ~PORT_CONTROL_STATE_MASK) | state;
1045 ret = _mv88e6xxx_reg_write(ds, REG_PORT(port), PORT_CONTROL,
1046 reg);
Guenter Roeckfacd95b2015-03-26 18:36:35 -07001047 }
1048
1049abort:
1050 mutex_unlock(&ps->smi_mutex);
1051 return ret;
1052}
1053
1054/* Must be called with smi lock held */
1055static int _mv88e6xxx_update_port_config(struct dsa_switch *ds, int port)
1056{
1057 struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
1058 u8 fid = ps->fid[port];
1059 u16 reg = fid << 12;
1060
1061 if (dsa_is_cpu_port(ds, port))
1062 reg |= ds->phys_port_mask;
1063 else
1064 reg |= (ps->bridge_mask[fid] |
1065 (1 << dsa_upstream_port(ds))) & ~(1 << port);
1066
Andrew Lunncca8b132015-04-02 04:06:39 +02001067 return _mv88e6xxx_reg_write(ds, REG_PORT(port), PORT_BASE_VLAN, reg);
Guenter Roeckfacd95b2015-03-26 18:36:35 -07001068}
1069
1070/* Must be called with smi lock held */
1071static int _mv88e6xxx_update_bridge_config(struct dsa_switch *ds, int fid)
1072{
1073 struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
1074 int port;
1075 u32 mask;
1076 int ret;
1077
1078 mask = ds->phys_port_mask;
1079 while (mask) {
1080 port = __ffs(mask);
1081 mask &= ~(1 << port);
1082 if (ps->fid[port] != fid)
1083 continue;
1084
1085 ret = _mv88e6xxx_update_port_config(ds, port);
1086 if (ret)
1087 return ret;
1088 }
1089
1090 return _mv88e6xxx_flush_fid(ds, fid);
1091}
1092
1093/* Bridge handling functions */
1094
1095int mv88e6xxx_join_bridge(struct dsa_switch *ds, int port, u32 br_port_mask)
1096{
1097 struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
1098 int ret = 0;
1099 u32 nmask;
1100 int fid;
1101
1102 /* If the bridge group is not empty, join that group.
1103 * Otherwise create a new group.
1104 */
1105 fid = ps->fid[port];
1106 nmask = br_port_mask & ~(1 << port);
1107 if (nmask)
1108 fid = ps->fid[__ffs(nmask)];
1109
1110 nmask = ps->bridge_mask[fid] | (1 << port);
1111 if (nmask != br_port_mask) {
1112 netdev_err(ds->ports[port],
1113 "join: Bridge port mask mismatch fid=%d mask=0x%x expected 0x%x\n",
1114 fid, br_port_mask, nmask);
1115 return -EINVAL;
1116 }
1117
1118 mutex_lock(&ps->smi_mutex);
1119
1120 ps->bridge_mask[fid] = br_port_mask;
1121
1122 if (fid != ps->fid[port]) {
1123 ps->fid_mask |= 1 << ps->fid[port];
1124 ps->fid[port] = fid;
1125 ret = _mv88e6xxx_update_bridge_config(ds, fid);
1126 }
1127
1128 mutex_unlock(&ps->smi_mutex);
1129
1130 return ret;
1131}
1132
1133int mv88e6xxx_leave_bridge(struct dsa_switch *ds, int port, u32 br_port_mask)
1134{
1135 struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
1136 u8 fid, newfid;
1137 int ret;
1138
1139 fid = ps->fid[port];
1140
1141 if (ps->bridge_mask[fid] != br_port_mask) {
1142 netdev_err(ds->ports[port],
1143 "leave: Bridge port mask mismatch fid=%d mask=0x%x expected 0x%x\n",
1144 fid, br_port_mask, ps->bridge_mask[fid]);
1145 return -EINVAL;
1146 }
1147
1148 /* If the port was the last port of a bridge, we are done.
1149 * Otherwise assign a new fid to the port, and fix up
1150 * the bridge configuration.
1151 */
1152 if (br_port_mask == (1 << port))
1153 return 0;
1154
1155 mutex_lock(&ps->smi_mutex);
1156
1157 newfid = __ffs(ps->fid_mask);
1158 ps->fid[port] = newfid;
1159 ps->fid_mask &= (1 << newfid);
1160 ps->bridge_mask[fid] &= ~(1 << port);
1161 ps->bridge_mask[newfid] = 1 << port;
1162
1163 ret = _mv88e6xxx_update_bridge_config(ds, fid);
1164 if (!ret)
1165 ret = _mv88e6xxx_update_bridge_config(ds, newfid);
1166
1167 mutex_unlock(&ps->smi_mutex);
1168
1169 return ret;
1170}
1171
1172int mv88e6xxx_port_stp_update(struct dsa_switch *ds, int port, u8 state)
1173{
1174 struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
1175 int stp_state;
1176
1177 switch (state) {
1178 case BR_STATE_DISABLED:
Andrew Lunncca8b132015-04-02 04:06:39 +02001179 stp_state = PORT_CONTROL_STATE_DISABLED;
Guenter Roeckfacd95b2015-03-26 18:36:35 -07001180 break;
1181 case BR_STATE_BLOCKING:
1182 case BR_STATE_LISTENING:
Andrew Lunncca8b132015-04-02 04:06:39 +02001183 stp_state = PORT_CONTROL_STATE_BLOCKING;
Guenter Roeckfacd95b2015-03-26 18:36:35 -07001184 break;
1185 case BR_STATE_LEARNING:
Andrew Lunncca8b132015-04-02 04:06:39 +02001186 stp_state = PORT_CONTROL_STATE_LEARNING;
Guenter Roeckfacd95b2015-03-26 18:36:35 -07001187 break;
1188 case BR_STATE_FORWARDING:
1189 default:
Andrew Lunncca8b132015-04-02 04:06:39 +02001190 stp_state = PORT_CONTROL_STATE_FORWARDING;
Guenter Roeckfacd95b2015-03-26 18:36:35 -07001191 break;
1192 }
1193
1194 netdev_dbg(ds->ports[port], "port state %d [%d]\n", state, stp_state);
1195
1196 /* mv88e6xxx_port_stp_update may be called with softirqs disabled,
1197 * so we can not update the port state directly but need to schedule it.
1198 */
1199 ps->port_state[port] = stp_state;
1200 set_bit(port, &ps->port_state_update_mask);
1201 schedule_work(&ps->bridge_work);
1202
1203 return 0;
1204}
1205
Guenter Roeckdefb05b2015-03-26 18:36:38 -07001206static int __mv88e6xxx_write_addr(struct dsa_switch *ds,
1207 const unsigned char *addr)
1208{
1209 int i, ret;
1210
1211 for (i = 0; i < 3; i++) {
Andrew Lunncca8b132015-04-02 04:06:39 +02001212 ret = _mv88e6xxx_reg_write(
1213 ds, REG_GLOBAL, GLOBAL_ATU_MAC_01 + i,
1214 (addr[i * 2] << 8) | addr[i * 2 + 1]);
Guenter Roeckdefb05b2015-03-26 18:36:38 -07001215 if (ret < 0)
1216 return ret;
1217 }
1218
1219 return 0;
1220}
1221
1222static int __mv88e6xxx_read_addr(struct dsa_switch *ds, unsigned char *addr)
1223{
1224 int i, ret;
1225
1226 for (i = 0; i < 3; i++) {
Andrew Lunncca8b132015-04-02 04:06:39 +02001227 ret = _mv88e6xxx_reg_read(ds, REG_GLOBAL,
1228 GLOBAL_ATU_MAC_01 + i);
Guenter Roeckdefb05b2015-03-26 18:36:38 -07001229 if (ret < 0)
1230 return ret;
1231 addr[i * 2] = ret >> 8;
1232 addr[i * 2 + 1] = ret & 0xff;
1233 }
1234
1235 return 0;
1236}
1237
1238static int __mv88e6xxx_port_fdb_cmd(struct dsa_switch *ds, int port,
1239 const unsigned char *addr, int state)
1240{
1241 struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
1242 u8 fid = ps->fid[port];
1243 int ret;
1244
1245 ret = _mv88e6xxx_atu_wait(ds);
1246 if (ret < 0)
1247 return ret;
1248
1249 ret = __mv88e6xxx_write_addr(ds, addr);
1250 if (ret < 0)
1251 return ret;
1252
Andrew Lunncca8b132015-04-02 04:06:39 +02001253 ret = _mv88e6xxx_reg_write(ds, REG_GLOBAL, GLOBAL_ATU_DATA,
Guenter Roeckdefb05b2015-03-26 18:36:38 -07001254 (0x10 << port) | state);
1255 if (ret)
1256 return ret;
1257
Andrew Lunncca8b132015-04-02 04:06:39 +02001258 ret = _mv88e6xxx_atu_cmd(ds, fid, GLOBAL_ATU_OP_LOAD_DB);
Guenter Roeckdefb05b2015-03-26 18:36:38 -07001259
1260 return ret;
1261}
1262
1263int mv88e6xxx_port_fdb_add(struct dsa_switch *ds, int port,
1264 const unsigned char *addr, u16 vid)
1265{
1266 int state = is_multicast_ether_addr(addr) ?
Andrew Lunncca8b132015-04-02 04:06:39 +02001267 GLOBAL_ATU_DATA_STATE_MC_STATIC :
1268 GLOBAL_ATU_DATA_STATE_UC_STATIC;
Guenter Roeckdefb05b2015-03-26 18:36:38 -07001269 struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
1270 int ret;
1271
1272 mutex_lock(&ps->smi_mutex);
1273 ret = __mv88e6xxx_port_fdb_cmd(ds, port, addr, state);
1274 mutex_unlock(&ps->smi_mutex);
1275
1276 return ret;
1277}
1278
1279int mv88e6xxx_port_fdb_del(struct dsa_switch *ds, int port,
1280 const unsigned char *addr, u16 vid)
1281{
1282 struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
1283 int ret;
1284
1285 mutex_lock(&ps->smi_mutex);
Andrew Lunncca8b132015-04-02 04:06:39 +02001286 ret = __mv88e6xxx_port_fdb_cmd(ds, port, addr,
1287 GLOBAL_ATU_DATA_STATE_UNUSED);
Guenter Roeckdefb05b2015-03-26 18:36:38 -07001288 mutex_unlock(&ps->smi_mutex);
1289
1290 return ret;
1291}
1292
1293static int __mv88e6xxx_port_getnext(struct dsa_switch *ds, int port,
1294 unsigned char *addr, bool *is_static)
1295{
1296 struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
1297 u8 fid = ps->fid[port];
1298 int ret, state;
1299
1300 ret = _mv88e6xxx_atu_wait(ds);
1301 if (ret < 0)
1302 return ret;
1303
1304 ret = __mv88e6xxx_write_addr(ds, addr);
1305 if (ret < 0)
1306 return ret;
1307
1308 do {
Andrew Lunncca8b132015-04-02 04:06:39 +02001309 ret = _mv88e6xxx_atu_cmd(ds, fid, GLOBAL_ATU_OP_GET_NEXT_DB);
Guenter Roeckdefb05b2015-03-26 18:36:38 -07001310 if (ret < 0)
1311 return ret;
1312
Andrew Lunncca8b132015-04-02 04:06:39 +02001313 ret = _mv88e6xxx_reg_read(ds, REG_GLOBAL, GLOBAL_ATU_DATA);
Guenter Roeckdefb05b2015-03-26 18:36:38 -07001314 if (ret < 0)
1315 return ret;
Andrew Lunncca8b132015-04-02 04:06:39 +02001316 state = ret & GLOBAL_ATU_DATA_STATE_MASK;
1317 if (state == GLOBAL_ATU_DATA_STATE_UNUSED)
Guenter Roeckdefb05b2015-03-26 18:36:38 -07001318 return -ENOENT;
1319 } while (!(((ret >> 4) & 0xff) & (1 << port)));
1320
1321 ret = __mv88e6xxx_read_addr(ds, addr);
1322 if (ret < 0)
1323 return ret;
1324
1325 *is_static = state == (is_multicast_ether_addr(addr) ?
Andrew Lunncca8b132015-04-02 04:06:39 +02001326 GLOBAL_ATU_DATA_STATE_MC_STATIC :
1327 GLOBAL_ATU_DATA_STATE_UC_STATIC);
Guenter Roeckdefb05b2015-03-26 18:36:38 -07001328
1329 return 0;
1330}
1331
1332/* get next entry for port */
1333int mv88e6xxx_port_fdb_getnext(struct dsa_switch *ds, int port,
1334 unsigned char *addr, bool *is_static)
1335{
1336 struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
1337 int ret;
1338
1339 mutex_lock(&ps->smi_mutex);
1340 ret = __mv88e6xxx_port_getnext(ds, port, addr, is_static);
1341 mutex_unlock(&ps->smi_mutex);
1342
1343 return ret;
1344}
1345
Guenter Roeckfacd95b2015-03-26 18:36:35 -07001346static void mv88e6xxx_bridge_work(struct work_struct *work)
1347{
1348 struct mv88e6xxx_priv_state *ps;
1349 struct dsa_switch *ds;
1350 int port;
1351
1352 ps = container_of(work, struct mv88e6xxx_priv_state, bridge_work);
1353 ds = ((struct dsa_switch *)ps) - 1;
1354
1355 while (ps->port_state_update_mask) {
1356 port = __ffs(ps->port_state_update_mask);
1357 clear_bit(port, &ps->port_state_update_mask);
1358 mv88e6xxx_set_port_state(ds, port, ps->port_state[port]);
1359 }
1360}
1361
Andrew Lunndbde9e62015-05-06 01:09:48 +02001362static int mv88e6xxx_setup_port(struct dsa_switch *ds, int port)
Guenter Roeckd827e882015-03-26 18:36:29 -07001363{
1364 struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
Guenter Roeckfacd95b2015-03-26 18:36:35 -07001365 int ret, fid;
Andrew Lunn54d792f2015-05-06 01:09:47 +02001366 u16 reg;
Guenter Roeckd827e882015-03-26 18:36:29 -07001367
1368 mutex_lock(&ps->smi_mutex);
1369
Andrew Lunn54d792f2015-05-06 01:09:47 +02001370 if (mv88e6xxx_6352_family(ds) || mv88e6xxx_6351_family(ds) ||
1371 mv88e6xxx_6165_family(ds) || mv88e6xxx_6097_family(ds) ||
1372 mv88e6xxx_6185_family(ds) || mv88e6xxx_6095_family(ds) ||
1373 mv88e6xxx_6065_family(ds)) {
1374 /* MAC Forcing register: don't force link, speed,
1375 * duplex or flow control state to any particular
1376 * values on physical ports, but force the CPU port
1377 * and all DSA ports to their maximum bandwidth and
1378 * full duplex.
1379 */
1380 reg = _mv88e6xxx_reg_read(ds, REG_PORT(port), PORT_PCS_CTRL);
1381 if (dsa_is_cpu_port(ds, port) ||
1382 ds->dsa_port_mask & (1 << port)) {
1383 reg |= PORT_PCS_CTRL_FORCE_LINK |
1384 PORT_PCS_CTRL_LINK_UP |
1385 PORT_PCS_CTRL_DUPLEX_FULL |
1386 PORT_PCS_CTRL_FORCE_DUPLEX;
1387 if (mv88e6xxx_6065_family(ds))
1388 reg |= PORT_PCS_CTRL_100;
1389 else
1390 reg |= PORT_PCS_CTRL_1000;
1391 } else {
1392 reg |= PORT_PCS_CTRL_UNFORCED;
1393 }
1394
1395 ret = _mv88e6xxx_reg_write(ds, REG_PORT(port),
1396 PORT_PCS_CTRL, reg);
1397 if (ret)
1398 goto abort;
1399 }
1400
1401 /* Port Control: disable Drop-on-Unlock, disable Drop-on-Lock,
1402 * disable Header mode, enable IGMP/MLD snooping, disable VLAN
1403 * tunneling, determine priority by looking at 802.1p and IP
1404 * priority fields (IP prio has precedence), and set STP state
1405 * to Forwarding.
1406 *
1407 * If this is the CPU link, use DSA or EDSA tagging depending
1408 * on which tagging mode was configured.
1409 *
1410 * If this is a link to another switch, use DSA tagging mode.
1411 *
1412 * If this is the upstream port for this switch, enable
1413 * forwarding of unknown unicasts and multicasts.
1414 */
1415 reg = 0;
1416 if (mv88e6xxx_6352_family(ds) || mv88e6xxx_6351_family(ds) ||
1417 mv88e6xxx_6165_family(ds) || mv88e6xxx_6097_family(ds) ||
1418 mv88e6xxx_6095_family(ds) || mv88e6xxx_6065_family(ds) ||
1419 mv88e6xxx_6185_family(ds))
1420 reg = PORT_CONTROL_IGMP_MLD_SNOOP |
1421 PORT_CONTROL_USE_TAG | PORT_CONTROL_USE_IP |
1422 PORT_CONTROL_STATE_FORWARDING;
1423 if (dsa_is_cpu_port(ds, port)) {
1424 if (mv88e6xxx_6095_family(ds) || mv88e6xxx_6185_family(ds))
1425 reg |= PORT_CONTROL_DSA_TAG;
1426 if (mv88e6xxx_6352_family(ds) || mv88e6xxx_6351_family(ds) ||
1427 mv88e6xxx_6165_family(ds) || mv88e6xxx_6097_family(ds)) {
1428 if (ds->dst->tag_protocol == DSA_TAG_PROTO_EDSA)
1429 reg |= PORT_CONTROL_FRAME_ETHER_TYPE_DSA;
1430 else
1431 reg |= PORT_CONTROL_FRAME_MODE_DSA;
1432 }
1433
1434 if (mv88e6xxx_6352_family(ds) || mv88e6xxx_6351_family(ds) ||
1435 mv88e6xxx_6165_family(ds) || mv88e6xxx_6097_family(ds) ||
1436 mv88e6xxx_6095_family(ds) || mv88e6xxx_6065_family(ds) ||
1437 mv88e6xxx_6185_family(ds)) {
1438 if (ds->dst->tag_protocol == DSA_TAG_PROTO_EDSA)
1439 reg |= PORT_CONTROL_EGRESS_ADD_TAG;
1440 }
1441 }
1442 if (mv88e6xxx_6352_family(ds) || mv88e6xxx_6351_family(ds) ||
1443 mv88e6xxx_6165_family(ds) || mv88e6xxx_6097_family(ds) ||
1444 mv88e6xxx_6095_family(ds) || mv88e6xxx_6065_family(ds)) {
1445 if (ds->dsa_port_mask & (1 << port))
1446 reg |= PORT_CONTROL_FRAME_MODE_DSA;
1447 if (port == dsa_upstream_port(ds))
1448 reg |= PORT_CONTROL_FORWARD_UNKNOWN |
1449 PORT_CONTROL_FORWARD_UNKNOWN_MC;
1450 }
1451 if (reg) {
1452 ret = _mv88e6xxx_reg_write(ds, REG_PORT(port),
1453 PORT_CONTROL, reg);
1454 if (ret)
1455 goto abort;
1456 }
1457
1458 /* Port Control 2: don't force a good FCS, set the maximum
1459 * frame size to 10240 bytes, don't let the switch add or
1460 * strip 802.1q tags, don't discard tagged or untagged frames
1461 * on this port, do a destination address lookup on all
1462 * received packets as usual, disable ARP mirroring and don't
1463 * send a copy of all transmitted/received frames on this port
1464 * to the CPU.
1465 */
1466 reg = 0;
1467 if (mv88e6xxx_6352_family(ds) || mv88e6xxx_6351_family(ds) ||
1468 mv88e6xxx_6165_family(ds) || mv88e6xxx_6097_family(ds) ||
1469 mv88e6xxx_6095_family(ds))
1470 reg = PORT_CONTROL_2_MAP_DA;
1471
1472 if (mv88e6xxx_6352_family(ds) || mv88e6xxx_6351_family(ds) ||
1473 mv88e6xxx_6165_family(ds))
1474 reg |= PORT_CONTROL_2_JUMBO_10240;
1475
1476 if (mv88e6xxx_6095_family(ds) || mv88e6xxx_6185_family(ds)) {
1477 /* Set the upstream port this port should use */
1478 reg |= dsa_upstream_port(ds);
1479 /* enable forwarding of unknown multicast addresses to
1480 * the upstream port
1481 */
1482 if (port == dsa_upstream_port(ds))
1483 reg |= PORT_CONTROL_2_FORWARD_UNKNOWN;
1484 }
1485
1486 if (reg) {
1487 ret = _mv88e6xxx_reg_write(ds, REG_PORT(port),
1488 PORT_CONTROL_2, reg);
1489 if (ret)
1490 goto abort;
1491 }
1492
1493 /* Port Association Vector: when learning source addresses
1494 * of packets, add the address to the address database using
1495 * a port bitmap that has only the bit for this port set and
1496 * the other bits clear.
1497 */
1498 ret = _mv88e6xxx_reg_write(ds, REG_PORT(port), PORT_ASSOC_VECTOR,
1499 1 << port);
1500 if (ret)
1501 goto abort;
1502
1503 /* Egress rate control 2: disable egress rate control. */
1504 ret = _mv88e6xxx_reg_write(ds, REG_PORT(port), PORT_RATE_CONTROL_2,
1505 0x0000);
1506 if (ret)
1507 goto abort;
1508
1509 if (mv88e6xxx_6352_family(ds) || mv88e6xxx_6351_family(ds) ||
1510 mv88e6xxx_6165_family(ds) || mv88e6xxx_6097_family(ds)) {
1511 /* Do not limit the period of time that this port can
1512 * be paused for by the remote end or the period of
1513 * time that this port can pause the remote end.
1514 */
1515 ret = _mv88e6xxx_reg_write(ds, REG_PORT(port),
1516 PORT_PAUSE_CTRL, 0x0000);
1517 if (ret)
1518 goto abort;
1519
1520 /* Port ATU control: disable limiting the number of
1521 * address database entries that this port is allowed
1522 * to use.
1523 */
1524 ret = _mv88e6xxx_reg_write(ds, REG_PORT(port),
1525 PORT_ATU_CONTROL, 0x0000);
1526 /* Priority Override: disable DA, SA and VTU priority
1527 * override.
1528 */
1529 ret = _mv88e6xxx_reg_write(ds, REG_PORT(port),
1530 PORT_PRI_OVERRIDE, 0x0000);
1531 if (ret)
1532 goto abort;
1533
1534 /* Port Ethertype: use the Ethertype DSA Ethertype
1535 * value.
1536 */
1537 ret = _mv88e6xxx_reg_write(ds, REG_PORT(port),
1538 PORT_ETH_TYPE, ETH_P_EDSA);
1539 if (ret)
1540 goto abort;
1541 /* Tag Remap: use an identity 802.1p prio -> switch
1542 * prio mapping.
1543 */
1544 ret = _mv88e6xxx_reg_write(ds, REG_PORT(port),
1545 PORT_TAG_REGMAP_0123, 0x3210);
1546 if (ret)
1547 goto abort;
1548
1549 /* Tag Remap 2: use an identity 802.1p prio -> switch
1550 * prio mapping.
1551 */
1552 ret = _mv88e6xxx_reg_write(ds, REG_PORT(port),
1553 PORT_TAG_REGMAP_4567, 0x7654);
1554 if (ret)
1555 goto abort;
1556 }
1557
1558 if (mv88e6xxx_6352_family(ds) || mv88e6xxx_6351_family(ds) ||
1559 mv88e6xxx_6165_family(ds) || mv88e6xxx_6097_family(ds) ||
1560 mv88e6xxx_6185_family(ds) || mv88e6xxx_6095_family(ds)) {
1561 /* Rate Control: disable ingress rate limiting. */
1562 ret = _mv88e6xxx_reg_write(ds, REG_PORT(port),
1563 PORT_RATE_CONTROL, 0x0001);
1564 if (ret)
1565 goto abort;
1566 }
1567
Guenter Roeck366f0a02015-03-26 18:36:30 -07001568 /* Port Control 1: disable trunking, disable sending
1569 * learning messages to this port.
Guenter Roeckd827e882015-03-26 18:36:29 -07001570 */
Vivien Didelot614f03f2015-04-20 17:19:23 -04001571 ret = _mv88e6xxx_reg_write(ds, REG_PORT(port), PORT_CONTROL_1, 0x0000);
Guenter Roeckd827e882015-03-26 18:36:29 -07001572 if (ret)
1573 goto abort;
1574
1575 /* Port based VLAN map: give each port its own address
1576 * database, allow the CPU port to talk to each of the 'real'
1577 * ports, and allow each of the 'real' ports to only talk to
1578 * the upstream port.
1579 */
Guenter Roeckfacd95b2015-03-26 18:36:35 -07001580 fid = __ffs(ps->fid_mask);
1581 ps->fid[port] = fid;
1582 ps->fid_mask &= ~(1 << fid);
Guenter Roeckd827e882015-03-26 18:36:29 -07001583
Guenter Roeckfacd95b2015-03-26 18:36:35 -07001584 if (!dsa_is_cpu_port(ds, port))
1585 ps->bridge_mask[fid] = 1 << port;
1586
1587 ret = _mv88e6xxx_update_port_config(ds, port);
Guenter Roeckd827e882015-03-26 18:36:29 -07001588 if (ret)
1589 goto abort;
1590
1591 /* Default VLAN ID and priority: don't set a default VLAN
1592 * ID, and set the default packet priority to zero.
1593 */
Vivien Didelot47cf1e62015-04-20 17:43:26 -04001594 ret = _mv88e6xxx_reg_write(ds, REG_PORT(port), PORT_DEFAULT_VLAN,
1595 0x0000);
Guenter Roeckd827e882015-03-26 18:36:29 -07001596abort:
1597 mutex_unlock(&ps->smi_mutex);
1598 return ret;
1599}
1600
Andrew Lunndbde9e62015-05-06 01:09:48 +02001601int mv88e6xxx_setup_ports(struct dsa_switch *ds)
1602{
1603 struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
1604 int ret;
1605 int i;
1606
1607 for (i = 0; i < ps->num_ports; i++) {
1608 ret = mv88e6xxx_setup_port(ds, i);
1609 if (ret < 0)
1610 return ret;
1611 }
1612 return 0;
1613}
1614
Andrew Lunn87c8cef2015-06-20 18:42:28 +02001615static int mv88e6xxx_regs_show(struct seq_file *s, void *p)
1616{
1617 struct dsa_switch *ds = s->private;
1618
1619 struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
1620 int reg, port;
1621
1622 seq_puts(s, " GLOBAL GLOBAL2 ");
1623 for (port = 0 ; port < ps->num_ports; port++)
1624 seq_printf(s, " %2d ", port);
1625 seq_puts(s, "\n");
1626
1627 for (reg = 0; reg < 32; reg++) {
1628 seq_printf(s, "%2x: ", reg);
1629 seq_printf(s, " %4x %4x ",
1630 mv88e6xxx_reg_read(ds, REG_GLOBAL, reg),
1631 mv88e6xxx_reg_read(ds, REG_GLOBAL2, reg));
1632
1633 for (port = 0 ; port < ps->num_ports; port++)
1634 seq_printf(s, "%4x ",
1635 mv88e6xxx_reg_read(ds, REG_PORT(port), reg));
1636 seq_puts(s, "\n");
1637 }
1638
1639 return 0;
1640}
1641
1642static int mv88e6xxx_regs_open(struct inode *inode, struct file *file)
1643{
1644 return single_open(file, mv88e6xxx_regs_show, inode->i_private);
1645}
1646
1647static const struct file_operations mv88e6xxx_regs_fops = {
1648 .open = mv88e6xxx_regs_open,
1649 .read = seq_read,
1650 .llseek = no_llseek,
1651 .release = single_release,
1652 .owner = THIS_MODULE,
1653};
1654
Andrew Lunn8a0a2652015-06-20 18:42:29 +02001655static void mv88e6xxx_atu_show_header(struct seq_file *s)
1656{
1657 seq_puts(s, "DB T/P Vec State Addr\n");
1658}
1659
1660static void mv88e6xxx_atu_show_entry(struct seq_file *s, int dbnum,
1661 unsigned char *addr, int data)
1662{
1663 bool trunk = !!(data & GLOBAL_ATU_DATA_TRUNK);
1664 int portvec = ((data & GLOBAL_ATU_DATA_PORT_VECTOR_MASK) >>
1665 GLOBAL_ATU_DATA_PORT_VECTOR_SHIFT);
1666 int state = data & GLOBAL_ATU_DATA_STATE_MASK;
1667
1668 seq_printf(s, "%03x %5s %10pb %x %pM\n",
1669 dbnum, (trunk ? "Trunk" : "Port"), &portvec, state, addr);
1670}
1671
1672static int mv88e6xxx_atu_show_db(struct seq_file *s, struct dsa_switch *ds,
1673 int dbnum)
1674{
1675 unsigned char bcast[] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
1676 unsigned char addr[6];
1677 int ret, data, state;
1678
1679 ret = __mv88e6xxx_write_addr(ds, bcast);
1680 if (ret < 0)
1681 return ret;
1682
1683 do {
1684 ret = _mv88e6xxx_atu_cmd(ds, dbnum, GLOBAL_ATU_OP_GET_NEXT_DB);
1685 if (ret < 0)
1686 return ret;
1687 data = _mv88e6xxx_reg_read(ds, REG_GLOBAL, GLOBAL_ATU_DATA);
1688 if (data < 0)
1689 return data;
1690
1691 state = data & GLOBAL_ATU_DATA_STATE_MASK;
1692 if (state == GLOBAL_ATU_DATA_STATE_UNUSED)
1693 break;
1694 ret = __mv88e6xxx_read_addr(ds, addr);
1695 if (ret < 0)
1696 return ret;
1697 mv88e6xxx_atu_show_entry(s, dbnum, addr, data);
1698 } while (state != GLOBAL_ATU_DATA_STATE_UNUSED);
1699
1700 return 0;
1701}
1702
1703static int mv88e6xxx_atu_show(struct seq_file *s, void *p)
1704{
1705 struct dsa_switch *ds = s->private;
1706 struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
1707 int dbnum;
1708
1709 mv88e6xxx_atu_show_header(s);
1710
1711 for (dbnum = 0; dbnum < 255; dbnum++) {
1712 mutex_lock(&ps->smi_mutex);
1713 mv88e6xxx_atu_show_db(s, ds, dbnum);
1714 mutex_unlock(&ps->smi_mutex);
1715 }
1716
1717 return 0;
1718}
1719
1720static int mv88e6xxx_atu_open(struct inode *inode, struct file *file)
1721{
1722 return single_open(file, mv88e6xxx_atu_show, inode->i_private);
1723}
1724
1725static const struct file_operations mv88e6xxx_atu_fops = {
1726 .open = mv88e6xxx_atu_open,
1727 .read = seq_read,
1728 .llseek = no_llseek,
1729 .release = single_release,
1730 .owner = THIS_MODULE,
1731};
1732
Andrew Lunn532c7a32015-06-20 18:42:31 +02001733static void mv88e6xxx_stats_show_header(struct seq_file *s,
1734 struct mv88e6xxx_priv_state *ps)
1735{
1736 int port;
1737
1738 seq_puts(s, " Statistic ");
1739 for (port = 0 ; port < ps->num_ports; port++)
1740 seq_printf(s, "Port %2d ", port);
1741 seq_puts(s, "\n");
1742}
1743
1744static int mv88e6xxx_stats_show(struct seq_file *s, void *p)
1745{
1746 struct dsa_switch *ds = s->private;
1747 struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
1748 struct mv88e6xxx_hw_stat *stats = mv88e6xxx_hw_stats;
1749 int port, stat, max_stats;
1750 uint64_t value;
1751
1752 if (have_sw_in_discards(ds))
1753 max_stats = ARRAY_SIZE(mv88e6xxx_hw_stats);
1754 else
1755 max_stats = ARRAY_SIZE(mv88e6xxx_hw_stats) - 3;
1756
1757 mv88e6xxx_stats_show_header(s, ps);
1758
1759 mutex_lock(&ps->smi_mutex);
1760
1761 for (stat = 0; stat < max_stats; stat++) {
1762 seq_printf(s, "%19s: ", stats[stat].string);
1763 for (port = 0 ; port < ps->num_ports; port++) {
1764 _mv88e6xxx_stats_snapshot(ds, port);
1765 value = _mv88e6xxx_get_ethtool_stat(ds, stat, stats,
1766 port);
1767 seq_printf(s, "%8llu ", value);
1768 }
1769 seq_puts(s, "\n");
1770 }
1771 mutex_unlock(&ps->smi_mutex);
1772
1773 return 0;
1774}
1775
1776static int mv88e6xxx_stats_open(struct inode *inode, struct file *file)
1777{
1778 return single_open(file, mv88e6xxx_stats_show, inode->i_private);
1779}
1780
1781static const struct file_operations mv88e6xxx_stats_fops = {
1782 .open = mv88e6xxx_stats_open,
1783 .read = seq_read,
1784 .llseek = no_llseek,
1785 .release = single_release,
1786 .owner = THIS_MODULE,
1787};
1788
Guenter Roeckacdaffc2015-03-26 18:36:28 -07001789int mv88e6xxx_setup_common(struct dsa_switch *ds)
1790{
1791 struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
Andrew Lunn87c8cef2015-06-20 18:42:28 +02001792 char *name;
Guenter Roeckacdaffc2015-03-26 18:36:28 -07001793
1794 mutex_init(&ps->smi_mutex);
Guenter Roeckacdaffc2015-03-26 18:36:28 -07001795
Andrew Lunncca8b132015-04-02 04:06:39 +02001796 ps->id = REG_READ(REG_PORT(0), PORT_SWITCH_ID) & 0xfff0;
Andrew Lunna8f064c2015-03-26 18:36:40 -07001797
Guenter Roeckfacd95b2015-03-26 18:36:35 -07001798 ps->fid_mask = (1 << DSA_MAX_PORTS) - 1;
1799
1800 INIT_WORK(&ps->bridge_work, mv88e6xxx_bridge_work);
1801
Andrew Lunn87c8cef2015-06-20 18:42:28 +02001802 name = kasprintf(GFP_KERNEL, "dsa%d", ds->index);
1803 ps->dbgfs = debugfs_create_dir(name, NULL);
1804 kfree(name);
1805
1806 debugfs_create_file("regs", S_IRUGO, ps->dbgfs, ds,
1807 &mv88e6xxx_regs_fops);
1808
Andrew Lunn8a0a2652015-06-20 18:42:29 +02001809 debugfs_create_file("atu", S_IRUGO, ps->dbgfs, ds,
1810 &mv88e6xxx_atu_fops);
1811
Andrew Lunn532c7a32015-06-20 18:42:31 +02001812 debugfs_create_file("stats", S_IRUGO, ps->dbgfs, ds,
1813 &mv88e6xxx_stats_fops);
1814
Guenter Roeckacdaffc2015-03-26 18:36:28 -07001815 return 0;
1816}
1817
Andrew Lunn54d792f2015-05-06 01:09:47 +02001818int mv88e6xxx_setup_global(struct dsa_switch *ds)
1819{
1820 struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
1821 int i;
1822
1823 /* Set the default address aging time to 5 minutes, and
1824 * enable address learn messages to be sent to all message
1825 * ports.
1826 */
1827 REG_WRITE(REG_GLOBAL, GLOBAL_ATU_CONTROL,
1828 0x0140 | GLOBAL_ATU_CONTROL_LEARN2ALL);
1829
1830 /* Configure the IP ToS mapping registers. */
1831 REG_WRITE(REG_GLOBAL, GLOBAL_IP_PRI_0, 0x0000);
1832 REG_WRITE(REG_GLOBAL, GLOBAL_IP_PRI_1, 0x0000);
1833 REG_WRITE(REG_GLOBAL, GLOBAL_IP_PRI_2, 0x5555);
1834 REG_WRITE(REG_GLOBAL, GLOBAL_IP_PRI_3, 0x5555);
1835 REG_WRITE(REG_GLOBAL, GLOBAL_IP_PRI_4, 0xaaaa);
1836 REG_WRITE(REG_GLOBAL, GLOBAL_IP_PRI_5, 0xaaaa);
1837 REG_WRITE(REG_GLOBAL, GLOBAL_IP_PRI_6, 0xffff);
1838 REG_WRITE(REG_GLOBAL, GLOBAL_IP_PRI_7, 0xffff);
1839
1840 /* Configure the IEEE 802.1p priority mapping register. */
1841 REG_WRITE(REG_GLOBAL, GLOBAL_IEEE_PRI, 0xfa41);
1842
1843 /* Send all frames with destination addresses matching
1844 * 01:80:c2:00:00:0x to the CPU port.
1845 */
1846 REG_WRITE(REG_GLOBAL2, GLOBAL2_MGMT_EN_0X, 0xffff);
1847
1848 /* Ignore removed tag data on doubly tagged packets, disable
1849 * flow control messages, force flow control priority to the
1850 * highest, and send all special multicast frames to the CPU
1851 * port at the highest priority.
1852 */
1853 REG_WRITE(REG_GLOBAL2, GLOBAL2_SWITCH_MGMT,
1854 0x7 | GLOBAL2_SWITCH_MGMT_RSVD2CPU | 0x70 |
1855 GLOBAL2_SWITCH_MGMT_FORCE_FLOW_CTRL_PRI);
1856
1857 /* Program the DSA routing table. */
1858 for (i = 0; i < 32; i++) {
1859 int nexthop = 0x1f;
1860
1861 if (ds->pd->rtable &&
1862 i != ds->index && i < ds->dst->pd->nr_chips)
1863 nexthop = ds->pd->rtable[i] & 0x1f;
1864
1865 REG_WRITE(REG_GLOBAL2, GLOBAL2_DEVICE_MAPPING,
1866 GLOBAL2_DEVICE_MAPPING_UPDATE |
1867 (i << GLOBAL2_DEVICE_MAPPING_TARGET_SHIFT) |
1868 nexthop);
1869 }
1870
1871 /* Clear all trunk masks. */
1872 for (i = 0; i < 8; i++)
1873 REG_WRITE(REG_GLOBAL2, GLOBAL2_TRUNK_MASK,
1874 0x8000 | (i << GLOBAL2_TRUNK_MASK_NUM_SHIFT) |
1875 ((1 << ps->num_ports) - 1));
1876
1877 /* Clear all trunk mappings. */
1878 for (i = 0; i < 16; i++)
1879 REG_WRITE(REG_GLOBAL2, GLOBAL2_TRUNK_MAPPING,
1880 GLOBAL2_TRUNK_MAPPING_UPDATE |
1881 (i << GLOBAL2_TRUNK_MAPPING_ID_SHIFT));
1882
1883 if (mv88e6xxx_6352_family(ds) || mv88e6xxx_6351_family(ds) ||
1884 mv88e6xxx_6165_family(ds) || mv88e6xxx_6097_family(ds)) {
1885 /* Send all frames with destination addresses matching
1886 * 01:80:c2:00:00:2x to the CPU port.
1887 */
1888 REG_WRITE(REG_GLOBAL2, GLOBAL2_MGMT_EN_2X, 0xffff);
1889
1890 /* Initialise cross-chip port VLAN table to reset
1891 * defaults.
1892 */
1893 REG_WRITE(REG_GLOBAL2, GLOBAL2_PVT_ADDR, 0x9000);
1894
1895 /* Clear the priority override table. */
1896 for (i = 0; i < 16; i++)
1897 REG_WRITE(REG_GLOBAL2, GLOBAL2_PRIO_OVERRIDE,
1898 0x8000 | (i << 8));
1899 }
1900
1901 if (mv88e6xxx_6352_family(ds) || mv88e6xxx_6351_family(ds) ||
1902 mv88e6xxx_6165_family(ds) || mv88e6xxx_6097_family(ds) ||
1903 mv88e6xxx_6185_family(ds) || mv88e6xxx_6095_family(ds)) {
1904 /* Disable ingress rate limiting by resetting all
1905 * ingress rate limit registers to their initial
1906 * state.
1907 */
1908 for (i = 0; i < ps->num_ports; i++)
1909 REG_WRITE(REG_GLOBAL2, GLOBAL2_INGRESS_OP,
1910 0x9000 | (i << 8));
1911 }
1912
1913 return 0;
1914}
1915
Andrew Lunn143a8302015-04-02 04:06:34 +02001916int mv88e6xxx_switch_reset(struct dsa_switch *ds, bool ppu_active)
1917{
1918 struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
1919 u16 is_reset = (ppu_active ? 0x8800 : 0xc800);
1920 unsigned long timeout;
1921 int ret;
1922 int i;
1923
1924 /* Set all ports to the disabled state. */
1925 for (i = 0; i < ps->num_ports; i++) {
Andrew Lunncca8b132015-04-02 04:06:39 +02001926 ret = REG_READ(REG_PORT(i), PORT_CONTROL);
1927 REG_WRITE(REG_PORT(i), PORT_CONTROL, ret & 0xfffc);
Andrew Lunn143a8302015-04-02 04:06:34 +02001928 }
1929
1930 /* Wait for transmit queues to drain. */
1931 usleep_range(2000, 4000);
1932
1933 /* Reset the switch. Keep the PPU active if requested. The PPU
1934 * needs to be active to support indirect phy register access
1935 * through global registers 0x18 and 0x19.
1936 */
1937 if (ppu_active)
1938 REG_WRITE(REG_GLOBAL, 0x04, 0xc000);
1939 else
1940 REG_WRITE(REG_GLOBAL, 0x04, 0xc400);
1941
1942 /* Wait up to one second for reset to complete. */
1943 timeout = jiffies + 1 * HZ;
1944 while (time_before(jiffies, timeout)) {
1945 ret = REG_READ(REG_GLOBAL, 0x00);
1946 if ((ret & is_reset) == is_reset)
1947 break;
1948 usleep_range(1000, 2000);
1949 }
1950 if (time_after(jiffies, timeout))
1951 return -ETIMEDOUT;
1952
1953 return 0;
1954}
1955
Andrew Lunn491435852015-04-02 04:06:35 +02001956int mv88e6xxx_phy_page_read(struct dsa_switch *ds, int port, int page, int reg)
1957{
1958 struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
1959 int ret;
1960
Andrew Lunn3898c142015-05-06 01:09:53 +02001961 mutex_lock(&ps->smi_mutex);
Andrew Lunnfd3a0ee2015-04-02 04:06:36 +02001962 ret = _mv88e6xxx_phy_write_indirect(ds, port, 0x16, page);
Andrew Lunn491435852015-04-02 04:06:35 +02001963 if (ret < 0)
1964 goto error;
Andrew Lunnfd3a0ee2015-04-02 04:06:36 +02001965 ret = _mv88e6xxx_phy_read_indirect(ds, port, reg);
Andrew Lunn491435852015-04-02 04:06:35 +02001966error:
Andrew Lunnfd3a0ee2015-04-02 04:06:36 +02001967 _mv88e6xxx_phy_write_indirect(ds, port, 0x16, 0x0);
Andrew Lunn3898c142015-05-06 01:09:53 +02001968 mutex_unlock(&ps->smi_mutex);
Andrew Lunn491435852015-04-02 04:06:35 +02001969 return ret;
1970}
1971
1972int mv88e6xxx_phy_page_write(struct dsa_switch *ds, int port, int page,
1973 int reg, int val)
1974{
1975 struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
1976 int ret;
1977
Andrew Lunn3898c142015-05-06 01:09:53 +02001978 mutex_lock(&ps->smi_mutex);
Andrew Lunnfd3a0ee2015-04-02 04:06:36 +02001979 ret = _mv88e6xxx_phy_write_indirect(ds, port, 0x16, page);
Andrew Lunn491435852015-04-02 04:06:35 +02001980 if (ret < 0)
1981 goto error;
1982
Andrew Lunnfd3a0ee2015-04-02 04:06:36 +02001983 ret = _mv88e6xxx_phy_write_indirect(ds, port, reg, val);
Andrew Lunn491435852015-04-02 04:06:35 +02001984error:
Andrew Lunnfd3a0ee2015-04-02 04:06:36 +02001985 _mv88e6xxx_phy_write_indirect(ds, port, 0x16, 0x0);
Andrew Lunn3898c142015-05-06 01:09:53 +02001986 mutex_unlock(&ps->smi_mutex);
Andrew Lunnfd3a0ee2015-04-02 04:06:36 +02001987 return ret;
1988}
1989
1990static int mv88e6xxx_port_to_phy_addr(struct dsa_switch *ds, int port)
1991{
1992 struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
1993
1994 if (port >= 0 && port < ps->num_ports)
1995 return port;
1996 return -EINVAL;
1997}
1998
1999int
2000mv88e6xxx_phy_read(struct dsa_switch *ds, int port, int regnum)
2001{
2002 struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
2003 int addr = mv88e6xxx_port_to_phy_addr(ds, port);
2004 int ret;
2005
2006 if (addr < 0)
2007 return addr;
2008
Andrew Lunn3898c142015-05-06 01:09:53 +02002009 mutex_lock(&ps->smi_mutex);
Andrew Lunnfd3a0ee2015-04-02 04:06:36 +02002010 ret = _mv88e6xxx_phy_read(ds, addr, regnum);
Andrew Lunn3898c142015-05-06 01:09:53 +02002011 mutex_unlock(&ps->smi_mutex);
Andrew Lunnfd3a0ee2015-04-02 04:06:36 +02002012 return ret;
2013}
2014
2015int
2016mv88e6xxx_phy_write(struct dsa_switch *ds, int port, int regnum, u16 val)
2017{
2018 struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
2019 int addr = mv88e6xxx_port_to_phy_addr(ds, port);
2020 int ret;
2021
2022 if (addr < 0)
2023 return addr;
2024
Andrew Lunn3898c142015-05-06 01:09:53 +02002025 mutex_lock(&ps->smi_mutex);
Andrew Lunnfd3a0ee2015-04-02 04:06:36 +02002026 ret = _mv88e6xxx_phy_write(ds, addr, regnum, val);
Andrew Lunn3898c142015-05-06 01:09:53 +02002027 mutex_unlock(&ps->smi_mutex);
Andrew Lunnfd3a0ee2015-04-02 04:06:36 +02002028 return ret;
2029}
2030
2031int
2032mv88e6xxx_phy_read_indirect(struct dsa_switch *ds, int port, int regnum)
2033{
2034 struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
2035 int addr = mv88e6xxx_port_to_phy_addr(ds, port);
2036 int ret;
2037
2038 if (addr < 0)
2039 return addr;
2040
Andrew Lunn3898c142015-05-06 01:09:53 +02002041 mutex_lock(&ps->smi_mutex);
Andrew Lunnfd3a0ee2015-04-02 04:06:36 +02002042 ret = _mv88e6xxx_phy_read_indirect(ds, addr, regnum);
Andrew Lunn3898c142015-05-06 01:09:53 +02002043 mutex_unlock(&ps->smi_mutex);
Andrew Lunnfd3a0ee2015-04-02 04:06:36 +02002044 return ret;
2045}
2046
2047int
2048mv88e6xxx_phy_write_indirect(struct dsa_switch *ds, int port, int regnum,
2049 u16 val)
2050{
2051 struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
2052 int addr = mv88e6xxx_port_to_phy_addr(ds, port);
2053 int ret;
2054
2055 if (addr < 0)
2056 return addr;
2057
Andrew Lunn3898c142015-05-06 01:09:53 +02002058 mutex_lock(&ps->smi_mutex);
Andrew Lunnfd3a0ee2015-04-02 04:06:36 +02002059 ret = _mv88e6xxx_phy_write_indirect(ds, addr, regnum, val);
Andrew Lunn3898c142015-05-06 01:09:53 +02002060 mutex_unlock(&ps->smi_mutex);
Andrew Lunn491435852015-04-02 04:06:35 +02002061 return ret;
2062}
2063
Ben Hutchings98e67302011-11-25 14:36:19 +00002064static int __init mv88e6xxx_init(void)
2065{
2066#if IS_ENABLED(CONFIG_NET_DSA_MV88E6131)
2067 register_switch_driver(&mv88e6131_switch_driver);
2068#endif
2069#if IS_ENABLED(CONFIG_NET_DSA_MV88E6123_61_65)
2070 register_switch_driver(&mv88e6123_61_65_switch_driver);
2071#endif
Guenter Roeck3ad50cc2014-10-29 10:44:56 -07002072#if IS_ENABLED(CONFIG_NET_DSA_MV88E6352)
2073 register_switch_driver(&mv88e6352_switch_driver);
2074#endif
Andrew Lunn42f27252014-09-12 23:58:44 +02002075#if IS_ENABLED(CONFIG_NET_DSA_MV88E6171)
2076 register_switch_driver(&mv88e6171_switch_driver);
2077#endif
Ben Hutchings98e67302011-11-25 14:36:19 +00002078 return 0;
2079}
2080module_init(mv88e6xxx_init);
2081
2082static void __exit mv88e6xxx_cleanup(void)
2083{
Andrew Lunn42f27252014-09-12 23:58:44 +02002084#if IS_ENABLED(CONFIG_NET_DSA_MV88E6171)
2085 unregister_switch_driver(&mv88e6171_switch_driver);
2086#endif
Vivien Didelot4212b542015-05-01 10:43:52 -04002087#if IS_ENABLED(CONFIG_NET_DSA_MV88E6352)
2088 unregister_switch_driver(&mv88e6352_switch_driver);
2089#endif
Ben Hutchings98e67302011-11-25 14:36:19 +00002090#if IS_ENABLED(CONFIG_NET_DSA_MV88E6123_61_65)
2091 unregister_switch_driver(&mv88e6123_61_65_switch_driver);
2092#endif
2093#if IS_ENABLED(CONFIG_NET_DSA_MV88E6131)
2094 unregister_switch_driver(&mv88e6131_switch_driver);
2095#endif
2096}
2097module_exit(mv88e6xxx_cleanup);
Ben Hutchings3d825ed2011-11-25 14:37:16 +00002098
2099MODULE_AUTHOR("Lennert Buytenhek <buytenh@wantstofly.org>");
2100MODULE_DESCRIPTION("Driver for Marvell 88E6XXX ethernet switch chips");
2101MODULE_LICENSE("GPL");