summaryrefslogtreecommitdiff
path: root/sys/arch/sgi/xbow
diff options
context:
space:
mode:
authorMiod Vallat <miod@cvs.openbsd.org>2009-05-03 19:44:29 +0000
committerMiod Vallat <miod@cvs.openbsd.org>2009-05-03 19:44:29 +0000
commit068967e49d34f75ebd3e56b19eaf19a5769ef8e0 (patch)
tree34c11bd94f6ce8d28b63ac3c334d45ab509827e6 /sys/arch/sgi/xbow
parent0e69e6e05d5002e9d80cf857b68d96b8310f55e5 (diff)
Complete overhaul of the PCI bridge initialization. It will now allocate
resources to cards not configured by the PROM. There are still some shortcomings, but this is a good start. Tested on IP35 with an fxp(4).
Diffstat (limited to 'sys/arch/sgi/xbow')
-rw-r--r--sys/arch/sgi/xbow/xbridge.c469
-rw-r--r--sys/arch/sgi/xbow/xbridgereg.h6
2 files changed, 380 insertions, 95 deletions
diff --git a/sys/arch/sgi/xbow/xbridge.c b/sys/arch/sgi/xbow/xbridge.c
index 7522bd6780f..08e115d2079 100644
--- a/sys/arch/sgi/xbow/xbridge.c
+++ b/sys/arch/sgi/xbow/xbridge.c
@@ -1,7 +1,7 @@
-/* $OpenBSD: xbridge.c,v 1.13 2009/05/02 21:30:13 miod Exp $ */
+/* $OpenBSD: xbridge.c,v 1.14 2009/05/03 19:44:28 miod Exp $ */
/*
- * Copyright (c) 2008 Miodrag Vallat.
+ * Copyright (c) 2008, 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
@@ -26,7 +26,7 @@
#include <sys/device.h>
#include <sys/evcount.h>
#include <sys/malloc.h>
-#include <sys/proc.h>
+#include <sys/extent.h>
#include <machine/atomic.h>
#include <machine/autoconf.h>
@@ -61,7 +61,8 @@ struct xbridge_softc {
struct mips_bus_space *sc_mem_bus_space;
struct mips_bus_space *sc_io_bus_space;
- struct machine_bus_dma_tag sc_dmatag;
+ struct extent *sc_mem_ex;
+ struct extent *sc_io_ex;
bus_space_tag_t sc_iot;
bus_space_handle_t sc_regh;
@@ -113,13 +114,20 @@ void xbridge_read_raw_8(bus_space_tag_t, bus_space_handle_t, bus_addr_t,
uint8_t *, bus_size_t);
void xbridge_write_raw_8(bus_space_tag_t, bus_space_handle_t, bus_addr_t,
const uint8_t *, bus_size_t);
+
int xbridge_space_map_short(bus_space_tag_t, bus_addr_t, bus_size_t, int,
bus_space_handle_t *);
bus_addr_t xbridge_pa_to_device(paddr_t);
paddr_t xbridge_device_to_pa(bus_addr_t);
-const struct machine_bus_dma_tag xbridge_dma_tag = {
+void xbridge_setup(struct xbridge_softc *);
+void xbridge_resource_manage(struct xbridge_softc *, pcitag_t,
+ struct extent *);
+void xbridge_resource_setup(struct xbridge_softc *);
+void xbridge_rrb_setup(struct xbridge_softc *, int);
+
+struct machine_bus_dma_tag xbridge_dma_tag = {
NULL, /* _cookie */
_dmamap_create,
_dmamap_destroy,
@@ -136,7 +144,7 @@ const struct machine_bus_dma_tag xbridge_dma_tag = {
_dmamem_mmap,
xbridge_pa_to_device,
xbridge_device_to_pa,
- 0ULL /* no mask */
+ BRIDGE_DMA_DIRECT_LENGTH - 1
};
int
@@ -161,7 +169,6 @@ xbridge_attach(struct device *parent, struct device *self, void *aux)
struct xbridge_softc *sc = (struct xbridge_softc *)self;
struct pcibus_attach_args pba;
struct xbow_attach_args *xaa = aux;
- int i;
sc->sc_widget = xaa->xaa_widget;
@@ -200,6 +207,9 @@ xbridge_attach(struct device *parent, struct device *self, void *aux)
bcopy(xaa->xaa_long_tag, sc->sc_mem_bus_space,
sizeof(*sc->sc_mem_bus_space));
sc->sc_mem_bus_space->bus_base += BRIDGE_PCI_MEM_SPACE_BASE;
+ sc->sc_mem_ex = extent_create("pcimem",
+ 0, BRIDGE_PCI_MEM_SPACE_LENGTH - 1,
+ M_DEVBUF, NULL, 0, EX_NOWAIT);
if (!ISSET(sc->sc_flags, XBRIDGE_FLAGS_XBRIDGE) &&
xaa->xaa_revision >= 4) {
@@ -208,6 +218,10 @@ xbridge_attach(struct device *parent, struct device *self, void *aux)
sizeof(*sc->sc_io_bus_space));
sc->sc_io_bus_space->bus_base +=
BRIDGE_PCI_IO_SPACE_BASE;
+
+ sc->sc_io_ex = extent_create("pciio",
+ 0, BRIDGE_PCI_IO_SPACE_LENGTH - 1,
+ M_DEVBUF, NULL, 0, EX_NOWAIT);
} else {
/* Programmable I/O mappings in the small window */
bcopy(xaa->xaa_short_tag, sc->sc_io_bus_space,
@@ -267,101 +281,23 @@ xbridge_attach(struct device *parent, struct device *self, void *aux)
sc->sc_pc.pc_intr_disestablish = xbridge_intr_disestablish;
/*
- * Configure the direct DMA window to access the low 2GB of memory.
+ * Configure Bridge for proper operation (DMA, I/O mappings,
+ * RRB allocation, etc).
*/
- if (sys_config.system_type == SGI_OCTANE)
- bus_space_write_4(sc->sc_iot, sc->sc_regh, BRIDGE_DIR_MAP,
- (xbow_intr_widget << BRIDGE_DIRMAP_WIDGET_SHIFT) |
- BRIDGE_DIRMAP_ADD_512MB);
- else
- bus_space_write_4(sc->sc_iot, sc->sc_regh, BRIDGE_DIR_MAP,
- xbow_intr_widget << BRIDGE_DIRMAP_WIDGET_SHIFT);
-
- /*
- * Gather device identification for all slots.
- * We need this to be able to allocate RRBs correctly, and also
- * to be able to check quickly whether a given device is an IOC3.
- */
-
- for (i = 0; i < BRIDGE_NSLOTS; i++) {
- paddr_t pa;
-
- pa = sc->sc_regh + BRIDGE_PCI_CFG_SPACE +
- (i << 12) + PCI_ID_REG;
- if (guarded_read_4(pa, &sc->sc_devices[i]) != 0)
- sc->sc_devices[i] = 0xffffffff;
- }
-
-#if 0 /* XXX write proper RRB allocation code */
- if (sys_config.system_type == SGI_OCTANE) {
- bus_space_write_4(sc->sc_iot, sc->sc_regh, BRIDGE_RRB_EVEN,
- 0x99889988 | 0x44440000);
- bus_space_write_4(sc->sc_iot, sc->sc_regh, BRIDGE_RRB_ODD,
- 0x99889988 | 0x44440000);
- } else {
- bus_space_write_4(sc->sc_iot, sc->sc_regh, BRIDGE_RRB_EVEN,
- 0xba98ba98 | 0x44440000);
- bus_space_write_4(sc->sc_iot, sc->sc_regh, BRIDGE_RRB_ODD,
- 0xba98ba98 | 0x44440000);
- }
-#endif
-
-#if 0 /* XXX write proper I/O mapping allocation code */
- for (i = 0; i < BRIDGE_NSLOTS; i++) {
- uint32_t dio;
-
- if (sc->sc_devices[i] ==
- PCI_ID_CODE(PCI_VENDOR_SGI, PCI_PRODUCT_SGI_IOC3))
- continue;
-
- dio = bus_space_read_4(sc->sc_iot, sc->sc_regh,
- BRIDGE_DEVICE(i));
- dio |= BRIDGE_DEVICE_SWAP_PMU | BRIDGE_DEVICE_SWAP_DIR |
- BRIDGE_DEVICE_COHERENT | BRIDGE_DEVICE_BARRIER;
- bus_space_write_4(sc->sc_iot, sc->sc_regh, BRIDGE_DEVICE(i),
- dio);
- }
-#endif
-
- (void)bus_space_read_4(sc->sc_iot, sc->sc_regh, WIDGET_TFLUSH);
-
- /*
- * Setup interrupt handling.
- */
-
- bus_space_write_4(sc->sc_iot, sc->sc_regh, BRIDGE_IER, 0);
- bus_space_write_4(sc->sc_iot, sc->sc_regh, BRIDGE_INT_MODE, 0);
- bus_space_write_4(sc->sc_iot, sc->sc_regh, BRIDGE_INT_DEV, 0);
-
- bus_space_write_4(sc->sc_iot, sc->sc_regh, WIDGET_INTDEST_ADDR_UPPER,
- (xbow_intr_widget_register >> 32) | (xbow_intr_widget << 16));
- bus_space_write_4(sc->sc_iot, sc->sc_regh, WIDGET_INTDEST_ADDR_LOWER,
- (uint32_t)xbow_intr_widget_register);
-
- (void)bus_space_read_4(sc->sc_iot, sc->sc_regh, WIDGET_TFLUSH);
-
- for (i = 0; i < BRIDGE_NINTRS; i++)
- sc->sc_intrbit[i] = -1;
+ xbridge_setup(sc);
/*
* Attach children.
*/
- bcopy(&xbridge_dma_tag, &sc->sc_dmatag, sizeof(xbridge_dma_tag));
- if (sys_config.system_type == SGI_OCTANE) {
- /*
- * Make sure we do not risk crossing the direct mapping
- * window.
- */
- sc->sc_dmatag._dma_mask = BRIDGE_DMA_DIRECT_LENGTH - 1;
- }
-
bzero(&pba, sizeof(pba));
pba.pba_busname = "pci";
pba.pba_iot = sc->sc_io_bus_space;
pba.pba_memt = sc->sc_mem_bus_space;
- pba.pba_dmat = &sc->sc_dmatag;
+ pba.pba_dmat = &xbridge_dma_tag;
+ pba.pba_ioex = sc->sc_io_ex;
+ pba.pba_memex = sc->sc_mem_ex;
pba.pba_pc = &sc->sc_pc;
pba.pba_domain = pci_ndomains++;
pba.pba_bus = 0;
@@ -829,8 +765,8 @@ xbridge_write_raw_8(bus_space_tag_t t, bus_space_handle_t h, bus_addr_t o,
}
/*
- * On IP27, we can not use the default xbow space_map_short because
- * of the games we play with bus addresses.
+ * On IP27 and IP35, we can not use the default xbow space_map_short
+ * because of the games we play with bus addresses.
*/
int
xbridge_space_map_short(bus_space_tag_t t, bus_addr_t offs, bus_size_t size,
@@ -891,3 +827,350 @@ xbridge_device_to_pa(bus_addr_t addr)
return pa;
}
+
+/*
+ * Bridge configuration code.
+ */
+
+void
+xbridge_setup(struct xbridge_softc *sc)
+{
+ paddr_t pa;
+ int dev, i;
+
+ /*
+ * Gather device identification for all slots.
+ * We need this to be able to allocate RRBs correctly, and also
+ * to be able to check quickly whether a given device is an IOC3.
+ */
+
+ for (dev = 0; dev < BRIDGE_NSLOTS; dev++) {
+ pa = sc->sc_regh + BRIDGE_PCI_CFG_SPACE +
+ (dev << 12) + PCI_ID_REG;
+ if (guarded_read_4(pa, &sc->sc_devices[dev]) != 0)
+ sc->sc_devices[dev] =
+ PCI_ID_CODE(PCI_VENDOR_INVALID, 0xffff);
+ }
+
+ /*
+ * Configure the direct DMA window to access the low 2GB of memory.
+ */
+
+ if (sys_config.system_type == SGI_OCTANE)
+ bus_space_write_4(sc->sc_iot, sc->sc_regh, BRIDGE_DIR_MAP,
+ (xbow_intr_widget << BRIDGE_DIRMAP_WIDGET_SHIFT) |
+ BRIDGE_DIRMAP_ADD_512MB);
+ else
+ bus_space_write_4(sc->sc_iot, sc->sc_regh, BRIDGE_DIR_MAP,
+ xbow_intr_widget << BRIDGE_DIRMAP_WIDGET_SHIFT);
+
+ /*
+ * Allocate RRB for the existing devices.
+ */
+
+ xbridge_rrb_setup(sc, 0);
+ xbridge_rrb_setup(sc, 1);
+
+ /*
+ * The PROM will only configure the onboard devices. Set up
+ * any other device we might encounter.
+ */
+
+ xbridge_resource_setup(sc);
+
+ /*
+ * Setup interrupt handling.
+ */
+
+ bus_space_write_4(sc->sc_iot, sc->sc_regh, BRIDGE_IER, 0);
+ bus_space_write_4(sc->sc_iot, sc->sc_regh, BRIDGE_INT_MODE, 0);
+ bus_space_write_4(sc->sc_iot, sc->sc_regh, BRIDGE_INT_DEV, 0);
+
+ bus_space_write_4(sc->sc_iot, sc->sc_regh, WIDGET_INTDEST_ADDR_UPPER,
+ (xbow_intr_widget_register >> 32) | (xbow_intr_widget << 16));
+ bus_space_write_4(sc->sc_iot, sc->sc_regh, WIDGET_INTDEST_ADDR_LOWER,
+ (uint32_t)xbow_intr_widget_register);
+
+ (void)bus_space_read_4(sc->sc_iot, sc->sc_regh, WIDGET_TFLUSH);
+
+ for (i = 0; i < BRIDGE_NINTRS; i++)
+ sc->sc_intrbit[i] = -1;
+}
+
+/*
+ * Build a not-so-pessimistic RRB allocation register value.
+ */
+void
+xbridge_rrb_setup(struct xbridge_softc *sc, int odd)
+{
+ uint rrb[BRIDGE_NSLOTS / 2]; /* tentative rrb assignment */
+ uint total; /* rrb count */
+ uint32_t proto; /* proto rrb value */
+ int dev, i, j;
+
+ /*
+ * First, try to allocate as many RRBs per device as possible.
+ */
+
+ total = 0;
+ for (i = 0; i < BRIDGE_NSLOTS / 2; i++) {
+ dev = (i << 1) + !!odd;
+ if (PCI_VENDOR(sc->sc_devices[dev]) == PCI_VENDOR_INVALID)
+ rrb[i] = 0;
+ else
+ rrb[i] = 4; /* optimistic value */
+ total += rrb[i];
+ }
+
+ /*
+ * Then, try to reduce greed until we do not claim more than
+ * the 8 RRBs we can afford.
+ */
+
+ if (total > 8) {
+ /*
+ * All devices should be able to live with 3 RRBs, so
+ * reduce their allocation from 4 to 3.
+ */
+ for (i = 0; i < BRIDGE_NSLOTS / 2; i++) {
+ if (rrb[i] == 4) {
+ rrb[i]--;
+ if (--total == 8)
+ break;
+ }
+ }
+ }
+
+ if (total > 8) {
+ /*
+ * There are too many devices for 3 RRBs per device to
+ * be possible. Attempt to reduce from 3 to 2, except
+ * for isp(4) devices.
+ */
+ for (i = 0; i < BRIDGE_NSLOTS / 2; i++) {
+ if (rrb[i] == 3) {
+ dev = (i << 1) + !!odd;
+ if (PCI_VENDOR(sc->sc_devices[dev]) !=
+ PCI_VENDOR_QLOGIC) {
+ rrb[i]--;
+ if (--total == 8)
+ break;
+ }
+ }
+ }
+ }
+
+ if (total > 8) {
+ /*
+ * Too bad, we need to shrink the RRB allocation for
+ * isp devices too. We'll try to favour the lowest
+ * slots, though, hence the reversed loop order.
+ */
+ for (i = BRIDGE_NSLOTS / 2 - 1; i >= 0; i--) {
+ if (rrb[i] == 3) {
+ rrb[i]--;
+ if (--total == 8)
+ break;
+ }
+ }
+ }
+
+ /*
+ * Now build the RRB register value proper.
+ */
+
+ proto = 0;
+ for (i = 0; i < BRIDGE_NSLOTS / 2; i++) {
+ for (j = 0; j < rrb[i]; j++)
+ proto = (proto << RRB_SHIFT) | (RRB_VALID | i);
+ }
+
+ bus_space_write_4(sc->sc_iot, sc->sc_regh,
+ odd ? BRIDGE_RRB_ODD : BRIDGE_RRB_EVEN, proto);
+}
+
+void
+xbridge_resource_setup(struct xbridge_softc *sc)
+{
+ pci_chipset_tag_t pc = &sc->sc_pc;
+ int dev, function, nfuncs;
+ pcitag_t tag;
+ pcireg_t id, bhlcr;
+ const struct pci_quirkdata *qd;
+ uint32_t devio, basewin;
+ int need_setup;
+ struct extent *ioex;
+
+ /*
+ * On Octane, the firmware will setup the I/O registers
+ * correctly for the on-board devices. Other PCI buses,
+ * and other systems, need more attention.
+ *
+ * XXX Another reason not to enter the loop below on the Octane
+ * XXX main Bridge widget is that it uses a sligthly different
+ * XXX devio window allocation scheme, with only one large devio
+ * XXX (used by the first isp controller).
+ */
+ if (sys_config.system_type == SGI_OCTANE && sc->sc_widget == WIDGET_MAX)
+ return;
+
+ for (dev = 0; dev < BRIDGE_NSLOTS; dev++) {
+ id = sc->sc_devices[dev];
+
+ if (PCI_VENDOR(id) == PCI_VENDOR_INVALID || PCI_VENDOR(id) == 0)
+ continue;
+
+ /*
+ * Devices which have been configured by the firmware
+ * have their I/O window pointing to the bridge widget.
+ */
+ 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_widget;
+
+ if (need_setup) {
+ basewin =
+ (sc->sc_widget << 24) | BRIDGE_DEVIO_OFFS(dev);
+
+ devio &= ~BRIDGE_DEVICE_BASE_MASK;
+
+ /*
+ * XXX This defaults to I/O resources only.
+ * XXX However some devices may carry only
+ * XXX memory mappings.
+ * XXX This code should assign devio in a more
+ * XXX flexible way...
+ */
+ devio &= ~BRIDGE_DEVICE_IO_MEM;
+
+ devio |= (basewin >> BRIDGE_DEVICE_BASE_SHIFT);
+ }
+
+ /*
+ * Enable byte swapping for PIO and DMA, except on IOC3 and
+ * RAD1 devices.
+ */
+ 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);
+ else
+ devio |= BRIDGE_DEVICE_SWAP_DIR |
+ BRIDGE_DEVICE_SWAP_PMU;
+
+ 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);
+
+ /*
+ * If we can manage I/O resource allocation in the MI code,
+ * we do not need to do anything more at this stage...
+ */
+
+ if (sc->sc_io_ex != NULL)
+ continue;
+
+ /*
+ * ...otherwise, we need to perform the resource allocation
+ * ourselves, within the devio window we have configured
+ * above, for the devices which have not been setup by the
+ * firmware already.
+ */
+
+ if (need_setup == 0)
+ continue;
+
+ ioex = extent_create("pciio",
+ basewin, basewin + BRIDGE_DEVIO_SIZE(dev) - 1,
+ M_DEVBUF, NULL, 0, EX_NOWAIT);
+ if (ioex == NULL)
+ continue;
+
+ qd = pci_lookup_quirkdata(PCI_VENDOR(id), PCI_PRODUCT(id));
+ tag = pci_make_tag(pc, 0, dev, 0);
+ bhlcr = pci_conf_read(pc, tag, PCI_BHLC_REG);
+
+ if (PCI_HDRTYPE_MULTIFN(bhlcr) ||
+ (qd != NULL && (qd->quirks & PCI_QUIRK_MULTIFUNCTION) != 0))
+ nfuncs = 8;
+ else
+ nfuncs = 1;
+
+ 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);
+ }
+
+ extent_destroy(ioex);
+ }
+}
+
+void
+xbridge_resource_manage(struct xbridge_softc *sc, pcitag_t tag,
+ struct extent *ioex)
+{
+ pci_chipset_tag_t pc = &sc->sc_pc;
+ pcireg_t bhlc, type;
+ bus_addr_t base;
+ bus_size_t size;
+ int reg, reg_start, reg_end;
+
+ bhlc = pci_conf_read(pc, tag, PCI_BHLC_REG);
+ switch (PCI_HDRTYPE(bhlc)) {
+ case 0:
+ reg_start = PCI_MAPREG_START;
+ reg_end = PCI_MAPREG_END;
+ break;
+ case 1: /* PCI-PCI bridge */
+ reg_start = PCI_MAPREG_START;
+ reg_end = PCI_MAPREG_PPB_END;
+ break;
+ case 2: /* PCI-CardBus bridge */
+ reg_start = PCI_MAPREG_START;
+ reg_end = PCI_MAPREG_PCB_END;
+ break;
+ default:
+ return;
+ }
+
+ for (reg = reg_start; reg < reg_end; reg += 4) {
+ if (pci_mapreg_probe(pc, tag, reg, &type) == 0)
+ continue;
+
+ if (pci_mapreg_info(pc, tag, reg, type, &base, &size, NULL))
+ continue;
+
+ switch (type) {
+ case PCI_MAPREG_TYPE_MEM | PCI_MAPREG_MEM_TYPE_32BIT:
+ case PCI_MAPREG_TYPE_MEM | PCI_MAPREG_MEM_TYPE_64BIT:
+ /*
+ * XXX Eventually do something if sc->sc_mem_ex is
+ * XXX NULL...
+ */
+ break;
+ case PCI_MAPREG_TYPE_IO:
+ if (base != 0) {
+ if (extent_alloc_region(ioex, base, size,
+ EX_NOWAIT))
+ printf("io address conflict"
+ " 0x%x/0x%x\n", base, size);
+ } else {
+ if (extent_alloc(ioex, size, size, 0, 0, 0,
+ &base) == 0)
+ pci_conf_write(pc, tag, reg, base);
+ /* otherwise the resource remains disabled */
+ }
+ break;
+ }
+
+ if (type & PCI_MAPREG_MEM_TYPE_64BIT)
+ reg += 4;
+ }
+}
diff --git a/sys/arch/sgi/xbow/xbridgereg.h b/sys/arch/sgi/xbow/xbridgereg.h
index 81675a01688..8b9e2718778 100644
--- a/sys/arch/sgi/xbow/xbridgereg.h
+++ b/sys/arch/sgi/xbow/xbridgereg.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: xbridgereg.h,v 1.2 2009/05/02 21:30:13 miod Exp $ */
+/* $OpenBSD: xbridgereg.h,v 1.3 2009/05/03 19:44:28 miod Exp $ */
/*
* Copyright (c) 2008 Miodrag Vallat.
@@ -90,7 +90,7 @@
#define BRIDGE_DEVICE_COHERENT 0x00010000
#define BRIDGE_DEVICE_BARRIER 0x00008000
#define BRIDGE_DEVICE_SWAP 0x00002000
-#define BRIDGE_DEVICE_IO 0x00001000
+#define BRIDGE_DEVICE_IO_MEM 0x00001000 /* clear if I/O */
#define BRIDGE_DEVICE_BASE_MASK 0x00000fff
#define BRIDGE_DEVICE_BASE_SHIFT 20
@@ -102,6 +102,8 @@
(BRIDGE_DEVIO_BASE + \
BRIDGE_DEVIO_LARGE * ((d) < 2 ? (d) : 2) + \
BRIDGE_DEVIO_SHORT * ((d) < 2 ? 0 : (d) - 2))
+#define BRIDGE_DEVIO_SIZE(d) \
+ ((d) < 2 ? BRIDGE_DEVIO_LARGE : BRIDGE_DEVIO_SHORT)
/*
* Read Response Buffer configuration registers