summaryrefslogtreecommitdiff
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
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).
-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