U-Boot: enable CMD_MEMTEST and validate the 3.5 GiB DRAM geometry before upstreaming #38

Closed
opened 2026-08-28 05:59:30 +00:00 by tiagoagueda · 2 comments
Owner

The DRAM geometry change that unlocked 3.5 GiB has never been validated beyond "Linux
boots and reports the right size", and the patch is queued to go to a mailing list.

What changed

Per 22-dram-4gb.md, rank 1 -> 2 and rows 16 -> 15, taking usable
memory from 2011 MB to 3471 MB. patches/uboot-sun9i-dram/ is staged for
u-boot@lists.denx.de per patches/README.md.

Why "it boots" is not enough

Wrong DRAM geometry does not fail at boot. It fails as address aliasing under memory
pressure — silent corruption, hours later, in whatever the board happens to be running.
A 3.5 GiB box that has mostly been idle is exactly the case where that would not have
been noticed yet.

There is also a hint in the vendor boot0 output already captured in
logs/uboot-interrupt.log:

Warn:CH0 BYTE0 LCDLR2 different
Warn:CH0 BYTE3 LCDLR2 different

Change

CONFIG_CMD_MEMTEST=y
CONFIG_SYS_ALT_MEMTEST=y

mtest at the U-Boot prompt walks the full range with no OS in the way — the cheapest
possible check, and the right place for it since the claim being tested is a
bootloader-level one.

Also worth running

memtester from Linux userspace over a large allocation, as a second opinion under
real conditions (cache, DVFS, thermals). The two are complementary: mtest covers the
full range, memtester covers realistic access patterns.

Acceptance

  • A full-range mtest pass across all 3.5 GiB, clean.
  • Result recorded in 22-dram-4gb.md, so the upstream patch can state
    what was actually verified rather than implying it.

Blocks: sending uboot-sun9i-dram upstream.

The DRAM geometry change that unlocked 3.5 GiB has never been validated beyond "Linux boots and reports the right size", and the patch is queued to go to a mailing list. ## What changed Per [22-dram-4gb.md](22-dram-4gb.md), `rank` 1 -> 2 and `rows` 16 -> 15, taking usable memory from 2011 MB to 3471 MB. `patches/uboot-sun9i-dram/` is staged for u-boot@lists.denx.de per [patches/README.md](patches/README.md). ## Why "it boots" is not enough Wrong DRAM geometry does not fail at boot. It fails as address aliasing under memory pressure — silent corruption, hours later, in whatever the board happens to be running. A 3.5 GiB box that has mostly been idle is exactly the case where that would not have been noticed yet. There is also a hint in the vendor boot0 output already captured in [logs/uboot-interrupt.log](logs/uboot-interrupt.log): ``` Warn:CH0 BYTE0 LCDLR2 different Warn:CH0 BYTE3 LCDLR2 different ``` ## Change ``` CONFIG_CMD_MEMTEST=y CONFIG_SYS_ALT_MEMTEST=y ``` `mtest` at the U-Boot prompt walks the full range with no OS in the way — the cheapest possible check, and the right place for it since the claim being tested is a bootloader-level one. ## Also worth running `memtester` from Linux userspace over a large allocation, as a second opinion under real conditions (cache, DVFS, thermals). The two are complementary: `mtest` covers the full range, `memtester` covers realistic access patterns. ## Acceptance - A full-range `mtest` pass across all 3.5 GiB, clean. - Result recorded in [22-dram-4gb.md](22-dram-4gb.md), so the upstream patch can state what was actually verified rather than implying it. Blocks: sending `uboot-sun9i-dram` upstream.
Author
Owner

More useful than when this was filed, 2026-08-28. A whole day went into #53, a
memory-corruption bug, and one of the things that made it slow was having no way to exercise
DRAM outside Linux. CMD_MEMTEST would have given a check that runs before any of the
scheduler, cache or cluster complexity exists.

It would also have settled the DRAM question directly. CONFIG_DRAM_CLK was changed 672 -> 600
and CONFIG_DRAM_ZQ to this board's own value, and neither moved the failure rate at all -
but that took a kernel-side test each time, with a bootloader flash and a reboot per data
point. A U-Boot memtest is the right instrument for that and it is a config symbol.

Note the DRAM geometry validation part of this issue is now more interesting too: the settings
in use are this board's own (dram_clk = 600, dram_zq = 0x3b3bbb) rather than the A80
Optimus values inherited before, so anything measured now measures the intended configuration.

**More useful than when this was filed, 2026-08-28.** A whole day went into #53, a memory-corruption bug, and one of the things that made it slow was having no way to exercise DRAM outside Linux. `CMD_MEMTEST` would have given a check that runs before any of the scheduler, cache or cluster complexity exists. It would also have settled the DRAM question directly. `CONFIG_DRAM_CLK` was changed 672 -> 600 and `CONFIG_DRAM_ZQ` to this board's own value, and neither moved the failure rate at all - but that took a kernel-side test each time, with a bootloader flash and a reboot per data point. A U-Boot memtest is the right instrument for that and it is a config symbol. Note the DRAM geometry validation part of this issue is now more interesting too: the settings in use are this board's own (`dram_clk = 600`, `dram_zq = 0x3b3bbb`) rather than the A80 Optimus values inherited before, so anything measured now measures the intended configuration.
Author
Owner

Done 2026-08-29. Both acceptance criteria met; recorded in 22-dram-4gb.md.

The geometry, stated by the bootloader

bdinfo, with no OS in the way:

memory[0]	[0x20000000-0xffffffff], 0xe0000000 bytes, flags: none
reserved[1]	[0xfaf63e50-0xffffffff], 0x509c1b0 bytes

One bank, 0xe0000000 = 3584 MiB. That is what the uboot-sun9i-dram patch claims, now
asserted by U-Boot itself rather than inferred from what Linux later reports.

Full-range mtest, clean

=> mtest 0x20000000 0xfaf5c000 0 1
Testing 20000000 ... faf5c000:
Iteration:      1
Tested 1 iteration(s) with 0 errors.

3503 MiB, zero errors, with SYS_ALT_MEMTEST and SYS_ALT_MEMTEST_BITFLIP so it includes
the address-line walk - the part that actually catches aliasing.

One run, deliberately. Chunking it would have been worthless: the address-line walk covers
the range it is given, so an alias between two chunks is invisible if they are tested
separately, and aliasing is the whole failure mode this issue is about.

⚠️ Stop the watchdogs first

The first attempt reset the board ~45 minutes in - no error line, no Tested line, no
pstore record, just an SPL banner. That was our own watchdog from #34. The mechanism is
in cmd/mem.c:

for (j = 0; j < 8; j++) {
	schedule();				/* the only servicing point */
	for (i = 0; i < count; i++)		/* writes the whole region */
		*p1++ = *p2++ = (i % 2) == 0 ? q : ~q;
	errs += compare_regions(bufa, bufb, count);   /* reads it again */
}

compare_regions() has no schedule() at all, so one pass over a large region blows through
the 16 s timeout. At 256 MiB it stays under; at 3503 MiB it does not. CONFIG_CMD_WDT, from
the same series, is what lets you stop them:

=> wdt dev watchdog@6000ca0; wdt stop
=> wdt dev watchdog@8001000; wdt stop

Probably worth reporting upstream - a command that runs for minutes without servicing the
watchdog - but it is our config that exposes it. Also setenv bootretry -1 first, or #35
boots the board out from under the session; it fired the instant the test finished.

Measured, not assumed

  • The watchdog does not affect throughput. 256 MiB took 360 s armed and 360 s stopped, so
    the first failure was a reset, not a slowdown.
  • Runtime is not linear in range. 13.7x the data took 2.2x the time. The 82-minute figure
    extrapolated from the small run was wrong; nothing depends on it, but do not plan against it.

Not covered

The range stops at 0xfaf5c000 because U-Boot reserves everything above for itself, so the
top 81 MiB is untested
. That needs the Linux-side memtester second opinion this issue also
suggests, and memtester is not installed on the board. Raising it as its own item rather
than holding this open, since the bootloader-level claim - the one that blocked
uboot-sun9i-dram - is now verified.

Unblocks: sending uboot-sun9i-dram upstream, which can now say what was actually tested.

**Done 2026-08-29.** Both acceptance criteria met; recorded in `22-dram-4gb.md`. ## The geometry, stated by the bootloader `bdinfo`, with no OS in the way: ``` memory[0] [0x20000000-0xffffffff], 0xe0000000 bytes, flags: none reserved[1] [0xfaf63e50-0xffffffff], 0x509c1b0 bytes ``` One bank, `0xe0000000` = 3584 MiB. That is what the `uboot-sun9i-dram` patch claims, now asserted by U-Boot itself rather than inferred from what Linux later reports. ## Full-range mtest, clean ``` => mtest 0x20000000 0xfaf5c000 0 1 Testing 20000000 ... faf5c000: Iteration: 1 Tested 1 iteration(s) with 0 errors. ``` **3503 MiB, zero errors**, with `SYS_ALT_MEMTEST` and `SYS_ALT_MEMTEST_BITFLIP` so it includes the address-line walk - the part that actually catches aliasing. **One run, deliberately.** Chunking it would have been worthless: the address-line walk covers the range it is given, so an alias between two chunks is invisible if they are tested separately, and aliasing is the whole failure mode this issue is about. ## ⚠️ Stop the watchdogs first The first attempt reset the board ~45 minutes in - no error line, no `Tested` line, no `pstore` record, just an SPL banner. That was **our own watchdog** from #34. The mechanism is in `cmd/mem.c`: ```c for (j = 0; j < 8; j++) { schedule(); /* the only servicing point */ for (i = 0; i < count; i++) /* writes the whole region */ *p1++ = *p2++ = (i % 2) == 0 ? q : ~q; errs += compare_regions(bufa, bufb, count); /* reads it again */ } ``` `compare_regions()` has no `schedule()` at all, so one pass over a large region blows through the 16 s timeout. At 256 MiB it stays under; at 3503 MiB it does not. `CONFIG_CMD_WDT`, from the same series, is what lets you stop them: ``` => wdt dev watchdog@6000ca0; wdt stop => wdt dev watchdog@8001000; wdt stop ``` Probably worth reporting upstream - a command that runs for minutes without servicing the watchdog - but it is our config that exposes it. Also `setenv bootretry -1` first, or #35 boots the board out from under the session; it fired the instant the test finished. ## Measured, not assumed - **The watchdog does not affect throughput.** 256 MiB took 360 s armed and 360 s stopped, so the first failure was a reset, not a slowdown. - **Runtime is not linear in range.** 13.7x the data took 2.2x the time. The 82-minute figure extrapolated from the small run was wrong; nothing depends on it, but do not plan against it. ## Not covered The range stops at `0xfaf5c000` because U-Boot reserves everything above for itself, so **the top 81 MiB is untested**. That needs the Linux-side `memtester` second opinion this issue also suggests, and `memtester` is not installed on the board. Raising it as its own item rather than holding this open, since the bootloader-level claim - the one that blocked `uboot-sun9i-dram` - is now verified. Unblocks: sending `uboot-sun9i-dram` upstream, which can now say what was actually tested.
Sign in to join this conversation.
No description provided.