svn commit: r259679 - head/sys/dev/pci

Jean-Sebastien Pedron dumbbell at FreeBSD.org
Sat Dec 21 12:55:43 UTC 2013


Author: dumbbell
Date: Sat Dec 21 12:55:42 2013
New Revision: 259679
URL: http://svnweb.freebsd.org/changeset/base/259679

Log:
  vga_pci: Improve boot display detection
  
  The previous code was checking the "VGA Enable" bit on the video card's
  parent PCI-to-PCI bridge only. This didn't work for the case where the
  video card is attached to the root PCI bus (ie. the card has no parent
  PCI-to-PCI bridge).
  
  Now, the new code:
      1. checks the "VGA Enable" bit on the parent bridge only if it's a
         PCI-to-PCI bridge;
      2. always checks the "I/O" and "Memory address space decoding" bits
         on the video card itself.
  
  However, vendor-specific bits are not used.
  
  This fixes the use of many integrated Radeon cards: without this patch,
  we fail to detect them as the boot display and, when radeonkms looks for
  the Video BIOS, it skips the shadow copy made by the System BIOS. It
  then fails to fully initialize the card, because the shadow copy is the
  only way to read the Video BIOS in these situations. A workaround was to
  force the boot display selection using the "hw.pci.default_vgapci_unit"
  tunable.
  
  A previous version of this patch added a new function doing the checks.
  Now, the vga_pci_is_boot_display() function is used to perform the
  checks (only until the boot display is found) and return if the given
  device is the boot display or not.
  
  Furthermore, vga_pci_attach() logs "Boot video device" if the card being
  attached it the Chosen One:
      vgapci0: <VGA-compatible display> [...]
      vgapci0: Boot video device
  
  Reviewed by:	kib@, jhb@ (both a previous version)
  Tested by:	lunatic_ (#freebsd-xorg, integrated Radeon card,
  		xmj (#freebsd-xorg, i915+NVIDIA cards)

Modified:
  head/sys/dev/pci/vga_pci.c

Modified: head/sys/dev/pci/vga_pci.c
==============================================================================
--- head/sys/dev/pci/vga_pci.c	Sat Dec 21 12:45:35 2013	(r259678)
+++ head/sys/dev/pci/vga_pci.c	Sat Dec 21 12:55:42 2013	(r259679)
@@ -81,16 +81,58 @@ SYSCTL_INT(_hw_pci, OID_AUTO, default_vg
 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 *b
 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);
 }
 


More information about the svn-src-head mailing list