debuggers.hg

view extras/mini-os/pcifront.c @ 20689:23bc248302df

mini-os: Fix memory leaks in blkfront, netfront, pcifront, etc.

The return value of Xenbus routines xenbus_transaction_start(),
xenbus_printf(), xenbus_transaction_end(), etc. is a pointer of error
message. This pointer should be passed to free() to release the
allocated memory when it is no longer needed.

Signed-off-by: Yu Zhiguo <yuzg@cn.fujitsu.com>
author Keir Fraser <keir.fraser@citrix.com>
date Mon Dec 14 09:51:07 2009 +0000 (2009-12-14)
parents e10d641b413f
children 91232efdcfdc
line source
1 /* Minimal PCI driver for Mini-OS.
2 * Copyright (c) 2007-2008 Samuel Thibault.
3 * Based on blkfront.c.
4 */
6 #include <string.h>
7 #include <mini-os/os.h>
8 #include <mini-os/lib.h>
9 #include <mini-os/xenbus.h>
10 #include <mini-os/events.h>
11 #include <errno.h>
12 #include <mini-os/gnttab.h>
13 #include <mini-os/xmalloc.h>
14 #include <mini-os/wait.h>
15 #include <mini-os/pcifront.h>
16 #include <mini-os/sched.h>
18 #define PCI_DEVFN(slot, func) ((((slot) & 0x1f) << 3) | ((func) & 0x07))
20 DECLARE_WAIT_QUEUE_HEAD(pcifront_queue);
21 static struct pcifront_dev *pcidev;
23 struct pcifront_dev {
24 domid_t dom;
26 struct xen_pci_sharedinfo *info;
27 grant_ref_t info_ref;
28 evtchn_port_t evtchn;
30 char *nodename;
31 char *backend;
33 xenbus_event_queue events;
34 };
36 void pcifront_handler(evtchn_port_t port, struct pt_regs *regs, void *data)
37 {
38 wake_up(&pcifront_queue);
39 }
41 static void free_pcifront(struct pcifront_dev *dev)
42 {
43 if (!dev)
44 dev = pcidev;
46 mask_evtchn(dev->evtchn);
48 gnttab_end_access(dev->info_ref);
49 free_page(dev->info);
51 unbind_evtchn(dev->evtchn);
53 free(dev->backend);
54 free(dev->nodename);
55 free(dev);
56 }
58 void 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[strlen(nodename) + 9];
65 char fe_state[strlen(nodename) + 7];
66 xenbus_event_queue events = NULL;
68 snprintf(path, sizeof(path), "%s/backend", nodename);
69 snprintf(fe_state, sizeof(fe_state), "%s/state", nodename);
71 while (1) {
72 printk("pcifront_watches: waiting for backend path to happear %s\n", path);
73 xenbus_watch_path_token(XBT_NIL, path, path, &events);
74 while ((err = xenbus_read(XBT_NIL, path, &be_path)) != NULL) {
75 free(err);
76 xenbus_wait_for_watch(&events);
77 }
78 xenbus_unwatch_path_token(XBT_NIL, path, path);
79 printk("pcifront_watches: waiting for backend to get into the right state %s\n", be_path);
80 be_state = (char *) malloc(strlen(be_path) + 7);
81 snprintf(be_state, strlen(be_path) + 7, "%s/state", be_path);
82 xenbus_watch_path_token(XBT_NIL, be_state, be_state, &events);
83 while ((err = xenbus_read(XBT_NIL, be_state, &msg)) != NULL || msg[0] > '4') {
84 free(msg);
85 free(err);
86 xenbus_wait_for_watch(&events);
87 }
88 xenbus_unwatch_path_token(XBT_NIL, be_state, be_state);
89 if (init_pcifront(NULL) == NULL) {
90 free(be_state);
91 free(be_path);
92 continue;
93 }
94 xenbus_watch_path_token(XBT_NIL, be_state, be_state, &events);
95 state = XenbusStateConnected;
96 printk("pcifront_watches: waiting for backend events %s\n", be_state);
97 while ((err = xenbus_wait_for_state_change(be_state, &state, &events)) == NULL &&
98 (err = xenbus_read(XBT_NIL, pcidev->backend, &msg)) == NULL) {
99 free(msg);
100 printk("pcifront_watches: backend state changed: %s %d\n", be_state, state);
101 if (state == XenbusStateReconfiguring) {
102 printk("pcifront_watches: writing %s %d\n", fe_state, XenbusStateReconfiguring);
103 if ((err = xenbus_switch_state(XBT_NIL, fe_state, XenbusStateReconfiguring)) != NULL) {
104 printk("pcifront_watches: error changing state to %d: %s\n",
105 XenbusStateReconfiguring, err);
106 if (!strcmp(err, "ENOENT")) {
107 xenbus_write(XBT_NIL, fe_state, "7");
108 free(err);
109 }
110 }
111 } else if (state == XenbusStateReconfigured) {
112 printk("pcifront_watches: writing %s %d\n", fe_state, XenbusStateConnected);
113 printk("pcifront_watches: changing state to %d\n", XenbusStateConnected);
114 if ((err = xenbus_switch_state(XBT_NIL, fe_state, XenbusStateConnected)) != NULL) {
115 printk("pcifront_watches: error changing state to %d: %s\n",
116 XenbusStateConnected, err);
117 if (!strcmp(err, "ENOENT")) {
118 xenbus_write(XBT_NIL, fe_state, "4");
119 free(err);
120 }
121 }
122 } else if (state == XenbusStateClosing)
123 break;
124 }
125 if (err)
126 printk("pcifront_watches: done waiting err=%s\n", err);
127 else
128 printk("pcifront_watches: done waiting\n");
129 xenbus_unwatch_path_token(XBT_NIL, be_state, be_state);
130 shutdown_pcifront(pcidev);
131 free(be_state);
132 free(be_path);
133 free(err);
134 pcidev = NULL;
135 }
137 xenbus_unwatch_path_token(XBT_NIL, path, path);
138 }
140 struct pcifront_dev *init_pcifront(char *_nodename)
141 {
142 xenbus_transaction_t xbt;
143 char* err;
144 char* message=NULL;
145 int retry=0;
146 char* msg;
147 char* nodename = _nodename ? _nodename : "device/pci/0";
148 int dom;
150 struct pcifront_dev *dev;
152 char path[strlen(nodename) + 1 + 10 + 1];
154 if (!_nodename && pcidev)
155 return pcidev;
157 printk("******************* PCIFRONT for %s **********\n\n\n", nodename);
159 snprintf(path, sizeof(path), "%s/backend-id", nodename);
160 dom = xenbus_read_integer(path);
161 if (dom == -1) {
162 printk("no backend\n");
163 return NULL;
164 }
166 dev = malloc(sizeof(*dev));
167 memset(dev, 0, sizeof(*dev));
168 dev->nodename = strdup(nodename);
169 dev->dom = dom;
171 evtchn_alloc_unbound(dev->dom, pcifront_handler, dev, &dev->evtchn);
173 dev->info = (struct xen_pci_sharedinfo*) alloc_page();
174 memset(dev->info,0,PAGE_SIZE);
176 dev->info_ref = gnttab_grant_access(dev->dom,virt_to_mfn(dev->info),0);
178 dev->events = NULL;
180 again:
181 err = xenbus_transaction_start(&xbt);
182 if (err) {
183 printk("starting transaction\n");
184 free(err);
185 }
187 err = xenbus_printf(xbt, nodename, "pci-op-ref","%u",
188 dev->info_ref);
189 if (err) {
190 message = "writing pci-op-ref";
191 goto abort_transaction;
192 }
193 err = xenbus_printf(xbt, nodename,
194 "event-channel", "%u", dev->evtchn);
195 if (err) {
196 message = "writing event-channel";
197 goto abort_transaction;
198 }
199 err = xenbus_printf(xbt, nodename,
200 "magic", XEN_PCI_MAGIC);
201 if (err) {
202 message = "writing magic";
203 goto abort_transaction;
204 }
206 snprintf(path, sizeof(path), "%s/state", nodename);
207 err = xenbus_switch_state(xbt, path, XenbusStateInitialised);
208 if (err) {
209 message = "switching state";
210 goto abort_transaction;
211 }
213 err = xenbus_transaction_end(xbt, 0, &retry);
214 if (err) free(err);
215 if (retry) {
216 goto again;
217 printk("completing transaction\n");
218 }
220 goto done;
222 abort_transaction:
223 free(err);
224 err = xenbus_transaction_end(xbt, 1, &retry);
225 goto error;
227 done:
229 snprintf(path, sizeof(path), "%s/backend", nodename);
230 msg = xenbus_read(XBT_NIL, path, &dev->backend);
231 if (msg) {
232 printk("Error %s when reading the backend path %s\n", msg, path);
233 goto error;
234 }
236 printk("backend at %s\n", dev->backend);
238 {
239 char path[strlen(dev->backend) + 1 + 5 + 1];
240 char frontpath[strlen(nodename) + 1 + 5 + 1];
241 XenbusState state;
242 snprintf(path, sizeof(path), "%s/state", dev->backend);
244 xenbus_watch_path_token(XBT_NIL, path, path, &dev->events);
246 err = NULL;
247 state = xenbus_read_integer(path);
248 while (err == NULL && state < XenbusStateConnected)
249 err = xenbus_wait_for_state_change(path, &state, &dev->events);
250 if (state != XenbusStateConnected) {
251 printk("backend not avalable, state=%d\n", state);
252 xenbus_unwatch_path_token(XBT_NIL, path, path);
253 goto error;
254 }
256 snprintf(frontpath, sizeof(frontpath), "%s/state", nodename);
257 if ((err = xenbus_switch_state(XBT_NIL, frontpath, XenbusStateConnected))
258 != NULL) {
259 printk("error switching state %s\n", err);
260 xenbus_unwatch_path_token(XBT_NIL, path, path);
261 goto error;
262 }
263 }
264 unmask_evtchn(dev->evtchn);
266 printk("**************************\n");
268 if (!_nodename)
269 pcidev = dev;
271 return dev;
273 error:
274 free(err);
275 free_pcifront(dev);
276 return NULL;
277 }
279 void pcifront_scan(struct pcifront_dev *dev, void (*func)(unsigned int domain, unsigned int bus, unsigned slot, unsigned int fun))
280 {
281 char *path;
282 int i, n, len;
283 char *s, *msg = NULL, *err = NULL;
284 unsigned int domain, bus, slot, fun;
286 if (!dev)
287 dev = pcidev;
288 if (!dev) {
289 xenbus_event_queue events = NULL;
290 char *fe_state = "device/pci/0/state";
291 xenbus_watch_path_token(XBT_NIL, fe_state, fe_state, &events);
292 while ((err = xenbus_read(XBT_NIL, fe_state, &msg)) != NULL || msg[0] != '4') {
293 free(msg);
294 free(err);
295 printk("pcifront_scan: waiting for pcifront to become ready\n");
296 xenbus_wait_for_watch(&events);
297 }
298 xenbus_unwatch_path_token(XBT_NIL, fe_state, fe_state);
299 dev = pcidev;
300 }
302 len = strlen(dev->backend) + 1 + 5 + 10 + 1;
303 path = (char *) malloc(len);
304 snprintf(path, len, "%s/num_devs", dev->backend);
305 n = xenbus_read_integer(path);
307 for (i = 0; i < n; i++) {
308 snprintf(path, len, "%s/dev-%d", dev->backend, i);
309 msg = xenbus_read(XBT_NIL, path, &s);
310 if (msg) {
311 printk("Error %s when reading the PCI root name at %s\n", msg, path);
312 continue;
313 }
315 if (sscanf(s, "%x:%x:%x.%x", &domain, &bus, &slot, &fun) != 4) {
316 printk("\"%s\" does not look like a PCI device address\n", s);
317 free(s);
318 continue;
319 }
320 free(s);
322 if (func)
323 func(domain, bus, slot, fun);
324 }
325 free(path);
326 }
328 void shutdown_pcifront(struct pcifront_dev *dev)
329 {
330 char* err = NULL;
331 XenbusState state;
333 char path[strlen(dev->backend) + 1 + 5 + 1];
334 char nodename[strlen(dev->nodename) + 1 + 5 + 1];
336 printk("close pci: backend at %s\n",dev->backend);
338 snprintf(path, sizeof(path), "%s/state", dev->backend);
339 snprintf(nodename, sizeof(nodename), "%s/state", dev->nodename);
340 if ((err = xenbus_switch_state(XBT_NIL, nodename, XenbusStateClosing)) != NULL) {
341 printk("shutdown_pcifront: error changing state to %d: %s\n",
342 XenbusStateClosing, err);
343 goto close_pcifront;
344 }
345 state = xenbus_read_integer(path);
346 while (err == NULL && state < XenbusStateClosing)
347 err = xenbus_wait_for_state_change(path, &state, &dev->events);
348 if (err) free(err);
350 if ((err = xenbus_switch_state(XBT_NIL, nodename, XenbusStateClosed)) != NULL) {
351 printk("shutdown_pcifront: error changing state to %d: %s\n",
352 XenbusStateClosed, err);
353 goto close_pcifront;
354 }
355 state = xenbus_read_integer(path);
356 if (state < XenbusStateClosed) {
357 err = xenbus_wait_for_state_change(path, &state, &dev->events);
358 free(err);
359 }
361 if ((err = xenbus_switch_state(XBT_NIL, nodename, XenbusStateInitialising)) != NULL) {
362 printk("shutdown_pcifront: error changing state to %d: %s\n",
363 XenbusStateInitialising, err);
364 goto close_pcifront;
365 }
366 err = NULL;
367 state = xenbus_read_integer(path);
368 while (err == NULL && (state < XenbusStateInitWait || state >= XenbusStateClosed))
369 err = xenbus_wait_for_state_change(path, &state, &dev->events);
371 close_pcifront:
372 if (err) free(err);
373 xenbus_unwatch_path_token(XBT_NIL, path, path);
375 snprintf(path, sizeof(path), "%s/info-ref", nodename);
376 xenbus_rm(XBT_NIL, path);
377 snprintf(path, sizeof(path), "%s/event-channel", nodename);
378 xenbus_rm(XBT_NIL, path);
380 free_pcifront(dev);
381 }
383 int pcifront_physical_to_virtual (struct pcifront_dev *dev,
384 unsigned int *dom,
385 unsigned int *bus,
386 unsigned int *slot,
387 unsigned long *fun)
388 {
389 char path[strlen(dev->backend) + 1 + 5 + 10 + 1];
390 int i, n;
391 char *s, *msg = NULL;
392 unsigned int dom1, bus1, slot1, fun1;
394 if (!dev)
395 dev = pcidev;
397 snprintf(path, sizeof(path), "%s/num_devs", dev->backend);
398 n = xenbus_read_integer(path);
400 for (i = 0; i < n; i++) {
401 snprintf(path, sizeof(path), "%s/dev-%d", dev->backend, i);
402 msg = xenbus_read(XBT_NIL, path, &s);
403 if (msg) {
404 printk("Error %s when reading the PCI root name at %s\n", msg, path);
405 continue;
406 }
408 if (sscanf(s, "%x:%x:%x.%x", &dom1, &bus1, &slot1, &fun1) != 4) {
409 printk("\"%s\" does not look like a PCI device address\n", s);
410 free(s);
411 continue;
412 }
413 free(s);
415 if (dom1 == *dom && bus1 == *bus && slot1 == *slot && fun1 == *fun) {
416 snprintf(path, sizeof(path), "%s/vdev-%d", dev->backend, i);
417 msg = xenbus_read(XBT_NIL, path, &s);
418 if (msg) {
419 printk("Error %s when reading the PCI root name at %s\n", msg, path);
420 continue;
421 }
423 if (sscanf(s, "%x:%x:%x.%x", dom, bus, slot, fun) != 4) {
424 printk("\"%s\" does not look like a PCI device address\n", s);
425 free(s);
426 continue;
427 }
428 free(s);
430 return 0;
431 }
432 }
433 return -1;
434 }
436 void pcifront_op(struct pcifront_dev *dev, struct xen_pci_op *op)
437 {
438 if (!dev)
439 dev = pcidev;
440 dev->info->op = *op;
441 /* Make sure info is written before the flag */
442 wmb();
443 set_bit(_XEN_PCIF_active, (void*) &dev->info->flags);
444 notify_remote_via_evtchn(dev->evtchn);
446 wait_event(pcifront_queue, !test_bit(_XEN_PCIF_active, (void*) &dev->info->flags));
448 /* Make sure flag is read before info */
449 rmb();
450 *op = dev->info->op;
451 }
453 int pcifront_conf_read(struct pcifront_dev *dev,
454 unsigned int dom,
455 unsigned int bus, unsigned int slot, unsigned long fun,
456 unsigned int off, unsigned int size, unsigned int *val)
457 {
458 struct xen_pci_op op;
460 if (!dev)
461 dev = pcidev;
462 if (pcifront_physical_to_virtual(dev, &dom, &bus, &slot, &fun) < 0)
463 return XEN_PCI_ERR_dev_not_found;
464 memset(&op, 0, sizeof(op));
466 op.cmd = XEN_PCI_OP_conf_read;
467 op.domain = dom;
468 op.bus = bus;
469 op.devfn = PCI_DEVFN(slot, fun);
470 op.offset = off;
471 op.size = size;
473 pcifront_op(dev, &op);
475 if (op.err)
476 return op.err;
478 *val = op.value;
480 return 0;
481 }
483 int pcifront_conf_write(struct pcifront_dev *dev,
484 unsigned int dom,
485 unsigned int bus, unsigned int slot, unsigned long fun,
486 unsigned int off, unsigned int size, unsigned int val)
487 {
488 struct xen_pci_op op;
490 if (!dev)
491 dev = pcidev;
492 if (pcifront_physical_to_virtual(dev, &dom, &bus, &slot, &fun) < 0)
493 return XEN_PCI_ERR_dev_not_found;
494 memset(&op, 0, sizeof(op));
496 op.cmd = XEN_PCI_OP_conf_write;
497 op.domain = dom;
498 op.bus = bus;
499 op.devfn = PCI_DEVFN(slot, fun);
500 op.offset = off;
501 op.size = size;
503 op.value = val;
505 pcifront_op(dev, &op);
507 return op.err;
508 }
510 int pcifront_enable_msi(struct pcifront_dev *dev,
511 unsigned int dom,
512 unsigned int bus, unsigned int slot, unsigned long fun)
513 {
514 struct xen_pci_op op;
516 if (!dev)
517 dev = pcidev;
518 if (pcifront_physical_to_virtual(dev, &dom, &bus, &slot, &fun) < 0)
519 return XEN_PCI_ERR_dev_not_found;
520 memset(&op, 0, sizeof(op));
522 op.cmd = XEN_PCI_OP_enable_msi;
523 op.domain = dom;
524 op.bus = bus;
525 op.devfn = PCI_DEVFN(slot, fun);
527 pcifront_op(dev, &op);
529 if (op.err)
530 return op.err;
531 else
532 return op.value;
533 }
535 int pcifront_disable_msi(struct pcifront_dev *dev,
536 unsigned int dom,
537 unsigned int bus, unsigned int slot, unsigned long fun)
538 {
539 struct xen_pci_op op;
541 if (!dev)
542 dev = pcidev;
543 if (pcifront_physical_to_virtual(dev, &dom, &bus, &slot, &fun) < 0)
544 return XEN_PCI_ERR_dev_not_found;
545 memset(&op, 0, sizeof(op));
547 op.cmd = XEN_PCI_OP_disable_msi;
548 op.domain = dom;
549 op.bus = bus;
550 op.devfn = PCI_DEVFN(slot, fun);
552 pcifront_op(dev, &op);
554 return op.err;
555 }
557 int pcifront_enable_msix(struct pcifront_dev *dev,
558 unsigned int dom,
559 unsigned int bus, unsigned int slot, unsigned long fun,
560 struct xen_msix_entry *entries, int n)
561 {
562 struct xen_pci_op op;
564 if (!dev)
565 dev = pcidev;
566 if (pcifront_physical_to_virtual(dev, &dom, &bus, &slot, &fun) < 0)
567 return XEN_PCI_ERR_dev_not_found;
568 if (n > SH_INFO_MAX_VEC)
569 return XEN_PCI_ERR_op_failed;
571 memset(&op, 0, sizeof(op));
573 op.cmd = XEN_PCI_OP_enable_msix;
574 op.domain = dom;
575 op.bus = bus;
576 op.devfn = PCI_DEVFN(slot, fun);
577 op.value = n;
579 memcpy(op.msix_entries, entries, n * sizeof(*entries));
581 pcifront_op(dev, &op);
583 if (op.err)
584 return op.err;
586 memcpy(entries, op.msix_entries, n * sizeof(*entries));
588 return 0;
589 }
592 int pcifront_disable_msix(struct pcifront_dev *dev,
593 unsigned int dom,
594 unsigned int bus, unsigned int slot, unsigned long fun)
595 {
596 struct xen_pci_op op;
598 if (!dev)
599 dev = pcidev;
600 if (pcifront_physical_to_virtual(dev, &dom, &bus, &slot, &fun) < 0)
601 return XEN_PCI_ERR_dev_not_found;
602 memset(&op, 0, sizeof(op));
604 op.cmd = XEN_PCI_OP_disable_msix;
605 op.domain = dom;
606 op.bus = bus;
607 op.devfn = PCI_DEVFN(slot, fun);
609 pcifront_op(dev, &op);
611 return op.err;
612 }