summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/net/fddi/defza.c33
-rw-r--r--include/linux/netdevice.h1
-rw-r--r--net/core/dev.c13
3 files changed, 44 insertions, 3 deletions
diff --git a/drivers/net/fddi/defza.c b/drivers/net/fddi/defza.c
index 7d01b70f7ed8..3b7f10a5f06a 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 22e4ef7bb701..dc1d9ed33b31 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 a4d39b87b4e5..8497feea8fb5 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;