File Index
Files and directories
Sign in
FILE

ice_irq.c

File preview with syntax highlighting.

linux-6.19.14/drivers/net/ethernet/intel/ice/ice_irq.c 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.