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 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 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 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