@@ -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;
@@ -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,
@@ -3297,51 +3357,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,