From: Simon Horman <horms@kernel.org>
To: han.junyang@zte.com.cn
Cc: Simon Horman <horms@kernel.org>,
andrew+netdev@lunn.ch, davem@davemloft.net, edumazet@google.com,
kuba@kernel.org, pabeni@redhat.com, linux-kernel@vger.kernel.org,
netdev@vger.kernel.org, ran.ming@zte.com.cn,
han.chengfei@zte.com.cn, zhang.yanze@zte.com.cn
Subject: Re: [PATCH net-next v2 1/3] dinghai: add firmware version check and RISC-V readiness polling
Date: Mon, 14 Sep 2026 08:20:31 +0100 [thread overview]
Message-ID: <20260914072032.232931-1-horms@kernel.org> (raw)
In-Reply-To: <20260911115929435mXJzcTF08xlUAdjnT8qqm@zte.com.cn>
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://sashiko.dev/#/patchset/20260911115929435mXJzcTF08xlUAdjnT8qqm@zte.com.cn?part=1
---
dinghai: add firmware version check and RISC-V readiness polling
This patch introduces firmware version compatibility checks and RISC-V health
buffer readiness polling during device probe. It reads version information from
a fixed offset in BAR 0 and waits for the firmware's RISC-V management core
to set a power-on flag.
> diff --git a/drivers/net/ethernet/zte/dinghai/en_pf.c b/drivers/net/ethernet/zte/dinghai/en_pf.c
> index 86d4374088203..d257d8e9b612e 100644
> --- a/drivers/net/ethernet/zte/dinghai/en_pf.c
> +++ b/drivers/net/ethernet/zte/dinghai/en_pf.c
[ ... ]
> @@ -369,6 +371,99 @@ int zxdh_pf_modern_cfg_init(struct zxdh_core_dev *zxdh_dev)
> return ret;
> }
>
> +/* Read the firmware version block and verify the driver/firmware
> + * version contract.
> + */
> +static int zxdh_pf_fw_compat_check(struct zxdh_core_dev *zxdh_dev)
> +{
> + struct zxdh_pf_dev *pf_dev = zxdh_dev->priv;
> + struct zxdh_fw_compat __iomem *compat;
> + struct zxdh_fw_compat *fw_compat;
> + u32 erased;
> +
> + fw_compat = &pf_dev->fw_compat;
> + compat = pf_dev->pci_ioremap_addr[0] + ZXDH_FW_COMPAT_OFFSET;
> +
> + /* The region reads as all ones until the firmware populates it at
> + * the end of its boot; allow up to 200 s for a cold boot.
> + */
> + readx_poll_timeout(ioread32, compat, erased, erased != 0xffffffffU,
> + USEC_PER_SEC,
> + ZXDH_FW_COMPAT_TIMEOUT_SEC * USEC_PER_SEC);
[Severity: High]
Is it intended to ignore the return value of readx_poll_timeout() here?
When running on older firmware that does not populate the compatibility
region, the memory remains 0xffffffff, which causes the driver to spin
synchronously for the full 200 seconds during device initialization.
> +
> + /* Firmware predating the compatibility region keeps the erased
> + * pattern, which fails the module id check below and defers the
> + * decision to the readiness wait.
> + */
> + fw_compat->module_id = ioread8(&compat->module_id);
> + fw_compat->major = ioread8(&compat->major);
> + fw_compat->fw_minor = ioread8(&compat->fw_minor);
> + fw_compat->drv_minor = ioread8(&compat->drv_minor);
> + fw_compat->patch = ioread16(&compat->patch);
[Severity: Medium]
Could there be a race condition between the firmware writing the
compatibility block and the driver reading it?
The readx_poll_timeout() loop polls the first 4 bytes using ioread32() and
proceeds as soon as they change from 0xffffffff. If the firmware writes
the data sequentially, the patch field might still be 0xFFFF when read by
the driver immediately afterward, potentially triggering false version
mismatches.
[Severity: High]
Can an erased compatibility region cause the probe to fail on older
firmware, despite the intended backward compatibility?
When the region is erased, fw_compat->patch is populated with 0xFFFF.
Later in zxdh_pf_wait_riscv_ready(), the driver attempts to skip the wait:
if (health_version != 1 &&
pf_dev->fw_compat.patch < ZXDH_HPIRQ_PATCH)
return 0;
Since 0xFFFF < 4 evaluates to false, the driver falls through, waits an
additional 40 seconds, and fails the probe.
[ ... ]
> @@ -405,6 +500,18 @@ static int zxdh_pf_probe(struct pci_dev *pdev, const struct pci_device_id *id)
> goto err_cfg_init;
> }
>
> + ret = zxdh_pf_fw_compat_check(zxdh_dev);
> + if (ret) {
> + dev_err(&pdev->dev, "zxdh_pf_fw_compat_check failed: %d\n", ret);
> + goto err_cfg_init;
> + }
> +
> + ret = zxdh_pf_wait_riscv_ready(zxdh_dev);
> + if (ret) {
> + dev_err(&pdev->dev, "zxdh_pf_wait_riscv_ready failed: %d\n", ret);
> + goto err_cfg_init;
> + }
[Severity: High]
Do these error paths leak the PCI I/O regions acquired earlier?
The error paths jump to err_cfg_init when these checks fail, which only
calls zxdh_pf_pci_close(). However, the mappings created in
zxdh_pf_modern_cfg_init() require a call to zxdh_pf_modern_cfg_uninit() to
be properly cleaned up.
> +
> devlink_register(devlink);
>
> return 0;
> diff --git a/drivers/net/ethernet/zte/dinghai/en_pf.h b/drivers/net/ethernet/zte/dinghai/en_pf.h
> index 7373dee8d1a9f..bc275ddd75b81 100644
> --- a/drivers/net/ethernet/zte/dinghai/en_pf.h
> +++ b/drivers/net/ethernet/zte/dinghai/en_pf.h
[ ... ]
> @@ -29,6 +29,51 @@
> #define ZXDH_PF_ALIGN2 2
> #define ZXDH_PF_MAP_MINLEN2 2
>
> +/* Fixed offsets of the firmware interface regions within BAR 0. */
> +#define ZXDH_RISCV_HB_OFFSET 0x5300
> +#define ZXDH_FW_COMPAT_OFFSET 0x5400
> +
> +/* Driver/firmware version contract. The firmware publishes its side of
> + * the contract in the region at ZXDH_FW_COMPAT_OFFSET.
> + */
> +#define ZXDH_MODULE_ID 1
> +#define ZXDH_MAJOR 1
> +#define ZXDH_FW_MINOR 0
> +#define ZXDH_DRV_MINOR 0
> +/* Firmware patch level that introduced the health buffer protocol. */
> +#define ZXDH_HPIRQ_PATCH 4
> +
> +#define ZXDH_FW_COMPAT_TIMEOUT_SEC 200
> +#define ZXDH_RISCV_READY_TIMEOUT_SEC 40
> +
> +/* Firmware version compatibility block at ZXDH_FW_COMPAT_OFFSET.
> + * Fields are read through ioread*(), which converts from little-endian.
> + */
> +struct zxdh_fw_compat {
> + u8 module_id;
> + u8 major;
> + s8 fw_minor;
[Severity: Medium]
Will firmware minor versions 128 or greater be improperly rejected due to
the signedness of fw_minor?
When fw_minor is read into an s8, values 128 or greater will wrap to
negative numbers. The validation check in zxdh_pf_fw_compat_check():
if (fw_compat->fw_minor < ZXDH_FW_MINOR) {
...
(where ZXDH_FW_MINOR is 0) evaluates to true for these negative values,
incorrectly triggering a version incompatibility error.
> + u8 drv_minor;
> + u16 patch;
> + u16 rsv;
> +} __packed;
next prev parent reply other threads:[~2026-09-14 7:20 UTC|newest]
Thread overview: 7+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-09-11 3:56 [PATCH net-next v2 0/3] dinghai: firmware handshake, MSI-X pools and async event queues han.junyang
2026-09-11 3:59 ` [PATCH net-next v2 1/3] dinghai: add firmware version check and RISC-V readiness polling han.junyang
2026-09-14 7:20 ` Simon Horman [this message]
2026-09-11 4:02 ` [PATCH net-next v2 2/3] dinghai: add MSI-X interrupt pools han.junyang
2026-09-14 7:20 ` Simon Horman
2026-09-11 4:05 ` [PATCH net-next v2 3/3] dinghai: add async event queue for firmware notifications han.junyang
2026-09-14 7:20 ` Simon Horman
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=20260914072032.232931-1-horms@kernel.org \
--to=horms@kernel.org \
--cc=andrew+netdev@lunn.ch \
--cc=davem@davemloft.net \
--cc=edumazet@google.com \
--cc=han.chengfei@zte.com.cn \
--cc=han.junyang@zte.com.cn \
--cc=kuba@kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=netdev@vger.kernel.org \
--cc=pabeni@redhat.com \
--cc=ran.ming@zte.com.cn \
--cc=zhang.yanze@zte.com.cn \
/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
all inboxes | Powered by JetHome®