]>
Commit | Line | Data |
---|---|---|
1299b0e0 HC |
1 | #include <linux/mm.h> |
2 | #include <linux/init.h> | |
3 | #include <linux/dma-mapping.h> | |
4 | #include <linux/scatterlist.h> | |
5 | #include <linux/swiotlb.h> | |
6 | #include <linux/bootmem.h> | |
7 | ||
8 | #include <asm/bootinfo.h> | |
9 | #include <boot_param.h> | |
10 | #include <dma-coherence.h> | |
11 | ||
12 | static void *loongson_dma_alloc_coherent(struct device *dev, size_t size, | |
00085f1e | 13 | dma_addr_t *dma_handle, gfp_t gfp, unsigned long attrs) |
1299b0e0 HC |
14 | { |
15 | void *ret; | |
16 | ||
1299b0e0 HC |
17 | /* ignore region specifiers */ |
18 | gfp &= ~(__GFP_DMA | __GFP_DMA32 | __GFP_HIGHMEM); | |
19 | ||
72d1cfc9 AB |
20 | if ((IS_ENABLED(CONFIG_ISA) && dev == NULL) || |
21 | (IS_ENABLED(CONFIG_ZONE_DMA) && | |
22 | dev->coherent_dma_mask < DMA_BIT_MASK(32))) | |
1299b0e0 | 23 | gfp |= __GFP_DMA; |
72d1cfc9 AB |
24 | else if (IS_ENABLED(CONFIG_ZONE_DMA32) && |
25 | dev->coherent_dma_mask < DMA_BIT_MASK(40)) | |
1299b0e0 | 26 | gfp |= __GFP_DMA32; |
72d1cfc9 | 27 | |
1299b0e0 HC |
28 | gfp |= __GFP_NORETRY; |
29 | ||
30 | ret = swiotlb_alloc_coherent(dev, size, dma_handle, gfp); | |
31 | mb(); | |
32 | return ret; | |
33 | } | |
34 | ||
35 | static void loongson_dma_free_coherent(struct device *dev, size_t size, | |
00085f1e | 36 | void *vaddr, dma_addr_t dma_handle, unsigned long attrs) |
1299b0e0 | 37 | { |
1299b0e0 HC |
38 | swiotlb_free_coherent(dev, size, vaddr, dma_handle); |
39 | } | |
40 | ||
41 | static dma_addr_t loongson_dma_map_page(struct device *dev, struct page *page, | |
42 | unsigned long offset, size_t size, | |
43 | enum dma_data_direction dir, | |
00085f1e | 44 | unsigned long attrs) |
1299b0e0 HC |
45 | { |
46 | dma_addr_t daddr = swiotlb_map_page(dev, page, offset, size, | |
47 | dir, attrs); | |
48 | mb(); | |
49 | return daddr; | |
50 | } | |
51 | ||
52 | static int loongson_dma_map_sg(struct device *dev, struct scatterlist *sg, | |
53 | int nents, enum dma_data_direction dir, | |
00085f1e | 54 | unsigned long attrs) |
1299b0e0 | 55 | { |
9f318d47 | 56 | int r = swiotlb_map_sg_attrs(dev, sg, nents, dir, attrs); |
1299b0e0 HC |
57 | mb(); |
58 | ||
59 | return r; | |
60 | } | |
61 | ||
62 | static void loongson_dma_sync_single_for_device(struct device *dev, | |
63 | dma_addr_t dma_handle, size_t size, | |
64 | enum dma_data_direction dir) | |
65 | { | |
66 | swiotlb_sync_single_for_device(dev, dma_handle, size, dir); | |
67 | mb(); | |
68 | } | |
69 | ||
70 | static void loongson_dma_sync_sg_for_device(struct device *dev, | |
71 | struct scatterlist *sg, int nents, | |
72 | enum dma_data_direction dir) | |
73 | { | |
74 | swiotlb_sync_sg_for_device(dev, sg, nents, dir); | |
75 | mb(); | |
76 | } | |
77 | ||
78 | static int loongson_dma_set_mask(struct device *dev, u64 mask) | |
79 | { | |
452e06af CH |
80 | if (!dev->dma_mask || !dma_supported(dev, mask)) |
81 | return -EIO; | |
82 | ||
1299b0e0 HC |
83 | if (mask > DMA_BIT_MASK(loongson_sysconf.dma_mask_bits)) { |
84 | *dev->dma_mask = DMA_BIT_MASK(loongson_sysconf.dma_mask_bits); | |
85 | return -EIO; | |
86 | } | |
87 | ||
88 | *dev->dma_mask = mask; | |
89 | ||
90 | return 0; | |
91 | } | |
92 | ||
93 | dma_addr_t phys_to_dma(struct device *dev, phys_addr_t paddr) | |
94 | { | |
f490682a HC |
95 | long nid; |
96 | #ifdef CONFIG_PHYS48_TO_HT40 | |
97 | /* We extract 2bit node id (bit 44~47, only bit 44~45 used now) from | |
98 | * Loongson-3's 48bit address space and embed it into 40bit */ | |
99 | nid = (paddr >> 44) & 0x3; | |
100 | paddr = ((nid << 44) ^ paddr) | (nid << 37); | |
101 | #endif | |
1299b0e0 HC |
102 | return paddr; |
103 | } | |
104 | ||
105 | phys_addr_t dma_to_phys(struct device *dev, dma_addr_t daddr) | |
106 | { | |
f490682a HC |
107 | long nid; |
108 | #ifdef CONFIG_PHYS48_TO_HT40 | |
109 | /* We extract 2bit node id (bit 44~47, only bit 44~45 used now) from | |
110 | * Loongson-3's 48bit address space and embed it into 40bit */ | |
111 | nid = (daddr >> 37) & 0x3; | |
112 | daddr = ((nid << 37) ^ daddr) | (nid << 44); | |
113 | #endif | |
1299b0e0 HC |
114 | return daddr; |
115 | } | |
116 | ||
117 | static struct dma_map_ops loongson_dma_map_ops = { | |
118 | .alloc = loongson_dma_alloc_coherent, | |
119 | .free = loongson_dma_free_coherent, | |
120 | .map_page = loongson_dma_map_page, | |
121 | .unmap_page = swiotlb_unmap_page, | |
122 | .map_sg = loongson_dma_map_sg, | |
123 | .unmap_sg = swiotlb_unmap_sg_attrs, | |
124 | .sync_single_for_cpu = swiotlb_sync_single_for_cpu, | |
125 | .sync_single_for_device = loongson_dma_sync_single_for_device, | |
126 | .sync_sg_for_cpu = swiotlb_sync_sg_for_cpu, | |
127 | .sync_sg_for_device = loongson_dma_sync_sg_for_device, | |
128 | .mapping_error = swiotlb_dma_mapping_error, | |
129 | .dma_supported = swiotlb_dma_supported, | |
130 | .set_dma_mask = loongson_dma_set_mask | |
131 | }; | |
132 | ||
133 | void __init plat_swiotlb_setup(void) | |
134 | { | |
135 | swiotlb_init(1); | |
136 | mips_dma_map_ops = &loongson_dma_map_ops; | |
137 | } |