Re: pci regression: "panic: resource_list_alloc: resource entry is busy"

From: John Baldwin <jhb_at_freebsd.org>
Date: Wed, 4 Mar 2009 10:34:06 -0500
On Wednesday 04 March 2009 10:11:24 am John Baldwin wrote:
> On Tuesday 03 March 2009 9:03:24 pm Michael Butler wrote:
> > Post SVN rev 189306 on my Toshiba laptop, I get a bootstrap panic as
> > follows:
> > 
> > vgapci0: <VGA-compatible display> port 0x1800-0x1807
> > 	mem 0xf0a00000-0xf0a7ffff,0xd0000000-0xdfffffff,
> > 	0xf0b00000-0xf0b3ffff
> > 	irq 16 at device 2.0 on pci0
> > acpi_video0: <ACPI video extension> on vgapci0
> > 	found VGA CRT or VESA Compatible Analog Monitor(100), idx#0,
> > 	port#0, detectable by BIOS, head #0
> > 	found TV/HDTV or Analog-Video Monitor(200), idx#0,
> > 	port#0, detectable by BIOS, head #0
> > 	found Internal/Integrated Digital Flat Panel(400), idx#0,
> > 	port#0, detectable by BIOS, head #0
> > agp0: <Intel 82945GM (945GM GMCH) SVGA controller> on vgapci0
> > vgapci0: Reserved 0x10000000 bytes for rid 0x18 type 3 at 0xd0000000
> > vgapci0: Reserved 0x80000 bytes for rid 0x10 type 3 at 0xf0a00000
> > vgapci0: Reserved 0x40000 bytes for rid 0x1c type 3 at 0xf0b00000
> > agp0: detected 7932k stolen memory
> > agp0: aperture size is 256M
> > drm0: <Intel i945GM> on vgapci0
> > 
> > <<< fails here with "panic: resource_list_alloc: resource entry is busy"
> > 
> > vgapci0: Reserved 0x80000 bytes for rid 0x10 type 3 at 0xf0a00000
> > vgapci0: child drm0 requested pci_enable_busmaster
> > info: [drm] AGP at 0xd0000000 256MB
> > info: [drm] Initialized i915 1.6.0 20080730
> > vgapci1: <VGA-compatible display> mem 0xf0a80000-0xf0afffff at
> > 	device 2.1 on pci0
> > 
> > Presumably, the agp/drm interaction with vgapci resources prompts this :-(
> 
> Hmmm, so the issue is that agp0 and drm0 are both allocating the same BAR.  I 
> can probably make this work with some patches to vgapci to have it proxy the 
> requests and share the resources.

Probably at some point the agp and drm drivers for Intel will be merged which
would fix this, but this patch should help for now.  We used to be leaking
a small portion of KVA due to this problem before.

--- //depot/vendor/freebsd/src/sys/dev/pci/vga_pci.c	2008/09/19 19:15:30
+++ //depot/user/jhb/acpipci/dev/pci/vga_pci.c	2009/03/04 15:32:08
_at__at_ -42,12 +42,20 _at__at_
 #include <sys/bus.h>
 #include <sys/kernel.h>
 #include <sys/module.h>
+#include <sys/rman.h>
+#include <sys/systm.h>
 
 #include <dev/pci/pcireg.h>
 #include <dev/pci/pcivar.h>
 
+struct vga_resource {
+	struct resource	*vr_res;
+	int	vr_refs;
+};
+
 struct vga_pci_softc {
 	device_t	vga_msi_child;	/* Child driver using MSI. */
+	struct vga_resource vga_res[PCIR_MAX_BAR_0 + 1];
 };
 
 static int
_at__at_ -130,7 +138,27 _at__at_
 vga_pci_alloc_resource(device_t dev, device_t child, int type, int *rid,
     u_long start, u_long end, u_long count, u_int flags)
 {
+	struct vga_pci_softc *sc;
+	int bar;
 
+	switch (type) {
+	case SYS_RES_MEMORY:
+	case SYS_RES_IOPORT:
+		/*
+		 * For BARs, we cache the resource so that we only allocate it
+		 * from the PCI bus once.
+		 */
+		bar = PCI_RID2BAR(*rid);
+		if (bar < 0 || bar > PCIR_MAX_BAR_0)
+			return (NULL);
+		sc = device_get_softc(dev);
+		if (sc->vga_res[bar].vr_res == NULL)
+			sc->vga_res[bar].vr_res = bus_alloc_resource(dev, type,
+			    rid, start, end, count, flags);
+		if (sc->vga_res[bar].vr_res != NULL)
+			sc->vga_res[bar].vr_refs++;
+		return (sc->vga_res[bar].vr_res);
+	}
 	return (bus_alloc_resource(dev, type, rid, start, end, count, flags));
 }
 
_at__at_ -138,6 +166,37 _at__at_
 vga_pci_release_resource(device_t dev, device_t child, int type, int rid,
     struct resource *r)
 {
+	struct vga_pci_softc *sc;
+	int bar, error;
+
+	switch (type) {
+	case SYS_RES_MEMORY:
+	case SYS_RES_IOPORT:
+		/*
+		 * For BARs, we release the resource from the PCI bus
+		 * when the last child reference goes away.
+		 */
+		bar = PCI_RID2BAR(rid);
+		if (bar < 0 || bar > PCIR_MAX_BAR_0)
+			return (EINVAL);
+		sc = device_get_softc(dev);
+		if (sc->vga_res[bar].vr_res == NULL)
+			return (EINVAL);
+		KASSERT(sc->vga_res[bar].vr_res == r,
+		    ("vga_pci resource mismatch"));
+		if (sc->vga_res[bar].vr_refs > 1) {
+			sc->vga_res[bar].vr_refs--;
+			return (0);
+		}
+		KASSERT(sc->vga_res[bar].vr_refs > 0,
+		    ("vga_pci resource reference count underflow"));
+		error = bus_release_resource(dev, type, rid, r);
+		if (error == 0) {
+			sc->vga_res[bar].vr_res = NULL;
+			sc->vga_res[bar].vr_refs = 0;
+		}
+		return (error);
+	}
 
 	return (bus_release_resource(dev, type, rid, r));
 }

-- 
John Baldwin
Received on Wed Mar 04 2009 - 14:34:17 UTC

This archive was generated by hypermail 2.4.0 : Wed May 19 2021 - 11:39:43 UTC