Allow mappings for DMA backed buffers if grant table module supports such: this extends grant device to not only map buffers made of balloon pages, but also from buffers allocated with dma_alloc_xxx.
Unified · Split
| @@ -37,6 +37,9 @@ · 36 unmodified lines | ||
| 37 | 37 | #include <linux/slab.h> |
| 38 | 38 | #include <linux/highmem.h> |
| 39 | 39 | #include <linux/refcount.h> |
| 40 | +#ifdef CONFIG_XEN_GRANT_DMA_ALLOC | |
| 41 | +#include <linux/of_device.h> | |
| 42 | +#endif | |
| 40 | 43 | |
| 41 | 44 | #include <xen/xen.h> |
| 42 | 45 | #include <xen/grant_table.h> |
| @@ -72,6 +75,11 @@ struct gntdev_priv { · 29 unmodified lines | ||
| 72 | 75 | struct mutex lock; |
| 73 | 76 | struct mm_struct *mm; |
| 74 | 77 | struct mmu_notifier mn; |
| 78 | + | |
| 79 | +#ifdef CONFIG_XEN_GRANT_DMA_ALLOC | |
| 80 | + /* Device for which DMA memory is allocated. */ | |
| 81 | + struct device *dma_dev; | |
| 82 | +#endif | |
| 75 | 83 | }; |
| 76 | 84 | |
| 77 | 85 | struct unmap_notify { |
| @@ -96,10 +104,27 @@ struct grant_map { · 18 unmodified lines | ||
| 96 | 104 | struct gnttab_unmap_grant_ref *kunmap_ops; |
| 97 | 105 | struct page **pages; |
| 98 | 106 | unsigned long pages_vm_start; |
| 107 | + | |
| 108 | +#ifdef CONFIG_XEN_GRANT_DMA_ALLOC | |
| 109 | + /* | |
| 110 | + * If dmabuf_vaddr is not NULL then this mapping is backed by DMA | |
| 111 | + * capable memory. | |
| 112 | + */ | |
| 113 | + | |
| 114 | + struct device *dma_dev; | |
| 115 | + /* Flags used to create this DMA buffer: GNTDEV_DMA_FLAG_XXX. */ | |
| 116 | + int dma_flags; | |
| 117 | + void *dma_vaddr; | |
| 118 | + dma_addr_t dma_bus_addr; | |
| 119 | + /* Needed to avoid allocation in gnttab_dma_free_pages(). */ | |
| 120 | + xen_pfn_t *frames; | |
| 121 | +#endif | |
| 99 | 122 | }; |
| 100 | 123 | |
| 101 | 124 | static int unmap_grant_pages(struct grant_map *map, int offset, int pages); |
| 102 | 125 | |
| 126 | +static struct miscdevice gntdev_miscdev; | |
| 127 | + | |
| 103 | 128 | /* ------------------------------------------------------------------ */ |
| 104 | 129 | |
| 105 | 130 | static void gntdev_print_maps(struct gntdev_priv *priv, |
| @@ -121,8 +146,27 @@ static void gntdev_free_map(struct grant_map *map) · 15 unmodified lines | ||
| 121 | 146 | if (map == NULL) |
| 122 | 147 | return; |
| 123 | 148 | |
| 149 | +#ifdef CONFIG_XEN_GRANT_DMA_ALLOC | |
| 150 | + if (map->dma_vaddr) { | |
| 151 | + struct gnttab_dma_alloc_args args; | |
| 152 | + | |
| 153 | + args.dev = map->dma_dev; | |
| 154 | + args.coherent = !!(map->dma_flags & GNTDEV_DMA_FLAG_COHERENT); | |
| 155 | + args.nr_pages = map->count; | |
| 156 | + args.pages = map->pages; | |
| 157 | + args.frames = map->frames; | |
| 158 | + args.vaddr = map->dma_vaddr; | |
| 159 | + args.dev_bus_addr = map->dma_bus_addr; | |
| 160 | + | |
| 161 | + gnttab_dma_free_pages(&args); | |
| 162 | + } else | |
| 163 | +#endif | |
| 124 | 164 | if (map->pages) |
| 125 | 165 | gnttab_free_pages(map->count, map->pages); |
| 166 | + | |
| 167 | +#ifdef CONFIG_XEN_GRANT_DMA_ALLOC | |
| 168 | + kfree(map->frames); | |
| 169 | +#endif | |
| 126 | 170 | kfree(map->pages); |
| 127 | 171 | kfree(map->grants); |
| 128 | 172 | kfree(map->map_ops); |
| @@ -132,7 +176,8 @@ static void gntdev_free_map(struct grant_map *map) · 3 unmodified lines | ||
| 132 | 176 | kfree(map); |
| 133 | 177 | } |
| 134 | 178 | |
| 135 | −static struct grant_map *gntdev_alloc_map(struct gntdev_priv *priv, int count) | |
| 179 | +static struct grant_map *gntdev_alloc_map(struct gntdev_priv *priv, int count, | |
| 180 | + int dma_flags) | |
| 136 | 181 | { |
| 137 | 182 | struct grant_map *add; |
| 138 | 183 | int i; |
| @@ -155,6 +200,37 @@ static struct grant_map *gntdev_alloc_map(struct gntdev_priv *priv, int count) · 16 unmodified lines | ||
| 155 | 200 | NULL == add->pages) |
| 156 | 201 | goto err; |
| 157 | 202 | |
| 203 | +#ifdef CONFIG_XEN_GRANT_DMA_ALLOC | |
| 204 | + add->dma_flags = dma_flags; | |
| 205 | + | |
| 206 | + /* | |
| 207 | + * Check if this mapping is requested to be backed | |
| 208 | + * by a DMA buffer. | |
| 209 | + */ | |
| 210 | + if (dma_flags & (GNTDEV_DMA_FLAG_WC | GNTDEV_DMA_FLAG_COHERENT)) { | |
| 211 | + struct gnttab_dma_alloc_args args; | |
| 212 | + | |
| 213 | + add->frames = kcalloc(count, sizeof(add->frames[0]), | |
| 214 | + GFP_KERNEL); | |
| 215 | + if (!add->frames) | |
| 216 | + goto err; | |
| 217 | + | |
| 218 | + /* Remember the device, so we can free DMA memory. */ | |
| 219 | + add->dma_dev = priv->dma_dev; | |
| 220 | + | |
| 221 | + args.dev = priv->dma_dev; | |
| 222 | + args.coherent = !!(dma_flags & GNTDEV_DMA_FLAG_COHERENT); | |
| 223 | + args.nr_pages = count; | |
| 224 | + args.pages = add->pages; | |
| 225 | + args.frames = add->frames; | |
| 226 | + | |
| 227 | + if (gnttab_dma_alloc_pages(&args)) | |
| 228 | + goto err; | |
| 229 | + | |
| 230 | + add->dma_vaddr = args.vaddr; | |
| 231 | + add->dma_bus_addr = args.dev_bus_addr; | |
| 232 | + } else | |
| 233 | +#endif | |
| 158 | 234 | if (gnttab_alloc_pages(count, add->pages)) |
| 159 | 235 | goto err; |
| 160 | 236 | |
| @@ -325,6 +401,14 @@ static int map_grant_pages(struct grant_map *map) · 164 unmodified lines | ||
| 325 | 401 | map->unmap_ops[i].handle = map->map_ops[i].handle; |
| 326 | 402 | if (use_ptemod) |
| 327 | 403 | map->kunmap_ops[i].handle = map->kmap_ops[i].handle; |
| 404 | +#ifdef CONFIG_XEN_GRANT_DMA_ALLOC | |
| 405 | + else if (map->dma_vaddr) { | |
| 406 | + unsigned long bfn; | |
| 407 | + | |
| 408 | + bfn = pfn_to_bfn(page_to_pfn(map->pages[i])); | |
| 409 | + map->unmap_ops[i].dev_bus_addr = __pfn_to_phys(bfn); | |
| 410 | + } | |
| 411 | +#endif | |
| 328 | 412 | } |
| 329 | 413 | return err; |
| 330 | 414 | } |
| @@ -548,6 +632,17 @@ static int gntdev_open(struct inode *inode, struct file *flip) · 217 unmodified lines | ||
| 548 | 632 | } |
| 549 | 633 | |
| 550 | 634 | flip->private_data = priv; |
| 635 | +#ifdef CONFIG_XEN_GRANT_DMA_ALLOC | |
| 636 | + priv->dma_dev = gntdev_miscdev.this_device; | |
| 637 | + | |
| 638 | + /* | |
| 639 | + * The device is not spawn from a device tree, so arch_setup_dma_ops | |
| 640 | + * is not called, thus leaving the device with dummy DMA ops. | |
| 641 | + * Fix this by calling of_dma_configure() with a NULL node to set | |
| 642 | + * default DMA ops. | |
| 643 | + */ | |
| 644 | + of_dma_configure(priv->dma_dev, NULL, true); | |
| 645 | +#endif | |
| 551 | 646 | pr_debug("priv %p\n", priv); |
| 552 | 647 | |
| 553 | 648 | return 0; |
| @@ -589,7 +684,7 @@ static long gntdev_ioctl_map_grant_ref(struct gntdev_priv *priv, · 35 unmodified lines | ||
| 589 | 684 | return -EINVAL; |
| 590 | 685 | |
| 591 | 686 | err = -ENOMEM; |
| 592 | − map = gntdev_alloc_map(priv, op.count); | |
| 687 | + map = gntdev_alloc_map(priv, op.count, 0 /* This is not a dma-buf. */); | |
| 593 | 688 | if (!map) |
| 594 | 689 | return err; |
| 595 | 690 | |
| @@ -200,4 +200,19 @@ struct ioctl_gntdev_grant_copy { · 199 unmodified lines | ||
| 200 | 200 | /* Send an interrupt on the indicated event channel */ |
| 201 | 201 | #define UNMAP_NOTIFY_SEND_EVENT 0x2 |
| 202 | 202 | |
| 203 | +/* | |
| 204 | + * Flags to be used while requesting memory mapping's backing storage | |
| 205 | + * to be allocated with DMA API. | |
| 206 | + */ | |
| 207 | + | |
| 208 | +/* | |
| 209 | + * The buffer is backed with memory allocated with dma_alloc_wc. | |
| 210 | + */ | |
| 211 | +#define GNTDEV_DMA_FLAG_WC (1 << 0) | |
| 212 | + | |
| 213 | +/* | |
| 214 | + * The buffer is backed with memory allocated with dma_alloc_coherent. | |
| 215 | + */ | |
| 216 | +#define GNTDEV_DMA_FLAG_COHERENT (1 << 1) | |
| 217 | + | |
| 203 | 218 | #endif /* __LINUX_PUBLIC_GNTDEV_H__ */ |