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