diff --git a/net/dsa/dsa2.c b/net/dsa/dsa2.c index 8150e16aaa55e8bacd76e4033d3e6c2f52d0ef5e..dcd67801eca48cb97393968637babd8bc3003fab 100644 --- a/net/dsa/dsa2.c +++ b/net/dsa/dsa2.c @@ -49,6 +49,9 @@ int dsa_tree_notify(struct dsa_switch_tree *dst, unsigned long e, void *v) * Can be used to notify the switching fabric of events such as cross-chip * bridging between disjoint trees (such as islands of tagger-compatible * switches bridged by an incompatible middle switch). + * + * WARNING: this function is not reliable during probe time, because probing + * between trees is asynchronous and not all DSA trees might have probed. */ int dsa_broadcast(unsigned long e, void *v) { diff --git a/net/dsa/dsa_priv.h b/net/dsa/dsa_priv.h index 9ea637832ea9f4f499b703d5aea36e85e1877e94..b7a269e0513f9e8d69b7c25ed28caaaba4a2f710 100644 --- a/net/dsa/dsa_priv.h +++ b/net/dsa/dsa_priv.h @@ -261,8 +261,8 @@ int dsa_port_link_register_of(struct dsa_port *dp); void dsa_port_link_unregister_of(struct dsa_port *dp); int dsa_port_hsr_join(struct dsa_port *dp, struct net_device *hsr); void dsa_port_hsr_leave(struct dsa_port *dp, struct net_device *hsr); -int dsa_port_tag_8021q_vlan_add(struct dsa_port *dp, u16 vid); -void dsa_port_tag_8021q_vlan_del(struct dsa_port *dp, u16 vid); +int dsa_port_tag_8021q_vlan_add(struct dsa_port *dp, u16 vid, bool broadcast); +void dsa_port_tag_8021q_vlan_del(struct dsa_port *dp, u16 vid, bool broadcast); extern const struct phylink_mac_ops dsa_port_phylink_mac_ops; static inline bool dsa_port_offloads_bridge_port(struct dsa_port *dp, diff --git a/net/dsa/port.c b/net/dsa/port.c index 831d50d28d5990a6f1fdca377b7f0f7060c057ef..979042a64d1ad2cd72522d367a90337520a7dfa5 100644 --- a/net/dsa/port.c +++ b/net/dsa/port.c @@ -426,7 +426,9 @@ void dsa_port_bridge_leave(struct dsa_port *dp, struct net_device *br) err = dsa_broadcast(DSA_NOTIFIER_BRIDGE_LEAVE, &info); if (err) - pr_err("DSA: failed to notify DSA_NOTIFIER_BRIDGE_LEAVE\n"); + dev_err(dp->ds->dev, + "port %d failed to notify DSA_NOTIFIER_BRIDGE_LEAVE: %pe\n", + dp->index, ERR_PTR(err)); dsa_port_switchdev_unsync_attrs(dp); } @@ -525,8 +527,9 @@ void dsa_port_lag_leave(struct dsa_port *dp, struct net_device *lag) err = dsa_port_notify(dp, DSA_NOTIFIER_LAG_LEAVE, &info); if (err) - pr_err("DSA: failed to notify DSA_NOTIFIER_LAG_LEAVE: %d\n", - err); + dev_err(dp->ds->dev, + "port %d failed to notify DSA_NOTIFIER_LAG_LEAVE: %pe\n", + dp->index, ERR_PTR(err)); dsa_lag_unmap(dp->ds->dst, lag); } @@ -1306,10 +1309,12 @@ void dsa_port_hsr_leave(struct dsa_port *dp, struct net_device *hsr) err = dsa_port_notify(dp, DSA_NOTIFIER_HSR_LEAVE, &info); if (err) - pr_err("DSA: failed to notify DSA_NOTIFIER_HSR_LEAVE\n"); + dev_err(dp->ds->dev, + "port %d failed to notify DSA_NOTIFIER_HSR_LEAVE: %pe\n", + dp->index, ERR_PTR(err)); } -int dsa_port_tag_8021q_vlan_add(struct dsa_port *dp, u16 vid) +int dsa_port_tag_8021q_vlan_add(struct dsa_port *dp, u16 vid, bool broadcast) { struct dsa_notifier_tag_8021q_vlan_info info = { .tree_index = dp->ds->dst->index, @@ -1318,10 +1323,13 @@ int dsa_port_tag_8021q_vlan_add(struct dsa_port *dp, u16 vid) .vid = vid, }; - return dsa_broadcast(DSA_NOTIFIER_TAG_8021Q_VLAN_ADD, &info); + if (broadcast) + return dsa_broadcast(DSA_NOTIFIER_TAG_8021Q_VLAN_ADD, &info); + + return dsa_port_notify(dp, DSA_NOTIFIER_TAG_8021Q_VLAN_ADD, &info); } -void dsa_port_tag_8021q_vlan_del(struct dsa_port *dp, u16 vid) +void dsa_port_tag_8021q_vlan_del(struct dsa_port *dp, u16 vid, bool broadcast) { struct dsa_notifier_tag_8021q_vlan_info info = { .tree_index = dp->ds->dst->index, @@ -1331,8 +1339,12 @@ void dsa_port_tag_8021q_vlan_del(struct dsa_port *dp, u16 vid) }; int err; - err = dsa_broadcast(DSA_NOTIFIER_TAG_8021Q_VLAN_DEL, &info); + if (broadcast) + err = dsa_broadcast(DSA_NOTIFIER_TAG_8021Q_VLAN_DEL, &info); + else + err = dsa_port_notify(dp, DSA_NOTIFIER_TAG_8021Q_VLAN_DEL, &info); if (err) - pr_err("DSA: failed to notify tag_8021q VLAN deletion: %pe\n", - ERR_PTR(err)); + dev_err(dp->ds->dev, + "port %d failed to notify tag_8021q VLAN %d deletion: %pe\n", + dp->index, vid, ERR_PTR(err)); } diff --git a/net/dsa/tag_8021q.c b/net/dsa/tag_8021q.c index 654697ebb6f3904dce4464407533c52a264b52db..e6d5f3b4fd89a2a0b3c27d49fc00618763c1c857 100644 --- a/net/dsa/tag_8021q.c +++ b/net/dsa/tag_8021q.c @@ -362,12 +362,12 @@ int dsa_tag_8021q_bridge_join(struct dsa_switch *ds, continue; /* Install the RX VID of the targeted port in our VLAN table */ - err = dsa_port_tag_8021q_vlan_add(dp, targeted_rx_vid); + err = dsa_port_tag_8021q_vlan_add(dp, targeted_rx_vid, false); if (err) return err; /* Install our RX VID into the targeted port's VLAN table */ - err = dsa_port_tag_8021q_vlan_add(targeted_dp, rx_vid); + err = dsa_port_tag_8021q_vlan_add(targeted_dp, rx_vid, false); if (err) return err; } @@ -398,10 +398,10 @@ int dsa_tag_8021q_bridge_leave(struct dsa_switch *ds, continue; /* Remove the RX VID of the targeted port from our VLAN table */ - dsa_port_tag_8021q_vlan_del(dp, targeted_rx_vid); + dsa_port_tag_8021q_vlan_del(dp, targeted_rx_vid, true); /* Remove our RX VID from the targeted port's VLAN table */ - dsa_port_tag_8021q_vlan_del(targeted_dp, rx_vid); + dsa_port_tag_8021q_vlan_del(targeted_dp, rx_vid, true); } return 0; @@ -413,7 +413,8 @@ int dsa_tag_8021q_bridge_tx_fwd_offload(struct dsa_switch *ds, int port, { u16 tx_vid = dsa_8021q_bridge_tx_fwd_offload_vid(bridge_num); - return dsa_port_tag_8021q_vlan_add(dsa_to_port(ds, port), tx_vid); + return dsa_port_tag_8021q_vlan_add(dsa_to_port(ds, port), tx_vid, + true); } EXPORT_SYMBOL_GPL(dsa_tag_8021q_bridge_tx_fwd_offload); @@ -423,7 +424,7 @@ void dsa_tag_8021q_bridge_tx_fwd_unoffload(struct dsa_switch *ds, int port, { u16 tx_vid = dsa_8021q_bridge_tx_fwd_offload_vid(bridge_num); - dsa_port_tag_8021q_vlan_del(dsa_to_port(ds, port), tx_vid); + dsa_port_tag_8021q_vlan_del(dsa_to_port(ds, port), tx_vid, true); } EXPORT_SYMBOL_GPL(dsa_tag_8021q_bridge_tx_fwd_unoffload); @@ -450,7 +451,7 @@ static int dsa_tag_8021q_port_setup(struct dsa_switch *ds, int port) * L2 forwarding rules still take precedence when there are no VLAN * restrictions, so there are no concerns about leaking traffic. */ - err = dsa_port_tag_8021q_vlan_add(dp, rx_vid); + err = dsa_port_tag_8021q_vlan_add(dp, rx_vid, true); if (err) { dev_err(ds->dev, "Failed to apply RX VID %d to port %d: %pe\n", @@ -462,7 +463,7 @@ static int dsa_tag_8021q_port_setup(struct dsa_switch *ds, int port) vlan_vid_add(master, ctx->proto, rx_vid); /* Finally apply the TX VID on this port and on the CPU port */ - err = dsa_port_tag_8021q_vlan_add(dp, tx_vid); + err = dsa_port_tag_8021q_vlan_add(dp, tx_vid, true); if (err) { dev_err(ds->dev, "Failed to apply TX VID %d on port %d: %pe\n", @@ -489,11 +490,11 @@ static void dsa_tag_8021q_port_teardown(struct dsa_switch *ds, int port) master = dp->cpu_dp->master; - dsa_port_tag_8021q_vlan_del(dp, rx_vid); + dsa_port_tag_8021q_vlan_del(dp, rx_vid, false); vlan_vid_del(master, ctx->proto, rx_vid); - dsa_port_tag_8021q_vlan_del(dp, tx_vid); + dsa_port_tag_8021q_vlan_del(dp, tx_vid, false); } static int dsa_tag_8021q_setup(struct dsa_switch *ds)