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