1/* $NetBSD: pciback.c,v 1.6 2011/12/07 15:47:43 cegger Exp $ */ 2 3/* 4 * Copyright (c) 2009 Manuel Bouyer. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 16 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 17 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 18 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 19 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 20 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 21 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 22 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 24 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 * 26 */ 27 28#include <sys/cdefs.h> 29__KERNEL_RCSID(0, "$NetBSD: pciback.c,v 1.6 2011/12/07 15:47:43 cegger Exp $"); 30 31#include "opt_xen.h" 32 33 34#include <sys/types.h> 35#include <sys/param.h> 36#include <sys/systm.h> 37#include <sys/errno.h> 38#include <sys/malloc.h> 39#include <sys/kernel.h> 40#include <sys/bus.h> 41#include <sys/queue.h> 42 43#include <uvm/uvm_extern.h> 44 45#include <machine/bus_private.h> 46 47#include <dev/isa/isareg.h> 48 49#include <xen/hypervisor.h> 50#include <xen/evtchn.h> 51#include <xen/granttables.h> 52#include <xen/xen-public/io/pciif.h> 53#include <xen/xenbus.h> 54 55#include <sys/stat.h> 56#include <sys/dirent.h> 57#include <miscfs/specfs/specdev.h> 58#include <miscfs/kernfs/kernfs.h> 59#include <xen/kernfs_machdep.h> 60 61#include "locators.h" 62 63#include <dev/pci/pcivar.h> 64#include <machine/i82093var.h> 65 66struct pciback_pci_softc; 67struct pb_xenbus_instance; 68/* list of devices we handle */ 69struct pciback_pci_dev { 70 SLIST_ENTRY(pciback_pci_dev) pb_devlist_next; /* global list of pbd */ 71 SLIST_ENTRY(pciback_pci_dev) pb_guest_next; /* per-guest list of pbd */ 72 u_int pb_bus; /* our location */ 73 u_int pb_device; 74 u_int pb_function; 75 pci_chipset_tag_t pb_pc; 76 pcitag_t pb_tag; 77 struct pciback_pci_softc *pb_pci_softc; 78 struct pb_xenbus_instance *pbx_instance; 79}; 80 81/* list of devices we want to match */ 82SLIST_HEAD(pciback_pci_devlist, pciback_pci_dev) pciback_pci_devlist_head = 83 SLIST_HEAD_INITIALIZER(pciback_pci_devlist_head); 84 85/* PCI-related functions and definitions */ 86 87#define PCI_NBARS ((PCI_MAPREG_END - PCI_MAPREG_START) / 4) 88 89struct pciback_pci_softc { 90 device_t sc_dev; 91 void *sc_ih; /* our interrupt; */ 92 struct pciback_pci_dev *sc_pb; /* our location */ 93 struct pci_bar { 94 bus_space_tag_t b_t; 95 bus_space_handle_t b_h; 96 bus_addr_t b_addr; 97 bus_size_t b_size; 98 int b_type; 99 int b_valid; 100 } sc_bars[PCI_NBARS]; 101 pci_intr_handle_t sc_intrhandle; 102 int sc_irq; 103 pcireg_t sc_id; 104 pcireg_t sc_subid; 105 char sc_kernfsname[16]; 106}; 107 108int pciback_pci_match(device_t, cfdata_t, void *); 109void pciback_pci_attach(device_t, device_t, void *); 110static struct pciback_pci_dev* pciback_pci_lookup(u_int, u_int, u_int); 111static void pciback_pci_init(void); 112 113static int pciback_parse_pci(const char *, u_int *, u_int *, u_int *); 114 115/* kernfs-related functions and definitions */ 116 117static kernfs_parentdir_t *pciback_kern_pkt; 118static int pciback_kernfs_read(void *); 119 120#define DIR_MODE (S_IRUSR|S_IXUSR|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH) 121#define FILE_MODE (S_IRUSR) 122static const struct kernfs_fileop pciback_dev_fileops[] = { 123 { .kf_fileop = KERNFS_FILEOP_READ, .kf_vop = pciback_kernfs_read }, 124}; 125 126/* xenbus-related functions and definitions */ 127 128static int pciback_xenbus_create(struct xenbus_device *); 129static int pciback_xenbus_destroy(void *); 130static void pciback_xenbus_frontend_changed(void *, XenbusState); 131static struct pb_xenbus_instance * pbxif_lookup(domid_t); 132static void pciback_xenbus_export_device(struct pb_xenbus_instance *, char *); 133static void pciback_xenbus_export_roots(struct pb_xenbus_instance *); 134 135static int pciback_xenbus_evthandler(void *); 136 137/* emulate byte and word access to PCI config space */ 138static inline u_int8_t 139pciback_read_byte(pci_chipset_tag_t pc, pcitag_t pa, int reg) 140{ 141 142 return (pci_conf_read(pc, pa, (reg & ~0x03)) >> 143 ((reg & 0x03) * 8) & 0xff); 144} 145 146static inline u_int16_t 147pciback_read_word(pci_chipset_tag_t pc, pcitag_t pa, int reg) 148{ 149 return (pci_conf_read(pc, pa, (reg & ~0x03)) >> 150 ((reg & 0x03) * 8) & 0xffff); 151} 152 153static inline void 154pciback_write_byte(pci_chipset_tag_t pc, pcitag_t pa, int reg, uint8_t val) 155{ 156 pcireg_t pcival; 157 158 pcival = pci_conf_read(pc, pa, (reg & ~0x03)); 159 pcival &= ~(0xff << ((reg & 0x03) * 8)); 160 pcival |= (val << ((reg & 0x03) * 8)); 161 pci_conf_write(pc, pa, (reg & ~0x03), pcival); 162} 163 164static inline void 165pciback_write_word(pci_chipset_tag_t pc, pcitag_t pa, int reg, uint16_t val) 166{ 167 pcireg_t pcival; 168 169 pcival = pci_conf_read(pc, pa, (reg & ~0x03)); 170 pcival &= ~(0xffff << ((reg & 0x03) * 8)); 171 pcival |= (val << ((reg & 0x03) * 8)); 172 pci_conf_write(pc, pa, (reg & ~0x03), pcival); 173} 174 175 176 177CFATTACH_DECL_NEW(pciback, sizeof(struct pciback_pci_softc), 178 pciback_pci_match, pciback_pci_attach, NULL, NULL); 179 180static int pciback_pci_inited = 0; 181 182/* a xenbus PCI backend instance */ 183struct pb_xenbus_instance { 184 SLIST_ENTRY(pb_xenbus_instance) pbx_next; /* list of backend instances*/ 185 struct xenbus_device *pbx_xbusd; 186 domid_t pbx_domid; 187 struct pciback_pci_devlist pbx_pb_pci_dev; /* list of exported PCI devices */ 188 /* communication with the domU */ 189 unsigned int pbx_evtchn; /* our even channel */ 190 struct xen_pci_sharedinfo *pbx_sh_info; 191 grant_handle_t pbx_shinfo_handle; /* to unmap shared page */ 192}; 193 194SLIST_HEAD(, pb_xenbus_instance) pb_xenbus_instances; 195 196static struct xenbus_backend_driver pci_backend_driver = { 197 .xbakd_create = pciback_xenbus_create, 198 .xbakd_type = "pci" 199}; 200 201int 202pciback_pci_match(device_t parent, cfdata_t match, void *aux) 203{ 204 struct pci_attach_args *pa = aux; 205 if (pciback_pci_inited == 0) { 206 pciback_pci_init(); 207 pciback_pci_inited = 1; 208 } 209 if (pciback_pci_lookup(pa->pa_bus, pa->pa_device, pa->pa_function)) 210 return 500; /* we really want to take over anything else */ 211 return 0; 212} 213 214void 215pciback_pci_attach(device_t parent, device_t self, void *aux) 216{ 217 struct pci_attach_args *pa = aux; 218 struct pciback_pci_softc *sc = device_private(self); 219 char devinfo[256]; 220 int i; 221 const char *intrstr; 222 kernfs_entry_t *dkt; 223 kfstype kfst; 224 pcireg_t reg; 225 226 sc->sc_dev = self; 227 sc->sc_pb = pciback_pci_lookup(pa->pa_bus, pa->pa_device, pa->pa_function); 228 if (sc->sc_pb == NULL) 229 panic("pciback_pci_attach: pciback_lookup"); 230 pci_devinfo(pa->pa_id, pa->pa_class, 0, devinfo, sizeof(devinfo)); 231 aprint_normal(": %s (rev. 0x%02x)\n", devinfo, 232 PCI_REVISION(pa->pa_class)); 233 sc->sc_pb->pb_pci_softc = sc; 234 sc->sc_pb->pb_pc = pa->pa_pc; 235 sc->sc_pb->pb_tag = pa->pa_tag; 236 237 sc->sc_id = pci_conf_read(pa->pa_pc, pa->pa_tag, PCI_ID_REG); 238 sc->sc_subid = pci_conf_read(pa->pa_pc, pa->pa_tag, PCI_SUBSYS_ID_REG); 239 240 for (i = 0; i < PCI_NBARS;) { 241 sc->sc_bars[i].b_type = pci_mapreg_type(pa->pa_pc, pa->pa_tag, 242 PCI_MAPREG_START + i * 4); 243 if (pci_mapreg_map(pa, PCI_MAPREG_START + i * 4, 244 sc->sc_bars[i].b_type, 0, 245 &sc->sc_bars[i].b_t, &sc->sc_bars[i].b_h, 246 &sc->sc_bars[i].b_addr, &sc->sc_bars[i].b_size) == 0) 247 sc->sc_bars[i].b_valid = 1; 248 if (sc->sc_bars[i].b_valid) { 249 aprint_verbose_dev(self, "%s: 0x%08jx - 0x%08jx\n", 250 (sc->sc_bars[i].b_type == PCI_MAPREG_TYPE_IO) ? 251 "I/O" : "mem", 252 (uintmax_t)sc->sc_bars[i].b_addr, 253 (uintmax_t)sc->sc_bars[i].b_size); 254 } 255 256 if (sc->sc_bars[i].b_type == 257 (PCI_MAPREG_TYPE_MEM | PCI_MAPREG_MEM_TYPE_64BIT)) 258 i += 2; 259 else 260 i += 1; 261 } 262 /* map the irq so interrupt routing is done */ 263 if (pci_intr_map(pa, &sc->sc_intrhandle) != 0) { 264 aprint_error_dev(self, "couldn't map interrupt\n"); 265 } else { 266 intrstr = pci_intr_string(pa->pa_pc, sc->sc_intrhandle); 267 aprint_normal_dev(self, "interrupting at %s\n", 268 intrstr ? intrstr : "unknown interrupt"); 269 } 270 unbind_pirq_from_evtch(APIC_IRQ_LEGACY_IRQ(sc->sc_intrhandle.pirq)); 271 sc->sc_irq = APIC_IRQ_LEGACY_IRQ(sc->sc_intrhandle.pirq); 272 /* XXX should be done elsewhere ? */ 273 reg = pci_conf_read(pa->pa_pc, pa->pa_tag, PCI_INTERRUPT_REG); 274 reg &= ~ (PCI_INTERRUPT_LINE_MASK << PCI_INTERRUPT_LINE_SHIFT); 275 reg |= (sc->sc_irq << PCI_INTERRUPT_LINE_SHIFT); 276 pci_conf_write(pa->pa_pc, pa->pa_tag, PCI_INTERRUPT_REG, reg); 277 printf("irq line %d pin %d sc %p\n", 278 PCI_INTERRUPT_LINE(pci_conf_read(pa->pa_pc, pa->pa_tag, PCI_INTERRUPT_REG)), 279 PCI_INTERRUPT_PIN(pci_conf_read(pa->pa_pc, pa->pa_tag, PCI_INTERRUPT_REG)), sc); 280 /* 281 * don't establish the interrupt, we're not interested in 282 * getting it here. 283 */ 284 /* publish the informations about this device to /kern/xen/pci */ 285 snprintf(sc->sc_kernfsname, sizeof(sc->sc_kernfsname), 286 "0000:%02x:%02x.%x", pa->pa_bus, pa->pa_device, pa->pa_function); 287 kfst = KERNFS_ALLOCTYPE(pciback_dev_fileops); 288 KERNFS_ALLOCENTRY(dkt, M_TEMP, M_WAITOK); 289 KERNFS_INITENTRY(dkt, DT_REG, sc->sc_kernfsname, sc, 290 kfst, VREG, FILE_MODE); 291 kernfs_addentry(pciback_kern_pkt, dkt); 292} 293 294static int 295pciback_kernfs_read(void *v) 296{ 297 struct vop_read_args /* { 298 struct vnode *a_vp; 299 struct uio *a_uio; 300 int a_ioflag; 301 struct ucred *a_cred; 302 } */ *ap = v; 303 struct kernfs_node *kfs = VTOKERN(ap->a_vp); 304 struct uio *uio = ap->a_uio; 305 struct pciback_pci_softc *sc = kfs->kfs_kt->kt_data; 306#define PCIBACK_KERNFS_SIZE 512 307 static char buf[PCIBACK_KERNFS_SIZE]; 308 off_t off; 309 off_t len; 310 int error, i; 311 312 off = uio->uio_offset; 313 len = 0; 314 len += snprintf(&buf[len], PCIBACK_KERNFS_SIZE - len, 315 "vendor: 0x%04x\nproduct: 0x%04x\n", 316 PCI_VENDOR(sc->sc_id), PCI_PRODUCT(sc->sc_id)); 317 len += snprintf(&buf[len], PCIBACK_KERNFS_SIZE - len, 318 "subsys_vendor: 0x%04x\nsubsys_product: 0x%04x\n", 319 PCI_VENDOR(sc->sc_subid), PCI_PRODUCT(sc->sc_subid)); 320 for(i = 0; i < PCI_NBARS; i++) { 321 if (sc->sc_bars[i].b_valid) { 322 len += snprintf(&buf[len], PCIBACK_KERNFS_SIZE - len, 323 "%s: 0x%08jx - 0x%08jx\n", 324 (sc->sc_bars[i].b_type == PCI_MAPREG_TYPE_IO) ? 325 "I/O" : "mem", 326 (uintmax_t)sc->sc_bars[i].b_addr, 327 (uintmax_t)(sc->sc_bars[i].b_addr + sc->sc_bars[i].b_size)); 328 } 329 } 330 len += snprintf(&buf[len], PCIBACK_KERNFS_SIZE - len, 331 "irq: %d\n", sc->sc_irq); 332 if (off >= len) { 333 error = uiomove(buf, 0, uio); 334 } else { 335 error = uiomove(&buf[off], len - off, uio); 336 } 337 return error; 338} 339 340static struct pciback_pci_dev* 341pciback_pci_lookup(u_int bus, u_int dev, u_int func) 342{ 343 struct pciback_pci_dev *pbd; 344 SLIST_FOREACH(pbd, &pciback_pci_devlist_head, pb_devlist_next) { 345 if (pbd->pb_bus == bus && 346 pbd->pb_device == dev && 347 pbd->pb_function == func) 348 return pbd; 349 } 350 return NULL; 351} 352 353static void 354pciback_pci_init(void) 355{ 356 union xen_cmdline_parseinfo xi; 357 char *pcidevs, *c; 358 u_int bus, dev, func; 359 struct pciback_pci_dev *pb; 360 kernfs_entry_t *dkt; 361 362 memset(&xi, 0, sizeof(xi)); 363 xen_parse_cmdline(XEN_PARSE_PCIBACK, &xi); 364 if (strlen(xi.xcp_pcidevs) == 0) 365 return; 366 pcidevs = xi.xcp_pcidevs; 367 for(pcidevs = xi.xcp_pcidevs; *pcidevs != '\0';) { 368 if (*pcidevs != '(') 369 goto error; 370 pcidevs++; 371 /* parse location */ 372 c = strchr(pcidevs, ')'); 373 if (c == NULL) 374 goto error; 375 *c = '\0'; 376 if (pciback_parse_pci(pcidevs, &bus, &dev, &func) == 0) { 377 pb = malloc(sizeof(struct pciback_pci_dev), M_DEVBUF, 378 M_NOWAIT | M_ZERO); 379 if (pb == NULL) { 380 aprint_error("pciback_pci_init: out or memory\n"); 381 return; 382 } 383 pb->pb_bus = bus; 384 pb->pb_device = dev; 385 pb->pb_function = func; 386 aprint_verbose("pciback_pci_init: hide claim device " 387 "%x:%x:%x\n", bus, dev, func); 388 SLIST_INSERT_HEAD(&pciback_pci_devlist_head, pb, 389 pb_devlist_next); 390 } 391 pcidevs = c + 1; 392 } 393 xenbus_backend_register(&pci_backend_driver); 394 395 KERNFS_ALLOCENTRY(dkt, M_TEMP, M_WAITOK); 396 KERNFS_INITENTRY(dkt, DT_DIR, "pci", NULL, KFSsubdir, VDIR, DIR_MODE); 397 kernfs_addentry(kernxen_pkt, dkt); 398 pciback_kern_pkt = KERNFS_ENTOPARENTDIR(dkt); 399 return; 400error: 401 aprint_error("pciback_pci_init: syntax error at %s\n", pcidevs); 402 return; 403} 404 405static int 406pciback_parse_pci(const char *str, u_int *busp, u_int *devp, u_int *funcp) 407{ 408 char *c; 409 410 /* parse location */ 411 c = strchr(str, ':'); 412 if (c == NULL) 413 goto error; 414 if (strncmp("0000", str, 4) == 0) { 415 /* must be domain number, get next */ 416 str = c + 1; 417 } 418 *busp = strtoul(str, &c, 16); 419 if (*c != ':') 420 goto error; 421 str = c + 1; 422 *devp = strtoul(str, &c, 16); 423 if (*c != '.') 424 goto error; 425 str = c + 1; 426 *funcp = strtoul(str, &c, 16); 427 if (*c != '\0') 428 goto error; 429 return 0; 430error: 431 aprint_error("pciback_pci_init: syntax error at char %c\n", *c); 432 return EINVAL; 433} 434 435static int 436pciback_xenbus_create(struct xenbus_device *xbusd) 437{ 438 struct pb_xenbus_instance *pbxi; 439 long domid; 440 char *val; 441 char path[10]; 442 int i, err; 443 u_long num_devs; 444 445 if ((err = xenbus_read_ul(NULL, xbusd->xbusd_path, 446 "frontend-id", &domid, 10)) != 0) { 447 aprint_error("pciback: can' read %s/frontend-id: %d\n", 448 xbusd->xbusd_path, err); 449 return err; 450 } 451 452 if (pbxif_lookup(domid) != NULL) { 453 return EEXIST; 454 } 455 pbxi = malloc(sizeof(struct pb_xenbus_instance), M_DEVBUF, 456 M_NOWAIT | M_ZERO); 457 if (pbxi == NULL) { 458 return ENOMEM; 459 } 460 pbxi->pbx_domid = domid; 461 462 xbusd->xbusd_u.b.b_cookie = pbxi; 463 xbusd->xbusd_u.b.b_detach = pciback_xenbus_destroy; 464 pbxi->pbx_xbusd = xbusd; 465 466 SLIST_INIT(&pbxi->pbx_pb_pci_dev); 467 468 SLIST_INSERT_HEAD(&pb_xenbus_instances, pbxi, pbx_next); 469 470 xbusd->xbusd_otherend_changed = pciback_xenbus_frontend_changed; 471 472 err = xenbus_switch_state(xbusd, NULL, XenbusStateInitWait); 473 if (err) { 474 printf("failed to switch state on %s: %d\n", 475 xbusd->xbusd_path, err); 476 goto fail; 477 } 478 if ((err = xenbus_read_ul(NULL, xbusd->xbusd_path, "num_devs", 479 &num_devs, 10)) != 0) { 480 aprint_error("pciback: can' read %s/num_devs %d\n", 481 xbusd->xbusd_path, err); 482 goto fail; 483 } 484 for (i = 0; i < num_devs; i++) { 485 snprintf(path, sizeof(path), "dev-%d", i); 486 if ((err = xenbus_read(NULL, xbusd->xbusd_path, path, 487 NULL, &val)) != 0) { 488 aprint_error("pciback: can' read %s/%s: %d\n", 489 xbusd->xbusd_path, path, err); 490 goto fail; 491 } 492 pciback_xenbus_export_device(pbxi, val); 493 free(val, M_DEVBUF); 494 } 495 pciback_xenbus_export_roots(pbxi); 496 if ((err = xenbus_switch_state(xbusd, NULL, XenbusStateInitialised))) { 497 printf("failed to switch state on %s: %d\n", 498 xbusd->xbusd_path, err); 499 goto fail; 500 } 501 502 return 0; 503fail: 504 free(pbxi, M_DEVBUF); 505 return err; 506} 507 508static int 509pciback_xenbus_destroy(void *arg) 510{ 511 struct pb_xenbus_instance *pbxi = arg; 512 struct pciback_pci_dev *pbd; 513 struct gnttab_unmap_grant_ref op; 514 int err; 515 516 hypervisor_mask_event(pbxi->pbx_evtchn); 517 event_remove_handler(pbxi->pbx_evtchn, 518 pciback_xenbus_evthandler, pbxi); 519 520 SLIST_REMOVE(&pb_xenbus_instances, 521 pbxi, pb_xenbus_instance, pbx_next); 522 523 if (pbxi->pbx_sh_info) { 524 op.host_addr = (vaddr_t)pbxi->pbx_sh_info; 525 op.handle = pbxi->pbx_shinfo_handle; 526 op.dev_bus_addr = 0; 527 err = HYPERVISOR_grant_table_op(GNTTABOP_unmap_grant_ref, 528 &op, 1); 529 if (err) 530 aprint_error("pciback: unmap_grant_ref failed: %d\n", 531 err); 532 } 533 SLIST_FOREACH(pbd, &pbxi->pbx_pb_pci_dev, pb_guest_next) { 534 pbd->pbx_instance = NULL; 535 } 536 uvm_km_free(kernel_map, (vaddr_t)pbxi->pbx_sh_info, 537 PAGE_SIZE, UVM_KMF_VAONLY); 538 free(pbxi, M_DEVBUF); 539 return 0; 540} 541 542static void 543pciback_xenbus_frontend_changed(void *arg, XenbusState new_state) 544{ 545 struct pb_xenbus_instance *pbxi = arg; 546 struct xenbus_device *xbusd = pbxi->pbx_xbusd; 547 int err; 548 struct gnttab_map_grant_ref op; 549 evtchn_op_t evop; 550 u_long shared_ref; 551 u_long revtchn; 552 553 /* do it only once */ 554 if (xenbus_read_driver_state(xbusd->xbusd_path) != 555 XenbusStateInitialised) 556 return; 557 558 switch(new_state) { 559 case XenbusStateInitialising: 560 case XenbusStateConnected: 561 break; 562 case XenbusStateInitialised: 563 /* read comunication informations */ 564 err = xenbus_read_ul(NULL, xbusd->xbusd_otherend, 565 "pci-op-ref", &shared_ref, 10); 566 if (err) { 567 xenbus_dev_fatal(xbusd, err, "reading %s/pci-op-ref", 568 xbusd->xbusd_otherend); 569 break; 570 } 571 err = xenbus_read_ul(NULL, xbusd->xbusd_otherend, 572 "event-channel", &revtchn, 10); 573 if (err) { 574 xenbus_dev_fatal(xbusd, err, "reading %s/event-channel", 575 xbusd->xbusd_otherend); 576 break; 577 } 578 /* allocate VA space and map rings */ 579 pbxi->pbx_sh_info = (void *)uvm_km_alloc(kernel_map, 580 PAGE_SIZE, 0, UVM_KMF_VAONLY); 581 if (pbxi->pbx_sh_info == 0) { 582 xenbus_dev_fatal(xbusd, ENOMEM, 583 "can't get VA for shared infos", 584 xbusd->xbusd_otherend); 585 break; 586 } 587 op.host_addr = (vaddr_t)pbxi->pbx_sh_info; 588 op.flags = GNTMAP_host_map; 589 op.ref = shared_ref; 590 op.dom = pbxi->pbx_domid; 591 err = HYPERVISOR_grant_table_op(GNTTABOP_map_grant_ref, &op, 1); 592 if (err || op.status) { 593 aprint_error("pciback: can't map shared grant ref: " 594 "%d/%d\n", err, op.status); 595 goto err1; 596 } 597 pbxi->pbx_shinfo_handle = op.handle; 598 599 evop.cmd = EVTCHNOP_bind_interdomain; 600 evop.u.bind_interdomain.remote_dom = pbxi->pbx_domid; 601 evop.u.bind_interdomain.remote_port = revtchn; 602 err = HYPERVISOR_event_channel_op(&evop); 603 if (err) { 604 printf("pciback: can't get event channel: %d\n", err); 605 goto err1; 606 } 607 pbxi->pbx_evtchn = evop.u.bind_interdomain.local_port; 608 x86_sfence(); 609 xenbus_switch_state(xbusd, NULL, XenbusStateConnected); 610 x86_sfence(); 611 event_set_handler(pbxi->pbx_evtchn, pciback_xenbus_evthandler, 612 pbxi, IPL_BIO, "pciback"); 613 hypervisor_enable_event(pbxi->pbx_evtchn); 614 hypervisor_notify_via_evtchn(pbxi->pbx_evtchn); 615 break; 616 617 case XenbusStateClosing: 618 xenbus_switch_state(xbusd, NULL, XenbusStateClosing); 619 break; 620 621 case XenbusStateClosed: 622 /* otherend_changed() should handle it for us */ 623 panic("pciback_xenbus_frontend_changed: closed\n"); 624 case XenbusStateUnknown: 625 case XenbusStateInitWait: 626 default: 627 aprint_error("pciback: invalid frontend state %d\n", 628 new_state); 629 break; 630 } 631 return; 632err1: 633 uvm_km_free(kernel_map, (vaddr_t)pbxi->pbx_sh_info, 634 PAGE_SIZE, UVM_KMF_VAONLY); 635} 636 637/* lookup a pbxi based on domain id and interface handle */ 638static struct pb_xenbus_instance * 639pbxif_lookup(domid_t dom) 640{ 641 struct pb_xenbus_instance *pbxi; 642 643 SLIST_FOREACH(pbxi, &pb_xenbus_instances, pbx_next) { 644 if (pbxi->pbx_domid == dom) 645 return pbxi; 646 } 647 return NULL; 648} 649 650static void 651pciback_xenbus_export_device(struct pb_xenbus_instance *pbxi, char *val) 652{ 653 u_int bus, dev, func; 654 struct pciback_pci_dev *pbd; 655 if (pciback_parse_pci(val, &bus, &dev, &func)) { 656 aprint_error("pciback: can't parse %s\n", val); 657 return; 658 } 659 pbd = pciback_pci_lookup(bus, dev, func); 660 if (pbd == NULL) { 661 aprint_error("pciback: can't locate 0x%02x:0x%02x.0x%02x\n", 662 bus, dev, func); 663 return; 664 } 665 if (pbd->pb_pci_softc == NULL) { 666 aprint_error("pciback: 0x%02x:0x%02x.0x%02x not detected\n", 667 bus, dev, func); 668 return; 669 } 670 pbd->pbx_instance = pbxi; 671 SLIST_INSERT_HEAD(&pbxi->pbx_pb_pci_dev, pbd, pb_guest_next); 672 return; 673} 674 675static void 676pciback_xenbus_export_roots(struct pb_xenbus_instance *pbxi) 677{ 678 char bus[256]; 679 char root[10]; 680 struct pciback_pci_dev *pbd; 681 int num_roots = 0; 682 int err; 683 684 memset(bus, 0, sizeof(bus)); 685 686 SLIST_FOREACH(pbd, &pbxi->pbx_pb_pci_dev, pb_guest_next) { 687 if (bus[pbd->pb_bus] == 0) { 688 /* not published yet */ 689 snprintf(root, sizeof(root), "root-%d", num_roots); 690 err = xenbus_printf(NULL, 691 pbxi->pbx_xbusd->xbusd_path, 692 root, "0000:%02x", pbd->pb_bus); 693 if (err) { 694 aprint_error("pciback: can't write to %s/%s: " 695 "%d\n", pbxi->pbx_xbusd->xbusd_path, root, 696 err); 697 } 698 num_roots++; 699 bus[pbd->pb_bus]++; 700 } 701 } 702 err = xenbus_printf(NULL, pbxi->pbx_xbusd->xbusd_path, "root_num", 703 "%d", num_roots); 704 if (err) { 705 aprint_error("pciback: can't write to %s/root_num: " 706 "%d\n", pbxi->pbx_xbusd->xbusd_path, err); 707 } 708} 709 710static int 711pciback_xenbus_evthandler(void * arg) 712{ 713 struct pb_xenbus_instance *pbxi = arg; 714 struct pciback_pci_dev *pbd; 715 struct xen_pci_op *op = &pbxi->pbx_sh_info->op; 716 u_int bus, dev, func; 717 718 hypervisor_clear_event(pbxi->pbx_evtchn); 719 if (xen_atomic_test_bit(&pbxi->pbx_sh_info->flags, 720 _XEN_PCIF_active) == 0) 721 return 0; 722 if (op->domain != 0) { 723 aprint_error("pciback: domain %d != 0", op->domain); 724 op->err = XEN_PCI_ERR_dev_not_found; 725 goto end; 726 } 727 bus = op->bus; 728 dev = (op->devfn >> 3) & 0xff; 729 func = (op->devfn) & 0x7; 730 SLIST_FOREACH(pbd, &pbxi->pbx_pb_pci_dev, pb_guest_next) { 731 if (pbd->pb_bus == bus && 732 pbd->pb_device == dev && 733 pbd->pb_function == func) 734 break; 735 } 736 if (pbd == NULL) { 737 aprint_debug("pciback: %02x:%02x.%x not found\n", 738 bus, dev, func); 739 op->err = XEN_PCI_ERR_dev_not_found; 740 goto end; 741 } 742 switch(op->cmd) { 743 case XEN_PCI_OP_conf_read: 744 op->err = XEN_PCI_ERR_success; 745 switch (op->size) { 746 case 1: 747 op->value = pciback_read_byte(pbd->pb_pc, pbd->pb_tag, 748 op->offset); 749 break; 750 case 2: 751 op->value = pciback_read_word(pbd->pb_pc, pbd->pb_tag, 752 op->offset); 753 break; 754 case 4: 755 op->value = pci_conf_read(pbd->pb_pc, pbd->pb_tag, 756 op->offset); 757 break; 758 default: 759 aprint_error("pciback: bad size %d\n", op->size); 760 break; 761 } 762 break; 763 case XEN_PCI_OP_conf_write: 764 op->err = XEN_PCI_ERR_success; 765 switch(op->size) { 766 case 1: 767 pciback_write_byte(pbd->pb_pc, pbd->pb_tag, 768 op->offset, op->value); 769 break; 770 case 2: 771 pciback_write_word(pbd->pb_pc, pbd->pb_tag, 772 op->offset, op->value); 773 break; 774 case 4: 775 pci_conf_write(pbd->pb_pc, pbd->pb_tag, 776 op->offset, op->value); 777 break; 778 default: 779 aprint_error("pciback: bad size %d\n", op->size); 780 op->err = XEN_PCI_ERR_invalid_offset; 781 break; 782 } 783 break; 784 default: 785 aprint_error("pciback: unknown cmd %d\n", op->cmd); 786 op->err = XEN_PCI_ERR_not_implemented; 787 } 788end: 789 xen_atomic_clear_bit(&pbxi->pbx_sh_info->flags, _XEN_PCIF_active); 790 hypervisor_notify_via_evtchn(pbxi->pbx_evtchn); 791 return 1; 792} 793