summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authormiod <miod@openbsd.org>2009-07-06 22:46:40 +0000
committermiod <miod@openbsd.org>2009-07-06 22:46:40 +0000
commit4081a62a5831318d5c64d75dabde9ccb7fe2c425 (patch)
tree56887d85d55bd61c6ddead15f27ab25295343ef0
parentremove unused WDEPCOL warning that became unused in 1.7.19 (diff)
downloadwireguard-openbsd-4081a62a5831318d5c64d75dabde9ccb7fe2c425.tar.xz
wireguard-openbsd-4081a62a5831318d5c64d75dabde9ccb7fe2c425.zip
Almost rewrite xbridge PCI resource allocation:
- introduce an interface for widget drivers to ask the xbow to map arbitrary views of their address space, in addition to the low 16MB. This operation may fail or map a subset range of what the caller asked for, depending on the platform we're running on. - use this in xbridge to set up views on the direct memory and i/o spaces, to map devices resources when they don't fit in one of the devio small ranges (limited to 2MB anyway). These views are only allocated when devio can't do the job, so as not to consume too many resources on Origin family systems where such views are scarce resources (and shared accross the whole crossbow). This makes pci devices with large resource needs configure correctly. While there, fix programming of 64 bit memory BAR; this makes bge(4) work. Tested on Octane (with Bridge revision < 4 and >= 4), Origin 200 (Bridge >= 4) and Fuel (XBridge). ok deraadt@
-rw-r--r--sys/arch/sgi/include/mnode.h4
-rw-r--r--sys/arch/sgi/sgi/ip27_machdep.c119
-rw-r--r--sys/arch/sgi/sgi/ip30_machdep.c22
-rw-r--r--sys/arch/sgi/sgi/sginode.c9
-rw-r--r--sys/arch/sgi/xbow/hub.h72
-rw-r--r--sys/arch/sgi/xbow/xbow.c29
-rw-r--r--sys/arch/sgi/xbow/xbow.h16
-rw-r--r--sys/arch/sgi/xbow/xbridge.c598
-rw-r--r--sys/arch/sgi/xbow/xbridgereg.h15
9 files changed, 637 insertions, 247 deletions
diff --git a/sys/arch/sgi/include/mnode.h b/sys/arch/sgi/include/mnode.h
index 9d628c38203..65bfec9c657 100644
--- a/sys/arch/sgi/include/mnode.h
+++ b/sys/arch/sgi/include/mnode.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: mnode.h,v 1.7 2009/06/13 18:47:30 miod Exp $ */
+/* $OpenBSD: mnode.h,v 1.8 2009/07/06 22:46:40 miod Exp $ */
/*
* Copyright (c) 2004 Opsycon AB (www.opsycon.se / www.opsycon.com)
@@ -392,7 +392,7 @@ typedef struct gda {
*/
vaddr_t kl_get_console_base(void);
-void kl_init(uint64_t);
+void kl_init(int);
void kl_scan_config(int);
void kl_scan_done(void);
int kl_scan_node(int, uint, int (*)(lboard_t *, void *), void *);
diff --git a/sys/arch/sgi/sgi/ip27_machdep.c b/sys/arch/sgi/sgi/ip27_machdep.c
index b4a3164d567..081ce363da6 100644
--- a/sys/arch/sgi/sgi/ip27_machdep.c
+++ b/sys/arch/sgi/sgi/ip27_machdep.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: ip27_machdep.c,v 1.15 2009/07/01 21:56:38 miod Exp $ */
+/* $OpenBSD: ip27_machdep.c,v 1.16 2009/07/06 22:46:43 miod Exp $ */
/*
* Copyright (c) 2008, 2009 Miodrag Vallat.
@@ -51,6 +51,7 @@ extern void (*md_halt)(int);
paddr_t ip27_widget_short(int16_t, u_int);
paddr_t ip27_widget_long(int16_t, u_int);
+paddr_t ip27_widget_map(int16_t, u_int,bus_addr_t *, bus_size_t *);
int ip27_widget_id(int16_t, u_int, uint32_t *);
void ip27_halt(int);
@@ -87,6 +88,7 @@ ip27_setup()
ip35 = sys_config.system_type == SGI_O300;
xbow_widget_base = ip27_widget_short;
+ xbow_widget_map = ip27_widget_map;
xbow_widget_id = ip27_widget_id;
md_halt = ip27_halt;
@@ -96,7 +98,7 @@ ip27_setup()
* or N mode.
*/
- kl_init(ip35 ? HUBNI_IP35 : HUBNI_IP27);
+ kl_init(ip35);
if (kl_n_mode != 0)
xbow_long_shift = 28;
@@ -261,16 +263,105 @@ ip27_widget_short(int16_t nasid, u_int widget)
* big window #6 (the last programmable big window).
*/
if (widget == 0)
- return ip27_widget_long(nasid, 6);
+ return ip27_widget_long(nasid, IOTTE_SWIN0);
- return ((uint64_t)(widget) << 24) | ((uint64_t)(nasid) << 32) | io_base;
+ return ((uint64_t)(widget) << 24) |
+ ((uint64_t)(nasid) << kl_n_shift) | io_base;
}
paddr_t
-ip27_widget_long(int16_t nasid, u_int widget)
+ip27_widget_long(int16_t nasid, u_int window)
{
- return ((uint64_t)(widget + 1) << xbow_long_shift) |
- ((uint64_t)(nasid) << 32) | io_base;
+ return ((uint64_t)(window + 1) << xbow_long_shift) |
+ ((uint64_t)(nasid) << kl_n_shift) | io_base;
+}
+
+paddr_t
+ip27_widget_map(int16_t nasid, u_int widget, bus_addr_t *offs, bus_size_t *len)
+{
+ uint tte, avail_tte;
+ uint64_t iotte;
+ paddr_t delta, start, end;
+ int s;
+
+ /*
+ * On Origin systems, we can only have partial views of the widget
+ * address space, due to the addressing scheme limiting each node's
+ * address space to 31 to 33 bits.
+ *
+ * The largest window is 256MB or 512MB large, depending on the
+ * mode the system is in (M/N).
+ */
+
+ /*
+ * Round the requested range to a large window boundary.
+ */
+
+ start = *offs;
+ end = start + *len;
+
+ start = (start >> xbow_long_shift);
+ end = (end + (1 << xbow_long_shift) - 1) >> xbow_long_shift;
+
+ /*
+ * See if an existing IOTTE covers part of the mapping we are asking
+ * for. If so, reuse it and truncate the caller's range.
+ */
+
+ s = splhigh(); /* XXX or disable interrupts completely? */
+
+ avail_tte = IOTTE_MAX;
+ for (tte = 0; tte < IOTTE_MAX; tte++) {
+ if (tte == IOTTE_SWIN0)
+ continue;
+
+ iotte = IP27_RHUB_L(nasid, HUBIOBASE + HUBIO_IOTTE(tte));
+ if (IOTTE_WIDGET(iotte) == 0) {
+ if (avail_tte == IOTTE_MAX)
+ avail_tte = tte;
+ continue;
+ }
+ if (IOTTE_WIDGET(iotte) != widget)
+ continue;
+
+ if (IOTTE_OFFSET(iotte) < start ||
+ (IOTTE_OFFSET(iotte) + 1) >= end)
+ continue;
+
+ /*
+ * We found a matching IOTTE (an exact match if we asked for
+ * less than the large window size, a partial match otherwise).
+ * Reuse it (since we never unmap IOTTE at this point, there
+ * is no need to maintain a reference count).
+ */
+ break;
+ }
+
+ /*
+ * If we found an unused IOTTE while searching above, program it
+ * to map the beginning of the requested range.
+ */
+
+ if (tte == IOTTE_MAX && avail_tte != IOTTE_MAX) {
+ tte = avail_tte;
+
+ /* XXX I don't understand why it's not device space. */
+ iotte = IOTTE(IOTTE_SPACE_MEMORY, widget, start);
+ IP27_RHUB_S(nasid, HUBIOBASE + HUBIO_IOTTE(tte), iotte);
+ (void)IP27_RHUB_L(nasid, HUBIOBASE + HUBIO_IOTTE(tte));
+ }
+
+ splx(s);
+
+ if (tte != IOTTE_MAX) {
+ delta = *offs - (start << xbow_long_shift);
+ /* *offs unmodified */
+ *len = (1 << xbow_long_shift) - delta;
+
+ return ip27_widget_long(nasid, tte) + delta;
+ }
+
+ return 0UL;
}
/*
@@ -319,13 +410,15 @@ ip27_halt(int howto)
return; /* caller will spin */
if (ip35) {
- IP27_LHUB_S(HUBNI_IP35 + HUBNI_RESET_ENABLE, NI_RESET_ENABLE);
- IP27_LHUB_S(HUBNI_IP35 + HUBNI_RESET,
- NI_RESET_LOCAL | NI_RESET_ACTION);
+ IP27_LHUB_S(HUBNIBASE_IP35 + HUBNI_RESET_ENABLE,
+ NI_RESET_ENABLE);
+ IP27_LHUB_S(HUBNIBASE_IP35 + HUBNI_RESET,
+ NI_RESET_LOCAL_IP35 | NI_RESET_ACTION_IP35);
} else {
- IP27_LHUB_S(HUBNI_IP27 + HUBNI_RESET_ENABLE, NI_RESET_ENABLE);
- IP27_LHUB_S(HUBNI_IP27 + HUBNI_RESET,
- NI_RESET_LOCAL | NI_RESET_ACTION);
+ IP27_LHUB_S(HUBNIBASE_IP27 + HUBNI_RESET_ENABLE,
+ NI_RESET_ENABLE);
+ IP27_LHUB_S(HUBNIBASE_IP27 + HUBNI_RESET,
+ NI_RESET_LOCAL_IP27 | NI_RESET_ACTION_IP27);
}
}
diff --git a/sys/arch/sgi/sgi/ip30_machdep.c b/sys/arch/sgi/sgi/ip30_machdep.c
index ef53cf1c1ac..768d5e550b9 100644
--- a/sys/arch/sgi/sgi/ip30_machdep.c
+++ b/sys/arch/sgi/sgi/ip30_machdep.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: ip30_machdep.c,v 1.7 2009/07/01 21:56:38 miod Exp $ */
+/* $OpenBSD: ip30_machdep.c,v 1.8 2009/07/06 22:46:43 miod Exp $ */
/*
* Copyright (c) 2008 Miodrag Vallat.
@@ -45,6 +45,7 @@
paddr_t ip30_widget_short(int16_t, u_int);
paddr_t ip30_widget_long(int16_t, u_int);
+paddr_t ip30_widget_map(int16_t, u_int, bus_addr_t *, bus_size_t *);
int ip30_widget_id(int16_t, u_int, uint32_t *);
void
@@ -94,6 +95,7 @@ ip30_setup()
#endif
xbow_widget_base = ip30_widget_short;
+ xbow_widget_map = ip30_widget_map;
xbow_widget_id = ip30_widget_id;
/*
@@ -111,7 +113,8 @@ ip30_setup()
* may consider this an evil abuse of bus_space knowledge, though.
*/
xbow_build_bus_space(&sys_config.console_io, 0, 15);
- sys_config.console_io.bus_base = ip30_widget_short(0, 15);
+ sys_config.console_io.bus_base = ip30_widget_long(0, 15) +
+ BRIDGE_PCI_MEM_SPACE_BASE;
comconsaddr = 0x500000 + IOC3_UARTA_BASE;
comconsfreq = 22000000 / 3;
@@ -135,6 +138,21 @@ ip30_widget_long(int16_t nasid, u_int widget)
return ((uint64_t)(widget) << 36) | uncached_base;
}
+paddr_t
+ip30_widget_map(int16_t nasid, u_int widget, bus_addr_t *offs, bus_size_t *len)
+{
+ paddr_t base;
+
+ /*
+ * On Octane, the whole widget space is always accessible.
+ */
+
+ base = ip30_widget_long(nasid, widget);
+ *len = (1ULL << 36) - *offs;
+
+ return base + *offs;
+}
+
/*
* Widget enumeration
*/
diff --git a/sys/arch/sgi/sgi/sginode.c b/sys/arch/sgi/sgi/sginode.c
index 9f3191d16f0..258f3acd107 100644
--- a/sys/arch/sgi/sgi/sginode.c
+++ b/sys/arch/sgi/sgi/sginode.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: sginode.c,v 1.10 2009/06/21 18:04:41 miod Exp $ */
+/* $OpenBSD: sginode.c,v 1.11 2009/07/06 22:46:43 miod Exp $ */
/*
* Copyright (c) 2008, 2009 Miodrag Vallat.
*
@@ -72,10 +72,11 @@ int kl_n_mode = 0;
u_int kl_n_shift = 32;
void
-kl_init(uint64_t nibase)
+kl_init(int ip35)
{
kl_config_hdr_t *cfghdr;
- u_int64_t val;
+ uint64_t val;
+ uint64_t nibase = ip35 ? HUBNIBASE_IP35 : HUBNIBASE_IP27;
/* will be recomputed when processing memory information */
physmem = 0;
@@ -88,7 +89,7 @@ kl_init(uint64_t nibase)
val = IP27_LHUB_L(nibase | HUBNI_STATUS);
kl_n_mode = (val & NI_MORENODES) != 0;
- kl_n_shift = 32 - kl_n_mode;
+ kl_n_shift = (ip35 ? 33 : 32) - kl_n_mode;
bios_printf("Machine is in %c mode.\n", kl_n_mode + 'M');
val = IP27_LHUB_L(HUBPI_REGION_PRESENT);
diff --git a/sys/arch/sgi/xbow/hub.h b/sys/arch/sgi/xbow/hub.h
index 43b05e70432..a1754183e55 100644
--- a/sys/arch/sgi/xbow/hub.h
+++ b/sys/arch/sgi/xbow/hub.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: hub.h,v 1.3 2009/06/13 16:28:11 miod Exp $ */
+/* $OpenBSD: hub.h,v 1.4 2009/07/06 22:46:43 miod Exp $ */
/*
* Copyright (c) 2009 Miodrag Vallat.
@@ -30,12 +30,13 @@
#define IP27_RHUB_ADDR(_n, _x) \
((volatile uint64_t *)(NODE_LWIN_BASE(_n, 1) + 0x800000 + (_x)))
#define IP27_RHUB_PI_ADDR(_n, _sn, _x) \
- ((volatile uint64_t *)(NODE_LWIN_BASE(_n, 1) + 0x800000 + (_x)))
+ ((volatile uint64_t *)(NODE_LWIN_BASE(_n, 1) + 0x800000 + \
+ ((_sn) ? HUBPI_OFFSET : 0) + (_x)))
#define IP27_LHUB_L(r) *(IP27_LHUB_ADDR(r))
#define IP27_LHUB_S(r, d) *(IP27_LHUB_ADDR(r)) = (d)
-#define IP27_RHUB_L(n, r) *(IP27_RHUB_ADDR((n), (r))
-#define IP27_RHUB_S(n, r, d) *(IP27_RHUB_ADDR((n), (r)) = (d)
+#define IP27_RHUB_L(n, r) *(IP27_RHUB_ADDR((n), (r)))
+#define IP27_RHUB_S(n, r, d) *(IP27_RHUB_ADDR((n), (r))) = (d)
#define IP27_RHUB_PI_L(n, s, r) *(IP27_RHUB_PI_ADDR((n), (s), (r)))
#define IP27_RHUB_PI_S(n, s, r, d) *(IP27_RHUB_PI_ADDR((n), (s), (r))) = (d)
@@ -48,9 +49,11 @@
*/
/*
- * HUB PI
+ * HUB PI - Processor Interface
*/
+#define HUBPIBASE 0x00000000
+
#define HUBPI_REGION_PRESENT 0x00000018
#define HUBPI_CPU_NUMBER 0x00000020
#define HUBPI_CALIAS_SIZE 0x00000028
@@ -72,19 +75,66 @@
#define HUBPI_CPU1_IMR0 0x000000b8
#define HUBPI_CPU1_IMR1 0x000000c0
+/*
+ * Offset to use to access the second PI over the remote hub interface
+ * on IP35.
+ */
+#define HUBPI_OFFSET 0x00200000
+
+/*
+ * HUB MD - Memory/Directory
+ */
+
+#define HUBMDBASE_IP27 0x00200000
+#define HUBMDBASE_IP35 0x00780000
+
+
+/*
+ * HUB IO - Widget I/O
+ */
+
+#define HUBIOBASE 0x00400000
+
+#define HUBIO_IOTTE(x) (0x00000160 + (x) * 8)
+#define IOTTE_MAX 7
+#define IOTTE_SWIN0 (IOTTE_MAX - 1)
+
+#define IOTTE(space,widget,offset) \
+ (((space) << 12) | ((widget) << 8) | (offset))
+#define IOTTE_SPACE_DEVICE 1
+#define IOTTE_SPACE_MEMORY 0
+#define IOTTE_SPACE(iotte) (((iotte) >> 12) & 0x01)
+#define IOTTE_WIDGET(iotte) (((iotte) >> 8) & 0x0f)
+#define IOTTE_OFFSET(iotte) ((iotte) & 0xff)
+
+
+/*
+ * HUB LB - Local Bedrock
+ */
+
+#define HUBLBBASE_IP35 0x00600000
/*
- * HUB NI
+ * HUB NI - Network Interface
*/
-#define HUBNI_IP27 0x00600000
-#define HUBNI_IP35 0x00680000
+#define HUBNIBASE_IP27 0x00600000
+#define HUBNIBASE_IP35 0x00680000
#define HUBNI_STATUS 0x00000000
#define NI_MORENODES 0x0000000000040000
#define HUBNI_RESET 0x00000008
-#define NI_RESET_ACTION 0x01
-#define NI_RESET_PORT 0x02
-#define NI_RESET_LOCAL 0x04
+#define NI_RESET_ACTION_IP27 0x02
+#define NI_RESET_PORT_IP27 0x80
+#define NI_RESET_LOCAL_IP27 0x01
+#define NI_RESET_ACTION_IP35 0x01
+#define NI_RESET_PORT_IP35 0x02
+#define NI_RESET_LOCAL_IP35 0x04
#define HUBNI_RESET_ENABLE 0x00000010
#define NI_RESET_ENABLE 0x01
+
+/*
+ * HUB XB - Crossbar interface
+ */
+
+#define HUBXBBASE_IP35 0x00700000
diff --git a/sys/arch/sgi/xbow/xbow.c b/sys/arch/sgi/xbow/xbow.c
index f7e19526de9..90954b50e3b 100644
--- a/sys/arch/sgi/xbow/xbow.c
+++ b/sys/arch/sgi/xbow/xbow.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: xbow.c,v 1.13 2009/07/01 21:56:38 miod Exp $ */
+/* $OpenBSD: xbow.c,v 1.14 2009/07/06 22:46:43 miod Exp $ */
/*
* Copyright (c) 2008, 2009 Miodrag Vallat.
@@ -103,8 +103,13 @@ void *xbow_space_vaddr(bus_space_tag_t, bus_space_handle_t);
const struct xbow_product *xbow_identify(uint32_t, uint32_t);
+struct xbow_softc {
+ struct device sc_dev;
+ int16_t sc_nasid;
+};
+
const struct cfattach xbow_ca = {
- sizeof(struct device), xbowmatch, xbowattach
+ sizeof(struct xbow_softc), xbowmatch, xbowattach
};
struct cfdriver xbow_cd = {
@@ -141,6 +146,7 @@ static const bus_space_t xbowbus_tag = {
* systems.
*/
paddr_t (*xbow_widget_base)(int16_t, u_int);
+paddr_t (*xbow_widget_map)(int16_t, u_int, bus_addr_t *, bus_size_t *);
int (*xbow_widget_id)(int16_t, u_int, uint32_t *);
@@ -261,6 +267,7 @@ struct xbow_kl_config {
void
xbowattach(struct device *parent, struct device *self, void *aux)
{
+ struct xbow_softc *sc = (struct xbow_softc *)self;
struct confargs *ca = aux;
int16_t nasid = ca->ca_nasid;
uint32_t wid, vendor, product;
@@ -269,6 +276,8 @@ xbowattach(struct device *parent, struct device *self, void *aux)
struct xbow_kl_config klcfg;
uint widget;
+ sc->sc_nasid = nasid;
+
/*
* This assumes widget 0 is the XBow itself (or an XXBow).
* If it isn't - feel free to haunt my bedroom at night.
@@ -665,3 +674,19 @@ xbow_intr_disestablish(int intrbit)
(*xbow_intr_widget_intr_disestablish)(intrbit);
}
+
+/*
+ * Widget mapping code.
+ */
+
+paddr_t
+xbow_widget_map_space(struct device *dev, u_int widget, bus_addr_t *offs,
+ bus_size_t *len)
+{
+ struct xbow_softc *sc = (struct xbow_softc *)dev;
+
+ if (xbow_widget_map == NULL)
+ return 0UL;
+
+ return (*xbow_widget_map)(sc->sc_nasid, widget, offs, len);
+}
diff --git a/sys/arch/sgi/xbow/xbow.h b/sys/arch/sgi/xbow/xbow.h
index 545c355a688..22797bd137a 100644
--- a/sys/arch/sgi/xbow/xbow.h
+++ b/sys/arch/sgi/xbow/xbow.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: xbow.h,v 1.5 2009/07/01 21:56:38 miod Exp $ */
+/* $OpenBSD: xbow.h,v 1.6 2009/07/06 22:46:43 miod Exp $ */
/*
* Copyright (c) 2008 Miodrag Vallat.
@@ -24,10 +24,12 @@
* identified by a common widget memory area at the beginning of their
* memory space.
*
- * Each widget has its own memory space, upon which windows of different
- * sizes can be defined. OpenBSD only cares about the shortest window
- * (which fits in 32 bits of address space), and the longest window (which
- * provides access to the complete widget space).
+ * Each widget has its own memory space. The lowest 16MB are always
+ * accessible as a so-called ``short window''. Other `views' of the
+ * widget are possible, depending on the system (the whole widget
+ * address space is always visible on Octane, while Origin family
+ * systems can only map a few ``large windows'', which are a scarce
+ * resource).
*
* Apart from the crossbow itself being widget #0, the widgets are divided
* in two groups: widgets #8 to #b are the ``upper'' widgets, while widgets
@@ -40,6 +42,7 @@
*/
extern paddr_t (*xbow_widget_base)(int16_t, u_int);
+extern paddr_t (*xbow_widget_map)(int16_t, u_int, bus_addr_t *, bus_size_t *);
extern int (*xbow_widget_id)(int16_t, u_int, uint32_t *);
extern int xbow_intr_widget;
@@ -121,6 +124,9 @@ int xbow_intr_register(int, int, int *);
int xbow_intr_establish(int (*)(void *), void *, int, int, const char *);
void xbow_intr_disestablish(int);
+paddr_t xbow_widget_map_space(struct device *, u_int,
+ bus_addr_t *, bus_size_t *);
+
int xbow_space_map(bus_space_tag_t, bus_addr_t, bus_size_t, int,
bus_space_handle_t *);
uint8_t xbow_read_1(bus_space_tag_t, bus_space_handle_t, bus_size_t);
diff --git a/sys/arch/sgi/xbow/xbridge.c b/sys/arch/sgi/xbow/xbridge.c
index 6e0e189a40b..7316037d9f9 100644
--- a/sys/arch/sgi/xbow/xbridge.c
+++ b/sys/arch/sgi/xbow/xbridge.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: xbridge.c,v 1.32 2009/07/03 19:28:47 miod Exp $ */
+/* $OpenBSD: xbridge.c,v 1.33 2009/07/06 22:46:43 miod Exp $ */
/*
* Copyright (c) 2008, 2009 Miodrag Vallat.
@@ -68,6 +68,7 @@ struct xbridge_ate;
struct xbridge_softc {
struct device sc_dev;
+ int sc_revision;
int sc_flags;
#define XBRIDGE_FLAGS_XBRIDGE 0x01 /* is XBridge vs Bridge */
int16_t sc_nasid;
@@ -158,18 +159,22 @@ uint64_t xbridge_ate_read(struct xbridge_softc *, uint);
void xbridge_ate_unref(struct xbridge_softc *, uint, uint);
void xbridge_ate_write(struct xbridge_softc *, uint, uint64_t);
-void xbridge_setup(struct xbridge_softc *);
-
int xbridge_allocate_devio(struct xbridge_softc *, int, int);
void xbridge_set_devio(struct xbridge_softc *, int, uint32_t);
-void xbridge_ate_setup(struct xbridge_softc *);
int xbridge_resource_explore(struct xbridge_softc *, pcitag_t,
struct extent *, struct extent *);
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 **);
+struct extent *
+ xbridge_mapping_setup(struct xbridge_softc *, int);
void xbridge_resource_setup(struct xbridge_softc *);
void xbridge_rrb_setup(struct xbridge_softc *, int);
+void xbridge_setup(struct xbridge_softc *);
const struct machine_bus_dma_tag xbridge_dma_tag = {
NULL, /* _cookie */
@@ -220,6 +225,7 @@ xbridge_attach(struct device *parent, struct device *self, void *aux)
sc->sc_nasid = xaa->xaa_nasid;
sc->sc_widget = xaa->xaa_widget;
+ sc->sc_revision = xaa->xaa_revision;
printf(" revision %d\n", xaa->xaa_revision);
if (xaa->xaa_vendor == XBOW_VENDOR_SGI3 &&
@@ -256,26 +262,10 @@ xbridge_attach(struct device *parent, struct device *self, void *aux)
if (sc->sc_io_bus_space == NULL)
goto fail2;
-#ifdef notyet
- /*
- * Memory mappings are available in the widget at
- * offset BRIDGE_PCI_MEM_SPACE_BASE onwards.
- */
- bcopy(xaa->xaa_iot, sc->sc_mem_bus_space,
- sizeof(*sc->sc_mem_bus_space));
- sc->sc_mem_bus_space->bus_base = ...
- sc->sc_mem_ex = extent_create("pcimem",
- 0, BRIDGE_PCI_MEM_SPACE_LENGTH - 1,
- M_DEVBUF, NULL, 0, EX_NOWAIT);
- sc->sc_mem_bus_space->_space_map = xbridge_space_map_mem;
-#else
- /* Programmable memory mappings in the small window */
bcopy(xaa->xaa_iot, sc->sc_mem_bus_space,
sizeof(*sc->sc_mem_bus_space));
- sc->sc_mem_bus_space->_space_map = xbridge_space_map_devio;
-#endif
-
sc->sc_mem_bus_space->bus_private = sc;
+ sc->sc_mem_bus_space->_space_map = xbridge_space_map_devio;
sc->sc_mem_bus_space->_space_read_1 = xbridge_read_1;
sc->sc_mem_bus_space->_space_write_1 = xbridge_write_1;
sc->sc_mem_bus_space->_space_read_2 = xbridge_read_2;
@@ -283,32 +273,10 @@ xbridge_attach(struct device *parent, struct device *self, void *aux)
sc->sc_mem_bus_space->_space_read_raw_2 = xbridge_read_raw_2;
sc->sc_mem_bus_space->_space_write_raw_2 = xbridge_write_raw_2;
-#ifdef notyet
- /*
- * I/O mappings are available in the widget at
- * offset BRIDGE_PCI_IO_SPACE_BASE onwards, but
- * weren't working correctly until Bridge revision 4.
- */
- if (ISSET(sc->sc_flags, XBRIDGE_FLAGS_XBRIDGE) ||
- xaa->xaa_revision >= 4) {
- /* Unrestricted I/O mappings in the large window */
- bcopy(xaa->xaa_iot, sc->sc_io_bus_space,
- sizeof(*sc->sc_io_bus_space));
- sc->sc_io_bus_space->bus_base = ...
- sc->sc_io_ex = extent_create("pciio",
- 0, BRIDGE_PCI_IO_SPACE_LENGTH - 1,
- M_DEVBUF, NULL, 0, EX_NOWAIT);
- sc->sc_io_bus_space->_space_map = xbridge_space_map_io;
- } else
-#endif
- {
- /* Programmable I/O mappings in the small window */
- bcopy(xaa->xaa_iot, sc->sc_io_bus_space,
- sizeof(*sc->sc_io_bus_space));
- sc->sc_io_bus_space->_space_map = xbridge_space_map_devio;
- }
-
+ bcopy(xaa->xaa_iot, sc->sc_io_bus_space,
+ sizeof(*sc->sc_io_bus_space));
sc->sc_io_bus_space->bus_private = sc;
+ sc->sc_io_bus_space->_space_map = xbridge_space_map_devio;
sc->sc_io_bus_space->_space_read_1 = xbridge_read_1;
sc->sc_io_bus_space->_space_write_1 = xbridge_write_1;
sc->sc_io_bus_space->_space_read_2 = xbridge_read_2;
@@ -883,8 +851,11 @@ xbridge_space_map_devio(bus_space_tag_t t, bus_addr_t offs, bus_size_t size,
int cacheable, bus_space_handle_t *bshp)
{
struct xbridge_softc *sc = (struct xbridge_softc *)t->bus_private;
- bus_addr_t bpa, start, end;
+ bus_addr_t bpa;
+#ifdef DIAGNOSTIC
+ bus_addr_t start, end;
uint d;
+#endif
if ((offs >> 24) != sc->sc_devio_skew)
return EINVAL; /* not a devio mapping */
@@ -894,6 +865,7 @@ xbridge_space_map_devio(bus_space_tag_t t, bus_addr_t offs, bus_size_t size,
* we do not overrun it.
*/
bpa = offs & ((1UL << 24) - 1);
+#ifdef DIAGNOSTIC
for (d = 0; d < BRIDGE_NSLOTS; d++) {
start = BRIDGE_DEVIO_OFFS(d);
end = start + BRIDGE_DEVIO_SIZE(d);
@@ -906,6 +878,7 @@ xbridge_space_map_devio(bus_space_tag_t t, bus_addr_t offs, bus_size_t size,
}
if (d == BRIDGE_NSLOTS)
return EINVAL;
+#endif
/*
* Note we can not use our own bus_base because it might not point
@@ -916,7 +889,6 @@ xbridge_space_map_devio(bus_space_tag_t t, bus_addr_t offs, bus_size_t size,
return 0;
}
-#ifdef notyet
int
xbridge_space_map_io(bus_space_tag_t t, bus_addr_t offs, bus_size_t size,
int cacheable, bus_space_handle_t *bshp)
@@ -931,11 +903,7 @@ xbridge_space_map_io(bus_space_tag_t t, bus_addr_t offs, bus_size_t size,
if ((offs >> 24) == sc->sc_devio_skew)
return xbridge_space_map_devio(t, offs, size, cacheable, bshp);
- /* check that this doesn't overflow the window */
- if (offs + size > BRIDGE_PCI_IO_SPACE_LENGTH || offs + size < offs)
- return EINVAL;
-
- *bshp = t->bus_base + BRIDGE_PCI_IO_SPACE_BASE + offs;
+ *bshp = (t->bus_base + offs);
return 0;
}
@@ -947,20 +915,17 @@ xbridge_space_map_mem(bus_space_tag_t t, bus_addr_t offs, bus_size_t size,
/*
* Base address is either within the devio area, or our direct
- * window.
+ * window. Except on Octane where we never setup devio memory
+ * mappings, because the large mapping is always available.
*/
- if ((offs >> 24) == sc->sc_devio_skew)
+ if (sys_config.system_type != SGI_OCTANE &&
+ (offs >> 24) == sc->sc_devio_skew)
return xbridge_space_map_devio(t, offs, size, cacheable, bshp);
- /* check that this doesn't overflow the window */
- if (offs + size > BRIDGE_PCI_MEM_SPACE_LENGTH || offs + size < offs)
- return EINVAL;
-
- *bshp = t->bus_base + BRIDGE_PCI_MEM_SPACE_BASE + offs;
+ *bshp = (t->bus_base + offs);
return 0;
}
-#endif
/*
********************* bus_dma helpers
@@ -1218,6 +1183,11 @@ xbridge_address_map(struct xbridge_softc *sc, paddr_t pa, bus_addr_t *mapping,
if (a != (uint)-1) {
ba = ATE_ADDRESS(a, BRIDGE_ATE_LSHIFT);
+ /*
+ * Ask for byteswap during DMA. On Bridge (i.e non-XBridge),
+ * this setting is device-global and is enforced by
+ * BRIDGE_DEVICE_SWAP_PMU set in the devio register.
+ */
if (ISSET(sc->sc_flags, XBRIDGE_FLAGS_XBRIDGE))
ba |= XBRIDGE_DMA_TRANSLATED_SWAP;
#ifdef ATE_DEBUG
@@ -1454,7 +1424,8 @@ xbridge_dmamap_load_mbuf(bus_dma_tag_t t, bus_dmamap_t map, struct mbuf *m,
goto fail_unmap;
}
- sgsize = min(buflen, PAGE_SIZE);
+ sgsize = PAGE_SIZE - ((u_long)vaddr & PGOFSET);
+ sgsize = min(buflen, sgsize);
sgsize = min(endaddr - busaddr, sgsize);
/*
@@ -1610,6 +1581,7 @@ void
xbridge_setup(struct xbridge_softc *sc)
{
paddr_t pa;
+ uint32_t ctrl;
int dev, i;
/*
@@ -1653,25 +1625,18 @@ xbridge_setup(struct xbridge_softc *sc)
xbridge_rrb_setup(sc, 0);
xbridge_rrb_setup(sc, 1);
-#ifdef notyet
/*
- * Enable byteswapping on accesses through the large window,
- * except on the main I/O widget on Octane, where the default
- * mappings require them to be disabled (which doesn't matter,
- * since the contents of the PCI bus are immutable and well-known).
+ * Disable byteswapping on PIO accesses through the large window
+ * (we handle this at the bus_space level). It should not have
+ * been enabled by ARCS, since IOC serial console relies on this,
+ * but better enforce this anyway.
*/
- if (sys_config.system_type != SGI_OCTANE ||
- sc->sc_widget != WIDGET_MAX) {
- uint32_t ctrl = bus_space_read_4(sc->sc_iot, sc->sc_regh,
- WIDGET_CONTROL);
- ctrl |= BRIDGE_WIDGET_CONTROL_IO_SWAP;
- ctrl |= BRIDGE_WIDGET_CONTROL_MEM_SWAP;
- bus_space_write_4(sc->sc_iot, sc->sc_regh, WIDGET_CONTROL,
- ctrl);
- (void)bus_space_read_4(sc->sc_iot, sc->sc_regh, WIDGET_TFLUSH);
- }
-#endif
+ ctrl = bus_space_read_4(sc->sc_iot, sc->sc_regh, WIDGET_CONTROL);
+ ctrl &= ~BRIDGE_WIDGET_CONTROL_IO_SWAP;
+ ctrl &= ~BRIDGE_WIDGET_CONTROL_MEM_SWAP;
+ bus_space_write_4(sc->sc_iot, sc->sc_regh, WIDGET_CONTROL, ctrl);
+ (void)bus_space_read_4(sc->sc_iot, sc->sc_regh, WIDGET_TFLUSH);
/*
* The PROM will only configure the onboard devices. Set up
@@ -1792,47 +1757,41 @@ xbridge_rrb_setup(struct xbridge_softc *sc, int odd)
}
/*
- * Flags returned by xbridge_resource_explore()
+ * Configure PCI resources for all devices.
*/
-#define XR_IO 0x01 /* needs I/O mappings */
-#define XR_MEM 0x02 /* needs memory mappings */
-#define XR_IO_OFLOW_S 0x04 /* can't fit I/O in a short devio */
-#define XR_MEM_OFLOW_S 0x08 /* can't fit memory in a short devio */
-#define XR_IO_OFLOW 0x10 /* can't fit I/O in a large devio */
-#define XR_MEM_OFLOW 0x20 /* can't fit memory in a large devio */
-
void
xbridge_resource_setup(struct xbridge_softc *sc)
{
pci_chipset_tag_t pc = &sc->sc_pc;
- int dev, function, nfuncs;
+ int dev, nfuncs;
pcitag_t tag;
pcireg_t id, bhlcr;
- const struct pci_quirkdata *qd;
- uint32_t devio, basewin;
+ uint32_t devio;
int need_setup;
- int resources;
- int io_devio, mem_devio;
- struct extent *ioex, *memex;
+ const struct pci_quirkdata *qd;
+ struct extent *io_ex = NULL, *mem_ex = NULL;
/*
- * Figure out where the devio mappings will lie in the widget.
- * On Octane (at least for the on-board devices widget), they are
- * relative to the beginning of the widget.
- * On other systems, they are offset an address multiple of the
- * widget number.
+ * Figure out where the devio mappings will go.
+ * On Octane, they are relative to the start of the widget.
+ * On Origin, they are computed from the widget number.
+ */
+
+ if (sys_config.system_type == SGI_OCTANE)
+ sc->sc_devio_skew = 0;
+ else
+ sc->sc_devio_skew = sc->sc_widget;
+
+ /*
+ * On Octane, we will want to map everything through the large
+ * windows, whenever possible.
*
- * We could remap everything to the beginning of the widget, but
- * since we need serial console mappings early, we can not afford
- * changing how ARCS maps the IOC device.
+ * Set up these mappings now.
*/
- sc->sc_devio_skew = sc->sc_widget;
if (sys_config.system_type == SGI_OCTANE) {
-#if 0 /* no reason not to expect all octane xbridge to behave the same way */
- if (sc->sc_widget == WIDGET_MAX)
-#endif
- sc->sc_devio_skew = 0;
+ io_ex = xbridge_mapping_setup(sc, 1);
+ mem_ex = xbridge_mapping_setup(sc, 0);
}
for (dev = 0; dev < BRIDGE_NSLOTS; dev++) {
@@ -1842,45 +1801,67 @@ xbridge_resource_setup(struct xbridge_softc *sc)
continue;
/*
- * Devices which have been configured by the firmware
- * have their I/O window pointing to the bridge widget.
- * XXX We only need to preserve IOC3 devio settings if
- * XXX it is the console.
+ * We want to avoid changing mapping configuration for
+ * devices which have been setup by ARCS.
+ *
+ * On Octane, the whole on-board I/O widget has been
+ * set up, with direct mappings into widget space.
+ *
+ * On Origin, since direct mappings are expensive,
+ * everything set up by ARCS has a valid devio
+ * mapping; those can be identified as they sport the
+ * widget number in the high address bits.
+ *
+ * We will only fix the device-global devio flags on
+ * devices which have been set up by ARCS. Otherwise,
+ * we'll need to perform proper PCI resource allocation.
*/
+
devio = bus_space_read_4(sc->sc_iot, sc->sc_regh,
BRIDGE_DEVICE(dev));
- need_setup = ((devio & BRIDGE_DEVICE_BASE_MASK) >>
- (24 - BRIDGE_DEVICE_BASE_SHIFT)) != sc->sc_devio_skew;
-
- /*
- * On Octane, the firmware will setup the I/O registers
- * correctly for the on-board devices, except for byteswap.
- * Other PCI buses, and other systems, need more attention.
- */
+#ifdef DEBUG
+ printf("device %d: devio %08x\n", dev, devio);
+#endif
if (sys_config.system_type == SGI_OCTANE &&
sc->sc_widget == WIDGET_MAX)
need_setup = 0;
+ else
+ need_setup = sc->sc_devio_skew !=
+ ((devio & BRIDGE_DEVICE_BASE_MASK) >>
+ (24 - BRIDGE_DEVICE_BASE_SHIFT));
/*
* Enable byte swapping for DMA, except on IOC3 and
* RAD1 devices.
*/
- devio &= ~(BRIDGE_DEVICE_SWAP_DIR | BRIDGE_DEVICE_SWAP_PMU);
- if (id != PCI_ID_CODE(PCI_VENDOR_SGI, PCI_PRODUCT_SGI_IOC3) &&
- id != PCI_ID_CODE(PCI_VENDOR_SGI, PCI_PRODUCT_SGI_RAD1))
+ if (ISSET(sc->sc_flags, XBRIDGE_FLAGS_XBRIDGE))
+ devio &= ~BRIDGE_DEVICE_SWAP_PMU;
+ else
devio |= BRIDGE_DEVICE_SWAP_PMU;
+ devio |= BRIDGE_DEVICE_SWAP_DIR;
+ if (id == PCI_ID_CODE(PCI_VENDOR_SGI, PCI_PRODUCT_SGI_IOC3) ||
+ id == PCI_ID_CODE(PCI_VENDOR_SGI, PCI_PRODUCT_SGI_RAD1))
+ devio &=
+ ~(BRIDGE_DEVICE_SWAP_DIR | BRIDGE_DEVICE_SWAP_PMU);
+
+ /*
+ * Disable prefetching - on-board isp(4) controllers on
+ * Octane are set up with this, but this confuses the
+ * driver.
+ */
+ devio &= ~BRIDGE_DEVICE_PREFETCH;
+
+ xbridge_set_devio(sc, dev, devio);
- if (need_setup == 0) {
- xbridge_set_devio(sc, dev, devio);
+ if (need_setup == 0)
continue;
- }
/*
- * Setup our proto devio value.
+ * Clear any residual devio mapping.
*/
-
devio &= ~BRIDGE_DEVICE_BASE_MASK;
devio &= ~BRIDGE_DEVICE_IO_MEM;
+ xbridge_set_devio(sc, dev, devio);
/*
* We now need to perform the resource allocation for this
@@ -1897,100 +1878,144 @@ xbridge_resource_setup(struct xbridge_softc *sc)
else
nfuncs = 1;
+ xbridge_device_setup(sc, dev, nfuncs, devio, &io_ex, &mem_ex);
+ }
+
+ if (io_ex != NULL)
+ extent_destroy(io_ex);
+ if (mem_ex != NULL)
+ extent_destroy(mem_ex);
+}
+
+struct extent *
+xbridge_mapping_setup(struct xbridge_softc *sc, int io)
+{
+ bus_addr_t offs;
+ bus_size_t len;
+ paddr_t base;
+ u_long start, end;
+ struct extent *ex = NULL;
+
+ if (io) {
/*
- * In a first step, we enumerate all the requested resources,
- * and check if they can fit within a devio mapping.
- *
- * Note that this is tricky, because if the device has both
- * I/O and memory resources to map, we might not be able
- * to get a second devio, or to get one of the same size.
+ * I/O mappings are available in the widget at offset
+ * BRIDGE_PCI_IO_SPACE_BASE onwards, but weren't working
+ * correctly until Bridge revision 4 (apparently, what
+ * didn't work was the byteswap logic).
*/
- ioex = extent_create("xbridge_io", 0, BRIDGE_DEVIO_LARGE - 1,
- M_DEVBUF, NULL, 0, EX_NOWAIT);
- memex = extent_create("xbridge_mem", 0, BRIDGE_DEVIO_LARGE - 1,
- M_DEVBUF, NULL, 0, EX_NOWAIT);
+ if (ISSET(sc->sc_flags, XBRIDGE_FLAGS_XBRIDGE) ||
+ sc->sc_revision >= 4) {
+ offs = BRIDGE_PCI_IO_SPACE_BASE;
+ len = BRIDGE_PCI_IO_SPACE_LENGTH;
+ base = xbow_widget_map_space(sc->sc_dev.dv_parent,
+ sc->sc_widget, &offs, &len);
+ } else
+ base = 0;
+
+ if (base != 0) {
+ if (offs + len > BRIDGE_PCI_IO_SPACE_BASE +
+ BRIDGE_PCI_IO_SPACE_LENGTH)
+ len = BRIDGE_PCI_IO_SPACE_BASE +
+ BRIDGE_PCI_IO_SPACE_LENGTH - offs;
- resources = 0;
- for (function = 0; function < nfuncs; function++) {
- tag = pci_make_tag(pc, 0, dev, function);
- id = pci_conf_read(pc, tag, PCI_ID_REG);
+#ifdef DEBUG
+ printf("direct io %p-%p base %p\n",
+ offs, offs + len - 1, base);
+#endif
+ offs -= BRIDGE_PCI_IO_SPACE_BASE;
- if (PCI_VENDOR(id) == PCI_VENDOR_INVALID ||
- PCI_VENDOR(id) == 0)
- continue;
+ ex = extent_create("xbridge_direct_io",
+ offs == 0 ? 1 : offs, offs + len - 1,
+ M_DEVBUF, NULL, 0, EX_NOWAIT);
- resources |= xbridge_resource_explore(sc, tag,
- ioex, memex);
+ if (ex != NULL) {
+ sc->sc_io_bus_space->bus_base = base - offs;
+ sc->sc_io_bus_space->_space_map =
+ xbridge_space_map_io;
+ }
}
-
- extent_destroy(memex);
- memex = NULL;
- extent_destroy(ioex);
- ioex = NULL;
-
+ } else {
/*
- * If resources can be mapped using devio slots, allocate
- * them. Otherwise, or if we can't get a devio slot
- * big enough for the resources we need to map, we'll need
- * to get a large window mapping.
+ * Memory mappings are available in the widget at offset
+ * BRIDGE_PCI_MEM_SPACE_BASE onwards.
*/
- io_devio = -1;
- if (ISSET(resources, XR_IO)) {
- if (!ISSET(resources, XR_IO_OFLOW))
- io_devio = xbridge_allocate_devio(sc, dev,
- ISSET(resources, XR_IO_OFLOW_S));
- if (io_devio >= 0) {
- basewin = (sc->sc_widget << 24) |
- BRIDGE_DEVIO_OFFS(io_devio);
- xbridge_set_devio(sc, io_devio, devio |
- (basewin >> BRIDGE_DEVICE_BASE_SHIFT));
-
- ioex = extent_create("xbridge_io", basewin,
- basewin + BRIDGE_DEVIO_SIZE(io_devio) - 1,
- M_DEVBUF, NULL, 0, EX_NOWAIT);
- }
- /* XXX else get a large window mapping */
- }
+ offs = BRIDGE_PCI_MEM_SPACE_BASE;
+ len = BRIDGE_PCI_MEM_SPACE_LENGTH;
+ base = xbow_widget_map_space(sc->sc_dev.dv_parent,
+ sc->sc_widget, &offs, &len);
- mem_devio = -1;
- if (ISSET(resources, XR_MEM)) {
- if (!ISSET(resources, XR_MEM_OFLOW))
- mem_devio = xbridge_allocate_devio(sc, dev,
- ISSET(resources, XR_MEM_OFLOW_S));
- if (mem_devio >= 0) {
- basewin = (sc->sc_widget << 24) |
- BRIDGE_DEVIO_OFFS(mem_devio);
- xbridge_set_devio(sc, mem_devio, devio |
- BRIDGE_DEVICE_IO_MEM |
- (basewin >> BRIDGE_DEVICE_BASE_SHIFT));
-
- memex = extent_create("xbridge_mem", basewin,
- basewin + BRIDGE_DEVIO_SIZE(mem_devio) - 1,
- M_DEVBUF, NULL, 0, EX_NOWAIT);
- }
- /* XXX else get a large window mapping */
- }
+ if (base != 0) {
+ /*
+ * Only the low 30 bits of memory BAR are honoured
+ * by the hardware, thus restricting memory mappings
+ * to 1GB.
+ */
+ if (offs + len > BRIDGE_PCI_MEM_SPACE_BASE +
+ BRIDGE_PCI_MEM_SPACE_LENGTH)
+ len = BRIDGE_PCI_MEM_SPACE_BASE +
+ BRIDGE_PCI_MEM_SPACE_LENGTH - offs;
- for (function = 0; function < nfuncs; function++) {
- tag = pci_make_tag(pc, 0, dev, function);
- id = pci_conf_read(pc, tag, PCI_ID_REG);
+#ifdef DEBUG
+ printf("direct mem %p-%p base %p\n",
+ offs, offs + len - 1, base);
+#endif
+ offs -= BRIDGE_PCI_MEM_SPACE_BASE;
- if (PCI_VENDOR(id) == PCI_VENDOR_INVALID ||
- PCI_VENDOR(id) == 0)
- continue;
+ ex = extent_create("xbridge_direct_mem",
+ offs == 0 ? 1 : offs, offs + len - 1,
+ M_DEVBUF, NULL, 0, EX_NOWAIT);
- xbridge_resource_manage(sc, tag, ioex, memex);
+ if (ex != NULL) {
+ sc->sc_mem_bus_space->bus_base = base - offs;
+ sc->sc_mem_bus_space->_space_map =
+ xbridge_space_map_mem;
+ }
}
+ }
- if (memex != NULL)
- extent_destroy(memex);
- if (ioex != NULL)
- extent_destroy(ioex);
+ if (ex != NULL) {
+ /*
+ * Remove the devio mapping range from the extent
+ * to avoid ambiguous mappings.
+ *
+ * Note that xbow_widget_map_space() may have returned
+ * a range in which the devio area does not appear.
+ */
+ start = sc->sc_devio_skew << 24;
+ end = start + (1 << 24) - 1;
+
+ 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,
+ EX_NOWAIT | EX_MALLOCOK) != 0) {
+ printf("%s: failed to expurge devio range"
+ " from %s large extent\n",
+ sc->sc_dev.dv_xname,
+ io ? "i/o" : "mem");
+ extent_destroy(ex);
+ ex = NULL;
+ }
+ }
}
+
+ return ex;
}
+/*
+ * Flags returned by xbridge_resource_explore()
+ */
+#define XR_IO 0x01 /* needs I/O mappings */
+#define XR_MEM 0x02 /* needs memory mappings */
+#define XR_IO_OFLOW_S 0x04 /* can't fit I/O in a short devio */
+#define XR_MEM_OFLOW_S 0x08 /* can't fit memory in a short devio */
+#define XR_IO_OFLOW 0x10 /* can't fit I/O in a large devio */
+#define XR_MEM_OFLOW 0x20 /* can't fit memory in a large devio */
+
int
xbridge_resource_explore(struct xbridge_softc *sc, pcitag_t tag,
struct extent *ioex, struct extent *memex)
@@ -2041,7 +2066,8 @@ xbridge_resource_explore(struct xbridge_softc *sc, pcitag_t tag,
rc |= XR_MEM_OFLOW | XR_MEM_OFLOW_S;
else if (base >= BRIDGE_DEVIO_SHORT)
rc |= XR_MEM_OFLOW_S;
- }
+ } else
+ rc |= XR_MEM | XR_MEM_OFLOW | XR_MEM_OFLOW_S;
break;
case PCI_MAPREG_TYPE_IO:
if (ioex != NULL) {
@@ -2053,7 +2079,8 @@ xbridge_resource_explore(struct xbridge_softc *sc, pcitag_t tag,
rc |= XR_IO_OFLOW | XR_IO_OFLOW_S;
else if (base >= BRIDGE_DEVIO_SHORT)
rc |= XR_IO_OFLOW_S;
- }
+ } else
+ rc |= XR_IO | XR_IO_OFLOW | XR_IO_OFLOW_S;
break;
}
}
@@ -2103,9 +2130,20 @@ xbridge_resource_manage(struct xbridge_softc *sc, pcitag_t tag,
* optional IOC3 PCI boards, which will get setup by
* ARCS but can be reinitialized as we see fit).
*/
+#ifdef DEBUG
+ printf("bar %02x type %d base %p size %p",
+ reg, type, base, size);
+#endif
switch (type) {
- case PCI_MAPREG_TYPE_MEM | PCI_MAPREG_MEM_TYPE_32BIT:
case PCI_MAPREG_TYPE_MEM | PCI_MAPREG_MEM_TYPE_64BIT:
+ /*
+ * Since our mapping ranges are restricted to
+ * at most 30 bits, the upper part of the 64 bit
+ * BAR registers is always zero.
+ */
+ pci_conf_write(pc, tag, reg + 4, 0);
+ /* FALLTHROUGH */
+ case PCI_MAPREG_TYPE_MEM | PCI_MAPREG_MEM_TYPE_32BIT:
if (memex != NULL) {
if (extent_alloc(memex, size, size, 0, 0, 0,
&base) != 0)
@@ -2123,13 +2161,162 @@ xbridge_resource_manage(struct xbridge_softc *sc, pcitag_t tag,
break;
}
+#ifdef DEBUG
+ printf(" setup at %p\n", base);
+#endif
pci_conf_write(pc, tag, reg, base);
- if (type & PCI_MAPREG_MEM_TYPE_64BIT)
+ if (type == (PCI_MAPREG_TYPE_MEM | PCI_MAPREG_MEM_TYPE_64BIT))
reg += 4;
}
}
+void
+xbridge_device_setup(struct xbridge_softc *sc, int dev, int nfuncs,
+ uint32_t devio, struct extent **large_ioex, struct extent **large_memex)
+{
+ pci_chipset_tag_t pc = &sc->sc_pc;
+ int function;
+ pcitag_t tag;
+ pcireg_t id;
+ uint32_t basewin;
+ int resources;
+ int io_devio, mem_devio;
+ struct extent *ioex, *memex;
+
+ /*
+ * In a first step, we enumerate all the requested resources,
+ * and check if they could fit within devio mappings.
+ *
+ * If devio can't afford us the mappings we need, we'll
+ * try and allocate a large window.
+ */
+
+ /*
+ * Allocate extents to use for devio mappings if necessary.
+ * 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)
+ ioex = NULL;
+ else
+ ioex = extent_create("xbridge_io",
+ 0, BRIDGE_DEVIO_LARGE - 1,
+ M_DEVBUF, NULL, 0, EX_NOWAIT);
+ if (*large_memex != NULL)
+ memex = NULL;
+ else
+ memex = extent_create("xbridge_mem",
+ 0, BRIDGE_DEVIO_LARGE - 1,
+ M_DEVBUF, NULL, 0, EX_NOWAIT);
+
+ resources = 0;
+ for (function = 0; function < nfuncs; function++) {
+ tag = pci_make_tag(pc, 0, dev, function);
+ id = pci_conf_read(pc, tag, PCI_ID_REG);
+
+ if (PCI_VENDOR(id) == PCI_VENDOR_INVALID ||
+ PCI_VENDOR(id) == 0)
+ continue;
+
+ resources |= xbridge_resource_explore(sc, tag, ioex, memex);
+ }
+
+ if (memex != NULL) {
+ extent_destroy(memex);
+ memex = NULL;
+ }
+ if (ioex != NULL) {
+ extent_destroy(ioex);
+ ioex = NULL;
+ }
+
+ /*
+ * In a second step, if resources can be mapped using devio slots,
+ * allocate them. Otherwise, or if we can't get a devio slot
+ * big enough for the resources we need to map, we'll need
+ * to get a large window mapping.
+ *
+ * Note that, on Octane, we try to avoid using devio whenever
+ * possible.
+ */
+
+ io_devio = -1;
+ if (ISSET(resources, XR_IO)) {
+ if (!ISSET(resources, XR_IO_OFLOW) &&
+ (sys_config.system_type != SGI_OCTANE ||
+ *large_ioex == NULL))
+ io_devio = xbridge_allocate_devio(sc, dev,
+ ISSET(resources, XR_IO_OFLOW_S));
+ if (io_devio >= 0) {
+ basewin = (sc->sc_devio_skew << 24) |
+ BRIDGE_DEVIO_OFFS(io_devio);
+ xbridge_set_devio(sc, io_devio, devio |
+ (basewin >> BRIDGE_DEVICE_BASE_SHIFT));
+
+ ioex = extent_create("xbridge_io", basewin,
+ basewin + BRIDGE_DEVIO_SIZE(io_devio) - 1,
+ M_DEVBUF, NULL, 0, EX_NOWAIT);
+ } else {
+ /*
+ * 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);
+ }
+ }
+
+ mem_devio = -1;
+ if (ISSET(resources, XR_MEM)) {
+ if (!ISSET(resources, XR_MEM_OFLOW) &&
+ sys_config.system_type != SGI_OCTANE)
+ mem_devio = xbridge_allocate_devio(sc, dev,
+ ISSET(resources, XR_MEM_OFLOW_S));
+ if (mem_devio >= 0) {
+ basewin = (sc->sc_devio_skew << 24) |
+ BRIDGE_DEVIO_OFFS(mem_devio);
+ xbridge_set_devio(sc, mem_devio, devio |
+ BRIDGE_DEVICE_IO_MEM |
+ (basewin >> BRIDGE_DEVICE_BASE_SHIFT));
+
+ memex = extent_create("xbridge_mem", basewin,
+ basewin + BRIDGE_DEVIO_SIZE(mem_devio) - 1,
+ M_DEVBUF, NULL, 0, EX_NOWAIT);
+ } else {
+ /*
+ * 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);
+ }
+ }
+
+ /*
+ * Finally allocate the resources proper and update the
+ * device BARs accordingly.
+ */
+
+ for (function = 0; function < nfuncs; function++) {
+ tag = pci_make_tag(pc, 0, dev, function);
+ id = pci_conf_read(pc, tag, PCI_ID_REG);
+
+ if (PCI_VENDOR(id) == PCI_VENDOR_INVALID ||
+ PCI_VENDOR(id) == 0)
+ continue;
+
+ xbridge_resource_manage(sc, tag,
+ ioex != NULL ? ioex : *large_ioex,
+ memex != NULL ? memex : *large_memex);
+ }
+
+ if (memex != NULL)
+ extent_destroy(memex);
+ if (ioex != NULL)
+ extent_destroy(ioex);
+}
+
int
xbridge_allocate_devio(struct xbridge_softc *sc, int dev, int wantlarge)
{
@@ -2173,4 +2360,7 @@ xbridge_set_devio(struct xbridge_softc *sc, int dev, uint32_t devio)
bus_space_write_4(sc->sc_iot, sc->sc_regh, BRIDGE_DEVICE(dev), devio);
(void)bus_space_read_4(sc->sc_iot, sc->sc_regh, WIDGET_TFLUSH);
sc->sc_devices[dev].devio = devio;
+#ifdef DEBUG
+ printf("device %d: new devio %08x\n", dev, devio);
+#endif
}
diff --git a/sys/arch/sgi/xbow/xbridgereg.h b/sys/arch/sgi/xbow/xbridgereg.h
index b306a9e4358..7537172842e 100644
--- a/sys/arch/sgi/xbow/xbridgereg.h
+++ b/sys/arch/sgi/xbow/xbridgereg.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: xbridgereg.h,v 1.6 2009/05/24 17:33:12 miod Exp $ */
+/* $OpenBSD: xbridgereg.h,v 1.7 2009/07/06 22:46:43 miod Exp $ */
/*
* Copyright (c) 2008 Miodrag Vallat.
@@ -87,13 +87,20 @@
*/
#define BRIDGE_DEVICE(d) (0x00000204 + 8 * (d))
-#define BRIDGE_DEVICE_SWAP_PMU 0x00080000 /* ??? */
-#define BRIDGE_DEVICE_SWAP_DIR 0x00040000 /* ??? */
+/* flags applying to the device itself */
+/* byteswap DMA done through ATE */
+#define BRIDGE_DEVICE_SWAP_PMU 0x00100000
+/* byteswap DMA done through the direct window */
+#define BRIDGE_DEVICE_SWAP_DIR 0x00080000
+/* flags applying to the mapping in this devio register */
+#define BRIDGE_DEVICE_PREFETCH 0x00040000
#define BRIDGE_DEVICE_PRECISE 0x00020000
#define BRIDGE_DEVICE_COHERENT 0x00010000
#define BRIDGE_DEVICE_BARRIER 0x00008000
+/* byteswap PIO */
#define BRIDGE_DEVICE_SWAP 0x00002000
-#define BRIDGE_DEVICE_IO_MEM 0x00001000 /* clear if I/O */
+/* set if memory space, clear if I/O space */
+#define BRIDGE_DEVICE_IO_MEM 0x00001000
#define BRIDGE_DEVICE_BASE_MASK 0x00000fff
#define BRIDGE_DEVICE_BASE_SHIFT 20