Linux Audio

Check our new training course

Loading...
Note: File does not exist in v4.6.
  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. */
 12static 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
 19static 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
 68int 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}
101EXPORT_SYMBOL_GPL(mqprio_validate_qopt);
102
103void 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}
115EXPORT_SYMBOL_GPL(mqprio_qopt_reconstruct);
116
117void 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}
129EXPORT_SYMBOL_GPL(mqprio_fp_to_offload);
130
131MODULE_LICENSE("GPL");
132MODULE_DESCRIPTION("Shared mqprio qdisc code currently between taprio and mqprio");