shithub: riscv

Download patch

ref: d3ebd02befdd967f92ea50fbac08963428e6e03e
parent: 3873eb06d95afafd4b20122130dae8664b69428f
parent: 4f85115526a87063489dc7cf347343bd520159b1
author: cinap_lenrek <cinap_lenrek@felloff.net>
date: Sun Sep 13 16:34:30 EDT 2020

merge

--- a/sys/src/9/bcm64/archbcm4.c
+++ b/sys/src/9/bcm64/archbcm4.c
@@ -9,6 +9,7 @@
 #include "fns.h"
 #include "../port/error.h"
 #include "io.h"
+#include "../port/pci.h"
 #include "sysreg.h"
 
 typedef struct Mbox Mbox;
--- a/sys/src/9/bcm64/fns.h
+++ b/sys/src/9/bcm64/fns.h
@@ -183,28 +183,9 @@
 
 extern int isaconfig(char*, int, ISAConf*);
 
-/* pci */
-typedef struct Pcidev Pcidev;
-extern int pcicfgr32(Pcidev* pcidev, int rno);
-extern void pcicfgw32(Pcidev* pcidev, int rno, int data);
-extern int pcicfgr16(Pcidev* pcidev, int rno);
-extern void pcicfgw16(Pcidev* pcidev, int rno, int data);
-extern int pcicfgr8(Pcidev* pcidev, int rno);
-extern void pcicfgw8(Pcidev* pcidev, int rno, int data);
-extern Pcidev* pcimatch(Pcidev* prev, int vid, int did);
-extern Pcidev* pcimatchtbdf(int tbdf);
-extern void pcisetioe(Pcidev* p);
-extern void pciclrioe(Pcidev* p);
-extern void pcisetbme(Pcidev* p);
-extern void pciclrbme(Pcidev* p);
-extern void pcisetmwi(Pcidev* p);
-extern void pciclrmwi(Pcidev* p);
-extern int pcicap(Pcidev *p, int cap);
-extern int pcinextcap(Pcidev *pci, int offset);
-extern int pcihtcap(Pcidev *p, int cap);
-extern int pcigetpms(Pcidev* p);
-extern int pcisetpms(Pcidev* p, int state);
-extern void pcienable(Pcidev *p);
-extern void pcidisable(Pcidev *p);
+/* pcibcm */
+extern int pcicfgrw8(int tbdf, int rno, int data, int read);
+extern int pcicfgrw16(int tbdf, int rno, int data, int read);
+extern int pcicfgrw32(int tbdf, int rno, int data, int read);
 extern void pciintrenable(int tbdf, void (*f)(Ureg*, void*), void *a);
 extern void pciintrdisable(int tbdf, void (*f)(Ureg*, void*), void *a);
--- a/sys/src/9/bcm64/gic.c
+++ b/sys/src/9/bcm64/gic.c
@@ -4,6 +4,7 @@
 #include "dat.h"
 #include "fns.h"
 #include "io.h"
+#include "../port/pci.h"
 #include "ureg.h"
 #include "sysreg.h"
 #include "../port/error.h"
--- a/sys/src/9/bcm64/io.h
+++ b/sys/src/9/bcm64/io.h
@@ -6,233 +6,5 @@
 	IRQether	= IRQgic + 29,
 };
 
-/*
- * PCI
- */
-enum {
-	BusCBUS		= 0,		/* Corollary CBUS */
-	BusCBUSII,			/* Corollary CBUS II */
-	BusEISA,			/* Extended ISA */
-	BusFUTURE,			/* IEEE Futurebus */
-	BusINTERN,			/* Internal bus */
-	BusISA,				/* Industry Standard Architecture */
-	BusMBI,				/* Multibus I */
-	BusMBII,			/* Multibus II */
-	BusMCA,				/* Micro Channel Architecture */
-	BusMPI,				/* MPI */
-	BusMPSA,			/* MPSA */
-	BusNUBUS,			/* Apple Macintosh NuBus */
-	BusPCI,				/* Peripheral Component Interconnect */
-	BusPCMCIA,			/* PC Memory Card International Association */
-	BusTC,				/* DEC TurboChannel */
-	BusVL,				/* VESA Local bus */
-	BusVME,				/* VMEbus */
-	BusXPRESS,			/* Express System Bus */
-};
-
-#define MKBUS(t,b,d,f)	(((t)<<24)|(((b)&0xFF)<<16)|(((d)&0x1F)<<11)|(((f)&0x07)<<8))
-#define BUSFNO(tbdf)	(((tbdf)>>8)&0x07)
-#define BUSDNO(tbdf)	(((tbdf)>>11)&0x1F)
-#define BUSBNO(tbdf)	(((tbdf)>>16)&0xFF)
-#define BUSTYPE(tbdf)	((tbdf)>>24)
-#define BUSBDF(tbdf)	((tbdf)&0x00FFFF00)
-
-enum {					/* type 0 & type 1 pre-defined header */
-	PciVID		= 0x00,		/* vendor ID */
-	PciDID		= 0x02,		/* device ID */
-	PciPCR		= 0x04,		/* command */
-	PciPSR		= 0x06,		/* status */
-	PciRID		= 0x08,		/* revision ID */
-	PciCCRp		= 0x09,		/* programming interface class code */
-	PciCCRu		= 0x0A,		/* sub-class code */
-	PciCCRb		= 0x0B,		/* base class code */
-	PciCLS		= 0x0C,		/* cache line size */
-	PciLTR		= 0x0D,		/* latency timer */
-	PciHDT		= 0x0E,		/* header type */
-	PciBST		= 0x0F,		/* BIST */
-
-	PciBAR0		= 0x10,		/* base address */
-	PciBAR1		= 0x14,
-
-	PciCAP		= 0x34,		/* capabilities pointer */
-	PciINTL		= 0x3C,		/* interrupt line */
-	PciINTP		= 0x3D,		/* interrupt pin */
-};
-
-/* ccrb (base class code) values; controller types */
-enum {
-	Pcibcpci1	= 0,		/* pci 1.0; no class codes defined */
-	Pcibcstore	= 1,		/* mass storage */
-	Pcibcnet	= 2,		/* network */
-	Pcibcdisp	= 3,		/* display */
-	Pcibcmmedia	= 4,		/* multimedia */
-	Pcibcmem	= 5,		/* memory */
-	Pcibcbridge	= 6,		/* bridge */
-	Pcibccomm	= 7,		/* simple comms (e.g., serial) */
-	Pcibcbasesys	= 8,		/* base system */
-	Pcibcinput	= 9,		/* input */
-	Pcibcdock	= 0xa,		/* docking stations */
-	Pcibcproc	= 0xb,		/* processors */
-	Pcibcserial	= 0xc,		/* serial bus (e.g., USB) */
-	Pcibcwireless	= 0xd,		/* wireless */
-	Pcibcintell	= 0xe,		/* intelligent i/o */
-	Pcibcsatcom	= 0xf,		/* satellite comms */
-	Pcibccrypto	= 0x10,		/* encryption/decryption */
-	Pcibcdacq	= 0x11,		/* data acquisition & signal proc. */
-};
-
-/* ccru (sub-class code) values; common cases only */
-enum {
-	/* mass storage */
-	Pciscscsi	= 0,		/* SCSI */
-	Pciscide	= 1,		/* IDE (ATA) */
-	Pciscsata	= 6,		/* SATA */
-
-	/* network */
-	Pciscether	= 0,		/* Ethernet */
-
-	/* display */
-	Pciscvga	= 0,		/* VGA */
-	Pciscxga	= 1,		/* XGA */
-	Pcisc3d		= 2,		/* 3D */
-
-	/* bridges */
-	Pcischostpci	= 0,		/* host/pci */
-	Pciscpcicpci	= 1,		/* pci/pci */
-
-	/* simple comms */
-	Pciscserial	= 0,		/* 16450, etc. */
-	Pciscmultiser	= 1,		/* multiport serial */
-
-	/* serial bus */
-	Pciscusb	= 3,		/* USB */
-};
-
-enum {					/* type 0 pre-defined header */
-	PciCIS		= 0x28,		/* cardbus CIS pointer */
-	PciSVID		= 0x2C,		/* subsystem vendor ID */
-	PciSID		= 0x2E,		/* subsystem ID */
-	PciEBAR0	= 0x30,		/* expansion ROM base address */
-	PciMGNT		= 0x3E,		/* burst period length */
-	PciMLT		= 0x3F,		/* maximum latency between bursts */
-};
-
-enum {					/* type 1 pre-defined header */
-	PciPBN		= 0x18,		/* primary bus number */
-	PciSBN		= 0x19,		/* secondary bus number */
-	PciUBN		= 0x1A,		/* subordinate bus number */
-	PciSLTR		= 0x1B,		/* secondary latency timer */
-	PciIBR		= 0x1C,		/* I/O base */
-	PciILR		= 0x1D,		/* I/O limit */
-	PciSPSR		= 0x1E,		/* secondary status */
-	PciMBR		= 0x20,		/* memory base */
-	PciMLR		= 0x22,		/* memory limit */
-	PciPMBR		= 0x24,		/* prefetchable memory base */
-	PciPMLR		= 0x26,		/* prefetchable memory limit */
-	PciPUBR		= 0x28,		/* prefetchable base upper 32 bits */
-	PciPULR		= 0x2C,		/* prefetchable limit upper 32 bits */
-	PciIUBR		= 0x30,		/* I/O base upper 16 bits */
-	PciIULR		= 0x32,		/* I/O limit upper 16 bits */
-	PciEBAR1	= 0x28,		/* expansion ROM base address */
-	PciBCR		= 0x3E,		/* bridge control register */
-};
-
-enum {					/* type 2 pre-defined header */
-	PciCBExCA	= 0x10,
-	PciCBSPSR	= 0x16,
-	PciCBPBN	= 0x18,		/* primary bus number */
-	PciCBSBN	= 0x19,		/* secondary bus number */
-	PciCBUBN	= 0x1A,		/* subordinate bus number */
-	PciCBSLTR	= 0x1B,		/* secondary latency timer */
-	PciCBMBR0	= 0x1C,
-	PciCBMLR0	= 0x20,
-	PciCBMBR1	= 0x24,
-	PciCBMLR1	= 0x28,
-	PciCBIBR0	= 0x2C,		/* I/O base */
-	PciCBILR0	= 0x30,		/* I/O limit */
-	PciCBIBR1	= 0x34,		/* I/O base */
-	PciCBILR1	= 0x38,		/* I/O limit */
-	PciCBSVID	= 0x40,		/* subsystem vendor ID */
-	PciCBSID	= 0x42,		/* subsystem ID */
-	PciCBLMBAR	= 0x44,		/* legacy mode base address */
-};
-
-enum {
-	/* bar bits */
-	Barioaddr	= 1<<0,		/* vs. memory addr */
-	Barwidthshift	= 1,
-	Barwidthmask	= 3,
-	Barwidth32	= 0,
-	Barwidth64	= 2,
-	Barprefetch	= 1<<3,
-};
-
-enum
-{					/* command register */
-	IOen		= (1<<0),
-	MEMen		= (1<<1),
-	MASen		= (1<<2),
-	MemWrInv	= (1<<4),
-	PErrEn		= (1<<6),
-	SErrEn		= (1<<8),
-};
-
-/* capabilities */
-enum {
-	PciCapPMG       = 0x01,         /* power management */
-	PciCapAGP       = 0x02,
-	PciCapVPD       = 0x03,         /* vital product data */
-	PciCapSID       = 0x04,         /* slot id */
-	PciCapMSI       = 0x05,
-	PciCapCHS       = 0x06,         /* compact pci hot swap */
-	PciCapPCIX      = 0x07,
-	PciCapHTC       = 0x08,         /* hypertransport irq conf */
-	PciCapVND       = 0x09,         /* vendor specific information */
-	PciCapPCIe      = 0x10,
-	PciCapMSIX      = 0x11,
-	PciCapSATA      = 0x12,
-	PciCapHSW       = 0x0c,         /* hot swap */
-};
-
-typedef struct Pcidev Pcidev;
-struct Pcidev
-{
-	int	tbdf;			/* type+bus+device+function */
-	ushort	vid;			/* vendor ID */
-	ushort	did;			/* device ID */
-
-	ushort	pcr;
-
-	uchar	rid;
-	uchar	ccrp;
-	uchar	ccru;
-	uchar	ccrb;
-	uchar	cls;
-	uchar	ltr;
-
-	struct {
-		uvlong	bar;		/* base address */
-		int	size;
-	} mem[6];
-
-	uchar	intl;			/* interrupt line */
-
-	Pcidev*	list;
-	Pcidev*	link;			/* next device on this bno */
-
-	Pcidev*	parent;			/* up a bus */
-	Pcidev*	bridge;			/* down a bus */
-
-	int	pmrb;			/* power management register block */
-
-	struct {
-		uvlong	bar;
-		int	size;
-	} ioa, mema;
-};
-
 #define PCIWINDOW	0
 #define PCIWADDR(va)	(PADDR(va)+PCIWINDOW)
-
-#pragma varargck	type	"T"	int
-#pragma varargck	type	"T"	uint
--- a/sys/src/9/bcm64/mkfile
+++ b/sys/src/9/bcm64/mkfile
@@ -103,6 +103,7 @@
 l.$O cache.v8.$O mmu.$O rebootcode.$O: mem.h
 l.$O cache.v8.$O archbcm3.$O clock.$O fpu.$O trap.$O mmu.$O rebootcode.$O: sysreg.h
 main.$O: rebootcode.i
+pcibcm.$O: ../port/pci.h
 
 devmouse.$O mouse.$O screen.$O: screen.h
 usbdwc.$O: dwcotg.h ../port/usb.h
--- a/sys/src/9/bcm64/pci.c
+++ /dev/null
@@ -1,1141 +1,0 @@
-#include "u.h"
-#include "../port/lib.h"
-#include "mem.h"
-#include "dat.h"
-#include "fns.h"
-#include "io.h"
-
-/* bcmstb PCIe controller registers */
-enum{
-	RC_CFG_VENDOR_VENDOR_SPECIFIC_REG1	= 0x0188/4,
-	RC_CFG_PRIV1_ID_VAL3			= 0x043c/4,
-	RC_DL_MDIO_ADDR				= 0x1100/4,
-	RC_DL_MDIO_WR_DATA			= 0x1104/4,
-	RC_DL_MDIO_RD_DATA			= 0x1108/4,
-	MISC_MISC_CTRL				= 0x4008/4,
-	MISC_CPU_2_PCIE_MEM_WIN0_LO		= 0x400c/4,
-	MISC_CPU_2_PCIE_MEM_WIN0_HI		= 0x4010/4,
-	MISC_RC_BAR1_CONFIG_LO			= 0x402c/4,
-	MISC_RC_BAR2_CONFIG_LO			= 0x4034/4,
-	MISC_RC_BAR2_CONFIG_HI			= 0x4038/4,
-	MISC_RC_BAR3_CONFIG_LO			= 0x403c/4,
-	MISC_MSI_BAR_CONFIG_LO			= 0x4044/4,
-	MISC_MSI_BAR_CONFIG_HI			= 0x4048/4,
-	MISC_MSI_DATA_CONFIG			= 0x404c/4,
-	MISC_EOI_CTRL				= 0x4060/4,
-	MISC_PCIE_CTRL				= 0x4064/4,
-	MISC_PCIE_STATUS			= 0x4068/4,
-	MISC_REVISION				= 0x406c/4,
-	MISC_CPU_2_PCIE_MEM_WIN0_BASE_LIMIT	= 0x4070/4,
-	MISC_CPU_2_PCIE_MEM_WIN0_BASE_HI	= 0x4080/4,
-	MISC_CPU_2_PCIE_MEM_WIN0_LIMIT_HI	= 0x4084/4,
-	MISC_HARD_PCIE_HARD_DEBUG		= 0x4204/4,
-
-	INTR2_CPU_BASE				= 0x4300/4,
-	MSI_INTR2_BASE				= 0x4500/4,
-		INTR_STATUS = 0,
-		INTR_SET,
-		INTR_CLR,
-		INTR_MASK_STATUS,
-		INTR_MASK_SET,
-		INTR_MASK_CLR,
-
-	EXT_CFG_INDEX				= 0x9000/4,
-	RGR1_SW_INIT_1				= 0x9210/4,
-	EXT_CFG_DATA				= 0x8000/4,
-
-};
-
-#define MSI_TARGET_ADDR		0xFFFFFFFFCULL
-
-static u32int *regs = (u32int*)(VIRTIO1 + 0x500000);
-
-static Lock pcicfglock;
-static int pcimaxbno = 0;
-static int pcimaxdno = 0;
-static Pcidev* pciroot;
-static Pcidev* pcilist;
-static Pcidev* pcitail;
-
-typedef struct Pcisiz Pcisiz;
-struct Pcisiz
-{
-	Pcidev*	dev;
-	int	bar;
-	int	siz;
-	int	typ;
-};
-
-enum
-{
-	MaxFNO		= 7,
-	MaxUBN		= 255,
-};
-
-static char* bustypes[] = {
-	"CBUSI",
-	"CBUSII",
-	"EISA",
-	"FUTURE",
-	"INTERN",
-	"ISA",
-	"MBI",
-	"MBII",
-	"MCA",
-	"MPI",
-	"MPSA",
-	"NUBUS",
-	"PCI",
-	"PCMCIA",
-	"TC",
-	"VL",
-	"VME",
-	"XPRESS",
-};
-
-static int
-tbdffmt(Fmt* fmt)
-{
-	char *p;
-	int l, r;
-	uint type, tbdf;
-
-	if((p = malloc(READSTR)) == nil)
-		return fmtstrcpy(fmt, "(tbdfconv)");
-
-	switch(fmt->r){
-	case 'T':
-		tbdf = va_arg(fmt->args, int);
-		if(tbdf == BUSUNKNOWN)
-			snprint(p, READSTR, "unknown");
-		else{
-			type = BUSTYPE(tbdf);
-			if(type < nelem(bustypes))
-				l = snprint(p, READSTR, bustypes[type]);
-			else
-				l = snprint(p, READSTR, "%d", type);
-			snprint(p+l, READSTR-l, ".%d.%d.%d",
-				BUSBNO(tbdf), BUSDNO(tbdf), BUSFNO(tbdf));
-		}
-		break;
-
-	default:
-		snprint(p, READSTR, "(tbdfconv)");
-		break;
-	}
-	r = fmtstrcpy(fmt, p);
-	free(p);
-
-	return r;
-}
-
-static void pcicfginit(void);
-
-static void*
-cfgaddr(int tbdf, int rno)
-{
-	if(BUSBNO(tbdf) == 0 && BUSDNO(tbdf) == 0)
-		return (uchar*)regs + rno;
-	regs[EXT_CFG_INDEX] = BUSBNO(tbdf) << 20 | BUSDNO(tbdf) << 15 | BUSFNO(tbdf) << 12;
-	coherence();
-	return ((uchar*)&regs[EXT_CFG_DATA]) + rno;
-}
-
-static int
-pcicfgrw32(int tbdf, int rno, int data, int read)
-{
-	int x = -1;
-	u32int *p;
-
-	ilock(&pcicfglock);
-	if((p = cfgaddr(tbdf, rno & ~3)) != nil){
-		if(read)
-			x = *p;
-		else
-			*p = data;
-	}
-	iunlock(&pcicfglock);
-	return x;
-}
-static int
-pcicfgrw16(int tbdf, int rno, int data, int read)
-{
-	int x = -1;
-	u16int *p;
-
-	ilock(&pcicfglock);
-	if((p = cfgaddr(tbdf, rno & ~1)) != nil){
-		if(read)
-			x = *p;
-		else
-			*p = data;
-	}
-	iunlock(&pcicfglock);
-	return x;
-}
-static int
-pcicfgrw8(int tbdf, int rno, int data, int read)
-{
-	int x = -1;
-	u8int *p;
-
-	ilock(&pcicfglock);
-	if((p = cfgaddr(tbdf, rno)) != nil){
-		if(read)
-			x = *p;
-		else
-			*p = data;
-	}
-	iunlock(&pcicfglock);
-	return x;
-}
-
-int
-pcicfgr32(Pcidev* pcidev, int rno)
-{
-	return pcicfgrw32(pcidev->tbdf, rno, 0, 1);
-}
-void
-pcicfgw32(Pcidev* pcidev, int rno, int data)
-{
-	pcicfgrw32(pcidev->tbdf, rno, data, 0);
-}
-int
-pcicfgr16(Pcidev* pcidev, int rno)
-{
-	return pcicfgrw16(pcidev->tbdf, rno, 0, 1);
-}
-void
-pcicfgw16(Pcidev* pcidev, int rno, int data)
-{
-	pcicfgrw16(pcidev->tbdf, rno, data, 0);
-}
-int
-pcicfgr8(Pcidev* pcidev, int rno)
-{
-	return pcicfgrw8(pcidev->tbdf, rno, 0, 1);
-}
-void
-pcicfgw8(Pcidev* pcidev, int rno, int data)
-{
-	pcicfgrw8(pcidev->tbdf, rno, data, 0);
-}
-
-Pcidev*
-pcimatch(Pcidev* prev, int vid, int did)
-{
-	if(prev == nil)
-		prev = pcilist;
-	else
-		prev = prev->list;
-
-	while(prev != nil){
-		if((vid == 0 || prev->vid == vid)
-		&& (did == 0 || prev->did == did))
-			break;
-		prev = prev->list;
-	}
-	return prev;
-}
-
-Pcidev*
-pcimatchtbdf(int tbdf)
-{
-	Pcidev *pcidev;
-
-	for(pcidev = pcilist; pcidev != nil; pcidev = pcidev->list) {
-		if(pcidev->tbdf == tbdf)
-			break;
-	}
-	return pcidev;
-}
-
-static u32int
-pcibarsize(Pcidev *p, int rno)
-{
-	u32int v, size;
-
-	v = pcicfgrw32(p->tbdf, rno, 0, 1);
-	pcicfgrw32(p->tbdf, rno, 0xFFFFFFF0, 0);
-	size = pcicfgrw32(p->tbdf, rno, 0, 1);
-	if(v & 1)
-		size |= 0xFFFF0000;
-	pcicfgrw32(p->tbdf, rno, v, 0);
-
-	return -(size & ~0x0F);
-}
-
-static int
-pcisizcmp(void *a, void *b)
-{
-	Pcisiz *aa, *bb;
-
-	aa = a;
-	bb = b;
-	return aa->siz - bb->siz;
-}
-
-static ulong
-pcimask(ulong v)
-{
-	ulong m;
-
-	m = BI2BY*sizeof(v);
-	for(m = 1<<(m-1); m != 0; m >>= 1) {
-		if(m & v)
-			break;
-	}
-
-	m--;
-	if((v & m) == 0)
-		return v;
-
-	v |= m;
-	return v+1;
-}
-
-static void
-pcibusmap(Pcidev *root, uvlong *pmema, ulong *pioa, int wrreg)
-{
-	Pcidev *p;
-	int ntb, i, size, rno, hole;
-	uvlong v, mema, smema, base, limit;
-	ulong ioa, sioa;
-	Pcisiz *table, *tptr, *mtb, *itb;
-
-	ioa = *pioa;
-	mema = *pmema;
-
-	ntb = 0;
-	for(p = root; p != nil; p = p->link)
-		ntb++;
-
-	ntb *= (PciCIS-PciBAR0)/4;
-	table = malloc(2*ntb*sizeof(Pcisiz));
-	if(table == nil)
-		panic("pcibusmap: can't allocate memory");
-	itb = table;
-	mtb = table+ntb;
-
-	/*
-	 * Build a table of sizes
-	 */
-	for(p = root; p != nil; p = p->link) {
-		if(p->ccrb == 0x06) {
-			if(p->ccru != 0x04 || p->bridge == nil)
-				continue;
-
-			sioa = ioa;
-			smema = mema;
-			pcibusmap(p->bridge, &smema, &sioa, 0);
-
-			hole = pcimask(smema-mema);
-			if(hole < (1<<20))
-				hole = 1<<20;
-			p->mema.size = hole;
-
-			hole = pcimask(sioa-ioa);
-			if(hole < (1<<12))
-				hole = 1<<12;
-
-			p->ioa.size = hole;
-
-			itb->dev = p;
-			itb->bar = -1;
-			itb->siz = p->ioa.size;
-			itb->typ = 0;
-			itb++;
-
-			mtb->dev = p;
-			mtb->bar = -1;
-			mtb->siz = p->mema.size;
-			mtb->typ = 0;
-			mtb++;
-			continue;
-		}
-
-		for(i = 0; i < nelem(p->mem); i++) {
-			rno = PciBAR0 + i*4;
-			v = pcicfgrw32(p->tbdf, rno, 0, 1);
-			size = pcibarsize(p, rno);
-			if(size == 0)
-				continue;
-
-			p->mem[i].size = size;
-			if(v & 1) {
-				itb->dev = p;
-				itb->bar = i;
-				itb->siz = size;
-				itb->typ = 1;
-				itb++;
-			}
-			else {
-				mtb->dev = p;
-				mtb->bar = i;
-				mtb->siz = size;
-				mtb->typ = v & 7;
-				if(mtb->typ & 4)
-					i++;
-				mtb++;
-			}
-		}
-	}
-
-	/*
-	 * Sort both tables IO smallest first, Memory largest
-	 */
-	qsort(table, itb-table, sizeof(Pcisiz), pcisizcmp);
-	tptr = table+ntb;
-	qsort(tptr, mtb-tptr, sizeof(Pcisiz), pcisizcmp);
-
-	/*
-	 * Allocate IO address space on this bus
-	 */
-	for(tptr = table; tptr < itb; tptr++) {
-		hole = tptr->siz;
-		if(tptr->bar == -1)
-			hole = 1<<12;
-		ioa = (ioa+hole-1) & ~(hole-1);
-
-		p = tptr->dev;
-		if(tptr->bar == -1)
-			p->ioa.bar = ioa;
-		else {
-			p->pcr |= IOen;
-			p->mem[tptr->bar].bar = ioa|1;
-			if(wrreg)
-				pcicfgrw32(p->tbdf, PciBAR0+(tptr->bar*4), ioa|1, 0);
-		}
-
-		ioa += tptr->siz;
-	}
-
-	/*
-	 * Allocate Memory address space on this bus
-	 */
-	for(tptr = table+ntb; tptr < mtb; tptr++) {
-		hole = tptr->siz;
-		if(tptr->bar == -1)
-			hole = 1<<20;
-		mema = (mema+hole-1) & ~((uvlong)hole-1);
-
-		p = tptr->dev;
-		if(tptr->bar == -1)
-			p->mema.bar = mema;
-		else {
-			p->pcr |= MEMen;
-			p->mem[tptr->bar].bar = mema|tptr->typ;
-			if(wrreg){
-				rno = PciBAR0+(tptr->bar*4);
-				pcicfgrw32(p->tbdf, rno, mema|tptr->typ, 0);
-				if(tptr->bar < nelem(p->mem)-1 && (tptr->typ & 4) != 0){
-					p->mem[tptr->bar+1].bar = 0;
-					p->mem[tptr->bar+1].size = 0;
-					pcicfgrw32(p->tbdf, rno+4, mema>>32, 0);
-				}
-			}
-		}
-		mema += tptr->siz;
-	}
-
-	*pmema = mema;
-	*pioa = ioa;
-	free(table);
-
-	if(wrreg == 0)
-		return;
-
-	/*
-	 * Finally set all the bridge addresses & registers
-	 */
-	for(p = root; p != nil; p = p->link) {
-		if(p->bridge == nil) {
-			if(p->cls == 0){
-				p->cls = 64;
-				pcicfgw8(p, PciCLS, p->cls);
-			}
-			pcicfgrw8(p->tbdf, PciLTR, 64, 0);
-			p->pcr |= MASen;
-			pcicfgrw16(p->tbdf, PciPCR, p->pcr, 0);
-			continue;
-		}
-
-		if(p == pciroot){
-			base = p->mema.bar;
-			limit = base+p->mema.size-1;
-			regs[MISC_CPU_2_PCIE_MEM_WIN0_LO] = base;
-			regs[MISC_CPU_2_PCIE_MEM_WIN0_HI] = base >> 32;
-			base >>= 20, limit >>= 20;
-			regs[MISC_CPU_2_PCIE_MEM_WIN0_BASE_LIMIT] = (base & 0xFFF) << 4 | (limit & 0xFFF) << 20;
-			regs[MISC_CPU_2_PCIE_MEM_WIN0_BASE_HI] = base >> 12;
-			regs[MISC_CPU_2_PCIE_MEM_WIN0_LIMIT_HI] = limit >> 12;
-		}
-
-		base = p->ioa.bar;
-		limit = base+p->ioa.size-1;
-		v = pcicfgrw32(p->tbdf, PciIBR, 0, 1);
-		v = (v&0xFFFF0000)|(limit & 0xF000)|((base & 0xF000)>>8);
-		pcicfgrw32(p->tbdf, PciIBR, v, 0);
-		v = (limit & 0xFFFF0000)|(base>>16);
-		pcicfgrw32(p->tbdf, PciIUBR, v, 0);
-
-		base = p->mema.bar;
-		limit = base+p->mema.size-1;
-		v = (limit & 0xFFF00000)|((base & 0xFFF00000)>>16);
-		pcicfgrw32(p->tbdf, PciMBR, v, 0);
-
-		/*
-		 * Disable memory prefetch
-		 */
-		pcicfgrw32(p->tbdf, PciPMBR, 0x0000FFFF, 0);
-		pcicfgrw8(p->tbdf, PciLTR, 64, 0);
-
-		/*
-		 * Enable the bridge
-		 */
-		p->pcr |= IOen|MEMen|MASen;
-		pcicfgrw32(p->tbdf, PciPCR, 0xFFFF0000|p->pcr, 0);
-
-		sioa = p->ioa.bar;
-		smema = p->mema.bar;
-		pcibusmap(p->bridge, &smema, &sioa, 1);
-	}
-}
-
-static int
-pcilscan(int bno, Pcidev** list, Pcidev *parent)
-{
-	Pcidev *p, *head, *tail;
-	int dno, fno, i, hdt, l, maxfno, maxubn, rno, sbn, tbdf, ubn;
-
-	maxubn = bno;
-	head = nil;
-	tail = nil;
-	for(dno = 0; dno <= pcimaxdno; dno++){
-		maxfno = 0;
-		for(fno = 0; fno <= maxfno; fno++){
-			/*
-			 * For this possible device, form the
-			 * bus+device+function triplet needed to address it
-			 * and try to read the vendor and device ID.
-			 * If successful, allocate a device struct and
-			 * start to fill it in with some useful information
-			 * from the device's configuration space.
-			 */
-			tbdf = MKBUS(BusPCI, bno, dno, fno);
-			l = pcicfgrw32(tbdf, PciVID, 0, 1);
-			if(l == 0xFFFFFFFF || l == 0)
-				continue;
-			p = malloc(sizeof(*p));
-			if(p == nil)
-				panic("pcilscan: no memory");
-			p->tbdf = tbdf;
-			p->vid = l;
-			p->did = l>>16;
-
-			if(pcilist != nil)
-				pcitail->list = p;
-			else
-				pcilist = p;
-			pcitail = p;
-
-			p->pcr = pcicfgr16(p, PciPCR);
-			p->rid = pcicfgr8(p, PciRID);
-			p->ccrp = pcicfgr8(p, PciCCRp);
-			p->ccru = pcicfgr8(p, PciCCRu);
-			p->ccrb = pcicfgr8(p, PciCCRb);
-			p->cls = pcicfgr8(p, PciCLS);
-			p->ltr = pcicfgr8(p, PciLTR);
-
-			p->intl = pcicfgr8(p, PciINTL);
-
-			/*
-			 * If the device is a multi-function device adjust the
-			 * loop count so all possible functions are checked.
-			 */
-			hdt = pcicfgr8(p, PciHDT);
-			if(hdt & 0x80)
-				maxfno = MaxFNO;
-
-			/*
-			 * If appropriate, read the base address registers
-			 * and work out the sizes.
-			 */
-			switch(p->ccrb) {
-			case 0x00:		/* prehistoric */
-			case 0x01:		/* mass storage controller */
-			case 0x02:		/* network controller */
-			case 0x03:		/* display controller */
-			case 0x04:		/* multimedia device */
-			case 0x07:		/* simple comm. controllers */
-			case 0x08:		/* base system peripherals */
-			case 0x09:		/* input devices */
-			case 0x0A:		/* docking stations */
-			case 0x0B:		/* processors */
-			case 0x0C:		/* serial bus controllers */
-			case 0x0D:		/* wireless controllers */
-			case 0x0E:		/* intelligent I/O controllers */
-			case 0x0F:		/* sattelite communication controllers */
-			case 0x10:		/* encryption/decryption controllers */
-			case 0x11:		/* signal processing controllers */
-				if((hdt & 0x7F) != 0)
-					break;
-				rno = PciBAR0;
-				for(i = 0; i < nelem(p->mem); i++) {
-					p->mem[i].bar = (ulong)pcicfgr32(p, rno);
-					p->mem[i].size = pcibarsize(p, rno);
-					if((p->mem[i].bar & 7) == 4 && i < nelem(p->mem)-1){
-						rno += 4;
-						p->mem[i++].bar |= (uvlong)pcicfgr32(p, rno) << 32;
-						p->mem[i].bar = 0;
-						p->mem[i].size = 0;
-					}
-					rno += 4;
-				}
-				break;
-
-			case 0x05:		/* memory controller */
-			case 0x06:		/* bridge device */
-			default:
-				break;
-			}
-
-			p->parent = parent;
-			if(head != nil)
-				tail->link = p;
-			else
-				head = p;
-			tail = p;
-		}
-	}
-
-	*list = head;
-	for(p = head; p != nil; p = p->link){
-		/*
-		 * Find PCI-PCI bridges and recursively descend the tree.
-		 */
-		if(p->ccrb != 0x06 || p->ccru != 0x04)
-			continue;
-
-		/*
-		 * If the secondary or subordinate bus number is not
-		 * initialised try to do what the PCI BIOS should have
-		 * done and fill in the numbers as the tree is descended.
-		 * On the way down the subordinate bus number is set to
-		 * the maximum as it's not known how many buses are behind
-		 * this one; the final value is set on the way back up.
-		 */
-		sbn = pcicfgr8(p, PciSBN);
-		ubn = pcicfgr8(p, PciUBN);
-
-		if(sbn == 0 || ubn == 0) {
-			sbn = maxubn+1;
-			/*
-			 * Make sure memory, I/O and master enables are
-			 * off, set the primary, secondary and subordinate
-			 * bus numbers and clear the secondary status before
-			 * attempting to scan the secondary bus.
-			 *
-			 * Initialisation of the bridge should be done here.
-			 */
-			pcicfgw32(p, PciPCR, 0xFFFF0000);
-			l = (MaxUBN<<16)|(sbn<<8)|bno;
-			pcicfgw32(p, PciPBN, l);
-			pcicfgw16(p, PciSPSR, 0xFFFF);
-			maxubn = pcilscan(sbn, &p->bridge, p);
-			l = (maxubn<<16)|(sbn<<8)|bno;
-
-			pcicfgw32(p, PciPBN, l);
-		}
-		else {
-			if(ubn > maxubn)
-				maxubn = ubn;
-			pcilscan(sbn, &p->bridge, p);
-		}
-	}
-
-	return maxubn;
-}
-
-static void
-pcicfginit(void)
-{
-	uvlong mema;
-	ulong ioa;
-
-	fmtinstall('T', tbdffmt);
-
-	pcilscan(0, &pciroot, nil);
-
-	/*
-	 * Work out how big the top bus is
-	 */
-	ioa = 0;
-	mema = 0;
-	pcibusmap(pciroot, &mema, &ioa, 0);
-
-	/*
-	 * Align the windows and map it
-	 */
-	ioa = 0;
-	mema = soc.pciwin;
-	pcibusmap(pciroot, &mema, &ioa, 1);
-}
-
-static void
-pcilhinv(Pcidev* p)
-{
-	int i;
-	Pcidev *t;
-
-	if(p == nil) {
-		p = pciroot;
-		print("bus dev type vid  did intl memory\n");
-	}
-	for(t = p; t != nil; t = t->link) {
-		print("%d  %2d/%d %.2ux %.2ux %.2ux %.4ux %.4ux %3d  ",
-			BUSBNO(t->tbdf), BUSDNO(t->tbdf), BUSFNO(t->tbdf),
-			t->ccrb, t->ccru, t->ccrp, t->vid, t->did, t->intl);
-
-		for(i = 0; i < nelem(p->mem); i++) {
-			if(t->mem[i].size == 0)
-				continue;
-			print("%d:%llux %d ", i,
-				(uvlong)t->mem[i].bar, t->mem[i].size);
-		}
-		if(t->bridge)
-			print("->%d", BUSBNO(t->bridge->tbdf));
-		print("\n");
-	}
-	while(p != nil) {
-		if(p->bridge != nil)
-			pcilhinv(p->bridge);
-		p = p->link;
-	}
-}
-
-static void
-pcihinv(Pcidev* p)
-{
-	pcilhinv(p);
-}
-
-void
-pcisetioe(Pcidev* p)
-{
-	p->pcr |= IOen;
-	pcicfgw16(p, PciPCR, p->pcr);
-}
-
-void
-pciclrioe(Pcidev* p)
-{
-	p->pcr &= ~IOen;
-	pcicfgw16(p, PciPCR, p->pcr);
-}
-
-void
-pcisetbme(Pcidev* p)
-{
-	p->pcr |= MASen;
-	pcicfgw16(p, PciPCR, p->pcr);
-}
-
-void
-pciclrbme(Pcidev* p)
-{
-	p->pcr &= ~MASen;
-	pcicfgw16(p, PciPCR, p->pcr);
-}
-
-void
-pcisetmwi(Pcidev* p)
-{
-	p->pcr |= MemWrInv;
-	pcicfgw16(p, PciPCR, p->pcr);
-}
-
-void
-pciclrmwi(Pcidev* p)
-{
-	p->pcr &= ~MemWrInv;
-	pcicfgw16(p, PciPCR, p->pcr);
-}
-
-static int
-enumcaps(Pcidev *p, int (*fmatch)(Pcidev*, int, int, int), int arg)
-{
-	int i, r, cap, off;
-
-	/* status register bit 4 has capabilities */
-	if((pcicfgr16(p, PciPSR) & 1<<4) == 0)
-		return -1;      
-	switch(pcicfgr8(p, PciHDT) & 0x7F){
-	default:
-		return -1;
-	case 0:                         /* etc */
-	case 1:                         /* pci to pci bridge */
-		off = 0x34;
-		break;
-	case 2:                         /* cardbus bridge */
-		off = 0x14;
-		break;
-	}
-	for(i = 48; i--;){
-		off = pcicfgr8(p, off);
-		if(off < 0x40 || (off & 3))
-			break;
-		off &= ~3;
-		cap = pcicfgr8(p, off);
-		if(cap == 0xff)
-			break;
-		r = (*fmatch)(p, cap, off, arg);
-		if(r < 0)
-			break;
-		if(r == 0)
-			return off;
-		off++;
-	}
-	return -1;
-}
-
-static int
-matchcap(Pcidev *, int cap, int, int arg)
-{
-	return cap != arg;
-}
-
-static int
-matchhtcap(Pcidev *p, int cap, int off, int arg)
-{
-	int mask;
-
-	if(cap != PciCapHTC)
-		return 1;
-	if(arg == 0x00 || arg == 0x20)
-		mask = 0xE0;
-	else
-		mask = 0xF8;
-	cap = pcicfgr8(p, off+3);
-	return (cap & mask) != arg;
-}
-
-int
-pcicap(Pcidev *p, int cap)
-{
-	return enumcaps(p, matchcap, cap);
-}
-
-int
-pcinextcap(Pcidev *pci, int offset)
-{
-	if(offset == 0) {
-		if((pcicfgr16(pci, PciPSR) & (1<<4)) == 0)
-			return 0; /* no capabilities */
-		offset = PciCAP-1;
-	}
-	return pcicfgr8(pci, offset+1) & ~3;
-}
-
-int
-pcihtcap(Pcidev *p, int cap)
-{
-	return enumcaps(p, matchhtcap, cap);
-}
-
-static int
-pcigetpmrb(Pcidev* p)
-{
-        if(p->pmrb != 0)
-                return p->pmrb;
-        return p->pmrb = pcicap(p, PciCapPMG);
-}
-
-int
-pcigetpms(Pcidev* p)
-{
-	int pmcsr, ptr;
-
-	if((ptr = pcigetpmrb(p)) == -1)
-		return -1;
-
-	/*
-	 * Power Management Register Block:
-	 *  offset 0:	Capability ID
-	 *	   1:	next item pointer
-	 *	   2:	capabilities
-	 *	   4:	control/status
-	 *	   6:	bridge support extensions
-	 *	   7:	data
-	 */
-	pmcsr = pcicfgr16(p, ptr+4);
-
-	return pmcsr & 0x0003;
-}
-
-int
-pcisetpms(Pcidev* p, int state)
-{
-	int ostate, pmc, pmcsr, ptr;
-
-	if((ptr = pcigetpmrb(p)) == -1)
-		return -1;
-
-	pmc = pcicfgr16(p, ptr+2);
-	pmcsr = pcicfgr16(p, ptr+4);
-	ostate = pmcsr & 0x0003;
-	pmcsr &= ~0x0003;
-
-	switch(state){
-	default:
-		return -1;
-	case 0:
-		break;
-	case 1:
-		if(!(pmc & 0x0200))
-			return -1;
-		break;
-	case 2:
-		if(!(pmc & 0x0400))
-			return -1;
-		break;
-	case 3:
-		break;
-	}
-	pmcsr |= state;
-	pcicfgw16(p, ptr+4, pmcsr);
-
-	return ostate;
-}
-
-void
-pcienable(Pcidev *p)
-{
-	uint pcr;
-	int i;
-
-	if(p == nil)
-		return;
-
-	pcienable(p->parent);
-
-	switch(pcisetpms(p, 0)){
-	case 1:
-		print("pcienable %T: wakeup from D1\n", p->tbdf);
-		break;
-	case 2:
-		print("pcienable %T: wakeup from D2\n", p->tbdf);
-		if(p->bridge != nil)
-			delay(100);	/* B2: minimum delay 50ms */
-		else
-			delay(1);	/* D2: minimum delay 200µs */
-		break;
-	case 3:
-		print("pcienable %T: wakeup from D3\n", p->tbdf);
-		delay(100);		/* D3: minimum delay 50ms */
-
-		/* restore registers */
-		for(i = 0; i < nelem(p->mem); i++){
-			pcicfgw32(p, PciBAR0+i*4, p->mem[i].bar);
-			if((p->mem[i].bar&7) == 4 && i < nelem(p->mem)-1){
-				pcicfgw32(p, PciBAR0+i*4+4, p->mem[i].bar>>32);
-				i++;
-			}
-		}
-		pcicfgw8(p, PciINTL, p->intl);
-		pcicfgw8(p, PciLTR, p->ltr);
-		pcicfgw8(p, PciCLS, p->cls);
-		pcicfgw16(p, PciPCR, p->pcr);
-		break;
-	}
-
-	if(p->bridge != nil)
-		pcr = IOen|MEMen|MASen;
-	else {
-		pcr = 0;
-		for(i = 0; i < nelem(p->mem); i++){
-			if(p->mem[i].size == 0)
-				continue;
-			if(p->mem[i].bar & 1)
-				pcr |= IOen;
-			else
-				pcr |= MEMen;
-		}
-	}
-
-	if((p->pcr & pcr) != pcr){
-		print("pcienable %T: pcr %ux->%ux\n", p->tbdf, p->pcr, p->pcr|pcr);
-		p->pcr |= pcr;
-		pcicfgrw32(p->tbdf, PciPCR, 0xFFFF0000|p->pcr, 0);
-	}
-}
-
-void
-pcidisable(Pcidev *p)
-{
-	if(p == nil)
-		return;
-	pciclrbme(p);
-}
-
-enum {
-	MSICtrl = 0x02, /* message control register (16 bit) */
-	MSIAddr = 0x04, /* message address register (64 bit) */
-	MSIData32 = 0x08, /* message data register for 32 bit MSI (16 bit) */
-	MSIData64 = 0x0C, /* message data register for 64 bit MSI (16 bit) */
-};
-
-typedef struct Pciisr Pciisr;
-struct Pciisr {
-	void	(*f)(Ureg*, void*);
-	void	*a;
-	Pcidev	*p;
-};
-
-static Pciisr pciisr[32];
-static Lock pciisrlk;
-
-void
-pciintrenable(int tbdf, void (*f)(Ureg*, void*), void *a)
-{
-	int cap, ok64;
-	u32int dat;
-	u64int adr;
-	Pcidev *p;
-	Pciisr *isr;
-
-	if((p = pcimatchtbdf(tbdf)) == nil){
-		print("pciintrenable: %T: unknown device\n", tbdf);
-		return;
-	}
-	if((cap = pcicap(p, PciCapMSI)) < 0){
-		print("pciintrenable: %T: no MSI cap\n", tbdf);
-		return;
-	}
-
-	lock(&pciisrlk);
-	for(isr = pciisr; isr < &pciisr[nelem(pciisr)]; isr++){
-		if(isr->p == p){
-			isr->p = nil;
-			regs[MSI_INTR2_BASE + INTR_MASK_SET] = 1 << (isr-pciisr);
-			break;
-		}
-	}
-	for(isr = pciisr; isr < &pciisr[nelem(pciisr)]; isr++){
-		if(isr->p == nil){
-			isr->p = p;
-			isr->a = a;
-			isr->f = f;
-			regs[MSI_INTR2_BASE + INTR_CLR] = 1 << (isr-pciisr);
-			regs[MSI_INTR2_BASE + INTR_MASK_CLR] = 1 << (isr-pciisr);
-			break;
-		}
-	}
-	unlock(&pciisrlk);
-
-	if(isr >= &pciisr[nelem(pciisr)]){
-		print("pciintrenable: %T: out of isr slots\n", tbdf);
-		return;
-	}
-
-	adr = MSI_TARGET_ADDR;
-	ok64 = (pcicfgr16(p, cap + MSICtrl) & (1<<7)) != 0;
-	pcicfgw32(p, cap + MSIAddr, adr);
-	if(ok64) pcicfgw32(p, cap + MSIAddr + 4, adr>>32);
-	dat = regs[MISC_MSI_DATA_CONFIG];
-	dat = ((dat >> 16) & (dat & 0xFFFF)) | (isr-pciisr);
-	pcicfgw16(p, cap + (ok64 ? MSIData64 : MSIData32), dat);
-	pcicfgw16(p, cap + MSICtrl, 1);
-}
-
-void
-pciintrdisable(int tbdf, void (*f)(Ureg*, void*), void *a)
-{
-	Pciisr *isr;
-
-	lock(&pciisrlk);
-	for(isr = pciisr; isr < &pciisr[nelem(pciisr)]; isr++){
-		if(isr->p != nil && isr->p->tbdf == tbdf && isr->f == f && isr->a == a){
-			regs[MSI_INTR2_BASE + INTR_MASK_SET] = 1 << (isr-pciisr);
-			isr->p = nil;
-			isr->f = nil;
-			isr->a = nil;
-			break;
-		}
-	}
-	unlock(&pciisrlk);
-}
-
-static void
-pciinterrupt(Ureg *ureg, void*)
-{
-	Pciisr *isr;
-	u32int sts;
-
-	sts = regs[MSI_INTR2_BASE + INTR_STATUS];
-	if(sts == 0)
-		return;
-	regs[MSI_INTR2_BASE + INTR_CLR] = sts;
-	for(isr = pciisr; sts != 0 && isr < &pciisr[nelem(pciisr)]; isr++, sts>>=1){
-		if((sts & 1) != 0 && isr->f != nil)
-			(*isr->f)(ureg, isr->a);
-	}
-	regs[MISC_EOI_CTRL] = 1;
-}
-
-void
-pcilink(void)
-{
-	int log2dmasize = 30;	// 1GB
-
-	regs[RGR1_SW_INIT_1] |= 3;
-	delay(200);
-	regs[RGR1_SW_INIT_1] &= ~2;
-	regs[MISC_PCIE_CTRL] &= ~5;
-	delay(200);
-
-	regs[MISC_HARD_PCIE_HARD_DEBUG] &= ~0x08000000;
-	delay(200);
-
-	regs[MSI_INTR2_BASE + INTR_CLR] = -1;
-	regs[MSI_INTR2_BASE + INTR_MASK_SET] = -1;
-
-	regs[MISC_CPU_2_PCIE_MEM_WIN0_LO] = 0;
-	regs[MISC_CPU_2_PCIE_MEM_WIN0_HI] = 0;
-	regs[MISC_CPU_2_PCIE_MEM_WIN0_BASE_LIMIT] = 0;
-	regs[MISC_CPU_2_PCIE_MEM_WIN0_BASE_HI] = 0;
-	regs[MISC_CPU_2_PCIE_MEM_WIN0_LIMIT_HI] = 0;
-
-	// SCB_ACCESS_EN, CFG_READ_UR_MODE, MAX_BURST_SIZE_128, SCB0SIZE
-	regs[MISC_MISC_CTRL] = 1<<12 | 1<<13 | 0<<20 | (log2dmasize-15)<<27;
-
-	regs[MISC_RC_BAR2_CONFIG_LO] = (log2dmasize-15);
-	regs[MISC_RC_BAR2_CONFIG_HI] = 0;
-
-	regs[MISC_RC_BAR1_CONFIG_LO] = 0;
-	regs[MISC_RC_BAR3_CONFIG_LO] = 0;
-
-	regs[MISC_MSI_BAR_CONFIG_LO] = MSI_TARGET_ADDR | 1;
-	regs[MISC_MSI_BAR_CONFIG_HI] = MSI_TARGET_ADDR>>32;
-	regs[MISC_MSI_DATA_CONFIG] = 0xFFF86540;
-	intrenable(IRQpci, pciinterrupt, nil, BUSUNKNOWN, "pci");
-
-	// force to GEN2
-	regs[(0xAC + 12)/4] = (regs[(0xAC + 12)/4] & ~15) | 2;	// linkcap
-	regs[(0xAC + 48)/4] = (regs[(0xAC + 48)/4] & ~15) | 2;	// linkctl2
-
-	regs[RGR1_SW_INIT_1] &= ~1;
-	delay(500);
-
-	if((regs[MISC_PCIE_STATUS] & 0x30) != 0x30){
-		print("pcireset: phy link is down\n");
-		return;
-	}
-
-	regs[RC_CFG_PRIV1_ID_VAL3] = 0x060400;
-	regs[RC_CFG_VENDOR_VENDOR_SPECIFIC_REG1] &= ~0xC;
-	regs[MISC_HARD_PCIE_HARD_DEBUG] |= 2;
-
-	pcicfginit();
-	pcihinv(nil);
-}
--- /dev/null
+++ b/sys/src/9/bcm64/pcibcm.c
@@ -1,0 +1,310 @@
+#include "u.h"
+#include "../port/lib.h"
+#include "mem.h"
+#include "dat.h"
+#include "fns.h"
+#include "io.h"
+#include "../port/pci.h"
+
+/* bcmstb PCIe controller registers */
+enum{
+	RC_CFG_VENDOR_VENDOR_SPECIFIC_REG1	= 0x0188/4,
+	RC_CFG_PRIV1_ID_VAL3			= 0x043c/4,
+	RC_DL_MDIO_ADDR				= 0x1100/4,
+	RC_DL_MDIO_WR_DATA			= 0x1104/4,
+	RC_DL_MDIO_RD_DATA			= 0x1108/4,
+	MISC_MISC_CTRL				= 0x4008/4,
+	MISC_CPU_2_PCIE_MEM_WIN0_LO		= 0x400c/4,
+	MISC_CPU_2_PCIE_MEM_WIN0_HI		= 0x4010/4,
+	MISC_RC_BAR1_CONFIG_LO			= 0x402c/4,
+	MISC_RC_BAR2_CONFIG_LO			= 0x4034/4,
+	MISC_RC_BAR2_CONFIG_HI			= 0x4038/4,
+	MISC_RC_BAR3_CONFIG_LO			= 0x403c/4,
+	MISC_MSI_BAR_CONFIG_LO			= 0x4044/4,
+	MISC_MSI_BAR_CONFIG_HI			= 0x4048/4,
+	MISC_MSI_DATA_CONFIG			= 0x404c/4,
+	MISC_EOI_CTRL				= 0x4060/4,
+	MISC_PCIE_CTRL				= 0x4064/4,
+	MISC_PCIE_STATUS			= 0x4068/4,
+	MISC_REVISION				= 0x406c/4,
+	MISC_CPU_2_PCIE_MEM_WIN0_BASE_LIMIT	= 0x4070/4,
+	MISC_CPU_2_PCIE_MEM_WIN0_BASE_HI	= 0x4080/4,
+	MISC_CPU_2_PCIE_MEM_WIN0_LIMIT_HI	= 0x4084/4,
+	MISC_HARD_PCIE_HARD_DEBUG		= 0x4204/4,
+
+	INTR2_CPU_BASE				= 0x4300/4,
+	MSI_INTR2_BASE				= 0x4500/4,
+		INTR_STATUS = 0,
+		INTR_SET,
+		INTR_CLR,
+		INTR_MASK_STATUS,
+		INTR_MASK_SET,
+		INTR_MASK_CLR,
+
+	EXT_CFG_INDEX				= 0x9000/4,
+	RGR1_SW_INIT_1				= 0x9210/4,
+	EXT_CFG_DATA				= 0x8000/4,
+
+};
+
+#define MSI_TARGET_ADDR		0xFFFFFFFFCULL
+
+static u32int *regs = (u32int*)(VIRTIO1 + 0x500000);
+static Pcidev* pciroot;
+
+static void*
+cfgaddr(int tbdf, int rno)
+{
+	if(BUSBNO(tbdf) == 0 && BUSDNO(tbdf) == 0)
+		return (uchar*)regs + rno;
+	regs[EXT_CFG_INDEX] = BUSBNO(tbdf) << 20 | BUSDNO(tbdf) << 15 | BUSFNO(tbdf) << 12;
+	coherence();
+	return ((uchar*)&regs[EXT_CFG_DATA]) + rno;
+}
+
+int
+pcicfgrw32(int tbdf, int rno, int data, int read)
+{
+	u32int *p;
+
+	if((p = cfgaddr(tbdf, rno & ~3)) != nil){
+		if(read)
+			data = *p;
+		else
+			*p = data;
+	} else {
+		data = -1;
+	}
+	return data;
+}
+
+int
+pcicfgrw16(int tbdf, int rno, int data, int read)
+{
+	u16int *p;
+
+	if((p = cfgaddr(tbdf, rno & ~1)) != nil){
+		if(read)
+			data = *p;
+		else
+			*p = data;
+	} else {
+		data = -1;
+	}
+	return data;
+}
+
+int
+pcicfgrw8(int tbdf, int rno, int data, int read)
+{
+	u8int *p;
+
+	if((p = cfgaddr(tbdf, rno)) != nil){
+		if(read)
+			data = *p;
+		else
+			*p = data;
+	} else {
+		data = -1;
+	}
+	return data;
+}
+
+enum {
+	MSICtrl = 0x02, /* message control register (16 bit) */
+	MSIAddr = 0x04, /* message address register (64 bit) */
+	MSIData32 = 0x08, /* message data register for 32 bit MSI (16 bit) */
+	MSIData64 = 0x0C, /* message data register for 64 bit MSI (16 bit) */
+};
+
+typedef struct Pciisr Pciisr;
+struct Pciisr {
+	void	(*f)(Ureg*, void*);
+	void	*a;
+	Pcidev	*p;
+};
+
+static Pciisr pciisr[32];
+static Lock pciisrlk;
+
+void
+pciintrenable(int tbdf, void (*f)(Ureg*, void*), void *a)
+{
+	int cap, ok64;
+	u32int dat;
+	u64int adr;
+	Pcidev *p;
+	Pciisr *isr;
+
+	if((p = pcimatchtbdf(tbdf)) == nil){
+		print("pciintrenable: %T: unknown device\n", tbdf);
+		return;
+	}
+	if((cap = pcicap(p, PciCapMSI)) < 0){
+		print("pciintrenable: %T: no MSI cap\n", tbdf);
+		return;
+	}
+
+	lock(&pciisrlk);
+	for(isr = pciisr; isr < &pciisr[nelem(pciisr)]; isr++){
+		if(isr->p == p){
+			isr->p = nil;
+			regs[MSI_INTR2_BASE + INTR_MASK_SET] = 1 << (isr-pciisr);
+			break;
+		}
+	}
+	for(isr = pciisr; isr < &pciisr[nelem(pciisr)]; isr++){
+		if(isr->p == nil){
+			isr->p = p;
+			isr->a = a;
+			isr->f = f;
+			regs[MSI_INTR2_BASE + INTR_CLR] = 1 << (isr-pciisr);
+			regs[MSI_INTR2_BASE + INTR_MASK_CLR] = 1 << (isr-pciisr);
+			break;
+		}
+	}
+	unlock(&pciisrlk);
+
+	if(isr >= &pciisr[nelem(pciisr)]){
+		print("pciintrenable: %T: out of isr slots\n", tbdf);
+		return;
+	}
+
+	adr = MSI_TARGET_ADDR;
+	ok64 = (pcicfgr16(p, cap + MSICtrl) & (1<<7)) != 0;
+	pcicfgw32(p, cap + MSIAddr, adr);
+	if(ok64) pcicfgw32(p, cap + MSIAddr + 4, adr>>32);
+	dat = regs[MISC_MSI_DATA_CONFIG];
+	dat = ((dat >> 16) & (dat & 0xFFFF)) | (isr-pciisr);
+	pcicfgw16(p, cap + (ok64 ? MSIData64 : MSIData32), dat);
+	pcicfgw16(p, cap + MSICtrl, 1);
+}
+
+void
+pciintrdisable(int tbdf, void (*f)(Ureg*, void*), void *a)
+{
+	Pciisr *isr;
+
+	lock(&pciisrlk);
+	for(isr = pciisr; isr < &pciisr[nelem(pciisr)]; isr++){
+		if(isr->p != nil && isr->p->tbdf == tbdf && isr->f == f && isr->a == a){
+			regs[MSI_INTR2_BASE + INTR_MASK_SET] = 1 << (isr-pciisr);
+			isr->p = nil;
+			isr->f = nil;
+			isr->a = nil;
+			break;
+		}
+	}
+	unlock(&pciisrlk);
+}
+
+static void
+pciinterrupt(Ureg *ureg, void*)
+{
+	Pciisr *isr;
+	u32int sts;
+
+	sts = regs[MSI_INTR2_BASE + INTR_STATUS];
+	if(sts == 0)
+		return;
+	regs[MSI_INTR2_BASE + INTR_CLR] = sts;
+	for(isr = pciisr; sts != 0 && isr < &pciisr[nelem(pciisr)]; isr++, sts>>=1){
+		if((sts & 1) != 0 && isr->f != nil)
+			(*isr->f)(ureg, isr->a);
+	}
+	regs[MISC_EOI_CTRL] = 1;
+}
+
+static void
+pcicfginit(void)
+{
+	uvlong base, limit;
+	ulong ioa;
+
+	fmtinstall('T', tbdffmt);
+
+	pciscan(0, &pciroot);
+	if(pciroot == nil)
+		return;
+
+	/*
+	 * Work out how big the top bus is
+	 */
+	ioa = 0;
+	base = soc.pciwin;
+	pcibusmap(pciroot, &base, &ioa, 0);
+	limit = base-1;
+
+	/*
+	 * Align the windows and map it
+	 */
+	base = soc.pciwin;
+	regs[MISC_CPU_2_PCIE_MEM_WIN0_LO] = base;
+	regs[MISC_CPU_2_PCIE_MEM_WIN0_HI] = base >> 32;
+	base >>= 20, limit >>= 20;
+	regs[MISC_CPU_2_PCIE_MEM_WIN0_BASE_LIMIT] = (base & 0xFFF) << 4 | (limit & 0xFFF) << 20;
+	regs[MISC_CPU_2_PCIE_MEM_WIN0_BASE_HI] = base >> 12;
+	regs[MISC_CPU_2_PCIE_MEM_WIN0_LIMIT_HI] = limit >> 12;
+
+	ioa = 0;
+	base = soc.pciwin;
+	pcibusmap(pciroot, &base, &ioa, 1);
+
+	pcihinv(pciroot);
+}
+
+void
+pcibcmlink(void)
+{
+	int log2dmasize = 30;	// 1GB
+
+	regs[RGR1_SW_INIT_1] |= 3;
+	delay(200);
+	regs[RGR1_SW_INIT_1] &= ~2;
+	regs[MISC_PCIE_CTRL] &= ~5;
+	delay(200);
+
+	regs[MISC_HARD_PCIE_HARD_DEBUG] &= ~0x08000000;
+	delay(200);
+
+	regs[MSI_INTR2_BASE + INTR_CLR] = -1;
+	regs[MSI_INTR2_BASE + INTR_MASK_SET] = -1;
+
+	regs[MISC_CPU_2_PCIE_MEM_WIN0_LO] = 0;
+	regs[MISC_CPU_2_PCIE_MEM_WIN0_HI] = 0;
+	regs[MISC_CPU_2_PCIE_MEM_WIN0_BASE_LIMIT] = 0;
+	regs[MISC_CPU_2_PCIE_MEM_WIN0_BASE_HI] = 0;
+	regs[MISC_CPU_2_PCIE_MEM_WIN0_LIMIT_HI] = 0;
+
+	// SCB_ACCESS_EN, CFG_READ_UR_MODE, MAX_BURST_SIZE_128, SCB0SIZE
+	regs[MISC_MISC_CTRL] = 1<<12 | 1<<13 | 0<<20 | (log2dmasize-15)<<27;
+
+	regs[MISC_RC_BAR2_CONFIG_LO] = (log2dmasize-15);
+	regs[MISC_RC_BAR2_CONFIG_HI] = 0;
+
+	regs[MISC_RC_BAR1_CONFIG_LO] = 0;
+	regs[MISC_RC_BAR3_CONFIG_LO] = 0;
+
+	regs[MISC_MSI_BAR_CONFIG_LO] = MSI_TARGET_ADDR | 1;
+	regs[MISC_MSI_BAR_CONFIG_HI] = MSI_TARGET_ADDR>>32;
+	regs[MISC_MSI_DATA_CONFIG] = 0xFFF86540;
+	intrenable(IRQpci, pciinterrupt, nil, BUSUNKNOWN, "pci");
+
+	// force to GEN2
+	regs[(0xAC + 12)/4] = (regs[(0xAC + 12)/4] & ~15) | 2;	// linkcap
+	regs[(0xAC + 48)/4] = (regs[(0xAC + 48)/4] & ~15) | 2;	// linkctl2
+
+	regs[RGR1_SW_INIT_1] &= ~1;
+	delay(500);
+
+	if((regs[MISC_PCIE_STATUS] & 0x30) != 0x30){
+		print("pcireset: phy link is down\n");
+		return;
+	}
+
+	regs[RC_CFG_PRIV1_ID_VAL3] = 0x060400;
+	regs[RC_CFG_VENDOR_VENDOR_SPECIFIC_REG1] &= ~0xC;
+	regs[MISC_HARD_PCIE_HARD_DEBUG] |= 2;
+
+	pcicfginit();
+}
--- a/sys/src/9/bcm64/pi4
+++ b/sys/src/9/bcm64/pi4
@@ -26,7 +26,7 @@
 
 link
 	gisb
-	pci
+	pcibcm
 	archbcm4	pci
 	usbxhci		pci archbcm4
 	ethergenet	ethermii
@@ -49,7 +49,7 @@
 	dma
 	gic
 	vcore
-
+	pci	pcibcm
 	dtracysys
 	dtracytimer
 
--- a/sys/src/9/kw/fns.h
+++ b/sys/src/9/kw/fns.h
@@ -130,31 +130,6 @@
 extern void sysprocsetup(Proc*);
 extern int isaconfig(char*, int, ISAConf*);	/* only devusb.c */
 
-/*
- * PCI
- */
-ulong	pcibarsize(Pcidev*, int);
-void	pcibussize(Pcidev*, ulong*, ulong*);
-int	pcicfgr8(Pcidev*, int);
-int	pcicfgr16(Pcidev*, int);
-int	pcicfgr32(Pcidev*, int);
-void	pcicfgw8(Pcidev*, int, int);
-void	pcicfgw16(Pcidev*, int, int);
-void	pcicfgw32(Pcidev*, int, int);
-void	pciclrbme(Pcidev*);
-void	pciclrioe(Pcidev*);
-void	pciclrmwi(Pcidev*);
-int	pcigetpms(Pcidev*);
-void	pcihinv(Pcidev*);
-uchar	pciipin(Pcidev*, uchar);
-Pcidev* pcimatch(Pcidev*, int, int);
-Pcidev* pcimatchtbdf(int);
-void	pcireset(void);
-int	pciscan(int, Pcidev**);
-void	pcisetbme(Pcidev*);
-void	pcisetioe(Pcidev*);
-void	pcisetmwi(Pcidev*);
-int	pcisetpms(Pcidev*, int);
 int	cas32(void*, u32int, u32int);
 int	tas32(void*);
 
--- a/sys/src/9/kw/io.h
+++ b/sys/src/9/kw/io.h
@@ -27,168 +27,6 @@
 #define BUSTYPE(tbdf)	((tbdf)>>24)
 #define BUSBDF(tbdf)	((tbdf)&0x00FFFF00)
 
-/*
- * PCI support code.
- */
-enum {					/* type 0 & type 1 pre-defined header */
-	PciVID		= 0x00,		/* vendor ID */
-	PciDID		= 0x02,		/* device ID */
-	PciPCR		= 0x04,		/* command */
-	PciPSR		= 0x06,		/* status */
-	PciRID		= 0x08,		/* revision ID */
-	PciCCRp		= 0x09,		/* programming interface class code */
-	PciCCRu		= 0x0A,		/* sub-class code */
-	PciCCRb		= 0x0B,		/* base class code */
-	PciCLS		= 0x0C,		/* cache line size */
-	PciLTR		= 0x0D,		/* latency timer */
-	PciHDT		= 0x0E,		/* header type */
-	PciBST		= 0x0F,		/* BIST */
-};
-
-/* ccrb (base class code) values; controller types */
-enum {
-	Pcibcpci1	= 0,		/* pci 1.0; no class codes defined */
-	Pcibcstore	= 1,		/* mass storage */
-	Pcibcnet	= 2,		/* network */
-	Pcibcdisp	= 3,		/* display */
-	Pcibcmmedia	= 4,		/* multimedia */
-	Pcibcmem	= 5,		/* memory */
-	Pcibcbridge	= 6,		/* bridge */
-	Pcibccomm	= 7,		/* simple comms (e.g., serial) */
-	Pcibcbasesys	= 8,		/* base system */
-	Pcibcinput	= 9,		/* input */
-	Pcibcdock	= 0xa,		/* docking stations */
-	Pcibcproc	= 0xb,		/* processors */
-	Pcibcserial	= 0xc,		/* serial bus (e.g., USB) */
-	Pcibcwireless	= 0xd,		/* wireless */
-	Pcibcintell	= 0xe,		/* intelligent i/o */
-	Pcibcsatcom	= 0xf,		/* satellite comms */
-	Pcibccrypto	= 0x10,		/* encryption/decryption */
-	Pcibcdacq	= 0x11,		/* data acquisition & signal proc. */
-};
-
-/* ccru (sub-class code) values; common cases only */
-enum {
-	/* mass storage */
-	Pciscscsi	= 0,		/* SCSI */
-	Pciscide	= 1,		/* IDE (ATA) */
-
-	/* network */
-	Pciscether	= 0,		/* Ethernet */
-
-	/* display */
-	Pciscvga	= 0,		/* VGA */
-	Pciscxga	= 1,		/* XGA */
-	Pcisc3d		= 2,		/* 3D */
-
-	/* bridges */
-	Pcischostpci	= 0,		/* host/pci */
-	Pciscpcicpci	= 1,		/* pci/pci */
-
-	/* simple comms */
-	Pciscserial	= 0,		/* 16450, etc. */
-	Pciscmultiser	= 1,		/* multiport serial */
-
-	/* serial bus */
-	Pciscusb	= 3,		/* USB */
-};
-
-enum {					/* type 0 pre-defined header */
-	PciCIS		= 0x28,		/* cardbus CIS pointer */
-	PciSVID		= 0x2C,		/* subsystem vendor ID */
-	PciSID		= 0x2E,		/* subsystem ID */
-	PciEBAR0	= 0x30,		/* expansion ROM base address */
-	PciMGNT		= 0x3E,		/* burst period length */
-	PciMLT		= 0x3F,		/* maximum latency between bursts */
-};
-
-enum {					/* type 1 pre-defined header */
-	PciPBN		= 0x18,		/* primary bus number */
-	PciSBN		= 0x19,		/* secondary bus number */
-	PciUBN		= 0x1A,		/* subordinate bus number */
-	PciSLTR		= 0x1B,		/* secondary latency timer */
-	PciIBR		= 0x1C,		/* I/O base */
-	PciILR		= 0x1D,		/* I/O limit */
-	PciSPSR		= 0x1E,		/* secondary status */
-	PciMBR		= 0x20,		/* memory base */
-	PciMLR		= 0x22,		/* memory limit */
-	PciPMBR		= 0x24,		/* prefetchable memory base */
-	PciPMLR		= 0x26,		/* prefetchable memory limit */
-	PciPUBR		= 0x28,		/* prefetchable base upper 32 bits */
-	PciPULR		= 0x2C,		/* prefetchable limit upper 32 bits */
-	PciIUBR		= 0x30,		/* I/O base upper 16 bits */
-	PciIULR		= 0x32,		/* I/O limit upper 16 bits */
-	PciEBAR1	= 0x28,		/* expansion ROM base address */
-	PciBCR		= 0x3E,		/* bridge control register */
-};
-
-enum {					/* type 2 pre-defined header */
-	PciCBExCA	= 0x10,
-	PciCBSPSR	= 0x16,
-	PciCBPBN	= 0x18,		/* primary bus number */
-	PciCBSBN	= 0x19,		/* secondary bus number */
-	PciCBUBN	= 0x1A,		/* subordinate bus number */
-	PciCBSLTR	= 0x1B,		/* secondary latency timer */
-	PciCBMBR0	= 0x1C,
-	PciCBMLR0	= 0x20,
-	PciCBMBR1	= 0x24,
-	PciCBMLR1	= 0x28,
-	PciCBIBR0	= 0x2C,		/* I/O base */
-	PciCBILR0	= 0x30,		/* I/O limit */
-	PciCBIBR1	= 0x34,		/* I/O base */
-	PciCBILR1	= 0x38,		/* I/O limit */
-	PciCBSVID	= 0x40,		/* subsystem vendor ID */
-	PciCBSID	= 0x42,		/* subsystem ID */
-	PciCBLMBAR	= 0x44,		/* legacy mode base address */
-};
-
-typedef struct Pcisiz Pcisiz;
-struct Pcisiz
-{
-	Pcidev*	dev;
-	int	siz;
-	int	bar;
-};
-
-typedef struct Pcidev Pcidev;
-struct Pcidev
-{
-	int	tbdf;			/* type+bus+device+function */
-	ushort	vid;			/* vendor ID */
-	ushort	did;			/* device ID */
-
-	ushort	pcr;
-
-	uchar	rid;
-	uchar	ccrp;
-	uchar	ccru;
-	uchar	ccrb;
-	uchar	cls;
-	uchar	ltr;
-
-	struct {
-		ulong	bar;		/* base address */
-		int	size;
-	} mem[6];
-
-	struct {
-		ulong	bar;	
-		int	size;
-	} rom;
-	uchar	intl;			/* interrupt line */
-
-	Pcidev*	list;
-	Pcidev*	link;			/* next device on this bno */
-
-	Pcidev*	bridge;			/* down a bus */
-	struct {
-		ulong	bar;
-		int	size;
-	} ioa, mema;
-
-	int	pmrb;			/* power management register block */
-};
-
 #define PCIWINDOW	0
 #define PCIWADDR(va)	(PADDR(va)+PCIWINDOW)
 
--- a/sys/src/9/mtx/ether2114x.c
+++ b/sys/src/9/mtx/ether2114x.c
@@ -14,6 +14,7 @@
 #include "dat.h"
 #include "fns.h"
 #include "io.h"
+#include "../port/pci.h"
 #include "../port/error.h"
 #include "../port/netif.h"
 #include "../port/etherif.h"
--- a/sys/src/9/mtx/fns.h
+++ b/sys/src/9/mtx/fns.h
@@ -65,21 +65,9 @@
 void	outss(int, void*, int);
 void	outl(int, ulong);
 void	outsl(int, void*, int);
-int	pciscan(int, Pcidev **);
-ulong pcibarsize(Pcidev *, int);
-int	pcicfgr8(Pcidev*, int);
-int	pcicfgr16(Pcidev*, int);
-int	pcicfgr32(Pcidev*, int);
-void	pcicfgw8(Pcidev*, int, int);
-void	pcicfgw16(Pcidev*, int, int);
-void	pcicfgw32(Pcidev*, int, int);
-void pciclrbme(Pcidev*);
-void	pcihinv(Pcidev*);
-uchar pciipin(Pcidev *, uchar);
-Pcidev* pcimatch(Pcidev*, int, int);
-Pcidev* pcimatchtbdf(int);
-void	pcireset(void);
-void	pcisetbme(Pcidev*);
+int	pcicfgrw8(int, int, int, int);
+int	pcicfgrw16(int, int, int, int);
+int	pcicfgrw32(int, int, int, int);
 #define procrestore(p)
 void	procsave(Proc*);
 void	procsetup(Proc*);
--- a/sys/src/9/mtx/io.h
+++ b/sys/src/9/mtx/io.h
@@ -32,149 +32,11 @@
 } Vctl;
 
 enum {
-	BusCBUS		= 0,		/* Corollary CBUS */
-	BusCBUSII,			/* Corollary CBUS II */
-	BusEISA,			/* Extended ISA */
-	BusFUTURE,			/* IEEE Futurebus */
-	BusINTERN,			/* Internal bus */
-	BusISA,				/* Industry Standard Architecture */
-	BusMBI,				/* Multibus I */
-	BusMBII,			/* Multibus II */
-	BusMCA,				/* Micro Channel Architecture */
-	BusMPI,				/* MPI */
-	BusMPSA,			/* MPSA */
-	BusNUBUS,			/* Apple Macintosh NuBus */
-	BusPCI,				/* Peripheral Component Interconnect */
-	BusPCMCIA,			/* PC Memory Card International Association */
-	BusTC,				/* DEC TurboChannel */
-	BusVL,				/* VESA Local bus */
-	BusVME,				/* VMEbus */
-	BusXPRESS,			/* Express System Bus */
-};
-
-#define MKBUS(t,b,d,f)	(((t)<<24)|(((b)&0xFF)<<16)|(((d)&0x1F)<<11)|(((f)&0x07)<<8))
-#define BUSFNO(tbdf)	(((tbdf)>>8)&0x07)
-#define BUSDNO(tbdf)	(((tbdf)>>11)&0x1F)
-#define BUSBNO(tbdf)	(((tbdf)>>16)&0xFF)
-#define BUSTYPE(tbdf)	((tbdf)>>24)
-#define BUSDF(tbdf)		((tbdf)&0x000FF00)
-#define BUSBDF(tbdf)	((tbdf)&0x0FFFF00)
-#define BUSUNKNOWN	(-1)
-
-enum {
 	MaxEISA		= 16,
 	EISAconfig	= 0xC80,
 };
 
-/*
- * PCI support code.
- */
-enum {					/* type 0 and type 1 pre-defined header */
-	PciVID		= 0x00,		/* vendor ID */
-	PciDID		= 0x02,		/* device ID */
-	PciPCR		= 0x04,		/* command */
-	PciPSR		= 0x06,		/* status */
-	PciRID		= 0x08,		/* revision ID */
-	PciCCRp		= 0x09,		/* programming interface class code */
-	PciCCRu		= 0x0A,		/* sub-class code */
-	PciCCRb		= 0x0B,		/* base class code */
-	PciCLS		= 0x0C,		/* cache line size */
-	PciLTR		= 0x0D,		/* latency timer */
-	PciHDT		= 0x0E,		/* header type */
-	PciBST		= 0x0F,		/* BIST */
-
-	PciBAR0		= 0x10,		/* base address */
-	PciBAR1		= 0x14,
-
-	PciINTL		= 0x3C,		/* interrupt line */
-	PciINTP		= 0x3D,		/* interrupt pin */
-};
-
-enum {					/* type 0 pre-defined header */
-	PciCIS		= 0x28,		/* cardbus CIS pointer */
-	PciSVID		= 0x2C,		/* subsystem vendor ID */
-	PciSID		= 0x2E,		/* subsystem ID */
-	PciEBAR0	= 0x30,		/* expansion ROM base address */
-	PciMGNT		= 0x3E,		/* burst period length */
-	PciMLT		= 0x3F,		/* maximum latency between bursts */
-};
-
-enum {					/* type 1 pre-defined header */
-	PciPBN		= 0x18,		/* primary bus number */
-	PciSBN		= 0x19,		/* secondary bus number */
-	PciUBN		= 0x1A,		/* subordinate bus number */
-	PciSLTR		= 0x1B,		/* secondary latency timer */
-	PciIBR		= 0x1C,		/* I/O base */
-	PciILR		= 0x1D,		/* I/O limit */
-	PciSPSR		= 0x1E,		/* secondary status */
-	PciMBR		= 0x20,		/* memory base */
-	PciMLR		= 0x22,		/* memory limit */
-	PciPMBR		= 0x24,		/* prefetchable memory base */
-	PciPMLR		= 0x26,		/* prefetchable memory limit */
-	PciPUBR		= 0x28,		/* prefetchable base upper 32 bits */
-	PciPULR		= 0x2C,		/* prefetchable limit upper 32 bits */
-	PciIUBR		= 0x30,		/* I/O base upper 16 bits */
-	PciIULR		= 0x32,		/* I/O limit upper 16 bits */
-	PciEBAR1	= 0x28,		/* expansion ROM base address */
-	PciBCR		= 0x3E,		/* bridge control register */
-};
-
-enum {					/* type 2 pre-defined header */
-	PciCBExCA	= 0x10,
-	PciCBSPSR	= 0x16,
-	PciCBPBN	= 0x18,		/* primary bus number */
-	PciCBSBN	= 0x19,		/* secondary bus number */
-	PciCBUBN	= 0x1A,		/* subordinate bus number */
-	PciCBSLTR	= 0x1B,		/* secondary latency timer */
-	PciCBMBR0	= 0x1C,
-	PciCBMLR0	= 0x20,
-	PciCBMBR1	= 0x24,
-	PciCBMLR1	= 0x28,
-	PciCBIBR0	= 0x2C,		/* I/O base */
-	PciCBILR0	= 0x30,		/* I/O limit */
-	PciCBIBR1	= 0x34,		/* I/O base */
-	PciCBILR1	= 0x38,		/* I/O limit */
-	PciCBSVID	= 0x40,		/* subsystem vendor ID */
-	PciCBSID	= 0x42,		/* subsystem ID */
-	PciCBLMBAR	= 0x44,		/* legacy mode base address */
-};
-
-typedef struct Pcisiz Pcisiz;
-struct Pcisiz
-{
-	Pcidev*	dev;
-	int	siz;
-	int	bar;
-};
-
-typedef struct Pcidev Pcidev;
-typedef struct Pcidev {
-	int	tbdf;			/* type+bus+device+function */
-	ushort	vid;			/* vendor ID */
-	ushort	did;			/* device ID */
-
-	uchar	rid;
-	uchar	ccrp;
-	uchar	ccru;
-	uchar	ccrb;
-
-	struct {
-		ulong	bar;		/* base address */
-		int	size;
-	} mem[6];
-
-	uchar	intl;			/* interrupt line */
-
-	Pcidev*	list;
-	Pcidev*	link;			/* next device on this bno */
-
-	Pcidev*	bridge;			/* down a bus */
-	struct {
-		ulong	bar;
-		int	size;
-	} ioa, mema;
-	ulong	pcr;
-};
-
 #define PCIWINDOW	0x80000000
 #define PCIWADDR(va)	(PADDR(va)+PCIWINDOW)
+
+#define BUSUNKNOWN	(-1)
--- a/sys/src/9/mtx/mkfile
+++ b/sys/src/9/mtx/mkfile
@@ -1,5 +1,5 @@
 CONF=mtx
-CONFLIST=mtx mtxcpu
+CONFLIST=mtx
 
 objtype=power
 </$objtype/mkfile
--- a/sys/src/9/mtx/mtx
+++ b/sys/src/9/mtx/mtx
@@ -20,11 +20,13 @@
 	ip		arp chandial ip ipv6 ipaux iproute netif netlog nullmedium pktmedium inferno
 
 link
+	pcimtx
 	ether2114x	pci
 	ethermedium
 	netdevmedium
 
 misc
+	pci		pcimtx
 	uarti8250
 
 ip
--- a/sys/src/9/mtx/mtxcpu
+++ /dev/null
@@ -1,44 +1,0 @@
-dev
-	root
-	cons
-	swap
-	arch
-	pnp		pci
-	env
-	pipe
-	proc
-	mnt
-	srv
-	dup
-	ssl
-	cap
-	kprof
-	uart
-	rtc
-
-	ether		netif
-	ip		arp chandial ip ipv6 ipaux iproute netif netlog nullmedium pktmedium inferno
-
-link
-	ether2114x	pci
-	ethermedium
-	netdevmedium
-
-misc
-	uarti8250
-
-ip
-	tcp
-	udp
-	ipifc
-	icmp
-	icmp6
-
-port
-	int cpuserver = 1;
-
-bootdir
-	/$objtype/bin/paqfs
-	/$objtype/bin/auth/factotum
-	bootfs.paq
-	boot
--- a/sys/src/9/mtx/pci.c
+++ /dev/null
@@ -1,908 +1,0 @@
-/*
- * PCI support code.
- */
-#include "u.h"
-#include "../port/lib.h"
-#include "mem.h"
-#include "dat.h"
-#include "fns.h"
-#include "io.h"
-#include "../port/error.h"
-
-#define DBG	if(0) pcilog
-
-struct
-{
-	char	output[16384];
-	int	ptr;
-}PCICONS;
-
-int
-pcilog(char *fmt, ...)
-{
-	int n;
-	va_list arg;
-	char buf[PRINTSIZE];
-
-	va_start(arg, fmt);
-	n = vseprint(buf, buf+sizeof(buf), fmt, arg) - buf;
-	va_end(arg);
-
-	memmove(PCICONS.output+PCICONS.ptr, buf, n);
-	PCICONS.ptr += n;
-	return n;
-}
-
-enum
-{					/* configuration mechanism #1 */
-	PciADDR		= 0xCF8,	/* CONFIG_ADDRESS */
-	PciDATA		= 0xCFC,	/* CONFIG_DATA */
-
-					/* configuration mechanism #2 */
-	PciCSE		= 0xCF8,	/* configuration space enable */
-	PciFORWARD	= 0xCFA,	/* which bus */
-
-	MaxFNO		= 7,
-	MaxUBN		= 255,
-};
-
-enum
-{					/* command register */
-	IOen		= (1<<0),
-	MEMen		= (1<<1),
-	MASen		= (1<<2),
-	MemWrInv	= (1<<4),
-	PErrEn		= (1<<6),
-	SErrEn		= (1<<8),
-};
-
-static Lock pcicfglock;
-static QLock pcicfginitlock;
-static int pcicfgmode = -1;
-static int pcimaxbno = 7;
-static int pcimaxdno;
-static Pcidev* pciroot;
-static Pcidev* pcilist;
-static Pcidev* pcitail;
-
-static int pcicfgrw32(int, int, int, int);
-static int pcicfgrw8(int, int, int, int);
-
-static char* bustypes[] = {
-	"CBUSI",
-	"CBUSII",
-	"EISA",
-	"FUTURE",
-	"INTERN",
-	"ISA",
-	"MBI",
-	"MBII",
-	"MCA",
-	"MPI",
-	"MPSA",
-	"NUBUS",
-	"PCI",
-	"PCMCIA",
-	"TC",
-	"VL",
-	"VME",
-	"XPRESS",
-};
-
-#pragma	varargck	type	"T"	int
-
-static int
-tbdffmt(Fmt* fmt)
-{
-	char *p;
-	int l, r, type, tbdf;
-
-	if((p = malloc(READSTR)) == nil)
-		return fmtstrcpy(fmt, "(tbdfconv)");
-		
-	switch(fmt->r){
-	case 'T':
-		tbdf = va_arg(fmt->args, int);
-		type = BUSTYPE(tbdf);
-		if(type < nelem(bustypes))
-			l = snprint(p, READSTR, bustypes[type]);
-		else
-			l = snprint(p, READSTR, "%d", type);
-		snprint(p+l, READSTR-l, ".%d.%d.%d",
-			BUSBNO(tbdf), BUSDNO(tbdf), BUSFNO(tbdf));
-		break;
-
-	default:
-		snprint(p, READSTR, "(tbdfconv)");
-		break;
-	}
-	r = fmtstrcpy(fmt, p);
-	free(p);
-
-	return r;
-}
-
-ulong
-pcibarsize(Pcidev *p, int rno)
-{
-	ulong v, size;
-
-	v = pcicfgrw32(p->tbdf, rno, 0, 1);
-	pcicfgrw32(p->tbdf, rno, 0xFFFFFFF0, 0);
-	size = pcicfgrw32(p->tbdf, rno, 0, 1);
-	if(v & 1)
-		size |= 0xFFFF0000;
-	pcicfgrw32(p->tbdf, rno, v, 0);
-
-	return -(size & ~0x0F);
-}
-
-static int
-pcisizcmp(void *a, void *b)
-{
-	Pcisiz *aa, *bb;
-
-	aa = a;
-	bb = b;
-	return aa->siz - bb->siz;
-}
-
-static ulong
-pcimask(ulong v)
-{
-	ulong m;
-
-	m = BI2BY*sizeof(v);
-	for(m = 1<<(m-1); m != 0; m >>= 1) {
-		if(m & v)
-			break;
-	}
-
-	m--;
-	if((v & m) == 0)
-		return v;
-
-	v |= m;
-	return v+1;
-}
-
-static void
-pcibusmap(Pcidev *root, ulong *pmema, ulong *pioa, int wrreg)
-{
-	Pcidev *p;
-	int ntb, i, size, rno, hole;
-	ulong v, mema, ioa, sioa, smema, base, limit;
-	Pcisiz *table, *tptr, *mtb, *itb;
-	extern void qsort(void*, long, long, int (*)(void*, void*));
-
-	ioa = *pioa;
-	mema = *pmema;
-
-	DBG("pcibusmap wr=%d %T mem=%luX io=%luX\n", 
-		wrreg, root->tbdf, mema, ioa);
-
-	ntb = 0;
-	for(p = root; p != nil; p = p->link)
-		ntb++;
-
-	ntb *= (PciCIS-PciBAR0)/4;
-	table = malloc(2*ntb*sizeof(Pcisiz));
-	itb = table;
-	mtb = table+ntb;
-
-	/*
-	 * Build a table of sizes
-	 */
-	for(p = root; p != nil; p = p->link) {
-		if(p->ccrb == 0x06) {
-			if(p->ccru == 0x04 && p->bridge != nil) {
-				sioa = ioa;
-				smema = mema;
-				pcibusmap(p->bridge, &smema, &sioa, 0);
-	
-				hole = pcimask(smema-mema);
-				if(hole < (1<<20))
-					hole = 1<<20;
-				p->mema.size = hole;
-	
-				hole = pcimask(sioa-ioa);
-				if(hole < (1<<12))
-					hole = 1<<12;
-	
-				p->ioa.size = hole;
-	
-				itb->dev = p;
-				itb->bar = -1;
-				itb->siz = p->ioa.size;
-				itb++;
-	
-				mtb->dev = p;
-				mtb->bar = -1;
-				mtb->siz = p->mema.size;
-				mtb++;
-			}
-			if((pcicfgr8(p, PciHDT)&0x7f) != 0)
-				continue;
-		}
-
-		for(i = 0; i <= 5; i++) {
-			rno = PciBAR0 + i*4;
-			v = pcicfgrw32(p->tbdf, rno, 0, 1);
-			size = pcibarsize(p, rno);
-			if(size == 0)
-				continue;
-
-			if(v & 1) {
-				itb->dev = p;
-				itb->bar = i;
-				itb->siz = size;
-				itb++;
-			}
-			else {
-				mtb->dev = p;
-				mtb->bar = i;
-				mtb->siz = size;
-				mtb++;
-			}
-
-			p->mem[i].size = size;
-		}
-	}
-
-	/*
-	 * Sort both tables IO smallest first, Memory largest
-	 */
-	qsort(table, itb-table, sizeof(Pcisiz), pcisizcmp);
-	tptr = table+ntb;
-	qsort(tptr, mtb-tptr, sizeof(Pcisiz), pcisizcmp);
-
-	/*
-	 * Allocate IO address space on this bus
-	 */
-	for(tptr = table; tptr < itb; tptr++) {
-		hole = tptr->siz;
-		if(tptr->bar == -1)
-			hole = 1<<12;
-		ioa = (ioa+hole-1) & ~(hole-1);
-
-		p = tptr->dev;
-		if(tptr->bar == -1)
-			p->ioa.bar = ioa;
-		else {
-			p->pcr |= IOen;
-			p->mem[tptr->bar].bar = ioa|1;
-			if(wrreg)
-				pcicfgrw32(p->tbdf, PciBAR0+(tptr->bar*4), ioa|1, 0);
-		}
-
-		ioa += tptr->siz;
-	}
-
-	/*
-	 * Allocate Memory address space on this bus
-	 */
-	for(tptr = table+ntb; tptr < mtb; tptr++) {
-		hole = tptr->siz;
-		if(tptr->bar == -1)
-			hole = 1<<20;
-		mema = (mema+hole-1) & ~(hole-1);
-
-		p = tptr->dev;
-		if(tptr->bar == -1)
-			p->mema.bar = mema;
-		else {
-			p->pcr |= MEMen;
-			p->mem[tptr->bar].bar = mema;
-			if(wrreg)
-				pcicfgrw32(p->tbdf, PciBAR0+(tptr->bar*4), mema, 0);
-		}
-		mema += tptr->siz;
-	}
-
-	*pmema = mema;
-	*pioa = ioa;
-	free(table);
-
-	if(wrreg == 0)
-		return;
-
-	/*
-	 * Finally set all the bridge addresses & registers
-	 */
-	for(p = root; p != nil; p = p->link) {
-		if(p->bridge == nil) {
-			pcicfgrw8(p->tbdf, PciLTR, 64, 0);
-
-			p->pcr |= MASen;
-			pcicfgrw32(p->tbdf, PciPCR, p->pcr, 0);
-			continue;
-		}
-
-		base = p->ioa.bar;
-		limit = base+p->ioa.size-1;
-		v = pcicfgrw32(p->tbdf, PciIBR, 0, 1);
-		v = (v&0xFFFF0000)|(limit & 0xF000)|((base & 0xF000)>>8);
-		pcicfgrw32(p->tbdf, PciIBR, v, 0);
-		v = (limit & 0xFFFF0000)|(base>>16);
-		pcicfgrw32(p->tbdf, PciIUBR, v, 0);
-
-		base = p->mema.bar;
-		limit = base+p->mema.size-1;
-		v = (limit & 0xFFF00000)|((base & 0xFFF00000)>>16);
-		pcicfgrw32(p->tbdf, PciMBR, v, 0);
-
-		/*
-		 * Disable memory prefetch
-		 */
-		pcicfgrw32(p->tbdf, PciPMBR, 0x0000FFFF, 0);
-		pcicfgrw8(p->tbdf, PciLTR, 64, 0);
-
-		/*
-		 * Enable the bridge
-		 */
-		v = 0xFFFF0000 | IOen | MEMen | MASen;
-		pcicfgrw32(p->tbdf, PciPCR, v, 0);
-
-		sioa = p->ioa.bar;
-		smema = p->mema.bar;
-		pcibusmap(p->bridge, &smema, &sioa, 1);
-	}
-}
-
-static int
-pcilscan(int bno, Pcidev** list)
-{
-	Pcidev *p, *head, *tail;
-	int dno, fno, i, hdt, l, maxfno, maxubn, rno, sbn, tbdf, ubn;
-
-	maxubn = bno;
-	head = nil;
-	tail = nil;
-	for(dno = 0; dno <= pcimaxdno; dno++){
-		maxfno = 0;
-		for(fno = 0; fno <= maxfno; fno++){
-			/*
-			 * For this possible device, form the
-			 * bus+device+function triplet needed to address it
-			 * and try to read the vendor and device ID.
-			 * If successful, allocate a device struct and
-			 * start to fill it in with some useful information
-			 * from the device's configuration space.
-			 */
-			tbdf = MKBUS(BusPCI, bno, dno, fno);
-			l = pcicfgrw32(tbdf, PciVID, 0, 1);
-			if(l == 0xFFFFFFFF || l == 0)
-				continue;
-			p = malloc(sizeof(*p));
-			p->tbdf = tbdf;
-			p->vid = l;
-			p->did = l>>16;
-
-			if(pcilist != nil)
-				pcitail->list = p;
-			else
-				pcilist = p;
-			pcitail = p;
-
-			p->rid = pcicfgr8(p, PciRID);
-			p->ccrp = pcicfgr8(p, PciCCRp);
-			p->ccru = pcicfgr8(p, PciCCRu);
-			p->ccrb = pcicfgr8(p, PciCCRb);
-			p->pcr = pcicfgr32(p, PciPCR);
-
-			p->intl = pcicfgr8(p, PciINTL);
-
-			/*
-			 * If the device is a multi-function device adjust the
-			 * loop count so all possible functions are checked.
-			 */
-			hdt = pcicfgr8(p, PciHDT);
-			if(hdt & 0x80)
-				maxfno = MaxFNO;
-
-			/*
-			 * If appropriate, read the base address registers
-			 * and work out the sizes.
-			 */
-			switch(p->ccrb) {
-			case 0x01:		/* mass storage controller */
-			case 0x02:		/* network controller */
-			case 0x03:		/* display controller */
-			case 0x04:		/* multimedia device */
-			case 0x06:		/* bridge device */
-			case 0x07:		/* simple comm. controllers */
-			case 0x08:		/* base system peripherals */
-			case 0x09:		/* input devices */
-			case 0x0A:		/* docking stations */
-			case 0x0B:		/* processors */
-			case 0x0C:		/* serial bus controllers */
-				if((hdt & 0x7F) != 0)
-					break;
-				rno = PciBAR0 - 4;
-				for(i = 0; i < nelem(p->mem); i++) {
-					rno += 4;
-					p->mem[i].bar = pcicfgr32(p, rno);
-					p->mem[i].size = pcibarsize(p, rno);
-				}
-				break;
-
-			case 0x00:
-			case 0x05:		/* memory controller */
-			default:
-				break;
-			}
-
-			if(head != nil)
-				tail->link = p;
-			else
-				head = p;
-			tail = p;
-		}
-	}
-
-	*list = head;
-	for(p = head; p != nil; p = p->link){
-		/*
-		 * Find PCI-PCI bridges and recursively descend the tree.
-		 */
-		if(p->ccrb != 0x06 || p->ccru != 0x04)
-			continue;
-
-		/*
-		 * If the secondary or subordinate bus number is not
-		 * initialised try to do what the PCI BIOS should have
-		 * done and fill in the numbers as the tree is descended.
-		 * On the way down the subordinate bus number is set to
-		 * the maximum as it's not known how many buses are behind
-		 * this one; the final value is set on the way back up.
-		 */
-		sbn = pcicfgr8(p, PciSBN);
-		ubn = pcicfgr8(p, PciUBN);
-
-		if(sbn == 0 || ubn == 0) {
-			sbn = maxubn+1;
-			/*
-			 * Make sure memory, I/O and master enables are
-			 * off, set the primary, secondary and subordinate
-			 * bus numbers and clear the secondary status before
-			 * attempting to scan the secondary bus.
-			 *
-			 * Initialisation of the bridge should be done here.
-			 */
-			pcicfgw32(p, PciPCR, 0xFFFF0000);
-			l = (MaxUBN<<16)|(sbn<<8)|bno;
-			pcicfgw32(p, PciPBN, l);
-			pcicfgw16(p, PciSPSR, 0xFFFF);
-			maxubn = pcilscan(sbn, &p->bridge);
-			l = (maxubn<<16)|(sbn<<8)|bno;
-
-			pcicfgw32(p, PciPBN, l);
-		}
-		else {
-			maxubn = ubn;
-			pcilscan(sbn, &p->bridge);
-		}
-	}
-
-	return maxubn;
-}
-
-int
-pciscan(int bno, Pcidev **list)
-{
-	int ubn;
-
-	qlock(&pcicfginitlock);
-	ubn = pcilscan(bno, list);
-	qunlock(&pcicfginitlock);
-	return ubn;
-}
-
-static void
-pcicfginit(void)
-{
-	char *p;
-	int bno;
-	Pcidev **list;
-	ulong mema, ioa;
-
-	qlock(&pcicfginitlock);
-	if(pcicfgmode != -1)
-		goto out;
-
-	/*
-	 * Try to determine which PCI configuration mode is implemented.
-	 * Mode2 uses a byte at 0xCF8 and another at 0xCFA; Mode1 uses
-	 * a DWORD at 0xCF8 and another at 0xCFC and will pass through
-	 * any non-DWORD accesses as normal I/O cycles. There shouldn't be
-	 * a device behind these addresses so if Mode2 accesses fail try
-	 * for Mode1 (which is preferred, Mode2 is deprecated).
-	 */
-	outb(PciCSE, 0);
-	if(inb(PciCSE) == 0){
-		pcicfgmode = 2;
-		pcimaxdno = 15;
-	}
-	else {
-		outl(PciADDR, 0);
-		if(inl(PciADDR) == 0){
-			pcicfgmode = 1;
-			pcimaxdno = 31;
-		}
-	}
-	
-	if(pcicfgmode < 0)
-		goto out;
-
-	fmtinstall('T', tbdffmt);
-
-	if(p = getconf("*pcimaxbno"))
-		pcimaxbno = strtoul(p, 0, 0);
-	if(p = getconf("*pcimaxdno"))
-		pcimaxdno = strtoul(p, 0, 0);
-
-	list = &pciroot;
-	for(bno = 0; bno <= pcimaxbno; bno++) {
-		int sbno = bno;
-		bno = pcilscan(bno, list);
-
-		while(*list)
-			list = &(*list)->link;
-
-		if (sbno == 0) {
-			Pcidev *pci;
-
-			/*
-			  * If we have found a PCI-to-Cardbus bridge, make sure
-			  * it has no valid mappings anymore.  
-			  */
-			pci = pciroot;
-			while (pci) {
-				if (pci->ccrb == 6 && pci->ccru == 7) {
-					ushort bcr;
-
-					/* reset the cardbus */
-					bcr = pcicfgr16(pci, PciBCR);
-					pcicfgw16(pci, PciBCR, 0x40 | bcr);
-					delay(50);
-				}
-				pci = pci->link;
-			}
-		}
-	}
-
-	if(pciroot == nil)
-		goto out;
-
-	/*
-	 * Work out how big the top bus is
-	 */
-	mema = 0;
-	ioa = 0;
-	pcibusmap(pciroot, &mema, &ioa, 0);
-
-	DBG("Sizes: mem=%8.8lux size=%8.8lux io=%8.8lux\n",
-		mema, pcimask(mema), ioa);
-
-	/*
-	 * Align the windows and map it
-	 */
-	ioa = 0x1000;
-	mema = 0;
-
-	pcilog("Mask sizes: mem=%lux io=%lux\n", mema, ioa);
-
-	pcibusmap(pciroot, &mema, &ioa, 1);
-	DBG("Sizes2: mem=%lux io=%lux\n", mema, ioa);
-
-out:
-	qunlock(&pcicfginitlock);
-}
-
-static int
-pcicfgrw8(int tbdf, int rno, int data, int read)
-{
-	int o, type, x;
-
-	if(pcicfgmode == -1)
-		pcicfginit();
-
-	if(BUSBNO(tbdf))
-		type = 0x01;
-	else
-		type = 0x00;
-	x = -1;
-	if(BUSDNO(tbdf) > pcimaxdno)
-		return x;
-
-	lock(&pcicfglock);
-	switch(pcicfgmode){
-
-	case 1:
-		o = rno & 0x03;
-		rno &= ~0x03;
-		outl(PciADDR, 0x80000000|BUSBDF(tbdf)|rno|type);
-		if(read)
-			x = inb(PciDATA+o);
-		else
-			outb(PciDATA+o, data);
-		outl(PciADDR, 0);
-		break;
-
-	case 2:
-		outb(PciCSE, 0x80|(BUSFNO(tbdf)<<1));
-		outb(PciFORWARD, BUSBNO(tbdf));
-		if(read)
-			x = inb((0xC000|(BUSDNO(tbdf)<<8)) + rno);
-		else
-			outb((0xC000|(BUSDNO(tbdf)<<8)) + rno, data);
-		outb(PciCSE, 0);
-		break;
-	}
-	unlock(&pcicfglock);
-
-	return x;
-}
-
-int
-pcicfgr8(Pcidev* pcidev, int rno)
-{
-	return pcicfgrw8(pcidev->tbdf, rno, 0, 1);
-}
-
-void
-pcicfgw8(Pcidev* pcidev, int rno, int data)
-{
-	pcicfgrw8(pcidev->tbdf, rno, data, 0);
-}
-
-static int
-pcicfgrw16(int tbdf, int rno, int data, int read)
-{
-	int o, type, x;
-
-	if(pcicfgmode == -1)
-		pcicfginit();
-
-	if(BUSBNO(tbdf))
-		type = 0x01;
-	else
-		type = 0x00;
-	x = -1;
-	if(BUSDNO(tbdf) > pcimaxdno)
-		return x;
-
-	lock(&pcicfglock);
-	switch(pcicfgmode){
-
-	case 1:
-		o = rno & 0x02;
-		rno &= ~0x03;
-		outl(PciADDR, 0x80000000|BUSBDF(tbdf)|rno|type);
-		if(read)
-			x = ins(PciDATA+o);
-		else
-			outs(PciDATA+o, data);
-		outl(PciADDR, 0);
-		break;
-
-	case 2:
-		outb(PciCSE, 0x80|(BUSFNO(tbdf)<<1));
-		outb(PciFORWARD, BUSBNO(tbdf));
-		if(read)
-			x = ins((0xC000|(BUSDNO(tbdf)<<8)) + rno);
-		else
-			outs((0xC000|(BUSDNO(tbdf)<<8)) + rno, data);
-		outb(PciCSE, 0);
-		break;
-	}
-	unlock(&pcicfglock);
-
-	return x;
-}
-
-int
-pcicfgr16(Pcidev* pcidev, int rno)
-{
-	return pcicfgrw16(pcidev->tbdf, rno, 0, 1);
-}
-
-void
-pcicfgw16(Pcidev* pcidev, int rno, int data)
-{
-	pcicfgrw16(pcidev->tbdf, rno, data, 0);
-}
-
-static int
-pcicfgrw32(int tbdf, int rno, int data, int read)
-{
-	int type, x;
-
-	if(pcicfgmode == -1)
-		pcicfginit();
-
-	if(BUSBNO(tbdf))
-		type = 0x01;
-	else
-		type = 0x00;
-	x = -1;
-	if(BUSDNO(tbdf) > pcimaxdno)
-		return x;
-
-	lock(&pcicfglock);
-	switch(pcicfgmode){
-
-	case 1:
-		rno &= ~0x03;
-		outl(PciADDR, 0x80000000|BUSBDF(tbdf)|rno|type);
-		if(read)
-			x = inl(PciDATA);
-		else
-			outl(PciDATA, data);
-		outl(PciADDR, 0);
-		break;
-
-	case 2:
-		outb(PciCSE, 0x80|(BUSFNO(tbdf)<<1));
-		outb(PciFORWARD, BUSBNO(tbdf));
-		if(read)
-			x = inl((0xC000|(BUSDNO(tbdf)<<8)) + rno);
-		else
-			outl((0xC000|(BUSDNO(tbdf)<<8)) + rno, data);
-		outb(PciCSE, 0);
-		break;
-	}
-	unlock(&pcicfglock);
-
-	return x;
-}
-
-int
-pcicfgr32(Pcidev* pcidev, int rno)
-{
-	return pcicfgrw32(pcidev->tbdf, rno, 0, 1);
-}
-
-void
-pcicfgw32(Pcidev* pcidev, int rno, int data)
-{
-	pcicfgrw32(pcidev->tbdf, rno, data, 0);
-}
-
-Pcidev*
-pcimatch(Pcidev* prev, int vid, int did)
-{
-	if(pcicfgmode == -1)
-		pcicfginit();
-
-	if(prev == nil)
-		prev = pcilist;
-	else
-		prev = prev->list;
-
-	while(prev != nil){
-		if((vid == 0 || prev->vid == vid)
-		&& (did == 0 || prev->did == did))
-			break;
-		prev = prev->list;
-	}
-	return prev;
-}
-
-Pcidev*
-pcimatchtbdf(int tbdf)
-{
-	Pcidev *pcidev;
-
-	if(pcicfgmode == -1)
-		pcicfginit();
-
-	for(pcidev = pcilist; pcidev != nil; pcidev = pcidev->list) {
-		if(pcidev->tbdf == tbdf)
-			break;
-	}
-	return pcidev;
-}
-
-uchar
-pciipin(Pcidev *pci, uchar pin)
-{
-	if (pci == nil)
-		pci = pcilist;
-
-	while (pci) {
-		uchar intl;
-
-		if (pcicfgr8(pci, PciINTP) == pin && pci->intl != 0 && pci->intl != 0xff)
-			return pci->intl;
-
-		if (pci->bridge && (intl = pciipin(pci->bridge, pin)) != 0)
-			return intl;
-
-		pci = pci->list;
-	}
-	return 0;
-}
-
-static void
-pcilhinv(Pcidev* p)
-{
-	int i;
-	Pcidev *t;
-
-	if(p == nil) {
-		putstrn(PCICONS.output, PCICONS.ptr);
-		p = pciroot;
-		print("bus dev type vid  did intl memory\n");
-	}
-	for(t = p; t != nil; t = t->link) {
-		print("%d  %2d/%d %.2ux %.2ux %.2ux %.4ux %.4ux %3d  ",
-			BUSBNO(t->tbdf), BUSDNO(t->tbdf), BUSFNO(t->tbdf),
-			t->ccrb, t->ccru, t->ccrp, t->vid, t->did, t->intl);
-
-		for(i = 0; i < nelem(p->mem); i++) {
-			if(t->mem[i].size == 0)
-				continue;
-			print("%d:%.8lux %d ", i,
-				t->mem[i].bar, t->mem[i].size);
-		}
-		if(t->ioa.bar || t->ioa.size)
-			print("ioa:%.8lux %d ", t->ioa.bar, t->ioa.size);
-		if(t->mema.bar || t->mema.size)
-			print("mema:%.8lux %d ", t->mema.bar, t->mema.size);
-		if(t->bridge)
-			print("->%d", BUSBNO(t->bridge->tbdf));
-		print("\n");
-	}
-	while(p != nil) {
-		if(p->bridge != nil)
-			pcilhinv(p->bridge);
-		p = p->link;
-	}	
-}
-
-void
-pcihinv(Pcidev* p)
-{
-	if(pcicfgmode == -1)
-		pcicfginit();
-	qlock(&pcicfginitlock);
-	pcilhinv(p);
-	qunlock(&pcicfginitlock);
-}
-
-void
-pcireset(void)
-{
-	Pcidev *p;
-	int pcr;
-
-	if(pcicfgmode == -1)
-		pcicfginit();
-
-	for(p = pcilist; p != nil; p = p->list){
-		pcr = pcicfgr16(p, PciPCR);
-		pcr &= ~0x0004;
-		pcicfgw16(p, PciPCR, pcr);
-	}
-}
-
-void
-pcisetbme(Pcidev* p)
-{
-	int pcr;
-
-	pcr = pcicfgr16(p, PciPCR);
-	pcr |= MASen;
-	pcicfgw16(p, PciPCR, pcr);
-}
-
-void
-pciclrbme(Pcidev* p)
-{
-	int pcr;
-
-	pcr = pcicfgr16(p, PciPCR);
-	pcr &= ~MASen;
-	pcicfgw16(p, PciPCR, pcr);
-}
--- /dev/null
+++ b/sys/src/9/mtx/pcimtx.c
@@ -1,0 +1,224 @@
+/*
+ * PCI support code.
+ */
+#include "u.h"
+#include "../port/lib.h"
+#include "mem.h"
+#include "dat.h"
+#include "fns.h"
+#include "io.h"
+#include "../port/pci.h"
+#include "../port/error.h"
+
+enum {
+	/* configuration mechanism #1 */
+	PciADDR		= 0xCF8,	/* CONFIG_ADDRESS */
+	PciDATA		= 0xCFC,	/* CONFIG_DATA */
+
+	/* configuration mechanism #2 */
+	PciCSE		= 0xCF8,	/* configuration space enable */
+	PciFORWARD	= 0xCFA,	/* which bus */
+};
+
+static int pcicfgmode = -1;
+static int pcimaxbno = 7;
+static Pcidev* pciroot;
+
+static void
+pcicfginit(void)
+{
+	char *p;
+	int bno;
+	Pcidev **list;
+	uvlong mema;
+	ulong ioa;
+
+	fmtinstall('T', tbdffmt);
+
+	/*
+	 * Try to determine which PCI configuration mode is implemented.
+	 * Mode2 uses a byte at 0xCF8 and another at 0xCFA; Mode1 uses
+	 * a DWORD at 0xCF8 and another at 0xCFC and will pass through
+	 * any non-DWORD accesses as normal I/O cycles. There shouldn't be
+	 * a device behind these addresses so if Mode2 accesses fail try
+	 * for Mode1 (which is preferred, Mode2 is deprecated).
+	 */
+	outb(PciCSE, 0);
+	if(inb(PciCSE) == 0){
+		pcicfgmode = 2;
+		pcimaxdno = 15;
+	}
+	else {
+		outl(PciADDR, 0);
+		if(inl(PciADDR) == 0){
+			pcicfgmode = 1;
+			pcimaxdno = 31;
+		}
+	}
+	
+	if(pcicfgmode < 0)
+		return;
+
+	if(p = getconf("*pcimaxbno"))
+		pcimaxbno = strtoul(p, 0, 0);
+	if(p = getconf("*pcimaxdno"))
+		pcimaxdno = strtoul(p, 0, 0);
+
+	list = &pciroot;
+	for(bno = 0; bno <= pcimaxbno; bno++) {
+		int sbno = bno;
+		bno = pciscan(bno, list);
+
+		while(*list)
+			list = &(*list)->link;
+
+		if (sbno == 0) {
+			Pcidev *pci;
+
+			/*
+			  * If we have found a PCI-to-Cardbus bridge, make sure
+			  * it has no valid mappings anymore.  
+			  */
+			pci = pciroot;
+			while (pci) {
+				if (pci->ccrb == 6 && pci->ccru == 7) {
+					ushort bcr;
+
+					/* reset the cardbus */
+					bcr = pcicfgr16(pci, PciBCR);
+					pcicfgw16(pci, PciBCR, 0x40 | bcr);
+					delay(50);
+				}
+				pci = pci->link;
+			}
+		}
+	}
+
+	if(pciroot == nil)
+		return;
+
+	/*
+	 * Work out how big the top bus is
+	 */
+	mema = 0;
+	ioa = 0;
+	pcibusmap(pciroot, &mema, &ioa, 0);
+
+	/*
+	 * Align the windows and map it
+	 */
+	ioa = 0x1000;
+	mema = 0;
+	pcibusmap(pciroot, &mema, &ioa, 1);
+}
+
+int
+pcicfgrw8(int tbdf, int rno, int data, int read)
+{
+	int o, type, x;
+
+	if(BUSBNO(tbdf))
+		type = 0x01;
+	else
+		type = 0x00;
+	switch(pcicfgmode){
+	case 1:
+		o = rno & 0x03;
+		rno &= ~0x03;
+		outl(PciADDR, 0x80000000|BUSBDF(tbdf)|rno|type);
+		if(read)
+			data = inb(PciDATA+o);
+		else
+			outb(PciDATA+o, data);
+		outl(PciADDR, 0);
+		break;
+
+	case 2:
+		outb(PciCSE, 0x80|(BUSFNO(tbdf)<<1));
+		outb(PciFORWARD, BUSBNO(tbdf));
+		if(read)
+			data = inb((0xC000|(BUSDNO(tbdf)<<8)) + rno);
+		else
+			outb((0xC000|(BUSDNO(tbdf)<<8)) + rno, data);
+		outb(PciCSE, 0);
+		break;
+	default:
+		data = -1;
+	}
+	return data;
+}
+
+int
+pcicfgrw16(int tbdf, int rno, int data, int read)
+{
+	int o, type;
+
+	if(BUSBNO(tbdf))
+		type = 0x01;
+	else
+		type = 0x00;
+	switch(pcicfgmode){
+	case 1:
+		o = rno & 0x02;
+		rno &= ~0x03;
+		outl(PciADDR, 0x80000000|BUSBDF(tbdf)|rno|type);
+		if(read)
+			data = ins(PciDATA+o);
+		else
+			outs(PciDATA+o, data);
+		outl(PciADDR, 0);
+		break;
+	case 2:
+		outb(PciCSE, 0x80|(BUSFNO(tbdf)<<1));
+		outb(PciFORWARD, BUSBNO(tbdf));
+		if(read)
+			data = ins((0xC000|(BUSDNO(tbdf)<<8)) + rno);
+		else
+			outs((0xC000|(BUSDNO(tbdf)<<8)) + rno, data);
+		outb(PciCSE, 0);
+		break;
+	default:
+		data = -1;
+	}
+	return data;
+}
+
+int
+pcicfgrw32(int tbdf, int rno, int data, int read)
+{
+	int type;
+
+	if(BUSBNO(tbdf))
+		type = 0x01;
+	else
+		type = 0x00;
+	switch(pcicfgmode){
+	case 1:
+		rno &= ~0x03;
+		outl(PciADDR, 0x80000000|BUSBDF(tbdf)|rno|type);
+		if(read)
+			data = inl(PciDATA);
+		else
+			outl(PciDATA, data);
+		outl(PciADDR, 0);
+		break;
+	case 2:
+		outb(PciCSE, 0x80|(BUSFNO(tbdf)<<1));
+		outb(PciFORWARD, BUSBNO(tbdf));
+		if(read)
+			data = inl((0xC000|(BUSDNO(tbdf)<<8)) + rno);
+		else
+			outl((0xC000|(BUSDNO(tbdf)<<8)) + rno, data);
+		outb(PciCSE, 0);
+		break;
+	default:
+		data = -1;
+	}
+	return data;
+}
+
+void
+pcimtxlink(void)
+{
+	pcicfginit();
+}
--- a/sys/src/9/pc/archacpi.c
+++ b/sys/src/9/pc/archacpi.c
@@ -4,6 +4,7 @@
 #include "dat.h"
 #include "fns.h"
 #include "io.h"
+#include "../port/pci.h"
 #include "../port/error.h"
 
 #include "mp.h"
--- a/sys/src/9/pc/archmp.c
+++ b/sys/src/9/pc/archmp.c
@@ -4,6 +4,7 @@
 #include "dat.h"
 #include "fns.h"
 #include "io.h"
+#include "../port/pci.h"
 
 #include "mp.h"
 
--- a/sys/src/9/pc/audioac97.c
+++ b/sys/src/9/pc/audioac97.c
@@ -4,6 +4,7 @@
 #include "dat.h"
 #include "fns.h"
 #include "io.h"
+#include "../port/pci.h"
 #include "../port/error.h"
 #include "../port/audioif.h"
 
--- a/sys/src/9/pc/audiohda.c
+++ b/sys/src/9/pc/audiohda.c
@@ -4,6 +4,7 @@
 #include "dat.h"
 #include "fns.h"
 #include "io.h"
+#include "../port/pci.h"
 #include "../port/error.h"
 #include "../port/audioif.h"
 
--- a/sys/src/9/pc/cputemp.c
+++ b/sys/src/9/pc/cputemp.c
@@ -4,6 +4,7 @@
 #include "dat.h"
 #include "fns.h"
 #include "io.h"
+#include "../port/pci.h"
 
 static int
 intelcputempok(void)
--- a/sys/src/9/pc/devarch.c
+++ b/sys/src/9/pc/devarch.c
@@ -153,7 +153,6 @@
 			ioalloc(io_s, io_e - io_s + 1, 0, "pre-allocated");
 		}
 	}
-
 }
 
 /*
--- a/sys/src/9/pc/devlm78.c
+++ b/sys/src/9/pc/devlm78.c
@@ -5,6 +5,7 @@
 #include "fns.h"
 #include "io.h"
 #include "ureg.h"
+#include "../port/pci.h"
 #include "../port/error.h"
 
 /* this driver doesn't implement the management interrupts.  we
--- a/sys/src/9/pc/devlml.c
+++ b/sys/src/9/pc/devlml.c
@@ -8,6 +8,7 @@
 #include	"fns.h"
 #include	"../port/error.h"
 #include	"io.h"
+#include	"../port/pci.h"
 
 #include	"devlml.h"
 
--- a/sys/src/9/pc/devpccard.c
+++ b/sys/src/9/pc/devpccard.c
@@ -8,6 +8,7 @@
 #include "fns.h"
 #include "../port/error.h"
 #include "io.h"
+#include "../port/pci.h"
 
 #define DEBUG	0
 
@@ -922,7 +923,7 @@
 			if (pci->mem[i].size == 0)
 				continue;
 			if (pci->mem[i].bar & 1) {
-				iofree(pci->mem[i].bar & ~1);
+				iofree(pci->mem[i].bar & ~3);
 				pcicfgw16(cb->pci, PciCBIBR0 + ioindex * 8,
 						 (ushort)-1);
 				pcicfgw16(cb->pci, PciCBILR0 + ioindex * 8, 0);
--- a/sys/src/9/pc/devtv.c
+++ b/sys/src/9/pc/devtv.c
@@ -8,8 +8,9 @@
 #include	"dat.h"
 #include	"fns.h"
 #include	"../port/error.h"
-#include "io.h"
-#include "hcwAMC.h"
+#include	"io.h"
+#include	"../port/pci.h"
+#include	"hcwAMC.h"
 
 #define max(a, b)	(((a) > (b))? (a): (b))
 
--- a/sys/src/9/pc/devvga.c
+++ b/sys/src/9/pc/devvga.c
@@ -7,6 +7,7 @@
 #include "dat.h"
 #include "fns.h"
 #include "io.h"
+#include "../port/pci.h"
 #include "../port/error.h"
 
 #define	Image	IMAGE
--- a/sys/src/9/pc/ether2000.c
+++ b/sys/src/9/pc/ether2000.c
@@ -4,6 +4,7 @@
 #include "dat.h"
 #include "fns.h"
 #include "io.h"
+#include "../port/pci.h"
 #include "../port/error.h"
 #include "../port/netif.h"
 #include "../port/etherif.h"
@@ -62,7 +63,7 @@
 		p = ctlr->pcidev;
 		if(((p->did<<16)|p->vid) != id)
 			continue;
-		port = p->mem[0].bar & ~0x01;
+		port = p->mem[0].bar & ~3;
 		if(edev->port != 0 && edev->port != port)
 			continue;
 
--- a/sys/src/9/pc/ether2114x.c
+++ b/sys/src/9/pc/ether2114x.c
@@ -14,6 +14,7 @@
 #include "dat.h"
 #include "fns.h"
 #include "io.h"
+#include "../port/pci.h"
 #include "../port/error.h"
 #include "../port/netif.h"
 #include "../port/etherif.h"
@@ -1671,7 +1672,7 @@
 			print("dec2114x: can't allocate memory\n");
 			continue;
 		}
-		ctlr->port = p->mem[0].bar & ~0x01;
+		ctlr->port = p->mem[0].bar & ~3;
 		ctlr->pcidev = p;
 		ctlr->id = (p->did<<16)|p->vid;
 
--- a/sys/src/9/pc/ether79c970.c
+++ b/sys/src/9/pc/ether79c970.c
@@ -10,6 +10,7 @@
 #include "dat.h"
 #include "fns.h"
 #include "io.h"
+#include "../port/pci.h"
 #include "../port/error.h"
 #include "../port/netif.h"
 #include "../port/etherif.h"
@@ -490,7 +491,7 @@
 
 	p = nil;
 	while(p = pcimatch(p, 0x1022, 0x2000)){
-		port = p->mem[0].bar & ~0x01;
+		port = p->mem[0].bar & ~3;
 		if(ioalloc(port, p->mem[0].size, 0, "amd79c970") < 0){
 			print("amd79c970: port 0x%uX in use\n", port);
 			continue;
@@ -501,7 +502,7 @@
 			iofree(port);
 			continue;
 		}
-		ctlr->port = p->mem[0].bar & ~0x01;
+		ctlr->port = port;
 		ctlr->pcidev = p;
 
 		if(ctlrhead != nil)
--- a/sys/src/9/pc/ether8139.c
+++ b/sys/src/9/pc/ether8139.c
@@ -9,6 +9,7 @@
 #include "dat.h"
 #include "fns.h"
 #include "io.h"
+#include "../port/pci.h"
 #include "../port/error.h"
 #include "../port/netif.h"
 #include "../port/etherif.h"
@@ -693,7 +694,7 @@
 		p = ctlr->pcidev;
 		if(((p->did<<16)|p->vid) != id)
 			continue;
-		port = p->mem[0].bar & ~0x01;
+		port = p->mem[0].bar & ~3;
 		if(edev->port != 0 && edev->port != port)
 			continue;
 
--- a/sys/src/9/pc/ether8169.c
+++ b/sys/src/9/pc/ether8169.c
@@ -13,6 +13,7 @@
 #include "dat.h"
 #include "fns.h"
 #include "io.h"
+#include "../port/pci.h"
 #include "../port/error.h"
 #include "../port/netif.h"
 #include "../port/etherif.h"
@@ -1102,7 +1103,7 @@
 			break;
 		}
 
-		port = p->mem[0].bar & ~0x01;
+		port = p->mem[0].bar & ~3;
 		if(ioalloc(port, p->mem[0].size, 0, "rtl8169") < 0){
 			print("rtl8169: port %#ux in use\n", port);
 			continue;
--- a/sys/src/9/pc/ether82543gc.c
+++ b/sys/src/9/pc/ether82543gc.c
@@ -16,6 +16,7 @@
 #include "dat.h"
 #include "fns.h"
 #include "io.h"
+#include "../port/pci.h"
 #include "../port/error.h"
 #include "../port/netif.h"
 #include "../port/etherif.h"
@@ -1282,8 +1283,7 @@
 			free(ctlr);
 			continue;
 		}
-		cls = pcicfgr8(p, PciCLS);
-		switch(cls){
+		switch(p->cls){
 		case 0x08:
 		case 0x10:
 			break;
--- a/sys/src/9/pc/ether82557.c
+++ b/sys/src/9/pc/ether82557.c
@@ -14,6 +14,7 @@
 #include "dat.h"
 #include "fns.h"
 #include "io.h"
+#include "../port/pci.h"
 #include "../port/error.h"
 #include "../port/netif.h"
 #include "../port/etherif.h"
@@ -963,7 +964,7 @@
 		 * bar[1] is the I/O port register address (32 bytes) and
 		 * bar[2] is for the flash ROM (1MB).
 		 */
-		port = p->mem[1].bar & ~0x01;
+		port = p->mem[1].bar & ~3;
 		if(ioalloc(port, p->mem[1].size, 0, "i82557") < 0){
 			print("i82557: port %#ux in use\n", port);
 			continue;
--- a/sys/src/9/pc/ether82563.c
+++ b/sys/src/9/pc/ether82563.c
@@ -9,6 +9,7 @@
 #include "dat.h"
 #include "fns.h"
 #include "io.h"
+#include "../port/pci.h"
 #include "../port/error.h"
 #include "../port/netif.h"
 #include "../port/etherif.h"
--- a/sys/src/9/pc/ether82598.c
+++ b/sys/src/9/pc/ether82598.c
@@ -8,6 +8,7 @@
 #include "dat.h"
 #include "fns.h"
 #include "io.h"
+#include "../port/pci.h"
 #include "../port/error.h"
 #include "../port/netif.h"
 #include "../port/etherif.h"
--- a/sys/src/9/pc/ether83815.c
+++ b/sys/src/9/pc/ether83815.c
@@ -22,6 +22,7 @@
 #include "dat.h"
 #include "fns.h"
 #include "io.h"
+#include "../port/pci.h"
 #include "../port/error.h"
 #include "../port/netif.h"
 #include "../port/etherif.h"
@@ -1089,7 +1090,7 @@
 			print("ns83815: can't allocate memory\n");
 			continue;
 		}
-		ctlr->port = p->mem[0].bar & ~0x01;
+		ctlr->port = p->mem[0].bar & ~3;
 		ctlr->pcidev = p;
 		ctlr->id = id;
 
--- a/sys/src/9/pc/etherbcm.c
+++ b/sys/src/9/pc/etherbcm.c
@@ -13,6 +13,7 @@
 #include "dat.h"
 #include "fns.h"
 #include "io.h"
+#include "../port/pci.h"
 #include "../port/error.h"
 #include "../port/netif.h"
 #include "../port/etherif.h"
--- a/sys/src/9/pc/etherdp83820.c
+++ b/sys/src/9/pc/etherdp83820.c
@@ -10,6 +10,7 @@
 #include "dat.h"
 #include "fns.h"
 #include "io.h"
+#include "../port/pci.h"
 #include "../port/error.h"
 #include "../port/netif.h"
 #include "../port/etherif.h"
--- a/sys/src/9/pc/etherelnk3.c
+++ b/sys/src/9/pc/etherelnk3.c
@@ -14,6 +14,7 @@
 #include "dat.h"
 #include "fns.h"
 #include "io.h"
+#include "../port/pci.h"
 #include "../port/error.h"
 #include "../port/netif.h"
 #include "../port/etherif.h"
@@ -1475,7 +1476,7 @@
 		 */
 		if(!(p->mem[0].bar & 0x01))
 			continue;
-		port = p->mem[0].bar & ~0x01;
+		port = p->mem[0].bar & ~3;
 		if((port = ioalloc((port == 0)? -1: port,  p->mem[0].size, 
 					  0, "tcm59Xpci")) < 0){
 			print("tcm59Xpci: port 0x%uX in use\n", port);
--- a/sys/src/9/pc/etherga620.c
+++ b/sys/src/9/pc/etherga620.c
@@ -16,6 +16,7 @@
 #include "dat.h"
 #include "fns.h"
 #include "io.h"
+#include "../port/pci.h"
 #include "../port/error.h"
 #include "../port/netif.h"
 #include "../port/etherif.h"
@@ -1085,7 +1086,7 @@
 static int
 ga620reset(Ctlr* ctlr)
 {
-	int cls, csr, i, r;
+	int csr, i, r;
 
 	if(ga620detach(ctlr) < 0)
 		return -1;
@@ -1108,9 +1109,10 @@
 	csr = csr32r(ctlr, Ps) & (PCI32|PCI66);
 	csr |= PCIwcmd|PCIrcmd|PCImrm;
 	if(ctlr->pcidev->pcr & 0x0010){
-		cls = pcicfgr8(ctlr->pcidev, PciCLS) * 4;
-		if(cls != 32)
-			pcicfgw8(ctlr->pcidev, PciCLS, 32/4);
+		if(ctlr->pcidev->cls != 32/4){
+			ctlr->pcidev->cls = 32/4;
+			pcicfgw8(ctlr->pcidev, PciCLS, ctlr->pcidev->cls);
+		}
 		csr |= PCIwm32;
 	}
 	csr32w(ctlr, Ps, csr);
--- a/sys/src/9/pc/etherigbe.c
+++ b/sys/src/9/pc/etherigbe.c
@@ -22,6 +22,7 @@
 #include "dat.h"
 #include "fns.h"
 #include "io.h"
+#include "../port/pci.h"
 #include "../port/error.h"
 #include "../port/netif.h"
 #include "../port/etherif.h"
@@ -1910,7 +1911,6 @@
 static void
 igbepci(void)
 {
-	int cls;
 	Pcidev *p;
 	Ctlr *ctlr;
 	void *mem;
@@ -1949,8 +1949,7 @@
 			print("igbe: can't map %llux\n", p->mem[0].bar & ~0xF);
 			continue;
 		}
-		cls = pcicfgr8(p, PciCLS);
-		switch(cls){
+		switch(p->cls){
 		default:
 			print("igbe: p->cls %#ux, setting to 0x10\n", p->cls);
 			p->cls = 0x10;
@@ -1969,7 +1968,7 @@
 		ctlr->pcidev = p;
 		pcienable(p);
 		ctlr->id = (p->did<<16)|p->vid;
-		ctlr->cls = cls*4;
+		ctlr->cls = p->cls*4;
 		ctlr->nic = mem;
 
 		if(igbereset(ctlr)){
--- a/sys/src/9/pc/etheriwl.c
+++ b/sys/src/9/pc/etheriwl.c
@@ -12,6 +12,7 @@
 #include "dat.h"
 #include "fns.h"
 #include "io.h"
+#include "../port/pci.h"
 #include "../port/error.h"
 #include "../port/netif.h"
 #include "../port/etherif.h"
--- a/sys/src/9/pc/etherm10g.c
+++ b/sys/src/9/pc/etherm10g.c
@@ -12,6 +12,7 @@
 #include "dat.h"
 #include "fns.h"
 #include "io.h"
+#include "../port/pci.h"
 #include "../port/error.h"
 #include "../port/netif.h"
 #include "../port/etherif.h"
--- a/sys/src/9/pc/etherrt2860.c
+++ b/sys/src/9/pc/etherrt2860.c
@@ -12,6 +12,7 @@
 #include "dat.h"
 #include "fns.h"
 #include "io.h"
+#include "../port/pci.h"
 #include "../port/error.h"
 #include "../port/netif.h"
 #include "../port/etherif.h"
--- a/sys/src/9/pc/ethervgbe.c
+++ b/sys/src/9/pc/ethervgbe.c
@@ -27,6 +27,7 @@
 #include "dat.h"
 #include "fns.h"
 #include "io.h"
+#include "../port/pci.h"
 #include "../port/error.h"
 #include "../port/netif.h"
 #include "../port/etherif.h"
@@ -942,7 +943,7 @@
 			continue;
 		}
 
-		port &= 0xfffe;
+		port &= 0xfffc;
 
 		if(size != 256){
 			print("vgbe: invalid io size: %d\n", size);
--- a/sys/src/9/pc/ethervirtio.c
+++ b/sys/src/9/pc/ethervirtio.c
@@ -4,6 +4,7 @@
 #include "dat.h"
 #include "fns.h"
 #include "io.h"
+#include "../port/pci.h"
 #include "../port/error.h"
 #include "../port/netif.h"
 #include "../port/etherif.h"
@@ -563,6 +564,9 @@
 		/* non-transitional devices will have a revision > 0 */
 		if(p->rid != 0)
 			continue;
+		/* first membar needs to be I/O */
+		if((p->mem[0].bar & 1) == 0)
+			continue;
 		/* non-transitional device will have typ+0x40 */
 		if(pcicfgr16(p, 0x2E) != typ)
 			continue;
@@ -570,8 +574,7 @@
 			print("ethervirtio: no memory for Ctlr\n");
 			break;
 		}
-
-		c->port = p->mem[0].bar & ~0x1;
+		c->port = p->mem[0].bar & ~3;
 		if(ioalloc(c->port, p->mem[0].size, 0, "ethervirtio") < 0){
 			print("ethervirtio: port %ux in use\n", c->port);
 			free(c);
--- a/sys/src/9/pc/ethervt6102.c
+++ b/sys/src/9/pc/ethervt6102.c
@@ -15,6 +15,7 @@
 #include "dat.h"
 #include "fns.h"
 #include "io.h"
+#include "../port/pci.h"
 #include "../port/error.h"
 #include "../port/netif.h"
 #include "../port/etherif.h"
@@ -947,7 +948,7 @@
 {
 	Pcidev *p;
 	Ctlr *ctlr;
-	int cls, port;
+	int port;
 
 	p = nil;
 	while(p = pcimatch(p, 0, 0)){
@@ -962,7 +963,7 @@
 			break;
 		}
 
-		port = p->mem[0].bar & ~0x01;
+		port = p->mem[0].bar & ~3;
 		if(ioalloc(port, p->mem[0].size, 0, "vt6102") < 0){
 			print("vt6102: port 0x%uX in use\n", port);
 			continue;
@@ -977,9 +978,7 @@
 		ctlr->pcidev = p;
 		pcienable(p);
 		ctlr->id = (p->did<<16)|p->vid;
-		if((cls = pcicfgr8(p, PciCLS)) == 0 || cls == 0xFF)
-			cls = 0x10;
-		ctlr->cls = cls*4;
+		ctlr->cls = p->cls*4;
 		ctlr->tft = Ctft64;
 
 		if(vt6102reset(ctlr)){
--- a/sys/src/9/pc/ethervt6105m.c
+++ b/sys/src/9/pc/ethervt6105m.c
@@ -18,6 +18,7 @@
 #include "dat.h"
 #include "fns.h"
 #include "io.h"
+#include "../port/pci.h"
 #include "../port/error.h"
 #include "../port/netif.h"
 #include "../port/etherif.h"
@@ -1112,7 +1113,7 @@
 {
 	Pcidev *p;
 	Ctlr *ctlr;
-	int cls, port;
+	int port;
 
 	p = nil;
 	while(p = pcimatch(p, 0, 0)){
@@ -1126,7 +1127,7 @@
 			break;
 		}
 
-		port = p->mem[0].bar & ~0x01;
+		port = p->mem[0].bar & ~3;
 		if(ioalloc(port, p->mem[0].size, 0, "vt6105M") < 0){
 			print("vt6105M: port 0x%uX in use\n", port);
 			continue;
@@ -1141,9 +1142,7 @@
 		ctlr->pcidev = p;
 		pcienable(p);
 		ctlr->id = (p->did<<16)|p->vid;
-		if((cls = pcicfgr8(p, PciCLS)) == 0 || cls == 0xFF)
-			cls = 0x10;
-		ctlr->cls = cls*4;
+		ctlr->cls = p->cls*4;
 		ctlr->tft = CtftSAF;
 
 		if(vt6105Mreset(ctlr)){
--- a/sys/src/9/pc/etherwavelan.c
+++ b/sys/src/9/pc/etherwavelan.c
@@ -6,6 +6,7 @@
 #include "dat.h"
 #include "fns.h"
 #include "io.h"
+#include "../port/pci.h"
 #include "../port/error.h"
 #include "../port/netif.h"
 #include "../port/etherif.h"
--- a/sys/src/9/pc/etherwpi.c
+++ b/sys/src/9/pc/etherwpi.c
@@ -4,6 +4,7 @@
 #include "dat.h"
 #include "fns.h"
 #include "io.h"
+#include "../port/pci.h"
 #include "../port/error.h"
 #include "../port/netif.h"
 #include "../port/etherif.h"
--- a/sys/src/9/pc/etherx550.c
+++ b/sys/src/9/pc/etherx550.c
@@ -9,6 +9,7 @@
 #include "dat.h"
 #include "fns.h"
 #include "io.h"
+#include "../port/pci.h"
 #include "../port/error.h"
 #include "../port/netif.h"
 #include "../port/etherif.h"
--- a/sys/src/9/pc/etheryuk.c
+++ b/sys/src/9/pc/etheryuk.c
@@ -8,6 +8,7 @@
 #include "dat.h"
 #include "fns.h"
 #include "io.h"
+#include "../port/pci.h"
 #include "../port/error.h"
 #include "../port/netif.h"
 #include "../port/etherif.h"
--- a/sys/src/9/pc/fns.h
+++ b/sys/src/9/pc/fns.h
@@ -125,32 +125,10 @@
 void	outsl(int, void*, int);
 ulong	paddr(void*);
 void	patwc(void*, int);
-ulong	pcibarsize(Pcidev*, int);
-void	pcibussize(Pcidev*, uvlong*, ulong*);
-int	pcicfgr8(Pcidev*, int);
-int	pcicfgr16(Pcidev*, int);
-int	pcicfgr32(Pcidev*, int);
-void	pcicfgw8(Pcidev*, int, int);
-void	pcicfgw16(Pcidev*, int, int);
-void	pcicfgw32(Pcidev*, int, int);
-void	pciclrbme(Pcidev*);
-void	pciclrioe(Pcidev*);
-void	pciclrmwi(Pcidev*);
-int	pcigetpms(Pcidev*);
-void	pcihinv(Pcidev*);
-uchar	pciipin(Pcidev*, uchar);
-Pcidev* pcimatch(Pcidev*, int, int);
-Pcidev* pcimatchtbdf(int);
-int	pcicap(Pcidev*, int);
-int	pcihtcap(Pcidev*, int);
-void	pcireset(void);
-int	pciscan(int, Pcidev**);
-void	pcisetbme(Pcidev*);
-void	pcisetioe(Pcidev*);
-void	pcisetmwi(Pcidev*);
-int	pcisetpms(Pcidev*, int);
-void	pcienable(Pcidev*);
-void	pcidisable(Pcidev*);
+void	pcicfginit(void);
+int	(*pcicfgrw8)(int, int, int, int);
+int	(*pcicfgrw16)(int, int, int, int);
+int	(*pcicfgrw32)(int, int, int, int);
 void	pcmcisread(PCMslot*);
 int	pcmcistuple(int, int, int, void*, int);
 PCMmap*	pcmmap(int, ulong, int, int);
@@ -193,6 +171,7 @@
 ulong	umballoc(ulong, ulong, ulong);
 void	umbfree(ulong, ulong);
 uvlong	upaalloc(uvlong, ulong, ulong);
+uvlong	upaallocwin(uvlong, ulong, ulong, ulong);
 void	upafree(uvlong, ulong);
 void	vectortable(void);
 void*	vmap(uvlong, int);
--- a/sys/src/9/pc/io.h
+++ b/sys/src/9/pc/io.h
@@ -60,229 +60,17 @@
 } Vctl;
 
 enum {
-	BusCBUS		= 0,		/* Corollary CBUS */
-	BusCBUSII,			/* Corollary CBUS II */
-	BusEISA,			/* Extended ISA */
-	BusFUTURE,			/* IEEE Futurebus */
-	BusINTERN,			/* Internal bus */
-	BusISA,				/* Industry Standard Architecture */
-	BusMBI,				/* Multibus I */
-	BusMBII,			/* Multibus II */
-	BusMCA,				/* Micro Channel Architecture */
-	BusMPI,				/* MPI */
-	BusMPSA,			/* MPSA */
-	BusNUBUS,			/* Apple Macintosh NuBus */
-	BusPCI,				/* Peripheral Component Interconnect */
-	BusPCMCIA,			/* PC Memory Card International Association */
-	BusTC,				/* DEC TurboChannel */
-	BusVL,				/* VESA Local bus */
-	BusVME,				/* VMEbus */
-	BusXPRESS,			/* Express System Bus */
-};
-
-#define MKBUS(t,b,d,f)	(((t)<<24)|(((b)&0xFF)<<16)|(((d)&0x1F)<<11)|(((f)&0x07)<<8))
-#define BUSFNO(tbdf)	(((tbdf)>>8)&0x07)
-#define BUSDNO(tbdf)	(((tbdf)>>11)&0x1F)
-#define BUSBNO(tbdf)	(((tbdf)>>16)&0xFF)
-#define BUSTYPE(tbdf)	((tbdf)>>24)
-#define BUSBDF(tbdf)	((tbdf)&0x00FFFF00)
-#define BUSUNKNOWN	(-1)
-
-enum {
 	MaxEISA		= 16,
 	CfgEISA		= 0xC80,
 };
 
-/*
- * PCI support code.
- */
-enum {					/* type 0 & type 1 pre-defined header */
-	PciVID		= 0x00,		/* vendor ID */
-	PciDID		= 0x02,		/* device ID */
-	PciPCR		= 0x04,		/* command */
-	PciPSR		= 0x06,		/* status */
-	PciRID		= 0x08,		/* revision ID */
-	PciCCRp		= 0x09,		/* programming interface class code */
-	PciCCRu		= 0x0A,		/* sub-class code */
-	PciCCRb		= 0x0B,		/* base class code */
-	PciCLS		= 0x0C,		/* cache line size */
-	PciLTR		= 0x0D,		/* latency timer */
-	PciHDT		= 0x0E,		/* header type */
-	PciBST		= 0x0F,		/* BIST */
-
-	PciBAR0		= 0x10,		/* base address */
-	PciBAR1		= 0x14,
-
-	PciCAP		= 0x34,		/* capabilities pointer */
-	PciINTL		= 0x3C,		/* interrupt line */
-	PciINTP		= 0x3D,		/* interrupt pin */
-};
-
-/* ccrb (base class code) values; controller types */
-enum {
-	Pcibcpci1	= 0,		/* pci 1.0; no class codes defined */
-	Pcibcstore	= 1,		/* mass storage */
-	Pcibcnet	= 2,		/* network */
-	Pcibcdisp	= 3,		/* display */
-	Pcibcmmedia	= 4,		/* multimedia */
-	Pcibcmem	= 5,		/* memory */
-	Pcibcbridge	= 6,		/* bridge */
-	Pcibccomm	= 7,		/* simple comms (e.g., serial) */
-	Pcibcbasesys	= 8,		/* base system */
-	Pcibcinput	= 9,		/* input */
-	Pcibcdock	= 0xa,		/* docking stations */
-	Pcibcproc	= 0xb,		/* processors */
-	Pcibcserial	= 0xc,		/* serial bus (e.g., USB) */
-	Pcibcwireless	= 0xd,		/* wireless */
-	Pcibcintell	= 0xe,		/* intelligent i/o */
-	Pcibcsatcom	= 0xf,		/* satellite comms */
-	Pcibccrypto	= 0x10,		/* encryption/decryption */
-	Pcibcdacq	= 0x11,		/* data acquisition & signal proc. */
-};
-
-/* ccru (sub-class code) values; common cases only */
-enum {
-	/* mass storage */
-	Pciscscsi	= 0,		/* SCSI */
-	Pciscide	= 1,		/* IDE (ATA) */
-
-	/* network */
-	Pciscether	= 0,		/* Ethernet */
-
-	/* display */
-	Pciscvga	= 0,		/* VGA */
-	Pciscxga	= 1,		/* XGA */
-	Pcisc3d		= 2,		/* 3D */
-
-	/* bridges */
-	Pcischostpci	= 0,		/* host/pci */
-	Pciscpcicpci	= 1,		/* pci/pci */
-
-	/* simple comms */
-	Pciscserial	= 0,		/* 16450, etc. */
-	Pciscmultiser	= 1,		/* multiport serial */
-
-	/* serial bus */
-	Pciscusb	= 3,		/* USB */
-};
-
-enum {					/* type 0 pre-defined header */
-	PciCIS		= 0x28,		/* cardbus CIS pointer */
-	PciSVID		= 0x2C,		/* subsystem vendor ID */
-	PciSID		= 0x2E,		/* subsystem ID */
-	PciEBAR0	= 0x30,		/* expansion ROM base address */
-	PciMGNT		= 0x3E,		/* burst period length */
-	PciMLT		= 0x3F,		/* maximum latency between bursts */
-};
-
-enum {					/* type 1 pre-defined header */
-	PciPBN		= 0x18,		/* primary bus number */
-	PciSBN		= 0x19,		/* secondary bus number */
-	PciUBN		= 0x1A,		/* subordinate bus number */
-	PciSLTR		= 0x1B,		/* secondary latency timer */
-	PciIBR		= 0x1C,		/* I/O base */
-	PciILR		= 0x1D,		/* I/O limit */
-	PciSPSR		= 0x1E,		/* secondary status */
-	PciMBR		= 0x20,		/* memory base */
-	PciMLR		= 0x22,		/* memory limit */
-	PciPMBR		= 0x24,		/* prefetchable memory base */
-	PciPMLR		= 0x26,		/* prefetchable memory limit */
-	PciPUBR		= 0x28,		/* prefetchable base upper 32 bits */
-	PciPULR		= 0x2C,		/* prefetchable limit upper 32 bits */
-	PciIUBR		= 0x30,		/* I/O base upper 16 bits */
-	PciIULR		= 0x32,		/* I/O limit upper 16 bits */
-	PciEBAR1	= 0x28,		/* expansion ROM base address */
-	PciBCR		= 0x3E,		/* bridge control register */
-};
-
-enum {					/* type 2 pre-defined header */
-	PciCBExCA	= 0x10,
-	PciCBSPSR	= 0x16,
-	PciCBPBN	= 0x18,		/* primary bus number */
-	PciCBSBN	= 0x19,		/* secondary bus number */
-	PciCBUBN	= 0x1A,		/* subordinate bus number */
-	PciCBSLTR	= 0x1B,		/* secondary latency timer */
-	PciCBMBR0	= 0x1C,
-	PciCBMLR0	= 0x20,
-	PciCBMBR1	= 0x24,
-	PciCBMLR1	= 0x28,
-	PciCBIBR0	= 0x2C,		/* I/O base */
-	PciCBILR0	= 0x30,		/* I/O limit */
-	PciCBIBR1	= 0x34,		/* I/O base */
-	PciCBILR1	= 0x38,		/* I/O limit */
-	PciCBSVID	= 0x40,		/* subsystem vendor ID */
-	PciCBSID	= 0x42,		/* subsystem ID */
-	PciCBLMBAR	= 0x44,		/* legacy mode base address */
-};
-
-/* capabilities */
-enum {
-	PciCapPMG       = 0x01,         /* power management */
-	PciCapAGP       = 0x02,
-	PciCapVPD       = 0x03,         /* vital product data */
-	PciCapSID       = 0x04,         /* slot id */
-	PciCapMSI       = 0x05,
-	PciCapCHS       = 0x06,         /* compact pci hot swap */
-	PciCapPCIX      = 0x07,
-	PciCapHTC       = 0x08,         /* hypertransport irq conf */
-	PciCapVND       = 0x09,         /* vendor specific information */
-	PciCapPCIe      = 0x10,
-	PciCapMSIX      = 0x11,
-	PciCapSATA      = 0x12,
-	PciCapHSW       = 0x0c,         /* hot swap */
-};
-
-typedef struct Pcidev Pcidev;
-struct Pcidev
-{
-	int	tbdf;			/* type+bus+device+function */
-	ushort	vid;			/* vendor ID */
-	ushort	did;			/* device ID */
-
-	ushort	pcr;
-
-	uchar	rid;
-	uchar	ccrp;
-	uchar	ccru;
-	uchar	ccrb;
-	uchar	cls;
-	uchar	ltr;
-
-	struct {
-		uvlong	bar;		/* base address */
-		int	size;
-	} mem[6];
-
-	struct {
-		uvlong	bar;	
-		int	size;
-	} rom;
-	uchar	intl;			/* interrupt line */
-
-	Pcidev*	list;
-	Pcidev*	link;			/* next device on this bno */
-
-	Pcidev*	parent;			/* up a bus */
-	Pcidev*	bridge;			/* down a bus */
-	struct {
-		uvlong	bar;
-		int	size;
-	} ioa, mema;
-
-	int	pmrb;			/* power management register block */
-};
-
-enum {
-	/* vendor ids */
-	Vintel	= 0x8086,
-	Vmyricom= 0x14c1,
-};
-
 #define PCIWINDOW	0
 #define PCIWADDR(va)	(PADDR(va)+PCIWINDOW)
 #define ISAWINDOW	0
 #define ISAWADDR(va)	(PADDR(va)+ISAWINDOW)
 
+#define	BUSUNKNOWN	(-1)
+
 /* SMBus transactions */
 enum
 {
@@ -387,6 +175,3 @@
 	int	time;
 	PCMmap	mmap[4];	/* maps, last is always for the kernel */
 };
-
-#pragma varargck	type	"T"	int
-#pragma varargck	type	"T"	uint
--- a/sys/src/9/pc/main.c
+++ b/sys/src/9/pc/main.c
@@ -40,6 +40,7 @@
 	ramdiskinit();
 	confinit();
 	xinit();
+	pcicfginit();
 	bootscreeninit();
 	if(i8237alloc != nil)
 		i8237alloc();
@@ -57,7 +58,6 @@
 	initseg();
 	if(delaylink){
 		bootlinks();
-		pcimatch(0, 0, 0);
 	}else
 		links();
 	chandevreset();
--- a/sys/src/9/pc/memory.c
+++ b/sys/src/9/pc/memory.c
@@ -250,6 +250,24 @@
 	return memmapalloc(pa, size, align, MemUPA);
 }
 
+uvlong
+upaallocwin(uvlong pa, ulong win, ulong size, ulong align)
+{
+	uvlong a, base, top = pa + win;
+
+	for(base = memmapnext(-1, MemUPA); base != -1 && base < top; base = memmapnext(base, MemUPA)){
+		if(base < pa){
+			if(pa >= base + memmapsize(base, 0))
+				continue;
+			base = pa;
+		}
+		a = upaalloc(base, size, align);
+		if(a != -1)
+			return a;
+	}
+	return -1ULL;
+}
+
 void
 upafree(uvlong pa, ulong size)
 {
--- a/sys/src/9/pc/mp.c
+++ b/sys/src/9/pc/mp.c
@@ -4,6 +4,7 @@
 #include "dat.h"
 #include "fns.h"
 #include "io.h"
+#include "../port/pci.h"
 #include "ureg.h"
 
 #include "mp.h"
--- a/sys/src/9/pc/pc
+++ b/sys/src/9/pc/pc
@@ -27,7 +27,7 @@
 	draw		screen vga vgax vgasoft
 	mouse		mouse
 	kbd
-	vga
+	vga		pci
 
 	sd
 	floppy		dma
@@ -35,7 +35,7 @@
 	lpt
 
 	audio		dma
-	pccard
+	pccard		pci
 	i82365		cis
 	uart
 	usb
@@ -45,11 +45,11 @@
 
 link
 	segdesc
-	devpccard
+	devpccard	pci
 	devi82365
-	cputemp
+	cputemp		pci
 	apm		apmjump
-	ether2000	ether8390
+	ether2000	pci ether8390
 	ether2114x	pci
 	ether589	etherelnk3
 	ether79c970	pci
@@ -73,7 +73,7 @@
 	ethervt6102	pci ethermii
 	ethervt6105m	pci ethermii
 	ethersink
-	ethersmc	devi82365 cis
+	ethersmc	pci devi82365 cis
 	etheryuk	pci
 	etherwavelan	wavelan devi82365 cis pci
 	etheriwl	pci wifi
@@ -84,16 +84,18 @@
 	pcmciamodem
 	netdevmedium
 	loopbackmedium
-	usbuhci
-	usbohci
+	usbuhci		pci
+	usbohci		pci
 	usbehci		usbehcipc
 	usbxhci		pci
 
 	audiosb16	dma
-	audioac97	audioac97mix
-	audiohda
+	audioac97	pci audioac97mix
+	audiohda	pci
 
 misc
+	pci		pcipc
+
 	archacpi	mp apic squidboy ec
 	archmp		mp apic squidboy
 	mtrr
--- a/sys/src/9/pc/pci.c
+++ /dev/null
@@ -1,1647 +1,0 @@
-/*
- * PCI support code.
- * Needs a massive rewrite.
- */
-#include "u.h"
-#include "../port/lib.h"
-#include "mem.h"
-#include "dat.h"
-#include "fns.h"
-#include "io.h"
-#include "../port/error.h"
-
-#define DBG	if(0) print
-
-enum
-{					/* configuration mechanism #1 */
-	PciADDR		= 0xCF8,	/* CONFIG_ADDRESS */
-	PciDATA		= 0xCFC,	/* CONFIG_DATA */
-
-					/* configuration mechanism #2 */
-	PciCSE		= 0xCF8,	/* configuration space enable */
-	PciFORWARD	= 0xCFA,	/* which bus */
-
-	MaxFNO		= 7,
-	MaxUBN		= 255,
-};
-
-enum
-{					/* command register */
-	IOen		= (1<<0),
-	MEMen		= (1<<1),
-	MASen		= (1<<2),
-	MemWrInv	= (1<<4),
-	PErrEn		= (1<<6),
-	SErrEn		= (1<<8),
-};
-
-typedef struct Pcisiz Pcisiz;
-struct Pcisiz
-{
-	Pcidev*	dev;
-	int	siz;
-	int	bar;
-	int	typ;
-};
-
-static Lock pcicfglock;
-static Lock pcicfginitlock;
-static int pcicfgmode = -1;
-static int pcimaxbno = 255;
-static int pcimaxdno;
-static Pcidev* pciroot;
-static Pcidev* pcilist;
-static Pcidev* pcitail;
-static int nobios, nopcirouting;
-static BIOS32si* pcibiossi;
-
-static int pcicfgrw8raw(int, int, int, int);
-static int pcicfgrw16raw(int, int, int, int);
-static int pcicfgrw32raw(int, int, int, int);
-
-static int (*pcicfgrw8)(int, int, int, int) = pcicfgrw8raw;
-static int (*pcicfgrw16)(int, int, int, int) = pcicfgrw16raw;
-static int (*pcicfgrw32)(int, int, int, int) = pcicfgrw32raw;
-
-static char* bustypes[] = {
-	"CBUSI",
-	"CBUSII",
-	"EISA",
-	"FUTURE",
-	"INTERN",
-	"ISA",
-	"MBI",
-	"MBII",
-	"MCA",
-	"MPI",
-	"MPSA",
-	"NUBUS",
-	"PCI",
-	"PCMCIA",
-	"TC",
-	"VL",
-	"VME",
-	"XPRESS",
-};
-
-static int
-tbdffmt(Fmt* fmt)
-{
-	char *p;
-	int l, r;
-	uint type, tbdf;
-
-	if((p = malloc(READSTR)) == nil)
-		return fmtstrcpy(fmt, "(tbdfconv)");
-
-	switch(fmt->r){
-	case 'T':
-		tbdf = va_arg(fmt->args, int);
-		if(tbdf == BUSUNKNOWN)
-			snprint(p, READSTR, "unknown");
-		else{
-			type = BUSTYPE(tbdf);
-			if(type < nelem(bustypes))
-				l = snprint(p, READSTR, bustypes[type]);
-			else
-				l = snprint(p, READSTR, "%d", type);
-			snprint(p+l, READSTR-l, ".%d.%d.%d",
-				BUSBNO(tbdf), BUSDNO(tbdf), BUSFNO(tbdf));
-		}
-		break;
-
-	default:
-		snprint(p, READSTR, "(tbdfconv)");
-		break;
-	}
-	r = fmtstrcpy(fmt, p);
-	free(p);
-
-	return r;
-}
-
-ulong
-pcibarsize(Pcidev *p, int rno)
-{
-	ulong v, size;
-
-	v = pcicfgrw32(p->tbdf, rno, 0, 1);
-	pcicfgrw32(p->tbdf, rno, 0xFFFFFFF0, 0);
-	size = pcicfgrw32(p->tbdf, rno, 0, 1);
-	if(v & 1)
-		size |= 0xFFFF0000;
-	pcicfgrw32(p->tbdf, rno, v, 0);
-
-	return -(size & ~0x0F);
-}
-
-static int
-pcisizcmp(void *a, void *b)
-{
-	Pcisiz *aa, *bb;
-
-	aa = a;
-	bb = b;
-	return aa->siz - bb->siz;
-}
-
-static ulong
-pcimask(ulong v)
-{
-	ulong m;
-
-	m = BI2BY*sizeof(v);
-	for(m = 1<<(m-1); m != 0; m >>= 1) {
-		if(m & v)
-			break;
-	}
-
-	m--;
-	if((v & m) == 0)
-		return v;
-
-	v |= m;
-	return v+1;
-}
-
-static void
-pcibusmap(Pcidev *root, uvlong *pmema, ulong *pioa, int wrreg)
-{
-	Pcidev *p;
-	int ntb, i, size, rno, hole;
-	uvlong mema, smema, base, limit;
-	ulong ioa, sioa, v;
-	Pcisiz *table, *tptr, *mtb, *itb;
-
-	if(!nobios)
-		return;
-
-	ioa = *pioa;
-	mema = *pmema;
-
-	DBG("pcibusmap wr=%d %T mem=%lluX io=%luX\n",
-		wrreg, root->tbdf, mema, ioa);
-
-	ntb = 0;
-	for(p = root; p != nil; p = p->link)
-		ntb++;
-
-	ntb *= (PciCIS-PciBAR0)/4;
-	table = malloc(2*ntb*sizeof(Pcisiz));
-	if(table == nil)
-		panic("pcibusmap: can't allocate memory");
-	itb = table;
-	mtb = table+ntb;
-
-	/*
-	 * Build a table of sizes
-	 */
-	for(p = root; p != nil; p = p->link) {
-		if(p->ccrb == 0x06) {
-			if(p->ccru != 0x04 || p->bridge == nil) {
-				DBG("pci: ignored bridge %T\n", p->tbdf);
-				continue;
-			}
-
-			sioa = ioa;
-			smema = mema;
-			pcibusmap(p->bridge, &smema, &sioa, 0);
-
-			hole = pcimask(smema-mema);
-			if(hole < (1<<20))
-				hole = 1<<20;
-			p->mema.size = hole;
-
-			hole = pcimask(sioa-ioa);
-			if(hole < (1<<12))
-				hole = 1<<12;
-
-			p->ioa.size = hole;
-
-			itb->dev = p;
-			itb->bar = -1;
-			itb->siz = p->ioa.size;
-			itb->typ = 0;
-			itb++;
-
-			mtb->dev = p;
-			mtb->bar = -1;
-			mtb->siz = p->mema.size;
-			mtb->typ = 0;
-			mtb++;
-			continue;
-		}
-
-		for(i = 0; i < nelem(p->mem); i++) {
-			rno = PciBAR0 + i*4;
-			v = pcicfgrw32(p->tbdf, rno, 0, 1);
-			size = pcibarsize(p, rno);
-			if(size == 0)
-				continue;
-
-			p->mem[i].size = size;
-			if(v & 1) {
-				itb->dev = p;
-				itb->bar = i;
-				itb->siz = size;
-				itb->typ = 1;
-				itb++;
-			}
-			else {
-				mtb->dev = p;
-				mtb->bar = i;
-				mtb->siz = size;
-				mtb->typ = v & 7;
-				if(mtb->typ & 4)
-					i++;
-				mtb++;
-			}
-		}
-	}
-
-	/*
-	 * Sort both tables IO smallest first, Memory largest
-	 */
-	qsort(table, itb-table, sizeof(Pcisiz), pcisizcmp);
-	tptr = table+ntb;
-	qsort(tptr, mtb-tptr, sizeof(Pcisiz), pcisizcmp);
-
-	/*
-	 * Allocate IO address space on this bus
-	 */
-	for(tptr = table; tptr < itb; tptr++) {
-		hole = tptr->siz;
-		if(tptr->bar == -1)
-			hole = 1<<12;
-		ioa = (ioa+hole-1) & ~(hole-1);
-
-		p = tptr->dev;
-		if(tptr->bar == -1)
-			p->ioa.bar = ioa;
-		else {
-			p->pcr |= IOen;
-			p->mem[tptr->bar].bar = ioa|1;
-			if(wrreg)
-				pcicfgrw32(p->tbdf, PciBAR0+(tptr->bar*4), ioa|1, 0);
-		}
-
-		ioa += tptr->siz;
-	}
-
-	/*
-	 * Allocate Memory address space on this bus
-	 */
-	for(tptr = table+ntb; tptr < mtb; tptr++) {
-		hole = tptr->siz;
-		if(tptr->bar == -1)
-			hole = 1<<20;
-		mema = (mema+hole-1) & ~((uvlong)hole-1);
-
-		p = tptr->dev;
-		if(tptr->bar == -1)
-			p->mema.bar = mema;
-		else {
-			p->pcr |= MEMen;
-			p->mem[tptr->bar].bar = mema|tptr->typ;
-			if(wrreg){
-				rno = PciBAR0+(tptr->bar*4);
-				pcicfgrw32(p->tbdf, rno, mema|tptr->typ, 0);
-				if(tptr->bar < nelem(p->mem)-1 && (tptr->typ & 4) != 0){
-					p->mem[tptr->bar+1].bar = 0;
-					p->mem[tptr->bar+1].size = 0;
-					pcicfgrw32(p->tbdf, rno+4, mema>>32, 0);
-				}
-			}
-		}
-		mema += tptr->siz;
-	}
-
-	*pmema = mema;
-	*pioa = ioa;
-	free(table);
-
-	if(wrreg == 0)
-		return;
-
-	/*
-	 * Finally set all the bridge addresses & registers
-	 */
-	for(p = root; p != nil; p = p->link) {
-		if(p->bridge == nil) {
-			pcicfgrw8(p->tbdf, PciLTR, 64, 0);
-
-			p->pcr |= MASen;
-			pcicfgrw16(p->tbdf, PciPCR, p->pcr, 0);
-			continue;
-		}
-
-		base = p->ioa.bar;
-		limit = base+p->ioa.size-1;
-		v = pcicfgrw32(p->tbdf, PciIBR, 0, 1);
-		v = (v&0xFFFF0000)|(limit & 0xF000)|((base & 0xF000)>>8);
-		pcicfgrw32(p->tbdf, PciIBR, v, 0);
-		v = (limit & 0xFFFF0000)|(base>>16);
-		pcicfgrw32(p->tbdf, PciIUBR, v, 0);
-
-		base = p->mema.bar;
-		limit = base+p->mema.size-1;
-		v = (limit & 0xFFF00000)|((base & 0xFFF00000)>>16);
-		pcicfgrw32(p->tbdf, PciMBR, v, 0);
-
-		/*
-		 * Disable memory prefetch
-		 */
-		pcicfgrw32(p->tbdf, PciPMBR, 0x0000FFFF, 0);
-		pcicfgrw8(p->tbdf, PciLTR, 64, 0);
-
-		/*
-		 * Enable the bridge
-		 */
-		p->pcr |= IOen|MEMen|MASen;
-		pcicfgrw32(p->tbdf, PciPCR, 0xFFFF0000|p->pcr , 0);
-
-		sioa = p->ioa.bar;
-		smema = p->mema.bar;
-		pcibusmap(p->bridge, &smema, &sioa, 1);
-	}
-}
-
-static int
-pcilscan(int bno, Pcidev** list, Pcidev *parent)
-{
-	Pcidev *p, *head, *tail;
-	int dno, fno, i, hdt, l, maxfno, maxubn, rno, sbn, tbdf, ubn;
-
-	maxubn = bno;
-	head = nil;
-	tail = nil;
-	for(dno = 0; dno <= pcimaxdno; dno++){
-		maxfno = 0;
-		for(fno = 0; fno <= maxfno; fno++){
-			/*
-			 * For this possible device, form the
-			 * bus+device+function triplet needed to address it
-			 * and try to read the vendor and device ID.
-			 * If successful, allocate a device struct and
-			 * start to fill it in with some useful information
-			 * from the device's configuration space.
-			 */
-			tbdf = MKBUS(BusPCI, bno, dno, fno);
-			l = pcicfgrw32(tbdf, PciVID, 0, 1);
-			if(l == 0xFFFFFFFF || l == 0)
-				continue;
-			p = malloc(sizeof(*p));
-			if(p == nil)
-				panic("pcilscan: can't allocate memory");
-			p->tbdf = tbdf;
-			p->vid = l;
-			p->did = l>>16;
-
-			if(pcilist != nil)
-				pcitail->list = p;
-			else
-				pcilist = p;
-			pcitail = p;
-
-			p->pcr = pcicfgr16(p, PciPCR);
-			p->rid = pcicfgr8(p, PciRID);
-			p->ccrp = pcicfgr8(p, PciCCRp);
-			p->ccru = pcicfgr8(p, PciCCRu);
-			p->ccrb = pcicfgr8(p, PciCCRb);
-			p->cls = pcicfgr8(p, PciCLS);
-			p->ltr = pcicfgr8(p, PciLTR);
-
-			p->intl = pcicfgr8(p, PciINTL);
-
-			/*
-			 * If the device is a multi-function device adjust the
-			 * loop count so all possible functions are checked.
-			 */
-			hdt = pcicfgr8(p, PciHDT);
-			if(hdt & 0x80)
-				maxfno = MaxFNO;
-
-			/*
-			 * If appropriate, read the base address registers
-			 * and work out the sizes.
-			 */
-			switch(p->ccrb) {
-			case 0x00:		/* prehistoric */
-			case 0x01:		/* mass storage controller */
-			case 0x02:		/* network controller */
-			case 0x03:		/* display controller */
-			case 0x04:		/* multimedia device */
-			case 0x07:		/* simple comm. controllers */
-			case 0x08:		/* base system peripherals */
-			case 0x09:		/* input devices */
-			case 0x0A:		/* docking stations */
-			case 0x0B:		/* processors */
-			case 0x0C:		/* serial bus controllers */
-			case 0x0D:		/* wireless controllers */
-			case 0x0E:		/* intelligent I/O controllers */
-			case 0x0F:		/* sattelite communication controllers */
-			case 0x10:		/* encryption/decryption controllers */
-			case 0x11:		/* signal processing controllers */
-				if((hdt & 0x7F) != 0)
-					break;
-				rno = PciBAR0;
-				for(i = 0; i < nelem(p->mem); i++) {
-					p->mem[i].bar = (ulong)pcicfgr32(p, rno);
-					p->mem[i].size = pcibarsize(p, rno);
-					if((p->mem[i].bar & 7) == 4 && i < nelem(p->mem)-1){
-						rno += 4;
-						p->mem[i++].bar |= (uvlong)pcicfgr32(p, rno) << 32;
-						p->mem[i].bar = 0;
-						p->mem[i].size = 0;
-					}
-					rno += 4;
-				}
-				break;
-
-			case 0x05:		/* memory controller */
-			case 0x06:		/* bridge device */
-			default:
-				break;
-			}
-
-			p->parent = parent;
-			if(head != nil)
-				tail->link = p;
-			else
-				head = p;
-			tail = p;
-		}
-	}
-
-	*list = head;
-	for(p = head; p != nil; p = p->link){
-		/*
-		 * Find PCI-PCI bridges and recursively descend the tree.
-		 */
-		if(p->ccrb != 0x06 || p->ccru != 0x04)
-			continue;
-
-		/*
-		 * If the secondary or subordinate bus number is not
-		 * initialised try to do what the PCI BIOS should have
-		 * done and fill in the numbers as the tree is descended.
-		 * On the way down the subordinate bus number is set to
-		 * the maximum as it's not known how many buses are behind
-		 * this one; the final value is set on the way back up.
-		 */
-		sbn = pcicfgr8(p, PciSBN);
-		ubn = pcicfgr8(p, PciUBN);
-
-		if(sbn == 0 || ubn == 0 || nobios) {
-			sbn = maxubn+1;
-			/*
-			 * Make sure memory, I/O and master enables are
-			 * off, set the primary, secondary and subordinate
-			 * bus numbers and clear the secondary status before
-			 * attempting to scan the secondary bus.
-			 *
-			 * Initialisation of the bridge should be done here.
-			 */
-			pcicfgw32(p, PciPCR, 0xFFFF0000);
-			l = (MaxUBN<<16)|(sbn<<8)|bno;
-			pcicfgw32(p, PciPBN, l);
-			pcicfgw16(p, PciSPSR, 0xFFFF);
-			maxubn = pcilscan(sbn, &p->bridge, p);
-			l = (maxubn<<16)|(sbn<<8)|bno;
-
-			pcicfgw32(p, PciPBN, l);
-		}
-		else {
-			if(ubn > maxubn)
-				maxubn = ubn;
-			pcilscan(sbn, &p->bridge, p);
-		}
-	}
-
-	return maxubn;
-}
-
-int
-pciscan(int bno, Pcidev **list)
-{
-	int ubn;
-
-	lock(&pcicfginitlock);
-	ubn = pcilscan(bno, list, nil);
-	unlock(&pcicfginitlock);
-	return ubn;
-}
-
-static uchar
-pIIxget(Pcidev *router, uchar link)
-{
-	uchar pirq;
-
-	/* link should be 0x60, 0x61, 0x62, 0x63 */
-	pirq = pcicfgr8(router, link);
-	return (pirq < 16)? pirq: 0;
-}
-
-static void
-pIIxset(Pcidev *router, uchar link, uchar irq)
-{
-	pcicfgw8(router, link, irq);
-}
-
-static uchar
-viaget(Pcidev *router, uchar link)
-{
-	uchar pirq;
-
-	/* link should be 1, 2, 3, 5 */
-	pirq = (link < 6)? pcicfgr8(router, 0x55 + (link>>1)): 0;
-
-	return (link & 1)? (pirq >> 4): (pirq & 15);
-}
-
-static void
-viaset(Pcidev *router, uchar link, uchar irq)
-{
-	uchar pirq;
-
-	pirq = pcicfgr8(router, 0x55 + (link >> 1));
-	pirq &= (link & 1)? 0x0f: 0xf0;
-	pirq |= (link & 1)? (irq << 4): (irq & 15);
-	pcicfgw8(router, 0x55 + (link>>1), pirq);
-}
-
-static uchar
-optiget(Pcidev *router, uchar link)
-{
-	uchar pirq = 0;
-
-	/* link should be 0x02, 0x12, 0x22, 0x32 */
-	if ((link & 0xcf) == 0x02)
-		pirq = pcicfgr8(router, 0xb8 + (link >> 5));
-	return (link & 0x10)? (pirq >> 4): (pirq & 15);
-}
-
-static void
-optiset(Pcidev *router, uchar link, uchar irq)
-{
-	uchar pirq;
-
-	pirq = pcicfgr8(router, 0xb8 + (link >> 5));
-    	pirq &= (link & 0x10)? 0x0f : 0xf0;
-    	pirq |= (link & 0x10)? (irq << 4): (irq & 15);
-	pcicfgw8(router, 0xb8 + (link >> 5), pirq);
-}
-
-static uchar
-aliget(Pcidev *router, uchar link)
-{
-	/* No, you're not dreaming */
-	static const uchar map[] = { 0, 9, 3, 10, 4, 5, 7, 6, 1, 11, 0, 12, 0, 14, 0, 15 };
-	uchar pirq;
-
-	/* link should be 0x01..0x08 */
-	pirq = pcicfgr8(router, 0x48 + ((link-1)>>1));
-	return (link & 1)? map[pirq&15]: map[pirq>>4];
-}
-
-static void
-aliset(Pcidev *router, uchar link, uchar irq)
-{
-	/* Inverse of map in aliget */
-	static const uchar map[] = { 0, 8, 0, 2, 4, 5, 7, 6, 0, 1, 3, 9, 11, 0, 13, 15 };
-	uchar pirq;
-
-	pirq = pcicfgr8(router, 0x48 + ((link-1)>>1));
-	pirq &= (link & 1)? 0x0f: 0xf0;
-	pirq |= (link & 1)? (map[irq] << 4): (map[irq] & 15);
-	pcicfgw8(router, 0x48 + ((link-1)>>1), pirq);
-}
-
-static uchar
-cyrixget(Pcidev *router, uchar link)
-{
-	uchar pirq;
-
-	/* link should be 1, 2, 3, 4 */
-	pirq = pcicfgr8(router, 0x5c + ((link-1)>>1));
-	return ((link & 1)? pirq >> 4: pirq & 15);
-}
-
-static void
-cyrixset(Pcidev *router, uchar link, uchar irq)
-{
-	uchar pirq;
-
-	pirq = pcicfgr8(router, 0x5c + (link>>1));
-	pirq &= (link & 1)? 0x0f: 0xf0;
-	pirq |= (link & 1)? (irq << 4): (irq & 15);
-	pcicfgw8(router, 0x5c + (link>>1), pirq);
-}
-
-typedef struct Bridge Bridge;
-struct Bridge
-{
-	ushort	vid;
-	ushort	did;
-	uchar	(*get)(Pcidev *, uchar);
-	void	(*set)(Pcidev *, uchar, uchar);
-};
-
-static Bridge southbridges[] = {
-	{ 0x8086, 0x122e, pIIxget, pIIxset },	/* Intel 82371FB */
-	{ 0x8086, 0x1234, pIIxget, pIIxset },	/* Intel 82371MX */
-	{ 0x8086, 0x7000, pIIxget, pIIxset },	/* Intel 82371SB */
-	{ 0x8086, 0x7110, pIIxget, pIIxset },	/* Intel 82371AB */
-	{ 0x8086, 0x7198, pIIxget, pIIxset },	/* Intel 82443MX (fn 1) */
-	{ 0x8086, 0x2410, pIIxget, pIIxset },	/* Intel 82801AA */
-	{ 0x8086, 0x2420, pIIxget, pIIxset },	/* Intel 82801AB */
-	{ 0x8086, 0x2440, pIIxget, pIIxset },	/* Intel 82801BA */
-	{ 0x8086, 0x2448, pIIxget, pIIxset },	/* Intel 82801BAM/CAM/DBM */
-	{ 0x8086, 0x244c, pIIxget, pIIxset },	/* Intel 82801BAM */
-	{ 0x8086, 0x244e, pIIxget, pIIxset },	/* Intel 82801 */
-	{ 0x8086, 0x2480, pIIxget, pIIxset },	/* Intel 82801CA */
-	{ 0x8086, 0x248c, pIIxget, pIIxset },	/* Intel 82801CAM */
-	{ 0x8086, 0x24c0, pIIxget, pIIxset },	/* Intel 82801DBL */
-	{ 0x8086, 0x24cc, pIIxget, pIIxset },	/* Intel 82801DBM */
-	{ 0x8086, 0x24d0, pIIxget, pIIxset },	/* Intel 82801EB */
-	{ 0x8086, 0x25a1, pIIxget, pIIxset },	/* Intel 6300ESB */
-	{ 0x8086, 0x2640, pIIxget, pIIxset },	/* Intel 82801FB */
-	{ 0x8086, 0x2641, pIIxget, pIIxset },	/* Intel 82801FBM */
-	{ 0x8086, 0x2670, pIIxget, pIIxset },	/* Intel 632xesb */
-	{ 0x8086, 0x27b8, pIIxget, pIIxset },	/* Intel 82801GB */
-	{ 0x8086, 0x27b9, pIIxget, pIIxset },	/* Intel 82801GBM */
-	{ 0x8086, 0x27bd, pIIxget, pIIxset },	/* Intel 82801GB/GR */
-	{ 0x8086, 0x3a16, pIIxget, pIIxset },	/* Intel 82801JIR */
-	{ 0x8086, 0x3a40, pIIxget, pIIxset },	/* Intel 82801JI */
-	{ 0x8086, 0x3a42, pIIxget, pIIxset },	/* Intel 82801JI */
-	{ 0x8086, 0x3a48, pIIxget, pIIxset },	/* Intel 82801JI */
-	{ 0x8086, 0x2916, pIIxget, pIIxset },	/* Intel 82801? */
-	{ 0x8086, 0x1c02, pIIxget, pIIxset },	/* Intel 6 Series/C200 */
-	{ 0x8086, 0x1e53, pIIxget, pIIxset },	/* Intel 7 Series/C216 */
-	{ 0x8086, 0x8c56, pIIxget, pIIxset },	/* Intel 8 Series/C226 */
-	{ 0x8086, 0x2810, pIIxget, pIIxset },	/* Intel 82801HB/HR (ich8/r) */
-	{ 0x8086, 0x2812, pIIxget, pIIxset },	/* Intel 82801HH (ich8dh) */
-	{ 0x8086, 0x2912, pIIxget, pIIxset },	/* Intel 82801ih ich9dh */
-	{ 0x8086, 0x2914, pIIxget, pIIxset },	/* Intel 82801io ich9do */
-	{ 0x8086, 0x2916, pIIxget, pIIxset },	/* Intel 82801ibr ich9r */
-	{ 0x8086, 0x2917, pIIxget, pIIxset },	/* Intel 82801iem ich9m-e  */
-	{ 0x8086, 0x2918, pIIxget, pIIxset },	/* Intel 82801ib ich9 */
-	{ 0x8086, 0x2919, pIIxget, pIIxset },	/* Intel 82801? ich9m  */
-	{ 0x8086, 0x3a16, pIIxget, pIIxset },	/* Intel 82801jir ich10r */
-	{ 0x8086, 0x3a18, pIIxget, pIIxset },	/* Intel 82801jib ich10 */
-	{ 0x8086, 0x3a40, pIIxget, pIIxset },	/* Intel 82801ji */
-	{ 0x8086, 0x3a42, pIIxget, pIIxset },	/* Intel 82801ji */
-	{ 0x8086, 0x3a48, pIIxget, pIIxset },	/* Intel 82801ji */
-	{ 0x8086, 0x3b06, pIIxget, pIIxset },	/* Intel 82801? ibex peak */
-	{ 0x8086, 0x3b14, pIIxget, pIIxset },	/* Intel 82801? 3420 */
-	{ 0x8086, 0x1c49, pIIxget, pIIxset },	/* Intel 82hm65 cougar point pch */
-	{ 0x8086, 0x1c4b, pIIxget, pIIxset },	/* Intel 82hm67 */
-	{ 0x8086, 0x1c4f, pIIxget, pIIxset },	/* Intel 82qm67 cougar point pch */
-	{ 0x8086, 0x1c52, pIIxget, pIIxset },	/* Intel 82q65 cougar point pch */
-	{ 0x8086, 0x1c54, pIIxget, pIIxset },	/* Intel 82q67 cougar point pch */
-	{ 0x8086, 0x1e55, pIIxget, pIIxset },	/* Intel QM77 panter point lpc */
-
-	{ 0x1106, 0x0586, viaget, viaset },	/* Viatech 82C586 */
-	{ 0x1106, 0x0596, viaget, viaset },	/* Viatech 82C596 */
-	{ 0x1106, 0x0686, viaget, viaset },	/* Viatech 82C686 */
-	{ 0x1106, 0x3177, viaget, viaset },	/* Viatech VT8235 */
-	{ 0x1106, 0x3227, viaget, viaset },	/* Viatech VT8237 */
-	{ 0x1106, 0x3287, viaget, viaset },	/* Viatech VT8251 */
-	{ 0x1106, 0x8410, viaget, viaset },	/* Viatech PV530 bridge */
-	{ 0x1045, 0xc700, optiget, optiset },	/* Opti 82C700 */
-	{ 0x10b9, 0x1533, aliget, aliset },	/* Al M1533 */
-	{ 0x1039, 0x0008, pIIxget, pIIxset },	/* SI 503 */
-	{ 0x1039, 0x0496, pIIxget, pIIxset },	/* SI 496 */
-	{ 0x1078, 0x0100, cyrixget, cyrixset },	/* Cyrix 5530 Legacy */
-
-	{ 0x1022, 0x790e, nil, nil },		/* AMD FCH LPC bridge */
-	{ 0x1022, 0x746b, nil, nil },		/* AMD 8111 */
-	{ 0x10de, 0x00d1, nil, nil },		/* NVIDIA nForce 3 */
-	{ 0x10de, 0x00e0, nil, nil },		/* NVIDIA nForce 3 250 Series */
-	{ 0x10de, 0x00e1, nil, nil },		/* NVIDIA nForce 3 250 Series */
-	{ 0x1166, 0x0200, nil, nil },		/* ServerWorks ServerSet III LE */
-	{ 0x1002, 0x4377, nil, nil },		/* ATI Radeon Xpress 200M */
-	{ 0x1002, 0x4372, nil, nil },		/* ATI SB400 */
-	{ 0x1002, 0x9601, nil, nil },		/* AMD SB710 */
-	{ 0x1002, 0x438d, nil, nil },		/* AMD SB600 */
-	{ 0x1002, 0x439d, nil, nil },		/* AMD SB810 */
-};
-
-typedef struct Slot Slot;
-struct Slot {
-	uchar	bus;		/* Pci bus number */
-	uchar	dev;		/* Pci device number */
-	uchar	maps[12];	/* Avoid structs!  Link and mask. */
-	uchar	slot;		/* Add-in/built-in slot */
-	uchar	reserved;
-};
-
-typedef struct Router Router;
-struct Router {
-	uchar	signature[4];	/* Routing table signature */
-	uchar	version[2];	/* Version number */
-	uchar	size[2];	/* Total table size */
-	uchar	bus;		/* Interrupt router bus number */
-	uchar	devfn;		/* Router's devfunc */
-	uchar	pciirqs[2];	/* Exclusive PCI irqs */
-	uchar	compat[4];	/* Compatible PCI interrupt router */
-	uchar	miniport[4];	/* Miniport data */
-	uchar	reserved[11];
-	uchar	checksum;
-};
-
-static ushort pciirqs;		/* Exclusive PCI irqs */
-static Bridge *southbridge;	/* Which southbridge to use. */
-
-static void
-pcirouting(void)
-{
-	Slot *e;
-	Router *r;
-	int i, size, tbdf;
-	Pcidev *sbpci, *pci;
-	uchar *p, pin, irq, link, *map;
-
-	if((p = sigsearch("$PIR", 0)) == nil)
-		return;
-
-	r = (Router*)p;
-	size = (r->size[1] << 8)|r->size[0];
-	if(size < sizeof(Router) || checksum(r, size))
-		return;
-
-	if(0) print("PCI interrupt routing table version %d.%d at %p\n",
-		r->version[0], r->version[1], r);
-
-	tbdf = MKBUS(BusPCI, r->bus, (r->devfn>>3)&0x1f, r->devfn&7);
-	sbpci = pcimatchtbdf(tbdf);
-	if(sbpci == nil) {
-		print("pcirouting: Cannot find south bridge %T\n", tbdf);
-		return;
-	}
-
-	for(i = 0; i < nelem(southbridges); i++)
-		if(sbpci->vid == southbridges[i].vid && sbpci->did == southbridges[i].did)
-			break;
-
-	if(i == nelem(southbridges)) {
-		print("pcirouting: ignoring south bridge %T %.4uX/%.4uX\n", tbdf, sbpci->vid, sbpci->did);
-		return;
-	}
-	southbridge = &southbridges[i];
-	if(southbridge->get == nil)
-		return;
-
-	pciirqs = (r->pciirqs[1] << 8)|r->pciirqs[0];
-	for(e = (Slot *)&r[1]; (uchar *)e < p + size; e++) {
-		if(0) {
-			print("%.2uX/%.2uX %.2uX: ", e->bus, e->dev, e->slot);
-			for (i = 0; i < 4; i++) {
-				map = &e->maps[i * 3];
-				print("[%d] %.2uX %.4uX ", i, map[0], (map[2] << 8)|map[1]);
-			}
-			print("\n");
-		}
-		for(i = 0; i < 8; i++) {
-			tbdf = MKBUS(BusPCI, e->bus, (e->dev>>3)&0x1f, i);
-			pci = pcimatchtbdf(tbdf);
-			if(pci == nil)
-				continue;
-			pin = pcicfgr8(pci, PciINTP);
-			if(pin == 0 || pin == 0xff)
-				continue;
-
-			map = &e->maps[((pin - 1) % 4) * 3];
-			link = map[0];
-			irq = southbridge->get(sbpci, link);
-			if(irq == pci->intl)
-				continue;
-			if(irq == 0 || (irq & 0x80) != 0){
-				irq = pci->intl;
-				if(irq == 0 || irq == 0xff)
-					continue;
-				if(southbridge->set == nil)
-					continue;
-				southbridge->set(sbpci, link, irq);
-			}
-			print("pcirouting: %T at pin %d link %.2uX irq %d -> %d\n", tbdf, pin, link, pci->intl, irq);
-			pcicfgw8(pci, PciINTL, irq);
-			pci->intl = irq;
-		}
-	}
-}
-
-static void pcireservemem(void);
-
-static int
-pcicfgrw8bios(int tbdf, int rno, int data, int read)
-{
-	BIOS32ci ci;
-
-	if(pcibiossi == nil)
-		return -1;
-
-	memset(&ci, 0, sizeof(BIOS32ci));
-	ci.ebx = (BUSBNO(tbdf)<<8)|(BUSDNO(tbdf)<<3)|BUSFNO(tbdf);
-	ci.edi = rno;
-	if(read){
-		ci.eax = 0xB108;
-		if(!bios32ci(pcibiossi, &ci)/* && !(ci.eax & 0xFF)*/)
-			return ci.ecx & 0xFF;
-	}
-	else{
-		ci.eax = 0xB10B;
-		ci.ecx = data & 0xFF;
-		if(!bios32ci(pcibiossi, &ci)/* && !(ci.eax & 0xFF)*/)
-			return 0;
-	}
-
-	return -1;
-}
-
-static int
-pcicfgrw16bios(int tbdf, int rno, int data, int read)
-{
-	BIOS32ci ci;
-
-	if(pcibiossi == nil)
-		return -1;
-
-	memset(&ci, 0, sizeof(BIOS32ci));
-	ci.ebx = (BUSBNO(tbdf)<<8)|(BUSDNO(tbdf)<<3)|BUSFNO(tbdf);
-	ci.edi = rno;
-	if(read){
-		ci.eax = 0xB109;
-		if(!bios32ci(pcibiossi, &ci)/* && !(ci.eax & 0xFF)*/)
-			return ci.ecx & 0xFFFF;
-	}
-	else{
-		ci.eax = 0xB10C;
-		ci.ecx = data & 0xFFFF;
-		if(!bios32ci(pcibiossi, &ci)/* && !(ci.eax & 0xFF)*/)
-			return 0;
-	}
-
-	return -1;
-}
-
-static int
-pcicfgrw32bios(int tbdf, int rno, int data, int read)
-{
-	BIOS32ci ci;
-
-	if(pcibiossi == nil)
-		return -1;
-
-	memset(&ci, 0, sizeof(BIOS32ci));
-	ci.ebx = (BUSBNO(tbdf)<<8)|(BUSDNO(tbdf)<<3)|BUSFNO(tbdf);
-	ci.edi = rno;
-	if(read){
-		ci.eax = 0xB10A;
-		if(!bios32ci(pcibiossi, &ci)/* && !(ci.eax & 0xFF)*/)
-			return ci.ecx;
-	}
-	else{
-		ci.eax = 0xB10D;
-		ci.ecx = data;
-		if(!bios32ci(pcibiossi, &ci)/* && !(ci.eax & 0xFF)*/)
-			return 0;
-	}
-
-	return -1;
-}
-
-static BIOS32si*
-pcibiosinit(void)
-{
-	BIOS32ci ci;
-	BIOS32si *si;
-
-	if((si = bios32open("$PCI")) == nil)
-		return nil;
-
-	memset(&ci, 0, sizeof(BIOS32ci));
-	ci.eax = 0xB101;
-	if(bios32ci(si, &ci) || ci.edx != ((' '<<24)|('I'<<16)|('C'<<8)|'P')){
-		free(si);
-		return nil;
-	}
-	if(ci.eax & 0x01)
-		pcimaxdno = 31;
-	else
-		pcimaxdno = 15;
-	pcimaxbno = ci.ecx & 0xff;
-
-	return si;
-}
-
-void
-pcibussize(Pcidev *root, uvlong *msize, ulong *iosize)
-{
-	*msize = 0;
-	*iosize = 0;
-	pcibusmap(root, msize, iosize, 0);
-}
-
-static void
-pcicfginit(void)
-{
-	char *p;
-	Pcidev **list;
-	uvlong mema;
-	ulong ioa;
-	int bno, n, pcibios;
-
-	lock(&pcicfginitlock);
-	if(pcicfgmode != -1)
-		goto out;
-
-	pcibios = 0;
-	if(getconf("*nobios"))
-		nobios = 1;
-	else if(getconf("*pcibios"))
-		pcibios = 1;
-	if(getconf("*nopcirouting"))
-		nopcirouting = 1;
-
-	/*
-	 * Try to determine which PCI configuration mode is implemented.
-	 * Mode2 uses a byte at 0xCF8 and another at 0xCFA; Mode1 uses
-	 * a DWORD at 0xCF8 and another at 0xCFC and will pass through
-	 * any non-DWORD accesses as normal I/O cycles. There shouldn't be
-	 * a device behind these addresses so if Mode1 accesses fail try
-	 * for Mode2 (Mode2 is deprecated).
-	 */
-	if(!pcibios){
-		/*
-		 * Bits [30:24] of PciADDR must be 0,
-		 * according to the spec.
-		 */
-		n = inl(PciADDR);
-		if(!(n & 0x7F000000)){
-			outl(PciADDR, 0x80000000);
-			outb(PciADDR+3, 0);
-			if(inl(PciADDR) & 0x80000000){
-				pcicfgmode = 1;
-				pcimaxdno = 31;
-			}
-		}
-		outl(PciADDR, n);
-
-		if(pcicfgmode < 0){
-			/*
-			 * The 'key' part of PciCSE should be 0.
-			 */
-			n = inb(PciCSE);
-			if(!(n & 0xF0)){
-				outb(PciCSE, 0x0E);
-				if(inb(PciCSE) == 0x0E){
-					pcicfgmode = 2;
-					pcimaxdno = 15;
-				}
-			}
-			outb(PciCSE, n);
-		}
-	}
-
-	if(pcicfgmode < 0 || pcibios) {
-		if((pcibiossi = pcibiosinit()) == nil)
-			goto out;
-		pcicfgrw8 = pcicfgrw8bios;
-		pcicfgrw16 = pcicfgrw16bios;
-		pcicfgrw32 = pcicfgrw32bios;
-		pcicfgmode = 3;
-	}
-
-	fmtinstall('T', tbdffmt);
-
-	if(p = getconf("*pcimaxbno"))
-		pcimaxbno = strtoul(p, 0, 0);
-	if(p = getconf("*pcimaxdno")){
-		n = strtoul(p, 0, 0);
-		if(n < pcimaxdno)
-			pcimaxdno = n;
-	}
-
-	list = &pciroot;
-	for(bno = 0; bno <= pcimaxbno; bno++) {
-		int sbno = bno;
-		bno = pcilscan(bno, list, nil);
-
-		while(*list)
-			list = &(*list)->link;
-
-		if (sbno == 0) {
-			Pcidev *pci;
-
-			/*
-			  * If we have found a PCI-to-Cardbus bridge, make sure
-			  * it has no valid mappings anymore.
-			  */
-			for(pci = pciroot; pci != nil; pci = pci->link){
-				if (pci->ccrb == 6 && pci->ccru == 7) {
-					ushort bcr;
-
-					/* reset the cardbus */
-					bcr = pcicfgr16(pci, PciBCR);
-					pcicfgw16(pci, PciBCR, 0x40 | bcr);
-					delay(50);
-				}
-			}
-		}
-	}
-
-	if(pciroot == nil)
-		goto out;
-
-	if(nobios) {
-		/*
-		 * Work out how big the top bus is
-		 */
-		pcibussize(pciroot, &mema, &ioa);
-
-		/*
-		 * Align the windows and map it
-		 */
-		ioa = 0x1000;
-		mema = 0x90000000;
-
-		DBG("Mask sizes: mem=%llux io=%lux\n", mema, ioa);
-
-		pcibusmap(pciroot, &mema, &ioa, 1);
-		DBG("Sizes2: mem=%llux io=%lux\n", mema, ioa);
-
-		goto out;
-	}
-
-	if(!nopcirouting)
-		pcirouting();
-
-out:
-	pcireservemem();
-	unlock(&pcicfginitlock);
-
-	if(getconf("*pcihinv"))
-		pcihinv(nil);
-}
-
-static void
-pcireservemem(void)
-{
-	int i;
-	Pcidev *p;
-
-	/*
-	 * mark all the physical address space claimed by pci devices
-	 * as in use, so that upaalloc doesn't give it out.
-	 */
-	for(p=pciroot; p; p=p->list)
-		for(i=0; i<nelem(p->mem); i++)
-			if(p->mem[i].size && (p->mem[i].bar&1) == 0 && (p->mem[i].bar&~0xF) != 0)
-				upaalloc(p->mem[i].bar&~0xF, p->mem[i].size, 0);
-}
-
-static int
-pcicfgrw8raw(int tbdf, int rno, int data, int read)
-{
-	int o, type, x;
-
-	if(pcicfgmode == -1)
-		pcicfginit();
-
-	if(BUSBNO(tbdf))
-		type = 0x01;
-	else
-		type = 0x00;
-	x = -1;
-	if(BUSDNO(tbdf) > pcimaxdno)
-		return x;
-
-	lock(&pcicfglock);
-	switch(pcicfgmode){
-
-	case 1:
-		o = rno & 0x03;
-		rno &= ~0x03;
-		outl(PciADDR, 0x80000000|BUSBDF(tbdf)|rno|type);
-		if(read)
-			x = inb(PciDATA+o);
-		else
-			outb(PciDATA+o, data);
-		outl(PciADDR, 0);
-		break;
-
-	case 2:
-		outb(PciCSE, 0x80|(BUSFNO(tbdf)<<1));
-		outb(PciFORWARD, BUSBNO(tbdf));
-		if(read)
-			x = inb((0xC000|(BUSDNO(tbdf)<<8)) + rno);
-		else
-			outb((0xC000|(BUSDNO(tbdf)<<8)) + rno, data);
-		outb(PciCSE, 0);
-		break;
-	}
-	unlock(&pcicfglock);
-
-	return x;
-}
-
-int
-pcicfgr8(Pcidev* pcidev, int rno)
-{
-	return pcicfgrw8(pcidev->tbdf, rno, 0, 1);
-}
-
-void
-pcicfgw8(Pcidev* pcidev, int rno, int data)
-{
-	pcicfgrw8(pcidev->tbdf, rno, data, 0);
-}
-
-static int
-pcicfgrw16raw(int tbdf, int rno, int data, int read)
-{
-	int o, type, x;
-
-	if(pcicfgmode == -1)
-		pcicfginit();
-
-	if(BUSBNO(tbdf))
-		type = 0x01;
-	else
-		type = 0x00;
-	x = -1;
-	if(BUSDNO(tbdf) > pcimaxdno)
-		return x;
-
-	lock(&pcicfglock);
-	switch(pcicfgmode){
-
-	case 1:
-		o = rno & 0x02;
-		rno &= ~0x03;
-		outl(PciADDR, 0x80000000|BUSBDF(tbdf)|rno|type);
-		if(read)
-			x = ins(PciDATA+o);
-		else
-			outs(PciDATA+o, data);
-		outl(PciADDR, 0);
-		break;
-
-	case 2:
-		outb(PciCSE, 0x80|(BUSFNO(tbdf)<<1));
-		outb(PciFORWARD, BUSBNO(tbdf));
-		if(read)
-			x = ins((0xC000|(BUSDNO(tbdf)<<8)) + rno);
-		else
-			outs((0xC000|(BUSDNO(tbdf)<<8)) + rno, data);
-		outb(PciCSE, 0);
-		break;
-	}
-	unlock(&pcicfglock);
-
-	return x;
-}
-
-int
-pcicfgr16(Pcidev* pcidev, int rno)
-{
-	return pcicfgrw16(pcidev->tbdf, rno, 0, 1);
-}
-
-void
-pcicfgw16(Pcidev* pcidev, int rno, int data)
-{
-	pcicfgrw16(pcidev->tbdf, rno, data, 0);
-}
-
-static int
-pcicfgrw32raw(int tbdf, int rno, int data, int read)
-{
-	int type, x;
-
-	if(pcicfgmode == -1)
-		pcicfginit();
-
-	if(BUSBNO(tbdf))
-		type = 0x01;
-	else
-		type = 0x00;
-	x = -1;
-	if(BUSDNO(tbdf) > pcimaxdno)
-		return x;
-
-	lock(&pcicfglock);
-	switch(pcicfgmode){
-
-	case 1:
-		rno &= ~0x03;
-		outl(PciADDR, 0x80000000|BUSBDF(tbdf)|rno|type);
-		if(read)
-			x = inl(PciDATA);
-		else
-			outl(PciDATA, data);
-		outl(PciADDR, 0);
-		break;
-
-	case 2:
-		outb(PciCSE, 0x80|(BUSFNO(tbdf)<<1));
-		outb(PciFORWARD, BUSBNO(tbdf));
-		if(read)
-			x = inl((0xC000|(BUSDNO(tbdf)<<8)) + rno);
-		else
-			outl((0xC000|(BUSDNO(tbdf)<<8)) + rno, data);
-		outb(PciCSE, 0);
-		break;
-	}
-	unlock(&pcicfglock);
-
-	return x;
-}
-
-int
-pcicfgr32(Pcidev* pcidev, int rno)
-{
-	return pcicfgrw32(pcidev->tbdf, rno, 0, 1);
-}
-
-void
-pcicfgw32(Pcidev* pcidev, int rno, int data)
-{
-	pcicfgrw32(pcidev->tbdf, rno, data, 0);
-}
-
-Pcidev*
-pcimatch(Pcidev* prev, int vid, int did)
-{
-	if(pcicfgmode == -1)
-		pcicfginit();
-
-	if(prev == nil)
-		prev = pcilist;
-	else
-		prev = prev->list;
-
-	while(prev != nil){
-		if((vid == 0 || prev->vid == vid)
-		&& (did == 0 || prev->did == did))
-			break;
-		prev = prev->list;
-	}
-	return prev;
-}
-
-Pcidev*
-pcimatchtbdf(int tbdf)
-{
-	Pcidev *pcidev;
-
-	if(pcicfgmode == -1)
-		pcicfginit();
-
-	for(pcidev = pcilist; pcidev != nil; pcidev = pcidev->list) {
-		if(pcidev->tbdf == tbdf)
-			break;
-	}
-	return pcidev;
-}
-
-uchar
-pciipin(Pcidev *pci, uchar pin)
-{
-	if (pci == nil)
-		pci = pcilist;
-
-	while (pci) {
-		uchar intl;
-
-		if (pcicfgr8(pci, PciINTP) == pin && pci->intl != 0 && pci->intl != 0xff)
-			return pci->intl;
-
-		if (pci->bridge && (intl = pciipin(pci->bridge, pin)) != 0)
-			return intl;
-
-		pci = pci->list;
-	}
-	return 0;
-}
-
-static void
-pcilhinv(Pcidev* p)
-{
-	int i;
-	Pcidev *t;
-
-	if(p == nil) {
-		p = pciroot;
-		print("bus dev type vid  did intl memory\n");
-	}
-	for(t = p; t != nil; t = t->link) {
-		print("%d  %2d/%d %.2ux %.2ux %.2ux %.4ux %.4ux %3d  ",
-			BUSBNO(t->tbdf), BUSDNO(t->tbdf), BUSFNO(t->tbdf),
-			t->ccrb, t->ccru, t->ccrp, t->vid, t->did, t->intl);
-
-		for(i = 0; i < nelem(p->mem); i++) {
-			if(t->mem[i].size == 0)
-				continue;
-			print("%d:%.8llux %d ", i,
-				t->mem[i].bar, t->mem[i].size);
-		}
-		if(t->ioa.bar || t->ioa.size)
-			print("ioa:%.8llux %d ", t->ioa.bar, t->ioa.size);
-		if(t->mema.bar || t->mema.size)
-			print("mema:%.8llux %d ", t->mema.bar, t->mema.size);
-		if(t->bridge)
-			print("->%d", BUSBNO(t->bridge->tbdf));
-		print("\n");
-	}
-	while(p != nil) {
-		if(p->bridge != nil)
-			pcilhinv(p->bridge);
-		p = p->link;
-	}
-}
-
-void
-pcihinv(Pcidev* p)
-{
-	if(pcicfgmode == -1)
-		pcicfginit();
-	lock(&pcicfginitlock);
-	pcilhinv(p);
-	unlock(&pcicfginitlock);
-}
-
-void
-pcireset(void)
-{
-	Pcidev *p;
-
-	if(pcicfgmode == -1)
-		pcicfginit();
-
-	for(p = pcilist; p != nil; p = p->list) {
-		/* don't mess with the bridges */
-		if(p->ccrb == 0x06)
-			continue;
-		pciclrbme(p);
-	}
-}
-
-void
-pcisetioe(Pcidev* p)
-{
-	p->pcr |= IOen;
-	pcicfgw16(p, PciPCR, p->pcr);
-}
-
-void
-pciclrioe(Pcidev* p)
-{
-	p->pcr &= ~IOen;
-	pcicfgw16(p, PciPCR, p->pcr);
-}
-
-void
-pcisetbme(Pcidev* p)
-{
-	p->pcr |= MASen;
-	pcicfgw16(p, PciPCR, p->pcr);
-}
-
-void
-pciclrbme(Pcidev* p)
-{
-	p->pcr &= ~MASen;
-	pcicfgw16(p, PciPCR, p->pcr);
-}
-
-void
-pcisetmwi(Pcidev* p)
-{
-	p->pcr |= MemWrInv;
-	pcicfgw16(p, PciPCR, p->pcr);
-}
-
-void
-pciclrmwi(Pcidev* p)
-{
-	p->pcr &= ~MemWrInv;
-	pcicfgw16(p, PciPCR, p->pcr);
-}
-
-static int
-enumcaps(Pcidev *p, int (*fmatch)(Pcidev*, int, int, int), int arg)
-{
-	int i, r, cap, off;
-
-	/* status register bit 4 has capabilities */
-	if((pcicfgr16(p, PciPSR) & 1<<4) == 0)
-		return -1;      
-	switch(pcicfgr8(p, PciHDT) & 0x7F){
-	default:
-		return -1;
-	case 0:                         /* etc */
-	case 1:                         /* pci to pci bridge */
-		off = 0x34;
-		break;
-	case 2:                         /* cardbus bridge */
-		off = 0x14;
-		break;
-	}
-	for(i = 48; i--;){
-		off = pcicfgr8(p, off);
-		if(off < 0x40 || (off & 3))
-			break;
-		off &= ~3;
-		cap = pcicfgr8(p, off);
-		if(cap == 0xff)
-			break;
-		r = (*fmatch)(p, cap, off, arg);
-		if(r < 0)
-			break;
-		if(r == 0)
-			return off;
-		off++;
-	}
-	return -1;
-}
-
-static int
-matchcap(Pcidev *, int cap, int, int arg)
-{
-	return cap != arg;
-}
-
-static int
-matchhtcap(Pcidev *p, int cap, int off, int arg)
-{
-	int mask;
-
-	if(cap != PciCapHTC)
-		return 1;
-	if(arg == 0x00 || arg == 0x20)
-		mask = 0xE0;
-	else
-		mask = 0xF8;
-	cap = pcicfgr8(p, off+3);
-	return (cap & mask) != arg;
-}
-
-int
-pcicap(Pcidev *p, int cap)
-{
-	return enumcaps(p, matchcap, cap);
-}
-
-int
-pcihtcap(Pcidev *p, int cap)
-{
-	return enumcaps(p, matchhtcap, cap);
-}
-
-static int
-pcigetpmrb(Pcidev* p)
-{
-        if(p->pmrb != 0)
-                return p->pmrb;
-        return p->pmrb = pcicap(p, PciCapPMG);
-}
-
-int
-pcigetpms(Pcidev* p)
-{
-	int pmcsr, ptr;
-
-	if((ptr = pcigetpmrb(p)) == -1)
-		return -1;
-
-	/*
-	 * Power Management Register Block:
-	 *  offset 0:	Capability ID
-	 *	   1:	next item pointer
-	 *	   2:	capabilities
-	 *	   4:	control/status
-	 *	   6:	bridge support extensions
-	 *	   7:	data
-	 */
-	pmcsr = pcicfgr16(p, ptr+4);
-
-	return pmcsr & 0x0003;
-}
-
-int
-pcisetpms(Pcidev* p, int state)
-{
-	int ostate, pmc, pmcsr, ptr;
-
-	if((ptr = pcigetpmrb(p)) == -1)
-		return -1;
-
-	pmc = pcicfgr16(p, ptr+2);
-	pmcsr = pcicfgr16(p, ptr+4);
-	ostate = pmcsr & 0x0003;
-	pmcsr &= ~0x0003;
-
-	switch(state){
-	default:
-		return -1;
-	case 0:
-		break;
-	case 1:
-		if(!(pmc & 0x0200))
-			return -1;
-		break;
-	case 2:
-		if(!(pmc & 0x0400))
-			return -1;
-		break;
-	case 3:
-		break;
-	}
-	pmcsr |= state;
-	pcicfgw16(p, ptr+4, pmcsr);
-
-	return ostate;
-}
-
-int
-pcinextcap(Pcidev *pci, int offset)
-{
-	if(offset == 0) {
-		if((pcicfgr16(pci, PciPSR) & (1<<4)) == 0)
-			return 0; /* no capabilities */
-		offset = PciCAP-1;
-	}
-	return pcicfgr8(pci, offset+1) & ~3;
-}
-
-void
-pcienable(Pcidev *p)
-{
-	uint pcr;
-	int i;
-
-	if(p == nil)
-		return;
-
-	pcienable(p->parent);
-
-	switch(pcisetpms(p, 0)){
-	case 1:
-		print("pcienable %T: wakeup from D1\n", p->tbdf);
-		break;
-	case 2:
-		print("pcienable %T: wakeup from D2\n", p->tbdf);
-		if(p->bridge != nil)
-			delay(100);	/* B2: minimum delay 50ms */
-		else
-			delay(1);	/* D2: minimum delay 200µs */
-		break;
-	case 3:
-		print("pcienable %T: wakeup from D3\n", p->tbdf);
-		delay(100);		/* D3: minimum delay 50ms */
-
-		/* restore registers */
-		for(i = 0; i < nelem(p->mem); i++){
-			pcicfgw32(p, PciBAR0+i*4, p->mem[i].bar);
-			if((p->mem[i].bar&7) == 4 && i < nelem(p->mem)-1){
-				pcicfgw32(p, PciBAR0+i*4+4, p->mem[i].bar>>32);
-				i++;
-			}
-		}
-		pcicfgw8(p, PciINTL, p->intl);
-		pcicfgw8(p, PciLTR, p->ltr);
-		pcicfgw8(p, PciCLS, p->cls);
-		pcicfgw16(p, PciPCR, p->pcr);
-		break;
-	}
-
-	if(p->bridge != nil)
-		pcr = IOen|MEMen|MASen;
-	else {
-		pcr = 0;
-		for(i = 0; i < nelem(p->mem); i++){
-			if(p->mem[i].size == 0)
-				continue;
-			if(p->mem[i].bar & 1)
-				pcr |= IOen;
-			else
-				pcr |= MEMen;
-		}
-	}
-
-	if((p->pcr & pcr) != pcr){
-		print("pcienable %T: pcr %ux->%ux\n", p->tbdf, p->pcr, p->pcr|pcr);
-		p->pcr |= pcr;
-		pcicfgrw32(p->tbdf, PciPCR, 0xFFFF0000|p->pcr, 0);
-	}
-}
-
-void
-pcidisable(Pcidev *p)
-{
-	if(p == nil)
-		return;
-	pciclrbme(p);
-}
--- /dev/null
+++ b/sys/src/9/pc/pcipc.c
@@ -1,0 +1,739 @@
+#include "u.h"
+#include "../port/lib.h"
+#include "mem.h"
+#include "dat.h"
+#include "fns.h"
+#include "io.h"
+#include "../port/pci.h"
+#include "../port/error.h"
+
+#define DBG	if(1) print
+
+enum
+{	/* configuration mechanism #1 */
+	PciADDR		= 0xCF8,	/* CONFIG_ADDRESS */
+	PciDATA		= 0xCFC,	/* CONFIG_DATA */
+
+	/* configuration mechanism #2 */
+	PciCSE		= 0xCF8,	/* configuration space enable */
+	PciFORWARD	= 0xCFA,	/* which bus */
+};
+
+static int pcimaxbno = 255;
+static int pcicfgmode = -1;
+static Pcidev* pciroot;
+static int nobios, nopcirouting;
+static BIOS32si* pcibiossi;
+
+static int pcicfgrw8raw(int, int, int, int);
+static int pcicfgrw16raw(int, int, int, int);
+static int pcicfgrw32raw(int, int, int, int);
+
+int (*pcicfgrw8)(int, int, int, int) = pcicfgrw8raw;
+int (*pcicfgrw16)(int, int, int, int) = pcicfgrw16raw;
+int (*pcicfgrw32)(int, int, int, int) = pcicfgrw32raw;
+
+static int
+pcicfgrw8raw(int tbdf, int rno, int data, int read)
+{
+	int o, type;
+
+	if(BUSBNO(tbdf))
+		type = 0x01;
+	else
+		type = 0x00;
+	switch(pcicfgmode){
+	case 1:
+		o = rno & 0x03;
+		rno &= ~0x03;
+		outl(PciADDR, 0x80000000|BUSBDF(tbdf)|rno|type);
+		if(read)
+			data = inb(PciDATA+o);
+		else
+			outb(PciDATA+o, data);
+		outl(PciADDR, 0);
+		break;
+
+	case 2:
+		outb(PciCSE, 0x80|(BUSFNO(tbdf)<<1));
+		outb(PciFORWARD, BUSBNO(tbdf));
+		if(read)
+			data = inb((0xC000|(BUSDNO(tbdf)<<8)) + rno);
+		else
+			outb((0xC000|(BUSDNO(tbdf)<<8)) + rno, data);
+		outb(PciCSE, 0);
+		break;
+	default:
+		data = -1;
+	}
+	return data;
+}
+
+static int
+pcicfgrw16raw(int tbdf, int rno, int data, int read)
+{
+	int o, type;
+
+	if(BUSBNO(tbdf))
+		type = 0x01;
+	else
+		type = 0x00;
+	switch(pcicfgmode){
+	case 1:
+		o = rno & 0x02;
+		rno &= ~0x03;
+		outl(PciADDR, 0x80000000|BUSBDF(tbdf)|rno|type);
+		if(read)
+			data = ins(PciDATA+o);
+		else
+			outs(PciDATA+o, data);
+		outl(PciADDR, 0);
+		break;
+
+	case 2:
+		outb(PciCSE, 0x80|(BUSFNO(tbdf)<<1));
+		outb(PciFORWARD, BUSBNO(tbdf));
+		if(read)
+			data = ins((0xC000|(BUSDNO(tbdf)<<8)) + rno);
+		else
+			outs((0xC000|(BUSDNO(tbdf)<<8)) + rno, data);
+		outb(PciCSE, 0);
+		break;
+	default:
+		data = -1;
+	}
+	return data;
+}
+
+static int
+pcicfgrw32raw(int tbdf, int rno, int data, int read)
+{
+	int type;
+
+	if(BUSBNO(tbdf))
+		type = 0x01;
+	else
+		type = 0x00;
+	switch(pcicfgmode){
+	case 1:
+		rno &= ~0x03;
+		outl(PciADDR, 0x80000000|BUSBDF(tbdf)|rno|type);
+		if(read)
+			data = inl(PciDATA);
+		else
+			outl(PciDATA, data);
+		outl(PciADDR, 0);
+		break;
+
+	case 2:
+		outb(PciCSE, 0x80|(BUSFNO(tbdf)<<1));
+		outb(PciFORWARD, BUSBNO(tbdf));
+		if(read)
+			data = inl((0xC000|(BUSDNO(tbdf)<<8)) + rno);
+		else
+			outl((0xC000|(BUSDNO(tbdf)<<8)) + rno, data);
+		outb(PciCSE, 0);
+		break;
+	default:
+		data = -1;
+	}
+	return data;
+}
+
+static int
+pcicfgrw8bios(int tbdf, int rno, int data, int read)
+{
+	BIOS32ci ci;
+
+	if(pcibiossi == nil)
+		return -1;
+
+	memset(&ci, 0, sizeof(BIOS32ci));
+	ci.ebx = (BUSBNO(tbdf)<<8)|(BUSDNO(tbdf)<<3)|BUSFNO(tbdf);
+	ci.edi = rno;
+	if(read){
+		ci.eax = 0xB108;
+		if(!bios32ci(pcibiossi, &ci)/* && !(ci.eax & 0xFF)*/)
+			return ci.ecx & 0xFF;
+	}
+	else{
+		ci.eax = 0xB10B;
+		ci.ecx = data & 0xFF;
+		if(!bios32ci(pcibiossi, &ci)/* && !(ci.eax & 0xFF)*/)
+			return 0;
+	}
+
+	return -1;
+}
+
+static int
+pcicfgrw16bios(int tbdf, int rno, int data, int read)
+{
+	BIOS32ci ci;
+
+	if(pcibiossi == nil)
+		return -1;
+
+	memset(&ci, 0, sizeof(BIOS32ci));
+	ci.ebx = (BUSBNO(tbdf)<<8)|(BUSDNO(tbdf)<<3)|BUSFNO(tbdf);
+	ci.edi = rno;
+	if(read){
+		ci.eax = 0xB109;
+		if(!bios32ci(pcibiossi, &ci)/* && !(ci.eax & 0xFF)*/)
+			return ci.ecx & 0xFFFF;
+	}
+	else{
+		ci.eax = 0xB10C;
+		ci.ecx = data & 0xFFFF;
+		if(!bios32ci(pcibiossi, &ci)/* && !(ci.eax & 0xFF)*/)
+			return 0;
+	}
+
+	return -1;
+}
+
+static int
+pcicfgrw32bios(int tbdf, int rno, int data, int read)
+{
+	BIOS32ci ci;
+
+	if(pcibiossi == nil)
+		return -1;
+
+	memset(&ci, 0, sizeof(BIOS32ci));
+	ci.ebx = (BUSBNO(tbdf)<<8)|(BUSDNO(tbdf)<<3)|BUSFNO(tbdf);
+	ci.edi = rno;
+	if(read){
+		ci.eax = 0xB10A;
+		if(!bios32ci(pcibiossi, &ci)/* && !(ci.eax & 0xFF)*/)
+			return ci.ecx;
+	}
+	else{
+		ci.eax = 0xB10D;
+		ci.ecx = data;
+		if(!bios32ci(pcibiossi, &ci)/* && !(ci.eax & 0xFF)*/)
+			return 0;
+	}
+
+	return -1;
+}
+
+static BIOS32si*
+pcibiosinit(void)
+{
+	BIOS32ci ci;
+	BIOS32si *si;
+
+	if((si = bios32open("$PCI")) == nil)
+		return nil;
+
+	memset(&ci, 0, sizeof(BIOS32ci));
+	ci.eax = 0xB101;
+	if(bios32ci(si, &ci) || ci.edx != ((' '<<24)|('I'<<16)|('C'<<8)|'P')){
+		free(si);
+		return nil;
+	}
+	if(ci.eax & 0x01)
+		pcimaxdno = 31;
+	else
+		pcimaxdno = 15;
+	pcimaxbno = ci.ecx & 0xff;
+
+	return si;
+}
+
+static uchar
+pIIxget(Pcidev *router, uchar link)
+{
+	uchar pirq;
+
+	/* link should be 0x60, 0x61, 0x62, 0x63 */
+	pirq = pcicfgr8(router, link);
+	return (pirq < 16)? pirq: 0;
+}
+
+static void
+pIIxset(Pcidev *router, uchar link, uchar irq)
+{
+	pcicfgw8(router, link, irq);
+}
+
+static uchar
+viaget(Pcidev *router, uchar link)
+{
+	uchar pirq;
+
+	/* link should be 1, 2, 3, 5 */
+	pirq = (link < 6)? pcicfgr8(router, 0x55 + (link>>1)): 0;
+
+	return (link & 1)? (pirq >> 4): (pirq & 15);
+}
+
+static void
+viaset(Pcidev *router, uchar link, uchar irq)
+{
+	uchar pirq;
+
+	pirq = pcicfgr8(router, 0x55 + (link >> 1));
+	pirq &= (link & 1)? 0x0f: 0xf0;
+	pirq |= (link & 1)? (irq << 4): (irq & 15);
+	pcicfgw8(router, 0x55 + (link>>1), pirq);
+}
+
+static uchar
+optiget(Pcidev *router, uchar link)
+{
+	uchar pirq = 0;
+
+	/* link should be 0x02, 0x12, 0x22, 0x32 */
+	if ((link & 0xcf) == 0x02)
+		pirq = pcicfgr8(router, 0xb8 + (link >> 5));
+	return (link & 0x10)? (pirq >> 4): (pirq & 15);
+}
+
+static void
+optiset(Pcidev *router, uchar link, uchar irq)
+{
+	uchar pirq;
+
+	pirq = pcicfgr8(router, 0xb8 + (link >> 5));
+    	pirq &= (link & 0x10)? 0x0f : 0xf0;
+    	pirq |= (link & 0x10)? (irq << 4): (irq & 15);
+	pcicfgw8(router, 0xb8 + (link >> 5), pirq);
+}
+
+static uchar
+aliget(Pcidev *router, uchar link)
+{
+	/* No, you're not dreaming */
+	static const uchar map[] = { 0, 9, 3, 10, 4, 5, 7, 6, 1, 11, 0, 12, 0, 14, 0, 15 };
+	uchar pirq;
+
+	/* link should be 0x01..0x08 */
+	pirq = pcicfgr8(router, 0x48 + ((link-1)>>1));
+	return (link & 1)? map[pirq&15]: map[pirq>>4];
+}
+
+static void
+aliset(Pcidev *router, uchar link, uchar irq)
+{
+	/* Inverse of map in aliget */
+	static const uchar map[] = { 0, 8, 0, 2, 4, 5, 7, 6, 0, 1, 3, 9, 11, 0, 13, 15 };
+	uchar pirq;
+
+	pirq = pcicfgr8(router, 0x48 + ((link-1)>>1));
+	pirq &= (link & 1)? 0x0f: 0xf0;
+	pirq |= (link & 1)? (map[irq] << 4): (map[irq] & 15);
+	pcicfgw8(router, 0x48 + ((link-1)>>1), pirq);
+}
+
+static uchar
+cyrixget(Pcidev *router, uchar link)
+{
+	uchar pirq;
+
+	/* link should be 1, 2, 3, 4 */
+	pirq = pcicfgr8(router, 0x5c + ((link-1)>>1));
+	return ((link & 1)? pirq >> 4: pirq & 15);
+}
+
+static void
+cyrixset(Pcidev *router, uchar link, uchar irq)
+{
+	uchar pirq;
+
+	pirq = pcicfgr8(router, 0x5c + (link>>1));
+	pirq &= (link & 1)? 0x0f: 0xf0;
+	pirq |= (link & 1)? (irq << 4): (irq & 15);
+	pcicfgw8(router, 0x5c + (link>>1), pirq);
+}
+
+typedef struct Bridge Bridge;
+struct Bridge
+{
+	ushort	vid;
+	ushort	did;
+	uchar	(*get)(Pcidev *, uchar);
+	void	(*set)(Pcidev *, uchar, uchar);
+};
+
+static Bridge southbridges[] = {
+	{ 0x8086, 0x122e, pIIxget, pIIxset },	/* Intel 82371FB */
+	{ 0x8086, 0x1234, pIIxget, pIIxset },	/* Intel 82371MX */
+	{ 0x8086, 0x7000, pIIxget, pIIxset },	/* Intel 82371SB */
+	{ 0x8086, 0x7110, pIIxget, pIIxset },	/* Intel 82371AB */
+	{ 0x8086, 0x7198, pIIxget, pIIxset },	/* Intel 82443MX (fn 1) */
+	{ 0x8086, 0x2410, pIIxget, pIIxset },	/* Intel 82801AA */
+	{ 0x8086, 0x2420, pIIxget, pIIxset },	/* Intel 82801AB */
+	{ 0x8086, 0x2440, pIIxget, pIIxset },	/* Intel 82801BA */
+	{ 0x8086, 0x2448, pIIxget, pIIxset },	/* Intel 82801BAM/CAM/DBM */
+	{ 0x8086, 0x244c, pIIxget, pIIxset },	/* Intel 82801BAM */
+	{ 0x8086, 0x244e, pIIxget, pIIxset },	/* Intel 82801 */
+	{ 0x8086, 0x2480, pIIxget, pIIxset },	/* Intel 82801CA */
+	{ 0x8086, 0x248c, pIIxget, pIIxset },	/* Intel 82801CAM */
+	{ 0x8086, 0x24c0, pIIxget, pIIxset },	/* Intel 82801DBL */
+	{ 0x8086, 0x24cc, pIIxget, pIIxset },	/* Intel 82801DBM */
+	{ 0x8086, 0x24d0, pIIxget, pIIxset },	/* Intel 82801EB */
+	{ 0x8086, 0x25a1, pIIxget, pIIxset },	/* Intel 6300ESB */
+	{ 0x8086, 0x2640, pIIxget, pIIxset },	/* Intel 82801FB */
+	{ 0x8086, 0x2641, pIIxget, pIIxset },	/* Intel 82801FBM */
+	{ 0x8086, 0x2670, pIIxget, pIIxset },	/* Intel 632xesb */
+	{ 0x8086, 0x27b8, pIIxget, pIIxset },	/* Intel 82801GB */
+	{ 0x8086, 0x27b9, pIIxget, pIIxset },	/* Intel 82801GBM */
+	{ 0x8086, 0x27bd, pIIxget, pIIxset },	/* Intel 82801GB/GR */
+	{ 0x8086, 0x3a16, pIIxget, pIIxset },	/* Intel 82801JIR */
+	{ 0x8086, 0x3a40, pIIxget, pIIxset },	/* Intel 82801JI */
+	{ 0x8086, 0x3a42, pIIxget, pIIxset },	/* Intel 82801JI */
+	{ 0x8086, 0x3a48, pIIxget, pIIxset },	/* Intel 82801JI */
+	{ 0x8086, 0x2916, pIIxget, pIIxset },	/* Intel 82801? */
+	{ 0x8086, 0x1c02, pIIxget, pIIxset },	/* Intel 6 Series/C200 */
+	{ 0x8086, 0x1e53, pIIxget, pIIxset },	/* Intel 7 Series/C216 */
+	{ 0x8086, 0x8c56, pIIxget, pIIxset },	/* Intel 8 Series/C226 */
+	{ 0x8086, 0x2810, pIIxget, pIIxset },	/* Intel 82801HB/HR (ich8/r) */
+	{ 0x8086, 0x2812, pIIxget, pIIxset },	/* Intel 82801HH (ich8dh) */
+	{ 0x8086, 0x2912, pIIxget, pIIxset },	/* Intel 82801ih ich9dh */
+	{ 0x8086, 0x2914, pIIxget, pIIxset },	/* Intel 82801io ich9do */
+	{ 0x8086, 0x2916, pIIxget, pIIxset },	/* Intel 82801ibr ich9r */
+	{ 0x8086, 0x2917, pIIxget, pIIxset },	/* Intel 82801iem ich9m-e  */
+	{ 0x8086, 0x2918, pIIxget, pIIxset },	/* Intel 82801ib ich9 */
+	{ 0x8086, 0x2919, pIIxget, pIIxset },	/* Intel 82801? ich9m  */
+	{ 0x8086, 0x3a16, pIIxget, pIIxset },	/* Intel 82801jir ich10r */
+	{ 0x8086, 0x3a18, pIIxget, pIIxset },	/* Intel 82801jib ich10 */
+	{ 0x8086, 0x3a40, pIIxget, pIIxset },	/* Intel 82801ji */
+	{ 0x8086, 0x3a42, pIIxget, pIIxset },	/* Intel 82801ji */
+	{ 0x8086, 0x3a48, pIIxget, pIIxset },	/* Intel 82801ji */
+	{ 0x8086, 0x3b06, pIIxget, pIIxset },	/* Intel 82801? ibex peak */
+	{ 0x8086, 0x3b14, pIIxget, pIIxset },	/* Intel 82801? 3420 */
+	{ 0x8086, 0x1c49, pIIxget, pIIxset },	/* Intel 82hm65 cougar point pch */
+	{ 0x8086, 0x1c4b, pIIxget, pIIxset },	/* Intel 82hm67 */
+	{ 0x8086, 0x1c4f, pIIxget, pIIxset },	/* Intel 82qm67 cougar point pch */
+	{ 0x8086, 0x1c52, pIIxget, pIIxset },	/* Intel 82q65 cougar point pch */
+	{ 0x8086, 0x1c54, pIIxget, pIIxset },	/* Intel 82q67 cougar point pch */
+	{ 0x8086, 0x1e55, pIIxget, pIIxset },	/* Intel QM77 panter point lpc */
+
+	{ 0x1106, 0x0586, viaget, viaset },	/* Viatech 82C586 */
+	{ 0x1106, 0x0596, viaget, viaset },	/* Viatech 82C596 */
+	{ 0x1106, 0x0686, viaget, viaset },	/* Viatech 82C686 */
+	{ 0x1106, 0x3177, viaget, viaset },	/* Viatech VT8235 */
+	{ 0x1106, 0x3227, viaget, viaset },	/* Viatech VT8237 */
+	{ 0x1106, 0x3287, viaget, viaset },	/* Viatech VT8251 */
+	{ 0x1106, 0x8410, viaget, viaset },	/* Viatech PV530 bridge */
+	{ 0x1045, 0xc700, optiget, optiset },	/* Opti 82C700 */
+	{ 0x10b9, 0x1533, aliget, aliset },	/* Al M1533 */
+	{ 0x1039, 0x0008, pIIxget, pIIxset },	/* SI 503 */
+	{ 0x1039, 0x0496, pIIxget, pIIxset },	/* SI 496 */
+	{ 0x1078, 0x0100, cyrixget, cyrixset },	/* Cyrix 5530 Legacy */
+
+	{ 0x1022, 0x790e, nil, nil },		/* AMD FCH LPC bridge */
+	{ 0x1022, 0x746b, nil, nil },		/* AMD 8111 */
+	{ 0x10de, 0x00d1, nil, nil },		/* NVIDIA nForce 3 */
+	{ 0x10de, 0x00e0, nil, nil },		/* NVIDIA nForce 3 250 Series */
+	{ 0x10de, 0x00e1, nil, nil },		/* NVIDIA nForce 3 250 Series */
+	{ 0x1166, 0x0200, nil, nil },		/* ServerWorks ServerSet III LE */
+	{ 0x1002, 0x4377, nil, nil },		/* ATI Radeon Xpress 200M */
+	{ 0x1002, 0x4372, nil, nil },		/* ATI SB400 */
+	{ 0x1002, 0x9601, nil, nil },		/* AMD SB710 */
+	{ 0x1002, 0x438d, nil, nil },		/* AMD SB600 */
+	{ 0x1002, 0x439d, nil, nil },		/* AMD SB810 */
+};
+
+typedef struct Slot Slot;
+struct Slot {
+	uchar	bus;		/* Pci bus number */
+	uchar	dev;		/* Pci device number */
+	uchar	maps[12];	/* Avoid structs!  Link and mask. */
+	uchar	slot;		/* Add-in/built-in slot */
+	uchar	reserved;
+};
+
+typedef struct Router Router;
+struct Router {
+	uchar	signature[4];	/* Routing table signature */
+	uchar	version[2];	/* Version number */
+	uchar	size[2];	/* Total table size */
+	uchar	bus;		/* Interrupt router bus number */
+	uchar	devfn;		/* Router's devfunc */
+	uchar	pciirqs[2];	/* Exclusive PCI irqs */
+	uchar	compat[4];	/* Compatible PCI interrupt router */
+	uchar	miniport[4];	/* Miniport data */
+	uchar	reserved[11];
+	uchar	checksum;
+};
+
+static ushort pciirqs;		/* Exclusive PCI irqs */
+static Bridge *southbridge;	/* Which southbridge to use. */
+
+static void
+pcirouting(void)
+{
+	Slot *e;
+	Router *r;
+	int i, size, tbdf;
+	Pcidev *sbpci, *pci;
+	uchar *p, pin, irq, link, *map;
+
+	if((p = sigsearch("$PIR", 0)) == nil)
+		return;
+
+	r = (Router*)p;
+	size = (r->size[1] << 8)|r->size[0];
+	if(size < sizeof(Router) || checksum(r, size))
+		return;
+
+	if(0) print("PCI interrupt routing table version %d.%d at %p\n",
+		r->version[0], r->version[1], r);
+
+	tbdf = MKBUS(BusPCI, r->bus, (r->devfn>>3)&0x1f, r->devfn&7);
+	sbpci = pcimatchtbdf(tbdf);
+	if(sbpci == nil) {
+		print("pcirouting: Cannot find south bridge %T\n", tbdf);
+		return;
+	}
+
+	for(i = 0; i < nelem(southbridges); i++)
+		if(sbpci->vid == southbridges[i].vid && sbpci->did == southbridges[i].did)
+			break;
+
+	if(i == nelem(southbridges)) {
+		print("pcirouting: ignoring south bridge %T %.4uX/%.4uX\n", tbdf, sbpci->vid, sbpci->did);
+		return;
+	}
+	southbridge = &southbridges[i];
+	if(southbridge->get == nil)
+		return;
+
+	pciirqs = (r->pciirqs[1] << 8)|r->pciirqs[0];
+	for(e = (Slot *)&r[1]; (uchar *)e < p + size; e++) {
+		if(0) {
+			print("%.2uX/%.2uX %.2uX: ", e->bus, e->dev, e->slot);
+			for (i = 0; i < 4; i++) {
+				map = &e->maps[i * 3];
+				print("[%d] %.2uX %.4uX ", i, map[0], (map[2] << 8)|map[1]);
+			}
+			print("\n");
+		}
+		for(i = 0; i < 8; i++) {
+			tbdf = MKBUS(BusPCI, e->bus, (e->dev>>3)&0x1f, i);
+			pci = pcimatchtbdf(tbdf);
+			if(pci == nil)
+				continue;
+			pin = pcicfgr8(pci, PciINTP);
+			if(pin == 0 || pin == 0xff)
+				continue;
+
+			map = &e->maps[((pin - 1) % 4) * 3];
+			link = map[0];
+			irq = southbridge->get(sbpci, link);
+			if(irq == pci->intl)
+				continue;
+			if(irq == 0 || (irq & 0x80) != 0){
+				irq = pci->intl;
+				if(irq == 0 || irq == 0xff)
+					continue;
+				if(southbridge->set == nil)
+					continue;
+				southbridge->set(sbpci, link, irq);
+			}
+			print("pcirouting: %T at pin %d link %.2uX irq %d -> %d\n", tbdf, pin, link, pci->intl, irq);
+			pcicfgw8(pci, PciINTL, irq);
+			pci->intl = irq;
+		}
+	}
+}
+
+static void
+pcireservemem(void)
+{
+	Pcidev *p;
+	uvlong pa;
+	int i;
+
+	/*
+	 * mark all valid physical address space claimed by pci devices
+	 * as in use, so that upaalloc doesn't give it out.
+	 */
+	for(p=pciroot; p != nil; p=p->list){
+		for(i=0; i<nelem(p->mem); i++){
+			if(p->mem[i].size == 0)
+				continue;
+			if(p->mem[i].bar & 1)
+				continue;
+			if((p->mem[i].bar & ~0xFULL) == 0)
+				continue;
+			upaalloc(p->mem[i].bar&~0xFULL, p->mem[i].size, 0);
+		}
+	}
+
+	/*
+	 * allocate physical address space for unassigned membars.
+	 */
+	for(p=pciroot; p != nil; p=p->list){
+		for(i=0; i<nelem(p->mem); i++){
+			if(p->mem[i].size == 0)
+				continue;
+			if(p->mem[i].bar & ~0xEULL)
+				continue;
+
+			if(p->parent == nil){
+				pa = upaalloc(-1ULL,
+					p->mem[i].size, p->mem[i].size);
+			} else if(p->mem[i].bar & 8){
+				pa = upaallocwin(p->parent->prefa.bar, p->parent->prefa.size,
+					p->mem[i].size, p->mem[i].size);
+				if(pa == -1ULL)
+					goto Mem;
+			} else {
+			Mem:
+				pa = upaallocwin(p->parent->mema.bar, p->parent->mema.size,
+					p->mem[i].size, p->mem[i].size);
+			}
+			if(pa == -1ULL)
+				continue;
+
+			p->mem[i].bar |= pa;
+			pcisetbar(p, PciBAR0 + i*4, p->mem[i].bar);
+
+			DBG("%T: bar%d: fixed %.8lluX %d\n",
+				p->tbdf, i, p->mem[i].bar, p->mem[i].size);
+		}
+	}
+}
+
+void
+pcicfginit(void)
+{
+	char *p;
+	Pcidev **list;
+	int bno, n, pcibios;
+
+	fmtinstall('T', tbdffmt);
+
+	pcibios = 0;
+	if(getconf("*nobios"))
+		nobios = 1;
+	else if(getconf("*pcibios"))
+		pcibios = 1;
+	if(getconf("*nopcirouting"))
+		nopcirouting = 1;
+
+	/*
+	 * Try to determine which PCI configuration mode is implemented.
+	 * Mode2 uses a byte at 0xCF8 and another at 0xCFA; Mode1 uses
+	 * a DWORD at 0xCF8 and another at 0xCFC and will pass through
+	 * any non-DWORD accesses as normal I/O cycles. There shouldn't be
+	 * a device behind these addresses so if Mode1 accesses fail try
+	 * for Mode2 (Mode2 is deprecated).
+	 */
+	if(!pcibios){
+		/*
+		 * Bits [30:24] of PciADDR must be 0,
+		 * according to the spec.
+		 */
+		n = inl(PciADDR);
+		if(!(n & 0x7F000000)){
+			outl(PciADDR, 0x80000000);
+			outb(PciADDR+3, 0);
+			if(inl(PciADDR) & 0x80000000){
+				pcicfgmode = 1;
+				pcimaxdno = 31;
+			}
+		}
+		outl(PciADDR, n);
+
+		if(pcicfgmode < 0){
+			/*
+			 * The 'key' part of PciCSE should be 0.
+			 */
+			n = inb(PciCSE);
+			if(!(n & 0xF0)){
+				outb(PciCSE, 0x0E);
+				if(inb(PciCSE) == 0x0E){
+					pcicfgmode = 2;
+					pcimaxdno = 15;
+				}
+			}
+			outb(PciCSE, n);
+		}
+	}
+
+	if(pcicfgmode < 0 || pcibios) {
+		if((pcibiossi = pcibiosinit()) == nil)
+			goto out;
+		pcicfgrw8 = pcicfgrw8bios;
+		pcicfgrw16 = pcicfgrw16bios;
+		pcicfgrw32 = pcicfgrw32bios;
+		pcicfgmode = 3;
+	}
+
+	if(p = getconf("*pcimaxbno"))
+		pcimaxbno = strtoul(p, 0, 0);
+	if(p = getconf("*pcimaxdno")){
+		n = strtoul(p, 0, 0);
+		if(n < pcimaxdno)
+			pcimaxdno = n;
+	}
+
+	list = &pciroot;
+	for(bno = 0; bno <= pcimaxbno; bno++) {
+		int sbno = bno;
+		bno = pciscan(bno, list);
+
+		while(*list)
+			list = &(*list)->link;
+
+		if (sbno == 0) {
+			Pcidev *pci;
+
+			/*
+			  * If we have found a PCI-to-Cardbus bridge, make sure
+			  * it has no valid mappings anymore.
+			  */
+			for(pci = pciroot; pci != nil; pci = pci->link){
+				if (pci->ccrb == 6 && pci->ccru == 7) {
+					ushort bcr;
+
+					/* reset the cardbus */
+					bcr = pcicfgr16(pci, PciBCR);
+					pcicfgw16(pci, PciBCR, 0x40 | bcr);
+					delay(50);
+				}
+			}
+		}
+	}
+
+	if(pciroot == nil)
+		goto out;
+
+	if(nobios) {
+		uvlong mema;
+		ulong ioa;
+
+		/*
+		 * Work out how big the top bus is
+		 */
+		pcibussize(pciroot, &mema, &ioa);
+		DBG("Size:  mem=%.8llux io=%lux\n", mema, ioa);
+
+		/*
+		 * Align the windows and map it
+		 */
+		mema = upaalloc(-1ULL, mema, mema);
+		if(mema == -1ULL)
+			panic("pcicfginit: can't allocate pci window");
+
+		ioa = 0x1000;
+		DBG("Base:  mem=%.8llux io=%lux\n", mema, ioa);
+		pcibusmap(pciroot, &mema, &ioa, 1);
+		DBG("Limit: mem=%.8llux io=%lux\n", mema, ioa);
+		goto out;
+	}
+
+	pcireservemem();
+
+	if(!nopcirouting)
+		pcirouting();
+
+out:
+	if(getconf("*pcihinv"))
+		pcihinv(pciroot);
+}
--- a/sys/src/9/pc/piix4smbus.c
+++ b/sys/src/9/pc/piix4smbus.c
@@ -4,6 +4,7 @@
 #include	"dat.h"
 #include	"fns.h"
 #include	"io.h"
+#include	"../port/pci.h"
 
 /*
  *	SMBus support for the PIIX4
--- a/sys/src/9/pc/pmmc.c
+++ b/sys/src/9/pc/pmmc.c
@@ -13,6 +13,7 @@
 #include "dat.h"
 #include "fns.h"
 #include "io.h"
+#include "../port/pci.h"
 #include "../port/sd.h"
 
 /* registers */
--- a/sys/src/9/pc/screen.c
+++ b/sys/src/9/pc/screen.c
@@ -4,6 +4,7 @@
 #include "dat.h"
 #include "fns.h"
 #include "io.h"
+#include "../port/pci.h"
 #include "ureg.h"
 #include "../port/error.h"
 
--- a/sys/src/9/pc/sd53c8xx.c
+++ b/sys/src/9/pc/sd53c8xx.c
@@ -23,6 +23,7 @@
 #include "dat.h"
 #include "fns.h"
 #include "io.h"
+#include "../port/pci.h"
 
 #include "../port/sd.h"
 extern SDifc sd53c8xxifc;
--- a/sys/src/9/pc/sdiahci.c
+++ b/sys/src/9/pc/sdiahci.c
@@ -9,6 +9,7 @@
 #include "dat.h"
 #include "fns.h"
 #include "io.h"
+#include "../port/pci.h"
 #include "../port/error.h"
 #include "../port/sd.h"
 #include <fis.h>
--- a/sys/src/9/pc/sdide.c
+++ b/sys/src/9/pc/sdide.c
@@ -4,6 +4,7 @@
 #include "dat.h"
 #include "fns.h"
 #include "io.h"
+#include "../port/pci.h"
 #include "ureg.h"
 #include "../port/error.h"
 
@@ -352,7 +353,7 @@
 		return;
 
 	x = pcicfgr32(p, 0x40);
-	if(ctlr->cmdport == p->mem[0].bar)
+	if(ctlr->cmdport == (p->mem[0].bar & ~3))
 		x &= ~0x00000100;
 	else
 		x &= ~0x00000200;
@@ -2142,8 +2143,8 @@
 			if((map & 1<<channel) == 0)
 				continue;
 			if(pi & 1<<2*channel){
-				sdev = ataprobe(p->mem[0+2*channel].bar & ~0x01,
-						p->mem[1+2*channel].bar & ~0x01,
+				sdev = ataprobe(p->mem[0+2*channel].bar & ~3,
+						p->mem[1+2*channel].bar & ~3,
 						p->intl, 3);
 				tbdf = p->tbdf;
 			}
@@ -2169,7 +2170,7 @@
 			ctlr->span = span;
 			ctlr->irqack = irqack;
 			if((pi & 0x80) && (p->mem[4].bar & 0x01))
-				ctlr->bmiba = (p->mem[4].bar & ~0x01) + channel*8;
+				ctlr->bmiba = (p->mem[4].bar & ~3) + channel*8;
 			if(head != nil)
 				tail->next = sdev;
 			else
--- a/sys/src/9/pc/sdmv50xx.c
+++ b/sys/src/9/pc/sdmv50xx.c
@@ -15,6 +15,7 @@
 #include "dat.h"
 #include "fns.h"
 #include "io.h"
+#include "../port/pci.h"
 #include "../port/error.h"
 #include	"../port/sd.h"
 #include <fis.h>
--- a/sys/src/9/pc/sdmylex.c
+++ b/sys/src/9/pc/sdmylex.c
@@ -15,6 +15,7 @@
 #include "dat.h"
 #include "fns.h"
 #include "io.h"
+#include "../port/pci.h"
 #include "ureg.h"
 #include "../port/error.h"
 
@@ -1054,7 +1055,7 @@
 	p = nil;
 	head = tail = nil;
 	while(p = pcimatch(p, 0x104B, 0)){
-		if((sdev = mylexprobe(p->mem[0].bar & ~0x01, p->intl)) == nil)
+		if((sdev = mylexprobe(p->mem[0].bar & ~3, p->intl)) == nil)
 			continue;
 
 		ctlr = sdev->ctlr;
--- a/sys/src/9/pc/sdnvme.c
+++ b/sys/src/9/pc/sdnvme.c
@@ -4,6 +4,7 @@
 #include "dat.h"
 #include "fns.h"
 #include "io.h"
+#include "../port/pci.h"
 #include "ureg.h"
 #include "../port/error.h"
 
--- a/sys/src/9/pc/sdodin.c
+++ b/sys/src/9/pc/sdodin.c
@@ -10,6 +10,7 @@
 #include "dat.h"
 #include "fns.h"
 #include "io.h"
+#include "../port/pci.h"
 #include "../port/error.h"
 #include "../port/sd.h"
 #include <fis.h>
--- a/sys/src/9/pc/sdvirtio.c
+++ b/sys/src/9/pc/sdvirtio.c
@@ -4,6 +4,7 @@
 #include "dat.h"
 #include "fns.h"
 #include "io.h"
+#include "../port/pci.h"
 #include "ureg.h"
 #include "../port/error.h"
 
@@ -203,6 +204,8 @@
 			continue;
 		if(p->rid != 0)
 			continue;
+		if((p->mem[0].bar & 1) == 0)
+			continue;
 		if(pcicfgr16(p, 0x2E) != typ)
 			continue;
 		if((vd = malloc(sizeof(*vd))) == nil){
@@ -209,7 +212,7 @@
 			print("virtio: no memory for Vdev\n");
 			break;
 		}
-		vd->port = p->mem[0].bar & ~0x1;
+		vd->port = p->mem[0].bar & ~3;
 		if(ioalloc(vd->port, p->mem[0].size, 0, "virtio") < 0){
 			print("virtio: port %lux in use\n", vd->port);
 			free(vd);
--- a/sys/src/9/pc/uartaxp.c
+++ b/sys/src/9/pc/uartaxp.c
@@ -7,6 +7,7 @@
 #include "dat.h"
 #include "fns.h"
 #include "io.h"
+#include "../port/pci.h"
 #include "../port/error.h"
 
 #include "uartaxp.i"
--- a/sys/src/9/pc/uartpci.c
+++ b/sys/src/9/pc/uartpci.c
@@ -4,6 +4,7 @@
 #include "dat.h"
 #include "fns.h"
 #include "io.h"
+#include "../port/pci.h"
 #include "../port/error.h"
 
 extern PhysUart i8250physuart;
@@ -21,21 +22,21 @@
 	char buf[64];
 	Uart *head, *uart;
 
-	head = malloc(sizeof(Uart)*n);
-	if(head == nil){
-		print("uartpci: no memory for Uarts\n");
+	if((p->mem[barno].bar & 1) == 0)
 		return nil;
-	}
-
-	io = p->mem[barno].bar & ~0x01;
+	io = p->mem[barno].bar & ~3;
 	snprint(buf, sizeof(buf), "%s%d", pciphysuart.name, ctlrno);
 	if(ioalloc(io, p->mem[barno].size, 0, buf) < 0){
 		print("uartpci: I/O 0x%uX in use\n", io);
-		free(head);
 		return nil;
 	}
-
 	pcienable(p);
+	head = malloc(sizeof(Uart)*n);
+	if(head == nil){
+		print("uartpci: no memory for Uarts\n");
+		iofree(io);
+		return nil;
+	}
 	uart = head;
 	for(i = 0; i < n; i++){
 		ctlr = i8250alloc(io + i*iosize, p->intl, p->tbdf);
--- a/sys/src/9/pc/usbehcipc.c
+++ b/sys/src/9/pc/usbehcipc.c
@@ -10,6 +10,7 @@
 #include	"dat.h"
 #include	"fns.h"
 #include	"io.h"
+#include	"../port/pci.h"
 #include	"../port/error.h"
 #include	"../port/usb.h"
 #include	"usbehci.h"
--- a/sys/src/9/pc/usbohci.c
+++ b/sys/src/9/pc/usbohci.c
@@ -16,6 +16,7 @@
 #include	"dat.h"
 #include	"fns.h"
 #include	"io.h"
+#include	"../port/pci.h"
 #include	"../port/error.h"
 
 #include	"../port/usb.h"
--- a/sys/src/9/pc/usbuhci.c
+++ b/sys/src/9/pc/usbuhci.c
@@ -14,6 +14,7 @@
 #include	"dat.h"
 #include	"fns.h"
 #include	"io.h"
+#include	"../port/pci.h"
 #include	"../port/error.h"
 #include	"../port/usb.h"
 
@@ -2131,7 +2132,7 @@
 		case 0:
 			if((p->mem[4].bar & 1) == 0)
 				continue;
-			io = (int)p->mem[4].bar & ~0xF;
+			io = p->mem[4].bar & ~3;
 			break;
 		default:
 			continue;
--- a/sys/src/9/pc/vga3dfx.c
+++ b/sys/src/9/pc/vga3dfx.c
@@ -4,6 +4,7 @@
 #include "dat.h"
 #include "fns.h"
 #include "io.h"
+#include "../port/pci.h"
 #include "../port/error.h"
 
 #define	Image	IMAGE
--- a/sys/src/9/pc/vgaclgd546x.c
+++ b/sys/src/9/pc/vgaclgd546x.c
@@ -4,6 +4,7 @@
 #include "dat.h"
 #include "fns.h"
 #include "io.h"
+#include "../port/pci.h"
 #include "../port/error.h"
 
 #define	Image	IMAGE
--- a/sys/src/9/pc/vgacyber938x.c
+++ b/sys/src/9/pc/vgacyber938x.c
@@ -4,6 +4,7 @@
 #include "dat.h"
 #include "fns.h"
 #include "io.h"
+#include "../port/pci.h"
 #include "../port/error.h"
 
 #define	Image	IMAGE
--- a/sys/src/9/pc/vgageode.c
+++ b/sys/src/9/pc/vgageode.c
@@ -4,6 +4,7 @@
 #include "dat.h"
 #include "fns.h"
 #include "io.h"
+#include "../port/pci.h"
 #include "../port/error.h"
 
 #define	Image	IMAGE
--- a/sys/src/9/pc/vgahiqvideo.c
+++ b/sys/src/9/pc/vgahiqvideo.c
@@ -4,6 +4,7 @@
 #include "dat.h"
 #include "fns.h"
 #include "io.h"
+#include "../port/pci.h"
 #include "../port/error.h"
 
 #define	Image	IMAGE
--- a/sys/src/9/pc/vgai81x.c
+++ b/sys/src/9/pc/vgai81x.c
@@ -4,6 +4,7 @@
 #include "dat.h"
 #include "fns.h"
 #include "io.h"
+#include "../port/pci.h"
 #include "../port/error.h"
 
 #define	Image	IMAGE
--- a/sys/src/9/pc/vgaigfx.c
+++ b/sys/src/9/pc/vgaigfx.c
@@ -4,6 +4,7 @@
 #include "dat.h"
 #include "fns.h"
 #include "io.h"
+#include "../port/pci.h"
 #include "../port/error.h"
 
 #define	Image	IMAGE
--- a/sys/src/9/pc/vgamach64xx.c
+++ b/sys/src/9/pc/vgamach64xx.c
@@ -4,6 +4,7 @@
 #include "dat.h"
 #include "fns.h"
 #include "io.h"
+#include "../port/pci.h"
 #include "../port/error.h"
 
 #define	Image	IMAGE
--- a/sys/src/9/pc/vgamga2164w.c
+++ b/sys/src/9/pc/vgamga2164w.c
@@ -4,6 +4,7 @@
 #include "dat.h"
 #include "fns.h"
 #include "io.h"
+#include "../port/pci.h"
 #include "../port/error.h"
 
 #define	Image	IMAGE
--- a/sys/src/9/pc/vgamga4xx.c
+++ b/sys/src/9/pc/vgamga4xx.c
@@ -14,6 +14,7 @@
 #include "dat.h"
 #include "fns.h"
 #include "io.h"
+#include "../port/pci.h"
 #include "../port/error.h"
 
 #define	Image IMAGE
--- a/sys/src/9/pc/vganeomagic.c
+++ b/sys/src/9/pc/vganeomagic.c
@@ -4,6 +4,7 @@
 #include "dat.h"
 #include "fns.h"
 #include "io.h"
+#include "../port/pci.h"
 #include "../port/error.h"
 
 #define	Image	IMAGE
--- a/sys/src/9/pc/vganvidia.c
+++ b/sys/src/9/pc/vganvidia.c
@@ -46,6 +46,7 @@
 #include "dat.h"
 #include "fns.h"
 #include "io.h"
+#include "../port/pci.h"
 #include "../port/error.h"
 
 #define	Image	IMAGE
--- a/sys/src/9/pc/vgaradeon.c
+++ b/sys/src/9/pc/vgaradeon.c
@@ -8,6 +8,7 @@
 #include "dat.h"
 #include "fns.h"
 #include "io.h"
+#include "../port/pci.h"
 #include "../port/error.h"
 
 #define Image	IMAGE
--- a/sys/src/9/pc/vgas3.c
+++ b/sys/src/9/pc/vgas3.c
@@ -4,6 +4,7 @@
 #include "dat.h"
 #include "fns.h"
 #include "io.h"
+#include "../port/pci.h"
 #include "../port/error.h"
 
 #define	Image	IMAGE
--- a/sys/src/9/pc/vgat2r4.c
+++ b/sys/src/9/pc/vgat2r4.c
@@ -4,6 +4,7 @@
 #include "dat.h"
 #include "fns.h"
 #include "io.h"
+#include "../port/pci.h"
 #include "../port/error.h"
 
 #define	Image	IMAGE
--- a/sys/src/9/pc/vgavesa.c
+++ b/sys/src/9/pc/vgavesa.c
@@ -7,6 +7,7 @@
 #include "dat.h"
 #include "fns.h"
 #include "io.h"
+#include "../port/pci.h"
 #include "../port/error.h"
 
 #define Ureg Ureg386
--- a/sys/src/9/pc/vgavmware.c
+++ b/sys/src/9/pc/vgavmware.c
@@ -4,6 +4,7 @@
 #include "dat.h"
 #include "fns.h"
 #include "io.h"
+#include "../port/pci.h"
 #include "../port/error.h"
 
 #define	Image	IMAGE
--- a/sys/src/9/pc64/fns.h
+++ b/sys/src/9/pc64/fns.h
@@ -124,32 +124,10 @@
 void	outsl(int, void*, int);
 uintptr	paddr(void*);
 void	patwc(void*, int);
-ulong	pcibarsize(Pcidev*, int);
-void	pcibussize(Pcidev*, uvlong*, ulong*);
-int	pcicfgr8(Pcidev*, int);
-int	pcicfgr16(Pcidev*, int);
-int	pcicfgr32(Pcidev*, int);
-void	pcicfgw8(Pcidev*, int, int);
-void	pcicfgw16(Pcidev*, int, int);
-void	pcicfgw32(Pcidev*, int, int);
-void	pciclrbme(Pcidev*);
-void	pciclrioe(Pcidev*);
-void	pciclrmwi(Pcidev*);
-int	pcigetpms(Pcidev*);
-void	pcihinv(Pcidev*);
-uchar	pciipin(Pcidev*, uchar);
-Pcidev* pcimatch(Pcidev*, int, int);
-Pcidev* pcimatchtbdf(int);
-int	pcicap(Pcidev*, int);
-int	pcihtcap(Pcidev*, int);
-void	pcireset(void);
-int	pciscan(int, Pcidev**);
-void	pcisetbme(Pcidev*);
-void	pcisetioe(Pcidev*);
-void	pcisetmwi(Pcidev*);
-int	pcisetpms(Pcidev*, int);
-void	pcienable(Pcidev*);
-void	pcidisable(Pcidev*);
+void	pcicfginit(void);
+int	(*pcicfgrw8)(int, int, int, int);
+int	(*pcicfgrw16)(int, int, int, int);
+int	(*pcicfgrw32)(int, int, int, int);
 void	pcmcisread(PCMslot*);
 int	pcmcistuple(int, int, int, void*, int);
 PCMmap*	pcmmap(int, ulong, int, int);
@@ -192,6 +170,7 @@
 ulong	umballoc(ulong, ulong, ulong);
 void	umbfree(ulong, ulong);
 uvlong	upaalloc(uvlong, ulong, ulong);
+uvlong	upaallocwin(uvlong, ulong, ulong, ulong);
 void	upafree(uvlong, ulong);
 void	vectortable(void);
 void	vmxprocrestore(Proc *);
--- a/sys/src/9/pc64/main.c
+++ b/sys/src/9/pc64/main.c
@@ -190,6 +190,7 @@
 	ramdiskinit();
 	confinit();
 	xinit();
+	pcicfginit();
 	bootscreeninit();
 	if(i8237alloc != nil)
 		i8237alloc();
@@ -207,7 +208,6 @@
 	initseg();
 	if(delaylink){
 		bootlinks();
-		pcimatch(0, 0, 0);
 	}else
 		links();
 	chandevreset();
--- a/sys/src/9/pc64/pc64
+++ b/sys/src/9/pc64/pc64
@@ -26,7 +26,7 @@
 	draw		screen vga vgax vgasoft
 	mouse		mouse
 	kbd
-	vga
+	vga		pci
 
 	sd
 #	floppy		dma
@@ -44,9 +44,9 @@
 	dtracy
 
 link
-#	devpccard
+#	devpccard	pci
 #	devi82365
-	cputemp
+	cputemp		pci
 #	ether2000	ether8390
 #	ether2114x	pci
 #	ether589	etherelnk3
@@ -82,16 +82,17 @@
 #	pcmciamodem
 	netdevmedium
 	loopbackmedium
-	usbuhci
-	usbohci
-	usbehci		usbehcipc
+	usbuhci		pci
+	usbohci		pci
+	usbehci		pci usbehcipc
 	usbxhci		pci
 
 #	audiosb16	dma
-#	audioac97	audioac97mix
-	audiohda
+#	audioac97	pci audioac97mix
+	audiohda	pci
 
 misc
+	pci		pcipc
 	archacpi	mp apic squidboy ec
 	archmp		mp apic squidboy
 	mtrr
--- a/sys/src/9/port/devpnp.c
+++ b/sys/src/9/port/devpnp.c
@@ -14,6 +14,7 @@
 #include	"dat.h"
 #include	"fns.h"
 #include	"io.h"
+#include	"../port/pci.h"
 #include	"../port/error.h"
 
 typedef struct Pnp Pnp;
--- /dev/null
+++ b/sys/src/9/port/pci.c
@@ -1,0 +1,1024 @@
+#include "u.h"
+#include "../port/lib.h"
+#include "mem.h"
+#include "dat.h"
+#include "fns.h"
+#include "io.h"
+#include "../port/pci.h"
+
+typedef struct Pcisiz Pcisiz;
+struct Pcisiz
+{
+	Pcidev*	dev;
+	int	siz;
+	int	bar;
+	int	typ;
+};
+
+int pcimaxdno;
+
+static Lock pcicfglock;
+static Pcidev* pcilist;
+static Pcidev* pcitail;
+
+static char* bustypes[] = {
+	"CBUSI",
+	"CBUSII",
+	"EISA",
+	"FUTURE",
+	"INTERN",
+	"ISA",
+	"MBI",
+	"MBII",
+	"MCA",
+	"MPI",
+	"MPSA",
+	"NUBUS",
+	"PCI",
+	"PCMCIA",
+	"TC",
+	"VL",
+	"VME",
+	"XPRESS",
+};
+
+int
+tbdffmt(Fmt* fmt)
+{
+	int type, tbdf;
+
+	switch(fmt->r){
+	default:
+		return fmtstrcpy(fmt, "(tbdffmt)");
+
+	case 'T':
+		tbdf = va_arg(fmt->args, int);
+		if(tbdf == BUSUNKNOWN) {
+			return fmtstrcpy(fmt, "unknown");
+		} else {
+			type = BUSTYPE(tbdf);
+			if(type < nelem(bustypes)) {
+				return fmtprint(fmt, "%s.%d.%d.%d",
+					bustypes[type], BUSBNO(tbdf), BUSDNO(tbdf), BUSFNO(tbdf));
+			} else {
+				return fmtprint(fmt, "%d.%d.%d.%d",
+					type, BUSBNO(tbdf), BUSDNO(tbdf), BUSFNO(tbdf));
+			}
+		}
+	}
+}
+
+int
+pcicfgr8(Pcidev* p, int rno)
+{
+	int data;
+
+	ilock(&pcicfglock);
+	data = pcicfgrw8(p->tbdf, rno, 0, 1);
+	iunlock(&pcicfglock);
+
+	return data;
+}
+void
+pcicfgw8(Pcidev* p, int rno, int data)
+{
+	ilock(&pcicfglock);
+	pcicfgrw8(p->tbdf, rno, data, 0);
+	iunlock(&pcicfglock);
+}
+int
+pcicfgr16(Pcidev* p, int rno)
+{
+	int data;
+
+	ilock(&pcicfglock);
+	data = pcicfgrw16(p->tbdf, rno, 0, 1);
+	iunlock(&pcicfglock);
+
+	return data;
+}
+void
+pcicfgw16(Pcidev* p, int rno, int data)
+{
+	ilock(&pcicfglock);
+	pcicfgrw16(p->tbdf, rno, data, 0);
+	iunlock(&pcicfglock);
+}
+int
+pcicfgr32(Pcidev* p, int rno)
+{
+	int data;
+
+	ilock(&pcicfglock);
+	data = pcicfgrw32(p->tbdf, rno, 0, 1);
+	iunlock(&pcicfglock);
+
+	return data;
+}
+void
+pcicfgw32(Pcidev* p, int rno, int data)
+{
+	ilock(&pcicfglock);
+	pcicfgrw32(p->tbdf, rno, data, 0);
+	iunlock(&pcicfglock);
+}
+
+int
+pcibarsize(Pcidev *p, int rno)
+{
+	int v, size;
+
+	ilock(&pcicfglock);
+	v = pcicfgrw32(p->tbdf, rno, 0, 1);
+	pcicfgrw32(p->tbdf, rno, -1, 0);
+	size = pcicfgrw32(p->tbdf, rno, 0, 1);
+	pcicfgrw32(p->tbdf, rno, v, 0);
+	iunlock(&pcicfglock);
+
+	if(v & 1){
+		size = (short)size;
+		size &= ~3;
+	} else {
+		size &= ~0xF;
+	}
+	return -size;
+}
+
+void
+pcisetbar(Pcidev *p, int rno, uvlong bar)
+{
+	ilock(&pcicfglock);
+	pcicfgrw32(p->tbdf, rno, bar, 0);
+	if((bar&7) == 4 && rno >= PciBAR0 && rno < PciBAR0+4*(nelem(p->mem)-1))
+		pcicfgrw32(p->tbdf, rno+4, bar>>32, 0);
+	iunlock(&pcicfglock);
+}
+
+void
+pcisetwin(Pcidev *p, uvlong base, uvlong limit)
+{
+	ilock(&pcicfglock);
+	if(base & 1){
+		pcicfgrw16(p->tbdf, PciIBR, (limit & 0xF000)|((base & 0xF000)>>8), 0);
+		pcicfgrw32(p->tbdf, PciIUBR, (limit & 0xFFFF0000)|(base>>16), 0);
+	} else if(base & 8){
+		pcicfgrw32(p->tbdf, PciPMBR, (limit & 0xFFF00000)|((base & 0xFFF00000)>>16), 0);
+		pcicfgrw32(p->tbdf, PciPUBR, base >> 32, 0);
+		pcicfgrw32(p->tbdf, PciPULR, limit >> 32, 0);
+	} else {
+		pcicfgrw32(p->tbdf, PciMBR, (limit & 0xFFF00000)|((base & 0xFFF00000)>>16), 0);
+	}
+	iunlock(&pcicfglock);
+}
+
+static int
+pcisizcmp(void *a, void *b)
+{
+	Pcisiz *aa, *bb;
+
+	aa = a;
+	bb = b;
+	return aa->siz - bb->siz;
+}
+
+static ulong
+pcimask(ulong v)
+{
+	ulong m;
+
+	m = BI2BY*sizeof(v);
+	for(m = 1<<(m-1); m != 0; m >>= 1) {
+		if(m & v)
+			break;
+	}
+
+	m--;
+	if((v & m) == 0)
+		return v;
+
+	v |= m;
+	return v+1;
+}
+
+void
+pcibusmap(Pcidev *root, uvlong *pmema, ulong *pioa, int wrreg)
+{
+	Pcidev *p;
+	int ntb, i, size, rno, hole;
+	uvlong mema, smema;
+	ulong ioa, sioa, v;
+	Pcisiz *table, *tptr, *mtb, *itb;
+
+	ioa = *pioa;
+	mema = *pmema;
+
+	ntb = 0;
+	for(p = root; p != nil; p = p->link)
+		ntb++;
+
+	ntb *= (PciCIS-PciBAR0)/4;
+	table = malloc(2*ntb*sizeof(Pcisiz));
+	if(table == nil)
+		panic("pcibusmap: can't allocate memory");
+	itb = table;
+	mtb = table+ntb;
+
+	/*
+	 * Build a table of sizes
+	 */
+	for(p = root; p != nil; p = p->link) {
+		if(p->ccrb == 0x06) {
+			if(p->ccru != 0x04 || p->bridge == nil)
+				continue;
+
+			sioa = ioa;
+			smema = mema;
+			pcibusmap(p->bridge, &smema, &sioa, 0);
+
+			hole = pcimask(sioa-ioa);
+			if(hole < (1<<12))
+				hole = 1<<12;
+			itb->dev = p;
+			itb->bar = -1;
+			itb->siz = hole;
+			itb->typ = 0;
+			itb++;
+
+			hole = pcimask(smema-mema);
+			if(hole < (1<<20))
+				hole = 1<<20;
+			mtb->dev = p;
+			mtb->bar = -1;
+			mtb->siz = hole;
+			mtb->typ = 0;
+			mtb++;
+			continue;
+		}
+
+		for(i = 0; i < nelem(p->mem); i++) {
+			rno = PciBAR0 + i*4;
+			v = pcicfgr32(p, rno);
+			size = pcibarsize(p, rno);
+			if(size == 0)
+				continue;
+			if(v & 1) {
+				itb->dev = p;
+				itb->bar = i;
+				itb->siz = size;
+				itb->typ = 1;
+				itb++;
+			} else {
+				mtb->dev = p;
+				mtb->bar = i;
+				mtb->siz = size;
+				mtb->typ = v & 7;
+				if(mtb->typ & 4)
+					i++;
+				mtb++;
+			}
+		}
+	}
+
+	/*
+	 * Sort both tables IO smallest first, Memory largest
+	 */
+	qsort(table, itb-table, sizeof(Pcisiz), pcisizcmp);
+	tptr = table+ntb;
+	qsort(tptr, mtb-tptr, sizeof(Pcisiz), pcisizcmp);
+
+	/*
+	 * Allocate IO address space on this bus
+	 */
+	for(tptr = table; tptr < itb; tptr++) {
+		hole = tptr->siz;
+		if(tptr->bar == -1)
+			hole = 1<<12;
+		ioa = (ioa+hole-1) & ~(hole-1);
+		if(wrreg){
+			p = tptr->dev;
+			if(tptr->bar == -1) {
+				p->ioa.bar = ioa;
+				p->ioa.size = tptr->siz;
+			} else {
+				p->mem[tptr->bar].size = tptr->siz;
+				p->mem[tptr->bar].bar = ioa|1;
+				pcisetbar(p, PciBAR0+tptr->bar*4, p->mem[tptr->bar].bar);
+			}
+		}
+		ioa += tptr->siz;
+	}
+
+	/*
+	 * Allocate Memory address space on this bus
+	 */
+	for(tptr = table+ntb; tptr < mtb; tptr++) {
+		hole = tptr->siz;
+		if(tptr->bar == -1)
+			hole = 1<<20;
+		mema = (mema+hole-1) & ~((uvlong)hole-1);
+		if(wrreg){
+			p = tptr->dev;
+			if(tptr->bar == -1) {
+				p->mema.bar = mema;
+				p->mema.size = tptr->siz;
+			} else {
+				p->mem[tptr->bar].size = tptr->siz;
+				p->mem[tptr->bar].bar = mema|tptr->typ;
+				pcisetbar(p, PciBAR0+tptr->bar*4, p->mem[tptr->bar].bar);
+			}
+		}
+		mema += tptr->siz;
+	}
+
+	*pmema = mema;
+	*pioa = ioa;
+	free(table);
+
+	if(wrreg == 0)
+		return;
+
+	/*
+	 * Finally set all the bridge addresses & registers
+	 */
+	for(p = root; p != nil; p = p->link) {
+		if(p->bridge == nil) {
+			pcienable(p);
+			continue;
+		}
+
+		/* Set I/O and Mem windows */
+		pcisetwin(p, p->ioa.bar|1, p->ioa.bar+p->ioa.size-1);
+		pcisetwin(p, p->mema.bar|0, p->mema.bar+p->mema.size-1);
+
+		/* Disable prefetch */
+		pcisetwin(p, 0xFFF00000|8, 0);
+
+		/* Enable the bridge */
+		pcienable(p);
+
+		sioa = p->ioa.bar;
+		smema = p->mema.bar;
+		pcibusmap(p->bridge, &smema, &sioa, 1);
+	}
+}
+
+static int
+pcivalidwin(Pcidev *p, uvlong base, uvlong limit)
+{
+	Pcidev *bridge = p->parent;
+	char *typ;
+
+	if(base & 1){
+		typ = "io";
+		base &= ~3;
+		if(base > limit)
+			return 0;
+		if(bridge == nil)
+			return 1;
+		if(base >= bridge->ioa.bar && limit < (bridge->ioa.bar + bridge->ioa.size))
+			return 1;
+	} else {
+		typ = "mem";
+		base &= ~0xFULL;
+		if(base > limit)
+			return 0;
+		if(bridge == nil)
+			return 1;
+		if(base >= bridge->mema.bar && limit < (bridge->mema.bar + bridge->mema.size))
+			return 1;
+		if(base >= bridge->prefa.bar && limit < (bridge->prefa.bar + bridge->prefa.size))
+			return 1;
+	}
+	print("%T: %.2uX invalid %s-window: %.8llux-%.8llux\n", p->tbdf, p->ccrb, typ, base, limit);
+	return 0;
+}
+
+static int
+pcivalidbar(Pcidev *p, uvlong bar, int size)
+{
+	if(bar & 1){
+		bar &= ~3;
+		if(bar == 0 || size < 4 || (bar & (size-1)) != 0)
+			return 0;
+		return pcivalidwin(p, bar|1, bar+size-1);
+	} else {
+		bar &= ~0xFULL;
+		if(bar == 0 || size < 16 || (bar & (size-1)) != 0)
+			return 0;
+		return pcivalidwin(p, bar|0, bar+size-1);
+	}
+}
+
+static int
+pcilscan(int bno, Pcidev** list, Pcidev *parent)
+{
+	Pcidev *p, *head, *tail;
+	int dno, fno, i, hdt, l, maxfno, maxubn, rno, sbn, tbdf, ubn;
+
+	maxubn = bno;
+	head = nil;
+	tail = nil;
+	for(dno = 0; dno <= pcimaxdno; dno++){
+		maxfno = 0;
+		for(fno = 0; fno <= maxfno; fno++){
+			/*
+			 * For this possible device, form the
+			 * bus+device+function triplet needed to address it
+			 * and try to read the vendor and device ID.
+			 * If successful, allocate a device struct and
+			 * start to fill it in with some useful information
+			 * from the device's configuration space.
+			 */
+			tbdf = MKBUS(BusPCI, bno, dno, fno);
+
+			lock(&pcicfglock);
+			l = pcicfgrw32(tbdf, PciVID, 0, 1);
+			unlock(&pcicfglock);
+
+			if(l == 0xFFFFFFFF || l == 0)
+				continue;
+			p = malloc(sizeof(*p));
+			if(p == nil)
+				panic("pcilscan: can't allocate memory");
+			p->tbdf = tbdf;
+			p->vid = l;
+			p->did = l>>16;
+
+			if(pcilist != nil)
+				pcitail->list = p;
+			else
+				pcilist = p;
+			pcitail = p;
+
+			p->pcr = pcicfgr16(p, PciPCR);
+			p->rid = pcicfgr8(p, PciRID);
+			p->ccrp = pcicfgr8(p, PciCCRp);
+			p->ccru = pcicfgr8(p, PciCCRu);
+			p->ccrb = pcicfgr8(p, PciCCRb);
+			p->cls = pcicfgr8(p, PciCLS);
+			p->ltr = pcicfgr8(p, PciLTR);
+			p->intl = pcicfgr8(p, PciINTL);
+
+			/*
+			 * If the device is a multi-function device adjust the
+			 * loop count so all possible functions are checked.
+			 */
+			hdt = pcicfgr8(p, PciHDT);
+			if(hdt & 0x80)
+				maxfno = MaxFNO;
+
+			/*
+			 * If appropriate, read the base address registers
+			 * and work out the sizes.
+			 */
+			switch(p->ccrb) {
+			case 0x00:		/* prehistoric */
+			case 0x01:		/* mass storage controller */
+			case 0x02:		/* network controller */
+			case 0x03:		/* display controller */
+			case 0x04:		/* multimedia device */
+			case 0x07:		/* simple comm. controllers */
+			case 0x08:		/* base system peripherals */
+			case 0x09:		/* input devices */
+			case 0x0A:		/* docking stations */
+			case 0x0B:		/* processors */
+			case 0x0C:		/* serial bus controllers */
+			case 0x0D:		/* wireless controllers */
+			case 0x0E:		/* intelligent I/O controllers */
+			case 0x0F:		/* sattelite communication controllers */
+			case 0x10:		/* encryption/decryption controllers */
+			case 0x11:		/* signal processing controllers */
+				if((hdt & 0x7F) != 0)
+					break;
+				rno = PciBAR0;
+				for(i = 0; i < nelem(p->mem); i++) {
+					p->mem[i].bar = (ulong)pcicfgr32(p, rno);
+					p->mem[i].size = pcibarsize(p, rno);
+					if((p->mem[i].bar & 7) == 4 && i < nelem(p->mem)-1){
+						rno += 4;
+						p->mem[i++].bar |= (uvlong)pcicfgr32(p, rno) << 32;
+						p->mem[i].bar = 0;
+						p->mem[i].size = 0;
+					}
+					rno += 4;
+				}
+				break;
+
+			case 0x05:		/* memory controller */
+			case 0x06:		/* bridge device */
+			default:
+				break;
+			}
+
+			p->parent = parent;
+			if(head != nil)
+				tail->link = p;
+			else
+				head = p;
+			tail = p;
+		}
+	}
+
+	*list = head;
+	for(p = head; p != nil; p = p->link){
+		/*
+		 * Find PCI-PCI bridges and recursively descend the tree.
+		 */
+		switch(p->ccrb) {
+		case 0x06:
+			if(p->ccru == 0x04)
+				break;
+		default:
+			for(i = 0; i < nelem(p->mem); i++) {
+				if(p->mem[i].size == 0)
+					continue;
+				if(!pcivalidbar(p, p->mem[i].bar, p->mem[i].size)){
+					if(p->mem[i].bar & 1)
+						p->mem[i].bar &= 3;
+					else
+						p->mem[i].bar &= 0xF;
+					pcisetbar(p, PciBAR0 + i*4, p->mem[i].bar);
+				}
+			}
+			continue;
+		}
+
+		/*
+		 * If the secondary or subordinate bus number is not
+		 * initialised try to do what the PCI BIOS should have
+		 * done and fill in the numbers as the tree is descended.
+		 * On the way down the subordinate bus number is set to
+		 * the maximum as it's not known how many buses are behind
+		 * this one; the final value is set on the way back up.
+		 */
+		sbn = pcicfgr8(p, PciSBN);
+		ubn = pcicfgr8(p, PciUBN);
+
+		if(sbn == 0 || ubn == 0) {
+			sbn = maxubn+1;
+			/*
+			 * Make sure memory, I/O and master enables are
+			 * off, set the primary, secondary and subordinate
+			 * bus numbers and clear the secondary status before
+			 * attempting to scan the secondary bus.
+			 *
+			 * Initialisation of the bridge should be done here.
+			 */
+			p->pcr = 0;
+			pcicfgw32(p, PciPCR, 0xFFFF0000);
+			l = (MaxUBN<<16)|(sbn<<8)|bno;
+			pcicfgw32(p, PciPBN, l);
+			pcicfgw16(p, PciSPSR, 0xFFFF);
+
+			p->ioa.bar = 0;
+			p->ioa.size = 0;
+			p->mema.bar = 0;
+			p->mema.size = 0;
+			p->prefa.bar = 0;
+			p->prefa.size = 0;
+
+			pcisetwin(p, 0xFFFFF000|1, 0);
+			pcisetwin(p, 0xFFF00000|0, 0);
+			pcisetwin(p, 0xFFF00000|8, 0);
+
+			maxubn = pcilscan(sbn, &p->bridge, p);
+			l = (maxubn<<16)|(sbn<<8)|bno;
+
+			pcicfgw32(p, PciPBN, l);
+		}
+		else {
+			uvlong base, limit;
+			ulong v;
+
+			v = pcicfgr16(p, PciIBR);
+			limit = (v & 0xF000) | 0x0FFF;
+			base  = (v & 0x00F0) << 8;
+			if((v & 0x0F) == 0x01){
+				v = pcicfgr32(p, PciIUBR);
+				limit |= (v & 0xFFFF0000);
+				base  |= (v & 0x0000FFFF) << 16;
+			}
+			if(pcivalidwin(p, base|1, limit)){
+				p->ioa.bar = base;
+				p->ioa.size = (limit - base)+1;
+			} else {
+				pcisetwin(p, 0xFFFFF000|1, 0);
+				p->ioa.bar = 0;
+				p->ioa.size = 0;
+			}
+
+			v = pcicfgr32(p, PciMBR);
+			limit = (v & 0xFFF00000) | 0x000FFFFF;
+			base  = (v & 0x0000FFF0) << 16;
+			if(pcivalidwin(p, base|0, limit)){
+				p->mema.bar = base;
+				p->mema.size = (limit - base)+1;
+			} else {
+				pcisetwin(p, 0xFFF00000|0, 0);
+				p->mema.bar = 0;
+				p->mema.size = 0;
+			}
+
+			v = pcicfgr32(p, PciPMBR);
+			limit = (v & 0xFFF00000) | 0x000FFFFF;
+			limit |= (uvlong)pcicfgr32(p, PciPULR) << 32;
+			base  = (v & 0x0000FFF0) << 16;
+			base  |= (uvlong)pcicfgr32(p, PciPUBR) << 32;
+			if(pcivalidwin(p, base|8, limit)){
+				p->prefa.bar = base;
+				p->prefa.size = (limit - base)+1;
+			} else {
+				pcisetwin(p, 0xFFF00000|8, 0);
+				p->prefa.bar = 0;
+				p->prefa.size = 0;
+			}
+
+			if(ubn > maxubn)
+				maxubn = ubn;
+			pcilscan(sbn, &p->bridge, p);
+		}
+	}
+
+	return maxubn;
+}
+
+int
+pciscan(int bno, Pcidev **list)
+{
+	return pcilscan(bno, list, nil);
+}
+
+void
+pcibussize(Pcidev *root, uvlong *msize, ulong *iosize)
+{
+	*msize = 0;
+	*iosize = 0;
+	pcibusmap(root, msize, iosize, 0);
+}
+
+Pcidev*
+pcimatch(Pcidev* prev, int vid, int did)
+{
+	if(prev == nil)
+		prev = pcilist;
+	else
+		prev = prev->list;
+
+	while(prev != nil){
+		if((vid == 0 || prev->vid == vid)
+		&& (did == 0 || prev->did == did))
+			break;
+		prev = prev->list;
+	}
+	return prev;
+}
+
+Pcidev*
+pcimatchtbdf(int tbdf)
+{
+	Pcidev *pcidev;
+
+	for(pcidev = pcilist; pcidev != nil; pcidev = pcidev->list) {
+		if(pcidev->tbdf == tbdf)
+			break;
+	}
+	return pcidev;
+}
+
+uchar
+pciipin(Pcidev *pci, uchar pin)
+{
+	if (pci == nil)
+		pci = pcilist;
+
+	while (pci != nil) {
+		uchar intl;
+
+		if (pcicfgr8(pci, PciINTP) == pin && pci->intl != 0 && pci->intl != 0xff)
+			return pci->intl;
+
+		if (pci->bridge && (intl = pciipin(pci->bridge, pin)) != 0)
+			return intl;
+
+		pci = pci->list;
+	}
+	return 0;
+}
+
+static void
+pcilhinv(Pcidev* p)
+{
+	int i;
+	Pcidev *t;
+
+	for(t = p; t != nil; t = t->link) {
+		print("%d  %2d/%d %.2ux %.2ux %.2ux %.4ux %.4ux %3d  ",
+			BUSBNO(t->tbdf), BUSDNO(t->tbdf), BUSFNO(t->tbdf),
+			t->ccrb, t->ccru, t->ccrp, t->vid, t->did, t->intl);
+		for(i = 0; i < nelem(p->mem); i++) {
+			if(t->mem[i].size == 0)
+				continue;
+			print("%d:%.8llux %d ", i, t->mem[i].bar, t->mem[i].size);
+		}
+		if(t->ioa.bar || t->ioa.size)
+			print("ioa:%.8llux-%.8llux %d ", t->ioa.bar, t->ioa.bar+t->ioa.size, t->ioa.size);
+		if(t->mema.bar || t->mema.size)
+			print("mema:%.8llux-%.8llux %d ", t->mema.bar, t->mema.bar+t->mema.size, t->mema.size);
+		if(t->prefa.bar || t->prefa.size)
+			print("prefa:%.8llux-%.8llux %llud ", t->prefa.bar, t->prefa.bar+t->prefa.size, t->prefa.size);
+		if(t->bridge)
+			print("->%d", BUSBNO(t->bridge->tbdf));
+		print("\n");
+	}
+	while(p != nil) {
+		if(p->bridge != nil)
+			pcilhinv(p->bridge);
+		p = p->link;
+	}
+}
+
+void
+pcihinv(Pcidev* p)
+{
+	print("bus dev type     vid  did  intl memory\n");
+	pcilhinv(p);
+}
+
+void
+pcireset(void)
+{
+	Pcidev *p;
+
+	for(p = pcilist; p != nil; p = p->list) {
+		/* don't mess with the bridges */
+		if(p->ccrb == 0x06)
+			continue;
+		pciclrbme(p);
+	}
+}
+
+void
+pcisetioe(Pcidev* p)
+{
+	p->pcr |= IOen;
+	pcicfgw16(p, PciPCR, p->pcr);
+}
+
+void
+pciclrioe(Pcidev* p)
+{
+	p->pcr &= ~IOen;
+	pcicfgw16(p, PciPCR, p->pcr);
+}
+
+void
+pcisetbme(Pcidev* p)
+{
+	p->pcr |= MASen;
+	pcicfgw16(p, PciPCR, p->pcr);
+}
+
+void
+pciclrbme(Pcidev* p)
+{
+	p->pcr &= ~MASen;
+	pcicfgw16(p, PciPCR, p->pcr);
+}
+
+void
+pcisetmwi(Pcidev* p)
+{
+	p->pcr |= MemWrInv;
+	pcicfgw16(p, PciPCR, p->pcr);
+}
+
+void
+pciclrmwi(Pcidev* p)
+{
+	p->pcr &= ~MemWrInv;
+	pcicfgw16(p, PciPCR, p->pcr);
+}
+
+static int
+enumcaps(Pcidev *p, int (*fmatch)(Pcidev*, int, int, int), int arg)
+{
+	int i, r, cap, off;
+
+	/* status register bit 4 has capabilities */
+	if((pcicfgr16(p, PciPSR) & 1<<4) == 0)
+		return -1;      
+	switch(pcicfgr8(p, PciHDT) & 0x7F){
+	default:
+		return -1;
+	case 0:                         /* etc */
+	case 1:                         /* pci to pci bridge */
+		off = 0x34;
+		break;
+	case 2:                         /* cardbus bridge */
+		off = 0x14;
+		break;
+	}
+	for(i = 48; i--;){
+		off = pcicfgr8(p, off);
+		if(off < 0x40 || (off & 3))
+			break;
+		off &= ~3;
+		cap = pcicfgr8(p, off);
+		if(cap == 0xff)
+			break;
+		r = (*fmatch)(p, cap, off, arg);
+		if(r < 0)
+			break;
+		if(r == 0)
+			return off;
+		off++;
+	}
+	return -1;
+}
+
+static int
+matchcap(Pcidev *, int cap, int, int arg)
+{
+	return cap != arg;
+}
+
+static int
+matchhtcap(Pcidev *p, int cap, int off, int arg)
+{
+	int mask;
+
+	if(cap != PciCapHTC)
+		return 1;
+	if(arg == 0x00 || arg == 0x20)
+		mask = 0xE0;
+	else
+		mask = 0xF8;
+	cap = pcicfgr8(p, off+3);
+	return (cap & mask) != arg;
+}
+
+int
+pcicap(Pcidev *p, int cap)
+{
+	return enumcaps(p, matchcap, cap);
+}
+
+int
+pcihtcap(Pcidev *p, int cap)
+{
+	return enumcaps(p, matchhtcap, cap);
+}
+
+static int
+pcigetpmrb(Pcidev* p)
+{
+        if(p->pmrb != 0)
+                return p->pmrb;
+        return p->pmrb = pcicap(p, PciCapPMG);
+}
+
+int
+pcigetpms(Pcidev* p)
+{
+	int pmcsr, ptr;
+
+	if((ptr = pcigetpmrb(p)) == -1)
+		return -1;
+
+	/*
+	 * Power Management Register Block:
+	 *  offset 0:	Capability ID
+	 *	   1:	next item pointer
+	 *	   2:	capabilities
+	 *	   4:	control/status
+	 *	   6:	bridge support extensions
+	 *	   7:	data
+	 */
+	pmcsr = pcicfgr16(p, ptr+4);
+
+	return pmcsr & 0x0003;
+}
+
+int
+pcisetpms(Pcidev* p, int state)
+{
+	int ostate, pmc, pmcsr, ptr;
+
+	if((ptr = pcigetpmrb(p)) == -1)
+		return -1;
+
+	pmc = pcicfgr16(p, ptr+2);
+	pmcsr = pcicfgr16(p, ptr+4);
+	ostate = pmcsr & 0x0003;
+	pmcsr &= ~0x0003;
+
+	switch(state){
+	default:
+		return -1;
+	case 0:
+		break;
+	case 1:
+		if(!(pmc & 0x0200))
+			return -1;
+		break;
+	case 2:
+		if(!(pmc & 0x0400))
+			return -1;
+		break;
+	case 3:
+		break;
+	}
+	pmcsr |= state;
+	pcicfgw16(p, ptr+4, pmcsr);
+
+	return ostate;
+}
+
+int
+pcinextcap(Pcidev *pci, int offset)
+{
+	if(offset == 0) {
+		if((pcicfgr16(pci, PciPSR) & (1<<4)) == 0)
+			return 0; /* no capabilities */
+		offset = PciCAP-1;
+	}
+	return pcicfgr8(pci, offset+1) & ~3;
+}
+
+void
+pcienable(Pcidev *p)
+{
+	uint pcr;
+	int i;
+
+	if(p == nil)
+		return;
+
+	pcienable(p->parent);
+
+	switch(pcisetpms(p, 0)){
+	case 1:
+		print("pcienable %T: wakeup from D1\n", p->tbdf);
+		break;
+	case 2:
+		print("pcienable %T: wakeup from D2\n", p->tbdf);
+		if(p->bridge != nil)
+			delay(100);	/* B2: minimum delay 50ms */
+		else
+			delay(1);	/* D2: minimum delay 200µs */
+		break;
+	case 3:
+		print("pcienable %T: wakeup from D3\n", p->tbdf);
+		delay(100);		/* D3: minimum delay 50ms */
+
+		/* restore registers */
+		for(i = 0; i < nelem(p->mem); i++){
+			if(p->mem[i].size == 0)
+				continue;
+			pcisetbar(p, PciBAR0+i*4, p->mem[i].bar);
+		}
+
+		pcicfgw8(p, PciINTL, p->intl);
+		pcicfgw8(p, PciLTR, p->ltr);
+		pcicfgw8(p, PciCLS, p->cls);
+		pcicfgw16(p, PciPCR, p->pcr);
+		break;
+	}
+
+	if(p->ltr == 0 || p->ltr == 0xFF){
+		p->ltr = 64;
+		pcicfgw8(p,PciLTR, p->ltr);
+	}
+	if(p->cls == 0 || p->cls == 0xFF){
+		p->cls = 64/4;
+		pcicfgw8(p, PciCLS, p->cls);
+	}
+
+	if(p->bridge != nil)
+		pcr = IOen|MEMen|MASen;
+	else {
+		pcr = 0;
+		for(i = 0; i < nelem(p->mem); i++){
+			if(p->mem[i].size == 0)
+				continue;
+			if(p->mem[i].bar & 1)
+				pcr |= IOen;
+			else
+				pcr |= MEMen;
+		}
+	}
+
+	if((p->pcr & pcr) != pcr){
+		print("pcienable %T: pcr %ux->%ux\n", p->tbdf, p->pcr, p->pcr|pcr);
+		p->pcr |= pcr;
+		pcicfgw32(p, PciPCR, 0xFFFF0000|p->pcr);
+	}
+}
+
+void
+pcidisable(Pcidev *p)
+{
+	if(p == nil)
+		return;
+	pciclrbme(p);
+}
--- /dev/null
+++ b/sys/src/9/port/pci.h
@@ -1,0 +1,292 @@
+/*
+ * PCI support code.
+ */
+enum {					/* type 0 & type 1 pre-defined header */
+	PciVID		= 0x00,		/* vendor ID */
+	PciDID		= 0x02,		/* device ID */
+	PciPCR		= 0x04,		/* command */
+	PciPSR		= 0x06,		/* status */
+	PciRID		= 0x08,		/* revision ID */
+	PciCCRp		= 0x09,		/* programming interface class code */
+	PciCCRu		= 0x0A,		/* sub-class code */
+	PciCCRb		= 0x0B,		/* base class code */
+	PciCLS		= 0x0C,		/* cache line size */
+	PciLTR		= 0x0D,		/* latency timer */
+	PciHDT		= 0x0E,		/* header type */
+	PciBST		= 0x0F,		/* BIST */
+
+	PciBAR0		= 0x10,		/* base address */
+	PciBAR1		= 0x14,
+
+	PciCAP		= 0x34,		/* capabilities pointer */
+	PciINTL		= 0x3C,		/* interrupt line */
+	PciINTP		= 0x3D,		/* interrupt pin */
+};
+
+/* ccrb (base class code) values; controller types */
+enum {
+	Pcibcpci1	= 0,		/* pci 1.0; no class codes defined */
+	Pcibcstore	= 1,		/* mass storage */
+	Pcibcnet	= 2,		/* network */
+	Pcibcdisp	= 3,		/* display */
+	Pcibcmmedia	= 4,		/* multimedia */
+	Pcibcmem	= 5,		/* memory */
+	Pcibcbridge	= 6,		/* bridge */
+	Pcibccomm	= 7,		/* simple comms (e.g., serial) */
+	Pcibcbasesys	= 8,		/* base system */
+	Pcibcinput	= 9,		/* input */
+	Pcibcdock	= 0xa,		/* docking stations */
+	Pcibcproc	= 0xb,		/* processors */
+	Pcibcserial	= 0xc,		/* serial bus (e.g., USB) */
+	Pcibcwireless	= 0xd,		/* wireless */
+	Pcibcintell	= 0xe,		/* intelligent i/o */
+	Pcibcsatcom	= 0xf,		/* satellite comms */
+	Pcibccrypto	= 0x10,		/* encryption/decryption */
+	Pcibcdacq	= 0x11,		/* data acquisition & signal proc. */
+};
+
+/* ccru (sub-class code) values; common cases only */
+enum {
+	/* mass storage */
+	Pciscscsi	= 0,		/* SCSI */
+	Pciscide	= 1,		/* IDE (ATA) */
+
+	/* network */
+	Pciscether	= 0,		/* Ethernet */
+
+	/* display */
+	Pciscvga	= 0,		/* VGA */
+	Pciscxga	= 1,		/* XGA */
+	Pcisc3d		= 2,		/* 3D */
+
+	/* bridges */
+	Pcischostpci	= 0,		/* host/pci */
+	Pciscpcicpci	= 1,		/* pci/pci */
+
+	/* simple comms */
+	Pciscserial	= 0,		/* 16450, etc. */
+	Pciscmultiser	= 1,		/* multiport serial */
+
+	/* serial bus */
+	Pciscusb	= 3,		/* USB */
+};
+
+enum {					/* type 0 pre-defined header */
+	PciCIS		= 0x28,		/* cardbus CIS pointer */
+	PciSVID		= 0x2C,		/* subsystem vendor ID */
+	PciSID		= 0x2E,		/* subsystem ID */
+	PciEBAR0	= 0x30,		/* expansion ROM base address */
+	PciMGNT		= 0x3E,		/* burst period length */
+	PciMLT		= 0x3F,		/* maximum latency between bursts */
+};
+
+enum {					/* type 1 pre-defined header */
+	PciPBN		= 0x18,		/* primary bus number */
+	PciSBN		= 0x19,		/* secondary bus number */
+	PciUBN		= 0x1A,		/* subordinate bus number */
+	PciSLTR		= 0x1B,		/* secondary latency timer */
+	PciIBR		= 0x1C,		/* I/O base */
+	PciILR		= 0x1D,		/* I/O limit */
+	PciSPSR		= 0x1E,		/* secondary status */
+	PciMBR		= 0x20,		/* memory base */
+	PciMLR		= 0x22,		/* memory limit */
+	PciPMBR		= 0x24,		/* prefetchable memory base */
+	PciPMLR		= 0x26,		/* prefetchable memory limit */
+	PciPUBR		= 0x28,		/* prefetchable base upper 32 bits */
+	PciPULR		= 0x2C,		/* prefetchable limit upper 32 bits */
+	PciIUBR		= 0x30,		/* I/O base upper 16 bits */
+	PciIULR		= 0x32,		/* I/O limit upper 16 bits */
+	PciEBAR1	= 0x28,		/* expansion ROM base address */
+	PciBCR		= 0x3E,		/* bridge control register */
+};
+
+enum {					/* type 2 pre-defined header */
+	PciCBExCA	= 0x10,
+	PciCBSPSR	= 0x16,
+	PciCBPBN	= 0x18,		/* primary bus number */
+	PciCBSBN	= 0x19,		/* secondary bus number */
+	PciCBUBN	= 0x1A,		/* subordinate bus number */
+	PciCBSLTR	= 0x1B,		/* secondary latency timer */
+	PciCBMBR0	= 0x1C,
+	PciCBMLR0	= 0x20,
+	PciCBMBR1	= 0x24,
+	PciCBMLR1	= 0x28,
+	PciCBIBR0	= 0x2C,		/* I/O base */
+	PciCBILR0	= 0x30,		/* I/O limit */
+	PciCBIBR1	= 0x34,		/* I/O base */
+	PciCBILR1	= 0x38,		/* I/O limit */
+	PciCBSVID	= 0x40,		/* subsystem vendor ID */
+	PciCBSID	= 0x42,		/* subsystem ID */
+	PciCBLMBAR	= 0x44,		/* legacy mode base address */
+};
+
+/* capabilities */
+enum {
+	PciCapPMG       = 0x01,         /* power management */
+	PciCapAGP       = 0x02,
+	PciCapVPD       = 0x03,         /* vital product data */
+	PciCapSID       = 0x04,         /* slot id */
+	PciCapMSI       = 0x05,
+	PciCapCHS       = 0x06,         /* compact pci hot swap */
+	PciCapPCIX      = 0x07,
+	PciCapHTC       = 0x08,         /* hypertransport irq conf */
+	PciCapVND       = 0x09,         /* vendor specific information */
+	PciCapPCIe      = 0x10,
+	PciCapMSIX      = 0x11,
+	PciCapSATA      = 0x12,
+	PciCapHSW       = 0x0c,         /* hot swap */
+};
+
+enum {
+	/* bar bits */
+	Barioaddr	= 1<<0,		/* vs. memory addr */
+	Barwidthshift	= 1,
+	Barwidthmask	= 3,
+	Barwidth32	= 0,
+	Barwidth64	= 2,
+	Barprefetch	= 1<<3,
+};
+
+enum
+{					/* command register */
+	IOen		= (1<<0),
+	MEMen		= (1<<1),
+	MASen		= (1<<2),
+	MemWrInv	= (1<<4),
+	PErrEn		= (1<<6),
+	SErrEn		= (1<<8),
+};
+
+typedef struct Pcidev Pcidev;
+struct Pcidev
+{
+	int	tbdf;			/* type+bus+device+function */
+	ushort	vid;			/* vendor ID */
+	ushort	did;			/* device ID */
+
+	ushort	pcr;
+
+	uchar	rid;
+	uchar	ccrp;
+	uchar	ccru;
+	uchar	ccrb;
+	uchar	cls;
+	uchar	ltr;
+
+	struct {
+		uvlong	bar;		/* base address */
+		int	size;
+	} mem[6];
+
+	struct {
+		uvlong	bar;	
+		int	size;
+	} rom;
+	uchar	intl;			/* interrupt line */
+
+	Pcidev*	list;
+	Pcidev*	link;			/* next device on this bno */
+
+	Pcidev*	parent;			/* up a bus */
+	Pcidev*	bridge;			/* down a bus */
+	struct {
+		uvlong	bar;
+		int	size;
+	} ioa, mema;
+	struct {
+		uvlong	bar;
+		uvlong	size;
+	} prefa;
+
+	int	pmrb;			/* power management register block */
+};
+
+enum {
+	/* vendor ids */
+	Vintel	= 0x8086,
+	Vmyricom= 0x14c1,
+	Vatiamd	= 0x1002,
+	Vjmicron= 0x197b,
+	Vmarvell= 0x1b4b,
+	Vnvidia	= 0x10de,
+	Vrealtek= 0x10ec,
+};
+
+enum
+{
+	MaxFNO		= 7,
+	MaxUBN		= 255,
+};
+
+extern int pcimaxdno;
+
+extern int pcicfgr32(Pcidev* pcidev, int rno);
+extern void pcicfgw32(Pcidev* pcidev, int rno, int data);
+extern int pcicfgr16(Pcidev* pcidev, int rno);
+extern void pcicfgw16(Pcidev* pcidev, int rno, int data);
+extern int pcicfgr8(Pcidev* pcidev, int rno);
+extern void pcicfgw8(Pcidev* pcidev, int rno, int data);
+
+extern int pciscan(int bno, Pcidev **list);
+extern void pcibusmap(Pcidev *root, uvlong *pmema, ulong *pioa, int wrreg);
+extern void pcibussize(Pcidev *root, uvlong *msize, ulong *iosize);
+
+extern Pcidev* pcimatch(Pcidev* prev, int vid, int did);
+extern Pcidev* pcimatchtbdf(int tbdf);
+
+extern int pcibarsize(Pcidev *, int rno);
+extern void pcisetbar(Pcidev *, int, uvlong);
+
+extern uchar pciipin(Pcidev *pci, uchar pin);
+
+extern void pcisetioe(Pcidev* p);
+extern void pciclrioe(Pcidev* p);
+extern void pcisetbme(Pcidev* p);
+extern void pciclrbme(Pcidev* p);
+extern void pcisetmwi(Pcidev* p);
+extern void pciclrmwi(Pcidev* p);
+
+extern int pcicap(Pcidev *p, int cap);
+extern int pcinextcap(Pcidev *pci, int offset);
+extern int pcihtcap(Pcidev *p, int cap);
+extern int pcigetpms(Pcidev* p);
+extern int pcisetpms(Pcidev* p, int state);
+
+extern void pcienable(Pcidev *p);
+extern void pcidisable(Pcidev *p);
+
+extern void pcihinv(Pcidev* p);
+extern void pcireset(void);
+
+enum {
+	BusCBUS		= 0,		/* Corollary CBUS */
+	BusCBUSII,			/* Corollary CBUS II */
+	BusEISA,			/* Extended ISA */
+	BusFUTURE,			/* IEEE Futurebus */
+	BusINTERN,			/* Internal bus */
+	BusISA,				/* Industry Standard Architecture */
+	BusMBI,				/* Multibus I */
+	BusMBII,			/* Multibus II */
+	BusMCA,				/* Micro Channel Architecture */
+	BusMPI,				/* MPI */
+	BusMPSA,			/* MPSA */
+	BusNUBUS,			/* Apple Macintosh NuBus */
+	BusPCI,				/* Peripheral Component Interconnect */
+	BusPCMCIA,			/* PC Memory Card International Association */
+	BusTC,				/* DEC TurboChannel */
+	BusVL,				/* VESA Local bus */
+	BusVME,				/* VMEbus */
+	BusXPRESS,			/* Express System Bus */
+};
+
+#define MKBUS(t,b,d,f)	(((t)<<24)|(((b)&0xFF)<<16)|(((d)&0x1F)<<11)|(((f)&0x07)<<8))
+#define BUSFNO(tbdf)	(((tbdf)>>8)&0x07)
+#define BUSDNO(tbdf)	(((tbdf)>>11)&0x1F)
+#define BUSBNO(tbdf)	(((tbdf)>>16)&0xFF)
+#define BUSTYPE(tbdf)	((tbdf)>>24)
+#define BUSBDF(tbdf)	((tbdf)&0x00FFFF00)
+
+extern int tbdffmt(Fmt*);
+
+#pragma varargck	type	"T"	int
+#pragma varargck	type	"T"	uint
--- a/sys/src/9/port/portmkfile
+++ b/sys/src/9/port/portmkfile
@@ -40,7 +40,7 @@
 nuke:V:	clean
 	rm -f ../boot/libboot.a$O *.elf *.rr *.acid
 
-%.$O:	/$objtype/include/u.h ../port/lib.h mem.h dat.h fns.h io.h ../port/error.h ../port/portdat.h ../port/portfns.h
+%.$O:	/$objtype/include/u.h ../port/lib.h mem.h dat.h fns.h io.h ../port/pci.h ../port/error.h ../port/portdat.h ../port/portfns.h
 
 ../port/systab.h:D:	/sys/src/libc/9syscall/sys.h ../port/mksystab
 	rc ../port/mksystab > ../port/systab.h
@@ -112,3 +112,4 @@
 wifi.$O:	../port/etherif.h ../port/netif.h ../port/wifi.h /sys/include/libsec.h
 wifi.$O:	../ip/ip.h ../ip/ipv6.h
 ethermii.$O:	../port/ethermii.h
+pci.$O devpnp.$O usbxhci.$O:	../port/pci.h
--- a/sys/src/9/port/usbxhci.c
+++ b/sys/src/9/port/usbxhci.c
@@ -4,6 +4,7 @@
 #include	"dat.h"
 #include	"fns.h"
 #include	"io.h"
+#include	"../port/pci.h"
 #include	"../port/error.h"
 #include	"../port/usb.h"
 
--- a/sys/src/9/ppc/fns.h
+++ b/sys/src/9/ppc/fns.h
@@ -67,12 +67,6 @@
 void	mmusweep(void*);
 int	newmmupid(void);
 void	outb(int, int);
-int	pcicfgr16(Pcidev*, int);
-int	pcicfgr32(Pcidev*, int);
-int	pcicfgr8(Pcidev*, int);
-void	pcicfgw16(Pcidev*, int, int);
-void	pcicfgw32(Pcidev*, int, int);
-void	pcicfgw8(Pcidev*, int, int);
 void	procsave(Proc*);
 void	procsetup(Proc*);
 void	procfork(Proc*);
--- a/sys/src/9/teg2/ether8169.c
+++ b/sys/src/9/teg2/ether8169.c
@@ -13,6 +13,7 @@
 #include "dat.h"
 #include "fns.h"
 #include "io.h"
+#include "../port/pci.h"
 #include "../port/error.h"
 #include "../port/netif.h"
 #include "../port/etherif.h"
@@ -1566,16 +1567,7 @@
 			continue;
 		}
 
-		if(pcigetpms(p) > 0){
-			pcisetpms(p, 0);
-
-			for(i = 0; i < 6; i++)
-				pcicfgw32(p, PciBAR0+i*4, p->mem[i].bar);
-			pcicfgw8(p, PciINTL, p->intl);
-			pcicfgw8(p, PciLTR, p->ltr);
-			pcicfgw8(p, PciCLS, p->cls);
-			pcicfgw16(p, PciPCR, p->pcr);
-		}
+		pcienable(p);
 
 		if(rtl8169reset(ctlr)){
 			free(ctlr);
--- a/sys/src/9/teg2/fns.h
+++ b/sys/src/9/teg2/fns.h
@@ -88,28 +88,10 @@
 extern void mmuinvalidate(void);		/* 'mmu' or 'tlb'? */
 extern void mmuinvalidateaddr(u32int);		/* 'mmu' or 'tlb'? */
 extern void mousectl(Cmdbuf *cb);
-extern ulong pcibarsize(Pcidev*, int);
-extern void pcibussize(Pcidev*, ulong*, ulong*);
-extern int pcicfgr8(Pcidev*, int);
-extern int pcicfgr16(Pcidev*, int);
-extern int pcicfgr32(Pcidev*, int);
-extern void pcicfgw8(Pcidev*, int, int);
-extern void pcicfgw16(Pcidev*, int, int);
-extern void pcicfgw32(Pcidev*, int, int);
-extern void pciclrbme(Pcidev*);
-extern void pciclrioe(Pcidev*);
-extern void pciclrmwi(Pcidev*);
+extern int pcicfgrw8(int, int, int, int);
+extern int pcicfgrw16(int, int, int, int);
+extern int pcicfgrw32(int, int, int, int);
 extern void pcieintrdone(void);
-extern int pcigetpms(Pcidev*);
-extern void pcihinv(Pcidev*);
-extern uchar pciipin(Pcidev*, uchar);
-extern Pcidev* pcimatch(Pcidev*, int, int);
-extern Pcidev* pcimatchtbdf(int);
-extern void pcireset(void);
-extern void pcisetbme(Pcidev*);
-extern void pcisetioe(Pcidev*);
-extern void pcisetmwi(Pcidev*);
-extern int pcisetpms(Pcidev*, int);
 extern u32int pidget(void);
 extern void pidput(u32int);
 extern void prcachecfg(void);
--- a/sys/src/9/teg2/io.h
+++ b/sys/src/9/teg2/io.h
@@ -1,219 +1,4 @@
-#pragma varargck	type	"T"	int
-#pragma varargck	type	"T"	uint
-
-/*
- * PCI
- */
-
-enum {
-	BusCBUS		= 0,		/* Corollary CBUS */
-	BusCBUSII,			/* Corollary CBUS II */
-	BusEISA,			/* Extended ISA */
-	BusFUTURE,			/* IEEE Futurebus */
-	BusINTERN,			/* Internal bus */
-	BusISA,				/* Industry Standard Architecture */
-	BusMBI,				/* Multibus I */
-	BusMBII,			/* Multibus II */
-	BusMCA,				/* Micro Channel Architecture */
-	BusMPI,				/* MPI */
-	BusMPSA,			/* MPSA */
-	BusNUBUS,			/* Apple Macintosh NuBus */
-	BusPCI,				/* Peripheral Component Interconnect */
-	BusPCMCIA,			/* PC Memory Card International Association */
-	BusTC,				/* DEC TurboChannel */
-	BusVL,				/* VESA Local bus */
-	BusVME,				/* VMEbus */
-	BusXPRESS,			/* Express System Bus */
-};
-
-#define MKBUS(t,b,d,f)	(((t)<<24)|(((b)&0xFF)<<16)|(((d)&0x1F)<<11)|(((f)&0x07)<<8))
-#define BUSFNO(tbdf)	(((tbdf)>>8)&0x07)
-#define BUSDNO(tbdf)	(((tbdf)>>11)&0x1F)
-#define BUSBNO(tbdf)	(((tbdf)>>16)&0xFF)
-#define BUSTYPE(tbdf)	((tbdf)>>24)
-#define BUSBDF(tbdf)	((tbdf)&0x00FFFF00)
 #define BUSUNKNOWN	(-1)
-
-enum {					/* type 0 & type 1 pre-defined header */
-	PciVID		= 0x00,		/* vendor ID */
-	PciDID		= 0x02,		/* device ID */
-	PciPCR		= 0x04,		/* command */
-	PciPSR		= 0x06,		/* status */
-	PciRID		= 0x08,		/* revision ID */
-	PciCCRp		= 0x09,		/* programming interface class code */
-	PciCCRu		= 0x0A,		/* sub-class code */
-	PciCCRb		= 0x0B,		/* base class code */
-	PciCLS		= 0x0C,		/* cache line size */
-	PciLTR		= 0x0D,		/* latency timer */
-	PciHDT		= 0x0E,		/* header type */
-	PciBST		= 0x0F,		/* BIST */
-
-	PciBAR0		= 0x10,		/* base address */
-	PciBAR1		= 0x14,
-
-	PciINTL		= 0x3C,		/* interrupt line */
-	PciINTP		= 0x3D,		/* interrupt pin */
-};
-
-/* ccrb (base class code) values; controller types */
-enum {
-	Pcibcpci1	= 0,		/* pci 1.0; no class codes defined */
-	Pcibcstore	= 1,		/* mass storage */
-	Pcibcnet	= 2,		/* network */
-	Pcibcdisp	= 3,		/* display */
-	Pcibcmmedia	= 4,		/* multimedia */
-	Pcibcmem	= 5,		/* memory */
-	Pcibcbridge	= 6,		/* bridge */
-	Pcibccomm	= 7,		/* simple comms (e.g., serial) */
-	Pcibcbasesys	= 8,		/* base system */
-	Pcibcinput	= 9,		/* input */
-	Pcibcdock	= 0xa,		/* docking stations */
-	Pcibcproc	= 0xb,		/* processors */
-	Pcibcserial	= 0xc,		/* serial bus (e.g., USB) */
-	Pcibcwireless	= 0xd,		/* wireless */
-	Pcibcintell	= 0xe,		/* intelligent i/o */
-	Pcibcsatcom	= 0xf,		/* satellite comms */
-	Pcibccrypto	= 0x10,		/* encryption/decryption */
-	Pcibcdacq	= 0x11,		/* data acquisition & signal proc. */
-};
-
-/* ccru (sub-class code) values; common cases only */
-enum {
-	/* mass storage */
-	Pciscscsi	= 0,		/* SCSI */
-	Pciscide	= 1,		/* IDE (ATA) */
-	Pciscsata	= 6,		/* SATA */
-
-	/* network */
-	Pciscether	= 0,		/* Ethernet */
-
-	/* display */
-	Pciscvga	= 0,		/* VGA */
-	Pciscxga	= 1,		/* XGA */
-	Pcisc3d		= 2,		/* 3D */
-
-	/* bridges */
-	Pcischostpci	= 0,		/* host/pci */
-	Pciscpcicpci	= 1,		/* pci/pci */
-
-	/* simple comms */
-	Pciscserial	= 0,		/* 16450, etc. */
-	Pciscmultiser	= 1,		/* multiport serial */
-
-	/* serial bus */
-	Pciscusb	= 3,		/* USB */
-};
-
-enum {					/* type 0 pre-defined header */
-	PciCIS		= 0x28,		/* cardbus CIS pointer */
-	PciSVID		= 0x2C,		/* subsystem vendor ID */
-	PciSID		= 0x2E,		/* subsystem ID */
-	PciEBAR0	= 0x30,		/* expansion ROM base address */
-	PciMGNT		= 0x3E,		/* burst period length */
-	PciMLT		= 0x3F,		/* maximum latency between bursts */
-};
-
-enum {					/* type 1 pre-defined header */
-	PciPBN		= 0x18,		/* primary bus number */
-	PciSBN		= 0x19,		/* secondary bus number */
-	PciUBN		= 0x1A,		/* subordinate bus number */
-	PciSLTR		= 0x1B,		/* secondary latency timer */
-	PciIBR		= 0x1C,		/* I/O base */
-	PciILR		= 0x1D,		/* I/O limit */
-	PciSPSR		= 0x1E,		/* secondary status */
-	PciMBR		= 0x20,		/* memory base */
-	PciMLR		= 0x22,		/* memory limit */
-	PciPMBR		= 0x24,		/* prefetchable memory base */
-	PciPMLR		= 0x26,		/* prefetchable memory limit */
-	PciPUBR		= 0x28,		/* prefetchable base upper 32 bits */
-	PciPULR		= 0x2C,		/* prefetchable limit upper 32 bits */
-	PciIUBR		= 0x30,		/* I/O base upper 16 bits */
-	PciIULR		= 0x32,		/* I/O limit upper 16 bits */
-	PciEBAR1	= 0x28,		/* expansion ROM base address */
-	PciBCR		= 0x3E,		/* bridge control register */
-};
-
-enum {					/* type 2 pre-defined header */
-	PciCBExCA	= 0x10,
-	PciCBSPSR	= 0x16,
-	PciCBPBN	= 0x18,		/* primary bus number */
-	PciCBSBN	= 0x19,		/* secondary bus number */
-	PciCBUBN	= 0x1A,		/* subordinate bus number */
-	PciCBSLTR	= 0x1B,		/* secondary latency timer */
-	PciCBMBR0	= 0x1C,
-	PciCBMLR0	= 0x20,
-	PciCBMBR1	= 0x24,
-	PciCBMLR1	= 0x28,
-	PciCBIBR0	= 0x2C,		/* I/O base */
-	PciCBILR0	= 0x30,		/* I/O limit */
-	PciCBIBR1	= 0x34,		/* I/O base */
-	PciCBILR1	= 0x38,		/* I/O limit */
-	PciCBSVID	= 0x40,		/* subsystem vendor ID */
-	PciCBSID	= 0x42,		/* subsystem ID */
-	PciCBLMBAR	= 0x44,		/* legacy mode base address */
-};
-
-enum {
-	/* bar bits */
-	Barioaddr	= 1<<0,		/* vs. memory addr */
-	Barwidthshift	= 1,
-	Barwidthmask	= MASK(2),
-	Barwidth32	= 0,
-	Barwidth64	= 2,
-	Barprefetch	= 1<<3,
-};
-
-struct Pcisiz
-{
-	Pcidev*	dev;
-	int	siz;
-	int	bar;
-};
-
-struct Pcidev
-{
-	int	tbdf;			/* type+bus+device+function */
-	ushort	vid;			/* vendor ID */
-	ushort	did;			/* device ID */
-
-	ushort	pcr;
-
-	uchar	rid;
-	uchar	ccrp;
-	uchar	ccru;
-	uchar	ccrb;
-	uchar	cls;
-	uchar	ltr;
-
-	struct {
-		ulong	bar;		/* base address */
-		int	size;
-	} mem[6];
-
-	struct {
-		ulong	bar;	
-		int	size;
-	} rom;
-	uchar	intl;			/* interrupt line */
-
-	Pcidev*	list;
-	Pcidev*	link;			/* next device on this bno */
-
-	Pcidev*	bridge;			/* down a bus */
-
-	int	pmrb;			/* power management register block */
-};
-
-enum {
-	/* vendor ids */
-	Vatiamd	= 0x1002,
-	Vintel	= 0x8086,
-	Vjmicron= 0x197b,
-	Vmarvell= 0x1b4b,
-	Vmyricom= 0x14c1,
-	Vnvidia	= 0x10de,
-	Vrealtek= 0x10ec,
-};
 
 #define PCIWINDOW	0
 #define PCIWADDR(va)	(PADDR(va)+PCIWINDOW)
--- a/sys/src/9/teg2/main.c
+++ b/sys/src/9/teg2/main.c
@@ -5,6 +5,7 @@
 #include "dat.h"
 #include "fns.h"
 #include "io.h"
+#include "../port/pci.h"
 
 #include <pool.h>
 
--- a/sys/src/9/teg2/pci.c
+++ /dev/null
@@ -1,853 +1,0 @@
-/*
- * PCI support code.
- * Needs a massive rewrite.
- */
-#include "u.h"
-#include "../port/lib.h"
-#include "mem.h"
-#include "dat.h"
-#include "fns.h"
-#include "io.h"
-
-#define DBG	if(0) pcilog
-
-typedef struct Pci Pci;
-
-struct
-{
-	char	output[16*1024];
-	int	ptr;
-}PCICONS;
-
-int
-pcilog(char *fmt, ...)
-{
-	int n;
-	va_list arg;
-	char buf[PRINTSIZE];
-
-	va_start(arg, fmt);
-	n = vseprint(buf, buf+sizeof(buf), fmt, arg) - buf;
-	va_end(arg);
-
-	memmove(PCICONS.output+PCICONS.ptr, buf, n);
-	PCICONS.ptr += n;
-	return n;
-}
-
-enum
-{
-	MaxFNO		= 7,
-	MaxUBN		= 255,
-};
-
-enum
-{					/* command register */
-	IOen		= (1<<0),
-	MEMen		= (1<<1),
-	MASen		= (1<<2),
-	MemWrInv	= (1<<4),
-	PErrEn		= (1<<6),
-	SErrEn		= (1<<8),
-};
-
-typedef struct {
-	ulong	cap;
-	ulong	ctl;
-} Capctl;
-typedef struct {
-	Capctl	dev;
-	Capctl	link;
-	Capctl	slot;
-} Devlinkslot;
-
-/* capability list id 0x10 is pci-e */
-struct Pci {
-	/* pci-compatible config */
-	/* what io.h calls type 0 & type 1 pre-defined header */
-	ulong	id;
-	ulong	cs;
-	ulong	revclass;
-	ulong	misc;	/* cache line size, latency timer, header type, bist */
-	ulong	bar[2];		/* always 0 on tegra 2 */
-
-	/* types 1 & 2 pre-defined header */
-	ulong	bus;
-	ulong	ioaddrs;
-	ulong	memaddrs;
-	ulong	prefmem;
-	ulong	prefbasehi;
-	ulong	preflimhi;
-	/* type 2 pre-defined header only */
-	ulong	ioaddrhi;
-	ulong	cfgcapoff;	/* offset in cfg. space to cap. list (0x40) */
-	ulong	rom;
-	ulong	intr;		/* PciINT[LP] */
-	/* subsystem capability regs */
-	ulong	subsysid;
-	ulong	subsyscap;
-	/* */
-
-	Capctl	pwrmgmt;
-
-	/* msi */
-	ulong	msictlcap;
-	ulong	msimsgaddr[2];	/* little-endian */
-	ulong	msimsgdata;
-
-	/* pci-e cap. */
-	uchar	_pad0[0x80-0x60];
-	ulong	pciecap;
-	Devlinkslot port0;
-	ulong	rootctl;
-	ulong	rootsts;
-	Devlinkslot port1;
-
-	/* 0xbc */
-	
-};
-
-enum {
-	/* offsets from soc.pci */
-	Port0		= 0,
-	Port1		= 0x1000,
-	Pads		= 0x3000,
-	Afi		= 0x3800,
-	Aficfg		= Afi + 0xac,
-	Cfgspace	= 0x4000,
-	Ecfgspace	= 0x104000,
-
-	/* cs bits */
-	Iospace		= 1<<0,
-	Memspace	= 1<<1,
-	Busmaster	= 1<<2,
-
-	/* Aficfg bits */
-	Fpcion		= 1<<0,
-};
-
-struct Pcictlr {
-	union {
-		uchar	_padpci[0x1000];
-		Pci;
-	} ports[2];
-	uchar	_padpads[0x1000];
-	uchar	pads[0x800];
-	uchar	afi[0x800];
-	ulong	cfg[0x1000];
-	ulong	extcfg[0x1000];
-};
-
-static Lock pcicfglock;
-static Lock pcicfginitlock;
-static int pcicfgmode = -1;
-static int pcimaxbno = 1;  /* was 7; only 2 pci buses; touching 3rd hangs */
-static int pcimaxdno;
-static Pcidev* pciroot;
-static Pcidev* pcilist;
-static Pcidev* pcitail;
-
-static int pcicfgrw8(int, int, int, int);
-static int pcicfgrw16(int, int, int, int);
-static int pcicfgrw32(int, int, int, int);
-
-static char* bustypes[] = {
-	"CBUSI",
-	"CBUSII",
-	"EISA",
-	"FUTURE",
-	"INTERN",
-	"ISA",
-	"MBI",
-	"MBII",
-	"MCA",
-	"MPI",
-	"MPSA",
-	"NUBUS",
-	"PCI",
-	"PCMCIA",
-	"TC",
-	"VL",
-	"VME",
-	"XPRESS",
-};
-
-static int
-tbdffmt(Fmt* fmt)
-{
-	char *p;
-	int l, r;
-	uint type, tbdf;
-
-	if((p = malloc(READSTR)) == nil)
-		return fmtstrcpy(fmt, "(tbdfconv)");
-
-	switch(fmt->r){
-	case 'T':
-		tbdf = va_arg(fmt->args, int);
-		if(tbdf == BUSUNKNOWN)
-			snprint(p, READSTR, "unknown");
-		else{
-			type = BUSTYPE(tbdf);
-			if(type < nelem(bustypes))
-				l = snprint(p, READSTR, bustypes[type]);
-			else
-				l = snprint(p, READSTR, "%d", type);
-			snprint(p+l, READSTR-l, ".%d.%d.%d",
-				BUSBNO(tbdf), BUSDNO(tbdf), BUSFNO(tbdf));
-		}
-		break;
-
-	default:
-		snprint(p, READSTR, "(tbdfconv)");
-		break;
-	}
-	r = fmtstrcpy(fmt, p);
-	free(p);
-
-	return r;
-}
-
-ulong
-pcibarsize(Pcidev *p, int rno)
-{
-	ulong v, size;
-
-	v = pcicfgrw32(p->tbdf, rno, 0, 1);
-	pcicfgrw32(p->tbdf, rno, 0xFFFFFFF0, 0);
-	size = pcicfgrw32(p->tbdf, rno, 0, 1);
-	if(v & 1)
-		size |= 0xFFFF0000;
-	pcicfgrw32(p->tbdf, rno, v, 0);
-
-	return -(size & ~0x0F);
-}
-
-static int
-pcilscan(int bno, Pcidev** list)
-{
-	Pcidev *p, *head, *tail;
-	int dno, fno, i, hdt, l, maxfno, maxubn, rno, sbn, tbdf, ubn;
-
-	maxubn = bno;
-	head = nil;
-	tail = nil;
-	for(dno = 0; dno <= pcimaxdno; dno++){
-		maxfno = 0;
-		for(fno = 0; fno <= maxfno; fno++){
-			/*
-			 * For this possible device, form the
-			 * bus+device+function triplet needed to address it
-			 * and try to read the vendor and device ID.
-			 * If successful, allocate a device struct and
-			 * start to fill it in with some useful information
-			 * from the device's configuration space.
-			 */
-			tbdf = MKBUS(BusPCI, bno, dno, fno);
-			l = pcicfgrw32(tbdf, PciVID, 0, 1);
-			if(l == 0xFFFFFFFF || l == 0)
-				continue;
-			p = malloc(sizeof(*p));
-			if(p == nil)
-				panic("pcilscan: no memory");
-			p->tbdf = tbdf;
-			p->vid = l;
-			p->did = l>>16;
-
-			if(pcilist != nil)
-				pcitail->list = p;
-			else
-				pcilist = p;
-			pcitail = p;
-
-			p->pcr = pcicfgr16(p, PciPCR);
-			p->rid = pcicfgr8(p, PciRID);
-			p->ccrp = pcicfgr8(p, PciCCRp);
-			p->ccru = pcicfgr8(p, PciCCRu);
-			p->ccrb = pcicfgr8(p, PciCCRb);
-			p->cls = pcicfgr8(p, PciCLS);
-			p->ltr = pcicfgr8(p, PciLTR);
-
-			p->intl = pcicfgr8(p, PciINTL);
-
-			/*
-			 * If the device is a multi-function device adjust the
-			 * loop count so all possible functions are checked.
-			 */
-			hdt = pcicfgr8(p, PciHDT);
-			if(hdt & 0x80)
-				maxfno = MaxFNO;
-
-			/*
-			 * If appropriate, read the base address registers
-			 * and work out the sizes.
-			 */
-			switch(p->ccrb) {
-			case 0x03:		/* display controller */
-				/* fall through */
-			case 0x01:		/* mass storage controller */
-			case 0x02:		/* network controller */
-			case 0x04:		/* multimedia device */
-			case 0x07:		/* simple comm. controllers */
-			case 0x08:		/* base system peripherals */
-			case 0x09:		/* input devices */
-			case 0x0A:		/* docking stations */
-			case 0x0B:		/* processors */
-			case 0x0C:		/* serial bus controllers */
-				if((hdt & 0x7F) != 0)
-					break;
-				rno = PciBAR0 - 4;
-				for(i = 0; i < nelem(p->mem); i++) {
-					rno += 4;
-					p->mem[i].bar = pcicfgr32(p, rno);
-					p->mem[i].size = pcibarsize(p, rno);
-				}
-				break;
-
-			case 0x00:
-			case 0x05:		/* memory controller */
-			case 0x06:		/* bridge device */
-			default:
-				break;
-			}
-
-			if(head != nil)
-				tail->link = p;
-			else
-				head = p;
-			tail = p;
-		}
-	}
-
-	*list = head;
-	for(p = head; p != nil; p = p->link){
-		/*
-		 * Find PCI-PCI bridges and recursively descend the tree.
-		 */
-		if(p->ccrb != 0x06 || p->ccru != 0x04)
-			continue;
-
-		/*
-		 * If the secondary or subordinate bus number is not
-		 * initialised try to do what the PCI BIOS should have
-		 * done and fill in the numbers as the tree is descended.
-		 * On the way down the subordinate bus number is set to
-		 * the maximum as it's not known how many buses are behind
-		 * this one; the final value is set on the way back up.
-		 */
-		sbn = pcicfgr8(p, PciSBN);
-		ubn = pcicfgr8(p, PciUBN);
-
-		if(sbn == 0 || ubn == 0) {
-			sbn = maxubn+1;
-			/*
-			 * Make sure memory, I/O and master enables are
-			 * off, set the primary, secondary and subordinate
-			 * bus numbers and clear the secondary status before
-			 * attempting to scan the secondary bus.
-			 *
-			 * Initialisation of the bridge should be done here.
-			 */
-			pcicfgw32(p, PciPCR, 0xFFFF0000);
-			l = (MaxUBN<<16)|(sbn<<8)|bno;
-			pcicfgw32(p, PciPBN, l);
-			pcicfgw16(p, PciSPSR, 0xFFFF);
-			maxubn = pcilscan(sbn, &p->bridge);
-			l = (maxubn<<16)|(sbn<<8)|bno;
-
-			pcicfgw32(p, PciPBN, l);
-		}
-		else {
-			if(ubn > maxubn)
-				maxubn = ubn;
-			pcilscan(sbn, &p->bridge);
-		}
-	}
-
-	return maxubn;
-}
-
-extern void rtl8169interrupt(Ureg*, void* arg);
-
-/* not used yet */
-static void
-pciintr(Ureg *ureg, void *p)
-{
-	rtl8169interrupt(ureg, p);		/* HACK */
-}
-
-static void
-pcicfginit(void)
-{
-	char *p;
-	Pci *pci = (Pci *)soc.pci;
-	Pcidev **list;
-	int bno, n;
-
-	lock(&pcicfginitlock);
-	if(pcicfgmode != -1) {
-		unlock(&pcicfginitlock);
-		return;
-	}
-
-	/*
-	 * TrimSlice # pci 0 1
-	 * Scanning PCI devices on bus 0 1
-	 * BusDevFun  VendorId   DeviceId   Device Class       Sub-Class
-	 * _____________________________________________________________
-	 * 00.00.00   0x10de     0x0bf0     Bridge device           0x04
-	 * 01.00.00   0x10ec     0x8168     Network controller      0x00
-	 *
-	 * thus pci bus 0 has a bridge with, perhaps, an ide/sata ctlr behind,
-	 * and pci bus 1 has the realtek 8169 on it:
-	 *
-	 * TrimSlice # pci 1 long
-	 * Scanning PCI devices on bus 1
-	 *
-	 * Found PCI device 01.00.00:
-	 *   vendor ID =                   0x10ec
-	 *   device ID =                   0x8168
-	 *   command register =            0x0007
-	 *   status register =             0x0010
-	 *   revision ID =                 0x03
-	 *   class code =                  0x02 (Network controller)
-	 *   sub class code =              0x00
-	 *   programming interface =       0x00
-	 *   cache line =                  0x08
-	 *   base address 0 =              0x80400001		config
-	 *   base address 1 =              0x00000000		(ext. config)
-	 *   base address 2 =              0xa000000c		"downstream"
-	 *   base address 3 =              0x00000000		(prefetchable)
-	 *   base address 4 =              0xa000400c		not "
-	 *   base address 5 =              0x00000000		(unused)
-	 */
-	n = pci->id >> 16;
-	if (((pci->id & MASK(16)) != Vnvidia || (n != 0xbf0 && n != 0xbf1)) &&
-	     (pci->id & MASK(16)) != Vrealtek) {
-		print("no pci controller at %#p\n", pci);
-		unlock(&pcicfginitlock);
-		return;
-	}
-	if (0)
-		iprint("pci: %#p: nvidia, rev %#ux class %#6.6lux misc %#8.8lux\n",
-			pci, (uchar)pci->revclass, pci->revclass >> 8,
-			pci->misc);
-
-	pci->cs &= Iospace;
-	pci->cs |= Memspace | Busmaster;
-	coherence();
-
-	pcicfgmode = 1;
-//	pcimaxdno = 31;
-	pcimaxdno = 15;			/* for trimslice */
-
-	fmtinstall('T', tbdffmt);
-
-	if(p = getconf("*pcimaxbno")){
-		n = strtoul(p, 0, 0);
-		if(n < pcimaxbno)
-			pcimaxbno = n;
-	}
-	if(p = getconf("*pcimaxdno")){
-		n = strtoul(p, 0, 0);
-		if(n < pcimaxdno)
-			pcimaxdno = n;
-	}
-
-	list = &pciroot;
-	/* was bno = 0; trimslice needs to start at 1 */
-	for(bno = 1; bno <= pcimaxbno; bno++) {
-		bno = pcilscan(bno, list);
-		while(*list)
-			list = &(*list)->link;
-	}
-	unlock(&pcicfginitlock);
-
-	if(getconf("*pcihinv"))
-		pcihinv(nil);
-}
-
-enum {
-	Afiintrcode	= 0xb8,
-};
-
-void
-pcieintrdone(void)				/* dismiss pci-e intr */
-{
-	ulong *afi;
-
-	afi = (ulong *)(soc.pci + Afi);
-	afi[Afiintrcode/sizeof *afi] = 0;	/* magic */
-	coherence();
-}
-
-/*
- * whole config space for tbdf should be at (return address - rno).
- */
-static void *
-tegracfgaddr(int tbdf, int rno)
-{
-	uintptr addr;
-
-	addr = soc.pci + (rno < 256? Cfgspace: Ecfgspace) + BUSBDF(tbdf) + rno;
-//	if (BUSBNO(tbdf) == 1)
-//		addr += Port1;
-	return (void *)addr;
-}
-
-static int
-pcicfgrw8(int tbdf, int rno, int data, int read)
-{
-	int x;
-	void *addr;
-
-	if(pcicfgmode == -1)
-		pcicfginit();
-
-	x = -1;
-	if(BUSDNO(tbdf) > pcimaxdno)
-		return x;
-
-	addr = tegracfgaddr(tbdf, rno);
-
-	lock(&pcicfglock);
-	if(read)
-		x = *(uchar *)addr;
-	else
-		*(uchar *)addr = data;
-	unlock(&pcicfglock);
-
-	return x;
-}
-
-int
-pcicfgr8(Pcidev* pcidev, int rno)
-{
-	return pcicfgrw8(pcidev->tbdf, rno, 0, 1);
-}
-
-void
-pcicfgw8(Pcidev* pcidev, int rno, int data)
-{
-	pcicfgrw8(pcidev->tbdf, rno, data, 0);
-}
-
-static int
-pcicfgrw16(int tbdf, int rno, int data, int read)
-{
-	int x;
-	void *addr;
-
-	if(pcicfgmode == -1)
-		pcicfginit();
-
-	x = -1;
-	if(BUSDNO(tbdf) > pcimaxdno)
-		return x;
-
-	addr = tegracfgaddr(tbdf, rno);
-
-	lock(&pcicfglock);
-	if(read)
-		x = *(ushort *)addr;
-	else
-		*(ushort *)addr = data;
-	unlock(&pcicfglock);
-
-	return x;
-}
-
-int
-pcicfgr16(Pcidev* pcidev, int rno)
-{
-	return pcicfgrw16(pcidev->tbdf, rno, 0, 1);
-}
-
-void
-pcicfgw16(Pcidev* pcidev, int rno, int data)
-{
-	pcicfgrw16(pcidev->tbdf, rno, data, 0);
-}
-
-static int
-pcicfgrw32(int tbdf, int rno, int data, int read)
-{
-	int x;
-	vlong v;
-	void *addr;
-
-	if(pcicfgmode == -1)
-		pcicfginit();
-
-	x = -1;
-	if(BUSDNO(tbdf) > pcimaxdno)
-		return x;
-
-	addr = tegracfgaddr(tbdf, rno);
-	v = probeaddr((uintptr)addr);
-	if (v < 0)
-		return -1;
-
-	lock(&pcicfglock);
-	if(read)
-		x = *(ulong *)addr;
-	else
-		*(ulong *)addr = data;
-	unlock(&pcicfglock);
-
-	return x;
-}
-
-int
-pcicfgr32(Pcidev* pcidev, int rno)
-{
-	return pcicfgrw32(pcidev->tbdf, rno, 0, 1);
-}
-
-void
-pcicfgw32(Pcidev* pcidev, int rno, int data)
-{
-	pcicfgrw32(pcidev->tbdf, rno, data, 0);
-}
-
-Pcidev*
-pcimatch(Pcidev* prev, int vid, int did)
-{
-	if(pcicfgmode == -1)
-		pcicfginit();
-
-	if(prev == nil)
-		prev = pcilist;
-	else
-		prev = prev->list;
-
-	while(prev != nil){
-		if((vid == 0 || prev->vid == vid)
-		&& (did == 0 || prev->did == did))
-			break;
-		prev = prev->list;
-	}
-	return prev;
-}
-
-Pcidev*
-pcimatchtbdf(int tbdf)
-{
-	Pcidev *pcidev;
-
-	if(pcicfgmode == -1)
-		pcicfginit();
-
-	for(pcidev = pcilist; pcidev != nil; pcidev = pcidev->list) {
-		if(pcidev->tbdf == tbdf)
-			break;
-	}
-	return pcidev;
-}
-
-static void
-pcilhinv(Pcidev* p)
-{
-	int i;
-	Pcidev *t;
-
-	if(p == nil) {
-		putstrn(PCICONS.output, PCICONS.ptr);
-		p = pciroot;
-		print("bus dev type vid  did intl memory\n");
-	}
-	for(t = p; t != nil; t = t->link) {
-		print("%d  %2d/%d %.2ux %.2ux %.2ux %.4ux %.4ux %3d  ",
-			BUSBNO(t->tbdf), BUSDNO(t->tbdf), BUSFNO(t->tbdf),
-			t->ccrb, t->ccru, t->ccrp, t->vid, t->did, t->intl);
-
-		for(i = 0; i < nelem(p->mem); i++) {
-			if(t->mem[i].size == 0)
-				continue;
-			print("%d:%.8lux %d ", i,
-				t->mem[i].bar, t->mem[i].size);
-		}
-		if(t->bridge)
-			print("->%d", BUSBNO(t->bridge->tbdf));
-		print("\n");
-	}
-	while(p != nil) {
-		if(p->bridge != nil)
-			pcilhinv(p->bridge);
-		p = p->link;
-	}
-}
-
-void
-pcihinv(Pcidev* p)
-{
-	if(pcicfgmode == -1)
-		pcicfginit();
-	lock(&pcicfginitlock);
-	pcilhinv(p);
-	unlock(&pcicfginitlock);
-}
-
-void
-pcireset(void)
-{
-	Pcidev *p;
-
-	if(pcicfgmode == -1)
-		pcicfginit();
-
-	for(p = pcilist; p != nil; p = p->list) {
-		/* don't mess with the bridges */
-		if(p->ccrb == 0x06)
-			continue;
-		pciclrbme(p);
-	}
-}
-
-void
-pcisetioe(Pcidev* p)
-{
-	p->pcr |= IOen;
-	pcicfgw16(p, PciPCR, p->pcr);
-}
-
-void
-pciclrioe(Pcidev* p)
-{
-	p->pcr &= ~IOen;
-	pcicfgw16(p, PciPCR, p->pcr);
-}
-
-void
-pcisetbme(Pcidev* p)
-{
-	p->pcr |= MASen;
-	pcicfgw16(p, PciPCR, p->pcr);
-}
-
-void
-pciclrbme(Pcidev* p)
-{
-	p->pcr &= ~MASen;
-	pcicfgw16(p, PciPCR, p->pcr);
-}
-
-void
-pcisetmwi(Pcidev* p)
-{
-	p->pcr |= MemWrInv;
-	pcicfgw16(p, PciPCR, p->pcr);
-}
-
-void
-pciclrmwi(Pcidev* p)
-{
-	p->pcr &= ~MemWrInv;
-	pcicfgw16(p, PciPCR, p->pcr);
-}
-
-static int
-pcigetpmrb(Pcidev* p)
-{
-	int ptr;
-
-	if(p->pmrb != 0)
-		return p->pmrb;
-	p->pmrb = -1;
-
-	/*
-	 * If there are no extended capabilities implemented,
-	 * (bit 4 in the status register) assume there's no standard
-	 * power management method.
-	 * Find the capabilities pointer based on PCI header type.
-	 */
-	if(!(pcicfgr16(p, PciPSR) & 0x0010))
-		return -1;
-	switch(pcicfgr8(p, PciHDT)){
-	default:
-		return -1;
-	case 0:					/* all other */
-	case 1:					/* PCI to PCI bridge */
-		ptr = 0x34;
-		break;
-	case 2:					/* CardBus bridge */
-		ptr = 0x14;
-		break;
-	}
-	ptr = pcicfgr32(p, ptr);
-
-	while(ptr != 0){
-		/*
-		 * Check for validity.
-		 * Can't be in standard header and must be double
-		 * word aligned.
-		 */
-		if(ptr < 0x40 || (ptr & ~0xFC))
-			return -1;
-		if(pcicfgr8(p, ptr) == 0x01){
-			p->pmrb = ptr;
-			return ptr;
-		}
-
-		ptr = pcicfgr8(p, ptr+1);
-	}
-
-	return -1;
-}
-
-int
-pcigetpms(Pcidev* p)
-{
-	int pmcsr, ptr;
-
-	if((ptr = pcigetpmrb(p)) == -1)
-		return -1;
-
-	/*
-	 * Power Management Register Block:
-	 *  offset 0:	Capability ID
-	 *	   1:	next item pointer
-	 *	   2:	capabilities
-	 *	   4:	control/status
-	 *	   6:	bridge support extensions
-	 *	   7:	data
-	 */
-	pmcsr = pcicfgr16(p, ptr+4);
-
-	return pmcsr & 0x0003;
-}
-
-int
-pcisetpms(Pcidev* p, int state)
-{
-	int ostate, pmc, pmcsr, ptr;
-
-	if((ptr = pcigetpmrb(p)) == -1)
-		return -1;
-
-	pmc = pcicfgr16(p, ptr+2);
-	pmcsr = pcicfgr16(p, ptr+4);
-	ostate = pmcsr & 0x0003;
-	pmcsr &= ~0x0003;
-
-	switch(state){
-	default:
-		return -1;
-	case 0:
-		break;
-	case 1:
-		if(!(pmc & 0x0200))
-			return -1;
-		break;
-	case 2:
-		if(!(pmc & 0x0400))
-			return -1;
-		break;
-	case 3:
-		break;
-	}
-	pmcsr |= state;
-	pcicfgw16(p, ptr+4, pmcsr);
-
-	return ostate;
-}
--- /dev/null
+++ b/sys/src/9/teg2/pciteg.c
@@ -1,0 +1,268 @@
+#include "u.h"
+#include "../port/lib.h"
+#include "mem.h"
+#include "dat.h"
+#include "fns.h"
+#include "io.h"
+#include "../port/pci.h"
+
+typedef struct {
+	ulong	cap;
+	ulong	ctl;
+} Capctl;
+
+typedef struct {
+	Capctl	dev;
+	Capctl	link;
+	Capctl	slot;
+} Devlinkslot;
+
+/* capability list id 0x10 is pci-e */
+typedef struct Pci Pci;
+struct Pci {
+	/* pci-compatible config */
+	/* what io.h calls type 0 & type 1 pre-defined header */
+	ulong	id;
+	ulong	cs;
+	ulong	revclass;
+	ulong	misc;	/* cache line size, latency timer, header type, bist */
+	ulong	bar[2];		/* always 0 on tegra 2 */
+
+	/* types 1 & 2 pre-defined header */
+	ulong	bus;
+	ulong	ioaddrs;
+	ulong	memaddrs;
+	ulong	prefmem;
+	ulong	prefbasehi;
+	ulong	preflimhi;
+	/* type 2 pre-defined header only */
+	ulong	ioaddrhi;
+	ulong	cfgcapoff;	/* offset in cfg. space to cap. list (0x40) */
+	ulong	rom;
+	ulong	intr;		/* PciINT[LP] */
+	/* subsystem capability regs */
+	ulong	subsysid;
+	ulong	subsyscap;
+	/* */
+
+	Capctl	pwrmgmt;
+
+	/* msi */
+	ulong	msictlcap;
+	ulong	msimsgaddr[2];	/* little-endian */
+	ulong	msimsgdata;
+
+	/* pci-e cap. */
+	uchar	_pad0[0x80-0x60];
+	ulong	pciecap;
+	Devlinkslot port0;
+	ulong	rootctl;
+	ulong	rootsts;
+	Devlinkslot port1;
+
+	/* 0xbc */
+	
+};
+
+enum {
+	/* offsets from soc.pci */
+	Port0		= 0,
+	Port1		= 0x1000,
+	Pads		= 0x3000,
+	Afi		= 0x3800,
+	Aficfg		= Afi + 0xac,
+	Cfgspace	= 0x4000,
+	Ecfgspace	= 0x104000,
+
+	/* cs bits */
+	Iospace		= 1<<0,
+	Memspace	= 1<<1,
+	Busmaster	= 1<<2,
+
+	/* Aficfg bits */
+	Fpcion		= 1<<0,
+};
+
+struct Pcictlr {
+	union {
+		uchar	_padpci[0x1000];
+		Pci;
+	} ports[2];
+	uchar	_padpads[0x1000];
+	uchar	pads[0x800];
+	uchar	afi[0x800];
+	ulong	cfg[0x1000];
+	ulong	extcfg[0x1000];
+};
+
+static int pcicfgmode = -1;
+static int pcimaxbno = 1;  /* was 7; only 2 pci buses; touching 3rd hangs */
+static Pcidev* pciroot;
+
+extern void rtl8169interrupt(Ureg*, void* arg);
+
+/* not used yet */
+static void
+pciintr(Ureg *ureg, void *p)
+{
+	rtl8169interrupt(ureg, p);		/* HACK */
+}
+
+static void
+pcicfginit(void)
+{
+	char *p;
+	Pci *pci = (Pci *)soc.pci;
+	Pcidev **list;
+	int bno, n;
+
+	/*
+	 * TrimSlice # pci 0 1
+	 * Scanning PCI devices on bus 0 1
+	 * BusDevFun  VendorId   DeviceId   Device Class       Sub-Class
+	 * _____________________________________________________________
+	 * 00.00.00   0x10de     0x0bf0     Bridge device           0x04
+	 * 01.00.00   0x10ec     0x8168     Network controller      0x00
+	 *
+	 * thus pci bus 0 has a bridge with, perhaps, an ide/sata ctlr behind,
+	 * and pci bus 1 has the realtek 8169 on it:
+	 *
+	 * TrimSlice # pci 1 long
+	 * Scanning PCI devices on bus 1
+	 *
+	 * Found PCI device 01.00.00:
+	 *   vendor ID =                   0x10ec
+	 *   device ID =                   0x8168
+	 *   command register =            0x0007
+	 *   status register =             0x0010
+	 *   revision ID =                 0x03
+	 *   class code =                  0x02 (Network controller)
+	 *   sub class code =              0x00
+	 *   programming interface =       0x00
+	 *   cache line =                  0x08
+	 *   base address 0 =              0x80400001		config
+	 *   base address 1 =              0x00000000		(ext. config)
+	 *   base address 2 =              0xa000000c		"downstream"
+	 *   base address 3 =              0x00000000		(prefetchable)
+	 *   base address 4 =              0xa000400c		not "
+	 *   base address 5 =              0x00000000		(unused)
+	 */
+	n = pci->id >> 16;
+	if (((pci->id & MASK(16)) != Vnvidia || (n != 0xbf0 && n != 0xbf1)) &&
+	     (pci->id & MASK(16)) != Vrealtek) {
+		print("no pci controller at %#p\n", pci);
+		return;
+	}
+	if (0)
+		iprint("pci: %#p: nvidia, rev %#ux class %#6.6lux misc %#8.8lux\n",
+			pci, (uchar)pci->revclass, pci->revclass >> 8,
+			pci->misc);
+
+	pci->cs &= Iospace;
+	pci->cs |= Memspace | Busmaster;
+	coherence();
+
+	pcicfgmode = 1;
+	pcimaxdno = 15;			/* for trimslice */
+
+	fmtinstall('T', tbdffmt);
+
+	if(p = getconf("*pcimaxbno")){
+		n = strtoul(p, 0, 0);
+		if(n < pcimaxbno)
+			pcimaxbno = n;
+	}
+	if(p = getconf("*pcimaxdno")){
+		n = strtoul(p, 0, 0);
+		if(n < pcimaxdno)
+			pcimaxdno = n;
+	}
+
+	list = &pciroot;
+	/* was bno = 0; trimslice needs to start at 1 */
+	for(bno = 1; bno <= pcimaxbno; bno++) {
+		bno = pciscan(bno, list);
+		while(*list)
+			list = &(*list)->link;
+	}
+
+	if(getconf("*pcihinv"))
+		pcihinv(pciroot);
+}
+
+enum {
+	Afiintrcode	= 0xb8,
+};
+
+void
+pcieintrdone(void)				/* dismiss pci-e intr */
+{
+	ulong *afi;
+
+	afi = (ulong *)(soc.pci + Afi);
+	afi[Afiintrcode/sizeof *afi] = 0;	/* magic */
+	coherence();
+}
+
+/*
+ * whole config space for tbdf should be at (return address - rno).
+ */
+static void *
+tegracfgaddr(int tbdf, int rno)
+{
+	uintptr addr;
+
+	addr = soc.pci + (rno < 256? Cfgspace: Ecfgspace) + BUSBDF(tbdf) + rno;
+//	if (BUSBNO(tbdf) == 1)
+//		addr += Port1;
+	return (void *)addr;
+}
+
+int
+pcicfgrw8(int tbdf, int rno, int data, int read)
+{
+	void *addr;
+
+	addr = tegracfgaddr(tbdf, rno);
+	if(read)
+		data = *(uchar *)addr;
+	else
+		*(uchar *)addr = data;
+	return data;
+}
+
+int
+pcicfgrw16(int tbdf, int rno, int data, int read)
+{
+	void *addr;
+
+	addr = tegracfgaddr(tbdf, rno);
+	if(read)
+		data = *(ushort *)addr;
+	else
+		*(ushort *)addr = data;
+	return data;
+}
+
+int
+pcicfgrw32(int tbdf, int rno, int data, int read)
+{
+	vlong v;
+	void *addr;
+
+	addr = tegracfgaddr(tbdf, rno);
+	v = probeaddr((uintptr)addr);
+	if (v < 0)
+		return -1;
+	if(read)
+		data = *(ulong *)addr;
+	else
+		*(ulong *)addr = data;
+	return data;
+}
+
+void
+pciteglink(void)
+{
+	pcicfginit();
+}
--- a/sys/src/9/teg2/ts
+++ b/sys/src/9/teg2/ts
@@ -33,6 +33,7 @@
 #	usb
 
 link
+	pciteg
 	archtegra
 	ethermedium
 #	flashtegra	ecc
@@ -39,7 +40,7 @@
 	loopbackmedium
 	netdevmedium
 
-	ether8169	ethermii
+	ether8169	pci ethermii
 #	usbohci
 #	usbehci		usbehcitegra
 
@@ -54,7 +55,7 @@
 	esp
 
 misc
-	pci
+	pci		pciteg
 	rdb
 	coproc
 	v7-arch