Skip to content

ns16550a: extract reusable uart16550_core#226

Open
SolAstrius wants to merge 2 commits into
LekKit:stagingfrom
pufit:refactor/uart16550-core
Open

ns16550a: extract reusable uart16550_core#226
SolAstrius wants to merge 2 commits into
LekKit:stagingfrom
pufit:refactor/uart16550-core

Conversation

@SolAstrius

Copy link
Copy Markdown
Contributor

Splits the 16550 register decode + state machine out of ns16550a.c into a standalone, backend-agnostic module, then rewrites ns16550a.c as a thin wrapper around it. Two commits: the extraction, then the rewrite.

uart16550_core

The bus wrapper (rvvm_reg MMIO/PIO for ns16550a, BAR-windowed multi-port for an Exar PCIe combo card, etc.) embeds a uart16550_core_t, drives byte-wide register access via uart16550_core_read/write, and supplies an IRQ callback so the core stays unaware of whether the line is wired via wired INTx, PCI INTx, or MSI.

The register handlers are otherwise identical to the in-tree ns16550a implementation: same DLAB banking, same IIR priority encoding, same LSR composition, same MSR=0xB0 stub. Pure extraction, plus two behaviours the historical ns16550a.c lacked:

  • RX-arm gate. Real silicon's RBR is empty after reset; pre-init RBR reads return floating-bus values the kernel discards as junk. Our chardev backend never resets, so bytes that arrived before the guest finishes startup would get eaten by serial8250_do_startup's two junk-drain RBR reads. The core suppresses chardev draining until the guest writes IER with the RECV bit (kernel signalling "ready to receive"); it flips true once and stays true until cleanup, so flow-control toggles don't silently re-enable the junk-drain path on the next port reopen.
  • Snapshot helper. uart16550_core_suspend() serializes/deserializes the core's seven register fields plus rx_armed via rvvm_snapshot_field; wrappers open the snapshot section themselves so multi-instance consumers (Exar) can name their per-port sections distinctly.

ns16550a rewrite

The MMIO device, IRQ wiring, FDT registration, and snapshot section are all that remain ns16550a-specific; this file now just translates between rvvm_reg_dev_t callbacks and uart16550_core_read/write/update/suspend. 281 LOC → 137 LOC. Public API unchanged — rvvm_ns16550a_init signature is identical, including the attr & RVVM_REG_ATTR_PIO toggle for 8-byte PIO vs 4 KiB MMIO.

Behaviour change worth noting

The RX-arm gate now applies on the canonical MMIO path too (previously it lived only in out-of-tree paths). The upside: Linux's startup junk-RBR-drain no longer eats the first character arriving on the serial console. The snapshot section keeps the serial-ns16550a name; old snapshots without rx_armed deserialize with rx_armed=0 (equivalent to "kernel hasn't enabled RX yet on this restored instance"), which the next IER write fixes immediately — a small, self-correcting forward-compat break for a field that wasn't in the prior format.

Signed-off-by: Sol Astrius <sol@astrius.ink>
Signed-off-by: Sol Astrius <sol@astrius.ink>
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