Netdev List
 help / color / mirror / Atom feed
From: "mengyuanlou@net-swift.com" <mengyuanlou@net-swift.com>
To: Harshitha Ramamurthy <hramamurthy@google.com>
Cc: netdev@vger.kernel.org, jiawenwu@trustnetic.com,
	duanqiangwen@net-swift.com, linglingzhang@net-swift.com,
	andrew+netdev@lunn.ch, davem@davemloft.net, edumazet@google.com,
	kuba@kernel.org, pabeni@redhat.com, jacob.e.keller@intel.com,
	przemyslaw.kitszel@intel.com, u.kleine-koenig@baylibre.com
Subject: Re: [PATCH net-next] net: libwx: Add ethtool -L support for VF drivers
Date: Thu, 17 Sep 2026 14:43:14 +0800	[thread overview]
Message-ID: <5151C867-ACED-4B65-A4FC-184CC432F3B2@net-swift.com> (raw)
In-Reply-To: <CAEAWyHfFYryMvtb+9XRY-hjjDpxiZUjfKX9ShK4My7Wtz-Dj2w@mail.gmail.com>



> 2026年9月16日 03:19,Harshitha Ramamurthy <hramamurthy@google.com> 写道:
> 
> On Tue, Sep 15, 2026 at 3:18 AM Mengyuan Lou <mengyuanlou@net-swift.com> wrote:
>> 
>> Implement get_channels and set_channels ethtool operations for Wangxun
>> VF net_device instances in libwx.
>> 
>> This allows users to query and dynamically reconfigure the number of RX/TX
>> channels on VF interfaces via `ethtool -l/ -L`.
>> 
>> Specifically:
>> - Add wx_get_channels_vf() and wx_set_channels_vf() to report and update
>>  channel limits and combined queue counts.
>> - Re-evaluate RSS limits in txgbevf_set_num_queues() based on user settings
>>  stored in wx->ring_feature[RING_F_RSS].limit.
>> - Adjust VF MRQC RSS hash mask logic in wx_setup_vfmrqc_vf() to correctly
>>  match queue configuration thresholds.
>> 
>> Signed-off-by: Mengyuan Lou <mengyuanlou@net-swift.com>
>> ---
>> .../net/ethernet/wangxun/libwx/wx_ethtool.c   | 64 +++++++++++++++++++
>> .../net/ethernet/wangxun/libwx/wx_vf_lib.c    |  2 +-
>> .../ethernet/wangxun/txgbevf/txgbevf_main.c   |  3 +
>> 3 files changed, 68 insertions(+), 1 deletion(-)
>> 
>> diff --git a/drivers/net/ethernet/wangxun/libwx/wx_ethtool.c b/drivers/net/ethernet/wangxun/libwx/wx_ethtool.c
>> index 940d2e59876c..d24370790941 100644
>> --- a/drivers/net/ethernet/wangxun/libwx/wx_ethtool.c
>> +++ b/drivers/net/ethernet/wangxun/libwx/wx_ethtool.c
>> @@ -564,6 +564,68 @@ int wx_set_channels(struct net_device *dev,
>> }
>> EXPORT_SYMBOL(wx_set_channels);
>> 
>> +static void wx_get_channels_vf(struct net_device *dev,
>> +                              struct ethtool_channels *ch)
>> +{
>> +       struct wx *wx = netdev_priv(dev);
>> +
>> +       /* report maximum channels */
>> +       ch->max_combined = wx->mac.max_rx_queues;
>> +
>> +       ch->max_other = 1;
>> +       ch->other_count = 1;
>> +
>> +       /* record current channels */
>> +       ch->combined_count = wx->num_rx_queues;
>> +}
>> +
>> +static int wx_set_channels_vf(struct net_device *dev,
>> +                             struct ethtool_channels *ch)
>> +{
>> +       struct wx *wx = netdev_priv(dev);
>> +       u16 rss_limit;
>> +       int ret;
>> +
>> +       rss_limit = wx->ring_feature[RING_F_RSS].limit;
>> +
>> +       /* verify other_count has not changed */
>> +       if (ch->other_count != 1)
>> +               return -EINVAL;
>> +
>> +       /* verify the number of channels does not exceed hardware limits */
>> +       if (ch->combined_count > wx->mac.max_rx_queues)
>> +               return -EINVAL;
>> +
>> +       /* if device is resetting, do nothing */
>> +       if (test_bit(WX_STATE_RESETTING, wx->state))
>> +               return -EBUSY;
>> +
>> +       wx->ring_feature[RING_F_RSS].limit = ch->combined_count;
>> +
>> +       if (netif_running(dev))
>> +               wxvf_close(dev);
> 
> The precedent has been for some time now that drivers are required to
> pre-allocate resources for the new queue counts before tearing down
> the existing ones. So that the driver doesn't knock itself out if
> something fails when attempting to apply the new configuration.
> 
> Look at the nfp_net_ring_config() or gve_adjust_config() for examples:
> both try to allocate memory for the new config first.

Thanks for the feedback.

I understand that pre-allocating resources before tearing down existing queues
("prepare-then-commit") is the ideal pattern used by drivers like NFP and GVE
to ensure zero-downtime or graceful failure recovery during queue reconfigurations.

However, adopting the NFP/GVE pre-allocation model is not technically feasible
for WangXun VF without closing the device first.

1. MSI-X Vector Lifecycle Constraints
	Unlike NFP (which can dynamically manage dual sets of MSI-X vectors) or GVE
(which pre-allocates all possible MSI-X vectors at probe time and only resizes
queues afterwards), WangXun VF acquires its MSI-X vectors in a single lump sum
via pci_alloc_irq_vectors_affinity().
    • To change the vector count or reconfigure queue-to-vector mappings, Linux
	PCI architecture requires freeing all active vectors via pci_free_irq_vectors()
	before requesting new ones.
    • Freeing active MSI-X vectors requires teardown of the current interrupt scheme,
	which cannot be safely done while the interface remains RUNNING.
2. NAPI Registration Constraints (netif_napi_add)
	Each queue vector allocates a struct wx_q_vector and registers a NAPI instance via
netif_napi_add().
    • In the WangXun driver architecture, NAPI instances are tightly bound to the
	queue/vector layout.
    • Allocating new q_vectors and invoking netif_napi_add() while the driver is running
	risks duplicate NAPI registrations or corrupted polling state. Therefore, the
	device must be down (wxvf_close) before cleaning up old NAPI instances and
	instantiating new ones.



%%{init: {'theme':'base','themeVariables':{'primaryColor':'#dd6b20','edgeLabelBackground':'#fff','clusterBkg':'#fff5f5','clusterBorder':'#fdba74'}}}%%
graph TD
    %% --------------------------------------------------------------
    %% Entry & parameter checks
    %% --------------------------------------------------------------
    A[wx_set_channels_vf(dev, ch)]
    A --> B[if (ch->other_count != 1)  →  -EINVAL]
    B --> C[if (ch->combined_count > wx->mac.max_rx_queues)  →  -EINVAL]
    C --> D[if (test_bit(WX_STATE_RESETTING, wx->state))  →  -EBUSY]

    %% --------------------------------------------------------------
    %% Must stop the VF first if it is running
    %% --------------------------------------------------------------
    D -->|netif_running(dev)| E[wxvf_close(dev)   // stop Tx/Rx, disable NAPI, free resources]
    D -->|!netif_running(dev)| F[(skip) ]

    %% --------------------------------------------------------------
    %% Completely clear the current interrupt scheme (including MSI‑X)
    %% --------------------------------------------------------------
    E --> G[wx_clear_interrupt_scheme(wx)]
    subgraph G[wx_clear_interrupt_scheme(wx) details]
        direction TB
        G1[wx_free_q_vectors(wx)                 // free q_vectors only]
        G2[wx_reset_interrupt_capability(wx)    // free MSI‑X vectors (pci_free_irq_vectors)]
        G1 --> G2
    end

    %% --------------------------------------------------------------
    %% Re‑initialize the whole interrupt scheme (allocate MSI‑X, q_vectors, rings)
    %% --------------------------------------------------------------
    G --> H[wx_init_interrupt_scheme(wx)]
    subgraph H[wx_init_interrupt_scheme(wx) details]
        direction TB
        H1[wx_set_num_queues(wx)                 // recompute num_tx/num_rx/num_q_vectors]
        H2[wx_set_interrupt_capability(wx)       // request MSI‑X vectors (pci_alloc_irq_vectors)]
        H3[wx_alloc_q_vectors(wx)               // allocate q_vector structs and rings (netif_napi_add)]
        H4[wx_cache_ring_rss(wx)                 // compute RSS reg_idx and program hardware]
        H5[set_bit(WX_STATE_DOWN, wx->state)]
        H1 --> H2 --> H3 --> H4 --> H5
    end

    %% --------------------------------------------------------------
    %% If the device was running before, open it again
    %% --------------------------------------------------------------
    H -->|netif_running(dev) after re‑init| I[wxvf_open(dev)   // re‑enable NAPI, wake Tx/Rx]
    H -->|!netif_running(dev) after re‑init| J[return 0]

    I --> K[return 0  // success]
    J --> K

    %% --------------------------------------------------------------
    %% Error path – restore old RSS limit and return error
    %% --------------------------------------------------------------
    H -->|ret != 0| L[restore original RSS limit & return error]

    %% --------------------------------------------------------------
    %% Conflict points (why we cannot “prepare‑first, close‑later”)
    %% --------------------------------------------------------------
    classDef note fill:#fffae6,color:#333,stroke:#ffa726;


    N1[**Conflict 1**: MSI‑X vectors are allocated only once (wx_set_interrupt_capability) – a new allocation requires pci_free_irq_vectors(), which can be done only after the old vectors are released (i.e. after the device is closed).]:::note
    N2[**Conflict 2**: netif_napi_add() (called inside wx_alloc_q_vectors) must be executed while the device is not RUNNING; otherwise double‑registration of NAPI leads to bugs.]:::note
    N3[**Conflict 3**: Hardware register mapping (reg_idx, RSS tables) must be programmed before the device is opened; changing them while the hardware is running causes race‑conditions.]:::note

    N1 -.-> H2
    N2 -.-> H3
    N3 -.-> H4





 |
|------|----------|----------|
| **NFP** | `nfp_net_set_channels()` → `nfp_net_ring_reconfig()`

**GVE** | `gve_set_channels()` → `gve_adjust_queues()` → `gve_adjust_config()`

NFP
 * struct nfp_net_dp - NFP network device datapath data structure

gve
   struct gve_tx_alloc_rings_cfg tx_alloc_cfg = {0};
   struct gve_rx_alloc_rings_cfg rx_alloc_cfg = {0};

The allocation of interrupt resources and ring resources can be separated
which Wangxun vf can not do it.







> 
>> +
>> +       wx_clear_interrupt_scheme(wx);
>> +
>> +       ret = wx_init_interrupt_scheme(wx);
>> +       if (ret)
>> +               goto err_out;
>> +
>> +       if (netif_running(dev)) {
>> +               ret = wxvf_open(dev);
>> +               if (ret)
>> +                       goto err_close;
>> +       }
>> +
>> +       return 0;
>> +
>> +err_close:
>> +       wx_clear_interrupt_scheme(wx);
>> +err_out:
>> +       wx->ring_feature[RING_F_RSS].limit = rss_limit;
>> +       return ret;
>> +}
>> +
>> u32 wx_rss_indir_size(struct net_device *netdev)
>> {
>>        struct wx *wx = netdev_priv(netdev);
>> @@ -852,6 +914,8 @@ static const struct ethtool_ops wx_ethtool_ops_vf = {
>>        .set_coalesce           = wx_set_coalesce,
>>        .get_ts_info            = ethtool_op_get_ts_info,
>>        .get_link_ksettings     = wx_get_link_ksettings_vf,
>> +       .get_channels           = wx_get_channels_vf,
>> +       .set_channels           = wx_set_channels_vf,
>> };
>> 
>> void wx_set_ethtool_ops_vf(struct net_device *netdev)
>> diff --git a/drivers/net/ethernet/wangxun/libwx/wx_vf_lib.c b/drivers/net/ethernet/wangxun/libwx/wx_vf_lib.c
>> index 7325b475ee10..6fec3ab5e4e4 100644
>> --- a/drivers/net/ethernet/wangxun/libwx/wx_vf_lib.c
>> +++ b/drivers/net/ethernet/wangxun/libwx/wx_vf_lib.c
>> @@ -237,7 +237,7 @@ void wx_setup_vfmrqc_vf(struct wx *wx)
>> 
>>        vfmrqc |= WX_VXMRQC_RSS_EN;
>> 
>> -       if (wx->num_rx_queues > 3)
>> +       if (wx->num_rx_queues >= 3)
>>                vfmrqc |= WX_VXMRQC_RSS_HASH(2);
>>        else if (wx->num_rx_queues > 1)
>>                vfmrqc |= WX_VXMRQC_RSS_HASH(1);
>> diff --git a/drivers/net/ethernet/wangxun/txgbevf/txgbevf_main.c b/drivers/net/ethernet/wangxun/txgbevf/txgbevf_main.c
>> index 8b16b900820a..6e8659082051 100644
>> --- a/drivers/net/ethernet/wangxun/txgbevf/txgbevf_main.c
>> +++ b/drivers/net/ethernet/wangxun/txgbevf/txgbevf_main.c
>> @@ -72,6 +72,9 @@ static void txgbevf_set_num_queues(struct wx *wx)
>>                queue = min_t(u16, wx->mac.max_rx_queues, wx->mac.max_tx_queues);
>>                rss = min_t(u16, queue, rss);
>> 
>> +               if (wx->ring_feature[RING_F_RSS].limit)
>> +                       rss = min_t(u16, rss, wx->ring_feature[RING_F_RSS].limit);
>> +
>>                if (wx->vfinfo->vf_api >= wx_mbox_api_13) {
>>                        wx->num_rx_queues = rss;
>>                        wx->num_tx_queues = rss;
>> --
>> 2.30.1
>> 
>> 
>> 
> 
> 


  reply	other threads:[~2026-09-17  6:45 UTC|newest]

Thread overview: 4+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-09-15  9:37 [PATCH net-next] net: libwx: Add ethtool -L support for VF drivers Mengyuan Lou
2026-09-15 19:19 ` Harshitha Ramamurthy
2026-09-17  6:43   ` mengyuanlou [this message]
2026-09-19  1:51 ` netdev-bot+sashiko

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=5151C867-ACED-4B65-A4FC-184CC432F3B2@net-swift.com \
    --to=mengyuanlou@net-swift.com \
    --cc=andrew+netdev@lunn.ch \
    --cc=davem@davemloft.net \
    --cc=duanqiangwen@net-swift.com \
    --cc=edumazet@google.com \
    --cc=hramamurthy@google.com \
    --cc=jacob.e.keller@intel.com \
    --cc=jiawenwu@trustnetic.com \
    --cc=kuba@kernel.org \
    --cc=linglingzhang@net-swift.com \
    --cc=netdev@vger.kernel.org \
    --cc=pabeni@redhat.com \
    --cc=przemyslaw.kitszel@intel.com \
    --cc=u.kleine-koenig@baylibre.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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox