Merge branch develop-3.10
[firefly-linux-kernel-4.4.55.git] / drivers / iommu / rockchip-iovmm.c
1 /*
2  * This program is free software; you can redistribute it and/or modify
3  * it under the terms of the GNU General Public License version 2 as
4  * published by the Free Software Foundation.
5  */
6
7 #ifdef CONFIG_ROCKCHIP_IOMMU_DEBUG
8 #define DEBUG
9 #endif
10
11 #include <linux/kernel.h>
12 #include <linux/hardirq.h>
13 #include <linux/slab.h>
14 #include <linux/scatterlist.h>
15 #include <linux/err.h>
16
17 #include <linux/of.h>
18 #include <linux/of_platform.h>
19
20 #include "rockchip-iommu.h"
21
22 static struct rk_vm_region *find_region(struct rk_iovmm *vmm, dma_addr_t iova)
23 {
24         struct rk_vm_region *region;
25
26         list_for_each_entry(region, &vmm->regions_list, node)
27                 if (region->start == iova)
28                         return region;
29
30         return NULL;
31 }
32
33 void rockchip_iovmm_set_fault_handler(struct device *dev,
34                                        rockchip_iommu_fault_handler_t handler)
35 {
36         return;
37 }
38
39 int rockchip_iovmm_activate(struct device *dev)
40 {
41         struct rk_iovmm *vmm = rockchip_get_iovmm(dev);
42
43         return iommu_attach_device(vmm->domain, dev);
44 }
45
46 void rockchip_iovmm_deactivate(struct device *dev)
47 {
48         struct rk_iovmm *vmm = rockchip_get_iovmm(dev);
49
50         iommu_detach_device(vmm->domain, dev);
51 }
52
53 dma_addr_t rockchip_iovmm_map(struct device *dev,
54         struct scatterlist *sg, off_t offset, size_t size)
55 {
56         off_t start_off;
57         dma_addr_t addr, start = 0;
58         size_t mapped_size = 0;
59         struct rk_vm_region *region;
60         struct rk_iovmm *vmm = rockchip_get_iovmm(dev);
61         int order;
62         int ret;
63         
64         for (; sg_dma_len(sg) < offset; sg = sg_next(sg))
65                 offset -= sg_dma_len(sg);
66
67         start_off = offset_in_page(sg_phys(sg) + offset);
68         size = PAGE_ALIGN(size + start_off);
69
70         order = __fls(min_t(size_t, size, SZ_1M));
71
72         region = kmalloc(sizeof(*region), GFP_KERNEL);
73         if (!region) {
74                 ret = -ENOMEM;
75                 goto err_map_nomem;
76         }
77
78         start = (dma_addr_t)gen_pool_alloc(vmm->vmm_pool, size);
79         if (!start) {
80                 ret = -ENOMEM;
81                 goto err_map_noiomem;
82         }
83
84         pr_debug("%s: size = %zx\n", __func__, size);
85
86         addr = start;
87         do {
88                 phys_addr_t phys;
89                 size_t len;
90
91                 phys = sg_phys(sg);
92                 len = sg_dma_len(sg);
93
94                 /* if back to back sg entries are contiguous consolidate them */
95                 while (sg_next(sg) && sg_phys(sg) +
96                        sg_dma_len(sg) == sg_phys(sg_next(sg))) {
97                         len += sg_dma_len(sg_next(sg));
98                         sg = sg_next(sg);
99                 }
100
101                 if (offset > 0) {
102                         len -= offset;
103                         phys += offset;
104                         offset = 0;
105                 }
106
107                 if (offset_in_page(phys)) {
108                         len += offset_in_page(phys);
109                         phys = round_down(phys, PAGE_SIZE);
110                 }
111
112                 len = PAGE_ALIGN(len);
113
114                 if (len > (size - mapped_size))
115                         len = size - mapped_size;
116                 pr_debug("addr = %pad, phys = %pa, len = %zx\n", &addr, &phys, len);
117                 ret = iommu_map(vmm->domain, addr, phys, len, 0);
118                 if (ret)
119                         break;
120
121                 addr += len;
122                 mapped_size += len;
123         } while ((sg = sg_next(sg)) && (mapped_size < size));
124
125         BUG_ON(mapped_size > size);
126
127         if (mapped_size < size)
128                 goto err_map_map;
129
130         region->start = start + start_off;
131         region->size = size;
132
133         INIT_LIST_HEAD(&region->node);
134
135         spin_lock(&vmm->lock);
136
137         list_add(&region->node, &vmm->regions_list);
138
139         spin_unlock(&vmm->lock);
140
141         ret = rockchip_iommu_tlb_invalidate(dev);
142         if (ret)
143                 goto err_map_map;
144
145         dev_dbg(dev->archdata.iommu, "IOVMM: Allocated VM region @ %pad%#zx bytes.\n",
146         &region->start, region->size);
147         
148         return region->start;
149
150 err_map_map:
151         iommu_unmap(vmm->domain, start, mapped_size);
152         gen_pool_free(vmm->vmm_pool, start, size);
153 err_map_noiomem:
154         kfree(region);
155 err_map_nomem:
156         dev_err(dev->archdata.iommu, "IOVMM: Failed to allocated VM region for %zx bytes.\n", size);
157         return (dma_addr_t)ret;
158 }
159
160 void rockchip_iovmm_unmap(struct device *dev, dma_addr_t iova)
161 {
162         struct rk_vm_region *region;
163         struct rk_iovmm *vmm = rockchip_get_iovmm(dev);
164         size_t unmapped_size;
165
166         /* This function must not be called in IRQ handlers */
167         BUG_ON(in_irq());
168
169         spin_lock(&vmm->lock);
170
171         region = find_region(vmm, iova);
172         if (WARN_ON(!region)) {
173                 spin_unlock(&vmm->lock);
174                 return;
175         }
176
177         list_del(&region->node);
178
179         spin_unlock(&vmm->lock);
180
181         region->start = round_down(region->start, PAGE_SIZE);
182
183         unmapped_size = iommu_unmap(vmm->domain,
184                                     region->start, region->size);
185         /*
186         rockchip_iommu_tlb_invalidate(dev);
187         */
188         gen_pool_free(vmm->vmm_pool, region->start, region->size);
189
190         WARN_ON(unmapped_size != region->size);
191         
192         dev_dbg(dev->archdata.iommu, "IOVMM: Unmapped %zx bytes from %pad.\n",
193                 unmapped_size, &region->start);
194         
195         kfree(region);
196 }
197
198 int rockchip_iovmm_map_oto(struct device *dev, phys_addr_t phys, size_t size)
199 {
200         struct rk_vm_region *region;
201         struct rk_iovmm *vmm = rockchip_get_iovmm(dev);
202         int ret;
203
204         if (WARN_ON((phys + size) >= IOVA_START)) {
205                 dev_err(dev->archdata.iommu, "Unable to create one to one mapping for %zx @ %pa\n",
206                        size, &phys);
207                 return -EINVAL;
208         }
209
210         region = kmalloc(sizeof(*region), GFP_KERNEL);
211         if (!region)
212                 return -ENOMEM;
213
214         if (WARN_ON(phys & ~PAGE_MASK))
215                 phys = round_down(phys, PAGE_SIZE);
216
217
218         ret = iommu_map(vmm->domain, (dma_addr_t)phys, phys, size, 0);
219         if (ret < 0) {
220                 kfree(region);
221                 return ret;
222         }
223
224         region->start = (dma_addr_t)phys;
225         region->size = size;
226         INIT_LIST_HEAD(&region->node);
227
228         spin_lock(&vmm->lock);
229
230         list_add(&region->node, &vmm->regions_list);
231
232         spin_unlock(&vmm->lock);
233
234         ret = rockchip_iommu_tlb_invalidate(dev);
235         if (ret)
236                 return ret;
237
238         return 0;
239 }
240
241 void rockchip_iovmm_unmap_oto(struct device *dev, phys_addr_t phys)
242 {
243         struct rk_vm_region *region;
244         struct rk_iovmm *vmm = rockchip_get_iovmm(dev);
245         size_t unmapped_size;
246
247         /* This function must not be called in IRQ handlers */
248         BUG_ON(in_irq());
249
250         if (WARN_ON(phys & ~PAGE_MASK))
251                 phys = round_down(phys, PAGE_SIZE);
252
253         spin_lock(&vmm->lock);
254
255         region = find_region(vmm, (dma_addr_t)phys);
256         if (WARN_ON(!region)) {
257                 spin_unlock(&vmm->lock);
258                 return;
259         }
260
261         list_del(&region->node);
262
263         spin_unlock(&vmm->lock);
264
265         unmapped_size = iommu_unmap(vmm->domain, region->start, region->size);
266         WARN_ON(unmapped_size != region->size);
267         dev_dbg(dev->archdata.iommu, "IOVMM: Unmapped %zx bytes from %pad.\n",
268                unmapped_size, &region->start);
269
270         kfree(region);
271 }
272
273 int rockchip_init_iovmm(struct device *iommu, struct rk_iovmm *vmm)
274 {
275         int ret = 0;
276
277         vmm->vmm_pool = gen_pool_create(PAGE_SHIFT, -1);
278         if (!vmm->vmm_pool) {
279                 ret = -ENOMEM;
280                 goto err_setup_genalloc;
281         }
282
283         /* (1GB - 4KB) addr space from 0x10000000 */
284         ret = gen_pool_add(vmm->vmm_pool, IOVA_START, IOVM_SIZE, -1);
285         if (ret)
286                 goto err_setup_domain;
287
288         vmm->domain = iommu_domain_alloc(&platform_bus_type);
289         if (!vmm->domain) {
290                 ret = -ENOMEM;
291                 goto err_setup_domain;
292         }
293
294         spin_lock_init(&vmm->lock);
295
296         INIT_LIST_HEAD(&vmm->regions_list);
297
298         dev_info(iommu, "IOVMM: Created %#x B IOVMM from %#x.\n",
299                 IOVM_SIZE, IOVA_START);
300         return 0;
301 err_setup_domain:
302         gen_pool_destroy(vmm->vmm_pool);
303 err_setup_genalloc:
304         dev_err(iommu, "IOVMM: Failed to create IOVMM (%d)\n", ret);
305
306         return ret;
307 }