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