net: an RTL8139 driver, and the e1000 stops refusing the PCIe parts

Two NICs, and unlike the RTL8111 last commit, QEMU emulates both -- so both
are tested rather than reasoned about.

**RTL8139** is its own driver and not a mode of the 8169, because it is its own
chip. No descriptor rings: the receiver is one circular buffer the chip writes
packets into back to back behind four-byte headers, and the transmitter is four
fixed slots. Putting both programming models behind one set of function
pointers is how a mode flag ends up threaded through every path.

Three details are the whole driver. CAPR runs sixteen bytes behind the true
read position -- a quirk of the part, not an off-by-one. WRAP means the chip
runs a packet past the end of the buffer rather than splitting it, so the 8 KB
buffer is allocated as 8 KB + 16 + one maximum frame; getting that wrong is a
chip writing past its allocation at line rate. And a length field of 0xFFF0
means "still writing this one", so treating it as a length copies a partial
packet and loses the alignment for everything after it.

**The e1000 now matches the PCIe 8257x parts.** Its header refused them, with
a note saying they "differ in NVM access and initialisation, and claiming a
device this driver has not been shown to initialise is worse than not claiming
it". That was right, and the second half is answerable: QEMU emulates the
82574L, so it can be *shown* to initialise.

What differs turned out to be one register. EERD moved its address field from
bits 8-15 to bits 2-15 and its done bit from 4 to 1; the rings, RCTL, TCTL and
ICR are identical. So there is a per-instance flag for the NVM layout and seven
more ids -- not a second copy of four hundred lines of ring code. The wrong
pair of constants fails silently, reading the wrong word or waiting for a bit
that never sets, and the MAC comes out as zeroes; that is why it is named in
the header rather than papered over.

Still refused: the ICH/PCH parts (82562, 82577-82579, I217-I219), which put the
PHY behind a MAC-PHY interconnect and need a different bring-up nothing here
can test.

Tested, each booted alone: rtl8139 (10ec:8139) and 82574L (8086:10d3) both bind,
read a real MAC, complete DHCP and ping 4 of 4 with no loss. The classic
82540EM does the same, which is the regression that mattered for the NVM
change. Both supported display configurations: one boot each, no traps, no
panics, socktest and memfdtest green.

Also recorded: the Chromebox CN62 carries an RTL8111, not an Intel part, so
last commit's driver covers it too.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
Nexoniarz 2026-09-24 15:30:38 +02:00
commit 0331d548c4
6 changed files with 530 additions and 8 deletions

View file

@ -29,6 +29,55 @@ that completes a handshake and drops every byte.
└────────────────────────────────────┘
```
## Intel e1000, and the PCIe generation it used to refuse
`drivers/net/e1000/` matched the 8254x parts and deliberately refused the PCIe
8257x, with a note saying they "differ in NVM access and initialisation, and
claiming a device this driver has not been shown to initialise is worse than
not claiming it".
That was right, and the second half of it is answerable: QEMU emulates the
**82574L**, so the part can be shown to initialise rather than assumed to. What
actually differs turned out to be **one register**. `EERD` moved its address
field from bits 8-15 to bits 2-15 and its done bit from 4 to 1; the descriptor
rings, `RCTL`, `TCTL` and the interrupt cause register are identical. So the
8257x ids are matched now, with a per-instance flag for the NVM layout — not a
second copy of four hundred lines of ring code.
Using the wrong pair of constants does not fail loudly, which is why it is
named rather than papered over: it reads the wrong word or waits for a bit that
will never be set, and the MAC comes out as zeroes.
Still refused: the ICH/PCH parts (82562, 82577-82579, I217-I219). Those put the
PHY behind a MAC-PHY interconnect and need a genuinely different bring-up, and
nothing here can test one.
## Realtek RTL8139 — `drivers/net/rtl8139/`
A separate driver from the RTL8111 next door, despite the neighbouring name,
because it is a different chip. The 8139 has **no descriptor rings**: the
receiver is one circular buffer the chip writes packets into back to back, each
behind a four-byte header, and the transmitter is four fixed slots used
round-robin. Sharing a driver with the 8169 would put two programming models
behind one set of function pointers, which is how a mode flag ends up threaded
through every path.
Three details that are the whole driver:
- **`CAPR` runs sixteen bytes behind.** The register that tells the chip how
far the driver has read is offset by 16 — a quirk of the part, not an
off-by-one, and the buffer is allocated with that padding in mind.
- **`WRAP` means the allocation is bigger than the buffer.** With it set the
chip runs a packet past the end rather than splitting it, so the 8 KB buffer
is allocated as 8 KB + 16 + one maximum frame. Getting that wrong is a chip
writing past the allocation at line rate.
- **A length of `0xFFF0` means "still writing"**, not a length. Copying on it
gives a partial packet *and* loses the alignment for everything after.
It is also the one Realtek part QEMU emulates, so unlike the 8169 every line of
it has run: DHCP completes and `ping` is 4 of 4.
## Realtek RTL8169/8168/8111 — `drivers/net/r8169/`
The NIC in a very large number of laptops and desktop boards. Every
@ -60,6 +109,13 @@ The register layout is a *fact about the hardware*, taken the way
[ldls.md](ldls.md) §3 says facts may be taken. The expression is this tree's:
a descriptor-ring driver in the same shape as the e1000 beside it.
### The Chromebox has one of these
The Asus Chromebox CN62 "Guado" turns out to carry an RTL8111 rather than the
Intel part its spec sheet suggests, so this driver covers it as well as the
laptop that prompted it — which is the argument for the family match in one
line rather than a device id per board.
### It has not run on hardware
**Stated plainly because it cannot be tested here.** QEMU emulates `rtl8139`