mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2024-12-28 16:53:49 +00:00
net: docs: update the sample code in driver.rst
The sample code talks about single-queue devices and uses locks. Update it to something resembling more modern code. Make sure we mention use of READ_ONCE() / WRITE_ONCE(). Change the comment which talked about consumer on the xmit side. AFAIU xmit is the producer and completions are a consumer. Reviewed-by: Eric Dumazet <edumazet@google.com> Reviewed-by: Jesse Brandeburg <jesse.brandeburg@intel.com> Signed-off-by: Jakub Kicinski <kuba@kernel.org> Signed-off-by: Paolo Abeni <pabeni@redhat.com>
This commit is contained in:
parent
21cdc87fa9
commit
50762d9af3
@ -47,30 +47,43 @@ for a driver implementing scatter-gather this means:
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
static u32 drv_tx_avail(struct drv_ring *dr)
|
||||
{
|
||||
u32 used = READ_ONCE(dr->prod) - READ_ONCE(dr->cons);
|
||||
|
||||
return dr->tx_ring_size - (used & bp->tx_ring_mask);
|
||||
}
|
||||
|
||||
static netdev_tx_t drv_hard_start_xmit(struct sk_buff *skb,
|
||||
struct net_device *dev)
|
||||
{
|
||||
struct drv *dp = netdev_priv(dev);
|
||||
struct netdev_queue *txq;
|
||||
struct drv_ring *dr;
|
||||
int idx;
|
||||
|
||||
idx = skb_get_queue_mapping(skb);
|
||||
dr = dp->tx_rings[idx];
|
||||
txq = netdev_get_tx_queue(dev, idx);
|
||||
|
||||
lock_tx(dp);
|
||||
//...
|
||||
/* This is a hard error log it. */
|
||||
if (TX_BUFFS_AVAIL(dp) <= (skb_shinfo(skb)->nr_frags + 1)) {
|
||||
/* This should be a very rare race - log it. */
|
||||
if (drv_tx_avail(dr) <= skb_shinfo(skb)->nr_frags + 1) {
|
||||
netif_stop_queue(dev);
|
||||
unlock_tx(dp);
|
||||
printk(KERN_ERR PFX "%s: BUG! Tx Ring full when queue awake!\n",
|
||||
dev->name);
|
||||
netdev_warn(dev, "Tx Ring full when queue awake!\n");
|
||||
return NETDEV_TX_BUSY;
|
||||
}
|
||||
|
||||
//... queue packet to card ...
|
||||
//... update tx consumer index ...
|
||||
|
||||
if (TX_BUFFS_AVAIL(dp) <= (MAX_SKB_FRAGS + 1))
|
||||
netif_stop_queue(dev);
|
||||
netdev_tx_sent_queue(txq, skb->len);
|
||||
|
||||
//... update tx producer index using WRITE_ONCE() ...
|
||||
|
||||
if (!netif_txq_maybe_stop(txq, drv_tx_avail(dr),
|
||||
MAX_SKB_FRAGS + 1, 2 * MAX_SKB_FRAGS))
|
||||
dr->stats.stopped++;
|
||||
|
||||
//...
|
||||
unlock_tx(dp);
|
||||
//...
|
||||
return NETDEV_TX_OK;
|
||||
}
|
||||
@ -79,30 +92,10 @@ And then at the end of your TX reclamation event handling:
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
if (netif_queue_stopped(dp->dev) &&
|
||||
TX_BUFFS_AVAIL(dp) > (MAX_SKB_FRAGS + 1))
|
||||
netif_wake_queue(dp->dev);
|
||||
//... update tx consumer index using WRITE_ONCE() ...
|
||||
|
||||
For a non-scatter-gather supporting card, the three tests simply become:
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
/* This is a hard error log it. */
|
||||
if (TX_BUFFS_AVAIL(dp) <= 0)
|
||||
|
||||
and:
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
if (TX_BUFFS_AVAIL(dp) == 0)
|
||||
|
||||
and:
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
if (netif_queue_stopped(dp->dev) &&
|
||||
TX_BUFFS_AVAIL(dp) > 0)
|
||||
netif_wake_queue(dp->dev);
|
||||
netif_txq_completed_wake(txq, cmpl_pkts, cmpl_bytes,
|
||||
drv_tx_avail(dr), 2 * MAX_SKB_FRAGS);
|
||||
|
||||
Lockless queue stop / wake helper macros
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
Loading…
Reference in New Issue
Block a user