drm/tests: hdmi: Fix memory leaks in drm_display_mode_from_cea_vic()
[drm/drm-misc.git] / net / sched / sch_mqprio_lib.c
blobb3a5572c167b719f96e2947fa4267f1f93077814
1 // SPDX-License-Identifier: GPL-2.0-only
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>
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);
16 return left < right;
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)
24 int i, j;
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",
31 i);
32 return -EINVAL;
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);
44 return -EINVAL;
47 if (allow_overlapping_txqs)
48 continue;
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;
65 return 0;
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)
73 int i, err;
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;
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;
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;
99 return 0;
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;
121 int tc;
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");