19a747e4fSDavid du Colombier /*
29a747e4fSDavid du Colombier * PCI support code.
39a747e4fSDavid du Colombier */
49a747e4fSDavid du Colombier #include "u.h"
59a747e4fSDavid du Colombier #include "../port/lib.h"
69a747e4fSDavid du Colombier #include "mem.h"
79a747e4fSDavid du Colombier #include "dat.h"
89a747e4fSDavid du Colombier #include "fns.h"
99a747e4fSDavid du Colombier #include "io.h"
109a747e4fSDavid du Colombier #include "../port/error.h"
119a747e4fSDavid du Colombier
129a747e4fSDavid du Colombier #define DBG if(0) pcilog
139a747e4fSDavid du Colombier
149a747e4fSDavid du Colombier struct
159a747e4fSDavid du Colombier {
169a747e4fSDavid du Colombier char output[16384];
179a747e4fSDavid du Colombier int ptr;
189a747e4fSDavid du Colombier }PCICONS;
199a747e4fSDavid du Colombier
209a747e4fSDavid du Colombier int
pcilog(char * fmt,...)219a747e4fSDavid du Colombier pcilog(char *fmt, ...)
229a747e4fSDavid du Colombier {
239a747e4fSDavid du Colombier int n;
249a747e4fSDavid du Colombier va_list arg;
259a747e4fSDavid du Colombier char buf[PRINTSIZE];
269a747e4fSDavid du Colombier
279a747e4fSDavid du Colombier va_start(arg, fmt);
289a747e4fSDavid du Colombier n = vseprint(buf, buf+sizeof(buf), fmt, arg) - buf;
299a747e4fSDavid du Colombier va_end(arg);
309a747e4fSDavid du Colombier
319a747e4fSDavid du Colombier memmove(PCICONS.output+PCICONS.ptr, buf, n);
329a747e4fSDavid du Colombier PCICONS.ptr += n;
339a747e4fSDavid du Colombier return n;
349a747e4fSDavid du Colombier }
359a747e4fSDavid du Colombier
369a747e4fSDavid du Colombier enum
379a747e4fSDavid du Colombier { /* configuration mechanism #1 */
389a747e4fSDavid du Colombier PciADDR = 0xCF8, /* CONFIG_ADDRESS */
399a747e4fSDavid du Colombier PciDATA = 0xCFC, /* CONFIG_DATA */
409a747e4fSDavid du Colombier
419a747e4fSDavid du Colombier /* configuration mechanism #2 */
429a747e4fSDavid du Colombier PciCSE = 0xCF8, /* configuration space enable */
439a747e4fSDavid du Colombier PciFORWARD = 0xCFA, /* which bus */
449a747e4fSDavid du Colombier
459a747e4fSDavid du Colombier MaxFNO = 7,
469a747e4fSDavid du Colombier MaxUBN = 255,
479a747e4fSDavid du Colombier };
489a747e4fSDavid du Colombier
499a747e4fSDavid du Colombier enum
509a747e4fSDavid du Colombier { /* command register */
519a747e4fSDavid du Colombier IOen = (1<<0),
529a747e4fSDavid du Colombier MEMen = (1<<1),
539a747e4fSDavid du Colombier MASen = (1<<2),
549a747e4fSDavid du Colombier MemWrInv = (1<<4),
559a747e4fSDavid du Colombier PErrEn = (1<<6),
569a747e4fSDavid du Colombier SErrEn = (1<<8),
579a747e4fSDavid du Colombier };
589a747e4fSDavid du Colombier
599a747e4fSDavid du Colombier static Lock pcicfglock;
609a747e4fSDavid du Colombier static QLock pcicfginitlock;
619a747e4fSDavid du Colombier static int pcicfgmode = -1;
629a747e4fSDavid du Colombier static int pcimaxbno = 7;
639a747e4fSDavid du Colombier static int pcimaxdno;
649a747e4fSDavid du Colombier static Pcidev* pciroot;
659a747e4fSDavid du Colombier static Pcidev* pcilist;
669a747e4fSDavid du Colombier static Pcidev* pcitail;
679a747e4fSDavid du Colombier
689a747e4fSDavid du Colombier static int pcicfgrw32(int, int, int, int);
699a747e4fSDavid du Colombier static int pcicfgrw8(int, int, int, int);
709a747e4fSDavid du Colombier
719a747e4fSDavid du Colombier static char* bustypes[] = {
729a747e4fSDavid du Colombier "CBUSI",
739a747e4fSDavid du Colombier "CBUSII",
749a747e4fSDavid du Colombier "EISA",
759a747e4fSDavid du Colombier "FUTURE",
769a747e4fSDavid du Colombier "INTERN",
779a747e4fSDavid du Colombier "ISA",
789a747e4fSDavid du Colombier "MBI",
799a747e4fSDavid du Colombier "MBII",
809a747e4fSDavid du Colombier "MCA",
819a747e4fSDavid du Colombier "MPI",
829a747e4fSDavid du Colombier "MPSA",
839a747e4fSDavid du Colombier "NUBUS",
849a747e4fSDavid du Colombier "PCI",
859a747e4fSDavid du Colombier "PCMCIA",
869a747e4fSDavid du Colombier "TC",
879a747e4fSDavid du Colombier "VL",
889a747e4fSDavid du Colombier "VME",
899a747e4fSDavid du Colombier "XPRESS",
909a747e4fSDavid du Colombier };
919a747e4fSDavid du Colombier
929a747e4fSDavid du Colombier #pragma varargck type "T" int
939a747e4fSDavid du Colombier
949a747e4fSDavid du Colombier static int
tbdffmt(Fmt * fmt)959a747e4fSDavid du Colombier tbdffmt(Fmt* fmt)
969a747e4fSDavid du Colombier {
979a747e4fSDavid du Colombier char *p;
989a747e4fSDavid du Colombier int l, r, type, tbdf;
999a747e4fSDavid du Colombier
1009a747e4fSDavid du Colombier if((p = malloc(READSTR)) == nil)
1019a747e4fSDavid du Colombier return fmtstrcpy(fmt, "(tbdfconv)");
1029a747e4fSDavid du Colombier
1039a747e4fSDavid du Colombier switch(fmt->r){
1049a747e4fSDavid du Colombier case 'T':
1059a747e4fSDavid du Colombier tbdf = va_arg(fmt->args, int);
1069a747e4fSDavid du Colombier type = BUSTYPE(tbdf);
1079a747e4fSDavid du Colombier if(type < nelem(bustypes))
1089a747e4fSDavid du Colombier l = snprint(p, READSTR, bustypes[type]);
1099a747e4fSDavid du Colombier else
1109a747e4fSDavid du Colombier l = snprint(p, READSTR, "%d", type);
1119a747e4fSDavid du Colombier snprint(p+l, READSTR-l, ".%d.%d.%d",
1129a747e4fSDavid du Colombier BUSBNO(tbdf), BUSDNO(tbdf), BUSFNO(tbdf));
1139a747e4fSDavid du Colombier break;
1149a747e4fSDavid du Colombier
1159a747e4fSDavid du Colombier default:
1169a747e4fSDavid du Colombier snprint(p, READSTR, "(tbdfconv)");
1179a747e4fSDavid du Colombier break;
1189a747e4fSDavid du Colombier }
1199a747e4fSDavid du Colombier r = fmtstrcpy(fmt, p);
1209a747e4fSDavid du Colombier free(p);
1219a747e4fSDavid du Colombier
1229a747e4fSDavid du Colombier return r;
1239a747e4fSDavid du Colombier }
1249a747e4fSDavid du Colombier
1259a747e4fSDavid du Colombier ulong
pcibarsize(Pcidev * p,int rno)1269a747e4fSDavid du Colombier pcibarsize(Pcidev *p, int rno)
1279a747e4fSDavid du Colombier {
1289a747e4fSDavid du Colombier ulong v, size;
1299a747e4fSDavid du Colombier
1309a747e4fSDavid du Colombier v = pcicfgrw32(p->tbdf, rno, 0, 1);
1319a747e4fSDavid du Colombier pcicfgrw32(p->tbdf, rno, 0xFFFFFFF0, 0);
1329a747e4fSDavid du Colombier size = pcicfgrw32(p->tbdf, rno, 0, 1);
1339a747e4fSDavid du Colombier if(v & 1)
1349a747e4fSDavid du Colombier size |= 0xFFFF0000;
1359a747e4fSDavid du Colombier pcicfgrw32(p->tbdf, rno, v, 0);
1369a747e4fSDavid du Colombier
1379a747e4fSDavid du Colombier return -(size & ~0x0F);
1389a747e4fSDavid du Colombier }
1399a747e4fSDavid du Colombier
1409a747e4fSDavid du Colombier static int
pcisizcmp(void * a,void * b)1419a747e4fSDavid du Colombier pcisizcmp(void *a, void *b)
1429a747e4fSDavid du Colombier {
1439a747e4fSDavid du Colombier Pcisiz *aa, *bb;
1449a747e4fSDavid du Colombier
1459a747e4fSDavid du Colombier aa = a;
1469a747e4fSDavid du Colombier bb = b;
1479a747e4fSDavid du Colombier return aa->siz - bb->siz;
1489a747e4fSDavid du Colombier }
1499a747e4fSDavid du Colombier
1509a747e4fSDavid du Colombier static ulong
pcimask(ulong v)1519a747e4fSDavid du Colombier pcimask(ulong v)
1529a747e4fSDavid du Colombier {
1539a747e4fSDavid du Colombier ulong m;
1549a747e4fSDavid du Colombier
1559a747e4fSDavid du Colombier m = BI2BY*sizeof(v);
1569a747e4fSDavid du Colombier for(m = 1<<(m-1); m != 0; m >>= 1) {
1579a747e4fSDavid du Colombier if(m & v)
1589a747e4fSDavid du Colombier break;
1599a747e4fSDavid du Colombier }
1609a747e4fSDavid du Colombier
1619a747e4fSDavid du Colombier m--;
1629a747e4fSDavid du Colombier if((v & m) == 0)
1639a747e4fSDavid du Colombier return v;
1649a747e4fSDavid du Colombier
1659a747e4fSDavid du Colombier v |= m;
1669a747e4fSDavid du Colombier return v+1;
1679a747e4fSDavid du Colombier }
1689a747e4fSDavid du Colombier
1699a747e4fSDavid du Colombier static void
pcibusmap(Pcidev * root,ulong * pmema,ulong * pioa,int wrreg)1709a747e4fSDavid du Colombier pcibusmap(Pcidev *root, ulong *pmema, ulong *pioa, int wrreg)
1719a747e4fSDavid du Colombier {
1729a747e4fSDavid du Colombier Pcidev *p;
1739a747e4fSDavid du Colombier int ntb, i, size, rno, hole;
1749a747e4fSDavid du Colombier ulong v, mema, ioa, sioa, smema, base, limit;
1759a747e4fSDavid du Colombier Pcisiz *table, *tptr, *mtb, *itb;
1769a747e4fSDavid du Colombier extern void qsort(void*, long, long, int (*)(void*, void*));
1779a747e4fSDavid du Colombier
1789a747e4fSDavid du Colombier ioa = *pioa;
1799a747e4fSDavid du Colombier mema = *pmema;
1809a747e4fSDavid du Colombier
1819a747e4fSDavid du Colombier DBG("pcibusmap wr=%d %T mem=%luX io=%luX\n",
1829a747e4fSDavid du Colombier wrreg, root->tbdf, mema, ioa);
1839a747e4fSDavid du Colombier
1849a747e4fSDavid du Colombier ntb = 0;
1859a747e4fSDavid du Colombier for(p = root; p != nil; p = p->link)
1869a747e4fSDavid du Colombier ntb++;
1879a747e4fSDavid du Colombier
1889a747e4fSDavid du Colombier ntb *= (PciCIS-PciBAR0)/4;
1899a747e4fSDavid du Colombier table = malloc(2*ntb*sizeof(Pcisiz));
1909a747e4fSDavid du Colombier itb = table;
1919a747e4fSDavid du Colombier mtb = table+ntb;
1929a747e4fSDavid du Colombier
1939a747e4fSDavid du Colombier /*
1949a747e4fSDavid du Colombier * Build a table of sizes
1959a747e4fSDavid du Colombier */
1969a747e4fSDavid du Colombier for(p = root; p != nil; p = p->link) {
1979a747e4fSDavid du Colombier if(p->ccrb == 0x06) {
1989a747e4fSDavid du Colombier if(p->ccru == 0x04 && p->bridge != nil) {
1999a747e4fSDavid du Colombier sioa = ioa;
2009a747e4fSDavid du Colombier smema = mema;
2019a747e4fSDavid du Colombier pcibusmap(p->bridge, &smema, &sioa, 0);
2029a747e4fSDavid du Colombier
2039a747e4fSDavid du Colombier hole = pcimask(smema-mema);
2049a747e4fSDavid du Colombier if(hole < (1<<20))
2059a747e4fSDavid du Colombier hole = 1<<20;
2069a747e4fSDavid du Colombier p->mema.size = hole;
2079a747e4fSDavid du Colombier
2089a747e4fSDavid du Colombier hole = pcimask(sioa-ioa);
2099a747e4fSDavid du Colombier if(hole < (1<<12))
2109a747e4fSDavid du Colombier hole = 1<<12;
2119a747e4fSDavid du Colombier
2129a747e4fSDavid du Colombier p->ioa.size = hole;
2139a747e4fSDavid du Colombier
2149a747e4fSDavid du Colombier itb->dev = p;
2159a747e4fSDavid du Colombier itb->bar = -1;
2169a747e4fSDavid du Colombier itb->siz = p->ioa.size;
2179a747e4fSDavid du Colombier itb++;
2189a747e4fSDavid du Colombier
2199a747e4fSDavid du Colombier mtb->dev = p;
2209a747e4fSDavid du Colombier mtb->bar = -1;
2219a747e4fSDavid du Colombier mtb->siz = p->mema.size;
2229a747e4fSDavid du Colombier mtb++;
2239a747e4fSDavid du Colombier }
2249a747e4fSDavid du Colombier if((pcicfgr8(p, PciHDT)&0x7f) != 0)
2259a747e4fSDavid du Colombier continue;
2269a747e4fSDavid du Colombier }
2279a747e4fSDavid du Colombier
2289a747e4fSDavid du Colombier for(i = 0; i <= 5; i++) {
2299a747e4fSDavid du Colombier rno = PciBAR0 + i*4;
2309a747e4fSDavid du Colombier v = pcicfgrw32(p->tbdf, rno, 0, 1);
2319a747e4fSDavid du Colombier size = pcibarsize(p, rno);
2329a747e4fSDavid du Colombier if(size == 0)
2339a747e4fSDavid du Colombier continue;
2349a747e4fSDavid du Colombier
2359a747e4fSDavid du Colombier if(v & 1) {
2369a747e4fSDavid du Colombier itb->dev = p;
2379a747e4fSDavid du Colombier itb->bar = i;
2389a747e4fSDavid du Colombier itb->siz = size;
2399a747e4fSDavid du Colombier itb++;
2409a747e4fSDavid du Colombier }
2419a747e4fSDavid du Colombier else {
2429a747e4fSDavid du Colombier mtb->dev = p;
2439a747e4fSDavid du Colombier mtb->bar = i;
2449a747e4fSDavid du Colombier mtb->siz = size;
2459a747e4fSDavid du Colombier mtb++;
2469a747e4fSDavid du Colombier }
2479a747e4fSDavid du Colombier
2489a747e4fSDavid du Colombier p->mem[i].size = size;
2499a747e4fSDavid du Colombier }
2509a747e4fSDavid du Colombier }
2519a747e4fSDavid du Colombier
2529a747e4fSDavid du Colombier /*
2539a747e4fSDavid du Colombier * Sort both tables IO smallest first, Memory largest
2549a747e4fSDavid du Colombier */
2559a747e4fSDavid du Colombier qsort(table, itb-table, sizeof(Pcisiz), pcisizcmp);
2569a747e4fSDavid du Colombier tptr = table+ntb;
2579a747e4fSDavid du Colombier qsort(tptr, mtb-tptr, sizeof(Pcisiz), pcisizcmp);
2589a747e4fSDavid du Colombier
2599a747e4fSDavid du Colombier /*
2609a747e4fSDavid du Colombier * Allocate IO address space on this bus
2619a747e4fSDavid du Colombier */
2629a747e4fSDavid du Colombier for(tptr = table; tptr < itb; tptr++) {
2639a747e4fSDavid du Colombier hole = tptr->siz;
2649a747e4fSDavid du Colombier if(tptr->bar == -1)
2659a747e4fSDavid du Colombier hole = 1<<12;
2669a747e4fSDavid du Colombier ioa = (ioa+hole-1) & ~(hole-1);
2679a747e4fSDavid du Colombier
2689a747e4fSDavid du Colombier p = tptr->dev;
2699a747e4fSDavid du Colombier if(tptr->bar == -1)
2709a747e4fSDavid du Colombier p->ioa.bar = ioa;
2719a747e4fSDavid du Colombier else {
2729a747e4fSDavid du Colombier p->pcr |= IOen;
2739a747e4fSDavid du Colombier p->mem[tptr->bar].bar = ioa|1;
2749a747e4fSDavid du Colombier if(wrreg)
2759a747e4fSDavid du Colombier pcicfgrw32(p->tbdf, PciBAR0+(tptr->bar*4), ioa|1, 0);
2769a747e4fSDavid du Colombier }
2779a747e4fSDavid du Colombier
2789a747e4fSDavid du Colombier ioa += tptr->siz;
2799a747e4fSDavid du Colombier }
2809a747e4fSDavid du Colombier
2819a747e4fSDavid du Colombier /*
2829a747e4fSDavid du Colombier * Allocate Memory address space on this bus
2839a747e4fSDavid du Colombier */
2849a747e4fSDavid du Colombier for(tptr = table+ntb; tptr < mtb; tptr++) {
2859a747e4fSDavid du Colombier hole = tptr->siz;
2869a747e4fSDavid du Colombier if(tptr->bar == -1)
2879a747e4fSDavid du Colombier hole = 1<<20;
2889a747e4fSDavid du Colombier mema = (mema+hole-1) & ~(hole-1);
2899a747e4fSDavid du Colombier
2909a747e4fSDavid du Colombier p = tptr->dev;
2919a747e4fSDavid du Colombier if(tptr->bar == -1)
2929a747e4fSDavid du Colombier p->mema.bar = mema;
2939a747e4fSDavid du Colombier else {
2949a747e4fSDavid du Colombier p->pcr |= MEMen;
2959a747e4fSDavid du Colombier p->mem[tptr->bar].bar = mema;
2969a747e4fSDavid du Colombier if(wrreg)
2979a747e4fSDavid du Colombier pcicfgrw32(p->tbdf, PciBAR0+(tptr->bar*4), mema, 0);
2989a747e4fSDavid du Colombier }
2999a747e4fSDavid du Colombier mema += tptr->siz;
3009a747e4fSDavid du Colombier }
3019a747e4fSDavid du Colombier
3029a747e4fSDavid du Colombier *pmema = mema;
3039a747e4fSDavid du Colombier *pioa = ioa;
3049a747e4fSDavid du Colombier free(table);
3059a747e4fSDavid du Colombier
3069a747e4fSDavid du Colombier if(wrreg == 0)
3079a747e4fSDavid du Colombier return;
3089a747e4fSDavid du Colombier
3099a747e4fSDavid du Colombier /*
3109a747e4fSDavid du Colombier * Finally set all the bridge addresses & registers
3119a747e4fSDavid du Colombier */
3129a747e4fSDavid du Colombier for(p = root; p != nil; p = p->link) {
3139a747e4fSDavid du Colombier if(p->bridge == nil) {
3149a747e4fSDavid du Colombier pcicfgrw8(p->tbdf, PciLTR, 64, 0);
3159a747e4fSDavid du Colombier
3169a747e4fSDavid du Colombier p->pcr |= MASen;
3179a747e4fSDavid du Colombier pcicfgrw32(p->tbdf, PciPCR, p->pcr, 0);
3189a747e4fSDavid du Colombier continue;
3199a747e4fSDavid du Colombier }
3209a747e4fSDavid du Colombier
3219a747e4fSDavid du Colombier base = p->ioa.bar;
3229a747e4fSDavid du Colombier limit = base+p->ioa.size-1;
323*d0f3faacSDavid du Colombier v = pcicfgrw32(p->tbdf, PciIBR, 0, 1);
3249a747e4fSDavid du Colombier v = (v&0xFFFF0000)|(limit & 0xF000)|((base & 0xF000)>>8);
325*d0f3faacSDavid du Colombier pcicfgrw32(p->tbdf, PciIBR, v, 0);
3269a747e4fSDavid du Colombier v = (limit & 0xFFFF0000)|(base>>16);
327*d0f3faacSDavid du Colombier pcicfgrw32(p->tbdf, PciIUBR, v, 0);
3289a747e4fSDavid du Colombier
3299a747e4fSDavid du Colombier base = p->mema.bar;
3309a747e4fSDavid du Colombier limit = base+p->mema.size-1;
3319a747e4fSDavid du Colombier v = (limit & 0xFFF00000)|((base & 0xFFF00000)>>16);
332*d0f3faacSDavid du Colombier pcicfgrw32(p->tbdf, PciMBR, v, 0);
3339a747e4fSDavid du Colombier
3349a747e4fSDavid du Colombier /*
3359a747e4fSDavid du Colombier * Disable memory prefetch
3369a747e4fSDavid du Colombier */
337*d0f3faacSDavid du Colombier pcicfgrw32(p->tbdf, PciPMBR, 0x0000FFFF, 0);
3389a747e4fSDavid du Colombier pcicfgrw8(p->tbdf, PciLTR, 64, 0);
3399a747e4fSDavid du Colombier
3409a747e4fSDavid du Colombier /*
3419a747e4fSDavid du Colombier * Enable the bridge
3429a747e4fSDavid du Colombier */
3439a747e4fSDavid du Colombier v = 0xFFFF0000 | IOen | MEMen | MASen;
3449a747e4fSDavid du Colombier pcicfgrw32(p->tbdf, PciPCR, v, 0);
3459a747e4fSDavid du Colombier
3469a747e4fSDavid du Colombier sioa = p->ioa.bar;
3479a747e4fSDavid du Colombier smema = p->mema.bar;
3489a747e4fSDavid du Colombier pcibusmap(p->bridge, &smema, &sioa, 1);
3499a747e4fSDavid du Colombier }
3509a747e4fSDavid du Colombier }
3519a747e4fSDavid du Colombier
3529a747e4fSDavid du Colombier static int
pcilscan(int bno,Pcidev ** list)3539a747e4fSDavid du Colombier pcilscan(int bno, Pcidev** list)
3549a747e4fSDavid du Colombier {
3559a747e4fSDavid du Colombier Pcidev *p, *head, *tail;
3569a747e4fSDavid du Colombier int dno, fno, i, hdt, l, maxfno, maxubn, rno, sbn, tbdf, ubn;
3579a747e4fSDavid du Colombier
3589a747e4fSDavid du Colombier maxubn = bno;
3599a747e4fSDavid du Colombier head = nil;
3609a747e4fSDavid du Colombier tail = nil;
3619a747e4fSDavid du Colombier for(dno = 0; dno <= pcimaxdno; dno++){
3629a747e4fSDavid du Colombier maxfno = 0;
3639a747e4fSDavid du Colombier for(fno = 0; fno <= maxfno; fno++){
3649a747e4fSDavid du Colombier /*
3659a747e4fSDavid du Colombier * For this possible device, form the
3669a747e4fSDavid du Colombier * bus+device+function triplet needed to address it
3679a747e4fSDavid du Colombier * and try to read the vendor and device ID.
3689a747e4fSDavid du Colombier * If successful, allocate a device struct and
3699a747e4fSDavid du Colombier * start to fill it in with some useful information
3709a747e4fSDavid du Colombier * from the device's configuration space.
3719a747e4fSDavid du Colombier */
3729a747e4fSDavid du Colombier tbdf = MKBUS(BusPCI, bno, dno, fno);
3739a747e4fSDavid du Colombier l = pcicfgrw32(tbdf, PciVID, 0, 1);
3749a747e4fSDavid du Colombier if(l == 0xFFFFFFFF || l == 0)
3759a747e4fSDavid du Colombier continue;
3769a747e4fSDavid du Colombier p = malloc(sizeof(*p));
3779a747e4fSDavid du Colombier p->tbdf = tbdf;
3789a747e4fSDavid du Colombier p->vid = l;
3799a747e4fSDavid du Colombier p->did = l>>16;
3809a747e4fSDavid du Colombier
3819a747e4fSDavid du Colombier if(pcilist != nil)
3829a747e4fSDavid du Colombier pcitail->list = p;
3839a747e4fSDavid du Colombier else
3849a747e4fSDavid du Colombier pcilist = p;
3859a747e4fSDavid du Colombier pcitail = p;
3869a747e4fSDavid du Colombier
3879a747e4fSDavid du Colombier p->rid = pcicfgr8(p, PciRID);
3889a747e4fSDavid du Colombier p->ccrp = pcicfgr8(p, PciCCRp);
3899a747e4fSDavid du Colombier p->ccru = pcicfgr8(p, PciCCRu);
3909a747e4fSDavid du Colombier p->ccrb = pcicfgr8(p, PciCCRb);
3919a747e4fSDavid du Colombier p->pcr = pcicfgr32(p, PciPCR);
3929a747e4fSDavid du Colombier
3939a747e4fSDavid du Colombier p->intl = pcicfgr8(p, PciINTL);
3949a747e4fSDavid du Colombier
3959a747e4fSDavid du Colombier /*
3969a747e4fSDavid du Colombier * If the device is a multi-function device adjust the
3979a747e4fSDavid du Colombier * loop count so all possible functions are checked.
3989a747e4fSDavid du Colombier */
3999a747e4fSDavid du Colombier hdt = pcicfgr8(p, PciHDT);
4009a747e4fSDavid du Colombier if(hdt & 0x80)
4019a747e4fSDavid du Colombier maxfno = MaxFNO;
4029a747e4fSDavid du Colombier
4039a747e4fSDavid du Colombier /*
4049a747e4fSDavid du Colombier * If appropriate, read the base address registers
4059a747e4fSDavid du Colombier * and work out the sizes.
4069a747e4fSDavid du Colombier */
4079a747e4fSDavid du Colombier switch(p->ccrb) {
4089a747e4fSDavid du Colombier case 0x01: /* mass storage controller */
4099a747e4fSDavid du Colombier case 0x02: /* network controller */
4109a747e4fSDavid du Colombier case 0x03: /* display controller */
4119a747e4fSDavid du Colombier case 0x04: /* multimedia device */
4129a747e4fSDavid du Colombier case 0x06: /* bridge device */
4139a747e4fSDavid du Colombier case 0x07: /* simple comm. controllers */
4149a747e4fSDavid du Colombier case 0x08: /* base system peripherals */
4159a747e4fSDavid du Colombier case 0x09: /* input devices */
4169a747e4fSDavid du Colombier case 0x0A: /* docking stations */
4179a747e4fSDavid du Colombier case 0x0B: /* processors */
4189a747e4fSDavid du Colombier case 0x0C: /* serial bus controllers */
4199a747e4fSDavid du Colombier if((hdt & 0x7F) != 0)
4209a747e4fSDavid du Colombier break;
4219a747e4fSDavid du Colombier rno = PciBAR0 - 4;
4229a747e4fSDavid du Colombier for(i = 0; i < nelem(p->mem); i++) {
4239a747e4fSDavid du Colombier rno += 4;
4249a747e4fSDavid du Colombier p->mem[i].bar = pcicfgr32(p, rno);
4259a747e4fSDavid du Colombier p->mem[i].size = pcibarsize(p, rno);
4269a747e4fSDavid du Colombier }
4279a747e4fSDavid du Colombier break;
4289a747e4fSDavid du Colombier
4299a747e4fSDavid du Colombier case 0x00:
4309a747e4fSDavid du Colombier case 0x05: /* memory controller */
4319a747e4fSDavid du Colombier default:
4329a747e4fSDavid du Colombier break;
4339a747e4fSDavid du Colombier }
4349a747e4fSDavid du Colombier
4359a747e4fSDavid du Colombier if(head != nil)
4369a747e4fSDavid du Colombier tail->link = p;
4379a747e4fSDavid du Colombier else
4389a747e4fSDavid du Colombier head = p;
4399a747e4fSDavid du Colombier tail = p;
4409a747e4fSDavid du Colombier }
4419a747e4fSDavid du Colombier }
4429a747e4fSDavid du Colombier
4439a747e4fSDavid du Colombier *list = head;
4449a747e4fSDavid du Colombier for(p = head; p != nil; p = p->link){
4459a747e4fSDavid du Colombier /*
4469a747e4fSDavid du Colombier * Find PCI-PCI bridges and recursively descend the tree.
4479a747e4fSDavid du Colombier */
4489a747e4fSDavid du Colombier if(p->ccrb != 0x06 || p->ccru != 0x04)
4499a747e4fSDavid du Colombier continue;
4509a747e4fSDavid du Colombier
4519a747e4fSDavid du Colombier /*
4529a747e4fSDavid du Colombier * If the secondary or subordinate bus number is not
4539a747e4fSDavid du Colombier * initialised try to do what the PCI BIOS should have
4549a747e4fSDavid du Colombier * done and fill in the numbers as the tree is descended.
4559a747e4fSDavid du Colombier * On the way down the subordinate bus number is set to
4569a747e4fSDavid du Colombier * the maximum as it's not known how many buses are behind
4579a747e4fSDavid du Colombier * this one; the final value is set on the way back up.
4589a747e4fSDavid du Colombier */
4599a747e4fSDavid du Colombier sbn = pcicfgr8(p, PciSBN);
4609a747e4fSDavid du Colombier ubn = pcicfgr8(p, PciUBN);
4619a747e4fSDavid du Colombier
4629a747e4fSDavid du Colombier if(sbn == 0 || ubn == 0) {
4639a747e4fSDavid du Colombier sbn = maxubn+1;
4649a747e4fSDavid du Colombier /*
4659a747e4fSDavid du Colombier * Make sure memory, I/O and master enables are
4669a747e4fSDavid du Colombier * off, set the primary, secondary and subordinate
4679a747e4fSDavid du Colombier * bus numbers and clear the secondary status before
4689a747e4fSDavid du Colombier * attempting to scan the secondary bus.
4699a747e4fSDavid du Colombier *
4709a747e4fSDavid du Colombier * Initialisation of the bridge should be done here.
4719a747e4fSDavid du Colombier */
4729a747e4fSDavid du Colombier pcicfgw32(p, PciPCR, 0xFFFF0000);
4739a747e4fSDavid du Colombier l = (MaxUBN<<16)|(sbn<<8)|bno;
4749a747e4fSDavid du Colombier pcicfgw32(p, PciPBN, l);
4759a747e4fSDavid du Colombier pcicfgw16(p, PciSPSR, 0xFFFF);
4769a747e4fSDavid du Colombier maxubn = pcilscan(sbn, &p->bridge);
4779a747e4fSDavid du Colombier l = (maxubn<<16)|(sbn<<8)|bno;
4789a747e4fSDavid du Colombier
4799a747e4fSDavid du Colombier pcicfgw32(p, PciPBN, l);
4809a747e4fSDavid du Colombier }
4819a747e4fSDavid du Colombier else {
4829a747e4fSDavid du Colombier maxubn = ubn;
4839a747e4fSDavid du Colombier pcilscan(sbn, &p->bridge);
4849a747e4fSDavid du Colombier }
4859a747e4fSDavid du Colombier }
4869a747e4fSDavid du Colombier
4879a747e4fSDavid du Colombier return maxubn;
4889a747e4fSDavid du Colombier }
4899a747e4fSDavid du Colombier
4909a747e4fSDavid du Colombier int
pciscan(int bno,Pcidev ** list)4919a747e4fSDavid du Colombier pciscan(int bno, Pcidev **list)
4929a747e4fSDavid du Colombier {
4939a747e4fSDavid du Colombier int ubn;
4949a747e4fSDavid du Colombier
4959a747e4fSDavid du Colombier qlock(&pcicfginitlock);
4969a747e4fSDavid du Colombier ubn = pcilscan(bno, list);
4979a747e4fSDavid du Colombier qunlock(&pcicfginitlock);
4989a747e4fSDavid du Colombier return ubn;
4999a747e4fSDavid du Colombier }
5009a747e4fSDavid du Colombier
5019a747e4fSDavid du Colombier static void
pcicfginit(void)5029a747e4fSDavid du Colombier pcicfginit(void)
5039a747e4fSDavid du Colombier {
5049a747e4fSDavid du Colombier char *p;
5059a747e4fSDavid du Colombier int bno;
5069a747e4fSDavid du Colombier Pcidev **list;
5079a747e4fSDavid du Colombier ulong mema, ioa;
5089a747e4fSDavid du Colombier
5099a747e4fSDavid du Colombier qlock(&pcicfginitlock);
5109a747e4fSDavid du Colombier if(pcicfgmode != -1)
5119a747e4fSDavid du Colombier goto out;
5129a747e4fSDavid du Colombier
5139a747e4fSDavid du Colombier /*
5149a747e4fSDavid du Colombier * Try to determine which PCI configuration mode is implemented.
5159a747e4fSDavid du Colombier * Mode2 uses a byte at 0xCF8 and another at 0xCFA; Mode1 uses
5169a747e4fSDavid du Colombier * a DWORD at 0xCF8 and another at 0xCFC and will pass through
5179a747e4fSDavid du Colombier * any non-DWORD accesses as normal I/O cycles. There shouldn't be
5189a747e4fSDavid du Colombier * a device behind these addresses so if Mode2 accesses fail try
5199a747e4fSDavid du Colombier * for Mode1 (which is preferred, Mode2 is deprecated).
5209a747e4fSDavid du Colombier */
5219a747e4fSDavid du Colombier outb(PciCSE, 0);
5229a747e4fSDavid du Colombier if(inb(PciCSE) == 0){
5239a747e4fSDavid du Colombier pcicfgmode = 2;
5249a747e4fSDavid du Colombier pcimaxdno = 15;
5259a747e4fSDavid du Colombier }
5269a747e4fSDavid du Colombier else {
5279a747e4fSDavid du Colombier outl(PciADDR, 0);
5289a747e4fSDavid du Colombier if(inl(PciADDR) == 0){
5299a747e4fSDavid du Colombier pcicfgmode = 1;
5309a747e4fSDavid du Colombier pcimaxdno = 31;
5319a747e4fSDavid du Colombier }
5329a747e4fSDavid du Colombier }
5339a747e4fSDavid du Colombier
5349a747e4fSDavid du Colombier if(pcicfgmode < 0)
5359a747e4fSDavid du Colombier goto out;
5369a747e4fSDavid du Colombier
5379a747e4fSDavid du Colombier fmtinstall('T', tbdffmt);
5389a747e4fSDavid du Colombier
5399a747e4fSDavid du Colombier if(p = getconf("*pcimaxbno"))
5409a747e4fSDavid du Colombier pcimaxbno = strtoul(p, 0, 0);
5419a747e4fSDavid du Colombier if(p = getconf("*pcimaxdno"))
5429a747e4fSDavid du Colombier pcimaxdno = strtoul(p, 0, 0);
5439a747e4fSDavid du Colombier
5449a747e4fSDavid du Colombier list = &pciroot;
5459a747e4fSDavid du Colombier for(bno = 0; bno <= pcimaxbno; bno++) {
5469a747e4fSDavid du Colombier int sbno = bno;
5479a747e4fSDavid du Colombier bno = pcilscan(bno, list);
5489a747e4fSDavid du Colombier
5499a747e4fSDavid du Colombier while(*list)
5509a747e4fSDavid du Colombier list = &(*list)->link;
5519a747e4fSDavid du Colombier
5529a747e4fSDavid du Colombier if (sbno == 0) {
5539a747e4fSDavid du Colombier Pcidev *pci;
5549a747e4fSDavid du Colombier
5559a747e4fSDavid du Colombier /*
5569a747e4fSDavid du Colombier * If we have found a PCI-to-Cardbus bridge, make sure
5579a747e4fSDavid du Colombier * it has no valid mappings anymore.
5589a747e4fSDavid du Colombier */
5599a747e4fSDavid du Colombier pci = pciroot;
5609a747e4fSDavid du Colombier while (pci) {
5619a747e4fSDavid du Colombier if (pci->ccrb == 6 && pci->ccru == 7) {
5629a747e4fSDavid du Colombier ushort bcr;
5639a747e4fSDavid du Colombier
5649a747e4fSDavid du Colombier /* reset the cardbus */
5659a747e4fSDavid du Colombier bcr = pcicfgr16(pci, PciBCR);
5669a747e4fSDavid du Colombier pcicfgw16(pci, PciBCR, 0x40 | bcr);
5679a747e4fSDavid du Colombier delay(50);
5689a747e4fSDavid du Colombier }
5699a747e4fSDavid du Colombier pci = pci->link;
5709a747e4fSDavid du Colombier }
5719a747e4fSDavid du Colombier }
5729a747e4fSDavid du Colombier }
5739a747e4fSDavid du Colombier
5749a747e4fSDavid du Colombier if(pciroot == nil)
5759a747e4fSDavid du Colombier goto out;
5769a747e4fSDavid du Colombier
5779a747e4fSDavid du Colombier /*
5789a747e4fSDavid du Colombier * Work out how big the top bus is
5799a747e4fSDavid du Colombier */
5809a747e4fSDavid du Colombier mema = 0;
5819a747e4fSDavid du Colombier ioa = 0;
5829a747e4fSDavid du Colombier pcibusmap(pciroot, &mema, &ioa, 0);
5839a747e4fSDavid du Colombier
5849a747e4fSDavid du Colombier DBG("Sizes: mem=%8.8lux size=%8.8lux io=%8.8lux\n",
5859a747e4fSDavid du Colombier mema, pcimask(mema), ioa);
5869a747e4fSDavid du Colombier
5879a747e4fSDavid du Colombier /*
5889a747e4fSDavid du Colombier * Align the windows and map it
5899a747e4fSDavid du Colombier */
5909a747e4fSDavid du Colombier ioa = 0x1000;
5919a747e4fSDavid du Colombier mema = 0;
5929a747e4fSDavid du Colombier
5939a747e4fSDavid du Colombier pcilog("Mask sizes: mem=%lux io=%lux\n", mema, ioa);
5949a747e4fSDavid du Colombier
5959a747e4fSDavid du Colombier pcibusmap(pciroot, &mema, &ioa, 1);
5969a747e4fSDavid du Colombier DBG("Sizes2: mem=%lux io=%lux\n", mema, ioa);
5979a747e4fSDavid du Colombier
5989a747e4fSDavid du Colombier out:
5999a747e4fSDavid du Colombier qunlock(&pcicfginitlock);
6009a747e4fSDavid du Colombier }
6019a747e4fSDavid du Colombier
6029a747e4fSDavid du Colombier static int
pcicfgrw8(int tbdf,int rno,int data,int read)6039a747e4fSDavid du Colombier pcicfgrw8(int tbdf, int rno, int data, int read)
6049a747e4fSDavid du Colombier {
6059a747e4fSDavid du Colombier int o, type, x;
6069a747e4fSDavid du Colombier
6079a747e4fSDavid du Colombier if(pcicfgmode == -1)
6089a747e4fSDavid du Colombier pcicfginit();
6099a747e4fSDavid du Colombier
6109a747e4fSDavid du Colombier if(BUSBNO(tbdf))
6119a747e4fSDavid du Colombier type = 0x01;
6129a747e4fSDavid du Colombier else
6139a747e4fSDavid du Colombier type = 0x00;
6149a747e4fSDavid du Colombier x = -1;
6159a747e4fSDavid du Colombier if(BUSDNO(tbdf) > pcimaxdno)
6169a747e4fSDavid du Colombier return x;
6179a747e4fSDavid du Colombier
6189a747e4fSDavid du Colombier lock(&pcicfglock);
6199a747e4fSDavid du Colombier switch(pcicfgmode){
6209a747e4fSDavid du Colombier
6219a747e4fSDavid du Colombier case 1:
6229a747e4fSDavid du Colombier o = rno & 0x03;
6239a747e4fSDavid du Colombier rno &= ~0x03;
6249a747e4fSDavid du Colombier outl(PciADDR, 0x80000000|BUSBDF(tbdf)|rno|type);
6259a747e4fSDavid du Colombier if(read)
6269a747e4fSDavid du Colombier x = inb(PciDATA+o);
6279a747e4fSDavid du Colombier else
6289a747e4fSDavid du Colombier outb(PciDATA+o, data);
6299a747e4fSDavid du Colombier outl(PciADDR, 0);
6309a747e4fSDavid du Colombier break;
6319a747e4fSDavid du Colombier
6329a747e4fSDavid du Colombier case 2:
6339a747e4fSDavid du Colombier outb(PciCSE, 0x80|(BUSFNO(tbdf)<<1));
6349a747e4fSDavid du Colombier outb(PciFORWARD, BUSBNO(tbdf));
6359a747e4fSDavid du Colombier if(read)
6369a747e4fSDavid du Colombier x = inb((0xC000|(BUSDNO(tbdf)<<8)) + rno);
6379a747e4fSDavid du Colombier else
6389a747e4fSDavid du Colombier outb((0xC000|(BUSDNO(tbdf)<<8)) + rno, data);
6399a747e4fSDavid du Colombier outb(PciCSE, 0);
6409a747e4fSDavid du Colombier break;
6419a747e4fSDavid du Colombier }
6429a747e4fSDavid du Colombier unlock(&pcicfglock);
6439a747e4fSDavid du Colombier
6449a747e4fSDavid du Colombier return x;
6459a747e4fSDavid du Colombier }
6469a747e4fSDavid du Colombier
6479a747e4fSDavid du Colombier int
pcicfgr8(Pcidev * pcidev,int rno)6489a747e4fSDavid du Colombier pcicfgr8(Pcidev* pcidev, int rno)
6499a747e4fSDavid du Colombier {
6509a747e4fSDavid du Colombier return pcicfgrw8(pcidev->tbdf, rno, 0, 1);
6519a747e4fSDavid du Colombier }
6529a747e4fSDavid du Colombier
6539a747e4fSDavid du Colombier void
pcicfgw8(Pcidev * pcidev,int rno,int data)6549a747e4fSDavid du Colombier pcicfgw8(Pcidev* pcidev, int rno, int data)
6559a747e4fSDavid du Colombier {
6569a747e4fSDavid du Colombier pcicfgrw8(pcidev->tbdf, rno, data, 0);
6579a747e4fSDavid du Colombier }
6589a747e4fSDavid du Colombier
6599a747e4fSDavid du Colombier static int
pcicfgrw16(int tbdf,int rno,int data,int read)6609a747e4fSDavid du Colombier pcicfgrw16(int tbdf, int rno, int data, int read)
6619a747e4fSDavid du Colombier {
6629a747e4fSDavid du Colombier int o, type, x;
6639a747e4fSDavid du Colombier
6649a747e4fSDavid du Colombier if(pcicfgmode == -1)
6659a747e4fSDavid du Colombier pcicfginit();
6669a747e4fSDavid du Colombier
6679a747e4fSDavid du Colombier if(BUSBNO(tbdf))
6689a747e4fSDavid du Colombier type = 0x01;
6699a747e4fSDavid du Colombier else
6709a747e4fSDavid du Colombier type = 0x00;
6719a747e4fSDavid du Colombier x = -1;
6729a747e4fSDavid du Colombier if(BUSDNO(tbdf) > pcimaxdno)
6739a747e4fSDavid du Colombier return x;
6749a747e4fSDavid du Colombier
6759a747e4fSDavid du Colombier lock(&pcicfglock);
6769a747e4fSDavid du Colombier switch(pcicfgmode){
6779a747e4fSDavid du Colombier
6789a747e4fSDavid du Colombier case 1:
6799a747e4fSDavid du Colombier o = rno & 0x02;
6809a747e4fSDavid du Colombier rno &= ~0x03;
6819a747e4fSDavid du Colombier outl(PciADDR, 0x80000000|BUSBDF(tbdf)|rno|type);
6829a747e4fSDavid du Colombier if(read)
6839a747e4fSDavid du Colombier x = ins(PciDATA+o);
6849a747e4fSDavid du Colombier else
6859a747e4fSDavid du Colombier outs(PciDATA+o, data);
6869a747e4fSDavid du Colombier outl(PciADDR, 0);
6879a747e4fSDavid du Colombier break;
6889a747e4fSDavid du Colombier
6899a747e4fSDavid du Colombier case 2:
6909a747e4fSDavid du Colombier outb(PciCSE, 0x80|(BUSFNO(tbdf)<<1));
6919a747e4fSDavid du Colombier outb(PciFORWARD, BUSBNO(tbdf));
6929a747e4fSDavid du Colombier if(read)
6939a747e4fSDavid du Colombier x = ins((0xC000|(BUSDNO(tbdf)<<8)) + rno);
6949a747e4fSDavid du Colombier else
6959a747e4fSDavid du Colombier outs((0xC000|(BUSDNO(tbdf)<<8)) + rno, data);
6969a747e4fSDavid du Colombier outb(PciCSE, 0);
6979a747e4fSDavid du Colombier break;
6989a747e4fSDavid du Colombier }
6999a747e4fSDavid du Colombier unlock(&pcicfglock);
7009a747e4fSDavid du Colombier
7019a747e4fSDavid du Colombier return x;
7029a747e4fSDavid du Colombier }
7039a747e4fSDavid du Colombier
7049a747e4fSDavid du Colombier int
pcicfgr16(Pcidev * pcidev,int rno)7059a747e4fSDavid du Colombier pcicfgr16(Pcidev* pcidev, int rno)
7069a747e4fSDavid du Colombier {
7079a747e4fSDavid du Colombier return pcicfgrw16(pcidev->tbdf, rno, 0, 1);
7089a747e4fSDavid du Colombier }
7099a747e4fSDavid du Colombier
7109a747e4fSDavid du Colombier void
pcicfgw16(Pcidev * pcidev,int rno,int data)7119a747e4fSDavid du Colombier pcicfgw16(Pcidev* pcidev, int rno, int data)
7129a747e4fSDavid du Colombier {
7139a747e4fSDavid du Colombier pcicfgrw16(pcidev->tbdf, rno, data, 0);
7149a747e4fSDavid du Colombier }
7159a747e4fSDavid du Colombier
7169a747e4fSDavid du Colombier static int
pcicfgrw32(int tbdf,int rno,int data,int read)7179a747e4fSDavid du Colombier pcicfgrw32(int tbdf, int rno, int data, int read)
7189a747e4fSDavid du Colombier {
7199a747e4fSDavid du Colombier int type, x;
7209a747e4fSDavid du Colombier
7219a747e4fSDavid du Colombier if(pcicfgmode == -1)
7229a747e4fSDavid du Colombier pcicfginit();
7239a747e4fSDavid du Colombier
7249a747e4fSDavid du Colombier if(BUSBNO(tbdf))
7259a747e4fSDavid du Colombier type = 0x01;
7269a747e4fSDavid du Colombier else
7279a747e4fSDavid du Colombier type = 0x00;
7289a747e4fSDavid du Colombier x = -1;
7299a747e4fSDavid du Colombier if(BUSDNO(tbdf) > pcimaxdno)
7309a747e4fSDavid du Colombier return x;
7319a747e4fSDavid du Colombier
7329a747e4fSDavid du Colombier lock(&pcicfglock);
7339a747e4fSDavid du Colombier switch(pcicfgmode){
7349a747e4fSDavid du Colombier
7359a747e4fSDavid du Colombier case 1:
7369a747e4fSDavid du Colombier rno &= ~0x03;
7379a747e4fSDavid du Colombier outl(PciADDR, 0x80000000|BUSBDF(tbdf)|rno|type);
7389a747e4fSDavid du Colombier if(read)
7399a747e4fSDavid du Colombier x = inl(PciDATA);
7409a747e4fSDavid du Colombier else
7419a747e4fSDavid du Colombier outl(PciDATA, data);
7429a747e4fSDavid du Colombier outl(PciADDR, 0);
7439a747e4fSDavid du Colombier break;
7449a747e4fSDavid du Colombier
7459a747e4fSDavid du Colombier case 2:
7469a747e4fSDavid du Colombier outb(PciCSE, 0x80|(BUSFNO(tbdf)<<1));
7479a747e4fSDavid du Colombier outb(PciFORWARD, BUSBNO(tbdf));
7489a747e4fSDavid du Colombier if(read)
7499a747e4fSDavid du Colombier x = inl((0xC000|(BUSDNO(tbdf)<<8)) + rno);
7509a747e4fSDavid du Colombier else
7519a747e4fSDavid du Colombier outl((0xC000|(BUSDNO(tbdf)<<8)) + rno, data);
7529a747e4fSDavid du Colombier outb(PciCSE, 0);
7539a747e4fSDavid du Colombier break;
7549a747e4fSDavid du Colombier }
7559a747e4fSDavid du Colombier unlock(&pcicfglock);
7569a747e4fSDavid du Colombier
7579a747e4fSDavid du Colombier return x;
7589a747e4fSDavid du Colombier }
7599a747e4fSDavid du Colombier
7609a747e4fSDavid du Colombier int
pcicfgr32(Pcidev * pcidev,int rno)7619a747e4fSDavid du Colombier pcicfgr32(Pcidev* pcidev, int rno)
7629a747e4fSDavid du Colombier {
7639a747e4fSDavid du Colombier return pcicfgrw32(pcidev->tbdf, rno, 0, 1);
7649a747e4fSDavid du Colombier }
7659a747e4fSDavid du Colombier
7669a747e4fSDavid du Colombier void
pcicfgw32(Pcidev * pcidev,int rno,int data)7679a747e4fSDavid du Colombier pcicfgw32(Pcidev* pcidev, int rno, int data)
7689a747e4fSDavid du Colombier {
7699a747e4fSDavid du Colombier pcicfgrw32(pcidev->tbdf, rno, data, 0);
7709a747e4fSDavid du Colombier }
7719a747e4fSDavid du Colombier
7729a747e4fSDavid du Colombier Pcidev*
pcimatch(Pcidev * prev,int vid,int did)7739a747e4fSDavid du Colombier pcimatch(Pcidev* prev, int vid, int did)
7749a747e4fSDavid du Colombier {
7759a747e4fSDavid du Colombier if(pcicfgmode == -1)
7769a747e4fSDavid du Colombier pcicfginit();
7779a747e4fSDavid du Colombier
7789a747e4fSDavid du Colombier if(prev == nil)
7799a747e4fSDavid du Colombier prev = pcilist;
7809a747e4fSDavid du Colombier else
7819a747e4fSDavid du Colombier prev = prev->list;
7829a747e4fSDavid du Colombier
7839a747e4fSDavid du Colombier while(prev != nil){
7849a747e4fSDavid du Colombier if((vid == 0 || prev->vid == vid)
7859a747e4fSDavid du Colombier && (did == 0 || prev->did == did))
7869a747e4fSDavid du Colombier break;
7879a747e4fSDavid du Colombier prev = prev->list;
7889a747e4fSDavid du Colombier }
7899a747e4fSDavid du Colombier return prev;
7909a747e4fSDavid du Colombier }
7919a747e4fSDavid du Colombier
7929a747e4fSDavid du Colombier Pcidev*
pcimatchtbdf(int tbdf)7939a747e4fSDavid du Colombier pcimatchtbdf(int tbdf)
7949a747e4fSDavid du Colombier {
7959a747e4fSDavid du Colombier Pcidev *pcidev;
7969a747e4fSDavid du Colombier
7979a747e4fSDavid du Colombier if(pcicfgmode == -1)
7989a747e4fSDavid du Colombier pcicfginit();
7999a747e4fSDavid du Colombier
8009a747e4fSDavid du Colombier for(pcidev = pcilist; pcidev != nil; pcidev = pcidev->list) {
8019a747e4fSDavid du Colombier if(pcidev->tbdf == tbdf)
8029a747e4fSDavid du Colombier break;
8039a747e4fSDavid du Colombier }
8049a747e4fSDavid du Colombier return pcidev;
8059a747e4fSDavid du Colombier }
8069a747e4fSDavid du Colombier
8079a747e4fSDavid du Colombier uchar
pciipin(Pcidev * pci,uchar pin)8089a747e4fSDavid du Colombier pciipin(Pcidev *pci, uchar pin)
8099a747e4fSDavid du Colombier {
8109a747e4fSDavid du Colombier if (pci == nil)
8119a747e4fSDavid du Colombier pci = pcilist;
8129a747e4fSDavid du Colombier
8139a747e4fSDavid du Colombier while (pci) {
8149a747e4fSDavid du Colombier uchar intl;
8159a747e4fSDavid du Colombier
8169a747e4fSDavid du Colombier if (pcicfgr8(pci, PciINTP) == pin && pci->intl != 0 && pci->intl != 0xff)
8179a747e4fSDavid du Colombier return pci->intl;
8189a747e4fSDavid du Colombier
8199a747e4fSDavid du Colombier if (pci->bridge && (intl = pciipin(pci->bridge, pin)) != 0)
8209a747e4fSDavid du Colombier return intl;
8219a747e4fSDavid du Colombier
8229a747e4fSDavid du Colombier pci = pci->list;
8239a747e4fSDavid du Colombier }
8249a747e4fSDavid du Colombier return 0;
8259a747e4fSDavid du Colombier }
8269a747e4fSDavid du Colombier
8279a747e4fSDavid du Colombier static void
pcilhinv(Pcidev * p)8289a747e4fSDavid du Colombier pcilhinv(Pcidev* p)
8299a747e4fSDavid du Colombier {
8309a747e4fSDavid du Colombier int i;
8319a747e4fSDavid du Colombier Pcidev *t;
8329a747e4fSDavid du Colombier
8339a747e4fSDavid du Colombier if(p == nil) {
8349a747e4fSDavid du Colombier putstrn(PCICONS.output, PCICONS.ptr);
8359a747e4fSDavid du Colombier p = pciroot;
8369a747e4fSDavid du Colombier print("bus dev type vid did intl memory\n");
8379a747e4fSDavid du Colombier }
8389a747e4fSDavid du Colombier for(t = p; t != nil; t = t->link) {
8399a747e4fSDavid du Colombier print("%d %2d/%d %.2ux %.2ux %.2ux %.4ux %.4ux %3d ",
8409a747e4fSDavid du Colombier BUSBNO(t->tbdf), BUSDNO(t->tbdf), BUSFNO(t->tbdf),
8419a747e4fSDavid du Colombier t->ccrb, t->ccru, t->ccrp, t->vid, t->did, t->intl);
8429a747e4fSDavid du Colombier
8439a747e4fSDavid du Colombier for(i = 0; i < nelem(p->mem); i++) {
8449a747e4fSDavid du Colombier if(t->mem[i].size == 0)
8459a747e4fSDavid du Colombier continue;
8469a747e4fSDavid du Colombier print("%d:%.8lux %d ", i,
8479a747e4fSDavid du Colombier t->mem[i].bar, t->mem[i].size);
8489a747e4fSDavid du Colombier }
8499a747e4fSDavid du Colombier if(t->ioa.bar || t->ioa.size)
8509a747e4fSDavid du Colombier print("ioa:%.8lux %d ", t->ioa.bar, t->ioa.size);
8519a747e4fSDavid du Colombier if(t->mema.bar || t->mema.size)
8529a747e4fSDavid du Colombier print("mema:%.8lux %d ", t->mema.bar, t->mema.size);
8539a747e4fSDavid du Colombier if(t->bridge)
8549a747e4fSDavid du Colombier print("->%d", BUSBNO(t->bridge->tbdf));
8559a747e4fSDavid du Colombier print("\n");
8569a747e4fSDavid du Colombier }
8579a747e4fSDavid du Colombier while(p != nil) {
8589a747e4fSDavid du Colombier if(p->bridge != nil)
8599a747e4fSDavid du Colombier pcilhinv(p->bridge);
8609a747e4fSDavid du Colombier p = p->link;
8619a747e4fSDavid du Colombier }
8629a747e4fSDavid du Colombier }
8639a747e4fSDavid du Colombier
8649a747e4fSDavid du Colombier void
pcihinv(Pcidev * p)8659a747e4fSDavid du Colombier pcihinv(Pcidev* p)
8669a747e4fSDavid du Colombier {
8679a747e4fSDavid du Colombier if(pcicfgmode == -1)
8689a747e4fSDavid du Colombier pcicfginit();
8699a747e4fSDavid du Colombier qlock(&pcicfginitlock);
8709a747e4fSDavid du Colombier pcilhinv(p);
8719a747e4fSDavid du Colombier qunlock(&pcicfginitlock);
8729a747e4fSDavid du Colombier }
8739a747e4fSDavid du Colombier
8749a747e4fSDavid du Colombier void
pcireset(void)8759a747e4fSDavid du Colombier pcireset(void)
8769a747e4fSDavid du Colombier {
8779a747e4fSDavid du Colombier Pcidev *p;
8789a747e4fSDavid du Colombier int pcr;
8799a747e4fSDavid du Colombier
8809a747e4fSDavid du Colombier if(pcicfgmode == -1)
8819a747e4fSDavid du Colombier pcicfginit();
8829a747e4fSDavid du Colombier
8839a747e4fSDavid du Colombier for(p = pcilist; p != nil; p = p->list){
8849a747e4fSDavid du Colombier pcr = pcicfgr16(p, PciPCR);
8859a747e4fSDavid du Colombier pcr &= ~0x0004;
8869a747e4fSDavid du Colombier pcicfgw16(p, PciPCR, pcr);
8879a747e4fSDavid du Colombier }
8889a747e4fSDavid du Colombier }
8899a747e4fSDavid du Colombier
8909a747e4fSDavid du Colombier void
pcisetbme(Pcidev * p)8919a747e4fSDavid du Colombier pcisetbme(Pcidev* p)
8929a747e4fSDavid du Colombier {
8939a747e4fSDavid du Colombier int pcr;
8949a747e4fSDavid du Colombier
8959a747e4fSDavid du Colombier pcr = pcicfgr16(p, PciPCR);
8969a747e4fSDavid du Colombier pcr |= MASen;
8979a747e4fSDavid du Colombier pcicfgw16(p, PciPCR, pcr);
8989a747e4fSDavid du Colombier }
8999a747e4fSDavid du Colombier
9009a747e4fSDavid du Colombier void
pciclrbme(Pcidev * p)9019a747e4fSDavid du Colombier pciclrbme(Pcidev* p)
9029a747e4fSDavid du Colombier {
9039a747e4fSDavid du Colombier int pcr;
9049a747e4fSDavid du Colombier
9059a747e4fSDavid du Colombier pcr = pcicfgr16(p, PciPCR);
9069a747e4fSDavid du Colombier pcr &= ~MASen;
9079a747e4fSDavid du Colombier pcicfgw16(p, PciPCR, pcr);
9089a747e4fSDavid du Colombier }
909