summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorOleksandr Andrushchenko <oleksandr_andrushchenko@epam.com>2018-07-20 05:01:45 -0400
committerBoris Ostrovsky <boris.ostrovsky@oracle.com>2018-07-26 23:05:14 -0400
commit9bdc7304f536f3f77f0a69e7c3a8f5afda561a68 (patch)
treeb2d1da458c919c4e78b6f3cb65a89f8cce15cd45
parentae4c51a50c990d6feba7058c181dc8f22ca5f1d8 (diff)
xen/grant-table: Allow allocating buffers suitable for DMA
Extend grant table module API to allow allocating buffers that can be used for DMA operations and mapping foreign grant references on top of those. The resulting buffer is similar to the one allocated by the balloon driver in that proper memory reservation is made by ({increase|decrease}_reservation and VA mappings are updated if needed). This is useful for sharing foreign buffers with HW drivers which cannot work with scattered buffers provided by the balloon driver, but require DMAable memory instead. Signed-off-by: Oleksandr Andrushchenko <oleksandr_andrushchenko@epam.com> Reviewed-by: Boris Ostrovsky <boris.ostrovsky@oracle.com> Signed-off-by: Boris Ostrovsky <boris.ostrovsky@oracle.com>
-rw-r--r--drivers/xen/Kconfig14
-rw-r--r--drivers/xen/grant-table.c97
-rw-r--r--include/xen/grant_table.h18
3 files changed, 129 insertions, 0 deletions
diff --git a/drivers/xen/Kconfig b/drivers/xen/Kconfig
index e5d0c28372ea..75e5c40f80a5 100644
--- a/drivers/xen/Kconfig
+++ b/drivers/xen/Kconfig
@@ -161,6 +161,20 @@ config XEN_GRANT_DEV_ALLOC
161 to other domains. This can be used to implement frontend drivers 161 to other domains. This can be used to implement frontend drivers
162 or as part of an inter-domain shared memory channel. 162 or as part of an inter-domain shared memory channel.
163 163
164config XEN_GRANT_DMA_ALLOC
165 bool "Allow allocating DMA capable buffers with grant reference module"
166 depends on XEN && HAS_DMA
167 help
168 Extends grant table module API to allow allocating DMA capable
169 buffers and mapping foreign grant references on top of it.
170 The resulting buffer is similar to one allocated by the balloon
171 driver in that proper memory reservation is made by
172 ({increase|decrease}_reservation and VA mappings are updated if
173 needed).
174 This is useful for sharing foreign buffers with HW drivers which
175 cannot work with scattered buffers provided by the balloon driver,
176 but require DMAable memory instead.
177
164config SWIOTLB_XEN 178config SWIOTLB_XEN
165 def_bool y 179 def_bool y
166 select SWIOTLB 180 select SWIOTLB
diff --git a/drivers/xen/grant-table.c b/drivers/xen/grant-table.c
index bb4840653bf2..7bafa703a992 100644
--- a/drivers/xen/grant-table.c
+++ b/drivers/xen/grant-table.c
@@ -45,6 +45,9 @@
45#include <linux/workqueue.h> 45#include <linux/workqueue.h>
46#include <linux/ratelimit.h> 46#include <linux/ratelimit.h>
47#include <linux/moduleparam.h> 47#include <linux/moduleparam.h>
48#ifdef CONFIG_XEN_GRANT_DMA_ALLOC
49#include <linux/dma-mapping.h>
50#endif
48 51
49#include <xen/xen.h> 52#include <xen/xen.h>
50#include <xen/interface/xen.h> 53#include <xen/interface/xen.h>
@@ -57,6 +60,7 @@
57#ifdef CONFIG_X86 60#ifdef CONFIG_X86
58#include <asm/xen/cpuid.h> 61#include <asm/xen/cpuid.h>
59#endif 62#endif
63#include <xen/mem-reservation.h>
60#include <asm/xen/hypercall.h> 64#include <asm/xen/hypercall.h>
61#include <asm/xen/interface.h> 65#include <asm/xen/interface.h>
62 66
@@ -838,6 +842,99 @@ void gnttab_free_pages(int nr_pages, struct page **pages)
838} 842}
839EXPORT_SYMBOL_GPL(gnttab_free_pages); 843EXPORT_SYMBOL_GPL(gnttab_free_pages);
840 844
845#ifdef CONFIG_XEN_GRANT_DMA_ALLOC
846/**
847 * gnttab_dma_alloc_pages - alloc DMAable pages suitable for grant mapping into
848 * @args: arguments to the function
849 */
850int gnttab_dma_alloc_pages(struct gnttab_dma_alloc_args *args)
851{
852 unsigned long pfn, start_pfn;
853 size_t size;
854 int i, ret;
855
856 size = args->nr_pages << PAGE_SHIFT;
857 if (args->coherent)
858 args->vaddr = dma_alloc_coherent(args->dev, size,
859 &args->dev_bus_addr,
860 GFP_KERNEL | __GFP_NOWARN);
861 else
862 args->vaddr = dma_alloc_wc(args->dev, size,
863 &args->dev_bus_addr,
864 GFP_KERNEL | __GFP_NOWARN);
865 if (!args->vaddr) {
866 pr_debug("Failed to allocate DMA buffer of size %zu\n", size);
867 return -ENOMEM;
868 }
869
870 start_pfn = __phys_to_pfn(args->dev_bus_addr);
871 for (pfn = start_pfn, i = 0; pfn < start_pfn + args->nr_pages;
872 pfn++, i++) {
873 struct page *page = pfn_to_page(pfn);
874
875 args->pages[i] = page;
876 args->frames[i] = xen_page_to_gfn(page);
877 xenmem_reservation_scrub_page(page);
878 }
879
880 xenmem_reservation_va_mapping_reset(args->nr_pages, args->pages);
881
882 ret = xenmem_reservation_decrease(args->nr_pages, args->frames);
883 if (ret != args->nr_pages) {
884 pr_debug("Failed to decrease reservation for DMA buffer\n");
885 ret = -EFAULT;
886 goto fail;
887 }
888
889 ret = gnttab_pages_set_private(args->nr_pages, args->pages);
890 if (ret < 0)
891 goto fail;
892
893 return 0;
894
895fail:
896 gnttab_dma_free_pages(args);
897 return ret;
898}
899EXPORT_SYMBOL_GPL(gnttab_dma_alloc_pages);
900
901/**
902 * gnttab_dma_free_pages - free DMAable pages
903 * @args: arguments to the function
904 */
905int gnttab_dma_free_pages(struct gnttab_dma_alloc_args *args)
906{
907 size_t size;
908 int i, ret;
909
910 gnttab_pages_clear_private(args->nr_pages, args->pages);
911
912 for (i = 0; i < args->nr_pages; i++)
913 args->frames[i] = page_to_xen_pfn(args->pages[i]);
914
915 ret = xenmem_reservation_increase(args->nr_pages, args->frames);
916 if (ret != args->nr_pages) {
917 pr_debug("Failed to decrease reservation for DMA buffer\n");
918 ret = -EFAULT;
919 } else {
920 ret = 0;
921 }
922
923 xenmem_reservation_va_mapping_update(args->nr_pages, args->pages,
924 args->frames);
925
926 size = args->nr_pages << PAGE_SHIFT;
927 if (args->coherent)
928 dma_free_coherent(args->dev, size,
929 args->vaddr, args->dev_bus_addr);
930 else
931 dma_free_wc(args->dev, size,
932 args->vaddr, args->dev_bus_addr);
933 return ret;
934}
935EXPORT_SYMBOL_GPL(gnttab_dma_free_pages);
936#endif
937
841/* Handling of paged out grant targets (GNTST_eagain) */ 938/* Handling of paged out grant targets (GNTST_eagain) */
842#define MAX_DELAY 256 939#define MAX_DELAY 256
843static inline void 940static inline void
diff --git a/include/xen/grant_table.h b/include/xen/grant_table.h
index de03f2542bb7..9bc5bc07d4d3 100644
--- a/include/xen/grant_table.h
+++ b/include/xen/grant_table.h
@@ -198,6 +198,24 @@ void gnttab_free_auto_xlat_frames(void);
198int gnttab_alloc_pages(int nr_pages, struct page **pages); 198int gnttab_alloc_pages(int nr_pages, struct page **pages);
199void gnttab_free_pages(int nr_pages, struct page **pages); 199void gnttab_free_pages(int nr_pages, struct page **pages);
200 200
201#ifdef CONFIG_XEN_GRANT_DMA_ALLOC
202struct gnttab_dma_alloc_args {
203 /* Device for which DMA memory will be/was allocated. */
204 struct device *dev;
205 /* If set then DMA buffer is coherent and write-combine otherwise. */
206 bool coherent;
207
208 int nr_pages;
209 struct page **pages;
210 xen_pfn_t *frames;
211 void *vaddr;
212 dma_addr_t dev_bus_addr;
213};
214
215int gnttab_dma_alloc_pages(struct gnttab_dma_alloc_args *args);
216int gnttab_dma_free_pages(struct gnttab_dma_alloc_args *args);
217#endif
218
201int gnttab_pages_set_private(int nr_pages, struct page **pages); 219int gnttab_pages_set_private(int nr_pages, struct page **pages);
202void gnttab_pages_clear_private(int nr_pages, struct page **pages); 220void gnttab_pages_clear_private(int nr_pages, struct page **pages);
203 221