Add support to 2.5G uplink for the MV88E6141 and MV88E6341 switches.
Force the switch port settings for fixed media types. Tested with: 88E6176, 88E6141 Sponsored by: Rubicon Communications, LLC (Netgate)
This commit is contained in:
parent
f9cdbaba8d
commit
091d140c99
@ -71,8 +71,10 @@ typedef struct e6000sw_softc {
|
||||
device_t miibus[E6000SW_MAX_PORTS];
|
||||
struct proc *kproc;
|
||||
|
||||
uint32_t swid;
|
||||
uint32_t cpuports_mask;
|
||||
uint32_t fixed_mask;
|
||||
uint32_t fixed25_mask;
|
||||
uint32_t ports_mask;
|
||||
int phy_base;
|
||||
int sw_addr;
|
||||
@ -126,6 +128,7 @@ static int e6000sw_get_pvid(e6000sw_softc_t *, int, int *);
|
||||
static int e6000sw_set_pvid(e6000sw_softc_t *, int, int);
|
||||
static __inline bool e6000sw_is_cpuport(e6000sw_softc_t *, int);
|
||||
static __inline bool e6000sw_is_fixedport(e6000sw_softc_t *, int);
|
||||
static __inline bool e6000sw_is_fixed25port(e6000sw_softc_t *, int);
|
||||
static __inline bool e6000sw_is_phyport(e6000sw_softc_t *, int);
|
||||
static __inline bool e6000sw_is_portenabled(e6000sw_softc_t *, int);
|
||||
static __inline struct mii_data *e6000sw_miiforphy(e6000sw_softc_t *,
|
||||
@ -198,7 +201,6 @@ e6000sw_probe(device_t dev)
|
||||
e6000sw_softc_t *sc;
|
||||
const char *description;
|
||||
phandle_t dsa_node, switch_node;
|
||||
uint32_t id;
|
||||
|
||||
dsa_node = fdt_find_compatible(OF_finddevice("/"),
|
||||
"marvell,dsa", 0);
|
||||
@ -223,35 +225,35 @@ e6000sw_probe(device_t dev)
|
||||
*/
|
||||
sx_init(&sc->sx, "e6000sw_tmp");
|
||||
E6000SW_LOCK(sc);
|
||||
id = e6000sw_readreg(sc, REG_PORT(0), SWITCH_ID);
|
||||
sc->swid = e6000sw_readreg(sc, REG_PORT(0), SWITCH_ID) & 0xfff0;
|
||||
E6000SW_UNLOCK(sc);
|
||||
sx_destroy(&sc->sx);
|
||||
|
||||
switch (id & 0xfff0) {
|
||||
case 0x3400:
|
||||
switch (sc->swid) {
|
||||
case MV88E6141:
|
||||
description = "Marvell 88E6141";
|
||||
sc->phy_base = 0x10;
|
||||
sc->num_ports = 6;
|
||||
break;
|
||||
case 0x3410:
|
||||
case MV88E6341:
|
||||
description = "Marvell 88E6341";
|
||||
sc->phy_base = 0x10;
|
||||
sc->num_ports = 6;
|
||||
break;
|
||||
case 0x3520:
|
||||
case MV88E6352:
|
||||
description = "Marvell 88E6352";
|
||||
sc->num_ports = 7;
|
||||
break;
|
||||
case 0x1720:
|
||||
case MV88E6172:
|
||||
description = "Marvell 88E6172";
|
||||
sc->num_ports = 7;
|
||||
break;
|
||||
case 0x1760:
|
||||
case MV88E6176:
|
||||
description = "Marvell 88E6176";
|
||||
sc->num_ports = 7;
|
||||
break;
|
||||
default:
|
||||
device_printf(dev, "Unrecognized device, id 0x%x.\n", id);
|
||||
device_printf(dev, "Unrecognized device, id 0x%x.\n", sc->swid);
|
||||
return (ENXIO);
|
||||
}
|
||||
|
||||
@ -261,18 +263,22 @@ e6000sw_probe(device_t dev)
|
||||
}
|
||||
|
||||
static int
|
||||
e6000sw_parse_child_fdt(e6000sw_softc_t *sc, phandle_t child,
|
||||
uint32_t *fixed_mask, uint32_t *cpu_mask, int *pport, int *pvlangroup)
|
||||
e6000sw_parse_child_fdt(e6000sw_softc_t *sc, phandle_t child, int *pport,
|
||||
int *pvlangroup)
|
||||
{
|
||||
boolean_t fixed_link;
|
||||
char portlabel[100];
|
||||
char *name, *portlabel;
|
||||
int speed;
|
||||
phandle_t fixed_link;
|
||||
uint32_t port, vlangroup;
|
||||
|
||||
if (fixed_mask == NULL || cpu_mask == NULL || pport == NULL)
|
||||
if (pport == NULL || pvlangroup == NULL)
|
||||
return (ENXIO);
|
||||
|
||||
OF_getprop(child, "label", (void *)portlabel, sizeof(portlabel));
|
||||
OF_getencprop(child, "reg", (void *)&port, sizeof(port));
|
||||
if (OF_getencprop(child, "reg", (void *)&port, sizeof(port)) < 0)
|
||||
return (ENXIO);
|
||||
if (port >= sc->num_ports)
|
||||
return (ENXIO);
|
||||
*pport = port;
|
||||
|
||||
if (OF_getencprop(child, "vlangroup", (void *)&vlangroup,
|
||||
sizeof(vlangroup)) > 0) {
|
||||
@ -283,22 +289,36 @@ e6000sw_parse_child_fdt(e6000sw_softc_t *sc, phandle_t child,
|
||||
*pvlangroup = -1;
|
||||
}
|
||||
|
||||
if (port >= sc->num_ports)
|
||||
return (ENXIO);
|
||||
*pport = port;
|
||||
|
||||
if (strncmp(portlabel, "cpu", 3) == 0) {
|
||||
device_printf(sc->dev, "CPU port at %d\n", port);
|
||||
*cpu_mask |= (1 << port);
|
||||
if (OF_getprop_alloc(child, "label", 1, (void **)&portlabel) > 0) {
|
||||
if (strncmp(portlabel, "cpu", 3) == 0) {
|
||||
device_printf(sc->dev, "CPU port at %d\n", port);
|
||||
sc->cpuports_mask |= (1 << port);
|
||||
sc->fixed_mask |= (1 << port);
|
||||
}
|
||||
free(portlabel, M_OFWPROP);
|
||||
}
|
||||
|
||||
fixed_link = OF_child(child);
|
||||
if (fixed_link) {
|
||||
*fixed_mask |= (1 << port);
|
||||
device_printf(sc->dev, "fixed port at %d\n", port);
|
||||
} else {
|
||||
device_printf(sc->dev, "PHY at port %d\n", port);
|
||||
if (fixed_link != 0 &&
|
||||
OF_getprop_alloc(fixed_link, "name", 1, (void **)&name) > 0) {
|
||||
if (strncmp(name, "fixed-link", 10) == 0) {
|
||||
/* Assume defaults: 1g - full-duplex. */
|
||||
sc->fixed_mask |= (1 << port);
|
||||
if (OF_getencprop(fixed_link, "speed", &speed,
|
||||
sizeof(speed)) > 0) {
|
||||
if (speed == 2500 &&
|
||||
(MVSWITCH(sc, MV88E6141) ||
|
||||
MVSWITCH(sc, MV88E6341))) {
|
||||
sc->fixed25_mask |= (1 << port);
|
||||
}
|
||||
}
|
||||
}
|
||||
free(name, M_OFWPROP);
|
||||
}
|
||||
if ((sc->fixed_mask & (1 << port)) != 0)
|
||||
device_printf(sc->dev, "fixed port at %d\n", port);
|
||||
else
|
||||
device_printf(sc->dev, "PHY at port %d\n", port);
|
||||
|
||||
return (0);
|
||||
}
|
||||
@ -344,11 +364,12 @@ e6000sw_attach_miibus(e6000sw_softc_t *sc, int port)
|
||||
static int
|
||||
e6000sw_attach(device_t dev)
|
||||
{
|
||||
etherswitch_vlangroup_t vg;
|
||||
e6000sw_softc_t *sc;
|
||||
phandle_t child;
|
||||
int err, port, vlangroup;
|
||||
int member_ports[E6000SW_NUM_VGROUPS];
|
||||
etherswitch_vlangroup_t vg;
|
||||
uint32_t reg;
|
||||
|
||||
err = 0;
|
||||
sc = device_get_softc(dev);
|
||||
@ -365,8 +386,7 @@ e6000sw_attach(device_t dev)
|
||||
bzero(member_ports, sizeof(member_ports));
|
||||
|
||||
for (child = OF_child(sc->node); child != 0; child = OF_peer(child)) {
|
||||
err = e6000sw_parse_child_fdt(sc, child, &sc->fixed_mask,
|
||||
&sc->cpuports_mask, &port, &vlangroup);
|
||||
err = e6000sw_parse_child_fdt(sc, child, &port, &vlangroup);
|
||||
if (err != 0) {
|
||||
device_printf(sc->dev, "failed to parse DTS\n");
|
||||
goto out_fail;
|
||||
@ -384,6 +404,30 @@ e6000sw_attach(device_t dev)
|
||||
goto out_fail;
|
||||
}
|
||||
|
||||
if (e6000sw_is_fixedport(sc, port)) {
|
||||
/* Link must be down to change speed force value. */
|
||||
reg = e6000sw_readreg(sc, REG_PORT(port), PSC_CONTROL);
|
||||
reg &= ~PSC_CONTROL_LINK_UP;
|
||||
reg |= PSC_CONTROL_FORCED_LINK;
|
||||
e6000sw_writereg(sc, REG_PORT(port), PSC_CONTROL, reg);
|
||||
|
||||
/*
|
||||
* Force speed, full-duplex, EEE off and flow-control
|
||||
* on.
|
||||
*/
|
||||
if (e6000sw_is_fixed25port(sc, port))
|
||||
reg = PSC_CONTROL_SPD2500;
|
||||
else
|
||||
reg = PSC_CONTROL_SPD1000;
|
||||
reg |= PSC_CONTROL_FORCED_DPX | PSC_CONTROL_FULLDPX |
|
||||
PSC_CONTROL_FORCED_LINK | PSC_CONTROL_LINK_UP |
|
||||
PSC_CONTROL_FORCED_FC | PSC_CONTROL_FC_ON |
|
||||
PSC_CONTROL_FORCED_SPD;
|
||||
if (MVSWITCH(sc, MV88E6141) || MVSWITCH(sc, MV88E6341))
|
||||
reg |= PSC_CONTROL_FORCED_EEE;
|
||||
e6000sw_writereg(sc, REG_PORT(port), PSC_CONTROL, reg);
|
||||
}
|
||||
|
||||
/* Don't attach miibus at CPU/fixed ports */
|
||||
if (!e6000sw_is_phyport(sc, port))
|
||||
continue;
|
||||
@ -604,20 +648,18 @@ e6000sw_getport(device_t dev, etherswitch_port_t *p)
|
||||
E6000SW_LOCK(sc);
|
||||
e6000sw_get_pvid(sc, p->es_port, &p->es_pvid);
|
||||
|
||||
if (e6000sw_is_cpuport(sc, p->es_port)) {
|
||||
p->es_flags |= ETHERSWITCH_PORT_CPU;
|
||||
if (e6000sw_is_fixedport(sc, p->es_port)) {
|
||||
if (e6000sw_is_cpuport(sc, p->es_port))
|
||||
p->es_flags |= ETHERSWITCH_PORT_CPU;
|
||||
ifmr = &p->es_ifmr;
|
||||
ifmr->ifm_status = IFM_ACTIVE | IFM_AVALID;
|
||||
ifmr->ifm_count = 0;
|
||||
ifmr->ifm_current = ifmr->ifm_active =
|
||||
IFM_ETHER | IFM_1000_T | IFM_FDX;
|
||||
ifmr->ifm_mask = 0;
|
||||
} else if (e6000sw_is_fixedport(sc, p->es_port)) {
|
||||
ifmr = &p->es_ifmr;
|
||||
ifmr->ifm_status = IFM_ACTIVE | IFM_AVALID;
|
||||
ifmr->ifm_count = 0;
|
||||
ifmr->ifm_current = ifmr->ifm_active =
|
||||
IFM_ETHER | IFM_1000_T | IFM_FDX;
|
||||
if (e6000sw_is_fixed25port(sc, p->es_port))
|
||||
ifmr->ifm_active = IFM_2500_T;
|
||||
else
|
||||
ifmr->ifm_active = IFM_1000_T;
|
||||
ifmr->ifm_active |= IFM_ETHER | IFM_FDX;
|
||||
ifmr->ifm_current = ifmr->ifm_active;
|
||||
ifmr->ifm_mask = 0;
|
||||
} else {
|
||||
mii = e6000sw_miiforphy(sc, p->es_port);
|
||||
@ -648,8 +690,7 @@ e6000sw_setport(device_t dev, etherswitch_port_t *p)
|
||||
E6000SW_LOCK(sc);
|
||||
if (p->es_pvid != 0)
|
||||
e6000sw_set_pvid(sc, p->es_port, p->es_pvid);
|
||||
if (!e6000sw_is_cpuport(sc, p->es_port) &&
|
||||
!e6000sw_is_fixedport(sc, p->es_port)) {
|
||||
if (e6000sw_is_phyport(sc, p->es_port)) {
|
||||
mii = e6000sw_miiforphy(sc, p->es_port);
|
||||
err = ifmedia_ioctl(mii->mii_ifp, &p->es_ifr, &mii->mii_media,
|
||||
SIOCSIFMEDIA);
|
||||
@ -966,6 +1007,13 @@ e6000sw_is_fixedport(e6000sw_softc_t *sc, int port)
|
||||
return ((sc->fixed_mask & (1 << port)) ? true : false);
|
||||
}
|
||||
|
||||
static __inline bool
|
||||
e6000sw_is_fixed25port(e6000sw_softc_t *sc, int port)
|
||||
{
|
||||
|
||||
return ((sc->fixed25_mask & (1 << port)) ? true : false);
|
||||
}
|
||||
|
||||
static __inline bool
|
||||
e6000sw_is_phyport(e6000sw_softc_t *sc, int port)
|
||||
{
|
||||
|
@ -42,6 +42,15 @@ struct atu_opt {
|
||||
* Definitions for the Marvell 88E6000 series Ethernet Switch.
|
||||
*/
|
||||
|
||||
/* Switch IDs. */
|
||||
#define MV88E6141 0x3400
|
||||
#define MV88E6341 0x3410
|
||||
#define MV88E6352 0x3520
|
||||
#define MV88E6172 0x1720
|
||||
#define MV88E6176 0x1760
|
||||
|
||||
#define MVSWITCH(_sc, id) ((_sc)->swid == (id))
|
||||
|
||||
/*
|
||||
* Switch Registers
|
||||
*/
|
||||
@ -64,6 +73,17 @@ struct atu_opt {
|
||||
#define PORT_STATUS_PHY_DETECT_MASK (1 << 12)
|
||||
|
||||
#define PSC_CONTROL 0x1
|
||||
#define PSC_CONTROL_FORCED_SPD (1 << 13)
|
||||
#define PSC_CONTROL_EEE_ON (1 << 9)
|
||||
#define PSC_CONTROL_FORCED_EEE (1 << 8)
|
||||
#define PSC_CONTROL_FC_ON (1 << 7)
|
||||
#define PSC_CONTROL_FORCED_FC (1 << 6)
|
||||
#define PSC_CONTROL_LINK_UP (1 << 5)
|
||||
#define PSC_CONTROL_FORCED_LINK (1 << 4)
|
||||
#define PSC_CONTROL_FULLDPX (1 << 3)
|
||||
#define PSC_CONTROL_FORCED_DPX (1 << 2)
|
||||
#define PSC_CONTROL_SPD2500 0x3
|
||||
#define PSC_CONTROL_SPD1000 0x2
|
||||
#define SWITCH_ID 0x3
|
||||
#define PORT_CONTROL 0x4
|
||||
#define PORT_CONTROL_1 0x5
|
||||
|
Loading…
Reference in New Issue
Block a user