From nobody Sat Jun 13 17:32:58 2026 Received: from rtits2.realtek.com.tw (rtits2.realtek.com [211.75.126.72]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id D8B0F2877DE; Wed, 6 May 2026 08:14:03 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=211.75.126.72 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1778055248; cv=none; b=h7k5n+NN6+iEsH+5D9mp2GFte3tCjFOSZ0F4Jfd2rH1ilAcuTNRx6XMw90Ewb65t5fipJH0BJTHQf0xRDTb12btaWEvAbpKvRMK7wnLHtOLUMqCqVtm7iDj+tWH0gLxj2mwprgdb4dai0mK/MdWoMEl6tFUHMnAcymxmBlPo48o= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1778055248; c=relaxed/simple; bh=KEb3FPVk8BLNCPa5PqGguLGMph3Qs9sC9Wq1o5IqywA=; h=From:To:CC:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=GVaWO35fKRBxrpRHijn4OFuQyK3HoIiRnsrqmZpQd8KPLN9/21kp+ZegrvkKHhSf5q8RDAdc7yz1VOstXZDE2WywbEzKh6OtfcZVratevqbQ02q5SoAlm6rQYPClGLc37HE9Aq/eo+NHvJqq0S1sHpbRWdbg5Ap0rlApeG0nKvU= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=realsil.com.cn; spf=pass smtp.mailfrom=realsil.com.cn; dkim=pass (2048-bit key) header.d=realsil.com.cn header.i=@realsil.com.cn header.b=GCeozlBC; arc=none smtp.client-ip=211.75.126.72 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=realsil.com.cn Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=realsil.com.cn Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=realsil.com.cn header.i=@realsil.com.cn header.b="GCeozlBC" X-SpamFilter-By: ArmorX SpamTrap 5.80 with qID 6468DTnrC1854043, This message is accepted by code: ctloc85258 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=realsil.com.cn; s=dkim; t=1778055209; bh=0F5YCSCpT8G2vNPIwaUaFholV0GpsBwt1vH+cMIshmM=; h=From:To:CC:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Transfer-Encoding:Content-Type; b=GCeozlBCoYFR0Y01NN4dFfFGZcWeP6ulU9kO0cwNotOLN0yXPkYF4HFpV8/hlfTBS 38pCRDkir3FnbiSZoJd8DR4zhDaMKMtY1HQdyzz0HD7B1Lf5yPkoE0hKUmXr8+EJh1 RAOW50w51DfF+XTWzvrgTV7dPs5xLXtkBYUhfywaC9UaV98K4uebj5JBmlhTLZQmdN sKLRHm+4rcziprZWoqSs4zkbs0qgDI7+LGTWibLY4V2/FxsFSB+8XLZjSfz3t7fZwo eNpoXYOFElJfi5LAVuc+JYgJfHc8gmWLjE1ybwbn1n1AhhgiD0zThuUzhZSDwaUhuz nCqMnPj5IgZ1w== Received: from RS-EX-MBS2.realsil.com.cn ([172.29.17.102]) by rtits2.realtek.com.tw (8.15.2/3.27/5.94) with ESMTPS id 6468DTnrC1854043 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=FAIL); Wed, 6 May 2026 16:13:29 +0800 Received: from RS-EX-MBS2.realsil.com.cn (172.29.17.102) by RS-EX-MBS2.realsil.com.cn (172.29.17.102) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.2.2562.17; Wed, 6 May 2026 16:13:28 +0800 Received: from 172.29.37.154 (172.29.37.152) by RS-EX-MBS2.realsil.com.cn (172.29.17.102) with Microsoft SMTP Server id 15.2.2562.17 via Frontend Transport; Wed, 6 May 2026 16:13:28 +0800 From: javen To: , , , , , , , CC: , , Javen Xu Subject: [Patch net-next v1 1/7] r8169: add support for multi irqs Date: Wed, 6 May 2026 16:13:19 +0800 Message-ID: <20260506081326.767-2-javen_xu@realsil.com.cn> X-Mailer: git-send-email 2.50.1.windows.1 In-Reply-To: <20260506081326.767-1-javen_xu@realsil.com.cn> References: <20260506081326.767-1-javen_xu@realsil.com.cn> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" From: Javen Xu RSS uses multi rx queues to receive packets, and each rx queue needs one irq and napi. So this patch adds support for multi irqs and napi here. Signed-off-by: Javen Xu --- drivers/net/ethernet/realtek/r8169_main.c | 199 ++++++++++++++++++++-- 1 file changed, 184 insertions(+), 15 deletions(-) diff --git a/drivers/net/ethernet/realtek/r8169_main.c b/drivers/net/ethern= et/realtek/r8169_main.c index 791277e750ba..ef74ee02c117 100644 --- a/drivers/net/ethernet/realtek/r8169_main.c +++ b/drivers/net/ethernet/realtek/r8169_main.c @@ -77,6 +77,7 @@ #define R8169_RX_RING_BYTES (NUM_RX_DESC * sizeof(struct RxDesc)) #define R8169_TX_STOP_THRS (MAX_SKB_FRAGS + 1) #define R8169_TX_START_THRS (2 * R8169_TX_STOP_THRS) +#define R8169_MAX_MSIX_VEC 32 =20 #define OCP_STD_PHY_BASE 0xa400 =20 @@ -435,6 +436,8 @@ enum rtl8125_registers { #define INT_CFG0_CLKREQEN BIT(3) IntrMask_8125 =3D 0x38, IntrStatus_8125 =3D 0x3c, + INTR_VEC_MAP_MASK =3D 0x800, + INTR_VEC_MAP_STATUS =3D 0x802, INT_CFG1_8125 =3D 0x7a, LEDSEL2 =3D 0x84, LEDSEL1 =3D 0x86, @@ -728,6 +731,19 @@ enum rtl_dash_type { RTL_DASH_25_BP, }; =20 +struct rtl8169_napi { + struct napi_struct napi; + void *priv; + int index; +}; + +struct rtl8169_irq { + irq_handler_t handler; + unsigned int vector; + u8 requested; + char name[IFNAMSIZ + 10]; +}; + struct rtl8169_private { void __iomem *mmio_addr; /* memory map physical address */ struct pci_dev *pci_dev; @@ -745,9 +761,19 @@ struct rtl8169_private { dma_addr_t RxPhyAddr; struct page *Rx_databuff[NUM_RX_DESC]; /* Rx data buffers */ struct ring_info tx_skb[NUM_TX_DESC]; /* Tx data buffers */ + struct rtl8169_irq irq_tbl[R8169_MAX_MSIX_VEC]; + struct rtl8169_napi r8169napi[R8169_MAX_MSIX_VEC]; + u16 isr_reg[R8169_MAX_MSIX_VEC]; + u16 imr_reg[R8169_MAX_MSIX_VEC]; + unsigned int num_rx_rings; u16 cp_cmd; u16 tx_lpi_timer; u32 irq_mask; + u8 min_irq_nvecs; + u8 max_irq_nvecs; + u8 hw_supp_isr_ver; + u8 hw_curr_isr_ver; + u8 irq_nvecs; int irq; struct clk *clk; =20 @@ -763,6 +789,8 @@ struct rtl8169_private { unsigned aspm_manageable:1; unsigned dash_enabled:1; bool sfp_mode:1; + bool rss_support:1; + bool rss_enable:1; dma_addr_t counters_phys_addr; struct rtl8169_counters *counters; struct rtl8169_tc_offsets tc_offset; @@ -2680,6 +2708,44 @@ static void rtl_hw_reset(struct rtl8169_private *tp) rtl_loop_wait_low(tp, &rtl_chipcmd_cond, 100, 100); } =20 +static void rtl_setup_mqs_reg(struct rtl8169_private *tp) +{ + if (tp->mac_version <=3D RTL_GIGA_MAC_VER_52) { + tp->isr_reg[0] =3D IntrStatus; + tp->imr_reg[0] =3D IntrMask; + } else { + tp->isr_reg[0] =3D IntrStatus_8125; + tp->imr_reg[0] =3D IntrMask_8125; + } + + for (int i =3D 1; i < tp->max_irq_nvecs; i++) + tp->isr_reg[i] =3D (u16)(INTR_VEC_MAP_STATUS + (i - 1) * 4); + + for (int i =3D 1; i < tp->max_irq_nvecs; i++) + tp->imr_reg[i] =3D (u16)(INTR_VEC_MAP_MASK + (i - 1) * 4); +} + +static void rtl_software_parameter_initialize(struct rtl8169_private *tp) +{ + tp->num_rx_rings =3D 1; + + switch (tp->mac_version) { + case RTL_GIGA_MAC_VER_80: + tp->min_irq_nvecs =3D 1; + tp->max_irq_nvecs =3D 1; + tp->hw_supp_isr_ver =3D 6; + break; + default: + tp->min_irq_nvecs =3D 1; + tp->max_irq_nvecs =3D 1; + tp->hw_supp_isr_ver =3D 1; + break; + } + tp->hw_curr_isr_ver =3D tp->hw_supp_isr_ver; + + rtl_setup_mqs_reg(tp); +} + static void rtl_request_firmware(struct rtl8169_private *tp) { struct rtl_fw *rtl_fw; @@ -4266,9 +4332,21 @@ static void rtl8169_tx_clear(struct rtl8169_private = *tp) netdev_reset_queue(tp->dev); } =20 +static void rtl8169_napi_disable(struct rtl8169_private *tp) +{ + for (int i =3D 0; i < tp->irq_nvecs; i++) + napi_disable(&tp->r8169napi[i].napi); +} + +static void rtl8169_napi_enable(struct rtl8169_private *tp) +{ + for (int i =3D 0; i < tp->irq_nvecs; i++) + napi_enable(&tp->r8169napi[i].napi); +} + static void rtl8169_cleanup(struct rtl8169_private *tp) { - napi_disable(&tp->napi); + rtl8169_napi_disable(tp); =20 /* Give a racing hard_start_xmit a few cycles to complete. */ synchronize_net(); @@ -4313,8 +4391,8 @@ static void rtl_reset_work(struct rtl8169_private *tp) =20 for (i =3D 0; i < NUM_RX_DESC; i++) rtl8169_mark_to_asic(tp->RxDescArray + i); + rtl8169_napi_enable(tp); =20 - napi_enable(&tp->napi); rtl_hw_start(tp); } =20 @@ -4820,7 +4898,7 @@ static int rtl_rx(struct net_device *dev, struct rtl8= 169_private *tp, int budget goto release_descriptor; } =20 - skb =3D napi_alloc_skb(&tp->napi, pkt_size); + skb =3D napi_alloc_skb(&tp->r8169napi[0].napi, pkt_size); if (unlikely(!skb)) { dev->stats.rx_dropped++; goto release_descriptor; @@ -4844,7 +4922,7 @@ static int rtl_rx(struct net_device *dev, struct rtl8= 169_private *tp, int budget if (skb->pkt_type =3D=3D PACKET_MULTICAST) dev->stats.multicast++; =20 - napi_gro_receive(&tp->napi, skb); + napi_gro_receive(&tp->r8169napi[0].napi, skb); =20 dev_sw_netstats_rx_add(dev, pkt_size); release_descriptor: @@ -4856,7 +4934,8 @@ static int rtl_rx(struct net_device *dev, struct rtl8= 169_private *tp, int budget =20 static irqreturn_t rtl8169_interrupt(int irq, void *dev_instance) { - struct rtl8169_private *tp =3D dev_instance; + struct rtl8169_napi *napi =3D dev_instance; + struct rtl8169_private *tp =3D napi->priv; u32 status =3D rtl_get_events(tp); =20 if ((status & 0xffff) =3D=3D 0xffff || !(status & tp->irq_mask)) @@ -4873,13 +4952,53 @@ static irqreturn_t rtl8169_interrupt(int irq, void = *dev_instance) phy_mac_interrupt(tp->phydev); =20 rtl_irq_disable(tp); - napi_schedule(&tp->napi); + napi_schedule(&napi->napi); out: rtl_ack_events(tp, status); =20 return IRQ_HANDLED; } =20 +static void rtl8169_free_irq(struct rtl8169_private *tp) +{ + for (int i =3D 0; i < tp->irq_nvecs; i++) { + struct rtl8169_irq *irq =3D &tp->irq_tbl[i]; + struct rtl8169_napi *napi =3D &tp->r8169napi[i]; + + if (irq->requested) { + irq->requested =3D 0; + pci_free_irq(tp->pci_dev, i, napi); + } + } +} + +static int rtl8169_request_irq(struct rtl8169_private *tp) +{ + const int len =3D sizeof(tp->irq_tbl[0].name); + struct net_device *dev =3D tp->dev; + struct rtl8169_napi *napi; + struct rtl8169_irq *irq; + int rc =3D 0; + + for (int i =3D 0; i < tp->irq_nvecs; i++) { + irq =3D &tp->irq_tbl[i]; + + napi =3D &tp->r8169napi[i]; + snprintf(irq->name, len, "%s-%d", dev->name, i); + irq->handler =3D rtl8169_interrupt; + rc =3D pci_request_irq(tp->pci_dev, i, irq->handler, NULL, napi, irq->na= me); + if (rc) + break; + + irq->vector =3D pci_irq_vector(tp->pci_dev, i); + irq->requested =3D 1; + } + + if (rc) + rtl8169_free_irq(tp); + return rc; +} + static void rtl_task(struct work_struct *work) { struct rtl8169_private *tp =3D @@ -4914,9 +5033,10 @@ static void rtl_task(struct work_struct *work) =20 static int rtl8169_poll(struct napi_struct *napi, int budget) { - struct rtl8169_private *tp =3D container_of(napi, struct rtl8169_private,= napi); + struct rtl8169_napi *r8169_napi =3D container_of(napi, struct rtl8169_nap= i, napi); + struct rtl8169_private *tp =3D r8169_napi->priv; struct net_device *dev =3D tp->dev; - int work_done; + int work_done =3D 0; =20 rtl_tx(dev, tp, budget); =20 @@ -5035,7 +5155,7 @@ static void rtl8169_up(struct rtl8169_private *tp) phy_init_hw(tp->phydev); phy_resume(tp->phydev); rtl8169_init_phy(tp); - napi_enable(&tp->napi); + rtl8169_napi_enable(tp); enable_work(&tp->wk.work); rtl_reset_work(tp); =20 @@ -5053,7 +5173,7 @@ static int rtl8169_close(struct net_device *dev) rtl8169_down(tp); rtl8169_rx_clear(tp); =20 - free_irq(tp->irq, tp); + rtl8169_free_irq(tp); =20 phy_disconnect(tp->phydev); =20 @@ -5108,7 +5228,8 @@ static int rtl_open(struct net_device *dev) rtl_request_firmware(tp); =20 irqflags =3D pci_dev_msi_enabled(pdev) ? IRQF_NO_THREAD : IRQF_SHARED; - retval =3D request_irq(tp->irq, rtl8169_interrupt, irqflags, dev->name, t= p); + + retval =3D rtl8169_request_irq(tp); if (retval < 0) goto err_release_fw_2; =20 @@ -5125,7 +5246,7 @@ static int rtl_open(struct net_device *dev) return retval; =20 err_free_irq: - free_irq(tp->irq, tp); + rtl8169_free_irq(tp); err_release_fw_2: rtl_release_firmware(tp); rtl8169_rx_clear(tp); @@ -5328,7 +5449,9 @@ static void rtl_set_irq_mask(struct rtl8169_private *= tp) =20 static int rtl_alloc_irq(struct rtl8169_private *tp) { + struct pci_dev *pdev =3D tp->pci_dev; unsigned int flags; + int nvecs; =20 switch (tp->mac_version) { case RTL_GIGA_MAC_VER_02 ... RTL_GIGA_MAC_VER_06: @@ -5344,7 +5467,18 @@ static int rtl_alloc_irq(struct rtl8169_private *tp) break; } =20 - return pci_alloc_irq_vectors(tp->pci_dev, 1, 1, flags); + nvecs =3D pci_alloc_irq_vectors(pdev, tp->min_irq_nvecs, tp->max_irq_nvec= s, flags); + + if (nvecs < 0) + nvecs =3D pci_alloc_irq_vectors(pdev, 1, 1, PCI_IRQ_ALL_TYPES); + + if (nvecs < 0) + return nvecs; + + tp->irq =3D pci_irq_vector(pdev, 0); + tp->irq_nvecs =3D nvecs; + + return 0; } =20 static void rtl_read_mac_address(struct rtl8169_private *tp, @@ -5539,6 +5673,17 @@ static void rtl_hw_initialize(struct rtl8169_private= *tp) } } =20 +static int rtl8169_set_real_num_queue(struct rtl8169_private *tp) +{ + int retval; + + retval =3D netif_set_real_num_tx_queues(tp->dev, 1); + if (retval < 0) + return retval; + + return netif_set_real_num_rx_queues(tp->dev, tp->num_rx_rings); +} + static int rtl_jumbo_max(struct rtl8169_private *tp) { /* Non-GBit versions don't support jumbo frames */ @@ -5599,6 +5744,19 @@ static bool rtl_aspm_is_safe(struct rtl8169_private = *tp) return false; } =20 +static void r8169_init_napi(struct rtl8169_private *tp) +{ + for (int i =3D 0; i < tp->irq_nvecs; i++) { + struct rtl8169_napi *r8169napi =3D &tp->r8169napi[i]; + int (*poll)(struct napi_struct *napi, int budget); + + poll =3D rtl8169_poll; + netif_napi_add(tp->dev, &r8169napi->napi, poll); + r8169napi->priv =3D tp; + r8169napi->index =3D i; + } +} + static int rtl_init_one(struct pci_dev *pdev, const struct pci_device_id *= ent) { const struct rtl_chip_info *chip; @@ -5703,11 +5861,12 @@ static int rtl_init_one(struct pci_dev *pdev, const= struct pci_device_id *ent) =20 rtl_hw_reset(tp); =20 + rtl_software_parameter_initialize(tp); + rc =3D rtl_alloc_irq(tp); if (rc < 0) return dev_err_probe(&pdev->dev, rc, "Can't allocate interrupt\n"); =20 - tp->irq =3D pci_irq_vector(pdev, 0); =20 INIT_WORK(&tp->wk.work, rtl_task); disable_work(&tp->wk.work); @@ -5716,7 +5875,13 @@ static int rtl_init_one(struct pci_dev *pdev, const = struct pci_device_id *ent) =20 dev->ethtool_ops =3D &rtl8169_ethtool_ops; =20 - netif_napi_add(dev, &tp->napi, rtl8169_poll); + if (!tp->rss_support) { + netif_napi_add(dev, &tp->r8169napi[0].napi, rtl8169_poll); + tp->r8169napi[0].priv =3D tp; + tp->r8169napi[0].index =3D 0; + } else { + r8169_init_napi(tp); + } =20 dev->hw_features =3D NETIF_F_IP_CSUM | NETIF_F_RXCSUM | NETIF_F_HW_VLAN_CTAG_TX | NETIF_F_HW_VLAN_CTAG_RX; @@ -5778,6 +5943,10 @@ static int rtl_init_one(struct pci_dev *pdev, const = struct pci_device_id *ent) if (jumbo_max) dev->max_mtu =3D jumbo_max; =20 + rc =3D rtl8169_set_real_num_queue(tp); + if (rc < 0) + return dev_err_probe(&pdev->dev, rc, "set tx/rx num failure\n"); + rtl_set_irq_mask(tp); =20 tp->counters =3D dmam_alloc_coherent (&pdev->dev, sizeof(*tp->counters), --=20 2.43.0 From nobody Sat Jun 13 17:32:58 2026 Received: from rtits2.realtek.com.tw (rtits2.realtek.com [211.75.126.72]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id D8BA33E123A; Wed, 6 May 2026 08:14:03 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=211.75.126.72 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1778055249; cv=none; b=BbK2K1VxbHs5PhKjMOFo0pes5DOKBYNMKyPEkRNIkXrP7vdzoBeE7Keux5/dfeEKYRwNBb6IeZT878cHO8zwHADfjCbzYKnFcXyy0cWhh/XLVZPDEIsIgx2Qc4f4iigwTeUVyIKSruuCO+Mt5ZtX2kS0RHhfYueiuCZ5HW9jYQI= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1778055249; c=relaxed/simple; bh=kHPKdduqxf6Q5JsPLrY+FhxD3xEgvrCiQ67Hyxevmlk=; h=From:To:CC:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=dyN1gNzrzc+wzoxJgREjlijT9miAjTHdxG65HWdhLT9Otv6WEgyqHrlX9qcuMCXw+Za22jfikzVXmdja9mt7qjQTjYIUlMDXVqgZ8/8ynrWvs6P/iMGBQG6CT7Yn7w3SBl1fW+l23zGQdp2u+IWE+c/hpIJudWGPrvPDL5qHVd4= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=realsil.com.cn; spf=pass smtp.mailfrom=realsil.com.cn; dkim=pass (2048-bit key) header.d=realsil.com.cn header.i=@realsil.com.cn header.b=EDqd3tJ5; arc=none smtp.client-ip=211.75.126.72 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=realsil.com.cn Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=realsil.com.cn Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=realsil.com.cn header.i=@realsil.com.cn header.b="EDqd3tJ5" X-SpamFilter-By: ArmorX SpamTrap 5.80 with qID 6468DTnsC1854043, This message is accepted by code: ctloc85258 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=realsil.com.cn; s=dkim; t=1778055210; bh=//M5V8hMfKpit/JPmk2oHYg6ZclHr0AUDLEcKiwc5Ao=; h=From:To:CC:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Transfer-Encoding:Content-Type; b=EDqd3tJ5Uq8KZ+z9c85BU/9zjsfdPErhTf+BaaUBuv97DE0R9ZzvwFFb0sJ4R+DME musvum1C79o1eHQWBjyne2Sp7QqTAM+uyvdZ2eFIaTB+QmW8Au2MfZ7ZNLROCRN3UI 3SCe0xPtqAGhds34RxO5GDpwlmi/OLnI2J3sp9CIj6x5KiMPkSoAoPWjp0Ik4cnPuC F9ew3zHsd/IU569eZXkvIVe3Jw6M9yz4I7DxrEvjtIFiztFgohlbEkGGLFtXAyrUYY zJpNV8xr6CiJSAQTg33gkrS7niF5cTWrW1MsZHcc3KeHJcYjxgdkjlZ33ryyq+Gkkl mEs6uNZXD0xUQ== Received: from RS-EX-MBS2.realsil.com.cn ([172.29.17.102]) by rtits2.realtek.com.tw (8.15.2/3.27/5.94) with ESMTPS id 6468DTnsC1854043 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=FAIL); Wed, 6 May 2026 16:13:29 +0800 Received: from RS-EX-MBS2.realsil.com.cn (172.29.17.102) by RS-EX-MBS2.realsil.com.cn (172.29.17.102) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.2.2562.17; Wed, 6 May 2026 16:13:29 +0800 Received: from 172.29.37.154 (172.29.37.152) by RS-EX-MBS2.realsil.com.cn (172.29.17.102) with Microsoft SMTP Server id 15.2.2562.17 via Frontend Transport; Wed, 6 May 2026 16:13:29 +0800 From: javen To: , , , , , , , CC: , , Javen Xu Subject: [Patch net-next v1 2/7] r8169: add support for multi rx queues Date: Wed, 6 May 2026 16:13:20 +0800 Message-ID: <20260506081326.767-3-javen_xu@realsil.com.cn> X-Mailer: git-send-email 2.50.1.windows.1 In-Reply-To: <20260506081326.767-1-javen_xu@realsil.com.cn> References: <20260506081326.767-1-javen_xu@realsil.com.cn> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" From: Javen Xu This patch adds support for multi rx queues. RSS requires multi rx queues to receive packets. So we need struct rtl8169_rx_ring for each queue. Signed-off-by: Javen Xu --- drivers/net/ethernet/realtek/r8169_main.c | 318 +++++++++++++++++----- 1 file changed, 251 insertions(+), 67 deletions(-) diff --git a/drivers/net/ethernet/realtek/r8169_main.c b/drivers/net/ethern= et/realtek/r8169_main.c index ef74ee02c117..bc75dbb9901d 100644 --- a/drivers/net/ethernet/realtek/r8169_main.c +++ b/drivers/net/ethernet/realtek/r8169_main.c @@ -74,10 +74,11 @@ #define NUM_TX_DESC 256 /* Number of Tx descriptor registers */ #define NUM_RX_DESC 256 /* Number of Rx descriptor registers */ #define R8169_TX_RING_BYTES (NUM_TX_DESC * sizeof(struct TxDesc)) -#define R8169_RX_RING_BYTES (NUM_RX_DESC * sizeof(struct RxDesc)) #define R8169_TX_STOP_THRS (MAX_SKB_FRAGS + 1) #define R8169_TX_START_THRS (2 * R8169_TX_STOP_THRS) +#define R8169_MAX_RX_QUEUES 8 #define R8169_MAX_MSIX_VEC 32 +#define R8127_MAX_RX_QUEUES 8 =20 #define OCP_STD_PHY_BASE 0xa400 =20 @@ -447,6 +448,7 @@ enum rtl8125_registers { RSS_CTRL_8125 =3D 0x4500, Q_NUM_CTRL_8125 =3D 0x4800, EEE_TXIDLE_TIMER_8125 =3D 0x6048, + RDSAR_Q1_LOW =3D 0x4000, }; =20 #define LEDSEL_MASK_8125 0x23f @@ -731,6 +733,19 @@ enum rtl_dash_type { RTL_DASH_25_BP, }; =20 +struct rtl8169_rx_ring { + u32 index; /* Rx queue index */ + u32 cur_rx; /* Index of next Rx pkt. */ + u32 dirty_rx; /* Index for recycling. */ + u32 num_rx_desc; /* num of Rx desc */ + struct RxDesc *rx_desc_array; /* array of Rx Desc*/ + u32 rx_desc_alloc_size; /* memory size per descs of ring */ + dma_addr_t rx_desc_phy_addr[NUM_RX_DESC]; /* Rx data buffer physical dma = address */ + dma_addr_t rx_phy_addr; /* Rx desc physical address */ + struct page *rx_databuff[NUM_RX_DESC]; /* Rx data buffers */ + u16 rdsar_reg; /* Receive Descriptor Start Address */ +}; + struct rtl8169_napi { struct napi_struct napi; void *priv; @@ -744,6 +759,13 @@ struct rtl8169_irq { char name[IFNAMSIZ + 10]; }; =20 +enum rx_desc_ring_type { + RX_DESC_RING_TYPE_UNKNOWN =3D 0, + RX_DESC_RING_TYPE_DEFAULT, + RX_DESC_RING_TYPE_RSS, + RX_DESC_RING_TYPE_MAX +}; + struct rtl8169_private { void __iomem *mmio_addr; /* memory map physical address */ struct pci_dev *pci_dev; @@ -752,28 +774,28 @@ struct rtl8169_private { struct napi_struct napi; enum mac_version mac_version; enum rtl_dash_type dash_type; - u32 cur_rx; /* Index into the Rx descriptor buffer of next Rx pkt. */ u32 cur_tx; /* Index into the Tx descriptor buffer of next Rx pkt. */ u32 dirty_tx; struct TxDesc *TxDescArray; /* 256-aligned Tx descriptor ring */ - struct RxDesc *RxDescArray; /* 256-aligned Rx descriptor ring */ dma_addr_t TxPhyAddr; - dma_addr_t RxPhyAddr; - struct page *Rx_databuff[NUM_RX_DESC]; /* Rx data buffers */ struct ring_info tx_skb[NUM_TX_DESC]; /* Tx data buffers */ struct rtl8169_irq irq_tbl[R8169_MAX_MSIX_VEC]; struct rtl8169_napi r8169napi[R8169_MAX_MSIX_VEC]; + struct rtl8169_rx_ring rx_ring[R8169_MAX_RX_QUEUES]; u16 isr_reg[R8169_MAX_MSIX_VEC]; u16 imr_reg[R8169_MAX_MSIX_VEC]; unsigned int num_rx_rings; u16 cp_cmd; u16 tx_lpi_timer; u32 irq_mask; + u16 hw_supp_num_rx_queues; u8 min_irq_nvecs; u8 max_irq_nvecs; u8 hw_supp_isr_ver; u8 hw_curr_isr_ver; u8 irq_nvecs; + u8 init_rx_desc_type; + u8 recheck_desc_ownbit; int irq; struct clk *clk; =20 @@ -2647,9 +2669,27 @@ static void rtl_init_rxcfg(struct rtl8169_private *t= p) } } =20 +static void rtl8169_rx_desc_init(struct rtl8169_private *tp) +{ + for (int i =3D 0; i < tp->num_rx_rings; i++) { + struct rtl8169_rx_ring *ring =3D &tp->rx_ring[i]; + + memset(ring->rx_desc_array, 0x0, ring->rx_desc_alloc_size); + } +} + static void rtl8169_init_ring_indexes(struct rtl8169_private *tp) { - tp->dirty_tx =3D tp->cur_tx =3D tp->cur_rx =3D 0; + tp->dirty_tx =3D 0; + tp->cur_tx =3D 0; + + for (int i =3D 0; i < tp->hw_supp_num_rx_queues; i++) { + struct rtl8169_rx_ring *ring =3D &tp->rx_ring[i]; + + ring->dirty_rx =3D 0; + ring->cur_rx =3D 0; + ring->index =3D i; + } } =20 static void rtl_jumbo_config(struct rtl8169_private *tp) @@ -2708,8 +2748,18 @@ static void rtl_hw_reset(struct rtl8169_private *tp) rtl_loop_wait_low(tp, &rtl_chipcmd_cond, 100, 100); } =20 +static void rtl_set_ring_size(struct rtl8169_private *tp, u32 rx_num) +{ + for (int i =3D 0; i < tp->hw_supp_num_rx_queues; i++) + tp->rx_ring[i].num_rx_desc =3D rx_num; +} + static void rtl_setup_mqs_reg(struct rtl8169_private *tp) { + tp->rx_ring[0].rdsar_reg =3D RxDescAddrLow; + for (int i =3D 1; i < tp->hw_supp_num_rx_queues; i++) + tp->rx_ring[i].rdsar_reg =3D (u16)(RDSAR_Q1_LOW + (i - 1) * 8); + if (tp->mac_version <=3D RTL_GIGA_MAC_VER_52) { tp->isr_reg[0] =3D IntrStatus; tp->imr_reg[0] =3D IntrMask; @@ -2733,17 +2783,21 @@ static void rtl_software_parameter_initialize(struc= t rtl8169_private *tp) case RTL_GIGA_MAC_VER_80: tp->min_irq_nvecs =3D 1; tp->max_irq_nvecs =3D 1; + tp->hw_supp_num_rx_queues =3D R8127_MAX_RX_QUEUES; tp->hw_supp_isr_ver =3D 6; break; default: tp->min_irq_nvecs =3D 1; tp->max_irq_nvecs =3D 1; + tp->hw_supp_num_rx_queues =3D 1; tp->hw_supp_isr_ver =3D 1; break; } + tp->init_rx_desc_type =3D RX_DESC_RING_TYPE_DEFAULT; tp->hw_curr_isr_ver =3D tp->hw_supp_isr_ver; =20 rtl_setup_mqs_reg(tp); + rtl_set_ring_size(tp, NUM_RX_DESC); } =20 static void rtl_request_firmware(struct rtl8169_private *tp) @@ -2877,8 +2931,13 @@ static void rtl_set_rx_tx_desc_registers(struct rtl8= 169_private *tp) */ RTL_W32(tp, TxDescStartAddrHigh, ((u64) tp->TxPhyAddr) >> 32); RTL_W32(tp, TxDescStartAddrLow, ((u64) tp->TxPhyAddr) & DMA_BIT_MASK(32)); - RTL_W32(tp, RxDescAddrHigh, ((u64) tp->RxPhyAddr) >> 32); - RTL_W32(tp, RxDescAddrLow, ((u64) tp->RxPhyAddr) & DMA_BIT_MASK(32)); + + for (int i =3D 0; i < tp->num_rx_rings; i++) { + struct rtl8169_rx_ring *ring =3D &tp->rx_ring[i]; + + RTL_W32(tp, ring->rdsar_reg, ((u64)ring->rx_phy_addr) & DMA_BIT_MASK(32)= ); + RTL_W32(tp, ring->rdsar_reg + 4, ((u64)ring->rx_phy_addr >> 32)); + } } =20 static void rtl8169_set_magic_reg(struct rtl8169_private *tp) @@ -4214,7 +4273,7 @@ static int rtl8169_change_mtu(struct net_device *dev,= int new_mtu) return 0; } =20 -static void rtl8169_mark_to_asic(struct RxDesc *desc) +static void rtl8169_mark_to_asic_default(struct RxDesc *desc) { u32 eor =3D le32_to_cpu(desc->opts1) & RingEnd; =20 @@ -4224,13 +4283,19 @@ static void rtl8169_mark_to_asic(struct RxDesc *des= c) WRITE_ONCE(desc->opts1, cpu_to_le32(DescOwn | eor | R8169_RX_BUF_SIZE)); } =20 +static void rtl8169_mark_to_asic(struct rtl8169_private *tp, struct RxDesc= *desc) +{ + rtl8169_mark_to_asic_default(desc); +} + static struct page *rtl8169_alloc_rx_data(struct rtl8169_private *tp, - struct RxDesc *desc) + struct rtl8169_rx_ring *ring, unsigned int index) { struct device *d =3D tp_to_dev(tp); int node =3D dev_to_node(d); dma_addr_t mapping; struct page *data; + struct RxDesc *desc =3D ring->rx_desc_array + index; =20 data =3D alloc_pages_node(node, GFP_KERNEL, get_order(R8169_RX_BUF_SIZE)); if (!data) @@ -4244,55 +4309,111 @@ static struct page *rtl8169_alloc_rx_data(struct r= tl8169_private *tp, } =20 desc->addr =3D cpu_to_le64(mapping); - rtl8169_mark_to_asic(desc); + ring->rx_desc_phy_addr[index] =3D mapping; + rtl8169_mark_to_asic(tp, desc); =20 return data; } =20 -static void rtl8169_rx_clear(struct rtl8169_private *tp) +static void rtl8169_rx_clear(struct rtl8169_private *tp, struct rtl8169_rx= _ring *ring) { int i; =20 - for (i =3D 0; i < NUM_RX_DESC && tp->Rx_databuff[i]; i++) { + for (i =3D 0; i < NUM_RX_DESC && ring->rx_databuff[i]; i++) { dma_unmap_page(tp_to_dev(tp), - le64_to_cpu(tp->RxDescArray[i].addr), + ring->rx_desc_phy_addr[i], R8169_RX_BUF_SIZE, DMA_FROM_DEVICE); - __free_pages(tp->Rx_databuff[i], get_order(R8169_RX_BUF_SIZE)); - tp->Rx_databuff[i] =3D NULL; - tp->RxDescArray[i].addr =3D 0; - tp->RxDescArray[i].opts1 =3D 0; + __free_pages(ring->rx_databuff[i], get_order(R8169_RX_BUF_SIZE)); + ring->rx_databuff[i] =3D NULL; + ring->rx_desc_phy_addr[i] =3D 0; + ring->rx_desc_array[i].addr =3D 0; + ring->rx_desc_array[i].opts1 =3D 0; } } =20 -static int rtl8169_rx_fill(struct rtl8169_private *tp) +static void rtl8169_mark_as_last_descriptor_default(struct RxDesc *desc) +{ + desc->opts1 |=3D cpu_to_le32(RingEnd); +} + +static void rtl8169_mark_as_last_descriptor(struct rtl8169_private *tp, st= ruct RxDesc *desc) +{ + rtl8169_mark_as_last_descriptor_default(desc); +} + +static int rtl8169_rx_fill(struct rtl8169_private *tp, struct rtl8169_rx_r= ing *ring) { int i; =20 for (i =3D 0; i < NUM_RX_DESC; i++) { struct page *data; =20 - data =3D rtl8169_alloc_rx_data(tp, tp->RxDescArray + i); + data =3D rtl8169_alloc_rx_data(tp, ring, i); if (!data) { - rtl8169_rx_clear(tp); + rtl8169_rx_clear(tp, ring); return -ENOMEM; } - tp->Rx_databuff[i] =3D data; + ring->rx_databuff[i] =3D data; } =20 /* mark as last descriptor in the ring */ - tp->RxDescArray[NUM_RX_DESC - 1].opts1 |=3D cpu_to_le32(RingEnd); + rtl8169_mark_as_last_descriptor(tp, &ring->rx_desc_array[NUM_RX_DESC - 1]= ); + + return 0; +} + +static int rtl8169_alloc_rx_desc(struct rtl8169_private *tp) +{ + struct rtl8169_rx_ring *ring; + struct pci_dev *pdev =3D tp->pci_dev; =20 + for (int i =3D 0; i < tp->num_rx_rings; i++) { + ring =3D &tp->rx_ring[i]; + ring->rx_desc_alloc_size =3D (ring->num_rx_desc + 1) * sizeof(struct RxD= esc); + ring->rx_desc_array =3D dma_alloc_coherent(&pdev->dev, + ring->rx_desc_alloc_size, + &ring->rx_phy_addr, + GFP_KERNEL); + if (!ring->rx_desc_array) + return -1; + } return 0; } =20 +static void rtl8169_free_rx_desc(struct rtl8169_private *tp) +{ + struct rtl8169_rx_ring *ring; + struct pci_dev *pdev =3D tp->pci_dev; + + for (int i =3D 0; i < tp->num_rx_rings; i++) { + ring =3D &tp->rx_ring[i]; + if (ring->rx_desc_array) { + dma_free_coherent(&pdev->dev, + ring->rx_desc_alloc_size, + ring->rx_desc_array, + ring->rx_phy_addr); + ring->rx_desc_array =3D NULL; + } + } +} + static int rtl8169_init_ring(struct rtl8169_private *tp) { + int retval =3D 0; + rtl8169_init_ring_indexes(tp); + rtl8169_rx_desc_init(tp); =20 memset(tp->tx_skb, 0, sizeof(tp->tx_skb)); - memset(tp->Rx_databuff, 0, sizeof(tp->Rx_databuff)); =20 - return rtl8169_rx_fill(tp); + for (int i =3D 0; i < tp->num_rx_rings; i++) { + struct rtl8169_rx_ring *ring =3D &tp->rx_ring[i]; + + memset(ring->rx_databuff, 0, sizeof(ring->rx_databuff)); + retval =3D rtl8169_rx_fill(tp, ring); + } + + return retval; } =20 static void rtl8169_unmap_tx_skb(struct rtl8169_private *tp, unsigned int = entry) @@ -4381,16 +4502,24 @@ static void rtl8169_cleanup(struct rtl8169_private = *tp) rtl8169_init_ring_indexes(tp); } =20 -static void rtl_reset_work(struct rtl8169_private *tp) +static void rtl8169_rx_desc_reset(struct rtl8169_private *tp) { - int i; + for (int i =3D 0; i < tp->num_rx_rings; i++) { + struct rtl8169_rx_ring *ring =3D &tp->rx_ring[i]; =20 + for (int j =3D 0; j < ring->num_rx_desc; j++) + rtl8169_mark_to_asic(tp, ring->rx_desc_array + j); + } +} + +static void rtl_reset_work(struct rtl8169_private *tp) +{ netif_stop_queue(tp->dev); =20 rtl8169_cleanup(tp); =20 - for (i =3D 0; i < NUM_RX_DESC; i++) - rtl8169_mark_to_asic(tp->RxDescArray + i); + rtl8169_rx_desc_reset(tp); + rtl8169_napi_enable(tp); =20 rtl_hw_start(tp); @@ -4784,6 +4913,11 @@ static void rtl8169_pcierr_interrupt(struct net_devi= ce *dev) rtl_schedule_task(tp, RTL_FLAG_TASK_RESET_PENDING); } =20 +static void rtl8169_desc_quirk(struct rtl8169_private *tp) +{ + RTL_R8(tp, tp->imr_reg[0]); +} + static void rtl_tx(struct net_device *dev, struct rtl8169_private *tp, int budget) { @@ -4836,9 +4970,11 @@ static inline int rtl8169_fragmented_frame(u32 statu= s) return (status & (FirstFrag | LastFrag)) !=3D (FirstFrag | LastFrag); } =20 -static inline void rtl8169_rx_csum(struct sk_buff *skb, u32 opts1) +static inline void rtl8169_rx_csum_default(struct rtl8169_private *tp, + struct sk_buff *skb, + struct RxDesc *desc) { - u32 status =3D opts1 & (RxProtoMask | RxCSFailMask); + u32 status =3D le32_to_cpu(desc->opts1) & (RxProtoMask | RxCSFailMask); =20 if (status =3D=3D RxProtoTCP || status =3D=3D RxProtoUDP) skb->ip_summed =3D CHECKSUM_UNNECESSARY; @@ -4846,22 +4982,71 @@ static inline void rtl8169_rx_csum(struct sk_buff *= skb, u32 opts1) skb_checksum_none_assert(skb); } =20 -static int rtl_rx(struct net_device *dev, struct rtl8169_private *tp, int = budget) +static inline void rtl8169_rx_csum(struct rtl8169_private *tp, + struct sk_buff *skb, + struct RxDesc *desc) +{ + rtl8169_rx_csum_default(tp, skb, desc); +} + +static u32 rtl8169_rx_desc_opts1(struct rtl8169_private *tp, struct RxDesc= *desc) +{ + return READ_ONCE(desc->opts1); +} + +static bool rtl8169_check_rx_desc_error(struct net_device *dev, + struct rtl8169_private *tp, + u32 status) +{ + if (unlikely(status & RxRES)) { + if (status & (RxRWT | RxRUNT)) + dev->stats.rx_length_errors++; + if (status & RxCRC) + dev->stats.rx_crc_errors++; + return true; + } + return false; +} + +static inline void rtl8169_set_desc_dma_addr(struct rtl8169_private *tp, + struct RxDesc *desc, + dma_addr_t mapping) +{ + desc->addr =3D cpu_to_le64(mapping); +} + +static int rtl_rx(struct net_device *dev, struct rtl8169_private *tp, + struct rtl8169_rx_ring *ring, int budget) { struct device *d =3D tp_to_dev(tp); int count; =20 - for (count =3D 0; count < budget; count++, tp->cur_rx++) { - unsigned int pkt_size, entry =3D tp->cur_rx % NUM_RX_DESC; - struct RxDesc *desc =3D tp->RxDescArray + entry; + for (count =3D 0; count < budget; count++, ring->cur_rx++) { + unsigned int pkt_size, entry =3D ring->cur_rx % ring->num_rx_desc; + struct RxDesc *desc =3D ring->rx_desc_array + entry; struct sk_buff *skb; const void *rx_buf; dma_addr_t addr; u32 status; =20 - status =3D le32_to_cpu(READ_ONCE(desc->opts1)); - if (status & DescOwn) - break; + status =3D le32_to_cpu(rtl8169_rx_desc_opts1(tp, desc)); + + if (status & DescOwn) { + if (!tp->recheck_desc_ownbit) + break; + + /* Workaround for a hardware issue: + * Hardware might trigger RX interrupt before the DMA + * engine fully updates RX desc ownbit in host memory. + * So we do a quirk and re-read to avoid missing RX + * packets. + */ + tp->recheck_desc_ownbit =3D false; + rtl8169_desc_quirk(tp); + status =3D le32_to_cpu(rtl8169_rx_desc_opts1(tp, desc)); + if (status & DescOwn) + break; + } =20 /* This barrier is needed to keep us from reading * any other fields out of the Rx descriptor until @@ -4869,20 +5054,15 @@ static int rtl_rx(struct net_device *dev, struct rt= l8169_private *tp, int budget */ dma_rmb(); =20 - if (unlikely(status & RxRES)) { + if (rtl8169_check_rx_desc_error(dev, tp, status)) { if (net_ratelimit()) netdev_warn(dev, "Rx ERROR. status =3D %08x\n", status); + dev->stats.rx_errors++; - if (status & (RxRWT | RxRUNT)) - dev->stats.rx_length_errors++; - if (status & RxCRC) - dev->stats.rx_crc_errors++; =20 if (!(dev->features & NETIF_F_RXALL)) goto release_descriptor; - else if (status & RxRWT || !(status & (RxRUNT | RxCRC))) - goto release_descriptor; } =20 pkt_size =3D status & GENMASK(13, 0); @@ -4898,14 +5078,14 @@ static int rtl_rx(struct net_device *dev, struct rt= l8169_private *tp, int budget goto release_descriptor; } =20 - skb =3D napi_alloc_skb(&tp->r8169napi[0].napi, pkt_size); + skb =3D napi_alloc_skb(&tp->r8169napi[ring->index].napi, pkt_size); if (unlikely(!skb)) { dev->stats.rx_dropped++; goto release_descriptor; } =20 - addr =3D le64_to_cpu(desc->addr); - rx_buf =3D page_address(tp->Rx_databuff[entry]); + addr =3D ring->rx_desc_phy_addr[entry]; + rx_buf =3D page_address(ring->rx_databuff[entry]); =20 dma_sync_single_for_cpu(d, addr, pkt_size, DMA_FROM_DEVICE); prefetch(rx_buf); @@ -4914,7 +5094,7 @@ static int rtl_rx(struct net_device *dev, struct rtl8= 169_private *tp, int budget skb->len =3D pkt_size; dma_sync_single_for_device(d, addr, pkt_size, DMA_FROM_DEVICE); =20 - rtl8169_rx_csum(skb, status); + rtl8169_rx_csum(tp, skb, desc); skb->protocol =3D eth_type_trans(skb, dev); =20 rtl8169_rx_vlan_tag(desc, skb); @@ -4922,11 +5102,12 @@ static int rtl_rx(struct net_device *dev, struct rt= l8169_private *tp, int budget if (skb->pkt_type =3D=3D PACKET_MULTICAST) dev->stats.multicast++; =20 - napi_gro_receive(&tp->r8169napi[0].napi, skb); + napi_gro_receive(&tp->r8169napi[ring->index].napi, skb); =20 dev_sw_netstats_rx_add(dev, pkt_size); release_descriptor: - rtl8169_mark_to_asic(desc); + rtl8169_set_desc_dma_addr(tp, desc, ring->rx_desc_phy_addr[entry]); + rtl8169_mark_to_asic(tp, desc); } =20 return count; @@ -4952,6 +5133,7 @@ static irqreturn_t rtl8169_interrupt(int irq, void *d= ev_instance) phy_mac_interrupt(tp->phydev); =20 rtl_irq_disable(tp); + tp->recheck_desc_ownbit =3D true; napi_schedule(&napi->napi); out: rtl_ack_events(tp, status); @@ -5040,7 +5222,8 @@ static int rtl8169_poll(struct napi_struct *napi, int= budget) =20 rtl_tx(dev, tp, budget); =20 - work_done =3D rtl_rx(dev, tp, budget); + for (int i =3D 0; i < tp->num_rx_rings; i++) + work_done +=3D rtl_rx(dev, tp, &tp->rx_ring[i], budget); =20 if (work_done < budget && napi_complete_done(napi, work_done)) rtl_irq_enable(tp); @@ -5168,21 +5351,21 @@ static int rtl8169_close(struct net_device *dev) struct pci_dev *pdev =3D tp->pci_dev; =20 pm_runtime_get_sync(&pdev->dev); - netif_stop_queue(dev); + rtl8169_down(tp); - rtl8169_rx_clear(tp); + for (int i =3D 0; i < tp->num_rx_rings; i++) + rtl8169_rx_clear(tp, &tp->rx_ring[i]); =20 rtl8169_free_irq(tp); =20 phy_disconnect(tp->phydev); =20 - dma_free_coherent(&pdev->dev, R8169_RX_RING_BYTES, tp->RxDescArray, - tp->RxPhyAddr); dma_free_coherent(&pdev->dev, R8169_TX_RING_BYTES, tp->TxDescArray, tp->TxPhyAddr); tp->TxDescArray =3D NULL; - tp->RxDescArray =3D NULL; + + rtl8169_free_rx_desc(tp); =20 pm_runtime_put_sync(&pdev->dev); =20 @@ -5211,16 +5394,15 @@ static int rtl_open(struct net_device *dev) * Rx and Tx descriptors needs 256 bytes alignment. * dma_alloc_coherent provides more. */ + tp->TxDescArray =3D dma_alloc_coherent(&pdev->dev, R8169_TX_RING_BYTES, &tp->TxPhyAddr, GFP_KERNEL); if (!tp->TxDescArray) - goto out; - - tp->RxDescArray =3D dma_alloc_coherent(&pdev->dev, R8169_RX_RING_BYTES, - &tp->RxPhyAddr, GFP_KERNEL); - if (!tp->RxDescArray) goto err_free_tx_0; =20 + if (rtl8169_alloc_rx_desc(tp) < 0) + goto err_free_rx_1; + retval =3D rtl8169_init_ring(tp); if (retval < 0) goto err_free_rx_1; @@ -5249,11 +5431,10 @@ static int rtl_open(struct net_device *dev) rtl8169_free_irq(tp); err_release_fw_2: rtl_release_firmware(tp); - rtl8169_rx_clear(tp); + for (int i =3D 0; i < tp->num_rx_rings; i++) + rtl8169_rx_clear(tp, &tp->rx_ring[i]); err_free_rx_1: - dma_free_coherent(&pdev->dev, R8169_RX_RING_BYTES, tp->RxDescArray, - tp->RxPhyAddr); - tp->RxDescArray =3D NULL; + rtl8169_free_rx_desc(tp); err_free_tx_0: dma_free_coherent(&pdev->dev, R8169_TX_RING_BYTES, tp->TxDescArray, tp->TxPhyAddr); @@ -5767,7 +5948,10 @@ static int rtl_init_one(struct pci_dev *pdev, const = struct pci_device_id *ent) u32 txconfig; u32 xid; =20 - dev =3D devm_alloc_etherdev(&pdev->dev, sizeof (*tp)); + dev =3D devm_alloc_etherdev_mqs(&pdev->dev, sizeof(*tp), + 1, + R8169_MAX_RX_QUEUES); + if (!dev) return -ENOMEM; =20 --=20 2.43.0 From nobody Sat Jun 13 17:32:58 2026 Received: from rtits2.realtek.com.tw (rtits2.realtek.com [211.75.126.72]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 0BC0B3E3151; Wed, 6 May 2026 08:14:03 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=211.75.126.72 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1778055247; cv=none; b=iJJ9OubZPNu8x0kve3AYk67CSLUBdcohMzTGkOFm3WP1KFlDmdoSiWNmqK52D5/eoYWqrk8ow6DYXbNcTD2SrVzwcO7Vmexm2yrL7JUKa0x5dY6MC8CASa/SpLOUD74sgoSRDTHhKLZQmEdUx4H5Z3ah/CBgJBJ4fNnatbM/Kho= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1778055247; c=relaxed/simple; bh=ymomAc0+lIrMy6WL0B7QPUjaKZstaEj2waHDJUFuPg4=; h=From:To:CC:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=HtaWxsIdFA45H8wvwciS6VViu4lIg5dhQWAIZeGXJAxRRZNsIWo3U/14LJxbI3OvKWpLY1wYrSnMDUw0nQ0ShPiFE++4SRUAybH53mRnsP6rsZ068rzZtecDnbP3S5Yy+gOMNxi62G4B8I+W8BC4Z4nTWGXrEPgq1MllF3NJmj0= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=realsil.com.cn; spf=pass smtp.mailfrom=realsil.com.cn; dkim=pass (2048-bit key) header.d=realsil.com.cn header.i=@realsil.com.cn header.b=adILIxfU; arc=none smtp.client-ip=211.75.126.72 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=realsil.com.cn Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=realsil.com.cn Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=realsil.com.cn header.i=@realsil.com.cn header.b="adILIxfU" X-SpamFilter-By: ArmorX SpamTrap 5.80 with qID 6468DUnqC1854043, This message is accepted by code: ctloc85258 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=realsil.com.cn; s=dkim; t=1778055210; bh=KvYW5SdMT4v8Koq00qERo5xMGdML7qHbkiyVwTWTok4=; h=From:To:CC:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Transfer-Encoding:Content-Type; b=adILIxfULtSGsomnhtMehviZr8lwPZfm92MUtg1LejeWkvAfVUxelZVNTKxhu7MfR LyyZkW4yjalKFPwIwCjTnF/U1kWncKlBxaLSj3coHTvh+7YclOuTQKG+TOq2tfGTdM Za6xDnToTy62A60HH49uduUjKIrmJoxyhuPFch4xyKR+LQbaz5F/KcyJ8jD/pgw77C aF9stNgzmpGlKqJDD6XbNMk82RiHEFyztWMl0YRo+aO+/us7uyE1AOt9ciTBBop4mZ DhKx4IDEDKK1TSWN71sAIuStumXCYOdF7quV8U/FlnnkOcEFeeIHDwMdvaErfgg8UJ n+Gfyj2HXfCqg== Received: from RS-EX-MBS2.realsil.com.cn ([172.29.17.102]) by rtits2.realtek.com.tw (8.15.2/3.27/5.94) with ESMTPS id 6468DUnqC1854043 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=FAIL); Wed, 6 May 2026 16:13:30 +0800 Received: from RS-EX-MBS2.realsil.com.cn (172.29.17.102) by RS-EX-MBS2.realsil.com.cn (172.29.17.102) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.2.2562.17; Wed, 6 May 2026 16:13:29 +0800 Received: from 172.29.37.154 (172.29.37.152) by RS-EX-MBS2.realsil.com.cn (172.29.17.102) with Microsoft SMTP Server id 15.2.2562.17 via Frontend Transport; Wed, 6 May 2026 16:13:29 +0800 From: javen To: , , , , , , , CC: , , Javen Xu Subject: [Patch net-next v1 3/7] r8169: add support for new interrupt mapping Date: Wed, 6 May 2026 16:13:21 +0800 Message-ID: <20260506081326.767-4-javen_xu@realsil.com.cn> X-Mailer: git-send-email 2.50.1.windows.1 In-Reply-To: <20260506081326.767-1-javen_xu@realsil.com.cn> References: <20260506081326.767-1-javen_xu@realsil.com.cn> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" From: Javen Xu To support RSS, the number of hardware interrupt bits should match the interrupt of software. So we add support for new interrupt mapping here. ISR_VER_MAP_REG is the hardware register to indicate interrupt status. IMR_SET_VEC_MAP_REG is interrupt mask which is set to enable irq. Signed-off-by: Javen Xu --- drivers/net/ethernet/realtek/r8169_main.c | 155 ++++++++++++++++++++-- 1 file changed, 145 insertions(+), 10 deletions(-) diff --git a/drivers/net/ethernet/realtek/r8169_main.c b/drivers/net/ethern= et/realtek/r8169_main.c index bc75dbb9901d..671f82c326d9 100644 --- a/drivers/net/ethernet/realtek/r8169_main.c +++ b/drivers/net/ethernet/realtek/r8169_main.c @@ -77,6 +77,7 @@ #define R8169_TX_STOP_THRS (MAX_SKB_FRAGS + 1) #define R8169_TX_START_THRS (2 * R8169_TX_STOP_THRS) #define R8169_MAX_RX_QUEUES 8 +#define R8127_MAX_TX_QUEUES 8 #define R8169_MAX_MSIX_VEC 32 #define R8127_MAX_RX_QUEUES 8 =20 @@ -449,8 +450,14 @@ enum rtl8125_registers { Q_NUM_CTRL_8125 =3D 0x4800, EEE_TXIDLE_TIMER_8125 =3D 0x6048, RDSAR_Q1_LOW =3D 0x4000, + IMR_SET_VEC_MAP_REG =3D 0x0d0c, + IMR_CLEAR_VEC_MAP_REG =3D 0x0d00, + ISR_VEC_MAP_REG =3D 0x0d04, }; =20 +#define MSIX_ID_VEC_MAP_LINKCHG 29 +#define RTL_VEC_MAP_ENABLE BIT(0) + #define LEDSEL_MASK_8125 0x23f =20 #define RX_VLAN_INNER_8125 BIT(22) @@ -581,6 +588,9 @@ enum rtl_register_content { =20 /* magic enable v2 */ MagicPacket_v2 =3D (1 << 16), /* Wake up when receives a Magic Packet */ +#define ISRIMR_LINKCHG BIT(29) +#define ISRIMR_TOK_Q0 BIT(8) +#define ISRIMR_ROK_Q0 BIT(0) }; =20 enum rtl_desc_bit { @@ -796,6 +806,7 @@ struct rtl8169_private { u8 irq_nvecs; u8 init_rx_desc_type; u8 recheck_desc_ownbit; + unsigned int features; int irq; struct clk *clk; =20 @@ -1694,26 +1705,36 @@ static u32 rtl_get_events(struct rtl8169_private *t= p) =20 static void rtl_ack_events(struct rtl8169_private *tp, u32 bits) { - if (rtl_is_8125(tp)) + if (rtl_is_8125(tp)) { RTL_W32(tp, IntrStatus_8125, bits); - else + if (tp->features & RTL_VEC_MAP_ENABLE) + RTL_W32(tp, ISR_VEC_MAP_REG, 0xffffffff); + } else { RTL_W16(tp, IntrStatus, bits); + } } =20 static void rtl_irq_disable(struct rtl8169_private *tp) { - if (rtl_is_8125(tp)) + if (rtl_is_8125(tp)) { RTL_W32(tp, IntrMask_8125, 0); - else + if (tp->features & RTL_VEC_MAP_ENABLE) + RTL_W32(tp, IMR_CLEAR_VEC_MAP_REG, 0xffffffff); + } else { RTL_W16(tp, IntrMask, 0); + } } =20 static void rtl_irq_enable(struct rtl8169_private *tp) { - if (rtl_is_8125(tp)) - RTL_W32(tp, IntrMask_8125, tp->irq_mask); - else + if (rtl_is_8125(tp)) { + if (tp->features & RTL_VEC_MAP_ENABLE) + RTL_W32(tp, IMR_SET_VEC_MAP_REG, tp->irq_mask); + else + RTL_W32(tp, IntrMask_8125, tp->irq_mask); + } else { RTL_W16(tp, IntrMask, tp->irq_mask); + } } =20 static void rtl8169_irq_mask_and_ack(struct rtl8169_private *tp) @@ -5154,6 +5175,44 @@ static void rtl8169_free_irq(struct rtl8169_private = *tp) } } =20 +static void rtl8169_disable_hw_interrupt_msix(struct rtl8169_private *tp, = int message_id) +{ + RTL_W32(tp, IMR_CLEAR_VEC_MAP_REG, BIT(message_id)); +} + +static void rtl8169_clear_hw_isr(struct rtl8169_private *tp, int message_i= d) +{ + RTL_W32(tp, ISR_VEC_MAP_REG, BIT(message_id)); +} + +static void rtl8169_enable_hw_interrupt_msix(struct rtl8169_private *tp, i= nt message_id) +{ + RTL_W32(tp, IMR_SET_VEC_MAP_REG, BIT(message_id)); +} + +static irqreturn_t rtl8169_interrupt_msix(int irq, void *dev_instance) +{ + struct rtl8169_napi *napi =3D dev_instance; + struct rtl8169_private *tp =3D napi->priv; + int message_id =3D napi->index; + + rtl8169_disable_hw_interrupt_msix(tp, message_id); + + rtl8169_clear_hw_isr(tp, message_id); + + if (message_id =3D=3D MSIX_ID_VEC_MAP_LINKCHG) { + phy_mac_interrupt(tp->phydev); + rtl8169_enable_hw_interrupt_msix(tp, message_id); + return IRQ_HANDLED; + } + + tp->recheck_desc_ownbit =3D true; + + napi_schedule(&napi->napi); + + return IRQ_HANDLED; +} + static int rtl8169_request_irq(struct rtl8169_private *tp) { const int len =3D sizeof(tp->irq_tbl[0].name); @@ -5164,6 +5223,10 @@ static int rtl8169_request_irq(struct rtl8169_privat= e *tp) =20 for (int i =3D 0; i < tp->irq_nvecs; i++) { irq =3D &tp->irq_tbl[i]; + if (tp->features & RTL_VEC_MAP_ENABLE && tp->hw_curr_isr_ver > 1) + irq->handler =3D rtl8169_interrupt_msix; + else + irq->handler =3D rtl8169_interrupt; =20 napi =3D &tp->r8169napi[i]; snprintf(irq->name, len, "%s-%d", dev->name, i); @@ -5622,10 +5685,16 @@ static const struct net_device_ops rtl_netdev_ops = =3D { =20 static void rtl_set_irq_mask(struct rtl8169_private *tp) { - tp->irq_mask =3D RxOK | RxErr | TxOK | TxErr | LinkChg; + if (tp->features & RTL_VEC_MAP_ENABLE) { + tp->irq_mask =3D ISRIMR_LINKCHG | ISRIMR_TOK_Q0; + for (int i =3D 0; i < tp->num_rx_rings; i++) + tp->irq_mask |=3D ISRIMR_ROK_Q0 << i; + } else { + tp->irq_mask =3D RxOK | RxErr | TxOK | TxErr | LinkChg; =20 - if (tp->mac_version <=3D RTL_GIGA_MAC_VER_06) - tp->irq_mask |=3D SYSErr | RxFIFOOver; + if (tp->mac_version <=3D RTL_GIGA_MAC_VER_06) + tp->irq_mask |=3D SYSErr | RxFIFOOver; + } } =20 static int rtl_alloc_irq(struct rtl8169_private *tp) @@ -5659,6 +5728,9 @@ static int rtl_alloc_irq(struct rtl8169_private *tp) tp->irq =3D pci_irq_vector(pdev, 0); tp->irq_nvecs =3D nvecs; =20 + if (nvecs > 1) + tp->features |=3D RTL_VEC_MAP_ENABLE; + return 0; } =20 @@ -5925,6 +5997,53 @@ static bool rtl_aspm_is_safe(struct rtl8169_private = *tp) return false; } =20 +static int rtl8169_poll_msix_rx(struct napi_struct *napi, int budget) +{ + struct rtl8169_napi *r8169_napi =3D container_of(napi, struct rtl8169_nap= i, napi); + struct rtl8169_private *tp =3D r8169_napi->priv; + const int message_id =3D r8169_napi->index; + struct net_device *dev =3D tp->dev; + int work_done =3D 0; + + if (message_id < tp->num_rx_rings) + work_done +=3D rtl_rx(dev, tp, &tp->rx_ring[message_id], budget); + + if (work_done < budget && napi_complete_done(napi, work_done)) + rtl8169_enable_hw_interrupt_msix(tp, message_id); + + return work_done; +} + +static int rtl8169_poll_msix_tx(struct napi_struct *napi, int budget) +{ + struct rtl8169_napi *r8169_napi =3D container_of(napi, struct rtl8169_nap= i, napi); + struct rtl8169_private *tp =3D r8169_napi->priv; + const int message_id =3D r8169_napi->index; + int tx_ring_idx =3D message_id - 8; + struct net_device *dev =3D tp->dev; + unsigned int work_done =3D 0; + + if (tx_ring_idx >=3D 0) + rtl_tx(dev, tp, budget); + + if (work_done < budget && napi_complete_done(napi, work_done)) + rtl8169_enable_hw_interrupt_msix(tp, message_id); + + return work_done; +} + +static int rtl8169_poll_msix_other(struct napi_struct *napi, int budget) +{ + struct rtl8169_napi *r8169_napi =3D container_of(napi, struct rtl8169_nap= i, napi); + struct rtl8169_private *tp =3D r8169_napi->priv; + const int message_id =3D r8169_napi->index; + + napi_complete_done(napi, budget); + rtl8169_enable_hw_interrupt_msix(tp, message_id); + + return 1; +} + static void r8169_init_napi(struct rtl8169_private *tp) { for (int i =3D 0; i < tp->irq_nvecs; i++) { @@ -5932,6 +6051,22 @@ static void r8169_init_napi(struct rtl8169_private *= tp) int (*poll)(struct napi_struct *napi, int budget); =20 poll =3D rtl8169_poll; + if (tp->features & RTL_VEC_MAP_ENABLE) { + switch (tp->hw_curr_isr_ver) { + case 6: + if (i < R8127_MAX_RX_QUEUES) + poll =3D rtl8169_poll_msix_rx; + else if (i >=3D R8127_MAX_RX_QUEUES && + i < (R8127_MAX_RX_QUEUES + + R8127_MAX_TX_QUEUES)) + poll =3D rtl8169_poll_msix_tx; + else + poll =3D rtl8169_poll_msix_other; + break; + default: + break; + } + } netif_napi_add(tp->dev, &r8169napi->napi, poll); r8169napi->priv =3D tp; r8169napi->index =3D i; --=20 2.43.0 From nobody Sat Jun 13 17:32:58 2026 Received: from rtits2.realtek.com.tw (rtits2.realtek.com [211.75.126.72]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 0B1CD3E314A; Wed, 6 May 2026 08:14:03 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=211.75.126.72 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1778055250; cv=none; b=VPEZJvyUGQ5FOnGJYaK5Bk63XAJXv0CPlf+/S4CW7uMAxhD50b7N5mohj8BE3cKC3w6DyDzM6knBKGIjToLR7W5DgmbsYQgqsyHvAG6GvGyA5cPY0CtQyZPWAu23PU7YFSXzJGhr3j+Z6X8pyoTOPFlQtRDyjzPWaHLgiO/CKhc= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1778055250; c=relaxed/simple; bh=abe0cYAsS28S/09SWhJ9xSqVoyt+naPJV6NAjqJW+ek=; h=From:To:CC:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=Vg04kr0f+aDUmtZf8D+nlJhKRt7y3eTEHUz/BuYykNk+aqPF71n6py269nDEO+3Jdlo8l+RjQMxtELyIOPg55ocM2a0rybDdEGo5tnl/VyJeeMrO0OWP1OozT1bgTofh4mXCjbgWA3YBoh/Vk37feL9FIYyFL7p/UIJEEjrMTfU= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=realsil.com.cn; spf=pass smtp.mailfrom=realsil.com.cn; dkim=pass (2048-bit key) header.d=realsil.com.cn header.i=@realsil.com.cn header.b=Q50JEjKi; arc=none smtp.client-ip=211.75.126.72 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=realsil.com.cn Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=realsil.com.cn Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=realsil.com.cn header.i=@realsil.com.cn header.b="Q50JEjKi" X-SpamFilter-By: ArmorX SpamTrap 5.80 with qID 6468DUnrC1854043, This message is accepted by code: ctloc85258 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=realsil.com.cn; s=dkim; t=1778055210; bh=epi82dfyb3QxHqFvOrGhnB+YLTkegHohYaK1Xpqhj2U=; h=From:To:CC:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Transfer-Encoding:Content-Type; b=Q50JEjKi7Z9mDThE5EZ+/BzwEHuPdia809qK+LDhLAlaVECwzEhhP4VgefFfuwUtO ngfWWZ8/V8y3vfTFsdYDRafcsNr3JUHoN5dd6AaTn07PDNWGp8qy0rshJepLQ2NJ1q VrUAlJ5Qw+WFyJp4CD1dalGBGXfGVgs5iLQKo8LrwejhCP4CXkTnyx/GIHxCbGFpK8 ILXhQ8xLDREEdCaSHKmU2UmBu6zRXCFy0LP2/ODmNVvXDTTy/euPUvUEIxMBqF+ZpI ZF5vfOSmuIFluBSvjrrCHHnHPNyJPG6RgqscvKVIRtI66n5Dnkz1AD1EppqTGMFQMi 0lXto+tDe/cBQ== Received: from RS-EX-MBS2.realsil.com.cn ([172.29.17.102]) by rtits2.realtek.com.tw (8.15.2/3.27/5.94) with ESMTPS id 6468DUnrC1854043 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=FAIL); Wed, 6 May 2026 16:13:30 +0800 Received: from RS-EX-MBS2.realsil.com.cn (172.29.17.102) by RS-EX-MBS2.realsil.com.cn (172.29.17.102) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.2.2562.17; Wed, 6 May 2026 16:13:29 +0800 Received: from 172.29.37.154 (172.29.37.152) by RS-EX-MBS2.realsil.com.cn (172.29.17.102) with Microsoft SMTP Server id 15.2.2562.17 via Frontend Transport; Wed, 6 May 2026 16:13:29 +0800 From: javen To: , , , , , , , CC: , , Javen Xu Subject: [Patch net-next v1 4/7] r8169: enable new interrupt mapping Date: Wed, 6 May 2026 16:13:22 +0800 Message-ID: <20260506081326.767-5-javen_xu@realsil.com.cn> X-Mailer: git-send-email 2.50.1.windows.1 In-Reply-To: <20260506081326.767-1-javen_xu@realsil.com.cn> References: <20260506081326.767-1-javen_xu@realsil.com.cn> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" From: Javen Xu This patch enables new interrupt mapping for RTL8127. Signed-off-by: Javen Xu --- drivers/net/ethernet/realtek/r8169_main.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/drivers/net/ethernet/realtek/r8169_main.c b/drivers/net/ethern= et/realtek/r8169_main.c index 671f82c326d9..69601e077646 100644 --- a/drivers/net/ethernet/realtek/r8169_main.c +++ b/drivers/net/ethernet/realtek/r8169_main.c @@ -4004,6 +4004,15 @@ DECLARE_RTL_COND(rtl_mac_ocp_e00e_cond) return r8168_mac_ocp_read(tp, 0xe00e) & BIT(13); } =20 +static void rtl8125_hw_set_interrupt_type(struct rtl8169_private *tp) +{ + u8 tmp; + + tmp =3D RTL_R8(tp, INT_CFG0_8125); + tmp |=3D INT_CFG0_ENABLE_8125; + RTL_W8(tp, INT_CFG0_8125, tmp); +} + static void rtl_hw_start_8125_common(struct rtl8169_private *tp) { rtl_pcie_state_l2l3_disable(tp); @@ -4012,6 +4021,9 @@ static void rtl_hw_start_8125_common(struct rtl8169_p= rivate *tp) RTL_W32(tp, RSS_CTRL_8125, 0); RTL_W16(tp, Q_NUM_CTRL_8125, 0); =20 + if (tp->features & RTL_VEC_MAP_ENABLE) + rtl8125_hw_set_interrupt_type(tp); + /* disable UPS */ r8168_mac_ocp_modify(tp, 0xd40a, 0x0010, 0x0000); =20 --=20 2.43.0 From nobody Sat Jun 13 17:32:58 2026 Received: from rtits2.realtek.com.tw (rtits2.realtek.com [211.75.126.72]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 6B32F3E315C; Wed, 6 May 2026 08:14:03 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=211.75.126.72 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1778055250; cv=none; b=auutfAxc6tkFuKPbB0bI8kmr4DRkDphhmYMczBTp1GolCzZpD72xDsuWHE5G2fqN38uXz6SN5c9RHHTxC7aqttduTxLHN+MD732Xe5wyMQu/hyPMxjLmD+McrCUYbwygoZfg6EwVlsoVxy8zh3l/3goOFEYDZ/RHr3cuhO/blhE= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1778055250; c=relaxed/simple; bh=7PSCrLcd/2bRHlthTjzhBwMoKgjJu6Schh+5MNaOVOc=; h=From:To:CC:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=EBqPEUHI196LN+iP6TWTEpiSoUHK8zTdUKlNG2neWLbZXzJYJn8h2mMK5IGS0R9E1gP+hexj9OK19JUSu36OPXSTC7zDbWMPO/V5ehmfb9v3/u/LCvZuRjwh0rXXfmAgjTfLSm7XtpXgnryiSyaJ4QDIIgXMU9ktZerRPN73sd0= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=realsil.com.cn; spf=pass smtp.mailfrom=realsil.com.cn; dkim=pass (2048-bit key) header.d=realsil.com.cn header.i=@realsil.com.cn header.b=IQZP4jSR; arc=none smtp.client-ip=211.75.126.72 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=realsil.com.cn Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=realsil.com.cn Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=realsil.com.cn header.i=@realsil.com.cn header.b="IQZP4jSR" X-SpamFilter-By: ArmorX SpamTrap 5.80 with qID 6468DUnsC1854043, This message is accepted by code: ctloc85258 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=realsil.com.cn; s=dkim; t=1778055210; bh=N7Qk6Nf0QnwCJOYn5dWFLoGJt/TOUe3HQCgtkt6POiE=; h=From:To:CC:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Transfer-Encoding:Content-Type; b=IQZP4jSRCDQIh1hFUFCoF5mKm2pZjuS/F7eLAbnAMxPsTf06EzLLNDAZ4nX5QCJfO 5YWYdPoBtktZvn0ZCI9WdhY9MhMA8rIKRgou3ArrJ3f//1bxocwxhRp6chiOpOLWgF jww+q/AUf37WbHkYmd2MH/dOscpJdk/Brc/b8TnY2t1IVL/4wIgZBIWBictxTUnlHv bqpvKier+JIiHn9tF+/XHpaBLCTWXqEVu+L02DI++v4ZPbZIG1N/bmYrcftQi6SkXv 5kOZNeROGzAO4zycOxsMPuZIIuDzEG/33q9EQYoL2afApMpAD6sg13tcUIYe+3Q0It AjUx8JTSfTI5g== Received: from RS-EX-MBS2.realsil.com.cn ([172.29.17.102]) by rtits2.realtek.com.tw (8.15.2/3.27/5.94) with ESMTPS id 6468DUnsC1854043 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=FAIL); Wed, 6 May 2026 16:13:30 +0800 Received: from RS-EX-MBS2.realsil.com.cn (172.29.17.102) by RS-EX-MBS2.realsil.com.cn (172.29.17.102) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.2.2562.17; Wed, 6 May 2026 16:13:29 +0800 Received: from 172.29.37.154 (172.29.37.152) by RS-EX-MBS2.realsil.com.cn (172.29.17.102) with Microsoft SMTP Server id 15.2.2562.17 via Frontend Transport; Wed, 6 May 2026 16:13:29 +0800 From: javen To: , , , , , , , CC: , , Javen Xu Subject: [Patch net-next v1 5/7] r8169: add support and enable rss Date: Wed, 6 May 2026 16:13:23 +0800 Message-ID: <20260506081326.767-6-javen_xu@realsil.com.cn> X-Mailer: git-send-email 2.50.1.windows.1 In-Reply-To: <20260506081326.767-1-javen_xu@realsil.com.cn> References: <20260506081326.767-1-javen_xu@realsil.com.cn> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" From: Javen Xu This patch adds support and enable rss for RTL8127. Signed-off-by: Javen Xu --- drivers/net/ethernet/realtek/r8169_main.c | 361 ++++++++++++++++++++-- 1 file changed, 343 insertions(+), 18 deletions(-) diff --git a/drivers/net/ethernet/realtek/r8169_main.c b/drivers/net/ethern= et/realtek/r8169_main.c index 69601e077646..9b42cee24b8a 100644 --- a/drivers/net/ethernet/realtek/r8169_main.c +++ b/drivers/net/ethernet/realtek/r8169_main.c @@ -80,6 +80,18 @@ #define R8127_MAX_TX_QUEUES 8 #define R8169_MAX_MSIX_VEC 32 #define R8127_MAX_RX_QUEUES 8 +#define R8127_MAX_IRQ 32 +#define R8127_MIN_IRQ 30 +#define RTL_RSS_KEY_SIZE 40 +#define RSS_CPU_NUM_OFFSET 16 +#define RSS_MASK_BITS_OFFSET 8 +#define RTL_MAX_INDIRECTION_TABLE_ENTRIES 128 +#define RXS_RSS_UDP BIT(27) +#define RXS_RSS_IPV4 BIT(28) +#define RXS_RSS_IPV6 BIT(29) +#define RXS_RSS_TCP BIT(30) +#define RXS_RSS_L3_TYPE_MASK (RXS_RSS_IPV4 | RXS_RSS_IPV6) +#define RXS_RSS_L4_TYPE_MASK (RXS_RSS_TCP | RXS_RSS_UDP) =20 #define OCP_STD_PHY_BASE 0xa400 =20 @@ -449,6 +461,7 @@ enum rtl8125_registers { RSS_CTRL_8125 =3D 0x4500, Q_NUM_CTRL_8125 =3D 0x4800, EEE_TXIDLE_TIMER_8125 =3D 0x6048, + TNPDS_Q1_LOW =3D 0x2100, RDSAR_Q1_LOW =3D 0x4000, IMR_SET_VEC_MAP_REG =3D 0x0d0c, IMR_CLEAR_VEC_MAP_REG =3D 0x0d00, @@ -456,7 +469,23 @@ enum rtl8125_registers { }; =20 #define MSIX_ID_VEC_MAP_LINKCHG 29 +#define RSS_CTRL_TCP_IPV4_SUPP BIT(0) +#define RSS_CTRL_IPV4_SUPP BIT(1) +#define RSS_CTRL_TCP_IPV6_SUPP BIT(2) +#define RSS_CTRL_IPV6_SUPP BIT(3) +#define RSS_CTRL_IPV6_EXT_SUPP BIT(4) +#define RSS_CTRL_TCP_IPV6_EXT_SUPP BIT(5) +#define RSS_CTRL_UDP_IPV4_SUPP BIT(6) +#define RSS_CTRL_UDP_IPV6_SUPP BIT(7) +#define RSS_CTRL_UDP_IPV6_EXT_SUPP BIT(8) +#define RTL_RSS_FLAG_HASH_UDP_IPV4 BIT(0) +#define RTL_RSS_FLAG_HASH_UDP_IPV6 BIT(1) +#define RX_RES_RSS BIT(22) +#define RX_RUNT_RSS BIT(21) +#define RX_CRC_RSS BIT(20) #define RTL_VEC_MAP_ENABLE BIT(0) +#define RSS_INDIRECTION_TBL_REG 0x4700 +#define RSS_KEY_REG 0x4600 =20 #define LEDSEL_MASK_8125 0x23f =20 @@ -648,6 +677,11 @@ enum rtl_rx_desc_bit { #define RxProtoIP (PID1 | PID0) #define RxProtoMask RxProtoIP =20 +#define RX_UDPT_DESC_RSS BIT(19) +#define RX_TCPT_DESC_RSS BIT(18) +#define RX_UDPF_DESC_RSS BIT(16) /* UDP/IP checksum failed */ +#define RX_TCPF_DESC_RSS BIT(15) /* TCP/IP checksum failed */ + IPFail =3D (1 << 16), /* IP checksum failed */ UDPFail =3D (1 << 15), /* UDP/IP checksum failed */ TCPFail =3D (1 << 14), /* TCP/IP checksum failed */ @@ -674,6 +708,21 @@ struct RxDesc { __le64 addr; }; =20 +struct rx_desc_rss { + union { + __le64 addr; + struct { + __le32 rss_info; + __le32 rss_result; + } rx_desc_rss_dword; + }; + + struct { + __le32 opts2; + __le32 opts1; + } rx_desc_opts; +}; + struct ring_info { struct sk_buff *skb; u32 len; @@ -795,9 +844,13 @@ struct rtl8169_private { u16 isr_reg[R8169_MAX_MSIX_VEC]; u16 imr_reg[R8169_MAX_MSIX_VEC]; unsigned int num_rx_rings; + u32 rss_flags; u16 cp_cmd; u16 tx_lpi_timer; u32 irq_mask; + u8 rss_key[RTL_RSS_KEY_SIZE]; + u8 rss_indir_tbl[RTL_MAX_INDIRECTION_TABLE_ENTRIES]; + u8 hw_supp_indir_tbl_entries; u16 hw_supp_num_rx_queues; u8 min_irq_nvecs; u8 max_irq_nvecs; @@ -1639,6 +1692,13 @@ static bool rtl_dash_is_enabled(struct rtl8169_priva= te *tp) } } =20 +static bool rtl_check_rss_support(struct rtl8169_private *tp) +{ + if (tp->mac_version =3D=3D RTL_GIGA_MAC_VER_80) + return true; + return false; +} + static enum rtl_dash_type rtl_get_dash_type(struct rtl8169_private *tp) { switch (tp->mac_version) { @@ -1938,9 +1998,20 @@ static inline u32 rtl8169_tx_vlan_tag(struct sk_buff= *skb) TxVlanTag | swab16(skb_vlan_tag_get(skb)) : 0x00; } =20 -static void rtl8169_rx_vlan_tag(struct RxDesc *desc, struct sk_buff *skb) +static void rtl8169_rx_vlan_tag(struct rtl8169_private *tp, + struct RxDesc *desc, + struct sk_buff *skb) { - u32 opts2 =3D le32_to_cpu(desc->opts2); + u32 opts2; + + switch (tp->init_rx_desc_type) { + case RX_DESC_RING_TYPE_RSS: + opts2 =3D le32_to_cpu(((struct rx_desc_rss *)desc)->rx_desc_opts.opts2); + break; + default: + opts2 =3D le32_to_cpu(desc->opts2); + break; + } =20 if (opts2 & RxVlanTag) __vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q), swab16(opts2 & 0xffff)); @@ -2796,15 +2867,24 @@ static void rtl_setup_mqs_reg(struct rtl8169_privat= e *tp) tp->imr_reg[i] =3D (u16)(INTR_VEC_MAP_MASK + (i - 1) * 4); } =20 +static void rtl8169_init_rss(struct rtl8169_private *tp) +{ + for (int i =3D 0; i < tp->hw_supp_indir_tbl_entries; i++) + tp->rss_indir_tbl[i] =3D ethtool_rxfh_indir_default(i, tp->num_rx_rings); + + netdev_rss_key_fill(tp->rss_key, RTL_RSS_KEY_SIZE); +} + static void rtl_software_parameter_initialize(struct rtl8169_private *tp) { tp->num_rx_rings =3D 1; =20 switch (tp->mac_version) { case RTL_GIGA_MAC_VER_80: - tp->min_irq_nvecs =3D 1; - tp->max_irq_nvecs =3D 1; + tp->min_irq_nvecs =3D R8127_MIN_IRQ; + tp->max_irq_nvecs =3D R8127_MAX_IRQ; tp->hw_supp_num_rx_queues =3D R8127_MAX_RX_QUEUES; + tp->hw_supp_indir_tbl_entries =3D RTL_MAX_INDIRECTION_TABLE_ENTRIES; tp->hw_supp_isr_ver =3D 6; break; default: @@ -2943,6 +3023,76 @@ static void rtl_set_rx_max_size(struct rtl8169_priva= te *tp) RTL_W16(tp, RxMaxSize, R8169_RX_BUF_SIZE + 1); } =20 +static void rtl8169_store_rss_key(struct rtl8169_private *tp) +{ + const u16 rss_key_reg =3D RSS_KEY_REG; + u32 i, rss_key_size =3D sizeof(tp->rss_key); + u32 *rss_key =3D (u32 *)tp->rss_key; + + /* Write redirection table to HW */ + for (i =3D 0; i < rss_key_size; i +=3D 4) + RTL_W32(tp, rss_key_reg + i, *rss_key++); +} + +static void rtl8169_store_reta(struct rtl8169_private *tp) +{ + u16 indir_tbl_reg =3D RSS_INDIRECTION_TBL_REG; + u32 i, reta_entries =3D tp->hw_supp_indir_tbl_entries; + u32 reta =3D 0; + u8 *indir_tbl =3D tp->rss_indir_tbl; + + /* Write redirection table to HW */ + for (i =3D 0; i < reta_entries; i++) { + reta |=3D indir_tbl[i] << (i & 0x3) * 8; + if ((i & 3) =3D=3D 3) { + RTL_W32(tp, indir_tbl_reg, reta); + indir_tbl_reg +=3D 4; + reta =3D 0; + } + } +} + +static int rtl8169_set_rss_hash_opt(struct rtl8169_private *tp) +{ + u32 rss_flags =3D tp->rss_flags; + u32 hash_mask_len; + u32 rss_ctrl; + + rss_ctrl =3D ilog2(tp->num_rx_rings); + rss_ctrl &=3D (BIT(0) | BIT(1) | BIT(2)); + rss_ctrl <<=3D RSS_CPU_NUM_OFFSET; + + /* Perform hash on these packet types */ + rss_ctrl |=3D RSS_CTRL_TCP_IPV4_SUPP + | RSS_CTRL_IPV4_SUPP + | RSS_CTRL_IPV6_SUPP + | RSS_CTRL_IPV6_EXT_SUPP + | RSS_CTRL_TCP_IPV6_SUPP + | RSS_CTRL_TCP_IPV6_EXT_SUPP; + + if (rss_flags & RTL_RSS_FLAG_HASH_UDP_IPV4) + rss_ctrl |=3D RSS_CTRL_UDP_IPV4_SUPP; + + if (rss_flags & RTL_RSS_FLAG_HASH_UDP_IPV6) + rss_ctrl |=3D RSS_CTRL_UDP_IPV6_SUPP | + RSS_CTRL_UDP_IPV6_EXT_SUPP; + + hash_mask_len =3D ilog2(tp->hw_supp_indir_tbl_entries); + hash_mask_len &=3D (BIT(0) | BIT(1) | BIT(2)); + rss_ctrl |=3D hash_mask_len << RSS_MASK_BITS_OFFSET; + + RTL_W32(tp, RSS_CTRL_8125, rss_ctrl); + + return 0; +} + +static void rtl_set_rss_config(struct rtl8169_private *tp) +{ + rtl8169_set_rss_hash_opt(tp); + rtl8169_store_reta(tp); + rtl8169_store_rss_key(tp); +} + static void rtl_set_rx_tx_desc_registers(struct rtl8169_private *tp) { /* @@ -4004,6 +4154,20 @@ DECLARE_RTL_COND(rtl_mac_ocp_e00e_cond) return r8168_mac_ocp_read(tp, 0xe00e) & BIT(13); } =20 +static void rtl8125_set_rx_q_num(struct rtl8169_private *tp) +{ + u16 q_ctrl; + u16 rx_q_num; + + rx_q_num =3D (u16)ilog2(tp->num_rx_rings); + rx_q_num &=3D (BIT(0) | BIT(1) | BIT(2)); + rx_q_num <<=3D 2; + q_ctrl =3D RTL_R16(tp, Q_NUM_CTRL_8125); + q_ctrl &=3D ~(BIT(2) | BIT(3) | BIT(4)); + q_ctrl |=3D rx_q_num; + RTL_W16(tp, Q_NUM_CTRL_8125, q_ctrl); +} + static void rtl8125_hw_set_interrupt_type(struct rtl8169_private *tp) { u8 tmp; @@ -4043,6 +4207,12 @@ static void rtl_hw_start_8125_common(struct rtl8169_= private *tp) tp->mac_version =3D=3D RTL_GIGA_MAC_VER_80) RTL_W8(tp, 0xD8, RTL_R8(tp, 0xD8) & ~0x02); =20 + /* enable rx descriptor type v4 and set queue num for rss*/ + if (tp->rss_enable) { + rtl8125_set_rx_q_num(tp); + RTL_W8(tp, 0xd8, RTL_R8(tp, 0xd8) | 0x02); + } + if (tp->mac_version =3D=3D RTL_GIGA_MAC_VER_80) r8168_mac_ocp_modify(tp, 0xe614, 0x0f00, 0x0f00); else if (tp->mac_version =3D=3D RTL_GIGA_MAC_VER_70) @@ -4279,6 +4449,12 @@ static void rtl_hw_start(struct rtl8169_private *tp) rtl_hw_aspm_clkreq_enable(tp, true); rtl_set_rx_max_size(tp); rtl_set_rx_tx_desc_registers(tp); + if (rtl_is_8125(tp)) { + if (tp->rss_enable) + rtl_set_rss_config(tp); + else + RTL_W32(tp, RSS_CTRL_8125, 0x00); + } rtl_lock_config_regs(tp); =20 rtl_jumbo_config(tp); @@ -4306,6 +4482,16 @@ static int rtl8169_change_mtu(struct net_device *dev= , int new_mtu) return 0; } =20 +static void rtl8169_mark_to_asic_rss(struct rx_desc_rss *descrss) +{ + u32 eor =3D le32_to_cpu(descrss->rx_desc_opts.opts1) & RingEnd; + + descrss->rx_desc_opts.opts2 =3D 0; + /* Force memory writes to complete before releasing descriptor */ + dma_wmb(); + WRITE_ONCE(descrss->rx_desc_opts.opts1, cpu_to_le32(DescOwn | eor | R8169= _RX_BUF_SIZE)); +} + static void rtl8169_mark_to_asic_default(struct RxDesc *desc) { u32 eor =3D le32_to_cpu(desc->opts1) & RingEnd; @@ -4318,7 +4504,14 @@ static void rtl8169_mark_to_asic_default(struct RxDe= sc *desc) =20 static void rtl8169_mark_to_asic(struct rtl8169_private *tp, struct RxDesc= *desc) { - rtl8169_mark_to_asic_default(desc); + switch (tp->init_rx_desc_type) { + case RX_DESC_RING_TYPE_RSS: + rtl8169_mark_to_asic_rss((struct rx_desc_rss *)desc); + break; + default: + rtl8169_mark_to_asic_default(desc); + break; + } } =20 static struct page *rtl8169_alloc_rx_data(struct rtl8169_private *tp, @@ -4341,8 +4534,14 @@ static struct page *rtl8169_alloc_rx_data(struct rtl= 8169_private *tp, return NULL; } =20 - desc->addr =3D cpu_to_le64(mapping); ring->rx_desc_phy_addr[index] =3D mapping; + if (tp->init_rx_desc_type =3D=3D RX_DESC_RING_TYPE_RSS) { + struct rx_desc_rss *descrss =3D (struct rx_desc_rss *)(ring->rx_desc_arr= ay) + index; + + descrss->addr =3D cpu_to_le64(mapping); + } else { + desc->addr =3D cpu_to_le64(mapping); + } rtl8169_mark_to_asic(tp, desc); =20 return data; @@ -4369,9 +4568,21 @@ static void rtl8169_mark_as_last_descriptor_default(= struct RxDesc *desc) desc->opts1 |=3D cpu_to_le32(RingEnd); } =20 +static void rtl8169_mark_as_last_descriptor_rss(struct rx_desc_rss *descrs= s) +{ + descrss->rx_desc_opts.opts1 |=3D cpu_to_le32(RingEnd); +} + static void rtl8169_mark_as_last_descriptor(struct rtl8169_private *tp, st= ruct RxDesc *desc) { - rtl8169_mark_as_last_descriptor_default(desc); + switch (tp->init_rx_desc_type) { + case RX_DESC_RING_TYPE_RSS: + rtl8169_mark_as_last_descriptor_rss((struct rx_desc_rss *)desc); + break; + default: + rtl8169_mark_as_last_descriptor_default(desc); + break; + } } =20 static int rtl8169_rx_fill(struct rtl8169_private *tp, struct rtl8169_rx_r= ing *ring) @@ -5003,6 +5214,28 @@ static inline int rtl8169_fragmented_frame(u32 statu= s) return (status & (FirstFrag | LastFrag)) !=3D (FirstFrag | LastFrag); } =20 +static inline void rtl8169_rx_hash(struct rtl8169_private *tp, + struct rx_desc_rss *desc, + struct sk_buff *skb) +{ + u32 rss_header_info; + u32 hash_val; + + if (!(tp->dev->features & NETIF_F_RXHASH)) + return; + + rss_header_info =3D le32_to_cpu(desc->rx_desc_rss_dword.rss_info); + + if (!(rss_header_info & RXS_RSS_L3_TYPE_MASK)) + return; + + hash_val =3D le32_to_cpu(desc->rx_desc_rss_dword.rss_result); + + skb_set_hash(skb, hash_val, + (RXS_RSS_L4_TYPE_MASK & rss_header_info) ? + PKT_HASH_TYPE_L4 : PKT_HASH_TYPE_L3); +} + static inline void rtl8169_rx_csum_default(struct rtl8169_private *tp, struct sk_buff *skb, struct RxDesc *desc) @@ -5015,28 +5248,66 @@ static inline void rtl8169_rx_csum_default(struct r= tl8169_private *tp, skb_checksum_none_assert(skb); } =20 +static inline void rtl8169_rx_csum_rss(struct rtl8169_private *tp, + struct sk_buff *skb, + struct rx_desc_rss *descrss) +{ + u32 opts1 =3D le32_to_cpu(descrss->rx_desc_opts.opts1); + + if (((opts1 & RX_TCPT_DESC_RSS) && !(opts1 & RX_TCPF_DESC_RSS)) || + ((opts1 & RX_UDPT_DESC_RSS) && !(opts1 & RX_UDPF_DESC_RSS))) + skb->ip_summed =3D CHECKSUM_UNNECESSARY; + else + skb_checksum_none_assert(skb); +} + static inline void rtl8169_rx_csum(struct rtl8169_private *tp, struct sk_buff *skb, struct RxDesc *desc) { - rtl8169_rx_csum_default(tp, skb, desc); + switch (tp->init_rx_desc_type) { + case RX_DESC_RING_TYPE_RSS: + rtl8169_rx_csum_rss(tp, skb, (struct rx_desc_rss *)desc); + break; + default: + rtl8169_rx_csum_default(tp, skb, desc); + break; + } } =20 static u32 rtl8169_rx_desc_opts1(struct rtl8169_private *tp, struct RxDesc= *desc) { - return READ_ONCE(desc->opts1); + switch (tp->init_rx_desc_type) { + case RX_DESC_RING_TYPE_RSS: + return READ_ONCE(((struct rx_desc_rss *)desc)->rx_desc_opts.opts1); + default: + return READ_ONCE(desc->opts1); + } } =20 static bool rtl8169_check_rx_desc_error(struct net_device *dev, struct rtl8169_private *tp, u32 status) { - if (unlikely(status & RxRES)) { - if (status & (RxRWT | RxRUNT)) - dev->stats.rx_length_errors++; - if (status & RxCRC) - dev->stats.rx_crc_errors++; - return true; + switch (tp->init_rx_desc_type) { + case RX_DESC_RING_TYPE_RSS: + if (unlikely(status & RX_RES_RSS)) { + if (status & RX_RUNT_RSS) + dev->stats.rx_length_errors++; + if (status & RX_CRC_RSS) + dev->stats.rx_crc_errors++; + return true; + } + break; + default: + if (unlikely(status & RxRES)) { + if (status & (RxRWT | RxRUNT)) + dev->stats.rx_length_errors++; + if (status & RxCRC) + dev->stats.rx_crc_errors++; + return true; + } + break; } return false; } @@ -5045,7 +5316,14 @@ static inline void rtl8169_set_desc_dma_addr(struct = rtl8169_private *tp, struct RxDesc *desc, dma_addr_t mapping) { - desc->addr =3D cpu_to_le64(mapping); + switch (tp->init_rx_desc_type) { + case RX_DESC_RING_TYPE_RSS: + ((struct rx_desc_rss *)desc)->addr =3D cpu_to_le64(mapping); + break; + default: + desc->addr =3D cpu_to_le64(mapping); + break; + } } =20 static int rtl_rx(struct net_device *dev, struct rtl8169_private *tp, @@ -5127,10 +5405,13 @@ static int rtl_rx(struct net_device *dev, struct rt= l8169_private *tp, skb->len =3D pkt_size; dma_sync_single_for_device(d, addr, pkt_size, DMA_FROM_DEVICE); =20 + if (tp->rss_enable) + rtl8169_rx_hash(tp, (struct rx_desc_rss *)desc, skb); + rtl8169_rx_csum(tp, skb, desc); skb->protocol =3D eth_type_trans(skb, dev); =20 - rtl8169_rx_vlan_tag(desc, skb); + rtl8169_rx_vlan_tag(tp, desc, skb); =20 if (skb->pkt_type =3D=3D PACKET_MULTICAST) dev->stats.multicast++; @@ -5242,7 +5523,6 @@ static int rtl8169_request_irq(struct rtl8169_private= *tp) =20 napi =3D &tp->r8169napi[i]; snprintf(irq->name, len, "%s-%d", dev->name, i); - irq->handler =3D rtl8169_interrupt; rc =3D pci_request_irq(tp->pci_dev, i, irq->handler, NULL, napi, irq->na= me); if (rc) break; @@ -5709,6 +5989,41 @@ static void rtl_set_irq_mask(struct rtl8169_private = *tp) } } =20 +static void rtl8169_double_check_rss_support(struct rtl8169_private *tp) +{ + if (tp->hw_curr_isr_ver > 1) { + if (!(tp->features & RTL_VEC_MAP_ENABLE) || tp->irq_nvecs < tp->min_irq_= nvecs) + tp->hw_curr_isr_ver =3D 1; + } + + if (tp->rss_support && tp->hw_curr_isr_ver > 1) { + u8 rss_queue_num =3D netif_get_num_default_rss_queues(); + + tp->num_rx_rings =3D min(rss_queue_num, tp->hw_supp_num_rx_queues); + if (!(tp->num_rx_rings >=3D 2 && tp->irq_nvecs >=3D tp->min_irq_nvecs)) + tp->num_rx_rings =3D 1; + } + + tp->rss_enable =3D 0; + + if (tp->num_rx_rings >=3D 2) { + tp->rss_enable =3D 1; + tp->init_rx_desc_type =3D RX_DESC_RING_TYPE_RSS; + } else if (tp->irq_nvecs > 1 && !tp->rss_support) { + pci_free_irq_vectors(tp->pci_dev); + tp->irq_nvecs =3D pci_alloc_irq_vectors(tp->pci_dev, 1, 1, PCI_IRQ_ALL_T= YPES); + + if (tp->irq_nvecs > 0) { + tp->irq =3D pci_irq_vector(tp->pci_dev, 0); + } else { + tp->irq =3D tp->pci_dev->irq; + tp->irq_nvecs =3D 1; + } + + tp->features &=3D ~RTL_VEC_MAP_ENABLE; + } +} + static int rtl_alloc_irq(struct rtl8169_private *tp) { struct pci_dev *pdev =3D tp->pci_dev; @@ -6177,6 +6492,7 @@ static int rtl_init_one(struct pci_dev *pdev, const s= truct pci_device_id *ent) =20 tp->dash_type =3D rtl_get_dash_type(tp); tp->dash_enabled =3D rtl_dash_is_enabled(tp); + tp->rss_support =3D rtl_check_rss_support(tp); =20 tp->cp_cmd =3D RTL_R16(tp, CPlusCmd) & CPCMD_MASK; =20 @@ -6198,6 +6514,10 @@ static int rtl_init_one(struct pci_dev *pdev, const = struct pci_device_id *ent) if (rc < 0) return dev_err_probe(&pdev->dev, rc, "Can't allocate interrupt\n"); =20 + rtl8169_double_check_rss_support(tp); + + if (tp->rss_support) + rtl8169_init_rss(tp); =20 INIT_WORK(&tp->wk.work, rtl_task); disable_work(&tp->wk.work); @@ -6219,6 +6539,11 @@ static int rtl_init_one(struct pci_dev *pdev, const = struct pci_device_id *ent) dev->vlan_features =3D NETIF_F_SG | NETIF_F_IP_CSUM | NETIF_F_TSO; dev->priv_flags |=3D IFF_LIVE_ADDR_CHANGE; =20 + if (tp->rss_support) { + dev->hw_features |=3D NETIF_F_RXHASH; + dev->features |=3D NETIF_F_RXHASH; + } + /* * Pretend we are using VLANs; This bypasses a nasty bug where * Interrupts stop flowing on high load on 8110SCd controllers. --=20 2.43.0 From nobody Sat Jun 13 17:32:58 2026 Received: from rtits2.realtek.com.tw (rtits2.realtek.com [211.75.126.72]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 949C23E315F; Wed, 6 May 2026 08:14:04 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=211.75.126.72 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1778055248; cv=none; b=gTawY7d6dP3T7qhJYOf/LsEtf2CGd0cMoMRgSg56g8xMa/KjNo9dMO3ZYLXYsoxHEW5ODFmddqRyQZCZy1PfPkOyl2qxWZUVdtkeIQA41dVFFGNiA4mY1CuW30KyBM88/WWeotkLGOoqOU2SwxEKORrjr1Z51uQYFPJvv3CDf7A= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1778055248; c=relaxed/simple; bh=I8RuWY6ofebec92FKNTacuSEC9h97iHSPA0oijrijbA=; h=From:To:CC:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=mpvKNVstergI7I7xZ75/OyKRHSzGxnOq+55oUgOoG8anPlOLDB8EcGD83FnNnsZza1kzwhtM2bADypWRM8BXnY1kjLBNcWuWhXuErDtXXAYUduBDIB3hM1V+NIeqnufm1GVacfIAaFb4sUZyDqs7KKOHqBsMwhXrdeEgLk+5wHc= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=realsil.com.cn; spf=pass smtp.mailfrom=realsil.com.cn; dkim=pass (2048-bit key) header.d=realsil.com.cn header.i=@realsil.com.cn header.b=wPna8ywg; arc=none smtp.client-ip=211.75.126.72 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=realsil.com.cn Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=realsil.com.cn Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=realsil.com.cn header.i=@realsil.com.cn header.b="wPna8ywg" X-SpamFilter-By: ArmorX SpamTrap 5.80 with qID 6468DUntC1854043, This message is accepted by code: ctloc85258 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=realsil.com.cn; s=dkim; t=1778055211; bh=23sD5oZ1vq0VhQNvYh6K2Ckfq/TUJwRLq+zI+agy2kM=; h=From:To:CC:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Transfer-Encoding:Content-Type; b=wPna8ywgV6UeV8DG+aprGIuvI0L+aZJb9xryrhh255jNL3NsVl8Jlo0dK1Tz1XDrH /XWrDpFLGlubGr5zzY0UHrRCT7eAErGJ8IqUDB/FnN6KoVVjNfZ+vq/VS8P4KdjWAV XNEfXiuHrHetMcgXp9ir6C98e3lTS9XRFRFqvPhzjq8eEQ0fhAk5kn8zm+9kTiYDT2 ztNbppEYlzIOUJpPUhNibrWzD/AR/CKxzfUDxK6z9ayHVnLXiKdqodBaOAP7KTbQmS 6QdXN7lQ73ETBg6j0cuI+Vn/Md4WTioHvD49Kp9feQCElTB0CzJp4nC7R620vSsSNh FHm8YYbuK1JCQ== Received: from RS-EX-MBS2.realsil.com.cn ([172.29.17.102]) by rtits2.realtek.com.tw (8.15.2/3.27/5.94) with ESMTPS id 6468DUntC1854043 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=FAIL); Wed, 6 May 2026 16:13:30 +0800 Received: from RS-EX-MBS2.realsil.com.cn (172.29.17.102) by RS-EX-MBS2.realsil.com.cn (172.29.17.102) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.2.2562.17; Wed, 6 May 2026 16:13:30 +0800 Received: from 172.29.37.154 (172.29.37.152) by RS-EX-MBS2.realsil.com.cn (172.29.17.102) with Microsoft SMTP Server id 15.2.2562.17 via Frontend Transport; Wed, 6 May 2026 16:13:29 +0800 From: javen To: , , , , , , , CC: , , Javen Xu Subject: [Patch net-next v1 6/7] r8169: move struct ethtool_ops Date: Wed, 6 May 2026 16:13:24 +0800 Message-ID: <20260506081326.767-7-javen_xu@realsil.com.cn> X-Mailer: git-send-email 2.50.1.windows.1 In-Reply-To: <20260506081326.767-1-javen_xu@realsil.com.cn> References: <20260506081326.767-1-javen_xu@realsil.com.cn> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" From: Javen Xu This patch move struct ethtool_ops, no changes. Prepare for next patch. Signed-off-by: Javen Xu --- drivers/net/ethernet/realtek/r8169_main.c | 56 +++++++++++------------ 1 file changed, 28 insertions(+), 28 deletions(-) diff --git a/drivers/net/ethernet/realtek/r8169_main.c b/drivers/net/ethern= et/realtek/r8169_main.c index 9b42cee24b8a..6e682a5538d3 100644 --- a/drivers/net/ethernet/realtek/r8169_main.c +++ b/drivers/net/ethernet/realtek/r8169_main.c @@ -2558,34 +2558,6 @@ static int rtl8169_set_link_ksettings(struct net_dev= ice *ndev, return 0; } =20 -static const struct ethtool_ops rtl8169_ethtool_ops =3D { - .supported_coalesce_params =3D ETHTOOL_COALESCE_USECS | - ETHTOOL_COALESCE_MAX_FRAMES, - .get_drvinfo =3D rtl8169_get_drvinfo, - .get_regs_len =3D rtl8169_get_regs_len, - .get_link =3D ethtool_op_get_link, - .get_coalesce =3D rtl_get_coalesce, - .set_coalesce =3D rtl_set_coalesce, - .get_regs =3D rtl8169_get_regs, - .get_wol =3D rtl8169_get_wol, - .set_wol =3D rtl8169_set_wol, - .get_strings =3D rtl8169_get_strings, - .get_sset_count =3D rtl8169_get_sset_count, - .get_ethtool_stats =3D rtl8169_get_ethtool_stats, - .get_ts_info =3D ethtool_op_get_ts_info, - .nway_reset =3D phy_ethtool_nway_reset, - .get_eee =3D rtl8169_get_eee, - .set_eee =3D rtl8169_set_eee, - .get_link_ksettings =3D phy_ethtool_get_link_ksettings, - .set_link_ksettings =3D rtl8169_set_link_ksettings, - .get_ringparam =3D rtl8169_get_ringparam, - .get_pause_stats =3D rtl8169_get_pause_stats, - .get_pauseparam =3D rtl8169_get_pauseparam, - .set_pauseparam =3D rtl8169_set_pauseparam, - .get_eth_mac_stats =3D rtl8169_get_eth_mac_stats, - .get_eth_ctrl_stats =3D rtl8169_get_eth_ctrl_stats, -}; - static const struct rtl_chip_info *rtl8169_get_chip_version(u32 xid, bool = gmii) { /* Chips combining a 1Gbps MAC with a 100Mbps PHY */ @@ -6400,6 +6372,34 @@ static void r8169_init_napi(struct rtl8169_private *= tp) } } =20 +static const struct ethtool_ops rtl8169_ethtool_ops =3D { + .supported_coalesce_params =3D ETHTOOL_COALESCE_USECS | + ETHTOOL_COALESCE_MAX_FRAMES, + .get_drvinfo =3D rtl8169_get_drvinfo, + .get_regs_len =3D rtl8169_get_regs_len, + .get_link =3D ethtool_op_get_link, + .get_coalesce =3D rtl_get_coalesce, + .set_coalesce =3D rtl_set_coalesce, + .get_regs =3D rtl8169_get_regs, + .get_wol =3D rtl8169_get_wol, + .set_wol =3D rtl8169_set_wol, + .get_strings =3D rtl8169_get_strings, + .get_sset_count =3D rtl8169_get_sset_count, + .get_ethtool_stats =3D rtl8169_get_ethtool_stats, + .get_ts_info =3D ethtool_op_get_ts_info, + .nway_reset =3D phy_ethtool_nway_reset, + .get_eee =3D rtl8169_get_eee, + .set_eee =3D rtl8169_set_eee, + .get_link_ksettings =3D phy_ethtool_get_link_ksettings, + .set_link_ksettings =3D rtl8169_set_link_ksettings, + .get_ringparam =3D rtl8169_get_ringparam, + .get_pause_stats =3D rtl8169_get_pause_stats, + .get_pauseparam =3D rtl8169_get_pauseparam, + .set_pauseparam =3D rtl8169_set_pauseparam, + .get_eth_mac_stats =3D rtl8169_get_eth_mac_stats, + .get_eth_ctrl_stats =3D rtl8169_get_eth_ctrl_stats, +}; + static int rtl_init_one(struct pci_dev *pdev, const struct pci_device_id *= ent) { const struct rtl_chip_info *chip; --=20 2.43.0 From nobody Sat Jun 13 17:32:58 2026 Received: from rtits2.realtek.com.tw (rtits2.realtek.com [211.75.126.72]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 4D6EE3E3158; Wed, 6 May 2026 08:14:04 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=211.75.126.72 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1778055251; cv=none; b=OJTD4/TNRJaahd+lC6JwXxfW+6uJW+NGLgCDGxbmlVFji3b6UHKam4as64qMwAhJToBoWBSGFy7NmoWSd3OfHLNE8QYJgneFIIix25htJ7MnAoCuATWilFOdPhjm75iO0CzIg5t64W+FllnJdVHUYv7EGzhyZA0HnwjnRHJPnHA= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1778055251; c=relaxed/simple; bh=bLoKsnLciGf9Qf8WZSR0Ek3RPaiss67zloQ4Cq79gtE=; h=From:To:CC:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=AuUFj/SCqkRUmJj4gnKUMhFQ0bOuM6W095TKI+W+6JFd3+u8Euhp/dFrDEEwR37rsUh4KSGHr9MEZifhZl8jDO4wzlw7rLD4kIzD+mY1/fb5lgwb1HRmPU24PKzi21vvkboIL5p43M9l1+pyTBOzS4dQXf4IKZC9qE1pQUfMmG8= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=realsil.com.cn; spf=pass smtp.mailfrom=realsil.com.cn; dkim=pass (2048-bit key) header.d=realsil.com.cn header.i=@realsil.com.cn header.b=fpwvx8/3; arc=none smtp.client-ip=211.75.126.72 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=realsil.com.cn Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=realsil.com.cn Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=realsil.com.cn header.i=@realsil.com.cn header.b="fpwvx8/3" X-SpamFilter-By: ArmorX SpamTrap 5.80 with qID 6468DVnqC1854043, This message is accepted by code: ctloc85258 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=realsil.com.cn; s=dkim; t=1778055211; bh=vQq78lfl+RoBaOJhx2UZk4CIZYEGBIk5kJXhHz2Gesg=; h=From:To:CC:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Transfer-Encoding:Content-Type; b=fpwvx8/39iB8h05t5LkplmMWl0Agb4FLr2eR3CgzRXwlRsFry4se2jhMy0yS7CWRN WXcW2XeoKr6fST5hCZlmv3Sue1syxkV5i0dbI2mNSz3YmLc7EYmW9jd6VPKcGyEX3O /I9GF+P+Wu0Z6KkCfXdY4Zp7uYT4C6cq+fSmhSf9edmg4fAFxFYFJ4vD21bU1wYd2q jmXgh6xRl9/XZetcyXmphxmh4pztNnzayg5k59crzcBehcEr1WcLPlyUDK5JZkZDMo rsWpYLUzUHGAtBz+0m2cj3oMupVDBTU6WrrxzejKz2fUOrSJCLF3kCtwuVPThjqnht vMr3KdDbN2GoQ== Received: from RS-EX-MBS2.realsil.com.cn ([172.29.17.102]) by rtits2.realtek.com.tw (8.15.2/3.27/5.94) with ESMTPS id 6468DVnqC1854043 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=FAIL); Wed, 6 May 2026 16:13:31 +0800 Received: from RS-EX-MBS2.realsil.com.cn (172.29.17.102) by RS-EX-MBS2.realsil.com.cn (172.29.17.102) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.2.2562.17; Wed, 6 May 2026 16:13:30 +0800 Received: from 172.29.37.154 (172.29.37.152) by RS-EX-MBS2.realsil.com.cn (172.29.17.102) with Microsoft SMTP Server id 15.2.2562.17 via Frontend Transport; Wed, 6 May 2026 16:13:30 +0800 From: javen To: , , , , , , , CC: , , Javen Xu Subject: [Patch net-next v1 7/7] r8169: add support for ethtool Date: Wed, 6 May 2026 16:13:25 +0800 Message-ID: <20260506081326.767-8-javen_xu@realsil.com.cn> X-Mailer: git-send-email 2.50.1.windows.1 In-Reply-To: <20260506081326.767-1-javen_xu@realsil.com.cn> References: <20260506081326.767-1-javen_xu@realsil.com.cn> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" From: Javen Xu This patch add support for changing rx queues by ethtool. We can set rx 1, 2, 4, 8 by ethtool -L eth1 rx num. Signed-off-by: Javen Xu --- drivers/net/ethernet/realtek/r8169_main.c | 133 ++++++++++++++++++++++ 1 file changed, 133 insertions(+) diff --git a/drivers/net/ethernet/realtek/r8169_main.c b/drivers/net/ethern= et/realtek/r8169_main.c index 6e682a5538d3..305c5eaf16f8 100644 --- a/drivers/net/ethernet/realtek/r8169_main.c +++ b/drivers/net/ethernet/realtek/r8169_main.c @@ -6372,6 +6372,137 @@ static void r8169_init_napi(struct rtl8169_private = *tp) } } =20 +static void rtl8169_get_channels(struct net_device *dev, + struct ethtool_channels *ch) +{ + struct rtl8169_private *tp =3D netdev_priv(dev); + + ch->max_rx =3D tp->hw_supp_num_rx_queues; + ch->max_tx =3D 1; + ch->max_other =3D 0; + ch->max_combined =3D 0; + + ch->rx_count =3D tp->num_rx_rings; + ch->tx_count =3D 1; + ch->other_count =3D 0; + ch->combined_count =3D 0; +} + +static int rtl8169_realloc_rx(struct rtl8169_private *tp, + struct rtl8169_rx_ring *new_rx, + int new_count) +{ + int i, ret; + + new_rx[0].rdsar_reg =3D RxDescAddrLow; + for (i =3D 1; i < new_count; i++) + new_rx[i].rdsar_reg =3D (u16)(RDSAR_Q1_LOW + (i - 1) * 8); + + for (i =3D 0; i < new_count; i++) + new_rx[i].num_rx_desc =3D NUM_RX_DESC; + + for (i =3D 0; i < new_count; i++) { + struct rtl8169_rx_ring *ring =3D &new_rx[i]; + + ring->rx_desc_alloc_size =3D (NUM_RX_DESC + 1) * sizeof(struct RxDesc); + ring->rx_desc_array =3D dma_alloc_coherent(&tp->pci_dev->dev, + ring->rx_desc_alloc_size, + &ring->rx_phy_addr, + GFP_KERNEL); + if (!ring->rx_desc_array) { + ret =3D -ENOMEM; + goto err_free; + } + + memset(ring->rx_databuff, 0, sizeof(ring->rx_databuff)); + ret =3D rtl8169_rx_fill(tp, ring); + if (ret) { + dma_free_coherent(&tp->pci_dev->dev, ring->rx_desc_alloc_size, + ring->rx_desc_array, ring->rx_phy_addr); + goto err_free; + } + } + return 0; + +err_free: + while (--i >=3D 0) { + rtl8169_rx_clear(tp, &new_rx[i]); + dma_free_coherent(&tp->pci_dev->dev, new_rx[i].rx_desc_alloc_size, + new_rx[i].rx_desc_array, new_rx[i].rx_phy_addr); + } + return ret; +} + +static int rtl8169_set_channels(struct net_device *dev, + struct ethtool_channels *ch) +{ + struct rtl8169_private *tp =3D netdev_priv(dev); + bool if_running =3D netif_running(dev); + struct rtl8169_rx_ring *new_rx; + u8 old_tx_desc_type =3D tp->init_rx_desc_type; + u8 new_desc_type; + bool new_rss_enable; + int i, ret; + + if (!tp->rss_support && (ch->rx_count > 1 || ch->tx_count > 1)) { + netdev_warn(dev, "This chip does not support multiple channels/RSS.\n"); + return -EOPNOTSUPP; + } + + if (!(tp->features & RTL_VEC_MAP_ENABLE)) + return -EINVAL; + + new_rss_enable =3D (ch->rx_count > 1 && tp->rss_support); + new_desc_type =3D new_rss_enable ? RX_DESC_RING_TYPE_RSS : RX_DESC_RING_T= YPE_DEFAULT; + tp->init_rx_desc_type =3D new_desc_type; + + if (!if_running) { + tp->num_rx_rings =3D ch->rx_count; + tp->rss_enable =3D new_rss_enable; + return 0; + } + + new_rx =3D kcalloc(R8169_MAX_RX_QUEUES, sizeof(*new_rx), GFP_KERNEL); + if (!new_rx) + return -ENOMEM; + + ret =3D rtl8169_realloc_rx(tp, new_rx, ch->rx_count); + if (ret) { + kfree(new_rx); + tp->init_rx_desc_type =3D old_tx_desc_type; + return ret; + } + + netif_stop_queue(dev); + rtl8169_down(tp); + + for (i =3D 0; i < tp->num_rx_rings; i++) + rtl8169_rx_clear(tp, &tp->rx_ring[i]); + rtl8169_free_rx_desc(tp); + + tp->num_rx_rings =3D ch->rx_count; + tp->rss_enable =3D new_rss_enable; + + memset(tp->rx_ring, 0, sizeof(tp->rx_ring)); + memcpy(tp->rx_ring, new_rx, sizeof(*new_rx) * ch->rx_count); + + for (i =3D 0; i < tp->hw_supp_indir_tbl_entries; i++) { + if (tp->rss_enable) + tp->rss_indir_tbl[i] =3D ethtool_rxfh_indir_default(i, tp->num_rx_rings= ); + else + tp->rss_indir_tbl[i] =3D 0; + } + + rtl_set_irq_mask(tp); + + rtl8169_up(tp); + netif_start_queue(dev); + + kfree(new_rx); + + return 0; +} + static const struct ethtool_ops rtl8169_ethtool_ops =3D { .supported_coalesce_params =3D ETHTOOL_COALESCE_USECS | ETHTOOL_COALESCE_MAX_FRAMES, @@ -6390,6 +6521,8 @@ static const struct ethtool_ops rtl8169_ethtool_ops = =3D { .nway_reset =3D phy_ethtool_nway_reset, .get_eee =3D rtl8169_get_eee, .set_eee =3D rtl8169_set_eee, + .get_channels =3D rtl8169_get_channels, + .set_channels =3D rtl8169_set_channels, .get_link_ksettings =3D phy_ethtool_get_link_ksettings, .set_link_ksettings =3D rtl8169_set_link_ksettings, .get_ringparam =3D rtl8169_get_ringparam, --=20 2.43.0