* [PATCH iwl-next v1 01/15] devlink, mlx5: add init/fini ops for shared devlink
2026-05-08 12:41 [PATCH iwl-next v1 00/15] devlink, mlx5, iavf, ice: XLVF for iavf Przemek Kitszel
@ 2026-05-08 12:41 ` Przemek Kitszel
2026-05-11 11:36 ` Jiri Pirko
2026-05-08 12:41 ` [PATCH iwl-next v1 02/15] ice: use shared devlink to store ice_adapters instead of custom xarray Przemek Kitszel
` (13 subsequent siblings)
14 siblings, 1 reply; 28+ messages in thread
From: Przemek Kitszel @ 2026-05-08 12:41 UTC (permalink / raw)
To: intel-wired-lan, Michal Schmidt, Jakub Kicinski, Jiri Pirko
Cc: netdev, Simon Horman, Tony Nguyen, Michal Swiatkowski,
bruce.richardson, Vladimir Medvedkin, padraig.j.connolly,
ananth.s, timothy.miskell, Jacob Keller, Lukasz Czapnik,
Aleksandr Loktionov, Andrew Lunn, David S. Miller, Eric Dumazet,
Paolo Abeni, Saeed Mahameed, Leon Romanovsky, Tariq Toukan,
Mark Bloch, Przemek Kitszel
Add .shd_init() and .shd_fini() ops, that will be called for the first
devlink_shd_get() (to initialize driver' priv data) and on the last
devlink_shd_put() (to allow for the cleanup). Both ops are optional.
.shd_init() could return an error, which will stop creation of shd
instance. The initializer also gets an additional, optional param,
that driver could use for any needs.
If any of the callbacks will need to get devlink instance, it could
be accessed by shd_priv_to_devlink().
Both callbacks are called with devl_lock held and devlink registered.
Next commit will make use of the callbacks, another one will make use also
of the non-null additional param (outside of this series).
Reviewed-by: Aleksandr Loktionov <aleksandr.loktionov@intel.com>
Signed-off-by: Przemek Kitszel <przemyslaw.kitszel@intel.com>
---
(v0) first discussed at:
https://lore.kernel.org/netdev/20260325063143.261806-3-przemyslaw.kitszel@intel.com
v1: remove redundant added blank line (Jiri)
---
include/net/devlink.h | 26 +++++++++++++
.../ethernet/mellanox/mlx5/core/sh_devlink.c | 2 +-
net/devlink/sh_dev.c | 38 ++++++++++++++++++-
3 files changed, 63 insertions(+), 3 deletions(-)
diff --git a/include/net/devlink.h b/include/net/devlink.h
index bcd31de1f890..5d3a1337bfa1 100644
--- a/include/net/devlink.h
+++ b/include/net/devlink.h
@@ -1586,6 +1586,30 @@ struct devlink_ops {
struct devlink_rate *parent,
void *priv_child, void *priv_parent,
struct netlink_ext_ack *extack);
+
+ /**
+ * shd_init: Shared devlink instance initializer
+ * @priv: shd_devlink' priv
+ * @init_param: additional param to pass to driver callback
+ *
+ * Called once when the shared instance is first created (by the first
+ * devlink_shd_get() call).
+ * Should initialize the driver's private data embedded in the shared
+ * devlink. May be NULL.
+ *
+ * Return: 0 on success, negative to prevent shared instance usage.
+ */
+ int (*shd_init)(void *priv, void *init_param);
+ /**
+ * shd_fini: Shared devlink instance finalizer
+ * @priv: shd_devlink' priv
+ *
+ * Called once when the last reference is dropped and the shared
+ * instance is destroyed. Should clean up the driver's private data.
+ * May be NULL.
+ */
+ void (*shd_fini)(void *priv);
+
/**
* selftests_check() - queries if selftest is supported
* @devlink: devlink instance
@@ -1651,9 +1675,11 @@ void devlink_free(struct devlink *devlink);
struct devlink *devlink_shd_get(const char *id,
const struct devlink_ops *ops,
size_t priv_size,
+ void *init_param,
const struct device_driver *driver);
void devlink_shd_put(struct devlink *devlink);
void *devlink_shd_get_priv(struct devlink *devlink);
+struct devlink *shd_priv_to_devlink(void *priv);
/**
* struct devlink_port_ops - Port operations
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/sh_devlink.c b/drivers/net/ethernet/mellanox/mlx5/core/sh_devlink.c
index b925364765ac..1b8b1ce7e72d 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/sh_devlink.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/sh_devlink.c
@@ -43,7 +43,7 @@ int mlx5_shd_init(struct mlx5_core_dev *dev)
*end = '\0';
/* Get or create shared devlink instance */
- devlink = devlink_shd_get(sn, &mlx5_shd_ops, 0, pdev->dev.driver);
+ devlink = devlink_shd_get(sn, &mlx5_shd_ops, 0, NULL, pdev->dev.driver);
kfree(sn);
if (!devlink)
return -ENOMEM;
diff --git a/net/devlink/sh_dev.c b/net/devlink/sh_dev.c
index 85acce97e788..7b9520d3f946 100644
--- a/net/devlink/sh_dev.c
+++ b/net/devlink/sh_dev.c
@@ -34,6 +34,7 @@ static struct devlink_shd *devlink_shd_lookup(const char *id)
static struct devlink_shd *devlink_shd_create(const char *id,
const struct devlink_ops *ops,
size_t priv_size,
+ void *init_param,
const struct device_driver *driver)
{
struct devlink_shd *shd;
@@ -49,16 +50,30 @@ static struct devlink_shd *devlink_shd_create(const char *id,
if (!shd->id)
goto err_devlink_free;
shd->priv_size = priv_size;
- refcount_set(&shd->refcount, 1);
devl_lock(devlink);
devl_register(devlink);
+
+ if (ops->shd_init) {
+ int err;
+
+ err = ops->shd_init(shd->priv, init_param);
+ if (err)
+ goto err_unregister;
+ }
+
devl_unlock(devlink);
+ refcount_set(&shd->refcount, 1);
list_add_tail(&shd->list, &shd_list);
return shd;
+err_unregister:
+ devl_unregister(devlink);
+ devl_unlock(devlink);
+ kfree(shd->id);
+
err_devlink_free:
devlink_free(devlink);
return NULL;
@@ -70,6 +85,10 @@ static void devlink_shd_destroy(struct devlink_shd *shd)
list_del(&shd->list);
devl_lock(devlink);
+
+ if (devlink->ops->shd_fini)
+ devlink->ops->shd_fini(shd->priv);
+
devl_unregister(devlink);
devl_unlock(devlink);
kfree(shd->id);
@@ -81,6 +100,7 @@ static void devlink_shd_destroy(struct devlink_shd *shd)
* @id: Identifier string (e.g., serial number) for the shared instance
* @ops: Devlink operations structure
* @priv_size: Size of private data structure
+ * @init_param: Passed to .shd_init() callback alongside driver's priv
* @driver: Driver associated with the shared devlink instance
*
* Get an existing shared devlink instance identified by @id, or create
@@ -96,16 +116,17 @@ static void devlink_shd_destroy(struct devlink_shd *shd)
struct devlink *devlink_shd_get(const char *id,
const struct devlink_ops *ops,
size_t priv_size,
+ void *init_param,
const struct device_driver *driver)
{
struct devlink *devlink;
struct devlink_shd *shd;
mutex_lock(&shd_mutex);
shd = devlink_shd_lookup(id);
if (!shd) {
- shd = devlink_shd_create(id, ops, priv_size, driver);
+ shd = devlink_shd_create(id, ops, priv_size, init_param, driver);
goto unlock;
}
@@ -159,3 +180,16 @@ void *devlink_shd_get_priv(struct devlink *devlink)
return shd->priv;
}
EXPORT_SYMBOL_GPL(devlink_shd_get_priv);
+
+/** shd_priv_to_devlink - Get devlink instance from shd_devlink's priv
+ * @priv: Driver's priv data
+ *
+ * Return: pointer to shared devlink instance the @priv belongs to.
+ */
+struct devlink *shd_priv_to_devlink(void *priv)
+{
+ struct devlink_shd *shd = container_of(priv, struct devlink_shd, priv);
+
+ return priv_to_devlink(shd);
+}
+EXPORT_SYMBOL_GPL(shd_priv_to_devlink);
--
2.39.3
^ permalink raw reply related [flat|nested] 28+ messages in thread* Re: [PATCH iwl-next v1 01/15] devlink, mlx5: add init/fini ops for shared devlink
2026-05-08 12:41 ` [PATCH iwl-next v1 01/15] devlink, mlx5: add init/fini ops for shared devlink Przemek Kitszel
@ 2026-05-11 11:36 ` Jiri Pirko
2026-05-11 13:26 ` Przemek Kitszel
0 siblings, 1 reply; 28+ messages in thread
From: Jiri Pirko @ 2026-05-11 11:36 UTC (permalink / raw)
To: Przemek Kitszel
Cc: intel-wired-lan, Michal Schmidt, Jakub Kicinski, netdev,
Simon Horman, Tony Nguyen, Michal Swiatkowski, bruce.richardson,
Vladimir Medvedkin, padraig.j.connolly, ananth.s, timothy.miskell,
Jacob Keller, Lukasz Czapnik, Aleksandr Loktionov, Andrew Lunn,
David S. Miller, Eric Dumazet, Paolo Abeni, Saeed Mahameed,
Leon Romanovsky, Tariq Toukan, Mark Bloch
Fri, May 08, 2026 at 02:41:54PM +0200, przemyslaw.kitszel@intel.com wrote:
>Add .shd_init() and .shd_fini() ops, that will be called for the first
>devlink_shd_get() (to initialize driver' priv data) and on the last
>devlink_shd_put() (to allow for the cleanup). Both ops are optional.
>
>.shd_init() could return an error, which will stop creation of shd
>instance. The initializer also gets an additional, optional param,
>that driver could use for any needs.
>
>If any of the callbacks will need to get devlink instance, it could
>be accessed by shd_priv_to_devlink().
>
>Both callbacks are called with devl_lock held and devlink registered.
>
>Next commit will make use of the callbacks, another one will make use also
>of the non-null additional param (outside of this series).
>
>Reviewed-by: Aleksandr Loktionov <aleksandr.loktionov@intel.com>
>Signed-off-by: Przemek Kitszel <przemyslaw.kitszel@intel.com>
>---
>(v0) first discussed at:
>https://lore.kernel.org/netdev/20260325063143.261806-3-przemyslaw.kitszel@intel.com
>
>v1: remove redundant added blank line (Jiri)
>---
> include/net/devlink.h | 26 +++++++++++++
> .../ethernet/mellanox/mlx5/core/sh_devlink.c | 2 +-
> net/devlink/sh_dev.c | 38 ++++++++++++++++++-
> 3 files changed, 63 insertions(+), 3 deletions(-)
>
>diff --git a/include/net/devlink.h b/include/net/devlink.h
>index bcd31de1f890..5d3a1337bfa1 100644
>--- a/include/net/devlink.h
>+++ b/include/net/devlink.h
>@@ -1586,6 +1586,30 @@ struct devlink_ops {
> struct devlink_rate *parent,
> void *priv_child, void *priv_parent,
> struct netlink_ext_ack *extack);
>+
>+ /**
>+ * shd_init: Shared devlink instance initializer
>+ * @priv: shd_devlink' priv
>+ * @init_param: additional param to pass to driver callback
The "param" word still pokes me to the eye. Could we figure out some
different name? "init_ctx" perhaps?
[...]
^ permalink raw reply [flat|nested] 28+ messages in thread* Re: [PATCH iwl-next v1 01/15] devlink, mlx5: add init/fini ops for shared devlink
2026-05-11 11:36 ` Jiri Pirko
@ 2026-05-11 13:26 ` Przemek Kitszel
0 siblings, 0 replies; 28+ messages in thread
From: Przemek Kitszel @ 2026-05-11 13:26 UTC (permalink / raw)
To: Jiri Pirko
Cc: intel-wired-lan, Michal Schmidt, Jakub Kicinski, netdev,
Simon Horman, Tony Nguyen, Michal Swiatkowski, bruce.richardson,
Vladimir Medvedkin, padraig.j.connolly, ananth.s, timothy.miskell,
Jacob Keller, Lukasz Czapnik, Aleksandr Loktionov, Andrew Lunn,
David S. Miller, Eric Dumazet, Paolo Abeni, Saeed Mahameed,
Leon Romanovsky, Tariq Toukan, Mark Bloch
On 5/11/26 13:36, Jiri Pirko wrote:
> Fri, May 08, 2026 at 02:41:54PM +0200, przemyslaw.kitszel@intel.com wrote:
>> Add .shd_init() and .shd_fini() ops, that will be called for the first
>> devlink_shd_get() (to initialize driver' priv data) and on the last
>> devlink_shd_put() (to allow for the cleanup). Both ops are optional.
>>
>> .shd_init() could return an error, which will stop creation of shd
>> instance. The initializer also gets an additional, optional param,
>> that driver could use for any needs.
>>
>> If any of the callbacks will need to get devlink instance, it could
>> be accessed by shd_priv_to_devlink().
>>
>> Both callbacks are called with devl_lock held and devlink registered.
>>
>> Next commit will make use of the callbacks, another one will make use also
>> of the non-null additional param (outside of this series).
>>
>> Reviewed-by: Aleksandr Loktionov <aleksandr.loktionov@intel.com>
>> Signed-off-by: Przemek Kitszel <przemyslaw.kitszel@intel.com>
>> ---
>> (v0) first discussed at:
>> https://lore.kernel.org/netdev/20260325063143.261806-3-przemyslaw.kitszel@intel.com
>>
>> v1: remove redundant added blank line (Jiri)
>> ---
>> include/net/devlink.h | 26 +++++++++++++
>> .../ethernet/mellanox/mlx5/core/sh_devlink.c | 2 +-
>> net/devlink/sh_dev.c | 38 ++++++++++++++++++-
>> 3 files changed, 63 insertions(+), 3 deletions(-)
>>
>> diff --git a/include/net/devlink.h b/include/net/devlink.h
>> index bcd31de1f890..5d3a1337bfa1 100644
>> --- a/include/net/devlink.h
>> +++ b/include/net/devlink.h
>> @@ -1586,6 +1586,30 @@ struct devlink_ops {
>> struct devlink_rate *parent,
>> void *priv_child, void *priv_parent,
>> struct netlink_ext_ack *extack);
>> +
>> + /**
>> + * shd_init: Shared devlink instance initializer
>> + * @priv: shd_devlink' priv
>> + * @init_param: additional param to pass to driver callback
>
> The "param" word still pokes me to the eye. Could we figure out some
> different name? "init_ctx" perhaps?
I like init_ctx,
will wait a bit before v2
>
> [...]
^ permalink raw reply [flat|nested] 28+ messages in thread
* [PATCH iwl-next v1 02/15] ice: use shared devlink to store ice_adapters instead of custom xarray
2026-05-08 12:41 [PATCH iwl-next v1 00/15] devlink, mlx5, iavf, ice: XLVF for iavf Przemek Kitszel
2026-05-08 12:41 ` [PATCH iwl-next v1 01/15] devlink, mlx5: add init/fini ops for shared devlink Przemek Kitszel
@ 2026-05-08 12:41 ` Przemek Kitszel
2026-05-08 12:41 ` [PATCH iwl-next v1 03/15] ice: simplify ice_vc_dis_qs_msg() a little Przemek Kitszel
` (12 subsequent siblings)
14 siblings, 0 replies; 28+ messages in thread
From: Przemek Kitszel @ 2026-05-08 12:41 UTC (permalink / raw)
To: intel-wired-lan, Michal Schmidt, Jakub Kicinski, Jiri Pirko
Cc: netdev, Simon Horman, Tony Nguyen, Michal Swiatkowski,
bruce.richardson, Vladimir Medvedkin, padraig.j.connolly,
ananth.s, timothy.miskell, Jacob Keller, Lukasz Czapnik,
Aleksandr Loktionov, Andrew Lunn, David S. Miller, Eric Dumazet,
Paolo Abeni, Saeed Mahameed, Leon Romanovsky, Tariq Toukan,
Mark Bloch, Przemek Kitszel, Jedrzej Jagielski,
Sergey Temerkhanov
Refactor our storage and deduplication logic of ice_adapters by moving
it to be handled by shared devlink instance, recently added by
Jiri Pirko [1].
We wanted the devlink instance for whole device anyway - later in the
series I will add devlink resources under it.
Make the shared devlink a parent (wrt. nesting) of the actual PF devices.
[1] commit 411ad0605875 ("Merge branch 'devlink-introduce-shared-devlink-instance-for-pfs-on-same-chip'")
[1] https://lore.kernel.org/all/20260312100407.551173-1-jiri@resnulli.us
Reviewed-by: Jedrzej Jagielski <jedrzej.jagielski@intel.com>
Reviewed-by: Aleksandr Loktionov <aleksandr.loktionov@intel.com>
Signed-off-by: Przemek Kitszel <przemyslaw.kitszel@intel.com>
---
CC: Sergey Temerkhanov <sergey.temerkhanov@intel.com>
---
drivers/net/ethernet/intel/ice/ice_adapter.h | 12 +--
.../net/ethernet/intel/ice/devlink/devlink.c | 3 +
drivers/net/ethernet/intel/ice/ice_adapter.c | 97 ++++++-------------
drivers/net/ethernet/intel/ice/ice_main.c | 4 +-
4 files changed, 42 insertions(+), 74 deletions(-)
diff --git a/drivers/net/ethernet/intel/ice/ice_adapter.h b/drivers/net/ethernet/intel/ice/ice_adapter.h
index e95266c7f20b..5539ec5f8515 100644
--- a/drivers/net/ethernet/intel/ice/ice_adapter.h
+++ b/drivers/net/ethernet/intel/ice/ice_adapter.h
@@ -6,7 +6,8 @@
#include <linux/types.h>
#include <linux/spinlock_types.h>
-#include <linux/refcount_types.h>
+
+#include <net/devlink.h>
struct pci_dev;
struct ice_pf;
@@ -27,27 +28,26 @@ struct ice_port_list {
/**
* struct ice_adapter - PCI adapter resources shared across PFs
- * @refcount: Reference count. struct ice_pf objects hold the references.
+ * @devlink: ice adapter's devlink (whole dev devlink)
* @ptp_gltsyn_time_lock: Spinlock protecting access to the GLTSYN_TIME
* register of the PTP clock.
* @txq_ctx_lock: Spinlock protecting access to the GLCOMM_QTX_CNTX_CTL register
* @ctrl_pf: Control PF of the adapter
* @ports: Ports list
- * @index: 64-bit index cached for collision detection on 32bit systems
*/
struct ice_adapter {
- refcount_t refcount;
+ struct devlink *devlink;
+
/* For access to the GLTSYN_TIME register */
spinlock_t ptp_gltsyn_time_lock;
/* For access to GLCOMM_QTX_CNTX_CTL register */
spinlock_t txq_ctx_lock;
struct ice_pf *ctrl_pf;
struct ice_port_list ports;
- u64 index;
};
struct ice_adapter *ice_adapter_get(struct pci_dev *pdev);
-void ice_adapter_put(struct pci_dev *pdev);
+void ice_adapter_put(struct ice_adapter *adapter);
#endif /* _ICE_ADAPTER_H */
diff --git a/drivers/net/ethernet/intel/ice/devlink/devlink.c b/drivers/net/ethernet/intel/ice/devlink/devlink.c
index 641d6e289d5c..f6382d038048 100644
--- a/drivers/net/ethernet/intel/ice/devlink/devlink.c
+++ b/drivers/net/ethernet/intel/ice/devlink/devlink.c
@@ -1750,7 +1750,10 @@ struct ice_sf_priv *ice_allocate_sf(struct device *dev, struct ice_pf *pf)
void ice_devlink_register(struct ice_pf *pf)
{
struct devlink *devlink = priv_to_devlink(pf);
+ struct ice_adapter *adapter = pf->adapter;
+ if (adapter)
+ devl_nested_devlink_set(adapter->devlink, devlink);
devl_register(devlink);
}
diff --git a/drivers/net/ethernet/intel/ice/ice_adapter.c b/drivers/net/ethernet/intel/ice/ice_adapter.c
index cbb57060bd56..d07d349a1692 100644
--- a/drivers/net/ethernet/intel/ice/ice_adapter.c
+++ b/drivers/net/ethernet/intel/ice/ice_adapter.c
@@ -1,18 +1,13 @@
// SPDX-License-Identifier: GPL-2.0-only
// SPDX-FileCopyrightText: Copyright Red Hat
-#include <linux/cleanup.h>
-#include <linux/mutex.h>
#include <linux/pci.h>
#include <linux/slab.h>
#include <linux/spinlock.h>
-#include <linux/xarray.h>
+
#include "ice_adapter.h"
#include "ice.h"
-static DEFINE_XARRAY(ice_adapters);
-static DEFINE_MUTEX(ice_adapters_mutex);
-
#define ICE_ADAPTER_FIXED_INDEX BIT_ULL(63)
#define ICE_ADAPTER_INDEX_E825C \
@@ -40,44 +35,36 @@ static u64 ice_adapter_index(struct pci_dev *pdev)
}
}
-static unsigned long ice_adapter_xa_index(struct pci_dev *pdev)
-{
- u64 index = ice_adapter_index(pdev);
-
-#if BITS_PER_LONG == 64
- return index;
-#else
- return (u32)index ^ (u32)(index >> 32);
-#endif
-}
-
-static struct ice_adapter *ice_adapter_new(struct pci_dev *pdev)
+static int ice_adapter_init(void *priv, void *init_param)
{
- struct ice_adapter *adapter;
+ struct ice_adapter *adapter = priv;
+ struct devlink *devlink;
- adapter = kzalloc_obj(*adapter);
- if (!adapter)
- return NULL;
+ devlink = shd_priv_to_devlink(adapter);
+ adapter->devlink = devlink;
- adapter->index = ice_adapter_index(pdev);
spin_lock_init(&adapter->ptp_gltsyn_time_lock);
spin_lock_init(&adapter->txq_ctx_lock);
- refcount_set(&adapter->refcount, 1);
mutex_init(&adapter->ports.lock);
INIT_LIST_HEAD(&adapter->ports.ports);
- return adapter;
+ return 0;
}
-static void ice_adapter_free(struct ice_adapter *adapter)
+static void ice_adapter_fini(void *priv)
{
+ struct ice_adapter *adapter = priv;
+
WARN_ON(!list_empty(&adapter->ports.ports));
mutex_destroy(&adapter->ports.lock);
-
- kfree(adapter);
}
+static const struct devlink_ops ice_adapter_devlink_ops = {
+ .shd_init = ice_adapter_init,
+ .shd_fini = ice_adapter_fini,
+};
+
/**
* ice_adapter_get - Get a shared ice_adapter structure.
* @pdev: Pointer to the pci_dev whose driver is getting the ice_adapter.
@@ -94,54 +81,32 @@ static void ice_adapter_free(struct ice_adapter *adapter)
struct ice_adapter *ice_adapter_get(struct pci_dev *pdev)
{
struct ice_adapter *adapter;
- unsigned long index;
- int err;
-
- index = ice_adapter_xa_index(pdev);
- scoped_guard(mutex, &ice_adapters_mutex) {
- adapter = xa_load(&ice_adapters, index);
- if (adapter) {
- refcount_inc(&adapter->refcount);
- WARN_ON_ONCE(adapter->index != ice_adapter_index(pdev));
- return adapter;
- }
- err = xa_reserve(&ice_adapters, index, GFP_KERNEL);
- if (err)
- return ERR_PTR(err);
-
- adapter = ice_adapter_new(pdev);
- if (!adapter) {
- xa_release(&ice_adapters, index);
- return ERR_PTR(-ENOMEM);
- }
- xa_store(&ice_adapters, index, adapter, GFP_KERNEL);
- }
+ struct devlink *devlink;
+ char devlink_id[32];
+ u64 index;
+
+ index = ice_adapter_index(pdev);
+ snprintf(devlink_id, sizeof(devlink_id), "%llx", index);
+ devlink = devlink_shd_get(devlink_id, &ice_adapter_devlink_ops,
+ sizeof(*adapter), NULL, pdev->dev.driver);
+ if (!devlink)
+ return ERR_PTR(-ENOMEM);
+
+ adapter = devlink_shd_get_priv(devlink);
+
return adapter;
}
/**
* ice_adapter_put - Release a reference to the shared ice_adapter structure.
- * @pdev: Pointer to the pci_dev whose driver is releasing the ice_adapter.
+ * @adapter: the ice_adapter to release reference to
*
* Releases the reference to ice_adapter previously obtained with
* ice_adapter_get.
*
* Context: Process, may sleep.
*/
-void ice_adapter_put(struct pci_dev *pdev)
+void ice_adapter_put(struct ice_adapter *adapter)
{
- struct ice_adapter *adapter;
- unsigned long index;
-
- index = ice_adapter_xa_index(pdev);
- scoped_guard(mutex, &ice_adapters_mutex) {
- adapter = xa_load(&ice_adapters, index);
- if (WARN_ON(!adapter))
- return;
- if (!refcount_dec_and_test(&adapter->refcount))
- return;
-
- WARN_ON(xa_erase(&ice_adapters, index) != adapter);
- }
- ice_adapter_free(adapter);
+ devlink_shd_put(adapter->devlink);
}
diff --git a/drivers/net/ethernet/intel/ice/ice_main.c b/drivers/net/ethernet/intel/ice/ice_main.c
index 716ac8800559..42d9c4220f43 100644
--- a/drivers/net/ethernet/intel/ice/ice_main.c
+++ b/drivers/net/ethernet/intel/ice/ice_main.c
@@ -5380,7 +5380,7 @@ ice_probe(struct pci_dev *pdev, const struct pci_device_id __always_unused *ent)
unroll_dev_init:
need_dev_deinit = true;
unroll_adapter:
- ice_adapter_put(pdev);
+ ice_adapter_put(adapter);
unroll_hw_init:
ice_deinit_hw(hw);
if (need_dev_deinit)
@@ -5493,7 +5493,7 @@ static void ice_remove(struct pci_dev *pdev)
ice_setup_mc_magic_wake(pf);
ice_set_wake(pf);
- ice_adapter_put(pdev);
+ ice_adapter_put(pf->adapter);
ice_deinit_hw(&pf->hw);
ice_deinit_dev(pf);
--
2.39.3
^ permalink raw reply related [flat|nested] 28+ messages in thread* [PATCH iwl-next v1 03/15] ice: simplify ice_vc_dis_qs_msg() a little
2026-05-08 12:41 [PATCH iwl-next v1 00/15] devlink, mlx5, iavf, ice: XLVF for iavf Przemek Kitszel
2026-05-08 12:41 ` [PATCH iwl-next v1 01/15] devlink, mlx5: add init/fini ops for shared devlink Przemek Kitszel
2026-05-08 12:41 ` [PATCH iwl-next v1 02/15] ice: use shared devlink to store ice_adapters instead of custom xarray Przemek Kitszel
@ 2026-05-08 12:41 ` Przemek Kitszel
2026-05-08 13:31 ` Loktionov, Aleksandr
2026-05-08 12:41 ` [PATCH iwl-next v1 04/15] ice: add VF queue ena/dis helper functions Przemek Kitszel
` (11 subsequent siblings)
14 siblings, 1 reply; 28+ messages in thread
From: Przemek Kitszel @ 2026-05-08 12:41 UTC (permalink / raw)
To: intel-wired-lan, Michal Schmidt, Jakub Kicinski, Jiri Pirko
Cc: netdev, Simon Horman, Tony Nguyen, Michal Swiatkowski,
bruce.richardson, Vladimir Medvedkin, padraig.j.connolly,
ananth.s, timothy.miskell, Jacob Keller, Lukasz Czapnik,
Aleksandr Loktionov, Andrew Lunn, David S. Miller, Eric Dumazet,
Paolo Abeni, Saeed Mahameed, Leon Romanovsky, Tariq Toukan,
Mark Bloch, Przemek Kitszel
Remove special case logic for disabling all queues in ice_vc_dis_qs_msg().
There were no actual speedup from it, the only difference was in saved
bitmap checks, but the HW operations take the majority of time anyway.
ice_vsi_stop_all_rx_rings() used (in the removed code) loops over rings
anyway.
With a message added just before removed code, in the "remove VF" scenario
there were no noticeable difference with the "speedup" and without, and it
takes ~0.06s on my machine from this point to the whole iavf removed, so
really no big deal anyway.
Next commit would otherwise need to complicate the "speedup possible"
check, so it's another reason to simplify here.
Signed-off-by: Przemek Kitszel <przemyslaw.kitszel@intel.com>
---
drivers/net/ethernet/intel/ice/virt/queues.c | 15 +++------------
1 file changed, 3 insertions(+), 12 deletions(-)
diff --git a/drivers/net/ethernet/intel/ice/virt/queues.c b/drivers/net/ethernet/intel/ice/virt/queues.c
index 31be2f76181c..6e4ec681fd07 100644
--- a/drivers/net/ethernet/intel/ice/virt/queues.c
+++ b/drivers/net/ethernet/intel/ice/virt/queues.c
@@ -357,6 +357,8 @@ int ice_vf_vsi_dis_single_txq(struct ice_vf *vf, struct ice_vsi *vsi, u16 q_id)
* @msg: pointer to the msg buffer
*
* called from the VF to disable all or specific queue(s)
+ *
+ * Return: exit code of sending the virtchnl response.
*/
int ice_vc_dis_qs_msg(struct ice_vf *vf, u8 *msg)
{
@@ -406,18 +408,7 @@ int ice_vc_dis_qs_msg(struct ice_vf *vf, u8 *msg)
}
q_map = vqs->rx_queues;
- /* speed up Rx queue disable by batching them if possible */
- if (q_map &&
- bitmap_equal(&q_map, vf->rxq_ena, ICE_MAX_RSS_QS_PER_VF)) {
- if (ice_vsi_stop_all_rx_rings(vsi)) {
- dev_err(ice_pf_to_dev(vsi->back), "Failed to stop all Rx rings on VSI %d\n",
- vsi->vsi_num);
- v_ret = VIRTCHNL_STATUS_ERR_PARAM;
- goto error_param;
- }
-
- bitmap_zero(vf->rxq_ena, ICE_MAX_RSS_QS_PER_VF);
- } else if (q_map) {
+ if (q_map) {
for_each_set_bit(vf_q_id, &q_map, ICE_MAX_RSS_QS_PER_VF) {
if (!ice_vc_isvalid_q_id(vsi, vf_q_id)) {
v_ret = VIRTCHNL_STATUS_ERR_PARAM;
--
2.39.3
^ permalink raw reply related [flat|nested] 28+ messages in thread* RE: [PATCH iwl-next v1 03/15] ice: simplify ice_vc_dis_qs_msg() a little
2026-05-08 12:41 ` [PATCH iwl-next v1 03/15] ice: simplify ice_vc_dis_qs_msg() a little Przemek Kitszel
@ 2026-05-08 13:31 ` Loktionov, Aleksandr
0 siblings, 0 replies; 28+ messages in thread
From: Loktionov, Aleksandr @ 2026-05-08 13:31 UTC (permalink / raw)
To: Kitszel, Przemyslaw, intel-wired-lan@lists.osuosl.org,
Schmidt, Michal, Jakub Kicinski, Jiri Pirko
Cc: netdev@vger.kernel.org, Simon Horman, Nguyen, Anthony L,
Michal Swiatkowski, Richardson, Bruce, Medvedkin, Vladimir,
Connolly, Padraig J, S, Ananth, Miskell, Timothy, Keller, Jacob E,
Czapnik, Lukasz, Andrew Lunn, David S. Miller, Eric Dumazet,
Paolo Abeni, Saeed Mahameed, Leon Romanovsky, Tariq Toukan,
Mark Bloch
> -----Original Message-----
> From: Kitszel, Przemyslaw <przemyslaw.kitszel@intel.com>
> Sent: Friday, May 8, 2026 2:42 PM
> To: intel-wired-lan@lists.osuosl.org; Schmidt, Michal
> <mschmidt@redhat.com>; Jakub Kicinski <kuba@kernel.org>; Jiri Pirko
> <jiri@resnulli.us>
> Cc: netdev@vger.kernel.org; Simon Horman <horms@kernel.org>; Nguyen,
> Anthony L <anthony.l.nguyen@intel.com>; Michal Swiatkowski
> <michal.swiatkowski@linux.intel.com>; Richardson, Bruce
> <bruce.richardson@intel.com>; Medvedkin, Vladimir
> <vladimir.medvedkin@intel.com>; Connolly, Padraig J
> <padraig.j.connolly@intel.com>; S, Ananth <ananth.s@intel.com>;
> Miskell, Timothy <timothy.miskell@intel.com>; Keller, Jacob E
> <jacob.e.keller@intel.com>; Czapnik, Lukasz
> <lukasz.czapnik@intel.com>; Loktionov, Aleksandr
> <aleksandr.loktionov@intel.com>; Andrew Lunn <andrew+netdev@lunn.ch>;
> David S. Miller <davem@davemloft.net>; Eric Dumazet
> <edumazet@google.com>; Paolo Abeni <pabeni@redhat.com>; Saeed Mahameed
> <saeedm@nvidia.com>; Leon Romanovsky <leon@kernel.org>; Tariq Toukan
> <tariqt@nvidia.com>; Mark Bloch <mbloch@nvidia.com>; Kitszel,
> Przemyslaw <przemyslaw.kitszel@intel.com>
> Subject: [PATCH iwl-next v1 03/15] ice: simplify ice_vc_dis_qs_msg() a
> little
>
> Remove special case logic for disabling all queues in
> ice_vc_dis_qs_msg().
> There were no actual speedup from it, the only difference was in saved
> bitmap checks, but the HW operations take the majority of time anyway.
> ice_vsi_stop_all_rx_rings() used (in the removed code) loops over
> rings anyway.
>
> With a message added just before removed code, in the "remove VF"
> scenario there were no noticeable difference with the "speedup" and
> without, and it takes ~0.06s on my machine from this point to the
> whole iavf removed, so really no big deal anyway.
>
> Next commit would otherwise need to complicate the "speedup possible"
> check, so it's another reason to simplify here.
>
> Signed-off-by: Przemek Kitszel <przemyslaw.kitszel@intel.com>
> ---
> drivers/net/ethernet/intel/ice/virt/queues.c | 15 +++------------
> 1 file changed, 3 insertions(+), 12 deletions(-)
>
> diff --git a/drivers/net/ethernet/intel/ice/virt/queues.c
> b/drivers/net/ethernet/intel/ice/virt/queues.c
> index 31be2f76181c..6e4ec681fd07 100644
> --- a/drivers/net/ethernet/intel/ice/virt/queues.c
> +++ b/drivers/net/ethernet/intel/ice/virt/queues.c
> @@ -357,6 +357,8 @@ int ice_vf_vsi_dis_single_txq(struct ice_vf *vf,
> struct ice_vsi *vsi, u16 q_id)
> * @msg: pointer to the msg buffer
> *
> * called from the VF to disable all or specific queue(s)
> + *
> + * Return: exit code of sending the virtchnl response.
> */
> int ice_vc_dis_qs_msg(struct ice_vf *vf, u8 *msg) { @@ -406,18
> +408,7 @@ int ice_vc_dis_qs_msg(struct ice_vf *vf, u8 *msg)
> }
>
> q_map = vqs->rx_queues;
> - /* speed up Rx queue disable by batching them if possible */
> - if (q_map &&
> - bitmap_equal(&q_map, vf->rxq_ena, ICE_MAX_RSS_QS_PER_VF)) {
> - if (ice_vsi_stop_all_rx_rings(vsi)) {
> - dev_err(ice_pf_to_dev(vsi->back), "Failed to stop
> all Rx rings on VSI %d\n",
> - vsi->vsi_num);
> - v_ret = VIRTCHNL_STATUS_ERR_PARAM;
> - goto error_param;
> - }
> -
> - bitmap_zero(vf->rxq_ena, ICE_MAX_RSS_QS_PER_VF);
> - } else if (q_map) {
> + if (q_map) {
> for_each_set_bit(vf_q_id, &q_map, ICE_MAX_RSS_QS_PER_VF)
> {
> if (!ice_vc_isvalid_q_id(vsi, vf_q_id)) {
> v_ret = VIRTCHNL_STATUS_ERR_PARAM;
> --
> 2.39.3
Reviewed-by: Aleksandr Loktionov <aleksandr.loktionov@intel.com>
^ permalink raw reply [flat|nested] 28+ messages in thread
* [PATCH iwl-next v1 04/15] ice: add VF queue ena/dis helper functions
2026-05-08 12:41 [PATCH iwl-next v1 00/15] devlink, mlx5, iavf, ice: XLVF for iavf Przemek Kitszel
` (2 preceding siblings ...)
2026-05-08 12:41 ` [PATCH iwl-next v1 03/15] ice: simplify ice_vc_dis_qs_msg() a little Przemek Kitszel
@ 2026-05-08 12:41 ` Przemek Kitszel
2026-05-08 13:37 ` Loktionov, Aleksandr
2026-05-08 12:41 ` [PATCH iwl-next v1 05/15] ice: add helpers for Global RSS LUT alloc, free, vsi_update Przemek Kitszel
` (10 subsequent siblings)
14 siblings, 1 reply; 28+ messages in thread
From: Przemek Kitszel @ 2026-05-08 12:41 UTC (permalink / raw)
To: intel-wired-lan, Michal Schmidt, Jakub Kicinski, Jiri Pirko
Cc: netdev, Simon Horman, Tony Nguyen, Michal Swiatkowski,
bruce.richardson, Vladimir Medvedkin, padraig.j.connolly,
ananth.s, timothy.miskell, Jacob Keller, Lukasz Czapnik,
Aleksandr Loktionov, Andrew Lunn, David S. Miller, Eric Dumazet,
Paolo Abeni, Saeed Mahameed, Leon Romanovsky, Tariq Toukan,
Mark Bloch, Przemek Kitszel, Wojciech Drewek, Jedrzej Jagielski
From: Brett Creeley <brett.creeley@intel.com>
Add three new functions:
- ice_vf_vsi_dis_single_rxq()
- ice_vf_vsi_ena_single_rxq()
- ice_vf_vsi_ena_single_txq()
(ice_vf_vsi_dis_single_txq() was introduced earlier.
Those functions wrap operations needed in the processes of enabling
and disabling single Tx/Rx VF queue, which are:
- check if the queue is not already in desired state
- perform the dis/ena operations
- bookkeeping of the queue's state.
Future commit will use them from another callsite.
Signed-off-by: Brett Creeley <brett.creeley@intel.com>
Signed-off-by: Wojciech Drewek <wojciech.drewek@intel.com>
Reviewed-by: Jedrzej Jagielski <jedrzej.jagielski@intel.com>
Signed-off-by: Przemek Kitszel <przemyslaw.kitszel@intel.com>
---
drivers/net/ethernet/intel/ice/virt/queues.c | 111 ++++++++++++++-----
1 file changed, 84 insertions(+), 27 deletions(-)
diff --git a/drivers/net/ethernet/intel/ice/virt/queues.c b/drivers/net/ethernet/intel/ice/virt/queues.c
index 6e4ec681fd07..28adc24197b8 100644
--- a/drivers/net/ethernet/intel/ice/virt/queues.c
+++ b/drivers/net/ethernet/intel/ice/virt/queues.c
@@ -224,6 +224,57 @@ void ice_vf_ena_rxq_interrupt(struct ice_vsi *vsi, u32 q_idx)
wr32(hw, QINT_RQCTL(pfq), reg | QINT_RQCTL_CAUSE_ENA_M);
}
+/**
+ * ice_vf_vsi_ena_single_rxq - enable single Rx queue based on relative q_id
+ * @vf: VF to enable queue for
+ * @vsi: VSI for the VF
+ * @q_id: VSI relative (0-based) queue ID
+ *
+ * Enable the Rx queue passed in.
+ *
+ * Return: 0 on success or negative on error.
+ */
+static int ice_vf_vsi_ena_single_rxq(struct ice_vf *vf, struct ice_vsi *vsi,
+ u16 q_id)
+{
+ int err;
+
+ if (test_bit(q_id, vf->rxq_ena))
+ return 0;
+
+ err = ice_vsi_ctrl_one_rx_ring(vsi, true, q_id, true);
+ if (err) {
+ dev_err(ice_pf_to_dev(vsi->back), "Failed to enable Rx ring %d on VSI %d\n",
+ q_id, vsi->vsi_num);
+ return err;
+ }
+
+ ice_vf_ena_rxq_interrupt(vsi, q_id);
+ set_bit(q_id, vf->rxq_ena);
+
+ return 0;
+}
+
+/**
+ * ice_vf_vsi_ena_single_txq - enable single Tx queue based on relative q_id
+ * @vf: VF to enable queue for
+ * @vsi: VSI for the VF
+ * @q_id: VSI relative (0-based) queue ID
+ *
+ * Enable the Tx queue's interrupt. Note that the Tx queue(s) should have
+ * already been configurated/enabled in VIRTCHNL_OP_CONFIG_QUEUES so this
+ * function only enables the interrupt associated with the q_id.
+ */
+static void ice_vf_vsi_ena_single_txq(struct ice_vf *vf, struct ice_vsi *vsi,
+ u16 q_id)
+{
+ if (test_bit(q_id, vf->txq_ena))
+ return;
+
+ ice_vf_ena_txq_interrupt(vsi, q_id);
+ set_bit(q_id, vf->txq_ena);
+}
+
/**
* ice_vc_ena_qs_msg
* @vf: pointer to the VF info
@@ -272,34 +323,20 @@ int ice_vc_ena_qs_msg(struct ice_vf *vf, u8 *msg)
goto error_param;
}
- /* Skip queue if enabled */
- if (test_bit(vf_q_id, vf->rxq_ena))
- continue;
-
- if (ice_vsi_ctrl_one_rx_ring(vsi, true, vf_q_id, true)) {
- dev_err(ice_pf_to_dev(vsi->back), "Failed to enable Rx ring %d on VSI %d\n",
- vf_q_id, vsi->vsi_num);
+ if (ice_vf_vsi_ena_single_rxq(vf, vsi, vf_q_id)) {
v_ret = VIRTCHNL_STATUS_ERR_PARAM;
goto error_param;
}
-
- ice_vf_ena_rxq_interrupt(vsi, vf_q_id);
- set_bit(vf_q_id, vf->rxq_ena);
}
q_map = vqs->tx_queues;
for_each_set_bit(vf_q_id, &q_map, ICE_MAX_RSS_QS_PER_VF) {
if (!ice_vc_isvalid_q_id(vsi, vf_q_id)) {
v_ret = VIRTCHNL_STATUS_ERR_PARAM;
goto error_param;
}
- /* Skip queue if enabled */
- if (test_bit(vf_q_id, vf->txq_ena))
- continue;
-
- ice_vf_ena_txq_interrupt(vsi, vf_q_id);
- set_bit(vf_q_id, vf->txq_ena);
+ ice_vf_vsi_ena_single_txq(vf, vsi, vf_q_id);
}
/* Set flag to indicate that queues are enabled */
@@ -351,6 +388,36 @@ int ice_vf_vsi_dis_single_txq(struct ice_vf *vf, struct ice_vsi *vsi, u16 q_id)
return 0;
}
+/*
+ * ice_vf_vsi_dis_single_rxq - disable a Rx queue for VF on relative queue ID
+ * @vf: VF to disable queue for
+ * @vsi: VSI for the VF
+ * @q_id: VSI relative (0-based) queue ID
+ *
+ * Attempt to disable the Rx queue passed in. If the Rx queue was successfully
+ * disabled then clear q_id bit in the enabled queues bitmap.
+ */
+static int ice_vf_vsi_dis_single_rxq(struct ice_vf *vf, struct ice_vsi *vsi,
+ u16 q_id)
+{
+ int err;
+
+ if (!test_bit(q_id, vf->rxq_ena))
+ return 0;
+
+ err = ice_vsi_ctrl_one_rx_ring(vsi, false, q_id, true);
+ if (err) {
+ dev_err(ice_pf_to_dev(vsi->back), "Failed to stop Rx ring %d on VSI %d\n",
+ q_id, vsi->vsi_num);
+ return err;
+ }
+
+ /* Clear enabled queues flag */
+ clear_bit(q_id, vf->rxq_ena);
+
+ return 0;
+}
+
/**
* ice_vc_dis_qs_msg
* @vf: pointer to the VF info
@@ -415,20 +482,10 @@ int ice_vc_dis_qs_msg(struct ice_vf *vf, u8 *msg)
goto error_param;
}
- /* Skip queue if not enabled */
- if (!test_bit(vf_q_id, vf->rxq_ena))
- continue;
-
- if (ice_vsi_ctrl_one_rx_ring(vsi, false, vf_q_id,
- true)) {
- dev_err(ice_pf_to_dev(vsi->back), "Failed to stop Rx ring %d on VSI %d\n",
- vf_q_id, vsi->vsi_num);
+ if (ice_vf_vsi_dis_single_rxq(vf, vsi, vf_q_id)) {
v_ret = VIRTCHNL_STATUS_ERR_PARAM;
goto error_param;
}
-
- /* Clear enabled queues flag */
- clear_bit(vf_q_id, vf->rxq_ena);
}
}
--
2.39.3
^ permalink raw reply related [flat|nested] 28+ messages in thread* RE: [PATCH iwl-next v1 04/15] ice: add VF queue ena/dis helper functions
2026-05-08 12:41 ` [PATCH iwl-next v1 04/15] ice: add VF queue ena/dis helper functions Przemek Kitszel
@ 2026-05-08 13:37 ` Loktionov, Aleksandr
2026-05-11 9:33 ` Przemek Kitszel
0 siblings, 1 reply; 28+ messages in thread
From: Loktionov, Aleksandr @ 2026-05-08 13:37 UTC (permalink / raw)
To: Kitszel, Przemyslaw, intel-wired-lan@lists.osuosl.org,
Schmidt, Michal, Jakub Kicinski, Jiri Pirko
Cc: netdev@vger.kernel.org, Simon Horman, Nguyen, Anthony L,
Michal Swiatkowski, Richardson, Bruce, Medvedkin, Vladimir,
Connolly, Padraig J, S, Ananth, Miskell, Timothy, Keller, Jacob E,
Czapnik, Lukasz, Andrew Lunn, David S. Miller, Eric Dumazet,
Paolo Abeni, Saeed Mahameed, Leon Romanovsky, Tariq Toukan,
Mark Bloch, Drewek, Wojciech, Jagielski, Jedrzej
> -----Original Message-----
> From: Kitszel, Przemyslaw <przemyslaw.kitszel@intel.com>
> Sent: Friday, May 8, 2026 2:42 PM
> To: intel-wired-lan@lists.osuosl.org; Schmidt, Michal
> <mschmidt@redhat.com>; Jakub Kicinski <kuba@kernel.org>; Jiri Pirko
> <jiri@resnulli.us>
> Cc: netdev@vger.kernel.org; Simon Horman <horms@kernel.org>; Nguyen,
> Anthony L <anthony.l.nguyen@intel.com>; Michal Swiatkowski
> <michal.swiatkowski@linux.intel.com>; Richardson, Bruce
> <bruce.richardson@intel.com>; Medvedkin, Vladimir
> <vladimir.medvedkin@intel.com>; Connolly, Padraig J
> <padraig.j.connolly@intel.com>; S, Ananth <ananth.s@intel.com>;
> Miskell, Timothy <timothy.miskell@intel.com>; Keller, Jacob E
> <jacob.e.keller@intel.com>; Czapnik, Lukasz
> <lukasz.czapnik@intel.com>; Loktionov, Aleksandr
> <aleksandr.loktionov@intel.com>; Andrew Lunn <andrew+netdev@lunn.ch>;
> David S. Miller <davem@davemloft.net>; Eric Dumazet
> <edumazet@google.com>; Paolo Abeni <pabeni@redhat.com>; Saeed Mahameed
> <saeedm@nvidia.com>; Leon Romanovsky <leon@kernel.org>; Tariq Toukan
> <tariqt@nvidia.com>; Mark Bloch <mbloch@nvidia.com>; Kitszel,
> Przemyslaw <przemyslaw.kitszel@intel.com>; Drewek, Wojciech
> <wojciech.drewek@intel.com>; Jagielski, Jedrzej
> <jedrzej.jagielski@intel.com>
> Subject: [PATCH iwl-next v1 04/15] ice: add VF queue ena/dis helper
> functions
>
> From: Brett Creeley <brett.creeley@intel.com>
>
> Add three new functions:
> - ice_vf_vsi_dis_single_rxq()
> - ice_vf_vsi_ena_single_rxq()
> - ice_vf_vsi_ena_single_txq()
> (ice_vf_vsi_dis_single_txq() was introduced earlier.
>
> Those functions wrap operations needed in the processes of enabling
> and disabling single Tx/Rx VF queue, which are:
> - check if the queue is not already in desired state
> - perform the dis/ena operations
> - bookkeeping of the queue's state.
>
> Future commit will use them from another callsite.
>
> Signed-off-by: Brett Creeley <brett.creeley@intel.com>
> Signed-off-by: Wojciech Drewek <wojciech.drewek@intel.com>
> Reviewed-by: Jedrzej Jagielski <jedrzej.jagielski@intel.com>
> Signed-off-by: Przemek Kitszel <przemyslaw.kitszel@intel.com>
> ---
> drivers/net/ethernet/intel/ice/virt/queues.c | 111 ++++++++++++++----
> -
> 1 file changed, 84 insertions(+), 27 deletions(-)
>
> diff --git a/drivers/net/ethernet/intel/ice/virt/queues.c
> b/drivers/net/ethernet/intel/ice/virt/queues.c
> index 6e4ec681fd07..28adc24197b8 100644
> --- a/drivers/net/ethernet/intel/ice/virt/queues.c
> +++ b/drivers/net/ethernet/intel/ice/virt/queues.c
> @@ -224,6 +224,57 @@ void ice_vf_ena_rxq_interrupt(struct ice_vsi
> *vsi, u32 q_idx)
> wr32(hw, QINT_RQCTL(pfq), reg | QINT_RQCTL_CAUSE_ENA_M); }
>
> +/**
> + * ice_vf_vsi_ena_single_rxq - enable single Rx queue based on
> relative
> +q_id
> + * @vf: VF to enable queue for
> + * @vsi: VSI for the VF
> + * @q_id: VSI relative (0-based) queue ID
> + *
> + * Enable the Rx queue passed in.
> + *
> + * Return: 0 on success or negative on error.
> + */
> +static int ice_vf_vsi_ena_single_rxq(struct ice_vf *vf, struct
> ice_vsi *vsi,
> + u16 q_id)
> +{
> + int err;
> +
> + if (test_bit(q_id, vf->rxq_ena))
> + return 0;
> +
> + err = ice_vsi_ctrl_one_rx_ring(vsi, true, q_id, true);
> + if (err) {
> + dev_err(ice_pf_to_dev(vsi->back), "Failed to enable Rx
> ring %d on VSI %d\n",
> + q_id, vsi->vsi_num);
> + return err;
> + }
> +
> + ice_vf_ena_rxq_interrupt(vsi, q_id);
> + set_bit(q_id, vf->rxq_ena);
> +
> + return 0;
> +}
> +
> +/**
> + * ice_vf_vsi_ena_single_txq - enable single Tx queue based on
> relative
> +q_id
> + * @vf: VF to enable queue for
> + * @vsi: VSI for the VF
> + * @q_id: VSI relative (0-based) queue ID
> + *
> + * Enable the Tx queue's interrupt. Note that the Tx queue(s) should
> +have
> + * already been configurated/enabled in VIRTCHNL_OP_CONFIG_QUEUES so
> +this
> + * function only enables the interrupt associated with the q_id.
> + */
> +static void ice_vf_vsi_ena_single_txq(struct ice_vf *vf, struct
> ice_vsi *vsi,
> + u16 q_id)
> +{
> + if (test_bit(q_id, vf->txq_ena))
> + return;
> +
> + ice_vf_ena_txq_interrupt(vsi, q_id);
> + set_bit(q_id, vf->txq_ena);
> +}
> +
> /**
> * ice_vc_ena_qs_msg
> * @vf: pointer to the VF info
> @@ -272,34 +323,20 @@ int ice_vc_ena_qs_msg(struct ice_vf *vf, u8
> *msg)
> goto error_param;
> }
>
> - /* Skip queue if enabled */
> - if (test_bit(vf_q_id, vf->rxq_ena))
> - continue;
> -
> - if (ice_vsi_ctrl_one_rx_ring(vsi, true, vf_q_id, true))
> {
> - dev_err(ice_pf_to_dev(vsi->back), "Failed to
> enable Rx ring %d on VSI %d\n",
> - vf_q_id, vsi->vsi_num);
> + if (ice_vf_vsi_ena_single_rxq(vf, vsi, vf_q_id)) {
> v_ret = VIRTCHNL_STATUS_ERR_PARAM;
> goto error_param;
> }
> -
> - ice_vf_ena_rxq_interrupt(vsi, vf_q_id);
> - set_bit(vf_q_id, vf->rxq_ena);
> }
>
> q_map = vqs->tx_queues;
> for_each_set_bit(vf_q_id, &q_map, ICE_MAX_RSS_QS_PER_VF) {
> if (!ice_vc_isvalid_q_id(vsi, vf_q_id)) {
> v_ret = VIRTCHNL_STATUS_ERR_PARAM;
> goto error_param;
> }
>
> - /* Skip queue if enabled */
> - if (test_bit(vf_q_id, vf->txq_ena))
> - continue;
> -
> - ice_vf_ena_txq_interrupt(vsi, vf_q_id);
> - set_bit(vf_q_id, vf->txq_ena);
> + ice_vf_vsi_ena_single_txq(vf, vsi, vf_q_id);
> }
>
> /* Set flag to indicate that queues are enabled */ @@ -351,6
> +388,36 @@ int ice_vf_vsi_dis_single_txq(struct ice_vf *vf, struct
> ice_vsi *vsi, u16 q_id)
> return 0;
> }
>
> +/*
Please use linux kernel style: /**
Reviewed-by: Aleksandr Loktionov <aleksandr.loktionov@intel.com>
> + * ice_vf_vsi_dis_single_rxq - disable a Rx queue for VF on relative
> +queue ID
> + * @vf: VF to disable queue for
> + * @vsi: VSI for the VF
> + * @q_id: VSI relative (0-based) queue ID
> + *
> + * Attempt to disable the Rx queue passed in. If the Rx queue was
> +successfully
> + * disabled then clear q_id bit in the enabled queues bitmap.
> + */
> +static int ice_vf_vsi_dis_single_rxq(struct ice_vf *vf, struct
> ice_vsi *vsi,
> + u16 q_id)
> +{
> + int err;
> +
> + if (!test_bit(q_id, vf->rxq_ena))
> + return 0;
> +
> + err = ice_vsi_ctrl_one_rx_ring(vsi, false, q_id, true);
> + if (err) {
> + dev_err(ice_pf_to_dev(vsi->back), "Failed to stop Rx
> ring %d on VSI %d\n",
> + q_id, vsi->vsi_num);
> + return err;
> + }
> +
> + /* Clear enabled queues flag */
> + clear_bit(q_id, vf->rxq_ena);
> +
> + return 0;
> +}
> +
> /**
> * ice_vc_dis_qs_msg
> * @vf: pointer to the VF info
> @@ -415,20 +482,10 @@ int ice_vc_dis_qs_msg(struct ice_vf *vf, u8
> *msg)
> goto error_param;
> }
>
> - /* Skip queue if not enabled */
> - if (!test_bit(vf_q_id, vf->rxq_ena))
> - continue;
> -
> - if (ice_vsi_ctrl_one_rx_ring(vsi, false, vf_q_id,
> - true)) {
> - dev_err(ice_pf_to_dev(vsi->back), "Failed
> to stop Rx ring %d on VSI %d\n",
> - vf_q_id, vsi->vsi_num);
> + if (ice_vf_vsi_dis_single_rxq(vf, vsi, vf_q_id))
> {
> v_ret = VIRTCHNL_STATUS_ERR_PARAM;
> goto error_param;
> }
> -
> - /* Clear enabled queues flag */
> - clear_bit(vf_q_id, vf->rxq_ena);
> }
> }
>
> --
> 2.39.3
^ permalink raw reply [flat|nested] 28+ messages in thread* Re: [PATCH iwl-next v1 04/15] ice: add VF queue ena/dis helper functions
2026-05-08 13:37 ` Loktionov, Aleksandr
@ 2026-05-11 9:33 ` Przemek Kitszel
0 siblings, 0 replies; 28+ messages in thread
From: Przemek Kitszel @ 2026-05-11 9:33 UTC (permalink / raw)
To: Loktionov, Aleksandr
Cc: netdev@vger.kernel.org, Simon Horman, Nguyen, Anthony L,
intel-wired-lan@lists.osuosl.org, Schmidt, Michal, Jakub Kicinski,
Jiri Pirko, Michal Swiatkowski, Richardson, Bruce,
Medvedkin, Vladimir, Connolly, Padraig J, S, Ananth,
Miskell, Timothy, Keller, Jacob E, Czapnik, Lukasz, Andrew Lunn,
David S. Miller, Eric Dumazet, Paolo Abeni, Saeed Mahameed,
Leon Romanovsky, Tariq Toukan, Mark Bloch, Drewek, Wojciech,
Jagielski, Jedrzej
>> +/*
> Please use linux kernel style: /**
this comment is not a kdoc
there is not much left to make it one though, will do
>
> Reviewed-by: Aleksandr Loktionov <aleksandr.loktionov@intel.com>
thank you
>
>> + * ice_vf_vsi_dis_single_rxq - disable a Rx queue for VF on relative
>> +queue ID
>> + * @vf: VF to disable queue for
>> + * @vsi: VSI for the VF
>> + * @q_id: VSI relative (0-based) queue ID
>> + *
>> + * Attempt to disable the Rx queue passed in. If the Rx queue was
>> +successfully
>> + * disabled then clear q_id bit in the enabled queues bitmap.
>> + */
>> +static int ice_vf_vsi_dis_single_rxq(struct ice_vf *vf, struct
>> ice_vsi *vsi,
>> + u16 q_id)
>> +{
>> + int err;
>> +
>> + if (!test_bit(q_id, vf->rxq_ena))
>> + return 0;
>> +
>> + err = ice_vsi_ctrl_one_rx_ring(vsi, false, q_id, true);
>> + if (err) {
>> + dev_err(ice_pf_to_dev(vsi->back), "Failed to stop Rx
>> ring %d on VSI %d\n",
>> + q_id, vsi->vsi_num);
>> + return err;
>> + }
>> +
>> + /* Clear enabled queues flag */
>> + clear_bit(q_id, vf->rxq_ena);
>> +
>> + return 0;
>> +}
^ permalink raw reply [flat|nested] 28+ messages in thread
* [PATCH iwl-next v1 05/15] ice: add helpers for Global RSS LUT alloc, free, vsi_update
2026-05-08 12:41 [PATCH iwl-next v1 00/15] devlink, mlx5, iavf, ice: XLVF for iavf Przemek Kitszel
` (3 preceding siblings ...)
2026-05-08 12:41 ` [PATCH iwl-next v1 04/15] ice: add VF queue ena/dis helper functions Przemek Kitszel
@ 2026-05-08 12:41 ` Przemek Kitszel
2026-05-08 13:38 ` Loktionov, Aleksandr
2026-05-08 12:41 ` [PATCH iwl-next v1 06/15] ice: rename ICE_MAX_RSS_QS_PER_VF to ICE_MAX_QS_PER_VF_VCV1 Przemek Kitszel
` (9 subsequent siblings)
14 siblings, 1 reply; 28+ messages in thread
From: Przemek Kitszel @ 2026-05-08 12:41 UTC (permalink / raw)
To: intel-wired-lan, Michal Schmidt, Jakub Kicinski, Jiri Pirko
Cc: netdev, Simon Horman, Tony Nguyen, Michal Swiatkowski,
bruce.richardson, Vladimir Medvedkin, padraig.j.connolly,
ananth.s, timothy.miskell, Jacob Keller, Lukasz Czapnik,
Aleksandr Loktionov, Andrew Lunn, David S. Miller, Eric Dumazet,
Paolo Abeni, Saeed Mahameed, Leon Romanovsky, Tariq Toukan,
Mark Bloch, Przemek Kitszel
Add AQ commands for RSS Global LUT allocation and free operations.
Functions will be called since subsequent commit.
Add programming code for GLOBAL LUT ID of UPDATE VSI AQ,
do the same for RSS LUT "type", also for PF LUT in case of VF VSI.
Co-developed-by: Brett Creeley <brett.creeley@intel.com>
Signed-off-by: Brett Creeley <brett.creeley@intel.com>
Signed-off-by: Przemek Kitszel <przemyslaw.kitszel@intel.com>
---
drivers/net/ethernet/intel/ice/ice.h | 1 +
.../net/ethernet/intel/ice/ice_adminq_cmd.h | 1 +
drivers/net/ethernet/intel/ice/ice_switch.h | 2 +
drivers/net/ethernet/intel/ice/ice_lib.c | 28 +++++++++++--
drivers/net/ethernet/intel/ice/ice_switch.c | 41 +++++++++++++++++++
5 files changed, 69 insertions(+), 4 deletions(-)
diff --git a/drivers/net/ethernet/intel/ice/ice.h b/drivers/net/ethernet/intel/ice/ice.h
index f9a43daf04fe..7f4f299c4d37 100644
--- a/drivers/net/ethernet/intel/ice/ice.h
+++ b/drivers/net/ethernet/intel/ice/ice.h
@@ -369,6 +369,7 @@ struct ice_vsi {
u8 *rss_hkey_user; /* User configured hash keys */
u8 *rss_lut_user; /* User configured lookup table entries */
u8 rss_lut_type; /* used to configure Get/Set RSS LUT AQ call */
+ u8 global_lut_id; /* valid when lut_type == GLOBAL_LUT */
/* aRFS members only allocated for the PF VSI */
#define ICE_MAX_ARFS_LIST 1024
diff --git a/drivers/net/ethernet/intel/ice/ice_adminq_cmd.h b/drivers/net/ethernet/intel/ice/ice_adminq_cmd.h
index d41b2427482d..c49896db51c6 100644
--- a/drivers/net/ethernet/intel/ice/ice_adminq_cmd.h
+++ b/drivers/net/ethernet/intel/ice/ice_adminq_cmd.h
@@ -169,6 +169,7 @@ struct ice_aqc_set_port_params {
#define ICE_AQC_RES_TYPE_VSI_LIST_PRUNE 0x04
#define ICE_AQC_RES_TYPE_RECIPE 0x05
#define ICE_AQC_RES_TYPE_SWID 0x07
+#define ICE_AQC_RES_TYPE_GLOBAL_RSS_HASH 0x20
#define ICE_AQC_RES_TYPE_FDIR_COUNTER_BLOCK 0x21
#define ICE_AQC_RES_TYPE_FDIR_GUARANTEED_ENTRIES 0x22
#define ICE_AQC_RES_TYPE_FDIR_SHARED_ENTRIES 0x23
diff --git a/drivers/net/ethernet/intel/ice/ice_switch.h b/drivers/net/ethernet/intel/ice/ice_switch.h
index b442db4a2ce5..ab6a8c78d14a 100644
--- a/drivers/net/ethernet/intel/ice/ice_switch.h
+++ b/drivers/net/ethernet/intel/ice/ice_switch.h
@@ -401,6 +401,8 @@ ice_rem_adv_rule_by_id(struct ice_hw *hw,
struct ice_rule_query_data *remove_entry);
int ice_init_def_sw_recp(struct ice_hw *hw);
+int ice_alloc_rss_global_lut(struct ice_hw *hw, u16 *global_lut_id);
+int ice_free_rss_global_lut(struct ice_hw *hw, u16 global_lut_id);
u16 ice_get_hw_vsi_num(struct ice_hw *hw, u16 vsi_handle);
int ice_replay_vsi_all_fltr(struct ice_hw *hw, u16 vsi_handle);
diff --git a/drivers/net/ethernet/intel/ice/ice_lib.c b/drivers/net/ethernet/intel/ice/ice_lib.c
index ac6698a01d2f..2de62cde14ab 100644
--- a/drivers/net/ethernet/intel/ice/ice_lib.c
+++ b/drivers/net/ethernet/intel/ice/ice_lib.c
@@ -1154,30 +1154,46 @@ static void ice_set_fd_vsi_ctx(struct ice_vsi_ctx *ctxt, struct ice_vsi *vsi)
ctxt->info.acl_def_act = cpu_to_le16(val);
}
+/* Translate @lut_type used in most of the places to the Admin Queue
+ * Q_OPT value for RSS.
+ * Used with VSI ADD and VSI UPDATE AQs (opcodes 0x0210, 0x0211).
+ */
+static u8 ice_lut_type_to_aq_qopt_rss_val(enum ice_lut_type lut_type)
+{
+ switch (lut_type) {
+ case ICE_LUT_PF:
+ return ICE_AQ_VSI_Q_OPT_RSS_LUT_PF;
+ case ICE_LUT_GLOBAL:
+ return ICE_AQ_VSI_Q_OPT_RSS_LUT_GBL;
+ case ICE_LUT_VSI:
+ default:
+ return ICE_AQ_VSI_Q_OPT_RSS_LUT_VSI;
+ }
+}
+
/**
* ice_set_rss_vsi_ctx - Set RSS VSI context before adding a VSI
* @ctxt: the VSI context being set
* @vsi: the VSI being configured
*/
void ice_set_rss_vsi_ctx(struct ice_vsi_ctx *ctxt, struct ice_vsi *vsi)
{
u8 lut_type, hash_type;
+ u8 global_lut_id = 0;
struct device *dev;
struct ice_pf *pf;
pf = vsi->back;
dev = ice_pf_to_dev(pf);
switch (vsi->type) {
case ICE_VSI_CHNL:
- case ICE_VSI_PF:
- /* PF VSI will inherit RSS instance of PF */
lut_type = ICE_AQ_VSI_Q_OPT_RSS_LUT_PF;
break;
+ case ICE_VSI_PF:
case ICE_VSI_VF:
case ICE_VSI_SF:
- /* VF VSI will gets a small RSS table which is a VSI LUT type */
- lut_type = ICE_AQ_VSI_Q_OPT_RSS_LUT_VSI;
+ lut_type = ice_lut_type_to_aq_qopt_rss_val(vsi->rss_lut_type);
break;
default:
dev_dbg(dev, "Unsupported VSI type %s\n",
@@ -1189,8 +1205,12 @@ void ice_set_rss_vsi_ctx(struct ice_vsi_ctx *ctxt, struct ice_vsi *vsi)
vsi->rss_hfunc = ICE_AQ_VSI_Q_OPT_RSS_HASH_TPLZ;
hash_type = vsi->rss_hfunc;
+ if (vsi->rss_lut_type == ICE_LUT_GLOBAL)
+ global_lut_id = vsi->global_lut_id;
+
ctxt->info.q_opt_rss =
FIELD_PREP(ICE_AQ_VSI_Q_OPT_RSS_LUT_M, lut_type) |
+ FIELD_PREP(ICE_AQ_VSI_Q_OPT_RSS_GBL_LUT_M, global_lut_id) |
FIELD_PREP(ICE_AQ_VSI_Q_OPT_RSS_HASH_M, hash_type);
}
diff --git a/drivers/net/ethernet/intel/ice/ice_switch.c b/drivers/net/ethernet/intel/ice/ice_switch.c
index 88f1aefc24b3..b783c97f6cfe 100644
--- a/drivers/net/ethernet/intel/ice/ice_switch.c
+++ b/drivers/net/ethernet/intel/ice/ice_switch.c
@@ -1527,6 +1527,47 @@ ice_aq_get_sw_cfg(struct ice_hw *hw, struct ice_aqc_get_sw_cfg_resp_elem *buf,
return status;
}
+/* Allocate a new Global LUT for the caller.
+ * LUT ID is returned via @global_lut_id.
+ */
+int ice_alloc_rss_global_lut(struct ice_hw *hw, u16 *global_lut_id)
+{
+ DEFINE_RAW_FLEX(struct ice_aqc_alloc_free_res_elem, buf, elem, 1);
+ u16 buf_len = __struct_size(buf);
+ int err;
+
+ buf->num_elems = cpu_to_le16(1);
+ buf->res_type = cpu_to_le16(ICE_AQC_RES_TYPE_GLOBAL_RSS_HASH);
+
+ err = ice_aq_alloc_free_res(hw, buf, buf_len, ice_aqc_opc_alloc_res);
+ if (err)
+ ice_debug(hw, ICE_DBG_RES, "Failed to allocate RSS global LUT, err %d\n",
+ err);
+ else
+ *global_lut_id = le16_to_cpu(buf->elem[0].e.sw_resp);
+
+ return err;
+}
+
+/* Free Global LUT at @global_lut_id. */
+int ice_free_rss_global_lut(struct ice_hw *hw, u16 global_lut_id)
+{
+ DEFINE_RAW_FLEX(struct ice_aqc_alloc_free_res_elem, buf, elem, 1);
+ u16 buf_len = __struct_size(buf);
+ int err;
+
+ buf->num_elems = cpu_to_le16(1);
+ buf->res_type = cpu_to_le16(ICE_AQC_RES_TYPE_GLOBAL_RSS_HASH);
+ buf->elem[0].e.sw_resp = cpu_to_le16(global_lut_id);
+
+ err = ice_aq_alloc_free_res(hw, buf, buf_len, ice_aqc_opc_free_res);
+ if (err)
+ ice_debug(hw, ICE_DBG_RES, "Failed to free RSS global LUT %d, err %d\n",
+ global_lut_id, err);
+
+ return err;
+}
+
/**
* ice_aq_add_vsi
* @hw: pointer to the HW struct
--
2.39.3
^ permalink raw reply related [flat|nested] 28+ messages in thread* RE: [PATCH iwl-next v1 05/15] ice: add helpers for Global RSS LUT alloc, free, vsi_update
2026-05-08 12:41 ` [PATCH iwl-next v1 05/15] ice: add helpers for Global RSS LUT alloc, free, vsi_update Przemek Kitszel
@ 2026-05-08 13:38 ` Loktionov, Aleksandr
0 siblings, 0 replies; 28+ messages in thread
From: Loktionov, Aleksandr @ 2026-05-08 13:38 UTC (permalink / raw)
To: Kitszel, Przemyslaw, intel-wired-lan@lists.osuosl.org,
Schmidt, Michal, Jakub Kicinski, Jiri Pirko
Cc: netdev@vger.kernel.org, Simon Horman, Nguyen, Anthony L,
Michal Swiatkowski, Richardson, Bruce, Medvedkin, Vladimir,
Connolly, Padraig J, S, Ananth, Miskell, Timothy, Keller, Jacob E,
Czapnik, Lukasz, Andrew Lunn, David S. Miller, Eric Dumazet,
Paolo Abeni, Saeed Mahameed, Leon Romanovsky, Tariq Toukan,
Mark Bloch
> -----Original Message-----
> From: Kitszel, Przemyslaw <przemyslaw.kitszel@intel.com>
> Sent: Friday, May 8, 2026 2:42 PM
> To: intel-wired-lan@lists.osuosl.org; Schmidt, Michal
> <mschmidt@redhat.com>; Jakub Kicinski <kuba@kernel.org>; Jiri Pirko
> <jiri@resnulli.us>
> Cc: netdev@vger.kernel.org; Simon Horman <horms@kernel.org>; Nguyen,
> Anthony L <anthony.l.nguyen@intel.com>; Michal Swiatkowski
> <michal.swiatkowski@linux.intel.com>; Richardson, Bruce
> <bruce.richardson@intel.com>; Medvedkin, Vladimir
> <vladimir.medvedkin@intel.com>; Connolly, Padraig J
> <padraig.j.connolly@intel.com>; S, Ananth <ananth.s@intel.com>;
> Miskell, Timothy <timothy.miskell@intel.com>; Keller, Jacob E
> <jacob.e.keller@intel.com>; Czapnik, Lukasz
> <lukasz.czapnik@intel.com>; Loktionov, Aleksandr
> <aleksandr.loktionov@intel.com>; Andrew Lunn <andrew+netdev@lunn.ch>;
> David S. Miller <davem@davemloft.net>; Eric Dumazet
> <edumazet@google.com>; Paolo Abeni <pabeni@redhat.com>; Saeed Mahameed
> <saeedm@nvidia.com>; Leon Romanovsky <leon@kernel.org>; Tariq Toukan
> <tariqt@nvidia.com>; Mark Bloch <mbloch@nvidia.com>; Kitszel,
> Przemyslaw <przemyslaw.kitszel@intel.com>
> Subject: [PATCH iwl-next v1 05/15] ice: add helpers for Global RSS LUT
> alloc, free, vsi_update
>
> Add AQ commands for RSS Global LUT allocation and free operations.
> Functions will be called since subsequent commit.
>
> Add programming code for GLOBAL LUT ID of UPDATE VSI AQ, do the same
> for RSS LUT "type", also for PF LUT in case of VF VSI.
>
> Co-developed-by: Brett Creeley <brett.creeley@intel.com>
> Signed-off-by: Brett Creeley <brett.creeley@intel.com>
> Signed-off-by: Przemek Kitszel <przemyslaw.kitszel@intel.com>
> ---
> drivers/net/ethernet/intel/ice/ice.h | 1 +
> .../net/ethernet/intel/ice/ice_adminq_cmd.h | 1 +
> drivers/net/ethernet/intel/ice/ice_switch.h | 2 +
> drivers/net/ethernet/intel/ice/ice_lib.c | 28 +++++++++++--
> drivers/net/ethernet/intel/ice/ice_switch.c | 41
> +++++++++++++++++++
> 5 files changed, 69 insertions(+), 4 deletions(-)
>
> diff --git a/drivers/net/ethernet/intel/ice/ice.h
> b/drivers/net/ethernet/intel/ice/ice.h
> index f9a43daf04fe..7f4f299c4d37 100644
> --- a/drivers/net/ethernet/intel/ice/ice.h
> +++ b/drivers/net/ethernet/intel/ice/ice.h
> @@ -369,6 +369,7 @@ struct ice_vsi {
> u8 *rss_hkey_user; /* User configured hash keys */
> u8 *rss_lut_user; /* User configured lookup table entries */
> u8 rss_lut_type; /* used to configure Get/Set RSS LUT AQ
> call */
> + u8 global_lut_id; /* valid when lut_type == GLOBAL_LUT */
>
> /* aRFS members only allocated for the PF VSI */
> #define ICE_MAX_ARFS_LIST 1024
> diff --git a/drivers/net/ethernet/intel/ice/ice_adminq_cmd.h
> b/drivers/net/ethernet/intel/ice/ice_adminq_cmd.h
> index d41b2427482d..c49896db51c6 100644
> --- a/drivers/net/ethernet/intel/ice/ice_adminq_cmd.h
> +++ b/drivers/net/ethernet/intel/ice/ice_adminq_cmd.h
> @@ -169,6 +169,7 @@ struct ice_aqc_set_port_params {
> #define ICE_AQC_RES_TYPE_VSI_LIST_PRUNE 0x04
> #define ICE_AQC_RES_TYPE_RECIPE 0x05
> #define ICE_AQC_RES_TYPE_SWID 0x07
> +#define ICE_AQC_RES_TYPE_GLOBAL_RSS_HASH 0x20
> #define ICE_AQC_RES_TYPE_FDIR_COUNTER_BLOCK 0x21
> #define ICE_AQC_RES_TYPE_FDIR_GUARANTEED_ENTRIES 0x22
> #define ICE_AQC_RES_TYPE_FDIR_SHARED_ENTRIES 0x23
> diff --git a/drivers/net/ethernet/intel/ice/ice_switch.h
> b/drivers/net/ethernet/intel/ice/ice_switch.h
> index b442db4a2ce5..ab6a8c78d14a 100644
> --- a/drivers/net/ethernet/intel/ice/ice_switch.h
> +++ b/drivers/net/ethernet/intel/ice/ice_switch.h
> @@ -401,6 +401,8 @@ ice_rem_adv_rule_by_id(struct ice_hw *hw,
> struct ice_rule_query_data *remove_entry);
>
> int ice_init_def_sw_recp(struct ice_hw *hw);
> +int ice_alloc_rss_global_lut(struct ice_hw *hw, u16 *global_lut_id);
> +int ice_free_rss_global_lut(struct ice_hw *hw, u16 global_lut_id);
> u16 ice_get_hw_vsi_num(struct ice_hw *hw, u16 vsi_handle);
>
> int ice_replay_vsi_all_fltr(struct ice_hw *hw, u16 vsi_handle); diff
> --git a/drivers/net/ethernet/intel/ice/ice_lib.c
> b/drivers/net/ethernet/intel/ice/ice_lib.c
> index ac6698a01d2f..2de62cde14ab 100644
> --- a/drivers/net/ethernet/intel/ice/ice_lib.c
> +++ b/drivers/net/ethernet/intel/ice/ice_lib.c
> @@ -1154,30 +1154,46 @@ static void ice_set_fd_vsi_ctx(struct
> ice_vsi_ctx *ctxt, struct ice_vsi *vsi)
> ctxt->info.acl_def_act = cpu_to_le16(val); }
>
> +/* Translate @lut_type used in most of the places to the Admin Queue
> + * Q_OPT value for RSS.
> + * Used with VSI ADD and VSI UPDATE AQs (opcodes 0x0210, 0x0211).
> + */
> +static u8 ice_lut_type_to_aq_qopt_rss_val(enum ice_lut_type lut_type)
> {
> + switch (lut_type) {
> + case ICE_LUT_PF:
> + return ICE_AQ_VSI_Q_OPT_RSS_LUT_PF;
> + case ICE_LUT_GLOBAL:
> + return ICE_AQ_VSI_Q_OPT_RSS_LUT_GBL;
> + case ICE_LUT_VSI:
> + default:
> + return ICE_AQ_VSI_Q_OPT_RSS_LUT_VSI;
> + }
> +}
> +
> /**
> * ice_set_rss_vsi_ctx - Set RSS VSI context before adding a VSI
> * @ctxt: the VSI context being set
> * @vsi: the VSI being configured
> */
> void ice_set_rss_vsi_ctx(struct ice_vsi_ctx *ctxt, struct ice_vsi
> *vsi) {
> u8 lut_type, hash_type;
> + u8 global_lut_id = 0;
> struct device *dev;
> struct ice_pf *pf;
>
> pf = vsi->back;
> dev = ice_pf_to_dev(pf);
>
> switch (vsi->type) {
> case ICE_VSI_CHNL:
> - case ICE_VSI_PF:
> - /* PF VSI will inherit RSS instance of PF */
> lut_type = ICE_AQ_VSI_Q_OPT_RSS_LUT_PF;
> break;
> + case ICE_VSI_PF:
> case ICE_VSI_VF:
> case ICE_VSI_SF:
> - /* VF VSI will gets a small RSS table which is a VSI LUT
> type */
> - lut_type = ICE_AQ_VSI_Q_OPT_RSS_LUT_VSI;
> + lut_type = ice_lut_type_to_aq_qopt_rss_val(vsi-
> >rss_lut_type);
> break;
> default:
> dev_dbg(dev, "Unsupported VSI type %s\n", @@ -1189,8
> +1205,12 @@ void ice_set_rss_vsi_ctx(struct ice_vsi_ctx *ctxt, struct
> ice_vsi *vsi)
> vsi->rss_hfunc = ICE_AQ_VSI_Q_OPT_RSS_HASH_TPLZ;
> hash_type = vsi->rss_hfunc;
>
> + if (vsi->rss_lut_type == ICE_LUT_GLOBAL)
> + global_lut_id = vsi->global_lut_id;
> +
> ctxt->info.q_opt_rss =
> FIELD_PREP(ICE_AQ_VSI_Q_OPT_RSS_LUT_M, lut_type) |
> + FIELD_PREP(ICE_AQ_VSI_Q_OPT_RSS_GBL_LUT_M,
> global_lut_id) |
> FIELD_PREP(ICE_AQ_VSI_Q_OPT_RSS_HASH_M, hash_type); }
>
> diff --git a/drivers/net/ethernet/intel/ice/ice_switch.c
> b/drivers/net/ethernet/intel/ice/ice_switch.c
> index 88f1aefc24b3..b783c97f6cfe 100644
> --- a/drivers/net/ethernet/intel/ice/ice_switch.c
> +++ b/drivers/net/ethernet/intel/ice/ice_switch.c
> @@ -1527,6 +1527,47 @@ ice_aq_get_sw_cfg(struct ice_hw *hw, struct
> ice_aqc_get_sw_cfg_resp_elem *buf,
> return status;
> }
>
> +/* Allocate a new Global LUT for the caller.
> + * LUT ID is returned via @global_lut_id.
> + */
> +int ice_alloc_rss_global_lut(struct ice_hw *hw, u16 *global_lut_id) {
> + DEFINE_RAW_FLEX(struct ice_aqc_alloc_free_res_elem, buf, elem,
> 1);
> + u16 buf_len = __struct_size(buf);
> + int err;
> +
> + buf->num_elems = cpu_to_le16(1);
> + buf->res_type = cpu_to_le16(ICE_AQC_RES_TYPE_GLOBAL_RSS_HASH);
> +
> + err = ice_aq_alloc_free_res(hw, buf, buf_len,
> ice_aqc_opc_alloc_res);
> + if (err)
> + ice_debug(hw, ICE_DBG_RES, "Failed to allocate RSS
> global LUT, err %d\n",
> + err);
> + else
> + *global_lut_id = le16_to_cpu(buf->elem[0].e.sw_resp);
> +
> + return err;
> +}
> +
> +/* Free Global LUT at @global_lut_id. */ int
> +ice_free_rss_global_lut(struct ice_hw *hw, u16 global_lut_id) {
> + DEFINE_RAW_FLEX(struct ice_aqc_alloc_free_res_elem, buf, elem,
> 1);
> + u16 buf_len = __struct_size(buf);
> + int err;
> +
> + buf->num_elems = cpu_to_le16(1);
> + buf->res_type = cpu_to_le16(ICE_AQC_RES_TYPE_GLOBAL_RSS_HASH);
> + buf->elem[0].e.sw_resp = cpu_to_le16(global_lut_id);
> +
> + err = ice_aq_alloc_free_res(hw, buf, buf_len,
> ice_aqc_opc_free_res);
> + if (err)
> + ice_debug(hw, ICE_DBG_RES, "Failed to free RSS global
> LUT %d, err %d\n",
> + global_lut_id, err);
> +
> + return err;
> +}
> +
> /**
> * ice_aq_add_vsi
> * @hw: pointer to the HW struct
> --
> 2.39.3
Reviewed-by: Aleksandr Loktionov <aleksandr.loktionov@intel.com>
^ permalink raw reply [flat|nested] 28+ messages in thread
* [PATCH iwl-next v1 06/15] ice: rename ICE_MAX_RSS_QS_PER_VF to ICE_MAX_QS_PER_VF_VCV1
2026-05-08 12:41 [PATCH iwl-next v1 00/15] devlink, mlx5, iavf, ice: XLVF for iavf Przemek Kitszel
` (4 preceding siblings ...)
2026-05-08 12:41 ` [PATCH iwl-next v1 05/15] ice: add helpers for Global RSS LUT alloc, free, vsi_update Przemek Kitszel
@ 2026-05-08 12:41 ` Przemek Kitszel
2026-05-08 12:42 ` [PATCH iwl-next v1 07/15] ice: bump to 256qs for VF Przemek Kitszel
` (8 subsequent siblings)
14 siblings, 0 replies; 28+ messages in thread
From: Przemek Kitszel @ 2026-05-08 12:41 UTC (permalink / raw)
To: intel-wired-lan, Michal Schmidt, Jakub Kicinski, Jiri Pirko
Cc: netdev, Simon Horman, Tony Nguyen, Michal Swiatkowski,
bruce.richardson, Vladimir Medvedkin, padraig.j.connolly,
ananth.s, timothy.miskell, Jacob Keller, Lukasz Czapnik,
Aleksandr Loktionov, Andrew Lunn, David S. Miller, Eric Dumazet,
Paolo Abeni, Saeed Mahameed, Leon Romanovsky, Tariq Toukan,
Mark Bloch, Przemek Kitszel, Jedrzej Jagielski
Rename ICE_MAX_RSS_QS_PER_VF to ICE_MAX_QS_PER_VF_VCV1, in preparation for
the next patch that will extend the max to 256, using old value of 16 for
the "v1" variant of virtchnl opcodes.
Suggested-by: Jedrzej Jagielski <jedrzej.jagielski@intel.com>
Suggested-by: Jacob Keller <jacob.e.keller@intel.com>
Reviewed-by: Aleksandr Loktionov <aleksandr.loktionov@intel.com>
Signed-off-by: Przemek Kitszel <przemyslaw.kitszel@intel.com>
---
drivers/net/ethernet/intel/ice/ice_lag.h | 2 +-
drivers/net/ethernet/intel/ice/ice_vf_lib.h | 9 +++---
drivers/net/ethernet/intel/ice/ice_lib.c | 2 +-
drivers/net/ethernet/intel/ice/ice_sriov.c | 4 +--
drivers/net/ethernet/intel/ice/ice_vf_lib.c | 12 ++++----
drivers/net/ethernet/intel/ice/virt/queues.c | 30 ++++++++++----------
6 files changed, 30 insertions(+), 29 deletions(-)
diff --git a/drivers/net/ethernet/intel/ice/ice_lag.h b/drivers/net/ethernet/intel/ice/ice_lag.h
index f77ebcd61042..4bfffecbdc97 100644
--- a/drivers/net/ethernet/intel/ice/ice_lag.h
+++ b/drivers/net/ethernet/intel/ice/ice_lag.h
@@ -52,7 +52,7 @@ struct ice_lag {
u8 bond_lport_sec; /* lport values for secondary PF */
/* q_home keeps track of which interface the q is currently on */
- u8 q_home[ICE_MAX_SRIOV_VFS][ICE_MAX_RSS_QS_PER_VF];
+ u8 q_home[ICE_MAX_SRIOV_VFS][ICE_MAX_QS_PER_VF_VCV1];
/* placeholder VSI for hanging VF queues from on secondary interface */
struct ice_vsi *sec_vf[ICE_MAX_SRIOV_VFS];
diff --git a/drivers/net/ethernet/intel/ice/ice_vf_lib.h b/drivers/net/ethernet/intel/ice/ice_vf_lib.h
index cdfc2a558732..36dbe5412336 100644
--- a/drivers/net/ethernet/intel/ice/ice_vf_lib.h
+++ b/drivers/net/ethernet/intel/ice/ice_vf_lib.h
@@ -19,7 +19,8 @@
#define ICE_MAX_SRIOV_VFS 256
/* VF resource constraints */
-#define ICE_MAX_RSS_QS_PER_VF 16
+/* for "old" virtchnl opcodes that accept up to 16 queues */
+#define ICE_MAX_QS_PER_VF_VCV1 16
struct ice_pf;
struct ice_vf;
@@ -161,8 +162,8 @@ struct ice_vf {
u8 dev_lan_addr[ETH_ALEN];
u8 hw_lan_addr[ETH_ALEN];
struct ice_time_mac legacy_last_added_umac;
- DECLARE_BITMAP(txq_ena, ICE_MAX_RSS_QS_PER_VF);
- DECLARE_BITMAP(rxq_ena, ICE_MAX_RSS_QS_PER_VF);
+ DECLARE_BITMAP(txq_ena, ICE_MAX_QS_PER_VF_VCV1);
+ DECLARE_BITMAP(rxq_ena, ICE_MAX_QS_PER_VF_VCV1);
struct ice_vlan port_vlan_info; /* Port VLAN ID, QoS, and TPID */
struct virtchnl_vlan_caps vlan_v2_caps;
struct ice_mbx_vf_info mbx_info;
@@ -205,7 +206,7 @@ struct ice_vf {
u16 lldp_recipe_id;
u16 lldp_rule_id;
- struct ice_vf_qs_bw qs_bw[ICE_MAX_RSS_QS_PER_VF];
+ struct ice_vf_qs_bw qs_bw[ICE_MAX_QS_PER_VF_VCV1];
};
/* Flags for controlling behavior of ice_reset_vf */
diff --git a/drivers/net/ethernet/intel/ice/ice_lib.c b/drivers/net/ethernet/intel/ice/ice_lib.c
index 2de62cde14ab..09e1dcab2179 100644
--- a/drivers/net/ethernet/intel/ice/ice_lib.c
+++ b/drivers/net/ethernet/intel/ice/ice_lib.c
@@ -925,7 +925,7 @@ static void ice_vsi_set_rss_params(struct ice_vsi *vsi)
* For VSI_LUT, LUT size should be set to 64 bytes.
*/
vsi->rss_table_size = ICE_LUT_VSI_SIZE;
- vsi->rss_size = ICE_MAX_RSS_QS_PER_VF;
+ vsi->rss_size = ICE_MAX_QS_PER_VF_VCV1;
vsi->rss_lut_type = ICE_LUT_VSI;
break;
case ICE_VSI_LB:
diff --git a/drivers/net/ethernet/intel/ice/ice_sriov.c b/drivers/net/ethernet/intel/ice/ice_sriov.c
index 8686c382404f..0482454f453b 100644
--- a/drivers/net/ethernet/intel/ice/ice_sriov.c
+++ b/drivers/net/ethernet/intel/ice/ice_sriov.c
@@ -398,15 +398,15 @@ static int ice_set_per_vf_res(struct ice_pf *pf, u16 num_vfs)
}
num_txq = min_t(u16, num_msix_per_vf - ICE_NONQ_VECS_VF,
- ICE_MAX_RSS_QS_PER_VF);
+ ICE_MAX_QS_PER_VF_VCV1);
avail_qs = ice_get_avail_txq_count(pf) / num_vfs;
if (!avail_qs)
num_txq = 0;
else if (num_txq > avail_qs)
num_txq = rounddown_pow_of_two(avail_qs);
num_rxq = min_t(u16, num_msix_per_vf - ICE_NONQ_VECS_VF,
- ICE_MAX_RSS_QS_PER_VF);
+ ICE_MAX_QS_PER_VF_VCV1);
avail_qs = ice_get_avail_rxq_count(pf) / num_vfs;
if (!avail_qs)
num_rxq = 0;
diff --git a/drivers/net/ethernet/intel/ice/ice_vf_lib.c b/drivers/net/ethernet/intel/ice/ice_vf_lib.c
index f1f437b1af1b..8e88ab8547ab 100644
--- a/drivers/net/ethernet/intel/ice/ice_vf_lib.c
+++ b/drivers/net/ethernet/intel/ice/ice_vf_lib.c
@@ -535,8 +535,8 @@ static void ice_vf_rebuild_host_cfg(struct ice_vf *vf)
static void ice_set_vf_state_qs_dis(struct ice_vf *vf)
{
/* Clear Rx/Tx enabled queues flag */
- bitmap_zero(vf->txq_ena, ICE_MAX_RSS_QS_PER_VF);
- bitmap_zero(vf->rxq_ena, ICE_MAX_RSS_QS_PER_VF);
+ bitmap_zero(vf->txq_ena, ICE_MAX_QS_PER_VF_VCV1);
+ bitmap_zero(vf->rxq_ena, ICE_MAX_QS_PER_VF_VCV1);
clear_bit(ICE_VF_STATE_QS_ENA, vf->vf_states);
}
@@ -1217,13 +1217,13 @@ bool ice_is_vf_trusted(struct ice_vf *vf)
* ice_vf_has_no_qs_ena - check if the VF has any Rx or Tx queues enabled
* @vf: the VF to check
*
- * Returns true if the VF has no Rx and no Tx queues enabled and returns false
- * otherwise
+ * Return: true if the VF has no Rx and no Tx queues enabled and returns false
+ * otherwise.
*/
bool ice_vf_has_no_qs_ena(struct ice_vf *vf)
{
- return bitmap_empty(vf->rxq_ena, ICE_MAX_RSS_QS_PER_VF) &&
- bitmap_empty(vf->txq_ena, ICE_MAX_RSS_QS_PER_VF);
+ return bitmap_empty(vf->rxq_ena, ICE_MAX_QS_PER_VF_VCV1) &&
+ bitmap_empty(vf->txq_ena, ICE_MAX_QS_PER_VF_VCV1);
}
/**
diff --git a/drivers/net/ethernet/intel/ice/virt/queues.c b/drivers/net/ethernet/intel/ice/virt/queues.c
index 28adc24197b8..7b165ee11a90 100644
--- a/drivers/net/ethernet/intel/ice/virt/queues.c
+++ b/drivers/net/ethernet/intel/ice/virt/queues.c
@@ -171,8 +171,8 @@ static int ice_vf_cfg_q_quanta_profile(struct ice_vf *vf, u16 quanta_size,
static bool ice_vc_validate_vqs_bitmaps(struct virtchnl_queue_select *vqs)
{
if ((!vqs->rx_queues && !vqs->tx_queues) ||
- vqs->rx_queues >= BIT(ICE_MAX_RSS_QS_PER_VF) ||
- vqs->tx_queues >= BIT(ICE_MAX_RSS_QS_PER_VF))
+ vqs->rx_queues >= BIT(ICE_MAX_QS_PER_VF_VCV1) ||
+ vqs->tx_queues >= BIT(ICE_MAX_QS_PER_VF_VCV1))
return false;
return true;
@@ -317,7 +317,7 @@ int ice_vc_ena_qs_msg(struct ice_vf *vf, u8 *msg)
* programmed using ice_vsi_cfg_txqs
*/
q_map = vqs->rx_queues;
- for_each_set_bit(vf_q_id, &q_map, ICE_MAX_RSS_QS_PER_VF) {
+ for_each_set_bit(vf_q_id, &q_map, ICE_MAX_QS_PER_VF_VCV1) {
if (!ice_vc_isvalid_q_id(vsi, vf_q_id)) {
v_ret = VIRTCHNL_STATUS_ERR_PARAM;
goto error_param;
@@ -330,7 +330,7 @@ int ice_vc_ena_qs_msg(struct ice_vf *vf, u8 *msg)
}
q_map = vqs->tx_queues;
- for_each_set_bit(vf_q_id, &q_map, ICE_MAX_RSS_QS_PER_VF) {
+ for_each_set_bit(vf_q_id, &q_map, ICE_MAX_QS_PER_VF_VCV1) {
if (!ice_vc_isvalid_q_id(vsi, vf_q_id)) {
v_ret = VIRTCHNL_STATUS_ERR_PARAM;
goto error_param;
@@ -461,7 +461,7 @@ int ice_vc_dis_qs_msg(struct ice_vf *vf, u8 *msg)
if (vqs->tx_queues) {
q_map = vqs->tx_queues;
- for_each_set_bit(vf_q_id, &q_map, ICE_MAX_RSS_QS_PER_VF) {
+ for_each_set_bit(vf_q_id, &q_map, ICE_MAX_QS_PER_VF_VCV1) {
if (!ice_vc_isvalid_q_id(vsi, vf_q_id)) {
v_ret = VIRTCHNL_STATUS_ERR_PARAM;
goto error_param;
@@ -476,7 +476,7 @@ int ice_vc_dis_qs_msg(struct ice_vf *vf, u8 *msg)
q_map = vqs->rx_queues;
if (q_map) {
- for_each_set_bit(vf_q_id, &q_map, ICE_MAX_RSS_QS_PER_VF) {
+ for_each_set_bit(vf_q_id, &q_map, ICE_MAX_QS_PER_VF_VCV1) {
if (!ice_vc_isvalid_q_id(vsi, vf_q_id)) {
v_ret = VIRTCHNL_STATUS_ERR_PARAM;
goto error_param;
@@ -519,7 +519,7 @@ ice_cfg_interrupt(struct ice_vf *vf, struct ice_vsi *vsi,
q_vector->num_ring_tx = 0;
qmap = map->rxq_map;
- for_each_set_bit(vsi_q_id_idx, &qmap, ICE_MAX_RSS_QS_PER_VF) {
+ for_each_set_bit(vsi_q_id_idx, &qmap, ICE_MAX_QS_PER_VF_VCV1) {
vsi_q_id = vsi_q_id_idx;
if (!ice_vc_isvalid_q_id(vsi, vsi_q_id))
@@ -534,7 +534,7 @@ ice_cfg_interrupt(struct ice_vf *vf, struct ice_vsi *vsi,
}
qmap = map->txq_map;
- for_each_set_bit(vsi_q_id_idx, &qmap, ICE_MAX_RSS_QS_PER_VF) {
+ for_each_set_bit(vsi_q_id_idx, &qmap, ICE_MAX_QS_PER_VF_VCV1) {
vsi_q_id = vsi_q_id_idx;
if (!ice_vc_isvalid_q_id(vsi, vsi_q_id))
@@ -658,7 +658,7 @@ int ice_vc_cfg_q_bw(struct ice_vf *vf, u8 *msg)
goto err;
}
- if (qbw->num_queues > ICE_MAX_RSS_QS_PER_VF ||
+ if (qbw->num_queues > ICE_MAX_QS_PER_VF_VCV1 ||
qbw->num_queues > min_t(u16, vsi->alloc_txq, vsi->alloc_rxq)) {
dev_err(ice_pf_to_dev(vf->pf), "VF-%d trying to configure more than allocated number of queues: %d\n",
vf->vf_id, min_t(u16, vsi->alloc_txq, vsi->alloc_rxq));
@@ -750,7 +750,7 @@ int ice_vc_cfg_q_quanta(struct ice_vf *vf, u8 *msg)
goto err;
}
- if (end_qid > ICE_MAX_RSS_QS_PER_VF ||
+ if (end_qid > ICE_MAX_QS_PER_VF_VCV1 ||
end_qid > min_t(u16, vsi->alloc_txq, vsi->alloc_rxq)) {
dev_err(ice_pf_to_dev(vf->pf), "VF-%d trying to configure more than allocated number of queues: %d\n",
vf->vf_id, min_t(u16, vsi->alloc_txq, vsi->alloc_rxq));
@@ -818,7 +818,7 @@ int ice_vc_cfg_qs_msg(struct ice_vf *vf, u8 *msg)
if (!vsi)
goto error_param;
- if (qci->num_queue_pairs > ICE_MAX_RSS_QS_PER_VF ||
+ if (qci->num_queue_pairs > ICE_MAX_QS_PER_VF_VCV1 ||
qci->num_queue_pairs > min_t(u16, vsi->alloc_txq, vsi->alloc_rxq)) {
dev_err(ice_pf_to_dev(pf), "VF-%d requesting more than supported number of queues: %d\n",
vf->vf_id, min_t(u16, vsi->alloc_txq, vsi->alloc_rxq));
@@ -996,16 +996,16 @@ int ice_vc_request_qs_msg(struct ice_vf *vf, u8 *msg)
if (!req_queues) {
dev_err(dev, "VF %d tried to request 0 queues. Ignoring.\n",
vf->vf_id);
- } else if (req_queues > ICE_MAX_RSS_QS_PER_VF) {
+ } else if (req_queues > ICE_MAX_QS_PER_VF_VCV1) {
dev_err(dev, "VF %d tried to request more than %d queues.\n",
- vf->vf_id, ICE_MAX_RSS_QS_PER_VF);
- vfres->num_queue_pairs = ICE_MAX_RSS_QS_PER_VF;
+ vf->vf_id, ICE_MAX_QS_PER_VF_VCV1);
+ vfres->num_queue_pairs = ICE_MAX_QS_PER_VF_VCV1;
} else if (req_queues > cur_queues &&
req_queues - cur_queues > tx_rx_queue_left) {
dev_warn(dev, "VF %d requested %u more queues, but only %u left.\n",
vf->vf_id, req_queues - cur_queues, tx_rx_queue_left);
vfres->num_queue_pairs = min_t(u16, max_allowed_vf_queues,
- ICE_MAX_RSS_QS_PER_VF);
+ ICE_MAX_QS_PER_VF_VCV1);
} else {
/* request is successful, then reset VF */
vf->num_req_qs = req_queues;
--
2.39.3
^ permalink raw reply related [flat|nested] 28+ messages in thread* [PATCH iwl-next v1 07/15] ice: bump to 256qs for VF
2026-05-08 12:41 [PATCH iwl-next v1 00/15] devlink, mlx5, iavf, ice: XLVF for iavf Przemek Kitszel
` (5 preceding siblings ...)
2026-05-08 12:41 ` [PATCH iwl-next v1 06/15] ice: rename ICE_MAX_RSS_QS_PER_VF to ICE_MAX_QS_PER_VF_VCV1 Przemek Kitszel
@ 2026-05-08 12:42 ` Przemek Kitszel
2026-05-08 12:42 ` [PATCH iwl-next v1 08/15] iavf: extend iavf_configure_queues() to support more queues Przemek Kitszel
` (7 subsequent siblings)
14 siblings, 0 replies; 28+ messages in thread
From: Przemek Kitszel @ 2026-05-08 12:42 UTC (permalink / raw)
To: intel-wired-lan, Michal Schmidt, Jakub Kicinski, Jiri Pirko
Cc: netdev, Simon Horman, Tony Nguyen, Michal Swiatkowski,
bruce.richardson, Vladimir Medvedkin, padraig.j.connolly,
ananth.s, timothy.miskell, Jacob Keller, Lukasz Czapnik,
Aleksandr Loktionov, Andrew Lunn, David S. Miller, Eric Dumazet,
Paolo Abeni, Saeed Mahameed, Leon Romanovsky, Tariq Toukan,
Mark Bloch, Przemek Kitszel, Jedrzej Jagielski
Adjust all bitmaps and arrays in ice to accept 256 VF queues.
Extend struct ice_vf::num_req_qs width to allow 256 queues.
Keep old/legacy size for virtchnl opcodes that were designed to accept
only up to 16 queues.
Reviewed-by: Jedrzej Jagielski <jedrzej.jagielski@intel.com>
Signed-off-by: Przemek Kitszel <przemyslaw.kitszel@intel.com>
---
drivers/net/ethernet/intel/ice/ice_lag.h | 2 +-
drivers/net/ethernet/intel/ice/ice_vf_lib.h | 9 +++++----
drivers/net/ethernet/intel/ice/ice_lib.c | 2 +-
drivers/net/ethernet/intel/ice/ice_sriov.c | 4 ++--
drivers/net/ethernet/intel/ice/ice_vf_lib.c | 8 ++++----
drivers/net/ethernet/intel/ice/virt/queues.c | 14 +++++++-------
6 files changed, 20 insertions(+), 19 deletions(-)
diff --git a/drivers/net/ethernet/intel/ice/ice_lag.h b/drivers/net/ethernet/intel/ice/ice_lag.h
index 4bfffecbdc97..39f6a6cc844d 100644
--- a/drivers/net/ethernet/intel/ice/ice_lag.h
+++ b/drivers/net/ethernet/intel/ice/ice_lag.h
@@ -52,7 +52,7 @@ struct ice_lag {
u8 bond_lport_sec; /* lport values for secondary PF */
/* q_home keeps track of which interface the q is currently on */
- u8 q_home[ICE_MAX_SRIOV_VFS][ICE_MAX_QS_PER_VF_VCV1];
+ u8 q_home[ICE_MAX_SRIOV_VFS][ICE_MAX_QS_PER_VF];
/* placeholder VSI for hanging VF queues from on secondary interface */
struct ice_vsi *sec_vf[ICE_MAX_SRIOV_VFS];
diff --git a/drivers/net/ethernet/intel/ice/ice_vf_lib.h b/drivers/net/ethernet/intel/ice/ice_vf_lib.h
index 36dbe5412336..1b56f7150eb7 100644
--- a/drivers/net/ethernet/intel/ice/ice_vf_lib.h
+++ b/drivers/net/ethernet/intel/ice/ice_vf_lib.h
@@ -21,6 +21,7 @@
/* VF resource constraints */
/* for "old" virtchnl opcodes that accept up to 16 queues */
#define ICE_MAX_QS_PER_VF_VCV1 16
+#define ICE_MAX_QS_PER_VF 256
struct ice_pf;
struct ice_vf;
@@ -162,8 +163,8 @@ struct ice_vf {
u8 dev_lan_addr[ETH_ALEN];
u8 hw_lan_addr[ETH_ALEN];
struct ice_time_mac legacy_last_added_umac;
- DECLARE_BITMAP(txq_ena, ICE_MAX_QS_PER_VF_VCV1);
- DECLARE_BITMAP(rxq_ena, ICE_MAX_QS_PER_VF_VCV1);
+ DECLARE_BITMAP(txq_ena, ICE_MAX_QS_PER_VF);
+ DECLARE_BITMAP(rxq_ena, ICE_MAX_QS_PER_VF);
struct ice_vlan port_vlan_info; /* Port VLAN ID, QoS, and TPID */
struct virtchnl_vlan_caps vlan_v2_caps;
struct ice_mbx_vf_info mbx_info;
@@ -185,7 +186,7 @@ struct ice_vf {
DECLARE_BITMAP(vf_states, ICE_VF_STATES_NBITS); /* VF runtime states */
unsigned long vf_caps; /* VF's adv. capabilities */
- u8 num_req_qs; /* num of queue pairs requested by VF */
+ u16 num_req_qs; /* num of queue pairs requested by VF */
u16 num_mac;
u16 num_mac_lldp;
u16 num_vf_qs; /* num of queue configured per VF */
@@ -206,7 +207,7 @@ struct ice_vf {
u16 lldp_recipe_id;
u16 lldp_rule_id;
- struct ice_vf_qs_bw qs_bw[ICE_MAX_QS_PER_VF_VCV1];
+ struct ice_vf_qs_bw qs_bw[ICE_MAX_QS_PER_VF];
};
/* Flags for controlling behavior of ice_reset_vf */
diff --git a/drivers/net/ethernet/intel/ice/ice_lib.c b/drivers/net/ethernet/intel/ice/ice_lib.c
index 09e1dcab2179..2ac4e23f30b5 100644
--- a/drivers/net/ethernet/intel/ice/ice_lib.c
+++ b/drivers/net/ethernet/intel/ice/ice_lib.c
@@ -925,7 +925,7 @@ static void ice_vsi_set_rss_params(struct ice_vsi *vsi)
* For VSI_LUT, LUT size should be set to 64 bytes.
*/
vsi->rss_table_size = ICE_LUT_VSI_SIZE;
- vsi->rss_size = ICE_MAX_QS_PER_VF_VCV1;
+ vsi->rss_size = ICE_MAX_QS_PER_VF;
vsi->rss_lut_type = ICE_LUT_VSI;
break;
case ICE_VSI_LB:
diff --git a/drivers/net/ethernet/intel/ice/ice_sriov.c b/drivers/net/ethernet/intel/ice/ice_sriov.c
index 0482454f453b..28f9e68f46cd 100644
--- a/drivers/net/ethernet/intel/ice/ice_sriov.c
+++ b/drivers/net/ethernet/intel/ice/ice_sriov.c
@@ -398,15 +398,15 @@ static int ice_set_per_vf_res(struct ice_pf *pf, u16 num_vfs)
}
num_txq = min_t(u16, num_msix_per_vf - ICE_NONQ_VECS_VF,
- ICE_MAX_QS_PER_VF_VCV1);
+ ICE_MAX_QS_PER_VF);
avail_qs = ice_get_avail_txq_count(pf) / num_vfs;
if (!avail_qs)
num_txq = 0;
else if (num_txq > avail_qs)
num_txq = rounddown_pow_of_two(avail_qs);
num_rxq = min_t(u16, num_msix_per_vf - ICE_NONQ_VECS_VF,
- ICE_MAX_QS_PER_VF_VCV1);
+ ICE_MAX_QS_PER_VF);
avail_qs = ice_get_avail_rxq_count(pf) / num_vfs;
if (!avail_qs)
num_rxq = 0;
diff --git a/drivers/net/ethernet/intel/ice/ice_vf_lib.c b/drivers/net/ethernet/intel/ice/ice_vf_lib.c
index 8e88ab8547ab..55ad03085bc9 100644
--- a/drivers/net/ethernet/intel/ice/ice_vf_lib.c
+++ b/drivers/net/ethernet/intel/ice/ice_vf_lib.c
@@ -535,8 +535,8 @@ static void ice_vf_rebuild_host_cfg(struct ice_vf *vf)
static void ice_set_vf_state_qs_dis(struct ice_vf *vf)
{
/* Clear Rx/Tx enabled queues flag */
- bitmap_zero(vf->txq_ena, ICE_MAX_QS_PER_VF_VCV1);
- bitmap_zero(vf->rxq_ena, ICE_MAX_QS_PER_VF_VCV1);
+ bitmap_zero(vf->txq_ena, ICE_MAX_QS_PER_VF);
+ bitmap_zero(vf->rxq_ena, ICE_MAX_QS_PER_VF);
clear_bit(ICE_VF_STATE_QS_ENA, vf->vf_states);
}
@@ -1222,8 +1222,8 @@ bool ice_is_vf_trusted(struct ice_vf *vf)
*/
bool ice_vf_has_no_qs_ena(struct ice_vf *vf)
{
- return bitmap_empty(vf->rxq_ena, ICE_MAX_QS_PER_VF_VCV1) &&
- bitmap_empty(vf->txq_ena, ICE_MAX_QS_PER_VF_VCV1);
+ return bitmap_empty(vf->rxq_ena, ICE_MAX_QS_PER_VF) &&
+ bitmap_empty(vf->txq_ena, ICE_MAX_QS_PER_VF);
}
/**
diff --git a/drivers/net/ethernet/intel/ice/virt/queues.c b/drivers/net/ethernet/intel/ice/virt/queues.c
index 7b165ee11a90..1d9f69026d1b 100644
--- a/drivers/net/ethernet/intel/ice/virt/queues.c
+++ b/drivers/net/ethernet/intel/ice/virt/queues.c
@@ -658,7 +658,7 @@ int ice_vc_cfg_q_bw(struct ice_vf *vf, u8 *msg)
goto err;
}
- if (qbw->num_queues > ICE_MAX_QS_PER_VF_VCV1 ||
+ if (qbw->num_queues > ICE_MAX_QS_PER_VF ||
qbw->num_queues > min_t(u16, vsi->alloc_txq, vsi->alloc_rxq)) {
dev_err(ice_pf_to_dev(vf->pf), "VF-%d trying to configure more than allocated number of queues: %d\n",
vf->vf_id, min_t(u16, vsi->alloc_txq, vsi->alloc_rxq));
@@ -750,7 +750,7 @@ int ice_vc_cfg_q_quanta(struct ice_vf *vf, u8 *msg)
goto err;
}
- if (end_qid > ICE_MAX_QS_PER_VF_VCV1 ||
+ if (end_qid > ICE_MAX_QS_PER_VF ||
end_qid > min_t(u16, vsi->alloc_txq, vsi->alloc_rxq)) {
dev_err(ice_pf_to_dev(vf->pf), "VF-%d trying to configure more than allocated number of queues: %d\n",
vf->vf_id, min_t(u16, vsi->alloc_txq, vsi->alloc_rxq));
@@ -818,7 +818,7 @@ int ice_vc_cfg_qs_msg(struct ice_vf *vf, u8 *msg)
if (!vsi)
goto error_param;
- if (qci->num_queue_pairs > ICE_MAX_QS_PER_VF_VCV1 ||
+ if (qci->num_queue_pairs > ICE_MAX_QS_PER_VF ||
qci->num_queue_pairs > min_t(u16, vsi->alloc_txq, vsi->alloc_rxq)) {
dev_err(ice_pf_to_dev(pf), "VF-%d requesting more than supported number of queues: %d\n",
vf->vf_id, min_t(u16, vsi->alloc_txq, vsi->alloc_rxq));
@@ -996,16 +996,16 @@ int ice_vc_request_qs_msg(struct ice_vf *vf, u8 *msg)
if (!req_queues) {
dev_err(dev, "VF %d tried to request 0 queues. Ignoring.\n",
vf->vf_id);
- } else if (req_queues > ICE_MAX_QS_PER_VF_VCV1) {
+ } else if (req_queues > ICE_MAX_QS_PER_VF) {
dev_err(dev, "VF %d tried to request more than %d queues.\n",
- vf->vf_id, ICE_MAX_QS_PER_VF_VCV1);
- vfres->num_queue_pairs = ICE_MAX_QS_PER_VF_VCV1;
+ vf->vf_id, ICE_MAX_QS_PER_VF);
+ vfres->num_queue_pairs = ICE_MAX_QS_PER_VF;
} else if (req_queues > cur_queues &&
req_queues - cur_queues > tx_rx_queue_left) {
dev_warn(dev, "VF %d requested %u more queues, but only %u left.\n",
vf->vf_id, req_queues - cur_queues, tx_rx_queue_left);
vfres->num_queue_pairs = min_t(u16, max_allowed_vf_queues,
- ICE_MAX_QS_PER_VF_VCV1);
+ ICE_MAX_QS_PER_VF);
} else {
/* request is successful, then reset VF */
vf->num_req_qs = req_queues;
--
2.39.3
^ permalink raw reply related [flat|nested] 28+ messages in thread* [PATCH iwl-next v1 08/15] iavf: extend iavf_configure_queues() to support more queues
2026-05-08 12:41 [PATCH iwl-next v1 00/15] devlink, mlx5, iavf, ice: XLVF for iavf Przemek Kitszel
` (6 preceding siblings ...)
2026-05-08 12:42 ` [PATCH iwl-next v1 07/15] ice: bump to 256qs for VF Przemek Kitszel
@ 2026-05-08 12:42 ` Przemek Kitszel
2026-05-08 12:42 ` [PATCH iwl-next v1 09/15] iavf: temporary rename of IAVF_MAX_REQ_QUEUES to IAVF_MAX_REQ_QUEUES_VCV1 Przemek Kitszel
` (6 subsequent siblings)
14 siblings, 0 replies; 28+ messages in thread
From: Przemek Kitszel @ 2026-05-08 12:42 UTC (permalink / raw)
To: intel-wired-lan, Michal Schmidt, Jakub Kicinski, Jiri Pirko
Cc: netdev, Simon Horman, Tony Nguyen, Michal Swiatkowski,
bruce.richardson, Vladimir Medvedkin, padraig.j.connolly,
ananth.s, timothy.miskell, Jacob Keller, Lukasz Czapnik,
Aleksandr Loktionov, Andrew Lunn, David S. Miller, Eric Dumazet,
Paolo Abeni, Saeed Mahameed, Leon Romanovsky, Tariq Toukan,
Mark Bloch, Przemek Kitszel
Extend iavf_configure_queues() to support more than 31 queues.
Virtchnl opcode used was already generic, but we have just not needed
more than one message before.
Add helper, iavf_max_vc_entries(), that determines how many entries we
could fit into virtchnl message (ending by flex array member). Will be
also used on another op later in this series.
Signed-off-by: Przemek Kitszel <przemyslaw.kitszel@intel.com>
---
.../net/ethernet/intel/iavf/iavf_virtchnl.c | 55 +++++++++++++++----
1 file changed, 45 insertions(+), 10 deletions(-)
diff --git a/drivers/net/ethernet/intel/iavf/iavf_virtchnl.c b/drivers/net/ethernet/intel/iavf/iavf_virtchnl.c
index a2f75bb4a74e..7a97fc76420f 100644
--- a/drivers/net/ethernet/intel/iavf/iavf_virtchnl.c
+++ b/drivers/net/ethernet/intel/iavf/iavf_virtchnl.c
@@ -8,6 +8,11 @@
#include "iavf_ptp.h"
#include "iavf_prototype.h"
+/* how many Flex Array Member entires do fit into VC message of type *ptr */
+#define iavf_max_vc_entries(ptr, flex_member) \
+ ((IAVF_MAX_AQ_BUF_SIZE - virtchnl_struct_size(ptr, flex_member, 1)) / \
+ sizeof(ptr->flex_member[0]) + 1)
+
/**
* iavf_send_pf_msg
* @adapter: adapter structure
@@ -366,6 +371,14 @@ int iavf_get_vf_ptp_caps(struct iavf_adapter *adapter)
return err;
}
+static bool iavf_match_vc_op_cb(struct iavf_adapter *adapter, const void *data,
+ enum virtchnl_ops recv_op)
+{
+ enum virtchnl_ops wanted_op = (enum virtchnl_ops)data;
+
+ return recv_op == wanted_op;
+}
+
/**
* iavf_configure_queues
* @adapter: adapter structure
@@ -377,8 +390,9 @@ void iavf_configure_queues(struct iavf_adapter *adapter)
struct virtchnl_vsi_queue_config_info *vqci;
int pairs = adapter->num_active_queues;
struct virtchnl_queue_pair_info *vqpi;
- u32 i, max_frame;
u8 rx_flags = 0;
+ u32 max_frame;
+ int max_pairs;
size_t len;
max_frame = LIBIE_MAX_RX_FRM_LEN(adapter->rx_rings->pp->p.offset);
@@ -390,22 +404,22 @@ void iavf_configure_queues(struct iavf_adapter *adapter)
adapter->current_op);
return;
}
- adapter->current_op = VIRTCHNL_OP_CONFIG_VSI_QUEUES;
- len = virtchnl_struct_size(vqci, qpair, pairs);
+
+ max_pairs = iavf_max_vc_entries(vqci, qpair);
+ len = virtchnl_struct_size(vqci, qpair, min(pairs, max_pairs));
vqci = kzalloc(len, GFP_KERNEL);
if (!vqci)
return;
if (iavf_ptp_cap_supported(adapter, VIRTCHNL_1588_PTP_CAP_RX_TSTAMP))
rx_flags |= VIRTCHNL_PTP_RX_TSTAMP;
vqci->vsi_id = adapter->vsi_res->vsi_id;
- vqci->num_queue_pairs = pairs;
vqpi = vqci->qpair;
- /* Size check is not needed here - HW max is 16 queue pairs, and we
- * can fit info for 31 of them into the AQ buffer before it overflows.
- */
- for (i = 0; i < pairs; i++) {
+
+ for (int i = 0, in_msg = 0; i < pairs; i++) {
+ const bool last = i + 1 == pairs;
+
vqpi->txq.vsi_id = vqci->vsi_id;
vqpi->txq.queue_id = i;
vqpi->txq.ring_len = adapter->tx_rings[i].count;
@@ -423,11 +437,32 @@ void iavf_configure_queues(struct iavf_adapter *adapter)
NETIF_F_RXFCS);
vqpi->rxq.flags = rx_flags;
vqpi++;
+ in_msg++;
+ if (last || in_msg == max_pairs) {
+ int err;
+
+ adapter->current_op = VIRTCHNL_OP_CONFIG_VSI_QUEUES;
+ vqci->num_queue_pairs = in_msg;
+
+ iavf_send_pf_msg(adapter,
+ VIRTCHNL_OP_CONFIG_VSI_QUEUES,
+ (u8 *)vqci,
+ virtchnl_struct_size(vqci, qpair, in_msg));
+ err = iavf_poll_virtchnl_response(adapter,
+ iavf_match_vc_op_cb,
+ (void *)VIRTCHNL_OP_CONFIG_VSI_QUEUES,
+ 1000);
+ if (err)
+ dev_warn(&adapter->pdev->dev,
+ "config queues poll failed, err: %d\n",
+ err);
+
+ vqpi = vqci->qpair;
+ in_msg = 0;
+ }
}
adapter->aq_required &= ~IAVF_FLAG_AQ_CONFIGURE_QUEUES;
- iavf_send_pf_msg(adapter, VIRTCHNL_OP_CONFIG_VSI_QUEUES,
- (u8 *)vqci, len);
kfree(vqci);
}
--
2.39.3
^ permalink raw reply related [flat|nested] 28+ messages in thread* [PATCH iwl-next v1 09/15] iavf: temporary rename of IAVF_MAX_REQ_QUEUES to IAVF_MAX_REQ_QUEUES_VCV1
2026-05-08 12:41 [PATCH iwl-next v1 00/15] devlink, mlx5, iavf, ice: XLVF for iavf Przemek Kitszel
` (7 preceding siblings ...)
2026-05-08 12:42 ` [PATCH iwl-next v1 08/15] iavf: extend iavf_configure_queues() to support more queues Przemek Kitszel
@ 2026-05-08 12:42 ` Przemek Kitszel
2026-05-08 12:42 ` [PATCH iwl-next v1 10/15] iavf: increase max number of queues to 256 Przemek Kitszel
` (5 subsequent siblings)
14 siblings, 0 replies; 28+ messages in thread
From: Przemek Kitszel @ 2026-05-08 12:42 UTC (permalink / raw)
To: intel-wired-lan, Michal Schmidt, Jakub Kicinski, Jiri Pirko
Cc: netdev, Simon Horman, Tony Nguyen, Michal Swiatkowski,
bruce.richardson, Vladimir Medvedkin, padraig.j.connolly,
ananth.s, timothy.miskell, Jacob Keller, Lukasz Czapnik,
Aleksandr Loktionov, Andrew Lunn, David S. Miller, Eric Dumazet,
Paolo Abeni, Saeed Mahameed, Leon Romanovsky, Tariq Toukan,
Mark Bloch, Przemek Kitszel, Jedrzej Jagielski
Rename IAVF_MAX_REQ_QUEUES to IAVF_MAX_REQ_QUEUES_VCV1, in preparation for
the next patch that will extend the max to 256, using old value of 16 for
the "v1" variant of virtchnl opcodes.
Suggested-by: Jedrzej Jagielski <jedrzej.jagielski@intel.com>
Suggested-by: Jacob Keller <jacob.e.keller@intel.com>
Reviewed-by: Aleksandr Loktionov <aleksandr.loktionov@intel.com>
Signed-off-by: Przemek Kitszel <przemyslaw.kitszel@intel.com>
---
drivers/net/ethernet/intel/iavf/iavf.h | 3 ++-
drivers/net/ethernet/intel/iavf/iavf_main.c | 2 +-
drivers/net/ethernet/intel/iavf/iavf_virtchnl.c | 10 +++++-----
3 files changed, 8 insertions(+), 7 deletions(-)
diff --git a/drivers/net/ethernet/intel/iavf/iavf.h b/drivers/net/ethernet/intel/iavf/iavf.h
index d97f0fd2cd0a..a0c42f2357fb 100644
--- a/drivers/net/ethernet/intel/iavf/iavf.h
+++ b/drivers/net/ethernet/intel/iavf/iavf.h
@@ -87,7 +87,8 @@ struct iavf_vsi {
#define IAVF_TX_DESC(R, i) (&(((struct iavf_tx_desc *)((R)->desc))[i]))
#define IAVF_TX_CTXTDESC(R, i) \
(&(((struct iavf_tx_context_desc *)((R)->desc))[i]))
-#define IAVF_MAX_REQ_QUEUES 16
+/* for "old" virtchnl opcodes that accept up to 16 queues */
+#define IAVF_MAX_REQ_QUEUES_VCV1 16
#define IAVF_HKEY_ARRAY_SIZE ((IAVF_VFQF_HKEY_MAX_INDEX + 1) * 4)
#define IAVF_HLUT_ARRAY_SIZE ((IAVF_VFQF_HLUT_MAX_INDEX + 1) * 4)
diff --git a/drivers/net/ethernet/intel/iavf/iavf_main.c b/drivers/net/ethernet/intel/iavf/iavf_main.c
index 1f9fcb82ddcb..8149b01ae24a 100644
--- a/drivers/net/ethernet/intel/iavf/iavf_main.c
+++ b/drivers/net/ethernet/intel/iavf/iavf_main.c
@@ -5362,7 +5362,7 @@ static int iavf_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
pci_set_master(pdev);
netdev = alloc_etherdev_mq(sizeof(struct iavf_adapter),
- IAVF_MAX_REQ_QUEUES);
+ IAVF_MAX_REQ_QUEUES_VCV1);
if (!netdev) {
err = -ENOMEM;
goto err_alloc_etherdev;
diff --git a/drivers/net/ethernet/intel/iavf/iavf_virtchnl.c b/drivers/net/ethernet/intel/iavf/iavf_virtchnl.c
index 7a97fc76420f..d3b5398b6130 100644
--- a/drivers/net/ethernet/intel/iavf/iavf_virtchnl.c
+++ b/drivers/net/ethernet/intel/iavf/iavf_virtchnl.c
@@ -260,19 +260,19 @@ int iavf_send_vf_ptp_caps_msg(struct iavf_adapter *adapter)
**/
static void iavf_validate_num_queues(struct iavf_adapter *adapter)
{
- if (adapter->vf_res->num_queue_pairs > IAVF_MAX_REQ_QUEUES) {
+ if (adapter->vf_res->num_queue_pairs > IAVF_MAX_REQ_QUEUES_VCV1) {
struct virtchnl_vsi_resource *vsi_res;
int i;
dev_info(&adapter->pdev->dev, "Received %d queues, but can only have a max of %d\n",
adapter->vf_res->num_queue_pairs,
- IAVF_MAX_REQ_QUEUES);
+ IAVF_MAX_REQ_QUEUES_VCV1);
dev_info(&adapter->pdev->dev, "Fixing by reducing queues to %d\n",
- IAVF_MAX_REQ_QUEUES);
- adapter->vf_res->num_queue_pairs = IAVF_MAX_REQ_QUEUES;
+ IAVF_MAX_REQ_QUEUES_VCV1);
+ adapter->vf_res->num_queue_pairs = IAVF_MAX_REQ_QUEUES_VCV1;
for (i = 0; i < adapter->vf_res->num_vsis; i++) {
vsi_res = &adapter->vf_res->vsi_res[i];
- vsi_res->num_queue_pairs = IAVF_MAX_REQ_QUEUES;
+ vsi_res->num_queue_pairs = IAVF_MAX_REQ_QUEUES_VCV1;
}
}
}
--
2.39.3
^ permalink raw reply related [flat|nested] 28+ messages in thread* [PATCH iwl-next v1 10/15] iavf: increase max number of queues to 256
2026-05-08 12:41 [PATCH iwl-next v1 00/15] devlink, mlx5, iavf, ice: XLVF for iavf Przemek Kitszel
` (8 preceding siblings ...)
2026-05-08 12:42 ` [PATCH iwl-next v1 09/15] iavf: temporary rename of IAVF_MAX_REQ_QUEUES to IAVF_MAX_REQ_QUEUES_VCV1 Przemek Kitszel
@ 2026-05-08 12:42 ` Przemek Kitszel
2026-05-08 16:49 ` Loktionov, Aleksandr
2026-05-08 12:42 ` [PATCH iwl-next v1 11/15] iavf: use new opcodes to request more than 16 queues Przemek Kitszel
` (4 subsequent siblings)
14 siblings, 1 reply; 28+ messages in thread
From: Przemek Kitszel @ 2026-05-08 12:42 UTC (permalink / raw)
To: intel-wired-lan, Michal Schmidt, Jakub Kicinski, Jiri Pirko
Cc: netdev, Simon Horman, Tony Nguyen, Michal Swiatkowski,
bruce.richardson, Vladimir Medvedkin, padraig.j.connolly,
ananth.s, timothy.miskell, Jacob Keller, Lukasz Czapnik,
Aleksandr Loktionov, Andrew Lunn, David S. Miller, Eric Dumazet,
Paolo Abeni, Saeed Mahameed, Leon Romanovsky, Tariq Toukan,
Mark Bloch, Przemek Kitszel, Jedrzej Jagielski
Increase the max number of queues that driver will handle to 256.
Use old legacy limit in the virtchnl handling of iavf_map_queues().
Reviewed-by: Jedrzej Jagielski <jedrzej.jagielski@intel.com>
Signed-off-by: Przemek Kitszel <przemyslaw.kitszel@intel.com>
---
drivers/net/ethernet/intel/iavf/iavf.h | 4 +++-
drivers/net/ethernet/intel/iavf/iavf_main.c | 4 ++--
drivers/net/ethernet/intel/iavf/iavf_virtchnl.c | 15 ++++++++-------
3 files changed, 13 insertions(+), 10 deletions(-)
diff --git a/drivers/net/ethernet/intel/iavf/iavf.h b/drivers/net/ethernet/intel/iavf/iavf.h
index a0c42f2357fb..569686d34ff4 100644
--- a/drivers/net/ethernet/intel/iavf/iavf.h
+++ b/drivers/net/ethernet/intel/iavf/iavf.h
@@ -87,8 +87,10 @@ struct iavf_vsi {
#define IAVF_TX_DESC(R, i) (&(((struct iavf_tx_desc *)((R)->desc))[i]))
#define IAVF_TX_CTXTDESC(R, i) \
(&(((struct iavf_tx_context_desc *)((R)->desc))[i]))
+
/* for "old" virtchnl opcodes that accept up to 16 queues */
#define IAVF_MAX_REQ_QUEUES_VCV1 16
+#define IAVF_MAX_REQ_QUEUES 256
#define IAVF_HKEY_ARRAY_SIZE ((IAVF_VFQF_HKEY_MAX_INDEX + 1) * 4)
#define IAVF_HLUT_ARRAY_SIZE ((IAVF_VFQF_HLUT_MAX_INDEX + 1) * 4)
@@ -108,7 +110,7 @@ struct iavf_q_vector {
struct napi_struct napi;
struct iavf_ring_container rx;
struct iavf_ring_container tx;
- u32 ring_mask;
+ DECLARE_BITMAP(ring_mask, IAVF_MAX_REQ_QUEUES);
u8 itr_countdown; /* when 0 should adjust adaptive ITR */
u8 num_ringpairs; /* total number of ring pairs in vector */
u16 v_idx; /* index in the vsi->q_vector array. */
diff --git a/drivers/net/ethernet/intel/iavf/iavf_main.c b/drivers/net/ethernet/intel/iavf/iavf_main.c
index 8149b01ae24a..abc0fe070ee7 100644
--- a/drivers/net/ethernet/intel/iavf/iavf_main.c
+++ b/drivers/net/ethernet/intel/iavf/iavf_main.c
@@ -439,7 +439,7 @@ iavf_map_vector_to_rxq(struct iavf_adapter *adapter, int v_idx, int r_idx)
q_vector->rx.count++;
q_vector->rx.next_update = jiffies + 1;
q_vector->rx.target_itr = ITR_TO_REG(rx_ring->itr_setting);
- q_vector->ring_mask |= BIT(r_idx);
+ set_bit(r_idx, q_vector->ring_mask);
wr32(hw, IAVF_VFINT_ITRN1(IAVF_RX_ITR, q_vector->reg_idx),
q_vector->rx.current_itr >> 1);
q_vector->rx.current_itr = q_vector->rx.target_itr;
@@ -5362,7 +5362,7 @@ static int iavf_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
pci_set_master(pdev);
netdev = alloc_etherdev_mq(sizeof(struct iavf_adapter),
- IAVF_MAX_REQ_QUEUES_VCV1);
+ IAVF_MAX_REQ_QUEUES);
if (!netdev) {
err = -ENOMEM;
goto err_alloc_etherdev;
diff --git a/drivers/net/ethernet/intel/iavf/iavf_virtchnl.c b/drivers/net/ethernet/intel/iavf/iavf_virtchnl.c
index d3b5398b6130..9102bc4bddb0 100644
--- a/drivers/net/ethernet/intel/iavf/iavf_virtchnl.c
+++ b/drivers/net/ethernet/intel/iavf/iavf_virtchnl.c
@@ -260,19 +260,19 @@ int iavf_send_vf_ptp_caps_msg(struct iavf_adapter *adapter)
**/
static void iavf_validate_num_queues(struct iavf_adapter *adapter)
{
- if (adapter->vf_res->num_queue_pairs > IAVF_MAX_REQ_QUEUES_VCV1) {
+ if (adapter->vf_res->num_queue_pairs > IAVF_MAX_REQ_QUEUES) {
struct virtchnl_vsi_resource *vsi_res;
int i;
dev_info(&adapter->pdev->dev, "Received %d queues, but can only have a max of %d\n",
adapter->vf_res->num_queue_pairs,
- IAVF_MAX_REQ_QUEUES_VCV1);
+ IAVF_MAX_REQ_QUEUES);
dev_info(&adapter->pdev->dev, "Fixing by reducing queues to %d\n",
- IAVF_MAX_REQ_QUEUES_VCV1);
- adapter->vf_res->num_queue_pairs = IAVF_MAX_REQ_QUEUES_VCV1;
+ IAVF_MAX_REQ_QUEUES);
+ adapter->vf_res->num_queue_pairs = IAVF_MAX_REQ_QUEUES;
for (i = 0; i < adapter->vf_res->num_vsis; i++) {
vsi_res = &adapter->vf_res->vsi_res[i];
- vsi_res->num_queue_pairs = IAVF_MAX_REQ_QUEUES_VCV1;
+ vsi_res->num_queue_pairs = IAVF_MAX_REQ_QUEUES;
}
}
}
@@ -554,8 +554,9 @@ void iavf_map_queues(struct iavf_adapter *adapter)
vecmap->vsi_id = adapter->vsi_res->vsi_id;
vecmap->vector_id = v_idx + NONQ_VECS;
- vecmap->txq_map = q_vector->ring_mask;
- vecmap->rxq_map = q_vector->ring_mask;
+ vecmap->txq_map = bitmap_read(q_vector->ring_mask, 0,
+ IAVF_MAX_REQ_QUEUES_VCV1);
+ vecmap->rxq_map = vecmap->txq_map;
vecmap->rxitr_idx = IAVF_RX_ITR;
vecmap->txitr_idx = IAVF_TX_ITR;
}
--
2.39.3
^ permalink raw reply related [flat|nested] 28+ messages in thread* RE: [PATCH iwl-next v1 10/15] iavf: increase max number of queues to 256
2026-05-08 12:42 ` [PATCH iwl-next v1 10/15] iavf: increase max number of queues to 256 Przemek Kitszel
@ 2026-05-08 16:49 ` Loktionov, Aleksandr
2026-05-11 9:37 ` Przemek Kitszel
0 siblings, 1 reply; 28+ messages in thread
From: Loktionov, Aleksandr @ 2026-05-08 16:49 UTC (permalink / raw)
To: Kitszel, Przemyslaw, intel-wired-lan@lists.osuosl.org,
Schmidt, Michal, Jakub Kicinski, Jiri Pirko
Cc: netdev@vger.kernel.org, Simon Horman, Nguyen, Anthony L,
Michal Swiatkowski, Richardson, Bruce, Medvedkin, Vladimir,
Connolly, Padraig J, S, Ananth, Miskell, Timothy, Keller, Jacob E,
Czapnik, Lukasz, Andrew Lunn, David S. Miller, Eric Dumazet,
Paolo Abeni, Saeed Mahameed, Leon Romanovsky, Tariq Toukan,
Mark Bloch, Jagielski, Jedrzej
> -----Original Message-----
> From: Kitszel, Przemyslaw <przemyslaw.kitszel@intel.com>
> Sent: Friday, May 8, 2026 2:42 PM
> To: intel-wired-lan@lists.osuosl.org; Schmidt, Michal
> <mschmidt@redhat.com>; Jakub Kicinski <kuba@kernel.org>; Jiri Pirko
> <jiri@resnulli.us>
> Cc: netdev@vger.kernel.org; Simon Horman <horms@kernel.org>; Nguyen,
> Anthony L <anthony.l.nguyen@intel.com>; Michal Swiatkowski
> <michal.swiatkowski@linux.intel.com>; Richardson, Bruce
> <bruce.richardson@intel.com>; Medvedkin, Vladimir
> <vladimir.medvedkin@intel.com>; Connolly, Padraig J
> <padraig.j.connolly@intel.com>; S, Ananth <ananth.s@intel.com>;
> Miskell, Timothy <timothy.miskell@intel.com>; Keller, Jacob E
> <jacob.e.keller@intel.com>; Czapnik, Lukasz
> <lukasz.czapnik@intel.com>; Loktionov, Aleksandr
> <aleksandr.loktionov@intel.com>; Andrew Lunn <andrew+netdev@lunn.ch>;
> David S. Miller <davem@davemloft.net>; Eric Dumazet
> <edumazet@google.com>; Paolo Abeni <pabeni@redhat.com>; Saeed Mahameed
> <saeedm@nvidia.com>; Leon Romanovsky <leon@kernel.org>; Tariq Toukan
> <tariqt@nvidia.com>; Mark Bloch <mbloch@nvidia.com>; Kitszel,
> Przemyslaw <przemyslaw.kitszel@intel.com>; Jagielski, Jedrzej
> <jedrzej.jagielski@intel.com>
> Subject: [PATCH iwl-next v1 10/15] iavf: increase max number of queues
> to 256
>
> Increase the max number of queues that driver will handle to 256.
> Use old legacy limit in the virtchnl handling of iavf_map_queues().
>
> Reviewed-by: Jedrzej Jagielski <jedrzej.jagielski@intel.com>
> Signed-off-by: Przemek Kitszel <przemyslaw.kitszel@intel.com>
> ---
> drivers/net/ethernet/intel/iavf/iavf.h | 4 +++-
> drivers/net/ethernet/intel/iavf/iavf_main.c | 4 ++--
> drivers/net/ethernet/intel/iavf/iavf_virtchnl.c | 15 ++++++++-------
> 3 files changed, 13 insertions(+), 10 deletions(-)
>
> diff --git a/drivers/net/ethernet/intel/iavf/iavf.h
> b/drivers/net/ethernet/intel/iavf/iavf.h
> index a0c42f2357fb..569686d34ff4 100644
> --- a/drivers/net/ethernet/intel/iavf/iavf.h
> +++ b/drivers/net/ethernet/intel/iavf/iavf.h
> @@ -87,8 +87,10 @@ struct iavf_vsi {
> #define IAVF_TX_DESC(R, i) (&(((struct iavf_tx_desc *)((R)-
> >desc))[i])) #define IAVF_TX_CTXTDESC(R, i) \
> (&(((struct iavf_tx_context_desc *)((R)->desc))[i]))
> +
> /* for "old" virtchnl opcodes that accept up to 16 queues */
> #define IAVF_MAX_REQ_QUEUES_VCV1 16
> +#define IAVF_MAX_REQ_QUEUES 256
>
> #define IAVF_HKEY_ARRAY_SIZE ((IAVF_VFQF_HKEY_MAX_INDEX + 1) * 4)
> #define IAVF_HLUT_ARRAY_SIZE ((IAVF_VFQF_HLUT_MAX_INDEX + 1) * 4) @@ -
> 108,7 +110,7 @@ struct iavf_q_vector {
> struct napi_struct napi;
> struct iavf_ring_container rx;
> struct iavf_ring_container tx;
> - u32 ring_mask;
> + DECLARE_BITMAP(ring_mask, IAVF_MAX_REQ_QUEUES);
> u8 itr_countdown; /* when 0 should adjust adaptive ITR */
> u8 num_ringpairs; /* total number of ring pairs in vector */
> u16 v_idx; /* index in the vsi->q_vector array. */
> diff --git a/drivers/net/ethernet/intel/iavf/iavf_main.c
> b/drivers/net/ethernet/intel/iavf/iavf_main.c
> index 8149b01ae24a..abc0fe070ee7 100644
> --- a/drivers/net/ethernet/intel/iavf/iavf_main.c
> +++ b/drivers/net/ethernet/intel/iavf/iavf_main.c
> @@ -439,7 +439,7 @@ iavf_map_vector_to_rxq(struct iavf_adapter
> *adapter, int v_idx, int r_idx)
> q_vector->rx.count++;
> q_vector->rx.next_update = jiffies + 1;
> q_vector->rx.target_itr = ITR_TO_REG(rx_ring->itr_setting);
> - q_vector->ring_mask |= BIT(r_idx);
> + set_bit(r_idx, q_vector->ring_mask);
> wr32(hw, IAVF_VFINT_ITRN1(IAVF_RX_ITR, q_vector->reg_idx),
> q_vector->rx.current_itr >> 1);
> q_vector->rx.current_itr = q_vector->rx.target_itr; @@ -5362,7
> +5362,7 @@ static int iavf_probe(struct pci_dev *pdev, const struct
> pci_device_id *ent)
> pci_set_master(pdev);
>
> netdev = alloc_etherdev_mq(sizeof(struct iavf_adapter),
> - IAVF_MAX_REQ_QUEUES_VCV1);
> + IAVF_MAX_REQ_QUEUES);
> if (!netdev) {
> err = -ENOMEM;
> goto err_alloc_etherdev;
> diff --git a/drivers/net/ethernet/intel/iavf/iavf_virtchnl.c
> b/drivers/net/ethernet/intel/iavf/iavf_virtchnl.c
> index d3b5398b6130..9102bc4bddb0 100644
> --- a/drivers/net/ethernet/intel/iavf/iavf_virtchnl.c
> +++ b/drivers/net/ethernet/intel/iavf/iavf_virtchnl.c
> @@ -260,19 +260,19 @@ int iavf_send_vf_ptp_caps_msg(struct
> iavf_adapter *adapter)
> **/
> static void iavf_validate_num_queues(struct iavf_adapter *adapter) {
> - if (adapter->vf_res->num_queue_pairs >
> IAVF_MAX_REQ_QUEUES_VCV1) {
> + if (adapter->vf_res->num_queue_pairs > IAVF_MAX_REQ_QUEUES) {
> struct virtchnl_vsi_resource *vsi_res;
> int i;
>
> dev_info(&adapter->pdev->dev, "Received %d queues, but
> can only have a max of %d\n",
> adapter->vf_res->num_queue_pairs,
> - IAVF_MAX_REQ_QUEUES_VCV1);
> + IAVF_MAX_REQ_QUEUES);
> dev_info(&adapter->pdev->dev, "Fixing by reducing queues
> to %d\n",
> - IAVF_MAX_REQ_QUEUES_VCV1);
> - adapter->vf_res->num_queue_pairs =
> IAVF_MAX_REQ_QUEUES_VCV1;
> + IAVF_MAX_REQ_QUEUES);
> + adapter->vf_res->num_queue_pairs = IAVF_MAX_REQ_QUEUES;
> for (i = 0; i < adapter->vf_res->num_vsis; i++) {
> vsi_res = &adapter->vf_res->vsi_res[i];
> - vsi_res->num_queue_pairs =
> IAVF_MAX_REQ_QUEUES_VCV1;
> + vsi_res->num_queue_pairs = IAVF_MAX_REQ_QUEUES;
> }
> }
> }
> @@ -554,8 +554,9 @@ void iavf_map_queues(struct iavf_adapter *adapter)
>
> vecmap->vsi_id = adapter->vsi_res->vsi_id;
> vecmap->vector_id = v_idx + NONQ_VECS;
> - vecmap->txq_map = q_vector->ring_mask;
> - vecmap->rxq_map = q_vector->ring_mask;
> + vecmap->txq_map = bitmap_read(q_vector->ring_mask, 0,
> + IAVF_MAX_REQ_QUEUES_VCV1);
It looks like a silent data loss on the legacy/V1 opcode path.
You read only 16 bits here.
> + vecmap->rxq_map = vecmap->txq_map;
> vecmap->rxitr_idx = IAVF_RX_ITR;
> vecmap->txitr_idx = IAVF_TX_ITR;
> }
> --
> 2.39.3
^ permalink raw reply [flat|nested] 28+ messages in thread* Re: [PATCH iwl-next v1 10/15] iavf: increase max number of queues to 256
2026-05-08 16:49 ` Loktionov, Aleksandr
@ 2026-05-11 9:37 ` Przemek Kitszel
0 siblings, 0 replies; 28+ messages in thread
From: Przemek Kitszel @ 2026-05-11 9:37 UTC (permalink / raw)
To: Loktionov, Aleksandr
Cc: netdev@vger.kernel.org, Simon Horman, Nguyen, Anthony L,
Michal Swiatkowski, Richardson, Bruce, Medvedkin, Vladimir,
Connolly, Padraig J, S, Ananth, Miskell, Timothy, Keller, Jacob E,
Czapnik, Lukasz, Andrew Lunn, David S. Miller, Eric Dumazet,
Paolo Abeni, Saeed Mahameed, Leon Romanovsky, Tariq Toukan,
Mark Bloch, Jagielski, Jedrzej, intel-wired-lan@lists.osuosl.org,
Schmidt, Michal, Jakub Kicinski, Jiri Pirko
>> @@ -554,8 +554,9 @@ void iavf_map_queues(struct iavf_adapter *adapter)
>>
>> vecmap->vsi_id = adapter->vsi_res->vsi_id;
>> vecmap->vector_id = v_idx + NONQ_VECS;
>> - vecmap->txq_map = q_vector->ring_mask;
>> - vecmap->rxq_map = q_vector->ring_mask;
>> + vecmap->txq_map = bitmap_read(q_vector->ring_mask, 0,
>> + IAVF_MAX_REQ_QUEUES_VCV1);
> It looks like a silent data loss on the legacy/V1 opcode path.
> You read only 16 bits here.
and this VC opcode is used only with upto 16 now
next patch (11th) adds an early check in this function to dispatch
to new opcodes in the case that more than 16 queues are used
(so, no need for change IMO)
>
>> + vecmap->rxq_map = vecmap->txq_map;
>> vecmap->rxitr_idx = IAVF_RX_ITR;
>> vecmap->txitr_idx = IAVF_TX_ITR;
>> }
>> --
>> 2.39.3
>
^ permalink raw reply [flat|nested] 28+ messages in thread
* [PATCH iwl-next v1 11/15] iavf: use new opcodes to request more than 16 queues
2026-05-08 12:41 [PATCH iwl-next v1 00/15] devlink, mlx5, iavf, ice: XLVF for iavf Przemek Kitszel
` (9 preceding siblings ...)
2026-05-08 12:42 ` [PATCH iwl-next v1 10/15] iavf: increase max number of queues to 256 Przemek Kitszel
@ 2026-05-08 12:42 ` Przemek Kitszel
2026-05-08 12:42 ` [PATCH iwl-next v1 12/15] ice: introduce handling of virtchnl LARGE VF opcodes Przemek Kitszel
` (3 subsequent siblings)
14 siblings, 0 replies; 28+ messages in thread
From: Przemek Kitszel @ 2026-05-08 12:42 UTC (permalink / raw)
To: intel-wired-lan, Michal Schmidt, Jakub Kicinski, Jiri Pirko
Cc: netdev, Simon Horman, Tony Nguyen, Michal Swiatkowski,
bruce.richardson, Vladimir Medvedkin, padraig.j.connolly,
ananth.s, timothy.miskell, Jacob Keller, Lukasz Czapnik,
Aleksandr Loktionov, Andrew Lunn, David S. Miller, Eric Dumazet,
Paolo Abeni, Saeed Mahameed, Leon Romanovsky, Tariq Toukan,
Mark Bloch, Przemek Kitszel
From: Ahmed Zaki <ahmed.zaki@intel.com>
The Virtchnl is using a bit wide filed to enable, disable or configure
the device queues. Define new OP codes in order to enable the VF to
request a variable number of queues.
First the new capability VIRTCHNL_VF_LARGE_NUM_QPAIRS is defined. Only
if this cap is negotiated, the VF is allowed to use the new OP codes.
The VIRTCHNL_OP_GET_MAX_RSS_QREGION is exchanged right after the VF
resource message is received. This is done similar to the PTP and other
extended cap exchanges.
Enabling and disabling queues, and mapping queues to vectors is done
through the new VIRTCHNL_OP_ENABLE_QUEUES_V2,
VIRTCHNL_OP_DISABLE_QUEUES_V2, and VIRTCHNL_OP_MAP_QUEUE_VECTOR messages.
Use the new iavf_request_queues() in the iavf_set_channels().
It's not only for elegance, but it enables our brittle handcoded state
machine to go through requesting the queues before PF driver reallocates
queue-related arrays.
Signed-off-by: Ahmed Zaki <ahmed.zaki@intel.com>
Co-developed-by: Przemek Kitszel <przemyslaw.kitszel@intel.com>
Signed-off-by: Przemek Kitszel <przemyslaw.kitszel@intel.com>
---
drivers/net/ethernet/intel/iavf/iavf.h | 11 +
include/linux/intel/virtchnl.h | 136 +++++++++++-
.../net/ethernet/intel/iavf/iavf_ethtool.c | 7 +-
drivers/net/ethernet/intel/iavf/iavf_main.c | 123 ++++++++++-
.../net/ethernet/intel/iavf/iavf_virtchnl.c | 202 +++++++++++++++++-
5 files changed, 460 insertions(+), 19 deletions(-)
diff --git a/drivers/net/ethernet/intel/iavf/iavf.h b/drivers/net/ethernet/intel/iavf/iavf.h
index 569686d34ff4..541d602149d8 100644
--- a/drivers/net/ethernet/intel/iavf/iavf.h
+++ b/drivers/net/ethernet/intel/iavf/iavf.h
@@ -345,6 +345,7 @@ struct iavf_adapter {
#define IAVF_FLAG_AQ_GET_SUPPORTED_RXDIDS BIT_ULL(42)
#define IAVF_FLAG_AQ_GET_PTP_CAPS BIT_ULL(43)
#define IAVF_FLAG_AQ_SEND_PTP_CMD BIT_ULL(44)
+#define IAVF_FLAG_AQ_GET_MAX_RSS_QREGION BIT_ULL(45)
/* AQ messages that must be sent after IAVF_FLAG_AQ_GET_CONFIG, in
* order to negotiated extended capabilities.
@@ -368,12 +369,16 @@ struct iavf_adapter {
#define IAVF_EXTENDED_CAP_RECV_RXDID BIT_ULL(3)
#define IAVF_EXTENDED_CAP_SEND_PTP BIT_ULL(4)
#define IAVF_EXTENDED_CAP_RECV_PTP BIT_ULL(5)
+#define IAVF_EXTENDED_CAP_SEND_RSS_QREGION BIT_ULL(6)
+#define IAVF_EXTENDED_CAP_RECV_RSS_QREGION BIT_ULL(7)
#define IAVF_EXTENDED_CAPS \
(IAVF_EXTENDED_CAP_SEND_VLAN_V2 | \
IAVF_EXTENDED_CAP_RECV_VLAN_V2 | \
IAVF_EXTENDED_CAP_SEND_RXDID | \
IAVF_EXTENDED_CAP_RECV_RXDID | \
+ IAVF_EXTENDED_CAP_SEND_RSS_QREGION | \
+ IAVF_EXTENDED_CAP_RECV_RSS_QREGION | \
IAVF_EXTENDED_CAP_SEND_PTP | \
IAVF_EXTENDED_CAP_RECV_PTP)
@@ -413,6 +418,8 @@ struct iavf_adapter {
#define RSS_REG(_a) (!((_a)->vf_res->vf_cap_flags & \
(VIRTCHNL_VF_OFFLOAD_RSS_AQ | \
VIRTCHNL_VF_OFFLOAD_RSS_PF)))
+#define LARGE_NUM_QPAIRS_SUPPORT(_a) \
+ ((_a)->vf_res->vf_cap_flags & VIRTCHNL_VF_LARGE_NUM_QPAIRS)
#define VLAN_ALLOWED(_a) ((_a)->vf_res->vf_cap_flags & \
VIRTCHNL_VF_OFFLOAD_VLAN)
#define VLAN_V2_ALLOWED(_a) ((_a)->vf_res->vf_cap_flags & \
@@ -447,6 +454,7 @@ struct iavf_adapter {
struct virtchnl_vlan_caps vlan_v2_caps;
u64 supp_rxdids;
struct iavf_ptp ptp;
+ struct virtchnl_max_rss_qregion max_rss_qregion;
u16 msg_enable;
struct iavf_eth_stats current_stats;
struct virtchnl_qos_cap_list *qos_caps;
@@ -583,13 +591,16 @@ int iavf_send_vf_supported_rxdids_msg(struct iavf_adapter *adapter);
int iavf_get_vf_supported_rxdids(struct iavf_adapter *adapter);
int iavf_send_vf_ptp_caps_msg(struct iavf_adapter *adapter);
int iavf_get_vf_ptp_caps(struct iavf_adapter *adapter);
+int iavf_send_max_rss_qregion(struct iavf_adapter *adapter);
+int iavf_get_max_rss_qregion(struct iavf_adapter *adapter);
void iavf_set_queue_vlan_tag_loc(struct iavf_adapter *adapter);
u16 iavf_get_num_vlans_added(struct iavf_adapter *adapter);
void iavf_irq_enable(struct iavf_adapter *adapter, bool flush);
void iavf_configure_queues(struct iavf_adapter *adapter);
void iavf_enable_queues(struct iavf_adapter *adapter);
void iavf_disable_queues(struct iavf_adapter *adapter);
void iavf_map_queues(struct iavf_adapter *adapter);
+int iavf_request_queues(struct iavf_adapter *adapter, int num);
int iavf_add_ether_addrs(struct iavf_adapter *adapter);
void iavf_del_ether_addrs(struct iavf_adapter *adapter);
void iavf_mac_add_reject(struct iavf_adapter *adapter);
diff --git a/include/linux/intel/virtchnl.h b/include/linux/intel/virtchnl.h
index 511c8827c640..622e89847b21 100644
--- a/include/linux/intel/virtchnl.h
+++ b/include/linux/intel/virtchnl.h
@@ -1,5 +1,5 @@
/* SPDX-License-Identifier: GPL-2.0-only */
-/* Copyright (c) 2013-2022, Intel Corporation. */
+/* Copyright (c) 2013-2026, Intel Corporation. */
#ifndef _VIRTCHNL_H_
#define _VIRTCHNL_H_
@@ -22,8 +22,7 @@
* we must send all messages as "indirect", i.e. using an external buffer.
*
* All the VSI indexes are relative to the VF. Each VF can have maximum of
- * three VSIs. All the queue indexes are relative to the VSI. Each VF can
- * have a maximum of sixteen queues for all of its VSIs.
+ * three VSIs. All the queue indexes are relative to the VSI.
*
* The PF is required to return a status code in v_retval for all messages
* except RESET_VF, which does not require any response. The returned value
@@ -147,6 +146,7 @@ enum virtchnl_ops {
VIRTCHNL_OP_DEL_RSS_CFG = 46,
VIRTCHNL_OP_ADD_FDIR_FILTER = 47,
VIRTCHNL_OP_DEL_FDIR_FILTER = 48,
+ VIRTCHNL_OP_GET_MAX_RSS_QREGION = 50,
VIRTCHNL_OP_GET_OFFLOAD_VLAN_V2_CAPS = 51,
VIRTCHNL_OP_ADD_VLAN_V2 = 52,
VIRTCHNL_OP_DEL_VLAN_V2 = 53,
@@ -159,7 +159,11 @@ enum virtchnl_ops {
VIRTCHNL_OP_1588_PTP_GET_TIME = 61,
/* opcode 62 - 65 are reserved */
VIRTCHNL_OP_GET_QOS_CAPS = 66,
- /* opcode 68 through 111 are reserved */
+ /* opcodes 67 through 106 are reserved */
+ VIRTCHNL_OP_ENABLE_QUEUES_V2 = 107,
+ VIRTCHNL_OP_DISABLE_QUEUES_V2 = 108,
+ /* opcodes 109 and 110 are reserved */
+ VIRTCHNL_OP_MAP_QUEUE_VECTOR = 111,
VIRTCHNL_OP_CONFIG_QUEUE_BW = 112,
VIRTCHNL_OP_CONFIG_QUANTA = 113,
VIRTCHNL_OP_MAX,
@@ -257,6 +261,7 @@ VIRTCHNL_CHECK_STRUCT_LEN(16, virtchnl_vsi_resource);
#define VIRTCHNL_VF_OFFLOAD_REQ_QUEUES BIT(6)
/* used to negotiate communicating link speeds in Mbps */
#define VIRTCHNL_VF_CAP_ADV_LINK_SPEED BIT(7)
+#define VIRTCHNL_VF_LARGE_NUM_QPAIRS BIT(9)
#define VIRTCHNL_VF_OFFLOAD_CRC BIT(10)
#define VIRTCHNL_VF_OFFLOAD_TC_U32 BIT(11)
#define VIRTCHNL_VF_OFFLOAD_VLAN_V2 BIT(15)
@@ -500,6 +505,34 @@ struct virtchnl_queue_select {
VIRTCHNL_CHECK_STRUCT_LEN(12, virtchnl_queue_select);
+/* VIRTCHNL_OP_GET_MAX_RSS_QREGION
+ *
+ * if VIRTCHNL_VF_LARGE_NUM_QPAIRS was negotiated in
+ * VIRTCHNL_OP_GET_VF_RESOURCES then this op must be supported.
+ *
+ * VF sends this message in order to query the max RSS queue region
+ * size supported by PF, when VIRTCHNL_VF_LARGE_NUM_QPAIRS is enabled.
+ * This information should be used when configuring the RSS LUT and/or
+ * configuring queue region based filters.
+ *
+ * The maximum RSS queue region is 2^qregion_width. So, a qregion_width of 6
+ * would inform the VF that the PF supports a maximum RSS queue region of 64.
+ *
+ * A queue region represents a range of queues that can be used to configure
+ * a RSS LUT. For example, if a VF is given 64 queues, but only a max queue
+ * region size of 16 (i.e. 2^qregion_width = 16) then it will only be able
+ * to configure the RSS LUT with queue indices from 0 to 15. However, other
+ * filters can be used to direct packets to queues >15 via specifying a queue
+ * base/offset and queue region width.
+ */
+struct virtchnl_max_rss_qregion {
+ u16 vport_id;
+ u16 qregion_width;
+ u8 pad[4];
+};
+
+VIRTCHNL_CHECK_STRUCT_LEN(8, virtchnl_max_rss_qregion);
+
/* VIRTCHNL_OP_ADD_ETH_ADDR
* VF sends this message in order to add one or more unicast or multicast
* address filters for the specified VSI.
@@ -1664,6 +1697,70 @@ struct virtchnl_queue_chunk {
VIRTCHNL_CHECK_STRUCT_LEN(8, virtchnl_queue_chunk);
+/* VIRTCHNL_OP_ENABLE_QUEUES_V2
+ * VIRTCHNL_OP_DISABLE_QUEUES_V2
+ *
+ * These opcodes can be used if VIRTCHNL_VF_LARGE_NUM_QPAIRS was negotiated in
+ * VIRTCHNL_OP_GET_VF_RESOURCES
+ *
+ * VF sends virtchnl_ena_dis_queues struct to specify the queues to be
+ * enabled/disabled in chunks. Also applicable to single queue RX or
+ * TX. PF performs requested action and returns status.
+ */
+struct virtchnl_del_ena_dis_queues {
+ u16 vport_id;
+ u16 pad;
+ u16 num_chunks;
+ u16 rsvd;
+ struct virtchnl_queue_chunk chunks[];
+};
+
+VIRTCHNL_CHECK_STRUCT_LEN(8, virtchnl_del_ena_dis_queues);
+#define virtchnl_del_ena_dis_queues_LEGACY_SIZEOF 16
+
+/* Virtchannel interrupt throttling rate index */
+enum virtchnl_itr_idx {
+ VIRTCHNL_ITR_IDX_0 = 0,
+ VIRTCHNL_ITR_IDX_1 = 1,
+ VIRTCHNL_ITR_IDX_NO_ITR = 3,
+};
+
+/* Queue to vector mapping */
+struct virtchnl_queue_vector {
+ u16 queue_id;
+ u16 vector_id;
+ u8 pad[4];
+
+ /* see enum virtchnl_itr_idx */
+ s32 itr_idx;
+
+ /* see enum virtchnl_queue_type */
+ s32 queue_type;
+};
+
+VIRTCHNL_CHECK_STRUCT_LEN(16, virtchnl_queue_vector);
+
+/* VIRTCHNL_OP_MAP_QUEUE_VECTOR
+ *
+ * This opcode can be used only if VIRTCHNL_VF_LARGE_NUM_QPAIRS was negotiated
+ * in VIRTCHNL_OP_GET_VF_RESOURCES
+ *
+ * VF sends this message to map queues to vectors and ITR index registers.
+ * External data buffer contains virtchnl_queue_vector_maps structure
+ * that contains num_qv_maps of virtchnl_queue_vector structures.
+ * PF maps the requested queue vector maps after validating the queue and vector
+ * ids and returns a status code.
+ */
+struct virtchnl_queue_vector_maps {
+ u16 vport_id;
+ u16 num_qv_maps;
+ u8 pad[4];
+ struct virtchnl_queue_vector qv_maps[];
+};
+
+VIRTCHNL_CHECK_STRUCT_LEN(8, virtchnl_queue_vector_maps);
+#define virtchnl_queue_vector_maps_LEGACY_SIZEOF 24
+
struct virtchnl_quanta_cfg {
u16 quanta_size;
u16 pad;
@@ -1696,6 +1793,8 @@ VIRTCHNL_CHECK_STRUCT_LEN(12, virtchnl_quanta_cfg);
__vss(virtchnl_rdma_qvlist_info, __vss_byelem, p, m, c), \
__vss(virtchnl_qos_cap_list, __vss_byelem, p, m, c), \
__vss(virtchnl_queues_bw_cfg, __vss_byelem, p, m, c), \
+ __vss(virtchnl_del_ena_dis_queues, __vss_byelem, p, m, c), \
+ __vss(virtchnl_queue_vector_maps, __vss_byelem, p, m, c), \
__vss(virtchnl_rss_key, __vss_byone, p, m, c), \
__vss(virtchnl_rss_lut, __vss_byone, p, m, c))
@@ -1758,6 +1857,8 @@ virtchnl_vc_validate_vf_msg(struct virtchnl_version_info *ver, u32 v_opcode,
case VIRTCHNL_OP_DISABLE_QUEUES:
valid_len = sizeof(struct virtchnl_queue_select);
break;
+ case VIRTCHNL_OP_GET_MAX_RSS_QREGION:
+ break;
case VIRTCHNL_OP_ADD_ETH_ADDR:
case VIRTCHNL_OP_DEL_ETH_ADDR:
valid_len = virtchnl_ether_addr_list_LEGACY_SIZEOF;
@@ -1930,7 +2031,32 @@ virtchnl_vc_validate_vf_msg(struct virtchnl_version_info *ver, u32 v_opcode,
case VIRTCHNL_OP_1588_PTP_GET_TIME:
valid_len = sizeof(struct virtchnl_phc_time);
break;
- /* These are always errors coming from the VF. */
+ case VIRTCHNL_OP_ENABLE_QUEUES_V2:
+ case VIRTCHNL_OP_DISABLE_QUEUES_V2:
+ valid_len = sizeof(struct virtchnl_del_ena_dis_queues);
+ if (msglen >= valid_len) {
+ struct virtchnl_del_ena_dis_queues *qs =
+ (struct virtchnl_del_ena_dis_queues *)msg;
+
+ if (!qs->num_chunks) {
+ err_msg_format = true;
+ break;
+ }
+ valid_len = virtchnl_struct_size(qs, chunks,
+ qs->num_chunks);
+ }
+ break;
+ case VIRTCHNL_OP_MAP_QUEUE_VECTOR:
+ valid_len = virtchnl_queue_vector_maps_LEGACY_SIZEOF;
+ if (msglen >= valid_len) {
+ struct virtchnl_queue_vector_maps *v_qp = (void *)msg;
+
+ err_msg_format = !v_qp->num_qv_maps;
+ valid_len = virtchnl_struct_size(v_qp, qv_maps,
+ v_qp->num_qv_maps);
+ }
+ break;
+ /* These are always errors when coming from the VF. */
case VIRTCHNL_OP_EVENT:
case VIRTCHNL_OP_UNKNOWN:
default:
diff --git a/drivers/net/ethernet/intel/iavf/iavf_ethtool.c b/drivers/net/ethernet/intel/iavf/iavf_ethtool.c
index dc2503e3c5ba..ff59d2dd5448 100644
--- a/drivers/net/ethernet/intel/iavf/iavf_ethtool.c
+++ b/drivers/net/ethernet/intel/iavf/iavf_ethtool.c
@@ -1744,12 +1744,9 @@ static int iavf_set_channels(struct net_device *netdev,
if (ch->rx_count || ch->tx_count || ch->other_count != NONQ_VECS)
return -EINVAL;
- adapter->num_req_queues = num_req;
- adapter->flags |= IAVF_FLAG_REINIT_ITR_NEEDED;
- adapter->flags |= IAVF_FLAG_RESET_NEEDED;
- iavf_reset_step(adapter);
- return 0;
+ adapter->current_op = VIRTCHNL_OP_UNKNOWN;
+ return iavf_request_queues(adapter, num_req);
}
/**
diff --git a/drivers/net/ethernet/intel/iavf/iavf_main.c b/drivers/net/ethernet/intel/iavf/iavf_main.c
index abc0fe070ee7..b7b4b857f384 100644
--- a/drivers/net/ethernet/intel/iavf/iavf_main.c
+++ b/drivers/net/ethernet/intel/iavf/iavf_main.c
@@ -1758,10 +1758,14 @@ int iavf_config_rss(struct iavf_adapter *adapter)
**/
static void iavf_fill_rss_lut(struct iavf_adapter *adapter)
{
- u16 i;
+ struct virtchnl_max_rss_qregion *qregion = &adapter->max_rss_qregion;
+ int max = adapter->num_active_queues;
+
+ if (LARGE_NUM_QPAIRS_SUPPORT(adapter) && qregion->qregion_width)
+ max = min(max, (int)BIT(qregion->qregion_width));
- for (i = 0; i < adapter->rss_lut_size; i++)
- adapter->rss_lut[i] = i % adapter->num_active_queues;
+ for (int i = 0; i < adapter->rss_lut_size; i++)
+ adapter->rss_lut[i] = i % max;
}
/**
@@ -2246,6 +2250,10 @@ static int iavf_process_aq_command(struct iavf_adapter *adapter)
iavf_virtchnl_send_ptp_cmd(adapter);
return IAVF_SUCCESS;
}
+ if (adapter->aq_required & IAVF_FLAG_AQ_GET_MAX_RSS_QREGION) {
+ iavf_get_max_rss_qregion(adapter);
+ return 0;
+ }
if (adapter->aq_required & IAVF_FLAG_AQ_REQUEST_STATS) {
iavf_request_stats(adapter);
return 0;
@@ -2441,8 +2449,9 @@ static void iavf_init_version_check(struct iavf_adapter *adapter)
*/
int iavf_parse_vf_resource_msg(struct iavf_adapter *adapter)
{
- int i, num_req_queues = adapter->num_req_queues;
+ int i, qnum, num_req_queues = adapter->num_req_queues;
struct iavf_vsi *vsi = &adapter->vsi;
+ bool reconfig_rss = false;
for (i = 0; i < adapter->vf_res->num_vsis; i++) {
if (adapter->vf_res->vsi_res[i].vsi_type == VIRTCHNL_VSI_SRIOV)
@@ -2469,21 +2478,58 @@ int iavf_parse_vf_resource_msg(struct iavf_adapter *adapter)
return -EAGAIN;
}
+ if (!num_req_queues) {
+ adapter->current_op = VIRTCHNL_OP_UNKNOWN;
+ qnum = min(adapter->vsi_res->num_queue_pairs,
+ num_online_cpus());
+
+ return iavf_request_queues(adapter, qnum);
+ }
adapter->num_req_queues = 0;
adapter->vsi.id = adapter->vsi_res->vsi_id;
adapter->vsi.back = adapter;
adapter->vsi.base_vector = 1;
vsi->netdev = adapter->netdev;
vsi->qs_handle = adapter->vsi_res->qset_handle;
if (adapter->vf_res->vf_cap_flags & VIRTCHNL_VF_OFFLOAD_RSS_PF) {
+ if ((adapter->rss_key &&
+ adapter->rss_key_size != adapter->vf_res->rss_key_size) ||
+ (adapter->rss_lut &&
+ adapter->rss_lut_size != adapter->vf_res->rss_lut_size)) {
+ reconfig_rss = true;
+ }
adapter->rss_key_size = adapter->vf_res->rss_key_size;
adapter->rss_lut_size = adapter->vf_res->rss_lut_size;
} else {
adapter->rss_key_size = IAVF_HKEY_ARRAY_SIZE;
adapter->rss_lut_size = IAVF_HLUT_ARRAY_SIZE;
}
+ if (reconfig_rss) {
+ u8 *rss_key, *rss_lut;
+
+ rss_key = krealloc(adapter->rss_key, adapter->rss_key_size,
+ GFP_KERNEL);
+ if (rss_key)
+ adapter->rss_key = rss_key;
+ rss_lut = krealloc(adapter->rss_lut, adapter->rss_lut_size,
+ GFP_KERNEL);
+ if (rss_lut)
+ adapter->rss_lut = rss_lut;
+ if (!rss_lut || !rss_key)
+ return -ENOMEM;
+
+ iavf_init_rss(adapter);
+ }
+
+ qnum = min_t(int, IAVF_MAX_REQ_QUEUES, (int)(num_online_cpus()));
+ if (LARGE_NUM_QPAIRS_SUPPORT(adapter) &&
+ adapter->vsi_res->num_queue_pairs < qnum) {
+ adapter->current_op = VIRTCHNL_OP_UNKNOWN;
+ return iavf_request_queues(adapter, qnum);
+ }
+
return 0;
}
@@ -2609,6 +2655,65 @@ static void iavf_init_recv_offload_vlan_v2_caps(struct iavf_adapter *adapter)
iavf_change_state(adapter, __IAVF_INIT_FAILED);
}
+/*
+ * iavf_init_send_max_rss_qregion - part of querying for RSS max queue region
+ * @adapter: board private structure
+ *
+ * Function processes send of the VIRTCHNL_OP_GET_MAX_RSS_QREGION to the PF.
+ * Must clear IAVF_EXTENDED_CAP_RECV_RSS_QREGION if the message is not sent, e.g.
+ * due to the PF not negotiating VIRTCHNL_VF_LARGE_NUM_QPAIRS.
+ */
+static void iavf_init_send_max_rss_qregion(struct iavf_adapter *adapter)
+{
+ int ret;
+
+ WARN_ON(!(adapter->extended_caps & IAVF_EXTENDED_CAP_SEND_RSS_QREGION));
+
+ ret = iavf_send_max_rss_qregion(adapter);
+ if (ret == -EOPNOTSUPP) {
+ /* PF does not support VIRTCHNL_VF_LARGE_NUM_QPAIRS. In this
+ * case, we did not send the capability exchange message and do
+ * not expect a response.
+ */
+ adapter->extended_caps &= ~IAVF_EXTENDED_CAP_RECV_RSS_QREGION;
+ }
+
+ /* We sent the message, so move on to the next step */
+ adapter->extended_caps &= ~IAVF_EXTENDED_CAP_SEND_RSS_QREGION;
+}
+
+/**
+ * iavf_init_recv_max_rss_qregion - part of querying for RSS max queue region
+ * @adapter: board private structure
+ *
+ * Function processes receipt of the RSS max qregion to be used for the LUT.
+ */
+static void iavf_init_recv_max_rss_qregion(struct iavf_adapter *adapter)
+{
+ int ret;
+
+ WARN_ON(!(adapter->extended_caps & IAVF_EXTENDED_CAP_RECV_RSS_QREGION));
+
+ memset(&adapter->max_rss_qregion, 0, sizeof(adapter->max_rss_qregion));
+
+ ret = iavf_get_max_rss_qregion(adapter);
+ if (ret)
+ goto err;
+
+ /* We've processed the PF response to the VIRTCHNL_OP_GET_MAX_RSS_QREGION
+ * message we sent previously.
+ */
+ adapter->extended_caps &= ~IAVF_EXTENDED_CAP_RECV_RSS_QREGION;
+ return;
+
+err:
+ /* We didn't receive a reply. Make sure we try sending again when
+ * __IAVF_INIT_FAILED attempts to recover.
+ */
+ adapter->extended_caps |= IAVF_EXTENDED_CAP_RECV_RSS_QREGION;
+ iavf_change_state(adapter, __IAVF_INIT_FAILED);
+}
+
/**
* iavf_init_send_supported_rxdids - part of querying for supported RXDID
* formats
@@ -2757,6 +2862,16 @@ static void iavf_init_process_extended_caps(struct iavf_adapter *adapter)
return;
}
+ /* Process capability exchange for RSS max qregion */
+ if (adapter->extended_caps & IAVF_EXTENDED_CAP_SEND_RSS_QREGION) {
+ iavf_init_send_max_rss_qregion(adapter);
+ return;
+ }
+ if (adapter->extended_caps & IAVF_EXTENDED_CAP_RECV_RSS_QREGION) {
+ iavf_init_recv_max_rss_qregion(adapter);
+ return;
+ }
+
/* When we reach here, no further extended capabilities exchanges are
* necessary, so we finally transition into __IAVF_INIT_CONFIG_ADAPTER
*/
diff --git a/drivers/net/ethernet/intel/iavf/iavf_virtchnl.c b/drivers/net/ethernet/intel/iavf/iavf_virtchnl.c
index 9102bc4bddb0..ab1019a91ff7 100644
--- a/drivers/net/ethernet/intel/iavf/iavf_virtchnl.c
+++ b/drivers/net/ethernet/intel/iavf/iavf_virtchnl.c
@@ -170,6 +170,7 @@ int iavf_send_vf_config_msg(struct iavf_adapter *adapter)
VIRTCHNL_VF_OFFLOAD_VLAN_V2 |
VIRTCHNL_VF_OFFLOAD_RX_FLEX_DESC |
VIRTCHNL_VF_OFFLOAD_CRC |
+ VIRTCHNL_VF_LARGE_NUM_QPAIRS |
VIRTCHNL_VF_OFFLOAD_ENCAP_CSUM |
VIRTCHNL_VF_OFFLOAD_REQ_QUEUES |
VIRTCHNL_VF_CAP_PTP |
@@ -251,28 +252,44 @@ int iavf_send_vf_ptp_caps_msg(struct iavf_adapter *adapter)
(u8 *)&hw_caps, sizeof(hw_caps));
}
+int iavf_send_max_rss_qregion(struct iavf_adapter *adapter)
+{
+ adapter->aq_required &= ~IAVF_FLAG_AQ_GET_MAX_RSS_QREGION;
+
+ if (!LARGE_NUM_QPAIRS_SUPPORT(adapter))
+ return -EOPNOTSUPP;
+
+ iavf_send_pf_msg(adapter, VIRTCHNL_OP_GET_MAX_RSS_QREGION, NULL, 0);
+ return 0;
+}
+
/**
* iavf_validate_num_queues
* @adapter: adapter structure
*
* Validate that the number of queues the PF has sent in
* VIRTCHNL_OP_GET_VF_RESOURCES is not larger than the VF can handle.
**/
static void iavf_validate_num_queues(struct iavf_adapter *adapter)
{
- if (adapter->vf_res->num_queue_pairs > IAVF_MAX_REQ_QUEUES) {
+ u32 max_req_queues = IAVF_MAX_REQ_QUEUES;
+
+ if (!LARGE_NUM_QPAIRS_SUPPORT(adapter))
+ max_req_queues = IAVF_MAX_VSI_QP;
+
+ if (adapter->vf_res->num_queue_pairs > max_req_queues) {
struct virtchnl_vsi_resource *vsi_res;
int i;
dev_info(&adapter->pdev->dev, "Received %d queues, but can only have a max of %d\n",
adapter->vf_res->num_queue_pairs,
- IAVF_MAX_REQ_QUEUES);
+ max_req_queues);
dev_info(&adapter->pdev->dev, "Fixing by reducing queues to %d\n",
- IAVF_MAX_REQ_QUEUES);
- adapter->vf_res->num_queue_pairs = IAVF_MAX_REQ_QUEUES;
+ max_req_queues);
+ adapter->vf_res->num_queue_pairs = max_req_queues;
for (i = 0; i < adapter->vf_res->num_vsis; i++) {
vsi_res = &adapter->vf_res->vsi_res[i];
- vsi_res->num_queue_pairs = IAVF_MAX_REQ_QUEUES;
+ vsi_res->num_queue_pairs = max_req_queues;
}
}
}
@@ -371,6 +388,30 @@ int iavf_get_vf_ptp_caps(struct iavf_adapter *adapter)
return err;
}
+int iavf_get_max_rss_qregion(struct iavf_adapter *adapter)
+{
+ struct iavf_arq_event_info event;
+ int err;
+ u16 len;
+
+ len = sizeof(struct virtchnl_max_rss_qregion);
+ event.buf_len = len;
+ event.msg_buf = kzalloc(len, GFP_KERNEL);
+ if (!event.msg_buf)
+ return -ENOMEM;
+
+ err = iavf_poll_virtchnl_msg(&adapter->hw, &event,
+ VIRTCHNL_OP_GET_MAX_RSS_QREGION);
+ if (!err)
+ memcpy(&adapter->max_rss_qregion, event.msg_buf,
+ min(event.msg_len, len));
+
+ adapter->current_op = VIRTCHNL_OP_UNKNOWN;
+
+ kfree(event.msg_buf);
+ return err;
+}
+
static bool iavf_match_vc_op_cb(struct iavf_adapter *adapter, const void *data,
enum virtchnl_ops recv_op)
{
@@ -466,6 +507,50 @@ void iavf_configure_queues(struct iavf_adapter *adapter)
kfree(vqci);
}
+/**
+ * iavf_enable_disable_queues_v2 - send V2 messages of ENABLE/DISABLE queues ops
+ * @adapter: private adapter structure
+ * @enable: true to enable and false to disable the queues
+ */
+static void iavf_enable_disable_queues_v2(struct iavf_adapter *adapter, bool enable)
+{
+ enum virtchnl_ops op = VIRTCHNL_OP_ENABLE_QUEUES_V2;
+ struct virtchnl_del_ena_dis_queues *msg;
+ u64 flag = IAVF_FLAG_AQ_ENABLE_QUEUES;
+ struct virtchnl_queue_chunk *chunk;
+ int len;
+
+ if (!enable) {
+ op = VIRTCHNL_OP_DISABLE_QUEUES_V2;
+ flag = IAVF_FLAG_AQ_DISABLE_QUEUES;
+ }
+
+ adapter->current_op = op;
+
+ /* We need 2 chunks (one Tx and one Rx). */
+ len = virtchnl_struct_size(msg, chunks, 2);
+ msg = kzalloc(len, GFP_KERNEL);
+ if (!msg)
+ return;
+
+ msg->vport_id = adapter->vsi_res->vsi_id;
+ msg->num_chunks = 2;
+
+ chunk = &msg->chunks[0];
+ chunk->type = VIRTCHNL_QUEUE_TYPE_RX;
+ chunk->start_queue_id = 0;
+ chunk->num_queues = adapter->num_active_queues;
+
+ chunk++;
+ chunk->type = VIRTCHNL_QUEUE_TYPE_TX;
+ chunk->start_queue_id = 0;
+ chunk->num_queues = adapter->num_active_queues;
+
+ adapter->aq_required &= ~flag;
+ iavf_send_pf_msg(adapter, op, (u8 *)msg, len);
+ kfree(msg);
+}
+
/**
* iavf_enable_queues
* @adapter: adapter structure
@@ -482,6 +567,12 @@ void iavf_enable_queues(struct iavf_adapter *adapter)
adapter->current_op);
return;
}
+
+ if (adapter->num_active_queues > IAVF_MAX_VSI_QP) {
+ iavf_enable_disable_queues_v2(adapter, true);
+ return;
+ }
+
adapter->current_op = VIRTCHNL_OP_ENABLE_QUEUES;
vqs.vsi_id = adapter->vsi_res->vsi_id;
vqs.tx_queues = BIT(adapter->num_active_queues) - 1;
@@ -507,15 +598,81 @@ void iavf_disable_queues(struct iavf_adapter *adapter)
adapter->current_op);
return;
}
+
+ if (LARGE_NUM_QPAIRS_SUPPORT(adapter)) {
+ iavf_enable_disable_queues_v2(adapter, false);
+ return;
+ }
+
adapter->current_op = VIRTCHNL_OP_DISABLE_QUEUES;
vqs.vsi_id = adapter->vsi_res->vsi_id;
vqs.tx_queues = BIT(adapter->num_active_queues) - 1;
vqs.rx_queues = vqs.tx_queues;
adapter->aq_required &= ~IAVF_FLAG_AQ_DISABLE_QUEUES;
iavf_send_pf_msg(adapter, VIRTCHNL_OP_DISABLE_QUEUES,
(u8 *)&vqs, sizeof(vqs));
}
+static void iavf_map_queue_vector(struct iavf_adapter *adapter)
+{
+ struct virtchnl_queue_vector_maps *qvmaps;
+ int qnum = adapter->num_active_queues;
+ struct virtchnl_queue_vector *qv;
+ int len, max_pairs;
+
+ max_pairs = iavf_max_vc_entries(qvmaps, qv_maps) / 2;
+ len = virtchnl_struct_size(qvmaps, qv_maps, 2 * min(qnum, max_pairs));
+ qvmaps = kzalloc(len, GFP_KERNEL);
+ if (!qvmaps)
+ return;
+
+ qvmaps->vport_id = adapter->vsi_res->vsi_id;
+ qv = qvmaps->qv_maps;
+ for (int qid = 0, in_msg = 0; qid < qnum; qid++) {
+ const bool last = qid + 1 == qnum;
+ struct iavf_q_vector *q_vector;
+
+ q_vector = adapter->tx_rings[qid].q_vector;
+ qv->queue_id = qid;
+ qv->vector_id = NONQ_VECS + q_vector->v_idx;
+ qv->itr_idx = IAVF_TX_ITR;
+ qv->queue_type = VIRTCHNL_QUEUE_TYPE_TX;
+ qv++;
+
+ q_vector = adapter->rx_rings[qid].q_vector;
+ qv->queue_id = qid;
+ qv->vector_id = NONQ_VECS + q_vector->v_idx;
+ qv->itr_idx = IAVF_RX_ITR;
+ qv->queue_type = VIRTCHNL_QUEUE_TYPE_RX;
+ qv++;
+
+ in_msg++;
+ if (last || in_msg == max_pairs) {
+ int err;
+
+ qvmaps->num_qv_maps = 2 * in_msg;
+ adapter->current_op = VIRTCHNL_OP_MAP_QUEUE_VECTOR;
+ iavf_send_pf_msg(adapter, VIRTCHNL_OP_MAP_QUEUE_VECTOR,
+ (u8 *)qvmaps,
+ virtchnl_struct_size(qvmaps, qv_maps,
+ 2 * in_msg));
+ err = iavf_poll_virtchnl_response(adapter,
+ iavf_match_vc_op_cb,
+ (void *)VIRTCHNL_OP_MAP_QUEUE_VECTOR,
+ 1000);
+ if (err)
+ dev_warn(&adapter->pdev->dev,
+ "polling response of mapping queue vectors failed, err: %d\n",
+ err);
+
+ in_msg = 0;
+ qv = qvmaps->qv_maps;
+ }
+ }
+ adapter->aq_required &= ~IAVF_FLAG_AQ_MAP_VECTORS;
+ kfree(qvmaps);
+}
+
/**
* iavf_map_queues
* @adapter: adapter structure
@@ -537,6 +694,12 @@ void iavf_map_queues(struct iavf_adapter *adapter)
adapter->current_op);
return;
}
+
+ if (LARGE_NUM_QPAIRS_SUPPORT(adapter)) {
+ iavf_map_queue_vector(adapter);
+ return;
+ }
+
adapter->current_op = VIRTCHNL_OP_CONFIG_IRQ_MAP;
q_vectors = adapter->num_msix_vectors - NONQ_VECS;
@@ -573,6 +736,32 @@ void iavf_map_queues(struct iavf_adapter *adapter)
kfree(vimi);
}
+/**
+ * iavf_request_queues - request queues via virtchnl
+ * @adapter: adapter structure
+ * @num: number of requested queues
+ *
+ * Return: 0 on success, negative on failure.
+ */
+int iavf_request_queues(struct iavf_adapter *adapter, int num)
+{
+ struct virtchnl_vf_res_request vfres = { num };
+
+ if (adapter->current_op != VIRTCHNL_OP_UNKNOWN) {
+ /* bail because we already have a command pending */
+ dev_err(&adapter->pdev->dev, "Cannot request queues, command %d pending\n",
+ adapter->current_op);
+ return -EBUSY;
+ }
+
+ adapter->current_op = VIRTCHNL_OP_REQUEST_QUEUES;
+ adapter->flags |= IAVF_FLAG_REINIT_ITR_NEEDED;
+ adapter->num_req_queues = num;
+
+ return iavf_send_pf_msg(adapter, VIRTCHNL_OP_REQUEST_QUEUES,
+ (u8 *)&vfres, sizeof(vfres));
+}
+
/**
* iavf_set_mac_addr_type - Set the correct request type from the filter type
* @virtchnl_ether_addr: pointer to requested list element
@@ -2749,20 +2938,23 @@ void iavf_virtchnl_completion(struct iavf_adapter *adapter,
iavf_virtchnl_ptp_get_time(adapter, msg, msglen);
break;
case VIRTCHNL_OP_ENABLE_QUEUES:
+ case VIRTCHNL_OP_ENABLE_QUEUES_V2:
/* enable transmits */
iavf_irq_enable(adapter, true);
adapter->flags &= ~IAVF_FLAG_QUEUES_DISABLED;
break;
case VIRTCHNL_OP_DISABLE_QUEUES:
+ case VIRTCHNL_OP_DISABLE_QUEUES_V2:
iavf_free_all_tx_resources(adapter);
iavf_free_all_rx_resources(adapter);
if (adapter->state == __IAVF_DOWN_PENDING) {
iavf_change_state(adapter, __IAVF_DOWN);
wake_up(&adapter->down_waitqueue);
}
break;
case VIRTCHNL_OP_VERSION:
case VIRTCHNL_OP_CONFIG_IRQ_MAP:
+ case VIRTCHNL_OP_MAP_QUEUE_VECTOR:
/* Don't display an error if we get these out of sequence.
* If the firmware needed to get kicked, we'll get these and
* it's no problem.
--
2.39.3
^ permalink raw reply related [flat|nested] 28+ messages in thread* [PATCH iwl-next v1 12/15] ice: introduce handling of virtchnl LARGE VF opcodes
2026-05-08 12:41 [PATCH iwl-next v1 00/15] devlink, mlx5, iavf, ice: XLVF for iavf Przemek Kitszel
` (10 preceding siblings ...)
2026-05-08 12:42 ` [PATCH iwl-next v1 11/15] iavf: use new opcodes to request more than 16 queues Przemek Kitszel
@ 2026-05-08 12:42 ` Przemek Kitszel
2026-05-08 16:55 ` Loktionov, Aleksandr
2026-05-08 12:42 ` [PATCH iwl-next v1 13/15] devlink: give user option to allocate resources Przemek Kitszel
` (2 subsequent siblings)
14 siblings, 1 reply; 28+ messages in thread
From: Przemek Kitszel @ 2026-05-08 12:42 UTC (permalink / raw)
To: intel-wired-lan, Michal Schmidt, Jakub Kicinski, Jiri Pirko
Cc: netdev, Simon Horman, Tony Nguyen, Michal Swiatkowski,
bruce.richardson, Vladimir Medvedkin, padraig.j.connolly,
ananth.s, timothy.miskell, Jacob Keller, Lukasz Czapnik,
Aleksandr Loktionov, Andrew Lunn, David S. Miller, Eric Dumazet,
Paolo Abeni, Saeed Mahameed, Leon Romanovsky, Tariq Toukan,
Mark Bloch, Przemek Kitszel
From: Brett Creeley <brett.creeley@intel.com>
With new virtchnl offload/capability VFs are able to make use of more than
16 queues. But to old opcodes were designed with a max of 16 queues, so
new ones were added (by iavf/virtchnl commit of this series):
VIRTCHNL_OP_GET_MAX_RSS_QREGION, VIRTCHNL_OP_ENABLE_QUEUES_V2,
VIRTCHNL_OP_DISABLE_QUEUES_V2, VIRTCHNL_OP_MAP_QUEUE_VECTOR.
If a VF wishes to request >16 queues it should first make sure that the
PF supports the VIRTCHNL_VF_LARGE_NUM_QPAIRS capability.
Co-developed-by: Przemek Kitszel <przemyslaw.kitszel@intel.com>
Signed-off-by: Przemek Kitszel <przemyslaw.kitszel@intel.com>
Co-developed-by: Aleksandr Loktionov <aleksandr.loktionov@intel.com> # msglen val
Signed-off-by: Aleksandr Loktionov <aleksandr.loktionov@intel.com>
Signed-off-by: Brett Creeley <brett.creeley@intel.com>
---
drivers/net/ethernet/intel/ice/ice_vf_lib.h | 1 +
drivers/net/ethernet/intel/ice/virt/queues.h | 3 +
.../net/ethernet/intel/ice/virt/allowlist.c | 8 +
drivers/net/ethernet/intel/ice/virt/queues.c | 324 ++++++++++++++++++
4 files changed, 336 insertions(+)
diff --git a/drivers/net/ethernet/intel/ice/ice_vf_lib.h b/drivers/net/ethernet/intel/ice/ice_vf_lib.h
index 1b56f7150eb7..5411eaa1761c 100644
--- a/drivers/net/ethernet/intel/ice/ice_vf_lib.h
+++ b/drivers/net/ethernet/intel/ice/ice_vf_lib.h
@@ -125,6 +125,7 @@ struct ice_vf_ops {
void (*clear_reset_trigger)(struct ice_vf *vf);
void (*irq_close)(struct ice_vf *vf);
void (*post_vsi_rebuild)(struct ice_vf *vf);
+ struct ice_q_vector *(*get_q_vector)(struct ice_vsi *vsi, u16 vec_id);
};
/* Virtchnl/SR-IOV config info */
diff --git a/drivers/net/ethernet/intel/ice/virt/queues.h b/drivers/net/ethernet/intel/ice/virt/queues.h
index c4a792cecea1..223f609dd4f3 100644
--- a/drivers/net/ethernet/intel/ice/virt/queues.h
+++ b/drivers/net/ethernet/intel/ice/virt/queues.h
@@ -16,5 +16,8 @@ int ice_vc_cfg_q_bw(struct ice_vf *vf, u8 *msg);
int ice_vc_cfg_q_quanta(struct ice_vf *vf, u8 *msg);
int ice_vc_cfg_qs_msg(struct ice_vf *vf, u8 *msg);
int ice_vc_request_qs_msg(struct ice_vf *vf, u8 *msg);
+int ice_vc_ena_qs_v2_msg(struct ice_vf *vf, u8 *msg, u16 msglen);
+int ice_vc_dis_qs_v2_msg(struct ice_vf *vf, u8 *msg, u16 msglen);
+int ice_vc_map_q_vector_msg(struct ice_vf *vf, u8 *msg, u16 msglen);
#endif /* _ICE_VIRT_QUEUES_H_ */
diff --git a/drivers/net/ethernet/intel/ice/virt/allowlist.c b/drivers/net/ethernet/intel/ice/virt/allowlist.c
index a07efec19c45..ef769b843c6f 100644
--- a/drivers/net/ethernet/intel/ice/virt/allowlist.c
+++ b/drivers/net/ethernet/intel/ice/virt/allowlist.c
@@ -95,6 +95,13 @@ static const u32 tc_allowlist_opcodes[] = {
VIRTCHNL_OP_CONFIG_QUANTA,
};
+static const u32 large_num_qpairs_allowlist_opcodes[] = {
+ VIRTCHNL_OP_GET_MAX_RSS_QREGION,
+ VIRTCHNL_OP_ENABLE_QUEUES_V2,
+ VIRTCHNL_OP_DISABLE_QUEUES_V2,
+ VIRTCHNL_OP_MAP_QUEUE_VECTOR,
+};
+
struct allowlist_opcode_info {
const u32 *opcodes;
size_t size;
@@ -117,6 +124,7 @@ static const struct allowlist_opcode_info allowlist_opcodes[] = {
ALLOW_ITEM(VIRTCHNL_VF_OFFLOAD_VLAN_V2, vlan_v2_allowlist_opcodes),
ALLOW_ITEM(VIRTCHNL_VF_OFFLOAD_QOS, tc_allowlist_opcodes),
ALLOW_ITEM(VIRTCHNL_VF_CAP_PTP, ptp_allowlist_opcodes),
+ ALLOW_ITEM(VIRTCHNL_VF_LARGE_NUM_QPAIRS, large_num_qpairs_allowlist_opcodes),
};
/**
diff --git a/drivers/net/ethernet/intel/ice/virt/queues.c b/drivers/net/ethernet/intel/ice/virt/queues.c
index 1d9f69026d1b..b99f18a25024 100644
--- a/drivers/net/ethernet/intel/ice/virt/queues.c
+++ b/drivers/net/ethernet/intel/ice/virt/queues.c
@@ -1021,3 +1021,327 @@ int ice_vc_request_qs_msg(struct ice_vf *vf, u8 *msg)
v_ret, (u8 *)vfres, sizeof(*vfres));
}
+static bool ice_vc_supported_queue_type(s32 queue_type)
+{
+ return queue_type == VIRTCHNL_QUEUE_TYPE_RX ||
+ queue_type == VIRTCHNL_QUEUE_TYPE_TX;
+}
+
+/**
+ * ice_vc_validate_qs_v2_msg - validate all qs_msg parameters
+ * @vf: VF the message was received from
+ * @qs_msg: contents of the message from the VF
+ * @msglen: length of @qs_msg
+ *
+ * Used to validate both the VIRTCHNL_OP_ENABLE_QUEUES_V2 and
+ * VIRTCHNL_OP_DISABLE_QUEUES_V2 messages. This should always be called before
+ * attempting to enable and/or disable queues on behalf of a VF in response to
+ * the previously mentioned opcodes.
+ *
+ * Return: If all checks succeed, then return true. Otherwise return
+ * false, indicating to the caller that the qs_msg is invalid.
+ */
+static bool ice_vc_validate_qs_v2_msg(struct ice_vf *vf,
+ struct virtchnl_del_ena_dis_queues *qs_msg,
+ u16 msglen)
+{
+ if (msglen < virtchnl_struct_size(qs_msg, chunks, 0))
+ return false;
+
+ if (msglen < virtchnl_struct_size(qs_msg, chunks, qs_msg->num_chunks))
+ return false;
+
+ if (!qs_msg->num_chunks)
+ return false;
+
+ if (!test_bit(ICE_VF_STATE_ACTIVE, vf->vf_states))
+ return false;
+
+ if (!ice_vc_isvalid_vsi_id(vf, qs_msg->vport_id))
+ return false;
+
+ for (int i = 0; i < qs_msg->num_chunks; i++) {
+ u32 max_queue_in_chunk;
+
+ if (!ice_vc_supported_queue_type(qs_msg->chunks[i].type))
+ return false;
+
+ if (!qs_msg->chunks[i].num_queues)
+ return false;
+
+ max_queue_in_chunk = qs_msg->chunks[i].start_queue_id +
+ qs_msg->chunks[i].num_queues;
+ if (max_queue_in_chunk > vf->num_vf_qs)
+ return false;
+ }
+
+ return true;
+}
+
+#define ice_for_each_q_in_chunk(chunk, q_id) \
+ for ((q_id) = (chunk)->start_queue_id; \
+ (q_id) < (chunk)->start_queue_id + (chunk)->num_queues; \
+ (q_id)++)
+
+static int
+ice_vc_ena_rxq_chunk(struct ice_vf *vf, struct virtchnl_queue_chunk *chunk)
+{
+ struct ice_vsi *vsi;
+ u32 vf_qid;
+
+ ice_for_each_q_in_chunk(chunk, vf_qid) {
+ int err;
+
+ vsi = ice_get_vf_vsi(vf);
+ err = ice_vf_vsi_ena_single_rxq(vf, vsi, vf_qid);
+ if (err)
+ return err;
+ }
+
+ return 0;
+}
+
+static int
+ice_vc_ena_txq_chunk(struct ice_vf *vf, struct virtchnl_queue_chunk *chunk)
+{
+ struct ice_vsi *vsi;
+ u32 vf_qid;
+
+ ice_for_each_q_in_chunk(chunk, vf_qid) {
+ vsi = ice_get_vf_vsi(vf);
+ ice_vf_vsi_ena_single_txq(vf, vsi, vf_qid);
+ }
+
+ return 0;
+}
+
+/**
+ * ice_vc_ena_qs_v2_msg - message handling for VIRTCHNL_OP_ENABLE_QUEUES_V2
+ * @vf: source of the request
+ * @msg: message to handle
+ * @msglen: length of the @msg
+ *
+ * Return: 0 on success or negative on error.
+ */
+int ice_vc_ena_qs_v2_msg(struct ice_vf *vf, u8 *msg, u16 msglen)
+{
+ struct virtchnl_del_ena_dis_queues *ena_qs_msg =
+ (struct virtchnl_del_ena_dis_queues *)msg;
+ enum virtchnl_status_code v_ret = VIRTCHNL_STATUS_SUCCESS;
+
+ if (!ice_vc_validate_qs_v2_msg(vf, ena_qs_msg, msglen))
+ goto error_param;
+
+ for (int i = 0; i < ena_qs_msg->num_chunks; i++) {
+ struct virtchnl_queue_chunk *chunk = &ena_qs_msg->chunks[i];
+
+ if (chunk->type == VIRTCHNL_QUEUE_TYPE_RX &&
+ ice_vc_ena_rxq_chunk(vf, chunk))
+ v_ret = VIRTCHNL_STATUS_ERR_PARAM;
+ else if (chunk->type == VIRTCHNL_QUEUE_TYPE_TX &&
+ ice_vc_ena_txq_chunk(vf, chunk))
+ v_ret = VIRTCHNL_STATUS_ERR_PARAM;
+
+ if (v_ret != VIRTCHNL_STATUS_SUCCESS)
+ goto error_param;
+ }
+
+ set_bit(ICE_VF_STATE_QS_ENA, vf->vf_states);
+
+error_param:
+ return ice_vc_send_msg_to_vf(vf, VIRTCHNL_OP_ENABLE_QUEUES_V2,
+ v_ret, NULL, 0);
+}
+
+static int
+ice_vc_dis_rxq_chunk(struct ice_vf *vf, struct virtchnl_queue_chunk *chunk)
+{
+ struct ice_vsi *vsi;
+ u32 vf_qid;
+
+ ice_for_each_q_in_chunk(chunk, vf_qid) {
+ int err;
+
+ vsi = ice_get_vf_vsi(vf);
+ err = ice_vf_vsi_dis_single_rxq(vf, vsi, vf_qid);
+ if (err)
+ return err;
+ }
+
+ return 0;
+}
+
+static int
+ice_vc_dis_txq_chunk(struct ice_vf *vf, struct virtchnl_queue_chunk *chunk)
+{
+ struct ice_vsi *vsi;
+ u32 vf_qid;
+
+ ice_for_each_q_in_chunk(chunk, vf_qid) {
+ int err;
+
+ vsi = ice_get_vf_vsi(vf);
+ err = ice_vf_vsi_dis_single_txq(vf, vsi, vf_qid);
+ if (err)
+ return err;
+ }
+
+ return 0;
+}
+
+/**
+ * ice_vc_dis_qs_v2_msg - message handling for VIRTCHNL_OP_DISABLE_QUEUES_V2
+ * @vf: source of the request
+ * @msg: message to handle
+ * @msglen: length of @msg
+ *
+ * Return: 0 on success or negative on error.
+ */
+int ice_vc_dis_qs_v2_msg(struct ice_vf *vf, u8 *msg, u16 msglen)
+{
+ struct virtchnl_del_ena_dis_queues *dis_qs_msg =
+ (struct virtchnl_del_ena_dis_queues *)msg;
+ enum virtchnl_status_code v_ret = VIRTCHNL_STATUS_SUCCESS;
+
+ if (!ice_vc_validate_qs_v2_msg(vf, dis_qs_msg, msglen))
+ goto error_param;
+
+ for (int i = 0; i < dis_qs_msg->num_chunks; i++) {
+ struct virtchnl_queue_chunk *chunk = &dis_qs_msg->chunks[i];
+
+ if (chunk->type == VIRTCHNL_QUEUE_TYPE_RX &&
+ ice_vc_dis_rxq_chunk(vf, chunk))
+ v_ret = VIRTCHNL_STATUS_ERR_PARAM;
+ else if (chunk->type == VIRTCHNL_QUEUE_TYPE_TX &&
+ ice_vc_dis_txq_chunk(vf, chunk))
+ v_ret = VIRTCHNL_STATUS_ERR_PARAM;
+
+ if (v_ret != VIRTCHNL_STATUS_SUCCESS)
+ goto error_param;
+ }
+
+ if (ice_vf_has_no_qs_ena(vf))
+ clear_bit(ICE_VF_STATE_QS_ENA, vf->vf_states);
+
+error_param:
+ return ice_vc_send_msg_to_vf(vf, VIRTCHNL_OP_DISABLE_QUEUES_V2,
+ v_ret, NULL, 0);
+}
+
+/**
+ * ice_vc_validate_qv_maps - validate parameters sent in the qs_msg structure
+ * @vf: VF the message was received from
+ * @qv_maps: contents of the message from the VF
+ * @msglen: length of the @qv_maps
+ *
+ * Used to validate VIRTCHNL_OP_MAP_QUEUE_VECTOR messages. This should always
+ * be called before attempting map interrupts to queues. If all checks succeed,
+ * then return success indicating to the caller that the qv_maps are valid.
+ * Otherwise return false, indicating to the caller that the qv_maps are
+ * invalid.
+ *
+ * Return: true if parameters are valid, false otherwise.
+ */
+static bool ice_vc_validate_qv_maps(struct ice_vf *vf,
+ struct virtchnl_queue_vector_maps *qv_maps,
+ u16 msglen)
+{
+ struct ice_vsi *vsi;
+ int total_vectors;
+
+ vsi = vf->pf->vsi[vf->lan_vsi_idx];
+ if (!vsi)
+ return false;
+
+ if (msglen < virtchnl_struct_size(qv_maps, qv_maps, 0))
+ return false;
+
+ if (msglen < virtchnl_struct_size(qv_maps, qv_maps, qv_maps->num_qv_maps))
+ return false;
+
+ if (!qv_maps->num_qv_maps)
+ return false;
+
+ if (!test_bit(ICE_VF_STATE_ACTIVE, vf->vf_states))
+ return false;
+
+ if (!ice_vc_isvalid_vsi_id(vf, qv_maps->vport_id))
+ return false;
+
+ total_vectors = vsi->num_q_vectors + ICE_NONQ_VECS_VF;
+
+ for (int i = 0; i < qv_maps->num_qv_maps; i++) {
+ if (!ice_vc_supported_queue_type(qv_maps->qv_maps[i].queue_type))
+ return false;
+
+ if (qv_maps->qv_maps[i].queue_id >= vf->num_vf_qs)
+ return false;
+
+ if (qv_maps->qv_maps[i].vector_id >= total_vectors ||
+ qv_maps->qv_maps[i].vector_id < ICE_NONQ_VECS_VF)
+ return false;
+ }
+
+ return true;
+}
+
+/**
+ * ice_vc_map_q_vector_msg - message handling for VIRTCHNL_OP_MAP_QUEUE_VECTOR
+ * @vf: source of the request
+ * @msg: message to handle
+ * @msglen: length of @msg
+ *
+ * Return: 0 on success or negative on error
+ */
+int ice_vc_map_q_vector_msg(struct ice_vf *vf, u8 *msg, u16 msglen)
+{
+ enum virtchnl_status_code v_ret = VIRTCHNL_STATUS_SUCCESS;
+ struct virtchnl_queue_vector_maps *qv_maps;
+ struct ice_vsi *vsi;
+
+ qv_maps = (struct virtchnl_queue_vector_maps *)msg;
+
+ if (!ice_vc_validate_qv_maps(vf, qv_maps, msglen)) {
+ v_ret = VIRTCHNL_STATUS_ERR_PARAM;
+ goto error_param;
+ }
+
+ for (int i = 0; i < qv_maps->num_qv_maps; i++) {
+ struct virtchnl_queue_vector *qv_map = &qv_maps->qv_maps[i];
+ struct ice_q_vector *q_vector;
+ u16 vector_id;
+ int vsi_q_id;
+
+ vsi = ice_get_vf_vsi(vf);
+ vsi_q_id = qv_map->queue_id;
+ vector_id = qv_map->vector_id;
+
+ if (!vsi) {
+ v_ret = VIRTCHNL_STATUS_ERR_PARAM;
+ goto error_param;
+ }
+
+ q_vector = vf->vf_ops->get_q_vector(vsi, vector_id);
+
+ if (!q_vector) {
+ v_ret = VIRTCHNL_STATUS_ERR_PARAM;
+ goto error_param;
+ }
+
+ if (!ice_vc_isvalid_q_id(vsi, vsi_q_id))
+ return VIRTCHNL_STATUS_ERR_PARAM;
+
+ if (qv_map->queue_type == VIRTCHNL_QUEUE_TYPE_RX)
+ ice_cfg_rxq_interrupt(vsi, vsi_q_id,
+ q_vector->vf_reg_idx,
+ qv_map->itr_idx);
+ else if (qv_map->queue_type == VIRTCHNL_QUEUE_TYPE_TX)
+ ice_cfg_txq_interrupt(vsi, vsi_q_id,
+ q_vector->vf_reg_idx,
+ qv_map->itr_idx);
+ }
+
+error_param:
+ return ice_vc_send_msg_to_vf(vf, VIRTCHNL_OP_MAP_QUEUE_VECTOR,
+ v_ret, NULL, 0);
+}
--
2.39.3
^ permalink raw reply related [flat|nested] 28+ messages in thread* RE: [PATCH iwl-next v1 12/15] ice: introduce handling of virtchnl LARGE VF opcodes
2026-05-08 12:42 ` [PATCH iwl-next v1 12/15] ice: introduce handling of virtchnl LARGE VF opcodes Przemek Kitszel
@ 2026-05-08 16:55 ` Loktionov, Aleksandr
2026-05-11 9:39 ` Przemek Kitszel
0 siblings, 1 reply; 28+ messages in thread
From: Loktionov, Aleksandr @ 2026-05-08 16:55 UTC (permalink / raw)
To: Kitszel, Przemyslaw, intel-wired-lan@lists.osuosl.org,
Schmidt, Michal, Jakub Kicinski, Jiri Pirko
Cc: netdev@vger.kernel.org, Simon Horman, Nguyen, Anthony L,
Michal Swiatkowski, Richardson, Bruce, Medvedkin, Vladimir,
Connolly, Padraig J, S, Ananth, Miskell, Timothy, Keller, Jacob E,
Czapnik, Lukasz, Andrew Lunn, David S. Miller, Eric Dumazet,
Paolo Abeni, Saeed Mahameed, Leon Romanovsky, Tariq Toukan,
Mark Bloch
> -----Original Message-----
> From: Kitszel, Przemyslaw <przemyslaw.kitszel@intel.com>
> Sent: Friday, May 8, 2026 2:42 PM
> To: intel-wired-lan@lists.osuosl.org; Schmidt, Michal
> <mschmidt@redhat.com>; Jakub Kicinski <kuba@kernel.org>; Jiri Pirko
> <jiri@resnulli.us>
> Cc: netdev@vger.kernel.org; Simon Horman <horms@kernel.org>; Nguyen,
> Anthony L <anthony.l.nguyen@intel.com>; Michal Swiatkowski
> <michal.swiatkowski@linux.intel.com>; Richardson, Bruce
> <bruce.richardson@intel.com>; Medvedkin, Vladimir
> <vladimir.medvedkin@intel.com>; Connolly, Padraig J
> <padraig.j.connolly@intel.com>; S, Ananth <ananth.s@intel.com>;
> Miskell, Timothy <timothy.miskell@intel.com>; Keller, Jacob E
> <jacob.e.keller@intel.com>; Czapnik, Lukasz
> <lukasz.czapnik@intel.com>; Loktionov, Aleksandr
> <aleksandr.loktionov@intel.com>; Andrew Lunn <andrew+netdev@lunn.ch>;
> David S. Miller <davem@davemloft.net>; Eric Dumazet
> <edumazet@google.com>; Paolo Abeni <pabeni@redhat.com>; Saeed Mahameed
> <saeedm@nvidia.com>; Leon Romanovsky <leon@kernel.org>; Tariq Toukan
> <tariqt@nvidia.com>; Mark Bloch <mbloch@nvidia.com>; Kitszel,
> Przemyslaw <przemyslaw.kitszel@intel.com>
> Subject: [PATCH iwl-next v1 12/15] ice: introduce handling of virtchnl
> LARGE VF opcodes
>
> From: Brett Creeley <brett.creeley@intel.com>
>
> With new virtchnl offload/capability VFs are able to make use of more
> than
> 16 queues. But to old opcodes were designed with a max of 16 queues,
> so new ones were added (by iavf/virtchnl commit of this series):
> VIRTCHNL_OP_GET_MAX_RSS_QREGION, VIRTCHNL_OP_ENABLE_QUEUES_V2,
> VIRTCHNL_OP_DISABLE_QUEUES_V2, VIRTCHNL_OP_MAP_QUEUE_VECTOR.
>
> If a VF wishes to request >16 queues it should first make sure that
> the PF supports the VIRTCHNL_VF_LARGE_NUM_QPAIRS capability.
>
> Co-developed-by: Przemek Kitszel <przemyslaw.kitszel@intel.com>
> Signed-off-by: Przemek Kitszel <przemyslaw.kitszel@intel.com>
> Co-developed-by: Aleksandr Loktionov <aleksandr.loktionov@intel.com> #
> msglen val
> Signed-off-by: Aleksandr Loktionov <aleksandr.loktionov@intel.com>
> Signed-off-by: Brett Creeley <brett.creeley@intel.com>
> ---
> drivers/net/ethernet/intel/ice/ice_vf_lib.h | 1 +
> drivers/net/ethernet/intel/ice/virt/queues.h | 3 +
> .../net/ethernet/intel/ice/virt/allowlist.c | 8 +
> drivers/net/ethernet/intel/ice/virt/queues.c | 324
> ++++++++++++++++++
> 4 files changed, 336 insertions(+)
>
> diff --git a/drivers/net/ethernet/intel/ice/ice_vf_lib.h
> b/drivers/net/ethernet/intel/ice/ice_vf_lib.h
> index 1b56f7150eb7..5411eaa1761c 100644
> --- a/drivers/net/ethernet/intel/ice/ice_vf_lib.h
> +++ b/drivers/net/ethernet/intel/ice/ice_vf_lib.h
> @@ -125,6 +125,7 @@ struct ice_vf_ops {
> void (*clear_reset_trigger)(struct ice_vf *vf);
> void (*irq_close)(struct ice_vf *vf);
> void (*post_vsi_rebuild)(struct ice_vf *vf);
...
> +/**
> + * ice_vc_map_q_vector_msg - message handling for
> +VIRTCHNL_OP_MAP_QUEUE_VECTOR
> + * @vf: source of the request
> + * @msg: message to handle
> + * @msglen: length of @msg
> + *
> + * Return: 0 on success or negative on error */ int
> +ice_vc_map_q_vector_msg(struct ice_vf *vf, u8 *msg, u16 msglen) {
> + enum virtchnl_status_code v_ret = VIRTCHNL_STATUS_SUCCESS;
> + struct virtchnl_queue_vector_maps *qv_maps;
> + struct ice_vsi *vsi;
> +
> + qv_maps = (struct virtchnl_queue_vector_maps *)msg;
> +
> + if (!ice_vc_validate_qv_maps(vf, qv_maps, msglen)) {
> + v_ret = VIRTCHNL_STATUS_ERR_PARAM;
> + goto error_param;
> + }
> +
> + for (int i = 0; i < qv_maps->num_qv_maps; i++) {
> + struct virtchnl_queue_vector *qv_map = &qv_maps-
> >qv_maps[i];
> + struct ice_q_vector *q_vector;
> + u16 vector_id;
> + int vsi_q_id;
> +
> + vsi = ice_get_vf_vsi(vf);
> + vsi_q_id = qv_map->queue_id;
> + vector_id = qv_map->vector_id;
> +
> + if (!vsi) {
> + v_ret = VIRTCHNL_STATUS_ERR_PARAM;
> + goto error_param;
> + }
> +
> + q_vector = vf->vf_ops->get_q_vector(vsi, vector_id);
> +
> + if (!q_vector) {
> + v_ret = VIRTCHNL_STATUS_ERR_PARAM;
> + goto error_param;
> + }
> +
> + if (!ice_vc_isvalid_q_id(vsi, vsi_q_id))
This function declared as returning linux errno, not enum.
And in this case there is no reply to VF (goto error_param), couldn't it lead to VF stall?
> + return VIRTCHNL_STATUS_ERR_PARAM;
> +
> + if (qv_map->queue_type == VIRTCHNL_QUEUE_TYPE_RX)
> + ice_cfg_rxq_interrupt(vsi, vsi_q_id,
> + q_vector->vf_reg_idx,
> + qv_map->itr_idx);
> + else if (qv_map->queue_type == VIRTCHNL_QUEUE_TYPE_TX)
> + ice_cfg_txq_interrupt(vsi, vsi_q_id,
> + q_vector->vf_reg_idx,
> + qv_map->itr_idx);
> + }
> +
> +error_param:
> + return ice_vc_send_msg_to_vf(vf, VIRTCHNL_OP_MAP_QUEUE_VECTOR,
> + v_ret, NULL, 0);
> +}
> --
> 2.39.3
^ permalink raw reply [flat|nested] 28+ messages in thread* Re: [PATCH iwl-next v1 12/15] ice: introduce handling of virtchnl LARGE VF opcodes
2026-05-08 16:55 ` Loktionov, Aleksandr
@ 2026-05-11 9:39 ` Przemek Kitszel
0 siblings, 0 replies; 28+ messages in thread
From: Przemek Kitszel @ 2026-05-11 9:39 UTC (permalink / raw)
To: Loktionov, Aleksandr, intel-wired-lan@lists.osuosl.org
Cc: netdev@vger.kernel.org, Schmidt, Michal, Jakub Kicinski,
Jiri Pirko, Simon Horman, Nguyen, Anthony L, Michal Swiatkowski,
Richardson, Bruce, Medvedkin, Vladimir, Connolly, Padraig J,
S, Ananth, Miskell, Timothy, Keller, Jacob E, Czapnik, Lukasz,
Andrew Lunn, David S. Miller, Eric Dumazet, Paolo Abeni,
Saeed Mahameed, Leon Romanovsky, Tariq Toukan, Mark Bloch
On 5/8/26 18:55, Loktionov, Aleksandr wrote:
>
>
>> -----Original Message-----
>> From: Kitszel, Przemyslaw <przemyslaw.kitszel@intel.com>
>> Sent: Friday, May 8, 2026 2:42 PM
>> To: intel-wired-lan@lists.osuosl.org; Schmidt, Michal
>> <mschmidt@redhat.com>; Jakub Kicinski <kuba@kernel.org>; Jiri Pirko
>> <jiri@resnulli.us>
>> Cc: netdev@vger.kernel.org; Simon Horman <horms@kernel.org>; Nguyen,
>> Anthony L <anthony.l.nguyen@intel.com>; Michal Swiatkowski
>> <michal.swiatkowski@linux.intel.com>; Richardson, Bruce
>> <bruce.richardson@intel.com>; Medvedkin, Vladimir
>> <vladimir.medvedkin@intel.com>; Connolly, Padraig J
>> <padraig.j.connolly@intel.com>; S, Ananth <ananth.s@intel.com>;
>> Miskell, Timothy <timothy.miskell@intel.com>; Keller, Jacob E
>> <jacob.e.keller@intel.com>; Czapnik, Lukasz
>> <lukasz.czapnik@intel.com>; Loktionov, Aleksandr
>> <aleksandr.loktionov@intel.com>; Andrew Lunn <andrew+netdev@lunn.ch>;
>> David S. Miller <davem@davemloft.net>; Eric Dumazet
>> <edumazet@google.com>; Paolo Abeni <pabeni@redhat.com>; Saeed Mahameed
>> <saeedm@nvidia.com>; Leon Romanovsky <leon@kernel.org>; Tariq Toukan
>> <tariqt@nvidia.com>; Mark Bloch <mbloch@nvidia.com>; Kitszel,
>> Przemyslaw <przemyslaw.kitszel@intel.com>
>> Subject: [PATCH iwl-next v1 12/15] ice: introduce handling of virtchnl
>> LARGE VF opcodes
>>
>> From: Brett Creeley <brett.creeley@intel.com>
>>
>> With new virtchnl offload/capability VFs are able to make use of more
>> than
>> 16 queues. But to old opcodes were designed with a max of 16 queues,
>> so new ones were added (by iavf/virtchnl commit of this series):
>> VIRTCHNL_OP_GET_MAX_RSS_QREGION, VIRTCHNL_OP_ENABLE_QUEUES_V2,
>> VIRTCHNL_OP_DISABLE_QUEUES_V2, VIRTCHNL_OP_MAP_QUEUE_VECTOR.
>>
>> If a VF wishes to request >16 queues it should first make sure that
>> the PF supports the VIRTCHNL_VF_LARGE_NUM_QPAIRS capability.
>>
>> Co-developed-by: Przemek Kitszel <przemyslaw.kitszel@intel.com>
>> Signed-off-by: Przemek Kitszel <przemyslaw.kitszel@intel.com>
>> Co-developed-by: Aleksandr Loktionov <aleksandr.loktionov@intel.com> #
>> msglen val
>> Signed-off-by: Aleksandr Loktionov <aleksandr.loktionov@intel.com>
>> Signed-off-by: Brett Creeley <brett.creeley@intel.com>
>> ---
>> drivers/net/ethernet/intel/ice/ice_vf_lib.h | 1 +
>> drivers/net/ethernet/intel/ice/virt/queues.h | 3 +
>> .../net/ethernet/intel/ice/virt/allowlist.c | 8 +
>> drivers/net/ethernet/intel/ice/virt/queues.c | 324
>> ++++++++++++++++++
>> 4 files changed, 336 insertions(+)
>>
>> diff --git a/drivers/net/ethernet/intel/ice/ice_vf_lib.h
>> b/drivers/net/ethernet/intel/ice/ice_vf_lib.h
>> index 1b56f7150eb7..5411eaa1761c 100644
>> --- a/drivers/net/ethernet/intel/ice/ice_vf_lib.h
>> +++ b/drivers/net/ethernet/intel/ice/ice_vf_lib.h
>> @@ -125,6 +125,7 @@ struct ice_vf_ops {
>> void (*clear_reset_trigger)(struct ice_vf *vf);
>> void (*irq_close)(struct ice_vf *vf);
>> void (*post_vsi_rebuild)(struct ice_vf *vf);
>
> ...
>
>> +/**
>> + * ice_vc_map_q_vector_msg - message handling for
>> +VIRTCHNL_OP_MAP_QUEUE_VECTOR
>> + * @vf: source of the request
>> + * @msg: message to handle
>> + * @msglen: length of @msg
>> + *
>> + * Return: 0 on success or negative on error */ int
>> +ice_vc_map_q_vector_msg(struct ice_vf *vf, u8 *msg, u16 msglen) {
>> + enum virtchnl_status_code v_ret = VIRTCHNL_STATUS_SUCCESS;
>> + struct virtchnl_queue_vector_maps *qv_maps;
>> + struct ice_vsi *vsi;
>> +
>> + qv_maps = (struct virtchnl_queue_vector_maps *)msg;
>> +
>> + if (!ice_vc_validate_qv_maps(vf, qv_maps, msglen)) {
>> + v_ret = VIRTCHNL_STATUS_ERR_PARAM;
>> + goto error_param;
>> + }
>> +
>> + for (int i = 0; i < qv_maps->num_qv_maps; i++) {
>> + struct virtchnl_queue_vector *qv_map = &qv_maps-
>>> qv_maps[i];
>> + struct ice_q_vector *q_vector;
>> + u16 vector_id;
>> + int vsi_q_id;
>> +
>> + vsi = ice_get_vf_vsi(vf);
>> + vsi_q_id = qv_map->queue_id;
>> + vector_id = qv_map->vector_id;
>> +
>> + if (!vsi) {
>> + v_ret = VIRTCHNL_STATUS_ERR_PARAM;
>> + goto error_param;
>> + }
>> +
>> + q_vector = vf->vf_ops->get_q_vector(vsi, vector_id);
>> +
>> + if (!q_vector) {
>> + v_ret = VIRTCHNL_STATUS_ERR_PARAM;
>> + goto error_param;
>> + }
>> +
>> + if (!ice_vc_isvalid_q_id(vsi, vsi_q_id))
> This function declared as returning linux errno, not enum.
> And in this case there is no reply to VF (goto error_param), couldn't it lead to VF stall?
good catch, will fix it
it wouldn't be VF stall, but an ugly "PF not replied to our request" msg
>
>> + return VIRTCHNL_STATUS_ERR_PARAM;
>> +
>> + if (qv_map->queue_type == VIRTCHNL_QUEUE_TYPE_RX)
>> + ice_cfg_rxq_interrupt(vsi, vsi_q_id,
>> + q_vector->vf_reg_idx,
>> + qv_map->itr_idx);
>> + else if (qv_map->queue_type == VIRTCHNL_QUEUE_TYPE_TX)
>> + ice_cfg_txq_interrupt(vsi, vsi_q_id,
>> + q_vector->vf_reg_idx,
>> + qv_map->itr_idx);
>> + }
>> +
>> +error_param:
>> + return ice_vc_send_msg_to_vf(vf, VIRTCHNL_OP_MAP_QUEUE_VECTOR,
>> + v_ret, NULL, 0);
>> +}
>> --
>> 2.39.3
>
^ permalink raw reply [flat|nested] 28+ messages in thread
* [PATCH iwl-next v1 13/15] devlink: give user option to allocate resources
2026-05-08 12:41 [PATCH iwl-next v1 00/15] devlink, mlx5, iavf, ice: XLVF for iavf Przemek Kitszel
` (11 preceding siblings ...)
2026-05-08 12:42 ` [PATCH iwl-next v1 12/15] ice: introduce handling of virtchnl LARGE VF opcodes Przemek Kitszel
@ 2026-05-08 12:42 ` Przemek Kitszel
2026-05-08 12:42 ` [PATCH iwl-next v1 14/15] ice: represent RSS LUTs as devlink resources Przemek Kitszel
2026-05-08 12:42 ` [PATCH iwl-next v1 15/15] ice: support up to 256 VF queues Przemek Kitszel
14 siblings, 0 replies; 28+ messages in thread
From: Przemek Kitszel @ 2026-05-08 12:42 UTC (permalink / raw)
To: intel-wired-lan, Michal Schmidt, Jakub Kicinski, Jiri Pirko
Cc: netdev, Simon Horman, Tony Nguyen, Michal Swiatkowski,
bruce.richardson, Vladimir Medvedkin, padraig.j.connolly,
ananth.s, timothy.miskell, Jacob Keller, Lukasz Czapnik,
Aleksandr Loktionov, Andrew Lunn, David S. Miller, Eric Dumazet,
Paolo Abeni, Saeed Mahameed, Leon Romanovsky, Tariq Toukan,
Mark Bloch, Przemek Kitszel
Current devlink resources are designed as a thing that user could limit,
but there is not much otherwise that could be done with them.
Perhaps that's the reason there is no much adoption despite API being
there for multiple years.
Add new mode of operation, where user could allocate/assign resources
(from a common pool) to specific devices.
That requires "occ set" support, triggered by user.
To support that mode, "occ get" is (only then) turned into a simple
"get/show" operation, as opposed to "ask driver about current occupation"
in the "legacy" mode.
Signed-off-by: Przemek Kitszel <przemyslaw.kitszel@intel.com>
---
RFC, Feb '25
https://lore.kernel.org/intel-wired-lan/20250219164410.35665-3-przemyslaw.kitszel@intel.com
I have structured code to just choose "the mode" of operation based on
the presence of .occ_set callback, instead of naming the mode, what,
even if not the most clear code, avoids the need of naming the modes.
---
include/net/devlink.h | 7 +++
net/devlink/resource.c | 98 +++++++++++++++++++++++++++++++++---------
2 files changed, 85 insertions(+), 20 deletions(-)
diff --git a/include/net/devlink.h b/include/net/devlink.h
index 5d3a1337bfa1..9b777f02beca 100644
--- a/include/net/devlink.h
+++ b/include/net/devlink.h
@@ -420,6 +420,8 @@ devlink_resource_size_params_init(struct devlink_resource_size_params *size_para
}
typedef u64 devlink_resource_occ_get_t(void *priv);
+typedef int devlink_resource_occ_set_t(u64 size, struct netlink_ext_ack *extack,
+ void *priv);
#define DEVLINK_RESOURCE_ID_PARENT_TOP 0
@@ -1934,6 +1936,11 @@ void devl_resource_occ_get_register(struct devlink *devlink,
void *occ_get_priv);
void devl_resource_occ_get_unregister(struct devlink *devlink,
u64 resource_id);
+void devl_resource_occ_set_get_register(struct devlink *devlink,
+ u64 resource_id,
+ devlink_resource_occ_set_t *occ_set,
+ devlink_resource_occ_get_t *occ_get,
+ void *occ_priv);
int devl_params_register(struct devlink *devlink,
const struct devlink_param *params,
size_t params_count);
diff --git a/net/devlink/resource.c b/net/devlink/resource.c
index 3d2f42bc2fb5..2212eff5230d 100644
--- a/net/devlink/resource.c
+++ b/net/devlink/resource.c
@@ -19,7 +19,8 @@
* @list: parent list
* @resource_list: list of child resources
* @occ_get: occupancy getter callback
- * @occ_get_priv: occupancy getter callback priv
+ * @occ_set: occupancy setter callback
+ * @occ_priv: occupancy callbacks priv
*/
struct devlink_resource {
const char *name;
@@ -32,7 +33,8 @@ struct devlink_resource {
struct list_head list;
struct list_head resource_list;
devlink_resource_occ_get_t *occ_get;
- void *occ_get_priv;
+ devlink_resource_occ_set_t *occ_set;
+ void *occ_priv;
};
static struct devlink_resource *
@@ -137,6 +139,9 @@ int devlink_nl_resource_set_doit(struct sk_buff *skb, struct genl_info *info)
if (err)
return err;
+ if (resource->occ_set)
+ return resource->occ_set(size, info->extack, resource->occ_priv);
+
resource->size_new = size;
devlink_resource_validate_children(resource);
if (resource->parent)
@@ -162,13 +167,40 @@ devlink_resource_size_params_put(struct devlink_resource *resource,
return 0;
}
-static int devlink_resource_occ_put(struct devlink_resource *resource,
- struct sk_buff *skb)
+static int
+devlink_resource_occ_size_put_legacy(struct devlink_resource *resource,
+ struct sk_buff *skb)
{
- if (!resource->occ_get)
- return 0;
- return devlink_nl_put_u64(skb, DEVLINK_ATTR_RESOURCE_OCC,
- resource->occ_get(resource->occ_get_priv));
+ if (devlink_nl_put_u64(skb, DEVLINK_ATTR_RESOURCE_SIZE, resource->size))
+ goto err;
+ if (resource->size != resource->size_new &&
+ devlink_nl_put_u64(skb, DEVLINK_ATTR_RESOURCE_SIZE_NEW,
+ resource->size_new))
+ goto err;
+ if (resource->occ_get &&
+ devlink_nl_put_u64(skb, DEVLINK_ATTR_RESOURCE_OCC,
+ resource->occ_get(resource->occ_priv)))
+ goto err;
+ if (nla_put_u8(skb, DEVLINK_ATTR_RESOURCE_SIZE_VALID,
+ resource->size_valid))
+ goto err;
+
+ return 0;
+err:
+ return -EMSGSIZE;
+}
+
+static int devlink_resource_occ_size_put(struct devlink_resource *resource,
+ struct sk_buff *skb)
+{
+ if (!resource->occ_get || !resource->occ_set)
+ return devlink_resource_occ_size_put_legacy(resource, skb);
+
+ if (nla_put_u8(skb, DEVLINK_ATTR_RESOURCE_SIZE_VALID, true))
+ return -EMSGSIZE;
+
+ return devlink_nl_put_u64(skb, DEVLINK_ATTR_RESOURCE_SIZE,
+ resource->occ_get(resource->occ_priv));
}
static int devlink_resource_put(struct devlink *devlink, struct sk_buff *skb,
@@ -183,24 +215,16 @@ static int devlink_resource_put(struct devlink *devlink, struct sk_buff *skb,
return -EMSGSIZE;
if (nla_put_string(skb, DEVLINK_ATTR_RESOURCE_NAME, resource->name) ||
- devlink_nl_put_u64(skb, DEVLINK_ATTR_RESOURCE_SIZE, resource->size) ||
devlink_nl_put_u64(skb, DEVLINK_ATTR_RESOURCE_ID, resource->id))
goto nla_put_failure;
- if (resource->size != resource->size_new &&
- devlink_nl_put_u64(skb, DEVLINK_ATTR_RESOURCE_SIZE_NEW,
- resource->size_new))
- goto nla_put_failure;
- if (devlink_resource_occ_put(resource, skb))
+ if (devlink_resource_occ_size_put(resource, skb))
goto nla_put_failure;
if (devlink_resource_size_params_put(resource, skb))
goto nla_put_failure;
+
if (list_empty(&resource->resource_list))
goto out;
- if (nla_put_u8(skb, DEVLINK_ATTR_RESOURCE_SIZE_VALID,
- resource->size_valid))
- goto nla_put_failure;
-
child_resource_attr = nla_nest_start_noflag(skb,
DEVLINK_ATTR_RESOURCE_LIST);
if (!child_resource_attr)
@@ -634,6 +658,39 @@ int devl_resource_size_get(struct devlink *devlink,
}
EXPORT_SYMBOL_GPL(devl_resource_size_get);
+/**
+ * devl_resource_occ_set_get_register - register occupancy getter and setter
+ *
+ * @devlink: devlink
+ * @resource_id: resource id
+ * @occ_set: occupancy setter callback
+ * @occ_get: occupancy getter callback
+ * @occ_priv: occupancy getter callback priv
+ *
+ * Setter will be called when the user wants to change the resource size,
+ * getter is called to show the user what is current size of the resource.
+ */
+void devl_resource_occ_set_get_register(struct devlink *devlink,
+ u64 resource_id,
+ devlink_resource_occ_set_t *occ_set,
+ devlink_resource_occ_get_t *occ_get,
+ void *occ_priv)
+{
+ struct devlink_resource *resource;
+
+ lockdep_assert_held(&devlink->lock);
+
+ resource = devlink_resource_find(devlink, NULL, resource_id);
+ if (WARN_ON(!resource))
+ return;
+ WARN_ON(resource->occ_get || resource->occ_set);
+
+ resource->occ_set = occ_set;
+ resource->occ_get = occ_get;
+ resource->occ_priv = occ_priv;
+}
+EXPORT_SYMBOL_GPL(devl_resource_occ_set_get_register);
+
/**
* devl_resource_occ_get_register - register occupancy getter
*
@@ -657,7 +714,7 @@ void devl_resource_occ_get_register(struct devlink *devlink,
WARN_ON(resource->occ_get);
resource->occ_get = occ_get;
- resource->occ_get_priv = occ_get_priv;
+ resource->occ_priv = occ_get_priv;
}
EXPORT_SYMBOL_GPL(devl_resource_occ_get_register);
@@ -678,9 +735,10 @@ void devl_resource_occ_get_unregister(struct devlink *devlink,
if (WARN_ON(!resource))
return;
WARN_ON(!resource->occ_get);
+ WARN_ON(resource->occ_set);
resource->occ_get = NULL;
- resource->occ_get_priv = NULL;
+ resource->occ_priv = NULL;
}
EXPORT_SYMBOL_GPL(devl_resource_occ_get_unregister);
--
2.39.3
^ permalink raw reply related [flat|nested] 28+ messages in thread* [PATCH iwl-next v1 14/15] ice: represent RSS LUTs as devlink resources
2026-05-08 12:41 [PATCH iwl-next v1 00/15] devlink, mlx5, iavf, ice: XLVF for iavf Przemek Kitszel
` (12 preceding siblings ...)
2026-05-08 12:42 ` [PATCH iwl-next v1 13/15] devlink: give user option to allocate resources Przemek Kitszel
@ 2026-05-08 12:42 ` Przemek Kitszel
2026-05-08 17:03 ` Loktionov, Aleksandr
2026-05-08 12:42 ` [PATCH iwl-next v1 15/15] ice: support up to 256 VF queues Przemek Kitszel
14 siblings, 1 reply; 28+ messages in thread
From: Przemek Kitszel @ 2026-05-08 12:42 UTC (permalink / raw)
To: intel-wired-lan, Michal Schmidt, Jakub Kicinski, Jiri Pirko
Cc: netdev, Simon Horman, Tony Nguyen, Michal Swiatkowski,
bruce.richardson, Vladimir Medvedkin, padraig.j.connolly,
ananth.s, timothy.miskell, Jacob Keller, Lukasz Czapnik,
Aleksandr Loktionov, Andrew Lunn, David S. Miller, Eric Dumazet,
Paolo Abeni, Saeed Mahameed, Leon Romanovsky, Tariq Toukan,
Mark Bloch, Przemek Kitszel
E800 family offers three kinds of RSS LUTs: VSI LUT (sized 64), GLOBAL LUT
(sized 256), and PF LUT (sized 2048). Until now the GLOBAL kind was not
used at all. There are two possible usages for it, subsequent commit will
give VF option to acquire it, and this one enables PF to switch between PF
LUT and GLOBAL LUT - switching to smaller one is, again, to make it
possible for VF to then acquire the former one.
Devlink resources are used to let user show current usage and change the
allocation, see examples below.
Default state on 8-port card, asking for aggregate "whole device" usage,
note that there are as many PF LUTs as there is PFs, and, for e810, there
are 16 GLOBAL LUTs:
$ devlink resource show devlink_index/11
devlink_index/11:
name rss size 8 unit entry size_min 0 size_max 24 size_gran 1 dpipe_tables none
resources:
name lut_512 size 0 unit entry size_min 0 size_max 16 size_gran 1 dpipe_tables none
name lut_2048 size 8 unit entry size_min 0 size_max 8 size_gran 1 dpipe_tables none
Now let's add GLOBAL LUT for a single PF (on one-port NIC):
$ sudo devlink resource set pci/0000:18:00.0 path rss/lut_512 size 1
And show it's resources after that:
$ devlink resource show pci/0000:18:00.0
pci/0000:18:00.0:
name rss size 2 unit entry size_min 0 size_max 2 size_gran 1 dpipe_tables none
resources:
name lut_512 size 1 unit entry size_min 0 size_max 1 size_gran 1 dpipe_tables none
name lut_2048 size 1 unit entry size_min 0 size_max 1 size_gran 1 dpipe_tables none
Let's take the PF LUT out of that PF afterwards:
$ sudo devlink resource set pci/0000:18:00.0 path rss/lut_2048 size 0
now `ethtool -x $ifacename` will report smaller RSS table.
Signed-off-by: Przemek Kitszel <przemyslaw.kitszel@intel.com>
---
drivers/net/ethernet/intel/ice/Makefile | 1 +
.../net/ethernet/intel/ice/devlink/resource.h | 19 +
drivers/net/ethernet/intel/ice/ice_adapter.h | 40 ++
drivers/net/ethernet/intel/ice/ice_common.h | 1 +
.../net/ethernet/intel/ice/devlink/resource.c | 469 ++++++++++++++++++
drivers/net/ethernet/intel/ice/ice_adapter.c | 12 +-
drivers/net/ethernet/intel/ice/ice_common.c | 2 +-
drivers/net/ethernet/intel/ice/ice_lib.c | 23 +-
drivers/net/ethernet/intel/ice/ice_main.c | 14 +-
9 files changed, 573 insertions(+), 8 deletions(-)
create mode 100644 drivers/net/ethernet/intel/ice/devlink/resource.h
create mode 100644 drivers/net/ethernet/intel/ice/devlink/resource.c
diff --git a/drivers/net/ethernet/intel/ice/Makefile b/drivers/net/ethernet/intel/ice/Makefile
index 7f06d9bafe4a..0217ab6403de 100644
--- a/drivers/net/ethernet/intel/ice/Makefile
+++ b/drivers/net/ethernet/intel/ice/Makefile
@@ -37,6 +37,7 @@ ice-y := ice_main.o \
devlink/devlink.o \
devlink/health.o \
devlink/port.o \
+ devlink/resource.o \
ice_sf_eth.o \
ice_sf_vsi_vlan_ops.o \
ice_ddp.o \
diff --git a/drivers/net/ethernet/intel/ice/devlink/resource.h b/drivers/net/ethernet/intel/ice/devlink/resource.h
new file mode 100644
index 000000000000..947f77a3cd49
--- /dev/null
+++ b/drivers/net/ethernet/intel/ice/devlink/resource.h
@@ -0,0 +1,19 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright (c) 2026, Intel Corporation. */
+
+#ifndef _ICE_DEVL_RESOURCE_H_
+#define _ICE_DEVL_RESOURCE_H_
+
+struct devlink;
+struct ice_adapter;
+struct ice_hw;
+struct ice_pf;
+
+void ice_devl_pf_resources_register(struct ice_pf *pf);
+void ice_devl_whole_dev_resources_register(const struct ice_hw *hw,
+ struct ice_adapter *adapter);
+
+int ice_take_rss_lut_pf(struct ice_pf *pf);
+void ice_free_rss_lut_flr(struct ice_pf *pf);
+
+#endif /* _ICE_DEVL_RESOURCE_H_ */
diff --git a/drivers/net/ethernet/intel/ice/ice_adapter.h b/drivers/net/ethernet/intel/ice/ice_adapter.h
index 5539ec5f8515..5a9148eb7b63 100644
--- a/drivers/net/ethernet/intel/ice/ice_adapter.h
+++ b/drivers/net/ethernet/intel/ice/ice_adapter.h
@@ -12,6 +12,40 @@
struct pci_dev;
struct ice_pf;
+enum ice_devl_resource_id {
+ /* keep parent IDs prior to children, because we register in order */
+ ICE_TOP_RESOURCE = DEVLINK_RESOURCE_ID_PARENT_TOP,
+ ICE_RSS_LUT_BOTH,
+ ICE_RSS_LUT_GLOBAL,
+ ICE_RSS_LUT_PF,
+ ICE_DEVL_RESOURCES_COUNT
+};
+
+#define ICE_MAX_DEVL_RESOURCE_UNITS 16
+
+/**
+ * struct ice_devl_resource - driver data for devlink resource, config & runtime
+ *
+ * @owner: entity that owns given resource (like ptr to ice_pf or ice_vf)
+ * @pf_id: on which PF the VF is (or just PF id when PF is the owner)
+ * @name: name of the resource to register it with
+ * @get: occ getter callback
+ * @set: occ setter callback
+ * @start_size: starting size of the resource
+ * @max_size: max size of the resource, to present in the uAPI/validate against
+ * @parent_id: ID of the parent resource
+ */
+struct ice_devl_resource {
+ void *owner[ICE_MAX_DEVL_RESOURCE_UNITS];
+ u8 pf_id[ICE_MAX_DEVL_RESOURCE_UNITS];
+ const char *name;
+ devlink_resource_occ_get_t *get;
+ devlink_resource_occ_set_t *set;
+ u32 start_size;
+ u32 max_size;
+ u32 parent_id;
+};
+
/**
* struct ice_port_list - data used to store the list of adapter ports
*
@@ -34,6 +68,7 @@ struct ice_port_list {
* @txq_ctx_lock: Spinlock protecting access to the GLCOMM_QTX_CNTX_CTL register
* @ctrl_pf: Control PF of the adapter
* @ports: Ports list
+ * @resources: array of ice's data for devlink resources
*/
struct ice_adapter {
struct devlink *devlink;
@@ -45,9 +80,14 @@ struct ice_adapter {
struct ice_pf *ctrl_pf;
struct ice_port_list ports;
+
+ struct ice_devl_resource resources[ICE_DEVL_RESOURCES_COUNT];
};
struct ice_adapter *ice_adapter_get(struct pci_dev *pdev);
void ice_adapter_put(struct ice_adapter *adapter);
+DEFINE_GUARD(ice_adapter_devl, struct ice_adapter *,
+ devl_lock((_T)->devlink), devl_unlock((_T)->devlink))
+
#endif /* _ICE_ADAPTER_H */
diff --git a/drivers/net/ethernet/intel/ice/ice_common.h b/drivers/net/ethernet/intel/ice/ice_common.h
index dbb44e9deaf7..c58dd5207da6 100644
--- a/drivers/net/ethernet/intel/ice/ice_common.h
+++ b/drivers/net/ethernet/intel/ice/ice_common.h
@@ -125,6 +125,7 @@ int ice_read_txq_ctx(struct ice_hw *hw, struct ice_tlan_ctx *tlan_ctx,
int ice_write_txq_ctx(struct ice_hw *hw, struct ice_tlan_ctx *tlan_ctx,
u32 txq_index);
+enum ice_lut_size ice_lut_type_to_size(enum ice_lut_type type);
int
ice_aq_get_rss_lut(struct ice_hw *hw, struct ice_aq_get_set_rss_lut_params *get_params);
int
diff --git a/drivers/net/ethernet/intel/ice/devlink/resource.c b/drivers/net/ethernet/intel/ice/devlink/resource.c
new file mode 100644
index 000000000000..42b65730ea52
--- /dev/null
+++ b/drivers/net/ethernet/intel/ice/devlink/resource.c
@@ -0,0 +1,469 @@
+// SPDX-License-Identifier: GPL-2.0
+/* Copyright (c) 2026, Intel Corporation. */
+
+#include "resource.h"
+#include "ice_adapter.h"
+#include "ice.h"
+#include "ice_lib.h"
+
+#define ICE_NUM_GLOBAL_LUTS 16
+#define ICE_ANY_SLOT -1
+
+static u32 ice_devl_res_cnt(const struct ice_adapter *adapter,
+ enum ice_devl_resource_id res_id)
+{
+ const struct ice_devl_resource *res = &adapter->resources[res_id];
+ u32 sum = 0;
+
+ for (int i = 0; i < res->max_size; i++)
+ sum += res->owner[i] != NULL;
+
+ return sum;
+}
+
+static int ice_devl_res_take(struct ice_pf *pf,
+ enum ice_devl_resource_id res_id, int slot,
+ void *owner)
+{
+ struct ice_devl_resource *res = &pf->adapter->resources[res_id];
+ int end = slot == ICE_ANY_SLOT ? res->max_size : slot + 1;
+ int beg = slot == ICE_ANY_SLOT ? 0 : slot;
+ int err, new_id = ICE_ANY_SLOT;
+
+ for (int id = beg; id < end; id++) {
+ if (!res->owner[id]) {
+ new_id = id;
+ break;
+ }
+ }
+ if (new_id == ICE_ANY_SLOT)
+ return -ENOSPC;
+
+ if (res_id == ICE_RSS_LUT_GLOBAL) {
+ struct ice_vsi *vsi;
+ u16 lut_id;
+
+ err = ice_alloc_rss_global_lut(&pf->hw, &lut_id);
+ if (err)
+ return err;
+ if (lut_id != new_id)
+ return -ENOANO;
+
+ if (pf == owner)
+ vsi = ice_get_main_vsi(pf);
+ else
+ vsi = ice_get_vf_vsi(owner);
+
+ vsi->global_lut_id = new_id;
+ }
+
+ res->owner[new_id] = owner;
+ res->pf_id[new_id] = pf->hw.pf_id;
+ return new_id;
+}
+
+static int ice_devl_res_free(struct ice_pf *pf,
+ enum ice_devl_resource_id res_id, void *owner)
+{
+ struct ice_devl_resource *res = &pf->adapter->resources[res_id];
+ int err = 0, id_to_free = ICE_ANY_SLOT;
+
+ for (int i = 0; i < res->max_size; i++) {
+ if (res->owner[i] == owner) {
+ id_to_free = i;
+ break;
+ }
+ }
+ if (id_to_free == ICE_ANY_SLOT)
+ return 0;
+
+ if (res_id == ICE_RSS_LUT_GLOBAL)
+ err = ice_free_rss_global_lut(&pf->hw, id_to_free);
+
+ res->owner[id_to_free] = NULL;
+ return err;
+}
+
+void ice_free_rss_lut_flr(struct ice_pf *pf)
+{
+ struct ice_devl_resource *res, *resources = pf->adapter->resources;
+ int pf_id = pf->hw.pf_id;
+
+ scoped_guard(ice_adapter_devl, pf->adapter) {
+ resources[ICE_RSS_LUT_PF].owner[pf_id] = NULL;
+
+ res = &resources[ICE_RSS_LUT_GLOBAL];
+ for (int i = 0; i < res->max_size; i++) {
+ /* On FLR/PFR resources assigned to PF are cleared by
+ * FW, reflect that in the SW table.
+ * VFs on given PF must be de-programmed too.
+ */
+ if (res->pf_id[i] == pf_id)
+ res->owner[i] = NULL;
+ }
+ }
+}
+
+static int ice_devl_res_owned_idx(struct ice_adapter *adapter,
+ enum ice_devl_resource_id res_id, void *owner)
+{
+ const struct ice_devl_resource *res = &adapter->resources[res_id];
+
+ for (int i = 0; i < res->max_size; i++) {
+ if (res->owner[i] == owner)
+ return i;
+ }
+
+ return -ENXIO;
+}
+
+static bool ice_is_devl_res_owned_by(struct ice_adapter *adapter,
+ enum ice_devl_resource_id res_id,
+ void *owner)
+{
+ return ice_devl_res_owned_idx(adapter, res_id, owner) >= 0;
+}
+
+static u64 ice_rss_lut_whole_dev_occ_get_global(void *priv)
+{
+ struct ice_adapter *adapter = priv;
+
+ return ice_devl_res_cnt(adapter, ICE_RSS_LUT_GLOBAL);
+}
+
+static u64 ice_rss_lut_whole_dev_occ_get_pf(void *priv)
+{
+ struct ice_adapter *adapter = priv;
+
+ return ice_devl_res_cnt(adapter, ICE_RSS_LUT_PF);
+}
+
+static u64 ice_rss_lut_whole_dev_occ_get_both(void *priv)
+{
+ return ice_rss_lut_whole_dev_occ_get_global(priv) +
+ ice_rss_lut_whole_dev_occ_get_pf(priv);
+}
+
+static u64 ice_rss_lut_pf_occ_get_global(void *priv)
+{
+ struct ice_adapter *adapter;
+ struct ice_pf *pf = priv;
+
+ adapter = pf->adapter;
+ scoped_guard(ice_adapter_devl, adapter)
+ return ice_is_devl_res_owned_by(adapter, ICE_RSS_LUT_GLOBAL, pf);
+}
+
+static u64 ice_rss_lut_pf_occ_get_pf(void *priv)
+{
+ struct ice_adapter *adapter;
+ struct ice_pf *pf = priv;
+
+ adapter = pf->adapter;
+ scoped_guard(ice_adapter_devl, adapter)
+ return ice_is_devl_res_owned_by(adapter, ICE_RSS_LUT_PF, pf);
+}
+
+static u64 ice_rss_lut_pf_occ_get_both(void *priv)
+{
+ struct ice_adapter *adapter;
+ struct ice_pf *pf = priv;
+
+ adapter = pf->adapter;
+ scoped_guard(ice_adapter_devl, adapter)
+ return ice_is_devl_res_owned_by(adapter, ICE_RSS_LUT_PF, pf) +
+ ice_is_devl_res_owned_by(adapter, ICE_RSS_LUT_GLOBAL, pf);
+}
+
+static int ice_devl_resource_deny_occ_set(u64 size,
+ struct netlink_ext_ack *extack,
+ void *priv)
+{
+ NL_SET_ERR_MSG_MOD(extack,
+ "can not change directly, parent/aggregate resource just adds up children data");
+ return -EPERM;
+}
+
+enum ice_rss_lut_resource_state {
+ ICE_HAS_NO_LUT = 0,
+ ICE_HAS_GLOBAL_LUT = BIT(ICE_RSS_LUT_GLOBAL),
+ ICE_HAS_PF_LUT = BIT(ICE_RSS_LUT_PF),
+ ICE_HAS_BOTH_LUTS = ICE_HAS_GLOBAL_LUT | ICE_HAS_PF_LUT,
+};
+
+/** ice_rss_lut_resource_state - compute opaque resource state for given owner
+ * @adapter: the adapter the @owner is on
+ * @owner: the entity to compute state of resources for
+ *
+ * Return: computed current state of the RSS resources the @owner has.
+ */
+static enum ice_rss_lut_resource_state
+ice_rss_lut_resource_state(struct ice_adapter *adapter, void *owner)
+{
+ enum ice_rss_lut_resource_state ret = ICE_HAS_NO_LUT;
+
+ if (ice_is_devl_res_owned_by(adapter, ICE_RSS_LUT_GLOBAL, owner))
+ ret |= ICE_HAS_GLOBAL_LUT;
+ if (ice_is_devl_res_owned_by(adapter, ICE_RSS_LUT_PF, owner))
+ ret |= ICE_HAS_PF_LUT;
+
+ return ret;
+}
+
+static int ice_maybe_change_rss_lut(struct ice_pf *pf, void *owner,
+ enum ice_rss_lut_resource_state old,
+ enum ice_rss_lut_resource_state new,
+ struct netlink_ext_ack *extack)
+{
+ struct ice_aq_get_set_rss_lut_params params = {};
+ struct ice_adapter *adapter = pf->adapter;
+ struct ice_hw *hw = &pf->hw;
+ enum ice_lut_type lut_type;
+ int err, lut_size, lut_id;
+ struct ice_vsi *vsi;
+ u8 *lut;
+
+ if (old & new & ICE_HAS_PF_LUT)
+ return 0;
+
+ if (new & ICE_HAS_PF_LUT) {
+ lut_type = ICE_LUT_PF;
+ } else if (new & ICE_HAS_GLOBAL_LUT) {
+ lut_id = ice_devl_res_owned_idx(adapter, ICE_RSS_LUT_GLOBAL, owner);
+ if (lut_id < 0)
+ return lut_id;
+
+ lut_type = ICE_LUT_GLOBAL;
+ params.global_lut_id = lut_id;
+ } else {
+ lut_type = ICE_LUT_VSI;
+ if (owner == pf) {
+ NL_SET_ERR_MSG_FMT(extack, "cannot change PF to use LUT_VSI (sized 64)");
+ return -EDOM;
+ }
+ }
+
+ if (pf == owner) {
+ vsi = ice_get_main_vsi(pf);
+ } else {
+ return -EOPNOTSUPP;
+ }
+
+ lut_size = ice_lut_type_to_size(lut_type);
+ lut = kmalloc(lut_size, GFP_KERNEL);
+ if (!lut)
+ return -ENOMEM;
+ ice_fill_rss_lut(lut, lut_size, vsi->rss_size);
+ params.lut = lut;
+ params.lut_size = lut_size;
+ params.lut_type = lut_type;
+ params.vsi_handle = vsi->idx;
+ err = ice_aq_set_rss_lut(hw, ¶ms);
+ if (err) {
+ NL_SET_ERR_MSG_FMT(extack, "AQ failed: %s", libie_aq_str(hw->adminq.sq_last_status));
+ goto out;
+ }
+
+ vsi->rss_table_size = lut_size;
+ vsi->rss_lut_type = lut_type;
+out:
+ kfree(lut);
+ return err;
+}
+
+static int ice_devl_res_change(bool take, enum ice_devl_resource_id res_id,
+ struct ice_pf *pf, void *owner, int slot,
+ struct netlink_ext_ack *extack)
+{
+ enum ice_rss_lut_resource_state old, new, change;
+ struct ice_adapter *adapter = pf->adapter;
+ int err;
+
+ change = BIT(res_id);
+ old = ice_rss_lut_resource_state(adapter, owner);
+ new = old;
+ if (take)
+ new |= change;
+ else
+ new &= ~change;
+ if (new == old)
+ return 0;
+
+ if (pf == owner && !take && old != ICE_HAS_BOTH_LUTS) {
+ NL_SET_ERR_MSG_MOD(extack,
+ "at least one of 512+ sized LUTs must be assigned to PF device at all times");
+ return -EDOM;
+ }
+
+ if (take) {
+ int slot_id;
+
+ slot_id = ice_devl_res_take(pf, res_id, slot, owner);
+ if (slot_id < 0)
+ return slot_id;
+ }
+
+ err = ice_maybe_change_rss_lut(pf, owner, old, new, extack);
+ if (err) {
+ NL_SET_ERR_MSG_FMT(extack, "failed to change RSS LUT, err: %d", err);
+ if (!take)
+ /* We have not released the resource, so we don't free
+ * it, to avoid freeing LUT still in use or assigning it
+ * to other entity.
+ */
+ return -EBUSY;
+
+ goto undo_res_take;
+ }
+
+ if (!take) {
+undo_res_take:
+ int rel_err;
+
+ rel_err = ice_devl_res_free(pf, res_id, owner);
+ if (rel_err) {
+ NL_SET_ERR_MSG_FMT(extack,
+ "could not free resource, err: %d", rel_err);
+ if (!err)
+ err = rel_err;
+ }
+ }
+
+ return err;
+}
+
+static int ice_rss_lut_pf_occ_set_pf(u64 size, struct netlink_ext_ack *extack,
+ void *priv)
+{
+ struct ice_pf *pf = priv;
+ int pf_id = pf->hw.pf_id;
+
+ scoped_guard(ice_adapter_devl, pf->adapter)
+ return ice_devl_res_change(size, ICE_RSS_LUT_PF, pf, pf, pf_id,
+ extack);
+}
+
+static int ice_rss_lut_pf_occ_set_global(u64 size,
+ struct netlink_ext_ack *extack,
+ void *priv)
+{
+ struct ice_pf *pf = priv;
+
+ scoped_guard(ice_adapter_devl, pf->adapter)
+ return ice_devl_res_change(size, ICE_RSS_LUT_GLOBAL, pf, pf,
+ ICE_ANY_SLOT, extack);
+}
+
+/**
+ * ice_take_rss_lut_pf - allocate PF RSS LUT for PF
+ * @pf: the PF device that PF LUT is physically on, and to allocate it for
+ *
+ * Acquire PF RSS LUT for the caller.
+ *
+ * Return: 0 on success, negative on error.
+ */
+int ice_take_rss_lut_pf(struct ice_pf *pf)
+{
+ int ret, pf_id = pf->hw.pf_id;
+
+ scoped_guard(ice_adapter_devl, pf->adapter) {
+ ret = ice_devl_res_take(pf, ICE_RSS_LUT_PF, pf_id, pf);
+ if (ret >= 0)
+ return 0;
+
+ return ret;
+ }
+}
+
+static void ice_devl_res_register(struct devlink *devlink,
+ struct ice_devl_resource *resources,
+ void *occ_priv)
+{
+ struct devlink_resource_size_params size_params;
+
+ devlink_resource_size_params_init(&size_params, 0, 0, 1,
+ DEVLINK_RESOURCE_UNIT_ENTRY);
+ for (int i = 0; i < ICE_DEVL_RESOURCES_COUNT; i++) {
+ struct ice_devl_resource *res = &resources[i];
+ int err, resource_id = i;
+
+ if (!res->name)
+ continue; /* skip empty entries in config table */
+
+ size_params.size_max = res->max_size;
+ err = devl_resource_register(devlink, res->name,
+ res->start_size, resource_id,
+ res->parent_id, &size_params);
+ if (WARN_ONCE(err, "not all resource handlers registered, err: %d, resname: %s\n",
+ err, res->name))
+ break;
+
+ devl_resource_occ_set_get_register(devlink, resource_id,
+ res->set, res->get, occ_priv);
+ }
+}
+
+void ice_devl_whole_dev_resources_register(const struct ice_hw *hw,
+ struct ice_adapter *adapter)
+{
+ struct devlink *devlink = adapter->devlink;
+ int pf_lut_cnt = hw->dev_caps.num_funcs;
+
+ devl_assert_locked(devlink);
+
+ adapter->resources[ICE_RSS_LUT_GLOBAL] = (struct ice_devl_resource) {
+ .name = "lut_512",
+ .parent_id = ICE_RSS_LUT_BOTH,
+ .max_size = ICE_NUM_GLOBAL_LUTS,
+ .get = ice_rss_lut_whole_dev_occ_get_global,
+ .set = ice_devl_resource_deny_occ_set,
+ };
+ adapter->resources[ICE_RSS_LUT_PF] = (struct ice_devl_resource) {
+ .name = "lut_2048",
+ .parent_id = ICE_RSS_LUT_BOTH,
+ .max_size = pf_lut_cnt,
+ .get = ice_rss_lut_whole_dev_occ_get_pf,
+ .set = ice_devl_resource_deny_occ_set,
+ };
+ adapter->resources[ICE_RSS_LUT_BOTH] = (struct ice_devl_resource) {
+ .name = "rss",
+ .parent_id = ICE_TOP_RESOURCE,
+ .max_size = pf_lut_cnt + ICE_NUM_GLOBAL_LUTS,
+ .get = ice_rss_lut_whole_dev_occ_get_both,
+ .set = ice_devl_resource_deny_occ_set,
+ };
+
+ ice_devl_res_register(devlink, adapter->resources, adapter);
+}
+
+void ice_devl_pf_resources_register(struct ice_pf *pf)
+{
+ struct ice_devl_resource pf_resources[ICE_DEVL_RESOURCES_COUNT] = {
+ [ICE_RSS_LUT_GLOBAL] = {
+ .name = "lut_512",
+ .parent_id = ICE_RSS_LUT_BOTH,
+ .max_size = 1,
+ .get = ice_rss_lut_pf_occ_get_global,
+ .set = ice_rss_lut_pf_occ_set_global,
+ },
+ [ICE_RSS_LUT_PF] = {
+ .name = "lut_2048",
+ .parent_id = ICE_RSS_LUT_BOTH,
+ .max_size = 1,
+ .get = ice_rss_lut_pf_occ_get_pf,
+ .set = ice_rss_lut_pf_occ_set_pf,
+ .start_size = 1,
+ },
+ [ICE_RSS_LUT_BOTH] = {
+ .name = "rss",
+ .parent_id = ICE_TOP_RESOURCE,
+ .max_size = 2,
+ .get = ice_rss_lut_pf_occ_get_both,
+ .set = ice_devl_resource_deny_occ_set,
+ },
+ };
+ struct devlink *devlink = priv_to_devlink(pf);
+
+ devl_assert_locked(devlink);
+ ice_devl_res_register(devlink, pf_resources, pf);
+}
diff --git a/drivers/net/ethernet/intel/ice/ice_adapter.c b/drivers/net/ethernet/intel/ice/ice_adapter.c
index d07d349a1692..064cf649714d 100644
--- a/drivers/net/ethernet/intel/ice/ice_adapter.c
+++ b/drivers/net/ethernet/intel/ice/ice_adapter.c
@@ -8,6 +8,8 @@
#include "ice_adapter.h"
#include "ice.h"
+#include "devlink/resource.h"
+
#define ICE_ADAPTER_FIXED_INDEX BIT_ULL(63)
#define ICE_ADAPTER_INDEX_E825C \
@@ -37,6 +39,7 @@ static u64 ice_adapter_index(struct pci_dev *pdev)
static int ice_adapter_init(void *priv, void *init_param)
{
+ const struct ice_hw *hw = init_param;
struct ice_adapter *adapter = priv;
struct devlink *devlink;
@@ -49,12 +52,18 @@ static int ice_adapter_init(void *priv, void *init_param)
mutex_init(&adapter->ports.lock);
INIT_LIST_HEAD(&adapter->ports.ports);
+ ice_devl_whole_dev_resources_register(hw, adapter);
+
return 0;
}
static void ice_adapter_fini(void *priv)
{
struct ice_adapter *adapter = priv;
+ struct devlink *devlink;
+
+ devlink = shd_priv_to_devlink(adapter);
+ devl_resources_unregister(devlink);
WARN_ON(!list_empty(&adapter->ports.ports));
mutex_destroy(&adapter->ports.lock);
@@ -80,15 +89,16 @@ static const struct devlink_ops ice_adapter_devlink_ops = {
*/
struct ice_adapter *ice_adapter_get(struct pci_dev *pdev)
{
+ struct ice_pf *pf = pci_get_drvdata(pdev);
struct ice_adapter *adapter;
struct devlink *devlink;
char devlink_id[32];
u64 index;
index = ice_adapter_index(pdev);
snprintf(devlink_id, sizeof(devlink_id), "%llx", index);
devlink = devlink_shd_get(devlink_id, &ice_adapter_devlink_ops,
- sizeof(*adapter), NULL, pdev->dev.driver);
+ sizeof(*adapter), &pf->hw, pdev->dev.driver);
if (!devlink)
return ERR_PTR(-ENOMEM);
diff --git a/drivers/net/ethernet/intel/ice/ice_common.c b/drivers/net/ethernet/intel/ice/ice_common.c
index 168890986696..41eae7b0a3db 100644
--- a/drivers/net/ethernet/intel/ice/ice_common.c
+++ b/drivers/net/ethernet/intel/ice/ice_common.c
@@ -4514,7 +4514,7 @@ ice_aq_sff_eeprom(struct ice_hw *hw, u16 lport, u8 bus_addr,
return status;
}
-static enum ice_lut_size ice_lut_type_to_size(enum ice_lut_type type)
+enum ice_lut_size ice_lut_type_to_size(enum ice_lut_type type)
{
switch (type) {
case ICE_LUT_VSI:
diff --git a/drivers/net/ethernet/intel/ice/ice_lib.c b/drivers/net/ethernet/intel/ice/ice_lib.c
index 2ac4e23f30b5..e47f2f881701 100644
--- a/drivers/net/ethernet/intel/ice/ice_lib.c
+++ b/drivers/net/ethernet/intel/ice/ice_lib.c
@@ -10,6 +10,8 @@
#include "ice_type.h"
#include "ice_vsi_vlan_ops.h"
+#include "devlink/resource.h"
+
/**
* ice_vsi_type_str - maps VSI type enum to string equivalents
* @vsi_type: VSI type enum
@@ -885,10 +887,10 @@ static void ice_rss_clean(struct ice_vsi *vsi)
}
/**
- * ice_vsi_set_rss_params - Setup RSS capabilities per VSI type
+ * ice_vsi_set_dflt_rss_params - Setup default RSS capabilities per VSI type
* @vsi: the VSI being configured
*/
-static void ice_vsi_set_rss_params(struct ice_vsi *vsi)
+static void ice_vsi_set_dflt_rss_params(struct ice_vsi *vsi)
{
struct ice_hw_common_caps *cap;
struct ice_pf *pf = vsi->back;
@@ -2352,6 +2354,9 @@ static int ice_vsi_cfg_def(struct ice_vsi *vsi)
vsi->vsw = pf->first_sw;
+ if (vsi->flags & ICE_VSI_FLAG_INIT)
+ ice_vsi_set_dflt_rss_params(vsi);
+
ret = ice_vsi_alloc_def(vsi, vsi->ch);
if (ret)
return ret;
@@ -2371,7 +2376,14 @@ static int ice_vsi_cfg_def(struct ice_vsi *vsi)
}
/* set RSS capabilities */
- ice_vsi_set_rss_params(vsi);
+ if ((vsi->flags & ICE_VSI_FLAG_INIT) && vsi->type == ICE_VSI_PF) {
+ ret = ice_take_rss_lut_pf(pf);
+ if (ret) {
+ dev_err(dev, "Failed to allocate RSS LUT for PF: %d\n",
+ ret);
+ goto unroll_vsi_alloc_stat;
+ }
+ }
/* set TC configuration */
ice_vsi_set_tc_cfg(vsi);
@@ -2559,6 +2571,11 @@ void ice_vsi_decfg(struct ice_vsi *vsi)
ice_vsi_put_qs(vsi);
ice_vsi_free_arrays(vsi);
+ if (vsi->flags & ICE_VSI_FLAG_INIT) {
+ if (vsi->type == ICE_VSI_PF)
+ ice_free_rss_lut_flr(pf);
+ }
+
/* SR-IOV determines needed MSIX resources all at once instead of per
* VSI since when VFs are spawned we know how many VFs there are and how
* many interrupts each VF needs. SR-IOV MSIX resources are also
diff --git a/drivers/net/ethernet/intel/ice/ice_main.c b/drivers/net/ethernet/intel/ice/ice_main.c
index 42d9c4220f43..94232f4a45ad 100644
--- a/drivers/net/ethernet/intel/ice/ice_main.c
+++ b/drivers/net/ethernet/intel/ice/ice_main.c
@@ -15,6 +15,7 @@
#include "ice_dcb_nl.h"
#include "devlink/devlink.h"
#include "devlink/port.h"
+#include "devlink/resource.h"
#include "ice_sf_eth.h"
#include "ice_hwmon.h"
#include "ice_acl.h"
@@ -5037,6 +5038,7 @@ static int ice_init_devlink(struct ice_pf *pf)
ice_devlink_init_regions(pf);
ice_devlink_register(pf);
ice_health_init(pf);
+ ice_devl_pf_resources_register(pf);
return 0;
}
@@ -5047,6 +5049,7 @@ static void ice_deinit_devlink(struct ice_pf *pf)
ice_devlink_unregister(pf);
ice_devlink_destroy_regions(pf);
ice_devlink_unregister_params(pf);
+ devl_resources_unregister(priv_to_devlink(pf));
}
static int ice_init(struct ice_pf *pf)
@@ -7972,6 +7975,8 @@ int ice_set_rss_lut(struct ice_vsi *vsi, u8 *lut, u16 lut_size)
params.lut_size = lut_size;
params.lut_type = vsi->rss_lut_type;
params.lut = lut;
+ if (params.lut_type == ICE_LUT_GLOBAL)
+ params.global_lut_id = vsi->global_lut_id;
status = ice_aq_set_rss_lut(hw, ¶ms);
if (status)
@@ -8025,11 +8030,14 @@ int ice_get_rss_lut(struct ice_vsi *vsi, u8 *lut, u16 lut_size)
params.lut_size = lut_size;
params.lut_type = vsi->rss_lut_type;
params.lut = lut;
+ if (params.lut_type == ICE_LUT_GLOBAL)
+ params.global_lut_id = vsi->global_lut_id;
status = ice_aq_get_rss_lut(hw, ¶ms);
- if (status)
- dev_err(ice_pf_to_dev(vsi->back), "Cannot get RSS lut, err %d aq_err %s\n",
- status, libie_aq_str(hw->adminq.sq_last_status));
+ if (status) {
+ dev_err(ice_pf_to_dev(vsi->back), "Cannot get RSS lut, err %d aq_err %s, luttype: %d\n",
+ status, libie_aq_str(hw->adminq.sq_last_status), params.lut_type);
+ }
return status;
}
--
2.39.3
^ permalink raw reply related [flat|nested] 28+ messages in thread* RE: [PATCH iwl-next v1 14/15] ice: represent RSS LUTs as devlink resources
2026-05-08 12:42 ` [PATCH iwl-next v1 14/15] ice: represent RSS LUTs as devlink resources Przemek Kitszel
@ 2026-05-08 17:03 ` Loktionov, Aleksandr
2026-05-11 9:41 ` Przemek Kitszel
0 siblings, 1 reply; 28+ messages in thread
From: Loktionov, Aleksandr @ 2026-05-08 17:03 UTC (permalink / raw)
To: Kitszel, Przemyslaw, intel-wired-lan@lists.osuosl.org,
Schmidt, Michal, Jakub Kicinski, Jiri Pirko
Cc: netdev@vger.kernel.org, Simon Horman, Nguyen, Anthony L,
Michal Swiatkowski, Richardson, Bruce, Medvedkin, Vladimir,
Connolly, Padraig J, S, Ananth, Miskell, Timothy, Keller, Jacob E,
Czapnik, Lukasz, Andrew Lunn, David S. Miller, Eric Dumazet,
Paolo Abeni, Saeed Mahameed, Leon Romanovsky, Tariq Toukan,
Mark Bloch
> -----Original Message-----
> From: Kitszel, Przemyslaw <przemyslaw.kitszel@intel.com>
> Sent: Friday, May 8, 2026 2:42 PM
> To: intel-wired-lan@lists.osuosl.org; Schmidt, Michal
> <mschmidt@redhat.com>; Jakub Kicinski <kuba@kernel.org>; Jiri Pirko
> <jiri@resnulli.us>
> Cc: netdev@vger.kernel.org; Simon Horman <horms@kernel.org>; Nguyen,
> Anthony L <anthony.l.nguyen@intel.com>; Michal Swiatkowski
> <michal.swiatkowski@linux.intel.com>; Richardson, Bruce
> <bruce.richardson@intel.com>; Medvedkin, Vladimir
> <vladimir.medvedkin@intel.com>; Connolly, Padraig J
> <padraig.j.connolly@intel.com>; S, Ananth <ananth.s@intel.com>;
> Miskell, Timothy <timothy.miskell@intel.com>; Keller, Jacob E
> <jacob.e.keller@intel.com>; Czapnik, Lukasz
> <lukasz.czapnik@intel.com>; Loktionov, Aleksandr
> <aleksandr.loktionov@intel.com>; Andrew Lunn <andrew+netdev@lunn.ch>;
> David S. Miller <davem@davemloft.net>; Eric Dumazet
> <edumazet@google.com>; Paolo Abeni <pabeni@redhat.com>; Saeed Mahameed
> <saeedm@nvidia.com>; Leon Romanovsky <leon@kernel.org>; Tariq Toukan
> <tariqt@nvidia.com>; Mark Bloch <mbloch@nvidia.com>; Kitszel,
> Przemyslaw <przemyslaw.kitszel@intel.com>
> Subject: [PATCH iwl-next v1 14/15] ice: represent RSS LUTs as devlink
> resources
>
> E800 family offers three kinds of RSS LUTs: VSI LUT (sized 64), GLOBAL
> LUT (sized 256), and PF LUT (sized 2048). Until now the GLOBAL kind
> was not used at all. There are two possible usages for it, subsequent
> commit will give VF option to acquire it, and this one enables PF to
> switch between PF LUT and GLOBAL LUT - switching to smaller one is,
> again, to make it possible for VF to then acquire the former one.
>
> Devlink resources are used to let user show current usage and change
> the allocation, see examples below.
>
> Default state on 8-port card, asking for aggregate "whole device"
> usage, note that there are as many PF LUTs as there is PFs, and, for
> e810, there are 16 GLOBAL LUTs:
> $ devlink resource show devlink_index/11
> devlink_index/11:
> name rss size 8 unit entry size_min 0 size_max 24 size_gran 1
> dpipe_tables none
> resources:
> name lut_512 size 0 unit entry size_min 0 size_max 16 size_gran
> 1 dpipe_tables none
> name lut_2048 size 8 unit entry size_min 0 size_max 8 size_gran
> 1 dpipe_tables none
>
> Now let's add GLOBAL LUT for a single PF (on one-port NIC):
> $ sudo devlink resource set pci/0000:18:00.0 path rss/lut_512 size 1
> And show it's resources after that:
> $ devlink resource show pci/0000:18:00.0
> pci/0000:18:00.0:
> name rss size 2 unit entry size_min 0 size_max 2 size_gran 1
> dpipe_tables none
> resources:
> name lut_512 size 1 unit entry size_min 0 size_max 1 size_gran 1
> dpipe_tables none
> name lut_2048 size 1 unit entry size_min 0 size_max 1 size_gran
> 1 dpipe_tables none Let's take the PF LUT out of that PF afterwards:
> $ sudo devlink resource set pci/0000:18:00.0 path rss/lut_2048 size 0
> now `ethtool -x $ifacename` will report smaller RSS table.
>
> Signed-off-by: Przemek Kitszel <przemyslaw.kitszel@intel.com>
> ---
> drivers/net/ethernet/intel/ice/Makefile | 1 +
> .../net/ethernet/intel/ice/devlink/resource.h | 19 +
> drivers/net/ethernet/intel/ice/ice_adapter.h | 40 ++
> drivers/net/ethernet/intel/ice/ice_common.h | 1 +
> .../net/ethernet/intel/ice/devlink/resource.c | 469
> ++++++++++++++++++ drivers/net/ethernet/intel/ice/ice_adapter.c |
> 12 +-
> drivers/net/ethernet/intel/ice/ice_common.c | 2 +-
> drivers/net/ethernet/intel/ice/ice_lib.c | 23 +-
> drivers/net/ethernet/intel/ice/ice_main.c | 14 +-
> 9 files changed, 573 insertions(+), 8 deletions(-) create mode
> 100644 drivers/net/ethernet/intel/ice/devlink/resource.h
> create mode 100644 drivers/net/ethernet/intel/ice/devlink/resource.c
>
> diff --git a/drivers/net/ethernet/intel/ice/Makefile
> b/drivers/net/ethernet/intel/ice/Makefile
> index 7f06d9bafe4a..0217ab6403de 100644
> --- a/drivers/net/ethernet/intel/ice/Makefile
> +++ b/drivers/net/ethernet/intel/ice/Makefile
> @@ -37,6 +37,7 @@ ice-y := ice_main.o \
> devlink/devlink.o \
> devlink/health.o \
> devlink/port.o \
...
> +
> +static int ice_devl_res_take(struct ice_pf *pf,
> + enum ice_devl_resource_id res_id, int slot,
> + void *owner)
> +{
> + struct ice_devl_resource *res = &pf->adapter-
> >resources[res_id];
> + int end = slot == ICE_ANY_SLOT ? res->max_size : slot + 1;
> + int beg = slot == ICE_ANY_SLOT ? 0 : slot;
> + int err, new_id = ICE_ANY_SLOT;
> +
> + for (int id = beg; id < end; id++) {
> + if (!res->owner[id]) {
> + new_id = id;
> + break;
> + }
> + }
> + if (new_id == ICE_ANY_SLOT)
> + return -ENOSPC;
> +
> + if (res_id == ICE_RSS_LUT_GLOBAL) {
> + struct ice_vsi *vsi;
> + u16 lut_id;
> +
> + err = ice_alloc_rss_global_lut(&pf->hw, &lut_id);
> + if (err)
> + return err;
> + if (lut_id != new_id)
> + return -ENOANO;
-ENOANO; looks for me very unusual choice.
BTW won't LUT leak without calling ice_free_rss_global_lut() ?
> +
> + if (pf == owner)
> + vsi = ice_get_main_vsi(pf);
> + else
> + vsi = ice_get_vf_vsi(owner);
> +
> + vsi->global_lut_id = new_id;
> + }
> +
> + res->owner[new_id] = owner;
> + res->pf_id[new_id] = pf->hw.pf_id;
> + return new_id;
> +}
...
>
> return status;
> }
> --
> 2.39.3
^ permalink raw reply [flat|nested] 28+ messages in thread* Re: [PATCH iwl-next v1 14/15] ice: represent RSS LUTs as devlink resources
2026-05-08 17:03 ` Loktionov, Aleksandr
@ 2026-05-11 9:41 ` Przemek Kitszel
0 siblings, 0 replies; 28+ messages in thread
From: Przemek Kitszel @ 2026-05-11 9:41 UTC (permalink / raw)
To: Loktionov, Aleksandr, intel-wired-lan@lists.osuosl.org
Cc: netdev@vger.kernel.org, Simon Horman, Nguyen, Anthony L,
Michal Swiatkowski, Richardson, Bruce, Medvedkin, Vladimir,
Connolly, Padraig J, S, Ananth, Miskell, Timothy, Keller, Jacob E,
Czapnik, Lukasz, Andrew Lunn, David S. Miller, Eric Dumazet,
Paolo Abeni, Saeed Mahameed, Leon Romanovsky, Tariq Toukan,
Mark Bloch, Schmidt, Michal, Jakub Kicinski, Jiri Pirko
On 5/8/26 19:03, Loktionov, Aleksandr wrote:
>
>
>> -----Original Message-----
>> From: Kitszel, Przemyslaw <przemyslaw.kitszel@intel.com>
>> Sent: Friday, May 8, 2026 2:42 PM
>> To: intel-wired-lan@lists.osuosl.org; Schmidt, Michal
>> <mschmidt@redhat.com>; Jakub Kicinski <kuba@kernel.org>; Jiri Pirko
>> <jiri@resnulli.us>
>> Cc: netdev@vger.kernel.org; Simon Horman <horms@kernel.org>; Nguyen,
>> Anthony L <anthony.l.nguyen@intel.com>; Michal Swiatkowski
>> <michal.swiatkowski@linux.intel.com>; Richardson, Bruce
>> <bruce.richardson@intel.com>; Medvedkin, Vladimir
>> <vladimir.medvedkin@intel.com>; Connolly, Padraig J
>> <padraig.j.connolly@intel.com>; S, Ananth <ananth.s@intel.com>;
>> Miskell, Timothy <timothy.miskell@intel.com>; Keller, Jacob E
>> <jacob.e.keller@intel.com>; Czapnik, Lukasz
>> <lukasz.czapnik@intel.com>; Loktionov, Aleksandr
>> <aleksandr.loktionov@intel.com>; Andrew Lunn <andrew+netdev@lunn.ch>;
>> David S. Miller <davem@davemloft.net>; Eric Dumazet
>> <edumazet@google.com>; Paolo Abeni <pabeni@redhat.com>; Saeed Mahameed
>> <saeedm@nvidia.com>; Leon Romanovsky <leon@kernel.org>; Tariq Toukan
>> <tariqt@nvidia.com>; Mark Bloch <mbloch@nvidia.com>; Kitszel,
>> Przemyslaw <przemyslaw.kitszel@intel.com>
>> Subject: [PATCH iwl-next v1 14/15] ice: represent RSS LUTs as devlink
>> resources
>>
>> E800 family offers three kinds of RSS LUTs: VSI LUT (sized 64), GLOBAL
>> LUT (sized 256), and PF LUT (sized 2048). Until now the GLOBAL kind
>> was not used at all. There are two possible usages for it, subsequent
>> commit will give VF option to acquire it, and this one enables PF to
>> switch between PF LUT and GLOBAL LUT - switching to smaller one is,
>> again, to make it possible for VF to then acquire the former one.
>>
>> Devlink resources are used to let user show current usage and change
>> the allocation, see examples below.
>>
>> Default state on 8-port card, asking for aggregate "whole device"
>> usage, note that there are as many PF LUTs as there is PFs, and, for
>> e810, there are 16 GLOBAL LUTs:
>> $ devlink resource show devlink_index/11
>> devlink_index/11:
>> name rss size 8 unit entry size_min 0 size_max 24 size_gran 1
>> dpipe_tables none
>> resources:
>> name lut_512 size 0 unit entry size_min 0 size_max 16 size_gran
>> 1 dpipe_tables none
>> name lut_2048 size 8 unit entry size_min 0 size_max 8 size_gran
>> 1 dpipe_tables none
>>
>> Now let's add GLOBAL LUT for a single PF (on one-port NIC):
>> $ sudo devlink resource set pci/0000:18:00.0 path rss/lut_512 size 1
>> And show it's resources after that:
>> $ devlink resource show pci/0000:18:00.0
>> pci/0000:18:00.0:
>> name rss size 2 unit entry size_min 0 size_max 2 size_gran 1
>> dpipe_tables none
>> resources:
>> name lut_512 size 1 unit entry size_min 0 size_max 1 size_gran 1
>> dpipe_tables none
>> name lut_2048 size 1 unit entry size_min 0 size_max 1 size_gran
>> 1 dpipe_tables none Let's take the PF LUT out of that PF afterwards:
>> $ sudo devlink resource set pci/0000:18:00.0 path rss/lut_2048 size 0
>> now `ethtool -x $ifacename` will report smaller RSS table.
>>
>> Signed-off-by: Przemek Kitszel <przemyslaw.kitszel@intel.com>
>> ---
>> drivers/net/ethernet/intel/ice/Makefile | 1 +
>> .../net/ethernet/intel/ice/devlink/resource.h | 19 +
>> drivers/net/ethernet/intel/ice/ice_adapter.h | 40 ++
>> drivers/net/ethernet/intel/ice/ice_common.h | 1 +
>> .../net/ethernet/intel/ice/devlink/resource.c | 469
>> ++++++++++++++++++ drivers/net/ethernet/intel/ice/ice_adapter.c |
>> 12 +-
>> drivers/net/ethernet/intel/ice/ice_common.c | 2 +-
>> drivers/net/ethernet/intel/ice/ice_lib.c | 23 +-
>> drivers/net/ethernet/intel/ice/ice_main.c | 14 +-
>> 9 files changed, 573 insertions(+), 8 deletions(-) create mode
>> 100644 drivers/net/ethernet/intel/ice/devlink/resource.h
>> create mode 100644 drivers/net/ethernet/intel/ice/devlink/resource.c
>>
>> diff --git a/drivers/net/ethernet/intel/ice/Makefile
>> b/drivers/net/ethernet/intel/ice/Makefile
>> index 7f06d9bafe4a..0217ab6403de 100644
>> --- a/drivers/net/ethernet/intel/ice/Makefile
>> +++ b/drivers/net/ethernet/intel/ice/Makefile
>> @@ -37,6 +37,7 @@ ice-y := ice_main.o \
>> devlink/devlink.o \
>> devlink/health.o \
>> devlink/port.o \
>
> ...
>
>> +
>> +static int ice_devl_res_take(struct ice_pf *pf,
>> + enum ice_devl_resource_id res_id, int slot,
>> + void *owner)
>> +{
>> + struct ice_devl_resource *res = &pf->adapter-
>>> resources[res_id];
>> + int end = slot == ICE_ANY_SLOT ? res->max_size : slot + 1;
>> + int beg = slot == ICE_ANY_SLOT ? 0 : slot;
>> + int err, new_id = ICE_ANY_SLOT;
>> +
>> + for (int id = beg; id < end; id++) {
>> + if (!res->owner[id]) {
>> + new_id = id;
>> + break;
>> + }
>> + }
>> + if (new_id == ICE_ANY_SLOT)
>> + return -ENOSPC;
>> +
>> + if (res_id == ICE_RSS_LUT_GLOBAL) {
>> + struct ice_vsi *vsi;
>> + u16 lut_id;
>> +
>> + err = ice_alloc_rss_global_lut(&pf->hw, &lut_id);
>> + if (err)
>> + return err;
>> + if (lut_id != new_id)
>> + return -ENOANO;
> -ENOANO; looks for me very unusual choice.
> BTW won't LUT leak without calling ice_free_rss_global_lut() ?
I will replace it by WARN_ONCE() and just let use the ID we were
assigned by FW
>
>> +
>> + if (pf == owner)
>> + vsi = ice_get_main_vsi(pf);
>> + else
>> + vsi = ice_get_vf_vsi(owner);
>> +
>> + vsi->global_lut_id = new_id;
>> + }
>> +
>> + res->owner[new_id] = owner;
>> + res->pf_id[new_id] = pf->hw.pf_id;
>> + return new_id;
>> +}
>
> ...
>
>>
>> return status;
>> }
>> --
>> 2.39.3
>
^ permalink raw reply [flat|nested] 28+ messages in thread
* [PATCH iwl-next v1 15/15] ice: support up to 256 VF queues
2026-05-08 12:41 [PATCH iwl-next v1 00/15] devlink, mlx5, iavf, ice: XLVF for iavf Przemek Kitszel
` (13 preceding siblings ...)
2026-05-08 12:42 ` [PATCH iwl-next v1 14/15] ice: represent RSS LUTs as devlink resources Przemek Kitszel
@ 2026-05-08 12:42 ` Przemek Kitszel
14 siblings, 0 replies; 28+ messages in thread
From: Przemek Kitszel @ 2026-05-08 12:42 UTC (permalink / raw)
To: intel-wired-lan, Michal Schmidt, Jakub Kicinski, Jiri Pirko
Cc: netdev, Simon Horman, Tony Nguyen, Michal Swiatkowski,
bruce.richardson, Vladimir Medvedkin, padraig.j.connolly,
ananth.s, timothy.miskell, Jacob Keller, Lukasz Czapnik,
Aleksandr Loktionov, Andrew Lunn, David S. Miller, Eric Dumazet,
Paolo Abeni, Saeed Mahameed, Leon Romanovsky, Tariq Toukan,
Mark Bloch, Przemek Kitszel, Jedrzej Jagielski
Add support for up to 256 VF queues. To enable more than usual 16, user
needs to assign GLOBAL LUT (devlink resource named "rss/lut_512") for 64
queues or PF LUT (name "rss/lut_2048") for maximum of 256 queues. There is
a need to assign the GLOBAL LUT to PF first, then release the PF LUT
(initially assigned to PF) from PF, to finally assign it to VF, see
examples further below. Usual default of number of CPU cores does still
apply, but queues could be requested later by usual ethtool -L command.
Add devlink instance of VF device to track RSS LUT resources under
a respective PF devlink instance.
Number of MSI-X vectors assigned to VF is orthogonal to this.
Note that VF reset is deferred to service task.
How to use:
1. Up to 64 queues
a. assign one of 16 GLOBAL LUTs to VF:
sudo devlink resource set pci/0000:18:01.0 path rss/lut_512 size 1
b. if more queues than the default (num of vCPU/CPU cores) are wanted:
sudo ethtool -L $vfiface combined $more
2. Up to 256 queues
a. assign a GLOBAL LUT to PF:
sudo devlink resource set pci/0000:18:00.0 path rss/lut_512 size 1
b. free the PF LUT from PF:
sudo devlink resource set pci/0000:18:00.0 path rss/lut_2048 size 0
c. assign the PF LUT to VF:
sudo devlink resource set pci/0000:18:01.0 path rss/lut_2048 size 1
d. if more queues than the default (num of vCPU/CPU cores) are wanted:
sudo ethtool -L $vfiface combined $more
3. display current RSS LUT or RSS table:
a. see if RSS is mapped correctly (e.g. for lut_512 there are 512
entries expected):
ethtool -x $vfiface
b. see what devlink devices are present:
devlink dev show # note the "faux" device over your pci netdevs
c. see PF, VF, and "whole device aggregate" (faux) resources:
devlink resource show pci/0000:18:00.0 # PF
devlink resource show pci/0000:18:01.0 # VF
devlink resource show faux/ice-90-cf-4c-ff-ff-6f-7c-50 # whole dev
output will look like: below, for device with 1 of PF and GLOBAL LUTs:
pci/0000:18:00.0:
name rss size 2 unit entry size_min 0 size_max 2 size_gran 1 dpipe_tables none
resources:
name lut_512 size 1 unit entry size_min 0 size_max 1 size_gran 1 dpipe_tables none
name lut_2048 size 1 unit entry size_min 0 size_max 1 size_gran 1 dpipe_tables none
Big thanks to Mateusz for working together on the whole story for long
time! Big thanks to Alex Loktionov for pointing the reason of one nasty
bug with the message size!
Co-developed-by: Mateusz Polchlopek <mateusz.polchlopek@intel.com>
Signed-off-by: Mateusz Polchlopek <mateusz.polchlopek@intel.com>
Signed-off-by: Aleksandr Loktionov <aleksandr.loktionov@intel.com>
Reviewed-by: Jedrzej Jagielski <jedrzej.jagielski@intel.com>
Signed-off-by: Przemek Kitszel <przemyslaw.kitszel@intel.com>
---
.../net/ethernet/intel/ice/devlink/resource.h | 3 +
drivers/net/ethernet/intel/ice/ice_lib.h | 5 +-
drivers/net/ethernet/intel/ice/ice_vf_lib.h | 13 +++
| 1 +
.../net/ethernet/intel/ice/virt/virtchnl.h | 4 +
.../net/ethernet/intel/ice/devlink/resource.c | 105 +++++++++++++++++-
drivers/net/ethernet/intel/ice/ice_lib.c | 27 ++++-
drivers/net/ethernet/intel/ice/ice_main.c | 25 +++++
drivers/net/ethernet/intel/ice/ice_sriov.c | 10 ++
drivers/net/ethernet/intel/ice/ice_vf_lib.c | 42 +++++++
| 36 +++++-
.../net/ethernet/intel/ice/virt/virtchnl.c | 47 +++++++-
12 files changed, 305 insertions(+), 13 deletions(-)
diff --git a/drivers/net/ethernet/intel/ice/devlink/resource.h b/drivers/net/ethernet/intel/ice/devlink/resource.h
index 947f77a3cd49..9c6c97e2e62d 100644
--- a/drivers/net/ethernet/intel/ice/devlink/resource.h
+++ b/drivers/net/ethernet/intel/ice/devlink/resource.h
@@ -8,12 +8,15 @@ struct devlink;
struct ice_adapter;
struct ice_hw;
struct ice_pf;
+struct ice_vf;
+void ice_devlink_vf_resources_register(struct ice_vf *vf);
void ice_devl_pf_resources_register(struct ice_pf *pf);
void ice_devl_whole_dev_resources_register(const struct ice_hw *hw,
struct ice_adapter *adapter);
int ice_take_rss_lut_pf(struct ice_pf *pf);
void ice_free_rss_lut_flr(struct ice_pf *pf);
+void ice_free_rss_lut_vf(struct ice_vf *vf);
#endif /* _ICE_DEVL_RESOURCE_H_ */
diff --git a/drivers/net/ethernet/intel/ice/ice_lib.h b/drivers/net/ethernet/intel/ice/ice_lib.h
index 54377c797bac..76efea676583 100644
--- a/drivers/net/ethernet/intel/ice/ice_lib.h
+++ b/drivers/net/ethernet/intel/ice/ice_lib.h
@@ -8,16 +8,19 @@
#include "ice_vlan.h"
/* Flags used for VSI configuration and rebuild */
-#define ICE_VSI_FLAG_INIT BIT(0)
#define ICE_VSI_FLAG_NO_INIT 0
+#define ICE_VSI_FLAG_INIT BIT(0)
+#define ICE_VSI_FLAG_RELOAD BIT(1) /* devlink reload action */
#define ICE_L2TSEL_QRX_CONTEXT_REG_IDX 3
#define ICE_L2TSEL_BIT_OFFSET 23
enum ice_l2tsel {
ICE_L2TSEL_EXTRACT_FIRST_TAG_L2TAG2_2ND,
ICE_L2TSEL_EXTRACT_FIRST_TAG_L2TAG1,
};
+u16 ice_lut_type_to_qs_num(enum ice_lut_type lut_type);
+
const char *ice_vsi_type_str(enum ice_vsi_type vsi_type);
bool ice_pf_state_is_nominal(struct ice_pf *pf);
diff --git a/drivers/net/ethernet/intel/ice/ice_vf_lib.h b/drivers/net/ethernet/intel/ice/ice_vf_lib.h
index 5411eaa1761c..397e1fa00dbc 100644
--- a/drivers/net/ethernet/intel/ice/ice_vf_lib.h
+++ b/drivers/net/ethernet/intel/ice/ice_vf_lib.h
@@ -145,6 +145,7 @@ struct ice_vf {
struct kref refcnt;
struct ice_pf *pf;
struct pci_dev *vfdev;
+ struct devlink *devlink;
/* Used during virtchnl message handling and NDO ops against the VF
* that will trigger a VFR
*/
@@ -175,6 +176,7 @@ struct ice_vf {
u8 link_forced:1;
u8 link_up:1; /* only valid if VF link is forced */
u8 lldp_tx_ena:1;
+ u8 needs_deferred_reset:1;
u16 num_msix; /* num of MSI-X configured on this VF */
@@ -320,9 +322,12 @@ int
ice_vf_clear_vsi_promisc(struct ice_vf *vf, struct ice_vsi *vsi, u8 promisc_m);
int ice_reset_vf(struct ice_vf *vf, u32 flags);
void ice_reset_all_vfs(struct ice_pf *pf);
+void ice_schedule_vf_reset(struct ice_vf *vf);
struct ice_vsi *ice_get_vf_ctrl_vsi(struct ice_pf *pf, struct ice_vsi *vsi);
void ice_vf_update_mac_lldp_num(struct ice_vf *vf, struct ice_vsi *vsi,
bool incr);
+void ice_init_vf_devlink(struct ice_vf *vf);
+void ice_deinit_vf_devlink(struct ice_vf *vf);
#else /* CONFIG_PCI_IOV */
static inline struct ice_vf *ice_get_vf_by_id(struct ice_pf *pf, u16 vf_id)
{
@@ -399,6 +404,14 @@ ice_get_vf_ctrl_vsi(struct ice_pf *pf, struct ice_vsi *vsi)
{
return NULL;
}
+
+static inline void ice_init_vf_devlink(struct ice_vf *vf)
+{
+}
+
+static inline void ice_deinit_vf_devlink(struct ice_vf *vf)
+{
+}
#endif /* !CONFIG_PCI_IOV */
#endif /* _ICE_VF_LIB_H_ */
--git a/drivers/net/ethernet/intel/ice/virt/rss.h b/drivers/net/ethernet/intel/ice/virt/rss.h
index 784d4c43ce8b..388f980b4cdf 100644
--- a/drivers/net/ethernet/intel/ice/virt/rss.h
+++ b/drivers/net/ethernet/intel/ice/virt/rss.h
@@ -14,5 +14,6 @@ int ice_vc_config_rss_lut(struct ice_vf *vf, u8 *msg);
int ice_vc_config_rss_hfunc(struct ice_vf *vf, u8 *msg);
int ice_vc_get_rss_hashcfg(struct ice_vf *vf);
int ice_vc_set_rss_hashcfg(struct ice_vf *vf, u8 *msg);
+int ice_vc_get_max_rss_qregion(struct ice_vf *vf);
#endif /* _ICE_VIRT_RSS_H_ */
diff --git a/drivers/net/ethernet/intel/ice/virt/virtchnl.h b/drivers/net/ethernet/intel/ice/virt/virtchnl.h
index f7f909424098..c7e074726f8a 100644
--- a/drivers/net/ethernet/intel/ice/virt/virtchnl.h
+++ b/drivers/net/ethernet/intel/ice/virt/virtchnl.h
@@ -78,6 +78,10 @@ struct ice_virtchnl_ops {
int (*get_ptp_cap)(struct ice_vf *vf,
const struct virtchnl_ptp_caps *msg);
int (*get_phc_time)(struct ice_vf *vf);
+ int (*get_max_rss_qregion)(struct ice_vf *vf);
+ int (*ena_qs_v2_msg)(struct ice_vf *vf, u8 *msg, u16 msglen);
+ int (*dis_qs_v2_msg)(struct ice_vf *vf, u8 *msg, u16 msglen);
+ int (*map_q_vector_msg)(struct ice_vf *vf, u8 *msg, u16 msglen);
};
#ifdef CONFIG_PCI_IOV
diff --git a/drivers/net/ethernet/intel/ice/devlink/resource.c b/drivers/net/ethernet/intel/ice/devlink/resource.c
index 42b65730ea52..dd2410f266b6 100644
--- a/drivers/net/ethernet/intel/ice/devlink/resource.c
+++ b/drivers/net/ethernet/intel/ice/devlink/resource.c
@@ -104,6 +104,16 @@ void ice_free_rss_lut_flr(struct ice_pf *pf)
}
}
+void ice_free_rss_lut_vf(struct ice_vf *vf)
+{
+ struct ice_pf *pf = vf->pf;
+
+ scoped_guard(ice_adapter_devl, pf->adapter) {
+ ice_devl_res_free(pf, ICE_RSS_LUT_GLOBAL, vf);
+ ice_devl_res_free(pf, ICE_RSS_LUT_PF, vf);
+ }
+}
+
static int ice_devl_res_owned_idx(struct ice_adapter *adapter,
enum ice_devl_resource_id res_id, void *owner)
{
@@ -175,6 +185,37 @@ static u64 ice_rss_lut_pf_occ_get_both(void *priv)
ice_is_devl_res_owned_by(adapter, ICE_RSS_LUT_GLOBAL, pf);
}
+static u64 ice_rss_lut_vf_occ_get_global(void *priv)
+{
+ struct ice_adapter *adapter;
+ struct ice_vf *vf = priv;
+
+ adapter = vf->pf->adapter;
+ scoped_guard(ice_adapter_devl, adapter)
+ return ice_is_devl_res_owned_by(adapter, ICE_RSS_LUT_GLOBAL, vf);
+}
+
+static u64 ice_rss_lut_vf_occ_get_pf(void *priv)
+{
+ struct ice_adapter *adapter;
+ struct ice_vf *vf = priv;
+
+ adapter = vf->pf->adapter;
+ scoped_guard(ice_adapter_devl, adapter)
+ return ice_is_devl_res_owned_by(adapter, ICE_RSS_LUT_PF, vf);
+}
+
+static u64 ice_rss_lut_vf_occ_get_both(void *priv)
+{
+ struct ice_adapter *adapter;
+ struct ice_vf *vf = priv;
+
+ adapter = vf->pf->adapter;
+ scoped_guard(ice_adapter_devl, adapter)
+ return ice_is_devl_res_owned_by(adapter, ICE_RSS_LUT_PF, vf) +
+ ice_is_devl_res_owned_by(adapter, ICE_RSS_LUT_GLOBAL, vf);
+}
+
static int ice_devl_resource_deny_occ_set(u64 size,
struct netlink_ext_ack *extack,
void *priv)
@@ -220,6 +261,7 @@ static int ice_maybe_change_rss_lut(struct ice_pf *pf, void *owner,
struct ice_hw *hw = &pf->hw;
enum ice_lut_type lut_type;
int err, lut_size, lut_id;
+ struct ice_vf *vf = NULL;
struct ice_vsi *vsi;
u8 *lut;
@@ -246,7 +288,8 @@ static int ice_maybe_change_rss_lut(struct ice_pf *pf, void *owner,
if (pf == owner) {
vsi = ice_get_main_vsi(pf);
} else {
- return -EOPNOTSUPP;
+ vf = owner;
+ vsi = ice_get_vf_vsi(vf);
}
lut_size = ice_lut_type_to_size(lut_type);
@@ -266,6 +309,11 @@ static int ice_maybe_change_rss_lut(struct ice_pf *pf, void *owner,
vsi->rss_table_size = lut_size;
vsi->rss_lut_type = lut_type;
+ if (vf) {
+ vsi->rss_size = ice_lut_type_to_qs_num(lut_type);
+ vsi->flags |= ICE_VSI_FLAG_RELOAD;
+ ice_schedule_vf_reset(vf);
+ }
out:
kfree(lut);
return err;
@@ -354,6 +402,30 @@ static int ice_rss_lut_pf_occ_set_global(u64 size,
ICE_ANY_SLOT, extack);
}
+static int ice_rss_lut_vf_occ_set_pf(u64 size, struct netlink_ext_ack *extack,
+ void *occ_priv)
+{
+ struct ice_vf *vf = occ_priv;
+ struct ice_pf *pf = vf->pf;
+ int pf_id = pf->hw.pf_id;
+
+ scoped_guard(ice_adapter_devl, pf->adapter)
+ return ice_devl_res_change(size, ICE_RSS_LUT_PF, pf, vf, pf_id,
+ extack);
+}
+
+static int ice_rss_lut_vf_occ_set_global(u64 size,
+ struct netlink_ext_ack *extack,
+ void *occ_priv)
+{
+ struct ice_vf *vf = occ_priv;
+ struct ice_pf *pf = vf->pf;
+
+ scoped_guard(ice_adapter_devl, pf->adapter)
+ return ice_devl_res_change(size, ICE_RSS_LUT_GLOBAL, pf, vf,
+ ICE_ANY_SLOT, extack);
+}
+
/**
* ice_take_rss_lut_pf - allocate PF RSS LUT for PF
* @pf: the PF device that PF LUT is physically on, and to allocate it for
@@ -467,3 +539,34 @@ void ice_devl_pf_resources_register(struct ice_pf *pf)
devl_assert_locked(devlink);
ice_devl_res_register(devlink, pf_resources, pf);
}
+
+void ice_devlink_vf_resources_register(struct ice_vf *vf)
+{
+ struct ice_devl_resource vf_resources[ICE_DEVL_RESOURCES_COUNT] = {
+ [ICE_RSS_LUT_GLOBAL] = {
+ .name = "lut_512",
+ .parent_id = ICE_RSS_LUT_BOTH,
+ .max_size = 1,
+ .get = ice_rss_lut_vf_occ_get_global,
+ .set = ice_rss_lut_vf_occ_set_global,
+ },
+ [ICE_RSS_LUT_PF] = {
+ .name = "lut_2048",
+ .parent_id = ICE_RSS_LUT_BOTH,
+ .max_size = 1,
+ .get = ice_rss_lut_vf_occ_get_pf,
+ .set = ice_rss_lut_vf_occ_set_pf,
+ },
+ [ICE_RSS_LUT_BOTH] = {
+ .name = "rss",
+ .parent_id = ICE_TOP_RESOURCE,
+ .max_size = 2,
+ .get = ice_rss_lut_vf_occ_get_both,
+ .set = ice_devl_resource_deny_occ_set,
+ },
+ };
+ struct devlink *devlink = vf->devlink;
+
+ scoped_guard(devl, devlink)
+ ice_devl_res_register(devlink, vf_resources, vf);
+}
diff --git a/drivers/net/ethernet/intel/ice/ice_lib.c b/drivers/net/ethernet/intel/ice/ice_lib.c
index e47f2f881701..2ab44eca7e11 100644
--- a/drivers/net/ethernet/intel/ice/ice_lib.c
+++ b/drivers/net/ethernet/intel/ice/ice_lib.c
@@ -12,6 +12,23 @@
#include "devlink/resource.h"
+#define ICE_LUT_VSI_MAX_QS 16
+#define ICE_LUT_GLOBAL_MAX_QS 64
+#define ICE_LUT_PF_MAX_QS 256
+
+u16 ice_lut_type_to_qs_num(enum ice_lut_type lut_type)
+{
+ switch (lut_type) {
+ case ICE_LUT_PF:
+ return ICE_LUT_PF_MAX_QS;
+ case ICE_LUT_GLOBAL:
+ return ICE_LUT_GLOBAL_MAX_QS;
+ case ICE_LUT_VSI:
+ default:
+ return ICE_LUT_VSI_MAX_QS;
+ }
+}
+
/**
* ice_vsi_type_str - maps VSI type enum to string equivalents
* @vsi_type: VSI type enum
@@ -1547,8 +1564,6 @@ int ice_vsi_cfg_rss_lut_key(struct ice_vsi *vsi)
(test_bit(ICE_FLAG_TC_MQPRIO, pf->flags))) {
vsi->rss_size = min_t(u16, vsi->rss_size, vsi->ch_rss_size);
} else {
- vsi->rss_size = min_t(u16, vsi->rss_size, vsi->num_rxq);
-
/* If orig_rss_size is valid and it is less than determined
* main VSI's rss_size, update main VSI's rss_size to be
* orig_rss_size so that when tc-qdisc is deleted, main VSI
@@ -2572,8 +2587,14 @@ void ice_vsi_decfg(struct ice_vsi *vsi)
ice_vsi_free_arrays(vsi);
if (vsi->flags & ICE_VSI_FLAG_INIT) {
- if (vsi->type == ICE_VSI_PF)
+ if (vsi->type == ICE_VSI_PF) {
ice_free_rss_lut_flr(pf);
+ } else if (vsi->type == ICE_VSI_VF) {
+ struct ice_vf *vf = vsi->vf;
+
+ vf->num_req_qs = 0;
+ vf->num_vf_qs = min(vf->num_vf_qs, pf->vfs.num_qps_per);
+ }
}
/* SR-IOV determines needed MSIX resources all at once instead of per
diff --git a/drivers/net/ethernet/intel/ice/ice_main.c b/drivers/net/ethernet/intel/ice/ice_main.c
index 94232f4a45ad..606e863f0f54 100644
--- a/drivers/net/ethernet/intel/ice/ice_main.c
+++ b/drivers/net/ethernet/intel/ice/ice_main.c
@@ -2275,6 +2275,30 @@ static void ice_check_media_subtask(struct ice_pf *pf)
}
}
+static void ice_handle_deferred_vf_reset(struct ice_pf *pf)
+{
+ struct ice_vf *vf;
+ unsigned int bkt;
+ int err;
+
+ mutex_lock(&pf->vfs.table_lock);
+ ice_for_each_vf(pf, bkt, vf) {
+ if (!vf->needs_deferred_reset)
+ continue;
+
+ dev_info(ice_pf_to_dev(pf), "doing deferred reset of VF %d\n",
+ vf->vf_id);
+ err = ice_reset_vf(vf, ICE_VF_RESET_NOTIFY | ICE_VF_RESET_LOCK);
+ if (err)
+ dev_warn(ice_pf_to_dev(pf), "deferred reset of VF %d failed: %d\n",
+ vf->vf_id, err);
+
+ vf->needs_deferred_reset = 0;
+ ice_put_vf(vf);
+ }
+ mutex_unlock(&pf->vfs.table_lock);
+}
+
static void ice_service_task_recovery_mode(struct work_struct *work)
{
struct ice_pf *pf = container_of(work, struct ice_pf, serv_task);
@@ -2357,6 +2381,7 @@ static void ice_service_task(struct work_struct *work)
return;
}
+ ice_handle_deferred_vf_reset(pf);
ice_process_vflr_event(pf);
ice_clean_mailboxq_subtask(pf);
ice_clean_sbq_subtask(pf);
diff --git a/drivers/net/ethernet/intel/ice/ice_sriov.c b/drivers/net/ethernet/intel/ice/ice_sriov.c
index 28f9e68f46cd..3de352e8f45b 100644
--- a/drivers/net/ethernet/intel/ice/ice_sriov.c
+++ b/drivers/net/ethernet/intel/ice/ice_sriov.c
@@ -655,6 +655,15 @@ static void ice_sriov_post_vsi_rebuild(struct ice_vf *vf)
wr32(&vf->pf->hw, VFGEN_RSTAT(vf->vf_id), VIRTCHNL_VFR_VFACTIVE);
}
+static struct ice_q_vector *ice_sriov_get_q_vector(struct ice_vsi *vsi,
+ u16 vector_id)
+{
+ /* Subtract non queue vector from vector_id passed by VF
+ * to get actual number of VSI queue vector array index
+ */
+ return vsi->q_vectors[vector_id - ICE_NONQ_VECS_VF];
+}
+
static const struct ice_vf_ops ice_sriov_vf_ops = {
.reset_type = ICE_VF_RESET,
.free = ice_sriov_free_vf,
@@ -665,6 +674,7 @@ static const struct ice_vf_ops ice_sriov_vf_ops = {
.clear_reset_trigger = ice_sriov_clear_reset_trigger,
.irq_close = NULL,
.post_vsi_rebuild = ice_sriov_post_vsi_rebuild,
+ .get_q_vector = ice_sriov_get_q_vector,
};
/**
diff --git a/drivers/net/ethernet/intel/ice/ice_vf_lib.c b/drivers/net/ethernet/intel/ice/ice_vf_lib.c
index 55ad03085bc9..6e1f1c9733ef 100644
--- a/drivers/net/ethernet/intel/ice/ice_vf_lib.c
+++ b/drivers/net/ethernet/intel/ice/ice_vf_lib.c
@@ -6,6 +6,7 @@
#include "ice_lib.h"
#include "ice_fltr.h"
#include "virt/allowlist.h"
+#include "devlink/resource.h"
/* Public functions which may be accessed by all driver files */
@@ -248,6 +249,8 @@ static void ice_vf_pre_vsi_rebuild(struct ice_vf *vf)
vf->vf_ops->clear_reset_trigger(vf);
}
+int ice_vsi_realloc_stat_arrays(struct ice_vsi *);
+
/**
* ice_vf_reconfig_vsi - Reconfigure a VF VSI with the device
* @vf: VF to reconfigure the VSI for
@@ -989,6 +992,16 @@ int ice_reset_vf(struct ice_vf *vf, u32 flags)
return err;
}
+/**
+ * ice_schedule_vf_reset - reset VF, deferred to next service_task context
+ * @vf: VF to reset
+ */
+void ice_schedule_vf_reset(struct ice_vf *vf)
+{
+ kref_get(&vf->refcnt);
+ vf->needs_deferred_reset = 1;
+}
+
/**
* ice_set_vf_state_dis - Set VF state to disabled
* @vf: pointer to the VF structure
@@ -1043,6 +1056,9 @@ void ice_deinitialize_vf_entry(struct ice_vf *vf)
{
struct ice_pf *pf = vf->pf;
+ ice_free_rss_lut_vf(vf);
+ ice_deinit_vf_devlink(vf);
+
if (!ice_is_feature_supported(pf, ICE_F_MBX_LIMIT))
list_del(&vf->mbx_info.list_entry);
}
@@ -1429,3 +1445,29 @@ void ice_vf_update_mac_lldp_num(struct ice_vf *vf, struct ice_vsi *vsi,
if (was_ena != is_ena)
ice_vsi_cfg_sw_lldp(vsi, false, is_ena);
}
+
+void ice_init_vf_devlink(struct ice_vf *vf)
+{
+ static const struct devlink_ops noop = {};
+ struct device *dev = &vf->vfdev->dev;
+ struct devlink *devlink;
+
+ devlink = devlink_alloc(&noop, 0, dev);
+ if (!devlink)
+ return;
+
+ devl_nested_devlink_set(priv_to_devlink(vf->pf), devlink);
+ devlink_register(devlink);
+ vf->devlink = devlink;
+
+ ice_devlink_vf_resources_register(vf);
+}
+
+void ice_deinit_vf_devlink(struct ice_vf *vf)
+{
+ struct devlink *devlink = vf->devlink;
+
+ devlink_resources_unregister(devlink);
+ devlink_unregister(devlink);
+ devlink_free(devlink);
+}
--git a/drivers/net/ethernet/intel/ice/virt/rss.c b/drivers/net/ethernet/intel/ice/virt/rss.c
index 960012ca91b5..9b23ad40f7e2 100644
--- a/drivers/net/ethernet/intel/ice/virt/rss.c
+++ b/drivers/net/ethernet/intel/ice/virt/rss.c
@@ -1746,7 +1746,13 @@ int ice_vc_config_rss_lut(struct ice_vf *vf, u8 *msg)
goto error_param;
}
- if (vrl->lut_entries != ICE_LUT_VSI_SIZE) {
+ vsi = ice_get_vf_vsi(vf);
+ if (!vsi) {
+ v_ret = VIRTCHNL_STATUS_ERR_PARAM;
+ goto error_param;
+ }
+
+ if (vrl->lut_entries != vsi->rss_table_size) {
v_ret = VIRTCHNL_STATUS_ERR_PARAM;
goto error_param;
}
@@ -1762,7 +1768,7 @@ int ice_vc_config_rss_lut(struct ice_vf *vf, u8 *msg)
goto error_param;
}
- if (ice_set_rss_lut(vsi, vrl->lut, ICE_LUT_VSI_SIZE))
+ if (ice_set_rss_lut(vsi, vrl->lut, vrl->lut_entries))
v_ret = VIRTCHNL_STATUS_ERR_ADMIN_QUEUE_ERROR;
error_param:
return ice_vc_send_msg_to_vf(vf, VIRTCHNL_OP_CONFIG_RSS_LUT, v_ret,
@@ -1920,3 +1926,29 @@ int ice_vc_set_rss_hashcfg(struct ice_vf *vf, u8 *msg)
NULL, 0);
}
+int ice_vc_get_max_rss_qregion(struct ice_vf *vf)
+{
+ enum virtchnl_status_code v_ret = VIRTCHNL_STATUS_SUCCESS;
+ struct virtchnl_max_rss_qregion max_rss_qregion = {};
+ struct ice_vsi *vsi;
+ int err, len = 0;
+
+ if (!test_bit(ICE_VF_STATE_ACTIVE, vf->vf_states)) {
+ v_ret = VIRTCHNL_STATUS_ERR_PARAM;
+ goto reply;
+ }
+
+ vsi = vf->pf->vsi[vf->lan_vsi_idx];
+ if (!vsi) {
+ v_ret = VIRTCHNL_STATUS_ERR_PARAM;
+ goto reply;
+ }
+
+ len = sizeof(max_rss_qregion);
+ max_rss_qregion.vport_id = vsi->vsi_num;
+ max_rss_qregion.qregion_width = ilog2(vsi->rss_table_size);
+reply:
+ err = ice_vc_send_msg_to_vf(vf, VIRTCHNL_OP_GET_MAX_RSS_QREGION, v_ret,
+ (u8 *)&max_rss_qregion, len);
+ return err;
+}
diff --git a/drivers/net/ethernet/intel/ice/virt/virtchnl.c b/drivers/net/ethernet/intel/ice/virt/virtchnl.c
index 06d2f9be93ae..b7ece2c36165 100644
--- a/drivers/net/ethernet/intel/ice/virt/virtchnl.c
+++ b/drivers/net/ethernet/intel/ice/virt/virtchnl.c
@@ -246,10 +246,10 @@ static int ice_vc_get_vf_res_msg(struct ice_vf *vf, u8 *msg)
{
enum virtchnl_status_code v_ret = VIRTCHNL_STATUS_SUCCESS;
struct virtchnl_vf_resource *vfres = NULL;
+ int ret, allowed_queues, len = 0;
struct ice_hw *hw = &vf->pf->hw;
+ enum ice_lut_type lut_type;
struct ice_vsi *vsi;
- int len = 0;
- int ret;
if (ice_check_vf_init(vf)) {
v_ret = VIRTCHNL_STATUS_ERR_PARAM;
@@ -330,16 +330,24 @@ static int ice_vc_get_vf_res_msg(struct ice_vf *vf, u8 *msg)
vfres->vf_cap_flags |= VIRTCHNL_VF_CAP_PTP;
vfres->num_vsis = 1;
- /* Tx and Rx queue are equal for VF */
- vfres->num_queue_pairs = vsi->num_txq;
+
+ lut_type = vsi->rss_lut_type;
+ if (vf->driver_caps & VIRTCHNL_VF_LARGE_NUM_QPAIRS &&
+ lut_type != ICE_LUT_VSI) {
+ vfres->vf_cap_flags |= VIRTCHNL_VF_LARGE_NUM_QPAIRS;
+ allowed_queues = ice_lut_type_to_qs_num(lut_type);
+ } else {
+ allowed_queues = vsi->num_txq;
+ }
+ vfres->num_queue_pairs = allowed_queues;
vfres->max_vectors = vf->num_msix;
vfres->rss_key_size = ICE_VSIQF_HKEY_ARRAY_SIZE;
- vfres->rss_lut_size = ICE_LUT_VSI_SIZE;
+ vfres->rss_lut_size = vsi->rss_table_size;
vfres->max_mtu = ice_vc_get_max_frame_size(vf);
vfres->vsi_res[0].vsi_id = ICE_VF_VSI_ID;
vfres->vsi_res[0].vsi_type = VIRTCHNL_VSI_SRIOV;
- vfres->vsi_res[0].num_queue_pairs = vsi->num_txq;
+ vfres->vsi_res[0].num_queue_pairs = allowed_queues;
ether_addr_copy(vfres->vsi_res[0].default_mac_addr,
vf->hw_lan_addr);
@@ -2539,6 +2547,10 @@ static const struct ice_virtchnl_ops ice_virtchnl_dflt_ops = {
.cfg_q_quanta = ice_vc_cfg_q_quanta,
.get_ptp_cap = ice_vc_get_ptp_cap,
.get_phc_time = ice_vc_get_phc_time,
+ .get_max_rss_qregion = ice_vc_get_max_rss_qregion,
+ .ena_qs_v2_msg = ice_vc_ena_qs_v2_msg,
+ .dis_qs_v2_msg = ice_vc_dis_qs_v2_msg,
+ .map_q_vector_msg = ice_vc_map_q_vector_msg,
/* If you add a new op here please make sure to add it to
* ice_virtchnl_repr_ops as well.
*/
@@ -2676,6 +2688,10 @@ static const struct ice_virtchnl_ops ice_virtchnl_repr_ops = {
.cfg_q_quanta = ice_vc_cfg_q_quanta,
.get_ptp_cap = ice_vc_get_ptp_cap,
.get_phc_time = ice_vc_get_phc_time,
+ .get_max_rss_qregion = ice_vc_get_max_rss_qregion,
+ .ena_qs_v2_msg = ice_vc_ena_qs_v2_msg,
+ .dis_qs_v2_msg = ice_vc_dis_qs_v2_msg,
+ .map_q_vector_msg = ice_vc_map_q_vector_msg,
};
/**
@@ -2745,6 +2761,7 @@ void ice_vc_process_vf_msg(struct ice_pf *pf, struct ice_rq_event_info *event,
u32 v_opcode = le32_to_cpu(event->desc.cookie_high);
s16 vf_id = le16_to_cpu(event->desc.retval);
const struct ice_virtchnl_ops *ops;
+ bool need_devlink_init = false;
u16 msglen = event->msg_len;
u8 *msg = event->msg_buf;
struct ice_vf *vf = NULL;
@@ -2783,6 +2800,8 @@ void ice_vc_process_vf_msg(struct ice_pf *pf, struct ice_rq_event_info *event,
err = -EINVAL;
}
+ need_devlink_init = !vf->devlink;
+
error_handler:
if (err) {
ice_vc_send_msg_to_vf(vf, v_opcode, VIRTCHNL_STATUS_ERR_PARAM,
@@ -2907,6 +2926,20 @@ void ice_vc_process_vf_msg(struct ice_pf *pf, struct ice_rq_event_info *event,
case VIRTCHNL_OP_GET_QOS_CAPS:
err = ops->get_qos_caps(vf);
break;
+ case VIRTCHNL_OP_GET_MAX_RSS_QREGION:
+ err = ops->get_max_rss_qregion(vf);
+ break;
+ case VIRTCHNL_OP_ENABLE_QUEUES_V2:
+ err = ops->ena_qs_v2_msg(vf, msg, msglen);
+ if (!err)
+ ice_vc_notify_vf_link_state(vf);
+ break;
+ case VIRTCHNL_OP_DISABLE_QUEUES_V2:
+ err = ops->dis_qs_v2_msg(vf, msg, msglen);
+ break;
+ case VIRTCHNL_OP_MAP_QUEUE_VECTOR:
+ err = ops->map_q_vector_msg(vf, msg, msglen);
+ break;
case VIRTCHNL_OP_CONFIG_QUEUE_BW:
err = ops->cfg_q_bw(vf, msg);
break;
@@ -2938,5 +2971,7 @@ void ice_vc_process_vf_msg(struct ice_pf *pf, struct ice_rq_event_info *event,
finish:
mutex_unlock(&vf->cfg_lock);
+ if (need_devlink_init)
+ ice_init_vf_devlink(vf);
ice_put_vf(vf);
}
--
2.39.3
^ permalink raw reply related [flat|nested] 28+ messages in thread