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