Commit 99949a74 authored by David S. Miller's avatar David S. Miller

Merge branch 'dsa-next'

Andrew Lunn says:

====================
DSA Mavell drivers refactoring and cleanup

v1->v2:
 * Add missing signed-of-by: For patches authored by Guenter Roeck.
 * Add Reviewed by from Guenter Roack to patch #5.

This is a collection of patches again net-next from today containing
refactoring and consolidate of code, cleanups and using #define's to
replace register numbers.

Patch #1 Swaps the 6131 driver to use the consolidated setup code.

Patch #2 Moves the Switch IDs used during probe into a central
         location.  We need these later so that we can differentiate
         the different features the devices have.

Patch #3 Makes the 6131 driver set the number of ports in the private
         state structure. It then uses this, rather than hard coded
         maximum number of ports.

Patch #4 Similar to Patch #3, but for the 6123_61_65 driver.

Patch #5 Similar to Patch #3, and #4, but for all the remaining
         drivers.  This greatly increases the similarity of the code
         between drivers, allow further patches to consolidate the
         duplicated code.

Patch #6 Consolidate the switch reset code, which has two minor
         variants. Removes around 35 lines per driver.

Patch #7 Moves phy page access functions out of the 6352 driver into
         the shared code. Currently only the 6352 driver uses this,
         but it is likely other devices will come along wanting this
         functionality.

Patch #8 Consolidates the code used to access phy registers. Removes
         around 40 lines of code per driver.

Patch #9 Fixes missing mutex locking in the EEE code, and refactors
         the code a bit to make it more understandable with respect to
         locks.

Patch #10 Consolidates reading statistics. This is very similar code
          for all devices, but the number of available statistics
          differ, which can be determined from the product ID. Removes
	  around 65 lines per driver.

Patch #11 Add #defines for registers, and bits within the
          registers. For the moment, this is limited to the shared
          code. The individual drivers will be converted once the
          remaining duplicated code is consolidated

Patch #12 Fix broken statistic counters on the 6172. The 6352 family
          requires the port number is poked into a different set of
          bits in the register compared to other devices.

Many thanks to Guenter Roeck for repeatedly reviewing the patches and
testing them on his hardware.
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 05e8bb86 f3a8b6b6
......@@ -25,66 +25,33 @@ static char *mv88e6123_61_65_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 == 0x1212)
if (ret == PORT_SWITCH_ID_6123_A1)
return "Marvell 88E6123 (A1)";
if (ret == 0x1213)
if (ret == PORT_SWITCH_ID_6123_A2)
return "Marvell 88E6123 (A2)";
if ((ret & 0xfff0) == 0x1210)
if ((ret & 0xfff0) == PORT_SWITCH_ID_6123)
return "Marvell 88E6123";
if (ret == 0x1612)
if (ret == PORT_SWITCH_ID_6161_A1)
return "Marvell 88E6161 (A1)";
if (ret == 0x1613)
if (ret == PORT_SWITCH_ID_6161_A2)
return "Marvell 88E6161 (A2)";
if ((ret & 0xfff0) == 0x1610)
if ((ret & 0xfff0) == PORT_SWITCH_ID_6161)
return "Marvell 88E6161";
if (ret == 0x1652)
if (ret == PORT_SWITCH_ID_6165_A1)
return "Marvell 88E6165 (A1)";
if (ret == 0x1653)
if (ret == PORT_SWITCH_ID_6165_A2)
return "Marvell 88e6165 (A2)";
if ((ret & 0xfff0) == 0x1650)
if ((ret & 0xfff0) == PORT_SWITCH_ID_6165)
return "Marvell 88E6165";
}
return NULL;
}
static int mv88e6123_61_65_switch_reset(struct dsa_switch *ds)
{
int i;
int ret;
unsigned long timeout;
/* Set all ports to the disabled state. */
for (i = 0; i < 8; 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. */
REG_WRITE(REG_GLOBAL, 0x04, 0xc400);
/* 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 & 0xc800) == 0xc800)
break;
usleep_range(1000, 2000);
}
if (time_after(jiffies, timeout))
return -ETIMEDOUT;
return 0;
}
static int mv88e6123_61_65_setup_global(struct dsa_switch *ds)
{
int ret;
......@@ -271,6 +238,7 @@ static int mv88e6123_61_65_setup_port(struct dsa_switch *ds, int p)
static int mv88e6123_61_65_setup(struct dsa_switch *ds)
{
struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
int i;
int ret;
......@@ -278,7 +246,19 @@ static int mv88e6123_61_65_setup(struct dsa_switch *ds)
if (ret < 0)
return ret;
ret = mv88e6123_61_65_switch_reset(ds);
switch (ps->id) {
case PORT_SWITCH_ID_6123:
ps->num_ports = 3;
break;
case PORT_SWITCH_ID_6161:
case PORT_SWITCH_ID_6165:
ps->num_ports = 6;
break;
default:
return -ENODEV;
}
ret = mv88e6xxx_switch_reset(ds, false);
if (ret < 0)
return ret;
......@@ -288,7 +268,7 @@ static int mv88e6123_61_65_setup(struct dsa_switch *ds)
if (ret < 0)
return ret;
for (i = 0; i < 6; i++) {
for (i = 0; i < ps->num_ports; i++) {
ret = mv88e6123_61_65_setup_port(ds, i);
if (ret < 0)
return ret;
......@@ -297,108 +277,18 @@ static int mv88e6123_61_65_setup(struct dsa_switch *ds)
return 0;
}
static int mv88e6123_61_65_port_to_phy_addr(int port)
{
if (port >= 0 && port <= 4)
return port;
return -1;
}
static int
mv88e6123_61_65_phy_read(struct dsa_switch *ds, int port, int regnum)
{
struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
int addr = mv88e6123_61_65_port_to_phy_addr(port);
int ret;
mutex_lock(&ps->phy_mutex);
ret = mv88e6xxx_phy_read(ds, addr, regnum);
mutex_unlock(&ps->phy_mutex);
return ret;
}
static int
mv88e6123_61_65_phy_write(struct dsa_switch *ds,
int port, int regnum, u16 val)
{
struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
int addr = mv88e6123_61_65_port_to_phy_addr(port);
int ret;
mutex_lock(&ps->phy_mutex);
ret = mv88e6xxx_phy_write(ds, addr, regnum, val);
mutex_unlock(&ps->phy_mutex);
return ret;
}
static struct mv88e6xxx_hw_stat mv88e6123_61_65_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 void
mv88e6123_61_65_get_strings(struct dsa_switch *ds, int port, uint8_t *data)
{
mv88e6xxx_get_strings(ds, ARRAY_SIZE(mv88e6123_61_65_hw_stats),
mv88e6123_61_65_hw_stats, port, data);
}
static void
mv88e6123_61_65_get_ethtool_stats(struct dsa_switch *ds,
int port, uint64_t *data)
{
mv88e6xxx_get_ethtool_stats(ds, ARRAY_SIZE(mv88e6123_61_65_hw_stats),
mv88e6123_61_65_hw_stats, port, data);
}
static int mv88e6123_61_65_get_sset_count(struct dsa_switch *ds)
{
return ARRAY_SIZE(mv88e6123_61_65_hw_stats);
}
struct dsa_switch_driver mv88e6123_61_65_switch_driver = {
.tag_protocol = DSA_TAG_PROTO_EDSA,
.priv_size = sizeof(struct mv88e6xxx_priv_state),
.probe = mv88e6123_61_65_probe,
.setup = mv88e6123_61_65_setup,
.set_addr = mv88e6xxx_set_addr_indirect,
.phy_read = mv88e6123_61_65_phy_read,
.phy_write = mv88e6123_61_65_phy_write,
.phy_read = mv88e6xxx_phy_read,
.phy_write = mv88e6xxx_phy_write,
.poll_link = mv88e6xxx_poll_link,
.get_strings = mv88e6123_61_65_get_strings,
.get_ethtool_stats = mv88e6123_61_65_get_ethtool_stats,
.get_sset_count = mv88e6123_61_65_get_sset_count,
.get_strings = mv88e6xxx_get_strings,
.get_ethtool_stats = mv88e6xxx_get_ethtool_stats,
.get_sset_count = mv88e6xxx_get_sset_count,
#ifdef CONFIG_NET_DSA_HWMON
.get_temp = mv88e6xxx_get_temp,
#endif
......
......@@ -17,12 +17,6 @@
#include <net/dsa.h>
#include "mv88e6xxx.h"
/* Switch product IDs */
#define ID_6085 0x04a0
#define ID_6095 0x0950
#define ID_6131 0x1060
#define ID_6131_B2 0x1066
static char *mv88e6131_probe(struct device *host_dev, int sw_addr)
{
struct mii_bus *bus = dsa_host_dev_to_mii_bus(host_dev);
......@@ -31,56 +25,23 @@ static char *mv88e6131_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) {
int ret_masked = ret & 0xfff0;
if (ret_masked == ID_6085)
if (ret_masked == PORT_SWITCH_ID_6085)
return "Marvell 88E6085";
if (ret_masked == ID_6095)
if (ret_masked == PORT_SWITCH_ID_6095)
return "Marvell 88E6095/88E6095F";
if (ret == ID_6131_B2)
if (ret == PORT_SWITCH_ID_6131_B2)
return "Marvell 88E6131 (B2)";
if (ret_masked == ID_6131)
if (ret_masked == PORT_SWITCH_ID_6131)
return "Marvell 88E6131";
}
return NULL;
}
static int mv88e6131_switch_reset(struct dsa_switch *ds)
{
int i;
int ret;
unsigned long timeout;
/* Set all ports to the disabled state. */
for (i = 0; i < 11; 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. */
REG_WRITE(REG_GLOBAL, 0x04, 0xc400);
/* 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 & 0xc800) == 0xc800)
break;
usleep_range(1000, 2000);
}
if (time_after(jiffies, timeout))
return -ETIMEDOUT;
return 0;
}
static int mv88e6131_setup_global(struct dsa_switch *ds)
{
int ret;
......@@ -174,7 +135,7 @@ static int mv88e6131_setup_port(struct dsa_switch *ds, int p)
* (100 Mb/s on 6085) full duplex.
*/
if (dsa_is_cpu_port(ds, p) || ds->dsa_port_mask & (1 << p))
if (ps->id == ID_6085)
if (ps->id == PORT_SWITCH_ID_6085)
REG_WRITE(addr, 0x01, 0x003d); /* 100 Mb/s */
else
REG_WRITE(addr, 0x01, 0x003e); /* 1000 Mb/s */
......@@ -201,35 +162,13 @@ static int mv88e6131_setup_port(struct dsa_switch *ds, int p)
/* On 6085, unknown multicast forward is controlled
* here rather than in Port Control 2 register.
*/
if (ps->id == ID_6085)
if (ps->id == PORT_SWITCH_ID_6085)
val |= 0x0008;
}
if (ds->dsa_port_mask & (1 << p))
val |= 0x0100;
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, don't use
* VLAN-based, source address-based or destination
* address-based priority overrides, don't let the switch
......@@ -242,7 +181,7 @@ static int mv88e6131_setup_port(struct dsa_switch *ds, int p)
* If this is the upstream port for this switch, enable
* forwarding of unknown multicast addresses.
*/
if (ps->id == ID_6085)
if (ps->id == PORT_SWITCH_ID_6085)
/* on 6085, bits 3:0 are reserved, bit 6 control ARP
* mirroring, and multicast forward is handled in
* Port Control register.
......@@ -278,7 +217,7 @@ static int mv88e6131_setup_port(struct dsa_switch *ds, int p)
*/
REG_WRITE(addr, 0x19, 0x7654);
return 0;
return mv88e6xxx_setup_port_common(ds, p);
}
static int mv88e6131_setup(struct dsa_switch *ds)
......@@ -287,13 +226,28 @@ static int mv88e6131_setup(struct dsa_switch *ds)
int i;
int ret;
mutex_init(&ps->smi_mutex);
ret = mv88e6xxx_setup_common(ds);
if (ret < 0)
return ret;
mv88e6xxx_ppu_state_init(ds);
mutex_init(&ps->stats_mutex);
ps->id = REG_READ(REG_PORT(0), 0x03) & 0xfff0;
switch (ps->id) {
case PORT_SWITCH_ID_6085:
ps->num_ports = 10;
break;
case PORT_SWITCH_ID_6095:
ps->num_ports = 11;
break;
case PORT_SWITCH_ID_6131:
case PORT_SWITCH_ID_6131_B2:
ps->num_ports = 8;
break;
default:
return -ENODEV;
}
ret = mv88e6131_switch_reset(ds);
ret = mv88e6xxx_switch_reset(ds, false);
if (ret < 0)
return ret;
......@@ -303,7 +257,7 @@ static int mv88e6131_setup(struct dsa_switch *ds)
if (ret < 0)
return ret;
for (i = 0; i < 11; i++) {
for (i = 0; i < ps->num_ports; i++) {
ret = mv88e6131_setup_port(ds, i);
if (ret < 0)
return ret;
......@@ -312,17 +266,24 @@ static int mv88e6131_setup(struct dsa_switch *ds)
return 0;
}
static int mv88e6131_port_to_phy_addr(int port)
static int mv88e6131_port_to_phy_addr(struct dsa_switch *ds, int port)
{
if (port >= 0 && port <= 11)
struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
if (port >= 0 && port < ps->num_ports)
return port;
return -1;
return -EINVAL;
}
static int
mv88e6131_phy_read(struct dsa_switch *ds, int port, int regnum)
{
int addr = mv88e6131_port_to_phy_addr(port);
int addr = mv88e6131_port_to_phy_addr(ds, port);
if (addr < 0)
return addr;
return mv88e6xxx_phy_read_ppu(ds, addr, regnum);
}
......@@ -330,61 +291,12 @@ static int
mv88e6131_phy_write(struct dsa_switch *ds,
int port, int regnum, u16 val)
{
int addr = mv88e6131_port_to_phy_addr(port);
return mv88e6xxx_phy_write_ppu(ds, addr, regnum, val);
}
static struct mv88e6xxx_hw_stat mv88e6131_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, },
};
static void
mv88e6131_get_strings(struct dsa_switch *ds, int port, uint8_t *data)
{
mv88e6xxx_get_strings(ds, ARRAY_SIZE(mv88e6131_hw_stats),
mv88e6131_hw_stats, port, data);
}
int addr = mv88e6131_port_to_phy_addr(ds, port);
static void
mv88e6131_get_ethtool_stats(struct dsa_switch *ds,
int port, uint64_t *data)
{
mv88e6xxx_get_ethtool_stats(ds, ARRAY_SIZE(mv88e6131_hw_stats),
mv88e6131_hw_stats, port, data);
}
if (addr < 0)
return addr;
static int mv88e6131_get_sset_count(struct dsa_switch *ds)
{
return ARRAY_SIZE(mv88e6131_hw_stats);
return mv88e6xxx_phy_write_ppu(ds, addr, regnum, val);
}
struct dsa_switch_driver mv88e6131_switch_driver = {
......@@ -396,9 +308,9 @@ struct dsa_switch_driver mv88e6131_switch_driver = {
.phy_read = mv88e6131_phy_read,
.phy_write = mv88e6131_phy_write,
.poll_link = mv88e6xxx_poll_link,
.get_strings = mv88e6131_get_strings,
.get_ethtool_stats = mv88e6131_get_ethtool_stats,
.get_sset_count = mv88e6131_get_sset_count,
.get_strings = mv88e6xxx_get_strings,
.get_ethtool_stats = mv88e6xxx_get_ethtool_stats,
.get_sset_count = mv88e6xxx_get_sset_count,
};
MODULE_ALIAS("platform:mv88e6085");
......
......@@ -17,10 +17,6 @@
#include <net/dsa.h>
#include "mv88e6xxx.h"
/* Switch product IDs */
#define ID_6171 0x1710
#define ID_6172 0x1720
static char *mv88e6171_probe(struct device *host_dev, int sw_addr)
{
struct mii_bus *bus = dsa_host_dev_to_mii_bus(host_dev);
......@@ -29,64 +25,20 @@ static char *mv88e6171_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) == ID_6171)
if ((ret & 0xfff0) == PORT_SWITCH_ID_6171)
return "Marvell 88E6171";
if ((ret & 0xfff0) == ID_6172)
if ((ret & 0xfff0) == PORT_SWITCH_ID_6172)
return "Marvell 88E6172";
}
return NULL;
}
static int mv88e6171_switch_reset(struct dsa_switch *ds)
{
int i;
int ret;
unsigned long timeout;
/* Set all ports to the disabled state. */
for (i = 0; i < 8; 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. 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 & 0xc800) == 0xc800)
break;
usleep_range(1000, 2000);
}
if (time_after(jiffies, timeout))
return -ETIMEDOUT;
/* Enable ports not under DSA, e.g. WAN port */
for (i = 0; i < 8; i++) {
if (dsa_is_cpu_port(ds, i) || ds->phys_port_mask & (1 << i))
continue;
ret = REG_READ(REG_PORT(i), 0x04);
REG_WRITE(REG_PORT(i), 0x04, ret | 0x03);
}
return 0;
}
static int mv88e6171_setup_global(struct dsa_switch *ds)
{
struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
int ret;
int i;
......@@ -151,7 +103,7 @@ static int mv88e6171_setup_global(struct dsa_switch *ds)
}
/* Clear all trunk masks. */
for (i = 0; i < 8; i++)
for (i = 0; i < ps->num_ports; i++)
REG_WRITE(REG_GLOBAL2, 0x07, 0x8000 | (i << 12) | 0xff);
/* Clear all trunk mappings. */
......@@ -274,6 +226,7 @@ static int mv88e6171_setup_port(struct dsa_switch *ds, int p)
static int mv88e6171_setup(struct dsa_switch *ds)
{
struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
int i;
int ret;
......@@ -281,7 +234,9 @@ static int mv88e6171_setup(struct dsa_switch *ds)
if (ret < 0)
return ret;
ret = mv88e6171_switch_reset(ds);
ps->num_ports = 7;
ret = mv88e6xxx_switch_reset(ds, true);
if (ret < 0)
return ret;
......@@ -291,7 +246,7 @@ static int mv88e6171_setup(struct dsa_switch *ds)
if (ret < 0)
return ret;
for (i = 0; i < 8; i++) {
for (i = 0; i < ps->num_ports; i++) {
if (!(dsa_is_cpu_port(ds, i) || ds->phys_port_mask & (1 << i)))
continue;
......@@ -303,99 +258,12 @@ static int mv88e6171_setup(struct dsa_switch *ds)
return 0;
}
static int mv88e6171_port_to_phy_addr(int port)
{
if (port >= 0 && port <= 4)
return port;
return -1;
}
static int
mv88e6171_phy_read(struct dsa_switch *ds, int port, int regnum)
{
struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
int addr = mv88e6171_port_to_phy_addr(port);
int ret;
mutex_lock(&ps->phy_mutex);
ret = mv88e6xxx_phy_read_indirect(ds, addr, regnum);
mutex_unlock(&ps->phy_mutex);
return ret;
}
static int
mv88e6171_phy_write(struct dsa_switch *ds,
int port, int regnum, u16 val)
{
struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
int addr = mv88e6171_port_to_phy_addr(port);
int ret;
mutex_lock(&ps->phy_mutex);
ret = mv88e6xxx_phy_write_indirect(ds, addr, regnum, val);
mutex_unlock(&ps->phy_mutex);
return ret;
}
static struct mv88e6xxx_hw_stat mv88e6171_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, },
};
static void
mv88e6171_get_strings(struct dsa_switch *ds, int port, uint8_t *data)
{
mv88e6xxx_get_strings(ds, ARRAY_SIZE(mv88e6171_hw_stats),
mv88e6171_hw_stats, port, data);
}
static void
mv88e6171_get_ethtool_stats(struct dsa_switch *ds,
int port, uint64_t *data)
{
mv88e6xxx_get_ethtool_stats(ds, ARRAY_SIZE(mv88e6171_hw_stats),
mv88e6171_hw_stats, port, data);
}
static int mv88e6171_get_sset_count(struct dsa_switch *ds)
{
return ARRAY_SIZE(mv88e6171_hw_stats);
}
static int mv88e6171_get_eee(struct dsa_switch *ds, int port,
struct ethtool_eee *e)
{
struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
if (ps->id == ID_6172)
if (ps->id == PORT_SWITCH_ID_6172)
return mv88e6xxx_get_eee(ds, port, e);
return -EOPNOTSUPP;
......@@ -406,7 +274,7 @@ static int mv88e6171_set_eee(struct dsa_switch *ds, int port,
{
struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
if (ps->id == ID_6172)
if (ps->id == PORT_SWITCH_ID_6172)
return mv88e6xxx_set_eee(ds, port, phydev, e);
return -EOPNOTSUPP;
......@@ -418,12 +286,12 @@ struct dsa_switch_driver mv88e6171_switch_driver = {
.probe = mv88e6171_probe,
.setup = mv88e6171_setup,
.set_addr = mv88e6xxx_set_addr_indirect,
.phy_read = mv88e6171_phy_read,
.phy_write = mv88e6171_phy_write,
.phy_read = mv88e6xxx_phy_read_indirect,
.phy_write = mv88e6xxx_phy_write_indirect,
.poll_link = mv88e6xxx_poll_link,
.get_strings = mv88e6171_get_strings,
.get_ethtool_stats = mv88e6171_get_ethtool_stats,
.get_sset_count = mv88e6171_get_sset_count,
.get_strings = mv88e6xxx_get_strings,
.get_ethtool_stats = mv88e6xxx_get_ethtool_stats,
.get_sset_count = mv88e6xxx_get_sset_count,
.set_eee = mv88e6171_set_eee,
.get_eee = mv88e6171_get_eee,
#ifdef CONFIG_NET_DSA_HWMON
......
......@@ -30,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;
......@@ -152,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. */
......@@ -264,48 +230,13 @@ static int mv88e6352_setup_port(struct dsa_switch *ds, int 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 = mv88e6xxx_phy_write_indirect(ds, port, 0x16, page);
if (ret < 0)
goto error;
ret = mv88e6xxx_phy_read_indirect(ds, port, reg);
error:
mv88e6xxx_phy_write_indirect(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 = mv88e6xxx_phy_write_indirect(ds, port, 0x16, page);
if (ret < 0)
goto error;
ret = mv88e6xxx_phy_write_indirect(ds, port, reg, val);
error:
mv88e6xxx_phy_write_indirect(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;
......@@ -320,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;
......@@ -333,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));
}
......@@ -347,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;
......@@ -367,9 +298,11 @@ static int mv88e6352_setup(struct dsa_switch *ds)
if (ret < 0)
return ret;
ps->num_ports = 7;
mutex_init(&ps->eeprom_mutex);
ret = mv88e6352_switch_reset(ds);
ret = mv88e6xxx_switch_reset(ds, true);
if (ret < 0)
return ret;
......@@ -379,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;
......@@ -388,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 = mv88e6xxx_phy_read_indirect(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 = mv88e6xxx_phy_write_indirect(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);
......@@ -663,37 +519,18 @@ 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
......
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment