xref: /qemu/hw/virtio/iothread-vq-mapping.c (revision d64db833d6e3cbe9ea5f36342480f920f3675cea)
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
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 
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 
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