iothread-vq-mapping.c 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131
  1. /*
  2. * IOThread Virtqueue Mapping
  3. *
  4. * Copyright Red Hat, Inc
  5. *
  6. * SPDX-License-Identifier: GPL-2.0-only
  7. */
  8. #include "qemu/osdep.h"
  9. #include "system/iothread.h"
  10. #include "hw/virtio/iothread-vq-mapping.h"
  11. static bool
  12. iothread_vq_mapping_validate(IOThreadVirtQueueMappingList *list, uint16_t
  13. num_queues, Error **errp)
  14. {
  15. g_autofree unsigned long *vqs = bitmap_new(num_queues);
  16. g_autoptr(GHashTable) iothreads =
  17. g_hash_table_new(g_str_hash, g_str_equal);
  18. for (IOThreadVirtQueueMappingList *node = list; node; node = node->next) {
  19. const char *name = node->value->iothread;
  20. uint16List *vq;
  21. if (!iothread_by_id(name)) {
  22. error_setg(errp, "IOThread \"%s\" object does not exist", name);
  23. return false;
  24. }
  25. if (!g_hash_table_add(iothreads, (gpointer)name)) {
  26. error_setg(errp,
  27. "duplicate IOThread name \"%s\" in iothread-vq-mapping",
  28. name);
  29. return false;
  30. }
  31. if (node != list) {
  32. if (!!node->value->vqs != !!list->value->vqs) {
  33. error_setg(errp, "either all items in iothread-vq-mapping "
  34. "must have vqs or none of them must have it");
  35. return false;
  36. }
  37. }
  38. for (vq = node->value->vqs; vq; vq = vq->next) {
  39. if (vq->value >= num_queues) {
  40. error_setg(errp, "vq index %u for IOThread \"%s\" must be "
  41. "less than num_queues %u in iothread-vq-mapping",
  42. vq->value, name, num_queues);
  43. return false;
  44. }
  45. if (test_and_set_bit(vq->value, vqs)) {
  46. error_setg(errp, "cannot assign vq %u to IOThread \"%s\" "
  47. "because it is already assigned", vq->value, name);
  48. return false;
  49. }
  50. }
  51. }
  52. if (list->value->vqs) {
  53. for (uint16_t i = 0; i < num_queues; i++) {
  54. if (!test_bit(i, vqs)) {
  55. error_setg(errp,
  56. "missing vq %u IOThread assignment in iothread-vq-mapping",
  57. i);
  58. return false;
  59. }
  60. }
  61. }
  62. return true;
  63. }
  64. bool iothread_vq_mapping_apply(
  65. IOThreadVirtQueueMappingList *list,
  66. AioContext **vq_aio_context,
  67. uint16_t num_queues,
  68. Error **errp)
  69. {
  70. IOThreadVirtQueueMappingList *node;
  71. size_t num_iothreads = 0;
  72. size_t cur_iothread = 0;
  73. if (!iothread_vq_mapping_validate(list, num_queues, errp)) {
  74. return false;
  75. }
  76. for (node = list; node; node = node->next) {
  77. num_iothreads++;
  78. }
  79. for (node = list; node; node = node->next) {
  80. IOThread *iothread = iothread_by_id(node->value->iothread);
  81. AioContext *ctx = iothread_get_aio_context(iothread);
  82. /* Released in virtio_blk_vq_aio_context_cleanup() */
  83. object_ref(OBJECT(iothread));
  84. if (node->value->vqs) {
  85. uint16List *vq;
  86. /* Explicit vq:IOThread assignment */
  87. for (vq = node->value->vqs; vq; vq = vq->next) {
  88. assert(vq->value < num_queues);
  89. vq_aio_context[vq->value] = ctx;
  90. }
  91. } else {
  92. /* Round-robin vq:IOThread assignment */
  93. for (unsigned i = cur_iothread; i < num_queues;
  94. i += num_iothreads) {
  95. vq_aio_context[i] = ctx;
  96. }
  97. }
  98. cur_iothread++;
  99. }
  100. return true;
  101. }
  102. void iothread_vq_mapping_cleanup(IOThreadVirtQueueMappingList *list)
  103. {
  104. IOThreadVirtQueueMappingList *node;
  105. for (node = list; node; node = node->next) {
  106. IOThread *iothread = iothread_by_id(node->value->iothread);
  107. object_unref(OBJECT(iothread));
  108. }
  109. }