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