Merge branch 'dsa-next'
Andrew Lunn says: ==================== More Marvell DSA refactring and fixup This patch setup continues the refactoring and cleanup of the Marvell DSA drivers. Patch #1 Centralizes the duplicated parts of port setup and global setup into the shared mv88e6xxx. Patch #2 Centralizes looping over the ports setting them up Patch #3 Uses mnemonics for the remaining register access in the drivers. Patch #4 The 6172 is actually a member of the 6352 family. This moves the probe code into the correct driver. Patch #5 Adds more members of the 6171 family to the 6171 driver. The new devices are untested. Patch #6 The 6185 is a member of the 6131 family. Add it to the probe code of the 6131 driver. Patch #7 and Patch #8 Simply the mutex's in mv88e6xxx.c. The SMI bus is the bottleneck, not the granularity of the mutex's so simply the code down to a single mutex. Patch #8 Fixes a false positive lockdep splat, due to nested uses of MDIO busses. Patch #9 Fixes another false positive lockdep splat with the transmit queue because of stacked Ethernet devices. ==================== Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
commit
f926204b8b
|
@ -37,22 +37,22 @@ config NET_DSA_MV88E6123_61_65
|
|||
ethernet switch chips.
|
||||
|
||||
config NET_DSA_MV88E6171
|
||||
tristate "Marvell 88E6171/6172 ethernet switch chip support"
|
||||
tristate "Marvell 88E6171/6175/6350/6351 ethernet switch chip support"
|
||||
depends on NET_DSA
|
||||
select NET_DSA_MV88E6XXX
|
||||
select NET_DSA_TAG_EDSA
|
||||
---help---
|
||||
This enables support for the Marvell 88E6171/6172 ethernet switch
|
||||
chips.
|
||||
This enables support for the Marvell 88E6171/6175/6350/6351
|
||||
ethernet switches chips.
|
||||
|
||||
config NET_DSA_MV88E6352
|
||||
tristate "Marvell 88E6176/88E6352 ethernet switch chip support"
|
||||
tristate "Marvell 88E6172/88E6176/88E6352 ethernet switch chip support"
|
||||
depends on NET_DSA
|
||||
select NET_DSA_MV88E6XXX
|
||||
select NET_DSA_TAG_EDSA
|
||||
---help---
|
||||
This enables support for the Marvell 88E6176 and 88E6352 ethernet
|
||||
switch chips.
|
||||
This enables support for the Marvell 88E6172, 88E6176 and 88E6352
|
||||
ethernet switch chips.
|
||||
|
||||
config NET_DSA_BCM_SF2
|
||||
tristate "Broadcom Starfighter 2 Ethernet switch support"
|
||||
|
|
|
@ -54,192 +54,40 @@ static char *mv88e6123_61_65_probe(struct device *host_dev, int sw_addr)
|
|||
|
||||
static int mv88e6123_61_65_setup_global(struct dsa_switch *ds)
|
||||
{
|
||||
u32 upstream_port = dsa_upstream_port(ds);
|
||||
int ret;
|
||||
int i;
|
||||
u32 reg;
|
||||
|
||||
ret = mv88e6xxx_setup_global(ds);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* Disable the PHY polling unit (since there won't be any
|
||||
* external PHYs to poll), don't discard packets with
|
||||
* excessive collisions, and mask all interrupt sources.
|
||||
*/
|
||||
REG_WRITE(REG_GLOBAL, 0x04, 0x0000);
|
||||
|
||||
/* Set the default address aging time to 5 minutes, and
|
||||
* enable address learn messages to be sent to all message
|
||||
* ports.
|
||||
*/
|
||||
REG_WRITE(REG_GLOBAL, 0x0a, 0x0148);
|
||||
|
||||
/* Configure the priority mapping registers. */
|
||||
ret = mv88e6xxx_config_prio(ds);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
REG_WRITE(REG_GLOBAL, GLOBAL_CONTROL, 0x0000);
|
||||
|
||||
/* Configure the upstream port, and configure the upstream
|
||||
* port as the port to which ingress and egress monitor frames
|
||||
* are to be sent.
|
||||
*/
|
||||
REG_WRITE(REG_GLOBAL, 0x1a, (dsa_upstream_port(ds) * 0x1110));
|
||||
reg = upstream_port << GLOBAL_MONITOR_CONTROL_INGRESS_SHIFT |
|
||||
upstream_port << GLOBAL_MONITOR_CONTROL_EGRESS_SHIFT |
|
||||
upstream_port << GLOBAL_MONITOR_CONTROL_ARP_SHIFT;
|
||||
REG_WRITE(REG_GLOBAL, GLOBAL_MONITOR_CONTROL, reg);
|
||||
|
||||
/* Disable remote management for now, and set the switch's
|
||||
* DSA device number.
|
||||
*/
|
||||
REG_WRITE(REG_GLOBAL, 0x1c, ds->index & 0x1f);
|
||||
|
||||
/* Send all frames with destination addresses matching
|
||||
* 01:80:c2:00:00:2x to the CPU port.
|
||||
*/
|
||||
REG_WRITE(REG_GLOBAL2, 0x02, 0xffff);
|
||||
|
||||
/* Send all frames with destination addresses matching
|
||||
* 01:80:c2:00:00:0x to the CPU port.
|
||||
*/
|
||||
REG_WRITE(REG_GLOBAL2, 0x03, 0xffff);
|
||||
|
||||
/* Disable the loopback filter, disable flow control
|
||||
* messages, disable flood broadcast override, disable
|
||||
* removing of provider tags, disable ATU age violation
|
||||
* interrupts, disable tag flow control, force flow
|
||||
* control priority to the highest, and send all special
|
||||
* multicast frames to the CPU at the highest priority.
|
||||
*/
|
||||
REG_WRITE(REG_GLOBAL2, 0x05, 0x00ff);
|
||||
|
||||
/* Program the DSA routing table. */
|
||||
for (i = 0; i < 32; i++) {
|
||||
int nexthop;
|
||||
|
||||
nexthop = 0x1f;
|
||||
if (i != ds->index && i < ds->dst->pd->nr_chips)
|
||||
nexthop = ds->pd->rtable[i] & 0x1f;
|
||||
|
||||
REG_WRITE(REG_GLOBAL2, 0x06, 0x8000 | (i << 8) | nexthop);
|
||||
}
|
||||
|
||||
/* Clear all trunk masks. */
|
||||
for (i = 0; i < 8; i++)
|
||||
REG_WRITE(REG_GLOBAL2, 0x07, 0x8000 | (i << 12) | 0xff);
|
||||
|
||||
/* Clear all trunk mappings. */
|
||||
for (i = 0; i < 16; i++)
|
||||
REG_WRITE(REG_GLOBAL2, 0x08, 0x8000 | (i << 11));
|
||||
|
||||
/* Disable ingress rate limiting by resetting all ingress
|
||||
* rate limit registers to their initial state.
|
||||
*/
|
||||
for (i = 0; i < 6; i++)
|
||||
REG_WRITE(REG_GLOBAL2, 0x09, 0x9000 | (i << 8));
|
||||
|
||||
/* Initialise cross-chip port VLAN table to reset defaults. */
|
||||
REG_WRITE(REG_GLOBAL2, 0x0b, 0x9000);
|
||||
|
||||
/* Clear the priority override table. */
|
||||
for (i = 0; i < 16; i++)
|
||||
REG_WRITE(REG_GLOBAL2, 0x0f, 0x8000 | (i << 8));
|
||||
|
||||
/* @@@ initialise AVB (22/23) watchdog (27) sdet (29) registers */
|
||||
REG_WRITE(REG_GLOBAL, GLOBAL_CONTROL_2, ds->index & 0x1f);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mv88e6123_61_65_setup_port(struct dsa_switch *ds, int p)
|
||||
{
|
||||
int addr = REG_PORT(p);
|
||||
u16 val;
|
||||
|
||||
/* MAC Forcing register: don't force link, speed, duplex
|
||||
* or flow control state to any particular values on physical
|
||||
* ports, but force the CPU port and all DSA ports to 1000 Mb/s
|
||||
* full duplex.
|
||||
*/
|
||||
if (dsa_is_cpu_port(ds, p) || ds->dsa_port_mask & (1 << p))
|
||||
REG_WRITE(addr, 0x01, 0x003e);
|
||||
else
|
||||
REG_WRITE(addr, 0x01, 0x0003);
|
||||
|
||||
/* Do not limit the period of time that this port can be
|
||||
* paused for by the remote end or the period of time that
|
||||
* this port can pause the remote end.
|
||||
*/
|
||||
REG_WRITE(addr, 0x02, 0x0000);
|
||||
|
||||
/* Port Control: disable Drop-on-Unlock, disable Drop-on-Lock,
|
||||
* disable Header mode, enable IGMP/MLD snooping, disable VLAN
|
||||
* tunneling, determine priority by looking at 802.1p and IP
|
||||
* priority fields (IP prio has precedence), and set STP state
|
||||
* to Forwarding.
|
||||
*
|
||||
* If this is the CPU link, use DSA or EDSA tagging depending
|
||||
* on which tagging mode was configured.
|
||||
*
|
||||
* If this is a link to another switch, use DSA tagging mode.
|
||||
*
|
||||
* If this is the upstream port for this switch, enable
|
||||
* forwarding of unknown unicasts and multicasts.
|
||||
*/
|
||||
val = 0x0433;
|
||||
if (dsa_is_cpu_port(ds, p)) {
|
||||
if (ds->dst->tag_protocol == DSA_TAG_PROTO_EDSA)
|
||||
val |= 0x3300;
|
||||
else
|
||||
val |= 0x0100;
|
||||
}
|
||||
if (ds->dsa_port_mask & (1 << p))
|
||||
val |= 0x0100;
|
||||
if (p == dsa_upstream_port(ds))
|
||||
val |= 0x000c;
|
||||
REG_WRITE(addr, 0x04, val);
|
||||
|
||||
/* 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
|
||||
* on this port, do a destination address lookup on all
|
||||
* received packets as usual, disable ARP mirroring and don't
|
||||
* send a copy of all transmitted/received frames on this port
|
||||
* to the CPU.
|
||||
*/
|
||||
REG_WRITE(addr, 0x08, 0x2080);
|
||||
|
||||
/* Egress rate control: disable egress rate control. */
|
||||
REG_WRITE(addr, 0x09, 0x0001);
|
||||
|
||||
/* Egress rate control 2: disable egress rate control. */
|
||||
REG_WRITE(addr, 0x0a, 0x0000);
|
||||
|
||||
/* Port Association Vector: when learning source addresses
|
||||
* of packets, add the address to the address database using
|
||||
* a port bitmap that has only the bit for this port set and
|
||||
* the other bits clear.
|
||||
*/
|
||||
REG_WRITE(addr, 0x0b, 1 << p);
|
||||
|
||||
/* Port ATU control: disable limiting the number of address
|
||||
* database entries that this port is allowed to use.
|
||||
*/
|
||||
REG_WRITE(addr, 0x0c, 0x0000);
|
||||
|
||||
/* Priority Override: disable DA, SA and VTU priority override. */
|
||||
REG_WRITE(addr, 0x0d, 0x0000);
|
||||
|
||||
/* Port Ethertype: use the Ethertype DSA Ethertype value. */
|
||||
REG_WRITE(addr, 0x0f, ETH_P_EDSA);
|
||||
|
||||
/* Tag Remap: use an identity 802.1p prio -> switch prio
|
||||
* mapping.
|
||||
*/
|
||||
REG_WRITE(addr, 0x18, 0x3210);
|
||||
|
||||
/* Tag Remap 2: use an identity 802.1p prio -> switch prio
|
||||
* mapping.
|
||||
*/
|
||||
REG_WRITE(addr, 0x19, 0x7654);
|
||||
|
||||
return mv88e6xxx_setup_port_common(ds, p);
|
||||
}
|
||||
|
||||
static int mv88e6123_61_65_setup(struct dsa_switch *ds)
|
||||
{
|
||||
struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
|
||||
int i;
|
||||
int ret;
|
||||
|
||||
ret = mv88e6xxx_setup_common(ds);
|
||||
|
@ -262,19 +110,11 @@ static int mv88e6123_61_65_setup(struct dsa_switch *ds)
|
|||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
/* @@@ initialise vtu and atu */
|
||||
|
||||
ret = mv88e6123_61_65_setup_global(ds);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
for (i = 0; i < ps->num_ports; i++) {
|
||||
ret = mv88e6123_61_65_setup_port(ds, i);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
return mv88e6xxx_setup_ports(ds);
|
||||
}
|
||||
|
||||
struct dsa_switch_driver mv88e6123_61_65_switch_driver = {
|
||||
|
|
|
@ -37,6 +37,8 @@ static char *mv88e6131_probe(struct device *host_dev, int sw_addr)
|
|||
return "Marvell 88E6131 (B2)";
|
||||
if (ret_masked == PORT_SWITCH_ID_6131)
|
||||
return "Marvell 88E6131";
|
||||
if (ret_masked == PORT_SWITCH_ID_6185)
|
||||
return "Marvell 88E6185";
|
||||
}
|
||||
|
||||
return NULL;
|
||||
|
@ -44,186 +46,62 @@ static char *mv88e6131_probe(struct device *host_dev, int sw_addr)
|
|||
|
||||
static int mv88e6131_setup_global(struct dsa_switch *ds)
|
||||
{
|
||||
u32 upstream_port = dsa_upstream_port(ds);
|
||||
int ret;
|
||||
int i;
|
||||
u32 reg;
|
||||
|
||||
ret = mv88e6xxx_setup_global(ds);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* Enable the PHY polling unit, don't discard packets with
|
||||
* excessive collisions, use a weighted fair queueing scheme
|
||||
* to arbitrate between packet queues, set the maximum frame
|
||||
* size to 1632, and mask all interrupt sources.
|
||||
*/
|
||||
REG_WRITE(REG_GLOBAL, 0x04, 0x4400);
|
||||
|
||||
/* Set the default address aging time to 5 minutes, and
|
||||
* enable address learn messages to be sent to all message
|
||||
* ports.
|
||||
*/
|
||||
REG_WRITE(REG_GLOBAL, 0x0a, 0x0148);
|
||||
|
||||
/* Configure the priority mapping registers. */
|
||||
ret = mv88e6xxx_config_prio(ds);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
REG_WRITE(REG_GLOBAL, GLOBAL_CONTROL,
|
||||
GLOBAL_CONTROL_PPU_ENABLE | GLOBAL_CONTROL_MAX_FRAME_1632);
|
||||
|
||||
/* Set the VLAN ethertype to 0x8100. */
|
||||
REG_WRITE(REG_GLOBAL, 0x19, 0x8100);
|
||||
REG_WRITE(REG_GLOBAL, GLOBAL_CORE_TAG_TYPE, 0x8100);
|
||||
|
||||
/* Disable ARP mirroring, and configure the upstream port as
|
||||
* the port to which ingress and egress monitor frames are to
|
||||
* be sent.
|
||||
*/
|
||||
REG_WRITE(REG_GLOBAL, 0x1a, (dsa_upstream_port(ds) * 0x1100) | 0x00f0);
|
||||
reg = upstream_port << GLOBAL_MONITOR_CONTROL_INGRESS_SHIFT |
|
||||
upstream_port << GLOBAL_MONITOR_CONTROL_EGRESS_SHIFT |
|
||||
GLOBAL_MONITOR_CONTROL_ARP_DISABLED;
|
||||
REG_WRITE(REG_GLOBAL, GLOBAL_MONITOR_CONTROL, reg);
|
||||
|
||||
/* Disable cascade port functionality unless this device
|
||||
* is used in a cascade configuration, and set the switch's
|
||||
* DSA device number.
|
||||
*/
|
||||
if (ds->dst->pd->nr_chips > 1)
|
||||
REG_WRITE(REG_GLOBAL, 0x1c, 0xf000 | (ds->index & 0x1f));
|
||||
REG_WRITE(REG_GLOBAL, GLOBAL_CONTROL_2,
|
||||
GLOBAL_CONTROL_2_MULTIPLE_CASCADE |
|
||||
(ds->index & 0x1f));
|
||||
else
|
||||
REG_WRITE(REG_GLOBAL, 0x1c, 0xe000 | (ds->index & 0x1f));
|
||||
|
||||
/* Send all frames with destination addresses matching
|
||||
* 01:80:c2:00:00:0x to the CPU port.
|
||||
*/
|
||||
REG_WRITE(REG_GLOBAL2, 0x03, 0xffff);
|
||||
|
||||
/* Ignore removed tag data on doubly tagged packets, disable
|
||||
* flow control messages, force flow control priority to the
|
||||
* highest, and send all special multicast frames to the CPU
|
||||
* port at the highest priority.
|
||||
*/
|
||||
REG_WRITE(REG_GLOBAL2, 0x05, 0x00ff);
|
||||
|
||||
/* Program the DSA routing table. */
|
||||
for (i = 0; i < 32; i++) {
|
||||
int nexthop;
|
||||
|
||||
nexthop = 0x1f;
|
||||
if (ds->pd->rtable &&
|
||||
i != ds->index && i < ds->dst->pd->nr_chips)
|
||||
nexthop = ds->pd->rtable[i] & 0x1f;
|
||||
|
||||
REG_WRITE(REG_GLOBAL2, 0x06, 0x8000 | (i << 8) | nexthop);
|
||||
}
|
||||
|
||||
/* Clear all trunk masks. */
|
||||
for (i = 0; i < 8; i++)
|
||||
REG_WRITE(REG_GLOBAL2, 0x07, 0x8000 | (i << 12) | 0x7ff);
|
||||
|
||||
/* Clear all trunk mappings. */
|
||||
for (i = 0; i < 16; i++)
|
||||
REG_WRITE(REG_GLOBAL2, 0x08, 0x8000 | (i << 11));
|
||||
REG_WRITE(REG_GLOBAL, GLOBAL_CONTROL_2,
|
||||
GLOBAL_CONTROL_2_NO_CASCADE |
|
||||
(ds->index & 0x1f));
|
||||
|
||||
/* Force the priority of IGMP/MLD snoop frames and ARP frames
|
||||
* to the highest setting.
|
||||
*/
|
||||
REG_WRITE(REG_GLOBAL2, 0x0f, 0x00ff);
|
||||
REG_WRITE(REG_GLOBAL2, GLOBAL2_PRIO_OVERRIDE,
|
||||
GLOBAL2_PRIO_OVERRIDE_FORCE_SNOOP |
|
||||
7 << GLOBAL2_PRIO_OVERRIDE_SNOOP_SHIFT |
|
||||
GLOBAL2_PRIO_OVERRIDE_FORCE_ARP |
|
||||
7 << GLOBAL2_PRIO_OVERRIDE_ARP_SHIFT);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mv88e6131_setup_port(struct dsa_switch *ds, int p)
|
||||
{
|
||||
struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
|
||||
int addr = REG_PORT(p);
|
||||
u16 val;
|
||||
|
||||
/* MAC Forcing register: don't force link, speed, duplex
|
||||
* or flow control state to any particular values on physical
|
||||
* ports, but force the CPU port and all DSA ports to 1000 Mb/s
|
||||
* (100 Mb/s on 6085) full duplex.
|
||||
*/
|
||||
if (dsa_is_cpu_port(ds, p) || ds->dsa_port_mask & (1 << p))
|
||||
if (ps->id == PORT_SWITCH_ID_6085)
|
||||
REG_WRITE(addr, 0x01, 0x003d); /* 100 Mb/s */
|
||||
else
|
||||
REG_WRITE(addr, 0x01, 0x003e); /* 1000 Mb/s */
|
||||
else
|
||||
REG_WRITE(addr, 0x01, 0x0003);
|
||||
|
||||
/* Port Control: disable Core Tag, disable Drop-on-Lock,
|
||||
* transmit frames unmodified, disable Header mode,
|
||||
* enable IGMP/MLD snoop, disable DoubleTag, disable VLAN
|
||||
* tunneling, determine priority by looking at 802.1p and
|
||||
* IP priority fields (IP prio has precedence), and set STP
|
||||
* state to Forwarding.
|
||||
*
|
||||
* If this is the upstream port for this switch, enable
|
||||
* forwarding of unknown unicasts, and enable DSA tagging
|
||||
* mode.
|
||||
*
|
||||
* If this is the link to another switch, use DSA tagging
|
||||
* mode, but do not enable forwarding of unknown unicasts.
|
||||
*/
|
||||
val = 0x0433;
|
||||
if (p == dsa_upstream_port(ds)) {
|
||||
val |= 0x0104;
|
||||
/* On 6085, unknown multicast forward is controlled
|
||||
* here rather than in Port Control 2 register.
|
||||
*/
|
||||
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 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
|
||||
* add or strip 802.1q tags, don't discard tagged or
|
||||
* untagged frames on this port, do a destination address
|
||||
* lookup on received packets as usual, don't send a copy
|
||||
* of all transmitted/received frames on this port to the
|
||||
* CPU, and configure the upstream port number.
|
||||
*
|
||||
* If this is the upstream port for this switch, enable
|
||||
* forwarding of unknown multicast addresses.
|
||||
*/
|
||||
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.
|
||||
*/
|
||||
REG_WRITE(addr, 0x08, 0x0080);
|
||||
else {
|
||||
val = 0x0080 | dsa_upstream_port(ds);
|
||||
if (p == dsa_upstream_port(ds))
|
||||
val |= 0x0040;
|
||||
REG_WRITE(addr, 0x08, val);
|
||||
}
|
||||
|
||||
/* Rate Control: disable ingress rate limiting. */
|
||||
REG_WRITE(addr, 0x09, 0x0000);
|
||||
|
||||
/* Rate Control 2: disable egress rate limiting. */
|
||||
REG_WRITE(addr, 0x0a, 0x0000);
|
||||
|
||||
/* Port Association Vector: when learning source addresses
|
||||
* of packets, add the address to the address database using
|
||||
* a port bitmap that has only the bit for this port set and
|
||||
* the other bits clear.
|
||||
*/
|
||||
REG_WRITE(addr, 0x0b, 1 << p);
|
||||
|
||||
/* Tag Remap: use an identity 802.1p prio -> switch prio
|
||||
* mapping.
|
||||
*/
|
||||
REG_WRITE(addr, 0x18, 0x3210);
|
||||
|
||||
/* Tag Remap 2: use an identity 802.1p prio -> switch prio
|
||||
* mapping.
|
||||
*/
|
||||
REG_WRITE(addr, 0x19, 0x7654);
|
||||
|
||||
return mv88e6xxx_setup_port_common(ds, p);
|
||||
}
|
||||
|
||||
static int mv88e6131_setup(struct dsa_switch *ds)
|
||||
{
|
||||
struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
|
||||
int i;
|
||||
int ret;
|
||||
|
||||
ret = mv88e6xxx_setup_common(ds);
|
||||
|
@ -234,6 +112,7 @@ static int mv88e6131_setup(struct dsa_switch *ds)
|
|||
|
||||
switch (ps->id) {
|
||||
case PORT_SWITCH_ID_6085:
|
||||
case PORT_SWITCH_ID_6185:
|
||||
ps->num_ports = 10;
|
||||
break;
|
||||
case PORT_SWITCH_ID_6095:
|
||||
|
@ -251,19 +130,11 @@ static int mv88e6131_setup(struct dsa_switch *ds)
|
|||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
/* @@@ initialise vtu and atu */
|
||||
|
||||
ret = mv88e6131_setup_global(ds);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
for (i = 0; i < ps->num_ports; i++) {
|
||||
ret = mv88e6131_setup_port(ds, i);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
return mv88e6xxx_setup_ports(ds);
|
||||
}
|
||||
|
||||
static int mv88e6131_port_to_phy_addr(struct dsa_switch *ds, int port)
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* net/dsa/mv88e6171.c - Marvell 88e6171/8826172 switch chip support
|
||||
/* net/dsa/mv88e6171.c - Marvell 88e6171 switch chip support
|
||||
* Copyright (c) 2008-2009 Marvell Semiconductor
|
||||
* Copyright (c) 2014 Claudio Leite <leitec@staticky.com>
|
||||
*
|
||||
|
@ -29,8 +29,12 @@ static char *mv88e6171_probe(struct device *host_dev, int sw_addr)
|
|||
if (ret >= 0) {
|
||||
if ((ret & 0xfff0) == PORT_SWITCH_ID_6171)
|
||||
return "Marvell 88E6171";
|
||||
if ((ret & 0xfff0) == PORT_SWITCH_ID_6172)
|
||||
return "Marvell 88E6172";
|
||||
if ((ret & 0xfff0) == PORT_SWITCH_ID_6175)
|
||||
return "Marvell 88E6175";
|
||||
if ((ret & 0xfff0) == PORT_SWITCH_ID_6350)
|
||||
return "Marvell 88E6350";
|
||||
if ((ret & 0xfff0) == PORT_SWITCH_ID_6351)
|
||||
return "Marvell 88E6351";
|
||||
}
|
||||
|
||||
return NULL;
|
||||
|
@ -38,196 +42,41 @@ static char *mv88e6171_probe(struct device *host_dev, int sw_addr)
|
|||
|
||||
static int mv88e6171_setup_global(struct dsa_switch *ds)
|
||||
{
|
||||
struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
|
||||
u32 upstream_port = dsa_upstream_port(ds);
|
||||
int ret;
|
||||
int i;
|
||||
u32 reg;
|
||||
|
||||
ret = mv88e6xxx_setup_global(ds);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* Discard packets with excessive collisions, mask all
|
||||
* interrupt sources, enable PPU.
|
||||
*/
|
||||
REG_WRITE(REG_GLOBAL, 0x04, 0x6000);
|
||||
|
||||
/* Set the default address aging time to 5 minutes, and
|
||||
* enable address learn messages to be sent to all message
|
||||
* ports.
|
||||
*/
|
||||
REG_WRITE(REG_GLOBAL, 0x0a, 0x0148);
|
||||
|
||||
/* Configure the priority mapping registers. */
|
||||
ret = mv88e6xxx_config_prio(ds);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
REG_WRITE(REG_GLOBAL, GLOBAL_CONTROL,
|
||||
GLOBAL_CONTROL_PPU_ENABLE | GLOBAL_CONTROL_DISCARD_EXCESS);
|
||||
|
||||
/* Configure the upstream port, and configure the upstream
|
||||
* port as the port to which ingress and egress monitor frames
|
||||
* are to be sent.
|
||||
*/
|
||||
if (REG_READ(REG_PORT(0), 0x03) == 0x1710)
|
||||
REG_WRITE(REG_GLOBAL, 0x1a, (dsa_upstream_port(ds) * 0x1111));
|
||||
else
|
||||
REG_WRITE(REG_GLOBAL, 0x1a, (dsa_upstream_port(ds) * 0x1110));
|
||||
reg = upstream_port << GLOBAL_MONITOR_CONTROL_INGRESS_SHIFT |
|
||||
upstream_port << GLOBAL_MONITOR_CONTROL_EGRESS_SHIFT |
|
||||
upstream_port << GLOBAL_MONITOR_CONTROL_ARP_SHIFT |
|
||||
upstream_port << GLOBAL_MONITOR_CONTROL_MIRROR_SHIFT;
|
||||
REG_WRITE(REG_GLOBAL, GLOBAL_MONITOR_CONTROL, reg);
|
||||
|
||||
/* Disable remote management for now, and set the switch's
|
||||
* DSA device number.
|
||||
*/
|
||||
REG_WRITE(REG_GLOBAL, 0x1c, ds->index & 0x1f);
|
||||
|
||||
/* Send all frames with destination addresses matching
|
||||
* 01:80:c2:00:00:2x to the CPU port.
|
||||
*/
|
||||
REG_WRITE(REG_GLOBAL2, 0x02, 0xffff);
|
||||
|
||||
/* Send all frames with destination addresses matching
|
||||
* 01:80:c2:00:00:0x to the CPU port.
|
||||
*/
|
||||
REG_WRITE(REG_GLOBAL2, 0x03, 0xffff);
|
||||
|
||||
/* Disable the loopback filter, disable flow control
|
||||
* messages, disable flood broadcast override, disable
|
||||
* removing of provider tags, disable ATU age violation
|
||||
* interrupts, disable tag flow control, force flow
|
||||
* control priority to the highest, and send all special
|
||||
* multicast frames to the CPU at the highest priority.
|
||||
*/
|
||||
REG_WRITE(REG_GLOBAL2, 0x05, 0x00ff);
|
||||
|
||||
/* Program the DSA routing table. */
|
||||
for (i = 0; i < 32; i++) {
|
||||
int nexthop;
|
||||
|
||||
nexthop = 0x1f;
|
||||
if (i != ds->index && i < ds->dst->pd->nr_chips)
|
||||
nexthop = ds->pd->rtable[i] & 0x1f;
|
||||
|
||||
REG_WRITE(REG_GLOBAL2, 0x06, 0x8000 | (i << 8) | nexthop);
|
||||
}
|
||||
|
||||
/* Clear all trunk masks. */
|
||||
for (i = 0; i < ps->num_ports; i++)
|
||||
REG_WRITE(REG_GLOBAL2, 0x07, 0x8000 | (i << 12) | 0xff);
|
||||
|
||||
/* Clear all trunk mappings. */
|
||||
for (i = 0; i < 16; i++)
|
||||
REG_WRITE(REG_GLOBAL2, 0x08, 0x8000 | (i << 11));
|
||||
|
||||
/* Disable ingress rate limiting by resetting all ingress
|
||||
* rate limit registers to their initial state.
|
||||
*/
|
||||
for (i = 0; i < 6; i++)
|
||||
REG_WRITE(REG_GLOBAL2, 0x09, 0x9000 | (i << 8));
|
||||
|
||||
/* Initialise cross-chip port VLAN table to reset defaults. */
|
||||
REG_WRITE(REG_GLOBAL2, 0x0b, 0x9000);
|
||||
|
||||
/* Clear the priority override table. */
|
||||
for (i = 0; i < 16; i++)
|
||||
REG_WRITE(REG_GLOBAL2, 0x0f, 0x8000 | (i << 8));
|
||||
|
||||
/* @@@ initialise AVB (22/23) watchdog (27) sdet (29) registers */
|
||||
REG_WRITE(REG_GLOBAL, GLOBAL_CONTROL_2, ds->index & 0x1f);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mv88e6171_setup_port(struct dsa_switch *ds, int p)
|
||||
{
|
||||
int addr = REG_PORT(p);
|
||||
u16 val;
|
||||
|
||||
/* MAC Forcing register: don't force link, speed, duplex
|
||||
* or flow control state to any particular values on physical
|
||||
* ports, but force the CPU port and all DSA ports to 1000 Mb/s
|
||||
* full duplex.
|
||||
*/
|
||||
val = REG_READ(addr, 0x01);
|
||||
if (dsa_is_cpu_port(ds, p) || ds->dsa_port_mask & (1 << p))
|
||||
REG_WRITE(addr, 0x01, val | 0x003e);
|
||||
else
|
||||
REG_WRITE(addr, 0x01, val | 0x0003);
|
||||
|
||||
/* Do not limit the period of time that this port can be
|
||||
* paused for by the remote end or the period of time that
|
||||
* this port can pause the remote end.
|
||||
*/
|
||||
REG_WRITE(addr, 0x02, 0x0000);
|
||||
|
||||
/* Port Control: disable Drop-on-Unlock, disable Drop-on-Lock,
|
||||
* disable Header mode, enable IGMP/MLD snooping, disable VLAN
|
||||
* tunneling, determine priority by looking at 802.1p and IP
|
||||
* priority fields (IP prio has precedence), and set STP state
|
||||
* to Forwarding.
|
||||
*
|
||||
* If this is the CPU link, use DSA or EDSA tagging depending
|
||||
* on which tagging mode was configured.
|
||||
*
|
||||
* If this is a link to another switch, use DSA tagging mode.
|
||||
*
|
||||
* If this is the upstream port for this switch, enable
|
||||
* forwarding of unknown unicasts and multicasts.
|
||||
*/
|
||||
val = 0x0433;
|
||||
if (dsa_is_cpu_port(ds, p)) {
|
||||
if (ds->dst->tag_protocol == DSA_TAG_PROTO_EDSA)
|
||||
val |= 0x3300;
|
||||
else
|
||||
val |= 0x0100;
|
||||
}
|
||||
if (ds->dsa_port_mask & (1 << p))
|
||||
val |= 0x0100;
|
||||
if (p == dsa_upstream_port(ds))
|
||||
val |= 0x000c;
|
||||
REG_WRITE(addr, 0x04, val);
|
||||
|
||||
/* 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
|
||||
* on this port, do a destination address lookup on all
|
||||
* received packets as usual, disable ARP mirroring and don't
|
||||
* send a copy of all transmitted/received frames on this port
|
||||
* to the CPU.
|
||||
*/
|
||||
REG_WRITE(addr, 0x08, 0x2080);
|
||||
|
||||
/* Egress rate control: disable egress rate control. */
|
||||
REG_WRITE(addr, 0x09, 0x0001);
|
||||
|
||||
/* Egress rate control 2: disable egress rate control. */
|
||||
REG_WRITE(addr, 0x0a, 0x0000);
|
||||
|
||||
/* Port Association Vector: when learning source addresses
|
||||
* of packets, add the address to the address database using
|
||||
* a port bitmap that has only the bit for this port set and
|
||||
* the other bits clear.
|
||||
*/
|
||||
REG_WRITE(addr, 0x0b, 1 << p);
|
||||
|
||||
/* Port ATU control: disable limiting the number of address
|
||||
* database entries that this port is allowed to use.
|
||||
*/
|
||||
REG_WRITE(addr, 0x0c, 0x0000);
|
||||
|
||||
/* Priority Override: disable DA, SA and VTU priority override. */
|
||||
REG_WRITE(addr, 0x0d, 0x0000);
|
||||
|
||||
/* Port Ethertype: use the Ethertype DSA Ethertype value. */
|
||||
REG_WRITE(addr, 0x0f, ETH_P_EDSA);
|
||||
|
||||
/* Tag Remap: use an identity 802.1p prio -> switch prio
|
||||
* mapping.
|
||||
*/
|
||||
REG_WRITE(addr, 0x18, 0x3210);
|
||||
|
||||
/* Tag Remap 2: use an identity 802.1p prio -> switch prio
|
||||
* mapping.
|
||||
*/
|
||||
REG_WRITE(addr, 0x19, 0x7654);
|
||||
|
||||
return mv88e6xxx_setup_port_common(ds, p);
|
||||
}
|
||||
|
||||
static int mv88e6171_setup(struct dsa_switch *ds)
|
||||
{
|
||||
struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
|
||||
int i;
|
||||
int ret;
|
||||
|
||||
ret = mv88e6xxx_setup_common(ds);
|
||||
|
@ -240,44 +89,11 @@ static int mv88e6171_setup(struct dsa_switch *ds)
|
|||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
/* @@@ initialise vtu and atu */
|
||||
|
||||
ret = mv88e6171_setup_global(ds);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
for (i = 0; i < ps->num_ports; i++) {
|
||||
if (!(dsa_is_cpu_port(ds, i) || ds->phys_port_mask & (1 << i)))
|
||||
continue;
|
||||
|
||||
ret = mv88e6171_setup_port(ds, i);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
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 == PORT_SWITCH_ID_6172)
|
||||
return mv88e6xxx_get_eee(ds, port, e);
|
||||
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
static int mv88e6171_set_eee(struct dsa_switch *ds, int port,
|
||||
struct phy_device *phydev, struct ethtool_eee *e)
|
||||
{
|
||||
struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
|
||||
|
||||
if (ps->id == PORT_SWITCH_ID_6172)
|
||||
return mv88e6xxx_set_eee(ds, port, phydev, e);
|
||||
|
||||
return -EOPNOTSUPP;
|
||||
return mv88e6xxx_setup_ports(ds);
|
||||
}
|
||||
|
||||
struct dsa_switch_driver mv88e6171_switch_driver = {
|
||||
|
@ -292,8 +108,6 @@ struct dsa_switch_driver mv88e6171_switch_driver = {
|
|||
.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
|
||||
.get_temp = mv88e6xxx_get_temp,
|
||||
#endif
|
||||
|
@ -308,4 +122,6 @@ struct dsa_switch_driver mv88e6171_switch_driver = {
|
|||
};
|
||||
|
||||
MODULE_ALIAS("platform:mv88e6171");
|
||||
MODULE_ALIAS("platform:mv88e6172");
|
||||
MODULE_ALIAS("platform:mv88e6175");
|
||||
MODULE_ALIAS("platform:mv88e6350");
|
||||
MODULE_ALIAS("platform:mv88e6351");
|
||||
|
|
|
@ -32,6 +32,8 @@ static char *mv88e6352_probe(struct device *host_dev, int sw_addr)
|
|||
|
||||
ret = __mv88e6xxx_reg_read(bus, sw_addr, REG_PORT(0), PORT_SWITCH_ID);
|
||||
if (ret >= 0) {
|
||||
if ((ret & 0xfff0) == PORT_SWITCH_ID_6172)
|
||||
return "Marvell 88E6172";
|
||||
if ((ret & 0xfff0) == PORT_SWITCH_ID_6176)
|
||||
return "Marvell 88E6176";
|
||||
if (ret == PORT_SWITCH_ID_6352_A0)
|
||||
|
@ -47,187 +49,37 @@ static char *mv88e6352_probe(struct device *host_dev, int sw_addr)
|
|||
|
||||
static int mv88e6352_setup_global(struct dsa_switch *ds)
|
||||
{
|
||||
struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
|
||||
u32 upstream_port = dsa_upstream_port(ds);
|
||||
int ret;
|
||||
int i;
|
||||
u32 reg;
|
||||
|
||||
ret = mv88e6xxx_setup_global(ds);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* Discard packets with excessive collisions,
|
||||
* mask all interrupt sources, enable PPU (bit 14, undocumented).
|
||||
*/
|
||||
REG_WRITE(REG_GLOBAL, 0x04, 0x6000);
|
||||
|
||||
/* Set the default address aging time to 5 minutes, and
|
||||
* enable address learn messages to be sent to all message
|
||||
* ports.
|
||||
*/
|
||||
REG_WRITE(REG_GLOBAL, 0x0a, 0x0148);
|
||||
|
||||
/* Configure the priority mapping registers. */
|
||||
ret = mv88e6xxx_config_prio(ds);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
REG_WRITE(REG_GLOBAL, GLOBAL_CONTROL,
|
||||
GLOBAL_CONTROL_PPU_ENABLE | GLOBAL_CONTROL_DISCARD_EXCESS);
|
||||
|
||||
/* Configure the upstream port, and configure the upstream
|
||||
* port as the port to which ingress and egress monitor frames
|
||||
* are to be sent.
|
||||
*/
|
||||
REG_WRITE(REG_GLOBAL, 0x1a, (dsa_upstream_port(ds) * 0x1110));
|
||||
reg = upstream_port << GLOBAL_MONITOR_CONTROL_INGRESS_SHIFT |
|
||||
upstream_port << GLOBAL_MONITOR_CONTROL_EGRESS_SHIFT |
|
||||
upstream_port << GLOBAL_MONITOR_CONTROL_ARP_SHIFT;
|
||||
REG_WRITE(REG_GLOBAL, GLOBAL_MONITOR_CONTROL, reg);
|
||||
|
||||
/* Disable remote management for now, and set the switch's
|
||||
* DSA device number.
|
||||
*/
|
||||
REG_WRITE(REG_GLOBAL, 0x1c, ds->index & 0x1f);
|
||||
|
||||
/* Send all frames with destination addresses matching
|
||||
* 01:80:c2:00:00:2x to the CPU port.
|
||||
*/
|
||||
REG_WRITE(REG_GLOBAL2, 0x02, 0xffff);
|
||||
|
||||
/* Send all frames with destination addresses matching
|
||||
* 01:80:c2:00:00:0x to the CPU port.
|
||||
*/
|
||||
REG_WRITE(REG_GLOBAL2, 0x03, 0xffff);
|
||||
|
||||
/* Disable the loopback filter, disable flow control
|
||||
* messages, disable flood broadcast override, disable
|
||||
* removing of provider tags, disable ATU age violation
|
||||
* interrupts, disable tag flow control, force flow
|
||||
* control priority to the highest, and send all special
|
||||
* multicast frames to the CPU at the highest priority.
|
||||
*/
|
||||
REG_WRITE(REG_GLOBAL2, 0x05, 0x00ff);
|
||||
|
||||
/* Program the DSA routing table. */
|
||||
for (i = 0; i < 32; i++) {
|
||||
int nexthop = 0x1f;
|
||||
|
||||
if (i != ds->index && i < ds->dst->pd->nr_chips)
|
||||
nexthop = ds->pd->rtable[i] & 0x1f;
|
||||
|
||||
REG_WRITE(REG_GLOBAL2, 0x06, 0x8000 | (i << 8) | nexthop);
|
||||
}
|
||||
|
||||
/* Clear all trunk masks. */
|
||||
for (i = 0; i < 8; i++)
|
||||
REG_WRITE(REG_GLOBAL2, 0x07, 0x8000 | (i << 12) | 0x7f);
|
||||
|
||||
/* Clear all trunk mappings. */
|
||||
for (i = 0; i < 16; i++)
|
||||
REG_WRITE(REG_GLOBAL2, 0x08, 0x8000 | (i << 11));
|
||||
|
||||
/* Disable ingress rate limiting by resetting all ingress
|
||||
* rate limit registers to their initial state.
|
||||
*/
|
||||
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. */
|
||||
REG_WRITE(REG_GLOBAL2, 0x0b, 0x9000);
|
||||
|
||||
/* Clear the priority override table. */
|
||||
for (i = 0; i < 16; i++)
|
||||
REG_WRITE(REG_GLOBAL2, 0x0f, 0x8000 | (i << 8));
|
||||
|
||||
/* @@@ initialise AVB (22/23) watchdog (27) sdet (29) registers */
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mv88e6352_setup_port(struct dsa_switch *ds, int p)
|
||||
{
|
||||
int addr = REG_PORT(p);
|
||||
u16 val;
|
||||
|
||||
/* MAC Forcing register: don't force link, speed, duplex
|
||||
* or flow control state to any particular values on physical
|
||||
* ports, but force the CPU port and all DSA ports to 1000 Mb/s
|
||||
* full duplex.
|
||||
*/
|
||||
if (dsa_is_cpu_port(ds, p) || ds->dsa_port_mask & (1 << p))
|
||||
REG_WRITE(addr, 0x01, 0x003e);
|
||||
else
|
||||
REG_WRITE(addr, 0x01, 0x0003);
|
||||
|
||||
/* Do not limit the period of time that this port can be
|
||||
* paused for by the remote end or the period of time that
|
||||
* this port can pause the remote end.
|
||||
*/
|
||||
REG_WRITE(addr, 0x02, 0x0000);
|
||||
|
||||
/* Port Control: disable Drop-on-Unlock, disable Drop-on-Lock,
|
||||
* disable Header mode, enable IGMP/MLD snooping, disable VLAN
|
||||
* tunneling, determine priority by looking at 802.1p and IP
|
||||
* priority fields (IP prio has precedence), and set STP state
|
||||
* to Forwarding.
|
||||
*
|
||||
* If this is the CPU link, use DSA or EDSA tagging depending
|
||||
* on which tagging mode was configured.
|
||||
*
|
||||
* If this is a link to another switch, use DSA tagging mode.
|
||||
*
|
||||
* If this is the upstream port for this switch, enable
|
||||
* forwarding of unknown unicasts and multicasts.
|
||||
*/
|
||||
val = 0x0433;
|
||||
if (dsa_is_cpu_port(ds, p)) {
|
||||
if (ds->dst->tag_protocol == DSA_TAG_PROTO_EDSA)
|
||||
val |= 0x3300;
|
||||
else
|
||||
val |= 0x0100;
|
||||
}
|
||||
if (ds->dsa_port_mask & (1 << p))
|
||||
val |= 0x0100;
|
||||
if (p == dsa_upstream_port(ds))
|
||||
val |= 0x000c;
|
||||
REG_WRITE(addr, 0x04, val);
|
||||
|
||||
/* 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
|
||||
* on this port, do a destination address lookup on all
|
||||
* received packets as usual, disable ARP mirroring and don't
|
||||
* send a copy of all transmitted/received frames on this port
|
||||
* to the CPU.
|
||||
*/
|
||||
REG_WRITE(addr, 0x08, 0x2080);
|
||||
|
||||
/* Egress rate control: disable egress rate control. */
|
||||
REG_WRITE(addr, 0x09, 0x0001);
|
||||
|
||||
/* Egress rate control 2: disable egress rate control. */
|
||||
REG_WRITE(addr, 0x0a, 0x0000);
|
||||
|
||||
/* Port Association Vector: when learning source addresses
|
||||
* of packets, add the address to the address database using
|
||||
* a port bitmap that has only the bit for this port set and
|
||||
* the other bits clear.
|
||||
*/
|
||||
REG_WRITE(addr, 0x0b, 1 << p);
|
||||
|
||||
/* Port ATU control: disable limiting the number of address
|
||||
* database entries that this port is allowed to use.
|
||||
*/
|
||||
REG_WRITE(addr, 0x0c, 0x0000);
|
||||
|
||||
/* Priority Override: disable DA, SA and VTU priority override. */
|
||||
REG_WRITE(addr, 0x0d, 0x0000);
|
||||
|
||||
/* Port Ethertype: use the Ethertype DSA Ethertype value. */
|
||||
REG_WRITE(addr, 0x0f, ETH_P_EDSA);
|
||||
|
||||
/* Tag Remap: use an identity 802.1p prio -> switch prio
|
||||
* mapping.
|
||||
*/
|
||||
REG_WRITE(addr, 0x18, 0x3210);
|
||||
|
||||
/* Tag Remap 2: use an identity 802.1p prio -> switch prio
|
||||
* mapping.
|
||||
*/
|
||||
REG_WRITE(addr, 0x19, 0x7654);
|
||||
|
||||
return mv88e6xxx_setup_port_common(ds, p);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_NET_DSA_HWMON
|
||||
|
||||
static int mv88e6352_get_temp(struct dsa_switch *ds, int *temp)
|
||||
|
@ -292,7 +144,6 @@ static int mv88e6352_setup(struct dsa_switch *ds)
|
|||
{
|
||||
struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
|
||||
int ret;
|
||||
int i;
|
||||
|
||||
ret = mv88e6xxx_setup_common(ds);
|
||||
if (ret < 0)
|
||||
|
@ -306,19 +157,11 @@ static int mv88e6352_setup(struct dsa_switch *ds)
|
|||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
/* @@@ initialise vtu and atu */
|
||||
|
||||
ret = mv88e6352_setup_global(ds);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
for (i = 0; i < ps->num_ports; i++) {
|
||||
ret = mv88e6352_setup_port(ds, i);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
return mv88e6xxx_setup_ports(ds);
|
||||
}
|
||||
|
||||
static int mv88e6352_read_eeprom_word(struct dsa_switch *ds, int addr)
|
||||
|
@ -552,3 +395,4 @@ struct dsa_switch_driver mv88e6352_switch_driver = {
|
|||
};
|
||||
|
||||
MODULE_ALIAS("platform:mv88e6352");
|
||||
MODULE_ALIAS("platform:mv88e6172");
|
||||
|
|
|
@ -19,6 +19,34 @@
|
|||
#include <net/dsa.h>
|
||||
#include "mv88e6xxx.h"
|
||||
|
||||
/* MDIO bus access can be nested in the case of PHYs connected to the
|
||||
* internal MDIO bus of the switch, which is accessed via MDIO bus of
|
||||
* the Ethernet interface. Avoid lockdep false positives by using
|
||||
* mutex_lock_nested().
|
||||
*/
|
||||
static int mv88e6xxx_mdiobus_read(struct mii_bus *bus, int addr, u32 regnum)
|
||||
{
|
||||
int ret;
|
||||
|
||||
mutex_lock_nested(&bus->mdio_lock, SINGLE_DEPTH_NESTING);
|
||||
ret = bus->read(bus, addr, regnum);
|
||||
mutex_unlock(&bus->mdio_lock);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int mv88e6xxx_mdiobus_write(struct mii_bus *bus, int addr, u32 regnum,
|
||||
u16 val)
|
||||
{
|
||||
int ret;
|
||||
|
||||
mutex_lock_nested(&bus->mdio_lock, SINGLE_DEPTH_NESTING);
|
||||
ret = bus->write(bus, addr, regnum, val);
|
||||
mutex_unlock(&bus->mdio_lock);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* If the switch's ADDR[4:0] strap pins are strapped to zero, it will
|
||||
* use all 32 SMI bus addresses on its SMI bus, and all switch registers
|
||||
* will be directly accessible on some {device address,register address}
|
||||
|
@ -33,7 +61,7 @@ static int mv88e6xxx_reg_wait_ready(struct mii_bus *bus, int sw_addr)
|
|||
int i;
|
||||
|
||||
for (i = 0; i < 16; i++) {
|
||||
ret = mdiobus_read(bus, sw_addr, SMI_CMD);
|
||||
ret = mv88e6xxx_mdiobus_read(bus, sw_addr, SMI_CMD);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
|
@ -49,7 +77,7 @@ int __mv88e6xxx_reg_read(struct mii_bus *bus, int sw_addr, int addr, int reg)
|
|||
int ret;
|
||||
|
||||
if (sw_addr == 0)
|
||||
return mdiobus_read(bus, addr, reg);
|
||||
return mv88e6xxx_mdiobus_read(bus, addr, reg);
|
||||
|
||||
/* Wait for the bus to become free. */
|
||||
ret = mv88e6xxx_reg_wait_ready(bus, sw_addr);
|
||||
|
@ -57,8 +85,8 @@ int __mv88e6xxx_reg_read(struct mii_bus *bus, int sw_addr, int addr, int reg)
|
|||
return ret;
|
||||
|
||||
/* Transmit the read command. */
|
||||
ret = mdiobus_write(bus, sw_addr, SMI_CMD,
|
||||
SMI_CMD_OP_22_READ | (addr << 5) | reg);
|
||||
ret = mv88e6xxx_mdiobus_write(bus, sw_addr, SMI_CMD,
|
||||
SMI_CMD_OP_22_READ | (addr << 5) | reg);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
|
@ -68,7 +96,7 @@ int __mv88e6xxx_reg_read(struct mii_bus *bus, int sw_addr, int addr, int reg)
|
|||
return ret;
|
||||
|
||||
/* Read the data. */
|
||||
ret = mdiobus_read(bus, sw_addr, SMI_DATA);
|
||||
ret = mv88e6xxx_mdiobus_read(bus, sw_addr, SMI_DATA);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
|
@ -112,7 +140,7 @@ int __mv88e6xxx_reg_write(struct mii_bus *bus, int sw_addr, int addr,
|
|||
int ret;
|
||||
|
||||
if (sw_addr == 0)
|
||||
return mdiobus_write(bus, addr, reg, val);
|
||||
return mv88e6xxx_mdiobus_write(bus, addr, reg, val);
|
||||
|
||||
/* Wait for the bus to become free. */
|
||||
ret = mv88e6xxx_reg_wait_ready(bus, sw_addr);
|
||||
|
@ -120,13 +148,13 @@ int __mv88e6xxx_reg_write(struct mii_bus *bus, int sw_addr, int addr,
|
|||
return ret;
|
||||
|
||||
/* Transmit the data to write. */
|
||||
ret = mdiobus_write(bus, sw_addr, SMI_DATA, val);
|
||||
ret = mv88e6xxx_mdiobus_write(bus, sw_addr, SMI_DATA, val);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
/* Transmit the write command. */
|
||||
ret = mdiobus_write(bus, sw_addr, SMI_CMD,
|
||||
SMI_CMD_OP_22_WRITE | (addr << 5) | reg);
|
||||
ret = mv88e6xxx_mdiobus_write(bus, sw_addr, SMI_CMD,
|
||||
SMI_CMD_OP_22_WRITE | (addr << 5) | reg);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
|
@ -165,24 +193,6 @@ int mv88e6xxx_reg_write(struct dsa_switch *ds, int addr, int reg, u16 val)
|
|||
return ret;
|
||||
}
|
||||
|
||||
int mv88e6xxx_config_prio(struct dsa_switch *ds)
|
||||
{
|
||||
/* Configure the IP ToS mapping registers. */
|
||||
REG_WRITE(REG_GLOBAL, GLOBAL_IP_PRI_0, 0x0000);
|
||||
REG_WRITE(REG_GLOBAL, GLOBAL_IP_PRI_1, 0x0000);
|
||||
REG_WRITE(REG_GLOBAL, GLOBAL_IP_PRI_2, 0x5555);
|
||||
REG_WRITE(REG_GLOBAL, GLOBAL_IP_PRI_3, 0x5555);
|
||||
REG_WRITE(REG_GLOBAL, GLOBAL_IP_PRI_4, 0xaaaa);
|
||||
REG_WRITE(REG_GLOBAL, GLOBAL_IP_PRI_5, 0xaaaa);
|
||||
REG_WRITE(REG_GLOBAL, GLOBAL_IP_PRI_6, 0xffff);
|
||||
REG_WRITE(REG_GLOBAL, GLOBAL_IP_PRI_7, 0xffff);
|
||||
|
||||
/* Configure the IEEE 802.1p priority mapping register. */
|
||||
REG_WRITE(REG_GLOBAL, GLOBAL_IEEE_PRI, 0xfa41);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int mv88e6xxx_set_addr_direct(struct dsa_switch *ds, u8 *addr)
|
||||
{
|
||||
REG_WRITE(REG_GLOBAL, GLOBAL_MAC_01, (addr[0] << 8) | addr[1]);
|
||||
|
@ -217,20 +227,20 @@ int mv88e6xxx_set_addr_indirect(struct dsa_switch *ds, u8 *addr)
|
|||
return 0;
|
||||
}
|
||||
|
||||
/* Must be called with phy mutex held */
|
||||
/* Must be called with SMI mutex held */
|
||||
static int _mv88e6xxx_phy_read(struct dsa_switch *ds, int addr, int regnum)
|
||||
{
|
||||
if (addr >= 0)
|
||||
return mv88e6xxx_reg_read(ds, addr, regnum);
|
||||
return _mv88e6xxx_reg_read(ds, addr, regnum);
|
||||
return 0xffff;
|
||||
}
|
||||
|
||||
/* Must be called with phy mutex held */
|
||||
/* Must be called with SMI mutex held */
|
||||
static int _mv88e6xxx_phy_write(struct dsa_switch *ds, int addr, int regnum,
|
||||
u16 val)
|
||||
{
|
||||
if (addr >= 0)
|
||||
return mv88e6xxx_reg_write(ds, addr, regnum, val);
|
||||
return _mv88e6xxx_reg_write(ds, addr, regnum, val);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -434,26 +444,113 @@ void mv88e6xxx_poll_link(struct dsa_switch *ds)
|
|||
}
|
||||
}
|
||||
|
||||
static bool mv88e6xxx_6352_family(struct dsa_switch *ds)
|
||||
static bool mv88e6xxx_6065_family(struct dsa_switch *ds)
|
||||
{
|
||||
struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
|
||||
|
||||
switch (ps->id) {
|
||||
case PORT_SWITCH_ID_6352:
|
||||
case PORT_SWITCH_ID_6172:
|
||||
case PORT_SWITCH_ID_6176:
|
||||
case PORT_SWITCH_ID_6031:
|
||||
case PORT_SWITCH_ID_6061:
|
||||
case PORT_SWITCH_ID_6035:
|
||||
case PORT_SWITCH_ID_6065:
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static int mv88e6xxx_stats_wait(struct dsa_switch *ds)
|
||||
static bool mv88e6xxx_6095_family(struct dsa_switch *ds)
|
||||
{
|
||||
struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
|
||||
|
||||
switch (ps->id) {
|
||||
case PORT_SWITCH_ID_6092:
|
||||
case PORT_SWITCH_ID_6095:
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool mv88e6xxx_6097_family(struct dsa_switch *ds)
|
||||
{
|
||||
struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
|
||||
|
||||
switch (ps->id) {
|
||||
case PORT_SWITCH_ID_6046:
|
||||
case PORT_SWITCH_ID_6085:
|
||||
case PORT_SWITCH_ID_6096:
|
||||
case PORT_SWITCH_ID_6097:
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool mv88e6xxx_6165_family(struct dsa_switch *ds)
|
||||
{
|
||||
struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
|
||||
|
||||
switch (ps->id) {
|
||||
case PORT_SWITCH_ID_6123:
|
||||
case PORT_SWITCH_ID_6161:
|
||||
case PORT_SWITCH_ID_6165:
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool mv88e6xxx_6185_family(struct dsa_switch *ds)
|
||||
{
|
||||
struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
|
||||
|
||||
switch (ps->id) {
|
||||
case PORT_SWITCH_ID_6121:
|
||||
case PORT_SWITCH_ID_6122:
|
||||
case PORT_SWITCH_ID_6152:
|
||||
case PORT_SWITCH_ID_6155:
|
||||
case PORT_SWITCH_ID_6182:
|
||||
case PORT_SWITCH_ID_6185:
|
||||
case PORT_SWITCH_ID_6108:
|
||||
case PORT_SWITCH_ID_6131:
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool mv88e6xxx_6351_family(struct dsa_switch *ds)
|
||||
{
|
||||
struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
|
||||
|
||||
switch (ps->id) {
|
||||
case PORT_SWITCH_ID_6171:
|
||||
case PORT_SWITCH_ID_6175:
|
||||
case PORT_SWITCH_ID_6350:
|
||||
case PORT_SWITCH_ID_6351:
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool mv88e6xxx_6352_family(struct dsa_switch *ds)
|
||||
{
|
||||
struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
|
||||
|
||||
switch (ps->id) {
|
||||
case PORT_SWITCH_ID_6172:
|
||||
case PORT_SWITCH_ID_6176:
|
||||
case PORT_SWITCH_ID_6240:
|
||||
case PORT_SWITCH_ID_6352:
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Must be called with SMI mutex held */
|
||||
static int _mv88e6xxx_stats_wait(struct dsa_switch *ds)
|
||||
{
|
||||
int ret;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < 10; i++) {
|
||||
ret = REG_READ(REG_GLOBAL, GLOBAL_STATS_OP);
|
||||
ret = _mv88e6xxx_reg_read(ds, REG_GLOBAL, GLOBAL_STATS_OP);
|
||||
if ((ret & GLOBAL_STATS_OP_BUSY) == 0)
|
||||
return 0;
|
||||
}
|
||||
|
@ -461,7 +558,8 @@ static int mv88e6xxx_stats_wait(struct dsa_switch *ds)
|
|||
return -ETIMEDOUT;
|
||||
}
|
||||
|
||||
static int mv88e6xxx_stats_snapshot(struct dsa_switch *ds, int port)
|
||||
/* Must be called with SMI mutex held */
|
||||
static int _mv88e6xxx_stats_snapshot(struct dsa_switch *ds, int port)
|
||||
{
|
||||
int ret;
|
||||
|
||||
|
@ -469,42 +567,45 @@ static int mv88e6xxx_stats_snapshot(struct dsa_switch *ds, int port)
|
|||
port = (port + 1) << 5;
|
||||
|
||||
/* Snapshot the hardware statistics counters for this port. */
|
||||
REG_WRITE(REG_GLOBAL, GLOBAL_STATS_OP,
|
||||
GLOBAL_STATS_OP_CAPTURE_PORT |
|
||||
GLOBAL_STATS_OP_HIST_RX_TX | port);
|
||||
ret = _mv88e6xxx_reg_write(ds, REG_GLOBAL, GLOBAL_STATS_OP,
|
||||
GLOBAL_STATS_OP_CAPTURE_PORT |
|
||||
GLOBAL_STATS_OP_HIST_RX_TX | port);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
/* Wait for the snapshotting to complete. */
|
||||
ret = mv88e6xxx_stats_wait(ds);
|
||||
ret = _mv88e6xxx_stats_wait(ds);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void mv88e6xxx_stats_read(struct dsa_switch *ds, int stat, u32 *val)
|
||||
/* Must be called with SMI mutex held */
|
||||
static void _mv88e6xxx_stats_read(struct dsa_switch *ds, int stat, u32 *val)
|
||||
{
|
||||
u32 _val;
|
||||
int ret;
|
||||
|
||||
*val = 0;
|
||||
|
||||
ret = mv88e6xxx_reg_write(ds, REG_GLOBAL, GLOBAL_STATS_OP,
|
||||
GLOBAL_STATS_OP_READ_CAPTURED |
|
||||
GLOBAL_STATS_OP_HIST_RX_TX | stat);
|
||||
ret = _mv88e6xxx_reg_write(ds, REG_GLOBAL, GLOBAL_STATS_OP,
|
||||
GLOBAL_STATS_OP_READ_CAPTURED |
|
||||
GLOBAL_STATS_OP_HIST_RX_TX | stat);
|
||||
if (ret < 0)
|
||||
return;
|
||||
|
||||
ret = mv88e6xxx_stats_wait(ds);
|
||||
ret = _mv88e6xxx_stats_wait(ds);
|
||||
if (ret < 0)
|
||||
return;
|
||||
|
||||
ret = mv88e6xxx_reg_read(ds, REG_GLOBAL, GLOBAL_STATS_COUNTER_32);
|
||||
ret = _mv88e6xxx_reg_read(ds, REG_GLOBAL, GLOBAL_STATS_COUNTER_32);
|
||||
if (ret < 0)
|
||||
return;
|
||||
|
||||
_val = ret << 16;
|
||||
|
||||
ret = mv88e6xxx_reg_read(ds, REG_GLOBAL, GLOBAL_STATS_COUNTER_01);
|
||||
ret = _mv88e6xxx_reg_read(ds, REG_GLOBAL, GLOBAL_STATS_COUNTER_01);
|
||||
if (ret < 0)
|
||||
return;
|
||||
|
||||
|
@ -587,11 +688,11 @@ static void _mv88e6xxx_get_ethtool_stats(struct dsa_switch *ds,
|
|||
int ret;
|
||||
int i;
|
||||
|
||||
mutex_lock(&ps->stats_mutex);
|
||||
mutex_lock(&ps->smi_mutex);
|
||||
|
||||
ret = mv88e6xxx_stats_snapshot(ds, port);
|
||||
ret = _mv88e6xxx_stats_snapshot(ds, port);
|
||||
if (ret < 0) {
|
||||
mutex_unlock(&ps->stats_mutex);
|
||||
mutex_unlock(&ps->smi_mutex);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -608,8 +709,8 @@ static void _mv88e6xxx_get_ethtool_stats(struct dsa_switch *ds,
|
|||
goto error;
|
||||
low = ret;
|
||||
if (s->sizeof_stat == 4) {
|
||||
ret = mv88e6xxx_reg_read(ds, REG_PORT(port),
|
||||
s->reg - 0x100 + 1);
|
||||
ret = _mv88e6xxx_reg_read(ds, REG_PORT(port),
|
||||
s->reg - 0x100 + 1);
|
||||
if (ret < 0)
|
||||
goto error;
|
||||
high = ret;
|
||||
|
@ -617,14 +718,14 @@ static void _mv88e6xxx_get_ethtool_stats(struct dsa_switch *ds,
|
|||
data[i] = (((u64)high) << 16) | low;
|
||||
continue;
|
||||
}
|
||||
mv88e6xxx_stats_read(ds, s->reg, &low);
|
||||
_mv88e6xxx_stats_read(ds, s->reg, &low);
|
||||
if (s->sizeof_stat == 8)
|
||||
mv88e6xxx_stats_read(ds, s->reg + 1, &high);
|
||||
_mv88e6xxx_stats_read(ds, s->reg + 1, &high);
|
||||
|
||||
data[i] = (((u64)high) << 32) | low;
|
||||
}
|
||||
error:
|
||||
mutex_unlock(&ps->stats_mutex);
|
||||
mutex_unlock(&ps->smi_mutex);
|
||||
}
|
||||
|
||||
/* All the statistics in the table */
|
||||
|
@ -694,7 +795,7 @@ int mv88e6xxx_get_temp(struct dsa_switch *ds, int *temp)
|
|||
|
||||
*temp = 0;
|
||||
|
||||
mutex_lock(&ps->phy_mutex);
|
||||
mutex_lock(&ps->smi_mutex);
|
||||
|
||||
ret = _mv88e6xxx_phy_write(ds, 0x0, 0x16, 0x6);
|
||||
if (ret < 0)
|
||||
|
@ -727,47 +828,14 @@ int mv88e6xxx_get_temp(struct dsa_switch *ds, int *temp)
|
|||
|
||||
error:
|
||||
_mv88e6xxx_phy_write(ds, 0x0, 0x16, 0x0);
|
||||
mutex_unlock(&ps->phy_mutex);
|
||||
mutex_unlock(&ps->smi_mutex);
|
||||
return ret;
|
||||
}
|
||||
#endif /* CONFIG_NET_DSA_HWMON */
|
||||
|
||||
static int mv88e6xxx_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;
|
||||
}
|
||||
|
||||
int mv88e6xxx_phy_wait(struct dsa_switch *ds)
|
||||
{
|
||||
return mv88e6xxx_wait(ds, REG_GLOBAL2, GLOBAL2_SMI_OP,
|
||||
GLOBAL2_SMI_OP_BUSY);
|
||||
}
|
||||
|
||||
int mv88e6xxx_eeprom_load_wait(struct dsa_switch *ds)
|
||||
{
|
||||
return mv88e6xxx_wait(ds, REG_GLOBAL2, GLOBAL2_EEPROM_OP,
|
||||
GLOBAL2_EEPROM_OP_LOAD);
|
||||
}
|
||||
|
||||
int mv88e6xxx_eeprom_busy_wait(struct dsa_switch *ds)
|
||||
{
|
||||
return mv88e6xxx_wait(ds, REG_GLOBAL2, GLOBAL2_EEPROM_OP,
|
||||
GLOBAL2_EEPROM_OP_BUSY);
|
||||
}
|
||||
|
||||
/* Must be called with SMI lock held */
|
||||
static int _mv88e6xxx_wait(struct dsa_switch *ds, int reg, int offset, u16 mask)
|
||||
static int _mv88e6xxx_wait(struct dsa_switch *ds, int reg, int offset,
|
||||
u16 mask)
|
||||
{
|
||||
unsigned long timeout = jiffies + HZ / 10;
|
||||
|
||||
|
@ -785,6 +853,36 @@ static int _mv88e6xxx_wait(struct dsa_switch *ds, int reg, int offset, u16 mask)
|
|||
return -ETIMEDOUT;
|
||||
}
|
||||
|
||||
static int mv88e6xxx_wait(struct dsa_switch *ds, int reg, int offset, u16 mask)
|
||||
{
|
||||
struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
|
||||
int ret;
|
||||
|
||||
mutex_lock(&ps->smi_mutex);
|
||||
ret = _mv88e6xxx_wait(ds, reg, offset, mask);
|
||||
mutex_unlock(&ps->smi_mutex);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int _mv88e6xxx_phy_wait(struct dsa_switch *ds)
|
||||
{
|
||||
return _mv88e6xxx_wait(ds, REG_GLOBAL2, GLOBAL2_SMI_OP,
|
||||
GLOBAL2_SMI_OP_BUSY);
|
||||
}
|
||||
|
||||
int mv88e6xxx_eeprom_load_wait(struct dsa_switch *ds)
|
||||
{
|
||||
return mv88e6xxx_wait(ds, REG_GLOBAL2, GLOBAL2_EEPROM_OP,
|
||||
GLOBAL2_EEPROM_OP_LOAD);
|
||||
}
|
||||
|
||||
int mv88e6xxx_eeprom_busy_wait(struct dsa_switch *ds)
|
||||
{
|
||||
return mv88e6xxx_wait(ds, REG_GLOBAL2, GLOBAL2_EEPROM_OP,
|
||||
GLOBAL2_EEPROM_OP_BUSY);
|
||||
}
|
||||
|
||||
/* Must be called with SMI lock held */
|
||||
static int _mv88e6xxx_atu_wait(struct dsa_switch *ds)
|
||||
{
|
||||
|
@ -792,31 +890,40 @@ static int _mv88e6xxx_atu_wait(struct dsa_switch *ds)
|
|||
GLOBAL_ATU_OP_BUSY);
|
||||
}
|
||||
|
||||
/* Must be called with phy mutex held */
|
||||
/* Must be called with SMI mutex held */
|
||||
static int _mv88e6xxx_phy_read_indirect(struct dsa_switch *ds, int addr,
|
||||
int regnum)
|
||||
{
|
||||
int ret;
|
||||
|
||||
REG_WRITE(REG_GLOBAL2, GLOBAL2_SMI_OP,
|
||||
GLOBAL2_SMI_OP_22_READ | (addr << 5) | regnum);
|
||||
|
||||
ret = mv88e6xxx_phy_wait(ds);
|
||||
ret = _mv88e6xxx_reg_write(ds, REG_GLOBAL2, GLOBAL2_SMI_OP,
|
||||
GLOBAL2_SMI_OP_22_READ | (addr << 5) |
|
||||
regnum);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
return REG_READ(REG_GLOBAL2, GLOBAL2_SMI_DATA);
|
||||
ret = _mv88e6xxx_phy_wait(ds);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
return _mv88e6xxx_reg_read(ds, REG_GLOBAL2, GLOBAL2_SMI_DATA);
|
||||
}
|
||||
|
||||
/* Must be called with phy mutex held */
|
||||
/* Must be called with SMI mutex held */
|
||||
static int _mv88e6xxx_phy_write_indirect(struct dsa_switch *ds, int addr,
|
||||
int regnum, u16 val)
|
||||
{
|
||||
REG_WRITE(REG_GLOBAL2, GLOBAL2_SMI_DATA, val);
|
||||
REG_WRITE(REG_GLOBAL2, GLOBAL2_SMI_OP,
|
||||
GLOBAL2_SMI_OP_22_WRITE | (addr << 5) | regnum);
|
||||
int ret;
|
||||
|
||||
return mv88e6xxx_phy_wait(ds);
|
||||
ret = _mv88e6xxx_reg_write(ds, REG_GLOBAL2, GLOBAL2_SMI_DATA, val);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = _mv88e6xxx_reg_write(ds, REG_GLOBAL2, GLOBAL2_SMI_OP,
|
||||
GLOBAL2_SMI_OP_22_WRITE | (addr << 5) |
|
||||
regnum);
|
||||
|
||||
return _mv88e6xxx_phy_wait(ds);
|
||||
}
|
||||
|
||||
int mv88e6xxx_get_eee(struct dsa_switch *ds, int port, struct ethtool_eee *e)
|
||||
|
@ -824,7 +931,7 @@ int mv88e6xxx_get_eee(struct dsa_switch *ds, int port, struct ethtool_eee *e)
|
|||
struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
|
||||
int reg;
|
||||
|
||||
mutex_lock(&ps->phy_mutex);
|
||||
mutex_lock(&ps->smi_mutex);
|
||||
|
||||
reg = _mv88e6xxx_phy_read_indirect(ds, port, 16);
|
||||
if (reg < 0)
|
||||
|
@ -833,7 +940,7 @@ int mv88e6xxx_get_eee(struct dsa_switch *ds, int port, struct ethtool_eee *e)
|
|||
e->eee_enabled = !!(reg & 0x0200);
|
||||
e->tx_lpi_enabled = !!(reg & 0x0100);
|
||||
|
||||
reg = mv88e6xxx_reg_read(ds, REG_PORT(port), PORT_STATUS);
|
||||
reg = _mv88e6xxx_reg_read(ds, REG_PORT(port), PORT_STATUS);
|
||||
if (reg < 0)
|
||||
goto out;
|
||||
|
||||
|
@ -841,7 +948,7 @@ int mv88e6xxx_get_eee(struct dsa_switch *ds, int port, struct ethtool_eee *e)
|
|||
reg = 0;
|
||||
|
||||
out:
|
||||
mutex_unlock(&ps->phy_mutex);
|
||||
mutex_unlock(&ps->smi_mutex);
|
||||
return reg;
|
||||
}
|
||||
|
||||
|
@ -852,7 +959,7 @@ int mv88e6xxx_set_eee(struct dsa_switch *ds, int port,
|
|||
int reg;
|
||||
int ret;
|
||||
|
||||
mutex_lock(&ps->phy_mutex);
|
||||
mutex_lock(&ps->smi_mutex);
|
||||
|
||||
ret = _mv88e6xxx_phy_read_indirect(ds, port, 16);
|
||||
if (ret < 0)
|
||||
|
@ -866,7 +973,7 @@ int mv88e6xxx_set_eee(struct dsa_switch *ds, int port,
|
|||
|
||||
ret = _mv88e6xxx_phy_write_indirect(ds, port, 16, reg);
|
||||
out:
|
||||
mutex_unlock(&ps->phy_mutex);
|
||||
mutex_unlock(&ps->smi_mutex);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
@ -1241,13 +1348,212 @@ static void mv88e6xxx_bridge_work(struct work_struct *work)
|
|||
}
|
||||
}
|
||||
|
||||
int mv88e6xxx_setup_port_common(struct dsa_switch *ds, int port)
|
||||
static int mv88e6xxx_setup_port(struct dsa_switch *ds, int port)
|
||||
{
|
||||
struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
|
||||
int ret, fid;
|
||||
u16 reg;
|
||||
|
||||
mutex_lock(&ps->smi_mutex);
|
||||
|
||||
if (mv88e6xxx_6352_family(ds) || mv88e6xxx_6351_family(ds) ||
|
||||
mv88e6xxx_6165_family(ds) || mv88e6xxx_6097_family(ds) ||
|
||||
mv88e6xxx_6185_family(ds) || mv88e6xxx_6095_family(ds) ||
|
||||
mv88e6xxx_6065_family(ds)) {
|
||||
/* MAC Forcing register: don't force link, speed,
|
||||
* duplex or flow control state to any particular
|
||||
* values on physical ports, but force the CPU port
|
||||
* and all DSA ports to their maximum bandwidth and
|
||||
* full duplex.
|
||||
*/
|
||||
reg = _mv88e6xxx_reg_read(ds, REG_PORT(port), PORT_PCS_CTRL);
|
||||
if (dsa_is_cpu_port(ds, port) ||
|
||||
ds->dsa_port_mask & (1 << port)) {
|
||||
reg |= PORT_PCS_CTRL_FORCE_LINK |
|
||||
PORT_PCS_CTRL_LINK_UP |
|
||||
PORT_PCS_CTRL_DUPLEX_FULL |
|
||||
PORT_PCS_CTRL_FORCE_DUPLEX;
|
||||
if (mv88e6xxx_6065_family(ds))
|
||||
reg |= PORT_PCS_CTRL_100;
|
||||
else
|
||||
reg |= PORT_PCS_CTRL_1000;
|
||||
} else {
|
||||
reg |= PORT_PCS_CTRL_UNFORCED;
|
||||
}
|
||||
|
||||
ret = _mv88e6xxx_reg_write(ds, REG_PORT(port),
|
||||
PORT_PCS_CTRL, reg);
|
||||
if (ret)
|
||||
goto abort;
|
||||
}
|
||||
|
||||
/* Port Control: disable Drop-on-Unlock, disable Drop-on-Lock,
|
||||
* disable Header mode, enable IGMP/MLD snooping, disable VLAN
|
||||
* tunneling, determine priority by looking at 802.1p and IP
|
||||
* priority fields (IP prio has precedence), and set STP state
|
||||
* to Forwarding.
|
||||
*
|
||||
* If this is the CPU link, use DSA or EDSA tagging depending
|
||||
* on which tagging mode was configured.
|
||||
*
|
||||
* If this is a link to another switch, use DSA tagging mode.
|
||||
*
|
||||
* If this is the upstream port for this switch, enable
|
||||
* forwarding of unknown unicasts and multicasts.
|
||||
*/
|
||||
reg = 0;
|
||||
if (mv88e6xxx_6352_family(ds) || mv88e6xxx_6351_family(ds) ||
|
||||
mv88e6xxx_6165_family(ds) || mv88e6xxx_6097_family(ds) ||
|
||||
mv88e6xxx_6095_family(ds) || mv88e6xxx_6065_family(ds) ||
|
||||
mv88e6xxx_6185_family(ds))
|
||||
reg = PORT_CONTROL_IGMP_MLD_SNOOP |
|
||||
PORT_CONTROL_USE_TAG | PORT_CONTROL_USE_IP |
|
||||
PORT_CONTROL_STATE_FORWARDING;
|
||||
if (dsa_is_cpu_port(ds, port)) {
|
||||
if (mv88e6xxx_6095_family(ds) || mv88e6xxx_6185_family(ds))
|
||||
reg |= PORT_CONTROL_DSA_TAG;
|
||||
if (mv88e6xxx_6352_family(ds) || mv88e6xxx_6351_family(ds) ||
|
||||
mv88e6xxx_6165_family(ds) || mv88e6xxx_6097_family(ds)) {
|
||||
if (ds->dst->tag_protocol == DSA_TAG_PROTO_EDSA)
|
||||
reg |= PORT_CONTROL_FRAME_ETHER_TYPE_DSA;
|
||||
else
|
||||
reg |= PORT_CONTROL_FRAME_MODE_DSA;
|
||||
}
|
||||
|
||||
if (mv88e6xxx_6352_family(ds) || mv88e6xxx_6351_family(ds) ||
|
||||
mv88e6xxx_6165_family(ds) || mv88e6xxx_6097_family(ds) ||
|
||||
mv88e6xxx_6095_family(ds) || mv88e6xxx_6065_family(ds) ||
|
||||
mv88e6xxx_6185_family(ds)) {
|
||||
if (ds->dst->tag_protocol == DSA_TAG_PROTO_EDSA)
|
||||
reg |= PORT_CONTROL_EGRESS_ADD_TAG;
|
||||
}
|
||||
}
|
||||
if (mv88e6xxx_6352_family(ds) || mv88e6xxx_6351_family(ds) ||
|
||||
mv88e6xxx_6165_family(ds) || mv88e6xxx_6097_family(ds) ||
|
||||
mv88e6xxx_6095_family(ds) || mv88e6xxx_6065_family(ds)) {
|
||||
if (ds->dsa_port_mask & (1 << port))
|
||||
reg |= PORT_CONTROL_FRAME_MODE_DSA;
|
||||
if (port == dsa_upstream_port(ds))
|
||||
reg |= PORT_CONTROL_FORWARD_UNKNOWN |
|
||||
PORT_CONTROL_FORWARD_UNKNOWN_MC;
|
||||
}
|
||||
if (reg) {
|
||||
ret = _mv88e6xxx_reg_write(ds, REG_PORT(port),
|
||||
PORT_CONTROL, reg);
|
||||
if (ret)
|
||||
goto abort;
|
||||
}
|
||||
|
||||
/* 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
|
||||
* on this port, do a destination address lookup on all
|
||||
* received packets as usual, disable ARP mirroring and don't
|
||||
* send a copy of all transmitted/received frames on this port
|
||||
* to the CPU.
|
||||
*/
|
||||
reg = 0;
|
||||
if (mv88e6xxx_6352_family(ds) || mv88e6xxx_6351_family(ds) ||
|
||||
mv88e6xxx_6165_family(ds) || mv88e6xxx_6097_family(ds) ||
|
||||
mv88e6xxx_6095_family(ds))
|
||||
reg = PORT_CONTROL_2_MAP_DA;
|
||||
|
||||
if (mv88e6xxx_6352_family(ds) || mv88e6xxx_6351_family(ds) ||
|
||||
mv88e6xxx_6165_family(ds))
|
||||
reg |= PORT_CONTROL_2_JUMBO_10240;
|
||||
|
||||
if (mv88e6xxx_6095_family(ds) || mv88e6xxx_6185_family(ds)) {
|
||||
/* Set the upstream port this port should use */
|
||||
reg |= dsa_upstream_port(ds);
|
||||
/* enable forwarding of unknown multicast addresses to
|
||||
* the upstream port
|
||||
*/
|
||||
if (port == dsa_upstream_port(ds))
|
||||
reg |= PORT_CONTROL_2_FORWARD_UNKNOWN;
|
||||
}
|
||||
|
||||
if (reg) {
|
||||
ret = _mv88e6xxx_reg_write(ds, REG_PORT(port),
|
||||
PORT_CONTROL_2, reg);
|
||||
if (ret)
|
||||
goto abort;
|
||||
}
|
||||
|
||||
/* Port Association Vector: when learning source addresses
|
||||
* of packets, add the address to the address database using
|
||||
* a port bitmap that has only the bit for this port set and
|
||||
* the other bits clear.
|
||||
*/
|
||||
ret = _mv88e6xxx_reg_write(ds, REG_PORT(port), PORT_ASSOC_VECTOR,
|
||||
1 << port);
|
||||
if (ret)
|
||||
goto abort;
|
||||
|
||||
/* Egress rate control 2: disable egress rate control. */
|
||||
ret = _mv88e6xxx_reg_write(ds, REG_PORT(port), PORT_RATE_CONTROL_2,
|
||||
0x0000);
|
||||
if (ret)
|
||||
goto abort;
|
||||
|
||||
if (mv88e6xxx_6352_family(ds) || mv88e6xxx_6351_family(ds) ||
|
||||
mv88e6xxx_6165_family(ds) || mv88e6xxx_6097_family(ds)) {
|
||||
/* Do not limit the period of time that this port can
|
||||
* be paused for by the remote end or the period of
|
||||
* time that this port can pause the remote end.
|
||||
*/
|
||||
ret = _mv88e6xxx_reg_write(ds, REG_PORT(port),
|
||||
PORT_PAUSE_CTRL, 0x0000);
|
||||
if (ret)
|
||||
goto abort;
|
||||
|
||||
/* Port ATU control: disable limiting the number of
|
||||
* address database entries that this port is allowed
|
||||
* to use.
|
||||
*/
|
||||
ret = _mv88e6xxx_reg_write(ds, REG_PORT(port),
|
||||
PORT_ATU_CONTROL, 0x0000);
|
||||
/* Priority Override: disable DA, SA and VTU priority
|
||||
* override.
|
||||
*/
|
||||
ret = _mv88e6xxx_reg_write(ds, REG_PORT(port),
|
||||
PORT_PRI_OVERRIDE, 0x0000);
|
||||
if (ret)
|
||||
goto abort;
|
||||
|
||||
/* Port Ethertype: use the Ethertype DSA Ethertype
|
||||
* value.
|
||||
*/
|
||||
ret = _mv88e6xxx_reg_write(ds, REG_PORT(port),
|
||||
PORT_ETH_TYPE, ETH_P_EDSA);
|
||||
if (ret)
|
||||
goto abort;
|
||||
/* Tag Remap: use an identity 802.1p prio -> switch
|
||||
* prio mapping.
|
||||
*/
|
||||
ret = _mv88e6xxx_reg_write(ds, REG_PORT(port),
|
||||
PORT_TAG_REGMAP_0123, 0x3210);
|
||||
if (ret)
|
||||
goto abort;
|
||||
|
||||
/* Tag Remap 2: use an identity 802.1p prio -> switch
|
||||
* prio mapping.
|
||||
*/
|
||||
ret = _mv88e6xxx_reg_write(ds, REG_PORT(port),
|
||||
PORT_TAG_REGMAP_4567, 0x7654);
|
||||
if (ret)
|
||||
goto abort;
|
||||
}
|
||||
|
||||
if (mv88e6xxx_6352_family(ds) || mv88e6xxx_6351_family(ds) ||
|
||||
mv88e6xxx_6165_family(ds) || mv88e6xxx_6097_family(ds) ||
|
||||
mv88e6xxx_6185_family(ds) || mv88e6xxx_6095_family(ds)) {
|
||||
/* Rate Control: disable ingress rate limiting. */
|
||||
ret = _mv88e6xxx_reg_write(ds, REG_PORT(port),
|
||||
PORT_RATE_CONTROL, 0x0001);
|
||||
if (ret)
|
||||
goto abort;
|
||||
}
|
||||
|
||||
/* Port Control 1: disable trunking, disable sending
|
||||
* learning messages to this port.
|
||||
*/
|
||||
|
@ -1281,13 +1587,25 @@ abort:
|
|||
return ret;
|
||||
}
|
||||
|
||||
int mv88e6xxx_setup_ports(struct dsa_switch *ds)
|
||||
{
|
||||
struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
|
||||
int ret;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < ps->num_ports; i++) {
|
||||
ret = mv88e6xxx_setup_port(ds, i);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int mv88e6xxx_setup_common(struct dsa_switch *ds)
|
||||
{
|
||||
struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
|
||||
|
||||
mutex_init(&ps->smi_mutex);
|
||||
mutex_init(&ps->stats_mutex);
|
||||
mutex_init(&ps->phy_mutex);
|
||||
|
||||
ps->id = REG_READ(REG_PORT(0), PORT_SWITCH_ID) & 0xfff0;
|
||||
|
||||
|
@ -1298,6 +1616,104 @@ int mv88e6xxx_setup_common(struct dsa_switch *ds)
|
|||
return 0;
|
||||
}
|
||||
|
||||
int mv88e6xxx_setup_global(struct dsa_switch *ds)
|
||||
{
|
||||
struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
|
||||
int i;
|
||||
|
||||
/* Set the default address aging time to 5 minutes, and
|
||||
* enable address learn messages to be sent to all message
|
||||
* ports.
|
||||
*/
|
||||
REG_WRITE(REG_GLOBAL, GLOBAL_ATU_CONTROL,
|
||||
0x0140 | GLOBAL_ATU_CONTROL_LEARN2ALL);
|
||||
|
||||
/* Configure the IP ToS mapping registers. */
|
||||
REG_WRITE(REG_GLOBAL, GLOBAL_IP_PRI_0, 0x0000);
|
||||
REG_WRITE(REG_GLOBAL, GLOBAL_IP_PRI_1, 0x0000);
|
||||
REG_WRITE(REG_GLOBAL, GLOBAL_IP_PRI_2, 0x5555);
|
||||
REG_WRITE(REG_GLOBAL, GLOBAL_IP_PRI_3, 0x5555);
|
||||
REG_WRITE(REG_GLOBAL, GLOBAL_IP_PRI_4, 0xaaaa);
|
||||
REG_WRITE(REG_GLOBAL, GLOBAL_IP_PRI_5, 0xaaaa);
|
||||
REG_WRITE(REG_GLOBAL, GLOBAL_IP_PRI_6, 0xffff);
|
||||
REG_WRITE(REG_GLOBAL, GLOBAL_IP_PRI_7, 0xffff);
|
||||
|
||||
/* Configure the IEEE 802.1p priority mapping register. */
|
||||
REG_WRITE(REG_GLOBAL, GLOBAL_IEEE_PRI, 0xfa41);
|
||||
|
||||
/* Send all frames with destination addresses matching
|
||||
* 01:80:c2:00:00:0x to the CPU port.
|
||||
*/
|
||||
REG_WRITE(REG_GLOBAL2, GLOBAL2_MGMT_EN_0X, 0xffff);
|
||||
|
||||
/* Ignore removed tag data on doubly tagged packets, disable
|
||||
* flow control messages, force flow control priority to the
|
||||
* highest, and send all special multicast frames to the CPU
|
||||
* port at the highest priority.
|
||||
*/
|
||||
REG_WRITE(REG_GLOBAL2, GLOBAL2_SWITCH_MGMT,
|
||||
0x7 | GLOBAL2_SWITCH_MGMT_RSVD2CPU | 0x70 |
|
||||
GLOBAL2_SWITCH_MGMT_FORCE_FLOW_CTRL_PRI);
|
||||
|
||||
/* Program the DSA routing table. */
|
||||
for (i = 0; i < 32; i++) {
|
||||
int nexthop = 0x1f;
|
||||
|
||||
if (ds->pd->rtable &&
|
||||
i != ds->index && i < ds->dst->pd->nr_chips)
|
||||
nexthop = ds->pd->rtable[i] & 0x1f;
|
||||
|
||||
REG_WRITE(REG_GLOBAL2, GLOBAL2_DEVICE_MAPPING,
|
||||
GLOBAL2_DEVICE_MAPPING_UPDATE |
|
||||
(i << GLOBAL2_DEVICE_MAPPING_TARGET_SHIFT) |
|
||||
nexthop);
|
||||
}
|
||||
|
||||
/* Clear all trunk masks. */
|
||||
for (i = 0; i < 8; i++)
|
||||
REG_WRITE(REG_GLOBAL2, GLOBAL2_TRUNK_MASK,
|
||||
0x8000 | (i << GLOBAL2_TRUNK_MASK_NUM_SHIFT) |
|
||||
((1 << ps->num_ports) - 1));
|
||||
|
||||
/* Clear all trunk mappings. */
|
||||
for (i = 0; i < 16; i++)
|
||||
REG_WRITE(REG_GLOBAL2, GLOBAL2_TRUNK_MAPPING,
|
||||
GLOBAL2_TRUNK_MAPPING_UPDATE |
|
||||
(i << GLOBAL2_TRUNK_MAPPING_ID_SHIFT));
|
||||
|
||||
if (mv88e6xxx_6352_family(ds) || mv88e6xxx_6351_family(ds) ||
|
||||
mv88e6xxx_6165_family(ds) || mv88e6xxx_6097_family(ds)) {
|
||||
/* Send all frames with destination addresses matching
|
||||
* 01:80:c2:00:00:2x to the CPU port.
|
||||
*/
|
||||
REG_WRITE(REG_GLOBAL2, GLOBAL2_MGMT_EN_2X, 0xffff);
|
||||
|
||||
/* Initialise cross-chip port VLAN table to reset
|
||||
* defaults.
|
||||
*/
|
||||
REG_WRITE(REG_GLOBAL2, GLOBAL2_PVT_ADDR, 0x9000);
|
||||
|
||||
/* Clear the priority override table. */
|
||||
for (i = 0; i < 16; i++)
|
||||
REG_WRITE(REG_GLOBAL2, GLOBAL2_PRIO_OVERRIDE,
|
||||
0x8000 | (i << 8));
|
||||
}
|
||||
|
||||
if (mv88e6xxx_6352_family(ds) || mv88e6xxx_6351_family(ds) ||
|
||||
mv88e6xxx_6165_family(ds) || mv88e6xxx_6097_family(ds) ||
|
||||
mv88e6xxx_6185_family(ds) || mv88e6xxx_6095_family(ds)) {
|
||||
/* Disable ingress rate limiting by resetting all
|
||||
* ingress rate limit registers to their initial
|
||||
* state.
|
||||
*/
|
||||
for (i = 0; i < ps->num_ports; i++)
|
||||
REG_WRITE(REG_GLOBAL2, GLOBAL2_INGRESS_OP,
|
||||
0x9000 | (i << 8));
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int mv88e6xxx_switch_reset(struct dsa_switch *ds, bool ppu_active)
|
||||
{
|
||||
struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
|
||||
|
@ -1343,14 +1759,14 @@ int mv88e6xxx_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);
|
||||
mutex_lock(&ps->smi_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);
|
||||
mutex_unlock(&ps->smi_mutex);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -1360,7 +1776,7 @@ int mv88e6xxx_phy_page_write(struct dsa_switch *ds, int port, int page,
|
|||
struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
|
||||
int ret;
|
||||
|
||||
mutex_lock(&ps->phy_mutex);
|
||||
mutex_lock(&ps->smi_mutex);
|
||||
ret = _mv88e6xxx_phy_write_indirect(ds, port, 0x16, page);
|
||||
if (ret < 0)
|
||||
goto error;
|
||||
|
@ -1368,7 +1784,7 @@ int mv88e6xxx_phy_page_write(struct dsa_switch *ds, int port, int page,
|
|||
ret = _mv88e6xxx_phy_write_indirect(ds, port, reg, val);
|
||||
error:
|
||||
_mv88e6xxx_phy_write_indirect(ds, port, 0x16, 0x0);
|
||||
mutex_unlock(&ps->phy_mutex);
|
||||
mutex_unlock(&ps->smi_mutex);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -1391,9 +1807,9 @@ mv88e6xxx_phy_read(struct dsa_switch *ds, int port, int regnum)
|
|||
if (addr < 0)
|
||||
return addr;
|
||||
|
||||
mutex_lock(&ps->phy_mutex);
|
||||
mutex_lock(&ps->smi_mutex);
|
||||
ret = _mv88e6xxx_phy_read(ds, addr, regnum);
|
||||
mutex_unlock(&ps->phy_mutex);
|
||||
mutex_unlock(&ps->smi_mutex);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -1407,9 +1823,9 @@ mv88e6xxx_phy_write(struct dsa_switch *ds, int port, int regnum, u16 val)
|
|||
if (addr < 0)
|
||||
return addr;
|
||||
|
||||
mutex_lock(&ps->phy_mutex);
|
||||
mutex_lock(&ps->smi_mutex);
|
||||
ret = _mv88e6xxx_phy_write(ds, addr, regnum, val);
|
||||
mutex_unlock(&ps->phy_mutex);
|
||||
mutex_unlock(&ps->smi_mutex);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -1423,9 +1839,9 @@ mv88e6xxx_phy_read_indirect(struct dsa_switch *ds, int port, int regnum)
|
|||
if (addr < 0)
|
||||
return addr;
|
||||
|
||||
mutex_lock(&ps->phy_mutex);
|
||||
mutex_lock(&ps->smi_mutex);
|
||||
ret = _mv88e6xxx_phy_read_indirect(ds, addr, regnum);
|
||||
mutex_unlock(&ps->phy_mutex);
|
||||
mutex_unlock(&ps->smi_mutex);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -1440,9 +1856,9 @@ mv88e6xxx_phy_write_indirect(struct dsa_switch *ds, int port, int regnum,
|
|||
if (addr < 0)
|
||||
return addr;
|
||||
|
||||
mutex_lock(&ps->phy_mutex);
|
||||
mutex_lock(&ps->smi_mutex);
|
||||
ret = _mv88e6xxx_phy_write_indirect(ds, addr, regnum, val);
|
||||
mutex_unlock(&ps->phy_mutex);
|
||||
mutex_unlock(&ps->smi_mutex);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
|
|
@ -40,9 +40,31 @@
|
|||
#define PORT_STATUS_TX_PAUSED BIT(5)
|
||||
#define PORT_STATUS_FLOW_CTRL BIT(4)
|
||||
#define PORT_PCS_CTRL 0x01
|
||||
#define PORT_PCS_CTRL_FC BIT(7)
|
||||
#define PORT_PCS_CTRL_FORCE_FC BIT(6)
|
||||
#define PORT_PCS_CTRL_LINK_UP BIT(5)
|
||||
#define PORT_PCS_CTRL_FORCE_LINK BIT(4)
|
||||
#define PORT_PCS_CTRL_DUPLEX_FULL BIT(3)
|
||||
#define PORT_PCS_CTRL_FORCE_DUPLEX BIT(2)
|
||||
#define PORT_PCS_CTRL_10 0x00
|
||||
#define PORT_PCS_CTRL_100 0x01
|
||||
#define PORT_PCS_CTRL_1000 0x02
|
||||
#define PORT_PCS_CTRL_UNFORCED 0x03
|
||||
#define PORT_PAUSE_CTRL 0x02
|
||||
#define PORT_SWITCH_ID 0x03
|
||||
#define PORT_SWITCH_ID_6031 0x0310
|
||||
#define PORT_SWITCH_ID_6035 0x0350
|
||||
#define PORT_SWITCH_ID_6046 0x0480
|
||||
#define PORT_SWITCH_ID_6061 0x0610
|
||||
#define PORT_SWITCH_ID_6065 0x0650
|
||||
#define PORT_SWITCH_ID_6085 0x04a0
|
||||
#define PORT_SWITCH_ID_6092 0x0970
|
||||
#define PORT_SWITCH_ID_6095 0x0950
|
||||
#define PORT_SWITCH_ID_6096 0x0980
|
||||
#define PORT_SWITCH_ID_6097 0x0990
|
||||
#define PORT_SWITCH_ID_6108 0x1070
|
||||
#define PORT_SWITCH_ID_6121 0x1040
|
||||
#define PORT_SWITCH_ID_6122 0x1050
|
||||
#define PORT_SWITCH_ID_6123 0x1210
|
||||
#define PORT_SWITCH_ID_6123_A1 0x1212
|
||||
#define PORT_SWITCH_ID_6123_A2 0x1213
|
||||
|
@ -58,13 +80,38 @@
|
|||
#define PORT_SWITCH_ID_6165_A2 0x1653
|
||||
#define PORT_SWITCH_ID_6171 0x1710
|
||||
#define PORT_SWITCH_ID_6172 0x1720
|
||||
#define PORT_SWITCH_ID_6175 0x1750
|
||||
#define PORT_SWITCH_ID_6176 0x1760
|
||||
#define PORT_SWITCH_ID_6182 0x1a60
|
||||
#define PORT_SWITCH_ID_6185 0x1a70
|
||||
#define PORT_SWITCH_ID_6240 0x2400
|
||||
#define PORT_SWITCH_ID_6320 0x1250
|
||||
#define PORT_SWITCH_ID_6350 0x3710
|
||||
#define PORT_SWITCH_ID_6351 0x3750
|
||||
#define PORT_SWITCH_ID_6352 0x3520
|
||||
#define PORT_SWITCH_ID_6352_A0 0x3521
|
||||
#define PORT_SWITCH_ID_6352_A1 0x3522
|
||||
#define PORT_CONTROL 0x04
|
||||
#define PORT_CONTROL_USE_CORE_TAG BIT(15)
|
||||
#define PORT_CONTROL_DROP_ON_LOCK BIT(14)
|
||||
#define PORT_CONTROL_EGRESS_UNMODIFIED (0x0 << 12)
|
||||
#define PORT_CONTROL_EGRESS_UNTAGGED (0x1 << 12)
|
||||
#define PORT_CONTROL_EGRESS_TAGGED (0x2 << 12)
|
||||
#define PORT_CONTROL_EGRESS_ADD_TAG (0x3 << 12)
|
||||
#define PORT_CONTROL_HEADER BIT(11)
|
||||
#define PORT_CONTROL_IGMP_MLD_SNOOP BIT(10)
|
||||
#define PORT_CONTROL_DOUBLE_TAG BIT(9)
|
||||
#define PORT_CONTROL_FRAME_MODE_NORMAL (0x0 << 8)
|
||||
#define PORT_CONTROL_FRAME_MODE_DSA (0x1 << 8)
|
||||
#define PORT_CONTROL_FRAME_MODE_PROVIDER (0x2 << 8)
|
||||
#define PORT_CONTROL_FRAME_ETHER_TYPE_DSA (0x3 << 8)
|
||||
#define PORT_CONTROL_DSA_TAG BIT(8)
|
||||
#define PORT_CONTROL_VLAN_TUNNEL BIT(7)
|
||||
#define PORT_CONTROL_TAG_IF_BOTH BIT(6)
|
||||
#define PORT_CONTROL_USE_IP BIT(5)
|
||||
#define PORT_CONTROL_USE_TAG BIT(4)
|
||||
#define PORT_CONTROL_FORWARD_UNKNOWN_MC BIT(3)
|
||||
#define PORT_CONTROL_FORWARD_UNKNOWN BIT(2)
|
||||
#define PORT_CONTROL_STATE_MASK 0x03
|
||||
#define PORT_CONTROL_STATE_DISABLED 0x00
|
||||
#define PORT_CONTROL_STATE_BLOCKING 0x01
|
||||
|
@ -74,15 +121,32 @@
|
|||
#define PORT_BASE_VLAN 0x06
|
||||
#define PORT_DEFAULT_VLAN 0x07
|
||||
#define PORT_CONTROL_2 0x08
|
||||
#define PORT_CONTROL_2_IGNORE_FCS BIT(15)
|
||||
#define PORT_CONTROL_2_VTU_PRI_OVERRIDE BIT(14)
|
||||
#define PORT_CONTROL_2_SA_PRIO_OVERRIDE BIT(13)
|
||||
#define PORT_CONTROL_2_DA_PRIO_OVERRIDE BIT(12)
|
||||
#define PORT_CONTROL_2_JUMBO_1522 (0x00 << 12)
|
||||
#define PORT_CONTROL_2_JUMBO_2048 (0x01 << 12)
|
||||
#define PORT_CONTROL_2_JUMBO_10240 (0x02 << 12)
|
||||
#define PORT_CONTROL_2_DISCARD_TAGGED BIT(9)
|
||||
#define PORT_CONTROL_2_DISCARD_UNTAGGED BIT(8)
|
||||
#define PORT_CONTROL_2_MAP_DA BIT(7)
|
||||
#define PORT_CONTROL_2_DEFAULT_FORWARD BIT(6)
|
||||
#define PORT_CONTROL_2_FORWARD_UNKNOWN BIT(6)
|
||||
#define PORT_CONTROL_2_EGRESS_MONITOR BIT(5)
|
||||
#define PORT_CONTROL_2_INGRESS_MONITOR BIT(4)
|
||||
#define PORT_RATE_CONTROL 0x09
|
||||
#define PORT_RATE_CONTROL_2 0x0a
|
||||
#define PORT_ASSOC_VECTOR 0x0b
|
||||
#define PORT_ATU_CONTROL 0x0c
|
||||
#define PORT_PRI_OVERRIDE 0x0d
|
||||
#define PORT_ETH_TYPE 0x0f
|
||||
#define PORT_IN_DISCARD_LO 0x10
|
||||
#define PORT_IN_DISCARD_HI 0x11
|
||||
#define PORT_IN_FILTERED 0x12
|
||||
#define PORT_OUT_FILTERED 0x13
|
||||
#define PORT_TAG_REGMAP_0123 0x19
|
||||
#define PORT_TAG_REGMAP_4567 0x1a
|
||||
#define PORT_TAG_REGMAP_0123 0x18
|
||||
#define PORT_TAG_REGMAP_4567 0x19
|
||||
|
||||
#define REG_GLOBAL 0x1b
|
||||
#define GLOBAL_STATUS 0x00
|
||||
|
@ -102,7 +166,7 @@
|
|||
#define GLOBAL_CONTROL_DISCARD_EXCESS BIT(13) /* 6352 */
|
||||
#define GLOBAL_CONTROL_SCHED_PRIO BIT(11) /* 6152 */
|
||||
#define GLOBAL_CONTROL_MAX_FRAME_1632 BIT(10) /* 6152 */
|
||||
#define GLOBAL_CONTROL_RELOAD_EEPROM BIT(9) /* 6152 */
|
||||
#define GLOBAL_CONTROL_RELOAD_EEPROM BIT(9) /* 6152 */
|
||||
#define GLOBAL_CONTROL_DEVICE_EN BIT(7)
|
||||
#define GLOBAL_CONTROL_STATS_DONE_EN BIT(6)
|
||||
#define GLOBAL_CONTROL_VTU_PROBLEM_EN BIT(5)
|
||||
|
@ -117,6 +181,7 @@
|
|||
#define GLOBAL_VTU_DATA_4_7 0x08
|
||||
#define GLOBAL_VTU_DATA_8_11 0x09
|
||||
#define GLOBAL_ATU_CONTROL 0x0a
|
||||
#define GLOBAL_ATU_CONTROL_LEARN2ALL BIT(3)
|
||||
#define GLOBAL_ATU_OP 0x0b
|
||||
#define GLOBAL_ATU_OP_BUSY BIT(15)
|
||||
#define GLOBAL_ATU_OP_NOP (0 << 12)
|
||||
|
@ -151,7 +216,15 @@
|
|||
#define GLOBAL_IEEE_PRI 0x18
|
||||
#define GLOBAL_CORE_TAG_TYPE 0x19
|
||||
#define GLOBAL_MONITOR_CONTROL 0x1a
|
||||
#define GLOBAL_MONITOR_CONTROL_INGRESS_SHIFT 12
|
||||
#define GLOBAL_MONITOR_CONTROL_EGRESS_SHIFT 8
|
||||
#define GLOBAL_MONITOR_CONTROL_ARP_SHIFT 4
|
||||
#define GLOBAL_MONITOR_CONTROL_MIRROR_SHIFT 0
|
||||
#define GLOBAL_MONITOR_CONTROL_ARP_DISABLED (0xf0)
|
||||
#define GLOBAL_CONTROL_2 0x1c
|
||||
#define GLOBAL_CONTROL_2_NO_CASCADE 0xe000
|
||||
#define GLOBAL_CONTROL_2_MULTIPLE_CASCADE 0xf000
|
||||
|
||||
#define GLOBAL_STATS_OP 0x1d
|
||||
#define GLOBAL_STATS_OP_BUSY BIT(15)
|
||||
#define GLOBAL_STATS_OP_NOP (0 << 12)
|
||||
|
@ -172,9 +245,20 @@
|
|||
#define GLOBAL2_MGMT_EN_0X 0x03
|
||||
#define GLOBAL2_FLOW_CONTROL 0x04
|
||||
#define GLOBAL2_SWITCH_MGMT 0x05
|
||||
#define GLOBAL2_SWITCH_MGMT_USE_DOUBLE_TAG_DATA BIT(15)
|
||||
#define GLOBAL2_SWITCH_MGMT_PREVENT_LOOPS BIT(14)
|
||||
#define GLOBAL2_SWITCH_MGMT_FLOW_CONTROL_MSG BIT(13)
|
||||
#define GLOBAL2_SWITCH_MGMT_FORCE_FLOW_CTRL_PRI BIT(7)
|
||||
#define GLOBAL2_SWITCH_MGMT_RSVD2CPU BIT(3)
|
||||
#define GLOBAL2_DEVICE_MAPPING 0x06
|
||||
#define GLOBAL2_DEVICE_MAPPING_UPDATE BIT(15)
|
||||
#define GLOBAL2_DEVICE_MAPPING_TARGET_SHIFT 8
|
||||
#define GLOBAL2_TRUNK_MASK 0x07
|
||||
#define GLOBAL2_TRUNK_MASK_UPDATE BIT(15)
|
||||
#define GLOBAL2_TRUNK_MASK_NUM_SHIFT 12
|
||||
#define GLOBAL2_TRUNK_MAPPING 0x08
|
||||
#define GLOBAL2_TRUNK_MAPPING_UPDATE BIT(15)
|
||||
#define GLOBAL2_TRUNK_MAPPING_ID_SHIFT 11
|
||||
#define GLOBAL2_INGRESS_OP 0x09
|
||||
#define GLOBAL2_INGRESS_DATA 0x0a
|
||||
#define GLOBAL2_PVT_ADDR 0x0b
|
||||
|
@ -183,6 +267,10 @@
|
|||
#define GLOBAL2_SWITCH_MAC_BUSY BIT(15)
|
||||
#define GLOBAL2_ATU_STATS 0x0e
|
||||
#define GLOBAL2_PRIO_OVERRIDE 0x0f
|
||||
#define GLOBAL2_PRIO_OVERRIDE_FORCE_SNOOP BIT(7)
|
||||
#define GLOBAL2_PRIO_OVERRIDE_SNOOP_SHIFT 4
|
||||
#define GLOBAL2_PRIO_OVERRIDE_FORCE_ARP BIT(3)
|
||||
#define GLOBAL2_PRIO_OVERRIDE_ARP_SHIFT 0
|
||||
#define GLOBAL2_EEPROM_OP 0x14
|
||||
#define GLOBAL2_EEPROM_OP_BUSY BIT(15)
|
||||
#define GLOBAL2_EEPROM_OP_LOAD BIT(11)
|
||||
|
@ -260,14 +348,14 @@ struct mv88e6xxx_hw_stat {
|
|||
};
|
||||
|
||||
int mv88e6xxx_switch_reset(struct dsa_switch *ds, bool ppu_active);
|
||||
int mv88e6xxx_setup_port_common(struct dsa_switch *ds, int port);
|
||||
int mv88e6xxx_setup_ports(struct dsa_switch *ds);
|
||||
int mv88e6xxx_setup_common(struct dsa_switch *ds);
|
||||
int mv88e6xxx_setup_global(struct dsa_switch *ds);
|
||||
int __mv88e6xxx_reg_read(struct mii_bus *bus, int sw_addr, int addr, int reg);
|
||||
int mv88e6xxx_reg_read(struct dsa_switch *ds, int addr, int reg);
|
||||
int __mv88e6xxx_reg_write(struct mii_bus *bus, int sw_addr, int addr,
|
||||
int reg, u16 val);
|
||||
int mv88e6xxx_reg_write(struct dsa_switch *ds, int addr, int reg, u16 val);
|
||||
int mv88e6xxx_config_prio(struct dsa_switch *ds);
|
||||
int mv88e6xxx_set_addr_direct(struct dsa_switch *ds, u8 *addr);
|
||||
int mv88e6xxx_set_addr_indirect(struct dsa_switch *ds, u8 *addr);
|
||||
int mv88e6xxx_phy_read(struct dsa_switch *ds, int port, int regnum);
|
||||
|
@ -289,7 +377,6 @@ int mv88e6xxx_get_regs_len(struct dsa_switch *ds, int port);
|
|||
void mv88e6xxx_get_regs(struct dsa_switch *ds, int port,
|
||||
struct ethtool_regs *regs, void *_p);
|
||||
int mv88e6xxx_get_temp(struct dsa_switch *ds, int *temp);
|
||||
int mv88e6xxx_phy_wait(struct dsa_switch *ds);
|
||||
int mv88e6xxx_eeprom_load_wait(struct dsa_switch *ds);
|
||||
int mv88e6xxx_eeprom_busy_wait(struct dsa_switch *ds);
|
||||
int mv88e6xxx_phy_read_indirect(struct dsa_switch *ds, int addr, int regnum);
|
||||
|
|
|
@ -810,12 +810,19 @@ static int dsa_slave_phy_setup(struct dsa_slave_priv *p,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static struct lock_class_key dsa_slave_netdev_xmit_lock_key;
|
||||
static void dsa_slave_set_lockdep_class_one(struct net_device *dev,
|
||||
struct netdev_queue *txq,
|
||||
void *_unused)
|
||||
{
|
||||
lockdep_set_class(&txq->_xmit_lock,
|
||||
&dsa_slave_netdev_xmit_lock_key);
|
||||
}
|
||||
|
||||
int dsa_slave_suspend(struct net_device *slave_dev)
|
||||
{
|
||||
struct dsa_slave_priv *p = netdev_priv(slave_dev);
|
||||
|
||||
netif_device_detach(slave_dev);
|
||||
|
||||
if (p->phy) {
|
||||
phy_stop(p->phy);
|
||||
p->old_pause = -1;
|
||||
|
@ -861,6 +868,9 @@ int dsa_slave_create(struct dsa_switch *ds, struct device *parent,
|
|||
slave_dev->netdev_ops = &dsa_slave_netdev_ops;
|
||||
slave_dev->swdev_ops = &dsa_slave_swdev_ops;
|
||||
|
||||
netdev_for_each_tx_queue(slave_dev, dsa_slave_set_lockdep_class_one,
|
||||
NULL);
|
||||
|
||||
SET_NETDEV_DEV(slave_dev, parent);
|
||||
slave_dev->dev.of_node = ds->pd->port_dn[port];
|
||||
slave_dev->vlan_features = master->vlan_features;
|
||||
|
|
Loading…
Reference in New Issue