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 */ 14 static void 15 ice_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 23 static int 24 ice_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 */ 40 static void ice_deinit_irq_tracker(struct ice_pf *pf) 41 { 42 xa_destroy(&pf->irq_tracker.entries); 43 } 44 45 static 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 */ 55 static 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 */ 74 static 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 107 static 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 */ 118 void 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 */ 129 int 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 */ 182 struct 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 204 exit_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 */ 218 void 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 */ 250 int 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 */ 271 void 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 } 276