diff --git a/sys/src/9/bcm64/archbcm4.c b/sys/src/9/bcm64/archbcm4.c index d47ba96e1..3fefe9b9d 100644 --- 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; diff --git a/sys/src/9/bcm64/fns.h b/sys/src/9/bcm64/fns.h index f42c2736c..7ace1ce9a 100644 --- a/sys/src/9/bcm64/fns.h +++ b/sys/src/9/bcm64/fns.h @@ -183,28 +183,9 @@ extern void screeninit(void); 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); diff --git a/sys/src/9/bcm64/gic.c b/sys/src/9/bcm64/gic.c index e6352ab5f..469a1b0e5 100644 --- 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" diff --git a/sys/src/9/bcm64/io.h b/sys/src/9/bcm64/io.h index ffcbee67c..ef6fab282 100644 --- a/sys/src/9/bcm64/io.h +++ b/sys/src/9/bcm64/io.h @@ -6,233 +6,5 @@ enum { 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 diff --git a/sys/src/9/bcm64/mkfile b/sys/src/9/bcm64/mkfile index 4ba978899..2a030b59f 100644 --- a/sys/src/9/bcm64/mkfile +++ b/sys/src/9/bcm64/mkfile @@ -103,6 +103,7 @@ trap.$O main.$O: /sys/include/tos.h 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 diff --git a/sys/src/9/bcm64/pcibcm.c b/sys/src/9/bcm64/pcibcm.c new file mode 100644 index 000000000..c1270f51c --- /dev/null +++ b/sys/src/9/bcm64/pcibcm.c @@ -0,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(); +} diff --git a/sys/src/9/bcm64/pi4 b/sys/src/9/bcm64/pi4 index 1a3b815ff..2bd10a1ea 100644 --- a/sys/src/9/bcm64/pi4 +++ b/sys/src/9/bcm64/pi4 @@ -26,7 +26,7 @@ dev link gisb - pci + pcibcm archbcm4 pci usbxhci pci archbcm4 ethergenet ethermii @@ -49,7 +49,7 @@ misc dma gic vcore - + pci pcibcm dtracysys dtracytimer diff --git a/sys/src/9/kw/fns.h b/sys/src/9/kw/fns.h index 703e8c503..50c6ea014 100644 --- a/sys/src/9/kw/fns.h +++ b/sys/src/9/kw/fns.h @@ -130,31 +130,6 @@ extern int splflo(void); 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*); diff --git a/sys/src/9/kw/io.h b/sys/src/9/kw/io.h index b05603254..e76f6faef 100644 --- a/sys/src/9/kw/io.h +++ b/sys/src/9/kw/io.h @@ -27,168 +27,6 @@ enum { #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) diff --git a/sys/src/9/mtx/ether2114x.c b/sys/src/9/mtx/ether2114x.c index 8906b3499..25260d4ea 100644 --- 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" diff --git a/sys/src/9/mtx/fns.h b/sys/src/9/mtx/fns.h index 98d2b28cc..d63cc6ddb 100644 --- a/sys/src/9/mtx/fns.h +++ b/sys/src/9/mtx/fns.h @@ -65,21 +65,9 @@ void outs(int, ushort); 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*); diff --git a/sys/src/9/mtx/io.h b/sys/src/9/mtx/io.h index 255debf97..3ebe26a7b 100644 --- a/sys/src/9/mtx/io.h +++ b/sys/src/9/mtx/io.h @@ -31,150 +31,12 @@ typedef struct Vctl { void* a; /* argument to call it with */ } 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) diff --git a/sys/src/9/mtx/mkfile b/sys/src/9/mtx/mkfile index 6dd9ba614..df5ba47e8 100644 --- 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 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); -} diff --git a/sys/src/9/mtx/pcimtx.c b/sys/src/9/mtx/pcimtx.c new file mode 100644 index 000000000..02f1f4e9a --- /dev/null +++ b/sys/src/9/mtx/pcimtx.c @@ -0,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(); +} diff --git a/sys/src/9/pc/archacpi.c b/sys/src/9/pc/archacpi.c index d74054c7d..e19c70166 100644 --- 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" diff --git a/sys/src/9/pc/archmp.c b/sys/src/9/pc/archmp.c index edf256256..5d613dd0d 100644 --- 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" diff --git a/sys/src/9/pc/audioac97.c b/sys/src/9/pc/audioac97.c index e4f175882..0a336cae4 100644 --- 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" diff --git a/sys/src/9/pc/audiohda.c b/sys/src/9/pc/audiohda.c index bb32e09e3..f04ad11ee 100644 --- 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" diff --git a/sys/src/9/pc/cputemp.c b/sys/src/9/pc/cputemp.c index 944c4a774..1ffbeb08b 100644 --- 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) diff --git a/sys/src/9/pc/devarch.c b/sys/src/9/pc/devarch.c index 5ba04b59c..9a845b3ab 100644 --- a/sys/src/9/pc/devarch.c +++ b/sys/src/9/pc/devarch.c @@ -153,7 +153,6 @@ ioinit(void) ioalloc(io_s, io_e - io_s + 1, 0, "pre-allocated"); } } - } /* diff --git a/sys/src/9/pc/devlm78.c b/sys/src/9/pc/devlm78.c index 617d5cb92..3aa4cf333 100644 --- 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 diff --git a/sys/src/9/pc/devlml.c b/sys/src/9/pc/devlml.c index 83c57b855..377b95e3e 100644 --- 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" diff --git a/sys/src/9/pc/devpccard.c b/sys/src/9/pc/devpccard.c index 68be9047a..b6c9bb682 100644 --- 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 @@ unconfigure(Cardbus *cb) 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); diff --git a/sys/src/9/pc/devtv.c b/sys/src/9/pc/devtv.c index 4e0c32792..e5690a88d 100644 --- 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)) diff --git a/sys/src/9/pc/devvga.c b/sys/src/9/pc/devvga.c index 5d95c98eb..cb97a4901 100644 --- 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 diff --git a/sys/src/9/pc/ether2000.c b/sys/src/9/pc/ether2000.c index 6cebf4f9f..3077e190c 100644 --- 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 @@ ne2000match(Ether* edev, int id) 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; diff --git a/sys/src/9/pc/ether2114x.c b/sys/src/9/pc/ether2114x.c index 57d426952..d451a1a1d 100644 --- 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 @@ dec2114xpci(void) 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; diff --git a/sys/src/9/pc/ether79c970.c b/sys/src/9/pc/ether79c970.c index d9e17e0b4..c2b629bbd 100644 --- 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 @@ amd79c970pci(void) 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 @@ amd79c970pci(void) iofree(port); continue; } - ctlr->port = p->mem[0].bar & ~0x01; + ctlr->port = port; ctlr->pcidev = p; if(ctlrhead != nil) diff --git a/sys/src/9/pc/ether8139.c b/sys/src/9/pc/ether8139.c index 21a1cad39..a5eccd230 100644 --- 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 @@ rtl8139match(Ether* edev, int id) 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; diff --git a/sys/src/9/pc/ether8169.c b/sys/src/9/pc/ether8169.c index bf6cf8ef4..a871a55d2 100644 --- 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 @@ rtl8169pci(void) 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; diff --git a/sys/src/9/pc/ether82543gc.c b/sys/src/9/pc/ether82543gc.c index 3b326b4af..b43beb161 100644 --- 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 @@ gc82543pci(void) free(ctlr); continue; } - cls = pcicfgr8(p, PciCLS); - switch(cls){ + switch(p->cls){ case 0x08: case 0x10: break; diff --git a/sys/src/9/pc/ether82557.c b/sys/src/9/pc/ether82557.c index b764f1c0b..33d7b6957 100644 --- 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 @@ i82557pci(void) * 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; diff --git a/sys/src/9/pc/ether82563.c b/sys/src/9/pc/ether82563.c index 4559fda5c..75af7825c 100644 --- 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" diff --git a/sys/src/9/pc/ether82598.c b/sys/src/9/pc/ether82598.c index 6792e779a..89ee64011 100644 --- 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" diff --git a/sys/src/9/pc/ether83815.c b/sys/src/9/pc/ether83815.c index a65fe719e..ebbec582f 100644 --- 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 @@ scanpci83815(void) 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; diff --git a/sys/src/9/pc/etherbcm.c b/sys/src/9/pc/etherbcm.c index 6ad24640c..cc96c8976 100644 --- 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" diff --git a/sys/src/9/pc/etherdp83820.c b/sys/src/9/pc/etherdp83820.c index 1b466d42a..deb427fb4 100644 --- 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" diff --git a/sys/src/9/pc/etherelnk3.c b/sys/src/9/pc/etherelnk3.c index 21ce10c65..ff5f173c2 100644 --- 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 @@ tcm59Xpci(void) */ 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); diff --git a/sys/src/9/pc/etherga620.c b/sys/src/9/pc/etherga620.c index c57159b7c..7a093d295 100644 --- 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 @@ print("ga620shutdown\n"); static int ga620reset(Ctlr* ctlr) { - int cls, csr, i, r; + int csr, i, r; if(ga620detach(ctlr) < 0) return -1; @@ -1108,9 +1109,10 @@ ga620reset(Ctlr* ctlr) 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); diff --git a/sys/src/9/pc/etherigbe.c b/sys/src/9/pc/etherigbe.c index ab28a824c..b75dc50dc 100644 --- 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 @@ igbereset(Ctlr* ctlr) static void igbepci(void) { - int cls; Pcidev *p; Ctlr *ctlr; void *mem; @@ -1949,8 +1949,7 @@ igbepci(void) 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 @@ igbepci(void) 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)){ diff --git a/sys/src/9/pc/etheriwl.c b/sys/src/9/pc/etheriwl.c index d91e7ce40..297be586c 100644 --- 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" diff --git a/sys/src/9/pc/etherm10g.c b/sys/src/9/pc/etherm10g.c index f74dab554..80a084d65 100644 --- 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" diff --git a/sys/src/9/pc/etherrt2860.c b/sys/src/9/pc/etherrt2860.c index bbebc2bab..a545dc5a3 100644 --- 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" diff --git a/sys/src/9/pc/ethervgbe.c b/sys/src/9/pc/ethervgbe.c index 3249549d0..eaf0a33b5 100644 --- 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 @@ vgbepci(void) continue; } - port &= 0xfffe; + port &= 0xfffc; if(size != 256){ print("vgbe: invalid io size: %d\n", size); diff --git a/sys/src/9/pc/ethervirtio.c b/sys/src/9/pc/ethervirtio.c index 92ec308b9..871f6d884 100644 --- 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 @@ pciprobe(int typ) /* 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 @@ pciprobe(int typ) 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); diff --git a/sys/src/9/pc/ethervt6102.c b/sys/src/9/pc/ethervt6102.c index b76d3be8b..9ea47f1ae 100644 --- 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 @@ vt6102pci(void) { Pcidev *p; Ctlr *ctlr; - int cls, port; + int port; p = nil; while(p = pcimatch(p, 0, 0)){ @@ -962,7 +963,7 @@ vt6102pci(void) 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 @@ vt6102pci(void) 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)){ diff --git a/sys/src/9/pc/ethervt6105m.c b/sys/src/9/pc/ethervt6105m.c index bd1e4543c..c0f513b52 100644 --- 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 @@ vt6105Mpci(void) { Pcidev *p; Ctlr *ctlr; - int cls, port; + int port; p = nil; while(p = pcimatch(p, 0, 0)){ @@ -1126,7 +1127,7 @@ vt6105Mpci(void) 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 @@ vt6105Mpci(void) 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)){ diff --git a/sys/src/9/pc/etherwavelan.c b/sys/src/9/pc/etherwavelan.c index bc7fc8e8c..4bbc94770 100644 --- 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" diff --git a/sys/src/9/pc/etherwpi.c b/sys/src/9/pc/etherwpi.c index f43ff64a1..5173c2869 100644 --- 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" diff --git a/sys/src/9/pc/etherx550.c b/sys/src/9/pc/etherx550.c index cdea48f04..c35325d14 100644 --- 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" diff --git a/sys/src/9/pc/etheryuk.c b/sys/src/9/pc/etheryuk.c index b856a3465..fca293329 100644 --- 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" diff --git a/sys/src/9/pc/fns.h b/sys/src/9/pc/fns.h index 7b15b2e74..1bda49c67 100644 --- a/sys/src/9/pc/fns.h +++ b/sys/src/9/pc/fns.h @@ -125,32 +125,10 @@ void outl(int, ulong); 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 @@ uvlong tscticks(uvlong*); 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); diff --git a/sys/src/9/pc/io.h b/sys/src/9/pc/io.h index 6179a47f6..01204ffa3 100644 --- a/sys/src/9/pc/io.h +++ b/sys/src/9/pc/io.h @@ -59,230 +59,18 @@ typedef struct Vctl { void* a; /* argument to call it with */ } 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 @@ struct PCMslot int time; PCMmap mmap[4]; /* maps, last is always for the kernel */ }; - -#pragma varargck type "T" int -#pragma varargck type "T" uint diff --git a/sys/src/9/pc/main.c b/sys/src/9/pc/main.c index 01fa783ad..231a62ad3 100644 --- a/sys/src/9/pc/main.c +++ b/sys/src/9/pc/main.c @@ -40,6 +40,7 @@ main(void) ramdiskinit(); confinit(); xinit(); + pcicfginit(); bootscreeninit(); if(i8237alloc != nil) i8237alloc(); @@ -57,7 +58,6 @@ main(void) initseg(); if(delaylink){ bootlinks(); - pcimatch(0, 0, 0); }else links(); chandevreset(); diff --git a/sys/src/9/pc/memory.c b/sys/src/9/pc/memory.c index 04cf3b9fe..e5eefd17b 100644 --- a/sys/src/9/pc/memory.c +++ b/sys/src/9/pc/memory.c @@ -250,6 +250,24 @@ upaalloc(uvlong pa, ulong size, ulong align) 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) { diff --git a/sys/src/9/pc/mp.c b/sys/src/9/pc/mp.c index 382e247f7..60b720c81 100644 --- 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" diff --git a/sys/src/9/pc/pc b/sys/src/9/pc/pc index e4171f127..3f7816d6e 100644 --- a/sys/src/9/pc/pc +++ b/sys/src/9/pc/pc @@ -27,7 +27,7 @@ dev draw screen vga vgax vgasoft mouse mouse kbd - vga + vga pci sd floppy dma @@ -35,7 +35,7 @@ dev lpt audio dma - pccard + pccard pci i82365 cis uart usb @@ -45,11 +45,11 @@ dev 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 @@ link 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 @@ link 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 diff --git a/sys/src/9/pc/pci.c b/sys/src/9/pc/pci.c deleted file mode 100644 index 3d3239e18..000000000 --- a/sys/src/9/pc/pci.c +++ /dev/null @@ -1,1647 +0,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; imem); 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); -} diff --git a/sys/src/9/pc/pcipc.c b/sys/src/9/pc/pcipc.c new file mode 100644 index 000000000..f618d24ba --- /dev/null +++ b/sys/src/9/pc/pcipc.c @@ -0,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; imem); 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; imem); 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); +} diff --git a/sys/src/9/pc/piix4smbus.c b/sys/src/9/pc/piix4smbus.c index 7ea4b8706..82d09a232 100644 --- 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 diff --git a/sys/src/9/pc/pmmc.c b/sys/src/9/pc/pmmc.c index 2578f7a8f..710ce52bc 100644 --- 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 */ diff --git a/sys/src/9/pc/screen.c b/sys/src/9/pc/screen.c index af5799934..947c9aee0 100644 --- 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" diff --git a/sys/src/9/pc/sd53c8xx.c b/sys/src/9/pc/sd53c8xx.c index f16644fff..234be0758 100644 --- 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; diff --git a/sys/src/9/pc/sdiahci.c b/sys/src/9/pc/sdiahci.c index 644850dd8..0247e7802 100644 --- 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 diff --git a/sys/src/9/pc/sdide.c b/sys/src/9/pc/sdide.c index 7da95b2e8..a7626726a 100644 --- 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 @@ pc87415ienable(Ctlr* ctlr) 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 @@ atapnp(void) if((map & 1<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 @@ atapnp(void) 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 diff --git a/sys/src/9/pc/sdmv50xx.c b/sys/src/9/pc/sdmv50xx.c index a48264d89..a1103cbc5 100644 --- 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 diff --git a/sys/src/9/pc/sdmylex.c b/sys/src/9/pc/sdmylex.c index 75cf5ac5b..a0785a7c1 100644 --- 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 @@ mylexpnp(void) 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; diff --git a/sys/src/9/pc/sdnvme.c b/sys/src/9/pc/sdnvme.c index 1db5fb677..152dba187 100644 --- 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" diff --git a/sys/src/9/pc/sdodin.c b/sys/src/9/pc/sdodin.c index 6c4277676..3ad371f82 100644 --- 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 diff --git a/sys/src/9/pc/sdvirtio.c b/sys/src/9/pc/sdvirtio.c index 57ed15811..e5a60767f 100644 --- 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,13 +204,15 @@ viopnpdevs(int typ) 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){ 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); diff --git a/sys/src/9/pc/uartaxp.c b/sys/src/9/pc/uartaxp.c index 2b84f6a30..48a26b3f6 100644 --- 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" diff --git a/sys/src/9/pc/uartpci.c b/sys/src/9/pc/uartpci.c index aed64a1b1..5819a4896 100644 --- 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 @@ uartpci(int ctlrno, Pcidev* p, int barno, int n, int freq, char* name, 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); diff --git a/sys/src/9/pc/usbehcipc.c b/sys/src/9/pc/usbehcipc.c index 7f6e47923..276bba117 100644 --- 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" diff --git a/sys/src/9/pc/usbohci.c b/sys/src/9/pc/usbohci.c index d24f2388e..1725c0351 100644 --- 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" diff --git a/sys/src/9/pc/usbuhci.c b/sys/src/9/pc/usbuhci.c index 1666be00d..a5783d546 100644 --- 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 @@ scanpci(void) 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; diff --git a/sys/src/9/pc/vga3dfx.c b/sys/src/9/pc/vga3dfx.c index 214adfbca..07afd740c 100644 --- 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 diff --git a/sys/src/9/pc/vgaclgd546x.c b/sys/src/9/pc/vgaclgd546x.c index e31ed432c..06762a876 100644 --- 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 diff --git a/sys/src/9/pc/vgacyber938x.c b/sys/src/9/pc/vgacyber938x.c index 4678680dc..4259f06de 100644 --- 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 diff --git a/sys/src/9/pc/vgageode.c b/sys/src/9/pc/vgageode.c index 0fe7890b5..7b6106fbe 100644 --- 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 diff --git a/sys/src/9/pc/vgahiqvideo.c b/sys/src/9/pc/vgahiqvideo.c index 824d5db0c..4a54b676c 100644 --- 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 diff --git a/sys/src/9/pc/vgai81x.c b/sys/src/9/pc/vgai81x.c index 1827aceac..f80a11bf5 100644 --- 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 diff --git a/sys/src/9/pc/vgaigfx.c b/sys/src/9/pc/vgaigfx.c index 6ad761b9b..ea70310ab 100644 --- 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 diff --git a/sys/src/9/pc/vgamach64xx.c b/sys/src/9/pc/vgamach64xx.c index 0f6ea6c10..0f1606c24 100644 --- 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 diff --git a/sys/src/9/pc/vgamga2164w.c b/sys/src/9/pc/vgamga2164w.c index 3269cd7a5..df9fa5ddf 100644 --- 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 diff --git a/sys/src/9/pc/vgamga4xx.c b/sys/src/9/pc/vgamga4xx.c index d29d3cfdc..30bcf7822 100644 --- 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 diff --git a/sys/src/9/pc/vganeomagic.c b/sys/src/9/pc/vganeomagic.c index b1bd3f84c..1cc2a02d9 100644 --- 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 diff --git a/sys/src/9/pc/vganvidia.c b/sys/src/9/pc/vganvidia.c index 54de9dc6e..0d20f43a8 100644 --- 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 diff --git a/sys/src/9/pc/vgaradeon.c b/sys/src/9/pc/vgaradeon.c index 9430a1a6c..e23d90753 100644 --- 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 diff --git a/sys/src/9/pc/vgas3.c b/sys/src/9/pc/vgas3.c index f055d8919..710756d7c 100644 --- 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 diff --git a/sys/src/9/pc/vgat2r4.c b/sys/src/9/pc/vgat2r4.c index 5cf282325..32ffeb833 100644 --- 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 diff --git a/sys/src/9/pc/vgavesa.c b/sys/src/9/pc/vgavesa.c index 3f7300326..08021c7bf 100644 --- 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 diff --git a/sys/src/9/pc/vgavmware.c b/sys/src/9/pc/vgavmware.c index aa4b12e30..8c84158a7 100644 --- 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 diff --git a/sys/src/9/pc64/fns.h b/sys/src/9/pc64/fns.h index 2bbd3ffd8..39afc4864 100644 --- a/sys/src/9/pc64/fns.h +++ b/sys/src/9/pc64/fns.h @@ -124,32 +124,10 @@ void outl(int, ulong); 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 @@ uvlong tscticks(uvlong*); 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 *); diff --git a/sys/src/9/pc64/main.c b/sys/src/9/pc64/main.c index 83f770587..50649d724 100644 --- a/sys/src/9/pc64/main.c +++ b/sys/src/9/pc64/main.c @@ -190,6 +190,7 @@ main(void) ramdiskinit(); confinit(); xinit(); + pcicfginit(); bootscreeninit(); if(i8237alloc != nil) i8237alloc(); @@ -207,7 +208,6 @@ main(void) initseg(); if(delaylink){ bootlinks(); - pcimatch(0, 0, 0); }else links(); chandevreset(); diff --git a/sys/src/9/pc64/pc64 b/sys/src/9/pc64/pc64 index 6e03dc00e..c5ef1fbbe 100644 --- a/sys/src/9/pc64/pc64 +++ b/sys/src/9/pc64/pc64 @@ -26,7 +26,7 @@ dev draw screen vga vgax vgasoft mouse mouse kbd - vga + vga pci sd # floppy dma @@ -44,9 +44,9 @@ dev dtracy link -# devpccard +# devpccard pci # devi82365 - cputemp + cputemp pci # ether2000 ether8390 # ether2114x pci # ether589 etherelnk3 @@ -82,16 +82,17 @@ link # 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 diff --git a/sys/src/9/port/devpnp.c b/sys/src/9/port/devpnp.c index ebaaa5cb7..7402a71d6 100644 --- 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; diff --git a/sys/src/9/bcm64/pci.c b/sys/src/9/port/pci.c similarity index 55% rename from sys/src/9/bcm64/pci.c rename to sys/src/9/port/pci.c index 62e8d6624..63d051ac9 100644 --- a/sys/src/9/bcm64/pci.c +++ b/sys/src/9/port/pci.c @@ -4,73 +4,22 @@ #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; +#include "../port/pci.h" typedef struct Pcisiz Pcisiz; struct Pcisiz { Pcidev* dev; - int bar; int siz; + int bar; int typ; }; -enum -{ - MaxFNO = 7, - MaxUBN = 255, -}; +int pcimaxdno; + +static Lock pcicfglock; +static Pcidev* pcilist; +static Pcidev* pcitail; static char* bustypes[] = { "CBUSI", @@ -93,176 +42,133 @@ static char* bustypes[] = { "XPRESS", }; -static int +int tbdffmt(Fmt* fmt) { - char *p; - int l, r; - uint type, tbdf; - - if((p = malloc(READSTR)) == nil) - return fmtstrcpy(fmt, "(tbdfconv)"); + int type, tbdf; switch(fmt->r){ + default: + return fmtstrcpy(fmt, "(tbdffmt)"); + case 'T': tbdf = va_arg(fmt->args, int); - if(tbdf == BUSUNKNOWN) - snprint(p, READSTR, "unknown"); - else{ + if(tbdf == BUSUNKNOWN) { + return fmtstrcpy(fmt, "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)); + 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)); + } } - 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) +pcicfgr8(Pcidev* p, int rno) { - return pcicfgrw32(pcidev->tbdf, rno, 0, 1); + int data; + + ilock(&pcicfglock); + data = pcicfgrw8(p->tbdf, rno, 0, 1); + iunlock(&pcicfglock); + + return data; } void -pcicfgw32(Pcidev* pcidev, int rno, int data) +pcicfgw8(Pcidev* p, int rno, int data) { - pcicfgrw32(pcidev->tbdf, rno, data, 0); + ilock(&pcicfglock); + pcicfgrw8(p->tbdf, rno, data, 0); + iunlock(&pcicfglock); } int -pcicfgr16(Pcidev* pcidev, int rno) +pcicfgr16(Pcidev* p, int rno) { - return pcicfgrw16(pcidev->tbdf, rno, 0, 1); + int data; + + ilock(&pcicfglock); + data = pcicfgrw16(p->tbdf, rno, 0, 1); + iunlock(&pcicfglock); + + return data; } void -pcicfgw16(Pcidev* pcidev, int rno, int data) +pcicfgw16(Pcidev* p, int rno, int data) { - pcicfgrw16(pcidev->tbdf, rno, data, 0); + ilock(&pcicfglock); + pcicfgrw16(p->tbdf, rno, data, 0); + iunlock(&pcicfglock); } int -pcicfgr8(Pcidev* pcidev, int rno) +pcicfgr32(Pcidev* p, int rno) { - return pcicfgrw8(pcidev->tbdf, rno, 0, 1); + int data; + + ilock(&pcicfglock); + data = pcicfgrw32(p->tbdf, rno, 0, 1); + iunlock(&pcicfglock); + + return data; } void -pcicfgw8(Pcidev* pcidev, int rno, int data) +pcicfgw32(Pcidev* p, int rno, int data) { - pcicfgrw8(pcidev->tbdf, rno, data, 0); + ilock(&pcicfglock); + pcicfgrw32(p->tbdf, rno, data, 0); + iunlock(&pcicfglock); } -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 +int pcibarsize(Pcidev *p, int rno) { - u32int v, size; + int v, size; + ilock(&pcicfglock); v = pcicfgrw32(p->tbdf, rno, 0, 1); - pcicfgrw32(p->tbdf, rno, 0xFFFFFFF0, 0); + pcicfgrw32(p->tbdf, rno, -1, 0); size = pcicfgrw32(p->tbdf, rno, 0, 1); - if(v & 1) - size |= 0xFFFF0000; pcicfgrw32(p->tbdf, rno, v, 0); + iunlock(&pcicfglock); - return -(size & ~0x0F); + 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 @@ -294,13 +200,13 @@ pcimask(ulong v) return v+1; } -static void +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; + uvlong mema, smema; + ulong ioa, sioa, v; Pcisiz *table, *tptr, *mtb, *itb; ioa = *pioa; @@ -329,26 +235,21 @@ pcibusmap(Pcidev *root, uvlong *pmema, ulong *pioa, int wrreg) 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->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 = p->mema.size; + mtb->siz = hole; mtb->typ = 0; mtb++; continue; @@ -356,20 +257,17 @@ pcibusmap(Pcidev *root, uvlong *pmema, ulong *pioa, int wrreg) for(i = 0; i < nelem(p->mem); i++) { rno = PciBAR0 + i*4; - v = pcicfgrw32(p->tbdf, rno, 0, 1); + v = pcicfgr32(p, rno); 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 { + } else { mtb->dev = p; mtb->bar = i; mtb->siz = size; @@ -396,17 +294,17 @@ pcibusmap(Pcidev *root, uvlong *pmema, ulong *pioa, int wrreg) 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); + 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; } @@ -418,21 +316,15 @@ pcibusmap(Pcidev *root, uvlong *pmema, ulong *pioa, int wrreg) 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); - } + 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; @@ -450,51 +342,19 @@ pcibusmap(Pcidev *root, uvlong *pmema, ulong *pioa, int wrreg) */ 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); + pcienable(p); 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; - } + /* 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); - 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); + /* Disable prefetch */ + pcisetwin(p, 0xFFF00000|8, 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); + /* Enable the bridge */ + pcienable(p); sioa = p->ioa.bar; smema = p->mema.bar; @@ -502,6 +362,53 @@ pcibusmap(Pcidev *root, uvlong *pmema, ulong *pioa, int wrreg) } } +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) { @@ -523,12 +430,16 @@ pcilscan(int bno, Pcidev** list, Pcidev *parent) * 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: no memory"); + panic("pcilscan: can't allocate memory"); p->tbdf = tbdf; p->vid = l; p->did = l>>16; @@ -546,7 +457,6 @@ pcilscan(int bno, Pcidev** list, Pcidev *parent) p->ccrb = pcicfgr8(p, PciCCRb); p->cls = pcicfgr8(p, PciCLS); p->ltr = pcicfgr8(p, PciLTR); - p->intl = pcicfgr8(p, PciINTL); /* @@ -614,8 +524,24 @@ pcilscan(int bno, Pcidev** list, Pcidev *parent) /* * Find PCI-PCI bridges and recursively descend the tree. */ - if(p->ccrb != 0x06 || p->ccru != 0x04) + 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 @@ -638,16 +564,75 @@ pcilscan(int bno, Pcidev** list, Pcidev *parent) * * 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); @@ -657,29 +642,67 @@ pcilscan(int bno, Pcidev** list, Pcidev *parent) return maxubn; } -static void -pcicfginit(void) +int +pciscan(int bno, Pcidev **list) { - uvlong mema; - ulong ioa; + return pcilscan(bno, list, nil); +} - fmtinstall('T', tbdffmt); +void +pcibussize(Pcidev *root, uvlong *msize, ulong *iosize) +{ + *msize = 0; + *iosize = 0; + pcibusmap(root, msize, iosize, 0); +} - pcilscan(0, &pciroot, nil); +Pcidev* +pcimatch(Pcidev* prev, int vid, int did) +{ + if(prev == nil) + prev = pcilist; + else + prev = prev->list; - /* - * Work out how big the top bus is - */ - ioa = 0; - mema = 0; - pcibusmap(pciroot, &mema, &ioa, 0); + while(prev != nil){ + if((vid == 0 || prev->vid == vid) + && (did == 0 || prev->did == did)) + break; + prev = prev->list; + } + return prev; +} - /* - * Align the windows and map it - */ - ioa = 0; - mema = soc.pciwin; - pcibusmap(pciroot, &mema, &ioa, 1); +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 @@ -688,21 +711,21 @@ 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); + 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"); @@ -714,12 +737,26 @@ pcilhinv(Pcidev* p) } } -static void +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) { @@ -826,17 +863,6 @@ 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) { @@ -908,6 +934,17 @@ pcisetpms(Pcidev* p, int state) 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) { @@ -936,12 +973,11 @@ pcienable(Pcidev *p) /* 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++; - } + 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); @@ -949,6 +985,15 @@ pcienable(Pcidev *p) 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 { @@ -966,7 +1011,7 @@ pcienable(Pcidev *p) 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); + pcicfgw32(p, PciPCR, 0xFFFF0000|p->pcr); } } @@ -977,165 +1022,3 @@ pcidisable(Pcidev *p) 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); -} diff --git a/sys/src/9/port/pci.h b/sys/src/9/port/pci.h new file mode 100644 index 000000000..25a6bb803 --- /dev/null +++ b/sys/src/9/port/pci.h @@ -0,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 diff --git a/sys/src/9/port/portmkfile b/sys/src/9/port/portmkfile index 5e88150c7..07f1b2518 100644 --- a/sys/src/9/port/portmkfile +++ b/sys/src/9/port/portmkfile @@ -40,7 +40,7 @@ clean:V: 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 @@ devether.$O ethersink.$O: ../port/etherif.h ../port/netif.h 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 diff --git a/sys/src/9/port/usbxhci.c b/sys/src/9/port/usbxhci.c index 1f87fddbe..5af746dfa 100644 --- 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" diff --git a/sys/src/9/ppc/fns.h b/sys/src/9/ppc/fns.h index 5ae2f8097..0606e3b69 100644 --- a/sys/src/9/ppc/fns.h +++ b/sys/src/9/ppc/fns.h @@ -67,12 +67,6 @@ void mmuinit(void); 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*); diff --git a/sys/src/9/teg2/ether8169.c b/sys/src/9/teg2/ether8169.c index d51816fcb..39bd5ae9f 100644 --- 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 @@ rtl8169pci(void) 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); diff --git a/sys/src/9/teg2/fns.h b/sys/src/9/teg2/fns.h index 62e253c27..801656c0e 100644 --- a/sys/src/9/teg2/fns.h +++ b/sys/src/9/teg2/fns.h @@ -88,28 +88,10 @@ extern void mmuidmap(uintptr phys, int mbs); 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); diff --git a/sys/src/9/teg2/io.h b/sys/src/9/teg2/io.h index e56d6c354..54818843b 100644 --- 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) diff --git a/sys/src/9/teg2/main.c b/sys/src/9/teg2/main.c index b08a00178..276a2fa68 100644 --- 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 diff --git a/sys/src/9/teg2/pci.c b/sys/src/9/teg2/pci.c deleted file mode 100644 index cd13902e8..000000000 --- a/sys/src/9/teg2/pci.c +++ /dev/null @@ -1,853 +0,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; -} diff --git a/sys/src/9/teg2/pciteg.c b/sys/src/9/teg2/pciteg.c new file mode 100644 index 000000000..d6cc8a291 --- /dev/null +++ b/sys/src/9/teg2/pciteg.c @@ -0,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(); +} diff --git a/sys/src/9/teg2/ts b/sys/src/9/teg2/ts index 0af12b757..3573a7dba 100644 --- a/sys/src/9/teg2/ts +++ b/sys/src/9/teg2/ts @@ -33,13 +33,14 @@ dev # usb link + pciteg archtegra ethermedium # flashtegra ecc loopbackmedium netdevmedium - ether8169 ethermii + ether8169 pci ethermii # usbohci # usbehci usbehcitegra @@ -54,7 +55,7 @@ ip esp misc - pci + pci pciteg rdb coproc v7-arch