Merge tag 'perf-tools-fixes-for-v6.4-1-2023-05-20' of git://git.kernel.org/pub/scm...
[linux-block.git] / 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 void mqprio_fp_to_offload(u32 fp[TC_QOPT_MAX_QUEUE],
118                           struct tc_mqprio_qopt_offload *mqprio)
119 {
120         unsigned long preemptible_tcs = 0;
121         int tc;
122
123         for (tc = 0; tc < TC_QOPT_MAX_QUEUE; tc++)
124                 if (fp[tc] == TC_FP_PREEMPTIBLE)
125                         preemptible_tcs |= BIT(tc);
126
127         mqprio->preemptible_tcs = preemptible_tcs;
128 }
129 EXPORT_SYMBOL_GPL(mqprio_fp_to_offload);
130
131 MODULE_LICENSE("GPL");