main.c 8.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350
  1. // SPDX-License-Identifier: GPL-2.0
  2. /*
  3. * Copyright (C) 2022-2023, Advanced Micro Devices, Inc.
  4. */
  5. #include <linux/vfio.h>
  6. #include <linux/cdx/cdx_bus.h>
  7. #include "private.h"
  8. static int vfio_cdx_open_device(struct vfio_device *core_vdev)
  9. {
  10. struct vfio_cdx_device *vdev =
  11. container_of(core_vdev, struct vfio_cdx_device, vdev);
  12. struct cdx_device *cdx_dev = to_cdx_device(core_vdev->dev);
  13. int count = cdx_dev->res_count;
  14. int i, ret;
  15. vdev->regions = kcalloc(count, sizeof(struct vfio_cdx_region),
  16. GFP_KERNEL_ACCOUNT);
  17. if (!vdev->regions)
  18. return -ENOMEM;
  19. for (i = 0; i < count; i++) {
  20. struct resource *res = &cdx_dev->res[i];
  21. vdev->regions[i].addr = res->start;
  22. vdev->regions[i].size = resource_size(res);
  23. vdev->regions[i].type = res->flags;
  24. /*
  25. * Only regions addressed with PAGE granularity may be
  26. * MMAP'ed securely.
  27. */
  28. if (!(vdev->regions[i].addr & ~PAGE_MASK) &&
  29. !(vdev->regions[i].size & ~PAGE_MASK))
  30. vdev->regions[i].flags |=
  31. VFIO_REGION_INFO_FLAG_MMAP;
  32. vdev->regions[i].flags |= VFIO_REGION_INFO_FLAG_READ;
  33. if (!(cdx_dev->res[i].flags & IORESOURCE_READONLY))
  34. vdev->regions[i].flags |= VFIO_REGION_INFO_FLAG_WRITE;
  35. }
  36. ret = cdx_dev_reset(core_vdev->dev);
  37. if (ret) {
  38. kfree(vdev->regions);
  39. vdev->regions = NULL;
  40. return ret;
  41. }
  42. ret = cdx_clear_master(cdx_dev);
  43. if (ret)
  44. vdev->flags &= ~BME_SUPPORT;
  45. else
  46. vdev->flags |= BME_SUPPORT;
  47. return 0;
  48. }
  49. static void vfio_cdx_close_device(struct vfio_device *core_vdev)
  50. {
  51. struct vfio_cdx_device *vdev =
  52. container_of(core_vdev, struct vfio_cdx_device, vdev);
  53. kfree(vdev->regions);
  54. cdx_dev_reset(core_vdev->dev);
  55. vfio_cdx_irqs_cleanup(vdev);
  56. }
  57. static int vfio_cdx_bm_ctrl(struct vfio_device *core_vdev, u32 flags,
  58. void __user *arg, size_t argsz)
  59. {
  60. size_t minsz =
  61. offsetofend(struct vfio_device_feature_bus_master, op);
  62. struct vfio_cdx_device *vdev =
  63. container_of(core_vdev, struct vfio_cdx_device, vdev);
  64. struct cdx_device *cdx_dev = to_cdx_device(core_vdev->dev);
  65. struct vfio_device_feature_bus_master ops;
  66. int ret;
  67. if (!(vdev->flags & BME_SUPPORT))
  68. return -ENOTTY;
  69. ret = vfio_check_feature(flags, argsz, VFIO_DEVICE_FEATURE_SET,
  70. sizeof(ops));
  71. if (ret != 1)
  72. return ret;
  73. if (copy_from_user(&ops, arg, minsz))
  74. return -EFAULT;
  75. switch (ops.op) {
  76. case VFIO_DEVICE_FEATURE_CLEAR_MASTER:
  77. return cdx_clear_master(cdx_dev);
  78. case VFIO_DEVICE_FEATURE_SET_MASTER:
  79. return cdx_set_master(cdx_dev);
  80. default:
  81. return -EINVAL;
  82. }
  83. }
  84. static int vfio_cdx_ioctl_feature(struct vfio_device *device, u32 flags,
  85. void __user *arg, size_t argsz)
  86. {
  87. switch (flags & VFIO_DEVICE_FEATURE_MASK) {
  88. case VFIO_DEVICE_FEATURE_BUS_MASTER:
  89. return vfio_cdx_bm_ctrl(device, flags, arg, argsz);
  90. default:
  91. return -ENOTTY;
  92. }
  93. }
  94. static int vfio_cdx_ioctl_get_info(struct vfio_cdx_device *vdev,
  95. struct vfio_device_info __user *arg)
  96. {
  97. unsigned long minsz = offsetofend(struct vfio_device_info, num_irqs);
  98. struct cdx_device *cdx_dev = to_cdx_device(vdev->vdev.dev);
  99. struct vfio_device_info info;
  100. if (copy_from_user(&info, arg, minsz))
  101. return -EFAULT;
  102. if (info.argsz < minsz)
  103. return -EINVAL;
  104. info.flags = VFIO_DEVICE_FLAGS_CDX;
  105. info.flags |= VFIO_DEVICE_FLAGS_RESET;
  106. info.num_regions = cdx_dev->res_count;
  107. info.num_irqs = cdx_dev->num_msi ? 1 : 0;
  108. return copy_to_user(arg, &info, minsz) ? -EFAULT : 0;
  109. }
  110. static int vfio_cdx_ioctl_get_region_info(struct vfio_cdx_device *vdev,
  111. struct vfio_region_info __user *arg)
  112. {
  113. unsigned long minsz = offsetofend(struct vfio_region_info, offset);
  114. struct cdx_device *cdx_dev = to_cdx_device(vdev->vdev.dev);
  115. struct vfio_region_info info;
  116. if (copy_from_user(&info, arg, minsz))
  117. return -EFAULT;
  118. if (info.argsz < minsz)
  119. return -EINVAL;
  120. if (info.index >= cdx_dev->res_count)
  121. return -EINVAL;
  122. /* map offset to the physical address */
  123. info.offset = vfio_cdx_index_to_offset(info.index);
  124. info.size = vdev->regions[info.index].size;
  125. info.flags = vdev->regions[info.index].flags;
  126. return copy_to_user(arg, &info, minsz) ? -EFAULT : 0;
  127. }
  128. static int vfio_cdx_ioctl_get_irq_info(struct vfio_cdx_device *vdev,
  129. struct vfio_irq_info __user *arg)
  130. {
  131. unsigned long minsz = offsetofend(struct vfio_irq_info, count);
  132. struct cdx_device *cdx_dev = to_cdx_device(vdev->vdev.dev);
  133. struct vfio_irq_info info;
  134. if (copy_from_user(&info, arg, minsz))
  135. return -EFAULT;
  136. if (info.argsz < minsz)
  137. return -EINVAL;
  138. if (info.index >= 1)
  139. return -EINVAL;
  140. if (!cdx_dev->num_msi)
  141. return -EINVAL;
  142. info.flags = VFIO_IRQ_INFO_EVENTFD | VFIO_IRQ_INFO_NORESIZE;
  143. info.count = cdx_dev->num_msi;
  144. return copy_to_user(arg, &info, minsz) ? -EFAULT : 0;
  145. }
  146. static int vfio_cdx_ioctl_set_irqs(struct vfio_cdx_device *vdev,
  147. struct vfio_irq_set __user *arg)
  148. {
  149. unsigned long minsz = offsetofend(struct vfio_irq_set, count);
  150. struct cdx_device *cdx_dev = to_cdx_device(vdev->vdev.dev);
  151. struct vfio_irq_set hdr;
  152. size_t data_size = 0;
  153. u8 *data = NULL;
  154. int ret = 0;
  155. if (copy_from_user(&hdr, arg, minsz))
  156. return -EFAULT;
  157. ret = vfio_set_irqs_validate_and_prepare(&hdr, cdx_dev->num_msi,
  158. 1, &data_size);
  159. if (ret)
  160. return ret;
  161. if (data_size) {
  162. data = memdup_user(arg->data, data_size);
  163. if (IS_ERR(data))
  164. return PTR_ERR(data);
  165. }
  166. ret = vfio_cdx_set_irqs_ioctl(vdev, hdr.flags, hdr.index,
  167. hdr.start, hdr.count, data);
  168. kfree(data);
  169. return ret;
  170. }
  171. static long vfio_cdx_ioctl(struct vfio_device *core_vdev,
  172. unsigned int cmd, unsigned long arg)
  173. {
  174. struct vfio_cdx_device *vdev =
  175. container_of(core_vdev, struct vfio_cdx_device, vdev);
  176. void __user *uarg = (void __user *)arg;
  177. switch (cmd) {
  178. case VFIO_DEVICE_GET_INFO:
  179. return vfio_cdx_ioctl_get_info(vdev, uarg);
  180. case VFIO_DEVICE_GET_REGION_INFO:
  181. return vfio_cdx_ioctl_get_region_info(vdev, uarg);
  182. case VFIO_DEVICE_GET_IRQ_INFO:
  183. return vfio_cdx_ioctl_get_irq_info(vdev, uarg);
  184. case VFIO_DEVICE_SET_IRQS:
  185. return vfio_cdx_ioctl_set_irqs(vdev, uarg);
  186. case VFIO_DEVICE_RESET:
  187. return cdx_dev_reset(core_vdev->dev);
  188. default:
  189. return -ENOTTY;
  190. }
  191. }
  192. static int vfio_cdx_mmap_mmio(struct vfio_cdx_region region,
  193. struct vm_area_struct *vma)
  194. {
  195. u64 size = vma->vm_end - vma->vm_start;
  196. u64 pgoff, base;
  197. pgoff = vma->vm_pgoff &
  198. ((1U << (VFIO_CDX_OFFSET_SHIFT - PAGE_SHIFT)) - 1);
  199. base = pgoff << PAGE_SHIFT;
  200. if (base + size > region.size)
  201. return -EINVAL;
  202. vma->vm_pgoff = (region.addr >> PAGE_SHIFT) + pgoff;
  203. vma->vm_page_prot = pgprot_device(vma->vm_page_prot);
  204. return io_remap_pfn_range(vma, vma->vm_start, vma->vm_pgoff,
  205. size, vma->vm_page_prot);
  206. }
  207. static int vfio_cdx_mmap(struct vfio_device *core_vdev,
  208. struct vm_area_struct *vma)
  209. {
  210. struct vfio_cdx_device *vdev =
  211. container_of(core_vdev, struct vfio_cdx_device, vdev);
  212. struct cdx_device *cdx_dev = to_cdx_device(core_vdev->dev);
  213. unsigned int index;
  214. index = vma->vm_pgoff >> (VFIO_CDX_OFFSET_SHIFT - PAGE_SHIFT);
  215. if (index >= cdx_dev->res_count)
  216. return -EINVAL;
  217. if (!(vdev->regions[index].flags & VFIO_REGION_INFO_FLAG_MMAP))
  218. return -EINVAL;
  219. if (!(vdev->regions[index].flags & VFIO_REGION_INFO_FLAG_READ) &&
  220. (vma->vm_flags & VM_READ))
  221. return -EPERM;
  222. if (!(vdev->regions[index].flags & VFIO_REGION_INFO_FLAG_WRITE) &&
  223. (vma->vm_flags & VM_WRITE))
  224. return -EPERM;
  225. return vfio_cdx_mmap_mmio(vdev->regions[index], vma);
  226. }
  227. static const struct vfio_device_ops vfio_cdx_ops = {
  228. .name = "vfio-cdx",
  229. .open_device = vfio_cdx_open_device,
  230. .close_device = vfio_cdx_close_device,
  231. .ioctl = vfio_cdx_ioctl,
  232. .device_feature = vfio_cdx_ioctl_feature,
  233. .mmap = vfio_cdx_mmap,
  234. .bind_iommufd = vfio_iommufd_physical_bind,
  235. .unbind_iommufd = vfio_iommufd_physical_unbind,
  236. .attach_ioas = vfio_iommufd_physical_attach_ioas,
  237. };
  238. static int vfio_cdx_probe(struct cdx_device *cdx_dev)
  239. {
  240. struct vfio_cdx_device *vdev;
  241. struct device *dev = &cdx_dev->dev;
  242. int ret;
  243. vdev = vfio_alloc_device(vfio_cdx_device, vdev, dev,
  244. &vfio_cdx_ops);
  245. if (IS_ERR(vdev))
  246. return PTR_ERR(vdev);
  247. ret = vfio_register_group_dev(&vdev->vdev);
  248. if (ret)
  249. goto out_uninit;
  250. dev_set_drvdata(dev, vdev);
  251. return 0;
  252. out_uninit:
  253. vfio_put_device(&vdev->vdev);
  254. return ret;
  255. }
  256. static int vfio_cdx_remove(struct cdx_device *cdx_dev)
  257. {
  258. struct device *dev = &cdx_dev->dev;
  259. struct vfio_cdx_device *vdev = dev_get_drvdata(dev);
  260. vfio_unregister_group_dev(&vdev->vdev);
  261. vfio_put_device(&vdev->vdev);
  262. return 0;
  263. }
  264. static const struct cdx_device_id vfio_cdx_table[] = {
  265. { CDX_DEVICE_DRIVER_OVERRIDE(CDX_ANY_ID, CDX_ANY_ID,
  266. CDX_ID_F_VFIO_DRIVER_OVERRIDE) }, /* match all by default */
  267. {}
  268. };
  269. MODULE_DEVICE_TABLE(cdx, vfio_cdx_table);
  270. static struct cdx_driver vfio_cdx_driver = {
  271. .probe = vfio_cdx_probe,
  272. .remove = vfio_cdx_remove,
  273. .match_id_table = vfio_cdx_table,
  274. .driver = {
  275. .name = "vfio-cdx",
  276. },
  277. .driver_managed_dma = true,
  278. };
  279. module_driver(vfio_cdx_driver, cdx_driver_register, cdx_driver_unregister);
  280. MODULE_LICENSE("GPL");
  281. MODULE_DESCRIPTION("VFIO for CDX devices - User Level meta-driver");
  282. MODULE_IMPORT_NS(CDX_BUS);