ref: 4f85115526a87063489dc7cf347343bd520159b1
parent: d7b541eaf317ca3586bf18a6a189dabae81d1e21
author: cinap_lenrek <[email protected]>
date: Sun Sep 13 16:33:17 EDT 2020
kernel: massive pci code rewrite The new pci code is moved to port/pci.[hc] and shared by all ports. Each port has its own PCI controller implementation, providing the pcicfgrw*() functions for low level pci config space access. The locking for pcicfgrw*() is now done by the caller (only port/pci.c). Device drivers now need to include "../port/pci.h" in addition to "io.h". The new code now checks bridge windows and membars, while enumerating the bus, giving the pc driver a chance to re-assign them. This is needed because some UEFI implementations fail to assign the bars for some devices, so we need to do it outselfs. (See pcireservemem()). While working on this, it was discovered that the pci code assimed the smallest I/O bar size is 16 (pcibarsize()), which is wrong. I/O bars can be as small as 4 bytes. Bit 1 in an I/O bar is also reserved and should be masked off, making the port mask: port = bar & ~3;
--- 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*)®s[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*)®s[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