--- zzzz-none-000/linux-5.4.213/net/sched/sch_generic.c 2022-09-15 10:04:56.000000000 +0000 +++ miami-7690-761/linux-5.4.213/net/sched/sch_generic.c 2024-05-29 11:20:02.000000000 +0000 @@ -32,7 +32,7 @@ #include /* Qdisc to use by default */ -const struct Qdisc_ops *default_qdisc_ops = &pfifo_fast_ops; +const struct Qdisc_ops *default_qdisc_ops = &fq_codel_qdisc_ops; EXPORT_SYMBOL(default_qdisc_ops); static void qdisc_maybe_clear_missed(struct Qdisc *q, @@ -305,6 +305,69 @@ * false - hardware queue frozen backoff * true - feel free to send more pkts */ +bool sch_direct_xmit_fast(struct sk_buff *first, struct Qdisc *q, struct net_device *dev, spinlock_t *root_lock) +{ + struct sk_buff *skb = first; + int rc = NETDEV_TX_OK; + bool requeue = false; + struct netdev_queue *txq; + int cpu; + + if (unlikely(!(dev->flags & IFF_UP))) { + dev_kfree_skb_any(skb); + return true; + } + + /* + * If GSO is enabled then handle segmentation through dev_queue_xmit + */ + if (unlikely(skb_is_gso(skb))) { + if (root_lock) + spin_unlock(root_lock); + dev_queue_xmit(first); + if (root_lock) + spin_lock(root_lock); + return true; + } + + cpu = smp_processor_id(); + + txq = netdev_core_pick_tx(dev, skb, NULL); + + if (likely(txq->xmit_lock_owner != cpu)) { + HARD_TX_LOCK(dev, txq, smp_processor_id()); + if (likely(!netif_xmit_stopped(txq))) { + rc = netdev_start_xmit(skb, dev, txq, 0); + if (unlikely(!dev_xmit_complete(rc))) { + HARD_TX_UNLOCK(dev, txq); + /* + * If we dont able to enqueue this to bottom interface, then we + * cannot requeue the packet back, as qdisc was enabled on different + * interface and transmit interface is different + */ + dev_kfree_skb_any(skb); + return true; + } + } else { + dev_kfree_skb_any(skb); + } + HARD_TX_UNLOCK(dev, txq); + } else { + dev_kfree_skb_any(skb); + } + + return true; +} + +/* + * Transmit possibly several skbs, and handle the return status as + * required. Owning running seqcount bit guarantees that + * only one CPU can execute this function. + * + * Returns to the caller: + * false - hardware queue frozen backoff + * true - feel free to send more pkts + */ bool sch_direct_xmit(struct sk_buff *skb, struct Qdisc *q, struct net_device *dev, struct netdev_queue *txq, spinlock_t *root_lock, bool validate) @@ -395,10 +458,39 @@ if (!(q->flags & TCQ_F_NOLOCK)) root_lock = qdisc_lock(q); - dev = qdisc_dev(q); - txq = skb_get_tx_queue(dev, skb); + while (skb) { + struct sk_buff *next = skb->next; + skb->next = NULL; + + if (likely(skb->fast_qdisc)) { + /* + * For SFE fast_qdisc marked packets, we send packets directly + * to physical interface pointed to by skb->dev + * We can clear fast_qdisc since we will not re-enqueue packet in this + * path + */ + skb->fast_qdisc = 0; + if (!sch_direct_xmit_fast(skb, q, skb->dev, root_lock)) { + return false; + } + } else { + dev = qdisc_dev(q); + txq = skb_get_tx_queue(dev, skb); + + if (!sch_direct_xmit(skb, q, dev, txq, root_lock, validate)) { + if (next) { + skb = next; + dev_requeue_skb(skb, q); + } + + return false; + } + } - return sch_direct_xmit(skb, q, dev, txq, root_lock, validate); + skb = next; + } + + return true; } void __qdisc_run(struct Qdisc *q) @@ -620,230 +712,6 @@ .owner = THIS_MODULE, }; -static const u8 prio2band[TC_PRIO_MAX + 1] = { - 1, 2, 2, 2, 1, 2, 0, 0 , 1, 1, 1, 1, 1, 1, 1, 1 -}; - -/* 3-band FIFO queue: old style, but should be a bit faster than - generic prio+fifo combination. - */ - -#define PFIFO_FAST_BANDS 3 - -/* - * Private data for a pfifo_fast scheduler containing: - * - rings for priority bands - */ -struct pfifo_fast_priv { - struct skb_array q[PFIFO_FAST_BANDS]; -}; - -static inline struct skb_array *band2list(struct pfifo_fast_priv *priv, - int band) -{ - return &priv->q[band]; -} - -static int pfifo_fast_enqueue(struct sk_buff *skb, struct Qdisc *qdisc, - struct sk_buff **to_free) -{ - int band = prio2band[skb->priority & TC_PRIO_MAX]; - struct pfifo_fast_priv *priv = qdisc_priv(qdisc); - struct skb_array *q = band2list(priv, band); - unsigned int pkt_len = qdisc_pkt_len(skb); - int err; - - err = skb_array_produce(q, skb); - - if (unlikely(err)) { - if (qdisc_is_percpu_stats(qdisc)) - return qdisc_drop_cpu(skb, qdisc, to_free); - else - return qdisc_drop(skb, qdisc, to_free); - } - - qdisc_update_stats_at_enqueue(qdisc, pkt_len); - return NET_XMIT_SUCCESS; -} - -static struct sk_buff *pfifo_fast_dequeue(struct Qdisc *qdisc) -{ - struct pfifo_fast_priv *priv = qdisc_priv(qdisc); - struct sk_buff *skb = NULL; - bool need_retry = true; - int band; - -retry: - for (band = 0; band < PFIFO_FAST_BANDS && !skb; band++) { - struct skb_array *q = band2list(priv, band); - - if (__skb_array_empty(q)) - continue; - - skb = __skb_array_consume(q); - } - if (likely(skb)) { - qdisc_update_stats_at_dequeue(qdisc, skb); - } else if (need_retry && - test_bit(__QDISC_STATE_MISSED, &qdisc->state)) { - /* Delay clearing the STATE_MISSED here to reduce - * the overhead of the second spin_trylock() in - * qdisc_run_begin() and __netif_schedule() calling - * in qdisc_run_end(). - */ - clear_bit(__QDISC_STATE_MISSED, &qdisc->state); - - /* Make sure dequeuing happens after clearing - * STATE_MISSED. - */ - smp_mb__after_atomic(); - - need_retry = false; - - goto retry; - } else { - WRITE_ONCE(qdisc->empty, true); - } - - return skb; -} - -static struct sk_buff *pfifo_fast_peek(struct Qdisc *qdisc) -{ - struct pfifo_fast_priv *priv = qdisc_priv(qdisc); - struct sk_buff *skb = NULL; - int band; - - for (band = 0; band < PFIFO_FAST_BANDS && !skb; band++) { - struct skb_array *q = band2list(priv, band); - - skb = __skb_array_peek(q); - } - - return skb; -} - -static void pfifo_fast_reset(struct Qdisc *qdisc) -{ - int i, band; - struct pfifo_fast_priv *priv = qdisc_priv(qdisc); - - for (band = 0; band < PFIFO_FAST_BANDS; band++) { - struct skb_array *q = band2list(priv, band); - struct sk_buff *skb; - - /* NULL ring is possible if destroy path is due to a failed - * skb_array_init() in pfifo_fast_init() case. - */ - if (!q->ring.queue) - continue; - - while ((skb = __skb_array_consume(q)) != NULL) - kfree_skb(skb); - } - - if (qdisc_is_percpu_stats(qdisc)) { - for_each_possible_cpu(i) { - struct gnet_stats_queue *q; - - q = per_cpu_ptr(qdisc->cpu_qstats, i); - q->backlog = 0; - q->qlen = 0; - } - } -} - -static int pfifo_fast_dump(struct Qdisc *qdisc, struct sk_buff *skb) -{ - struct tc_prio_qopt opt = { .bands = PFIFO_FAST_BANDS }; - - memcpy(&opt.priomap, prio2band, TC_PRIO_MAX + 1); - if (nla_put(skb, TCA_OPTIONS, sizeof(opt), &opt)) - goto nla_put_failure; - return skb->len; - -nla_put_failure: - return -1; -} - -static int pfifo_fast_init(struct Qdisc *qdisc, struct nlattr *opt, - struct netlink_ext_ack *extack) -{ - unsigned int qlen = qdisc_dev(qdisc)->tx_queue_len; - struct pfifo_fast_priv *priv = qdisc_priv(qdisc); - int prio; - - /* guard against zero length rings */ - if (!qlen) - return -EINVAL; - - for (prio = 0; prio < PFIFO_FAST_BANDS; prio++) { - struct skb_array *q = band2list(priv, prio); - int err; - - err = skb_array_init(q, qlen, GFP_KERNEL); - if (err) - return -ENOMEM; - } - - /* Can by-pass the queue discipline */ - qdisc->flags |= TCQ_F_CAN_BYPASS; - return 0; -} - -static void pfifo_fast_destroy(struct Qdisc *sch) -{ - struct pfifo_fast_priv *priv = qdisc_priv(sch); - int prio; - - for (prio = 0; prio < PFIFO_FAST_BANDS; prio++) { - struct skb_array *q = band2list(priv, prio); - - /* NULL ring is possible if destroy path is due to a failed - * skb_array_init() in pfifo_fast_init() case. - */ - if (!q->ring.queue) - continue; - /* Destroy ring but no need to kfree_skb because a call to - * pfifo_fast_reset() has already done that work. - */ - ptr_ring_cleanup(&q->ring, NULL); - } -} - -static int pfifo_fast_change_tx_queue_len(struct Qdisc *sch, - unsigned int new_len) -{ - struct pfifo_fast_priv *priv = qdisc_priv(sch); - struct skb_array *bands[PFIFO_FAST_BANDS]; - int prio; - - for (prio = 0; prio < PFIFO_FAST_BANDS; prio++) { - struct skb_array *q = band2list(priv, prio); - - bands[prio] = q; - } - - return skb_array_resize_multiple(bands, PFIFO_FAST_BANDS, new_len, - GFP_KERNEL); -} - -struct Qdisc_ops pfifo_fast_ops __read_mostly = { - .id = "pfifo_fast", - .priv_size = sizeof(struct pfifo_fast_priv), - .enqueue = pfifo_fast_enqueue, - .dequeue = pfifo_fast_dequeue, - .peek = pfifo_fast_peek, - .init = pfifo_fast_init, - .destroy = pfifo_fast_destroy, - .reset = pfifo_fast_reset, - .dump = pfifo_fast_dump, - .change_tx_queue_len = pfifo_fast_change_tx_queue_len, - .owner = THIS_MODULE, - .static_flags = TCQ_F_NOLOCK | TCQ_F_CPUSTATS, -}; -EXPORT_SYMBOL(pfifo_fast_ops); - struct Qdisc *qdisc_alloc(struct netdev_queue *dev_queue, const struct Qdisc_ops *ops, struct netlink_ext_ack *extack) @@ -1079,12 +947,12 @@ void *_unused) { struct Qdisc *qdisc; - const struct Qdisc_ops *ops = default_qdisc_ops; + const struct Qdisc_ops *ops = &fq_codel_qdisc_ops; if (dev->priv_flags & IFF_NO_QUEUE) ops = &noqueue_qdisc_ops; else if(dev->type == ARPHRD_CAN) - ops = &pfifo_fast_ops; + ops = &fq_codel_qdisc_ops; qdisc = qdisc_create_dflt(dev_queue, ops, TC_H_ROOT, NULL); if (!qdisc) { @@ -1389,6 +1257,7 @@ WARN_ON(timer_pending(&dev->watchdog_timer)); } +EXPORT_SYMBOL(dev_shutdown); void psched_ratecfg_precompute(struct psched_ratecfg *r, const struct tc_ratespec *conf,