Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * Copyright (c) 2015, Linaro Limited, Shannon Zhao
0004  */
0005 
0006 #include <linux/platform_device.h>
0007 #include <linux/acpi.h>
0008 #include <xen/xen.h>
0009 #include <xen/page.h>
0010 #include <xen/interface/memory.h>
0011 #include <asm/xen/hypervisor.h>
0012 #include <asm/xen/hypercall.h>
0013 
0014 static int xen_unmap_device_mmio(const struct resource *resources,
0015                  unsigned int count)
0016 {
0017     unsigned int i, j, nr;
0018     int rc = 0;
0019     const struct resource *r;
0020     struct xen_remove_from_physmap xrp;
0021 
0022     for (i = 0; i < count; i++) {
0023         r = &resources[i];
0024         nr = DIV_ROUND_UP(resource_size(r), XEN_PAGE_SIZE);
0025         if ((resource_type(r) != IORESOURCE_MEM) || (nr == 0))
0026             continue;
0027 
0028         for (j = 0; j < nr; j++) {
0029             xrp.domid = DOMID_SELF;
0030             xrp.gpfn = XEN_PFN_DOWN(r->start) + j;
0031             rc = HYPERVISOR_memory_op(XENMEM_remove_from_physmap,
0032                           &xrp);
0033             if (rc)
0034                 return rc;
0035         }
0036     }
0037 
0038     return rc;
0039 }
0040 
0041 static int xen_map_device_mmio(const struct resource *resources,
0042                    unsigned int count)
0043 {
0044     unsigned int i, j, nr;
0045     int rc = 0;
0046     const struct resource *r;
0047     xen_pfn_t *gpfns;
0048     xen_ulong_t *idxs;
0049     int *errs;
0050 
0051     for (i = 0; i < count; i++) {
0052         struct xen_add_to_physmap_range xatp = {
0053             .domid = DOMID_SELF,
0054             .space = XENMAPSPACE_dev_mmio
0055         };
0056 
0057         r = &resources[i];
0058         nr = DIV_ROUND_UP(resource_size(r), XEN_PAGE_SIZE);
0059         if ((resource_type(r) != IORESOURCE_MEM) || (nr == 0))
0060             continue;
0061 
0062         gpfns = kcalloc(nr, sizeof(xen_pfn_t), GFP_KERNEL);
0063         idxs = kcalloc(nr, sizeof(xen_ulong_t), GFP_KERNEL);
0064         errs = kcalloc(nr, sizeof(int), GFP_KERNEL);
0065         if (!gpfns || !idxs || !errs) {
0066             kfree(gpfns);
0067             kfree(idxs);
0068             kfree(errs);
0069             rc = -ENOMEM;
0070             goto unmap;
0071         }
0072 
0073         for (j = 0; j < nr; j++) {
0074             /*
0075              * The regions are always mapped 1:1 to DOM0 and this is
0076              * fine because the memory map for DOM0 is the same as
0077              * the host (except for the RAM).
0078              */
0079             gpfns[j] = XEN_PFN_DOWN(r->start) + j;
0080             idxs[j] = XEN_PFN_DOWN(r->start) + j;
0081         }
0082 
0083         xatp.size = nr;
0084 
0085         set_xen_guest_handle(xatp.gpfns, gpfns);
0086         set_xen_guest_handle(xatp.idxs, idxs);
0087         set_xen_guest_handle(xatp.errs, errs);
0088 
0089         rc = HYPERVISOR_memory_op(XENMEM_add_to_physmap_range, &xatp);
0090         kfree(gpfns);
0091         kfree(idxs);
0092         kfree(errs);
0093         if (rc)
0094             goto unmap;
0095     }
0096 
0097     return rc;
0098 
0099 unmap:
0100     xen_unmap_device_mmio(resources, i);
0101     return rc;
0102 }
0103 
0104 static int xen_platform_notifier(struct notifier_block *nb,
0105                  unsigned long action, void *data)
0106 {
0107     struct platform_device *pdev = to_platform_device(data);
0108     int r = 0;
0109 
0110     if (pdev->num_resources == 0 || pdev->resource == NULL)
0111         return NOTIFY_OK;
0112 
0113     switch (action) {
0114     case BUS_NOTIFY_ADD_DEVICE:
0115         r = xen_map_device_mmio(pdev->resource, pdev->num_resources);
0116         break;
0117     case BUS_NOTIFY_DEL_DEVICE:
0118         r = xen_unmap_device_mmio(pdev->resource, pdev->num_resources);
0119         break;
0120     default:
0121         return NOTIFY_DONE;
0122     }
0123     if (r)
0124         dev_err(&pdev->dev, "Platform: Failed to %s device %s MMIO!\n",
0125             action == BUS_NOTIFY_ADD_DEVICE ? "map" :
0126             (action == BUS_NOTIFY_DEL_DEVICE ? "unmap" : "?"),
0127             pdev->name);
0128 
0129     return NOTIFY_OK;
0130 }
0131 
0132 static struct notifier_block platform_device_nb = {
0133     .notifier_call = xen_platform_notifier,
0134 };
0135 
0136 static int __init register_xen_platform_notifier(void)
0137 {
0138     if (!xen_initial_domain() || acpi_disabled)
0139         return 0;
0140 
0141     return bus_register_notifier(&platform_bus_type, &platform_device_nb);
0142 }
0143 
0144 arch_initcall(register_xen_platform_notifier);
0145 
0146 #ifdef CONFIG_ARM_AMBA
0147 #include <linux/amba/bus.h>
0148 
0149 static int xen_amba_notifier(struct notifier_block *nb,
0150                  unsigned long action, void *data)
0151 {
0152     struct amba_device *adev = to_amba_device(data);
0153     int r = 0;
0154 
0155     switch (action) {
0156     case BUS_NOTIFY_ADD_DEVICE:
0157         r = xen_map_device_mmio(&adev->res, 1);
0158         break;
0159     case BUS_NOTIFY_DEL_DEVICE:
0160         r = xen_unmap_device_mmio(&adev->res, 1);
0161         break;
0162     default:
0163         return NOTIFY_DONE;
0164     }
0165     if (r)
0166         dev_err(&adev->dev, "AMBA: Failed to %s device %s MMIO!\n",
0167             action == BUS_NOTIFY_ADD_DEVICE ? "map" :
0168             (action == BUS_NOTIFY_DEL_DEVICE ? "unmap" : "?"),
0169             adev->dev.init_name);
0170 
0171     return NOTIFY_OK;
0172 }
0173 
0174 static struct notifier_block amba_device_nb = {
0175     .notifier_call = xen_amba_notifier,
0176 };
0177 
0178 static int __init register_xen_amba_notifier(void)
0179 {
0180     if (!xen_initial_domain() || acpi_disabled)
0181         return 0;
0182 
0183     return bus_register_notifier(&amba_bustype, &amba_device_nb);
0184 }
0185 
0186 arch_initcall(register_xen_amba_notifier);
0187 #endif