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 static device_t nexus; 55 56 /* 57 * This is used to find our platform device instance. 58 */ 59 static devclass_t xenpci_devclass; 60 61 static int 62 xenpci_intr_filter(void *trap_frame) 63 { 64 xen_intr_handle_upcall(trap_frame); 65 return (FILTER_HANDLED); 66 } 67 68 static int 69 xenpci_irq_init(device_t device, struct xenpci_softc *scp) 70 { 71 int error; 72 73 error = BUS_SETUP_INTR(device_get_parent(device), device, 74 scp->res_irq, INTR_MPSAFE|INTR_TYPE_MISC, 75 xenpci_intr_filter, NULL, /*trap_frame*/NULL, 76 &scp->intr_cookie); 77 if (error) 78 return error; 79 80 #ifdef SMP 81 /* 82 * When using the PCI event delivery callback we cannot assign 83 * events to specific vCPUs, so all events are delivered to vCPU#0 by 84 * Xen. Since the PCI interrupt can fire on any CPU by default, we 85 * need to bind it to vCPU#0 in order to ensure that 86 * xen_intr_handle_upcall always gets called on vCPU#0. 87 */ 88 error = BUS_BIND_INTR(device_get_parent(device), device, 89 scp->res_irq, 0); 90 if (error) 91 return error; 92 #endif 93 94 xen_hvm_set_callback(device); 95 return (0); 96 } 97 98 /* 99 * Deallocate anything allocated by xenpci_allocate_resources. 100 */ 101 static int 102 xenpci_deallocate_resources(device_t dev) 103 { 104 struct xenpci_softc *scp = device_get_softc(dev); 105 106 if (scp->res_irq != 0) { 107 bus_deactivate_resource(dev, SYS_RES_IRQ, 108 scp->rid_irq, scp->res_irq); 109 bus_release_resource(dev, SYS_RES_IRQ, 110 scp->rid_irq, scp->res_irq); 111 scp->res_irq = 0; 112 } 113 if (scp->res_memory != 0) { 114 bus_deactivate_resource(dev, SYS_RES_MEMORY, 115 scp->rid_memory, scp->res_memory); 116 bus_release_resource(dev, SYS_RES_MEMORY, 117 scp->rid_memory, scp->res_memory); 118 scp->res_memory = 0; 119 } 120 121 return (0); 122 } 123 124 /* 125 * Allocate irq and memory resources. 126 */ 127 static int 128 xenpci_allocate_resources(device_t dev) 129 { 130 struct xenpci_softc *scp = device_get_softc(dev); 131 132 scp->res_irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, 133 &scp->rid_irq, RF_SHAREABLE|RF_ACTIVE); 134 if (scp->res_irq == NULL) { 135 printf("xenpci Could not allocate irq.\n"); 136 goto errexit; 137 } 138 139 scp->rid_memory = PCIR_BAR(1); 140 scp->res_memory = bus_alloc_resource_any(dev, SYS_RES_MEMORY, 141 &scp->rid_memory, RF_ACTIVE); 142 if (scp->res_memory == NULL) { 143 printf("xenpci Could not allocate memory bar.\n"); 144 goto errexit; 145 } 146 147 scp->phys_next = rman_get_start(scp->res_memory); 148 149 return (0); 150 151 errexit: 152 /* Cleanup anything we may have assigned. */ 153 xenpci_deallocate_resources(dev); 154 return (ENXIO); /* For want of a better idea. */ 155 } 156 157 /* 158 * Allocate a physical address range from our mmio region. 159 */ 160 static int 161 xenpci_alloc_space_int(struct xenpci_softc *scp, size_t sz, 162 vm_paddr_t *pa) 163 { 164 165 if (scp->phys_next + sz > rman_get_end(scp->res_memory)) { 166 return (ENOMEM); 167 } 168 169 *pa = scp->phys_next; 170 scp->phys_next += sz; 171 172 return (0); 173 } 174 175 /* 176 * Allocate a physical address range from our mmio region. 177 */ 178 int 179 xenpci_alloc_space(size_t sz, vm_paddr_t *pa) 180 { 181 device_t dev = devclass_get_device(xenpci_devclass, 0); 182 183 if (dev) { 184 return (xenpci_alloc_space_int(device_get_softc(dev), 185 sz, pa)); 186 } else { 187 return (ENOMEM); 188 } 189 } 190 191 static struct resource * 192 xenpci_alloc_resource(device_t dev, device_t child, int type, int *rid, 193 u_long start, u_long end, u_long count, u_int flags) 194 { 195 return (BUS_ALLOC_RESOURCE(nexus, child, type, rid, start, 196 end, count, flags)); 197 } 198 199 200 static int 201 xenpci_release_resource(device_t dev, device_t child, int type, int rid, 202 struct resource *r) 203 { 204 return (BUS_RELEASE_RESOURCE(nexus, child, type, rid, r)); 205 } 206 207 static int 208 xenpci_activate_resource(device_t dev, device_t child, int type, int rid, 209 struct resource *r) 210 { 211 return (BUS_ACTIVATE_RESOURCE(nexus, child, type, rid, r)); 212 } 213 214 static int 215 xenpci_deactivate_resource(device_t dev, device_t child, int type, 216 int rid, struct resource *r) 217 { 218 return (BUS_DEACTIVATE_RESOURCE(nexus, child, type, rid, r)); 219 } 220 221 /* 222 * Probe - just check device ID. 223 */ 224 static int 225 xenpci_probe(device_t dev) 226 { 227 228 if (pci_get_devid(dev) != 0x00015853) 229 return (ENXIO); 230 231 device_set_desc(dev, "Xen Platform Device"); 232 return (bus_generic_probe(dev)); 233 } 234 235 /* 236 * Attach - find resources and talk to Xen. 237 */ 238 static int 239 xenpci_attach(device_t dev) 240 { 241 struct xenpci_softc *scp = device_get_softc(dev); 242 devclass_t dc; 243 int error; 244 245 /* 246 * Find and record nexus0. Since we are not really on the 247 * PCI bus, all resource operations are directed to nexus 248 * instead of through our parent. 249 */ 250 if ((dc = devclass_find("nexus")) == 0 251 || (nexus = devclass_get_device(dc, 0)) == 0) { 252 device_printf(dev, "unable to find nexus."); 253 return (ENOENT); 254 } 255 256 error = xenpci_allocate_resources(dev); 257 if (error) { 258 device_printf(dev, "xenpci_allocate_resources failed(%d).\n", 259 error); 260 goto errexit; 261 } 262 263 /* 264 * Hook the irq up to evtchn 265 */ 266 error = xenpci_irq_init(dev, scp); 267 if (error) { 268 device_printf(dev, "xenpci_irq_init failed(%d).\n", 269 error); 270 goto errexit; 271 } 272 273 return (bus_generic_attach(dev)); 274 275 errexit: 276 /* 277 * Undo anything we may have done. 278 */ 279 xenpci_deallocate_resources(dev); 280 return (error); 281 } 282 283 /* 284 * Detach - reverse anything done by attach. 285 */ 286 static int 287 xenpci_detach(device_t dev) 288 { 289 struct xenpci_softc *scp = device_get_softc(dev); 290 device_t parent = device_get_parent(dev); 291 292 /* 293 * Take our interrupt handler out of the list of handlers 294 * that can handle this irq. 295 */ 296 if (scp->intr_cookie != NULL) { 297 if (BUS_TEARDOWN_INTR(parent, dev, 298 scp->res_irq, scp->intr_cookie) != 0) 299 device_printf(dev, 300 "intr teardown failed.. continuing\n"); 301 scp->intr_cookie = NULL; 302 } 303 304 /* 305 * Deallocate any system resources we may have 306 * allocated on behalf of this driver. 307 */ 308 return (xenpci_deallocate_resources(dev)); 309 } 310 311 static int 312 xenpci_suspend(device_t dev) 313 { 314 return (bus_generic_suspend(dev)); 315 } 316 317 static int 318 xenpci_resume(device_t dev) 319 { 320 xen_hvm_set_callback(dev); 321 return (bus_generic_resume(dev)); 322 } 323 324 static device_method_t xenpci_methods[] = { 325 /* Device interface */ 326 DEVMETHOD(device_probe, xenpci_probe), 327 DEVMETHOD(device_attach, xenpci_attach), 328 DEVMETHOD(device_detach, xenpci_detach), 329 DEVMETHOD(device_suspend, xenpci_suspend), 330 DEVMETHOD(device_resume, xenpci_resume), 331 332 /* Bus interface */ 333 DEVMETHOD(bus_add_child, bus_generic_add_child), 334 DEVMETHOD(bus_alloc_resource, xenpci_alloc_resource), 335 DEVMETHOD(bus_release_resource, xenpci_release_resource), 336 DEVMETHOD(bus_activate_resource, xenpci_activate_resource), 337 DEVMETHOD(bus_deactivate_resource, xenpci_deactivate_resource), 338 339 { 0, 0 } 340 }; 341 342 static driver_t xenpci_driver = { 343 "xenpci", 344 xenpci_methods, 345 sizeof(struct xenpci_softc), 346 }; 347 348 DRIVER_MODULE(xenpci, pci, xenpci_driver, xenpci_devclass, 0, 0); 349