1 /* 2 * Copyright (c) 2008 Citrix Systems, Inc. 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS AS IS'' AND 15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24 * SUCH DAMAGE. 25 */ 26 27 #include <sys/cdefs.h> 28 __FBSDID("$FreeBSD$"); 29 30 #include <sys/param.h> 31 #include <sys/bus.h> 32 #include <sys/kernel.h> 33 #include <sys/malloc.h> 34 #include <sys/module.h> 35 36 #include <machine/bus.h> 37 #include <machine/resource.h> 38 #include <sys/rman.h> 39 40 #include <machine/stdarg.h> 41 42 #include <xen/xen-os.h> 43 #include <xen/features.h> 44 #include <xen/hypervisor.h> 45 #include <xen/hvm.h> 46 47 #include <dev/pci/pcireg.h> 48 #include <dev/pci/pcivar.h> 49 50 #include <dev/xen/xenpci/xenpcivar.h> 51 52 extern void xen_intr_handle_upcall(struct trapframe *trap_frame); 53 54 /* 55 * This is used to find our platform device instance. 56 */ 57 static devclass_t xenpci_devclass; 58 59 static int 60 xenpci_intr_filter(void *trap_frame) 61 { 62 xen_intr_handle_upcall(trap_frame); 63 return (FILTER_HANDLED); 64 } 65 66 static int 67 xenpci_irq_init(device_t device, struct xenpci_softc *scp) 68 { 69 int error; 70 71 error = BUS_SETUP_INTR(device_get_parent(device), device, 72 scp->res_irq, INTR_MPSAFE|INTR_TYPE_MISC, 73 xenpci_intr_filter, NULL, /*trap_frame*/NULL, 74 &scp->intr_cookie); 75 if (error) 76 return error; 77 78 #ifdef SMP 79 /* 80 * When using the PCI event delivery callback we cannot assign 81 * events to specific vCPUs, so all events are delivered to vCPU#0 by 82 * Xen. Since the PCI interrupt can fire on any CPU by default, we 83 * need to bind it to vCPU#0 in order to ensure that 84 * xen_intr_handle_upcall always gets called on vCPU#0. 85 */ 86 error = BUS_BIND_INTR(device_get_parent(device), device, 87 scp->res_irq, 0); 88 if (error) 89 return error; 90 #endif 91 92 xen_hvm_set_callback(device); 93 return (0); 94 } 95 96 /* 97 * Deallocate anything allocated by xenpci_allocate_resources. 98 */ 99 static int 100 xenpci_deallocate_resources(device_t dev) 101 { 102 struct xenpci_softc *scp = device_get_softc(dev); 103 104 if (scp->res_irq != 0) { 105 bus_deactivate_resource(dev, SYS_RES_IRQ, 106 scp->rid_irq, scp->res_irq); 107 bus_release_resource(dev, SYS_RES_IRQ, 108 scp->rid_irq, scp->res_irq); 109 scp->res_irq = 0; 110 } 111 112 return (0); 113 } 114 115 /* 116 * Allocate irq and memory resources. 117 */ 118 static int 119 xenpci_allocate_resources(device_t dev) 120 { 121 struct xenpci_softc *scp = device_get_softc(dev); 122 123 scp->res_irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, 124 &scp->rid_irq, RF_SHAREABLE|RF_ACTIVE); 125 if (scp->res_irq == NULL) { 126 printf("xenpci Could not allocate irq.\n"); 127 goto errexit; 128 } 129 130 return (0); 131 132 errexit: 133 /* Cleanup anything we may have assigned. */ 134 xenpci_deallocate_resources(dev); 135 return (ENXIO); /* For want of a better idea. */ 136 } 137 138 /* 139 * Probe - just check device ID. 140 */ 141 static int 142 xenpci_probe(device_t dev) 143 { 144 145 if (pci_get_devid(dev) != 0x00015853) 146 return (ENXIO); 147 148 device_set_desc(dev, "Xen Platform Device"); 149 return (BUS_PROBE_DEFAULT); 150 } 151 152 /* 153 * Attach - find resources and talk to Xen. 154 */ 155 static int 156 xenpci_attach(device_t dev) 157 { 158 struct xenpci_softc *scp = device_get_softc(dev); 159 int error; 160 161 error = xenpci_allocate_resources(dev); 162 if (error) { 163 device_printf(dev, "xenpci_allocate_resources failed(%d).\n", 164 error); 165 goto errexit; 166 } 167 168 /* 169 * Hook the irq up to evtchn 170 */ 171 error = xenpci_irq_init(dev, scp); 172 if (error) { 173 device_printf(dev, "xenpci_irq_init failed(%d).\n", 174 error); 175 goto errexit; 176 } 177 178 return (0); 179 180 errexit: 181 /* 182 * Undo anything we may have done. 183 */ 184 xenpci_deallocate_resources(dev); 185 return (error); 186 } 187 188 /* 189 * Detach - reverse anything done by attach. 190 */ 191 static int 192 xenpci_detach(device_t dev) 193 { 194 struct xenpci_softc *scp = device_get_softc(dev); 195 device_t parent = device_get_parent(dev); 196 197 /* 198 * Take our interrupt handler out of the list of handlers 199 * that can handle this irq. 200 */ 201 if (scp->intr_cookie != NULL) { 202 if (BUS_TEARDOWN_INTR(parent, dev, 203 scp->res_irq, scp->intr_cookie) != 0) 204 device_printf(dev, 205 "intr teardown failed.. continuing\n"); 206 scp->intr_cookie = NULL; 207 } 208 209 /* 210 * Deallocate any system resources we may have 211 * allocated on behalf of this driver. 212 */ 213 return (xenpci_deallocate_resources(dev)); 214 } 215 216 static int 217 xenpci_resume(device_t dev) 218 { 219 xen_hvm_set_callback(dev); 220 return (0); 221 } 222 223 static device_method_t xenpci_methods[] = { 224 /* Device interface */ 225 DEVMETHOD(device_probe, xenpci_probe), 226 DEVMETHOD(device_attach, xenpci_attach), 227 DEVMETHOD(device_detach, xenpci_detach), 228 DEVMETHOD(device_resume, xenpci_resume), 229 230 { 0, 0 } 231 }; 232 233 static driver_t xenpci_driver = { 234 "xenpci", 235 xenpci_methods, 236 sizeof(struct xenpci_softc), 237 }; 238 239 DRIVER_MODULE(xenpci, pci, xenpci_driver, xenpci_devclass, 0, 0); 240