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