blob: 82747744103b5088e189a858eb9e2c6af0f9de8a [file] [log] [blame]
Mitchel Humpherys42296fb2015-06-23 16:29:16 -07001/*
Mitchel Humpherys0fe337d2015-07-06 15:21:24 -07002 * Copyright (c) 2015-2016, The Linux Foundation. All rights reserved.
Mitchel Humpherys42296fb2015-06-23 16:29:16 -07003 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 and
6 * only version 2 as published by the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 */
14
15#define pr_fmt(fmt) "iommu-debug: %s: " fmt, __func__
16
17#include <linux/debugfs.h>
18#include <linux/device.h>
19#include <linux/iommu.h>
20#include <linux/of.h>
21#include <linux/platform_device.h>
22#include <linux/slab.h>
23#include <linux/module.h>
Mitchel Humpherys0fe337d2015-07-06 15:21:24 -070024#include <linux/uaccess.h>
Mitchel Humpherys42296fb2015-06-23 16:29:16 -070025
Mitchel Humpherys42296fb2015-06-23 16:29:16 -070026#ifdef CONFIG_IOMMU_DEBUG_TRACKING
27
28static DEFINE_MUTEX(iommu_debug_attachments_lock);
29static LIST_HEAD(iommu_debug_attachments);
30static struct dentry *debugfs_attachments_dir;
31
32struct iommu_debug_attachment {
33 struct iommu_domain *domain;
34 struct device *dev;
35 struct dentry *dentry;
36 struct list_head list;
37};
38
Mitchel Humpherys088cc582015-07-09 15:02:03 -070039static int iommu_debug_attachment_info_show(struct seq_file *s, void *ignored)
Mitchel Humpherys42296fb2015-06-23 16:29:16 -070040{
41 struct iommu_debug_attachment *attach = s->private;
42
43 seq_printf(s, "Domain: 0x%p\n", attach->domain);
44 return 0;
45}
46
Mitchel Humpherys088cc582015-07-09 15:02:03 -070047static int iommu_debug_attachment_info_open(struct inode *inode,
48 struct file *file)
Mitchel Humpherys42296fb2015-06-23 16:29:16 -070049{
Mitchel Humpherys088cc582015-07-09 15:02:03 -070050 return single_open(file, iommu_debug_attachment_info_show,
51 inode->i_private);
Mitchel Humpherys42296fb2015-06-23 16:29:16 -070052}
53
Mitchel Humpherys088cc582015-07-09 15:02:03 -070054static const struct file_operations iommu_debug_attachment_info_fops = {
55 .open = iommu_debug_attachment_info_open,
Mitchel Humpherys42296fb2015-06-23 16:29:16 -070056 .read = seq_read,
57 .llseek = seq_lseek,
58 .release = single_release,
59};
60
Mitchel Humpherysa05b2522015-07-14 14:30:33 -070061/* should be called with iommu_debug_attachments_lock locked */
62static int iommu_debug_attach_add_debugfs(
63 struct iommu_debug_attachment *attach)
Mitchel Humpherys42296fb2015-06-23 16:29:16 -070064{
Mitchel Humpherys876e2be2015-07-10 11:56:56 -070065 uuid_le uuid;
Mitchel Humpherysa05b2522015-07-14 14:30:33 -070066 char *attach_name;
67 struct device *dev = attach->dev;
68 struct iommu_domain *domain = attach->domain;
Mitchel Humpherys42296fb2015-06-23 16:29:16 -070069
Mitchel Humpherys876e2be2015-07-10 11:56:56 -070070 uuid_le_gen(&uuid);
71 attach_name = kasprintf(GFP_KERNEL, "%s-%pUl", dev_name(dev), uuid.b);
72 if (!attach_name)
Mitchel Humpherysa05b2522015-07-14 14:30:33 -070073 return -ENOMEM;
Mitchel Humpherys42296fb2015-06-23 16:29:16 -070074
Mitchel Humpherys088cc582015-07-09 15:02:03 -070075 attach->dentry = debugfs_create_dir(attach_name,
76 debugfs_attachments_dir);
Mitchel Humpherys42296fb2015-06-23 16:29:16 -070077 if (!attach->dentry) {
Mitchel Humpherys088cc582015-07-09 15:02:03 -070078 pr_err("Couldn't create iommu/attachments/%s debugfs directory for domain 0x%p\n",
Mitchel Humpherys876e2be2015-07-10 11:56:56 -070079 attach_name, domain);
Mitchel Humpherysa05b2522015-07-14 14:30:33 -070080 kfree(attach_name);
81 return -EIO;
Mitchel Humpherys42296fb2015-06-23 16:29:16 -070082 }
Mitchel Humpherysa05b2522015-07-14 14:30:33 -070083 kfree(attach_name);
Mitchel Humpherys42296fb2015-06-23 16:29:16 -070084
Mitchel Humpherys088cc582015-07-09 15:02:03 -070085 if (!debugfs_create_file(
86 "info", S_IRUSR, attach->dentry, attach,
87 &iommu_debug_attachment_info_fops)) {
88 pr_err("Couldn't create iommu/attachments/%s/info debugfs file for domain 0x%p\n",
89 dev_name(dev), domain);
Mitchel Humpherysa05b2522015-07-14 14:30:33 -070090 goto err_rmdir;
Mitchel Humpherys088cc582015-07-09 15:02:03 -070091 }
92
Mitchel Humpherysa05b2522015-07-14 14:30:33 -070093 return 0;
94
95err_rmdir:
96 debugfs_remove_recursive(attach->dentry);
97 return -EIO;
98}
99
100void iommu_debug_attach_device(struct iommu_domain *domain,
101 struct device *dev)
102{
103 struct iommu_debug_attachment *attach;
104
105 mutex_lock(&iommu_debug_attachments_lock);
106
107 attach = kmalloc(sizeof(*attach), GFP_KERNEL);
108 if (!attach)
109 goto out_unlock;
110
111 attach->domain = domain;
112 attach->dev = dev;
113
114 /*
115 * we might not init until after other drivers start calling
116 * iommu_attach_device. Only set up the debugfs nodes if we've
117 * already init'd to avoid polluting the top-level debugfs
118 * directory (by calling debugfs_create_dir with a NULL
119 * parent). These will be flushed out later once we init.
120 */
121 if (debugfs_attachments_dir)
122 iommu_debug_attach_add_debugfs(attach);
123
Mitchel Humpherys42296fb2015-06-23 16:29:16 -0700124 list_add(&attach->list, &iommu_debug_attachments);
Mitchel Humpherysa05b2522015-07-14 14:30:33 -0700125out_unlock:
Mitchel Humpherys42296fb2015-06-23 16:29:16 -0700126 mutex_unlock(&iommu_debug_attachments_lock);
127}
128
129void iommu_debug_detach_device(struct iommu_domain *domain,
130 struct device *dev)
131{
132 struct iommu_debug_attachment *it;
133
134 mutex_lock(&iommu_debug_attachments_lock);
135 list_for_each_entry(it, &iommu_debug_attachments, list)
136 if (it->domain == domain && it->dev == dev)
137 break;
138
139 if (&it->list == &iommu_debug_attachments) {
140 WARN(1, "Couldn't find debug attachment for domain=0x%p dev=%s",
141 domain, dev_name(dev));
142 } else {
143 list_del(&it->list);
144 debugfs_remove_recursive(it->dentry);
145 kfree(it);
146 }
147 mutex_unlock(&iommu_debug_attachments_lock);
148}
149
150static int iommu_debug_init_tracking(void)
151{
Mitchel Humpherysa05b2522015-07-14 14:30:33 -0700152 int ret = 0;
153 struct iommu_debug_attachment *attach;
154
155 mutex_lock(&iommu_debug_attachments_lock);
Mitchel Humpherys42296fb2015-06-23 16:29:16 -0700156 debugfs_attachments_dir = debugfs_create_dir("attachments",
Mitchel Humpherysc75ae492015-07-15 18:27:36 -0700157 iommu_debugfs_top);
Mitchel Humpherys42296fb2015-06-23 16:29:16 -0700158 if (!debugfs_attachments_dir) {
159 pr_err("Couldn't create iommu/attachments debugfs directory\n");
Mitchel Humpherysa05b2522015-07-14 14:30:33 -0700160 ret = -ENODEV;
161 goto out_unlock;
Mitchel Humpherys42296fb2015-06-23 16:29:16 -0700162 }
163
Mitchel Humpherysa05b2522015-07-14 14:30:33 -0700164 /* set up debugfs entries for attachments made during early boot */
165 list_for_each_entry(attach, &iommu_debug_attachments, list)
166 iommu_debug_attach_add_debugfs(attach);
167
168out_unlock:
169 mutex_unlock(&iommu_debug_attachments_lock);
170 return ret;
Mitchel Humpherys42296fb2015-06-23 16:29:16 -0700171}
Mitchel Humpherysc75ae492015-07-15 18:27:36 -0700172
173static void iommu_debug_destroy_tracking(void)
174{
175 debugfs_remove_recursive(debugfs_attachments_dir);
176}
Mitchel Humpherys42296fb2015-06-23 16:29:16 -0700177#else
178static inline int iommu_debug_init_tracking(void) { return 0; }
Mitchel Humpherysc75ae492015-07-15 18:27:36 -0700179static inline void iommu_debug_destroy_tracking(void) { }
Mitchel Humpherys42296fb2015-06-23 16:29:16 -0700180#endif
181
182#ifdef CONFIG_IOMMU_TESTS
183
184static LIST_HEAD(iommu_debug_devices);
185static struct dentry *debugfs_tests_dir;
186
187struct iommu_debug_device {
188 struct device *dev;
Mitchel Humpherys0fe337d2015-07-06 15:21:24 -0700189 struct iommu_domain *domain;
190 u64 iova;
191 u64 phys;
192 size_t len;
Mitchel Humpherys42296fb2015-06-23 16:29:16 -0700193 struct list_head list;
194};
195
196static int iommu_debug_build_phoney_sg_table(struct device *dev,
197 struct sg_table *table,
198 unsigned long total_size,
199 unsigned long chunk_size)
200{
201 unsigned long nents = total_size / chunk_size;
202 struct scatterlist *sg;
203 int i;
204 struct page *page;
205
206 if (!IS_ALIGNED(total_size, PAGE_SIZE))
207 return -EINVAL;
208 if (!IS_ALIGNED(total_size, chunk_size))
209 return -EINVAL;
210 if (sg_alloc_table(table, nents, GFP_KERNEL))
211 return -EINVAL;
212 page = alloc_pages(GFP_KERNEL, get_order(chunk_size));
213 if (!page)
214 goto free_table;
215
216 /* all the same page... why not. */
217 for_each_sg(table->sgl, sg, table->nents, i)
218 sg_set_page(sg, page, chunk_size, 0);
219
220 return 0;
221
222free_table:
223 sg_free_table(table);
224 return -ENOMEM;
225}
226
227static void iommu_debug_destroy_phoney_sg_table(struct device *dev,
228 struct sg_table *table,
229 unsigned long chunk_size)
230{
231 __free_pages(sg_page(table->sgl), get_order(chunk_size));
232 sg_free_table(table);
233}
234
235static const char * const _size_to_string(unsigned long size)
236{
237 switch (size) {
238 case SZ_4K:
239 return "4K";
240 case SZ_64K:
241 return "64K";
242 case SZ_2M:
243 return "2M";
244 case SZ_1M * 12:
245 return "12M";
246 case SZ_1M * 20:
247 return "20M";
248 }
249 return "unknown size, please add to _size_to_string";
250}
251
252static void iommu_debug_device_profiling(struct seq_file *s, struct device *dev)
253{
254 unsigned long sizes[] = { SZ_4K, SZ_64K, SZ_2M, SZ_1M * 12,
255 SZ_1M * 20, 0 };
256 unsigned long *sz;
257 struct iommu_domain *domain;
258 unsigned long iova = 0x10000;
259 phys_addr_t paddr = 0xa000;
260
261 domain = iommu_domain_alloc(&platform_bus_type);
262 if (!domain) {
263 seq_puts(s, "Couldn't allocate domain\n");
264 return;
265 }
266
267 if (iommu_attach_device(domain, dev)) {
268 seq_puts(s,
269 "Couldn't attach new domain to device. Is it already attached?\n");
270 goto out_domain_free;
271 }
272
273 seq_printf(s, "%8s %15s %12s\n", "size", "iommu_map", "iommu_unmap");
274 for (sz = sizes; *sz; ++sz) {
275 unsigned long size = *sz;
276 size_t unmapped;
277 s64 map_elapsed_us, unmap_elapsed_us;
278 struct timespec tbefore, tafter, diff;
279
280 getnstimeofday(&tbefore);
281 if (iommu_map(domain, iova, paddr, size,
282 IOMMU_READ | IOMMU_WRITE)) {
283 seq_puts(s, "Failed to map\n");
284 continue;
285 }
286 getnstimeofday(&tafter);
287 diff = timespec_sub(tafter, tbefore);
288 map_elapsed_us = div_s64(timespec_to_ns(&diff), 1000);
289
290 getnstimeofday(&tbefore);
291 unmapped = iommu_unmap(domain, iova, size);
292 if (unmapped != size) {
293 seq_printf(s, "Only unmapped %zx instead of %zx\n",
294 unmapped, size);
295 continue;
296 }
297 getnstimeofday(&tafter);
298 diff = timespec_sub(tafter, tbefore);
299 unmap_elapsed_us = div_s64(timespec_to_ns(&diff), 1000);
300
301 seq_printf(s, "%8s %12lld us %9lld us\n", _size_to_string(size),
302 map_elapsed_us, unmap_elapsed_us);
303 }
304
305 seq_putc(s, '\n');
306 seq_printf(s, "%8s %15s %12s\n", "size", "iommu_map_sg", "iommu_unmap");
307 for (sz = sizes; *sz; ++sz) {
308 unsigned long size = *sz;
309 size_t unmapped;
310 s64 map_elapsed_us, unmap_elapsed_us;
311 struct timespec tbefore, tafter, diff;
312 struct sg_table table;
313 unsigned long chunk_size = SZ_4K;
314
315 if (iommu_debug_build_phoney_sg_table(dev, &table, size,
316 chunk_size)) {
317 seq_puts(s,
318 "couldn't build phoney sg table! bailing...\n");
319 goto out_detach;
320 }
321
322 getnstimeofday(&tbefore);
323 if (iommu_map_sg(domain, iova, table.sgl, table.nents,
324 IOMMU_READ | IOMMU_WRITE) != size) {
325 seq_puts(s, "Failed to map_sg\n");
326 goto next;
327 }
328 getnstimeofday(&tafter);
329 diff = timespec_sub(tafter, tbefore);
330 map_elapsed_us = div_s64(timespec_to_ns(&diff), 1000);
331
332 getnstimeofday(&tbefore);
333 unmapped = iommu_unmap(domain, iova, size);
334 if (unmapped != size) {
335 seq_printf(s, "Only unmapped %zx instead of %zx\n",
336 unmapped, size);
337 goto next;
338 }
339 getnstimeofday(&tafter);
340 diff = timespec_sub(tafter, tbefore);
341 unmap_elapsed_us = div_s64(timespec_to_ns(&diff), 1000);
342
343 seq_printf(s, "%8s %12lld us %9lld us\n", _size_to_string(size),
344 map_elapsed_us, unmap_elapsed_us);
345
346next:
347 iommu_debug_destroy_phoney_sg_table(dev, &table, chunk_size);
348 }
349
350out_detach:
351 iommu_detach_device(domain, dev);
352out_domain_free:
353 iommu_domain_free(domain);
354}
355
Mitchel Humpherys7cc56e42015-07-06 14:58:23 -0700356static int iommu_debug_profiling_show(struct seq_file *s, void *ignored)
Mitchel Humpherys42296fb2015-06-23 16:29:16 -0700357{
358 struct iommu_debug_device *ddev = s->private;
359
360 iommu_debug_device_profiling(s, ddev->dev);
361
362 return 0;
363}
364
Mitchel Humpherys7cc56e42015-07-06 14:58:23 -0700365static int iommu_debug_profiling_open(struct inode *inode, struct file *file)
Mitchel Humpherys42296fb2015-06-23 16:29:16 -0700366{
Mitchel Humpherys7cc56e42015-07-06 14:58:23 -0700367 return single_open(file, iommu_debug_profiling_show, inode->i_private);
Mitchel Humpherys42296fb2015-06-23 16:29:16 -0700368}
369
Mitchel Humpherys7cc56e42015-07-06 14:58:23 -0700370static const struct file_operations iommu_debug_profiling_fops = {
371 .open = iommu_debug_profiling_open,
Mitchel Humpherys42296fb2015-06-23 16:29:16 -0700372 .read = seq_read,
373 .llseek = seq_lseek,
374 .release = single_release,
375};
376
Mitchel Humpherys0fe337d2015-07-06 15:21:24 -0700377static int iommu_debug_attach_do_attach(struct iommu_debug_device *ddev)
378{
379 ddev->domain = iommu_domain_alloc(&platform_bus_type);
380 if (!ddev->domain) {
381 pr_err("Couldn't allocate domain\n");
382 return -ENOMEM;
383 }
384
385 if (iommu_attach_device(ddev->domain, ddev->dev)) {
386 pr_err("Couldn't attach new domain to device. Is it already attached?\n");
387 goto out_domain_free;
388 }
389
390 return 0;
391
392out_domain_free:
393 iommu_domain_free(ddev->domain);
394 ddev->domain = NULL;
395 return -EIO;
396}
397
398static ssize_t iommu_debug_attach_write(struct file *file,
399 const char __user *ubuf,
400 size_t count, loff_t *offset)
401{
402 struct iommu_debug_device *ddev = file->private_data;
403 ssize_t retval;
404 char val;
405
406 if (count > 2) {
407 pr_err("Invalid value. Expected 0 or 1.\n");
408 retval = -EINVAL;
409 goto out;
410 }
411
412 if (copy_from_user(&val, ubuf, 1)) {
413 pr_err("Couldn't copy from user\n");
414 retval = -EFAULT;
415 goto out;
416 }
417
418 if (val == '1') {
419 if (ddev->domain) {
420 pr_err("Already attached.\n");
421 retval = -EINVAL;
422 goto out;
423 }
424 if (WARN(ddev->dev->archdata.iommu,
425 "Attachment tracking out of sync with device\n")) {
426 retval = -EINVAL;
427 goto out;
428 }
429 if (iommu_debug_attach_do_attach(ddev)) {
430 retval = -EIO;
431 goto out;
432 }
433 pr_err("Attached\n");
434 } else if (val == '0') {
435 if (!ddev->domain) {
436 pr_err("No domain. Did you already attach?\n");
437 retval = -EINVAL;
438 goto out;
439 }
440 iommu_detach_device(ddev->domain, ddev->dev);
441 iommu_domain_free(ddev->domain);
442 ddev->domain = NULL;
443 pr_err("Detached\n");
444 } else {
445 pr_err("Invalid value. Expected 0 or 1\n");
446 retval = -EFAULT;
447 goto out;
448 }
449
450 retval = count;
451out:
452 return retval;
453}
454
455static ssize_t iommu_debug_attach_read(struct file *file, char __user *ubuf,
456 size_t count, loff_t *offset)
457{
458 struct iommu_debug_device *ddev = file->private_data;
459 char c[2];
460
461 if (*offset)
462 return 0;
463
464 c[0] = ddev->domain ? '1' : '0';
465 c[1] = '\n';
466 if (copy_to_user(ubuf, &c, 2)) {
467 pr_err("copy_to_user failed\n");
468 return -EFAULT;
469 }
470 *offset = 1; /* non-zero means we're done */
471
472 return 2;
473}
474
475static const struct file_operations iommu_debug_attach_fops = {
476 .open = simple_open,
477 .write = iommu_debug_attach_write,
478 .read = iommu_debug_attach_read,
479};
480
481static ssize_t iommu_debug_atos_write(struct file *file,
482 const char __user *ubuf,
483 size_t count, loff_t *offset)
484{
485 struct iommu_debug_device *ddev = file->private_data;
486 dma_addr_t iova;
487
488 if (kstrtoll_from_user(ubuf, count, 0, &iova)) {
489 pr_err("Invalid format for iova\n");
490 ddev->iova = 0;
491 return -EINVAL;
492 }
493
494 ddev->iova = iova;
495 pr_err("Saved iova=%pa for future ATOS commands\n", &iova);
496 return count;
497}
498
499static ssize_t iommu_debug_atos_read(struct file *file, char __user *ubuf,
500 size_t count, loff_t *offset)
501{
502 struct iommu_debug_device *ddev = file->private_data;
503 phys_addr_t phys;
504 char buf[100];
505 ssize_t retval;
506 size_t buflen;
507
508 if (!ddev->domain) {
509 pr_err("No domain. Did you already attach?\n");
510 return -EINVAL;
511 }
512
513 if (*offset)
514 return 0;
515
516 memset(buf, 0, 100);
517
518 phys = iommu_iova_to_phys_hard(ddev->domain, ddev->iova);
519 if (!phys)
520 strlcpy(buf, "FAIL\n", 100);
521 else
522 snprintf(buf, 100, "%pa\n", &phys);
523
524 buflen = strlen(buf);
525 if (copy_to_user(ubuf, buf, buflen)) {
526 pr_err("Couldn't copy_to_user\n");
527 retval = -EFAULT;
528 } else {
529 *offset = 1; /* non-zero means we're done */
530 retval = buflen;
531 }
532
533 return retval;
534}
535
536static const struct file_operations iommu_debug_atos_fops = {
537 .open = simple_open,
538 .write = iommu_debug_atos_write,
539 .read = iommu_debug_atos_read,
540};
541
542static ssize_t iommu_debug_map_write(struct file *file, const char __user *ubuf,
543 size_t count, loff_t *offset)
544{
545 ssize_t retval;
546 int ret;
547 char *comma1, *comma2, *comma3;
548 char buf[100];
549 dma_addr_t iova;
550 phys_addr_t phys;
551 size_t size;
552 int prot;
553 struct iommu_debug_device *ddev = file->private_data;
554
555 if (count >= 100) {
556 pr_err("Value too large\n");
557 return -EINVAL;
558 }
559
560 if (!ddev->domain) {
561 pr_err("No domain. Did you already attach?\n");
562 return -EINVAL;
563 }
564
565 memset(buf, 0, 100);
566
567 if (copy_from_user(buf, ubuf, count)) {
568 pr_err("Couldn't copy from user\n");
569 retval = -EFAULT;
570 }
571
572 comma1 = strnchr(buf, count, ',');
573 if (!comma1)
574 goto invalid_format;
575
576 comma2 = strnchr(comma1 + 1, count, ',');
577 if (!comma2)
578 goto invalid_format;
579
580 comma3 = strnchr(comma2 + 1, count, ',');
581 if (!comma3)
582 goto invalid_format;
583
584 /* split up the words */
585 *comma1 = *comma2 = *comma3 = '\0';
586
587 if (kstrtou64(buf, 0, &iova))
588 goto invalid_format;
589
590 if (kstrtou64(comma1 + 1, 0, &phys))
591 goto invalid_format;
592
593 if (kstrtoul(comma2 + 1, 0, &size))
594 goto invalid_format;
595
596 if (kstrtoint(comma3 + 1, 0, &prot))
597 goto invalid_format;
598
599 ret = iommu_map(ddev->domain, iova, phys, size, prot);
600 if (ret) {
601 pr_err("iommu_map failed with %d\n", ret);
602 retval = -EIO;
603 goto out;
604 }
605
606 retval = count;
607 pr_err("Mapped %pa to %pa (len=0x%zx, prot=0x%x)\n",
608 &iova, &phys, size, prot);
609out:
610 return retval;
611
612invalid_format:
613 pr_err("Invalid format. Expected: iova,phys,len,prot where `prot' is the bitwise OR of IOMMU_READ, IOMMU_WRITE, etc.\n");
614 return -EINVAL;
615}
616
617static const struct file_operations iommu_debug_map_fops = {
618 .open = simple_open,
619 .write = iommu_debug_map_write,
620};
621
622static ssize_t iommu_debug_unmap_write(struct file *file,
623 const char __user *ubuf,
624 size_t count, loff_t *offset)
625{
626 ssize_t retval = 0;
627 char *comma1;
628 char buf[100];
629 dma_addr_t iova;
630 size_t size;
631 size_t unmapped;
632 struct iommu_debug_device *ddev = file->private_data;
633
634 if (count >= 100) {
635 pr_err("Value too large\n");
636 return -EINVAL;
637 }
638
639 if (!ddev->domain) {
640 pr_err("No domain. Did you already attach?\n");
641 return -EINVAL;
642 }
643
644 memset(buf, 0, 100);
645
646 if (copy_from_user(buf, ubuf, count)) {
647 pr_err("Couldn't copy from user\n");
648 retval = -EFAULT;
649 goto out;
650 }
651
652 comma1 = strnchr(buf, count, ',');
653 if (!comma1)
654 goto invalid_format;
655
656 /* split up the words */
657 *comma1 = '\0';
658
659 if (kstrtou64(buf, 0, &iova))
660 goto invalid_format;
661
662 if (kstrtoul(buf, 0, &size))
663 goto invalid_format;
664
665 unmapped = iommu_unmap(ddev->domain, iova, size);
666 if (unmapped != size) {
667 pr_err("iommu_unmap failed. Expected to unmap: 0x%zx, unmapped: 0x%zx",
668 size, unmapped);
669 return -EIO;
670 }
671
672 retval = count;
673 pr_err("Unmapped %pa (len=0x%zx)\n", &iova, size);
674out:
675 return retval;
676
677invalid_format:
678 pr_err("Invalid format. Expected: iova,len\n");
679 return retval;
680}
681
682static const struct file_operations iommu_debug_unmap_fops = {
683 .open = simple_open,
684 .write = iommu_debug_unmap_write,
685};
686
Mitchel Humpherys42296fb2015-06-23 16:29:16 -0700687/*
688 * The following will only work for drivers that implement the generic
689 * device tree bindings described in
690 * Documentation/devicetree/bindings/iommu/iommu.txt
691 */
692static int snarf_iommu_devices(struct device *dev, void *ignored)
693{
694 struct iommu_debug_device *ddev;
Mitchel Humpherys0fe337d2015-07-06 15:21:24 -0700695 struct dentry *dir;
Mitchel Humpherys42296fb2015-06-23 16:29:16 -0700696
697 if (!of_find_property(dev->of_node, "iommus", NULL))
698 return 0;
699
Mitchel Humpherys89924fd2015-07-09 14:50:22 -0700700 ddev = kzalloc(sizeof(*ddev), GFP_KERNEL);
Mitchel Humpherys42296fb2015-06-23 16:29:16 -0700701 if (!ddev)
702 return -ENODEV;
703 ddev->dev = dev;
704 dir = debugfs_create_dir(dev_name(dev), debugfs_tests_dir);
705 if (!dir) {
706 pr_err("Couldn't create iommu/devices/%s debugfs dir\n",
707 dev_name(dev));
708 goto err;
709 }
Mitchel Humpherys0fe337d2015-07-06 15:21:24 -0700710
711 if (!debugfs_create_file("profiling", S_IRUSR, dir, ddev,
712 &iommu_debug_profiling_fops)) {
Mitchel Humpherys42296fb2015-06-23 16:29:16 -0700713 pr_err("Couldn't create iommu/devices/%s/profiling debugfs file\n",
714 dev_name(dev));
715 goto err_rmdir;
716 }
717
Mitchel Humpherys0fe337d2015-07-06 15:21:24 -0700718 if (!debugfs_create_file("attach", S_IRUSR, dir, ddev,
719 &iommu_debug_attach_fops)) {
720 pr_err("Couldn't create iommu/devices/%s/attach debugfs file\n",
721 dev_name(dev));
722 goto err_rmdir;
723 }
724
725 if (!debugfs_create_file("atos", S_IWUSR, dir, ddev,
726 &iommu_debug_atos_fops)) {
727 pr_err("Couldn't create iommu/devices/%s/atos debugfs file\n",
728 dev_name(dev));
729 goto err_rmdir;
730 }
731
732 if (!debugfs_create_file("map", S_IWUSR, dir, ddev,
733 &iommu_debug_map_fops)) {
734 pr_err("Couldn't create iommu/devices/%s/map debugfs file\n",
735 dev_name(dev));
736 goto err_rmdir;
737 }
738
739 if (!debugfs_create_file("unmap", S_IWUSR, dir, ddev,
740 &iommu_debug_unmap_fops)) {
741 pr_err("Couldn't create iommu/devices/%s/unmap debugfs file\n",
742 dev_name(dev));
743 goto err_rmdir;
744 }
745
Mitchel Humpherys42296fb2015-06-23 16:29:16 -0700746 list_add(&ddev->list, &iommu_debug_devices);
747 return 0;
748
749err_rmdir:
750 debugfs_remove_recursive(dir);
751err:
752 kfree(ddev);
753 return 0;
754}
755
756static int iommu_debug_init_tests(void)
757{
758 debugfs_tests_dir = debugfs_create_dir("tests",
Mitchel Humpherysc75ae492015-07-15 18:27:36 -0700759 iommu_debugfs_top);
Mitchel Humpherys42296fb2015-06-23 16:29:16 -0700760 if (!debugfs_tests_dir) {
761 pr_err("Couldn't create iommu/tests debugfs directory\n");
762 return -ENODEV;
763 }
764
765 return bus_for_each_dev(&platform_bus_type, NULL, NULL,
766 snarf_iommu_devices);
767}
Mitchel Humpherysc75ae492015-07-15 18:27:36 -0700768
769static void iommu_debug_destroy_tests(void)
770{
771 debugfs_remove_recursive(debugfs_tests_dir);
772}
Mitchel Humpherys42296fb2015-06-23 16:29:16 -0700773#else
774static inline int iommu_debug_init_tests(void) { return 0; }
Mitchel Humpherysc75ae492015-07-15 18:27:36 -0700775static inline void iommu_debug_destroy_tests(void) { }
Mitchel Humpherys42296fb2015-06-23 16:29:16 -0700776#endif
777
778static int iommu_debug_init(void)
779{
Mitchel Humpherys42296fb2015-06-23 16:29:16 -0700780 if (iommu_debug_init_tracking())
Mitchel Humpherysc75ae492015-07-15 18:27:36 -0700781 return -ENODEV;
Mitchel Humpherys42296fb2015-06-23 16:29:16 -0700782
783 if (iommu_debug_init_tests())
Mitchel Humpherysc75ae492015-07-15 18:27:36 -0700784 return -ENODEV;
Mitchel Humpherys42296fb2015-06-23 16:29:16 -0700785
786 return 0;
Mitchel Humpherys42296fb2015-06-23 16:29:16 -0700787}
788
789static void iommu_debug_exit(void)
790{
Mitchel Humpherysc75ae492015-07-15 18:27:36 -0700791 iommu_debug_destroy_tracking();
792 iommu_debug_destroy_tests();
Mitchel Humpherys42296fb2015-06-23 16:29:16 -0700793}
794
795module_init(iommu_debug_init);
796module_exit(iommu_debug_exit);