diff --git a/sys/dev/pci/vga_pci.c b/sys/dev/pci/vga_pci.c index d7ff20f..c64037f 100644 --- a/sys/dev/pci/vga_pci.c +++ b/sys/dev/pci/vga_pci.c @@ -81,16 +81,58 @@ SYSCTL_INT(_hw_pci, OID_AUTO, default_vgapci_unit, CTLFLAG_RDTUN, int vga_pci_is_boot_display(device_t dev) { + int unit; + device_t pcib; + uint16_t config; + + /* Check that the given device is a video card */ + if ((pci_get_class(dev) != PCIC_DISPLAY && + (pci_get_class(dev) != PCIC_OLD || + pci_get_subclass(dev) != PCIS_OLD_VGA))) + return (0); + + unit = device_get_unit(dev); + + if (vga_pci_default_unit >= 0) { + /* + * The boot display device was determined by a previous + * call to this function, or the user forced it using + * the hw.pci.default_vgapci_unit tunable. + */ + return (vga_pci_default_unit == unit); + } /* - * Return true if the given device is the default display used - * at boot time. + * The primary video card used as a boot display must have the + * "I/O" and "Memory Address Space Decoding" bits set in its + * Command register. + * + * Furthermore, if the card is attached to a bridge, instead of + * the root PCI bus, the bridge must have the "VGA Enable" bit + * set in its Control register. */ - return ( - (pci_get_class(dev) == PCIC_DISPLAY || - (pci_get_class(dev) == PCIC_OLD && - pci_get_subclass(dev) == PCIS_OLD_VGA)) && - device_get_unit(dev) == vga_pci_default_unit); + + pcib = device_get_parent(device_get_parent(dev)); + if (device_get_devclass(device_get_parent(pcib)) == + devclass_find("pci")) { + /* + * The parent bridge is a PCI-to-PCI bridge: check the + * value of the "VGA Enable" bit. + */ + config = pci_read_config(pcib, PCIR_BRIDGECTL_1, 2); + if ((config & PCIB_BCR_VGA_ENABLE) == 0) + return (0); + } + + config = pci_read_config(dev, PCIR_COMMAND, 2); + if ((config & (PCIM_CMD_PORTEN | PCIM_CMD_MEMEN)) == 0) + return (0); + + /* This video card is the boot display: record its unit number. */ + vga_pci_default_unit = unit; + device_set_flags(dev, 1); + + return (1); } void * @@ -159,9 +201,6 @@ vga_pci_unmap_bios(device_t dev, void *bios) static int vga_pci_probe(device_t dev) { - device_t bdev; - int unit; - uint16_t bctl; switch (pci_get_class(dev)) { case PCIC_DISPLAY: @@ -175,13 +214,7 @@ vga_pci_probe(device_t dev) } /* Probe default display. */ - unit = device_get_unit(dev); - bdev = device_get_parent(device_get_parent(dev)); - bctl = pci_read_config(bdev, PCIR_BRIDGECTL_1, 2); - if (vga_pci_default_unit < 0 && (bctl & PCIB_BCR_VGA_ENABLE) != 0) - vga_pci_default_unit = unit; - if (vga_pci_default_unit == unit) - device_set_flags(dev, 1); + vga_pci_is_boot_display(dev); device_set_desc(dev, "VGA-compatible display"); return (BUS_PROBE_GENERIC); @@ -197,6 +230,10 @@ vga_pci_attach(device_t dev) device_add_child(dev, "drm", -1); device_add_child(dev, "drmn", -1); bus_generic_attach(dev); + + if (vga_pci_is_boot_display(dev)) + device_printf(dev, "Boot video device\n"); + return (0); }