diff options
author | Miod Vallat <miod@cvs.openbsd.org> | 2009-07-21 21:25:20 +0000 |
---|---|---|
committer | Miod Vallat <miod@cvs.openbsd.org> | 2009-07-21 21:25:20 +0000 |
commit | 99c98641e7aa8125661822dd134269b4fcabea53 (patch) | |
tree | a1ad683a8caf2139f654c58594f503f0cd7ec227 | |
parent | 2019cfde39e1ce5163fae9ccdc7b78d4b49de3bd (diff) |
PCI-Cardbus bridge support for both O2 (macepcibr) and Octane/Origin (xbridge)
class systems. Tested on O2 and Origin 200 with wi@pcmcia and xl@cardbus,
using a Ricoh 5C475-based cbb(4) board.
acx@cardbus doesn't work reliably yet, so your mileage may vary until more
bugs are fixed.
Thanks to matthieu@ for lending me some cardbus devices for testing.
-rw-r--r-- | sys/arch/sgi/conf/files.sgi | 8 | ||||
-rw-r--r-- | sys/arch/sgi/include/rbus_machdep.h | 60 | ||||
-rw-r--r-- | sys/arch/sgi/pci/macepcibridge.c | 162 | ||||
-rw-r--r-- | sys/arch/sgi/pci/pci_machdep.c | 34 | ||||
-rw-r--r-- | sys/arch/sgi/pci/pci_machdep.h | 15 | ||||
-rw-r--r-- | sys/arch/sgi/xbow/xbridge.c | 217 |
6 files changed, 433 insertions, 63 deletions
diff --git a/sys/arch/sgi/conf/files.sgi b/sys/arch/sgi/conf/files.sgi index 2ef7fb46583..cc554952376 100644 --- a/sys/arch/sgi/conf/files.sgi +++ b/sys/arch/sgi/conf/files.sgi @@ -1,4 +1,4 @@ -# $OpenBSD: files.sgi,v 1.29 2009/07/19 19:02:03 kettenis Exp $ +# $OpenBSD: files.sgi,v 1.30 2009/07/21 21:25:17 miod Exp $ # # maxpartitions must be first item in files.${ARCH} # @@ -158,6 +158,12 @@ include "dev/wsfont/files.wsfont" include "dev/wscons/files.wscons" # +# CardBus and PCMCIA bus support +# +include "dev/cardbus/files.cardbus" +include "dev/pcmcia/files.pcmcia" + +# # Machine-independent USB drivers # include "dev/usb/files.usb" diff --git a/sys/arch/sgi/include/rbus_machdep.h b/sys/arch/sgi/include/rbus_machdep.h new file mode 100644 index 00000000000..c98c66b0648 --- /dev/null +++ b/sys/arch/sgi/include/rbus_machdep.h @@ -0,0 +1,60 @@ +/* $OpenBSD: rbus_machdep.h,v 1.1 2009/07/21 21:25:19 miod Exp $ */ + +/* + * Copyright (c) 2009 Miodrag Vallat. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef _SGI_RBUS_MACHDEP_H_ +#define _SGI_RBUS_MACHDEP_H_ + +/* + * RBUS mapping routines + */ + +struct rb_md_fnptr { + int (*rbus_md_space_map)(bus_space_tag_t, bus_addr_t, bus_size_t, + int, bus_space_handle_t *); + void (*rbus_md_space_unmap)(bus_space_tag_t, bus_space_handle_t, + bus_size_t, bus_addr_t *); +}; + +static __inline__ int +md_space_map(rbus_tag_t rbt, u_long addr, bus_size_t size, int flags, + bus_space_handle_t *bshp) +{ + struct rb_md_fnptr *fn = (struct rb_md_fnptr *)rbt->rb_md; + + return (*fn->rbus_md_space_map)(rbt->rb_bt, (bus_addr_t)addr, size, + flags, bshp); +} + +static __inline__ void +md_space_unmap(rbus_tag_t rbt, bus_space_handle_t h, bus_size_t size, + bus_addr_t *addrp) +{ + struct rb_md_fnptr *fn = (struct rb_md_fnptr *)rbt->rb_md; + + (*fn->rbus_md_space_unmap)(rbt->rb_bt, h, size, addrp); +} + +/* + * PCCBB RBUS allocation routines (rbus_pccbb_parent_io, rbus_pccbb_parent_mem) + * are implemented in pci_machdep.h. + */ + +#define pccbb_attach_hook(parent, self, paa) \ + do { /* nothing */} while (/*CONSTCOND*/0) + +#endif /* _SGI_RBUS_MACHDEP_H_ */ diff --git a/sys/arch/sgi/pci/macepcibridge.c b/sys/arch/sgi/pci/macepcibridge.c index b1b0931590e..00842c04d51 100644 --- a/sys/arch/sgi/pci/macepcibridge.c +++ b/sys/arch/sgi/pci/macepcibridge.c @@ -1,4 +1,4 @@ -/* $OpenBSD: macepcibridge.c,v 1.25 2009/07/19 19:02:03 kettenis Exp $ */ +/* $OpenBSD: macepcibridge.c,v 1.26 2009/07/21 21:25:19 miod Exp $ */ /* * Copyright (c) 2001-2004 Opsycon AB (www.opsycon.se) @@ -49,11 +49,15 @@ #include <dev/pci/ppbreg.h> #include <dev/pci/pcidevs.h> +#include <dev/cardbus/rbus.h> + #include <mips64/archtype.h> #include <sgi/localbus/crimebus.h> #include <sgi/localbus/macebus.h> #include <sgi/pci/macepcibrvar.h> +#include "cardbus.h" + int mace_pcibrmatch(struct device *, void *, void *); void mace_pcibrattach(struct device *, struct device *, void *); @@ -69,16 +73,23 @@ const char *mace_pcibr_intr_string(void *, pci_intr_handle_t); void *mace_pcibr_intr_establish(void *, pci_intr_handle_t, int, int (*)(void *), void *, char *); void mace_pcibr_intr_disestablish(void *, void *); +int mace_pcibr_intr_line(void *, pci_intr_handle_t); +int mace_pcibr_ppb_setup(void *, pcitag_t, bus_addr_t *, bus_addr_t *, + bus_addr_t *, bus_addr_t *); +void *mace_pcibr_rbus_parent_io(struct pci_attach_args *); +void *mace_pcibr_rbus_parent_mem(struct pci_attach_args *); bus_addr_t mace_pcibr_pa_to_device(paddr_t); paddr_t mace_pcibr_device_to_pa(bus_addr_t); -int mace_pcibr_errintr(void *); +int mace_pcibr_rbus_space_map(bus_space_tag_t, bus_addr_t, bus_size_t, + int, bus_space_handle_t *); +void mace_pcibr_rbus_space_unmap(bus_space_tag_t, bus_space_handle_t, + bus_size_t, bus_addr_t *); -void mace_pcibr_configure(struct mace_pcibr_softc *); -void mace_pcibr_device_fixup(struct mace_pcibr_softc *, int, int); -int mace_pcibr_ppb_setup(void *, pcitag_t, bus_addr_t *, bus_addr_t *, - bus_addr_t *, bus_addr_t *); +void mace_pcibr_configure(struct mace_pcibr_softc *); +void mace_pcibr_device_fixup(struct mace_pcibr_softc *, int, int); +int mace_pcibr_errintr(void *); extern void pciaddr_remap(pci_chipset_tag_t); @@ -189,14 +200,6 @@ mace_pcibrattach(struct device *parent, struct device *self, void *aux) struct confargs *ca = aux; pcireg_t pcireg; - /* - * Common to all bridge chips. - */ - sc->sc_pc.pc_conf_v = sc; - sc->sc_pc.pc_attach_hook = mace_pcibr_attach_hook; - sc->sc_pc.pc_make_tag = mace_pcibr_make_tag; - sc->sc_pc.pc_decompose_tag = mace_pcibr_decompose_tag; - /* 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, @@ -228,16 +231,24 @@ mace_pcibrattach(struct device *parent, struct device *self, void *aux) macebus_intr_establish(NULL, 8, IST_LEVEL, IPL_HIGH, mace_pcibr_errintr, (void *)sc, sc->sc_dev.dv_xname); + sc->sc_pc.pc_conf_v = sc; + sc->sc_pc.pc_attach_hook = mace_pcibr_attach_hook; + sc->sc_pc.pc_make_tag = mace_pcibr_make_tag; + sc->sc_pc.pc_decompose_tag = mace_pcibr_decompose_tag; sc->sc_pc.pc_bus_maxdevs = mace_pcibr_bus_maxdevs; sc->sc_pc.pc_conf_read = mace_pcibr_conf_read; sc->sc_pc.pc_conf_write = mace_pcibr_conf_write; - sc->sc_pc.pc_intr_v = NULL; sc->sc_pc.pc_intr_map = mace_pcibr_intr_map; 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_intr_line = mace_pcibr_intr_line; sc->sc_pc.pc_ppb_setup = mace_pcibr_ppb_setup; +#if NCARDBUS > 0 + sc->sc_pc.pc_rbus_parent_io = mace_pcibr_rbus_parent_io; + sc->sc_pc.pc_rbus_parent_mem = mace_pcibr_rbus_parent_mem; +#endif /* * The O2 firmware sucks. It makes a mess off I/O BARs and @@ -457,6 +468,12 @@ mace_pcibr_intr_disestablish(void *lcv, void *cookie) macebus_intr_disestablish(lcv, cookie); } +int +mace_pcibr_intr_line(void *lcv, pci_intr_handle_t ih) +{ + return ih; +} + /* * Bus access primitives */ @@ -678,10 +695,10 @@ mace_pcibr_configure(struct mace_pcibr_softc *sc) pcitag_t tag; pcireg_t id, bhlcr; int dev, nfuncs; - uint curppb, nppb; + uint nppb, npccbb; const struct pci_quirkdata *qd; - nppb = 0; + nppb = npccbb = 0; for (dev = 0; dev < pci_bus_maxdevs(pc, 0); dev++) { tag = pci_make_tag(pc, 0, dev, 0); @@ -693,6 +710,8 @@ mace_pcibr_configure(struct mace_pcibr_softc *sc) bhlcr = pci_conf_read(pc, tag, PCI_BHLC_REG); if (PCI_HDRTYPE_TYPE(bhlcr) == 1) nppb++; + if (PCI_HDRTYPE_TYPE(bhlcr) == 2) + npccbb++; qd = pci_lookup_quirkdata(PCI_VENDOR(id), PCI_PRODUCT(id)); if (PCI_HDRTYPE_MULTIFN(bhlcr) || @@ -706,13 +725,12 @@ mace_pcibr_configure(struct mace_pcibr_softc *sc) /* * 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. + * up to one bridge (PCI-PCI or PCI-CardBus), which we'll map + * after the on-board device resources. */ - if (nppb != 1) + if (nppb + npccbb != 1) return; - curppb = 0; for (dev = 0; dev < pci_bus_maxdevs(pc, 0); dev++) { tag = pci_make_tag(pc, 0, dev, 0); @@ -722,12 +740,14 @@ mace_pcibr_configure(struct mace_pcibr_softc *sc) 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++; + switch (PCI_HDRTYPE_TYPE(bhlcr)) { + case 1: + ppb_initialize(pc, tag, 0, 1, 255); + break; + case 2: + pccbb_initialize(pc, tag, 0, 1, 1); + break; + } } } @@ -807,7 +827,7 @@ mace_pcibr_ppb_setup(void *cookie, pcitag_t tag, bus_addr_t *iostart, /* * Give all resources to the bridge. */ - *iostart = 0x01000000; + *iostart = 0x00010000; *ioend = MACE_PCI_IO_SIZE - *iostart; } else { *iostart = 0xffffffff; @@ -816,3 +836,89 @@ mace_pcibr_ppb_setup(void *cookie, pcitag_t tag, bus_addr_t *iostart, return 0; } + +#if NCARDBUS > 0 + +static struct rb_md_fnptr mace_pcibr_rb_md_fn = { + mace_pcibr_rbus_space_map, + mace_pcibr_rbus_space_unmap +}; + +int +mace_pcibr_rbus_space_map(bus_space_tag_t t, bus_addr_t addr, bus_size_t size, + int flags, bus_space_handle_t *bshp) +{ + return bus_space_map(t, addr, size, flags, bshp); +} + +void +mace_pcibr_rbus_space_unmap(bus_space_tag_t t, bus_space_handle_t h, + bus_size_t size, bus_addr_t *addrp) +{ + bus_addr_t sva; + bus_size_t off, len; + paddr_t paddr; + + /* should this verify that the proper size is freed? */ + sva = trunc_page(h); + off = h - sva; + len = size + off; + + if (pmap_extract(pmap_kernel(), h, &paddr) == 0) { + printf("bus_space_unmap: no pa for va %p\n", h); + *addrp = 0; /* XXX */ + return; + } + + if (extent_free(t->bus_extent, (u_long)paddr, size, + EX_NOWAIT | extent_malloc_flags)) { + printf("bus_space_map: pa %p, size %p\n", paddr, size); + printf("bus_space_map: can't free region\n"); + } + + *addrp = paddr - t->bus_base; + if (t->bus_base == MACE_PCI_MEM_BASE) + *addrp += 0x80000000; +} + +void * +mace_pcibr_rbus_parent_io(struct pci_attach_args *pa) +{ + rbus_tag_t rb; + bus_addr_t start, end; + + /* + * Give all resources to the CardBus bridge. + */ + + start = 0x2000; /* leave some I/O for ahc */ + end = 0x10000; + + rb = rbus_new_root_delegate(pa->pa_iot, start, end - start, 0); + if (rb != NULL) + rb->rb_md = &mace_pcibr_rb_md_fn; + + return rb; +} + +void * +mace_pcibr_rbus_parent_mem(struct pci_attach_args *pa) +{ + rbus_tag_t rb; + bus_addr_t start, end; + + /* + * Give all resources to the CardBus bridge. + */ + + start = 0x90000000; + end = 0x100000000UL; + + rb = rbus_new_root_delegate(pa->pa_memt, start, end - start, 0); + if (rb != NULL) + rb->rb_md = &mace_pcibr_rb_md_fn; + + return rb; +} + +#endif /* NCARDBUS > 0 */ diff --git a/sys/arch/sgi/pci/pci_machdep.c b/sys/arch/sgi/pci/pci_machdep.c index d252e4b6b0d..76ccc4fb76a 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.3 2009/07/16 21:52:22 miod Exp $ */ +/* $OpenBSD: pci_machdep.c,v 1.4 2009/07/21 21:25:19 miod Exp $ */ /* * Copyright (c) 2009 Miodrag Vallat. @@ -24,6 +24,7 @@ #include <dev/pci/pcireg.h> #include <dev/pci/pcivar.h> +#include <dev/pci/pccbbreg.h> #include <dev/pci/ppbreg.h> #include <dev/pci/pcidevs.h> @@ -36,8 +37,8 @@ void ppb_function_explore(pci_chipset_tag_t, pcitag_t, struct extent *, * Configure a PCI-PCI bridge. */ void -ppb_initialize(pci_chipset_tag_t pc, pcitag_t ppbtag, uint secondary, - uint subordinate) +ppb_initialize(pci_chipset_tag_t pc, pcitag_t ppbtag, uint primary, + uint secondary, uint subordinate) { int dev, nfuncs; pcireg_t id, csr, bhlcr; @@ -62,7 +63,7 @@ ppb_initialize(pci_chipset_tag_t pc, pcitag_t ppbtag, uint secondary, pci_conf_write(pc, ppbtag, PCI_COMMAND_STATUS_REG, csr); pci_conf_write(pc, ppbtag, PPB_REG_BUSINFO, - (secondary << 8) | (subordinate << 16)); + primary | (secondary << 8) | (subordinate << 16)); ioex = extent_create("ppb_io", 0, 0xffffffff, M_DEVBUF, NULL, 0, EX_NOWAIT); @@ -238,3 +239,28 @@ ppb_function_explore(pci_chipset_tag_t pc, pcitag_t tag, struct extent *ioex, * bridges behind PCI-PCI bridges. */ } + +/* + * Configure a PCI-CardBus bridge. + */ +void +pccbb_initialize(pci_chipset_tag_t pc, pcitag_t tag, uint primary, + uint secondary, uint subordinate) +{ + pcireg_t csr; + + csr = pci_conf_read(pc, tag, PCI_COMMAND_STATUS_REG); + csr &= ~(PCI_COMMAND_IO_ENABLE | PCI_COMMAND_MEM_ENABLE); + pci_conf_write(pc, tag, PCI_COMMAND_STATUS_REG, csr); + + pci_conf_write(pc, tag, PCI_BUSNUM, + primary | (secondary << 8) | (subordinate << 16)); + +#if 0 /* done by pccbb(4) */ + csr |= PCI_COMMAND_IO_ENABLE; + csr |= PCI_COMMAND_MEM_ENABLE; + + pci_conf_write(pc, tag, PCI_COMMAND_STATUS_REG, csr | + PCI_COMMAND_MASTER_ENABLE); +#endif +} diff --git a/sys/arch/sgi/pci/pci_machdep.h b/sys/arch/sgi/pci/pci_machdep.h index f3c89613d19..48a455213f9 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.6 2009/07/16 21:02:56 miod Exp $ */ +/* $OpenBSD: pci_machdep.h,v 1.7 2009/07/21 21:25:19 miod Exp $ */ /* * Copyright (c) 2003-2004 Opsycon AB (www.opsycon.se / www.opsycon.com) @@ -52,9 +52,13 @@ 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_intr_line)(void *, pci_intr_handle_t); int (*pc_ppb_setup)(void *, pcitag_t, bus_addr_t *, bus_addr_t *, bus_addr_t *, bus_addr_t *); + + void *(*pc_rbus_parent_io)(struct pci_attach_args *); + void *(*pc_rbus_parent_mem)(struct pci_attach_args *); }; /* @@ -80,5 +84,12 @@ struct mips_pci_chipset { (*(c)->pc_intr_establish)((c)->pc_intr_v, (ih), (l), (h), (a), (nm)) #define pci_intr_disestablish(c, iv) \ (*(c)->pc_intr_disestablish)((c)->pc_intr_v, (iv)) +#define pci_intr_line(c, ih) \ + (*(c)->pc_intr_line)((c)->pc_intr_v, (ih)) +#define rbus_pccbb_parent_io(dev, pa) \ + (rbus_tag_t)((*(pa)->pa_pc->pc_rbus_parent_io)(pa)) +#define rbus_pccbb_parent_mem(dev, pa) \ + (rbus_tag_t)((*(pa)->pa_pc->pc_rbus_parent_mem)(pa)) -void ppb_initialize(pci_chipset_tag_t, pcitag_t, uint, uint); +void pccbb_initialize(pci_chipset_tag_t, pcitag_t, uint, uint, uint); +void ppb_initialize(pci_chipset_tag_t, pcitag_t, uint, uint, uint); diff --git a/sys/arch/sgi/xbow/xbridge.c b/sys/arch/sgi/xbow/xbridge.c index 02716007602..b47a721d204 100644 --- a/sys/arch/sgi/xbow/xbridge.c +++ b/sys/arch/sgi/xbow/xbridge.c @@ -1,4 +1,4 @@ -/* $OpenBSD: xbridge.c,v 1.39 2009/07/18 16:38:49 miod Exp $ */ +/* $OpenBSD: xbridge.c,v 1.40 2009/07/21 21:25:19 miod Exp $ */ /* * Copyright (c) 2008, 2009 Miodrag Vallat. @@ -51,6 +51,8 @@ #include <dev/pci/pcidevs.h> #include <dev/pci/ppbreg.h> +#include <dev/cardbus/rbus.h> + #include <mips64/archtype.h> #include <sgi/xbow/hub.h> #include <sgi/xbow/xbow.h> @@ -60,6 +62,8 @@ #include <sgi/sgi/ip30.h> +#include "cardbus.h" + int xbridge_match(struct device *, void *, void *); void xbridge_attach(struct device *, struct device *, void *); int xbridge_print(void *, const char *); @@ -139,8 +143,11 @@ 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_intr_line(void *, pci_intr_handle_t); int xbridge_ppb_setup(void *, pcitag_t, bus_addr_t *, bus_addr_t *, bus_addr_t *, bus_addr_t *); +void *xbridge_rbus_parent_io(struct pci_attach_args *); +void *xbridge_rbus_parent_mem(struct pci_attach_args *); int xbridge_intr_handler(void *); @@ -178,6 +185,11 @@ int xbridge_dmamem_alloc(bus_dma_tag_t, bus_size_t, bus_size_t, bus_size_t, bus_addr_t xbridge_pa_to_device(paddr_t); paddr_t xbridge_device_to_pa(bus_addr_t); +int xbridge_rbus_space_map(bus_space_tag_t, bus_addr_t, bus_size_t, + int, bus_space_handle_t *); +void xbridge_rbus_space_unmap(bus_space_tag_t, bus_space_handle_t, + bus_size_t, bus_addr_t *); + int xbridge_address_map(struct xbridge_softc *, paddr_t, bus_addr_t *, bus_addr_t *); void xbridge_address_unmap(struct xbridge_softc *, bus_addr_t, bus_size_t); @@ -345,7 +357,12 @@ 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_intr_line = xbridge_intr_line; sc->sc_pc.pc_ppb_setup = xbridge_ppb_setup; +#if NCARDBUS > 0 + sc->sc_pc.pc_rbus_parent_io = xbridge_rbus_parent_io; + sc->sc_pc.pc_rbus_parent_mem = xbridge_rbus_parent_mem; +#endif /* * Configure Bridge for proper operation (DMA, I/O mappings, @@ -787,6 +804,12 @@ xbridge_intr_disestablish(void *cookie, void *vih) } int +xbridge_intr_line(void *cookie, pci_intr_handle_t ih) +{ + return XBRIDGE_INTR_BIT(ih); +} + +int xbridge_intr_handler(void *v) { struct xbridge_intr *xi = (struct xbridge_intr *)v; @@ -1833,7 +1856,7 @@ xbridge_resource_setup(struct xbridge_softc *sc) pcireg_t id, bhlcr; uint32_t devio; int need_setup; - uint secondary, nppb, ppbstride; + uint secondary, nppb, npccbb, ppbstride; const struct pci_quirkdata *qd; /* @@ -1863,7 +1886,7 @@ xbridge_resource_setup(struct xbridge_softc *sc) * Configure all regular PCI devices. */ - nppb = 0; + nppb = npccbb = 0; for (dev = 0; dev < BRIDGE_NSLOTS; dev++) { id = sc->sc_devices[dev].id; @@ -1871,13 +1894,15 @@ xbridge_resource_setup(struct xbridge_softc *sc) continue; /* - * Count ppb devices, we will need their number later. + * Count ppb and pccbb devices, we will need their number later. */ tag = pci_make_tag(pc, 0, dev, 0); bhlcr = pci_conf_read(pc, tag, PCI_BHLC_REG); if (PCI_HDRTYPE_TYPE(bhlcr) == 1) nppb++; + if (PCI_HDRTYPE_TYPE(bhlcr) == 2) + npccbb++; /* * We want to avoid changing mapping configuration for @@ -1962,31 +1987,49 @@ xbridge_resource_setup(struct xbridge_softc *sc) } /* - * Configure PCI-PCI bridges, if any. + * Configure PCI-PCI and PCI-CardBus bridges, if any. * * We do this after all the other PCI devices have been configured * in order to favour them during resource allocation. */ - secondary = 1; + if (npccbb != 0) { + /* + * If there are PCI-CardBus bridges, we really want to be + * able to have large resource spaces... + */ + if (sc->sc_ioex == NULL) + sc->sc_ioex = xbridge_mapping_setup(sc, 1); + if (sc->sc_memex == NULL) + sc->sc_memex = xbridge_mapping_setup(sc, 0); + } - if (nppb != 0) { - ppbstride = (256 - secondary) / nppb; - for (dev = 0; dev < BRIDGE_NSLOTS; dev++) { - id = sc->sc_devices[dev].id; + secondary = 1; + ppbstride = nppb == 0 ? 0 : (255 - npccbb) / nppb; + for (dev = 0; dev < BRIDGE_NSLOTS; dev++) { + id = sc->sc_devices[dev].id; - if (PCI_VENDOR(id) == PCI_VENDOR_INVALID || - PCI_VENDOR(id) == 0) - continue; + if (PCI_VENDOR(id) == PCI_VENDOR_INVALID || PCI_VENDOR(id) == 0) + continue; - tag = pci_make_tag(pc, 0, dev, 0); - bhlcr = pci_conf_read(pc, tag, PCI_BHLC_REG); + tag = pci_make_tag(pc, 0, dev, 0); + bhlcr = pci_conf_read(pc, tag, PCI_BHLC_REG); - if (PCI_HDRTYPE_TYPE(bhlcr) == 1) { - ppb_initialize(pc, tag, secondary, - secondary + ppbstride - 1); - secondary += ppbstride; - } + switch (PCI_HDRTYPE_TYPE(bhlcr)) { + case 1: /* PCI-PCI bridge */ + ppb_initialize(pc, tag, 0, secondary, + secondary + ppbstride - 1); + secondary += ppbstride; + break; + case 2: /* PCI-CardBus bridge */ + /* + * We do not expect cardbus devices to sport + * PCI-PCI bridges themselves, so only one + * PCI bus will do. + */ + pccbb_initialize(pc, tag, 0, secondary, secondary); + secondary++; + break; } } @@ -2010,7 +2053,7 @@ xbridge_extent_setup(struct xbridge_softc *sc) { int dev; int errors; - bus_addr_t start; + bus_addr_t start, end; uint32_t devio; snprintf(sc->sc_ioexname, sizeof(sc->sc_ioexname), "%s_io", @@ -2039,6 +2082,15 @@ xbridge_extent_setup(struct xbridge_softc *sc) } /* ...as well as the large views, if any */ if (sc->sc_ioend != 0) { + start = sc->sc_iostart; + if (start == 0) + start = 1; + end = sc->sc_devio_skew << 24; + if (start < end) + if (extent_free(sc->sc_ioex, start, + end, EX_NOWAIT) != 0) + errors++; + start = (sc->sc_devio_skew + 1) << 24; if (start < sc->sc_iostart) start = sc->sc_iostart; @@ -2077,6 +2129,15 @@ xbridge_extent_setup(struct xbridge_softc *sc) } /* ...as well as the large views, if any */ if (sc->sc_memend != 0) { + start = sc->sc_memstart; + if (start == 0) + start = 1; + end = sc->sc_devio_skew << 24; + if (start < end) + if (extent_free(sc->sc_memex, start, + end, EX_NOWAIT) != 0) + errors++; + start = (sc->sc_devio_skew + 1) << 24; if (start < sc->sc_memstart) start = sc->sc_memstart; @@ -2188,21 +2249,20 @@ xbridge_mapping_setup(struct xbridge_softc *sc, int io) if (ex != NULL) { /* * Remove the devio mapping range from the extent - * to avoid ambiguous mappings (all addresses under - * the devio area need to be expelled). + * to avoid ambiguous mappings. * * Note that xbow_widget_map_space() may have returned * a range in which the devio area does not appear. */ - start = 0; - end = ((sc->sc_devio_skew + 1) << 24) - 1; + start = sc->sc_devio_skew << 24; + end = (sc->sc_devio_skew + 1) << 24; if (end >= ex->ex_start && start <= ex->ex_end) { if (start < ex->ex_start) start = ex->ex_start; - if (end > ex->ex_end) - end = ex->ex_end; - if (extent_alloc_region(ex, start, end - start + 1, + if (end > ex->ex_end + 1) + end = ex->ex_end + 1; + if (extent_alloc_region(ex, start, end - start, EX_NOWAIT | EX_MALLOCOK) != 0) { printf("%s: failed to expurge devio range" " from %s large extent\n", @@ -2665,6 +2725,107 @@ xbridge_ppb_setup(void *cookie, pcitag_t tag, bus_addr_t *iostart, return 0; } +#if NCARDBUS > 0 + +static struct rb_md_fnptr xbridge_rb_md_fn = { + xbridge_rbus_space_map, + xbridge_rbus_space_unmap +}; + +int +xbridge_rbus_space_map(bus_space_tag_t t, bus_addr_t addr, bus_size_t size, + int flags, bus_space_handle_t *bshp) +{ + return bus_space_map(t, addr, size, flags, bshp); +} + +void +xbridge_rbus_space_unmap(bus_space_tag_t t, bus_space_handle_t h, + bus_size_t size, bus_addr_t *addrp) +{ + bus_space_unmap(t, h, size); + *addrp = h - t->bus_base; +} + +void * +xbridge_rbus_parent_io(struct pci_attach_args *pa) +{ + struct extent *ex = pa->pa_ioex; + bus_addr_t start, end; + rbus_tag_t rb = NULL; + + /* + * We want to force I/O mappings to lie in the low 16 bits + * area. This is mandatory for 16-bit pcmcia devices; and + * although 32-bit cardbus devices could use a larger range, + * the pccbb driver doesn't enable the large I/O windows. + */ + if (ex != NULL) { + start = 0; + end = 0x10000; + if (start < ex->ex_start) + start = ex->ex_start; + if (end > ex->ex_end) + end = ex->ex_end; + + if (start < end) { + rb = rbus_new_root_share(pa->pa_iot, ex, + start, end - start, 0); + if (rb != NULL) + rb->rb_md = &xbridge_rb_md_fn; + } + } + + /* + * We are not allowed to return NULL. If we can't provide + * resources, return a valid body which will fail requests. + */ + if (rb == NULL) + rb = rbus_new_body(pa->pa_iot, NULL, NULL, 0, 0, 0, + RBUS_SPACE_INVALID); + + return rb; +} + +void * +xbridge_rbus_parent_mem(struct pci_attach_args *pa) +{ + struct xbridge_softc *sc = pa->pa_pc->pc_conf_v; + struct extent *ex = pa->pa_memex; + bus_addr_t start; + rbus_tag_t rb = NULL; + + /* + * There is no restriction for the memory mappings, + * however we need to make sure these won't hit the + * devio range (for md_space_unmap to work correctly). + */ + if (ex != NULL) { + start = (sc->sc_devio_skew + 1) << 24; + if (start < ex->ex_start) + start = ex->ex_start; + + if (start < ex->ex_end) { + rb = rbus_new_root_share(pa->pa_memt, ex, + start, ex->ex_end - start, 0); + if (rb != NULL) + rb->rb_md = &xbridge_rb_md_fn; + } + } + + /* + * We are not allowed to return NULL. If we can't provide + * resources, return a valid body which will fail requests. + */ + if (rb == NULL) + rb = rbus_new_body(pa->pa_iot, NULL, NULL, 0, 0, 0, + RBUS_SPACE_INVALID); + + return rb; +} + +#endif /* NCARDBUS > 0 */ + int xbridge_allocate_devio(struct xbridge_softc *sc, int dev, int wantlarge) { |