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