175bb4625SJens Axboe /* 275bb4625SJens Axboe * CPU <-> hardware queue mapping helpers 375bb4625SJens Axboe * 475bb4625SJens Axboe * Copyright (C) 2013-2014 Jens Axboe 575bb4625SJens Axboe */ 6*320ae51fSJens Axboe #include <linux/kernel.h> 7*320ae51fSJens Axboe #include <linux/threads.h> 8*320ae51fSJens Axboe #include <linux/module.h> 9*320ae51fSJens Axboe #include <linux/mm.h> 10*320ae51fSJens Axboe #include <linux/smp.h> 11*320ae51fSJens Axboe #include <linux/cpu.h> 12*320ae51fSJens Axboe 13*320ae51fSJens Axboe #include <linux/blk-mq.h> 14*320ae51fSJens Axboe #include "blk.h" 15*320ae51fSJens Axboe #include "blk-mq.h" 16*320ae51fSJens Axboe 17*320ae51fSJens Axboe static int cpu_to_queue_index(unsigned int nr_cpus, unsigned int nr_queues, 18*320ae51fSJens Axboe const int cpu) 19*320ae51fSJens Axboe { 20959f5f5bSBart Van Assche return cpu * nr_queues / nr_cpus; 21*320ae51fSJens Axboe } 22*320ae51fSJens Axboe 23*320ae51fSJens Axboe static int get_first_sibling(unsigned int cpu) 24*320ae51fSJens Axboe { 25*320ae51fSJens Axboe unsigned int ret; 26*320ae51fSJens Axboe 27*320ae51fSJens Axboe ret = cpumask_first(topology_thread_cpumask(cpu)); 28*320ae51fSJens Axboe if (ret < nr_cpu_ids) 29*320ae51fSJens Axboe return ret; 30*320ae51fSJens Axboe 31*320ae51fSJens Axboe return cpu; 32*320ae51fSJens Axboe } 33*320ae51fSJens Axboe 34*320ae51fSJens Axboe int blk_mq_update_queue_map(unsigned int *map, unsigned int nr_queues) 35*320ae51fSJens Axboe { 36*320ae51fSJens Axboe unsigned int i, nr_cpus, nr_uniq_cpus, queue, first_sibling; 37*320ae51fSJens Axboe cpumask_var_t cpus; 38*320ae51fSJens Axboe 39*320ae51fSJens Axboe if (!alloc_cpumask_var(&cpus, GFP_ATOMIC)) 40*320ae51fSJens Axboe return 1; 41*320ae51fSJens Axboe 42*320ae51fSJens Axboe cpumask_clear(cpus); 43*320ae51fSJens Axboe nr_cpus = nr_uniq_cpus = 0; 44*320ae51fSJens Axboe for_each_online_cpu(i) { 45*320ae51fSJens Axboe nr_cpus++; 46*320ae51fSJens Axboe first_sibling = get_first_sibling(i); 47*320ae51fSJens Axboe if (!cpumask_test_cpu(first_sibling, cpus)) 48*320ae51fSJens Axboe nr_uniq_cpus++; 49*320ae51fSJens Axboe cpumask_set_cpu(i, cpus); 50*320ae51fSJens Axboe } 51*320ae51fSJens Axboe 52*320ae51fSJens Axboe queue = 0; 53*320ae51fSJens Axboe for_each_possible_cpu(i) { 54*320ae51fSJens Axboe if (!cpu_online(i)) { 55*320ae51fSJens Axboe map[i] = 0; 56*320ae51fSJens Axboe continue; 57*320ae51fSJens Axboe } 58*320ae51fSJens Axboe 59*320ae51fSJens Axboe /* 60*320ae51fSJens Axboe * Easy case - we have equal or more hardware queues. Or 61*320ae51fSJens Axboe * there are no thread siblings to take into account. Do 62*320ae51fSJens Axboe * 1:1 if enough, or sequential mapping if less. 63*320ae51fSJens Axboe */ 64*320ae51fSJens Axboe if (nr_queues >= nr_cpus || nr_cpus == nr_uniq_cpus) { 65*320ae51fSJens Axboe map[i] = cpu_to_queue_index(nr_cpus, nr_queues, queue); 66*320ae51fSJens Axboe queue++; 67*320ae51fSJens Axboe continue; 68*320ae51fSJens Axboe } 69*320ae51fSJens Axboe 70*320ae51fSJens Axboe /* 71*320ae51fSJens Axboe * Less then nr_cpus queues, and we have some number of 72*320ae51fSJens Axboe * threads per cores. Map sibling threads to the same 73*320ae51fSJens Axboe * queue. 74*320ae51fSJens Axboe */ 75*320ae51fSJens Axboe first_sibling = get_first_sibling(i); 76*320ae51fSJens Axboe if (first_sibling == i) { 77*320ae51fSJens Axboe map[i] = cpu_to_queue_index(nr_uniq_cpus, nr_queues, 78*320ae51fSJens Axboe queue); 79*320ae51fSJens Axboe queue++; 80*320ae51fSJens Axboe } else 81*320ae51fSJens Axboe map[i] = map[first_sibling]; 82*320ae51fSJens Axboe } 83*320ae51fSJens Axboe 84*320ae51fSJens Axboe free_cpumask_var(cpus); 85*320ae51fSJens Axboe return 0; 86*320ae51fSJens Axboe } 87*320ae51fSJens Axboe 8824d2f903SChristoph Hellwig unsigned int *blk_mq_make_queue_map(struct blk_mq_tag_set *set) 89*320ae51fSJens Axboe { 90*320ae51fSJens Axboe unsigned int *map; 91*320ae51fSJens Axboe 92*320ae51fSJens Axboe /* If cpus are offline, map them to first hctx */ 93a33c1ba2SJens Axboe map = kzalloc_node(sizeof(*map) * nr_cpu_ids, GFP_KERNEL, 9424d2f903SChristoph Hellwig set->numa_node); 95*320ae51fSJens Axboe if (!map) 96*320ae51fSJens Axboe return NULL; 97*320ae51fSJens Axboe 9824d2f903SChristoph Hellwig if (!blk_mq_update_queue_map(map, set->nr_hw_queues)) 99*320ae51fSJens Axboe return map; 100*320ae51fSJens Axboe 101*320ae51fSJens Axboe kfree(map); 102*320ae51fSJens Axboe return NULL; 103*320ae51fSJens Axboe } 104f14bbe77SJens Axboe 105f14bbe77SJens Axboe /* 106f14bbe77SJens Axboe * We have no quick way of doing reverse lookups. This is only used at 107f14bbe77SJens Axboe * queue init time, so runtime isn't important. 108f14bbe77SJens Axboe */ 109f14bbe77SJens Axboe int blk_mq_hw_queue_to_node(unsigned int *mq_map, unsigned int index) 110f14bbe77SJens Axboe { 111f14bbe77SJens Axboe int i; 112f14bbe77SJens Axboe 113f14bbe77SJens Axboe for_each_possible_cpu(i) { 114f14bbe77SJens Axboe if (index == mq_map[i]) 115f14bbe77SJens Axboe return cpu_to_node(i); 116f14bbe77SJens Axboe } 117f14bbe77SJens Axboe 118f14bbe77SJens Axboe return NUMA_NO_NODE; 119f14bbe77SJens Axboe } 120