mirror of
https://github.com/opnsense/src.git
synced 2026-05-28 04:12:45 -04:00
Add the initial support for the Marvell 88E6141 and 88E6341 switches.
Right now the driver only supports port VLANs, so make sure etherswitch_getinfo() return the proper switch capabilities. Handle the cases where not all ports are in use (that will also require etherswitch cooperation). Sponsored by: Rubicon Communications, LLC (Netgate)
This commit is contained in:
parent
56c940ba49
commit
ff2748ec10
1 changed files with 66 additions and 18 deletions
|
|
@ -73,6 +73,8 @@ typedef struct e6000sw_softc {
|
|||
|
||||
uint32_t cpuports_mask;
|
||||
uint32_t fixed_mask;
|
||||
uint32_t ports_mask;
|
||||
int phy_base;
|
||||
int sw_addr;
|
||||
int num_ports;
|
||||
boolean_t multi_chip;
|
||||
|
|
@ -85,6 +87,7 @@ typedef struct e6000sw_softc {
|
|||
static etherswitch_info_t etherswitch_info = {
|
||||
.es_nports = 0,
|
||||
.es_nvlangroups = E6000SW_NUM_VGROUPS,
|
||||
.es_vlan_caps = ETHERSWITCH_VLAN_PORT,
|
||||
.es_name = "Marvell 6000 series switch"
|
||||
};
|
||||
|
||||
|
|
@ -95,6 +98,7 @@ static int e6000sw_detach(device_t);
|
|||
static int e6000sw_readphy(device_t, int, int);
|
||||
static int e6000sw_writephy(device_t, int, int, int);
|
||||
static etherswitch_info_t* e6000sw_getinfo(device_t);
|
||||
static int e6000sw_getconf(device_t, etherswitch_conf_t *);
|
||||
static void e6000sw_lock(device_t);
|
||||
static void e6000sw_unlock(device_t);
|
||||
static int e6000sw_getport(device_t, etherswitch_port_t *);
|
||||
|
|
@ -123,6 +127,7 @@ 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_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 *,
|
||||
unsigned int);
|
||||
|
||||
|
|
@ -142,6 +147,7 @@ static device_method_t e6000sw_methods[] = {
|
|||
|
||||
/* etherswitch interface */
|
||||
DEVMETHOD(etherswitch_getinfo, e6000sw_getinfo),
|
||||
DEVMETHOD(etherswitch_getconf, e6000sw_getconf),
|
||||
DEVMETHOD(etherswitch_lock, e6000sw_lock),
|
||||
DEVMETHOD(etherswitch_unlock, e6000sw_unlock),
|
||||
DEVMETHOD(etherswitch_getport, e6000sw_getport),
|
||||
|
|
@ -202,7 +208,6 @@ e6000sw_probe(device_t dev)
|
|||
return (ENXIO);
|
||||
|
||||
sc = device_get_softc(dev);
|
||||
bzero(sc, sizeof(e6000sw_softc_t));
|
||||
sc->dev = dev;
|
||||
sc->node = switch_node;
|
||||
|
||||
|
|
@ -219,14 +224,27 @@ e6000sw_probe(device_t dev)
|
|||
E6000SW_UNLOCK(sc);
|
||||
|
||||
switch (id & 0xfff0) {
|
||||
case 0x3400:
|
||||
description = "Marvell 88E6141";
|
||||
sc->phy_base = 0x10;
|
||||
sc->num_ports = 6;
|
||||
break;
|
||||
case 0x3410:
|
||||
description = "Marvell 88E6341";
|
||||
sc->phy_base = 0x10;
|
||||
sc->num_ports = 6;
|
||||
break;
|
||||
case 0x3520:
|
||||
description = "Marvell 88E6352";
|
||||
sc->num_ports = 7;
|
||||
break;
|
||||
case 0x1720:
|
||||
description = "Marvell 88E6172";
|
||||
sc->num_ports = 7;
|
||||
break;
|
||||
case 0x1760:
|
||||
description = "Marvell 88E6176";
|
||||
sc->num_ports = 7;
|
||||
break;
|
||||
default:
|
||||
sx_destroy(&sc->sx);
|
||||
|
|
@ -240,17 +258,17 @@ e6000sw_probe(device_t dev)
|
|||
}
|
||||
|
||||
static int
|
||||
e6000sw_parse_child_fdt(device_t dev, 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,
|
||||
uint32_t *fixed_mask, uint32_t *cpu_mask, int *pport, int *pvlangroup)
|
||||
{
|
||||
boolean_t fixed_link;
|
||||
char portlabel[100];
|
||||
uint32_t port, vlangroup;
|
||||
boolean_t fixed_link;
|
||||
|
||||
if (fixed_mask == NULL || cpu_mask == NULL || pport == NULL)
|
||||
return (ENXIO);
|
||||
|
||||
OF_getprop(child, "label", (void *)portlabel, 100);
|
||||
OF_getprop(child, "label", (void *)portlabel, sizeof(portlabel));
|
||||
OF_getencprop(child, "reg", (void *)&port, sizeof(port));
|
||||
|
||||
if (OF_getencprop(child, "vlangroup", (void *)&vlangroup,
|
||||
|
|
@ -262,22 +280,21 @@ e6000sw_parse_child_fdt(device_t dev, phandle_t child, uint32_t *fixed_mask,
|
|||
*pvlangroup = -1;
|
||||
}
|
||||
|
||||
if (port >= E6000SW_MAX_PORTS)
|
||||
if (port >= sc->num_ports)
|
||||
return (ENXIO);
|
||||
*pport = port;
|
||||
|
||||
if (strncmp(portlabel, "cpu", 3) == 0) {
|
||||
device_printf(dev, "CPU port at %d\n", port);
|
||||
device_printf(sc->dev, "CPU port at %d\n", port);
|
||||
*cpu_mask |= (1 << port);
|
||||
return (0);
|
||||
}
|
||||
|
||||
fixed_link = OF_child(child);
|
||||
if (fixed_link) {
|
||||
*fixed_mask |= (1 << port);
|
||||
device_printf(dev, "fixed port at %d\n", port);
|
||||
device_printf(sc->dev, "fixed port at %d\n", port);
|
||||
} else {
|
||||
device_printf(dev, "PHY at port %d\n", port);
|
||||
device_printf(sc->dev, "PHY at port %d\n", port);
|
||||
}
|
||||
|
||||
return (0);
|
||||
|
|
@ -314,7 +331,7 @@ e6000sw_attach_miibus(e6000sw_softc_t *sc, int port)
|
|||
|
||||
err = mii_attach(sc->dev, &sc->miibus[port], sc->ifp[port],
|
||||
e6000sw_ifmedia_upd, e6000sw_ifmedia_sts, BMSR_DEFCAPMASK,
|
||||
port, MII_OFFSET_ANY, 0);
|
||||
port + sc->phy_base, MII_OFFSET_ANY, 0);
|
||||
if (err != 0)
|
||||
return (err);
|
||||
|
||||
|
|
@ -343,7 +360,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(dev, child, &sc->fixed_mask,
|
||||
err = e6000sw_parse_child_fdt(sc, child, &sc->fixed_mask,
|
||||
&sc->cpuports_mask, &port, &vlangroup);
|
||||
if (err != 0) {
|
||||
device_printf(sc->dev, "failed to parse DTS\n");
|
||||
|
|
@ -353,7 +370,8 @@ e6000sw_attach(device_t dev)
|
|||
if (vlangroup != -1)
|
||||
member_ports[vlangroup] |= (1 << port);
|
||||
|
||||
sc->num_ports++;
|
||||
/* Port is in use. */
|
||||
sc->ports_mask |= (1 << port);
|
||||
|
||||
err = e6000sw_init_interface(sc, port);
|
||||
if (err != 0) {
|
||||
|
|
@ -529,6 +547,17 @@ e6000sw_getinfo(device_t dev)
|
|||
return (ðerswitch_info);
|
||||
}
|
||||
|
||||
static int
|
||||
e6000sw_getconf(device_t dev __unused, etherswitch_conf_t *conf)
|
||||
{
|
||||
|
||||
/* Return the VLAN mode. */
|
||||
conf->cmd = ETHERSWITCH_CONF_VLAN_MODE;
|
||||
conf->vlan_mode = ETHERSWITCH_VLAN_PORT;
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
static void
|
||||
e6000sw_lock(device_t dev)
|
||||
{
|
||||
|
|
@ -563,6 +592,8 @@ e6000sw_getport(device_t dev, etherswitch_port_t *p)
|
|||
|
||||
if (p->es_port >= sc->num_ports || p->es_port < 0)
|
||||
return (EINVAL);
|
||||
if (!e6000sw_is_portenabled(sc, p->es_port))
|
||||
return (0);
|
||||
|
||||
err = 0;
|
||||
E6000SW_LOCK(sc);
|
||||
|
|
@ -605,12 +636,15 @@ e6000sw_setport(device_t dev, etherswitch_port_t *p)
|
|||
|
||||
if (p->es_port >= sc->num_ports || p->es_port < 0)
|
||||
return (EINVAL);
|
||||
if (!e6000sw_is_portenabled(sc, p->es_port))
|
||||
return (0);
|
||||
|
||||
err = 0;
|
||||
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)) {
|
||||
if (!e6000sw_is_cpuport(sc, p->es_port) &&
|
||||
!e6000sw_is_fixedport(sc, p->es_port)) {
|
||||
mii = e6000sw_miiforphy(sc, p->es_port);
|
||||
err = ifmedia_ioctl(mii->mii_ifp, &p->es_ifr, &mii->mii_media,
|
||||
SIOCSIFMEDIA);
|
||||
|
|
@ -780,8 +814,7 @@ e6000sw_setvgroup(device_t dev, etherswitch_vlangroup_t *vg)
|
|||
vg->es_untagged_ports &= PORT_VLAN_MAP_TABLE_MASK;
|
||||
fid = vg->es_vlangroup + 1;
|
||||
for (port = 0; port < sc->num_ports; port++) {
|
||||
if ((sc->members[vg->es_vlangroup] & (1 << port)) ||
|
||||
(vg->es_untagged_ports & (1 << port)))
|
||||
if ((sc->members[sc->vgroup[port]] & (1 << port)))
|
||||
e6000sw_flush_port(sc, port);
|
||||
if (vg->es_untagged_ports & (1 << port))
|
||||
e6000sw_port_assign_vgroup(sc, port, fid,
|
||||
|
|
@ -805,7 +838,8 @@ e6000sw_getvgroup(device_t dev, etherswitch_vlangroup_t *vg)
|
|||
return (EINVAL);
|
||||
vg->es_untagged_ports = vg->es_member_ports =
|
||||
sc->members[vg->es_vlangroup];
|
||||
vg->es_vid = ETHERSWITCH_VID_VALID;
|
||||
if (vg->es_untagged_ports != 0)
|
||||
vg->es_vid = ETHERSWITCH_VID_VALID;
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
|
@ -936,6 +970,13 @@ e6000sw_is_phyport(e6000sw_softc_t *sc, int port)
|
|||
return ((phy_mask & (1 << port)) ? true : false);
|
||||
}
|
||||
|
||||
static __inline bool
|
||||
e6000sw_is_portenabled(e6000sw_softc_t *sc, int port)
|
||||
{
|
||||
|
||||
return ((sc->ports_mask & (1 << port)) ? true : false);
|
||||
}
|
||||
|
||||
static __inline int
|
||||
e6000sw_set_pvid(e6000sw_softc_t *sc, int port, int pvid)
|
||||
{
|
||||
|
|
@ -1010,7 +1051,8 @@ e6000sw_tick (void *arg)
|
|||
E6000SW_LOCK(sc);
|
||||
for (port = 0; port < sc->num_ports; port++) {
|
||||
/* Tick only on PHY ports */
|
||||
if (!e6000sw_is_phyport(sc, port))
|
||||
if (!e6000sw_is_portenabled(sc, port) ||
|
||||
!e6000sw_is_phyport(sc, port))
|
||||
continue;
|
||||
|
||||
mii = e6000sw_miiforphy(sc, port);
|
||||
|
|
@ -1090,6 +1132,8 @@ e6000sw_port_vlan_conf(e6000sw_softc_t *sc)
|
|||
|
||||
/* Set port priority */
|
||||
for (port = 0; port < sc->num_ports; port++) {
|
||||
if (!e6000sw_is_portenabled(sc, port))
|
||||
continue;
|
||||
ret = e6000sw_readreg(sc, REG_PORT(port), PORT_VID);
|
||||
ret &= ~PORT_VID_PRIORITY_MASK;
|
||||
e6000sw_writereg(sc, REG_PORT(port), PORT_VID, ret);
|
||||
|
|
@ -1097,6 +1141,8 @@ e6000sw_port_vlan_conf(e6000sw_softc_t *sc)
|
|||
|
||||
/* Set VID map */
|
||||
for (port = 0; port < sc->num_ports; port++) {
|
||||
if (!e6000sw_is_portenabled(sc, port))
|
||||
continue;
|
||||
ret = e6000sw_readreg(sc, REG_PORT(port), PORT_VID);
|
||||
ret &= ~PORT_VID_DEF_VID_MASK;
|
||||
ret |= (port + 1);
|
||||
|
|
@ -1105,6 +1151,8 @@ e6000sw_port_vlan_conf(e6000sw_softc_t *sc)
|
|||
|
||||
/* Enable all ports */
|
||||
for (port = 0; port < sc->num_ports; port++) {
|
||||
if (!e6000sw_is_portenabled(sc, port))
|
||||
continue;
|
||||
ret = e6000sw_readreg(sc, REG_PORT(port), PORT_CONTROL);
|
||||
e6000sw_writereg(sc, REG_PORT(port), PORT_CONTROL, (ret |
|
||||
PORT_CONTROL_ENABLE));
|
||||
|
|
|
|||
Loading…
Reference in a new issue