1 /* 2 * access to PCI configuration space (devpnp.c without PNP) 3 * 4 * TODO 5 * - extend PCI raw access to configuration space (writes, byte/short access?) 6 * - implement PCI access to memory/io space/BIOS ROM 7 * - use c->aux instead of performing lookup on each read/write? 8 */ 9 #include "u.h" 10 #include "../port/lib.h" 11 #include "mem.h" 12 #include "dat.h" 13 #include "fns.h" 14 #include "io.h" 15 #include "../port/error.h" 16 17 #define DPRINT if(0) print 18 #define XPRINT if(1) print 19 20 enum { 21 Qtopdir = 0, 22 23 Qpcidir, 24 Qpcictl, 25 Qpciraw, 26 }; 27 28 #define TYPE(q) ((ulong)(q).path & 0x0F) 29 #define QID(c, t) (((c)<<4)|(t)) 30 31 static Dirtab topdir[] = { 32 ".", { Qtopdir, 0, QTDIR }, 0, 0555, 33 "pci", { Qpcidir, 0, QTDIR }, 0, 0555, 34 }; 35 36 extern Dev pcidevtab; 37 38 static int 39 pcigen2(Chan *c, int t, int tbdf, Dir *dp) 40 { 41 Qid q; 42 43 q = (Qid){BUSBDF(tbdf)|t, 0, 0}; 44 switch(t) { 45 case Qpcictl: 46 sprint(up->genbuf, "%d.%d.%dctl", BUSBNO(tbdf), BUSDNO(tbdf), BUSFNO(tbdf)); 47 devdir(c, q, up->genbuf, 0, eve, 0444, dp); 48 return 1; 49 case Qpciraw: 50 sprint(up->genbuf, "%d.%d.%draw", BUSBNO(tbdf), BUSDNO(tbdf), BUSFNO(tbdf)); 51 devdir(c, q, up->genbuf, 128, eve, 0444, dp); 52 return 1; 53 } 54 return -1; 55 } 56 57 static int 58 pcigen(Chan *c, char *, Dirtab*, int, int s, Dir *dp) 59 { 60 Qid q; 61 Pcidev *p; 62 int tbdf; 63 64 switch(TYPE(c->qid)){ 65 case Qtopdir: 66 if(s == DEVDOTDOT){ 67 q = (Qid){QID(0, Qtopdir), 0, QTDIR}; 68 sprint(up->genbuf, "#%C", pcidevtab.dc); 69 devdir(c, q, up->genbuf, 0, eve, 0555, dp); 70 return 1; 71 } 72 return devgen(c, nil, topdir, nelem(topdir), s, dp); 73 case Qpcidir: 74 if(s == DEVDOTDOT){ 75 q = (Qid){QID(0, Qtopdir), 0, QTDIR}; 76 sprint(up->genbuf, "#%C", pcidevtab.dc); 77 devdir(c, q, up->genbuf, 0, eve, 0555, dp); 78 return 1; 79 } 80 p = pcimatch(nil, 0, 0); 81 while(s >= 2 && p != nil) { 82 p = pcimatch(p, 0, 0); 83 s -= 2; 84 } 85 if(p == nil) 86 return -1; 87 return pcigen2(c, s+Qpcictl, p->tbdf, dp); 88 case Qpcictl: 89 case Qpciraw: 90 tbdf = MKBUS(BusPCI, 0, 0, 0)|BUSBDF((ulong)c->qid.path); 91 p = pcimatchtbdf(tbdf); 92 if(p == nil) 93 return -1; 94 return pcigen2(c, TYPE(c->qid), tbdf, dp); 95 default: 96 break; 97 } 98 return -1; 99 } 100 101 static Chan* 102 pciattach(char *spec) 103 { 104 return devattach(pcidevtab.dc, spec); 105 } 106 107 Walkqid* 108 pciwalk(Chan* c, Chan *nc, char** name, int nname) 109 { 110 return devwalk(c, nc, name, nname, nil, 0, pcigen); 111 } 112 113 static int 114 pcistat(Chan* c, uchar* dp, int n) 115 { 116 return devstat(c, dp, n, nil, 0, pcigen); 117 } 118 119 static Chan* 120 pciopen(Chan *c, int omode) 121 { 122 return devopen(c, omode, nil, 0, pcigen); 123 } 124 125 static void 126 pciclose(Chan*) 127 { 128 } 129 130 static long 131 pciread(Chan *c, void *va, long n, vlong offset) 132 { 133 ulong x; 134 Pcidev *p; 135 char buf[256], *ebuf, *w; 136 char *a = va; 137 int i, tbdf, r; 138 139 switch(TYPE(c->qid)){ 140 case Qtopdir: 141 case Qpcidir: 142 return devdirread(c, a, n, nil, 0, pcigen); 143 case Qpcictl: 144 tbdf = MKBUS(BusPCI, 0, 0, 0)|BUSBDF((ulong)c->qid.path); 145 p = pcimatchtbdf(tbdf); 146 if(p == nil) 147 error(Egreg); 148 ebuf = buf+sizeof buf-1; /* -1 for newline */ 149 w = seprint(buf, ebuf, "%.2x.%.2x.%.2x %.4x/%.4x %3d", 150 p->ccrb, p->ccru, p->ccrp, p->vid, p->did, p->intl); 151 for(i=0; i<nelem(p->mem); i++){ 152 if(p->mem[i].size == 0) 153 continue; 154 w = seprint(w, ebuf, " %d:%.8lux %d", i, p->mem[i].bar, p->mem[i].size); 155 } 156 *w++ = '\n'; 157 *w = '\0'; 158 return readstr(offset, a, n, buf); 159 case Qpciraw: 160 tbdf = MKBUS(BusPCI, 0, 0, 0)|BUSBDF((ulong)c->qid.path); 161 p = pcimatchtbdf(tbdf); 162 if(p == nil) 163 error(Egreg); 164 if(offset > 256) 165 return 0; 166 if(n+offset > 256) 167 n = 256-offset; 168 if(offset%4) 169 error(Ebadarg); 170 r = offset; 171 for(i = 0; i+4 <= n; i+=4) { 172 x = pcicfgr32(p, r); 173 a[0] = x; 174 a[1] = (x>>8); 175 a[2] = (x>>16); 176 a[3] = (x>>24); 177 a += 4; 178 r += 4; 179 } 180 return i; 181 default: 182 error(Egreg); 183 } 184 return n; 185 } 186 187 static long 188 pciwrite(Chan *c, void *a, long n, vlong) 189 { 190 char buf[256]; 191 192 if(n >= sizeof(buf)) 193 n = sizeof(buf)-1; 194 strncpy(buf, a, n); 195 buf[n] = 0; 196 197 switch(TYPE(c->qid)){ 198 case Qpcictl: 199 case Qpciraw: 200 error(Eperm); 201 default: 202 error(Egreg); 203 } 204 return n; 205 } 206 207 208 Dev pcidevtab = { 209 '$', 210 "pci", 211 212 devreset, 213 devinit, 214 devshutdown, 215 pciattach, 216 pciwalk, 217 pcistat, 218 pciopen, 219 devcreate, 220 pciclose, 221 pciread, 222 devbread, 223 pciwrite, 224 devbwrite, 225 devremove, 226 devwstat, 227 }; 228