Skip to main content

Module delay

Module delay 

Source
Expand description

Holding still for a set time, waiting for nothing.

§Why this exists

Some hardware needs a gap that no register reports: let a reset bit land before the next write, give a port the recovery time a specification demands before it is addressed. Nothing can be read to say the gap is over, so this is not a wait - there is no condition, only a duration. Drivers wrote it by hand, and the copies disagreed about the one case that matters, a machine whose clock the kernel could not calibrate:

  • genet’s delay_us yielded once, which returns at once when nothing else is runnable;
  • xhci’s two holds built their length from duration_cycles, which floors to one counter tick there, so they held for nothing at all.

Both are the same mistake in the direction that matters. A hold is a MINIMUM: the device needs at least this long, and the safe error is too long, never too short.

§What it does

ⓘ
use godspeed::driver::delay;
use godspeed::driver::wait::Budget;

m.write32(CMD, SW_RESET);
delay::hold(ctx, Budget::us(10)); // the reset bit needs time to land; nothing says when it has
m.write32(CMD, 0);

On a calibrated machine hold spins for the duration, measured by the counter. It does not sleep: on every port but ARMv7 (whose sub-tick sleep is not relied on here) the kernel’s sleep floors at a scheduler quantum, nominally 10 ms (CLAUDE.md 9.1), which would turn a 10 us hold into a thousand times that. hold_parked sleeps first and spins out the rest, for holds of tens of milliseconds where the core matters more than the microsecond: it can run up to a quantum long, which a minimum allows, and is never short. It has three callers (ehci, wifi-usb’s rtl8188 backend, and sdk/audio’s settings read, pausing between retries), and it is in on probation: docs/driver-library.md 1l says why.

On an uncalibrated one both sleep whole quanta, as many as the duration needs at the nominal 10 ms: the quantum is measured by the kernel’s tick rather than the counter nobody could calibrate, so it is the one duration left, and it errs long. super::wait::calibrated says which case this machine is in.

It does not log, for the reason wait does not: it cannot fail.

Functions§

hold
Hold for at least d. Spins on a calibrated machine; sleeps whole scheduler quanta on one that is not. See the module documentation.
hold_parked
Hold for at least d, PARKED: sleep through it, then spin out whatever the sleep left. For holds of tens of milliseconds - a USB reset, a debounce - where the core matters more than waking on the microsecond.