Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

Merge branch 'ENETC-mqprio-taprio-cleanup'

Vladimir Oltean says:

====================
net: ENETC mqprio/taprio cleanup

Please excuse the increased patch set size compared to v4's 15 patches,
but Claudiu stirred up the pot :) when he pointed out that the mqprio
TXQ validation procedure is still incorrect, so I had to fix that, and
then do some consolidation work so that taprio doesn't duplicate
mqprio's bugs. Compared to v4, 3 patches are new and 1 was dropped for now
("net/sched: taprio: mask off bits in gate mask that exceed number of TCs"),
since there's not really much to gain from it. Since the previous patch
set has largely been reviewed, I hope that a delta overview will help
and make up for the large size.

v4->v5:
- new patches:
"[08/17] net/sched: mqprio: allow reverse TC:TXQ mappings"
"[11/17] net/sched: taprio: centralize mqprio qopt validation"
"[12/17] net/sched: refactor mqprio qopt reconstruction to a library function"
- changed patches worth revisiting:
"[09/17] net/sched: mqprio: allow offloading drivers to request queue
count validation"
v4 at:
https://patchwork.kernel.org/project/netdevbpf/cover/20230130173145.475943-1-vladimir.oltean@nxp.com/

v3->v4:
- adjusted patch 07/15 to not remove "#include <net/pkt_sched.h>" from
ti cpsw
https://patchwork.kernel.org/project/netdevbpf/cover/20230127001516.592984-1-vladimir.oltean@nxp.com/

v2->v3:
- move min_num_stack_tx_queues definition so it doesn't conflict with
the ethtool mm patches I haven't submitted yet for enetc (and also to
make use of a 4 byte hole)
- warn and mask off excess TCs in gate mask instead of failing
- finally CC qdisc maintainers
v2 at:
https://patchwork.kernel.org/project/netdevbpf/patch/20230126125308.1199404-16-vladimir.oltean@nxp.com/

v1->v2:
- patches 1->4 are new
- update some header inclusions in drivers
- fix typo (said "taprio" instead of "mqprio")
- better enetc mqprio error handling
- dynamically reconstruct mqprio configuration in taprio offload
- also let stmmac and tsnep use per-TXQ gate_mask
v1 (RFC) at:
https://patchwork.kernel.org/project/netdevbpf/cover/20230120141537.1350744-1-vladimir.oltean@nxp.com/

The main goal of this patch set is to make taprio pass the mqprio queue
configuration structure down to ndo_setup_tc() - patch 13/17. But mqprio
itself is not in the best shape currently, so there are some
consolidation patches on that as well.

Next, there are some consolidation patches in the enetc driver's
handling of TX queues and their traffic class assignment. Then, there is
a consolidation between the TX queue configuration for mqprio and
taprio.

Finally, there is a change in the meaning of the gate_mask passed by
taprio through ndo_setup_tc(). We introduce a capability through which
drivers can request the gate mask to be per TXQ. The default is changed
so that it is per TC.
====================

Signed-off-by: David S. Miller <davem@davemloft.net>

+518 -256
+1
drivers/net/ethernet/aquantia/atlantic/aq_main.c
··· 21 21 #include <linux/ip.h> 22 22 #include <linux/udp.h> 23 23 #include <net/pkt_cls.h> 24 + #include <net/pkt_sched.h> 24 25 #include <linux/filter.h> 25 26 26 27 MODULE_LICENSE("GPL v2");
+1 -1
drivers/net/ethernet/chelsio/cxgb4/cxgb4_tc_mqprio.h
··· 4 4 #ifndef __CXGB4_TC_MQPRIO_H__ 5 5 #define __CXGB4_TC_MQPRIO_H__ 6 6 7 - #include <net/pkt_cls.h> 7 + #include <net/pkt_sched.h> 8 8 9 9 #define CXGB4_EOSW_TXQ_DEFAULT_DESC_NUM 128 10 10
+21
drivers/net/ethernet/engleder/tsnep_tc.c
··· 403 403 return 0; 404 404 } 405 405 406 + static int tsnep_tc_query_caps(struct tsnep_adapter *adapter, 407 + struct tc_query_caps_base *base) 408 + { 409 + switch (base->type) { 410 + case TC_SETUP_QDISC_TAPRIO: { 411 + struct tc_taprio_caps *caps = base->caps; 412 + 413 + if (!adapter->gate_control) 414 + return -EOPNOTSUPP; 415 + 416 + caps->gate_mask_per_txq = true; 417 + 418 + return 0; 419 + } 420 + default: 421 + return -EOPNOTSUPP; 422 + } 423 + } 424 + 406 425 int tsnep_tc_setup(struct net_device *netdev, enum tc_setup_type type, 407 426 void *type_data) 408 427 { 409 428 struct tsnep_adapter *adapter = netdev_priv(netdev); 410 429 411 430 switch (type) { 431 + case TC_QUERY_CAPS: 432 + return tsnep_tc_query_caps(adapter, type_data); 412 433 case TC_SETUP_QDISC_TAPRIO: 413 434 return tsnep_taprio(adapter, type_data); 414 435 default:
+72 -40
drivers/net/ethernet/freescale/enetc/enetc.c
··· 2609 2609 return err; 2610 2610 } 2611 2611 2612 + static void enetc_debug_tx_ring_prios(struct enetc_ndev_priv *priv) 2613 + { 2614 + int i; 2615 + 2616 + for (i = 0; i < priv->num_tx_rings; i++) 2617 + netdev_dbg(priv->ndev, "TX ring %d prio %d\n", i, 2618 + priv->tx_ring[i]->prio); 2619 + } 2620 + 2621 + static void enetc_reset_tc_mqprio(struct net_device *ndev) 2622 + { 2623 + struct enetc_ndev_priv *priv = netdev_priv(ndev); 2624 + struct enetc_hw *hw = &priv->si->hw; 2625 + struct enetc_bdr *tx_ring; 2626 + int num_stack_tx_queues; 2627 + int i; 2628 + 2629 + num_stack_tx_queues = enetc_num_stack_tx_queues(priv); 2630 + 2631 + netdev_reset_tc(ndev); 2632 + netif_set_real_num_tx_queues(ndev, num_stack_tx_queues); 2633 + priv->min_num_stack_tx_queues = num_possible_cpus(); 2634 + 2635 + /* Reset all ring priorities to 0 */ 2636 + for (i = 0; i < priv->num_tx_rings; i++) { 2637 + tx_ring = priv->tx_ring[i]; 2638 + tx_ring->prio = 0; 2639 + enetc_set_bdr_prio(hw, tx_ring->index, tx_ring->prio); 2640 + } 2641 + 2642 + enetc_debug_tx_ring_prios(priv); 2643 + } 2644 + 2612 2645 int enetc_setup_tc_mqprio(struct net_device *ndev, void *type_data) 2613 2646 { 2614 2647 struct enetc_ndev_priv *priv = netdev_priv(ndev); 2615 2648 struct tc_mqprio_qopt *mqprio = type_data; 2616 2649 struct enetc_hw *hw = &priv->si->hw; 2650 + int num_stack_tx_queues = 0; 2651 + u8 num_tc = mqprio->num_tc; 2617 2652 struct enetc_bdr *tx_ring; 2618 - int num_stack_tx_queues; 2619 - u8 num_tc; 2620 - int i; 2621 - 2622 - num_stack_tx_queues = enetc_num_stack_tx_queues(priv); 2623 - mqprio->hw = TC_MQPRIO_HW_OFFLOAD_TCS; 2624 - num_tc = mqprio->num_tc; 2653 + int offset, count; 2654 + int err, tc, q; 2625 2655 2626 2656 if (!num_tc) { 2627 - netdev_reset_tc(ndev); 2628 - netif_set_real_num_tx_queues(ndev, num_stack_tx_queues); 2629 - priv->min_num_stack_tx_queues = num_possible_cpus(); 2630 - 2631 - /* Reset all ring priorities to 0 */ 2632 - for (i = 0; i < priv->num_tx_rings; i++) { 2633 - tx_ring = priv->tx_ring[i]; 2634 - tx_ring->prio = 0; 2635 - enetc_set_bdr_prio(hw, tx_ring->index, tx_ring->prio); 2636 - } 2637 - 2657 + enetc_reset_tc_mqprio(ndev); 2638 2658 return 0; 2639 2659 } 2640 2660 2641 - /* Check if we have enough BD rings available to accommodate all TCs */ 2642 - if (num_tc > num_stack_tx_queues) { 2643 - netdev_err(ndev, "Max %d traffic classes supported\n", 2644 - priv->num_tx_rings); 2645 - return -EINVAL; 2661 + err = netdev_set_num_tc(ndev, num_tc); 2662 + if (err) 2663 + return err; 2664 + 2665 + for (tc = 0; tc < num_tc; tc++) { 2666 + offset = mqprio->offset[tc]; 2667 + count = mqprio->count[tc]; 2668 + num_stack_tx_queues += count; 2669 + 2670 + err = netdev_set_tc_queue(ndev, tc, count, offset); 2671 + if (err) 2672 + goto err_reset_tc; 2673 + 2674 + for (q = offset; q < offset + count; q++) { 2675 + tx_ring = priv->tx_ring[q]; 2676 + /* The prio_tc_map is skb_tx_hash()'s way of selecting 2677 + * between TX queues based on skb->priority. As such, 2678 + * there's nothing to offload based on it. 2679 + * Make the mqprio "traffic class" be the priority of 2680 + * this ring group, and leave the Tx IPV to traffic 2681 + * class mapping as its default mapping value of 1:1. 2682 + */ 2683 + tx_ring->prio = tc; 2684 + enetc_set_bdr_prio(hw, tx_ring->index, tx_ring->prio); 2685 + } 2646 2686 } 2647 2687 2648 - /* For the moment, we use only one BD ring per TC. 2649 - * 2650 - * Configure num_tc BD rings with increasing priorities. 2651 - */ 2652 - for (i = 0; i < num_tc; i++) { 2653 - tx_ring = priv->tx_ring[i]; 2654 - tx_ring->prio = i; 2655 - enetc_set_bdr_prio(hw, tx_ring->index, tx_ring->prio); 2656 - } 2688 + err = netif_set_real_num_tx_queues(ndev, num_stack_tx_queues); 2689 + if (err) 2690 + goto err_reset_tc; 2657 2691 2658 - /* Reset the number of netdev queues based on the TC count */ 2659 - netif_set_real_num_tx_queues(ndev, num_tc); 2660 - priv->min_num_stack_tx_queues = num_tc; 2692 + priv->min_num_stack_tx_queues = num_stack_tx_queues; 2661 2693 2662 - netdev_set_num_tc(ndev, num_tc); 2663 - 2664 - /* Each TC is associated with one netdev queue */ 2665 - for (i = 0; i < num_tc; i++) 2666 - netdev_set_tc_queue(ndev, i, 1, i); 2694 + enetc_debug_tx_ring_prios(priv); 2667 2695 2668 2696 return 0; 2697 + 2698 + err_reset_tc: 2699 + enetc_reset_tc_mqprio(ndev); 2700 + return err; 2669 2701 } 2670 2702 EXPORT_SYMBOL_GPL(enetc_setup_tc_mqprio); 2671 2703
+13 -14
drivers/net/ethernet/freescale/enetc/enetc_qos.c
··· 136 136 { 137 137 struct tc_taprio_qopt_offload *taprio = type_data; 138 138 struct enetc_ndev_priv *priv = netdev_priv(ndev); 139 - struct enetc_hw *hw = &priv->si->hw; 140 - struct enetc_bdr *tx_ring; 141 - int err; 142 - int i; 139 + int err, i; 143 140 144 141 /* TSD and Qbv are mutually exclusive in hardware */ 145 142 for (i = 0; i < priv->num_tx_rings; i++) 146 143 if (priv->tx_ring[i]->tsd_enable) 147 144 return -EBUSY; 148 145 149 - for (i = 0; i < priv->num_tx_rings; i++) { 150 - tx_ring = priv->tx_ring[i]; 151 - tx_ring->prio = taprio->enable ? i : 0; 152 - enetc_set_bdr_prio(hw, tx_ring->index, tx_ring->prio); 153 - } 146 + err = enetc_setup_tc_mqprio(ndev, &taprio->mqprio); 147 + if (err) 148 + return err; 154 149 155 150 err = enetc_setup_taprio(ndev, taprio); 156 151 if (err) { 157 - for (i = 0; i < priv->num_tx_rings; i++) { 158 - tx_ring = priv->tx_ring[i]; 159 - tx_ring->prio = taprio->enable ? 0 : i; 160 - enetc_set_bdr_prio(hw, tx_ring->index, tx_ring->prio); 161 - } 152 + taprio->mqprio.qopt.num_tc = 0; 153 + enetc_setup_tc_mqprio(ndev, &taprio->mqprio); 162 154 } 163 155 164 156 return err; ··· 1603 1611 struct enetc_si *si = priv->si; 1604 1612 1605 1613 switch (base->type) { 1614 + case TC_SETUP_QDISC_MQPRIO: { 1615 + struct tc_mqprio_caps *caps = base->caps; 1616 + 1617 + caps->validate_queue_counts = true; 1618 + 1619 + return 0; 1620 + } 1606 1621 case TC_SETUP_QDISC_TAPRIO: { 1607 1622 struct tc_taprio_caps *caps = base->caps; 1608 1623
+1
drivers/net/ethernet/hisilicon/hns3/hnae3.h
··· 32 32 #include <linux/pkt_sched.h> 33 33 #include <linux/types.h> 34 34 #include <net/pkt_cls.h> 35 + #include <net/pkt_sched.h> 35 36 36 37 #define HNAE3_MOD_VERSION "1.0" 37 38
+1
drivers/net/ethernet/hisilicon/hns3/hns3_enet.c
··· 20 20 #include <net/gro.h> 21 21 #include <net/ip6_checksum.h> 22 22 #include <net/pkt_cls.h> 23 + #include <net/pkt_sched.h> 23 24 #include <net/tcp.h> 24 25 #include <net/vxlan.h> 25 26 #include <net/geneve.h>
+1
drivers/net/ethernet/intel/i40e/i40e.h
··· 33 33 #include <linux/net_tstamp.h> 34 34 #include <linux/ptp_clock_kernel.h> 35 35 #include <net/pkt_cls.h> 36 + #include <net/pkt_sched.h> 36 37 #include <net/tc_act/tc_gact.h> 37 38 #include <net/tc_act/tc_mirred.h> 38 39 #include <net/udp_tunnel.h>
+1
drivers/net/ethernet/intel/iavf/iavf.h
··· 30 30 #include <linux/jiffies.h> 31 31 #include <net/ip6_checksum.h> 32 32 #include <net/pkt_cls.h> 33 + #include <net/pkt_sched.h> 33 34 #include <net/udp.h> 34 35 #include <net/tc_act/tc_gact.h> 35 36 #include <net/tc_act/tc_mirred.h>
+1
drivers/net/ethernet/intel/ice/ice.h
··· 41 41 #include <linux/dim.h> 42 42 #include <linux/gnss.h> 43 43 #include <net/pkt_cls.h> 44 + #include <net/pkt_sched.h> 44 45 #include <net/tc_act/tc_mirred.h> 45 46 #include <net/tc_act/tc_gact.h> 46 47 #include <net/ip.h>
+23
drivers/net/ethernet/intel/igc/igc_main.c
··· 6205 6205 return igc_tsn_offload_apply(adapter); 6206 6206 } 6207 6207 6208 + static int igc_tc_query_caps(struct igc_adapter *adapter, 6209 + struct tc_query_caps_base *base) 6210 + { 6211 + struct igc_hw *hw = &adapter->hw; 6212 + 6213 + switch (base->type) { 6214 + case TC_SETUP_QDISC_TAPRIO: { 6215 + struct tc_taprio_caps *caps = base->caps; 6216 + 6217 + if (hw->mac.type != igc_i225) 6218 + return -EOPNOTSUPP; 6219 + 6220 + caps->gate_mask_per_txq = true; 6221 + 6222 + return 0; 6223 + } 6224 + default: 6225 + return -EOPNOTSUPP; 6226 + } 6227 + } 6228 + 6208 6229 static int igc_setup_tc(struct net_device *dev, enum tc_setup_type type, 6209 6230 void *type_data) 6210 6231 { 6211 6232 struct igc_adapter *adapter = netdev_priv(dev); 6212 6233 6213 6234 switch (type) { 6235 + case TC_QUERY_CAPS: 6236 + return igc_tc_query_caps(adapter, type_data); 6214 6237 case TC_SETUP_QDISC_TAPRIO: 6215 6238 return igc_tsn_enable_qbv_scheduling(adapter, type_data); 6216 6239
+1 -1
drivers/net/ethernet/marvell/mvneta.c
··· 38 38 #include <net/ipv6.h> 39 39 #include <net/tso.h> 40 40 #include <net/page_pool.h> 41 - #include <net/pkt_cls.h> 41 + #include <net/pkt_sched.h> 42 42 #include <linux/bpf_trace.h> 43 43 44 44 /* Registers */
+1
drivers/net/ethernet/mellanox/mlx5/core/en_main.c
··· 39 39 #include <linux/if_bridge.h> 40 40 #include <linux/filter.h> 41 41 #include <net/page_pool.h> 42 + #include <net/pkt_sched.h> 42 43 #include <net/xdp_sock_drv.h> 43 44 #include "eswitch.h" 44 45 #include "en.h"
+1
drivers/net/ethernet/microchip/lan966x/lan966x_tc.c
··· 1 1 // SPDX-License-Identifier: GPL-2.0+ 2 2 3 3 #include <net/pkt_cls.h> 4 + #include <net/pkt_sched.h> 4 5 5 6 #include "lan966x_main.h" 6 7
+1
drivers/net/ethernet/microchip/sparx5/sparx5_tc.c
··· 5 5 */ 6 6 7 7 #include <net/pkt_cls.h> 8 + #include <net/pkt_sched.h> 8 9 9 10 #include "sparx5_tc.h" 10 11 #include "sparx5_main.h"
+5
drivers/net/ethernet/stmicro/stmmac/hwif.h
··· 567 567 struct flow_cls_offload; 568 568 struct tc_taprio_qopt_offload; 569 569 struct tc_etf_qopt_offload; 570 + struct tc_query_caps_base; 570 571 571 572 struct stmmac_tc_ops { 572 573 int (*init)(struct stmmac_priv *priv); ··· 581 580 struct tc_taprio_qopt_offload *qopt); 582 581 int (*setup_etf)(struct stmmac_priv *priv, 583 582 struct tc_etf_qopt_offload *qopt); 583 + int (*query_caps)(struct stmmac_priv *priv, 584 + struct tc_query_caps_base *base); 584 585 }; 585 586 586 587 #define stmmac_tc_init(__priv, __args...) \ ··· 597 594 stmmac_do_callback(__priv, tc, setup_taprio, __args) 598 595 #define stmmac_tc_setup_etf(__priv, __args...) \ 599 596 stmmac_do_callback(__priv, tc, setup_etf, __args) 597 + #define stmmac_tc_query_caps(__priv, __args...) \ 598 + stmmac_do_callback(__priv, tc, query_caps, __args) 600 599 601 600 struct stmmac_counters; 602 601
+2
drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
··· 5992 5992 struct stmmac_priv *priv = netdev_priv(ndev); 5993 5993 5994 5994 switch (type) { 5995 + case TC_QUERY_CAPS: 5996 + return stmmac_tc_query_caps(priv, priv, type_data); 5995 5997 case TC_SETUP_BLOCK: 5996 5998 return flow_block_cb_setup_simple(type_data, 5997 5999 &stmmac_block_cb_list,
+20
drivers/net/ethernet/stmicro/stmmac/stmmac_tc.c
··· 1107 1107 return 0; 1108 1108 } 1109 1109 1110 + static int tc_query_caps(struct stmmac_priv *priv, 1111 + struct tc_query_caps_base *base) 1112 + { 1113 + switch (base->type) { 1114 + case TC_SETUP_QDISC_TAPRIO: { 1115 + struct tc_taprio_caps *caps = base->caps; 1116 + 1117 + if (!priv->dma_cap.estsel) 1118 + return -EOPNOTSUPP; 1119 + 1120 + caps->gate_mask_per_txq = true; 1121 + 1122 + return 0; 1123 + } 1124 + default: 1125 + return -EOPNOTSUPP; 1126 + } 1127 + } 1128 + 1110 1129 const struct stmmac_tc_ops dwmac510_tc_ops = { 1111 1130 .init = tc_init, 1112 1131 .setup_cls_u32 = tc_setup_cls_u32, ··· 1133 1114 .setup_cls = tc_setup_cls, 1134 1115 .setup_taprio = tc_setup_taprio, 1135 1116 .setup_etf = tc_setup_etf, 1117 + .query_caps = tc_query_caps, 1136 1118 };
+22
drivers/net/ethernet/ti/am65-cpsw-qos.c
··· 585 585 return am65_cpsw_set_taprio(ndev, type_data); 586 586 } 587 587 588 + static int am65_cpsw_tc_query_caps(struct net_device *ndev, void *type_data) 589 + { 590 + struct tc_query_caps_base *base = type_data; 591 + 592 + switch (base->type) { 593 + case TC_SETUP_QDISC_TAPRIO: { 594 + struct tc_taprio_caps *caps = base->caps; 595 + 596 + if (!IS_ENABLED(CONFIG_TI_AM65_CPSW_TAS)) 597 + return -EOPNOTSUPP; 598 + 599 + caps->gate_mask_per_txq = true; 600 + 601 + return 0; 602 + } 603 + default: 604 + return -EOPNOTSUPP; 605 + } 606 + } 607 + 588 608 static int am65_cpsw_qos_clsflower_add_policer(struct am65_cpsw_port *port, 589 609 struct netlink_ext_ack *extack, 590 610 struct flow_cls_offload *cls, ··· 785 765 void *type_data) 786 766 { 787 767 switch (type) { 768 + case TC_QUERY_CAPS: 769 + return am65_cpsw_tc_query_caps(ndev, type_data); 788 770 case TC_SETUP_QDISC_TAPRIO: 789 771 return am65_cpsw_setup_taprio(ndev, type_data); 790 772 case TC_SETUP_BLOCK:
+1
drivers/net/ethernet/ti/cpsw_priv.c
··· 20 20 #include <linux/skbuff.h> 21 21 #include <net/page_pool.h> 22 22 #include <net/pkt_cls.h> 23 + #include <net/pkt_sched.h> 23 24 24 25 #include "cpsw.h" 25 26 #include "cpts.h"
-10
include/net/pkt_cls.h
··· 788 788 bool exts_integrated; 789 789 }; 790 790 791 - struct tc_mqprio_qopt_offload { 792 - /* struct tc_mqprio_qopt must always be the first element */ 793 - struct tc_mqprio_qopt qopt; 794 - u16 mode; 795 - u16 shaper; 796 - u32 flags; 797 - u64 min_rate[TC_QOPT_MAX_QUEUE]; 798 - u64 max_rate[TC_QOPT_MAX_QUEUE]; 799 - }; 800 - 801 791 /* This structure holds cookie structure that is passed from user 802 792 * to the kernel for actions and classifiers 803 793 */
+16
include/net/pkt_sched.h
··· 160 160 s32 queue; 161 161 }; 162 162 163 + struct tc_mqprio_caps { 164 + bool validate_queue_counts:1; 165 + }; 166 + 167 + struct tc_mqprio_qopt_offload { 168 + /* struct tc_mqprio_qopt must always be the first element */ 169 + struct tc_mqprio_qopt qopt; 170 + u16 mode; 171 + u16 shaper; 172 + u32 flags; 173 + u64 min_rate[TC_QOPT_MAX_QUEUE]; 174 + u64 max_rate[TC_QOPT_MAX_QUEUE]; 175 + }; 176 + 163 177 struct tc_taprio_caps { 164 178 bool supports_queue_max_sdu:1; 179 + bool gate_mask_per_txq:1; 165 180 }; 166 181 167 182 struct tc_taprio_sched_entry { ··· 188 173 }; 189 174 190 175 struct tc_taprio_qopt_offload { 176 + struct tc_mqprio_qopt_offload mqprio; 191 177 u8 enable; 192 178 ktime_t base_time; 193 179 u64 cycle_time;
+7
net/sched/Kconfig
··· 195 195 To compile this code as a module, choose M here: the 196 196 module will be called sch_etf. 197 197 198 + config NET_SCH_MQPRIO_LIB 199 + tristate 200 + help 201 + Common library for manipulating mqprio queue configurations. 202 + 198 203 config NET_SCH_TAPRIO 199 204 tristate "Time Aware Priority (taprio) Scheduler" 205 + select NET_SCH_MQPRIO_LIB 200 206 help 201 207 Say Y here if you want to use the Time Aware Priority (taprio) packet 202 208 scheduling algorithm. ··· 259 253 260 254 config NET_SCH_MQPRIO 261 255 tristate "Multi-queue priority scheduler (MQPRIO)" 256 + select NET_SCH_MQPRIO_LIB 262 257 help 263 258 Say Y here if you want to use the Multi-queue Priority scheduler. 264 259 This scheduler allows QOS to be offloaded on NICs that have support
+1
net/sched/Makefile
··· 52 52 obj-$(CONFIG_NET_SCH_PLUG) += sch_plug.o 53 53 obj-$(CONFIG_NET_SCH_ETS) += sch_ets.o 54 54 obj-$(CONFIG_NET_SCH_MQPRIO) += sch_mqprio.o 55 + obj-$(CONFIG_NET_SCH_MQPRIO_LIB) += sch_mqprio_lib.o 55 56 obj-$(CONFIG_NET_SCH_SKBPRIO) += sch_skbprio.o 56 57 obj-$(CONFIG_NET_SCH_CHOKE) += sch_choke.o 57 58 obj-$(CONFIG_NET_SCH_QFQ) += sch_qfq.o
+151 -138
net/sched/sch_mqprio.c
··· 17 17 #include <net/sch_generic.h> 18 18 #include <net/pkt_cls.h> 19 19 20 + #include "sch_mqprio_lib.h" 21 + 20 22 struct mqprio_sched { 21 23 struct Qdisc **qdiscs; 22 24 u16 mode; ··· 28 26 u64 min_rate[TC_QOPT_MAX_QUEUE]; 29 27 u64 max_rate[TC_QOPT_MAX_QUEUE]; 30 28 }; 29 + 30 + static int mqprio_enable_offload(struct Qdisc *sch, 31 + const struct tc_mqprio_qopt *qopt, 32 + struct netlink_ext_ack *extack) 33 + { 34 + struct tc_mqprio_qopt_offload mqprio = {.qopt = *qopt}; 35 + struct mqprio_sched *priv = qdisc_priv(sch); 36 + struct net_device *dev = qdisc_dev(sch); 37 + int err, i; 38 + 39 + switch (priv->mode) { 40 + case TC_MQPRIO_MODE_DCB: 41 + if (priv->shaper != TC_MQPRIO_SHAPER_DCB) 42 + return -EINVAL; 43 + break; 44 + case TC_MQPRIO_MODE_CHANNEL: 45 + mqprio.flags = priv->flags; 46 + if (priv->flags & TC_MQPRIO_F_MODE) 47 + mqprio.mode = priv->mode; 48 + if (priv->flags & TC_MQPRIO_F_SHAPER) 49 + mqprio.shaper = priv->shaper; 50 + if (priv->flags & TC_MQPRIO_F_MIN_RATE) 51 + for (i = 0; i < mqprio.qopt.num_tc; i++) 52 + mqprio.min_rate[i] = priv->min_rate[i]; 53 + if (priv->flags & TC_MQPRIO_F_MAX_RATE) 54 + for (i = 0; i < mqprio.qopt.num_tc; i++) 55 + mqprio.max_rate[i] = priv->max_rate[i]; 56 + break; 57 + default: 58 + return -EINVAL; 59 + } 60 + 61 + err = dev->netdev_ops->ndo_setup_tc(dev, TC_SETUP_QDISC_MQPRIO, 62 + &mqprio); 63 + if (err) 64 + return err; 65 + 66 + priv->hw_offload = mqprio.qopt.hw; 67 + 68 + return 0; 69 + } 70 + 71 + static void mqprio_disable_offload(struct Qdisc *sch) 72 + { 73 + struct tc_mqprio_qopt_offload mqprio = { { 0 } }; 74 + struct mqprio_sched *priv = qdisc_priv(sch); 75 + struct net_device *dev = qdisc_dev(sch); 76 + 77 + switch (priv->mode) { 78 + case TC_MQPRIO_MODE_DCB: 79 + case TC_MQPRIO_MODE_CHANNEL: 80 + dev->netdev_ops->ndo_setup_tc(dev, TC_SETUP_QDISC_MQPRIO, 81 + &mqprio); 82 + break; 83 + } 84 + } 31 85 32 86 static void mqprio_destroy(struct Qdisc *sch) 33 87 { ··· 99 41 kfree(priv->qdiscs); 100 42 } 101 43 102 - if (priv->hw_offload && dev->netdev_ops->ndo_setup_tc) { 103 - struct tc_mqprio_qopt_offload mqprio = { { 0 } }; 104 - 105 - switch (priv->mode) { 106 - case TC_MQPRIO_MODE_DCB: 107 - case TC_MQPRIO_MODE_CHANNEL: 108 - dev->netdev_ops->ndo_setup_tc(dev, 109 - TC_SETUP_QDISC_MQPRIO, 110 - &mqprio); 111 - break; 112 - default: 113 - return; 114 - } 115 - } else { 44 + if (priv->hw_offload && dev->netdev_ops->ndo_setup_tc) 45 + mqprio_disable_offload(sch); 46 + else 116 47 netdev_set_num_tc(dev, 0); 117 - } 118 48 } 119 49 120 - static int mqprio_parse_opt(struct net_device *dev, struct tc_mqprio_qopt *qopt) 50 + static int mqprio_parse_opt(struct net_device *dev, struct tc_mqprio_qopt *qopt, 51 + const struct tc_mqprio_caps *caps, 52 + struct netlink_ext_ack *extack) 121 53 { 122 - int i, j; 123 - 124 - /* Verify num_tc is not out of max range */ 125 - if (qopt->num_tc > TC_MAX_QUEUE) 126 - return -EINVAL; 127 - 128 - /* Verify priority mapping uses valid tcs */ 129 - for (i = 0; i < TC_BITMASK + 1; i++) { 130 - if (qopt->prio_tc_map[i] >= qopt->num_tc) 131 - return -EINVAL; 132 - } 54 + int err; 133 55 134 56 /* Limit qopt->hw to maximum supported offload value. Drivers have 135 57 * the option of overriding this later if they don't support the a ··· 118 80 if (qopt->hw > TC_MQPRIO_HW_OFFLOAD_MAX) 119 81 qopt->hw = TC_MQPRIO_HW_OFFLOAD_MAX; 120 82 121 - /* If hardware offload is requested we will leave it to the device 122 - * to either populate the queue counts itself or to validate the 123 - * provided queue counts. If ndo_setup_tc is not present then 124 - * hardware doesn't support offload and we should return an error. 83 + /* If hardware offload is requested, we will leave 3 options to the 84 + * device driver: 85 + * - populate the queue counts itself (and ignore what was requested) 86 + * - validate the provided queue counts by itself (and apply them) 87 + * - request queue count validation here (and apply them) 125 88 */ 126 - if (qopt->hw) 127 - return dev->netdev_ops->ndo_setup_tc ? 0 : -EINVAL; 89 + err = mqprio_validate_qopt(dev, qopt, 90 + !qopt->hw || caps->validate_queue_counts, 91 + false, extack); 92 + if (err) 93 + return err; 128 94 129 - for (i = 0; i < qopt->num_tc; i++) { 130 - unsigned int last = qopt->offset[i] + qopt->count[i]; 131 - 132 - /* Verify the queue count is in tx range being equal to the 133 - * real_num_tx_queues indicates the last queue is in use. 134 - */ 135 - if (qopt->offset[i] >= dev->real_num_tx_queues || 136 - !qopt->count[i] || 137 - last > dev->real_num_tx_queues) 138 - return -EINVAL; 139 - 140 - /* Verify that the offset and counts do not overlap */ 141 - for (j = i + 1; j < qopt->num_tc; j++) { 142 - if (last > qopt->offset[j]) 143 - return -EINVAL; 144 - } 145 - } 95 + /* If ndo_setup_tc is not present then hardware doesn't support offload 96 + * and we should return an error. 97 + */ 98 + if (qopt->hw && !dev->netdev_ops->ndo_setup_tc) 99 + return -EINVAL; 146 100 147 101 return 0; 148 102 } ··· 160 130 return 0; 161 131 } 162 132 133 + static int mqprio_parse_nlattr(struct Qdisc *sch, struct tc_mqprio_qopt *qopt, 134 + struct nlattr *opt) 135 + { 136 + struct mqprio_sched *priv = qdisc_priv(sch); 137 + struct nlattr *tb[TCA_MQPRIO_MAX + 1]; 138 + struct nlattr *attr; 139 + int i, rem, err; 140 + 141 + err = parse_attr(tb, TCA_MQPRIO_MAX, opt, mqprio_policy, 142 + sizeof(*qopt)); 143 + if (err < 0) 144 + return err; 145 + 146 + if (!qopt->hw) 147 + return -EINVAL; 148 + 149 + if (tb[TCA_MQPRIO_MODE]) { 150 + priv->flags |= TC_MQPRIO_F_MODE; 151 + priv->mode = *(u16 *)nla_data(tb[TCA_MQPRIO_MODE]); 152 + } 153 + 154 + if (tb[TCA_MQPRIO_SHAPER]) { 155 + priv->flags |= TC_MQPRIO_F_SHAPER; 156 + priv->shaper = *(u16 *)nla_data(tb[TCA_MQPRIO_SHAPER]); 157 + } 158 + 159 + if (tb[TCA_MQPRIO_MIN_RATE64]) { 160 + if (priv->shaper != TC_MQPRIO_SHAPER_BW_RATE) 161 + return -EINVAL; 162 + i = 0; 163 + nla_for_each_nested(attr, tb[TCA_MQPRIO_MIN_RATE64], 164 + rem) { 165 + if (nla_type(attr) != TCA_MQPRIO_MIN_RATE64) 166 + return -EINVAL; 167 + if (i >= qopt->num_tc) 168 + break; 169 + priv->min_rate[i] = *(u64 *)nla_data(attr); 170 + i++; 171 + } 172 + priv->flags |= TC_MQPRIO_F_MIN_RATE; 173 + } 174 + 175 + if (tb[TCA_MQPRIO_MAX_RATE64]) { 176 + if (priv->shaper != TC_MQPRIO_SHAPER_BW_RATE) 177 + return -EINVAL; 178 + i = 0; 179 + nla_for_each_nested(attr, tb[TCA_MQPRIO_MAX_RATE64], 180 + rem) { 181 + if (nla_type(attr) != TCA_MQPRIO_MAX_RATE64) 182 + return -EINVAL; 183 + if (i >= qopt->num_tc) 184 + break; 185 + priv->max_rate[i] = *(u64 *)nla_data(attr); 186 + i++; 187 + } 188 + priv->flags |= TC_MQPRIO_F_MAX_RATE; 189 + } 190 + 191 + return 0; 192 + } 193 + 163 194 static int mqprio_init(struct Qdisc *sch, struct nlattr *opt, 164 195 struct netlink_ext_ack *extack) 165 196 { ··· 230 139 struct Qdisc *qdisc; 231 140 int i, err = -EOPNOTSUPP; 232 141 struct tc_mqprio_qopt *qopt = NULL; 233 - struct nlattr *tb[TCA_MQPRIO_MAX + 1]; 234 - struct nlattr *attr; 235 - int rem; 142 + struct tc_mqprio_caps caps; 236 143 int len; 237 144 238 145 BUILD_BUG_ON(TC_MAX_QUEUE != TC_QOPT_MAX_QUEUE); ··· 249 160 if (!opt || nla_len(opt) < sizeof(*qopt)) 250 161 return -EINVAL; 251 162 163 + qdisc_offload_query_caps(dev, TC_SETUP_QDISC_MQPRIO, 164 + &caps, sizeof(caps)); 165 + 252 166 qopt = nla_data(opt); 253 - if (mqprio_parse_opt(dev, qopt)) 167 + if (mqprio_parse_opt(dev, qopt, &caps, extack)) 254 168 return -EINVAL; 255 169 256 170 len = nla_len(opt) - NLA_ALIGN(sizeof(*qopt)); 257 171 if (len > 0) { 258 - err = parse_attr(tb, TCA_MQPRIO_MAX, opt, mqprio_policy, 259 - sizeof(*qopt)); 260 - if (err < 0) 172 + err = mqprio_parse_nlattr(sch, qopt, opt); 173 + if (err) 261 174 return err; 262 - 263 - if (!qopt->hw) 264 - return -EINVAL; 265 - 266 - if (tb[TCA_MQPRIO_MODE]) { 267 - priv->flags |= TC_MQPRIO_F_MODE; 268 - priv->mode = *(u16 *)nla_data(tb[TCA_MQPRIO_MODE]); 269 - } 270 - 271 - if (tb[TCA_MQPRIO_SHAPER]) { 272 - priv->flags |= TC_MQPRIO_F_SHAPER; 273 - priv->shaper = *(u16 *)nla_data(tb[TCA_MQPRIO_SHAPER]); 274 - } 275 - 276 - if (tb[TCA_MQPRIO_MIN_RATE64]) { 277 - if (priv->shaper != TC_MQPRIO_SHAPER_BW_RATE) 278 - return -EINVAL; 279 - i = 0; 280 - nla_for_each_nested(attr, tb[TCA_MQPRIO_MIN_RATE64], 281 - rem) { 282 - if (nla_type(attr) != TCA_MQPRIO_MIN_RATE64) 283 - return -EINVAL; 284 - if (i >= qopt->num_tc) 285 - break; 286 - priv->min_rate[i] = *(u64 *)nla_data(attr); 287 - i++; 288 - } 289 - priv->flags |= TC_MQPRIO_F_MIN_RATE; 290 - } 291 - 292 - if (tb[TCA_MQPRIO_MAX_RATE64]) { 293 - if (priv->shaper != TC_MQPRIO_SHAPER_BW_RATE) 294 - return -EINVAL; 295 - i = 0; 296 - nla_for_each_nested(attr, tb[TCA_MQPRIO_MAX_RATE64], 297 - rem) { 298 - if (nla_type(attr) != TCA_MQPRIO_MAX_RATE64) 299 - return -EINVAL; 300 - if (i >= qopt->num_tc) 301 - break; 302 - priv->max_rate[i] = *(u64 *)nla_data(attr); 303 - i++; 304 - } 305 - priv->flags |= TC_MQPRIO_F_MAX_RATE; 306 - } 307 175 } 308 176 309 177 /* pre-allocate qdisc, attachment can't fail */ ··· 287 241 * supplied and verified mapping 288 242 */ 289 243 if (qopt->hw) { 290 - struct tc_mqprio_qopt_offload mqprio = {.qopt = *qopt}; 291 - 292 - switch (priv->mode) { 293 - case TC_MQPRIO_MODE_DCB: 294 - if (priv->shaper != TC_MQPRIO_SHAPER_DCB) 295 - return -EINVAL; 296 - break; 297 - case TC_MQPRIO_MODE_CHANNEL: 298 - mqprio.flags = priv->flags; 299 - if (priv->flags & TC_MQPRIO_F_MODE) 300 - mqprio.mode = priv->mode; 301 - if (priv->flags & TC_MQPRIO_F_SHAPER) 302 - mqprio.shaper = priv->shaper; 303 - if (priv->flags & TC_MQPRIO_F_MIN_RATE) 304 - for (i = 0; i < mqprio.qopt.num_tc; i++) 305 - mqprio.min_rate[i] = priv->min_rate[i]; 306 - if (priv->flags & TC_MQPRIO_F_MAX_RATE) 307 - for (i = 0; i < mqprio.qopt.num_tc; i++) 308 - mqprio.max_rate[i] = priv->max_rate[i]; 309 - break; 310 - default: 311 - return -EINVAL; 312 - } 313 - err = dev->netdev_ops->ndo_setup_tc(dev, 314 - TC_SETUP_QDISC_MQPRIO, 315 - &mqprio); 244 + err = mqprio_enable_offload(sch, qopt, extack); 316 245 if (err) 317 246 return err; 318 - 319 - priv->hw_offload = mqprio.qopt.hw; 320 247 } else { 321 248 netdev_set_num_tc(dev, qopt->num_tc); 322 249 for (i = 0; i < qopt->num_tc; i++) ··· 406 387 struct nlattr *nla = (struct nlattr *)skb_tail_pointer(skb); 407 388 struct tc_mqprio_qopt opt = { 0 }; 408 389 struct Qdisc *qdisc; 409 - unsigned int ntx, tc; 390 + unsigned int ntx; 410 391 411 392 sch->q.qlen = 0; 412 393 gnet_stats_basic_sync_init(&sch->bstats); ··· 430 411 spin_unlock_bh(qdisc_lock(qdisc)); 431 412 } 432 413 433 - opt.num_tc = netdev_get_num_tc(dev); 434 - memcpy(opt.prio_tc_map, dev->prio_tc_map, sizeof(opt.prio_tc_map)); 414 + mqprio_qopt_reconstruct(dev, &opt); 435 415 opt.hw = priv->hw_offload; 436 - 437 - for (tc = 0; tc < netdev_get_num_tc(dev); tc++) { 438 - opt.count[tc] = dev->tc_to_txq[tc].count; 439 - opt.offset[tc] = dev->tc_to_txq[tc].offset; 440 - } 441 416 442 417 if (nla_put(skb, TCA_OPTIONS, sizeof(opt), &opt)) 443 418 goto nla_put_failure;
+117
net/sched/sch_mqprio_lib.c
··· 1 + // SPDX-License-Identifier: GPL-2.0-only 2 + 3 + #include <linux/net.h> 4 + #include <linux/netdevice.h> 5 + #include <linux/netlink.h> 6 + #include <linux/types.h> 7 + #include <net/pkt_sched.h> 8 + 9 + #include "sch_mqprio_lib.h" 10 + 11 + /* Returns true if the intervals [a, b) and [c, d) overlap. */ 12 + static bool intervals_overlap(int a, int b, int c, int d) 13 + { 14 + int left = max(a, c), right = min(b, d); 15 + 16 + return left < right; 17 + } 18 + 19 + static int mqprio_validate_queue_counts(struct net_device *dev, 20 + const struct tc_mqprio_qopt *qopt, 21 + bool allow_overlapping_txqs, 22 + struct netlink_ext_ack *extack) 23 + { 24 + int i, j; 25 + 26 + for (i = 0; i < qopt->num_tc; i++) { 27 + unsigned int last = qopt->offset[i] + qopt->count[i]; 28 + 29 + if (!qopt->count[i]) { 30 + NL_SET_ERR_MSG_FMT_MOD(extack, "No queues for TC %d", 31 + i); 32 + return -EINVAL; 33 + } 34 + 35 + /* Verify the queue count is in tx range being equal to the 36 + * real_num_tx_queues indicates the last queue is in use. 37 + */ 38 + if (qopt->offset[i] >= dev->real_num_tx_queues || 39 + last > dev->real_num_tx_queues) { 40 + NL_SET_ERR_MSG_FMT_MOD(extack, 41 + "Queues %d:%d for TC %d exceed the %d TX queues available", 42 + qopt->count[i], qopt->offset[i], 43 + i, dev->real_num_tx_queues); 44 + return -EINVAL; 45 + } 46 + 47 + if (allow_overlapping_txqs) 48 + continue; 49 + 50 + /* Verify that the offset and counts do not overlap */ 51 + for (j = i + 1; j < qopt->num_tc; j++) { 52 + if (intervals_overlap(qopt->offset[i], last, 53 + qopt->offset[j], 54 + qopt->offset[j] + 55 + qopt->count[j])) { 56 + NL_SET_ERR_MSG_FMT_MOD(extack, 57 + "TC %d queues %d@%d overlap with TC %d queues %d@%d", 58 + i, qopt->count[i], qopt->offset[i], 59 + j, qopt->count[j], qopt->offset[j]); 60 + return -EINVAL; 61 + } 62 + } 63 + } 64 + 65 + return 0; 66 + } 67 + 68 + int mqprio_validate_qopt(struct net_device *dev, struct tc_mqprio_qopt *qopt, 69 + bool validate_queue_counts, 70 + bool allow_overlapping_txqs, 71 + struct netlink_ext_ack *extack) 72 + { 73 + int i, err; 74 + 75 + /* Verify num_tc is not out of max range */ 76 + if (qopt->num_tc > TC_MAX_QUEUE) { 77 + NL_SET_ERR_MSG(extack, 78 + "Number of traffic classes is outside valid range"); 79 + return -EINVAL; 80 + } 81 + 82 + /* Verify priority mapping uses valid tcs */ 83 + for (i = 0; i <= TC_BITMASK; i++) { 84 + if (qopt->prio_tc_map[i] >= qopt->num_tc) { 85 + NL_SET_ERR_MSG(extack, 86 + "Invalid traffic class in priority to traffic class mapping"); 87 + return -EINVAL; 88 + } 89 + } 90 + 91 + if (validate_queue_counts) { 92 + err = mqprio_validate_queue_counts(dev, qopt, 93 + allow_overlapping_txqs, 94 + extack); 95 + if (err) 96 + return err; 97 + } 98 + 99 + return 0; 100 + } 101 + EXPORT_SYMBOL_GPL(mqprio_validate_qopt); 102 + 103 + void mqprio_qopt_reconstruct(struct net_device *dev, struct tc_mqprio_qopt *qopt) 104 + { 105 + int tc, num_tc = netdev_get_num_tc(dev); 106 + 107 + qopt->num_tc = num_tc; 108 + memcpy(qopt->prio_tc_map, dev->prio_tc_map, sizeof(qopt->prio_tc_map)); 109 + 110 + for (tc = 0; tc < num_tc; tc++) { 111 + qopt->count[tc] = dev->tc_to_txq[tc].count; 112 + qopt->offset[tc] = dev->tc_to_txq[tc].offset; 113 + } 114 + } 115 + EXPORT_SYMBOL_GPL(mqprio_qopt_reconstruct); 116 + 117 + MODULE_LICENSE("GPL");
+18
net/sched/sch_mqprio_lib.h
··· 1 + /* SPDX-License-Identifier: GPL-2.0 */ 2 + #ifndef __SCH_MQPRIO_LIB_H 3 + #define __SCH_MQPRIO_LIB_H 4 + 5 + #include <linux/types.h> 6 + 7 + struct net_device; 8 + struct netlink_ext_ack; 9 + struct tc_mqprio_qopt; 10 + 11 + int mqprio_validate_qopt(struct net_device *dev, struct tc_mqprio_qopt *qopt, 12 + bool validate_queue_counts, 13 + bool allow_overlapping_txqs, 14 + struct netlink_ext_ack *extack); 15 + void mqprio_qopt_reconstruct(struct net_device *dev, 16 + struct tc_mqprio_qopt *qopt); 17 + 18 + #endif
+18 -52
net/sched/sch_taprio.c
··· 26 26 #include <net/sock.h> 27 27 #include <net/tcp.h> 28 28 29 + #include "sch_mqprio_lib.h" 30 + 29 31 static LIST_HEAD(taprio_list); 30 32 31 33 #define TAPRIO_ALL_GATES_OPEN -1 ··· 926 924 struct netlink_ext_ack *extack, 927 925 u32 taprio_flags) 928 926 { 929 - int i, j; 927 + bool allow_overlapping_txqs = TXTIME_ASSIST_IS_ENABLED(taprio_flags); 930 928 931 929 if (!qopt && !dev->num_tc) { 932 930 NL_SET_ERR_MSG(extack, "'mqprio' configuration is necessary"); ··· 939 937 if (dev->num_tc) 940 938 return 0; 941 939 942 - /* Verify num_tc is not out of max range */ 943 - if (qopt->num_tc > TC_MAX_QUEUE) { 944 - NL_SET_ERR_MSG(extack, "Number of traffic classes is outside valid range"); 945 - return -EINVAL; 946 - } 947 - 948 940 /* taprio imposes that traffic classes map 1:n to tx queues */ 949 941 if (qopt->num_tc > dev->num_tx_queues) { 950 942 NL_SET_ERR_MSG(extack, "Number of traffic classes is greater than number of HW queues"); 951 943 return -EINVAL; 952 944 } 953 945 954 - /* Verify priority mapping uses valid tcs */ 955 - for (i = 0; i <= TC_BITMASK; i++) { 956 - if (qopt->prio_tc_map[i] >= qopt->num_tc) { 957 - NL_SET_ERR_MSG(extack, "Invalid traffic class in priority to traffic class mapping"); 958 - return -EINVAL; 959 - } 960 - } 961 - 962 - for (i = 0; i < qopt->num_tc; i++) { 963 - unsigned int last = qopt->offset[i] + qopt->count[i]; 964 - 965 - /* Verify the queue count is in tx range being equal to the 966 - * real_num_tx_queues indicates the last queue is in use. 967 - */ 968 - if (qopt->offset[i] >= dev->num_tx_queues || 969 - !qopt->count[i] || 970 - last > dev->real_num_tx_queues) { 971 - NL_SET_ERR_MSG(extack, "Invalid queue in traffic class to queue mapping"); 972 - return -EINVAL; 973 - } 974 - 975 - if (TXTIME_ASSIST_IS_ENABLED(taprio_flags)) 976 - continue; 977 - 978 - /* Verify that the offset and counts do not overlap */ 979 - for (j = i + 1; j < qopt->num_tc; j++) { 980 - if (last > qopt->offset[j]) { 981 - NL_SET_ERR_MSG(extack, "Detected overlap in the traffic class to queue mapping"); 982 - return -EINVAL; 983 - } 984 - } 985 - } 986 - 987 - return 0; 946 + /* For some reason, in txtime-assist mode, we allow TXQ ranges for 947 + * different TCs to overlap, and just validate the TXQ ranges. 948 + */ 949 + return mqprio_validate_qopt(dev, qopt, true, allow_overlapping_txqs, 950 + extack); 988 951 } 989 952 990 953 static int taprio_get_start_time(struct Qdisc *sch, ··· 1170 1203 1171 1204 static void taprio_sched_to_offload(struct net_device *dev, 1172 1205 struct sched_gate_list *sched, 1173 - struct tc_taprio_qopt_offload *offload) 1206 + struct tc_taprio_qopt_offload *offload, 1207 + const struct tc_taprio_caps *caps) 1174 1208 { 1175 1209 struct sched_entry *entry; 1176 1210 int i = 0; ··· 1185 1217 1186 1218 e->command = entry->command; 1187 1219 e->interval = entry->interval; 1188 - e->gate_mask = tc_map_to_queue_mask(dev, entry->gate_mask); 1220 + if (caps->gate_mask_per_txq) 1221 + e->gate_mask = tc_map_to_queue_mask(dev, 1222 + entry->gate_mask); 1223 + else 1224 + e->gate_mask = entry->gate_mask; 1189 1225 1190 1226 i++; 1191 1227 } ··· 1233 1261 return -ENOMEM; 1234 1262 } 1235 1263 offload->enable = 1; 1236 - taprio_sched_to_offload(dev, sched, offload); 1264 + mqprio_qopt_reconstruct(dev, &offload->mqprio.qopt); 1265 + taprio_sched_to_offload(dev, sched, offload, &caps); 1237 1266 1238 1267 for (tc = 0; tc < TC_MAX_QUEUE; tc++) 1239 1268 offload->max_sdu[tc] = q->max_sdu[tc]; ··· 1954 1981 struct sched_gate_list *oper, *admin; 1955 1982 struct tc_mqprio_qopt opt = { 0 }; 1956 1983 struct nlattr *nest, *sched_nest; 1957 - unsigned int i; 1958 1984 1959 1985 oper = rtnl_dereference(q->oper_sched); 1960 1986 admin = rtnl_dereference(q->admin_sched); 1961 1987 1962 - opt.num_tc = netdev_get_num_tc(dev); 1963 - memcpy(opt.prio_tc_map, dev->prio_tc_map, sizeof(opt.prio_tc_map)); 1964 - 1965 - for (i = 0; i < netdev_get_num_tc(dev); i++) { 1966 - opt.count[i] = dev->tc_to_txq[i].count; 1967 - opt.offset[i] = dev->tc_to_txq[i].offset; 1968 - } 1988 + mqprio_qopt_reconstruct(dev, &opt); 1969 1989 1970 1990 nest = nla_nest_start_noflag(skb, TCA_OPTIONS); 1971 1991 if (!nest)