aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid S. Miller <davem@davemloft.net>2021-02-16 14:02:46 -0800
committerDavid S. Miller <davem@davemloft.net>2021-02-16 14:02:46 -0800
commit455843d231f5772355a4663446361e3f9a3fe522 (patch)
treef274f922b50633cbda873252f5fcec2786fb3d4a
parent786621d200235c44e1d043b954f96212ac4dd272 (diff)
parent7f7ccdea8c730ff85ba9abc2297b9e2954d3ed19 (diff)
downloadbluetooth-next-455843d231f5772355a4663446361e3f9a3fe522.tar.gz
Merge branch 'Fix-buggy-brport-flags-offload-for-SJA1105-DSA'
Vladimir Oltean says: ==================== Fix buggy brport flags offload for SJA1105 DSA I am resending this series because the title and the patches were mixed up and these patches were lost. This series' cover letter was used as the merge commit for the unrelated "Fixing build breakage after "Merge branch 'Propagate-extack-for-switchdev-LANs-from-DSA'"" series, as can be seen below: https://git.kernel.org/pub/scm/linux/kernel/git/netdev/net-next.git/commit/?id=ca04422afd6998611a81d0ea1b61d5a5f4923f84 while the actual patches from the "Fix buggy brport flags offload for SJA1105 DSA" series were marked as superseded and not applied: https://patchwork.kernel.org/project/netdevbpf/cover/20210214155704.1784220-1-olteanv@gmail.com/ which they should have. I know with so many bugs I introduced it's hard to keep track, I'm sorry. Original series description: While testing software bridging on sja1105, I discovered that I managed to introduce two bugs in a single patch submitted recently to net-next. ==================== Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--drivers/net/dsa/sja1105/sja1105.h2
-rw-r--r--drivers/net/dsa/sja1105/sja1105_main.c117
2 files changed, 77 insertions, 42 deletions
diff --git a/drivers/net/dsa/sja1105/sja1105.h b/drivers/net/dsa/sja1105/sja1105.h
index 90f0f6f3124e4a..f9e87fb33da038 100644
--- a/drivers/net/dsa/sja1105/sja1105.h
+++ b/drivers/net/dsa/sja1105/sja1105.h
@@ -206,6 +206,8 @@ struct sja1105_private {
bool rgmii_tx_delay[SJA1105_NUM_PORTS];
bool best_effort_vlan_filtering;
unsigned long learn_ena;
+ unsigned long ucast_egress_floods;
+ unsigned long bcast_egress_floods;
const struct sja1105_info *info;
struct gpio_desc *reset_gpio;
struct spi_device *spidev;
diff --git a/drivers/net/dsa/sja1105/sja1105_main.c b/drivers/net/dsa/sja1105/sja1105_main.c
index 85a39d599ff3d2..7692338730df52 100644
--- a/drivers/net/dsa/sja1105/sja1105_main.c
+++ b/drivers/net/dsa/sja1105/sja1105_main.c
@@ -50,6 +50,12 @@ sja1105_port_allow_traffic(struct sja1105_l2_forwarding_entry *l2_fwd,
l2_fwd[from].reach_port &= ~BIT(to);
}
+static bool sja1105_can_forward(struct sja1105_l2_forwarding_entry *l2_fwd,
+ int from, int to)
+{
+ return !!(l2_fwd[from].reach_port & BIT(to));
+}
+
/* Structure used to temporarily transport device tree
* settings into sja1105_setup
*/
@@ -408,6 +414,12 @@ static int sja1105_init_l2_forwarding(struct sja1105_private *priv)
for (j = 0; j < SJA1105_NUM_TC; j++)
l2fwd[i].vlan_pmap[j] = j;
+ /* All ports start up with egress flooding enabled,
+ * including the CPU port.
+ */
+ priv->ucast_egress_floods |= BIT(i);
+ priv->bcast_egress_floods |= BIT(i);
+
if (i == upstream)
continue;
@@ -1571,6 +1583,50 @@ static int sja1105_mdb_del(struct dsa_switch *ds, int port,
return sja1105_fdb_del(ds, port, mdb->addr, mdb->vid);
}
+/* Common function for unicast and broadcast flood configuration.
+ * Flooding is configured between each {ingress, egress} port pair, and since
+ * the bridge's semantics are those of "egress flooding", it means we must
+ * enable flooding towards this port from all ingress ports that are in the
+ * same forwarding domain.
+ */
+static int sja1105_manage_flood_domains(struct sja1105_private *priv)
+{
+ struct sja1105_l2_forwarding_entry *l2_fwd;
+ struct dsa_switch *ds = priv->ds;
+ int from, to, rc;
+
+ l2_fwd = priv->static_config.tables[BLK_IDX_L2_FORWARDING].entries;
+
+ for (from = 0; from < ds->num_ports; from++) {
+ u64 fl_domain = 0, bc_domain = 0;
+
+ for (to = 0; to < priv->ds->num_ports; to++) {
+ if (!sja1105_can_forward(l2_fwd, from, to))
+ continue;
+
+ if (priv->ucast_egress_floods & BIT(to))
+ fl_domain |= BIT(to);
+ if (priv->bcast_egress_floods & BIT(to))
+ bc_domain |= BIT(to);
+ }
+
+ /* Nothing changed, nothing to do */
+ if (l2_fwd[from].fl_domain == fl_domain &&
+ l2_fwd[from].bc_domain == bc_domain)
+ continue;
+
+ l2_fwd[from].fl_domain = fl_domain;
+ l2_fwd[from].bc_domain = bc_domain;
+
+ rc = sja1105_dynamic_config_write(priv, BLK_IDX_L2_FORWARDING,
+ from, &l2_fwd[from], true);
+ if (rc < 0)
+ return rc;
+ }
+
+ return 0;
+}
+
static int sja1105_bridge_member(struct dsa_switch *ds, int port,
struct net_device *br, bool member)
{
@@ -1608,8 +1664,12 @@ static int sja1105_bridge_member(struct dsa_switch *ds, int port,
return rc;
}
- return sja1105_dynamic_config_write(priv, BLK_IDX_L2_FORWARDING,
- port, &l2_fwd[port], true);
+ rc = sja1105_dynamic_config_write(priv, BLK_IDX_L2_FORWARDING,
+ port, &l2_fwd[port], true);
+ if (rc)
+ return rc;
+
+ return sja1105_manage_flood_domains(priv);
}
static void sja1105_bridge_stp_state_set(struct dsa_switch *ds, int port,
@@ -3287,7 +3347,7 @@ static int sja1105_port_set_learning(struct sja1105_private *priv, int port,
mac = priv->static_config.tables[BLK_IDX_MAC_CONFIG].entries;
- mac[port].dyn_learn = !!(priv->learn_ena & BIT(port));
+ mac[port].dyn_learn = enabled;
rc = sja1105_dynamic_config_write(priv, BLK_IDX_MAC_CONFIG, port,
&mac[port], true);
@@ -3302,51 +3362,24 @@ static int sja1105_port_set_learning(struct sja1105_private *priv, int port,
return 0;
}
-/* Common function for unicast and broadcast flood configuration.
- * Flooding is configured between each {ingress, egress} port pair, and since
- * the bridge's semantics are those of "egress flooding", it means we must
- * enable flooding towards this port from all ingress ports that are in the
- * same bridge. In practice, we just enable flooding from all possible ingress
- * ports regardless of whether they're in the same bridge or not, since the
- * reach_port configuration will not allow flooded frames to leak across
- * bridging domains anyway.
- */
static int sja1105_port_ucast_bcast_flood(struct sja1105_private *priv, int to,
struct switchdev_brport_flags flags)
{
- struct sja1105_l2_forwarding_entry *l2_fwd;
- int from, rc;
-
- l2_fwd = priv->static_config.tables[BLK_IDX_L2_FORWARDING].entries;
-
- for (from = 0; from < priv->ds->num_ports; from++) {
- if (dsa_is_unused_port(priv->ds, from))
- continue;
- if (from == to)
- continue;
-
- /* Unicast */
- if (flags.mask & BR_FLOOD) {
- if (flags.val & BR_FLOOD)
- l2_fwd[from].fl_domain |= BIT(to);
- else
- l2_fwd[from].fl_domain &= ~BIT(to);
- }
- /* Broadcast */
- if (flags.mask & BR_BCAST_FLOOD) {
- if (flags.val & BR_BCAST_FLOOD)
- l2_fwd[from].bc_domain |= BIT(to);
- else
- l2_fwd[from].bc_domain &= ~BIT(to);
- }
+ if (flags.mask & BR_FLOOD) {
+ if (flags.val & BR_FLOOD)
+ priv->ucast_egress_floods |= BIT(to);
+ else
+ priv->ucast_egress_floods |= BIT(to);
+ }
- rc = sja1105_dynamic_config_write(priv, BLK_IDX_L2_FORWARDING,
- from, &l2_fwd[from], true);
- if (rc < 0)
- return rc;
+ if (flags.mask & BR_BCAST_FLOOD) {
+ if (flags.val & BR_BCAST_FLOOD)
+ priv->bcast_egress_floods |= BIT(to);
+ else
+ priv->bcast_egress_floods |= BIT(to);
}
- return 0;
+ return sja1105_manage_flood_domains(priv);
}
static int sja1105_port_mcast_flood(struct sja1105_private *priv, int to,