diff mbox series

[net-next,07/16] idpf: link NAPIs to queues

Message ID 20250305162132.1106080-8-aleksander.lobakin@intel.com (mailing list archive)
State Changes Requested
Delegated to: Netdev Maintainers
Headers show
Series idpf: add XDP support | expand

Checks

Context Check Description
netdev/series_format fail Series longer than 15 patches
netdev/tree_selection success Clearly marked for net-next, async
netdev/ynl success Generated files up to date; no warnings/errors; no diff in generated;
netdev/fixes_present success Fixes tag not required for -next series
netdev/header_inline success No static functions without inline keyword in header files
netdev/build_32bit success Errors and warnings before: 0 this patch: 0
netdev/build_tools success No tools touched, skip
netdev/cc_maintainers success CCed 9 of 9 maintainers
netdev/build_clang success Errors and warnings before: 0 this patch: 0
netdev/verify_signedoff success Signed-off-by tag matches author and committer
netdev/deprecated_api success None detected
netdev/check_selftest success No net selftest shell script
netdev/verify_fixes success No Fixes tag
netdev/build_allmodconfig_warn success Errors and warnings before: 0 this patch: 0
netdev/checkpatch success total: 0 errors, 0 warnings, 0 checks, 52 lines checked
netdev/build_clang_rust success No Rust files in patch. Skipping build
netdev/kdoc success Errors and warnings before: 50 this patch: 50
netdev/source_inline success Was 0 now: 0

Commit Message

Alexander Lobakin March 5, 2025, 4:21 p.m. UTC
Add the missing linking of NAPIs to netdev queues when enabling
interrupt vectors in order to support NAPI configuration and
interfaces requiring get_rx_queue()->napi to be set (like XSk
busy polling).

Signed-off-by: Alexander Lobakin <aleksander.lobakin@intel.com>
---
 drivers/net/ethernet/intel/idpf/idpf_txrx.c | 30 +++++++++++++++++++++
 1 file changed, 30 insertions(+)

Comments

Eric Dumazet March 7, 2025, 10:28 a.m. UTC | #1
On Wed, Mar 5, 2025 at 5:22 PM Alexander Lobakin
<aleksander.lobakin@intel.com> wrote:
>
> Add the missing linking of NAPIs to netdev queues when enabling
> interrupt vectors in order to support NAPI configuration and
> interfaces requiring get_rx_queue()->napi to be set (like XSk
> busy polling).
>
> Signed-off-by: Alexander Lobakin <aleksander.lobakin@intel.com>
> ---
>  drivers/net/ethernet/intel/idpf/idpf_txrx.c | 30 +++++++++++++++++++++
>  1 file changed, 30 insertions(+)
>
> diff --git a/drivers/net/ethernet/intel/idpf/idpf_txrx.c b/drivers/net/ethernet/intel/idpf/idpf_txrx.c
> index 2f221c0abad8..a3f6e8cff7a0 100644
> --- a/drivers/net/ethernet/intel/idpf/idpf_txrx.c
> +++ b/drivers/net/ethernet/intel/idpf/idpf_txrx.c
> @@ -3560,8 +3560,11 @@ void idpf_vport_intr_rel(struct idpf_vport *vport)
>  static void idpf_vport_intr_rel_irq(struct idpf_vport *vport)
>  {
>         struct idpf_adapter *adapter = vport->adapter;
> +       bool unlock;
>         int vector;
>
> +       unlock = rtnl_trylock();

This is probably not what you want here ?

If another thread is holding RTNL, then rtnl_ttrylock() will not add
any protection.
Maciej Fijalkowski March 7, 2025, 10:51 a.m. UTC | #2
On Wed, Mar 05, 2025 at 05:21:23PM +0100, Alexander Lobakin wrote:
> Add the missing linking of NAPIs to netdev queues when enabling
> interrupt vectors in order to support NAPI configuration and
> interfaces requiring get_rx_queue()->napi to be set (like XSk
> busy polling).
> 
> Signed-off-by: Alexander Lobakin <aleksander.lobakin@intel.com>
> ---
>  drivers/net/ethernet/intel/idpf/idpf_txrx.c | 30 +++++++++++++++++++++
>  1 file changed, 30 insertions(+)
> 
> diff --git a/drivers/net/ethernet/intel/idpf/idpf_txrx.c b/drivers/net/ethernet/intel/idpf/idpf_txrx.c
> index 2f221c0abad8..a3f6e8cff7a0 100644
> --- a/drivers/net/ethernet/intel/idpf/idpf_txrx.c
> +++ b/drivers/net/ethernet/intel/idpf/idpf_txrx.c
> @@ -3560,8 +3560,11 @@ void idpf_vport_intr_rel(struct idpf_vport *vport)
>  static void idpf_vport_intr_rel_irq(struct idpf_vport *vport)
>  {
>  	struct idpf_adapter *adapter = vport->adapter;
> +	bool unlock;
>  	int vector;
>  
> +	unlock = rtnl_trylock();
> +
>  	for (vector = 0; vector < vport->num_q_vectors; vector++) {
>  		struct idpf_q_vector *q_vector = &vport->q_vectors[vector];
>  		int irq_num, vidx;
> @@ -3573,8 +3576,23 @@ static void idpf_vport_intr_rel_irq(struct idpf_vport *vport)
>  		vidx = vport->q_vector_idxs[vector];
>  		irq_num = adapter->msix_entries[vidx].vector;
>  
> +		for (u32 i = 0; i < q_vector->num_rxq; i++)
> +			netif_queue_set_napi(vport->netdev,
> +					     q_vector->rx[i]->idx,
> +					     NETDEV_QUEUE_TYPE_RX,
> +					     NULL);
> +
> +		for (u32 i = 0; i < q_vector->num_txq; i++)
> +			netif_queue_set_napi(vport->netdev,
> +					     q_vector->tx[i]->idx,
> +					     NETDEV_QUEUE_TYPE_TX,
> +					     NULL);
> +

maybe we could have a wrapper for this?

static void idpf_q_set_napi(struct net_device *netdev,
			    struct idpf_q_vector *q_vector,
			    enum netdev_queue_type q_type,
			    struct napi_struct *napi)
{
	u32 q_cnt = q_type == NETDEV_QUEUE_TYPE_RX ? q_vector->num_rxq :
						     q_vector->num_txq;
	struct idpf_rx_queue **qs = q_type == NETDEV_QUEUE_TYPE_RX ?
					      q_vector->rx : q_vector->tx;

	for (u32 i = 0; i < q_cnt; i++)
		netif_queue_set_napi(netdev, qs[i]->idx, q_type, napi);
}

idpf_q_set_napi(vport->netdev, q_vector, NETDEV_QUEUE_TYPE_RX, NULL);
idpf_q_set_napi(vport->netdev, q_vector, NETDEV_QUEUE_TYPE_TX, NULL);
...
idpf_q_set_napi(vport->netdev, q_vector, NETDEV_QUEUE_TYPE_RX, &q_vector->napi);
idpf_q_set_napi(vport->netdev, q_vector, NETDEV_QUEUE_TYPE_TX, &q_vector->napi);


up to you if you take it, less lines in the end but i don't have strong
opinion if this should be considered as an improvement or makes code
harder to follow.

>  		kfree(free_irq(irq_num, q_vector));
>  	}
> +
> +	if (unlock)
> +		rtnl_unlock();
>  }
>  
>  /**
> @@ -3760,6 +3778,18 @@ static int idpf_vport_intr_req_irq(struct idpf_vport *vport)
>  				   "Request_irq failed, error: %d\n", err);
>  			goto free_q_irqs;
>  		}
> +
> +		for (u32 i = 0; i < q_vector->num_rxq; i++)
> +			netif_queue_set_napi(vport->netdev,
> +					     q_vector->rx[i]->idx,
> +					     NETDEV_QUEUE_TYPE_RX,
> +					     &q_vector->napi);
> +
> +		for (u32 i = 0; i < q_vector->num_txq; i++)
> +			netif_queue_set_napi(vport->netdev,
> +					     q_vector->tx[i]->idx,
> +					     NETDEV_QUEUE_TYPE_TX,
> +					     &q_vector->napi);
>  	}
>  
>  	return 0;
> -- 
> 2.48.1
>
Alexander Lobakin March 12, 2025, 5:16 p.m. UTC | #3
From: Eric Dumazet <edumazet@google.com>
Date: Fri, 7 Mar 2025 11:28:36 +0100

> On Wed, Mar 5, 2025 at 5:22 PM Alexander Lobakin
> <aleksander.lobakin@intel.com> wrote:
>>
>> Add the missing linking of NAPIs to netdev queues when enabling
>> interrupt vectors in order to support NAPI configuration and
>> interfaces requiring get_rx_queue()->napi to be set (like XSk
>> busy polling).
>>
>> Signed-off-by: Alexander Lobakin <aleksander.lobakin@intel.com>
>> ---
>>  drivers/net/ethernet/intel/idpf/idpf_txrx.c | 30 +++++++++++++++++++++
>>  1 file changed, 30 insertions(+)
>>
>> diff --git a/drivers/net/ethernet/intel/idpf/idpf_txrx.c b/drivers/net/ethernet/intel/idpf/idpf_txrx.c
>> index 2f221c0abad8..a3f6e8cff7a0 100644
>> --- a/drivers/net/ethernet/intel/idpf/idpf_txrx.c
>> +++ b/drivers/net/ethernet/intel/idpf/idpf_txrx.c
>> @@ -3560,8 +3560,11 @@ void idpf_vport_intr_rel(struct idpf_vport *vport)
>>  static void idpf_vport_intr_rel_irq(struct idpf_vport *vport)
>>  {
>>         struct idpf_adapter *adapter = vport->adapter;
>> +       bool unlock;
>>         int vector;
>>
>> +       unlock = rtnl_trylock();
> 
> This is probably not what you want here ?
> 
> If another thread is holding RTNL, then rtnl_ttrylock() will not add
> any protection.

Yep I know. trylock() is because this function can be called in two
scenarios:

1) .ndo_close(), when RTNL is already locked;
2) "soft reset" aka "stop the traffic, reallocate the queues, start the
   traffic", when RTNL is not taken.

The second one spits a WARN without the RTNL being locked. So this
trylock() will do nothing for the first scenario and will take the lock
for the second one.

If that is not correct, let me know, I'll do it a different way (maybe
it's better to unconditionally take the lock on the callsite for the
second case?).

Thanks,
Olek
Alexander Lobakin March 12, 2025, 5:25 p.m. UTC | #4
From: Maciej Fijalkowski <maciej.fijalkowski@intel.com>
Date: Fri, 7 Mar 2025 11:51:18 +0100

> On Wed, Mar 05, 2025 at 05:21:23PM +0100, Alexander Lobakin wrote:
>> Add the missing linking of NAPIs to netdev queues when enabling
>> interrupt vectors in order to support NAPI configuration and
>> interfaces requiring get_rx_queue()->napi to be set (like XSk
>> busy polling).
>>
>> Signed-off-by: Alexander Lobakin <aleksander.lobakin@intel.com>
>> ---
>>  drivers/net/ethernet/intel/idpf/idpf_txrx.c | 30 +++++++++++++++++++++
>>  1 file changed, 30 insertions(+)
>>
>> diff --git a/drivers/net/ethernet/intel/idpf/idpf_txrx.c b/drivers/net/ethernet/intel/idpf/idpf_txrx.c
>> index 2f221c0abad8..a3f6e8cff7a0 100644
>> --- a/drivers/net/ethernet/intel/idpf/idpf_txrx.c
>> +++ b/drivers/net/ethernet/intel/idpf/idpf_txrx.c
>> @@ -3560,8 +3560,11 @@ void idpf_vport_intr_rel(struct idpf_vport *vport)
>>  static void idpf_vport_intr_rel_irq(struct idpf_vport *vport)
>>  {
>>  	struct idpf_adapter *adapter = vport->adapter;
>> +	bool unlock;
>>  	int vector;
>>  
>> +	unlock = rtnl_trylock();
>> +
>>  	for (vector = 0; vector < vport->num_q_vectors; vector++) {
>>  		struct idpf_q_vector *q_vector = &vport->q_vectors[vector];
>>  		int irq_num, vidx;
>> @@ -3573,8 +3576,23 @@ static void idpf_vport_intr_rel_irq(struct idpf_vport *vport)
>>  		vidx = vport->q_vector_idxs[vector];
>>  		irq_num = adapter->msix_entries[vidx].vector;
>>  
>> +		for (u32 i = 0; i < q_vector->num_rxq; i++)
>> +			netif_queue_set_napi(vport->netdev,
>> +					     q_vector->rx[i]->idx,
>> +					     NETDEV_QUEUE_TYPE_RX,
>> +					     NULL);
>> +
>> +		for (u32 i = 0; i < q_vector->num_txq; i++)
>> +			netif_queue_set_napi(vport->netdev,
>> +					     q_vector->tx[i]->idx,
>> +					     NETDEV_QUEUE_TYPE_TX,
>> +					     NULL);
>> +
> 
> maybe we could have a wrapper for this?
> 
> static void idpf_q_set_napi(struct net_device *netdev,
> 			    struct idpf_q_vector *q_vector,
> 			    enum netdev_queue_type q_type,
> 			    struct napi_struct *napi)
> {
> 	u32 q_cnt = q_type == NETDEV_QUEUE_TYPE_RX ? q_vector->num_rxq :
> 						     q_vector->num_txq;
> 	struct idpf_rx_queue **qs = q_type == NETDEV_QUEUE_TYPE_RX ?
> 					      q_vector->rx : q_vector->tx;
> 
> 	for (u32 i = 0; i < q_cnt; i++)
> 		netif_queue_set_napi(netdev, qs[i]->idx, q_type, napi);
> }
> 
> idpf_q_set_napi(vport->netdev, q_vector, NETDEV_QUEUE_TYPE_RX, NULL);
> idpf_q_set_napi(vport->netdev, q_vector, NETDEV_QUEUE_TYPE_TX, NULL);
> ...
> idpf_q_set_napi(vport->netdev, q_vector, NETDEV_QUEUE_TYPE_RX, &q_vector->napi);
> idpf_q_set_napi(vport->netdev, q_vector, NETDEV_QUEUE_TYPE_TX, &q_vector->napi);
> 
> 
> up to you if you take it, less lines in the end but i don't have strong
> opinion if this should be considered as an improvement or makes code
> harder to follow.

No no, it's actually a good idea. Previously, it looked different, but
then this stuff with the CPU affinity embedded into the NAPI config got
merged and I had to rewrite this in the last minute.

> 
>>  		kfree(free_irq(irq_num, q_vector));
>>  	}
>> +
>> +	if (unlock)
>> +		rtnl_unlock();
>>  }

Thanks,
Olek
Alexander Lobakin March 18, 2025, 5:10 p.m. UTC | #5
From: Alexander Lobakin <aleksander.lobakin@intel.com>
Date: Wed, 12 Mar 2025 18:16:11 +0100

> From: Eric Dumazet <edumazet@google.com>
> Date: Fri, 7 Mar 2025 11:28:36 +0100
> 
>> On Wed, Mar 5, 2025 at 5:22 PM Alexander Lobakin
>> <aleksander.lobakin@intel.com> wrote:
>>>
>>> Add the missing linking of NAPIs to netdev queues when enabling
>>> interrupt vectors in order to support NAPI configuration and
>>> interfaces requiring get_rx_queue()->napi to be set (like XSk
>>> busy polling).
>>>
>>> Signed-off-by: Alexander Lobakin <aleksander.lobakin@intel.com>
>>> ---
>>>  drivers/net/ethernet/intel/idpf/idpf_txrx.c | 30 +++++++++++++++++++++
>>>  1 file changed, 30 insertions(+)
>>>
>>> diff --git a/drivers/net/ethernet/intel/idpf/idpf_txrx.c b/drivers/net/ethernet/intel/idpf/idpf_txrx.c
>>> index 2f221c0abad8..a3f6e8cff7a0 100644
>>> --- a/drivers/net/ethernet/intel/idpf/idpf_txrx.c
>>> +++ b/drivers/net/ethernet/intel/idpf/idpf_txrx.c
>>> @@ -3560,8 +3560,11 @@ void idpf_vport_intr_rel(struct idpf_vport *vport)
>>>  static void idpf_vport_intr_rel_irq(struct idpf_vport *vport)
>>>  {
>>>         struct idpf_adapter *adapter = vport->adapter;
>>> +       bool unlock;
>>>         int vector;
>>>
>>> +       unlock = rtnl_trylock();
>>
>> This is probably not what you want here ?
>>
>> If another thread is holding RTNL, then rtnl_ttrylock() will not add
>> any protection.
> 
> Yep I know. trylock() is because this function can be called in two
> scenarios:
> 
> 1) .ndo_close(), when RTNL is already locked;
> 2) "soft reset" aka "stop the traffic, reallocate the queues, start the
>    traffic", when RTNL is not taken.
> 
> The second one spits a WARN without the RTNL being locked. So this
> trylock() will do nothing for the first scenario and will take the lock
> for the second one.
> 
> If that is not correct, let me know, I'll do it a different way (maybe
> it's better to unconditionally take the lock on the callsite for the
> second case?).

Ping. What should I do, lock RTNL on the callsite or proceed with trylock?

Thanks,
Olek
diff mbox series

Patch

diff --git a/drivers/net/ethernet/intel/idpf/idpf_txrx.c b/drivers/net/ethernet/intel/idpf/idpf_txrx.c
index 2f221c0abad8..a3f6e8cff7a0 100644
--- a/drivers/net/ethernet/intel/idpf/idpf_txrx.c
+++ b/drivers/net/ethernet/intel/idpf/idpf_txrx.c
@@ -3560,8 +3560,11 @@  void idpf_vport_intr_rel(struct idpf_vport *vport)
 static void idpf_vport_intr_rel_irq(struct idpf_vport *vport)
 {
 	struct idpf_adapter *adapter = vport->adapter;
+	bool unlock;
 	int vector;
 
+	unlock = rtnl_trylock();
+
 	for (vector = 0; vector < vport->num_q_vectors; vector++) {
 		struct idpf_q_vector *q_vector = &vport->q_vectors[vector];
 		int irq_num, vidx;
@@ -3573,8 +3576,23 @@  static void idpf_vport_intr_rel_irq(struct idpf_vport *vport)
 		vidx = vport->q_vector_idxs[vector];
 		irq_num = adapter->msix_entries[vidx].vector;
 
+		for (u32 i = 0; i < q_vector->num_rxq; i++)
+			netif_queue_set_napi(vport->netdev,
+					     q_vector->rx[i]->idx,
+					     NETDEV_QUEUE_TYPE_RX,
+					     NULL);
+
+		for (u32 i = 0; i < q_vector->num_txq; i++)
+			netif_queue_set_napi(vport->netdev,
+					     q_vector->tx[i]->idx,
+					     NETDEV_QUEUE_TYPE_TX,
+					     NULL);
+
 		kfree(free_irq(irq_num, q_vector));
 	}
+
+	if (unlock)
+		rtnl_unlock();
 }
 
 /**
@@ -3760,6 +3778,18 @@  static int idpf_vport_intr_req_irq(struct idpf_vport *vport)
 				   "Request_irq failed, error: %d\n", err);
 			goto free_q_irqs;
 		}
+
+		for (u32 i = 0; i < q_vector->num_rxq; i++)
+			netif_queue_set_napi(vport->netdev,
+					     q_vector->rx[i]->idx,
+					     NETDEV_QUEUE_TYPE_RX,
+					     &q_vector->napi);
+
+		for (u32 i = 0; i < q_vector->num_txq; i++)
+			netif_queue_set_napi(vport->netdev,
+					     q_vector->tx[i]->idx,
+					     NETDEV_QUEUE_TYPE_TX,
+					     &q_vector->napi);
 	}
 
 	return 0;