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