162306a36Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0 */ 262306a36Sopenharmony_ci#ifndef _LINUX_NET_QUEUES_H 362306a36Sopenharmony_ci#define _LINUX_NET_QUEUES_H 462306a36Sopenharmony_ci 562306a36Sopenharmony_ci#include <linux/netdevice.h> 662306a36Sopenharmony_ci 762306a36Sopenharmony_ci/** 862306a36Sopenharmony_ci * DOC: Lockless queue stopping / waking helpers. 962306a36Sopenharmony_ci * 1062306a36Sopenharmony_ci * The netif_txq_maybe_stop() and __netif_txq_completed_wake() 1162306a36Sopenharmony_ci * macros are designed to safely implement stopping 1262306a36Sopenharmony_ci * and waking netdev queues without full lock protection. 1362306a36Sopenharmony_ci * 1462306a36Sopenharmony_ci * We assume that there can be no concurrent stop attempts and no concurrent 1562306a36Sopenharmony_ci * wake attempts. The try-stop should happen from the xmit handler, 1662306a36Sopenharmony_ci * while wake up should be triggered from NAPI poll context. 1762306a36Sopenharmony_ci * The two may run concurrently (single producer, single consumer). 1862306a36Sopenharmony_ci * 1962306a36Sopenharmony_ci * The try-stop side is expected to run from the xmit handler and therefore 2062306a36Sopenharmony_ci * it does not reschedule Tx (netif_tx_start_queue() instead of 2162306a36Sopenharmony_ci * netif_tx_wake_queue()). Uses of the ``stop`` macros outside of the xmit 2262306a36Sopenharmony_ci * handler may lead to xmit queue being enabled but not run. 2362306a36Sopenharmony_ci * The waking side does not have similar context restrictions. 2462306a36Sopenharmony_ci * 2562306a36Sopenharmony_ci * The macros guarantee that rings will not remain stopped if there's 2662306a36Sopenharmony_ci * space available, but they do *not* prevent false wake ups when 2762306a36Sopenharmony_ci * the ring is full! Drivers should check for ring full at the start 2862306a36Sopenharmony_ci * for the xmit handler. 2962306a36Sopenharmony_ci * 3062306a36Sopenharmony_ci * All descriptor ring indexes (and other relevant shared state) must 3162306a36Sopenharmony_ci * be updated before invoking the macros. 3262306a36Sopenharmony_ci */ 3362306a36Sopenharmony_ci 3462306a36Sopenharmony_ci#define netif_txq_try_stop(txq, get_desc, start_thrs) \ 3562306a36Sopenharmony_ci ({ \ 3662306a36Sopenharmony_ci int _res; \ 3762306a36Sopenharmony_ci \ 3862306a36Sopenharmony_ci netif_tx_stop_queue(txq); \ 3962306a36Sopenharmony_ci /* Producer index and stop bit must be visible \ 4062306a36Sopenharmony_ci * to consumer before we recheck. \ 4162306a36Sopenharmony_ci * Pairs with a barrier in __netif_txq_completed_wake(). \ 4262306a36Sopenharmony_ci */ \ 4362306a36Sopenharmony_ci smp_mb__after_atomic(); \ 4462306a36Sopenharmony_ci \ 4562306a36Sopenharmony_ci /* We need to check again in a case another \ 4662306a36Sopenharmony_ci * CPU has just made room available. \ 4762306a36Sopenharmony_ci */ \ 4862306a36Sopenharmony_ci _res = 0; \ 4962306a36Sopenharmony_ci if (unlikely(get_desc >= start_thrs)) { \ 5062306a36Sopenharmony_ci netif_tx_start_queue(txq); \ 5162306a36Sopenharmony_ci _res = -1; \ 5262306a36Sopenharmony_ci } \ 5362306a36Sopenharmony_ci _res; \ 5462306a36Sopenharmony_ci }) \ 5562306a36Sopenharmony_ci 5662306a36Sopenharmony_ci/** 5762306a36Sopenharmony_ci * netif_txq_maybe_stop() - locklessly stop a Tx queue, if needed 5862306a36Sopenharmony_ci * @txq: struct netdev_queue to stop/start 5962306a36Sopenharmony_ci * @get_desc: get current number of free descriptors (see requirements below!) 6062306a36Sopenharmony_ci * @stop_thrs: minimal number of available descriptors for queue to be left 6162306a36Sopenharmony_ci * enabled 6262306a36Sopenharmony_ci * @start_thrs: minimal number of descriptors to re-enable the queue, can be 6362306a36Sopenharmony_ci * equal to @stop_thrs or higher to avoid frequent waking 6462306a36Sopenharmony_ci * 6562306a36Sopenharmony_ci * All arguments may be evaluated multiple times, beware of side effects. 6662306a36Sopenharmony_ci * @get_desc must be a formula or a function call, it must always 6762306a36Sopenharmony_ci * return up-to-date information when evaluated! 6862306a36Sopenharmony_ci * Expected to be used from ndo_start_xmit, see the comment on top of the file. 6962306a36Sopenharmony_ci * 7062306a36Sopenharmony_ci * Returns: 7162306a36Sopenharmony_ci * 0 if the queue was stopped 7262306a36Sopenharmony_ci * 1 if the queue was left enabled 7362306a36Sopenharmony_ci * -1 if the queue was re-enabled (raced with waking) 7462306a36Sopenharmony_ci */ 7562306a36Sopenharmony_ci#define netif_txq_maybe_stop(txq, get_desc, stop_thrs, start_thrs) \ 7662306a36Sopenharmony_ci ({ \ 7762306a36Sopenharmony_ci int _res; \ 7862306a36Sopenharmony_ci \ 7962306a36Sopenharmony_ci _res = 1; \ 8062306a36Sopenharmony_ci if (unlikely(get_desc < stop_thrs)) \ 8162306a36Sopenharmony_ci _res = netif_txq_try_stop(txq, get_desc, start_thrs); \ 8262306a36Sopenharmony_ci _res; \ 8362306a36Sopenharmony_ci }) \ 8462306a36Sopenharmony_ci 8562306a36Sopenharmony_ci/* Variant of netdev_tx_completed_queue() which guarantees smp_mb() if 8662306a36Sopenharmony_ci * @bytes != 0, regardless of kernel config. 8762306a36Sopenharmony_ci */ 8862306a36Sopenharmony_cistatic inline void 8962306a36Sopenharmony_cinetdev_txq_completed_mb(struct netdev_queue *dev_queue, 9062306a36Sopenharmony_ci unsigned int pkts, unsigned int bytes) 9162306a36Sopenharmony_ci{ 9262306a36Sopenharmony_ci if (IS_ENABLED(CONFIG_BQL)) 9362306a36Sopenharmony_ci netdev_tx_completed_queue(dev_queue, pkts, bytes); 9462306a36Sopenharmony_ci else if (bytes) 9562306a36Sopenharmony_ci smp_mb(); 9662306a36Sopenharmony_ci} 9762306a36Sopenharmony_ci 9862306a36Sopenharmony_ci/** 9962306a36Sopenharmony_ci * __netif_txq_completed_wake() - locklessly wake a Tx queue, if needed 10062306a36Sopenharmony_ci * @txq: struct netdev_queue to stop/start 10162306a36Sopenharmony_ci * @pkts: number of packets completed 10262306a36Sopenharmony_ci * @bytes: number of bytes completed 10362306a36Sopenharmony_ci * @get_desc: get current number of free descriptors (see requirements below!) 10462306a36Sopenharmony_ci * @start_thrs: minimal number of descriptors to re-enable the queue 10562306a36Sopenharmony_ci * @down_cond: down condition, predicate indicating that the queue should 10662306a36Sopenharmony_ci * not be woken up even if descriptors are available 10762306a36Sopenharmony_ci * 10862306a36Sopenharmony_ci * All arguments may be evaluated multiple times. 10962306a36Sopenharmony_ci * @get_desc must be a formula or a function call, it must always 11062306a36Sopenharmony_ci * return up-to-date information when evaluated! 11162306a36Sopenharmony_ci * Reports completed pkts/bytes to BQL. 11262306a36Sopenharmony_ci * 11362306a36Sopenharmony_ci * Returns: 11462306a36Sopenharmony_ci * 0 if the queue was woken up 11562306a36Sopenharmony_ci * 1 if the queue was already enabled (or disabled but @down_cond is true) 11662306a36Sopenharmony_ci * -1 if the queue was left unchanged (@start_thrs not reached) 11762306a36Sopenharmony_ci */ 11862306a36Sopenharmony_ci#define __netif_txq_completed_wake(txq, pkts, bytes, \ 11962306a36Sopenharmony_ci get_desc, start_thrs, down_cond) \ 12062306a36Sopenharmony_ci ({ \ 12162306a36Sopenharmony_ci int _res; \ 12262306a36Sopenharmony_ci \ 12362306a36Sopenharmony_ci /* Report to BQL and piggy back on its barrier. \ 12462306a36Sopenharmony_ci * Barrier makes sure that anybody stopping the queue \ 12562306a36Sopenharmony_ci * after this point sees the new consumer index. \ 12662306a36Sopenharmony_ci * Pairs with barrier in netif_txq_try_stop(). \ 12762306a36Sopenharmony_ci */ \ 12862306a36Sopenharmony_ci netdev_txq_completed_mb(txq, pkts, bytes); \ 12962306a36Sopenharmony_ci \ 13062306a36Sopenharmony_ci _res = -1; \ 13162306a36Sopenharmony_ci if (pkts && likely(get_desc >= start_thrs)) { \ 13262306a36Sopenharmony_ci _res = 1; \ 13362306a36Sopenharmony_ci if (unlikely(netif_tx_queue_stopped(txq)) && \ 13462306a36Sopenharmony_ci !(down_cond)) { \ 13562306a36Sopenharmony_ci netif_tx_wake_queue(txq); \ 13662306a36Sopenharmony_ci _res = 0; \ 13762306a36Sopenharmony_ci } \ 13862306a36Sopenharmony_ci } \ 13962306a36Sopenharmony_ci _res; \ 14062306a36Sopenharmony_ci }) 14162306a36Sopenharmony_ci 14262306a36Sopenharmony_ci#define netif_txq_completed_wake(txq, pkts, bytes, get_desc, start_thrs) \ 14362306a36Sopenharmony_ci __netif_txq_completed_wake(txq, pkts, bytes, get_desc, start_thrs, false) 14462306a36Sopenharmony_ci 14562306a36Sopenharmony_ci/* subqueue variants follow */ 14662306a36Sopenharmony_ci 14762306a36Sopenharmony_ci#define netif_subqueue_try_stop(dev, idx, get_desc, start_thrs) \ 14862306a36Sopenharmony_ci ({ \ 14962306a36Sopenharmony_ci struct netdev_queue *txq; \ 15062306a36Sopenharmony_ci \ 15162306a36Sopenharmony_ci txq = netdev_get_tx_queue(dev, idx); \ 15262306a36Sopenharmony_ci netif_txq_try_stop(txq, get_desc, start_thrs); \ 15362306a36Sopenharmony_ci }) 15462306a36Sopenharmony_ci 15562306a36Sopenharmony_ci#define netif_subqueue_maybe_stop(dev, idx, get_desc, stop_thrs, start_thrs) \ 15662306a36Sopenharmony_ci ({ \ 15762306a36Sopenharmony_ci struct netdev_queue *txq; \ 15862306a36Sopenharmony_ci \ 15962306a36Sopenharmony_ci txq = netdev_get_tx_queue(dev, idx); \ 16062306a36Sopenharmony_ci netif_txq_maybe_stop(txq, get_desc, stop_thrs, start_thrs); \ 16162306a36Sopenharmony_ci }) 16262306a36Sopenharmony_ci 16362306a36Sopenharmony_ci#define netif_subqueue_completed_wake(dev, idx, pkts, bytes, \ 16462306a36Sopenharmony_ci get_desc, start_thrs) \ 16562306a36Sopenharmony_ci ({ \ 16662306a36Sopenharmony_ci struct netdev_queue *txq; \ 16762306a36Sopenharmony_ci \ 16862306a36Sopenharmony_ci txq = netdev_get_tx_queue(dev, idx); \ 16962306a36Sopenharmony_ci netif_txq_completed_wake(txq, pkts, bytes, \ 17062306a36Sopenharmony_ci get_desc, start_thrs); \ 17162306a36Sopenharmony_ci }) 17262306a36Sopenharmony_ci 17362306a36Sopenharmony_ci#endif 174