[PATCH net-next v6 0/3] dinghai: firmware handshake, MSI-X pools and async event queues
From: han.junyang
Date: Fri Nov 13 2026 - 02:23:07 EST
From: Junyang Han <han.junyang@xxxxxxxxxx>
This series continues the DingHai (ZXDH) PF driver bring-up: after PCI
probing, it verifies the firmware version contract, waits for the
RISC-V management core to become ready, sets up the MSI-X interrupt
pools, and creates the async event queues through which the firmware
will report events.
Some notes on the IRQ design:
The vector space is partitioned into per-purpose pools (async, RDMA,
vq). Event queues share a vector through an atomic notifier chain
attached to the IRQ, and the sharing degree is governed by pool
thresholds. The IRQ table hangs off a void *priv in the shared core
device: the PF, MPF and SF core devices each carry a different pool
layout behind that pointer, so a type-specific struct in en_pf.c keeps
the shared header free of PF-only details.
Changes in v6:
- Guard the IRQ table teardown in patch 2 rather than deferring the
guards to patch 3, so the probe error paths of the MSI-X patch are
safe on their own and bisection cannot land on an unguarded cleanup
(sashiko review of v5).
- Review findings not taken from v5:
The sashiko automated review of v5 [1], which was not posted to the
list, reported four findings. The IRQ table teardown NULL
dereferences on the probe error paths were real and are fixed in
this revision. The remaining three restate earlier findings or
do not apply: the BAR0 bounds item repeats the BAR 0 entry below;
the 20 s legacy wait is the legacy-firmware detection itself:
firmware that predates the compat region never populates it and
the driver reports and proceeds in legacy mode after the timeout
(see Changes in v4); and the health_version read cannot race the
RISC-V core initialization: the readiness skip fires only for
firmware with patch < ZXDH_HPIRQ_PATCH, which never reports the
power-on flag, while firmware that does report health_version
carries patch >= ZXDH_HPIRQ_PATCH and initializes the health
buffer before the compat block reports ready.
[1] https://sashiko.dev/#/patchset/20261014151200489685SCIlolykW0NGfL5EtQ%40zte.com.cn
Changes in v5:
- Drop __packed from zxdh_fw_compat and zxdh_health_buffer: both
structs are naturally aligned with no padding.
Changes in v4:
- Fold the irq and eq table create() steps into their init()
counterparts and route every probe error path through the same
destroy() functions remove() uses, so cleanup has a single
authority from the start (review feedback on v3).
- Give the pool name a buffer bound of its own (16 bytes) instead of
sharing the 100-byte IRQ name buffer, so W=1 builds stay clean of
-Wformat-truncation (review feedback on v3).
- Lower the compat region wait from 200 s to 20 s: the firmware
publishes the block within 10 s of boot, so twice that leaves
margin, and the wait now sits far below the 180 s udev event
window raised on the thread (review feedback on v3).
- Wait for the compat block with a per-field readiness check instead
of only the first dword: the firmware fills the fields one by one,
and a dword-granular check can read a half-populated block (the
"single write" justification given in v3 was wrong).
- Log the legacy-firmware assumption when the compat region wait
times out, making the intentionally ignored timeout visible.
Changes in v3:
- Unmap the modern config MMIO regions on the probe error paths added
in this series; they used to leak when the fw compat check or the
RISC-V readiness wait failed.
- Skip the RISC-V readiness wait for firmware without the compat
region: the erased patch field read as 0xffff and defeated the skip.
- Make fw_minor unsigned so firmware minor versions >= 128 are not
rejected through sign wrap.
- Balance the per-CPU IRQ accounting on release, so pool teardown does
not trip its leftover WARN; set the IRQ affinity for real with
irq_set_affinity_and_hint() instead of only updating the hint; name
IRQs after their pool instead of a hardcoded prefix; assert that the
pool is empty at free instead of force-releasing leftovers.
- Clear eq->irq when the async IRQ request fails, so teardown does not
treat the ERR_PTR as a live IRQ.
Review findings not taken:
- xa_alloc() with a NULL entry does not fail: __xa_alloc() turns a
NULL entry into the internal zero entry as a reservation
(lib/xarray.c), which is the reservation semantics the pool relies
on.
- BAR 0 length checks against a truncated bar: the bar layout is part
of the board firmware contract and the driver does not defend
against a broken device, as settled during the review of the
earlier device bring-up series (Andrew Lunn).
Changes in v2:
- Convert both firmware readiness polls to readx_poll_timeout()
(Andrew Lunn).
- Read the fw compat block field by field through ioread*() accessors
instead of an ioread32_rep() bulk copy, which misplaces the u8/u16
fields on big-endian; no __le annotations are needed since each
accessor converts from little-endian (Andrew Lunn).
- Use kref for the IRQ reference count (Andrew Lunn).
Junyang Han (3):
dinghai: add firmware version check and RISC-V readiness polling
dinghai: add MSI-X interrupt pools
dinghai: add async event queue for firmware notifications
drivers/net/ethernet/zte/dinghai/Makefile | 2 +-
drivers/net/ethernet/zte/dinghai/en_pf.c | 223 +++++++++++
drivers/net/ethernet/zte/dinghai/en_pf.h | 56 +++
drivers/net/ethernet/zte/dinghai/zxdh_eq.c | 137 +++++++
drivers/net/ethernet/zte/dinghai/zxdh_eq.h | 60 +++
drivers/net/ethernet/zte/dinghai/zxdh_irq.c | 406 ++++++++++++++++++++
drivers/net/ethernet/zte/dinghai/zxdh_irq.h | 73 ++++
7 files changed, 956 insertions(+), 1 deletion(-)
create mode 100644 drivers/net/ethernet/zte/dinghai/zxdh_eq.c
create mode 100644 drivers/net/ethernet/zte/dinghai/zxdh_eq.h
create mode 100644 drivers/net/ethernet/zte/dinghai/zxdh_irq.c
create mode 100644 drivers/net/ethernet/zte/dinghai/zxdh_irq.h
--
2.27.0