mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-05-16 13:41:48 -04:00
Merge branch 'devlink-introduce-shared-devlink-instance-for-pfs-on-same-chip'
Jiri Pirko says:
====================
devlink: introduce shared devlink instance for PFs on same chip
Multiple PFs on a network adapter often reside on the same physical
chip, running a single firmware. Some resources and configurations
are inherently shared among these PFs - PTP clocks, VF group rates,
firmware parameters, and others. Today there is no good object in
the devlink model to attach these chip-wide configuration knobs to.
Drivers resort to workarounds like pinning shared state to PF0 or
maintaining ad-hoc internal structures (e.g., ice_adapter) that are
invisible to userspace.
This problem was discussed extensively starting with Przemek Kitszel's
"whole device devlink instance" RFC for the ice driver [1]. Several
approaches for representing the parent instance were considered:
using a partial PCI BDF as the dev_name (breaks when PFs have different
BDFs in VMs), creating a per-driver bus, using auxiliary devices, or
using faux devices. All of these required a backing struct device for
the parent devlink instance, which does not naturally exist - there is
no PCI device that represents the chip as a whole.
This patchset takes a different approach: allow devlink instances to
exist without any backing struct device. The instance is identified
purely by its internal index, exposed over devlin netlink. This avoids
fabricating fake devices and keeps the devlink handle semantics clean.
The first ten patches prepare the devlink core for device-less
instances by decoupling the handle from the parent device. The last
three introduce the shared devlink infrastructure and its first user
in the mlx5 driver.
Example output showing the shared instance and nesting:
pci/0000:08:00.0: index 0
nested_devlink:
auxiliary/mlx5_core.eth.0
devlink_index/1: index 1
nested_devlink:
pci/0000:08:00.0
pci/0000:08:00.1
auxiliary/mlx5_core.eth.0: index 2
pci/0000:08:00.1: index 3
nested_devlink:
auxiliary/mlx5_core.eth.1
auxiliary/mlx5_core.eth.1: index 4
[1] https://lore.kernel.org/netdev/20250219164410.35665-1-przemyslaw.kitszel@intel.com/
---
Decoupled from "devlink and mlx5: Support cross-function rate scheduling"
patchset to maintain 15-patches limit.
See individual patches for changelog.
====================
Link: https://patch.msgid.link/20260312100407.551173-1-jiri@resnulli.us
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
@@ -867,6 +867,12 @@ attribute-sets:
|
||||
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: dl-dev-stats
|
||||
subset-of: devlink
|
||||
@@ -1306,11 +1312,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:
|
||||
@@ -1329,6 +1337,7 @@ operations:
|
||||
attributes: &port-id-attrs
|
||||
- bus-name
|
||||
- dev-name
|
||||
- index
|
||||
- port-index
|
||||
reply:
|
||||
value: 7
|
||||
@@ -1353,6 +1362,7 @@ operations:
|
||||
attributes:
|
||||
- bus-name
|
||||
- dev-name
|
||||
- index
|
||||
- port-index
|
||||
- port-type
|
||||
- port-function
|
||||
@@ -1370,6 +1380,7 @@ operations:
|
||||
attributes:
|
||||
- bus-name
|
||||
- dev-name
|
||||
- index
|
||||
- port-index
|
||||
- port-flavour
|
||||
- port-pci-pf-number
|
||||
@@ -1404,6 +1415,7 @@ operations:
|
||||
attributes:
|
||||
- bus-name
|
||||
- dev-name
|
||||
- index
|
||||
- port-index
|
||||
- port-split-count
|
||||
|
||||
@@ -1432,6 +1444,7 @@ operations:
|
||||
attributes: &sb-id-attrs
|
||||
- bus-name
|
||||
- dev-name
|
||||
- index
|
||||
- sb-index
|
||||
reply: &sb-get-reply
|
||||
value: 13
|
||||
@@ -1454,6 +1467,7 @@ operations:
|
||||
attributes: &sb-pool-id-attrs
|
||||
- bus-name
|
||||
- dev-name
|
||||
- index
|
||||
- sb-index
|
||||
- sb-pool-index
|
||||
reply: &sb-pool-get-reply
|
||||
@@ -1477,6 +1491,7 @@ operations:
|
||||
attributes:
|
||||
- bus-name
|
||||
- dev-name
|
||||
- index
|
||||
- sb-index
|
||||
- sb-pool-index
|
||||
- sb-pool-threshold-type
|
||||
@@ -1495,6 +1510,7 @@ operations:
|
||||
attributes: &sb-port-pool-id-attrs
|
||||
- bus-name
|
||||
- dev-name
|
||||
- index
|
||||
- port-index
|
||||
- sb-index
|
||||
- sb-pool-index
|
||||
@@ -1519,6 +1535,7 @@ operations:
|
||||
attributes:
|
||||
- bus-name
|
||||
- dev-name
|
||||
- index
|
||||
- port-index
|
||||
- sb-index
|
||||
- sb-pool-index
|
||||
@@ -1537,6 +1554,7 @@ operations:
|
||||
attributes: &sb-tc-pool-bind-id-attrs
|
||||
- bus-name
|
||||
- dev-name
|
||||
- index
|
||||
- port-index
|
||||
- sb-index
|
||||
- sb-pool-type
|
||||
@@ -1562,6 +1580,7 @@ operations:
|
||||
attributes:
|
||||
- bus-name
|
||||
- dev-name
|
||||
- index
|
||||
- port-index
|
||||
- sb-index
|
||||
- sb-pool-index
|
||||
@@ -1583,6 +1602,7 @@ operations:
|
||||
attributes:
|
||||
- bus-name
|
||||
- dev-name
|
||||
- index
|
||||
- sb-index
|
||||
|
||||
-
|
||||
@@ -1598,6 +1618,7 @@ operations:
|
||||
attributes:
|
||||
- bus-name
|
||||
- dev-name
|
||||
- index
|
||||
- sb-index
|
||||
|
||||
-
|
||||
@@ -1616,6 +1637,7 @@ operations:
|
||||
attributes: &eswitch-attrs
|
||||
- bus-name
|
||||
- dev-name
|
||||
- index
|
||||
- eswitch-mode
|
||||
- eswitch-inline-mode
|
||||
- eswitch-encap-mode
|
||||
@@ -1644,12 +1666,14 @@ operations:
|
||||
attributes:
|
||||
- bus-name
|
||||
- dev-name
|
||||
- index
|
||||
- dpipe-table-name
|
||||
reply:
|
||||
value: 31
|
||||
attributes:
|
||||
- bus-name
|
||||
- dev-name
|
||||
- index
|
||||
- dpipe-tables
|
||||
|
||||
-
|
||||
@@ -1664,11 +1688,13 @@ operations:
|
||||
attributes:
|
||||
- bus-name
|
||||
- dev-name
|
||||
- index
|
||||
- dpipe-table-name
|
||||
reply:
|
||||
attributes:
|
||||
- bus-name
|
||||
- dev-name
|
||||
- index
|
||||
- dpipe-entries
|
||||
|
||||
-
|
||||
@@ -1683,10 +1709,12 @@ operations:
|
||||
attributes:
|
||||
- bus-name
|
||||
- dev-name
|
||||
- index
|
||||
reply:
|
||||
attributes:
|
||||
- bus-name
|
||||
- dev-name
|
||||
- index
|
||||
- dpipe-headers
|
||||
|
||||
-
|
||||
@@ -1702,6 +1730,7 @@ operations:
|
||||
attributes:
|
||||
- bus-name
|
||||
- dev-name
|
||||
- index
|
||||
- dpipe-table-name
|
||||
- dpipe-table-counters-enabled
|
||||
|
||||
@@ -1718,6 +1747,7 @@ operations:
|
||||
attributes:
|
||||
- bus-name
|
||||
- dev-name
|
||||
- index
|
||||
- resource-id
|
||||
- resource-size
|
||||
|
||||
@@ -1733,11 +1763,13 @@ operations:
|
||||
attributes:
|
||||
- bus-name
|
||||
- dev-name
|
||||
- index
|
||||
reply:
|
||||
value: 36
|
||||
attributes:
|
||||
- bus-name
|
||||
- dev-name
|
||||
- index
|
||||
- resource-list
|
||||
|
||||
-
|
||||
@@ -1753,6 +1785,7 @@ operations:
|
||||
attributes:
|
||||
- bus-name
|
||||
- dev-name
|
||||
- index
|
||||
- reload-action
|
||||
- reload-limits
|
||||
- netns-pid
|
||||
@@ -1762,6 +1795,7 @@ operations:
|
||||
attributes:
|
||||
- bus-name
|
||||
- dev-name
|
||||
- index
|
||||
- reload-actions-performed
|
||||
|
||||
-
|
||||
@@ -1776,6 +1810,7 @@ operations:
|
||||
attributes: ¶m-id-attrs
|
||||
- bus-name
|
||||
- dev-name
|
||||
- index
|
||||
- param-name
|
||||
reply: ¶m-get-reply
|
||||
attributes: *param-id-attrs
|
||||
@@ -1797,6 +1832,7 @@ operations:
|
||||
attributes:
|
||||
- bus-name
|
||||
- dev-name
|
||||
- index
|
||||
- param-name
|
||||
- param-type
|
||||
# param-value-data is missing here as the type is variable
|
||||
@@ -1816,6 +1852,7 @@ operations:
|
||||
attributes: ®ion-id-attrs
|
||||
- bus-name
|
||||
- dev-name
|
||||
- index
|
||||
- port-index
|
||||
- region-name
|
||||
reply: ®ion-get-reply
|
||||
@@ -1840,6 +1877,7 @@ operations:
|
||||
attributes: ®ion-snapshot-id-attrs
|
||||
- bus-name
|
||||
- dev-name
|
||||
- index
|
||||
- port-index
|
||||
- region-name
|
||||
- region-snapshot-id
|
||||
@@ -1870,6 +1908,7 @@ operations:
|
||||
attributes:
|
||||
- bus-name
|
||||
- dev-name
|
||||
- index
|
||||
- port-index
|
||||
- region-name
|
||||
- region-snapshot-id
|
||||
@@ -1881,6 +1920,7 @@ operations:
|
||||
attributes:
|
||||
- bus-name
|
||||
- dev-name
|
||||
- index
|
||||
- port-index
|
||||
- region-name
|
||||
|
||||
@@ -1930,6 +1970,7 @@ operations:
|
||||
attributes:
|
||||
- bus-name
|
||||
- dev-name
|
||||
- index
|
||||
- info-driver-name
|
||||
- info-serial-number
|
||||
- info-version-fixed
|
||||
@@ -1951,6 +1992,7 @@ operations:
|
||||
attributes: &health-reporter-id-attrs
|
||||
- bus-name
|
||||
- dev-name
|
||||
- index
|
||||
- port-index
|
||||
- health-reporter-name
|
||||
reply: &health-reporter-get-reply
|
||||
@@ -1973,6 +2015,7 @@ operations:
|
||||
attributes:
|
||||
- bus-name
|
||||
- dev-name
|
||||
- index
|
||||
- port-index
|
||||
- health-reporter-name
|
||||
- health-reporter-graceful-period
|
||||
@@ -2043,6 +2086,7 @@ operations:
|
||||
attributes:
|
||||
- bus-name
|
||||
- dev-name
|
||||
- index
|
||||
- flash-update-file-name
|
||||
- flash-update-component
|
||||
- flash-update-overwrite-mask
|
||||
@@ -2060,6 +2104,7 @@ operations:
|
||||
attributes: &trap-id-attrs
|
||||
- bus-name
|
||||
- dev-name
|
||||
- index
|
||||
- trap-name
|
||||
reply: &trap-get-reply
|
||||
value: 63
|
||||
@@ -2082,6 +2127,7 @@ operations:
|
||||
attributes:
|
||||
- bus-name
|
||||
- dev-name
|
||||
- index
|
||||
- trap-name
|
||||
- trap-action
|
||||
|
||||
@@ -2098,6 +2144,7 @@ operations:
|
||||
attributes: &trap-group-id-attrs
|
||||
- bus-name
|
||||
- dev-name
|
||||
- index
|
||||
- trap-group-name
|
||||
reply: &trap-group-get-reply
|
||||
value: 67
|
||||
@@ -2120,6 +2167,7 @@ operations:
|
||||
attributes:
|
||||
- bus-name
|
||||
- dev-name
|
||||
- index
|
||||
- trap-group-name
|
||||
- trap-action
|
||||
- trap-policer-id
|
||||
@@ -2137,6 +2185,7 @@ operations:
|
||||
attributes: &trap-policer-id-attrs
|
||||
- bus-name
|
||||
- dev-name
|
||||
- index
|
||||
- trap-policer-id
|
||||
reply: &trap-policer-get-reply
|
||||
value: 71
|
||||
@@ -2159,6 +2208,7 @@ operations:
|
||||
attributes:
|
||||
- bus-name
|
||||
- dev-name
|
||||
- index
|
||||
- trap-policer-id
|
||||
- trap-policer-rate
|
||||
- trap-policer-burst
|
||||
@@ -2189,6 +2239,7 @@ operations:
|
||||
attributes: &rate-id-attrs
|
||||
- bus-name
|
||||
- dev-name
|
||||
- index
|
||||
- port-index
|
||||
- rate-node-name
|
||||
reply: &rate-get-reply
|
||||
@@ -2212,6 +2263,7 @@ operations:
|
||||
attributes:
|
||||
- bus-name
|
||||
- dev-name
|
||||
- index
|
||||
- rate-node-name
|
||||
- rate-tx-share
|
||||
- rate-tx-max
|
||||
@@ -2233,6 +2285,7 @@ operations:
|
||||
attributes:
|
||||
- bus-name
|
||||
- dev-name
|
||||
- index
|
||||
- rate-node-name
|
||||
- rate-tx-share
|
||||
- rate-tx-max
|
||||
@@ -2254,6 +2307,7 @@ operations:
|
||||
attributes:
|
||||
- bus-name
|
||||
- dev-name
|
||||
- index
|
||||
- rate-node-name
|
||||
|
||||
-
|
||||
@@ -2269,6 +2323,7 @@ operations:
|
||||
attributes: &linecard-id-attrs
|
||||
- bus-name
|
||||
- dev-name
|
||||
- index
|
||||
- linecard-index
|
||||
reply: &linecard-get-reply
|
||||
value: 80
|
||||
@@ -2291,6 +2346,7 @@ operations:
|
||||
attributes:
|
||||
- bus-name
|
||||
- dev-name
|
||||
- index
|
||||
- linecard-index
|
||||
- linecard-type
|
||||
|
||||
@@ -2324,6 +2380,7 @@ operations:
|
||||
attributes:
|
||||
- bus-name
|
||||
- dev-name
|
||||
- index
|
||||
- selftests
|
||||
|
||||
-
|
||||
@@ -2335,4 +2392,5 @@ operations:
|
||||
attributes:
|
||||
- bus-name
|
||||
- dev-name
|
||||
- index
|
||||
- port-index
|
||||
|
||||
97
Documentation/networking/devlink/devlink-shared.rst
Normal file
97
Documentation/networking/devlink/devlink-shared.rst
Normal file
@@ -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.
|
||||
@@ -68,6 +68,7 @@ general.
|
||||
devlink-resource
|
||||
devlink-selftests
|
||||
devlink-trap
|
||||
devlink-shared
|
||||
|
||||
Driver-specific documentation
|
||||
-----------------------------
|
||||
|
||||
@@ -16,8 +16,9 @@ mlx5_core-y := main.o cmd.o debugfs.o fw.o eq.o uar.o pagealloc.o \
|
||||
transobj.o vport.o sriov.o fs_cmd.o fs_core.o pci_irq.o \
|
||||
fs_counters.o fs_ft_pool.o rl.o lag/debugfs.o lag/lag.o dev.o events.o wq.o lib/gid.o \
|
||||
lib/devcom.o lib/pci_vsc.o lib/dm.o lib/fs_ttc.o diag/fs_tracepoint.o \
|
||||
diag/fw_tracer.o diag/crdump.o devlink.o diag/rsc_dump.o diag/reporter_vnic.o \
|
||||
fw_reset.o qos.o lib/tout.o lib/aso.o wc.o fs_pool.o lib/nv_param.o
|
||||
diag/fw_tracer.o diag/crdump.o devlink.o sh_devlink.o diag/rsc_dump.o \
|
||||
diag/reporter_vnic.o fw_reset.o qos.o lib/tout.o lib/aso.o wc.o fs_pool.o \
|
||||
lib/nv_param.o
|
||||
|
||||
#
|
||||
# Netdev basic
|
||||
|
||||
@@ -74,6 +74,7 @@
|
||||
#include "mlx5_irq.h"
|
||||
#include "hwmon.h"
|
||||
#include "lag/lag.h"
|
||||
#include "sh_devlink.h"
|
||||
|
||||
MODULE_AUTHOR("Eli Cohen <eli@mellanox.com>");
|
||||
MODULE_DESCRIPTION("Mellanox 5th generation network adapters (ConnectX series) core driver");
|
||||
@@ -1520,10 +1521,16 @@ int mlx5_init_one(struct mlx5_core_dev *dev)
|
||||
int err;
|
||||
|
||||
devl_lock(devlink);
|
||||
if (dev->shd) {
|
||||
err = devl_nested_devlink_set(dev->shd, devlink);
|
||||
if (err)
|
||||
goto unlock;
|
||||
}
|
||||
devl_register(devlink);
|
||||
err = mlx5_init_one_devl_locked(dev);
|
||||
if (err)
|
||||
devl_unregister(devlink);
|
||||
unlock:
|
||||
devl_unlock(devlink);
|
||||
return err;
|
||||
}
|
||||
@@ -2005,6 +2012,13 @@ static int probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
|
||||
goto pci_init_err;
|
||||
}
|
||||
|
||||
err = mlx5_shd_init(dev);
|
||||
if (err) {
|
||||
mlx5_core_err(dev, "mlx5_shd_init failed with error code %d\n",
|
||||
err);
|
||||
goto shd_init_err;
|
||||
}
|
||||
|
||||
err = mlx5_init_one(dev);
|
||||
if (err) {
|
||||
mlx5_core_err(dev, "mlx5_init_one failed with error code %d\n",
|
||||
@@ -2018,6 +2032,8 @@ static int probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
|
||||
return 0;
|
||||
|
||||
err_init_one:
|
||||
mlx5_shd_uninit(dev);
|
||||
shd_init_err:
|
||||
mlx5_pci_close(dev);
|
||||
pci_init_err:
|
||||
mlx5_mdev_uninit(dev);
|
||||
@@ -2039,6 +2055,7 @@ static void remove_one(struct pci_dev *pdev)
|
||||
mlx5_drain_health_wq(dev);
|
||||
mlx5_sriov_disable(pdev, false);
|
||||
mlx5_uninit_one(dev);
|
||||
mlx5_shd_uninit(dev);
|
||||
mlx5_pci_close(dev);
|
||||
mlx5_mdev_uninit(dev);
|
||||
mlx5_adev_idx_free(dev->priv.adev_idx);
|
||||
|
||||
61
drivers/net/ethernet/mellanox/mlx5/core/sh_devlink.c
Normal file
61
drivers/net/ethernet/mellanox/mlx5/core/sh_devlink.c
Normal file
@@ -0,0 +1,61 @@
|
||||
// SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB
|
||||
/* Copyright (c) 2025, NVIDIA CORPORATION & AFFILIATES. All rights reserved. */
|
||||
|
||||
#include <linux/mlx5/driver.h>
|
||||
#include <net/devlink.h>
|
||||
|
||||
#include "sh_devlink.h"
|
||||
|
||||
static const struct devlink_ops mlx5_shd_ops = {
|
||||
};
|
||||
|
||||
int mlx5_shd_init(struct mlx5_core_dev *dev)
|
||||
{
|
||||
u8 *vpd_data __free(kfree) = NULL;
|
||||
struct pci_dev *pdev = dev->pdev;
|
||||
unsigned int vpd_size, kw_len;
|
||||
struct devlink *devlink;
|
||||
char *sn, *end;
|
||||
int start;
|
||||
int err;
|
||||
|
||||
if (!mlx5_core_is_pf(dev))
|
||||
return 0;
|
||||
|
||||
vpd_data = pci_vpd_alloc(pdev, &vpd_size);
|
||||
if (IS_ERR(vpd_data)) {
|
||||
err = PTR_ERR(vpd_data);
|
||||
return err == -ENODEV ? 0 : err;
|
||||
}
|
||||
start = pci_vpd_find_ro_info_keyword(vpd_data, vpd_size, "V3", &kw_len);
|
||||
if (start < 0) {
|
||||
/* Fall-back to SN for older devices. */
|
||||
start = pci_vpd_find_ro_info_keyword(vpd_data, vpd_size,
|
||||
PCI_VPD_RO_KEYWORD_SERIALNO, &kw_len);
|
||||
if (start < 0)
|
||||
return -ENOENT;
|
||||
}
|
||||
sn = kstrndup(vpd_data + start, kw_len, GFP_KERNEL);
|
||||
if (!sn)
|
||||
return -ENOMEM;
|
||||
/* Firmware may return spaces at the end of the string, strip it. */
|
||||
end = strchrnul(sn, ' ');
|
||||
*end = '\0';
|
||||
|
||||
/* Get or create shared devlink instance */
|
||||
devlink = devlink_shd_get(sn, &mlx5_shd_ops, 0, pdev->dev.driver);
|
||||
kfree(sn);
|
||||
if (!devlink)
|
||||
return -ENOMEM;
|
||||
|
||||
dev->shd = devlink;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void mlx5_shd_uninit(struct mlx5_core_dev *dev)
|
||||
{
|
||||
if (!dev->shd)
|
||||
return;
|
||||
|
||||
devlink_shd_put(dev->shd);
|
||||
}
|
||||
12
drivers/net/ethernet/mellanox/mlx5/core/sh_devlink.h
Normal file
12
drivers/net/ethernet/mellanox/mlx5/core/sh_devlink.h
Normal file
@@ -0,0 +1,12 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB */
|
||||
/* Copyright (c) 2025, NVIDIA CORPORATION & AFFILIATES. All rights reserved. */
|
||||
|
||||
#ifndef __MLX5_SH_DEVLINK_H__
|
||||
#define __MLX5_SH_DEVLINK_H__
|
||||
|
||||
#include <linux/mlx5/driver.h>
|
||||
|
||||
int mlx5_shd_init(struct mlx5_core_dev *dev);
|
||||
void mlx5_shd_uninit(struct mlx5_core_dev *dev);
|
||||
|
||||
#endif /* __MLX5_SH_DEVLINK_H__ */
|
||||
@@ -798,6 +798,7 @@ struct mlx5_core_dev {
|
||||
enum mlx5_wc_state wc_state;
|
||||
/* sync write combining state */
|
||||
struct mutex wc_state_lock;
|
||||
struct devlink *shd;
|
||||
};
|
||||
|
||||
struct mlx5_db {
|
||||
|
||||
@@ -1611,6 +1611,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);
|
||||
@@ -1644,6 +1647,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.
|
||||
|
||||
@@ -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,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,
|
||||
@@ -642,6 +644,8 @@ enum devlink_attr {
|
||||
DEVLINK_ATTR_PARAM_VALUE_DEFAULT, /* dynamic */
|
||||
DEVLINK_ATTR_PARAM_RESET_DEFAULT, /* flag */
|
||||
|
||||
DEVLINK_ATTR_INDEX, /* uint */
|
||||
|
||||
/* Add new attributes above here, update the spec in
|
||||
* Documentation/netlink/specs/devlink.yaml and re-generate
|
||||
* net/devlink/netlink_gen.c.
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -248,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);
|
||||
@@ -311,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);
|
||||
}
|
||||
|
||||
@@ -321,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;
|
||||
|
||||
@@ -346,6 +369,16 @@ struct devlink *devlinks_xa_find_get(struct net *net, unsigned long *indexp)
|
||||
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
|
||||
@@ -394,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;
|
||||
|
||||
@@ -427,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);
|
||||
@@ -452,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);
|
||||
|
||||
/**
|
||||
|
||||
@@ -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));
|
||||
@@ -854,7 +855,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)
|
||||
@@ -872,7 +873,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;
|
||||
@@ -892,7 +892,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;
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -174,9 +190,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 +220,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 +229,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,
|
||||
|
||||
@@ -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,
|
||||
@@ -352,7 +385,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
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -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)
|
||||
@@ -1241,9 +1242,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 +1273,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);
|
||||
|
||||
161
net/devlink/sh_dev.c
Normal file
161
net/devlink/sh_dev.c
Normal 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);
|
||||
Reference in New Issue
Block a user