summaryrefslogtreecommitdiffstats
path: root/drivers/net/dsa/mv88e6352.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/dsa/mv88e6352.c')
-rw-r--r--drivers/net/dsa/mv88e6352.c307
1 files changed, 38 insertions, 269 deletions
diff --git a/drivers/net/dsa/mv88e6352.c b/drivers/net/dsa/mv88e6352.c
index e13adc7b3dda..126c11b81e75 100644
--- a/drivers/net/dsa/mv88e6352.c
+++ b/drivers/net/dsa/mv88e6352.c
@@ -22,59 +22,6 @@
#include <net/dsa.h>
#include "mv88e6xxx.h"
-static int mv88e6352_wait(struct dsa_switch *ds, int reg, int offset, u16 mask)
-{
- unsigned long timeout = jiffies + HZ / 10;
-
- while (time_before(jiffies, timeout)) {
- int ret;
-
- ret = REG_READ(reg, offset);
- if (!(ret & mask))
- return 0;
-
- usleep_range(1000, 2000);
- }
- return -ETIMEDOUT;
-}
-
-static inline int mv88e6352_phy_wait(struct dsa_switch *ds)
-{
- return mv88e6352_wait(ds, REG_GLOBAL2, 0x18, 0x8000);
-}
-
-static inline int mv88e6352_eeprom_load_wait(struct dsa_switch *ds)
-{
- return mv88e6352_wait(ds, REG_GLOBAL2, 0x14, 0x0800);
-}
-
-static inline int mv88e6352_eeprom_busy_wait(struct dsa_switch *ds)
-{
- return mv88e6352_wait(ds, REG_GLOBAL2, 0x14, 0x8000);
-}
-
-static int __mv88e6352_phy_read(struct dsa_switch *ds, int addr, int regnum)
-{
- int ret;
-
- REG_WRITE(REG_GLOBAL2, 0x18, 0x9800 | (addr << 5) | regnum);
-
- ret = mv88e6352_phy_wait(ds);
- if (ret < 0)
- return ret;
-
- return REG_READ(REG_GLOBAL2, 0x19);
-}
-
-static int __mv88e6352_phy_write(struct dsa_switch *ds, int addr, int regnum,
- u16 val)
-{
- REG_WRITE(REG_GLOBAL2, 0x19, val);
- REG_WRITE(REG_GLOBAL2, 0x18, 0x9400 | (addr << 5) | regnum);
-
- return mv88e6352_phy_wait(ds);
-}
-
static char *mv88e6352_probe(struct device *host_dev, int sw_addr)
{
struct mii_bus *bus = dsa_host_dev_to_mii_bus(host_dev);
@@ -83,58 +30,24 @@ static char *mv88e6352_probe(struct device *host_dev, int sw_addr)
if (bus == NULL)
return NULL;
- ret = __mv88e6xxx_reg_read(bus, sw_addr, REG_PORT(0), 0x03);
+ ret = __mv88e6xxx_reg_read(bus, sw_addr, REG_PORT(0), PORT_SWITCH_ID);
if (ret >= 0) {
- if ((ret & 0xfff0) == 0x1760)
+ if ((ret & 0xfff0) == PORT_SWITCH_ID_6176)
return "Marvell 88E6176";
- if (ret == 0x3521)
+ if (ret == PORT_SWITCH_ID_6352_A0)
return "Marvell 88E6352 (A0)";
- if (ret == 0x3522)
+ if (ret == PORT_SWITCH_ID_6352_A1)
return "Marvell 88E6352 (A1)";
- if ((ret & 0xfff0) == 0x3520)
+ if ((ret & 0xfff0) == PORT_SWITCH_ID_6352)
return "Marvell 88E6352";
}
return NULL;
}
-static int mv88e6352_switch_reset(struct dsa_switch *ds)
-{
- unsigned long timeout;
- int ret;
- int i;
-
- /* Set all ports to the disabled state. */
- for (i = 0; i < 7; i++) {
- ret = REG_READ(REG_PORT(i), 0x04);
- REG_WRITE(REG_PORT(i), 0x04, ret & 0xfffc);
- }
-
- /* Wait for transmit queues to drain. */
- usleep_range(2000, 4000);
-
- /* Reset the switch. Keep PPU active (bit 14, undocumented).
- * The PPU needs to be active to support indirect phy register
- * accesses through global registers 0x18 and 0x19.
- */
- REG_WRITE(REG_GLOBAL, 0x04, 0xc000);
-
- /* Wait up to one second for reset to complete. */
- timeout = jiffies + 1 * HZ;
- while (time_before(jiffies, timeout)) {
- ret = REG_READ(REG_GLOBAL, 0x00);
- if ((ret & 0x8800) == 0x8800)
- break;
- usleep_range(1000, 2000);
- }
- if (time_after(jiffies, timeout))
- return -ETIMEDOUT;
-
- return 0;
-}
-
static int mv88e6352_setup_global(struct dsa_switch *ds)
{
+ struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
int ret;
int i;
@@ -205,7 +118,7 @@ static int mv88e6352_setup_global(struct dsa_switch *ds)
/* Disable ingress rate limiting by resetting all ingress
* rate limit registers to their initial state.
*/
- for (i = 0; i < 7; i++)
+ for (i = 0; i < ps->num_ports; i++)
REG_WRITE(REG_GLOBAL2, 0x09, 0x9000 | (i << 8));
/* Initialise cross-chip port VLAN table to reset defaults. */
@@ -268,28 +181,6 @@ static int mv88e6352_setup_port(struct dsa_switch *ds, int p)
val |= 0x000c;
REG_WRITE(addr, 0x04, val);
- /* Port Control 1: disable trunking. Also, if this is the
- * CPU port, enable learn messages to be sent to this port.
- */
- REG_WRITE(addr, 0x05, dsa_is_cpu_port(ds, p) ? 0x8000 : 0x0000);
-
- /* Port based VLAN map: give each port its own address
- * database, allow the CPU port to talk to each of the 'real'
- * ports, and allow each of the 'real' ports to only talk to
- * the upstream port.
- */
- val = (p & 0xf) << 12;
- if (dsa_is_cpu_port(ds, p))
- val |= ds->phys_port_mask;
- else
- val |= 1 << dsa_upstream_port(ds);
- REG_WRITE(addr, 0x06, val);
-
- /* Default VLAN ID and priority: don't set a default VLAN
- * ID, and set the default packet priority to zero.
- */
- REG_WRITE(addr, 0x07, 0x0000);
-
/* Port Control 2: don't force a good FCS, set the maximum
* frame size to 10240 bytes, don't let the switch add or
* strip 802.1q tags, don't discard tagged or untagged frames
@@ -334,53 +225,18 @@ static int mv88e6352_setup_port(struct dsa_switch *ds, int p)
*/
REG_WRITE(addr, 0x19, 0x7654);
- return 0;
+ return mv88e6xxx_setup_port_common(ds, p);
}
#ifdef CONFIG_NET_DSA_HWMON
-static int mv88e6352_phy_page_read(struct dsa_switch *ds,
- int port, int page, int reg)
-{
- struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
- int ret;
-
- mutex_lock(&ps->phy_mutex);
- ret = __mv88e6352_phy_write(ds, port, 0x16, page);
- if (ret < 0)
- goto error;
- ret = __mv88e6352_phy_read(ds, port, reg);
-error:
- __mv88e6352_phy_write(ds, port, 0x16, 0x0);
- mutex_unlock(&ps->phy_mutex);
- return ret;
-}
-
-static int mv88e6352_phy_page_write(struct dsa_switch *ds,
- int port, int page, int reg, int val)
-{
- struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
- int ret;
-
- mutex_lock(&ps->phy_mutex);
- ret = __mv88e6352_phy_write(ds, port, 0x16, page);
- if (ret < 0)
- goto error;
-
- ret = __mv88e6352_phy_write(ds, port, reg, val);
-error:
- __mv88e6352_phy_write(ds, port, 0x16, 0x0);
- mutex_unlock(&ps->phy_mutex);
- return ret;
-}
-
static int mv88e6352_get_temp(struct dsa_switch *ds, int *temp)
{
int ret;
*temp = 0;
- ret = mv88e6352_phy_page_read(ds, 0, 6, 27);
+ ret = mv88e6xxx_phy_page_read(ds, 0, 6, 27);
if (ret < 0)
return ret;
@@ -395,7 +251,7 @@ static int mv88e6352_get_temp_limit(struct dsa_switch *ds, int *temp)
*temp = 0;
- ret = mv88e6352_phy_page_read(ds, 0, 6, 26);
+ ret = mv88e6xxx_phy_page_read(ds, 0, 6, 26);
if (ret < 0)
return ret;
@@ -408,11 +264,11 @@ static int mv88e6352_set_temp_limit(struct dsa_switch *ds, int temp)
{
int ret;
- ret = mv88e6352_phy_page_read(ds, 0, 6, 26);
+ ret = mv88e6xxx_phy_page_read(ds, 0, 6, 26);
if (ret < 0)
return ret;
temp = clamp_val(DIV_ROUND_CLOSEST(temp, 5) + 5, 0, 0x1f);
- return mv88e6352_phy_page_write(ds, 0, 6, 26,
+ return mv88e6xxx_phy_page_write(ds, 0, 6, 26,
(ret & 0xe0ff) | (temp << 8));
}
@@ -422,7 +278,7 @@ static int mv88e6352_get_temp_alarm(struct dsa_switch *ds, bool *alarm)
*alarm = false;
- ret = mv88e6352_phy_page_read(ds, 0, 6, 26);
+ ret = mv88e6xxx_phy_page_read(ds, 0, 6, 26);
if (ret < 0)
return ret;
@@ -438,14 +294,15 @@ static int mv88e6352_setup(struct dsa_switch *ds)
int ret;
int i;
- mutex_init(&ps->smi_mutex);
- mutex_init(&ps->stats_mutex);
- mutex_init(&ps->phy_mutex);
- mutex_init(&ps->eeprom_mutex);
+ ret = mv88e6xxx_setup_common(ds);
+ if (ret < 0)
+ return ret;
- ps->id = REG_READ(REG_PORT(0), 0x03) & 0xfff0;
+ ps->num_ports = 7;
- ret = mv88e6352_switch_reset(ds);
+ mutex_init(&ps->eeprom_mutex);
+
+ ret = mv88e6xxx_switch_reset(ds, true);
if (ret < 0)
return ret;
@@ -455,7 +312,7 @@ static int mv88e6352_setup(struct dsa_switch *ds)
if (ret < 0)
return ret;
- for (i = 0; i < 7; i++) {
+ for (i = 0; i < ps->num_ports; i++) {
ret = mv88e6352_setup_port(ds, i);
if (ret < 0)
return ret;
@@ -464,83 +321,6 @@ static int mv88e6352_setup(struct dsa_switch *ds)
return 0;
}
-static int mv88e6352_port_to_phy_addr(int port)
-{
- if (port >= 0 && port <= 4)
- return port;
- return -EINVAL;
-}
-
-static int
-mv88e6352_phy_read(struct dsa_switch *ds, int port, int regnum)
-{
- struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
- int addr = mv88e6352_port_to_phy_addr(port);
- int ret;
-
- if (addr < 0)
- return addr;
-
- mutex_lock(&ps->phy_mutex);
- ret = __mv88e6352_phy_read(ds, addr, regnum);
- mutex_unlock(&ps->phy_mutex);
-
- return ret;
-}
-
-static int
-mv88e6352_phy_write(struct dsa_switch *ds, int port, int regnum, u16 val)
-{
- struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
- int addr = mv88e6352_port_to_phy_addr(port);
- int ret;
-
- if (addr < 0)
- return addr;
-
- mutex_lock(&ps->phy_mutex);
- ret = __mv88e6352_phy_write(ds, addr, regnum, val);
- mutex_unlock(&ps->phy_mutex);
-
- return ret;
-}
-
-static struct mv88e6xxx_hw_stat mv88e6352_hw_stats[] = {
- { "in_good_octets", 8, 0x00, },
- { "in_bad_octets", 4, 0x02, },
- { "in_unicast", 4, 0x04, },
- { "in_broadcasts", 4, 0x06, },
- { "in_multicasts", 4, 0x07, },
- { "in_pause", 4, 0x16, },
- { "in_undersize", 4, 0x18, },
- { "in_fragments", 4, 0x19, },
- { "in_oversize", 4, 0x1a, },
- { "in_jabber", 4, 0x1b, },
- { "in_rx_error", 4, 0x1c, },
- { "in_fcs_error", 4, 0x1d, },
- { "out_octets", 8, 0x0e, },
- { "out_unicast", 4, 0x10, },
- { "out_broadcasts", 4, 0x13, },
- { "out_multicasts", 4, 0x12, },
- { "out_pause", 4, 0x15, },
- { "excessive", 4, 0x11, },
- { "collisions", 4, 0x1e, },
- { "deferred", 4, 0x05, },
- { "single", 4, 0x14, },
- { "multiple", 4, 0x17, },
- { "out_fcs_error", 4, 0x03, },
- { "late", 4, 0x1f, },
- { "hist_64bytes", 4, 0x08, },
- { "hist_65_127bytes", 4, 0x09, },
- { "hist_128_255bytes", 4, 0x0a, },
- { "hist_256_511bytes", 4, 0x0b, },
- { "hist_512_1023bytes", 4, 0x0c, },
- { "hist_1024_max_bytes", 4, 0x0d, },
- { "sw_in_discards", 4, 0x110, },
- { "sw_in_filtered", 2, 0x112, },
- { "sw_out_filtered", 2, 0x113, },
-};
-
static int mv88e6352_read_eeprom_word(struct dsa_switch *ds, int addr)
{
struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
@@ -553,7 +333,7 @@ static int mv88e6352_read_eeprom_word(struct dsa_switch *ds, int addr)
if (ret < 0)
goto error;
- ret = mv88e6352_eeprom_busy_wait(ds);
+ ret = mv88e6xxx_eeprom_busy_wait(ds);
if (ret < 0)
goto error;
@@ -576,7 +356,7 @@ static int mv88e6352_get_eeprom(struct dsa_switch *ds,
eeprom->magic = 0xc3ec4951;
- ret = mv88e6352_eeprom_load_wait(ds);
+ ret = mv88e6xxx_eeprom_load_wait(ds);
if (ret < 0)
return ret;
@@ -657,7 +437,7 @@ static int mv88e6352_write_eeprom_word(struct dsa_switch *ds, int addr,
if (ret < 0)
goto error;
- ret = mv88e6352_eeprom_busy_wait(ds);
+ ret = mv88e6xxx_eeprom_busy_wait(ds);
error:
mutex_unlock(&ps->eeprom_mutex);
return ret;
@@ -681,7 +461,7 @@ static int mv88e6352_set_eeprom(struct dsa_switch *ds,
len = eeprom->len;
eeprom->len = 0;
- ret = mv88e6352_eeprom_load_wait(ds);
+ ret = mv88e6xxx_eeprom_load_wait(ds);
if (ret < 0)
return ret;
@@ -739,37 +519,20 @@ static int mv88e6352_set_eeprom(struct dsa_switch *ds,
return 0;
}
-static void
-mv88e6352_get_strings(struct dsa_switch *ds, int port, uint8_t *data)
-{
- mv88e6xxx_get_strings(ds, ARRAY_SIZE(mv88e6352_hw_stats),
- mv88e6352_hw_stats, port, data);
-}
-
-static void
-mv88e6352_get_ethtool_stats(struct dsa_switch *ds, int port, uint64_t *data)
-{
- mv88e6xxx_get_ethtool_stats(ds, ARRAY_SIZE(mv88e6352_hw_stats),
- mv88e6352_hw_stats, port, data);
-}
-
-static int mv88e6352_get_sset_count(struct dsa_switch *ds)
-{
- return ARRAY_SIZE(mv88e6352_hw_stats);
-}
-
struct dsa_switch_driver mv88e6352_switch_driver = {
.tag_protocol = DSA_TAG_PROTO_EDSA,
.priv_size = sizeof(struct mv88e6xxx_priv_state),
.probe = mv88e6352_probe,
.setup = mv88e6352_setup,
.set_addr = mv88e6xxx_set_addr_indirect,
- .phy_read = mv88e6352_phy_read,
- .phy_write = mv88e6352_phy_write,
+ .phy_read = mv88e6xxx_phy_read_indirect,
+ .phy_write = mv88e6xxx_phy_write_indirect,
.poll_link = mv88e6xxx_poll_link,
- .get_strings = mv88e6352_get_strings,
- .get_ethtool_stats = mv88e6352_get_ethtool_stats,
- .get_sset_count = mv88e6352_get_sset_count,
+ .get_strings = mv88e6xxx_get_strings,
+ .get_ethtool_stats = mv88e6xxx_get_ethtool_stats,
+ .get_sset_count = mv88e6xxx_get_sset_count,
+ .set_eee = mv88e6xxx_set_eee,
+ .get_eee = mv88e6xxx_get_eee,
#ifdef CONFIG_NET_DSA_HWMON
.get_temp = mv88e6352_get_temp,
.get_temp_limit = mv88e6352_get_temp_limit,
@@ -780,6 +543,12 @@ struct dsa_switch_driver mv88e6352_switch_driver = {
.set_eeprom = mv88e6352_set_eeprom,
.get_regs_len = mv88e6xxx_get_regs_len,
.get_regs = mv88e6xxx_get_regs,
+ .port_join_bridge = mv88e6xxx_join_bridge,
+ .port_leave_bridge = mv88e6xxx_leave_bridge,
+ .port_stp_update = mv88e6xxx_port_stp_update,
+ .fdb_add = mv88e6xxx_port_fdb_add,
+ .fdb_del = mv88e6xxx_port_fdb_del,
+ .fdb_getnext = mv88e6xxx_port_fdb_getnext,
};
MODULE_ALIAS("platform:mv88e6352");