18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause) 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Copyright(c) 2018 - 2020 Intel Corporation. 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * This file is provided under a dual BSD/GPLv2 license. When using or 68c2ecf20Sopenharmony_ci * redistributing this file, you may do so under either license. 78c2ecf20Sopenharmony_ci * 88c2ecf20Sopenharmony_ci * GPL LICENSE SUMMARY 98c2ecf20Sopenharmony_ci * 108c2ecf20Sopenharmony_ci * This program is free software; you can redistribute it and/or modify 118c2ecf20Sopenharmony_ci * it under the terms of version 2 of the GNU General Public License as 128c2ecf20Sopenharmony_ci * published by the Free Software Foundation. 138c2ecf20Sopenharmony_ci * 148c2ecf20Sopenharmony_ci * This program is distributed in the hope that it will be useful, but 158c2ecf20Sopenharmony_ci * WITHOUT ANY WARRANTY; without even the implied warranty of 168c2ecf20Sopenharmony_ci * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 178c2ecf20Sopenharmony_ci * General Public License for more details. 188c2ecf20Sopenharmony_ci * 198c2ecf20Sopenharmony_ci * BSD LICENSE 208c2ecf20Sopenharmony_ci * 218c2ecf20Sopenharmony_ci * Redistribution and use in source and binary forms, with or without 228c2ecf20Sopenharmony_ci * modification, are permitted provided that the following conditions 238c2ecf20Sopenharmony_ci * are met: 248c2ecf20Sopenharmony_ci * 258c2ecf20Sopenharmony_ci * - Redistributions of source code must retain the above copyright 268c2ecf20Sopenharmony_ci * notice, this list of conditions and the following disclaimer. 278c2ecf20Sopenharmony_ci * - Redistributions in binary form must reproduce the above copyright 288c2ecf20Sopenharmony_ci * notice, this list of conditions and the following disclaimer in 298c2ecf20Sopenharmony_ci * the documentation and/or other materials provided with the 308c2ecf20Sopenharmony_ci * distribution. 318c2ecf20Sopenharmony_ci * - Neither the name of Intel Corporation nor the names of its 328c2ecf20Sopenharmony_ci * contributors may be used to endorse or promote products derived 338c2ecf20Sopenharmony_ci * from this software without specific prior written permission. 348c2ecf20Sopenharmony_ci * 358c2ecf20Sopenharmony_ci * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 368c2ecf20Sopenharmony_ci * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 378c2ecf20Sopenharmony_ci * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 388c2ecf20Sopenharmony_ci * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 398c2ecf20Sopenharmony_ci * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 408c2ecf20Sopenharmony_ci * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 418c2ecf20Sopenharmony_ci * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 428c2ecf20Sopenharmony_ci * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 438c2ecf20Sopenharmony_ci * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 448c2ecf20Sopenharmony_ci * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 458c2ecf20Sopenharmony_ci * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 468c2ecf20Sopenharmony_ci * 478c2ecf20Sopenharmony_ci */ 488c2ecf20Sopenharmony_ci 498c2ecf20Sopenharmony_ci#include "hfi.h" 508c2ecf20Sopenharmony_ci#include "affinity.h" 518c2ecf20Sopenharmony_ci#include "sdma.h" 528c2ecf20Sopenharmony_ci#include "netdev.h" 538c2ecf20Sopenharmony_ci 548c2ecf20Sopenharmony_ci/** 558c2ecf20Sopenharmony_ci * msix_initialize() - Calculate, request and configure MSIx IRQs 568c2ecf20Sopenharmony_ci * @dd: valid hfi1 devdata 578c2ecf20Sopenharmony_ci * 588c2ecf20Sopenharmony_ci */ 598c2ecf20Sopenharmony_ciint msix_initialize(struct hfi1_devdata *dd) 608c2ecf20Sopenharmony_ci{ 618c2ecf20Sopenharmony_ci u32 total; 628c2ecf20Sopenharmony_ci int ret; 638c2ecf20Sopenharmony_ci struct hfi1_msix_entry *entries; 648c2ecf20Sopenharmony_ci 658c2ecf20Sopenharmony_ci /* 668c2ecf20Sopenharmony_ci * MSIx interrupt count: 678c2ecf20Sopenharmony_ci * one for the general, "slow path" interrupt 688c2ecf20Sopenharmony_ci * one per used SDMA engine 698c2ecf20Sopenharmony_ci * one per kernel receive context 708c2ecf20Sopenharmony_ci * one for each VNIC context 718c2ecf20Sopenharmony_ci * ...any new IRQs should be added here. 728c2ecf20Sopenharmony_ci */ 738c2ecf20Sopenharmony_ci total = 1 + dd->num_sdma + dd->n_krcv_queues + dd->num_netdev_contexts; 748c2ecf20Sopenharmony_ci 758c2ecf20Sopenharmony_ci if (total >= CCE_NUM_MSIX_VECTORS) 768c2ecf20Sopenharmony_ci return -EINVAL; 778c2ecf20Sopenharmony_ci 788c2ecf20Sopenharmony_ci ret = pci_alloc_irq_vectors(dd->pcidev, total, total, PCI_IRQ_MSIX); 798c2ecf20Sopenharmony_ci if (ret < 0) { 808c2ecf20Sopenharmony_ci dd_dev_err(dd, "pci_alloc_irq_vectors() failed: %d\n", ret); 818c2ecf20Sopenharmony_ci return ret; 828c2ecf20Sopenharmony_ci } 838c2ecf20Sopenharmony_ci 848c2ecf20Sopenharmony_ci entries = kcalloc(total, sizeof(*dd->msix_info.msix_entries), 858c2ecf20Sopenharmony_ci GFP_KERNEL); 868c2ecf20Sopenharmony_ci if (!entries) { 878c2ecf20Sopenharmony_ci pci_free_irq_vectors(dd->pcidev); 888c2ecf20Sopenharmony_ci return -ENOMEM; 898c2ecf20Sopenharmony_ci } 908c2ecf20Sopenharmony_ci 918c2ecf20Sopenharmony_ci dd->msix_info.msix_entries = entries; 928c2ecf20Sopenharmony_ci spin_lock_init(&dd->msix_info.msix_lock); 938c2ecf20Sopenharmony_ci bitmap_zero(dd->msix_info.in_use_msix, total); 948c2ecf20Sopenharmony_ci dd->msix_info.max_requested = total; 958c2ecf20Sopenharmony_ci dd_dev_info(dd, "%u MSI-X interrupts allocated\n", total); 968c2ecf20Sopenharmony_ci 978c2ecf20Sopenharmony_ci return 0; 988c2ecf20Sopenharmony_ci} 998c2ecf20Sopenharmony_ci 1008c2ecf20Sopenharmony_ci/** 1018c2ecf20Sopenharmony_ci * msix_request_irq() - Allocate a free MSIx IRQ 1028c2ecf20Sopenharmony_ci * @dd: valid devdata 1038c2ecf20Sopenharmony_ci * @arg: context information for the IRQ 1048c2ecf20Sopenharmony_ci * @handler: IRQ handler 1058c2ecf20Sopenharmony_ci * @thread: IRQ thread handler (could be NULL) 1068c2ecf20Sopenharmony_ci * @idx: zero base idx if multiple devices are needed 1078c2ecf20Sopenharmony_ci * @type: affinty IRQ type 1088c2ecf20Sopenharmony_ci * 1098c2ecf20Sopenharmony_ci * Allocated an MSIx vector if available, and then create the appropriate 1108c2ecf20Sopenharmony_ci * meta data needed to keep track of the pci IRQ request. 1118c2ecf20Sopenharmony_ci * 1128c2ecf20Sopenharmony_ci * Return: 1138c2ecf20Sopenharmony_ci * < 0 Error 1148c2ecf20Sopenharmony_ci * >= 0 MSIx vector 1158c2ecf20Sopenharmony_ci * 1168c2ecf20Sopenharmony_ci */ 1178c2ecf20Sopenharmony_cistatic int msix_request_irq(struct hfi1_devdata *dd, void *arg, 1188c2ecf20Sopenharmony_ci irq_handler_t handler, irq_handler_t thread, 1198c2ecf20Sopenharmony_ci enum irq_type type, const char *name) 1208c2ecf20Sopenharmony_ci{ 1218c2ecf20Sopenharmony_ci unsigned long nr; 1228c2ecf20Sopenharmony_ci int irq; 1238c2ecf20Sopenharmony_ci int ret; 1248c2ecf20Sopenharmony_ci struct hfi1_msix_entry *me; 1258c2ecf20Sopenharmony_ci 1268c2ecf20Sopenharmony_ci /* Allocate an MSIx vector */ 1278c2ecf20Sopenharmony_ci spin_lock(&dd->msix_info.msix_lock); 1288c2ecf20Sopenharmony_ci nr = find_first_zero_bit(dd->msix_info.in_use_msix, 1298c2ecf20Sopenharmony_ci dd->msix_info.max_requested); 1308c2ecf20Sopenharmony_ci if (nr < dd->msix_info.max_requested) 1318c2ecf20Sopenharmony_ci __set_bit(nr, dd->msix_info.in_use_msix); 1328c2ecf20Sopenharmony_ci spin_unlock(&dd->msix_info.msix_lock); 1338c2ecf20Sopenharmony_ci 1348c2ecf20Sopenharmony_ci if (nr == dd->msix_info.max_requested) 1358c2ecf20Sopenharmony_ci return -ENOSPC; 1368c2ecf20Sopenharmony_ci 1378c2ecf20Sopenharmony_ci if (type < IRQ_SDMA || type >= IRQ_OTHER) 1388c2ecf20Sopenharmony_ci return -EINVAL; 1398c2ecf20Sopenharmony_ci 1408c2ecf20Sopenharmony_ci irq = pci_irq_vector(dd->pcidev, nr); 1418c2ecf20Sopenharmony_ci ret = pci_request_irq(dd->pcidev, nr, handler, thread, arg, name); 1428c2ecf20Sopenharmony_ci if (ret) { 1438c2ecf20Sopenharmony_ci dd_dev_err(dd, 1448c2ecf20Sopenharmony_ci "%s: request for IRQ %d failed, MSIx %lx, err %d\n", 1458c2ecf20Sopenharmony_ci name, irq, nr, ret); 1468c2ecf20Sopenharmony_ci spin_lock(&dd->msix_info.msix_lock); 1478c2ecf20Sopenharmony_ci __clear_bit(nr, dd->msix_info.in_use_msix); 1488c2ecf20Sopenharmony_ci spin_unlock(&dd->msix_info.msix_lock); 1498c2ecf20Sopenharmony_ci return ret; 1508c2ecf20Sopenharmony_ci } 1518c2ecf20Sopenharmony_ci 1528c2ecf20Sopenharmony_ci /* 1538c2ecf20Sopenharmony_ci * assign arg after pci_request_irq call, so it will be 1548c2ecf20Sopenharmony_ci * cleaned up 1558c2ecf20Sopenharmony_ci */ 1568c2ecf20Sopenharmony_ci me = &dd->msix_info.msix_entries[nr]; 1578c2ecf20Sopenharmony_ci me->irq = irq; 1588c2ecf20Sopenharmony_ci me->arg = arg; 1598c2ecf20Sopenharmony_ci me->type = type; 1608c2ecf20Sopenharmony_ci 1618c2ecf20Sopenharmony_ci /* This is a request, so a failure is not fatal */ 1628c2ecf20Sopenharmony_ci ret = hfi1_get_irq_affinity(dd, me); 1638c2ecf20Sopenharmony_ci if (ret) 1648c2ecf20Sopenharmony_ci dd_dev_err(dd, "%s: unable to pin IRQ %d\n", name, ret); 1658c2ecf20Sopenharmony_ci 1668c2ecf20Sopenharmony_ci return nr; 1678c2ecf20Sopenharmony_ci} 1688c2ecf20Sopenharmony_ci 1698c2ecf20Sopenharmony_cistatic int msix_request_rcd_irq_common(struct hfi1_ctxtdata *rcd, 1708c2ecf20Sopenharmony_ci irq_handler_t handler, 1718c2ecf20Sopenharmony_ci irq_handler_t thread, 1728c2ecf20Sopenharmony_ci const char *name) 1738c2ecf20Sopenharmony_ci{ 1748c2ecf20Sopenharmony_ci int nr = msix_request_irq(rcd->dd, rcd, handler, thread, 1758c2ecf20Sopenharmony_ci rcd->is_vnic ? IRQ_NETDEVCTXT : IRQ_RCVCTXT, 1768c2ecf20Sopenharmony_ci name); 1778c2ecf20Sopenharmony_ci if (nr < 0) 1788c2ecf20Sopenharmony_ci return nr; 1798c2ecf20Sopenharmony_ci 1808c2ecf20Sopenharmony_ci /* 1818c2ecf20Sopenharmony_ci * Set the interrupt register and mask for this 1828c2ecf20Sopenharmony_ci * context's interrupt. 1838c2ecf20Sopenharmony_ci */ 1848c2ecf20Sopenharmony_ci rcd->ireg = (IS_RCVAVAIL_START + rcd->ctxt) / 64; 1858c2ecf20Sopenharmony_ci rcd->imask = ((u64)1) << ((IS_RCVAVAIL_START + rcd->ctxt) % 64); 1868c2ecf20Sopenharmony_ci rcd->msix_intr = nr; 1878c2ecf20Sopenharmony_ci remap_intr(rcd->dd, IS_RCVAVAIL_START + rcd->ctxt, nr); 1888c2ecf20Sopenharmony_ci 1898c2ecf20Sopenharmony_ci return 0; 1908c2ecf20Sopenharmony_ci} 1918c2ecf20Sopenharmony_ci 1928c2ecf20Sopenharmony_ci/** 1938c2ecf20Sopenharmony_ci * msix_request_rcd_irq() - Helper function for RCVAVAIL IRQs 1948c2ecf20Sopenharmony_ci * @rcd: valid rcd context 1958c2ecf20Sopenharmony_ci * 1968c2ecf20Sopenharmony_ci */ 1978c2ecf20Sopenharmony_ciint msix_request_rcd_irq(struct hfi1_ctxtdata *rcd) 1988c2ecf20Sopenharmony_ci{ 1998c2ecf20Sopenharmony_ci char name[MAX_NAME_SIZE]; 2008c2ecf20Sopenharmony_ci 2018c2ecf20Sopenharmony_ci snprintf(name, sizeof(name), DRIVER_NAME "_%d kctxt%d", 2028c2ecf20Sopenharmony_ci rcd->dd->unit, rcd->ctxt); 2038c2ecf20Sopenharmony_ci 2048c2ecf20Sopenharmony_ci return msix_request_rcd_irq_common(rcd, receive_context_interrupt, 2058c2ecf20Sopenharmony_ci receive_context_thread, name); 2068c2ecf20Sopenharmony_ci} 2078c2ecf20Sopenharmony_ci 2088c2ecf20Sopenharmony_ci/** 2098c2ecf20Sopenharmony_ci * msix_request_rcd_irq() - Helper function for RCVAVAIL IRQs 2108c2ecf20Sopenharmony_ci * for netdev context 2118c2ecf20Sopenharmony_ci * @rcd: valid netdev contexti 2128c2ecf20Sopenharmony_ci */ 2138c2ecf20Sopenharmony_ciint msix_netdev_request_rcd_irq(struct hfi1_ctxtdata *rcd) 2148c2ecf20Sopenharmony_ci{ 2158c2ecf20Sopenharmony_ci char name[MAX_NAME_SIZE]; 2168c2ecf20Sopenharmony_ci 2178c2ecf20Sopenharmony_ci snprintf(name, sizeof(name), DRIVER_NAME "_%d nd kctxt%d", 2188c2ecf20Sopenharmony_ci rcd->dd->unit, rcd->ctxt); 2198c2ecf20Sopenharmony_ci return msix_request_rcd_irq_common(rcd, receive_context_interrupt_napi, 2208c2ecf20Sopenharmony_ci NULL, name); 2218c2ecf20Sopenharmony_ci} 2228c2ecf20Sopenharmony_ci 2238c2ecf20Sopenharmony_ci/** 2248c2ecf20Sopenharmony_ci * msix_request_smda_ira() - Helper for getting SDMA IRQ resources 2258c2ecf20Sopenharmony_ci * @sde: valid sdma engine 2268c2ecf20Sopenharmony_ci * 2278c2ecf20Sopenharmony_ci */ 2288c2ecf20Sopenharmony_ciint msix_request_sdma_irq(struct sdma_engine *sde) 2298c2ecf20Sopenharmony_ci{ 2308c2ecf20Sopenharmony_ci int nr; 2318c2ecf20Sopenharmony_ci char name[MAX_NAME_SIZE]; 2328c2ecf20Sopenharmony_ci 2338c2ecf20Sopenharmony_ci snprintf(name, sizeof(name), DRIVER_NAME "_%d sdma%d", 2348c2ecf20Sopenharmony_ci sde->dd->unit, sde->this_idx); 2358c2ecf20Sopenharmony_ci nr = msix_request_irq(sde->dd, sde, sdma_interrupt, NULL, 2368c2ecf20Sopenharmony_ci IRQ_SDMA, name); 2378c2ecf20Sopenharmony_ci if (nr < 0) 2388c2ecf20Sopenharmony_ci return nr; 2398c2ecf20Sopenharmony_ci sde->msix_intr = nr; 2408c2ecf20Sopenharmony_ci remap_sdma_interrupts(sde->dd, sde->this_idx, nr); 2418c2ecf20Sopenharmony_ci 2428c2ecf20Sopenharmony_ci return 0; 2438c2ecf20Sopenharmony_ci} 2448c2ecf20Sopenharmony_ci 2458c2ecf20Sopenharmony_ci/** 2468c2ecf20Sopenharmony_ci * msix_request_general_irq(void) - Helper for getting general IRQ 2478c2ecf20Sopenharmony_ci * resources 2488c2ecf20Sopenharmony_ci * @dd: valid device data 2498c2ecf20Sopenharmony_ci */ 2508c2ecf20Sopenharmony_ciint msix_request_general_irq(struct hfi1_devdata *dd) 2518c2ecf20Sopenharmony_ci{ 2528c2ecf20Sopenharmony_ci int nr; 2538c2ecf20Sopenharmony_ci char name[MAX_NAME_SIZE]; 2548c2ecf20Sopenharmony_ci 2558c2ecf20Sopenharmony_ci snprintf(name, sizeof(name), DRIVER_NAME "_%d", dd->unit); 2568c2ecf20Sopenharmony_ci nr = msix_request_irq(dd, dd, general_interrupt, NULL, IRQ_GENERAL, 2578c2ecf20Sopenharmony_ci name); 2588c2ecf20Sopenharmony_ci if (nr < 0) 2598c2ecf20Sopenharmony_ci return nr; 2608c2ecf20Sopenharmony_ci 2618c2ecf20Sopenharmony_ci /* general interrupt must be MSIx vector 0 */ 2628c2ecf20Sopenharmony_ci if (nr) { 2638c2ecf20Sopenharmony_ci msix_free_irq(dd, (u8)nr); 2648c2ecf20Sopenharmony_ci dd_dev_err(dd, "Invalid index %d for GENERAL IRQ\n", nr); 2658c2ecf20Sopenharmony_ci return -EINVAL; 2668c2ecf20Sopenharmony_ci } 2678c2ecf20Sopenharmony_ci 2688c2ecf20Sopenharmony_ci return 0; 2698c2ecf20Sopenharmony_ci} 2708c2ecf20Sopenharmony_ci 2718c2ecf20Sopenharmony_ci/** 2728c2ecf20Sopenharmony_ci * enable_sdma_src() - Helper to enable SDMA IRQ srcs 2738c2ecf20Sopenharmony_ci * @dd: valid devdata structure 2748c2ecf20Sopenharmony_ci * @i: index of SDMA engine 2758c2ecf20Sopenharmony_ci */ 2768c2ecf20Sopenharmony_cistatic void enable_sdma_srcs(struct hfi1_devdata *dd, int i) 2778c2ecf20Sopenharmony_ci{ 2788c2ecf20Sopenharmony_ci set_intr_bits(dd, IS_SDMA_START + i, IS_SDMA_START + i, true); 2798c2ecf20Sopenharmony_ci set_intr_bits(dd, IS_SDMA_PROGRESS_START + i, 2808c2ecf20Sopenharmony_ci IS_SDMA_PROGRESS_START + i, true); 2818c2ecf20Sopenharmony_ci set_intr_bits(dd, IS_SDMA_IDLE_START + i, IS_SDMA_IDLE_START + i, true); 2828c2ecf20Sopenharmony_ci set_intr_bits(dd, IS_SDMAENG_ERR_START + i, IS_SDMAENG_ERR_START + i, 2838c2ecf20Sopenharmony_ci true); 2848c2ecf20Sopenharmony_ci} 2858c2ecf20Sopenharmony_ci 2868c2ecf20Sopenharmony_ci/** 2878c2ecf20Sopenharmony_ci * msix_request_irqs() - Allocate all MSIx IRQs 2888c2ecf20Sopenharmony_ci * @dd: valid devdata structure 2898c2ecf20Sopenharmony_ci * 2908c2ecf20Sopenharmony_ci * Helper function to request the used MSIx IRQs. 2918c2ecf20Sopenharmony_ci * 2928c2ecf20Sopenharmony_ci */ 2938c2ecf20Sopenharmony_ciint msix_request_irqs(struct hfi1_devdata *dd) 2948c2ecf20Sopenharmony_ci{ 2958c2ecf20Sopenharmony_ci int i; 2968c2ecf20Sopenharmony_ci int ret = msix_request_general_irq(dd); 2978c2ecf20Sopenharmony_ci 2988c2ecf20Sopenharmony_ci if (ret) 2998c2ecf20Sopenharmony_ci return ret; 3008c2ecf20Sopenharmony_ci 3018c2ecf20Sopenharmony_ci for (i = 0; i < dd->num_sdma; i++) { 3028c2ecf20Sopenharmony_ci struct sdma_engine *sde = &dd->per_sdma[i]; 3038c2ecf20Sopenharmony_ci 3048c2ecf20Sopenharmony_ci ret = msix_request_sdma_irq(sde); 3058c2ecf20Sopenharmony_ci if (ret) 3068c2ecf20Sopenharmony_ci return ret; 3078c2ecf20Sopenharmony_ci enable_sdma_srcs(sde->dd, i); 3088c2ecf20Sopenharmony_ci } 3098c2ecf20Sopenharmony_ci 3108c2ecf20Sopenharmony_ci for (i = 0; i < dd->n_krcv_queues; i++) { 3118c2ecf20Sopenharmony_ci struct hfi1_ctxtdata *rcd = hfi1_rcd_get_by_index_safe(dd, i); 3128c2ecf20Sopenharmony_ci 3138c2ecf20Sopenharmony_ci if (rcd) 3148c2ecf20Sopenharmony_ci ret = msix_request_rcd_irq(rcd); 3158c2ecf20Sopenharmony_ci hfi1_rcd_put(rcd); 3168c2ecf20Sopenharmony_ci if (ret) 3178c2ecf20Sopenharmony_ci return ret; 3188c2ecf20Sopenharmony_ci } 3198c2ecf20Sopenharmony_ci 3208c2ecf20Sopenharmony_ci return 0; 3218c2ecf20Sopenharmony_ci} 3228c2ecf20Sopenharmony_ci 3238c2ecf20Sopenharmony_ci/** 3248c2ecf20Sopenharmony_ci * msix_free_irq() - Free the specified MSIx resources and IRQ 3258c2ecf20Sopenharmony_ci * @dd: valid devdata 3268c2ecf20Sopenharmony_ci * @msix_intr: MSIx vector to free. 3278c2ecf20Sopenharmony_ci * 3288c2ecf20Sopenharmony_ci */ 3298c2ecf20Sopenharmony_civoid msix_free_irq(struct hfi1_devdata *dd, u8 msix_intr) 3308c2ecf20Sopenharmony_ci{ 3318c2ecf20Sopenharmony_ci struct hfi1_msix_entry *me; 3328c2ecf20Sopenharmony_ci 3338c2ecf20Sopenharmony_ci if (msix_intr >= dd->msix_info.max_requested) 3348c2ecf20Sopenharmony_ci return; 3358c2ecf20Sopenharmony_ci 3368c2ecf20Sopenharmony_ci me = &dd->msix_info.msix_entries[msix_intr]; 3378c2ecf20Sopenharmony_ci 3388c2ecf20Sopenharmony_ci if (!me->arg) /* => no irq, no affinity */ 3398c2ecf20Sopenharmony_ci return; 3408c2ecf20Sopenharmony_ci 3418c2ecf20Sopenharmony_ci hfi1_put_irq_affinity(dd, me); 3428c2ecf20Sopenharmony_ci pci_free_irq(dd->pcidev, msix_intr, me->arg); 3438c2ecf20Sopenharmony_ci 3448c2ecf20Sopenharmony_ci me->arg = NULL; 3458c2ecf20Sopenharmony_ci 3468c2ecf20Sopenharmony_ci spin_lock(&dd->msix_info.msix_lock); 3478c2ecf20Sopenharmony_ci __clear_bit(msix_intr, dd->msix_info.in_use_msix); 3488c2ecf20Sopenharmony_ci spin_unlock(&dd->msix_info.msix_lock); 3498c2ecf20Sopenharmony_ci} 3508c2ecf20Sopenharmony_ci 3518c2ecf20Sopenharmony_ci/** 3528c2ecf20Sopenharmony_ci * hfi1_clean_up_msix_interrupts() - Free all MSIx IRQ resources 3538c2ecf20Sopenharmony_ci * @dd: valid device data data structure 3548c2ecf20Sopenharmony_ci * 3558c2ecf20Sopenharmony_ci * Free the MSIx and associated PCI resources, if they have been allocated. 3568c2ecf20Sopenharmony_ci */ 3578c2ecf20Sopenharmony_civoid msix_clean_up_interrupts(struct hfi1_devdata *dd) 3588c2ecf20Sopenharmony_ci{ 3598c2ecf20Sopenharmony_ci int i; 3608c2ecf20Sopenharmony_ci struct hfi1_msix_entry *me = dd->msix_info.msix_entries; 3618c2ecf20Sopenharmony_ci 3628c2ecf20Sopenharmony_ci /* remove irqs - must happen before disabling/turning off */ 3638c2ecf20Sopenharmony_ci for (i = 0; i < dd->msix_info.max_requested; i++, me++) 3648c2ecf20Sopenharmony_ci msix_free_irq(dd, i); 3658c2ecf20Sopenharmony_ci 3668c2ecf20Sopenharmony_ci /* clean structures */ 3678c2ecf20Sopenharmony_ci kfree(dd->msix_info.msix_entries); 3688c2ecf20Sopenharmony_ci dd->msix_info.msix_entries = NULL; 3698c2ecf20Sopenharmony_ci dd->msix_info.max_requested = 0; 3708c2ecf20Sopenharmony_ci 3718c2ecf20Sopenharmony_ci pci_free_irq_vectors(dd->pcidev); 3728c2ecf20Sopenharmony_ci} 3738c2ecf20Sopenharmony_ci 3748c2ecf20Sopenharmony_ci/** 3758c2ecf20Sopenharmony_ci * msix_netdev_syncrhonize_irq() - netdev IRQ synchronize 3768c2ecf20Sopenharmony_ci * @dd: valid devdata 3778c2ecf20Sopenharmony_ci */ 3788c2ecf20Sopenharmony_civoid msix_netdev_synchronize_irq(struct hfi1_devdata *dd) 3798c2ecf20Sopenharmony_ci{ 3808c2ecf20Sopenharmony_ci int i; 3818c2ecf20Sopenharmony_ci int ctxt_count = hfi1_netdev_ctxt_count(dd); 3828c2ecf20Sopenharmony_ci 3838c2ecf20Sopenharmony_ci for (i = 0; i < ctxt_count; i++) { 3848c2ecf20Sopenharmony_ci struct hfi1_ctxtdata *rcd = hfi1_netdev_get_ctxt(dd, i); 3858c2ecf20Sopenharmony_ci struct hfi1_msix_entry *me; 3868c2ecf20Sopenharmony_ci 3878c2ecf20Sopenharmony_ci me = &dd->msix_info.msix_entries[rcd->msix_intr]; 3888c2ecf20Sopenharmony_ci 3898c2ecf20Sopenharmony_ci synchronize_irq(me->irq); 3908c2ecf20Sopenharmony_ci } 3918c2ecf20Sopenharmony_ci} 392