Skip to content

Commit 97a69a0

Browse files
vladimirolteandavem330
authored andcommitted
net: dsa: Add support for deferred xmit
Some hardware needs to take work to get convinced to receive frames on the CPU port (such as the sja1105 which takes temporary L2 forwarding rules over SPI that last for a single frame). Such work needs a sleepable context, and because the regular .ndo_start_xmit is atomic, this cannot be done in the tagger. So introduce a generic DSA mechanism that sets up a transmit skb queue and a workqueue for deferred transmission. The new driver callback (.port_deferred_xmit) is in dsa_switch and not in the tagger because the operations that require sleeping typically also involve interacting with the hardware, and not simply skb manipulations. Therefore having it there simplifies the structure a bit and makes it unnecessary to export functions from the driver to the tagger. The driver is responsible of calling dsa_enqueue_skb which transfers it to the master netdevice. This is so that it has a chance of performing some more work afterwards, such as cleanup or TX timestamping. To tell DSA that skb xmit deferral is required, I have thought about changing the return type of the tagger .xmit from struct sk_buff * into a enum dsa_tx_t that could potentially encode a DSA_XMIT_DEFER value. But the trailer tagger is reallocating every skb on xmit and therefore making a valid use of the pointer return value. So instead of reworking the API in complicated ways, right now a boolean property in the newly introduced DSA_SKB_CB is set. Signed-off-by: Vladimir Oltean <[email protected]> Reviewed-by: Florian Fainelli <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent b68b0dd commit 97a69a0

File tree

3 files changed

+66
-12
lines changed

3 files changed

+66
-12
lines changed

include/net/dsa.h

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,7 @@ struct dsa_device_ops {
8585

8686
struct dsa_skb_cb {
8787
struct sk_buff *clone;
88+
bool deferred_xmit;
8889
};
8990

9091
struct __dsa_skb_cb {
@@ -205,6 +206,10 @@ struct dsa_port {
205206
struct net_device *bridge_dev;
206207
struct devlink_port devlink_port;
207208
struct phylink *pl;
209+
210+
struct work_struct xmit_work;
211+
struct sk_buff_head xmit_queue;
212+
208213
/*
209214
* Original copy of the master netdev ethtool_ops
210215
*/
@@ -539,6 +544,12 @@ struct dsa_switch_ops {
539544
struct sk_buff *clone, unsigned int type);
540545
bool (*port_rxtstamp)(struct dsa_switch *ds, int port,
541546
struct sk_buff *skb, unsigned int type);
547+
548+
/*
549+
* Deferred frame Tx
550+
*/
551+
netdev_tx_t (*port_deferred_xmit)(struct dsa_switch *ds, int port,
552+
struct sk_buff *skb);
542553
};
543554

544555
struct dsa_switch_driver {
@@ -634,6 +645,7 @@ static inline int call_dsa_notifiers(unsigned long val, struct net_device *dev,
634645
#define BRCM_TAG_GET_QUEUE(v) ((v) & 0xff)
635646

636647

648+
netdev_tx_t dsa_enqueue_skb(struct sk_buff *skb, struct net_device *dev);
637649
int dsa_port_get_phy_strings(struct dsa_port *dp, uint8_t *data);
638650
int dsa_port_get_ethtool_phy_stats(struct dsa_port *dp, uint64_t *data);
639651
int dsa_port_get_phy_sset_count(struct dsa_port *dp);

net/dsa/dsa_priv.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -174,6 +174,8 @@ int dsa_slave_resume(struct net_device *slave_dev);
174174
int dsa_slave_register_notifier(void);
175175
void dsa_slave_unregister_notifier(void);
176176

177+
void *dsa_defer_xmit(struct sk_buff *skb, struct net_device *dev);
178+
177179
static inline struct dsa_port *dsa_slave_to_port(const struct net_device *dev)
178180
{
179181
struct dsa_slave_priv *p = netdev_priv(dev);

net/dsa/slave.c

Lines changed: 52 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,9 @@ static int dsa_slave_close(struct net_device *dev)
120120
struct net_device *master = dsa_slave_to_master(dev);
121121
struct dsa_port *dp = dsa_slave_to_port(dev);
122122

123+
cancel_work_sync(&dp->xmit_work);
124+
skb_queue_purge(&dp->xmit_queue);
125+
123126
phylink_stop(dp->pl);
124127

125128
dsa_port_disable(dp);
@@ -430,6 +433,24 @@ static void dsa_skb_tx_timestamp(struct dsa_slave_priv *p,
430433
kfree_skb(clone);
431434
}
432435

436+
netdev_tx_t dsa_enqueue_skb(struct sk_buff *skb, struct net_device *dev)
437+
{
438+
/* SKB for netpoll still need to be mangled with the protocol-specific
439+
* tag to be successfully transmitted
440+
*/
441+
if (unlikely(netpoll_tx_running(dev)))
442+
return dsa_slave_netpoll_send_skb(dev, skb);
443+
444+
/* Queue the SKB for transmission on the parent interface, but
445+
* do not modify its EtherType
446+
*/
447+
skb->dev = dsa_slave_to_master(dev);
448+
dev_queue_xmit(skb);
449+
450+
return NETDEV_TX_OK;
451+
}
452+
EXPORT_SYMBOL_GPL(dsa_enqueue_skb);
453+
433454
static netdev_tx_t dsa_slave_xmit(struct sk_buff *skb, struct net_device *dev)
434455
{
435456
struct dsa_slave_priv *p = netdev_priv(dev);
@@ -452,23 +473,37 @@ static netdev_tx_t dsa_slave_xmit(struct sk_buff *skb, struct net_device *dev)
452473
*/
453474
nskb = p->xmit(skb, dev);
454475
if (!nskb) {
455-
kfree_skb(skb);
476+
if (!DSA_SKB_CB(skb)->deferred_xmit)
477+
kfree_skb(skb);
456478
return NETDEV_TX_OK;
457479
}
458480

459-
/* SKB for netpoll still need to be mangled with the protocol-specific
460-
* tag to be successfully transmitted
461-
*/
462-
if (unlikely(netpoll_tx_running(dev)))
463-
return dsa_slave_netpoll_send_skb(dev, nskb);
481+
return dsa_enqueue_skb(nskb, dev);
482+
}
464483

465-
/* Queue the SKB for transmission on the parent interface, but
466-
* do not modify its EtherType
467-
*/
468-
nskb->dev = dsa_slave_to_master(dev);
469-
dev_queue_xmit(nskb);
484+
void *dsa_defer_xmit(struct sk_buff *skb, struct net_device *dev)
485+
{
486+
struct dsa_port *dp = dsa_slave_to_port(dev);
470487

471-
return NETDEV_TX_OK;
488+
DSA_SKB_CB(skb)->deferred_xmit = true;
489+
490+
skb_queue_tail(&dp->xmit_queue, skb);
491+
schedule_work(&dp->xmit_work);
492+
return NULL;
493+
}
494+
EXPORT_SYMBOL_GPL(dsa_defer_xmit);
495+
496+
static void dsa_port_xmit_work(struct work_struct *work)
497+
{
498+
struct dsa_port *dp = container_of(work, struct dsa_port, xmit_work);
499+
struct dsa_switch *ds = dp->ds;
500+
struct sk_buff *skb;
501+
502+
if (unlikely(!ds->ops->port_deferred_xmit))
503+
return;
504+
505+
while ((skb = skb_dequeue(&dp->xmit_queue)) != NULL)
506+
ds->ops->port_deferred_xmit(ds, dp->index, skb);
472507
}
473508

474509
/* ethtool operations *******************************************************/
@@ -1318,6 +1353,9 @@ int dsa_slave_suspend(struct net_device *slave_dev)
13181353
if (!netif_running(slave_dev))
13191354
return 0;
13201355

1356+
cancel_work_sync(&dp->xmit_work);
1357+
skb_queue_purge(&dp->xmit_queue);
1358+
13211359
netif_device_detach(slave_dev);
13221360

13231361
rtnl_lock();
@@ -1405,6 +1443,8 @@ int dsa_slave_create(struct dsa_port *port)
14051443
}
14061444
p->dp = port;
14071445
INIT_LIST_HEAD(&p->mall_tc_list);
1446+
INIT_WORK(&port->xmit_work, dsa_port_xmit_work);
1447+
skb_queue_head_init(&port->xmit_queue);
14081448
p->xmit = cpu_dp->tag_ops->xmit;
14091449
port->slave = slave_dev;
14101450

0 commit comments

Comments
 (0)