aboutsummaryrefslogtreecommitdiff
path: root/sys/dev/uart
diff options
context:
space:
mode:
authorColin Percival <cperciva@FreeBSD.org>2022-03-29 07:41:37 +0000
committerColin Percival <cperciva@FreeBSD.org>2022-03-31 23:02:24 +0000
commitad93649d230428561db983153c546b39336fa4f1 (patch)
tree7eefc51f86adcfb5e9eb7a70bfa6b1f2c4ddd94d /sys/dev/uart
parentc0f846ff235296249271b1235ff6a52b7d23cefb (diff)
Diffstat (limited to 'sys/dev/uart')
-rw-r--r--sys/dev/uart/uart_bus_pci.c51
-rw-r--r--sys/dev/uart/uart_cpu.h9
-rw-r--r--sys/dev/uart/uart_cpu_acpi.c7
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) ==