ref: d3ebd02befdd967f92ea50fbac08963428e6e03e
parent: 3873eb06d95afafd4b20122130dae8664b69428f
parent: 4f85115526a87063489dc7cf347343bd520159b1
author: cinap_lenrek <[email protected]>
date: Sun Sep 13 16:34:30 EDT 2020
merge
--- a/sys/src/9/bcm64/archbcm4.c
+++ b/sys/src/9/bcm64/archbcm4.c
@@ -9,6 +9,7 @@
#include "fns.h"
#include "../port/error.h"
#include "io.h"
+#include "../port/pci.h"
#include "sysreg.h"
typedef struct Mbox Mbox;
--- a/sys/src/9/bcm64/fns.h
+++ b/sys/src/9/bcm64/fns.h
@@ -183,28 +183,9 @@
extern int isaconfig(char*, int, ISAConf*);
-/* pci */
-typedef struct Pcidev Pcidev;
-extern int pcicfgr32(Pcidev* pcidev, int rno);
-extern void pcicfgw32(Pcidev* pcidev, int rno, int data);
-extern int pcicfgr16(Pcidev* pcidev, int rno);
-extern void pcicfgw16(Pcidev* pcidev, int rno, int data);
-extern int pcicfgr8(Pcidev* pcidev, int rno);
-extern void pcicfgw8(Pcidev* pcidev, int rno, int data);
-extern Pcidev* pcimatch(Pcidev* prev, int vid, int did);
-extern Pcidev* pcimatchtbdf(int tbdf);
-extern void pcisetioe(Pcidev* p);
-extern void pciclrioe(Pcidev* p);
-extern void pcisetbme(Pcidev* p);
-extern void pciclrbme(Pcidev* p);
-extern void pcisetmwi(Pcidev* p);
-extern void pciclrmwi(Pcidev* p);
-extern int pcicap(Pcidev *p, int cap);
-extern int pcinextcap(Pcidev *pci, int offset);
-extern int pcihtcap(Pcidev *p, int cap);
-extern int pcigetpms(Pcidev* p);
-extern int pcisetpms(Pcidev* p, int state);
-extern void pcienable(Pcidev *p);
-extern void pcidisable(Pcidev *p);
+/* pcibcm */
+extern int pcicfgrw8(int tbdf, int rno, int data, int read);
+extern int pcicfgrw16(int tbdf, int rno, int data, int read);
+extern int pcicfgrw32(int tbdf, int rno, int data, int read);
extern void pciintrenable(int tbdf, void (*f)(Ureg*, void*), void *a);
extern void pciintrdisable(int tbdf, void (*f)(Ureg*, void*), void *a);
--- a/sys/src/9/bcm64/gic.c
+++ b/sys/src/9/bcm64/gic.c
@@ -4,6 +4,7 @@
#include "dat.h"
#include "fns.h"
#include "io.h"
+#include "../port/pci.h"
#include "ureg.h"
#include "sysreg.h"
#include "../port/error.h"
--- a/sys/src/9/bcm64/io.h
+++ b/sys/src/9/bcm64/io.h
@@ -6,233 +6,5 @@
IRQether = IRQgic + 29,
};
-/*
- * PCI
- */
-enum {
- BusCBUS = 0, /* Corollary CBUS */
- BusCBUSII, /* Corollary CBUS II */
- BusEISA, /* Extended ISA */
- BusFUTURE, /* IEEE Futurebus */
- BusINTERN, /* Internal bus */
- BusISA, /* Industry Standard Architecture */
- BusMBI, /* Multibus I */
- BusMBII, /* Multibus II */
- BusMCA, /* Micro Channel Architecture */
- BusMPI, /* MPI */
- BusMPSA, /* MPSA */
- BusNUBUS, /* Apple Macintosh NuBus */
- BusPCI, /* Peripheral Component Interconnect */
- BusPCMCIA, /* PC Memory Card International Association */
- BusTC, /* DEC TurboChannel */
- BusVL, /* VESA Local bus */
- BusVME, /* VMEbus */
- BusXPRESS, /* Express System Bus */
-};
-
-#define MKBUS(t,b,d,f) (((t)<<24)|(((b)&0xFF)<<16)|(((d)&0x1F)<<11)|(((f)&0x07)<<8))
-#define BUSFNO(tbdf) (((tbdf)>>8)&0x07)
-#define BUSDNO(tbdf) (((tbdf)>>11)&0x1F)
-#define BUSBNO(tbdf) (((tbdf)>>16)&0xFF)
-#define BUSTYPE(tbdf) ((tbdf)>>24)
-#define BUSBDF(tbdf) ((tbdf)&0x00FFFF00)
-
-enum { /* type 0 & type 1 pre-defined header */
- PciVID = 0x00, /* vendor ID */
- PciDID = 0x02, /* device ID */
- PciPCR = 0x04, /* command */
- PciPSR = 0x06, /* status */
- PciRID = 0x08, /* revision ID */
- PciCCRp = 0x09, /* programming interface class code */
- PciCCRu = 0x0A, /* sub-class code */
- PciCCRb = 0x0B, /* base class code */
- PciCLS = 0x0C, /* cache line size */
- PciLTR = 0x0D, /* latency timer */
- PciHDT = 0x0E, /* header type */
- PciBST = 0x0F, /* BIST */
-
- PciBAR0 = 0x10, /* base address */
- PciBAR1 = 0x14,
-
- PciCAP = 0x34, /* capabilities pointer */
- PciINTL = 0x3C, /* interrupt line */
- PciINTP = 0x3D, /* interrupt pin */
-};
-
-/* ccrb (base class code) values; controller types */
-enum {
- Pcibcpci1 = 0, /* pci 1.0; no class codes defined */
- Pcibcstore = 1, /* mass storage */
- Pcibcnet = 2, /* network */
- Pcibcdisp = 3, /* display */
- Pcibcmmedia = 4, /* multimedia */
- Pcibcmem = 5, /* memory */
- Pcibcbridge = 6, /* bridge */
- Pcibccomm = 7, /* simple comms (e.g., serial) */
- Pcibcbasesys = 8, /* base system */
- Pcibcinput = 9, /* input */
- Pcibcdock = 0xa, /* docking stations */
- Pcibcproc = 0xb, /* processors */
- Pcibcserial = 0xc, /* serial bus (e.g., USB) */
- Pcibcwireless = 0xd, /* wireless */
- Pcibcintell = 0xe, /* intelligent i/o */
- Pcibcsatcom = 0xf, /* satellite comms */
- Pcibccrypto = 0x10, /* encryption/decryption */
- Pcibcdacq = 0x11, /* data acquisition & signal proc. */
-};
-
-/* ccru (sub-class code) values; common cases only */
-enum {
- /* mass storage */
- Pciscscsi = 0, /* SCSI */
- Pciscide = 1, /* IDE (ATA) */
- Pciscsata = 6, /* SATA */
-
- /* network */
- Pciscether = 0, /* Ethernet */
-
- /* display */
- Pciscvga = 0, /* VGA */
- Pciscxga = 1, /* XGA */
- Pcisc3d = 2, /* 3D */
-
- /* bridges */
- Pcischostpci = 0, /* host/pci */
- Pciscpcicpci = 1, /* pci/pci */
-
- /* simple comms */
- Pciscserial = 0, /* 16450, etc. */
- Pciscmultiser = 1, /* multiport serial */
-
- /* serial bus */
- Pciscusb = 3, /* USB */
-};
-
-enum { /* type 0 pre-defined header */
- PciCIS = 0x28, /* cardbus CIS pointer */
- PciSVID = 0x2C, /* subsystem vendor ID */
- PciSID = 0x2E, /* subsystem ID */
- PciEBAR0 = 0x30, /* expansion ROM base address */
- PciMGNT = 0x3E, /* burst period length */
- PciMLT = 0x3F, /* maximum latency between bursts */
-};
-
-enum { /* type 1 pre-defined header */
- PciPBN = 0x18, /* primary bus number */
- PciSBN = 0x19, /* secondary bus number */
- PciUBN = 0x1A, /* subordinate bus number */
- PciSLTR = 0x1B, /* secondary latency timer */
- PciIBR = 0x1C, /* I/O base */
- PciILR = 0x1D, /* I/O limit */
- PciSPSR = 0x1E, /* secondary status */
- PciMBR = 0x20, /* memory base */
- PciMLR = 0x22, /* memory limit */
- PciPMBR = 0x24, /* prefetchable memory base */
- PciPMLR = 0x26, /* prefetchable memory limit */
- PciPUBR = 0x28, /* prefetchable base upper 32 bits */
- PciPULR = 0x2C, /* prefetchable limit upper 32 bits */
- PciIUBR = 0x30, /* I/O base upper 16 bits */
- PciIULR = 0x32, /* I/O limit upper 16 bits */
- PciEBAR1 = 0x28, /* expansion ROM base address */
- PciBCR = 0x3E, /* bridge control register */
-};
-
-enum { /* type 2 pre-defined header */
- PciCBExCA = 0x10,
- PciCBSPSR = 0x16,
- PciCBPBN = 0x18, /* primary bus number */
- PciCBSBN = 0x19, /* secondary bus number */
- PciCBUBN = 0x1A, /* subordinate bus number */
- PciCBSLTR = 0x1B, /* secondary latency timer */
- PciCBMBR0 = 0x1C,
- PciCBMLR0 = 0x20,
- PciCBMBR1 = 0x24,
- PciCBMLR1 = 0x28,
- PciCBIBR0 = 0x2C, /* I/O base */
- PciCBILR0 = 0x30, /* I/O limit */
- PciCBIBR1 = 0x34, /* I/O base */
- PciCBILR1 = 0x38, /* I/O limit */
- PciCBSVID = 0x40, /* subsystem vendor ID */
- PciCBSID = 0x42, /* subsystem ID */
- PciCBLMBAR = 0x44, /* legacy mode base address */
-};
-
-enum {
- /* bar bits */
- Barioaddr = 1<<0, /* vs. memory addr */
- Barwidthshift = 1,
- Barwidthmask = 3,
- Barwidth32 = 0,
- Barwidth64 = 2,
- Barprefetch = 1<<3,
-};
-
-enum
-{ /* command register */
- IOen = (1<<0),
- MEMen = (1<<1),
- MASen = (1<<2),
- MemWrInv = (1<<4),
- PErrEn = (1<<6),
- SErrEn = (1<<8),
-};
-
-/* capabilities */
-enum {
- PciCapPMG = 0x01, /* power management */
- PciCapAGP = 0x02,
- PciCapVPD = 0x03, /* vital product data */
- PciCapSID = 0x04, /* slot id */
- PciCapMSI = 0x05,
- PciCapCHS = 0x06, /* compact pci hot swap */
- PciCapPCIX = 0x07,
- PciCapHTC = 0x08, /* hypertransport irq conf */
- PciCapVND = 0x09, /* vendor specific information */
- PciCapPCIe = 0x10,
- PciCapMSIX = 0x11,
- PciCapSATA = 0x12,
- PciCapHSW = 0x0c, /* hot swap */
-};
-
-typedef struct Pcidev Pcidev;
-struct Pcidev
-{
- int tbdf; /* type+bus+device+function */
- ushort vid; /* vendor ID */
- ushort did; /* device ID */
-
- ushort pcr;
-
- uchar rid;
- uchar ccrp;
- uchar ccru;
- uchar ccrb;
- uchar cls;
- uchar ltr;
-
- struct {
- uvlong bar; /* base address */
- int size;
- } mem[6];
-
- uchar intl; /* interrupt line */
-
- Pcidev* list;
- Pcidev* link; /* next device on this bno */
-
- Pcidev* parent; /* up a bus */
- Pcidev* bridge; /* down a bus */
-
- int pmrb; /* power management register block */
-
- struct {
- uvlong bar;
- int size;
- } ioa, mema;
-};
-
#define PCIWINDOW 0
#define PCIWADDR(va) (PADDR(va)+PCIWINDOW)
-
-#pragma varargck type "T" int
-#pragma varargck type "T" uint
--- a/sys/src/9/bcm64/mkfile
+++ b/sys/src/9/bcm64/mkfile
@@ -103,6 +103,7 @@
l.$O cache.v8.$O mmu.$O rebootcode.$O: mem.h
l.$O cache.v8.$O archbcm3.$O clock.$O fpu.$O trap.$O mmu.$O rebootcode.$O: sysreg.h
main.$O: rebootcode.i
+pcibcm.$O: ../port/pci.h
devmouse.$O mouse.$O screen.$O: screen.h
usbdwc.$O: dwcotg.h ../port/usb.h
--- a/sys/src/9/bcm64/pci.c
+++ /dev/null
@@ -1,1141 +1,0 @@
-#include "u.h"
-#include "../port/lib.h"
-#include "mem.h"
-#include "dat.h"
-#include "fns.h"
-#include "io.h"
-
-/* bcmstb PCIe controller registers */
-enum{
- RC_CFG_VENDOR_VENDOR_SPECIFIC_REG1 = 0x0188/4,
- RC_CFG_PRIV1_ID_VAL3 = 0x043c/4,
- RC_DL_MDIO_ADDR = 0x1100/4,
- RC_DL_MDIO_WR_DATA = 0x1104/4,
- RC_DL_MDIO_RD_DATA = 0x1108/4,
- MISC_MISC_CTRL = 0x4008/4,
- MISC_CPU_2_PCIE_MEM_WIN0_LO = 0x400c/4,
- MISC_CPU_2_PCIE_MEM_WIN0_HI = 0x4010/4,
- MISC_RC_BAR1_CONFIG_LO = 0x402c/4,
- MISC_RC_BAR2_CONFIG_LO = 0x4034/4,
- MISC_RC_BAR2_CONFIG_HI = 0x4038/4,
- MISC_RC_BAR3_CONFIG_LO = 0x403c/4,
- MISC_MSI_BAR_CONFIG_LO = 0x4044/4,
- MISC_MSI_BAR_CONFIG_HI = 0x4048/4,
- MISC_MSI_DATA_CONFIG = 0x404c/4,
- MISC_EOI_CTRL = 0x4060/4,
- MISC_PCIE_CTRL = 0x4064/4,
- MISC_PCIE_STATUS = 0x4068/4,
- MISC_REVISION = 0x406c/4,
- MISC_CPU_2_PCIE_MEM_WIN0_BASE_LIMIT = 0x4070/4,
- MISC_CPU_2_PCIE_MEM_WIN0_BASE_HI = 0x4080/4,
- MISC_CPU_2_PCIE_MEM_WIN0_LIMIT_HI = 0x4084/4,
- MISC_HARD_PCIE_HARD_DEBUG = 0x4204/4,
-
- INTR2_CPU_BASE = 0x4300/4,
- MSI_INTR2_BASE = 0x4500/4,
- INTR_STATUS = 0,
- INTR_SET,
- INTR_CLR,
- INTR_MASK_STATUS,
- INTR_MASK_SET,
- INTR_MASK_CLR,
-
- EXT_CFG_INDEX = 0x9000/4,
- RGR1_SW_INIT_1 = 0x9210/4,
- EXT_CFG_DATA = 0x8000/4,
-
-};
-
-#define MSI_TARGET_ADDR 0xFFFFFFFFCULL
-
-static u32int *regs = (u32int*)(VIRTIO1 + 0x500000);
-
-static Lock pcicfglock;
-static int pcimaxbno = 0;
-static int pcimaxdno = 0;
-static Pcidev* pciroot;
-static Pcidev* pcilist;
-static Pcidev* pcitail;
-
-typedef struct Pcisiz Pcisiz;
-struct Pcisiz
-{
- Pcidev* dev;
- int bar;
- int siz;
- int typ;
-};
-
-enum
-{
- MaxFNO = 7,
- MaxUBN = 255,
-};
-
-static char* bustypes[] = {
- "CBUSI",
- "CBUSII",
- "EISA",
- "FUTURE",
- "INTERN",
- "ISA",
- "MBI",
- "MBII",
- "MCA",
- "MPI",
- "MPSA",
- "NUBUS",
- "PCI",
- "PCMCIA",
- "TC",
- "VL",
- "VME",
- "XPRESS",
-};
-
-static int
-tbdffmt(Fmt* fmt)
-{
- char *p;
- int l, r;
- uint type, tbdf;
-
- if((p = malloc(READSTR)) == nil)
- return fmtstrcpy(fmt, "(tbdfconv)");
-
- switch(fmt->r){
- case 'T':
- tbdf = va_arg(fmt->args, int);
- if(tbdf == BUSUNKNOWN)
- snprint(p, READSTR, "unknown");
- else{
- type = BUSTYPE(tbdf);
- if(type < nelem(bustypes))
- l = snprint(p, READSTR, bustypes[type]);
- else
- l = snprint(p, READSTR, "%d", type);
- snprint(p+l, READSTR-l, ".%d.%d.%d",
- BUSBNO(tbdf), BUSDNO(tbdf), BUSFNO(tbdf));
- }
- break;
-
- default:
- snprint(p, READSTR, "(tbdfconv)");
- break;
- }
- r = fmtstrcpy(fmt, p);
- free(p);
-
- return r;
-}
-
-static void pcicfginit(void);
-
-static void*
-cfgaddr(int tbdf, int rno)
-{
- if(BUSBNO(tbdf) == 0 && BUSDNO(tbdf) == 0)
- return (uchar*)regs + rno;
- regs[EXT_CFG_INDEX] = BUSBNO(tbdf) << 20 | BUSDNO(tbdf) << 15 | BUSFNO(tbdf) << 12;
- coherence();
- return ((uchar*)®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