17dd7cddfSDavid du Colombier /* 27dd7cddfSDavid du Colombier * PCI support code. 3e569ccb5SDavid du Colombier * Needs a massive rewrite. 47dd7cddfSDavid du Colombier */ 57dd7cddfSDavid du Colombier #include "u.h" 67dd7cddfSDavid du Colombier #include "../port/lib.h" 77dd7cddfSDavid du Colombier #include "mem.h" 87dd7cddfSDavid du Colombier #include "dat.h" 97dd7cddfSDavid du Colombier #include "fns.h" 107dd7cddfSDavid du Colombier #include "io.h" 117dd7cddfSDavid du Colombier #include "../port/error.h" 127dd7cddfSDavid du Colombier 137dd7cddfSDavid du Colombier #define DBG if(0) pcilog 147dd7cddfSDavid du Colombier 157dd7cddfSDavid du Colombier struct 167dd7cddfSDavid du Colombier { 177dd7cddfSDavid du Colombier char output[16384]; 187dd7cddfSDavid du Colombier int ptr; 197dd7cddfSDavid du Colombier }PCICONS; 207dd7cddfSDavid du Colombier 217dd7cddfSDavid du Colombier int 227dd7cddfSDavid du Colombier pcilog(char *fmt, ...) 237dd7cddfSDavid du Colombier { 247dd7cddfSDavid du Colombier int n; 257dd7cddfSDavid du Colombier va_list arg; 267dd7cddfSDavid du Colombier char buf[PRINTSIZE]; 277dd7cddfSDavid du Colombier 287dd7cddfSDavid du Colombier va_start(arg, fmt); 299a747e4fSDavid du Colombier n = vseprint(buf, buf+sizeof(buf), fmt, arg) - buf; 307dd7cddfSDavid du Colombier va_end(arg); 317dd7cddfSDavid du Colombier 327dd7cddfSDavid du Colombier memmove(PCICONS.output+PCICONS.ptr, buf, n); 337dd7cddfSDavid du Colombier PCICONS.ptr += n; 347dd7cddfSDavid du Colombier return n; 357dd7cddfSDavid du Colombier } 367dd7cddfSDavid du Colombier 377dd7cddfSDavid du Colombier enum 387dd7cddfSDavid du Colombier { /* configuration mechanism #1 */ 397dd7cddfSDavid du Colombier PciADDR = 0xCF8, /* CONFIG_ADDRESS */ 407dd7cddfSDavid du Colombier PciDATA = 0xCFC, /* CONFIG_DATA */ 417dd7cddfSDavid du Colombier 427dd7cddfSDavid du Colombier /* configuration mechanism #2 */ 437dd7cddfSDavid du Colombier PciCSE = 0xCF8, /* configuration space enable */ 447dd7cddfSDavid du Colombier PciFORWARD = 0xCFA, /* which bus */ 457dd7cddfSDavid du Colombier 467dd7cddfSDavid du Colombier MaxFNO = 7, 477dd7cddfSDavid du Colombier MaxUBN = 255, 487dd7cddfSDavid du Colombier }; 497dd7cddfSDavid du Colombier 507dd7cddfSDavid du Colombier enum 517dd7cddfSDavid du Colombier { /* command register */ 527dd7cddfSDavid du Colombier IOen = (1<<0), 537dd7cddfSDavid du Colombier MEMen = (1<<1), 547dd7cddfSDavid du Colombier MASen = (1<<2), 557dd7cddfSDavid du Colombier MemWrInv = (1<<4), 567dd7cddfSDavid du Colombier PErrEn = (1<<6), 577dd7cddfSDavid du Colombier SErrEn = (1<<8), 587dd7cddfSDavid du Colombier }; 597dd7cddfSDavid du Colombier 607dd7cddfSDavid du Colombier static Lock pcicfglock; 617dd7cddfSDavid du Colombier static Lock pcicfginitlock; 627dd7cddfSDavid du Colombier static int pcicfgmode = -1; 6359cc4ca5SDavid du Colombier static int pcimaxbno = 7; 647dd7cddfSDavid du Colombier static int pcimaxdno; 657dd7cddfSDavid du Colombier static Pcidev* pciroot; 667dd7cddfSDavid du Colombier static Pcidev* pcilist; 677dd7cddfSDavid du Colombier static Pcidev* pcitail; 683ff48bf5SDavid du Colombier static int nobios, nopcirouting; 697dd7cddfSDavid du Colombier 707dd7cddfSDavid du Colombier static int pcicfgrw32(int, int, int, int); 71e569ccb5SDavid du Colombier static int pcicfgrw16(int, int, int, int); 727dd7cddfSDavid du Colombier static int pcicfgrw8(int, int, int, int); 737dd7cddfSDavid du Colombier 747dd7cddfSDavid du Colombier static char* bustypes[] = { 757dd7cddfSDavid du Colombier "CBUSI", 767dd7cddfSDavid du Colombier "CBUSII", 777dd7cddfSDavid du Colombier "EISA", 787dd7cddfSDavid du Colombier "FUTURE", 797dd7cddfSDavid du Colombier "INTERN", 807dd7cddfSDavid du Colombier "ISA", 817dd7cddfSDavid du Colombier "MBI", 827dd7cddfSDavid du Colombier "MBII", 837dd7cddfSDavid du Colombier "MCA", 847dd7cddfSDavid du Colombier "MPI", 857dd7cddfSDavid du Colombier "MPSA", 867dd7cddfSDavid du Colombier "NUBUS", 877dd7cddfSDavid du Colombier "PCI", 887dd7cddfSDavid du Colombier "PCMCIA", 897dd7cddfSDavid du Colombier "TC", 907dd7cddfSDavid du Colombier "VL", 917dd7cddfSDavid du Colombier "VME", 927dd7cddfSDavid du Colombier "XPRESS", 937dd7cddfSDavid du Colombier }; 947dd7cddfSDavid du Colombier 957dd7cddfSDavid du Colombier #pragma varargck type "T" int 967dd7cddfSDavid du Colombier 977dd7cddfSDavid du Colombier static int 989a747e4fSDavid du Colombier tbdffmt(Fmt* fmt) 997dd7cddfSDavid du Colombier { 1007dd7cddfSDavid du Colombier char *p; 1019a747e4fSDavid du Colombier int l, r, type, tbdf; 1027dd7cddfSDavid du Colombier 1039a747e4fSDavid du Colombier if((p = malloc(READSTR)) == nil) 1049a747e4fSDavid du Colombier return fmtstrcpy(fmt, "(tbdfconv)"); 1057dd7cddfSDavid du Colombier 1069a747e4fSDavid du Colombier switch(fmt->r){ 1077dd7cddfSDavid du Colombier case 'T': 1089a747e4fSDavid du Colombier tbdf = va_arg(fmt->args, int); 1097dd7cddfSDavid du Colombier type = BUSTYPE(tbdf); 1107dd7cddfSDavid du Colombier if(type < nelem(bustypes)) 1117dd7cddfSDavid du Colombier l = snprint(p, READSTR, bustypes[type]); 1127dd7cddfSDavid du Colombier else 1137dd7cddfSDavid du Colombier l = snprint(p, READSTR, "%d", type); 1147dd7cddfSDavid du Colombier snprint(p+l, READSTR-l, ".%d.%d.%d", 1157dd7cddfSDavid du Colombier BUSBNO(tbdf), BUSDNO(tbdf), BUSFNO(tbdf)); 1167dd7cddfSDavid du Colombier break; 1177dd7cddfSDavid du Colombier 1187dd7cddfSDavid du Colombier default: 1197dd7cddfSDavid du Colombier snprint(p, READSTR, "(tbdfconv)"); 1207dd7cddfSDavid du Colombier break; 1217dd7cddfSDavid du Colombier } 1229a747e4fSDavid du Colombier r = fmtstrcpy(fmt, p); 1237dd7cddfSDavid du Colombier free(p); 1247dd7cddfSDavid du Colombier 1259a747e4fSDavid du Colombier return r; 1267dd7cddfSDavid du Colombier } 1277dd7cddfSDavid du Colombier 1287dd7cddfSDavid du Colombier ulong 1297dd7cddfSDavid du Colombier pcibarsize(Pcidev *p, int rno) 1307dd7cddfSDavid du Colombier { 1317dd7cddfSDavid du Colombier ulong v, size; 1327dd7cddfSDavid du Colombier 1337dd7cddfSDavid du Colombier v = pcicfgrw32(p->tbdf, rno, 0, 1); 1347dd7cddfSDavid du Colombier pcicfgrw32(p->tbdf, rno, 0xFFFFFFF0, 0); 1357dd7cddfSDavid du Colombier size = pcicfgrw32(p->tbdf, rno, 0, 1); 1367dd7cddfSDavid du Colombier if(v & 1) 1377dd7cddfSDavid du Colombier size |= 0xFFFF0000; 1387dd7cddfSDavid du Colombier pcicfgrw32(p->tbdf, rno, v, 0); 1397dd7cddfSDavid du Colombier 1407dd7cddfSDavid du Colombier return -(size & ~0x0F); 1417dd7cddfSDavid du Colombier } 1427dd7cddfSDavid du Colombier 1437dd7cddfSDavid du Colombier static int 1447dd7cddfSDavid du Colombier pcisizcmp(void *a, void *b) 1457dd7cddfSDavid du Colombier { 1467dd7cddfSDavid du Colombier Pcisiz *aa, *bb; 1477dd7cddfSDavid du Colombier 1487dd7cddfSDavid du Colombier aa = a; 1497dd7cddfSDavid du Colombier bb = b; 1507dd7cddfSDavid du Colombier return aa->siz - bb->siz; 1517dd7cddfSDavid du Colombier } 1527dd7cddfSDavid du Colombier 1537dd7cddfSDavid du Colombier static ulong 1547dd7cddfSDavid du Colombier pcimask(ulong v) 1557dd7cddfSDavid du Colombier { 1567dd7cddfSDavid du Colombier ulong m; 1577dd7cddfSDavid du Colombier 1587dd7cddfSDavid du Colombier m = BI2BY*sizeof(v); 1597dd7cddfSDavid du Colombier for(m = 1<<(m-1); m != 0; m >>= 1) { 1607dd7cddfSDavid du Colombier if(m & v) 1617dd7cddfSDavid du Colombier break; 1627dd7cddfSDavid du Colombier } 1637dd7cddfSDavid du Colombier 1647dd7cddfSDavid du Colombier m--; 1657dd7cddfSDavid du Colombier if((v & m) == 0) 1667dd7cddfSDavid du Colombier return v; 1677dd7cddfSDavid du Colombier 1687dd7cddfSDavid du Colombier v |= m; 1697dd7cddfSDavid du Colombier return v+1; 1707dd7cddfSDavid du Colombier } 1717dd7cddfSDavid du Colombier 1727dd7cddfSDavid du Colombier static void 1737dd7cddfSDavid du Colombier pcibusmap(Pcidev *root, ulong *pmema, ulong *pioa, int wrreg) 1747dd7cddfSDavid du Colombier { 1757dd7cddfSDavid du Colombier Pcidev *p; 1767dd7cddfSDavid du Colombier int ntb, i, size, rno, hole; 1777dd7cddfSDavid du Colombier ulong v, mema, ioa, sioa, smema, base, limit; 1787dd7cddfSDavid du Colombier Pcisiz *table, *tptr, *mtb, *itb; 1797dd7cddfSDavid du Colombier extern void qsort(void*, long, long, int (*)(void*, void*)); 1807dd7cddfSDavid du Colombier 18180ee5cbfSDavid du Colombier if(!nobios) 1827dd7cddfSDavid du Colombier return; 1837dd7cddfSDavid du Colombier 1847dd7cddfSDavid du Colombier ioa = *pioa; 1857dd7cddfSDavid du Colombier mema = *pmema; 1867dd7cddfSDavid du Colombier 1877dd7cddfSDavid du Colombier DBG("pcibusmap wr=%d %T mem=%luX io=%luX\n", 1887dd7cddfSDavid du Colombier wrreg, root->tbdf, mema, ioa); 1897dd7cddfSDavid du Colombier 1907dd7cddfSDavid du Colombier ntb = 0; 1917dd7cddfSDavid du Colombier for(p = root; p != nil; p = p->link) 1927dd7cddfSDavid du Colombier ntb++; 1937dd7cddfSDavid du Colombier 1947dd7cddfSDavid du Colombier ntb *= (PciCIS-PciBAR0)/4; 1957dd7cddfSDavid du Colombier table = malloc(2*ntb*sizeof(Pcisiz)); 1967dd7cddfSDavid du Colombier itb = table; 1977dd7cddfSDavid du Colombier mtb = table+ntb; 1987dd7cddfSDavid du Colombier 1997dd7cddfSDavid du Colombier /* 2007dd7cddfSDavid du Colombier * Build a table of sizes 2017dd7cddfSDavid du Colombier */ 2027dd7cddfSDavid du Colombier for(p = root; p != nil; p = p->link) { 2037dd7cddfSDavid du Colombier if(p->ccrb == 0x06) { 2047dd7cddfSDavid du Colombier if(p->ccru != 0x04 || p->bridge == nil) { 2057dd7cddfSDavid du Colombier // DBG("pci: ignored bridge %T\n", p->tbdf); 2067dd7cddfSDavid du Colombier continue; 2077dd7cddfSDavid du Colombier } 2087dd7cddfSDavid du Colombier 2097dd7cddfSDavid du Colombier sioa = ioa; 2107dd7cddfSDavid du Colombier smema = mema; 2117dd7cddfSDavid du Colombier pcibusmap(p->bridge, &smema, &sioa, 0); 2127dd7cddfSDavid du Colombier 2137dd7cddfSDavid du Colombier hole = pcimask(smema-mema); 2147dd7cddfSDavid du Colombier if(hole < (1<<20)) 2157dd7cddfSDavid du Colombier hole = 1<<20; 2167dd7cddfSDavid du Colombier p->mema.size = hole; 2177dd7cddfSDavid du Colombier 2187dd7cddfSDavid du Colombier hole = pcimask(sioa-ioa); 2197dd7cddfSDavid du Colombier if(hole < (1<<12)) 2207dd7cddfSDavid du Colombier hole = 1<<12; 2217dd7cddfSDavid du Colombier 2227dd7cddfSDavid du Colombier p->ioa.size = hole; 2237dd7cddfSDavid du Colombier 2247dd7cddfSDavid du Colombier itb->dev = p; 2257dd7cddfSDavid du Colombier itb->bar = -1; 2267dd7cddfSDavid du Colombier itb->siz = p->ioa.size; 2277dd7cddfSDavid du Colombier itb++; 2287dd7cddfSDavid du Colombier 2297dd7cddfSDavid du Colombier mtb->dev = p; 2307dd7cddfSDavid du Colombier mtb->bar = -1; 2317dd7cddfSDavid du Colombier mtb->siz = p->mema.size; 2327dd7cddfSDavid du Colombier mtb++; 2337dd7cddfSDavid du Colombier continue; 2347dd7cddfSDavid du Colombier } 2357dd7cddfSDavid du Colombier 2367dd7cddfSDavid du Colombier for(i = 0; i <= 5; i++) { 2377dd7cddfSDavid du Colombier rno = PciBAR0 + i*4; 2387dd7cddfSDavid du Colombier v = pcicfgrw32(p->tbdf, rno, 0, 1); 2397dd7cddfSDavid du Colombier size = pcibarsize(p, rno); 2407dd7cddfSDavid du Colombier if(size == 0) 2417dd7cddfSDavid du Colombier continue; 2427dd7cddfSDavid du Colombier 2437dd7cddfSDavid du Colombier if(v & 1) { 2447dd7cddfSDavid du Colombier itb->dev = p; 2457dd7cddfSDavid du Colombier itb->bar = i; 2467dd7cddfSDavid du Colombier itb->siz = size; 2477dd7cddfSDavid du Colombier itb++; 2487dd7cddfSDavid du Colombier } 2497dd7cddfSDavid du Colombier else { 2507dd7cddfSDavid du Colombier mtb->dev = p; 2517dd7cddfSDavid du Colombier mtb->bar = i; 2527dd7cddfSDavid du Colombier mtb->siz = size; 2537dd7cddfSDavid du Colombier mtb++; 2547dd7cddfSDavid du Colombier } 2557dd7cddfSDavid du Colombier 2567dd7cddfSDavid du Colombier p->mem[i].size = size; 2577dd7cddfSDavid du Colombier } 2587dd7cddfSDavid du Colombier } 2597dd7cddfSDavid du Colombier 2607dd7cddfSDavid du Colombier /* 2617dd7cddfSDavid du Colombier * Sort both tables IO smallest first, Memory largest 2627dd7cddfSDavid du Colombier */ 2637dd7cddfSDavid du Colombier qsort(table, itb-table, sizeof(Pcisiz), pcisizcmp); 2647dd7cddfSDavid du Colombier tptr = table+ntb; 2657dd7cddfSDavid du Colombier qsort(tptr, mtb-tptr, sizeof(Pcisiz), pcisizcmp); 2667dd7cddfSDavid du Colombier 2677dd7cddfSDavid du Colombier /* 2687dd7cddfSDavid du Colombier * Allocate IO address space on this bus 2697dd7cddfSDavid du Colombier */ 2707dd7cddfSDavid du Colombier for(tptr = table; tptr < itb; tptr++) { 2717dd7cddfSDavid du Colombier hole = tptr->siz; 2727dd7cddfSDavid du Colombier if(tptr->bar == -1) 2737dd7cddfSDavid du Colombier hole = 1<<12; 2747dd7cddfSDavid du Colombier ioa = (ioa+hole-1) & ~(hole-1); 2757dd7cddfSDavid du Colombier 2767dd7cddfSDavid du Colombier p = tptr->dev; 2777dd7cddfSDavid du Colombier if(tptr->bar == -1) 2787dd7cddfSDavid du Colombier p->ioa.bar = ioa; 2797dd7cddfSDavid du Colombier else { 2807dd7cddfSDavid du Colombier p->pcr |= IOen; 2817dd7cddfSDavid du Colombier p->mem[tptr->bar].bar = ioa|1; 2827dd7cddfSDavid du Colombier if(wrreg) 2837dd7cddfSDavid du Colombier pcicfgrw32(p->tbdf, PciBAR0+(tptr->bar*4), ioa|1, 0); 2847dd7cddfSDavid du Colombier } 2857dd7cddfSDavid du Colombier 2867dd7cddfSDavid du Colombier ioa += tptr->siz; 2877dd7cddfSDavid du Colombier } 2887dd7cddfSDavid du Colombier 2897dd7cddfSDavid du Colombier /* 2907dd7cddfSDavid du Colombier * Allocate Memory address space on this bus 2917dd7cddfSDavid du Colombier */ 2927dd7cddfSDavid du Colombier for(tptr = table+ntb; tptr < mtb; tptr++) { 2937dd7cddfSDavid du Colombier hole = tptr->siz; 2947dd7cddfSDavid du Colombier if(tptr->bar == -1) 2957dd7cddfSDavid du Colombier hole = 1<<20; 2967dd7cddfSDavid du Colombier mema = (mema+hole-1) & ~(hole-1); 2977dd7cddfSDavid du Colombier 2987dd7cddfSDavid du Colombier p = tptr->dev; 2997dd7cddfSDavid du Colombier if(tptr->bar == -1) 3007dd7cddfSDavid du Colombier p->mema.bar = mema; 3017dd7cddfSDavid du Colombier else { 3027dd7cddfSDavid du Colombier p->pcr |= MEMen; 3037dd7cddfSDavid du Colombier p->mem[tptr->bar].bar = mema; 3047dd7cddfSDavid du Colombier if(wrreg) 3057dd7cddfSDavid du Colombier pcicfgrw32(p->tbdf, PciBAR0+(tptr->bar*4), mema, 0); 3067dd7cddfSDavid du Colombier } 3077dd7cddfSDavid du Colombier mema += tptr->siz; 3087dd7cddfSDavid du Colombier } 3097dd7cddfSDavid du Colombier 3107dd7cddfSDavid du Colombier *pmema = mema; 3117dd7cddfSDavid du Colombier *pioa = ioa; 3127dd7cddfSDavid du Colombier free(table); 3137dd7cddfSDavid du Colombier 3147dd7cddfSDavid du Colombier if(wrreg == 0) 3157dd7cddfSDavid du Colombier return; 3167dd7cddfSDavid du Colombier 3177dd7cddfSDavid du Colombier /* 3187dd7cddfSDavid du Colombier * Finally set all the bridge addresses & registers 3197dd7cddfSDavid du Colombier */ 3207dd7cddfSDavid du Colombier for(p = root; p != nil; p = p->link) { 3217dd7cddfSDavid du Colombier if(p->bridge == nil) { 3227dd7cddfSDavid du Colombier pcicfgrw8(p->tbdf, PciLTR, 64, 0); 3237dd7cddfSDavid du Colombier 3247dd7cddfSDavid du Colombier p->pcr |= MASen; 325e569ccb5SDavid du Colombier pcicfgrw16(p->tbdf, PciPCR, p->pcr, 0); 3267dd7cddfSDavid du Colombier continue; 3277dd7cddfSDavid du Colombier } 3287dd7cddfSDavid du Colombier 3297dd7cddfSDavid du Colombier base = p->ioa.bar; 3307dd7cddfSDavid du Colombier limit = base+p->ioa.size-1; 331d0f3faacSDavid du Colombier v = pcicfgrw32(p->tbdf, PciIBR, 0, 1); 3327dd7cddfSDavid du Colombier v = (v&0xFFFF0000)|(limit & 0xF000)|((base & 0xF000)>>8); 333d0f3faacSDavid du Colombier pcicfgrw32(p->tbdf, PciIBR, v, 0); 3347dd7cddfSDavid du Colombier v = (limit & 0xFFFF0000)|(base>>16); 335d0f3faacSDavid du Colombier pcicfgrw32(p->tbdf, PciIUBR, v, 0); 3367dd7cddfSDavid du Colombier 3377dd7cddfSDavid du Colombier base = p->mema.bar; 3387dd7cddfSDavid du Colombier limit = base+p->mema.size-1; 3397dd7cddfSDavid du Colombier v = (limit & 0xFFF00000)|((base & 0xFFF00000)>>16); 340d0f3faacSDavid du Colombier pcicfgrw32(p->tbdf, PciMBR, v, 0); 3417dd7cddfSDavid du Colombier 3427dd7cddfSDavid du Colombier /* 3437dd7cddfSDavid du Colombier * Disable memory prefetch 3447dd7cddfSDavid du Colombier */ 345d0f3faacSDavid du Colombier pcicfgrw32(p->tbdf, PciPMBR, 0x0000FFFF, 0); 3467dd7cddfSDavid du Colombier pcicfgrw8(p->tbdf, PciLTR, 64, 0); 3477dd7cddfSDavid du Colombier 3487dd7cddfSDavid du Colombier /* 3497dd7cddfSDavid du Colombier * Enable the bridge 3507dd7cddfSDavid du Colombier */ 351e569ccb5SDavid du Colombier p->pcr |= IOen|MEMen|MASen; 352e569ccb5SDavid du Colombier pcicfgrw32(p->tbdf, PciPCR, 0xFFFF0000|p->pcr , 0); 3537dd7cddfSDavid du Colombier 3547dd7cddfSDavid du Colombier sioa = p->ioa.bar; 3557dd7cddfSDavid du Colombier smema = p->mema.bar; 3567dd7cddfSDavid du Colombier pcibusmap(p->bridge, &smema, &sioa, 1); 3577dd7cddfSDavid du Colombier } 3587dd7cddfSDavid du Colombier } 3597dd7cddfSDavid du Colombier 3607dd7cddfSDavid du Colombier static int 3619a747e4fSDavid du Colombier pcilscan(int bno, Pcidev** list) 3627dd7cddfSDavid du Colombier { 3637dd7cddfSDavid du Colombier Pcidev *p, *head, *tail; 3647dd7cddfSDavid du Colombier int dno, fno, i, hdt, l, maxfno, maxubn, rno, sbn, tbdf, ubn; 3657dd7cddfSDavid du Colombier 3667dd7cddfSDavid du Colombier maxubn = bno; 3677dd7cddfSDavid du Colombier head = nil; 3687dd7cddfSDavid du Colombier tail = nil; 3697dd7cddfSDavid du Colombier for(dno = 0; dno <= pcimaxdno; dno++){ 3707dd7cddfSDavid du Colombier maxfno = 0; 3717dd7cddfSDavid du Colombier for(fno = 0; fno <= maxfno; fno++){ 3727dd7cddfSDavid du Colombier /* 3737dd7cddfSDavid du Colombier * For this possible device, form the 3747dd7cddfSDavid du Colombier * bus+device+function triplet needed to address it 3757dd7cddfSDavid du Colombier * and try to read the vendor and device ID. 3767dd7cddfSDavid du Colombier * If successful, allocate a device struct and 3777dd7cddfSDavid du Colombier * start to fill it in with some useful information 3787dd7cddfSDavid du Colombier * from the device's configuration space. 3797dd7cddfSDavid du Colombier */ 3807dd7cddfSDavid du Colombier tbdf = MKBUS(BusPCI, bno, dno, fno); 3817dd7cddfSDavid du Colombier l = pcicfgrw32(tbdf, PciVID, 0, 1); 3827dd7cddfSDavid du Colombier if(l == 0xFFFFFFFF || l == 0) 3837dd7cddfSDavid du Colombier continue; 3847dd7cddfSDavid du Colombier p = malloc(sizeof(*p)); 3857dd7cddfSDavid du Colombier p->tbdf = tbdf; 3867dd7cddfSDavid du Colombier p->vid = l; 3877dd7cddfSDavid du Colombier p->did = l>>16; 3887dd7cddfSDavid du Colombier 3897dd7cddfSDavid du Colombier if(pcilist != nil) 3907dd7cddfSDavid du Colombier pcitail->list = p; 3917dd7cddfSDavid du Colombier else 3927dd7cddfSDavid du Colombier pcilist = p; 3937dd7cddfSDavid du Colombier pcitail = p; 3947dd7cddfSDavid du Colombier 395e569ccb5SDavid du Colombier p->pcr = pcicfgr16(p, PciPCR); 3967dd7cddfSDavid du Colombier p->rid = pcicfgr8(p, PciRID); 3977dd7cddfSDavid du Colombier p->ccrp = pcicfgr8(p, PciCCRp); 3987dd7cddfSDavid du Colombier p->ccru = pcicfgr8(p, PciCCRu); 3997dd7cddfSDavid du Colombier p->ccrb = pcicfgr8(p, PciCCRb); 400e569ccb5SDavid du Colombier p->cls = pcicfgr8(p, PciCLS); 401e569ccb5SDavid du Colombier p->ltr = pcicfgr8(p, PciLTR); 4027dd7cddfSDavid du Colombier 4037dd7cddfSDavid du Colombier p->intl = pcicfgr8(p, PciINTL); 4047dd7cddfSDavid du Colombier 4057dd7cddfSDavid du Colombier /* 4067dd7cddfSDavid du Colombier * If the device is a multi-function device adjust the 4077dd7cddfSDavid du Colombier * loop count so all possible functions are checked. 4087dd7cddfSDavid du Colombier */ 4097dd7cddfSDavid du Colombier hdt = pcicfgr8(p, PciHDT); 4107dd7cddfSDavid du Colombier if(hdt & 0x80) 4117dd7cddfSDavid du Colombier maxfno = MaxFNO; 4127dd7cddfSDavid du Colombier 4137dd7cddfSDavid du Colombier /* 4147dd7cddfSDavid du Colombier * If appropriate, read the base address registers 4157dd7cddfSDavid du Colombier * and work out the sizes. 4167dd7cddfSDavid du Colombier */ 4177dd7cddfSDavid du Colombier switch(p->ccrb) { 4187dd7cddfSDavid du Colombier case 0x01: /* mass storage controller */ 4197dd7cddfSDavid du Colombier case 0x02: /* network controller */ 4207dd7cddfSDavid du Colombier case 0x03: /* display controller */ 4217dd7cddfSDavid du Colombier case 0x04: /* multimedia device */ 4227dd7cddfSDavid du Colombier case 0x07: /* simple comm. controllers */ 4237dd7cddfSDavid du Colombier case 0x08: /* base system peripherals */ 4247dd7cddfSDavid du Colombier case 0x09: /* input devices */ 4257dd7cddfSDavid du Colombier case 0x0A: /* docking stations */ 4267dd7cddfSDavid du Colombier case 0x0B: /* processors */ 4277dd7cddfSDavid du Colombier case 0x0C: /* serial bus controllers */ 4287dd7cddfSDavid du Colombier if((hdt & 0x7F) != 0) 4297dd7cddfSDavid du Colombier break; 4307dd7cddfSDavid du Colombier rno = PciBAR0 - 4; 4317dd7cddfSDavid du Colombier for(i = 0; i < nelem(p->mem); i++) { 4327dd7cddfSDavid du Colombier rno += 4; 4337dd7cddfSDavid du Colombier p->mem[i].bar = pcicfgr32(p, rno); 4347dd7cddfSDavid du Colombier p->mem[i].size = pcibarsize(p, rno); 4357dd7cddfSDavid du Colombier } 4367dd7cddfSDavid du Colombier break; 4377dd7cddfSDavid du Colombier 4387dd7cddfSDavid du Colombier case 0x00: 4397dd7cddfSDavid du Colombier case 0x05: /* memory controller */ 4407dd7cddfSDavid du Colombier case 0x06: /* bridge device */ 4417dd7cddfSDavid du Colombier default: 4427dd7cddfSDavid du Colombier break; 4437dd7cddfSDavid du Colombier } 4447dd7cddfSDavid du Colombier 4457dd7cddfSDavid du Colombier if(head != nil) 4467dd7cddfSDavid du Colombier tail->link = p; 4477dd7cddfSDavid du Colombier else 4487dd7cddfSDavid du Colombier head = p; 4497dd7cddfSDavid du Colombier tail = p; 4507dd7cddfSDavid du Colombier } 4517dd7cddfSDavid du Colombier } 4527dd7cddfSDavid du Colombier 4537dd7cddfSDavid du Colombier *list = head; 4547dd7cddfSDavid du Colombier for(p = head; p != nil; p = p->link){ 4557dd7cddfSDavid du Colombier /* 4567dd7cddfSDavid du Colombier * Find PCI-PCI bridges and recursively descend the tree. 4577dd7cddfSDavid du Colombier */ 4587dd7cddfSDavid du Colombier if(p->ccrb != 0x06 || p->ccru != 0x04) 4597dd7cddfSDavid du Colombier continue; 4607dd7cddfSDavid du Colombier 4617dd7cddfSDavid du Colombier /* 4627dd7cddfSDavid du Colombier * If the secondary or subordinate bus number is not 4637dd7cddfSDavid du Colombier * initialised try to do what the PCI BIOS should have 4647dd7cddfSDavid du Colombier * done and fill in the numbers as the tree is descended. 4657dd7cddfSDavid du Colombier * On the way down the subordinate bus number is set to 4667dd7cddfSDavid du Colombier * the maximum as it's not known how many buses are behind 4677dd7cddfSDavid du Colombier * this one; the final value is set on the way back up. 4687dd7cddfSDavid du Colombier */ 4697dd7cddfSDavid du Colombier sbn = pcicfgr8(p, PciSBN); 4707dd7cddfSDavid du Colombier ubn = pcicfgr8(p, PciUBN); 4717dd7cddfSDavid du Colombier 47280ee5cbfSDavid du Colombier if(sbn == 0 || ubn == 0 || nobios) { 4737dd7cddfSDavid du Colombier sbn = maxubn+1; 4747dd7cddfSDavid du Colombier /* 4757dd7cddfSDavid du Colombier * Make sure memory, I/O and master enables are 4767dd7cddfSDavid du Colombier * off, set the primary, secondary and subordinate 4777dd7cddfSDavid du Colombier * bus numbers and clear the secondary status before 4787dd7cddfSDavid du Colombier * attempting to scan the secondary bus. 4797dd7cddfSDavid du Colombier * 4807dd7cddfSDavid du Colombier * Initialisation of the bridge should be done here. 4817dd7cddfSDavid du Colombier */ 4827dd7cddfSDavid du Colombier pcicfgw32(p, PciPCR, 0xFFFF0000); 4837dd7cddfSDavid du Colombier l = (MaxUBN<<16)|(sbn<<8)|bno; 4847dd7cddfSDavid du Colombier pcicfgw32(p, PciPBN, l); 4857dd7cddfSDavid du Colombier pcicfgw16(p, PciSPSR, 0xFFFF); 4869a747e4fSDavid du Colombier maxubn = pcilscan(sbn, &p->bridge); 4877dd7cddfSDavid du Colombier l = (maxubn<<16)|(sbn<<8)|bno; 4887dd7cddfSDavid du Colombier 4897dd7cddfSDavid du Colombier pcicfgw32(p, PciPBN, l); 4907dd7cddfSDavid du Colombier } 4917dd7cddfSDavid du Colombier else { 492e569ccb5SDavid du Colombier if(ubn > maxubn) 4937dd7cddfSDavid du Colombier maxubn = ubn; 4949a747e4fSDavid du Colombier pcilscan(sbn, &p->bridge); 4957dd7cddfSDavid du Colombier } 4967dd7cddfSDavid du Colombier } 4977dd7cddfSDavid du Colombier 4987dd7cddfSDavid du Colombier return maxubn; 4997dd7cddfSDavid du Colombier } 5007dd7cddfSDavid du Colombier 5019a747e4fSDavid du Colombier int 5029a747e4fSDavid du Colombier pciscan(int bno, Pcidev **list) 5039a747e4fSDavid du Colombier { 5049a747e4fSDavid du Colombier int ubn; 5059a747e4fSDavid du Colombier 5069a747e4fSDavid du Colombier lock(&pcicfginitlock); 5079a747e4fSDavid du Colombier ubn = pcilscan(bno, list); 5089a747e4fSDavid du Colombier unlock(&pcicfginitlock); 5099a747e4fSDavid du Colombier return ubn; 5109a747e4fSDavid du Colombier } 5119a747e4fSDavid du Colombier 5129a747e4fSDavid du Colombier static uchar 51359c21d95SDavid du Colombier pIIxget(Pcidev *router, uchar link) 5149a747e4fSDavid du Colombier { 5159a747e4fSDavid du Colombier uchar pirq; 5169a747e4fSDavid du Colombier 5179a747e4fSDavid du Colombier /* link should be 0x60, 0x61, 0x62, 0x63 */ 5189a747e4fSDavid du Colombier pirq = pcicfgr8(router, link); 5199a747e4fSDavid du Colombier return (pirq < 16)? pirq: 0; 5209a747e4fSDavid du Colombier } 5219a747e4fSDavid du Colombier 5229a747e4fSDavid du Colombier static void 52359c21d95SDavid du Colombier pIIxset(Pcidev *router, uchar link, uchar irq) 5249a747e4fSDavid du Colombier { 5259a747e4fSDavid du Colombier pcicfgw8(router, link, irq); 5269a747e4fSDavid du Colombier } 5279a747e4fSDavid du Colombier 5289a747e4fSDavid du Colombier static uchar 52959c21d95SDavid du Colombier viaget(Pcidev *router, uchar link) 5309a747e4fSDavid du Colombier { 5319a747e4fSDavid du Colombier uchar pirq; 5329a747e4fSDavid du Colombier 5339a747e4fSDavid du Colombier /* link should be 1, 2, 3, 5 */ 5349a747e4fSDavid du Colombier pirq = (link < 6)? pcicfgr8(router, 0x55 + (link>>1)): 0; 5359a747e4fSDavid du Colombier 5369a747e4fSDavid du Colombier return (link & 1)? (pirq >> 4): (pirq & 15); 5379a747e4fSDavid du Colombier } 5389a747e4fSDavid du Colombier 5399a747e4fSDavid du Colombier static void 54059c21d95SDavid du Colombier viaset(Pcidev *router, uchar link, uchar irq) 5419a747e4fSDavid du Colombier { 5429a747e4fSDavid du Colombier uchar pirq; 5439a747e4fSDavid du Colombier 5449a747e4fSDavid du Colombier pirq = pcicfgr8(router, 0x55 + (link >> 1)); 5459a747e4fSDavid du Colombier pirq &= (link & 1)? 0x0f: 0xf0; 5469a747e4fSDavid du Colombier pirq |= (link & 1)? (irq << 4): (irq & 15); 5479a747e4fSDavid du Colombier pcicfgw8(router, 0x55 + (link>>1), pirq); 5489a747e4fSDavid du Colombier } 5499a747e4fSDavid du Colombier 5509a747e4fSDavid du Colombier static uchar 55159c21d95SDavid du Colombier optiget(Pcidev *router, uchar link) 5529a747e4fSDavid du Colombier { 5539a747e4fSDavid du Colombier uchar pirq = 0; 5549a747e4fSDavid du Colombier 5559a747e4fSDavid du Colombier /* link should be 0x02, 0x12, 0x22, 0x32 */ 5569a747e4fSDavid du Colombier if ((link & 0xcf) == 0x02) 5579a747e4fSDavid du Colombier pirq = pcicfgr8(router, 0xb8 + (link >> 5)); 5589a747e4fSDavid du Colombier return (link & 0x10)? (pirq >> 4): (pirq & 15); 5599a747e4fSDavid du Colombier } 5609a747e4fSDavid du Colombier 5619a747e4fSDavid du Colombier static void 56259c21d95SDavid du Colombier optiset(Pcidev *router, uchar link, uchar irq) 5639a747e4fSDavid du Colombier { 5649a747e4fSDavid du Colombier uchar pirq; 5659a747e4fSDavid du Colombier 5669a747e4fSDavid du Colombier pirq = pcicfgr8(router, 0xb8 + (link >> 5)); 5679a747e4fSDavid du Colombier pirq &= (link & 0x10)? 0x0f : 0xf0; 5689a747e4fSDavid du Colombier pirq |= (link & 0x10)? (irq << 4): (irq & 15); 5699a747e4fSDavid du Colombier pcicfgw8(router, 0xb8 + (link >> 5), pirq); 5709a747e4fSDavid du Colombier } 5719a747e4fSDavid du Colombier 5729a747e4fSDavid du Colombier static uchar 57359c21d95SDavid du Colombier aliget(Pcidev *router, uchar link) 5749a747e4fSDavid du Colombier { 5759a747e4fSDavid du Colombier /* No, you're not dreaming */ 5769a747e4fSDavid du Colombier static const uchar map[] = { 0, 9, 3, 10, 4, 5, 7, 6, 1, 11, 0, 12, 0, 14, 0, 15 }; 5779a747e4fSDavid du Colombier uchar pirq; 5789a747e4fSDavid du Colombier 5799a747e4fSDavid du Colombier /* link should be 0x01..0x08 */ 5809a747e4fSDavid du Colombier pirq = pcicfgr8(router, 0x48 + ((link-1)>>1)); 5819a747e4fSDavid du Colombier return (link & 1)? map[pirq&15]: map[pirq>>4]; 5829a747e4fSDavid du Colombier } 5839a747e4fSDavid du Colombier 5849a747e4fSDavid du Colombier static void 58559c21d95SDavid du Colombier aliset(Pcidev *router, uchar link, uchar irq) 5869a747e4fSDavid du Colombier { 58759c21d95SDavid du Colombier /* Inverse of map in aliget */ 5889a747e4fSDavid du Colombier static const uchar map[] = { 0, 8, 0, 2, 4, 5, 7, 6, 0, 1, 3, 9, 11, 0, 13, 15 }; 5899a747e4fSDavid du Colombier uchar pirq; 5909a747e4fSDavid du Colombier 5919a747e4fSDavid du Colombier pirq = pcicfgr8(router, 0x48 + ((link-1)>>1)); 5929a747e4fSDavid du Colombier pirq &= (link & 1)? 0x0f: 0xf0; 5939a747e4fSDavid du Colombier pirq |= (link & 1)? (map[irq] << 4): (map[irq] & 15); 5949a747e4fSDavid du Colombier pcicfgw8(router, 0x48 + ((link-1)>>1), pirq); 5959a747e4fSDavid du Colombier } 5969a747e4fSDavid du Colombier 5979a747e4fSDavid du Colombier static uchar 59859c21d95SDavid du Colombier cyrixget(Pcidev *router, uchar link) 5999a747e4fSDavid du Colombier { 6009a747e4fSDavid du Colombier uchar pirq; 6019a747e4fSDavid du Colombier 6029a747e4fSDavid du Colombier /* link should be 1, 2, 3, 4 */ 6039a747e4fSDavid du Colombier pirq = pcicfgr8(router, 0x5c + ((link-1)>>1)); 6049a747e4fSDavid du Colombier return ((link & 1)? pirq >> 4: pirq & 15); 6059a747e4fSDavid du Colombier } 6069a747e4fSDavid du Colombier 6079a747e4fSDavid du Colombier static void 60859c21d95SDavid du Colombier cyrixset(Pcidev *router, uchar link, uchar irq) 6099a747e4fSDavid du Colombier { 6109a747e4fSDavid du Colombier uchar pirq; 6119a747e4fSDavid du Colombier 6129a747e4fSDavid du Colombier pirq = pcicfgr8(router, 0x5c + (link>>1)); 6139a747e4fSDavid du Colombier pirq &= (link & 1)? 0x0f: 0xf0; 6149a747e4fSDavid du Colombier pirq |= (link & 1)? (irq << 4): (irq & 15); 6159a747e4fSDavid du Colombier pcicfgw8(router, 0x5c + (link>>1), pirq); 6169a747e4fSDavid du Colombier } 6179a747e4fSDavid du Colombier 61859c21d95SDavid du Colombier typedef struct Bridge Bridge; 61959c21d95SDavid du Colombier struct Bridge 6209a747e4fSDavid du Colombier { 6219a747e4fSDavid du Colombier ushort vid; 6229a747e4fSDavid du Colombier ushort did; 6239a747e4fSDavid du Colombier uchar (*get)(Pcidev *, uchar); 6249a747e4fSDavid du Colombier void (*set)(Pcidev *, uchar, uchar); 6259a747e4fSDavid du Colombier }; 6269a747e4fSDavid du Colombier 62759c21d95SDavid du Colombier static Bridge southbridges[] = { 62859c21d95SDavid du Colombier { 0x8086, 0x122e, pIIxget, pIIxset }, // Intel 82371FB 62959c21d95SDavid du Colombier { 0x8086, 0x1234, pIIxget, pIIxset }, // Intel 82371MX 63059c21d95SDavid du Colombier { 0x8086, 0x7000, pIIxget, pIIxset }, // Intel 82371SB 63159c21d95SDavid du Colombier { 0x8086, 0x7110, pIIxget, pIIxset }, // Intel 82371AB 63259c21d95SDavid du Colombier { 0x8086, 0x7198, pIIxget, pIIxset }, // Intel 82443MX (fn 1) 63359c21d95SDavid du Colombier { 0x8086, 0x2410, pIIxget, pIIxset }, // Intel 82801AA 63459c21d95SDavid du Colombier { 0x8086, 0x2420, pIIxget, pIIxset }, // Intel 82801AB 63559c21d95SDavid du Colombier { 0x8086, 0x2440, pIIxget, pIIxset }, // Intel 82801BA 63659c21d95SDavid du Colombier { 0x8086, 0x244c, pIIxget, pIIxset }, // Intel 82801BAM 6377c881178SDavid du Colombier { 0x8086, 0x248c, pIIxget, pIIxset }, // Intel 82801CAM 6382839d78eSDavid du Colombier { 0x8086, 0x24cc, pIIxget, pIIxset }, // Intel 82801DBM 6397c881178SDavid du Colombier { 0x8086, 0x24d0, pIIxget, pIIxset }, // Intel 82801EB 640d8f3f65eSDavid du Colombier { 0x8086, 0x2640, pIIxget, pIIxset }, // Intel 82801FB 64159c21d95SDavid du Colombier { 0x1106, 0x0586, viaget, viaset }, // Viatech 82C586 64259c21d95SDavid du Colombier { 0x1106, 0x0596, viaget, viaset }, // Viatech 82C596 64359c21d95SDavid du Colombier { 0x1106, 0x0686, viaget, viaset }, // Viatech 82C686 6445000fddeSDavid du Colombier { 0x1106, 0x3227, viaget, viaset }, // Viatech VT8237 64559c21d95SDavid du Colombier { 0x1045, 0xc700, optiget, optiset }, // Opti 82C700 64659c21d95SDavid du Colombier { 0x10b9, 0x1533, aliget, aliset }, // Al M1533 64759c21d95SDavid du Colombier { 0x1039, 0x0008, pIIxget, pIIxset }, // SI 503 64859c21d95SDavid du Colombier { 0x1039, 0x0496, pIIxget, pIIxset }, // SI 496 6495000fddeSDavid du Colombier { 0x1078, 0x0100, cyrixget, cyrixset }, // Cyrix 5530 Legacy 6505000fddeSDavid du Colombier 6515000fddeSDavid du Colombier { 0x1022, 0x746B, nil, nil }, // AMD 8111 6525000fddeSDavid du Colombier { 0x10DE, 0x00D1, nil, nil }, // NVIDIA nForce 3 6532839d78eSDavid du Colombier { 0x1166, 0x0200, nil, nil }, // ServerWorks ServerSet III LE 65459c21d95SDavid du Colombier }; 6559a747e4fSDavid du Colombier 65659c21d95SDavid du Colombier typedef struct Slot Slot; 65759c21d95SDavid du Colombier struct Slot { 65859c21d95SDavid du Colombier uchar bus; // Pci bus number 65959c21d95SDavid du Colombier uchar dev; // Pci device number 66059c21d95SDavid du Colombier uchar maps[12]; // Avoid structs! Link and mask. 66159c21d95SDavid du Colombier uchar slot; // Add-in/built-in slot 66259c21d95SDavid du Colombier uchar reserved; 66359c21d95SDavid du Colombier }; 66459c21d95SDavid du Colombier 66559c21d95SDavid du Colombier typedef struct Router Router; 66659c21d95SDavid du Colombier struct Router { 66759c21d95SDavid du Colombier uchar signature[4]; // Routing table signature 66859c21d95SDavid du Colombier uchar version[2]; // Version number 66959c21d95SDavid du Colombier uchar size[2]; // Total table size 67059c21d95SDavid du Colombier uchar bus; // Interrupt router bus number 67159c21d95SDavid du Colombier uchar devfn; // Router's devfunc 67259c21d95SDavid du Colombier uchar pciirqs[2]; // Exclusive PCI irqs 67359c21d95SDavid du Colombier uchar compat[4]; // Compatible PCI interrupt router 67459c21d95SDavid du Colombier uchar miniport[4]; // Miniport data 67559c21d95SDavid du Colombier uchar reserved[11]; 67659c21d95SDavid du Colombier uchar checksum; 67759c21d95SDavid du Colombier }; 6789a747e4fSDavid du Colombier 6799a747e4fSDavid du Colombier static ushort pciirqs; // Exclusive PCI irqs 68059c21d95SDavid du Colombier static Bridge *southbridge; // Which southbridge to use. 6819a747e4fSDavid du Colombier 6829a747e4fSDavid du Colombier static void 6839a747e4fSDavid du Colombier pcirouting(void) 6849a747e4fSDavid du Colombier { 68559c21d95SDavid du Colombier Slot *e; 68659c21d95SDavid du Colombier Router *r; 6879a747e4fSDavid du Colombier int size, i, fn, tbdf; 6889a747e4fSDavid du Colombier Pcidev *sbpci, *pci; 6895000fddeSDavid du Colombier uchar *p, pin, irq, link, *map; 6909a747e4fSDavid du Colombier 6919a747e4fSDavid du Colombier // Search for PCI interrupt routing table in BIOS 6929a747e4fSDavid du Colombier for(p = (uchar *)KADDR(0xf0000); p < (uchar *)KADDR(0xfffff); p += 16) 6939a747e4fSDavid du Colombier if(p[0] == '$' && p[1] == 'P' && p[2] == 'I' && p[3] == 'R') 6949a747e4fSDavid du Colombier break; 6959a747e4fSDavid du Colombier 6969a747e4fSDavid du Colombier if(p >= (uchar *)KADDR(0xfffff)) 6979a747e4fSDavid du Colombier return; 6989a747e4fSDavid du Colombier 69959c21d95SDavid du Colombier r = (Router *)p; 7009a747e4fSDavid du Colombier 7019a747e4fSDavid du Colombier // print("PCI interrupt routing table version %d.%d at %.6uX\n", 70259c21d95SDavid du Colombier // r->version[0], r->version[1], (ulong)r & 0xfffff); 7039a747e4fSDavid du Colombier 70459c21d95SDavid du Colombier tbdf = (BusPCI << 24)|(r->bus << 16)|(r->devfn << 8); 7059a747e4fSDavid du Colombier sbpci = pcimatchtbdf(tbdf); 7069a747e4fSDavid du Colombier if(sbpci == nil) { 7079a747e4fSDavid du Colombier print("pcirouting: Cannot find south bridge %T\n", tbdf); 7089a747e4fSDavid du Colombier return; 7099a747e4fSDavid du Colombier } 7109a747e4fSDavid du Colombier 7119a747e4fSDavid du Colombier for(i = 0; i != nelem(southbridges); i++) 7129a747e4fSDavid du Colombier if(sbpci->vid == southbridges[i].vid && sbpci->did == southbridges[i].did) 7139a747e4fSDavid du Colombier break; 7149a747e4fSDavid du Colombier 7159a747e4fSDavid du Colombier if(i == nelem(southbridges)) { 7163ff48bf5SDavid du Colombier print("pcirouting: ignoring south bridge %T %.4uX/%.4uX\n", tbdf, sbpci->vid, sbpci->did); 7179a747e4fSDavid du Colombier return; 7189a747e4fSDavid du Colombier } 7199a747e4fSDavid du Colombier southbridge = &southbridges[i]; 7205000fddeSDavid du Colombier if(southbridge->get == nil || southbridge->set == nil) 7215000fddeSDavid du Colombier return; 7229a747e4fSDavid du Colombier 72359c21d95SDavid du Colombier pciirqs = (r->pciirqs[1] << 8)|r->pciirqs[0]; 7249a747e4fSDavid du Colombier 72559c21d95SDavid du Colombier size = (r->size[1] << 8)|r->size[0]; 72659c21d95SDavid du Colombier for(e = (Slot *)&r[1]; (uchar *)e < p + size; e++) { 72759c21d95SDavid du Colombier // print("%.2uX/%.2uX %.2uX: ", e->bus, e->dev, e->slot); 7289a747e4fSDavid du Colombier // for (i = 0; i != 4; i++) { 72959c21d95SDavid du Colombier // uchar *m = &e->maps[i * 3]; 7309a747e4fSDavid du Colombier // print("[%d] %.2uX %.4uX ", 7319a747e4fSDavid du Colombier // i, m[0], (m[2] << 8)|m[1]); 7329a747e4fSDavid du Colombier // } 7339a747e4fSDavid du Colombier // print("\n"); 7349a747e4fSDavid du Colombier 7359a747e4fSDavid du Colombier for(fn = 0; fn != 8; fn++) { 73659c21d95SDavid du Colombier tbdf = (BusPCI << 24)|(e->bus << 16)|((e->dev | fn) << 8); 7379a747e4fSDavid du Colombier pci = pcimatchtbdf(tbdf); 7389a747e4fSDavid du Colombier if(pci == nil) 7399a747e4fSDavid du Colombier continue; 7409a747e4fSDavid du Colombier pin = pcicfgr8(pci, PciINTP); 7419a747e4fSDavid du Colombier if(pin == 0 || pin == 0xff) 7429a747e4fSDavid du Colombier continue; 7439a747e4fSDavid du Colombier 7445000fddeSDavid du Colombier map = &e->maps[(pin - 1) * 3]; 7455000fddeSDavid du Colombier link = map[0]; 7463ff48bf5SDavid du Colombier irq = southbridge->get(sbpci, link); 7479a747e4fSDavid du Colombier if(irq == 0 || irq == pci->intl) 7489a747e4fSDavid du Colombier continue; 7499a747e4fSDavid du Colombier if(pci->intl != 0 && pci->intl != 0xFF) { 7503ff48bf5SDavid du Colombier print("pcirouting: BIOS workaround: %T at pin %d link %d irq %d -> %d\n", 7513ff48bf5SDavid du Colombier tbdf, pin, link, irq, pci->intl); 7523ff48bf5SDavid du Colombier southbridge->set(sbpci, link, pci->intl); 7539a747e4fSDavid du Colombier continue; 7549a747e4fSDavid du Colombier } 7553ff48bf5SDavid du Colombier print("pcirouting: %T at pin %d link %d irq %d\n", tbdf, pin, link, irq); 7569a747e4fSDavid du Colombier pcicfgw8(pci, PciINTL, irq); 7579a747e4fSDavid du Colombier pci->intl = irq; 7589a747e4fSDavid du Colombier } 7599a747e4fSDavid du Colombier } 7609a747e4fSDavid du Colombier } 7619a747e4fSDavid du Colombier 762*4de34a7eSDavid du Colombier static void pcireservemem(void); 763*4de34a7eSDavid du Colombier 7647dd7cddfSDavid du Colombier static void 7657dd7cddfSDavid du Colombier pcicfginit(void) 7667dd7cddfSDavid du Colombier { 7677dd7cddfSDavid du Colombier char *p; 7687dd7cddfSDavid du Colombier Pcidev **list; 7697dd7cddfSDavid du Colombier ulong mema, ioa; 770becaf2abSDavid du Colombier int bno, n, pcibios; 7717dd7cddfSDavid du Colombier 7727dd7cddfSDavid du Colombier lock(&pcicfginitlock); 7737dd7cddfSDavid du Colombier if(pcicfgmode != -1) 7747dd7cddfSDavid du Colombier goto out; 7757dd7cddfSDavid du Colombier 776becaf2abSDavid du Colombier pcibios = 0; 77780ee5cbfSDavid du Colombier if(getconf("*nobios")) 77880ee5cbfSDavid du Colombier nobios = 1; 779becaf2abSDavid du Colombier else if(getconf("*pcibios")) 780becaf2abSDavid du Colombier pcibios = 1; 7813ff48bf5SDavid du Colombier if(getconf("*nopcirouting")) 7823ff48bf5SDavid du Colombier nopcirouting = 1; 7833ff48bf5SDavid du Colombier 7847dd7cddfSDavid du Colombier /* 7857dd7cddfSDavid du Colombier * Try to determine which PCI configuration mode is implemented. 7867dd7cddfSDavid du Colombier * Mode2 uses a byte at 0xCF8 and another at 0xCFA; Mode1 uses 7877dd7cddfSDavid du Colombier * a DWORD at 0xCF8 and another at 0xCFC and will pass through 7887dd7cddfSDavid du Colombier * any non-DWORD accesses as normal I/O cycles. There shouldn't be 7893ff48bf5SDavid du Colombier * a device behind these addresses so if Mode1 accesses fail try 7903ff48bf5SDavid du Colombier * for Mode2 (Mode2 is deprecated). 7917dd7cddfSDavid du Colombier */ 792becaf2abSDavid du Colombier if(!pcibios){ 793becaf2abSDavid du Colombier /* 794becaf2abSDavid du Colombier * Bits [30:24] of PciADDR must be 0, 795becaf2abSDavid du Colombier * according to the spec. 796becaf2abSDavid du Colombier */ 797becaf2abSDavid du Colombier n = inl(PciADDR); 798becaf2abSDavid du Colombier if(!(n & 0x7FF00000)){ 799becaf2abSDavid du Colombier outl(PciADDR, 0x80000000); 800becaf2abSDavid du Colombier outb(PciADDR+3, 0); 801becaf2abSDavid du Colombier if(inl(PciADDR) & 0x80000000){ 8027dd7cddfSDavid du Colombier pcicfgmode = 1; 8037dd7cddfSDavid du Colombier pcimaxdno = 31; 8047dd7cddfSDavid du Colombier } 805becaf2abSDavid du Colombier } 806becaf2abSDavid du Colombier outl(PciADDR, n); 807becaf2abSDavid du Colombier 808becaf2abSDavid du Colombier if(pcicfgmode < 0){ 809becaf2abSDavid du Colombier /* 810becaf2abSDavid du Colombier * The 'key' part of PciCSE should be 0. 811becaf2abSDavid du Colombier */ 812becaf2abSDavid du Colombier n = inb(PciCSE); 813becaf2abSDavid du Colombier if(!(n & 0xF0)){ 814becaf2abSDavid du Colombier outb(PciCSE, 0x0E); 815becaf2abSDavid du Colombier if(inb(PciCSE) == 0x0E){ 8163ff48bf5SDavid du Colombier pcicfgmode = 2; 8173ff48bf5SDavid du Colombier pcimaxdno = 15; 8183ff48bf5SDavid du Colombier } 8197dd7cddfSDavid du Colombier } 820becaf2abSDavid du Colombier outb(PciCSE, n); 821becaf2abSDavid du Colombier } 822becaf2abSDavid du Colombier } 8237dd7cddfSDavid du Colombier 8247dd7cddfSDavid du Colombier if(pcicfgmode < 0) 8257dd7cddfSDavid du Colombier goto out; 8267dd7cddfSDavid du Colombier 8279a747e4fSDavid du Colombier fmtinstall('T', tbdffmt); 8287dd7cddfSDavid du Colombier 829becaf2abSDavid du Colombier if(p = getconf("*pcimaxbno")){ 830becaf2abSDavid du Colombier n = strtoul(p, 0, 0); 831becaf2abSDavid du Colombier if(n < pcimaxbno) 832becaf2abSDavid du Colombier pcimaxbno = n; 833becaf2abSDavid du Colombier } 834becaf2abSDavid du Colombier if(p = getconf("*pcimaxdno")){ 835becaf2abSDavid du Colombier n = strtoul(p, 0, 0); 836becaf2abSDavid du Colombier if(n < pcimaxdno) 837becaf2abSDavid du Colombier pcimaxdno = n; 838becaf2abSDavid du Colombier } 8397dd7cddfSDavid du Colombier 8407dd7cddfSDavid du Colombier list = &pciroot; 841223a736eSDavid du Colombier for(bno = 0; bno <= pcimaxbno; bno++) { 8429a747e4fSDavid du Colombier int sbno = bno; 8439a747e4fSDavid du Colombier bno = pcilscan(bno, list); 8449a747e4fSDavid du Colombier 8457dd7cddfSDavid du Colombier while(*list) 8467dd7cddfSDavid du Colombier list = &(*list)->link; 8479a747e4fSDavid du Colombier 8489a747e4fSDavid du Colombier if (sbno == 0) { 8499a747e4fSDavid du Colombier Pcidev *pci; 8509a747e4fSDavid du Colombier 8519a747e4fSDavid du Colombier /* 8529a747e4fSDavid du Colombier * If we have found a PCI-to-Cardbus bridge, make sure 8539a747e4fSDavid du Colombier * it has no valid mappings anymore. 8549a747e4fSDavid du Colombier */ 8559a747e4fSDavid du Colombier pci = pciroot; 8569a747e4fSDavid du Colombier while (pci) { 8579a747e4fSDavid du Colombier if (pci->ccrb == 6 && pci->ccru == 7) { 8589a747e4fSDavid du Colombier ushort bcr; 8599a747e4fSDavid du Colombier 8609a747e4fSDavid du Colombier /* reset the cardbus */ 8619a747e4fSDavid du Colombier bcr = pcicfgr16(pci, PciBCR); 8629a747e4fSDavid du Colombier pcicfgw16(pci, PciBCR, 0x40 | bcr); 8639a747e4fSDavid du Colombier delay(50); 8649a747e4fSDavid du Colombier } 8659a747e4fSDavid du Colombier pci = pci->link; 8669a747e4fSDavid du Colombier } 8679a747e4fSDavid du Colombier } 8687dd7cddfSDavid du Colombier } 8697dd7cddfSDavid du Colombier 8707dd7cddfSDavid du Colombier if(pciroot == nil) 8717dd7cddfSDavid du Colombier goto out; 8727dd7cddfSDavid du Colombier 87380ee5cbfSDavid du Colombier if(nobios) { 8747dd7cddfSDavid du Colombier /* 8757dd7cddfSDavid du Colombier * Work out how big the top bus is 8767dd7cddfSDavid du Colombier */ 8777dd7cddfSDavid du Colombier mema = 0; 8787dd7cddfSDavid du Colombier ioa = 0; 8797dd7cddfSDavid du Colombier pcibusmap(pciroot, &mema, &ioa, 0); 8807dd7cddfSDavid du Colombier 8817dd7cddfSDavid du Colombier DBG("Sizes: mem=%8.8lux size=%8.8lux io=%8.8lux\n", 8827dd7cddfSDavid du Colombier mema, pcimask(mema), ioa); 8837dd7cddfSDavid du Colombier 8847dd7cddfSDavid du Colombier /* 8857dd7cddfSDavid du Colombier * Align the windows and map it 8867dd7cddfSDavid du Colombier */ 8877dd7cddfSDavid du Colombier ioa = 0x1000; 8887dd7cddfSDavid du Colombier mema = 0x90000000; 8897dd7cddfSDavid du Colombier 8907dd7cddfSDavid du Colombier pcilog("Mask sizes: mem=%lux io=%lux\n", mema, ioa); 8917dd7cddfSDavid du Colombier 8927dd7cddfSDavid du Colombier pcibusmap(pciroot, &mema, &ioa, 1); 8937dd7cddfSDavid du Colombier DBG("Sizes2: mem=%lux io=%lux\n", mema, ioa); 8947dd7cddfSDavid du Colombier 8957dd7cddfSDavid du Colombier unlock(&pcicfginitlock); 8967dd7cddfSDavid du Colombier return; 8977dd7cddfSDavid du Colombier } 8989a747e4fSDavid du Colombier 8993ff48bf5SDavid du Colombier if (!nopcirouting) 9009a747e4fSDavid du Colombier pcirouting(); 9019a747e4fSDavid du Colombier 9027dd7cddfSDavid du Colombier out: 903*4de34a7eSDavid du Colombier pcireservemem(); 9047dd7cddfSDavid du Colombier unlock(&pcicfginitlock); 9059a747e4fSDavid du Colombier 9063ff48bf5SDavid du Colombier if(getconf("*pcihinv")) 9073ff48bf5SDavid du Colombier pcihinv(nil); 9087dd7cddfSDavid du Colombier } 9097dd7cddfSDavid du Colombier 910*4de34a7eSDavid du Colombier static void 911*4de34a7eSDavid du Colombier pcireservemem(void) 912*4de34a7eSDavid du Colombier { 913*4de34a7eSDavid du Colombier int i; 914*4de34a7eSDavid du Colombier Pcidev *p; 915*4de34a7eSDavid du Colombier 916*4de34a7eSDavid du Colombier /* 917*4de34a7eSDavid du Colombier * mark all the physical address space claimed by pci devices 918*4de34a7eSDavid du Colombier * as in use, so that upaalloc doesn't give it out. 919*4de34a7eSDavid du Colombier */ 920*4de34a7eSDavid du Colombier for(p=pciroot; p; p=p->list) 921*4de34a7eSDavid du Colombier for(i=0; i<nelem(p->mem); i++) 922*4de34a7eSDavid du Colombier if(p->mem[i].bar && (p->mem[i].bar&1) == 0) 923*4de34a7eSDavid du Colombier upareserve(p->mem[i].bar&~0x0F, p->mem[i].size); 924*4de34a7eSDavid du Colombier } 925*4de34a7eSDavid du Colombier 9267dd7cddfSDavid du Colombier static int 9277dd7cddfSDavid du Colombier pcicfgrw8(int tbdf, int rno, int data, int read) 9287dd7cddfSDavid du Colombier { 9297dd7cddfSDavid du Colombier int o, type, x; 9307dd7cddfSDavid du Colombier 9317dd7cddfSDavid du Colombier if(pcicfgmode == -1) 9327dd7cddfSDavid du Colombier pcicfginit(); 9337dd7cddfSDavid du Colombier 9347dd7cddfSDavid du Colombier if(BUSBNO(tbdf)) 9357dd7cddfSDavid du Colombier type = 0x01; 9367dd7cddfSDavid du Colombier else 9377dd7cddfSDavid du Colombier type = 0x00; 9387dd7cddfSDavid du Colombier x = -1; 9397dd7cddfSDavid du Colombier if(BUSDNO(tbdf) > pcimaxdno) 9407dd7cddfSDavid du Colombier return x; 9417dd7cddfSDavid du Colombier 9427dd7cddfSDavid du Colombier lock(&pcicfglock); 9437dd7cddfSDavid du Colombier switch(pcicfgmode){ 9447dd7cddfSDavid du Colombier 9457dd7cddfSDavid du Colombier case 1: 9467dd7cddfSDavid du Colombier o = rno & 0x03; 9477dd7cddfSDavid du Colombier rno &= ~0x03; 9487dd7cddfSDavid du Colombier outl(PciADDR, 0x80000000|BUSBDF(tbdf)|rno|type); 9497dd7cddfSDavid du Colombier if(read) 9507dd7cddfSDavid du Colombier x = inb(PciDATA+o); 9517dd7cddfSDavid du Colombier else 9527dd7cddfSDavid du Colombier outb(PciDATA+o, data); 9537dd7cddfSDavid du Colombier outl(PciADDR, 0); 9547dd7cddfSDavid du Colombier break; 9557dd7cddfSDavid du Colombier 9567dd7cddfSDavid du Colombier case 2: 9577dd7cddfSDavid du Colombier outb(PciCSE, 0x80|(BUSFNO(tbdf)<<1)); 9587dd7cddfSDavid du Colombier outb(PciFORWARD, BUSBNO(tbdf)); 9597dd7cddfSDavid du Colombier if(read) 9607dd7cddfSDavid du Colombier x = inb((0xC000|(BUSDNO(tbdf)<<8)) + rno); 9617dd7cddfSDavid du Colombier else 9627dd7cddfSDavid du Colombier outb((0xC000|(BUSDNO(tbdf)<<8)) + rno, data); 9637dd7cddfSDavid du Colombier outb(PciCSE, 0); 9647dd7cddfSDavid du Colombier break; 9657dd7cddfSDavid du Colombier } 9667dd7cddfSDavid du Colombier unlock(&pcicfglock); 9677dd7cddfSDavid du Colombier 9687dd7cddfSDavid du Colombier return x; 9697dd7cddfSDavid du Colombier } 9707dd7cddfSDavid du Colombier 9717dd7cddfSDavid du Colombier int 9727dd7cddfSDavid du Colombier pcicfgr8(Pcidev* pcidev, int rno) 9737dd7cddfSDavid du Colombier { 9747dd7cddfSDavid du Colombier return pcicfgrw8(pcidev->tbdf, rno, 0, 1); 9757dd7cddfSDavid du Colombier } 9767dd7cddfSDavid du Colombier 9777dd7cddfSDavid du Colombier void 9787dd7cddfSDavid du Colombier pcicfgw8(Pcidev* pcidev, int rno, int data) 9797dd7cddfSDavid du Colombier { 9807dd7cddfSDavid du Colombier pcicfgrw8(pcidev->tbdf, rno, data, 0); 9817dd7cddfSDavid du Colombier } 9827dd7cddfSDavid du Colombier 9837dd7cddfSDavid du Colombier static int 9847dd7cddfSDavid du Colombier pcicfgrw16(int tbdf, int rno, int data, int read) 9857dd7cddfSDavid du Colombier { 9867dd7cddfSDavid du Colombier int o, type, x; 9877dd7cddfSDavid du Colombier 9887dd7cddfSDavid du Colombier if(pcicfgmode == -1) 9897dd7cddfSDavid du Colombier pcicfginit(); 9907dd7cddfSDavid du Colombier 9917dd7cddfSDavid du Colombier if(BUSBNO(tbdf)) 9927dd7cddfSDavid du Colombier type = 0x01; 9937dd7cddfSDavid du Colombier else 9947dd7cddfSDavid du Colombier type = 0x00; 9957dd7cddfSDavid du Colombier x = -1; 9967dd7cddfSDavid du Colombier if(BUSDNO(tbdf) > pcimaxdno) 9977dd7cddfSDavid du Colombier return x; 9987dd7cddfSDavid du Colombier 9997dd7cddfSDavid du Colombier lock(&pcicfglock); 10007dd7cddfSDavid du Colombier switch(pcicfgmode){ 10017dd7cddfSDavid du Colombier 10027dd7cddfSDavid du Colombier case 1: 10037dd7cddfSDavid du Colombier o = rno & 0x02; 10047dd7cddfSDavid du Colombier rno &= ~0x03; 10057dd7cddfSDavid du Colombier outl(PciADDR, 0x80000000|BUSBDF(tbdf)|rno|type); 10067dd7cddfSDavid du Colombier if(read) 10077dd7cddfSDavid du Colombier x = ins(PciDATA+o); 10087dd7cddfSDavid du Colombier else 10097dd7cddfSDavid du Colombier outs(PciDATA+o, data); 10107dd7cddfSDavid du Colombier outl(PciADDR, 0); 10117dd7cddfSDavid du Colombier break; 10127dd7cddfSDavid du Colombier 10137dd7cddfSDavid du Colombier case 2: 10147dd7cddfSDavid du Colombier outb(PciCSE, 0x80|(BUSFNO(tbdf)<<1)); 10157dd7cddfSDavid du Colombier outb(PciFORWARD, BUSBNO(tbdf)); 10167dd7cddfSDavid du Colombier if(read) 10177dd7cddfSDavid du Colombier x = ins((0xC000|(BUSDNO(tbdf)<<8)) + rno); 10187dd7cddfSDavid du Colombier else 10197dd7cddfSDavid du Colombier outs((0xC000|(BUSDNO(tbdf)<<8)) + rno, data); 10207dd7cddfSDavid du Colombier outb(PciCSE, 0); 10217dd7cddfSDavid du Colombier break; 10227dd7cddfSDavid du Colombier } 10237dd7cddfSDavid du Colombier unlock(&pcicfglock); 10247dd7cddfSDavid du Colombier 10257dd7cddfSDavid du Colombier return x; 10267dd7cddfSDavid du Colombier } 10277dd7cddfSDavid du Colombier 10287dd7cddfSDavid du Colombier int 10297dd7cddfSDavid du Colombier pcicfgr16(Pcidev* pcidev, int rno) 10307dd7cddfSDavid du Colombier { 10317dd7cddfSDavid du Colombier return pcicfgrw16(pcidev->tbdf, rno, 0, 1); 10327dd7cddfSDavid du Colombier } 10337dd7cddfSDavid du Colombier 10347dd7cddfSDavid du Colombier void 10357dd7cddfSDavid du Colombier pcicfgw16(Pcidev* pcidev, int rno, int data) 10367dd7cddfSDavid du Colombier { 10377dd7cddfSDavid du Colombier pcicfgrw16(pcidev->tbdf, rno, data, 0); 10387dd7cddfSDavid du Colombier } 10397dd7cddfSDavid du Colombier 10407dd7cddfSDavid du Colombier static int 10417dd7cddfSDavid du Colombier pcicfgrw32(int tbdf, int rno, int data, int read) 10427dd7cddfSDavid du Colombier { 10437dd7cddfSDavid du Colombier int type, x; 10447dd7cddfSDavid du Colombier 10457dd7cddfSDavid du Colombier if(pcicfgmode == -1) 10467dd7cddfSDavid du Colombier pcicfginit(); 10477dd7cddfSDavid du Colombier 10487dd7cddfSDavid du Colombier if(BUSBNO(tbdf)) 10497dd7cddfSDavid du Colombier type = 0x01; 10507dd7cddfSDavid du Colombier else 10517dd7cddfSDavid du Colombier type = 0x00; 10527dd7cddfSDavid du Colombier x = -1; 10537dd7cddfSDavid du Colombier if(BUSDNO(tbdf) > pcimaxdno) 10547dd7cddfSDavid du Colombier return x; 10557dd7cddfSDavid du Colombier 10567dd7cddfSDavid du Colombier lock(&pcicfglock); 10577dd7cddfSDavid du Colombier switch(pcicfgmode){ 10587dd7cddfSDavid du Colombier 10597dd7cddfSDavid du Colombier case 1: 10607dd7cddfSDavid du Colombier rno &= ~0x03; 10617dd7cddfSDavid du Colombier outl(PciADDR, 0x80000000|BUSBDF(tbdf)|rno|type); 10627dd7cddfSDavid du Colombier if(read) 10637dd7cddfSDavid du Colombier x = inl(PciDATA); 10647dd7cddfSDavid du Colombier else 10657dd7cddfSDavid du Colombier outl(PciDATA, data); 10667dd7cddfSDavid du Colombier outl(PciADDR, 0); 10677dd7cddfSDavid du Colombier break; 10687dd7cddfSDavid du Colombier 10697dd7cddfSDavid du Colombier case 2: 10707dd7cddfSDavid du Colombier outb(PciCSE, 0x80|(BUSFNO(tbdf)<<1)); 10717dd7cddfSDavid du Colombier outb(PciFORWARD, BUSBNO(tbdf)); 10727dd7cddfSDavid du Colombier if(read) 10737dd7cddfSDavid du Colombier x = inl((0xC000|(BUSDNO(tbdf)<<8)) + rno); 10747dd7cddfSDavid du Colombier else 10757dd7cddfSDavid du Colombier outl((0xC000|(BUSDNO(tbdf)<<8)) + rno, data); 10767dd7cddfSDavid du Colombier outb(PciCSE, 0); 10777dd7cddfSDavid du Colombier break; 10787dd7cddfSDavid du Colombier } 10797dd7cddfSDavid du Colombier unlock(&pcicfglock); 10807dd7cddfSDavid du Colombier 10817dd7cddfSDavid du Colombier return x; 10827dd7cddfSDavid du Colombier } 10837dd7cddfSDavid du Colombier 10847dd7cddfSDavid du Colombier int 10857dd7cddfSDavid du Colombier pcicfgr32(Pcidev* pcidev, int rno) 10867dd7cddfSDavid du Colombier { 10877dd7cddfSDavid du Colombier return pcicfgrw32(pcidev->tbdf, rno, 0, 1); 10887dd7cddfSDavid du Colombier } 10897dd7cddfSDavid du Colombier 10907dd7cddfSDavid du Colombier void 10917dd7cddfSDavid du Colombier pcicfgw32(Pcidev* pcidev, int rno, int data) 10927dd7cddfSDavid du Colombier { 10937dd7cddfSDavid du Colombier pcicfgrw32(pcidev->tbdf, rno, data, 0); 10947dd7cddfSDavid du Colombier } 10957dd7cddfSDavid du Colombier 10967dd7cddfSDavid du Colombier Pcidev* 10977dd7cddfSDavid du Colombier pcimatch(Pcidev* prev, int vid, int did) 10987dd7cddfSDavid du Colombier { 10997dd7cddfSDavid du Colombier if(pcicfgmode == -1) 11007dd7cddfSDavid du Colombier pcicfginit(); 11017dd7cddfSDavid du Colombier 11027dd7cddfSDavid du Colombier if(prev == nil) 11037dd7cddfSDavid du Colombier prev = pcilist; 11047dd7cddfSDavid du Colombier else 11057dd7cddfSDavid du Colombier prev = prev->list; 11067dd7cddfSDavid du Colombier 11077dd7cddfSDavid du Colombier while(prev != nil){ 11087dd7cddfSDavid du Colombier if((vid == 0 || prev->vid == vid) 11097dd7cddfSDavid du Colombier && (did == 0 || prev->did == did)) 11107dd7cddfSDavid du Colombier break; 11117dd7cddfSDavid du Colombier prev = prev->list; 11127dd7cddfSDavid du Colombier } 11137dd7cddfSDavid du Colombier return prev; 11147dd7cddfSDavid du Colombier } 11157dd7cddfSDavid du Colombier 11167dd7cddfSDavid du Colombier Pcidev* 11177dd7cddfSDavid du Colombier pcimatchtbdf(int tbdf) 11187dd7cddfSDavid du Colombier { 11197dd7cddfSDavid du Colombier Pcidev *pcidev; 11207dd7cddfSDavid du Colombier 11217dd7cddfSDavid du Colombier if(pcicfgmode == -1) 11227dd7cddfSDavid du Colombier pcicfginit(); 11237dd7cddfSDavid du Colombier 11247dd7cddfSDavid du Colombier for(pcidev = pcilist; pcidev != nil; pcidev = pcidev->list) { 11257dd7cddfSDavid du Colombier if(pcidev->tbdf == tbdf) 11267dd7cddfSDavid du Colombier break; 11277dd7cddfSDavid du Colombier } 11287dd7cddfSDavid du Colombier return pcidev; 11297dd7cddfSDavid du Colombier } 11307dd7cddfSDavid du Colombier 11319a747e4fSDavid du Colombier uchar 11329a747e4fSDavid du Colombier pciipin(Pcidev *pci, uchar pin) 11339a747e4fSDavid du Colombier { 11349a747e4fSDavid du Colombier if (pci == nil) 11359a747e4fSDavid du Colombier pci = pcilist; 11369a747e4fSDavid du Colombier 11379a747e4fSDavid du Colombier while (pci) { 11389a747e4fSDavid du Colombier uchar intl; 11399a747e4fSDavid du Colombier 11409a747e4fSDavid du Colombier if (pcicfgr8(pci, PciINTP) == pin && pci->intl != 0 && pci->intl != 0xff) 11419a747e4fSDavid du Colombier return pci->intl; 11429a747e4fSDavid du Colombier 11439a747e4fSDavid du Colombier if (pci->bridge && (intl = pciipin(pci->bridge, pin)) != 0) 11449a747e4fSDavid du Colombier return intl; 11459a747e4fSDavid du Colombier 11469a747e4fSDavid du Colombier pci = pci->list; 11479a747e4fSDavid du Colombier } 11489a747e4fSDavid du Colombier return 0; 11499a747e4fSDavid du Colombier } 11509a747e4fSDavid du Colombier 11519a747e4fSDavid du Colombier static void 11529a747e4fSDavid du Colombier pcilhinv(Pcidev* p) 11537dd7cddfSDavid du Colombier { 11547dd7cddfSDavid du Colombier int i; 11557dd7cddfSDavid du Colombier Pcidev *t; 11567dd7cddfSDavid du Colombier 11577dd7cddfSDavid du Colombier if(p == nil) { 11587dd7cddfSDavid du Colombier putstrn(PCICONS.output, PCICONS.ptr); 11597dd7cddfSDavid du Colombier p = pciroot; 11607dd7cddfSDavid du Colombier print("bus dev type vid did intl memory\n"); 11617dd7cddfSDavid du Colombier } 11627dd7cddfSDavid du Colombier for(t = p; t != nil; t = t->link) { 11637dd7cddfSDavid du Colombier print("%d %2d/%d %.2ux %.2ux %.2ux %.4ux %.4ux %3d ", 11647dd7cddfSDavid du Colombier BUSBNO(t->tbdf), BUSDNO(t->tbdf), BUSFNO(t->tbdf), 11657dd7cddfSDavid du Colombier t->ccrb, t->ccru, t->ccrp, t->vid, t->did, t->intl); 11667dd7cddfSDavid du Colombier 11677dd7cddfSDavid du Colombier for(i = 0; i < nelem(p->mem); i++) { 11687dd7cddfSDavid du Colombier if(t->mem[i].size == 0) 11697dd7cddfSDavid du Colombier continue; 11707dd7cddfSDavid du Colombier print("%d:%.8lux %d ", i, 11717dd7cddfSDavid du Colombier t->mem[i].bar, t->mem[i].size); 11727dd7cddfSDavid du Colombier } 11737dd7cddfSDavid du Colombier if(t->ioa.bar || t->ioa.size) 11747dd7cddfSDavid du Colombier print("ioa:%.8lux %d ", t->ioa.bar, t->ioa.size); 11757dd7cddfSDavid du Colombier if(t->mema.bar || t->mema.size) 11767dd7cddfSDavid du Colombier print("mema:%.8lux %d ", t->mema.bar, t->mema.size); 11777dd7cddfSDavid du Colombier if(t->bridge) 11787dd7cddfSDavid du Colombier print("->%d", BUSBNO(t->bridge->tbdf)); 11797dd7cddfSDavid du Colombier print("\n"); 11807dd7cddfSDavid du Colombier } 11817dd7cddfSDavid du Colombier while(p != nil) { 11827dd7cddfSDavid du Colombier if(p->bridge != nil) 11839a747e4fSDavid du Colombier pcilhinv(p->bridge); 11847dd7cddfSDavid du Colombier p = p->link; 11857dd7cddfSDavid du Colombier } 11867dd7cddfSDavid du Colombier } 11877dd7cddfSDavid du Colombier 11887dd7cddfSDavid du Colombier void 11899a747e4fSDavid du Colombier pcihinv(Pcidev* p) 11909a747e4fSDavid du Colombier { 11919a747e4fSDavid du Colombier if(pcicfgmode == -1) 11929a747e4fSDavid du Colombier pcicfginit(); 11939a747e4fSDavid du Colombier lock(&pcicfginitlock); 11949a747e4fSDavid du Colombier pcilhinv(p); 11959a747e4fSDavid du Colombier unlock(&pcicfginitlock); 11969a747e4fSDavid du Colombier } 11979a747e4fSDavid du Colombier 11989a747e4fSDavid du Colombier void 11997dd7cddfSDavid du Colombier pcireset(void) 12007dd7cddfSDavid du Colombier { 12017dd7cddfSDavid du Colombier Pcidev *p; 12027dd7cddfSDavid du Colombier 12037dd7cddfSDavid du Colombier if(pcicfgmode == -1) 12047dd7cddfSDavid du Colombier pcicfginit(); 12057dd7cddfSDavid du Colombier 12067dd7cddfSDavid du Colombier for(p = pcilist; p != nil; p = p->list) { 12079a747e4fSDavid du Colombier /* don't mess with the bridges */ 12089a747e4fSDavid du Colombier if(p->ccrb == 0x06) 12099a747e4fSDavid du Colombier continue; 12109a747e4fSDavid du Colombier pciclrbme(p); 12117dd7cddfSDavid du Colombier } 12127dd7cddfSDavid du Colombier } 12137dd7cddfSDavid du Colombier 12147dd7cddfSDavid du Colombier void 1215220e960cSDavid du Colombier pcisetioe(Pcidev* p) 1216220e960cSDavid du Colombier { 1217e569ccb5SDavid du Colombier p->pcr |= IOen; 1218e569ccb5SDavid du Colombier pcicfgw16(p, PciPCR, p->pcr); 1219220e960cSDavid du Colombier } 1220220e960cSDavid du Colombier 1221220e960cSDavid du Colombier void 1222220e960cSDavid du Colombier pciclrioe(Pcidev* p) 1223220e960cSDavid du Colombier { 1224e569ccb5SDavid du Colombier p->pcr &= ~IOen; 1225e569ccb5SDavid du Colombier pcicfgw16(p, PciPCR, p->pcr); 1226220e960cSDavid du Colombier } 1227220e960cSDavid du Colombier 1228220e960cSDavid du Colombier void 12297dd7cddfSDavid du Colombier pcisetbme(Pcidev* p) 12307dd7cddfSDavid du Colombier { 1231e569ccb5SDavid du Colombier p->pcr |= MASen; 1232e569ccb5SDavid du Colombier pcicfgw16(p, PciPCR, p->pcr); 12337dd7cddfSDavid du Colombier } 12349a747e4fSDavid du Colombier 12359a747e4fSDavid du Colombier void 12369a747e4fSDavid du Colombier pciclrbme(Pcidev* p) 12379a747e4fSDavid du Colombier { 1238e569ccb5SDavid du Colombier p->pcr &= ~MASen; 1239e569ccb5SDavid du Colombier pcicfgw16(p, PciPCR, p->pcr); 1240e569ccb5SDavid du Colombier } 12419a747e4fSDavid du Colombier 1242d8f3f65eSDavid du Colombier void 1243d8f3f65eSDavid du Colombier pcisetmwi(Pcidev* p) 1244d8f3f65eSDavid du Colombier { 1245d8f3f65eSDavid du Colombier p->pcr |= MemWrInv; 1246d8f3f65eSDavid du Colombier pcicfgw16(p, PciPCR, p->pcr); 1247d8f3f65eSDavid du Colombier } 1248d8f3f65eSDavid du Colombier 1249d8f3f65eSDavid du Colombier void 1250d8f3f65eSDavid du Colombier pciclrmwi(Pcidev* p) 1251d8f3f65eSDavid du Colombier { 1252d8f3f65eSDavid du Colombier p->pcr &= ~MemWrInv; 1253d8f3f65eSDavid du Colombier pcicfgw16(p, PciPCR, p->pcr); 1254d8f3f65eSDavid du Colombier } 1255d8f3f65eSDavid du Colombier 1256e569ccb5SDavid du Colombier static int 1257e569ccb5SDavid du Colombier pcigetpmrb(Pcidev* p) 1258e569ccb5SDavid du Colombier { 1259e569ccb5SDavid du Colombier int ptr; 1260e569ccb5SDavid du Colombier 1261e569ccb5SDavid du Colombier if(p->pmrb != 0) 1262e569ccb5SDavid du Colombier return p->pmrb; 1263e569ccb5SDavid du Colombier p->pmrb = -1; 1264e569ccb5SDavid du Colombier 1265e569ccb5SDavid du Colombier /* 1266e569ccb5SDavid du Colombier * If there are no extended capabilities implemented, 1267e569ccb5SDavid du Colombier * (bit 4 in the status register) assume there's no standard 1268e569ccb5SDavid du Colombier * power management method. 1269e569ccb5SDavid du Colombier * Find the capabilities pointer based on PCI header type. 1270e569ccb5SDavid du Colombier */ 1271e569ccb5SDavid du Colombier if(!(p->pcr & 0x0010)) 1272e569ccb5SDavid du Colombier return -1; 1273e569ccb5SDavid du Colombier switch(pcicfgr8(p, PciHDT)){ 1274e569ccb5SDavid du Colombier default: 1275e569ccb5SDavid du Colombier return -1; 1276e569ccb5SDavid du Colombier case 0: /* all other */ 1277e569ccb5SDavid du Colombier case 1: /* PCI to PCI bridge */ 1278e569ccb5SDavid du Colombier ptr = 0x34; 1279e569ccb5SDavid du Colombier break; 1280e569ccb5SDavid du Colombier case 2: /* CardBus bridge */ 1281e569ccb5SDavid du Colombier ptr = 0x14; 1282e569ccb5SDavid du Colombier break; 1283e569ccb5SDavid du Colombier } 1284e569ccb5SDavid du Colombier ptr = pcicfgr32(p, ptr); 1285e569ccb5SDavid du Colombier 1286e569ccb5SDavid du Colombier while(ptr != 0){ 1287e569ccb5SDavid du Colombier /* 1288e569ccb5SDavid du Colombier * Check for validity. 1289e569ccb5SDavid du Colombier * Can't be in standard header and must be double 1290e569ccb5SDavid du Colombier * word aligned. 1291e569ccb5SDavid du Colombier */ 1292e569ccb5SDavid du Colombier if(ptr < 0x40 || (ptr & ~0xFC)) 1293e569ccb5SDavid du Colombier return -1; 1294e569ccb5SDavid du Colombier if(pcicfgr8(p, ptr) == 0x01){ 1295e569ccb5SDavid du Colombier p->pmrb = ptr; 1296e569ccb5SDavid du Colombier return ptr; 1297e569ccb5SDavid du Colombier } 1298e569ccb5SDavid du Colombier 1299e569ccb5SDavid du Colombier ptr = pcicfgr8(p, ptr+1); 1300e569ccb5SDavid du Colombier } 1301e569ccb5SDavid du Colombier 1302e569ccb5SDavid du Colombier return -1; 1303e569ccb5SDavid du Colombier } 1304e569ccb5SDavid du Colombier 1305e569ccb5SDavid du Colombier int 1306e569ccb5SDavid du Colombier pcigetpms(Pcidev* p) 1307e569ccb5SDavid du Colombier { 1308e569ccb5SDavid du Colombier int pmcsr, ptr; 1309e569ccb5SDavid du Colombier 1310e569ccb5SDavid du Colombier if((ptr = pcigetpmrb(p)) == -1) 1311e569ccb5SDavid du Colombier return -1; 1312e569ccb5SDavid du Colombier 1313e569ccb5SDavid du Colombier /* 1314e569ccb5SDavid du Colombier * Power Management Register Block: 1315e569ccb5SDavid du Colombier * offset 0: Capability ID 1316e569ccb5SDavid du Colombier * 1: next item pointer 1317e569ccb5SDavid du Colombier * 2: capabilities 1318e569ccb5SDavid du Colombier * 4: control/status 1319e569ccb5SDavid du Colombier * 6: bridge support extensions 1320e569ccb5SDavid du Colombier * 7: data 1321e569ccb5SDavid du Colombier */ 1322e569ccb5SDavid du Colombier pmcsr = pcicfgr16(p, ptr+4); 1323e569ccb5SDavid du Colombier 1324e569ccb5SDavid du Colombier return pmcsr & 0x0003; 1325e569ccb5SDavid du Colombier } 1326e569ccb5SDavid du Colombier 1327e569ccb5SDavid du Colombier int 1328e569ccb5SDavid du Colombier pcisetpms(Pcidev* p, int state) 1329e569ccb5SDavid du Colombier { 1330e569ccb5SDavid du Colombier int ostate, pmc, pmcsr, ptr; 1331e569ccb5SDavid du Colombier 1332e569ccb5SDavid du Colombier if((ptr = pcigetpmrb(p)) == -1) 1333e569ccb5SDavid du Colombier return -1; 1334e569ccb5SDavid du Colombier 1335e569ccb5SDavid du Colombier pmc = pcicfgr16(p, ptr+2); 1336e569ccb5SDavid du Colombier pmcsr = pcicfgr16(p, ptr+4); 1337e569ccb5SDavid du Colombier ostate = pmcsr & 0x0003; 1338e569ccb5SDavid du Colombier pmcsr &= ~0x0003; 1339e569ccb5SDavid du Colombier 1340e569ccb5SDavid du Colombier switch(state){ 1341e569ccb5SDavid du Colombier default: 1342e569ccb5SDavid du Colombier return -1; 1343e569ccb5SDavid du Colombier case 0: 1344e569ccb5SDavid du Colombier break; 1345e569ccb5SDavid du Colombier case 1: 1346e569ccb5SDavid du Colombier if(!(pmc & 0x0200)) 1347e569ccb5SDavid du Colombier return -1; 1348e569ccb5SDavid du Colombier break; 1349e569ccb5SDavid du Colombier case 2: 1350e569ccb5SDavid du Colombier if(!(pmc & 0x0400)) 1351e569ccb5SDavid du Colombier return -1; 1352e569ccb5SDavid du Colombier break; 1353e569ccb5SDavid du Colombier case 3: 1354e569ccb5SDavid du Colombier break; 1355e569ccb5SDavid du Colombier } 1356e569ccb5SDavid du Colombier pmcsr |= state; 1357e569ccb5SDavid du Colombier pcicfgw16(p, ptr+4, pmcsr); 1358e569ccb5SDavid du Colombier 1359e569ccb5SDavid du Colombier return ostate; 13609a747e4fSDavid du Colombier } 1361