xref: /inferno-os/os/port/devpci.c (revision 74a4d8c26dd3c1e9febcb717cfd6cb6512991a7a)
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