Netdev List
 help / color / mirror / Atom feed
* [PATCH iwl-next v2 00/10] Interrupts helper in libie
@ 2026-09-11 12:49 Michal Swiatkowski
  2026-09-11 12:49 ` [PATCH iwl-next v2 01/10] idpf: store HW vectors information Michal Swiatkowski
                   ` (9 more replies)
  0 siblings, 10 replies; 11+ messages in thread
From: Michal Swiatkowski @ 2026-09-11 12:49 UTC (permalink / raw)
  To: intel-wired-lan; +Cc: netdev, Michal Swiatkowski

Hi,

To not copy the same code to handle interrupts in ixd driver move it to
libie_irq module and use in both idpf and ixd.

First part is changing current idpf code to make it more friendly to be
moved to the lib. Basically there is no need to store MSI-X entries in
separate table. Instead of that store it in xarray which also replace
custom lifo implementation.

Patch with libie is about moving the code to the new module. No
functional changes here, just moving the code or adding some more
descriptions.

The irq code is similar in ice. One patch also coverd the changes in ice
driver.

Last patches is the implementation in ixd driver. To manage MSI-X it
needs to first map correct regions. Do this using virtchnl command,
similiary as in idpf.

v1 --> v2: [1]
* patch 05
- New struct idpf_rdma_irq { entries, map, num } replaces
  adapter->rdma_msix_entries and adapter->num_rdma_msix_entries.
  idpf_idc.c is now touched by this patch to follow the rename.
- Removed the idpf_rdma_entry_to_index() helper. v1 reverse-looked-up the
  libie index from msix_entry.entry on every free; v2 stores the
  struct msi_map directly in rdma_irq->map[].
- idpf_rdma_intr_init() now allocates rdma_irq->map as well and unwinds
  both arrays on failure; idpf_rdma_intr_free() frees both.
- libie_irq_deinit() sets irq->pdev = NULL at the end.
- libie_get_irq() gains an "if (!irq->pdev) return NULL;" guard.
- libie_irq_free() guard changed from "if (!map.virq || map.index < 0)"
  to "if (map.virq <= 0 || map.index < 0)".
- idpf_vport_intr_alloc(): tmp_irqs changed from __free(kfree) to a plain
  pointer with an explicit kfree() on every error path and on success;
  loop variable i hoisted to function scope.
- idpf_mb_intr_init(): the libie_irq_alloc() call moved above the index
  check (cosmetic).

* patch 06
- Dropped Reviewed-by: Ahmed Zaki <ahmed.zaki@intel.com>.
- Otherwise only context churn from the idpf_rdma_irq change in patch 05.

* patch 07
- Dropped Reviewed-by: Ahmed Zaki <ahmed.zaki@intel.com>.
- include/linux/net/intel/libie/irq.h no longer includes
  <linux/net/intel/virtchnl2.h>; it forward declares
  struct virtchnl2_get_capabilities and struct virtchnl2_alloc_vectors
  instead.

* patch 08
- Commit message corrected. v1 claimed the allocation order was
  preserved

- LIBIE_IRQ_ANY is now introduced here rather than in patch 05: the enum
  value, the kernel-doc entries, and the struct xa_limit local plus the
  dynamic-then-static fallback in libie_get_irq() all moved into this
  patch.

* patch 09
- Removed the hardcoded PF_PCI_0/1/2 offset and size defines from
  ixd_lan_regs.h and the static ixd_running_regions[] table.
  ixd_iomap_running_regions() now computes the three ranges around the
  mailbox and reset registers from PF_FW_MBX, PFGEN_RTRIG and
  pci_resource_len().
- ixd_start_regions[] made static, with a comment explaining it stays
  mapped for the whole driver life.
- uint i -> unsigned int i in ixd_iomap_is_not_start_region().
- New ixd_fill_caps() requests VIRTCHNL2_CAP_LAN_MEMORY_REGIONS in
  GET_CAPS, and new ixd_is_cap_ena() helper. ixd_vc_dev_init() now
  selects the path based on the negotiated capability instead of sending
  the command and falling back on error.
- ixd_handle_lan_mmio_regions(): bounds check uses
  struct_size(recv_mmio, mem_reg, num_regions) instead of the open-coded
  sizeof() + sizeof() * n; zero-size padding regions are skipped; the
  unused err variable is gone.

* patch 10
- Register addresses are resolved once and cached in the new
  adapter->mb_dyn_ctl and adapter->oicr_ena via the new
  ixd_mailbox_irq_regs_init(), with a NULL check returning -EINVAL. v1
  called libie_pci_get_mmio_addr() on every enable with no NULL check.
- New ixd_mailbox_irq_disable().
- ixd_mailbox_irq_deinit() rewritten: early return on the flag, disable
  the interrupt in HW, then cancel_delayed_work_sync(&adapter->mbx_task)
  before free_irq(). v1 instead re-queued mbx_task after freeing the irq.
- ixd_mailbox_irq_init() now handles kasprintf() returning NULL (frees
  the libie irq, returns -ENOMEM). v1 passed a possibly NULL name to
  request_irq().
- ixd_remove(): ixd_deinit_interrupts() moved earlier, before
  libie_ctlq_xn_shutdown() and ixd_trigger_reset(), instead of after
  them.

[1] https://lore.kernel.org/netdev/20260907102418.2697317-1-michal.swiatkowski@linux.intel.com/

Michal Swiatkowski (10):
  idpf: store HW vectors information
  idpf: fill q_vector interrupt registers one by one
  idpf: get rid of msix_entries array
  idpf: drop v_idx from q_vector structure
  libie, idpf: move irq code to libie
  libie, idpf: move hardware irq info struct to libie
  libie, idpf: move parsing alloc vectors command to libie
  ice: use libie_irq for interrupts managing
  ixd: support for getting lan memory regions
  ixd: use interrupt for mailbox communication

 drivers/net/ethernet/intel/Kconfig            |   1 +
 drivers/net/ethernet/intel/ice/ice.h          |   5 +-
 drivers/net/ethernet/intel/ice/ice_base.c     |   4 +-
 drivers/net/ethernet/intel/ice/ice_idc.c      |   4 +-
 drivers/net/ethernet/intel/ice/ice_irq.c      | 181 +-------
 drivers/net/ethernet/intel/ice/ice_irq.h      |  14 -
 drivers/net/ethernet/intel/ice/ice_lib.c      |   3 -
 drivers/net/ethernet/intel/ice/ice_main.c     |  15 +-
 drivers/net/ethernet/intel/idpf/Kconfig       |   1 +
 drivers/net/ethernet/intel/idpf/idpf.h        |  88 ++--
 drivers/net/ethernet/intel/idpf/idpf_dev.c    | 108 ++---
 drivers/net/ethernet/intel/idpf/idpf_idc.c    |   6 +-
 drivers/net/ethernet/intel/idpf/idpf_lib.c    | 425 +++++-------------
 drivers/net/ethernet/intel/idpf/idpf_main.c   |   3 +-
 drivers/net/ethernet/intel/idpf/idpf_txrx.c   | 142 +++---
 drivers/net/ethernet/intel/idpf/idpf_txrx.h   |  23 +-
 drivers/net/ethernet/intel/idpf/idpf_vf_dev.c | 109 ++---
 .../net/ethernet/intel/idpf/idpf_virtchnl.c   | 159 +------
 .../net/ethernet/intel/idpf/idpf_virtchnl.h   |   9 +-
 drivers/net/ethernet/intel/ixd/Kconfig        |   1 +
 drivers/net/ethernet/intel/ixd/ixd.h          |  31 ++
 drivers/net/ethernet/intel/ixd/ixd_ctlq.c     |   8 +-
 drivers/net/ethernet/intel/ixd/ixd_lan_regs.h |  10 +
 drivers/net/ethernet/intel/ixd/ixd_lib.c      | 126 ++++++
 drivers/net/ethernet/intel/ixd/ixd_main.c     | 133 +++++-
 drivers/net/ethernet/intel/ixd/ixd_virtchnl.c |  90 +++-
 drivers/net/ethernet/intel/libie/Kconfig      |   6 +
 drivers/net/ethernet/intel/libie/Makefile     |   4 +
 drivers/net/ethernet/intel/libie/irq.c        | 368 +++++++++++++++
 include/linux/net/intel/libie/irq.h           | 120 +++++
 30 files changed, 1250 insertions(+), 947 deletions(-)
 create mode 100644 drivers/net/ethernet/intel/libie/irq.c
 create mode 100644 include/linux/net/intel/libie/irq.h

-- 
2.49.0


^ permalink raw reply	[flat|nested] 11+ messages in thread

* [PATCH iwl-next v2 01/10] idpf: store HW vectors information
  2026-09-11 12:49 [PATCH iwl-next v2 00/10] Interrupts helper in libie Michal Swiatkowski
@ 2026-09-11 12:49 ` Michal Swiatkowski
  2026-09-11 12:49 ` [PATCH iwl-next v2 02/10] idpf: fill q_vector interrupt registers one by one Michal Swiatkowski
                   ` (8 subsequent siblings)
  9 siblings, 0 replies; 11+ messages in thread
From: Michal Swiatkowski @ 2026-09-11 12:49 UTC (permalink / raw)
  To: intel-wired-lan; +Cc: netdev, Michal Swiatkowski, Aleksandr Loktionov

Currently hardware vectors information (registers address and HW indexes)
is stored in virtchnl command. When this information is needed they
are parsed and returned. There is a need for alloc/free array for this
information each time it is called.

Information about indexes and registers are parsed in two similar
functions. Create one parse function for both and store it in irq_info
structure to use whenever it is needed.

Stored virtchnl command still has to exist, because it is used when
sending dealloc message.

Make intr_reg_init() functions (for VF and PF) return void to
simplify code. With stored irq information there is no need to alloc an
array for it, so these functions can't fail.

Previously mailbox vector wasn't filled in idpf_intr_reg_init()
function. Store the mailbox information in irq_info.vectors to have
everything in one place. Because of that tweak index in few places by
adding IDPF_MBX_Q_VEC (when allocatig or iterrating) or not substracting
IDPF_MBX_Q_VEC from q_vector_idxs, because it is no needed now.

Reviewed-by: Aleksandr Loktionov <aleksandr.loktionov@intel.com>
Signed-off-by: Michal Swiatkowski <michal.swiatkowski@linux.intel.com>
---
 drivers/net/ethernet/intel/idpf/idpf.h        |  41 +++-
 drivers/net/ethernet/intel/idpf/idpf_dev.c    |  51 ++---
 drivers/net/ethernet/intel/idpf/idpf_lib.c    |  34 +---
 drivers/net/ethernet/intel/idpf/idpf_txrx.c   |  42 +---
 drivers/net/ethernet/intel/idpf/idpf_txrx.h   |  13 --
 drivers/net/ethernet/intel/idpf/idpf_vf_dev.c |  51 ++---
 .../net/ethernet/intel/idpf/idpf_virtchnl.c   | 184 ++++++++----------
 .../net/ethernet/intel/idpf/idpf_virtchnl.h   |   6 -
 8 files changed, 176 insertions(+), 246 deletions(-)

diff --git a/drivers/net/ethernet/intel/idpf/idpf.h b/drivers/net/ethernet/intel/idpf/idpf.h
index df9e42bfeaa2..84b145431693 100644
--- a/drivers/net/ethernet/intel/idpf/idpf.h
+++ b/drivers/net/ethernet/intel/idpf/idpf.h
@@ -36,6 +36,7 @@ struct idpf_rss_data;
 #define IDPF_NUM_FILTERS_PER_MSG	20
 #define IDPF_NUM_DFLT_MBX_Q		2	/* includes both TX and RX */
 #define IDPF_DFLT_MBX_Q_LEN		64
+#define IDPF_MBX_IRQ_INDEX		0
 /* maximum number of times to try before resetting mailbox */
 #define IDPF_MB_MAX_ERR			20
 #define IDPF_NUM_CHUNKS_PER_MSG(struct_sz, chunk_sz)	\
@@ -204,8 +205,8 @@ struct idpf_vport_max_q {
 struct idpf_reg_ops {
 	void (*ctlq_reg_init)(struct libie_mmio_info *mmio,
 			      struct libie_ctlq_create_info *cctlq_info);
-	int (*intr_reg_init)(struct idpf_vport *vport,
-			     struct idpf_q_vec_rsrc *rsrc);
+	void (*intr_reg_init)(struct idpf_vport *vport,
+			      struct idpf_q_vec_rsrc *rsrc);
 	void (*mb_intr_reg_init)(struct idpf_adapter *adapter);
 	void (*reset_reg_init)(struct idpf_adapter *adapter);
 	void (*trigger_reset)(struct idpf_adapter *adapter,
@@ -614,6 +615,40 @@ struct idpf_vport_config {
 	     iter = (++__##iter) < &(adapter)->vports[(adapter)->max_vports] ? \
 	     *__##iter : NULL)
 
+/**
+ * struct idpf_vec_regs - hardware registers related to vector
+ * @dyn_ctl: Dynamic control interrupt register offset
+ * @itrn: Interrupt Throttling Rate register offset
+ * @itrn_index_spacing: Register spacing between ITR registers of the same
+ *			vector
+ */
+struct idpf_vec_regs {
+	u32 dyn_ctl;
+	u32 itrn;
+	u32 itrn_index_spacing;
+};
+
+/**
+ * struct idpf_hw_vector - single hardware vector info
+ * @regs: address of irq registers
+ * @idx: hardware vector index
+ */
+struct idpf_hw_vector {
+	struct idpf_vec_regs regs;
+	int idx;
+};
+
+/**
+ * struct idpf_irq_info - hardware data needed to setup irq
+ * @vectors: allocated during initialization store hardware information
+ *	     for all vectors that can be used on a whole device
+ * @num: amount of vectors stored here
+ */
+struct idpf_irq_info {
+	struct idpf_hw_vector *vectors;
+	int num;
+};
+
 /**
  * struct idpf_adapter - Device data struct generated on probe
  * @pdev: PCI device struct given on probe
@@ -633,6 +668,7 @@ struct idpf_vport_config {
  * @msix_entries: MSIX table
  * @num_rdma_msix_entries: Available number of MSIX vectors for RDMA
  * @rdma_msix_entries: RDMA MSIX table
+ * @irq_info: hardware data needed to setup irq
  * @req_vec_chunks: Requested vector chunk data
  * @mb_vector: Mailbox vector data
  * @vector_stack: Stack to store the msix vector indexes
@@ -693,6 +729,7 @@ struct idpf_adapter {
 	u16 num_rdma_msix_entries;
 	struct msix_entry *rdma_msix_entries;
 	struct virtchnl2_alloc_vectors *req_vec_chunks;
+	struct idpf_irq_info irq_info;
 	struct idpf_q_vector mb_vector;
 	struct idpf_vector_lifo vector_stack;
 	irqreturn_t (*irq_mb_handler)(int irq, void *data);
diff --git a/drivers/net/ethernet/intel/idpf/idpf_dev.c b/drivers/net/ethernet/intel/idpf/idpf_dev.c
index 083cf6319d26..42e65f1285df 100644
--- a/drivers/net/ethernet/intel/idpf/idpf_dev.c
+++ b/drivers/net/ethernet/intel/idpf/idpf_dev.c
@@ -46,7 +46,9 @@ static void idpf_mb_intr_reg_init(struct idpf_adapter *adapter)
 {
 	struct libie_mmio_info *mmio = &adapter->ctlq_ctx.mmio_info;
 	struct idpf_intr_reg *intr = &adapter->mb_vector.intr_reg;
-	u32 dyn_ctl = le32_to_cpu(adapter->caps.mailbox_dyn_ctl);
+	u32 dyn_ctl;
+
+	dyn_ctl = adapter->irq_info.vectors[IDPF_MBX_IRQ_INDEX].regs.dyn_ctl;
 
 	intr->dyn_ctl = libie_pci_get_mmio_addr(mmio, dyn_ctl);
 	intr->dyn_ctl_intena_m = PF_GLINT_DYN_CTL_INTENA_M;
@@ -60,39 +62,27 @@ static void idpf_mb_intr_reg_init(struct idpf_adapter *adapter)
  * @vport: virtual port structure
  * @rsrc: pointer to queue and vector resources
  */
-static int idpf_intr_reg_init(struct idpf_vport *vport,
-			      struct idpf_q_vec_rsrc *rsrc)
+static void idpf_intr_reg_init(struct idpf_vport *vport,
+			       struct idpf_q_vec_rsrc *rsrc)
 {
 	struct idpf_adapter *adapter = vport->adapter;
-	u16 num_vecs = rsrc->num_q_vectors;
-	struct idpf_vec_regs *reg_vals;
+	int num_vecs = rsrc->num_q_vectors;
 	struct libie_mmio_info *mmio;
-	int num_regs, i, err = 0;
 	u32 rx_itr, tx_itr, val;
-	u16 total_vecs;
-
-	total_vecs = idpf_get_reserved_vecs(vport->adapter);
-	reg_vals = kzalloc_objs(struct idpf_vec_regs, total_vecs);
-	if (!reg_vals)
-		return -ENOMEM;
-
-	num_regs = idpf_get_reg_intr_vecs(adapter, reg_vals, total_vecs);
-	if (num_regs < num_vecs) {
-		err = -EINVAL;
-		goto free_reg_vals;
-	}
+	int i;
 
 	mmio = &adapter->ctlq_ctx.mmio_info;
 
 	for (i = 0; i < num_vecs; i++) {
 		struct idpf_q_vector *q_vector = &rsrc->q_vectors[i];
-		u16 vec_id = rsrc->q_vector_idxs[i] - IDPF_MBX_Q_VEC;
 		struct idpf_intr_reg *intr = &q_vector->intr_reg;
-		struct idpf_vec_regs *reg = &reg_vals[vec_id];
+		u16 vec_id = rsrc->q_vector_idxs[i];
+		struct idpf_hw_vector *v;
 		u32 spacing;
 
-		intr->dyn_ctl = libie_pci_get_mmio_addr(mmio,
-							reg->dyn_ctl_reg);
+		v = &adapter->irq_info.vectors[vec_id];
+
+		intr->dyn_ctl = libie_pci_get_mmio_addr(mmio, v->regs.dyn_ctl);
 		intr->dyn_ctl_intena_m = PF_GLINT_DYN_CTL_INTENA_M;
 		intr->dyn_ctl_intena_msk_m = PF_GLINT_DYN_CTL_INTENA_MSK_M;
 		intr->dyn_ctl_itridx_s = PF_GLINT_DYN_CTL_ITR_INDX_S;
@@ -102,30 +92,25 @@ static int idpf_intr_reg_init(struct idpf_vport *vport,
 		intr->dyn_ctl_sw_itridx_ena_m =
 			PF_GLINT_DYN_CTL_SW_ITR_INDX_ENA_M;
 
-		spacing = IDPF_ITR_IDX_SPACING(reg->itrn_index_spacing,
+		spacing = IDPF_ITR_IDX_SPACING(v->regs.itrn_index_spacing,
 					       IDPF_PF_ITR_IDX_SPACING);
-		rx_itr = PF_GLINT_ITR_ADDR(VIRTCHNL2_ITR_IDX_0,
-					   reg->itrn_reg, spacing);
-		tx_itr = PF_GLINT_ITR_ADDR(VIRTCHNL2_ITR_IDX_1,
-					   reg->itrn_reg, spacing);
+		rx_itr = PF_GLINT_ITR_ADDR(VIRTCHNL2_ITR_IDX_0, v->regs.itrn,
+					   spacing);
+		tx_itr = PF_GLINT_ITR_ADDR(VIRTCHNL2_ITR_IDX_1, v->regs.itrn,
+					   spacing);
 		intr->rx_itr = libie_pci_get_mmio_addr(mmio, rx_itr);
 		intr->tx_itr = libie_pci_get_mmio_addr(mmio, tx_itr);
 	}
 
 	/* Data vector for NOIRQ queues */
 
-	val = reg_vals[rsrc->q_vector_idxs[i] - IDPF_MBX_Q_VEC].dyn_ctl_reg;
+	val = adapter->irq_info.vectors[rsrc->q_vector_idxs[i]].regs.dyn_ctl;
 	rsrc->noirq_dyn_ctl =
 		libie_pci_get_mmio_addr(&adapter->ctlq_ctx.mmio_info, val);
 
 	val = PF_GLINT_DYN_CTL_WB_ON_ITR_M | PF_GLINT_DYN_CTL_INTENA_MSK_M |
 	      FIELD_PREP(PF_GLINT_DYN_CTL_ITR_INDX_M, IDPF_NO_ITR_UPDATE_IDX);
 	rsrc->noirq_dyn_ctl_ena = val;
-
-free_reg_vals:
-	kfree(reg_vals);
-
-	return err;
 }
 
 /**
diff --git a/drivers/net/ethernet/intel/idpf/idpf_lib.c b/drivers/net/ethernet/intel/idpf/idpf_lib.c
index 5d61ecb73a40..36bb6a268042 100644
--- a/drivers/net/ethernet/intel/idpf/idpf_lib.c
+++ b/drivers/net/ethernet/intel/idpf/idpf_lib.c
@@ -305,16 +305,14 @@ int idpf_req_rel_vector_indexes(struct idpf_adapter *adapter,
  */
 int idpf_intr_req(struct idpf_adapter *adapter)
 {
-	u16 num_lan_vecs, min_lan_vecs, num_rdma_vecs = 0, min_rdma_vecs = 0;
+	int num_rdma_vecs = 0, min_rdma_vecs = 0, num_lan_vecs = 0;
 	u16 default_vports = idpf_get_default_vports(adapter);
-	int num_q_vecs, total_vecs, num_vec_ids;
-	int min_vectors, actual_vecs, err;
+	int min_vectors, actual_vecs, min_lan_vecs, err;
+	int num_q_vecs, total_vecs;
 	unsigned int vector;
-	u16 *vecids;
 	int i;
 
 	total_vecs = idpf_get_reserved_vecs(adapter);
-	num_lan_vecs = total_vecs;
 	if (idpf_is_rdma_cap_ena(adapter)) {
 		num_rdma_vecs = idpf_get_reserved_rdma_vecs(adapter);
 		min_rdma_vecs = IDPF_MIN_RDMA_VEC;
@@ -376,28 +374,15 @@ int idpf_intr_req(struct idpf_adapter *adapter)
 		goto free_rdma_msix;
 	}
 
-	adapter->mb_vector.v_idx = le16_to_cpu(adapter->caps.mailbox_vector_id);
-
-	vecids = kcalloc(actual_vecs, sizeof(u16), GFP_KERNEL);
-	if (!vecids) {
-		err = -ENOMEM;
-		goto free_msix;
-	}
-
-	num_vec_ids = idpf_get_vec_ids(adapter, vecids, actual_vecs,
-				       &adapter->req_vec_chunks->vchunks);
-	if (num_vec_ids < actual_vecs) {
-		err = -EINVAL;
-		goto free_vecids;
-	}
-
 	for (vector = 0; vector < num_lan_vecs; vector++) {
-		adapter->msix_entries[vector].entry = vecids[vector];
+		adapter->msix_entries[vector].entry =
+			adapter->irq_info.vectors[vector].idx;
 		adapter->msix_entries[vector].vector =
 			pci_irq_vector(adapter->pdev, vector);
 	}
 	for (i = 0; i < num_rdma_vecs; vector++, i++) {
-		adapter->rdma_msix_entries[i].entry = vecids[vector];
+		adapter->rdma_msix_entries[i].entry =
+			adapter->irq_info.vectors[vector].idx;
 		adapter->rdma_msix_entries[i].vector =
 			pci_irq_vector(adapter->pdev, vector);
 	}
@@ -414,20 +399,17 @@ int idpf_intr_req(struct idpf_adapter *adapter)
 	/* Fill MSIX vector lifo stack with vector indexes */
 	err = idpf_init_vector_stack(adapter);
 	if (err)
-		goto free_vecids;
+		goto free_msix;
 
 	err = idpf_mb_intr_init(adapter);
 	if (err)
 		goto deinit_vec_stack;
 	idpf_mb_irq_enable(adapter);
-	kfree(vecids);
 
 	return 0;
 
 deinit_vec_stack:
 	idpf_deinit_vector_stack(adapter);
-free_vecids:
-	kfree(vecids);
 free_msix:
 	kfree(adapter->msix_entries);
 	adapter->msix_entries = NULL;
diff --git a/drivers/net/ethernet/intel/idpf/idpf_txrx.c b/drivers/net/ethernet/intel/idpf/idpf_txrx.c
index 5e66652afa5b..2b21f599f569 100644
--- a/drivers/net/ethernet/intel/idpf/idpf_txrx.c
+++ b/drivers/net/ethernet/intel/idpf/idpf_txrx.c
@@ -4502,42 +4502,18 @@ static void idpf_vport_intr_map_vector_to_qs(struct idpf_vport *vport,
  * @rsrc: pointer to queue and vector resources
  *
  * Initialize vector indexes with values returned over mailbox.
- *
- * Return: 0 on success, negative on failure
  */
-static int idpf_vport_intr_init_vec_idx(struct idpf_vport *vport,
-					struct idpf_q_vec_rsrc *rsrc)
+static void idpf_vport_intr_init_vec_idx(struct idpf_vport *vport,
+					 struct idpf_q_vec_rsrc *rsrc)
 {
 	struct idpf_adapter *adapter = vport->adapter;
-	struct virtchnl2_alloc_vectors *ac;
-	u16 *vecids, total_vecs;
 	int i;
 
-	ac = adapter->req_vec_chunks;
-	if (!ac) {
-		for (i = 0; i < rsrc->num_q_vectors; i++)
-			rsrc->q_vectors[i].v_idx = rsrc->q_vector_idxs[i];
-
-		rsrc->noirq_v_idx = rsrc->q_vector_idxs[i];
-
-		return 0;
-	}
-
-	total_vecs = idpf_get_reserved_vecs(adapter);
-	vecids = kcalloc(total_vecs, sizeof(u16), GFP_KERNEL);
-	if (!vecids)
-		return -ENOMEM;
-
-	idpf_get_vec_ids(adapter, vecids, total_vecs, &ac->vchunks);
-
 	for (i = 0; i < rsrc->num_q_vectors; i++)
-		rsrc->q_vectors[i].v_idx = vecids[rsrc->q_vector_idxs[i]];
-
-	rsrc->noirq_v_idx = vecids[rsrc->q_vector_idxs[i]];
+		rsrc->q_vectors[i].v_idx =
+			adapter->irq_info.vectors[rsrc->q_vector_idxs[i]].idx;
 
-	kfree(vecids);
-
-	return 0;
+	rsrc->noirq_v_idx = adapter->irq_info.vectors[rsrc->q_vector_idxs[i]].idx;
 }
 
 /**
@@ -4668,16 +4644,12 @@ int idpf_vport_intr_init(struct idpf_vport *vport, struct idpf_q_vec_rsrc *rsrc)
 {
 	int err;
 
-	err = idpf_vport_intr_init_vec_idx(vport, rsrc);
-	if (err)
-		return err;
+	idpf_vport_intr_init_vec_idx(vport, rsrc);
 
 	idpf_vport_intr_map_vector_to_qs(vport, rsrc);
 	idpf_vport_intr_napi_add_all(vport, rsrc);
 
-	err = vport->adapter->dev_ops.reg_ops.intr_reg_init(vport, rsrc);
-	if (err)
-		goto unroll_vectors_alloc;
+	vport->adapter->dev_ops.reg_ops.intr_reg_init(vport, rsrc);
 
 	err = idpf_vport_intr_req_irq(vport, rsrc);
 	if (err)
diff --git a/drivers/net/ethernet/intel/idpf/idpf_txrx.h b/drivers/net/ethernet/intel/idpf/idpf_txrx.h
index dce07fbb6e77..ecff84df776d 100644
--- a/drivers/net/ethernet/intel/idpf/idpf_txrx.h
+++ b/drivers/net/ethernet/intel/idpf/idpf_txrx.h
@@ -318,19 +318,6 @@ enum idpf_queue_flags_t {
 #define idpf_queue_assign(f, q, v)			\
 	__assign_bit(__IDPF_Q_##f, (q)->flags, v)
 
-/**
- * struct idpf_vec_regs
- * @dyn_ctl_reg: Dynamic control interrupt register offset
- * @itrn_reg: Interrupt Throttling Rate register offset
- * @itrn_index_spacing: Register spacing between ITR registers of the same
- *			vector
- */
-struct idpf_vec_regs {
-	u32 dyn_ctl_reg;
-	u32 itrn_reg;
-	u32 itrn_index_spacing;
-};
-
 /**
  * struct idpf_intr_reg
  * @dyn_ctl: Dynamic control interrupt register
diff --git a/drivers/net/ethernet/intel/idpf/idpf_vf_dev.c b/drivers/net/ethernet/intel/idpf/idpf_vf_dev.c
index b537de3592f4..c0080842b7e2 100644
--- a/drivers/net/ethernet/intel/idpf/idpf_vf_dev.c
+++ b/drivers/net/ethernet/intel/idpf/idpf_vf_dev.c
@@ -45,7 +45,9 @@ static void idpf_vf_mb_intr_reg_init(struct idpf_adapter *adapter)
 {
 	struct libie_mmio_info *mmio = &adapter->ctlq_ctx.mmio_info;
 	struct idpf_intr_reg *intr = &adapter->mb_vector.intr_reg;
-	u32 dyn_ctl = le32_to_cpu(adapter->caps.mailbox_dyn_ctl);
+	u32 dyn_ctl;
+
+	dyn_ctl = adapter->irq_info.vectors[IDPF_MBX_IRQ_INDEX].regs.dyn_ctl;
 
 	intr->dyn_ctl = libie_pci_get_mmio_addr(mmio, dyn_ctl);
 	intr->dyn_ctl_intena_m = VF_INT_DYN_CTL0_INTENA_M;
@@ -59,39 +61,27 @@ static void idpf_vf_mb_intr_reg_init(struct idpf_adapter *adapter)
  * @vport: virtual port structure
  * @rsrc: pointer to queue and vector resources
  */
-static int idpf_vf_intr_reg_init(struct idpf_vport *vport,
-				 struct idpf_q_vec_rsrc *rsrc)
+static void idpf_vf_intr_reg_init(struct idpf_vport *vport,
+				  struct idpf_q_vec_rsrc *rsrc)
 {
 	struct idpf_adapter *adapter = vport->adapter;
-	u16 num_vecs = rsrc->num_q_vectors;
-	struct idpf_vec_regs *reg_vals;
+	int num_vecs = rsrc->num_q_vectors;
 	struct libie_mmio_info *mmio;
-	int num_regs, i, err = 0;
 	u32 rx_itr, tx_itr, val;
-	u16 total_vecs;
-
-	total_vecs = idpf_get_reserved_vecs(vport->adapter);
-	reg_vals = kzalloc_objs(struct idpf_vec_regs, total_vecs);
-	if (!reg_vals)
-		return -ENOMEM;
-
-	num_regs = idpf_get_reg_intr_vecs(adapter, reg_vals, total_vecs);
-	if (num_regs < num_vecs) {
-		err = -EINVAL;
-		goto free_reg_vals;
-	}
+	int i;
 
 	mmio = &adapter->ctlq_ctx.mmio_info;
 
 	for (i = 0; i < num_vecs; i++) {
 		struct idpf_q_vector *q_vector = &rsrc->q_vectors[i];
-		u16 vec_id = rsrc->q_vector_idxs[i] - IDPF_MBX_Q_VEC;
 		struct idpf_intr_reg *intr = &q_vector->intr_reg;
-		struct idpf_vec_regs *reg = &reg_vals[vec_id];
+		u16 vec_id = rsrc->q_vector_idxs[i];
+		struct idpf_hw_vector *v;
 		u32 spacing;
 
-		intr->dyn_ctl = libie_pci_get_mmio_addr(mmio,
-							reg->dyn_ctl_reg);
+		v = &adapter->irq_info.vectors[vec_id];
+
+		intr->dyn_ctl = libie_pci_get_mmio_addr(mmio, v->regs.dyn_ctl);
 		intr->dyn_ctl_intena_m = VF_INT_DYN_CTLN_INTENA_M;
 		intr->dyn_ctl_intena_msk_m = VF_INT_DYN_CTLN_INTENA_MSK_M;
 		intr->dyn_ctl_itridx_s = VF_INT_DYN_CTLN_ITR_INDX_S;
@@ -101,30 +91,25 @@ static int idpf_vf_intr_reg_init(struct idpf_vport *vport,
 		intr->dyn_ctl_sw_itridx_ena_m =
 			VF_INT_DYN_CTLN_SW_ITR_INDX_ENA_M;
 
-		spacing = IDPF_ITR_IDX_SPACING(reg->itrn_index_spacing,
+		spacing = IDPF_ITR_IDX_SPACING(v->regs.itrn_index_spacing,
 					       IDPF_VF_ITR_IDX_SPACING);
-		rx_itr = VF_INT_ITRN_ADDR(VIRTCHNL2_ITR_IDX_0,
-					  reg->itrn_reg, spacing);
-		tx_itr = VF_INT_ITRN_ADDR(VIRTCHNL2_ITR_IDX_1,
-					  reg->itrn_reg, spacing);
+		rx_itr = VF_INT_ITRN_ADDR(VIRTCHNL2_ITR_IDX_0, v->regs.itrn,
+					  spacing);
+		tx_itr = VF_INT_ITRN_ADDR(VIRTCHNL2_ITR_IDX_1, v->regs.itrn,
+					  spacing);
 		intr->rx_itr = libie_pci_get_mmio_addr(mmio, rx_itr);
 		intr->tx_itr = libie_pci_get_mmio_addr(mmio, tx_itr);
 	}
 
 	/* Data vector for NOIRQ queues */
 
-	val = reg_vals[rsrc->q_vector_idxs[i] - IDPF_MBX_Q_VEC].dyn_ctl_reg;
+	val = adapter->irq_info.vectors[rsrc->q_vector_idxs[i]].regs.dyn_ctl;
 	rsrc->noirq_dyn_ctl =
 		libie_pci_get_mmio_addr(&adapter->ctlq_ctx.mmio_info, val);
 
 	val = VF_INT_DYN_CTLN_WB_ON_ITR_M | VF_INT_DYN_CTLN_INTENA_MSK_M |
 	      FIELD_PREP(VF_INT_DYN_CTLN_ITR_INDX_M, IDPF_NO_ITR_UPDATE_IDX);
 	rsrc->noirq_dyn_ctl_ena = val;
-
-free_reg_vals:
-	kfree(reg_vals);
-
-	return err;
 }
 
 /**
diff --git a/drivers/net/ethernet/intel/idpf/idpf_virtchnl.c b/drivers/net/ethernet/intel/idpf/idpf_virtchnl.c
index f2a58b814cb8..267ac9fa3846 100644
--- a/drivers/net/ethernet/intel/idpf/idpf_virtchnl.c
+++ b/drivers/net/ethernet/intel/idpf/idpf_virtchnl.c
@@ -896,54 +896,6 @@ idpf_vport_init_queue_reg_chunks(struct idpf_vport_config *vport_config,
 	return 0;
 }
 
-/**
- * idpf_get_reg_intr_vecs - Get vector queue register offset
- * @adapter: adapter structure to get the vector chunks
- * @reg_vals: Register offsets to store in
- * @num_vecs: number of entries the @reg_vals array can hold
- *
- * Return: number of registers that got populated
- */
-int idpf_get_reg_intr_vecs(struct idpf_adapter *adapter,
-			   struct idpf_vec_regs *reg_vals, int num_vecs)
-{
-	struct virtchnl2_vector_chunks *chunks;
-	struct idpf_vec_regs reg_val;
-	u16 num_vchunks, num_vec;
-	int num_regs = 0, i, j;
-
-	chunks = &adapter->req_vec_chunks->vchunks;
-	num_vchunks = le16_to_cpu(chunks->num_vchunks);
-
-	for (j = 0; j < num_vchunks; j++) {
-		struct virtchnl2_vector_chunk *chunk;
-		u32 dynctl_reg_spacing;
-		u32 itrn_reg_spacing;
-
-		chunk = &chunks->vchunks[j];
-		num_vec = le16_to_cpu(chunk->num_vectors);
-		reg_val.dyn_ctl_reg = le32_to_cpu(chunk->dynctl_reg_start);
-		reg_val.itrn_reg = le32_to_cpu(chunk->itrn_reg_start);
-		reg_val.itrn_index_spacing = le32_to_cpu(chunk->itrn_index_spacing);
-
-		dynctl_reg_spacing = le32_to_cpu(chunk->dynctl_reg_spacing);
-		itrn_reg_spacing = le32_to_cpu(chunk->itrn_reg_spacing);
-
-		for (i = 0; i < num_vec && num_regs < num_vecs; i++) {
-			reg_vals[num_regs].dyn_ctl_reg = reg_val.dyn_ctl_reg;
-			reg_vals[num_regs].itrn_reg = reg_val.itrn_reg;
-			reg_vals[num_regs].itrn_index_spacing =
-						reg_val.itrn_index_spacing;
-
-			reg_val.dyn_ctl_reg += dynctl_reg_spacing;
-			reg_val.itrn_reg += itrn_reg_spacing;
-			num_regs++;
-		}
-	}
-
-	return num_regs;
-}
-
 /**
  * idpf_vport_get_q_reg - Get the queue registers for the vport
  * @reg_vals: register values needing to be set
@@ -2274,6 +2226,83 @@ int idpf_send_add_queues_msg(struct idpf_adapter *adapter,
 	return err;
 }
 
+/**
+ * idpf_create_vectors_info - Save vectors information from firmware
+ * @info: parsed information is stored here
+ * @caps: virtchannel capabilities
+ * @vectors: vector information from firmware to be parsed
+ * @num_vectors: number of vectors
+ *
+ * Returns 0 on success, negative on failure.
+ */
+static int idpf_create_vectors_info(struct idpf_irq_info *info,
+				    const struct virtchnl2_get_capabilities *caps,
+				    const struct virtchnl2_alloc_vectors *vectors,
+				    const u16 num_vectors)
+{
+	const struct virtchnl2_vector_chunks *chunks = &vectors->vchunks;
+	int all_vectors = num_vectors + IDPF_MBX_Q_VEC;
+	struct idpf_hw_vector *vector;
+	int reg_cnt;
+
+	if (le16_to_cpu(vectors->num_vectors) < num_vectors)
+		return -EINVAL;
+
+	info->vectors = kzalloc_objs(*info->vectors, num_vectors + IDPF_MBX_Q_VEC);
+	if (!info->vectors)
+		return -ENOMEM;
+	/* Mailbox irq information are stored in different places. Fill index 0
+	 * of our vectors info with capabilities and rest with information
+	 * from vector chunks.
+	 */
+	vector = &info->vectors[0];
+	vector->idx = le16_to_cpu(caps->mailbox_vector_id);
+	vector->regs.dyn_ctl = le32_to_cpu(caps->mailbox_dyn_ctl);
+	reg_cnt = IDPF_MBX_Q_VEC;
+
+	for (int i = 0; i < le16_to_cpu(chunks->num_vchunks); i++) {
+		const struct virtchnl2_vector_chunk *chunk = &chunks->vchunks[i];
+		u32 dyn_spacing, itrn_spacing;
+		struct idpf_vec_regs reg_val;
+		u16 vec_id;
+
+		reg_val.dyn_ctl = le32_to_cpu(chunk->dynctl_reg_start);
+		reg_val.itrn = le32_to_cpu(chunk->itrn_reg_start);
+		reg_val.itrn_index_spacing =
+			le32_to_cpu(chunk->itrn_index_spacing);
+
+		dyn_spacing = le32_to_cpu(chunk->dynctl_reg_spacing);
+		itrn_spacing = le32_to_cpu(chunk->itrn_reg_spacing);
+		vec_id = le16_to_cpu(chunk->start_vector_id);
+
+		for (int j = 0; j < le16_to_cpu(chunk->num_vectors); j++) {
+			if (reg_cnt >= all_vectors)
+				break;
+
+			vector = &info->vectors[reg_cnt];
+
+			vector->regs = reg_val;
+			vector->idx = vec_id;
+
+			reg_val.dyn_ctl += dyn_spacing;
+			reg_val.itrn += itrn_spacing;
+
+			vec_id += 1;
+			reg_cnt += 1;
+		}
+	}
+
+	if (reg_cnt != all_vectors) {
+		kfree(info->vectors);
+		info->vectors = NULL;
+		return -EINVAL;
+	}
+
+	info->num = num_vectors + IDPF_MBX_Q_VEC;
+
+	return 0;
+}
+
 /**
  * idpf_send_alloc_vectors_msg - Send virtchnl alloc vectors message
  * @adapter: Driver specific private structure
@@ -2318,11 +2347,10 @@ int idpf_send_alloc_vectors_msg(struct idpf_adapter *adapter, u16 num_vectors)
 		goto free_rx_buf;
 	}
 
-	if (le16_to_cpu(adapter->req_vec_chunks->num_vectors) < num_vectors) {
-		kfree(adapter->req_vec_chunks);
-		adapter->req_vec_chunks = NULL;
-		err = -EINVAL;
-	}
+	err = idpf_create_vectors_info(&adapter->irq_info, &adapter->caps,
+				       rcvd_vec, num_vectors);
+	if (err)
+		idpf_send_dealloc_vectors_msg(adapter);
 
 free_rx_buf:
 	libie_ctlq_release_rx_buf(&xn_params.recv_mem);
@@ -2346,6 +2374,11 @@ int idpf_send_dealloc_vectors_msg(struct idpf_adapter *adapter)
 	struct virtchnl2_vector_chunks *vcs;
 	int buf_size, err;
 
+	/* dealloc vectors can fail, but irq_info still needs to be cleaned */
+	kfree(adapter->irq_info.vectors);
+	adapter->irq_info.vectors = NULL;
+	adapter->irq_info.num = 0;
+
 	buf_size = struct_size(&ac->vchunks, vchunks,
 			       le16_to_cpu(ac->vchunks.num_vchunks));
 	vcs = kmemdup(&ac->vchunks, buf_size, GFP_KERNEL);
@@ -3340,51 +3373,6 @@ int idpf_vport_init(struct idpf_vport *vport, struct idpf_vport_max_q *max_q)
 	return 0;
 }
 
-/**
- * idpf_get_vec_ids - Initialize vector id from Mailbox parameters
- * @adapter: adapter structure to get the mailbox vector id
- * @vecids: Array of vector ids
- * @num_vecids: number of vector ids
- * @chunks: vector ids received over mailbox
- *
- * Will initialize the mailbox vector id which is received from the
- * get capabilities and data queue vector ids with ids received as
- * mailbox parameters.
- * Returns number of ids filled
- */
-int idpf_get_vec_ids(struct idpf_adapter *adapter,
-		     u16 *vecids, int num_vecids,
-		     struct virtchnl2_vector_chunks *chunks)
-{
-	u16 num_chunks = le16_to_cpu(chunks->num_vchunks);
-	int num_vecid_filled = 0;
-	int i, j;
-
-	vecids[num_vecid_filled] = adapter->mb_vector.v_idx;
-	num_vecid_filled++;
-
-	for (j = 0; j < num_chunks; j++) {
-		struct virtchnl2_vector_chunk *chunk;
-		u16 start_vecid, num_vec;
-
-		chunk = &chunks->vchunks[j];
-		num_vec = le16_to_cpu(chunk->num_vectors);
-		start_vecid = le16_to_cpu(chunk->start_vector_id);
-
-		for (i = 0; i < num_vec; i++) {
-			if ((num_vecid_filled + i) < num_vecids) {
-				vecids[num_vecid_filled + i] = start_vecid;
-				start_vecid++;
-			} else {
-				break;
-			}
-		}
-		num_vecid_filled = num_vecid_filled + i;
-	}
-
-	return num_vecid_filled;
-}
-
 /**
  * idpf_vport_get_queue_ids - Initialize queue id from Mailbox parameters
  * @qids: Array of queue ids
diff --git a/drivers/net/ethernet/intel/idpf/idpf_virtchnl.h b/drivers/net/ethernet/intel/idpf/idpf_virtchnl.h
index 5d27805ff40f..ec4c79191c85 100644
--- a/drivers/net/ethernet/intel/idpf/idpf_virtchnl.h
+++ b/drivers/net/ethernet/intel/idpf/idpf_virtchnl.h
@@ -10,7 +10,6 @@
 
 struct idpf_adapter;
 struct idpf_netdev_priv;
-struct idpf_vec_regs;
 struct idpf_vport;
 struct idpf_vport_max_q;
 struct idpf_vport_config;
@@ -21,8 +20,6 @@ void idpf_deinit_dflt_mbx(struct idpf_adapter *adapter);
 int idpf_vc_core_init(struct idpf_adapter *adapter);
 void idpf_vc_core_deinit(struct idpf_adapter *adapter);
 
-int idpf_get_reg_intr_vecs(struct idpf_adapter *adapter,
-			   struct idpf_vec_regs *reg_vals, int num_vecs);
 int idpf_queue_reg_init(struct idpf_vport *vport,
 			struct idpf_q_vec_rsrc *rsrc,
 			struct idpf_queue_id_reg_info *chunks);
@@ -129,9 +126,6 @@ int idpf_send_delete_queues_msg(struct idpf_adapter *adapter,
 
 int idpf_vport_alloc_vec_indexes(struct idpf_vport *vport,
 				 struct idpf_q_vec_rsrc *rsrc);
-int idpf_get_vec_ids(struct idpf_adapter *adapter,
-		     u16 *vecids, int num_vecids,
-		     struct virtchnl2_vector_chunks *chunks);
 int idpf_send_alloc_vectors_msg(struct idpf_adapter *adapter, u16 num_vectors);
 int idpf_send_dealloc_vectors_msg(struct idpf_adapter *adapter);
 int idpf_send_map_unmap_queue_vector_msg(struct idpf_adapter *adapter,
-- 
2.49.0


^ permalink raw reply related	[flat|nested] 11+ messages in thread

* [PATCH iwl-next v2 02/10] idpf: fill q_vector interrupt registers one by one
  2026-09-11 12:49 [PATCH iwl-next v2 00/10] Interrupts helper in libie Michal Swiatkowski
  2026-09-11 12:49 ` [PATCH iwl-next v2 01/10] idpf: store HW vectors information Michal Swiatkowski
@ 2026-09-11 12:49 ` Michal Swiatkowski
  2026-09-11 12:49 ` [PATCH iwl-next v2 03/10] idpf: get rid of msix_entries array Michal Swiatkowski
                   ` (7 subsequent siblings)
  9 siblings, 0 replies; 11+ messages in thread
From: Michal Swiatkowski @ 2026-09-11 12:49 UTC (permalink / raw)
  To: intel-wired-lan
  Cc: netdev, Michal Swiatkowski, Aleksandr Loktionov, Madhu Chittim

Most structures pointer used in *_intr_reg_init() are already used in
idpf_vport_intr_req_irq(). Use it by rewriting *_intr_reg_init() to
fill one q_vector in one call.

Reviewed-by: Aleksandr Loktionov <aleksandr.loktionov@intel.com>
Reviewed-by: Madhu Chittim <madhu.chittim@intel.com>
Signed-off-by: Michal Swiatkowski <michal.swiatkowski@linux.intel.com>
---
 drivers/net/ethernet/intel/idpf/idpf.h        |  7 +-
 drivers/net/ethernet/intel/idpf/idpf_dev.c    | 91 +++++++++---------
 drivers/net/ethernet/intel/idpf/idpf_txrx.c   |  7 +-
 drivers/net/ethernet/intel/idpf/idpf_vf_dev.c | 92 ++++++++++---------
 4 files changed, 105 insertions(+), 92 deletions(-)

diff --git a/drivers/net/ethernet/intel/idpf/idpf.h b/drivers/net/ethernet/intel/idpf/idpf.h
index 84b145431693..5eafabacd167 100644
--- a/drivers/net/ethernet/intel/idpf/idpf.h
+++ b/drivers/net/ethernet/intel/idpf/idpf.h
@@ -197,6 +197,7 @@ struct idpf_vport_max_q {
  * struct idpf_reg_ops - Device specific register operation function pointers
  * @ctlq_reg_init: Mailbox control queue register initialization
  * @intr_reg_init: Traffic interrupt register initialization
+ * @noirq_intr_reg_init: Vector without interrupt register initialization
  * @mb_intr_reg_init: Mailbox interrupt register initialization
  * @reset_reg_init: Reset register initialization
  * @trigger_reset: Trigger a reset to occur
@@ -205,8 +206,10 @@ struct idpf_vport_max_q {
 struct idpf_reg_ops {
 	void (*ctlq_reg_init)(struct libie_mmio_info *mmio,
 			      struct libie_ctlq_create_info *cctlq_info);
-	void (*intr_reg_init)(struct idpf_vport *vport,
-			      struct idpf_q_vec_rsrc *rsrc);
+	void (*intr_reg_init)(struct idpf_adapter *adapter,
+			      struct idpf_q_vector *q_vector, u16 idx);
+	void (*noirq_intr_reg_init)(struct idpf_adapter *adapter,
+				    struct idpf_q_vec_rsrc *rsrc, u16 idx);
 	void (*mb_intr_reg_init)(struct idpf_adapter *adapter);
 	void (*reset_reg_init)(struct idpf_adapter *adapter);
 	void (*trigger_reset)(struct idpf_adapter *adapter,
diff --git a/drivers/net/ethernet/intel/idpf/idpf_dev.c b/drivers/net/ethernet/intel/idpf/idpf_dev.c
index 42e65f1285df..cd947fd24ff6 100644
--- a/drivers/net/ethernet/intel/idpf/idpf_dev.c
+++ b/drivers/net/ethernet/intel/idpf/idpf_dev.c
@@ -58,53 +58,17 @@ static void idpf_mb_intr_reg_init(struct idpf_adapter *adapter)
 }
 
 /**
- * idpf_intr_reg_init - Initialize interrupt registers
- * @vport: virtual port structure
- * @rsrc: pointer to queue and vector resources
+ * idpf_noirq_intr_reg_init - Initialize noirq registers
+ * @adapter: adapter structure
+ * @rsrc: to store noirq register and value
+ * @idx: global software irq index used to get hardware information from
+ *	 irq_info structure
  */
-static void idpf_intr_reg_init(struct idpf_vport *vport,
-			       struct idpf_q_vec_rsrc *rsrc)
+static void idpf_noirq_intr_reg_init(struct idpf_adapter *adapter,
+				     struct idpf_q_vec_rsrc *rsrc, u16 idx)
 {
-	struct idpf_adapter *adapter = vport->adapter;
-	int num_vecs = rsrc->num_q_vectors;
-	struct libie_mmio_info *mmio;
-	u32 rx_itr, tx_itr, val;
-	int i;
-
-	mmio = &adapter->ctlq_ctx.mmio_info;
+	u32 val = adapter->irq_info.vectors[idx].regs.dyn_ctl;
 
-	for (i = 0; i < num_vecs; i++) {
-		struct idpf_q_vector *q_vector = &rsrc->q_vectors[i];
-		struct idpf_intr_reg *intr = &q_vector->intr_reg;
-		u16 vec_id = rsrc->q_vector_idxs[i];
-		struct idpf_hw_vector *v;
-		u32 spacing;
-
-		v = &adapter->irq_info.vectors[vec_id];
-
-		intr->dyn_ctl = libie_pci_get_mmio_addr(mmio, v->regs.dyn_ctl);
-		intr->dyn_ctl_intena_m = PF_GLINT_DYN_CTL_INTENA_M;
-		intr->dyn_ctl_intena_msk_m = PF_GLINT_DYN_CTL_INTENA_MSK_M;
-		intr->dyn_ctl_itridx_s = PF_GLINT_DYN_CTL_ITR_INDX_S;
-		intr->dyn_ctl_intrvl_s = PF_GLINT_DYN_CTL_INTERVAL_S;
-		intr->dyn_ctl_wb_on_itr_m = PF_GLINT_DYN_CTL_WB_ON_ITR_M;
-		intr->dyn_ctl_swint_trig_m = PF_GLINT_DYN_CTL_SWINT_TRIG_M;
-		intr->dyn_ctl_sw_itridx_ena_m =
-			PF_GLINT_DYN_CTL_SW_ITR_INDX_ENA_M;
-
-		spacing = IDPF_ITR_IDX_SPACING(v->regs.itrn_index_spacing,
-					       IDPF_PF_ITR_IDX_SPACING);
-		rx_itr = PF_GLINT_ITR_ADDR(VIRTCHNL2_ITR_IDX_0, v->regs.itrn,
-					   spacing);
-		tx_itr = PF_GLINT_ITR_ADDR(VIRTCHNL2_ITR_IDX_1, v->regs.itrn,
-					   spacing);
-		intr->rx_itr = libie_pci_get_mmio_addr(mmio, rx_itr);
-		intr->tx_itr = libie_pci_get_mmio_addr(mmio, tx_itr);
-	}
-
-	/* Data vector for NOIRQ queues */
-
-	val = adapter->irq_info.vectors[rsrc->q_vector_idxs[i]].regs.dyn_ctl;
 	rsrc->noirq_dyn_ctl =
 		libie_pci_get_mmio_addr(&adapter->ctlq_ctx.mmio_info, val);
 
@@ -113,6 +77,44 @@ static void idpf_intr_reg_init(struct idpf_vport *vport,
 	rsrc->noirq_dyn_ctl_ena = val;
 }
 
+/**
+ * idpf_intr_reg_init - Initialize interrupt registers
+ * @adapter: adapter structure
+ * @q_vector: q_vector in which the registers should be initialized
+ * @idx: global software irq index used to get hardware information from
+ *	 irq_info structure
+ */
+static void idpf_intr_reg_init(struct idpf_adapter *adapter,
+			       struct idpf_q_vector *q_vector, u16 idx)
+{
+	struct idpf_hw_vector *v = &adapter->irq_info.vectors[idx];
+	struct idpf_intr_reg *intr = &q_vector->intr_reg;
+	struct libie_mmio_info *mmio;
+	u32 rx_itr, tx_itr;
+	u32 spacing;
+
+	mmio = &adapter->ctlq_ctx.mmio_info;
+
+	intr->dyn_ctl = libie_pci_get_mmio_addr(mmio, v->regs.dyn_ctl);
+	intr->dyn_ctl_intena_m = PF_GLINT_DYN_CTL_INTENA_M;
+	intr->dyn_ctl_intena_msk_m = PF_GLINT_DYN_CTL_INTENA_MSK_M;
+	intr->dyn_ctl_itridx_s = PF_GLINT_DYN_CTL_ITR_INDX_S;
+	intr->dyn_ctl_intrvl_s = PF_GLINT_DYN_CTL_INTERVAL_S;
+	intr->dyn_ctl_wb_on_itr_m = PF_GLINT_DYN_CTL_WB_ON_ITR_M;
+	intr->dyn_ctl_swint_trig_m = PF_GLINT_DYN_CTL_SWINT_TRIG_M;
+	intr->dyn_ctl_sw_itridx_ena_m =
+		PF_GLINT_DYN_CTL_SW_ITR_INDX_ENA_M;
+
+	spacing = IDPF_ITR_IDX_SPACING(v->regs.itrn_index_spacing,
+				       IDPF_PF_ITR_IDX_SPACING);
+	rx_itr = PF_GLINT_ITR_ADDR(VIRTCHNL2_ITR_IDX_0, v->regs.itrn,
+				   spacing);
+	tx_itr = PF_GLINT_ITR_ADDR(VIRTCHNL2_ITR_IDX_1, v->regs.itrn,
+				   spacing);
+	intr->rx_itr = libie_pci_get_mmio_addr(mmio, rx_itr);
+	intr->tx_itr = libie_pci_get_mmio_addr(mmio, tx_itr);
+}
+
 /**
  * idpf_reset_reg_init - Initialize reset registers
  * @adapter: Driver specific private structure
@@ -171,6 +173,7 @@ static void idpf_reg_ops_init(struct idpf_adapter *adapter)
 {
 	adapter->dev_ops.reg_ops.ctlq_reg_init = idpf_ctlq_reg_init;
 	adapter->dev_ops.reg_ops.intr_reg_init = idpf_intr_reg_init;
+	adapter->dev_ops.reg_ops.noirq_intr_reg_init = idpf_noirq_intr_reg_init;
 	adapter->dev_ops.reg_ops.mb_intr_reg_init = idpf_mb_intr_reg_init;
 	adapter->dev_ops.reg_ops.reset_reg_init = idpf_reset_reg_init;
 	adapter->dev_ops.reg_ops.trigger_reset = idpf_trigger_reset;
diff --git a/drivers/net/ethernet/intel/idpf/idpf_txrx.c b/drivers/net/ethernet/intel/idpf/idpf_txrx.c
index 2b21f599f569..00c8fe692821 100644
--- a/drivers/net/ethernet/intel/idpf/idpf_txrx.c
+++ b/drivers/net/ethernet/intel/idpf/idpf_txrx.c
@@ -4054,6 +4054,9 @@ static int idpf_vport_intr_req_irq(struct idpf_vport *vport,
 	const char *drv_name, *if_name, *vec_name;
 	int vector, err, irq_num, vidx;
 
+	vidx = rsrc->q_vector_idxs[rsrc->num_q_vectors];
+	adapter->dev_ops.reg_ops.noirq_intr_reg_init(adapter, rsrc, vidx);
+
 	drv_name = dev_driver_string(&adapter->pdev->dev);
 	if_name = netdev_name(vport->netdev);
 
@@ -4064,6 +4067,8 @@ static int idpf_vport_intr_req_irq(struct idpf_vport *vport,
 		vidx = rsrc->q_vector_idxs[vector];
 		irq_num = adapter->msix_entries[vidx].vector;
 
+		adapter->dev_ops.reg_ops.intr_reg_init(adapter, q_vector, vidx);
+
 		if (q_vector->num_rxq && q_vector->num_txq)
 			vec_name = "TxRx";
 		else if (q_vector->num_rxq)
@@ -4649,8 +4654,6 @@ int idpf_vport_intr_init(struct idpf_vport *vport, struct idpf_q_vec_rsrc *rsrc)
 	idpf_vport_intr_map_vector_to_qs(vport, rsrc);
 	idpf_vport_intr_napi_add_all(vport, rsrc);
 
-	vport->adapter->dev_ops.reg_ops.intr_reg_init(vport, rsrc);
-
 	err = idpf_vport_intr_req_irq(vport, rsrc);
 	if (err)
 		goto unroll_vectors_alloc;
diff --git a/drivers/net/ethernet/intel/idpf/idpf_vf_dev.c b/drivers/net/ethernet/intel/idpf/idpf_vf_dev.c
index c0080842b7e2..df3eabe12b18 100644
--- a/drivers/net/ethernet/intel/idpf/idpf_vf_dev.c
+++ b/drivers/net/ethernet/intel/idpf/idpf_vf_dev.c
@@ -57,53 +57,17 @@ static void idpf_vf_mb_intr_reg_init(struct idpf_adapter *adapter)
 }
 
 /**
- * idpf_vf_intr_reg_init - Initialize interrupt registers
- * @vport: virtual port structure
- * @rsrc: pointer to queue and vector resources
+ * idpf_vf_noirq_intr_reg_init - Initialize noirq registers
+ * @adapter: adapter structure
+ * @rsrc: to store noirq register and value
+ * @idx: global software irq index used to get hardware information from
+ *	 irq_info structure
  */
-static void idpf_vf_intr_reg_init(struct idpf_vport *vport,
-				  struct idpf_q_vec_rsrc *rsrc)
+static void idpf_vf_noirq_intr_reg_init(struct idpf_adapter *adapter,
+					struct idpf_q_vec_rsrc *rsrc, u16 idx)
 {
-	struct idpf_adapter *adapter = vport->adapter;
-	int num_vecs = rsrc->num_q_vectors;
-	struct libie_mmio_info *mmio;
-	u32 rx_itr, tx_itr, val;
-	int i;
-
-	mmio = &adapter->ctlq_ctx.mmio_info;
+	u32 val = adapter->irq_info.vectors[idx].regs.dyn_ctl;
 
-	for (i = 0; i < num_vecs; i++) {
-		struct idpf_q_vector *q_vector = &rsrc->q_vectors[i];
-		struct idpf_intr_reg *intr = &q_vector->intr_reg;
-		u16 vec_id = rsrc->q_vector_idxs[i];
-		struct idpf_hw_vector *v;
-		u32 spacing;
-
-		v = &adapter->irq_info.vectors[vec_id];
-
-		intr->dyn_ctl = libie_pci_get_mmio_addr(mmio, v->regs.dyn_ctl);
-		intr->dyn_ctl_intena_m = VF_INT_DYN_CTLN_INTENA_M;
-		intr->dyn_ctl_intena_msk_m = VF_INT_DYN_CTLN_INTENA_MSK_M;
-		intr->dyn_ctl_itridx_s = VF_INT_DYN_CTLN_ITR_INDX_S;
-		intr->dyn_ctl_intrvl_s = VF_INT_DYN_CTLN_INTERVAL_S;
-		intr->dyn_ctl_wb_on_itr_m = VF_INT_DYN_CTLN_WB_ON_ITR_M;
-		intr->dyn_ctl_swint_trig_m = VF_INT_DYN_CTLN_SWINT_TRIG_M;
-		intr->dyn_ctl_sw_itridx_ena_m =
-			VF_INT_DYN_CTLN_SW_ITR_INDX_ENA_M;
-
-		spacing = IDPF_ITR_IDX_SPACING(v->regs.itrn_index_spacing,
-					       IDPF_VF_ITR_IDX_SPACING);
-		rx_itr = VF_INT_ITRN_ADDR(VIRTCHNL2_ITR_IDX_0, v->regs.itrn,
-					  spacing);
-		tx_itr = VF_INT_ITRN_ADDR(VIRTCHNL2_ITR_IDX_1, v->regs.itrn,
-					  spacing);
-		intr->rx_itr = libie_pci_get_mmio_addr(mmio, rx_itr);
-		intr->tx_itr = libie_pci_get_mmio_addr(mmio, tx_itr);
-	}
-
-	/* Data vector for NOIRQ queues */
-
-	val = adapter->irq_info.vectors[rsrc->q_vector_idxs[i]].regs.dyn_ctl;
 	rsrc->noirq_dyn_ctl =
 		libie_pci_get_mmio_addr(&adapter->ctlq_ctx.mmio_info, val);
 
@@ -112,6 +76,44 @@ static void idpf_vf_intr_reg_init(struct idpf_vport *vport,
 	rsrc->noirq_dyn_ctl_ena = val;
 }
 
+/**
+ * idpf_vf_intr_reg_init - Initialize interrupt registers
+ * @adapter: adapter structure
+ * @q_vector: q_vector in which the registers should be initialized
+ * @idx: global software irq index used to get hardware information from
+ *	 irq_info structure
+ */
+static void idpf_vf_intr_reg_init(struct idpf_adapter *adapter,
+				  struct idpf_q_vector *q_vector, u16 idx)
+{
+	struct idpf_hw_vector *v = &adapter->irq_info.vectors[idx];
+	struct idpf_intr_reg *intr = &q_vector->intr_reg;
+	struct libie_mmio_info *mmio;
+	u32 rx_itr, tx_itr;
+	u32 spacing;
+
+	mmio = &adapter->ctlq_ctx.mmio_info;
+
+	intr->dyn_ctl = libie_pci_get_mmio_addr(mmio, v->regs.dyn_ctl);
+	intr->dyn_ctl_intena_m = VF_INT_DYN_CTLN_INTENA_M;
+	intr->dyn_ctl_intena_msk_m = VF_INT_DYN_CTLN_INTENA_MSK_M;
+	intr->dyn_ctl_itridx_s = VF_INT_DYN_CTLN_ITR_INDX_S;
+	intr->dyn_ctl_intrvl_s = VF_INT_DYN_CTLN_INTERVAL_S;
+	intr->dyn_ctl_wb_on_itr_m = VF_INT_DYN_CTLN_WB_ON_ITR_M;
+	intr->dyn_ctl_swint_trig_m = VF_INT_DYN_CTLN_SWINT_TRIG_M;
+	intr->dyn_ctl_sw_itridx_ena_m =
+		VF_INT_DYN_CTLN_SW_ITR_INDX_ENA_M;
+
+	spacing = IDPF_ITR_IDX_SPACING(v->regs.itrn_index_spacing,
+				       IDPF_VF_ITR_IDX_SPACING);
+	rx_itr = VF_INT_ITRN_ADDR(VIRTCHNL2_ITR_IDX_0, v->regs.itrn,
+				  spacing);
+	tx_itr = VF_INT_ITRN_ADDR(VIRTCHNL2_ITR_IDX_1, v->regs.itrn,
+				  spacing);
+	intr->rx_itr = libie_pci_get_mmio_addr(mmio, rx_itr);
+	intr->tx_itr = libie_pci_get_mmio_addr(mmio, tx_itr);
+}
+
 /**
  * idpf_vf_reset_reg_init - Initialize reset registers
  * @adapter: Driver specific private structure
@@ -157,6 +159,8 @@ static void idpf_vf_reg_ops_init(struct idpf_adapter *adapter)
 {
 	adapter->dev_ops.reg_ops.ctlq_reg_init = idpf_vf_ctlq_reg_init;
 	adapter->dev_ops.reg_ops.intr_reg_init = idpf_vf_intr_reg_init;
+	adapter->dev_ops.reg_ops.noirq_intr_reg_init =
+		idpf_vf_noirq_intr_reg_init;
 	adapter->dev_ops.reg_ops.mb_intr_reg_init = idpf_vf_mb_intr_reg_init;
 	adapter->dev_ops.reg_ops.reset_reg_init = idpf_vf_reset_reg_init;
 	adapter->dev_ops.reg_ops.trigger_reset = idpf_vf_trigger_reset;
-- 
2.49.0


^ permalink raw reply related	[flat|nested] 11+ messages in thread

* [PATCH iwl-next v2 03/10] idpf: get rid of msix_entries array
  2026-09-11 12:49 [PATCH iwl-next v2 00/10] Interrupts helper in libie Michal Swiatkowski
  2026-09-11 12:49 ` [PATCH iwl-next v2 01/10] idpf: store HW vectors information Michal Swiatkowski
  2026-09-11 12:49 ` [PATCH iwl-next v2 02/10] idpf: fill q_vector interrupt registers one by one Michal Swiatkowski
@ 2026-09-11 12:49 ` Michal Swiatkowski
  2026-09-11 12:49 ` [PATCH iwl-next v2 04/10] idpf: drop v_idx from q_vector structure Michal Swiatkowski
                   ` (6 subsequent siblings)
  9 siblings, 0 replies; 11+ messages in thread
From: Michal Swiatkowski @ 2026-09-11 12:49 UTC (permalink / raw)
  To: intel-wired-lan
  Cc: netdev, Michal Swiatkowski, Aleksandr Loktionov, Larysa Zaremba,
	Madhu Chittim

There is no special need for storing MSI-X info in one array. Instead
move this data into q_vector where it is commonly used. With that one
layer of accessing correct kernel irq line number can be dropped.

Moving pci_irq_vector() after q_vectors creation will be useful when
switching to dynamic irq allocation.

Reviewed-by: Aleksandr Loktionov <aleksandr.loktionov@intel.com>
Reviewed-by: Larysa Zaremba <larysa.zaremba@intel.com>
Reviewed-by: Madhu Chittim <madhu.chittim@intel.com>
Signed-off-by: Michal Swiatkowski <michal.swiatkowski@linux.intel.com>
---
 drivers/net/ethernet/intel/idpf/idpf.h      |  2 -
 drivers/net/ethernet/intel/idpf/idpf_lib.c  | 45 ++++++---------
 drivers/net/ethernet/intel/idpf/idpf_txrx.c | 61 +++++++++++----------
 drivers/net/ethernet/intel/idpf/idpf_txrx.h |  5 +-
 4 files changed, 51 insertions(+), 62 deletions(-)

diff --git a/drivers/net/ethernet/intel/idpf/idpf.h b/drivers/net/ethernet/intel/idpf/idpf.h
index 5eafabacd167..86e5bb30ecc6 100644
--- a/drivers/net/ethernet/intel/idpf/idpf.h
+++ b/drivers/net/ethernet/intel/idpf/idpf.h
@@ -668,7 +668,6 @@ struct idpf_irq_info {
  * @xnm: Xn transaction manager
  * @num_avail_msix: Available number of MSIX vectors
  * @num_msix_entries: Number of entries in MSIX table
- * @msix_entries: MSIX table
  * @num_rdma_msix_entries: Available number of MSIX vectors for RDMA
  * @rdma_msix_entries: RDMA MSIX table
  * @irq_info: hardware data needed to setup irq
@@ -728,7 +727,6 @@ struct idpf_adapter {
 	struct libie_ctlq_xn_manager *xnm;
 	u16 num_avail_msix;
 	u16 num_msix_entries;
-	struct msix_entry *msix_entries;
 	u16 num_rdma_msix_entries;
 	struct msix_entry *rdma_msix_entries;
 	struct virtchnl2_alloc_vectors *req_vec_chunks;
diff --git a/drivers/net/ethernet/intel/idpf/idpf_lib.c b/drivers/net/ethernet/intel/idpf/idpf_lib.c
index 36bb6a268042..5a2975081227 100644
--- a/drivers/net/ethernet/intel/idpf/idpf_lib.c
+++ b/drivers/net/ethernet/intel/idpf/idpf_lib.c
@@ -73,7 +73,7 @@ void idpf_mb_intr_rel_irq(struct idpf_adapter *adapter)
 	if (!test_and_clear_bit(IDPF_MB_INTR_MODE, adapter->flags))
 		return;
 
-	kfree(free_irq(adapter->msix_entries[0].vector, adapter));
+	kfree(free_irq(adapter->mb_vector.irq.virq, adapter));
 	queue_delayed_work(adapter->mbx_wq, &adapter->mbx_task, 0);
 }
 
@@ -83,15 +83,10 @@ void idpf_mb_intr_rel_irq(struct idpf_adapter *adapter)
  */
 void idpf_intr_rel(struct idpf_adapter *adapter)
 {
-	if (!adapter->msix_entries)
-		return;
-
 	idpf_mb_intr_rel_irq(adapter);
 	pci_free_irq_vectors(adapter->pdev);
 	idpf_send_dealloc_vectors_msg(adapter);
 	idpf_deinit_vector_stack(adapter);
-	kfree(adapter->msix_entries);
-	adapter->msix_entries = NULL;
 	kfree(adapter->rdma_msix_entries);
 	adapter->rdma_msix_entries = NULL;
 }
@@ -130,14 +125,14 @@ static void idpf_mb_irq_enable(struct idpf_adapter *adapter)
  */
 static int idpf_mb_intr_req_irq(struct idpf_adapter *adapter)
 {
-	int irq_num, mb_vidx = 0, err;
+	struct msi_map *irq = &adapter->mb_vector.irq;
 	char *name;
+	int err;
 
-	irq_num = adapter->msix_entries[mb_vidx].vector;
 	name = kasprintf(GFP_KERNEL, "%s-%s-%d",
 			 dev_driver_string(&adapter->pdev->dev),
-			 "Mailbox", mb_vidx);
-	err = request_irq(irq_num, adapter->irq_mb_handler, 0, name, adapter);
+			 "Mailbox", irq->index);
+	err = request_irq(irq->virq, adapter->irq_mb_handler, 0, name, adapter);
 	if (err) {
 		dev_err(&adapter->pdev->dev,
 			"IRQ request for mailbox failed, error: %d\n", err);
@@ -156,6 +151,13 @@ static int idpf_mb_intr_req_irq(struct idpf_adapter *adapter)
  */
 static int idpf_mb_intr_init(struct idpf_adapter *adapter)
 {
+	struct msi_map *mb_irq = &adapter->mb_vector.irq;
+
+	mb_irq->index = IDPF_MBX_IRQ_INDEX;
+	mb_irq->virq = pci_irq_vector(adapter->pdev, mb_irq->index);
+	if (mb_irq->virq < 0)
+		return mb_irq->virq;
+
 	adapter->dev_ops.reg_ops.mb_intr_reg_init(adapter);
 	adapter->irq_mb_handler = idpf_mb_intr_clean;
 
@@ -309,7 +311,6 @@ int idpf_intr_req(struct idpf_adapter *adapter)
 	u16 default_vports = idpf_get_default_vports(adapter);
 	int min_vectors, actual_vecs, min_lan_vecs, err;
 	int num_q_vecs, total_vecs;
-	unsigned int vector;
 	int i;
 
 	total_vecs = idpf_get_reserved_vecs(adapter);
@@ -368,23 +369,12 @@ int idpf_intr_req(struct idpf_adapter *adapter)
 	}
 
 	num_lan_vecs = actual_vecs - num_rdma_vecs;
-	adapter->msix_entries = kzalloc_objs(struct msix_entry, num_lan_vecs);
-	if (!adapter->msix_entries) {
-		err = -ENOMEM;
-		goto free_rdma_msix;
-	}
 
-	for (vector = 0; vector < num_lan_vecs; vector++) {
-		adapter->msix_entries[vector].entry =
-			adapter->irq_info.vectors[vector].idx;
-		adapter->msix_entries[vector].vector =
-			pci_irq_vector(adapter->pdev, vector);
-	}
-	for (i = 0; i < num_rdma_vecs; vector++, i++) {
+	for (i = 0; i < num_rdma_vecs; i++) {
 		adapter->rdma_msix_entries[i].entry =
-			adapter->irq_info.vectors[vector].idx;
+			adapter->irq_info.vectors[num_lan_vecs + i].idx;
 		adapter->rdma_msix_entries[i].vector =
-			pci_irq_vector(adapter->pdev, vector);
+			pci_irq_vector(adapter->pdev, num_lan_vecs + i);
 	}
 
 	/* 'num_avail_msix' is used to distribute excess vectors to the vports
@@ -399,7 +389,7 @@ int idpf_intr_req(struct idpf_adapter *adapter)
 	/* Fill MSIX vector lifo stack with vector indexes */
 	err = idpf_init_vector_stack(adapter);
 	if (err)
-		goto free_msix;
+		goto free_rdma_msix;
 
 	err = idpf_mb_intr_init(adapter);
 	if (err)
@@ -410,9 +400,6 @@ int idpf_intr_req(struct idpf_adapter *adapter)
 
 deinit_vec_stack:
 	idpf_deinit_vector_stack(adapter);
-free_msix:
-	kfree(adapter->msix_entries);
-	adapter->msix_entries = NULL;
 free_rdma_msix:
 	kfree(adapter->rdma_msix_entries);
 	adapter->rdma_msix_entries = NULL;
diff --git a/drivers/net/ethernet/intel/idpf/idpf_txrx.c b/drivers/net/ethernet/intel/idpf/idpf_txrx.c
index 00c8fe692821..c75fc1fc4f64 100644
--- a/drivers/net/ethernet/intel/idpf/idpf_txrx.c
+++ b/drivers/net/ethernet/intel/idpf/idpf_txrx.c
@@ -3863,27 +3863,19 @@ static void idpf_q_vector_set_napi(struct idpf_q_vector *q_vector, bool link)
 
 /**
  * idpf_vport_intr_rel_irq - Free the IRQ association with the OS
- * @vport: main vport structure
  * @rsrc: pointer to queue and vector resources
  */
-static void idpf_vport_intr_rel_irq(struct idpf_vport *vport,
-				    struct idpf_q_vec_rsrc *rsrc)
+static void idpf_vport_intr_rel_irq(struct idpf_q_vec_rsrc *rsrc)
 {
-	struct idpf_adapter *adapter = vport->adapter;
-
-	for (u16 vector = 0; vector < rsrc->num_q_vectors; vector++) {
+	for (int vector = 0; vector < rsrc->num_q_vectors; vector++) {
 		struct idpf_q_vector *q_vector = &rsrc->q_vectors[vector];
-		int irq_num, vidx;
 
 		/* free only the irqs that were actually requested */
 		if (!q_vector)
 			continue;
 
-		vidx = rsrc->q_vector_idxs[vector];
-		irq_num = adapter->msix_entries[vidx].vector;
-
 		idpf_q_vector_set_napi(q_vector, false);
-		kfree(free_irq(irq_num, q_vector));
+		kfree(free_irq(q_vector->irq.virq, q_vector));
 	}
 }
 
@@ -4052,7 +4044,7 @@ static int idpf_vport_intr_req_irq(struct idpf_vport *vport,
 {
 	struct idpf_adapter *adapter = vport->adapter;
 	const char *drv_name, *if_name, *vec_name;
-	int vector, err, irq_num, vidx;
+	int vector, err, vidx;
 
 	vidx = rsrc->q_vector_idxs[rsrc->num_q_vectors];
 	adapter->dev_ops.reg_ops.noirq_intr_reg_init(adapter, rsrc, vidx);
@@ -4062,10 +4054,10 @@ static int idpf_vport_intr_req_irq(struct idpf_vport *vport,
 
 	for (vector = 0; vector < rsrc->num_q_vectors; vector++) {
 		struct idpf_q_vector *q_vector = &rsrc->q_vectors[vector];
+		int virq = q_vector->irq.virq;
 		char *name;
 
 		vidx = rsrc->q_vector_idxs[vector];
-		irq_num = adapter->msix_entries[vidx].vector;
 
 		adapter->dev_ops.reg_ops.intr_reg_init(adapter, q_vector, vidx);
 
@@ -4081,8 +4073,8 @@ static int idpf_vport_intr_req_irq(struct idpf_vport *vport,
 		name = kasprintf(GFP_KERNEL, "%s-%s-%s-%d", drv_name, if_name,
 				 vec_name, vector);
 
-		err = request_irq(irq_num, idpf_vport_intr_clean_queues, 0,
-				  name, q_vector);
+		err = request_irq(virq, idpf_vport_intr_clean_queues, 0, name,
+				  q_vector);
 		if (err) {
 			netdev_err(vport->netdev,
 				   "Request_irq failed, error: %d\n", err);
@@ -4096,9 +4088,9 @@ static int idpf_vport_intr_req_irq(struct idpf_vport *vport,
 
 free_q_irqs:
 	while (--vector >= 0) {
-		vidx = rsrc->q_vector_idxs[vector];
-		irq_num = adapter->msix_entries[vidx].vector;
-		kfree(free_irq(irq_num, &rsrc->q_vectors[vector]));
+		int virq = rsrc->q_vectors[vector].irq.virq;
+
+		kfree(free_irq(virq, &rsrc->q_vectors[vector]));
 	}
 
 	return err;
@@ -4194,7 +4186,7 @@ void idpf_vport_intr_deinit(struct idpf_vport *vport,
 	idpf_vport_intr_napi_dis_all(rsrc);
 	idpf_vport_intr_dis_dim_all(rsrc);
 	idpf_vport_intr_napi_del_all(rsrc);
-	idpf_vport_intr_rel_irq(vport, rsrc);
+	idpf_vport_intr_rel_irq(rsrc);
 }
 
 /**
@@ -4507,18 +4499,30 @@ static void idpf_vport_intr_map_vector_to_qs(struct idpf_vport *vport,
  * @rsrc: pointer to queue and vector resources
  *
  * Initialize vector indexes with values returned over mailbox.
+ *
+ * Return: 0 on success, negative on failure
  */
-static void idpf_vport_intr_init_vec_idx(struct idpf_vport *vport,
-					 struct idpf_q_vec_rsrc *rsrc)
+static int idpf_vport_intr_init_vec_idx(struct idpf_vport *vport,
+					struct idpf_q_vec_rsrc *rsrc)
 {
 	struct idpf_adapter *adapter = vport->adapter;
 	int i;
 
-	for (i = 0; i < rsrc->num_q_vectors; i++)
-		rsrc->q_vectors[i].v_idx =
+	for (i = 0; i < rsrc->num_q_vectors; i++) {
+		struct idpf_q_vector *q_vector = &rsrc->q_vectors[i];
+
+		q_vector->v_idx =
 			adapter->irq_info.vectors[rsrc->q_vector_idxs[i]].idx;
+		q_vector->irq.index = rsrc->q_vector_idxs[i];
+		q_vector->irq.virq = pci_irq_vector(adapter->pdev,
+						    q_vector->irq.index);
+		if (q_vector->irq.virq < 0)
+			return q_vector->irq.virq;
+	}
 
 	rsrc->noirq_v_idx = adapter->irq_info.vectors[rsrc->q_vector_idxs[i]].idx;
+
+	return 0;
 }
 
 /**
@@ -4530,8 +4534,6 @@ static void idpf_vport_intr_napi_add_all(struct idpf_vport *vport,
 					 struct idpf_q_vec_rsrc *rsrc)
 {
 	int (*napi_poll)(struct napi_struct *napi, int budget);
-	int irq_num;
-	u16 qv_idx;
 
 	if (idpf_is_queue_model_split(rsrc->txq_model))
 		napi_poll = idpf_vport_splitq_napi_poll;
@@ -4541,12 +4543,9 @@ static void idpf_vport_intr_napi_add_all(struct idpf_vport *vport,
 	for (u16 v_idx = 0; v_idx < rsrc->num_q_vectors; v_idx++) {
 		struct idpf_q_vector *q_vector = &rsrc->q_vectors[v_idx];
 
-		qv_idx = rsrc->q_vector_idxs[v_idx];
-		irq_num = vport->adapter->msix_entries[qv_idx].vector;
-
 		netif_napi_add_config(vport->netdev, &q_vector->napi,
 				      napi_poll, v_idx);
-		netif_napi_set_irq(&q_vector->napi, irq_num);
+		netif_napi_set_irq(&q_vector->napi, q_vector->irq.virq);
 	}
 }
 
@@ -4649,7 +4648,9 @@ int idpf_vport_intr_init(struct idpf_vport *vport, struct idpf_q_vec_rsrc *rsrc)
 {
 	int err;
 
-	idpf_vport_intr_init_vec_idx(vport, rsrc);
+	err = idpf_vport_intr_init_vec_idx(vport, rsrc);
+	if (err)
+		return err;
 
 	idpf_vport_intr_map_vector_to_qs(vport, rsrc);
 	idpf_vport_intr_napi_add_all(vport, rsrc);
diff --git a/drivers/net/ethernet/intel/idpf/idpf_txrx.h b/drivers/net/ethernet/intel/idpf/idpf_txrx.h
index ecff84df776d..57e61936ffda 100644
--- a/drivers/net/ethernet/intel/idpf/idpf_txrx.h
+++ b/drivers/net/ethernet/intel/idpf/idpf_txrx.h
@@ -6,6 +6,7 @@
 
 #include <linux/dim.h>
 #include <linux/net/intel/virtchnl2_lan_desc.h>
+#include <linux/pci.h>
 
 #include <net/libeth/cache.h>
 #include <net/libeth/types.h>
@@ -377,6 +378,7 @@ struct idpf_intr_reg {
  * @rx_intr_mode: Dynamic ITR or not
  * @rx_itr_idx: RX ITR index
  * @v_idx: Vector index
+ * @irq: kernel and driver irq numbers
  */
 struct idpf_q_vector {
 	__cacheline_group_begin_aligned(read_mostly);
@@ -418,12 +420,13 @@ struct idpf_q_vector {
 	__cacheline_group_begin_aligned(cold);
 	u16 v_idx;
 
+	struct msi_map irq;
 	__cacheline_group_end_aligned(cold);
 };
 libeth_cacheline_set_assert(struct idpf_q_vector, 136,
 			    56 + sizeof(struct napi_struct) +
 			    2 * sizeof(struct dim),
-			    8);
+			    8 + sizeof(struct msi_map));
 
 struct idpf_rx_queue_stats {
 	u64_stats_t packets;
-- 
2.49.0


^ permalink raw reply related	[flat|nested] 11+ messages in thread

* [PATCH iwl-next v2 04/10] idpf: drop v_idx from q_vector structure
  2026-09-11 12:49 [PATCH iwl-next v2 00/10] Interrupts helper in libie Michal Swiatkowski
                   ` (2 preceding siblings ...)
  2026-09-11 12:49 ` [PATCH iwl-next v2 03/10] idpf: get rid of msix_entries array Michal Swiatkowski
@ 2026-09-11 12:49 ` Michal Swiatkowski
  2026-09-11 12:49 ` [PATCH iwl-next v2 05/10] libie, idpf: move irq code to libie Michal Swiatkowski
                   ` (5 subsequent siblings)
  9 siblings, 0 replies; 11+ messages in thread
From: Michal Swiatkowski @ 2026-09-11 12:49 UTC (permalink / raw)
  To: intel-wired-lan
  Cc: netdev, Michal Swiatkowski, Larysa Zaremba, Aleksandr Loktionov

Storing another index related to irq in q_vector can be misleading. It
is only used when matching q_vectors with queues. It can be obtained
using 0-based software irq index.

Use irq.index (from q_vector) and get the hardware irq index
(q_vector->v_idx earlier) from irq_info structure.

Reviewed-by: Larysa Zaremba <larysa.zaremba@intel.com>
Reviewed-by: Aleksandr Loktionov <aleksandr.loktionov@intel.com>
Signed-off-by: Michal Swiatkowski <michal.swiatkowski@linux.intel.com>
---
 drivers/net/ethernet/intel/idpf/idpf.h          |  2 +-
 drivers/net/ethernet/intel/idpf/idpf_txrx.c     |  4 +---
 drivers/net/ethernet/intel/idpf/idpf_txrx.h     |  5 +----
 drivers/net/ethernet/intel/idpf/idpf_virtchnl.c | 11 +++++++----
 4 files changed, 10 insertions(+), 12 deletions(-)

diff --git a/drivers/net/ethernet/intel/idpf/idpf.h b/drivers/net/ethernet/intel/idpf/idpf.h
index 86e5bb30ecc6..785d551c795d 100644
--- a/drivers/net/ethernet/intel/idpf/idpf.h
+++ b/drivers/net/ethernet/intel/idpf/idpf.h
@@ -301,7 +301,7 @@ struct idpf_fsteer_fltr {
  * @q_vectors: array of queue vectors
  * @q_vector_idxs: starting index of queue vectors
  * @num_q_vectors: number of IRQ vectors allocated
- * @noirq_v_idx: ID of the NOIRQ vector
+ * @noirq_v_idx: software IRQ index used to get hardware vector information
  * @noirq_dyn_ctl_ena: value to write to the above to enable it
  * @noirq_dyn_ctl: register to enable/disable the vector for NOIRQ queues
  * @txq_grps: array of TX queue groups
diff --git a/drivers/net/ethernet/intel/idpf/idpf_txrx.c b/drivers/net/ethernet/intel/idpf/idpf_txrx.c
index c75fc1fc4f64..2a3dd04ebe23 100644
--- a/drivers/net/ethernet/intel/idpf/idpf_txrx.c
+++ b/drivers/net/ethernet/intel/idpf/idpf_txrx.c
@@ -4511,8 +4511,6 @@ static int idpf_vport_intr_init_vec_idx(struct idpf_vport *vport,
 	for (i = 0; i < rsrc->num_q_vectors; i++) {
 		struct idpf_q_vector *q_vector = &rsrc->q_vectors[i];
 
-		q_vector->v_idx =
-			adapter->irq_info.vectors[rsrc->q_vector_idxs[i]].idx;
 		q_vector->irq.index = rsrc->q_vector_idxs[i];
 		q_vector->irq.virq = pci_irq_vector(adapter->pdev,
 						    q_vector->irq.index);
@@ -4520,7 +4518,7 @@ static int idpf_vport_intr_init_vec_idx(struct idpf_vport *vport,
 			return q_vector->irq.virq;
 	}
 
-	rsrc->noirq_v_idx = adapter->irq_info.vectors[rsrc->q_vector_idxs[i]].idx;
+	rsrc->noirq_v_idx = rsrc->q_vector_idxs[i];
 
 	return 0;
 }
diff --git a/drivers/net/ethernet/intel/idpf/idpf_txrx.h b/drivers/net/ethernet/intel/idpf/idpf_txrx.h
index 57e61936ffda..9a2e3665277f 100644
--- a/drivers/net/ethernet/intel/idpf/idpf_txrx.h
+++ b/drivers/net/ethernet/intel/idpf/idpf_txrx.h
@@ -377,7 +377,6 @@ struct idpf_intr_reg {
  * @rx_itr_value: RX interrupt throttling rate
  * @rx_intr_mode: Dynamic ITR or not
  * @rx_itr_idx: RX ITR index
- * @v_idx: Vector index
  * @irq: kernel and driver irq numbers
  */
 struct idpf_q_vector {
@@ -418,15 +417,13 @@ struct idpf_q_vector {
 	__cacheline_group_end_aligned(read_write);
 
 	__cacheline_group_begin_aligned(cold);
-	u16 v_idx;
-
 	struct msi_map irq;
 	__cacheline_group_end_aligned(cold);
 };
 libeth_cacheline_set_assert(struct idpf_q_vector, 136,
 			    56 + sizeof(struct napi_struct) +
 			    2 * sizeof(struct dim),
-			    8 + sizeof(struct msi_map));
+			    sizeof(struct msi_map));
 
 struct idpf_rx_queue_stats {
 	u64_stats_t packets;
diff --git a/drivers/net/ethernet/intel/idpf/idpf_virtchnl.c b/drivers/net/ethernet/intel/idpf/idpf_virtchnl.c
index 267ac9fa3846..90f3c40c7928 100644
--- a/drivers/net/ethernet/intel/idpf/idpf_virtchnl.c
+++ b/drivers/net/ethernet/intel/idpf/idpf_virtchnl.c
@@ -1848,12 +1848,14 @@ idpf_prep_map_unmap_queue_set_vector_msg(u32 vport_id, void *buf,
  * idpf_send_map_unmap_queue_set_vector_msg - send virtchnl map or unmap
  *					      queue set vector message
  * @qs: set of the queues to map or unmap
+ * @info: interrupts info to map software index to firmware one
  * @map: true for map and false for unmap
  *
  * Return: 0 on success, -errno on failure.
  */
 static int
 idpf_send_map_unmap_queue_set_vector_msg(const struct idpf_queue_set *qs,
+					 const struct idpf_irq_info *info,
 					 bool map)
 {
 	struct virtchnl2_queue_vector *vqv __free(kfree) = NULL;
@@ -1893,7 +1895,7 @@ idpf_send_map_unmap_queue_set_vector_msg(const struct idpf_queue_set *qs,
 				vec = q->rxq->q_vector;
 
 			if (vec) {
-				v_idx = vec->v_idx;
+				v_idx = vec->irq.index;
 				itr_idx = vec->rx_itr_idx;
 			} else {
 				v_idx = qs->qv_rsrc->noirq_v_idx;
@@ -1913,7 +1915,7 @@ idpf_send_map_unmap_queue_set_vector_msg(const struct idpf_queue_set *qs,
 				vec = q->txq->q_vector;
 
 			if (vec) {
-				v_idx = vec->v_idx;
+				v_idx = vec->irq.index;
 				itr_idx = vec->tx_itr_idx;
 			} else {
 				v_idx = qs->qv_rsrc->noirq_v_idx;
@@ -1925,7 +1927,7 @@ idpf_send_map_unmap_queue_set_vector_msg(const struct idpf_queue_set *qs,
 		}
 
 		vqv[i].queue_id = cpu_to_le32(qid);
-		vqv[i].vector_id = cpu_to_le16(v_idx);
+		vqv[i].vector_id = cpu_to_le16(info->vectors[v_idx].idx);
 		vqv[i].itr_idx = cpu_to_le32(itr_idx);
 	}
 
@@ -1989,7 +1991,8 @@ int idpf_send_map_unmap_queue_vector_msg(struct idpf_adapter *adapter,
 	if (k != num_q)
 		return -EINVAL;
 
-	return idpf_send_map_unmap_queue_set_vector_msg(qs, map);
+	return idpf_send_map_unmap_queue_set_vector_msg(qs, &adapter->irq_info,
+							map);
 }
 
 /**
-- 
2.49.0


^ permalink raw reply related	[flat|nested] 11+ messages in thread

* [PATCH iwl-next v2 05/10] libie, idpf: move irq code to libie
  2026-09-11 12:49 [PATCH iwl-next v2 00/10] Interrupts helper in libie Michal Swiatkowski
                   ` (3 preceding siblings ...)
  2026-09-11 12:49 ` [PATCH iwl-next v2 04/10] idpf: drop v_idx from q_vector structure Michal Swiatkowski
@ 2026-09-11 12:49 ` Michal Swiatkowski
  2026-09-11 12:49 ` [PATCH iwl-next v2 06/10] libie, idpf: move hardware irq info struct " Michal Swiatkowski
                   ` (4 subsequent siblings)
  9 siblings, 0 replies; 11+ messages in thread
From: Michal Swiatkowski @ 2026-09-11 12:49 UTC (permalink / raw)
  To: intel-wired-lan
  Cc: netdev, Michal Swiatkowski, Aleksandr Loktionov, Larysa Zaremba

Management of irqs is the same in idpf and ixd driver. Move the common
code to separate lib to reuse it in ixd.

libie_irq keeps the allocated interrupts in an xarray split into two
index ranges: LIBIE_IRQ_STATIC for the vectors that must exist for the
device to be functional at all (mailbox, the minimum per default vport,
RDMA), and LIBIE_IRQ_DYNAMIC for the rest.

libie_irq_init() allocates the static range with pci_alloc_irq_vectors()
at probe.  When the platform supports post-enable MSI-X allocation,
libie_irq_alloc() backs the dynamic range with pci_msix_alloc_irq_at()
on demand, so vectors are only claimed once a vport actually needs them;
when it does not, the whole range is allocated up front and
LIBIE_IRQ_DYNAMIC is transparently served from the static pool.

libie_irq_reserve() hands out an index without an MSI-X vector behind it,
for queues that are mapped to a vector but never raise an interrupt
(the idpf NOIRQ vector used by XDP send queues).

Move getting irq slot before allocating q_vectors array. Alloc only
q_vectors for which there is an available interrupt.

Allocating more lead to the situation where there are unused q_vector
which can be confused.

Reviewed-by: Aleksandr Loktionov <aleksandr.loktionov@intel.com>
Reviewed-by: Larysa Zaremba <larysa.zaremba@intel.com>
Signed-off-by: Michal Swiatkowski <michal.swiatkowski@linux.intel.com>
---
 drivers/net/ethernet/intel/idpf/Kconfig       |   1 +
 drivers/net/ethernet/intel/idpf/idpf.h        |  74 +---
 drivers/net/ethernet/intel/idpf/idpf_idc.c    |   6 +-
 drivers/net/ethernet/intel/idpf/idpf_lib.c    | 382 ++++++------------
 drivers/net/ethernet/intel/idpf/idpf_main.c   |   3 +-
 drivers/net/ethernet/intel/idpf/idpf_txrx.c   | 104 +++--
 drivers/net/ethernet/intel/idpf/idpf_txrx.h   |   2 +-
 .../net/ethernet/intel/idpf/idpf_virtchnl.c   |  45 +--
 .../net/ethernet/intel/idpf/idpf_virtchnl.h   |   3 +-
 drivers/net/ethernet/intel/libie/Kconfig      |   6 +
 drivers/net/ethernet/intel/libie/Makefile     |   4 +
 drivers/net/ethernet/intel/libie/irq.c        | 256 ++++++++++++
 include/linux/net/intel/libie/irq.h           |  75 ++++
 13 files changed, 560 insertions(+), 401 deletions(-)
 create mode 100644 drivers/net/ethernet/intel/libie/irq.c
 create mode 100644 include/linux/net/intel/libie/irq.h

diff --git a/drivers/net/ethernet/intel/idpf/Kconfig b/drivers/net/ethernet/intel/idpf/Kconfig
index 586df3a4afe9..6e21e4749904 100644
--- a/drivers/net/ethernet/intel/idpf/Kconfig
+++ b/drivers/net/ethernet/intel/idpf/Kconfig
@@ -8,6 +8,7 @@ config IDPF
 	select DIMLIB
 	select LIBIE_CP
 	select LIBETH_XDP
+	select LIBIE_IRQ
 	help
 	  This driver supports Intel(R) Infrastructure Data Path Function
 	  devices.
diff --git a/drivers/net/ethernet/intel/idpf/idpf.h b/drivers/net/ethernet/intel/idpf/idpf.h
index 785d551c795d..51f447135693 100644
--- a/drivers/net/ethernet/intel/idpf/idpf.h
+++ b/drivers/net/ethernet/intel/idpf/idpf.h
@@ -24,6 +24,7 @@ struct idpf_rss_data;
 #include <linux/net/intel/iidc_rdma.h>
 #include <linux/net/intel/iidc_rdma_idpf.h>
 #include <linux/net/intel/libie/controlq.h>
+#include <linux/net/intel/libie/irq.h>
 #include <linux/net/intel/virtchnl2.h>
 
 #include "idpf_txrx.h"
@@ -299,7 +300,6 @@ struct idpf_fsteer_fltr {
  * struct idpf_q_vec_rsrc - handle for queue and vector resources
  * @dev: device pointer for DMA mapping
  * @q_vectors: array of queue vectors
- * @q_vector_idxs: starting index of queue vectors
  * @num_q_vectors: number of IRQ vectors allocated
  * @noirq_v_idx: software IRQ index used to get hardware vector information
  * @noirq_dyn_ctl_ena: value to write to the above to enable it
@@ -328,7 +328,6 @@ struct idpf_fsteer_fltr {
 struct idpf_q_vec_rsrc {
 	struct device		*dev;
 	struct idpf_q_vector	*q_vectors;
-	u16			*q_vector_idxs;
 	u16			num_q_vectors;
 	u16			noirq_v_idx;
 	u32			noirq_dyn_ctl_ena;
@@ -526,46 +525,6 @@ struct idpf_avail_queue_info {
 	u16 avail_complq;
 };
 
-/**
- * struct idpf_vector_info - Utility structure to pass function arguments as a
- *			     structure
- * @num_req_vecs: Vectors required based on the number of queues updated by the
- *		  user via ethtool
- * @num_curr_vecs: Current number of vectors, must be >= @num_req_vecs
- * @index: Relative starting index for vectors
- * @default_vport: Vectors are for default vport
- */
-struct idpf_vector_info {
-	u16 num_req_vecs;
-	u16 num_curr_vecs;
-	u16 index;
-	bool default_vport;
-};
-
-/**
- * struct idpf_vector_lifo - Stack to maintain vector indexes used for vector
- *			     distribution algorithm
- * @top: Points to stack top i.e. next available vector index
- * @base: Always points to start of the free pool
- * @size: Total size of the vector stack
- * @vec_idx: Array to store all the vector indexes
- *
- * Vector stack maintains all the relative vector indexes at the *adapter*
- * level. This stack is divided into 2 parts, first one is called as 'default
- * pool' and other one is called 'free pool'.  Vector distribution algorithm
- * gives priority to default vports in a way that at least IDPF_MIN_Q_VEC
- * vectors are allocated per default vport and the relative vector indexes for
- * those are maintained in default pool. Free pool contains all the unallocated
- * vector indexes which can be allocated on-demand basis. Mailbox vector index
- * is maintained in the default pool of the stack.
- */
-struct idpf_vector_lifo {
-	u16 top;
-	u16 base;
-	u16 size;
-	u16 *vec_idx;
-};
-
 /**
  * struct idpf_queue_id_reg_chunk - individual queue ID and register chunk
  * @qtail_reg_start: queue tail register offset
@@ -652,6 +611,18 @@ struct idpf_irq_info {
 	int num;
 };
 
+/**
+ * struct idpf_rdma_irq - RDMA interrupt vectors data
+ * @entries: MSIX table shared with the RDMA auxiliary device
+ * @map: libie IRQ mappings corresponding to @entries
+ * @num: number of vectors granted for RDMA
+ */
+struct idpf_rdma_irq {
+	struct msix_entry *entries;
+	struct msi_map *map;
+	u16 num;
+};
+
 /**
  * struct idpf_adapter - Device data struct generated on probe
  * @pdev: PCI device struct given on probe
@@ -666,14 +637,11 @@ struct idpf_irq_info {
  * @asq: Send control queue info
  * @arq: Receive control queue info
  * @xnm: Xn transaction manager
- * @num_avail_msix: Available number of MSIX vectors
- * @num_msix_entries: Number of entries in MSIX table
- * @num_rdma_msix_entries: Available number of MSIX vectors for RDMA
- * @rdma_msix_entries: RDMA MSIX table
+ * @rdma_irq: RDMA interrupt vectors data
+ * @irq: libie irq structure
  * @irq_info: hardware data needed to setup irq
  * @req_vec_chunks: Requested vector chunk data
  * @mb_vector: Mailbox vector data
- * @vector_stack: Stack to store the msix vector indexes
  * @irq_mb_handler: Handler for hard interrupt for mailbox
  * @tx_timeout_count: Number of TX timeouts that have occurred
  * @avail_queues: Device given queue limits
@@ -706,7 +674,6 @@ struct idpf_irq_info {
  * @req_tx_splitq: TX split or single queue model to request
  * @req_rx_splitq: RX split or single queue model to request
  * @vport_ctrl_lock: Lock to protect the vport control flow
- * @vector_lock: Lock to protect vector distribution
  * @queue_lock: Lock to protect queue distribution
  * @vc_buf_lock: Lock to protect virtchnl buffer
  * @ptp: Storage for PTP-related data
@@ -725,14 +692,11 @@ struct idpf_adapter {
 	struct libie_ctlq_info *asq;
 	struct libie_ctlq_info *arq;
 	struct libie_ctlq_xn_manager *xnm;
-	u16 num_avail_msix;
-	u16 num_msix_entries;
-	u16 num_rdma_msix_entries;
-	struct msix_entry *rdma_msix_entries;
+	struct idpf_rdma_irq rdma_irq;
+	struct libie_irq irq;
 	struct virtchnl2_alloc_vectors *req_vec_chunks;
 	struct idpf_irq_info irq_info;
 	struct idpf_q_vector mb_vector;
-	struct idpf_vector_lifo vector_stack;
 	irqreturn_t (*irq_mb_handler)(int irq, void *data);
 
 	u32 tx_timeout_count;
@@ -770,7 +734,6 @@ struct idpf_adapter {
 	bool req_rx_splitq;
 
 	struct mutex vport_ctrl_lock;
-	struct mutex vector_lock;
 	struct mutex queue_lock;
 	struct mutex vc_buf_lock;
 
@@ -1031,9 +994,6 @@ u16 idpf_get_max_tx_hdr_size(struct idpf_adapter *adapter);
 int idpf_initiate_soft_reset(struct idpf_vport *vport,
 			     enum idpf_vport_reset_cause reset_cause);
 void idpf_deinit_task(struct idpf_adapter *adapter);
-int idpf_req_rel_vector_indexes(struct idpf_adapter *adapter,
-				u16 *q_vector_idxs,
-				struct idpf_vector_info *vec_info);
 void idpf_set_ethtool_ops(struct net_device *netdev);
 void idpf_vport_intr_write_itr(struct idpf_q_vector *q_vector,
 			       u16 itr, bool tx);
diff --git a/drivers/net/ethernet/intel/idpf/idpf_idc.c b/drivers/net/ethernet/intel/idpf/idpf_idc.c
index b6cd1c25ae5d..5d15bef6eec3 100644
--- a/drivers/net/ethernet/intel/idpf/idpf_idc.c
+++ b/drivers/net/ethernet/intel/idpf/idpf_idc.c
@@ -396,14 +396,14 @@ idpf_idc_init_msix_data(struct idpf_adapter *adapter)
 	struct iidc_rdma_core_dev_info *cdev_info;
 	struct iidc_rdma_priv_dev_info *privd;
 
-	if (!adapter->rdma_msix_entries)
+	if (!adapter->rdma_irq.entries)
 		return;
 
 	cdev_info = adapter->cdev_info;
 	privd = cdev_info->iidc_priv;
 
-	privd->msix_entries = adapter->rdma_msix_entries;
-	privd->msix_count = adapter->num_rdma_msix_entries;
+	privd->msix_entries = adapter->rdma_irq.entries;
+	privd->msix_count = adapter->rdma_irq.num;
 }
 
 /**
diff --git a/drivers/net/ethernet/intel/idpf/idpf_lib.c b/drivers/net/ethernet/intel/idpf/idpf_lib.c
index 5a2975081227..ddd1dff391e0 100644
--- a/drivers/net/ethernet/intel/idpf/idpf_lib.c
+++ b/drivers/net/ethernet/intel/idpf/idpf_lib.c
@@ -9,56 +9,85 @@
 
 static const struct net_device_ops idpf_netdev_ops;
 
-/**
- * idpf_init_vector_stack - Fill the MSIX vector stack with vector index
- * @adapter: private data struct
- *
- * Return 0 on success, error on failure
- */
-static int idpf_init_vector_stack(struct idpf_adapter *adapter)
+static int idpf_rdma_intr_init(struct idpf_adapter *adapter, u16 num)
 {
-	struct idpf_vector_lifo *stack;
-	u16 min_vec;
-	u32 i;
-
-	mutex_lock(&adapter->vector_lock);
-	min_vec = adapter->num_msix_entries - adapter->num_avail_msix;
-	stack = &adapter->vector_stack;
-	stack->size = adapter->num_msix_entries;
-	/* set the base and top to point at start of the 'free pool' to
-	 * distribute the unused vectors on-demand basis
-	 */
-	stack->base = min_vec;
-	stack->top = min_vec;
+	struct idpf_rdma_irq *rdma_irq = &adapter->rdma_irq;
+	int i;
 
-	stack->vec_idx = kcalloc(stack->size, sizeof(u16), GFP_KERNEL);
-	if (!stack->vec_idx) {
-		mutex_unlock(&adapter->vector_lock);
+	if (!idpf_is_rdma_cap_ena(adapter))
+		return 0;
 
+	rdma_irq->entries = kzalloc_objs(struct msix_entry, num);
+	if (!rdma_irq->entries)
 		return -ENOMEM;
+
+	rdma_irq->map = kzalloc_objs(struct msi_map, num);
+	if (!rdma_irq->map) {
+		kfree(rdma_irq->entries);
+		rdma_irq->entries = NULL;
+
+		return -ENOMEM;
+	}
+
+	for (i = 0; i < min(IDPF_MIN_RDMA_VEC, num); i++) {
+		struct msi_map map = libie_irq_alloc(&adapter->irq,
+						     LIBIE_IRQ_STATIC);
+		if (map.index < 0) {
+			for (int j = i - 1; j >= 0; j--)
+				libie_irq_free(&adapter->irq, rdma_irq->map[j]);
+
+			kfree(rdma_irq->map);
+			rdma_irq->map = NULL;
+			kfree(rdma_irq->entries);
+			rdma_irq->entries = NULL;
+
+			return -EINVAL;
+		}
+
+		rdma_irq->map[i] = map;
+		rdma_irq->entries[i].entry =
+			adapter->irq_info.vectors[map.index].idx;
+		rdma_irq->entries[i].vector = map.virq;
+	}
+	for (; i < num; i++) {
+		struct msi_map map = libie_irq_alloc(&adapter->irq,
+						     LIBIE_IRQ_DYNAMIC);
+
+		/* Lower number of entries if alloc fails. */
+		if (map.index < 0)
+			break;
+
+		rdma_irq->map[i] = map;
+		rdma_irq->entries[i].entry =
+			adapter->irq_info.vectors[map.index].idx;
+		rdma_irq->entries[i].vector = map.virq;
 	}
 
-	for (i = 0; i < stack->size; i++)
-		stack->vec_idx[i] = i;
+	rdma_irq->num = i;
 
-	mutex_unlock(&adapter->vector_lock);
+	if (i != num)
+		dev_warn(&adapter->pdev->dev,
+			 "Warning: %d RDMA vectors requested, %d granted\n",
+			 num, i);
 
 	return 0;
 }
 
-/**
- * idpf_deinit_vector_stack - zero out the MSIX vector stack
- * @adapter: private data struct
- */
-static void idpf_deinit_vector_stack(struct idpf_adapter *adapter)
+static void idpf_rdma_intr_free(struct idpf_adapter *adapter)
 {
-	struct idpf_vector_lifo *stack;
+	struct idpf_rdma_irq *rdma_irq = &adapter->rdma_irq;
+
+	if (!idpf_is_rdma_cap_ena(adapter))
+		return;
+
+	for (int i = 0; i < rdma_irq->num; i++)
+		libie_irq_free(&adapter->irq, rdma_irq->map[i]);
 
-	mutex_lock(&adapter->vector_lock);
-	stack = &adapter->vector_stack;
-	kfree(stack->vec_idx);
-	stack->vec_idx = NULL;
-	mutex_unlock(&adapter->vector_lock);
+	kfree(rdma_irq->map);
+	rdma_irq->map = NULL;
+	kfree(rdma_irq->entries);
+	rdma_irq->entries = NULL;
+	rdma_irq->num = 0;
 }
 
 /**
@@ -74,6 +103,7 @@ void idpf_mb_intr_rel_irq(struct idpf_adapter *adapter)
 		return;
 
 	kfree(free_irq(adapter->mb_vector.irq.virq, adapter));
+	libie_irq_free(&adapter->irq, adapter->mb_vector.irq);
 	queue_delayed_work(adapter->mbx_wq, &adapter->mbx_task, 0);
 }
 
@@ -84,11 +114,9 @@ void idpf_mb_intr_rel_irq(struct idpf_adapter *adapter)
 void idpf_intr_rel(struct idpf_adapter *adapter)
 {
 	idpf_mb_intr_rel_irq(adapter);
-	pci_free_irq_vectors(adapter->pdev);
+	idpf_rdma_intr_free(adapter);
+	libie_irq_deinit(&adapter->irq);
 	idpf_send_dealloc_vectors_msg(adapter);
-	idpf_deinit_vector_stack(adapter);
-	kfree(adapter->rdma_msix_entries);
-	adapter->rdma_msix_entries = NULL;
 }
 
 /**
@@ -151,152 +179,22 @@ static int idpf_mb_intr_req_irq(struct idpf_adapter *adapter)
  */
 static int idpf_mb_intr_init(struct idpf_adapter *adapter)
 {
-	struct msi_map *mb_irq = &adapter->mb_vector.irq;
+	struct idpf_q_vector *mb_vector = &adapter->mb_vector;
+	int err;
+
+	mb_vector->irq = libie_irq_alloc(&adapter->irq, LIBIE_IRQ_STATIC);
 
-	mb_irq->index = IDPF_MBX_IRQ_INDEX;
-	mb_irq->virq = pci_irq_vector(adapter->pdev, mb_irq->index);
-	if (mb_irq->virq < 0)
-		return mb_irq->virq;
+	if (mb_vector->irq.index < 0)
+		return mb_vector->irq.index;
 
 	adapter->dev_ops.reg_ops.mb_intr_reg_init(adapter);
 	adapter->irq_mb_handler = idpf_mb_intr_clean;
 
-	return idpf_mb_intr_req_irq(adapter);
-}
-
-/**
- * idpf_vector_lifo_push - push MSIX vector index onto stack
- * @adapter: private data struct
- * @vec_idx: vector index to store
- */
-static int idpf_vector_lifo_push(struct idpf_adapter *adapter, u16 vec_idx)
-{
-	struct idpf_vector_lifo *stack = &adapter->vector_stack;
-
-	lockdep_assert_held(&adapter->vector_lock);
-
-	if (stack->top == stack->base) {
-		dev_err(&adapter->pdev->dev, "Exceeded the vector stack limit: %d\n",
-			stack->top);
-		return -EINVAL;
-	}
-
-	stack->vec_idx[--stack->top] = vec_idx;
-
-	return 0;
-}
-
-/**
- * idpf_vector_lifo_pop - pop MSIX vector index from stack
- * @adapter: private data struct
- */
-static int idpf_vector_lifo_pop(struct idpf_adapter *adapter)
-{
-	struct idpf_vector_lifo *stack = &adapter->vector_stack;
-
-	lockdep_assert_held(&adapter->vector_lock);
-
-	if (stack->top == stack->size) {
-		dev_err(&adapter->pdev->dev, "No interrupt vectors are available to distribute!\n");
-
-		return -EINVAL;
-	}
-
-	return stack->vec_idx[stack->top++];
-}
-
-/**
- * idpf_vector_stash - Store the vector indexes onto the stack
- * @adapter: private data struct
- * @q_vector_idxs: vector index array
- * @vec_info: info related to the number of vectors
- *
- * This function is a no-op if there are no vectors indexes to be stashed
- */
-static void idpf_vector_stash(struct idpf_adapter *adapter, u16 *q_vector_idxs,
-			      struct idpf_vector_info *vec_info)
-{
-	int i, base = 0;
-	u16 vec_idx;
-
-	lockdep_assert_held(&adapter->vector_lock);
-
-	if (!vec_info->num_curr_vecs)
-		return;
-
-	/* For default vports, no need to stash vector allocated from the
-	 * default pool onto the stack
-	 */
-	if (vec_info->default_vport)
-		base = IDPF_MIN_Q_VEC;
-
-	for (i = vec_info->num_curr_vecs - 1; i >= base ; i--) {
-		vec_idx = q_vector_idxs[i];
-		idpf_vector_lifo_push(adapter, vec_idx);
-		adapter->num_avail_msix++;
-	}
-}
-
-/**
- * idpf_req_rel_vector_indexes - Request or release MSIX vector indexes
- * @adapter: driver specific private structure
- * @q_vector_idxs: vector index array
- * @vec_info: info related to the number of vectors
- *
- * This is the core function to distribute the MSIX vectors acquired from the
- * OS. It expects the caller to pass the number of vectors required and
- * also previously allocated. First, it stashes previously allocated vector
- * indexes on to the stack and then figures out if it can allocate requested
- * vectors. It can wait on acquiring the mutex lock. If the caller passes 0 as
- * requested vectors, then this function just stashes the already allocated
- * vectors and returns 0.
- *
- * Returns actual number of vectors allocated on success, error value on failure
- * If 0 is returned, implies the stack has no vectors to allocate which is also
- * a failure case for the caller
- */
-int idpf_req_rel_vector_indexes(struct idpf_adapter *adapter,
-				u16 *q_vector_idxs,
-				struct idpf_vector_info *vec_info)
-{
-	u16 num_req_vecs, num_alloc_vecs = 0, max_vecs;
-	struct idpf_vector_lifo *stack;
-	int i, j, vecid;
-
-	mutex_lock(&adapter->vector_lock);
-	stack = &adapter->vector_stack;
-	num_req_vecs = vec_info->num_req_vecs;
-
-	/* Stash interrupt vector indexes onto the stack if required */
-	idpf_vector_stash(adapter, q_vector_idxs, vec_info);
-
-	if (!num_req_vecs)
-		goto rel_lock;
-
-	if (vec_info->default_vport) {
-		/* As IDPF_MIN_Q_VEC per default vport is put aside in the
-		 * default pool of the stack, use them for default vports
-		 */
-		j = vec_info->index * IDPF_MIN_Q_VEC + IDPF_MBX_Q_VEC;
-		for (i = 0; i < IDPF_MIN_Q_VEC; i++) {
-			q_vector_idxs[num_alloc_vecs++] = stack->vec_idx[j++];
-			num_req_vecs--;
-		}
-	}
-
-	/* Find if stack has enough vector to allocate */
-	max_vecs = min(adapter->num_avail_msix, num_req_vecs);
-
-	for (j = 0; j < max_vecs; j++) {
-		vecid = idpf_vector_lifo_pop(adapter);
-		q_vector_idxs[num_alloc_vecs++] = vecid;
-	}
-	adapter->num_avail_msix -= max_vecs;
-
-rel_lock:
-	mutex_unlock(&adapter->vector_lock);
+	err = idpf_mb_intr_req_irq(adapter);
+	if (err)
+		libie_irq_free(&adapter->irq, mb_vector->irq);
 
-	return num_alloc_vecs;
+	return err;
 }
 
 /**
@@ -307,26 +205,24 @@ int idpf_req_rel_vector_indexes(struct idpf_adapter *adapter,
  */
 int idpf_intr_req(struct idpf_adapter *adapter)
 {
-	int num_rdma_vecs = 0, min_rdma_vecs = 0, num_lan_vecs = 0;
 	u16 default_vports = idpf_get_default_vports(adapter);
-	int min_vectors, actual_vecs, min_lan_vecs, err;
-	int num_q_vecs, total_vecs;
-	int i;
+	int num_q_vecs, total_vecs, static_vecs;
+	struct libie_irq *irq = &adapter->irq;
+	int num_rdma_vecs = 0;
+	int err;
 
 	total_vecs = idpf_get_reserved_vecs(adapter);
 	if (idpf_is_rdma_cap_ena(adapter)) {
 		num_rdma_vecs = idpf_get_reserved_rdma_vecs(adapter);
-		min_rdma_vecs = IDPF_MIN_RDMA_VEC;
-
 		if (!num_rdma_vecs) {
 			/* If idpf_get_reserved_rdma_vecs is 0, vectors are
 			 * pulled from the LAN pool.
 			 */
-			num_rdma_vecs = min_rdma_vecs;
-		} else if (num_rdma_vecs < min_rdma_vecs) {
+			num_rdma_vecs = IDPF_MIN_RDMA_VEC;
+		} else if (num_rdma_vecs < IDPF_MIN_RDMA_VEC) {
 			dev_err(&adapter->pdev->dev,
 				"Not enough vectors reserved for RDMA (min: %u, current: %u)\n",
-				min_rdma_vecs, num_rdma_vecs);
+				IDPF_MIN_RDMA_VEC, num_rdma_vecs);
 			return -EINVAL;
 		}
 	}
@@ -341,70 +237,32 @@ int idpf_intr_req(struct idpf_adapter *adapter)
 		return -EAGAIN;
 	}
 
-	min_lan_vecs = IDPF_MBX_Q_VEC + IDPF_MIN_Q_VEC * default_vports;
-	min_vectors = min_lan_vecs + min_rdma_vecs;
-	actual_vecs = pci_alloc_irq_vectors(adapter->pdev, min_vectors,
-					    total_vecs, PCI_IRQ_MSIX);
-	if (actual_vecs < 0) {
-		dev_err(&adapter->pdev->dev, "Failed to allocate minimum MSIX vectors required: %d\n",
-			min_vectors);
-		err = actual_vecs;
+	static_vecs = IDPF_MBX_Q_VEC + IDPF_MIN_Q_VEC * default_vports +
+		      min(IDPF_MIN_RDMA_VEC, num_rdma_vecs);
+	err = libie_irq_init(irq, adapter->pdev, static_vecs, total_vecs);
+	if (err) {
+		dev_err(&adapter->pdev->dev, "Failed to allocate MSIX vectors: %d\n",
+			err);
+		err = -EAGAIN;
 		goto send_dealloc_vecs;
 	}
 
-	if (idpf_is_rdma_cap_ena(adapter)) {
-		if (actual_vecs < total_vecs) {
-			dev_warn(&adapter->pdev->dev,
-				 "Warning: %d vectors requested, only %d available. Defaulting to minimum (%d) for RDMA and remaining for LAN.\n",
-				 total_vecs, actual_vecs, IDPF_MIN_RDMA_VEC);
-			num_rdma_vecs = IDPF_MIN_RDMA_VEC;
-		}
-
-		adapter->rdma_msix_entries = kzalloc_objs(struct msix_entry,
-							  num_rdma_vecs);
-		if (!adapter->rdma_msix_entries) {
-			err = -ENOMEM;
-			goto free_irq;
-		}
-	}
-
-	num_lan_vecs = actual_vecs - num_rdma_vecs;
-
-	for (i = 0; i < num_rdma_vecs; i++) {
-		adapter->rdma_msix_entries[i].entry =
-			adapter->irq_info.vectors[num_lan_vecs + i].idx;
-		adapter->rdma_msix_entries[i].vector =
-			pci_irq_vector(adapter->pdev, num_lan_vecs + i);
-	}
-
-	/* 'num_avail_msix' is used to distribute excess vectors to the vports
-	 * after considering the minimum vectors required per each default
-	 * vport
-	 */
-	adapter->num_avail_msix = num_lan_vecs - min_lan_vecs;
-	adapter->num_msix_entries = num_lan_vecs;
-	if (idpf_is_rdma_cap_ena(adapter))
-		adapter->num_rdma_msix_entries = num_rdma_vecs;
-
-	/* Fill MSIX vector lifo stack with vector indexes */
-	err = idpf_init_vector_stack(adapter);
+	err = idpf_mb_intr_init(adapter);
 	if (err)
-		goto free_rdma_msix;
+		goto free_irq;
 
-	err = idpf_mb_intr_init(adapter);
+	err = idpf_rdma_intr_init(adapter, num_rdma_vecs);
 	if (err)
-		goto deinit_vec_stack;
+		goto free_mb_irq;
+
 	idpf_mb_irq_enable(adapter);
 
 	return 0;
 
-deinit_vec_stack:
-	idpf_deinit_vector_stack(adapter);
-free_rdma_msix:
-	kfree(adapter->rdma_msix_entries);
-	adapter->rdma_msix_entries = NULL;
+free_mb_irq:
+	idpf_mb_intr_rel_irq(adapter);
 free_irq:
-	pci_free_irq_vectors(adapter->pdev);
+	libie_irq_deinit(irq);
 send_dealloc_vecs:
 	idpf_send_dealloc_vectors_msg(adapter);
 
@@ -986,7 +844,7 @@ static void idpf_vport_stop(struct idpf_vport *vport, bool rtnl)
 	idpf_vport_intr_deinit(vport, rsrc);
 	idpf_xdp_rxq_info_deinit_all(rsrc);
 	idpf_vport_queues_rel(vport, rsrc);
-	idpf_vport_intr_rel(rsrc);
+	idpf_vport_intr_rel(rsrc, &adapter->irq);
 	clear_bit(IDPF_VPORT_UP, np->state);
 
 	if (rtnl)
@@ -1042,10 +900,8 @@ static void idpf_decfg_netdev(struct idpf_vport *vport)
  */
 static void idpf_vport_rel(struct idpf_vport *vport)
 {
-	struct idpf_q_vec_rsrc *rsrc = &vport->dflt_qv_rsrc;
 	struct idpf_adapter *adapter = vport->adapter;
 	struct idpf_vport_config *vport_config;
-	struct idpf_vector_info vec_info;
 	struct idpf_rss_data *rss_data;
 	struct idpf_vport_max_q max_q;
 	u16 idx = vport->idx;
@@ -1065,16 +921,6 @@ static void idpf_vport_rel(struct idpf_vport *vport)
 	max_q.max_complq = vport_config->max_q.max_complq;
 	idpf_vport_dealloc_max_qs(adapter, &max_q);
 
-	/* Release all the allocated vectors on the stack */
-	vec_info.num_req_vecs = 0;
-	vec_info.num_curr_vecs = rsrc->num_q_vectors;
-	vec_info.default_vport = vport->default_vport;
-
-	idpf_req_rel_vector_indexes(adapter, rsrc->q_vector_idxs, &vec_info);
-
-	kfree(rsrc->q_vector_idxs);
-	rsrc->q_vector_idxs = NULL;
-
 	idpf_vport_deinit_queue_reg_chunks(vport_config);
 
 	kfree(adapter->vport_params_recvd[idx]);
@@ -1196,8 +1042,8 @@ static struct idpf_vport *idpf_vport_alloc(struct idpf_adapter *adapter,
 					   struct idpf_vport_max_q *max_q)
 {
 	struct idpf_rss_data *rss_data;
-	u16 idx = adapter->next_vport;
 	struct idpf_q_vec_rsrc *rsrc;
+	u16 idx = adapter->next_vport;
 	struct idpf_vport *vport;
 	u16 num_max_q;
 	int err;
@@ -1247,13 +1093,10 @@ static struct idpf_vport *idpf_vport_alloc(struct idpf_adapter *adapter,
 
 	rsrc = &vport->dflt_qv_rsrc;
 	rsrc->dev = &adapter->pdev->dev;
-	rsrc->q_vector_idxs = kcalloc(num_max_q, sizeof(u16), GFP_KERNEL);
-	if (!rsrc->q_vector_idxs)
-		goto free_vport;
 
 	err = idpf_vport_init(vport, max_q);
 	if (err)
-		goto free_vector_idxs;
+		goto free_vport;
 
 	/* LUT and key are both initialized here. Key is not strictly dependent
 	 * on how many queues we have. If we change number of queues and soft
@@ -1264,7 +1107,7 @@ static struct idpf_vport *idpf_vport_alloc(struct idpf_adapter *adapter,
 	rss_data = &adapter->vport_config[idx]->user_config.rss_data;
 	rss_data->rss_key = kzalloc(rss_data->rss_key_size, GFP_KERNEL);
 	if (!rss_data->rss_key)
-		goto free_qreg_chunks;
+		goto deinit_vport_queues;
 
 	/* Initialize default RSS key */
 	netdev_rss_key_fill((void *)rss_data->rss_key, rss_data->rss_key_size);
@@ -1287,10 +1130,8 @@ static struct idpf_vport *idpf_vport_alloc(struct idpf_adapter *adapter,
 free_rss_key:
 	kfree(rss_data->rss_key);
 	rss_data->rss_key = NULL;
-free_qreg_chunks:
+deinit_vport_queues:
 	idpf_vport_deinit_queue_reg_chunks(adapter->vport_config[idx]);
-free_vector_idxs:
-	kfree(rsrc->q_vector_idxs);
 free_vport:
 	kfree(vport);
 
@@ -1485,6 +1326,12 @@ static int idpf_vport_open(struct idpf_vport *vport, bool rtnl)
 	/* we do not allow interface up just yet */
 	netif_carrier_off(vport->netdev);
 
+	/*
+	 * num_q_vectors can be lowered by previous open/close cycle or
+	 * error during open. Reset it back to default value. Still can be
+	 * changed when there is not enough interrupts available.
+	 */
+	idpf_vport_set_num_q_vectors(rsrc, vport->num_xdp_txq);
 	err = idpf_vport_intr_alloc(vport, rsrc);
 	if (err) {
 		dev_err(&adapter->pdev->dev, "Failed to allocate interrupts for vport %u: %d\n",
@@ -1599,7 +1446,7 @@ static int idpf_vport_open(struct idpf_vport *vport, bool rtnl)
 queues_rel:
 	idpf_vport_queues_rel(vport, rsrc);
 intr_rel:
-	idpf_vport_intr_rel(rsrc);
+	idpf_vport_intr_rel(rsrc, &adapter->irq);
 
 err_rtnl_unlock:
 	if (rtnl)
@@ -2062,7 +1909,8 @@ int idpf_initiate_soft_reset(struct idpf_vport *vport,
 	memcpy(vport, new_vport, offsetof(struct idpf_vport, link_up));
 
 	if (reset_cause == IDPF_SR_Q_CHANGE)
-		idpf_vport_alloc_vec_indexes(vport, &vport->dflt_qv_rsrc);
+		idpf_vport_set_num_q_vectors(&vport->dflt_qv_rsrc,
+					     vport->num_xdp_txq);
 
 	err = idpf_set_real_num_queues(vport);
 	if (err)
diff --git a/drivers/net/ethernet/intel/idpf/idpf_main.c b/drivers/net/ethernet/intel/idpf/idpf_main.c
index 1e4dd9b713a0..e27ad0e6e4e6 100644
--- a/drivers/net/ethernet/intel/idpf/idpf_main.c
+++ b/drivers/net/ethernet/intel/idpf/idpf_main.c
@@ -18,6 +18,7 @@ MODULE_IMPORT_NS("LIBETH");
 MODULE_IMPORT_NS("LIBIE_CP");
 MODULE_IMPORT_NS("LIBIE_PCI");
 MODULE_IMPORT_NS("LIBETH_XDP");
+MODULE_IMPORT_NS("LIBIE_IRQ");
 MODULE_LICENSE("GPL");
 
 /**
@@ -177,7 +178,6 @@ static void idpf_remove(struct pci_dev *pdev)
 	adapter->netdevs = NULL;
 
 	mutex_destroy(&adapter->vport_ctrl_lock);
-	mutex_destroy(&adapter->vector_lock);
 	mutex_destroy(&adapter->queue_lock);
 	mutex_destroy(&adapter->vc_buf_lock);
 
@@ -338,7 +338,6 @@ static int idpf_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
 	adapter->msg_enable = netif_msg_init(-1, IDPF_AVAIL_NETIF_M);
 
 	mutex_init(&adapter->vport_ctrl_lock);
-	mutex_init(&adapter->vector_lock);
 	mutex_init(&adapter->queue_lock);
 	mutex_init(&adapter->vc_buf_lock);
 
diff --git a/drivers/net/ethernet/intel/idpf/idpf_txrx.c b/drivers/net/ethernet/intel/idpf/idpf_txrx.c
index 2a3dd04ebe23..a75d4cc35013 100644
--- a/drivers/net/ethernet/intel/idpf/idpf_txrx.c
+++ b/drivers/net/ethernet/intel/idpf/idpf_txrx.c
@@ -3823,14 +3823,18 @@ static void idpf_vport_intr_napi_dis_all(struct idpf_q_vec_rsrc *rsrc)
 /**
  * idpf_vport_intr_rel - Free memory allocated for interrupt vectors
  * @rsrc: pointer to queue and vector resources
+ * @irq: libie_irq structure to be passed to libie_irq_free()
  *
  * Free the memory allocated for interrupt vectors  associated to a vport
  */
-void idpf_vport_intr_rel(struct idpf_q_vec_rsrc *rsrc)
+void idpf_vport_intr_rel(struct idpf_q_vec_rsrc *rsrc, struct libie_irq *irq)
 {
+	libie_put_irq(irq, rsrc->noirq_v_idx);
+
 	for (u16 v_idx = 0; v_idx < rsrc->num_q_vectors; v_idx++) {
 		struct idpf_q_vector *q_vector = &rsrc->q_vectors[v_idx];
 
+		libie_irq_free(irq, q_vector->irq);
 		kfree(q_vector->xsksq);
 		q_vector->xsksq = NULL;
 		kfree(q_vector->complq);
@@ -3863,15 +3867,17 @@ static void idpf_q_vector_set_napi(struct idpf_q_vector *q_vector, bool link)
 
 /**
  * idpf_vport_intr_rel_irq - Free the IRQ association with the OS
+ * @vport: main vport structure
  * @rsrc: pointer to queue and vector resources
  */
-static void idpf_vport_intr_rel_irq(struct idpf_q_vec_rsrc *rsrc)
+static void idpf_vport_intr_rel_irq(struct idpf_vport *vport,
+				    struct idpf_q_vec_rsrc *rsrc)
 {
 	for (int vector = 0; vector < rsrc->num_q_vectors; vector++) {
 		struct idpf_q_vector *q_vector = &rsrc->q_vectors[vector];
 
 		/* free only the irqs that were actually requested */
-		if (!q_vector)
+		if (!q_vector->irq.virq)
 			continue;
 
 		idpf_q_vector_set_napi(q_vector, false);
@@ -4044,10 +4050,10 @@ static int idpf_vport_intr_req_irq(struct idpf_vport *vport,
 {
 	struct idpf_adapter *adapter = vport->adapter;
 	const char *drv_name, *if_name, *vec_name;
-	int vector, err, vidx;
+	int vector, err;
 
-	vidx = rsrc->q_vector_idxs[rsrc->num_q_vectors];
-	adapter->dev_ops.reg_ops.noirq_intr_reg_init(adapter, rsrc, vidx);
+	adapter->dev_ops.reg_ops.noirq_intr_reg_init(adapter, rsrc,
+						     rsrc->noirq_v_idx);
 
 	drv_name = dev_driver_string(&adapter->pdev->dev);
 	if_name = netdev_name(vport->netdev);
@@ -4057,9 +4063,8 @@ static int idpf_vport_intr_req_irq(struct idpf_vport *vport,
 		int virq = q_vector->irq.virq;
 		char *name;
 
-		vidx = rsrc->q_vector_idxs[vector];
-
-		adapter->dev_ops.reg_ops.intr_reg_init(adapter, q_vector, vidx);
+		adapter->dev_ops.reg_ops.intr_reg_init(adapter, q_vector,
+						       q_vector->irq.index);
 
 		if (q_vector->num_rxq && q_vector->num_txq)
 			vec_name = "TxRx";
@@ -4186,7 +4191,7 @@ void idpf_vport_intr_deinit(struct idpf_vport *vport,
 	idpf_vport_intr_napi_dis_all(rsrc);
 	idpf_vport_intr_dis_dim_all(rsrc);
 	idpf_vport_intr_napi_del_all(rsrc);
-	idpf_vport_intr_rel_irq(rsrc);
+	idpf_vport_intr_rel_irq(vport, rsrc);
 }
 
 /**
@@ -4496,31 +4501,38 @@ static void idpf_vport_intr_map_vector_to_qs(struct idpf_vport *vport,
 /**
  * idpf_vport_intr_init_vec_idx - Initialize the vector indexes
  * @vport: virtual port
- * @rsrc: pointer to queue and vector resources
+ * @tmp_irqs: place to store reserved irqs number
+ * @num_vec: number of q_vectors
  *
- * Initialize vector indexes with values returned over mailbox.
+ * Initialize vector indexes with values returned from libie_irq
  *
- * Return: 0 on success, negative on failure
+ * Return: number of initialized vectors, or negative value in case of error
  */
 static int idpf_vport_intr_init_vec_idx(struct idpf_vport *vport,
-					struct idpf_q_vec_rsrc *rsrc)
+					struct msi_map *tmp_irqs, u16 num_vec)
 {
 	struct idpf_adapter *adapter = vport->adapter;
 	int i;
 
-	for (i = 0; i < rsrc->num_q_vectors; i++) {
-		struct idpf_q_vector *q_vector = &rsrc->q_vectors[i];
+	for (i = 0; i < num_vec; i++) {
+		if (vport->default_vport && i == 0) {
+			tmp_irqs[i] = libie_irq_alloc(&adapter->irq,
+						      LIBIE_IRQ_STATIC);
+			if (tmp_irqs[i].index < 0)
+				return tmp_irqs[i].index;
+			continue;
+		}
 
-		q_vector->irq.index = rsrc->q_vector_idxs[i];
-		q_vector->irq.virq = pci_irq_vector(adapter->pdev,
-						    q_vector->irq.index);
-		if (q_vector->irq.virq < 0)
-			return q_vector->irq.virq;
+		tmp_irqs[i] = libie_irq_alloc(&adapter->irq, LIBIE_IRQ_DYNAMIC);
+		/* not crucial if there is already allocated irq */
+		if (tmp_irqs[i].index < 0) {
+			if (i == 0)
+				return tmp_irqs[i].index;
+			break;
+		}
 	}
 
-	rsrc->noirq_v_idx = rsrc->q_vector_idxs[i];
-
-	return 0;
+	return i;
 }
 
 /**
@@ -4561,17 +4573,49 @@ int idpf_vport_intr_alloc(struct idpf_vport *vport,
 {
 	u16 txqs_per_vector, rxqs_per_vector, bufqs_per_vector;
 	struct idpf_vport_user_config_data *user_config;
+	struct idpf_adapter *adapter = vport->adapter;
 	struct idpf_q_vector *q_vector;
 	struct idpf_q_coalesce *q_coal;
+	struct msi_map *tmp_irqs;
+	int irqs, i, noirq_v_idx;
 	u32 complqs_per_vector;
 	u16 idx = vport->idx;
 
-	user_config = &vport->adapter->vport_config[idx]->user_config;
+	user_config = &adapter->vport_config[idx]->user_config;
 
+	tmp_irqs = kzalloc_objs(struct msi_map, rsrc->num_q_vectors);
+	if (!tmp_irqs)
+		return -ENOMEM;
+
+	noirq_v_idx = libie_irq_reserve(&adapter->irq);
+	if (noirq_v_idx < 0) {
+		kfree(tmp_irqs);
+		return noirq_v_idx;
+	}
+
+	rsrc->noirq_v_idx = noirq_v_idx;
+
+	irqs = idpf_vport_intr_init_vec_idx(vport, tmp_irqs,
+					    rsrc->num_q_vectors);
+	if (irqs < 0) {
+		libie_put_irq(&adapter->irq, rsrc->noirq_v_idx);
+		kfree(tmp_irqs);
+		return irqs;
+	}
+
+	rsrc->num_q_vectors = irqs;
 	rsrc->q_vectors = kzalloc_objs(struct idpf_q_vector,
 				       rsrc->num_q_vectors);
-	if (!rsrc->q_vectors)
+	if (!rsrc->q_vectors) {
+		libie_put_irq(&adapter->irq, rsrc->noirq_v_idx);
+		for (i = 0; i < rsrc->num_q_vectors; i++)
+			libie_irq_free(&adapter->irq, tmp_irqs[i]);
+		kfree(tmp_irqs);
 		return -ENOMEM;
+	}
+
+	for (i = 0; i < rsrc->num_q_vectors; i++)
+		rsrc->q_vectors[i].irq = tmp_irqs[i];
 
 	txqs_per_vector = DIV_ROUND_UP(rsrc->num_txq_grp,
 				       rsrc->num_q_vectors);
@@ -4627,10 +4671,12 @@ int idpf_vport_intr_alloc(struct idpf_vport *vport,
 			goto error;
 	}
 
+	kfree(tmp_irqs);
 	return 0;
 
 error:
-	idpf_vport_intr_rel(rsrc);
+	idpf_vport_intr_rel(rsrc, &adapter->irq);
+	kfree(tmp_irqs);
 
 	return -ENOMEM;
 }
@@ -4646,10 +4692,6 @@ int idpf_vport_intr_init(struct idpf_vport *vport, struct idpf_q_vec_rsrc *rsrc)
 {
 	int err;
 
-	err = idpf_vport_intr_init_vec_idx(vport, rsrc);
-	if (err)
-		return err;
-
 	idpf_vport_intr_map_vector_to_qs(vport, rsrc);
 	idpf_vport_intr_napi_add_all(vport, rsrc);
 
diff --git a/drivers/net/ethernet/intel/idpf/idpf_txrx.h b/drivers/net/ethernet/intel/idpf/idpf_txrx.h
index 9a2e3665277f..f40a0a67d7ea 100644
--- a/drivers/net/ethernet/intel/idpf/idpf_txrx.h
+++ b/drivers/net/ethernet/intel/idpf/idpf_txrx.h
@@ -1079,7 +1079,7 @@ int idpf_vport_queues_alloc(struct idpf_vport *vport,
 			    struct idpf_q_vec_rsrc *rsrc);
 void idpf_vport_queues_rel(struct idpf_vport *vport,
 			   struct idpf_q_vec_rsrc *rsrc);
-void idpf_vport_intr_rel(struct idpf_q_vec_rsrc *rsrc);
+void idpf_vport_intr_rel(struct idpf_q_vec_rsrc *rsrc, struct libie_irq *irq);
 int idpf_vport_intr_alloc(struct idpf_vport *vport,
 			  struct idpf_q_vec_rsrc *rsrc);
 void idpf_vport_intr_update_itr_ena_irq(struct idpf_q_vector *q_vector);
diff --git a/drivers/net/ethernet/intel/idpf/idpf_virtchnl.c b/drivers/net/ethernet/intel/idpf/idpf_virtchnl.c
index 90f3c40c7928..65ddc6f893fc 100644
--- a/drivers/net/ethernet/intel/idpf/idpf_virtchnl.c
+++ b/drivers/net/ethernet/intel/idpf/idpf_virtchnl.c
@@ -2251,7 +2251,7 @@ static int idpf_create_vectors_info(struct idpf_irq_info *info,
 	if (le16_to_cpu(vectors->num_vectors) < num_vectors)
 		return -EINVAL;
 
-	info->vectors = kzalloc_objs(*info->vectors, num_vectors + IDPF_MBX_Q_VEC);
+	info->vectors = kzalloc_objs(*info->vectors, all_vectors);
 	if (!info->vectors)
 		return -ENOMEM;
 	/* Mailbox irq information are stored in different places. Fill index 0
@@ -3257,47 +3257,16 @@ void idpf_vc_core_deinit(struct idpf_adapter *adapter)
 }
 
 /**
- * idpf_vport_alloc_vec_indexes - Get relative vector indexes
- * @vport: virtual port data struct
+ * idpf_vport_set_num_q_vectors - Set the number of vectors
  * @rsrc: pointer to queue and vector resources
+ * @xdpqs: number of noirq queues (XDP)
  *
- * This function requests the vector information required for the vport and
- * stores the vector indexes received from the 'global vector distribution'
- * in the vport's queue vectors array.
- *
- * Return: 0 on success, error on failure
+ * This function set the number of q_vectors for the vport.
  */
-int idpf_vport_alloc_vec_indexes(struct idpf_vport *vport,
-				 struct idpf_q_vec_rsrc *rsrc)
+void idpf_vport_set_num_q_vectors(struct idpf_q_vec_rsrc *rsrc, u16 xdpqs)
 {
-	struct idpf_vector_info vec_info;
-	int num_alloc_vecs;
-	u32 req;
-
-	vec_info.num_curr_vecs = rsrc->num_q_vectors;
-	if (vec_info.num_curr_vecs)
-		vec_info.num_curr_vecs += IDPF_RESERVED_VECS;
-
 	/* XDPSQs are all bound to the NOIRQ vector from IDPF_RESERVED_VECS */
-	req = max(rsrc->num_txq - vport->num_xdp_txq, rsrc->num_rxq) +
-	      IDPF_RESERVED_VECS;
-	vec_info.num_req_vecs = req;
-
-	vec_info.default_vport = vport->default_vport;
-	vec_info.index = vport->idx;
-
-	num_alloc_vecs = idpf_req_rel_vector_indexes(vport->adapter,
-						     rsrc->q_vector_idxs,
-						     &vec_info);
-	if (num_alloc_vecs <= 0) {
-		dev_err(&vport->adapter->pdev->dev, "Vector distribution failed: %d\n",
-			num_alloc_vecs);
-		return -EINVAL;
-	}
-
-	rsrc->num_q_vectors = num_alloc_vecs - IDPF_RESERVED_VECS;
-
-	return 0;
+	rsrc->num_q_vectors = max(rsrc->num_txq - xdpqs, rsrc->num_rxq);
 }
 
 /**
@@ -3356,7 +3325,7 @@ int idpf_vport_init(struct idpf_vport *vport, struct idpf_vport_max_q *max_q)
 	idpf_vport_init_num_qs(vport, vport_msg, rsrc);
 	idpf_vport_calc_num_q_desc(vport, rsrc);
 	idpf_vport_calc_num_q_groups(rsrc);
-	idpf_vport_alloc_vec_indexes(vport, rsrc);
+	idpf_vport_set_num_q_vectors(rsrc, vport->num_xdp_txq);
 
 	vport->crc_enable = adapter->crc_enable;
 
diff --git a/drivers/net/ethernet/intel/idpf/idpf_virtchnl.h b/drivers/net/ethernet/intel/idpf/idpf_virtchnl.h
index ec4c79191c85..8fad35a8c64c 100644
--- a/drivers/net/ethernet/intel/idpf/idpf_virtchnl.h
+++ b/drivers/net/ethernet/intel/idpf/idpf_virtchnl.h
@@ -124,8 +124,7 @@ int idpf_send_delete_queues_msg(struct idpf_adapter *adapter,
 				struct idpf_queue_id_reg_info *chunks,
 				u32 vport_id);
 
-int idpf_vport_alloc_vec_indexes(struct idpf_vport *vport,
-				 struct idpf_q_vec_rsrc *rsrc);
+void idpf_vport_set_num_q_vectors(struct idpf_q_vec_rsrc *rsrc, u16 xdpqs);
 int idpf_send_alloc_vectors_msg(struct idpf_adapter *adapter, u16 num_vectors);
 int idpf_send_dealloc_vectors_msg(struct idpf_adapter *adapter);
 int idpf_send_map_unmap_queue_vector_msg(struct idpf_adapter *adapter,
diff --git a/drivers/net/ethernet/intel/libie/Kconfig b/drivers/net/ethernet/intel/libie/Kconfig
index 9c5fdebb6766..47fb77191604 100644
--- a/drivers/net/ethernet/intel/libie/Kconfig
+++ b/drivers/net/ethernet/intel/libie/Kconfig
@@ -37,3 +37,9 @@ config LIBIE_PCI
 	help
 	  Helper functions for management of PCI resources belonging
 	  to networking devices.
+
+config LIBIE_IRQ
+	tristate
+	help
+	  Helpers used to manage irqs by drivers, take care of managing static
+	  and dynamic interrupts, using xarray to store irqs and track usage.
diff --git a/drivers/net/ethernet/intel/libie/Makefile b/drivers/net/ethernet/intel/libie/Makefile
index 3065aa057798..380af47398d8 100644
--- a/drivers/net/ethernet/intel/libie/Makefile
+++ b/drivers/net/ethernet/intel/libie/Makefile
@@ -20,3 +20,7 @@ libie_fwlog-y			:= fwlog.o
 obj-$(CONFIG_LIBIE_PCI)		+= libie_pci.o
 
 libie_pci-y			:= pci.o
+
+obj-$(CONFIG_LIBIE_IRQ)		+= libie_irq.o
+
+libie_irq-y			:= irq.o
diff --git a/drivers/net/ethernet/intel/libie/irq.c b/drivers/net/ethernet/intel/libie/irq.c
new file mode 100644
index 000000000000..0f73f8becefb
--- /dev/null
+++ b/drivers/net/ethernet/intel/libie/irq.c
@@ -0,0 +1,256 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/* Copyright (C) 2025 Intel Corporation */
+
+#include <linux/net/intel/libie/irq.h>
+
+/**
+ * libie_irq_init - init irq for whole device
+ * @irq: pointer to libie_irq structure
+ * @pdev: pdev which interrupts is used
+ * @min: number of static interrupts
+ * @max: max - min is the number of dynamic interrupts
+ *
+ * Function will call pci_alloc_irq_vectors(). Minimum vectors value is a number
+ * of LIBIE_IRQ_STATIC. It means that if there is no enough interrupts for
+ * all static interrupts this function will return -ENOSPC.
+ *
+ * If there is no support for dynamic interrupts allocation
+ * pci_alloc_irq_vectors() is called with max value, otherwise max is equal to
+ * min. There is no need to change the limits values for LIBIE_IRQ_DYNAMIC.
+ * The libie_irq_alloc() function is changing the LIBIE_IRQ_DYNAMIC to
+ * LIBIE_IRQ_STATIC when there is no such support. User of this helpers doesn't
+ * have to think if there is dynamic support or there isn't.
+ *
+ * Limits' max is the last index that can be used. Assuming 0 index is valid
+ * (which is true here) there is need to subtract one from the number of
+ * interrupts.
+ * Ex. min = 5 -> limits.min = 0, limits.max = 4; indexes 0, 1, 2, 3, 4
+ *
+ * Return: 0 in case of success otherwise -ENOSPC or -EINVAL when called
+ *         with min == 0
+ */
+int libie_irq_init(struct libie_irq *irq, struct pci_dev *pdev,
+		   int min, int max)
+{
+	int vectors;
+
+	/* At least one static vector needs to be allocated */
+	if (!min || min > max)
+		return -EINVAL;
+
+	irq->limits[LIBIE_IRQ_STATIC].min = 0;
+	irq->limits[LIBIE_IRQ_STATIC].max = min - 1;
+	irq->limits[LIBIE_IRQ_DYNAMIC].min = min;
+	irq->limits[LIBIE_IRQ_DYNAMIC].max = max - 1;
+
+	if (!pci_msix_can_alloc_dyn(pdev))
+		irq->limits[LIBIE_IRQ_STATIC].max = max - 1;
+	else
+		/* max can be lowered, as rest can be allocated dynamically */
+		max = min;
+
+	vectors = pci_alloc_irq_vectors(pdev, min, max, PCI_IRQ_MSIX);
+	if (vectors < 0)
+		return vectors;
+
+	/* static vectors needs to be lowered if there is not enough irqs */
+	if (irq->limits[LIBIE_IRQ_STATIC].max + 1 > vectors)
+		irq->limits[LIBIE_IRQ_STATIC].max = vectors - 1;
+
+	irq->pdev = pdev;
+	xa_init_flags(&irq->entries, XA_FLAGS_ALLOC);
+
+	return 0;
+}
+EXPORT_SYMBOL_NS_GPL(libie_irq_init, "LIBIE_IRQ");
+
+/**
+ * libie_irq_deinit - deinit irq initialized by libie_irq_init()
+ * @irq: libie_irq stored in driver data
+ *
+ * Should be called after all irqs are cleaned by libie_put_irq()
+ */
+void libie_irq_deinit(struct libie_irq *irq)
+{
+	struct libie_irq_entry *entry;
+	unsigned long i;
+
+	if (!irq->pdev)
+		return;
+
+	xa_for_each(&irq->entries, i, entry)
+		kfree(entry);
+	xa_destroy(&irq->entries);
+	pci_free_irq_vectors(irq->pdev);
+	irq->pdev = NULL;
+}
+EXPORT_SYMBOL_NS_GPL(libie_irq_deinit, "LIBIE_IRQ");
+
+/**
+ * libie_get_irq - get new allocated entry for specific irq type
+ * @irq: libie_irq structure used to get limits and entries xarray
+ * @type: one of the enum libie_irq_type
+ *
+ * Return: struct libie_irq_entry * in case of success or NULL otherwise
+ */
+static struct libie_irq_entry *libie_get_irq(struct libie_irq *irq,
+					     enum libie_irq_type type)
+{
+	struct libie_irq_entry *entry;
+	unsigned int index;
+
+	if (!irq->pdev)
+		return NULL;
+
+	/* Change entry type if dynamic isn't supported. Reflect correct type
+	 * to not call pci_msix_free_irq() during freeing this irq.
+	 */
+	if (!pci_msix_can_alloc_dyn(irq->pdev))
+		type = LIBIE_IRQ_STATIC;
+
+	entry = kzalloc_obj(*entry);
+	if (!entry)
+		return NULL;
+
+	if (xa_alloc(&irq->entries, &index, entry, irq->limits[type],
+		     GFP_KERNEL))
+		goto free_entry;
+
+	entry->index = index;
+	entry->type = type;
+
+	return entry;
+
+free_entry:
+	kfree(entry);
+	return NULL;
+}
+
+/**
+ * libie_put_irq - inform that the irq isn't used anymore
+ * @irq: libie_irq structure used to get entries xarray
+ * @index: software 0-based index of irq to be marked as unused
+ */
+void libie_put_irq(struct libie_irq *irq, unsigned int index)
+{
+	struct libie_irq_entry *entry;
+
+	entry = xa_erase(&irq->entries, index);
+	kfree(entry);
+}
+EXPORT_SYMBOL_NS_GPL(libie_put_irq, "LIBIE_IRQ");
+
+/**
+ * libie_irq_alloc - alloc new irq, or get existing one in case of static
+ * @irq: libie_irq structure
+ * @type: one of enum libie_irq_type
+ *
+ *
+ * For LIBIE_IRQ_DYNAMIC function allocs new interrupt and return it.
+ * For LIBIE_IRQ_STATIC function returns already allocated one.
+ *
+ * The function should be called for getting irq information (index and virq)
+ * for specific irq type. Returned information should be stored to use index for
+ * gathering HW specific information and virq to request/free irq line.
+ *
+ * Calling this function with LIBIE_IRQ_DYNAMIC type when dynamic irq isn't
+ * support is fine and will use limits from static field set in
+ * libie_irq_init().
+ *
+ * Return: map.index = -ENOENT if there is no free interrupts of chosen type
+ *	   map.index = -EINVAL if pci_irq_vector() fails
+ *	   correct map.index and map.virq if everything is fine
+ */
+struct msi_map libie_irq_alloc(struct libie_irq *irq, enum libie_irq_type type)
+{
+	struct msi_map map = { .index = -ENOENT,
+			       .virq = 0 };
+	struct libie_irq_entry *entry;
+
+	entry = libie_get_irq(irq, type);
+	if (!entry)
+		return map;
+
+	if (entry->type == LIBIE_IRQ_DYNAMIC) {
+		map = pci_msix_alloc_irq_at(irq->pdev, entry->index, NULL);
+		if (map.index < 0)
+			goto put_irq;
+	} else {
+		map.index = entry->index;
+		map.virq = pci_irq_vector(irq->pdev, map.index);
+		if (map.virq < 0) {
+			/* In dynamic case error is in .index, put it there
+			 * also for static case to allow the caller always look
+			 * for an error in the same place.
+			 */
+			map.index = map.virq;
+			goto put_irq;
+		}
+	}
+
+	return map;
+
+put_irq:
+	libie_put_irq(irq, entry->index);
+	return map;
+}
+EXPORT_SYMBOL_NS_GPL(libie_irq_alloc, "LIBIE_IRQ");
+
+/**
+ * libie_irq_free - free irq, allocated using libie_alloc_irq()
+ * @irq: libie_irq structure
+ * @map: msi_map structure returned from libie_alloc_irq()
+ *
+ * In case of dynamic allocation and LIBIE_IRQ_DYNAMIC type pci_msix_free_irq()
+ * is called. Otherwise only free driver irq entry related resources.
+ *
+ * It is safe to call this function with map that doesn't exist in xarray
+ * as long as the map.virq is 0 or negative. It is true when libie_irq_alloc()
+ * has failed.
+ */
+void libie_irq_free(struct libie_irq *irq, struct msi_map map)
+{
+	struct libie_irq_entry *entry;
+
+	if (map.virq <= 0 || map.index < 0)
+		return;
+
+	entry = xa_load(&irq->entries, map.index);
+	if (!entry)
+		return;
+
+	if (entry->type == LIBIE_IRQ_DYNAMIC)
+		pci_msix_free_irq(irq->pdev, map);
+
+	libie_put_irq(irq, map.index);
+}
+EXPORT_SYMBOL_NS_GPL(libie_irq_free, "LIBIE_IRQ");
+
+/**
+ * libie_irq_reserve - reserve a interrupt index without allocating MSI-X
+ * @irq: libie_irq structure containing interrupt management data
+ *
+ * This function reserves an interrupt index from the dynamic range without
+ * actually allocating the corresponding MSI-X vector. The reserved index can
+ * be used for hardware queue configuration before the actual interrupt
+ * allocation. The caller should use libie_put_irq() to release the reserved
+ * index when no longer needed.
+ *
+ * Return: Reserved interrupt index on success, or -ENOENT if no dynamic
+ *         interrupt indices are available.
+ */
+int libie_irq_reserve(struct libie_irq *irq)
+{
+	struct libie_irq_entry *ent = libie_get_irq(irq, LIBIE_IRQ_DYNAMIC);
+
+	if (!ent)
+		return -ENOENT;
+
+	return ent->index;
+}
+EXPORT_SYMBOL_NS_GPL(libie_irq_reserve, "LIBIE_IRQ");
+
+/* Module */
+
+MODULE_DESCRIPTION("Helper functions for managing MSI-X in driver");
+MODULE_LICENSE("GPL");
diff --git a/include/linux/net/intel/libie/irq.h b/include/linux/net/intel/libie/irq.h
new file mode 100644
index 000000000000..8af8fc22ab09
--- /dev/null
+++ b/include/linux/net/intel/libie/irq.h
@@ -0,0 +1,75 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/* Copyright (C) 2025 Intel Corporation */
+
+#ifndef __LIBIE_IRQ_H
+#define __LIBIE_IRQ_H
+
+#include <linux/pci.h>
+
+/* In whole code in libie_irq index means the software 0-based irq index
+ * for driver purpose, virq means the linux irq line number. Index can be used
+ * for getting HW registers address and HW indexes (ex. for idpf there is
+ * another irq index used in virtchnl communication which isn't driver index or
+ * linux irq number). It is following the scheme from structure msi_map.
+ */
+
+/**
+ * enum libie_irq_type - enum representing types of irq entries
+ * @LIBIE_IRQ_STATIC: irq static allocated from kernel at driver probe
+ * @LIBIE_IRQ_DYNAMIC: irq dynamic allocated during normal driver operation
+ * @LIBIE_IRQ_NUM_TYPES: must be the last one, used to define the array size
+ *
+ * Enum is used to get software irq indexes from some kind of pool. The pool is
+ * based on xa_array. Depending on the limit value passed to xa_alloc() software
+ * irq indexes only from limited range can be returned.
+ *
+ * LIBIE_IRQ_STATIC .min = 0, max = 5 -> 5 irq static allocated to be sure that
+ *	all default vport can operate
+ * LIBIE_IRQ_DYNAMIC .min = 6, max = HW irq max -> rest to be dynamically used
+ *	when needed
+ */
+enum libie_irq_type {
+	LIBIE_IRQ_STATIC,
+	LIBIE_IRQ_DYNAMIC,
+	LIBIE_IRQ_NUM_TYPES,
+};
+
+/**
+ * struct libie_irq_entry - structure to store irq entry information
+ * @index: managed by software 0 based irq index, used to get correct hardware
+ *	   information about irq (HW index and HW registers address)
+ * @type: the type of irq, look at enum libie_irq_type for more information
+ *
+ * This structure is used to store the basic information about irq used during
+ * alloc and free. Type needs to be known, because freeing dynamic type needs
+ * extra call.
+ */
+struct libie_irq_entry {
+	int index;
+	enum libie_irq_type type;
+};
+
+/**
+ * struct libie_irq - main structure to be used by libie_irq code
+ * @pdev: pdev of driver that is using this lib
+ * @limits: the irq pool scheme definition, take a look at irq_type note
+ * @entries: xarray to store irq entries
+ *
+ * pdev and limits values need to be passed by the driver during lib
+ * initialization.
+ */
+struct libie_irq {
+	struct pci_dev *pdev;
+	struct xa_limit limits[LIBIE_IRQ_NUM_TYPES];
+	struct xarray entries;
+};
+
+int libie_irq_init(struct libie_irq *irq, struct pci_dev *pdev,
+		   int min, int max);
+void libie_irq_deinit(struct libie_irq *irq);
+struct msi_map libie_irq_alloc(struct libie_irq *irq, enum libie_irq_type type);
+void libie_irq_free(struct libie_irq *irq, struct msi_map map);
+int libie_irq_reserve(struct libie_irq *irq);
+void libie_put_irq(struct libie_irq *irq, unsigned int index);
+
+#endif /* __LIBIE_IRQ_H */
-- 
2.49.0


^ permalink raw reply related	[flat|nested] 11+ messages in thread

* [PATCH iwl-next v2 06/10] libie, idpf: move hardware irq info struct to libie
  2026-09-11 12:49 [PATCH iwl-next v2 00/10] Interrupts helper in libie Michal Swiatkowski
                   ` (4 preceding siblings ...)
  2026-09-11 12:49 ` [PATCH iwl-next v2 05/10] libie, idpf: move irq code to libie Michal Swiatkowski
@ 2026-09-11 12:49 ` Michal Swiatkowski
  2026-09-11 12:49 ` [PATCH iwl-next v2 07/10] libie, idpf: move parsing alloc vectors command " Michal Swiatkowski
                   ` (3 subsequent siblings)
  9 siblings, 0 replies; 11+ messages in thread
From: Michal Swiatkowski @ 2026-09-11 12:49 UTC (permalink / raw)
  To: intel-wired-lan; +Cc: netdev, Michal Swiatkowski

Manually move definition related to irq info from idpf to libie_irq.
s/idpf_/libie_

It will be used by idpf and ixd driver.

Signed-off-by: Michal Swiatkowski <michal.swiatkowski@linux.intel.com>
---
 drivers/net/ethernet/intel/idpf/idpf.h        | 36 +------------------
 drivers/net/ethernet/intel/idpf/idpf_dev.c    |  2 +-
 drivers/net/ethernet/intel/idpf/idpf_vf_dev.c |  2 +-
 .../net/ethernet/intel/idpf/idpf_virtchnl.c   |  8 ++---
 include/linux/net/intel/libie/irq.h           | 34 ++++++++++++++++++
 5 files changed, 41 insertions(+), 41 deletions(-)

diff --git a/drivers/net/ethernet/intel/idpf/idpf.h b/drivers/net/ethernet/intel/idpf/idpf.h
index 51f447135693..33ee30424b77 100644
--- a/drivers/net/ethernet/intel/idpf/idpf.h
+++ b/drivers/net/ethernet/intel/idpf/idpf.h
@@ -577,40 +577,6 @@ struct idpf_vport_config {
 	     iter = (++__##iter) < &(adapter)->vports[(adapter)->max_vports] ? \
 	     *__##iter : NULL)
 
-/**
- * struct idpf_vec_regs - hardware registers related to vector
- * @dyn_ctl: Dynamic control interrupt register offset
- * @itrn: Interrupt Throttling Rate register offset
- * @itrn_index_spacing: Register spacing between ITR registers of the same
- *			vector
- */
-struct idpf_vec_regs {
-	u32 dyn_ctl;
-	u32 itrn;
-	u32 itrn_index_spacing;
-};
-
-/**
- * struct idpf_hw_vector - single hardware vector info
- * @regs: address of irq registers
- * @idx: hardware vector index
- */
-struct idpf_hw_vector {
-	struct idpf_vec_regs regs;
-	int idx;
-};
-
-/**
- * struct idpf_irq_info - hardware data needed to setup irq
- * @vectors: allocated during initialization store hardware information
- *	     for all vectors that can be used on a whole device
- * @num: amount of vectors stored here
- */
-struct idpf_irq_info {
-	struct idpf_hw_vector *vectors;
-	int num;
-};
-
 /**
  * struct idpf_rdma_irq - RDMA interrupt vectors data
  * @entries: MSIX table shared with the RDMA auxiliary device
@@ -695,7 +661,7 @@ struct idpf_adapter {
 	struct idpf_rdma_irq rdma_irq;
 	struct libie_irq irq;
 	struct virtchnl2_alloc_vectors *req_vec_chunks;
-	struct idpf_irq_info irq_info;
+	struct libie_irq_info irq_info;
 	struct idpf_q_vector mb_vector;
 	irqreturn_t (*irq_mb_handler)(int irq, void *data);
 
diff --git a/drivers/net/ethernet/intel/idpf/idpf_dev.c b/drivers/net/ethernet/intel/idpf/idpf_dev.c
index cd947fd24ff6..61f5e8e4d20b 100644
--- a/drivers/net/ethernet/intel/idpf/idpf_dev.c
+++ b/drivers/net/ethernet/intel/idpf/idpf_dev.c
@@ -87,7 +87,7 @@ static void idpf_noirq_intr_reg_init(struct idpf_adapter *adapter,
 static void idpf_intr_reg_init(struct idpf_adapter *adapter,
 			       struct idpf_q_vector *q_vector, u16 idx)
 {
-	struct idpf_hw_vector *v = &adapter->irq_info.vectors[idx];
+	struct libie_hw_vector *v = &adapter->irq_info.vectors[idx];
 	struct idpf_intr_reg *intr = &q_vector->intr_reg;
 	struct libie_mmio_info *mmio;
 	u32 rx_itr, tx_itr;
diff --git a/drivers/net/ethernet/intel/idpf/idpf_vf_dev.c b/drivers/net/ethernet/intel/idpf/idpf_vf_dev.c
index df3eabe12b18..4c1c2476613b 100644
--- a/drivers/net/ethernet/intel/idpf/idpf_vf_dev.c
+++ b/drivers/net/ethernet/intel/idpf/idpf_vf_dev.c
@@ -86,7 +86,7 @@ static void idpf_vf_noirq_intr_reg_init(struct idpf_adapter *adapter,
 static void idpf_vf_intr_reg_init(struct idpf_adapter *adapter,
 				  struct idpf_q_vector *q_vector, u16 idx)
 {
-	struct idpf_hw_vector *v = &adapter->irq_info.vectors[idx];
+	struct libie_hw_vector *v = &adapter->irq_info.vectors[idx];
 	struct idpf_intr_reg *intr = &q_vector->intr_reg;
 	struct libie_mmio_info *mmio;
 	u32 rx_itr, tx_itr;
diff --git a/drivers/net/ethernet/intel/idpf/idpf_virtchnl.c b/drivers/net/ethernet/intel/idpf/idpf_virtchnl.c
index 65ddc6f893fc..20e471def235 100644
--- a/drivers/net/ethernet/intel/idpf/idpf_virtchnl.c
+++ b/drivers/net/ethernet/intel/idpf/idpf_virtchnl.c
@@ -1855,7 +1855,7 @@ idpf_prep_map_unmap_queue_set_vector_msg(u32 vport_id, void *buf,
  */
 static int
 idpf_send_map_unmap_queue_set_vector_msg(const struct idpf_queue_set *qs,
-					 const struct idpf_irq_info *info,
+					 const struct libie_irq_info *info,
 					 bool map)
 {
 	struct virtchnl2_queue_vector *vqv __free(kfree) = NULL;
@@ -2238,14 +2238,14 @@ int idpf_send_add_queues_msg(struct idpf_adapter *adapter,
  *
  * Returns 0 on success, negative on failure.
  */
-static int idpf_create_vectors_info(struct idpf_irq_info *info,
+static int idpf_create_vectors_info(struct libie_irq_info *info,
 				    const struct virtchnl2_get_capabilities *caps,
 				    const struct virtchnl2_alloc_vectors *vectors,
 				    const u16 num_vectors)
 {
 	const struct virtchnl2_vector_chunks *chunks = &vectors->vchunks;
 	int all_vectors = num_vectors + IDPF_MBX_Q_VEC;
-	struct idpf_hw_vector *vector;
+	struct libie_hw_vector *vector;
 	int reg_cnt;
 
 	if (le16_to_cpu(vectors->num_vectors) < num_vectors)
@@ -2266,7 +2266,7 @@ static int idpf_create_vectors_info(struct idpf_irq_info *info,
 	for (int i = 0; i < le16_to_cpu(chunks->num_vchunks); i++) {
 		const struct virtchnl2_vector_chunk *chunk = &chunks->vchunks[i];
 		u32 dyn_spacing, itrn_spacing;
-		struct idpf_vec_regs reg_val;
+		struct libie_vec_regs reg_val;
 		u16 vec_id;
 
 		reg_val.dyn_ctl = le32_to_cpu(chunk->dynctl_reg_start);
diff --git a/include/linux/net/intel/libie/irq.h b/include/linux/net/intel/libie/irq.h
index 8af8fc22ab09..e219fde575d8 100644
--- a/include/linux/net/intel/libie/irq.h
+++ b/include/linux/net/intel/libie/irq.h
@@ -64,6 +64,40 @@ struct libie_irq {
 	struct xarray entries;
 };
 
+/**
+ * struct libie_vec_regs - hardware registers related to vector
+ * @dyn_ctl: Dynamic control interrupt register offset
+ * @itrn: Interrupt Throttling Rate register offset
+ * @itrn_index_spacing: Register spacing between ITR registers of the same
+ *			vector
+ */
+struct libie_vec_regs {
+	u32 dyn_ctl;
+	u32 itrn;
+	u32 itrn_index_spacing;
+};
+
+/**
+ * struct libie_hw_vector - single hardware vector info
+ * @regs: address of irq registers
+ * @idx: hardware vector index
+ */
+struct libie_hw_vector {
+	struct libie_vec_regs regs;
+	int idx;
+};
+
+/**
+ * struct libie_irq_info - hardware data needed to setup irq
+ * @vectors: allocated during initialization store hardware information
+ *	     for all vectors that can be used on a whole device
+ * @num: amount of vectors stored here
+ */
+struct libie_irq_info {
+	struct libie_hw_vector *vectors;
+	int num;
+};
+
 int libie_irq_init(struct libie_irq *irq, struct pci_dev *pdev,
 		   int min, int max);
 void libie_irq_deinit(struct libie_irq *irq);
-- 
2.49.0


^ permalink raw reply related	[flat|nested] 11+ messages in thread

* [PATCH iwl-next v2 07/10] libie, idpf: move parsing alloc vectors command to libie
  2026-09-11 12:49 [PATCH iwl-next v2 00/10] Interrupts helper in libie Michal Swiatkowski
                   ` (5 preceding siblings ...)
  2026-09-11 12:49 ` [PATCH iwl-next v2 06/10] libie, idpf: move hardware irq info struct " Michal Swiatkowski
@ 2026-09-11 12:49 ` Michal Swiatkowski
  2026-09-11 12:49 ` [PATCH iwl-next v2 08/10] ice: use libie_irq for interrupts managing Michal Swiatkowski
                   ` (2 subsequent siblings)
  9 siblings, 0 replies; 11+ messages in thread
From: Michal Swiatkowski @ 2026-09-11 12:49 UTC (permalink / raw)
  To: intel-wired-lan; +Cc: netdev, Michal Swiatkowski, Aleksandr Loktionov

No functional changes. Just moving to make it available from other
ipu drivers.

Reviewed-by: Aleksandr Loktionov <aleksandr.loktionov@intel.com>
Signed-off-by: Michal Swiatkowski <michal.swiatkowski@linux.intel.com>
---
 .../net/ethernet/intel/idpf/idpf_virtchnl.c   | 85 +----------------
 drivers/net/ethernet/intel/libie/irq.c        | 92 +++++++++++++++++++
 include/linux/net/intel/libie/irq.h           |  9 ++
 3 files changed, 104 insertions(+), 82 deletions(-)

diff --git a/drivers/net/ethernet/intel/idpf/idpf_virtchnl.c b/drivers/net/ethernet/intel/idpf/idpf_virtchnl.c
index 20e471def235..3df6ad291e64 100644
--- a/drivers/net/ethernet/intel/idpf/idpf_virtchnl.c
+++ b/drivers/net/ethernet/intel/idpf/idpf_virtchnl.c
@@ -2229,83 +2229,6 @@ int idpf_send_add_queues_msg(struct idpf_adapter *adapter,
 	return err;
 }
 
-/**
- * idpf_create_vectors_info - Save vectors information from firmware
- * @info: parsed information is stored here
- * @caps: virtchannel capabilities
- * @vectors: vector information from firmware to be parsed
- * @num_vectors: number of vectors
- *
- * Returns 0 on success, negative on failure.
- */
-static int idpf_create_vectors_info(struct libie_irq_info *info,
-				    const struct virtchnl2_get_capabilities *caps,
-				    const struct virtchnl2_alloc_vectors *vectors,
-				    const u16 num_vectors)
-{
-	const struct virtchnl2_vector_chunks *chunks = &vectors->vchunks;
-	int all_vectors = num_vectors + IDPF_MBX_Q_VEC;
-	struct libie_hw_vector *vector;
-	int reg_cnt;
-
-	if (le16_to_cpu(vectors->num_vectors) < num_vectors)
-		return -EINVAL;
-
-	info->vectors = kzalloc_objs(*info->vectors, all_vectors);
-	if (!info->vectors)
-		return -ENOMEM;
-	/* Mailbox irq information are stored in different places. Fill index 0
-	 * of our vectors info with capabilities and rest with information
-	 * from vector chunks.
-	 */
-	vector = &info->vectors[0];
-	vector->idx = le16_to_cpu(caps->mailbox_vector_id);
-	vector->regs.dyn_ctl = le32_to_cpu(caps->mailbox_dyn_ctl);
-	reg_cnt = IDPF_MBX_Q_VEC;
-
-	for (int i = 0; i < le16_to_cpu(chunks->num_vchunks); i++) {
-		const struct virtchnl2_vector_chunk *chunk = &chunks->vchunks[i];
-		u32 dyn_spacing, itrn_spacing;
-		struct libie_vec_regs reg_val;
-		u16 vec_id;
-
-		reg_val.dyn_ctl = le32_to_cpu(chunk->dynctl_reg_start);
-		reg_val.itrn = le32_to_cpu(chunk->itrn_reg_start);
-		reg_val.itrn_index_spacing =
-			le32_to_cpu(chunk->itrn_index_spacing);
-
-		dyn_spacing = le32_to_cpu(chunk->dynctl_reg_spacing);
-		itrn_spacing = le32_to_cpu(chunk->itrn_reg_spacing);
-		vec_id = le16_to_cpu(chunk->start_vector_id);
-
-		for (int j = 0; j < le16_to_cpu(chunk->num_vectors); j++) {
-			if (reg_cnt >= all_vectors)
-				break;
-
-			vector = &info->vectors[reg_cnt];
-
-			vector->regs = reg_val;
-			vector->idx = vec_id;
-
-			reg_val.dyn_ctl += dyn_spacing;
-			reg_val.itrn += itrn_spacing;
-
-			vec_id += 1;
-			reg_cnt += 1;
-		}
-	}
-
-	if (reg_cnt != all_vectors) {
-		kfree(info->vectors);
-		info->vectors = NULL;
-		return -EINVAL;
-	}
-
-	info->num = num_vectors + IDPF_MBX_Q_VEC;
-
-	return 0;
-}
-
 /**
  * idpf_send_alloc_vectors_msg - Send virtchnl alloc vectors message
  * @adapter: Driver specific private structure
@@ -2350,8 +2273,8 @@ int idpf_send_alloc_vectors_msg(struct idpf_adapter *adapter, u16 num_vectors)
 		goto free_rx_buf;
 	}
 
-	err = idpf_create_vectors_info(&adapter->irq_info, &adapter->caps,
-				       rcvd_vec, num_vectors);
+	err = libie_irq_create_info(&adapter->irq_info, &adapter->caps,
+				    rcvd_vec, num_vectors);
 	if (err)
 		idpf_send_dealloc_vectors_msg(adapter);
 
@@ -2378,9 +2301,7 @@ int idpf_send_dealloc_vectors_msg(struct idpf_adapter *adapter)
 	int buf_size, err;
 
 	/* dealloc vectors can fail, but irq_info still needs to be cleaned */
-	kfree(adapter->irq_info.vectors);
-	adapter->irq_info.vectors = NULL;
-	adapter->irq_info.num = 0;
+	libie_irq_destroy_info(&adapter->irq_info);
 
 	buf_size = struct_size(&ac->vchunks, vchunks,
 			       le16_to_cpu(ac->vchunks.num_vchunks));
diff --git a/drivers/net/ethernet/intel/libie/irq.c b/drivers/net/ethernet/intel/libie/irq.c
index 0f73f8becefb..d26ffeffdcb2 100644
--- a/drivers/net/ethernet/intel/libie/irq.c
+++ b/drivers/net/ethernet/intel/libie/irq.c
@@ -2,6 +2,7 @@
 /* Copyright (C) 2025 Intel Corporation */
 
 #include <linux/net/intel/libie/irq.h>
+#include <linux/net/intel/virtchnl2.h>
 
 /**
  * libie_irq_init - init irq for whole device
@@ -250,6 +251,97 @@ int libie_irq_reserve(struct libie_irq *irq)
 }
 EXPORT_SYMBOL_NS_GPL(libie_irq_reserve, "LIBIE_IRQ");
 
+/**
+ * libie_irq_create_info - Save vectors information from firmware
+ * @info: parsed information is stored here
+ * @caps: virtchannel capabilities
+ * @vectors: vector information from firmware to be parsed
+ * @num_vectors: number of vectors
+ *
+ * Return: 0 on success, negative on failure.
+ */
+int libie_irq_create_info(struct libie_irq_info *info,
+			  const struct virtchnl2_get_capabilities *caps,
+			  const struct virtchnl2_alloc_vectors *vectors,
+			  const u16 num_vectors)
+{
+	const struct virtchnl2_vector_chunks *chunks = &vectors->vchunks;
+	struct libie_hw_vector *vector;
+	const int mb_vectors = 1;
+	int reg_cnt, all_vectors;
+
+	if (le16_to_cpu(vectors->num_vectors) < num_vectors)
+		return -EINVAL;
+
+	all_vectors = num_vectors + mb_vectors;
+	info->vectors = kzalloc_objs(*info->vectors, all_vectors);
+	if (!info->vectors)
+		return -ENOMEM;
+	/* Mailbox irq information are stored in different places. Fill index 0
+	 * of our vectors info with capabilities and rest with information
+	 * from vector chunks.
+	 */
+	vector = &info->vectors[0];
+	vector->idx = le16_to_cpu(caps->mailbox_vector_id);
+	vector->regs.dyn_ctl = le32_to_cpu(caps->mailbox_dyn_ctl);
+	reg_cnt = mb_vectors;
+
+	for (int i = 0; i < le16_to_cpu(chunks->num_vchunks); i++) {
+		const struct virtchnl2_vector_chunk *chunk = &chunks->vchunks[i];
+		u32 dyn_spacing, itrn_spacing;
+		struct libie_vec_regs reg_val;
+		u16 vec_id;
+
+		reg_val.dyn_ctl = le32_to_cpu(chunk->dynctl_reg_start);
+		reg_val.itrn = le32_to_cpu(chunk->itrn_reg_start);
+		reg_val.itrn_index_spacing =
+			le32_to_cpu(chunk->itrn_index_spacing);
+
+		dyn_spacing = le32_to_cpu(chunk->dynctl_reg_spacing);
+		itrn_spacing = le32_to_cpu(chunk->itrn_reg_spacing);
+		vec_id = le16_to_cpu(chunk->start_vector_id);
+
+		for (int j = 0; j < le16_to_cpu(chunk->num_vectors); j++) {
+			if (reg_cnt >= all_vectors)
+				break;
+
+			vector = &info->vectors[reg_cnt];
+
+			vector->regs = reg_val;
+			vector->idx = vec_id;
+
+			reg_val.dyn_ctl += dyn_spacing;
+			reg_val.itrn += itrn_spacing;
+
+			vec_id += 1;
+			reg_cnt += 1;
+		}
+	}
+
+	if (reg_cnt != all_vectors) {
+		kfree(info->vectors);
+		info->vectors = NULL;
+		return -EINVAL;
+	}
+
+	info->num = all_vectors;
+
+	return 0;
+}
+EXPORT_SYMBOL_NS_GPL(libie_irq_create_info, "LIBIE_IRQ");
+
+/**
+ * libie_irq_destroy_info - free memory allocated during building irq_info
+ * @info: libie_irq_info struct to be freed
+ */
+void libie_irq_destroy_info(struct libie_irq_info *info)
+{
+	kfree(info->vectors);
+	info->vectors = NULL;
+	info->num = 0;
+}
+EXPORT_SYMBOL_NS_GPL(libie_irq_destroy_info, "LIBIE_IRQ");
+
 /* Module */
 
 MODULE_DESCRIPTION("Helper functions for managing MSI-X in driver");
diff --git a/include/linux/net/intel/libie/irq.h b/include/linux/net/intel/libie/irq.h
index e219fde575d8..8d5873f13871 100644
--- a/include/linux/net/intel/libie/irq.h
+++ b/include/linux/net/intel/libie/irq.h
@@ -105,5 +105,14 @@ struct msi_map libie_irq_alloc(struct libie_irq *irq, enum libie_irq_type type);
 void libie_irq_free(struct libie_irq *irq, struct msi_map map);
 int libie_irq_reserve(struct libie_irq *irq);
 void libie_put_irq(struct libie_irq *irq, unsigned int index);
+/* IPU specific functions. */
+struct virtchnl2_get_capabilities;
+struct virtchnl2_alloc_vectors;
+
+void libie_irq_destroy_info(struct libie_irq_info *info);
+int libie_irq_create_info(struct libie_irq_info *info,
+			  const struct virtchnl2_get_capabilities *caps,
+			  const struct virtchnl2_alloc_vectors *vectors,
+			  const u16 num_vectors);
 
 #endif /* __LIBIE_IRQ_H */
-- 
2.49.0


^ permalink raw reply related	[flat|nested] 11+ messages in thread

* [PATCH iwl-next v2 08/10] ice: use libie_irq for interrupts managing
  2026-09-11 12:49 [PATCH iwl-next v2 00/10] Interrupts helper in libie Michal Swiatkowski
                   ` (6 preceding siblings ...)
  2026-09-11 12:49 ` [PATCH iwl-next v2 07/10] libie, idpf: move parsing alloc vectors command " Michal Swiatkowski
@ 2026-09-11 12:49 ` Michal Swiatkowski
  2026-09-11 12:49 ` [PATCH iwl-next v2 09/10] ixd: support for getting lan memory regions Michal Swiatkowski
  2026-09-11 12:49 ` [PATCH iwl-next v2 10/10] ixd: use interrupt for mailbox communication Michal Swiatkowski
  9 siblings, 0 replies; 11+ messages in thread
From: Michal Swiatkowski @ 2026-09-11 12:49 UTC (permalink / raw)
  To: intel-wired-lan; +Cc: netdev, Michal Swiatkowski, Aleksandr Loktionov

Change interrupts code to fit the libie_irq calls.

There is not many difference. Bool for dynamic alloc in libie is changed
to enum for static and dynamic. Rest code is the same. Instead of custom
ice_irq_tracker there is libie_irq that tracks the interrupts.

Code fallback to static when there is not more dynamic. Previously
it first used static part. Getting dynamic first better fit the lib
code. It isn't breaking current driver code.

Dynamic alloc is always set to true if there is support. In libie_irq
code check for dynamic support is done inside. LIBIE_IRQ_ANY can be
always pass in case of getting interrupts for VSI. If there is no
platform support it is changed to LIBIE_IRQ_STATIC inside libie code.

Reviewed-by: Aleksandr Loktionov <aleksandr.loktionov@intel.com>
Signed-off-by: Michal Swiatkowski <michal.swiatkowski@linux.intel.com>
---
 drivers/net/ethernet/intel/Kconfig        |   1 +
 drivers/net/ethernet/intel/ice/ice.h      |   5 +-
 drivers/net/ethernet/intel/ice/ice_base.c |   4 +-
 drivers/net/ethernet/intel/ice/ice_idc.c  |   4 +-
 drivers/net/ethernet/intel/ice/ice_irq.c  | 181 ++--------------------
 drivers/net/ethernet/intel/ice/ice_irq.h  |  14 --
 drivers/net/ethernet/intel/ice/ice_lib.c  |   3 -
 drivers/net/ethernet/intel/ice/ice_main.c |  15 +-
 drivers/net/ethernet/intel/libie/irq.c    |  30 +++-
 include/linux/net/intel/libie/irq.h       |   2 +
 10 files changed, 51 insertions(+), 208 deletions(-)

diff --git a/drivers/net/ethernet/intel/Kconfig b/drivers/net/ethernet/intel/Kconfig
index 1228ae099b15..bd0dd8c28352 100644
--- a/drivers/net/ethernet/intel/Kconfig
+++ b/drivers/net/ethernet/intel/Kconfig
@@ -301,6 +301,7 @@ config ICE
 	select LIBIE
 	select LIBIE_ADMINQ
 	select LIBIE_FWLOG if DEBUG_FS
+	select LIBIE_IRQ
 	select NET_DEVLINK
 	select PACKING
 	select PLDMFW
diff --git a/drivers/net/ethernet/intel/ice/ice.h b/drivers/net/ethernet/intel/ice/ice.h
index 6a158ee882a7..18ee6f0c1abc 100644
--- a/drivers/net/ethernet/intel/ice/ice.h
+++ b/drivers/net/ethernet/intel/ice/ice.h
@@ -36,6 +36,7 @@
 #include <linux/bpf.h>
 #include <linux/btf.h>
 #include <linux/auxiliary_bus.h>
+#include <linux/net/intel/libie/irq.h>
 #include <linux/net/intel/virtchnl.h>
 #include <linux/cpu_rmap.h>
 #include <linux/dim.h>
@@ -351,8 +352,6 @@ struct ice_vsi {
 	u32 rx_buf_failed;
 	u32 rx_page_failed;
 	u16 num_q_vectors;
-	/* tell if only dynamic irq allocation is allowed */
-	bool irq_dyn_alloc;
 	bool hsplit:1;
 
 	u16 vsi_num;			/* HW (absolute) index of this VSI */
@@ -565,7 +564,7 @@ struct ice_pf {
 	struct devlink_port devlink_port;
 
 	/* OS reserved IRQ details */
-	struct ice_irq_tracker irq_tracker;
+	struct libie_irq irq;
 	struct ice_virt_irq_tracker virt_irq_tracker;
 
 	u16 ctrl_vsi_idx;		/* control VSI index in pf->vsi array */
diff --git a/drivers/net/ethernet/intel/ice/ice_base.c b/drivers/net/ethernet/intel/ice/ice_base.c
index 1667f686ff75..b592d3c389c0 100644
--- a/drivers/net/ethernet/intel/ice/ice_base.c
+++ b/drivers/net/ethernet/intel/ice/ice_base.c
@@ -140,7 +140,7 @@ static int ice_vsi_alloc_q_vector(struct ice_vsi *vsi, u16 v_idx)
 		}
 	}
 
-	q_vector->irq = ice_alloc_irq(pf, vsi->irq_dyn_alloc);
+	q_vector->irq = libie_irq_alloc(&pf->irq, LIBIE_IRQ_ANY);
 	if (q_vector->irq.index < 0) {
 		err = -ENOMEM;
 		goto err_free_q_vector;
@@ -209,7 +209,7 @@ static void ice_free_q_vector(struct ice_vsi *vsi, int v_idx)
 	    ice_get_vf_ctrl_vsi(pf, vsi))
 		goto free_q_vector;
 
-	ice_free_irq(pf, q_vector->irq);
+	libie_irq_free(&pf->irq, q_vector->irq);
 
 free_q_vector:
 	kfree(q_vector);
diff --git a/drivers/net/ethernet/intel/ice/ice_idc.c b/drivers/net/ethernet/intel/ice/ice_idc.c
index 102d63c3018b..337ba65b6318 100644
--- a/drivers/net/ethernet/intel/ice/ice_idc.c
+++ b/drivers/net/ethernet/intel/ice/ice_idc.c
@@ -239,7 +239,7 @@ int ice_alloc_rdma_qvector(struct iidc_rdma_core_dev_info *cdev,
 		return -EINVAL;
 
 	pf = pci_get_drvdata(cdev->pdev);
-	map = ice_alloc_irq(pf, true);
+	map = libie_irq_alloc(&pf->irq, LIBIE_IRQ_ANY);
 	if (map.index < 0)
 		return -ENOMEM;
 
@@ -268,7 +268,7 @@ void ice_free_rdma_qvector(struct iidc_rdma_core_dev_info *cdev,
 
 	map.index = entry->entry;
 	map.virq = entry->vector;
-	ice_free_irq(pf, map);
+	libie_irq_free(&pf->irq, map);
 }
 EXPORT_SYMBOL_GPL(ice_free_rdma_qvector);
 
diff --git a/drivers/net/ethernet/intel/ice/ice_irq.c b/drivers/net/ethernet/intel/ice/ice_irq.c
index cd59579568b7..a883b65b4e34 100644
--- a/drivers/net/ethernet/intel/ice/ice_irq.c
+++ b/drivers/net/ethernet/intel/ice/ice_irq.c
@@ -5,21 +5,6 @@
 #include "ice_lib.h"
 #include "ice_irq.h"
 
-/**
- * ice_init_irq_tracker - initialize interrupt tracker
- * @pf: board private structure
- * @max_vectors: maximum number of vectors that tracker can hold
- * @num_static: number of preallocated interrupts
- */
-static void
-ice_init_irq_tracker(struct ice_pf *pf, unsigned int max_vectors,
-		     unsigned int num_static)
-{
-	pf->irq_tracker.num_entries = max_vectors;
-	pf->irq_tracker.num_static = num_static;
-	xa_init_flags(&pf->irq_tracker.entries, XA_FLAGS_ALLOC);
-}
-
 static int
 ice_init_virt_irq_tracker(struct ice_pf *pf, u32 base, u32 num_entries)
 {
@@ -33,76 +18,11 @@ ice_init_virt_irq_tracker(struct ice_pf *pf, u32 base, u32 num_entries)
 	return 0;
 }
 
-/**
- * ice_deinit_irq_tracker - free xarray tracker
- * @pf: board private structure
- */
-static void ice_deinit_irq_tracker(struct ice_pf *pf)
-{
-	xa_destroy(&pf->irq_tracker.entries);
-}
-
 static void ice_deinit_virt_irq_tracker(struct ice_pf *pf)
 {
 	bitmap_free(pf->virt_irq_tracker.bm);
 }
 
-/**
- * ice_free_irq_res - free a block of resources
- * @pf: board private structure
- * @index: starting index previously returned by ice_get_res
- */
-static void ice_free_irq_res(struct ice_pf *pf, u16 index)
-{
-	struct ice_irq_entry *entry;
-
-	entry = xa_erase(&pf->irq_tracker.entries, index);
-	kfree(entry);
-}
-
-/**
- * ice_get_irq_res - get an interrupt resource
- * @pf: board private structure
- * @dyn_allowed: allow entry to be dynamically allocated
- *
- * Allocate new irq entry in the free slot of the tracker. Since xarray
- * is used, always allocate new entry at the lowest possible index. Set
- * proper allocation limit for maximum tracker entries.
- *
- * Returns allocated irq entry or NULL on failure.
- */
-static struct ice_irq_entry *ice_get_irq_res(struct ice_pf *pf,
-					     bool dyn_allowed)
-{
-	struct xa_limit limit = { .max = pf->irq_tracker.num_entries - 1,
-				  .min = 0 };
-	unsigned int num_static = pf->irq_tracker.num_static - 1;
-	struct ice_irq_entry *entry;
-	unsigned int index;
-	int ret;
-
-	entry = kzalloc_obj(*entry);
-	if (!entry)
-		return NULL;
-
-	/* only already allocated if the caller says so */
-	if (!dyn_allowed)
-		limit.max = num_static;
-
-	ret = xa_alloc(&pf->irq_tracker.entries, &index, entry, limit,
-		       GFP_KERNEL);
-
-	if (ret) {
-		kfree(entry);
-		entry = NULL;
-	} else {
-		entry->index = index;
-		entry->dynamic = index > num_static;
-	}
-
-	return entry;
-}
-
 #define ICE_RDMA_AEQ_MSIX 1
 static int ice_get_default_msix_amount(struct ice_pf *pf)
 {
@@ -118,8 +38,7 @@ static int ice_get_default_msix_amount(struct ice_pf *pf)
  */
 void ice_clear_interrupt_scheme(struct ice_pf *pf)
 {
-	pci_free_irq_vectors(pf->pdev);
-	ice_deinit_irq_tracker(pf);
+	libie_irq_deinit(&pf->irq);
 	ice_deinit_virt_irq_tracker(pf);
 }
 
@@ -130,7 +49,7 @@ void ice_clear_interrupt_scheme(struct ice_pf *pf)
 int ice_init_interrupt_scheme(struct ice_pf *pf)
 {
 	int total_vectors = pf->hw.func_caps.common_cap.num_msix_vectors;
-	int vectors;
+	int err;
 
 	/* load default PF MSI-X range */
 	if (!pf->msix.min)
@@ -143,97 +62,15 @@ int ice_init_interrupt_scheme(struct ice_pf *pf)
 	pf->msix.total = total_vectors;
 	pf->msix.rest = total_vectors - pf->msix.max;
 
-	if (pci_msix_can_alloc_dyn(pf->pdev))
-		vectors = pf->msix.min;
-	else
-		vectors = pf->msix.max;
-
-	vectors = pci_alloc_irq_vectors(pf->pdev, pf->msix.min, vectors,
-					PCI_IRQ_MSIX);
-	if (vectors < 0)
-		return vectors;
-
-	ice_init_irq_tracker(pf, pf->msix.max, vectors);
-
-	return ice_init_virt_irq_tracker(pf, pf->msix.max, pf->msix.rest);
-}
-
-/**
- * ice_alloc_irq - Allocate new interrupt vector
- * @pf: board private structure
- * @dyn_allowed: allow dynamic allocation of the interrupt
- *
- * Allocate new interrupt vector for a given owner id.
- * return struct msi_map with interrupt details and track
- * allocated interrupt appropriately.
- *
- * This function reserves new irq entry from the irq_tracker.
- * if according to the tracker information all interrupts that
- * were allocated with ice_pci_alloc_irq_vectors are already used
- * and dynamically allocated interrupts are supported then new
- * interrupt will be allocated with pci_msix_alloc_irq_at.
- *
- * Some callers may only support dynamically allocated interrupts.
- * This is indicated with dyn_allowed flag.
- *
- * On failure, return map with negative .index. The caller
- * is expected to check returned map index.
- *
- */
-struct msi_map ice_alloc_irq(struct ice_pf *pf, bool dyn_allowed)
-{
-	struct msi_map map = { .index = -ENOENT };
-	struct device *dev = ice_pf_to_dev(pf);
-	struct ice_irq_entry *entry;
-
-	entry = ice_get_irq_res(pf, dyn_allowed);
-	if (!entry)
-		return map;
-
-	if (pci_msix_can_alloc_dyn(pf->pdev) && entry->dynamic) {
-		map = pci_msix_alloc_irq_at(pf->pdev, entry->index, NULL);
-		if (map.index < 0)
-			goto exit_free_res;
-		dev_dbg(dev, "allocated new irq at index %d\n", map.index);
-	} else {
-		map.index = entry->index;
-		map.virq = pci_irq_vector(pf->pdev, map.index);
-	}
-
-	return map;
-
-exit_free_res:
-	dev_err(dev, "Could not allocate irq at idx %d\n", entry->index);
-	ice_free_irq_res(pf, entry->index);
-	return map;
-}
-
-/**
- * ice_free_irq - Free interrupt vector
- * @pf: board private structure
- * @map: map with interrupt details
- *
- * Remove allocated interrupt from the interrupt tracker. If interrupt was
- * allocated dynamically, free respective interrupt vector.
- */
-void ice_free_irq(struct ice_pf *pf, struct msi_map map)
-{
-	struct ice_irq_entry *entry;
-
-	entry = xa_load(&pf->irq_tracker.entries, map.index);
-
-	if (!entry) {
-		dev_err(ice_pf_to_dev(pf), "Failed to get MSIX interrupt entry at index %d",
-			map.index);
-		return;
-	}
-
-	dev_dbg(ice_pf_to_dev(pf), "Free irq at index %d\n", map.index);
+	err = libie_irq_init(&pf->irq, pf->pdev, pf->msix.min, pf->msix.max);
+	if (err)
+		return err;
 
-	if (entry->dynamic)
-		pci_msix_free_irq(pf->pdev, map);
+	err = ice_init_virt_irq_tracker(pf, pf->msix.max, pf->msix.rest);
+	if (err)
+		libie_irq_deinit(&pf->irq);
 
-	ice_free_irq_res(pf, map.index);
+	return err;
 }
 
 /**
diff --git a/drivers/net/ethernet/intel/ice/ice_irq.h b/drivers/net/ethernet/intel/ice/ice_irq.h
index b2f9dbafd57e..a4ecf50e9ccf 100644
--- a/drivers/net/ethernet/intel/ice/ice_irq.h
+++ b/drivers/net/ethernet/intel/ice/ice_irq.h
@@ -4,17 +4,6 @@
 #ifndef _ICE_IRQ_H_
 #define _ICE_IRQ_H_
 
-struct ice_irq_entry {
-	unsigned int index;
-	bool dynamic;	/* allocation type flag */
-};
-
-struct ice_irq_tracker {
-	struct xarray entries;
-	u16 num_entries;	/* total vectors available */
-	u16 num_static;	/* preallocated entries */
-};
-
 struct ice_virt_irq_tracker {
 	unsigned long *bm;	/* bitmap to track irq usage */
 	u32 num_entries;
@@ -28,9 +17,6 @@ struct ice_virt_irq_tracker {
 int ice_init_interrupt_scheme(struct ice_pf *pf);
 void ice_clear_interrupt_scheme(struct ice_pf *pf);
 
-struct msi_map ice_alloc_irq(struct ice_pf *pf, bool dyn_only);
-void ice_free_irq(struct ice_pf *pf, struct msi_map map);
-
 int ice_virt_get_irqs(struct ice_pf *pf, u32 needed);
 void ice_virt_free_irqs(struct ice_pf *pf, u32 index, u32 irqs);
 #endif
diff --git a/drivers/net/ethernet/intel/ice/ice_lib.c b/drivers/net/ethernet/intel/ice/ice_lib.c
index 93e405dd6f5a..6eb758404f54 100644
--- a/drivers/net/ethernet/intel/ice/ice_lib.c
+++ b/drivers/net/ethernet/intel/ice/ice_lib.c
@@ -211,7 +211,6 @@ static void ice_vsi_set_num_qs(struct ice_vsi *vsi)
 		vsi->alloc_txq = 1;
 		vsi->alloc_rxq = 1;
 		vsi->num_q_vectors = 1;
-		vsi->irq_dyn_alloc = true;
 		break;
 	case ICE_VSI_VF:
 		if (vf->num_req_qs)
@@ -572,8 +571,6 @@ ice_vsi_alloc_def(struct ice_vsi *vsi, struct ice_channel *ch)
 			return -ENOMEM;
 	}
 
-	vsi->irq_dyn_alloc = pci_msix_can_alloc_dyn(vsi->back->pdev);
-
 	switch (vsi->type) {
 	case ICE_VSI_PF:
 	case ICE_VSI_SF:
diff --git a/drivers/net/ethernet/intel/ice/ice_main.c b/drivers/net/ethernet/intel/ice/ice_main.c
index 4d63ebba36d6..12f8f2ebf119 100644
--- a/drivers/net/ethernet/intel/ice/ice_main.c
+++ b/drivers/net/ethernet/intel/ice/ice_main.c
@@ -44,6 +44,7 @@ MODULE_IMPORT_NS("LIBETH_XDP");
 MODULE_IMPORT_NS("LIBIE");
 MODULE_IMPORT_NS("LIBIE_ADMINQ");
 MODULE_IMPORT_NS("LIBIE_FWLOG");
+MODULE_IMPORT_NS("LIBIE_IRQ");
 MODULE_LICENSE("GPL v2");
 MODULE_FIRMWARE(ICE_DDP_PKG_FILE);
 
@@ -3357,7 +3358,7 @@ static void ice_free_irq_msix_ll_ts(struct ice_pf *pf)
 	synchronize_irq(irq_num);
 	devm_free_irq(ice_pf_to_dev(pf), irq_num, pf);
 
-	ice_free_irq(pf, pf->ll_ts_irq);
+	libie_irq_free(&pf->irq, pf->ll_ts_irq);
 }
 
 /**
@@ -3378,7 +3379,7 @@ static void ice_free_irq_msix_misc(struct ice_pf *pf)
 	synchronize_irq(misc_irq_num);
 	devm_free_irq(ice_pf_to_dev(pf), misc_irq_num, pf);
 
-	ice_free_irq(pf, pf->oicr_irq);
+	libie_irq_free(&pf->irq, pf->oicr_irq);
 	if (pf->ll_ts_irq.index >= 0)
 		ice_free_irq_msix_ll_ts(pf);
 }
@@ -3447,7 +3448,7 @@ static int ice_req_irq_msix_misc(struct ice_pf *pf)
 		goto skip_req_irq;
 
 	/* reserve one vector in irq_tracker for misc interrupts */
-	irq = ice_alloc_irq(pf, false);
+	irq = libie_irq_alloc(&pf->irq, LIBIE_IRQ_STATIC);
 	if (irq.index < 0)
 		return irq.index;
 
@@ -3458,7 +3459,7 @@ static int ice_req_irq_msix_misc(struct ice_pf *pf)
 	if (err) {
 		dev_err(dev, "devm_request_threaded_irq for %s failed: %d\n",
 			pf->int_name, err);
-		ice_free_irq(pf, pf->oicr_irq);
+		libie_irq_free(&pf->irq, pf->oicr_irq);
 		return err;
 	}
 
@@ -3468,7 +3469,7 @@ static int ice_req_irq_msix_misc(struct ice_pf *pf)
 		goto skip_req_irq;
 	}
 
-	irq = ice_alloc_irq(pf, false);
+	irq = libie_irq_alloc(&pf->irq, LIBIE_IRQ_STATIC);
 	if (irq.index < 0)
 		return irq.index;
 
@@ -3478,7 +3479,7 @@ static int ice_req_irq_msix_misc(struct ice_pf *pf)
 	if (err) {
 		dev_err(dev, "devm_request_irq for %s failed: %d\n",
 			pf->int_name_ll_ts, err);
-		ice_free_irq(pf, pf->ll_ts_irq);
+		libie_irq_free(&pf->irq, pf->ll_ts_irq);
 		pf->ll_ts_irq.index = -ENOENT;
 		return err;
 	}
@@ -3963,7 +3964,7 @@ void ice_deinit_pf(struct ice_pf *pf)
 	if (pf->ptp.clock)
 		ptp_clock_unregister(pf->ptp.clock);
 
-	if (!xa_empty(&pf->irq_tracker.entries))
+	if (!xa_empty(&pf->irq.entries))
 		ice_free_irq_msix_misc(pf);
 
 	xa_destroy(&pf->dyn_ports);
diff --git a/drivers/net/ethernet/intel/libie/irq.c b/drivers/net/ethernet/intel/libie/irq.c
index d26ffeffdcb2..4da763943b14 100644
--- a/drivers/net/ethernet/intel/libie/irq.c
+++ b/drivers/net/ethernet/intel/libie/irq.c
@@ -98,6 +98,7 @@ static struct libie_irq_entry *libie_get_irq(struct libie_irq *irq,
 					     enum libie_irq_type type)
 {
 	struct libie_irq_entry *entry;
+	struct xa_limit limit;
 	unsigned int index;
 
 	if (!irq->pdev)
@@ -113,9 +114,26 @@ static struct libie_irq_entry *libie_get_irq(struct libie_irq *irq,
 	if (!entry)
 		return NULL;
 
-	if (xa_alloc(&irq->entries, &index, entry, irq->limits[type],
-		     GFP_KERNEL))
-		goto free_entry;
+	/* If any, first try dynamic */
+	if (type == LIBIE_IRQ_ANY)
+		limit = irq->limits[LIBIE_IRQ_DYNAMIC];
+	else
+		limit = irq->limits[type];
+
+	if (xa_alloc(&irq->entries, &index, entry, limit, GFP_KERNEL)) {
+		if (type != LIBIE_IRQ_ANY)
+			goto free_entry;
+		/* Dynamic for any type failed, try static */
+		if (xa_alloc(&irq->entries, &index, entry,
+			     irq->limits[LIBIE_IRQ_STATIC], GFP_KERNEL))
+			goto free_entry;
+
+		type = LIBIE_IRQ_STATIC;
+	}
+
+	/* If still any it is dynamic */
+	if (type == LIBIE_IRQ_ANY)
+		type = LIBIE_IRQ_DYNAMIC;
 
 	entry->index = index;
 	entry->type = type;
@@ -149,6 +167,7 @@ EXPORT_SYMBOL_NS_GPL(libie_put_irq, "LIBIE_IRQ");
  *
  * For LIBIE_IRQ_DYNAMIC function allocs new interrupt and return it.
  * For LIBIE_IRQ_STATIC function returns already allocated one.
+ * For LIBIE_IRQ_ANY first try DYNAMIC, if it failed try STATIC
  *
  * The function should be called for getting irq information (index and virq)
  * for specific irq type. Returned information should be stored to use index for
@@ -202,8 +221,9 @@ EXPORT_SYMBOL_NS_GPL(libie_irq_alloc, "LIBIE_IRQ");
  * @irq: libie_irq structure
  * @map: msi_map structure returned from libie_alloc_irq()
  *
- * In case of dynamic allocation and LIBIE_IRQ_DYNAMIC type pci_msix_free_irq()
- * is called. Otherwise only free driver irq entry related resources.
+ * In case of dynamic allocation and LIBIE_IRQ_DYNAMIC (or LIBIE_IRQ_ANY)
+ * type pci_msix_free_irq() is called. Otherwise only free driver irq entry
+ * related resources.
  *
  * It is safe to call this function with map that doesn't exist in xarray
  * as long as the map.virq is 0 or negative. It is true when libie_irq_alloc()
diff --git a/include/linux/net/intel/libie/irq.h b/include/linux/net/intel/libie/irq.h
index 8d5873f13871..ff3f30b90ebd 100644
--- a/include/linux/net/intel/libie/irq.h
+++ b/include/linux/net/intel/libie/irq.h
@@ -17,6 +17,7 @@
  * enum libie_irq_type - enum representing types of irq entries
  * @LIBIE_IRQ_STATIC: irq static allocated from kernel at driver probe
  * @LIBIE_IRQ_DYNAMIC: irq dynamic allocated during normal driver operation
+ * @LIBIE_IRQ_ANY: use when STATIC or DYNAMIC can be allocated
  * @LIBIE_IRQ_NUM_TYPES: must be the last one, used to define the array size
  *
  * Enum is used to get software irq indexes from some kind of pool. The pool is
@@ -31,6 +32,7 @@
 enum libie_irq_type {
 	LIBIE_IRQ_STATIC,
 	LIBIE_IRQ_DYNAMIC,
+	LIBIE_IRQ_ANY,
 	LIBIE_IRQ_NUM_TYPES,
 };
 
-- 
2.49.0


^ permalink raw reply related	[flat|nested] 11+ messages in thread

* [PATCH iwl-next v2 09/10] ixd: support for getting lan memory regions
  2026-09-11 12:49 [PATCH iwl-next v2 00/10] Interrupts helper in libie Michal Swiatkowski
                   ` (7 preceding siblings ...)
  2026-09-11 12:49 ` [PATCH iwl-next v2 08/10] ice: use libie_irq for interrupts managing Michal Swiatkowski
@ 2026-09-11 12:49 ` Michal Swiatkowski
  2026-09-11 12:49 ` [PATCH iwl-next v2 10/10] ixd: use interrupt for mailbox communication Michal Swiatkowski
  9 siblings, 0 replies; 11+ messages in thread
From: Michal Swiatkowski @ 2026-09-11 12:49 UTC (permalink / raw)
  To: intel-wired-lan; +Cc: netdev, Michal Swiatkowski

Send and parse get lan memory regions command. Map the regions from
the command response.

It is needed to set number of regions to not zero value even when
just sending the command. Set it to 1 and add comment about that.

It is possible that get lan memory regions isn't supported. Driver
should cover this situation by mapping regions needed for running.

Signed-off-by: Michal Swiatkowski <michal.swiatkowski@linux.intel.com>
---
 drivers/net/ethernet/intel/ixd/ixd.h          |   3 +
 drivers/net/ethernet/intel/ixd/ixd_main.c     | 131 +++++++++++++++---
 drivers/net/ethernet/intel/ixd/ixd_virtchnl.c |  90 +++++++++++-
 3 files changed, 201 insertions(+), 23 deletions(-)

diff --git a/drivers/net/ethernet/intel/ixd/ixd.h b/drivers/net/ethernet/intel/ixd/ixd.h
index 2a09ccba13d5..4a1590f937b5 100644
--- a/drivers/net/ethernet/intel/ixd/ixd.h
+++ b/drivers/net/ethernet/intel/ixd/ixd.h
@@ -63,5 +63,8 @@ bool ixd_check_reset_complete(struct ixd_adapter *adapter);
 void ixd_init_task(struct work_struct *work);
 int ixd_init_dflt_mbx(struct ixd_adapter *adapter);
 void ixd_deinit_dflt_mbx(struct ixd_adapter *adapter);
+int ixd_iomap_running_regions(struct ixd_adapter *adapter);
+bool ixd_iomap_is_not_start_region(struct libie_mmio_info *info,
+				   struct libie_pci_mmio_region *reg);
 
 #endif /* _IXD_H_ */
diff --git a/drivers/net/ethernet/intel/ixd/ixd_main.c b/drivers/net/ethernet/intel/ixd/ixd_main.c
index 5db992d4f9fb..488a919f3b1b 100644
--- a/drivers/net/ethernet/intel/ixd/ixd_main.c
+++ b/drivers/net/ethernet/intel/ixd/ixd_main.c
@@ -48,37 +48,124 @@ static void ixd_shutdown(struct pci_dev *pdev)
 
 /**
  * ixd_iomap_regions - iomap PCI BARs
- * @adapter: adapter to map memory regions for
+ * @mmio_info: PCI resources info
+ * @num: number of regions to map
+ * @regions: array of regions to map (offset and size)
  *
  * Returns: %0 on success, negative on failure
  */
-static int ixd_iomap_regions(struct ixd_adapter *adapter)
+static int ixd_iomap_regions(struct libie_mmio_info *mmio_info, int num,
+			     const struct ixd_bar_region *regions)
 {
-	const struct ixd_bar_region regions[] = {
-		{
-			.offset = PFGEN_RTRIG,
-			.size = PFGEN_RTRIG_REG_LEN,
-		},
-		{
-			.offset = PF_FW_MBX,
-			.size = PF_FW_MBX_REG_LEN,
-		},
-	};
-
-	for (int i = 0; i < ARRAY_SIZE(regions); i++) {
-		struct libie_mmio_info *mmio_info = &adapter->cp_ctx.mmio_info;
+	for (int i = 0; i < num; i++) {
 		bool map_ok;
 
 		map_ok = libie_pci_map_mmio_region(mmio_info,
 						   regions[i].offset,
 						   regions[i].size);
-		if (!map_ok) {
-			dev_err(ixd_to_dev(adapter),
-				"Failed to map PCI device MMIO region\n");
-
-			libie_pci_unmap_all_mmio_regions(mmio_info);
+		if (!map_ok)
 			return -EIO;
-		}
+	}
+
+	return 0;
+}
+
+/* Regions needed to reset the device and to talk to the control plane.
+ * They are mapped in probe and stay mapped for the whole driver life.
+ */
+static const struct ixd_bar_region ixd_start_regions[] = {
+	{
+		.offset = PFGEN_RTRIG,
+		.size = PFGEN_RTRIG_REG_LEN,
+	},
+	{
+		.offset = PF_FW_MBX,
+		.size = PF_FW_MBX_REG_LEN,
+	},
+};
+
+/**
+ * ixd_iomap_is_not_start_region - check if the region isn't a start region
+ * @info: PCI resources info, unused
+ * @reg: region to check
+ *
+ * Return: %true if it isn't a start region, %false otherwise
+ */
+bool ixd_iomap_is_not_start_region(struct libie_mmio_info *info,
+				   struct libie_pci_mmio_region *reg)
+{
+	for (unsigned int i = 0; i < ARRAY_SIZE(ixd_start_regions); i++) {
+		if (reg->bar_idx == 0 &&
+		    reg->offset == ixd_start_regions[i].offset &&
+		    reg->size == ixd_start_regions[i].size)
+			return false;
+	}
+
+	return true;
+}
+
+/**
+ * ixd_iomap_start_regions - iomap PCI BARs needed for driver startup
+ * @adapter: adapter to map memory regions for
+ *
+ * Returns: %0 on success, negative on failure
+ */
+static int ixd_iomap_start_regions(struct ixd_adapter *adapter)
+{
+	struct libie_mmio_info *mmio_info = &adapter->cp_ctx.mmio_info;
+	int err;
+
+	err = ixd_iomap_regions(mmio_info, ARRAY_SIZE(ixd_start_regions),
+				ixd_start_regions);
+	if (err) {
+		dev_err(ixd_to_dev(adapter),
+			"Failed to map startup PCI device MMIO region\n");
+
+		libie_pci_unmap_all_mmio_regions(mmio_info);
+	}
+
+	return err;
+}
+
+/**
+ * ixd_iomap_running_regions - iomap PCI BARs needed for driver when running
+ * @adapter: adapter to map memory regions for
+ *
+ * It should be called only when the GET_LAN_MEMORY_REGIONS virtchnl command
+ * isn't supported. Calculate the offsets and sizes for the regions before,
+ * in between, and after the start regions (mailbox and reset registers) and
+ * map those ranges.
+ *
+ * Returns: %0 on success, negative on failure
+ */
+int ixd_iomap_running_regions(struct ixd_adapter *adapter)
+{
+	struct libie_mmio_info *mmio_info = &adapter->cp_ctx.mmio_info;
+	resource_size_t start, size;
+	bool ok = true;
+
+	/* Region preceding the mailbox */
+	size = PF_FW_MBX;
+	ok &= !size || libie_pci_map_mmio_region(mmio_info, 0, size);
+
+	/* Region between the mailbox and the reset registers */
+	start = PF_FW_MBX + PF_FW_MBX_REG_LEN;
+	size = PFGEN_RTRIG - start;
+	ok &= !size || libie_pci_map_mmio_region(mmio_info, start, size);
+
+	/* Region after the reset registers */
+	start = PFGEN_RTRIG + PFGEN_RTRIG_REG_LEN;
+	size = pci_resource_len(mmio_info->pdev, 0) - start;
+	ok &= !size || libie_pci_map_mmio_region(mmio_info, start, size);
+
+	if (!ok) {
+		dev_err(ixd_to_dev(adapter),
+			"Failed to map running PCI device MMIO region\n");
+
+		libie_pci_unmap_fltr_regs(mmio_info,
+					  ixd_iomap_is_not_start_region);
+
+		return -EIO;
 	}
 
 	return 0;
@@ -109,7 +196,7 @@ static int ixd_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
 
 	pci_set_drvdata(pdev, adapter);
 
-	err = ixd_iomap_regions(adapter);
+	err = ixd_iomap_start_regions(adapter);
 	if (err)
 		goto free_adapter;
 
diff --git a/drivers/net/ethernet/intel/ixd/ixd_virtchnl.c b/drivers/net/ethernet/intel/ixd/ixd_virtchnl.c
index fc3b6d2e28c5..3487183b49c9 100644
--- a/drivers/net/ethernet/intel/ixd/ixd_virtchnl.c
+++ b/drivers/net/ethernet/intel/ixd/ixd_virtchnl.c
@@ -3,6 +3,7 @@
 
 #include "ixd.h"
 #include "ixd_ctlq.h"
+#include "ixd_lan_regs.h"
 #include "ixd_virtchnl.h"
 
 /**
@@ -62,6 +63,14 @@ static int ixd_handle_caps(struct ixd_adapter *adapter, void *recv_buff,
 	return 0;
 }
 
+static void ixd_fill_caps(struct ixd_adapter *adapter, void *send_buff,
+			  void *ctx)
+{
+	struct virtchnl2_get_capabilities *caps = send_buff;
+
+	caps->other_caps = cpu_to_le64(VIRTCHNL2_CAP_LAN_MEMORY_REGIONS);
+}
+
 /**
  * ixd_req_vc_caps - Request and save device capability
  * @adapter: The adapter to get the capabilities for
@@ -74,13 +83,18 @@ static int ixd_req_vc_caps(struct ixd_adapter *adapter)
 		.opcode = VIRTCHNL2_OP_GET_CAPS,
 		.send_size = sizeof(struct virtchnl2_get_capabilities),
 		.ctx = NULL,
-		.send_buff_init = NULL,
+		.send_buff_init = ixd_fill_caps,
 		.recv_process = ixd_handle_caps,
 	};
 
 	return ixd_ctlq_do_req(adapter, &req);
 }
 
+static bool ixd_is_cap_ena(struct ixd_adapter *adapter, u64 cap)
+{
+	return (le64_to_cpu(adapter->caps.other_caps) & cap) == cap;
+}
+
 /**
  * ixd_get_vc_ver - Get version info from adapter
  *
@@ -160,6 +174,69 @@ static int ixd_req_vc_version(struct ixd_adapter *adapter)
 	return ixd_ctlq_do_req(adapter, &req);
 }
 
+static void ixd_fill_lan_mmio_regions(struct ixd_adapter *adapter,
+				      void *send_buff, void *ctx)
+{
+	struct virtchnl2_get_lan_memory_regions *lan = send_buff;
+
+	/* Needed to be parsed correctly, this mem_region doesn't matter. */
+	lan->num_memory_regions = cpu_to_le16(1);
+}
+
+static int ixd_handle_lan_mmio_regions(struct ixd_adapter *adapter,
+				       void *recv_buff, size_t recv_size,
+				       void *ctx)
+{
+	struct libie_mmio_info *mmio_info = &adapter->cp_ctx.mmio_info;
+	struct virtchnl2_get_lan_memory_regions *recv_mmio = recv_buff;
+	int num_regions;
+
+	if (recv_size < sizeof(*recv_mmio))
+		return -EBADMSG;
+
+	num_regions = le16_to_cpu(recv_mmio->num_memory_regions);
+	if (!num_regions)
+		return -EBADMSG;
+
+	if (recv_size < struct_size(recv_mmio, mem_reg, num_regions))
+		return -EBADMSG;
+
+	for (int i = 0; i < num_regions; i++) {
+		struct virtchnl2_mem_region *reg = &recv_mmio->mem_reg[i];
+		resource_size_t offset, size;
+
+		offset = le64_to_cpu(reg->start_offset);
+		size = le64_to_cpu(reg->size);
+
+		/* Empty regions are used as a padding, skip them. */
+		if (!size)
+			continue;
+
+		if (!libie_pci_map_mmio_region(mmio_info, offset, size)) {
+			/* Unmap already mapped */
+			libie_pci_unmap_fltr_regs(mmio_info,
+						  ixd_iomap_is_not_start_region);
+			return -EIO;
+		}
+	}
+
+	return 0;
+}
+
+static int ixd_req_lan_mmio_regions(struct ixd_adapter *adapter)
+{
+	const struct ixd_ctlq_req req = {
+		.opcode = VIRTCHNL2_OP_GET_LAN_MEMORY_REGIONS,
+		.send_size = sizeof(struct virtchnl2_get_lan_memory_regions) +
+			     sizeof(struct virtchnl2_mem_region),
+		.ctx = NULL,
+		.send_buff_init = ixd_fill_lan_mmio_regions,
+		.recv_process = ixd_handle_lan_mmio_regions,
+	};
+
+	return ixd_ctlq_do_req(adapter, &req);
+}
+
 /**
  * ixd_vc_dev_init - virtchnl device core initialization
  * @adapter: device information
@@ -186,5 +263,16 @@ int ixd_vc_dev_init(struct ixd_adapter *adapter)
 		return err;
 	}
 
+	if (ixd_is_cap_ena(adapter, VIRTCHNL2_CAP_LAN_MEMORY_REGIONS))
+		err = ixd_req_lan_mmio_regions(adapter);
+	else
+		/* Fallback to mapping the remaining regions of the whole BAR */
+		err = ixd_iomap_running_regions(adapter);
+
+	if (err)
+		dev_warn(ixd_to_dev(adapter),
+			 "Getting LAN mmio regions failed, error=%pe\n",
+			 ERR_PTR(err));
+
 	return err;
 }
-- 
2.49.0


^ permalink raw reply related	[flat|nested] 11+ messages in thread

* [PATCH iwl-next v2 10/10] ixd: use interrupt for mailbox communication
  2026-09-11 12:49 [PATCH iwl-next v2 00/10] Interrupts helper in libie Michal Swiatkowski
                   ` (8 preceding siblings ...)
  2026-09-11 12:49 ` [PATCH iwl-next v2 09/10] ixd: support for getting lan memory regions Michal Swiatkowski
@ 2026-09-11 12:49 ` Michal Swiatkowski
  9 siblings, 0 replies; 11+ messages in thread
From: Michal Swiatkowski @ 2026-09-11 12:49 UTC (permalink / raw)
  To: intel-wired-lan; +Cc: netdev, Michal Swiatkowski, Aleksandr Loktionov

Switch from polling to interrupt for invoking mailbox operations when it
is available.

Add flag to store the information about the mailbox interrupt. If
interrupt is turned off mailbox will be handled by periodic workqueue.
If it is enabled interrupt will take care of it.

Reviewed-by: Aleksandr Loktionov <aleksandr.loktionov@intel.com>
Signed-off-by: Michal Swiatkowski <michal.swiatkowski@linux.intel.com>
---
 drivers/net/ethernet/intel/ixd/Kconfig        |   1 +
 drivers/net/ethernet/intel/ixd/ixd.h          |  28 ++++
 drivers/net/ethernet/intel/ixd/ixd_ctlq.c     |   8 +-
 drivers/net/ethernet/intel/ixd/ixd_lan_regs.h |  10 ++
 drivers/net/ethernet/intel/ixd/ixd_lib.c      | 126 ++++++++++++++++++
 drivers/net/ethernet/intel/ixd/ixd_main.c     |   2 +
 6 files changed, 173 insertions(+), 2 deletions(-)

diff --git a/drivers/net/ethernet/intel/ixd/Kconfig b/drivers/net/ethernet/intel/ixd/Kconfig
index 0a48b3bb7bc2..69c37c2cdb67 100644
--- a/drivers/net/ethernet/intel/ixd/Kconfig
+++ b/drivers/net/ethernet/intel/ixd/Kconfig
@@ -6,6 +6,7 @@ config IXD
 	depends on PCI_MSI
 	select LIBIE_CP
 	select LIBIE_PCI
+	select LIBIE_IRQ
 	select NET_DEVLINK
 	help
 	  This driver supports Intel(R) Control Plane PCI Function
diff --git a/drivers/net/ethernet/intel/ixd/ixd.h b/drivers/net/ethernet/intel/ixd/ixd.h
index 4a1590f937b5..ed5ffe04f48d 100644
--- a/drivers/net/ethernet/intel/ixd/ixd.h
+++ b/drivers/net/ethernet/intel/ixd/ixd.h
@@ -5,9 +5,20 @@
 #define _IXD_H_
 
 #include <linux/net/intel/libie/controlq.h>
+#include <linux/net/intel/libie/irq.h>
 
 #define IXD_INIT_TASK_DELAY_JIFFIES	msecs_to_jiffies(500)
 
+/**
+ * enum ixd_flags - Whole device flags
+ * @IXD_MB_INTR_MODE: Mailbox in interrupt mode
+ * @IXD_FLAGS_NBITS: Must be last
+ */
+enum ixd_flags {
+	IXD_MB_INTR_MODE,
+	IXD_FLAGS_NBITS,
+};
+
 /**
  * struct ixd_adapter - Data structure representing a CPF
  * @cp_ctx: Control plane communication context
@@ -24,6 +35,11 @@
  * @vc_ver.major: Negotiated major virtchnl version
  * @vc_ver.minor: Negotiated minor virtchnl version
  * @caps: Negotiated virtchnl capabilities
+ * @mb_irq: index and virq to track mailbox
+ * @irq: libie irq for interrupts management
+ * @mb_dyn_ctl: mailbox dynamic control register address
+ * @oicr_ena: direct OICR enable register address
+ * @flags: look at enum ixd_flags for more details
  */
 struct ixd_adapter {
 	struct libie_ctlq_ctx cp_ctx;
@@ -42,6 +58,11 @@ struct ixd_adapter {
 		u32 minor;
 	} vc_ver;
 	struct virtchnl2_get_capabilities caps;
+	struct msi_map mb_irq;
+	struct libie_irq irq;
+	void __iomem *mb_dyn_ctl;
+	void __iomem *oicr_ena;
+	DECLARE_BITMAP(flags, IXD_FLAGS_NBITS);
 };
 
 /**
@@ -55,6 +76,11 @@ static inline struct device *ixd_to_dev(struct ixd_adapter *adapter)
 	return &adapter->cp_ctx.mmio_info.pdev->dev;
 }
 
+static inline struct pci_dev *ixd_to_pdev(struct ixd_adapter *adapter)
+{
+	return adapter->cp_ctx.mmio_info.pdev;
+}
+
 void ixd_ctlq_reg_init(struct ixd_adapter *adapter,
 		       struct libie_ctlq_reg *ctlq_reg_tx,
 		       struct libie_ctlq_reg *ctlq_reg_rx);
@@ -66,5 +92,7 @@ void ixd_deinit_dflt_mbx(struct ixd_adapter *adapter);
 int ixd_iomap_running_regions(struct ixd_adapter *adapter);
 bool ixd_iomap_is_not_start_region(struct libie_mmio_info *info,
 				   struct libie_pci_mmio_region *reg);
+void ixd_deinit_interrupts(struct ixd_adapter *adapter);
+void ixd_mailbox_irq_enable(struct ixd_adapter *adapter);
 
 #endif /* _IXD_H_ */
diff --git a/drivers/net/ethernet/intel/ixd/ixd_ctlq.c b/drivers/net/ethernet/intel/ixd/ixd_ctlq.c
index 8712e10c8c50..43daef30689a 100644
--- a/drivers/net/ethernet/intel/ixd/ixd_ctlq.c
+++ b/drivers/net/ethernet/intel/ixd/ixd_ctlq.c
@@ -134,8 +134,12 @@ void ixd_ctlq_rx_task(struct work_struct *work)
 
 	adapter = container_of(work, struct ixd_adapter, mbx_task.work);
 
-	queue_delayed_work(system_dfl_wq, &adapter->mbx_task,
-			   IXD_CTLQ_RX_TASK_DELAY_JIFFIES);
+	if (test_bit(IXD_MB_INTR_MODE, adapter->flags))
+		/* Just re-enable irq in HW. */
+		ixd_mailbox_irq_enable(adapter);
+	else
+		queue_delayed_work(system_dfl_wq, &adapter->mbx_task,
+				   IXD_CTLQ_RX_TASK_DELAY_JIFFIES);
 
 	ixd_ctlq_recv_mb_msg(adapter);
 }
diff --git a/drivers/net/ethernet/intel/ixd/ixd_lan_regs.h b/drivers/net/ethernet/intel/ixd/ixd_lan_regs.h
index 58e58c75981b..b924ada5f831 100644
--- a/drivers/net/ethernet/intel/ixd/ixd_lan_regs.h
+++ b/drivers/net/ethernet/intel/ixd/ixd_lan_regs.h
@@ -31,6 +31,16 @@
 #define PF_FW_ATQH			(PF_FW_MBX + 0x20)
 #define PF_FW_ATQT			(PF_FW_MBX + 0x24)
 
+/* Interrupts */
+#define PF_GLINT_DYN_CTL_INTENA_S	0
+#define PF_GLINT_DYN_CTL_INTENA_M	BIT(PF_GLINT_DYN_CTL_INTENA_S)
+#define PF_GLINT_DYN_CTL_ITR_INDX_S	3
+#define PF_GLINT_DYN_CTL_ITR_INDX_M	GENMASK(4, 3)
+
+/* Generic registers */
+#define PF_INT_DIR_OICR_ENA		0x08406000
+#define PF_INT_DIR_OICR_ENA_M		GENMASK(31, 0)
+
 /* Reset registers */
 #define PFGEN_RTRIG_REG_LEN		2048
 #define PFGEN_RTRIG			0x08407000	/* Device resets */
diff --git a/drivers/net/ethernet/intel/ixd/ixd_lib.c b/drivers/net/ethernet/intel/ixd/ixd_lib.c
index 8311f7590666..e13614603a9e 100644
--- a/drivers/net/ethernet/intel/ixd/ixd_lib.c
+++ b/drivers/net/ethernet/intel/ixd/ixd_lib.c
@@ -4,6 +4,7 @@
 #include "ixd.h"
 #include "ixd_ctlq.h"
 #include "ixd_devlink.h"
+#include "ixd_lan_regs.h"
 #include "ixd_virtchnl.h"
 
 #define IXD_DFLT_MBX_Q_LEN 64
@@ -57,6 +58,125 @@ static void ixd_adapter_fill_dflt_ctlqs(struct ixd_adapter *adapter)
 				       LIBIE_CTLQ_MBX_ID);
 }
 
+static irqreturn_t ixd_mailbox_irq_handler(int __always_unused irq, void *data)
+{
+	struct ixd_adapter *adapter = (struct ixd_adapter *)data;
+
+	queue_delayed_work(system_dfl_wq, &adapter->mbx_task, 0);
+
+	return IRQ_HANDLED;
+}
+
+void ixd_mailbox_irq_enable(struct ixd_adapter *adapter)
+{
+	writel(PF_GLINT_DYN_CTL_INTENA_M | PF_GLINT_DYN_CTL_ITR_INDX_M,
+	       adapter->mb_dyn_ctl);
+	writel(PF_INT_DIR_OICR_ENA_M, adapter->oicr_ena);
+}
+
+static void ixd_mailbox_irq_disable(struct ixd_adapter *adapter)
+{
+	/* Clear INTENA, keep the ITR index pointing to the no update one. */
+	writel(PF_GLINT_DYN_CTL_ITR_INDX_M, adapter->mb_dyn_ctl);
+	writel(0, adapter->oicr_ena);
+}
+
+static int ixd_mailbox_irq_regs_init(struct ixd_adapter *adapter)
+{
+	struct libie_mmio_info *mmio = &adapter->cp_ctx.mmio_info;
+	u32 dyn_ctl = le32_to_cpu(adapter->caps.mailbox_dyn_ctl);
+
+	adapter->mb_dyn_ctl = libie_pci_get_mmio_addr(mmio, dyn_ctl);
+	adapter->oicr_ena = libie_pci_get_mmio_addr(mmio, PF_INT_DIR_OICR_ENA);
+
+	if (!adapter->mb_dyn_ctl || !adapter->oicr_ena)
+		return -EINVAL;
+
+	return 0;
+}
+
+static void ixd_mailbox_irq_deinit(struct ixd_adapter *adapter)
+{
+	if (!test_and_clear_bit(IXD_MB_INTR_MODE, adapter->flags))
+		return;
+
+	ixd_mailbox_irq_disable(adapter);
+
+	/* The mailbox task re-arms the interrupt, make sure it isn't running
+	 * anymore before the irq line is freed.
+	 */
+	cancel_delayed_work_sync(&adapter->mbx_task);
+
+	kfree(free_irq(adapter->mb_irq.virq, adapter));
+	libie_irq_free(&adapter->irq, adapter->mb_irq);
+}
+
+static int ixd_mailbox_irq_init(struct ixd_adapter *adapter)
+{
+	struct msi_map *irq = &adapter->mb_irq;
+	char *name;
+	int err;
+
+	*irq = libie_irq_alloc(&adapter->irq, LIBIE_IRQ_STATIC);
+	if (irq->index < 0)
+		return irq->index;
+
+	name = kasprintf(GFP_KERNEL, "%s-%s-%d",
+			 dev_driver_string(ixd_to_dev(adapter)), "Mailbox", 0);
+	if (!name) {
+		libie_irq_free(&adapter->irq, adapter->mb_irq);
+
+		return -ENOMEM;
+	}
+
+	err = request_irq(irq->virq, ixd_mailbox_irq_handler, 0, name, adapter);
+	if (err) {
+		kfree(name);
+		libie_irq_free(&adapter->irq, adapter->mb_irq);
+		dev_err(ixd_to_dev(adapter), "IRQ request for mailbox failed, error: %d\n",
+			err);
+
+		return err;
+	}
+
+	set_bit(IXD_MB_INTR_MODE, adapter->flags);
+
+	return 0;
+}
+
+void ixd_deinit_interrupts(struct ixd_adapter *adapter)
+{
+	ixd_mailbox_irq_deinit(adapter);
+	libie_irq_deinit(&adapter->irq);
+}
+
+static int ixd_init_interrupts(struct ixd_adapter *adapter)
+{
+	struct libie_irq *irq = &adapter->irq;
+	int err;
+
+	err = libie_irq_init(irq, ixd_to_pdev(adapter), 1, 1);
+	if (err)
+		return err;
+
+	err = ixd_mailbox_irq_regs_init(adapter);
+	if (err)
+		goto free_irq;
+
+	err = ixd_mailbox_irq_init(adapter);
+	if (err)
+		goto free_irq;
+
+	ixd_mailbox_irq_enable(adapter);
+
+	return 0;
+
+free_irq:
+	libie_irq_deinit(irq);
+
+	return err;
+}
+
 /**
  * ixd_deinit_dflt_mbx - Deinitialize default mailbox
  * @adapter: adapter info struct
@@ -154,6 +274,12 @@ void ixd_init_task(struct work_struct *work)
 		adapter->init_task.vc_retries = 0;
 		adapter->init_task.success = true;
 		ixd_devlink_register(adapter);
+
+		err = ixd_init_interrupts(adapter);
+		if (err)
+			dev_err(ixd_to_dev(adapter),
+				"Failed to initialize interrupts: %d\n",
+				err);
 		return;
 	}
 
diff --git a/drivers/net/ethernet/intel/ixd/ixd_main.c b/drivers/net/ethernet/intel/ixd/ixd_main.c
index 488a919f3b1b..e83550da3e9a 100644
--- a/drivers/net/ethernet/intel/ixd/ixd_main.c
+++ b/drivers/net/ethernet/intel/ixd/ixd_main.c
@@ -9,6 +9,7 @@
 MODULE_DESCRIPTION("Intel(R) Control Plane Function Device Driver");
 MODULE_IMPORT_NS("LIBIE_CP");
 MODULE_IMPORT_NS("LIBIE_PCI");
+MODULE_IMPORT_NS("LIBIE_IRQ");
 MODULE_LICENSE("GPL");
 
 /**
@@ -25,6 +26,7 @@ static void ixd_remove(struct pci_dev *pdev)
 	ixd_devlink_unregister(adapter);
 
 	/* Leave the device clean on exit */
+	ixd_deinit_interrupts(adapter);
 	if (adapter->xnm)
 		libie_ctlq_xn_shutdown(adapter->xnm);
 	ixd_trigger_reset(adapter);
-- 
2.49.0


^ permalink raw reply related	[flat|nested] 11+ messages in thread

end of thread, other threads:[~2026-09-11 13:30 UTC | newest]

Thread overview: 11+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-09-11 12:49 [PATCH iwl-next v2 00/10] Interrupts helper in libie Michal Swiatkowski
2026-09-11 12:49 ` [PATCH iwl-next v2 01/10] idpf: store HW vectors information Michal Swiatkowski
2026-09-11 12:49 ` [PATCH iwl-next v2 02/10] idpf: fill q_vector interrupt registers one by one Michal Swiatkowski
2026-09-11 12:49 ` [PATCH iwl-next v2 03/10] idpf: get rid of msix_entries array Michal Swiatkowski
2026-09-11 12:49 ` [PATCH iwl-next v2 04/10] idpf: drop v_idx from q_vector structure Michal Swiatkowski
2026-09-11 12:49 ` [PATCH iwl-next v2 05/10] libie, idpf: move irq code to libie Michal Swiatkowski
2026-09-11 12:49 ` [PATCH iwl-next v2 06/10] libie, idpf: move hardware irq info struct " Michal Swiatkowski
2026-09-11 12:49 ` [PATCH iwl-next v2 07/10] libie, idpf: move parsing alloc vectors command " Michal Swiatkowski
2026-09-11 12:49 ` [PATCH iwl-next v2 08/10] ice: use libie_irq for interrupts managing Michal Swiatkowski
2026-09-11 12:49 ` [PATCH iwl-next v2 09/10] ixd: support for getting lan memory regions Michal Swiatkowski
2026-09-11 12:49 ` [PATCH iwl-next v2 10/10] ixd: use interrupt for mailbox communication Michal Swiatkowski

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox