Stefano Stabellini | 340720b | 2014-09-10 22:49:41 +0000 | [diff] [blame] | 1 | #include <linux/cpu.h> |
| 2 | #include <linux/dma-mapping.h> |
| 3 | #include <linux/gfp.h> |
| 4 | #include <linux/highmem.h> |
| 5 | |
| 6 | #include <xen/features.h> |
Stefano Stabellini | 2f91fc3 | 2014-11-11 14:31:56 +0000 | [diff] [blame] | 7 | enum dma_cache_op { |
| 8 | DMA_UNMAP, |
| 9 | DMA_MAP, |
| 10 | }; |
Stefano Stabellini | 340720b | 2014-09-10 22:49:41 +0000 | [diff] [blame] | 11 | |
| 12 | /* functions called by SWIOTLB */ |
| 13 | |
| 14 | static void dma_cache_maint(dma_addr_t handle, unsigned long offset, |
Stefano Stabellini | 2f91fc3 | 2014-11-11 14:31:56 +0000 | [diff] [blame] | 15 | size_t size, enum dma_data_direction dir, enum dma_cache_op op) |
Stefano Stabellini | 340720b | 2014-09-10 22:49:41 +0000 | [diff] [blame] | 16 | { |
| 17 | unsigned long pfn; |
| 18 | size_t left = size; |
| 19 | |
| 20 | pfn = (handle >> PAGE_SHIFT) + offset / PAGE_SIZE; |
| 21 | offset %= PAGE_SIZE; |
| 22 | |
| 23 | do { |
| 24 | size_t len = left; |
Stefano Stabellini | 340720b | 2014-09-10 22:49:41 +0000 | [diff] [blame] | 25 | |
Stefano Stabellini | 2f91fc3 | 2014-11-11 14:31:56 +0000 | [diff] [blame] | 26 | /* TODO: cache flush */ |
Stefano Stabellini | 340720b | 2014-09-10 22:49:41 +0000 | [diff] [blame] | 27 | |
| 28 | offset = 0; |
| 29 | pfn++; |
| 30 | left -= len; |
| 31 | } while (left); |
| 32 | } |
| 33 | |
| 34 | static void __xen_dma_page_dev_to_cpu(struct device *hwdev, dma_addr_t handle, |
| 35 | size_t size, enum dma_data_direction dir) |
| 36 | { |
Stefano Stabellini | 2f91fc3 | 2014-11-11 14:31:56 +0000 | [diff] [blame] | 37 | dma_cache_maint(handle & PAGE_MASK, handle & ~PAGE_MASK, size, dir, DMA_UNMAP); |
Stefano Stabellini | 340720b | 2014-09-10 22:49:41 +0000 | [diff] [blame] | 38 | } |
| 39 | |
| 40 | static void __xen_dma_page_cpu_to_dev(struct device *hwdev, dma_addr_t handle, |
| 41 | size_t size, enum dma_data_direction dir) |
| 42 | { |
Stefano Stabellini | 2f91fc3 | 2014-11-11 14:31:56 +0000 | [diff] [blame] | 43 | dma_cache_maint(handle & PAGE_MASK, handle & ~PAGE_MASK, size, dir, DMA_MAP); |
Stefano Stabellini | 340720b | 2014-09-10 22:49:41 +0000 | [diff] [blame] | 44 | } |
| 45 | |
Stefano Stabellini | 2f91fc3 | 2014-11-11 14:31:56 +0000 | [diff] [blame] | 46 | void __xen_dma_unmap_page(struct device *hwdev, dma_addr_t handle, |
Stefano Stabellini | 340720b | 2014-09-10 22:49:41 +0000 | [diff] [blame] | 47 | size_t size, enum dma_data_direction dir, |
| 48 | struct dma_attrs *attrs) |
| 49 | |
| 50 | { |
Stefano Stabellini | 2e2a781 | 2014-11-20 10:42:40 +0000 | [diff] [blame^] | 51 | if (is_device_dma_coherent(hwdev)) |
Stefano Stabellini | 340720b | 2014-09-10 22:49:41 +0000 | [diff] [blame] | 52 | return; |
| 53 | if (dma_get_attr(DMA_ATTR_SKIP_CPU_SYNC, attrs)) |
| 54 | return; |
| 55 | |
| 56 | __xen_dma_page_dev_to_cpu(hwdev, handle, size, dir); |
| 57 | } |
| 58 | |
Stefano Stabellini | 2f91fc3 | 2014-11-11 14:31:56 +0000 | [diff] [blame] | 59 | void __xen_dma_sync_single_for_cpu(struct device *hwdev, |
Stefano Stabellini | 340720b | 2014-09-10 22:49:41 +0000 | [diff] [blame] | 60 | dma_addr_t handle, size_t size, enum dma_data_direction dir) |
| 61 | { |
Stefano Stabellini | 2e2a781 | 2014-11-20 10:42:40 +0000 | [diff] [blame^] | 62 | if (is_device_dma_coherent(hwdev)) |
Stefano Stabellini | 340720b | 2014-09-10 22:49:41 +0000 | [diff] [blame] | 63 | return; |
| 64 | __xen_dma_page_dev_to_cpu(hwdev, handle, size, dir); |
| 65 | } |
| 66 | |
Stefano Stabellini | 2f91fc3 | 2014-11-11 14:31:56 +0000 | [diff] [blame] | 67 | void __xen_dma_sync_single_for_device(struct device *hwdev, |
Stefano Stabellini | 340720b | 2014-09-10 22:49:41 +0000 | [diff] [blame] | 68 | dma_addr_t handle, size_t size, enum dma_data_direction dir) |
| 69 | { |
Stefano Stabellini | 2e2a781 | 2014-11-20 10:42:40 +0000 | [diff] [blame^] | 70 | if (is_device_dma_coherent(hwdev)) |
Stefano Stabellini | 340720b | 2014-09-10 22:49:41 +0000 | [diff] [blame] | 71 | return; |
| 72 | __xen_dma_page_cpu_to_dev(hwdev, handle, size, dir); |
| 73 | } |
| 74 | |
| 75 | int __init xen_mm32_init(void) |
| 76 | { |
Stefano Stabellini | 340720b | 2014-09-10 22:49:41 +0000 | [diff] [blame] | 77 | if (!xen_initial_domain()) |
| 78 | return 0; |
| 79 | |
Stefano Stabellini | 340720b | 2014-09-10 22:49:41 +0000 | [diff] [blame] | 80 | return 0; |
| 81 | } |
| 82 | arch_initcall(xen_mm32_init); |