arm-device.c 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199
  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. #include <linux/platform_device.h>
  17. #include <linux/acpi.h>
  18. #include <xen/xen.h>
  19. #include <xen/page.h>
  20. #include <xen/interface/memory.h>
  21. #include <asm/xen/hypervisor.h>
  22. #include <asm/xen/hypercall.h>
  23. static int xen_unmap_device_mmio(const struct resource *resources,
  24. unsigned int count)
  25. {
  26. unsigned int i, j, nr;
  27. int rc = 0;
  28. const struct resource *r;
  29. struct xen_remove_from_physmap xrp;
  30. for (i = 0; i < count; i++) {
  31. r = &resources[i];
  32. nr = DIV_ROUND_UP(resource_size(r), XEN_PAGE_SIZE);
  33. if ((resource_type(r) != IORESOURCE_MEM) || (nr == 0))
  34. continue;
  35. for (j = 0; j < nr; j++) {
  36. xrp.domid = DOMID_SELF;
  37. xrp.gpfn = XEN_PFN_DOWN(r->start) + j;
  38. rc = HYPERVISOR_memory_op(XENMEM_remove_from_physmap,
  39. &xrp);
  40. if (rc)
  41. return rc;
  42. }
  43. }
  44. return rc;
  45. }
  46. static int xen_map_device_mmio(const struct resource *resources,
  47. unsigned int count)
  48. {
  49. unsigned int i, j, nr;
  50. int rc = 0;
  51. const struct resource *r;
  52. xen_pfn_t *gpfns;
  53. xen_ulong_t *idxs;
  54. int *errs;
  55. for (i = 0; i < count; i++) {
  56. struct xen_add_to_physmap_range xatp = {
  57. .domid = DOMID_SELF,
  58. .space = XENMAPSPACE_dev_mmio
  59. };
  60. r = &resources[i];
  61. nr = DIV_ROUND_UP(resource_size(r), XEN_PAGE_SIZE);
  62. if ((resource_type(r) != IORESOURCE_MEM) || (nr == 0))
  63. continue;
  64. gpfns = kcalloc(nr, sizeof(xen_pfn_t), GFP_KERNEL);
  65. idxs = kcalloc(nr, sizeof(xen_ulong_t), GFP_KERNEL);
  66. errs = kcalloc(nr, sizeof(int), GFP_KERNEL);
  67. if (!gpfns || !idxs || !errs) {
  68. kfree(gpfns);
  69. kfree(idxs);
  70. kfree(errs);
  71. rc = -ENOMEM;
  72. goto unmap;
  73. }
  74. for (j = 0; j < nr; j++) {
  75. /*
  76. * The regions are always mapped 1:1 to DOM0 and this is
  77. * fine because the memory map for DOM0 is the same as
  78. * the host (except for the RAM).
  79. */
  80. gpfns[j] = XEN_PFN_DOWN(r->start) + j;
  81. idxs[j] = XEN_PFN_DOWN(r->start) + j;
  82. }
  83. xatp.size = nr;
  84. set_xen_guest_handle(xatp.gpfns, gpfns);
  85. set_xen_guest_handle(xatp.idxs, idxs);
  86. set_xen_guest_handle(xatp.errs, errs);
  87. rc = HYPERVISOR_memory_op(XENMEM_add_to_physmap_range, &xatp);
  88. kfree(gpfns);
  89. kfree(idxs);
  90. kfree(errs);
  91. if (rc)
  92. goto unmap;
  93. }
  94. return rc;
  95. unmap:
  96. xen_unmap_device_mmio(resources, i);
  97. return rc;
  98. }
  99. static int xen_platform_notifier(struct notifier_block *nb,
  100. unsigned long action, void *data)
  101. {
  102. struct platform_device *pdev = to_platform_device(data);
  103. int r = 0;
  104. if (pdev->num_resources == 0 || pdev->resource == NULL)
  105. return NOTIFY_OK;
  106. switch (action) {
  107. case BUS_NOTIFY_ADD_DEVICE:
  108. r = xen_map_device_mmio(pdev->resource, pdev->num_resources);
  109. break;
  110. case BUS_NOTIFY_DEL_DEVICE:
  111. r = xen_unmap_device_mmio(pdev->resource, pdev->num_resources);
  112. break;
  113. default:
  114. return NOTIFY_DONE;
  115. }
  116. if (r)
  117. dev_err(&pdev->dev, "Platform: Failed to %s device %s MMIO!\n",
  118. action == BUS_NOTIFY_ADD_DEVICE ? "map" :
  119. (action == BUS_NOTIFY_DEL_DEVICE ? "unmap" : "?"),
  120. pdev->name);
  121. return NOTIFY_OK;
  122. }
  123. static struct notifier_block platform_device_nb = {
  124. .notifier_call = xen_platform_notifier,
  125. };
  126. static int __init register_xen_platform_notifier(void)
  127. {
  128. if (!xen_initial_domain() || acpi_disabled)
  129. return 0;
  130. return bus_register_notifier(&platform_bus_type, &platform_device_nb);
  131. }
  132. arch_initcall(register_xen_platform_notifier);
  133. #ifdef CONFIG_ARM_AMBA
  134. #include <linux/amba/bus.h>
  135. static int xen_amba_notifier(struct notifier_block *nb,
  136. unsigned long action, void *data)
  137. {
  138. struct amba_device *adev = to_amba_device(data);
  139. int r = 0;
  140. switch (action) {
  141. case BUS_NOTIFY_ADD_DEVICE:
  142. r = xen_map_device_mmio(&adev->res, 1);
  143. break;
  144. case BUS_NOTIFY_DEL_DEVICE:
  145. r = xen_unmap_device_mmio(&adev->res, 1);
  146. break;
  147. default:
  148. return NOTIFY_DONE;
  149. }
  150. if (r)
  151. dev_err(&adev->dev, "AMBA: Failed to %s device %s MMIO!\n",
  152. action == BUS_NOTIFY_ADD_DEVICE ? "map" :
  153. (action == BUS_NOTIFY_DEL_DEVICE ? "unmap" : "?"),
  154. adev->dev.init_name);
  155. return NOTIFY_OK;
  156. }
  157. static struct notifier_block amba_device_nb = {
  158. .notifier_call = xen_amba_notifier,
  159. };
  160. static int __init register_xen_amba_notifier(void)
  161. {
  162. if (!xen_initial_domain() || acpi_disabled)
  163. return 0;
  164. return bus_register_notifier(&amba_bustype, &amba_device_nb);
  165. }
  166. arch_initcall(register_xen_amba_notifier);
  167. #endif