diff options
author | Miod Vallat <miod@cvs.openbsd.org> | 2009-07-16 21:02:59 +0000 |
---|---|---|
committer | Miod Vallat <miod@cvs.openbsd.org> | 2009-07-16 21:02:59 +0000 |
commit | 4fca826517a2f9595a073f0b0f2e9c47908be7fd (patch) | |
tree | 362295fb056eb6000279bf9f17503f6dd950f52d /sys | |
parent | b12d022e613f07bd1838760bb15d583075c5ff91 (diff) |
Make the PCI-PCI bridge initialization code bus-independent, relying on a
per-pci_chipset_t function to perform actual resource allocation.
Add the necessary bits to macepcibr(4), and enable ppb(4) on O2 kernels now.
Joint effort with kettenis@
Diffstat (limited to 'sys')
-rw-r--r-- | sys/arch/sgi/conf/GENERIC-IP32 | 5 | ||||
-rw-r--r-- | sys/arch/sgi/conf/RAMDISK-IP32 | 5 | ||||
-rw-r--r-- | sys/arch/sgi/pci/macepcibridge.c | 239 | ||||
-rw-r--r-- | sys/arch/sgi/pci/pci_machdep.c | 216 | ||||
-rw-r--r-- | sys/arch/sgi/pci/pci_machdep.h | 8 | ||||
-rw-r--r-- | sys/arch/sgi/xbow/xbridge.c | 292 |
6 files changed, 535 insertions, 230 deletions
diff --git a/sys/arch/sgi/conf/GENERIC-IP32 b/sys/arch/sgi/conf/GENERIC-IP32 index 7e450718253..62798a2984e 100644 --- a/sys/arch/sgi/conf/GENERIC-IP32 +++ b/sys/arch/sgi/conf/GENERIC-IP32 @@ -1,4 +1,4 @@ -# $OpenBSD: GENERIC-IP32,v 1.8 2009/07/15 18:15:21 miod Exp $ +# $OpenBSD: GENERIC-IP32,v 1.9 2009/07/16 21:02:54 miod Exp $ # # THIS KERNEL IS FOR O2 (IP32) SYSTEMS ONLY. # @@ -129,6 +129,9 @@ video* at uvideo? udl* at uhub? wsdisplay* at udl? +ppb* at pci? # PCI-PCI bridges +pci* at ppb? + #### NICs dc* at pci? # 21143, "tulip" clone ethernet em* at pci? # Intel Pro/1000 ethernet diff --git a/sys/arch/sgi/conf/RAMDISK-IP32 b/sys/arch/sgi/conf/RAMDISK-IP32 index 46908654248..47e6496f104 100644 --- a/sys/arch/sgi/conf/RAMDISK-IP32 +++ b/sys/arch/sgi/conf/RAMDISK-IP32 @@ -1,4 +1,4 @@ -# $OpenBSD: RAMDISK-IP32,v 1.6 2009/07/15 18:15:21 miod Exp $ +# $OpenBSD: RAMDISK-IP32,v 1.7 2009/07/16 21:02:54 miod Exp $ # # THIS KERNEL IS FOR O2 (IP32) SYSTEMS ONLY. @@ -120,6 +120,9 @@ wi* at uhub? # WaveLAN IEEE 802.11DS zyd* at uhub? # Zydas ZD1211 ugen* at uhub? # USB Generic driver +ppb* at pci? # PCI-PCI bridges +pci* at ppb? + #### NICs dc* at pci? # 21143, "tulip" clone ethernet em* at pci? # Intel Pro/1000 ethernet diff --git a/sys/arch/sgi/pci/macepcibridge.c b/sys/arch/sgi/pci/macepcibridge.c index d9a0d7f1fc3..2c6653810ad 100644 --- a/sys/arch/sgi/pci/macepcibridge.c +++ b/sys/arch/sgi/pci/macepcibridge.c @@ -1,4 +1,4 @@ -/* $OpenBSD: macepcibridge.c,v 1.22 2009/07/16 21:00:51 miod Exp $ */ +/* $OpenBSD: macepcibridge.c,v 1.23 2009/07/16 21:02:56 miod Exp $ */ /* * Copyright (c) 2001-2004 Opsycon AB (www.opsycon.se) @@ -47,39 +47,38 @@ #include <dev/pci/pcireg.h> #include <dev/pci/pcivar.h> #include <dev/pci/ppbreg.h> +#include <dev/pci/pcidevs.h> #include <mips64/archtype.h> #include <sgi/localbus/crimebus.h> #include <sgi/localbus/macebus.h> #include <sgi/pci/macepcibrvar.h> -extern void *macebus_intr_establish(void *, u_long, int, int, - int (*)(void *), void *, char *); -extern void macebus_intr_disestablish(void *, void *); -extern void pciaddr_remap(pci_chipset_tag_t); - -/**/ int mace_pcibrmatch(struct device *, void *, void *); void mace_pcibrattach(struct device *, struct device *, void *); -void mace_pcibr_attach_hook(struct device *, struct device *, - struct pcibus_attach_args *); -int mace_pcibr_errintr(void *); +void mace_pcibr_attach_hook(struct device *, struct device *, + struct pcibus_attach_args *); +int mace_pcibr_bus_maxdevs(void *, int); pcitag_t mace_pcibr_make_tag(void *, int, int, int); void mace_pcibr_decompose_tag(void *, pcitag_t, int *, int *, int *); - -int mace_pcibr_bus_maxdevs(void *, int); pcireg_t mace_pcibr_conf_read(void *, pcitag_t, int); void mace_pcibr_conf_write(void *, pcitag_t, int, pcireg_t); - -int mace_pcibr_intr_map(struct pci_attach_args *, pci_intr_handle_t *); +int mace_pcibr_intr_map(struct pci_attach_args *, pci_intr_handle_t *); const char *mace_pcibr_intr_string(void *, pci_intr_handle_t); -void *mace_pcibr_intr_establish(void *, pci_intr_handle_t, - int, int (*func)(void *), void *, char *); -void mace_pcibr_intr_disestablish(void *, void *); +void *mace_pcibr_intr_establish(void *, pci_intr_handle_t, int, + int (*)(void *), void *, char *); +void mace_pcibr_intr_disestablish(void *, void *); bus_addr_t mace_pcibr_pa_to_device(paddr_t); -paddr_t mace_pcibr_device_to_pa(bus_addr_t); +paddr_t mace_pcibr_device_to_pa(bus_addr_t); + +void mace_pcibr_configure(struct mace_pcibr_softc *); +int mace_pcibr_errintr(void *); +int mace_pcibr_ppb_setup(void *, pcitag_t, bus_addr_t *, bus_addr_t *, + bus_addr_t *, bus_addr_t *); + +extern void pciaddr_remap(pci_chipset_tag_t); struct cfattach macepcibr_ca = { sizeof(struct mace_pcibr_softc), mace_pcibrmatch, mace_pcibrattach, @@ -146,10 +145,10 @@ struct machine_bus_dma_tag pci_bus_dma_tag = { CRIME_MEMORY_MASK }; -struct _perr_map { +const struct _perr_map { pcireg_t mask; pcireg_t flag; - char *text; + const char *text; } perr_map[] = { { PERR_MASTER_ABORT, PERR_MASTER_ABORT_ADDR_VALID, "master abort" }, { PERR_TARGET_ABORT, PERR_TARGET_ABORT_ADDR_VALID, "target abort" }, @@ -166,18 +165,17 @@ struct _perr_map { { 0, 0 } }; - static int mace_pcibrprint(void *, const char *pnp); - int mace_pcibrmatch(struct device *parent, void *match, void *aux) { - switch(sys_config.system_type) { + switch (sys_config.system_type) { case SGI_O2: return 1; + default: + return 0; } - return (0); } void @@ -198,14 +196,14 @@ mace_pcibrattach(struct device *parent, struct device *self, void *aux) /* Create extents for PCI mappings */ mace_pcibbus_io_tag.bus_extent = extent_create("pci_io", - MACE_PCI_IO_BASE, MACE_PCI_IO_BASE + MACE_PCI_IO_SIZE - 1, - M_DEVBUF, (caddr_t)pci_io_ext_storage, - sizeof(pci_io_ext_storage), EX_NOCOALESCE|EX_NOWAIT); + MACE_PCI_IO_BASE, MACE_PCI_IO_BASE + MACE_PCI_IO_SIZE - 1, + M_DEVBUF, (caddr_t)pci_io_ext_storage, + sizeof(pci_io_ext_storage), EX_NOCOALESCE|EX_NOWAIT); mace_pcibbus_mem_tag.bus_extent = extent_create("pci_mem", - MACE_PCI_MEM_BASE, MACE_PCI_MEM_BASE + MACE_PCI_MEM_SIZE - 1, - M_DEVBUF, (caddr_t)pci_mem_ext_storage, - sizeof(pci_mem_ext_storage), EX_NOCOALESCE|EX_NOWAIT); + MACE_PCI_MEM_BASE, MACE_PCI_MEM_BASE + MACE_PCI_MEM_SIZE - 1, + M_DEVBUF, (caddr_t)pci_mem_ext_storage, + sizeof(pci_mem_ext_storage), EX_NOCOALESCE|EX_NOWAIT); /* local -> PCI MEM mapping offset */ sc->sc_mem_bus_space = &mace_pcibbus_mem_tag; @@ -216,7 +214,7 @@ mace_pcibrattach(struct device *parent, struct device *self, void *aux) /* Map in PCI control registers */ sc->sc_memt = ca->ca_memt; if (bus_space_map(sc->sc_memt, MACE_PCI_OFFS, 4096, 0, &sc->sc_memh)) { - printf("UH-OH! Can't map PCI control registers!\n"); + printf(": can't map PCI control registers\n"); return; } pcireg = bus_space_read_4(sc->sc_memt, sc->sc_memh, MACE_PCI_REVISION); @@ -236,6 +234,7 @@ mace_pcibrattach(struct device *parent, struct device *self, void *aux) sc->sc_pc.pc_intr_string = mace_pcibr_intr_string; sc->sc_pc.pc_intr_establish = mace_pcibr_intr_establish; sc->sc_pc.pc_intr_disestablish = mace_pcibr_intr_disestablish; + sc->sc_pc.pc_ppb_setup = mace_pcibr_ppb_setup; /* * Firmware sucks. Remap PCI BAR registers. (sigh) @@ -243,6 +242,11 @@ mace_pcibrattach(struct device *parent, struct device *self, void *aux) pciaddr_remap(&sc->sc_pc); /* + * Setup any PCI-PCI bridge. + */ + mace_pcibr_configure(sc); + + /* * Configure our PCI devices. */ bzero(&pba, sizeof(pba)); @@ -264,22 +268,19 @@ mace_pcibrattach(struct device *parent, struct device *self, void *aux) } static int -mace_pcibrprint(aux, pnp) - void *aux; - const char *pnp; +mace_pcibrprint(void *aux, const char *pnp) { struct pcibus_attach_args *pba = aux; if (pnp) printf("%s at %s", pba->pba_busname, pnp); printf(" bus %d", pba->pba_bus); - return(UNCONF); + return (UNCONF); } void -mace_pcibr_attach_hook(parent, self, pba) - struct device *parent, *self; - struct pcibus_attach_args *pba; +mace_pcibr_attach_hook(struct device *parent, struct device *self, + struct pcibus_attach_args *pba) { } @@ -289,7 +290,7 @@ mace_pcibr_errintr(void *v) struct mace_pcibr_softc *sc = v; bus_space_tag_t memt = sc->sc_memt; bus_space_handle_t memh = sc->sc_memh; - struct _perr_map *emap = perr_map; + const struct _perr_map *emap = perr_map; pcireg_t stat, erraddr; /* Check and clear any PCI error, report found */ @@ -313,21 +314,17 @@ mace_pcibr_errintr(void *v) */ pcitag_t -mace_pcibr_make_tag(cpv, bus, dev, fnc) - void *cpv; - int bus, dev, fnc; +mace_pcibr_make_tag(void *cpv, int bus, int dev, int fnc) { return (bus << 16) | (dev << 11) | (fnc << 8); } void -mace_pcibr_decompose_tag(cpv, tag, busp, devp, fncp) - void *cpv; - pcitag_t tag; - int *busp, *devp, *fncp; +mace_pcibr_decompose_tag(void *cpv, pcitag_t tag, int *busp, int *devp, + int *fncp) { if (busp != NULL) - *busp = (tag >> 16) & 0x7; + *busp = (tag >> 16) & 0xff; if (devp != NULL) *devp = (tag >> 11) & 0x1f; if (fncp != NULL) @@ -335,11 +332,9 @@ mace_pcibr_decompose_tag(cpv, tag, busp, devp, fncp) } int -mace_pcibr_bus_maxdevs(cpv, busno) - void *cpv; - int busno; +mace_pcibr_bus_maxdevs(void *cpv, int busno) { - return 5; + return busno == 0 ? 4 : 32; } pcireg_t @@ -381,11 +376,7 @@ mace_pcibr_conf_read(void *cpv, pcitag_t tag, int offset) } void -mace_pcibr_conf_write(cpv, tag, offset, data) - void *cpv; - pcitag_t tag; - int offset; - pcireg_t data; +mace_pcibr_conf_write(void *cpv, pcitag_t tag, int offset, pcireg_t data) { struct mace_pcibr_softc *sc = cpv; pcireg_t addr; @@ -410,8 +401,10 @@ mace_pcibr_intr_map(struct pci_attach_args *pa, pci_intr_handle_t *ihp) { 9, -1, -1, -1 }, /* ahc0 */ { 10, -1, -1, -1 }, /* ahc1 */ { 11, 14, 15, 16 }, /* slot */ +#ifdef useless { 12, 16, 14, 15 }, /* no slots... */ { 13, 15, 16, 14 } /* ... unless you solder them */ +#endif }; *ihp = -1; @@ -443,9 +436,7 @@ mace_pcibr_intr_map(struct pci_attach_args *pa, pci_intr_handle_t *ihp) } const char * -mace_pcibr_intr_string(lcv, ih) - void *lcv; - pci_intr_handle_t ih; +mace_pcibr_intr_string(void *lcv, pci_intr_handle_t ih) { static char str[16]; @@ -454,39 +445,33 @@ mace_pcibr_intr_string(lcv, ih) } void * -mace_pcibr_intr_establish(lcv, ih, level, func, arg, name) - void *lcv; - pci_intr_handle_t ih; - int level; - int (*func)(void *); - void *arg; - char *name; +mace_pcibr_intr_establish(void *lcv, pci_intr_handle_t ih, int level, + int (*func)(void *), void *arg, char *name) { - return macebus_intr_establish(NULL, ih, IST_LEVEL, level, func, arg, name); + return + macebus_intr_establish(NULL, ih, IST_LEVEL, level, func, arg, name); } void -mace_pcibr_intr_disestablish(lcv, cookie) - void *lcv, *cookie; +mace_pcibr_intr_disestablish(void *lcv, void *cookie) { macebus_intr_disestablish(lcv, cookie); } /* * Bus access primitives - * XXX 64 bit access not clean in lp32 mode. */ u_int8_t mace_pcib_read_1(bus_space_tag_t t, bus_space_handle_t h, bus_size_t o) { - return *(volatile u_int8_t *)(h + (o | 3) - (o & 3)); + return *(volatile u_int8_t *)(h + (o ^ 3)); } u_int16_t mace_pcib_read_2(bus_space_tag_t t, bus_space_handle_t h, bus_size_t o) { - return *(volatile u_int16_t *)(h + (o | 2) - (o & 3)); + return *(volatile u_int16_t *)(h + (o ^ 2)); } u_int32_t @@ -502,25 +487,29 @@ mace_pcib_read_8(bus_space_tag_t t, bus_space_handle_t h, bus_size_t o) } void -mace_pcib_write_1(bus_space_tag_t t, bus_space_handle_t h, bus_size_t o, u_int8_t v) +mace_pcib_write_1(bus_space_tag_t t, bus_space_handle_t h, bus_size_t o, + u_int8_t v) { - *(volatile u_int8_t *)(h + (o | 3) - (o & 3)) = v; + *(volatile u_int8_t *)(h + (o ^ 3)) = v; } void -mace_pcib_write_2(bus_space_tag_t t, bus_space_handle_t h, bus_size_t o, u_int16_t v) +mace_pcib_write_2(bus_space_tag_t t, bus_space_handle_t h, bus_size_t o, + u_int16_t v) { - *(volatile u_int16_t *)(h + (o | 2) - (o & 3)) = v; + *(volatile u_int16_t *)(h + (o ^ 2)) = v; } void -mace_pcib_write_4(bus_space_tag_t t, bus_space_handle_t h, bus_size_t o, u_int32_t v) +mace_pcib_write_4(bus_space_tag_t t, bus_space_handle_t h, bus_size_t o, + u_int32_t v) { *(volatile u_int32_t *)(h + o) = v; } void -mace_pcib_write_8(bus_space_tag_t t, bus_space_handle_t h, bus_size_t o, u_int64_t v) +mace_pcib_write_8(bus_space_tag_t t, bus_space_handle_t h, bus_size_t o, + u_int64_t v) { *(volatile u_int64_t *)(h + o) = v; } @@ -529,7 +518,7 @@ void mace_pcib_read_raw_2(bus_space_tag_t t, bus_space_handle_t h, bus_addr_t o, u_int8_t *buf, bus_size_t len) { - volatile u_int16_t *addr = (volatile u_int16_t *)(h + (o | 2) - (o & 3)); + volatile u_int16_t *addr = (volatile u_int16_t *)(h + (o ^ 2)); len >>= 1; while (len-- != 0) { *(u_int16_t *)buf = letoh16(*addr); @@ -541,7 +530,7 @@ void mace_pcib_write_raw_2(bus_space_tag_t t, bus_space_handle_t h, bus_addr_t o, const u_int8_t *buf, bus_size_t len) { - volatile u_int16_t *addr = (volatile u_int16_t *)(h + (o | 2) - (o & 3)); + volatile u_int16_t *addr = (volatile u_int16_t *)(h + (o ^ 2)); len >>= 1; while (len-- != 0) { *addr = htole16(*(u_int16_t *)buf); @@ -601,7 +590,7 @@ extern int extent_malloc_flags; int mace_pcib_space_map(bus_space_tag_t t, bus_addr_t offs, bus_size_t size, - int cacheable, bus_space_handle_t *bshp) + int cacheable, bus_space_handle_t *bshp) { bus_addr_t bpa; int error; @@ -625,7 +614,8 @@ mace_pcib_space_map(bus_space_tag_t t, bus_addr_t offs, bus_size_t size, } void -mace_pcib_space_unmap(bus_space_tag_t t, bus_space_handle_t bsh, bus_size_t size) +mace_pcib_space_unmap(bus_space_tag_t t, bus_space_handle_t bsh, + bus_size_t size) { bus_addr_t sva; bus_size_t off, len; @@ -650,7 +640,7 @@ mace_pcib_space_unmap(bus_space_tag_t t, bus_space_handle_t bsh, bus_size_t size int mace_pcib_space_region(bus_space_tag_t t, bus_space_handle_t bsh, - bus_size_t offset, bus_size_t size, bus_space_handle_t *nbshp) + bus_size_t offset, bus_size_t size, bus_space_handle_t *nbshp) { *nbshp = bsh + offset; return (0); @@ -677,3 +667,86 @@ mace_pcibr_device_to_pa(bus_addr_t addr) return (pa); } + +/* + * PCI configuration. + */ + +void +mace_pcibr_configure(struct mace_pcibr_softc *sc) +{ + pci_chipset_tag_t pc = &sc->sc_pc; + int dev; + uint curppb, nppb; + pcitag_t tag; + pcireg_t id, bhlcr; + + nppb = 0; + for (dev = 0; dev < pci_bus_maxdevs(pc, 0); dev++) { + tag = pci_make_tag(pc, 0, dev, 0); + + id = pci_conf_read(pc, tag, PCI_ID_REG); + if (PCI_VENDOR(id) == PCI_VENDOR_INVALID || + PCI_VENDOR(id) == 0) + continue; + + bhlcr = pci_conf_read(pc, tag, PCI_BHLC_REG); + if (PCI_HDRTYPE_TYPE(bhlcr) == 1) + nppb++; + } + + /* + * Since there is only one working slot, there should be only + * up to one bridge, which we'll map after the on-board device + * resources. + */ + if (nppb != 1) + return; + + curppb = 0; + for (dev = 0; dev < pci_bus_maxdevs(pc, 0); dev++) { + tag = pci_make_tag(pc, 0, dev, 0); + + id = pci_conf_read(pc, tag, PCI_ID_REG); + if (PCI_VENDOR(id) == PCI_VENDOR_INVALID || + PCI_VENDOR(id) == 0) + continue; + + bhlcr = pci_conf_read(pc, tag, PCI_BHLC_REG); + if (PCI_HDRTYPE_TYPE(bhlcr) != 1) + continue; + + ppb_initialize(pc, tag, 1 + curppb * (255 / nppb), + (curppb + 1) * (255 / nppb)); + curppb++; + } +} + +int +mace_pcibr_ppb_setup(void *cookie, pcitag_t tag, bus_addr_t *iostart, + bus_addr_t *ioend, bus_addr_t *memstart, bus_addr_t *memend) +{ + if (*memend != 0) { + /* + * Give all resources to the bridge. + */ + *memstart = 0x90000000; + *memend = 0xffffffff; + } else { + *memstart = 0xffffffff; + *memend = 0; + } + + if (*ioend != 0) { + /* + * Give all resources to the bridge. + */ + *iostart = 0x01000000; + *ioend = MACE_PCI_IO_SIZE - *iostart; + } else { + *iostart = 0xffffffff; + *ioend = 0; + } + + return 0; +} diff --git a/sys/arch/sgi/pci/pci_machdep.c b/sys/arch/sgi/pci/pci_machdep.c index db8dcc051ac..ffa32844de3 100644 --- a/sys/arch/sgi/pci/pci_machdep.c +++ b/sys/arch/sgi/pci/pci_machdep.c @@ -1,4 +1,4 @@ -/* $OpenBSD: pci_machdep.c,v 1.1 2009/07/13 21:19:26 miod Exp $ */ +/* $OpenBSD: pci_machdep.c,v 1.2 2009/07/16 21:02:56 miod Exp $ */ /* * Copyright (c) 2009 Miodrag Vallat. @@ -20,31 +20,221 @@ #include <sys/systm.h> #include <sys/kernel.h> #include <sys/device.h> +#include <sys/extent.h> #include <dev/pci/pcireg.h> #include <dev/pci/pcivar.h> #include <dev/pci/ppbreg.h> +#include <dev/pci/pcidevs.h> +void ppb_device_explore(pci_chipset_tag_t, uint, int, int, struct extent *, + struct extent *); +void ppb_function_explore(pci_chipset_tag_t, pcitag_t, struct extent *, + struct extent *); + +/* + * Configure a PCI-PCI bridge. + */ void -ppb_initialize(pci_chipset_tag_t pc, pcitag_t tag, uint secondary, - uint subordinate, bus_addr_t iostart, bus_addr_t ioend, - bus_addr_t memstart, bus_addr_t memend) +ppb_initialize(pci_chipset_tag_t pc, pcitag_t ppbtag, uint secondary, + uint subordinate) { - pci_conf_write(pc, tag, PPB_REG_BUSINFO, + int dev, nfuncs; + pcireg_t id, csr, bhlcr; + pcitag_t tag; + const struct pci_quirkdata *qd; + bus_addr_t iostart, ioend, memstart, memend; + struct extent *ioex, *memex; + struct extent_region *region; + + /* + * In a first pass, enable access to the configuration space, + * and figure out what resources the devices behind it will + * need. + * + * Note that, doing this, we do not intend to support any + * hotplug capabilities. This should not be a problem on + * sgi. + */ + + csr = pci_conf_read(pc, ppbtag, PCI_COMMAND_STATUS_REG); + csr &= ~(PCI_COMMAND_IO_ENABLE | PCI_COMMAND_MEM_ENABLE); + pci_conf_write(pc, ppbtag, PCI_COMMAND_STATUS_REG, csr); + + pci_conf_write(pc, ppbtag, PPB_REG_BUSINFO, (secondary << 8) | (subordinate << 16)); - pci_conf_write(pc, tag, PPB_REG_MEM, + ioex = extent_create("ppb_io", 0, 0xffffffff, + M_DEVBUF, NULL, 0, EX_NOWAIT); + memex = extent_create("ppb_mem", 0, 0xffffffff, + M_DEVBUF, NULL, 0, EX_NOWAIT); + + for (dev = 0; dev < pci_bus_maxdevs(pc, secondary); dev++) { + tag = pci_make_tag(pc, secondary, dev, 0); + id = pci_conf_read(pc, tag, PCI_ID_REG); + + if (PCI_VENDOR(id) == PCI_VENDOR_INVALID || + PCI_VENDOR(id) == 0) + continue; + + bhlcr = pci_conf_read(pc, tag, PCI_BHLC_REG); + qd = pci_lookup_quirkdata(PCI_VENDOR(id), PCI_PRODUCT(id)); + if (PCI_HDRTYPE_MULTIFN(bhlcr) || + (qd != NULL && (qd->quirks & PCI_QUIRK_MULTIFUNCTION) != 0)) + nfuncs = 8; + else + nfuncs = 1; + + ppb_device_explore(pc, secondary, dev, nfuncs, ioex, memex); + } + + /* + * Now figure out the size of the resources we need... + */ + + iostart = memstart = 0xffffffff; + ioend = memend = 0; + + if (ioex != NULL) { + LIST_FOREACH(region, &ioex->ex_regions, er_link) { + if (region->er_start < iostart) + iostart = region->er_start; + if (region->er_end > ioend) + ioend = region->er_end; + } + extent_destroy(ioex); + } + if (memex != NULL) { + LIST_FOREACH(region, &memex->ex_regions, er_link) { + if (region->er_start < memstart) + memstart = region->er_start; + if (region->er_end > memend) + memend = region->er_end; + } + extent_destroy(memex); + } + + /* + * ... and ask the bridge to setup resources for them. + */ + + if (pc->pc_ppb_setup == NULL || (*pc->pc_ppb_setup)(pc->pc_conf_v, + ppbtag, &iostart, &ioend, &memstart, &memend) != 0) { + iostart = memstart = 0xffffffff; + ioend = memend = 0; + } + + pci_conf_write(pc, ppbtag, PPB_REG_MEM, ((memstart & 0xfff00000) >> 16) | (memend & 0xfff00000)); - pci_conf_write(pc, tag, PPB_REG_IOSTATUS, - (pci_conf_read(pc, tag, PPB_REG_IOSTATUS) & 0xffff0000) | + pci_conf_write(pc, ppbtag, PPB_REG_IOSTATUS, + (pci_conf_read(pc, ppbtag, PPB_REG_IOSTATUS) & 0xffff0000) | ((iostart & 0x0000f000) >> 8) | (ioend & 0x0000f000)); - pci_conf_write(pc, tag, PPB_REG_IO_HI, + pci_conf_write(pc, ppbtag, PPB_REG_IO_HI, ((iostart & 0xffff0000) >> 16) | (ioend & 0xffff0000)); - pci_conf_write(pc, tag, PPB_REG_PREFMEM, 0); + pci_conf_write(pc, ppbtag, PPB_REG_PREFMEM, 0x0000fff0); + pci_conf_write(pc, ppbtag, PPB_REG_PREFBASE_HI32, 0); + pci_conf_write(pc, ppbtag, PPB_REG_PREFBASE_HI32, 0); + + if (iostart <= ioend) + csr |= PCI_COMMAND_IO_ENABLE; + if (memstart <= memend) + csr |= PCI_COMMAND_MEM_ENABLE; - pci_conf_write(pc, tag, PCI_COMMAND_STATUS_REG, - pci_conf_read(pc, tag, PCI_COMMAND_STATUS_REG) | - PCI_COMMAND_IO_ENABLE | PCI_COMMAND_MEM_ENABLE | + pci_conf_write(pc, ppbtag, PCI_COMMAND_STATUS_REG, csr | PCI_COMMAND_MASTER_ENABLE | PCI_COMMAND_INVALIDATE_ENABLE | PCI_COMMAND_SERR_ENABLE); } + +/* + * Figure out what resources a device behind a bridge would need and + * disable them. + */ +void +ppb_device_explore(pci_chipset_tag_t pc, uint bus, int dev, int nfuncs, + struct extent *ioex, struct extent *memex) +{ + pcitag_t tag; + pcireg_t id; + int function; + + for (function = 0; function < nfuncs; function++) { + tag = pci_make_tag(pc, bus, dev, function); + + id = pci_conf_read(pc, tag, PCI_ID_REG); + if (PCI_VENDOR(id) == PCI_VENDOR_INVALID || + PCI_VENDOR(id) == 0) + continue; + + ppb_function_explore(pc, tag, ioex, memex); + } +} + +/* + * Figure out what resources a device function would need and + * disable them. + */ +void +ppb_function_explore(pci_chipset_tag_t pc, pcitag_t tag, struct extent *ioex, + struct extent *memex) +{ + bus_addr_t base; + bus_size_t size; + int reg, reg_start, reg_end; + pcireg_t csr, bhlcr, type; + + csr = pci_conf_read(pc, tag, PCI_COMMAND_STATUS_REG); + pci_conf_write(pc, tag, PCI_COMMAND_STATUS_REG, csr & + ~(PCI_COMMAND_IO_ENABLE | PCI_COMMAND_MEM_ENABLE)); + + bhlcr = pci_conf_read(pc, tag, PCI_BHLC_REG); + switch (PCI_HDRTYPE_TYPE(bhlcr)) { + case 0: + reg_start = PCI_MAPREG_START; + reg_end = PCI_MAPREG_END; + break; + case 1: /* PCI-PCI bridge */ + reg_start = PCI_MAPREG_START; + reg_end = PCI_MAPREG_PPB_END; + break; + case 2: /* PCI-Cardbus bridge */ + reg_start = PCI_MAPREG_START; + reg_end = PCI_MAPREG_PCB_END; + break; + default: + return; + } + + for (reg = reg_start; reg < reg_end; reg += 4) { + if (pci_mapreg_probe(pc, tag, reg, &type) == 0) + continue; + + if (pci_mapreg_info(pc, tag, reg, type, &base, &size, NULL)) + continue; + + switch (type) { + case PCI_MAPREG_TYPE_MEM | PCI_MAPREG_MEM_TYPE_64BIT: + pci_conf_write(pc, tag, reg + 4, 0); + /* FALLTHROUGH */ + case PCI_MAPREG_TYPE_MEM | PCI_MAPREG_MEM_TYPE_32BIT: + if (memex != NULL) + (void)extent_alloc(memex, size, size, 0, 0, 0, + &base); + break; + case PCI_MAPREG_TYPE_IO: + if (ioex != NULL) + (void)extent_alloc(ioex, size, size, 0, 0, 0, + &base); + break; + } + + pci_conf_write(pc, tag, reg, 0); + + if (type == (PCI_MAPREG_TYPE_MEM | PCI_MAPREG_MEM_TYPE_64BIT)) + reg += 4; + } + + /* + * Note that we do not try to be recursive and configure PCI-PCI + * bridges behind PCI-PCI bridges. + */ +} diff --git a/sys/arch/sgi/pci/pci_machdep.h b/sys/arch/sgi/pci/pci_machdep.h index e1a1dfcd68f..f3c89613d19 100644 --- a/sys/arch/sgi/pci/pci_machdep.h +++ b/sys/arch/sgi/pci/pci_machdep.h @@ -1,4 +1,4 @@ -/* $OpenBSD: pci_machdep.h,v 1.5 2009/07/13 21:19:26 miod Exp $ */ +/* $OpenBSD: pci_machdep.h,v 1.6 2009/07/16 21:02:56 miod Exp $ */ /* * Copyright (c) 2003-2004 Opsycon AB (www.opsycon.se / www.opsycon.com) @@ -52,6 +52,9 @@ struct mips_pci_chipset { void *(*pc_intr_establish)(void *, pci_intr_handle_t, int, int (*)(void *), void *, char *); void (*pc_intr_disestablish)(void *, void *); + + int (*pc_ppb_setup)(void *, pcitag_t, bus_addr_t *, bus_addr_t *, + bus_addr_t *, bus_addr_t *); }; /* @@ -78,5 +81,4 @@ struct mips_pci_chipset { #define pci_intr_disestablish(c, iv) \ (*(c)->pc_intr_disestablish)((c)->pc_intr_v, (iv)) -void ppb_initialize(pci_chipset_tag_t, pcitag_t, uint, uint, bus_addr_t, - bus_addr_t, bus_addr_t, bus_addr_t); +void ppb_initialize(pci_chipset_tag_t, pcitag_t, uint, uint); diff --git a/sys/arch/sgi/xbow/xbridge.c b/sys/arch/sgi/xbow/xbridge.c index 8e504daaa62..139e40ad6de 100644 --- a/sys/arch/sgi/xbow/xbridge.c +++ b/sys/arch/sgi/xbow/xbridge.c @@ -1,4 +1,4 @@ -/* $OpenBSD: xbridge.c,v 1.34 2009/07/13 21:19:28 miod Exp $ */ +/* $OpenBSD: xbridge.c,v 1.35 2009/07/16 21:02:58 miod Exp $ */ /* * Copyright (c) 2008, 2009 Miodrag Vallat. @@ -86,16 +86,29 @@ struct xbridge_softc { struct xbridge_intr *sc_intr[BRIDGE_NINTRS]; + /* + * Device information. + */ struct { pcireg_t id; uint32_t devio; } sc_devices[BRIDGE_NSLOTS]; + /* + * ATE management. + */ struct mutex sc_atemtx; uint sc_atecnt; struct xbridge_ate *sc_ate; LIST_HEAD(, xbridge_ate) sc_free_ate; LIST_HEAD(, xbridge_ate) sc_used_ate; + + /* + * Resource extents for the large resource views, used during + * resource setup and destroyed afterwards. + */ + struct extent *sc_ioex; + struct extent *sc_memex; }; const struct cfattach xbridge_ca = { @@ -108,17 +121,19 @@ struct cfdriver xbridge_cd = { void xbridge_attach_hook(struct device *, struct device *, struct pcibus_attach_args *); +int xbridge_bus_maxdevs(void *, int); pcitag_t xbridge_make_tag(void *, int, int, int); void xbridge_decompose_tag(void *, pcitag_t, int *, int *, int *); -int xbridge_bus_maxdevs(void *, int); pcireg_t xbridge_conf_read(void *, pcitag_t, int); void xbridge_conf_write(void *, pcitag_t, int, pcireg_t); - int xbridge_intr_map(struct pci_attach_args *, pci_intr_handle_t *); const char *xbridge_intr_string(void *, pci_intr_handle_t); void *xbridge_intr_establish(void *, pci_intr_handle_t, int, int (*func)(void *), void *, char *); void xbridge_intr_disestablish(void *, void *); +int xbridge_ppb_setup(void *, pcitag_t, bus_addr_t *, bus_addr_t *, + bus_addr_t *, bus_addr_t *); + int xbridge_intr_handler(void *); uint8_t xbridge_read_1(bus_space_tag_t, bus_space_handle_t, bus_size_t); @@ -169,12 +184,9 @@ void xbridge_resource_manage(struct xbridge_softc *, pcitag_t, struct extent *, struct extent *); void xbridge_ate_setup(struct xbridge_softc *); -void xbridge_device_setup(struct xbridge_softc *, int, int, uint32_t, - struct extent **, struct extent **); +void xbridge_device_setup(struct xbridge_softc *, int, int, uint32_t); struct extent * xbridge_mapping_setup(struct xbridge_softc *, int); -void xbridge_ppb_setup(struct xbridge_softc *, int, uint, uint, - struct extent **, struct extent **); void xbridge_resource_setup(struct xbridge_softc *); void xbridge_rrb_setup(struct xbridge_softc *, int); void xbridge_setup(struct xbridge_softc *); @@ -310,6 +322,7 @@ xbridge_attach(struct device *parent, struct device *self, void *aux) sc->sc_pc.pc_intr_string = xbridge_intr_string; sc->sc_pc.pc_intr_establish = xbridge_intr_establish; sc->sc_pc.pc_intr_disestablish = xbridge_intr_disestablish; + sc->sc_pc.pc_ppb_setup = xbridge_ppb_setup; /* * Configure Bridge for proper operation (DMA, I/O mappings, @@ -391,7 +404,7 @@ xbridge_decompose_tag(void *cookie, pcitag_t tag, int *busp, int *devp, int xbridge_bus_maxdevs(void *cookie, int busno) { - return BRIDGE_NSLOTS; + return busno == 0 ? BRIDGE_NSLOTS : 32; } pcireg_t @@ -661,11 +674,11 @@ xbridge_intr_establish(void *cookie, pci_intr_handle_t ih, int level, if (new) { /* * XXX The interrupt dispatcher is always registered - * XXX at IPL_BIO, in case the interrupt will be shared + * XXX at IPL_TTY, in case the interrupt will be shared * XXX between devices of different levels. */ if (xbow_intr_establish(xbridge_intr_handler, xi, intrsrc, - IPL_BIO, NULL)) { + IPL_TTY, NULL)) { printf("%s: unable to register interrupt handler\n", sc->sc_dev.dv_xname); return NULL; @@ -1859,7 +1872,6 @@ xbridge_resource_setup(struct xbridge_softc *sc) int need_setup; uint curppb, nppb; const struct pci_quirkdata *qd; - struct extent *io_ex = NULL, *mem_ex = NULL; /* * Figure out where the devio mappings will go. @@ -1880,9 +1892,9 @@ xbridge_resource_setup(struct xbridge_softc *sc) */ if (sys_config.system_type == SGI_OCTANE) { - io_ex = xbridge_mapping_setup(sc, 1); - mem_ex = xbridge_mapping_setup(sc, 0); - } + sc->sc_ioex = xbridge_mapping_setup(sc, 1); + sc->sc_memex = xbridge_mapping_setup(sc, 0); + } else /* * Configure all regular PCI devices. @@ -1901,7 +1913,7 @@ xbridge_resource_setup(struct xbridge_softc *sc) tag = pci_make_tag(pc, 0, dev, 0); bhlcr = pci_conf_read(pc, tag, PCI_BHLC_REG); - if (PCI_HDRTYPE(bhlcr) == 1) + if (PCI_HDRTYPE_TYPE(bhlcr) == 1) nppb++; /* @@ -1984,7 +1996,7 @@ xbridge_resource_setup(struct xbridge_softc *sc) else nfuncs = 1; - xbridge_device_setup(sc, dev, nfuncs, devio, &io_ex, &mem_ex); + xbridge_device_setup(sc, dev, nfuncs, devio); } /* @@ -2003,7 +2015,7 @@ xbridge_resource_setup(struct xbridge_softc *sc) tag = pci_make_tag(pc, 0, dev, 0); bhlcr = pci_conf_read(pc, tag, PCI_BHLC_REG); - if (PCI_HDRTYPE(bhlcr) != 1) + if (PCI_HDRTYPE_TYPE(bhlcr) != 1) continue; /* @@ -2015,15 +2027,15 @@ xbridge_resource_setup(struct xbridge_softc *sc) * 1 + M * (255/N) .. (M + 1) * (255 / N). */ - xbridge_ppb_setup(sc, dev, 1 + curppb * (255 / nppb), - (curppb + 1) * (255 / nppb), &io_ex, &mem_ex); + ppb_initialize(pc, tag, 1 + curppb * (255 / nppb), + (curppb + 1) * (255 / nppb)); curppb++; } - if (io_ex != NULL) - extent_destroy(io_ex); - if (mem_ex != NULL) - extent_destroy(mem_ex); + if (sc->sc_ioex != NULL) + extent_destroy(sc->sc_ioex); + if (sc->sc_memex != NULL) + extent_destroy(sc->sc_memex); } struct extent * @@ -2121,8 +2133,17 @@ xbridge_mapping_setup(struct xbridge_softc *sc, int io) * Note that xbow_widget_map_space() may have returned * a range in which the devio area does not appear. */ +#if 0 start = sc->sc_devio_skew << 24; end = start + (1 << 24) - 1; +#else + /* + * Apparently, all addresses under devio need to be + * expelled... + */ + start = 0; + end = ((sc->sc_devio_skew + 1) << 24) - 1; +#endif if (end >= ex->ex_start && start <= ex->ex_end) { if (start < ex->ex_start) @@ -2166,7 +2187,7 @@ xbridge_resource_explore(struct xbridge_softc *sc, pcitag_t tag, int rc = 0; bhlc = pci_conf_read(pc, tag, PCI_BHLC_REG); - switch (PCI_HDRTYPE(bhlc)) { + switch (PCI_HDRTYPE_TYPE(bhlc)) { case 0: reg_start = PCI_MAPREG_START; reg_end = PCI_MAPREG_END; @@ -2237,7 +2258,7 @@ xbridge_resource_manage(struct xbridge_softc *sc, pcitag_t tag, int reg, reg_start, reg_end; bhlc = pci_conf_read(pc, tag, PCI_BHLC_REG); - switch (PCI_HDRTYPE(bhlc)) { + switch (PCI_HDRTYPE_TYPE(bhlc)) { case 0: reg_start = PCI_MAPREG_START; reg_end = PCI_MAPREG_END; @@ -2311,12 +2332,12 @@ xbridge_resource_manage(struct xbridge_softc *sc, pcitag_t tag, void xbridge_device_setup(struct xbridge_softc *sc, int dev, int nfuncs, - uint32_t devio, struct extent **large_ioex, struct extent **large_memex) + uint32_t devio) { pci_chipset_tag_t pc = &sc->sc_pc; int function; pcitag_t tag; - pcireg_t id; + pcireg_t id, csr; uint32_t basewin; int resources; int io_devio, mem_devio; @@ -2335,13 +2356,13 @@ xbridge_device_setup(struct xbridge_softc *sc, int dev, int nfuncs, * This can fail; in that case we'll try to use a large mapping * whenever possible, or silently fail to configure the device. */ - if (*large_ioex != NULL) + if (sc->sc_ioex != NULL) ioex = NULL; else ioex = extent_create("xbridge_io", 0, BRIDGE_DEVIO_LARGE - 1, M_DEVBUF, NULL, 0, EX_NOWAIT); - if (*large_memex != NULL) + if (sc->sc_memex != NULL) memex = NULL; else memex = extent_create("xbridge_mem", @@ -2357,6 +2378,10 @@ xbridge_device_setup(struct xbridge_softc *sc, int dev, int nfuncs, PCI_VENDOR(id) == 0) continue; + csr = pci_conf_read(pc, tag, PCI_COMMAND_STATUS_REG); + pci_conf_write(pc, tag, PCI_COMMAND_STATUS_REG, csr & + ~(PCI_COMMAND_IO_ENABLE | PCI_COMMAND_MEM_ENABLE)); + resources |= xbridge_resource_explore(sc, tag, ioex, memex); } @@ -2383,7 +2408,7 @@ xbridge_device_setup(struct xbridge_softc *sc, int dev, int nfuncs, if (ISSET(resources, XR_IO)) { if (!ISSET(resources, XR_IO_OFLOW) && (sys_config.system_type != SGI_OCTANE || - *large_ioex == NULL)) + sc->sc_ioex == NULL)) io_devio = xbridge_allocate_devio(sc, dev, ISSET(resources, XR_IO_OFLOW_S)); if (io_devio >= 0) { @@ -2400,8 +2425,8 @@ xbridge_device_setup(struct xbridge_softc *sc, int dev, int nfuncs, * Try to get a large window mapping if we don't * have one already. */ - if (*large_ioex == NULL) - *large_ioex = xbridge_mapping_setup(sc, 1); + if (sc->sc_ioex == NULL) + sc->sc_ioex = xbridge_mapping_setup(sc, 1); } } @@ -2426,8 +2451,8 @@ xbridge_device_setup(struct xbridge_softc *sc, int dev, int nfuncs, * Try to get a large window mapping if we don't * have one already. */ - if (*large_memex == NULL) - *large_memex = xbridge_mapping_setup(sc, 0); + if (sc->sc_memex == NULL) + sc->sc_memex = xbridge_mapping_setup(sc, 0); } } @@ -2445,8 +2470,8 @@ xbridge_device_setup(struct xbridge_softc *sc, int dev, int nfuncs, continue; xbridge_resource_manage(sc, tag, - ioex != NULL ? ioex : *large_ioex, - memex != NULL ? memex : *large_memex); + ioex != NULL ? ioex : sc->sc_ioex, + memex != NULL ? memex : sc->sc_memex); } if (memex != NULL) @@ -2455,128 +2480,137 @@ xbridge_device_setup(struct xbridge_softc *sc, int dev, int nfuncs, extent_destroy(ioex); } -void -xbridge_ppb_setup(struct xbridge_softc *sc, int dev, uint secondary, - uint subordinate, struct extent **large_ioex, struct extent **large_memex) +int +xbridge_ppb_setup(void *cookie, pcitag_t tag, bus_addr_t *iostart, + bus_addr_t *ioend, bus_addr_t *memstart, bus_addr_t *memend) { + struct xbridge_softc *sc = cookie; pci_chipset_tag_t pc = &sc->sc_pc; - pcitag_t tag; - uint32_t devio; - uint32_t base; - bus_addr_t iostart, ioend; - bus_addr_t memstart, memend; + uint32_t base, devio; bus_size_t exsize; u_long exstart; - int devio_idx; - int tries; + int dev, devio_idx, tries; - iostart = memstart = 0; - ioend = memend = 0xffffffff; + pci_decompose_tag(pc, tag, NULL, &dev, NULL); devio = bus_space_read_4(sc->sc_iot, sc->sc_regh, BRIDGE_DEVICE(dev)); /* - * Since we can't know in advance how much resource space will be - * needed by the devices behind the bridge, try to be generous. - * - * We'll try to get large mappings, and provide 1/8 of the range - * to the bridge. If this isn't possible, we'll try to allocate - * the largest possible devio range. This can still fail since - * we want to provide both I/O and memory resources and might - * not have enough devio slots available. + * Since our caller computes resource needs starting at zero, we + * can ignore the start values when computing the amount of + * resources we'll need. */ - if (*large_memex == NULL) - *large_memex = xbridge_mapping_setup(sc, 0); - if (*large_memex == NULL) { - devio_idx = xbridge_allocate_devio(sc, dev, 1); - if (devio_idx < 0) + exsize = *memend; + *memstart = 0xffffffff; + *memend = 0; + if (exsize++ != 0) { + /* try to allocate through a devio slot whenever possible... */ + if (exsize < BRIDGE_DEVIO_SHORT) devio_idx = xbridge_allocate_devio(sc, dev, 0); - if (devio_idx < 0) { - /* no resources */ - } else { + else if (exsize < BRIDGE_DEVIO_LARGE) + devio_idx = xbridge_allocate_devio(sc, dev, 1); + else + devio_idx = -1; + + /* ...if it fails, try the large view.... */ + if (devio_idx < 0 && sc->sc_memex == NULL) + sc->sc_memex = xbridge_mapping_setup(sc, 0); + + /* ...if it is not available, try to get a devio slot anyway. */ + if (devio_idx < 0 && sc->sc_memex == NULL) { + if (exsize > BRIDGE_DEVIO_SHORT) + devio_idx = xbridge_allocate_devio(sc, dev, 1); + if (devio_idx < 0) + devio_idx = xbridge_allocate_devio(sc, dev, 0); + } + + if (devio_idx >= 0) { base = (sc->sc_devio_skew << 24) | BRIDGE_DEVIO_OFFS(devio_idx); xbridge_set_devio(sc, devio_idx, devio | BRIDGE_DEVICE_IO_MEM | (base >> BRIDGE_DEVICE_BASE_SHIFT)); - memstart = base; - memend = base + BRIDGE_DEVIO_SIZE(devio_idx) - 1; - } - } else { - /* - * We know that the direct memory resource range fits - * within the 32 bit address space, and is limited to - * 30 bits, so our allocation, if successfull, will work - * as a 32 bit memory range. - */ - exsize = (*large_memex)->ex_end + 1 - (*large_memex)->ex_start; - if ((*large_memex)->ex_start == 1) - exsize++; - exsize /= BRIDGE_NSLOTS; - /* no need to round, exsize is >= 1 << 25 */ - - for (tries = 0; tries < 5; tries++) { - if (extent_alloc(*large_memex, exsize, - 1UL << 20, 0, 0, EX_NOWAIT | EX_MALLOCOK, - &exstart) == 0) { - memstart = exstart; - memend = exstart + exsize - 1; - break; + *memstart = base; + *memend = base + BRIDGE_DEVIO_SIZE(devio_idx) - 1; + } else { + /* + * We know that the direct memory resource range fits + * within the 32 bit address space, and is limited to + * 30 bits, so our allocation, if successfull, will + * work as a 32 bit memory range. + */ + if (exsize < 1UL << 20) + exsize = 1UL << 20; + for (tries = 0; tries < 5; tries++) { + if (extent_alloc(sc->sc_memex, exsize, + 1UL << 20, 0, 0, EX_NOWAIT | EX_MALLOCOK, + &exstart) == 0) { + *memstart = exstart; + *memend = exstart + exsize - 1; + break; + } + exsize >>= 1; + if (exsize < 1UL << 20) + break; } - exsize >>= 1; } } - if (*large_ioex == NULL) - *large_ioex = xbridge_mapping_setup(sc, 1); - if (*large_ioex == NULL) { - devio_idx = xbridge_allocate_devio(sc, dev, 1); - if (devio_idx < 0) + exsize = *ioend; + *iostart = 0xffffffff; + *ioend = 0; + if (exsize++ != 0) { + /* try to allocate through a devio slot whenever possible... */ + if (exsize < BRIDGE_DEVIO_SHORT) devio_idx = xbridge_allocate_devio(sc, dev, 0); - if (devio_idx < 0) { - /* no resources */ - } else { + else if (exsize < BRIDGE_DEVIO_LARGE) + devio_idx = xbridge_allocate_devio(sc, dev, 1); + else + devio_idx = -1; + + /* ...if it fails, try the large view.... */ + if (devio_idx < 0 && sc->sc_ioex == NULL) + sc->sc_ioex = xbridge_mapping_setup(sc, 1); + + /* ...if it is not available, try to get a devio slot anyway. */ + if (devio_idx < 0 && sc->sc_ioex == NULL) { + if (exsize > BRIDGE_DEVIO_SHORT) + devio_idx = xbridge_allocate_devio(sc, dev, 1); + if (devio_idx < 0) + devio_idx = xbridge_allocate_devio(sc, dev, 0); + } + + if (devio_idx >= 0) { base = (sc->sc_devio_skew << 24) | BRIDGE_DEVIO_OFFS(devio_idx); xbridge_set_devio(sc, devio_idx, devio | (base >> BRIDGE_DEVICE_BASE_SHIFT)); - iostart = base; - ioend = base + BRIDGE_DEVIO_SIZE(devio_idx) - 1; - } - } else { - /* - * We know that the direct I/O resource range fits - * within the 32 bit address space, so our allocation, - * if successfull, will work as a 32 bit i/o range. - */ - exsize = (*large_ioex)->ex_end + 1 - (*large_ioex)->ex_start; - if ((*large_ioex)->ex_start == 1) - exsize++; - exsize /= BRIDGE_NSLOTS; - /* no need to round, exsize is >= 1 << 25 */ - - for (tries = 0; tries < 5; tries++) { - if (extent_alloc(*large_ioex, exsize, - 1UL << 12, 0, 0, EX_NOWAIT | EX_MALLOCOK, - &exstart) == 0) { - iostart = exstart; - ioend = exstart + exsize - 1; - break; + *iostart = base; + *ioend = base + BRIDGE_DEVIO_SIZE(devio_idx) - 1; + } else { + /* + * We know that the direct I/O resource range fits + * within the 32 bit address space, so our allocation, + * if successfull, will work as a 32 bit i/o range. + */ + if (exsize < 1UL << 12) + exsize = 1UL << 12; + for (tries = 0; tries < 5; tries++) { + if (extent_alloc(sc->sc_ioex, exsize, + 1UL << 12, 0, 0, EX_NOWAIT | EX_MALLOCOK, + &exstart) == 0) { + *iostart = exstart; + *ioend = exstart + exsize - 1; + break; + } + exsize >>= 1; + if (exsize < 1UL << 12) + break; } - exsize >>= 1; } } - /* - * Finally program the bridge registers. - * - * We do not expect PCI-PCI bridges to be multifunction - * devices, so we'll only configure function #0. - */ - - tag = pci_make_tag(pc, 0, dev, 0); - ppb_initialize(pc, tag, secondary, subordinate, iostart, ioend, - memstart, memend); + return 0; } int |