1 // SPDX-License-Identifier: GPL-2.0
2 /* Copyright (C) 2023, Intel Corporation. */
9 * ice_reduce_msix_usage - Reduce usage of MSI-X vectors
10 * @pf: board private structure
11 * @v_remain: number of remaining MSI-X vectors to be distributed
13 * Reduce the usage of MSI-X vectors when entire request cannot be fulfilled.
14 * pf->num_lan_msix and pf->num_rdma_msix values are set based on number of
17 static void ice_reduce_msix_usage(struct ice_pf *pf, int v_remain)
21 if (!ice_is_rdma_ena(pf)) {
22 pf->num_lan_msix = v_remain;
26 /* RDMA needs at least 1 interrupt in addition to AEQ MSIX */
27 v_rdma = ICE_RDMA_NUM_AEQ_MSIX + 1;
29 if (v_remain < ICE_MIN_LAN_TXRX_MSIX + ICE_MIN_RDMA_MSIX) {
30 dev_warn(ice_pf_to_dev(pf), "Not enough MSI-X vectors to support RDMA.\n");
31 clear_bit(ICE_FLAG_RDMA_ENA, pf->flags);
33 pf->num_rdma_msix = 0;
34 pf->num_lan_msix = ICE_MIN_LAN_TXRX_MSIX;
35 } else if ((v_remain < ICE_MIN_LAN_TXRX_MSIX + v_rdma) ||
36 (v_remain - v_rdma < v_rdma)) {
37 /* Support minimum RDMA and give remaining vectors to LAN MSIX
39 pf->num_rdma_msix = ICE_MIN_RDMA_MSIX;
40 pf->num_lan_msix = v_remain - ICE_MIN_RDMA_MSIX;
42 /* Split remaining MSIX with RDMA after accounting for AEQ MSIX
44 pf->num_rdma_msix = (v_remain - ICE_RDMA_NUM_AEQ_MSIX) / 2 +
45 ICE_RDMA_NUM_AEQ_MSIX;
46 pf->num_lan_msix = v_remain - pf->num_rdma_msix;
51 * ice_ena_msix_range - Request a range of MSIX vectors from the OS
52 * @pf: board private structure
54 * Compute the number of MSIX vectors wanted and request from the OS. Adjust
55 * device usage if there are not enough vectors. Return the number of vectors
56 * reserved or negative on failure.
58 static int ice_ena_msix_range(struct ice_pf *pf)
60 int num_cpus, hw_num_msix, v_other, v_wanted, v_actual;
61 struct device *dev = ice_pf_to_dev(pf);
64 hw_num_msix = pf->hw.func_caps.common_cap.num_msix_vectors;
65 num_cpus = num_online_cpus();
67 /* LAN miscellaneous handler */
68 v_other = ICE_MIN_LAN_OICR_MSIX;
71 if (test_bit(ICE_FLAG_FD_ENA, pf->flags))
72 v_other += ICE_FDIR_MSIX;
75 v_other += ICE_ESWITCH_MSIX;
80 pf->num_lan_msix = num_cpus;
81 v_wanted += pf->num_lan_msix;
83 /* RDMA auxiliary driver */
84 if (ice_is_rdma_ena(pf)) {
85 pf->num_rdma_msix = num_cpus + ICE_RDMA_NUM_AEQ_MSIX;
86 v_wanted += pf->num_rdma_msix;
89 if (v_wanted > hw_num_msix) {
92 dev_warn(dev, "not enough device MSI-X vectors. wanted = %d, available = %d\n",
93 v_wanted, hw_num_msix);
95 if (hw_num_msix < ICE_MIN_MSIX) {
100 v_remain = hw_num_msix - v_other;
101 if (v_remain < ICE_MIN_LAN_TXRX_MSIX) {
102 v_other = ICE_MIN_MSIX - ICE_MIN_LAN_TXRX_MSIX;
103 v_remain = ICE_MIN_LAN_TXRX_MSIX;
106 ice_reduce_msix_usage(pf, v_remain);
107 v_wanted = pf->num_lan_msix + pf->num_rdma_msix + v_other;
109 dev_notice(dev, "Reducing request to %d MSI-X vectors for LAN traffic.\n",
111 if (ice_is_rdma_ena(pf))
112 dev_notice(dev, "Reducing request to %d MSI-X vectors for RDMA.\n",
116 /* actually reserve the vectors */
117 v_actual = pci_alloc_irq_vectors(pf->pdev, ICE_MIN_MSIX, v_wanted,
120 dev_err(dev, "unable to reserve MSI-X vectors\n");
125 if (v_actual < v_wanted) {
126 dev_warn(dev, "not enough OS MSI-X vectors. requested = %d, obtained = %d\n",
129 if (v_actual < ICE_MIN_MSIX) {
130 /* error if we can't get minimum vectors */
131 pci_free_irq_vectors(pf->pdev);
135 int v_remain = v_actual - v_other;
137 if (v_remain < ICE_MIN_LAN_TXRX_MSIX)
138 v_remain = ICE_MIN_LAN_TXRX_MSIX;
140 ice_reduce_msix_usage(pf, v_remain);
142 dev_notice(dev, "Enabled %d MSI-X vectors for LAN traffic.\n",
145 if (ice_is_rdma_ena(pf))
146 dev_notice(dev, "Enabled %d MSI-X vectors for RDMA.\n",
154 pf->num_rdma_msix = 0;
155 pf->num_lan_msix = 0;
160 * ice_clear_interrupt_scheme - Undo things done by ice_init_interrupt_scheme
161 * @pf: board private structure
163 void ice_clear_interrupt_scheme(struct ice_pf *pf)
165 pci_free_irq_vectors(pf->pdev);
167 if (pf->irq_tracker) {
168 devm_kfree(ice_pf_to_dev(pf), pf->irq_tracker);
169 pf->irq_tracker = NULL;
174 * ice_init_interrupt_scheme - Determine proper interrupt scheme
175 * @pf: board private structure to initialize
177 int ice_init_interrupt_scheme(struct ice_pf *pf)
181 vectors = ice_ena_msix_range(pf);
186 /* set up vector assignment tracking */
187 pf->irq_tracker = devm_kzalloc(ice_pf_to_dev(pf),
188 struct_size(pf->irq_tracker, list,
191 if (!pf->irq_tracker) {
192 pci_free_irq_vectors(pf->pdev);
196 /* populate SW interrupts pool with number of OS granted IRQs. */
197 pf->irq_tracker->num_entries = (u16)vectors;
198 pf->irq_tracker->end = pf->irq_tracker->num_entries;
204 * ice_alloc_irq - Allocate new interrupt vector
205 * @pf: board private structure
207 * Allocate new interrupt vector for a given owner id.
208 * return struct msi_map with interrupt details and track
209 * allocated interrupt appropriately.
211 * This function mimics individual interrupt allocation,
212 * even interrupts are actually already allocated with
213 * pci_alloc_irq_vectors. Individual allocation helps
214 * to track interrupts and simplifies interrupt related
217 * On failure, return map with negative .index. The caller
218 * is expected to check returned map index.
221 struct msi_map ice_alloc_irq(struct ice_pf *pf)
223 struct msi_map map = { .index = -ENOENT };
226 entry = ice_get_res(pf, pf->irq_tracker);
231 map.virq = pci_irq_vector(pf->pdev, map.index);
237 * ice_free_irq - Free interrupt vector
238 * @pf: board private structure
239 * @map: map with interrupt details
241 * Remove allocated interrupt from the interrupt tracker
243 void ice_free_irq(struct ice_pf *pf, struct msi_map map)
245 ice_free_res(pf->irq_tracker, map.index);