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