Index: src/sys/dev/pci/vga_pci.c =================================================================== RCS file: /home/ncvs/src/sys/dev/pci/vga_pci.c,v retrieving revision 1.5 diff -u -r1.5 vga_pci.c --- src/sys/dev/pci/vga_pci.c 1 Feb 2006 15:45:29 -0000 1.5 +++ src/sys/dev/pci/vga_pci.c 5 May 2009 13:39:01 -0000 @@ -42,10 +42,21 @@ #include #include #include +#include +#include #include #include +struct vga_resource { + struct resource *vr_res; + int vr_refs; +}; + +struct vga_pci_softc { + struct vga_resource vga_res[PCIR_MAX_BAR_0 + 1]; +}; + static int vga_pci_probe(device_t dev) { @@ -110,7 +121,27 @@ 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)); } @@ -118,6 +149,37 @@ 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)); } @@ -247,7 +309,7 @@ static driver_t vga_pci_driver = { "vgapci", vga_pci_methods, - 1, + sizeof(struct vga_pci_softc), }; static devclass_t vga_devclass;