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