diff --git a/drivers/net/fddi/defza.c b/drivers/net/fddi/defza.c index 7d01b70f7ed8b4c8c66b6c8fb233e66791f20c82..3b7f10a5f06a660fbf6408f7adbcd0851ad79921 100644 --- a/drivers/net/fddi/defza.c +++ b/drivers/net/fddi/defza.c @@ -797,11 +797,40 @@ static void fza_tx_smt(struct net_device *dev) smt_tx_ptr = fp->mmio + readl_u(&fp->ring_smt_tx[i].buffer); len = readl_u(&fp->ring_smt_tx[i].rmc) & FZA_RING_PBC_MASK; - /* Queue the frame to the RMC transmit ring. */ - if (!netif_queue_stopped(dev)) + if (!netif_queue_stopped(dev)) { + if (dev_nit_active(dev)) { + struct sk_buff *skb; + + /* Length must be a multiple of 4 as only word + * reads are permitted! + */ + skb = fza_alloc_skb_irq(dev, (len + 3) & ~3); + if (!skb) + goto err_no_skb; /* Drop. */ + + skb_data_ptr = (struct fza_buffer_tx *) + skb->data; + + fza_reads(smt_tx_ptr, skb_data_ptr, + (len + 3) & ~3); + skb->dev = dev; + skb_reserve(skb, 3); /* Skip over PRH. */ + skb_put(skb, len - 3); + skb_reset_network_header(skb); + + dev_queue_xmit_nit(skb, dev); + + dev_kfree_skb_irq(skb); + +err_no_skb: + ; + } + + /* Queue the frame to the RMC transmit ring. */ fza_do_xmit((union fza_buffer_txp) { .mmio_ptr = smt_tx_ptr }, len, dev, 1); + } writel_o(FZA_RING_OWN_FZA, &fp->ring_smt_tx[i].own); fp->ring_smt_tx_index = diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index 22e4ef7bb7010a6cc205f5ed76c66e9a9ea0c79f..dc1d9ed33b3192e9406b17c3107b3235b28ff1b9 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h @@ -3645,6 +3645,7 @@ static __always_inline int ____dev_forward_skb(struct net_device *dev, return 0; } +bool dev_nit_active(struct net_device *dev); void dev_queue_xmit_nit(struct sk_buff *skb, struct net_device *dev); extern int netdev_budget; diff --git a/net/core/dev.c b/net/core/dev.c index a4d39b87b4e59f2db03f8e894e7ef83b6c7a80fa..8497feea8fb58401177c3056190351bfadea215d 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -1976,6 +1976,17 @@ static inline bool skb_loop_sk(struct packet_type *ptype, struct sk_buff *skb) return false; } +/** + * dev_nit_active - return true if any network interface taps are in use + * + * @dev: network device to check for the presence of taps + */ +bool dev_nit_active(struct net_device *dev) +{ + return !list_empty(&ptype_all) || !list_empty(&dev->ptype_all); +} +EXPORT_SYMBOL_GPL(dev_nit_active); + /* * Support routine. Sends outgoing frames to any network * taps currently in use. @@ -3233,7 +3244,7 @@ static int xmit_one(struct sk_buff *skb, struct net_device *dev, unsigned int len; int rc; - if (!list_empty(&ptype_all) || !list_empty(&dev->ptype_all)) + if (dev_nit_active(dev)) dev_queue_xmit_nit(skb, dev); len = skb->len;