summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLuiz Souza <luiz@netgate.com>2017-06-22 10:51:07 -0500
committerLuiz Souza <luiz@netgate.com>2017-06-22 10:51:07 -0500
commitb9f3af6b8a65f84f59910eac8f0f25655843059d (patch)
treecb0bb84868b16d0430f10e6fbe7082331fe03eb4
parentc3d78dab701406f5bc46cfc1267df5f24ed4ad7a (diff)
downloadFreeBSD-src-b9f3af6b8a65f84f59910eac8f0f25655843059d.zip
FreeBSD-src-b9f3af6b8a65f84f59910eac8f0f25655843059d.tar.gz
Fix the port based vlans for the Marvell e6000 series switches.
-rw-r--r--sys/dev/etherswitch/e6000sw/e6000sw.c173
-rw-r--r--sys/dev/etherswitch/e6000sw/e6000swreg.h6
2 files changed, 87 insertions, 92 deletions
diff --git a/sys/dev/etherswitch/e6000sw/e6000sw.c b/sys/dev/etherswitch/e6000sw/e6000sw.c
index cc79ba2..15701a7 100644
--- a/sys/dev/etherswitch/e6000sw/e6000sw.c
+++ b/sys/dev/etherswitch/e6000sw/e6000sw.c
@@ -72,6 +72,7 @@ typedef struct e6000sw_softc {
struct proc *kproc;
uint32_t swid;
+ uint32_t vlan_mode;
uint32_t cpuports_mask;
uint32_t fixed_mask;
uint32_t fixed25_mask;
@@ -80,16 +81,13 @@ typedef struct e6000sw_softc {
int sw_addr;
int num_ports;
boolean_t multi_chip;
-
- int vid[E6000SW_NUM_VGROUPS];
- int members[E6000SW_NUM_VGROUPS];
- int vgroup[E6000SW_MAX_PORTS];
} e6000sw_softc_t;
static etherswitch_info_t etherswitch_info = {
.es_nports = 0,
- .es_nvlangroups = E6000SW_NUM_VGROUPS,
+ .es_nvlangroups = 0,
.es_vlan_caps = ETHERSWITCH_VLAN_PORT,
+ .es_switch_caps = ETHERSWITCH_CAPS_PORTS_MASK,
.es_name = "Marvell 6000 series switch"
};
@@ -263,15 +261,14 @@ e6000sw_probe(device_t dev)
}
static int
-e6000sw_parse_child_fdt(e6000sw_softc_t *sc, phandle_t child, int *pport,
- int *pvlangroup)
+e6000sw_parse_child_fdt(e6000sw_softc_t *sc, phandle_t child, int *pport)
{
char *name, *portlabel;
int speed;
phandle_t fixed_link;
- uint32_t port, vlangroup;
+ uint32_t port;
- if (pport == NULL || pvlangroup == NULL)
+ if (pport == NULL)
return (ENXIO);
if (OF_getencprop(child, "reg", (void *)&port, sizeof(port)) < 0)
@@ -280,15 +277,6 @@ e6000sw_parse_child_fdt(e6000sw_softc_t *sc, phandle_t child, int *pport,
return (ENXIO);
*pport = port;
- if (OF_getencprop(child, "vlangroup", (void *)&vlangroup,
- sizeof(vlangroup)) > 0) {
- if (vlangroup >= E6000SW_NUM_VGROUPS)
- return (ENXIO);
- *pvlangroup = vlangroup;
- } else {
- *pvlangroup = -1;
- }
-
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);
@@ -364,11 +352,9 @@ 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];
+ int err, port;
uint32_t reg;
err = 0;
@@ -383,18 +369,14 @@ e6000sw_attach(device_t dev)
E6000SW_LOCK(sc);
e6000sw_setup(dev, sc);
- 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, &port, &vlangroup);
+ err = e6000sw_parse_child_fdt(sc, child, &port);
if (err != 0) {
device_printf(sc->dev, "failed to parse DTS\n");
goto out_fail;
}
- if (vlangroup != -1)
- member_ports[vlangroup] |= (1 << port);
-
/* Port is in use. */
sc->ports_mask |= (1 << port);
@@ -440,21 +422,10 @@ e6000sw_attach(device_t dev)
}
etherswitch_info.es_nports = sc->num_ports;
- for (port = 0; port < sc->num_ports; port++)
- sc->vgroup[port] = E6000SW_PORT_NO_VGROUP;
+ etherswitch_info.es_ports_mask[0] = sc->ports_mask;
- /* Set VLAN configuration */
+ /* Default to port vlan. */
e6000sw_port_vlan_conf(sc);
-
- /* Set vlangroups */
- for (vlangroup = 0; vlangroup < E6000SW_NUM_VGROUPS; vlangroup++)
- if (member_ports[vlangroup] != 0) {
- vg.es_vlangroup = vg.es_vid = vlangroup;
- vg.es_member_ports = vg.es_untagged_ports =
- member_ports[vlangroup];
- e6000sw_setvgroup(dev, &vg);
- }
-
E6000SW_UNLOCK(sc);
bus_generic_probe(dev);
@@ -597,12 +568,14 @@ e6000sw_getinfo(device_t dev)
}
static int
-e6000sw_getconf(device_t dev __unused, etherswitch_conf_t *conf)
+e6000sw_getconf(device_t dev, etherswitch_conf_t *conf)
{
+ struct e6000sw_softc *sc;
/* Return the VLAN mode. */
+ sc = device_get_softc(dev);
conf->cmd = ETHERSWITCH_CONF_VLAN_MODE;
- conf->vlan_mode = ETHERSWITCH_VLAN_PORT;
+ conf->vlan_mode = sc->vlan_mode;
return (0);
}
@@ -808,66 +781,78 @@ e6000sw_getvgroup_wrapper(device_t dev, etherswitch_vlangroup_t *vg)
}
static __inline void
-e6000sw_flush_port(e6000sw_softc_t *sc, int port)
+e6000sw_port_vlan_assign(e6000sw_softc_t *sc, int port, uint32_t fid,
+ uint32_t members)
{
uint32_t reg;
reg = e6000sw_readreg(sc, REG_PORT(port), PORT_VLAN_MAP);
reg &= ~PORT_VLAN_MAP_TABLE_MASK;
reg &= ~PORT_VLAN_MAP_FID_MASK;
+ reg |= members & PORT_VLAN_MAP_TABLE_MASK & ~(1 << port);
+ reg |= (fid << PORT_VLAN_MAP_FID) & PORT_VLAN_MAP_FID_MASK;
e6000sw_writereg(sc, REG_PORT(port), PORT_VLAN_MAP, reg);
- if (sc->vgroup[port] != E6000SW_PORT_NO_VGROUP) {
- /*
- * If port belonged somewhere, owner-group
- * should have its entry removed.
- */
- sc->members[sc->vgroup[port]] &= ~(1 << port);
- sc->vgroup[port] = E6000SW_PORT_NO_VGROUP;
- }
+ reg = e6000sw_readreg(sc, REG_PORT(port), PORT_CONTROL_1);
+ reg &= ~PORT_CONTROL_1_FID_MASK;
+ reg |= (fid >> 4) & PORT_CONTROL_1_FID_MASK;
+ e6000sw_writereg(sc, REG_PORT(port), PORT_CONTROL_1, reg);
}
-static __inline void
-e6000sw_port_assign_vgroup(e6000sw_softc_t *sc, int port, int fid, int vgroup,
- int members)
+static int
+e6000sw_set_port_vlan(e6000sw_softc_t *sc, etherswitch_vlangroup_t *vg)
{
- uint32_t reg;
+ uint32_t port;
- reg = e6000sw_readreg(sc, REG_PORT(port), PORT_VLAN_MAP);
- reg &= ~PORT_VLAN_MAP_TABLE_MASK;
- reg &= ~PORT_VLAN_MAP_FID_MASK;
- reg |= members & ~(1 << port);
- reg |= (fid << PORT_VLAN_MAP_FID) & PORT_VLAN_MAP_FID_MASK;
- e6000sw_writereg(sc, REG_PORT(port), PORT_VLAN_MAP, reg);
- sc->vgroup[port] = vgroup;
+ port = vg->es_vlangroup;
+ if (port > sc->num_ports)
+ return (EINVAL);
+
+ if (vg->es_member_ports != vg->es_untagged_ports) {
+ device_printf(sc->dev, "Tagged ports not supported.\n");
+ return (EINVAL);
+ }
+
+ e6000sw_port_vlan_assign(sc, port, port + 1, vg->es_untagged_ports);
+ vg->es_vid = port | ETHERSWITCH_VID_VALID;
+
+ return (0);
}
static int
e6000sw_setvgroup(device_t dev, etherswitch_vlangroup_t *vg)
{
e6000sw_softc_t *sc;
- int port, fid;
sc = device_get_softc(dev);
E6000SW_LOCK_ASSERT(sc, SA_XLOCKED);
- if (vg->es_vlangroup >= E6000SW_NUM_VGROUPS)
- return (EINVAL);
- if (vg->es_member_ports != vg->es_untagged_ports) {
- device_printf(dev, "Tagged ports not supported.\n");
+ if (sc->vlan_mode == ETHERSWITCH_VLAN_PORT)
+ return (e6000sw_set_port_vlan(sc, vg));
+
+ return (EINVAL);
+}
+
+static int
+e6000sw_get_port_vlan(e6000sw_softc_t *sc, etherswitch_vlangroup_t *vg)
+{
+ uint32_t port, reg;
+
+ port = vg->es_vlangroup;
+ if (port > sc->num_ports)
return (EINVAL);
- }
- 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[sc->vgroup[port]] & (1 << port)))
- e6000sw_flush_port(sc, port);
- if (vg->es_untagged_ports & (1 << port))
- e6000sw_port_assign_vgroup(sc, port, fid,
- vg->es_vlangroup, vg->es_untagged_ports);
+ if (!e6000sw_is_portenabled(sc, port)) {
+ vg->es_vid = port;
+ return (0);
}
- sc->vid[vg->es_vlangroup] = vg->es_vid;
- sc->members[vg->es_vlangroup] = vg->es_untagged_ports;
+
+ reg = e6000sw_readreg(sc, REG_PORT(port), PORT_VLAN_MAP);
+ vg->es_untagged_ports = vg->es_member_ports =
+ reg & PORT_VLAN_MAP_TABLE_MASK;
+ vg->es_vid = port | ETHERSWITCH_VID_VALID;
+ vg->es_fid = (reg & PORT_VLAN_MAP_FID_MASK) >> PORT_VLAN_MAP_FID;
+ reg = e6000sw_readreg(sc, REG_PORT(port), PORT_CONTROL_1);
+ vg->es_fid |= (reg & PORT_CONTROL_1_FID_MASK) << 4;
return (0);
}
@@ -880,14 +865,10 @@ e6000sw_getvgroup(device_t dev, etherswitch_vlangroup_t *vg)
sc = device_get_softc(dev);
E6000SW_LOCK_ASSERT(sc, SA_XLOCKED);
- if (vg->es_vlangroup >= E6000SW_NUM_VGROUPS)
- return (EINVAL);
- vg->es_untagged_ports = vg->es_member_ports =
- sc->members[vg->es_vlangroup];
- if (vg->es_untagged_ports != 0)
- vg->es_vid = ETHERSWITCH_VID_VALID;
+ if (sc->vlan_mode == ETHERSWITCH_VLAN_PORT)
+ return (e6000sw_get_port_vlan(sc, vg));
- return (0);
+ return (EINVAL);
}
static __inline struct mii_data*
@@ -1172,10 +1153,9 @@ e6000sw_setup(device_t dev, e6000sw_softc_t *sc)
static void
e6000sw_port_vlan_conf(e6000sw_softc_t *sc)
{
- int port, ret;
- device_t dev;
+ int i, port, ret;
+ uint32_t members;
- dev = sc->dev;
/* Disable all ports */
for (port = 0; port < sc->num_ports; port++) {
ret = e6000sw_readreg(sc, REG_PORT(port), PORT_CONTROL);
@@ -1207,8 +1187,23 @@ e6000sw_port_vlan_conf(e6000sw_softc_t *sc)
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));
+ e6000sw_writereg(sc, REG_PORT(port), PORT_CONTROL,
+ (ret | PORT_CONTROL_ENABLE));
+ }
+
+ /* Set VLAN mode. */
+ sc->vlan_mode = ETHERSWITCH_VLAN_PORT;
+ etherswitch_info.es_nvlangroups = sc->num_ports;
+ for (port = 0; port < sc->num_ports; port++) {
+ members = 0;
+ if (e6000sw_is_portenabled(sc, port)) {
+ for (i = 0; i < sc->num_ports; i++) {
+ if (i == port || !e6000sw_is_portenabled(sc, i))
+ continue;
+ members |= (1 << i);
+ }
+ }
+ e6000sw_port_vlan_assign(sc, port, port + 1, members);
}
}
diff --git a/sys/dev/etherswitch/e6000sw/e6000swreg.h b/sys/dev/etherswitch/e6000sw/e6000swreg.h
index 6a92377..f491ab3 100644
--- a/sys/dev/etherswitch/e6000sw/e6000swreg.h
+++ b/sys/dev/etherswitch/e6000sw/e6000swreg.h
@@ -87,6 +87,7 @@ struct atu_opt {
#define SWITCH_ID 0x3
#define PORT_CONTROL 0x4
#define PORT_CONTROL_1 0x5
+#define PORT_CONTROL_1_FID_MASK 0xf
#define PORT_VLAN_MAP 0x6
#define PORT_VID 0x7
#define PORT_ASSOCIATION_VECTOR 0xb
@@ -104,6 +105,7 @@ struct atu_opt {
#define PORT_VLAN_MAP_TABLE_MASK 0x7f
#define PORT_VLAN_MAP_FID 12
#define PORT_VLAN_MAP_FID_MASK 0xf000
+
/*
* Switch Global Register 1 accessed via REG_GLOBAL_ADDR
*/
@@ -201,9 +203,7 @@ struct atu_opt {
#define SCR_AND_MISC_DATA_CFG_MASK 0xf0
#define E6000SW_NUM_PHY_REGS 29
-#define E6000SW_NUM_VGROUPS 8
-#define E6000SW_MAX_PORTS 10
-#define E6000SW_PORT_NO_VGROUP -1
+#define E6000SW_MAX_PORTS 8
#define E6000SW_DEFAULT_AGETIME 20
#define E6000SW_RETRIES 100
#define E6000SW_SMI_TIMEOUT 16
OpenPOWER on IntegriCloud