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