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; 694fafed5dSDavid du Colombier static BIOS32si* pcibiossi; 707dd7cddfSDavid du Colombier 714fafed5dSDavid du Colombier static int pcicfgrw8raw(int, int, int, int); 724fafed5dSDavid du Colombier static int pcicfgrw16raw(int, int, int, int); 734fafed5dSDavid du Colombier static int pcicfgrw32raw(int, int, int, int); 744fafed5dSDavid du Colombier 754fafed5dSDavid du Colombier static int (*pcicfgrw8)(int, int, int, int) = pcicfgrw8raw; 764fafed5dSDavid du Colombier static int (*pcicfgrw16)(int, int, int, int) = pcicfgrw16raw; 774fafed5dSDavid du Colombier static int (*pcicfgrw32)(int, int, int, int) = pcicfgrw32raw; 787dd7cddfSDavid du Colombier 797dd7cddfSDavid du Colombier static char* bustypes[] = { 807dd7cddfSDavid du Colombier "CBUSI", 817dd7cddfSDavid du Colombier "CBUSII", 827dd7cddfSDavid du Colombier "EISA", 837dd7cddfSDavid du Colombier "FUTURE", 847dd7cddfSDavid du Colombier "INTERN", 857dd7cddfSDavid du Colombier "ISA", 867dd7cddfSDavid du Colombier "MBI", 877dd7cddfSDavid du Colombier "MBII", 887dd7cddfSDavid du Colombier "MCA", 897dd7cddfSDavid du Colombier "MPI", 907dd7cddfSDavid du Colombier "MPSA", 917dd7cddfSDavid du Colombier "NUBUS", 927dd7cddfSDavid du Colombier "PCI", 937dd7cddfSDavid du Colombier "PCMCIA", 947dd7cddfSDavid du Colombier "TC", 957dd7cddfSDavid du Colombier "VL", 967dd7cddfSDavid du Colombier "VME", 977dd7cddfSDavid du Colombier "XPRESS", 987dd7cddfSDavid du Colombier }; 997dd7cddfSDavid du Colombier 1007dd7cddfSDavid du Colombier #pragma varargck type "T" int 1017dd7cddfSDavid du Colombier 1027dd7cddfSDavid du Colombier static int 1039a747e4fSDavid du Colombier tbdffmt(Fmt* fmt) 1047dd7cddfSDavid du Colombier { 1057dd7cddfSDavid du Colombier char *p; 1069a747e4fSDavid du Colombier int l, r, type, tbdf; 1077dd7cddfSDavid du Colombier 1089a747e4fSDavid du Colombier if((p = malloc(READSTR)) == nil) 1099a747e4fSDavid du Colombier return fmtstrcpy(fmt, "(tbdfconv)"); 1107dd7cddfSDavid du Colombier 1119a747e4fSDavid du Colombier switch(fmt->r){ 1127dd7cddfSDavid du Colombier case 'T': 1139a747e4fSDavid du Colombier tbdf = va_arg(fmt->args, int); 1147dd7cddfSDavid du Colombier type = BUSTYPE(tbdf); 1157dd7cddfSDavid du Colombier if(type < nelem(bustypes)) 1167dd7cddfSDavid du Colombier l = snprint(p, READSTR, bustypes[type]); 1177dd7cddfSDavid du Colombier else 1187dd7cddfSDavid du Colombier l = snprint(p, READSTR, "%d", type); 1197dd7cddfSDavid du Colombier snprint(p+l, READSTR-l, ".%d.%d.%d", 1207dd7cddfSDavid du Colombier BUSBNO(tbdf), BUSDNO(tbdf), BUSFNO(tbdf)); 1217dd7cddfSDavid du Colombier break; 1227dd7cddfSDavid du Colombier 1237dd7cddfSDavid du Colombier default: 1247dd7cddfSDavid du Colombier snprint(p, READSTR, "(tbdfconv)"); 1257dd7cddfSDavid du Colombier break; 1267dd7cddfSDavid du Colombier } 1279a747e4fSDavid du Colombier r = fmtstrcpy(fmt, p); 1287dd7cddfSDavid du Colombier free(p); 1297dd7cddfSDavid du Colombier 1309a747e4fSDavid du Colombier return r; 1317dd7cddfSDavid du Colombier } 1327dd7cddfSDavid du Colombier 1337dd7cddfSDavid du Colombier ulong 1347dd7cddfSDavid du Colombier pcibarsize(Pcidev *p, int rno) 1357dd7cddfSDavid du Colombier { 1367dd7cddfSDavid du Colombier ulong v, size; 1377dd7cddfSDavid du Colombier 1387dd7cddfSDavid du Colombier v = pcicfgrw32(p->tbdf, rno, 0, 1); 1397dd7cddfSDavid du Colombier pcicfgrw32(p->tbdf, rno, 0xFFFFFFF0, 0); 1407dd7cddfSDavid du Colombier size = pcicfgrw32(p->tbdf, rno, 0, 1); 1417dd7cddfSDavid du Colombier if(v & 1) 1427dd7cddfSDavid du Colombier size |= 0xFFFF0000; 1437dd7cddfSDavid du Colombier pcicfgrw32(p->tbdf, rno, v, 0); 1447dd7cddfSDavid du Colombier 1457dd7cddfSDavid du Colombier return -(size & ~0x0F); 1467dd7cddfSDavid du Colombier } 1477dd7cddfSDavid du Colombier 1487dd7cddfSDavid du Colombier static int 1497dd7cddfSDavid du Colombier pcisizcmp(void *a, void *b) 1507dd7cddfSDavid du Colombier { 1517dd7cddfSDavid du Colombier Pcisiz *aa, *bb; 1527dd7cddfSDavid du Colombier 1537dd7cddfSDavid du Colombier aa = a; 1547dd7cddfSDavid du Colombier bb = b; 1557dd7cddfSDavid du Colombier return aa->siz - bb->siz; 1567dd7cddfSDavid du Colombier } 1577dd7cddfSDavid du Colombier 1587dd7cddfSDavid du Colombier static ulong 1597dd7cddfSDavid du Colombier pcimask(ulong v) 1607dd7cddfSDavid du Colombier { 1617dd7cddfSDavid du Colombier ulong m; 1627dd7cddfSDavid du Colombier 1637dd7cddfSDavid du Colombier m = BI2BY*sizeof(v); 1647dd7cddfSDavid du Colombier for(m = 1<<(m-1); m != 0; m >>= 1) { 1657dd7cddfSDavid du Colombier if(m & v) 1667dd7cddfSDavid du Colombier break; 1677dd7cddfSDavid du Colombier } 1687dd7cddfSDavid du Colombier 1697dd7cddfSDavid du Colombier m--; 1707dd7cddfSDavid du Colombier if((v & m) == 0) 1717dd7cddfSDavid du Colombier return v; 1727dd7cddfSDavid du Colombier 1737dd7cddfSDavid du Colombier v |= m; 1747dd7cddfSDavid du Colombier return v+1; 1757dd7cddfSDavid du Colombier } 1767dd7cddfSDavid du Colombier 1777dd7cddfSDavid du Colombier static void 1787dd7cddfSDavid du Colombier pcibusmap(Pcidev *root, ulong *pmema, ulong *pioa, int wrreg) 1797dd7cddfSDavid du Colombier { 1807dd7cddfSDavid du Colombier Pcidev *p; 1817dd7cddfSDavid du Colombier int ntb, i, size, rno, hole; 1827dd7cddfSDavid du Colombier ulong v, mema, ioa, sioa, smema, base, limit; 1837dd7cddfSDavid du Colombier Pcisiz *table, *tptr, *mtb, *itb; 1847dd7cddfSDavid du Colombier 1854fafed5dSDavid du Colombier if(!nobios) 1864fafed5dSDavid du Colombier return; 1874fafed5dSDavid du Colombier 1887dd7cddfSDavid du Colombier ioa = *pioa; 1897dd7cddfSDavid du Colombier mema = *pmema; 1907dd7cddfSDavid du Colombier 1917dd7cddfSDavid du Colombier DBG("pcibusmap wr=%d %T mem=%luX io=%luX\n", 1927dd7cddfSDavid du Colombier wrreg, root->tbdf, mema, ioa); 1937dd7cddfSDavid du Colombier 1947dd7cddfSDavid du Colombier ntb = 0; 1957dd7cddfSDavid du Colombier for(p = root; p != nil; p = p->link) 1967dd7cddfSDavid du Colombier ntb++; 1977dd7cddfSDavid du Colombier 1987dd7cddfSDavid du Colombier ntb *= (PciCIS-PciBAR0)/4; 1997dd7cddfSDavid du Colombier table = malloc(2*ntb*sizeof(Pcisiz)); 2007dd7cddfSDavid du Colombier itb = table; 2017dd7cddfSDavid du Colombier mtb = table+ntb; 2027dd7cddfSDavid du Colombier 2037dd7cddfSDavid du Colombier /* 2047dd7cddfSDavid du Colombier * Build a table of sizes 2057dd7cddfSDavid du Colombier */ 2067dd7cddfSDavid du Colombier for(p = root; p != nil; p = p->link) { 2077dd7cddfSDavid du Colombier if(p->ccrb == 0x06) { 2087dd7cddfSDavid du Colombier if(p->ccru != 0x04 || p->bridge == nil) { 2097dd7cddfSDavid du Colombier // DBG("pci: ignored bridge %T\n", p->tbdf); 2107dd7cddfSDavid du Colombier continue; 2117dd7cddfSDavid du Colombier } 2127dd7cddfSDavid du Colombier 2137dd7cddfSDavid du Colombier sioa = ioa; 2147dd7cddfSDavid du Colombier smema = mema; 2157dd7cddfSDavid du Colombier pcibusmap(p->bridge, &smema, &sioa, 0); 2167dd7cddfSDavid du Colombier 2177dd7cddfSDavid du Colombier hole = pcimask(smema-mema); 2187dd7cddfSDavid du Colombier if(hole < (1<<20)) 2197dd7cddfSDavid du Colombier hole = 1<<20; 2207dd7cddfSDavid du Colombier p->mema.size = hole; 2217dd7cddfSDavid du Colombier 2227dd7cddfSDavid du Colombier hole = pcimask(sioa-ioa); 2237dd7cddfSDavid du Colombier if(hole < (1<<12)) 2247dd7cddfSDavid du Colombier hole = 1<<12; 2257dd7cddfSDavid du Colombier 2267dd7cddfSDavid du Colombier p->ioa.size = hole; 2277dd7cddfSDavid du Colombier 2287dd7cddfSDavid du Colombier itb->dev = p; 2297dd7cddfSDavid du Colombier itb->bar = -1; 2307dd7cddfSDavid du Colombier itb->siz = p->ioa.size; 2317dd7cddfSDavid du Colombier itb++; 2327dd7cddfSDavid du Colombier 2337dd7cddfSDavid du Colombier mtb->dev = p; 2347dd7cddfSDavid du Colombier mtb->bar = -1; 2357dd7cddfSDavid du Colombier mtb->siz = p->mema.size; 2367dd7cddfSDavid du Colombier mtb++; 2377dd7cddfSDavid du Colombier continue; 2387dd7cddfSDavid du Colombier } 2397dd7cddfSDavid du Colombier 2407dd7cddfSDavid du Colombier for(i = 0; i <= 5; i++) { 2417dd7cddfSDavid du Colombier rno = PciBAR0 + i*4; 2427dd7cddfSDavid du Colombier v = pcicfgrw32(p->tbdf, rno, 0, 1); 2437dd7cddfSDavid du Colombier size = pcibarsize(p, rno); 2447dd7cddfSDavid du Colombier if(size == 0) 2457dd7cddfSDavid du Colombier continue; 2467dd7cddfSDavid du Colombier 2477dd7cddfSDavid du Colombier if(v & 1) { 2487dd7cddfSDavid du Colombier itb->dev = p; 2497dd7cddfSDavid du Colombier itb->bar = i; 2507dd7cddfSDavid du Colombier itb->siz = size; 2517dd7cddfSDavid du Colombier itb++; 2527dd7cddfSDavid du Colombier } 2537dd7cddfSDavid du Colombier else { 2547dd7cddfSDavid du Colombier mtb->dev = p; 2557dd7cddfSDavid du Colombier mtb->bar = i; 2567dd7cddfSDavid du Colombier mtb->siz = size; 2577dd7cddfSDavid du Colombier mtb++; 2587dd7cddfSDavid du Colombier } 2597dd7cddfSDavid du Colombier 2607dd7cddfSDavid du Colombier p->mem[i].size = size; 2617dd7cddfSDavid du Colombier } 2627dd7cddfSDavid du Colombier } 2637dd7cddfSDavid du Colombier 2647dd7cddfSDavid du Colombier /* 2657dd7cddfSDavid du Colombier * Sort both tables IO smallest first, Memory largest 2667dd7cddfSDavid du Colombier */ 2677dd7cddfSDavid du Colombier qsort(table, itb-table, sizeof(Pcisiz), pcisizcmp); 2687dd7cddfSDavid du Colombier tptr = table+ntb; 2697dd7cddfSDavid du Colombier qsort(tptr, mtb-tptr, sizeof(Pcisiz), pcisizcmp); 2707dd7cddfSDavid du Colombier 2717dd7cddfSDavid du Colombier /* 2727dd7cddfSDavid du Colombier * Allocate IO address space on this bus 2737dd7cddfSDavid du Colombier */ 2747dd7cddfSDavid du Colombier for(tptr = table; tptr < itb; tptr++) { 2757dd7cddfSDavid du Colombier hole = tptr->siz; 2767dd7cddfSDavid du Colombier if(tptr->bar == -1) 2777dd7cddfSDavid du Colombier hole = 1<<12; 2787dd7cddfSDavid du Colombier ioa = (ioa+hole-1) & ~(hole-1); 2797dd7cddfSDavid du Colombier 2807dd7cddfSDavid du Colombier p = tptr->dev; 2817dd7cddfSDavid du Colombier if(tptr->bar == -1) 2827dd7cddfSDavid du Colombier p->ioa.bar = ioa; 2837dd7cddfSDavid du Colombier else { 2847dd7cddfSDavid du Colombier p->pcr |= IOen; 2857dd7cddfSDavid du Colombier p->mem[tptr->bar].bar = ioa|1; 2867dd7cddfSDavid du Colombier if(wrreg) 2877dd7cddfSDavid du Colombier pcicfgrw32(p->tbdf, PciBAR0+(tptr->bar*4), ioa|1, 0); 2887dd7cddfSDavid du Colombier } 2897dd7cddfSDavid du Colombier 2907dd7cddfSDavid du Colombier ioa += tptr->siz; 2917dd7cddfSDavid du Colombier } 2927dd7cddfSDavid du Colombier 2937dd7cddfSDavid du Colombier /* 2947dd7cddfSDavid du Colombier * Allocate Memory address space on this bus 2957dd7cddfSDavid du Colombier */ 2967dd7cddfSDavid du Colombier for(tptr = table+ntb; tptr < mtb; tptr++) { 2977dd7cddfSDavid du Colombier hole = tptr->siz; 2987dd7cddfSDavid du Colombier if(tptr->bar == -1) 2997dd7cddfSDavid du Colombier hole = 1<<20; 3007dd7cddfSDavid du Colombier mema = (mema+hole-1) & ~(hole-1); 3017dd7cddfSDavid du Colombier 3027dd7cddfSDavid du Colombier p = tptr->dev; 3037dd7cddfSDavid du Colombier if(tptr->bar == -1) 3047dd7cddfSDavid du Colombier p->mema.bar = mema; 3057dd7cddfSDavid du Colombier else { 3067dd7cddfSDavid du Colombier p->pcr |= MEMen; 3077dd7cddfSDavid du Colombier p->mem[tptr->bar].bar = mema; 3087dd7cddfSDavid du Colombier if(wrreg) 3097dd7cddfSDavid du Colombier pcicfgrw32(p->tbdf, PciBAR0+(tptr->bar*4), mema, 0); 3107dd7cddfSDavid du Colombier } 3117dd7cddfSDavid du Colombier mema += tptr->siz; 3127dd7cddfSDavid du Colombier } 3137dd7cddfSDavid du Colombier 3147dd7cddfSDavid du Colombier *pmema = mema; 3157dd7cddfSDavid du Colombier *pioa = ioa; 3167dd7cddfSDavid du Colombier free(table); 3177dd7cddfSDavid du Colombier 3187dd7cddfSDavid du Colombier if(wrreg == 0) 3197dd7cddfSDavid du Colombier return; 3207dd7cddfSDavid du Colombier 3217dd7cddfSDavid du Colombier /* 3227dd7cddfSDavid du Colombier * Finally set all the bridge addresses & registers 3237dd7cddfSDavid du Colombier */ 3247dd7cddfSDavid du Colombier for(p = root; p != nil; p = p->link) { 3257dd7cddfSDavid du Colombier if(p->bridge == nil) { 3267dd7cddfSDavid du Colombier pcicfgrw8(p->tbdf, PciLTR, 64, 0); 3277dd7cddfSDavid du Colombier 3287dd7cddfSDavid du Colombier p->pcr |= MASen; 329e569ccb5SDavid du Colombier pcicfgrw16(p->tbdf, PciPCR, p->pcr, 0); 3307dd7cddfSDavid du Colombier continue; 3317dd7cddfSDavid du Colombier } 3327dd7cddfSDavid du Colombier 3337dd7cddfSDavid du Colombier base = p->ioa.bar; 3347dd7cddfSDavid du Colombier limit = base+p->ioa.size-1; 335d0f3faacSDavid du Colombier v = pcicfgrw32(p->tbdf, PciIBR, 0, 1); 3367dd7cddfSDavid du Colombier v = (v&0xFFFF0000)|(limit & 0xF000)|((base & 0xF000)>>8); 337d0f3faacSDavid du Colombier pcicfgrw32(p->tbdf, PciIBR, v, 0); 3387dd7cddfSDavid du Colombier v = (limit & 0xFFFF0000)|(base>>16); 339d0f3faacSDavid du Colombier pcicfgrw32(p->tbdf, PciIUBR, v, 0); 3407dd7cddfSDavid du Colombier 3417dd7cddfSDavid du Colombier base = p->mema.bar; 3427dd7cddfSDavid du Colombier limit = base+p->mema.size-1; 3437dd7cddfSDavid du Colombier v = (limit & 0xFFF00000)|((base & 0xFFF00000)>>16); 344d0f3faacSDavid du Colombier pcicfgrw32(p->tbdf, PciMBR, v, 0); 3457dd7cddfSDavid du Colombier 3467dd7cddfSDavid du Colombier /* 3477dd7cddfSDavid du Colombier * Disable memory prefetch 3487dd7cddfSDavid du Colombier */ 349d0f3faacSDavid du Colombier pcicfgrw32(p->tbdf, PciPMBR, 0x0000FFFF, 0); 3507dd7cddfSDavid du Colombier pcicfgrw8(p->tbdf, PciLTR, 64, 0); 3517dd7cddfSDavid du Colombier 3527dd7cddfSDavid du Colombier /* 3537dd7cddfSDavid du Colombier * Enable the bridge 3547dd7cddfSDavid du Colombier */ 355e569ccb5SDavid du Colombier p->pcr |= IOen|MEMen|MASen; 356e569ccb5SDavid du Colombier pcicfgrw32(p->tbdf, PciPCR, 0xFFFF0000|p->pcr , 0); 3577dd7cddfSDavid du Colombier 3587dd7cddfSDavid du Colombier sioa = p->ioa.bar; 3597dd7cddfSDavid du Colombier smema = p->mema.bar; 3607dd7cddfSDavid du Colombier pcibusmap(p->bridge, &smema, &sioa, 1); 3617dd7cddfSDavid du Colombier } 3627dd7cddfSDavid du Colombier } 3637dd7cddfSDavid du Colombier 3647dd7cddfSDavid du Colombier static int 3659a747e4fSDavid du Colombier pcilscan(int bno, Pcidev** list) 3667dd7cddfSDavid du Colombier { 3677dd7cddfSDavid du Colombier Pcidev *p, *head, *tail; 3687dd7cddfSDavid du Colombier int dno, fno, i, hdt, l, maxfno, maxubn, rno, sbn, tbdf, ubn; 3697dd7cddfSDavid du Colombier 3707dd7cddfSDavid du Colombier maxubn = bno; 3717dd7cddfSDavid du Colombier head = nil; 3727dd7cddfSDavid du Colombier tail = nil; 3737dd7cddfSDavid du Colombier for(dno = 0; dno <= pcimaxdno; dno++){ 3747dd7cddfSDavid du Colombier maxfno = 0; 3757dd7cddfSDavid du Colombier for(fno = 0; fno <= maxfno; fno++){ 3767dd7cddfSDavid du Colombier /* 3777dd7cddfSDavid du Colombier * For this possible device, form the 3787dd7cddfSDavid du Colombier * bus+device+function triplet needed to address it 3797dd7cddfSDavid du Colombier * and try to read the vendor and device ID. 3807dd7cddfSDavid du Colombier * If successful, allocate a device struct and 3817dd7cddfSDavid du Colombier * start to fill it in with some useful information 3827dd7cddfSDavid du Colombier * from the device's configuration space. 3837dd7cddfSDavid du Colombier */ 3847dd7cddfSDavid du Colombier tbdf = MKBUS(BusPCI, bno, dno, fno); 3857dd7cddfSDavid du Colombier l = pcicfgrw32(tbdf, PciVID, 0, 1); 3867dd7cddfSDavid du Colombier if(l == 0xFFFFFFFF || l == 0) 3877dd7cddfSDavid du Colombier continue; 3887dd7cddfSDavid du Colombier p = malloc(sizeof(*p)); 3897dd7cddfSDavid du Colombier p->tbdf = tbdf; 3907dd7cddfSDavid du Colombier p->vid = l; 3917dd7cddfSDavid du Colombier p->did = l>>16; 3927dd7cddfSDavid du Colombier 3937dd7cddfSDavid du Colombier if(pcilist != nil) 3947dd7cddfSDavid du Colombier pcitail->list = p; 3957dd7cddfSDavid du Colombier else 3967dd7cddfSDavid du Colombier pcilist = p; 3977dd7cddfSDavid du Colombier pcitail = p; 3987dd7cddfSDavid du Colombier 399e569ccb5SDavid du Colombier p->pcr = pcicfgr16(p, PciPCR); 4007dd7cddfSDavid du Colombier p->rid = pcicfgr8(p, PciRID); 4017dd7cddfSDavid du Colombier p->ccrp = pcicfgr8(p, PciCCRp); 4027dd7cddfSDavid du Colombier p->ccru = pcicfgr8(p, PciCCRu); 4037dd7cddfSDavid du Colombier p->ccrb = pcicfgr8(p, PciCCRb); 404e569ccb5SDavid du Colombier p->cls = pcicfgr8(p, PciCLS); 405e569ccb5SDavid du Colombier p->ltr = pcicfgr8(p, PciLTR); 4067dd7cddfSDavid du Colombier 4077dd7cddfSDavid du Colombier p->intl = pcicfgr8(p, PciINTL); 4087dd7cddfSDavid du Colombier 4097dd7cddfSDavid du Colombier /* 4107dd7cddfSDavid du Colombier * If the device is a multi-function device adjust the 4117dd7cddfSDavid du Colombier * loop count so all possible functions are checked. 4127dd7cddfSDavid du Colombier */ 4137dd7cddfSDavid du Colombier hdt = pcicfgr8(p, PciHDT); 4147dd7cddfSDavid du Colombier if(hdt & 0x80) 4157dd7cddfSDavid du Colombier maxfno = MaxFNO; 4167dd7cddfSDavid du Colombier 4177dd7cddfSDavid du Colombier /* 4187dd7cddfSDavid du Colombier * If appropriate, read the base address registers 4197dd7cddfSDavid du Colombier * and work out the sizes. 4207dd7cddfSDavid du Colombier */ 4217dd7cddfSDavid du Colombier switch(p->ccrb) { 4227dd7cddfSDavid du Colombier case 0x01: /* mass storage controller */ 4237dd7cddfSDavid du Colombier case 0x02: /* network controller */ 4247dd7cddfSDavid du Colombier case 0x03: /* display controller */ 4257dd7cddfSDavid du Colombier case 0x04: /* multimedia device */ 4267dd7cddfSDavid du Colombier case 0x07: /* simple comm. controllers */ 4277dd7cddfSDavid du Colombier case 0x08: /* base system peripherals */ 4287dd7cddfSDavid du Colombier case 0x09: /* input devices */ 4297dd7cddfSDavid du Colombier case 0x0A: /* docking stations */ 4307dd7cddfSDavid du Colombier case 0x0B: /* processors */ 4317dd7cddfSDavid du Colombier case 0x0C: /* serial bus controllers */ 4327dd7cddfSDavid du Colombier if((hdt & 0x7F) != 0) 4337dd7cddfSDavid du Colombier break; 4347dd7cddfSDavid du Colombier rno = PciBAR0 - 4; 4357dd7cddfSDavid du Colombier for(i = 0; i < nelem(p->mem); i++) { 4367dd7cddfSDavid du Colombier rno += 4; 4377dd7cddfSDavid du Colombier p->mem[i].bar = pcicfgr32(p, rno); 4387dd7cddfSDavid du Colombier p->mem[i].size = pcibarsize(p, rno); 4397dd7cddfSDavid du Colombier } 4407dd7cddfSDavid du Colombier break; 4417dd7cddfSDavid du Colombier 4427dd7cddfSDavid du Colombier case 0x00: 4437dd7cddfSDavid du Colombier case 0x05: /* memory controller */ 4447dd7cddfSDavid du Colombier case 0x06: /* bridge device */ 4457dd7cddfSDavid du Colombier default: 4467dd7cddfSDavid du Colombier break; 4477dd7cddfSDavid du Colombier } 4487dd7cddfSDavid du Colombier 4497dd7cddfSDavid du Colombier if(head != nil) 4507dd7cddfSDavid du Colombier tail->link = p; 4517dd7cddfSDavid du Colombier else 4527dd7cddfSDavid du Colombier head = p; 4537dd7cddfSDavid du Colombier tail = p; 4547dd7cddfSDavid du Colombier } 4557dd7cddfSDavid du Colombier } 4567dd7cddfSDavid du Colombier 4577dd7cddfSDavid du Colombier *list = head; 4587dd7cddfSDavid du Colombier for(p = head; p != nil; p = p->link){ 4597dd7cddfSDavid du Colombier /* 4607dd7cddfSDavid du Colombier * Find PCI-PCI bridges and recursively descend the tree. 4617dd7cddfSDavid du Colombier */ 4627dd7cddfSDavid du Colombier if(p->ccrb != 0x06 || p->ccru != 0x04) 4637dd7cddfSDavid du Colombier continue; 4647dd7cddfSDavid du Colombier 4657dd7cddfSDavid du Colombier /* 4667dd7cddfSDavid du Colombier * If the secondary or subordinate bus number is not 4677dd7cddfSDavid du Colombier * initialised try to do what the PCI BIOS should have 4687dd7cddfSDavid du Colombier * done and fill in the numbers as the tree is descended. 4697dd7cddfSDavid du Colombier * On the way down the subordinate bus number is set to 4707dd7cddfSDavid du Colombier * the maximum as it's not known how many buses are behind 4717dd7cddfSDavid du Colombier * this one; the final value is set on the way back up. 4727dd7cddfSDavid du Colombier */ 4737dd7cddfSDavid du Colombier sbn = pcicfgr8(p, PciSBN); 4747dd7cddfSDavid du Colombier ubn = pcicfgr8(p, PciUBN); 4757dd7cddfSDavid du Colombier 47680ee5cbfSDavid du Colombier if(sbn == 0 || ubn == 0 || nobios) { 4777dd7cddfSDavid du Colombier sbn = maxubn+1; 4787dd7cddfSDavid du Colombier /* 4797dd7cddfSDavid du Colombier * Make sure memory, I/O and master enables are 4807dd7cddfSDavid du Colombier * off, set the primary, secondary and subordinate 4817dd7cddfSDavid du Colombier * bus numbers and clear the secondary status before 4827dd7cddfSDavid du Colombier * attempting to scan the secondary bus. 4837dd7cddfSDavid du Colombier * 4847dd7cddfSDavid du Colombier * Initialisation of the bridge should be done here. 4857dd7cddfSDavid du Colombier */ 4867dd7cddfSDavid du Colombier pcicfgw32(p, PciPCR, 0xFFFF0000); 4877dd7cddfSDavid du Colombier l = (MaxUBN<<16)|(sbn<<8)|bno; 4887dd7cddfSDavid du Colombier pcicfgw32(p, PciPBN, l); 4897dd7cddfSDavid du Colombier pcicfgw16(p, PciSPSR, 0xFFFF); 4909a747e4fSDavid du Colombier maxubn = pcilscan(sbn, &p->bridge); 4917dd7cddfSDavid du Colombier l = (maxubn<<16)|(sbn<<8)|bno; 4927dd7cddfSDavid du Colombier 4937dd7cddfSDavid du Colombier pcicfgw32(p, PciPBN, l); 4947dd7cddfSDavid du Colombier } 4957dd7cddfSDavid du Colombier else { 496e569ccb5SDavid du Colombier if(ubn > maxubn) 4977dd7cddfSDavid du Colombier maxubn = ubn; 4989a747e4fSDavid du Colombier pcilscan(sbn, &p->bridge); 4997dd7cddfSDavid du Colombier } 5007dd7cddfSDavid du Colombier } 5017dd7cddfSDavid du Colombier 5027dd7cddfSDavid du Colombier return maxubn; 5037dd7cddfSDavid du Colombier } 5047dd7cddfSDavid du Colombier 5059a747e4fSDavid du Colombier int 5069a747e4fSDavid du Colombier pciscan(int bno, Pcidev **list) 5079a747e4fSDavid du Colombier { 5089a747e4fSDavid du Colombier int ubn; 5099a747e4fSDavid du Colombier 5109a747e4fSDavid du Colombier lock(&pcicfginitlock); 5119a747e4fSDavid du Colombier ubn = pcilscan(bno, list); 5129a747e4fSDavid du Colombier unlock(&pcicfginitlock); 5139a747e4fSDavid du Colombier return ubn; 5149a747e4fSDavid du Colombier } 5159a747e4fSDavid du Colombier 5169a747e4fSDavid du Colombier static uchar 51759c21d95SDavid du Colombier pIIxget(Pcidev *router, uchar link) 5189a747e4fSDavid du Colombier { 5199a747e4fSDavid du Colombier uchar pirq; 5209a747e4fSDavid du Colombier 5219a747e4fSDavid du Colombier /* link should be 0x60, 0x61, 0x62, 0x63 */ 5229a747e4fSDavid du Colombier pirq = pcicfgr8(router, link); 5239a747e4fSDavid du Colombier return (pirq < 16)? pirq: 0; 5249a747e4fSDavid du Colombier } 5259a747e4fSDavid du Colombier 5269a747e4fSDavid du Colombier static void 52759c21d95SDavid du Colombier pIIxset(Pcidev *router, uchar link, uchar irq) 5289a747e4fSDavid du Colombier { 5299a747e4fSDavid du Colombier pcicfgw8(router, link, irq); 5309a747e4fSDavid du Colombier } 5319a747e4fSDavid du Colombier 5329a747e4fSDavid du Colombier static uchar 53359c21d95SDavid du Colombier viaget(Pcidev *router, uchar link) 5349a747e4fSDavid du Colombier { 5359a747e4fSDavid du Colombier uchar pirq; 5369a747e4fSDavid du Colombier 5379a747e4fSDavid du Colombier /* link should be 1, 2, 3, 5 */ 5389a747e4fSDavid du Colombier pirq = (link < 6)? pcicfgr8(router, 0x55 + (link>>1)): 0; 5399a747e4fSDavid du Colombier 5409a747e4fSDavid du Colombier return (link & 1)? (pirq >> 4): (pirq & 15); 5419a747e4fSDavid du Colombier } 5429a747e4fSDavid du Colombier 5439a747e4fSDavid du Colombier static void 54459c21d95SDavid du Colombier viaset(Pcidev *router, uchar link, uchar irq) 5459a747e4fSDavid du Colombier { 5469a747e4fSDavid du Colombier uchar pirq; 5479a747e4fSDavid du Colombier 5489a747e4fSDavid du Colombier pirq = pcicfgr8(router, 0x55 + (link >> 1)); 5499a747e4fSDavid du Colombier pirq &= (link & 1)? 0x0f: 0xf0; 5509a747e4fSDavid du Colombier pirq |= (link & 1)? (irq << 4): (irq & 15); 5519a747e4fSDavid du Colombier pcicfgw8(router, 0x55 + (link>>1), pirq); 5529a747e4fSDavid du Colombier } 5539a747e4fSDavid du Colombier 5549a747e4fSDavid du Colombier static uchar 55559c21d95SDavid du Colombier optiget(Pcidev *router, uchar link) 5569a747e4fSDavid du Colombier { 5579a747e4fSDavid du Colombier uchar pirq = 0; 5589a747e4fSDavid du Colombier 5599a747e4fSDavid du Colombier /* link should be 0x02, 0x12, 0x22, 0x32 */ 5609a747e4fSDavid du Colombier if ((link & 0xcf) == 0x02) 5619a747e4fSDavid du Colombier pirq = pcicfgr8(router, 0xb8 + (link >> 5)); 5629a747e4fSDavid du Colombier return (link & 0x10)? (pirq >> 4): (pirq & 15); 5639a747e4fSDavid du Colombier } 5649a747e4fSDavid du Colombier 5659a747e4fSDavid du Colombier static void 56659c21d95SDavid du Colombier optiset(Pcidev *router, uchar link, uchar irq) 5679a747e4fSDavid du Colombier { 5689a747e4fSDavid du Colombier uchar pirq; 5699a747e4fSDavid du Colombier 5709a747e4fSDavid du Colombier pirq = pcicfgr8(router, 0xb8 + (link >> 5)); 5719a747e4fSDavid du Colombier pirq &= (link & 0x10)? 0x0f : 0xf0; 5729a747e4fSDavid du Colombier pirq |= (link & 0x10)? (irq << 4): (irq & 15); 5739a747e4fSDavid du Colombier pcicfgw8(router, 0xb8 + (link >> 5), pirq); 5749a747e4fSDavid du Colombier } 5759a747e4fSDavid du Colombier 5769a747e4fSDavid du Colombier static uchar 57759c21d95SDavid du Colombier aliget(Pcidev *router, uchar link) 5789a747e4fSDavid du Colombier { 5799a747e4fSDavid du Colombier /* No, you're not dreaming */ 5809a747e4fSDavid du Colombier static const uchar map[] = { 0, 9, 3, 10, 4, 5, 7, 6, 1, 11, 0, 12, 0, 14, 0, 15 }; 5819a747e4fSDavid du Colombier uchar pirq; 5829a747e4fSDavid du Colombier 5839a747e4fSDavid du Colombier /* link should be 0x01..0x08 */ 5849a747e4fSDavid du Colombier pirq = pcicfgr8(router, 0x48 + ((link-1)>>1)); 5859a747e4fSDavid du Colombier return (link & 1)? map[pirq&15]: map[pirq>>4]; 5869a747e4fSDavid du Colombier } 5879a747e4fSDavid du Colombier 5889a747e4fSDavid du Colombier static void 58959c21d95SDavid du Colombier aliset(Pcidev *router, uchar link, uchar irq) 5909a747e4fSDavid du Colombier { 59159c21d95SDavid du Colombier /* Inverse of map in aliget */ 5929a747e4fSDavid du Colombier static const uchar map[] = { 0, 8, 0, 2, 4, 5, 7, 6, 0, 1, 3, 9, 11, 0, 13, 15 }; 5939a747e4fSDavid du Colombier uchar pirq; 5949a747e4fSDavid du Colombier 5959a747e4fSDavid du Colombier pirq = pcicfgr8(router, 0x48 + ((link-1)>>1)); 5969a747e4fSDavid du Colombier pirq &= (link & 1)? 0x0f: 0xf0; 5979a747e4fSDavid du Colombier pirq |= (link & 1)? (map[irq] << 4): (map[irq] & 15); 5989a747e4fSDavid du Colombier pcicfgw8(router, 0x48 + ((link-1)>>1), pirq); 5999a747e4fSDavid du Colombier } 6009a747e4fSDavid du Colombier 6019a747e4fSDavid du Colombier static uchar 60259c21d95SDavid du Colombier cyrixget(Pcidev *router, uchar link) 6039a747e4fSDavid du Colombier { 6049a747e4fSDavid du Colombier uchar pirq; 6059a747e4fSDavid du Colombier 6069a747e4fSDavid du Colombier /* link should be 1, 2, 3, 4 */ 6079a747e4fSDavid du Colombier pirq = pcicfgr8(router, 0x5c + ((link-1)>>1)); 6089a747e4fSDavid du Colombier return ((link & 1)? pirq >> 4: pirq & 15); 6099a747e4fSDavid du Colombier } 6109a747e4fSDavid du Colombier 6119a747e4fSDavid du Colombier static void 61259c21d95SDavid du Colombier cyrixset(Pcidev *router, uchar link, uchar irq) 6139a747e4fSDavid du Colombier { 6149a747e4fSDavid du Colombier uchar pirq; 6159a747e4fSDavid du Colombier 6169a747e4fSDavid du Colombier pirq = pcicfgr8(router, 0x5c + (link>>1)); 6179a747e4fSDavid du Colombier pirq &= (link & 1)? 0x0f: 0xf0; 6189a747e4fSDavid du Colombier pirq |= (link & 1)? (irq << 4): (irq & 15); 6199a747e4fSDavid du Colombier pcicfgw8(router, 0x5c + (link>>1), pirq); 6209a747e4fSDavid du Colombier } 6219a747e4fSDavid du Colombier 62259c21d95SDavid du Colombier typedef struct Bridge Bridge; 62359c21d95SDavid du Colombier struct Bridge 6249a747e4fSDavid du Colombier { 6259a747e4fSDavid du Colombier ushort vid; 6269a747e4fSDavid du Colombier ushort did; 6279a747e4fSDavid du Colombier uchar (*get)(Pcidev *, uchar); 6289a747e4fSDavid du Colombier void (*set)(Pcidev *, uchar, uchar); 6299a747e4fSDavid du Colombier }; 6309a747e4fSDavid du Colombier 63159c21d95SDavid du Colombier static Bridge southbridges[] = { 63241dd6b47SDavid du Colombier { 0x8086, 0x122e, pIIxget, pIIxset }, /* Intel 82371FB */ 63341dd6b47SDavid du Colombier { 0x8086, 0x1234, pIIxget, pIIxset }, /* Intel 82371MX */ 63441dd6b47SDavid du Colombier { 0x8086, 0x7000, pIIxget, pIIxset }, /* Intel 82371SB */ 63541dd6b47SDavid du Colombier { 0x8086, 0x7110, pIIxget, pIIxset }, /* Intel 82371AB */ 63641dd6b47SDavid du Colombier { 0x8086, 0x7198, pIIxget, pIIxset }, /* Intel 82443MX (fn 1) */ 63741dd6b47SDavid du Colombier { 0x8086, 0x2410, pIIxget, pIIxset }, /* Intel 82801AA */ 63841dd6b47SDavid du Colombier { 0x8086, 0x2420, pIIxget, pIIxset }, /* Intel 82801AB */ 63941dd6b47SDavid du Colombier { 0x8086, 0x2440, pIIxget, pIIxset }, /* Intel 82801BA */ 64041dd6b47SDavid du Colombier { 0x8086, 0x244c, pIIxget, pIIxset }, /* Intel 82801BAM */ 64141dd6b47SDavid du Colombier { 0x8086, 0x2480, pIIxget, pIIxset }, /* Intel 82801CA */ 64241dd6b47SDavid du Colombier { 0x8086, 0x248c, pIIxget, pIIxset }, /* Intel 82801CAM */ 64341dd6b47SDavid du Colombier { 0x8086, 0x24c0, pIIxget, pIIxset }, /* Intel 82801DBL */ 64441dd6b47SDavid du Colombier { 0x8086, 0x24cc, pIIxget, pIIxset }, /* Intel 82801DBM */ 64541dd6b47SDavid du Colombier { 0x8086, 0x24d0, pIIxget, pIIxset }, /* Intel 82801EB */ 64641dd6b47SDavid du Colombier { 0x8086, 0x2640, pIIxget, pIIxset }, /* Intel 82801FB */ 64741dd6b47SDavid du Colombier { 0x8086, 0x27b8, pIIxget, pIIxset }, /* Intel 82801GB */ 64841dd6b47SDavid du Colombier { 0x8086, 0x27b9, pIIxget, pIIxset }, /* Intel 82801GBM */ 64941dd6b47SDavid du Colombier { 0x1106, 0x0586, viaget, viaset }, /* Viatech 82C586 */ 65041dd6b47SDavid du Colombier { 0x1106, 0x0596, viaget, viaset }, /* Viatech 82C596 */ 65141dd6b47SDavid du Colombier { 0x1106, 0x0686, viaget, viaset }, /* Viatech 82C686 */ 65241dd6b47SDavid du Colombier { 0x1106, 0x3227, viaget, viaset }, /* Viatech VT8237 */ 65341dd6b47SDavid du Colombier { 0x1045, 0xc700, optiget, optiset }, /* Opti 82C700 */ 65441dd6b47SDavid du Colombier { 0x10b9, 0x1533, aliget, aliset }, /* Al M1533 */ 65541dd6b47SDavid du Colombier { 0x1039, 0x0008, pIIxget, pIIxset }, /* SI 503 */ 65641dd6b47SDavid du Colombier { 0x1039, 0x0496, pIIxget, pIIxset }, /* SI 496 */ 65741dd6b47SDavid du Colombier { 0x1078, 0x0100, cyrixget, cyrixset }, /* Cyrix 5530 Legacy */ 6585000fddeSDavid du Colombier 65941dd6b47SDavid du Colombier { 0x1022, 0x746B, nil, nil }, /* AMD 8111 */ 66041dd6b47SDavid du Colombier { 0x10DE, 0x00D1, nil, nil }, /* NVIDIA nForce 3 */ 66141dd6b47SDavid du Colombier { 0x1166, 0x0200, nil, nil }, /* ServerWorks ServerSet III LE */ 66241dd6b47SDavid du Colombier { 0x1002, 0x4377, nil, nil }, /* ATI Radeon Xpress 200M */ 66341dd6b47SDavid du Colombier { 0x1002, 0x4372, nil, nil }, /* ATI SB400 */ 66459c21d95SDavid du Colombier }; 6659a747e4fSDavid du Colombier 66659c21d95SDavid du Colombier typedef struct Slot Slot; 66759c21d95SDavid du Colombier struct Slot { 66841dd6b47SDavid du Colombier uchar bus; /* Pci bus number */ 66941dd6b47SDavid du Colombier uchar dev; /* Pci device number */ 67041dd6b47SDavid du Colombier uchar maps[12]; /* Avoid structs! Link and mask. */ 67141dd6b47SDavid du Colombier uchar slot; /* Add-in/built-in slot */ 67259c21d95SDavid du Colombier uchar reserved; 67359c21d95SDavid du Colombier }; 67459c21d95SDavid du Colombier 67559c21d95SDavid du Colombier typedef struct Router Router; 67659c21d95SDavid du Colombier struct Router { 67741dd6b47SDavid du Colombier uchar signature[4]; /* Routing table signature */ 67841dd6b47SDavid du Colombier uchar version[2]; /* Version number */ 67941dd6b47SDavid du Colombier uchar size[2]; /* Total table size */ 68041dd6b47SDavid du Colombier uchar bus; /* Interrupt router bus number */ 68141dd6b47SDavid du Colombier uchar devfn; /* Router's devfunc */ 68241dd6b47SDavid du Colombier uchar pciirqs[2]; /* Exclusive PCI irqs */ 68341dd6b47SDavid du Colombier uchar compat[4]; /* Compatible PCI interrupt router */ 68441dd6b47SDavid du Colombier uchar miniport[4]; /* Miniport data */ 68559c21d95SDavid du Colombier uchar reserved[11]; 68659c21d95SDavid du Colombier uchar checksum; 68759c21d95SDavid du Colombier }; 6889a747e4fSDavid du Colombier 68941dd6b47SDavid du Colombier static ushort pciirqs; /* Exclusive PCI irqs */ 69041dd6b47SDavid du Colombier static Bridge *southbridge; /* Which southbridge to use. */ 6919a747e4fSDavid du Colombier 6929a747e4fSDavid du Colombier static void 6939a747e4fSDavid du Colombier pcirouting(void) 6949a747e4fSDavid du Colombier { 69559c21d95SDavid du Colombier Slot *e; 69659c21d95SDavid du Colombier Router *r; 6979a747e4fSDavid du Colombier int size, i, fn, tbdf; 6989a747e4fSDavid du Colombier Pcidev *sbpci, *pci; 6995000fddeSDavid du Colombier uchar *p, pin, irq, link, *map; 7009a747e4fSDavid du Colombier 70141dd6b47SDavid du Colombier /* Search for PCI interrupt routing table in BIOS */ 7029a747e4fSDavid du Colombier for(p = (uchar *)KADDR(0xf0000); p < (uchar *)KADDR(0xfffff); p += 16) 7039a747e4fSDavid du Colombier if(p[0] == '$' && p[1] == 'P' && p[2] == 'I' && p[3] == 'R') 7049a747e4fSDavid du Colombier break; 7059a747e4fSDavid du Colombier 7069a747e4fSDavid du Colombier if(p >= (uchar *)KADDR(0xfffff)) 7079a747e4fSDavid du Colombier return; 7089a747e4fSDavid du Colombier 70959c21d95SDavid du Colombier r = (Router *)p; 7109a747e4fSDavid du Colombier 7119a747e4fSDavid du Colombier // print("PCI interrupt routing table version %d.%d at %.6uX\n", 71259c21d95SDavid du Colombier // r->version[0], r->version[1], (ulong)r & 0xfffff); 7139a747e4fSDavid du Colombier 71459c21d95SDavid du Colombier tbdf = (BusPCI << 24)|(r->bus << 16)|(r->devfn << 8); 7159a747e4fSDavid du Colombier sbpci = pcimatchtbdf(tbdf); 7169a747e4fSDavid du Colombier if(sbpci == nil) { 7179a747e4fSDavid du Colombier print("pcirouting: Cannot find south bridge %T\n", tbdf); 7189a747e4fSDavid du Colombier return; 7199a747e4fSDavid du Colombier } 7209a747e4fSDavid du Colombier 7219a747e4fSDavid du Colombier for(i = 0; i != nelem(southbridges); i++) 7229a747e4fSDavid du Colombier if(sbpci->vid == southbridges[i].vid && sbpci->did == southbridges[i].did) 7239a747e4fSDavid du Colombier break; 7249a747e4fSDavid du Colombier 7259a747e4fSDavid du Colombier if(i == nelem(southbridges)) { 7263ff48bf5SDavid du Colombier print("pcirouting: ignoring south bridge %T %.4uX/%.4uX\n", tbdf, sbpci->vid, sbpci->did); 7279a747e4fSDavid du Colombier return; 7289a747e4fSDavid du Colombier } 7299a747e4fSDavid du Colombier southbridge = &southbridges[i]; 7305000fddeSDavid du Colombier if(southbridge->get == nil || southbridge->set == nil) 7315000fddeSDavid du Colombier return; 7329a747e4fSDavid du Colombier 73359c21d95SDavid du Colombier pciirqs = (r->pciirqs[1] << 8)|r->pciirqs[0]; 7349a747e4fSDavid du Colombier 73559c21d95SDavid du Colombier size = (r->size[1] << 8)|r->size[0]; 73659c21d95SDavid du Colombier for(e = (Slot *)&r[1]; (uchar *)e < p + size; e++) { 73741dd6b47SDavid du Colombier if (0) { 73841dd6b47SDavid du Colombier print("%.2uX/%.2uX %.2uX: ", e->bus, e->dev, e->slot); 73941dd6b47SDavid du Colombier for (i = 0; i != 4; i++) { 74041dd6b47SDavid du Colombier uchar *m = &e->maps[i * 3]; 74141dd6b47SDavid du Colombier print("[%d] %.2uX %.4uX ", 74241dd6b47SDavid du Colombier i, m[0], (m[2] << 8)|m[1]); 74341dd6b47SDavid du Colombier } 74441dd6b47SDavid du Colombier print("\n"); 74541dd6b47SDavid du Colombier } 7469a747e4fSDavid du Colombier for(fn = 0; fn != 8; fn++) { 74759c21d95SDavid du Colombier tbdf = (BusPCI << 24)|(e->bus << 16)|((e->dev | fn) << 8); 7489a747e4fSDavid du Colombier pci = pcimatchtbdf(tbdf); 7499a747e4fSDavid du Colombier if(pci == nil) 7509a747e4fSDavid du Colombier continue; 7519a747e4fSDavid du Colombier pin = pcicfgr8(pci, PciINTP); 7529a747e4fSDavid du Colombier if(pin == 0 || pin == 0xff) 7539a747e4fSDavid du Colombier continue; 7549a747e4fSDavid du Colombier 7555000fddeSDavid du Colombier map = &e->maps[(pin - 1) * 3]; 7565000fddeSDavid du Colombier link = map[0]; 7573ff48bf5SDavid du Colombier irq = southbridge->get(sbpci, link); 7589a747e4fSDavid du Colombier if(irq == 0 || irq == pci->intl) 7599a747e4fSDavid du Colombier continue; 7609a747e4fSDavid du Colombier if(pci->intl != 0 && pci->intl != 0xFF) { 7613ff48bf5SDavid du Colombier print("pcirouting: BIOS workaround: %T at pin %d link %d irq %d -> %d\n", 7623ff48bf5SDavid du Colombier tbdf, pin, link, irq, pci->intl); 7633ff48bf5SDavid du Colombier southbridge->set(sbpci, link, pci->intl); 7649a747e4fSDavid du Colombier continue; 7659a747e4fSDavid du Colombier } 7663ff48bf5SDavid du Colombier print("pcirouting: %T at pin %d link %d irq %d\n", tbdf, pin, link, irq); 7679a747e4fSDavid du Colombier pcicfgw8(pci, PciINTL, irq); 7689a747e4fSDavid du Colombier pci->intl = irq; 7699a747e4fSDavid du Colombier } 7709a747e4fSDavid du Colombier } 7719a747e4fSDavid du Colombier } 7729a747e4fSDavid du Colombier 7734de34a7eSDavid du Colombier static void pcireservemem(void); 7744de34a7eSDavid du Colombier 7754fafed5dSDavid du Colombier static int 7764fafed5dSDavid du Colombier pcicfgrw8bios(int tbdf, int rno, int data, int read) 7774fafed5dSDavid du Colombier { 7784fafed5dSDavid du Colombier BIOS32ci ci; 7794fafed5dSDavid du Colombier 7804fafed5dSDavid du Colombier if(pcibiossi == nil) 7814fafed5dSDavid du Colombier return -1; 7824fafed5dSDavid du Colombier 7834fafed5dSDavid du Colombier memset(&ci, 0, sizeof(BIOS32ci)); 7844fafed5dSDavid du Colombier ci.ebx = (BUSBNO(tbdf)<<8)|(BUSDNO(tbdf)<<3)|BUSFNO(tbdf); 7854fafed5dSDavid du Colombier ci.edi = rno; 7864fafed5dSDavid du Colombier if(read){ 7874fafed5dSDavid du Colombier ci.eax = 0xB108; 7884fafed5dSDavid du Colombier if(!bios32ci(pcibiossi, &ci)/* && !(ci.eax & 0xFF)*/) 7894fafed5dSDavid du Colombier return ci.ecx & 0xFF; 7904fafed5dSDavid du Colombier } 7914fafed5dSDavid du Colombier else{ 7924fafed5dSDavid du Colombier ci.eax = 0xB10B; 7934fafed5dSDavid du Colombier ci.ecx = data & 0xFF; 7944fafed5dSDavid du Colombier if(!bios32ci(pcibiossi, &ci)/* && !(ci.eax & 0xFF)*/) 7954fafed5dSDavid du Colombier return 0; 7964fafed5dSDavid du Colombier } 7974fafed5dSDavid du Colombier 7984fafed5dSDavid du Colombier return -1; 7994fafed5dSDavid du Colombier } 8004fafed5dSDavid du Colombier 8014fafed5dSDavid du Colombier static int 8024fafed5dSDavid du Colombier pcicfgrw16bios(int tbdf, int rno, int data, int read) 8034fafed5dSDavid du Colombier { 8044fafed5dSDavid du Colombier BIOS32ci ci; 8054fafed5dSDavid du Colombier 8064fafed5dSDavid du Colombier if(pcibiossi == nil) 8074fafed5dSDavid du Colombier return -1; 8084fafed5dSDavid du Colombier 8094fafed5dSDavid du Colombier memset(&ci, 0, sizeof(BIOS32ci)); 8104fafed5dSDavid du Colombier ci.ebx = (BUSBNO(tbdf)<<8)|(BUSDNO(tbdf)<<3)|BUSFNO(tbdf); 8114fafed5dSDavid du Colombier ci.edi = rno; 8124fafed5dSDavid du Colombier if(read){ 8134fafed5dSDavid du Colombier ci.eax = 0xB109; 8144fafed5dSDavid du Colombier if(!bios32ci(pcibiossi, &ci)/* && !(ci.eax & 0xFF)*/) 8154fafed5dSDavid du Colombier return ci.ecx & 0xFFFF; 8164fafed5dSDavid du Colombier } 8174fafed5dSDavid du Colombier else{ 8184fafed5dSDavid du Colombier ci.eax = 0xB10C; 8194fafed5dSDavid du Colombier ci.ecx = data & 0xFFFF; 8204fafed5dSDavid du Colombier if(!bios32ci(pcibiossi, &ci)/* && !(ci.eax & 0xFF)*/) 8214fafed5dSDavid du Colombier return 0; 8224fafed5dSDavid du Colombier } 8234fafed5dSDavid du Colombier 8244fafed5dSDavid du Colombier return -1; 8254fafed5dSDavid du Colombier } 8264fafed5dSDavid du Colombier 8274fafed5dSDavid du Colombier static int 8284fafed5dSDavid du Colombier pcicfgrw32bios(int tbdf, int rno, int data, int read) 8294fafed5dSDavid du Colombier { 8304fafed5dSDavid du Colombier BIOS32ci ci; 8314fafed5dSDavid du Colombier 8324fafed5dSDavid du Colombier if(pcibiossi == nil) 8334fafed5dSDavid du Colombier return -1; 8344fafed5dSDavid du Colombier 8354fafed5dSDavid du Colombier memset(&ci, 0, sizeof(BIOS32ci)); 8364fafed5dSDavid du Colombier ci.ebx = (BUSBNO(tbdf)<<8)|(BUSDNO(tbdf)<<3)|BUSFNO(tbdf); 8374fafed5dSDavid du Colombier ci.edi = rno; 8384fafed5dSDavid du Colombier if(read){ 8394fafed5dSDavid du Colombier ci.eax = 0xB10A; 8404fafed5dSDavid du Colombier if(!bios32ci(pcibiossi, &ci)/* && !(ci.eax & 0xFF)*/) 8414fafed5dSDavid du Colombier return ci.ecx; 8424fafed5dSDavid du Colombier } 8434fafed5dSDavid du Colombier else{ 8444fafed5dSDavid du Colombier ci.eax = 0xB10D; 8454fafed5dSDavid du Colombier ci.ecx = data; 8464fafed5dSDavid du Colombier if(!bios32ci(pcibiossi, &ci)/* && !(ci.eax & 0xFF)*/) 8474fafed5dSDavid du Colombier return 0; 8484fafed5dSDavid du Colombier } 8494fafed5dSDavid du Colombier 8504fafed5dSDavid du Colombier return -1; 8514fafed5dSDavid du Colombier } 8524fafed5dSDavid du Colombier 8534fafed5dSDavid du Colombier static BIOS32si* 8544fafed5dSDavid du Colombier pcibiosinit(void) 8554fafed5dSDavid du Colombier { 8564fafed5dSDavid du Colombier BIOS32ci ci; 8574fafed5dSDavid du Colombier BIOS32si *si; 8584fafed5dSDavid du Colombier 8594fafed5dSDavid du Colombier if((si = bios32open("$PCI")) == nil) 8604fafed5dSDavid du Colombier return nil; 8614fafed5dSDavid du Colombier 8624fafed5dSDavid du Colombier memset(&ci, 0, sizeof(BIOS32ci)); 8634fafed5dSDavid du Colombier ci.eax = 0xB101; 8644fafed5dSDavid du Colombier if(bios32ci(si, &ci) || ci.edx != ((' '<<24)|('I'<<16)|('C'<<8)|'P')){ 8654fafed5dSDavid du Colombier free(si); 8664fafed5dSDavid du Colombier return nil; 8674fafed5dSDavid du Colombier } 8684fafed5dSDavid du Colombier if(ci.eax & 0x01) 8694fafed5dSDavid du Colombier pcimaxdno = 31; 8704fafed5dSDavid du Colombier else 8714fafed5dSDavid du Colombier pcimaxdno = 15; 8724fafed5dSDavid du Colombier pcimaxbno = ci.ecx & 0xff; 8734fafed5dSDavid du Colombier 8744fafed5dSDavid du Colombier return si; 8754fafed5dSDavid du Colombier } 8764fafed5dSDavid du Colombier 877c91329d7SDavid du Colombier void 878c91329d7SDavid du Colombier pcibussize(Pcidev *root, ulong *msize, ulong *iosize) 879c91329d7SDavid du Colombier { 880c91329d7SDavid du Colombier *msize = 0; 881c91329d7SDavid du Colombier *iosize = 0; 882c91329d7SDavid du Colombier pcibusmap(root, msize, iosize, 0); 883c91329d7SDavid du Colombier } 884c91329d7SDavid du Colombier 8857dd7cddfSDavid du Colombier static void 8867dd7cddfSDavid du Colombier pcicfginit(void) 8877dd7cddfSDavid du Colombier { 8887dd7cddfSDavid du Colombier char *p; 8897dd7cddfSDavid du Colombier Pcidev **list; 8907dd7cddfSDavid du Colombier ulong mema, ioa; 891becaf2abSDavid du Colombier int bno, n, pcibios; 8927dd7cddfSDavid du Colombier 8937dd7cddfSDavid du Colombier lock(&pcicfginitlock); 8947dd7cddfSDavid du Colombier if(pcicfgmode != -1) 8957dd7cddfSDavid du Colombier goto out; 8967dd7cddfSDavid du Colombier 897becaf2abSDavid du Colombier pcibios = 0; 89880ee5cbfSDavid du Colombier if(getconf("*nobios")) 89980ee5cbfSDavid du Colombier nobios = 1; 900becaf2abSDavid du Colombier else if(getconf("*pcibios")) 901becaf2abSDavid du Colombier pcibios = 1; 9023ff48bf5SDavid du Colombier if(getconf("*nopcirouting")) 9033ff48bf5SDavid du Colombier nopcirouting = 1; 9043ff48bf5SDavid du Colombier 9057dd7cddfSDavid du Colombier /* 9067dd7cddfSDavid du Colombier * Try to determine which PCI configuration mode is implemented. 9077dd7cddfSDavid du Colombier * Mode2 uses a byte at 0xCF8 and another at 0xCFA; Mode1 uses 9087dd7cddfSDavid du Colombier * a DWORD at 0xCF8 and another at 0xCFC and will pass through 9097dd7cddfSDavid du Colombier * any non-DWORD accesses as normal I/O cycles. There shouldn't be 9103ff48bf5SDavid du Colombier * a device behind these addresses so if Mode1 accesses fail try 9113ff48bf5SDavid du Colombier * for Mode2 (Mode2 is deprecated). 9127dd7cddfSDavid du Colombier */ 913becaf2abSDavid du Colombier if(!pcibios){ 914becaf2abSDavid du Colombier /* 915becaf2abSDavid du Colombier * Bits [30:24] of PciADDR must be 0, 916becaf2abSDavid du Colombier * according to the spec. 917becaf2abSDavid du Colombier */ 918becaf2abSDavid du Colombier n = inl(PciADDR); 919*6e712d44SDavid du Colombier if(!(n & 0x7F000000)){ 920becaf2abSDavid du Colombier outl(PciADDR, 0x80000000); 921becaf2abSDavid du Colombier outb(PciADDR+3, 0); 922becaf2abSDavid du Colombier if(inl(PciADDR) & 0x80000000){ 9237dd7cddfSDavid du Colombier pcicfgmode = 1; 9247dd7cddfSDavid du Colombier pcimaxdno = 31; 9257dd7cddfSDavid du Colombier } 926becaf2abSDavid du Colombier } 927becaf2abSDavid du Colombier outl(PciADDR, n); 928becaf2abSDavid du Colombier 929becaf2abSDavid du Colombier if(pcicfgmode < 0){ 930becaf2abSDavid du Colombier /* 931becaf2abSDavid du Colombier * The 'key' part of PciCSE should be 0. 932becaf2abSDavid du Colombier */ 933becaf2abSDavid du Colombier n = inb(PciCSE); 934becaf2abSDavid du Colombier if(!(n & 0xF0)){ 935becaf2abSDavid du Colombier outb(PciCSE, 0x0E); 936becaf2abSDavid du Colombier if(inb(PciCSE) == 0x0E){ 9373ff48bf5SDavid du Colombier pcicfgmode = 2; 9383ff48bf5SDavid du Colombier pcimaxdno = 15; 9393ff48bf5SDavid du Colombier } 9407dd7cddfSDavid du Colombier } 941becaf2abSDavid du Colombier outb(PciCSE, n); 942becaf2abSDavid du Colombier } 943becaf2abSDavid du Colombier } 9447dd7cddfSDavid du Colombier 9454fafed5dSDavid du Colombier if(pcicfgmode < 0 || pcibios) { 9464fafed5dSDavid du Colombier if((pcibiossi = pcibiosinit()) == nil) 9477dd7cddfSDavid du Colombier goto out; 9484fafed5dSDavid du Colombier pcicfgrw8 = pcicfgrw8bios; 9494fafed5dSDavid du Colombier pcicfgrw16 = pcicfgrw16bios; 9504fafed5dSDavid du Colombier pcicfgrw32 = pcicfgrw32bios; 9514fafed5dSDavid du Colombier pcicfgmode = 3; 9524fafed5dSDavid du Colombier } 9537dd7cddfSDavid du Colombier 9549a747e4fSDavid du Colombier fmtinstall('T', tbdffmt); 9557dd7cddfSDavid du Colombier 956becaf2abSDavid du Colombier if(p = getconf("*pcimaxbno")){ 957becaf2abSDavid du Colombier n = strtoul(p, 0, 0); 958becaf2abSDavid du Colombier if(n < pcimaxbno) 959becaf2abSDavid du Colombier pcimaxbno = n; 960becaf2abSDavid du Colombier } 961becaf2abSDavid du Colombier if(p = getconf("*pcimaxdno")){ 962becaf2abSDavid du Colombier n = strtoul(p, 0, 0); 963becaf2abSDavid du Colombier if(n < pcimaxdno) 964becaf2abSDavid du Colombier pcimaxdno = n; 965becaf2abSDavid du Colombier } 9667dd7cddfSDavid du Colombier 9677dd7cddfSDavid du Colombier list = &pciroot; 968223a736eSDavid du Colombier for(bno = 0; bno <= pcimaxbno; bno++) { 9699a747e4fSDavid du Colombier int sbno = bno; 9709a747e4fSDavid du Colombier bno = pcilscan(bno, list); 9719a747e4fSDavid du Colombier 9727dd7cddfSDavid du Colombier while(*list) 9737dd7cddfSDavid du Colombier list = &(*list)->link; 9749a747e4fSDavid du Colombier 9759a747e4fSDavid du Colombier if (sbno == 0) { 9769a747e4fSDavid du Colombier Pcidev *pci; 9779a747e4fSDavid du Colombier 9789a747e4fSDavid du Colombier /* 9799a747e4fSDavid du Colombier * If we have found a PCI-to-Cardbus bridge, make sure 9809a747e4fSDavid du Colombier * it has no valid mappings anymore. 9819a747e4fSDavid du Colombier */ 982c91329d7SDavid du Colombier for(pci = pciroot; pci != nil; pci = pci->link){ 9839a747e4fSDavid du Colombier if (pci->ccrb == 6 && pci->ccru == 7) { 9849a747e4fSDavid du Colombier ushort bcr; 9859a747e4fSDavid du Colombier 9869a747e4fSDavid du Colombier /* reset the cardbus */ 9879a747e4fSDavid du Colombier bcr = pcicfgr16(pci, PciBCR); 9889a747e4fSDavid du Colombier pcicfgw16(pci, PciBCR, 0x40 | bcr); 9899a747e4fSDavid du Colombier delay(50); 9909a747e4fSDavid du Colombier } 9919a747e4fSDavid du Colombier } 9929a747e4fSDavid du Colombier } 9937dd7cddfSDavid du Colombier } 9947dd7cddfSDavid du Colombier 9957dd7cddfSDavid du Colombier if(pciroot == nil) 9967dd7cddfSDavid du Colombier goto out; 9977dd7cddfSDavid du Colombier 99880ee5cbfSDavid du Colombier if(nobios) { 9997dd7cddfSDavid du Colombier /* 10007dd7cddfSDavid du Colombier * Work out how big the top bus is 10017dd7cddfSDavid du Colombier */ 1002c91329d7SDavid du Colombier pcibussize(pciroot, &mema, &ioa); 10037dd7cddfSDavid du Colombier 10047dd7cddfSDavid du Colombier /* 10057dd7cddfSDavid du Colombier * Align the windows and map it 10067dd7cddfSDavid du Colombier */ 10077dd7cddfSDavid du Colombier ioa = 0x1000; 10087dd7cddfSDavid du Colombier mema = 0x90000000; 10097dd7cddfSDavid du Colombier 10107dd7cddfSDavid du Colombier pcilog("Mask sizes: mem=%lux io=%lux\n", mema, ioa); 10117dd7cddfSDavid du Colombier 10127dd7cddfSDavid du Colombier pcibusmap(pciroot, &mema, &ioa, 1); 10137dd7cddfSDavid du Colombier DBG("Sizes2: mem=%lux io=%lux\n", mema, ioa); 10147dd7cddfSDavid du Colombier 10157dd7cddfSDavid du Colombier unlock(&pcicfginitlock); 10167dd7cddfSDavid du Colombier return; 10177dd7cddfSDavid du Colombier } 10189a747e4fSDavid du Colombier 10193ff48bf5SDavid du Colombier if (!nopcirouting) 10209a747e4fSDavid du Colombier pcirouting(); 10219a747e4fSDavid du Colombier 10227dd7cddfSDavid du Colombier out: 10234de34a7eSDavid du Colombier pcireservemem(); 10247dd7cddfSDavid du Colombier unlock(&pcicfginitlock); 10259a747e4fSDavid du Colombier 10263ff48bf5SDavid du Colombier if(getconf("*pcihinv")) 10273ff48bf5SDavid du Colombier pcihinv(nil); 10287dd7cddfSDavid du Colombier } 10297dd7cddfSDavid du Colombier 10304de34a7eSDavid du Colombier static void 10314de34a7eSDavid du Colombier pcireservemem(void) 10324de34a7eSDavid du Colombier { 10334de34a7eSDavid du Colombier int i; 10344de34a7eSDavid du Colombier Pcidev *p; 10354de34a7eSDavid du Colombier 10364de34a7eSDavid du Colombier /* 10374de34a7eSDavid du Colombier * mark all the physical address space claimed by pci devices 10384de34a7eSDavid du Colombier * as in use, so that upaalloc doesn't give it out. 10394de34a7eSDavid du Colombier */ 10404de34a7eSDavid du Colombier for(p=pciroot; p; p=p->list) 10414de34a7eSDavid du Colombier for(i=0; i<nelem(p->mem); i++) 10424de34a7eSDavid du Colombier if(p->mem[i].bar && (p->mem[i].bar&1) == 0) 10434de34a7eSDavid du Colombier upareserve(p->mem[i].bar&~0x0F, p->mem[i].size); 10444de34a7eSDavid du Colombier } 10454de34a7eSDavid du Colombier 10467dd7cddfSDavid du Colombier static int 10474fafed5dSDavid du Colombier pcicfgrw8raw(int tbdf, int rno, int data, int read) 10487dd7cddfSDavid du Colombier { 10497dd7cddfSDavid du Colombier int o, type, x; 10507dd7cddfSDavid du Colombier 10517dd7cddfSDavid du Colombier if(pcicfgmode == -1) 10527dd7cddfSDavid du Colombier pcicfginit(); 10537dd7cddfSDavid du Colombier 10547dd7cddfSDavid du Colombier if(BUSBNO(tbdf)) 10557dd7cddfSDavid du Colombier type = 0x01; 10567dd7cddfSDavid du Colombier else 10577dd7cddfSDavid du Colombier type = 0x00; 10587dd7cddfSDavid du Colombier x = -1; 10597dd7cddfSDavid du Colombier if(BUSDNO(tbdf) > pcimaxdno) 10607dd7cddfSDavid du Colombier return x; 10617dd7cddfSDavid du Colombier 10627dd7cddfSDavid du Colombier lock(&pcicfglock); 10637dd7cddfSDavid du Colombier switch(pcicfgmode){ 10647dd7cddfSDavid du Colombier 10657dd7cddfSDavid du Colombier case 1: 10667dd7cddfSDavid du Colombier o = rno & 0x03; 10677dd7cddfSDavid du Colombier rno &= ~0x03; 10687dd7cddfSDavid du Colombier outl(PciADDR, 0x80000000|BUSBDF(tbdf)|rno|type); 10697dd7cddfSDavid du Colombier if(read) 10707dd7cddfSDavid du Colombier x = inb(PciDATA+o); 10717dd7cddfSDavid du Colombier else 10727dd7cddfSDavid du Colombier outb(PciDATA+o, data); 10737dd7cddfSDavid du Colombier outl(PciADDR, 0); 10747dd7cddfSDavid du Colombier break; 10757dd7cddfSDavid du Colombier 10767dd7cddfSDavid du Colombier case 2: 10777dd7cddfSDavid du Colombier outb(PciCSE, 0x80|(BUSFNO(tbdf)<<1)); 10787dd7cddfSDavid du Colombier outb(PciFORWARD, BUSBNO(tbdf)); 10797dd7cddfSDavid du Colombier if(read) 10807dd7cddfSDavid du Colombier x = inb((0xC000|(BUSDNO(tbdf)<<8)) + rno); 10817dd7cddfSDavid du Colombier else 10827dd7cddfSDavid du Colombier outb((0xC000|(BUSDNO(tbdf)<<8)) + rno, data); 10837dd7cddfSDavid du Colombier outb(PciCSE, 0); 10847dd7cddfSDavid du Colombier break; 10857dd7cddfSDavid du Colombier } 10867dd7cddfSDavid du Colombier unlock(&pcicfglock); 10877dd7cddfSDavid du Colombier 10887dd7cddfSDavid du Colombier return x; 10897dd7cddfSDavid du Colombier } 10907dd7cddfSDavid du Colombier 10917dd7cddfSDavid du Colombier int 10927dd7cddfSDavid du Colombier pcicfgr8(Pcidev* pcidev, int rno) 10937dd7cddfSDavid du Colombier { 10947dd7cddfSDavid du Colombier return pcicfgrw8(pcidev->tbdf, rno, 0, 1); 10957dd7cddfSDavid du Colombier } 10967dd7cddfSDavid du Colombier 10977dd7cddfSDavid du Colombier void 10987dd7cddfSDavid du Colombier pcicfgw8(Pcidev* pcidev, int rno, int data) 10997dd7cddfSDavid du Colombier { 11007dd7cddfSDavid du Colombier pcicfgrw8(pcidev->tbdf, rno, data, 0); 11017dd7cddfSDavid du Colombier } 11027dd7cddfSDavid du Colombier 11037dd7cddfSDavid du Colombier static int 11044fafed5dSDavid du Colombier pcicfgrw16raw(int tbdf, int rno, int data, int read) 11057dd7cddfSDavid du Colombier { 11067dd7cddfSDavid du Colombier int o, type, x; 11077dd7cddfSDavid du Colombier 11087dd7cddfSDavid du Colombier if(pcicfgmode == -1) 11097dd7cddfSDavid du Colombier pcicfginit(); 11107dd7cddfSDavid du Colombier 11117dd7cddfSDavid du Colombier if(BUSBNO(tbdf)) 11127dd7cddfSDavid du Colombier type = 0x01; 11137dd7cddfSDavid du Colombier else 11147dd7cddfSDavid du Colombier type = 0x00; 11157dd7cddfSDavid du Colombier x = -1; 11167dd7cddfSDavid du Colombier if(BUSDNO(tbdf) > pcimaxdno) 11177dd7cddfSDavid du Colombier return x; 11187dd7cddfSDavid du Colombier 11197dd7cddfSDavid du Colombier lock(&pcicfglock); 11207dd7cddfSDavid du Colombier switch(pcicfgmode){ 11217dd7cddfSDavid du Colombier 11227dd7cddfSDavid du Colombier case 1: 11237dd7cddfSDavid du Colombier o = rno & 0x02; 11247dd7cddfSDavid du Colombier rno &= ~0x03; 11257dd7cddfSDavid du Colombier outl(PciADDR, 0x80000000|BUSBDF(tbdf)|rno|type); 11267dd7cddfSDavid du Colombier if(read) 11277dd7cddfSDavid du Colombier x = ins(PciDATA+o); 11287dd7cddfSDavid du Colombier else 11297dd7cddfSDavid du Colombier outs(PciDATA+o, data); 11307dd7cddfSDavid du Colombier outl(PciADDR, 0); 11317dd7cddfSDavid du Colombier break; 11327dd7cddfSDavid du Colombier 11337dd7cddfSDavid du Colombier case 2: 11347dd7cddfSDavid du Colombier outb(PciCSE, 0x80|(BUSFNO(tbdf)<<1)); 11357dd7cddfSDavid du Colombier outb(PciFORWARD, BUSBNO(tbdf)); 11367dd7cddfSDavid du Colombier if(read) 11377dd7cddfSDavid du Colombier x = ins((0xC000|(BUSDNO(tbdf)<<8)) + rno); 11387dd7cddfSDavid du Colombier else 11397dd7cddfSDavid du Colombier outs((0xC000|(BUSDNO(tbdf)<<8)) + rno, data); 11407dd7cddfSDavid du Colombier outb(PciCSE, 0); 11417dd7cddfSDavid du Colombier break; 11427dd7cddfSDavid du Colombier } 11437dd7cddfSDavid du Colombier unlock(&pcicfglock); 11447dd7cddfSDavid du Colombier 11457dd7cddfSDavid du Colombier return x; 11467dd7cddfSDavid du Colombier } 11477dd7cddfSDavid du Colombier 11487dd7cddfSDavid du Colombier int 11497dd7cddfSDavid du Colombier pcicfgr16(Pcidev* pcidev, int rno) 11507dd7cddfSDavid du Colombier { 11517dd7cddfSDavid du Colombier return pcicfgrw16(pcidev->tbdf, rno, 0, 1); 11527dd7cddfSDavid du Colombier } 11537dd7cddfSDavid du Colombier 11547dd7cddfSDavid du Colombier void 11557dd7cddfSDavid du Colombier pcicfgw16(Pcidev* pcidev, int rno, int data) 11567dd7cddfSDavid du Colombier { 11577dd7cddfSDavid du Colombier pcicfgrw16(pcidev->tbdf, rno, data, 0); 11587dd7cddfSDavid du Colombier } 11597dd7cddfSDavid du Colombier 11607dd7cddfSDavid du Colombier static int 11614fafed5dSDavid du Colombier pcicfgrw32raw(int tbdf, int rno, int data, int read) 11627dd7cddfSDavid du Colombier { 11637dd7cddfSDavid du Colombier int type, x; 11647dd7cddfSDavid du Colombier 11657dd7cddfSDavid du Colombier if(pcicfgmode == -1) 11667dd7cddfSDavid du Colombier pcicfginit(); 11677dd7cddfSDavid du Colombier 11687dd7cddfSDavid du Colombier if(BUSBNO(tbdf)) 11697dd7cddfSDavid du Colombier type = 0x01; 11707dd7cddfSDavid du Colombier else 11717dd7cddfSDavid du Colombier type = 0x00; 11727dd7cddfSDavid du Colombier x = -1; 11737dd7cddfSDavid du Colombier if(BUSDNO(tbdf) > pcimaxdno) 11747dd7cddfSDavid du Colombier return x; 11757dd7cddfSDavid du Colombier 11767dd7cddfSDavid du Colombier lock(&pcicfglock); 11777dd7cddfSDavid du Colombier switch(pcicfgmode){ 11787dd7cddfSDavid du Colombier 11797dd7cddfSDavid du Colombier case 1: 11807dd7cddfSDavid du Colombier rno &= ~0x03; 11817dd7cddfSDavid du Colombier outl(PciADDR, 0x80000000|BUSBDF(tbdf)|rno|type); 11827dd7cddfSDavid du Colombier if(read) 11837dd7cddfSDavid du Colombier x = inl(PciDATA); 11847dd7cddfSDavid du Colombier else 11857dd7cddfSDavid du Colombier outl(PciDATA, data); 11867dd7cddfSDavid du Colombier outl(PciADDR, 0); 11877dd7cddfSDavid du Colombier break; 11887dd7cddfSDavid du Colombier 11897dd7cddfSDavid du Colombier case 2: 11907dd7cddfSDavid du Colombier outb(PciCSE, 0x80|(BUSFNO(tbdf)<<1)); 11917dd7cddfSDavid du Colombier outb(PciFORWARD, BUSBNO(tbdf)); 11927dd7cddfSDavid du Colombier if(read) 11937dd7cddfSDavid du Colombier x = inl((0xC000|(BUSDNO(tbdf)<<8)) + rno); 11947dd7cddfSDavid du Colombier else 11957dd7cddfSDavid du Colombier outl((0xC000|(BUSDNO(tbdf)<<8)) + rno, data); 11967dd7cddfSDavid du Colombier outb(PciCSE, 0); 11977dd7cddfSDavid du Colombier break; 11987dd7cddfSDavid du Colombier } 11997dd7cddfSDavid du Colombier unlock(&pcicfglock); 12007dd7cddfSDavid du Colombier 12017dd7cddfSDavid du Colombier return x; 12027dd7cddfSDavid du Colombier } 12037dd7cddfSDavid du Colombier 12047dd7cddfSDavid du Colombier int 12057dd7cddfSDavid du Colombier pcicfgr32(Pcidev* pcidev, int rno) 12067dd7cddfSDavid du Colombier { 12077dd7cddfSDavid du Colombier return pcicfgrw32(pcidev->tbdf, rno, 0, 1); 12087dd7cddfSDavid du Colombier } 12097dd7cddfSDavid du Colombier 12107dd7cddfSDavid du Colombier void 12117dd7cddfSDavid du Colombier pcicfgw32(Pcidev* pcidev, int rno, int data) 12127dd7cddfSDavid du Colombier { 12137dd7cddfSDavid du Colombier pcicfgrw32(pcidev->tbdf, rno, data, 0); 12147dd7cddfSDavid du Colombier } 12157dd7cddfSDavid du Colombier 12167dd7cddfSDavid du Colombier Pcidev* 12177dd7cddfSDavid du Colombier pcimatch(Pcidev* prev, int vid, int did) 12187dd7cddfSDavid du Colombier { 12197dd7cddfSDavid du Colombier if(pcicfgmode == -1) 12207dd7cddfSDavid du Colombier pcicfginit(); 12217dd7cddfSDavid du Colombier 12227dd7cddfSDavid du Colombier if(prev == nil) 12237dd7cddfSDavid du Colombier prev = pcilist; 12247dd7cddfSDavid du Colombier else 12257dd7cddfSDavid du Colombier prev = prev->list; 12267dd7cddfSDavid du Colombier 12277dd7cddfSDavid du Colombier while(prev != nil){ 12287dd7cddfSDavid du Colombier if((vid == 0 || prev->vid == vid) 12297dd7cddfSDavid du Colombier && (did == 0 || prev->did == did)) 12307dd7cddfSDavid du Colombier break; 12317dd7cddfSDavid du Colombier prev = prev->list; 12327dd7cddfSDavid du Colombier } 12337dd7cddfSDavid du Colombier return prev; 12347dd7cddfSDavid du Colombier } 12357dd7cddfSDavid du Colombier 12367dd7cddfSDavid du Colombier Pcidev* 12377dd7cddfSDavid du Colombier pcimatchtbdf(int tbdf) 12387dd7cddfSDavid du Colombier { 12397dd7cddfSDavid du Colombier Pcidev *pcidev; 12407dd7cddfSDavid du Colombier 12417dd7cddfSDavid du Colombier if(pcicfgmode == -1) 12427dd7cddfSDavid du Colombier pcicfginit(); 12437dd7cddfSDavid du Colombier 12447dd7cddfSDavid du Colombier for(pcidev = pcilist; pcidev != nil; pcidev = pcidev->list) { 12457dd7cddfSDavid du Colombier if(pcidev->tbdf == tbdf) 12467dd7cddfSDavid du Colombier break; 12477dd7cddfSDavid du Colombier } 12487dd7cddfSDavid du Colombier return pcidev; 12497dd7cddfSDavid du Colombier } 12507dd7cddfSDavid du Colombier 12519a747e4fSDavid du Colombier uchar 12529a747e4fSDavid du Colombier pciipin(Pcidev *pci, uchar pin) 12539a747e4fSDavid du Colombier { 12549a747e4fSDavid du Colombier if (pci == nil) 12559a747e4fSDavid du Colombier pci = pcilist; 12569a747e4fSDavid du Colombier 12579a747e4fSDavid du Colombier while (pci) { 12589a747e4fSDavid du Colombier uchar intl; 12599a747e4fSDavid du Colombier 12609a747e4fSDavid du Colombier if (pcicfgr8(pci, PciINTP) == pin && pci->intl != 0 && pci->intl != 0xff) 12619a747e4fSDavid du Colombier return pci->intl; 12629a747e4fSDavid du Colombier 12639a747e4fSDavid du Colombier if (pci->bridge && (intl = pciipin(pci->bridge, pin)) != 0) 12649a747e4fSDavid du Colombier return intl; 12659a747e4fSDavid du Colombier 12669a747e4fSDavid du Colombier pci = pci->list; 12679a747e4fSDavid du Colombier } 12689a747e4fSDavid du Colombier return 0; 12699a747e4fSDavid du Colombier } 12709a747e4fSDavid du Colombier 12719a747e4fSDavid du Colombier static void 12729a747e4fSDavid du Colombier pcilhinv(Pcidev* p) 12737dd7cddfSDavid du Colombier { 12747dd7cddfSDavid du Colombier int i; 12757dd7cddfSDavid du Colombier Pcidev *t; 12767dd7cddfSDavid du Colombier 12777dd7cddfSDavid du Colombier if(p == nil) { 12787dd7cddfSDavid du Colombier putstrn(PCICONS.output, PCICONS.ptr); 12797dd7cddfSDavid du Colombier p = pciroot; 12807dd7cddfSDavid du Colombier print("bus dev type vid did intl memory\n"); 12817dd7cddfSDavid du Colombier } 12827dd7cddfSDavid du Colombier for(t = p; t != nil; t = t->link) { 12837dd7cddfSDavid du Colombier print("%d %2d/%d %.2ux %.2ux %.2ux %.4ux %.4ux %3d ", 12847dd7cddfSDavid du Colombier BUSBNO(t->tbdf), BUSDNO(t->tbdf), BUSFNO(t->tbdf), 12857dd7cddfSDavid du Colombier t->ccrb, t->ccru, t->ccrp, t->vid, t->did, t->intl); 12867dd7cddfSDavid du Colombier 12877dd7cddfSDavid du Colombier for(i = 0; i < nelem(p->mem); i++) { 12887dd7cddfSDavid du Colombier if(t->mem[i].size == 0) 12897dd7cddfSDavid du Colombier continue; 12907dd7cddfSDavid du Colombier print("%d:%.8lux %d ", i, 12917dd7cddfSDavid du Colombier t->mem[i].bar, t->mem[i].size); 12927dd7cddfSDavid du Colombier } 12937dd7cddfSDavid du Colombier if(t->ioa.bar || t->ioa.size) 12947dd7cddfSDavid du Colombier print("ioa:%.8lux %d ", t->ioa.bar, t->ioa.size); 12957dd7cddfSDavid du Colombier if(t->mema.bar || t->mema.size) 12967dd7cddfSDavid du Colombier print("mema:%.8lux %d ", t->mema.bar, t->mema.size); 12977dd7cddfSDavid du Colombier if(t->bridge) 12987dd7cddfSDavid du Colombier print("->%d", BUSBNO(t->bridge->tbdf)); 12997dd7cddfSDavid du Colombier print("\n"); 13007dd7cddfSDavid du Colombier } 13017dd7cddfSDavid du Colombier while(p != nil) { 13027dd7cddfSDavid du Colombier if(p->bridge != nil) 13039a747e4fSDavid du Colombier pcilhinv(p->bridge); 13047dd7cddfSDavid du Colombier p = p->link; 13057dd7cddfSDavid du Colombier } 13067dd7cddfSDavid du Colombier } 13077dd7cddfSDavid du Colombier 13087dd7cddfSDavid du Colombier void 13099a747e4fSDavid du Colombier pcihinv(Pcidev* p) 13109a747e4fSDavid du Colombier { 13119a747e4fSDavid du Colombier if(pcicfgmode == -1) 13129a747e4fSDavid du Colombier pcicfginit(); 13139a747e4fSDavid du Colombier lock(&pcicfginitlock); 13149a747e4fSDavid du Colombier pcilhinv(p); 13159a747e4fSDavid du Colombier unlock(&pcicfginitlock); 13169a747e4fSDavid du Colombier } 13179a747e4fSDavid du Colombier 13189a747e4fSDavid du Colombier void 13197dd7cddfSDavid du Colombier pcireset(void) 13207dd7cddfSDavid du Colombier { 13217dd7cddfSDavid du Colombier Pcidev *p; 13227dd7cddfSDavid du Colombier 13237dd7cddfSDavid du Colombier if(pcicfgmode == -1) 13247dd7cddfSDavid du Colombier pcicfginit(); 13257dd7cddfSDavid du Colombier 13267dd7cddfSDavid du Colombier for(p = pcilist; p != nil; p = p->list) { 13279a747e4fSDavid du Colombier /* don't mess with the bridges */ 13289a747e4fSDavid du Colombier if(p->ccrb == 0x06) 13299a747e4fSDavid du Colombier continue; 13309a747e4fSDavid du Colombier pciclrbme(p); 13317dd7cddfSDavid du Colombier } 13327dd7cddfSDavid du Colombier } 13337dd7cddfSDavid du Colombier 13347dd7cddfSDavid du Colombier void 1335220e960cSDavid du Colombier pcisetioe(Pcidev* p) 1336220e960cSDavid du Colombier { 1337e569ccb5SDavid du Colombier p->pcr |= IOen; 1338e569ccb5SDavid du Colombier pcicfgw16(p, PciPCR, p->pcr); 1339220e960cSDavid du Colombier } 1340220e960cSDavid du Colombier 1341220e960cSDavid du Colombier void 1342220e960cSDavid du Colombier pciclrioe(Pcidev* p) 1343220e960cSDavid du Colombier { 1344e569ccb5SDavid du Colombier p->pcr &= ~IOen; 1345e569ccb5SDavid du Colombier pcicfgw16(p, PciPCR, p->pcr); 1346220e960cSDavid du Colombier } 1347220e960cSDavid du Colombier 1348220e960cSDavid du Colombier void 13497dd7cddfSDavid du Colombier pcisetbme(Pcidev* p) 13507dd7cddfSDavid du Colombier { 1351e569ccb5SDavid du Colombier p->pcr |= MASen; 1352e569ccb5SDavid du Colombier pcicfgw16(p, PciPCR, p->pcr); 13537dd7cddfSDavid du Colombier } 13549a747e4fSDavid du Colombier 13559a747e4fSDavid du Colombier void 13569a747e4fSDavid du Colombier pciclrbme(Pcidev* p) 13579a747e4fSDavid du Colombier { 1358e569ccb5SDavid du Colombier p->pcr &= ~MASen; 1359e569ccb5SDavid du Colombier pcicfgw16(p, PciPCR, p->pcr); 1360e569ccb5SDavid du Colombier } 13619a747e4fSDavid du Colombier 1362d8f3f65eSDavid du Colombier void 1363d8f3f65eSDavid du Colombier pcisetmwi(Pcidev* p) 1364d8f3f65eSDavid du Colombier { 1365d8f3f65eSDavid du Colombier p->pcr |= MemWrInv; 1366d8f3f65eSDavid du Colombier pcicfgw16(p, PciPCR, p->pcr); 1367d8f3f65eSDavid du Colombier } 1368d8f3f65eSDavid du Colombier 1369d8f3f65eSDavid du Colombier void 1370d8f3f65eSDavid du Colombier pciclrmwi(Pcidev* p) 1371d8f3f65eSDavid du Colombier { 1372d8f3f65eSDavid du Colombier p->pcr &= ~MemWrInv; 1373d8f3f65eSDavid du Colombier pcicfgw16(p, PciPCR, p->pcr); 1374d8f3f65eSDavid du Colombier } 1375d8f3f65eSDavid du Colombier 1376e569ccb5SDavid du Colombier static int 1377e569ccb5SDavid du Colombier pcigetpmrb(Pcidev* p) 1378e569ccb5SDavid du Colombier { 1379e569ccb5SDavid du Colombier int ptr; 1380e569ccb5SDavid du Colombier 1381e569ccb5SDavid du Colombier if(p->pmrb != 0) 1382e569ccb5SDavid du Colombier return p->pmrb; 1383e569ccb5SDavid du Colombier p->pmrb = -1; 1384e569ccb5SDavid du Colombier 1385e569ccb5SDavid du Colombier /* 1386e569ccb5SDavid du Colombier * If there are no extended capabilities implemented, 1387e569ccb5SDavid du Colombier * (bit 4 in the status register) assume there's no standard 1388e569ccb5SDavid du Colombier * power management method. 1389e569ccb5SDavid du Colombier * Find the capabilities pointer based on PCI header type. 1390e569ccb5SDavid du Colombier */ 13915979f962SDavid du Colombier if(!(pcicfgr16(p, PciPSR) & 0x0010)) 1392e569ccb5SDavid du Colombier return -1; 1393e569ccb5SDavid du Colombier switch(pcicfgr8(p, PciHDT)){ 1394e569ccb5SDavid du Colombier default: 1395e569ccb5SDavid du Colombier return -1; 1396e569ccb5SDavid du Colombier case 0: /* all other */ 1397e569ccb5SDavid du Colombier case 1: /* PCI to PCI bridge */ 1398e569ccb5SDavid du Colombier ptr = 0x34; 1399e569ccb5SDavid du Colombier break; 1400e569ccb5SDavid du Colombier case 2: /* CardBus bridge */ 1401e569ccb5SDavid du Colombier ptr = 0x14; 1402e569ccb5SDavid du Colombier break; 1403e569ccb5SDavid du Colombier } 1404e569ccb5SDavid du Colombier ptr = pcicfgr32(p, ptr); 1405e569ccb5SDavid du Colombier 1406e569ccb5SDavid du Colombier while(ptr != 0){ 1407e569ccb5SDavid du Colombier /* 1408e569ccb5SDavid du Colombier * Check for validity. 1409e569ccb5SDavid du Colombier * Can't be in standard header and must be double 1410e569ccb5SDavid du Colombier * word aligned. 1411e569ccb5SDavid du Colombier */ 1412e569ccb5SDavid du Colombier if(ptr < 0x40 || (ptr & ~0xFC)) 1413e569ccb5SDavid du Colombier return -1; 1414e569ccb5SDavid du Colombier if(pcicfgr8(p, ptr) == 0x01){ 1415e569ccb5SDavid du Colombier p->pmrb = ptr; 1416e569ccb5SDavid du Colombier return ptr; 1417e569ccb5SDavid du Colombier } 1418e569ccb5SDavid du Colombier 1419e569ccb5SDavid du Colombier ptr = pcicfgr8(p, ptr+1); 1420e569ccb5SDavid du Colombier } 1421e569ccb5SDavid du Colombier 1422e569ccb5SDavid du Colombier return -1; 1423e569ccb5SDavid du Colombier } 1424e569ccb5SDavid du Colombier 1425e569ccb5SDavid du Colombier int 1426e569ccb5SDavid du Colombier pcigetpms(Pcidev* p) 1427e569ccb5SDavid du Colombier { 1428e569ccb5SDavid du Colombier int pmcsr, ptr; 1429e569ccb5SDavid du Colombier 1430e569ccb5SDavid du Colombier if((ptr = pcigetpmrb(p)) == -1) 1431e569ccb5SDavid du Colombier return -1; 1432e569ccb5SDavid du Colombier 1433e569ccb5SDavid du Colombier /* 1434e569ccb5SDavid du Colombier * Power Management Register Block: 1435e569ccb5SDavid du Colombier * offset 0: Capability ID 1436e569ccb5SDavid du Colombier * 1: next item pointer 1437e569ccb5SDavid du Colombier * 2: capabilities 1438e569ccb5SDavid du Colombier * 4: control/status 1439e569ccb5SDavid du Colombier * 6: bridge support extensions 1440e569ccb5SDavid du Colombier * 7: data 1441e569ccb5SDavid du Colombier */ 1442e569ccb5SDavid du Colombier pmcsr = pcicfgr16(p, ptr+4); 1443e569ccb5SDavid du Colombier 1444e569ccb5SDavid du Colombier return pmcsr & 0x0003; 1445e569ccb5SDavid du Colombier } 1446e569ccb5SDavid du Colombier 1447e569ccb5SDavid du Colombier int 1448e569ccb5SDavid du Colombier pcisetpms(Pcidev* p, int state) 1449e569ccb5SDavid du Colombier { 1450e569ccb5SDavid du Colombier int ostate, pmc, pmcsr, ptr; 1451e569ccb5SDavid du Colombier 1452e569ccb5SDavid du Colombier if((ptr = pcigetpmrb(p)) == -1) 1453e569ccb5SDavid du Colombier return -1; 1454e569ccb5SDavid du Colombier 1455e569ccb5SDavid du Colombier pmc = pcicfgr16(p, ptr+2); 1456e569ccb5SDavid du Colombier pmcsr = pcicfgr16(p, ptr+4); 1457e569ccb5SDavid du Colombier ostate = pmcsr & 0x0003; 1458e569ccb5SDavid du Colombier pmcsr &= ~0x0003; 1459e569ccb5SDavid du Colombier 1460e569ccb5SDavid du Colombier switch(state){ 1461e569ccb5SDavid du Colombier default: 1462e569ccb5SDavid du Colombier return -1; 1463e569ccb5SDavid du Colombier case 0: 1464e569ccb5SDavid du Colombier break; 1465e569ccb5SDavid du Colombier case 1: 1466e569ccb5SDavid du Colombier if(!(pmc & 0x0200)) 1467e569ccb5SDavid du Colombier return -1; 1468e569ccb5SDavid du Colombier break; 1469e569ccb5SDavid du Colombier case 2: 1470e569ccb5SDavid du Colombier if(!(pmc & 0x0400)) 1471e569ccb5SDavid du Colombier return -1; 1472e569ccb5SDavid du Colombier break; 1473e569ccb5SDavid du Colombier case 3: 1474e569ccb5SDavid du Colombier break; 1475e569ccb5SDavid du Colombier } 1476e569ccb5SDavid du Colombier pmcsr |= state; 1477e569ccb5SDavid du Colombier pcicfgw16(p, ptr+4, pmcsr); 1478e569ccb5SDavid du Colombier 1479e569ccb5SDavid du Colombier return ostate; 14809a747e4fSDavid du Colombier } 1481