Commit 51e4082c authored by Jakub Kicinski's avatar Jakub Kicinski

Merge branch 'vlan-improvements-for-ocelot-switch'

Vladimir Oltean says:

====================
VLAN improvements for Ocelot switch

The main reason why I started this work is that deleting the bridge mdb
entries fails when the bridge is deleted, as described here:
https://lore.kernel.org/netdev/20201015173355.564934-1-vladimir.oltean@nxp.com/

In short, that happens because the bridge mdb entries are added with a
vid of 1, but deletion is attempted with a vid of 0. So the deletion
code fails to find the mdb entries.

The solution is to make ocelot use a pvid of 0 when it is under a bridge
with vlan_filtering 0. When vlan_filtering is 1, the pvid of the bridge
is what is programmed into the hardware.

The patch series also uncovers more bugs and does some more cleanup, but
the above is the main idea behind it.
====================

Link: https://lore.kernel.org/r/20201031102916.667619-1-vladimir.oltean@nxp.comSigned-off-by: default avatarJakub Kicinski <kuba@kernel.org>
parents 802dcb43 9a720680
...@@ -112,10 +112,32 @@ static void felix_bridge_leave(struct dsa_switch *ds, int port, ...@@ -112,10 +112,32 @@ static void felix_bridge_leave(struct dsa_switch *ds, int port,
ocelot_port_bridge_leave(ocelot, port, br); ocelot_port_bridge_leave(ocelot, port, br);
} }
/* This callback needs to be present */
static int felix_vlan_prepare(struct dsa_switch *ds, int port, static int felix_vlan_prepare(struct dsa_switch *ds, int port,
const struct switchdev_obj_port_vlan *vlan) const struct switchdev_obj_port_vlan *vlan)
{ {
struct ocelot *ocelot = ds->priv;
u16 vid, flags = vlan->flags;
int err;
/* Ocelot switches copy frames as-is to the CPU, so the flags:
* egress-untagged or not, pvid or not, make no difference. This
* behavior is already better than what DSA just tries to approximate
* when it installs the VLAN with the same flags on the CPU port.
* Just accept any configuration, and don't let ocelot deny installing
* multiple native VLANs on the NPI port, because the switch doesn't
* look at the port tag settings towards the NPI interface anyway.
*/
if (port == ocelot->npi)
return 0;
for (vid = vlan->vid_begin; vid <= vlan->vid_end; vid++) {
err = ocelot_vlan_prepare(ocelot, port, vid,
flags & BRIDGE_VLAN_INFO_PVID,
flags & BRIDGE_VLAN_INFO_UNTAGGED);
if (err)
return err;
}
return 0; return 0;
} }
...@@ -135,9 +157,6 @@ static void felix_vlan_add(struct dsa_switch *ds, int port, ...@@ -135,9 +157,6 @@ static void felix_vlan_add(struct dsa_switch *ds, int port,
u16 vid; u16 vid;
int err; int err;
if (dsa_is_cpu_port(ds, port))
flags &= ~BRIDGE_VLAN_INFO_UNTAGGED;
for (vid = vlan->vid_begin; vid <= vlan->vid_end; vid++) { for (vid = vlan->vid_begin; vid <= vlan->vid_end; vid++) {
err = ocelot_vlan_add(ocelot, port, vid, err = ocelot_vlan_add(ocelot, port, vid,
flags & BRIDGE_VLAN_INFO_PVID, flags & BRIDGE_VLAN_INFO_PVID,
......
...@@ -147,42 +147,20 @@ static int ocelot_vlant_set_mask(struct ocelot *ocelot, u16 vid, u32 mask) ...@@ -147,42 +147,20 @@ static int ocelot_vlant_set_mask(struct ocelot *ocelot, u16 vid, u32 mask)
return ocelot_vlant_wait_for_completion(ocelot); return ocelot_vlant_wait_for_completion(ocelot);
} }
static int ocelot_port_set_native_vlan(struct ocelot *ocelot, int port, static void ocelot_port_set_native_vlan(struct ocelot *ocelot, int port,
u16 vid) struct ocelot_vlan native_vlan)
{ {
struct ocelot_port *ocelot_port = ocelot->ports[port]; struct ocelot_port *ocelot_port = ocelot->ports[port];
u32 val = 0; u32 val = 0;
if (ocelot_port->vid != vid) { ocelot_port->native_vlan = native_vlan;
/* Always permit deleting the native VLAN (vid = 0) */
if (ocelot_port->vid && vid) {
dev_err(ocelot->dev,
"Port already has a native VLAN: %d\n",
ocelot_port->vid);
return -EBUSY;
}
ocelot_port->vid = vid;
}
ocelot_rmw_gix(ocelot, REW_PORT_VLAN_CFG_PORT_VID(vid), ocelot_rmw_gix(ocelot, REW_PORT_VLAN_CFG_PORT_VID(native_vlan.vid),
REW_PORT_VLAN_CFG_PORT_VID_M, REW_PORT_VLAN_CFG_PORT_VID_M,
REW_PORT_VLAN_CFG, port); REW_PORT_VLAN_CFG, port);
if (ocelot_port->vlan_aware && !ocelot_port->vid)
/* If port is vlan-aware and tagged, drop untagged and priority
* tagged frames.
*/
val = ANA_PORT_DROP_CFG_DROP_UNTAGGED_ENA |
ANA_PORT_DROP_CFG_DROP_PRIO_S_TAGGED_ENA |
ANA_PORT_DROP_CFG_DROP_PRIO_C_TAGGED_ENA;
ocelot_rmw_gix(ocelot, val,
ANA_PORT_DROP_CFG_DROP_UNTAGGED_ENA |
ANA_PORT_DROP_CFG_DROP_PRIO_S_TAGGED_ENA |
ANA_PORT_DROP_CFG_DROP_PRIO_C_TAGGED_ENA,
ANA_PORT_DROP_CFG, port);
if (ocelot_port->vlan_aware) { if (ocelot_port->vlan_aware) {
if (ocelot_port->vid) if (native_vlan.valid)
/* Tag all frames except when VID == DEFAULT_VLAN */ /* Tag all frames except when VID == DEFAULT_VLAN */
val = REW_TAG_CFG_TAG_CFG(1); val = REW_TAG_CFG_TAG_CFG(1);
else else
...@@ -195,8 +173,38 @@ static int ocelot_port_set_native_vlan(struct ocelot *ocelot, int port, ...@@ -195,8 +173,38 @@ static int ocelot_port_set_native_vlan(struct ocelot *ocelot, int port,
ocelot_rmw_gix(ocelot, val, ocelot_rmw_gix(ocelot, val,
REW_TAG_CFG_TAG_CFG_M, REW_TAG_CFG_TAG_CFG_M,
REW_TAG_CFG, port); REW_TAG_CFG, port);
}
return 0; /* Default vlan to clasify for untagged frames (may be zero) */
static void ocelot_port_set_pvid(struct ocelot *ocelot, int port,
struct ocelot_vlan pvid_vlan)
{
struct ocelot_port *ocelot_port = ocelot->ports[port];
u32 val = 0;
ocelot_port->pvid_vlan = pvid_vlan;
if (!ocelot_port->vlan_aware)
pvid_vlan.vid = 0;
ocelot_rmw_gix(ocelot,
ANA_PORT_VLAN_CFG_VLAN_VID(pvid_vlan.vid),
ANA_PORT_VLAN_CFG_VLAN_VID_M,
ANA_PORT_VLAN_CFG, port);
/* If there's no pvid, we should drop not only untagged traffic (which
* happens automatically), but also 802.1p traffic which gets
* classified to VLAN 0, but that is always in our RX filter, so it
* would get accepted were it not for this setting.
*/
if (!pvid_vlan.valid && ocelot_port->vlan_aware)
val = ANA_PORT_DROP_CFG_DROP_PRIO_S_TAGGED_ENA |
ANA_PORT_DROP_CFG_DROP_PRIO_C_TAGGED_ENA;
ocelot_rmw_gix(ocelot, val,
ANA_PORT_DROP_CFG_DROP_PRIO_S_TAGGED_ENA |
ANA_PORT_DROP_CFG_DROP_PRIO_C_TAGGED_ENA,
ANA_PORT_DROP_CFG, port);
} }
int ocelot_port_vlan_filtering(struct ocelot *ocelot, int port, int ocelot_port_vlan_filtering(struct ocelot *ocelot, int port,
...@@ -233,24 +241,30 @@ int ocelot_port_vlan_filtering(struct ocelot *ocelot, int port, ...@@ -233,24 +241,30 @@ int ocelot_port_vlan_filtering(struct ocelot *ocelot, int port,
ANA_PORT_VLAN_CFG_VLAN_POP_CNT_M, ANA_PORT_VLAN_CFG_VLAN_POP_CNT_M,
ANA_PORT_VLAN_CFG, port); ANA_PORT_VLAN_CFG, port);
ocelot_port_set_native_vlan(ocelot, port, ocelot_port->vid); ocelot_port_set_pvid(ocelot, port, ocelot_port->pvid_vlan);
ocelot_port_set_native_vlan(ocelot, port, ocelot_port->native_vlan);
return 0; return 0;
} }
EXPORT_SYMBOL(ocelot_port_vlan_filtering); EXPORT_SYMBOL(ocelot_port_vlan_filtering);
/* Default vlan to clasify for untagged frames (may be zero) */ int ocelot_vlan_prepare(struct ocelot *ocelot, int port, u16 vid, bool pvid,
static void ocelot_port_set_pvid(struct ocelot *ocelot, int port, u16 pvid) bool untagged)
{ {
struct ocelot_port *ocelot_port = ocelot->ports[port]; struct ocelot_port *ocelot_port = ocelot->ports[port];
ocelot_rmw_gix(ocelot, /* Deny changing the native VLAN, but always permit deleting it */
ANA_PORT_VLAN_CFG_VLAN_VID(pvid), if (untagged && ocelot_port->native_vlan.vid != vid &&
ANA_PORT_VLAN_CFG_VLAN_VID_M, ocelot_port->native_vlan.valid) {
ANA_PORT_VLAN_CFG, port); dev_err(ocelot->dev,
"Port already has a native VLAN: %d\n",
ocelot_port->native_vlan.vid);
return -EBUSY;
}
ocelot_port->pvid = pvid; return 0;
} }
EXPORT_SYMBOL(ocelot_vlan_prepare);
int ocelot_vlan_add(struct ocelot *ocelot, int port, u16 vid, bool pvid, int ocelot_vlan_add(struct ocelot *ocelot, int port, u16 vid, bool pvid,
bool untagged) bool untagged)
...@@ -264,14 +278,21 @@ int ocelot_vlan_add(struct ocelot *ocelot, int port, u16 vid, bool pvid, ...@@ -264,14 +278,21 @@ int ocelot_vlan_add(struct ocelot *ocelot, int port, u16 vid, bool pvid,
return ret; return ret;
/* Default ingress vlan classification */ /* Default ingress vlan classification */
if (pvid) if (pvid) {
ocelot_port_set_pvid(ocelot, port, vid); struct ocelot_vlan pvid_vlan;
pvid_vlan.vid = vid;
pvid_vlan.valid = true;
ocelot_port_set_pvid(ocelot, port, pvid_vlan);
}
/* Untagged egress vlan clasification */ /* Untagged egress vlan clasification */
if (untagged) { if (untagged) {
ret = ocelot_port_set_native_vlan(ocelot, port, vid); struct ocelot_vlan native_vlan;
if (ret)
return ret; native_vlan.vid = vid;
native_vlan.valid = true;
ocelot_port_set_native_vlan(ocelot, port, native_vlan);
} }
return 0; return 0;
...@@ -290,12 +311,18 @@ int ocelot_vlan_del(struct ocelot *ocelot, int port, u16 vid) ...@@ -290,12 +311,18 @@ int ocelot_vlan_del(struct ocelot *ocelot, int port, u16 vid)
return ret; return ret;
/* Ingress */ /* Ingress */
if (ocelot_port->pvid == vid) if (ocelot_port->pvid_vlan.vid == vid) {
ocelot_port_set_pvid(ocelot, port, 0); struct ocelot_vlan pvid_vlan = {0};
ocelot_port_set_pvid(ocelot, port, pvid_vlan);
}
/* Egress */ /* Egress */
if (ocelot_port->vid == vid) if (ocelot_port->native_vlan.vid == vid) {
ocelot_port_set_native_vlan(ocelot, port, 0); struct ocelot_vlan native_vlan = {0};
ocelot_port_set_native_vlan(ocelot, port, native_vlan);
}
return 0; return 0;
} }
...@@ -542,26 +569,11 @@ EXPORT_SYMBOL(ocelot_get_txtstamp); ...@@ -542,26 +569,11 @@ EXPORT_SYMBOL(ocelot_get_txtstamp);
int ocelot_fdb_add(struct ocelot *ocelot, int port, int ocelot_fdb_add(struct ocelot *ocelot, int port,
const unsigned char *addr, u16 vid) const unsigned char *addr, u16 vid)
{ {
struct ocelot_port *ocelot_port = ocelot->ports[port];
int pgid = port; int pgid = port;
if (port == ocelot->npi) if (port == ocelot->npi)
pgid = PGID_CPU; pgid = PGID_CPU;
if (!vid) {
if (!ocelot_port->vlan_aware)
/* If the bridge is not VLAN aware and no VID was
* provided, set it to pvid to ensure the MAC entry
* matches incoming untagged packets
*/
vid = ocelot_port->pvid;
else
/* If the bridge is VLAN aware a VID must be provided as
* otherwise the learnt entry wouldn't match any frame.
*/
return -EINVAL;
}
return ocelot_mact_learn(ocelot, pgid, addr, vid, ENTRYTYPE_LOCKED); return ocelot_mact_learn(ocelot, pgid, addr, vid, ENTRYTYPE_LOCKED);
} }
EXPORT_SYMBOL(ocelot_fdb_add); EXPORT_SYMBOL(ocelot_fdb_add);
...@@ -1048,7 +1060,6 @@ static void ocelot_encode_ports_to_mdb(unsigned char *addr, ...@@ -1048,7 +1060,6 @@ static void ocelot_encode_ports_to_mdb(unsigned char *addr,
int ocelot_port_mdb_add(struct ocelot *ocelot, int port, int ocelot_port_mdb_add(struct ocelot *ocelot, int port,
const struct switchdev_obj_port_mdb *mdb) const struct switchdev_obj_port_mdb *mdb)
{ {
struct ocelot_port *ocelot_port = ocelot->ports[port];
unsigned char addr[ETH_ALEN]; unsigned char addr[ETH_ALEN];
struct ocelot_multicast *mc; struct ocelot_multicast *mc;
struct ocelot_pgid *pgid; struct ocelot_pgid *pgid;
...@@ -1057,9 +1068,6 @@ int ocelot_port_mdb_add(struct ocelot *ocelot, int port, ...@@ -1057,9 +1068,6 @@ int ocelot_port_mdb_add(struct ocelot *ocelot, int port,
if (port == ocelot->npi) if (port == ocelot->npi)
port = ocelot->num_phys_ports; port = ocelot->num_phys_ports;
if (!vid)
vid = ocelot_port->pvid;
mc = ocelot_multicast_get(ocelot, mdb->addr, vid); mc = ocelot_multicast_get(ocelot, mdb->addr, vid);
if (!mc) { if (!mc) {
/* New entry */ /* New entry */
...@@ -1108,7 +1116,6 @@ EXPORT_SYMBOL(ocelot_port_mdb_add); ...@@ -1108,7 +1116,6 @@ EXPORT_SYMBOL(ocelot_port_mdb_add);
int ocelot_port_mdb_del(struct ocelot *ocelot, int port, int ocelot_port_mdb_del(struct ocelot *ocelot, int port,
const struct switchdev_obj_port_mdb *mdb) const struct switchdev_obj_port_mdb *mdb)
{ {
struct ocelot_port *ocelot_port = ocelot->ports[port];
unsigned char addr[ETH_ALEN]; unsigned char addr[ETH_ALEN];
struct ocelot_multicast *mc; struct ocelot_multicast *mc;
struct ocelot_pgid *pgid; struct ocelot_pgid *pgid;
...@@ -1117,9 +1124,6 @@ int ocelot_port_mdb_del(struct ocelot *ocelot, int port, ...@@ -1117,9 +1124,6 @@ int ocelot_port_mdb_del(struct ocelot *ocelot, int port,
if (port == ocelot->npi) if (port == ocelot->npi)
port = ocelot->num_phys_ports; port = ocelot->num_phys_ports;
if (!vid)
vid = ocelot_port->pvid;
mc = ocelot_multicast_get(ocelot, mdb->addr, vid); mc = ocelot_multicast_get(ocelot, mdb->addr, vid);
if (!mc) if (!mc)
return -ENOENT; return -ENOENT;
...@@ -1174,6 +1178,7 @@ EXPORT_SYMBOL(ocelot_port_bridge_join); ...@@ -1174,6 +1178,7 @@ EXPORT_SYMBOL(ocelot_port_bridge_join);
int ocelot_port_bridge_leave(struct ocelot *ocelot, int port, int ocelot_port_bridge_leave(struct ocelot *ocelot, int port,
struct net_device *bridge) struct net_device *bridge)
{ {
struct ocelot_vlan pvid = {0}, native_vlan = {0};
struct switchdev_trans trans; struct switchdev_trans trans;
int ret; int ret;
...@@ -1192,8 +1197,10 @@ int ocelot_port_bridge_leave(struct ocelot *ocelot, int port, ...@@ -1192,8 +1197,10 @@ int ocelot_port_bridge_leave(struct ocelot *ocelot, int port,
if (ret) if (ret)
return ret; return ret;
ocelot_port_set_pvid(ocelot, port, 0); ocelot_port_set_pvid(ocelot, port, pvid);
return ocelot_port_set_native_vlan(ocelot, port, 0); ocelot_port_set_native_vlan(ocelot, port, native_vlan);
return 0;
} }
EXPORT_SYMBOL(ocelot_port_bridge_leave); EXPORT_SYMBOL(ocelot_port_bridge_leave);
......
...@@ -206,6 +206,17 @@ static void ocelot_port_adjust_link(struct net_device *dev) ...@@ -206,6 +206,17 @@ static void ocelot_port_adjust_link(struct net_device *dev)
ocelot_adjust_link(ocelot, port, dev->phydev); ocelot_adjust_link(ocelot, port, dev->phydev);
} }
static int ocelot_vlan_vid_prepare(struct net_device *dev, u16 vid, bool pvid,
bool untagged)
{
struct ocelot_port_private *priv = netdev_priv(dev);
struct ocelot_port *ocelot_port = &priv->port;
struct ocelot *ocelot = ocelot_port->ocelot;
int port = priv->chip_port;
return ocelot_vlan_prepare(ocelot, port, vid, pvid, untagged);
}
static int ocelot_vlan_vid_add(struct net_device *dev, u16 vid, bool pvid, static int ocelot_vlan_vid_add(struct net_device *dev, u16 vid, bool pvid,
bool untagged) bool untagged)
{ {
...@@ -409,7 +420,7 @@ static int ocelot_mc_unsync(struct net_device *dev, const unsigned char *addr) ...@@ -409,7 +420,7 @@ static int ocelot_mc_unsync(struct net_device *dev, const unsigned char *addr)
struct ocelot_port *ocelot_port = &priv->port; struct ocelot_port *ocelot_port = &priv->port;
struct ocelot *ocelot = ocelot_port->ocelot; struct ocelot *ocelot = ocelot_port->ocelot;
return ocelot_mact_forget(ocelot, addr, ocelot_port->pvid); return ocelot_mact_forget(ocelot, addr, ocelot_port->pvid_vlan.vid);
} }
static int ocelot_mc_sync(struct net_device *dev, const unsigned char *addr) static int ocelot_mc_sync(struct net_device *dev, const unsigned char *addr)
...@@ -418,8 +429,8 @@ static int ocelot_mc_sync(struct net_device *dev, const unsigned char *addr) ...@@ -418,8 +429,8 @@ static int ocelot_mc_sync(struct net_device *dev, const unsigned char *addr)
struct ocelot_port *ocelot_port = &priv->port; struct ocelot_port *ocelot_port = &priv->port;
struct ocelot *ocelot = ocelot_port->ocelot; struct ocelot *ocelot = ocelot_port->ocelot;
return ocelot_mact_learn(ocelot, PGID_CPU, addr, ocelot_port->pvid, return ocelot_mact_learn(ocelot, PGID_CPU, addr,
ENTRYTYPE_LOCKED); ocelot_port->pvid_vlan.vid, ENTRYTYPE_LOCKED);
} }
static void ocelot_set_rx_mode(struct net_device *dev) static void ocelot_set_rx_mode(struct net_device *dev)
...@@ -462,10 +473,10 @@ static int ocelot_port_set_mac_address(struct net_device *dev, void *p) ...@@ -462,10 +473,10 @@ static int ocelot_port_set_mac_address(struct net_device *dev, void *p)
const struct sockaddr *addr = p; const struct sockaddr *addr = p;
/* Learn the new net device MAC address in the mac table. */ /* Learn the new net device MAC address in the mac table. */
ocelot_mact_learn(ocelot, PGID_CPU, addr->sa_data, ocelot_port->pvid, ocelot_mact_learn(ocelot, PGID_CPU, addr->sa_data,
ENTRYTYPE_LOCKED); ocelot_port->pvid_vlan.vid, ENTRYTYPE_LOCKED);
/* Then forget the previous one. */ /* Then forget the previous one. */
ocelot_mact_forget(ocelot, dev->dev_addr, ocelot_port->pvid); ocelot_mact_forget(ocelot, dev->dev_addr, ocelot_port->pvid_vlan.vid);
ether_addr_copy(dev->dev_addr, addr->sa_data); ether_addr_copy(dev->dev_addr, addr->sa_data);
return 0; return 0;
...@@ -812,9 +823,14 @@ static int ocelot_port_obj_add_vlan(struct net_device *dev, ...@@ -812,9 +823,14 @@ static int ocelot_port_obj_add_vlan(struct net_device *dev,
u16 vid; u16 vid;
for (vid = vlan->vid_begin; vid <= vlan->vid_end; vid++) { for (vid = vlan->vid_begin; vid <= vlan->vid_end; vid++) {
ret = ocelot_vlan_vid_add(dev, vid, bool pvid = vlan->flags & BRIDGE_VLAN_INFO_PVID;
vlan->flags & BRIDGE_VLAN_INFO_PVID, bool untagged = vlan->flags & BRIDGE_VLAN_INFO_UNTAGGED;
vlan->flags & BRIDGE_VLAN_INFO_UNTAGGED);
if (switchdev_trans_ph_prepare(trans))
ret = ocelot_vlan_vid_prepare(dev, vid, pvid,
untagged);
else
ret = ocelot_vlan_vid_add(dev, vid, pvid, untagged);
if (ret) if (ret)
return ret; return ret;
} }
...@@ -1074,8 +1090,8 @@ int ocelot_probe_port(struct ocelot *ocelot, int port, struct regmap *target, ...@@ -1074,8 +1090,8 @@ int ocelot_probe_port(struct ocelot *ocelot, int port, struct regmap *target,
memcpy(dev->dev_addr, ocelot->base_mac, ETH_ALEN); memcpy(dev->dev_addr, ocelot->base_mac, ETH_ALEN);
dev->dev_addr[ETH_ALEN - 1] += port; dev->dev_addr[ETH_ALEN - 1] += port;
ocelot_mact_learn(ocelot, PGID_CPU, dev->dev_addr, ocelot_port->pvid, ocelot_mact_learn(ocelot, PGID_CPU, dev->dev_addr,
ENTRYTYPE_LOCKED); ocelot_port->pvid_vlan.vid, ENTRYTYPE_LOCKED);
ocelot_init_port(ocelot, port); ocelot_init_port(ocelot, port);
......
...@@ -571,18 +571,21 @@ struct ocelot_vcap_block { ...@@ -571,18 +571,21 @@ struct ocelot_vcap_block {
int pol_lpr; int pol_lpr;
}; };
struct ocelot_vlan {
bool valid;
u16 vid;
};
struct ocelot_port { struct ocelot_port {
struct ocelot *ocelot; struct ocelot *ocelot;
struct regmap *target; struct regmap *target;
bool vlan_aware; bool vlan_aware;
/* VLAN that untagged frames are classified to, on ingress */
/* Ingress default VLAN (pvid) */ struct ocelot_vlan pvid_vlan;
u16 pvid; /* The VLAN ID that will be transmitted as untagged, on egress */
struct ocelot_vlan native_vlan;
/* Egress default VLAN (vid) */
u16 vid;
u8 ptp_cmd; u8 ptp_cmd;
struct sk_buff_head tx_skbs; struct sk_buff_head tx_skbs;
...@@ -744,6 +747,8 @@ int ocelot_fdb_add(struct ocelot *ocelot, int port, ...@@ -744,6 +747,8 @@ int ocelot_fdb_add(struct ocelot *ocelot, int port,
const unsigned char *addr, u16 vid); const unsigned char *addr, u16 vid);
int ocelot_fdb_del(struct ocelot *ocelot, int port, int ocelot_fdb_del(struct ocelot *ocelot, int port,
const unsigned char *addr, u16 vid); const unsigned char *addr, u16 vid);
int ocelot_vlan_prepare(struct ocelot *ocelot, int port, u16 vid, bool pvid,
bool untagged);
int ocelot_vlan_add(struct ocelot *ocelot, int port, u16 vid, bool pvid, int ocelot_vlan_add(struct ocelot *ocelot, int port, u16 vid, bool pvid,
bool untagged); bool untagged);
int ocelot_vlan_del(struct ocelot *ocelot, int port, u16 vid); int ocelot_vlan_del(struct ocelot *ocelot, int port, u16 vid);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment