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
pcigen2(Chan * c,int t,int tbdf,Dir * dp)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
pcigen(Chan * c,char *,Dirtab *,int,int s,Dir * dp)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*
pciattach(char * spec)102 pciattach(char *spec)
103 {
104 return devattach(pcidevtab.dc, spec);
105 }
106
107 Walkqid*
pciwalk(Chan * c,Chan * nc,char ** name,int nname)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
pcistat(Chan * c,uchar * dp,int n)114 pcistat(Chan* c, uchar* dp, int n)
115 {
116 return devstat(c, dp, n, nil, 0, pcigen);
117 }
118
119 static Chan*
pciopen(Chan * c,int omode)120 pciopen(Chan *c, int omode)
121 {
122 return devopen(c, omode, nil, 0, pcigen);
123 }
124
125 static void
pciclose(Chan *)126 pciclose(Chan*)
127 {
128 }
129
130 static long
pciread(Chan * c,void * va,long n,vlong offset)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
pciwrite(Chan * c,void * a,long n,vlong)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