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