Commit ec5ae610 authored by Vladimir Oltean's avatar Vladimir Oltean Committed by David S. Miller

net: dsa: sja1105: save/restore VLANs using a delta commit method

Managing the VLAN table that is present in hardware will become very
difficult once we add a third operating state
(best_effort_vlan_filtering). That is because correct cleanup (not too
little, not too much) becomes virtually impossible, when VLANs can be
added from the bridge layer, from dsa_8021q for basic tagging, for
cross-chip bridging, as well as retagging rules for sub-VLANs and
cross-chip sub-VLANs. So we need to rethink VLAN interaction with the
switch in a more scalable way.

In preparation for that, use the priv->expect_dsa_8021q boolean to
classify any VLAN request received through .port_vlan_add or
.port_vlan_del towards either one of 2 internal lists: bridge VLANs and
dsa_8021q VLANs.

Then, implement a central sja1105_build_vlan_table method that creates a
VLAN configuration from scratch based on the 2 lists of VLANs kept by
the driver, and based on the VLAN awareness state. Currently, if we are
VLAN-unaware, install the dsa_8021q VLANs, otherwise the bridge VLANs.

Then, implement a delta commit procedure that identifies which VLANs
from this new configuration are actually different from the config
previously committed to hardware. We apply the delta through the dynamic
configuration interface (we don't reset the switch). The result is that
the hardware should see the exact sequence of operations as before this
patch.

This also helps remove the "br" argument passed to
dsa_8021q_crosschip_bridge_join, which it was only using to figure out
whether it should commit the configuration back to us or not, based on
the VLAN awareness state of the bridge. We can simplify that, by always
allowing those VLANs inside of our dsa_8021q_vlans list, and committing
those to hardware when necessary.
Signed-off-by: default avatarVladimir Oltean <vladimir.oltean@nxp.com>
Reviewed-by: default avatarFlorian Fainelli <f.fainelli@gmail.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 60b33aeb
...@@ -178,6 +178,14 @@ struct sja1105_flow_block { ...@@ -178,6 +178,14 @@ struct sja1105_flow_block {
int num_virtual_links; int num_virtual_links;
}; };
struct sja1105_bridge_vlan {
struct list_head list;
int port;
u16 vid;
bool pvid;
bool untagged;
};
enum sja1105_vlan_state { enum sja1105_vlan_state {
SJA1105_VLAN_UNAWARE, SJA1105_VLAN_UNAWARE,
SJA1105_VLAN_FILTERING_FULL, SJA1105_VLAN_FILTERING_FULL,
...@@ -191,6 +199,8 @@ struct sja1105_private { ...@@ -191,6 +199,8 @@ struct sja1105_private {
struct gpio_desc *reset_gpio; struct gpio_desc *reset_gpio;
struct spi_device *spidev; struct spi_device *spidev;
struct dsa_switch *ds; struct dsa_switch *ds;
struct list_head dsa_8021q_vlans;
struct list_head bridge_vlans;
struct list_head crosschip_links; struct list_head crosschip_links;
struct sja1105_flow_block flow_block; struct sja1105_flow_block flow_block;
struct sja1105_port ports[SJA1105_NUM_PORTS]; struct sja1105_port ports[SJA1105_NUM_PORTS];
......
This diff is collapsed.
...@@ -25,18 +25,14 @@ struct dsa_8021q_crosschip_link { ...@@ -25,18 +25,14 @@ struct dsa_8021q_crosschip_link {
int dsa_port_setup_8021q_tagging(struct dsa_switch *ds, int index, int dsa_port_setup_8021q_tagging(struct dsa_switch *ds, int index,
bool enabled); bool enabled);
int dsa_8021q_crosschip_link_apply(struct dsa_switch *ds, int port,
struct dsa_switch *other_ds,
int other_port, bool enabled);
int dsa_8021q_crosschip_bridge_join(struct dsa_switch *ds, int port, int dsa_8021q_crosschip_bridge_join(struct dsa_switch *ds, int port,
struct dsa_switch *other_ds, struct dsa_switch *other_ds,
int other_port, struct net_device *br, int other_port,
struct list_head *crosschip_links); struct list_head *crosschip_links);
int dsa_8021q_crosschip_bridge_leave(struct dsa_switch *ds, int port, int dsa_8021q_crosschip_bridge_leave(struct dsa_switch *ds, int port,
struct dsa_switch *other_ds, struct dsa_switch *other_ds,
int other_port, struct net_device *br, int other_port,
struct list_head *crosschip_links); struct list_head *crosschip_links);
struct sk_buff *dsa_8021q_xmit(struct sk_buff *skb, struct net_device *netdev, struct sk_buff *dsa_8021q_xmit(struct sk_buff *skb, struct net_device *netdev,
...@@ -60,16 +56,9 @@ int dsa_port_setup_8021q_tagging(struct dsa_switch *ds, int index, ...@@ -60,16 +56,9 @@ int dsa_port_setup_8021q_tagging(struct dsa_switch *ds, int index,
return 0; return 0;
} }
int dsa_8021q_crosschip_link_apply(struct dsa_switch *ds, int port,
struct dsa_switch *other_ds,
int other_port, bool enabled)
{
return 0;
}
int dsa_8021q_crosschip_bridge_join(struct dsa_switch *ds, int port, int dsa_8021q_crosschip_bridge_join(struct dsa_switch *ds, int port,
struct dsa_switch *other_ds, struct dsa_switch *other_ds,
int other_port, struct net_device *br, int other_port,
struct list_head *crosschip_links) struct list_head *crosschip_links)
{ {
return 0; return 0;
...@@ -77,7 +66,7 @@ int dsa_8021q_crosschip_bridge_join(struct dsa_switch *ds, int port, ...@@ -77,7 +66,7 @@ int dsa_8021q_crosschip_bridge_join(struct dsa_switch *ds, int port,
int dsa_8021q_crosschip_bridge_leave(struct dsa_switch *ds, int port, int dsa_8021q_crosschip_bridge_leave(struct dsa_switch *ds, int port,
struct dsa_switch *other_ds, struct dsa_switch *other_ds,
int other_port, struct net_device *br, int other_port,
struct list_head *crosschip_links) struct list_head *crosschip_links)
{ {
return 0; return 0;
......
...@@ -296,9 +296,9 @@ int dsa_port_setup_8021q_tagging(struct dsa_switch *ds, int port, bool enabled) ...@@ -296,9 +296,9 @@ int dsa_port_setup_8021q_tagging(struct dsa_switch *ds, int port, bool enabled)
} }
EXPORT_SYMBOL_GPL(dsa_port_setup_8021q_tagging); EXPORT_SYMBOL_GPL(dsa_port_setup_8021q_tagging);
int dsa_8021q_crosschip_link_apply(struct dsa_switch *ds, int port, static int dsa_8021q_crosschip_link_apply(struct dsa_switch *ds, int port,
struct dsa_switch *other_ds, struct dsa_switch *other_ds,
int other_port, bool enabled) int other_port, bool enabled)
{ {
u16 rx_vid = dsa_8021q_rx_vid(ds, port); u16 rx_vid = dsa_8021q_rx_vid(ds, port);
...@@ -308,7 +308,6 @@ int dsa_8021q_crosschip_link_apply(struct dsa_switch *ds, int port, ...@@ -308,7 +308,6 @@ int dsa_8021q_crosschip_link_apply(struct dsa_switch *ds, int port,
return dsa_8021q_vid_apply(other_ds, other_port, rx_vid, return dsa_8021q_vid_apply(other_ds, other_port, rx_vid,
BRIDGE_VLAN_INFO_UNTAGGED, enabled); BRIDGE_VLAN_INFO_UNTAGGED, enabled);
} }
EXPORT_SYMBOL_GPL(dsa_8021q_crosschip_link_apply);
static int dsa_8021q_crosschip_link_add(struct dsa_switch *ds, int port, static int dsa_8021q_crosschip_link_add(struct dsa_switch *ds, int port,
struct dsa_switch *other_ds, struct dsa_switch *other_ds,
...@@ -369,7 +368,7 @@ static void dsa_8021q_crosschip_link_del(struct dsa_switch *ds, ...@@ -369,7 +368,7 @@ static void dsa_8021q_crosschip_link_del(struct dsa_switch *ds,
*/ */
int dsa_8021q_crosschip_bridge_join(struct dsa_switch *ds, int port, int dsa_8021q_crosschip_bridge_join(struct dsa_switch *ds, int port,
struct dsa_switch *other_ds, struct dsa_switch *other_ds,
int other_port, struct net_device *br, int other_port,
struct list_head *crosschip_links) struct list_head *crosschip_links)
{ {
/* @other_upstream is how @other_ds reaches us. If we are part /* @other_upstream is how @other_ds reaches us. If we are part
...@@ -385,12 +384,10 @@ int dsa_8021q_crosschip_bridge_join(struct dsa_switch *ds, int port, ...@@ -385,12 +384,10 @@ int dsa_8021q_crosschip_bridge_join(struct dsa_switch *ds, int port,
if (rc) if (rc)
return rc; return rc;
if (!br_vlan_enabled(br)) { rc = dsa_8021q_crosschip_link_apply(ds, port, other_ds,
rc = dsa_8021q_crosschip_link_apply(ds, port, other_ds, other_port, true);
other_port, true); if (rc)
if (rc) return rc;
return rc;
}
rc = dsa_8021q_crosschip_link_add(ds, port, other_ds, rc = dsa_8021q_crosschip_link_add(ds, port, other_ds,
other_upstream, other_upstream,
...@@ -398,20 +395,14 @@ int dsa_8021q_crosschip_bridge_join(struct dsa_switch *ds, int port, ...@@ -398,20 +395,14 @@ int dsa_8021q_crosschip_bridge_join(struct dsa_switch *ds, int port,
if (rc) if (rc)
return rc; return rc;
if (!br_vlan_enabled(br)) { return dsa_8021q_crosschip_link_apply(ds, port, other_ds,
rc = dsa_8021q_crosschip_link_apply(ds, port, other_ds, other_upstream, true);
other_upstream, true);
if (rc)
return rc;
}
return 0;
} }
EXPORT_SYMBOL_GPL(dsa_8021q_crosschip_bridge_join); EXPORT_SYMBOL_GPL(dsa_8021q_crosschip_bridge_join);
int dsa_8021q_crosschip_bridge_leave(struct dsa_switch *ds, int port, int dsa_8021q_crosschip_bridge_leave(struct dsa_switch *ds, int port,
struct dsa_switch *other_ds, struct dsa_switch *other_ds,
int other_port, struct net_device *br, int other_port,
struct list_head *crosschip_links) struct list_head *crosschip_links)
{ {
int other_upstream = dsa_upstream_port(other_ds, other_port); int other_upstream = dsa_upstream_port(other_ds, other_port);
...@@ -431,14 +422,12 @@ int dsa_8021q_crosschip_bridge_leave(struct dsa_switch *ds, int port, ...@@ -431,14 +422,12 @@ int dsa_8021q_crosschip_bridge_leave(struct dsa_switch *ds, int port,
if (keep) if (keep)
continue; continue;
if (!br_vlan_enabled(br)) { rc = dsa_8021q_crosschip_link_apply(ds, port,
rc = dsa_8021q_crosschip_link_apply(ds, port, other_ds,
other_ds, other_port,
other_port, false);
false); if (rc)
if (rc) return rc;
return rc;
}
} }
} }
......
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