summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMiod Vallat <miod@cvs.openbsd.org>2009-07-21 21:25:20 +0000
committerMiod Vallat <miod@cvs.openbsd.org>2009-07-21 21:25:20 +0000
commit99c98641e7aa8125661822dd134269b4fcabea53 (patch)
treea1ad683a8caf2139f654c58594f503f0cd7ec227
parent2019cfde39e1ce5163fae9ccdc7b78d4b49de3bd (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.sgi8
-rw-r--r--sys/arch/sgi/include/rbus_machdep.h60
-rw-r--r--sys/arch/sgi/pci/macepcibridge.c162
-rw-r--r--sys/arch/sgi/pci/pci_machdep.c34
-rw-r--r--sys/arch/sgi/pci/pci_machdep.h15
-rw-r--r--sys/arch/sgi/xbow/xbridge.c217
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)
{