debuggers.hg

view extras/mini-os/pcifront.c @ 17984:b3d827e63a09

stubdom: PCI passthrough support via PV-PCI

Signed-off-by: Samuel Thibault <samuel.thibault@eu.citrix.com>
author Keir Fraser <keir.fraser@citrix.com>
date Wed Jul 02 13:54:20 2008 +0100 (2008-07-02)
parents
children 97b4c5c511f0
line source
1 /* Minimal PCI driver for Mini-OS.
2 * Copyright (c) 2007-2008 Samuel Thibault.
3 * Based on blkfront.c.
4 */
6 #include <os.h>
7 #include <xenbus.h>
8 #include <events.h>
9 #include <errno.h>
10 #include <gnttab.h>
11 #include <xmalloc.h>
12 #include <wait.h>
13 #include <pcifront.h>
15 #define PCI_DEVFN(slot, func) ((((slot) & 0x1f) << 3) | ((func) & 0x07))
17 DECLARE_WAIT_QUEUE_HEAD(pcifront_queue);
19 struct pcifront_dev {
20 domid_t dom;
22 struct xen_pci_sharedinfo *info;
23 grant_ref_t info_ref;
24 evtchn_port_t evtchn;
26 char *nodename;
27 char *backend;
29 xenbus_event_queue events;
30 };
32 void pcifront_handler(evtchn_port_t port, struct pt_regs *regs, void *data)
33 {
34 wake_up(&pcifront_queue);
35 }
37 static void free_pcifront(struct pcifront_dev *dev)
38 {
39 mask_evtchn(dev->evtchn);
41 free(dev->backend);
43 gnttab_end_access(dev->info_ref);
44 free_page(dev->info);
46 unbind_evtchn(dev->evtchn);
48 free(dev->nodename);
49 free(dev);
50 }
52 struct pcifront_dev *init_pcifront(char *nodename)
53 {
54 xenbus_transaction_t xbt;
55 char* err;
56 char* message=NULL;
57 int retry=0;
58 char* msg;
60 struct pcifront_dev *dev;
62 if (!nodename)
63 nodename = "device/pci/0";
65 char path[strlen(nodename) + 1 + 10 + 1];
67 printk("******************* PCIFRONT for %s **********\n\n\n", nodename);
69 dev = malloc(sizeof(*dev));
70 memset(dev, 0, sizeof(*dev));
71 dev->nodename = strdup(nodename);
73 snprintf(path, sizeof(path), "%s/backend-id", nodename);
74 dev->dom = xenbus_read_integer(path);
75 evtchn_alloc_unbound(dev->dom, pcifront_handler, dev, &dev->evtchn);
77 dev->info = (struct xen_pci_sharedinfo*) alloc_page();
78 memset(dev->info,0,PAGE_SIZE);
80 dev->info_ref = gnttab_grant_access(dev->dom,virt_to_mfn(dev->info),0);
82 dev->events = NULL;
84 again:
85 err = xenbus_transaction_start(&xbt);
86 if (err) {
87 printk("starting transaction\n");
88 }
90 err = xenbus_printf(xbt, nodename, "pci-op-ref","%u",
91 dev->info_ref);
92 if (err) {
93 message = "writing pci-op-ref";
94 goto abort_transaction;
95 }
96 err = xenbus_printf(xbt, nodename,
97 "event-channel", "%u", dev->evtchn);
98 if (err) {
99 message = "writing event-channel";
100 goto abort_transaction;
101 }
102 err = xenbus_printf(xbt, nodename,
103 "magic", XEN_PCI_MAGIC);
104 if (err) {
105 message = "writing magic";
106 goto abort_transaction;
107 }
109 err = xenbus_printf(xbt, nodename, "state", "%u",
110 3); /* initialised */
113 err = xenbus_transaction_end(xbt, 0, &retry);
114 if (retry) {
115 goto again;
116 printk("completing transaction\n");
117 }
119 goto done;
121 abort_transaction:
122 xenbus_transaction_end(xbt, 1, &retry);
123 goto error;
125 done:
127 snprintf(path, sizeof(path), "%s/backend", nodename);
128 msg = xenbus_read(XBT_NIL, path, &dev->backend);
129 if (msg) {
130 printk("Error %s when reading the backend path %s\n", msg, path);
131 goto error;
132 }
134 printk("backend at %s\n", dev->backend);
136 {
137 char path[strlen(dev->backend) + 1 + 5 + 1];
138 snprintf(path, sizeof(path), "%s/state", dev->backend);
140 xenbus_watch_path_token(XBT_NIL, path, path, &dev->events);
142 xenbus_wait_for_value(path, "4", &dev->events);
144 xenbus_printf(xbt, nodename, "state", "%u", 4); /* connected */
145 }
146 unmask_evtchn(dev->evtchn);
148 printk("**************************\n");
150 return dev;
152 error:
153 free_pcifront(dev);
154 return NULL;
155 }
157 void pcifront_scan(struct pcifront_dev *dev, void (*func)(unsigned int domain, unsigned int bus, unsigned slot, unsigned int fun))
158 {
159 char path[strlen(dev->backend) + 1 + 5 + 10 + 1];
160 int i, n;
161 char *s, *msg;
162 unsigned int domain, bus, slot, fun;
164 snprintf(path, sizeof(path), "%s/num_devs", dev->backend);
165 n = xenbus_read_integer(path);
167 for (i = 0; i < n; i++) {
168 snprintf(path, sizeof(path), "%s/vdev-%d", dev->backend, i);
169 msg = xenbus_read(XBT_NIL, path, &s);
170 if (msg) {
171 printk("Error %s when reading the PCI root name at %s\n", path);
172 continue;
173 }
175 if (sscanf(s, "%x:%x:%x.%x", &domain, &bus, &slot, &fun) != 4) {
176 printk("\"%s\" does not look like a PCI device address\n", s);
177 free(s);
178 continue;
179 }
180 free(s);
182 func(domain, bus, slot, fun);
183 }
184 }
186 void shutdown_pcifront(struct pcifront_dev *dev)
187 {
188 char* err;
189 char *nodename = dev->nodename;
191 char path[strlen(dev->backend) + 1 + 5 + 1];
193 printk("close pci: backend at %s\n",dev->backend);
195 snprintf(path, sizeof(path), "%s/state", dev->backend);
196 err = xenbus_printf(XBT_NIL, nodename, "state", "%u", 5); /* closing */
197 xenbus_wait_for_value(path, "5", &dev->events);
199 err = xenbus_printf(XBT_NIL, nodename, "state", "%u", 6);
200 xenbus_wait_for_value(path, "6", &dev->events);
202 err = xenbus_printf(XBT_NIL, nodename, "state", "%u", 1);
203 xenbus_wait_for_value(path, "2", &dev->events);
205 xenbus_unwatch_path(XBT_NIL, path);
207 snprintf(path, sizeof(path), "%s/info-ref", nodename);
208 xenbus_rm(XBT_NIL, path);
209 snprintf(path, sizeof(path), "%s/event-channel", nodename);
210 xenbus_rm(XBT_NIL, path);
212 free_pcifront(dev);
213 }
216 void pcifront_op(struct pcifront_dev *dev, struct xen_pci_op *op)
217 {
218 dev->info->op = *op;
219 /* Make sure info is written before the flag */
220 wmb();
221 set_bit(_XEN_PCIF_active, &dev->info->flags);
222 notify_remote_via_evtchn(dev->evtchn);
224 wait_event(pcifront_queue, !test_bit(_XEN_PCIF_active, &dev->info->flags));
226 /* Make sure flag is read before info */
227 rmb();
228 *op = dev->info->op;
229 }
231 int pcifront_conf_read(struct pcifront_dev *dev,
232 unsigned int dom,
233 unsigned int bus, unsigned int slot, unsigned long fun,
234 unsigned int off, unsigned int size, unsigned int *val)
235 {
236 struct xen_pci_op op;
238 memset(&op, 0, sizeof(op));
240 op.cmd = XEN_PCI_OP_conf_read;
241 op.domain = dom;
242 op.bus = bus;
243 op.devfn = PCI_DEVFN(slot, fun);
244 op.offset = off;
245 op.size = size;
247 pcifront_op(dev, &op);
249 if (op.err)
250 return op.err;
252 *val = op.value;
254 return 0;
255 }
257 int pcifront_conf_write(struct pcifront_dev *dev,
258 unsigned int dom,
259 unsigned int bus, unsigned int slot, unsigned long fun,
260 unsigned int off, unsigned int size, unsigned int val)
261 {
262 struct xen_pci_op op;
264 memset(&op, 0, sizeof(op));
266 op.cmd = XEN_PCI_OP_conf_write;
267 op.domain = dom;
268 op.bus = bus;
269 op.devfn = PCI_DEVFN(slot, fun);
270 op.offset = off;
271 op.size = size;
273 op.value = val;
275 pcifront_op(dev, &op);
277 return op.err;
278 }