/*	$OpenBSD: xbridge.c,v 1.96 2015/06/24 16:52:52 miod Exp $	*/

/*
 * Copyright (c) 2008, 2009, 2011  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.
 */

/*
 * XBow Bridge (as well as XBridge and PIC) Widget driver.
 */

/*
 * IMPORTANT AUTHOR'S NOTE: I did not write any of this code under the
 * influence of drugs.  Looking back at that particular piece of hardware,
 * I wonder if this hasn't been a terrible mistake.
 */

/*

  xbridge 101
  ===========

  There are three ASIC using this model:

  - Bridge, used on Octane and maybe early Origin 200 and 2000 systems.
  - XBridge, used on later Origin 200/2000 and Origin 300/3000 systems.
  - PIC, used on Origin 350/3500 systems.

  (for the record, Fuel is Origin 300 like and Tezro is Origin 350 like).

  Bridge and XBridge each appear as a single widget, supporting 8 PCI devices,
  while PIC appears as two contiguous widgets, each supporting 2 PCI-X devices.

- - address space

  Each widget has a 36-bit address space.  xbridge widgets only use 33 bits
  though.

  On Octane systems, the whole 36 bit address space is fully available.  On
  all other systems, the low 16MB (24 bit) address space is always available,
  and access to arbitrary areas of the address space can be achieved by
  programming the Crossbow's IOTTE (I/O Translation Table Entries).

  IMPORTANT! there is a limited number of IOTTE per Crossbow: 7, of which the
  seventh is used to workaround a hardware bug, leaving only 6 entries
  available accross all widgets.

  Each IOTTE opens a contiguous window of 28 or 29 bits, depending on the
  particular system model and configuration.  On Origin 300/3000 and 350/3500,
  this will always be 29 bit (512MB), while on Origin 200/2000 systems, this
  depends on the ``M mode vs N mode'' configuration.  Most systems run in M
  mode (which is the default) which also allows for 29 bit; systems in N mode
  (allowing more than 64 nodes to be connected) can only provide 28 bit IOTTE
  windows (256MB).

  The widget address space is as follows:

   offset         size           description
  0##0000##0000  0##0003##0000  registers
  0##4000##0000  0##4000##0000  PCI memory space
  1##0000##0000  1##0000##0000  PCI I/O space

  Note the PCI memory space is limited to 30 bit; this is supposedly hardware
  enforced, i.e. one may set the top two bits of 32-bit memory BAR and they
  would be ignored.  The xbridge driver doesn't try this though (-:

  IMPORTANT! On Bridge (not XBridge) revision up to 3, the I/O space is not
  available (apparently this would be because of a hardware issue in the
  byteswap logic, causing it to return unpredictable values when accessing
  this address range).
  
- - PCI resource mapping

  Each BAR value is an offset within the memory or I/O space (with the memory
  space being limited to 30 bits, or 1GB), *EXCEPT* when the value fits in one
  of the ``devio'' slots.

  So now is a good time to introduce the devio.

  There are 8 devio registers, one per device; theses registers contain various
  device-global flags (such as byte swapping and coherency), as well as the
  location of a ``devio window'' in one of the address spaces, selected on a
  per-devio basis.

  The devio register only programs the upper 12 bits of the 32 window base
  address, the low 20 bits being zero; the window size are fixed and depend on
  the given device: devices 0 and 1 have ``large'' windows of 2MB (0020##0000),
  while devices 2 to 7 have ``small'' windows of 1MB (0010##0000).

  Apparently there are some hidden rules about the upper 12 bits, though, and
  the rules differ on Octane vs Origin systems.

  This is why the address space, from the pci driver point of view, is split
  in three parts: there is the ``devio black hole'' where we must make sure
  that no BAR allocation crosses a devio boundary, and the rest of the address
  space (under the devio zone and above it).

  I am slowly moving away from the devio mappings the PROM leaves us in, and
  eventually I expect to be able to have more flexibility in their position.
  However there is the console uart mapping I don't want to change now, and -
  of course - we inherit it from the prom as a devio register for the IOC3 or
  IOC4 device.

  So currently, the extents I provide the MI code with span the 0->ffff##ffff
  address space, with only the following areas available:
  - each devio range, if configured for the given address space
  - on Octane, the whole memory or I/O space minus the 16MB area in which all
    devio mappings take place
  - on Origin, if we have an IOTTE mapping a part of the memory or I/O address
    space, the whole window minus the 16MB area in which all devio mappings
    take place.

  Now I need to make sure that the MI code will never allocate mappings
  crossing devio ranges.  So during the Bridge setup, I am initializing
  ALL BAR on a device-by-device basis, working with smaller extents:
  - if the device can have all its resources of a given type (I/O or mem)
    fitting in a devio area, I configure a devio, and make it allocate from
    an extent spanning only the devio range.
  - if there are not enough devio (because the device might need two devio
    ranges, one for I/O resources and one for memory resources, and there are
    only 8 devio, and if the bus is populated there might not be enough unused
    devio slots to hijack), then allocation is done on the larger address space
    (granted on Octane, or provided with an IOTTE window on Origin), using an
    extent covering this area minus the 16MB area in which all devio mappings
    take place.
  So in either case, I am now sure that there are no resources crossing the
  devio boundaries, which are invisible to the MI code.

  This also explains why I am making sure that the devio ranges are close to
  each other - it makes the creation of the temporary resource extents simpler
  (bear in mind that a device might need resources from the IOTTE window before
  all devio ranges are set up).

  And of course to make things even less simple, the IOTTE allocation may fail
  (e.g. on a P-Brick with 6 XBridge chips on the same Crossbow), and if we are
  using an old revision Bridge, all I/O resources need to be allocated with
  devio (so we can't decide to get rid of them anyway).

  So, when it's time to configure further devices (for ppb and pccbb), I need
  the same trick to prevent resource allocation to cross devio boundaries.

  Actually, as far as pccbb is concerned, I give up entirely on resources if
  all I have is a devio to map within - at least for now, because the devio do
  not cover the 0000..ffff range in I/O space needed for pcmcia.  So for the
  I/O resources, I give rbus the low 16 bits of the I/O extent (if available);
  as for the memory resources, I need to exclude the devio area, and since rbus
  currently only supports a single contiguous area, I give it the area starting
  after the devio range (which is, by far, the largest part of the
  at-least-256MB region).

  Do you need aspirin yet?

- - DMA

  Device DMA addresses can be constructed in three ways:
  - direct 64 bit address
  - 32 bit address within a programmable 31 bit ``direct DMA'' window
  - 32 bit translated address using ATE (Address Translation Entries)

  direct 64 bit address:
    These are easy to construct (pick your memory address, set bit 56, and
    you're done), but these can only work with pci devices aware of 64 bit
    addresses.

  direct DMA window:
    There is a Bridge global register to define the base address of the window,
    and then we have 2GB available.  This is what I am currently using, and
    convenient for PCI devices unable to use 64 bit DMA addresses.

  translated DMA:
    There is another 2GB window in which accesses are indirected through ATE,
    which can point anywhere in memory.

    ATE are IOMMU translation entries.  PCI addresses in the translated window
    transparently map to the address their ATE point to.

    Bridge chip have 128 so-called `internal' entries, and can use their
    optional `external' SSRAM to provide more (up to 65536 entries with 512KB
    SSRAM).  However, due to chip bugs, those `external' entries can not be
    updated while there is DMA in progress using external entries, even if the
    updated entries are not related to those used by the DMA transfer.

    XBridge chip extend the internal entries to 1024, but do not provide
    support for external entries.

    All ATE share the same page size, which is configurable as 4KB or 16KB.

    Due to the small number of ATE entries, and since you can not use part of
    the system's RAM to add entries as you need them (unlike hppa or sparc64),
    the driver no longer uses them, as there is nothing we can do when we run
    out of ATE.

- - interrupts

  This is easy, for a change.  There are 8 interrupt sources, one per device;
  pins A and C map of devices 0-7 map to interrupt sources 0-7, and pins B and
  D of devices 0-7 map to interrupt sources 4-7 then 0-3 (i.e. device# ^ 4).

  All interrupts occuring on the Bridge cause an XIO interrupt packet to be
  sent to the XIO interrupt address programmed at Bridge initialization time;
  packets can be configured as self-clearing or not on an interrupt source
  basis.

  Due to silicon bugs, interrupts can be lost if two interrupt sources
  interrupt within a too short interval; there is a documented workaround for
  this which consists of recognizing this situation and self-inflicting
  ourselves the lost interrupt (see details in xbridge_intr_handler() ).

- - endianness

  Endianness control is quite finegrained and quite complex at first glance:
  - memory and I/O accesses not occuring within devio ranges have their
    endianness controlled by the endianness flags in the (global) Bridge
    configuration register...
  - ... to which adds the per-device endianness flag in the device devio
    register...
  - and accesses occuring through devio register only use the
    per-device devio register mentioned above, even if the devio
    range is defined in a different register!

  i.e.

  devio 0 = endianness control C0, devio range R0
  devio 1 = endianness control C1, devio range R1
  global Bridge = endianness control C2

  1. access from device 0 to R0 uses C2^C0
  2. access from device 0 to R1 uses C2^C0
  3. access from device 0 outside R0 and R1 uses C2
  4. access from device 1 to R0 uses C2^C1
  5. access from device 1 to R1 uses C2^C1
  6. access from device 1 outside R0 and R1 uses C1

  (note that, the way I set up devio registers, cases 2 and 4 can never
   occur if both device 0 and device 1 are present)

  Now for DMA:
  - i don't remember what 64 bit DMA uses
  - direct DMA (within the 2GB window) uses a per-device bit in devio
  - translated DMA (using ATE) uses a per-device bit in devio if the
    chip is a Bridge, while XBridge and PIC use different DMA addresses
    (i.e. with a given ATE, there is one address pointing to it in
     non-swapped mode, and another address pointing to it in swapped
     mode).

 */

#include <sys/param.h>
#include <sys/systm.h>
#include <sys/kernel.h>
#include <sys/device.h>
#include <sys/evcount.h>
#include <sys/malloc.h>
#include <sys/proc.h>
#include <sys/extent.h>
#include <sys/mbuf.h>
#include <sys/mutex.h>
#include <sys/queue.h>
#include <sys/atomic.h>

#include <machine/autoconf.h>
#include <machine/bus.h>
#include <machine/cpu.h>
#include <machine/intr.h>
#include <machine/mnode.h>

#include <uvm/uvm_extern.h>

#include <dev/pci/pcireg.h>
#include <dev/pci/pcivar.h>
#include <dev/pci/pcidevs.h>
#include <dev/pci/ppbreg.h>

#include <dev/cardbus/rbus.h>

#include <mips64/archtype.h>
#include <sgi/xbow/xbow.h>
#include <sgi/xbow/xbowdevs.h>

#include <sgi/xbow/widget.h>
#include <sgi/xbow/xbridgereg.h>

#ifdef TGT_OCTANE
#include <sgi/sgi/ip30.h>
#endif

#include "cardbus.h"

int	xbridge_match(struct device *, void *, void *);
void	xbridge_attach(struct device *, struct device *, void *);
int	xbridge_print(void *, const char *);
int	xbridge_submatch(struct device *, void *, void *);
int	xbpci_match(struct device *, void *, void *);
void	xbpci_attach(struct device *, struct device *, void *);
int	xbpci_print(void *, const char *);

struct xbridge_intr;

struct xbpci_attach_args {
	uint	xaa_busno;

	int	xaa_flags;
	int16_t	xaa_nasid;
	int	xaa_widget;
	uint	xaa_devio_skew;
	int	xaa_revision;

	bus_space_tag_t	xaa_regt;
	bus_addr_t	xaa_offset;
};

struct xbpci_softc {
	struct device	xb_dev;
	struct device	*xb_bow;

	/*
	 * Bridge register accessors.
	 * Due to hardware bugs, PIC registers can only be accessed
	 * with 64 bit operations, although the hardware was supposed
	 * to be directly compatible with XBridge on that aspect.
	 */
	uint64_t	(*xb_read_reg)(bus_space_tag_t, bus_space_handle_t,
			    bus_addr_t);
	void		(*xb_write_reg)(bus_space_tag_t, bus_space_handle_t,
			    bus_addr_t, uint64_t);

	uint		xb_busno;
	uint		xb_nslots;

	int		xb_flags;
#define	XF_XBRIDGE		0x01	/* is either PIC or XBridge */
#define	XF_PIC			0x02	/* is PIC */
#define	XF_NO_DIRECT_IO		0x04	/* no direct I/O mapping */
#define	XF_PCIX			0x08	/* bus in PCIX mode */
	int16_t		xb_nasid;
	int		xb_widget;
	uint		xb_devio_skew;	/* upper bits of devio ARCS mappings */
	int		xb_revision;

	struct mips_pci_chipset xb_pc;

	bus_space_tag_t	xb_regt;
	bus_space_handle_t xb_regh;

	struct mips_bus_space *xb_mem_bus_space;
	struct mips_bus_space *xb_mem_bus_space_sw;
	struct mips_bus_space *xb_io_bus_space;
	struct mips_bus_space *xb_io_bus_space_sw;
	struct machine_bus_dma_tag *xb_dmat;

	struct xbridge_intr	*xb_intr[BRIDGE_NINTRS];
	char	xb_intrstr[BRIDGE_NINTRS][sizeof("irq #, xbow irq ###")];

	int		xb_err_intrsrc;
	int		(*xb_pci_intr_handler)(void *);

	uint64_t	xb_ier;		/* copy of BRIDGE_IER value */

	/*
	 * Device information.
	 */
	struct {
		pcireg_t	id;
		uint32_t	devio;
	} xb_devices[MAX_SLOTS];
	uint		xb_devio_usemask;

	/*
	 * Large resource view sizes
	 */
	bus_addr_t	xb_iostart, xb_ioend;
	bus_addr_t	xb_memstart, xb_memend;

	/*
	 * Resource extents for the large resource views, used during
	 * resource setup, then cleaned up for the MI code.
	 */
	char		xb_ioexname[32];
	struct extent	*xb_ioex;
	char		xb_memexname[32];
	struct extent	*xb_memex;
};

struct xbridge_softc {
	struct device	sc_dev;
	uint		sc_nbuses;

	struct mips_bus_space	sc_regt;
};

#define	DEVNAME(xb)	((xb)->xb_dev.dv_xname)

#define	PCI_ID_EMPTY		PCI_ID_CODE(PCI_VENDOR_INVALID, 0xffff);
#define	SLOT_EMPTY(xb,dev) \
	(PCI_VENDOR((xb)->xb_devices[dev].id) == PCI_VENDOR_INVALID || \
	 PCI_VENDOR((xb)->xb_devices[dev].id) == 0)

const struct cfattach xbridge_ca = {
	sizeof(struct xbridge_softc), xbridge_match, xbridge_attach
};

struct cfdriver xbridge_cd = {
	NULL, "xbridge", DV_DULL
};

const struct cfattach xbpci_ca = {
	sizeof(struct xbpci_softc), xbpci_match, xbpci_attach
};

struct cfdriver xbpci_cd = {
	NULL, "xbpci", DV_DULL
};

void	xbridge_attach_hook(struct device *, struct device *,
				struct pcibus_attach_args *);
int	xbridge_bus_maxdevs(void *, int);
pcitag_t xbridge_make_tag(void *, int, int, int);
void	xbridge_decompose_tag(void *, pcitag_t, int *, int *, int *);
int	xbridge_conf_size(void *, pcitag_t);
pcireg_t xbridge_conf_read(void *, pcitag_t, int);
void	xbridge_conf_write(void *, pcitag_t, int, pcireg_t);
int	xbridge_intr_map(struct pci_attach_args *, pci_intr_handle_t *);
const char *xbridge_intr_string(void *, pci_intr_handle_t);
void	*xbridge_intr_establish(void *, pci_intr_handle_t, int,
	    int (*func)(void *), void *, const 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 *);
int	xbridge_probe_device_hook(void *, struct pci_attach_args *);
void	*xbridge_rbus_parent_io(struct pci_attach_args *);
void	*xbridge_rbus_parent_mem(struct pci_attach_args *);
int	xbridge_get_widget(void *);
int	xbridge_get_dl(void *, pcitag_t, struct sgi_device_location *);

int	xbridge_pci_intr_handler(void *);
int	xbridge_picv1_pci_intr_handler(void *);
int	xbridge_err_intr_handler(void *);

uint8_t xbridge_read_1(bus_space_tag_t, bus_space_handle_t, bus_size_t);
uint16_t xbridge_read_2(bus_space_tag_t, bus_space_handle_t, bus_size_t);
void	xbridge_write_1(bus_space_tag_t, bus_space_handle_t, bus_size_t,
	    uint8_t);
void	xbridge_write_2(bus_space_tag_t, bus_space_handle_t, bus_size_t,
	    uint16_t);
void	xbridge_read_raw_2(bus_space_tag_t, bus_space_handle_t, bus_addr_t,
	    uint8_t *, bus_size_t);
void	xbridge_write_raw_2(bus_space_tag_t, bus_space_handle_t, bus_addr_t,
	    const uint8_t *, bus_size_t);
void	xbridge_read_raw_4(bus_space_tag_t, bus_space_handle_t, bus_addr_t,
	    uint8_t *, bus_size_t);
void	xbridge_write_raw_4(bus_space_tag_t, bus_space_handle_t, bus_addr_t,
	    const uint8_t *, bus_size_t);
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_devio(bus_space_tag_t, bus_addr_t, bus_size_t, int,
	    bus_space_handle_t *);
int	xbridge_space_map_io(bus_space_tag_t, bus_addr_t, bus_size_t, int,
	    bus_space_handle_t *);
int	xbridge_space_map_mem(bus_space_tag_t, bus_addr_t, bus_size_t, int,
	    bus_space_handle_t *);
int	xbridge_space_region_devio(bus_space_tag_t, bus_space_handle_t,
	    bus_size_t, bus_size_t, bus_space_handle_t *);
int	xbridge_space_region_io(bus_space_tag_t, bus_space_handle_t,
	    bus_size_t, bus_size_t, bus_space_handle_t *);
int	xbridge_space_region_mem(bus_space_tag_t, bus_space_handle_t,
	    bus_size_t, bus_size_t, bus_space_handle_t *);

void	xbridge_space_barrier(bus_space_tag_t, bus_space_handle_t,
	    bus_size_t, bus_size_t, int);

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 *);

void	xbridge_err_clear(struct xbpci_softc *, uint64_t);
void	xbridge_err_handle(struct xbpci_softc *, uint64_t);

int	xbridge_allocate_devio(struct xbpci_softc *, int, int);
void	xbridge_set_devio(struct xbpci_softc *, int, uint32_t, int);

int	xbridge_resource_explore(struct xbpci_softc *, pcitag_t,
	    struct extent *, struct extent *);
void	xbridge_resource_manage(struct xbpci_softc *, pcitag_t,
	    struct extent *, struct extent *);

void	xbridge_device_setup(struct xbpci_softc *, int, int, uint32_t);
int	xbridge_extent_chomp(struct xbpci_softc *, struct extent *);
void	xbridge_extent_setup(struct xbpci_softc *);
struct extent *
	xbridge_mapping_setup(struct xbpci_softc *, int);
void	xbridge_resource_setup(struct xbpci_softc *);
void	xbridge_rrb_setup(struct xbpci_softc *, int);
const char *
	xbridge_setup(struct xbpci_softc *);

uint64_t bridge_read_reg(bus_space_tag_t, bus_space_handle_t, bus_addr_t);
void	bridge_write_reg(bus_space_tag_t, bus_space_handle_t, bus_addr_t,
	    uint64_t);
uint64_t pic_read_reg(bus_space_tag_t, bus_space_handle_t, bus_addr_t);
void	pic_write_reg(bus_space_tag_t, bus_space_handle_t, bus_addr_t,
	    uint64_t);

static __inline__ uint64_t
xbridge_read_reg(struct xbpci_softc *xb, bus_addr_t a)
{
	return (*xb->xb_read_reg)(xb->xb_regt, xb->xb_regh, a);
}
static __inline__ void
xbridge_write_reg(struct xbpci_softc *xb, bus_addr_t a, uint64_t v)
{
	(*xb->xb_write_reg)(xb->xb_regt, xb->xb_regh, a, v);
}

static __inline__ void
xbridge_wbflush(struct xbpci_softc *xb, uint d)
{
	while (xbridge_read_reg(xb, BRIDGE_DEVICE_WBFLUSH(d)) != 0) ;
}

static const struct machine_bus_dma_tag xbridge_dma_tag = {
	NULL,			/* _cookie */
	_dmamap_create,
	_dmamap_destroy,
	_dmamap_load,
	_dmamap_load_mbuf,
	_dmamap_load_uio,
	_dmamap_load_raw,
	_dmamap_load_buffer,
	_dmamap_unload,
	_dmamap_sync,
	_dmamem_alloc,
	_dmamem_free,
	_dmamem_map,
	_dmamem_unmap,
	_dmamem_mmap,
	xbridge_pa_to_device,
	xbridge_device_to_pa,
	BRIDGE_DMA_DIRECT_LENGTH - 1
};

static const struct mips_pci_chipset xbridge_pci_chipset = {
	.pc_attach_hook = xbridge_attach_hook,
	.pc_bus_maxdevs = xbridge_bus_maxdevs,
	.pc_make_tag = xbridge_make_tag,
	.pc_decompose_tag = xbridge_decompose_tag,
	.pc_conf_size = xbridge_conf_size,
	.pc_conf_read = xbridge_conf_read,
	.pc_conf_write = xbridge_conf_write,
	.pc_probe_device_hook = xbridge_probe_device_hook,
	.pc_get_widget = xbridge_get_widget,
	.pc_get_dl = xbridge_get_dl,
	.pc_intr_map = xbridge_intr_map,
	.pc_intr_string = xbridge_intr_string,
	.pc_intr_establish = xbridge_intr_establish,
	.pc_intr_disestablish = xbridge_intr_disestablish,
	.pc_intr_line = xbridge_intr_line,
	.pc_ppb_setup = xbridge_ppb_setup,
#if NCARDBUS > 0
	.pc_rbus_parent_io = xbridge_rbus_parent_io,
	.pc_rbus_parent_mem = xbridge_rbus_parent_mem
#endif
};

/*
 ********************* Autoconf glue.
 */

static const struct {
	uint32_t vendor;
	uint32_t product;
	int	flags;
} xbridge_devices[] = {
	/* original Bridge */
	{ XBOW_VENDOR_SGI4, XBOW_PRODUCT_SGI4_BRIDGE,	0 },
	/* XBridge */
	{ XBOW_VENDOR_SGI3, XBOW_PRODUCT_SGI3_XBRIDGE,	XF_XBRIDGE },
	/* PIC */
	{ XBOW_VENDOR_SGI3, XBOW_PRODUCT_SGI3_PIC,	XF_PIC }
};

int
xbridge_match(struct device *parent, void *match, void *aux)
{
	struct xbow_attach_args *xaa = aux;
	uint i;

	for (i = 0; i < nitems(xbridge_devices); i++)
		if (xaa->xaa_vendor == xbridge_devices[i].vendor &&
		    xaa->xaa_product == xbridge_devices[i].product)
			return 1;

	return 0;
}

void
xbridge_attach(struct device *parent, struct device *self, void *aux)
{
	struct xbridge_softc *sc = (struct xbridge_softc *)self;
	struct xbow_attach_args *xaa = aux;
	struct xbpci_attach_args xbpa;
	int flags;
	uint devio_skew;
	uint i;

	printf(" revision %d\n", xaa->xaa_revision);

	for (i = 0; i < nitems(xbridge_devices); i++)
		if (xaa->xaa_vendor == xbridge_devices[i].vendor &&
		    xaa->xaa_product == xbridge_devices[i].product) {
			flags = xbridge_devices[i].flags;
			break;
		}

	/* PICs are XBridges without an I/O window */
	if (ISSET(flags, XF_PIC))
		SET(flags, XF_XBRIDGE | XF_NO_DIRECT_IO);
	/* Bridge < D lacks an I/O window */
	if (!ISSET(flags, XF_XBRIDGE) && xaa->xaa_revision < 4)
		SET(flags, XF_NO_DIRECT_IO);

	/*
	 * Figure out where the ARCS devio mappings will go.
	 * ARCS configures all the devio in a contiguous 16MB area
	 * (i.e. the upper 8 bits of the DEVIO_BASE field of the
	 * devio registers are the same).
	 *
	 * In order to make our life simpler, on widgets where we may
	 * want to keep some of the ARCS mappings (because that's where
	 * our console device lives), we will use the same 16MB area.
	 *
	 * Otherwise, we can use whatever values we want; to keep the
	 * code simpler, we will nevertheless use a 16MB area as well,
	 * making sure it does not start at zero so that pcmcia bridges
	 * can be used.
	 *
	 * On Octane, the upper bits of ARCS mappings are zero, and thus
	 * point to the start of the widget. On Origin, they match the
	 * widget number.
	 */
#ifdef TGT_OCTANE
	if (sys_config.system_type == SGI_OCTANE &&
	    xaa->xaa_widget == IP30_BRIDGE_WIDGET)
		devio_skew = 0;
	else
#endif
		devio_skew = xaa->xaa_widget;

	sc->sc_nbuses = ISSET(flags, XF_PIC) ? PIC_NBUSES : BRIDGE_NBUSES;

	/* make a permanent copy of the on-stack bus_space_tag */
	bcopy(xaa->xaa_iot, &sc->sc_regt, sizeof(struct mips_bus_space));

	/* configure and attach PCI buses */
	for (i = 0; i < sc->sc_nbuses; i++) {
		xbpa.xaa_busno = i;
		xbpa.xaa_flags = flags;
		xbpa.xaa_nasid = xaa->xaa_nasid;
		xbpa.xaa_widget = xaa->xaa_widget;
		xbpa.xaa_devio_skew = devio_skew;
		xbpa.xaa_revision = xaa->xaa_revision;
		xbpa.xaa_regt = &sc->sc_regt;
		xbpa.xaa_offset = i != 0 ? BRIDGE_BUS_OFFSET : 0;

		config_found_sm(&sc->sc_dev, &xbpa, xbridge_print,
		    xbridge_submatch);
	}
}

int
xbridge_submatch(struct device *parent, void *vcf, void *aux)
{
	struct cfdata *cf = vcf;
	struct xbpci_attach_args *xaa = aux;

	if (cf->cf_loc[0] != -1 && cf->cf_loc[0] != xaa->xaa_busno)
		return 0;

	return (*cf->cf_attach->ca_match)(parent, vcf, aux);
}

int
xbridge_print(void *aux, const char *pnp)
{
	struct xbpci_attach_args *xaa = aux;

	if (pnp)
		printf("xbpci at %s", pnp);
	printf(" bus %d", xaa->xaa_busno);

	return UNCONF;
}

int
xbpci_match(struct device *parent, void *vcf, void *aux)
{
	return 1;
}

void
xbpci_attach(struct device *parent, struct device *self, void *aux)
{
	struct xbpci_softc *xb = (struct xbpci_softc *)self;
	struct xbpci_attach_args *xaa = (struct xbpci_attach_args *)aux;
	struct pcibus_attach_args pba;
	const char *errmsg = NULL;

	printf(": ");

	/* xbow -> xbridge -> xbpci: xbow device is our grandfather */
	xb->xb_bow = parent->dv_parent;
	xb->xb_busno = xaa->xaa_busno;
	xb->xb_flags = xaa->xaa_flags;
	xb->xb_nasid = xaa->xaa_nasid;
	xb->xb_widget = xaa->xaa_widget;
	xb->xb_devio_skew = xaa->xaa_devio_skew;
	xb->xb_revision = xaa->xaa_revision;

	if (ISSET(xb->xb_flags, XF_PIC)) {
		xb->xb_nslots = PIC_NSLOTS;

		xb->xb_read_reg = pic_read_reg;
		xb->xb_write_reg = pic_write_reg;
	} else {
		xb->xb_nslots = BRIDGE_NSLOTS;

		xb->xb_read_reg = bridge_read_reg;
		xb->xb_write_reg = bridge_write_reg;
	}

	/*
	 * Revision 1 of PIC requires a wrapper around
	 * xbridge_pci_intr_handler().
	 */
	if (ISSET(xb->xb_flags, XF_PIC) && xb->xb_revision <= 1)
		xb->xb_pci_intr_handler = xbridge_picv1_pci_intr_handler;
	else
		xb->xb_pci_intr_handler = xbridge_pci_intr_handler;

	/*
	 * Map Bridge registers.
	 */

	xb->xb_regt = xaa->xaa_regt;
	if (bus_space_map(xaa->xaa_regt, xaa->xaa_offset,
	    BRIDGE_REGISTERS_SIZE, 0, &xb->xb_regh)) {
		printf("unable to map control registers\n");
		return;
	}

	/*
	 * Create bus_space accessors... we inherit them from xbow, but
	 * need to overwrite mapping routines, and set up byteswapping
	 * versions.
	 */

	xb->xb_mem_bus_space = malloc(sizeof (*xb->xb_mem_bus_space),
	    M_DEVBUF, M_NOWAIT);
	xb->xb_mem_bus_space_sw = malloc(sizeof (*xb->xb_mem_bus_space_sw),
	    M_DEVBUF, M_NOWAIT);
	xb->xb_io_bus_space = malloc(sizeof (*xb->xb_io_bus_space),
	    M_DEVBUF, M_NOWAIT);
	xb->xb_io_bus_space_sw = malloc(sizeof (*xb->xb_io_bus_space_sw),
	    M_DEVBUF, M_NOWAIT);
	if (xb->xb_mem_bus_space == NULL || xb->xb_mem_bus_space_sw == NULL ||
	    xb->xb_io_bus_space == NULL || xb->xb_io_bus_space_sw == NULL)
		goto fail1;

	bcopy(xb->xb_regt, xb->xb_mem_bus_space, sizeof(*xb->xb_mem_bus_space));
	xb->xb_mem_bus_space->bus_private = xb;
	xb->xb_mem_bus_space->_space_map = xbridge_space_map_devio;
	xb->xb_mem_bus_space->_space_subregion = xbridge_space_region_devio;
	xb->xb_mem_bus_space->_space_barrier = xbridge_space_barrier;

	bcopy(xb->xb_mem_bus_space, xb->xb_mem_bus_space_sw,
	    sizeof(*xb->xb_mem_bus_space));
	xb->xb_mem_bus_space_sw->_space_read_1 = xbridge_read_1;
	xb->xb_mem_bus_space_sw->_space_write_1 = xbridge_write_1;
	xb->xb_mem_bus_space_sw->_space_read_2 = xbridge_read_2;
	xb->xb_mem_bus_space_sw->_space_write_2 = xbridge_write_2;
	xb->xb_mem_bus_space_sw->_space_read_raw_2 = xbridge_read_raw_2;
	xb->xb_mem_bus_space_sw->_space_write_raw_2 = xbridge_write_raw_2;
	xb->xb_mem_bus_space_sw->_space_read_raw_4 = xbridge_read_raw_4;
	xb->xb_mem_bus_space_sw->_space_write_raw_4 = xbridge_write_raw_4;
	xb->xb_mem_bus_space_sw->_space_read_raw_8 = xbridge_read_raw_8;
	xb->xb_mem_bus_space_sw->_space_write_raw_8 = xbridge_write_raw_8;

	bcopy(xb->xb_regt, xb->xb_io_bus_space, sizeof(*xb->xb_io_bus_space));
	xb->xb_io_bus_space->bus_private = xb;
	xb->xb_io_bus_space->_space_map = xbridge_space_map_devio;
	xb->xb_io_bus_space->_space_subregion = xbridge_space_region_devio;
	xb->xb_io_bus_space->_space_barrier = xbridge_space_barrier;

	bcopy(xb->xb_io_bus_space, xb->xb_io_bus_space_sw,
	    sizeof(*xb->xb_io_bus_space));
	xb->xb_io_bus_space_sw->_space_read_1 = xbridge_read_1;
	xb->xb_io_bus_space_sw->_space_write_1 = xbridge_write_1;
	xb->xb_io_bus_space_sw->_space_read_2 = xbridge_read_2;
	xb->xb_io_bus_space_sw->_space_write_2 = xbridge_write_2;
	xb->xb_io_bus_space_sw->_space_read_raw_2 = xbridge_read_raw_2;
	xb->xb_io_bus_space_sw->_space_write_raw_2 = xbridge_write_raw_2;
	xb->xb_io_bus_space_sw->_space_read_raw_4 = xbridge_read_raw_4;
	xb->xb_io_bus_space_sw->_space_write_raw_4 = xbridge_write_raw_4;
	xb->xb_io_bus_space_sw->_space_read_raw_8 = xbridge_read_raw_8;
	xb->xb_io_bus_space_sw->_space_write_raw_8 = xbridge_write_raw_8;

	xb->xb_dmat = malloc(sizeof (*xb->xb_dmat), M_DEVBUF, M_NOWAIT);
	if (xb->xb_dmat == NULL)
		goto fail1;
	memcpy(xb->xb_dmat, &xbridge_dma_tag, sizeof(*xb->xb_dmat));
	xb->xb_dmat->_cookie = xb;

	/*
	 * Initialize PCI methods.
	 */

	bcopy(&xbridge_pci_chipset, &xb->xb_pc, sizeof(xbridge_pci_chipset));
	xb->xb_pc.pc_conf_v = xb;
	xb->xb_pc.pc_intr_v = xb;

	/*
	 * Configure Bridge for proper operation (DMA, I/O mappings,
	 * RRB allocation, etc).
	 */

	if ((errmsg = xbridge_setup(xb)) != NULL)
		goto fail2;
	printf("\n");

	/*
	 * Attach children.
	 */

	xbridge_extent_setup(xb);

	bzero(&pba, sizeof(pba));
	pba.pba_busname = "pci";
	/*
	 * XXX pba_iot and pba_memt ought to be irrelevant, since we
	 * XXX return the tags a device needs in probe_device_hook();
	 * XXX however the pci(4) device needs a valid pba_memt for the
	 * XXX PCIOCGETROM* ioctls.
	 * XXX
	 * XXX Since most devices will need the byteswap tags, and those
	 * XXX which don't do not have PCI roms, let's pass the byteswap
	 * XXX versions by default.
	 */
	pba.pba_iot = xb->xb_io_bus_space_sw;
	pba.pba_memt = xb->xb_mem_bus_space_sw;
	pba.pba_dmat = xb->xb_dmat;
	pba.pba_ioex = xb->xb_ioex;
	pba.pba_memex = xb->xb_memex;
#ifdef DEBUG
	if (xb->xb_ioex != NULL)
		extent_print(xb->xb_ioex);
	if (xb->xb_memex != NULL)
		extent_print(xb->xb_memex);
#endif
	pba.pba_pc = &xb->xb_pc;
	pba.pba_domain = pci_ndomains++;
	pba.pba_bus = 0;

	config_found(self, &pba, xbpci_print);
	return;

fail2:
	free(xb->xb_dmat, M_DEVBUF, 0);
fail1:
	if (xb->xb_io_bus_space_sw != NULL)
		free(xb->xb_io_bus_space_sw, M_DEVBUF, 0);
	if (xb->xb_io_bus_space != NULL)
		free(xb->xb_io_bus_space, M_DEVBUF, 0);
	if (xb->xb_mem_bus_space_sw != NULL)
		free(xb->xb_mem_bus_space_sw, M_DEVBUF, 0);
	if (xb->xb_mem_bus_space != NULL)
		free(xb->xb_mem_bus_space, M_DEVBUF, 0);
	if (errmsg == NULL)
		errmsg = "not enough memory to build bus access structures";
	printf("%s\n", errmsg);
}

int
xbpci_print(void *aux, const char *pnp)
{
	struct pcibus_attach_args *pba = aux;

	if (pnp)
		printf("%s at %s", pba->pba_busname, pnp);
	printf(" bus %d", pba->pba_bus);

	return UNCONF;
}

/*
 ********************* PCI glue.
 */

void
xbridge_attach_hook(struct device *parent, struct device *self,
    struct pcibus_attach_args *pba)
{
}

pcitag_t
xbridge_make_tag(void *cookie, int bus, int dev, int func)
{
	return (bus << 16) | (dev << 11) | (func << 8);
}

void
xbridge_decompose_tag(void *cookie, pcitag_t tag, int *busp, int *devp,
    int *funcp)
{
	if (busp != NULL)
		*busp = (tag >> 16) & 0xff;
	if (devp != NULL)
		*devp = (tag >> 11) & 0x1f;
	if (funcp != NULL)
		*funcp = (tag >> 8) & 0x7;
}

int
xbridge_bus_maxdevs(void *cookie, int busno)
{
	struct xbpci_softc *xb = cookie;

	return busno == 0 ? xb->xb_nslots : 32;
}

int
xbridge_conf_size(void *cookie, pcitag_t tag)
{
#if 0
	struct xbpci_softc *xb = cookie;
	int bus, dev, fn;

	xbridge_decompose_tag(cookie, tag, &bus, &dev, &fn);

	/*
	 * IOC3 devices only implement a subset of the PCI configuration
	 * registers. Although xbridge_conf_{read,write} correctly
	 * handle the unimplemented registers, better provide a limited
	 * configuration space to userland.
	 */

	if (bus == 0 && xb->xb_devices[dev].id ==
	    PCI_ID_CODE(PCI_VENDOR_SGI, PCI_PRODUCT_SGI_IOC3))
		return PCI_INTERRUPT_REG + 4;
#endif

	return PCI_CONFIG_SPACE_SIZE;
}

pcireg_t
xbridge_conf_read(void *cookie, pcitag_t tag, int offset)
{
	struct xbpci_softc *xb = cookie;
	pcireg_t data;
	int bus, dev, fn;
	paddr_t pa;
	int skip;
	int s;

	xbridge_decompose_tag(cookie, tag, &bus, &dev, &fn);

	/*
	 * IOC3 devices only implement a subset of the PCI configuration
	 * registers (supposedly only the first 0x20 bytes, however
	 * writing to the second BAR also writes to the first).
	 *
	 * Depending on which particular model we encounter, things may
	 * seem to work, or write access to nonexisting registers would
	 * completely freeze the machine.
	 *
	 * We thus check for the device type here, and handle the non
	 * existing registers ourselves.
	 */

	skip = 0;
	if (bus == 0 && xb->xb_devices[dev].id ==
	    PCI_ID_CODE(PCI_VENDOR_SGI, PCI_PRODUCT_SGI_IOC3)) {
		switch (offset) {
		case PCI_ID_REG:
		case PCI_COMMAND_STATUS_REG:
		case PCI_CLASS_REG:
		case PCI_BHLC_REG:
		case PCI_MAPREG_START:
			/* These registers are implemented. Go ahead. */
			break;
		case PCI_INTERRUPT_REG:
			/* This register is not implemented. Fake it. */
			data = (PCI_INTERRUPT_PIN_A <<
			    PCI_INTERRUPT_PIN_SHIFT) |
			    (dev << PCI_INTERRUPT_LINE_SHIFT);
			skip = 1;
			break;
		default:
			/* These registers are not implemented. */
			data = 0;
			skip = 1;
			break;
		}
	}

	if (skip == 0) {
		/*
		 * Disable interrupts on this bridge (especially error
		 * interrupts).
		 */
		s = splhigh();
		xbridge_write_reg(xb, BRIDGE_IER, 0);
		(void)xbridge_read_reg(xb, WIDGET_TFLUSH);

		if (bus != 0) {
			xbridge_write_reg(xb, BRIDGE_PCI_CFG,
			    (bus << 16) | (dev << 11));
			pa = xb->xb_regh + BRIDGE_PCI_CFG1_SPACE;
		} else {
			/*
			 * On PIC, device 0 in configuration space is the
			 * PIC itself, device slots are offset by one.
			 */
			if (ISSET(xb->xb_flags, XF_PIC))
				dev++;
			pa = xb->xb_regh + BRIDGE_PCI_CFG_SPACE + (dev << 12);
		}

		pa += (fn << 8) + offset;
		if (guarded_read_4(pa, &data) != 0)
			data = 0xffffffff;

		xbridge_write_reg(xb, BRIDGE_IER, xb->xb_ier);
		(void)xbridge_read_reg(xb, WIDGET_TFLUSH);
		splx(s);
	}

	return data;
}

void
xbridge_conf_write(void *cookie, pcitag_t tag, int offset, pcireg_t data)
{
	struct xbpci_softc *xb = cookie;
	int bus, dev, fn;
	paddr_t pa;
	int skip;
	int s;

	xbridge_decompose_tag(cookie, tag, &bus, &dev, &fn);

	/*
	 * IOC3 devices only implement a subset of the PCI configuration
	 * registers.
	 * Depending on which particular model we encounter, things may
	 * seem to work, or write access to nonexisting registers would
	 * completely freeze the machine.
	 *
	 * We thus check for the device type here, and handle the non
	 * existing registers ourselves.
	 */

	skip = 0;
	if (bus == 0 && xb->xb_devices[dev].id ==
	    PCI_ID_CODE(PCI_VENDOR_SGI, PCI_PRODUCT_SGI_IOC3)) {
		switch (offset) {
		case PCI_COMMAND_STATUS_REG:
			/*
			 * Some IOC3 models do not support having this bit
			 * cleared (which is what pci_mapreg_probe() will
			 * do), so we set it unconditionnaly.
			 */
			data |= PCI_COMMAND_MEM_ENABLE;
			/* FALLTHROUGH */
		case PCI_ID_REG:
		case PCI_CLASS_REG:
		case PCI_BHLC_REG:
		case PCI_MAPREG_START:
			/* These registers are implemented. Go ahead. */
			break;
		default:
			/* These registers are not implemented. */
			skip = 1;
			break;
		}
	}

	if (skip == 0) {
		/*
		 * Disable interrupts on this bridge (especially error
		 * interrupts).
		 */
		s = splhigh();
		xbridge_write_reg(xb, BRIDGE_IER, 0);
		(void)xbridge_read_reg(xb, WIDGET_TFLUSH);

		if (bus != 0) {
			xbridge_write_reg(xb, BRIDGE_PCI_CFG,
			    (bus << 16) | (dev << 11));
			pa = xb->xb_regh + BRIDGE_PCI_CFG1_SPACE;
		} else {
			/*
			 * On PIC, device 0 in configuration space is the
			 * PIC itself, device slots are offset by one.
			 */
			if (ISSET(xb->xb_flags, XF_PIC))
				dev++;
			pa = xb->xb_regh + BRIDGE_PCI_CFG_SPACE + (dev << 12);
		}

		pa += (fn << 8) + offset;
		guarded_write_4(pa, data);

		xbridge_write_reg(xb, BRIDGE_IER, xb->xb_ier);
		(void)xbridge_read_reg(xb, WIDGET_TFLUSH);
		splx(s);
	}
}

int
xbridge_probe_device_hook(void *cookie, struct pci_attach_args *pa)
{
	struct xbpci_softc *xb = cookie;

	/*
	 * Check for the hardware byteswap setting of the device we are
	 * interested in, and pick bus_space_tag accordingly.
	 * Note that the device list here must match xbridge_resource_setup().
	 */
	if (pa->pa_id == PCI_ID_CODE(PCI_VENDOR_SGI, PCI_PRODUCT_SGI_IOC3) ||
	    pa->pa_id == PCI_ID_CODE(PCI_VENDOR_SGI, PCI_PRODUCT_SGI_IOC4) ||
	    pa->pa_id == PCI_ID_CODE(PCI_VENDOR_SGI, PCI_PRODUCT_SGI_RAD1)) {
		pa->pa_iot = xb->xb_io_bus_space;
		pa->pa_memt = xb->xb_mem_bus_space;
	} else {
		pa->pa_iot = xb->xb_io_bus_space_sw;
		pa->pa_memt = xb->xb_mem_bus_space_sw;
	}

	return 0;
}

int
xbridge_get_widget(void *cookie)
{
	struct xbpci_softc *xb = cookie;

	return xb->xb_widget;
}

int
xbridge_get_dl(void *cookie, pcitag_t tag, struct sgi_device_location *sdl)
{
	int bus, device, fn;
	struct xbpci_softc *xb = cookie;

	xbridge_decompose_tag(cookie, tag, &bus, &device, &fn);
	if (bus != 0)
		return 0;

	sdl->nasid = xb->xb_nasid;
	sdl->widget = xb->xb_widget;

	sdl->bus = xb->xb_busno;
	sdl->device = device;
	sdl->fn = fn;

	return 1;
}

/*
 ********************* Interrupt handling.
 */

/*
 * We map each slot to its own interrupt bit, which will in turn be routed to
 * the Heart or Hub widget in charge of interrupt processing.
 */

struct xbridge_intrhandler {
	LIST_ENTRY(xbridge_intrhandler)	xih_nxt;
	struct xbridge_intr *xih_main;
	int	(*xih_func)(void *);
	void	*xih_arg;
	struct evcount	xih_count;
	int	 xih_level;
	int	 xih_device;	/* device slot number */
};

struct xbridge_intr {
	struct	xbpci_softc	*xi_bus;
	int	xi_intrsrc;	/* interrupt source on interrupt widget */
	int	xi_intrbit;	/* interrupt source on BRIDGE */
	LIST_HEAD(, xbridge_intrhandler) xi_handlers;
};

/* how our pci_intr_handle_t are constructed... */
#define	XBRIDGE_INTR_VALID		0x100
#define	XBRIDGE_INTR_HANDLE(d,b)	(XBRIDGE_INTR_VALID | ((d) << 3) | (b))
#define	XBRIDGE_INTR_DEVICE(h)		(((h) >> 3) & 07)
#define	XBRIDGE_INTR_BIT(h)		((h) & 07)

int
xbridge_intr_map(struct pci_attach_args *pa, pci_intr_handle_t *ihp)
{
	struct xbpci_softc *xb = pa->pa_pc->pc_conf_v;
	int bus, device, intr;
	int pin;

	*ihp = 0;

	if (pa->pa_intrpin == 0) {
		/* No IRQ used. */
		return 1;
	}

#ifdef DIAGNOSTIC
	if (pa->pa_intrpin > 4) {
		printf("%s: bad interrupt pin %d\n", __func__, pa->pa_intrpin);
		return 1;
	}
#endif

	pci_decompose_tag(pa->pa_pc, pa->pa_tag, &bus, &device, NULL);

	if (pa->pa_bridgetag) {
		pin = PPB_INTERRUPT_SWIZZLE(pa->pa_rawintrpin, device);
		if (!ISSET(pa->pa_bridgeih[pin - 1], XBRIDGE_INTR_VALID))
			return 0;
		intr = XBRIDGE_INTR_BIT(pa->pa_bridgeih[pin - 1]);
	} else {
		/*
		 * For IOC3 devices, pin A is always the regular PCI interrupt,
		 * but wiring of interrupt pin B may vary.
		 * We rely upon ioc(4) being able to figure out whether it's
		 * an onboard chip or not, and to require interrupt pin D
		 * instead of B in the former case.
		 */
		intr = -1;
		if (xb->xb_devices[device].id ==
		    PCI_ID_CODE(PCI_VENDOR_SGI, PCI_PRODUCT_SGI_IOC3)) {

			switch (pa->pa_intrpin) {
			case PCI_INTERRUPT_PIN_A:
			case PCI_INTERRUPT_PIN_B:
				break;
			case PCI_INTERRUPT_PIN_D:
				/*
				 * If this device is an onboard IOC3,
				 * interrupt pin B is wired as pin A of
				 * the first empty PCI slot...
				 */
				for (intr = 0; intr < MAX_SLOTS; intr++)
					if (SLOT_EMPTY(xb, intr))
						break;
				/* should not happen, but fallback anyway */
				if (intr >= MAX_SLOTS)
					intr = -1;
				break;
			default:
				return 1;
			}
		}
		if (intr < 0) {
			if (pa->pa_intrpin & 1)
				intr = device;
			else
				intr = device ^ 4;
		}
	}

	*ihp = XBRIDGE_INTR_HANDLE(device, intr);

	return 0;
}

const char *
xbridge_intr_string(void *cookie, pci_intr_handle_t ih)
{
	struct xbpci_softc *xb = (struct xbpci_softc *)cookie;
	int intrbit = XBRIDGE_INTR_BIT(ih);

	if (xb->xb_intrstr[intrbit][0] == '\0')
		snprintf(xb->xb_intrstr[intrbit],
		    sizeof xb->xb_intrstr[intrbit], "irq %ld", ih);
	return xb->xb_intrstr[intrbit];
}

void *
xbridge_intr_establish(void *cookie, pci_intr_handle_t ih, int level,
    int (*func)(void *), void *arg, const char *name)
{
	struct xbpci_softc *xb = (struct xbpci_softc *)cookie;
	struct xbridge_intr *xi;
	struct xbridge_intrhandler *xih;
	uint64_t int_addr;
	int intrbit = XBRIDGE_INTR_BIT(ih);
	int device = XBRIDGE_INTR_DEVICE(ih);
	int intrsrc;
	int new;

	/*
	 * Allocate bookkeeping structure if this is the
	 * first time we're using this interrupt source.
	 */
	if ((xi = xb->xb_intr[intrbit]) == NULL) {
		xi = (struct xbridge_intr *)
		    malloc(sizeof(*xi), M_DEVBUF, M_NOWAIT);
		if (xi == NULL)
			return NULL;

		xi->xi_bus = xb;
		xi->xi_intrbit = intrbit;
		LIST_INIT(&xi->xi_handlers);

		if (xbow_intr_register(xb->xb_widget, level, &intrsrc) != 0) {
			free(xi, M_DEVBUF, 0);
			return NULL;
		}

		xi->xi_intrsrc = intrsrc;
		xb->xb_intr[intrbit] = xi;
		snprintf(xb->xb_intrstr[intrbit],
		    sizeof xb->xb_intrstr[intrbit],
		    "irq %d, xbow irq %d", intrbit, intrsrc);
	} else
		intrsrc = xi->xi_intrsrc;
	
	/*
	 * Register the interrupt at the Heart or Hub level if this is the
	 * first time we're using this interrupt source.
	 */
	new = LIST_EMPTY(&xi->xi_handlers);
	if (new) {
		/*
		 * XXX The interrupt dispatcher is always registered
		 * XXX at IPL_BIO, in case the interrupt will be shared
		 * XXX between devices of different levels.
		 */
		if (xbow_intr_establish(xb->xb_pci_intr_handler, xi, intrsrc,
		    IPL_BIO, NULL, NULL)) {
			printf("%s: unable to register interrupt handler\n",
			    DEVNAME(xb));
			return NULL;
		}
	}

	xih = (struct xbridge_intrhandler *)
	    malloc(sizeof(*xih), M_DEVBUF, M_NOWAIT);
	if (xih == NULL)
		return NULL;

	xih->xih_main = xi;
	xih->xih_func = func;
	xih->xih_arg = arg;
	xih->xih_level = level;
	xih->xih_device = device;
	evcount_attach(&xih->xih_count, name, &xi->xi_intrsrc);
	LIST_INSERT_HEAD(&xi->xi_handlers, xih, xih_nxt);

	if (new) {
		/*
		 * Note that, while PIC uses a complete XIO address,
		 * Bridge will only store the interrupt source and high
		 * bits of the address, and will reuse the widget interrupt
		 * address for the low 38 bits of the XIO address.
		 */
		if (ISSET(xb->xb_flags, XF_PIC))
			int_addr = ((uint64_t)intrsrc << 48) |
			    (xbow_intr_address & ((1UL << 48) - 1));
		else
			int_addr = ((xbow_intr_address >> 30) &
			    0x0003ff00) | intrsrc;
		xb->xb_ier |= 1L << intrbit;

		xbridge_write_reg(xb, BRIDGE_INT_ADDR(intrbit), int_addr);
		xbridge_write_reg(xb, BRIDGE_IER, xb->xb_ier);
		/*
		 * INT_MODE register controls which interrupt pins cause
		 * ``interrupt clear'' packets to be sent for high->low
		 * transition.
		 * We enable such packets to be sent in order not to have to
		 * clear interrupts ourselves.
		 */
		xbridge_write_reg(xb, BRIDGE_INT_MODE,
		    xbridge_read_reg(xb, BRIDGE_INT_MODE) | (1 << intrbit));
		xbridge_write_reg(xb, BRIDGE_INT_DEV,
		    xbridge_read_reg(xb, BRIDGE_INT_DEV) |
		    (device << (intrbit * 3)));
		(void)xbridge_read_reg(xb, WIDGET_TFLUSH);
	}

	return (void *)xih;
}

void
xbridge_intr_disestablish(void *cookie, void *vih)
{
	struct xbpci_softc *xb = cookie;
	struct xbridge_intrhandler *xih = (struct xbridge_intrhandler *)vih;
	struct xbridge_intr *xi = xih->xih_main;
	int intrbit = xi->xi_intrbit;

	evcount_detach(&xih->xih_count);
	LIST_REMOVE(xih, xih_nxt);

	if (LIST_EMPTY(&xi->xi_handlers)) {
		xb->xb_ier &= ~(1 << intrbit);
		xbridge_write_reg(xb, BRIDGE_INT_ADDR(intrbit), 0);
		xbridge_write_reg(xb, BRIDGE_IER, xb->xb_ier);
		xbridge_write_reg(xb, BRIDGE_INT_MODE,
		    xbridge_read_reg(xb, BRIDGE_INT_MODE) & ~(1 << intrbit));
		xbridge_write_reg(xb, BRIDGE_INT_DEV,
		    xbridge_read_reg(xb, BRIDGE_INT_DEV) &
		    ~(7 << (intrbit * 3)));
		(void)xbridge_read_reg(xb, WIDGET_TFLUSH);

		xbow_intr_disestablish(xi->xi_intrsrc);
		/*
		 * Note we could free xb->xb_intr[intrbit] at this point,
		 * but it's not really worth doing.
		 */
	}

	free(xih, M_DEVBUF, 0);
}

int
xbridge_intr_line(void *cookie, pci_intr_handle_t ih)
{
	return XBRIDGE_INTR_BIT(ih);
}

int
xbridge_err_intr_handler(void *v)
{
	struct xbpci_softc *xb = (struct xbpci_softc *)v;
	uint64_t isr;

	isr = xbridge_read_reg(xb, BRIDGE_ISR) & ~BRIDGE_ISR_HWINTR_MASK;
	xbridge_err_handle(xb, isr);

	xbow_intr_clear(xb->xb_err_intrsrc);

	return 1;
}

int
xbridge_pci_intr_handler(void *v)
{
	struct xbridge_intr *xi = (struct xbridge_intr *)v;
	struct xbpci_softc *xb = xi->xi_bus;
	struct xbridge_intrhandler *xih;
	int rc;
	uint64_t isr;

	/* XXX shouldn't happen, and assumes interrupt is not shared */
	if (LIST_EMPTY(&xi->xi_handlers)) {
		printf("%s: spurious irq %d\n", DEVNAME(xb), xi->xi_intrbit);
		return 0;
	}

	/*
	 * Flush PCI write buffers before servicing the interrupt.
	 */
	LIST_FOREACH(xih, &xi->xi_handlers, xih_nxt)
		xbridge_wbflush(xb, xih->xih_device);

	isr = xbridge_read_reg(xb, BRIDGE_ISR);
	if ((isr & ~BRIDGE_ISR_HWINTR_MASK) != 0) {
		/*
		 * This is an error interrupt triggered by a particular
		 * device.
		 */
		xbridge_err_handle(xb, isr & ~BRIDGE_ISR_HWINTR_MASK);
		if ((isr &= BRIDGE_ISR_HWINTR_MASK) == 0)
			return 1;
	}

	if ((isr & (1L << xi->xi_intrbit)) == 0) {
		/*
		 * May be a result of the lost interrupt workaround (see
		 * near the end of this function); don't complain in that
		 * case.
		 */
		rc = -1;
#ifdef DEBUG
		printf("%s: irq %d but not pending in ISR %08x\n",
		    DEVNAME(xb), xi->xi_intrbit, isr);
#endif
	} else {
		rc = 0;
		LIST_FOREACH(xih, &xi->xi_handlers, xih_nxt) {
			splraise(xih->xih_level);
			if ((*xih->xih_func)(xih->xih_arg) != 0) {
				xih->xih_count.ec_count++;
				rc = 1;
			}
			/*
			 * No need to lower spl here, as our caller will
			 * lower spl upon our return.
			 * However that splraise() is necessary so that
			 * interrupt handler code calling splx() will not
			 * cause our interrupt source to be unmasked.
			 */
		}
		/* XXX assumes interrupt is not shared */
		if (rc == 0)
			printf("%s: spurious irq %d\n",
			    DEVNAME(xb), xi->xi_intrbit);
	}

	/*
	 * There is a known BRIDGE race in which, if two interrupts
	 * on two different pins occur within 60nS of each other,
	 * further interrupts on the first pin do not cause an
	 * interrupt to be sent.
	 *
	 * The workaround against this is to check if our interrupt
	 * source is still active (i.e. another interrupt is pending),
	 * in which case we force an interrupt anyway.
	 *
	 * The XBridge even has a nice facility to do this, where we
	 * do not even have to check if our interrupt is pending.
	 */

	if (ISSET(xb->xb_flags, XF_XBRIDGE)) {
		xbridge_write_reg(xb, BRIDGE_INT_FORCE_PIN(xi->xi_intrbit), 1);
		(void)xbridge_read_reg(xb, WIDGET_TFLUSH);
	} else {
		if (xbridge_read_reg(xb, BRIDGE_ISR) & (1 << xi->xi_intrbit))
			xbow_intr_set(xi->xi_intrsrc);
	}

	return rc;
}

int
xbridge_picv1_pci_intr_handler(void *v)
{
	struct xbridge_intr *xi = (struct xbridge_intr *)v;
	struct xbpci_softc *xb = xi->xi_bus;

	/*
	 * Revision 1 of PIC is supposed to need the interrupt enable bit
	 * to be toggled to prevent loss of interrupt.
	 */
	xbridge_write_reg(xb, BRIDGE_IER, xb->xb_ier & ~(1L << xi->xi_intrbit));
	(void)xbridge_read_reg(xb, WIDGET_TFLUSH);
	xbridge_write_reg(xb, BRIDGE_IER, xb->xb_ier);
	(void)xbridge_read_reg(xb, WIDGET_TFLUSH);

	return xbridge_pci_intr_handler(v);
}

/*
 ********************* chip register access.
 */

uint64_t
bridge_read_reg(bus_space_tag_t t, bus_space_handle_t h, bus_addr_t a)
{
	return (uint64_t)widget_read_4(t, h, a);
}
void
bridge_write_reg(bus_space_tag_t t, bus_space_handle_t h, bus_addr_t a,
    uint64_t v)
{
	widget_write_4(t, h, a, (uint32_t)v);
}

uint64_t
pic_read_reg(bus_space_tag_t t, bus_space_handle_t h, bus_addr_t a)
{
	return widget_read_8(t, h, a);
}

void
pic_write_reg(bus_space_tag_t t, bus_space_handle_t h, bus_addr_t a,
    uint64_t v)
{
	widget_write_8(t, h, a, v);
}

/*
 ********************* bus_space glue.
 */

uint8_t
xbridge_read_1(bus_space_tag_t t, bus_space_handle_t h, bus_size_t o)
{
	return *(volatile uint8_t *)((h + o) ^ 3);
}

uint16_t
xbridge_read_2(bus_space_tag_t t, bus_space_handle_t h, bus_size_t o)
{
	return *(volatile uint16_t *)((h + o) ^ 2);
}

void
xbridge_write_1(bus_space_tag_t t, bus_space_handle_t h, bus_size_t o,
    uint8_t v)
{
	*(volatile uint8_t *)((h + o) ^ 3) = v;
}

void
xbridge_write_2(bus_space_tag_t t, bus_space_handle_t h, bus_size_t o,
    uint16_t v)
{
	*(volatile uint16_t *)((h + o) ^ 2) = v;
}

void
xbridge_read_raw_2(bus_space_tag_t t, bus_space_handle_t h, bus_addr_t o,
    uint8_t *buf, bus_size_t len)
{
	volatile uint16_t *addr = (volatile uint16_t *)((h + o) ^ 2);
	len >>= 1;
	while (len-- != 0) {
		*(uint16_t *)buf = letoh16(*addr);
		buf += 2;
	}
}

void
xbridge_write_raw_2(bus_space_tag_t t, bus_space_handle_t h, bus_addr_t o,
    const uint8_t *buf, bus_size_t len)
{
	volatile uint16_t *addr = (volatile uint16_t *)((h + o) ^ 2);
	len >>= 1;
	while (len-- != 0) {
		*addr = htole16(*(uint16_t *)buf);
		buf += 2;
	}
}

void
xbridge_read_raw_4(bus_space_tag_t t, bus_space_handle_t h, bus_addr_t o,
    uint8_t *buf, bus_size_t len)
{
	volatile uint32_t *addr = (volatile uint32_t *)(h + o);
	len >>= 2;
	while (len-- != 0) {
		*(uint32_t *)buf = letoh32(*addr);
		buf += 4;
	}
}

void
xbridge_write_raw_4(bus_space_tag_t t, bus_space_handle_t h, bus_addr_t o,
    const uint8_t *buf, bus_size_t len)
{
	volatile uint32_t *addr = (volatile uint32_t *)(h + o);
	len >>= 2;
	while (len-- != 0) {
		*addr = htole32(*(uint32_t *)buf);
		buf += 4;
	}
}

void
xbridge_read_raw_8(bus_space_tag_t t, bus_space_handle_t h, bus_addr_t o,
    uint8_t *buf, bus_size_t len)
{
	volatile uint64_t *addr = (volatile uint64_t *)(h + o);
	len >>= 3;
	while (len-- != 0) {
		*(uint64_t *)buf = letoh64(*addr);
		buf += 8;
	}
}

void
xbridge_write_raw_8(bus_space_tag_t t, bus_space_handle_t h, bus_addr_t o,
    const uint8_t *buf, bus_size_t len)
{
	volatile uint64_t *addr = (volatile uint64_t *)(h + o);
	len >>= 3;
	while (len-- != 0) {
		*addr = htole64(*(uint64_t *)buf);
		buf += 8;
	}
}

int
xbridge_space_map_devio(bus_space_tag_t t, bus_addr_t offs, bus_size_t size,
    int flags, bus_space_handle_t *bshp)
{
	struct xbpci_softc *xb = (struct xbpci_softc *)t->bus_private;
	bus_addr_t bpa;
#ifdef DIAGNOSTIC
	bus_addr_t start, end;
	uint d;
#endif

	if ((offs >> 24) != xb->xb_devio_skew)
		return EINVAL;	/* not a devio mapping */

	/*
	 * Figure out which devio `slot' we are using, and make sure
	 * we do not overrun it.
	 */
	bpa = offs & ((1UL << 24) - 1);
#ifdef DIAGNOSTIC
	for (d = 0; d < xb->xb_nslots; d++) {
		start = PIC_DEVIO_OFFS(xb->xb_busno, d);
		end = start + BRIDGE_DEVIO_SIZE(d);
		if (bpa >= start && bpa < end) {
			if (bpa + size > end)
				return EINVAL;
			else
				break;
		}
	}
	if (d == xb->xb_nslots)
		return EINVAL;
#endif

	/*
	 * Note we can not use our own bus_base because it might not point
	 * to our small window. Instead, use the one used by the xbridge
	 * driver itself, which _always_ points to the short window.
	 */
	*bshp = xb->xb_regt->bus_base + bpa;
	return 0;
}

int
xbridge_space_map_io(bus_space_tag_t t, bus_addr_t offs, bus_size_t size,
    int flags, bus_space_handle_t *bshp)
{
	struct xbpci_softc *xb = (struct xbpci_softc *)t->bus_private;

	/*
	 * Base address is either within the devio area, or our direct
	 * window.
	 */

	if ((offs >> 24) == xb->xb_devio_skew)
		return xbridge_space_map_devio(t, offs, size, flags, bshp);

#ifdef DIAGNOSTIC
	/* check that this does not overflow the mapping */
	if (offs < xb->xb_iostart || offs + size - 1 > xb->xb_ioend)
		return EINVAL;
#endif

	*bshp = (t->bus_base + offs);
	return 0;
}

int
xbridge_space_map_mem(bus_space_tag_t t, bus_addr_t offs, bus_size_t size,
    int flags, bus_space_handle_t *bshp)
{
#if defined(TGT_ORIGIN) || defined(DIAGNOSTIC)
	struct xbpci_softc *xb = (struct xbpci_softc *)t->bus_private;
#endif

	/*
	 * Base address is either within the devio area, or our direct
	 * window.  Except on Octane where we never setup devio memory
	 * mappings, because the large mapping is always available.
	 */

#ifdef TGT_ORIGIN
	if (sys_config.system_type != SGI_OCTANE &&
	    (offs >> 24) == xb->xb_devio_skew)
		return xbridge_space_map_devio(t, offs, size, flags, bshp);
#endif

#ifdef DIAGNOSTIC
	/* check that this does not overflow the mapping */
	if (offs < xb->xb_memstart || offs + size - 1 > xb->xb_memend)
		return EINVAL;
#endif

	*bshp = (t->bus_base + offs);
	return 0;
}

int
xbridge_space_region_devio(bus_space_tag_t t , bus_space_handle_t bsh,
    bus_size_t offset, bus_size_t size, bus_space_handle_t *nbshp)
{
#ifdef DIAGNOSTIC
	struct xbpci_softc *xb = (struct xbpci_softc *)t->bus_private;
	bus_addr_t bpa;
	bus_addr_t start, end;
	uint d;
#endif

#ifdef DIAGNOSTIC
	/*
	 * Note we can not use our own bus_base because it might not point
	 * to our small window. Instead, use the one used by the xbridge
	 * driver itself, which _always_ points to the short window.
	 */
	bpa = (bus_addr_t)bsh - xb->xb_regt->bus_base;

	if ((bpa >> 24) != 0)
		return EINVAL;	/* not a devio mapping */

	/*
	 * Figure out which devio `slot' we are using, and make sure
	 * we do not overrun it.
	 */
	for (d = 0; d < xb->xb_nslots; d++) {
		start = PIC_DEVIO_OFFS(xb->xb_busno, d);
		end = start + BRIDGE_DEVIO_SIZE(d);
		if (bpa >= start && bpa < end) {
			if (bpa + offset + size > end)
				return EINVAL;
			else
				break;
		}
	}
	if (d == xb->xb_nslots)
		return EINVAL;
#endif

	*nbshp = bsh + offset;
	return 0;
}

int
xbridge_space_region_io(bus_space_tag_t t, bus_space_handle_t bsh,
    bus_size_t offset, bus_size_t size, bus_space_handle_t *nbshp)
{
	struct xbpci_softc *xb = (struct xbpci_softc *)t->bus_private;
	bus_addr_t bpa;

	/*
	 * Note we can not use our own bus_base because it might not point
	 * to our small window. Instead, use the one used by the xbridge
	 * driver itself, which _always_ points to the short window.
	 */
	bpa = (bus_addr_t)bsh - xb->xb_regt->bus_base;

	if ((bpa >> 24) == 0)
		return xbridge_space_region_devio(t, bsh, offset, size, nbshp);

#ifdef DIAGNOSTIC
	/* check that this does not overflow the mapping */
	bpa = (bus_addr_t)bsh - t->bus_base;
	if (bpa + offset + size - 1 > xb->xb_ioend)
		return EINVAL;
#endif

	*nbshp = bsh + offset;
	return 0;
}

int
xbridge_space_region_mem(bus_space_tag_t t, bus_space_handle_t bsh,
    bus_size_t offset, bus_size_t size, bus_space_handle_t *nbshp)
{
#if defined(TGT_ORIGIN) || defined(DIAGNOSTIC)
	struct xbpci_softc *xb = (struct xbpci_softc *)t->bus_private;
	bus_addr_t bpa;
#endif

	/*
	 * Base address is either within the devio area, or our direct
	 * window.  Except on Octane where we never setup devio memory
	 * mappings, because the large mapping is always available.
	 */

#ifdef TGT_ORIGIN
	if (sys_config.system_type != SGI_OCTANE) {
		/*
		 * Note we can not use our own bus_base because it might not
		 * point to our small window. Instead, use the one used by
		 * the xbridge driver itself, which _always_ points to the
		 * short window.
		 */
		bpa = (bus_addr_t)bsh - xb->xb_regt->bus_base;

		if ((bpa >> 24) == 0)
			return xbridge_space_region_devio(t, bsh, offset, size,
			    nbshp);
	}
#endif

#ifdef DIAGNOSTIC
	/* check that this does not overflow the mapping */
	bpa = (bus_addr_t)bsh - t->bus_base;
	if (bpa + offset + size - 1 > xb->xb_memend)
		return EINVAL;
#endif

	*nbshp = bsh + offset;
	return 0;
}

void
xbridge_space_barrier(bus_space_tag_t t, bus_space_handle_t h, bus_size_t offs,
    bus_size_t len, int flags)
{
	struct xbpci_softc *xb = (struct xbpci_softc *)t->bus_private;
	bus_addr_t bpa, start, end;
	uint d, devmin, devmax;

	mips_sync();

	if (flags & BUS_SPACE_BARRIER_WRITE) {
		/*
		 * Try to figure out which device we are working for, and
		 * flush its PCI write buffer.
		 * This is ugly; we really need to be able to provide a
		 * different bus_space_tag_t to each slot, to be able
		 * to tell them apart.
		 */
		if (t->_space_map == xbridge_space_map_devio) {
			bpa = (bus_addr_t)h - xb->xb_regt->bus_base;
			for (d = 0; d < xb->xb_nslots; d++) {
				start = PIC_DEVIO_OFFS(xb->xb_busno, d);
				end = start + BRIDGE_DEVIO_SIZE(d);
				if (bpa >= start && bpa < end)
					break;
			}
			devmin = d;
			devmax = d + 1;
			/* should not happen */
			if (d == xb->xb_nslots) {
				devmin = 0;
				devmax = xb->xb_nslots;
			}
		} else {
			/* nothing better came up my sleeve... */
			devmin = 0;
			devmax = xb->xb_nslots;
		}
		for (d = devmin; d < devmax; d++)
			xbridge_wbflush(xb, d);
		(void)xbridge_read_reg(xb, WIDGET_TFLUSH);
	}
}

/*
 ********************* bus_dma helpers
 */

/*
 * Since the common bus_dma code makes sure DMA-able memory is allocated
 * within the dma_constraint limits, which are set to the direct DMA
 * window, we do not need to check for addresses outside this range here.
 */

bus_addr_t
xbridge_pa_to_device(paddr_t pa)
{
	return (pa - dma_constraint.ucr_low) + BRIDGE_DMA_DIRECT_BASE;
}

paddr_t
xbridge_device_to_pa(bus_addr_t addr)
{
	return (addr - BRIDGE_DMA_DIRECT_BASE) + dma_constraint.ucr_low;
}

/*
 ********************* Bridge configuration code.
 */

const char *
xbridge_setup(struct xbpci_softc *xb)
{
	bus_addr_t ba;
	paddr_t pa;
	uint64_t status, ctrl, int_addr, dirmap;
	int mode, speed, dev;

	status = xbridge_read_reg(xb, WIDGET_STATUS);
	ctrl = xbridge_read_reg(xb, WIDGET_CONTROL);

	/*
	 * Print bus mode and speed.
	 */

	mode = ISSET(xb->xb_flags, XF_PIC) &&
	    ISSET(status, PIC_WIDGET_STATUS_PCIX_MODE);
	if (mode != 0) {
		SET(xb->xb_flags, XF_PCIX);
		speed = (status & PIC_WIDGET_STATUS_PCIX_SPEED_MASK) >>
		    PIC_WIDGET_STATUS_PCIX_SPEED_SHIFT;
	} else if (ISSET(xb->xb_flags, XF_XBRIDGE)) {
		speed = (ctrl & BRIDGE_WIDGET_CONTROL_SPEED_MASK) >>
		    BRIDGE_WIDGET_CONTROL_SPEED_SHIFT;
	} else
		speed = 0;
	/* 0 = 33 MHz, 1 = 66 MHz, 2 = 100 MHz, 3 = 133 MHz */
	speed = (speed & 2 ? 100 : 33) + (speed & 1 ? 33 : 0);
	printf("%d MHz %s bus", speed, mode ? "PCIX" : "PCI");

	/*
	 * 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 < xb->xb_nslots; dev++) {
		if (ISSET(xb->xb_flags, XF_PIC))
			pa = xb->xb_regh + BRIDGE_PCI_CFG_SPACE +
			    ((dev + 1) << 12) + PCI_ID_REG;
		else
			pa = xb->xb_regh + BRIDGE_PCI_CFG_SPACE +
			    (dev << 12) + PCI_ID_REG;
		if (guarded_read_4(pa, &xb->xb_devices[dev].id) != 0)
			xb->xb_devices[dev].id = PCI_ID_EMPTY;
	}

	/*
	 * Configure the direct DMA window to access the 2GB memory
	 * window selected as our DMA memory range.
	 */
	dirmap = (dma_constraint.ucr_low >> BRIDGE_DIRMAP_BASE_SHIFT) &
	     BRIDGE_DIRMAP_BASE_MASK;
	switch (sys_config.system_type) {
	default:
#ifdef TGT_ORIGIN
		dirmap |= kl_hub_widget[
		    IP27_PHYS_TO_NODE(dma_constraint.ucr_low)] <<
		      BRIDGE_DIRMAP_WIDGET_SHIFT;
		break;
#endif
#ifdef TGT_OCTANE
	case SGI_OCTANE:
		dirmap |= IP30_HEART_WIDGET << BRIDGE_DIRMAP_WIDGET_SHIFT;
		break;
#endif
	}
	xbridge_write_reg(xb, BRIDGE_DIR_MAP, dirmap);

	/*
	 * Allocate RRB for the existing devices.
	 */

	xbridge_rrb_setup(xb, 0);
	xbridge_rrb_setup(xb, 1);

	/*
	 * Enable(?) snooping and disable relaxed order on PIC.
	 */

	if (ISSET(xb->xb_flags, XF_PIC)) {
		ctrl &= ~PIC_WIDGET_CONTROL_NO_SNOOP;
		ctrl &= ~PIC_WIDGET_CONTROL_RELAX_ORDER;
	}

	/*
	 * 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.
	 */

	ctrl &= ~BRIDGE_WIDGET_CONTROL_IO_SWAP;
	ctrl &= ~BRIDGE_WIDGET_CONTROL_MEM_SWAP;
	xbridge_write_reg(xb, WIDGET_CONTROL, ctrl);
	(void)xbridge_read_reg(xb, WIDGET_TFLUSH);

	/*
	 * The PROM will only configure the onboard devices. Set up
	 * any other device we might encounter.
	 */

	xbridge_resource_setup(xb);

	/*
	 * Older Bridge chips needs to run with pci timeouts
	 * disabled.
	 */

	if (!ISSET(xb->xb_flags, XF_XBRIDGE) && xb->xb_revision < 4) {
		xbridge_write_reg(xb, BRIDGE_BUS_TIMEOUT,
		    xbridge_read_reg(xb, BRIDGE_BUS_TIMEOUT) &
		    ~BRIDGE_BUS_PCI_RETRY_CNT_MASK);
	}

	/*
	 * AT&T/Lucent USS-302 and USS-312 USB controllers require
	 * a larger PCI retry hold interval for proper operation.
	 */

	for (dev = 0; dev < xb->xb_nslots; dev++) {
		if (xb->xb_devices[dev].id ==
		    PCI_ID_CODE(PCI_VENDOR_LUCENT, PCI_PRODUCT_LUCENT_USBHC) ||
		    xb->xb_devices[dev].id ==
		    PCI_ID_CODE(PCI_VENDOR_LUCENT, PCI_PRODUCT_LUCENT_USBHC2)) {
			ctrl = xbridge_read_reg(xb, BRIDGE_BUS_TIMEOUT);
			ctrl &= ~BRIDGE_BUS_PCI_RETRY_HOLD_MASK;
			ctrl |= (4 << BRIDGE_BUS_PCI_RETRY_HOLD_SHIFT);
			xbridge_write_reg(xb, BRIDGE_BUS_TIMEOUT, ctrl);

			break;
		}
	}

	/*
	 * Clear the write request memory in PIC, to avoid risking
	 * spurious parity errors if it is not clean.
	 */
	if (ISSET(xb->xb_flags, XF_PIC)) {
		for (ba = PIC_WR_REQ_LOWER(0);
		    ba != PIC_WR_REQ_LOWER(PIC_WR_REQ_ENTRIES); ba += 8)
			xbridge_write_reg(xb, ba, 0ULL);
		for (ba = PIC_WR_REQ_UPPER(0);
		    ba != PIC_WR_REQ_UPPER(PIC_WR_REQ_ENTRIES); ba += 8)
			xbridge_write_reg(xb, ba, 0ULL);
		for (ba = PIC_WR_REQ_PARITY(0);
		    ba != PIC_WR_REQ_PARITY(PIC_WR_REQ_ENTRIES); ba += 8)
			xbridge_write_reg(xb, ba, 0ULL);
	}

	/*
	 * Setup interrupt handling.
	 *
	 * Note that, on PIC, the `lower address' register is a 64 bit
	 * register and thus need to be initialized with the whole 64 bit
	 * address; the `upper address' register is hardwired to zero and
	 * ignores writes, so we can use the same logic on Bridge and PIC.
	 *
	 * Also, on Octane, we need to keep otherwise unused interrupt source
	 * #6 enabled on the obio widget, as it controls routing of the
	 * power button interrupt (and to make things more complicated than
	 * necessary, this pin is wired to a particular Heart interrupt
	 * register bit, so interrupts on this pin will never be seen at the
	 * Bridge level).
	 */

#ifdef TGT_OCTANE
	if (sys_config.system_type == SGI_OCTANE &&
	    xb->xb_widget == IP30_BRIDGE_WIDGET)
		xb->xb_ier = 1L << 6;
	else
#endif
		xb->xb_ier = 0;
	xbridge_write_reg(xb, BRIDGE_IER, 0);
	xbridge_write_reg(xb, BRIDGE_INT_MODE, 0);
	xbridge_write_reg(xb, BRIDGE_INT_DEV, 0);
	int_addr = xbow_intr_address & ((1UL << 48) - 1);
	switch (sys_config.system_type) {
	default:
#ifdef TGT_ORIGIN
		int_addr |= (uint64_t)kl_hub_widget[masternasid] << 48;
		break;
#endif
#ifdef TGT_OCTANE
	case SGI_OCTANE:
		int_addr |= (uint64_t)IP30_HEART_WIDGET << 48;
		break;
#endif
	}
	xbridge_write_reg(xb, WIDGET_INTDEST_ADDR_LOWER, int_addr);
	xbridge_write_reg(xb, WIDGET_INTDEST_ADDR_UPPER, int_addr >> 32);

	(void)xbridge_read_reg(xb, WIDGET_TFLUSH);

	/*
	 * Register an error interrupt handler.
	 */

	if (xbow_intr_register(xb->xb_widget, IPL_HIGH,
	    &xb->xb_err_intrsrc) != 0)
		return "can't allocate error interrupt source";
	if (xbow_intr_establish(xbridge_err_intr_handler, xb,
	    xb->xb_err_intrsrc, IPL_HIGH, DEVNAME(xb), NULL))
		return "unable to register error interrupt handler";

	xbridge_err_clear(xb, 0);
	xbridge_write_reg(xb, BRIDGE_INT_HOST_ERR, xb->xb_err_intrsrc);

	/*
	 * Enable as many error interrupt sources as possible; older
	 * Bridge chips need to have a few of them kept masked to
	 * avoid hitting hardware issues.
	 */
	xb->xb_ier |= (ISSET(xb->xb_flags, XF_PIC) ?
	    PIC_ISR_ERRMASK : BRIDGE_ISR_ERRMASK) &
	      ~(BRIDGE_ISR_MULTIPLE_ERR | BRIDGE_ISR_SSRAM_PERR |
		BRIDGE_ISR_GIO_BENABLE_ERR);
	if (xb->xb_busno != 0) {
		/* xtalk errors will only show up on bus #0 */
		xb->xb_ier &= ~(BRIDGE_ISR_UNSUPPORTED_XOP |
		    BRIDGE_ISR_LLP_REC_SNERR | BRIDGE_ISR_LLP_REC_CBERR |
		    BRIDGE_ISR_LLP_RCTY | BRIDGE_ISR_LLP_TX_RETRY |
		    BRIDGE_ISR_LLP_TCTY);
	}
	if (!ISSET(xb->xb_flags, XF_XBRIDGE)) {
		if (xb->xb_revision < 2)
			xb->xb_ier &= ~(BRIDGE_ISR_UNEXPECTED_RESP |
			    BRIDGE_ISR_PCI_MASTER_TMO |
			    BRIDGE_ISR_RESP_XTALK_ERR |
			    BRIDGE_ISR_LLP_TX_RETRY | BRIDGE_ISR_XREAD_REQ_TMO);
		if (xb->xb_revision < 3)
			xb->xb_ier &= ~BRIDGE_ISR_BAD_XRESP_PACKET;
	}

	xbridge_write_reg(xb, BRIDGE_IER, xb->xb_ier);

	(void)xbridge_read_reg(xb, WIDGET_TFLUSH);

	return NULL;
}

/*
 * Handle PCI errors.
 */
void
xbridge_err_handle(struct xbpci_softc *xb, uint64_t isr)
{
	uint64_t pci_err, wid_err, resp_err;

	wid_err = xbridge_read_reg(xb, WIDGET_ERR_ADDR_LOWER);
	if (!ISSET(xb->xb_flags, XF_PIC))
		wid_err |= xbridge_read_reg(xb, WIDGET_ERR_ADDR_UPPER) << 32;
	pci_err = xbridge_read_reg(xb, BRIDGE_PCI_ERR_LOWER);
	if (!ISSET(xb->xb_flags, XF_PIC))
		pci_err |= xbridge_read_reg(xb, BRIDGE_PCI_ERR_UPPER) << 32;
	resp_err = xbridge_read_reg(xb, BRIDGE_WIDGET_RESP_LOWER);
	if (!ISSET(xb->xb_flags, XF_PIC))
		resp_err |=
		    xbridge_read_reg(xb, BRIDGE_WIDGET_RESP_UPPER) << 32;

	/* XXX give more detailed information */
	printf("%s: error interrupt, isr %llx wid %llx pci %llx resp %llx\n",
	    DEVNAME(xb), isr, wid_err, pci_err, resp_err);

	xbridge_err_clear(xb, isr);
}

/*
 * Clear any error condition.
 */
void
xbridge_err_clear(struct xbpci_softc *xb, uint64_t isr)
{
	if (ISSET(xb->xb_flags, XF_PIC)) {
		if (isr == 0)
			isr = xbridge_read_reg(xb, BRIDGE_ISR) &
			    ~BRIDGE_ISR_HWINTR_MASK;
		xbridge_write_reg(xb, BRIDGE_ICR, isr);
	} else
		xbridge_write_reg(xb, BRIDGE_ICR, BRIDGE_ICR_ALL);

	(void)xbridge_read_reg(xb, WIDGET_TFLUSH);
}

/*
 * Build a not-so-pessimistic RRB allocation register value.
 */
void
xbridge_rrb_setup(struct xbpci_softc *xb, int odd)
{
	uint rrb[MAX_SLOTS / 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 < nitems(rrb); i++) {
		dev = (i << 1) + !!odd;
		if (dev >= xb->xb_nslots || SLOT_EMPTY(xb, dev))
			rrb[i] = 0;
		else {
			rrb[i] = 4;	/* optimistic value */
			total += 4;
		}
	}

	/*
	 * 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 < nitems(rrb); 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 < nitems(rrb); i++) {
			if (rrb[i] == 3) {
				dev = (i << 1) + !!odd;
				if (PCI_VENDOR(xb->xb_devices[dev].id) !=
				    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 = nitems(rrb) - 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 < nitems(rrb); i++) {
		for (j = 0; j < rrb[i]; j++)
			proto = (proto << RRB_SHIFT) | (RRB_VALID | i);
	}

	xbridge_write_reg(xb, odd ? BRIDGE_RRB_ODD : BRIDGE_RRB_EVEN, proto);
}

/*
 * Configure PCI resources for all devices.
 */
void
xbridge_resource_setup(struct xbpci_softc *xb)
{
	pci_chipset_tag_t pc = &xb->xb_pc;
	int dev, nfuncs;
	pcitag_t tag;
	pcireg_t id, bhlcr;
	uint32_t devio;
	int need_setup;
	uint secondary, nppb, npccbb, ppbstride;
	const struct pci_quirkdata *qd;

	/*
	 * On Octane, we will want to map everything through the large
	 * windows, whenever possible.
	 *
	 * Set up these mappings now.
	 */

	if (sys_config.system_type == SGI_OCTANE) {
		xb->xb_ioex = xbridge_mapping_setup(xb, 1);
		xb->xb_memex = xbridge_mapping_setup(xb, 0);
	}

	/*
	 * Configure all regular PCI devices.
	 */

#ifdef DEBUG
	for (dev = 0; dev < xb->xb_nslots; dev++)
		printf("device %d: devio %08x\n",
		    dev, xbridge_read_reg(xb, BRIDGE_DEVICE(dev)));
#endif
	nppb = npccbb = 0;
	for (dev = 0; dev < xb->xb_nslots; dev++) {
		if (SLOT_EMPTY(xb, dev))
			continue;

		/*
		 * 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
		 * 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.
		 */

		id = xb->xb_devices[dev].id;
		devio = xbridge_read_reg(xb, BRIDGE_DEVICE(dev));
		if (id != PCI_ID_CODE(PCI_VENDOR_SGI, PCI_PRODUCT_SGI_IOC3) &&
		    id != PCI_ID_CODE(PCI_VENDOR_SGI, PCI_PRODUCT_SGI_IOC4))
			need_setup = 1;
		else
			need_setup = xb->xb_busno != 0 || xb->xb_devio_skew !=
			    ((devio & BRIDGE_DEVICE_BASE_MASK) >>
			     (24 - BRIDGE_DEVICE_BASE_SHIFT));

		/*
		 * Enable byte swapping for DMA, except on IOC3, IOC4 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_IOC4) ||
		    id == PCI_ID_CODE(PCI_VENDOR_SGI, PCI_PRODUCT_SGI_RAD1))
			devio &=
			    ~(BRIDGE_DEVICE_SWAP_PMU | BRIDGE_DEVICE_SWAP_DIR);
		else
			devio |=
			    BRIDGE_DEVICE_SWAP_PMU | BRIDGE_DEVICE_SWAP_DIR;

		/*
		 * Disable write gathering.
		 */
		devio &=
		    ~(BRIDGE_DEVICE_WGATHER_PMU | BRIDGE_DEVICE_WGATHER_DIR);

		/*
		 * Disable prefetching - on-board isp(4) controllers on
		 * Octane are set up with this, but this confuses the
		 * driver.
		 */
		devio &= ~BRIDGE_DEVICE_PREFETCH;

		/*
		 * Force cache coherency.
		 */
		devio |= BRIDGE_DEVICE_COHERENT;

		if (need_setup == 0) {
			xbridge_set_devio(xb, dev, devio, 1);
			continue;
		}

		/*
		 * Clear any residual devio mapping.
		 */
		devio &= ~BRIDGE_DEVICE_BASE_MASK;
		devio &= ~BRIDGE_DEVICE_IO_MEM;
		xbridge_set_devio(xb, dev, devio, 0);

		/*
		 * We now need to perform the resource allocation for this
		 * device, which has not been setup by ARCS.
		 */

		qd = pci_lookup_quirkdata(PCI_VENDOR(id), PCI_PRODUCT(id));
		if (PCI_HDRTYPE_MULTIFN(bhlcr) ||
		    (qd != NULL && (qd->quirks & PCI_QUIRK_MULTIFUNCTION) != 0))
			nfuncs = 8;
		else
			nfuncs = 1;

		xbridge_device_setup(xb, dev, nfuncs, devio);
	}

	/*
	 * 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.
	 */

	if (npccbb != 0) {
		/*
		 * If there are PCI-CardBus bridges, we really want to be
		 * able to have large resource spaces...
		 */
		if (xb->xb_ioex == NULL)
			xb->xb_ioex = xbridge_mapping_setup(xb, 1);
		if (xb->xb_memex == NULL)
			xb->xb_memex = xbridge_mapping_setup(xb, 0);
	}

	secondary = 1;
	ppbstride = nppb == 0 ? 0 : (255 - npccbb) / nppb;
	for (dev = 0; dev < xb->xb_nslots; dev++) {
		if (SLOT_EMPTY(xb, dev))
			continue;

		tag = pci_make_tag(pc, 0, dev, 0);
		bhlcr = pci_conf_read(pc, tag, PCI_BHLC_REG);

		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;
		}
	}

	if (xb->xb_ioex != NULL) {
		extent_destroy(xb->xb_ioex);
		xb->xb_ioex = NULL;
	}
	if (xb->xb_memex != NULL) {
		extent_destroy(xb->xb_memex);
		xb->xb_memex = NULL;
	}
}

/*
 * Make the Octane flash area unavailable in the PCI space extents, so
 * that we do not try to map devices in its area.
 */
int
xbridge_extent_chomp(struct xbpci_softc *xb, struct extent *ex)
{
#ifdef TGT_OCTANE
	/*
	 * On Octane, the boot PROM is part of the onboard IOC3
	 * device, and is accessible through the PCI memory space
	 * (and maybe through the PCI I/O space as well).
	 *
	 * To avoid undebuggable surprises, make sure we never use
	 * this space.
	 */
	if (sys_config.system_type == SGI_OCTANE &&
	    xb->xb_widget == IP30_BRIDGE_WIDGET) {
		u_long fmin, fmax;

		/*
		 * This relies upon the knowledge that both flash bases
		 * are contiguous, to perform only one extent operation.
		 * I don't think we need to be pedantic to the point of
		 * doing this in two steps, really -- miod
		 */
		fmin = max(IP30_FLASH_BASE, ex->ex_start);
		fmax = min(IP30_FLASH_ALT + IP30_FLASH_SIZE - 1, ex->ex_end);
		if (fmax >= fmin)
			return extent_alloc_region(ex, fmin, fmax + 1 - fmin,
			    EX_NOWAIT | EX_MALLOCOK);
	}
#endif

	return 0;
}

/*
 * Build resource extents for the MI PCI code to play with.
 * These extents cover the configured devio areas, and the large resource
 * views, if applicable.
 */
void
xbridge_extent_setup(struct xbpci_softc *xb)
{
	int dev;
	int errors;
	bus_addr_t start, end;
	uint32_t devio;

	snprintf(xb->xb_ioexname, sizeof(xb->xb_ioexname), "%s_io",
	    DEVNAME(xb));
	xb->xb_ioex = extent_create(xb->xb_ioexname, 0, 0xffffffff,
	    M_DEVBUF, NULL, 0, EX_NOWAIT | EX_FILLED);

	if (xb->xb_ioex != NULL) {
		errors = 0;
		/* make all configured devio ranges available... */
		for (dev = 0; dev < xb->xb_nslots; dev++) {
			devio = xb->xb_devices[dev].devio;
			if (devio == 0 || ISSET(devio, BRIDGE_DEVICE_IO_MEM))
				continue;
			start = (devio & BRIDGE_DEVICE_BASE_MASK) <<
			    BRIDGE_DEVICE_BASE_SHIFT;
			if (start == 0)
				continue;
			if (extent_free(xb->xb_ioex, start,
			    BRIDGE_DEVIO_SIZE(dev), EX_NOWAIT) != 0) {
				errors++;
				break;
			}
		}
		/* ...as well as the large views, if any */
		if (xb->xb_ioend != 0) {
			start = xb->xb_iostart;
			if (start == 0)
				start = 1;
			end = xb->xb_devio_skew << 24;
			if (start < end)
				if (extent_free(xb->xb_ioex, start,
				    end, EX_NOWAIT) != 0)
					errors++;
			
			start = (xb->xb_devio_skew + 1) << 24;
			if (start < xb->xb_iostart)
				start = xb->xb_iostart;
			if (extent_free(xb->xb_ioex, start,
			    xb->xb_ioend + 1 - start, EX_NOWAIT) != 0)
				errors++;
		}

		if (xbridge_extent_chomp(xb, xb->xb_ioex) != 0)
			errors++;

		if (errors != 0) {
			extent_destroy(xb->xb_ioex);
			xb->xb_ioex = NULL;
		}
	}

	snprintf(xb->xb_memexname, sizeof(xb->xb_memexname), "%s_mem",
	    DEVNAME(xb));
	xb->xb_memex = extent_create(xb->xb_memexname, 0, 0xffffffff,
	    M_DEVBUF, NULL, 0, EX_NOWAIT | EX_FILLED);

	if (xb->xb_memex != NULL) {
		errors = 0;
		/* make all configured devio ranges available... */
		for (dev = 0; dev < xb->xb_nslots; dev++) {
			devio = xb->xb_devices[dev].devio;
			if (devio == 0 || !ISSET(devio, BRIDGE_DEVICE_IO_MEM))
				continue;
			start = (devio & BRIDGE_DEVICE_BASE_MASK) <<
			    BRIDGE_DEVICE_BASE_SHIFT;
			if (start == 0)
				continue;
			if (extent_free(xb->xb_memex, start,
			    BRIDGE_DEVIO_SIZE(dev), EX_NOWAIT) != 0) {
				errors++;
				break;
			}
		}
		/* ...as well as the large views, if any */
		if (xb->xb_memend != 0) {
			start = xb->xb_memstart;
			if (start == 0)
				start = 1;
			end = xb->xb_devio_skew << 24;
			if (start < end)
				if (extent_free(xb->xb_memex, start,
				    end, EX_NOWAIT) != 0)
					errors++;

			start = (xb->xb_devio_skew + 1) << 24;
			if (start < xb->xb_memstart)
				start = xb->xb_memstart;
			if (extent_free(xb->xb_memex, start,
			    xb->xb_memend + 1 - start, EX_NOWAIT) != 0)
				errors++;
		}

		if (xbridge_extent_chomp(xb, xb->xb_memex) != 0)
			errors++;

		if (errors != 0) {
			extent_destroy(xb->xb_memex);
			xb->xb_memex = NULL;
		}
	}
}

struct extent *
xbridge_mapping_setup(struct xbpci_softc *xb, int io)
{
	bus_addr_t membase, offs;
	bus_size_t len;
	paddr_t base;
	u_long start, end;
	struct extent *ex = NULL;

	if (io) {
		/*
		 * 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).
		 *
		 * Also, this direct I/O space is not supported on PIC
		 * widgets.
		 */

		if (!ISSET(xb->xb_flags, XF_NO_DIRECT_IO)) {
			offs = BRIDGE_PCI_IO_SPACE_BASE;
			len = BRIDGE_PCI_IO_SPACE_LENGTH;
			base = xbow_widget_map_space(xb->xb_bow,
			    xb->xb_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;

#ifdef DEBUG
			printf("direct io %p-%p base %p\n",
			    offs, offs + len - 1, base);
#endif
			offs -= BRIDGE_PCI_IO_SPACE_BASE;

			ex = extent_create("xbridge_direct_io",
			    offs == 0 ? 1 : offs, offs + len - 1,
			    M_DEVBUF, NULL, 0, EX_NOWAIT);

			/*
			 * Note that we do not need to invoke
			 * xbridge_extent_chomp() here since we will
			 * reserve the whole devio area.
			 */

			if (ex != NULL) {
				xb->xb_io_bus_space->bus_base = base - offs;
				xb->xb_io_bus_space->_space_map =
				    xbridge_space_map_io;
				xb->xb_io_bus_space->_space_subregion =
				    xbridge_space_region_io;

				xb->xb_io_bus_space_sw->bus_base = base - offs;
				xb->xb_io_bus_space_sw->_space_map =
				    xbridge_space_map_io;
				xb->xb_io_bus_space_sw->_space_subregion =
				    xbridge_space_region_io;

				xb->xb_iostart = offs;
				xb->xb_ioend = offs + len - 1;
			}
		}
	} else {
		/*
		 * Memory mappings are available in the widget at offset
		 * BRIDGE_PCI#_MEM_SPACE_BASE onwards.
		 */

		membase = xb->xb_busno == 0 ? BRIDGE_PCI0_MEM_SPACE_BASE :
		    BRIDGE_PCI1_MEM_SPACE_BASE;
		offs = membase;
		len = BRIDGE_PCI_MEM_SPACE_LENGTH;
		base = xbow_widget_map_space(xb->xb_bow,
		    xb->xb_widget, &offs, &len);

		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 > membase + BRIDGE_PCI_MEM_SPACE_LENGTH)
				len = membase + BRIDGE_PCI_MEM_SPACE_LENGTH -
				    offs;

#ifdef DEBUG
			printf("direct mem %p-%p base %p\n",
			    offs, offs + len - 1, base);
#endif
			offs -= membase;

			ex = extent_create("xbridge_direct_mem",
			    offs == 0 ? 1 : offs, offs + len - 1,
			    M_DEVBUF, NULL, 0, EX_NOWAIT);

			/*
			 * Note that we do not need to invoke
			 * xbridge_extent_chomp() here since we will
			 * reserve the whole devio area.
			 */

			if (ex != NULL) {
				xb->xb_mem_bus_space->bus_base = base - offs;
				xb->xb_mem_bus_space->_space_map =
				    xbridge_space_map_mem;
				xb->xb_mem_bus_space->_space_subregion =
				    xbridge_space_region_mem;

				xb->xb_mem_bus_space_sw->bus_base = base - offs;
				xb->xb_mem_bus_space_sw->_space_map =
				    xbridge_space_map_mem;
				xb->xb_mem_bus_space_sw->_space_subregion =
				    xbridge_space_region_mem;

				xb->xb_memstart = offs;
				xb->xb_memend = offs + len - 1;
			}
		}
	}

	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 = xb->xb_devio_skew << 24;
		end = (xb->xb_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 + 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",
				    DEVNAME(xb), 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 xbpci_softc *xb, pcitag_t tag,
    struct extent *ioex, struct extent *memex)
{
	pci_chipset_tag_t pc = &xb->xb_pc;
	pcireg_t bhlc, type, addr, mask;
	bus_addr_t base;
	bus_size_t size;
	int reg, reg_start, reg_end, reg_rom;
	int rc = 0;

	bhlc = pci_conf_read(pc, tag, PCI_BHLC_REG);
	switch (PCI_HDRTYPE_TYPE(bhlc)) {
	case 0:
		reg_start = PCI_MAPREG_START;
		reg_end = PCI_MAPREG_END;
		reg_rom = PCI_ROM_REG;
		break;
	case 1:	/* PCI-PCI bridge */
		reg_start = PCI_MAPREG_START;
		reg_end = PCI_MAPREG_PPB_END;
		reg_rom = 0;	/* 0x38 */
		break;
	case 2:	/* PCI-CardBus bridge */
		reg_start = PCI_MAPREG_START;
		reg_end = PCI_MAPREG_PCB_END;
		reg_rom = 0;
		break;
	default:
		return rc;
	}

	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, NULL, &size, NULL))
			continue;

		switch (type) {
		case PCI_MAPREG_TYPE_MEM | PCI_MAPREG_MEM_TYPE_64BIT:
			reg += 4;
			/* FALLTHROUGH */
		case PCI_MAPREG_TYPE_MEM | PCI_MAPREG_MEM_TYPE_32BIT:
			rc |= XR_MEM;
			if (memex != NULL) {
				if (size > memex->ex_end - memex->ex_start)
					rc |= XR_MEM_OFLOW | XR_MEM_OFLOW_S;
				else if (extent_alloc(memex, size, size,
				    0, 0, 0, &base) != 0)
					rc |= XR_MEM_OFLOW | XR_MEM_OFLOW_S;
				else if (base >= BRIDGE_DEVIO_SHORT)
					rc |= XR_MEM_OFLOW_S;
			} else
				rc |= XR_MEM_OFLOW | XR_MEM_OFLOW_S;
			break;
		case PCI_MAPREG_TYPE_IO:
			rc |= XR_IO;
			if (ioex != NULL) {
				if (size > ioex->ex_end - ioex->ex_start)
					rc |= XR_IO_OFLOW | XR_IO_OFLOW_S;
				else if (extent_alloc(ioex, size, size,
				    0, 0, 0, &base) != 0)
					rc |= XR_IO_OFLOW | XR_IO_OFLOW_S;
				else if (base >= BRIDGE_DEVIO_SHORT)
					rc |= XR_IO_OFLOW_S;
			} else
				rc |= XR_IO_OFLOW | XR_IO_OFLOW_S;
			break;
		}
	}

	if (reg_rom != 0) {
		addr = pci_conf_read(pc, tag, reg_rom);
		pci_conf_write(pc, tag, reg_rom, ~PCI_ROM_ENABLE);
		mask = pci_conf_read(pc, tag, reg_rom);
		pci_conf_write(pc, tag, reg_rom, addr);
		size = PCI_ROM_SIZE(mask);

		if (size != 0) {
			rc |= XR_MEM;
			if (memex != NULL) {
				if (size > memex->ex_end - memex->ex_start)
					rc |= XR_MEM_OFLOW | XR_MEM_OFLOW_S;
				else if (extent_alloc(memex, size, size,
				    0, 0, 0, &base) != 0)
					rc |= XR_MEM_OFLOW | XR_MEM_OFLOW_S;
				else if (base >= BRIDGE_DEVIO_SHORT)
					rc |= XR_MEM_OFLOW_S;
			} else
				rc |= XR_MEM_OFLOW | XR_MEM_OFLOW_S;
		}
	}

	return rc;
}

void
xbridge_resource_manage(struct xbpci_softc *xb, pcitag_t tag,
    struct extent *ioex, struct extent *memex)
{
	pci_chipset_tag_t pc = &xb->xb_pc;
	pcireg_t bhlc, type, mask;
	bus_addr_t base;
	bus_size_t size;
	int reg, reg_start, reg_end, reg_rom;

	bhlc = pci_conf_read(pc, tag, PCI_BHLC_REG);
	switch (PCI_HDRTYPE_TYPE(bhlc)) {
	case 0:
		reg_start = PCI_MAPREG_START;
		reg_end = PCI_MAPREG_END;
		reg_rom = PCI_ROM_REG;
		break;
	case 1:	/* PCI-PCI bridge */
		reg_start = PCI_MAPREG_START;
		reg_end = PCI_MAPREG_PPB_END;
		reg_rom = 0;	/* 0x38 */
		break;
	case 2:	/* PCI-CardBus bridge */
		reg_start = PCI_MAPREG_START;
		reg_end = PCI_MAPREG_PCB_END;
		reg_rom = 0;
		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;

		/*
		 * Note that we do not care about the existing BAR values,
		 * since these devices either have not been setup by ARCS
		 * or do not matter for early system setup (such as
		 * optional IOC3 PCI boards, which will get setup by
		 * ARCS but can be reinitialized as we see fit).
		 */
#ifdef DEBUG
		printf("tag %04x bar %02x type %d base %p size %p",
		    tag, reg, type, base, size);
#endif
		switch (type) {
		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)
					base = 0;
			} else
				base = 0;
			break;
		case PCI_MAPREG_TYPE_IO:
			if (ioex != NULL) {
				if (extent_alloc(ioex, size, size, 0, 0, 0,
				    &base) != 0)
					base = 0;
			} else
				base = 0;
			break;
		}

#ifdef DEBUG
		printf(" setup at %p\n", base);
#endif
		pci_conf_write(pc, tag, reg, base);

		if (type == (PCI_MAPREG_TYPE_MEM | PCI_MAPREG_MEM_TYPE_64BIT))
			reg += 4;
	}

	if (reg_rom != 0) {
		base = (bus_addr_t)pci_conf_read(pc, tag, reg_rom);
		pci_conf_write(pc, tag, reg_rom, ~PCI_ROM_ENABLE);
		mask = pci_conf_read(pc, tag, reg_rom);
		size = PCI_ROM_SIZE(mask);

		if (size != 0) {
#ifdef DEBUG
			printf("bar %02x type rom base %p size %p",
			    reg_rom, base, size);
#endif
			if (memex != NULL) {
				if (extent_alloc(memex, size, size, 0, 0, 0,
				    &base) != 0)
					base = 0;
			} else
				base = 0;
#ifdef DEBUG
			printf(" setup at %p\n", base);
#endif
		} else
			base = 0;

		/* ROM intentionally left disabled */
		pci_conf_write(pc, tag, reg_rom, base);
	}
}

void
xbridge_device_setup(struct xbpci_softc *xb, int dev, int nfuncs,
    uint32_t devio)
{
	pci_chipset_tag_t pc = &xb->xb_pc;
	int function;
	pcitag_t tag;
	pcireg_t id, csr;
	uint32_t baseio;
	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 (xb->xb_ioex != NULL)
		ioex = NULL;
	else {
		ioex = extent_create("xbridge_io",
		    0, BRIDGE_DEVIO_LARGE - 1,
		    M_DEVBUF, NULL, 0, EX_NOWAIT);
#ifdef DEBUG
		if (ioex == NULL)
			printf("%s: ioex extent_create failed\n", __func__);
#endif
	}
	if (xb->xb_memex != NULL)
		memex = NULL;
	else {
		memex = extent_create("xbridge_mem",
		    0, BRIDGE_DEVIO_LARGE - 1,
		    M_DEVBUF, NULL, 0, EX_NOWAIT);
#ifdef DEBUG
		if (memex == NULL)
			printf("%s: memex extent_create failed\n", __func__);
#endif
	}

	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;

		csr = pci_conf_read(pc, tag, PCI_COMMAND_STATUS_REG);
		pci_conf_write(pc, tag, PCI_COMMAND_STATUS_REG, csr &
		    ~(PCI_COMMAND_IO_ENABLE | PCI_COMMAND_MEM_ENABLE));

		resources |= xbridge_resource_explore(xb, tag, ioex, memex);
	}
#ifdef DEBUG
	printf("resources mask: %02x\n", resources);
#endif

	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 ||
		     xb->xb_ioex == NULL))
			io_devio = xbridge_allocate_devio(xb, dev,
			    ISSET(resources, XR_IO_OFLOW_S));
		if (io_devio >= 0) {
			baseio = (xb->xb_devio_skew << 24) |
			    PIC_DEVIO_OFFS(xb->xb_busno, io_devio);
			xbridge_set_devio(xb, io_devio, devio |
			    (baseio >> BRIDGE_DEVICE_BASE_SHIFT), 1);

			ioex = extent_create("xbridge_io", baseio,
			    baseio + 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 (xb->xb_ioex == NULL)
				xb->xb_ioex = xbridge_mapping_setup(xb, 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(xb, dev,
			    ISSET(resources, XR_MEM_OFLOW_S));
		if (mem_devio >= 0) {
			baseio = (xb->xb_devio_skew << 24) |
			    PIC_DEVIO_OFFS(xb->xb_busno, mem_devio);
			xbridge_set_devio(xb, mem_devio, devio |
			    BRIDGE_DEVICE_IO_MEM |
			    (baseio >> BRIDGE_DEVICE_BASE_SHIFT), 1);

			memex = extent_create("xbridge_mem", baseio,
			    baseio + 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 (xb->xb_memex == NULL)
				xb->xb_memex = xbridge_mapping_setup(xb, 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(xb, tag,
		    ioex != NULL ? ioex : xb->xb_ioex,
		    memex != NULL ?  memex : xb->xb_memex);
	}

	if (memex != NULL)
		extent_destroy(memex);
	if (ioex != NULL)
		extent_destroy(ioex);
}

int
xbridge_ppb_setup(void *cookie, pcitag_t tag, bus_addr_t *iostart,
    bus_addr_t *ioend, bus_addr_t *memstart, bus_addr_t *memend)
{
	struct xbpci_softc *xb = cookie;
	pci_chipset_tag_t pc = &xb->xb_pc;
	uint32_t base, devio;
	bus_size_t exsize;
	u_long exstart;
	int dev, devio_idx, tries;

	pci_decompose_tag(pc, tag, NULL, &dev, NULL);
	devio = xbridge_read_reg(xb, BRIDGE_DEVICE(dev));

	/*
	 * Since our caller computes resource needs starting at zero, we
	 * can ignore the start values when computing the amount of
	 * resources we'll need.
	 */

	/*
	 * Try and allocate I/O resources first, as we may not be able
	 * to use a large I/O mapping, in which case we want to use our
	 * reserved devio for this purpose.
	 */

	exsize = *ioend;
	*iostart = 0xffffffff;
	*ioend = 0;
	if (exsize++ != 0) {
		/* try to allocate through a devio slot whenever possible... */
		if (exsize < BRIDGE_DEVIO_SHORT)
			devio_idx = xbridge_allocate_devio(xb, dev, 0);
		else if (exsize < BRIDGE_DEVIO_LARGE)
			devio_idx = xbridge_allocate_devio(xb, dev, 1);
		else
			devio_idx = -1;

		/* ...if it fails, try the large view.... */
		if (devio_idx < 0 && xb->xb_ioex == NULL)
			xb->xb_ioex = xbridge_mapping_setup(xb, 1);

		/* ...if it is not available, try to get a devio slot anyway. */
		if (devio_idx < 0 && xb->xb_ioex == NULL) {
			if (exsize > BRIDGE_DEVIO_SHORT)
				devio_idx = xbridge_allocate_devio(xb, dev, 1);
			if (devio_idx < 0)
				devio_idx = xbridge_allocate_devio(xb, dev, 0);
		}

		if (devio_idx >= 0) {
			base = (xb->xb_devio_skew << 24) |
			    PIC_DEVIO_OFFS(xb->xb_busno, devio_idx);
			xbridge_set_devio(xb, devio_idx, devio |
			    (base >> BRIDGE_DEVICE_BASE_SHIFT), 1);
			*iostart = base;
			*ioend = base + BRIDGE_DEVIO_SIZE(devio_idx) - 1;
		} else if (xb->xb_ioex != NULL) {
			/*
			 * We know that the direct I/O resource range fits
			 * within the 32 bit address space, so our allocation,
			 * if successful, will work as a 32 bit i/o range.
			 */
			if (exsize < 1UL << 12)
				exsize = 1UL << 12;
			for (tries = 0; tries < 5; tries++) {
				if (extent_alloc(xb->xb_ioex, exsize,
				    1UL << 12, 0, 0, EX_NOWAIT | EX_MALLOCOK,
				    &exstart) == 0) {
					*iostart = exstart;
					*ioend = exstart + exsize - 1;
					break;
				}
				exsize >>= 1;
				if (exsize < 1UL << 12)
					break;
			}
		}
	}

	exsize = *memend;
	*memstart = 0xffffffff;
	*memend = 0;
	if (exsize++ != 0) {
		/* try to allocate through a devio slot whenever possible... */
		if (exsize < BRIDGE_DEVIO_SHORT)
			devio_idx = xbridge_allocate_devio(xb, dev, 0);
		else if (exsize < BRIDGE_DEVIO_LARGE)
			devio_idx = xbridge_allocate_devio(xb, dev, 1);
		else
			devio_idx = -1;

		/* ...if it fails, try the large view.... */
		if (devio_idx < 0 && xb->xb_memex == NULL)
			xb->xb_memex = xbridge_mapping_setup(xb, 0);

		/* ...if it is not available, try to get a devio slot anyway. */
		if (devio_idx < 0 && xb->xb_memex == NULL) {
			if (exsize > BRIDGE_DEVIO_SHORT)
				devio_idx = xbridge_allocate_devio(xb, dev, 1);
			if (devio_idx < 0)
				devio_idx = xbridge_allocate_devio(xb, dev, 0);
		}

		if (devio_idx >= 0) {
			base = (xb->xb_devio_skew << 24) |
			    PIC_DEVIO_OFFS(xb->xb_busno, devio_idx);
			xbridge_set_devio(xb, devio_idx, devio |
			    BRIDGE_DEVICE_IO_MEM |
			    (base >> BRIDGE_DEVICE_BASE_SHIFT), 1);
			*memstart = base;
			*memend = base + BRIDGE_DEVIO_SIZE(devio_idx) - 1;
		} else if (xb->xb_memex != NULL) {
			/*
			 * We know that the direct memory resource range fits
			 * within the 32 bit address space, and is limited to
			 * 30 bits, so our allocation, if successful, will
			 * work as a 32 bit memory range.
			 */
			if (exsize < 1UL << 20)
				exsize = 1UL << 20;
			for (tries = 0; tries < 5; tries++) {
				if (extent_alloc(xb->xb_memex, exsize,
				    1UL << 20, 0, 0, EX_NOWAIT | EX_MALLOCOK,
				    &exstart) == 0) {
					*memstart = exstart;
					*memend = exstart + exsize - 1;
					break;
				}
				exsize >>= 1;
				if (exsize < 1UL << 20)
					break;
			}
		}
	}

	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);
			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, 0, 0, RBUS_SPACE_INVALID);

	return rb;
}

void *
xbridge_rbus_parent_mem(struct pci_attach_args *pa)
{
	struct xbpci_softc *xb = 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 = (xb->xb_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);
			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, 0, 0, RBUS_SPACE_INVALID);

	return rb;
}

#endif	/* NCARDBUS > 0 */

int
xbridge_allocate_devio(struct xbpci_softc *xb, int dev, int wantlarge)
{
#ifdef DEBUG
	int orig_dev = dev;
#endif

	/*
	 * If the preferred slot is available and matches the size requested,
	 * use it.
	 */

	if (!ISSET(xb->xb_devio_usemask, 1 << dev)) {
		if (BRIDGE_DEVIO_SIZE(dev) >=
		    wantlarge ? BRIDGE_DEVIO_LARGE : BRIDGE_DEVIO_SHORT) {
#ifdef DEBUG
			printf("%s(%d,%d): using reserved entry\n",
			    __func__, dev, wantlarge);
#endif
			return dev;
		}
	}

	/*
	 * Otherwise pick the smallest available devio matching our size
	 * request.
	 */

	for (dev = 0; dev < xb->xb_nslots; dev++) {
		if (ISSET(xb->xb_devio_usemask, 1 << dev))
			continue;	/* devio in use */

		if (!SLOT_EMPTY(xb, dev))
			continue;	/* devio to be used soon */

		if (BRIDGE_DEVIO_SIZE(dev) >=
		    wantlarge ? BRIDGE_DEVIO_LARGE : BRIDGE_DEVIO_SHORT) {
#ifdef DEBUG
			printf("%s(%d,%d): using unused entry %d\n",
			    __func__, orig_dev, wantlarge, dev);
#endif
			return dev;
		}
	}

#ifdef DEBUG
	printf("%s(%d,%d): no entry available\n",
	    __func__, orig_dev, wantlarge);
#endif
	return -1;
}

void
xbridge_set_devio(struct xbpci_softc *xb, int dev, uint32_t devio, int final)
{
	xbridge_write_reg(xb, BRIDGE_DEVICE(dev), devio);
	(void)xbridge_read_reg(xb, WIDGET_TFLUSH);
	xb->xb_devices[dev].devio = devio;
	if (final)
		SET(xb->xb_devio_usemask, 1 << dev);
#ifdef DEBUG
	printf("device %d: new %sdevio %08x\n",
	    dev, final ? "final " : "", devio);
#endif
}

#ifdef DDB
void xbridge_ddb(void);
void
xbridge_ddb()
{
	struct xbpci_softc *xb;
	unsigned int n, intrbit;

	for (n = 0; n < xbpci_cd.cd_ndevs; n++) {
		xb = xbpci_cd.cd_devs[n];
		if (xb == NULL)
			continue;

		printf("%s: ISR %p IER %p xb_ier %p\n",
		    xb->xb_dev.dv_xname,
		    (void *)xbridge_read_reg(xb, BRIDGE_ISR),
		    (void *)xbridge_read_reg(xb, BRIDGE_IER),
		    (void *)xb->xb_ier);

		printf("mode %p dev %p\n",
		    (void *)xbridge_read_reg(xb, BRIDGE_INT_MODE),
		    (void *)xbridge_read_reg(xb, BRIDGE_INT_DEV));

		for (intrbit = 0; intrbit < 8; intrbit++)
			printf("IRQ%u to %p\n", intrbit,
			    (void *)xbridge_read_reg(xb,
			      BRIDGE_INT_ADDR(intrbit)));
	}
}
#endif
