From nobody Mon Jun 8 22:01:57 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 538CB3911A8; Tue, 26 May 2026 08:11:56 +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=1779783118; cv=none; b=DxRTnaStIlppoQXUCzMusUspKKPfWjZYAbqARSD6RDYrIF4gV/WhLYGDRZY5gOWJaQRHQeuKw4s8+Qne1W86D8cH33jmiwrrtiC7SfblDYPA+hnWTOdrfjcNzAb+ADW04cvvvSZFRE9+kJZmoXOr/afc8A0pxRAEKokwW/UhGVg= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1779783118; c=relaxed/simple; bh=C247nFkcc53kKShf0zqLEKQlSuS4XJj5zMcWwKJPdXA=; h=From:To:CC:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=IWGZySISiEQ4gfT3G3aI1fONMo6d3fmNXrzpLQyKOYJHfyrGU5BGDwULVnD2B5+0XTxc4zlggPdv+6cR102xrEye34wa4wVtyjdLw0q6SmSD6jx7VUGngFBp+AcGqhGPBs74DQtaxjyosN/VwdrPpdW1IshdJWbNhTbCb7D6GyI= 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=hqX16E4D; 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="hqX16E4D" X-SpamFilter-By: ArmorX SpamTrap 5.80 with qID 64Q8BKl741615336, This message is accepted by code: ctloc85258 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=realsil.com.cn; s=dkim; t=1779783081; bh=m25k9OXhAVjiX6CcGLbl6v6l97TFZY3gqWibdEnO/zE=; h=From:To:CC:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Transfer-Encoding:Content-Type; b=hqX16E4Dbsr4IW/63IJKID9BO69yTcQs9XMft/BMO6BuNq39U0xrcHaE7xbNrST8q uqnH2VWuOwRhSYKpgNyclLfWvFtAF2EiqERQfFRbB8VR9bkG34iS5DsZeob8U6j3AJ NOhLXj+HOuAV8diWcg4kwBYbThDDjPM9X5p2NAnVc3ATIg9Nn8UAz6M9aCNJI2D2fN OrQ3wlrl8tqd81f7mwRRbn7m0RJz8u97A/RqWEpgdhjcLUHOyfyVZCnOiLqkGsB/2D kRjDbqk3i1QtRIAlYd+iIMACNvK+psT+768EfzP29cXFAnIt46RODWN3jrGgocRu9W rC/MSlyxAi6Xg== Received: from RS-EX-MBS4.realsil.com.cn ([172.29.17.104]) by rtits2.realtek.com.tw (8.15.2/3.28/5.94) with ESMTPS id 64Q8BKl741615336 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=FAIL); Tue, 26 May 2026 16:11:21 +0800 Received: from RS-EX-MBS1.realsil.com.cn (172.29.17.101) by RS-EX-MBS4.realsil.com.cn (172.29.17.104) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.2.2562.17; Tue, 26 May 2026 16:11:19 +0800 Received: from 172.29.37.154 (172.29.37.152) by RS-EX-MBS1.realsil.com.cn (172.29.17.101) with Microsoft SMTP Server id 15.2.2562.17 via Frontend Transport; Tue, 26 May 2026 16:11:19 +0800 From: javen To: , , , , , , , CC: , , Javen Xu Subject: [Patch net-next v6 1/7] r8169: add support for multi irqs Date: Tue, 26 May 2026 16:11:11 +0800 Message-ID: <20260526081117.173-2-javen_xu@realsil.com.cn> X-Mailer: git-send-email 2.50.1.windows.1 In-Reply-To: <20260526081117.173-1-javen_xu@realsil.com.cn> References: <20260526081117.173-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 --- Changes in v2: - remove some unused definitions, such as index, name in rtl8169_irq - remove array imr and isr - remove min_irq_nvecs and max_irq_nvecs, replaced with help function get_min_irq_nvecs and get_max_irq_nvecs - alloc irq by flags, instead of PCI_IRQ_ALL_TYPES Changes in v3: - add enum rtl_isr_version to replace macro definition - remove struct rtl8169_napi, use napi_struct array instead and alloc memory for this array dynamically - remove struct rtl8169_irq Changes in v4: - change retval to ret in rtl8169_set_real_num_queue() - reverse xmas tree in rtl8169_poll() and rtl8169_interrupt() - remove tp->hw_supp_isr_ver Changes in v5: - rtl8169_request_irq(), when failed, only free irqs which are allocated - remove rss_support, simplied napi init, call r8169_init_napi() directly - remove rtl_isr_version, INTR_VEC_MAP_MASK, INTR_VEC_MAP_STATUS, R8169_MAX_MSIX_VEC, rss_enable, recheck_desc_ownbit - rtl_software_parameter_initialize() this function will be expanded in next patch, so i want to remain it here. Changes in v6: - Fix netpoll crash - Fix use-after-free during driver unload by registering a devm action for netif_napi_del() - remove tp->irq --- drivers/net/ethernet/realtek/r8169_main.c | 144 ++++++++++++++++++---- 1 file changed, 120 insertions(+), 24 deletions(-) diff --git a/drivers/net/ethernet/realtek/r8169_main.c b/drivers/net/ethern= et/realtek/r8169_main.c index ec4fc21fa21f..22e843baffc7 100644 --- a/drivers/net/ethernet/realtek/r8169_main.c +++ b/drivers/net/ethernet/realtek/r8169_main.c @@ -733,7 +733,6 @@ struct rtl8169_private { struct pci_dev *pci_dev; struct net_device *dev; struct phy_device *phydev; - 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. */ @@ -745,10 +744,12 @@ 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 napi_struct *rtl8169_napi; + unsigned int num_rx_rings; u16 cp_cmd; u16 tx_lpi_timer; u32 irq_mask; - int irq; + unsigned int irq_nvecs; struct clk *clk; =20 struct { @@ -2680,6 +2681,11 @@ static void rtl_hw_reset(struct rtl8169_private *tp) rtl_loop_wait_low(tp, &rtl_chipcmd_cond, 100, 100); } =20 +static void rtl_software_parameter_initialize(struct rtl8169_private *tp) +{ + tp->num_rx_rings =3D 1; +} + static void rtl_request_firmware(struct rtl8169_private *tp) { struct rtl_fw *rtl_fw; @@ -4266,9 +4272,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->rtl8169_napi[i]); +} + +static void rtl8169_napi_enable(struct rtl8169_private *tp) +{ + for (int i =3D 0; i < tp->irq_nvecs; i++) + napi_enable(&tp->rtl8169_napi[i]); +} + 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(); @@ -4314,7 +4332,7 @@ static void rtl_reset_work(struct rtl8169_private *tp) for (i =3D 0; i < NUM_RX_DESC; i++) rtl8169_mark_to_asic(tp->RxDescArray + i); =20 - napi_enable(&tp->napi); + rtl8169_napi_enable(tp); rtl_hw_start(tp); } =20 @@ -4820,7 +4838,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->rtl8169_napi[0], pkt_size); if (unlikely(!skb)) { dev->stats.rx_dropped++; goto release_descriptor; @@ -4844,7 +4862,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->rtl8169_napi[0], skb); =20 dev_sw_netstats_rx_add(dev, pkt_size); release_descriptor: @@ -4856,8 +4874,12 @@ static int rtl_rx(struct net_device *dev, struct rtl= 8169_private *tp, int budget =20 static irqreturn_t rtl8169_interrupt(int irq, void *dev_instance) { - struct rtl8169_private *tp =3D dev_instance; - u32 status =3D rtl_get_events(tp); + struct napi_struct *napi =3D dev_instance; + struct rtl8169_private *tp; + u32 status; + + tp =3D netdev_priv(napi->dev); + status =3D rtl_get_events(tp); =20 if ((status & 0xffff) =3D=3D 0xffff || !(status & tp->irq_mask)) return IRQ_NONE; @@ -4873,13 +4895,43 @@ 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); 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 napi_struct *napi =3D &tp->rtl8169_napi[i]; + + pci_free_irq(tp->pci_dev, i, napi); + } +} + +static int rtl8169_request_irq(struct rtl8169_private *tp) +{ + struct net_device *dev =3D tp->dev; + struct napi_struct *napi; + int i, rc; + + for (i =3D 0; i < tp->irq_nvecs; i++) { + napi =3D &tp->rtl8169_napi[i]; + rc =3D pci_request_irq(tp->pci_dev, i, rtl8169_interrupt, + NULL, napi, "%s-%d", dev->name, i); + if (rc) + goto free_irq; + } + return 0; + +free_irq: + while (--i >=3D 0) + pci_free_irq(tp->pci_dev, i, &tp->rtl8169_napi[i]); + return rc; +} + static void rtl_task(struct work_struct *work) { struct rtl8169_private *tp =3D @@ -4914,9 +4966,9 @@ 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 net_device *dev =3D tp->dev; - int work_done; + struct rtl8169_private *tp =3D netdev_priv(napi->dev); + struct net_device *dev =3D napi->dev; + int work_done =3D 0; =20 rtl_tx(dev, tp, budget); =20 @@ -5035,7 +5087,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 +5105,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 @@ -5074,7 +5126,7 @@ static void rtl8169_netpoll(struct net_device *dev) { struct rtl8169_private *tp =3D netdev_priv(dev); =20 - rtl8169_interrupt(tp->irq, tp); + rtl8169_interrupt(pci_irq_vector(tp->pci_dev, 0), &tp->rtl8169_napi[0]); } #endif =20 @@ -5082,7 +5134,6 @@ static int rtl_open(struct net_device *dev) { struct rtl8169_private *tp =3D netdev_priv(dev); struct pci_dev *pdev =3D tp->pci_dev; - unsigned long irqflags; int retval =3D -ENOMEM; =20 pm_runtime_get_sync(&pdev->dev); @@ -5107,8 +5158,7 @@ static int rtl_open(struct net_device *dev) =20 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 +5175,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 +5378,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 +5396,14 @@ 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, 1, 1, flags); + + if (nvecs < 0) + return nvecs; + + tp->irq_nvecs =3D nvecs; + + return 0; } =20 static void rtl_read_mac_address(struct rtl8169_private *tp, @@ -5539,6 +5598,17 @@ static void rtl_hw_initialize(struct rtl8169_private= *tp) } } =20 +static int rtl8169_set_real_num_queues(struct rtl8169_private *tp) +{ + int ret; + + ret =3D netif_set_real_num_tx_queues(tp->dev, 1); + if (ret < 0) + return ret; + + 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 +5669,22 @@ static bool rtl_aspm_is_safe(struct rtl8169_private = *tp) return false; } =20 +static void r8169_del_napi_action(void *data) +{ + struct rtl8169_private *tp =3D data; + int i; + + for (i =3D 0; i < tp->irq_nvecs; i++) + netif_napi_del(&tp->rtl8169_napi[i]); +} + +static void r8169_init_napi(struct rtl8169_private *tp) +{ + for (int i =3D 0; i < tp->irq_nvecs; i++) + netif_napi_add(tp->dev, &tp->rtl8169_napi[i], rtl8169_poll); + devm_add_action_or_reset(&tp->pci_dev->dev, r8169_del_napi_action, tp); +} + static int rtl_init_one(struct pci_dev *pdev, const struct pci_device_id *= ent) { const struct rtl_chip_info *chip; @@ -5703,11 +5789,16 @@ 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); + tp->rtl8169_napi =3D devm_kcalloc(&pdev->dev, tp->irq_nvecs, + sizeof(struct napi_struct), GFP_KERNEL); + if (!tp->rtl8169_napi) + return -ENOMEM; =20 INIT_WORK(&tp->wk.work, rtl_task); disable_work(&tp->wk.work); @@ -5716,7 +5807,7 @@ static int rtl_init_one(struct pci_dev *pdev, const s= truct pci_device_id *ent) =20 dev->ethtool_ops =3D &rtl8169_ethtool_ops; =20 - netif_napi_add(dev, &tp->napi, rtl8169_poll); + 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 +5869,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_queues(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), @@ -5803,8 +5898,9 @@ static int rtl_init_one(struct pci_dev *pdev, const s= truct pci_device_id *ent) tp->leds =3D rtl8168_init_leds(dev); } =20 - netdev_info(dev, "%s, %pM, %sXID %x, IRQ %d\n", - chip->name, dev->dev_addr, ext_xid_str, xid, tp->irq); + netdev_info(dev, "%s, %pM, %sXID %x, IRQ %d (%d total)\n", + chip->name, dev->dev_addr, ext_xid_str, xid, + pci_irq_vector(pdev, 0), tp->irq_nvecs); =20 if (jumbo_max) netdev_info(dev, "jumbo features [frames: %d bytes, tx checksumming: %s]= \n", --=20 2.43.0 From nobody Mon Jun 8 22:01:57 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 53B5D3B9949; Tue, 26 May 2026 08:11:55 +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=1779783119; cv=none; b=OXP1Kf+aSFVPmMY7PzWEQzoc5wuemB8qfvJzAfdZLgdHLFHRk3ehsVXaZVsbL2D1B/bxd7HFlAtnvJ08W51M1ZNusV65pdB9P3wrAPC0CHcMqqZW39zunxjlUwurZxocen/Dj/A1FdiNi+1sA8NR5b2m3aN+i8tHWyT6OpM3aMU= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1779783119; c=relaxed/simple; bh=HrszNPvzN+OnMQuEBbSZUZ7IqGbIWjQJMXKnI2C9P1I=; h=From:To:CC:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=NeWJcXZyh45EdYeeZAIdzSjS+MSKL/GEG8Jop1jIoDMkhk1xF5M8ygo2dXU0ho4gopCYLzRCEMjCV41yS7TTMxGseAJfwiBceK78ynqnxzSMAG5wu62YC0ibquTjK4QDMHpqkUTmjc8Je/sTEZwz25/vLjwRSwXduyfmIJ0Kr3I= 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=qYuPOIFS; 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="qYuPOIFS" X-SpamFilter-By: ArmorX SpamTrap 5.80 with qID 64Q8BLl641615336, This message is accepted by code: ctloc85258 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=realsil.com.cn; s=dkim; t=1779783081; bh=WGHPDOOWfdOT36kZ3ecbdZ5qcasp5BJUPtiTYcBLzBo=; h=From:To:CC:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Transfer-Encoding:Content-Type; b=qYuPOIFSipOHkGpX47NDohbE00Nmr4EPgC3kprxXvYwhIlrj0tWq4Q3gj6+l3ZlsT LWa0kBfgSSceske/ntFrjiGW2sA4WtwyEiKeZpbI3tmMXqKWnqtI5PQsrmTWfRFWLP KqUDjZizxPJtBznh7DpR2+HjRVDar/mINSGF7BL5lNFLgzwA6QzZjsaZAjSJGC4a0Y CcvbsTcJI2VRJa+xRZhXtAl/Dl54icQ244S8lJpKZEvs2/ueQMhAkVAapJDT7Sbsbl XoInQ3hmQyk/FAu1kH+eP8PpJa4l9dar6MXiQJ8m2/PSkXT5EZxkcptMoxN/3AKjM9 34QPxV9oVGDTQ== Received: from RS-EX-MBS4.realsil.com.cn ([172.29.17.104]) by rtits2.realtek.com.tw (8.15.2/3.28/5.94) with ESMTPS id 64Q8BLl641615336 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=FAIL); Tue, 26 May 2026 16:11:21 +0800 Received: from RS-EX-MBS1.realsil.com.cn (172.29.17.101) by RS-EX-MBS4.realsil.com.cn (172.29.17.104) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.2.2562.17; Tue, 26 May 2026 16:11:20 +0800 Received: from 172.29.37.154 (172.29.37.152) by RS-EX-MBS1.realsil.com.cn (172.29.17.101) with Microsoft SMTP Server id 15.2.2562.17 via Frontend Transport; Tue, 26 May 2026 16:11:20 +0800 From: javen To: , , , , , , , CC: , , Javen Xu Subject: [Patch net-next v6 2/7] r8169: add support for multi rx queues Date: Tue, 26 May 2026 16:11:12 +0800 Message-ID: <20260526081117.173-3-javen_xu@realsil.com.cn> X-Mailer: git-send-email 2.50.1.windows.1 In-Reply-To: <20260526081117.173-1-javen_xu@realsil.com.cn> References: <20260526081117.173-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 --- Changes in v2: - sort some registers by its number - remove some unused definitions, like RX_DESC_RING_TYPE_MAX - change recheck_desc_ownbit type - remove rdsar_reg in rx_ring struct - opts1 are different in rx_desc and rx_desc_rss, move the judgement to Patch 5/7 Changes in v3: - remove ring->rx_desc_alloc_size, use constant instead Changes in v4: - change rdsar_reg type to unsigned int - follow reverse xmas tree, in rtl_set_rx_tx_desc_registers(), rtl8169_alloc_rx_data(), rtl8169_alloc_rx_desc(), rtl8169_free_rx_desc() - add comments on LED_CTRL, remove helper function Changes in v5: - modify rtl8169_init_ring(), do rx clear when failed - add definition R8169_MAX_TX_QUEUES 1 Changes in v6: - Restore the secondary Rx error filter when NETIF_F_RXFALL is enabled in rtl_rx() --- drivers/net/ethernet/realtek/r8169_main.c | 272 +++++++++++++++++----- 1 file changed, 211 insertions(+), 61 deletions(-) diff --git a/drivers/net/ethernet/realtek/r8169_main.c b/drivers/net/ethern= et/realtek/r8169_main.c index 22e843baffc7..62bf77aa1ec8 100644 --- a/drivers/net/ethernet/realtek/r8169_main.c +++ b/drivers/net/ethernet/realtek/r8169_main.c @@ -74,9 +74,13 @@ #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_RX_RING_BYTES ((NUM_RX_DESC + 1) * 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 R8127_MAX_RX_QUEUES 8 +#define R8169_DEFAULT_RX_QUEUES 1 +#define R8169_MAX_TX_QUEUES 1 =20 #define OCP_STD_PHY_BASE 0xa400 =20 @@ -441,6 +445,7 @@ enum rtl8125_registers { TxPoll_8125 =3D 0x90, LEDSEL3 =3D 0x96, MAC0_BKP =3D 0x19e0, + RDSAR_Q1_LOW =3D 0x4000, RSS_CTRL_8125 =3D 0x4500, Q_NUM_CTRL_8125 =3D 0x4800, EEE_TXIDLE_TIMER_8125 =3D 0x6048, @@ -728,6 +733,21 @@ enum rtl_dash_type { RTL_DASH_25_BP, }; =20 +enum rx_desc_ring_type { + RX_DESC_RING_TYPE_DEFAULT, + RX_DESC_RING_TYPE_RSS, +}; + +struct rtl8169_rx_ring { + u32 index; /* Rx queue index */ + u32 cur_rx; /* Index of next Rx pkt. */ + u32 dirty_rx; /* Index for recycling. */ + struct RxDesc *rx_desc_array; /* array of Rx Desc*/ + 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 */ +}; + struct rtl8169_private { void __iomem *mmio_addr; /* memory map physical address */ struct pci_dev *pci_dev; @@ -735,20 +755,18 @@ struct rtl8169_private { struct phy_device *phydev; 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 napi_struct *rtl8169_napi; + struct rtl8169_rx_ring rx_ring[R8169_MAX_RX_QUEUES]; unsigned int num_rx_rings; u16 cp_cmd; u16 tx_lpi_timer; u32 irq_mask; + unsigned int hw_supp_num_rx_queues; unsigned int irq_nvecs; struct clk *clk; =20 @@ -764,6 +782,7 @@ struct rtl8169_private { unsigned aspm_manageable:1; unsigned dash_enabled:1; bool sfp_mode:1; + bool recheck_desc_ownbit:1; dma_addr_t counters_phys_addr; struct rtl8169_counters *counters; struct rtl8169_tc_offsets tc_offset; @@ -2620,9 +2639,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, R8169_RX_RING_BYTES); + } +} + 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) @@ -2684,6 +2721,14 @@ static void rtl_hw_reset(struct rtl8169_private *tp) 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->hw_supp_num_rx_queues =3D R8127_MAX_RX_QUEUES; + break; + default: + tp->hw_supp_num_rx_queues =3D R8169_DEFAULT_RX_QUEUES; + break; + } } =20 static void rtl_request_firmware(struct rtl8169_private *tp) @@ -2810,6 +2855,8 @@ static void rtl_set_rx_max_size(struct rtl8169_privat= e *tp) =20 static void rtl_set_rx_tx_desc_registers(struct rtl8169_private *tp) { + struct rtl8169_rx_ring *ring =3D &tp->rx_ring[0]; + /* * Magic spell: some iop3xx ARM board needs the TxDescAddrHigh * register to be written before TxDescAddrLow to work. @@ -2817,8 +2864,16 @@ 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)); + RTL_W32(tp, RxDescAddrHigh, ((u64) ring->rx_phy_addr) >> 32); + RTL_W32(tp, RxDescAddrLow, ((u64) ring->rx_phy_addr) & DMA_BIT_MASK(32)); + + for (int i =3D 1; i < tp->num_rx_rings; i++) { + unsigned int rdsar_reg =3D RDSAR_Q1_LOW + (i - 1) * 8; + struct rtl8169_rx_ring *ring =3D &tp->rx_ring[i]; + + RTL_W32(tp, rdsar_reg + 4, ((u64)ring->rx_phy_addr >> 32)); + RTL_W32(tp, rdsar_reg, ((u64)ring->rx_phy_addr) & DMA_BIT_MASK(32)); + } } =20 static void rtl8169_set_magic_reg(struct rtl8169_private *tp) @@ -4165,8 +4220,9 @@ static void rtl8169_mark_to_asic(struct RxDesc *desc) } =20 static struct page *rtl8169_alloc_rx_data(struct rtl8169_private *tp, - struct RxDesc *desc) + struct rtl8169_rx_ring *ring, unsigned int index) { + struct RxDesc *desc =3D ring->rx_desc_array + index; struct device *d =3D tp_to_dev(tp); int node =3D dev_to_node(d); dma_addr_t mapping; @@ -4184,55 +4240,106 @@ static struct page *rtl8169_alloc_rx_data(struct r= tl8169_private *tp, } =20 desc->addr =3D cpu_to_le64(mapping); + ring->rx_desc_phy_addr[index] =3D mapping; rtl8169_mark_to_asic(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 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); + ring->rx_desc_array[NUM_RX_DESC - 1].opts1 |=3D cpu_to_le32(RingEnd); =20 return 0; } =20 +static int rtl8169_alloc_rx_desc(struct rtl8169_private *tp) +{ + struct pci_dev *pdev =3D tp->pci_dev; + struct rtl8169_rx_ring *ring; + + for (int i =3D 0; i < tp->num_rx_rings; i++) { + ring =3D &tp->rx_ring[i]; + ring->rx_desc_array =3D dma_alloc_coherent(&pdev->dev, + R8169_RX_RING_BYTES, + &ring->rx_phy_addr, + GFP_KERNEL); + if (!ring->rx_desc_array) + return -ENOMEM; + } + return 0; +} + +static void rtl8169_free_rx_desc(struct rtl8169_private *tp) +{ + struct pci_dev *pdev =3D tp->pci_dev; + struct rtl8169_rx_ring *ring; + + 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, + R8169_RX_RING_BYTES, + ring->rx_desc_array, + ring->rx_phy_addr); + ring->rx_desc_array =3D NULL; + } + } +} + static int rtl8169_init_ring(struct rtl8169_private *tp) { + int i, ret; + 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 (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)); + ret =3D rtl8169_rx_fill(tp, ring); + if (ret < 0) + goto err_clear; + } + return 0; + +err_clear: + while (--i >=3D 0) + rtl8169_rx_clear(tp, &tp->rx_ring[i]); + return ret; } =20 static void rtl8169_unmap_tx_skb(struct rtl8169_private *tp, unsigned int = entry) @@ -4321,16 +4428,23 @@ 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 < NUM_RX_DESC; j++) + rtl8169_mark_to_asic(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); =20 rtl8169_napi_enable(tp); rtl_hw_start(tp); @@ -4776,9 +4890,10 @@ 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(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; @@ -4786,22 +4901,60 @@ 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 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 void rtl8169_set_desc_dma_addr(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 % 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; + + if (status & DescOwn) { + if (!tp->recheck_desc_ownbit) + break; + + /* Workaround for a hardware issue: + * A dummy read to any register forces a PCIe flush. We + * choose LED_CTRL here simply because reading it has no + * side effects. This ensures the descriptor ownbit is + * fully updated in RAM before we recheck it, preventing + * from missing RX packets right before exiting NAPI + * polling loop. + */ + tp->recheck_desc_ownbit =3D false; + RTL_R8(tp, LED_CTRL); + status =3D le32_to_cpu(READ_ONCE(desc->opts1)); + if (status & DescOwn) + break; + } =20 /* This barrier is needed to keep us from reading * any other fields out of the Rx descriptor until @@ -4809,15 +4962,11 @@ 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; @@ -4838,14 +4987,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->rtl8169_napi[0], pkt_size); + skb =3D napi_alloc_skb(&tp->rtl8169_napi[ring->index], 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); @@ -4854,7 +5003,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(skb, desc); skb->protocol =3D eth_type_trans(skb, dev); =20 rtl8169_rx_vlan_tag(desc, skb); @@ -4862,10 +5011,11 @@ 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->rtl8169_napi[0], skb); + napi_gro_receive(&tp->rtl8169_napi[ring->index], skb); =20 dev_sw_netstats_rx_add(dev, pkt_size); release_descriptor: + rtl8169_set_desc_dma_addr(desc, ring->rx_desc_phy_addr[entry]); rtl8169_mark_to_asic(desc); } =20 @@ -4895,6 +5045,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); out: rtl_ack_events(tp, status); @@ -4972,7 +5123,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); @@ -5100,21 +5252,19 @@ 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 @@ -5145,13 +5295,11 @@ static int rtl_open(struct net_device *dev) 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; @@ -5178,11 +5326,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); @@ -5695,7 +5842,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), + R8169_MAX_TX_QUEUES, + R8169_MAX_RX_QUEUES); + if (!dev) return -ENOMEM; =20 --=20 2.43.0 From nobody Mon Jun 8 22:01:57 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 53AD53B6C15; Tue, 26 May 2026 08:11:56 +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=1779783118; cv=none; b=iD4P67BFdA8SF5lm2WC4yq30vhiCmEbUqGRI55vK/MkS2PRl0uwzw0vev1TB3viy07kS52KBCENByUeoLR0A+OHLTICm9luujFSPRlJXqSniiooo1nSez2XPNcR5abAWuzPMNZeWAXtbkBTzqTzITu0M7/kRQQZ+lZPNJrYQwOk= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1779783118; c=relaxed/simple; bh=4358bVdU2NaaCgzn27czEpWWclPRKub78+cZt6mmOqo=; h=From:To:CC:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=qCZqhmIQtaIHb219LDrc3Fdg4GxfzahTxJot5zYLHQisYCG0VloGY4TYAzdzTuGVjpe3N1k/ojQh0H2S1VJajXvdFGethTaldZO4D51I271Z2vBcEc21o2+oxzFrFi+4RQstzKjOdDM4oh+TFrHDRvZ7qiNWL9X2XzwDUHmHJVE= 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=ASrhA1Jq; 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="ASrhA1Jq" X-SpamFilter-By: ArmorX SpamTrap 5.80 with qID 64Q8BLl741615336, This message is accepted by code: ctloc85258 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=realsil.com.cn; s=dkim; t=1779783081; bh=zpnZrDYd9eT435QapNavxSMfzoYz0f6vK1GkpsqNFDI=; h=From:To:CC:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Transfer-Encoding:Content-Type; b=ASrhA1JqWi33WQGt0y7KX2ClbMDXhNnlWCrwXqi1gjieLltfz/qY6JyFUVhosYEQh 9q2+FkVGrAaTL93BsFE6PSjuEh3paZGMObFTByv5UqQar6ANa3FDvdF24fyaHcCfq7 1EalTbaDzsIUnU0MyLLCg6vzR0q015+KIJTsMwqvpV/ku9HX+5pNdWkp8baE2N+2st +m3iFvQ8GANWoZL2O2AaJfNb+kc0Qcp55F520c3Uoqf5bDfI8Dl3dWxZddzvC5CxIq epED4xjmdIKMkYhs5COMzztKvxpN5bwT78QNaxq3k3d5b2pZwrKPpi6OdcICQxI1x6 2mV1gRzN6vguw== Received: from RS-EX-MBS4.realsil.com.cn ([172.29.17.104]) by rtits2.realtek.com.tw (8.15.2/3.28/5.94) with ESMTPS id 64Q8BLl741615336 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=FAIL); Tue, 26 May 2026 16:11:21 +0800 Received: from RS-EX-MBS1.realsil.com.cn (172.29.17.101) by RS-EX-MBS4.realsil.com.cn (172.29.17.104) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.2.2562.17; Tue, 26 May 2026 16:11:20 +0800 Received: from 172.29.37.154 (172.29.37.152) by RS-EX-MBS1.realsil.com.cn (172.29.17.101) with Microsoft SMTP Server id 15.2.2562.17 via Frontend Transport; Tue, 26 May 2026 16:11:20 +0800 From: javen To: , , , , , , , CC: , , Javen Xu Subject: [Patch net-next v6 3/7] r8169: add support for new interrupt mapping Date: Tue, 26 May 2026 16:11:13 +0800 Message-ID: <20260526081117.173-4-javen_xu@realsil.com.cn> X-Mailer: git-send-email 2.50.1.windows.1 In-Reply-To: <20260526081117.173-1-javen_xu@realsil.com.cn> References: <20260526081117.173-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 --- Changes in v2: - no changes Changes in v3: - init index in napi_struct and get message_id from index - move rtl8169_disable_hw_interrupt_msix directly before the call to napi_schedule() - change the condition in rtl8169_request_irq when RTL_VEC_MAP_ENABLE enabled, use rtl8169_interrupt_msix Changes in v4: - remove flag tp->feature, replace tp->features & RTL_VEC_MAP_ENABLE with tp->irq_nvecs > 1, they are equivalent. - follow reverse xmas tree, in rtl8169_interrupt_msix(), rtl8169_poll_msix_rx(), rtl8169_poll_msix_tx(), rtl8169_poll_msix_other() - use napi->index in rtl8169_poll_msix_other() - add a comment to describe RTL8127 MSI-X vector layout - simplify r8169_init_napi() Changes in v5: - replace magic number in rtl8169_poll_msix_tx() Changes in v6: - when irq_nvecs <=3D 1, use register IntrMask_8125, else using vec map - fix irq sequence in rtl8169_interrupt_msix(), disable interrupts before clean it - remove dead code in rtl8169_poll_msix_tx() --- drivers/net/ethernet/realtek/r8169_main.c | 166 +++++++++++++++++++--- 1 file changed, 150 insertions(+), 16 deletions(-) diff --git a/drivers/net/ethernet/realtek/r8169_main.c b/drivers/net/ethern= et/realtek/r8169_main.c index 62bf77aa1ec8..951d2046a81b 100644 --- a/drivers/net/ethernet/realtek/r8169_main.c +++ b/drivers/net/ethernet/realtek/r8169_main.c @@ -79,6 +79,7 @@ #define R8169_TX_START_THRS (2 * R8169_TX_STOP_THRS) #define R8169_MAX_RX_QUEUES 8 #define R8127_MAX_RX_QUEUES 8 +#define R8127_MAX_TX_QUEUES 8 #define R8169_DEFAULT_RX_QUEUES 1 #define R8169_MAX_TX_QUEUES 1 =20 @@ -449,8 +450,12 @@ enum rtl8125_registers { RSS_CTRL_8125 =3D 0x4500, Q_NUM_CTRL_8125 =3D 0x4800, EEE_TXIDLE_TIMER_8125 =3D 0x6048, + IMR_CLEAR_VEC_MAP_REG =3D 0x0d00, + ISR_VEC_MAP_REG =3D 0x0d04, + IMR_SET_VEC_MAP_REG =3D 0x0d0c, }; =20 +#define MSIX_ID_VEC_MAP_LINKCHG 29 #define LEDSEL_MASK_8125 0x23f =20 #define RX_VLAN_INNER_8125 BIT(22) @@ -581,6 +586,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 { @@ -1664,26 +1672,38 @@ 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)) - RTL_W32(tp, IntrStatus_8125, bits); - else + if (rtl_is_8125(tp)) { + if (tp->irq_nvecs > 1) + RTL_W32(tp, ISR_VEC_MAP_REG, bits); + else + RTL_W32(tp, IntrStatus_8125, bits); + } else { RTL_W16(tp, IntrStatus, bits); + } } =20 static void rtl_irq_disable(struct rtl8169_private *tp) { - if (rtl_is_8125(tp)) - RTL_W32(tp, IntrMask_8125, 0); - else + if (rtl_is_8125(tp)) { + if (tp->irq_nvecs > 1) + RTL_W32(tp, IMR_CLEAR_VEC_MAP_REG, 0xffffffff); + else + RTL_W32(tp, IntrMask_8125, 0); + } 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->irq_nvecs > 1) + 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) @@ -5062,6 +5082,45 @@ 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 napi_struct *napi =3D dev_instance; + struct net_device *dev =3D napi->dev; + int message_id =3D napi->index; + struct rtl8169_private *tp; + + tp =3D netdev_priv(dev); + + if (message_id =3D=3D MSIX_ID_VEC_MAP_LINKCHG) { + rtl8169_clear_hw_isr(tp, message_id); + phy_mac_interrupt(tp->phydev); + return IRQ_HANDLED; + } + + rtl8169_disable_hw_interrupt_msix(tp, message_id); + rtl8169_clear_hw_isr(tp, message_id); + + tp->recheck_desc_ownbit =3D true; + napi_schedule(napi); + + return IRQ_HANDLED; +} + static int rtl8169_request_irq(struct rtl8169_private *tp) { struct net_device *dev =3D tp->dev; @@ -5070,8 +5129,12 @@ static int rtl8169_request_irq(struct rtl8169_privat= e *tp) =20 for (i =3D 0; i < tp->irq_nvecs; i++) { napi =3D &tp->rtl8169_napi[i]; - rc =3D pci_request_irq(tp->pci_dev, i, rtl8169_interrupt, - NULL, napi, "%s-%d", dev->name, i); + if (tp->irq_nvecs > 1) + rc =3D pci_request_irq(tp->pci_dev, i, rtl8169_interrupt_msix, + NULL, napi, "%s-%d", dev->name, i); + else + rc =3D pci_request_irq(tp->pci_dev, i, rtl8169_interrupt, + NULL, napi, "%s-%d", dev->name, i); if (rc) goto free_irq; } @@ -5517,10 +5580,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->irq_nvecs > 1) { + 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) @@ -5825,10 +5894,75 @@ static void r8169_del_napi_action(void *data) netif_napi_del(&tp->rtl8169_napi[i]); } =20 +static int rtl8169_poll_msix_rx(struct napi_struct *napi, int budget) +{ + struct net_device *dev =3D napi->dev; + const int message_id =3D napi->index; + struct rtl8169_private *tp; + int work_done =3D 0; + + tp =3D netdev_priv(dev); + + 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 net_device *dev =3D napi->dev; + const int message_id =3D napi->index; + struct rtl8169_private *tp; + + tp =3D netdev_priv(dev); + + rtl_tx(dev, tp, budget); + + if (napi_complete_done(napi, 0)) + rtl8169_enable_hw_interrupt_msix(tp, message_id); + + return 0; +} + +static int rtl8169_poll_msix_other(struct napi_struct *napi, int budget) +{ + struct net_device *dev =3D napi->dev; + const int message_id =3D napi->index; + struct rtl8169_private *tp; + + tp =3D netdev_priv(dev); + + if (napi_complete_done(napi, 0)) + rtl8169_enable_hw_interrupt_msix(tp, message_id); + + return 0; +} + +/* RTL8127 MSI-X vector layout: + * Vectors 0 .. (RxQs - 1) : Rx Queues + * Vectors RxQs .. (RxQs + TxQs - 1) : Tx Queues + * Vector (RxQs + TxQs) and up : Other events (Link status(29), etc.) + */ static void r8169_init_napi(struct rtl8169_private *tp) { - for (int i =3D 0; i < tp->irq_nvecs; i++) - netif_napi_add(tp->dev, &tp->rtl8169_napi[i], rtl8169_poll); + for (int i =3D 0; i < tp->irq_nvecs; i++) { + int (*poll_fn)(struct napi_struct *, int) =3D rtl8169_poll; + + if (tp->irq_nvecs > 1) { + if (i < R8127_MAX_RX_QUEUES) + poll_fn =3D rtl8169_poll_msix_rx; + else if (i < R8127_MAX_RX_QUEUES + R8127_MAX_TX_QUEUES) + poll_fn =3D rtl8169_poll_msix_tx; + else + poll_fn =3D rtl8169_poll_msix_other; + } + netif_napi_add(tp->dev, &tp->rtl8169_napi[i], poll_fn); + tp->rtl8169_napi[i].index =3D i; + } devm_add_action_or_reset(&tp->pci_dev->dev, r8169_del_napi_action, tp); } =20 --=20 2.43.0 From nobody Mon Jun 8 22:01:57 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 5399C3B637E; Tue, 26 May 2026 08:11:55 +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=1779783118; cv=none; b=F0j6mftzRw8yAImD2SdocmtkKkTP/h7L/hGoC6BbfpgiGFfXXmmeiKfpxmCBbHjRe2mJF7f+rAv3BnhkYYYXfcCY2AZmjkAzc3MAoBdffufBsrsmkUoYe+kHhoOkFKE8RHlmxMbPqmYuPB5zsyO5O73We+TDRUPLF7DCpParERM= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1779783118; c=relaxed/simple; bh=iWb5eAXnxHkdFdqNN7VNdXABCfaHK30yLC14ehF9RNI=; h=From:To:CC:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=TS7HaMqaJC9qXYd6EzCWw0z6Mt951JTXTmt4iHCLIiPoSGD7CisocBjywdNrKaefVlGi61PmTHpJ+WerS9ikqcv8KeAeruS2PjiHk4Gz9Hc/oXJegtVxZo/z4zX30k9L/eAg2Ftcb1G3kNUkpqZa1iBpID5ojuT8/9O/goY+caA= 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=D9mFkdSI; 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="D9mFkdSI" X-SpamFilter-By: ArmorX SpamTrap 5.80 with qID 64Q8BLl841615336, This message is accepted by code: ctloc85258 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=realsil.com.cn; s=dkim; t=1779783082; bh=oYsAzz/U51SyaPg7DUTGOeOQ4Mt/8RK6/X37eHKrR3I=; h=From:To:CC:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Transfer-Encoding:Content-Type; b=D9mFkdSIF3kS6UTmP339I1VG5IxgNTI8+uGslYeD7SUf95cugdHuJeKooj47Bp4ge jCziUM1Be86976VQOP2GVxVkEP0NwyhG1Y0yQo6sGqb5AJtB1MZ2kaQumDB/XiRBlW mUR9tmhUTbaeuBWai8T2P/cTGzl5hVkWEI4FqmqKyHgrq0mUhSp7ioT//grm/NvVNp fltv9DitTEVr62K3PcdkPmU5/2EtJXNqJT+DwKJMB3M1kZgm7XDG5L3YlQL+2T1w3m wdZWcEYzCskVemH5PtDMsm4hZY7s6bPXoDNydtgHtCcgWAPSc3rre9sYAZ0cBEeiak 2w8/VCMj9TYtQ== Received: from RS-EX-MBS4.realsil.com.cn ([172.29.17.104]) by rtits2.realtek.com.tw (8.15.2/3.28/5.94) with ESMTPS id 64Q8BLl841615336 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=FAIL); Tue, 26 May 2026 16:11:21 +0800 Received: from RS-EX-MBS1.realsil.com.cn (172.29.17.101) by RS-EX-MBS4.realsil.com.cn (172.29.17.104) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.2.2562.17; Tue, 26 May 2026 16:11:20 +0800 Received: from 172.29.37.154 (172.29.37.152) by RS-EX-MBS1.realsil.com.cn (172.29.17.101) with Microsoft SMTP Server id 15.2.2562.17 via Frontend Transport; Tue, 26 May 2026 16:11:20 +0800 From: javen To: , , , , , , , CC: , , Javen Xu Subject: [Patch net-next v6 4/7] r8169: enable new interrupt mapping Date: Tue, 26 May 2026 16:11:14 +0800 Message-ID: <20260526081117.173-5-javen_xu@realsil.com.cn> X-Mailer: git-send-email 2.50.1.windows.1 In-Reply-To: <20260526081117.173-1-javen_xu@realsil.com.cn> References: <20260526081117.173-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 --- Changes in v2: - no changes Changes in v3: - no changes Changes in v4: - no changes Changes in v5: - no changes Changes in v6: - no changes --- 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 951d2046a81b..13d955324037 100644 --- a/drivers/net/ethernet/realtek/r8169_main.c +++ b/drivers/net/ethernet/realtek/r8169_main.c @@ -3939,6 +3939,15 @@ DECLARE_RTL_COND(rtl_mac_ocp_e00e_cond) return r8168_mac_ocp_read(tp, 0xe00e) & BIT(13); } =20 +static void rtl8169_hw_enable_vec_mapping(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); @@ -3947,6 +3956,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->irq_nvecs > 1) + rtl8169_hw_enable_vec_mapping(tp); + /* disable UPS */ r8168_mac_ocp_modify(tp, 0xd40a, 0x0010, 0x0000); =20 --=20 2.43.0 From nobody Mon Jun 8 22:01:57 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 53C513BB110; Tue, 26 May 2026 08:11:55 +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=1779783119; cv=none; b=Tj48s1uGIPdvCw6+gS6Bi17curSL3D+QILxZdnUWUW8og4neD3yzBlNKHZ5AHt6pY+GrzEvb6p36MPmQzrRJGoamH0OHXcSI6ZFPXJYnzy5Ow20dKMoeOBhsfsVUljB8JND2j31EaB+Yw72o4nF+ghWhHMacq/oZrSKqUWLLzK0= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1779783119; c=relaxed/simple; bh=NE3fXbnJfHPmJrOP5jvr1JarVJiQcfLy758m4ndrDFk=; h=From:To:CC:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=Bf5tXGdDnnL60ejPkcnB7GqLtF7xr4vd/uOYdVI2olmRP4QgwSJKMcOjUOY+4XQQcFZT6P8n5SlqECbhejXq6pHImRzalm28bWWh05c38cEEymE8lkzSzFnXGvT+spkA0CHNoeg6bgBF7RfXHZc6WwG2b89n0kLAASc7OvmXZUs= 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=DzKzM3NL; 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="DzKzM3NL" X-SpamFilter-By: ArmorX SpamTrap 5.80 with qID 64Q8BMl641615336, This message is accepted by code: ctloc85258 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=realsil.com.cn; s=dkim; t=1779783082; bh=Ju4rIANqGriUa13M9mkpBm4pSFMf7zhyi+UoqzXbifA=; h=From:To:CC:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Transfer-Encoding:Content-Type; b=DzKzM3NLmgyFtvSo0VXaBY0CPO4Ujlzc9GaMYBuS/KH7gSZmSSii/4v4sBOjIq0x+ X9lEpmbpqth1uZlag9JVLxB0VZTgfBJR9IWLPSsrtskz+pRn6KaVXgOAviI/uTMtFQ RKQ5qRQvheKM9G0T21stW0546318iNJ4c65KQr2K5w8OaD1dUMLDomDZ8s4gZaToPR BDcqrB+hCA7Uk6rU6A12S2iK6Eh7+/sxOKEOqjE+IdVheR6ubHZkqpPJL0RLXlxXB+ I/k9/shE7RbYKqJXbOchF/ggXG/WclwdKgWcUbzEI8lQxylKXVXafE0StcMoAPKZJD DadxMNQ46SWtg== Received: from RS-EX-MBS4.realsil.com.cn ([172.29.17.104]) by rtits2.realtek.com.tw (8.15.2/3.28/5.94) with ESMTPS id 64Q8BMl641615336 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=FAIL); Tue, 26 May 2026 16:11:22 +0800 Received: from RS-EX-MBS1.realsil.com.cn (172.29.17.101) by RS-EX-MBS4.realsil.com.cn (172.29.17.104) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.2.2562.17; Tue, 26 May 2026 16:11:20 +0800 Received: from 172.29.37.154 (172.29.37.152) by RS-EX-MBS1.realsil.com.cn (172.29.17.101) with Microsoft SMTP Server id 15.2.2562.17 via Frontend Transport; Tue, 26 May 2026 16:11:20 +0800 From: javen To: , , , , , , , CC: , , Javen Xu Subject: [Patch net-next v6 5/7] r8169: add support and enable rss Date: Tue, 26 May 2026 16:11:15 +0800 Message-ID: <20260526081117.173-6-javen_xu@realsil.com.cn> X-Mailer: git-send-email 2.50.1.windows.1 In-Reply-To: <20260526081117.173-1-javen_xu@realsil.com.cn> References: <20260526081117.173-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 --- Changes in v2: - some changes moved from Patch 2/7 Changes in v3: - add struct rtl8169_rss_data. Allocate it dynamically when needed. - define rss_key as an u32 array - replace some magic bit numbers in rtl8169_set_rss_hash_opt() and rtl8125_set_rx_q_num() - use union to combine different rx descriptor, refactor struct RxDesc - remove dead code from rtl8169_double_check_rss_support() Changes in v4: - rename macro definition, e.g R8127_MAX_IRQ to R8127_MAX_NUM_IRQVEC - change hw_supp_indir_tbl_entries type to unsigned int - change init_rx_desc_type type to enum - remove rtl_check_rss_support(), add helper function rtl_hw_support_rss() - remove hw_curr_isr_ver, use irq_nvecs to judge whether we should enable vector interrupt mapping, use tp->num_rx_ring to judge whether we should enable rss - remove function rtl8169_double_check_rss_support(), use rtl8169_set_rx_ring_num() to set num_rx_ring according to tp->irq_nvecs Changes in v5: - no changes Changes in v6: - change rss_queue_num type from u8 to unsigned int - fix rx desc clear in rtl8169_rx_clear() for different desc type - clamping num_rx_ring with rounddown_pow_of_two() --- drivers/net/ethernet/realtek/r8169_main.c | 397 +++++++++++++++++++--- 1 file changed, 358 insertions(+), 39 deletions(-) diff --git a/drivers/net/ethernet/realtek/r8169_main.c b/drivers/net/ethern= et/realtek/r8169_main.c index 13d955324037..a79a8756516d 100644 --- a/drivers/net/ethernet/realtek/r8169_main.c +++ b/drivers/net/ethernet/realtek/r8169_main.c @@ -82,6 +82,19 @@ #define R8127_MAX_TX_QUEUES 8 #define R8169_DEFAULT_RX_QUEUES 1 #define R8169_MAX_TX_QUEUES 1 +#define R8127_MAX_NUM_IRQVEC 32 +#define R8127_MIN_NUM_IRQVEC 30 +#define R8169_IRQ_DEFAULT 1 +#define RTL_RSS_KEY_SIZE 40 +#define RSS_CPU_NUM_MASK GENMASK(18, 16) +#define RSS_HASH_MASK GENMASK(10, 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 @@ -589,6 +602,25 @@ enum rtl_register_content { #define ISRIMR_LINKCHG BIT(29) #define ISRIMR_TOK_Q0 BIT(8) #define ISRIMR_ROK_Q0 BIT(0) +#define RTL_DESC_TYPE_CTRL 0xd8 +#define RSS_KEY_REG 0x4600 +#define RSS_INDIRECTION_TBL_REG 0x4700 +#define RSS_CTRL_TCP_IPV4_SUPP BIT(0) +#define RTL_DESC_TYPE_RSS BIT(1) +#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_RX_Q_NUM_MASK GENMASK(4, 2) }; =20 enum rtl_desc_bit { @@ -646,6 +678,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 */ @@ -667,9 +704,27 @@ struct TxDesc { }; =20 struct RxDesc { - __le32 opts1; - __le32 opts2; - __le64 addr; + union { + /* RX_DESC_TYPE_DEFAULT */ + struct { + __le32 opts1; + __le32 opts2; + __le64 addr; + }; + + /* RX_DESC_TYPE_RSS */ + struct { + union { + __le64 rss_addr; + struct { + __le32 rss_info; + __le32 rss_result; + } rss_dword; + }; + __le32 rss_opts2; + __le32 rss_opts1; + }; + }; }; =20 struct ring_info { @@ -741,9 +796,9 @@ enum rtl_dash_type { RTL_DASH_25_BP, }; =20 -enum rx_desc_ring_type { - RX_DESC_RING_TYPE_DEFAULT, - RX_DESC_RING_TYPE_RSS, +enum rx_desc_type { + RX_DESC_TYPE_DEFAULT, + RX_DESC_TYPE_RSS, }; =20 struct rtl8169_rx_ring { @@ -756,6 +811,12 @@ struct rtl8169_rx_ring { struct page *rx_databuff[NUM_RX_DESC]; /* Rx data buffers */ }; =20 +struct rtl8169_rss_data { + u32 rss_key[RTL_RSS_KEY_SIZE / sizeof(u32)]; + u8 rss_indir_tbl[RTL_MAX_INDIRECTION_TABLE_ENTRIES]; + unsigned int hw_supp_indir_tbl_entries; +}; + struct rtl8169_private { void __iomem *mmio_addr; /* memory map physical address */ struct pci_dev *pci_dev; @@ -775,7 +836,9 @@ struct rtl8169_private { u16 tx_lpi_timer; u32 irq_mask; unsigned int hw_supp_num_rx_queues; + struct rtl8169_rss_data *rss_data; unsigned int irq_nvecs; + enum rx_desc_type init_rx_desc_type; struct clk *clk; =20 struct { @@ -1606,6 +1669,11 @@ static bool rtl_dash_is_enabled(struct rtl8169_priva= te *tp) } } =20 +static bool rtl_hw_support_rss(struct rtl8169_private *tp) +{ + return tp->mac_version =3D=3D RTL_GIGA_MAC_VER_80; +} + static enum rtl_dash_type rtl_get_dash_type(struct rtl8169_private *tp) { switch (tp->mac_version) { @@ -1907,9 +1975,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_TYPE_RSS: + opts2 =3D le32_to_cpu(desc->rss_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)); @@ -2738,17 +2817,27 @@ static void rtl_hw_reset(struct rtl8169_private *tp) rtl_loop_wait_low(tp, &rtl_chipcmd_cond, 100, 100); } =20 +static void rtl8169_init_rss(struct rtl8169_private *tp) +{ + for (int i =3D 0; i < tp->rss_data->hw_supp_indir_tbl_entries; i++) + tp->rss_data->rss_indir_tbl[i] =3D ethtool_rxfh_indir_default(i, tp->num= _rx_rings); + + netdev_rss_key_fill(tp->rss_data->rss_key, RTL_RSS_KEY_SIZE); +} + 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->hw_supp_num_rx_queues =3D R8127_MAX_RX_QUEUES; + tp->rss_data->hw_supp_indir_tbl_entries =3D RTL_MAX_INDIRECTION_TABLE_EN= TRIES; break; default: tp->hw_supp_num_rx_queues =3D R8169_DEFAULT_RX_QUEUES; break; } + tp->init_rx_desc_type =3D RX_DESC_TYPE_DEFAULT; } =20 static void rtl_request_firmware(struct rtl8169_private *tp) @@ -2873,6 +2962,64 @@ 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) +{ + u32 num_entries =3D RTL_RSS_KEY_SIZE / sizeof(u32); + u32 *rss_key =3D tp->rss_data->rss_key; + const u16 rss_key_reg =3D RSS_KEY_REG; + + /* Write redirection table to HW */ + for (int i =3D 0; i < num_entries; i++) + RTL_W32(tp, rss_key_reg + (i * 4), rss_key[i]); +} + +static void rtl8169_store_reta(struct rtl8169_private *tp) +{ + u32 i, reta_entries =3D tp->rss_data->hw_supp_indir_tbl_entries; + u16 indir_tbl_reg =3D RSS_INDIRECTION_TBL_REG; + u8 *indir_tbl =3D tp->rss_data->rss_indir_tbl; + u32 reta =3D 0; + + /* 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_ctrl; + + rss_ctrl =3D FIELD_PREP(RSS_CPU_NUM_MASK, ilog2(tp->num_rx_rings)); + + /* 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; + + rss_ctrl |=3D FIELD_PREP(RSS_HASH_MASK, + ilog2(tp->rss_data->hw_supp_indir_tbl_entries)); + + 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) { struct rtl8169_rx_ring *ring =3D &tp->rx_ring[0]; @@ -3939,6 +4086,18 @@ 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 rx_q_num; + u16 q_ctrl; + + rx_q_num =3D (u16)ilog2(tp->num_rx_rings); + q_ctrl =3D RTL_R16(tp, Q_NUM_CTRL_8125); + q_ctrl &=3D ~RTL_RX_Q_NUM_MASK; + q_ctrl |=3D FIELD_PREP(RTL_RX_Q_NUM_MASK, rx_q_num); + RTL_W16(tp, Q_NUM_CTRL_8125, q_ctrl); +} + static void rtl8169_hw_enable_vec_mapping(struct rtl8169_private *tp) { u8 tmp; @@ -3978,6 +4137,13 @@ 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->num_rx_rings > 1) { + rtl8125_set_rx_q_num(tp); + RTL_W8(tp, RTL_DESC_TYPE_CTRL, + RTL_R8(tp, RTL_DESC_TYPE_CTRL) | RTL_DESC_TYPE_RSS); + } + 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) @@ -4214,6 +4380,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->num_rx_rings > 1) + rtl_set_rss_config(tp); + else + RTL_W32(tp, RSS_CTRL_8125, 0x00); + } rtl_lock_config_regs(tp); =20 rtl_jumbo_config(tp); @@ -4241,14 +4413,26 @@ static int rtl8169_change_mtu(struct net_device *de= v, int new_mtu) return 0; } =20 -static void rtl8169_mark_to_asic(struct RxDesc *desc) +static void rtl8169_mark_to_asic(struct rtl8169_private *tp, struct RxDesc= *desc) { - u32 eor =3D le32_to_cpu(desc->opts1) & RingEnd; + u32 eor; =20 - desc->opts2 =3D 0; - /* Force memory writes to complete before releasing descriptor */ - dma_wmb(); - WRITE_ONCE(desc->opts1, cpu_to_le32(DescOwn | eor | R8169_RX_BUF_SIZE)); + switch (tp->init_rx_desc_type) { + case RX_DESC_TYPE_RSS: + eor =3D le32_to_cpu(desc->rss_opts1) & RingEnd; + desc->rss_opts2 =3D cpu_to_le32(0); + /* Force memory writes to complete before releasing descriptor */ + dma_wmb(); + WRITE_ONCE(desc->rss_opts1, cpu_to_le32(DescOwn | eor | R8169_RX_BUF_SIZ= E)); + break; + default: + eor =3D le32_to_cpu(desc->opts1) & RingEnd; + desc->opts2 =3D cpu_to_le32(0); + /* Force memory writes to complete before releasing descriptor */ + dma_wmb(); + WRITE_ONCE(desc->opts1, cpu_to_le32(DescOwn | eor | R8169_RX_BUF_SIZE)); + break; + } } =20 static struct page *rtl8169_alloc_rx_data(struct rtl8169_private *tp, @@ -4271,9 +4455,12 @@ 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; - rtl8169_mark_to_asic(desc); + if (tp->init_rx_desc_type =3D=3D RX_DESC_TYPE_RSS) + desc->rss_addr =3D cpu_to_le64(mapping); + else + desc->addr =3D cpu_to_le64(mapping); + rtl8169_mark_to_asic(tp, desc); =20 return data; } @@ -4289,8 +4476,25 @@ static void rtl8169_rx_clear(struct rtl8169_private = *tp, struct rtl8169_rx_ring __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; + if (tp->init_rx_desc_type =3D=3D RX_DESC_TYPE_RSS) { + ring->rx_desc_array[i].rss_addr =3D 0; + ring->rx_desc_array[i].rss_opts1 =3D 0; + } else { + ring->rx_desc_array[i].addr =3D 0; + ring->rx_desc_array[i].opts1 =3D 0; + } + } +} + +static void rtl8169_mark_as_last_descriptor(struct rtl8169_private *tp, st= ruct RxDesc *desc) +{ + switch (tp->init_rx_desc_type) { + case RX_DESC_TYPE_RSS: + desc->rss_opts1 |=3D cpu_to_le32(RingEnd); + break; + default: + desc->opts1 |=3D cpu_to_le32(RingEnd); + break; } } =20 @@ -4310,7 +4514,7 @@ static int rtl8169_rx_fill(struct rtl8169_private *tp= , struct rtl8169_rx_ring *r } =20 /* mark as last descriptor in the ring */ - ring->rx_desc_array[NUM_RX_DESC - 1].opts1 |=3D cpu_to_le32(RingEnd); + rtl8169_mark_as_last_descriptor(tp, &ring->rx_desc_array[NUM_RX_DESC - 1]= ); =20 return 0; } @@ -4466,7 +4670,7 @@ static void rtl8169_rx_desc_reset(struct rtl8169_priv= ate *tp) struct rtl8169_rx_ring *ring =3D &tp->rx_ring[i]; =20 for (int j =3D 0; j < NUM_RX_DESC; j++) - rtl8169_mark_to_asic(ring->rx_desc_array + j); + rtl8169_mark_to_asic(tp, ring->rx_desc_array + j); } } =20 @@ -4922,35 +5126,104 @@ static inline int rtl8169_fragmented_frame(u32 sta= tus) return (status & (FirstFrag | LastFrag)) !=3D (FirstFrag | LastFrag); } =20 -static inline void rtl8169_rx_csum(struct sk_buff *skb, +static inline void rtl8169_rx_hash(struct rtl8169_private *tp, + struct RxDesc *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->rss_dword.rss_info); + + if (!(rss_header_info & RXS_RSS_L3_TYPE_MASK)) + return; + + hash_val =3D le32_to_cpu(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(struct rtl8169_private *tp, + struct sk_buff *skb, struct RxDesc *desc) { - u32 status =3D le32_to_cpu(desc->opts1) & (RxProtoMask | RxCSFailMask); + bool csum_ok =3D false; + u32 opts1; =20 - if (status =3D=3D RxProtoTCP || status =3D=3D RxProtoUDP) + switch (tp->init_rx_desc_type) { + case RX_DESC_TYPE_RSS: + opts1 =3D le32_to_cpu(desc->rss_opts1); + if (((opts1 & RX_TCPT_DESC_RSS) && !(opts1 & RX_TCPF_DESC_RSS)) || + ((opts1 & RX_UDPT_DESC_RSS) && !(opts1 & RX_UDPF_DESC_RSS))) + csum_ok =3D true; + break; + default: + opts1 =3D le32_to_cpu(desc->opts1) & (RxProtoMask | RxCSFailMask); + if (opts1 =3D=3D RxProtoTCP || opts1 =3D=3D RxProtoUDP) + csum_ok =3D true; + break; + } + + if (csum_ok) skb->ip_summed =3D CHECKSUM_UNNECESSARY; else skb_checksum_none_assert(skb); } =20 +static __le32 rtl8169_rx_desc_opts1(struct rtl8169_private *tp, struct RxD= esc *desc) +{ + switch (tp->init_rx_desc_type) { + case RX_DESC_TYPE_RSS: + return READ_ONCE(desc->rss_opts1); + default: + 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; + switch (tp->init_rx_desc_type) { + case RX_DESC_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; } =20 -static void rtl8169_set_desc_dma_addr(struct RxDesc *desc, +static 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_TYPE_RSS: + desc->rss_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, @@ -4967,7 +5240,7 @@ static int rtl_rx(struct net_device *dev, struct rtl8= 169_private *tp, dma_addr_t addr; u32 status; =20 - status =3D le32_to_cpu(READ_ONCE(desc->opts1)); + status =3D le32_to_cpu(rtl8169_rx_desc_opts1(tp, desc)); =20 if (status & DescOwn) { if (!tp->recheck_desc_ownbit) @@ -4983,7 +5256,7 @@ static int rtl_rx(struct net_device *dev, struct rtl8= 169_private *tp, */ tp->recheck_desc_ownbit =3D false; RTL_R8(tp, LED_CTRL); - status =3D le32_to_cpu(READ_ONCE(desc->opts1)); + status =3D le32_to_cpu(rtl8169_rx_desc_opts1(tp, desc)); if (status & DescOwn) break; } @@ -5034,11 +5307,12 @@ static int rtl_rx(struct net_device *dev, struct rt= l8169_private *tp, skb->tail +=3D pkt_size; skb->len =3D pkt_size; dma_sync_single_for_device(d, addr, pkt_size, DMA_FROM_DEVICE); - - rtl8169_rx_csum(skb, desc); + if (tp->num_rx_rings > 1) + rtl8169_rx_hash(tp, 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++; @@ -5047,8 +5321,8 @@ static int rtl_rx(struct net_device *dev, struct rtl8= 169_private *tp, =20 dev_sw_netstats_rx_add(dev, pkt_size); release_descriptor: - rtl8169_set_desc_dma_addr(desc, ring->rx_desc_phy_addr[entry]); - 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; @@ -5604,6 +5878,32 @@ static void rtl_set_irq_mask(struct rtl8169_private = *tp) } } =20 +static int get_max_irq_nvecs(struct rtl8169_private *tp) +{ + if (tp->mac_version =3D=3D RTL_GIGA_MAC_VER_80) + return R8127_MAX_NUM_IRQVEC; + return R8169_IRQ_DEFAULT; +} + +static int get_min_irq_nvecs(struct rtl8169_private *tp) +{ + if (tp->mac_version =3D=3D RTL_GIGA_MAC_VER_80) + return R8127_MIN_NUM_IRQVEC; + return R8169_IRQ_DEFAULT; +} + +static void rtl8169_set_rx_ring_num(struct rtl8169_private *tp) +{ + if (tp->irq_nvecs >=3D get_min_irq_nvecs(tp)) { + unsigned int rss_queue_num =3D netif_get_num_default_rss_queues(); + + tp->num_rx_rings =3D rounddown_pow_of_two(min(rss_queue_num, + tp->hw_supp_num_rx_queues)); + if (tp->num_rx_rings >=3D 2) + tp->init_rx_desc_type =3D RX_DESC_TYPE_RSS; + } +} + static int rtl_alloc_irq(struct rtl8169_private *tp) { struct pci_dev *pdev =3D tp->pci_dev; @@ -5624,7 +5924,10 @@ static int rtl_alloc_irq(struct rtl8169_private *tp) break; } =20 - nvecs =3D pci_alloc_irq_vectors(pdev, 1, 1, flags); + nvecs =3D pci_alloc_irq_vectors(pdev, get_min_irq_nvecs(tp), get_max_irq_= nvecs(tp), flags); + + if (nvecs < 0) + nvecs =3D pci_alloc_irq_vectors(pdev, 1, 1, flags); =20 if (nvecs < 0) return nvecs; @@ -6071,6 +6374,12 @@ static int rtl_init_one(struct pci_dev *pdev, const = struct pci_device_id *ent) tp->dash_type =3D rtl_get_dash_type(tp); tp->dash_enabled =3D rtl_dash_is_enabled(tp); =20 + if (rtl_hw_support_rss(tp)) { + tp->rss_data =3D devm_kzalloc(&pdev->dev, sizeof(*tp->rss_data), GFP_KER= NEL); + if (!tp->rss_data) + return -ENOMEM; + } + tp->cp_cmd =3D RTL_R16(tp, CPlusCmd) & CPCMD_MASK; =20 if (sizeof(dma_addr_t) > 4 && tp->mac_version >=3D RTL_GIGA_MAC_VER_18 && @@ -6096,6 +6405,11 @@ static int rtl_init_one(struct pci_dev *pdev, const = struct pci_device_id *ent) if (!tp->rtl8169_napi) return -ENOMEM; =20 + rtl8169_set_rx_ring_num(tp); + + if (rtl_hw_support_rss(tp)) + rtl8169_init_rss(tp); + INIT_WORK(&tp->wk.work, rtl_task); disable_work(&tp->wk.work); =20 @@ -6110,6 +6424,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 (rtl_hw_support_rss(tp) && tp->num_rx_rings > 1) { + 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 Mon Jun 8 22:01:57 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 8657A3BB9FE; Tue, 26 May 2026 08:11:56 +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=1779783119; cv=none; b=Ttn/Vm8DcGxVQRqgesnBQ457ls+cg3IYks+W9qdfvrjVHS9aSgVRtF1i7K8HqAoGcs0YLoEz1kKshQfU12GGTtts5ZEXLFUwILWay19+NtBQPcEyhQmyaeH4mj0XYZVyIPf64ADWbeVhoE+lUp37O1dKvAOUPWYsGfPn9R+exnQ= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1779783119; c=relaxed/simple; bh=qAZ5aT1ocltZ+d3Hm7SI7Lnkqpb2RtgByp/iix87W6c=; h=From:To:CC:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=dgJnfpU3nmYDhc+F4zLB0CZKdjsfqd/GZa6GJg/f2BfIsS1mAN/xvfTihSdlypa1ay86VnKjwLG0ImFVOBmU/tYmZA51nq6tRbXOjm7nkm5UtWboP/8f8pZ22upqfO9PY83zhIOGLZnj2m4oLSY8M02r9dnLDpDgu+/tr/Bf2SA= 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=FbzBq1Vz; 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="FbzBq1Vz" X-SpamFilter-By: ArmorX SpamTrap 5.80 with qID 64Q8BMl741615336, This message is accepted by code: ctloc85258 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=realsil.com.cn; s=dkim; t=1779783082; bh=irjK2PyymjVHPL3WPHY5qMJVp17uNXo4K4aBceRjKSY=; h=From:To:CC:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Transfer-Encoding:Content-Type; b=FbzBq1VzHI2eBdN09AmFGdn3wL1dbLUxlgLOw5WcWXqKfUyJS/fmaV7Xa+Xod2c+h N2CJqUHMp08CzGZs+D+aCeb4zjUQG0ElT3NNBRGIxWjfAT1ZkDkSS7Wj4JMlJ7nJ8k wEBkKCM7I5vIrT5d4LZ9o6EvB7AF801RfXbOvxtfZ7VtOj3oyxmk8EvI0y6kcLLfef 6wvRMGtBQMRwniuSzWd0xaWQe7j68vhsWc8kQNihlnhEFGeMTqmjgMRSf+L1sNxWQJ ponHzfZM36KXUZW3O3UPJnExb7x+0wbxlyiHhCWVP/BLHXPvbJ4zLZQJobKMz6hAVo gCyCcyRWEiIKg== Received: from RS-EX-MBS4.realsil.com.cn ([172.29.17.104]) by rtits2.realtek.com.tw (8.15.2/3.28/5.94) with ESMTPS id 64Q8BMl741615336 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=FAIL); Tue, 26 May 2026 16:11:22 +0800 Received: from RS-EX-MBS1.realsil.com.cn (172.29.17.101) by RS-EX-MBS4.realsil.com.cn (172.29.17.104) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.2.2562.17; Tue, 26 May 2026 16:11:21 +0800 Received: from 172.29.37.154 (172.29.37.152) by RS-EX-MBS1.realsil.com.cn (172.29.17.101) with Microsoft SMTP Server id 15.2.2562.17 via Frontend Transport; Tue, 26 May 2026 16:11:21 +0800 From: javen To: , , , , , , , CC: , , Javen Xu Subject: [Patch net-next v6 6/7] r8169: move struct ethtool_ops Date: Tue, 26 May 2026 16:11:16 +0800 Message-ID: <20260526081117.173-7-javen_xu@realsil.com.cn> X-Mailer: git-send-email 2.50.1.windows.1 In-Reply-To: <20260526081117.173-1-javen_xu@realsil.com.cn> References: <20260526081117.173-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 The patch moves the rtl8169_ethtool_ops definition further down in r8169_main.c so that subsequent additions of rtl8169_get_channels and rtl8169_set_channels can be referenced from the ops struct without needing forward declarations. Signed-off-by: Javen Xu --- Changes in v2: - no changes Changes in v3: - no changes Changes in v4: - no changes Changes in v5: - no changes Changes in v6: - modify commit message --- 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 a79a8756516d..bf031f09437f 100644 --- a/drivers/net/ethernet/realtek/r8169_main.c +++ b/drivers/net/ethernet/realtek/r8169_main.c @@ -2535,34 +2535,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 */ @@ -6281,6 +6253,34 @@ static void r8169_init_napi(struct rtl8169_private *= tp) devm_add_action_or_reset(&tp->pci_dev->dev, r8169_del_napi_action, 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 Mon Jun 8 22:01:57 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 53A5D3B6BF1; Tue, 26 May 2026 08:11:56 +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=1779783118; cv=none; b=ed5i64idq04Qi8rWjqCWClMkskPJrWvGhejtsrX6ow0KEH3V9J0vRuEa5Z8/xK2R7GCKbirPhfxCeA/urnw59YPBIfL0UAEUpMQdpH8boB64JlXgbgDCx6mvs/CaH+iSVB9fog54+WArCgILEwf+rzn2ZmIl/0ZzYrZOwkGkVRw= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1779783118; c=relaxed/simple; bh=eqCqGJYrnj3iC652B2Z7LezNLPvZUE1KA8l9PK43+XM=; h=From:To:CC:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=X6kYEJ9GbsvkSoMXJENxdYsK8oCA1vUgCsik2cgZn9jAJi6vfzlz8ajgbKGyZmwmnYOtu6XRf0Az+AhZcuSoqrgfcf7lF/sfY1X6/FGQta/wkNv656jh6V9xu4BIji6rQtc4Iam9oYEMpi4Xn5jeysNw3ZAR8T5YlsJdPG10Cyk= 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=QejnQFjH; 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="QejnQFjH" X-SpamFilter-By: ArmorX SpamTrap 5.80 with qID 64Q8BMl841615336, This message is accepted by code: ctloc85258 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=realsil.com.cn; s=dkim; t=1779783082; bh=x7F67mPSSkLgJ0EQdQ6cxf1mBRFtH0btTcJ1DI/PsTk=; h=From:To:CC:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Transfer-Encoding:Content-Type; b=QejnQFjHhc5HgpwIarO56aEVLtV6OPjfIxuVW4/mMx2skVZEoyXT5/p3q9PQC/IvW 44ykswR3HgQKRUdFFpzb2L9ujFO58UsUvwCh8nCJmhNPqJpXavxu3fo525XJfSbXNx UXNL3vbLidJC51ecruHS0wH+bfXi+BuiQrDdpiZT5zOMzqlFx676u+t3ZZuta7grnw D56a8ObA9zZT8fInbal1eii9XgU8P+7T5sKglsN1i5mLafylmsoBLR8t2WPCF7fFGe c8OeGlDn333hqpzHtJj/MklJGQoE69TyBB5SAl1T6BK9XSY22m1iwlDQeT1m5IobJK qc1CGOe9gjUlA== Received: from RS-EX-MBS4.realsil.com.cn ([172.29.17.104]) by rtits2.realtek.com.tw (8.15.2/3.28/5.94) with ESMTPS id 64Q8BMl841615336 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=FAIL); Tue, 26 May 2026 16:11:22 +0800 Received: from RS-EX-MBS1.realsil.com.cn (172.29.17.101) by RS-EX-MBS4.realsil.com.cn (172.29.17.104) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.2.2562.17; Tue, 26 May 2026 16:11:21 +0800 Received: from 172.29.37.154 (172.29.37.152) by RS-EX-MBS1.realsil.com.cn (172.29.17.101) with Microsoft SMTP Server id 15.2.2562.17 via Frontend Transport; Tue, 26 May 2026 16:11:21 +0800 From: javen To: , , , , , , , CC: , , Javen Xu Subject: [Patch net-next v6 7/7] r8169: support setting rx queue numbers via ethtool Date: Tue, 26 May 2026 16:11:17 +0800 Message-ID: <20260526081117.173-8-javen_xu@realsil.com.cn> X-Mailer: git-send-email 2.50.1.windows.1 In-Reply-To: <20260526081117.173-1-javen_xu@realsil.com.cn> References: <20260526081117.173-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 --- Changes in v2: - no changes Changes in v3: - no changes Changes in v4: - remove rss_support and rss_enable - remove some zero-initialized - use kzalloc_objs instead of kcalloc Changes in v5: - no changes Changes in v6: - change subject of this patch - defer the assignment of tp->init_rx_desc_type until after rtl8169_down() - call netif_set_real_num_rx_queues() to synchronize the new rx queue number with networking core --- drivers/net/ethernet/realtek/r8169_main.c | 125 ++++++++++++++++++++++ 1 file changed, 125 insertions(+) diff --git a/drivers/net/ethernet/realtek/r8169_main.c b/drivers/net/ethern= et/realtek/r8169_main.c index bf031f09437f..039465cd7ee1 100644 --- a/drivers/net/ethernet/realtek/r8169_main.c +++ b/drivers/net/ethernet/realtek/r8169_main.c @@ -6253,6 +6253,129 @@ static void r8169_init_napi(struct rtl8169_private = *tp) devm_add_action_or_reset(&tp->pci_dev->dev, r8169_del_napi_action, 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->rx_count =3D tp->num_rx_rings; + ch->tx_count =3D 1; +} + +static int rtl8169_realloc_rx(struct rtl8169_private *tp, + struct rtl8169_rx_ring *new_rx, + int new_count) +{ + int i, ret; + + for (i =3D 0; i < new_count; i++) { + struct rtl8169_rx_ring *ring =3D &new_rx[i]; + + ring->rx_desc_array =3D dma_alloc_coherent(&tp->pci_dev->dev, + R8169_RX_RING_BYTES, + &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, R8169_RX_RING_BYTES, + 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, R8169_RX_RING_BYTES, + 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); + enum rx_desc_type old_rx_desc_type; + enum rx_desc_type new_desc_type; + struct rtl8169_rx_ring *new_rx; + int i, ret; + + old_rx_desc_type =3D tp->init_rx_desc_type; + + if (!rtl_hw_support_rss(tp)) { + netdev_warn(dev, "This chip does not support multiple channels/RSS.\n"); + return -EOPNOTSUPP; + } + + if (ch->rx_count > R8169_MAX_RX_QUEUES) + return -EINVAL; + + new_desc_type =3D ch->rx_count > 1 ? RX_DESC_TYPE_RSS : RX_DESC_TYPE_DEFA= ULT; + + if (!if_running) { + tp->num_rx_rings =3D ch->rx_count; + tp->init_rx_desc_type =3D new_desc_type; + return 0; + } + + netif_stop_queue(dev); + rtl8169_down(tp); + + new_rx =3D kzalloc_objs(*new_rx, R8169_MAX_RX_QUEUES); + if (!new_rx) + return -ENOMEM; + + tp->init_rx_desc_type =3D new_desc_type; + ret =3D rtl8169_realloc_rx(tp, new_rx, ch->rx_count); + if (ret) { + tp->init_rx_desc_type =3D old_rx_desc_type; + kfree(new_rx); + return ret; + } + + 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; + + 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->rss_data->hw_supp_indir_tbl_entries; i++) { + if (ch->rx_count > 1) + tp->rss_data->rss_indir_tbl[i] =3D + ethtool_rxfh_indir_default(i, tp->num_rx_rings); + else + tp->rss_data->rss_indir_tbl[i] =3D 0; + } + + rtl_set_irq_mask(tp); + + rtl8169_up(tp); + netif_start_queue(dev); + + ret =3D netif_set_real_num_rx_queues(dev, ch->rx_count); + if (ret) + netdev_warn(dev, "Failed to set real num rx queues\n"); + + 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, @@ -6271,6 +6394,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