From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from smtpbg150.qq.com (smtpbg150.qq.com [18.132.163.193]) (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 7211B347507; Wed, 25 Mar 2026 09:13:29 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=18.132.163.193 ARC-Seal:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1774430016; cv=none; b=VGTPR4DPIATI3kuzPzrsYdPaLzmHGJmuY+iCgowtAOCOfRgrR/wliiNXq5Tzw6N5O/eI6Z6Asvo4qY8nm69h0CT6A+udQEZjMxaExMP3sW1ZLd1N8DO531swCA/eqcAUax779cjETrYgg5eFRS6US2AHMz/Ff9Wmw6gqvxEoSdM= ARC-Message-Signature:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1774430016; c=relaxed/simple; bh=FYBzihB3FeK7ndcXN1Bw52J4vYLAdWtjE0dgcK8oZEY=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=dbUSiWF9RtgpO8fzSw5h6kjJ4iIcwtr+30WMnsWbYC6PpeKAjdNAk/TNLx0dAitqjsF41jjKDgMKaKInUUwROn5FDWeoo07nmu/tNeOkrLsYVvDmudPjFCVhdkwyknLnaPIsjJEXr51oH/Rs5P9jirHiZMrkOeNuKPAv4JN9OXk= ARC-Authentication-Results:i=1; smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=mucse.com; spf=pass smtp.mailfrom=mucse.com; arc=none smtp.client-ip=18.132.163.193 Authentication-Results: smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=mucse.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=mucse.com X-QQ-mid: zesmtpsz4t1774429935t6e4063e2 X-QQ-Originating-IP: iS9L1J0Fhrq36/gFFUOVwsBwsGdfDrtSUIUI9we3ICE= Received: from localhost.localdomain ( [203.174.112.180]) by bizesmtp.qq.com (ESMTP) with id ; Wed, 25 Mar 2026 17:12:13 +0800 (CST) X-QQ-SSF: 0000000000000000000000000000000 X-QQ-GoodBg: 0 X-BIZMAIL-ID: 16712764290251698791 EX-QQ-RecipientCnt: 9 From: Dong Yibo To: andrew+netdev@lunn.ch, davem@davemloft.net, edumazet@google.com, kuba@kernel.org, pabeni@redhat.com, danishanwar@ti.com Cc: linux-kernel@vger.kernel.org, netdev@vger.kernel.org, dong100@mucse.com Subject: [PATCH net-next 1/4] net: rnpgbe: Add interrupt handling Date: Wed, 25 Mar 2026 17:12:01 +0800 Message-Id: <20260325091204.94015-2-dong100@mucse.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20260325091204.94015-1-dong100@mucse.com> References: <20260325091204.94015-1-dong100@mucse.com> Precedence: bulk X-Mailing-List: netdev@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-QQ-SENDSIZE: 520 Feedback-ID: zesmtpsz:mucse.com:qybglogicsvrgz:qybglogicsvrgz3a-1 X-QQ-XMAILINFO: OW4JKxETGMY2adAB6aEA6wZ1ZpmUxQuLn2+JIb3Or56Uj/CFen912z/M 4tjYNpSX4MCD+ZgWNz6wG7PEEsNUp4yFt0lOr6IytKw8P5U2XWxiuoZYNMkart3PtphL8q2 V4r4+AXuYgjhOutZ5sSnN/4h4eH1L82Kv7j4BUT7H71xKNGSBAnXSu+w4+xIWA5QELeRItj H8tjpfLD90qTNP1GOaPnJzh9ESmDFmS0pmi7MTfxr57rjs58zs69+g/jvBtdfB9Jh+8Agnf yCsf/e4Bhe4305Gd5LP0OYzn+IrSYuZBf7t2NZj7k+MeM4dbh6XaqFYgOMn99FwkVNnRRV8 TWqxy9DuIKw74zg3jqD/lUzhTFVSJfpYasSs3Mg+O3RUs+artDzXr3ow8p7IQgjNXIkiQYG 42hEziOA6al/c4z6h/D5doekTOguGzPN1YST9+YwrgY4+4/ghCnuFeRh7f11Sv72EtIq6O5 9S69p9+Jqo3xW7B6Sy7fQmDfvTC1T5Xj+aYx/VnzKXovGv4gHruDri/vejthK8gxl+VxGMy I8f5Wyupba5OOJq4o7JS3otvC8FhOInKd3xwUJm1jIoaOlvnVRlWtcfT/tVs0jQcJCoGlg4 dzNJV4+aMODqNjkCptC8HG9qfsfqq+n30WryTuHz83mQ/zMoX7iHAjpkoTJhA1zuhO9Kfrz CN7HGlKGL2GUALkePTTTbrOxJ7NCt7/5xAsRb+FU0YVEU2zjQ/H0q1UoBGJQYLwV652bSud woEkgSC92ugXswnLhFLIYHOYTC3c8GEYPHYPNwzvb6Ej8cTF4EQWjFqxVX+cDWhLPnWi/1D Y21ERRLPb0b3gMUYr+ptMPKaCgxa9yl8E6V4YEYsqSKYotz7/+TcCBZoqw27EbF9qUsernv JSWnu9eikZJT4dUnqxVbr0dAP1r4+nQPVwLkfsYSw3zcA/S1iCHBbGwi6cYTVZdPthTHvjN kzNF2p2m/pXnHA+lhLGicCM17z/01IBMuN0M2VREQMstA9Jsc7C+YovI6kx61IW7FzyxPAv 1ADzLozqapXgKh8mzd X-QQ-XMRINFO: NI4Ajvh11aEjEMj13RCX7UuhPEoou2bs1g== X-QQ-RECHKSPAM: 0 Add comprehensive interrupt handling for the RNPGBE driver: - Implement MSI-X/legacy interrupt configuration and management - Create library functions for interrupt registration and cleanup This infrastructure enables proper interrupt handling for the RNPGBE driver. Signed-off-by: Dong Yibo --- drivers/net/ethernet/mucse/rnpgbe/Makefile | 3 +- drivers/net/ethernet/mucse/rnpgbe/rnpgbe.h | 44 ++ .../net/ethernet/mucse/rnpgbe/rnpgbe_chip.c | 4 + drivers/net/ethernet/mucse/rnpgbe/rnpgbe_hw.h | 4 + .../net/ethernet/mucse/rnpgbe/rnpgbe_lib.c | 603 ++++++++++++++++++ .../net/ethernet/mucse/rnpgbe/rnpgbe_lib.h | 33 + .../net/ethernet/mucse/rnpgbe/rnpgbe_main.c | 43 +- 7 files changed, 732 insertions(+), 2 deletions(-) create mode 100644 drivers/net/ethernet/mucse/rnpgbe/rnpgbe_lib.c create mode 100644 drivers/net/ethernet/mucse/rnpgbe/rnpgbe_lib.h diff --git a/drivers/net/ethernet/mucse/rnpgbe/Makefile b/drivers/net/ethernet/mucse/rnpgbe/Makefile index de8bcb7772ab..17574cad392a 100644 --- a/drivers/net/ethernet/mucse/rnpgbe/Makefile +++ b/drivers/net/ethernet/mucse/rnpgbe/Makefile @@ -8,4 +8,5 @@ obj-$(CONFIG_MGBE) += rnpgbe.o rnpgbe-objs := rnpgbe_main.o\ rnpgbe_chip.o\ rnpgbe_mbx.o\ - rnpgbe_mbx_fw.o + rnpgbe_mbx_fw.o\ + rnpgbe_lib.o diff --git a/drivers/net/ethernet/mucse/rnpgbe/rnpgbe.h b/drivers/net/ethernet/mucse/rnpgbe/rnpgbe.h index 5b024f9f7e17..47cfaa6739f7 100644 --- a/drivers/net/ethernet/mucse/rnpgbe/rnpgbe.h +++ b/drivers/net/ethernet/mucse/rnpgbe/rnpgbe.h @@ -6,6 +6,10 @@ #include #include +#include +#include + +#include "rnpgbe_hw.h" enum rnpgbe_boards { board_n500, @@ -35,21 +39,61 @@ enum { struct mucse_hw { void __iomem *hw_addr; + void __iomem *ring_msix_base; struct pci_dev *pdev; struct mucse_mbx_info mbx; int port; u8 pfvfnum; }; +struct mucse_ring { + struct mucse_ring *next; + struct mucse_q_vector *q_vector; + void __iomem *ring_addr; + void __iomem *irq_mask; + void __iomem *trig; + u8 queue_index; + /* hw ring idx */ + u8 rnpgbe_queue_idx; +} ____cacheline_internodealigned_in_smp; + +struct mucse_ring_container { + struct mucse_ring *ring; + u16 count; +}; + +struct mucse_q_vector { + struct mucse *mucse; + int v_idx; + struct mucse_ring_container rx, tx; + struct napi_struct napi; + char name[IFNAMSIZ + 18]; + /* for dynamic allocation of rings associated with this q_vector */ + struct mucse_ring ring[0] ____cacheline_internodealigned_in_smp; +}; + struct mucse_stats { u64 tx_dropped; }; +#define MAX_Q_VECTORS 8 + struct mucse { struct net_device *netdev; struct pci_dev *pdev; struct mucse_hw hw; struct mucse_stats stats; +#define M_FLAG_LEGACY_EN BIT(0) +#define M_FLAG_MSI_EN BIT(1) +#define M_FLAG_MSIX_SINGLE_EN BIT(2) +#define M_FLAG_MSIX_EN BIT(3) + u32 flags; + struct mucse_ring *tx_ring[RNPGBE_MAX_QUEUES] ____cacheline_aligned_in_smp; + struct mucse_ring *rx_ring[RNPGBE_MAX_QUEUES] ____cacheline_aligned_in_smp; + struct mucse_q_vector *q_vector[MAX_Q_VECTORS]; + int num_tx_queues; + int num_q_vectors; + int num_rx_queues; }; int rnpgbe_get_permanent_mac(struct mucse_hw *hw, u8 *perm_addr); diff --git a/drivers/net/ethernet/mucse/rnpgbe/rnpgbe_chip.c b/drivers/net/ethernet/mucse/rnpgbe/rnpgbe_chip.c index ebc7b3750157..921cc325a991 100644 --- a/drivers/net/ethernet/mucse/rnpgbe/rnpgbe_chip.c +++ b/drivers/net/ethernet/mucse/rnpgbe/rnpgbe_chip.c @@ -89,6 +89,8 @@ static void rnpgbe_init_n500(struct mucse_hw *hw) { struct mucse_mbx_info *mbx = &hw->mbx; + hw->ring_msix_base = hw->hw_addr + MUCSE_N500_RING_MSIX_BASE; + mbx->fwpf_ctrl_base = MUCSE_N500_FWPF_CTRL_BASE; mbx->fwpf_shm_base = MUCSE_N500_FWPF_SHM_BASE; } @@ -104,6 +106,8 @@ static void rnpgbe_init_n210(struct mucse_hw *hw) { struct mucse_mbx_info *mbx = &hw->mbx; + hw->ring_msix_base = hw->hw_addr + MUCSE_N210_RING_MSIX_BASE; + mbx->fwpf_ctrl_base = MUCSE_N210_FWPF_CTRL_BASE; mbx->fwpf_shm_base = MUCSE_N210_FWPF_SHM_BASE; } diff --git a/drivers/net/ethernet/mucse/rnpgbe/rnpgbe_hw.h b/drivers/net/ethernet/mucse/rnpgbe/rnpgbe_hw.h index e77e6bc3d3e3..bc2c27fa6e71 100644 --- a/drivers/net/ethernet/mucse/rnpgbe/rnpgbe_hw.h +++ b/drivers/net/ethernet/mucse/rnpgbe/rnpgbe_hw.h @@ -6,12 +6,16 @@ #define MUCSE_N500_FWPF_CTRL_BASE 0x28b00 #define MUCSE_N500_FWPF_SHM_BASE 0x2d000 +#define MUCSE_N500_RING_MSIX_BASE 0x28700 #define MUCSE_GBE_PFFW_MBX_CTRL_OFFSET 0x5500 #define MUCSE_GBE_FWPF_MBX_MASK_OFFSET 0x5700 #define MUCSE_N210_FWPF_CTRL_BASE 0x29400 #define MUCSE_N210_FWPF_SHM_BASE 0x2d900 +#define MUCSE_N210_RING_MSIX_BASE 0x29000 #define RNPGBE_DMA_AXI_EN 0x0010 +#define RNPGBE_LEGACY_TIME 0xd000 +#define RNPGBE_LEGACY_ENABLE 0xd004 #define RNPGBE_MAX_QUEUES 8 #endif /* _RNPGBE_HW_H */ diff --git a/drivers/net/ethernet/mucse/rnpgbe/rnpgbe_lib.c b/drivers/net/ethernet/mucse/rnpgbe/rnpgbe_lib.c new file mode 100644 index 000000000000..00943deff940 --- /dev/null +++ b/drivers/net/ethernet/mucse/rnpgbe/rnpgbe_lib.c @@ -0,0 +1,603 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Copyright(c) 2020 - 2025 Mucse Corporation. */ + +#include +#include + +#include "rnpgbe_lib.h" +#include "rnpgbe.h" + +/** + * rnpgbe_msix_other - Other irq handler + * @irq: irq num + * @data: private data + * + * @return: IRQ_HANDLED + **/ +static irqreturn_t rnpgbe_msix_other(int irq, void *data) +{ + return IRQ_HANDLED; +} + +static void rnpgbe_irq_disable_queues(struct mucse_q_vector *q_vector) +{ + struct mucse_ring *ring; + + /* tx/rx use one register, different bit */ + mucse_for_each_ring(ring, q_vector->tx) { + writel(INT_VALID, ring->trig); + writel((RX_INT_MASK | TX_INT_MASK), ring->irq_mask); + } +} + +static void rnpgbe_irq_enable_queues(struct mucse_q_vector *q_vector) +{ + struct mucse_ring *ring; + + /* tx/rx use one register, different bit */ + mucse_for_each_ring(ring, q_vector->tx) { + writel(0, ring->irq_mask); + writel(INT_VALID | TX_INT_MASK | RX_INT_MASK, ring->trig); + } +} + +/** + * rnpgbe_poll - NAPI Rx polling callback + * @napi: structure for representing this polling device + * @budget: how many packets driver is allowed to clean + * + * @return: work done in this call + * This function is used for legacy and MSI, NAPI mode + **/ +static int rnpgbe_poll(struct napi_struct *napi, int budget) +{ + struct mucse_q_vector *q_vector = + container_of(napi, struct mucse_q_vector, napi); + + rnpgbe_irq_enable_queues(q_vector); + + return 0; +} + +/** + * register_mbx_irq - Register mbx routine + * @mucse: pointer to private structure + * + * @return: 0 on success, negative on failure + **/ +int register_mbx_irq(struct mucse *mucse) +{ + struct net_device *netdev = mucse->netdev; + struct pci_dev *pdev = mucse->pdev; + int err = 0; + + if (mucse->flags & M_FLAG_MSIX_EN) { + err = request_irq(pci_irq_vector(pdev, 0), + rnpgbe_msix_other, 0, netdev->name, + mucse); + } + + return err; +} + +/** + * remove_mbx_irq - Remove mbx routine + * @mucse: pointer to private structure + **/ +void remove_mbx_irq(struct mucse *mucse) +{ + struct pci_dev *pdev = mucse->pdev; + + if (mucse->flags & M_FLAG_MSIX_EN) + free_irq(pci_irq_vector(pdev, 0), mucse); +} + +/** + * rnpgbe_set_num_queues - Allocate queues for device, feature dependent + * @mucse: pointer to private structure + * + * Determine tx/rx queue nums + **/ +static void rnpgbe_set_num_queues(struct mucse *mucse) +{ + /* start from 1 queue */ + mucse->num_tx_queues = 1; + mucse->num_rx_queues = 1; +} + +/** + * rnpgbe_set_interrupt_capability - Set MSI-X or MSI if supported + * @mucse: pointer to private structure + * + * Attempt to configure the interrupts using the best available + * capabilities of the hardware. + * + * @return: 0 on success, negative on failure + **/ +static int rnpgbe_set_interrupt_capability(struct mucse *mucse) +{ + int v_budget; + + v_budget = min_t(int, mucse->num_tx_queues, mucse->num_rx_queues); + v_budget = min_t(int, v_budget, num_online_cpus()); + /* add one vector for mbx */ + v_budget += 1; + v_budget = pci_alloc_irq_vectors(mucse->pdev, 1, v_budget, + PCI_IRQ_ALL_TYPES); + if (v_budget < 0) + return v_budget; + + if (mucse->pdev->msix_enabled) { + /* q_vector not include mbx */ + if (v_budget > 1) { + mucse->flags |= M_FLAG_MSIX_EN; + mucse->num_q_vectors = v_budget - 1; + } else { + mucse->flags |= M_FLAG_MSIX_SINGLE_EN; + mucse->num_q_vectors = 1; + } + } else { + /* msi/legacy use only 1 irq */ + mucse->num_q_vectors = 1; + + if (mucse->pdev->msi_enabled) + mucse->flags |= M_FLAG_MSI_EN; + else + mucse->flags |= M_FLAG_LEGACY_EN; + } + + return 0; +} + +/** + * mucse_add_ring - Add ring to ring container + * @ring: ring to be added + * @head: ring container + **/ +static void mucse_add_ring(struct mucse_ring *ring, + struct mucse_ring_container *head) +{ + ring->next = head->ring; + head->ring = ring; + head->count++; +} + +/** + * rnpgbe_alloc_q_vector - Allocate memory for a single interrupt vector + * @mucse: pointer to private structure + * @eth_queue_idx: queue_index idx for this q_vector + * @v_idx: index of vector used for this q_vector + * @r_idx: total number of rings to allocate + * @r_count: ring count + * @step: ring step + * + * @return: 0 on success. If allocation fails we return -ENOMEM. + **/ +static int rnpgbe_alloc_q_vector(struct mucse *mucse, + int eth_queue_idx, int v_idx, int r_idx, + int r_count, int step) +{ + int rxr_idx = r_idx, txr_idx = r_idx; + struct mucse_hw *hw = &mucse->hw; + struct mucse_q_vector *q_vector; + int txr_count, rxr_count, idx; + struct mucse_ring *ring; + int ring_count, size; + + txr_count = r_count; + rxr_count = r_count; + ring_count = txr_count + rxr_count; + size = sizeof(struct mucse_q_vector) + + (sizeof(struct mucse_ring) * ring_count); + + q_vector = kzalloc(size, GFP_KERNEL); + if (!q_vector) + return -ENOMEM; + + netif_napi_add(mucse->netdev, &q_vector->napi, rnpgbe_poll); + /* tie q_vector and mucse together */ + mucse->q_vector[v_idx] = q_vector; + q_vector->mucse = mucse; + q_vector->v_idx = v_idx; + /* if mbx use separate irq, we should add 1 */ + if (mucse->flags & M_FLAG_MSIX_EN) + q_vector->v_idx++; + + ring = q_vector->ring; + + for (idx = 0; idx < txr_count; idx++) { + mucse_add_ring(ring, &q_vector->tx); + ring->queue_index = eth_queue_idx + idx; + ring->rnpgbe_queue_idx = txr_idx; + ring->ring_addr = hw->hw_addr + RING_OFFSET(txr_idx); + ring->irq_mask = ring->ring_addr + RNPGBE_DMA_INT_MASK; + ring->trig = ring->ring_addr + RNPGBE_DMA_INT_TRIG; + mucse->tx_ring[ring->queue_index] = ring; + txr_idx += step; + ring++; + } + + for (idx = 0; idx < rxr_count; idx++) { + mucse_add_ring(ring, &q_vector->rx); + ring->queue_index = eth_queue_idx + idx; + ring->rnpgbe_queue_idx = rxr_idx; + ring->ring_addr = hw->hw_addr + RING_OFFSET(rxr_idx); + ring->irq_mask = ring->ring_addr + RNPGBE_DMA_INT_MASK; + ring->trig = ring->ring_addr + RNPGBE_DMA_INT_TRIG; + mucse->rx_ring[ring->queue_index] = ring; + rxr_idx += step; + ring++; + } + + return 0; +} + +/** + * rnpgbe_free_q_vector - Free memory allocated for specific interrupt vector + * @mucse: pointer to private structure + * @v_idx: index of vector to be freed + * + * This function frees the memory allocated to the q_vector. In addition if + * NAPI is enabled it will delete any references to the NAPI struct prior + * to freeing the q_vector. + **/ +static void rnpgbe_free_q_vector(struct mucse *mucse, int v_idx) +{ + struct mucse_q_vector *q_vector = mucse->q_vector[v_idx]; + struct mucse_ring *ring; + + mucse_for_each_ring(ring, q_vector->tx) + mucse->tx_ring[ring->queue_index] = NULL; + mucse_for_each_ring(ring, q_vector->rx) + mucse->rx_ring[ring->queue_index] = NULL; + mucse->q_vector[v_idx] = NULL; + netif_napi_del(&q_vector->napi); + kfree(q_vector); +} + +/** + * rnpgbe_alloc_q_vectors - Allocate memory for interrupt vectors + * @mucse: pointer to private structure + * + * @return: 0 if success. if allocation fails we return -ENOMEM. + **/ +static int rnpgbe_alloc_q_vectors(struct mucse *mucse) +{ + int err, ring_cnt, v_remaing = mucse->num_q_vectors; + int r_remaing = min_t(int, mucse->num_tx_queues, + mucse->num_rx_queues); + int q_vector_nums = 0; + int eth_queue_idx = 0; + int ring_step = 1; + int ring_idx = 0; + int v_idx = 0; + + for (; r_remaing > 0 && v_remaing > 0; v_remaing--) { + ring_cnt = DIV_ROUND_UP(r_remaing, v_remaing); + err = rnpgbe_alloc_q_vector(mucse, eth_queue_idx, + v_idx, ring_idx, ring_cnt, + ring_step); + if (err) + goto err_free_q_vector; + ring_idx += ring_step * ring_cnt; + eth_queue_idx += ring_cnt; + r_remaing -= ring_cnt; + q_vector_nums++; + v_idx++; + } + /* Fix the real used q_vectors_nums */ + mucse->num_q_vectors = q_vector_nums; + + return 0; + +err_free_q_vector: + mucse->num_tx_queues = 0; + mucse->num_rx_queues = 0; + mucse->num_q_vectors = 0; + + while (v_idx--) + rnpgbe_free_q_vector(mucse, v_idx); + + return err; +} + +/** + * rnpgbe_reset_interrupt_capability - Reset irq capability setup + * @mucse: pointer to private structure + **/ +static void rnpgbe_reset_interrupt_capability(struct mucse *mucse) +{ + pci_free_irq_vectors(mucse->pdev); + mucse->flags &= ~(M_FLAG_MSIX_EN | + M_FLAG_MSIX_SINGLE_EN | + M_FLAG_MSI_EN | + M_FLAG_LEGACY_EN); +} + +/** + * rnpgbe_init_interrupt_scheme - Determine proper interrupt scheme + * @mucse: pointer to private structure + * + * We determine which interrupt scheme to use based on... + * - Hardware queue count + * - cpu numbers + * - irq mode (msi/legacy force 1) + * + * @return: 0 on success, negative on failure + **/ +int rnpgbe_init_interrupt_scheme(struct mucse *mucse) +{ + int err; + + rnpgbe_set_num_queues(mucse); + + err = rnpgbe_set_interrupt_capability(mucse); + if (err) + return err; + + err = rnpgbe_alloc_q_vectors(mucse); + if (err) { + rnpgbe_reset_interrupt_capability(mucse); + return err; + } + + return 0; +} + +/** + * rnpgbe_free_q_vectors - Free memory allocated for interrupt vectors + * @mucse: pointer to private structure + * + * This function frees the memory allocated to the q_vectors. In addition if + * NAPI is enabled it will delete any references to the NAPI struct prior + * to freeing the q_vector. + **/ +static void rnpgbe_free_q_vectors(struct mucse *mucse) +{ + int v_idx = mucse->num_q_vectors; + + mucse->num_rx_queues = 0; + mucse->num_tx_queues = 0; + mucse->num_q_vectors = 0; + + while (v_idx--) + rnpgbe_free_q_vector(mucse, v_idx); +} + +/** + * rnpgbe_clear_interrupt_scheme - Clear the current interrupt scheme settings + * @mucse: pointer to private structure + * + * Clear interrupt specific resources and reset the structure + **/ +void rnpgbe_clear_interrupt_scheme(struct mucse *mucse) +{ + mucse->num_tx_queues = 0; + mucse->num_rx_queues = 0; + rnpgbe_free_q_vectors(mucse); + rnpgbe_reset_interrupt_capability(mucse); +} + +/** + * rnpgbe_msix_clean_rings - Msix irq handler for ring irq + * @irq: irq num + * @data: private data + * + * rnpgbe_msix_clean_rings handle irq from ring, start napi + * @return: IRQ_HANDLED + **/ +static irqreturn_t rnpgbe_msix_clean_rings(int irq, void *data) +{ + struct mucse_q_vector *q_vector = (struct mucse_q_vector *)data; + + rnpgbe_irq_disable_queues(q_vector); + if (q_vector->rx.ring || q_vector->tx.ring) + napi_schedule_irqoff(&q_vector->napi); + + return IRQ_HANDLED; +} + +/** + * rnpgbe_intr - Msi/Legacy irq handler + * @irq: irq num + * @data: private data + * @return: IRQ_HANDLED + **/ +static irqreturn_t rnpgbe_intr(int irq, void *data) +{ + struct mucse *mucse = (struct mucse *)data; + struct mucse_q_vector *q_vector; + + q_vector = mucse->q_vector[0]; + rnpgbe_irq_disable_queues(q_vector); + if (q_vector->rx.ring || q_vector->tx.ring) + napi_schedule_irqoff(&q_vector->napi); + + return IRQ_HANDLED; +} + +/** + * rnpgbe_request_irq - Initialize interrupts + * @mucse: pointer to private structure + * + * Attempts to configure interrupts using the best available + * capabilities of the hardware and kernel. + * + * @return: 0 on success, negative value on failure + **/ +int rnpgbe_request_irq(struct mucse *mucse) +{ + struct net_device *netdev = mucse->netdev; + struct pci_dev *pdev = mucse->pdev; + struct mucse_hw *hw = &mucse->hw; + struct mucse_q_vector *q_vector; + int err, i; + + if (mucse->flags & M_FLAG_MSIX_EN) { + for (i = 0; i < mucse->num_q_vectors; i++) { + q_vector = mucse->q_vector[i]; + + snprintf(q_vector->name, sizeof(q_vector->name) - 1, + "%s-%s-%d", netdev->name, "TxRx", i); + + err = request_irq(pci_irq_vector(pdev, i + 1), + rnpgbe_msix_clean_rings, 0, + q_vector->name, + q_vector); + if (err) { + dev_err(&pdev->dev, "MSI-X req err %d: %d\n", + i + 1, err); + goto err_free_irqs; + } + } + } else { + /* Generic irq handler for all single-vector modes */ + err = request_irq(pci_irq_vector(pdev, 0), + rnpgbe_intr, 0, netdev->name, + mucse); + if (err) + return err; + } + + if (mucse->flags & M_FLAG_LEGACY_EN) { + mucse_hw_wr32(hw, RNPGBE_LEGACY_ENABLE, 1); + mucse_hw_wr32(hw, RNPGBE_LEGACY_TIME, 0x200); + } else { + mucse_hw_wr32(hw, RNPGBE_LEGACY_ENABLE, 0); + } + + return 0; +err_free_irqs: + while (i >= 0) { + i--; + q_vector = mucse->q_vector[i]; + synchronize_irq(pci_irq_vector(pdev, i + 1)); + free_irq(pci_irq_vector(pdev, i + 1), q_vector); + } + + return err; +} + +/** + * rnpgbe_free_irq - Free interrupts + * @mucse: pointer to private structure + * + * Attempts to free interrupts according initialized type. + **/ +void rnpgbe_free_irq(struct mucse *mucse) +{ + struct pci_dev *pdev = mucse->pdev; + struct mucse_q_vector *q_vector; + + if (mucse->flags & M_FLAG_MSIX_EN) { + for (int i = 0; i < mucse->num_q_vectors; i++) { + q_vector = mucse->q_vector[i]; + if (!q_vector) + continue; + + free_irq(pci_irq_vector(pdev, i + 1), q_vector); + } + } else { + free_irq(pci_irq_vector(pdev, 0), mucse); + } +} + +/** + * rnpgbe_set_ring_vector - Set the ring_vector registers, + * mapping interrupt causes to vectors + * @mucse: pointer to private structure + * @queue: queue to map the corresponding interrupt to + * @msix_vector: the vector num to map to the corresponding queue + * + */ +static void rnpgbe_set_ring_vector(struct mucse *mucse, + u8 queue, u8 msix_vector) +{ + struct mucse_hw *hw = &mucse->hw; + u32 data; + + data = hw->pfvfnum << 24; + data |= (msix_vector << 8); + data |= msix_vector; + writel(data, hw->ring_msix_base + RING_VECTOR(queue)); +} + +/** + * rnpgbe_configure_msix - Configure MSI-X hardware + * @mucse: pointer to private structure + * + * rnpgbe_configure_msix sets up the hardware to properly generate MSI-X + * interrupts. + **/ +static void rnpgbe_configure_msix(struct mucse *mucse) +{ + struct mucse_q_vector *q_vector; + + if (!(mucse->flags & (M_FLAG_MSIX_EN | M_FLAG_MSIX_SINGLE_EN))) + return; + + for (int i = 0; i < mucse->num_q_vectors; i++) { + struct mucse_ring *ring; + + q_vector = mucse->q_vector[i]; + /* tx/rx use one register, different bit */ + mucse_for_each_ring(ring, q_vector->tx) { + rnpgbe_set_ring_vector(mucse, ring->rnpgbe_queue_idx, + q_vector->v_idx); + } + } +} + +static void rnpgbe_irq_enable(struct mucse *mucse) +{ + for (int i = 0; i < mucse->num_q_vectors; i++) + rnpgbe_irq_enable_queues(mucse->q_vector[i]); +} + +/** + * rnpgbe_irq_disable - Mask off interrupt generation on the NIC + * @mucse: board private structure + **/ +void rnpgbe_irq_disable(struct mucse *mucse) +{ + struct pci_dev *pdev = mucse->pdev; + + if (mucse->flags & M_FLAG_MSIX_EN) { + for (int i = 0; i < mucse->num_q_vectors; i++) { + rnpgbe_irq_disable_queues(mucse->q_vector[i]); + synchronize_irq(pci_irq_vector(pdev, i + 1)); + } + } else { + rnpgbe_irq_disable_queues(mucse->q_vector[0]); + synchronize_irq(pci_irq_vector(pdev, 0)); + } +} + +static void rnpgbe_napi_enable_all(struct mucse *mucse) +{ + for (int i = 0; i < mucse->num_q_vectors; i++) + napi_enable(&mucse->q_vector[i]->napi); +} + +static void rnpgbe_napi_disable_all(struct mucse *mucse) +{ + for (int i = 0; i < mucse->num_q_vectors; i++) + napi_disable(&mucse->q_vector[i]->napi); +} + +void rnpgbe_down(struct mucse *mucse) +{ + rnpgbe_irq_disable(mucse); + rnpgbe_napi_disable_all(mucse); +} + +/** + * rnpgbe_up_complete - Final step for port up + * @mucse: pointer to private structure + **/ +void rnpgbe_up_complete(struct mucse *mucse) +{ + rnpgbe_configure_msix(mucse); + rnpgbe_napi_enable_all(mucse); + rnpgbe_irq_enable(mucse); +} diff --git a/drivers/net/ethernet/mucse/rnpgbe/rnpgbe_lib.h b/drivers/net/ethernet/mucse/rnpgbe/rnpgbe_lib.h new file mode 100644 index 000000000000..8e8234209840 --- /dev/null +++ b/drivers/net/ethernet/mucse/rnpgbe/rnpgbe_lib.h @@ -0,0 +1,33 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* Copyright(c) 2020 - 2025 Mucse Corporation. */ + +#ifndef _RNPGBE_LIB_H +#define _RNPGBE_LIB_H + +struct mucse; + +#define RING_OFFSET(n) (0x1000 + 0x100 * (n)) +#define RNPGBE_DMA_INT_MASK 0x24 +#define TX_INT_MASK BIT(1) +#define RX_INT_MASK BIT(0) +#define INT_VALID (BIT(16) | BIT(17)) +#define RNPGBE_DMA_INT_TRIG 0x2c +/* | 31:24 | .... | 15:8 | 7:0 | */ +/* | pfvfnum | | tx vector | rx vector | */ +#define RING_VECTOR(n) (0x04 * (n)) + +#define mucse_for_each_ring(pos, head)\ + for (typeof((head).ring) __pos = (head).ring;\ + __pos ? ({ pos = __pos; 1; }) : 0;\ + __pos = __pos->next) + +int rnpgbe_init_interrupt_scheme(struct mucse *mucse); +void rnpgbe_clear_interrupt_scheme(struct mucse *mucse); +int register_mbx_irq(struct mucse *mucse); +void remove_mbx_irq(struct mucse *mucse); +int rnpgbe_request_irq(struct mucse *mucse); +void rnpgbe_free_irq(struct mucse *mucse); +void rnpgbe_irq_disable(struct mucse *mucse); +void rnpgbe_down(struct mucse *mucse); +void rnpgbe_up_complete(struct mucse *mucse); +#endif diff --git a/drivers/net/ethernet/mucse/rnpgbe/rnpgbe_main.c b/drivers/net/ethernet/mucse/rnpgbe/rnpgbe_main.c index 316f941629d4..343c53d872a5 100644 --- a/drivers/net/ethernet/mucse/rnpgbe/rnpgbe_main.c +++ b/drivers/net/ethernet/mucse/rnpgbe/rnpgbe_main.c @@ -7,6 +7,7 @@ #include "rnpgbe.h" #include "rnpgbe_hw.h" +#include "rnpgbe_lib.h" #include "rnpgbe_mbx_fw.h" static const char rnpgbe_driver_name[] = "rnpgbe"; @@ -36,7 +37,24 @@ static struct pci_device_id rnpgbe_pci_tbl[] = { **/ static int rnpgbe_open(struct net_device *netdev) { + struct mucse *mucse = netdev_priv(netdev); + int err; + + err = rnpgbe_request_irq(mucse); + if (err) + return err; + + err = netif_set_real_num_queues(netdev, mucse->num_tx_queues, + mucse->num_rx_queues); + if (err) + goto err_free_irqs; + + rnpgbe_up_complete(mucse); + return 0; +err_free_irqs: + rnpgbe_free_irq(mucse); + return err; } /** @@ -50,6 +68,11 @@ static int rnpgbe_open(struct net_device *netdev) **/ static int rnpgbe_close(struct net_device *netdev) { + struct mucse *mucse = netdev_priv(netdev); + + rnpgbe_down(mucse); + rnpgbe_free_irq(mucse); + return 0; } @@ -166,11 +189,27 @@ static int rnpgbe_add_adapter(struct pci_dev *pdev, goto err_powerdown; } + err = rnpgbe_init_interrupt_scheme(mucse); + if (err) { + dev_err(&pdev->dev, "init interrupt failed %d\n", err); + goto err_powerdown; + } + + err = register_mbx_irq(mucse); + if (err) { + dev_err(&pdev->dev, "register mbx irq failed %d\n", err); + goto err_clear_interrupt; + } + err = register_netdev(netdev); if (err) - goto err_powerdown; + goto err_free_mbx_irq; return 0; +err_free_mbx_irq: + remove_mbx_irq(mucse); +err_clear_interrupt: + rnpgbe_clear_interrupt_scheme(mucse); err_powerdown: /* notify powerdown only powerup ok */ if (!err_notify) { @@ -256,6 +295,8 @@ static void rnpgbe_rm_adapter(struct pci_dev *pdev) err = rnpgbe_send_notify(hw, false, mucse_fw_powerup); if (err) dev_warn(&pdev->dev, "Send powerdown to hw failed %d\n", err); + remove_mbx_irq(mucse); + rnpgbe_clear_interrupt_scheme(mucse); free_netdev(netdev); } -- 2.25.1