serial: skip 8250 ports the firmware advertises but does not populate - #8
serial: skip 8250 ports the firmware advertises but does not populate#8europaul wants to merge 2 commits into
Conversation
readUintHex compared the raw attribute text against "0" before stripping the "0x" prefix the kernel emits, so the string "0x0" slipped past the guard, parsed as a valid base address and was reported as usable. An 8250 port the firmware advertises but the board does not populate has neither an I/O base nor a mapped address, and its port attribute reads back exactly that value. Every such port therefore ended up carrying a fabricated 0000-0007 I/O range, computed as 0 through 0+7. Strip the prefix first and reject a zero value after parsing, which also covers the other spellings of zero the guard used to miss. Signed-off-by: Paul Gaiduk <paulg@zededa.com>
A tty was accepted as a serial port whenever /sys/class/tty/<tty>/device existed. The kernel creates that symlink for every 8250 port the firmware advertises, populated or not, so a machine whose firmware advertises 32 ports while wiring up 4 reported all 32. Filter on the value of the "port" attribute instead. The serial core exposes it for every uart_port it manages, and an unpopulated port reads back zero because it has no I/O base and no mapped address. Absence of the attribute has to keep meaning something different. A UART behind a USB-to-serial converter is driven by usbserial rather than the serial core and exposes neither "port" nor "irq"; those ports are real and were already reported correctly. So the discriminator is the attribute being present and zero, not merely a zero value. Neither "type" nor "io_type" can stand in here - a populated ttyS1 at 0x2f8 reports type 0 just as an unpopulated port does. Add table-driven cases over synthetic sysfs trees covering a populated 8250, an unpopulated one, a USB-attached UART with a USB device ancestor, and a virtual tty with no device symlink. The attribute sets are taken from a 6.12 kernel. One case pins the COM numbering closing up over the skipped ports rather than leaving gaps, which is the intended result. Signed-off-by: Paul Gaiduk <paulg@zededa.com>
|
@christoph-zededa do you think such a change would make sense? or is it better to keep all the unpopulated serial devices like the kernel does? |
lgtm, but perhaps you do the PR directly upstream? |
|
@christoph-zededa now I think it's probably not such a good idea if ghw shows less devices than the kernel in |
I don't think it is a problem if ghw shows less devices than in
You're right, I see, they do: in zedcloud. This might have consequences when updating eve vs. directly installing the new version of eve on the same hardware model ... |
Problem
Hardware inventory reported serial ports that do not exist. On an x86 machine whose firmware advertises 32 8250 ports but populates only 4, all 32 were listed, and each of the 28 unpopulated ones carried a fabricated
"ioport_range": "0000-0007".Two independent defects in
pkg/serial/serial_linux.gocombined to produce that:serialPortFromTTY()treated a tty as a serial port whenever/sys/class/tty/<tty>/deviceexisted. The kernel creates that symlink for every 8250 port the firmware advertises, populated or not, so unpopulated ports passed the check just like real ones.readUintHex()compared the raw attribute text against"0"before stripping the0xprefix, so"0x0"slipped past the guard and parsed as a valid base address. The I/O range was then computed as0 .. 0+7, which is where0000-0007came from.Fix
Reject a zero value in
readUintHex()by stripping the prefix first, and filter on the value of theportattribute inserialPortFromTTY(). The serial core exposesportfor everyuart_portit manages, and an unpopulated port reads back zero because it has neither an I/O base nor a mapped address.The subtlety is that absence of the attribute has to keep meaning something different. A UART behind a USB-to-serial converter (
ttyUSB*,ttyACM*) is driven by usbserial rather than the serial core and exposes noportand noirqat all — those ports are real and were already handled correctly. A blanket "require a non-zero port" would have silently dropped every USB-attached serial port. So the discriminator is the attribute being present and zero, not merely reading as zero.typeandio_typelook like they could serve here and cannot: a populatedttyS1atport=0x2F8reportstype=0, exactly like an unpopulated port.Attribute sets observed on a 6.12 kernel:
ttyUSB0(FTDI converter)dev device power subsystem ueventttyS0(populated 8250)... irq port io_type type line ...port=0x3F8 irq=4ttyS4(advertised, unpopulated)ttyS0port=0x0 irq=0Tests
TestSerialUnpopulatedPortsis table-driven over synthetic sysfs trees built undert.TempDir()and read throughNew(option.WithChroot(root)), following the existingTestSerialPCIParentBehindBridgepattern — no root privileges or real hardware needed. It covers a populated 8250, an unpopulated one (port=0x0), a USB UART with a USB device ancestor, and virtual ttys with nodevicesymlink.The USB case passes both before and after this change; it is there as a regression guard for the constraint above.
Note on COM numbering
COM%dnames renumber once the phantoms are dropped, since the counter only advances for ports that are actually reported. A tree ofttyS0, ttyS1, [3 unpopulated], ttyS5, ttyUSB0now yieldsCOM1..COM4with no gaps, and one table case pins that. This is the intended outcome rather than a regression, but it is a visible change for any consumer that keyed on the old numbering.Generated by Claude Code