1/* Minimal PCI driver for Mini-OS.
2 * Copyright (c) 2007-2008 Samuel Thibault.
3 * Based on blkfront.c.
4 */
5
6#include <mini-os/os.h>
7#include <mini-os/xenbus.h>
8#include <mini-os/events.h>
9#include <mini-os/gnttab.h>
10#include <mini-os/wait.h>
11#include <mini-os/pcifront.h>
12
13#include <bmk-core/errno.h>
14#include <bmk-core/memalloc.h>
15#include <bmk-core/pgalloc.h>
16#include <bmk-core/printf.h>
17#include <bmk-core/string.h>
18
19#define PCI_DEVFN(slot, func) ((((slot) & 0x1f) << 3) | ((func) & 0x07))
20
21DECLARE_WAIT_QUEUE_HEAD(pcifront_queue);
22static struct pcifront_dev *pcidev;
23
24struct pcifront_dev {
25    domid_t dom;
26
27    struct xen_pci_sharedinfo *info;
28    grant_ref_t info_ref;
29    evtchn_port_t evtchn;
30
31    char nodename[64];
32    char *backend;
33
34    struct xenbus_event_queue events;
35};
36
37void pcifront_handler(evtchn_port_t port, struct pt_regs *regs, void *data)
38{
39    minios_wake_up(&pcifront_queue);
40}
41
42static void free_pcifront(struct pcifront_dev *dev)
43{
44    if (!dev)
45        dev = pcidev;
46
47    minios_mask_evtchn(dev->evtchn);
48
49    gnttab_end_access(dev->info_ref);
50    bmk_pgfree_one(dev->info);
51
52    minios_unbind_evtchn(dev->evtchn);
53
54    bmk_memfree(dev->backend, BMK_MEMWHO_WIREDBMK);
55    bmk_memfree(dev, BMK_MEMWHO_WIREDBMK);
56}
57
58void pcifront_watches(void *opaque)
59{
60    XenbusState state;
61    char *err = NULL, *msg = NULL;
62    char *be_path, *be_state;
63    char* nodename = opaque ? opaque : "device/pci/0";
64    char path[bmk_strlen(nodename) + 9];
65    char fe_state[bmk_strlen(nodename) + 7];
66    struct xenbus_event_queue events;
67    xenbus_event_queue_init(&events);
68
69    bmk_snprintf(path, sizeof(path), "%s/backend", nodename);
70    bmk_snprintf(fe_state, sizeof(fe_state), "%s/state", nodename);
71
72    while (1) {
73        minios_printk("pcifront_watches: waiting for backend path to appear %s\n", path);
74        xenbus_watch_path_token(XBT_NIL, path, path, &events);
75        while ((err = xenbus_read(XBT_NIL, path, &be_path)) != NULL) {
76            bmk_memfree(err, BMK_MEMWHO_WIREDBMK);
77            xenbus_wait_for_watch(&events);
78        }
79        xenbus_unwatch_path_token(XBT_NIL, path, path);
80        minios_printk("pcifront_watches: waiting for backend to get into the right state %s\n", be_path);
81        be_state = (char *) bmk_xmalloc_bmk(bmk_strlen(be_path) +  7);
82        bmk_snprintf(be_state, bmk_strlen(be_path) +  7, "%s/state", be_path);
83        xenbus_watch_path_token(XBT_NIL, be_state, be_state, &events);
84        while ((err = xenbus_read(XBT_NIL, be_state, &msg)) != NULL || msg[0] > '4') {
85            bmk_memfree(msg, BMK_MEMWHO_WIREDBMK);
86            bmk_memfree(err, BMK_MEMWHO_WIREDBMK);
87            xenbus_wait_for_watch(&events);
88        }
89        xenbus_unwatch_path_token(XBT_NIL, be_state, be_state);
90        if (init_pcifront(NULL) == NULL) {
91            bmk_memfree(be_state, BMK_MEMWHO_WIREDBMK);
92            bmk_memfree(be_path, BMK_MEMWHO_WIREDBMK);
93            continue;
94        }
95        xenbus_watch_path_token(XBT_NIL, be_state, be_state, &events);
96        state = XenbusStateConnected;
97        minios_printk("pcifront_watches: waiting for backend events %s\n", be_state);
98        while ((err = xenbus_wait_for_state_change(be_state, &state, &events)) == NULL &&
99               (err = xenbus_read(XBT_NIL, pcidev->backend, &msg)) == NULL) {
100            bmk_memfree(msg, BMK_MEMWHO_WIREDBMK);
101            minios_printk("pcifront_watches: backend state changed: %s %d\n", be_state, state);
102            if (state == XenbusStateReconfiguring) {
103                minios_printk("pcifront_watches: writing %s %d\n", fe_state, XenbusStateReconfiguring);
104                if ((err = xenbus_switch_state(XBT_NIL, fe_state, XenbusStateReconfiguring)) != NULL) {
105                    minios_printk("pcifront_watches: error changing state to %d: %s\n",
106                            XenbusStateReconfiguring, err);
107                    if (!bmk_strcmp(err, "ENOENT")) {
108                        xenbus_write(XBT_NIL, fe_state, "7");
109                        bmk_memfree(err, BMK_MEMWHO_WIREDBMK);
110                    }
111                }
112            } else if (state == XenbusStateReconfigured) {
113                minios_printk("pcifront_watches: writing %s %d\n", fe_state, XenbusStateConnected);
114                minios_printk("pcifront_watches: changing state to %d\n", XenbusStateConnected);
115                if ((err = xenbus_switch_state(XBT_NIL, fe_state, XenbusStateConnected)) != NULL) {
116                    minios_printk("pcifront_watches: error changing state to %d: %s\n",
117                            XenbusStateConnected, err);
118                    if (!bmk_strcmp(err, "ENOENT")) {
119                        xenbus_write(XBT_NIL, fe_state, "4");
120                        bmk_memfree(err, BMK_MEMWHO_WIREDBMK);
121                    }
122                }
123            } else if (state == XenbusStateClosing)
124                break;
125        }
126        if (err)
127            minios_printk("pcifront_watches: done waiting err=%s\n", err);
128        else
129            minios_printk("pcifront_watches: done waiting\n");
130        xenbus_unwatch_path_token(XBT_NIL, be_state, be_state);
131        shutdown_pcifront(pcidev);
132        bmk_memfree(be_state, BMK_MEMWHO_WIREDBMK);
133        bmk_memfree(be_path, BMK_MEMWHO_WIREDBMK);
134        bmk_memfree(err, BMK_MEMWHO_WIREDBMK);
135        pcidev = NULL;
136    }
137
138    xenbus_unwatch_path_token(XBT_NIL, path, path);
139}
140
141struct pcifront_dev *init_pcifront(char *_nodename)
142{
143    xenbus_transaction_t xbt;
144    char* err;
145    char* message=NULL;
146    int retry=0;
147    char* msg;
148    char* nodename = _nodename ? _nodename : "device/pci/0";
149    int dom;
150
151    struct pcifront_dev *dev;
152
153    char path[bmk_strlen(nodename) + 1 + 10 + 1];
154
155    if (!_nodename && pcidev)
156        return pcidev;
157
158    bmk_snprintf(path, sizeof(path), "%s/backend-id", nodename);
159    dom = xenbus_read_integer(path);
160    if (dom == -1) {
161        minios_printk("no backend\n");
162        return NULL;
163    }
164
165    dev = bmk_memcalloc(1, sizeof(*dev), BMK_MEMWHO_WIREDBMK);
166    bmk_strncpy(dev->nodename, nodename, sizeof(dev->nodename)-1);
167    dev->dom = dom;
168
169    minios_evtchn_alloc_unbound(dev->dom, pcifront_handler, dev, &dev->evtchn);
170
171    dev->info = bmk_pgalloc_one();
172    bmk_memset(dev->info,0,PAGE_SIZE);
173
174    dev->info_ref = gnttab_grant_access(dev->dom,virt_to_mfn(dev->info),0);
175
176    xenbus_event_queue_init(&dev->events);
177
178again:
179    err = xenbus_transaction_start(&xbt);
180    if (err) {
181        minios_printk("starting transaction\n");
182        bmk_memfree(err, BMK_MEMWHO_WIREDBMK);
183    }
184
185    err = xenbus_printf(xbt, nodename, "pci-op-ref","%u",
186                dev->info_ref);
187    if (err) {
188        message = "writing pci-op-ref";
189        goto abort_transaction;
190    }
191    err = xenbus_printf(xbt, nodename,
192                "event-channel", "%u", dev->evtchn);
193    if (err) {
194        message = "writing event-channel";
195        goto abort_transaction;
196    }
197    err = xenbus_printf(xbt, nodename,
198                "magic", XEN_PCI_MAGIC);
199    if (err) {
200        message = "writing magic";
201        goto abort_transaction;
202    }
203
204    bmk_snprintf(path, sizeof(path), "%s/state", nodename);
205    err = xenbus_switch_state(xbt, path, XenbusStateInitialised);
206    if (err) {
207        message = "switching state";
208        goto abort_transaction;
209    }
210
211    err = xenbus_transaction_end(xbt, 0, &retry);
212    if (err) bmk_memfree(err, BMK_MEMWHO_WIREDBMK);
213    if (retry) {
214            goto again;
215        minios_printk("completing transaction\n");
216    }
217
218    goto done;
219
220abort_transaction:
221    bmk_memfree(err, BMK_MEMWHO_WIREDBMK);
222    err = xenbus_transaction_end(xbt, 1, &retry);
223    minios_printk("Abort transaction %s\n", message);
224    goto error;
225
226done:
227
228    bmk_snprintf(path, sizeof(path), "%s/backend", nodename);
229    msg = xenbus_read(XBT_NIL, path, &dev->backend);
230    if (msg) {
231        minios_printk("Error %s when reading the backend path %s\n", msg, path);
232        goto error;
233    }
234
235    minios_printk("pcifront: node=%s backend=%s\n", nodename, dev->backend);
236
237    {
238        char path[bmk_strlen(dev->backend) + 1 + 5 + 1];
239        char frontpath[bmk_strlen(nodename) + 1 + 5 + 1];
240        XenbusState state;
241        bmk_snprintf(path, sizeof(path), "%s/state", dev->backend);
242
243        xenbus_watch_path_token(XBT_NIL, path, path, &dev->events);
244
245        err = NULL;
246        state = xenbus_read_integer(path);
247        while (err == NULL && state < XenbusStateConnected)
248            err = xenbus_wait_for_state_change(path, &state, &dev->events);
249        if (state != XenbusStateConnected) {
250            minios_printk("backend not avalable, state=%d\n", state);
251            xenbus_unwatch_path_token(XBT_NIL, path, path);
252            goto error;
253        }
254
255        bmk_snprintf(frontpath, sizeof(frontpath), "%s/state", nodename);
256        if ((err = xenbus_switch_state(XBT_NIL, frontpath, XenbusStateConnected))
257            != NULL) {
258            minios_printk("error switching state %s\n", err);
259            xenbus_unwatch_path_token(XBT_NIL, path, path);
260            goto error;
261        }
262    }
263    minios_unmask_evtchn(dev->evtchn);
264
265    if (!_nodename)
266        pcidev = dev;
267
268    return dev;
269
270error:
271    bmk_memfree(err, BMK_MEMWHO_WIREDBMK);
272    free_pcifront(dev);
273    return NULL;
274}
275
276/*
277 * XXX: why is the pci function in this module sometimes
278 * an int and sometimes a long?
279 */
280static int
281parsepciaddr(const char *s, unsigned int *domain, unsigned int *bus,
282    unsigned int *slot, unsigned long *fun)
283{
284    char *ep;
285
286    *domain = bmk_strtoul(s, &ep, 16);
287    if (*ep != ':') {
288        minios_printk("\"%s\" does not look like a PCI device address\n", s);
289        return 0;
290    }
291    *bus = bmk_strtoul(ep+1, &ep, 16);
292    if (*ep != ':') {
293        minios_printk("\"%s\" does not look like a PCI device address\n", s);
294        return 0;
295    }
296    *slot = bmk_strtoul(ep+1, &ep, 16);
297    if (*ep != '.') {
298        minios_printk("\"%s\" does not look like a PCI device address\n", s);
299        return 0;
300    }
301    *fun = bmk_strtoul(ep+1, &ep, 16);
302    if (*ep != '\0') {
303        minios_printk("\"%s\" does not look like a PCI device address\n", s);
304        return 0;
305    }
306
307    return 1;
308}
309
310void pcifront_scan(struct pcifront_dev *dev, void (*func)(unsigned int domain, unsigned int bus, unsigned slot, unsigned int fun))
311{
312    char *path;
313    int i, n, len, rv;
314    char *s, *msg = NULL;
315    unsigned int domain, bus, slot;
316    unsigned long fun;
317
318    if (!dev)
319        dev = pcidev;
320    if (!dev) {
321	minios_printk("pcifront_scan: device or bus\n");
322	return;
323    }
324
325    len = bmk_strlen(dev->backend) + 1 + 5 + 10 + 1;
326    path = (char *) bmk_xmalloc_bmk(len);
327    bmk_snprintf(path, len, "%s/num_devs", dev->backend);
328    n = xenbus_read_integer(path);
329
330    for (i = 0; i < n; i++) {
331        bmk_snprintf(path, len, "%s/dev-%d", dev->backend, i);
332        msg = xenbus_read(XBT_NIL, path, &s);
333        if (msg) {
334            minios_printk("Error %s when reading the PCI root name at %s\n", msg, path);
335            continue;
336        }
337
338        rv = parsepciaddr(s, &domain, &bus, &slot, &fun);
339        bmk_memfree(s, BMK_MEMWHO_WIREDBMK);
340        if (!rv)
341            continue;
342
343#undef NOTPCIADDR
344
345        if (func)
346            func(domain, bus, slot, fun);
347    }
348    bmk_memfree(path, BMK_MEMWHO_WIREDBMK);
349}
350
351void shutdown_pcifront(struct pcifront_dev *dev)
352{
353    char* err = NULL;
354    XenbusState state;
355
356    char path[bmk_strlen(dev->backend) + 1 + 5 + 1];
357    char nodename[bmk_strlen(dev->nodename) + 1 + 5 + 1];
358
359    minios_printk("close pci: backend at %s\n",dev->backend);
360
361    bmk_snprintf(path, sizeof(path), "%s/state", dev->backend);
362    bmk_snprintf(nodename, sizeof(nodename), "%s/state", dev->nodename);
363    if ((err = xenbus_switch_state(XBT_NIL, nodename, XenbusStateClosing)) != NULL) {
364        minios_printk("shutdown_pcifront: error changing state to %d: %s\n",
365                XenbusStateClosing, err);
366        goto close_pcifront;
367    }
368    state = xenbus_read_integer(path);
369    while (err == NULL && state < XenbusStateClosing)
370        err = xenbus_wait_for_state_change(path, &state, &dev->events);
371    if (err) bmk_memfree(err, BMK_MEMWHO_WIREDBMK);
372
373    if ((err = xenbus_switch_state(XBT_NIL, nodename, XenbusStateClosed)) != NULL) {
374        minios_printk("shutdown_pcifront: error changing state to %d: %s\n",
375                XenbusStateClosed, err);
376        goto close_pcifront;
377    }
378    state = xenbus_read_integer(path);
379    while (state < XenbusStateClosed) {
380        err = xenbus_wait_for_state_change(path, &state, &dev->events);
381        bmk_memfree(err, BMK_MEMWHO_WIREDBMK);
382    }
383
384    if ((err = xenbus_switch_state(XBT_NIL, nodename, XenbusStateInitialising)) != NULL) {
385        minios_printk("shutdown_pcifront: error changing state to %d: %s\n",
386                XenbusStateInitialising, err);
387        goto close_pcifront;
388    }
389    err = NULL;
390    state = xenbus_read_integer(path);
391    while (err == NULL && (state < XenbusStateInitWait || state >= XenbusStateClosed))
392        err = xenbus_wait_for_state_change(path, &state, &dev->events);
393
394close_pcifront:
395    if (err) bmk_memfree(err, BMK_MEMWHO_WIREDBMK);
396    xenbus_unwatch_path_token(XBT_NIL, path, path);
397
398    bmk_snprintf(path, sizeof(path), "%s/info-ref", nodename);
399    xenbus_rm(XBT_NIL, path);
400    bmk_snprintf(path, sizeof(path), "%s/event-channel", nodename);
401    xenbus_rm(XBT_NIL, path);
402
403    if (!err)
404        free_pcifront(dev);
405}
406
407int pcifront_physical_to_virtual (struct pcifront_dev *dev,
408                                  unsigned int *dom,
409                                  unsigned int *bus,
410                                  unsigned int *slot,
411                                  unsigned long *fun)
412{
413    char path[bmk_strlen(dev->backend) + 1 + 5 + 10 + 1];
414    int i, n, rv;
415    char *s, *msg = NULL;
416    unsigned int dom1, bus1, slot1;
417    unsigned long fun1;
418
419    if (!dev)
420        dev = pcidev;
421
422    bmk_snprintf(path, sizeof(path), "%s/num_devs", dev->backend);
423    n = xenbus_read_integer(path);
424
425    for (i = 0; i < n; i++) {
426        bmk_snprintf(path, sizeof(path), "%s/dev-%d", dev->backend, i);
427        msg = xenbus_read(XBT_NIL, path, &s);
428        if (msg) {
429            minios_printk("Error %s when reading the PCI root name at %s\n", msg, path);
430            continue;
431        }
432
433        rv = parsepciaddr(s, &dom1, &bus1, &slot1, &fun1);
434        bmk_memfree(s, BMK_MEMWHO_WIREDBMK);
435        if (!rv)
436            continue;
437
438        if (dom1 == *dom && bus1 == *bus && slot1 == *slot && fun1 == *fun) {
439            bmk_snprintf(path, sizeof(path), "%s/vdev-%d", dev->backend, i);
440            msg = xenbus_read(XBT_NIL, path, &s);
441            if (msg) {
442                minios_printk("Error %s when reading the PCI root name at %s\n", msg, path);
443                continue;
444            }
445
446            rv = parsepciaddr(s, dom, bus, slot, fun);
447            bmk_memfree(s, BMK_MEMWHO_WIREDBMK);
448            if (!rv)
449                continue;
450
451            return 0;
452        }
453    }
454    return -1;
455}
456
457void pcifront_op(struct pcifront_dev *dev, struct xen_pci_op *op)
458{
459    if (!dev)
460        dev = pcidev;
461    dev->info->op = *op;
462    /* Make sure info is written before the flag */
463    wmb();
464    set_bit(_XEN_PCIF_active, (void*) &dev->info->flags);
465    minios_notify_remote_via_evtchn(dev->evtchn);
466
467    minios_wait_event(pcifront_queue, !test_bit(_XEN_PCIF_active, (void*) &dev->info->flags));
468
469    /* Make sure flag is read before info */
470    rmb();
471    *op = dev->info->op;
472}
473
474int pcifront_conf_read(struct pcifront_dev *dev,
475                       unsigned int dom,
476                       unsigned int bus, unsigned int slot, unsigned long fun,
477                       unsigned int off, unsigned int size, unsigned int *val)
478{
479    struct xen_pci_op op;
480
481    if (!dev)
482        dev = pcidev;
483    if (!dev)
484        return BMK_ENXIO;
485
486    if (pcifront_physical_to_virtual(dev, &dom, &bus, &slot, &fun) < 0)
487        return XEN_PCI_ERR_dev_not_found;
488    bmk_memset(&op, 0, sizeof(op));
489
490    op.cmd = XEN_PCI_OP_conf_read;
491    op.domain = dom;
492    op.bus = bus;
493    op.devfn = PCI_DEVFN(slot, fun);
494    op.offset = off;
495    op.size = size;
496
497    pcifront_op(dev, &op);
498
499    if (op.err)
500        return op.err;
501
502    *val = op.value;
503
504    return 0;
505}
506
507int pcifront_conf_write(struct pcifront_dev *dev,
508                        unsigned int dom,
509                        unsigned int bus, unsigned int slot, unsigned long fun,
510                        unsigned int off, unsigned int size, unsigned int val)
511{
512    struct xen_pci_op op;
513
514    if (!dev)
515        dev = pcidev;
516    if (!dev)
517        return BMK_ENXIO;
518
519    if (pcifront_physical_to_virtual(dev, &dom, &bus, &slot, &fun) < 0)
520        return XEN_PCI_ERR_dev_not_found;
521    bmk_memset(&op, 0, sizeof(op));
522
523    op.cmd = XEN_PCI_OP_conf_write;
524    op.domain = dom;
525    op.bus = bus;
526    op.devfn = PCI_DEVFN(slot, fun);
527    op.offset = off;
528    op.size = size;
529
530    op.value = val;
531
532    pcifront_op(dev, &op);
533
534    return op.err;
535}
536
537int pcifront_enable_msi(struct pcifront_dev *dev,
538                        unsigned int dom,
539                        unsigned int bus, unsigned int slot, unsigned long fun)
540{
541    struct xen_pci_op op;
542
543    if (!dev)
544        dev = pcidev;
545    if (pcifront_physical_to_virtual(dev, &dom, &bus, &slot, &fun) < 0)
546        return XEN_PCI_ERR_dev_not_found;
547    bmk_memset(&op, 0, sizeof(op));
548
549    op.cmd = XEN_PCI_OP_enable_msi;
550    op.domain = dom;
551    op.bus = bus;
552    op.devfn = PCI_DEVFN(slot, fun);
553
554    pcifront_op(dev, &op);
555
556    if (op.err)
557        return op.err;
558    else
559        return op.value;
560}
561
562int pcifront_disable_msi(struct pcifront_dev *dev,
563                         unsigned int dom,
564                         unsigned int bus, unsigned int slot, unsigned long fun)
565{
566    struct xen_pci_op op;
567
568    if (!dev)
569        dev = pcidev;
570    if (pcifront_physical_to_virtual(dev, &dom, &bus, &slot, &fun) < 0)
571        return XEN_PCI_ERR_dev_not_found;
572    bmk_memset(&op, 0, sizeof(op));
573
574    op.cmd = XEN_PCI_OP_disable_msi;
575    op.domain = dom;
576    op.bus = bus;
577    op.devfn = PCI_DEVFN(slot, fun);
578
579    pcifront_op(dev, &op);
580
581    return op.err;
582}
583
584int pcifront_enable_msix(struct pcifront_dev *dev,
585                         unsigned int dom,
586                         unsigned int bus, unsigned int slot, unsigned long fun,
587                         struct xen_msix_entry *entries, int n)
588{
589    struct xen_pci_op op;
590
591    if (!dev)
592        dev = pcidev;
593    if (pcifront_physical_to_virtual(dev, &dom, &bus, &slot, &fun) < 0)
594        return XEN_PCI_ERR_dev_not_found;
595    if (n > SH_INFO_MAX_VEC)
596        return XEN_PCI_ERR_op_failed;
597
598    bmk_memset(&op, 0, sizeof(op));
599
600    op.cmd = XEN_PCI_OP_enable_msix;
601    op.domain = dom;
602    op.bus = bus;
603    op.devfn = PCI_DEVFN(slot, fun);
604    op.value = n;
605
606    bmk_memcpy(op.msix_entries, entries, n * sizeof(*entries));
607
608    pcifront_op(dev, &op);
609
610    if (op.err)
611        return op.err;
612
613    bmk_memcpy(entries, op.msix_entries, n * sizeof(*entries));
614
615    return 0;
616}
617
618
619int pcifront_disable_msix(struct pcifront_dev *dev,
620                          unsigned int dom,
621                          unsigned int bus, unsigned int slot, unsigned long fun)
622{
623    struct xen_pci_op op;
624
625    if (!dev)
626        dev = pcidev;
627    if (pcifront_physical_to_virtual(dev, &dom, &bus, &slot, &fun) < 0)
628        return XEN_PCI_ERR_dev_not_found;
629    bmk_memset(&op, 0, sizeof(op));
630
631    op.cmd = XEN_PCI_OP_disable_msix;
632    op.domain = dom;
633    op.bus = bus;
634    op.devfn = PCI_DEVFN(slot, fun);
635
636    pcifront_op(dev, &op);
637
638    return op.err;
639}
640