112678024SDoug Rabson /* 212678024SDoug Rabson * Copyright (c) 2008 Citrix Systems, Inc. 312678024SDoug Rabson * All rights reserved. 412678024SDoug Rabson * 512678024SDoug Rabson * Redistribution and use in source and binary forms, with or without 612678024SDoug Rabson * modification, are permitted provided that the following conditions 712678024SDoug Rabson * are met: 812678024SDoug Rabson * 1. Redistributions of source code must retain the above copyright 912678024SDoug Rabson * notice, this list of conditions and the following disclaimer. 1012678024SDoug Rabson * 2. Redistributions in binary form must reproduce the above copyright 1112678024SDoug Rabson * notice, this list of conditions and the following disclaimer in the 1212678024SDoug Rabson * documentation and/or other materials provided with the distribution. 1312678024SDoug Rabson * 1412678024SDoug Rabson * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS AS IS'' AND 1512678024SDoug Rabson * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1612678024SDoug Rabson * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 1712678024SDoug Rabson * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 1812678024SDoug Rabson * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 1912678024SDoug Rabson * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2012678024SDoug Rabson * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2112678024SDoug Rabson * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2212678024SDoug Rabson * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2312678024SDoug Rabson * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2412678024SDoug Rabson * SUCH DAMAGE. 2512678024SDoug Rabson */ 2612678024SDoug Rabson 2712678024SDoug Rabson #include <sys/cdefs.h> 2812678024SDoug Rabson __FBSDID("$FreeBSD$"); 2912678024SDoug Rabson 3012678024SDoug Rabson #include <sys/param.h> 3112678024SDoug Rabson #include <sys/bus.h> 3212678024SDoug Rabson #include <sys/kernel.h> 3312678024SDoug Rabson #include <sys/malloc.h> 3412678024SDoug Rabson #include <sys/module.h> 3512678024SDoug Rabson 3612678024SDoug Rabson #include <machine/bus.h> 3712678024SDoug Rabson #include <machine/resource.h> 3812678024SDoug Rabson #include <sys/rman.h> 3912678024SDoug Rabson 4012678024SDoug Rabson #include <machine/stdarg.h> 4176acc41fSJustin T. Gibbs 4276acc41fSJustin T. Gibbs #include <xen/xen-os.h> 4312678024SDoug Rabson #include <xen/features.h> 4412678024SDoug Rabson #include <xen/hypervisor.h> 4576acc41fSJustin T. Gibbs #include <xen/hvm.h> 46*2f9ec994SRoger Pau Monné #include <xen/xen_intr.h> 4712678024SDoug Rabson 4812678024SDoug Rabson #include <dev/pci/pcireg.h> 4912678024SDoug Rabson #include <dev/pci/pcivar.h> 5012678024SDoug Rabson 5112678024SDoug Rabson #include <dev/xen/xenpci/xenpcivar.h> 5212678024SDoug Rabson 5312678024SDoug Rabson /* 5412678024SDoug Rabson * This is used to find our platform device instance. 5512678024SDoug Rabson */ 5612678024SDoug Rabson static devclass_t xenpci_devclass; 5712678024SDoug Rabson 5812678024SDoug Rabson static int 5976acc41fSJustin T. Gibbs xenpci_intr_filter(void *trap_frame) 6012678024SDoug Rabson { 6176acc41fSJustin T. Gibbs xen_intr_handle_upcall(trap_frame); 6276acc41fSJustin T. Gibbs return (FILTER_HANDLED); 6312678024SDoug Rabson } 6412678024SDoug Rabson 6576acc41fSJustin T. Gibbs static int 6676acc41fSJustin T. Gibbs xenpci_irq_init(device_t device, struct xenpci_softc *scp) 6776acc41fSJustin T. Gibbs { 6876acc41fSJustin T. Gibbs int error; 6976acc41fSJustin T. Gibbs 7076acc41fSJustin T. Gibbs error = BUS_SETUP_INTR(device_get_parent(device), device, 7176acc41fSJustin T. Gibbs scp->res_irq, INTR_MPSAFE|INTR_TYPE_MISC, 7276acc41fSJustin T. Gibbs xenpci_intr_filter, NULL, /*trap_frame*/NULL, 7376acc41fSJustin T. Gibbs &scp->intr_cookie); 7476acc41fSJustin T. Gibbs if (error) 7576acc41fSJustin T. Gibbs return error; 7612678024SDoug Rabson 77428b7ca2SJustin T. Gibbs #ifdef SMP 7812678024SDoug Rabson /* 7976acc41fSJustin T. Gibbs * When using the PCI event delivery callback we cannot assign 8076acc41fSJustin T. Gibbs * events to specific vCPUs, so all events are delivered to vCPU#0 by 8176acc41fSJustin T. Gibbs * Xen. Since the PCI interrupt can fire on any CPU by default, we 8276acc41fSJustin T. Gibbs * need to bind it to vCPU#0 in order to ensure that 8376acc41fSJustin T. Gibbs * xen_intr_handle_upcall always gets called on vCPU#0. 8412678024SDoug Rabson */ 8576acc41fSJustin T. Gibbs error = BUS_BIND_INTR(device_get_parent(device), device, 8676acc41fSJustin T. Gibbs scp->res_irq, 0); 8776acc41fSJustin T. Gibbs if (error) 8876acc41fSJustin T. Gibbs return error; 89428b7ca2SJustin T. Gibbs #endif 9012678024SDoug Rabson 9176acc41fSJustin T. Gibbs xen_hvm_set_callback(device); 9212678024SDoug Rabson return (0); 9312678024SDoug Rabson } 9412678024SDoug Rabson 9512678024SDoug Rabson /* 9612678024SDoug Rabson * Deallocate anything allocated by xenpci_allocate_resources. 9712678024SDoug Rabson */ 9812678024SDoug Rabson static int 9912678024SDoug Rabson xenpci_deallocate_resources(device_t dev) 10012678024SDoug Rabson { 10112678024SDoug Rabson struct xenpci_softc *scp = device_get_softc(dev); 10212678024SDoug Rabson 10312678024SDoug Rabson if (scp->res_irq != 0) { 10412678024SDoug Rabson bus_deactivate_resource(dev, SYS_RES_IRQ, 10512678024SDoug Rabson scp->rid_irq, scp->res_irq); 10612678024SDoug Rabson bus_release_resource(dev, SYS_RES_IRQ, 10712678024SDoug Rabson scp->rid_irq, scp->res_irq); 10812678024SDoug Rabson scp->res_irq = 0; 10912678024SDoug Rabson } 11012678024SDoug Rabson 11112678024SDoug Rabson return (0); 11212678024SDoug Rabson } 11312678024SDoug Rabson 11412678024SDoug Rabson /* 11512678024SDoug Rabson * Allocate irq and memory resources. 11612678024SDoug Rabson */ 11712678024SDoug Rabson static int 11812678024SDoug Rabson xenpci_allocate_resources(device_t dev) 11912678024SDoug Rabson { 12012678024SDoug Rabson struct xenpci_softc *scp = device_get_softc(dev); 12112678024SDoug Rabson 12212678024SDoug Rabson scp->res_irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, 12312678024SDoug Rabson &scp->rid_irq, RF_SHAREABLE|RF_ACTIVE); 124ff662b5cSJustin T. Gibbs if (scp->res_irq == NULL) { 125ff662b5cSJustin T. Gibbs printf("xenpci Could not allocate irq.\n"); 12612678024SDoug Rabson goto errexit; 127ff662b5cSJustin T. Gibbs } 12812678024SDoug Rabson 12912678024SDoug Rabson return (0); 13012678024SDoug Rabson 13112678024SDoug Rabson errexit: 13212678024SDoug Rabson /* Cleanup anything we may have assigned. */ 13312678024SDoug Rabson xenpci_deallocate_resources(dev); 13412678024SDoug Rabson return (ENXIO); /* For want of a better idea. */ 13512678024SDoug Rabson } 13612678024SDoug Rabson 13712678024SDoug Rabson /* 13812678024SDoug Rabson * Probe - just check device ID. 13912678024SDoug Rabson */ 14012678024SDoug Rabson static int 14112678024SDoug Rabson xenpci_probe(device_t dev) 14212678024SDoug Rabson { 14312678024SDoug Rabson 14412678024SDoug Rabson if (pci_get_devid(dev) != 0x00015853) 14512678024SDoug Rabson return (ENXIO); 14612678024SDoug Rabson 14712678024SDoug Rabson device_set_desc(dev, "Xen Platform Device"); 148aa64d12bSRoger Pau Monné return (BUS_PROBE_DEFAULT); 14912678024SDoug Rabson } 15012678024SDoug Rabson 15112678024SDoug Rabson /* 15212678024SDoug Rabson * Attach - find resources and talk to Xen. 15312678024SDoug Rabson */ 15412678024SDoug Rabson static int 15512678024SDoug Rabson xenpci_attach(device_t dev) 15612678024SDoug Rabson { 15712678024SDoug Rabson struct xenpci_softc *scp = device_get_softc(dev); 15876acc41fSJustin T. Gibbs int error; 159ff662b5cSJustin T. Gibbs 16012678024SDoug Rabson error = xenpci_allocate_resources(dev); 161ff662b5cSJustin T. Gibbs if (error) { 162ff662b5cSJustin T. Gibbs device_printf(dev, "xenpci_allocate_resources failed(%d).\n", 163ff662b5cSJustin T. Gibbs error); 16412678024SDoug Rabson goto errexit; 165ff662b5cSJustin T. Gibbs } 16612678024SDoug Rabson 16712678024SDoug Rabson /* 16812678024SDoug Rabson * Hook the irq up to evtchn 16912678024SDoug Rabson */ 17076acc41fSJustin T. Gibbs error = xenpci_irq_init(dev, scp); 17176acc41fSJustin T. Gibbs if (error) { 17276acc41fSJustin T. Gibbs device_printf(dev, "xenpci_irq_init failed(%d).\n", 17376acc41fSJustin T. Gibbs error); 17476acc41fSJustin T. Gibbs goto errexit; 17576acc41fSJustin T. Gibbs } 17612678024SDoug Rabson 177aa64d12bSRoger Pau Monné return (0); 17812678024SDoug Rabson 17912678024SDoug Rabson errexit: 18012678024SDoug Rabson /* 18112678024SDoug Rabson * Undo anything we may have done. 18212678024SDoug Rabson */ 18312678024SDoug Rabson xenpci_deallocate_resources(dev); 18412678024SDoug Rabson return (error); 18512678024SDoug Rabson } 18612678024SDoug Rabson 18712678024SDoug Rabson /* 18812678024SDoug Rabson * Detach - reverse anything done by attach. 18912678024SDoug Rabson */ 19012678024SDoug Rabson static int 19112678024SDoug Rabson xenpci_detach(device_t dev) 19212678024SDoug Rabson { 19312678024SDoug Rabson struct xenpci_softc *scp = device_get_softc(dev); 19412678024SDoug Rabson device_t parent = device_get_parent(dev); 19512678024SDoug Rabson 19612678024SDoug Rabson /* 19712678024SDoug Rabson * Take our interrupt handler out of the list of handlers 19812678024SDoug Rabson * that can handle this irq. 19912678024SDoug Rabson */ 20012678024SDoug Rabson if (scp->intr_cookie != NULL) { 20112678024SDoug Rabson if (BUS_TEARDOWN_INTR(parent, dev, 20212678024SDoug Rabson scp->res_irq, scp->intr_cookie) != 0) 203ff662b5cSJustin T. Gibbs device_printf(dev, 204ff662b5cSJustin T. Gibbs "intr teardown failed.. continuing\n"); 20512678024SDoug Rabson scp->intr_cookie = NULL; 20612678024SDoug Rabson } 20712678024SDoug Rabson 20812678024SDoug Rabson /* 20912678024SDoug Rabson * Deallocate any system resources we may have 21012678024SDoug Rabson * allocated on behalf of this driver. 21112678024SDoug Rabson */ 21212678024SDoug Rabson return (xenpci_deallocate_resources(dev)); 21312678024SDoug Rabson } 21412678024SDoug Rabson 21576acc41fSJustin T. Gibbs static int 21676acc41fSJustin T. Gibbs xenpci_resume(device_t dev) 21776acc41fSJustin T. Gibbs { 21876acc41fSJustin T. Gibbs xen_hvm_set_callback(dev); 219aa64d12bSRoger Pau Monné return (0); 22076acc41fSJustin T. Gibbs } 22176acc41fSJustin T. Gibbs 22212678024SDoug Rabson static device_method_t xenpci_methods[] = { 22312678024SDoug Rabson /* Device interface */ 22412678024SDoug Rabson DEVMETHOD(device_probe, xenpci_probe), 22512678024SDoug Rabson DEVMETHOD(device_attach, xenpci_attach), 22612678024SDoug Rabson DEVMETHOD(device_detach, xenpci_detach), 22776acc41fSJustin T. Gibbs DEVMETHOD(device_resume, xenpci_resume), 22812678024SDoug Rabson 22912678024SDoug Rabson { 0, 0 } 23012678024SDoug Rabson }; 23112678024SDoug Rabson 23212678024SDoug Rabson static driver_t xenpci_driver = { 23312678024SDoug Rabson "xenpci", 23412678024SDoug Rabson xenpci_methods, 23512678024SDoug Rabson sizeof(struct xenpci_softc), 23612678024SDoug Rabson }; 23712678024SDoug Rabson 23812678024SDoug Rabson DRIVER_MODULE(xenpci, pci, xenpci_driver, xenpci_devclass, 0, 0); 239