Merge: CNB103: devlink: update devlink to the v7.1

MR: https://gitlab.com/redhat/centos-stream/src/kernel/centos-stream-10/-/merge_requests/2822

JIRA: https://redhat.atlassian.net/browse/RHEL-179081
Depends: !2273

Devlink update to version v7.1

Signed-off-by: Petr Oros <poros@redhat.com>

Approved-by: Tony Camuso <tcamuso@redhat.com>
Approved-by: Eric Chanudet <echanude@redhat.com>
Approved-by: Ivan Vecera <ivecera@redhat.com>
Approved-by: CKI KWF Bot <cki-ci-bot+kwf-gitlab-com@redhat.com>

Merged-by: CKI GitLab Kmaint Pipeline Bot <26919896-cki-kmaint-pipeline-bot@users.noreply.gitlab.com>
This commit is contained in:
CKI KWF Bot
2026-08-13 08:29:40 +00:00
56 changed files with 2073 additions and 606 deletions
+101 -2
View File
@@ -157,6 +157,14 @@ definitions:
entries:
-
name: entry
-
type: enum
name: resource-scope
entries:
-
name: dev
-
name: port
-
type: enum
name: reload-action
@@ -226,6 +234,10 @@ definitions:
value: 10
-
name: binary
-
name: u64-array
value: 129
-
name: rate-tc-index-max
type: const
@@ -859,6 +871,30 @@ attribute-sets:
name: health-reporter-burst-period
type: u64
doc: Time (in msec) for recoveries before starting the grace period.
# TODO: fill in the attributes in between
-
name: param-reset-default
type: flag
doc: Request restoring parameter to its default value.
value: 183
-
name: index
type: uint
doc: Unique devlink instance index.
checks:
max: u32-max
-
name: resource-scope-mask
type: u32
enum: resource-scope
enum-as-flags: true
doc: |
Bitmask selecting which resource classes to include in a
resource-dump response. Bit 0 (dev) selects device-level
resources; bit 1 (port) selects port-level resources.
When absent all classes are returned.
-
name: dl-dev-stats
subset-of: devlink
@@ -1298,11 +1334,13 @@ operations:
attributes: &dev-id-attrs
- bus-name
- dev-name
- index
reply: &get-reply
value: 3
attributes:
- bus-name
- dev-name
- index
- reload-failed
- dev-stats
dump:
@@ -1321,6 +1359,7 @@ operations:
attributes: &port-id-attrs
- bus-name
- dev-name
- index
- port-index
reply:
value: 7
@@ -1345,6 +1384,7 @@ operations:
attributes:
- bus-name
- dev-name
- index
- port-index
- port-type
- port-function
@@ -1362,6 +1402,7 @@ operations:
attributes:
- bus-name
- dev-name
- index
- port-index
- port-flavour
- port-pci-pf-number
@@ -1396,6 +1437,7 @@ operations:
attributes:
- bus-name
- dev-name
- index
- port-index
- port-split-count
@@ -1424,6 +1466,7 @@ operations:
attributes: &sb-id-attrs
- bus-name
- dev-name
- index
- sb-index
reply: &sb-get-reply
value: 13
@@ -1446,6 +1489,7 @@ operations:
attributes: &sb-pool-id-attrs
- bus-name
- dev-name
- index
- sb-index
- sb-pool-index
reply: &sb-pool-get-reply
@@ -1469,6 +1513,7 @@ operations:
attributes:
- bus-name
- dev-name
- index
- sb-index
- sb-pool-index
- sb-pool-threshold-type
@@ -1487,6 +1532,7 @@ operations:
attributes: &sb-port-pool-id-attrs
- bus-name
- dev-name
- index
- port-index
- sb-index
- sb-pool-index
@@ -1511,6 +1557,7 @@ operations:
attributes:
- bus-name
- dev-name
- index
- port-index
- sb-index
- sb-pool-index
@@ -1529,6 +1576,7 @@ operations:
attributes: &sb-tc-pool-bind-id-attrs
- bus-name
- dev-name
- index
- port-index
- sb-index
- sb-pool-type
@@ -1554,6 +1602,7 @@ operations:
attributes:
- bus-name
- dev-name
- index
- port-index
- sb-index
- sb-pool-index
@@ -1575,6 +1624,7 @@ operations:
attributes:
- bus-name
- dev-name
- index
- sb-index
-
@@ -1590,6 +1640,7 @@ operations:
attributes:
- bus-name
- dev-name
- index
- sb-index
-
@@ -1608,6 +1659,7 @@ operations:
attributes: &eswitch-attrs
- bus-name
- dev-name
- index
- eswitch-mode
- eswitch-inline-mode
- eswitch-encap-mode
@@ -1636,12 +1688,14 @@ operations:
attributes:
- bus-name
- dev-name
- index
- dpipe-table-name
reply:
value: 31
attributes:
- bus-name
- dev-name
- index
- dpipe-tables
-
@@ -1656,11 +1710,13 @@ operations:
attributes:
- bus-name
- dev-name
- index
- dpipe-table-name
reply:
attributes:
- bus-name
- dev-name
- index
- dpipe-entries
-
@@ -1675,10 +1731,12 @@ operations:
attributes:
- bus-name
- dev-name
- index
reply:
attributes:
- bus-name
- dev-name
- index
- dpipe-headers
-
@@ -1694,6 +1752,7 @@ operations:
attributes:
- bus-name
- dev-name
- index
- dpipe-table-name
- dpipe-table-counters-enabled
@@ -1710,6 +1769,7 @@ operations:
attributes:
- bus-name
- dev-name
- index
- resource-id
- resource-size
@@ -1719,18 +1779,30 @@ operations:
attribute-set: devlink
dont-validate: [strict]
do:
pre: devlink-nl-pre-doit
pre: devlink-nl-pre-doit-port-optional
post: devlink-nl-post-doit
request:
attributes:
- bus-name
- dev-name
reply:
- index
- port-index
reply: &resource-dump-reply
value: 36
attributes:
- bus-name
- dev-name
- index
- port-index
- resource-list
dump:
request:
attributes:
- bus-name
- dev-name
- index
- resource-scope-mask
reply: *resource-dump-reply
-
name: reload
@@ -1745,6 +1817,7 @@ operations:
attributes:
- bus-name
- dev-name
- index
- reload-action
- reload-limits
- netns-pid
@@ -1754,6 +1827,7 @@ operations:
attributes:
- bus-name
- dev-name
- index
- reload-actions-performed
-
@@ -1768,6 +1842,7 @@ operations:
attributes: &param-id-attrs
- bus-name
- dev-name
- index
- param-name
reply: &param-get-reply
attributes: *param-id-attrs
@@ -1789,10 +1864,12 @@ operations:
attributes:
- bus-name
- dev-name
- index
- param-name
- param-type
# param-value-data is missing here as the type is variable
- param-value-cmode
- param-reset-default
-
name: region-get
@@ -1807,6 +1884,7 @@ operations:
attributes: &region-id-attrs
- bus-name
- dev-name
- index
- port-index
- region-name
reply: &region-get-reply
@@ -1831,6 +1909,7 @@ operations:
attributes: &region-snapshot-id-attrs
- bus-name
- dev-name
- index
- port-index
- region-name
- region-snapshot-id
@@ -1861,6 +1940,7 @@ operations:
attributes:
- bus-name
- dev-name
- index
- port-index
- region-name
- region-snapshot-id
@@ -1872,6 +1952,7 @@ operations:
attributes:
- bus-name
- dev-name
- index
- port-index
- region-name
@@ -1921,6 +2002,7 @@ operations:
attributes:
- bus-name
- dev-name
- index
- info-driver-name
- info-serial-number
- info-version-fixed
@@ -1942,6 +2024,7 @@ operations:
attributes: &health-reporter-id-attrs
- bus-name
- dev-name
- index
- port-index
- health-reporter-name
reply: &health-reporter-get-reply
@@ -1964,6 +2047,7 @@ operations:
attributes:
- bus-name
- dev-name
- index
- port-index
- health-reporter-name
- health-reporter-graceful-period
@@ -2034,6 +2118,7 @@ operations:
attributes:
- bus-name
- dev-name
- index
- flash-update-file-name
- flash-update-component
- flash-update-overwrite-mask
@@ -2051,6 +2136,7 @@ operations:
attributes: &trap-id-attrs
- bus-name
- dev-name
- index
- trap-name
reply: &trap-get-reply
value: 63
@@ -2073,6 +2159,7 @@ operations:
attributes:
- bus-name
- dev-name
- index
- trap-name
- trap-action
@@ -2089,6 +2176,7 @@ operations:
attributes: &trap-group-id-attrs
- bus-name
- dev-name
- index
- trap-group-name
reply: &trap-group-get-reply
value: 67
@@ -2111,6 +2199,7 @@ operations:
attributes:
- bus-name
- dev-name
- index
- trap-group-name
- trap-action
- trap-policer-id
@@ -2128,6 +2217,7 @@ operations:
attributes: &trap-policer-id-attrs
- bus-name
- dev-name
- index
- trap-policer-id
reply: &trap-policer-get-reply
value: 71
@@ -2150,6 +2240,7 @@ operations:
attributes:
- bus-name
- dev-name
- index
- trap-policer-id
- trap-policer-rate
- trap-policer-burst
@@ -2180,6 +2271,7 @@ operations:
attributes: &rate-id-attrs
- bus-name
- dev-name
- index
- port-index
- rate-node-name
reply: &rate-get-reply
@@ -2203,6 +2295,7 @@ operations:
attributes:
- bus-name
- dev-name
- index
- rate-node-name
- rate-tx-share
- rate-tx-max
@@ -2224,6 +2317,7 @@ operations:
attributes:
- bus-name
- dev-name
- index
- rate-node-name
- rate-tx-share
- rate-tx-max
@@ -2245,6 +2339,7 @@ operations:
attributes:
- bus-name
- dev-name
- index
- rate-node-name
-
@@ -2260,6 +2355,7 @@ operations:
attributes: &linecard-id-attrs
- bus-name
- dev-name
- index
- linecard-index
reply: &linecard-get-reply
value: 80
@@ -2282,6 +2378,7 @@ operations:
attributes:
- bus-name
- dev-name
- index
- linecard-index
- linecard-type
@@ -2315,6 +2412,7 @@ operations:
attributes:
- bus-name
- dev-name
- index
- selftests
-
@@ -2326,4 +2424,5 @@ operations:
attributes:
- bus-name
- dev-name
- index
- port-index
@@ -33,7 +33,9 @@ Device driver can provide specific callbacks for each "health reporter", e.g.:
* Recovery procedures
* Diagnostics procedures
* Object dump procedures
* Out Of Box initial parameters
Drivers also provide default values for generic reporter parameters when
creating a health reporter.
Different parts of the driver can register different types of health reporters
with different handlers.
@@ -45,8 +47,9 @@ Once an error is reported, devlink health will perform the following actions:
* A log is being send to the kernel trace events buffer
* Health status and statistics are being updated for the reporter instance
* Object dump is being taken and saved at the reporter instance (as long as
auto-dump is set and there is no other dump which is already stored)
* Object dump is being taken and saved at the reporter instance. This is
best effort and skipped when recovery is aborted, auto-dump is disabled,
no dump callback is registered, or a dump is already stored.
* Auto recovery attempt is being done. Depends on:
- Auto-recovery configuration
@@ -75,7 +78,8 @@ User Interface
==============
User can access/change each reporter's parameters and driver specific callbacks
via ``devlink``, e.g per error type (per health reporter):
via ``devlink``, e.g. per error type (per health reporter). Reporters may be
registered for the whole devlink instance or for a specific devlink port.
* Configure reporter's generic parameters (like: disable/enable auto recovery)
* Invoke recovery procedure
@@ -41,6 +41,16 @@ In order for ``driverinit`` parameters to take effect, the driver must
support reloading via the ``devlink-reload`` command. This command will
request a reload of the device driver.
Default parameter values
=========================
Drivers may optionally export default values for parameters of cmode
``runtime`` and ``permanent``. For ``driverinit`` parameters, the last
value set by the driver will be used as the default value. Drivers can
also support resetting params with cmode ``runtime`` and ``permanent``
to their default values. Resetting ``driverinit`` params is supported
by devlink core without additional driver support needed.
.. _devlink_params_generic:
Generic configuration parameters
@@ -112,7 +122,7 @@ own name.
* - ``enable_iwarp``
- Boolean
- Enable handling of iWARP traffic in the device.
* - ``internal_err_reset``
* - ``internal_error_reset``
- Boolean
- When enabled, the device driver will reset the device on internal
errors.
@@ -38,7 +38,7 @@ Devlink port flavours are described below.
- This indicates an eswitch port representing a port of PCI
subfunction (SF).
* - ``DEVLINK_PORT_FLAVOUR_VIRTUAL``
- This indicates a virtual port for the PCI virtual function.
- Any virtual port facing the user.
Devlink port can have a different type based on the link layer described below.
@@ -134,6 +134,9 @@ Users may also set the IPsec crypto capability of the function using
Users may also set the IPsec packet capability of the function using
`devlink port function set ipsec_packet` command.
The ``migratable`` attribute may be set only on ports with
``DEVLINK_PORT_FLAVOUR_PCI_VF``.
Users may also set the maximum IO event queues of the function
using `devlink port function set max_io_eqs` command.
@@ -74,3 +74,73 @@ attribute, which represents the pending change in size. For example:
Note that changes in resource size may require a device reload to properly
take effect.
Port-level Resources and Full Dump
==================================
In addition to device-level resources, ``devlink`` also supports port-level
resources. These resources are associated with a specific devlink port rather
than the device as a whole.
To list resources for all devlink devices and ports:
.. code:: shell
$ devlink resource show
pci/0000:03:00.0:
name max_local_SFs size 128 unit entry dpipe_tables none
name max_external_SFs size 128 unit entry dpipe_tables none
pci/0000:03:00.0/196608:
name max_SFs size 128 unit entry dpipe_tables none
pci/0000:03:00.0/196609:
name max_SFs size 128 unit entry dpipe_tables none
pci/0000:03:00.1:
name max_local_SFs size 128 unit entry dpipe_tables none
name max_external_SFs size 128 unit entry dpipe_tables none
pci/0000:03:00.1/196708:
name max_SFs size 128 unit entry dpipe_tables none
pci/0000:03:00.1/196709:
name max_SFs size 128 unit entry dpipe_tables none
To show resources for a specific port:
.. code:: shell
$ devlink resource show pci/0000:03:00.0/196608
pci/0000:03:00.0/196608:
name max_SFs size 128 unit entry dpipe_tables none
Resource Scope Filtering
========================
When dumping resources for all devices, ``devlink resource show`` accepts
an optional ``scope`` parameter to restrict the response to device-level
resources, port-level resources, or both (the default).
To dump only device-level resources across all devices:
.. code:: shell
$ devlink resource show scope dev
pci/0000:03:00.0:
name max_local_SFs size 128 unit entry dpipe_tables none
name max_external_SFs size 128 unit entry dpipe_tables none
pci/0000:03:00.1:
name max_local_SFs size 128 unit entry dpipe_tables none
name max_external_SFs size 128 unit entry dpipe_tables none
To dump only port-level resources across all devices:
.. code:: shell
$ devlink resource show scope port
pci/0000:03:00.0/196608:
name max_SFs size 128 unit entry dpipe_tables none
pci/0000:03:00.0/196609:
name max_SFs size 128 unit entry dpipe_tables none
pci/0000:03:00.1/196708:
name max_SFs size 128 unit entry dpipe_tables none
pci/0000:03:00.1/196709:
name max_SFs size 128 unit entry dpipe_tables none
Note that port-level resources are read-only.
@@ -0,0 +1,97 @@
.. SPDX-License-Identifier: GPL-2.0
========================
Devlink Shared Instances
========================
Overview
========
Shared devlink instances allow multiple physical functions (PFs) on the same
chip to share a devlink instance for chip-wide operations.
Multiple PFs may reside on the same physical chip, running a single firmware.
Some of the resources and configurations may be shared among these PFs. The
shared devlink instance provides an object to pin configuration knobs on.
There are two possible usage models:
1. The shared devlink instance is used alongside individual PF devlink
instances, providing chip-wide configuration in addition to per-PF
configuration.
2. The shared devlink instance is the only devlink instance, without
per-PF instances.
It is up to the driver to decide which usage model to use.
The shared devlink instance is not backed by any struct *device*.
Implementation
==============
Architecture
------------
The implementation uses:
* **Chip identification**: PFs are grouped by chip using a driver-specific identifier
* **Shared instance management**: Global list of shared instances with reference counting
API Functions
-------------
The following functions are provided for managing shared devlink instances:
* ``devlink_shd_get()``: Get or create a shared devlink instance identified by a string ID
* ``devlink_shd_put()``: Release a reference on a shared devlink instance
* ``devlink_shd_get_priv()``: Get private data from shared devlink instance
Initialization Flow
-------------------
1. **PF calls shared devlink init** during driver probe
2. **Chip identification** using driver-specific method to determine device identity
3. **Get or create shared instance** using ``devlink_shd_get()``:
* The function looks up existing instance by identifier
* If none exists, creates new instance:
- Allocates and registers devlink instance
- Adds to global shared instances list
- Increments reference count
4. **Set nested devlink instance** for the PF devlink instance using
``devl_nested_devlink_set()`` before registering the PF devlink instance
Cleanup Flow
------------
1. **Cleanup** when PF is removed
2. **Call** ``devlink_shd_put()`` to release reference (decrements reference count)
3. **Shared instance is automatically destroyed** when the last PF removes (reference count reaches zero)
Chip Identification
-------------------
PFs belonging to the same chip are identified using a driver-specific method.
The driver is free to choose any identifier that is suitable for determining
whether two PFs are part of the same device. Examples include:
* **PCI VPD serial numbers**: Extract from PCI VPD
* **Device tree properties**: Read chip identifier from device tree
* **Other hardware-specific identifiers**: Any unique identifier that groups PFs by chip
Locking
-------
A global mutex (``shd_mutex``) protects the shared instances list during registration/deregistration.
Similarly to other nested devlink instance relationships, devlink lock of
the shared instance should be always taken after the devlink lock of PF.
Reference Counting
------------------
Each shared devlink instance maintains a reference count (``refcount_t refcount``).
The reference count is incremented when ``devlink_shd_get()`` is called and decremented
when ``devlink_shd_put()`` is called. When the reference count reaches zero, the shared
instance is automatically destroyed.
@@ -516,9 +516,11 @@ Generic Packet Trap Groups
Generic packet trap groups are used to aggregate logically related packet
traps. These groups allow the user to batch operations such as setting the trap
action of all member traps. In addition, ``devlink-trap`` can report aggregated
per-group packets and bytes statistics, in case per-trap statistics are too
narrow. The description of these groups must be added to the following table:
action of all member drop traps whose action may legally change. Exception and
control traps remain unchanged. In addition, ``devlink-trap`` can report
aggregated per-group packets and bytes statistics, in case per-trap statistics
are too narrow. The description of these groups must be added to the following
table:
.. list-table:: List of Generic Packet Trap Groups
:widths: 10 90
+8 -5
View File
@@ -13,8 +13,8 @@ new APIs prefixed by ``devl_*``. The older APIs handle all the locking
in devlink core, but don't allow registration of most sub-objects once
the main devlink object is itself registered. The newer ``devl_*`` APIs assume
the devlink instance lock is already held. Drivers can take the instance
lock by calling ``devl_lock()``. It is also held all callbacks of devlink
netlink commands.
lock by calling ``devl_lock()``. It is also held across all callbacks of
devlink netlink commands.
Drivers are encouraged to use the devlink instance lock for their own needs.
@@ -33,11 +33,11 @@ sure to respect following rules:
lock of both nested and parent instances at the same time, devlink
instance lock of the parent instance should be taken first, only then
instance lock of the nested instance could be taken.
- Driver should use object-specific helpers to setup the
nested relationship:
- Driver should use object-specific helpers to setup the nested relationship
before registering the nested devlink instance:
- ``devl_nested_devlink_set()`` - called to setup devlink -> nested
devlink relationship (could be user for multiple nested instances.
devlink relationship (could be used for multiple nested instances).
- ``devl_port_fn_devlink_set()`` - called to setup port function ->
nested devlink relationship.
- ``devlink_linecard_nested_dl_set()`` - called to setup linecard ->
@@ -68,6 +68,7 @@ general.
devlink-resource
devlink-selftests
devlink-trap
devlink-shared
Driver-specific documentation
-----------------------------
@@ -87,6 +88,8 @@ parameters, info versions, and other features it supports.
ionic
iosm
ixgbe
kvaser_pciefd
kvaser_usb
mlx4
mlx5
mlxsw
@@ -0,0 +1,24 @@
.. SPDX-License-Identifier: GPL-2.0
=============================
kvaser_pciefd devlink support
=============================
This document describes the devlink features implemented by the
``kvaser_pciefd`` device driver.
Info versions
=============
The ``kvaser_pciefd`` driver reports the following versions
.. list-table:: devlink info versions implemented
:widths: 5 5 90
* - Name
- Type
- Description
* - ``fw``
- running
- Version of the firmware running on the device. Also available
through ``ethtool -i`` as ``firmware-version``.
@@ -0,0 +1,33 @@
.. SPDX-License-Identifier: GPL-2.0
==========================
kvaser_usb devlink support
==========================
This document describes the devlink features implemented by the
``kvaser_usb`` device driver.
Info versions
=============
The ``kvaser_usb`` driver reports the following versions
.. list-table:: devlink info versions implemented
:widths: 5 5 90
* - Name
- Type
- Description
* - ``fw``
- running
- Version of the firmware running on the device. Also available
through ``ethtool -i`` as ``firmware-version``.
* - ``board.rev``
- fixed
- The device hardware revision.
* - ``board.id``
- fixed
- The device EAN (product number).
* - ``serial_number``
- fixed
- The device serial number.
@@ -24,7 +24,8 @@ static int otx2_cpt_dl_egrp_delete(struct devlink *dl, u32 id,
}
static int otx2_cpt_dl_uc_info(struct devlink *dl, u32 id,
struct devlink_param_gset_ctx *ctx)
struct devlink_param_gset_ctx *ctx,
struct netlink_ext_ack *extack)
{
ctx->val.vstr[0] = '\0';
@@ -32,7 +33,8 @@ static int otx2_cpt_dl_uc_info(struct devlink *dl, u32 id,
}
static int otx2_cpt_dl_t106_mode_get(struct devlink *dl, u32 id,
struct devlink_param_gset_ctx *ctx)
struct devlink_param_gset_ctx *ctx,
struct netlink_ext_ack *extack)
{
struct otx2_cpt_devlink *cpt_dl = devlink_priv(dl);
struct otx2_cptpf_dev *cptpf = cpt_dl->cptpf;
+3 -3
View File
@@ -315,10 +315,10 @@ EXPORT_SYMBOL_NS_GPL(zl3073x_devm_alloc, "ZL3073X");
static int
zl3073x_devlink_param_clock_id_validate(struct devlink *devlink, u32 id,
union devlink_param_value val,
union devlink_param_value *val,
struct netlink_ext_ack *extack)
{
if (!val.vu64) {
if (!val->vu64) {
NL_SET_ERR_MSG_MOD(extack, "'clock_id' must be non-zero");
return -EINVAL;
}
@@ -377,7 +377,7 @@ int zl3073x_devlink_register(struct zl3073x_dev *zldev)
value.vu64 = zldev->clock_id;
devl_param_driverinit_value_set(devlink,
DEVLINK_PARAM_GENERIC_ID_CLOCK_ID,
value);
&value);
/* Register devlink instance */
devl_register(devlink);
@@ -8,12 +8,12 @@
#include "ena_phc.h"
static int ena_devlink_enable_phc_validate(struct devlink *devlink, u32 id,
union devlink_param_value val,
union devlink_param_value *val,
struct netlink_ext_ack *extack)
{
struct ena_adapter *adapter = ENA_DEVLINK_PRIV(devlink);
if (!val.vbool)
if (!val->vbool)
return 0;
if (!ena_com_phc_supported(adapter->ena_dev)) {
@@ -57,7 +57,7 @@ void ena_devlink_disable_phc_param(struct devlink *devlink)
value.vbool = false;
devl_param_driverinit_value_set(devlink,
DEVLINK_PARAM_GENERIC_ID_ENABLE_PHC,
value);
&value);
devl_unlock(devlink);
}
@@ -151,7 +151,7 @@ static int ena_devlink_configure_params(struct devlink *devlink)
value.vbool = ena_phc_is_enabled(adapter);
devl_param_driverinit_value_set(devlink,
DEVLINK_PARAM_GENERIC_ID_ENABLE_PHC,
value);
&value);
devl_unlock(devlink);
return 0;
+3 -2
View File
@@ -254,12 +254,13 @@ int pdsc_dl_flash_update(struct devlink *dl,
struct devlink_flash_update_params *params,
struct netlink_ext_ack *extack);
int pdsc_dl_enable_get(struct devlink *dl, u32 id,
struct devlink_param_gset_ctx *ctx);
struct devlink_param_gset_ctx *ctx,
struct netlink_ext_ack *extack);
int pdsc_dl_enable_set(struct devlink *dl, u32 id,
struct devlink_param_gset_ctx *ctx,
struct netlink_ext_ack *extack);
int pdsc_dl_enable_validate(struct devlink *dl, u32 id,
union devlink_param_value val,
union devlink_param_value *val,
struct netlink_ext_ack *extack);
void __iomem *pdsc_map_dbpage(struct pdsc *pdsc, int page_num);
+3 -2
View File
@@ -22,7 +22,8 @@ pdsc_viftype *pdsc_dl_find_viftype_by_id(struct pdsc *pdsc,
}
int pdsc_dl_enable_get(struct devlink *dl, u32 id,
struct devlink_param_gset_ctx *ctx)
struct devlink_param_gset_ctx *ctx,
struct netlink_ext_ack *extack)
{
struct pdsc *pdsc = devlink_priv(dl);
struct pdsc_viftype *vt_entry;
@@ -64,7 +65,7 @@ int pdsc_dl_enable_set(struct devlink *dl, u32 id,
}
int pdsc_dl_enable_validate(struct devlink *dl, u32 id,
union devlink_param_value val,
union devlink_param_value *val,
struct netlink_ext_ack *extack)
{
struct pdsc *pdsc = devlink_priv(dl);
@@ -1086,7 +1086,8 @@ static int bnxt_hwrm_nvm_req(struct bnxt *bp, u32 param_id, void *msg,
}
static int bnxt_dl_nvm_param_get(struct devlink *dl, u32 id,
struct devlink_param_gset_ctx *ctx)
struct devlink_param_gset_ctx *ctx,
struct netlink_ext_ack *extack)
{
struct bnxt *bp = bnxt_get_bp_from_dl(dl);
struct hwrm_nvm_get_variable_input *req;
@@ -1122,7 +1123,7 @@ static int bnxt_dl_nvm_param_set(struct devlink *dl, u32 id,
}
static int bnxt_dl_roce_validate(struct devlink *dl, u32 id,
union devlink_param_value val,
union devlink_param_value *val,
struct netlink_ext_ack *extack)
{
const struct bnxt_dl_nvm_param nvm_roce_cap = {0, NVM_OFF_RDMA_CAPABLE,
@@ -1148,7 +1149,7 @@ static int bnxt_dl_roce_validate(struct devlink *dl, u32 id,
}
static int bnxt_dl_msix_validate(struct devlink *dl, u32 id,
union devlink_param_value val,
union devlink_param_value *val,
struct netlink_ext_ack *extack)
{
int max_val = -1;
@@ -1159,7 +1160,7 @@ static int bnxt_dl_msix_validate(struct devlink *dl, u32 id,
if (id == DEVLINK_PARAM_GENERIC_ID_MSIX_VEC_PER_PF_MIN)
max_val = BNXT_MSIX_VEC_MIN_MAX;
if (val.vu32 > max_val) {
if (val->vu32 > max_val) {
NL_SET_ERR_MSG_MOD(extack, "MSIX value is exceeding the range");
return -EINVAL;
}
@@ -1168,7 +1169,8 @@ static int bnxt_dl_msix_validate(struct devlink *dl, u32 id,
}
static int bnxt_remote_dev_reset_get(struct devlink *dl, u32 id,
struct devlink_param_gset_ctx *ctx)
struct devlink_param_gset_ctx *ctx,
struct netlink_ext_ack *extack)
{
struct bnxt *bp = bnxt_get_bp_from_dl(dl);
@@ -24,7 +24,8 @@ static int i40e_max_mac_per_vf_set(struct devlink *devlink,
static int i40e_max_mac_per_vf_get(struct devlink *devlink,
u32 id,
struct devlink_param_gset_ctx *ctx)
struct devlink_param_gset_ctx *ctx,
struct netlink_ext_ack *extack)
{
struct i40e_pf *pf = devlink_priv(devlink);
@@ -611,11 +611,13 @@ exit_release_res:
* @devlink: pointer to the devlink instance
* @id: the parameter ID to set
* @ctx: context to store the parameter value
* @extack: netlink extended ACK structure
*
* Return: zero on success and negative value on failure.
*/
static int ice_devlink_tx_sched_layers_get(struct devlink *devlink, u32 id,
struct devlink_param_gset_ctx *ctx)
struct devlink_param_gset_ctx *ctx,
struct netlink_ext_ack *extack)
{
struct ice_pf *pf = devlink_priv(devlink);
int err;
@@ -669,10 +671,10 @@ static int ice_devlink_tx_sched_layers_set(struct devlink *devlink, u32 id,
* error.
*/
static int ice_devlink_tx_sched_layers_validate(struct devlink *devlink, u32 id,
union devlink_param_value val,
union devlink_param_value *val,
struct netlink_ext_ack *extack)
{
if (val.vu8 != ICE_SCHED_5_LAYERS && val.vu8 != ICE_SCHED_9_LAYERS) {
if (val->vu8 != ICE_SCHED_5_LAYERS && val->vu8 != ICE_SCHED_9_LAYERS) {
NL_SET_ERR_MSG_MOD(extack,
"Wrong number of tx scheduler layers provided.");
return -EINVAL;
@@ -1352,7 +1354,8 @@ static const struct devlink_ops ice_sf_devlink_ops;
static int
ice_devlink_enable_roce_get(struct devlink *devlink, u32 id,
struct devlink_param_gset_ctx *ctx)
struct devlink_param_gset_ctx *ctx,
struct netlink_ext_ack *extack)
{
struct ice_pf *pf = devlink_priv(devlink);
struct iidc_rdma_core_dev_info *cdev;
@@ -1395,7 +1398,7 @@ static int ice_devlink_enable_roce_set(struct devlink *devlink, u32 id,
static int
ice_devlink_enable_roce_validate(struct devlink *devlink, u32 id,
union devlink_param_value val,
union devlink_param_value *val,
struct netlink_ext_ack *extack)
{
struct ice_pf *pf = devlink_priv(devlink);
@@ -1418,7 +1421,8 @@ ice_devlink_enable_roce_validate(struct devlink *devlink, u32 id,
static int
ice_devlink_enable_iw_get(struct devlink *devlink, u32 id,
struct devlink_param_gset_ctx *ctx)
struct devlink_param_gset_ctx *ctx,
struct netlink_ext_ack *extack)
{
struct ice_pf *pf = devlink_priv(devlink);
struct iidc_rdma_core_dev_info *cdev;
@@ -1461,7 +1465,7 @@ static int ice_devlink_enable_iw_set(struct devlink *devlink, u32 id,
static int
ice_devlink_enable_iw_validate(struct devlink *devlink, u32 id,
union devlink_param_value val,
union devlink_param_value *val,
struct netlink_ext_ack *extack)
{
struct ice_pf *pf = devlink_priv(devlink);
@@ -1525,11 +1529,13 @@ static int ice_devlink_local_fwd_str_to_mode(const char *mode_str)
* @devlink: Pointer to the devlink instance.
* @id: The parameter ID to set.
* @ctx: Context to store the parameter value.
* @extack: netlink extended ACK structure
*
* Return: Zero.
*/
static int ice_devlink_local_fwd_get(struct devlink *devlink, u32 id,
struct devlink_param_gset_ctx *ctx)
struct devlink_param_gset_ctx *ctx,
struct netlink_ext_ack *extack)
{
struct ice_pf *pf = devlink_priv(devlink);
struct ice_port_info *pi;
@@ -1585,10 +1591,10 @@ static int ice_devlink_local_fwd_set(struct devlink *devlink, u32 id,
* error.
*/
static int ice_devlink_local_fwd_validate(struct devlink *devlink, u32 id,
union devlink_param_value val,
union devlink_param_value *val,
struct netlink_ext_ack *extack)
{
if (ice_devlink_local_fwd_str_to_mode(val.vstr) < 0) {
if (ice_devlink_local_fwd_str_to_mode(val->vstr) < 0) {
NL_SET_ERR_MSG_MOD(extack, "Error: Requested value is not supported.");
return -EINVAL;
}
@@ -1598,12 +1604,12 @@ static int ice_devlink_local_fwd_validate(struct devlink *devlink, u32 id,
static int
ice_devlink_msix_max_pf_validate(struct devlink *devlink, u32 id,
union devlink_param_value val,
union devlink_param_value *val,
struct netlink_ext_ack *extack)
{
struct ice_pf *pf = devlink_priv(devlink);
if (val.vu32 > pf->hw.func_caps.common_cap.num_msix_vectors)
if (val->vu32 > pf->hw.func_caps.common_cap.num_msix_vectors)
return -EINVAL;
return 0;
@@ -1611,21 +1617,21 @@ ice_devlink_msix_max_pf_validate(struct devlink *devlink, u32 id,
static int
ice_devlink_msix_min_pf_validate(struct devlink *devlink, u32 id,
union devlink_param_value val,
union devlink_param_value *val,
struct netlink_ext_ack *extack)
{
if (val.vu32 < ICE_MIN_MSIX)
if (val->vu32 < ICE_MIN_MSIX)
return -EINVAL;
return 0;
}
static int ice_devlink_enable_rdma_validate(struct devlink *devlink, u32 id,
union devlink_param_value val,
union devlink_param_value *val,
struct netlink_ext_ack *extack)
{
struct ice_pf *pf = devlink_priv(devlink);
bool new_state = val.vbool;
bool new_state = val->vbool;
if (new_state && !test_bit(ICE_FLAG_RDMA_ENA, pf->flags))
return -EOPNOTSUPP;
@@ -1785,16 +1791,16 @@ int ice_devlink_register_params(struct ice_pf *pf)
value.vu32 = pf->msix.max;
devl_param_driverinit_value_set(devlink,
DEVLINK_PARAM_GENERIC_ID_MSIX_VEC_PER_PF_MAX,
value);
&value);
value.vu32 = pf->msix.min;
devl_param_driverinit_value_set(devlink,
DEVLINK_PARAM_GENERIC_ID_MSIX_VEC_PER_PF_MIN,
value);
&value);
value.vbool = test_bit(ICE_FLAG_RDMA_ENA, pf->flags);
devl_param_driverinit_value_set(devlink,
DEVLINK_PARAM_GENERIC_ID_ENABLE_RDMA,
value);
&value);
return 0;
@@ -1179,12 +1179,12 @@ static void rvu_health_reporters_destroy(struct rvu *rvu)
/* Devlink Params APIs */
static int rvu_af_dl_dwrr_mtu_validate(struct devlink *devlink, u32 id,
union devlink_param_value val,
union devlink_param_value *val,
struct netlink_ext_ack *extack)
{
struct rvu_devlink *rvu_dl = devlink_priv(devlink);
struct rvu *rvu = rvu_dl->rvu;
int dwrr_mtu = val.vu32;
int dwrr_mtu = val->vu32;
struct nix_txsch *txsch;
struct nix_hw *nix_hw;
@@ -1233,7 +1233,8 @@ static int rvu_af_dl_dwrr_mtu_set(struct devlink *devlink, u32 id,
}
static int rvu_af_dl_dwrr_mtu_get(struct devlink *devlink, u32 id,
struct devlink_param_gset_ctx *ctx)
struct devlink_param_gset_ctx *ctx,
struct netlink_ext_ack *extack)
{
struct rvu_devlink *rvu_dl = devlink_priv(devlink);
struct rvu *rvu = rvu_dl->rvu;
@@ -1259,7 +1260,8 @@ enum rvu_af_dl_param_id {
};
static int rvu_af_npc_exact_feature_get(struct devlink *devlink, u32 id,
struct devlink_param_gset_ctx *ctx)
struct devlink_param_gset_ctx *ctx,
struct netlink_ext_ack *extack)
{
struct rvu_devlink *rvu_dl = devlink_priv(devlink);
struct rvu *rvu = rvu_dl->rvu;
@@ -1286,14 +1288,14 @@ static int rvu_af_npc_exact_feature_disable(struct devlink *devlink, u32 id,
}
static int rvu_af_npc_exact_feature_validate(struct devlink *devlink, u32 id,
union devlink_param_value val,
union devlink_param_value *val,
struct netlink_ext_ack *extack)
{
struct rvu_devlink *rvu_dl = devlink_priv(devlink);
struct rvu *rvu = rvu_dl->rvu;
u64 enable;
if (kstrtoull(val.vstr, 10, &enable)) {
if (kstrtoull(val->vstr, 10, &enable)) {
NL_SET_ERR_MSG_MOD(extack,
"Only 1 value is supported");
return -EINVAL;
@@ -1314,7 +1316,8 @@ static int rvu_af_npc_exact_feature_validate(struct devlink *devlink, u32 id,
}
static int rvu_af_dl_npc_mcam_high_zone_percent_get(struct devlink *devlink, u32 id,
struct devlink_param_gset_ctx *ctx)
struct devlink_param_gset_ctx *ctx,
struct netlink_ext_ack *extack)
{
struct rvu_devlink *rvu_dl = devlink_priv(devlink);
struct rvu *rvu = rvu_dl->rvu;
@@ -1348,7 +1351,7 @@ static int rvu_af_dl_npc_mcam_high_zone_percent_set(struct devlink *devlink, u32
}
static int rvu_af_dl_npc_mcam_high_zone_percent_validate(struct devlink *devlink, u32 id,
union devlink_param_value val,
union devlink_param_value *val,
struct netlink_ext_ack *extack)
{
struct rvu_devlink *rvu_dl = devlink_priv(devlink);
@@ -1356,7 +1359,7 @@ static int rvu_af_dl_npc_mcam_high_zone_percent_validate(struct devlink *devlink
struct npc_mcam *mcam;
/* The percent of high prio zone must range from 12% to 100% of unreserved mcam space */
if (val.vu8 < 12 || val.vu8 > 100) {
if (val->vu8 < 12 || val->vu8 > 100) {
NL_SET_ERR_MSG_MOD(extack,
"mcam high zone percent must be between 12% to 100%");
return -EINVAL;
@@ -1376,7 +1379,8 @@ static int rvu_af_dl_npc_mcam_high_zone_percent_validate(struct devlink *devlink
}
static int rvu_af_dl_npc_def_rule_cntr_get(struct devlink *devlink, u32 id,
struct devlink_param_gset_ctx *ctx)
struct devlink_param_gset_ctx *ctx,
struct netlink_ext_ack *extack)
{
struct rvu_devlink *rvu_dl = devlink_priv(devlink);
struct rvu *rvu = rvu_dl->rvu;
@@ -1402,7 +1406,8 @@ static int rvu_af_dl_npc_def_rule_cntr_set(struct devlink *devlink, u32 id,
}
static int rvu_af_dl_nix_maxlf_get(struct devlink *devlink, u32 id,
struct devlink_param_gset_ctx *ctx)
struct devlink_param_gset_ctx *ctx,
struct netlink_ext_ack *extack)
{
struct rvu_devlink *rvu_dl = devlink_priv(devlink);
struct rvu *rvu = rvu_dl->rvu;
@@ -1436,7 +1441,7 @@ static int rvu_af_dl_nix_maxlf_set(struct devlink *devlink, u32 id,
}
static int rvu_af_dl_nix_maxlf_validate(struct devlink *devlink, u32 id,
union devlink_param_value val,
union devlink_param_value *val,
struct netlink_ext_ack *extack)
{
struct rvu_devlink *rvu_dl = devlink_priv(devlink);
@@ -1460,13 +1465,13 @@ static int rvu_af_dl_nix_maxlf_validate(struct devlink *devlink, u32 id,
return -EPERM;
}
if (max_nix0_lf && val.vu16 > max_nix0_lf) {
if (max_nix0_lf && val->vu16 > max_nix0_lf) {
NL_SET_ERR_MSG_MOD(extack,
"requested nixlf is greater than the max supported nix0_lf");
return -EPERM;
}
if (max_nix1_lf && val.vu16 > max_nix1_lf) {
if (max_nix1_lf && val->vu16 > max_nix1_lf) {
NL_SET_ERR_MSG_MOD(extack,
"requested nixlf is greater than the max supported nix1_lf");
return -EINVAL;
@@ -8,7 +8,7 @@
/* Devlink Params APIs */
static int otx2_dl_mcam_count_validate(struct devlink *devlink, u32 id,
union devlink_param_value val,
union devlink_param_value *val,
struct netlink_ext_ack *extack)
{
struct otx2_devlink *otx2_dl = devlink_priv(devlink);
@@ -48,7 +48,8 @@ static int otx2_dl_mcam_count_set(struct devlink *devlink, u32 id,
}
static int otx2_dl_mcam_count_get(struct devlink *devlink, u32 id,
struct devlink_param_gset_ctx *ctx)
struct devlink_param_gset_ctx *ctx,
struct netlink_ext_ack *extack)
{
struct otx2_devlink *otx2_dl = devlink_priv(devlink);
struct otx2_nic *pfvf = otx2_dl->pfvf;
@@ -84,7 +85,8 @@ static int otx2_dl_ucast_flt_cnt_set(struct devlink *devlink, u32 id,
}
static int otx2_dl_ucast_flt_cnt_get(struct devlink *devlink, u32 id,
struct devlink_param_gset_ctx *ctx)
struct devlink_param_gset_ctx *ctx,
struct netlink_ext_ack *extack)
{
struct otx2_devlink *otx2_dl = devlink_priv(devlink);
struct otx2_nic *pfvf = otx2_dl->pfvf;
@@ -95,7 +97,7 @@ static int otx2_dl_ucast_flt_cnt_get(struct devlink *devlink, u32 id,
}
static int otx2_dl_ucast_flt_cnt_validate(struct devlink *devlink, u32 id,
union devlink_param_value val,
union devlink_param_value *val,
struct netlink_ext_ack *extack)
{
struct otx2_devlink *otx2_dl = devlink_priv(devlink);
+11 -9
View File
@@ -172,7 +172,8 @@ MODULE_PARM_DESC(port_type_array, "Array of port types: HW_DEFAULT (0) is defaul
static atomic_t pf_loading = ATOMIC_INIT(0);
static int mlx4_devlink_ierr_reset_get(struct devlink *devlink, u32 id,
struct devlink_param_gset_ctx *ctx)
struct devlink_param_gset_ctx *ctx,
struct netlink_ext_ack *extack)
{
ctx->val.vbool = !!mlx4_internal_err_reset;
return 0;
@@ -187,7 +188,8 @@ static int mlx4_devlink_ierr_reset_set(struct devlink *devlink, u32 id,
}
static int mlx4_devlink_crdump_snapshot_get(struct devlink *devlink, u32 id,
struct devlink_param_gset_ctx *ctx)
struct devlink_param_gset_ctx *ctx,
struct netlink_ext_ack *extack)
{
struct mlx4_priv *priv = devlink_priv(devlink);
struct mlx4_dev *dev = &priv->dev;
@@ -209,10 +211,10 @@ static int mlx4_devlink_crdump_snapshot_set(struct devlink *devlink, u32 id,
static int
mlx4_devlink_max_macs_validate(struct devlink *devlink, u32 id,
union devlink_param_value val,
union devlink_param_value *val,
struct netlink_ext_ack *extack)
{
u32 value = val.vu32;
u32 value = val->vu32;
if (value < 1 || value > 128)
return -ERANGE;
@@ -262,27 +264,27 @@ static void mlx4_devlink_set_params_init_values(struct devlink *devlink)
value.vbool = !!mlx4_internal_err_reset;
devl_param_driverinit_value_set(devlink,
DEVLINK_PARAM_GENERIC_ID_INT_ERR_RESET,
value);
&value);
value.vu32 = 1UL << log_num_mac;
devl_param_driverinit_value_set(devlink,
DEVLINK_PARAM_GENERIC_ID_MAX_MACS,
value);
&value);
value.vbool = enable_64b_cqe_eqe;
devl_param_driverinit_value_set(devlink,
MLX4_DEVLINK_PARAM_ID_ENABLE_64B_CQE_EQE,
value);
&value);
value.vbool = enable_4k_uar;
devl_param_driverinit_value_set(devlink,
MLX4_DEVLINK_PARAM_ID_ENABLE_4K_UAR,
value);
&value);
value.vbool = false;
devl_param_driverinit_value_set(devlink,
DEVLINK_PARAM_GENERIC_ID_REGION_SNAPSHOT,
value);
&value);
}
static inline void mlx4_set_num_reserved_uars(struct mlx4_dev *dev,
@@ -461,11 +461,11 @@ void mlx5_devlink_free(struct devlink *devlink)
}
static int mlx5_devlink_enable_roce_validate(struct devlink *devlink, u32 id,
union devlink_param_value val,
union devlink_param_value *val,
struct netlink_ext_ack *extack)
{
struct mlx5_core_dev *dev = devlink_priv(devlink);
bool new_state = val.vbool;
bool new_state = val->vbool;
if (new_state && !MLX5_CAP_GEN(dev, roce) &&
!(MLX5_CAP_GEN(dev, roce_rw_supported) && MLX5_CAP_GEN_MAX(dev, roce))) {
@@ -482,10 +482,10 @@ static int mlx5_devlink_enable_roce_validate(struct devlink *devlink, u32 id,
#ifdef CONFIG_MLX5_ESWITCH
static int mlx5_devlink_large_group_num_validate(struct devlink *devlink, u32 id,
union devlink_param_value val,
union devlink_param_value *val,
struct netlink_ext_ack *extack)
{
int group_num = val.vu32;
int group_num = val->vu32;
if (group_num < 1 || group_num > 1024) {
NL_SET_ERR_MSG_MOD(extack,
@@ -498,27 +498,27 @@ static int mlx5_devlink_large_group_num_validate(struct devlink *devlink, u32 id
#endif
static int mlx5_devlink_eq_depth_validate(struct devlink *devlink, u32 id,
union devlink_param_value val,
union devlink_param_value *val,
struct netlink_ext_ack *extack)
{
return (val.vu32 >= 64 && val.vu32 <= 4096) ? 0 : -EINVAL;
return (val->vu32 >= 64 && val->vu32 <= 4096) ? 0 : -EINVAL;
}
static int
mlx5_devlink_hairpin_num_queues_validate(struct devlink *devlink, u32 id,
union devlink_param_value val,
union devlink_param_value *val,
struct netlink_ext_ack *extack)
{
return val.vu32 ? 0 : -EINVAL;
return val->vu32 ? 0 : -EINVAL;
}
static int
mlx5_devlink_hairpin_queue_size_validate(struct devlink *devlink, u32 id,
union devlink_param_value val,
union devlink_param_value *val,
struct netlink_ext_ack *extack)
{
struct mlx5_core_dev *dev = devlink_priv(devlink);
u32 val32 = val.vu32;
u32 val32 = val->vu32;
if (!is_power_of_2(val32)) {
NL_SET_ERR_MSG_MOD(extack, "Value is not power of two");
@@ -550,13 +550,13 @@ static void mlx5_devlink_hairpin_params_init_values(struct devlink *devlink)
value.vu32 = link_speed64;
devl_param_driverinit_value_set(
devlink, MLX5_DEVLINK_PARAM_ID_HAIRPIN_NUM_QUEUES, value);
devlink, MLX5_DEVLINK_PARAM_ID_HAIRPIN_NUM_QUEUES, &value);
value.vu32 =
BIT(min_t(u32, 16 - MLX5_MPWRQ_MIN_LOG_STRIDE_SZ(dev),
MLX5_CAP_GEN(dev, log_max_hairpin_num_packets)));
devl_param_driverinit_value_set(
devlink, MLX5_DEVLINK_PARAM_ID_HAIRPIN_QUEUE_SIZE, value);
devlink, MLX5_DEVLINK_PARAM_ID_HAIRPIN_QUEUE_SIZE, &value);
}
static const struct devlink_param mlx5_devlink_params[] = {
@@ -583,24 +583,24 @@ static void mlx5_devlink_set_params_init_values(struct devlink *devlink)
value.vbool = MLX5_CAP_GEN(dev, roce) && !mlx5_dev_is_lightweight(dev);
devl_param_driverinit_value_set(devlink,
DEVLINK_PARAM_GENERIC_ID_ENABLE_ROCE,
value);
&value);
#ifdef CONFIG_MLX5_ESWITCH
value.vu32 = ESW_OFFLOADS_DEFAULT_NUM_GROUPS;
devl_param_driverinit_value_set(devlink,
MLX5_DEVLINK_PARAM_ID_ESW_LARGE_GROUP_NUM,
value);
&value);
#endif
value.vu32 = MLX5_COMP_EQ_SIZE;
devl_param_driverinit_value_set(devlink,
DEVLINK_PARAM_GENERIC_ID_IO_EQ_SIZE,
value);
&value);
value.vu32 = MLX5_NUM_ASYNC_EQE;
devl_param_driverinit_value_set(devlink,
DEVLINK_PARAM_GENERIC_ID_EVENT_EQ_SIZE,
value);
&value);
}
static const struct devlink_param mlx5_devlink_eth_params[] = {
@@ -633,7 +633,7 @@ static int mlx5_devlink_eth_params_register(struct devlink *devlink)
value.vbool = !mlx5_dev_is_lightweight(dev);
devl_param_driverinit_value_set(devlink,
DEVLINK_PARAM_GENERIC_ID_ENABLE_ETH,
value);
&value);
mlx5_devlink_hairpin_params_init_values(devlink);
@@ -657,12 +657,12 @@ static void mlx5_devlink_eth_params_unregister(struct devlink *devlink)
static int
mlx5_devlink_pcie_cong_thresh_validate(struct devlink *devl, u32 id,
union devlink_param_value val,
union devlink_param_value *val,
struct netlink_ext_ack *extack)
{
if (val.vu16 > MLX5_PCIE_CONG_THRESH_MAX) {
if (val->vu16 > MLX5_PCIE_CONG_THRESH_MAX) {
NL_SET_ERR_MSG_FMT_MOD(extack, "Value %u > max supported (%u)",
val.vu16, MLX5_PCIE_CONG_THRESH_MAX);
val->vu16, MLX5_PCIE_CONG_THRESH_MAX);
return -EINVAL;
}
@@ -687,19 +687,19 @@ static void mlx5_devlink_pcie_cong_init_values(struct devlink *devlink)
value.vu16 = MLX5_PCIE_CONG_THRESH_DEF_LOW;
id = MLX5_DEVLINK_PARAM_ID_PCIE_CONG_IN_LOW;
devl_param_driverinit_value_set(devlink, id, value);
devl_param_driverinit_value_set(devlink, id, &value);
value.vu16 = MLX5_PCIE_CONG_THRESH_DEF_HIGH;
id = MLX5_DEVLINK_PARAM_ID_PCIE_CONG_IN_HIGH;
devl_param_driverinit_value_set(devlink, id, value);
devl_param_driverinit_value_set(devlink, id, &value);
value.vu16 = MLX5_PCIE_CONG_THRESH_DEF_LOW;
id = MLX5_DEVLINK_PARAM_ID_PCIE_CONG_OUT_LOW;
devl_param_driverinit_value_set(devlink, id, value);
devl_param_driverinit_value_set(devlink, id, &value);
value.vu16 = MLX5_PCIE_CONG_THRESH_DEF_HIGH;
id = MLX5_DEVLINK_PARAM_ID_PCIE_CONG_OUT_HIGH;
devl_param_driverinit_value_set(devlink, id, value);
devl_param_driverinit_value_set(devlink, id, &value);
}
static const struct devlink_param mlx5_devlink_pcie_cong_params[] = {
@@ -751,11 +751,11 @@ static void mlx5_devlink_pcie_cong_params_unregister(struct devlink *devlink)
}
static int mlx5_devlink_enable_rdma_validate(struct devlink *devlink, u32 id,
union devlink_param_value val,
union devlink_param_value *val,
struct netlink_ext_ack *extack)
{
struct mlx5_core_dev *dev = devlink_priv(devlink);
bool new_state = val.vbool;
bool new_state = val->vbool;
if (new_state && !mlx5_rdma_supported(dev))
return -EOPNOTSUPP;
@@ -784,7 +784,7 @@ static int mlx5_devlink_rdma_params_register(struct devlink *devlink)
value.vbool = !mlx5_dev_is_lightweight(dev);
devl_param_driverinit_value_set(devlink,
DEVLINK_PARAM_GENERIC_ID_ENABLE_RDMA,
value);
&value);
return 0;
}
@@ -819,7 +819,7 @@ static int mlx5_devlink_vnet_params_register(struct devlink *devlink)
value.vbool = !mlx5_dev_is_lightweight(dev);
devl_param_driverinit_value_set(devlink,
DEVLINK_PARAM_GENERIC_ID_ENABLE_VNET,
value);
&value);
return 0;
}
@@ -866,22 +866,22 @@ static void mlx5_devlink_auxdev_params_unregister(struct devlink *devlink)
}
static int mlx5_devlink_max_uc_list_validate(struct devlink *devlink, u32 id,
union devlink_param_value val,
union devlink_param_value *val,
struct netlink_ext_ack *extack)
{
struct mlx5_core_dev *dev = devlink_priv(devlink);
if (val.vu32 == 0) {
if (val->vu32 == 0) {
NL_SET_ERR_MSG_MOD(extack, "max_macs value must be greater than 0");
return -EINVAL;
}
if (!is_power_of_2(val.vu32)) {
if (!is_power_of_2(val->vu32)) {
NL_SET_ERR_MSG_MOD(extack, "Only power of 2 values are supported for max_macs");
return -EINVAL;
}
if (ilog2(val.vu32) >
if (ilog2(val->vu32) >
MLX5_CAP_GEN_MAX(dev, log_max_current_uc_list)) {
NL_SET_ERR_MSG_MOD(extack, "max_macs value is out of the supported range");
return -EINVAL;
@@ -912,7 +912,7 @@ static int mlx5_devlink_max_uc_list_params_register(struct devlink *devlink)
value.vu32 = 1 << MLX5_CAP_GEN(dev, log_max_current_uc_list);
devl_param_driverinit_value_set(devlink,
DEVLINK_PARAM_GENERIC_ID_MAX_MACS,
value);
&value);
return 0;
}
@@ -1962,7 +1962,8 @@ static int mlx5_devlink_esw_multiport_set(struct devlink *devlink, u32 id,
}
static int mlx5_devlink_esw_multiport_get(struct devlink *devlink, u32 id,
struct devlink_param_gset_ctx *ctx)
struct devlink_param_gset_ctx *ctx,
struct netlink_ext_ack *extack)
{
struct mlx5_core_dev *dev = devlink_priv(devlink);
@@ -2619,7 +2619,8 @@ done:
}
static int esw_port_metadata_get(struct devlink *devlink, u32 id,
struct devlink_param_gset_ctx *ctx)
struct devlink_param_gset_ctx *ctx,
struct netlink_ext_ack *extack)
{
struct mlx5_core_dev *dev = devlink_priv(devlink);
@@ -2628,7 +2629,7 @@ static int esw_port_metadata_get(struct devlink *devlink, u32 id,
}
static int esw_port_metadata_validate(struct devlink *devlink, u32 id,
union devlink_param_value val,
union devlink_param_value *val,
struct netlink_ext_ack *extack)
{
struct mlx5_core_dev *dev = devlink_priv(devlink);
@@ -3772,11 +3772,11 @@ cleanup:
}
static int mlx5_fs_mode_validate(struct devlink *devlink, u32 id,
union devlink_param_value val,
union devlink_param_value *val,
struct netlink_ext_ack *extack)
{
struct mlx5_core_dev *dev = devlink_priv(devlink);
char *value = val.vstr;
char *value = val->vstr;
u8 eswitch_mode;
eswitch_mode = mlx5_eswitch_mode(dev);
@@ -3833,7 +3833,8 @@ static int mlx5_fs_mode_set(struct devlink *devlink, u32 id,
}
static int mlx5_fs_mode_get(struct devlink *devlink, u32 id,
struct devlink_param_gset_ctx *ctx)
struct devlink_param_gset_ctx *ctx,
struct netlink_ext_ack *extack)
{
struct mlx5_core_dev *dev = devlink_priv(devlink);
@@ -74,7 +74,8 @@ static int mlx5_fw_reset_enable_remote_dev_reset_set(struct devlink *devlink, u3
}
static int mlx5_fw_reset_enable_remote_dev_reset_get(struct devlink *devlink, u32 id,
struct devlink_param_gset_ctx *ctx)
struct devlink_param_gset_ctx *ctx,
struct netlink_ext_ack *extack)
{
struct mlx5_core_dev *dev = devlink_priv(devlink);
struct mlx5_fw_reset *fw_reset;
@@ -200,7 +200,8 @@ static const char *const
static int
mlx5_nv_param_devlink_cqe_compress_get(struct devlink *devlink, u32 id,
struct devlink_param_gset_ctx *ctx)
struct devlink_param_gset_ctx *ctx,
struct netlink_ext_ack *extack)
{
struct mlx5_core_dev *dev = devlink_priv(devlink);
u32 mnvda[MLX5_ST_SZ_DW(mnvda_reg)] = {};
@@ -224,13 +225,13 @@ mlx5_nv_param_devlink_cqe_compress_get(struct devlink *devlink, u32 id,
static int
mlx5_nv_param_devlink_cqe_compress_validate(struct devlink *devlink, u32 id,
union devlink_param_value val,
union devlink_param_value *val,
struct netlink_ext_ack *extack)
{
int i;
for (i = 0; i < ARRAY_SIZE(cqe_compress_str); i++) {
if (!strcmp(val.vstr, cqe_compress_str[i]))
if (!strcmp(val->vstr, cqe_compress_str[i]))
return 0;
}
@@ -302,7 +303,8 @@ static int mlx5_nv_param_read_per_host_pf_conf(struct mlx5_core_dev *dev,
}
static int mlx5_devlink_enable_sriov_get(struct devlink *devlink, u32 id,
struct devlink_param_gset_ctx *ctx)
struct devlink_param_gset_ctx *ctx,
struct netlink_ext_ack *extack)
{
struct mlx5_core_dev *dev = devlink_priv(devlink);
u32 mnvda[MLX5_ST_SZ_DW(mnvda_reg)] = {};
@@ -413,7 +415,8 @@ static int mlx5_devlink_enable_sriov_set(struct devlink *devlink, u32 id,
}
static int mlx5_devlink_total_vfs_get(struct devlink *devlink, u32 id,
struct devlink_param_gset_ctx *ctx)
struct devlink_param_gset_ctx *ctx,
struct netlink_ext_ack *extack)
{
struct mlx5_core_dev *dev = devlink_priv(devlink);
u32 mnvda[MLX5_ST_SZ_DW(mnvda_reg)] = {};
@@ -503,7 +506,7 @@ static int mlx5_devlink_total_vfs_set(struct devlink *devlink, u32 id,
}
static int mlx5_devlink_total_vfs_validate(struct devlink *devlink, u32 id,
union devlink_param_value val,
union devlink_param_value *val,
struct netlink_ext_ack *extack)
{
struct mlx5_core_dev *dev = devlink_priv(devlink);
@@ -522,7 +525,7 @@ static int mlx5_devlink_total_vfs_validate(struct devlink *devlink, u32 id,
return 0; /* optimistic, but set might fail later */
max = MLX5_GET(nv_global_pci_cap, data, max_vfs_per_pf);
if (val.vu16 > max) {
if (val->vu16 > max) {
NL_SET_ERR_MSG_FMT_MOD(extack,
"Max allowed by device is %u", max);
return -EINVAL;
+4 -4
View File
@@ -1306,11 +1306,11 @@ static int mlxsw_core_fw_flash_update(struct mlxsw_core *mlxsw_core,
}
static int mlxsw_core_devlink_param_fw_load_policy_validate(struct devlink *devlink, u32 id,
union devlink_param_value val,
union devlink_param_value *val,
struct netlink_ext_ack *extack)
{
if (val.vu8 != DEVLINK_PARAM_FW_LOAD_POLICY_VALUE_DRIVER &&
val.vu8 != DEVLINK_PARAM_FW_LOAD_POLICY_VALUE_FLASH) {
if (val->vu8 != DEVLINK_PARAM_FW_LOAD_POLICY_VALUE_DRIVER &&
val->vu8 != DEVLINK_PARAM_FW_LOAD_POLICY_VALUE_FLASH) {
NL_SET_ERR_MSG_MOD(extack, "'fw_load_policy' must be 'driver' or 'flash'");
return -EINVAL;
}
@@ -1337,7 +1337,7 @@ static int mlxsw_core_fw_params_register(struct mlxsw_core *mlxsw_core)
value.vu8 = DEVLINK_PARAM_FW_LOAD_POLICY_VALUE_DRIVER;
devl_param_driverinit_value_set(devlink,
DEVLINK_PARAM_GENERIC_ID_FW_LOAD_POLICY,
value);
&value);
return 0;
}
@@ -1489,7 +1489,8 @@ mlxsw_sp_acl_tcam_vregion_rehash(struct mlxsw_sp *mlxsw_sp,
static int
mlxsw_sp_acl_tcam_region_rehash_intrvl_get(struct devlink *devlink, u32 id,
struct devlink_param_gset_ctx *ctx)
struct devlink_param_gset_ctx *ctx,
struct netlink_ext_ack *extack)
{
struct mlxsw_core *mlxsw_core = devlink_priv(devlink);
struct mlxsw_sp_acl_tcam *tcam;
@@ -81,7 +81,8 @@ static const struct nfp_devlink_param_u8_arg nfp_devlink_u8_args[] = {
static int
nfp_devlink_param_u8_get(struct devlink *devlink, u32 id,
struct devlink_param_gset_ctx *ctx)
struct devlink_param_gset_ctx *ctx,
struct netlink_ext_ack *extack)
{
const struct nfp_devlink_param_u8_arg *arg;
struct nfp_pf *pf = devlink_priv(devlink);
@@ -169,7 +170,7 @@ exit_close_nsp:
static int
nfp_devlink_param_u8_validate(struct devlink *devlink, u32 id,
union devlink_param_value val,
union devlink_param_value *val,
struct netlink_ext_ack *extack)
{
const struct nfp_devlink_param_u8_arg *arg;
@@ -179,12 +180,12 @@ nfp_devlink_param_u8_validate(struct devlink *devlink, u32 id,
arg = &nfp_devlink_u8_args[id];
if (val.vu8 > arg->max_dl_val) {
if (val->vu8 > arg->max_dl_val) {
NL_SET_ERR_MSG_MOD(extack, "parameter out of range");
return -EINVAL;
}
if (val.vu8 == arg->invalid_dl_val) {
if (val->vu8 == arg->invalid_dl_val) {
NL_SET_ERR_MSG_MOD(extack, "unknown/invalid value specified");
return -EINVAL;
}
@@ -121,7 +121,8 @@ void qed_fw_reporters_destroy(struct devlink *devlink)
}
static int qed_dl_param_get(struct devlink *dl, u32 id,
struct devlink_param_gset_ctx *ctx)
struct devlink_param_gset_ctx *ctx,
struct netlink_ext_ack *extack)
{
struct qed_devlink *qed_dl = devlink_priv(dl);
struct qed_dev *cdev;
+2 -1
View File
@@ -3042,7 +3042,8 @@ static void am65_cpsw_init_host_port_emac(struct am65_cpsw_common *common)
}
static int am65_cpsw_dl_switch_mode_get(struct devlink *dl, u32 id,
struct devlink_param_gset_ctx *ctx)
struct devlink_param_gset_ctx *ctx,
struct netlink_ext_ack *extack)
{
struct am65_cpsw_devlink *dl_priv = devlink_priv(dl);
struct am65_cpsw_common *common = dl_priv->common;
+4 -2
View File
@@ -1610,7 +1610,8 @@ static const struct devlink_ops cpsw_devlink_ops = {
};
static int cpsw_dl_switch_mode_get(struct devlink *dl, u32 id,
struct devlink_param_gset_ctx *ctx)
struct devlink_param_gset_ctx *ctx,
struct netlink_ext_ack *extack)
{
struct cpsw_devlink *dl_priv = devlink_priv(dl);
struct cpsw_common *cpsw = dl_priv->cpsw;
@@ -1745,7 +1746,8 @@ exit:
}
static int cpsw_dl_ale_ctrl_get(struct devlink *dl, u32 id,
struct devlink_param_gset_ctx *ctx)
struct devlink_param_gset_ctx *ctx,
struct netlink_ext_ack *extack)
{
struct cpsw_devlink *dl_priv = devlink_priv(dl);
struct cpsw_common *cpsw = dl_priv->cpsw;
+80 -3
View File
@@ -320,6 +320,8 @@ static int nsim_dev_debugfs_init(struct nsim_dev *nsim_dev)
&nsim_dev->max_macs);
debugfs_create_bool("test1", 0600, nsim_dev->ddir,
&nsim_dev->test1);
debugfs_create_u32("test2", 0600, nsim_dev->ddir,
&nsim_dev->test2);
nsim_dev->take_snapshot = debugfs_create_file("take_snapshot",
0200,
nsim_dev->ddir,
@@ -521,8 +523,53 @@ err_out:
enum nsim_devlink_param_id {
NSIM_DEVLINK_PARAM_ID_BASE = DEVLINK_PARAM_GENERIC_ID_MAX,
NSIM_DEVLINK_PARAM_ID_TEST1,
NSIM_DEVLINK_PARAM_ID_TEST2,
};
static int
nsim_devlink_param_test2_get(struct devlink *devlink, u32 id,
struct devlink_param_gset_ctx *ctx,
struct netlink_ext_ack *extack)
{
struct nsim_dev *nsim_dev = devlink_priv(devlink);
ctx->val.vu32 = nsim_dev->test2;
return 0;
}
static int
nsim_devlink_param_test2_set(struct devlink *devlink, u32 id,
struct devlink_param_gset_ctx *ctx,
struct netlink_ext_ack *extack)
{
struct nsim_dev *nsim_dev = devlink_priv(devlink);
nsim_dev->test2 = ctx->val.vu32;
return 0;
}
#define NSIM_DEV_TEST2_DEFAULT 1234
static int
nsim_devlink_param_test2_get_default(struct devlink *devlink, u32 id,
struct devlink_param_gset_ctx *ctx,
struct netlink_ext_ack *extack)
{
ctx->val.vu32 = NSIM_DEV_TEST2_DEFAULT;
return 0;
}
static int
nsim_devlink_param_test2_reset_default(struct devlink *devlink, u32 id,
enum devlink_param_cmode cmode,
struct netlink_ext_ack *extack)
{
struct nsim_dev *nsim_dev = devlink_priv(devlink);
nsim_dev->test2 = NSIM_DEV_TEST2_DEFAULT;
return 0;
}
static const struct devlink_param nsim_devlink_params[] = {
DEVLINK_PARAM_GENERIC(MAX_MACS,
BIT(DEVLINK_PARAM_CMODE_DRIVERINIT),
@@ -531,6 +578,14 @@ static const struct devlink_param nsim_devlink_params[] = {
"test1", DEVLINK_PARAM_TYPE_BOOL,
BIT(DEVLINK_PARAM_CMODE_DRIVERINIT),
NULL, NULL, NULL),
DEVLINK_PARAM_DRIVER_WITH_DEFAULTS(NSIM_DEVLINK_PARAM_ID_TEST2,
"test2", DEVLINK_PARAM_TYPE_U32,
BIT(DEVLINK_PARAM_CMODE_RUNTIME),
nsim_devlink_param_test2_get,
nsim_devlink_param_test2_set,
NULL,
nsim_devlink_param_test2_get_default,
nsim_devlink_param_test2_reset_default),
};
static void nsim_devlink_set_params_init_values(struct nsim_dev *nsim_dev,
@@ -541,11 +596,11 @@ static void nsim_devlink_set_params_init_values(struct nsim_dev *nsim_dev,
value.vu32 = nsim_dev->max_macs;
devl_param_driverinit_value_set(devlink,
DEVLINK_PARAM_GENERIC_ID_MAX_MACS,
value);
&value);
value.vbool = nsim_dev->test1;
devl_param_driverinit_value_set(devlink,
NSIM_DEVLINK_PARAM_ID_TEST1,
value);
&value);
}
static void nsim_devlink_param_load_driverinit_values(struct devlink *devlink)
@@ -1431,9 +1486,25 @@ static int __nsim_dev_port_add(struct nsim_dev *nsim_dev, enum nsim_dev_port_typ
if (err)
goto err_port_free;
if (nsim_dev_port_is_pf(nsim_dev_port)) {
u64 parent_id = DEVLINK_RESOURCE_ID_PARENT_TOP;
struct devlink_resource_size_params params = {
.size_max = 100,
.size_granularity = 1,
.unit = DEVLINK_RESOURCE_UNIT_ENTRY
};
err = devl_port_resource_register(devlink_port,
"test_resource", 20,
NSIM_PORT_RESOURCE_TEST,
parent_id, &params);
if (err)
goto err_dl_port_unregister;
}
err = nsim_dev_port_debugfs_init(nsim_dev, nsim_dev_port);
if (err)
goto err_dl_port_unregister;
goto err_port_resource_unregister;
nsim_dev_port->ns = nsim_create(nsim_dev, nsim_dev_port);
if (IS_ERR(nsim_dev_port->ns)) {
@@ -1456,6 +1527,9 @@ err_nsim_destroy:
nsim_destroy(nsim_dev_port->ns);
err_port_debugfs_exit:
nsim_dev_port_debugfs_exit(nsim_dev_port);
err_port_resource_unregister:
if (nsim_dev_port_is_pf(nsim_dev_port))
devl_port_resources_unregister(devlink_port);
err_dl_port_unregister:
devl_port_unregister(devlink_port);
err_port_free:
@@ -1472,6 +1546,8 @@ static void __nsim_dev_port_del(struct nsim_dev_port *nsim_dev_port)
devl_rate_leaf_destroy(&nsim_dev_port->devlink_port);
nsim_destroy(nsim_dev_port->ns);
nsim_dev_port_debugfs_exit(nsim_dev_port);
if (nsim_dev_port_is_pf(nsim_dev_port))
devl_port_resources_unregister(devlink_port);
devl_port_unregister(devlink_port);
kfree(nsim_dev_port);
}
@@ -1590,6 +1666,7 @@ int nsim_drv_probe(struct nsim_bus_dev *nsim_bus_dev)
nsim_dev->fw_update_flash_chunk_time_ms = NSIM_DEV_FLASH_CHUNK_TIME_MS_DEFAULT;
nsim_dev->max_macs = NSIM_DEV_MAX_MACS_DEFAULT;
nsim_dev->test1 = NSIM_DEV_TEST1_DEFAULT;
nsim_dev->test2 = NSIM_DEV_TEST2_DEFAULT;
spin_lock_init(&nsim_dev->fa_cookie_lock);
dev_set_drvdata(&nsim_bus_dev->dev, nsim_dev);
+5
View File
@@ -213,6 +213,10 @@ enum nsim_resource_id {
NSIM_RESOURCE_NEXTHOPS,
};
enum nsim_port_resource_id {
NSIM_PORT_RESOURCE_TEST = 1,
};
struct nsim_dev_health {
struct devlink_health_reporter *empty_reporter;
struct devlink_health_reporter *dummy_reporter;
@@ -320,6 +324,7 @@ struct nsim_dev {
u32 fw_update_flash_chunk_time_ms;
u32 max_macs;
bool test1;
u32 test2;
bool dont_allow_reload;
bool fail_reload;
struct devlink_region *dummy_region;
+2 -1
View File
@@ -21,7 +21,8 @@ static struct iosm_coredump_file_info list[IOSM_NOF_CD_REGION] = {
/* Get the param values for the specific param ID's */
static int ipc_devlink_get_param(struct devlink *dl, u32 id,
struct devlink_param_gset_ctx *ctx)
struct devlink_param_gset_ctx *ctx,
struct netlink_ext_ack *extack)
{
struct iosm_devlink *ipc_devlink = devlink_priv(dl);
+73 -4
View File
@@ -131,6 +131,7 @@ struct devlink_rate {
struct devlink_port {
struct list_head list;
struct list_head region_list;
struct list_head resource_list;
struct devlink *devlink;
const struct devlink_port_ops *ops;
unsigned int index;
@@ -457,6 +458,13 @@ enum devlink_param_type {
DEVLINK_PARAM_TYPE_U64 = DEVLINK_VAR_ATTR_TYPE_U64,
DEVLINK_PARAM_TYPE_STRING = DEVLINK_VAR_ATTR_TYPE_STRING,
DEVLINK_PARAM_TYPE_BOOL = DEVLINK_VAR_ATTR_TYPE_FLAG,
DEVLINK_PARAM_TYPE_U64_ARRAY = DEVLINK_VAR_ATTR_TYPE_U64_ARRAY,
};
#define __DEVLINK_PARAM_MAX_ARRAY_SIZE 32
struct devlink_param_u64_array {
u64 size;
u64 val[__DEVLINK_PARAM_MAX_ARRAY_SIZE];
};
union devlink_param_value {
@@ -466,6 +474,7 @@ union devlink_param_value {
u64 vu64;
char vstr[__DEVLINK_PARAM_MAX_STRING_VALUE];
bool vbool;
struct devlink_param_u64_array u64arr;
};
struct devlink_param_gset_ctx {
@@ -504,6 +513,10 @@ struct devlink_flash_notify {
* @set: set parameter value, used for runtime and permanent
* configuration modes
* @validate: validate input value is applicable (within value range, etc.)
* @get_default: get parameter default value, used for runtime and permanent
* configuration modes
* @reset_default: reset parameter to default value, used for runtime and permanent
* configuration modes
*
* This struct should be used by the driver to fill the data for
* a parameter it registers.
@@ -515,13 +528,20 @@ struct devlink_param {
enum devlink_param_type type;
unsigned long supported_cmodes;
int (*get)(struct devlink *devlink, u32 id,
struct devlink_param_gset_ctx *ctx);
struct devlink_param_gset_ctx *ctx,
struct netlink_ext_ack *extack);
int (*set)(struct devlink *devlink, u32 id,
struct devlink_param_gset_ctx *ctx,
struct netlink_ext_ack *extack);
int (*validate)(struct devlink *devlink, u32 id,
union devlink_param_value val,
union devlink_param_value *val,
struct netlink_ext_ack *extack);
int (*get_default)(struct devlink *devlink, u32 id,
struct devlink_param_gset_ctx *ctx,
struct netlink_ext_ack *extack);
int (*reset_default)(struct devlink *devlink, u32 id,
enum devlink_param_cmode cmode,
struct netlink_ext_ack *extack);
RH_KABI_RESERVE(1)
RH_KABI_RESERVE(2)
@@ -536,6 +556,7 @@ struct devlink_param_item {
* until reload.
*/
bool driverinit_value_new_valid;
union devlink_param_value driverinit_default;
};
enum devlink_param_generic_id {
@@ -657,6 +678,37 @@ enum devlink_param_generic_id {
.validate = _validate, \
}
#define DEVLINK_PARAM_GENERIC_WITH_DEFAULTS(_id, _cmodes, _get, _set, \
_validate, _get_default, \
_reset_default) \
{ \
.id = DEVLINK_PARAM_GENERIC_ID_##_id, \
.name = DEVLINK_PARAM_GENERIC_##_id##_NAME, \
.type = DEVLINK_PARAM_GENERIC_##_id##_TYPE, \
.generic = true, \
.supported_cmodes = _cmodes, \
.get = _get, \
.set = _set, \
.validate = _validate, \
.get_default = _get_default, \
.reset_default = _reset_default, \
}
#define DEVLINK_PARAM_DRIVER_WITH_DEFAULTS(_id, _name, _type, _cmodes, \
_get, _set, _validate, \
_get_default, _reset_default) \
{ \
.id = _id, \
.name = _name, \
.type = _type, \
.supported_cmodes = _cmodes, \
.get = _get, \
.set = _set, \
.validate = _validate, \
.get_default = _get_default, \
.reset_default = _reset_default, \
}
/* Identifier of board design */
#define DEVLINK_INFO_VERSION_GENERIC_BOARD_ID "board.id"
/* Revision of board design */
@@ -1614,6 +1666,9 @@ struct devlink_ops {
void *devlink_priv(struct devlink *devlink);
struct devlink *priv_to_devlink(void *priv);
struct device *devlink_to_dev(const struct devlink *devlink);
const char *devlink_bus_name(const struct devlink *devlink);
const char *devlink_dev_name(const struct devlink *devlink);
const char *devlink_dev_driver_name(const struct devlink *devlink);
/* Devlink instance explicit locking */
void devl_lock(struct devlink *devlink);
@@ -1647,6 +1702,13 @@ void devlink_register(struct devlink *devlink);
void devlink_unregister(struct devlink *devlink);
void devlink_free(struct devlink *devlink);
struct devlink *devlink_shd_get(const char *id,
const struct devlink_ops *ops,
size_t priv_size,
const struct device_driver *driver);
void devlink_shd_put(struct devlink *devlink);
void *devlink_shd_get_priv(struct devlink *devlink);
/**
* struct devlink_port_ops - Port operations
* @port_split: Callback used to split the port into multiple ones.
@@ -1887,12 +1949,19 @@ int devl_resource_register(struct devlink *devlink,
u64 resource_size,
u64 resource_id,
u64 parent_resource_id,
const struct devlink_resource_size_params *size_params);
const struct devlink_resource_size_params *params);
void devl_resources_unregister(struct devlink *devlink);
void devlink_resources_unregister(struct devlink *devlink);
int devl_resource_size_get(struct devlink *devlink,
u64 resource_id,
u64 *p_resource_size);
int
devl_port_resource_register(struct devlink_port *devlink_port,
const char *resource_name,
u64 resource_size, u64 resource_id,
u64 parent_resource_id,
const struct devlink_resource_size_params *params);
void devl_port_resources_unregister(struct devlink_port *devlink_port);
int devl_dpipe_table_resource_set(struct devlink *devlink,
const char *table_name, u64 resource_id,
u64 resource_units);
@@ -1917,7 +1986,7 @@ void devlink_params_unregister(struct devlink *devlink,
int devl_param_driverinit_value_get(struct devlink *devlink, u32 param_id,
union devlink_param_value *val);
void devl_param_driverinit_value_set(struct devlink *devlink, u32 param_id,
union devlink_param_value init_val);
union devlink_param_value *init_val);
void devl_param_value_changed(struct devlink *devlink, u32 param_id);
struct devlink_region *devl_region_create(struct devlink *devlink,
const struct devlink_region_ops *ops,
+2 -1
View File
@@ -1258,7 +1258,8 @@ struct dsa_switch_ops {
dsa_devlink_param_get, dsa_devlink_param_set, NULL)
int dsa_devlink_param_get(struct devlink *dl, u32 id,
struct devlink_param_gset_ctx *ctx);
struct devlink_param_gset_ctx *ctx,
struct netlink_ext_ack *extack);
int dsa_devlink_param_set(struct devlink *dl, u32 id,
struct devlink_param_gset_ctx *ctx,
struct netlink_ext_ack *extack);
+18 -18
View File
@@ -21,9 +21,9 @@ TRACE_EVENT(devlink_hwmsg,
TP_ARGS(devlink, incoming, type, buf, len),
TP_STRUCT__entry(
__string(bus_name, devlink_to_dev(devlink)->bus->name)
__string(dev_name, dev_name(devlink_to_dev(devlink)))
__string(driver_name, devlink_to_dev(devlink)->driver->name)
__string(bus_name, devlink_bus_name(devlink))
__string(dev_name, devlink_dev_name(devlink))
__string(driver_name, devlink_dev_driver_name(devlink))
__field(bool, incoming)
__field(unsigned long, type)
__dynamic_array(u8, buf, len)
@@ -55,9 +55,9 @@ TRACE_EVENT(devlink_hwerr,
TP_ARGS(devlink, err, msg),
TP_STRUCT__entry(
__string(bus_name, devlink_to_dev(devlink)->bus->name)
__string(dev_name, dev_name(devlink_to_dev(devlink)))
__string(driver_name, devlink_to_dev(devlink)->driver->name)
__string(bus_name, devlink_bus_name(devlink))
__string(dev_name, devlink_dev_name(devlink))
__string(driver_name, devlink_dev_driver_name(devlink))
__field(int, err)
__string(msg, msg)
),
@@ -85,9 +85,9 @@ TRACE_EVENT(devlink_health_report,
TP_ARGS(devlink, reporter_name, msg),
TP_STRUCT__entry(
__string(bus_name, devlink_to_dev(devlink)->bus->name)
__string(dev_name, dev_name(devlink_to_dev(devlink)))
__string(driver_name, devlink_to_dev(devlink)->driver->name)
__string(bus_name, devlink_bus_name(devlink))
__string(dev_name, devlink_dev_name(devlink))
__string(driver_name, devlink_dev_driver_name(devlink))
__string(reporter_name, reporter_name)
__string(msg, msg)
),
@@ -116,9 +116,9 @@ TRACE_EVENT(devlink_health_recover_aborted,
TP_ARGS(devlink, reporter_name, health_state, time_since_last_recover),
TP_STRUCT__entry(
__string(bus_name, devlink_to_dev(devlink)->bus->name)
__string(dev_name, dev_name(devlink_to_dev(devlink)))
__string(driver_name, devlink_to_dev(devlink)->driver->name)
__string(bus_name, devlink_bus_name(devlink))
__string(dev_name, devlink_dev_name(devlink))
__string(driver_name, devlink_dev_driver_name(devlink))
__string(reporter_name, reporter_name)
__field(bool, health_state)
__field(u64, time_since_last_recover)
@@ -150,9 +150,9 @@ TRACE_EVENT(devlink_health_reporter_state_update,
TP_ARGS(devlink, reporter_name, new_state),
TP_STRUCT__entry(
__string(bus_name, devlink_to_dev(devlink)->bus->name)
__string(dev_name, dev_name(devlink_to_dev(devlink)))
__string(driver_name, devlink_to_dev(devlink)->driver->name)
__string(bus_name, devlink_bus_name(devlink))
__string(dev_name, devlink_dev_name(devlink))
__string(driver_name, devlink_dev_driver_name(devlink))
__string(reporter_name, reporter_name)
__field(u8, new_state)
),
@@ -181,9 +181,9 @@ TRACE_EVENT(devlink_trap_report,
TP_ARGS(devlink, skb, metadata),
TP_STRUCT__entry(
__string(bus_name, devlink_to_dev(devlink)->bus->name)
__string(dev_name, dev_name(devlink_to_dev(devlink)))
__string(driver_name, devlink_to_dev(devlink)->driver->name)
__string(bus_name, devlink_bus_name(devlink))
__string(dev_name, devlink_dev_name(devlink))
__string(driver_name, devlink_dev_driver_name(devlink))
__string(trap_name, metadata->trap_name)
__string(trap_group_name, metadata->trap_group_name)
__array(char, input_dev_name, IFNAMSIZ)
+19
View File
@@ -19,6 +19,8 @@
#define DEVLINK_GENL_VERSION 0x1
#define DEVLINK_GENL_MCGRP_CONFIG_NAME "config"
#define DEVLINK_INDEX_BUS_NAME "devlink_index"
enum devlink_command {
/* don't change the order or add anything between, this is ABI! */
DEVLINK_CMD_UNSPEC,
@@ -404,6 +406,7 @@ enum devlink_var_attr_type {
DEVLINK_VAR_ATTR_TYPE_BINARY,
__DEVLINK_VAR_ATTR_TYPE_CUSTOM_BASE = 0x80,
/* Any possible custom types, unrelated to NLA_* values go below */
DEVLINK_VAR_ATTR_TYPE_U64_ARRAY,
};
enum devlink_attr {
@@ -639,6 +642,12 @@ enum devlink_attr {
DEVLINK_ATTR_HEALTH_REPORTER_BURST_PERIOD, /* u64 */
DEVLINK_ATTR_PARAM_VALUE_DEFAULT, /* dynamic */
DEVLINK_ATTR_PARAM_RESET_DEFAULT, /* flag */
DEVLINK_ATTR_INDEX, /* uint */
DEVLINK_ATTR_RESOURCE_SCOPE_MASK, /* u32 */
/* Add new attributes above here, update the spec in
* Documentation/netlink/specs/devlink.yaml and re-generate
* net/devlink/netlink_gen.c.
@@ -697,6 +706,16 @@ enum devlink_resource_unit {
DEVLINK_RESOURCE_UNIT_ENTRY,
};
enum devlink_resource_scope {
DEVLINK_RESOURCE_SCOPE_DEV_BIT,
DEVLINK_RESOURCE_SCOPE_PORT_BIT,
};
#define DEVLINK_RESOURCE_SCOPE_DEV \
_BITUL(DEVLINK_RESOURCE_SCOPE_DEV_BIT)
#define DEVLINK_RESOURCE_SCOPE_PORT \
_BITUL(DEVLINK_RESOURCE_SCOPE_PORT_BIT)
enum devlink_port_fn_attr_cap {
DEVLINK_PORT_FN_ATTR_CAP_ROCE_BIT,
DEVLINK_PORT_FN_ATTR_CAP_MIGRATABLE_BIT,
+1 -1
View File
@@ -1,4 +1,4 @@
# SPDX-License-Identifier: GPL-2.0
obj-y := core.o netlink.o netlink_gen.o dev.o port.o sb.o dpipe.o \
resource.o param.o region.o health.o trap.o rate.o linecard.o
resource.o param.o region.o health.o trap.o rate.o linecard.o sh_dev.o
+75 -24
View File
@@ -178,9 +178,7 @@ int devlink_rel_nested_in_add(u32 *rel_index, u32 devlink_index,
* a notification of a change of this object should be sent
* over netlink. The parent devlink instance lock needs to be
* taken during the notification preparation.
* However, since the devlink lock of nested instance is held here,
* we would end with wrong devlink instance lock ordering and
* deadlock. Therefore the work is utilized to avoid that.
* Since the parent may or may not be locked, 'work' is utilized.
*/
void devlink_rel_nested_in_notify(struct devlink *devlink)
{
@@ -250,6 +248,24 @@ struct device *devlink_to_dev(const struct devlink *devlink)
}
EXPORT_SYMBOL_GPL(devlink_to_dev);
const char *devlink_bus_name(const struct devlink *devlink)
{
return devlink->dev ? devlink->dev->bus->name : DEVLINK_INDEX_BUS_NAME;
}
EXPORT_SYMBOL_GPL(devlink_bus_name);
const char *devlink_dev_name(const struct devlink *devlink)
{
return devlink->dev ? dev_name(devlink->dev) : devlink->dev_name_index;
}
EXPORT_SYMBOL_GPL(devlink_dev_name);
const char *devlink_dev_driver_name(const struct devlink *devlink)
{
return devlink->dev_driver->name;
}
EXPORT_SYMBOL_GPL(devlink_dev_driver_name);
struct net *devlink_net(const struct devlink *devlink)
{
return read_pnet(&devlink->_net);
@@ -313,7 +329,10 @@ static void devlink_release(struct work_struct *work)
mutex_destroy(&devlink->lock);
lockdep_unregister_key(&devlink->lock_key);
put_device(devlink->dev);
if (devlink->dev)
put_device(devlink->dev);
else
kfree(devlink->dev_name_index);
kvfree(devlink);
}
@@ -323,13 +342,15 @@ void devlink_put(struct devlink *devlink)
queue_rcu_work(system_percpu_wq, &devlink->rwork);
}
struct devlink *devlinks_xa_find_get(struct net *net, unsigned long *indexp)
static struct devlink *__devlinks_xa_find_get(struct net *net,
unsigned long *indexp,
unsigned long end)
{
struct devlink *devlink = NULL;
rcu_read_lock();
retry:
devlink = xa_find(&devlinks, indexp, ULONG_MAX, DEVLINK_REGISTERED);
devlink = xa_find(&devlinks, indexp, end, DEVLINK_REGISTERED);
if (!devlink)
goto unlock;
@@ -348,6 +369,16 @@ next:
goto retry;
}
struct devlink *devlinks_xa_find_get(struct net *net, unsigned long *indexp)
{
return __devlinks_xa_find_get(net, indexp, ULONG_MAX);
}
struct devlink *devlinks_xa_lookup_get(struct net *net, unsigned long index)
{
return __devlinks_xa_find_get(net, &index, index);
}
/**
* devl_register - Register devlink instance
* @devlink: devlink
@@ -396,27 +427,15 @@ void devlink_unregister(struct devlink *devlink)
}
EXPORT_SYMBOL_GPL(devlink_unregister);
/**
* devlink_alloc_ns - Allocate new devlink instance resources
* in specific namespace
*
* @ops: ops
* @priv_size: size of user private data
* @net: net namespace
* @dev: parent device
*
* Allocate new devlink instance resources, including devlink index
* and name.
*/
struct devlink *devlink_alloc_ns(const struct devlink_ops *ops,
size_t priv_size, struct net *net,
struct device *dev)
struct devlink *__devlink_alloc(const struct devlink_ops *ops, size_t priv_size,
struct net *net, struct device *dev,
const struct device_driver *dev_driver)
{
struct devlink *devlink;
static u32 last_id;
int ret;
WARN_ON(!ops || !dev);
WARN_ON(!ops || !dev_driver);
if (!devlink_reload_actions_valid(ops))
return NULL;
@@ -429,8 +448,16 @@ struct devlink *devlink_alloc_ns(const struct devlink_ops *ops,
if (ret < 0)
goto err_xa_alloc;
devlink->dev = get_device(dev);
if (dev) {
devlink->dev = get_device(dev);
} else {
devlink->dev_name_index = kasprintf(GFP_KERNEL, "%u", devlink->index);
if (!devlink->dev_name_index)
goto err_kasprintf;
}
devlink->ops = ops;
devlink->dev_driver = dev_driver;
xa_init_flags(&devlink->ports, XA_FLAGS_ALLOC);
xa_init_flags(&devlink->params, XA_FLAGS_ALLOC);
xa_init_flags(&devlink->snapshot_ids, XA_FLAGS_ALLOC);
@@ -454,10 +481,32 @@ struct devlink *devlink_alloc_ns(const struct devlink_ops *ops,
return devlink;
err_kasprintf:
xa_erase(&devlinks, devlink->index);
err_xa_alloc:
kvfree(devlink);
return NULL;
}
/**
* devlink_alloc_ns - Allocate new devlink instance resources
* in specific namespace
*
* @ops: ops
* @priv_size: size of user private data
* @net: net namespace
* @dev: parent device
*
* Allocate new devlink instance resources, including devlink index
* and name.
*/
struct devlink *devlink_alloc_ns(const struct devlink_ops *ops,
size_t priv_size, struct net *net,
struct device *dev)
{
WARN_ON(!dev);
return __devlink_alloc(ops, priv_size, net, dev, dev->driver);
}
EXPORT_SYMBOL_GPL(devlink_alloc_ns);
/**
@@ -469,6 +518,8 @@ void devlink_free(struct devlink *devlink)
{
ASSERT_DEVLINK_NOT_REGISTERED(devlink);
devlink_rel_put(devlink);
WARN_ON(!list_empty(&devlink->trap_policer_list));
WARN_ON(!list_empty(&devlink->trap_group_list));
WARN_ON(!list_empty(&devlink->trap_list));
@@ -477,7 +528,7 @@ void devlink_free(struct devlink *devlink)
WARN_ON(!list_empty(&devlink->resource_list));
WARN_ON(!list_empty(&devlink->dpipe_table_list));
WARN_ON(!list_empty(&devlink->sb_list));
WARN_ON(!list_empty(&devlink->rate_list));
WARN_ON(devlink_rates_check(devlink, NULL, NULL));
WARN_ON(!list_empty(&devlink->linecard_list));
WARN_ON(!xa_empty(&devlink->ports));
+8 -7
View File
@@ -434,7 +434,7 @@ static void devlink_reload_reinit_sanity_check(struct devlink *devlink)
WARN_ON(!list_empty(&devlink->trap_list));
WARN_ON(!list_empty(&devlink->dpipe_table_list));
WARN_ON(!list_empty(&devlink->sb_list));
WARN_ON(!list_empty(&devlink->rate_list));
WARN_ON(devlink_rates_check(devlink, NULL, NULL));
WARN_ON(!list_empty(&devlink->linecard_list));
WARN_ON(!xa_empty(&devlink->ports));
}
@@ -453,7 +453,8 @@ int devlink_reload(struct devlink *devlink, struct net *dest_net,
* (e.g., PCI reset) and to close possible races between these
* operations and probe/remove.
*/
device_lock_assert(devlink->dev);
if (devlink->dev)
device_lock_assert(devlink->dev);
memcpy(remote_reload_stats, devlink->stats.remote_reload_stats,
sizeof(remote_reload_stats));
@@ -715,10 +716,11 @@ int devlink_nl_eswitch_set_doit(struct sk_buff *skb, struct genl_info *info)
if (info->attrs[DEVLINK_ATTR_ESWITCH_MODE]) {
if (!ops->eswitch_mode_set)
return -EOPNOTSUPP;
mode = nla_get_u16(info->attrs[DEVLINK_ATTR_ESWITCH_MODE]);
err = devlink_rate_nodes_check(devlink, mode, info->extack);
err = devlink_rates_check(devlink, devlink_rate_is_node,
info->extack);
if (err)
return err;
mode = nla_get_u16(info->attrs[DEVLINK_ATTR_ESWITCH_MODE]);
err = ops->eswitch_mode_set(devlink, mode, info->extack);
if (err)
return err;
@@ -855,7 +857,7 @@ int devlink_info_version_running_put_ext(struct devlink_info_req *req,
}
EXPORT_SYMBOL_GPL(devlink_info_version_running_put_ext);
static int devlink_nl_driver_info_get(struct device_driver *drv,
static int devlink_nl_driver_info_get(const struct device_driver *drv,
struct devlink_info_req *req)
{
if (!drv)
@@ -873,7 +875,6 @@ devlink_nl_info_fill(struct sk_buff *msg, struct devlink *devlink,
enum devlink_command cmd, u32 portid,
u32 seq, int flags, struct netlink_ext_ack *extack)
{
struct device *dev = devlink_to_dev(devlink);
struct devlink_info_req req = {};
void *hdr;
int err;
@@ -893,7 +894,7 @@ devlink_nl_info_fill(struct sk_buff *msg, struct devlink *devlink,
goto err_cancel_msg;
}
err = devlink_nl_driver_info_get(dev->driver, &req);
err = devlink_nl_driver_info_get(devlink->dev_driver, &req);
if (err)
goto err_cancel_msg;
+37 -8
View File
@@ -49,6 +49,8 @@ struct devlink {
struct xarray snapshot_ids;
struct devlink_dev_stats stats;
struct device *dev;
const char *dev_name_index;
const struct device_driver *dev_driver;
possible_net_t _net;
/* Serializes access to devlink instance specific objects such as
* port, sb, dpipe, resource, params, region, traps and more.
@@ -66,6 +68,19 @@ struct devlink {
extern struct xarray devlinks;
extern struct genl_family devlink_nl_family;
struct devlink *__devlink_alloc(const struct devlink_ops *ops, size_t priv_size,
struct net *net, struct device *dev,
const struct device_driver *dev_driver);
#define devl_warn(devlink, format, args...) \
do { \
if ((devlink)->dev) \
dev_warn((devlink)->dev, format, ##args); \
else \
pr_warn("devlink (%s): " format, \
devlink_dev_name(devlink), ##args); \
} while (0)
/* devlink instances are open to the access from the user space after
* devlink_register() call. Such logical barrier allows us to have certain
* expectations related to locking.
@@ -90,6 +105,7 @@ extern struct genl_family devlink_nl_family;
for (index = 0; (devlink = devlinks_xa_find_get(net, &index)); index++)
struct devlink *devlinks_xa_find_get(struct net *net, unsigned long *indexp);
struct devlink *devlinks_xa_lookup_get(struct net *net, unsigned long index);
static inline bool __devl_is_registered(struct devlink *devlink)
{
@@ -104,7 +120,7 @@ static inline bool devl_is_registered(struct devlink *devlink)
static inline void devl_dev_lock(struct devlink *devlink, bool dev_lock)
{
if (dev_lock)
if (dev_lock && devlink->dev)
device_lock(devlink->dev);
devl_lock(devlink);
}
@@ -112,7 +128,7 @@ static inline void devl_dev_lock(struct devlink *devlink, bool dev_lock)
static inline void devl_dev_unlock(struct devlink *devlink, bool dev_lock)
{
devl_unlock(devlink);
if (dev_lock)
if (dev_lock && devlink->dev)
device_unlock(devlink->dev);
}
@@ -148,6 +164,11 @@ struct devlink_nl_dump_state {
struct {
u64 dump_ts;
};
/* DEVLINK_CMD_RESOURCE_DUMP */
struct {
u32 index;
bool index_valid;
} port_ctx;
};
};
@@ -174,9 +195,11 @@ devlink_dump_state(struct netlink_callback *cb)
static inline int
devlink_nl_put_handle(struct sk_buff *msg, struct devlink *devlink)
{
if (nla_put_string(msg, DEVLINK_ATTR_BUS_NAME, devlink->dev->bus->name))
if (nla_put_string(msg, DEVLINK_ATTR_BUS_NAME, devlink_bus_name(devlink)))
return -EMSGSIZE;
if (nla_put_string(msg, DEVLINK_ATTR_DEV_NAME, dev_name(devlink->dev)))
if (nla_put_string(msg, DEVLINK_ATTR_DEV_NAME, devlink_dev_name(devlink)))
return -EMSGSIZE;
if (nla_put_uint(msg, DEVLINK_ATTR_INDEX, devlink->index))
return -EMSGSIZE;
return 0;
}
@@ -202,6 +225,8 @@ struct devlink_obj_desc {
const char *dev_name;
unsigned int port_index;
bool port_index_valid;
unsigned int devlink_index;
bool devlink_index_valid;
long data[];
};
@@ -209,8 +234,10 @@ static inline void devlink_nl_obj_desc_init(struct devlink_obj_desc *desc,
struct devlink *devlink)
{
memset(desc, 0, sizeof(*desc));
desc->bus_name = devlink->dev->bus->name;
desc->dev_name = dev_name(devlink->dev);
desc->bus_name = devlink_bus_name(devlink);
desc->dev_name = devlink_dev_name(devlink);
desc->devlink_index = devlink->index;
desc->devlink_index_valid = true;
}
static inline void devlink_nl_obj_desc_port_set(struct devlink_obj_desc *desc,
@@ -297,8 +324,10 @@ int devlink_resources_validate(struct devlink *devlink,
struct genl_info *info);
/* Rates */
int devlink_rate_nodes_check(struct devlink *devlink, u16 mode,
struct netlink_ext_ack *extack);
bool devlink_rate_is_node(const struct devlink_rate *devlink_rate);
int devlink_rates_check(struct devlink *devlink,
bool (*rate_filter)(const struct devlink_rate *),
struct netlink_ext_ack *extack);
/* Linecards */
unsigned int devlink_linecard_index(struct devlink_linecard *linecard);
+1 -1
View File
@@ -1327,7 +1327,7 @@ void devlink_fmsg_dump_skb(struct devlink_fmsg *fmsg, const struct sk_buff *skb)
if (sk) {
devlink_fmsg_pair_nest_start(fmsg, "sk");
devlink_fmsg_obj_nest_start(fmsg);
devlink_fmsg_put(fmsg, "family", sk->sk_type);
devlink_fmsg_put(fmsg, "family", sk->sk_family);
devlink_fmsg_put(fmsg, "type", sk->sk_type);
devlink_fmsg_put(fmsg, "proto", sk->sk_protocol);
devlink_fmsg_obj_nest_end(fmsg);
+45 -9
View File
@@ -73,13 +73,19 @@ int devlink_nl_notify_filter_set_doit(struct sk_buff *skb,
flt->dev_name = pos;
}
if (attrs[DEVLINK_ATTR_INDEX]) {
flt->devlink_index = nla_get_uint(attrs[DEVLINK_ATTR_INDEX]);
flt->devlink_index_valid = true;
}
if (attrs[DEVLINK_ATTR_PORT_INDEX]) {
flt->port_index = nla_get_u32(attrs[DEVLINK_ATTR_PORT_INDEX]);
flt->port_index_valid = true;
}
/* Don't attach empty filter. */
if (!flt->bus_name && !flt->dev_name && !flt->port_index_valid) {
if (!flt->bus_name && !flt->dev_name &&
!flt->devlink_index_valid && !flt->port_index_valid) {
kfree(flt);
flt = NULL;
}
@@ -100,6 +106,9 @@ int devlink_nl_notify_filter_set_doit(struct sk_buff *skb,
static bool devlink_obj_desc_match(const struct devlink_obj_desc *desc,
const struct devlink_obj_desc *flt)
{
if (desc->devlink_index_valid && flt->devlink_index_valid &&
desc->devlink_index != flt->devlink_index)
return false;
if (desc->bus_name && flt->bus_name &&
strcmp(desc->bus_name, flt->bus_name))
return false;
@@ -186,24 +195,48 @@ devlink_get_from_attrs_lock(struct net *net, struct nlattr **attrs,
char *busname;
char *devname;
if (attrs[DEVLINK_ATTR_INDEX]) {
if (attrs[DEVLINK_ATTR_BUS_NAME] ||
attrs[DEVLINK_ATTR_DEV_NAME])
return ERR_PTR(-EINVAL);
index = nla_get_u32(attrs[DEVLINK_ATTR_INDEX]);
devlink = devlinks_xa_lookup_get(net, index);
if (!devlink)
return ERR_PTR(-ENODEV);
goto found;
}
if (!attrs[DEVLINK_ATTR_BUS_NAME] || !attrs[DEVLINK_ATTR_DEV_NAME])
return ERR_PTR(-EINVAL);
busname = nla_data(attrs[DEVLINK_ATTR_BUS_NAME]);
devname = nla_data(attrs[DEVLINK_ATTR_DEV_NAME]);
if (!strcmp(busname, DEVLINK_INDEX_BUS_NAME)) {
if (kstrtoul(devname, 10, &index))
return ERR_PTR(-ENODEV);
devlink = devlinks_xa_lookup_get(net, index);
if (!devlink)
return ERR_PTR(-ENODEV);
goto found;
}
devlinks_xa_for_each_registered_get(net, index, devlink) {
if (strcmp(devlink->dev->bus->name, busname) == 0 &&
strcmp(dev_name(devlink->dev), devname) == 0) {
devl_dev_lock(devlink, dev_lock);
if (devl_is_registered(devlink))
return devlink;
devl_dev_unlock(devlink, dev_lock);
}
if (strcmp(devlink_bus_name(devlink), busname) == 0 &&
strcmp(devlink_dev_name(devlink), devname) == 0)
goto found;
devlink_put(devlink);
}
return ERR_PTR(-ENODEV);
found:
devl_dev_lock(devlink, dev_lock);
if (devl_is_registered(devlink))
return devlink;
devl_dev_unlock(devlink, dev_lock);
devlink_put(devlink);
return ERR_PTR(-ENODEV);
}
static int __devlink_nl_pre_doit(struct sk_buff *skb, struct genl_info *info,
@@ -337,6 +370,8 @@ static int devlink_nl_inst_iter_dumpit(struct sk_buff *msg,
/* restart sub-object walk for the next instance */
state->idx = 0;
state->port_ctx.index = 0;
state->port_ctx.index_valid = false;
}
if (err != -EMSGSIZE)
@@ -352,7 +387,8 @@ int devlink_nl_dumpit(struct sk_buff *msg, struct netlink_callback *cb,
int flags = NLM_F_MULTI;
if (attrs &&
(attrs[DEVLINK_ATTR_BUS_NAME] || attrs[DEVLINK_ATTR_DEV_NAME]))
(attrs[DEVLINK_ATTR_BUS_NAME] || attrs[DEVLINK_ATTR_DEV_NAME] ||
attrs[DEVLINK_ATTR_INDEX]))
return devlink_nl_inst_single_dumpit(msg, cb, flags, dump_one,
attrs);
else
+237 -143
View File
File diff suppressed because it is too large Load Diff
+5 -3
View File
@@ -17,17 +17,17 @@ extern const struct nla_policy devlink_dl_rate_tc_bws_nl_policy[DEVLINK_RATE_TC_
extern const struct nla_policy devlink_dl_selftest_id_nl_policy[DEVLINK_ATTR_SELFTEST_ID_FLASH + 1];
/* Ops table for devlink */
extern const struct genl_split_ops devlink_nl_ops[74];
extern const struct genl_split_ops devlink_nl_ops[75];
int devlink_nl_pre_doit(const struct genl_split_ops *ops, struct sk_buff *skb,
struct genl_info *info);
int devlink_nl_pre_doit_port(const struct genl_split_ops *ops,
struct sk_buff *skb, struct genl_info *info);
int devlink_nl_pre_doit_dev_lock(const struct genl_split_ops *ops,
struct sk_buff *skb, struct genl_info *info);
int devlink_nl_pre_doit_port_optional(const struct genl_split_ops *ops,
struct sk_buff *skb,
struct genl_info *info);
int devlink_nl_pre_doit_dev_lock(const struct genl_split_ops *ops,
struct sk_buff *skb, struct genl_info *info);
void
devlink_nl_post_doit(const struct genl_split_ops *ops, struct sk_buff *skb,
struct genl_info *info);
@@ -79,6 +79,8 @@ int devlink_nl_dpipe_table_counters_set_doit(struct sk_buff *skb,
struct genl_info *info);
int devlink_nl_resource_set_doit(struct sk_buff *skb, struct genl_info *info);
int devlink_nl_resource_dump_doit(struct sk_buff *skb, struct genl_info *info);
int devlink_nl_resource_dump_dumpit(struct sk_buff *skb,
struct netlink_callback *cb);
int devlink_nl_reload_doit(struct sk_buff *skb, struct genl_info *info);
int devlink_nl_param_get_doit(struct sk_buff *skb, struct genl_info *info);
int devlink_nl_param_get_dumpit(struct sk_buff *skb,
+213 -60
View File
@@ -174,11 +174,12 @@ devlink_param_cmode_is_supported(const struct devlink_param *param,
static int devlink_param_get(struct devlink *devlink,
const struct devlink_param *param,
struct devlink_param_gset_ctx *ctx)
struct devlink_param_gset_ctx *ctx,
struct netlink_ext_ack *extack)
{
if (!param->get)
return -EOPNOTSUPP;
return param->get(devlink, param->id, ctx);
return param->get(devlink, param->id, ctx, extack);
}
static int devlink_param_set(struct devlink *devlink,
@@ -191,50 +192,110 @@ static int devlink_param_set(struct devlink *devlink,
return param->set(devlink, param->id, ctx, extack);
}
static int devlink_param_get_default(struct devlink *devlink,
const struct devlink_param *param,
struct devlink_param_gset_ctx *ctx,
struct netlink_ext_ack *extack)
{
if (!param->get_default)
return -EOPNOTSUPP;
return param->get_default(devlink, param->id, ctx, extack);
}
static int devlink_param_reset_default(struct devlink *devlink,
const struct devlink_param *param,
enum devlink_param_cmode cmode,
struct netlink_ext_ack *extack)
{
if (!param->reset_default)
return -EOPNOTSUPP;
return param->reset_default(devlink, param->id, cmode, extack);
}
static int
devlink_nl_param_value_put(struct sk_buff *msg, enum devlink_param_type type,
int nla_type, union devlink_param_value *val,
bool flag_as_u8)
{
switch (type) {
case DEVLINK_PARAM_TYPE_U8:
if (nla_put_u8(msg, nla_type, val->vu8))
return -EMSGSIZE;
break;
case DEVLINK_PARAM_TYPE_U16:
if (nla_put_u16(msg, nla_type, val->vu16))
return -EMSGSIZE;
break;
case DEVLINK_PARAM_TYPE_U32:
if (nla_put_u32(msg, nla_type, val->vu32))
return -EMSGSIZE;
break;
case DEVLINK_PARAM_TYPE_U64:
if (devlink_nl_put_u64(msg, nla_type, val->vu64))
return -EMSGSIZE;
break;
case DEVLINK_PARAM_TYPE_STRING:
if (nla_put_string(msg, nla_type, val->vstr))
return -EMSGSIZE;
break;
case DEVLINK_PARAM_TYPE_BOOL:
/* default values of type bool are encoded with u8, so that
* false can be distinguished from not present
*/
if (flag_as_u8) {
if (nla_put_u8(msg, nla_type, val->vbool))
return -EMSGSIZE;
} else {
if (val->vbool && nla_put_flag(msg, nla_type))
return -EMSGSIZE;
}
break;
case DEVLINK_PARAM_TYPE_U64_ARRAY:
if (val->u64arr.size > __DEVLINK_PARAM_MAX_ARRAY_SIZE)
return -EMSGSIZE;
for (int i = 0; i < val->u64arr.size; i++) {
if (nla_put_uint(msg, nla_type, val->u64arr.val[i]))
return -EMSGSIZE;
}
break;
}
return 0;
}
static int
devlink_nl_param_value_fill_one(struct sk_buff *msg,
enum devlink_param_type type,
enum devlink_param_cmode cmode,
union devlink_param_value val)
union devlink_param_value *val,
union devlink_param_value *default_val,
bool has_default)
{
struct nlattr *param_value_attr;
int err = -EMSGSIZE;
param_value_attr = nla_nest_start_noflag(msg,
DEVLINK_ATTR_PARAM_VALUE);
if (!param_value_attr)
goto nla_put_failure;
return -EMSGSIZE;
if (nla_put_u8(msg, DEVLINK_ATTR_PARAM_VALUE_CMODE, cmode))
goto value_nest_cancel;
switch (type) {
case DEVLINK_PARAM_TYPE_U8:
if (nla_put_u8(msg, DEVLINK_ATTR_PARAM_VALUE_DATA, val.vu8))
err = devlink_nl_param_value_put(msg, type,
DEVLINK_ATTR_PARAM_VALUE_DATA,
val, false);
if (err)
goto value_nest_cancel;
if (has_default) {
err = devlink_nl_param_value_put(msg, type,
DEVLINK_ATTR_PARAM_VALUE_DEFAULT,
default_val, true);
if (err)
goto value_nest_cancel;
break;
case DEVLINK_PARAM_TYPE_U16:
if (nla_put_u16(msg, DEVLINK_ATTR_PARAM_VALUE_DATA, val.vu16))
goto value_nest_cancel;
break;
case DEVLINK_PARAM_TYPE_U32:
if (nla_put_u32(msg, DEVLINK_ATTR_PARAM_VALUE_DATA, val.vu32))
goto value_nest_cancel;
break;
case DEVLINK_PARAM_TYPE_U64:
if (devlink_nl_put_u64(msg, DEVLINK_ATTR_PARAM_VALUE_DATA,
val.vu64))
goto value_nest_cancel;
break;
case DEVLINK_PARAM_TYPE_STRING:
if (nla_put_string(msg, DEVLINK_ATTR_PARAM_VALUE_DATA,
val.vstr))
goto value_nest_cancel;
break;
case DEVLINK_PARAM_TYPE_BOOL:
if (val.vbool &&
nla_put_flag(msg, DEVLINK_ATTR_PARAM_VALUE_DATA))
goto value_nest_cancel;
break;
}
nla_nest_end(msg, param_value_attr);
@@ -242,50 +303,89 @@ devlink_nl_param_value_fill_one(struct sk_buff *msg,
value_nest_cancel:
nla_nest_cancel(msg, param_value_attr);
nla_put_failure:
return -EMSGSIZE;
return err;
}
static int devlink_nl_param_fill(struct sk_buff *msg, struct devlink *devlink,
unsigned int port_index,
struct devlink_param_item *param_item,
enum devlink_command cmd,
u32 portid, u32 seq, int flags)
u32 portid, u32 seq, int flags,
struct netlink_ext_ack *extack)
{
union devlink_param_value param_value[DEVLINK_PARAM_CMODE_MAX + 1];
bool default_value_set[DEVLINK_PARAM_CMODE_MAX + 1] = {};
bool param_value_set[DEVLINK_PARAM_CMODE_MAX + 1] = {};
const struct devlink_param *param = param_item->param;
struct devlink_param_gset_ctx ctx;
union devlink_param_value *default_value;
union devlink_param_value *param_value;
struct devlink_param_gset_ctx *ctx;
struct nlattr *param_values_list;
struct nlattr *param_attr;
void *hdr;
int err;
int i;
default_value = kcalloc(DEVLINK_PARAM_CMODE_MAX + 1,
sizeof(*default_value), GFP_KERNEL);
if (!default_value)
return -ENOMEM;
param_value = kcalloc(DEVLINK_PARAM_CMODE_MAX + 1,
sizeof(*param_value), GFP_KERNEL);
if (!param_value) {
kfree(default_value);
return -ENOMEM;
}
ctx = kzalloc_obj(*ctx);
if (!ctx) {
kfree(param_value);
kfree(default_value);
return -ENOMEM;
}
/* Get value from driver part to driverinit configuration mode */
for (i = 0; i <= DEVLINK_PARAM_CMODE_MAX; i++) {
if (!devlink_param_cmode_is_supported(param, i))
continue;
if (i == DEVLINK_PARAM_CMODE_DRIVERINIT) {
if (param_item->driverinit_value_new_valid)
if (param_item->driverinit_value_new_valid) {
param_value[i] = param_item->driverinit_value_new;
else if (param_item->driverinit_value_valid)
} else if (param_item->driverinit_value_valid) {
param_value[i] = param_item->driverinit_value;
else
return -EOPNOTSUPP;
} else {
err = -EOPNOTSUPP;
goto get_put_fail;
}
if (param_item->driverinit_value_valid) {
default_value[i] = param_item->driverinit_default;
default_value_set[i] = true;
}
} else {
ctx.cmode = i;
err = devlink_param_get(devlink, param, &ctx);
ctx->cmode = i;
err = devlink_param_get(devlink, param, ctx, extack);
if (err)
return err;
param_value[i] = ctx.val;
goto get_put_fail;
param_value[i] = ctx->val;
err = devlink_param_get_default(devlink, param, ctx,
extack);
if (!err) {
default_value[i] = ctx->val;
default_value_set[i] = true;
} else if (err != -EOPNOTSUPP) {
goto get_put_fail;
}
}
param_value_set[i] = true;
}
err = -EMSGSIZE;
hdr = genlmsg_put(msg, portid, seq, &devlink_nl_family, flags, cmd);
if (!hdr)
return -EMSGSIZE;
goto get_put_fail;
if (devlink_nl_put_handle(msg, devlink))
goto genlmsg_cancel;
@@ -315,7 +415,9 @@ static int devlink_nl_param_fill(struct sk_buff *msg, struct devlink *devlink,
if (!param_value_set[i])
continue;
err = devlink_nl_param_value_fill_one(msg, param->type,
i, param_value[i]);
i, &param_value[i],
&default_value[i],
default_value_set[i]);
if (err)
goto values_list_nest_cancel;
}
@@ -323,6 +425,9 @@ static int devlink_nl_param_fill(struct sk_buff *msg, struct devlink *devlink,
nla_nest_end(msg, param_values_list);
nla_nest_end(msg, param_attr);
genlmsg_end(msg, hdr);
kfree(default_value);
kfree(param_value);
kfree(ctx);
return 0;
values_list_nest_cancel:
@@ -331,7 +436,11 @@ param_nest_cancel:
nla_nest_cancel(msg, param_attr);
genlmsg_cancel:
genlmsg_cancel(msg, hdr);
return -EMSGSIZE;
get_put_fail:
kfree(default_value);
kfree(param_value);
kfree(ctx);
return err;
}
static void devlink_param_notify(struct devlink *devlink,
@@ -357,7 +466,7 @@ static void devlink_param_notify(struct devlink *devlink,
if (!msg)
return;
err = devlink_nl_param_fill(msg, devlink, port_index, param_item, cmd,
0, 0, 0);
0, 0, 0, NULL);
if (err) {
nlmsg_free(msg);
return;
@@ -400,7 +509,8 @@ static int devlink_nl_param_get_dump_one(struct sk_buff *msg,
err = devlink_nl_param_fill(msg, devlink, 0, param_item,
DEVLINK_CMD_PARAM_GET,
NETLINK_CB(cb->skb).portid,
cb->nlh->nlmsg_seq, flags);
cb->nlh->nlmsg_seq, flags,
cb->extack);
if (err == -EOPNOTSUPP) {
err = 0;
} else if (err) {
@@ -436,7 +546,7 @@ devlink_param_value_get_from_info(const struct devlink_param *param,
union devlink_param_value *value)
{
struct nlattr *param_data;
int len;
int len, cnt, rem;
param_data = info->attrs[DEVLINK_ATTR_PARAM_VALUE_DATA];
@@ -476,6 +586,28 @@ devlink_param_value_get_from_info(const struct devlink_param *param,
return -EINVAL;
value->vbool = nla_get_flag(param_data);
break;
case DEVLINK_PARAM_TYPE_U64_ARRAY:
cnt = 0;
nla_for_each_attr_type(param_data,
DEVLINK_ATTR_PARAM_VALUE_DATA,
genlmsg_data(info->genlhdr),
genlmsg_len(info->genlhdr), rem) {
if (cnt >= __DEVLINK_PARAM_MAX_ARRAY_SIZE)
return -EMSGSIZE;
if ((nla_len(param_data) != sizeof(u64)) &&
(nla_len(param_data) != sizeof(u32))) {
NL_SET_BAD_ATTR(info->extack, param_data);
return -EINVAL;
}
value->u64arr.val[cnt] = nla_get_uint(param_data);
cnt++;
}
value->u64arr.size = cnt;
break;
}
return 0;
}
@@ -509,8 +641,8 @@ int devlink_nl_param_get_doit(struct sk_buff *skb,
return -ENOMEM;
err = devlink_nl_param_fill(msg, devlink, 0, param_item,
DEVLINK_CMD_PARAM_GET,
info->snd_portid, info->snd_seq, 0);
DEVLINK_CMD_PARAM_GET, info->snd_portid,
info->snd_seq, 0, info->extack);
if (err) {
nlmsg_free(msg);
return err;
@@ -531,6 +663,7 @@ static int __devlink_nl_cmd_param_set_doit(struct devlink *devlink,
struct devlink_param_item *param_item;
const struct devlink_param *param;
union devlink_param_value value;
bool reset_default;
int err = 0;
param_item = devlink_param_get_from_info(params, info);
@@ -542,13 +675,18 @@ static int __devlink_nl_cmd_param_set_doit(struct devlink *devlink,
return err;
if (param_type != param->type)
return -EINVAL;
err = devlink_param_value_get_from_info(param, info, &value);
if (err)
return err;
if (param->validate) {
err = param->validate(devlink, param->id, value, info->extack);
reset_default = info->attrs[DEVLINK_ATTR_PARAM_RESET_DEFAULT];
if (!reset_default) {
err = devlink_param_value_get_from_info(param, info, &value);
if (err)
return err;
if (param->validate) {
err = param->validate(devlink, param->id, &value,
info->extack);
if (err)
return err;
}
}
if (GENL_REQ_ATTR_CHECK(info, DEVLINK_ATTR_PARAM_VALUE_CMODE))
@@ -558,6 +696,15 @@ static int __devlink_nl_cmd_param_set_doit(struct devlink *devlink,
return -EOPNOTSUPP;
if (cmode == DEVLINK_PARAM_CMODE_DRIVERINIT) {
if (reset_default) {
if (!param_item->driverinit_value_valid) {
NL_SET_ERR_MSG(info->extack,
"Default value not available");
return -EOPNOTSUPP;
}
value = param_item->driverinit_default;
}
param_item->driverinit_value_new = value;
param_item->driverinit_value_new_valid = true;
} else {
@@ -565,7 +712,12 @@ static int __devlink_nl_cmd_param_set_doit(struct devlink *devlink,
return -EOPNOTSUPP;
ctx.val = value;
ctx.cmode = cmode;
err = devlink_param_set(devlink, param, &ctx, info->extack);
if (reset_default)
err = devlink_param_reset_default(devlink, param, cmode,
info->extack);
else
err = devlink_param_set(devlink, param, &ctx,
info->extack);
if (err)
return err;
}
@@ -797,7 +949,7 @@ EXPORT_SYMBOL_GPL(devl_param_driverinit_value_get);
* configuration mode default value.
*/
void devl_param_driverinit_value_set(struct devlink *devlink, u32 param_id,
union devlink_param_value init_val)
union devlink_param_value *init_val)
{
struct devlink_param_item *param_item;
@@ -811,8 +963,9 @@ void devl_param_driverinit_value_set(struct devlink *devlink, u32 param_id,
DEVLINK_PARAM_CMODE_DRIVERINIT)))
return;
param_item->driverinit_value = init_val;
param_item->driverinit_value = *init_val;
param_item->driverinit_value_valid = true;
param_item->driverinit_default = *init_val;
devlink_param_notify(devlink, 0, param_item, DEVLINK_CMD_PARAM_NEW);
}
+12 -9
View File
@@ -220,8 +220,9 @@ size_t devlink_nl_port_handle_size(struct devlink_port *devlink_port)
{
struct devlink *devlink = devlink_port->devlink;
return nla_total_size(strlen(devlink->dev->bus->name) + 1) /* DEVLINK_ATTR_BUS_NAME */
+ nla_total_size(strlen(dev_name(devlink->dev)) + 1) /* DEVLINK_ATTR_DEV_NAME */
return nla_total_size(strlen(devlink_bus_name(devlink)) + 1) /* DEVLINK_ATTR_BUS_NAME */
+ nla_total_size(strlen(devlink_dev_name(devlink)) + 1) /* DEVLINK_ATTR_DEV_NAME */
+ nla_total_size(8) /* DEVLINK_ATTR_INDEX */
+ nla_total_size(4); /* DEVLINK_ATTR_PORT_INDEX */
}
@@ -975,7 +976,7 @@ static void devlink_port_type_warn(struct work_struct *work)
struct devlink_port *port = container_of(to_delayed_work(work),
struct devlink_port,
type_warn_dw);
dev_warn(port->devlink->dev, "Type was not set for devlink port.");
devl_warn(port->devlink, "Type was not set for devlink port.");
}
static bool devlink_port_type_should_warn(struct devlink_port *devlink_port)
@@ -1024,6 +1025,7 @@ void devlink_port_init(struct devlink *devlink,
return;
devlink_port->devlink = devlink;
INIT_LIST_HEAD(&devlink_port->region_list);
INIT_LIST_HEAD(&devlink_port->resource_list);
devlink_port->initialized = true;
}
EXPORT_SYMBOL_GPL(devlink_port_init);
@@ -1041,6 +1043,7 @@ EXPORT_SYMBOL_GPL(devlink_port_init);
void devlink_port_fini(struct devlink_port *devlink_port)
{
WARN_ON(!list_empty(&devlink_port->region_list));
WARN_ON(!list_empty(&devlink_port->resource_list));
}
EXPORT_SYMBOL_GPL(devlink_port_fini);
@@ -1241,9 +1244,9 @@ static void __devlink_port_type_set(struct devlink_port *devlink_port,
*/
void devlink_port_type_eth_set(struct devlink_port *devlink_port)
{
dev_warn(devlink_port->devlink->dev,
"devlink port type for port %d set to Ethernet without a software interface reference, device type not supported by the kernel?\n",
devlink_port->index);
devl_warn(devlink_port->devlink,
"devlink port type for port %d set to Ethernet without a software interface reference, device type not supported by the kernel?\n",
devlink_port->index);
__devlink_port_type_set(devlink_port, DEVLINK_PORT_TYPE_ETH, NULL);
}
EXPORT_SYMBOL_GPL(devlink_port_type_eth_set);
@@ -1272,9 +1275,9 @@ EXPORT_SYMBOL_GPL(devlink_port_type_ib_set);
void devlink_port_type_clear(struct devlink_port *devlink_port)
{
if (devlink_port->type == DEVLINK_PORT_TYPE_ETH)
dev_warn(devlink_port->devlink->dev,
"devlink port type for port %d cleared without a software interface reference, device type not supported by the kernel?\n",
devlink_port->index);
devl_warn(devlink_port->devlink,
"devlink port type for port %d cleared without a software interface reference, device type not supported by the kernel?\n",
devlink_port->index);
__devlink_port_type_set(devlink_port, DEVLINK_PORT_TYPE_NOTSET, NULL);
}
EXPORT_SYMBOL_GPL(devlink_port_type_clear);
+21 -17
View File
@@ -12,8 +12,7 @@ devlink_rate_is_leaf(struct devlink_rate *devlink_rate)
return devlink_rate->type == DEVLINK_RATE_TYPE_LEAF;
}
static inline bool
devlink_rate_is_node(struct devlink_rate *devlink_rate)
bool devlink_rate_is_node(const struct devlink_rate *devlink_rate)
{
return devlink_rate->type == DEVLINK_RATE_TYPE_NODE;
}
@@ -487,16 +486,19 @@ static int devlink_nl_rate_set(struct devlink_rate *devlink_rate,
devlink_rate->tx_weight = weight;
}
nla_parent = attrs[DEVLINK_ATTR_RATE_PARENT_NODE_NAME];
if (nla_parent) {
err = devlink_nl_rate_parent_node_set(devlink_rate, info,
nla_parent);
if (attrs[DEVLINK_ATTR_RATE_TC_BWS]) {
err = devlink_nl_rate_tc_bw_set(devlink_rate, info);
if (err)
return err;
}
if (attrs[DEVLINK_ATTR_RATE_TC_BWS]) {
err = devlink_nl_rate_tc_bw_set(devlink_rate, info);
/* Keep parent setting last because it takes a reference. This function
* has no rollback, so failing after taking the ref would leak it.
*/
nla_parent = attrs[DEVLINK_ATTR_RATE_PARENT_NODE_NAME];
if (nla_parent) {
err = devlink_nl_rate_parent_node_set(devlink_rate, info,
nla_parent);
if (err)
return err;
}
@@ -688,14 +690,16 @@ int devlink_nl_rate_del_doit(struct sk_buff *skb, struct genl_info *info)
return err;
}
int devlink_rate_nodes_check(struct devlink *devlink, u16 mode,
struct netlink_ext_ack *extack)
int devlink_rates_check(struct devlink *devlink,
bool (*rate_filter)(const struct devlink_rate *),
struct netlink_ext_ack *extack)
{
struct devlink_rate *devlink_rate;
list_for_each_entry(devlink_rate, &devlink->rate_list, list)
if (devlink_rate_is_node(devlink_rate)) {
NL_SET_ERR_MSG(extack, "Rate node(s) exists.");
if (!rate_filter || rate_filter(devlink_rate)) {
if (extack)
NL_SET_ERR_MSG(extack, "Rate node(s) exists.");
return -EBUSY;
}
return 0;
@@ -724,11 +728,6 @@ devl_rate_node_create(struct devlink *devlink, void *priv, char *node_name,
if (!rate_node)
return ERR_PTR(-ENOMEM);
if (parent) {
rate_node->parent = parent;
refcount_inc(&rate_node->parent->refcnt);
}
rate_node->type = DEVLINK_RATE_TYPE_NODE;
rate_node->devlink = devlink;
rate_node->priv = priv;
@@ -739,6 +738,11 @@ devl_rate_node_create(struct devlink *devlink, void *priv, char *node_name,
return ERR_PTR(-ENOMEM);
}
if (parent) {
rate_node->parent = parent;
refcount_inc(&rate_node->parent->refcnt);
}
refcount_set(&rate_node->refcnt, 1);
list_add(&rate_node->list, &devlink->rate_list);
devlink_rate_notify(rate_node, DEVLINK_CMD_RATE_NEW);
+273 -47
View File
@@ -36,15 +36,16 @@ struct devlink_resource {
};
static struct devlink_resource *
devlink_resource_find(struct devlink *devlink,
struct devlink_resource *resource, u64 resource_id)
__devlink_resource_find(struct list_head *resource_list_head,
struct devlink_resource *resource,
u64 resource_id)
{
struct list_head *resource_list;
if (resource)
resource_list = &resource->resource_list;
else
resource_list = &devlink->resource_list;
resource_list = resource_list_head;
list_for_each_entry(resource, resource_list, list) {
struct devlink_resource *child_resource;
@@ -52,14 +53,23 @@ devlink_resource_find(struct devlink *devlink,
if (resource->id == resource_id)
return resource;
child_resource = devlink_resource_find(devlink, resource,
resource_id);
child_resource = __devlink_resource_find(resource_list_head,
resource,
resource_id);
if (child_resource)
return child_resource;
}
return NULL;
}
static struct devlink_resource *
devlink_resource_find(struct devlink *devlink,
struct devlink_resource *resource, u64 resource_id)
{
return __devlink_resource_find(&devlink->resource_list,
resource, resource_id);
}
static void
devlink_resource_validate_children(struct devlink_resource *resource)
{
@@ -213,11 +223,38 @@ nla_put_failure:
return -EMSGSIZE;
}
static int devlink_resource_list_fill(struct sk_buff *skb,
struct devlink *devlink,
struct list_head *resource_list_head,
int *idx)
{
struct devlink_resource *resource;
int i = 0;
int err;
list_for_each_entry(resource, resource_list_head, list) {
if (i < *idx) {
i++;
continue;
}
err = devlink_resource_put(devlink, skb, resource);
if (err) {
*idx = i;
return err;
}
i++;
}
*idx = 0;
return 0;
}
static int devlink_resource_fill(struct genl_info *info,
enum devlink_command cmd, int flags)
{
struct devlink_port *devlink_port = info->user_ptr[1];
struct devlink *devlink = info->user_ptr[0];
struct devlink_resource *resource;
struct list_head *resource_list;
struct nlattr *resources_attr;
struct sk_buff *skb = NULL;
struct nlmsghdr *nlh;
@@ -226,7 +263,9 @@ static int devlink_resource_fill(struct genl_info *info,
int i;
int err;
resource = list_first_entry(&devlink->resource_list,
resource_list = devlink_port ?
&devlink_port->resource_list : &devlink->resource_list;
resource = list_first_entry(resource_list,
struct devlink_resource, list);
start_again:
err = devlink_nl_msg_reply_and_new(&skb, info);
@@ -242,6 +281,9 @@ start_again:
if (devlink_nl_put_handle(skb, devlink))
goto nla_put_failure;
if (devlink_port &&
nla_put_u32(skb, DEVLINK_ATTR_PORT_INDEX, devlink_port->index))
goto nla_put_failure;
resources_attr = nla_nest_start_noflag(skb,
DEVLINK_ATTR_RESOURCE_LIST);
@@ -250,7 +292,7 @@ start_again:
incomplete = false;
i = 0;
list_for_each_entry_from(resource, &devlink->resource_list, list) {
list_for_each_entry_from(resource, resource_list, list) {
err = devlink_resource_put(devlink, skb, resource);
if (err) {
if (!i)
@@ -284,14 +326,133 @@ err_resource_put:
int devlink_nl_resource_dump_doit(struct sk_buff *skb, struct genl_info *info)
{
struct devlink_port *devlink_port = info->user_ptr[1];
struct devlink *devlink = info->user_ptr[0];
struct list_head *resource_list;
if (list_empty(&devlink->resource_list))
if (info->attrs[DEVLINK_ATTR_PORT_INDEX] && !devlink_port)
return -ENODEV;
resource_list = devlink_port ?
&devlink_port->resource_list : &devlink->resource_list;
if (list_empty(resource_list))
return -EOPNOTSUPP;
return devlink_resource_fill(info, DEVLINK_CMD_RESOURCE_DUMP, 0);
}
static int
devlink_resource_dump_fill_one(struct sk_buff *skb, struct devlink *devlink,
struct devlink_port *devlink_port,
struct netlink_callback *cb, int flags, int *idx)
{
struct list_head *resource_list;
struct nlattr *resources_attr;
int start_idx = *idx;
void *hdr;
int err;
resource_list = devlink_port ?
&devlink_port->resource_list : &devlink->resource_list;
if (list_empty(resource_list))
return 0;
err = -EMSGSIZE;
hdr = genlmsg_put(skb, NETLINK_CB(cb->skb).portid, cb->nlh->nlmsg_seq,
&devlink_nl_family, flags, DEVLINK_CMD_RESOURCE_DUMP);
if (!hdr)
return err;
if (devlink_nl_put_handle(skb, devlink))
goto nla_put_failure;
if (devlink_port &&
nla_put_u32(skb, DEVLINK_ATTR_PORT_INDEX, devlink_port->index))
goto nla_put_failure;
resources_attr = nla_nest_start_noflag(skb, DEVLINK_ATTR_RESOURCE_LIST);
if (!resources_attr)
goto nla_put_failure;
err = devlink_resource_list_fill(skb, devlink, resource_list, idx);
if (err) {
if (*idx == start_idx)
goto resource_list_cancel;
nla_nest_end(skb, resources_attr);
genlmsg_end(skb, hdr);
return err;
}
nla_nest_end(skb, resources_attr);
genlmsg_end(skb, hdr);
return 0;
resource_list_cancel:
nla_nest_cancel(skb, resources_attr);
nla_put_failure:
genlmsg_cancel(skb, hdr);
return err;
}
static int
devlink_nl_resource_dump_one(struct sk_buff *skb, struct devlink *devlink,
struct netlink_callback *cb, int flags)
{
struct devlink_nl_dump_state *state = devlink_dump_state(cb);
const struct genl_info *info = genl_info_dump(cb);
struct devlink_port *devlink_port;
struct nlattr *scope_attr = NULL;
unsigned long port_idx;
u32 scope = 0;
int err;
if (info->attrs && info->attrs[DEVLINK_ATTR_RESOURCE_SCOPE_MASK]) {
scope_attr = info->attrs[DEVLINK_ATTR_RESOURCE_SCOPE_MASK];
scope = nla_get_u32(scope_attr);
if (!scope) {
NL_SET_ERR_MSG_ATTR(info->extack, scope_attr,
"empty resource scope selection");
return -EINVAL;
}
}
if (!state->port_ctx.index_valid &&
(!scope || (scope & DEVLINK_RESOURCE_SCOPE_DEV))) {
err = devlink_resource_dump_fill_one(skb, devlink, NULL,
cb, flags, &state->idx);
if (err)
return err;
state->idx = 0;
}
if (scope && !(scope & DEVLINK_RESOURCE_SCOPE_PORT))
goto out;
/* Check in case port was removed between dump callbacks. */
if (state->port_ctx.index_valid &&
!xa_load(&devlink->ports, state->port_ctx.index))
state->idx = 0;
state->port_ctx.index_valid = true;
xa_for_each_start(&devlink->ports, port_idx, devlink_port,
state->port_ctx.index) {
err = devlink_resource_dump_fill_one(skb, devlink, devlink_port,
cb, flags, &state->idx);
if (err) {
state->port_ctx.index = port_idx;
return err;
}
state->idx = 0;
}
out:
state->port_ctx.index_valid = false;
state->port_ctx.index = 0;
return 0;
}
int devlink_nl_resource_dump_dumpit(struct sk_buff *skb,
struct netlink_callback *cb)
{
return devlink_nl_dumpit(skb, cb, devlink_nl_resource_dump_one);
}
int devlink_resources_validate(struct devlink *devlink,
struct devlink_resource *resource,
struct genl_info *info)
@@ -314,36 +475,25 @@ int devlink_resources_validate(struct devlink *devlink,
return err;
}
/**
* devl_resource_register - devlink resource register
*
* @devlink: devlink
* @resource_name: resource's name
* @resource_size: resource's size
* @resource_id: resource's id
* @parent_resource_id: resource's parent id
* @size_params: size parameters
*
* Generic resources should reuse the same names across drivers.
* Please see the generic resources list at:
* Documentation/networking/devlink/devlink-resource.rst
*/
int devl_resource_register(struct devlink *devlink,
const char *resource_name,
u64 resource_size,
u64 resource_id,
u64 parent_resource_id,
const struct devlink_resource_size_params *size_params)
static int
__devl_resource_register(struct devlink *devlink,
struct list_head *resource_list_head,
const char *resource_name, u64 resource_size,
u64 resource_id, u64 parent_resource_id,
const struct devlink_resource_size_params *params)
{
struct devlink_resource *resource;
struct list_head *resource_list;
bool top_hierarchy;
WARN_ON(resource_id == DEVLINK_RESOURCE_ID_PARENT_TOP);
lockdep_assert_held(&devlink->lock);
top_hierarchy = parent_resource_id == DEVLINK_RESOURCE_ID_PARENT_TOP;
resource = devlink_resource_find(devlink, NULL, resource_id);
resource = __devlink_resource_find(resource_list_head, NULL,
resource_id);
if (resource)
return -EEXIST;
@@ -352,12 +502,13 @@ int devl_resource_register(struct devlink *devlink,
return -ENOMEM;
if (top_hierarchy) {
resource_list = &devlink->resource_list;
resource_list = resource_list_head;
} else {
struct devlink_resource *parent_resource;
parent_resource = devlink_resource_find(devlink, NULL,
parent_resource_id);
parent_resource = __devlink_resource_find(resource_list_head,
NULL,
parent_resource_id);
if (parent_resource) {
resource_list = &parent_resource->resource_list;
resource->parent = parent_resource;
@@ -372,23 +523,64 @@ int devl_resource_register(struct devlink *devlink,
resource->size_new = resource_size;
resource->id = resource_id;
resource->size_valid = true;
memcpy(&resource->size_params, size_params,
sizeof(resource->size_params));
memcpy(&resource->size_params, params, sizeof(resource->size_params));
INIT_LIST_HEAD(&resource->resource_list);
list_add_tail(&resource->list, resource_list);
return 0;
}
/**
* devl_resource_register - devlink resource register
*
* @devlink: devlink
* @resource_name: resource's name
* @resource_size: resource's size
* @resource_id: resource's id
* @parent_resource_id: resource's parent id
* @params: size parameters
*
* Generic resources should reuse the same names across drivers.
* Please see the generic resources list at:
* Documentation/networking/devlink/devlink-resource.rst
*
* Return: 0 on success, negative error code otherwise.
*/
int devl_resource_register(struct devlink *devlink, const char *resource_name,
u64 resource_size, u64 resource_id,
u64 parent_resource_id,
const struct devlink_resource_size_params *params)
{
return __devl_resource_register(devlink, &devlink->resource_list,
resource_name, resource_size,
resource_id, parent_resource_id,
params);
}
EXPORT_SYMBOL_GPL(devl_resource_register);
static void devlink_resource_unregister(struct devlink *devlink,
struct devlink_resource *resource)
static void devlink_resource_unregister(struct devlink_resource *resource)
{
struct devlink_resource *tmp, *child_resource;
list_for_each_entry_safe(child_resource, tmp, &resource->resource_list,
list) {
devlink_resource_unregister(devlink, child_resource);
devlink_resource_unregister(child_resource);
list_del(&child_resource->list);
kfree(child_resource);
}
}
static void
__devl_resources_unregister(struct devlink *devlink,
struct list_head *resource_list_head)
{
struct devlink_resource *tmp, *child_resource;
lockdep_assert_held(&devlink->lock);
list_for_each_entry_safe(child_resource, tmp, resource_list_head,
list) {
devlink_resource_unregister(child_resource);
list_del(&child_resource->list);
kfree(child_resource);
}
@@ -401,16 +593,7 @@ static void devlink_resource_unregister(struct devlink *devlink,
*/
void devl_resources_unregister(struct devlink *devlink)
{
struct devlink_resource *tmp, *child_resource;
lockdep_assert_held(&devlink->lock);
list_for_each_entry_safe(child_resource, tmp, &devlink->resource_list,
list) {
devlink_resource_unregister(devlink, child_resource);
list_del(&child_resource->list);
kfree(child_resource);
}
__devl_resources_unregister(devlink, &devlink->resource_list);
}
EXPORT_SYMBOL_GPL(devl_resources_unregister);
@@ -502,3 +685,46 @@ void devl_resource_occ_get_unregister(struct devlink *devlink,
resource->occ_get_priv = NULL;
}
EXPORT_SYMBOL_GPL(devl_resource_occ_get_unregister);
/**
* devl_port_resource_register - devlink port resource register
*
* @devlink_port: devlink port
* @resource_name: resource's name
* @resource_size: resource's size
* @resource_id: resource's id
* @parent_resource_id: resource's parent id
* @params: size parameters
*
* Generic resources should reuse the same names across drivers.
* Please see the generic resources list at:
* Documentation/networking/devlink/devlink-resource.rst
*
* Return: 0 on success, negative error code otherwise.
*/
int
devl_port_resource_register(struct devlink_port *devlink_port,
const char *resource_name,
u64 resource_size, u64 resource_id,
u64 parent_resource_id,
const struct devlink_resource_size_params *params)
{
return __devl_resource_register(devlink_port->devlink,
&devlink_port->resource_list,
resource_name, resource_size,
resource_id, parent_resource_id,
params);
}
EXPORT_SYMBOL_GPL(devl_port_resource_register);
/**
* devl_port_resources_unregister - unregister all devlink port resources
*
* @devlink_port: devlink port
*/
void devl_port_resources_unregister(struct devlink_port *devlink_port)
{
__devl_resources_unregister(devlink_port->devlink,
&devlink_port->resource_list);
}
EXPORT_SYMBOL_GPL(devl_port_resources_unregister);
+161
View File
@@ -0,0 +1,161 @@
// SPDX-License-Identifier: GPL-2.0-or-later
/* Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. */
#include <net/devlink.h>
#include "devl_internal.h"
static LIST_HEAD(shd_list);
static DEFINE_MUTEX(shd_mutex); /* Protects shd_list and shd->list */
/* This structure represents a shared devlink instance,
* there is one created per identifier (e.g., serial number).
*/
struct devlink_shd {
struct list_head list; /* Node in shd list */
const char *id; /* Identifier string (e.g., serial number) */
refcount_t refcount; /* Reference count */
size_t priv_size; /* Size of driver private data */
char priv[] __aligned(NETDEV_ALIGN) __counted_by(priv_size);
};
static struct devlink_shd *devlink_shd_lookup(const char *id)
{
struct devlink_shd *shd;
list_for_each_entry(shd, &shd_list, list) {
if (!strcmp(shd->id, id))
return shd;
}
return NULL;
}
static struct devlink_shd *devlink_shd_create(const char *id,
const struct devlink_ops *ops,
size_t priv_size,
const struct device_driver *driver)
{
struct devlink_shd *shd;
struct devlink *devlink;
devlink = __devlink_alloc(ops, sizeof(struct devlink_shd) + priv_size,
&init_net, NULL, driver);
if (!devlink)
return NULL;
shd = devlink_priv(devlink);
shd->id = kstrdup(id, GFP_KERNEL);
if (!shd->id)
goto err_devlink_free;
shd->priv_size = priv_size;
refcount_set(&shd->refcount, 1);
devl_lock(devlink);
devl_register(devlink);
devl_unlock(devlink);
list_add_tail(&shd->list, &shd_list);
return shd;
err_devlink_free:
devlink_free(devlink);
return NULL;
}
static void devlink_shd_destroy(struct devlink_shd *shd)
{
struct devlink *devlink = priv_to_devlink(shd);
list_del(&shd->list);
devl_lock(devlink);
devl_unregister(devlink);
devl_unlock(devlink);
kfree(shd->id);
devlink_free(devlink);
}
/**
* devlink_shd_get - Get or create a shared devlink instance
* @id: Identifier string (e.g., serial number) for the shared instance
* @ops: Devlink operations structure
* @priv_size: Size of private data structure
* @driver: Driver associated with the shared devlink instance
*
* Get an existing shared devlink instance identified by @id, or create
* a new one if it doesn't exist. Return the devlink instance with a
* reference held. The caller must call devlink_shd_put() when done.
*
* All callers sharing the same @id must pass identical @ops, @priv_size
* and @driver. A mismatch triggers a warning and returns NULL.
*
* Return: Pointer to the shared devlink instance on success,
* NULL on failure
*/
struct devlink *devlink_shd_get(const char *id,
const struct devlink_ops *ops,
size_t priv_size,
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);
goto unlock;
}
devlink = priv_to_devlink(shd);
if (WARN_ON_ONCE(devlink->ops != ops ||
shd->priv_size != priv_size ||
devlink->dev_driver != driver)) {
shd = NULL;
goto unlock;
}
refcount_inc(&shd->refcount);
unlock:
mutex_unlock(&shd_mutex);
return shd ? priv_to_devlink(shd) : NULL;
}
EXPORT_SYMBOL_GPL(devlink_shd_get);
/**
* devlink_shd_put - Release a reference on a shared devlink instance
* @devlink: Shared devlink instance
*
* Release a reference on a shared devlink instance obtained via
* devlink_shd_get().
*/
void devlink_shd_put(struct devlink *devlink)
{
struct devlink_shd *shd;
mutex_lock(&shd_mutex);
shd = devlink_priv(devlink);
if (refcount_dec_and_test(&shd->refcount))
devlink_shd_destroy(shd);
mutex_unlock(&shd_mutex);
}
EXPORT_SYMBOL_GPL(devlink_shd_put);
/**
* devlink_shd_get_priv - Get private data from shared devlink instance
* @devlink: Devlink instance
*
* Returns a pointer to the driver's private data structure within
* the shared devlink instance.
*
* Return: Pointer to private data
*/
void *devlink_shd_get_priv(struct devlink *devlink)
{
struct devlink_shd *shd = devlink_priv(devlink);
return shd->priv;
}
EXPORT_SYMBOL_GPL(devlink_shd_get_priv);
+2 -1
View File
@@ -182,7 +182,8 @@ static const struct devlink_ops dsa_devlink_ops = {
};
int dsa_devlink_param_get(struct devlink *dl, u32 id,
struct devlink_param_gset_ctx *ctx)
struct devlink_param_gset_ctx *ctx,
struct netlink_ext_ack *extack)
{
struct dsa_switch *ds = dsa_devlink_to_ds(dl);
@@ -21,21 +21,21 @@ Test Cases:
----------
1. test_no_tc_mapping_bandwidth:
- Verifies that without TC mapping, bandwidth is NOT distributed according to
the configured 80/20 split between TC4 and TC3
- This test should fail if bandwidth matches the 80/20 split without TC
the configured 20/80 split between TC3 and TC4
- This test should fail if bandwidth matches the 20/80 split without TC
mapping
- Expected: Bandwidth should NOT be distributed as 80/20
- Expected: Bandwidth should NOT be distributed as 20/80
2. test_tc_mapping_bandwidth:
- Configures TC mapping using mqprio qdisc
- Verifies that with TC mapping, bandwidth IS distributed according to the
configured 80/20 split between TC3 and TC4
- Expected: Bandwidth should be distributed as 80/20
configured 20/80 split between TC3 and TC4
- Expected: Bandwidth should be distributed as 20/80
Bandwidth Distribution:
----------------------
- TC3 (VLAN 101): Configured for 80% of total bandwidth
- TC4 (VLAN 102): Configured for 20% of total bandwidth
- TC3 (VLAN 101): Configured for 20% of total bandwidth
- TC4 (VLAN 102): Configured for 80% of total bandwidth
- Total bandwidth: 1Gbps
- Tolerance: +-12%
@@ -64,43 +64,40 @@ from lib.py import KsftSkipEx, KsftFailEx, KsftXfailEx
from lib.py import NetDrvEpEnv, DevlinkFamily
from lib.py import NlError
from lib.py import cmd, defer, ethtool, ip
from lib.py import Iperf3Runner
class BandwidthValidator:
"""
Validates bandwidth totals and per-TC shares against expected values
with a tolerance.
Validates total bandwidth and individual shares with tolerance
relative to the overall total.
"""
def __init__(self):
def __init__(self, shares):
self.tolerance_percent = 12
self.expected_total_gbps = 1.0
self.total_min_expected = self.min_expected(self.expected_total_gbps)
self.total_max_expected = self.max_expected(self.expected_total_gbps)
self.tc_expected_percent = {
3: 20.0,
4: 80.0,
}
self.expected_total = sum(shares.values())
self.bounds = {}
for name, exp in shares.items():
self.bounds[name] = (self.min_expected(exp), self.max_expected(exp))
def min_expected(self, value):
"""Calculates the minimum acceptable value based on tolerance."""
return value - (value * self.tolerance_percent / 100)
return value - (self.expected_total * self.tolerance_percent / 100)
def max_expected(self, value):
"""Calculates the maximum acceptable value based on tolerance."""
return value + (value * self.tolerance_percent / 100)
return value + (self.expected_total * self.tolerance_percent / 100)
def bound(self, expected, value):
"""Returns True if value is within expected tolerance."""
return self.min_expected(expected) <= value <= self.max_expected(expected)
def tc_bandwidth_bound(self, value, tc_ix):
def bound(self, values):
"""
Returns True if the given bandwidth value is within tolerance
for the TC's expected bandwidth.
Return True if all given values fall within tolerance.
"""
expected = self.tc_expected_percent[tc_ix]
return self.bound(expected, value)
for name, value in values.items():
low, high = self.bounds[name]
if not low <= value <= high:
return False
return True
def setup_vf(cfg, set_tc_mapping=True):
@@ -116,8 +113,8 @@ def setup_vf(cfg, set_tc_mapping=True):
except Exception as exc:
raise KsftSkipEx(f"Failed to enable switchdev mode on {cfg.pci}") from exc
try:
cmd(f"echo 1 > /sys/class/net/{cfg.ifname}/device/sriov_numvfs")
defer(cmd, f"echo 0 > /sys/class/net/{cfg.ifname}/device/sriov_numvfs")
cmd(f"echo 1 > /sys/class/net/{cfg.ifname}/device/sriov_numvfs", shell=True)
defer(cmd, f"echo 0 > /sys/class/net/{cfg.ifname}/device/sriov_numvfs", shell=True)
except Exception as exc:
raise KsftSkipEx(f"Failed to enable SR-IOV on {cfg.ifname}") from exc
@@ -139,8 +136,8 @@ def setup_vlans_on_vf(vf_ifc):
Sets up two VLAN interfaces on the given VF, each mapped to a different TC.
"""
vlan_configs = [
{"vlan_id": 101, "tc": 3, "ip": "198.51.100.2"},
{"vlan_id": 102, "tc": 4, "ip": "198.51.100.10"},
{"vlan_id": 101, "tc": 3, "ip": "198.51.100.1"},
{"vlan_id": 102, "tc": 4, "ip": "198.51.100.9"},
]
for config in vlan_configs:
@@ -224,13 +221,13 @@ def setup_devlink_rate(cfg):
raise KsftFailEx(f"rate_set failed on VF port {port_index}") from exc
def setup_remote_server(cfg):
def setup_remote_vlans(cfg):
"""
Sets up VLAN interfaces and starts iperf3 servers on the remote side.
Sets up VLAN interfaces on the remote side.
"""
remote_dev = cfg.remote_ifname
vlan_ids = [101, 102]
remote_ips = ["198.51.100.1", "198.51.100.9"]
remote_ips = ["198.51.100.2", "198.51.100.10"]
for vlan_id, ip_addr in zip(vlan_ids, remote_ips):
vlan_dev = f"{remote_dev}.{vlan_id}"
@@ -238,14 +235,13 @@ def setup_remote_server(cfg):
f"type vlan id {vlan_id}", host=cfg.remote)
cmd(f"ip addr add {ip_addr}/29 dev {vlan_dev}", host=cfg.remote)
cmd(f"ip link set dev {vlan_dev} up", host=cfg.remote)
cmd(f"iperf3 -s -1 -B {ip_addr}",background=True, host=cfg.remote)
defer(cmd, f"ip link del {vlan_dev}", host=cfg.remote)
def setup_test_environment(cfg, set_tc_mapping=True):
"""
Sets up the complete test environment including VF creation, VLANs,
bridge configuration, devlink rate setup, and the remote server.
bridge configuration and devlink rate setup.
"""
vf_ifc = setup_vf(cfg, set_tc_mapping)
ksft_pr(f"Created VF interface: {vf_ifc}")
@@ -256,51 +252,39 @@ def setup_test_environment(cfg, set_tc_mapping=True):
setup_bridge(cfg)
setup_devlink_rate(cfg)
setup_remote_server(cfg)
time.sleep(2)
setup_remote_vlans(cfg)
def run_iperf_client(server_ip, local_ip, barrier, min_expected_gbps=0.1):
def measure_bandwidth(cfg, server_ip, client_ip, barrier):
"""
Runs a single iperf3 client instance, binding to the given local IP.
Waits on a barrier to synchronize with other threads.
Synchronizes with peers and runs an iperf3-based bandwidth measurement
between the given endpoints. Returns average Gbps.
"""
runner = Iperf3Runner(cfg, server_ip=server_ip, client_ip=client_ip)
try:
barrier.wait(timeout=10)
except Exception as exc:
raise KsftFailEx("iperf3 barrier wait timed") from exc
iperf_cmd = ["iperf3", "-c", server_ip, "-B", local_ip, "-J"]
result = subprocess.run(iperf_cmd, capture_output=True, text=True,
check=True)
try:
output = json.loads(result.stdout)
bits_per_second = output["end"]["sum_received"]["bits_per_second"]
gbps = bits_per_second / 1e9
if gbps < min_expected_gbps:
ksft_pr(
f"iperf3 bandwidth too low: {gbps:.2f} Gbps "
f"(expected ≥ {min_expected_gbps} Gbps)"
)
return None
return gbps
except json.JSONDecodeError as exc:
ksft_pr(f"Failed to parse iperf3 JSON output: {exc}")
return None
bw_gbps = runner.measure_bandwidth(reverse=True)
except Exception as exc:
raise KsftFailEx("iperf3 bandwidth measurement failed") from exc
return bw_gbps
def run_bandwidth_test():
def run_bandwidth_test(cfg):
"""
Launches iperf3 client threads for each VLAN/TC pair and collects results.
Runs parallel bandwidth measurements for each VLAN/TC pair and collects results.
"""
def _run_iperf_client_thread(server_ip, local_ip, results, barrier, tc_ix):
results[tc_ix] = run_iperf_client(server_ip, local_ip, barrier)
def _run_measure_bandwidth_thread(local_ip, remote_ip, results, barrier, tc_ix):
results[tc_ix] = measure_bandwidth(cfg, local_ip, remote_ip, barrier)
vf_vlan_data = [
# (local_ip, remote_ip, TC)
("198.51.100.2", "198.51.100.1", 3),
("198.51.100.10", "198.51.100.9", 4),
("198.51.100.1", "198.51.100.2", 3),
("198.51.100.9", "198.51.100.10", 4),
]
results = {}
@@ -309,8 +293,8 @@ def run_bandwidth_test():
for local_ip, remote_ip, tc_ix in vf_vlan_data:
thread = threading.Thread(
target=_run_iperf_client_thread,
args=(remote_ip, local_ip, results, start_barrier, tc_ix)
target=_run_measure_bandwidth_thread,
args=(local_ip, remote_ip, results, start_barrier, tc_ix)
)
thread.start()
threads.append(thread)
@@ -320,10 +304,11 @@ def run_bandwidth_test():
for tc_ix, tc_bw in results.items():
if tc_bw is None:
raise KsftFailEx("iperf3 client failed; cannot evaluate bandwidth")
raise KsftFailEx("iperf3 failed; cannot evaluate bandwidth")
return results
def calculate_bandwidth_percentages(results):
"""
Calculates the percentage of total bandwidth received by TC3 and TC4.
@@ -364,59 +349,48 @@ def verify_total_bandwidth(bw_data, validator):
"""
total = bw_data['total_bw']
if validator.bound(validator.expected_total_gbps, total):
if validator.bound({"total": total}):
return
if total < validator.total_min_expected:
low, high = validator.bounds["total"]
if total < low:
raise KsftSkipEx(
f"Total bandwidth {total:.2f} Gbps < minimum "
f"{validator.total_min_expected:.2f} Gbps; "
f"parent tx_max ({validator.expected_total_gbps:.1f} G) "
f"{low:.2f} Gbps; "
f"parent tx_max ({validator.expected_total:.1f} G) "
f"not reached, cannot validate share"
)
raise KsftFailEx(
f"Total bandwidth {total:.2f} Gbps exceeds allowed ceiling "
f"{validator.total_max_expected:.2f} Gbps "
f"(VF tx_max set to {validator.expected_total_gbps:.1f} G)"
f"{high:.2f} Gbps "
f"(VF tx_max set to {validator.expected_total:.1f} G)"
)
def check_bandwidth_distribution(bw_data, validator):
"""
Checks whether the measured TC3 and TC4 bandwidth percentages
fall within their expected tolerance ranges.
Returns:
bool: True if both TC3 and TC4 percentages are within bounds.
"""
tc3_valid = validator.tc_bandwidth_bound(bw_data['tc3_percentage'], 3)
tc4_valid = validator.tc_bandwidth_bound(bw_data['tc4_percentage'], 4)
return tc3_valid and tc4_valid
def run_bandwidth_distribution_test(cfg, set_tc_mapping):
"""
Runs parallel iperf3 tests for both TCs and collects results.
Runs parallel bandwidth measurements for both TCs and collects results.
"""
setup_test_environment(cfg, set_tc_mapping)
bandwidths = run_bandwidth_test()
bandwidths = run_bandwidth_test(cfg)
bw_data = calculate_bandwidth_percentages(bandwidths)
test_name = "with TC mapping" if set_tc_mapping else "without TC mapping"
print_bandwidth_results(bw_data, test_name)
verify_total_bandwidth(bw_data, cfg.bw_validator)
verify_total_bandwidth(bw_data, cfg.traffic_bw_validator)
return check_bandwidth_distribution(bw_data, cfg.bw_validator)
return cfg.tc_bw_validator.bound({"tc3": bw_data['tc3_percentage'],
"tc4": bw_data['tc4_percentage']})
def test_no_tc_mapping_bandwidth(cfg):
"""
Verifies that bandwidth is not split 80/20 without traffic class mapping.
Verifies that bandwidth is not split 20/80 without traffic class mapping.
"""
pass_bw_msg = "Bandwidth is NOT distributed as 80/20 without TC mapping"
fail_bw_msg = "Bandwidth matched 80/20 split without TC mapping"
pass_bw_msg = "Bandwidth is NOT distributed as 20/80 without TC mapping"
fail_bw_msg = "Bandwidth matched 20/80 split without TC mapping"
is_mlx5 = "driver: mlx5" in ethtool(f"-i {cfg.ifname}").stdout
if run_bandwidth_distribution_test(cfg, set_tc_mapping=False):
@@ -430,13 +404,13 @@ def test_no_tc_mapping_bandwidth(cfg):
def test_tc_mapping_bandwidth(cfg):
"""
Verifies that bandwidth is correctly split 80/20 between TC3 and TC4
Verifies that bandwidth is correctly split 20/80 between TC3 and TC4
when traffic class mapping is set.
"""
if run_bandwidth_distribution_test(cfg, set_tc_mapping=True):
ksft_pr("Bandwidth is distributed as 80/20 with TC mapping")
ksft_pr("Bandwidth is distributed as 20/80 with TC mapping")
else:
raise KsftFailEx("Bandwidth did not match 80/20 split with TC mapping")
raise KsftFailEx("Bandwidth did not match 20/80 split with TC mapping")
def main() -> None:
@@ -451,10 +425,9 @@ def main() -> None:
)
if not cfg.pci:
raise KsftSkipEx("Could not get PCI address of the interface")
cfg.require_cmd("iperf3")
cfg.require_cmd("iperf3", remote=True)
cfg.bw_validator = BandwidthValidator()
cfg.traffic_bw_validator = BandwidthValidator({"total": 1})
cfg.tc_bw_validator = BandwidthValidator({"tc3": 20, "tc4": 80})
cases = [test_no_tc_mapping_bandwidth, test_tc_mapping_bandwidth]
@@ -3,8 +3,10 @@
lib_dir=$(dirname $0)/../../../net/forwarding
ALL_TESTS="fw_flash_test params_test regions_test reload_test \
netns_reload_test resource_test dev_info_test \
ALL_TESTS="fw_flash_test params_test \
params_default_test regions_test reload_test \
netns_reload_test resource_test resource_dump_test \
port_resource_doit_test dev_info_test \
empty_reporter_test dummy_reporter_test rate_test"
NUM_NETIFS=0
source $lib_dir/lib.sh
@@ -78,17 +80,28 @@ fw_flash_test()
param_get()
{
local name=$1
local attr=${2:-value}
local cmode=${3:-driverinit}
cmd_jq "devlink dev param show $DL_HANDLE name $name -j" \
'.[][][].values[] | select(.cmode == "driverinit").value'
'.[][][].values[] | select(.cmode == "'"$cmode"'").'"$attr"
}
param_set()
{
local name=$1
local value=$2
local cmode=${3:-driverinit}
devlink dev param set $DL_HANDLE name $name cmode driverinit value $value
devlink dev param set $DL_HANDLE name $name cmode $cmode value $value
}
param_set_default()
{
local name=$1
local cmode=${2:-driverinit}
devlink dev param set $DL_HANDLE name $name default cmode $cmode
}
check_value()
@@ -97,12 +110,18 @@ check_value()
local phase_name=$2
local expected_param_value=$3
local expected_debugfs_value=$4
local cmode=${5:-driverinit}
local value
local attr="value"
value=$(param_get $name)
check_err $? "Failed to get $name param value"
if [[ "$phase_name" == *"default"* ]]; then
attr="default"
fi
value=$(param_get $name $attr $cmode)
check_err $? "Failed to get $name param $attr"
[ "$value" == "$expected_param_value" ]
check_err $? "Unexpected $phase_name $name param value"
check_err $? "Unexpected $phase_name $name param $attr"
value=$(<$DEBUGFS_DIR/$name)
check_err $? "Failed to get $name debugfs value"
[ "$value" == "$expected_debugfs_value" ]
@@ -135,6 +154,92 @@ params_test()
log_test "params test"
}
value_to_debugfs()
{
local value=$1
case "$value" in
true)
echo "Y"
;;
false)
echo "N"
;;
*)
echo "$value"
;;
esac
}
test_default()
{
local param_name=$1
local new_value=$2
local expected_default=$3
local cmode=${4:-driverinit}
local default_debugfs
local new_debugfs
local expected_debugfs
default_debugfs=$(value_to_debugfs $expected_default)
new_debugfs=$(value_to_debugfs $new_value)
expected_debugfs=$default_debugfs
check_value $param_name initial-default $expected_default $expected_debugfs $cmode
param_set $param_name $new_value $cmode
check_err $? "Failed to set $param_name to $new_value"
expected_debugfs=$([ "$cmode" == "runtime" ] && echo "$new_debugfs" || echo "$default_debugfs")
check_value $param_name post-set $new_value $expected_debugfs $cmode
devlink dev reload $DL_HANDLE
check_err $? "Failed to reload device"
expected_debugfs=$new_debugfs
check_value $param_name post-reload-new-value $new_value $expected_debugfs $cmode
param_set_default $param_name $cmode
check_err $? "Failed to set $param_name to default"
expected_debugfs=$([ "$cmode" == "runtime" ] && echo "$default_debugfs" || echo "$new_debugfs")
check_value $param_name post-set-default $expected_default $expected_debugfs $cmode
devlink dev reload $DL_HANDLE
check_err $? "Failed to reload device"
expected_debugfs=$default_debugfs
check_value $param_name post-reload-default $expected_default $expected_debugfs $cmode
}
params_default_test()
{
RET=0
if ! devlink dev param help 2>&1 | grep -q "value VALUE | default"; then
echo "SKIP: devlink cli missing default feature"
return
fi
# Remove side effects of previous tests. Use plain param_set, because
# param_set_default is a feature under test here.
param_set max_macs 32 driverinit
check_err $? "Failed to reset max_macs to default value"
param_set test1 true driverinit
check_err $? "Failed to reset test1 to default value"
param_set test2 1234 runtime
check_err $? "Failed to reset test2 to default value"
devlink dev reload $DL_HANDLE
check_err $? "Failed to reload device for clean state"
test_default max_macs 16 32 driverinit
test_default test1 false true driverinit
test_default test2 100 1234 runtime
log_test "params default test"
}
check_region_size()
{
local name=$1
@@ -378,6 +483,56 @@ resource_test()
log_test "resource test"
}
resource_dump_test()
{
RET=0
local port_jq
local dev_jq
local dl_jq
local count
dl_jq="with_entries(select(.key | startswith(\"$DL_HANDLE\")))"
port_jq="[.[] | $dl_jq | keys |"
port_jq+=" map(select(test(\"/.+/\"))) | length] | add"
dev_jq="[.[] | $dl_jq | keys |"
dev_jq+=" map(select(test(\"/.+/\")|not)) | length] | add"
if ! devlink resource help 2>&1 | grep -q "scope"; then
echo "SKIP: devlink resource show not supported"
return
fi
devlink resource show > /dev/null 2>&1
check_err $? "Failed to dump all resources"
count=$(cmd_jq "devlink resource show -j" "$port_jq")
[ "$count" -gt "0" ]
check_err $? "missing port resources in resource dump"
count=$(cmd_jq "devlink resource show -j" "$dev_jq")
[ "$count" -gt "0" ]
check_err $? "missing device resources in resource dump"
count=$(cmd_jq "devlink resource show scope dev -j" "$dev_jq")
[ "$count" -gt "0" ]
check_err $? "dev scope missing device resources"
count=$(cmd_jq "devlink resource show scope dev -j" "$port_jq")
[ "$count" -eq "0" ]
check_err $? "dev scope returned port resources"
count=$(cmd_jq "devlink resource show scope port -j" "$port_jq")
[ "$count" -gt "0" ]
check_err $? "port scope missing port resources"
count=$(cmd_jq "devlink resource show scope port -j" "$dev_jq")
[ "$count" -eq "0" ]
check_err $? "port scope returned device resources"
log_test "resource dump test"
}
info_get()
{
local name=$1
@@ -664,6 +819,32 @@ rate_node_del()
devlink port function rate del $handle
}
port_resource_doit_test()
{
RET=0
local port_handle="${DL_HANDLE}/0"
local name
local size
if ! devlink resource help 2>&1 | grep -q "PORT_INDEX"; then
echo "SKIP: devlink resource show with port not supported"
return
fi
name=$(cmd_jq "devlink resource show $port_handle -j" \
'.[][][].name')
[ "$name" == "test_resource" ]
check_err $? "wrong port resource name (got $name)"
size=$(cmd_jq "devlink resource show $port_handle -j" \
'.[][][].size')
[ "$size" == "20" ]
check_err $? "wrong port resource size (got $size)"
log_test "port resource doit test"
}
rate_test()
{
RET=0