19ef1f84bSDavid du Colombier /*
29ef1f84bSDavid du Colombier * PCI support code.
39ef1f84bSDavid du Colombier * Needs a massive rewrite.
49ef1f84bSDavid du Colombier */
59ef1f84bSDavid du Colombier #include "u.h"
69ef1f84bSDavid du Colombier #include "../port/lib.h"
79ef1f84bSDavid du Colombier #include "mem.h"
89ef1f84bSDavid du Colombier #include "dat.h"
99ef1f84bSDavid du Colombier #include "fns.h"
109ef1f84bSDavid du Colombier
119ef1f84bSDavid du Colombier #include "io.h"
129ef1f84bSDavid du Colombier
139ef1f84bSDavid du Colombier struct
149ef1f84bSDavid du Colombier {
159ef1f84bSDavid du Colombier char output[16384];
169ef1f84bSDavid du Colombier int ptr;
179ef1f84bSDavid du Colombier }PCICONS;
189ef1f84bSDavid du Colombier
19277b6efdSDavid du Colombier int pcivga;
20277b6efdSDavid du Colombier
219ef1f84bSDavid du Colombier int
pcilog(char * fmt,...)229ef1f84bSDavid du Colombier pcilog(char *fmt, ...)
239ef1f84bSDavid du Colombier {
249ef1f84bSDavid du Colombier int n;
259ef1f84bSDavid du Colombier va_list arg;
269ef1f84bSDavid du Colombier char buf[PRINTSIZE];
279ef1f84bSDavid du Colombier
289ef1f84bSDavid du Colombier va_start(arg, fmt);
299ef1f84bSDavid du Colombier n = vseprint(buf, buf+sizeof(buf), fmt, arg) - buf;
309ef1f84bSDavid du Colombier va_end(arg);
319ef1f84bSDavid du Colombier
329ef1f84bSDavid du Colombier memmove(PCICONS.output+PCICONS.ptr, buf, n);
339ef1f84bSDavid du Colombier PCICONS.ptr += n;
349ef1f84bSDavid du Colombier return n;
359ef1f84bSDavid du Colombier }
369ef1f84bSDavid du Colombier
379ef1f84bSDavid du Colombier enum
389ef1f84bSDavid du Colombier { /* configuration mechanism #1 */
399ef1f84bSDavid du Colombier PciADDR = 0xCF8, /* CONFIG_ADDRESS */
409ef1f84bSDavid du Colombier PciDATA = 0xCFC, /* CONFIG_DATA */
419ef1f84bSDavid du Colombier
429ef1f84bSDavid du Colombier /* configuration mechanism #2 */
439ef1f84bSDavid du Colombier PciCSE = 0xCF8, /* configuration space enable */
449ef1f84bSDavid du Colombier PciFORWARD = 0xCFA, /* which bus */
459ef1f84bSDavid du Colombier
469ef1f84bSDavid du Colombier MaxFNO = 7,
479ef1f84bSDavid du Colombier MaxUBN = 255,
489ef1f84bSDavid du Colombier };
499ef1f84bSDavid du Colombier
509ef1f84bSDavid du Colombier enum
519ef1f84bSDavid du Colombier { /* command register */
529ef1f84bSDavid du Colombier IOen = (1<<0),
539ef1f84bSDavid du Colombier MEMen = (1<<1),
549ef1f84bSDavid du Colombier MASen = (1<<2),
559ef1f84bSDavid du Colombier MemWrInv = (1<<4),
569ef1f84bSDavid du Colombier PErrEn = (1<<6),
579ef1f84bSDavid du Colombier SErrEn = (1<<8),
589ef1f84bSDavid du Colombier };
599ef1f84bSDavid du Colombier
609ef1f84bSDavid du Colombier static Lock pcicfglock;
619ef1f84bSDavid du Colombier static Lock pcicfginitlock;
629ef1f84bSDavid du Colombier static int pcicfgmode = -1;
639ef1f84bSDavid du Colombier static int pcimaxbno = 7;
649ef1f84bSDavid du Colombier static int pcimaxdno;
659ef1f84bSDavid du Colombier static Pcidev* pciroot;
669ef1f84bSDavid du Colombier static Pcidev* pcilist;
679ef1f84bSDavid du Colombier static Pcidev* pcitail;
689ef1f84bSDavid du Colombier static int nobios, nopcirouting;
699ef1f84bSDavid du Colombier
709ef1f84bSDavid du Colombier static int pcicfgrw32(int, int, int, int);
719ef1f84bSDavid du Colombier static int pcicfgrw16(int, int, int, int);
729ef1f84bSDavid du Colombier static int pcicfgrw8(int, int, int, int);
739ef1f84bSDavid du Colombier
749ef1f84bSDavid du Colombier static char* bustypes[] = {
759ef1f84bSDavid du Colombier "CBUSI",
769ef1f84bSDavid du Colombier "CBUSII",
779ef1f84bSDavid du Colombier "EISA",
789ef1f84bSDavid du Colombier "FUTURE",
799ef1f84bSDavid du Colombier "INTERN",
809ef1f84bSDavid du Colombier "ISA",
819ef1f84bSDavid du Colombier "MBI",
829ef1f84bSDavid du Colombier "MBII",
839ef1f84bSDavid du Colombier "MCA",
849ef1f84bSDavid du Colombier "MPI",
859ef1f84bSDavid du Colombier "MPSA",
869ef1f84bSDavid du Colombier "NUBUS",
879ef1f84bSDavid du Colombier "PCI",
889ef1f84bSDavid du Colombier "PCMCIA",
899ef1f84bSDavid du Colombier "TC",
909ef1f84bSDavid du Colombier "VL",
919ef1f84bSDavid du Colombier "VME",
929ef1f84bSDavid du Colombier "XPRESS",
939ef1f84bSDavid du Colombier };
949ef1f84bSDavid du Colombier
959ef1f84bSDavid du Colombier #pragma varargck type "T" int
969ef1f84bSDavid du Colombier
979ef1f84bSDavid du Colombier static int
tbdffmt(Fmt * fmt)989ef1f84bSDavid du Colombier tbdffmt(Fmt* fmt)
999ef1f84bSDavid du Colombier {
1009ef1f84bSDavid du Colombier char *p;
1019ef1f84bSDavid du Colombier int l, r, type, tbdf;
1029ef1f84bSDavid du Colombier
1039ef1f84bSDavid du Colombier if((p = malloc(READSTR)) == nil)
1049ef1f84bSDavid du Colombier return fmtstrcpy(fmt, "(tbdfconv)");
1059ef1f84bSDavid du Colombier
1069ef1f84bSDavid du Colombier switch(fmt->r){
1079ef1f84bSDavid du Colombier case 'T':
1089ef1f84bSDavid du Colombier tbdf = va_arg(fmt->args, int);
1099ef1f84bSDavid du Colombier type = BUSTYPE(tbdf);
1109ef1f84bSDavid du Colombier if(type < nelem(bustypes))
1119ef1f84bSDavid du Colombier l = snprint(p, READSTR, bustypes[type]);
1129ef1f84bSDavid du Colombier else
1139ef1f84bSDavid du Colombier l = snprint(p, READSTR, "%d", type);
1149ef1f84bSDavid du Colombier snprint(p+l, READSTR-l, ".%d.%d.%d",
1159ef1f84bSDavid du Colombier BUSBNO(tbdf), BUSDNO(tbdf), BUSFNO(tbdf));
1169ef1f84bSDavid du Colombier break;
1179ef1f84bSDavid du Colombier
1189ef1f84bSDavid du Colombier default:
1199ef1f84bSDavid du Colombier snprint(p, READSTR, "(tbdfconv)");
1209ef1f84bSDavid du Colombier break;
1219ef1f84bSDavid du Colombier }
1229ef1f84bSDavid du Colombier r = fmtstrcpy(fmt, p);
1239ef1f84bSDavid du Colombier free(p);
1249ef1f84bSDavid du Colombier
1259ef1f84bSDavid du Colombier return r;
1269ef1f84bSDavid du Colombier }
1279ef1f84bSDavid du Colombier
1289ef1f84bSDavid du Colombier ulong
pcibarsize(Pcidev * p,int rno)1299ef1f84bSDavid du Colombier pcibarsize(Pcidev *p, int rno)
1309ef1f84bSDavid du Colombier {
1319ef1f84bSDavid du Colombier ulong v, size;
1329ef1f84bSDavid du Colombier
1339ef1f84bSDavid du Colombier v = pcicfgrw32(p->tbdf, rno, 0, 1);
1349ef1f84bSDavid du Colombier pcicfgrw32(p->tbdf, rno, 0xFFFFFFF0, 0);
1359ef1f84bSDavid du Colombier size = pcicfgrw32(p->tbdf, rno, 0, 1);
1369ef1f84bSDavid du Colombier if(v & 1)
1379ef1f84bSDavid du Colombier size |= 0xFFFF0000;
1389ef1f84bSDavid du Colombier pcicfgrw32(p->tbdf, rno, v, 0);
1399ef1f84bSDavid du Colombier
1409ef1f84bSDavid du Colombier return -(size & ~0x0F);
1419ef1f84bSDavid du Colombier }
1429ef1f84bSDavid du Colombier
1439ef1f84bSDavid du Colombier static int
pcisizcmp(void * a,void * b)1449ef1f84bSDavid du Colombier pcisizcmp(void *a, void *b)
1459ef1f84bSDavid du Colombier {
1469ef1f84bSDavid du Colombier Pcisiz *aa, *bb;
1479ef1f84bSDavid du Colombier
1489ef1f84bSDavid du Colombier aa = a;
1499ef1f84bSDavid du Colombier bb = b;
1509ef1f84bSDavid du Colombier return aa->siz - bb->siz;
1519ef1f84bSDavid du Colombier }
1529ef1f84bSDavid du Colombier
1539ef1f84bSDavid du Colombier static ulong
pcimask(ulong v)1549ef1f84bSDavid du Colombier pcimask(ulong v)
1559ef1f84bSDavid du Colombier {
1569ef1f84bSDavid du Colombier ulong mask;
1579ef1f84bSDavid du Colombier
1589ef1f84bSDavid du Colombier mask = BI2BY*sizeof(v);
1599ef1f84bSDavid du Colombier for(mask = 1<<(mask-1); mask != 0; mask >>= 1) {
1609ef1f84bSDavid du Colombier if(mask & v)
1619ef1f84bSDavid du Colombier break;
1629ef1f84bSDavid du Colombier }
1639ef1f84bSDavid du Colombier
1649ef1f84bSDavid du Colombier mask--;
1659ef1f84bSDavid du Colombier if((v & mask) == 0)
1669ef1f84bSDavid du Colombier return v;
1679ef1f84bSDavid du Colombier
1689ef1f84bSDavid du Colombier v |= mask;
1699ef1f84bSDavid du Colombier return v+1;
1709ef1f84bSDavid du Colombier }
1719ef1f84bSDavid du Colombier
1729ef1f84bSDavid du Colombier static void
pcibusmap(Pcidev * root,ulong * pmema,ulong * pioa,int wrreg)1739ef1f84bSDavid du Colombier pcibusmap(Pcidev *root, ulong *pmema, ulong *pioa, int wrreg)
1749ef1f84bSDavid du Colombier {
1759ef1f84bSDavid du Colombier Pcidev *p;
1769ef1f84bSDavid du Colombier int ntb, i, size, rno, hole;
1779ef1f84bSDavid du Colombier ulong v, mema, ioa, sioa, smema, base, limit;
1789ef1f84bSDavid du Colombier Pcisiz *table, *tptr, *mtb, *itb;
1799ef1f84bSDavid du Colombier extern void qsort(void*, long, long, int (*)(void*, void*));
1809ef1f84bSDavid du Colombier
1819ef1f84bSDavid du Colombier if(!nobios)
1829ef1f84bSDavid du Colombier return;
1839ef1f84bSDavid du Colombier
1849ef1f84bSDavid du Colombier ioa = *pioa;
1859ef1f84bSDavid du Colombier mema = *pmema;
1869ef1f84bSDavid du Colombier
1879ef1f84bSDavid du Colombier DBG("pcibusmap wr=%d %T mem=%#lux io=%#lux\n",
1889ef1f84bSDavid du Colombier wrreg, root->tbdf, mema, ioa);
1899ef1f84bSDavid du Colombier
1909ef1f84bSDavid du Colombier ntb = 0;
1919ef1f84bSDavid du Colombier for(p = root; p != nil; p = p->link)
1929ef1f84bSDavid du Colombier ntb++;
1939ef1f84bSDavid du Colombier
1949ef1f84bSDavid du Colombier ntb *= (PciCIS-PciBAR0)/4;
1959ef1f84bSDavid du Colombier table = malloc(2*ntb*sizeof(Pcisiz));
196277b6efdSDavid du Colombier if(table == nil)
197277b6efdSDavid du Colombier panic("pcibusmap: no memory");
1989ef1f84bSDavid du Colombier itb = table;
1999ef1f84bSDavid du Colombier mtb = table+ntb;
2009ef1f84bSDavid du Colombier
2019ef1f84bSDavid du Colombier /*
2029ef1f84bSDavid du Colombier * Build a table of sizes
2039ef1f84bSDavid du Colombier */
2049ef1f84bSDavid du Colombier for(p = root; p != nil; p = p->link) {
2059ef1f84bSDavid du Colombier if(p->ccrb == 0x06) {
2069ef1f84bSDavid du Colombier if(p->ccru != 0x04 || p->bridge == nil) {
2079ef1f84bSDavid du Colombier // DBG("pci: ignored bridge %T\n", p->tbdf);
2089ef1f84bSDavid du Colombier continue;
2099ef1f84bSDavid du Colombier }
2109ef1f84bSDavid du Colombier
2119ef1f84bSDavid du Colombier sioa = ioa;
2129ef1f84bSDavid du Colombier smema = mema;
2139ef1f84bSDavid du Colombier pcibusmap(p->bridge, &smema, &sioa, 0);
2149ef1f84bSDavid du Colombier
2159ef1f84bSDavid du Colombier hole = pcimask(smema-mema);
2169ef1f84bSDavid du Colombier if(hole < (1<<20))
2179ef1f84bSDavid du Colombier hole = 1<<20;
2189ef1f84bSDavid du Colombier p->mema.size = hole;
2199ef1f84bSDavid du Colombier
2209ef1f84bSDavid du Colombier hole = pcimask(sioa-ioa);
2219ef1f84bSDavid du Colombier if(hole < (1<<12))
2229ef1f84bSDavid du Colombier hole = 1<<12;
2239ef1f84bSDavid du Colombier
2249ef1f84bSDavid du Colombier p->ioa.size = hole;
2259ef1f84bSDavid du Colombier
2269ef1f84bSDavid du Colombier itb->dev = p;
2279ef1f84bSDavid du Colombier itb->bar = -1;
2289ef1f84bSDavid du Colombier itb->siz = p->ioa.size;
2299ef1f84bSDavid du Colombier itb++;
2309ef1f84bSDavid du Colombier
2319ef1f84bSDavid du Colombier mtb->dev = p;
2329ef1f84bSDavid du Colombier mtb->bar = -1;
2339ef1f84bSDavid du Colombier mtb->siz = p->mema.size;
2349ef1f84bSDavid du Colombier mtb++;
2359ef1f84bSDavid du Colombier continue;
2369ef1f84bSDavid du Colombier }
2379ef1f84bSDavid du Colombier
2389ef1f84bSDavid du Colombier for(i = 0; i <= 5; i++) {
2399ef1f84bSDavid du Colombier rno = PciBAR0 + i*4;
2409ef1f84bSDavid du Colombier v = pcicfgrw32(p->tbdf, rno, 0, 1);
2419ef1f84bSDavid du Colombier size = pcibarsize(p, rno);
2429ef1f84bSDavid du Colombier if(size == 0)
2439ef1f84bSDavid du Colombier continue;
2449ef1f84bSDavid du Colombier
2459ef1f84bSDavid du Colombier if(v & 1) {
2469ef1f84bSDavid du Colombier itb->dev = p;
2479ef1f84bSDavid du Colombier itb->bar = i;
2489ef1f84bSDavid du Colombier itb->siz = size;
2499ef1f84bSDavid du Colombier itb++;
2509ef1f84bSDavid du Colombier }
2519ef1f84bSDavid du Colombier else {
2529ef1f84bSDavid du Colombier mtb->dev = p;
2539ef1f84bSDavid du Colombier mtb->bar = i;
2549ef1f84bSDavid du Colombier mtb->siz = size;
2559ef1f84bSDavid du Colombier mtb++;
2569ef1f84bSDavid du Colombier }
2579ef1f84bSDavid du Colombier
2589ef1f84bSDavid du Colombier p->mem[i].size = size;
2599ef1f84bSDavid du Colombier }
2609ef1f84bSDavid du Colombier }
2619ef1f84bSDavid du Colombier
2629ef1f84bSDavid du Colombier /*
2639ef1f84bSDavid du Colombier * Sort both tables IO smallest first, Memory largest
2649ef1f84bSDavid du Colombier */
2659ef1f84bSDavid du Colombier qsort(table, itb-table, sizeof(Pcisiz), pcisizcmp);
2669ef1f84bSDavid du Colombier tptr = table+ntb;
2679ef1f84bSDavid du Colombier qsort(tptr, mtb-tptr, sizeof(Pcisiz), pcisizcmp);
2689ef1f84bSDavid du Colombier
2699ef1f84bSDavid du Colombier /*
2709ef1f84bSDavid du Colombier * Allocate IO address space on this bus
2719ef1f84bSDavid du Colombier */
2729ef1f84bSDavid du Colombier for(tptr = table; tptr < itb; tptr++) {
2739ef1f84bSDavid du Colombier hole = tptr->siz;
2749ef1f84bSDavid du Colombier if(tptr->bar == -1)
2759ef1f84bSDavid du Colombier hole = 1<<12;
2769ef1f84bSDavid du Colombier ioa = (ioa+hole-1) & ~(hole-1);
2779ef1f84bSDavid du Colombier
2789ef1f84bSDavid du Colombier p = tptr->dev;
2799ef1f84bSDavid du Colombier if(tptr->bar == -1)
2809ef1f84bSDavid du Colombier p->ioa.bar = ioa;
2819ef1f84bSDavid du Colombier else {
2829ef1f84bSDavid du Colombier p->pcr |= IOen;
2839ef1f84bSDavid du Colombier p->mem[tptr->bar].bar = ioa|1;
2849ef1f84bSDavid du Colombier if(wrreg)
2859ef1f84bSDavid du Colombier pcicfgrw32(p->tbdf, PciBAR0+(tptr->bar*4), ioa|1, 0);
2869ef1f84bSDavid du Colombier }
2879ef1f84bSDavid du Colombier
2889ef1f84bSDavid du Colombier ioa += tptr->siz;
2899ef1f84bSDavid du Colombier }
2909ef1f84bSDavid du Colombier
2919ef1f84bSDavid du Colombier /*
2929ef1f84bSDavid du Colombier * Allocate Memory address space on this bus
2939ef1f84bSDavid du Colombier */
2949ef1f84bSDavid du Colombier for(tptr = table+ntb; tptr < mtb; tptr++) {
2959ef1f84bSDavid du Colombier hole = tptr->siz;
2969ef1f84bSDavid du Colombier if(tptr->bar == -1)
2979ef1f84bSDavid du Colombier hole = 1<<20;
2989ef1f84bSDavid du Colombier mema = (mema+hole-1) & ~(hole-1);
2999ef1f84bSDavid du Colombier
3009ef1f84bSDavid du Colombier p = tptr->dev;
3019ef1f84bSDavid du Colombier if(tptr->bar == -1)
3029ef1f84bSDavid du Colombier p->mema.bar = mema;
3039ef1f84bSDavid du Colombier else {
3049ef1f84bSDavid du Colombier p->pcr |= MEMen;
3059ef1f84bSDavid du Colombier p->mem[tptr->bar].bar = mema;
3069ef1f84bSDavid du Colombier if(wrreg)
3079ef1f84bSDavid du Colombier pcicfgrw32(p->tbdf, PciBAR0+(tptr->bar*4), mema, 0);
3089ef1f84bSDavid du Colombier }
3099ef1f84bSDavid du Colombier mema += tptr->siz;
3109ef1f84bSDavid du Colombier }
3119ef1f84bSDavid du Colombier
3129ef1f84bSDavid du Colombier *pmema = mema;
3139ef1f84bSDavid du Colombier *pioa = ioa;
3149ef1f84bSDavid du Colombier free(table);
3159ef1f84bSDavid du Colombier
3169ef1f84bSDavid du Colombier if(wrreg == 0)
3179ef1f84bSDavid du Colombier return;
3189ef1f84bSDavid du Colombier
3199ef1f84bSDavid du Colombier /*
3209ef1f84bSDavid du Colombier * Finally set all the bridge addresses & registers
3219ef1f84bSDavid du Colombier */
3229ef1f84bSDavid du Colombier for(p = root; p != nil; p = p->link) {
3239ef1f84bSDavid du Colombier if(p->bridge == nil) {
3249ef1f84bSDavid du Colombier pcicfgrw8(p->tbdf, PciLTR, 64, 0);
3259ef1f84bSDavid du Colombier
3269ef1f84bSDavid du Colombier p->pcr |= MASen;
3279ef1f84bSDavid du Colombier pcicfgrw16(p->tbdf, PciPCR, p->pcr, 0);
3289ef1f84bSDavid du Colombier continue;
3299ef1f84bSDavid du Colombier }
3309ef1f84bSDavid du Colombier
3319ef1f84bSDavid du Colombier base = p->ioa.bar;
3329ef1f84bSDavid du Colombier limit = base+p->ioa.size-1;
3339ef1f84bSDavid du Colombier v = pcicfgrw32(p->tbdf, PciIBR, 0, 1);
3349ef1f84bSDavid du Colombier v = (v&0xFFFF0000)|(limit & 0xF000)|((base & 0xF000)>>8);
3359ef1f84bSDavid du Colombier pcicfgrw32(p->tbdf, PciIBR, v, 0);
3369ef1f84bSDavid du Colombier v = (limit & 0xFFFF0000)|(base>>16);
3379ef1f84bSDavid du Colombier pcicfgrw32(p->tbdf, PciIUBR, v, 0);
3389ef1f84bSDavid du Colombier
3399ef1f84bSDavid du Colombier base = p->mema.bar;
3409ef1f84bSDavid du Colombier limit = base+p->mema.size-1;
3419ef1f84bSDavid du Colombier v = (limit & 0xFFF00000)|((base & 0xFFF00000)>>16);
3429ef1f84bSDavid du Colombier pcicfgrw32(p->tbdf, PciMBR, v, 0);
3439ef1f84bSDavid du Colombier
3449ef1f84bSDavid du Colombier /*
3459ef1f84bSDavid du Colombier * Disable memory prefetch
3469ef1f84bSDavid du Colombier */
3479ef1f84bSDavid du Colombier pcicfgrw32(p->tbdf, PciPMBR, 0x0000FFFF, 0);
3489ef1f84bSDavid du Colombier pcicfgrw8(p->tbdf, PciLTR, 64, 0);
3499ef1f84bSDavid du Colombier
3509ef1f84bSDavid du Colombier /*
3519ef1f84bSDavid du Colombier * Enable the bridge
3529ef1f84bSDavid du Colombier */
3539ef1f84bSDavid du Colombier p->pcr |= IOen|MEMen|MASen;
3549ef1f84bSDavid du Colombier pcicfgrw32(p->tbdf, PciPCR, 0xFFFF0000|p->pcr , 0);
3559ef1f84bSDavid du Colombier
3569ef1f84bSDavid du Colombier sioa = p->ioa.bar;
3579ef1f84bSDavid du Colombier smema = p->mema.bar;
3589ef1f84bSDavid du Colombier pcibusmap(p->bridge, &smema, &sioa, 1);
3599ef1f84bSDavid du Colombier }
3609ef1f84bSDavid du Colombier }
3619ef1f84bSDavid du Colombier
362277b6efdSDavid du Colombier /* side effect: if a video controller is seen, set pcivga non-zero */
3639ef1f84bSDavid du Colombier static int
pcilscan(int bno,Pcidev ** list)3649ef1f84bSDavid du Colombier pcilscan(int bno, Pcidev** list)
3659ef1f84bSDavid du Colombier {
3669ef1f84bSDavid du Colombier Pcidev *p, *head, *tail;
3679ef1f84bSDavid du Colombier int dno, fno, i, hdt, l, maxfno, maxubn, rno, sbn, tbdf, ubn;
3689ef1f84bSDavid du Colombier
3699ef1f84bSDavid du Colombier maxubn = bno;
3709ef1f84bSDavid du Colombier head = nil;
3719ef1f84bSDavid du Colombier tail = nil;
3729ef1f84bSDavid du Colombier for(dno = 0; dno <= pcimaxdno; dno++){
3739ef1f84bSDavid du Colombier maxfno = 0;
3749ef1f84bSDavid du Colombier for(fno = 0; fno <= maxfno; fno++){
3759ef1f84bSDavid du Colombier /*
3769ef1f84bSDavid du Colombier * For this possible device, form the
3779ef1f84bSDavid du Colombier * bus+device+function triplet needed to address it
3789ef1f84bSDavid du Colombier * and try to read the vendor and device ID.
3799ef1f84bSDavid du Colombier * If successful, allocate a device struct and
3809ef1f84bSDavid du Colombier * start to fill it in with some useful information
3819ef1f84bSDavid du Colombier * from the device's configuration space.
3829ef1f84bSDavid du Colombier */
3839ef1f84bSDavid du Colombier tbdf = MKBUS(BusPCI, bno, dno, fno);
3849ef1f84bSDavid du Colombier l = pcicfgrw32(tbdf, PciVID, 0, 1);
3859ef1f84bSDavid du Colombier if(l == 0xFFFFFFFF || l == 0)
3869ef1f84bSDavid du Colombier continue;
3879ef1f84bSDavid du Colombier p = malloc(sizeof(*p));
388277b6efdSDavid du Colombier if(p == nil)
389277b6efdSDavid du Colombier panic("pcilscan: no memory");
3909ef1f84bSDavid du Colombier p->tbdf = tbdf;
3919ef1f84bSDavid du Colombier p->vid = l;
3929ef1f84bSDavid du Colombier p->did = l>>16;
3939ef1f84bSDavid du Colombier
3949ef1f84bSDavid du Colombier if(pcilist != nil)
3959ef1f84bSDavid du Colombier pcitail->list = p;
3969ef1f84bSDavid du Colombier else
3979ef1f84bSDavid du Colombier pcilist = p;
3989ef1f84bSDavid du Colombier pcitail = p;
3999ef1f84bSDavid du Colombier
4009ef1f84bSDavid du Colombier p->pcr = pcicfgr16(p, PciPCR);
4019ef1f84bSDavid du Colombier p->rid = pcicfgr8(p, PciRID);
4029ef1f84bSDavid du Colombier p->ccrp = pcicfgr8(p, PciCCRp);
4039ef1f84bSDavid du Colombier p->ccru = pcicfgr8(p, PciCCRu);
4049ef1f84bSDavid du Colombier p->ccrb = pcicfgr8(p, PciCCRb);
4059ef1f84bSDavid du Colombier p->cls = pcicfgr8(p, PciCLS);
4069ef1f84bSDavid du Colombier p->ltr = pcicfgr8(p, PciLTR);
4079ef1f84bSDavid du Colombier
4089ef1f84bSDavid du Colombier p->intl = pcicfgr8(p, PciINTL);
4099ef1f84bSDavid du Colombier
4109ef1f84bSDavid du Colombier /*
4119ef1f84bSDavid du Colombier * If the device is a multi-function device adjust the
4129ef1f84bSDavid du Colombier * loop count so all possible functions are checked.
4139ef1f84bSDavid du Colombier */
4149ef1f84bSDavid du Colombier hdt = pcicfgr8(p, PciHDT);
4159ef1f84bSDavid du Colombier if(hdt & 0x80)
4169ef1f84bSDavid du Colombier maxfno = MaxFNO;
4179ef1f84bSDavid du Colombier
4189ef1f84bSDavid du Colombier /*
4199ef1f84bSDavid du Colombier * If appropriate, read the base address registers
4209ef1f84bSDavid du Colombier * and work out the sizes.
4219ef1f84bSDavid du Colombier */
4229ef1f84bSDavid du Colombier switch(p->ccrb) {
423277b6efdSDavid du Colombier case 0x03: /* display controller */
424277b6efdSDavid du Colombier pcivga = 1;
425277b6efdSDavid du Colombier /* fall through */
4269ef1f84bSDavid du Colombier case 0x01: /* mass storage controller */
4279ef1f84bSDavid du Colombier case 0x02: /* network controller */
4289ef1f84bSDavid du Colombier case 0x04: /* multimedia device */
4299ef1f84bSDavid du Colombier case 0x07: /* simple comm. controllers */
4309ef1f84bSDavid du Colombier case 0x08: /* base system peripherals */
4319ef1f84bSDavid du Colombier case 0x09: /* input devices */
4329ef1f84bSDavid du Colombier case 0x0A: /* docking stations */
4339ef1f84bSDavid du Colombier case 0x0B: /* processors */
4349ef1f84bSDavid du Colombier case 0x0C: /* serial bus controllers */
4359ef1f84bSDavid du Colombier if((hdt & 0x7F) != 0)
4369ef1f84bSDavid du Colombier break;
4379ef1f84bSDavid du Colombier rno = PciBAR0 - 4;
4389ef1f84bSDavid du Colombier for(i = 0; i < nelem(p->mem); i++) {
4399ef1f84bSDavid du Colombier rno += 4;
4409ef1f84bSDavid du Colombier p->mem[i].bar = pcicfgr32(p, rno);
4419ef1f84bSDavid du Colombier p->mem[i].size = pcibarsize(p, rno);
4429ef1f84bSDavid du Colombier }
4439ef1f84bSDavid du Colombier break;
4449ef1f84bSDavid du Colombier
4459ef1f84bSDavid du Colombier case 0x00:
4469ef1f84bSDavid du Colombier case 0x05: /* memory controller */
4479ef1f84bSDavid du Colombier case 0x06: /* bridge device */
4489ef1f84bSDavid du Colombier default:
4499ef1f84bSDavid du Colombier break;
4509ef1f84bSDavid du Colombier }
4519ef1f84bSDavid du Colombier
4529ef1f84bSDavid du Colombier if(head != nil)
4539ef1f84bSDavid du Colombier tail->link = p;
4549ef1f84bSDavid du Colombier else
4559ef1f84bSDavid du Colombier head = p;
4569ef1f84bSDavid du Colombier tail = p;
4579ef1f84bSDavid du Colombier }
4589ef1f84bSDavid du Colombier }
4599ef1f84bSDavid du Colombier
4609ef1f84bSDavid du Colombier *list = head;
4619ef1f84bSDavid du Colombier for(p = head; p != nil; p = p->link){
4629ef1f84bSDavid du Colombier /*
4639ef1f84bSDavid du Colombier * Find PCI-PCI bridges and recursively descend the tree.
4649ef1f84bSDavid du Colombier */
4659ef1f84bSDavid du Colombier if(p->ccrb != 0x06 || p->ccru != 0x04)
4669ef1f84bSDavid du Colombier continue;
4679ef1f84bSDavid du Colombier
4689ef1f84bSDavid du Colombier /*
4699ef1f84bSDavid du Colombier * If the secondary or subordinate bus number is not
4709ef1f84bSDavid du Colombier * initialised try to do what the PCI BIOS should have
4719ef1f84bSDavid du Colombier * done and fill in the numbers as the tree is descended.
4729ef1f84bSDavid du Colombier * On the way down the subordinate bus number is set to
4739ef1f84bSDavid du Colombier * the maximum as it's not known how many buses are behind
4749ef1f84bSDavid du Colombier * this one; the final value is set on the way back up.
4759ef1f84bSDavid du Colombier */
4769ef1f84bSDavid du Colombier sbn = pcicfgr8(p, PciSBN);
4779ef1f84bSDavid du Colombier ubn = pcicfgr8(p, PciUBN);
4789ef1f84bSDavid du Colombier
4799ef1f84bSDavid du Colombier if(sbn == 0 || ubn == 0 || nobios) {
4809ef1f84bSDavid du Colombier sbn = maxubn+1;
4819ef1f84bSDavid du Colombier /*
4829ef1f84bSDavid du Colombier * Make sure memory, I/O and master enables are
4839ef1f84bSDavid du Colombier * off, set the primary, secondary and subordinate
4849ef1f84bSDavid du Colombier * bus numbers and clear the secondary status before
4859ef1f84bSDavid du Colombier * attempting to scan the secondary bus.
4869ef1f84bSDavid du Colombier *
4879ef1f84bSDavid du Colombier * Initialisation of the bridge should be done here.
4889ef1f84bSDavid du Colombier */
4899ef1f84bSDavid du Colombier pcicfgw32(p, PciPCR, 0xFFFF0000);
4909ef1f84bSDavid du Colombier l = (MaxUBN<<16)|(sbn<<8)|bno;
4919ef1f84bSDavid du Colombier pcicfgw32(p, PciPBN, l);
4929ef1f84bSDavid du Colombier pcicfgw16(p, PciSPSR, 0xFFFF);
4939ef1f84bSDavid du Colombier maxubn = pcilscan(sbn, &p->bridge);
4949ef1f84bSDavid du Colombier l = (maxubn<<16)|(sbn<<8)|bno;
4959ef1f84bSDavid du Colombier
4969ef1f84bSDavid du Colombier pcicfgw32(p, PciPBN, l);
4979ef1f84bSDavid du Colombier }
4989ef1f84bSDavid du Colombier else {
4999ef1f84bSDavid du Colombier /*
5009ef1f84bSDavid du Colombier * You can't go back.
5019ef1f84bSDavid du Colombier * This shouldn't be possible, but the
5029ef1f84bSDavid du Colombier * Iwill DK8-HTX seems to have subordinate
5039ef1f84bSDavid du Colombier * bus numbers which get smaller on the
5049ef1f84bSDavid du Colombier * way down. Need to look more closely at
5059ef1f84bSDavid du Colombier * this.
5069ef1f84bSDavid du Colombier */
5079ef1f84bSDavid du Colombier if(ubn > maxubn)
5089ef1f84bSDavid du Colombier maxubn = ubn;
5099ef1f84bSDavid du Colombier pcilscan(sbn, &p->bridge);
5109ef1f84bSDavid du Colombier }
5119ef1f84bSDavid du Colombier }
5129ef1f84bSDavid du Colombier
5139ef1f84bSDavid du Colombier return maxubn;
5149ef1f84bSDavid du Colombier }
5159ef1f84bSDavid du Colombier
5169ef1f84bSDavid du Colombier int
pciscan(int bno,Pcidev ** list)5179ef1f84bSDavid du Colombier pciscan(int bno, Pcidev **list)
5189ef1f84bSDavid du Colombier {
5199ef1f84bSDavid du Colombier int ubn;
5209ef1f84bSDavid du Colombier
5219ef1f84bSDavid du Colombier lock(&pcicfginitlock);
5229ef1f84bSDavid du Colombier ubn = pcilscan(bno, list);
5239ef1f84bSDavid du Colombier unlock(&pcicfginitlock);
5249ef1f84bSDavid du Colombier return ubn;
5259ef1f84bSDavid du Colombier }
5269ef1f84bSDavid du Colombier
5279ef1f84bSDavid du Colombier static uchar
pIIxget(Pcidev * router,uchar link)5289ef1f84bSDavid du Colombier pIIxget(Pcidev *router, uchar link)
5299ef1f84bSDavid du Colombier {
5309ef1f84bSDavid du Colombier uchar pirq;
5319ef1f84bSDavid du Colombier
5329ef1f84bSDavid du Colombier /* link should be 0x60, 0x61, 0x62, 0x63 */
5339ef1f84bSDavid du Colombier pirq = pcicfgr8(router, link);
5349ef1f84bSDavid du Colombier return (pirq < 16)? pirq: 0;
5359ef1f84bSDavid du Colombier }
5369ef1f84bSDavid du Colombier
5379ef1f84bSDavid du Colombier static void
pIIxset(Pcidev * router,uchar link,uchar irq)5389ef1f84bSDavid du Colombier pIIxset(Pcidev *router, uchar link, uchar irq)
5399ef1f84bSDavid du Colombier {
5409ef1f84bSDavid du Colombier pcicfgw8(router, link, irq);
5419ef1f84bSDavid du Colombier }
5429ef1f84bSDavid du Colombier
5439ef1f84bSDavid du Colombier static uchar
viaget(Pcidev * router,uchar link)5449ef1f84bSDavid du Colombier viaget(Pcidev *router, uchar link)
5459ef1f84bSDavid du Colombier {
5469ef1f84bSDavid du Colombier uchar pirq;
5479ef1f84bSDavid du Colombier
5489ef1f84bSDavid du Colombier /* link should be 1, 2, 3, 5 */
5499ef1f84bSDavid du Colombier pirq = (link < 6)? pcicfgr8(router, 0x55 + (link>>1)): 0;
5509ef1f84bSDavid du Colombier
5519ef1f84bSDavid du Colombier return (link & 1)? (pirq >> 4): (pirq & 15);
5529ef1f84bSDavid du Colombier }
5539ef1f84bSDavid du Colombier
5549ef1f84bSDavid du Colombier static void
viaset(Pcidev * router,uchar link,uchar irq)5559ef1f84bSDavid du Colombier viaset(Pcidev *router, uchar link, uchar irq)
5569ef1f84bSDavid du Colombier {
5579ef1f84bSDavid du Colombier uchar pirq;
5589ef1f84bSDavid du Colombier
5599ef1f84bSDavid du Colombier pirq = pcicfgr8(router, 0x55 + (link >> 1));
5609ef1f84bSDavid du Colombier pirq &= (link & 1)? 0x0f: 0xf0;
5619ef1f84bSDavid du Colombier pirq |= (link & 1)? (irq << 4): (irq & 15);
5629ef1f84bSDavid du Colombier pcicfgw8(router, 0x55 + (link>>1), pirq);
5639ef1f84bSDavid du Colombier }
5649ef1f84bSDavid du Colombier
5659ef1f84bSDavid du Colombier static uchar
optiget(Pcidev * router,uchar link)5669ef1f84bSDavid du Colombier optiget(Pcidev *router, uchar link)
5679ef1f84bSDavid du Colombier {
5689ef1f84bSDavid du Colombier uchar pirq = 0;
5699ef1f84bSDavid du Colombier
5709ef1f84bSDavid du Colombier /* link should be 0x02, 0x12, 0x22, 0x32 */
5719ef1f84bSDavid du Colombier if ((link & 0xcf) == 0x02)
5729ef1f84bSDavid du Colombier pirq = pcicfgr8(router, 0xb8 + (link >> 5));
5739ef1f84bSDavid du Colombier return (link & 0x10)? (pirq >> 4): (pirq & 15);
5749ef1f84bSDavid du Colombier }
5759ef1f84bSDavid du Colombier
5769ef1f84bSDavid du Colombier static void
optiset(Pcidev * router,uchar link,uchar irq)5779ef1f84bSDavid du Colombier optiset(Pcidev *router, uchar link, uchar irq)
5789ef1f84bSDavid du Colombier {
5799ef1f84bSDavid du Colombier uchar pirq;
5809ef1f84bSDavid du Colombier
5819ef1f84bSDavid du Colombier pirq = pcicfgr8(router, 0xb8 + (link >> 5));
5829ef1f84bSDavid du Colombier pirq &= (link & 0x10)? 0x0f : 0xf0;
5839ef1f84bSDavid du Colombier pirq |= (link & 0x10)? (irq << 4): (irq & 15);
5849ef1f84bSDavid du Colombier pcicfgw8(router, 0xb8 + (link >> 5), pirq);
5859ef1f84bSDavid du Colombier }
5869ef1f84bSDavid du Colombier
5879ef1f84bSDavid du Colombier static uchar
aliget(Pcidev * router,uchar link)5889ef1f84bSDavid du Colombier aliget(Pcidev *router, uchar link)
5899ef1f84bSDavid du Colombier {
5909ef1f84bSDavid du Colombier /* No, you're not dreaming */
5919ef1f84bSDavid du Colombier static const uchar map[] = { 0, 9, 3, 10, 4, 5, 7, 6, 1, 11, 0, 12, 0, 14, 0, 15 };
5929ef1f84bSDavid du Colombier uchar pirq;
5939ef1f84bSDavid du Colombier
5949ef1f84bSDavid du Colombier /* link should be 0x01..0x08 */
5959ef1f84bSDavid du Colombier pirq = pcicfgr8(router, 0x48 + ((link-1)>>1));
5969ef1f84bSDavid du Colombier return (link & 1)? map[pirq&15]: map[pirq>>4];
5979ef1f84bSDavid du Colombier }
5989ef1f84bSDavid du Colombier
5999ef1f84bSDavid du Colombier static void
aliset(Pcidev * router,uchar link,uchar irq)6009ef1f84bSDavid du Colombier aliset(Pcidev *router, uchar link, uchar irq)
6019ef1f84bSDavid du Colombier {
6029ef1f84bSDavid du Colombier /* Inverse of map in aliget */
6039ef1f84bSDavid du Colombier static const uchar map[] = { 0, 8, 0, 2, 4, 5, 7, 6, 0, 1, 3, 9, 11, 0, 13, 15 };
6049ef1f84bSDavid du Colombier uchar pirq;
6059ef1f84bSDavid du Colombier
6069ef1f84bSDavid du Colombier pirq = pcicfgr8(router, 0x48 + ((link-1)>>1));
6079ef1f84bSDavid du Colombier pirq &= (link & 1)? 0x0f: 0xf0;
6089ef1f84bSDavid du Colombier pirq |= (link & 1)? (map[irq] << 4): (map[irq] & 15);
6099ef1f84bSDavid du Colombier pcicfgw8(router, 0x48 + ((link-1)>>1), pirq);
6109ef1f84bSDavid du Colombier }
6119ef1f84bSDavid du Colombier
6129ef1f84bSDavid du Colombier static uchar
cyrixget(Pcidev * router,uchar link)6139ef1f84bSDavid du Colombier cyrixget(Pcidev *router, uchar link)
6149ef1f84bSDavid du Colombier {
6159ef1f84bSDavid du Colombier uchar pirq;
6169ef1f84bSDavid du Colombier
6179ef1f84bSDavid du Colombier /* link should be 1, 2, 3, 4 */
6189ef1f84bSDavid du Colombier pirq = pcicfgr8(router, 0x5c + ((link-1)>>1));
6199ef1f84bSDavid du Colombier return ((link & 1)? pirq >> 4: pirq & 15);
6209ef1f84bSDavid du Colombier }
6219ef1f84bSDavid du Colombier
6229ef1f84bSDavid du Colombier static void
cyrixset(Pcidev * router,uchar link,uchar irq)6239ef1f84bSDavid du Colombier cyrixset(Pcidev *router, uchar link, uchar irq)
6249ef1f84bSDavid du Colombier {
6259ef1f84bSDavid du Colombier uchar pirq;
6269ef1f84bSDavid du Colombier
6279ef1f84bSDavid du Colombier pirq = pcicfgr8(router, 0x5c + (link>>1));
6289ef1f84bSDavid du Colombier pirq &= (link & 1)? 0x0f: 0xf0;
6299ef1f84bSDavid du Colombier pirq |= (link & 1)? (irq << 4): (irq & 15);
6309ef1f84bSDavid du Colombier pcicfgw8(router, 0x5c + (link>>1), pirq);
6319ef1f84bSDavid du Colombier }
6329ef1f84bSDavid du Colombier
6339ef1f84bSDavid du Colombier typedef struct Bridge Bridge;
6349ef1f84bSDavid du Colombier struct Bridge
6359ef1f84bSDavid du Colombier {
6369ef1f84bSDavid du Colombier ushort vid;
6379ef1f84bSDavid du Colombier ushort did;
6389ef1f84bSDavid du Colombier uchar (*get)(Pcidev *, uchar);
6399ef1f84bSDavid du Colombier void (*set)(Pcidev *, uchar, uchar);
6409ef1f84bSDavid du Colombier };
6419ef1f84bSDavid du Colombier
6429ef1f84bSDavid du Colombier static Bridge southbridges[] = {
6439ef1f84bSDavid du Colombier { 0x8086, 0x122e, pIIxget, pIIxset }, /* Intel 82371FB */
6449ef1f84bSDavid du Colombier { 0x8086, 0x1234, pIIxget, pIIxset }, /* Intel 82371MX */
6459ef1f84bSDavid du Colombier { 0x8086, 0x7000, pIIxget, pIIxset }, /* Intel 82371SB */
6469ef1f84bSDavid du Colombier { 0x8086, 0x7110, pIIxget, pIIxset }, /* Intel 82371AB */
6479ef1f84bSDavid du Colombier { 0x8086, 0x7198, pIIxget, pIIxset }, /* Intel 82443MX (fn 1) */
6489ef1f84bSDavid du Colombier { 0x8086, 0x2410, pIIxget, pIIxset }, /* Intel 82801AA */
6499ef1f84bSDavid du Colombier { 0x8086, 0x2420, pIIxget, pIIxset }, /* Intel 82801AB */
6509ef1f84bSDavid du Colombier { 0x8086, 0x2440, pIIxget, pIIxset }, /* Intel 82801BA */
6519ef1f84bSDavid du Colombier { 0x8086, 0x2448, pIIxget, pIIxset }, /* Intel 82801BAM/CAM/DBM */
6529ef1f84bSDavid du Colombier { 0x8086, 0x244c, pIIxget, pIIxset }, /* Intel 82801BAM */
6539ef1f84bSDavid du Colombier { 0x8086, 0x244e, pIIxget, pIIxset }, /* Intel 82801 */
6549ef1f84bSDavid du Colombier { 0x8086, 0x2480, pIIxget, pIIxset }, /* Intel 82801CA */
6559ef1f84bSDavid du Colombier { 0x8086, 0x248c, pIIxget, pIIxset }, /* Intel 82801CAM */
6569ef1f84bSDavid du Colombier { 0x8086, 0x24c0, pIIxget, pIIxset }, /* Intel 82801DBL */
6579ef1f84bSDavid du Colombier { 0x8086, 0x24cc, pIIxget, pIIxset }, /* Intel 82801DBM */
6589ef1f84bSDavid du Colombier { 0x8086, 0x24d0, pIIxget, pIIxset }, /* Intel 82801EB */
6599ef1f84bSDavid du Colombier { 0x8086, 0x25a1, pIIxget, pIIxset }, /* Intel 6300ESB */
6609ef1f84bSDavid du Colombier { 0x8086, 0x2640, pIIxget, pIIxset }, /* Intel 82801FB */
6619ef1f84bSDavid du Colombier { 0x8086, 0x2641, pIIxget, pIIxset }, /* Intel 82801FBM */
6629ef1f84bSDavid du Colombier { 0x8086, 0x27b8, pIIxget, pIIxset }, /* Intel 82801GB */
6639ef1f84bSDavid du Colombier { 0x8086, 0x27b9, pIIxget, pIIxset }, /* Intel 82801GBM */
6649ef1f84bSDavid du Colombier { 0x8086, 0x27bd, pIIxget, pIIxset }, /* Intel 82801GB/GR */
6659ef1f84bSDavid du Colombier { 0x8086, 0x3a16, pIIxget, pIIxset }, /* Intel 82801JIR */
6669ef1f84bSDavid du Colombier { 0x8086, 0x3a40, pIIxget, pIIxset }, /* Intel 82801JI */
6679ef1f84bSDavid du Colombier { 0x8086, 0x3a42, pIIxget, pIIxset }, /* Intel 82801JI */
6689ef1f84bSDavid du Colombier { 0x8086, 0x3a48, pIIxget, pIIxset }, /* Intel 82801JI */
6699ef1f84bSDavid du Colombier { 0x8086, 0x2916, pIIxget, pIIxset }, /* Intel 82801? */
6709ef1f84bSDavid du Colombier { 0x8086, 0x1c02, pIIxget, pIIxset }, /* Intel 6 Series/C200 */
671277b6efdSDavid du Colombier { 0x8086, 0x1c44, pIIxget, pIIxset }, /* Intel 6 Series/Z68 Express */
6729ef1f84bSDavid du Colombier { 0x8086, 0x1e53, pIIxget, pIIxset }, /* Intel 7 Series/C216 */
6739ef1f84bSDavid du Colombier { 0x1106, 0x0586, viaget, viaset }, /* Viatech 82C586 */
6749ef1f84bSDavid du Colombier { 0x1106, 0x0596, viaget, viaset }, /* Viatech 82C596 */
6759ef1f84bSDavid du Colombier { 0x1106, 0x0686, viaget, viaset }, /* Viatech 82C686 */
6769ef1f84bSDavid du Colombier { 0x1106, 0x3227, viaget, viaset }, /* Viatech VT8237 */
6779ef1f84bSDavid du Colombier { 0x1045, 0xc700, optiget, optiset }, /* Opti 82C700 */
6789ef1f84bSDavid du Colombier { 0x10b9, 0x1533, aliget, aliset }, /* Al M1533 */
6799ef1f84bSDavid du Colombier { 0x1039, 0x0008, pIIxget, pIIxset }, /* SI 503 */
6809ef1f84bSDavid du Colombier { 0x1039, 0x0496, pIIxget, pIIxset }, /* SI 496 */
6819ef1f84bSDavid du Colombier { 0x1078, 0x0100, cyrixget, cyrixset }, /* Cyrix 5530 Legacy */
6829ef1f84bSDavid du Colombier
6839ef1f84bSDavid du Colombier { 0x1022, 0x746B, nil, nil }, /* AMD 8111 */
6849ef1f84bSDavid du Colombier { 0x10DE, 0x00D1, nil, nil }, /* NVIDIA nForce 3 */
6859ef1f84bSDavid du Colombier { 0x10DE, 0x00E0, nil, nil }, /* NVIDIA nForce 3 250 Series */
6869ef1f84bSDavid du Colombier { 0x10DE, 0x00E1, nil, nil }, /* NVIDIA nForce 3 250 Series */
6879ef1f84bSDavid du Colombier { 0x1166, 0x0200, nil, nil }, /* ServerWorks ServerSet III LE */
6889ef1f84bSDavid du Colombier { 0x1002, 0x4377, nil, nil }, /* ATI Radeon Xpress 200M */
6899ef1f84bSDavid du Colombier { 0x1002, 0x4372, nil, nil }, /* ATI SB400 */
6909ef1f84bSDavid du Colombier };
6919ef1f84bSDavid du Colombier
6929ef1f84bSDavid du Colombier typedef struct Slot Slot;
6939ef1f84bSDavid du Colombier struct Slot {
6949ef1f84bSDavid du Colombier uchar bus; // Pci bus number
6959ef1f84bSDavid du Colombier uchar dev; // Pci device number
6969ef1f84bSDavid du Colombier uchar maps[12]; // Avoid structs! Link and mask.
6979ef1f84bSDavid du Colombier uchar slot; // Add-in/built-in slot
6989ef1f84bSDavid du Colombier uchar reserved;
6999ef1f84bSDavid du Colombier };
7009ef1f84bSDavid du Colombier
7019ef1f84bSDavid du Colombier typedef struct Router Router;
7029ef1f84bSDavid du Colombier struct Router {
7039ef1f84bSDavid du Colombier uchar signature[4]; // Routing table signature
7049ef1f84bSDavid du Colombier uchar version[2]; // Version number
7059ef1f84bSDavid du Colombier uchar size[2]; // Total table size
7069ef1f84bSDavid du Colombier uchar bus; // Interrupt router bus number
7079ef1f84bSDavid du Colombier uchar devfn; // Router's devfunc
7089ef1f84bSDavid du Colombier uchar pciirqs[2]; // Exclusive PCI irqs
7099ef1f84bSDavid du Colombier uchar compat[4]; // Compatible PCI interrupt router
7109ef1f84bSDavid du Colombier uchar miniport[4]; // Miniport data
7119ef1f84bSDavid du Colombier uchar reserved[11];
7129ef1f84bSDavid du Colombier uchar checksum;
7139ef1f84bSDavid du Colombier };
7149ef1f84bSDavid du Colombier
7159ef1f84bSDavid du Colombier static ushort pciirqs; // Exclusive PCI irqs
7169ef1f84bSDavid du Colombier static Bridge *southbridge; // Which southbridge to use.
7179ef1f84bSDavid du Colombier
7189ef1f84bSDavid du Colombier static void
pcirouting(void)7199ef1f84bSDavid du Colombier pcirouting(void)
7209ef1f84bSDavid du Colombier {
7219ef1f84bSDavid du Colombier Slot *e;
7229ef1f84bSDavid du Colombier Router *r;
7239ef1f84bSDavid du Colombier int size, i, fn, tbdf;
7249ef1f84bSDavid du Colombier Pcidev *sbpci, *pci;
7259ef1f84bSDavid du Colombier uchar *p, pin, irq, link, *map;
7269ef1f84bSDavid du Colombier
7279ef1f84bSDavid du Colombier // Search for PCI interrupt routing table in BIOS
7289ef1f84bSDavid du Colombier for(p = (uchar *)KADDR(0xf0000); p < (uchar *)KADDR(0xfffff); p += 16)
7299ef1f84bSDavid du Colombier if(p[0] == '$' && p[1] == 'P' && p[2] == 'I' && p[3] == 'R')
7309ef1f84bSDavid du Colombier break;
7319ef1f84bSDavid du Colombier
732277b6efdSDavid du Colombier if(p >= (uchar *)KADDR(0xfffff)) {
733277b6efdSDavid du Colombier // print("no PCI intr routing table found\n");
7349ef1f84bSDavid du Colombier return;
735277b6efdSDavid du Colombier }
7369ef1f84bSDavid du Colombier
7379ef1f84bSDavid du Colombier r = (Router *)p;
7389ef1f84bSDavid du Colombier
739277b6efdSDavid du Colombier if (0)
7409ef1f84bSDavid du Colombier print("PCI interrupt routing table version %d.%d at %#p\n",
7419ef1f84bSDavid du Colombier r->version[0], r->version[1], r);
7429ef1f84bSDavid du Colombier
7439ef1f84bSDavid du Colombier tbdf = (BusPCI << 24)|(r->bus << 16)|(r->devfn << 8);
7449ef1f84bSDavid du Colombier sbpci = pcimatchtbdf(tbdf);
7459ef1f84bSDavid du Colombier if(sbpci == nil) {
7469ef1f84bSDavid du Colombier print("pcirouting: Cannot find south bridge %T\n", tbdf);
7479ef1f84bSDavid du Colombier return;
7489ef1f84bSDavid du Colombier }
7499ef1f84bSDavid du Colombier
7509ef1f84bSDavid du Colombier for(i = 0; i != nelem(southbridges); i++)
7519ef1f84bSDavid du Colombier if(sbpci->vid == southbridges[i].vid && sbpci->did == southbridges[i].did)
7529ef1f84bSDavid du Colombier break;
7539ef1f84bSDavid du Colombier
7549ef1f84bSDavid du Colombier if(i == nelem(southbridges)) {
7559ef1f84bSDavid du Colombier print("pcirouting: ignoring south bridge %T %.4ux/%.4ux\n", tbdf, sbpci->vid, sbpci->did);
7569ef1f84bSDavid du Colombier return;
7579ef1f84bSDavid du Colombier }
7589ef1f84bSDavid du Colombier southbridge = &southbridges[i];
7599ef1f84bSDavid du Colombier if(southbridge->get == nil || southbridge->set == nil)
7609ef1f84bSDavid du Colombier return;
7619ef1f84bSDavid du Colombier
7629ef1f84bSDavid du Colombier pciirqs = (r->pciirqs[1] << 8)|r->pciirqs[0];
7639ef1f84bSDavid du Colombier
7649ef1f84bSDavid du Colombier size = (r->size[1] << 8)|r->size[0];
7659ef1f84bSDavid du Colombier for(e = (Slot *)&r[1]; (uchar *)e < p + size; e++) {
7669ef1f84bSDavid du Colombier // print("%.2ux/%.2ux %.2ux: ", e->bus, e->dev, e->slot);
7679ef1f84bSDavid du Colombier // for (i = 0; i != 4; i++) {
7689ef1f84bSDavid du Colombier // uchar *m = &e->maps[i * 3];
7699ef1f84bSDavid du Colombier // print("[%d] %.2ux %.4ux ",
7709ef1f84bSDavid du Colombier // i, m[0], (m[2] << 8)|m[1]);
7719ef1f84bSDavid du Colombier // }
7729ef1f84bSDavid du Colombier // print("\n");
7739ef1f84bSDavid du Colombier
7749ef1f84bSDavid du Colombier for(fn = 0; fn != 8; fn++) {
7759ef1f84bSDavid du Colombier tbdf = (BusPCI << 24)|(e->bus << 16)|((e->dev | fn) << 8);
7769ef1f84bSDavid du Colombier pci = pcimatchtbdf(tbdf);
7779ef1f84bSDavid du Colombier if(pci == nil)
7789ef1f84bSDavid du Colombier continue;
7799ef1f84bSDavid du Colombier pin = pcicfgr8(pci, PciINTP);
7809ef1f84bSDavid du Colombier if(pin == 0 || pin == 0xff)
7819ef1f84bSDavid du Colombier continue;
7829ef1f84bSDavid du Colombier
7839ef1f84bSDavid du Colombier map = &e->maps[(pin - 1) * 3];
7849ef1f84bSDavid du Colombier link = map[0];
7859ef1f84bSDavid du Colombier irq = southbridge->get(sbpci, link);
7869ef1f84bSDavid du Colombier if(irq == 0 || irq == pci->intl)
7879ef1f84bSDavid du Colombier continue;
7889ef1f84bSDavid du Colombier if(pci->intl != 0 && pci->intl != 0xFF) {
7899ef1f84bSDavid du Colombier print("pcirouting: BIOS workaround: %T at pin %d link %d irq %d -> %d\n",
7909ef1f84bSDavid du Colombier tbdf, pin, link, irq, pci->intl);
7919ef1f84bSDavid du Colombier southbridge->set(sbpci, link, pci->intl);
7929ef1f84bSDavid du Colombier continue;
7939ef1f84bSDavid du Colombier }
7949ef1f84bSDavid du Colombier print("pcirouting: %T at pin %d link %d irq %d\n", tbdf, pin, link, irq);
7959ef1f84bSDavid du Colombier pcicfgw8(pci, PciINTL, irq);
7969ef1f84bSDavid du Colombier pci->intl = irq;
7979ef1f84bSDavid du Colombier }
7989ef1f84bSDavid du Colombier }
7999ef1f84bSDavid du Colombier }
8009ef1f84bSDavid du Colombier
8019ef1f84bSDavid du Colombier static void pcireservemem(void);
8029ef1f84bSDavid du Colombier
8039ef1f84bSDavid du Colombier static void
pcicfginit(void)8049ef1f84bSDavid du Colombier pcicfginit(void)
8059ef1f84bSDavid du Colombier {
8069ef1f84bSDavid du Colombier char *p;
8079ef1f84bSDavid du Colombier Pcidev **list;
8089ef1f84bSDavid du Colombier ulong mema, ioa;
8099ef1f84bSDavid du Colombier int bno, n;
8109ef1f84bSDavid du Colombier
8119ef1f84bSDavid du Colombier lock(&pcicfginitlock);
8129ef1f84bSDavid du Colombier if(pcicfgmode != -1)
8139ef1f84bSDavid du Colombier goto out;
8149ef1f84bSDavid du Colombier
8159ef1f84bSDavid du Colombier if(getconf("*nobios"))
8169ef1f84bSDavid du Colombier nobios = 1;
8179ef1f84bSDavid du Colombier if(getconf("*nopcirouting"))
8189ef1f84bSDavid du Colombier nopcirouting = 1;
8199ef1f84bSDavid du Colombier
8209ef1f84bSDavid du Colombier /*
8219ef1f84bSDavid du Colombier * Assume Configuration Mechanism One. Method Two was deprecated
8229ef1f84bSDavid du Colombier * a long time ago and was only for backwards compaibility with the
8239ef1f84bSDavid du Colombier * Intel Saturn and Mercury chip sets. Thank you, QEMU.
8249ef1f84bSDavid du Colombier */
8259ef1f84bSDavid du Colombier pcicfgmode = 1;
8269ef1f84bSDavid du Colombier pcimaxdno = 31;
8279ef1f84bSDavid du Colombier
8289ef1f84bSDavid du Colombier if(pcicfgmode < 0)
8299ef1f84bSDavid du Colombier goto out;
8309ef1f84bSDavid du Colombier
8319ef1f84bSDavid du Colombier fmtinstall('T', tbdffmt);
8329ef1f84bSDavid du Colombier
8339ef1f84bSDavid du Colombier if(p = getconf("*pcimaxbno")){
8349ef1f84bSDavid du Colombier n = strtoul(p, 0, 0);
8359ef1f84bSDavid du Colombier if(n < pcimaxbno)
8369ef1f84bSDavid du Colombier pcimaxbno = n;
8379ef1f84bSDavid du Colombier }
8389ef1f84bSDavid du Colombier if(p = getconf("*pcimaxdno")){
8399ef1f84bSDavid du Colombier n = strtoul(p, 0, 0);
8409ef1f84bSDavid du Colombier if(n < pcimaxdno)
8419ef1f84bSDavid du Colombier pcimaxdno = n;
8429ef1f84bSDavid du Colombier }
8439ef1f84bSDavid du Colombier
8449ef1f84bSDavid du Colombier list = &pciroot;
8459ef1f84bSDavid du Colombier for(bno = 0; bno <= pcimaxbno; bno++) {
8469ef1f84bSDavid du Colombier int sbno = bno;
8479ef1f84bSDavid du Colombier bno = pcilscan(bno, list);
8489ef1f84bSDavid du Colombier
8499ef1f84bSDavid du Colombier while(*list)
8509ef1f84bSDavid du Colombier list = &(*list)->link;
8519ef1f84bSDavid du Colombier
8529ef1f84bSDavid du Colombier if (sbno == 0) {
8539ef1f84bSDavid du Colombier Pcidev *pci;
8549ef1f84bSDavid du Colombier
8559ef1f84bSDavid du Colombier /*
8569ef1f84bSDavid du Colombier * If we have found a PCI-to-Cardbus bridge, make sure
8579ef1f84bSDavid du Colombier * it has no valid mappings anymore.
8589ef1f84bSDavid du Colombier */
8599ef1f84bSDavid du Colombier pci = pciroot;
8609ef1f84bSDavid du Colombier while (pci) {
8619ef1f84bSDavid du Colombier if (pci->ccrb == 6 && pci->ccru == 7) {
8629ef1f84bSDavid du Colombier ushort bcr;
8639ef1f84bSDavid du Colombier
8649ef1f84bSDavid du Colombier /* reset the cardbus */
8659ef1f84bSDavid du Colombier bcr = pcicfgr16(pci, PciBCR);
8669ef1f84bSDavid du Colombier pcicfgw16(pci, PciBCR, 0x40 | bcr);
8679ef1f84bSDavid du Colombier delay(50);
8689ef1f84bSDavid du Colombier }
8699ef1f84bSDavid du Colombier pci = pci->link;
8709ef1f84bSDavid du Colombier }
8719ef1f84bSDavid du Colombier }
8729ef1f84bSDavid du Colombier }
8739ef1f84bSDavid du Colombier
8749ef1f84bSDavid du Colombier if(pciroot == nil)
8759ef1f84bSDavid du Colombier goto out;
8769ef1f84bSDavid du Colombier
8779ef1f84bSDavid du Colombier if(nobios) {
8789ef1f84bSDavid du Colombier /*
8799ef1f84bSDavid du Colombier * Work out how big the top bus is
8809ef1f84bSDavid du Colombier */
8819ef1f84bSDavid du Colombier mema = 0;
8829ef1f84bSDavid du Colombier ioa = 0;
8839ef1f84bSDavid du Colombier pcibusmap(pciroot, &mema, &ioa, 0);
8849ef1f84bSDavid du Colombier
8859ef1f84bSDavid du Colombier DBG("Sizes: mem=%8.8lux size=%8.8lux io=%8.8lux\n",
8869ef1f84bSDavid du Colombier mema, pcimask(mema), ioa);
8879ef1f84bSDavid du Colombier
8889ef1f84bSDavid du Colombier /*
8899ef1f84bSDavid du Colombier * Align the windows and map it
8909ef1f84bSDavid du Colombier */
8919ef1f84bSDavid du Colombier ioa = 0x1000;
8929ef1f84bSDavid du Colombier mema = 0x90000000;
8939ef1f84bSDavid du Colombier
8949ef1f84bSDavid du Colombier pcilog("Mask sizes: mem=%lux io=%lux\n", mema, ioa);
8959ef1f84bSDavid du Colombier
8969ef1f84bSDavid du Colombier pcibusmap(pciroot, &mema, &ioa, 1);
8979ef1f84bSDavid du Colombier DBG("Sizes2: mem=%lux io=%lux\n", mema, ioa);
8989ef1f84bSDavid du Colombier
8999ef1f84bSDavid du Colombier unlock(&pcicfginitlock);
9009ef1f84bSDavid du Colombier return;
9019ef1f84bSDavid du Colombier }
9029ef1f84bSDavid du Colombier
9039ef1f84bSDavid du Colombier if (!nopcirouting)
9049ef1f84bSDavid du Colombier pcirouting();
9059ef1f84bSDavid du Colombier
9069ef1f84bSDavid du Colombier out:
9079ef1f84bSDavid du Colombier pcireservemem();
9089ef1f84bSDavid du Colombier unlock(&pcicfginitlock);
9099ef1f84bSDavid du Colombier
9109ef1f84bSDavid du Colombier if(getconf("*pcihinv"))
9119ef1f84bSDavid du Colombier pcihinv(nil);
9129ef1f84bSDavid du Colombier }
9139ef1f84bSDavid du Colombier
9149ef1f84bSDavid du Colombier static void
pcireservemem(void)9159ef1f84bSDavid du Colombier pcireservemem(void)
9169ef1f84bSDavid du Colombier {
9179ef1f84bSDavid du Colombier int i;
9189ef1f84bSDavid du Colombier Pcidev *p;
9199ef1f84bSDavid du Colombier
9209ef1f84bSDavid du Colombier /*
9219ef1f84bSDavid du Colombier * mark all the physical address space claimed by pci devices
9229ef1f84bSDavid du Colombier * as in use, so that it's not given out elsewhere.
9239ef1f84bSDavid du Colombier * beware the type and size of 'bar'.
9249ef1f84bSDavid du Colombier */
9259ef1f84bSDavid du Colombier for(p=pciroot; p; p=p->list)
9269ef1f84bSDavid du Colombier for(i=0; i<nelem(p->mem); i++)
9279ef1f84bSDavid du Colombier if(p->mem[i].bar && (p->mem[i].bar&1) == 0)
9289ef1f84bSDavid du Colombier asmmapinit(p->mem[i].bar&~0x0F, p->mem[i].size, 5);
9299ef1f84bSDavid du Colombier }
9309ef1f84bSDavid du Colombier
9319ef1f84bSDavid du Colombier static int
pcicfgrw8(int tbdf,int rno,int data,int read)9329ef1f84bSDavid du Colombier pcicfgrw8(int tbdf, int rno, int data, int read)
9339ef1f84bSDavid du Colombier {
9349ef1f84bSDavid du Colombier int o, type, x;
9359ef1f84bSDavid du Colombier
9369ef1f84bSDavid du Colombier if(pcicfgmode == -1)
9379ef1f84bSDavid du Colombier pcicfginit();
9389ef1f84bSDavid du Colombier
9399ef1f84bSDavid du Colombier if(BUSBNO(tbdf))
9409ef1f84bSDavid du Colombier type = 0x01;
9419ef1f84bSDavid du Colombier else
9429ef1f84bSDavid du Colombier type = 0x00;
9439ef1f84bSDavid du Colombier x = -1;
9449ef1f84bSDavid du Colombier if(BUSDNO(tbdf) > pcimaxdno)
9459ef1f84bSDavid du Colombier return x;
9469ef1f84bSDavid du Colombier
9479ef1f84bSDavid du Colombier lock(&pcicfglock);
9489ef1f84bSDavid du Colombier switch(pcicfgmode){
9499ef1f84bSDavid du Colombier
9509ef1f84bSDavid du Colombier case 1:
9519ef1f84bSDavid du Colombier o = rno & 0x03;
9529ef1f84bSDavid du Colombier rno &= ~0x03;
9539ef1f84bSDavid du Colombier outl(PciADDR, 0x80000000|BUSBDF(tbdf)|rno|type);
9549ef1f84bSDavid du Colombier if(read)
9559ef1f84bSDavid du Colombier x = inb(PciDATA+o);
9569ef1f84bSDavid du Colombier else
9579ef1f84bSDavid du Colombier outb(PciDATA+o, data);
9589ef1f84bSDavid du Colombier outl(PciADDR, 0);
9599ef1f84bSDavid du Colombier break;
9609ef1f84bSDavid du Colombier
9619ef1f84bSDavid du Colombier case 2:
9629ef1f84bSDavid du Colombier outb(PciCSE, 0x80|(BUSFNO(tbdf)<<1));
9639ef1f84bSDavid du Colombier outb(PciFORWARD, BUSBNO(tbdf));
9649ef1f84bSDavid du Colombier if(read)
9659ef1f84bSDavid du Colombier x = inb((0xC000|(BUSDNO(tbdf)<<8)) + rno);
9669ef1f84bSDavid du Colombier else
9679ef1f84bSDavid du Colombier outb((0xC000|(BUSDNO(tbdf)<<8)) + rno, data);
9689ef1f84bSDavid du Colombier outb(PciCSE, 0);
9699ef1f84bSDavid du Colombier break;
9709ef1f84bSDavid du Colombier }
9719ef1f84bSDavid du Colombier unlock(&pcicfglock);
9729ef1f84bSDavid du Colombier
9739ef1f84bSDavid du Colombier return x;
9749ef1f84bSDavid du Colombier }
9759ef1f84bSDavid du Colombier
9769ef1f84bSDavid du Colombier int
pcicfgr8(Pcidev * pcidev,int rno)9779ef1f84bSDavid du Colombier pcicfgr8(Pcidev* pcidev, int rno)
9789ef1f84bSDavid du Colombier {
9799ef1f84bSDavid du Colombier return pcicfgrw8(pcidev->tbdf, rno, 0, 1);
9809ef1f84bSDavid du Colombier }
9819ef1f84bSDavid du Colombier
9829ef1f84bSDavid du Colombier void
pcicfgw8(Pcidev * pcidev,int rno,int data)9839ef1f84bSDavid du Colombier pcicfgw8(Pcidev* pcidev, int rno, int data)
9849ef1f84bSDavid du Colombier {
9859ef1f84bSDavid du Colombier pcicfgrw8(pcidev->tbdf, rno, data, 0);
9869ef1f84bSDavid du Colombier }
9879ef1f84bSDavid du Colombier
9889ef1f84bSDavid du Colombier static int
pcicfgrw16(int tbdf,int rno,int data,int read)9899ef1f84bSDavid du Colombier pcicfgrw16(int tbdf, int rno, int data, int read)
9909ef1f84bSDavid du Colombier {
9919ef1f84bSDavid du Colombier int o, type, x;
9929ef1f84bSDavid du Colombier
9939ef1f84bSDavid du Colombier if(pcicfgmode == -1)
9949ef1f84bSDavid du Colombier pcicfginit();
9959ef1f84bSDavid du Colombier
9969ef1f84bSDavid du Colombier if(BUSBNO(tbdf))
9979ef1f84bSDavid du Colombier type = 0x01;
9989ef1f84bSDavid du Colombier else
9999ef1f84bSDavid du Colombier type = 0x00;
10009ef1f84bSDavid du Colombier x = -1;
10019ef1f84bSDavid du Colombier if(BUSDNO(tbdf) > pcimaxdno)
10029ef1f84bSDavid du Colombier return x;
10039ef1f84bSDavid du Colombier
10049ef1f84bSDavid du Colombier lock(&pcicfglock);
10059ef1f84bSDavid du Colombier switch(pcicfgmode){
10069ef1f84bSDavid du Colombier
10079ef1f84bSDavid du Colombier case 1:
10089ef1f84bSDavid du Colombier o = rno & 0x02;
10099ef1f84bSDavid du Colombier rno &= ~0x03;
10109ef1f84bSDavid du Colombier outl(PciADDR, 0x80000000|BUSBDF(tbdf)|rno|type);
10119ef1f84bSDavid du Colombier if(read)
10129ef1f84bSDavid du Colombier x = ins(PciDATA+o);
10139ef1f84bSDavid du Colombier else
10149ef1f84bSDavid du Colombier outs(PciDATA+o, data);
10159ef1f84bSDavid du Colombier outl(PciADDR, 0);
10169ef1f84bSDavid du Colombier break;
10179ef1f84bSDavid du Colombier
10189ef1f84bSDavid du Colombier case 2:
10199ef1f84bSDavid du Colombier outb(PciCSE, 0x80|(BUSFNO(tbdf)<<1));
10209ef1f84bSDavid du Colombier outb(PciFORWARD, BUSBNO(tbdf));
10219ef1f84bSDavid du Colombier if(read)
10229ef1f84bSDavid du Colombier x = ins((0xC000|(BUSDNO(tbdf)<<8)) + rno);
10239ef1f84bSDavid du Colombier else
10249ef1f84bSDavid du Colombier outs((0xC000|(BUSDNO(tbdf)<<8)) + rno, data);
10259ef1f84bSDavid du Colombier outb(PciCSE, 0);
10269ef1f84bSDavid du Colombier break;
10279ef1f84bSDavid du Colombier }
10289ef1f84bSDavid du Colombier unlock(&pcicfglock);
10299ef1f84bSDavid du Colombier
10309ef1f84bSDavid du Colombier return x;
10319ef1f84bSDavid du Colombier }
10329ef1f84bSDavid du Colombier
10339ef1f84bSDavid du Colombier int
pcicfgr16(Pcidev * pcidev,int rno)10349ef1f84bSDavid du Colombier pcicfgr16(Pcidev* pcidev, int rno)
10359ef1f84bSDavid du Colombier {
10369ef1f84bSDavid du Colombier return pcicfgrw16(pcidev->tbdf, rno, 0, 1);
10379ef1f84bSDavid du Colombier }
10389ef1f84bSDavid du Colombier
10399ef1f84bSDavid du Colombier void
pcicfgw16(Pcidev * pcidev,int rno,int data)10409ef1f84bSDavid du Colombier pcicfgw16(Pcidev* pcidev, int rno, int data)
10419ef1f84bSDavid du Colombier {
10429ef1f84bSDavid du Colombier pcicfgrw16(pcidev->tbdf, rno, data, 0);
10439ef1f84bSDavid du Colombier }
10449ef1f84bSDavid du Colombier
10459ef1f84bSDavid du Colombier static int
pcicfgrw32(int tbdf,int rno,int data,int read)10469ef1f84bSDavid du Colombier pcicfgrw32(int tbdf, int rno, int data, int read)
10479ef1f84bSDavid du Colombier {
10489ef1f84bSDavid du Colombier int type, x;
10499ef1f84bSDavid du Colombier
10509ef1f84bSDavid du Colombier if(pcicfgmode == -1)
10519ef1f84bSDavid du Colombier pcicfginit();
10529ef1f84bSDavid du Colombier
10539ef1f84bSDavid du Colombier if(BUSBNO(tbdf))
10549ef1f84bSDavid du Colombier type = 0x01;
10559ef1f84bSDavid du Colombier else
10569ef1f84bSDavid du Colombier type = 0x00;
10579ef1f84bSDavid du Colombier x = -1;
10589ef1f84bSDavid du Colombier if(BUSDNO(tbdf) > pcimaxdno)
10599ef1f84bSDavid du Colombier return x;
10609ef1f84bSDavid du Colombier
10619ef1f84bSDavid du Colombier lock(&pcicfglock);
10629ef1f84bSDavid du Colombier switch(pcicfgmode){
10639ef1f84bSDavid du Colombier
10649ef1f84bSDavid du Colombier case 1:
10659ef1f84bSDavid du Colombier rno &= ~0x03;
10669ef1f84bSDavid du Colombier outl(PciADDR, 0x80000000|BUSBDF(tbdf)|rno|type);
10679ef1f84bSDavid du Colombier if(read)
10689ef1f84bSDavid du Colombier x = inl(PciDATA);
10699ef1f84bSDavid du Colombier else
10709ef1f84bSDavid du Colombier outl(PciDATA, data);
10719ef1f84bSDavid du Colombier outl(PciADDR, 0);
10729ef1f84bSDavid du Colombier break;
10739ef1f84bSDavid du Colombier
10749ef1f84bSDavid du Colombier case 2:
10759ef1f84bSDavid du Colombier outb(PciCSE, 0x80|(BUSFNO(tbdf)<<1));
10769ef1f84bSDavid du Colombier outb(PciFORWARD, BUSBNO(tbdf));
10779ef1f84bSDavid du Colombier if(read)
10789ef1f84bSDavid du Colombier x = inl((0xC000|(BUSDNO(tbdf)<<8)) + rno);
10799ef1f84bSDavid du Colombier else
10809ef1f84bSDavid du Colombier outl((0xC000|(BUSDNO(tbdf)<<8)) + rno, data);
10819ef1f84bSDavid du Colombier outb(PciCSE, 0);
10829ef1f84bSDavid du Colombier break;
10839ef1f84bSDavid du Colombier }
10849ef1f84bSDavid du Colombier unlock(&pcicfglock);
10859ef1f84bSDavid du Colombier
10869ef1f84bSDavid du Colombier return x;
10879ef1f84bSDavid du Colombier }
10889ef1f84bSDavid du Colombier
10899ef1f84bSDavid du Colombier int
pcicfgr32(Pcidev * pcidev,int rno)10909ef1f84bSDavid du Colombier pcicfgr32(Pcidev* pcidev, int rno)
10919ef1f84bSDavid du Colombier {
10929ef1f84bSDavid du Colombier return pcicfgrw32(pcidev->tbdf, rno, 0, 1);
10939ef1f84bSDavid du Colombier }
10949ef1f84bSDavid du Colombier
10959ef1f84bSDavid du Colombier void
pcicfgw32(Pcidev * pcidev,int rno,int data)10969ef1f84bSDavid du Colombier pcicfgw32(Pcidev* pcidev, int rno, int data)
10979ef1f84bSDavid du Colombier {
10989ef1f84bSDavid du Colombier pcicfgrw32(pcidev->tbdf, rno, data, 0);
10999ef1f84bSDavid du Colombier }
11009ef1f84bSDavid du Colombier
11019ef1f84bSDavid du Colombier Pcidev*
pcimatch(Pcidev * prev,int vid,int did)11029ef1f84bSDavid du Colombier pcimatch(Pcidev* prev, int vid, int did)
11039ef1f84bSDavid du Colombier {
11049ef1f84bSDavid du Colombier if(pcicfgmode == -1)
11059ef1f84bSDavid du Colombier pcicfginit();
11069ef1f84bSDavid du Colombier
11079ef1f84bSDavid du Colombier if(prev == nil)
11089ef1f84bSDavid du Colombier prev = pcilist;
11099ef1f84bSDavid du Colombier else
11109ef1f84bSDavid du Colombier prev = prev->list;
11119ef1f84bSDavid du Colombier
11129ef1f84bSDavid du Colombier while(prev != nil){
11139ef1f84bSDavid du Colombier if((vid == 0 || prev->vid == vid)
11149ef1f84bSDavid du Colombier && (did == 0 || prev->did == did))
11159ef1f84bSDavid du Colombier break;
11169ef1f84bSDavid du Colombier prev = prev->list;
11179ef1f84bSDavid du Colombier }
11189ef1f84bSDavid du Colombier return prev;
11199ef1f84bSDavid du Colombier }
11209ef1f84bSDavid du Colombier
11219ef1f84bSDavid du Colombier Pcidev*
pcimatchtbdf(int tbdf)11229ef1f84bSDavid du Colombier pcimatchtbdf(int tbdf)
11239ef1f84bSDavid du Colombier {
11249ef1f84bSDavid du Colombier Pcidev *pcidev;
11259ef1f84bSDavid du Colombier
11269ef1f84bSDavid du Colombier if(pcicfgmode == -1)
11279ef1f84bSDavid du Colombier pcicfginit();
11289ef1f84bSDavid du Colombier
11299ef1f84bSDavid du Colombier for(pcidev = pcilist; pcidev != nil; pcidev = pcidev->list) {
11309ef1f84bSDavid du Colombier if(pcidev->tbdf == tbdf)
11319ef1f84bSDavid du Colombier break;
11329ef1f84bSDavid du Colombier }
11339ef1f84bSDavid du Colombier return pcidev;
11349ef1f84bSDavid du Colombier }
11359ef1f84bSDavid du Colombier
11369ef1f84bSDavid du Colombier uchar
pciipin(Pcidev * pci,uchar pin)11379ef1f84bSDavid du Colombier pciipin(Pcidev *pci, uchar pin)
11389ef1f84bSDavid du Colombier {
11399ef1f84bSDavid du Colombier if (pci == nil)
11409ef1f84bSDavid du Colombier pci = pcilist;
11419ef1f84bSDavid du Colombier
11429ef1f84bSDavid du Colombier while (pci) {
11439ef1f84bSDavid du Colombier uchar intl;
11449ef1f84bSDavid du Colombier
11459ef1f84bSDavid du Colombier if (pcicfgr8(pci, PciINTP) == pin && pci->intl != 0 && pci->intl != 0xff)
11469ef1f84bSDavid du Colombier return pci->intl;
11479ef1f84bSDavid du Colombier
11489ef1f84bSDavid du Colombier if (pci->bridge && (intl = pciipin(pci->bridge, pin)) != 0)
11499ef1f84bSDavid du Colombier return intl;
11509ef1f84bSDavid du Colombier
11519ef1f84bSDavid du Colombier pci = pci->list;
11529ef1f84bSDavid du Colombier }
11539ef1f84bSDavid du Colombier return 0;
11549ef1f84bSDavid du Colombier }
11559ef1f84bSDavid du Colombier
11569ef1f84bSDavid du Colombier static void
pcilhinv(Pcidev * p)11579ef1f84bSDavid du Colombier pcilhinv(Pcidev* p)
11589ef1f84bSDavid du Colombier {
11599ef1f84bSDavid du Colombier int i;
11609ef1f84bSDavid du Colombier Pcidev *t;
11619ef1f84bSDavid du Colombier
11629ef1f84bSDavid du Colombier if(p == nil) {
11639ef1f84bSDavid du Colombier putstrn(PCICONS.output, PCICONS.ptr);
11649ef1f84bSDavid du Colombier p = pciroot;
11659ef1f84bSDavid du Colombier print("bus dev type vid did intl memory\n");
11669ef1f84bSDavid du Colombier }
11679ef1f84bSDavid du Colombier for(t = p; t != nil; t = t->link) {
11689ef1f84bSDavid du Colombier print("%d %2d/%d %.2ux %.2ux %.2ux %.4ux %.4ux %3d ",
11699ef1f84bSDavid du Colombier BUSBNO(t->tbdf), BUSDNO(t->tbdf), BUSFNO(t->tbdf),
11709ef1f84bSDavid du Colombier t->ccrb, t->ccru, t->ccrp, t->vid, t->did, t->intl);
11719ef1f84bSDavid du Colombier
11729ef1f84bSDavid du Colombier for(i = 0; i < nelem(p->mem); i++) {
11739ef1f84bSDavid du Colombier if(t->mem[i].size == 0)
11749ef1f84bSDavid du Colombier continue;
11759ef1f84bSDavid du Colombier print("%d:%.8lux %d ", i,
11769ef1f84bSDavid du Colombier t->mem[i].bar, t->mem[i].size);
11779ef1f84bSDavid du Colombier }
11789ef1f84bSDavid du Colombier if(t->ioa.bar || t->ioa.size)
11799ef1f84bSDavid du Colombier print("ioa:%.8lux %d ", t->ioa.bar, t->ioa.size);
11809ef1f84bSDavid du Colombier if(t->mema.bar || t->mema.size)
11819ef1f84bSDavid du Colombier print("mema:%.8lux %d ", t->mema.bar, t->mema.size);
11829ef1f84bSDavid du Colombier if(t->bridge)
11839ef1f84bSDavid du Colombier print("->%d", BUSBNO(t->bridge->tbdf));
11849ef1f84bSDavid du Colombier print("\n");
11859ef1f84bSDavid du Colombier }
11869ef1f84bSDavid du Colombier while(p != nil) {
11879ef1f84bSDavid du Colombier if(p->bridge != nil)
11889ef1f84bSDavid du Colombier pcilhinv(p->bridge);
11899ef1f84bSDavid du Colombier p = p->link;
11909ef1f84bSDavid du Colombier }
11919ef1f84bSDavid du Colombier }
11929ef1f84bSDavid du Colombier
11939ef1f84bSDavid du Colombier void
pcihinv(Pcidev * p)11949ef1f84bSDavid du Colombier pcihinv(Pcidev* p)
11959ef1f84bSDavid du Colombier {
11969ef1f84bSDavid du Colombier if(pcicfgmode == -1)
11979ef1f84bSDavid du Colombier pcicfginit();
11989ef1f84bSDavid du Colombier lock(&pcicfginitlock);
11999ef1f84bSDavid du Colombier pcilhinv(p);
12009ef1f84bSDavid du Colombier unlock(&pcicfginitlock);
12019ef1f84bSDavid du Colombier }
12029ef1f84bSDavid du Colombier
12039ef1f84bSDavid du Colombier void
pcireset(void)12049ef1f84bSDavid du Colombier pcireset(void)
12059ef1f84bSDavid du Colombier {
12069ef1f84bSDavid du Colombier Pcidev *p;
12079ef1f84bSDavid du Colombier
12089ef1f84bSDavid du Colombier if(pcicfgmode == -1)
12099ef1f84bSDavid du Colombier pcicfginit();
12109ef1f84bSDavid du Colombier
12119ef1f84bSDavid du Colombier for(p = pcilist; p != nil; p = p->list) {
12129ef1f84bSDavid du Colombier /* don't mess with the bridges */
12139ef1f84bSDavid du Colombier if(p->ccrb == 0x06)
12149ef1f84bSDavid du Colombier continue;
12159ef1f84bSDavid du Colombier pciclrbme(p);
12169ef1f84bSDavid du Colombier }
12179ef1f84bSDavid du Colombier }
12189ef1f84bSDavid du Colombier
12199ef1f84bSDavid du Colombier void
pcisetioe(Pcidev * p)12209ef1f84bSDavid du Colombier pcisetioe(Pcidev* p)
12219ef1f84bSDavid du Colombier {
12229ef1f84bSDavid du Colombier p->pcr |= IOen;
12239ef1f84bSDavid du Colombier pcicfgw16(p, PciPCR, p->pcr);
12249ef1f84bSDavid du Colombier }
12259ef1f84bSDavid du Colombier
12269ef1f84bSDavid du Colombier void
pciclrioe(Pcidev * p)12279ef1f84bSDavid du Colombier pciclrioe(Pcidev* p)
12289ef1f84bSDavid du Colombier {
12299ef1f84bSDavid du Colombier p->pcr &= ~IOen;
12309ef1f84bSDavid du Colombier pcicfgw16(p, PciPCR, p->pcr);
12319ef1f84bSDavid du Colombier }
12329ef1f84bSDavid du Colombier
12339ef1f84bSDavid du Colombier void
pcisetbme(Pcidev * p)12349ef1f84bSDavid du Colombier pcisetbme(Pcidev* p)
12359ef1f84bSDavid du Colombier {
12369ef1f84bSDavid du Colombier p->pcr |= MASen;
12379ef1f84bSDavid du Colombier pcicfgw16(p, PciPCR, p->pcr);
12389ef1f84bSDavid du Colombier }
12399ef1f84bSDavid du Colombier
12409ef1f84bSDavid du Colombier void
pciclrbme(Pcidev * p)12419ef1f84bSDavid du Colombier pciclrbme(Pcidev* p)
12429ef1f84bSDavid du Colombier {
12439ef1f84bSDavid du Colombier p->pcr &= ~MASen;
12449ef1f84bSDavid du Colombier pcicfgw16(p, PciPCR, p->pcr);
12459ef1f84bSDavid du Colombier }
12469ef1f84bSDavid du Colombier
12479ef1f84bSDavid du Colombier void
pcisetmwi(Pcidev * p)12489ef1f84bSDavid du Colombier pcisetmwi(Pcidev* p)
12499ef1f84bSDavid du Colombier {
12509ef1f84bSDavid du Colombier p->pcr |= MemWrInv;
12519ef1f84bSDavid du Colombier pcicfgw16(p, PciPCR, p->pcr);
12529ef1f84bSDavid du Colombier }
12539ef1f84bSDavid du Colombier
12549ef1f84bSDavid du Colombier void
pciclrmwi(Pcidev * p)12559ef1f84bSDavid du Colombier pciclrmwi(Pcidev* p)
12569ef1f84bSDavid du Colombier {
12579ef1f84bSDavid du Colombier p->pcr &= ~MemWrInv;
12589ef1f84bSDavid du Colombier pcicfgw16(p, PciPCR, p->pcr);
12599ef1f84bSDavid du Colombier }
12609ef1f84bSDavid du Colombier
12618547cd99SDavid du Colombier int
pcienumcaps(Pcidev * p,int (* fmatch)(Pcidev *,int,int,int),int arg)1262*da317bb8SDavid du Colombier pcienumcaps(Pcidev* p, int (*fmatch)(Pcidev*, int, int, int), int arg)
12639ef1f84bSDavid du Colombier {
1264*da317bb8SDavid du Colombier int i, r, cap, off;
12659ef1f84bSDavid du Colombier
12668547cd99SDavid du Colombier /* status register bit 4 has capabilities */
12678547cd99SDavid du Colombier if((pcicfgr16(p, PciPSR) & 1<<4) == 0)
12689ef1f84bSDavid du Colombier return -1;
12698547cd99SDavid du Colombier switch(pcicfgr8(p, PciHDT) & 0x7f){
12709ef1f84bSDavid du Colombier default:
12719ef1f84bSDavid du Colombier return -1;
12729ef1f84bSDavid du Colombier case 0: /* all other */
12739ef1f84bSDavid du Colombier case 1: /* PCI to PCI bridge */
12748547cd99SDavid du Colombier off = PciCP;
12759ef1f84bSDavid du Colombier break;
12769ef1f84bSDavid du Colombier case 2: /* CardBus bridge */
12778547cd99SDavid du Colombier off = 0x14;
12789ef1f84bSDavid du Colombier break;
12799ef1f84bSDavid du Colombier }
12808547cd99SDavid du Colombier for(i = 48; i--;){
12818547cd99SDavid du Colombier off = pcicfgr8(p, off);
12828547cd99SDavid du Colombier if(off < 0x40 || (off & 3))
12838547cd99SDavid du Colombier break;
12848547cd99SDavid du Colombier off &= ~3;
1285*da317bb8SDavid du Colombier cap = pcicfgr8(p, off);
1286*da317bb8SDavid du Colombier if(cap == 0xff)
12878547cd99SDavid du Colombier break;
1288*da317bb8SDavid du Colombier r = (*fmatch)(p, cap, off, arg);
1289*da317bb8SDavid du Colombier if(r < 0)
1290*da317bb8SDavid du Colombier break;
1291*da317bb8SDavid du Colombier if(r == 0)
12928547cd99SDavid du Colombier return off;
12938547cd99SDavid du Colombier off++;
12949ef1f84bSDavid du Colombier }
12959ef1f84bSDavid du Colombier
12969ef1f84bSDavid du Colombier return -1;
12979ef1f84bSDavid du Colombier }
12989ef1f84bSDavid du Colombier
1299*da317bb8SDavid du Colombier static int
matchcap(Pcidev *,int cap,int,int arg)1300*da317bb8SDavid du Colombier matchcap(Pcidev*, int cap, int, int arg)
1301*da317bb8SDavid du Colombier {
1302*da317bb8SDavid du Colombier return cap != arg;
1303*da317bb8SDavid du Colombier }
1304*da317bb8SDavid du Colombier
1305*da317bb8SDavid du Colombier static int
matchhtcap(Pcidev * p,int cap,int off,int arg)1306*da317bb8SDavid du Colombier matchhtcap(Pcidev* p, int cap, int off, int arg)
1307*da317bb8SDavid du Colombier {
1308*da317bb8SDavid du Colombier int mask;
1309*da317bb8SDavid du Colombier
1310*da317bb8SDavid du Colombier if(cap != PciCapHTC)
1311*da317bb8SDavid du Colombier return 1;
1312*da317bb8SDavid du Colombier if(arg == 0x00 || arg == 0x20)
1313*da317bb8SDavid du Colombier mask = 0xE0;
1314*da317bb8SDavid du Colombier else
1315*da317bb8SDavid du Colombier mask = 0xF8;
1316*da317bb8SDavid du Colombier cap = pcicfgr8(p, off+3);
1317*da317bb8SDavid du Colombier return (cap & mask) != arg;
1318*da317bb8SDavid du Colombier }
1319*da317bb8SDavid du Colombier
1320*da317bb8SDavid du Colombier int
pcicap(Pcidev * p,int cap)1321*da317bb8SDavid du Colombier pcicap(Pcidev* p, int cap)
1322*da317bb8SDavid du Colombier {
1323*da317bb8SDavid du Colombier return pcienumcaps(p, matchcap, cap);
1324*da317bb8SDavid du Colombier }
1325*da317bb8SDavid du Colombier
1326*da317bb8SDavid du Colombier int
pcihtcap(Pcidev * p,int cap)1327*da317bb8SDavid du Colombier pcihtcap(Pcidev* p, int cap)
1328*da317bb8SDavid du Colombier {
1329*da317bb8SDavid du Colombier return pcienumcaps(p, matchhtcap, cap);
1330*da317bb8SDavid du Colombier }
1331*da317bb8SDavid du Colombier
13329ef1f84bSDavid du Colombier int
pcigetpms(Pcidev * p)13339ef1f84bSDavid du Colombier pcigetpms(Pcidev* p)
13349ef1f84bSDavid du Colombier {
13359ef1f84bSDavid du Colombier int pmcsr, ptr;
13369ef1f84bSDavid du Colombier
13378547cd99SDavid du Colombier if((ptr = pcicap(p, PciCapPMG)) == -1)
13389ef1f84bSDavid du Colombier return -1;
13399ef1f84bSDavid du Colombier
13409ef1f84bSDavid du Colombier /*
13419ef1f84bSDavid du Colombier * Power Management Register Block:
13429ef1f84bSDavid du Colombier * offset 0: Capability ID
13439ef1f84bSDavid du Colombier * 1: next item pointer
13449ef1f84bSDavid du Colombier * 2: capabilities
13459ef1f84bSDavid du Colombier * 4: control/status
13469ef1f84bSDavid du Colombier * 6: bridge support extensions
13479ef1f84bSDavid du Colombier * 7: data
13489ef1f84bSDavid du Colombier */
13499ef1f84bSDavid du Colombier pmcsr = pcicfgr16(p, ptr+4);
13509ef1f84bSDavid du Colombier
13519ef1f84bSDavid du Colombier return pmcsr & 0x0003;
13529ef1f84bSDavid du Colombier }
13539ef1f84bSDavid du Colombier
13549ef1f84bSDavid du Colombier int
pcisetpms(Pcidev * p,int state)13559ef1f84bSDavid du Colombier pcisetpms(Pcidev* p, int state)
13569ef1f84bSDavid du Colombier {
13579ef1f84bSDavid du Colombier int ostate, pmc, pmcsr, ptr;
13589ef1f84bSDavid du Colombier
13598547cd99SDavid du Colombier if((ptr = pcicap(p, PciCapPMG)) == -1)
13609ef1f84bSDavid du Colombier return -1;
13619ef1f84bSDavid du Colombier
13629ef1f84bSDavid du Colombier pmc = pcicfgr16(p, ptr+2);
13639ef1f84bSDavid du Colombier pmcsr = pcicfgr16(p, ptr+4);
13649ef1f84bSDavid du Colombier ostate = pmcsr & 0x0003;
13659ef1f84bSDavid du Colombier pmcsr &= ~0x0003;
13669ef1f84bSDavid du Colombier
13679ef1f84bSDavid du Colombier switch(state){
13689ef1f84bSDavid du Colombier default:
13699ef1f84bSDavid du Colombier return -1;
13709ef1f84bSDavid du Colombier case 0:
13719ef1f84bSDavid du Colombier break;
13729ef1f84bSDavid du Colombier case 1:
13739ef1f84bSDavid du Colombier if(!(pmc & 0x0200))
13749ef1f84bSDavid du Colombier return -1;
13759ef1f84bSDavid du Colombier break;
13769ef1f84bSDavid du Colombier case 2:
13779ef1f84bSDavid du Colombier if(!(pmc & 0x0400))
13789ef1f84bSDavid du Colombier return -1;
13799ef1f84bSDavid du Colombier break;
13809ef1f84bSDavid du Colombier case 3:
13819ef1f84bSDavid du Colombier break;
13829ef1f84bSDavid du Colombier }
13839ef1f84bSDavid du Colombier pmcsr |= state;
13849ef1f84bSDavid du Colombier pcicfgw16(p, ptr+4, pmcsr);
13859ef1f84bSDavid du Colombier
13869ef1f84bSDavid du Colombier return ostate;
13879ef1f84bSDavid du Colombier }
1388