AHCI: re enable the PCI device.
[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 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, 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, 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, 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, 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, int nname)
124 {
125         return devwalk(c, nc, name, nname, (struct dirtab *)0, 0, pcigen);
126 }
127
128 static int pcistat(struct chan *c, uint8_t *dp, int 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 long pciread(struct chan *c, void *va, long n, int64_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, p->dev_id,
167                              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 %d", i, p->bar[i].pio_base,
172                                      p->bar[i].mmio_sz);
173                 }
174                 *w++ = '\n';
175                 *w = '\0';
176                 return readstr(offset, a, n, buf);
177         case Qpciraw:
178                 tbdf = MKBUS(BusPCI, 0, 0, 0) | BUSBDF((uint32_t) c->qid.path);
179                 p = pci_match_tbdf(tbdf);
180                 if (p == NULL)
181                         error(EINVAL, ERROR_FIXME);
182                 if (n + offset > 256)
183                         n = 256 - offset;
184                 if (n < 0)
185                         return 0;
186                 r = offset;
187                 if (!(r & 3) && n == 4) {
188                         x = pcidev_read32(p, r);
189                         PBIT32(a, x);
190                         return 4;
191                 }
192                 if (!(r & 1) && n == 2) {
193                         x = pcidev_read16(p, r);
194                         PBIT16(a, x);
195                         return 2;
196                 }
197                 for (i = 0; i < n; i++) {
198                         x = pcidev_read8(p, r);
199                         PBIT8(a, x);
200                         a++;
201                         r++;
202                 }
203                 return i;
204         default:
205                 error(EINVAL, ERROR_FIXME);
206         }
207         return n;
208 }
209
210 static long pciwrite(struct chan *c, void *va, long n, int64_t offset)
211 {
212         uint8_t *a;
213         int i, r, tbdf;
214         uint32_t x;
215         struct pci_device *p;
216
217         if (n > PCI_CONFIG_SZ)
218                 n = PCI_CONFIG_SZ;
219         a = va;
220
221         switch (TYPE(c->qid)) {
222         case Qpciraw:
223                 tbdf = MKBUS(BusPCI, 0, 0, 0) | BUSBDF((uint32_t) c->qid.path);
224                 p = pci_match_tbdf(tbdf);
225                 if (p == NULL)
226                         error(EINVAL, ERROR_FIXME);
227                 if (offset > PCI_CONFIG_SZ)
228                         return 0;
229                 if (n + offset > PCI_CONFIG_SZ)
230                         n = PCI_CONFIG_SZ - offset;
231                 r = offset;
232                 if (!(r & 3) && n == 4) {
233                         x = GBIT32(a);
234                         pcidev_write32(p, r, x);
235                         return 4;
236                 }
237                 if (!(r & 1) && n == 2) {
238                         x = GBIT16(a);
239                         pcidev_write16(p, r, x);
240                         return 2;
241                 }
242                 for (i = 0; i < n; i++) {
243                         x = GBIT8(a);
244                         pcidev_write8(p, r, x);
245                         a++;
246                         r++;
247                 }
248                 return i;
249         default:
250                 error(EINVAL, ERROR_FIXME);
251         }
252         return n;
253 }
254
255 struct dev pcidevtab __devtab = {
256         .name = "pci",
257
258         .reset = devreset,
259         .init = devinit,
260         .shutdown = devshutdown,
261         .attach = pciattach,
262         .walk = pciwalk,
263         .stat = pcistat,
264         .open = pciopen,
265         .create = devcreate,
266         .close = pciclose,
267         .read = pciread,
268         .bread = devbread,
269         .write = pciwrite,
270         .bwrite = devbwrite,
271         .remove = devremove,
272         .wstat = devwstat,
273 };