First pass at enabling interrupts.
[akaros.git] / kern / drivers / dev / pci.c
1 /* 
2  * This file is part of the UCB release of Plan 9. It is subject to the license
3  * terms in the LICENSE file found in the top-level directory of this
4  * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
5  * part of the UCB release of Plan 9, including this file, may be copied,
6  * modified, propagated, or distributed except according to the terms contained
7  * in the LICENSE file.
8  */
9
10 #include <vfs.h>
11 #include <kfs.h>
12 #include <slab.h>
13 #include <kmalloc.h>
14 #include <kref.h>
15 #include <string.h>
16 #include <stdio.h>
17 #include <assert.h>
18 #include <error.h>
19 #include <cpio.h>
20 #include <pmap.h>
21 #include <smp.h>
22 #include <ip.h>
23
24 enum {
25         Qtopdir = 0,
26
27         Qpcidir,
28         Qpcictl,
29         Qpciraw,
30 };
31
32 #define TYPE(q)         ((uint32_t)(q).path & 0x0F)
33 #define QID(c, t)       (((c)<<4)|(t))
34
35 static struct dirtab topdir[] = {
36         {".",   { Qtopdir, 0, QTDIR },  0,      0555},
37         {"pci", { Qpcidir, 0, QTDIR },  0,      0555},
38 };
39
40 extern struct dev pcidevtab;
41
42 static int
43 pcidirgen(struct chan *c, int t, int tbdf, struct dir *dp)
44 {
45         struct qid q;
46
47         q = (struct qid){BUSBDF(tbdf)|t, 0, 0};
48         switch(t) {
49         case Qpcictl:
50                 snprintf(get_cur_genbuf(), GENBUF_SZ, "%d.%d.%dctl",
51                         BUSBNO(tbdf), BUSDNO(tbdf), BUSFNO(tbdf));
52                 devdir(c, q, get_cur_genbuf(), 0, eve, 0444, dp);
53                 return 1;
54         case Qpciraw:
55                 snprintf(get_cur_genbuf(), GENBUF_SZ, "%d.%d.%draw",
56                         BUSBNO(tbdf), BUSDNO(tbdf), BUSFNO(tbdf));
57                 devdir(c, q, get_cur_genbuf(), 128, eve, 0664, dp);
58                 return 1;
59         }
60         return -1;
61 }
62
63 static int
64 pcigen(struct chan *c, char *, struct dirtab*, int unused_int, int s, struct dir *dp)
65 {
66         int tbdf;
67         Pcidev *p;
68         struct qid q;
69
70         switch(TYPE(c->qid)){
71         case Qtopdir:
72                 if(s == DEVDOTDOT){
73                         q = (struct qid){QID(0, Qtopdir), 0, QTDIR};
74                         snprintf(get_cur_genbuf(), GENBUF_SZ, "#%C", pcidevtab.dc);
75                         devdir(c, q, get_cur_genbuf(), 0, eve, 0555, dp);
76                         return 1;
77                 }
78                 return devgen(c, NULL, topdir, ARRAY_SIZE(topdir), s, dp);
79         case Qpcidir:
80                 if(s == DEVDOTDOT){
81                         q = (struct qid){QID(0, Qtopdir), 0, QTDIR};
82                         snprintf(get_cur_genbuf(), GENBUF_SZ, "#%C", pcidevtab.dc);
83                         devdir(c, q, get_cur_genbuf(), 0, eve, 0555, dp);
84                         return 1;
85                 }
86                 p = pcimatch(NULL, 0, 0);
87                 while(s >= 2 && p != NULL) {
88                         p = pcimatch(p, 0, 0);
89                         s -= 2;
90                 }
91                 if(p == NULL)
92                         return -1;
93                 return pcidirgen(c, s+Qpcictl, p->tbdf, dp);
94         case Qpcictl:
95         case Qpciraw:
96                 tbdf = MKBUS(BusPCI, 0, 0, 0)|BUSBDF((uint32_t)c->qid.path);
97                 p = pcimatchtbdf(tbdf);
98                 if(p == NULL)
99                         return -1;
100                 return pcidirgen(c, TYPE(c->qid), tbdf, dp);
101         default:
102                 break;
103         }
104         return -1;
105 }
106
107 static struct chan*
108 pciattach(char *spec)
109 {
110         return devattach(pcidevtab.dc, spec);
111 }
112
113 struct walkqid*
114 pciwalk(struct chan* c, struct chan *nc, char** name, int nname)
115 {
116         return devwalk(c, nc, name, nname, (struct dirtab *)0, 0, pcigen);
117 }
118
119 static long
120 pcistat(struct chan* c, uint8_t* dp, long n)
121 {
122         return devstat(c, dp, n, (struct dirtab *)0, 0L, pcigen);
123 }
124
125 static struct chan*
126 pciopen(struct chan *c, int omode)
127 {
128         c = devopen(c, omode, (struct dirtab*)0, 0, pcigen);
129         switch(TYPE(c->qid)){
130         default:
131                 break;
132         }
133         return c;
134 }
135
136 static void
137 pciclose(struct chan*)
138 {
139 }
140
141 static long
142 pciread(struct chan *c, void *va, long n, int64_t offset)
143 {
144         char buf[256], *ebuf, *w, *a;
145         int i, tbdf, r;
146         uint32_t x;
147         Pcidev *p;
148
149         a = va;
150         switch(TYPE(c->qid)){
151         case Qtopdir:
152         case Qpcidir:
153                 return devdirread(c, a, n, (struct dirtab *)0, 0L, pcigen);
154         case Qpcictl:
155                 tbdf = MKBUS(BusPCI, 0, 0, 0)|BUSBDF((uint32_t)c->qid.path);
156                 p = pcimatchtbdf(tbdf);
157                 if(p == NULL)
158                         error(Egreg);
159                 ebuf = buf+sizeof buf-1;        /* -1 for newline */
160                 w = seprintf(buf, ebuf, "%.2x.%.2x.%.2x %.4x/%.4x %3d",
161                         p->ccrb, p->ccru, p->ccrp, p->vid, p->did, p->intl);
162                 for(i=0; i<ARRAY_SIZE(p->mem); i++){
163                         if(p->mem[i].size == 0)
164                                 continue;
165                         w = seprintf(w, ebuf, " %d:%.8lux %d", i, p->mem[i].bar, p->mem[i].size);
166                 }
167                 *w++ = '\n';
168                 *w = '\0';
169                 return readstr(offset, a, n, buf);
170         case Qpciraw:
171                 tbdf = MKBUS(BusPCI, 0, 0, 0)|BUSBDF((uint32_t)c->qid.path);
172                 p = pcimatchtbdf(tbdf);
173                 if(p == NULL)
174                         error(Egreg);
175                 if(n+offset > 256)
176                         n = 256-offset;
177                 if(n < 0)
178                         return 0;
179                 r = offset;
180                 if(!(r & 3) && n == 4){
181                         x = pcicfgr32(p, r);
182                         PBIT32(a, x);
183                         return 4;
184                 }
185                 if(!(r & 1) && n == 2){
186                         x = pcicfgr16(p, r);
187                         PBIT16(a, x);
188                         return 2;
189                 }
190                 for(i = 0; i <  n; i++){
191                         x = pcicfgr8(p, r);
192                         PBIT8(a, x);
193                         a++;
194                         r++;
195                 }
196                 return i;
197         default:
198                 error(Egreg);
199         }
200         return n;
201 }
202
203 static long
204 pciwrite(struct chan *c, void *va, long n, int64_t offset)
205 {
206         char buf[256];
207         uint8_t *a;
208         int i, r, tbdf;
209         uint32_t x;
210         Pcidev *p;
211
212         if(n >= sizeof(buf))
213                 n = sizeof(buf)-1;
214         a = va;
215         strncpy(buf, ( char *unused_char_p_t)a, n);
216         buf[n] = 0;
217
218         switch(TYPE(c->qid)){
219         case Qpciraw:
220                 tbdf = MKBUS(BusPCI, 0, 0, 0)|BUSBDF((uint32_t)c->qid.path);
221                 p = pcimatchtbdf(tbdf);
222                 if(p == NULL)
223                         error(Egreg);
224                 if(offset > 256)
225                         return 0;
226                 if(n+offset > 256)
227                         n = 256-offset;
228                 r = offset;
229                 if(!(r & 3) && n == 4){
230                         x = GBIT32(a);
231                         pcicfgw32(p, r, x);
232                         return 4;
233                 }
234                 if(!(r & 1) && n == 2){
235                         x = GBIT16(a);
236                         pcicfgw16(p, r, x);
237                         return 2;
238                 }
239                 for(i = 0; i <  n; i++){
240                         x = GBIT8(a);
241                         pcicfgw8(p, r, x);
242                         a++;
243                         r++;
244                 }
245                 return i;
246         default:
247                 error(Egreg);
248         }
249         return n;
250 }
251
252 struct dev pcidevtab = {
253         '$',
254         "pci",
255
256         devreset,
257         devinit,
258         devshutdown,
259         pciattach,
260         pciwalk,
261         pcistat,
262         pciopen,
263         devcreate,
264         pciclose,
265         pciread,
266         devbread,
267         pciwrite,
268         devbwrite,
269         devremove,
270         devwstat,
271 };