Add support for the Marvell 88E6190 11 ports switch.
With more ports, some of the registers are shifted a bit to accommodate. This switch also adds two high speed Serdes/SGMII interfaces (2.5 Gb/s). Sponsored by: Rubicon Communications, LLC (Netgate)
This commit is contained in:
parent
b46517aa7b
commit
9aba06377d
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=349578
@ -106,6 +106,8 @@ static int e6000sw_parse_fixed_link(e6000sw_softc_t *, phandle_t, uint32_t);
|
|||||||
static int e6000sw_parse_ethernet(e6000sw_softc_t *, phandle_t, uint32_t);
|
static int e6000sw_parse_ethernet(e6000sw_softc_t *, phandle_t, uint32_t);
|
||||||
static int e6000sw_attach(device_t);
|
static int e6000sw_attach(device_t);
|
||||||
static int e6000sw_detach(device_t);
|
static int e6000sw_detach(device_t);
|
||||||
|
static int e6000sw_read_xmdio(device_t, int, int, int);
|
||||||
|
static int e6000sw_write_xmdio(device_t, int, int, int, int);
|
||||||
static int e6000sw_readphy(device_t, int, int);
|
static int e6000sw_readphy(device_t, int, int);
|
||||||
static int e6000sw_writephy(device_t, int, int, int);
|
static int e6000sw_writephy(device_t, int, int, int);
|
||||||
static etherswitch_info_t* e6000sw_getinfo(device_t);
|
static etherswitch_info_t* e6000sw_getinfo(device_t);
|
||||||
@ -205,16 +207,26 @@ e6000sw_probe(device_t dev)
|
|||||||
const char *description;
|
const char *description;
|
||||||
phandle_t switch_node;
|
phandle_t switch_node;
|
||||||
|
|
||||||
|
sc = device_get_softc(dev);
|
||||||
switch_node = ofw_bus_find_compatible(OF_finddevice("/"),
|
switch_node = ofw_bus_find_compatible(OF_finddevice("/"),
|
||||||
"marvell,mv88e6085");
|
"marvell,mv88e6085");
|
||||||
|
if (switch_node == 0) {
|
||||||
|
switch_node = ofw_bus_find_compatible(OF_finddevice("/"),
|
||||||
|
"marvell,mv88e6190");
|
||||||
|
|
||||||
if (switch_node == 0)
|
if (switch_node == 0)
|
||||||
return (ENXIO);
|
return (ENXIO);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Trust DTS and fix the port register offset for the MV88E6190
|
||||||
|
* detection bellow.
|
||||||
|
*/
|
||||||
|
sc->swid = MV88E6190;
|
||||||
|
}
|
||||||
|
|
||||||
if (bootverbose)
|
if (bootverbose)
|
||||||
device_printf(dev, "Found switch_node: 0x%x\n", switch_node);
|
device_printf(dev, "Found switch_node: 0x%x\n", switch_node);
|
||||||
|
|
||||||
sc = device_get_softc(dev);
|
|
||||||
sc->dev = dev;
|
sc->dev = dev;
|
||||||
sc->node = switch_node;
|
sc->node = switch_node;
|
||||||
|
|
||||||
@ -230,7 +242,7 @@ e6000sw_probe(device_t dev)
|
|||||||
*/
|
*/
|
||||||
sx_init(&sc->sx, "e6000sw_tmp");
|
sx_init(&sc->sx, "e6000sw_tmp");
|
||||||
E6000SW_LOCK(sc);
|
E6000SW_LOCK(sc);
|
||||||
sc->swid = e6000sw_readreg(sc, REG_PORT(0), SWITCH_ID) & 0xfff0;
|
sc->swid = e6000sw_readreg(sc, REG_PORT(sc, 0), SWITCH_ID) & 0xfff0;
|
||||||
E6000SW_UNLOCK(sc);
|
E6000SW_UNLOCK(sc);
|
||||||
sx_destroy(&sc->sx);
|
sx_destroy(&sc->sx);
|
||||||
|
|
||||||
@ -257,6 +269,10 @@ e6000sw_probe(device_t dev)
|
|||||||
description = "Marvell 88E6176";
|
description = "Marvell 88E6176";
|
||||||
sc->num_ports = 7;
|
sc->num_ports = 7;
|
||||||
break;
|
break;
|
||||||
|
case MV88E6190:
|
||||||
|
description = "Marvell 88E6190";
|
||||||
|
sc->num_ports = 11;
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
device_printf(dev, "Unrecognized device, id 0x%x.\n", sc->swid);
|
device_printf(dev, "Unrecognized device, id 0x%x.\n", sc->swid);
|
||||||
return (ENXIO);
|
return (ENXIO);
|
||||||
@ -278,18 +294,16 @@ e6000sw_parse_fixed_link(e6000sw_softc_t *sc, phandle_t node, uint32_t port)
|
|||||||
if (fixed_link != 0) {
|
if (fixed_link != 0) {
|
||||||
sc->fixed_mask |= (1 << port);
|
sc->fixed_mask |= (1 << port);
|
||||||
|
|
||||||
if (OF_getencprop(fixed_link, "speed", &speed, sizeof(speed))> 0) {
|
if (OF_getencprop(fixed_link,
|
||||||
if (speed == 2500 &&
|
"speed", &speed, sizeof(speed)) < 0) {
|
||||||
(MVSWITCH(sc, MV88E6141) ||
|
device_printf(sc->dev,
|
||||||
MVSWITCH(sc, MV88E6341)))
|
|
||||||
sc->fixed25_mask |= (1 << port);
|
|
||||||
} else {
|
|
||||||
device_printf(sc->dev,
|
|
||||||
"Port %d has a fixed-link node without a speed "
|
"Port %d has a fixed-link node without a speed "
|
||||||
"property\n", port);
|
"property\n", port);
|
||||||
|
return (ENXIO);
|
||||||
return (ENXIO);
|
|
||||||
}
|
}
|
||||||
|
if (speed == 2500 && (MVSWITCH(sc, MV88E6141) ||
|
||||||
|
MVSWITCH(sc, MV88E6341) || MVSWITCH(sc, MV88E6190)))
|
||||||
|
sc->fixed25_mask |= (1 << port);
|
||||||
}
|
}
|
||||||
|
|
||||||
return (0);
|
return (0);
|
||||||
@ -383,9 +397,36 @@ e6000sw_attach_miibus(e6000sw_softc_t *sc, int port)
|
|||||||
return (0);
|
return (0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
e6000sw_serdes_power(device_t dev, int port, bool sgmii)
|
||||||
|
{
|
||||||
|
uint32_t reg;
|
||||||
|
|
||||||
|
/* SGMII */
|
||||||
|
reg = e6000sw_read_xmdio(dev, port, E6000SW_SERDES_DEV,
|
||||||
|
E6000SW_SERDES_SGMII_CTL);
|
||||||
|
if (sgmii)
|
||||||
|
reg &= ~E6000SW_SERDES_PDOWN;
|
||||||
|
else
|
||||||
|
reg |= E6000SW_SERDES_PDOWN;
|
||||||
|
e6000sw_write_xmdio(dev, port, E6000SW_SERDES_DEV,
|
||||||
|
E6000SW_SERDES_SGMII_CTL, reg);
|
||||||
|
|
||||||
|
/* 10GBASE-R/10GBASE-X4/X2 */
|
||||||
|
reg = e6000sw_read_xmdio(dev, port, E6000SW_SERDES_DEV,
|
||||||
|
E6000SW_SERDES_PCS_CTL1);
|
||||||
|
if (sgmii)
|
||||||
|
reg |= E6000SW_SERDES_PDOWN;
|
||||||
|
else
|
||||||
|
reg &= ~E6000SW_SERDES_PDOWN;
|
||||||
|
e6000sw_write_xmdio(dev, port, E6000SW_SERDES_DEV,
|
||||||
|
E6000SW_SERDES_PCS_CTL1, reg);
|
||||||
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
e6000sw_attach(device_t dev)
|
e6000sw_attach(device_t dev)
|
||||||
{
|
{
|
||||||
|
bool sgmii;
|
||||||
e6000sw_softc_t *sc;
|
e6000sw_softc_t *sc;
|
||||||
phandle_t child, ports;
|
phandle_t child, ports;
|
||||||
int err, port;
|
int err, port;
|
||||||
@ -436,28 +477,47 @@ e6000sw_attach(device_t dev)
|
|||||||
|
|
||||||
if (e6000sw_is_fixedport(sc, port)) {
|
if (e6000sw_is_fixedport(sc, port)) {
|
||||||
/* Link must be down to change speed force value. */
|
/* Link must be down to change speed force value. */
|
||||||
reg = e6000sw_readreg(sc, REG_PORT(port), PSC_CONTROL);
|
reg = e6000sw_readreg(sc, REG_PORT(sc, port),
|
||||||
|
PSC_CONTROL);
|
||||||
reg &= ~PSC_CONTROL_LINK_UP;
|
reg &= ~PSC_CONTROL_LINK_UP;
|
||||||
reg |= PSC_CONTROL_FORCED_LINK;
|
reg |= PSC_CONTROL_FORCED_LINK;
|
||||||
e6000sw_writereg(sc, REG_PORT(port), PSC_CONTROL, reg);
|
e6000sw_writereg(sc, REG_PORT(sc, port), PSC_CONTROL,
|
||||||
|
reg);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Force speed, full-duplex, EEE off and flow-control
|
* Force speed, full-duplex, EEE off and flow-control
|
||||||
* on.
|
* on.
|
||||||
*/
|
*/
|
||||||
reg &= ~(PSC_CONTROL_SPD2500 | PSC_CONTROL_ALT_SPD |
|
reg &= ~(PSC_CONTROL_SPD2500 | PSC_CONTROL_ALT_SPD |
|
||||||
|
PSC_CONTROL_FORCED_FC | PSC_CONTROL_FC_ON |
|
||||||
PSC_CONTROL_FORCED_EEE);
|
PSC_CONTROL_FORCED_EEE);
|
||||||
if (e6000sw_is_fixed25port(sc, port))
|
if (e6000sw_is_fixed25port(sc, port))
|
||||||
reg |= PSC_CONTROL_SPD2500;
|
reg |= PSC_CONTROL_SPD2500;
|
||||||
else
|
else
|
||||||
reg |= PSC_CONTROL_SPD1000;
|
reg |= PSC_CONTROL_SPD1000;
|
||||||
|
if (MVSWITCH(sc, MV88E6190) &&
|
||||||
|
e6000sw_is_fixed25port(sc, port))
|
||||||
|
reg |= PSC_CONTROL_ALT_SPD;
|
||||||
reg |= PSC_CONTROL_FORCED_DPX | PSC_CONTROL_FULLDPX |
|
reg |= PSC_CONTROL_FORCED_DPX | PSC_CONTROL_FULLDPX |
|
||||||
PSC_CONTROL_FORCED_LINK | PSC_CONTROL_LINK_UP |
|
PSC_CONTROL_FORCED_LINK | PSC_CONTROL_LINK_UP |
|
||||||
PSC_CONTROL_FORCED_FC | PSC_CONTROL_FC_ON |
|
|
||||||
PSC_CONTROL_FORCED_SPD;
|
PSC_CONTROL_FORCED_SPD;
|
||||||
if (MVSWITCH(sc, MV88E6141) || MVSWITCH(sc, MV88E6341))
|
if (!MVSWITCH(sc, MV88E6190))
|
||||||
reg |= PSC_CONTROL_FORCED_EEE;
|
reg |= PSC_CONTROL_FORCED_FC | PSC_CONTROL_FC_ON;
|
||||||
e6000sw_writereg(sc, REG_PORT(port), PSC_CONTROL, reg);
|
if (MVSWITCH(sc, MV88E6141) ||
|
||||||
|
MVSWITCH(sc, MV88E6341) ||
|
||||||
|
MVSWITCH(sc, MV88E6190))
|
||||||
|
reg |= PSC_CONTROL_FORCED_EEE;
|
||||||
|
e6000sw_writereg(sc, REG_PORT(sc, port), PSC_CONTROL,
|
||||||
|
reg);
|
||||||
|
/* Power on the SERDES interfaces. */
|
||||||
|
if (MVSWITCH(sc, MV88E6190) &&
|
||||||
|
(port == 9 || port == 10)) {
|
||||||
|
if (e6000sw_is_fixed25port(sc, port))
|
||||||
|
sgmii = false;
|
||||||
|
else
|
||||||
|
sgmii = true;
|
||||||
|
e6000sw_serdes_power(sc->dev, port, sgmii);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Don't attach miibus at CPU/fixed ports */
|
/* Don't attach miibus at CPU/fixed ports */
|
||||||
@ -510,6 +570,79 @@ e6000sw_waitready(e6000sw_softc_t *sc, uint32_t phy, uint32_t reg,
|
|||||||
return (1);
|
return (1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* XMDIO/Clause 45 access. */
|
||||||
|
static int
|
||||||
|
e6000sw_read_xmdio(device_t dev, int phy, int devaddr, int devreg)
|
||||||
|
{
|
||||||
|
e6000sw_softc_t *sc;
|
||||||
|
uint32_t reg;
|
||||||
|
|
||||||
|
sc = device_get_softc(dev);
|
||||||
|
E6000SW_LOCK_ASSERT(sc, SA_XLOCKED);
|
||||||
|
if (E6000SW_WAITREADY2(sc, SMI_PHY_CMD_REG, SMI_CMD_BUSY)) {
|
||||||
|
device_printf(dev, "Timeout while waiting for switch\n");
|
||||||
|
return (ETIMEDOUT);
|
||||||
|
}
|
||||||
|
|
||||||
|
reg = devaddr & SMI_CMD_REG_ADDR_MASK;
|
||||||
|
reg |= (phy << SMI_CMD_DEV_ADDR) & SMI_CMD_DEV_ADDR_MASK;
|
||||||
|
|
||||||
|
/* Load C45 register address. */
|
||||||
|
e6000sw_writereg(sc, REG_GLOBAL2, SMI_PHY_DATA_REG, devreg);
|
||||||
|
e6000sw_writereg(sc, REG_GLOBAL2, SMI_PHY_CMD_REG,
|
||||||
|
reg | SMI_CMD_OP_C45_ADDR);
|
||||||
|
if (E6000SW_WAITREADY2(sc, SMI_PHY_CMD_REG, SMI_CMD_BUSY)) {
|
||||||
|
device_printf(dev, "Timeout while waiting for switch\n");
|
||||||
|
return (ETIMEDOUT);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Start C45 read operation. */
|
||||||
|
e6000sw_writereg(sc, REG_GLOBAL2, SMI_PHY_CMD_REG,
|
||||||
|
reg | SMI_CMD_OP_C45_READ);
|
||||||
|
if (E6000SW_WAITREADY2(sc, SMI_PHY_CMD_REG, SMI_CMD_BUSY)) {
|
||||||
|
device_printf(dev, "Timeout while waiting for switch\n");
|
||||||
|
return (ETIMEDOUT);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Read C45 data. */
|
||||||
|
reg = e6000sw_readreg(sc, REG_GLOBAL2, SMI_PHY_DATA_REG);
|
||||||
|
|
||||||
|
return (reg & PHY_DATA_MASK);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
e6000sw_write_xmdio(device_t dev, int phy, int devaddr, int devreg, int val)
|
||||||
|
{
|
||||||
|
e6000sw_softc_t *sc;
|
||||||
|
uint32_t reg;
|
||||||
|
|
||||||
|
sc = device_get_softc(dev);
|
||||||
|
E6000SW_LOCK_ASSERT(sc, SA_XLOCKED);
|
||||||
|
if (E6000SW_WAITREADY2(sc, SMI_PHY_CMD_REG, SMI_CMD_BUSY)) {
|
||||||
|
device_printf(dev, "Timeout while waiting for switch\n");
|
||||||
|
return (ETIMEDOUT);
|
||||||
|
}
|
||||||
|
|
||||||
|
reg = devaddr & SMI_CMD_REG_ADDR_MASK;
|
||||||
|
reg |= (phy << SMI_CMD_DEV_ADDR) & SMI_CMD_DEV_ADDR_MASK;
|
||||||
|
|
||||||
|
/* Load C45 register address. */
|
||||||
|
e6000sw_writereg(sc, REG_GLOBAL2, SMI_PHY_DATA_REG, devreg);
|
||||||
|
e6000sw_writereg(sc, REG_GLOBAL2, SMI_PHY_CMD_REG,
|
||||||
|
reg | SMI_CMD_OP_C45_ADDR);
|
||||||
|
if (E6000SW_WAITREADY2(sc, SMI_PHY_CMD_REG, SMI_CMD_BUSY)) {
|
||||||
|
device_printf(dev, "Timeout while waiting for switch\n");
|
||||||
|
return (ETIMEDOUT);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Load data and start the C45 write operation. */
|
||||||
|
e6000sw_writereg(sc, REG_GLOBAL2, SMI_PHY_DATA_REG, devreg);
|
||||||
|
e6000sw_writereg(sc, REG_GLOBAL2, SMI_PHY_CMD_REG,
|
||||||
|
reg | SMI_CMD_OP_C45_WRITE);
|
||||||
|
|
||||||
|
return (0);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* PHY registers are paged. Put page index in reg 22 (accessible from every
|
* PHY registers are paged. Put page index in reg 22 (accessible from every
|
||||||
* page), then access specific register.
|
* page), then access specific register.
|
||||||
@ -670,7 +803,7 @@ e6000sw_getport(device_t dev, etherswitch_port_t *p)
|
|||||||
e6000sw_get_pvid(sc, p->es_port, &p->es_pvid);
|
e6000sw_get_pvid(sc, p->es_port, &p->es_pvid);
|
||||||
|
|
||||||
/* Port flags. */
|
/* Port flags. */
|
||||||
reg = e6000sw_readreg(sc, REG_PORT(p->es_port), PORT_CONTROL2);
|
reg = e6000sw_readreg(sc, REG_PORT(sc, p->es_port), PORT_CONTROL2);
|
||||||
if (reg & PORT_CONTROL2_DISC_TAGGED)
|
if (reg & PORT_CONTROL2_DISC_TAGGED)
|
||||||
p->es_flags |= ETHERSWITCH_PORT_DROPTAGGED;
|
p->es_flags |= ETHERSWITCH_PORT_DROPTAGGED;
|
||||||
if (reg & PORT_CONTROL2_DISC_UNTAGGED)
|
if (reg & PORT_CONTROL2_DISC_UNTAGGED)
|
||||||
@ -717,7 +850,7 @@ e6000sw_setport(device_t dev, etherswitch_port_t *p)
|
|||||||
return (0);
|
return (0);
|
||||||
|
|
||||||
/* Port flags. */
|
/* Port flags. */
|
||||||
reg = e6000sw_readreg(sc, REG_PORT(p->es_port), PORT_CONTROL2);
|
reg = e6000sw_readreg(sc, REG_PORT(sc, p->es_port), PORT_CONTROL2);
|
||||||
if (p->es_flags & ETHERSWITCH_PORT_DROPTAGGED)
|
if (p->es_flags & ETHERSWITCH_PORT_DROPTAGGED)
|
||||||
reg |= PORT_CONTROL2_DISC_TAGGED;
|
reg |= PORT_CONTROL2_DISC_TAGGED;
|
||||||
else
|
else
|
||||||
@ -726,7 +859,7 @@ e6000sw_setport(device_t dev, etherswitch_port_t *p)
|
|||||||
reg |= PORT_CONTROL2_DISC_UNTAGGED;
|
reg |= PORT_CONTROL2_DISC_UNTAGGED;
|
||||||
else
|
else
|
||||||
reg &= ~PORT_CONTROL2_DISC_UNTAGGED;
|
reg &= ~PORT_CONTROL2_DISC_UNTAGGED;
|
||||||
e6000sw_writereg(sc, REG_PORT(p->es_port), PORT_CONTROL2, reg);
|
e6000sw_writereg(sc, REG_PORT(sc, p->es_port), PORT_CONTROL2, reg);
|
||||||
|
|
||||||
err = 0;
|
err = 0;
|
||||||
E6000SW_LOCK(sc);
|
E6000SW_LOCK(sc);
|
||||||
@ -748,15 +881,15 @@ e6000sw_port_vlan_assign(e6000sw_softc_t *sc, int port, uint32_t fid,
|
|||||||
{
|
{
|
||||||
uint32_t reg;
|
uint32_t reg;
|
||||||
|
|
||||||
reg = e6000sw_readreg(sc, REG_PORT(port), PORT_VLAN_MAP);
|
reg = e6000sw_readreg(sc, REG_PORT(sc, port), PORT_VLAN_MAP);
|
||||||
reg &= ~(PORT_MASK(sc) | PORT_VLAN_MAP_FID_MASK);
|
reg &= ~(PORT_MASK(sc) | PORT_VLAN_MAP_FID_MASK);
|
||||||
reg |= members & PORT_MASK(sc) & ~(1 << port);
|
reg |= members & PORT_MASK(sc) & ~(1 << port);
|
||||||
reg |= (fid << PORT_VLAN_MAP_FID) & PORT_VLAN_MAP_FID_MASK;
|
reg |= (fid << PORT_VLAN_MAP_FID) & PORT_VLAN_MAP_FID_MASK;
|
||||||
e6000sw_writereg(sc, REG_PORT(port), PORT_VLAN_MAP, reg);
|
e6000sw_writereg(sc, REG_PORT(sc, port), PORT_VLAN_MAP, reg);
|
||||||
reg = e6000sw_readreg(sc, REG_PORT(port), PORT_CONTROL1);
|
reg = e6000sw_readreg(sc, REG_PORT(sc, port), PORT_CONTROL1);
|
||||||
reg &= ~PORT_CONTROL1_FID_MASK;
|
reg &= ~PORT_CONTROL1_FID_MASK;
|
||||||
reg |= (fid >> 4) & PORT_CONTROL1_FID_MASK;
|
reg |= (fid >> 4) & PORT_CONTROL1_FID_MASK;
|
||||||
e6000sw_writereg(sc, REG_PORT(port), PORT_CONTROL1, reg);
|
e6000sw_writereg(sc, REG_PORT(sc, port), PORT_CONTROL1, reg);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
@ -767,8 +900,8 @@ e6000sw_init_vlan(struct e6000sw_softc *sc)
|
|||||||
|
|
||||||
/* Disable all ports */
|
/* Disable all ports */
|
||||||
for (port = 0; port < sc->num_ports; port++) {
|
for (port = 0; port < sc->num_ports; port++) {
|
||||||
ret = e6000sw_readreg(sc, REG_PORT(port), PORT_CONTROL);
|
ret = e6000sw_readreg(sc, REG_PORT(sc, port), PORT_CONTROL);
|
||||||
e6000sw_writereg(sc, REG_PORT(port), PORT_CONTROL,
|
e6000sw_writereg(sc, REG_PORT(sc, port), PORT_CONTROL,
|
||||||
(ret & ~PORT_CONTROL_ENABLE));
|
(ret & ~PORT_CONTROL_ENABLE));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -777,23 +910,23 @@ e6000sw_init_vlan(struct e6000sw_softc *sc)
|
|||||||
|
|
||||||
for (port = 0; port < sc->num_ports; port++) {
|
for (port = 0; port < sc->num_ports; port++) {
|
||||||
/* Reset the egress and frame mode. */
|
/* Reset the egress and frame mode. */
|
||||||
ret = e6000sw_readreg(sc, REG_PORT(port), PORT_CONTROL);
|
ret = e6000sw_readreg(sc, REG_PORT(sc, port), PORT_CONTROL);
|
||||||
ret &= ~(PORT_CONTROL_EGRESS | PORT_CONTROL_FRAME);
|
ret &= ~(PORT_CONTROL_EGRESS | PORT_CONTROL_FRAME);
|
||||||
e6000sw_writereg(sc, REG_PORT(port), PORT_CONTROL, ret);
|
e6000sw_writereg(sc, REG_PORT(sc, port), PORT_CONTROL, ret);
|
||||||
|
|
||||||
/* Set the the 802.1q mode. */
|
/* Set the the 802.1q mode. */
|
||||||
ret = e6000sw_readreg(sc, REG_PORT(port), PORT_CONTROL2);
|
ret = e6000sw_readreg(sc, REG_PORT(sc, port), PORT_CONTROL2);
|
||||||
ret &= ~PORT_CONTROL2_DOT1Q;
|
ret &= ~PORT_CONTROL2_DOT1Q;
|
||||||
if (sc->vlan_mode == ETHERSWITCH_VLAN_DOT1Q)
|
if (sc->vlan_mode == ETHERSWITCH_VLAN_DOT1Q)
|
||||||
ret |= PORT_CONTROL2_DOT1Q;
|
ret |= PORT_CONTROL2_DOT1Q;
|
||||||
e6000sw_writereg(sc, REG_PORT(port), PORT_CONTROL2, ret);
|
e6000sw_writereg(sc, REG_PORT(sc, port), PORT_CONTROL2, ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (port = 0; port < sc->num_ports; port++) {
|
for (port = 0; port < sc->num_ports; port++) {
|
||||||
if (!e6000sw_is_portenabled(sc, port))
|
if (!e6000sw_is_portenabled(sc, port))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
ret = e6000sw_readreg(sc, REG_PORT(port), PORT_VID);
|
ret = e6000sw_readreg(sc, REG_PORT(sc, port), PORT_VID);
|
||||||
|
|
||||||
/* Set port priority */
|
/* Set port priority */
|
||||||
ret &= ~PORT_VID_PRIORITY_MASK;
|
ret &= ~PORT_VID_PRIORITY_MASK;
|
||||||
@ -804,7 +937,7 @@ e6000sw_init_vlan(struct e6000sw_softc *sc)
|
|||||||
ret |= 1;
|
ret |= 1;
|
||||||
else
|
else
|
||||||
ret |= (port + 1);
|
ret |= (port + 1);
|
||||||
e6000sw_writereg(sc, REG_PORT(port), PORT_VID, ret);
|
e6000sw_writereg(sc, REG_PORT(sc, port), PORT_VID, ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Assign the member ports to each origin port. */
|
/* Assign the member ports to each origin port. */
|
||||||
@ -835,8 +968,8 @@ e6000sw_init_vlan(struct e6000sw_softc *sc)
|
|||||||
for (port = 0; port < sc->num_ports; port++) {
|
for (port = 0; port < sc->num_ports; port++) {
|
||||||
if (!e6000sw_is_portenabled(sc, port))
|
if (!e6000sw_is_portenabled(sc, port))
|
||||||
continue;
|
continue;
|
||||||
ret = e6000sw_readreg(sc, REG_PORT(port), PORT_CONTROL);
|
ret = e6000sw_readreg(sc, REG_PORT(sc, port), PORT_CONTROL);
|
||||||
e6000sw_writereg(sc, REG_PORT(port), PORT_CONTROL,
|
e6000sw_writereg(sc, REG_PORT(sc, port), PORT_CONTROL,
|
||||||
(ret | PORT_CONTROL_ENABLE));
|
(ret | PORT_CONTROL_ENABLE));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -873,9 +1006,11 @@ e6000sw_set_vlan_mode(struct e6000sw_softc *sc, uint32_t mode)
|
|||||||
static int
|
static int
|
||||||
e6000sw_readreg_wrapper(device_t dev, int addr_reg)
|
e6000sw_readreg_wrapper(device_t dev, int addr_reg)
|
||||||
{
|
{
|
||||||
|
e6000sw_softc_t *sc;
|
||||||
|
|
||||||
|
sc = device_get_softc(dev);
|
||||||
if ((addr_reg > (REG_GLOBAL2 * 32 + REG_NUM_MAX)) ||
|
if ((addr_reg > (REG_GLOBAL2 * 32 + REG_NUM_MAX)) ||
|
||||||
(addr_reg < (REG_PORT(0) * 32))) {
|
(addr_reg < (REG_PORT(sc, 0) * 32))) {
|
||||||
device_printf(dev, "Wrong register address.\n");
|
device_printf(dev, "Wrong register address.\n");
|
||||||
return (EINVAL);
|
return (EINVAL);
|
||||||
}
|
}
|
||||||
@ -887,9 +1022,11 @@ e6000sw_readreg_wrapper(device_t dev, int addr_reg)
|
|||||||
static int
|
static int
|
||||||
e6000sw_writereg_wrapper(device_t dev, int addr_reg, int val)
|
e6000sw_writereg_wrapper(device_t dev, int addr_reg, int val)
|
||||||
{
|
{
|
||||||
|
e6000sw_softc_t *sc;
|
||||||
|
|
||||||
|
sc = device_get_softc(dev);
|
||||||
if ((addr_reg > (REG_GLOBAL2 * 32 + REG_NUM_MAX)) ||
|
if ((addr_reg > (REG_GLOBAL2 * 32 + REG_NUM_MAX)) ||
|
||||||
(addr_reg < (REG_PORT(0) * 32))) {
|
(addr_reg < (REG_PORT(sc, 0) * 32))) {
|
||||||
device_printf(dev, "Wrong register address.\n");
|
device_printf(dev, "Wrong register address.\n");
|
||||||
return (EINVAL);
|
return (EINVAL);
|
||||||
}
|
}
|
||||||
@ -1049,11 +1186,11 @@ e6000sw_get_port_vlan(e6000sw_softc_t *sc, etherswitch_vlangroup_t *vg)
|
|||||||
return (0);
|
return (0);
|
||||||
}
|
}
|
||||||
|
|
||||||
reg = e6000sw_readreg(sc, REG_PORT(port), PORT_VLAN_MAP);
|
reg = e6000sw_readreg(sc, REG_PORT(sc, port), PORT_VLAN_MAP);
|
||||||
vg->es_untagged_ports = vg->es_member_ports = reg & PORT_MASK(sc);
|
vg->es_untagged_ports = vg->es_member_ports = reg & PORT_MASK(sc);
|
||||||
vg->es_vid = port | ETHERSWITCH_VID_VALID;
|
vg->es_vid = port | ETHERSWITCH_VID_VALID;
|
||||||
vg->es_fid = (reg & PORT_VLAN_MAP_FID_MASK) >> PORT_VLAN_MAP_FID;
|
vg->es_fid = (reg & PORT_VLAN_MAP_FID_MASK) >> PORT_VLAN_MAP_FID;
|
||||||
reg = e6000sw_readreg(sc, REG_PORT(port), PORT_CONTROL1);
|
reg = e6000sw_readreg(sc, REG_PORT(sc, port), PORT_CONTROL1);
|
||||||
vg->es_fid |= (reg & PORT_CONTROL1_FID_MASK) << 4;
|
vg->es_fid |= (reg & PORT_CONTROL1_FID_MASK) << 4;
|
||||||
|
|
||||||
return (0);
|
return (0);
|
||||||
@ -1268,10 +1405,10 @@ e6000sw_set_pvid(e6000sw_softc_t *sc, int port, int pvid)
|
|||||||
{
|
{
|
||||||
uint32_t reg;
|
uint32_t reg;
|
||||||
|
|
||||||
reg = e6000sw_readreg(sc, REG_PORT(port), PORT_VID);
|
reg = e6000sw_readreg(sc, REG_PORT(sc, port), PORT_VID);
|
||||||
reg &= ~PORT_VID_DEF_VID_MASK;
|
reg &= ~PORT_VID_DEF_VID_MASK;
|
||||||
reg |= (pvid & PORT_VID_DEF_VID_MASK);
|
reg |= (pvid & PORT_VID_DEF_VID_MASK);
|
||||||
e6000sw_writereg(sc, REG_PORT(port), PORT_VID, reg);
|
e6000sw_writereg(sc, REG_PORT(sc, port), PORT_VID, reg);
|
||||||
}
|
}
|
||||||
|
|
||||||
static __inline int
|
static __inline int
|
||||||
@ -1281,7 +1418,7 @@ e6000sw_get_pvid(e6000sw_softc_t *sc, int port, int *pvid)
|
|||||||
if (pvid == NULL)
|
if (pvid == NULL)
|
||||||
return (ENXIO);
|
return (ENXIO);
|
||||||
|
|
||||||
*pvid = e6000sw_readreg(sc, REG_PORT(port), PORT_VID) &
|
*pvid = e6000sw_readreg(sc, REG_PORT(sc, port), PORT_VID) &
|
||||||
PORT_VID_DEF_VID_MASK;
|
PORT_VID_DEF_VID_MASK;
|
||||||
|
|
||||||
return (0);
|
return (0);
|
||||||
@ -1346,7 +1483,7 @@ e6000sw_tick(void *arg)
|
|||||||
if (mii == NULL)
|
if (mii == NULL)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
portstatus = e6000sw_readreg(sc, REG_PORT(port),
|
portstatus = e6000sw_readreg(sc, REG_PORT(sc, port),
|
||||||
PORT_STATUS);
|
PORT_STATUS);
|
||||||
|
|
||||||
e6000sw_update_ifmedia(portstatus,
|
e6000sw_update_ifmedia(portstatus,
|
||||||
|
@ -48,6 +48,7 @@ struct atu_opt {
|
|||||||
#define MV88E6352 0x3520
|
#define MV88E6352 0x3520
|
||||||
#define MV88E6172 0x1720
|
#define MV88E6172 0x1720
|
||||||
#define MV88E6176 0x1760
|
#define MV88E6176 0x1760
|
||||||
|
#define MV88E6190 0x1900
|
||||||
|
|
||||||
#define MVSWITCH(_sc, id) ((_sc)->swid == (id))
|
#define MVSWITCH(_sc, id) ((_sc)->swid == (id))
|
||||||
#define MVSWITCH_MULTICHIP(_sc) ((_sc)->sw_addr != 0)
|
#define MVSWITCH_MULTICHIP(_sc) ((_sc)->sw_addr != 0)
|
||||||
@ -57,7 +58,7 @@ struct atu_opt {
|
|||||||
*/
|
*/
|
||||||
#define REG_GLOBAL 0x1b
|
#define REG_GLOBAL 0x1b
|
||||||
#define REG_GLOBAL2 0x1c
|
#define REG_GLOBAL2 0x1c
|
||||||
#define REG_PORT(p) (0x10 + (p))
|
#define REG_PORT(_sc, p) ((MVSWITCH((_sc), MV88E6190) ? 0 : 0x10) + (p))
|
||||||
|
|
||||||
#define REG_NUM_MAX 31
|
#define REG_NUM_MAX 31
|
||||||
|
|
||||||
@ -139,13 +140,13 @@ struct atu_opt {
|
|||||||
#define VTU_DATA 7
|
#define VTU_DATA 7
|
||||||
#define VTU_DATA2 8
|
#define VTU_DATA2 8
|
||||||
|
|
||||||
#define VTU_FID_MASK(_sc) 0xff
|
#define VTU_FID_MASK(_sc) (MVSWITCH((_sc), MV88E6190) ? 0xfff : 0xff)
|
||||||
#define VTU_FID_POLICY (1 << 12)
|
#define VTU_FID_POLICY (1 << 12)
|
||||||
#define VTU_PORT_UNMODIFIED 0
|
#define VTU_PORT_UNMODIFIED 0
|
||||||
#define VTU_PORT_UNTAGGED 1
|
#define VTU_PORT_UNTAGGED 1
|
||||||
#define VTU_PORT_TAGGED 2
|
#define VTU_PORT_TAGGED 2
|
||||||
#define VTU_PORT_DISCARD 3
|
#define VTU_PORT_DISCARD 3
|
||||||
#define VTU_PPREG(_sc) 4
|
#define VTU_PPREG(_sc) (MVSWITCH((_sc), MV88E6190) ? 8 : 4)
|
||||||
#define VTU_PORT(_sc, p) (((p) % VTU_PPREG(_sc)) * (16 / VTU_PPREG(_sc)))
|
#define VTU_PORT(_sc, p) (((p) % VTU_PPREG(_sc)) * (16 / VTU_PPREG(_sc)))
|
||||||
#define VTU_PORT_MASK 3
|
#define VTU_PORT_MASK 3
|
||||||
#define VTU_BUSY (1 << 15)
|
#define VTU_BUSY (1 << 15)
|
||||||
@ -175,7 +176,7 @@ struct atu_opt {
|
|||||||
#define ATU_MAC_ADDR45 15
|
#define ATU_MAC_ADDR45 15
|
||||||
|
|
||||||
#define ATU_DATA_LAG (1 << 15)
|
#define ATU_DATA_LAG (1 << 15)
|
||||||
#define ATU_PORT_MASK(_sc) 0xff0
|
#define ATU_PORT_MASK(_sc) (MVSWITCH((_sc), MV88E6190) ? 0xfff0 : 0xff0)
|
||||||
#define ATU_PORT_SHIFT 4
|
#define ATU_PORT_SHIFT 4
|
||||||
#define ATU_LAG_MASK 0xf0
|
#define ATU_LAG_MASK 0xf0
|
||||||
#define ATU_LAG_SHIFT 4
|
#define ATU_LAG_SHIFT 4
|
||||||
|
Loading…
Reference in New Issue
Block a user