Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

Xen: ARM: Add support for mapping platform device mmio

Add a bus_notifier for platform bus device in order to map the device
mmio regions when DOM0 booting with ACPI.

Signed-off-by: Shannon Zhao <shannon.zhao@linaro.org>
Acked-by: Stefano Stabellini <stefano.stabellini@eu.citrix.com>
Tested-by: Julien Grall <julien.grall@arm.com>

authored by

Shannon Zhao and committed by
David Vrabel
4ba04bec 712a5b77

+154
+1
drivers/xen/Makefile
··· 10 10 CFLAGS_efi.o += -fshort-wchar 11 11 LDFLAGS += $(call ld-option, --no-wchar-size-warning) 12 12 13 + dom0-$(CONFIG_ARM64) += arm-device.o 13 14 dom0-$(CONFIG_PCI) += pci.o 14 15 dom0-$(CONFIG_USB_SUPPORT) += dbgp.o 15 16 dom0-$(CONFIG_XEN_ACPI) += acpi.o $(xen-pad-y)
+153
drivers/xen/arm-device.c
··· 1 + /* 2 + * Copyright (c) 2015, Linaro Limited, Shannon Zhao 3 + * 4 + * This program is free software; you can redistribute it and/or modify it 5 + * under the terms and conditions of the GNU General Public License, 6 + * version 2, as published by the Free Software Foundation. 7 + * 8 + * This program is distributed in the hope it will be useful, but WITHOUT 9 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 10 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 11 + * more details. 12 + * 13 + * You should have received a copy of the GNU General Public License 14 + * along with this program. If not, see <http://www.gnu.org/licenses/>. 15 + */ 16 + 17 + #include <linux/platform_device.h> 18 + #include <linux/acpi.h> 19 + #include <xen/xen.h> 20 + #include <xen/page.h> 21 + #include <xen/interface/memory.h> 22 + #include <asm/xen/hypervisor.h> 23 + #include <asm/xen/hypercall.h> 24 + 25 + static int xen_unmap_device_mmio(const struct resource *resources, 26 + unsigned int count) 27 + { 28 + unsigned int i, j, nr; 29 + int rc = 0; 30 + const struct resource *r; 31 + struct xen_remove_from_physmap xrp; 32 + 33 + for (i = 0; i < count; i++) { 34 + r = &resources[i]; 35 + nr = DIV_ROUND_UP(resource_size(r), XEN_PAGE_SIZE); 36 + if ((resource_type(r) != IORESOURCE_MEM) || (nr == 0)) 37 + continue; 38 + 39 + for (j = 0; j < nr; j++) { 40 + xrp.domid = DOMID_SELF; 41 + xrp.gpfn = XEN_PFN_DOWN(r->start) + j; 42 + rc = HYPERVISOR_memory_op(XENMEM_remove_from_physmap, 43 + &xrp); 44 + if (rc) 45 + return rc; 46 + } 47 + } 48 + 49 + return rc; 50 + } 51 + 52 + static int xen_map_device_mmio(const struct resource *resources, 53 + unsigned int count) 54 + { 55 + unsigned int i, j, nr; 56 + int rc = 0; 57 + const struct resource *r; 58 + xen_pfn_t *gpfns; 59 + xen_ulong_t *idxs; 60 + int *errs; 61 + struct xen_add_to_physmap_range xatp; 62 + 63 + for (i = 0; i < count; i++) { 64 + r = &resources[i]; 65 + nr = DIV_ROUND_UP(resource_size(r), XEN_PAGE_SIZE); 66 + if ((resource_type(r) != IORESOURCE_MEM) || (nr == 0)) 67 + continue; 68 + 69 + gpfns = kzalloc(sizeof(xen_pfn_t) * nr, GFP_KERNEL); 70 + idxs = kzalloc(sizeof(xen_ulong_t) * nr, GFP_KERNEL); 71 + errs = kzalloc(sizeof(int) * nr, GFP_KERNEL); 72 + if (!gpfns || !idxs || !errs) { 73 + kfree(gpfns); 74 + kfree(idxs); 75 + kfree(errs); 76 + rc = -ENOMEM; 77 + goto unmap; 78 + } 79 + 80 + for (j = 0; j < nr; j++) { 81 + /* 82 + * The regions are always mapped 1:1 to DOM0 and this is 83 + * fine because the memory map for DOM0 is the same as 84 + * the host (except for the RAM). 85 + */ 86 + gpfns[j] = XEN_PFN_DOWN(r->start) + j; 87 + idxs[j] = XEN_PFN_DOWN(r->start) + j; 88 + } 89 + 90 + xatp.domid = DOMID_SELF; 91 + xatp.size = nr; 92 + xatp.space = XENMAPSPACE_dev_mmio; 93 + 94 + set_xen_guest_handle(xatp.gpfns, gpfns); 95 + set_xen_guest_handle(xatp.idxs, idxs); 96 + set_xen_guest_handle(xatp.errs, errs); 97 + 98 + rc = HYPERVISOR_memory_op(XENMEM_add_to_physmap_range, &xatp); 99 + kfree(gpfns); 100 + kfree(idxs); 101 + kfree(errs); 102 + if (rc) 103 + goto unmap; 104 + } 105 + 106 + return rc; 107 + 108 + unmap: 109 + xen_unmap_device_mmio(resources, i); 110 + return rc; 111 + } 112 + 113 + static int xen_platform_notifier(struct notifier_block *nb, 114 + unsigned long action, void *data) 115 + { 116 + struct platform_device *pdev = to_platform_device(data); 117 + int r = 0; 118 + 119 + if (pdev->num_resources == 0 || pdev->resource == NULL) 120 + return NOTIFY_OK; 121 + 122 + switch (action) { 123 + case BUS_NOTIFY_ADD_DEVICE: 124 + r = xen_map_device_mmio(pdev->resource, pdev->num_resources); 125 + break; 126 + case BUS_NOTIFY_DEL_DEVICE: 127 + r = xen_unmap_device_mmio(pdev->resource, pdev->num_resources); 128 + break; 129 + default: 130 + return NOTIFY_DONE; 131 + } 132 + if (r) 133 + dev_err(&pdev->dev, "Platform: Failed to %s device %s MMIO!\n", 134 + action == BUS_NOTIFY_ADD_DEVICE ? "map" : 135 + (action == BUS_NOTIFY_DEL_DEVICE ? "unmap" : "?"), 136 + pdev->name); 137 + 138 + return NOTIFY_OK; 139 + } 140 + 141 + static struct notifier_block platform_device_nb = { 142 + .notifier_call = xen_platform_notifier, 143 + }; 144 + 145 + static int __init register_xen_platform_notifier(void) 146 + { 147 + if (!xen_initial_domain() || acpi_disabled) 148 + return 0; 149 + 150 + return bus_register_notifier(&platform_bus_type, &platform_device_nb); 151 + } 152 + 153 + arch_initcall(register_xen_platform_notifier);