Show inlined functions with bt-akaros.sh (kernel)
[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 <slab.h>
11 #include <kmalloc.h>
12 #include <kref.h>
13 #include <string.h>
14 #include <stdio.h>
15 #include <assert.h>
16 #include <error.h>
17 #include <cpio.h>
18 #include <pmap.h>
19 #include <smp.h>
20 #include <net/ip.h>
21 #include <arch/io.h>
22
23 struct dev pcidevtab;
24
25 static char *devname(void)
26 {
27         return pcidevtab.name;
28 }
29
30 enum {
31         Qtopdir = 0,
32
33         Qpcidir,
34         Qpcictl,
35         Qpciraw,
36
37         PCI_CONFIG_SZ = 256,
38 };
39
40 #define TYPE(q)         ((uint32_t)(q).path & 0x0F)
41 #define QID(c, t)       (((c)<<4)|(t))
42
43 static struct dirtab topdir[] = {
44         {".", {Qtopdir, 0, QTDIR}, 0, 0555},
45         {"pci", {Qpcidir, 0, QTDIR}, 0, 0555},
46 };
47
48 static int pcidirgen(struct chan *c, int t, int tbdf, struct dir *dp)
49 {
50         struct qid q;
51
52         q = (struct qid) {
53                 BUSBDF(tbdf) | t, 0, 0};
54         switch (t) {
55         case Qpcictl:
56                 snprintf(get_cur_genbuf(), GENBUF_SZ, "%d.%d.%dctl",
57                          BUSBNO(tbdf), BUSDNO(tbdf), BUSFNO(tbdf));
58                 devdir(c, q, get_cur_genbuf(), 0, eve.name, 0444, dp);
59                 return 1;
60         case Qpciraw:
61                 snprintf(get_cur_genbuf(), GENBUF_SZ, "%d.%d.%draw",
62                          BUSBNO(tbdf), BUSDNO(tbdf), BUSFNO(tbdf));
63                 devdir(c, q, get_cur_genbuf(), 128, eve.name, 0664, dp);
64                 return 1;
65         }
66         return -1;
67 }
68
69 static int
70 pcigen(struct chan *c, char *_1, struct dirtab *_2, int _3, int s,
71        struct dir *dp)
72 {
73         int tbdf;
74         struct pci_device *p;
75         struct qid q;
76
77         switch (TYPE(c->qid)) {
78         case Qtopdir:
79                 if (s == DEVDOTDOT) {
80                         q = (struct qid) { QID(0, Qtopdir), 0, QTDIR };
81                         snprintf(get_cur_genbuf(), GENBUF_SZ, "#%s",
82                                  pcidevtab.name);
83                         devdir(c, q, get_cur_genbuf(), 0, eve.name, 0555, dp);
84                         return 1;
85                 }
86                 return devgen(c, NULL, topdir, ARRAY_SIZE(topdir), s, dp);
87         case Qpcidir:
88                 if (s == DEVDOTDOT) {
89                         q = (struct qid) {
90                                 QID(0, Qtopdir), 0, QTDIR};
91                         snprintf(get_cur_genbuf(), GENBUF_SZ, "#%s",
92                                  pcidevtab.name);
93                         devdir(c, q, get_cur_genbuf(), 0, eve.name, 0555, dp);
94                         return 1;
95                 }
96                 STAILQ_FOREACH(p, &pci_devices, all_dev) {
97                         if (s < 2)
98                                 break;
99                         s -= 2;
100                 }
101                 if (p == NULL)
102                         return -1;
103                 return pcidirgen(c, s + Qpcictl, pci_to_tbdf(p), dp);
104         case Qpcictl:
105         case Qpciraw:
106                 tbdf = MKBUS(BusPCI, 0, 0, 0) | BUSBDF((uint32_t) c->qid.path);
107                 p = pci_match_tbdf(tbdf);
108                 if (p == NULL)
109                         return -1;
110                 return pcidirgen(c, TYPE(c->qid), tbdf, dp);
111         default:
112                 break;
113         }
114         return -1;
115 }
116
117 static struct chan *pciattach(char *spec)
118 {
119         return devattach(devname(), spec);
120 }
121
122 struct walkqid *pciwalk(struct chan *c, struct chan *nc, char **name,
123                         unsigned int nname)
124 {
125         return devwalk(c, nc, name, nname, (struct dirtab *)0, 0, pcigen);
126 }
127
128 static size_t pcistat(struct chan *c, uint8_t *dp, size_t n)
129 {
130         return devstat(c, dp, n, (struct dirtab *)0, 0L, pcigen);
131 }
132
133 static struct chan *pciopen(struct chan *c, int omode)
134 {
135         c = devopen(c, omode, (struct dirtab *)0, 0, pcigen);
136         switch (TYPE(c->qid)) {
137         default:
138                 break;
139         }
140         return c;
141 }
142
143 static void pciclose(struct chan *_)
144 {
145 }
146
147 static size_t pciread(struct chan *c, void *va, size_t n, off64_t offset)
148 {
149         char buf[PCI_CONFIG_SZ], *ebuf, *w, *a;
150         int i, tbdf, r;
151         uint32_t x;
152         struct pci_device *p;
153
154         a = va;
155         switch (TYPE(c->qid)) {
156         case Qtopdir:
157         case Qpcidir:
158                 return devdirread(c, a, n, (struct dirtab *)0, 0L, pcigen);
159         case Qpcictl:
160                 tbdf = MKBUS(BusPCI, 0, 0, 0) | BUSBDF((uint32_t) c->qid.path);
161                 p = pci_match_tbdf(tbdf);
162                 if (p == NULL)
163                         error(EINVAL, ERROR_FIXME);
164                 ebuf = buf + sizeof(buf) - 1;   /* -1 for newline */
165                 w = seprintf(buf, ebuf, "%.2x.%.2x.%.2x %.4x/%.4x %3d",
166                              p->class, p->subclass, p->progif, p->ven_id,
167                              p->dev_id, p->irqline);
168                 for (i = 0; i < COUNT_OF(p->bar); i++) {
169                         if (p->bar[i].mmio_sz == 0)
170                                 continue;
171                         w = seprintf(w, ebuf, " %d:%.8lux %4x/%8x %d", i,
172                                      p->bar[i].pio_base, p->bar[i].mmio_base32,
173                                      p->bar[i].mmio_base64, 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 };