summaryrefslogtreecommitdiff
path: root/sys
diff options
context:
space:
mode:
authorMiod Vallat <miod@cvs.openbsd.org>2009-07-16 21:02:59 +0000
committerMiod Vallat <miod@cvs.openbsd.org>2009-07-16 21:02:59 +0000
commit4fca826517a2f9595a073f0b0f2e9c47908be7fd (patch)
tree362295fb056eb6000279bf9f17503f6dd950f52d /sys
parentb12d022e613f07bd1838760bb15d583075c5ff91 (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-IP325
-rw-r--r--sys/arch/sgi/conf/RAMDISK-IP325
-rw-r--r--sys/arch/sgi/pci/macepcibridge.c239
-rw-r--r--sys/arch/sgi/pci/pci_machdep.c216
-rw-r--r--sys/arch/sgi/pci/pci_machdep.h8
-rw-r--r--sys/arch/sgi/xbow/xbridge.c292
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