Page MenuHomeFreeBSD

uart(4): Add a concept of "unique" serial devices

Authored by cperciva on Mar 29 2022, 7:58 AM.
Referenced Files
Unknown Object (File)
Dec 15 2022, 5:56 PM
Unknown Object (File)
Dec 14 2022, 9:34 PM
Unknown Object (File)
Dec 14 2022, 6:58 PM



FreeBSD detects serial ports twice: First, very early in the boot
process, in order to obtain a usable console; and second, during
the device probe/attach process. When a UART is discovered during
device probing, FreeBSD attempts to determine whether it is a
device which was already being used as a console; without this,
the console doesn't work in userland.

Unfortunately it's possible for a UART to be mapped to a different
location in memory when it is discovered on a bus than it has when
it is announced via the ACPI SPCR table; this breaks the matching
process, which relies on comparing bus addresses.

To address this, we introduce a concept of "unique" serial devices,
i.e. devices which are guaranteed to be present *only once* on any
system. If we discover one of these during device probing, we can
match it to a same-PCI-vendor-and-device-numbers console which was
announced via the ACPI SPCR table, regardless of the differing bus

At present, the only unique serial device is the "Amazon PCI serial
device" (vendor 0x1d0f, device 0x8250) found in some EC2 instances.
This unbreaks the serial console on those systems.

Diff Detail

rG FreeBSD src repository
Lint Not Applicable
Tests Not Applicable

Event Timeline

cperciva created this revision.

Third try. It's a bit hacky, but in discussions with EC2 folks it sounds like this is the best way to identify that the UART we discovered is the console we configured from SPCR.


We usually use #defines for these
Or at the very least a comment...
but do we even need a table?
Don't we have these ids from the ACPI tables?


I'd just use count rather than having a sentinel like this at the end.


I was matching the style of the pci_ns8250_ids table earlier, which simply lists vendor and device IDs as raw integers.

For setting up the console early in the kernel boot process, we get the IDs from the ACPI tables (that happens in the uart_cpu_acpi.c bits below). The bit here is to tell us that when we see the same PCI vendor/device pair during PCI bus probing, it's guaranteed to be the same device. (Unlike, say, a 0x1028 / 0x0008 UART, which might conceivably be one of multiple Dell Remote Access Card IIIs in a system.)


If I was writing this as entirely new code I would do that too. I wanted to match the style of the uart_pci_match code (which uses the same sentinel in its table).


Are the dell devices in the ACPI tables too? If not, then it doesn't matter...


at least use PCIV_INVALID then. But you wrote new code to look at the table, so there's no reason to have a sentinel.


Please use PCIV_INVALID here.


You don' t need valid. vendor == 0 is not legal either and will never happen. You can test to see if it's set at all.


I don't think you need valid here at all... The whole struct will be initialized to 0, which is never a valid vendor.

rpokala added inline comments.

... vendor and device IDs as raw integers.

Raw integers used for identification -- rather than for math -- are a tool of the devil.


Sure, but there's 76 lines of PCI vendors/devices already in this file. Maybe replacing all of those with #defines can be done later...


That bit is going away since I'm changing the code to eliminate the sentinel.


Got it. I wasn't sure if anything other than PCIV_INVALID was reserved.

Updated to add comments, use the table size instead of a sentinel,
and eliminate an unnecessary 'valid' flag.

OK. I'm happy enough with this. Go ahead and commit it when you are happy as well.

This revision is now accepted and ready to land.Mar 31 2022, 9:31 PM