evidence · 9.6 KiB

mainline-sd1-clock-consumers-2026-10-02.md

Committed at docs/research/mainline-sd1-clock-consumers-2026-10-02.md. This is what grounds the requirements that cite it.

Open raw source

Optional SD1 clock-consumer correction, 2026-10-02

Recorded at 2026-10-02T19:54:43Z. Evidence class: read-only host source inspection and coordinator-reported physical comparison. No kernel/config change, build, board input or serial access was performed here. A correction without the diagnostic flag and specific-clock attribution remain UNVERIFIED.

Worktree /home/jadams/tmp/k230-mainline-sd1-clock-consumers, branch audit/mainline-sd1-clock-consumers, base 9cd4a3f870a62c01d63abae60dc07b309e054c52. Only this note is owned; no board or build slot was reserved. Start and handoff use cached tools/work-status.py at idle priority, with output outside the repository.

Observation and source boundary

The coordinator reports the same asj7l4zj5jrjkgng4nrcx3y72p7jf7aa trial bundle, 4wkhxf55y1abg1kg2xd0acsfjqr64j0h kernel and v9qc1sf0iz53s3x6g6vwfyaxghkfpnyk system, with volatile clk_ignore_unused, printed clk: Not disabling unused clocks, advanced beyond the earlier MMC shutdown entry, printed reboot: Restarting system, reached SPL and returned automatically to the protected normal system. The controller exited 0; a fresh boot ID, profile, kernel, services and all eight protected hashes passed. This supports dependence on global unused-clock cleanup. It does not isolate SD1 or any particular gate. The quiet baseline without the flag remains a failed automatic-return trial. Physical provenance belongs to the coordinator’s committed comparison packet; no private capture was read for this note.

The inspected exact source is /nix/store/jvz4v73g8a67pqwm06v079h6s1cpqr9s-linux-mainline-k230-drm-src, Linux pin 72d3fcf802c45d00b300f25b848a93c3a2bd7c7e plus optional K230 patches. Vendor source is /nix/store/pn7bm6ck5a3x6pnk1ng30hlf24qn85jx-source, pin 7d4e1f444f461dbe3833bd99a4640e7b6c2cd529. See the prior MMC boundary audit and vendor/mainline clock comparison.

Why three additional consumers are the smallest supported set

Pinned upstream snps,dwcmshc-sdhci.yaml:115 requires five clocks for canaan,k230-emmc / canaan,k230-sdio, named core, bus, axi, block, timer. Its sdhci-of-dwcmshc.c:1947 explicitly obtains/enables the three additional K230 clocks. The current candidate uses the distinct vendor compatible canaan,k230-dw-mshc and copied Kendryte driver; that driver only obtains core/bus (:398–410).

The vendor clock-provider source (arch/riscv/boot/dts/canaan/k230_clock_provider.dtsi:465–538) describes separate SD base, AXI, card-TX and timer branches. Its SD1 definitions at :617,881,905,959,1081 agree with mainline’s register offset/bit/parent definitions in drivers/clk/clk-k230.c:454,559,582,592,639:

DT nameMainline IDVendor role; retained purpose
coreK230_HS_SD1_BASE_GATE = 31Base clock; keep existing rate source for sdhci_pltfm_clk_get_max_clock() (sdhci-pltfm.c:31).
busK230_HS_SD1_AHB_GATE = 13Register-bus interface clock.
axiK230_HS_SD1_AXI_GATE = 29AXI branch, distinct from the base branch despite their shared upstream source. Relevant to controller/data traffic; this trial does not prove it alone blocked shutdown.
blockK230_HS_SD1_CARD_GATE = 26Vendor card-TX branch from the SD card-clock source. This is the proposed semantic translation to the K230 binding’s block name; no upstream board DTS at this pin supplies a concrete ID-26 example.
timerK230_HS_SD1_TIMER_GATE = 35Separate oscillator-derived SD timer branch, not the Linux scheduler timer. Its necessity in the observed failure is unproved.

All three extras currently have flags 0 and no consumer. Vendor clock init adopts firmware-enabled gates (drivers/clk/clk-k230.c:538–547); mainline ordinary gates do not. Claiming only AXI, card or timer would select a hypothesis unsupported by the global comparison. Claiming the whole provider or marking these clocks permanently critical would bypass device ownership. Five clocks are the smallest source-supported host resource set, not a proven minimal hardware subset.

Concrete proposed patch, not applied

Keep the existing base forward port and console/default DT outputs untouched. Add an optional DRM-only patch to the existing applyPatches.patches list in kernel-mainline-drm.nix, applied to the already-copied drivers/mmc/host/sdhci-of-kendryte.c. Add this override only to k230-tdisplay-mainline-drm.dts:

&mmc_sd1 {
        clocks = <&sysclk K230_HS_SD1_BASE_GATE>,
                 <&sysclk K230_HS_SD1_AHB_GATE>,
                 <&sysclk K230_HS_SD1_AXI_GATE>,
                 <&sysclk K230_HS_SD1_CARD_GATE>,
                 <&sysclk K230_HS_SD1_TIMER_GATE>;
        clock-names = "core", "bus", "axi", "block", "timer";
};

Extend the private driver state and acquire the extras before enabling them:

/* In struct dwcmshc_priv: */
struct clk_bulk_data other_clks[3];

/* In probe, after obtaining priv: */
priv->other_clks[0].id = "axi";
priv->other_clks[1].id = "block";
priv->other_clks[2].id = "timer";
err = devm_clk_bulk_get(&pdev->dev, ARRAY_SIZE(priv->other_clks),
                        priv->other_clks);
if (err)
        return dev_err_probe(&pdev->dev, err, "failed to get SD clocks\n");
/* After successful core/bus enable, before sdhci_add_host: */
err = clk_bulk_prepare_enable(ARRAY_SIZE(priv->other_clks), priv->other_clks);
if (err)
        goto disable_bus_clk;

Use mandatory lookup for all five resources in this matched optional candidate, including checking bus lookup and enable errors. A missing resource or deferred provider must fail probe cleanly, rather than quietly recreating the defect. The upstream helper’s optional lookup preserves other-platform compatibility; the proposed candidate has a matching five-clock DT and no enabled SD0 host. Keep existing max-frequency, clock-rate/divider programming, PHY choice, IRQ, reset and DMA semantics. Do not swap the entire upstream host driver or change compatible: the upstream K230 path also requires USB-PHY/regmap integration and differs beyond resource ownership. The current legacy compatible is not accepted by the upstream schema; five names alone do not make the full node schema-valid.

LifecycleRequired ordering/error handling
ProbeAcquire resources with managed lifetime; enable core, bus, then bulk extras before registering the host. On later failure disable extras, bus, core. Failed bulk enable unwinds itself; do not disable that bulk twice.
Removesdhci_remove_host() completes first; then disable extras, bus, core. The host must retain resources while draining/removing requests.
SuspendCall sdhci_suspend_host() first; on error retain clocks. Only on success disable extras, bus, core.
ResumeEnable core, bus, extras, then call sdhci_resume_host(). Every failed enable/host-resume step unwinds only successfully enabled resources in reverse order. Existing immediate bus-error return leaks a core enable; correct it as part of this lifecycle change.
RebootAdd no clock-disabling .shutdown. MMC card shutdown precedes the platform host and can claim the host, issue SD commands and reset/power off the controller. Keep resources claimed through that sequence; existing platform driver has no shutdown callback.

Narrow build and physical proof plan, not run

This fits the existing mainline usable-root and bounded restart diagnosis; no new capability or normative clock policy is proposed. After review, prepare the exact patched source/config and compile only drivers/mmc/host/sdhci-of-kendryte.o with the matching RISC-V kernel toolchain before a full build. Host object/API proof, full kernel, DTB and matched trial bundle are separate gates:

nix build .#kernelMainlineDrm .#deviceTreeMainlineDrm --no-link
nix build .#kernelMainlineDrmTrialBootFiles --no-link

Check the built SD1 node’s exact five IDs/names, absence of global clock flags, new source/kernel/DTB/system pins and per-artifact SHA/size manifest. Compare unchanged vendor/default and console derivation identities to the base. Review lookup/enable failure unwind and suspend/resume paths; static fake clock tests alone are not physical ownership proof.

The exclusive operator then stages only the reviewed matching optional bundle and runs the same quiet minimal/runtime-trace controller with explicit --bundle and --normal-report, without --ignore-unused-clocks. Require readiness, minimal/runtime-Y gates, clk: Disabling unused clocks, real reboot, SPL, fresh protected normal boot identity and all postflight checks within the same 180-second deadline. Any unknown child/return means stop input and preserve manual recovery. A passing result tests this targeted correction, not per-gate attribution. Only after baseline automatic recovery works proceed separately to the returned read-only label and ro,noload root diagnostics. Usable root, ordinary /init and deliberate touch remain task 5b.5’s open physical gates.

Host checks for this note: git diff --cached --check and openspec validate the-board-runs-a-mainline-kernel --strict passed. Review, merge/push, source implementation, build and physical proof remain; no source change or new board claim is supplied by this document.