0001
0002
0003
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
0076
0077
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