diff --git a/sys/dev/uart/uart_bus_pci.c b/sys/dev/uart/uart_bus_pci.c index 92046261f54..b7612cda9f5 100644 --- a/sys/dev/uart/uart_bus_pci.c +++ b/sys/dev/uart/uart_bus_pci.c @@ -42,6 +42,7 @@ __FBSDID("$FreeBSD$"); #include #include +#include #define DEFAULT_RCLK 1843200 @@ -75,6 +76,11 @@ struct pci_id { int regshft; }; +struct pci_unique_id { + uint16_t vendor; + uint16_t device; +}; + static const struct pci_id pci_ns8250_ids[] = { { 0x1028, 0x0008, 0xffff, 0, "Dell Remote Access Card III", 0x14, 128 * DEFAULT_RCLK }, @@ -209,6 +215,44 @@ uart_pci_match(device_t dev, const struct pci_id *id) return ((id->vendor == vendor && id->device == device) ? id : NULL); } +extern SLIST_HEAD(uart_devinfo_list, uart_devinfo) uart_sysdevs; + +/* PCI vendor/device pairs of devices guaranteed to be unique on a system. */ +static const struct pci_unique_id pci_unique_devices[] = { +{ 0x1d0f, 0x8250 } /* Amazon PCI serial device */ +}; + +/* Match a UART to a console if it's a PCI device known to be unique. */ +static void +uart_pci_unique_console_match(device_t dev) +{ + struct uart_softc *sc; + struct uart_devinfo * sysdev; + const struct pci_unique_id * id; + uint16_t vendor, device; + + sc = device_get_softc(dev); + vendor = pci_get_vendor(dev); + device = pci_get_device(dev); + + /* Is this a device known to exist only once in a system? */ + for (id = pci_unique_devices; ; id++) { + if (id == &pci_unique_devices[nitems(pci_unique_devices)]) + return; + if (id->vendor == vendor && id->device == device) + break; + } + + /* If it matches a console, it must be the same device. */ + SLIST_FOREACH(sysdev, &uart_sysdevs, next) { + if (sysdev->pci_info.vendor == vendor && + sysdev->pci_info.device == device) { + sc->sc_sysdev = sysdev; + sysdev->bas.rclk = sc->sc_bas.rclk; + } + } +} + static int uart_pci_probe(device_t dev) { @@ -231,6 +275,13 @@ uart_pci_probe(device_t dev) /* Bail out on error. */ if (result > 0) return (result); + /* + * If we haven't already matched this to a console, check if it's a + * PCI device which is known to only exist once in any given system + * and we can match it that way. + */ + if (sc->sc_sysdev == NULL) + uart_pci_unique_console_match(dev); /* Set/override the device description. */ if (id->desc) device_set_desc(dev, id->desc); diff --git a/sys/dev/uart/uart_cpu.h b/sys/dev/uart/uart_cpu.h index 4f34c767efc..4eb7327fc78 100644 --- a/sys/dev/uart/uart_cpu.h +++ b/sys/dev/uart/uart_cpu.h @@ -52,6 +52,14 @@ struct uart_ops { extern bus_space_tag_t uart_bus_space_io; extern bus_space_tag_t uart_bus_space_mem; +/* + * PCI ID used for matching "unique" devices to a console. + */ +struct uart_pci_info { + uint16_t vendor; + uint16_t device; +}; + /* * Console and debug port device info. */ @@ -72,6 +80,7 @@ struct uart_devinfo { void *cookie; /* Type dependent use. */ struct mtx *hwmtx; struct uart_softc *sc; /* valid only from start of attach */ + struct uart_pci_info pci_info; }; int uart_cpu_eqres(struct uart_bas *, struct uart_bas *); diff --git a/sys/dev/uart/uart_cpu_acpi.c b/sys/dev/uart/uart_cpu_acpi.c index 1e46462fc58..68f743c8e8d 100644 --- a/sys/dev/uart/uart_cpu_acpi.c +++ b/sys/dev/uart/uart_cpu_acpi.c @@ -36,6 +36,8 @@ __FBSDID("$FreeBSD$"); #include +#include + #include #include #include @@ -182,6 +184,11 @@ uart_cpu_acpi_spcr(int devtype, struct uart_devinfo *di) (int)spcr->BaudRate); goto out; } + if (spcr->PciVendorId != PCIV_INVALID && + spcr->PciDeviceId != PCIV_INVALID) { + di->pci_info.vendor = spcr->PciVendorId; + di->pci_info.device = spcr->PciDeviceId; + } /* Apply device tweaks. */ if ((cd->cd_quirks & UART_F_IGNORE_SPCR_REGSHFT) ==