Skip to content

kernel/ive_neo: support hi3516cv500 alongside hi3516ev200#105

Merged
widgetii merged 2 commits into
mainfrom
ive-neo-cv500-support
May 13, 2026
Merged

kernel/ive_neo: support hi3516cv500 alongside hi3516ev200#105
widgetii merged 2 commits into
mainfrom
ive-neo-cv500-support

Conversation

@widgetii
Copy link
Copy Markdown
Member

Summary

  • Extend ive_neo to build and run on cv500 (CHIPARCH=hi3516cv500, board hi3516av300) in addition to the existing V4 family (ev200/ev300, gk7205v200/v300).
  • cv500 has a classic-only IVE block at 0x11230000 — no fused NEO/XNN unit like V4 has at 0x11320000 — so XNN ioctls return -EOPNOTSUPP on cv500 and the 24 classic IVE ops (DMA, Filter, Sobel, Thresh, CCL, SAD, CannyHysEdge, GMM2, …) work as on V4. CNN inference on cv500 lives on a separate NNIE block at 0x11100000 and is out of scope for this PR (NNIE backend will land later).

What's in kernel/ive_neo/ive_neo.c

  • Compile-time ive_neo_chip table (has_xnn, standalone_base, setup_mem_speed), selected via $(CHIPARCH).
  • Split OSAL/CMPI ABI by chip:
    • V4: CMPI_GetModuleFuncById(2)SYS_EXPORT_FUNC_SpfnSysDrvIoCtrl(chn, 144=reset, 145=clk_en), MPP_CHN_S.
    • cv500: cmpi_get_module_func_by_id(HI_ID_SYS)sys_export_funcpfn_sys_drv_ioctrl(chn, SYS_IVE_RESET_SEL, SYS_IVE_CLK_EN), hi_mpp_chn.
  • ev200-only register writes in ive_hw_init (offsets 0x34/0x54/0x60/0x8C — outside cv500's IVE window) gated with #if !defined(hi3516cv500).
  • [0x90] DRAM-arbitration sequence skipped on cv500 (only Conv needs it; cv500's IVE has no Conv).
  • XNN handlers (loadmodel, unloadmodel, forward, fwd_slice, query, open_dev) early-return -EOPNOTSUPP when !ive_neo_chip.has_xnn.
  • Removed three ev200-fallback ioremap(0x11320000, …) paths in ive_svp_init/ive_submit_nonxnn/ive_op_canny_hys — OSAL mode now hard-fails -ENODEV if DT probe didn't run, standalone uses ive_neo_chip.standalone_base.
  • ive_init.c switches to plain Linux kernel types and picks hi_osal.h on cv500 vs osal.h+common.h on V4 so the same source compiles for both families.
  • cv500 reuses the kmalloc + virt_to_phys + osal_flush_dcache_area MMZ path from the QEMU standalone build (cv500 vendor headers don't expose CMPI_* MMZ symbols).

Build wiring

  • kernel/hi3516cv500.kbuild now includes ive_neo/Kbuild alongside the vendor \$(PREFIX)ive.o blob. Both open_ive.ko (vendor) and open_ive_neo.ko (clean-room) ship — init scripts pick one at runtime, same coexistence pattern as on ev200.

Two cv500 bugs caught during on-target verification

  1. Register writes outside cv500's IVE window triggered a sync-abort that hung the board. Fixed by gating offsets 0x34/0x54/0x60/0x8C to V4 only.
  2. Pre-clock-enable register read in ive_svp_init (reading regs+0x80 and regs+0x04 to decide whether to re-init) hung cv500 because the IVE clock is gated off at boot — ive_assert_clock_cv500 runs inside hw_init, so the pre-read fired before clocks. Fixed by going straight to hw_init on the first call; the cheap pre-check only fires on subsequent calls.

CI additions

Extended the toolchain matrix step (Verify ive_neo built for this platform) to gate ev200/gk7205v200/cv500 rows on:

  • open_ive_neo.ko exists in the build output.
  • The chip-ops format string chip=%s xnn=%s base=0x%x is present in the .ko.
  • The correct chip-name string is baked in (hi3516cv500 for the cv500 row, hi3516ev200 for the V4 rows).
  • For cv500 specifically: the XNN dispatch code is fully DCE'd (no FC layer using non-tiled string in the .ko) — sanity check that the has_xnn=false guard isn't bypassed in future refactors. The XNN-reject log line is kept as a positive guard.

The qemu-ive-ops job continues to run the existing 19-op register regression against the hi3516ev300 QEMU machine model (cv500 doesn't model the clock-gate cleanly enough to be a useful end-to-end test for this driver — that's why the bug only surfaced on hardware).

Test plan

  • ev200 toolchain build: make BOARD=hi3516ev300_lite … br-hisilicon-opensdk-rebuildopen_ive_neo.ko 29132 B, contains hi3516ev200 + new chip-ops log strings.
  • cv500 toolchain build: make BOARD=hi3516av300_lite … br-hisilicon-opensdk-rebuildopen_ive_neo.ko 26432 B (smaller, XNN code DCE'd), contains hi3516cv500 + skipping [0x90] mem-speed strings.
  • QEMU ive_ops regression (kernel/ive_neo/test/qemu/run-qemu.sh): 19/19 ops pass under hi3516ev300 model.
  • On-target ev300 (10.216.128.68, CHIPARCH=hi3516ev200): module loaded, IRQ 52 registered, /dev/ive present, ioctl(SVP_INIT) returns 0, dmesg shows chip=hi3516ev200 xnn=yes base=0x11320000, HW ID=0x11e1a300, [0x90]=0x01ab5159.
  • On-target av300 (10.216.128.64, CHIPARCH=hi3516cv500): module loaded, IRQ 61 registered, /dev/ive present, ioctl(SVP_INIT) returns 0, dmesg shows chip=hi3516cv500 xnn=no base=0x11230000, skipping [0x90] mem-speed, HW ID=0x11e1a300, svp_init: svp_alg phys=0x9dc6e000. Board stays up across reload cycles.
  • New CI rows (Verify ive_neo built for this platform) green on the matrix.

The on-target smoke test driver lives at kernel/ive_neo/test/board/verify-on-target.sh for anyone with ssh to the same lab boards.

🤖 Generated with Claude Code

widgetii and others added 2 commits May 13, 2026 14:10
Extend ive_neo to build and run on cv500 (CHIPARCH=hi3516cv500, board
hi3516av300) in addition to the existing V4 family (hi3516ev200/ev300,
gk7205v200/v300). cv500 has a classic-only IVE block at 0x11230000 — no
fused NEO/XNN unit like V4 has at 0x11320000 — so XNN ioctls return
-EOPNOTSUPP and the 24 classic IVE ops (DMA, Filter, Sobel, Thresh,
CCL, SAD, CannyHysEdge, GMM2, ...) work as on V4. CNN inference on
cv500 lives on a separate NNIE block at 0x11100000 and is out of scope
for this PR (will land as a separate NNIE backend later).

The port introduces a compile-time chip-ops table in ive_neo.c
(has_xnn flag, standalone_base, setup_mem_speed function pointer) and
splits the OSAL/CMPI ABI by chip: V4 uses CMPI_GetModuleFuncById +
SYS_EXPORT_FUNC_S->pfnSysDrvIoCtrl with cmds 144/145; cv500 uses
cmpi_get_module_func_by_id + sys_export_func->pfn_sys_drv_ioctrl with
SYS_IVE_RESET_SEL/SYS_IVE_CLK_EN. The four ev200-only register writes
in ive_hw_init (offsets 0x34/0x54/0x60/0x8C — outside cv500's IVE
window) are gated out on cv500, and the [0x90] DRAM-arbitration
sequence is skipped (only Conv needs it, and cv500's IVE has no Conv).

Two on-target bugs caught during verification and fixed:
- cv500 register writes outside its IVE window faulted with sync-abort
  (gated with #if !defined(hi3516cv500))
- ive_svp_init pre-read at regs+0x80 hung the board on cv500 because
  cv500 boots with the IVE clock gated off; reorder to run hw_init
  (which calls ive_assert_clock_cv500) before any IVE register read

cv500 reuses the kmalloc+virt_to_phys MMZ path from the QEMU
standalone build because cv500's vendor headers don't expose the CMPI
MMZ symbols. ive_init.c switches to plain Linux kernel types and picks
hi_osal.h on cv500 vs osal.h+common.h on V4 so the same source tree
builds for both families.

CI: extend the toolchain matrix step to verify open_ive_neo.ko is
actually produced for ev200/gk7205v200/cv500 and that the chip-ops
backend selection baked the right name in. Also assert that cv500
builds DCE the XNN dispatch (no "FC layer using non-tiled" string in
the .ko) — a sanity check that the has_xnn=false guard isn't bypassed
in future refactors.

Verified on lab boards 2026-05-13:
- ev300 (CHIPARCH=hi3516ev200): chip=hi3516ev200 xnn=yes, HW ID
  0x11e1a300, [0x90]=0x01ab5159, SVP_INIT returns 0.
- av300 (CHIPARCH=hi3516cv500): chip=hi3516cv500 xnn=no, [0x90]
  skipped, HW ID 0x11e1a300, SVP_INIT returns 0.
- QEMU ive_ops regression (hi3516ev300 model): 19/19 ops pass.

A board-side smoke test script at kernel/ive_neo/test/board/
verify-on-target.sh runs the same checks across both lab boards via
ssh; the firmware build artefacts in kernel/ive_neo/test/qemu/ now
have a .gitignore.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The first CI run on PR #105 hit FAIL: open_ive_neo.ko not built for
hi3516ev200 even though the build step succeeded. With
HISILICON_OPENSDK_SITE_METHOD=local and HISILICON_OPENSDK_VERSION
cleared, buildroot's per-package build dir name isn't deterministic
across versions — locally it lands at hisilicon-opensdk-custom/ but in
CI the pkg-generic.mk fallback uses a different suffix.

Walk the entire output/ tree instead, and on failure dump candidate
dir names + any other open_*.ko found so future regressions surface
the actual path.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@widgetii widgetii merged commit 7aa0f08 into main May 13, 2026
24 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant