From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from mgamail.intel.com (mgamail.intel.com [198.175.65.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id D88BA46D560 for ; Mon, 7 Sep 2026 11:04:24 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=198.175.65.17 ARC-Seal:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788779068; cv=none; b=OnYWwMKBoJv3DNVCXFrPWqC/n/4oCucbGixXbNa1Kk5lf6mcAXcbjBchOWnXI+ovXN6mPZtrOja9HB/jbT1lK3tAAmltvI7NrlnpXSoTjtBsZOXUq7xrY5X3DglSyFaxXO/k9XGIGLmTA47UTKdMsabl/AMBtLXf4lL9okDlvEw= ARC-Message-Signature:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788779068; c=relaxed/simple; bh=tqX4SlANhV/RWQwCr4N0XPAJtdpwpLJ8dgOF/Z2ybl0=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=e8G7767qD5Z8x/7wTUTz8QrMA++wlL2wEM07NkCg3PA3GEpBsWxErr+5vmeRtLzJ5jBTXhko1bgyog/BEKNKXcWRGKm4BqRAPBITXGYvTx0JoC8PhoY1+UwBNOJJz5za/zwXwftsdzKW7RIqGrwVxq6iqt45XnkWmFpPakSPnhk= ARC-Authentication-Results:i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linux.intel.com; spf=pass smtp.mailfrom=linux.intel.com; dkim=pass (2048-bit key) header.d=intel.com header.i=@intel.com header.b=CNEgr74v; arc=none smtp.client-ip=198.175.65.17 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linux.intel.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=linux.intel.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=intel.com header.i=@intel.com header.b="CNEgr74v" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1788779065; x=1820315065; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=tqX4SlANhV/RWQwCr4N0XPAJtdpwpLJ8dgOF/Z2ybl0=; b=CNEgr74vlgQwBI8hCVnEwWOEV9NyvnIktTMZf1XZhH9V9XcJFECrvCHL WC5W++DE14V7u94zpRXMFbQAgDOAurRXH2xRDqmzxRMRil4XYpbJtoutt C6CjRALNOMIigkGuTbSM0Vi3cBvmuul+WqPPS7l+KIrP2yUwqAyIaDoC5 3b5eLf1ZXK1cAwT6hBCSv6DfYDC/IcDaA3GO37PJUfkeU1G0Whq5mUAI1 1Qd/nYF2RID323zdSErEjj2PFFIN/6D9PecrmsMJeP17IFVqrlbf3SXhc phffXIBswLz/U5a0uJE9pZdg/y/yBi38fzWUMZWkTB2l1fXLOPXl+X3Pm A==; X-CSE-ConnectionGUID: KgqBhbRlTWyUyjyP3BRtng== X-CSE-MsgGUID: KYye/1KoRj6hzxKEJS+4AQ== X-IronPort-AV: E=McAfee;i="6800,10657,11898"; a="89214075" X-IronPort-AV: E=Sophos;i="6.25,267,1779174000"; d="scan'208";a="89214075" Received: from orviesa003.jf.intel.com ([10.64.159.143]) by orvoesa109.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 07 Sep 2026 04:04:25 -0700 X-CSE-ConnectionGUID: jd3y+11iQwyR8+mGWBDyvA== X-CSE-MsgGUID: gd79quRJSk+BhdX8HGPtbQ== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="6.25,267,1779174000"; d="scan'208";a="274195407" Received: from os-delivery.igk.intel.com ([10.102.21.165]) by orviesa003.jf.intel.com with ESMTP; 07 Sep 2026 04:04:22 -0700 From: Michal Swiatkowski To: intel-wired-lan@lists.osuosl.org Cc: netdev@vger.kernel.org, Michal Swiatkowski , Aleksandr Loktionov , Larysa Zaremba Subject: [PATCH iwl-next v1 05/10] libie, idpf: move irq code to libie Date: Mon, 7 Sep 2026 12:24:12 +0200 Message-ID: <20260907102418.2697317-6-michal.swiatkowski@linux.intel.com> X-Mailer: git-send-email 2.49.0 In-Reply-To: <20260907102418.2697317-1-michal.swiatkowski@linux.intel.com> References: <20260907102418.2697317-1-michal.swiatkowski@linux.intel.com> Precedence: bulk X-Mailing-List: netdev@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: 8bit 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 Reviewed-by: Larysa Zaremba Signed-off-by: Michal Swiatkowski --- drivers/net/ethernet/intel/idpf/Kconfig | 1 + drivers/net/ethernet/intel/idpf/idpf.h | 56 +-- drivers/net/ethernet/intel/idpf/idpf_lib.c | 387 ++++++------------ drivers/net/ethernet/intel/idpf/idpf_main.c | 3 +- drivers/net/ethernet/intel/idpf/idpf_txrx.c | 98 +++-- 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 | 252 ++++++++++++ include/linux/net/intel/libie/irq.h | 75 ++++ 12 files changed, 538 insertions(+), 394 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..b7ed8272bc93 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 #include #include +#include #include #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 @@ -666,14 +625,12 @@ 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 + * @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 +663,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 +681,12 @@ 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 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 +724,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 +984,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_lib.c b/drivers/net/ethernet/intel/idpf/idpf_lib.c index 5a2975081227..a7143c58845d 100644 --- a/drivers/net/ethernet/intel/idpf/idpf_lib.c +++ b/drivers/net/ethernet/intel/idpf/idpf_lib.c @@ -9,56 +9,90 @@ 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_entry_to_index(struct idpf_adapter *adapter, int entry) { - 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; + for (int i = 0; i < adapter->irq_info.num; i++) + if (adapter->irq_info.vectors[i].idx == entry) + return i; - stack->vec_idx = kcalloc(stack->size, sizeof(u16), GFP_KERNEL); - if (!stack->vec_idx) { - mutex_unlock(&adapter->vector_lock); + return -EINVAL; +} +static int idpf_rdma_intr_init(struct idpf_adapter *adapter, u16 num) +{ + int i; + + if (!idpf_is_rdma_cap_ena(adapter)) + return 0; + + adapter->rdma_msix_entries = kzalloc_objs(struct msix_entry, num); + if (!adapter->rdma_msix_entries) 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--) { + struct msix_entry *entry = + &adapter->rdma_msix_entries[j]; + struct msi_map rdma_map; + + rdma_map.index = + idpf_rdma_entry_to_index(adapter, + entry->entry); + rdma_map.virq = entry->vector; + libie_irq_free(&adapter->irq, rdma_map); + } + kfree(adapter->rdma_msix_entries); + adapter->rdma_msix_entries = NULL; + return -EINVAL; + } + + adapter->rdma_msix_entries[i].entry = + adapter->irq_info.vectors[map.index].idx; + adapter->rdma_msix_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; + + adapter->rdma_msix_entries[i].entry = + adapter->irq_info.vectors[map.index].idx; + adapter->rdma_msix_entries[i].vector = map.virq; } - for (i = 0; i < stack->size; i++) - stack->vec_idx[i] = i; + adapter->num_rdma_msix_entries = 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; + if (!idpf_is_rdma_cap_ena(adapter)) + return; + + for (int i = 0; i < adapter->num_rdma_msix_entries; i++) { + struct msix_entry *entry = &adapter->rdma_msix_entries[i]; + struct msi_map map = { .index = + idpf_rdma_entry_to_index(adapter, entry->entry), + .virq = entry->vector }; + + libie_irq_free(&adapter->irq, map); + } - mutex_lock(&adapter->vector_lock); - stack = &adapter->vector_stack; - kfree(stack->vec_idx); - stack->vec_idx = NULL; - mutex_unlock(&adapter->vector_lock); + kfree(adapter->rdma_msix_entries); + adapter->rdma_msix_entries = NULL; + adapter->num_rdma_msix_entries = 0; } /** @@ -74,6 +108,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 +119,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 +184,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_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; + mb_vector->irq = libie_irq_alloc(&adapter->irq, LIBIE_IRQ_STATIC); + + 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 +210,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 +242,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 +849,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 +905,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 +926,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 +1047,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 +1098,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 +1112,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 +1135,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 +1331,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 +1451,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 +1914,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..69021e1deae4 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,45 @@ 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 msi_map *tmp_irqs __free(kfree) = NULL; + struct idpf_adapter *adapter = vport->adapter; struct idpf_q_vector *q_vector; struct idpf_q_coalesce *q_coal; + 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) + 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); + 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 (int i = 0; i < rsrc->num_q_vectors; i++) + libie_irq_free(&adapter->irq, tmp_irqs[i]); 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); @@ -4630,7 +4670,7 @@ int idpf_vport_intr_alloc(struct idpf_vport *vport, return 0; error: - idpf_vport_intr_rel(rsrc); + idpf_vport_intr_rel(rsrc, &adapter->irq); return -ENOMEM; } @@ -4646,10 +4686,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 71cac3e70ed8..e24740bbb7ca 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 @@ -3260,47 +3260,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); } /** @@ -3359,7 +3328,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..eb47bfd34cdd --- /dev/null +++ b/drivers/net/ethernet/intel/libie/irq.c @@ -0,0 +1,252 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* Copyright (C) 2025 Intel Corporation */ + +#include + +/** + * 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); +} +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; + + /* 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 || 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 + +/* 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