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