mirror of
https://github.com/edk2-porting/linux-next.git
synced 2024-12-16 09:13:55 +08:00
net: mscc: ocelot: convert the VLAN masks to a list
First and foremost, the driver currently allocates a constant sized 4K * u32 (16KB memory) array for the VLAN masks. However, a typical application might not need so many VLANs, so if we dynamically allocate the memory as needed, we might actually save some space. Secondly, we'll need to keep more advanced bookkeeping of the VLANs we have, notably we'll have to check how many untagged and how many tagged VLANs we have. This will have to stay in a structure, and allocating another 16 KB array for that is again a bit too much. So refactor the bridge VLANs in a linked list of structures. The hook points inside the driver are ocelot_vlan_member_add() and ocelot_vlan_member_del(), which previously used to operate on the ocelot->vlan_mask[vid] array element. ocelot_vlan_member_add() and ocelot_vlan_member_del() used to call ocelot_vlan_member_set() to commit to the ocelot->vlan_mask. Additionally, we had two calls to ocelot_vlan_member_set() from outside those callers, and those were directly from ocelot_vlan_init(). Those calls do not set up bridging service VLANs, instead they: - clear the VLAN table on reset - set the port pvid to the value used by this driver for VLAN-unaware standalone port operation (VID 0) So now, when we have a structure which represents actual bridge VLANs, VID 0 doesn't belong in that structure, since it is not part of the bridging layer. So delete the middle man, ocelot_vlan_member_set(), and let ocelot_vlan_init() call directly ocelot_vlant_set_mask() which forgoes any data structure and writes directly to hardware, which is all that we need. Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
parent
62a22bcbd3
commit
90e0aa8d10
@ -219,31 +219,79 @@ static void ocelot_port_set_pvid(struct ocelot *ocelot, int port,
|
||||
ANA_PORT_DROP_CFG, port);
|
||||
}
|
||||
|
||||
static int ocelot_vlan_member_set(struct ocelot *ocelot, u32 vlan_mask, u16 vid)
|
||||
static struct ocelot_bridge_vlan *ocelot_bridge_vlan_find(struct ocelot *ocelot,
|
||||
u16 vid)
|
||||
{
|
||||
int err;
|
||||
struct ocelot_bridge_vlan *vlan;
|
||||
|
||||
err = ocelot_vlant_set_mask(ocelot, vid, vlan_mask);
|
||||
if (err)
|
||||
return err;
|
||||
list_for_each_entry(vlan, &ocelot->vlans, list)
|
||||
if (vlan->vid == vid)
|
||||
return vlan;
|
||||
|
||||
ocelot->vlan_mask[vid] = vlan_mask;
|
||||
|
||||
return 0;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int ocelot_vlan_member_add(struct ocelot *ocelot, int port, u16 vid)
|
||||
{
|
||||
return ocelot_vlan_member_set(ocelot,
|
||||
ocelot->vlan_mask[vid] | BIT(port),
|
||||
vid);
|
||||
struct ocelot_bridge_vlan *vlan = ocelot_bridge_vlan_find(ocelot, vid);
|
||||
unsigned long portmask;
|
||||
int err;
|
||||
|
||||
if (vlan) {
|
||||
portmask = vlan->portmask | BIT(port);
|
||||
|
||||
err = ocelot_vlant_set_mask(ocelot, vid, portmask);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
vlan->portmask = portmask;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
vlan = kzalloc(sizeof(*vlan), GFP_KERNEL);
|
||||
if (!vlan)
|
||||
return -ENOMEM;
|
||||
|
||||
portmask = BIT(port);
|
||||
|
||||
err = ocelot_vlant_set_mask(ocelot, vid, portmask);
|
||||
if (err) {
|
||||
kfree(vlan);
|
||||
return err;
|
||||
}
|
||||
|
||||
vlan->vid = vid;
|
||||
vlan->portmask = portmask;
|
||||
INIT_LIST_HEAD(&vlan->list);
|
||||
list_add_tail(&vlan->list, &ocelot->vlans);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ocelot_vlan_member_del(struct ocelot *ocelot, int port, u16 vid)
|
||||
{
|
||||
return ocelot_vlan_member_set(ocelot,
|
||||
ocelot->vlan_mask[vid] & ~BIT(port),
|
||||
vid);
|
||||
struct ocelot_bridge_vlan *vlan = ocelot_bridge_vlan_find(ocelot, vid);
|
||||
unsigned long portmask;
|
||||
int err;
|
||||
|
||||
if (!vlan)
|
||||
return 0;
|
||||
|
||||
portmask = vlan->portmask & ~BIT(port);
|
||||
|
||||
err = ocelot_vlant_set_mask(ocelot, vid, portmask);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
vlan->portmask = portmask;
|
||||
if (vlan->portmask)
|
||||
return 0;
|
||||
|
||||
list_del(&vlan->list);
|
||||
kfree(vlan);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ocelot_port_vlan_filtering(struct ocelot *ocelot, int port,
|
||||
@ -369,13 +417,13 @@ static void ocelot_vlan_init(struct ocelot *ocelot)
|
||||
|
||||
/* Configure the port VLAN memberships */
|
||||
for (vid = 1; vid < VLAN_N_VID; vid++)
|
||||
ocelot_vlan_member_set(ocelot, 0, vid);
|
||||
ocelot_vlant_set_mask(ocelot, vid, 0);
|
||||
|
||||
/* Because VLAN filtering is enabled, we need VID 0 to get untagged
|
||||
* traffic. It is added automatically if 8021q module is loaded, but
|
||||
* we can't rely on it since module may be not loaded.
|
||||
*/
|
||||
ocelot_vlan_member_set(ocelot, all_ports, 0);
|
||||
ocelot_vlant_set_mask(ocelot, 0, all_ports);
|
||||
|
||||
/* Set vlan ingress filter mask to all ports but the CPU port by
|
||||
* default.
|
||||
@ -2127,6 +2175,7 @@ int ocelot_init(struct ocelot *ocelot)
|
||||
|
||||
INIT_LIST_HEAD(&ocelot->multicast);
|
||||
INIT_LIST_HEAD(&ocelot->pgids);
|
||||
INIT_LIST_HEAD(&ocelot->vlans);
|
||||
ocelot_detect_features(ocelot);
|
||||
ocelot_mact_init(ocelot);
|
||||
ocelot_vlan_init(ocelot);
|
||||
|
@ -568,6 +568,12 @@ struct ocelot_vlan {
|
||||
u16 vid;
|
||||
};
|
||||
|
||||
struct ocelot_bridge_vlan {
|
||||
u16 vid;
|
||||
unsigned long portmask;
|
||||
struct list_head list;
|
||||
};
|
||||
|
||||
enum ocelot_port_tag_config {
|
||||
/* all VLANs are egress-untagged */
|
||||
OCELOT_PORT_TAG_DISABLED = 0,
|
||||
@ -646,8 +652,7 @@ struct ocelot {
|
||||
|
||||
u8 base_mac[ETH_ALEN];
|
||||
|
||||
/* Keep track of the vlan port masks */
|
||||
u32 vlan_mask[VLAN_N_VID];
|
||||
struct list_head vlans;
|
||||
|
||||
/* Switches like VSC9959 have flooding per traffic class */
|
||||
int num_flooding_pgids;
|
||||
|
Loading…
Reference in New Issue
Block a user