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(a: qopt->offset[i], b: last, |
53 | c: qopt->offset[j], |
54 | d: 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" ); |
132 | MODULE_DESCRIPTION("Shared mqprio qdisc code currently between taprio and mqprio" ); |
133 | |