1f48ad614SDennis Dalessandro /* 2f48ad614SDennis Dalessandro * Copyright(c) 2015, 2016 Intel Corporation. 3f48ad614SDennis Dalessandro * 4f48ad614SDennis Dalessandro * This file is provided under a dual BSD/GPLv2 license. When using or 5f48ad614SDennis Dalessandro * redistributing this file, you may do so under either license. 6f48ad614SDennis Dalessandro * 7f48ad614SDennis Dalessandro * GPL LICENSE SUMMARY 8f48ad614SDennis Dalessandro * 9f48ad614SDennis Dalessandro * This program is free software; you can redistribute it and/or modify 10f48ad614SDennis Dalessandro * it under the terms of version 2 of the GNU General Public License as 11f48ad614SDennis Dalessandro * published by the Free Software Foundation. 12f48ad614SDennis Dalessandro * 13f48ad614SDennis Dalessandro * This program is distributed in the hope that it will be useful, but 14f48ad614SDennis Dalessandro * WITHOUT ANY WARRANTY; without even the implied warranty of 15f48ad614SDennis Dalessandro * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 16f48ad614SDennis Dalessandro * General Public License for more details. 17f48ad614SDennis Dalessandro * 18f48ad614SDennis Dalessandro * BSD LICENSE 19f48ad614SDennis Dalessandro * 20f48ad614SDennis Dalessandro * Redistribution and use in source and binary forms, with or without 21f48ad614SDennis Dalessandro * modification, are permitted provided that the following conditions 22f48ad614SDennis Dalessandro * are met: 23f48ad614SDennis Dalessandro * 24f48ad614SDennis Dalessandro * - Redistributions of source code must retain the above copyright 25f48ad614SDennis Dalessandro * notice, this list of conditions and the following disclaimer. 26f48ad614SDennis Dalessandro * - Redistributions in binary form must reproduce the above copyright 27f48ad614SDennis Dalessandro * notice, this list of conditions and the following disclaimer in 28f48ad614SDennis Dalessandro * the documentation and/or other materials provided with the 29f48ad614SDennis Dalessandro * distribution. 30f48ad614SDennis Dalessandro * - Neither the name of Intel Corporation nor the names of its 31f48ad614SDennis Dalessandro * contributors may be used to endorse or promote products derived 32f48ad614SDennis Dalessandro * from this software without specific prior written permission. 33f48ad614SDennis Dalessandro * 34f48ad614SDennis Dalessandro * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 35f48ad614SDennis Dalessandro * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 36f48ad614SDennis Dalessandro * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 37f48ad614SDennis Dalessandro * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 38f48ad614SDennis Dalessandro * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 39f48ad614SDennis Dalessandro * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 40f48ad614SDennis Dalessandro * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 41f48ad614SDennis Dalessandro * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 42f48ad614SDennis Dalessandro * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 43f48ad614SDennis Dalessandro * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 44f48ad614SDennis Dalessandro * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 45f48ad614SDennis Dalessandro * 46f48ad614SDennis Dalessandro */ 47f48ad614SDennis Dalessandro #include <linux/topology.h> 48f48ad614SDennis Dalessandro #include <linux/cpumask.h> 49f48ad614SDennis Dalessandro #include <linux/module.h> 50f48ad614SDennis Dalessandro 51f48ad614SDennis Dalessandro #include "hfi.h" 52f48ad614SDennis Dalessandro #include "affinity.h" 53f48ad614SDennis Dalessandro #include "sdma.h" 54f48ad614SDennis Dalessandro #include "trace.h" 55f48ad614SDennis Dalessandro 564197344bSDennis Dalessandro struct hfi1_affinity_node_list node_affinity = { 574197344bSDennis Dalessandro .list = LIST_HEAD_INIT(node_affinity.list), 58*584d9577STadeusz Struk .lock = __MUTEX_INITIALIZER(node_affinity.lock) 594197344bSDennis Dalessandro }; 604197344bSDennis Dalessandro 61f48ad614SDennis Dalessandro /* Name of IRQ types, indexed by enum irq_type */ 62f48ad614SDennis Dalessandro static const char * const irq_type_names[] = { 63f48ad614SDennis Dalessandro "SDMA", 64f48ad614SDennis Dalessandro "RCVCTXT", 65f48ad614SDennis Dalessandro "GENERAL", 66f48ad614SDennis Dalessandro "OTHER", 67f48ad614SDennis Dalessandro }; 68f48ad614SDennis Dalessandro 69d6373019SSebastian Sanchez /* Per NUMA node count of HFI devices */ 70d6373019SSebastian Sanchez static unsigned int *hfi1_per_node_cntr; 71d6373019SSebastian Sanchez 72f48ad614SDennis Dalessandro static inline void init_cpu_mask_set(struct cpu_mask_set *set) 73f48ad614SDennis Dalessandro { 74f48ad614SDennis Dalessandro cpumask_clear(&set->mask); 75f48ad614SDennis Dalessandro cpumask_clear(&set->used); 76f48ad614SDennis Dalessandro set->gen = 0; 77f48ad614SDennis Dalessandro } 78f48ad614SDennis Dalessandro 79f48ad614SDennis Dalessandro /* Initialize non-HT cpu cores mask */ 804197344bSDennis Dalessandro void init_real_cpu_mask(void) 81f48ad614SDennis Dalessandro { 82f48ad614SDennis Dalessandro int possible, curr_cpu, i, ht; 83f48ad614SDennis Dalessandro 844197344bSDennis Dalessandro cpumask_clear(&node_affinity.real_cpu_mask); 85f48ad614SDennis Dalessandro 86f48ad614SDennis Dalessandro /* Start with cpu online mask as the real cpu mask */ 874197344bSDennis Dalessandro cpumask_copy(&node_affinity.real_cpu_mask, cpu_online_mask); 88f48ad614SDennis Dalessandro 89f48ad614SDennis Dalessandro /* 90f48ad614SDennis Dalessandro * Remove HT cores from the real cpu mask. Do this in two steps below. 91f48ad614SDennis Dalessandro */ 924197344bSDennis Dalessandro possible = cpumask_weight(&node_affinity.real_cpu_mask); 93f48ad614SDennis Dalessandro ht = cpumask_weight(topology_sibling_cpumask( 944197344bSDennis Dalessandro cpumask_first(&node_affinity.real_cpu_mask))); 95f48ad614SDennis Dalessandro /* 96f48ad614SDennis Dalessandro * Step 1. Skip over the first N HT siblings and use them as the 97f48ad614SDennis Dalessandro * "real" cores. Assumes that HT cores are not enumerated in 98f48ad614SDennis Dalessandro * succession (except in the single core case). 99f48ad614SDennis Dalessandro */ 1004197344bSDennis Dalessandro curr_cpu = cpumask_first(&node_affinity.real_cpu_mask); 101f48ad614SDennis Dalessandro for (i = 0; i < possible / ht; i++) 1024197344bSDennis Dalessandro curr_cpu = cpumask_next(curr_cpu, &node_affinity.real_cpu_mask); 103f48ad614SDennis Dalessandro /* 104f48ad614SDennis Dalessandro * Step 2. Remove the remaining HT siblings. Use cpumask_next() to 105f48ad614SDennis Dalessandro * skip any gaps. 106f48ad614SDennis Dalessandro */ 107f48ad614SDennis Dalessandro for (; i < possible; i++) { 1084197344bSDennis Dalessandro cpumask_clear_cpu(curr_cpu, &node_affinity.real_cpu_mask); 1094197344bSDennis Dalessandro curr_cpu = cpumask_next(curr_cpu, &node_affinity.real_cpu_mask); 1104197344bSDennis Dalessandro } 111f48ad614SDennis Dalessandro } 112f48ad614SDennis Dalessandro 113d6373019SSebastian Sanchez int node_affinity_init(void) 1144197344bSDennis Dalessandro { 115d6373019SSebastian Sanchez int node; 116d6373019SSebastian Sanchez struct pci_dev *dev = NULL; 117d6373019SSebastian Sanchez const struct pci_device_id *ids = hfi1_pci_tbl; 118d6373019SSebastian Sanchez 119b094a36fSSebastian Sanchez cpumask_clear(&node_affinity.proc.used); 1204197344bSDennis Dalessandro cpumask_copy(&node_affinity.proc.mask, cpu_online_mask); 121b094a36fSSebastian Sanchez 122b094a36fSSebastian Sanchez node_affinity.proc.gen = 0; 123b094a36fSSebastian Sanchez node_affinity.num_core_siblings = 124b094a36fSSebastian Sanchez cpumask_weight(topology_sibling_cpumask( 125b094a36fSSebastian Sanchez cpumask_first(&node_affinity.proc.mask) 126b094a36fSSebastian Sanchez )); 127b094a36fSSebastian Sanchez node_affinity.num_online_nodes = num_online_nodes(); 128b094a36fSSebastian Sanchez node_affinity.num_online_cpus = num_online_cpus(); 129b094a36fSSebastian Sanchez 1304197344bSDennis Dalessandro /* 1314197344bSDennis Dalessandro * The real cpu mask is part of the affinity struct but it has to be 1324197344bSDennis Dalessandro * initialized early. It is needed to calculate the number of user 1334197344bSDennis Dalessandro * contexts in set_up_context_variables(). 1344197344bSDennis Dalessandro */ 1354197344bSDennis Dalessandro init_real_cpu_mask(); 136d6373019SSebastian Sanchez 137d6373019SSebastian Sanchez hfi1_per_node_cntr = kcalloc(num_possible_nodes(), 138d6373019SSebastian Sanchez sizeof(*hfi1_per_node_cntr), GFP_KERNEL); 139d6373019SSebastian Sanchez if (!hfi1_per_node_cntr) 140d6373019SSebastian Sanchez return -ENOMEM; 141d6373019SSebastian Sanchez 142d6373019SSebastian Sanchez while (ids->vendor) { 143d6373019SSebastian Sanchez dev = NULL; 144d6373019SSebastian Sanchez while ((dev = pci_get_device(ids->vendor, ids->device, dev))) { 145d6373019SSebastian Sanchez node = pcibus_to_node(dev->bus); 146d6373019SSebastian Sanchez if (node < 0) 147d6373019SSebastian Sanchez node = numa_node_id(); 148d6373019SSebastian Sanchez 149d6373019SSebastian Sanchez hfi1_per_node_cntr[node]++; 150d6373019SSebastian Sanchez } 151d6373019SSebastian Sanchez ids++; 152d6373019SSebastian Sanchez } 153d6373019SSebastian Sanchez 154d6373019SSebastian Sanchez return 0; 1554197344bSDennis Dalessandro } 1564197344bSDennis Dalessandro 1574197344bSDennis Dalessandro void node_affinity_destroy(void) 1584197344bSDennis Dalessandro { 1594197344bSDennis Dalessandro struct list_head *pos, *q; 1604197344bSDennis Dalessandro struct hfi1_affinity_node *entry; 1614197344bSDennis Dalessandro 162*584d9577STadeusz Struk mutex_lock(&node_affinity.lock); 1634197344bSDennis Dalessandro list_for_each_safe(pos, q, &node_affinity.list) { 1644197344bSDennis Dalessandro entry = list_entry(pos, struct hfi1_affinity_node, 1654197344bSDennis Dalessandro list); 1664197344bSDennis Dalessandro list_del(pos); 1674197344bSDennis Dalessandro kfree(entry); 1684197344bSDennis Dalessandro } 169*584d9577STadeusz Struk mutex_unlock(&node_affinity.lock); 170d6373019SSebastian Sanchez kfree(hfi1_per_node_cntr); 1714197344bSDennis Dalessandro } 1724197344bSDennis Dalessandro 1734197344bSDennis Dalessandro static struct hfi1_affinity_node *node_affinity_allocate(int node) 1744197344bSDennis Dalessandro { 1754197344bSDennis Dalessandro struct hfi1_affinity_node *entry; 1764197344bSDennis Dalessandro 1774197344bSDennis Dalessandro entry = kzalloc(sizeof(*entry), GFP_KERNEL); 1784197344bSDennis Dalessandro if (!entry) 1794197344bSDennis Dalessandro return NULL; 1804197344bSDennis Dalessandro entry->node = node; 1814197344bSDennis Dalessandro INIT_LIST_HEAD(&entry->list); 1824197344bSDennis Dalessandro 1834197344bSDennis Dalessandro return entry; 1844197344bSDennis Dalessandro } 1854197344bSDennis Dalessandro 1864197344bSDennis Dalessandro /* 1874197344bSDennis Dalessandro * It appends an entry to the list. 1884197344bSDennis Dalessandro * It *must* be called with node_affinity.lock held. 1894197344bSDennis Dalessandro */ 1904197344bSDennis Dalessandro static void node_affinity_add_tail(struct hfi1_affinity_node *entry) 1914197344bSDennis Dalessandro { 1924197344bSDennis Dalessandro list_add_tail(&entry->list, &node_affinity.list); 1934197344bSDennis Dalessandro } 1944197344bSDennis Dalessandro 1954197344bSDennis Dalessandro /* It must be called with node_affinity.lock held */ 1964197344bSDennis Dalessandro static struct hfi1_affinity_node *node_affinity_lookup(int node) 1974197344bSDennis Dalessandro { 1984197344bSDennis Dalessandro struct list_head *pos; 1994197344bSDennis Dalessandro struct hfi1_affinity_node *entry; 2004197344bSDennis Dalessandro 2014197344bSDennis Dalessandro list_for_each(pos, &node_affinity.list) { 2024197344bSDennis Dalessandro entry = list_entry(pos, struct hfi1_affinity_node, list); 2034197344bSDennis Dalessandro if (entry->node == node) 2044197344bSDennis Dalessandro return entry; 2054197344bSDennis Dalessandro } 2064197344bSDennis Dalessandro 2074197344bSDennis Dalessandro return NULL; 208f48ad614SDennis Dalessandro } 209f48ad614SDennis Dalessandro 210f48ad614SDennis Dalessandro /* 211f48ad614SDennis Dalessandro * Interrupt affinity. 212f48ad614SDennis Dalessandro * 213f48ad614SDennis Dalessandro * non-rcv avail gets a default mask that 214f48ad614SDennis Dalessandro * starts as possible cpus with threads reset 215f48ad614SDennis Dalessandro * and each rcv avail reset. 216f48ad614SDennis Dalessandro * 217f48ad614SDennis Dalessandro * rcv avail gets node relative 1 wrapping back 218f48ad614SDennis Dalessandro * to the node relative 1 as necessary. 219f48ad614SDennis Dalessandro * 220f48ad614SDennis Dalessandro */ 2214197344bSDennis Dalessandro int hfi1_dev_affinity_init(struct hfi1_devdata *dd) 222f48ad614SDennis Dalessandro { 223f48ad614SDennis Dalessandro int node = pcibus_to_node(dd->pcidev->bus); 2244197344bSDennis Dalessandro struct hfi1_affinity_node *entry; 225f48ad614SDennis Dalessandro const struct cpumask *local_mask; 226f48ad614SDennis Dalessandro int curr_cpu, possible, i; 227f48ad614SDennis Dalessandro 228f48ad614SDennis Dalessandro if (node < 0) 229f48ad614SDennis Dalessandro node = numa_node_id(); 230f48ad614SDennis Dalessandro dd->node = node; 231f48ad614SDennis Dalessandro 232f48ad614SDennis Dalessandro local_mask = cpumask_of_node(dd->node); 233f48ad614SDennis Dalessandro if (cpumask_first(local_mask) >= nr_cpu_ids) 234f48ad614SDennis Dalessandro local_mask = topology_core_cpumask(0); 2354197344bSDennis Dalessandro 236*584d9577STadeusz Struk mutex_lock(&node_affinity.lock); 2374197344bSDennis Dalessandro entry = node_affinity_lookup(dd->node); 2384197344bSDennis Dalessandro 2394197344bSDennis Dalessandro /* 2404197344bSDennis Dalessandro * If this is the first time this NUMA node's affinity is used, 2414197344bSDennis Dalessandro * create an entry in the global affinity structure and initialize it. 2424197344bSDennis Dalessandro */ 2434197344bSDennis Dalessandro if (!entry) { 2444197344bSDennis Dalessandro entry = node_affinity_allocate(node); 2454197344bSDennis Dalessandro if (!entry) { 2464197344bSDennis Dalessandro dd_dev_err(dd, 2474197344bSDennis Dalessandro "Unable to allocate global affinity node\n"); 248*584d9577STadeusz Struk mutex_unlock(&node_affinity.lock); 2494197344bSDennis Dalessandro return -ENOMEM; 2504197344bSDennis Dalessandro } 2514197344bSDennis Dalessandro init_cpu_mask_set(&entry->def_intr); 2524197344bSDennis Dalessandro init_cpu_mask_set(&entry->rcv_intr); 253d6373019SSebastian Sanchez cpumask_clear(&entry->general_intr_mask); 254f48ad614SDennis Dalessandro /* Use the "real" cpu mask of this node as the default */ 2554197344bSDennis Dalessandro cpumask_and(&entry->def_intr.mask, &node_affinity.real_cpu_mask, 2564197344bSDennis Dalessandro local_mask); 257f48ad614SDennis Dalessandro 258f48ad614SDennis Dalessandro /* fill in the receive list */ 2594197344bSDennis Dalessandro possible = cpumask_weight(&entry->def_intr.mask); 2604197344bSDennis Dalessandro curr_cpu = cpumask_first(&entry->def_intr.mask); 2614197344bSDennis Dalessandro 262f48ad614SDennis Dalessandro if (possible == 1) { 263f48ad614SDennis Dalessandro /* only one CPU, everyone will use it */ 2644197344bSDennis Dalessandro cpumask_set_cpu(curr_cpu, &entry->rcv_intr.mask); 265d6373019SSebastian Sanchez cpumask_set_cpu(curr_cpu, &entry->general_intr_mask); 266f48ad614SDennis Dalessandro } else { 267f48ad614SDennis Dalessandro /* 268d6373019SSebastian Sanchez * The general/control context will be the first CPU in 269d6373019SSebastian Sanchez * the default list, so it is removed from the default 270d6373019SSebastian Sanchez * list and added to the general interrupt list. 271f48ad614SDennis Dalessandro */ 272d6373019SSebastian Sanchez cpumask_clear_cpu(curr_cpu, &entry->def_intr.mask); 273d6373019SSebastian Sanchez cpumask_set_cpu(curr_cpu, &entry->general_intr_mask); 2744197344bSDennis Dalessandro curr_cpu = cpumask_next(curr_cpu, 2754197344bSDennis Dalessandro &entry->def_intr.mask); 2764197344bSDennis Dalessandro 277f48ad614SDennis Dalessandro /* 278f48ad614SDennis Dalessandro * Remove the remaining kernel receive queues from 279f48ad614SDennis Dalessandro * the default list and add them to the receive list. 280f48ad614SDennis Dalessandro */ 281d6373019SSebastian Sanchez for (i = 0; 282d6373019SSebastian Sanchez i < (dd->n_krcv_queues - 1) * 283d6373019SSebastian Sanchez hfi1_per_node_cntr[dd->node]; 284d6373019SSebastian Sanchez i++) { 2854197344bSDennis Dalessandro cpumask_clear_cpu(curr_cpu, 2864197344bSDennis Dalessandro &entry->def_intr.mask); 2874197344bSDennis Dalessandro cpumask_set_cpu(curr_cpu, 2884197344bSDennis Dalessandro &entry->rcv_intr.mask); 2894197344bSDennis Dalessandro curr_cpu = cpumask_next(curr_cpu, 2904197344bSDennis Dalessandro &entry->def_intr.mask); 291f48ad614SDennis Dalessandro if (curr_cpu >= nr_cpu_ids) 292f48ad614SDennis Dalessandro break; 293f48ad614SDennis Dalessandro } 294d6373019SSebastian Sanchez 295d6373019SSebastian Sanchez /* 296d6373019SSebastian Sanchez * If there ends up being 0 CPU cores leftover for SDMA 297d6373019SSebastian Sanchez * engines, use the same CPU cores as general/control 298d6373019SSebastian Sanchez * context. 299d6373019SSebastian Sanchez */ 300d6373019SSebastian Sanchez if (cpumask_weight(&entry->def_intr.mask) == 0) 301d6373019SSebastian Sanchez cpumask_copy(&entry->def_intr.mask, 302d6373019SSebastian Sanchez &entry->general_intr_mask); 303f48ad614SDennis Dalessandro } 304f48ad614SDennis Dalessandro 3054197344bSDennis Dalessandro node_affinity_add_tail(entry); 306f48ad614SDennis Dalessandro } 307*584d9577STadeusz Struk mutex_unlock(&node_affinity.lock); 3084197344bSDennis Dalessandro return 0; 309f48ad614SDennis Dalessandro } 310f48ad614SDennis Dalessandro 311*584d9577STadeusz Struk /* 312*584d9577STadeusz Struk * Function sets the irq affinity for msix. 313*584d9577STadeusz Struk * It *must* be called with node_affinity.lock held. 314*584d9577STadeusz Struk */ 315*584d9577STadeusz Struk static int get_irq_affinity(struct hfi1_devdata *dd, 316*584d9577STadeusz Struk struct hfi1_msix_entry *msix) 317f48ad614SDennis Dalessandro { 318f48ad614SDennis Dalessandro int ret; 319f48ad614SDennis Dalessandro cpumask_var_t diff; 3204197344bSDennis Dalessandro struct hfi1_affinity_node *entry; 321d6373019SSebastian Sanchez struct cpu_mask_set *set = NULL; 322f48ad614SDennis Dalessandro struct sdma_engine *sde = NULL; 323f48ad614SDennis Dalessandro struct hfi1_ctxtdata *rcd = NULL; 324f48ad614SDennis Dalessandro char extra[64]; 325f48ad614SDennis Dalessandro int cpu = -1; 326f48ad614SDennis Dalessandro 327f48ad614SDennis Dalessandro extra[0] = '\0'; 328f48ad614SDennis Dalessandro cpumask_clear(&msix->mask); 329f48ad614SDennis Dalessandro 330f48ad614SDennis Dalessandro ret = zalloc_cpumask_var(&diff, GFP_KERNEL); 331f48ad614SDennis Dalessandro if (!ret) 332f48ad614SDennis Dalessandro return -ENOMEM; 333f48ad614SDennis Dalessandro 3344197344bSDennis Dalessandro entry = node_affinity_lookup(dd->node); 3354197344bSDennis Dalessandro 336f48ad614SDennis Dalessandro switch (msix->type) { 337f48ad614SDennis Dalessandro case IRQ_SDMA: 338f48ad614SDennis Dalessandro sde = (struct sdma_engine *)msix->arg; 339f48ad614SDennis Dalessandro scnprintf(extra, 64, "engine %u", sde->this_idx); 3404197344bSDennis Dalessandro set = &entry->def_intr; 341f48ad614SDennis Dalessandro break; 342d6373019SSebastian Sanchez case IRQ_GENERAL: 343d6373019SSebastian Sanchez cpu = cpumask_first(&entry->general_intr_mask); 344d6373019SSebastian Sanchez break; 345f48ad614SDennis Dalessandro case IRQ_RCVCTXT: 346f48ad614SDennis Dalessandro rcd = (struct hfi1_ctxtdata *)msix->arg; 347d6373019SSebastian Sanchez if (rcd->ctxt == HFI1_CTRL_CTXT) 348d6373019SSebastian Sanchez cpu = cpumask_first(&entry->general_intr_mask); 349d6373019SSebastian Sanchez else 3504197344bSDennis Dalessandro set = &entry->rcv_intr; 351f48ad614SDennis Dalessandro scnprintf(extra, 64, "ctxt %u", rcd->ctxt); 352f48ad614SDennis Dalessandro break; 353f48ad614SDennis Dalessandro default: 354f48ad614SDennis Dalessandro dd_dev_err(dd, "Invalid IRQ type %d\n", msix->type); 355f48ad614SDennis Dalessandro return -EINVAL; 356f48ad614SDennis Dalessandro } 357f48ad614SDennis Dalessandro 358f48ad614SDennis Dalessandro /* 359d6373019SSebastian Sanchez * The general and control contexts are placed on a particular 360d6373019SSebastian Sanchez * CPU, which is set above. Skip accounting for it. Everything else 361d6373019SSebastian Sanchez * finds its CPU here. 362f48ad614SDennis Dalessandro */ 3634197344bSDennis Dalessandro if (cpu == -1 && set) { 364f48ad614SDennis Dalessandro if (cpumask_equal(&set->mask, &set->used)) { 365f48ad614SDennis Dalessandro /* 366f48ad614SDennis Dalessandro * We've used up all the CPUs, bump up the generation 367f48ad614SDennis Dalessandro * and reset the 'used' map 368f48ad614SDennis Dalessandro */ 369f48ad614SDennis Dalessandro set->gen++; 370f48ad614SDennis Dalessandro cpumask_clear(&set->used); 371f48ad614SDennis Dalessandro } 372f48ad614SDennis Dalessandro cpumask_andnot(diff, &set->mask, &set->used); 373f48ad614SDennis Dalessandro cpu = cpumask_first(diff); 374f48ad614SDennis Dalessandro cpumask_set_cpu(cpu, &set->used); 375f48ad614SDennis Dalessandro } 376f48ad614SDennis Dalessandro 377f48ad614SDennis Dalessandro switch (msix->type) { 378f48ad614SDennis Dalessandro case IRQ_SDMA: 379f48ad614SDennis Dalessandro sde->cpu = cpu; 380f48ad614SDennis Dalessandro break; 381f48ad614SDennis Dalessandro case IRQ_GENERAL: 382f48ad614SDennis Dalessandro case IRQ_RCVCTXT: 383f48ad614SDennis Dalessandro case IRQ_OTHER: 384f48ad614SDennis Dalessandro break; 385f48ad614SDennis Dalessandro } 386f48ad614SDennis Dalessandro 387f48ad614SDennis Dalessandro cpumask_set_cpu(cpu, &msix->mask); 388f48ad614SDennis Dalessandro dd_dev_info(dd, "IRQ vector: %u, type %s %s -> cpu: %d\n", 389f48ad614SDennis Dalessandro msix->msix.vector, irq_type_names[msix->type], 390f48ad614SDennis Dalessandro extra, cpu); 391f48ad614SDennis Dalessandro irq_set_affinity_hint(msix->msix.vector, &msix->mask); 392f48ad614SDennis Dalessandro 393f48ad614SDennis Dalessandro free_cpumask_var(diff); 394f48ad614SDennis Dalessandro return 0; 395f48ad614SDennis Dalessandro } 396f48ad614SDennis Dalessandro 397*584d9577STadeusz Struk int hfi1_get_irq_affinity(struct hfi1_devdata *dd, struct hfi1_msix_entry *msix) 398*584d9577STadeusz Struk { 399*584d9577STadeusz Struk int ret; 400*584d9577STadeusz Struk 401*584d9577STadeusz Struk mutex_lock(&node_affinity.lock); 402*584d9577STadeusz Struk ret = get_irq_affinity(dd, msix); 403*584d9577STadeusz Struk mutex_unlock(&node_affinity.lock); 404*584d9577STadeusz Struk return ret; 405*584d9577STadeusz Struk } 406*584d9577STadeusz Struk 407f48ad614SDennis Dalessandro void hfi1_put_irq_affinity(struct hfi1_devdata *dd, 408f48ad614SDennis Dalessandro struct hfi1_msix_entry *msix) 409f48ad614SDennis Dalessandro { 410f48ad614SDennis Dalessandro struct cpu_mask_set *set = NULL; 411f48ad614SDennis Dalessandro struct hfi1_ctxtdata *rcd; 4124197344bSDennis Dalessandro struct hfi1_affinity_node *entry; 4134197344bSDennis Dalessandro 414*584d9577STadeusz Struk mutex_lock(&node_affinity.lock); 4154197344bSDennis Dalessandro entry = node_affinity_lookup(dd->node); 416f48ad614SDennis Dalessandro 417f48ad614SDennis Dalessandro switch (msix->type) { 418f48ad614SDennis Dalessandro case IRQ_SDMA: 4194197344bSDennis Dalessandro set = &entry->def_intr; 420f48ad614SDennis Dalessandro break; 421d6373019SSebastian Sanchez case IRQ_GENERAL: 422b094a36fSSebastian Sanchez /* Don't do accounting for general contexts */ 423d6373019SSebastian Sanchez break; 424f48ad614SDennis Dalessandro case IRQ_RCVCTXT: 425f48ad614SDennis Dalessandro rcd = (struct hfi1_ctxtdata *)msix->arg; 426d6373019SSebastian Sanchez /* Don't do accounting for control contexts */ 427f48ad614SDennis Dalessandro if (rcd->ctxt != HFI1_CTRL_CTXT) 4284197344bSDennis Dalessandro set = &entry->rcv_intr; 429f48ad614SDennis Dalessandro break; 430f48ad614SDennis Dalessandro default: 431*584d9577STadeusz Struk mutex_unlock(&node_affinity.lock); 432f48ad614SDennis Dalessandro return; 433f48ad614SDennis Dalessandro } 434f48ad614SDennis Dalessandro 435f48ad614SDennis Dalessandro if (set) { 436f48ad614SDennis Dalessandro cpumask_andnot(&set->used, &set->used, &msix->mask); 437f48ad614SDennis Dalessandro if (cpumask_empty(&set->used) && set->gen) { 438f48ad614SDennis Dalessandro set->gen--; 439f48ad614SDennis Dalessandro cpumask_copy(&set->used, &set->mask); 440f48ad614SDennis Dalessandro } 441f48ad614SDennis Dalessandro } 442f48ad614SDennis Dalessandro 443f48ad614SDennis Dalessandro irq_set_affinity_hint(msix->msix.vector, NULL); 444f48ad614SDennis Dalessandro cpumask_clear(&msix->mask); 445*584d9577STadeusz Struk mutex_unlock(&node_affinity.lock); 446f48ad614SDennis Dalessandro } 447f48ad614SDennis Dalessandro 448b094a36fSSebastian Sanchez /* This should be called with node_affinity.lock held */ 449b094a36fSSebastian Sanchez static void find_hw_thread_mask(uint hw_thread_no, cpumask_var_t hw_thread_mask, 450b094a36fSSebastian Sanchez struct hfi1_affinity_node_list *affinity) 451f48ad614SDennis Dalessandro { 452b094a36fSSebastian Sanchez int possible, curr_cpu, i; 453b094a36fSSebastian Sanchez uint num_cores_per_socket = node_affinity.num_online_cpus / 454b094a36fSSebastian Sanchez affinity->num_core_siblings / 455b094a36fSSebastian Sanchez node_affinity.num_online_nodes; 456b094a36fSSebastian Sanchez 457b094a36fSSebastian Sanchez cpumask_copy(hw_thread_mask, &affinity->proc.mask); 458b094a36fSSebastian Sanchez if (affinity->num_core_siblings > 0) { 459b094a36fSSebastian Sanchez /* Removing other siblings not needed for now */ 460b094a36fSSebastian Sanchez possible = cpumask_weight(hw_thread_mask); 461b094a36fSSebastian Sanchez curr_cpu = cpumask_first(hw_thread_mask); 462b094a36fSSebastian Sanchez for (i = 0; 463b094a36fSSebastian Sanchez i < num_cores_per_socket * node_affinity.num_online_nodes; 464b094a36fSSebastian Sanchez i++) 465b094a36fSSebastian Sanchez curr_cpu = cpumask_next(curr_cpu, hw_thread_mask); 466b094a36fSSebastian Sanchez 467b094a36fSSebastian Sanchez for (; i < possible; i++) { 468b094a36fSSebastian Sanchez cpumask_clear_cpu(curr_cpu, hw_thread_mask); 469b094a36fSSebastian Sanchez curr_cpu = cpumask_next(curr_cpu, hw_thread_mask); 470b094a36fSSebastian Sanchez } 471b094a36fSSebastian Sanchez 472b094a36fSSebastian Sanchez /* Identifying correct HW threads within physical cores */ 473b094a36fSSebastian Sanchez cpumask_shift_left(hw_thread_mask, hw_thread_mask, 474b094a36fSSebastian Sanchez num_cores_per_socket * 475b094a36fSSebastian Sanchez node_affinity.num_online_nodes * 476b094a36fSSebastian Sanchez hw_thread_no); 477b094a36fSSebastian Sanchez } 478b094a36fSSebastian Sanchez } 479b094a36fSSebastian Sanchez 480b094a36fSSebastian Sanchez int hfi1_get_proc_affinity(int node) 481b094a36fSSebastian Sanchez { 482b094a36fSSebastian Sanchez int cpu = -1, ret, i; 4834197344bSDennis Dalessandro struct hfi1_affinity_node *entry; 484b094a36fSSebastian Sanchez cpumask_var_t diff, hw_thread_mask, available_mask, intrs_mask; 485f48ad614SDennis Dalessandro const struct cpumask *node_mask, 486f48ad614SDennis Dalessandro *proc_mask = tsk_cpus_allowed(current); 487b094a36fSSebastian Sanchez struct hfi1_affinity_node_list *affinity = &node_affinity; 488b094a36fSSebastian Sanchez struct cpu_mask_set *set = &affinity->proc; 489f48ad614SDennis Dalessandro 490f48ad614SDennis Dalessandro /* 491f48ad614SDennis Dalessandro * check whether process/context affinity has already 492f48ad614SDennis Dalessandro * been set 493f48ad614SDennis Dalessandro */ 494f48ad614SDennis Dalessandro if (cpumask_weight(proc_mask) == 1) { 495f242d93aSLeon Romanovsky hfi1_cdbg(PROC, "PID %u %s affinity set to CPU %*pbl", 496f242d93aSLeon Romanovsky current->pid, current->comm, 497f242d93aSLeon Romanovsky cpumask_pr_args(proc_mask)); 498f48ad614SDennis Dalessandro /* 499f48ad614SDennis Dalessandro * Mark the pre-set CPU as used. This is atomic so we don't 500f48ad614SDennis Dalessandro * need the lock 501f48ad614SDennis Dalessandro */ 502f48ad614SDennis Dalessandro cpu = cpumask_first(proc_mask); 503f48ad614SDennis Dalessandro cpumask_set_cpu(cpu, &set->used); 504f48ad614SDennis Dalessandro goto done; 505f48ad614SDennis Dalessandro } else if (cpumask_weight(proc_mask) < cpumask_weight(&set->mask)) { 506f242d93aSLeon Romanovsky hfi1_cdbg(PROC, "PID %u %s affinity set to CPU set(s) %*pbl", 507f242d93aSLeon Romanovsky current->pid, current->comm, 508f242d93aSLeon Romanovsky cpumask_pr_args(proc_mask)); 509f48ad614SDennis Dalessandro goto done; 510f48ad614SDennis Dalessandro } 511f48ad614SDennis Dalessandro 512f48ad614SDennis Dalessandro /* 513f48ad614SDennis Dalessandro * The process does not have a preset CPU affinity so find one to 514b094a36fSSebastian Sanchez * recommend using the following algorithm: 515b094a36fSSebastian Sanchez * 516b094a36fSSebastian Sanchez * For each user process that is opening a context on HFI Y: 517b094a36fSSebastian Sanchez * a) If all cores are filled, reinitialize the bitmask 518b094a36fSSebastian Sanchez * b) Fill real cores first, then HT cores (First set of HT 519b094a36fSSebastian Sanchez * cores on all physical cores, then second set of HT core, 520b094a36fSSebastian Sanchez * and, so on) in the following order: 521b094a36fSSebastian Sanchez * 522b094a36fSSebastian Sanchez * 1. Same NUMA node as HFI Y and not running an IRQ 523b094a36fSSebastian Sanchez * handler 524b094a36fSSebastian Sanchez * 2. Same NUMA node as HFI Y and running an IRQ handler 525b094a36fSSebastian Sanchez * 3. Different NUMA node to HFI Y and not running an IRQ 526b094a36fSSebastian Sanchez * handler 527b094a36fSSebastian Sanchez * 4. Different NUMA node to HFI Y and running an IRQ 528b094a36fSSebastian Sanchez * handler 529b094a36fSSebastian Sanchez * c) Mark core as filled in the bitmask. As user processes are 530b094a36fSSebastian Sanchez * done, clear cores from the bitmask. 531f48ad614SDennis Dalessandro */ 532f48ad614SDennis Dalessandro 533f48ad614SDennis Dalessandro ret = zalloc_cpumask_var(&diff, GFP_KERNEL); 534f48ad614SDennis Dalessandro if (!ret) 535f48ad614SDennis Dalessandro goto done; 536b094a36fSSebastian Sanchez ret = zalloc_cpumask_var(&hw_thread_mask, GFP_KERNEL); 537f48ad614SDennis Dalessandro if (!ret) 538f48ad614SDennis Dalessandro goto free_diff; 539b094a36fSSebastian Sanchez ret = zalloc_cpumask_var(&available_mask, GFP_KERNEL); 540f48ad614SDennis Dalessandro if (!ret) 541b094a36fSSebastian Sanchez goto free_hw_thread_mask; 542b094a36fSSebastian Sanchez ret = zalloc_cpumask_var(&intrs_mask, GFP_KERNEL); 543b094a36fSSebastian Sanchez if (!ret) 544b094a36fSSebastian Sanchez goto free_available_mask; 545f48ad614SDennis Dalessandro 546*584d9577STadeusz Struk mutex_lock(&affinity->lock); 547f48ad614SDennis Dalessandro /* 548b094a36fSSebastian Sanchez * If we've used all available HW threads, clear the mask and start 549f48ad614SDennis Dalessandro * overloading. 550f48ad614SDennis Dalessandro */ 551f48ad614SDennis Dalessandro if (cpumask_equal(&set->mask, &set->used)) { 552f48ad614SDennis Dalessandro set->gen++; 553f48ad614SDennis Dalessandro cpumask_clear(&set->used); 554f48ad614SDennis Dalessandro } 555f48ad614SDennis Dalessandro 556d6373019SSebastian Sanchez /* 557d6373019SSebastian Sanchez * If NUMA node has CPUs used by interrupt handlers, include them in the 558d6373019SSebastian Sanchez * interrupt handler mask. 559d6373019SSebastian Sanchez */ 560d6373019SSebastian Sanchez entry = node_affinity_lookup(node); 561d6373019SSebastian Sanchez if (entry) { 562b094a36fSSebastian Sanchez cpumask_copy(intrs_mask, (entry->def_intr.gen ? 5634197344bSDennis Dalessandro &entry->def_intr.mask : 5644197344bSDennis Dalessandro &entry->def_intr.used)); 565b094a36fSSebastian Sanchez cpumask_or(intrs_mask, intrs_mask, (entry->rcv_intr.gen ? 5664197344bSDennis Dalessandro &entry->rcv_intr.mask : 5674197344bSDennis Dalessandro &entry->rcv_intr.used)); 568b094a36fSSebastian Sanchez cpumask_or(intrs_mask, intrs_mask, &entry->general_intr_mask); 569d6373019SSebastian Sanchez } 570f242d93aSLeon Romanovsky hfi1_cdbg(PROC, "CPUs used by interrupts: %*pbl", 571b094a36fSSebastian Sanchez cpumask_pr_args(intrs_mask)); 572b094a36fSSebastian Sanchez 573b094a36fSSebastian Sanchez cpumask_copy(hw_thread_mask, &set->mask); 574f48ad614SDennis Dalessandro 575f48ad614SDennis Dalessandro /* 576b094a36fSSebastian Sanchez * If HT cores are enabled, identify which HW threads within the 577b094a36fSSebastian Sanchez * physical cores should be used. 578f48ad614SDennis Dalessandro */ 579b094a36fSSebastian Sanchez if (affinity->num_core_siblings > 0) { 580b094a36fSSebastian Sanchez for (i = 0; i < affinity->num_core_siblings; i++) { 581b094a36fSSebastian Sanchez find_hw_thread_mask(i, hw_thread_mask, affinity); 582b094a36fSSebastian Sanchez 583b094a36fSSebastian Sanchez /* 584b094a36fSSebastian Sanchez * If there's at least one available core for this HW 585b094a36fSSebastian Sanchez * thread number, stop looking for a core. 586b094a36fSSebastian Sanchez * 587b094a36fSSebastian Sanchez * diff will always be not empty at least once in this 588b094a36fSSebastian Sanchez * loop as the used mask gets reset when 589b094a36fSSebastian Sanchez * (set->mask == set->used) before this loop. 590b094a36fSSebastian Sanchez */ 591b094a36fSSebastian Sanchez cpumask_andnot(diff, hw_thread_mask, &set->used); 592b094a36fSSebastian Sanchez if (!cpumask_empty(diff)) 593b094a36fSSebastian Sanchez break; 594b094a36fSSebastian Sanchez } 595b094a36fSSebastian Sanchez } 596b094a36fSSebastian Sanchez hfi1_cdbg(PROC, "Same available HW thread on all physical CPUs: %*pbl", 597b094a36fSSebastian Sanchez cpumask_pr_args(hw_thread_mask)); 598b094a36fSSebastian Sanchez 599f48ad614SDennis Dalessandro node_mask = cpumask_of_node(node); 600b094a36fSSebastian Sanchez hfi1_cdbg(PROC, "Device on NUMA %u, CPUs %*pbl", node, 601f242d93aSLeon Romanovsky cpumask_pr_args(node_mask)); 602f48ad614SDennis Dalessandro 603b094a36fSSebastian Sanchez /* Get cpumask of available CPUs on preferred NUMA */ 604b094a36fSSebastian Sanchez cpumask_and(available_mask, hw_thread_mask, node_mask); 605b094a36fSSebastian Sanchez cpumask_andnot(available_mask, available_mask, &set->used); 606b094a36fSSebastian Sanchez hfi1_cdbg(PROC, "Available CPUs on NUMA %u: %*pbl", node, 607b094a36fSSebastian Sanchez cpumask_pr_args(available_mask)); 608f48ad614SDennis Dalessandro 609b094a36fSSebastian Sanchez /* 610b094a36fSSebastian Sanchez * At first, we don't want to place processes on the same 611b094a36fSSebastian Sanchez * CPUs as interrupt handlers. Then, CPUs running interrupt 612b094a36fSSebastian Sanchez * handlers are used. 613b094a36fSSebastian Sanchez * 614b094a36fSSebastian Sanchez * 1) If diff is not empty, then there are CPUs not running 615b094a36fSSebastian Sanchez * non-interrupt handlers available, so diff gets copied 616b094a36fSSebastian Sanchez * over to available_mask. 617b094a36fSSebastian Sanchez * 2) If diff is empty, then all CPUs not running interrupt 618b094a36fSSebastian Sanchez * handlers are taken, so available_mask contains all 619b094a36fSSebastian Sanchez * available CPUs running interrupt handlers. 620b094a36fSSebastian Sanchez * 3) If available_mask is empty, then all CPUs on the 621b094a36fSSebastian Sanchez * preferred NUMA node are taken, so other NUMA nodes are 622b094a36fSSebastian Sanchez * used for process assignments using the same method as 623b094a36fSSebastian Sanchez * the preferred NUMA node. 624b094a36fSSebastian Sanchez */ 625b094a36fSSebastian Sanchez cpumask_andnot(diff, available_mask, intrs_mask); 626b094a36fSSebastian Sanchez if (!cpumask_empty(diff)) 627b094a36fSSebastian Sanchez cpumask_copy(available_mask, diff); 628b094a36fSSebastian Sanchez 629b094a36fSSebastian Sanchez /* If we don't have CPUs on the preferred node, use other NUMA nodes */ 630b094a36fSSebastian Sanchez if (cpumask_empty(available_mask)) { 631b094a36fSSebastian Sanchez cpumask_andnot(available_mask, hw_thread_mask, &set->used); 632b094a36fSSebastian Sanchez /* Excluding preferred NUMA cores */ 633b094a36fSSebastian Sanchez cpumask_andnot(available_mask, available_mask, node_mask); 634b094a36fSSebastian Sanchez hfi1_cdbg(PROC, 635b094a36fSSebastian Sanchez "Preferred NUMA node cores are taken, cores available in other NUMA nodes: %*pbl", 636b094a36fSSebastian Sanchez cpumask_pr_args(available_mask)); 637f48ad614SDennis Dalessandro 638f48ad614SDennis Dalessandro /* 639f48ad614SDennis Dalessandro * At first, we don't want to place processes on the same 640f48ad614SDennis Dalessandro * CPUs as interrupt handlers. 641f48ad614SDennis Dalessandro */ 642b094a36fSSebastian Sanchez cpumask_andnot(diff, available_mask, intrs_mask); 643f48ad614SDennis Dalessandro if (!cpumask_empty(diff)) 644b094a36fSSebastian Sanchez cpumask_copy(available_mask, diff); 645f48ad614SDennis Dalessandro } 646b094a36fSSebastian Sanchez hfi1_cdbg(PROC, "Possible CPUs for process: %*pbl", 647b094a36fSSebastian Sanchez cpumask_pr_args(available_mask)); 648f48ad614SDennis Dalessandro 649b094a36fSSebastian Sanchez cpu = cpumask_first(available_mask); 650f48ad614SDennis Dalessandro if (cpu >= nr_cpu_ids) /* empty */ 651f48ad614SDennis Dalessandro cpu = -1; 652f48ad614SDennis Dalessandro else 653f48ad614SDennis Dalessandro cpumask_set_cpu(cpu, &set->used); 654*584d9577STadeusz Struk 655*584d9577STadeusz Struk mutex_unlock(&affinity->lock); 656b094a36fSSebastian Sanchez hfi1_cdbg(PROC, "Process assigned to CPU %d", cpu); 657f48ad614SDennis Dalessandro 658b094a36fSSebastian Sanchez free_cpumask_var(intrs_mask); 659b094a36fSSebastian Sanchez free_available_mask: 660b094a36fSSebastian Sanchez free_cpumask_var(available_mask); 661b094a36fSSebastian Sanchez free_hw_thread_mask: 662b094a36fSSebastian Sanchez free_cpumask_var(hw_thread_mask); 663f48ad614SDennis Dalessandro free_diff: 664f48ad614SDennis Dalessandro free_cpumask_var(diff); 665f48ad614SDennis Dalessandro done: 666f48ad614SDennis Dalessandro return cpu; 667f48ad614SDennis Dalessandro } 668f48ad614SDennis Dalessandro 669b094a36fSSebastian Sanchez void hfi1_put_proc_affinity(int cpu) 670f48ad614SDennis Dalessandro { 671b094a36fSSebastian Sanchez struct hfi1_affinity_node_list *affinity = &node_affinity; 672b094a36fSSebastian Sanchez struct cpu_mask_set *set = &affinity->proc; 673f48ad614SDennis Dalessandro 674f48ad614SDennis Dalessandro if (cpu < 0) 675f48ad614SDennis Dalessandro return; 676*584d9577STadeusz Struk 677*584d9577STadeusz Struk mutex_lock(&affinity->lock); 678f48ad614SDennis Dalessandro cpumask_clear_cpu(cpu, &set->used); 679b094a36fSSebastian Sanchez hfi1_cdbg(PROC, "Returning CPU %d for future process assignment", cpu); 680f48ad614SDennis Dalessandro if (cpumask_empty(&set->used) && set->gen) { 681f48ad614SDennis Dalessandro set->gen--; 682f48ad614SDennis Dalessandro cpumask_copy(&set->used, &set->mask); 683f48ad614SDennis Dalessandro } 684*584d9577STadeusz Struk mutex_unlock(&affinity->lock); 685f48ad614SDennis Dalessandro } 686b14db1f0STadeusz Struk 687b14db1f0STadeusz Struk int hfi1_set_sdma_affinity(struct hfi1_devdata *dd, const char *buf, 688b14db1f0STadeusz Struk size_t count) 689b14db1f0STadeusz Struk { 690b14db1f0STadeusz Struk struct hfi1_affinity_node *entry; 6918303f683STadeusz Struk cpumask_var_t mask; 692b14db1f0STadeusz Struk int ret, i; 693b14db1f0STadeusz Struk 694*584d9577STadeusz Struk mutex_lock(&node_affinity.lock); 695b14db1f0STadeusz Struk entry = node_affinity_lookup(dd->node); 696b14db1f0STadeusz Struk 697*584d9577STadeusz Struk if (!entry) { 698*584d9577STadeusz Struk ret = -EINVAL; 699*584d9577STadeusz Struk goto unlock; 700*584d9577STadeusz Struk } 701b14db1f0STadeusz Struk 7028303f683STadeusz Struk ret = zalloc_cpumask_var(&mask, GFP_KERNEL); 703*584d9577STadeusz Struk if (!ret) { 704*584d9577STadeusz Struk ret = -ENOMEM; 705*584d9577STadeusz Struk goto unlock; 706*584d9577STadeusz Struk } 707b14db1f0STadeusz Struk 7088303f683STadeusz Struk ret = cpulist_parse(buf, mask); 7098303f683STadeusz Struk if (ret) 7108303f683STadeusz Struk goto out; 7118303f683STadeusz Struk 7128303f683STadeusz Struk if (!cpumask_subset(mask, cpu_online_mask) || cpumask_empty(mask)) { 713b14db1f0STadeusz Struk dd_dev_warn(dd, "Invalid CPU mask\n"); 7148303f683STadeusz Struk ret = -EINVAL; 7158303f683STadeusz Struk goto out; 716b14db1f0STadeusz Struk } 717b14db1f0STadeusz Struk 718b14db1f0STadeusz Struk /* reset the SDMA interrupt affinity details */ 719b14db1f0STadeusz Struk init_cpu_mask_set(&entry->def_intr); 7208303f683STadeusz Struk cpumask_copy(&entry->def_intr.mask, mask); 721*584d9577STadeusz Struk 722*584d9577STadeusz Struk /* Reassign the affinity for each SDMA interrupt. */ 723b14db1f0STadeusz Struk for (i = 0; i < dd->num_msix_entries; i++) { 724b14db1f0STadeusz Struk struct hfi1_msix_entry *msix; 725b14db1f0STadeusz Struk 726b14db1f0STadeusz Struk msix = &dd->msix_entries[i]; 727b14db1f0STadeusz Struk if (msix->type != IRQ_SDMA) 728b14db1f0STadeusz Struk continue; 729b14db1f0STadeusz Struk 730*584d9577STadeusz Struk ret = get_irq_affinity(dd, msix); 731b14db1f0STadeusz Struk 732b14db1f0STadeusz Struk if (ret) 733b14db1f0STadeusz Struk break; 734b14db1f0STadeusz Struk } 7358303f683STadeusz Struk out: 7368303f683STadeusz Struk free_cpumask_var(mask); 737*584d9577STadeusz Struk unlock: 738*584d9577STadeusz Struk mutex_unlock(&node_affinity.lock); 739b14db1f0STadeusz Struk return ret ? ret : strnlen(buf, PAGE_SIZE); 740b14db1f0STadeusz Struk } 741b14db1f0STadeusz Struk 742b14db1f0STadeusz Struk int hfi1_get_sdma_affinity(struct hfi1_devdata *dd, char *buf) 743b14db1f0STadeusz Struk { 744b14db1f0STadeusz Struk struct hfi1_affinity_node *entry; 745b14db1f0STadeusz Struk 746*584d9577STadeusz Struk mutex_lock(&node_affinity.lock); 747b14db1f0STadeusz Struk entry = node_affinity_lookup(dd->node); 748b14db1f0STadeusz Struk 749*584d9577STadeusz Struk if (!entry) { 750*584d9577STadeusz Struk mutex_unlock(&node_affinity.lock); 751b14db1f0STadeusz Struk return -EINVAL; 752*584d9577STadeusz Struk } 753b14db1f0STadeusz Struk 754b14db1f0STadeusz Struk cpumap_print_to_pagebuf(true, buf, &entry->def_intr.mask); 755*584d9577STadeusz Struk mutex_unlock(&node_affinity.lock); 756b14db1f0STadeusz Struk return strnlen(buf, PAGE_SIZE); 757b14db1f0STadeusz Struk } 758