1181643Skmacy/* 2181643Skmacy * Copyright (c) 2006, Cisco Systems, Inc. 3181643Skmacy * All rights reserved. 4181643Skmacy * 5181643Skmacy * Redistribution and use in source and binary forms, with or without 6181643Skmacy * modification, are permitted provided that the following conditions 7181643Skmacy * are met: 8181643Skmacy * 9181643Skmacy * 1. Redistributions of source code must retain the above copyright 10181643Skmacy * notice, this list of conditions and the following disclaimer. 11181643Skmacy * 2. Redistributions in binary form must reproduce the above copyright 12181643Skmacy * notice, this list of conditions and the following disclaimer in the 13181643Skmacy * documentation and/or other materials provided with the distribution. 14181643Skmacy * 3. Neither the name of Cisco Systems, Inc. nor the names of its contributors 15181643Skmacy * may be used to endorse or promote products derived from this software 16181643Skmacy * without specific prior written permission. 17181643Skmacy * 18181643Skmacy * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 19181643Skmacy * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20181643Skmacy * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21181643Skmacy * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 22181643Skmacy * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 23181643Skmacy * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 24181643Skmacy * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 25181643Skmacy * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 26181643Skmacy * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 27181643Skmacy * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 28181643Skmacy * POSSIBILITY OF SUCH DAMAGE. 29181643Skmacy */ 30181643Skmacy 31181643Skmacy#include <sys/cdefs.h> 32181643Skmacy__FBSDID("$FreeBSD$"); 33181643Skmacy 34181643Skmacy#include <sys/param.h> 35181643Skmacy#include <sys/module.h> 36181643Skmacy#include <sys/systm.h> 37181643Skmacy#include <sys/mbuf.h> 38181643Skmacy#include <sys/malloc.h> 39181643Skmacy#include <sys/kernel.h> 40181643Skmacy#include <sys/socket.h> 41181643Skmacy#include <sys/queue.h> 42181643Skmacy 43181643Skmacy#include <machine/vmparam.h> 44181643Skmacy#include <vm/vm.h> 45181643Skmacy#include <vm/pmap.h> 46181643Skmacy 47181643Skmacy#include <machine/bus.h> 48181643Skmacy#include <machine/resource.h> 49181643Skmacy#include <machine/frame.h> 50181643Skmacy 51181643Skmacy#include <sys/bus.h> 52181643Skmacy#include <sys/rman.h> 53181643Skmacy 54181643Skmacy#include <machine/intr_machdep.h> 55181643Skmacy 56181643Skmacy#include <machine/xen-os.h> 57181643Skmacy#include <machine/hypervisor.h> 58181643Skmacy#include <machine/hypervisor-ifs.h> 59181643Skmacy#include <machine/xen_intr.h> 60181643Skmacy#include <machine/evtchn.h> 61181643Skmacy#include <machine/xenbus.h> 62181643Skmacy#include <machine/gnttab.h> 63181643Skmacy#include <machine/xen-public/memory.h> 64181643Skmacy#include <machine/xen-public/io/pciif.h> 65181643Skmacy 66181643Skmacy#include <sys/pciio.h> 67181643Skmacy#include <dev/pci/pcivar.h> 68181643Skmacy#include "pcib_if.h" 69181643Skmacy 70181643Skmacy#ifdef XEN_PCIDEV_FE_DEBUG 71181643Skmacy#define DPRINTF(fmt, args...) \ 72181643Skmacy printf("pcifront (%s:%d): " fmt, __FUNCTION__, __LINE__, ##args) 73181643Skmacy#else 74181643Skmacy#define DPRINTF(fmt, args...) ((void)0) 75181643Skmacy#endif 76181643Skmacy#define WPRINTF(fmt, args...) \ 77181643Skmacy printf("pcifront (%s:%d): " fmt, __FUNCTION__, __LINE__, ##args) 78181643Skmacy 79181643Skmacy#define INVALID_GRANT_REF (0) 80181643Skmacy#define INVALID_EVTCHN (-1) 81181643Skmacy#define virt_to_mfn(x) (vtomach(x) >> PAGE_SHIFT) 82181643Skmacy 83181643Skmacystruct pcifront_device { 84181643Skmacy STAILQ_ENTRY(pcifront_device) next; 85181643Skmacy 86181643Skmacy struct xenbus_device *xdev; 87181643Skmacy 88181643Skmacy int unit; 89181643Skmacy int evtchn; 90181643Skmacy int gnt_ref; 91181643Skmacy 92181643Skmacy /* Lock this when doing any operations in sh_info */ 93181643Skmacy struct mtx sh_info_lock; 94181643Skmacy struct xen_pci_sharedinfo *sh_info; 95181643Skmacy 96181643Skmacy device_t ndev; 97181643Skmacy 98181643Skmacy int ref_cnt; 99181643Skmacy}; 100181643Skmacy 101181643Skmacystatic STAILQ_HEAD(pcifront_dlist, pcifront_device) pdev_list = STAILQ_HEAD_INITIALIZER(pdev_list); 102181643Skmacy 103181643Skmacystruct xpcib_softc { 104181643Skmacy int domain; 105181643Skmacy int bus; 106181643Skmacy struct pcifront_device *pdev; 107181643Skmacy}; 108181643Skmacy 109181643Skmacy/* Allocate a PCI device structure */ 110181643Skmacystatic struct pcifront_device * 111181643Skmacyalloc_pdev(struct xenbus_device *xdev) 112181643Skmacy{ 113181643Skmacy struct pcifront_device *pdev = NULL; 114181643Skmacy int err, unit; 115181643Skmacy 116181643Skmacy err = sscanf(xdev->nodename, "device/pci/%d", &unit); 117181643Skmacy if (err != 1) { 118181643Skmacy if (err == 0) 119181643Skmacy err = -EINVAL; 120181643Skmacy xenbus_dev_fatal(pdev->xdev, err, "Error scanning pci device instance number"); 121181643Skmacy goto out; 122181643Skmacy } 123181643Skmacy 124181643Skmacy pdev = (struct pcifront_device *)malloc(sizeof(struct pcifront_device), M_DEVBUF, M_NOWAIT); 125181643Skmacy if (pdev == NULL) { 126181643Skmacy err = -ENOMEM; 127181643Skmacy xenbus_dev_fatal(xdev, err, "Error allocating pcifront_device struct"); 128181643Skmacy goto out; 129181643Skmacy } 130181643Skmacy pdev->unit = unit; 131181643Skmacy pdev->xdev = xdev; 132181643Skmacy pdev->ref_cnt = 1; 133181643Skmacy 134181643Skmacy pdev->sh_info = (struct xen_pci_sharedinfo *)malloc(PAGE_SIZE, M_DEVBUF, M_NOWAIT); 135181643Skmacy if (pdev->sh_info == NULL) { 136181643Skmacy free(pdev, M_DEVBUF); 137181643Skmacy pdev = NULL; 138181643Skmacy err = -ENOMEM; 139181643Skmacy xenbus_dev_fatal(xdev, err, "Error allocating sh_info struct"); 140181643Skmacy goto out; 141181643Skmacy } 142181643Skmacy pdev->sh_info->flags = 0; 143181643Skmacy 144181643Skmacy xdev->data = pdev; 145181643Skmacy 146181643Skmacy mtx_init(&pdev->sh_info_lock, "info_lock", "pci shared dev info lock", MTX_DEF); 147181643Skmacy 148181643Skmacy pdev->evtchn = INVALID_EVTCHN; 149181643Skmacy pdev->gnt_ref = INVALID_GRANT_REF; 150181643Skmacy 151181643Skmacy STAILQ_INSERT_TAIL(&pdev_list, pdev, next); 152181643Skmacy 153181643Skmacy DPRINTF("Allocated pdev @ 0x%p (unit=%d)\n", pdev, unit); 154181643Skmacy 155181643Skmacy out: 156181643Skmacy return pdev; 157181643Skmacy} 158181643Skmacy 159181643Skmacy/* Hold a reference to a pcifront device */ 160181643Skmacystatic void 161181643Skmacyget_pdev(struct pcifront_device *pdev) 162181643Skmacy{ 163181643Skmacy pdev->ref_cnt++; 164181643Skmacy} 165181643Skmacy 166181643Skmacy/* Release a reference to a pcifront device */ 167181643Skmacystatic void 168181643Skmacyput_pdev(struct pcifront_device *pdev) 169181643Skmacy{ 170181643Skmacy if (--pdev->ref_cnt > 0) 171181643Skmacy return; 172181643Skmacy 173181643Skmacy DPRINTF("freeing pdev @ 0x%p (ref_cnt=%d)\n", pdev, pdev->ref_cnt); 174181643Skmacy 175181643Skmacy if (pdev->evtchn != INVALID_EVTCHN) 176181643Skmacy xenbus_free_evtchn(pdev->xdev, pdev->evtchn); 177181643Skmacy 178181643Skmacy if (pdev->gnt_ref != INVALID_GRANT_REF) 179181643Skmacy gnttab_end_foreign_access(pdev->gnt_ref, 0, (void *)pdev->sh_info); 180181643Skmacy 181181643Skmacy pdev->xdev->data = NULL; 182181643Skmacy 183181643Skmacy free(pdev, M_DEVBUF); 184181643Skmacy} 185181643Skmacy 186181643Skmacy 187181643Skmacy/* Write to the xenbus info needed by backend */ 188181643Skmacystatic int 189181643Skmacypcifront_publish_info(struct pcifront_device *pdev) 190181643Skmacy{ 191181643Skmacy int err = 0; 192181643Skmacy struct xenbus_transaction *trans; 193181643Skmacy 194181643Skmacy err = xenbus_grant_ring(pdev->xdev, virt_to_mfn(pdev->sh_info)); 195181643Skmacy if (err < 0) { 196181643Skmacy WPRINTF("error granting access to ring page\n"); 197181643Skmacy goto out; 198181643Skmacy } 199181643Skmacy 200181643Skmacy pdev->gnt_ref = err; 201181643Skmacy 202181643Skmacy err = xenbus_alloc_evtchn(pdev->xdev, &pdev->evtchn); 203181643Skmacy if (err) 204181643Skmacy goto out; 205181643Skmacy 206181643Skmacy do_publish: 207181643Skmacy trans = xenbus_transaction_start(); 208181643Skmacy if (IS_ERR(trans)) { 209181643Skmacy xenbus_dev_fatal(pdev->xdev, err, 210181643Skmacy "Error writing configuration for backend " 211181643Skmacy "(start transaction)"); 212181643Skmacy goto out; 213181643Skmacy } 214181643Skmacy 215181643Skmacy err = xenbus_printf(trans, pdev->xdev->nodename, 216181643Skmacy "pci-op-ref", "%u", pdev->gnt_ref); 217181643Skmacy if (!err) 218181643Skmacy err = xenbus_printf(trans, pdev->xdev->nodename, 219181643Skmacy "event-channel", "%u", pdev->evtchn); 220181643Skmacy if (!err) 221181643Skmacy err = xenbus_printf(trans, pdev->xdev->nodename, 222181643Skmacy "magic", XEN_PCI_MAGIC); 223181643Skmacy if (!err) 224181643Skmacy err = xenbus_switch_state(pdev->xdev, trans, 225181643Skmacy XenbusStateInitialised); 226181643Skmacy 227181643Skmacy if (err) { 228181643Skmacy xenbus_transaction_end(trans, 1); 229181643Skmacy xenbus_dev_fatal(pdev->xdev, err, 230181643Skmacy "Error writing configuration for backend"); 231181643Skmacy goto out; 232181643Skmacy } else { 233181643Skmacy err = xenbus_transaction_end(trans, 0); 234181643Skmacy if (err == -EAGAIN) 235181643Skmacy goto do_publish; 236181643Skmacy else if (err) { 237181643Skmacy xenbus_dev_fatal(pdev->xdev, err, 238181643Skmacy "Error completing transaction for backend"); 239181643Skmacy goto out; 240181643Skmacy } 241181643Skmacy } 242181643Skmacy 243181643Skmacy out: 244181643Skmacy return err; 245181643Skmacy} 246181643Skmacy 247181643Skmacy/* The backend is now connected so complete the connection process on our side */ 248181643Skmacystatic int 249181643Skmacypcifront_connect(struct pcifront_device *pdev) 250181643Skmacy{ 251181643Skmacy device_t nexus; 252181643Skmacy devclass_t nexus_devclass; 253181643Skmacy 254181643Skmacy /* We will add our device as a child of the nexus0 device */ 255181643Skmacy if (!(nexus_devclass = devclass_find("nexus")) || 256181643Skmacy !(nexus = devclass_get_device(nexus_devclass, 0))) { 257181643Skmacy WPRINTF("could not find nexus0!\n"); 258181643Skmacy return -1; 259181643Skmacy } 260181643Skmacy 261181643Skmacy /* Create a newbus device representing this frontend instance */ 262181643Skmacy pdev->ndev = BUS_ADD_CHILD(nexus, 0, "xpcife", pdev->unit); 263181643Skmacy if (!pdev->ndev) { 264181643Skmacy WPRINTF("could not create xpcife%d!\n", pdev->unit); 265181643Skmacy return -EFAULT; 266181643Skmacy } 267181643Skmacy get_pdev(pdev); 268181643Skmacy device_set_ivars(pdev->ndev, pdev); 269181643Skmacy 270181643Skmacy /* Good to go connected now */ 271181643Skmacy xenbus_switch_state(pdev->xdev, NULL, XenbusStateConnected); 272181643Skmacy 273181643Skmacy printf("pcifront: connected to %s\n", pdev->xdev->nodename); 274181643Skmacy 275181643Skmacy mtx_lock(&Giant); 276181643Skmacy device_probe_and_attach(pdev->ndev); 277181643Skmacy mtx_unlock(&Giant); 278181643Skmacy 279181643Skmacy return 0; 280181643Skmacy} 281181643Skmacy 282181643Skmacy/* The backend is closing so process a disconnect */ 283181643Skmacystatic int 284181643Skmacypcifront_disconnect(struct pcifront_device *pdev) 285181643Skmacy{ 286181643Skmacy int err = 0; 287181643Skmacy XenbusState prev_state; 288181643Skmacy 289181643Skmacy prev_state = xenbus_read_driver_state(pdev->xdev->nodename); 290181643Skmacy 291181643Skmacy if (prev_state < XenbusStateClosing) { 292181643Skmacy err = xenbus_switch_state(pdev->xdev, NULL, XenbusStateClosing); 293181643Skmacy if (!err && prev_state == XenbusStateConnected) { 294181643Skmacy /* TODO - need to detach the newbus devices */ 295181643Skmacy } 296181643Skmacy } 297181643Skmacy 298181643Skmacy return err; 299181643Skmacy} 300181643Skmacy 301181643Skmacy/* Process a probe from the xenbus */ 302181643Skmacystatic int 303181643Skmacypcifront_probe(struct xenbus_device *xdev, 304181643Skmacy const struct xenbus_device_id *id) 305181643Skmacy{ 306181643Skmacy int err = 0; 307181643Skmacy struct pcifront_device *pdev; 308181643Skmacy 309181643Skmacy DPRINTF("xenbus probing\n"); 310181643Skmacy 311181643Skmacy if ((pdev = alloc_pdev(xdev)) == NULL) 312181643Skmacy goto out; 313181643Skmacy 314181643Skmacy err = pcifront_publish_info(pdev); 315181643Skmacy 316181643Skmacy out: 317181643Skmacy if (err) 318181643Skmacy put_pdev(pdev); 319181643Skmacy return err; 320181643Skmacy} 321181643Skmacy 322181643Skmacy/* Remove the xenbus PCI device */ 323181643Skmacystatic int 324181643Skmacypcifront_remove(struct xenbus_device *xdev) 325181643Skmacy{ 326181643Skmacy DPRINTF("removing xenbus device node (%s)\n", xdev->nodename); 327181643Skmacy if (xdev->data) 328181643Skmacy put_pdev(xdev->data); 329181643Skmacy return 0; 330181643Skmacy} 331181643Skmacy 332181643Skmacy/* Called by xenbus when our backend node changes state */ 333181643Skmacystatic void 334181643Skmacypcifront_backend_changed(struct xenbus_device *xdev, 335181643Skmacy XenbusState be_state) 336181643Skmacy{ 337181643Skmacy struct pcifront_device *pdev = xdev->data; 338181643Skmacy 339181643Skmacy switch (be_state) { 340181643Skmacy case XenbusStateClosing: 341181643Skmacy DPRINTF("backend closing (%s)\n", xdev->nodename); 342181643Skmacy pcifront_disconnect(pdev); 343181643Skmacy break; 344181643Skmacy 345181643Skmacy case XenbusStateClosed: 346181643Skmacy DPRINTF("backend closed (%s)\n", xdev->nodename); 347181643Skmacy pcifront_disconnect(pdev); 348181643Skmacy break; 349181643Skmacy 350181643Skmacy case XenbusStateConnected: 351181643Skmacy DPRINTF("backend connected (%s)\n", xdev->nodename); 352181643Skmacy pcifront_connect(pdev); 353181643Skmacy break; 354181643Skmacy 355181643Skmacy default: 356181643Skmacy break; 357181643Skmacy } 358181643Skmacy} 359181643Skmacy 360181643Skmacy/* Process PCI operation */ 361181643Skmacystatic int 362181643Skmacydo_pci_op(struct pcifront_device *pdev, struct xen_pci_op *op) 363181643Skmacy{ 364181643Skmacy int err = 0; 365181643Skmacy struct xen_pci_op *active_op = &pdev->sh_info->op; 366181643Skmacy evtchn_port_t port = pdev->evtchn; 367181643Skmacy time_t timeout; 368181643Skmacy 369181643Skmacy mtx_lock(&pdev->sh_info_lock); 370181643Skmacy 371181643Skmacy memcpy(active_op, op, sizeof(struct xen_pci_op)); 372181643Skmacy 373181643Skmacy /* Go */ 374181643Skmacy wmb(); 375181643Skmacy set_bit(_XEN_PCIF_active, (unsigned long *)&pdev->sh_info->flags); 376181643Skmacy notify_remote_via_evtchn(port); 377181643Skmacy 378181643Skmacy timeout = time_uptime + 2; 379181643Skmacy 380181643Skmacy clear_evtchn(port); 381181643Skmacy 382181643Skmacy /* Spin while waiting for the answer */ 383181643Skmacy while (test_bit 384181643Skmacy (_XEN_PCIF_active, (unsigned long *)&pdev->sh_info->flags)) { 385181643Skmacy int err = HYPERVISOR_poll(&port, 1, 3 * hz); 386181643Skmacy if (err) 387181643Skmacy panic("Failed HYPERVISOR_poll: err=%d", err); 388181643Skmacy clear_evtchn(port); 389181643Skmacy if (time_uptime > timeout) { 390181643Skmacy WPRINTF("pciback not responding!!!\n"); 391181643Skmacy clear_bit(_XEN_PCIF_active, 392181643Skmacy (unsigned long *)&pdev->sh_info->flags); 393181643Skmacy err = XEN_PCI_ERR_dev_not_found; 394181643Skmacy goto out; 395181643Skmacy } 396181643Skmacy } 397181643Skmacy 398181643Skmacy memcpy(op, active_op, sizeof(struct xen_pci_op)); 399181643Skmacy 400181643Skmacy err = op->err; 401181643Skmacy out: 402181643Skmacy mtx_unlock(&pdev->sh_info_lock); 403181643Skmacy return err; 404181643Skmacy} 405181643Skmacy 406181643Skmacy/* ** XenBus Driver registration ** */ 407181643Skmacy 408181643Skmacystatic struct xenbus_device_id pcifront_ids[] = { 409181643Skmacy { "pci" }, 410181643Skmacy { "" } 411181643Skmacy}; 412181643Skmacy 413181643Skmacystatic struct xenbus_driver pcifront = { 414181643Skmacy .name = "pcifront", 415181643Skmacy .ids = pcifront_ids, 416181643Skmacy .probe = pcifront_probe, 417181643Skmacy .remove = pcifront_remove, 418181643Skmacy .otherend_changed = pcifront_backend_changed, 419181643Skmacy}; 420181643Skmacy 421181643Skmacy/* Register the driver with xenbus during sys init */ 422181643Skmacystatic void 423181643Skmacypcifront_init(void *unused) 424181643Skmacy{ 425181643Skmacy if ((xen_start_info->flags & SIF_INITDOMAIN)) 426181643Skmacy return; 427181643Skmacy 428181643Skmacy DPRINTF("xenbus registering\n"); 429181643Skmacy 430181643Skmacy xenbus_register_frontend(&pcifront); 431181643Skmacy} 432181643Skmacy 433181643SkmacySYSINIT(pciif, SI_SUB_PSEUDO, SI_ORDER_ANY, pcifront_init, NULL) 434181643Skmacy 435181643Skmacy 436181643Skmacy/* Newbus xpcife device driver probe */ 437181643Skmacystatic int 438181643Skmacyxpcife_probe(device_t dev) 439181643Skmacy{ 440181643Skmacy#ifdef XEN_PCIDEV_FE_DEBUG 441181643Skmacy struct pcifront_device *pdev = (struct pcifront_device *)device_get_ivars(dev); 442181643Skmacy DPRINTF("xpcife probe (unit=%d)\n", pdev->unit); 443181643Skmacy#endif 444265999Sian return (BUS_PROBE_NOWILDCARD); 445181643Skmacy} 446181643Skmacy 447181643Skmacy/* Newbus xpcife device driver attach */ 448181643Skmacystatic int 449181643Skmacyxpcife_attach(device_t dev) 450181643Skmacy{ 451181643Skmacy struct pcifront_device *pdev = (struct pcifront_device *)device_get_ivars(dev); 452181643Skmacy int i, num_roots, len, err; 453181643Skmacy char str[64]; 454181643Skmacy unsigned int domain, bus; 455181643Skmacy 456181643Skmacy DPRINTF("xpcife attach (unit=%d)\n", pdev->unit); 457181643Skmacy 458181643Skmacy err = xenbus_scanf(NULL, pdev->xdev->otherend, 459181643Skmacy "root_num", "%d", &num_roots); 460181643Skmacy if (err != 1) { 461181643Skmacy if (err == 0) 462181643Skmacy err = -EINVAL; 463181643Skmacy xenbus_dev_fatal(pdev->xdev, err, 464181643Skmacy "Error reading number of PCI roots"); 465181643Skmacy goto out; 466181643Skmacy } 467181643Skmacy 468181643Skmacy /* Add a pcib device for each root */ 469181643Skmacy for (i = 0; i < num_roots; i++) { 470181643Skmacy device_t child; 471181643Skmacy 472181643Skmacy len = snprintf(str, sizeof(str), "root-%d", i); 473181643Skmacy if (unlikely(len >= (sizeof(str) - 1))) { 474181643Skmacy err = -ENOMEM; 475181643Skmacy goto out; 476181643Skmacy } 477181643Skmacy 478181643Skmacy err = xenbus_scanf(NULL, pdev->xdev->otherend, str, 479181643Skmacy "%x:%x", &domain, &bus); 480181643Skmacy if (err != 2) { 481181643Skmacy if (err >= 0) 482181643Skmacy err = -EINVAL; 483181643Skmacy xenbus_dev_fatal(pdev->xdev, err, 484181643Skmacy "Error reading PCI root %d", i); 485181643Skmacy goto out; 486181643Skmacy } 487181643Skmacy err = 0; 488181643Skmacy if (domain != pdev->xdev->otherend_id) { 489181643Skmacy err = -EINVAL; 490181643Skmacy xenbus_dev_fatal(pdev->xdev, err, 491181643Skmacy "Domain mismatch %d != %d", domain, pdev->xdev->otherend_id); 492181643Skmacy goto out; 493181643Skmacy } 494181643Skmacy 495181643Skmacy child = device_add_child(dev, "pcib", bus); 496181643Skmacy if (!child) { 497181643Skmacy err = -ENOMEM; 498181643Skmacy xenbus_dev_fatal(pdev->xdev, err, 499181643Skmacy "Unable to create pcib%d", bus); 500181643Skmacy goto out; 501181643Skmacy } 502181643Skmacy } 503181643Skmacy 504181643Skmacy out: 505181643Skmacy return bus_generic_attach(dev); 506181643Skmacy} 507181643Skmacy 508181643Skmacystatic devclass_t xpcife_devclass; 509181643Skmacy 510181643Skmacystatic device_method_t xpcife_methods[] = { 511181643Skmacy /* Device interface */ 512181643Skmacy DEVMETHOD(device_probe, xpcife_probe), 513181643Skmacy DEVMETHOD(device_attach, xpcife_attach), 514181643Skmacy DEVMETHOD(device_detach, bus_generic_detach), 515181643Skmacy DEVMETHOD(device_shutdown, bus_generic_shutdown), 516181643Skmacy DEVMETHOD(device_suspend, bus_generic_suspend), 517181643Skmacy DEVMETHOD(device_resume, bus_generic_resume), 518181643Skmacy /* Bus interface */ 519181643Skmacy DEVMETHOD(bus_alloc_resource, bus_generic_alloc_resource), 520181643Skmacy DEVMETHOD(bus_release_resource, bus_generic_release_resource), 521181643Skmacy DEVMETHOD(bus_activate_resource, bus_generic_activate_resource), 522181643Skmacy DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource), 523181643Skmacy DEVMETHOD(bus_setup_intr, bus_generic_setup_intr), 524181643Skmacy DEVMETHOD(bus_teardown_intr, bus_generic_teardown_intr), 525227843Smarius 526227843Smarius DEVMETHOD_END 527181643Skmacy}; 528181643Skmacy 529181643Skmacystatic driver_t xpcife_driver = { 530181643Skmacy "xpcife", 531181643Skmacy xpcife_methods, 532181643Skmacy 0, 533181643Skmacy}; 534181643Skmacy 535181643SkmacyDRIVER_MODULE(xpcife, nexus, xpcife_driver, xpcife_devclass, 0, 0); 536181643Skmacy 537181643Skmacy 538181643Skmacy/* Newbus xen pcib device driver probe */ 539181643Skmacystatic int 540181643Skmacyxpcib_probe(device_t dev) 541181643Skmacy{ 542181643Skmacy struct xpcib_softc *sc = (struct xpcib_softc *)device_get_softc(dev); 543181643Skmacy struct pcifront_device *pdev = (struct pcifront_device *)device_get_ivars(device_get_parent(dev)); 544181643Skmacy 545181643Skmacy DPRINTF("xpcib probe (bus=%d)\n", device_get_unit(dev)); 546181643Skmacy 547181643Skmacy sc->domain = pdev->xdev->otherend_id; 548181643Skmacy sc->bus = device_get_unit(dev); 549181643Skmacy sc->pdev = pdev; 550181643Skmacy 551181643Skmacy return 0; 552181643Skmacy} 553181643Skmacy 554181643Skmacy/* Newbus xen pcib device driver attach */ 555181643Skmacystatic int 556181643Skmacyxpcib_attach(device_t dev) 557181643Skmacy{ 558181643Skmacy struct xpcib_softc *sc = (struct xpcib_softc *)device_get_softc(dev); 559181643Skmacy 560181643Skmacy DPRINTF("xpcib attach (bus=%d)\n", sc->bus); 561181643Skmacy 562181643Skmacy device_add_child(dev, "pci", sc->bus); 563181643Skmacy return bus_generic_attach(dev); 564181643Skmacy} 565181643Skmacy 566181643Skmacystatic int 567181643Skmacyxpcib_read_ivar(device_t dev, device_t child, int which, uintptr_t *result) 568181643Skmacy{ 569181643Skmacy struct xpcib_softc *sc = (struct xpcib_softc *)device_get_softc(dev); 570181643Skmacy switch (which) { 571181643Skmacy case PCIB_IVAR_BUS: 572181643Skmacy *result = sc->bus; 573181643Skmacy return 0; 574181643Skmacy } 575181643Skmacy return ENOENT; 576181643Skmacy} 577181643Skmacy 578181643Skmacy/* Return the number of slots supported */ 579181643Skmacystatic int 580181643Skmacyxpcib_maxslots(device_t dev) 581181643Skmacy{ 582181643Skmacy return 31; 583181643Skmacy} 584181643Skmacy 585181643Skmacy#define PCI_DEVFN(slot,func) ((((slot) & 0x1f) << 3) | ((func) & 0x07)) 586181643Skmacy 587181643Skmacy/* Read configuration space register */ 588181643Skmacystatic u_int32_t 589181643Skmacyxpcib_read_config(device_t dev, int bus, int slot, int func, 590181643Skmacy int reg, int bytes) 591181643Skmacy{ 592181643Skmacy struct xpcib_softc *sc = (struct xpcib_softc *)device_get_softc(dev); 593181643Skmacy struct xen_pci_op op = { 594181643Skmacy .cmd = XEN_PCI_OP_conf_read, 595181643Skmacy .domain = sc->domain, 596181643Skmacy .bus = sc->bus, 597181643Skmacy .devfn = PCI_DEVFN(slot, func), 598181643Skmacy .offset = reg, 599181643Skmacy .size = bytes, 600181643Skmacy }; 601181643Skmacy int err; 602181643Skmacy 603181643Skmacy err = do_pci_op(sc->pdev, &op); 604181643Skmacy 605181643Skmacy DPRINTF("read config (b=%d, s=%d, f=%d, reg=%d, len=%d, val=%x, err=%d)\n", 606181643Skmacy bus, slot, func, reg, bytes, op.value, err); 607181643Skmacy 608181643Skmacy if (err) 609181643Skmacy op.value = ~0; 610181643Skmacy 611181643Skmacy return op.value; 612181643Skmacy} 613181643Skmacy 614181643Skmacy/* Write configuration space register */ 615181643Skmacystatic void 616181643Skmacyxpcib_write_config(device_t dev, int bus, int slot, int func, 617181643Skmacy int reg, u_int32_t data, int bytes) 618181643Skmacy{ 619181643Skmacy struct xpcib_softc *sc = (struct xpcib_softc *)device_get_softc(dev); 620181643Skmacy struct xen_pci_op op = { 621181643Skmacy .cmd = XEN_PCI_OP_conf_write, 622181643Skmacy .domain = sc->domain, 623181643Skmacy .bus = sc->bus, 624181643Skmacy .devfn = PCI_DEVFN(slot, func), 625181643Skmacy .offset = reg, 626181643Skmacy .size = bytes, 627181643Skmacy .value = data, 628181643Skmacy }; 629181643Skmacy int err; 630181643Skmacy 631181643Skmacy err = do_pci_op(sc->pdev, &op); 632181643Skmacy 633181643Skmacy DPRINTF("write config (b=%d, s=%d, f=%d, reg=%d, len=%d, val=%x, err=%d)\n", 634181643Skmacy bus, slot, func, reg, bytes, data, err); 635181643Skmacy} 636181643Skmacy 637181643Skmacystatic int 638181643Skmacyxpcib_route_interrupt(device_t pcib, device_t dev, int pin) 639181643Skmacy{ 640181643Skmacy struct pci_devinfo *dinfo = device_get_ivars(dev); 641181643Skmacy pcicfgregs *cfg = &dinfo->cfg; 642181643Skmacy 643181643Skmacy DPRINTF("route intr (pin=%d, line=%d)\n", pin, cfg->intline); 644181643Skmacy 645181643Skmacy return cfg->intline; 646181643Skmacy} 647181643Skmacy 648181643Skmacystatic device_method_t xpcib_methods[] = { 649181643Skmacy /* Device interface */ 650227843Smarius DEVMETHOD(device_probe, xpcib_probe), 651181643Skmacy DEVMETHOD(device_attach, xpcib_attach), 652181643Skmacy DEVMETHOD(device_detach, bus_generic_detach), 653181643Skmacy DEVMETHOD(device_shutdown, bus_generic_shutdown), 654181643Skmacy DEVMETHOD(device_suspend, bus_generic_suspend), 655181643Skmacy DEVMETHOD(device_resume, bus_generic_resume), 656181643Skmacy 657181643Skmacy /* Bus interface */ 658181643Skmacy DEVMETHOD(bus_read_ivar, xpcib_read_ivar), 659181643Skmacy DEVMETHOD(bus_alloc_resource, bus_generic_alloc_resource), 660181643Skmacy DEVMETHOD(bus_activate_resource, bus_generic_activate_resource), 661181643Skmacy DEVMETHOD(bus_release_resource, bus_generic_release_resource), 662181643Skmacy DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource), 663181643Skmacy DEVMETHOD(bus_setup_intr, bus_generic_setup_intr), 664181643Skmacy DEVMETHOD(bus_teardown_intr, bus_generic_teardown_intr), 665181643Skmacy 666181643Skmacy /* pcib interface */ 667181643Skmacy DEVMETHOD(pcib_maxslots, xpcib_maxslots), 668181643Skmacy DEVMETHOD(pcib_read_config, xpcib_read_config), 669181643Skmacy DEVMETHOD(pcib_write_config, xpcib_write_config), 670181643Skmacy DEVMETHOD(pcib_route_interrupt, xpcib_route_interrupt), 671227843Smarius 672227843Smarius DEVMETHOD_END 673181643Skmacy}; 674181643Skmacy 675181643Skmacystatic devclass_t xpcib_devclass; 676181643Skmacy 677181643SkmacyDEFINE_CLASS_0(pcib, xpcib_driver, xpcib_methods, sizeof(struct xpcib_softc)); 678181643SkmacyDRIVER_MODULE(pcib, xpcife, xpcib_driver, xpcib_devclass, 0, 0); 679181643Skmacy 680181643Skmacy/* 681181643Skmacy * Local variables: 682181643Skmacy * mode: C 683181643Skmacy * c-set-style: "BSD" 684181643Skmacy * c-basic-offset: 4 685181643Skmacy * tab-width: 4 686181643Skmacy * indent-tabs-mode: t 687181643Skmacy * End: 688181643Skmacy */ 689