162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * net/sched/sch_generic.c Generic packet scheduler routines. 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Authors: Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru> 662306a36Sopenharmony_ci * Jamal Hadi Salim, <hadi@cyberus.ca> 990601 762306a36Sopenharmony_ci * - Ingress support 862306a36Sopenharmony_ci */ 962306a36Sopenharmony_ci 1062306a36Sopenharmony_ci#include <linux/bitops.h> 1162306a36Sopenharmony_ci#include <linux/module.h> 1262306a36Sopenharmony_ci#include <linux/types.h> 1362306a36Sopenharmony_ci#include <linux/kernel.h> 1462306a36Sopenharmony_ci#include <linux/sched.h> 1562306a36Sopenharmony_ci#include <linux/string.h> 1662306a36Sopenharmony_ci#include <linux/errno.h> 1762306a36Sopenharmony_ci#include <linux/netdevice.h> 1862306a36Sopenharmony_ci#include <linux/skbuff.h> 1962306a36Sopenharmony_ci#include <linux/rtnetlink.h> 2062306a36Sopenharmony_ci#include <linux/init.h> 2162306a36Sopenharmony_ci#include <linux/rcupdate.h> 2262306a36Sopenharmony_ci#include <linux/list.h> 2362306a36Sopenharmony_ci#include <linux/slab.h> 2462306a36Sopenharmony_ci#include <linux/if_vlan.h> 2562306a36Sopenharmony_ci#include <linux/skb_array.h> 2662306a36Sopenharmony_ci#include <linux/if_macvlan.h> 2762306a36Sopenharmony_ci#include <net/sch_generic.h> 2862306a36Sopenharmony_ci#include <net/pkt_sched.h> 2962306a36Sopenharmony_ci#include <net/dst.h> 3062306a36Sopenharmony_ci#include <trace/events/qdisc.h> 3162306a36Sopenharmony_ci#include <trace/events/net.h> 3262306a36Sopenharmony_ci#include <net/xfrm.h> 3362306a36Sopenharmony_ci 3462306a36Sopenharmony_ci/* Qdisc to use by default */ 3562306a36Sopenharmony_ciconst struct Qdisc_ops *default_qdisc_ops = &pfifo_fast_ops; 3662306a36Sopenharmony_ciEXPORT_SYMBOL(default_qdisc_ops); 3762306a36Sopenharmony_ci 3862306a36Sopenharmony_cistatic void qdisc_maybe_clear_missed(struct Qdisc *q, 3962306a36Sopenharmony_ci const struct netdev_queue *txq) 4062306a36Sopenharmony_ci{ 4162306a36Sopenharmony_ci clear_bit(__QDISC_STATE_MISSED, &q->state); 4262306a36Sopenharmony_ci 4362306a36Sopenharmony_ci /* Make sure the below netif_xmit_frozen_or_stopped() 4462306a36Sopenharmony_ci * checking happens after clearing STATE_MISSED. 4562306a36Sopenharmony_ci */ 4662306a36Sopenharmony_ci smp_mb__after_atomic(); 4762306a36Sopenharmony_ci 4862306a36Sopenharmony_ci /* Checking netif_xmit_frozen_or_stopped() again to 4962306a36Sopenharmony_ci * make sure STATE_MISSED is set if the STATE_MISSED 5062306a36Sopenharmony_ci * set by netif_tx_wake_queue()'s rescheduling of 5162306a36Sopenharmony_ci * net_tx_action() is cleared by the above clear_bit(). 5262306a36Sopenharmony_ci */ 5362306a36Sopenharmony_ci if (!netif_xmit_frozen_or_stopped(txq)) 5462306a36Sopenharmony_ci set_bit(__QDISC_STATE_MISSED, &q->state); 5562306a36Sopenharmony_ci else 5662306a36Sopenharmony_ci set_bit(__QDISC_STATE_DRAINING, &q->state); 5762306a36Sopenharmony_ci} 5862306a36Sopenharmony_ci 5962306a36Sopenharmony_ci/* Main transmission queue. */ 6062306a36Sopenharmony_ci 6162306a36Sopenharmony_ci/* Modifications to data participating in scheduling must be protected with 6262306a36Sopenharmony_ci * qdisc_lock(qdisc) spinlock. 6362306a36Sopenharmony_ci * 6462306a36Sopenharmony_ci * The idea is the following: 6562306a36Sopenharmony_ci * - enqueue, dequeue are serialized via qdisc root lock 6662306a36Sopenharmony_ci * - ingress filtering is also serialized via qdisc root lock 6762306a36Sopenharmony_ci * - updates to tree and tree walking are only done under the rtnl mutex. 6862306a36Sopenharmony_ci */ 6962306a36Sopenharmony_ci 7062306a36Sopenharmony_ci#define SKB_XOFF_MAGIC ((struct sk_buff *)1UL) 7162306a36Sopenharmony_ci 7262306a36Sopenharmony_cistatic inline struct sk_buff *__skb_dequeue_bad_txq(struct Qdisc *q) 7362306a36Sopenharmony_ci{ 7462306a36Sopenharmony_ci const struct netdev_queue *txq = q->dev_queue; 7562306a36Sopenharmony_ci spinlock_t *lock = NULL; 7662306a36Sopenharmony_ci struct sk_buff *skb; 7762306a36Sopenharmony_ci 7862306a36Sopenharmony_ci if (q->flags & TCQ_F_NOLOCK) { 7962306a36Sopenharmony_ci lock = qdisc_lock(q); 8062306a36Sopenharmony_ci spin_lock(lock); 8162306a36Sopenharmony_ci } 8262306a36Sopenharmony_ci 8362306a36Sopenharmony_ci skb = skb_peek(&q->skb_bad_txq); 8462306a36Sopenharmony_ci if (skb) { 8562306a36Sopenharmony_ci /* check the reason of requeuing without tx lock first */ 8662306a36Sopenharmony_ci txq = skb_get_tx_queue(txq->dev, skb); 8762306a36Sopenharmony_ci if (!netif_xmit_frozen_or_stopped(txq)) { 8862306a36Sopenharmony_ci skb = __skb_dequeue(&q->skb_bad_txq); 8962306a36Sopenharmony_ci if (qdisc_is_percpu_stats(q)) { 9062306a36Sopenharmony_ci qdisc_qstats_cpu_backlog_dec(q, skb); 9162306a36Sopenharmony_ci qdisc_qstats_cpu_qlen_dec(q); 9262306a36Sopenharmony_ci } else { 9362306a36Sopenharmony_ci qdisc_qstats_backlog_dec(q, skb); 9462306a36Sopenharmony_ci q->q.qlen--; 9562306a36Sopenharmony_ci } 9662306a36Sopenharmony_ci } else { 9762306a36Sopenharmony_ci skb = SKB_XOFF_MAGIC; 9862306a36Sopenharmony_ci qdisc_maybe_clear_missed(q, txq); 9962306a36Sopenharmony_ci } 10062306a36Sopenharmony_ci } 10162306a36Sopenharmony_ci 10262306a36Sopenharmony_ci if (lock) 10362306a36Sopenharmony_ci spin_unlock(lock); 10462306a36Sopenharmony_ci 10562306a36Sopenharmony_ci return skb; 10662306a36Sopenharmony_ci} 10762306a36Sopenharmony_ci 10862306a36Sopenharmony_cistatic inline struct sk_buff *qdisc_dequeue_skb_bad_txq(struct Qdisc *q) 10962306a36Sopenharmony_ci{ 11062306a36Sopenharmony_ci struct sk_buff *skb = skb_peek(&q->skb_bad_txq); 11162306a36Sopenharmony_ci 11262306a36Sopenharmony_ci if (unlikely(skb)) 11362306a36Sopenharmony_ci skb = __skb_dequeue_bad_txq(q); 11462306a36Sopenharmony_ci 11562306a36Sopenharmony_ci return skb; 11662306a36Sopenharmony_ci} 11762306a36Sopenharmony_ci 11862306a36Sopenharmony_cistatic inline void qdisc_enqueue_skb_bad_txq(struct Qdisc *q, 11962306a36Sopenharmony_ci struct sk_buff *skb) 12062306a36Sopenharmony_ci{ 12162306a36Sopenharmony_ci spinlock_t *lock = NULL; 12262306a36Sopenharmony_ci 12362306a36Sopenharmony_ci if (q->flags & TCQ_F_NOLOCK) { 12462306a36Sopenharmony_ci lock = qdisc_lock(q); 12562306a36Sopenharmony_ci spin_lock(lock); 12662306a36Sopenharmony_ci } 12762306a36Sopenharmony_ci 12862306a36Sopenharmony_ci __skb_queue_tail(&q->skb_bad_txq, skb); 12962306a36Sopenharmony_ci 13062306a36Sopenharmony_ci if (qdisc_is_percpu_stats(q)) { 13162306a36Sopenharmony_ci qdisc_qstats_cpu_backlog_inc(q, skb); 13262306a36Sopenharmony_ci qdisc_qstats_cpu_qlen_inc(q); 13362306a36Sopenharmony_ci } else { 13462306a36Sopenharmony_ci qdisc_qstats_backlog_inc(q, skb); 13562306a36Sopenharmony_ci q->q.qlen++; 13662306a36Sopenharmony_ci } 13762306a36Sopenharmony_ci 13862306a36Sopenharmony_ci if (lock) 13962306a36Sopenharmony_ci spin_unlock(lock); 14062306a36Sopenharmony_ci} 14162306a36Sopenharmony_ci 14262306a36Sopenharmony_cistatic inline void dev_requeue_skb(struct sk_buff *skb, struct Qdisc *q) 14362306a36Sopenharmony_ci{ 14462306a36Sopenharmony_ci spinlock_t *lock = NULL; 14562306a36Sopenharmony_ci 14662306a36Sopenharmony_ci if (q->flags & TCQ_F_NOLOCK) { 14762306a36Sopenharmony_ci lock = qdisc_lock(q); 14862306a36Sopenharmony_ci spin_lock(lock); 14962306a36Sopenharmony_ci } 15062306a36Sopenharmony_ci 15162306a36Sopenharmony_ci while (skb) { 15262306a36Sopenharmony_ci struct sk_buff *next = skb->next; 15362306a36Sopenharmony_ci 15462306a36Sopenharmony_ci __skb_queue_tail(&q->gso_skb, skb); 15562306a36Sopenharmony_ci 15662306a36Sopenharmony_ci /* it's still part of the queue */ 15762306a36Sopenharmony_ci if (qdisc_is_percpu_stats(q)) { 15862306a36Sopenharmony_ci qdisc_qstats_cpu_requeues_inc(q); 15962306a36Sopenharmony_ci qdisc_qstats_cpu_backlog_inc(q, skb); 16062306a36Sopenharmony_ci qdisc_qstats_cpu_qlen_inc(q); 16162306a36Sopenharmony_ci } else { 16262306a36Sopenharmony_ci q->qstats.requeues++; 16362306a36Sopenharmony_ci qdisc_qstats_backlog_inc(q, skb); 16462306a36Sopenharmony_ci q->q.qlen++; 16562306a36Sopenharmony_ci } 16662306a36Sopenharmony_ci 16762306a36Sopenharmony_ci skb = next; 16862306a36Sopenharmony_ci } 16962306a36Sopenharmony_ci 17062306a36Sopenharmony_ci if (lock) { 17162306a36Sopenharmony_ci spin_unlock(lock); 17262306a36Sopenharmony_ci set_bit(__QDISC_STATE_MISSED, &q->state); 17362306a36Sopenharmony_ci } else { 17462306a36Sopenharmony_ci __netif_schedule(q); 17562306a36Sopenharmony_ci } 17662306a36Sopenharmony_ci} 17762306a36Sopenharmony_ci 17862306a36Sopenharmony_cistatic void try_bulk_dequeue_skb(struct Qdisc *q, 17962306a36Sopenharmony_ci struct sk_buff *skb, 18062306a36Sopenharmony_ci const struct netdev_queue *txq, 18162306a36Sopenharmony_ci int *packets) 18262306a36Sopenharmony_ci{ 18362306a36Sopenharmony_ci int bytelimit = qdisc_avail_bulklimit(txq) - skb->len; 18462306a36Sopenharmony_ci 18562306a36Sopenharmony_ci while (bytelimit > 0) { 18662306a36Sopenharmony_ci struct sk_buff *nskb = q->dequeue(q); 18762306a36Sopenharmony_ci 18862306a36Sopenharmony_ci if (!nskb) 18962306a36Sopenharmony_ci break; 19062306a36Sopenharmony_ci 19162306a36Sopenharmony_ci bytelimit -= nskb->len; /* covers GSO len */ 19262306a36Sopenharmony_ci skb->next = nskb; 19362306a36Sopenharmony_ci skb = nskb; 19462306a36Sopenharmony_ci (*packets)++; /* GSO counts as one pkt */ 19562306a36Sopenharmony_ci } 19662306a36Sopenharmony_ci skb_mark_not_on_list(skb); 19762306a36Sopenharmony_ci} 19862306a36Sopenharmony_ci 19962306a36Sopenharmony_ci/* This variant of try_bulk_dequeue_skb() makes sure 20062306a36Sopenharmony_ci * all skbs in the chain are for the same txq 20162306a36Sopenharmony_ci */ 20262306a36Sopenharmony_cistatic void try_bulk_dequeue_skb_slow(struct Qdisc *q, 20362306a36Sopenharmony_ci struct sk_buff *skb, 20462306a36Sopenharmony_ci int *packets) 20562306a36Sopenharmony_ci{ 20662306a36Sopenharmony_ci int mapping = skb_get_queue_mapping(skb); 20762306a36Sopenharmony_ci struct sk_buff *nskb; 20862306a36Sopenharmony_ci int cnt = 0; 20962306a36Sopenharmony_ci 21062306a36Sopenharmony_ci do { 21162306a36Sopenharmony_ci nskb = q->dequeue(q); 21262306a36Sopenharmony_ci if (!nskb) 21362306a36Sopenharmony_ci break; 21462306a36Sopenharmony_ci if (unlikely(skb_get_queue_mapping(nskb) != mapping)) { 21562306a36Sopenharmony_ci qdisc_enqueue_skb_bad_txq(q, nskb); 21662306a36Sopenharmony_ci break; 21762306a36Sopenharmony_ci } 21862306a36Sopenharmony_ci skb->next = nskb; 21962306a36Sopenharmony_ci skb = nskb; 22062306a36Sopenharmony_ci } while (++cnt < 8); 22162306a36Sopenharmony_ci (*packets) += cnt; 22262306a36Sopenharmony_ci skb_mark_not_on_list(skb); 22362306a36Sopenharmony_ci} 22462306a36Sopenharmony_ci 22562306a36Sopenharmony_ci/* Note that dequeue_skb can possibly return a SKB list (via skb->next). 22662306a36Sopenharmony_ci * A requeued skb (via q->gso_skb) can also be a SKB list. 22762306a36Sopenharmony_ci */ 22862306a36Sopenharmony_cistatic struct sk_buff *dequeue_skb(struct Qdisc *q, bool *validate, 22962306a36Sopenharmony_ci int *packets) 23062306a36Sopenharmony_ci{ 23162306a36Sopenharmony_ci const struct netdev_queue *txq = q->dev_queue; 23262306a36Sopenharmony_ci struct sk_buff *skb = NULL; 23362306a36Sopenharmony_ci 23462306a36Sopenharmony_ci *packets = 1; 23562306a36Sopenharmony_ci if (unlikely(!skb_queue_empty(&q->gso_skb))) { 23662306a36Sopenharmony_ci spinlock_t *lock = NULL; 23762306a36Sopenharmony_ci 23862306a36Sopenharmony_ci if (q->flags & TCQ_F_NOLOCK) { 23962306a36Sopenharmony_ci lock = qdisc_lock(q); 24062306a36Sopenharmony_ci spin_lock(lock); 24162306a36Sopenharmony_ci } 24262306a36Sopenharmony_ci 24362306a36Sopenharmony_ci skb = skb_peek(&q->gso_skb); 24462306a36Sopenharmony_ci 24562306a36Sopenharmony_ci /* skb may be null if another cpu pulls gso_skb off in between 24662306a36Sopenharmony_ci * empty check and lock. 24762306a36Sopenharmony_ci */ 24862306a36Sopenharmony_ci if (!skb) { 24962306a36Sopenharmony_ci if (lock) 25062306a36Sopenharmony_ci spin_unlock(lock); 25162306a36Sopenharmony_ci goto validate; 25262306a36Sopenharmony_ci } 25362306a36Sopenharmony_ci 25462306a36Sopenharmony_ci /* skb in gso_skb were already validated */ 25562306a36Sopenharmony_ci *validate = false; 25662306a36Sopenharmony_ci if (xfrm_offload(skb)) 25762306a36Sopenharmony_ci *validate = true; 25862306a36Sopenharmony_ci /* check the reason of requeuing without tx lock first */ 25962306a36Sopenharmony_ci txq = skb_get_tx_queue(txq->dev, skb); 26062306a36Sopenharmony_ci if (!netif_xmit_frozen_or_stopped(txq)) { 26162306a36Sopenharmony_ci skb = __skb_dequeue(&q->gso_skb); 26262306a36Sopenharmony_ci if (qdisc_is_percpu_stats(q)) { 26362306a36Sopenharmony_ci qdisc_qstats_cpu_backlog_dec(q, skb); 26462306a36Sopenharmony_ci qdisc_qstats_cpu_qlen_dec(q); 26562306a36Sopenharmony_ci } else { 26662306a36Sopenharmony_ci qdisc_qstats_backlog_dec(q, skb); 26762306a36Sopenharmony_ci q->q.qlen--; 26862306a36Sopenharmony_ci } 26962306a36Sopenharmony_ci } else { 27062306a36Sopenharmony_ci skb = NULL; 27162306a36Sopenharmony_ci qdisc_maybe_clear_missed(q, txq); 27262306a36Sopenharmony_ci } 27362306a36Sopenharmony_ci if (lock) 27462306a36Sopenharmony_ci spin_unlock(lock); 27562306a36Sopenharmony_ci goto trace; 27662306a36Sopenharmony_ci } 27762306a36Sopenharmony_civalidate: 27862306a36Sopenharmony_ci *validate = true; 27962306a36Sopenharmony_ci 28062306a36Sopenharmony_ci if ((q->flags & TCQ_F_ONETXQUEUE) && 28162306a36Sopenharmony_ci netif_xmit_frozen_or_stopped(txq)) { 28262306a36Sopenharmony_ci qdisc_maybe_clear_missed(q, txq); 28362306a36Sopenharmony_ci return skb; 28462306a36Sopenharmony_ci } 28562306a36Sopenharmony_ci 28662306a36Sopenharmony_ci skb = qdisc_dequeue_skb_bad_txq(q); 28762306a36Sopenharmony_ci if (unlikely(skb)) { 28862306a36Sopenharmony_ci if (skb == SKB_XOFF_MAGIC) 28962306a36Sopenharmony_ci return NULL; 29062306a36Sopenharmony_ci goto bulk; 29162306a36Sopenharmony_ci } 29262306a36Sopenharmony_ci skb = q->dequeue(q); 29362306a36Sopenharmony_ci if (skb) { 29462306a36Sopenharmony_cibulk: 29562306a36Sopenharmony_ci if (qdisc_may_bulk(q)) 29662306a36Sopenharmony_ci try_bulk_dequeue_skb(q, skb, txq, packets); 29762306a36Sopenharmony_ci else 29862306a36Sopenharmony_ci try_bulk_dequeue_skb_slow(q, skb, packets); 29962306a36Sopenharmony_ci } 30062306a36Sopenharmony_citrace: 30162306a36Sopenharmony_ci trace_qdisc_dequeue(q, txq, *packets, skb); 30262306a36Sopenharmony_ci return skb; 30362306a36Sopenharmony_ci} 30462306a36Sopenharmony_ci 30562306a36Sopenharmony_ci/* 30662306a36Sopenharmony_ci * Transmit possibly several skbs, and handle the return status as 30762306a36Sopenharmony_ci * required. Owning qdisc running bit guarantees that only one CPU 30862306a36Sopenharmony_ci * can execute this function. 30962306a36Sopenharmony_ci * 31062306a36Sopenharmony_ci * Returns to the caller: 31162306a36Sopenharmony_ci * false - hardware queue frozen backoff 31262306a36Sopenharmony_ci * true - feel free to send more pkts 31362306a36Sopenharmony_ci */ 31462306a36Sopenharmony_cibool sch_direct_xmit(struct sk_buff *skb, struct Qdisc *q, 31562306a36Sopenharmony_ci struct net_device *dev, struct netdev_queue *txq, 31662306a36Sopenharmony_ci spinlock_t *root_lock, bool validate) 31762306a36Sopenharmony_ci{ 31862306a36Sopenharmony_ci int ret = NETDEV_TX_BUSY; 31962306a36Sopenharmony_ci bool again = false; 32062306a36Sopenharmony_ci 32162306a36Sopenharmony_ci /* And release qdisc */ 32262306a36Sopenharmony_ci if (root_lock) 32362306a36Sopenharmony_ci spin_unlock(root_lock); 32462306a36Sopenharmony_ci 32562306a36Sopenharmony_ci /* Note that we validate skb (GSO, checksum, ...) outside of locks */ 32662306a36Sopenharmony_ci if (validate) 32762306a36Sopenharmony_ci skb = validate_xmit_skb_list(skb, dev, &again); 32862306a36Sopenharmony_ci 32962306a36Sopenharmony_ci#ifdef CONFIG_XFRM_OFFLOAD 33062306a36Sopenharmony_ci if (unlikely(again)) { 33162306a36Sopenharmony_ci if (root_lock) 33262306a36Sopenharmony_ci spin_lock(root_lock); 33362306a36Sopenharmony_ci 33462306a36Sopenharmony_ci dev_requeue_skb(skb, q); 33562306a36Sopenharmony_ci return false; 33662306a36Sopenharmony_ci } 33762306a36Sopenharmony_ci#endif 33862306a36Sopenharmony_ci 33962306a36Sopenharmony_ci if (likely(skb)) { 34062306a36Sopenharmony_ci HARD_TX_LOCK(dev, txq, smp_processor_id()); 34162306a36Sopenharmony_ci if (!netif_xmit_frozen_or_stopped(txq)) 34262306a36Sopenharmony_ci skb = dev_hard_start_xmit(skb, dev, txq, &ret); 34362306a36Sopenharmony_ci else 34462306a36Sopenharmony_ci qdisc_maybe_clear_missed(q, txq); 34562306a36Sopenharmony_ci 34662306a36Sopenharmony_ci HARD_TX_UNLOCK(dev, txq); 34762306a36Sopenharmony_ci } else { 34862306a36Sopenharmony_ci if (root_lock) 34962306a36Sopenharmony_ci spin_lock(root_lock); 35062306a36Sopenharmony_ci return true; 35162306a36Sopenharmony_ci } 35262306a36Sopenharmony_ci 35362306a36Sopenharmony_ci if (root_lock) 35462306a36Sopenharmony_ci spin_lock(root_lock); 35562306a36Sopenharmony_ci 35662306a36Sopenharmony_ci if (!dev_xmit_complete(ret)) { 35762306a36Sopenharmony_ci /* Driver returned NETDEV_TX_BUSY - requeue skb */ 35862306a36Sopenharmony_ci if (unlikely(ret != NETDEV_TX_BUSY)) 35962306a36Sopenharmony_ci net_warn_ratelimited("BUG %s code %d qlen %d\n", 36062306a36Sopenharmony_ci dev->name, ret, q->q.qlen); 36162306a36Sopenharmony_ci 36262306a36Sopenharmony_ci dev_requeue_skb(skb, q); 36362306a36Sopenharmony_ci return false; 36462306a36Sopenharmony_ci } 36562306a36Sopenharmony_ci 36662306a36Sopenharmony_ci return true; 36762306a36Sopenharmony_ci} 36862306a36Sopenharmony_ci 36962306a36Sopenharmony_ci/* 37062306a36Sopenharmony_ci * NOTE: Called under qdisc_lock(q) with locally disabled BH. 37162306a36Sopenharmony_ci * 37262306a36Sopenharmony_ci * running seqcount guarantees only one CPU can process 37362306a36Sopenharmony_ci * this qdisc at a time. qdisc_lock(q) serializes queue accesses for 37462306a36Sopenharmony_ci * this queue. 37562306a36Sopenharmony_ci * 37662306a36Sopenharmony_ci * netif_tx_lock serializes accesses to device driver. 37762306a36Sopenharmony_ci * 37862306a36Sopenharmony_ci * qdisc_lock(q) and netif_tx_lock are mutually exclusive, 37962306a36Sopenharmony_ci * if one is grabbed, another must be free. 38062306a36Sopenharmony_ci * 38162306a36Sopenharmony_ci * Note, that this procedure can be called by a watchdog timer 38262306a36Sopenharmony_ci * 38362306a36Sopenharmony_ci * Returns to the caller: 38462306a36Sopenharmony_ci * 0 - queue is empty or throttled. 38562306a36Sopenharmony_ci * >0 - queue is not empty. 38662306a36Sopenharmony_ci * 38762306a36Sopenharmony_ci */ 38862306a36Sopenharmony_cistatic inline bool qdisc_restart(struct Qdisc *q, int *packets) 38962306a36Sopenharmony_ci{ 39062306a36Sopenharmony_ci spinlock_t *root_lock = NULL; 39162306a36Sopenharmony_ci struct netdev_queue *txq; 39262306a36Sopenharmony_ci struct net_device *dev; 39362306a36Sopenharmony_ci struct sk_buff *skb; 39462306a36Sopenharmony_ci bool validate; 39562306a36Sopenharmony_ci 39662306a36Sopenharmony_ci /* Dequeue packet */ 39762306a36Sopenharmony_ci skb = dequeue_skb(q, &validate, packets); 39862306a36Sopenharmony_ci if (unlikely(!skb)) 39962306a36Sopenharmony_ci return false; 40062306a36Sopenharmony_ci 40162306a36Sopenharmony_ci if (!(q->flags & TCQ_F_NOLOCK)) 40262306a36Sopenharmony_ci root_lock = qdisc_lock(q); 40362306a36Sopenharmony_ci 40462306a36Sopenharmony_ci dev = qdisc_dev(q); 40562306a36Sopenharmony_ci txq = skb_get_tx_queue(dev, skb); 40662306a36Sopenharmony_ci 40762306a36Sopenharmony_ci return sch_direct_xmit(skb, q, dev, txq, root_lock, validate); 40862306a36Sopenharmony_ci} 40962306a36Sopenharmony_ci 41062306a36Sopenharmony_civoid __qdisc_run(struct Qdisc *q) 41162306a36Sopenharmony_ci{ 41262306a36Sopenharmony_ci int quota = READ_ONCE(dev_tx_weight); 41362306a36Sopenharmony_ci int packets; 41462306a36Sopenharmony_ci 41562306a36Sopenharmony_ci while (qdisc_restart(q, &packets)) { 41662306a36Sopenharmony_ci quota -= packets; 41762306a36Sopenharmony_ci if (quota <= 0) { 41862306a36Sopenharmony_ci if (q->flags & TCQ_F_NOLOCK) 41962306a36Sopenharmony_ci set_bit(__QDISC_STATE_MISSED, &q->state); 42062306a36Sopenharmony_ci else 42162306a36Sopenharmony_ci __netif_schedule(q); 42262306a36Sopenharmony_ci 42362306a36Sopenharmony_ci break; 42462306a36Sopenharmony_ci } 42562306a36Sopenharmony_ci } 42662306a36Sopenharmony_ci} 42762306a36Sopenharmony_ci 42862306a36Sopenharmony_ciunsigned long dev_trans_start(struct net_device *dev) 42962306a36Sopenharmony_ci{ 43062306a36Sopenharmony_ci unsigned long res = READ_ONCE(netdev_get_tx_queue(dev, 0)->trans_start); 43162306a36Sopenharmony_ci unsigned long val; 43262306a36Sopenharmony_ci unsigned int i; 43362306a36Sopenharmony_ci 43462306a36Sopenharmony_ci for (i = 1; i < dev->num_tx_queues; i++) { 43562306a36Sopenharmony_ci val = READ_ONCE(netdev_get_tx_queue(dev, i)->trans_start); 43662306a36Sopenharmony_ci if (val && time_after(val, res)) 43762306a36Sopenharmony_ci res = val; 43862306a36Sopenharmony_ci } 43962306a36Sopenharmony_ci 44062306a36Sopenharmony_ci return res; 44162306a36Sopenharmony_ci} 44262306a36Sopenharmony_ciEXPORT_SYMBOL(dev_trans_start); 44362306a36Sopenharmony_ci 44462306a36Sopenharmony_cistatic void netif_freeze_queues(struct net_device *dev) 44562306a36Sopenharmony_ci{ 44662306a36Sopenharmony_ci unsigned int i; 44762306a36Sopenharmony_ci int cpu; 44862306a36Sopenharmony_ci 44962306a36Sopenharmony_ci cpu = smp_processor_id(); 45062306a36Sopenharmony_ci for (i = 0; i < dev->num_tx_queues; i++) { 45162306a36Sopenharmony_ci struct netdev_queue *txq = netdev_get_tx_queue(dev, i); 45262306a36Sopenharmony_ci 45362306a36Sopenharmony_ci /* We are the only thread of execution doing a 45462306a36Sopenharmony_ci * freeze, but we have to grab the _xmit_lock in 45562306a36Sopenharmony_ci * order to synchronize with threads which are in 45662306a36Sopenharmony_ci * the ->hard_start_xmit() handler and already 45762306a36Sopenharmony_ci * checked the frozen bit. 45862306a36Sopenharmony_ci */ 45962306a36Sopenharmony_ci __netif_tx_lock(txq, cpu); 46062306a36Sopenharmony_ci set_bit(__QUEUE_STATE_FROZEN, &txq->state); 46162306a36Sopenharmony_ci __netif_tx_unlock(txq); 46262306a36Sopenharmony_ci } 46362306a36Sopenharmony_ci} 46462306a36Sopenharmony_ci 46562306a36Sopenharmony_civoid netif_tx_lock(struct net_device *dev) 46662306a36Sopenharmony_ci{ 46762306a36Sopenharmony_ci spin_lock(&dev->tx_global_lock); 46862306a36Sopenharmony_ci netif_freeze_queues(dev); 46962306a36Sopenharmony_ci} 47062306a36Sopenharmony_ciEXPORT_SYMBOL(netif_tx_lock); 47162306a36Sopenharmony_ci 47262306a36Sopenharmony_cistatic void netif_unfreeze_queues(struct net_device *dev) 47362306a36Sopenharmony_ci{ 47462306a36Sopenharmony_ci unsigned int i; 47562306a36Sopenharmony_ci 47662306a36Sopenharmony_ci for (i = 0; i < dev->num_tx_queues; i++) { 47762306a36Sopenharmony_ci struct netdev_queue *txq = netdev_get_tx_queue(dev, i); 47862306a36Sopenharmony_ci 47962306a36Sopenharmony_ci /* No need to grab the _xmit_lock here. If the 48062306a36Sopenharmony_ci * queue is not stopped for another reason, we 48162306a36Sopenharmony_ci * force a schedule. 48262306a36Sopenharmony_ci */ 48362306a36Sopenharmony_ci clear_bit(__QUEUE_STATE_FROZEN, &txq->state); 48462306a36Sopenharmony_ci netif_schedule_queue(txq); 48562306a36Sopenharmony_ci } 48662306a36Sopenharmony_ci} 48762306a36Sopenharmony_ci 48862306a36Sopenharmony_civoid netif_tx_unlock(struct net_device *dev) 48962306a36Sopenharmony_ci{ 49062306a36Sopenharmony_ci netif_unfreeze_queues(dev); 49162306a36Sopenharmony_ci spin_unlock(&dev->tx_global_lock); 49262306a36Sopenharmony_ci} 49362306a36Sopenharmony_ciEXPORT_SYMBOL(netif_tx_unlock); 49462306a36Sopenharmony_ci 49562306a36Sopenharmony_cistatic void dev_watchdog(struct timer_list *t) 49662306a36Sopenharmony_ci{ 49762306a36Sopenharmony_ci struct net_device *dev = from_timer(dev, t, watchdog_timer); 49862306a36Sopenharmony_ci bool release = true; 49962306a36Sopenharmony_ci 50062306a36Sopenharmony_ci spin_lock(&dev->tx_global_lock); 50162306a36Sopenharmony_ci if (!qdisc_tx_is_noop(dev)) { 50262306a36Sopenharmony_ci if (netif_device_present(dev) && 50362306a36Sopenharmony_ci netif_running(dev) && 50462306a36Sopenharmony_ci netif_carrier_ok(dev)) { 50562306a36Sopenharmony_ci unsigned int timedout_ms = 0; 50662306a36Sopenharmony_ci unsigned int i; 50762306a36Sopenharmony_ci unsigned long trans_start; 50862306a36Sopenharmony_ci 50962306a36Sopenharmony_ci for (i = 0; i < dev->num_tx_queues; i++) { 51062306a36Sopenharmony_ci struct netdev_queue *txq; 51162306a36Sopenharmony_ci 51262306a36Sopenharmony_ci txq = netdev_get_tx_queue(dev, i); 51362306a36Sopenharmony_ci trans_start = READ_ONCE(txq->trans_start); 51462306a36Sopenharmony_ci if (netif_xmit_stopped(txq) && 51562306a36Sopenharmony_ci time_after(jiffies, (trans_start + 51662306a36Sopenharmony_ci dev->watchdog_timeo))) { 51762306a36Sopenharmony_ci timedout_ms = jiffies_to_msecs(jiffies - trans_start); 51862306a36Sopenharmony_ci atomic_long_inc(&txq->trans_timeout); 51962306a36Sopenharmony_ci break; 52062306a36Sopenharmony_ci } 52162306a36Sopenharmony_ci } 52262306a36Sopenharmony_ci 52362306a36Sopenharmony_ci if (unlikely(timedout_ms)) { 52462306a36Sopenharmony_ci trace_net_dev_xmit_timeout(dev, i); 52562306a36Sopenharmony_ci WARN_ONCE(1, "NETDEV WATCHDOG: %s (%s): transmit queue %u timed out %u ms\n", 52662306a36Sopenharmony_ci dev->name, netdev_drivername(dev), i, timedout_ms); 52762306a36Sopenharmony_ci netif_freeze_queues(dev); 52862306a36Sopenharmony_ci dev->netdev_ops->ndo_tx_timeout(dev, i); 52962306a36Sopenharmony_ci netif_unfreeze_queues(dev); 53062306a36Sopenharmony_ci } 53162306a36Sopenharmony_ci if (!mod_timer(&dev->watchdog_timer, 53262306a36Sopenharmony_ci round_jiffies(jiffies + 53362306a36Sopenharmony_ci dev->watchdog_timeo))) 53462306a36Sopenharmony_ci release = false; 53562306a36Sopenharmony_ci } 53662306a36Sopenharmony_ci } 53762306a36Sopenharmony_ci spin_unlock(&dev->tx_global_lock); 53862306a36Sopenharmony_ci 53962306a36Sopenharmony_ci if (release) 54062306a36Sopenharmony_ci netdev_put(dev, &dev->watchdog_dev_tracker); 54162306a36Sopenharmony_ci} 54262306a36Sopenharmony_ci 54362306a36Sopenharmony_civoid __netdev_watchdog_up(struct net_device *dev) 54462306a36Sopenharmony_ci{ 54562306a36Sopenharmony_ci if (dev->netdev_ops->ndo_tx_timeout) { 54662306a36Sopenharmony_ci if (dev->watchdog_timeo <= 0) 54762306a36Sopenharmony_ci dev->watchdog_timeo = 5*HZ; 54862306a36Sopenharmony_ci if (!mod_timer(&dev->watchdog_timer, 54962306a36Sopenharmony_ci round_jiffies(jiffies + dev->watchdog_timeo))) 55062306a36Sopenharmony_ci netdev_hold(dev, &dev->watchdog_dev_tracker, 55162306a36Sopenharmony_ci GFP_ATOMIC); 55262306a36Sopenharmony_ci } 55362306a36Sopenharmony_ci} 55462306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(__netdev_watchdog_up); 55562306a36Sopenharmony_ci 55662306a36Sopenharmony_cistatic void dev_watchdog_up(struct net_device *dev) 55762306a36Sopenharmony_ci{ 55862306a36Sopenharmony_ci __netdev_watchdog_up(dev); 55962306a36Sopenharmony_ci} 56062306a36Sopenharmony_ci 56162306a36Sopenharmony_cistatic void dev_watchdog_down(struct net_device *dev) 56262306a36Sopenharmony_ci{ 56362306a36Sopenharmony_ci netif_tx_lock_bh(dev); 56462306a36Sopenharmony_ci if (del_timer(&dev->watchdog_timer)) 56562306a36Sopenharmony_ci netdev_put(dev, &dev->watchdog_dev_tracker); 56662306a36Sopenharmony_ci netif_tx_unlock_bh(dev); 56762306a36Sopenharmony_ci} 56862306a36Sopenharmony_ci 56962306a36Sopenharmony_ci/** 57062306a36Sopenharmony_ci * netif_carrier_on - set carrier 57162306a36Sopenharmony_ci * @dev: network device 57262306a36Sopenharmony_ci * 57362306a36Sopenharmony_ci * Device has detected acquisition of carrier. 57462306a36Sopenharmony_ci */ 57562306a36Sopenharmony_civoid netif_carrier_on(struct net_device *dev) 57662306a36Sopenharmony_ci{ 57762306a36Sopenharmony_ci if (test_and_clear_bit(__LINK_STATE_NOCARRIER, &dev->state)) { 57862306a36Sopenharmony_ci if (dev->reg_state == NETREG_UNINITIALIZED) 57962306a36Sopenharmony_ci return; 58062306a36Sopenharmony_ci atomic_inc(&dev->carrier_up_count); 58162306a36Sopenharmony_ci linkwatch_fire_event(dev); 58262306a36Sopenharmony_ci if (netif_running(dev)) 58362306a36Sopenharmony_ci __netdev_watchdog_up(dev); 58462306a36Sopenharmony_ci } 58562306a36Sopenharmony_ci} 58662306a36Sopenharmony_ciEXPORT_SYMBOL(netif_carrier_on); 58762306a36Sopenharmony_ci 58862306a36Sopenharmony_ci/** 58962306a36Sopenharmony_ci * netif_carrier_off - clear carrier 59062306a36Sopenharmony_ci * @dev: network device 59162306a36Sopenharmony_ci * 59262306a36Sopenharmony_ci * Device has detected loss of carrier. 59362306a36Sopenharmony_ci */ 59462306a36Sopenharmony_civoid netif_carrier_off(struct net_device *dev) 59562306a36Sopenharmony_ci{ 59662306a36Sopenharmony_ci if (!test_and_set_bit(__LINK_STATE_NOCARRIER, &dev->state)) { 59762306a36Sopenharmony_ci if (dev->reg_state == NETREG_UNINITIALIZED) 59862306a36Sopenharmony_ci return; 59962306a36Sopenharmony_ci atomic_inc(&dev->carrier_down_count); 60062306a36Sopenharmony_ci linkwatch_fire_event(dev); 60162306a36Sopenharmony_ci } 60262306a36Sopenharmony_ci} 60362306a36Sopenharmony_ciEXPORT_SYMBOL(netif_carrier_off); 60462306a36Sopenharmony_ci 60562306a36Sopenharmony_ci/** 60662306a36Sopenharmony_ci * netif_carrier_event - report carrier state event 60762306a36Sopenharmony_ci * @dev: network device 60862306a36Sopenharmony_ci * 60962306a36Sopenharmony_ci * Device has detected a carrier event but the carrier state wasn't changed. 61062306a36Sopenharmony_ci * Use in drivers when querying carrier state asynchronously, to avoid missing 61162306a36Sopenharmony_ci * events (link flaps) if link recovers before it's queried. 61262306a36Sopenharmony_ci */ 61362306a36Sopenharmony_civoid netif_carrier_event(struct net_device *dev) 61462306a36Sopenharmony_ci{ 61562306a36Sopenharmony_ci if (dev->reg_state == NETREG_UNINITIALIZED) 61662306a36Sopenharmony_ci return; 61762306a36Sopenharmony_ci atomic_inc(&dev->carrier_up_count); 61862306a36Sopenharmony_ci atomic_inc(&dev->carrier_down_count); 61962306a36Sopenharmony_ci linkwatch_fire_event(dev); 62062306a36Sopenharmony_ci} 62162306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(netif_carrier_event); 62262306a36Sopenharmony_ci 62362306a36Sopenharmony_ci/* "NOOP" scheduler: the best scheduler, recommended for all interfaces 62462306a36Sopenharmony_ci under all circumstances. It is difficult to invent anything faster or 62562306a36Sopenharmony_ci cheaper. 62662306a36Sopenharmony_ci */ 62762306a36Sopenharmony_ci 62862306a36Sopenharmony_cistatic int noop_enqueue(struct sk_buff *skb, struct Qdisc *qdisc, 62962306a36Sopenharmony_ci struct sk_buff **to_free) 63062306a36Sopenharmony_ci{ 63162306a36Sopenharmony_ci __qdisc_drop(skb, to_free); 63262306a36Sopenharmony_ci return NET_XMIT_CN; 63362306a36Sopenharmony_ci} 63462306a36Sopenharmony_ci 63562306a36Sopenharmony_cistatic struct sk_buff *noop_dequeue(struct Qdisc *qdisc) 63662306a36Sopenharmony_ci{ 63762306a36Sopenharmony_ci return NULL; 63862306a36Sopenharmony_ci} 63962306a36Sopenharmony_ci 64062306a36Sopenharmony_cistruct Qdisc_ops noop_qdisc_ops __read_mostly = { 64162306a36Sopenharmony_ci .id = "noop", 64262306a36Sopenharmony_ci .priv_size = 0, 64362306a36Sopenharmony_ci .enqueue = noop_enqueue, 64462306a36Sopenharmony_ci .dequeue = noop_dequeue, 64562306a36Sopenharmony_ci .peek = noop_dequeue, 64662306a36Sopenharmony_ci .owner = THIS_MODULE, 64762306a36Sopenharmony_ci}; 64862306a36Sopenharmony_ci 64962306a36Sopenharmony_cistatic struct netdev_queue noop_netdev_queue = { 65062306a36Sopenharmony_ci RCU_POINTER_INITIALIZER(qdisc, &noop_qdisc), 65162306a36Sopenharmony_ci RCU_POINTER_INITIALIZER(qdisc_sleeping, &noop_qdisc), 65262306a36Sopenharmony_ci}; 65362306a36Sopenharmony_ci 65462306a36Sopenharmony_cistruct Qdisc noop_qdisc = { 65562306a36Sopenharmony_ci .enqueue = noop_enqueue, 65662306a36Sopenharmony_ci .dequeue = noop_dequeue, 65762306a36Sopenharmony_ci .flags = TCQ_F_BUILTIN, 65862306a36Sopenharmony_ci .ops = &noop_qdisc_ops, 65962306a36Sopenharmony_ci .q.lock = __SPIN_LOCK_UNLOCKED(noop_qdisc.q.lock), 66062306a36Sopenharmony_ci .dev_queue = &noop_netdev_queue, 66162306a36Sopenharmony_ci .busylock = __SPIN_LOCK_UNLOCKED(noop_qdisc.busylock), 66262306a36Sopenharmony_ci .gso_skb = { 66362306a36Sopenharmony_ci .next = (struct sk_buff *)&noop_qdisc.gso_skb, 66462306a36Sopenharmony_ci .prev = (struct sk_buff *)&noop_qdisc.gso_skb, 66562306a36Sopenharmony_ci .qlen = 0, 66662306a36Sopenharmony_ci .lock = __SPIN_LOCK_UNLOCKED(noop_qdisc.gso_skb.lock), 66762306a36Sopenharmony_ci }, 66862306a36Sopenharmony_ci .skb_bad_txq = { 66962306a36Sopenharmony_ci .next = (struct sk_buff *)&noop_qdisc.skb_bad_txq, 67062306a36Sopenharmony_ci .prev = (struct sk_buff *)&noop_qdisc.skb_bad_txq, 67162306a36Sopenharmony_ci .qlen = 0, 67262306a36Sopenharmony_ci .lock = __SPIN_LOCK_UNLOCKED(noop_qdisc.skb_bad_txq.lock), 67362306a36Sopenharmony_ci }, 67462306a36Sopenharmony_ci}; 67562306a36Sopenharmony_ciEXPORT_SYMBOL(noop_qdisc); 67662306a36Sopenharmony_ci 67762306a36Sopenharmony_cistatic int noqueue_init(struct Qdisc *qdisc, struct nlattr *opt, 67862306a36Sopenharmony_ci struct netlink_ext_ack *extack) 67962306a36Sopenharmony_ci{ 68062306a36Sopenharmony_ci /* register_qdisc() assigns a default of noop_enqueue if unset, 68162306a36Sopenharmony_ci * but __dev_queue_xmit() treats noqueue only as such 68262306a36Sopenharmony_ci * if this is NULL - so clear it here. */ 68362306a36Sopenharmony_ci qdisc->enqueue = NULL; 68462306a36Sopenharmony_ci return 0; 68562306a36Sopenharmony_ci} 68662306a36Sopenharmony_ci 68762306a36Sopenharmony_cistruct Qdisc_ops noqueue_qdisc_ops __read_mostly = { 68862306a36Sopenharmony_ci .id = "noqueue", 68962306a36Sopenharmony_ci .priv_size = 0, 69062306a36Sopenharmony_ci .init = noqueue_init, 69162306a36Sopenharmony_ci .enqueue = noop_enqueue, 69262306a36Sopenharmony_ci .dequeue = noop_dequeue, 69362306a36Sopenharmony_ci .peek = noop_dequeue, 69462306a36Sopenharmony_ci .owner = THIS_MODULE, 69562306a36Sopenharmony_ci}; 69662306a36Sopenharmony_ci 69762306a36Sopenharmony_cistatic const u8 prio2band[TC_PRIO_MAX + 1] = { 69862306a36Sopenharmony_ci 1, 2, 2, 2, 1, 2, 0, 0 , 1, 1, 1, 1, 1, 1, 1, 1 69962306a36Sopenharmony_ci}; 70062306a36Sopenharmony_ci 70162306a36Sopenharmony_ci/* 3-band FIFO queue: old style, but should be a bit faster than 70262306a36Sopenharmony_ci generic prio+fifo combination. 70362306a36Sopenharmony_ci */ 70462306a36Sopenharmony_ci 70562306a36Sopenharmony_ci#define PFIFO_FAST_BANDS 3 70662306a36Sopenharmony_ci 70762306a36Sopenharmony_ci/* 70862306a36Sopenharmony_ci * Private data for a pfifo_fast scheduler containing: 70962306a36Sopenharmony_ci * - rings for priority bands 71062306a36Sopenharmony_ci */ 71162306a36Sopenharmony_cistruct pfifo_fast_priv { 71262306a36Sopenharmony_ci struct skb_array q[PFIFO_FAST_BANDS]; 71362306a36Sopenharmony_ci}; 71462306a36Sopenharmony_ci 71562306a36Sopenharmony_cistatic inline struct skb_array *band2list(struct pfifo_fast_priv *priv, 71662306a36Sopenharmony_ci int band) 71762306a36Sopenharmony_ci{ 71862306a36Sopenharmony_ci return &priv->q[band]; 71962306a36Sopenharmony_ci} 72062306a36Sopenharmony_ci 72162306a36Sopenharmony_cistatic int pfifo_fast_enqueue(struct sk_buff *skb, struct Qdisc *qdisc, 72262306a36Sopenharmony_ci struct sk_buff **to_free) 72362306a36Sopenharmony_ci{ 72462306a36Sopenharmony_ci int band = prio2band[skb->priority & TC_PRIO_MAX]; 72562306a36Sopenharmony_ci struct pfifo_fast_priv *priv = qdisc_priv(qdisc); 72662306a36Sopenharmony_ci struct skb_array *q = band2list(priv, band); 72762306a36Sopenharmony_ci unsigned int pkt_len = qdisc_pkt_len(skb); 72862306a36Sopenharmony_ci int err; 72962306a36Sopenharmony_ci 73062306a36Sopenharmony_ci err = skb_array_produce(q, skb); 73162306a36Sopenharmony_ci 73262306a36Sopenharmony_ci if (unlikely(err)) { 73362306a36Sopenharmony_ci if (qdisc_is_percpu_stats(qdisc)) 73462306a36Sopenharmony_ci return qdisc_drop_cpu(skb, qdisc, to_free); 73562306a36Sopenharmony_ci else 73662306a36Sopenharmony_ci return qdisc_drop(skb, qdisc, to_free); 73762306a36Sopenharmony_ci } 73862306a36Sopenharmony_ci 73962306a36Sopenharmony_ci qdisc_update_stats_at_enqueue(qdisc, pkt_len); 74062306a36Sopenharmony_ci return NET_XMIT_SUCCESS; 74162306a36Sopenharmony_ci} 74262306a36Sopenharmony_ci 74362306a36Sopenharmony_cistatic struct sk_buff *pfifo_fast_dequeue(struct Qdisc *qdisc) 74462306a36Sopenharmony_ci{ 74562306a36Sopenharmony_ci struct pfifo_fast_priv *priv = qdisc_priv(qdisc); 74662306a36Sopenharmony_ci struct sk_buff *skb = NULL; 74762306a36Sopenharmony_ci bool need_retry = true; 74862306a36Sopenharmony_ci int band; 74962306a36Sopenharmony_ci 75062306a36Sopenharmony_ciretry: 75162306a36Sopenharmony_ci for (band = 0; band < PFIFO_FAST_BANDS && !skb; band++) { 75262306a36Sopenharmony_ci struct skb_array *q = band2list(priv, band); 75362306a36Sopenharmony_ci 75462306a36Sopenharmony_ci if (__skb_array_empty(q)) 75562306a36Sopenharmony_ci continue; 75662306a36Sopenharmony_ci 75762306a36Sopenharmony_ci skb = __skb_array_consume(q); 75862306a36Sopenharmony_ci } 75962306a36Sopenharmony_ci if (likely(skb)) { 76062306a36Sopenharmony_ci qdisc_update_stats_at_dequeue(qdisc, skb); 76162306a36Sopenharmony_ci } else if (need_retry && 76262306a36Sopenharmony_ci READ_ONCE(qdisc->state) & QDISC_STATE_NON_EMPTY) { 76362306a36Sopenharmony_ci /* Delay clearing the STATE_MISSED here to reduce 76462306a36Sopenharmony_ci * the overhead of the second spin_trylock() in 76562306a36Sopenharmony_ci * qdisc_run_begin() and __netif_schedule() calling 76662306a36Sopenharmony_ci * in qdisc_run_end(). 76762306a36Sopenharmony_ci */ 76862306a36Sopenharmony_ci clear_bit(__QDISC_STATE_MISSED, &qdisc->state); 76962306a36Sopenharmony_ci clear_bit(__QDISC_STATE_DRAINING, &qdisc->state); 77062306a36Sopenharmony_ci 77162306a36Sopenharmony_ci /* Make sure dequeuing happens after clearing 77262306a36Sopenharmony_ci * STATE_MISSED. 77362306a36Sopenharmony_ci */ 77462306a36Sopenharmony_ci smp_mb__after_atomic(); 77562306a36Sopenharmony_ci 77662306a36Sopenharmony_ci need_retry = false; 77762306a36Sopenharmony_ci 77862306a36Sopenharmony_ci goto retry; 77962306a36Sopenharmony_ci } 78062306a36Sopenharmony_ci 78162306a36Sopenharmony_ci return skb; 78262306a36Sopenharmony_ci} 78362306a36Sopenharmony_ci 78462306a36Sopenharmony_cistatic struct sk_buff *pfifo_fast_peek(struct Qdisc *qdisc) 78562306a36Sopenharmony_ci{ 78662306a36Sopenharmony_ci struct pfifo_fast_priv *priv = qdisc_priv(qdisc); 78762306a36Sopenharmony_ci struct sk_buff *skb = NULL; 78862306a36Sopenharmony_ci int band; 78962306a36Sopenharmony_ci 79062306a36Sopenharmony_ci for (band = 0; band < PFIFO_FAST_BANDS && !skb; band++) { 79162306a36Sopenharmony_ci struct skb_array *q = band2list(priv, band); 79262306a36Sopenharmony_ci 79362306a36Sopenharmony_ci skb = __skb_array_peek(q); 79462306a36Sopenharmony_ci } 79562306a36Sopenharmony_ci 79662306a36Sopenharmony_ci return skb; 79762306a36Sopenharmony_ci} 79862306a36Sopenharmony_ci 79962306a36Sopenharmony_cistatic void pfifo_fast_reset(struct Qdisc *qdisc) 80062306a36Sopenharmony_ci{ 80162306a36Sopenharmony_ci int i, band; 80262306a36Sopenharmony_ci struct pfifo_fast_priv *priv = qdisc_priv(qdisc); 80362306a36Sopenharmony_ci 80462306a36Sopenharmony_ci for (band = 0; band < PFIFO_FAST_BANDS; band++) { 80562306a36Sopenharmony_ci struct skb_array *q = band2list(priv, band); 80662306a36Sopenharmony_ci struct sk_buff *skb; 80762306a36Sopenharmony_ci 80862306a36Sopenharmony_ci /* NULL ring is possible if destroy path is due to a failed 80962306a36Sopenharmony_ci * skb_array_init() in pfifo_fast_init() case. 81062306a36Sopenharmony_ci */ 81162306a36Sopenharmony_ci if (!q->ring.queue) 81262306a36Sopenharmony_ci continue; 81362306a36Sopenharmony_ci 81462306a36Sopenharmony_ci while ((skb = __skb_array_consume(q)) != NULL) 81562306a36Sopenharmony_ci kfree_skb(skb); 81662306a36Sopenharmony_ci } 81762306a36Sopenharmony_ci 81862306a36Sopenharmony_ci if (qdisc_is_percpu_stats(qdisc)) { 81962306a36Sopenharmony_ci for_each_possible_cpu(i) { 82062306a36Sopenharmony_ci struct gnet_stats_queue *q; 82162306a36Sopenharmony_ci 82262306a36Sopenharmony_ci q = per_cpu_ptr(qdisc->cpu_qstats, i); 82362306a36Sopenharmony_ci q->backlog = 0; 82462306a36Sopenharmony_ci q->qlen = 0; 82562306a36Sopenharmony_ci } 82662306a36Sopenharmony_ci } 82762306a36Sopenharmony_ci} 82862306a36Sopenharmony_ci 82962306a36Sopenharmony_cistatic int pfifo_fast_dump(struct Qdisc *qdisc, struct sk_buff *skb) 83062306a36Sopenharmony_ci{ 83162306a36Sopenharmony_ci struct tc_prio_qopt opt = { .bands = PFIFO_FAST_BANDS }; 83262306a36Sopenharmony_ci 83362306a36Sopenharmony_ci memcpy(&opt.priomap, prio2band, TC_PRIO_MAX + 1); 83462306a36Sopenharmony_ci if (nla_put(skb, TCA_OPTIONS, sizeof(opt), &opt)) 83562306a36Sopenharmony_ci goto nla_put_failure; 83662306a36Sopenharmony_ci return skb->len; 83762306a36Sopenharmony_ci 83862306a36Sopenharmony_cinla_put_failure: 83962306a36Sopenharmony_ci return -1; 84062306a36Sopenharmony_ci} 84162306a36Sopenharmony_ci 84262306a36Sopenharmony_cistatic int pfifo_fast_init(struct Qdisc *qdisc, struct nlattr *opt, 84362306a36Sopenharmony_ci struct netlink_ext_ack *extack) 84462306a36Sopenharmony_ci{ 84562306a36Sopenharmony_ci unsigned int qlen = qdisc_dev(qdisc)->tx_queue_len; 84662306a36Sopenharmony_ci struct pfifo_fast_priv *priv = qdisc_priv(qdisc); 84762306a36Sopenharmony_ci int prio; 84862306a36Sopenharmony_ci 84962306a36Sopenharmony_ci /* guard against zero length rings */ 85062306a36Sopenharmony_ci if (!qlen) 85162306a36Sopenharmony_ci return -EINVAL; 85262306a36Sopenharmony_ci 85362306a36Sopenharmony_ci for (prio = 0; prio < PFIFO_FAST_BANDS; prio++) { 85462306a36Sopenharmony_ci struct skb_array *q = band2list(priv, prio); 85562306a36Sopenharmony_ci int err; 85662306a36Sopenharmony_ci 85762306a36Sopenharmony_ci err = skb_array_init(q, qlen, GFP_KERNEL); 85862306a36Sopenharmony_ci if (err) 85962306a36Sopenharmony_ci return -ENOMEM; 86062306a36Sopenharmony_ci } 86162306a36Sopenharmony_ci 86262306a36Sopenharmony_ci /* Can by-pass the queue discipline */ 86362306a36Sopenharmony_ci qdisc->flags |= TCQ_F_CAN_BYPASS; 86462306a36Sopenharmony_ci return 0; 86562306a36Sopenharmony_ci} 86662306a36Sopenharmony_ci 86762306a36Sopenharmony_cistatic void pfifo_fast_destroy(struct Qdisc *sch) 86862306a36Sopenharmony_ci{ 86962306a36Sopenharmony_ci struct pfifo_fast_priv *priv = qdisc_priv(sch); 87062306a36Sopenharmony_ci int prio; 87162306a36Sopenharmony_ci 87262306a36Sopenharmony_ci for (prio = 0; prio < PFIFO_FAST_BANDS; prio++) { 87362306a36Sopenharmony_ci struct skb_array *q = band2list(priv, prio); 87462306a36Sopenharmony_ci 87562306a36Sopenharmony_ci /* NULL ring is possible if destroy path is due to a failed 87662306a36Sopenharmony_ci * skb_array_init() in pfifo_fast_init() case. 87762306a36Sopenharmony_ci */ 87862306a36Sopenharmony_ci if (!q->ring.queue) 87962306a36Sopenharmony_ci continue; 88062306a36Sopenharmony_ci /* Destroy ring but no need to kfree_skb because a call to 88162306a36Sopenharmony_ci * pfifo_fast_reset() has already done that work. 88262306a36Sopenharmony_ci */ 88362306a36Sopenharmony_ci ptr_ring_cleanup(&q->ring, NULL); 88462306a36Sopenharmony_ci } 88562306a36Sopenharmony_ci} 88662306a36Sopenharmony_ci 88762306a36Sopenharmony_cistatic int pfifo_fast_change_tx_queue_len(struct Qdisc *sch, 88862306a36Sopenharmony_ci unsigned int new_len) 88962306a36Sopenharmony_ci{ 89062306a36Sopenharmony_ci struct pfifo_fast_priv *priv = qdisc_priv(sch); 89162306a36Sopenharmony_ci struct skb_array *bands[PFIFO_FAST_BANDS]; 89262306a36Sopenharmony_ci int prio; 89362306a36Sopenharmony_ci 89462306a36Sopenharmony_ci for (prio = 0; prio < PFIFO_FAST_BANDS; prio++) { 89562306a36Sopenharmony_ci struct skb_array *q = band2list(priv, prio); 89662306a36Sopenharmony_ci 89762306a36Sopenharmony_ci bands[prio] = q; 89862306a36Sopenharmony_ci } 89962306a36Sopenharmony_ci 90062306a36Sopenharmony_ci return skb_array_resize_multiple(bands, PFIFO_FAST_BANDS, new_len, 90162306a36Sopenharmony_ci GFP_KERNEL); 90262306a36Sopenharmony_ci} 90362306a36Sopenharmony_ci 90462306a36Sopenharmony_cistruct Qdisc_ops pfifo_fast_ops __read_mostly = { 90562306a36Sopenharmony_ci .id = "pfifo_fast", 90662306a36Sopenharmony_ci .priv_size = sizeof(struct pfifo_fast_priv), 90762306a36Sopenharmony_ci .enqueue = pfifo_fast_enqueue, 90862306a36Sopenharmony_ci .dequeue = pfifo_fast_dequeue, 90962306a36Sopenharmony_ci .peek = pfifo_fast_peek, 91062306a36Sopenharmony_ci .init = pfifo_fast_init, 91162306a36Sopenharmony_ci .destroy = pfifo_fast_destroy, 91262306a36Sopenharmony_ci .reset = pfifo_fast_reset, 91362306a36Sopenharmony_ci .dump = pfifo_fast_dump, 91462306a36Sopenharmony_ci .change_tx_queue_len = pfifo_fast_change_tx_queue_len, 91562306a36Sopenharmony_ci .owner = THIS_MODULE, 91662306a36Sopenharmony_ci .static_flags = TCQ_F_NOLOCK | TCQ_F_CPUSTATS, 91762306a36Sopenharmony_ci}; 91862306a36Sopenharmony_ciEXPORT_SYMBOL(pfifo_fast_ops); 91962306a36Sopenharmony_ci 92062306a36Sopenharmony_cistatic struct lock_class_key qdisc_tx_busylock; 92162306a36Sopenharmony_ci 92262306a36Sopenharmony_cistruct Qdisc *qdisc_alloc(struct netdev_queue *dev_queue, 92362306a36Sopenharmony_ci const struct Qdisc_ops *ops, 92462306a36Sopenharmony_ci struct netlink_ext_ack *extack) 92562306a36Sopenharmony_ci{ 92662306a36Sopenharmony_ci struct Qdisc *sch; 92762306a36Sopenharmony_ci unsigned int size = sizeof(*sch) + ops->priv_size; 92862306a36Sopenharmony_ci int err = -ENOBUFS; 92962306a36Sopenharmony_ci struct net_device *dev; 93062306a36Sopenharmony_ci 93162306a36Sopenharmony_ci if (!dev_queue) { 93262306a36Sopenharmony_ci NL_SET_ERR_MSG(extack, "No device queue given"); 93362306a36Sopenharmony_ci err = -EINVAL; 93462306a36Sopenharmony_ci goto errout; 93562306a36Sopenharmony_ci } 93662306a36Sopenharmony_ci 93762306a36Sopenharmony_ci dev = dev_queue->dev; 93862306a36Sopenharmony_ci sch = kzalloc_node(size, GFP_KERNEL, netdev_queue_numa_node_read(dev_queue)); 93962306a36Sopenharmony_ci 94062306a36Sopenharmony_ci if (!sch) 94162306a36Sopenharmony_ci goto errout; 94262306a36Sopenharmony_ci __skb_queue_head_init(&sch->gso_skb); 94362306a36Sopenharmony_ci __skb_queue_head_init(&sch->skb_bad_txq); 94462306a36Sopenharmony_ci gnet_stats_basic_sync_init(&sch->bstats); 94562306a36Sopenharmony_ci spin_lock_init(&sch->q.lock); 94662306a36Sopenharmony_ci 94762306a36Sopenharmony_ci if (ops->static_flags & TCQ_F_CPUSTATS) { 94862306a36Sopenharmony_ci sch->cpu_bstats = 94962306a36Sopenharmony_ci netdev_alloc_pcpu_stats(struct gnet_stats_basic_sync); 95062306a36Sopenharmony_ci if (!sch->cpu_bstats) 95162306a36Sopenharmony_ci goto errout1; 95262306a36Sopenharmony_ci 95362306a36Sopenharmony_ci sch->cpu_qstats = alloc_percpu(struct gnet_stats_queue); 95462306a36Sopenharmony_ci if (!sch->cpu_qstats) { 95562306a36Sopenharmony_ci free_percpu(sch->cpu_bstats); 95662306a36Sopenharmony_ci goto errout1; 95762306a36Sopenharmony_ci } 95862306a36Sopenharmony_ci } 95962306a36Sopenharmony_ci 96062306a36Sopenharmony_ci spin_lock_init(&sch->busylock); 96162306a36Sopenharmony_ci lockdep_set_class(&sch->busylock, 96262306a36Sopenharmony_ci dev->qdisc_tx_busylock ?: &qdisc_tx_busylock); 96362306a36Sopenharmony_ci 96462306a36Sopenharmony_ci /* seqlock has the same scope of busylock, for NOLOCK qdisc */ 96562306a36Sopenharmony_ci spin_lock_init(&sch->seqlock); 96662306a36Sopenharmony_ci lockdep_set_class(&sch->seqlock, 96762306a36Sopenharmony_ci dev->qdisc_tx_busylock ?: &qdisc_tx_busylock); 96862306a36Sopenharmony_ci 96962306a36Sopenharmony_ci sch->ops = ops; 97062306a36Sopenharmony_ci sch->flags = ops->static_flags; 97162306a36Sopenharmony_ci sch->enqueue = ops->enqueue; 97262306a36Sopenharmony_ci sch->dequeue = ops->dequeue; 97362306a36Sopenharmony_ci sch->dev_queue = dev_queue; 97462306a36Sopenharmony_ci netdev_hold(dev, &sch->dev_tracker, GFP_KERNEL); 97562306a36Sopenharmony_ci refcount_set(&sch->refcnt, 1); 97662306a36Sopenharmony_ci 97762306a36Sopenharmony_ci return sch; 97862306a36Sopenharmony_cierrout1: 97962306a36Sopenharmony_ci kfree(sch); 98062306a36Sopenharmony_cierrout: 98162306a36Sopenharmony_ci return ERR_PTR(err); 98262306a36Sopenharmony_ci} 98362306a36Sopenharmony_ci 98462306a36Sopenharmony_cistruct Qdisc *qdisc_create_dflt(struct netdev_queue *dev_queue, 98562306a36Sopenharmony_ci const struct Qdisc_ops *ops, 98662306a36Sopenharmony_ci unsigned int parentid, 98762306a36Sopenharmony_ci struct netlink_ext_ack *extack) 98862306a36Sopenharmony_ci{ 98962306a36Sopenharmony_ci struct Qdisc *sch; 99062306a36Sopenharmony_ci 99162306a36Sopenharmony_ci if (!try_module_get(ops->owner)) { 99262306a36Sopenharmony_ci NL_SET_ERR_MSG(extack, "Failed to increase module reference counter"); 99362306a36Sopenharmony_ci return NULL; 99462306a36Sopenharmony_ci } 99562306a36Sopenharmony_ci 99662306a36Sopenharmony_ci sch = qdisc_alloc(dev_queue, ops, extack); 99762306a36Sopenharmony_ci if (IS_ERR(sch)) { 99862306a36Sopenharmony_ci module_put(ops->owner); 99962306a36Sopenharmony_ci return NULL; 100062306a36Sopenharmony_ci } 100162306a36Sopenharmony_ci sch->parent = parentid; 100262306a36Sopenharmony_ci 100362306a36Sopenharmony_ci if (!ops->init || ops->init(sch, NULL, extack) == 0) { 100462306a36Sopenharmony_ci trace_qdisc_create(ops, dev_queue->dev, parentid); 100562306a36Sopenharmony_ci return sch; 100662306a36Sopenharmony_ci } 100762306a36Sopenharmony_ci 100862306a36Sopenharmony_ci qdisc_put(sch); 100962306a36Sopenharmony_ci return NULL; 101062306a36Sopenharmony_ci} 101162306a36Sopenharmony_ciEXPORT_SYMBOL(qdisc_create_dflt); 101262306a36Sopenharmony_ci 101362306a36Sopenharmony_ci/* Under qdisc_lock(qdisc) and BH! */ 101462306a36Sopenharmony_ci 101562306a36Sopenharmony_civoid qdisc_reset(struct Qdisc *qdisc) 101662306a36Sopenharmony_ci{ 101762306a36Sopenharmony_ci const struct Qdisc_ops *ops = qdisc->ops; 101862306a36Sopenharmony_ci 101962306a36Sopenharmony_ci trace_qdisc_reset(qdisc); 102062306a36Sopenharmony_ci 102162306a36Sopenharmony_ci if (ops->reset) 102262306a36Sopenharmony_ci ops->reset(qdisc); 102362306a36Sopenharmony_ci 102462306a36Sopenharmony_ci __skb_queue_purge(&qdisc->gso_skb); 102562306a36Sopenharmony_ci __skb_queue_purge(&qdisc->skb_bad_txq); 102662306a36Sopenharmony_ci 102762306a36Sopenharmony_ci qdisc->q.qlen = 0; 102862306a36Sopenharmony_ci qdisc->qstats.backlog = 0; 102962306a36Sopenharmony_ci} 103062306a36Sopenharmony_ciEXPORT_SYMBOL(qdisc_reset); 103162306a36Sopenharmony_ci 103262306a36Sopenharmony_civoid qdisc_free(struct Qdisc *qdisc) 103362306a36Sopenharmony_ci{ 103462306a36Sopenharmony_ci if (qdisc_is_percpu_stats(qdisc)) { 103562306a36Sopenharmony_ci free_percpu(qdisc->cpu_bstats); 103662306a36Sopenharmony_ci free_percpu(qdisc->cpu_qstats); 103762306a36Sopenharmony_ci } 103862306a36Sopenharmony_ci 103962306a36Sopenharmony_ci kfree(qdisc); 104062306a36Sopenharmony_ci} 104162306a36Sopenharmony_ci 104262306a36Sopenharmony_cistatic void qdisc_free_cb(struct rcu_head *head) 104362306a36Sopenharmony_ci{ 104462306a36Sopenharmony_ci struct Qdisc *q = container_of(head, struct Qdisc, rcu); 104562306a36Sopenharmony_ci 104662306a36Sopenharmony_ci qdisc_free(q); 104762306a36Sopenharmony_ci} 104862306a36Sopenharmony_ci 104962306a36Sopenharmony_cistatic void __qdisc_destroy(struct Qdisc *qdisc) 105062306a36Sopenharmony_ci{ 105162306a36Sopenharmony_ci const struct Qdisc_ops *ops = qdisc->ops; 105262306a36Sopenharmony_ci 105362306a36Sopenharmony_ci#ifdef CONFIG_NET_SCHED 105462306a36Sopenharmony_ci qdisc_hash_del(qdisc); 105562306a36Sopenharmony_ci 105662306a36Sopenharmony_ci qdisc_put_stab(rtnl_dereference(qdisc->stab)); 105762306a36Sopenharmony_ci#endif 105862306a36Sopenharmony_ci gen_kill_estimator(&qdisc->rate_est); 105962306a36Sopenharmony_ci 106062306a36Sopenharmony_ci qdisc_reset(qdisc); 106162306a36Sopenharmony_ci 106262306a36Sopenharmony_ci if (ops->destroy) 106362306a36Sopenharmony_ci ops->destroy(qdisc); 106462306a36Sopenharmony_ci 106562306a36Sopenharmony_ci module_put(ops->owner); 106662306a36Sopenharmony_ci netdev_put(qdisc_dev(qdisc), &qdisc->dev_tracker); 106762306a36Sopenharmony_ci 106862306a36Sopenharmony_ci trace_qdisc_destroy(qdisc); 106962306a36Sopenharmony_ci 107062306a36Sopenharmony_ci call_rcu(&qdisc->rcu, qdisc_free_cb); 107162306a36Sopenharmony_ci} 107262306a36Sopenharmony_ci 107362306a36Sopenharmony_civoid qdisc_destroy(struct Qdisc *qdisc) 107462306a36Sopenharmony_ci{ 107562306a36Sopenharmony_ci if (qdisc->flags & TCQ_F_BUILTIN) 107662306a36Sopenharmony_ci return; 107762306a36Sopenharmony_ci 107862306a36Sopenharmony_ci __qdisc_destroy(qdisc); 107962306a36Sopenharmony_ci} 108062306a36Sopenharmony_ci 108162306a36Sopenharmony_civoid qdisc_put(struct Qdisc *qdisc) 108262306a36Sopenharmony_ci{ 108362306a36Sopenharmony_ci if (!qdisc) 108462306a36Sopenharmony_ci return; 108562306a36Sopenharmony_ci 108662306a36Sopenharmony_ci if (qdisc->flags & TCQ_F_BUILTIN || 108762306a36Sopenharmony_ci !refcount_dec_and_test(&qdisc->refcnt)) 108862306a36Sopenharmony_ci return; 108962306a36Sopenharmony_ci 109062306a36Sopenharmony_ci __qdisc_destroy(qdisc); 109162306a36Sopenharmony_ci} 109262306a36Sopenharmony_ciEXPORT_SYMBOL(qdisc_put); 109362306a36Sopenharmony_ci 109462306a36Sopenharmony_ci/* Version of qdisc_put() that is called with rtnl mutex unlocked. 109562306a36Sopenharmony_ci * Intended to be used as optimization, this function only takes rtnl lock if 109662306a36Sopenharmony_ci * qdisc reference counter reached zero. 109762306a36Sopenharmony_ci */ 109862306a36Sopenharmony_ci 109962306a36Sopenharmony_civoid qdisc_put_unlocked(struct Qdisc *qdisc) 110062306a36Sopenharmony_ci{ 110162306a36Sopenharmony_ci if (qdisc->flags & TCQ_F_BUILTIN || 110262306a36Sopenharmony_ci !refcount_dec_and_rtnl_lock(&qdisc->refcnt)) 110362306a36Sopenharmony_ci return; 110462306a36Sopenharmony_ci 110562306a36Sopenharmony_ci __qdisc_destroy(qdisc); 110662306a36Sopenharmony_ci rtnl_unlock(); 110762306a36Sopenharmony_ci} 110862306a36Sopenharmony_ciEXPORT_SYMBOL(qdisc_put_unlocked); 110962306a36Sopenharmony_ci 111062306a36Sopenharmony_ci/* Attach toplevel qdisc to device queue. */ 111162306a36Sopenharmony_cistruct Qdisc *dev_graft_qdisc(struct netdev_queue *dev_queue, 111262306a36Sopenharmony_ci struct Qdisc *qdisc) 111362306a36Sopenharmony_ci{ 111462306a36Sopenharmony_ci struct Qdisc *oqdisc = rtnl_dereference(dev_queue->qdisc_sleeping); 111562306a36Sopenharmony_ci spinlock_t *root_lock; 111662306a36Sopenharmony_ci 111762306a36Sopenharmony_ci root_lock = qdisc_lock(oqdisc); 111862306a36Sopenharmony_ci spin_lock_bh(root_lock); 111962306a36Sopenharmony_ci 112062306a36Sopenharmony_ci /* ... and graft new one */ 112162306a36Sopenharmony_ci if (qdisc == NULL) 112262306a36Sopenharmony_ci qdisc = &noop_qdisc; 112362306a36Sopenharmony_ci rcu_assign_pointer(dev_queue->qdisc_sleeping, qdisc); 112462306a36Sopenharmony_ci rcu_assign_pointer(dev_queue->qdisc, &noop_qdisc); 112562306a36Sopenharmony_ci 112662306a36Sopenharmony_ci spin_unlock_bh(root_lock); 112762306a36Sopenharmony_ci 112862306a36Sopenharmony_ci return oqdisc; 112962306a36Sopenharmony_ci} 113062306a36Sopenharmony_ciEXPORT_SYMBOL(dev_graft_qdisc); 113162306a36Sopenharmony_ci 113262306a36Sopenharmony_cistatic void shutdown_scheduler_queue(struct net_device *dev, 113362306a36Sopenharmony_ci struct netdev_queue *dev_queue, 113462306a36Sopenharmony_ci void *_qdisc_default) 113562306a36Sopenharmony_ci{ 113662306a36Sopenharmony_ci struct Qdisc *qdisc = rtnl_dereference(dev_queue->qdisc_sleeping); 113762306a36Sopenharmony_ci struct Qdisc *qdisc_default = _qdisc_default; 113862306a36Sopenharmony_ci 113962306a36Sopenharmony_ci if (qdisc) { 114062306a36Sopenharmony_ci rcu_assign_pointer(dev_queue->qdisc, qdisc_default); 114162306a36Sopenharmony_ci rcu_assign_pointer(dev_queue->qdisc_sleeping, qdisc_default); 114262306a36Sopenharmony_ci 114362306a36Sopenharmony_ci qdisc_put(qdisc); 114462306a36Sopenharmony_ci } 114562306a36Sopenharmony_ci} 114662306a36Sopenharmony_ci 114762306a36Sopenharmony_cistatic void attach_one_default_qdisc(struct net_device *dev, 114862306a36Sopenharmony_ci struct netdev_queue *dev_queue, 114962306a36Sopenharmony_ci void *_unused) 115062306a36Sopenharmony_ci{ 115162306a36Sopenharmony_ci struct Qdisc *qdisc; 115262306a36Sopenharmony_ci const struct Qdisc_ops *ops = default_qdisc_ops; 115362306a36Sopenharmony_ci 115462306a36Sopenharmony_ci if (dev->priv_flags & IFF_NO_QUEUE) 115562306a36Sopenharmony_ci ops = &noqueue_qdisc_ops; 115662306a36Sopenharmony_ci else if(dev->type == ARPHRD_CAN) 115762306a36Sopenharmony_ci ops = &pfifo_fast_ops; 115862306a36Sopenharmony_ci 115962306a36Sopenharmony_ci qdisc = qdisc_create_dflt(dev_queue, ops, TC_H_ROOT, NULL); 116062306a36Sopenharmony_ci if (!qdisc) 116162306a36Sopenharmony_ci return; 116262306a36Sopenharmony_ci 116362306a36Sopenharmony_ci if (!netif_is_multiqueue(dev)) 116462306a36Sopenharmony_ci qdisc->flags |= TCQ_F_ONETXQUEUE | TCQ_F_NOPARENT; 116562306a36Sopenharmony_ci rcu_assign_pointer(dev_queue->qdisc_sleeping, qdisc); 116662306a36Sopenharmony_ci} 116762306a36Sopenharmony_ci 116862306a36Sopenharmony_cistatic void attach_default_qdiscs(struct net_device *dev) 116962306a36Sopenharmony_ci{ 117062306a36Sopenharmony_ci struct netdev_queue *txq; 117162306a36Sopenharmony_ci struct Qdisc *qdisc; 117262306a36Sopenharmony_ci 117362306a36Sopenharmony_ci txq = netdev_get_tx_queue(dev, 0); 117462306a36Sopenharmony_ci 117562306a36Sopenharmony_ci if (!netif_is_multiqueue(dev) || 117662306a36Sopenharmony_ci dev->priv_flags & IFF_NO_QUEUE) { 117762306a36Sopenharmony_ci netdev_for_each_tx_queue(dev, attach_one_default_qdisc, NULL); 117862306a36Sopenharmony_ci qdisc = rtnl_dereference(txq->qdisc_sleeping); 117962306a36Sopenharmony_ci rcu_assign_pointer(dev->qdisc, qdisc); 118062306a36Sopenharmony_ci qdisc_refcount_inc(qdisc); 118162306a36Sopenharmony_ci } else { 118262306a36Sopenharmony_ci qdisc = qdisc_create_dflt(txq, &mq_qdisc_ops, TC_H_ROOT, NULL); 118362306a36Sopenharmony_ci if (qdisc) { 118462306a36Sopenharmony_ci rcu_assign_pointer(dev->qdisc, qdisc); 118562306a36Sopenharmony_ci qdisc->ops->attach(qdisc); 118662306a36Sopenharmony_ci } 118762306a36Sopenharmony_ci } 118862306a36Sopenharmony_ci qdisc = rtnl_dereference(dev->qdisc); 118962306a36Sopenharmony_ci 119062306a36Sopenharmony_ci /* Detect default qdisc setup/init failed and fallback to "noqueue" */ 119162306a36Sopenharmony_ci if (qdisc == &noop_qdisc) { 119262306a36Sopenharmony_ci netdev_warn(dev, "default qdisc (%s) fail, fallback to %s\n", 119362306a36Sopenharmony_ci default_qdisc_ops->id, noqueue_qdisc_ops.id); 119462306a36Sopenharmony_ci netdev_for_each_tx_queue(dev, shutdown_scheduler_queue, &noop_qdisc); 119562306a36Sopenharmony_ci dev->priv_flags |= IFF_NO_QUEUE; 119662306a36Sopenharmony_ci netdev_for_each_tx_queue(dev, attach_one_default_qdisc, NULL); 119762306a36Sopenharmony_ci qdisc = rtnl_dereference(txq->qdisc_sleeping); 119862306a36Sopenharmony_ci rcu_assign_pointer(dev->qdisc, qdisc); 119962306a36Sopenharmony_ci qdisc_refcount_inc(qdisc); 120062306a36Sopenharmony_ci dev->priv_flags ^= IFF_NO_QUEUE; 120162306a36Sopenharmony_ci } 120262306a36Sopenharmony_ci 120362306a36Sopenharmony_ci#ifdef CONFIG_NET_SCHED 120462306a36Sopenharmony_ci if (qdisc != &noop_qdisc) 120562306a36Sopenharmony_ci qdisc_hash_add(qdisc, false); 120662306a36Sopenharmony_ci#endif 120762306a36Sopenharmony_ci} 120862306a36Sopenharmony_ci 120962306a36Sopenharmony_cistatic void transition_one_qdisc(struct net_device *dev, 121062306a36Sopenharmony_ci struct netdev_queue *dev_queue, 121162306a36Sopenharmony_ci void *_need_watchdog) 121262306a36Sopenharmony_ci{ 121362306a36Sopenharmony_ci struct Qdisc *new_qdisc = rtnl_dereference(dev_queue->qdisc_sleeping); 121462306a36Sopenharmony_ci int *need_watchdog_p = _need_watchdog; 121562306a36Sopenharmony_ci 121662306a36Sopenharmony_ci if (!(new_qdisc->flags & TCQ_F_BUILTIN)) 121762306a36Sopenharmony_ci clear_bit(__QDISC_STATE_DEACTIVATED, &new_qdisc->state); 121862306a36Sopenharmony_ci 121962306a36Sopenharmony_ci rcu_assign_pointer(dev_queue->qdisc, new_qdisc); 122062306a36Sopenharmony_ci if (need_watchdog_p) { 122162306a36Sopenharmony_ci WRITE_ONCE(dev_queue->trans_start, 0); 122262306a36Sopenharmony_ci *need_watchdog_p = 1; 122362306a36Sopenharmony_ci } 122462306a36Sopenharmony_ci} 122562306a36Sopenharmony_ci 122662306a36Sopenharmony_civoid dev_activate(struct net_device *dev) 122762306a36Sopenharmony_ci{ 122862306a36Sopenharmony_ci int need_watchdog; 122962306a36Sopenharmony_ci 123062306a36Sopenharmony_ci /* No queueing discipline is attached to device; 123162306a36Sopenharmony_ci * create default one for devices, which need queueing 123262306a36Sopenharmony_ci * and noqueue_qdisc for virtual interfaces 123362306a36Sopenharmony_ci */ 123462306a36Sopenharmony_ci 123562306a36Sopenharmony_ci if (rtnl_dereference(dev->qdisc) == &noop_qdisc) 123662306a36Sopenharmony_ci attach_default_qdiscs(dev); 123762306a36Sopenharmony_ci 123862306a36Sopenharmony_ci if (!netif_carrier_ok(dev)) 123962306a36Sopenharmony_ci /* Delay activation until next carrier-on event */ 124062306a36Sopenharmony_ci return; 124162306a36Sopenharmony_ci 124262306a36Sopenharmony_ci need_watchdog = 0; 124362306a36Sopenharmony_ci netdev_for_each_tx_queue(dev, transition_one_qdisc, &need_watchdog); 124462306a36Sopenharmony_ci if (dev_ingress_queue(dev)) 124562306a36Sopenharmony_ci transition_one_qdisc(dev, dev_ingress_queue(dev), NULL); 124662306a36Sopenharmony_ci 124762306a36Sopenharmony_ci if (need_watchdog) { 124862306a36Sopenharmony_ci netif_trans_update(dev); 124962306a36Sopenharmony_ci dev_watchdog_up(dev); 125062306a36Sopenharmony_ci } 125162306a36Sopenharmony_ci} 125262306a36Sopenharmony_ciEXPORT_SYMBOL(dev_activate); 125362306a36Sopenharmony_ci 125462306a36Sopenharmony_cistatic void qdisc_deactivate(struct Qdisc *qdisc) 125562306a36Sopenharmony_ci{ 125662306a36Sopenharmony_ci if (qdisc->flags & TCQ_F_BUILTIN) 125762306a36Sopenharmony_ci return; 125862306a36Sopenharmony_ci 125962306a36Sopenharmony_ci set_bit(__QDISC_STATE_DEACTIVATED, &qdisc->state); 126062306a36Sopenharmony_ci} 126162306a36Sopenharmony_ci 126262306a36Sopenharmony_cistatic void dev_deactivate_queue(struct net_device *dev, 126362306a36Sopenharmony_ci struct netdev_queue *dev_queue, 126462306a36Sopenharmony_ci void *_qdisc_default) 126562306a36Sopenharmony_ci{ 126662306a36Sopenharmony_ci struct Qdisc *qdisc_default = _qdisc_default; 126762306a36Sopenharmony_ci struct Qdisc *qdisc; 126862306a36Sopenharmony_ci 126962306a36Sopenharmony_ci qdisc = rtnl_dereference(dev_queue->qdisc); 127062306a36Sopenharmony_ci if (qdisc) { 127162306a36Sopenharmony_ci qdisc_deactivate(qdisc); 127262306a36Sopenharmony_ci rcu_assign_pointer(dev_queue->qdisc, qdisc_default); 127362306a36Sopenharmony_ci } 127462306a36Sopenharmony_ci} 127562306a36Sopenharmony_ci 127662306a36Sopenharmony_cistatic void dev_reset_queue(struct net_device *dev, 127762306a36Sopenharmony_ci struct netdev_queue *dev_queue, 127862306a36Sopenharmony_ci void *_unused) 127962306a36Sopenharmony_ci{ 128062306a36Sopenharmony_ci struct Qdisc *qdisc; 128162306a36Sopenharmony_ci bool nolock; 128262306a36Sopenharmony_ci 128362306a36Sopenharmony_ci qdisc = rtnl_dereference(dev_queue->qdisc_sleeping); 128462306a36Sopenharmony_ci if (!qdisc) 128562306a36Sopenharmony_ci return; 128662306a36Sopenharmony_ci 128762306a36Sopenharmony_ci nolock = qdisc->flags & TCQ_F_NOLOCK; 128862306a36Sopenharmony_ci 128962306a36Sopenharmony_ci if (nolock) 129062306a36Sopenharmony_ci spin_lock_bh(&qdisc->seqlock); 129162306a36Sopenharmony_ci spin_lock_bh(qdisc_lock(qdisc)); 129262306a36Sopenharmony_ci 129362306a36Sopenharmony_ci qdisc_reset(qdisc); 129462306a36Sopenharmony_ci 129562306a36Sopenharmony_ci spin_unlock_bh(qdisc_lock(qdisc)); 129662306a36Sopenharmony_ci if (nolock) { 129762306a36Sopenharmony_ci clear_bit(__QDISC_STATE_MISSED, &qdisc->state); 129862306a36Sopenharmony_ci clear_bit(__QDISC_STATE_DRAINING, &qdisc->state); 129962306a36Sopenharmony_ci spin_unlock_bh(&qdisc->seqlock); 130062306a36Sopenharmony_ci } 130162306a36Sopenharmony_ci} 130262306a36Sopenharmony_ci 130362306a36Sopenharmony_cistatic bool some_qdisc_is_busy(struct net_device *dev) 130462306a36Sopenharmony_ci{ 130562306a36Sopenharmony_ci unsigned int i; 130662306a36Sopenharmony_ci 130762306a36Sopenharmony_ci for (i = 0; i < dev->num_tx_queues; i++) { 130862306a36Sopenharmony_ci struct netdev_queue *dev_queue; 130962306a36Sopenharmony_ci spinlock_t *root_lock; 131062306a36Sopenharmony_ci struct Qdisc *q; 131162306a36Sopenharmony_ci int val; 131262306a36Sopenharmony_ci 131362306a36Sopenharmony_ci dev_queue = netdev_get_tx_queue(dev, i); 131462306a36Sopenharmony_ci q = rtnl_dereference(dev_queue->qdisc_sleeping); 131562306a36Sopenharmony_ci 131662306a36Sopenharmony_ci root_lock = qdisc_lock(q); 131762306a36Sopenharmony_ci spin_lock_bh(root_lock); 131862306a36Sopenharmony_ci 131962306a36Sopenharmony_ci val = (qdisc_is_running(q) || 132062306a36Sopenharmony_ci test_bit(__QDISC_STATE_SCHED, &q->state)); 132162306a36Sopenharmony_ci 132262306a36Sopenharmony_ci spin_unlock_bh(root_lock); 132362306a36Sopenharmony_ci 132462306a36Sopenharmony_ci if (val) 132562306a36Sopenharmony_ci return true; 132662306a36Sopenharmony_ci } 132762306a36Sopenharmony_ci return false; 132862306a36Sopenharmony_ci} 132962306a36Sopenharmony_ci 133062306a36Sopenharmony_ci/** 133162306a36Sopenharmony_ci * dev_deactivate_many - deactivate transmissions on several devices 133262306a36Sopenharmony_ci * @head: list of devices to deactivate 133362306a36Sopenharmony_ci * 133462306a36Sopenharmony_ci * This function returns only when all outstanding transmissions 133562306a36Sopenharmony_ci * have completed, unless all devices are in dismantle phase. 133662306a36Sopenharmony_ci */ 133762306a36Sopenharmony_civoid dev_deactivate_many(struct list_head *head) 133862306a36Sopenharmony_ci{ 133962306a36Sopenharmony_ci struct net_device *dev; 134062306a36Sopenharmony_ci 134162306a36Sopenharmony_ci list_for_each_entry(dev, head, close_list) { 134262306a36Sopenharmony_ci netdev_for_each_tx_queue(dev, dev_deactivate_queue, 134362306a36Sopenharmony_ci &noop_qdisc); 134462306a36Sopenharmony_ci if (dev_ingress_queue(dev)) 134562306a36Sopenharmony_ci dev_deactivate_queue(dev, dev_ingress_queue(dev), 134662306a36Sopenharmony_ci &noop_qdisc); 134762306a36Sopenharmony_ci 134862306a36Sopenharmony_ci dev_watchdog_down(dev); 134962306a36Sopenharmony_ci } 135062306a36Sopenharmony_ci 135162306a36Sopenharmony_ci /* Wait for outstanding qdisc-less dev_queue_xmit calls or 135262306a36Sopenharmony_ci * outstanding qdisc enqueuing calls. 135362306a36Sopenharmony_ci * This is avoided if all devices are in dismantle phase : 135462306a36Sopenharmony_ci * Caller will call synchronize_net() for us 135562306a36Sopenharmony_ci */ 135662306a36Sopenharmony_ci synchronize_net(); 135762306a36Sopenharmony_ci 135862306a36Sopenharmony_ci list_for_each_entry(dev, head, close_list) { 135962306a36Sopenharmony_ci netdev_for_each_tx_queue(dev, dev_reset_queue, NULL); 136062306a36Sopenharmony_ci 136162306a36Sopenharmony_ci if (dev_ingress_queue(dev)) 136262306a36Sopenharmony_ci dev_reset_queue(dev, dev_ingress_queue(dev), NULL); 136362306a36Sopenharmony_ci } 136462306a36Sopenharmony_ci 136562306a36Sopenharmony_ci /* Wait for outstanding qdisc_run calls. */ 136662306a36Sopenharmony_ci list_for_each_entry(dev, head, close_list) { 136762306a36Sopenharmony_ci while (some_qdisc_is_busy(dev)) { 136862306a36Sopenharmony_ci /* wait_event() would avoid this sleep-loop but would 136962306a36Sopenharmony_ci * require expensive checks in the fast paths of packet 137062306a36Sopenharmony_ci * processing which isn't worth it. 137162306a36Sopenharmony_ci */ 137262306a36Sopenharmony_ci schedule_timeout_uninterruptible(1); 137362306a36Sopenharmony_ci } 137462306a36Sopenharmony_ci } 137562306a36Sopenharmony_ci} 137662306a36Sopenharmony_ci 137762306a36Sopenharmony_civoid dev_deactivate(struct net_device *dev) 137862306a36Sopenharmony_ci{ 137962306a36Sopenharmony_ci LIST_HEAD(single); 138062306a36Sopenharmony_ci 138162306a36Sopenharmony_ci list_add(&dev->close_list, &single); 138262306a36Sopenharmony_ci dev_deactivate_many(&single); 138362306a36Sopenharmony_ci list_del(&single); 138462306a36Sopenharmony_ci} 138562306a36Sopenharmony_ciEXPORT_SYMBOL(dev_deactivate); 138662306a36Sopenharmony_ci 138762306a36Sopenharmony_cistatic int qdisc_change_tx_queue_len(struct net_device *dev, 138862306a36Sopenharmony_ci struct netdev_queue *dev_queue) 138962306a36Sopenharmony_ci{ 139062306a36Sopenharmony_ci struct Qdisc *qdisc = rtnl_dereference(dev_queue->qdisc_sleeping); 139162306a36Sopenharmony_ci const struct Qdisc_ops *ops = qdisc->ops; 139262306a36Sopenharmony_ci 139362306a36Sopenharmony_ci if (ops->change_tx_queue_len) 139462306a36Sopenharmony_ci return ops->change_tx_queue_len(qdisc, dev->tx_queue_len); 139562306a36Sopenharmony_ci return 0; 139662306a36Sopenharmony_ci} 139762306a36Sopenharmony_ci 139862306a36Sopenharmony_civoid dev_qdisc_change_real_num_tx(struct net_device *dev, 139962306a36Sopenharmony_ci unsigned int new_real_tx) 140062306a36Sopenharmony_ci{ 140162306a36Sopenharmony_ci struct Qdisc *qdisc = rtnl_dereference(dev->qdisc); 140262306a36Sopenharmony_ci 140362306a36Sopenharmony_ci if (qdisc->ops->change_real_num_tx) 140462306a36Sopenharmony_ci qdisc->ops->change_real_num_tx(qdisc, new_real_tx); 140562306a36Sopenharmony_ci} 140662306a36Sopenharmony_ci 140762306a36Sopenharmony_civoid mq_change_real_num_tx(struct Qdisc *sch, unsigned int new_real_tx) 140862306a36Sopenharmony_ci{ 140962306a36Sopenharmony_ci#ifdef CONFIG_NET_SCHED 141062306a36Sopenharmony_ci struct net_device *dev = qdisc_dev(sch); 141162306a36Sopenharmony_ci struct Qdisc *qdisc; 141262306a36Sopenharmony_ci unsigned int i; 141362306a36Sopenharmony_ci 141462306a36Sopenharmony_ci for (i = new_real_tx; i < dev->real_num_tx_queues; i++) { 141562306a36Sopenharmony_ci qdisc = rtnl_dereference(netdev_get_tx_queue(dev, i)->qdisc_sleeping); 141662306a36Sopenharmony_ci /* Only update the default qdiscs we created, 141762306a36Sopenharmony_ci * qdiscs with handles are always hashed. 141862306a36Sopenharmony_ci */ 141962306a36Sopenharmony_ci if (qdisc != &noop_qdisc && !qdisc->handle) 142062306a36Sopenharmony_ci qdisc_hash_del(qdisc); 142162306a36Sopenharmony_ci } 142262306a36Sopenharmony_ci for (i = dev->real_num_tx_queues; i < new_real_tx; i++) { 142362306a36Sopenharmony_ci qdisc = rtnl_dereference(netdev_get_tx_queue(dev, i)->qdisc_sleeping); 142462306a36Sopenharmony_ci if (qdisc != &noop_qdisc && !qdisc->handle) 142562306a36Sopenharmony_ci qdisc_hash_add(qdisc, false); 142662306a36Sopenharmony_ci } 142762306a36Sopenharmony_ci#endif 142862306a36Sopenharmony_ci} 142962306a36Sopenharmony_ciEXPORT_SYMBOL(mq_change_real_num_tx); 143062306a36Sopenharmony_ci 143162306a36Sopenharmony_ciint dev_qdisc_change_tx_queue_len(struct net_device *dev) 143262306a36Sopenharmony_ci{ 143362306a36Sopenharmony_ci bool up = dev->flags & IFF_UP; 143462306a36Sopenharmony_ci unsigned int i; 143562306a36Sopenharmony_ci int ret = 0; 143662306a36Sopenharmony_ci 143762306a36Sopenharmony_ci if (up) 143862306a36Sopenharmony_ci dev_deactivate(dev); 143962306a36Sopenharmony_ci 144062306a36Sopenharmony_ci for (i = 0; i < dev->num_tx_queues; i++) { 144162306a36Sopenharmony_ci ret = qdisc_change_tx_queue_len(dev, &dev->_tx[i]); 144262306a36Sopenharmony_ci 144362306a36Sopenharmony_ci /* TODO: revert changes on a partial failure */ 144462306a36Sopenharmony_ci if (ret) 144562306a36Sopenharmony_ci break; 144662306a36Sopenharmony_ci } 144762306a36Sopenharmony_ci 144862306a36Sopenharmony_ci if (up) 144962306a36Sopenharmony_ci dev_activate(dev); 145062306a36Sopenharmony_ci return ret; 145162306a36Sopenharmony_ci} 145262306a36Sopenharmony_ci 145362306a36Sopenharmony_cistatic void dev_init_scheduler_queue(struct net_device *dev, 145462306a36Sopenharmony_ci struct netdev_queue *dev_queue, 145562306a36Sopenharmony_ci void *_qdisc) 145662306a36Sopenharmony_ci{ 145762306a36Sopenharmony_ci struct Qdisc *qdisc = _qdisc; 145862306a36Sopenharmony_ci 145962306a36Sopenharmony_ci rcu_assign_pointer(dev_queue->qdisc, qdisc); 146062306a36Sopenharmony_ci rcu_assign_pointer(dev_queue->qdisc_sleeping, qdisc); 146162306a36Sopenharmony_ci} 146262306a36Sopenharmony_ci 146362306a36Sopenharmony_civoid dev_init_scheduler(struct net_device *dev) 146462306a36Sopenharmony_ci{ 146562306a36Sopenharmony_ci rcu_assign_pointer(dev->qdisc, &noop_qdisc); 146662306a36Sopenharmony_ci netdev_for_each_tx_queue(dev, dev_init_scheduler_queue, &noop_qdisc); 146762306a36Sopenharmony_ci if (dev_ingress_queue(dev)) 146862306a36Sopenharmony_ci dev_init_scheduler_queue(dev, dev_ingress_queue(dev), &noop_qdisc); 146962306a36Sopenharmony_ci 147062306a36Sopenharmony_ci timer_setup(&dev->watchdog_timer, dev_watchdog, 0); 147162306a36Sopenharmony_ci} 147262306a36Sopenharmony_ci 147362306a36Sopenharmony_civoid dev_shutdown(struct net_device *dev) 147462306a36Sopenharmony_ci{ 147562306a36Sopenharmony_ci netdev_for_each_tx_queue(dev, shutdown_scheduler_queue, &noop_qdisc); 147662306a36Sopenharmony_ci if (dev_ingress_queue(dev)) 147762306a36Sopenharmony_ci shutdown_scheduler_queue(dev, dev_ingress_queue(dev), &noop_qdisc); 147862306a36Sopenharmony_ci qdisc_put(rtnl_dereference(dev->qdisc)); 147962306a36Sopenharmony_ci rcu_assign_pointer(dev->qdisc, &noop_qdisc); 148062306a36Sopenharmony_ci 148162306a36Sopenharmony_ci WARN_ON(timer_pending(&dev->watchdog_timer)); 148262306a36Sopenharmony_ci} 148362306a36Sopenharmony_ci 148462306a36Sopenharmony_ci/** 148562306a36Sopenharmony_ci * psched_ratecfg_precompute__() - Pre-compute values for reciprocal division 148662306a36Sopenharmony_ci * @rate: Rate to compute reciprocal division values of 148762306a36Sopenharmony_ci * @mult: Multiplier for reciprocal division 148862306a36Sopenharmony_ci * @shift: Shift for reciprocal division 148962306a36Sopenharmony_ci * 149062306a36Sopenharmony_ci * The multiplier and shift for reciprocal division by rate are stored 149162306a36Sopenharmony_ci * in mult and shift. 149262306a36Sopenharmony_ci * 149362306a36Sopenharmony_ci * The deal here is to replace a divide by a reciprocal one 149462306a36Sopenharmony_ci * in fast path (a reciprocal divide is a multiply and a shift) 149562306a36Sopenharmony_ci * 149662306a36Sopenharmony_ci * Normal formula would be : 149762306a36Sopenharmony_ci * time_in_ns = (NSEC_PER_SEC * len) / rate_bps 149862306a36Sopenharmony_ci * 149962306a36Sopenharmony_ci * We compute mult/shift to use instead : 150062306a36Sopenharmony_ci * time_in_ns = (len * mult) >> shift; 150162306a36Sopenharmony_ci * 150262306a36Sopenharmony_ci * We try to get the highest possible mult value for accuracy, 150362306a36Sopenharmony_ci * but have to make sure no overflows will ever happen. 150462306a36Sopenharmony_ci * 150562306a36Sopenharmony_ci * reciprocal_value() is not used here it doesn't handle 64-bit values. 150662306a36Sopenharmony_ci */ 150762306a36Sopenharmony_cistatic void psched_ratecfg_precompute__(u64 rate, u32 *mult, u8 *shift) 150862306a36Sopenharmony_ci{ 150962306a36Sopenharmony_ci u64 factor = NSEC_PER_SEC; 151062306a36Sopenharmony_ci 151162306a36Sopenharmony_ci *mult = 1; 151262306a36Sopenharmony_ci *shift = 0; 151362306a36Sopenharmony_ci 151462306a36Sopenharmony_ci if (rate <= 0) 151562306a36Sopenharmony_ci return; 151662306a36Sopenharmony_ci 151762306a36Sopenharmony_ci for (;;) { 151862306a36Sopenharmony_ci *mult = div64_u64(factor, rate); 151962306a36Sopenharmony_ci if (*mult & (1U << 31) || factor & (1ULL << 63)) 152062306a36Sopenharmony_ci break; 152162306a36Sopenharmony_ci factor <<= 1; 152262306a36Sopenharmony_ci (*shift)++; 152362306a36Sopenharmony_ci } 152462306a36Sopenharmony_ci} 152562306a36Sopenharmony_ci 152662306a36Sopenharmony_civoid psched_ratecfg_precompute(struct psched_ratecfg *r, 152762306a36Sopenharmony_ci const struct tc_ratespec *conf, 152862306a36Sopenharmony_ci u64 rate64) 152962306a36Sopenharmony_ci{ 153062306a36Sopenharmony_ci memset(r, 0, sizeof(*r)); 153162306a36Sopenharmony_ci r->overhead = conf->overhead; 153262306a36Sopenharmony_ci r->mpu = conf->mpu; 153362306a36Sopenharmony_ci r->rate_bytes_ps = max_t(u64, conf->rate, rate64); 153462306a36Sopenharmony_ci r->linklayer = (conf->linklayer & TC_LINKLAYER_MASK); 153562306a36Sopenharmony_ci psched_ratecfg_precompute__(r->rate_bytes_ps, &r->mult, &r->shift); 153662306a36Sopenharmony_ci} 153762306a36Sopenharmony_ciEXPORT_SYMBOL(psched_ratecfg_precompute); 153862306a36Sopenharmony_ci 153962306a36Sopenharmony_civoid psched_ppscfg_precompute(struct psched_pktrate *r, u64 pktrate64) 154062306a36Sopenharmony_ci{ 154162306a36Sopenharmony_ci r->rate_pkts_ps = pktrate64; 154262306a36Sopenharmony_ci psched_ratecfg_precompute__(r->rate_pkts_ps, &r->mult, &r->shift); 154362306a36Sopenharmony_ci} 154462306a36Sopenharmony_ciEXPORT_SYMBOL(psched_ppscfg_precompute); 154562306a36Sopenharmony_ci 154662306a36Sopenharmony_civoid mini_qdisc_pair_swap(struct mini_Qdisc_pair *miniqp, 154762306a36Sopenharmony_ci struct tcf_proto *tp_head) 154862306a36Sopenharmony_ci{ 154962306a36Sopenharmony_ci /* Protected with chain0->filter_chain_lock. 155062306a36Sopenharmony_ci * Can't access chain directly because tp_head can be NULL. 155162306a36Sopenharmony_ci */ 155262306a36Sopenharmony_ci struct mini_Qdisc *miniq_old = 155362306a36Sopenharmony_ci rcu_dereference_protected(*miniqp->p_miniq, 1); 155462306a36Sopenharmony_ci struct mini_Qdisc *miniq; 155562306a36Sopenharmony_ci 155662306a36Sopenharmony_ci if (!tp_head) { 155762306a36Sopenharmony_ci RCU_INIT_POINTER(*miniqp->p_miniq, NULL); 155862306a36Sopenharmony_ci } else { 155962306a36Sopenharmony_ci miniq = miniq_old != &miniqp->miniq1 ? 156062306a36Sopenharmony_ci &miniqp->miniq1 : &miniqp->miniq2; 156162306a36Sopenharmony_ci 156262306a36Sopenharmony_ci /* We need to make sure that readers won't see the miniq 156362306a36Sopenharmony_ci * we are about to modify. So ensure that at least one RCU 156462306a36Sopenharmony_ci * grace period has elapsed since the miniq was made 156562306a36Sopenharmony_ci * inactive. 156662306a36Sopenharmony_ci */ 156762306a36Sopenharmony_ci if (IS_ENABLED(CONFIG_PREEMPT_RT)) 156862306a36Sopenharmony_ci cond_synchronize_rcu(miniq->rcu_state); 156962306a36Sopenharmony_ci else if (!poll_state_synchronize_rcu(miniq->rcu_state)) 157062306a36Sopenharmony_ci synchronize_rcu_expedited(); 157162306a36Sopenharmony_ci 157262306a36Sopenharmony_ci miniq->filter_list = tp_head; 157362306a36Sopenharmony_ci rcu_assign_pointer(*miniqp->p_miniq, miniq); 157462306a36Sopenharmony_ci } 157562306a36Sopenharmony_ci 157662306a36Sopenharmony_ci if (miniq_old) 157762306a36Sopenharmony_ci /* This is counterpart of the rcu sync above. We need to 157862306a36Sopenharmony_ci * block potential new user of miniq_old until all readers 157962306a36Sopenharmony_ci * are not seeing it. 158062306a36Sopenharmony_ci */ 158162306a36Sopenharmony_ci miniq_old->rcu_state = start_poll_synchronize_rcu(); 158262306a36Sopenharmony_ci} 158362306a36Sopenharmony_ciEXPORT_SYMBOL(mini_qdisc_pair_swap); 158462306a36Sopenharmony_ci 158562306a36Sopenharmony_civoid mini_qdisc_pair_block_init(struct mini_Qdisc_pair *miniqp, 158662306a36Sopenharmony_ci struct tcf_block *block) 158762306a36Sopenharmony_ci{ 158862306a36Sopenharmony_ci miniqp->miniq1.block = block; 158962306a36Sopenharmony_ci miniqp->miniq2.block = block; 159062306a36Sopenharmony_ci} 159162306a36Sopenharmony_ciEXPORT_SYMBOL(mini_qdisc_pair_block_init); 159262306a36Sopenharmony_ci 159362306a36Sopenharmony_civoid mini_qdisc_pair_init(struct mini_Qdisc_pair *miniqp, struct Qdisc *qdisc, 159462306a36Sopenharmony_ci struct mini_Qdisc __rcu **p_miniq) 159562306a36Sopenharmony_ci{ 159662306a36Sopenharmony_ci miniqp->miniq1.cpu_bstats = qdisc->cpu_bstats; 159762306a36Sopenharmony_ci miniqp->miniq1.cpu_qstats = qdisc->cpu_qstats; 159862306a36Sopenharmony_ci miniqp->miniq2.cpu_bstats = qdisc->cpu_bstats; 159962306a36Sopenharmony_ci miniqp->miniq2.cpu_qstats = qdisc->cpu_qstats; 160062306a36Sopenharmony_ci miniqp->miniq1.rcu_state = get_state_synchronize_rcu(); 160162306a36Sopenharmony_ci miniqp->miniq2.rcu_state = miniqp->miniq1.rcu_state; 160262306a36Sopenharmony_ci miniqp->p_miniq = p_miniq; 160362306a36Sopenharmony_ci} 160462306a36Sopenharmony_ciEXPORT_SYMBOL(mini_qdisc_pair_init); 1605