From owner-svn-src-all@FreeBSD.ORG Thu Jun 21 14:55:35 2012 Return-Path: Delivered-To: svn-src-all@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [69.147.83.52]) by hub.freebsd.org (Postfix) with ESMTP id B719210657A2; Thu, 21 Jun 2012 14:55:35 +0000 (UTC) (envelope-from fabient@FreeBSD.org) Received: from svn.freebsd.org (svn.freebsd.org [IPv6:2001:4f8:fff6::2c]) by mx1.freebsd.org (Postfix) with ESMTP id 973D78FC1A; Thu, 21 Jun 2012 14:55:35 +0000 (UTC) Received: from svn.freebsd.org (localhost [127.0.0.1]) by svn.freebsd.org (8.14.4/8.14.4) with ESMTP id q5LEtZTN019444; Thu, 21 Jun 2012 14:55:35 GMT (envelope-from fabient@svn.freebsd.org) Received: (from fabient@localhost) by svn.freebsd.org (8.14.4/8.14.4/Submit) id q5LEtZOD019442; Thu, 21 Jun 2012 14:55:35 GMT (envelope-from fabient@svn.freebsd.org) Message-Id: <201206211455.q5LEtZOD019442@svn.freebsd.org> From: Fabien Thomas Date: Thu, 21 Jun 2012 14:55:35 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-stable@freebsd.org, svn-src-stable-8@freebsd.org X-SVN-Group: stable-8 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Cc: Subject: svn commit: r237400 - stable/8/sys/dev/pci X-BeenThere: svn-src-all@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: "SVN commit messages for the entire src tree \(except for " user" and " projects" \)" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Thu, 21 Jun 2012 14:55:35 -0000 Author: fabient Date: Thu Jun 21 14:55:35 2012 New Revision: 237400 URL: http://svn.freebsd.org/changeset/base/237400 Log: MFC r221839: Allow direct children of PCI-ISA bridges to allocate resources from the parent PCI bus. Heavily inspired by jhb@ and a similar implementation present in sys/dev/pci/vga_pci.c. Modified: stable/8/sys/dev/pci/isa_pci.c Directory Properties: stable/8/sys/ (props changed) Modified: stable/8/sys/dev/pci/isa_pci.c ============================================================================== --- stable/8/sys/dev/pci/isa_pci.c Thu Jun 21 14:37:05 2012 (r237399) +++ stable/8/sys/dev/pci/isa_pci.c Thu Jun 21 14:55:35 2012 (r237400) @@ -45,12 +45,22 @@ __FBSDID("$FreeBSD$"); #include #include -static int isab_probe(device_t dev); +#include +#include +#include + +static int isab_pci_probe(device_t dev); +static int isab_pci_attach(device_t dev); +static struct resource * isab_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); +static int isab_pci_release_resource(device_t dev, device_t child, + int type, int rid, struct resource *r); static device_method_t isab_methods[] = { /* Device interface */ - DEVMETHOD(device_probe, isab_probe), - DEVMETHOD(device_attach, isab_attach), + DEVMETHOD(device_probe, isab_pci_probe), + DEVMETHOD(device_attach, isab_pci_attach), DEVMETHOD(device_detach, bus_generic_detach), DEVMETHOD(device_shutdown, bus_generic_shutdown), DEVMETHOD(device_suspend, bus_generic_suspend), @@ -58,8 +68,8 @@ static device_method_t isab_methods[] = /* Bus interface */ DEVMETHOD(bus_add_child, bus_generic_add_child), - DEVMETHOD(bus_alloc_resource, bus_generic_alloc_resource), - DEVMETHOD(bus_release_resource, bus_generic_release_resource), + DEVMETHOD(bus_alloc_resource, isab_pci_alloc_resource), + DEVMETHOD(bus_release_resource, isab_pci_release_resource), DEVMETHOD(bus_activate_resource, bus_generic_activate_resource), DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource), DEVMETHOD(bus_setup_intr, bus_generic_setup_intr), @@ -68,10 +78,19 @@ static device_method_t isab_methods[] = DEVMETHOD_END }; +struct isab_pci_resource { + struct resource *ip_res; + int ip_refs; +}; + +struct isab_pci_softc { + struct isab_pci_resource isab_pci_res[PCIR_MAX_BAR_0 + 1]; +}; + static driver_t isab_driver = { "isab", isab_methods, - 0, + sizeof(struct isab_pci_softc), }; DRIVER_MODULE(isab, pci, isab_driver, isab_devclass, 0, 0); @@ -81,7 +100,7 @@ DRIVER_MODULE(isab, pci, isab_driver, is * report themselves. */ static int -isab_probe(device_t dev) +isab_pci_probe(device_t dev) { int matched = 0; @@ -139,3 +158,88 @@ isab_probe(device_t dev) } return(ENXIO); } + +static int +isab_pci_attach(device_t dev) +{ + + bus_generic_probe(dev); + return (isab_attach(dev)); +} + +static struct resource * +isab_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 isab_pci_softc *sc; + int bar; + + if (device_get_parent(child) != dev) + return bus_generic_alloc_resource(dev, child, type, rid, start, + end, count, flags); + + 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->isab_pci_res[bar].ip_res == NULL) + sc->isab_pci_res[bar].ip_res = bus_alloc_resource(dev, type, + rid, start, end, count, flags); + if (sc->isab_pci_res[bar].ip_res != NULL) + sc->isab_pci_res[bar].ip_refs++; + return (sc->isab_pci_res[bar].ip_res); + } + + return (BUS_ALLOC_RESOURCE(device_get_parent(dev), child, type, rid, + start, end, count, flags)); +} + +static int +isab_pci_release_resource(device_t dev, device_t child, int type, int rid, + struct resource *r) +{ + struct isab_pci_softc *sc; + int bar, error; + + if (device_get_parent(child) != dev) + return bus_generic_release_resource(dev, child, type, rid, r); + + 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->isab_pci_res[bar].ip_res == NULL) + return (EINVAL); + KASSERT(sc->isab_pci_res[bar].ip_res == r, + ("isa_pci resource mismatch")); + if (sc->isab_pci_res[bar].ip_refs > 1) { + sc->isab_pci_res[bar].ip_refs--; + return (0); + } + KASSERT(sc->isab_pci_res[bar].ip_refs > 0, + ("isa_pci resource reference count underflow")); + error = bus_release_resource(dev, type, rid, r); + if (error == 0) { + sc->isab_pci_res[bar].ip_res = NULL; + sc->isab_pci_res[bar].ip_refs = 0; + } + return (error); + } + + return (BUS_RELEASE_RESOURCE(device_get_parent(dev), child, type, + rid, r)); +}