1 /*
2  * IOMMU for IPMMU/IPMMUI
3  * Copyright (C) 2012  Hideki EIRAKU
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; version 2 of the License.
8  */
9 
10 #include <linux/dma-mapping.h>
11 #include <linux/io.h>
12 #include <linux/iommu.h>
13 #include <linux/platform_device.h>
14 #include <linux/sizes.h>
15 #include <linux/slab.h>
16 #include <asm/dma-iommu.h>
17 #include "shmobile-ipmmu.h"
18 
19 #define L1_SIZE CONFIG_SHMOBILE_IOMMU_L1SIZE
20 #define L1_LEN (L1_SIZE / 4)
21 #define L1_ALIGN L1_SIZE
22 #define L2_SIZE SZ_1K
23 #define L2_LEN (L2_SIZE / 4)
24 #define L2_ALIGN L2_SIZE
25 
26 struct shmobile_iommu_domain_pgtable {
27 	uint32_t *pgtable;
28 	dma_addr_t handle;
29 };
30 
31 struct shmobile_iommu_archdata {
32 	struct list_head attached_list;
33 	struct dma_iommu_mapping *iommu_mapping;
34 	spinlock_t attach_lock;
35 	struct shmobile_iommu_domain *attached;
36 	int num_attached_devices;
37 	struct shmobile_ipmmu *ipmmu;
38 };
39 
40 struct shmobile_iommu_domain {
41 	struct shmobile_iommu_domain_pgtable l1, l2[L1_LEN];
42 	spinlock_t map_lock;
43 	spinlock_t attached_list_lock;
44 	struct list_head attached_list;
45 	struct iommu_domain domain;
46 };
47 
48 static struct shmobile_iommu_archdata *ipmmu_archdata;
49 static struct kmem_cache *l1cache, *l2cache;
50 
to_sh_domain(struct iommu_domain * dom)51 static struct shmobile_iommu_domain *to_sh_domain(struct iommu_domain *dom)
52 {
53 	return container_of(dom, struct shmobile_iommu_domain, domain);
54 }
55 
pgtable_alloc(struct shmobile_iommu_domain_pgtable * pgtable,struct kmem_cache * cache,size_t size)56 static int pgtable_alloc(struct shmobile_iommu_domain_pgtable *pgtable,
57 			 struct kmem_cache *cache, size_t size)
58 {
59 	pgtable->pgtable = kmem_cache_zalloc(cache, GFP_ATOMIC);
60 	if (!pgtable->pgtable)
61 		return -ENOMEM;
62 	pgtable->handle = dma_map_single(NULL, pgtable->pgtable, size,
63 					 DMA_TO_DEVICE);
64 	return 0;
65 }
66 
pgtable_free(struct shmobile_iommu_domain_pgtable * pgtable,struct kmem_cache * cache,size_t size)67 static void pgtable_free(struct shmobile_iommu_domain_pgtable *pgtable,
68 			 struct kmem_cache *cache, size_t size)
69 {
70 	dma_unmap_single(NULL, pgtable->handle, size, DMA_TO_DEVICE);
71 	kmem_cache_free(cache, pgtable->pgtable);
72 }
73 
pgtable_read(struct shmobile_iommu_domain_pgtable * pgtable,unsigned int index)74 static uint32_t pgtable_read(struct shmobile_iommu_domain_pgtable *pgtable,
75 			     unsigned int index)
76 {
77 	return pgtable->pgtable[index];
78 }
79 
pgtable_write(struct shmobile_iommu_domain_pgtable * pgtable,unsigned int index,unsigned int count,uint32_t val)80 static void pgtable_write(struct shmobile_iommu_domain_pgtable *pgtable,
81 			  unsigned int index, unsigned int count, uint32_t val)
82 {
83 	unsigned int i;
84 
85 	for (i = 0; i < count; i++)
86 		pgtable->pgtable[index + i] = val;
87 	dma_sync_single_for_device(NULL, pgtable->handle + index * sizeof(val),
88 				   sizeof(val) * count, DMA_TO_DEVICE);
89 }
90 
shmobile_iommu_domain_alloc(unsigned type)91 static struct iommu_domain *shmobile_iommu_domain_alloc(unsigned type)
92 {
93 	struct shmobile_iommu_domain *sh_domain;
94 	int i, ret;
95 
96 	if (type != IOMMU_DOMAIN_UNMANAGED)
97 		return NULL;
98 
99 	sh_domain = kzalloc(sizeof(*sh_domain), GFP_KERNEL);
100 	if (!sh_domain)
101 		return NULL;
102 	ret = pgtable_alloc(&sh_domain->l1, l1cache, L1_SIZE);
103 	if (ret < 0) {
104 		kfree(sh_domain);
105 		return NULL;
106 	}
107 	for (i = 0; i < L1_LEN; i++)
108 		sh_domain->l2[i].pgtable = NULL;
109 	spin_lock_init(&sh_domain->map_lock);
110 	spin_lock_init(&sh_domain->attached_list_lock);
111 	INIT_LIST_HEAD(&sh_domain->attached_list);
112 	return &sh_domain->domain;
113 }
114 
shmobile_iommu_domain_free(struct iommu_domain * domain)115 static void shmobile_iommu_domain_free(struct iommu_domain *domain)
116 {
117 	struct shmobile_iommu_domain *sh_domain = to_sh_domain(domain);
118 	int i;
119 
120 	for (i = 0; i < L1_LEN; i++) {
121 		if (sh_domain->l2[i].pgtable)
122 			pgtable_free(&sh_domain->l2[i], l2cache, L2_SIZE);
123 	}
124 	pgtable_free(&sh_domain->l1, l1cache, L1_SIZE);
125 	kfree(sh_domain);
126 }
127 
shmobile_iommu_attach_device(struct iommu_domain * domain,struct device * dev)128 static int shmobile_iommu_attach_device(struct iommu_domain *domain,
129 					struct device *dev)
130 {
131 	struct shmobile_iommu_archdata *archdata = dev->archdata.iommu;
132 	struct shmobile_iommu_domain *sh_domain = to_sh_domain(domain);
133 	int ret = -EBUSY;
134 
135 	if (!archdata)
136 		return -ENODEV;
137 	spin_lock(&sh_domain->attached_list_lock);
138 	spin_lock(&archdata->attach_lock);
139 	if (archdata->attached != sh_domain) {
140 		if (archdata->attached)
141 			goto err;
142 		ipmmu_tlb_set(archdata->ipmmu, sh_domain->l1.handle, L1_SIZE,
143 			      0);
144 		ipmmu_tlb_flush(archdata->ipmmu);
145 		archdata->attached = sh_domain;
146 		archdata->num_attached_devices = 0;
147 		list_add(&archdata->attached_list, &sh_domain->attached_list);
148 	}
149 	archdata->num_attached_devices++;
150 	ret = 0;
151 err:
152 	spin_unlock(&archdata->attach_lock);
153 	spin_unlock(&sh_domain->attached_list_lock);
154 	return ret;
155 }
156 
shmobile_iommu_detach_device(struct iommu_domain * domain,struct device * dev)157 static void shmobile_iommu_detach_device(struct iommu_domain *domain,
158 					 struct device *dev)
159 {
160 	struct shmobile_iommu_archdata *archdata = dev->archdata.iommu;
161 	struct shmobile_iommu_domain *sh_domain = to_sh_domain(domain);
162 
163 	if (!archdata)
164 		return;
165 	spin_lock(&sh_domain->attached_list_lock);
166 	spin_lock(&archdata->attach_lock);
167 	archdata->num_attached_devices--;
168 	if (!archdata->num_attached_devices) {
169 		ipmmu_tlb_set(archdata->ipmmu, 0, 0, 0);
170 		ipmmu_tlb_flush(archdata->ipmmu);
171 		archdata->attached = NULL;
172 		list_del(&archdata->attached_list);
173 	}
174 	spin_unlock(&archdata->attach_lock);
175 	spin_unlock(&sh_domain->attached_list_lock);
176 }
177 
domain_tlb_flush(struct shmobile_iommu_domain * sh_domain)178 static void domain_tlb_flush(struct shmobile_iommu_domain *sh_domain)
179 {
180 	struct shmobile_iommu_archdata *archdata;
181 
182 	spin_lock(&sh_domain->attached_list_lock);
183 	list_for_each_entry(archdata, &sh_domain->attached_list, attached_list)
184 		ipmmu_tlb_flush(archdata->ipmmu);
185 	spin_unlock(&sh_domain->attached_list_lock);
186 }
187 
l2alloc(struct shmobile_iommu_domain * sh_domain,unsigned int l1index)188 static int l2alloc(struct shmobile_iommu_domain *sh_domain,
189 		   unsigned int l1index)
190 {
191 	int ret;
192 
193 	if (!sh_domain->l2[l1index].pgtable) {
194 		ret = pgtable_alloc(&sh_domain->l2[l1index], l2cache, L2_SIZE);
195 		if (ret < 0)
196 			return ret;
197 	}
198 	pgtable_write(&sh_domain->l1, l1index, 1,
199 		      sh_domain->l2[l1index].handle | 0x1);
200 	return 0;
201 }
202 
l2realfree(struct shmobile_iommu_domain_pgtable * l2)203 static void l2realfree(struct shmobile_iommu_domain_pgtable *l2)
204 {
205 	if (l2->pgtable)
206 		pgtable_free(l2, l2cache, L2_SIZE);
207 }
208 
l2free(struct shmobile_iommu_domain * sh_domain,unsigned int l1index,struct shmobile_iommu_domain_pgtable * l2)209 static void l2free(struct shmobile_iommu_domain *sh_domain,
210 		   unsigned int l1index,
211 		   struct shmobile_iommu_domain_pgtable *l2)
212 {
213 	pgtable_write(&sh_domain->l1, l1index, 1, 0);
214 	if (sh_domain->l2[l1index].pgtable) {
215 		*l2 = sh_domain->l2[l1index];
216 		sh_domain->l2[l1index].pgtable = NULL;
217 	}
218 }
219 
shmobile_iommu_map(struct iommu_domain * domain,unsigned long iova,phys_addr_t paddr,size_t size,int prot)220 static int shmobile_iommu_map(struct iommu_domain *domain, unsigned long iova,
221 			      phys_addr_t paddr, size_t size, int prot)
222 {
223 	struct shmobile_iommu_domain_pgtable l2 = { .pgtable = NULL };
224 	struct shmobile_iommu_domain *sh_domain = to_sh_domain(domain);
225 	unsigned int l1index, l2index;
226 	int ret;
227 
228 	l1index = iova >> 20;
229 	switch (size) {
230 	case SZ_4K:
231 		l2index = (iova >> 12) & 0xff;
232 		spin_lock(&sh_domain->map_lock);
233 		ret = l2alloc(sh_domain, l1index);
234 		if (!ret)
235 			pgtable_write(&sh_domain->l2[l1index], l2index, 1,
236 				      paddr | 0xff2);
237 		spin_unlock(&sh_domain->map_lock);
238 		break;
239 	case SZ_64K:
240 		l2index = (iova >> 12) & 0xf0;
241 		spin_lock(&sh_domain->map_lock);
242 		ret = l2alloc(sh_domain, l1index);
243 		if (!ret)
244 			pgtable_write(&sh_domain->l2[l1index], l2index, 0x10,
245 				      paddr | 0xff1);
246 		spin_unlock(&sh_domain->map_lock);
247 		break;
248 	case SZ_1M:
249 		spin_lock(&sh_domain->map_lock);
250 		l2free(sh_domain, l1index, &l2);
251 		pgtable_write(&sh_domain->l1, l1index, 1, paddr | 0xc02);
252 		spin_unlock(&sh_domain->map_lock);
253 		ret = 0;
254 		break;
255 	default:
256 		ret = -EINVAL;
257 	}
258 	if (!ret)
259 		domain_tlb_flush(sh_domain);
260 	l2realfree(&l2);
261 	return ret;
262 }
263 
shmobile_iommu_unmap(struct iommu_domain * domain,unsigned long iova,size_t size)264 static size_t shmobile_iommu_unmap(struct iommu_domain *domain,
265 				   unsigned long iova, size_t size)
266 {
267 	struct shmobile_iommu_domain_pgtable l2 = { .pgtable = NULL };
268 	struct shmobile_iommu_domain *sh_domain = to_sh_domain(domain);
269 	unsigned int l1index, l2index;
270 	uint32_t l2entry = 0;
271 	size_t ret = 0;
272 
273 	l1index = iova >> 20;
274 	if (!(iova & 0xfffff) && size >= SZ_1M) {
275 		spin_lock(&sh_domain->map_lock);
276 		l2free(sh_domain, l1index, &l2);
277 		spin_unlock(&sh_domain->map_lock);
278 		ret = SZ_1M;
279 		goto done;
280 	}
281 	l2index = (iova >> 12) & 0xff;
282 	spin_lock(&sh_domain->map_lock);
283 	if (sh_domain->l2[l1index].pgtable)
284 		l2entry = pgtable_read(&sh_domain->l2[l1index], l2index);
285 	switch (l2entry & 3) {
286 	case 1:
287 		if (l2index & 0xf)
288 			break;
289 		pgtable_write(&sh_domain->l2[l1index], l2index, 0x10, 0);
290 		ret = SZ_64K;
291 		break;
292 	case 2:
293 		pgtable_write(&sh_domain->l2[l1index], l2index, 1, 0);
294 		ret = SZ_4K;
295 		break;
296 	}
297 	spin_unlock(&sh_domain->map_lock);
298 done:
299 	if (ret)
300 		domain_tlb_flush(sh_domain);
301 	l2realfree(&l2);
302 	return ret;
303 }
304 
shmobile_iommu_iova_to_phys(struct iommu_domain * domain,dma_addr_t iova)305 static phys_addr_t shmobile_iommu_iova_to_phys(struct iommu_domain *domain,
306 					       dma_addr_t iova)
307 {
308 	struct shmobile_iommu_domain *sh_domain = to_sh_domain(domain);
309 	uint32_t l1entry = 0, l2entry = 0;
310 	unsigned int l1index, l2index;
311 
312 	l1index = iova >> 20;
313 	l2index = (iova >> 12) & 0xff;
314 	spin_lock(&sh_domain->map_lock);
315 	if (sh_domain->l2[l1index].pgtable)
316 		l2entry = pgtable_read(&sh_domain->l2[l1index], l2index);
317 	else
318 		l1entry = pgtable_read(&sh_domain->l1, l1index);
319 	spin_unlock(&sh_domain->map_lock);
320 	switch (l2entry & 3) {
321 	case 1:
322 		return (l2entry & ~0xffff) | (iova & 0xffff);
323 	case 2:
324 		return (l2entry & ~0xfff) | (iova & 0xfff);
325 	default:
326 		if ((l1entry & 3) == 2)
327 			return (l1entry & ~0xfffff) | (iova & 0xfffff);
328 		return 0;
329 	}
330 }
331 
find_dev_name(struct shmobile_ipmmu * ipmmu,const char * dev_name)332 static int find_dev_name(struct shmobile_ipmmu *ipmmu, const char *dev_name)
333 {
334 	unsigned int i, n = ipmmu->num_dev_names;
335 
336 	for (i = 0; i < n; i++) {
337 		if (strcmp(ipmmu->dev_names[i], dev_name) == 0)
338 			return 1;
339 	}
340 	return 0;
341 }
342 
shmobile_iommu_add_device(struct device * dev)343 static int shmobile_iommu_add_device(struct device *dev)
344 {
345 	struct shmobile_iommu_archdata *archdata = ipmmu_archdata;
346 	struct dma_iommu_mapping *mapping;
347 
348 	if (!find_dev_name(archdata->ipmmu, dev_name(dev)))
349 		return 0;
350 	mapping = archdata->iommu_mapping;
351 	if (!mapping) {
352 		mapping = arm_iommu_create_mapping(&platform_bus_type, 0,
353 						   L1_LEN << 20);
354 		if (IS_ERR(mapping))
355 			return PTR_ERR(mapping);
356 		archdata->iommu_mapping = mapping;
357 	}
358 	dev->archdata.iommu = archdata;
359 	if (arm_iommu_attach_device(dev, mapping))
360 		pr_err("arm_iommu_attach_device failed\n");
361 	return 0;
362 }
363 
364 static const struct iommu_ops shmobile_iommu_ops = {
365 	.domain_alloc = shmobile_iommu_domain_alloc,
366 	.domain_free = shmobile_iommu_domain_free,
367 	.attach_dev = shmobile_iommu_attach_device,
368 	.detach_dev = shmobile_iommu_detach_device,
369 	.map = shmobile_iommu_map,
370 	.unmap = shmobile_iommu_unmap,
371 	.map_sg = default_iommu_map_sg,
372 	.iova_to_phys = shmobile_iommu_iova_to_phys,
373 	.add_device = shmobile_iommu_add_device,
374 	.pgsize_bitmap = SZ_1M | SZ_64K | SZ_4K,
375 };
376 
ipmmu_iommu_init(struct shmobile_ipmmu * ipmmu)377 int ipmmu_iommu_init(struct shmobile_ipmmu *ipmmu)
378 {
379 	static struct shmobile_iommu_archdata *archdata;
380 
381 	l1cache = kmem_cache_create("shmobile-iommu-pgtable1", L1_SIZE,
382 				    L1_ALIGN, SLAB_HWCACHE_ALIGN, NULL);
383 	if (!l1cache)
384 		return -ENOMEM;
385 	l2cache = kmem_cache_create("shmobile-iommu-pgtable2", L2_SIZE,
386 				    L2_ALIGN, SLAB_HWCACHE_ALIGN, NULL);
387 	if (!l2cache) {
388 		kmem_cache_destroy(l1cache);
389 		return -ENOMEM;
390 	}
391 	archdata = kzalloc(sizeof(*archdata), GFP_KERNEL);
392 	if (!archdata) {
393 		kmem_cache_destroy(l1cache);
394 		kmem_cache_destroy(l2cache);
395 		return -ENOMEM;
396 	}
397 	spin_lock_init(&archdata->attach_lock);
398 	archdata->ipmmu = ipmmu;
399 	ipmmu_archdata = archdata;
400 	bus_set_iommu(&platform_bus_type, &shmobile_iommu_ops);
401 	return 0;
402 }
403