From: "Rao, Nikhil" <nikhirao@amd.com>
To: Paolo Abeni <pabeni@redhat.com>
Cc: netdev@vger.kernel.org, kuba@kernel.org, brett.creeley@amd.com,
eric.joyner@amd.com, andrew+netdev@lunn.ch, davem@davemloft.net,
edumazet@google.com, jacob.e.keller@intel.com,
nikhil.rao@amd.com
Subject: Re: [PATCH net-next v6 4/6] pds_core: add PLDM component info display
Date: Wed, 8 Jul 2026 10:55:48 -0700 [thread overview]
Message-ID: <bd8b3e07-223e-4dab-957f-d3513d0f27c0@amd.com> (raw)
In-Reply-To: <20260702091115.93857-1-pabeni@redhat.com>
On 7/2/2026 2:11 AM, Paolo Abeni wrote:
> From: AI Reviewer <ai@example.com>
>
> This is an AI-generated review of your patch. The human sending this
> email has considered the AI review valid, or at least plausible.
> Full review at: https://netdev-ai.bots.linux.dev/sashiko/
> ---
> pds_core: add PLDM component info display
>
> This change adds detailed PLDM component info to devlink info on
> identity v2 devices, introduces a pdsc_fw_components_invalidate()
> helper used during firmware recovery and after firmware update, and
> maps PDS_CORE_FW_TYPE_MAIN to the generic "fw" name in the PLDM
> flash path.
>
>> diff --git a/drivers/net/ethernet/amd/pds_core/core.c b/drivers/net/ethernet/amd/pds_core/core.c
>> index 38a2446571af..4d9ab8b74ec6 100644
>> --- a/drivers/net/ethernet/amd/pds_core/core.c
>> +++ b/drivers/net/ethernet/amd/pds_core/core.c
>> @@ -580,6 +580,8 @@ void pdsc_fw_up(struct pdsc *pdsc)
>> return;
>> }
>>
>> + pdsc_fw_components_invalidate(pdsc);
>> +
>> err = pdsc_setup(pdsc, PDSC_SETUP_RECOVERY);
>> if (err)
>> goto err_out;
>
> [Medium]
> Can concurrent access to pdsc->fw_components race here?
> pdsc_fw_up() runs from pdsc_health_thread (workqueue, holding only
> pdsc->config_lock) and from pdsc_reset_done (PCI reset handler, holding
> neither), so pdsc_fw_components_invalidate() writes num_components = 0
> without the devlink instance lock.
>
> Meanwhile, pdsc_dl_component_info_get() reads pdsc->fw_components from
> the devlink info_get callback under only the devlink lock, never
> config_lock. The two domains do not exclude each other.
>
> In pdsc_dl_component_info_get():
>
> if (!pdsc->fw_components.num_components) {
> err = pdsc_get_component_info(pdsc);
> if (err || !pdsc->fw_components.num_components)
> return pdsc_dl_report_fw_ver(req,
> pdsc->dev_info.fw_version);
> }
>
> list_info = &pdsc->fw_components;
> num_components = min_t(u16, list_info->num_components,
> le16_to_cpu(pdsc->dev_ident.max_fw_slots));
>
> The reader can observe num_components > 0 on the first load, then
> re-read it inside min_t() and observe 0 after pdsc_fw_up() invalidates
> the cache, producing zero iterations and no fallback. Conversely, a
> stale non-zero count could be iterated over info[] entries describing
> the previous firmware.
>
> No READ_ONCE/WRITE_ONCE or memory barriers are used. Would a lock or
> RCU be a better fit here?
Will fix in v7 using READ_ONCE/WRITE_ONCE pairing for num_components.
>
>> diff --git a/drivers/net/ethernet/amd/pds_core/devlink.c b/drivers/net/ethernet/amd/pds_core/devlink.c
>> index 3b763ee1715e..bd234c3c50b2 100644
>> --- a/drivers/net/ethernet/amd/pds_core/devlink.c
>> +++ b/drivers/net/ethernet/amd/pds_core/devlink.c
>> @@ -93,14 +93,110 @@ int pdsc_dl_flash_update(struct devlink *dl,
>> return pdsc_firmware_update(pdsc, params, extack);
>> }
>>
>> +static int pdsc_dl_report_component(struct devlink_info_req *req,
>> + struct pds_core_fw_component_info *info)
>> +{
>> + enum devlink_info_version_type ver_type;
>> + u16 flags = le16_to_cpu(info->flags);
>> + char *ver = info->version;
>> + const char *name;
>> + char buf[32];
>> +
>> + /* Main firmware is reported as generic "fw" */
>> + if (info->component_type == PDS_CORE_FW_TYPE_MAIN) {
>> + if (info->slot_id == PDS_CORE_FW_SLOT_GOLD)
>> + snprintf(buf, sizeof(buf), "fw.gold");
>> + else
>> + snprintf(buf, sizeof(buf), "fw");
>> + } else {
>> + name = pdsc_fw_type_to_name(info->component_type);
>> + if (!name)
>> + return 0;
>> +
>> + if (info->slot_id == PDS_CORE_FW_SLOT_GOLD)
>> + snprintf(buf, sizeof(buf), "fw.%s.gold", name);
>> + else
>> + snprintf(buf, sizeof(buf), "fw.%s", name);
>> + }
>
> [Medium]
> For PDS_CORE_FW_TYPE_MAIN, only PDS_CORE_FW_SLOT_GOLD is special-cased.
> PDS_CORE_FW_SLOT_INVALID, PDS_CORE_FW_SLOT_A, and PDS_CORE_FW_SLOT_B all
> end up emitting the bare name "fw".
>
> The legacy v1 path used distinct names fw.mainfwa and fw.mainfwb for
> these two slots, and devlink_info_version_*_put() does not deduplicate
> names. If firmware reports two MAIN components (which the v1
> pds_core_fw_list_info already exposed as A/B), will userspace see two
> entries both named "fw" with no way to distinguish them?
Both slots emit "fw" but are distinguished by version type: one is
reported as "running", the other as "stored" if there's a pending
update. If no pending update, the active slot is reported as both
"running" and "stored".
V1 and V2 use different naming conventions - this is expected.
>
> [Medium]
> Are the new component names documented anywhere? The driver introduces
> fw.bootloader, fw.cpld, fw.secure, fw.fpga, fw.suc, fw.suc.bootloader,
> fw.uboot, plus a .gold variant of each, and fw.gold.
>
> Documentation/networking/devlink/devlink-info.rst says:
>
> It is expected that drivers use the following generic names ... As
> last resort, if a component is truly unique, using driver-specific
> names is allowed, but these should be documented in the driver-specific
> file.
>
> Of those names only fw and fw.bootloader correspond to documented
> generic suffixes; the rest appear to be driver-invented, and there is
> no Documentation/networking/devlink/pds_core.rst introduced by this
> patch.
Accepted. Will move devlink documentation to
Documentation/networking/devlink/pds_core.rst in a follow-up patch per
devlink-info.rst requirements.
>The .gold suffix in particular is not part of the generic
> vocabulary (different copies of the same component are normally handled
> via bundle_id or by reporting the same name under both running and
> stored).
We do report the same name under both running and stored for main
firmware (fw appears in both sections). The .gold suffix is for recovery
firmware, which is a different component - not another copy of the same
firmware.
> Composite names like fw.suc.bootloader.gold do not have any
> documented dot-separation semantics either.
The .gold suffix is documented as indicating recovery firmware.
Composite names like fw.suc.bootloader use dots to separate hierarchical
components (SUC's bootloader).
>
>> +
>> + ver_type = DEVLINK_INFO_VERSION_TYPE_NONE;
>> + if (flags & PDS_CORE_FW_COMPONENT_INFO_F_UPDATE_BY_NAME)
>> + ver_type = DEVLINK_INFO_VERSION_TYPE_COMPONENT;
>> +
>> + if (flags & PDS_CORE_FW_COMPONENT_INFO_F_FIXED) {
>> + int err;
>> +
>> + err = devlink_info_version_fixed_put(req, buf, ver);
>> + if (err)
>> + return err;
>> + }
>> +
>> + if (flags & PDS_CORE_FW_COMPONENT_INFO_F_RUNNING) {
>> + int err;
>> +
>> + err = devlink_info_version_running_put_ext(req, buf,
>> + ver, ver_type);
>> + if (err)
>> + return err;
>> + }
>> +
>> + if (flags & PDS_CORE_FW_COMPONENT_INFO_F_STARTUP) {
>> + int err;
>> +
>> + err = devlink_info_version_stored_put_ext(req, buf,
>> + ver, ver_type);
>> + if (err)
>> + return err;
>> + }
>> +
>> + return 0;
>> +}
>
> [Medium]
> Is the generic running "fw" entry still guaranteed on the v2 path?
> It is produced only as a side effect of pdsc_dl_report_component()
> seeing component_type == PDS_CORE_FW_TYPE_MAIN with
> PDS_CORE_FW_COMPONENT_INFO_F_RUNNING set.
>
> The v1 path always called:
>
> devlink_info_version_running_put(req,
> DEVLINK_INFO_VERSION_GENERIC_FW,
> pdsc->dev_info.fw_version);
>
> unconditionally. If firmware reports MAIN only with F_STARTUP/F_FIXED
> (no F_RUNNING), or reports no MAIN component at all, does the user
> silently lose the generic running fw version that monitoring tools rely
> on to identify the active firmware?
No, Firmware always reports F_RUNNING for the currently running slot.
>
>> +
>> +static int pdsc_dl_report_fw_ver(struct devlink_info_req *req, char *fw_ver)
>> +{
>> + return devlink_info_version_running_put(req,
>> + DEVLINK_INFO_VERSION_GENERIC_FW,
>> + fw_ver);
>> +}
>> +
>> +static int pdsc_dl_component_info_get(struct devlink *dl,
>> + struct devlink_info_req *req,
>> + struct netlink_ext_ack *extack)
>> +{
>> + struct pds_core_component_list_info *list_info;
>> + struct pdsc *pdsc = devlink_priv(dl);
>> + u8 num_components;
>> + int err;
>> + int i;
>> +
>> + if (!pdsc->fw_components.num_components) {
>> + err = pdsc_get_component_info(pdsc);
>> + if (err || !pdsc->fw_components.num_components)
>> + return pdsc_dl_report_fw_ver(req,
>> + pdsc->dev_info.fw_version);
>> + }
>
> [High]
> Can devlink info polling accumulate deferred DMA buffers when the
> firmware is hung?
>
> pdsc_dl_component_info_get() is reachable from any devlink dev info
> request. On -EAGAIN or -ETIMEDOUT, pdsc_get_component_info() calls
> pdsc_deferred_dma_add() and returns the error without setting
> pdsc->fw_components.num_components:
>
> err = pdsc_devcmd(pdsc, &cmd, &comp, pdsc->devcmd_timeout * 2);
> if (err == -ETIMEDOUT || err == -EAGAIN) {
> pdsc_deferred_dma_add(pdsc, deferred, dma_addr, list_info,
> PDS_PAGE_SIZE, DMA_FROM_DEVICE);
> return err;
> }
>
> The cached count therefore stays 0, so the next devlink info request
> re-enters the same path and queues another PDS_PAGE_SIZE allocation
> plus DMA mapping. The deferred list is only drained by
> pdsc_deferred_dma_free() in __pdsc_devcmd_locked() on a non-EAGAIN
> return.
>
> Before this patch, pdsc_get_component_info() was reachable only from
> the privileged flash path. Is it intentional that any monitoring agent
> polling devlink dev info while firmware is wedged can grow the deferred
> DMA list unbounded?
If firmware is hung, health_work triggers recovery. Deferred buffers are
cleaned up in pdsc_teardown() during recovery. Each buffer is ~4KB, and
repeated polling during a hang accumulates minimal memory before
recovery kicks in and cleans up.
>
> [Medium]
> On the v2 branch, the function falls back to a single
> pdsc_dl_report_fw_ver() call whenever pdsc_get_component_info() returns
> an error or num_components is still 0 (which also happens when the
> firmware reports comp.get_component_info.ver == 0 and the function
> returns 0).
>
> Before this patch, pdsc_dl_info_get() unconditionally invoked
> PDS_CORE_FW_GET_LIST and emitted fw.goldfw, fw.mainfwa, fw.mainfwb.
> On v2 devices that branch is unreachable, since pdsc_dl_fw_list_info_get()
> is only called from pdsc_dl_info_get_v1().
>
> For transitional firmware that advertises identity v2 but does not yet
> support PLDM/GET_COMPONENT_INFO, would calling pdsc_dl_fw_list_info_get()
> as a v2 fallback preserve the previous four-version output rather than
> silently collapsing it to one?
V2 firmware always supports GET_COMPONENT_INFO. There is no transitional
v2 firmware without this support
>
>> +
>> + list_info = &pdsc->fw_components;
>> + num_components = min_t(u16, list_info->num_components,
>> + le16_to_cpu(pdsc->dev_ident.max_fw_slots));
>> + for (i = 0; i < num_components; i++) {
>> + err = pdsc_dl_report_component(req, &list_info->info[i]);
>> + if (err)
>> + return err;
>> + }
>> +
>> + return 0;
>> +}
>
> [Medium]
> What happens if dev_ident.max_fw_slots is 0? pdsc_get_component_info()
> populates pdsc->fw_components.num_components from the firmware list
> (bounded by PDS_CORE_FW_COMPONENT_LIST_LEN), but the loop bound clamps
> that against the separate max_fw_slots identity field:
>
> num_components = min_t(u16, list_info->num_components,
> le16_to_cpu(pdsc->dev_ident.max_fw_slots));
>
> If firmware advertises identity v2 but reports max_fw_slots == 0, the
> earlier !pdsc->fw_components.num_components check does not fire (the
> count is non-zero), min_t() yields 0, the loop body is skipped, and
> pdsc_dl_info_get() proceeds straight to ASIC ID/REV/serial. Would
> adding a fallback to pdsc_dl_report_fw_ver() in this case avoid
> emitting devlink info with no fw entry at all?
"max_fw_slots" is the component count from firmware identity.A v2 device
reporting max_fw_slots == 0 would be invalid firmware configuration
>> +
>> static char *fw_slotnames[] = {
>> "fw.goldfw",
>> "fw.mainfwa",
>> "fw.mainfwb",
>> };
>>
>> -int pdsc_dl_info_get(struct devlink *dl, struct devlink_info_req *req,
>> - struct netlink_ext_ack *extack)
>> +static int pdsc_dl_fw_list_info_get(struct devlink *dl,
>> + struct devlink_info_req *req,
>> + struct netlink_ext_ack *extack)
>> {
>
> [ ... ]
>
>> @@ -134,12 +230,41 @@ int pdsc_dl_info_get(struct devlink *dl, struct devlink_info_req *req,
>> return err;
>> }
>>
>> - err = devlink_info_version_running_put(req,
>> - DEVLINK_INFO_VERSION_GENERIC_FW,
>> - pdsc->dev_info.fw_version);
>> + return 0;
>> +}
>> +
>> +static int pdsc_dl_info_get_v1(struct devlink *dl,
>> + struct devlink_info_req *req,
>> + struct netlink_ext_ack *extack)
>> +{
>> + struct pdsc *pdsc = devlink_priv(dl);
>> + int err;
>> +
>> + err = pdsc_dl_fw_list_info_get(dl, req, extack);
>> if (err)
>> return err;
>>
>> + /* Version 1: report fw from dev_info (running only) */
>> + return pdsc_dl_report_fw_ver(req, pdsc->dev_info.fw_version);
>> +}
>> +
>> +int pdsc_dl_info_get(struct devlink *dl, struct devlink_info_req *req,
>> + struct netlink_ext_ack *extack)
>> +{
>> + struct pdsc *pdsc = devlink_priv(dl);
>> + char buf[32];
>> + int err;
>> +
>> + if (pdsc->dev_ident.version >= PDS_CORE_IDENTITY_VERSION_2) {
>> + err = pdsc_dl_component_info_get(dl, req, extack);
>> + if (err)
>> + return err;
>> + } else {
>> + err = pdsc_dl_info_get_v1(dl, req, extack);
>> + if (err)
>> + return err;
>> + }
>> +
>
> [Medium]
> Is the devlink-info naming change across the identity-version boundary
> intentional, and is it captured in the commit message or a Documentation
> update?
Yes, the naming change is intentional. This is documented in the "Info
versions (PLDM)" section of pds_core.rst, which lists all the V2
component names separately from the legacy V1 names.
> Before this patch every device emitted stored slot names from
> fw_slotnames[] (fw.goldfw, fw.mainfwa, fw.mainfwb) via the unconditional
> PDS_CORE_FW_GET_LIST devcmd. After this patch, devices that advertise
> identity >= PDS_CORE_IDENTITY_VERSION_2 take the
> pdsc_dl_component_info_get() branch and emit a different set of names
> (fw, fw.gold, fw.bootloader, fw.uboot, fw.cpld, ...), with no alias for
> the old names.
>
> A firmware-only upgrade can therefore silently rename the user-visible
> stored entries. Should the commit message call out this UAPI rename,
> and should the legacy names remain emitted as aliases for compatibility
> with existing fleet tooling that parses devlink dev info output?
V1 named specific physical slots (fw.mainfwa, fw.mainfwb). V2 uses a
single fw name that appears in either the running: or stored: section.
The concepts don't map 1:1, emitting legacy names as aliases doesn't
make sense. Fleet tooling that upgrades firmware to PLDM-capable version
should expect the new format.
Nikhil
next prev parent reply other threads:[~2026-07-08 17:55 UTC|newest]
Thread overview: 11+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-06-29 23:01 [PATCH net-next v6 0/6] pds_core: Add PLDM firmware update and host backed memory support Nikhil P. Rao
2026-06-29 23:01 ` [PATCH net-next v6 1/6] pds_core: add support for quiet devcmd failures Nikhil P. Rao
2026-06-29 23:01 ` [PATCH net-next v6 2/6] pds_core: add support for identity version 2 Nikhil P. Rao
2026-06-29 23:01 ` [PATCH net-next v6 3/6] pds_core: add PLDM firmware update support via devlink flash Nikhil P. Rao
2026-07-02 9:11 ` Paolo Abeni
2026-07-08 18:25 ` Rao, Nikhil
2026-06-29 23:01 ` [PATCH net-next v6 4/6] pds_core: add PLDM component info display Nikhil P. Rao
2026-07-02 9:11 ` Paolo Abeni
2026-07-08 17:55 ` Rao, Nikhil [this message]
2026-06-29 23:01 ` [PATCH net-next v6 5/6] pds_core: add host backed memory support for firmware Nikhil P. Rao
2026-06-29 23:02 ` [PATCH net-next v6 6/6] pds_core: add debugfs support for host backed memory Nikhil P. Rao
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=bd8b3e07-223e-4dab-957f-d3513d0f27c0@amd.com \
--to=nikhirao@amd.com \
--cc=andrew+netdev@lunn.ch \
--cc=brett.creeley@amd.com \
--cc=davem@davemloft.net \
--cc=edumazet@google.com \
--cc=eric.joyner@amd.com \
--cc=jacob.e.keller@intel.com \
--cc=kuba@kernel.org \
--cc=netdev@vger.kernel.org \
--cc=nikhil.rao@amd.com \
--cc=pabeni@redhat.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox