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 #include <sys/proc.h> 3612678024SDoug Rabson #include <sys/systm.h> 3712678024SDoug Rabson #include <sys/time.h> 3812678024SDoug Rabson 3912678024SDoug Rabson #include <machine/bus.h> 4012678024SDoug Rabson #include <machine/resource.h> 4112678024SDoug Rabson #include <sys/rman.h> 4212678024SDoug Rabson 4312678024SDoug Rabson #include <machine/stdarg.h> 4412678024SDoug Rabson #include <machine/xen/xen-os.h> 4512678024SDoug Rabson #include <xen/features.h> 4612678024SDoug Rabson #include <xen/hypervisor.h> 4712678024SDoug Rabson #include <xen/gnttab.h> 4812678024SDoug Rabson #include <xen/xen_intr.h> 4912678024SDoug Rabson #include <xen/interface/memory.h> 5012678024SDoug Rabson #include <xen/interface/hvm/params.h> 5112678024SDoug Rabson 5212678024SDoug Rabson #include <dev/pci/pcireg.h> 5312678024SDoug Rabson #include <dev/pci/pcivar.h> 5412678024SDoug Rabson 5512678024SDoug Rabson #include <vm/vm.h> 5612678024SDoug Rabson #include <vm/vm_extern.h> 5712678024SDoug Rabson #include <vm/vm_kern.h> 5812678024SDoug Rabson #include <vm/pmap.h> 5912678024SDoug Rabson 6012678024SDoug Rabson #include <dev/xen/xenpci/xenpcivar.h> 6112678024SDoug Rabson 6212678024SDoug Rabson /* 6312678024SDoug Rabson * These variables are used by the rest of the kernel to access the 6412678024SDoug Rabson * hypervisor. 6512678024SDoug Rabson */ 6612678024SDoug Rabson char *hypercall_stubs; 6712678024SDoug Rabson shared_info_t *HYPERVISOR_shared_info; 6812678024SDoug Rabson static vm_paddr_t shared_info_pa; 6912678024SDoug Rabson 7012678024SDoug Rabson /* 7112678024SDoug Rabson * This is used to find our platform device instance. 7212678024SDoug Rabson */ 7312678024SDoug Rabson static devclass_t xenpci_devclass; 7412678024SDoug Rabson 7512678024SDoug Rabson /* 7612678024SDoug Rabson * Return the CPUID base address for Xen functions. 7712678024SDoug Rabson */ 7812678024SDoug Rabson static uint32_t 7912678024SDoug Rabson xenpci_cpuid_base(void) 8012678024SDoug Rabson { 8112678024SDoug Rabson uint32_t base, regs[4]; 8212678024SDoug Rabson 8312678024SDoug Rabson for (base = 0x40000000; base < 0x40001000; base += 0x100) { 8412678024SDoug Rabson do_cpuid(base, regs); 8512678024SDoug Rabson if (!memcmp("XenVMMXenVMM", ®s[1], 12) 8612678024SDoug Rabson && (regs[0] - base) >= 2) 8712678024SDoug Rabson return (base); 8812678024SDoug Rabson } 8912678024SDoug Rabson return (0); 9012678024SDoug Rabson } 9112678024SDoug Rabson 9212678024SDoug Rabson /* 9312678024SDoug Rabson * Allocate and fill in the hypcall page. 9412678024SDoug Rabson */ 9512678024SDoug Rabson static int 9612678024SDoug Rabson xenpci_init_hypercall_stubs(device_t dev, struct xenpci_softc * scp) 9712678024SDoug Rabson { 9812678024SDoug Rabson uint32_t base, regs[4]; 9912678024SDoug Rabson int i; 10012678024SDoug Rabson 10112678024SDoug Rabson base = xenpci_cpuid_base(); 10212678024SDoug Rabson if (!base) { 10312678024SDoug Rabson device_printf(dev, "Xen platform device but not Xen VMM\n"); 10412678024SDoug Rabson return (EINVAL); 10512678024SDoug Rabson } 10612678024SDoug Rabson 10712678024SDoug Rabson if (bootverbose) { 10812678024SDoug Rabson do_cpuid(base + 1, regs); 10912678024SDoug Rabson device_printf(dev, "Xen version %d.%d.\n", 11012678024SDoug Rabson regs[0] >> 16, regs[0] & 0xffff); 11112678024SDoug Rabson } 11212678024SDoug Rabson 11312678024SDoug Rabson /* 11412678024SDoug Rabson * Find the hypercall pages. 11512678024SDoug Rabson */ 11612678024SDoug Rabson do_cpuid(base + 2, regs); 11712678024SDoug Rabson 11812678024SDoug Rabson hypercall_stubs = malloc(regs[0] * PAGE_SIZE, M_TEMP, M_WAITOK); 11912678024SDoug Rabson 12012678024SDoug Rabson for (i = 0; i < regs[0]; i++) { 12112678024SDoug Rabson wrmsr(regs[1], vtophys(hypercall_stubs + i * PAGE_SIZE) + i); 12212678024SDoug Rabson } 12312678024SDoug Rabson 12412678024SDoug Rabson return (0); 12512678024SDoug Rabson } 12612678024SDoug Rabson 12712678024SDoug Rabson /* 12812678024SDoug Rabson * After a resume, re-initialise the hypercall page. 12912678024SDoug Rabson */ 13012678024SDoug Rabson static void 13112678024SDoug Rabson xenpci_resume_hypercall_stubs(device_t dev, struct xenpci_softc * scp) 13212678024SDoug Rabson { 13312678024SDoug Rabson uint32_t base, regs[4]; 13412678024SDoug Rabson int i; 13512678024SDoug Rabson 13612678024SDoug Rabson base = xenpci_cpuid_base(); 13712678024SDoug Rabson 13812678024SDoug Rabson do_cpuid(base + 2, regs); 13912678024SDoug Rabson for (i = 0; i < regs[0]; i++) { 14012678024SDoug Rabson wrmsr(regs[1], vtophys(hypercall_stubs + i * PAGE_SIZE) + i); 14112678024SDoug Rabson } 14212678024SDoug Rabson } 14312678024SDoug Rabson 14412678024SDoug Rabson /* 14512678024SDoug Rabson * Tell the hypervisor how to contact us for event channel callbacks. 14612678024SDoug Rabson */ 14712678024SDoug Rabson static void 14812678024SDoug Rabson xenpci_set_callback(device_t dev) 14912678024SDoug Rabson { 15012678024SDoug Rabson int irq; 15112678024SDoug Rabson uint64_t callback; 15212678024SDoug Rabson struct xen_hvm_param xhp; 15312678024SDoug Rabson 15412678024SDoug Rabson irq = pci_get_irq(dev); 15512678024SDoug Rabson if (irq < 16) { 15612678024SDoug Rabson callback = irq; 15712678024SDoug Rabson } else { 15812678024SDoug Rabson callback = (pci_get_intpin(dev) - 1) & 3; 15912678024SDoug Rabson callback |= pci_get_slot(dev) << 11; 16012678024SDoug Rabson callback |= 1ull << 56; 16112678024SDoug Rabson } 16212678024SDoug Rabson 16312678024SDoug Rabson xhp.domid = DOMID_SELF; 16412678024SDoug Rabson xhp.index = HVM_PARAM_CALLBACK_IRQ; 16512678024SDoug Rabson xhp.value = callback; 16612678024SDoug Rabson if (HYPERVISOR_hvm_op(HVMOP_set_param, &xhp)) 16712678024SDoug Rabson panic("Can't set evtchn callback"); 16812678024SDoug Rabson } 16912678024SDoug Rabson 17012678024SDoug Rabson 17112678024SDoug Rabson /* 17212678024SDoug Rabson * Deallocate anything allocated by xenpci_allocate_resources. 17312678024SDoug Rabson */ 17412678024SDoug Rabson static int 17512678024SDoug Rabson xenpci_deallocate_resources(device_t dev) 17612678024SDoug Rabson { 17712678024SDoug Rabson struct xenpci_softc *scp = device_get_softc(dev); 17812678024SDoug Rabson 17912678024SDoug Rabson if (scp->res_irq != 0) { 18012678024SDoug Rabson bus_deactivate_resource(dev, SYS_RES_IRQ, 18112678024SDoug Rabson scp->rid_irq, scp->res_irq); 18212678024SDoug Rabson bus_release_resource(dev, SYS_RES_IRQ, 18312678024SDoug Rabson scp->rid_irq, scp->res_irq); 18412678024SDoug Rabson scp->res_irq = 0; 18512678024SDoug Rabson } 18612678024SDoug Rabson if (scp->res_memory != 0) { 18712678024SDoug Rabson bus_deactivate_resource(dev, SYS_RES_MEMORY, 18812678024SDoug Rabson scp->rid_memory, scp->res_memory); 18912678024SDoug Rabson bus_release_resource(dev, SYS_RES_MEMORY, 19012678024SDoug Rabson scp->rid_memory, scp->res_memory); 19112678024SDoug Rabson scp->res_memory = 0; 19212678024SDoug Rabson } 19312678024SDoug Rabson 19412678024SDoug Rabson return (0); 19512678024SDoug Rabson } 19612678024SDoug Rabson 19712678024SDoug Rabson /* 19812678024SDoug Rabson * Allocate irq and memory resources. 19912678024SDoug Rabson */ 20012678024SDoug Rabson static int 20112678024SDoug Rabson xenpci_allocate_resources(device_t dev) 20212678024SDoug Rabson { 20312678024SDoug Rabson struct xenpci_softc *scp = device_get_softc(dev); 20412678024SDoug Rabson 20512678024SDoug Rabson scp->res_irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, 20612678024SDoug Rabson &scp->rid_irq, RF_SHAREABLE|RF_ACTIVE); 20712678024SDoug Rabson if (scp->res_irq == NULL) 20812678024SDoug Rabson goto errexit; 20912678024SDoug Rabson 21012678024SDoug Rabson scp->rid_memory = PCIR_BAR(1); 21112678024SDoug Rabson scp->res_memory = bus_alloc_resource_any(dev, SYS_RES_MEMORY, 21212678024SDoug Rabson &scp->rid_memory, RF_ACTIVE); 21312678024SDoug Rabson if (scp->res_memory == NULL) 21412678024SDoug Rabson goto errexit; 21512678024SDoug Rabson return (0); 21612678024SDoug Rabson 21712678024SDoug Rabson errexit: 21812678024SDoug Rabson /* Cleanup anything we may have assigned. */ 21912678024SDoug Rabson xenpci_deallocate_resources(dev); 22012678024SDoug Rabson return (ENXIO); /* For want of a better idea. */ 22112678024SDoug Rabson } 22212678024SDoug Rabson 22312678024SDoug Rabson /* 22412678024SDoug Rabson * Allocate a physical address range from our mmio region. 22512678024SDoug Rabson */ 22612678024SDoug Rabson static int 22712678024SDoug Rabson xenpci_alloc_space_int(struct xenpci_softc *scp, size_t sz, 22812678024SDoug Rabson vm_paddr_t *pa) 22912678024SDoug Rabson { 23012678024SDoug Rabson 23112678024SDoug Rabson if (scp->phys_next + sz > rman_get_end(scp->res_memory)) { 23212678024SDoug Rabson return (ENOMEM); 23312678024SDoug Rabson } 23412678024SDoug Rabson 23512678024SDoug Rabson *pa = scp->phys_next; 23612678024SDoug Rabson scp->phys_next += sz; 23712678024SDoug Rabson 23812678024SDoug Rabson return (0); 23912678024SDoug Rabson } 24012678024SDoug Rabson 24112678024SDoug Rabson /* 24212678024SDoug Rabson * Allocate a physical address range from our mmio region. 24312678024SDoug Rabson */ 24412678024SDoug Rabson int 24512678024SDoug Rabson xenpci_alloc_space(size_t sz, vm_paddr_t *pa) 24612678024SDoug Rabson { 24712678024SDoug Rabson device_t dev = devclass_get_device(xenpci_devclass, 0); 24812678024SDoug Rabson 24912678024SDoug Rabson if (dev) { 25012678024SDoug Rabson return (xenpci_alloc_space_int(device_get_softc(dev), 25112678024SDoug Rabson sz, pa)); 25212678024SDoug Rabson } else { 25312678024SDoug Rabson return (ENOMEM); 25412678024SDoug Rabson } 25512678024SDoug Rabson } 25612678024SDoug Rabson 25712678024SDoug Rabson /* 25812678024SDoug Rabson * Called very early in the resume sequence - reinitialise the various 25912678024SDoug Rabson * bits of Xen machinery including the hypercall page and the shared 26012678024SDoug Rabson * info page. 26112678024SDoug Rabson */ 26212678024SDoug Rabson void 26312678024SDoug Rabson xenpci_resume() 26412678024SDoug Rabson { 26512678024SDoug Rabson device_t dev = devclass_get_device(xenpci_devclass, 0); 26612678024SDoug Rabson struct xenpci_softc *scp = device_get_softc(dev); 26712678024SDoug Rabson struct xen_add_to_physmap xatp; 26812678024SDoug Rabson 26912678024SDoug Rabson xenpci_resume_hypercall_stubs(dev, scp); 27012678024SDoug Rabson 27112678024SDoug Rabson xatp.domid = DOMID_SELF; 27212678024SDoug Rabson xatp.idx = 0; 27312678024SDoug Rabson xatp.space = XENMAPSPACE_shared_info; 27412678024SDoug Rabson xatp.gpfn = shared_info_pa >> PAGE_SHIFT; 27512678024SDoug Rabson if (HYPERVISOR_memory_op(XENMEM_add_to_physmap, &xatp)) 27612678024SDoug Rabson panic("HYPERVISOR_memory_op failed"); 27712678024SDoug Rabson 27812678024SDoug Rabson pmap_kenter((vm_offset_t) HYPERVISOR_shared_info, shared_info_pa); 27912678024SDoug Rabson 28012678024SDoug Rabson xenpci_set_callback(dev); 28112678024SDoug Rabson 28212678024SDoug Rabson gnttab_resume(); 28312678024SDoug Rabson irq_resume(); 28412678024SDoug Rabson } 28512678024SDoug Rabson 28612678024SDoug Rabson /* 28712678024SDoug Rabson * Probe - just check device ID. 28812678024SDoug Rabson */ 28912678024SDoug Rabson static int 29012678024SDoug Rabson xenpci_probe(device_t dev) 29112678024SDoug Rabson { 29212678024SDoug Rabson 29312678024SDoug Rabson if (pci_get_devid(dev) != 0x00015853) 29412678024SDoug Rabson return (ENXIO); 29512678024SDoug Rabson 29612678024SDoug Rabson device_set_desc(dev, "Xen Platform Device"); 29712678024SDoug Rabson return (bus_generic_probe(dev)); 29812678024SDoug Rabson } 29912678024SDoug Rabson 30012678024SDoug Rabson /* 30112678024SDoug Rabson * Attach - find resources and talk to Xen. 30212678024SDoug Rabson */ 30312678024SDoug Rabson static int 30412678024SDoug Rabson xenpci_attach(device_t dev) 30512678024SDoug Rabson { 30612678024SDoug Rabson int error; 30712678024SDoug Rabson struct xenpci_softc *scp = device_get_softc(dev); 30812678024SDoug Rabson struct xen_add_to_physmap xatp; 30912678024SDoug Rabson vm_offset_t shared_va; 31012678024SDoug Rabson 31112678024SDoug Rabson error = xenpci_allocate_resources(dev); 31212678024SDoug Rabson if (error) 31312678024SDoug Rabson goto errexit; 31412678024SDoug Rabson 31512678024SDoug Rabson scp->phys_next = rman_get_start(scp->res_memory); 31612678024SDoug Rabson 31712678024SDoug Rabson error = xenpci_init_hypercall_stubs(dev, scp); 31812678024SDoug Rabson if (error) 31912678024SDoug Rabson goto errexit; 32012678024SDoug Rabson 32112678024SDoug Rabson setup_xen_features(); 32212678024SDoug Rabson 32312678024SDoug Rabson xenpci_alloc_space_int(scp, PAGE_SIZE, &shared_info_pa); 32412678024SDoug Rabson 32512678024SDoug Rabson xatp.domid = DOMID_SELF; 32612678024SDoug Rabson xatp.idx = 0; 32712678024SDoug Rabson xatp.space = XENMAPSPACE_shared_info; 32812678024SDoug Rabson xatp.gpfn = shared_info_pa >> PAGE_SHIFT; 32912678024SDoug Rabson if (HYPERVISOR_memory_op(XENMEM_add_to_physmap, &xatp)) 33012678024SDoug Rabson panic("HYPERVISOR_memory_op failed"); 33112678024SDoug Rabson 33212678024SDoug Rabson shared_va = kmem_alloc_nofault(kernel_map, PAGE_SIZE); 33312678024SDoug Rabson pmap_kenter(shared_va, shared_info_pa); 33412678024SDoug Rabson HYPERVISOR_shared_info = (void *) shared_va; 33512678024SDoug Rabson 33612678024SDoug Rabson /* 33712678024SDoug Rabson * Hook the irq up to evtchn 33812678024SDoug Rabson */ 33912678024SDoug Rabson xenpci_irq_init(dev, scp); 34012678024SDoug Rabson xenpci_set_callback(dev); 34112678024SDoug Rabson 34212678024SDoug Rabson return (bus_generic_attach(dev)); 34312678024SDoug Rabson 34412678024SDoug Rabson errexit: 34512678024SDoug Rabson /* 34612678024SDoug Rabson * Undo anything we may have done. 34712678024SDoug Rabson */ 34812678024SDoug Rabson xenpci_deallocate_resources(dev); 34912678024SDoug Rabson return (error); 35012678024SDoug Rabson } 35112678024SDoug Rabson 35212678024SDoug Rabson /* 35312678024SDoug Rabson * Detach - reverse anything done by attach. 35412678024SDoug Rabson */ 35512678024SDoug Rabson static int 35612678024SDoug Rabson xenpci_detach(device_t dev) 35712678024SDoug Rabson { 35812678024SDoug Rabson struct xenpci_softc *scp = device_get_softc(dev); 35912678024SDoug Rabson device_t parent = device_get_parent(dev); 36012678024SDoug Rabson 36112678024SDoug Rabson /* 36212678024SDoug Rabson * Take our interrupt handler out of the list of handlers 36312678024SDoug Rabson * that can handle this irq. 36412678024SDoug Rabson */ 36512678024SDoug Rabson if (scp->intr_cookie != NULL) { 36612678024SDoug Rabson if (BUS_TEARDOWN_INTR(parent, dev, 36712678024SDoug Rabson scp->res_irq, scp->intr_cookie) != 0) 36812678024SDoug Rabson printf("intr teardown failed.. continuing\n"); 36912678024SDoug Rabson scp->intr_cookie = NULL; 37012678024SDoug Rabson } 37112678024SDoug Rabson 37212678024SDoug Rabson /* 37312678024SDoug Rabson * Deallocate any system resources we may have 37412678024SDoug Rabson * allocated on behalf of this driver. 37512678024SDoug Rabson */ 37612678024SDoug Rabson return (xenpci_deallocate_resources(dev)); 37712678024SDoug Rabson } 37812678024SDoug Rabson 37912678024SDoug Rabson static device_method_t xenpci_methods[] = { 38012678024SDoug Rabson /* Device interface */ 38112678024SDoug Rabson DEVMETHOD(device_probe, xenpci_probe), 38212678024SDoug Rabson DEVMETHOD(device_attach, xenpci_attach), 38312678024SDoug Rabson DEVMETHOD(device_detach, xenpci_detach), 38412678024SDoug Rabson DEVMETHOD(device_suspend, bus_generic_suspend), 38512678024SDoug Rabson DEVMETHOD(device_resume, bus_generic_resume), 38612678024SDoug Rabson 38712678024SDoug Rabson /* Bus interface */ 38812678024SDoug Rabson DEVMETHOD(bus_add_child, bus_generic_add_child), 38912678024SDoug Rabson 39012678024SDoug Rabson { 0, 0 } 39112678024SDoug Rabson }; 39212678024SDoug Rabson 39312678024SDoug Rabson static driver_t xenpci_driver = { 39412678024SDoug Rabson "xenpci", 39512678024SDoug Rabson xenpci_methods, 39612678024SDoug Rabson sizeof(struct xenpci_softc), 39712678024SDoug Rabson }; 39812678024SDoug Rabson 39912678024SDoug Rabson DRIVER_MODULE(xenpci, pci, xenpci_driver, xenpci_devclass, 0, 0); 400