From 4f85115526a87063489dc7cf347343bd520159b1 Mon Sep 17 00:00:00 2001 From: cinap_lenrek Date: Sun, 13 Sep 2020 20:33:17 +0200 Subject: kernel: massive pci code rewrite The new pci code is moved to port/pci.[hc] and shared by all ports. Each port has its own PCI controller implementation, providing the pcicfgrw*() functions for low level pci config space access. The locking for pcicfgrw*() is now done by the caller (only port/pci.c). Device drivers now need to include "../port/pci.h" in addition to "io.h". The new code now checks bridge windows and membars, while enumerating the bus, giving the pc driver a chance to re-assign them. This is needed because some UEFI implementations fail to assign the bars for some devices, so we need to do it outselfs. (See pcireservemem()). While working on this, it was discovered that the pci code assimed the smallest I/O bar size is 16 (pcibarsize()), which is wrong. I/O bars can be as small as 4 bytes. Bit 1 in an I/O bar is also reserved and should be masked off, making the port mask: port = bar & ~3; --- sys/src/9/teg2/ether8169.c | 12 +- sys/src/9/teg2/fns.h | 24 +- sys/src/9/teg2/io.h | 215 ------------ sys/src/9/teg2/main.c | 1 + sys/src/9/teg2/pci.c | 853 --------------------------------------------- sys/src/9/teg2/pciteg.c | 268 ++++++++++++++ sys/src/9/teg2/ts | 5 +- 7 files changed, 277 insertions(+), 1101 deletions(-) delete mode 100644 sys/src/9/teg2/pci.c create mode 100644 sys/src/9/teg2/pciteg.c (limited to 'sys/src/9/teg2') 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 -- cgit v1.2.3