sch_mqprio_lib.c 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132
  1. // SPDX-License-Identifier: GPL-2.0-only
  2. #include <linux/net.h>
  3. #include <linux/netdevice.h>
  4. #include <linux/netlink.h>
  5. #include <linux/types.h>
  6. #include <net/pkt_sched.h>
  7. #include "sch_mqprio_lib.h"
  8. /* Returns true if the intervals [a, b) and [c, d) overlap. */
  9. static bool intervals_overlap(int a, int b, int c, int d)
  10. {
  11. int left = max(a, c), right = min(b, d);
  12. return left < right;
  13. }
  14. static int mqprio_validate_queue_counts(struct net_device *dev,
  15. const struct tc_mqprio_qopt *qopt,
  16. bool allow_overlapping_txqs,
  17. struct netlink_ext_ack *extack)
  18. {
  19. int i, j;
  20. for (i = 0; i < qopt->num_tc; i++) {
  21. unsigned int last = qopt->offset[i] + qopt->count[i];
  22. if (!qopt->count[i]) {
  23. NL_SET_ERR_MSG_FMT_MOD(extack, "No queues for TC %d",
  24. i);
  25. return -EINVAL;
  26. }
  27. /* Verify the queue count is in tx range being equal to the
  28. * real_num_tx_queues indicates the last queue is in use.
  29. */
  30. if (qopt->offset[i] >= dev->real_num_tx_queues ||
  31. last > dev->real_num_tx_queues) {
  32. NL_SET_ERR_MSG_FMT_MOD(extack,
  33. "Queues %d:%d for TC %d exceed the %d TX queues available",
  34. qopt->count[i], qopt->offset[i],
  35. i, dev->real_num_tx_queues);
  36. return -EINVAL;
  37. }
  38. if (allow_overlapping_txqs)
  39. continue;
  40. /* Verify that the offset and counts do not overlap */
  41. for (j = i + 1; j < qopt->num_tc; j++) {
  42. if (intervals_overlap(qopt->offset[i], last,
  43. qopt->offset[j],
  44. qopt->offset[j] +
  45. qopt->count[j])) {
  46. NL_SET_ERR_MSG_FMT_MOD(extack,
  47. "TC %d queues %d@%d overlap with TC %d queues %d@%d",
  48. i, qopt->count[i], qopt->offset[i],
  49. j, qopt->count[j], qopt->offset[j]);
  50. return -EINVAL;
  51. }
  52. }
  53. }
  54. return 0;
  55. }
  56. int mqprio_validate_qopt(struct net_device *dev, struct tc_mqprio_qopt *qopt,
  57. bool validate_queue_counts,
  58. bool allow_overlapping_txqs,
  59. struct netlink_ext_ack *extack)
  60. {
  61. int i, err;
  62. /* Verify num_tc is not out of max range */
  63. if (qopt->num_tc > TC_MAX_QUEUE) {
  64. NL_SET_ERR_MSG(extack,
  65. "Number of traffic classes is outside valid range");
  66. return -EINVAL;
  67. }
  68. /* Verify priority mapping uses valid tcs */
  69. for (i = 0; i <= TC_BITMASK; i++) {
  70. if (qopt->prio_tc_map[i] >= qopt->num_tc) {
  71. NL_SET_ERR_MSG(extack,
  72. "Invalid traffic class in priority to traffic class mapping");
  73. return -EINVAL;
  74. }
  75. }
  76. if (validate_queue_counts) {
  77. err = mqprio_validate_queue_counts(dev, qopt,
  78. allow_overlapping_txqs,
  79. extack);
  80. if (err)
  81. return err;
  82. }
  83. return 0;
  84. }
  85. EXPORT_SYMBOL_GPL(mqprio_validate_qopt);
  86. void mqprio_qopt_reconstruct(struct net_device *dev, struct tc_mqprio_qopt *qopt)
  87. {
  88. int tc, num_tc = netdev_get_num_tc(dev);
  89. qopt->num_tc = num_tc;
  90. memcpy(qopt->prio_tc_map, dev->prio_tc_map, sizeof(qopt->prio_tc_map));
  91. for (tc = 0; tc < num_tc; tc++) {
  92. qopt->count[tc] = dev->tc_to_txq[tc].count;
  93. qopt->offset[tc] = dev->tc_to_txq[tc].offset;
  94. }
  95. }
  96. EXPORT_SYMBOL_GPL(mqprio_qopt_reconstruct);
  97. void mqprio_fp_to_offload(u32 fp[TC_QOPT_MAX_QUEUE],
  98. struct tc_mqprio_qopt_offload *mqprio)
  99. {
  100. unsigned long preemptible_tcs = 0;
  101. int tc;
  102. for (tc = 0; tc < TC_QOPT_MAX_QUEUE; tc++)
  103. if (fp[tc] == TC_FP_PREEMPTIBLE)
  104. preemptible_tcs |= BIT(tc);
  105. mqprio->preemptible_tcs = preemptible_tcs;
  106. }
  107. EXPORT_SYMBOL_GPL(mqprio_fp_to_offload);
  108. MODULE_LICENSE("GPL");
  109. MODULE_DESCRIPTION("Shared mqprio qdisc code currently between taprio and mqprio");