Introduce an xmit and work queue to allow switches to send frames on their own, which can be useful to implement control frames via Ethernet for instance.
Signed-off-by: Vivien Didelot <vivien.dide...@gmail.com> --- include/net/dsa.h | 5 +++++ net/dsa/dsa2.c | 6 ++++++ net/dsa/dsa_priv.h | 2 ++ net/dsa/switch.c | 15 +++++++++++++++ 4 files changed, 28 insertions(+) diff --git a/include/net/dsa.h b/include/net/dsa.h index 027bb67ebaf7..7b10a067b06d 100644 --- a/include/net/dsa.h +++ b/include/net/dsa.h @@ -275,6 +275,9 @@ struct dsa_switch { */ bool vlan_filtering; + struct work_struct xmit_work; + struct sk_buff_head xmit_queue; + unsigned long *bitmap; unsigned long _bitmap; @@ -283,6 +286,8 @@ struct dsa_switch { struct dsa_port ports[]; }; +void dsa_switch_xmit(struct dsa_switch *ds, struct sk_buff *skb); + static inline const struct dsa_port *dsa_to_port(struct dsa_switch *ds, int p) { return &ds->ports[p]; diff --git a/net/dsa/dsa2.c b/net/dsa/dsa2.c index 3b5f434cad3f..fb7318b20e0a 100644 --- a/net/dsa/dsa2.c +++ b/net/dsa/dsa2.c @@ -375,6 +375,9 @@ static int dsa_switch_setup(struct dsa_switch *ds) if (err) return err; + skb_queue_head_init(&ds->xmit_queue); + INIT_WORK(&ds->xmit_work, dsa_switch_xmit_work); + err = ds->ops->setup(ds); if (err < 0) return err; @@ -399,6 +402,9 @@ static void dsa_switch_teardown(struct dsa_switch *ds) if (ds->slave_mii_bus && ds->ops->phy_read) mdiobus_unregister(ds->slave_mii_bus); + cancel_work_sync(&ds->xmit_work); + skb_queue_purge(&ds->xmit_queue); + dsa_switch_unregister_notifier(ds); if (ds->devlink) { diff --git a/net/dsa/dsa_priv.h b/net/dsa/dsa_priv.h index 2a8ee4c6adc5..0ccb0eab6295 100644 --- a/net/dsa/dsa_priv.h +++ b/net/dsa/dsa_priv.h @@ -201,4 +201,6 @@ dsa_slave_to_master(const struct net_device *dev) /* switch.c */ int dsa_switch_register_notifier(struct dsa_switch *ds); void dsa_switch_unregister_notifier(struct dsa_switch *ds); +void dsa_switch_xmit_work(struct work_struct *work); + #endif diff --git a/net/dsa/switch.c b/net/dsa/switch.c index 7d8cd9bc0ecc..b39d246f0d55 100644 --- a/net/dsa/switch.c +++ b/net/dsa/switch.c @@ -371,3 +371,18 @@ void dsa_switch_unregister_notifier(struct dsa_switch *ds) if (err) dev_err(ds->dev, "failed to unregister notifier (%d)\n", err); } + +void dsa_switch_xmit(struct dsa_switch *ds, struct sk_buff *skb) +{ + skb_queue_tail(&ds->xmit_queue, skb); + schedule_work(&ds->xmit_work); +} + +void dsa_switch_xmit_work(struct work_struct *work) +{ + struct dsa_switch *ds = container_of(work, struct dsa_switch, xmit_work); + struct sk_buff *skb; + + while ((skb = skb_dequeue(&ds->xmit_queue)) != NULL) + dev_queue_xmit(skb); +} -- 2.21.0