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