net: Remove ndo_xmit_flush netdev operation, use signalling instead.
As reported by Jesper Dangaard Brouer, for high packet rates the
overhead of having another indirect call in the TX path is
non-trivial.
There is the indirect call itself, and then there is all of the
reloading of the state to refetch the tail pointer value and
then write the device register.
Move to a more passive scheme, which requires very light modifications
to the device drivers.
The signal is a new skb->xmit_more value, if it is non-zero it means
that more SKBs are pending to be transmitted on the same queue as the
current SKB. And therefore, the driver may elide the tail pointer
update.
Right now skb->xmit_more is always zero.
Signed-off-by: David S. Miller <davem@davemloft.net>
diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
index 220c509..039b237 100644
--- a/include/linux/netdevice.h
+++ b/include/linux/netdevice.h
@@ -782,19 +782,6 @@
* (can also return NETDEV_TX_LOCKED iff NETIF_F_LLTX)
* Required can not be NULL.
*
- * void (*ndo_xmit_flush)(struct net_device *dev, u16 queue);
- * A driver implements this function when it wishes to support
- * deferred TX queue flushing. The idea is that the expensive
- * operation to trigger TX queue processing can be done after
- * N calls to ndo_start_xmit rather than being done every single
- * time. In this regime ndo_start_xmit will be called one or more
- * times, and then a final ndo_xmit_flush call will be made to
- * have the driver tell the device about the new pending TX queue
- * entries. The kernel keeps track of which queues need flushing
- * by monitoring skb->queue_mapping of the packets it submits to
- * ndo_start_xmit. This is the queue value that will be passed
- * to ndo_xmit_flush.
- *
* u16 (*ndo_select_queue)(struct net_device *dev, struct sk_buff *skb,
* void *accel_priv, select_queue_fallback_t fallback);
* Called to decide which queue to when device supports multiple
@@ -1018,7 +1005,6 @@
int (*ndo_stop)(struct net_device *dev);
netdev_tx_t (*ndo_start_xmit) (struct sk_buff *skb,
struct net_device *dev);
- void (*ndo_xmit_flush)(struct net_device *dev, u16 queue);
u16 (*ndo_select_queue)(struct net_device *dev,
struct sk_buff *skb,
void *accel_priv,
@@ -3447,15 +3433,8 @@
static inline netdev_tx_t __netdev_start_xmit(const struct net_device_ops *ops,
struct sk_buff *skb, struct net_device *dev)
{
- netdev_tx_t ret;
- u16 q;
-
- q = skb->queue_mapping;
- ret = ops->ndo_start_xmit(skb, dev);
- if (dev_xmit_complete(ret) && ops->ndo_xmit_flush)
- ops->ndo_xmit_flush(dev, q);
-
- return ret;
+ skb->xmit_more = 0;
+ return ops->ndo_start_xmit(skb, dev);
}
static inline netdev_tx_t netdev_start_xmit(struct sk_buff *skb, struct net_device *dev)
diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h
index 18ddf96..9b3802a 100644
--- a/include/linux/skbuff.h
+++ b/include/linux/skbuff.h
@@ -452,6 +452,7 @@
* @tc_verd: traffic control verdict
* @hash: the packet hash
* @queue_mapping: Queue mapping for multiqueue devices
+ * @xmit_more: More SKBs are pending for this queue
* @ndisc_nodetype: router type (from link layer)
* @ooo_okay: allow the mapping of a socket to a queue to be changed
* @l4_hash: indicate hash is a canonical 4-tuple hash over transport
@@ -558,6 +559,7 @@
__u16 queue_mapping;
kmemcheck_bitfield_begin(flags2);
+ __u8 xmit_more:1;
#ifdef CONFIG_IPV6_NDISC_NODETYPE
__u8 ndisc_nodetype:2;
#endif