FILE
ice_irq.c
File preview with syntax highlighting.
linux-6.19.14/drivers/net/ethernet/intel/ice/ice_irq.c
1// SPDX-License-Identifier: GPL-2.0 2/* Copyright (C) 2023, Intel Corporation. */ 3 4#include "ice.h" 5#include "ice_lib.h" 6#include "ice_irq.h" 7 8/** 9 * ice_init_irq_tracker - initialize interrupt tracker 10 * @pf: board private structure 11 * @max_vectors: maximum number of vectors that tracker can hold 12 * @num_static: number of preallocated interrupts 13 */ 14static void 15ice_init_irq_tracker(struct ice_pf *pf, unsigned int max_vectors, 16 unsigned int num_static) 17{ 18 pf->irq_tracker.num_entries = max_vectors; 19 pf->irq_tracker.num_static = num_static; 20 xa_init_flags(&pf->irq_tracker.entries, XA_FLAGS_ALLOC); 21} 22 23static int 24ice_init_virt_irq_tracker(struct ice_pf *pf, u32 base, u32 num_entries) 25{ 26 pf->virt_irq_tracker.bm = bitmap_zalloc(num_entries, GFP_KERNEL); 27 if (!pf->virt_irq_tracker.bm) 28 return -ENOMEM; 29 30 pf->virt_irq_tracker.num_entries = num_entries; 31 pf->virt_irq_tracker.base = base; 32 33 return 0; 34} 35 36/** 37 * ice_deinit_irq_tracker - free xarray tracker 38 * @pf: board private structure 39 */ 40static void ice_deinit_irq_tracker(struct ice_pf *pf) 41{ 42 xa_destroy(&pf->irq_tracker.entries); 43} 44 45static void ice_deinit_virt_irq_tracker(struct ice_pf *pf) 46{ 47 bitmap_free(pf->virt_irq_tracker.bm); 48} 49 50/** 51 * ice_free_irq_res - free a block of resources 52 * @pf: board private structure 53 * @index: starting index previously returned by ice_get_res 54 */ 55static void ice_free_irq_res(struct ice_pf *pf, u16 index) 56{ 57 struct ice_irq_entry *entry; 58 59 entry = xa_erase(&pf->irq_tracker.entries, index); 60 kfree(entry); 61} 62 63/** 64 * ice_get_irq_res - get an interrupt resource 65 * @pf: board private structure 66 * @dyn_allowed: allow entry to be dynamically allocated 67 * 68 * Allocate new irq entry in the free slot of the tracker. Since xarray 69 * is used, always allocate new entry at the lowest possible index. Set 70 * proper allocation limit for maximum tracker entries. 71 * 72 * Returns allocated irq entry or NULL on failure. 73 */ 74static struct ice_irq_entry *ice_get_irq_res(struct ice_pf *pf, 75 bool dyn_allowed) 76{ 77 struct xa_limit limit = { .max = pf->irq_tracker.num_entries - 1, 78 .min = 0 }; 79 unsigned int num_static = pf->irq_tracker.num_static - 1; 80 struct ice_irq_entry *entry; 81 unsigned int index; 82 int ret; 83 84 entry = kzalloc(sizeof(*entry), GFP_KERNEL); 85 if (!entry) 86 return NULL; 87 88 /* only already allocated if the caller says so */ 89 if (!dyn_allowed) 90 limit.max = num_static; 91 92 ret = xa_alloc(&pf->irq_tracker.entries, &index, entry, limit, 93 GFP_KERNEL); 94 95 if (ret) { 96 kfree(entry); 97 entry = NULL; 98 } else { 99 entry->index = index; 100 entry->dynamic = index > num_static; 101 } 102 103 return entry; 104} 105 106#define ICE_RDMA_AEQ_MSIX 1 107static int ice_get_default_msix_amount(struct ice_pf *pf) 108{ 109 return ICE_MIN_LAN_OICR_MSIX + num_online_cpus() + 110 (test_bit(ICE_FLAG_FD_ENA, pf->flags) ? ICE_FDIR_MSIX : 0) + 111 (ice_is_rdma_ena(pf) ? num_online_cpus() + ICE_RDMA_AEQ_MSIX : 0); 112} 113 114/** 115 * ice_clear_interrupt_scheme - Undo things done by ice_init_interrupt_scheme 116 * @pf: board private structure 117 */ 118void ice_clear_interrupt_scheme(struct ice_pf *pf) 119{ 120 pci_free_irq_vectors(pf->pdev); 121 ice_deinit_irq_tracker(pf); 122 ice_deinit_virt_irq_tracker(pf); 123} 124 125/** 126 * ice_init_interrupt_scheme - Determine proper interrupt scheme 127 * @pf: board private structure to initialize 128 */ 129int ice_init_interrupt_scheme(struct ice_pf *pf) 130{ 131 int total_vectors = pf->hw.func_caps.common_cap.num_msix_vectors; 132 int vectors; 133 134 /* load default PF MSI-X range */ 135 if (!pf->msix.min) 136 pf->msix.min = ICE_MIN_MSIX; 137 138 if (!pf->msix.max) 139 pf->msix.max = min(total_vectors, 140 ice_get_default_msix_amount(pf)); 141 142 pf->msix.total = total_vectors; 143 pf->msix.rest = total_vectors - pf->msix.max; 144 145 if (pci_msix_can_alloc_dyn(pf->pdev)) 146 vectors = pf->msix.min; 147 else 148 vectors = pf->msix.max; 149 150 vectors = pci_alloc_irq_vectors(pf->pdev, pf->msix.min, vectors, 151 PCI_IRQ_MSIX); 152 if (vectors < 0) 153 return vectors; 154 155 ice_init_irq_tracker(pf, pf->msix.max, vectors); 156 157 return ice_init_virt_irq_tracker(pf, pf->msix.max, pf->msix.rest); 158} 159 160/** 161 * ice_alloc_irq - Allocate new interrupt vector 162 * @pf: board private structure 163 * @dyn_allowed: allow dynamic allocation of the interrupt 164 * 165 * Allocate new interrupt vector for a given owner id. 166 * return struct msi_map with interrupt details and track 167 * allocated interrupt appropriately. 168 * 169 * This function reserves new irq entry from the irq_tracker. 170 * if according to the tracker information all interrupts that 171 * were allocated with ice_pci_alloc_irq_vectors are already used 172 * and dynamically allocated interrupts are supported then new 173 * interrupt will be allocated with pci_msix_alloc_irq_at. 174 * 175 * Some callers may only support dynamically allocated interrupts. 176 * This is indicated with dyn_allowed flag. 177 * 178 * On failure, return map with negative .index. The caller 179 * is expected to check returned map index. 180 * 181 */ 182struct msi_map ice_alloc_irq(struct ice_pf *pf, bool dyn_allowed) 183{ 184 struct msi_map map = { .index = -ENOENT }; 185 struct device *dev = ice_pf_to_dev(pf); 186 struct ice_irq_entry *entry; 187 188 entry = ice_get_irq_res(pf, dyn_allowed); 189 if (!entry) 190 return map; 191 192 if (pci_msix_can_alloc_dyn(pf->pdev) && entry->dynamic) { 193 map = pci_msix_alloc_irq_at(pf->pdev, entry->index, NULL); 194 if (map.index < 0) 195 goto exit_free_res; 196 dev_dbg(dev, "allocated new irq at index %d\n", map.index); 197 } else { 198 map.index = entry->index; 199 map.virq = pci_irq_vector(pf->pdev, map.index); 200 } 201 202 return map; 203 204exit_free_res: 205 dev_err(dev, "Could not allocate irq at idx %d\n", entry->index); 206 ice_free_irq_res(pf, entry->index); 207 return map; 208} 209 210/** 211 * ice_free_irq - Free interrupt vector 212 * @pf: board private structure 213 * @map: map with interrupt details 214 * 215 * Remove allocated interrupt from the interrupt tracker. If interrupt was 216 * allocated dynamically, free respective interrupt vector. 217 */ 218void ice_free_irq(struct ice_pf *pf, struct msi_map map) 219{ 220 struct ice_irq_entry *entry; 221 222 entry = xa_load(&pf->irq_tracker.entries, map.index); 223 224 if (!entry) { 225 dev_err(ice_pf_to_dev(pf), "Failed to get MSIX interrupt entry at index %d", 226 map.index); 227 return; 228 } 229 230 dev_dbg(ice_pf_to_dev(pf), "Free irq at index %d\n", map.index); 231 232 if (entry->dynamic) 233 pci_msix_free_irq(pf->pdev, map); 234 235 ice_free_irq_res(pf, map.index); 236} 237 238/** 239 * ice_virt_get_irqs - get irqs for SR-IOV usacase 240 * @pf: pointer to PF structure 241 * @needed: number of irqs to get 242 * 243 * This returns the first MSI-X vector index in PF space that is used by this 244 * VF. This index is used when accessing PF relative registers such as 245 * GLINT_VECT2FUNC and GLINT_DYN_CTL. 246 * This will always be the OICR index in the AVF driver so any functionality 247 * using vf->first_vector_idx for queue configuration_id: id of VF which will 248 * use this irqs 249 */ 250int ice_virt_get_irqs(struct ice_pf *pf, u32 needed) 251{ 252 int res = bitmap_find_next_zero_area(pf->virt_irq_tracker.bm, 253 pf->virt_irq_tracker.num_entries, 254 0, needed, 0); 255 256 if (res >= pf->virt_irq_tracker.num_entries) 257 return -ENOENT; 258 259 bitmap_set(pf->virt_irq_tracker.bm, res, needed); 260 261 /* conversion from number in bitmap to global irq index */ 262 return res + pf->virt_irq_tracker.base; 263} 264 265/** 266 * ice_virt_free_irqs - free irqs used by the VF 267 * @pf: pointer to PF structure 268 * @index: first index to be free 269 * @irqs: number of irqs to free 270 */ 271void ice_virt_free_irqs(struct ice_pf *pf, u32 index, u32 irqs) 272{ 273 bitmap_clear(pf->virt_irq_tracker.bm, index - pf->virt_irq_tracker.base, 274 irqs); 275}
~/
Read-only file preview.