summaryrefslogtreecommitdiffstats
path: root/sys/dev/pci
diff options
context:
space:
mode:
authorjhb <jhb@FreeBSD.org>2013-04-09 19:36:34 +0000
committerjhb <jhb@FreeBSD.org>2013-04-09 19:36:34 +0000
commit20fe0ed0a2a5bd81e9d7828cbefa56e1576a5033 (patch)
tree2041c9a64edb1dabff2415eb73b7c4b9bfe54e55 /sys/dev/pci
parent4eacc6be7b9d078e160e4c2fb1f13d33849eba65 (diff)
downloadFreeBSD-src-20fe0ed0a2a5bd81e9d7828cbefa56e1576a5033.zip
FreeBSD-src-20fe0ed0a2a5bd81e9d7828cbefa56e1576a5033.tar.gz
Proxy allocation requests for the PCI ROM BAR from child devices similar
to how the VGA bus driver currently proxies allocation requests for other PCI BARs. MFC after: 1 week
Diffstat (limited to 'sys/dev/pci')
-rw-r--r--sys/dev/pci/vga_pci.c60
1 files changed, 35 insertions, 25 deletions
diff --git a/sys/dev/pci/vga_pci.c b/sys/dev/pci/vga_pci.c
index 6d796c8..e52d5d8 100644
--- a/sys/dev/pci/vga_pci.c
+++ b/sys/dev/pci/vga_pci.c
@@ -56,7 +56,8 @@ struct vga_resource {
struct vga_pci_softc {
device_t vga_msi_child; /* Child driver using MSI. */
- struct vga_resource vga_res[PCIR_MAX_BAR_0 + 1];
+ struct vga_resource vga_bars[PCIR_MAX_BAR_0 + 1];
+ struct vga_resource vga_bios;
};
SYSCTL_DECL(_hw_pci);
@@ -156,12 +157,24 @@ vga_pci_teardown_intr(device_t dev, device_t child, struct resource *irq,
return (BUS_TEARDOWN_INTR(device_get_parent(dev), dev, irq, cookie));
}
+static struct vga_resource *
+lookup_res(struct vga_pci_softc *sc, int rid)
+{
+ int bar;
+
+ if (rid == PCIR_BIOS)
+ return (&sc->vga_bios);
+ bar = PCI_RID2BAR(rid);
+ if (bar >= 0 && bar <= PCIR_MAX_BAR_0)
+ return (&sc->vga_bars[bar]);
+ return (NULL);
+}
+
static struct resource *
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;
+ struct vga_resource *vr;
switch (type) {
case SYS_RES_MEMORY:
@@ -170,16 +183,15 @@ vga_pci_alloc_resource(device_t dev, device_t child, int type, int *rid,
* 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)
+ vr = lookup_res(device_get_softc(dev), *rid);
+ if (vr == NULL)
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);
+ if (vr->vr_res == NULL)
+ vr->vr_res = bus_alloc_resource(dev, type, rid, start,
+ end, count, flags);
+ if (vr->vr_res != NULL)
+ vr->vr_refs++;
+ return (vr->vr_res);
}
return (bus_alloc_resource(dev, type, rid, start, end, count, flags));
}
@@ -188,8 +200,8 @@ static int
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;
+ struct vga_resource *vr;
+ int error;
switch (type) {
case SYS_RES_MEMORY:
@@ -198,24 +210,22 @@ vga_pci_release_resource(device_t dev, device_t child, int type, int rid,
* 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)
+ vr = lookup_res(device_get_softc(dev), rid);
+ if (vr == NULL)
return (EINVAL);
- sc = device_get_softc(dev);
- if (sc->vga_res[bar].vr_res == NULL)
+ if (vr->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--;
+ KASSERT(vr->vr_res == r, ("vga_pci resource mismatch"));
+ if (vr->vr_refs > 1) {
+ vr->vr_refs--;
return (0);
}
- KASSERT(sc->vga_res[bar].vr_refs > 0,
+ KASSERT(vr->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;
+ vr->vr_res = NULL;
+ vr->vr_refs = 0;
}
return (error);
}
OpenPOWER on IntegriCloud