All of lore.kernel.org
 help / color / mirror / Atom feed
From: Mohsin Bashir <mohsin.bashr@gmail.com>
To: javen <javen_xu@realsil.com.cn>,
	hkallweit1@gmail.com, nic_swsd@realtek.com,
	andrew+netdev@lunn.ch, davem@davemloft.net, edumazet@google.com,
	kuba@kernel.org, pabeni@redhat.com, horms@kernel.org
Cc: netdev@vger.kernel.org, linux-kernel@vger.kernel.org
Subject: Re: [PATCH net-next v11 3/7] r8169: add support for new interrupt mapping
Date: Fri, 14 Aug 2026 15:45:17 -0700	[thread overview]
Message-ID: <cc106b5e-943d-445e-a48c-77af70e67e70@gmail.com> (raw)
In-Reply-To: <20260814015203.1328-4-javen_xu@realsil.com.cn>



On 8/13/26 6:51 PM, javen wrote:
> From: Javen Xu <javen_xu@realsil.com.cn>
> 
> 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_VEC_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 <javen_xu@realsil.com.cn>
> ---
> 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 <= 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()
> 
> Changes in v7:
>   - remove recheck_desc_ownbit
>   - change return value of rtl_tx
>   - remove message_id which only used once
> 
> Changes in v8:
>   - fix rtl8169_netpoll()
>   - remove tx_done
> 
> Changes in v9:
>   - change the way of getting message_id of napi
> 
> Changes in v10:
>   - no changes
> 
> Changes in v11:
>   - add comment on rtl8169_poll_msix_tx, only use 1 tx
>   - remove napi for other. Separate napi only for datapath, control path
>     like linkchg is handled in interrupt function, which will not call
>     napi any more.
> ---
>   drivers/net/ethernet/realtek/r8169_main.c | 213 +++++++++++++++++++---
>   1 file changed, 187 insertions(+), 26 deletions(-)
> 
> diff --git a/drivers/net/ethernet/realtek/r8169_main.c b/drivers/net/ethernet/realtek/r8169_main.c
> index 9311a0cab4eb..b30f0a31d7c7 100644
> --- a/drivers/net/ethernet/realtek/r8169_main.c
> +++ b/drivers/net/ethernet/realtek/r8169_main.c
> @@ -84,6 +84,7 @@
>   #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_QUEUES	16
>   #define R8169_MAX_RX_QUEUES	8
>   #define R8169_DEFAULT_RX_QUEUES	1
>   #define R8169_MAX_TX_QUEUES	1
> @@ -455,8 +456,12 @@ enum rtl8125_registers {
>   	RSS_CTRL_8125		= 0x4500,
>   	Q_NUM_CTRL_8125		= 0x4800,
>   	EEE_TXIDLE_TIMER_8125	= 0x6048,
> +	IMR_CLEAR_VEC_MAP_REG	= 0x0d00,
> +	ISR_VEC_MAP_REG		= 0x0d04,
> +	IMR_SET_VEC_MAP_REG	= 0x0d0c,
>   };
>   
> +#define MSIX_ID_VEC_MAP_LINKCHG	29
>   #define LEDSEL_MASK_8125	0x23f
>   
>   #define RX_VLAN_INNER_8125	BIT(22)
> @@ -587,6 +592,9 @@ enum rtl_register_content {
>   
>   	/* magic enable v2 */
>   	MagicPacket_v2	= (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)
>   };
>   
>   enum rtl_desc_bit {
> @@ -1663,26 +1671,38 @@ static u32 rtl_get_events(struct rtl8169_private *tp)
>   
>   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);
> +	}
>   }
>   
>   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);
> +	}
>   }
>   
>   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);
> +	}
>   }
>   
>   static void rtl8169_irq_mask_and_ack(struct rtl8169_private *tp)
> @@ -4382,13 +4402,17 @@ static void rtl8169_tx_clear(struct rtl8169_private *tp)
>   
>   static void rtl8169_napi_disable(struct rtl8169_private *tp)
>   {
> -	for (int i = 0; i < tp->irq_nvecs; i++)
> +	int napi_num = min(tp->irq_nvecs, R8169_MAX_QUEUES);
> +
> +	for (int i = 0; i < napi_num; i++)
>   		napi_disable(&tp->rtl8169_napi[i]);
>   }
>   
>   static void rtl8169_napi_enable(struct rtl8169_private *tp)
>   {
> -	for (int i = 0; i < tp->irq_nvecs; i++)
> +	int napi_num = min(tp->irq_nvecs, R8169_MAX_QUEUES);
> +
> +	for (int i = 0; i < napi_num; i++)
>   		napi_enable(&tp->rtl8169_napi[i]);
>   }
>   
> @@ -5030,13 +5054,66 @@ static irqreturn_t rtl8169_interrupt(int irq, void *dev_instance)
>   	return IRQ_HANDLED;
>   }
>   
> +static void rtl8169_free_one_irq(struct rtl8169_private *tp, int i)
> +{
> +	if (tp->irq_nvecs > 1) {
> +		if (i < R8169_MAX_QUEUES)
> +			pci_free_irq(tp->pci_dev, i, &tp->rtl8169_napi[i]);
> +		else if (i == MSIX_ID_VEC_MAP_LINKCHG)
> +			pci_free_irq(tp->pci_dev, i, tp);
> +	} else {
> +		pci_free_irq(tp->pci_dev, i, &tp->rtl8169_napi[i]);
> +	}
> +}
> +
>   static void rtl8169_free_irq(struct rtl8169_private *tp)
>   {
> -	for (int i = 0; i < tp->irq_nvecs; i++) {
> -		struct napi_struct *napi = &tp->rtl8169_napi[i];
> +	for (int i = 0; i < tp->irq_nvecs; i++)
> +		rtl8169_free_one_irq(tp, i);
> +}
>   
> -		pci_free_irq(tp->pci_dev, i, napi);
> -	}
> +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_id)
> +{
> +	RTL_W32(tp, ISR_VEC_MAP_REG, BIT(message_id));
> +}
> +
> +static void rtl8169_enable_hw_interrupt_msix(struct rtl8169_private *tp,
> +					     int 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 = dev_instance;
> +	struct net_device *dev = napi->dev;
> +	struct rtl8169_private *tp;
> +	int message_id;
> +
> +	tp = netdev_priv(dev);
> +	message_id = napi - tp->rtl8169_napi;
> +
> +	rtl8169_disable_hw_interrupt_msix(tp, message_id);
> +	rtl8169_clear_hw_isr(tp, message_id);
> +
> +	napi_schedule(napi);
> +
> +	return IRQ_HANDLED;
> +}
> +
> +static irqreturn_t rtl8169_interrupt_other(int irq, void *dev_instance)
> +{
> +	struct rtl8169_private *tp = dev_instance;
> +
> +	rtl8169_clear_hw_isr(tp, MSIX_ID_VEC_MAP_LINKCHG);
> +	phy_mac_interrupt(tp->phydev);
> +	return IRQ_HANDLED;
>   }
>   
>   static int rtl8169_request_irq(struct rtl8169_private *tp)
> @@ -5047,8 +5124,26 @@ static int rtl8169_request_irq(struct rtl8169_private *tp)
>   
>   	for (i = 0; i < tp->irq_nvecs; i++) {
>   		napi = &tp->rtl8169_napi[i];
> -		rc = pci_request_irq(tp->pci_dev, i, rtl8169_interrupt,
> -				     NULL, napi, "%s-%d", dev->name, i);
> +		if (tp->irq_nvecs > 1) {
> +			if (i < R8169_MAX_QUEUES)
> +				rc = pci_request_irq(tp->pci_dev, i,
> +						     rtl8169_interrupt_msix,
> +						     NULL, napi, "%s-%d",
> +						     dev->name, i);
> +			else if (i == MSIX_ID_VEC_MAP_LINKCHG)
> +				rc = pci_request_irq(tp->pci_dev, i,
> +						     rtl8169_interrupt_other,
> +						     NULL, tp, "%s-%d",
> +						     dev->name, i);
> +			else
> +				continue;
> +		} else {
> +			rc = pci_request_irq(tp->pci_dev, i,
> +					     rtl8169_interrupt,
> +					     NULL, napi, "%s-%d",
> +					     dev->name, i);
> +		}
> +
>   		if (rc)
>   			goto free_irq;
>   	}
> @@ -5056,7 +5151,7 @@ static int rtl8169_request_irq(struct rtl8169_private *tp)
>   
>   free_irq:
>   	while (--i >= 0)
> -		pci_free_irq(tp->pci_dev, i, &tp->rtl8169_napi[i]);
> +		rtl8169_free_one_irq(tp, i);
>   	return rc;
>   }
>   
> @@ -5255,8 +5350,12 @@ static void rtl8169_netpoll(struct net_device *dev)
>   	struct rtl8169_private *tp = netdev_priv(dev);
>   
>   	for (int i = 0; i < tp->irq_nvecs; i++) {

Looking at r8169_init_napi(), later down the patch, it only calls 
netif_napi_add() for min(tp->irq_nvecs, R8169_MAX_QUEUES) vectors, but 
this loop iterates all tp->irq_nvecs. Can this be an issue? Looks like 
it will be because entries entries >= R8169_MAX_QUEUES are zeroed but 
rtl8169_interrupt_msix() would set dev to NULL.

> -		rtl8169_interrupt(pci_irq_vector(tp->pci_dev, i),
> -				  &tp->rtl8169_napi[i]);
> +		if (tp->irq_nvecs > 1)
> +			rtl8169_interrupt_msix(pci_irq_vector(tp->pci_dev, i),
> +					       &tp->rtl8169_napi[i]);
> +		else
> +			rtl8169_interrupt(pci_irq_vector(tp->pci_dev, i),
> +					  &tp->rtl8169_napi[i]);
>   	}
>   }
>   #endif
> @@ -5454,7 +5553,9 @@ static void rtl_shutdown(struct pci_dev *pdev)
>   
>   static void r8169_free_napi(struct rtl8169_private *tp)
>   {
> -	for (int i = 0; i < tp->irq_nvecs; i++)
> +	int napi_num = min(tp->irq_nvecs, R8169_MAX_QUEUES);
> +
> +	for (int i = 0; i < napi_num; i++)
>   		netif_napi_del(&tp->rtl8169_napi[i]);
>   
>   	kfree(tp->rtl8169_napi);
> @@ -5508,10 +5609,16 @@ static const struct net_device_ops rtl_netdev_ops = {
>   
>   static void rtl_set_irq_mask(struct rtl8169_private *tp)
>   {
> -	tp->irq_mask = RxOK | RxErr | TxOK | TxErr | LinkChg;
> +	if (tp->irq_nvecs > 1) {
> +		tp->irq_mask = ISRIMR_LINKCHG | ISRIMR_TOK_Q0;
> +		for (int i = 0; i < tp->num_rx_rings; i++)
> +			tp->irq_mask |= ISRIMR_ROK_Q0 << i;
> +	} else {
> +		tp->irq_mask = RxOK | RxErr | TxOK | TxErr | LinkChg;
>   
> -	if (tp->mac_version <= RTL_GIGA_MAC_VER_06)
> -		tp->irq_mask |= SYSErr | RxFIFOOver;
> +		if (tp->mac_version <= RTL_GIGA_MAC_VER_06)
> +			tp->irq_mask |= SYSErr | RxFIFOOver;
> +	}
>   }
>   
>   static int rtl_alloc_irq(struct rtl8169_private *tp)
> @@ -5796,10 +5903,64 @@ static bool rtl_aspm_is_safe(struct rtl8169_private *tp)
>   	return false;
>   }
>   
> +static int rtl8169_poll_msix_rx(struct napi_struct *napi, int budget)
> +{
> +	struct net_device *dev = napi->dev;
> +	struct rtl8169_private *tp;
> +	int work_done = 0;
> +	int message_id;
> +
> +	tp = netdev_priv(dev);
> +	message_id = napi - tp->rtl8169_napi;
> +
> +	if (message_id < tp->num_rx_rings)
> +		work_done += rtl_rx(dev, tp, &tp->rx_ring[message_id],
> +				    budget, napi);
> +
> +	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 = napi->dev;
> +	struct rtl8169_private *tp;
> +
> +	tp = netdev_priv(dev);
> +
> +	/* Currently r8169 only supports a single Tx ring.
> +	 * Therefore, we don't need a per-ring Tx processing loop here.
> +	 */
> +	rtl_tx(dev, tp, budget);
> +
> +	if (napi_complete_done(napi, 0))
> +		rtl8169_enable_hw_interrupt_msix(tp, (int)(napi - tp->rtl8169_napi));
> +
> +	return 0;
> +}
> +
> +/* RTL8127 MSI-X vector layout:
> + * Vectors 0 .. (RxQs - 1)		: Rx Queues
> + * Vectors RxQs .. (RxQs + TxQs - 1)	: Tx Queues
> + * NAPI is only allocated for data path
> + */
>   static void r8169_init_napi(struct rtl8169_private *tp)
>   {
> -	for (int i = 0; i < tp->irq_nvecs; i++)
> -		netif_napi_add(tp->dev, &tp->rtl8169_napi[i], rtl8169_poll);
> +	int napi_num = min(tp->irq_nvecs, R8169_MAX_QUEUES);
> +
> +	for (int i = 0; i < napi_num; i++) {
> +		int (*poll_fn)(struct napi_struct *, int) = rtl8169_poll;
> +
> +		if (tp->irq_nvecs > 1) {
> +			if (i < R8169_MAX_RX_QUEUES)
> +				poll_fn = rtl8169_poll_msix_rx;
> +			else
> +				poll_fn = rtl8169_poll_msix_tx;
> +		}
> +		netif_napi_add(tp->dev, &tp->rtl8169_napi[i], poll_fn);
> +	}
>   }
>   
>   static int rtl_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)


  reply	other threads:[~2026-08-14 22:45 UTC|newest]

Thread overview: 14+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-08-14  1:51 [PATCH net-next v11 0/7] r8169: add RSS support for RTL8127 javen
2026-08-14  1:51 ` [PATCH net-next v11 1/7] r8169: add support for multi irqs javen
2026-08-14  1:51 ` [PATCH net-next v11 2/7] r8169: refactor RX path to prepare for multi-queue javen
2026-08-14  1:51 ` [PATCH net-next v11 3/7] r8169: add support for new interrupt mapping javen
2026-08-14 22:45   ` Mohsin Bashir [this message]
2026-08-17  7:21     ` Javen
2026-08-14  1:52 ` [PATCH net-next v11 4/7] r8169: enable " javen
2026-08-14 22:54   ` Mohsin Bashir
2026-08-17  7:21     ` Javen
2026-08-17 23:38   ` Jakub Kicinski
2026-08-14  1:52 ` [PATCH net-next v11 5/7] r8169: add support and enable rss javen
2026-08-14 23:00   ` Mohsin Bashir
2026-08-14  1:52 ` [PATCH net-next v11 6/7] r8169: move struct ethtool_ops javen
2026-08-14  1:52 ` [PATCH net-next v11 7/7] r8169: add get_channel support for ethtool javen

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=cc106b5e-943d-445e-a48c-77af70e67e70@gmail.com \
    --to=mohsin.bashr@gmail.com \
    --cc=andrew+netdev@lunn.ch \
    --cc=davem@davemloft.net \
    --cc=edumazet@google.com \
    --cc=hkallweit1@gmail.com \
    --cc=horms@kernel.org \
    --cc=javen_xu@realsil.com.cn \
    --cc=kuba@kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=netdev@vger.kernel.org \
    --cc=nic_swsd@realtek.com \
    --cc=pabeni@redhat.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.