From 41f96e698e71a2e79702cc6ec04840b7ed3eebbe Mon Sep 17 00:00:00 2001 From: sephe Date: Fri, 8 Jun 2007 13:52:09 +0000 Subject: [PATCH] If PCI_MAP_FIXUP is defined, following fixes will be applied: - For PCI/PCI bridge, adjust requested IO port/memory's start/range according to bridge's base/limit register value. - For Host/PCI bridge, if requested IO port/memory's starts from 0 and range is ~0, o If the request is for IO port, the start address is set to 0x1000. o If the request is for IO memory, the start address is set to tunable hw.pci.host_mem_start, which is 0x80000000 by default. This unbreaks cardbus bridge support, if PCI_MAP_FIXUP is defined. My laptop's cardbus bridge is on the PCI bus mastered by a PCI/PCI bridge, while swildner@'s laptop's cardbus bridge is on the PCI bus mastered by Host/PCI bridge. Tested-by: swildner@ and me Obtained-from: FreeBSD (imp@freebsd.org) # # It seems BIOS does not set cardbus bridge's BAR for most of the system, # so in the original code, the resource_list_alloc() in pci_alloc_resource() # will return NULL for cardbus bridge's IO memory allocation request; cardbus # bridge's code actually depends on that to reallocate IO memory using # hw.cbb.start_memory as start address. # # Before this commit, if PCI_MAP_FIXUP is defined, cardbus bridge's invalid # IO memory request will be delivered to various PCI bridge code, which does # not validate/fixup the request and returns "successful" result bindly. # --- sys/bus/pci/i386/pcibus.c | 49 ++++++++++++++++++++++++++++++++++++++++++++++- sys/bus/pci/pci_pcib.c | 10 +++++++--- 2 files changed, 55 insertions(+), 4 deletions(-) diff --git a/sys/bus/pci/i386/pcibus.c b/sys/bus/pci/i386/pcibus.c index 78bd7d5617..78e1706dec 100644 --- a/sys/bus/pci/i386/pcibus.c +++ b/sys/bus/pci/i386/pcibus.c @@ -24,15 +24,18 @@ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * $FreeBSD: src/sys/i386/isa/pcibus.c,v 1.57.2.12 2003/08/07 06:19:26 imp Exp $ - * $DragonFly: src/sys/bus/pci/i386/pcibus.c,v 1.18 2007/05/01 00:05:16 dillon Exp $ + * $DragonFly: src/sys/bus/pci/i386/pcibus.c,v 1.19 2007/06/08 13:52:09 sephe Exp $ * */ +#include "opt_pci.h" + #include #include #include #include #include +#include #include #include @@ -427,6 +430,46 @@ nexus_legacypci_attach(device_t dev) return (0); } +#ifdef PCI_MAP_FIXUP + +SYSCTL_NODE(_hw, OID_AUTO, pci, CTLFLAG_RD, 0, "pci parameters"); + +static unsigned long legacy_host_mem_start = 0x80000000; +/* XXX need TUNABLE_ULONG? */ +TUNABLE_INT("hw.pci.host_mem_start", (int *)&legacy_host_mem_start); +SYSCTL_ULONG(_hw_pci, OID_AUTO, host_mem_start, CTLFLAG_RD, + &legacy_host_mem_start, 0x80000000, + "Limit the host bridge memory to being above this address. " + "Must be\n" + "set at boot via hw.pci.host_mem_start tunable."); + +static struct resource * +nexus_legacypci_alloc_resource(device_t dev, device_t child, int type, int *rid, + u_long start, u_long end, u_long count, + u_int flags) +{ + /* + * If no memory preference is given, use upper 32MB slot most + * bioses use for their memory window. Typically other bridges + * before us get in the way to assert their preferences on memory. + * Hardcoding like this sucks, so a more MD/MI way needs to be + * found to do it. This is typically only used on older laptops + * that don't have pci busses behind pci bridge, so assuming > 32MB + * is likely OK. + * + * However, this can cause problems for other chipsets, so we make + * this tunable by hw.pci.host_mem_start. + */ + if (type == SYS_RES_MEMORY && start == 0UL && end == ~0UL) + start = legacy_host_mem_start; + if (type == SYS_RES_IOPORT && start == 0UL && end == ~0UL) + start = 0x1000; + return bus_generic_alloc_resource(dev, child, type, rid, + start, end, count, flags); +} + +#endif /* PCI_MAP_FIXUP */ + static device_method_t legacypci_methods[] = { /* Device interface */ DEVMETHOD(device_identify, nexus_legacypci_identify), @@ -444,7 +487,11 @@ static device_method_t legacypci_methods[] = { DEVMETHOD(bus_print_child, bus_generic_print_child), DEVMETHOD(bus_read_ivar, bus_generic_read_ivar), DEVMETHOD(bus_write_ivar, bus_generic_write_ivar), +#ifdef PCI_MAP_FIXUP + DEVMETHOD(bus_alloc_resource, nexus_legacypci_alloc_resource), +#else DEVMETHOD(bus_alloc_resource, bus_generic_alloc_resource), +#endif DEVMETHOD(bus_release_resource, bus_generic_release_resource), DEVMETHOD(bus_activate_resource, bus_generic_activate_resource), DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource), diff --git a/sys/bus/pci/pci_pcib.c b/sys/bus/pci/pci_pcib.c index b706a5450b..5cb6eb6bc9 100644 --- a/sys/bus/pci/pci_pcib.c +++ b/sys/bus/pci/pci_pcib.c @@ -26,9 +26,11 @@ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * - * $DragonFly: src/sys/bus/pci/pci_pcib.c,v 1.6 2006/10/25 20:55:51 dillon Exp $ + * $DragonFly: src/sys/bus/pci/pci_pcib.c,v 1.7 2007/06/08 13:52:09 sephe Exp $ */ +#include "opt_pci.h" + #include #include #include @@ -416,10 +418,12 @@ pcib_alloc_resource(device_t dev, device_t child, int type, int *rid, start = sc->iobase; if (end > sc->iolimit) end = sc->iolimit; + if (start < end) + ok = 1; } } else { ok = 1; -#if 0 +#ifdef PCI_MAP_FIXUP if (start < sc->iobase && end > sc->iolimit) { start = sc->iobase; end = sc->iolimit; @@ -475,7 +479,7 @@ pcib_alloc_resource(device_t dev, device_t child, int type, int *rid, } } else if (!ok) { ok = 1; /* subtractive bridge: always ok */ -#if 0 +#ifdef PCI_MAP_FIXUP if (pcib_is_nonprefetch_open(sc)) { if (start < sc->membase && end > sc->memlimit) { start = sc->membase; -- 2.11.4.GIT