1 // SPDX-License-Identifier: GPL-2.0-only
4 #include <linux/netdevice.h>
5 #include <linux/netlink.h>
6 #include <linux/types.h>
7 #include <net/pkt_sched.h>
9 #include "sch_mqprio_lib.h"
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
)
14 int left
= max(a
, c
), right
= min(b
, d
);
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
)
26 for (i
= 0; i
< qopt
->num_tc
; i
++) {
27 unsigned int last
= qopt
->offset
[i
] + qopt
->count
[i
];
29 if (!qopt
->count
[i
]) {
30 NL_SET_ERR_MSG_FMT_MOD(extack
, "No queues for TC %d",
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.
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
);
47 if (allow_overlapping_txqs
)
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
,
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
]);
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
)
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");
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");
91 if (validate_queue_counts
) {
92 err
= mqprio_validate_queue_counts(dev
, qopt
,
93 allow_overlapping_txqs
,
101 EXPORT_SYMBOL_GPL(mqprio_validate_qopt
);
103 void mqprio_qopt_reconstruct(struct net_device
*dev
, struct tc_mqprio_qopt
*qopt
)
105 int tc
, num_tc
= netdev_get_num_tc(dev
);
107 qopt
->num_tc
= num_tc
;
108 memcpy(qopt
->prio_tc_map
, dev
->prio_tc_map
, sizeof(qopt
->prio_tc_map
));
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
;
115 EXPORT_SYMBOL_GPL(mqprio_qopt_reconstruct
);
117 void mqprio_fp_to_offload(u32 fp
[TC_QOPT_MAX_QUEUE
],
118 struct tc_mqprio_qopt_offload
*mqprio
)
120 unsigned long preemptible_tcs
= 0;
123 for (tc
= 0; tc
< TC_QOPT_MAX_QUEUE
; tc
++)
124 if (fp
[tc
] == TC_FP_PREEMPTIBLE
)
125 preemptible_tcs
|= BIT(tc
);
127 mqprio
->preemptible_tcs
= preemptible_tcs
;
129 EXPORT_SYMBOL_GPL(mqprio_fp_to_offload
);
131 MODULE_LICENSE("GPL");
132 MODULE_DESCRIPTION("Shared mqprio qdisc code currently between taprio and mqprio");