diff options
| author | Colin Percival <cperciva@FreeBSD.org> | 2022-03-29 07:41:37 +0000 |
|---|---|---|
| committer | Colin Percival <cperciva@FreeBSD.org> | 2022-03-31 23:02:24 +0000 |
| commit | ad93649d230428561db983153c546b39336fa4f1 (patch) | |
| tree | 7eefc51f86adcfb5e9eb7a70bfa6b1f2c4ddd94d /sys/dev/uart | |
| parent | c0f846ff235296249271b1235ff6a52b7d23cefb (diff) | |
Diffstat (limited to 'sys/dev/uart')
| -rw-r--r-- | sys/dev/uart/uart_bus_pci.c | 51 | ||||
| -rw-r--r-- | sys/dev/uart/uart_cpu.h | 9 | ||||
| -rw-r--r-- | sys/dev/uart/uart_cpu_acpi.c | 7 |
3 files changed, 67 insertions, 0 deletions
diff --git a/sys/dev/uart/uart_bus_pci.c b/sys/dev/uart/uart_bus_pci.c index fe5ad2b6d206..a20be1c577d4 100644 --- a/sys/dev/uart/uart_bus_pci.c +++ b/sys/dev/uart/uart_bus_pci.c @@ -43,6 +43,7 @@ __FBSDID("$FreeBSD$"); #include <dev/uart/uart.h> #include <dev/uart/uart_bus.h> +#include <dev/uart/uart_cpu.h> #define DEFAULT_RCLK 1843200 @@ -76,6 +77,11 @@ struct pci_id { int regshft; }; +struct pci_unique_id { + uint16_t vendor; + uint16_t device; +}; + #define PCI_NO_MSI 0x40000000 #define PCI_RID_MASK 0x0000ffff @@ -214,6 +220,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) { @@ -251,6 +295,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 4f34c767efc0..4eb7327fc788 100644 --- a/sys/dev/uart/uart_cpu.h +++ b/sys/dev/uart/uart_cpu.h @@ -53,6 +53,14 @@ 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. */ struct uart_devinfo { @@ -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 1e46462fc58a..68f743c8e8d2 100644 --- a/sys/dev/uart/uart_cpu_acpi.c +++ b/sys/dev/uart/uart_cpu_acpi.c @@ -36,6 +36,8 @@ __FBSDID("$FreeBSD$"); #include <machine/bus.h> +#include <dev/pci/pcireg.h> + #include <dev/uart/uart.h> #include <dev/uart/uart_bus.h> #include <dev/uart/uart_cpu.h> @@ -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) == |
