On Fri, Sep 4, 2026 at 6:37 AM Paul Greenwalt <[email protected]> wrote:
>
> Add a devlink instance for the idpf adapter and implement the .info_get
> callback, reporting:
>   - serial_number: PCI Device Serial Number, for device identification
>   - fw.mgmt.api: running version of the driver-device communication
>     channel (virtchnl)
>
> This enables NIPA CI and other tools to uniquely identify devices under
> test and track device capabilities. This phased implementation initially
> focuses on stable, readily available information. Firmware version
> information will be added in future patches as support is exposed
> through virtchnl and the driver architecture allows reliable retrieval.
>
> The adapter structure is carved out of the devlink private area, so
> devlink_alloc() replaces the plain kzalloc_obj() in idpf_probe() and
> devlink_free() replaces the corresponding kfree() on both the probe
> error path and in idpf_remove(). The instance is registered in
> idpf_probe(), before the reset worker that performs the virtchnl
> handshake is queued, and unregistered in idpf_remove(), so it stays
> available for the whole time the driver is bound.
>
> The serial number is omitted on devices that do not implement the PCI
> Device Serial Number extended capability, where pci_get_dsn() returns 0,
> rather than reporting an all-zero serial number. The virtchnl version is
> omitted until it has been negotiated, as the instance is registered
> before the handshake runs.
>
> $ devlink dev show
> pci/0000:85:00.0
>
> $ devlink dev info pci/0000:85:00.0
> pci/0000:85:00.0:
>   driver idpf
>   serial_number 00-a0-c9-ff-ff-23-45-67
>   versions:
>       running:
>         fw.mgmt.api 2.0
>
> Link: 
> https://github.com/linux-netdev/nipa/wiki/Netdev-CI-system#device-information
> Signed-off-by: Paul Greenwalt <[email protected]>
> ---

Verified the devlink info output:

$ devlink -j dev info pci/0000:05:00.0
{"info":{"pci/0000:05:00.0":{"driver":"idpf","versions":{"running":{"fw.mgmt.api":"2.0"}}}}}

Tested-by: Danny Gonzalez <[email protected]>

>  Documentation/networking/devlink/idpf.rst     | 30 ++++++
>  Documentation/networking/devlink/index.rst    |  1 +
>  drivers/net/ethernet/intel/idpf/Kconfig       |  1 +
>  drivers/net/ethernet/intel/idpf/Makefile      |  1 +
>  .../net/ethernet/intel/idpf/idpf_devlink.c    | 98 +++++++++++++++++++
>  .../net/ethernet/intel/idpf/idpf_devlink.h    | 45 +++++++++
>  drivers/net/ethernet/intel/idpf/idpf_main.c   | 13 ++-
>  7 files changed, 186 insertions(+), 3 deletions(-)
>  create mode 100644 Documentation/networking/devlink/idpf.rst
>  create mode 100644 drivers/net/ethernet/intel/idpf/idpf_devlink.c
>  create mode 100644 drivers/net/ethernet/intel/idpf/idpf_devlink.h
>
> diff --git a/Documentation/networking/devlink/idpf.rst 
> b/Documentation/networking/devlink/idpf.rst
> new file mode 100644
> index 0000000000000..5121cffd8f476
> --- /dev/null
> +++ b/Documentation/networking/devlink/idpf.rst
> @@ -0,0 +1,30 @@
> +.. SPDX-License-Identifier: GPL-2.0
> +
> +====================
> +idpf devlink support
> +====================
> +
> +This document describes the devlink features implemented by the ``idpf``
> +device driver.
> +
> +Info versions
> +=============
> +
> +The ``idpf`` driver reports the following versions
> +
> +.. list-table:: devlink info versions implemented
> +    :widths: 5 5 5 90
> +
> +    * - Name
> +      - Type
> +      - Example
> +      - Description
> +    * - ``fw.mgmt.api``
> +      - running
> +      - 2.0
> +      - 2-digit version number (major.minor) of the communication channel
> +        (virtchnl) used by the device.
> +
> +The driver also reports the PCI Device Serial Number through the
> +``serial_number`` attribute, on devices that implement the PCI Device Serial
> +Number extended capability.
> diff --git a/Documentation/networking/devlink/index.rst 
> b/Documentation/networking/devlink/index.rst
> index d4a83fdcff7fe..538494b1051bd 100644
> --- a/Documentation/networking/devlink/index.rst
> +++ b/Documentation/networking/devlink/index.rst
> @@ -85,6 +85,7 @@ parameters, info versions, and other features it supports.
>     hns3
>     i40e
>     ice
> +   idpf
>     ionic
>     iosm
>     ixd
> diff --git a/drivers/net/ethernet/intel/idpf/Kconfig 
> b/drivers/net/ethernet/intel/idpf/Kconfig
> index 586df3a4afe90..4ee8bbc401fe6 100644
> --- a/drivers/net/ethernet/intel/idpf/Kconfig
> +++ b/drivers/net/ethernet/intel/idpf/Kconfig
> @@ -6,6 +6,7 @@ config IDPF
>       depends on PCI_MSI
>       depends on PTP_1588_CLOCK_OPTIONAL
>       select DIMLIB
> +     select NET_DEVLINK
>       select LIBIE_CP
>       select LIBETH_XDP
>       help
> diff --git a/drivers/net/ethernet/intel/idpf/Makefile 
> b/drivers/net/ethernet/intel/idpf/Makefile
> index 4aaafa175ec37..81b27a4067478 100644
> --- a/drivers/net/ethernet/intel/idpf/Makefile
> +++ b/drivers/net/ethernet/intel/idpf/Makefile
> @@ -7,6 +7,7 @@ obj-$(CONFIG_IDPF) += idpf.o
>
>  idpf-y := \
>       idpf_dev.o              \
> +     idpf_devlink.o          \
>       idpf_ethtool.o          \
>       idpf_idc.o              \
>       idpf_lib.o              \
> diff --git a/drivers/net/ethernet/intel/idpf/idpf_devlink.c 
> b/drivers/net/ethernet/intel/idpf/idpf_devlink.c
> new file mode 100644
> index 0000000000000..afdb5bc2e002c
> --- /dev/null
> +++ b/drivers/net/ethernet/intel/idpf/idpf_devlink.c
> @@ -0,0 +1,98 @@
> +// SPDX-License-Identifier: GPL-2.0-only
> +/* Copyright (C) 2026 Intel Corporation */
> +
> +#include <linux/pci.h>
> +#include <linux/unaligned.h>
> +
> +#include "idpf.h"
> +#include "idpf_devlink.h"
> +
> +#define IDPF_DEVLINK_INFO_LEN                128
> +
> +/**
> + * idpf_info_get_dsn - format the PCI DSN as the device serial number
> + * @adapter: the idpf adapter structure
> + * @buf: buffer to store the formatted serial number
> + * @buf_size: size of @buf
> + *
> + * Return: true if the device reports a DSN, false otherwise.
> + */
> +static bool idpf_info_get_dsn(struct idpf_adapter *adapter, char *buf,
> +                           size_t buf_size)
> +{
> +     u64 dsn = pci_get_dsn(adapter->pdev);
> +     u8 dsn_be[sizeof(dsn)];
> +
> +     if (!dsn)
> +             return false;
> +
> +     /* Copy the DSN into an array in Big Endian format */
> +     put_unaligned_be64(dsn, dsn_be);
> +     snprintf(buf, buf_size, "%8phD", dsn_be);
> +
> +     return true;
> +}
> +
> +/**
> + * idpf_devlink_info_get - .info_get devlink handler
> + * @devlink: devlink instance structure
> + * @req: the devlink info request
> + * @extack: extended netlink ack structure
> + *
> + * Callback for the devlink .info_get operation. Reports information about 
> the
> + * device. The virtchnl version is only reported once it has been negotiated,
> + * as the instance is registered before the handshake runs.
> + *
> + * Return: zero on success or a negative error code on failure.
> + */
> +static int idpf_devlink_info_get(struct devlink *devlink,
> +                              struct devlink_info_req *req,
> +                              struct netlink_ext_ack *extack)
> +{
> +     struct idpf_adapter *adapter = devlink_priv(devlink);
> +     char buf[IDPF_DEVLINK_INFO_LEN];
> +     u32 maj, min;
> +     int err;
> +
> +     if (idpf_info_get_dsn(adapter, buf, sizeof(buf))) {
> +             err = devlink_info_serial_number_put(req, buf);
> +             if (err)
> +                     return err;
> +     }
> +
> +     maj = READ_ONCE(adapter->virt_ver_maj);
> +     min = READ_ONCE(adapter->virt_ver_min);
> +     if (!maj && !min)
> +             return 0;
> +
> +     snprintf(buf, sizeof(buf), "%u.%u", maj, min);
> +
> +     return devlink_info_version_running_put(req,
> +                                     
> DEVLINK_INFO_VERSION_GENERIC_FW_MGMT_API,
> +                                     buf);
> +}
> +
> +static const struct devlink_ops idpf_devlink_ops = {
> +     .info_get = idpf_devlink_info_get,
> +};
> +
> +/**
> + * idpf_adapter_alloc - allocate devlink and return adapter
> + * @dev: IDPF device to allocate for
> + *
> + * Allocate a devlink instance for this device and return the private area as
> + * the adapter structure.
> + *
> + * Return: adapter structure on success, NULL on failure
> + */
> +struct idpf_adapter *idpf_adapter_alloc(struct device *dev)
> +{
> +     struct devlink *devlink;
> +
> +     devlink = devlink_alloc(&idpf_devlink_ops, sizeof(struct idpf_adapter),
> +                             dev);
> +     if (!devlink)
> +             return NULL;
> +
> +     return devlink_priv(devlink);
> +}
> diff --git a/drivers/net/ethernet/intel/idpf/idpf_devlink.h 
> b/drivers/net/ethernet/intel/idpf/idpf_devlink.h
> new file mode 100644
> index 0000000000000..3ace09be8dddf
> --- /dev/null
> +++ b/drivers/net/ethernet/intel/idpf/idpf_devlink.h
> @@ -0,0 +1,45 @@
> +/* SPDX-License-Identifier: GPL-2.0-only */
> +/* Copyright (C) 2026 Intel Corporation */
> +
> +#ifndef _IDPF_DEVLINK_H_
> +#define _IDPF_DEVLINK_H_
> +#include <net/devlink.h>
> +
> +struct idpf_adapter;
> +
> +struct idpf_adapter *idpf_adapter_alloc(struct device *dev);
> +
> +/**
> + * idpf_devlink_free - teardown the devlink
> + * @adapter: IDPF adapter structure to free
> + */
> +static inline void idpf_devlink_free(struct idpf_adapter *adapter)
> +{
> +     struct devlink *devlink = priv_to_devlink(adapter);
> +
> +     devlink_free(devlink);
> +}
> +
> +/**
> + * idpf_devlink_register - register the devlink
> + * @adapter: IDPF adapter structure
> + */
> +static inline void idpf_devlink_register(struct idpf_adapter *adapter)
> +{
> +     struct devlink *devlink = priv_to_devlink(adapter);
> +
> +     devlink_register(devlink);
> +}
> +
> +/**
> + * idpf_devlink_unregister - unregister the devlink
> + * @adapter: IDPF adapter structure
> + */
> +static inline void idpf_devlink_unregister(struct idpf_adapter *adapter)
> +{
> +     struct devlink *devlink = priv_to_devlink(adapter);
> +
> +     devlink_unregister(devlink);
> +}
> +
> +#endif /* _IDPF_DEVLINK_H_ */
> diff --git a/drivers/net/ethernet/intel/idpf/idpf_main.c 
> b/drivers/net/ethernet/intel/idpf/idpf_main.c
> index 3dbbe21459990..34a69bb2e36bc 100644
> --- a/drivers/net/ethernet/intel/idpf/idpf_main.c
> +++ b/drivers/net/ethernet/intel/idpf/idpf_main.c
> @@ -3,6 +3,7 @@
>
>  #include "idpf.h"
>  #include "idpf_devids.h"
> +#include "idpf_devlink.h"
>  #include "idpf_lan_vf_regs.h"
>  #include "idpf_virtchnl.h"
>
> @@ -127,12 +128,15 @@ static void idpf_remove(struct pci_dev *pdev)
>
>       set_bit(IDPF_REMOVE_IN_PROG, adapter->flags);
>
> +     idpf_devlink_unregister(adapter);
> +
>       /* Wait until vc_event_task is done to consider if any hard reset is
>        * in progress else we may go ahead and release the resources but the
>        * thread doing the hard reset might continue the init path and
>        * end up in bad state.
>        */
>       cancel_delayed_work_sync(&adapter->vc_event_task);
> +
>       if (adapter->num_vfs)
>               idpf_sriov_configure(pdev, 0);
>
> @@ -184,7 +188,8 @@ static void idpf_remove(struct pci_dev *pdev)
>       mutex_destroy(&adapter->vc_buf_lock);
>
>       idpf_decfg_device(adapter);
> -     kfree(adapter);
> +
> +     idpf_devlink_free(adapter);
>  }
>
>  /**
> @@ -263,7 +268,7 @@ static int idpf_probe(struct pci_dev *pdev, const struct 
> pci_device_id *ent)
>       struct idpf_adapter *adapter;
>       int err;
>
> -     adapter = kzalloc_obj(*adapter);
> +     adapter = idpf_adapter_alloc(dev);
>       if (!adapter)
>               return -ENOMEM;
>
> @@ -349,6 +354,8 @@ static int idpf_probe(struct pci_dev *pdev, const struct 
> pci_device_id *ent)
>       INIT_DELAYED_WORK(&adapter->stats_task, idpf_statistics_task);
>       INIT_DELAYED_WORK(&adapter->vc_event_task, idpf_vc_event_task);
>
> +     idpf_devlink_register(adapter);
> +
>       adapter->dev_ops.reg_ops.reset_reg_init(adapter);
>       set_bit(IDPF_HR_DRV_LOAD, adapter->flags);
>       queue_delayed_work(adapter->vc_event_wq, &adapter->vc_event_task,
> @@ -367,7 +374,7 @@ static int idpf_probe(struct pci_dev *pdev, const struct 
> pci_device_id *ent)
>  err_init_wq:
>       idpf_decfg_device(adapter);
>  err_free:
> -     kfree(adapter);
> +     idpf_devlink_free(adapter);
>       return err;
>  }
>
> --
> 2.52.0

Reply via email to