blob: 5c038c778c87ba974d0eca4045ae5bd089009d13 [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
26static struct dentry *debugfs_top_dir;
27
28#ifdef CONFIG_IOMMU_DEBUG_TRACKING
29
30static DEFINE_MUTEX(iommu_debug_attachments_lock);
31static LIST_HEAD(iommu_debug_attachments);
32static struct dentry *debugfs_attachments_dir;
33
34struct iommu_debug_attachment {
35 struct iommu_domain *domain;
36 struct device *dev;
37 struct dentry *dentry;
38 struct list_head list;
39};
40
41static int iommu_debug_attachment_show(struct seq_file *s, void *ignored)
42{
43 struct iommu_debug_attachment *attach = s->private;
44
45 seq_printf(s, "Domain: 0x%p\n", attach->domain);
46 return 0;
47}
48
49static int iommu_debug_attachment_open(struct inode *inode, struct file *file)
50{
51 return single_open(file, iommu_debug_attachment_show, inode->i_private);
52}
53
54static const struct file_operations iommu_debug_attachment_fops = {
55 .open = iommu_debug_attachment_open,
56 .read = seq_read,
57 .llseek = seq_lseek,
58 .release = single_release,
59};
60
61void iommu_debug_attach_device(struct iommu_domain *domain,
62 struct device *dev)
63{
64 struct iommu_debug_attachment *attach;
Mitchel Humpherys876e2be2015-07-10 11:56:56 -070065 char *attach_name;
66 uuid_le uuid;
Mitchel Humpherys42296fb2015-06-23 16:29:16 -070067
68 mutex_lock(&iommu_debug_attachments_lock);
69
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)
73 goto unlock;
74
Mitchel Humpherys42296fb2015-06-23 16:29:16 -070075 attach = kmalloc(sizeof(*attach), GFP_KERNEL);
76 if (!attach)
Mitchel Humpherys876e2be2015-07-10 11:56:56 -070077 goto free_attach_name;
Mitchel Humpherys42296fb2015-06-23 16:29:16 -070078
79 attach->domain = domain;
80 attach->dev = dev;
81
82 attach->dentry = debugfs_create_file(
Mitchel Humpherys876e2be2015-07-10 11:56:56 -070083 attach_name, S_IRUSR, debugfs_attachments_dir, attach,
Mitchel Humpherys42296fb2015-06-23 16:29:16 -070084 &iommu_debug_attachment_fops);
85 if (!attach->dentry) {
86 pr_err("Couldn't create iommu/attachments/%s debugfs file for domain 0x%p\n",
Mitchel Humpherys876e2be2015-07-10 11:56:56 -070087 attach_name, domain);
Mitchel Humpherys42296fb2015-06-23 16:29:16 -070088 kfree(attach);
Mitchel Humpherys876e2be2015-07-10 11:56:56 -070089 goto free_attach_name;
Mitchel Humpherys42296fb2015-06-23 16:29:16 -070090 }
91
92 list_add(&attach->list, &iommu_debug_attachments);
Mitchel Humpherys876e2be2015-07-10 11:56:56 -070093free_attach_name:
94 kfree(attach_name);
Mitchel Humpherys42296fb2015-06-23 16:29:16 -070095unlock:
96 mutex_unlock(&iommu_debug_attachments_lock);
97}
98
99void iommu_debug_detach_device(struct iommu_domain *domain,
100 struct device *dev)
101{
102 struct iommu_debug_attachment *it;
103
104 mutex_lock(&iommu_debug_attachments_lock);
105 list_for_each_entry(it, &iommu_debug_attachments, list)
106 if (it->domain == domain && it->dev == dev)
107 break;
108
109 if (&it->list == &iommu_debug_attachments) {
110 WARN(1, "Couldn't find debug attachment for domain=0x%p dev=%s",
111 domain, dev_name(dev));
112 } else {
113 list_del(&it->list);
114 debugfs_remove_recursive(it->dentry);
115 kfree(it);
116 }
117 mutex_unlock(&iommu_debug_attachments_lock);
118}
119
120static int iommu_debug_init_tracking(void)
121{
122 debugfs_attachments_dir = debugfs_create_dir("attachments",
123 debugfs_top_dir);
124 if (!debugfs_attachments_dir) {
125 pr_err("Couldn't create iommu/attachments debugfs directory\n");
126 return -ENODEV;
127 }
128
129 return 0;
130}
131#else
132static inline int iommu_debug_init_tracking(void) { return 0; }
133#endif
134
135#ifdef CONFIG_IOMMU_TESTS
136
137static LIST_HEAD(iommu_debug_devices);
138static struct dentry *debugfs_tests_dir;
139
140struct iommu_debug_device {
141 struct device *dev;
Mitchel Humpherys0fe337d2015-07-06 15:21:24 -0700142 struct iommu_domain *domain;
143 u64 iova;
144 u64 phys;
145 size_t len;
Mitchel Humpherys42296fb2015-06-23 16:29:16 -0700146 struct list_head list;
147};
148
149static int iommu_debug_build_phoney_sg_table(struct device *dev,
150 struct sg_table *table,
151 unsigned long total_size,
152 unsigned long chunk_size)
153{
154 unsigned long nents = total_size / chunk_size;
155 struct scatterlist *sg;
156 int i;
157 struct page *page;
158
159 if (!IS_ALIGNED(total_size, PAGE_SIZE))
160 return -EINVAL;
161 if (!IS_ALIGNED(total_size, chunk_size))
162 return -EINVAL;
163 if (sg_alloc_table(table, nents, GFP_KERNEL))
164 return -EINVAL;
165 page = alloc_pages(GFP_KERNEL, get_order(chunk_size));
166 if (!page)
167 goto free_table;
168
169 /* all the same page... why not. */
170 for_each_sg(table->sgl, sg, table->nents, i)
171 sg_set_page(sg, page, chunk_size, 0);
172
173 return 0;
174
175free_table:
176 sg_free_table(table);
177 return -ENOMEM;
178}
179
180static void iommu_debug_destroy_phoney_sg_table(struct device *dev,
181 struct sg_table *table,
182 unsigned long chunk_size)
183{
184 __free_pages(sg_page(table->sgl), get_order(chunk_size));
185 sg_free_table(table);
186}
187
188static const char * const _size_to_string(unsigned long size)
189{
190 switch (size) {
191 case SZ_4K:
192 return "4K";
193 case SZ_64K:
194 return "64K";
195 case SZ_2M:
196 return "2M";
197 case SZ_1M * 12:
198 return "12M";
199 case SZ_1M * 20:
200 return "20M";
201 }
202 return "unknown size, please add to _size_to_string";
203}
204
205static void iommu_debug_device_profiling(struct seq_file *s, struct device *dev)
206{
207 unsigned long sizes[] = { SZ_4K, SZ_64K, SZ_2M, SZ_1M * 12,
208 SZ_1M * 20, 0 };
209 unsigned long *sz;
210 struct iommu_domain *domain;
211 unsigned long iova = 0x10000;
212 phys_addr_t paddr = 0xa000;
213
214 domain = iommu_domain_alloc(&platform_bus_type);
215 if (!domain) {
216 seq_puts(s, "Couldn't allocate domain\n");
217 return;
218 }
219
220 if (iommu_attach_device(domain, dev)) {
221 seq_puts(s,
222 "Couldn't attach new domain to device. Is it already attached?\n");
223 goto out_domain_free;
224 }
225
226 seq_printf(s, "%8s %15s %12s\n", "size", "iommu_map", "iommu_unmap");
227 for (sz = sizes; *sz; ++sz) {
228 unsigned long size = *sz;
229 size_t unmapped;
230 s64 map_elapsed_us, unmap_elapsed_us;
231 struct timespec tbefore, tafter, diff;
232
233 getnstimeofday(&tbefore);
234 if (iommu_map(domain, iova, paddr, size,
235 IOMMU_READ | IOMMU_WRITE)) {
236 seq_puts(s, "Failed to map\n");
237 continue;
238 }
239 getnstimeofday(&tafter);
240 diff = timespec_sub(tafter, tbefore);
241 map_elapsed_us = div_s64(timespec_to_ns(&diff), 1000);
242
243 getnstimeofday(&tbefore);
244 unmapped = iommu_unmap(domain, iova, size);
245 if (unmapped != size) {
246 seq_printf(s, "Only unmapped %zx instead of %zx\n",
247 unmapped, size);
248 continue;
249 }
250 getnstimeofday(&tafter);
251 diff = timespec_sub(tafter, tbefore);
252 unmap_elapsed_us = div_s64(timespec_to_ns(&diff), 1000);
253
254 seq_printf(s, "%8s %12lld us %9lld us\n", _size_to_string(size),
255 map_elapsed_us, unmap_elapsed_us);
256 }
257
258 seq_putc(s, '\n');
259 seq_printf(s, "%8s %15s %12s\n", "size", "iommu_map_sg", "iommu_unmap");
260 for (sz = sizes; *sz; ++sz) {
261 unsigned long size = *sz;
262 size_t unmapped;
263 s64 map_elapsed_us, unmap_elapsed_us;
264 struct timespec tbefore, tafter, diff;
265 struct sg_table table;
266 unsigned long chunk_size = SZ_4K;
267
268 if (iommu_debug_build_phoney_sg_table(dev, &table, size,
269 chunk_size)) {
270 seq_puts(s,
271 "couldn't build phoney sg table! bailing...\n");
272 goto out_detach;
273 }
274
275 getnstimeofday(&tbefore);
276 if (iommu_map_sg(domain, iova, table.sgl, table.nents,
277 IOMMU_READ | IOMMU_WRITE) != size) {
278 seq_puts(s, "Failed to map_sg\n");
279 goto next;
280 }
281 getnstimeofday(&tafter);
282 diff = timespec_sub(tafter, tbefore);
283 map_elapsed_us = div_s64(timespec_to_ns(&diff), 1000);
284
285 getnstimeofday(&tbefore);
286 unmapped = iommu_unmap(domain, iova, size);
287 if (unmapped != size) {
288 seq_printf(s, "Only unmapped %zx instead of %zx\n",
289 unmapped, size);
290 goto next;
291 }
292 getnstimeofday(&tafter);
293 diff = timespec_sub(tafter, tbefore);
294 unmap_elapsed_us = div_s64(timespec_to_ns(&diff), 1000);
295
296 seq_printf(s, "%8s %12lld us %9lld us\n", _size_to_string(size),
297 map_elapsed_us, unmap_elapsed_us);
298
299next:
300 iommu_debug_destroy_phoney_sg_table(dev, &table, chunk_size);
301 }
302
303out_detach:
304 iommu_detach_device(domain, dev);
305out_domain_free:
306 iommu_domain_free(domain);
307}
308
Mitchel Humpherys7cc56e42015-07-06 14:58:23 -0700309static int iommu_debug_profiling_show(struct seq_file *s, void *ignored)
Mitchel Humpherys42296fb2015-06-23 16:29:16 -0700310{
311 struct iommu_debug_device *ddev = s->private;
312
313 iommu_debug_device_profiling(s, ddev->dev);
314
315 return 0;
316}
317
Mitchel Humpherys7cc56e42015-07-06 14:58:23 -0700318static int iommu_debug_profiling_open(struct inode *inode, struct file *file)
Mitchel Humpherys42296fb2015-06-23 16:29:16 -0700319{
Mitchel Humpherys7cc56e42015-07-06 14:58:23 -0700320 return single_open(file, iommu_debug_profiling_show, inode->i_private);
Mitchel Humpherys42296fb2015-06-23 16:29:16 -0700321}
322
Mitchel Humpherys7cc56e42015-07-06 14:58:23 -0700323static const struct file_operations iommu_debug_profiling_fops = {
324 .open = iommu_debug_profiling_open,
Mitchel Humpherys42296fb2015-06-23 16:29:16 -0700325 .read = seq_read,
326 .llseek = seq_lseek,
327 .release = single_release,
328};
329
Mitchel Humpherys0fe337d2015-07-06 15:21:24 -0700330static int iommu_debug_attach_do_attach(struct iommu_debug_device *ddev)
331{
332 ddev->domain = iommu_domain_alloc(&platform_bus_type);
333 if (!ddev->domain) {
334 pr_err("Couldn't allocate domain\n");
335 return -ENOMEM;
336 }
337
338 if (iommu_attach_device(ddev->domain, ddev->dev)) {
339 pr_err("Couldn't attach new domain to device. Is it already attached?\n");
340 goto out_domain_free;
341 }
342
343 return 0;
344
345out_domain_free:
346 iommu_domain_free(ddev->domain);
347 ddev->domain = NULL;
348 return -EIO;
349}
350
351static ssize_t iommu_debug_attach_write(struct file *file,
352 const char __user *ubuf,
353 size_t count, loff_t *offset)
354{
355 struct iommu_debug_device *ddev = file->private_data;
356 ssize_t retval;
357 char val;
358
359 if (count > 2) {
360 pr_err("Invalid value. Expected 0 or 1.\n");
361 retval = -EINVAL;
362 goto out;
363 }
364
365 if (copy_from_user(&val, ubuf, 1)) {
366 pr_err("Couldn't copy from user\n");
367 retval = -EFAULT;
368 goto out;
369 }
370
371 if (val == '1') {
372 if (ddev->domain) {
373 pr_err("Already attached.\n");
374 retval = -EINVAL;
375 goto out;
376 }
377 if (WARN(ddev->dev->archdata.iommu,
378 "Attachment tracking out of sync with device\n")) {
379 retval = -EINVAL;
380 goto out;
381 }
382 if (iommu_debug_attach_do_attach(ddev)) {
383 retval = -EIO;
384 goto out;
385 }
386 pr_err("Attached\n");
387 } else if (val == '0') {
388 if (!ddev->domain) {
389 pr_err("No domain. Did you already attach?\n");
390 retval = -EINVAL;
391 goto out;
392 }
393 iommu_detach_device(ddev->domain, ddev->dev);
394 iommu_domain_free(ddev->domain);
395 ddev->domain = NULL;
396 pr_err("Detached\n");
397 } else {
398 pr_err("Invalid value. Expected 0 or 1\n");
399 retval = -EFAULT;
400 goto out;
401 }
402
403 retval = count;
404out:
405 return retval;
406}
407
408static ssize_t iommu_debug_attach_read(struct file *file, char __user *ubuf,
409 size_t count, loff_t *offset)
410{
411 struct iommu_debug_device *ddev = file->private_data;
412 char c[2];
413
414 if (*offset)
415 return 0;
416
417 c[0] = ddev->domain ? '1' : '0';
418 c[1] = '\n';
419 if (copy_to_user(ubuf, &c, 2)) {
420 pr_err("copy_to_user failed\n");
421 return -EFAULT;
422 }
423 *offset = 1; /* non-zero means we're done */
424
425 return 2;
426}
427
428static const struct file_operations iommu_debug_attach_fops = {
429 .open = simple_open,
430 .write = iommu_debug_attach_write,
431 .read = iommu_debug_attach_read,
432};
433
434static ssize_t iommu_debug_atos_write(struct file *file,
435 const char __user *ubuf,
436 size_t count, loff_t *offset)
437{
438 struct iommu_debug_device *ddev = file->private_data;
439 dma_addr_t iova;
440
441 if (kstrtoll_from_user(ubuf, count, 0, &iova)) {
442 pr_err("Invalid format for iova\n");
443 ddev->iova = 0;
444 return -EINVAL;
445 }
446
447 ddev->iova = iova;
448 pr_err("Saved iova=%pa for future ATOS commands\n", &iova);
449 return count;
450}
451
452static ssize_t iommu_debug_atos_read(struct file *file, char __user *ubuf,
453 size_t count, loff_t *offset)
454{
455 struct iommu_debug_device *ddev = file->private_data;
456 phys_addr_t phys;
457 char buf[100];
458 ssize_t retval;
459 size_t buflen;
460
461 if (!ddev->domain) {
462 pr_err("No domain. Did you already attach?\n");
463 return -EINVAL;
464 }
465
466 if (*offset)
467 return 0;
468
469 memset(buf, 0, 100);
470
471 phys = iommu_iova_to_phys_hard(ddev->domain, ddev->iova);
472 if (!phys)
473 strlcpy(buf, "FAIL\n", 100);
474 else
475 snprintf(buf, 100, "%pa\n", &phys);
476
477 buflen = strlen(buf);
478 if (copy_to_user(ubuf, buf, buflen)) {
479 pr_err("Couldn't copy_to_user\n");
480 retval = -EFAULT;
481 } else {
482 *offset = 1; /* non-zero means we're done */
483 retval = buflen;
484 }
485
486 return retval;
487}
488
489static const struct file_operations iommu_debug_atos_fops = {
490 .open = simple_open,
491 .write = iommu_debug_atos_write,
492 .read = iommu_debug_atos_read,
493};
494
495static ssize_t iommu_debug_map_write(struct file *file, const char __user *ubuf,
496 size_t count, loff_t *offset)
497{
498 ssize_t retval;
499 int ret;
500 char *comma1, *comma2, *comma3;
501 char buf[100];
502 dma_addr_t iova;
503 phys_addr_t phys;
504 size_t size;
505 int prot;
506 struct iommu_debug_device *ddev = file->private_data;
507
508 if (count >= 100) {
509 pr_err("Value too large\n");
510 return -EINVAL;
511 }
512
513 if (!ddev->domain) {
514 pr_err("No domain. Did you already attach?\n");
515 return -EINVAL;
516 }
517
518 memset(buf, 0, 100);
519
520 if (copy_from_user(buf, ubuf, count)) {
521 pr_err("Couldn't copy from user\n");
522 retval = -EFAULT;
523 }
524
525 comma1 = strnchr(buf, count, ',');
526 if (!comma1)
527 goto invalid_format;
528
529 comma2 = strnchr(comma1 + 1, count, ',');
530 if (!comma2)
531 goto invalid_format;
532
533 comma3 = strnchr(comma2 + 1, count, ',');
534 if (!comma3)
535 goto invalid_format;
536
537 /* split up the words */
538 *comma1 = *comma2 = *comma3 = '\0';
539
540 if (kstrtou64(buf, 0, &iova))
541 goto invalid_format;
542
543 if (kstrtou64(comma1 + 1, 0, &phys))
544 goto invalid_format;
545
546 if (kstrtoul(comma2 + 1, 0, &size))
547 goto invalid_format;
548
549 if (kstrtoint(comma3 + 1, 0, &prot))
550 goto invalid_format;
551
552 ret = iommu_map(ddev->domain, iova, phys, size, prot);
553 if (ret) {
554 pr_err("iommu_map failed with %d\n", ret);
555 retval = -EIO;
556 goto out;
557 }
558
559 retval = count;
560 pr_err("Mapped %pa to %pa (len=0x%zx, prot=0x%x)\n",
561 &iova, &phys, size, prot);
562out:
563 return retval;
564
565invalid_format:
566 pr_err("Invalid format. Expected: iova,phys,len,prot where `prot' is the bitwise OR of IOMMU_READ, IOMMU_WRITE, etc.\n");
567 return -EINVAL;
568}
569
570static const struct file_operations iommu_debug_map_fops = {
571 .open = simple_open,
572 .write = iommu_debug_map_write,
573};
574
575static ssize_t iommu_debug_unmap_write(struct file *file,
576 const char __user *ubuf,
577 size_t count, loff_t *offset)
578{
579 ssize_t retval = 0;
580 char *comma1;
581 char buf[100];
582 dma_addr_t iova;
583 size_t size;
584 size_t unmapped;
585 struct iommu_debug_device *ddev = file->private_data;
586
587 if (count >= 100) {
588 pr_err("Value too large\n");
589 return -EINVAL;
590 }
591
592 if (!ddev->domain) {
593 pr_err("No domain. Did you already attach?\n");
594 return -EINVAL;
595 }
596
597 memset(buf, 0, 100);
598
599 if (copy_from_user(buf, ubuf, count)) {
600 pr_err("Couldn't copy from user\n");
601 retval = -EFAULT;
602 goto out;
603 }
604
605 comma1 = strnchr(buf, count, ',');
606 if (!comma1)
607 goto invalid_format;
608
609 /* split up the words */
610 *comma1 = '\0';
611
612 if (kstrtou64(buf, 0, &iova))
613 goto invalid_format;
614
615 if (kstrtoul(buf, 0, &size))
616 goto invalid_format;
617
618 unmapped = iommu_unmap(ddev->domain, iova, size);
619 if (unmapped != size) {
620 pr_err("iommu_unmap failed. Expected to unmap: 0x%zx, unmapped: 0x%zx",
621 size, unmapped);
622 return -EIO;
623 }
624
625 retval = count;
626 pr_err("Unmapped %pa (len=0x%zx)\n", &iova, size);
627out:
628 return retval;
629
630invalid_format:
631 pr_err("Invalid format. Expected: iova,len\n");
632 return retval;
633}
634
635static const struct file_operations iommu_debug_unmap_fops = {
636 .open = simple_open,
637 .write = iommu_debug_unmap_write,
638};
639
Mitchel Humpherys42296fb2015-06-23 16:29:16 -0700640/*
641 * The following will only work for drivers that implement the generic
642 * device tree bindings described in
643 * Documentation/devicetree/bindings/iommu/iommu.txt
644 */
645static int snarf_iommu_devices(struct device *dev, void *ignored)
646{
647 struct iommu_debug_device *ddev;
Mitchel Humpherys0fe337d2015-07-06 15:21:24 -0700648 struct dentry *dir;
Mitchel Humpherys42296fb2015-06-23 16:29:16 -0700649
650 if (!of_find_property(dev->of_node, "iommus", NULL))
651 return 0;
652
653 ddev = kmalloc(sizeof(*ddev), GFP_KERNEL);
654 if (!ddev)
655 return -ENODEV;
656 ddev->dev = dev;
657 dir = debugfs_create_dir(dev_name(dev), debugfs_tests_dir);
658 if (!dir) {
659 pr_err("Couldn't create iommu/devices/%s debugfs dir\n",
660 dev_name(dev));
661 goto err;
662 }
Mitchel Humpherys0fe337d2015-07-06 15:21:24 -0700663
664 if (!debugfs_create_file("profiling", S_IRUSR, dir, ddev,
665 &iommu_debug_profiling_fops)) {
Mitchel Humpherys42296fb2015-06-23 16:29:16 -0700666 pr_err("Couldn't create iommu/devices/%s/profiling debugfs file\n",
667 dev_name(dev));
668 goto err_rmdir;
669 }
670
Mitchel Humpherys0fe337d2015-07-06 15:21:24 -0700671 if (!debugfs_create_file("attach", S_IRUSR, dir, ddev,
672 &iommu_debug_attach_fops)) {
673 pr_err("Couldn't create iommu/devices/%s/attach debugfs file\n",
674 dev_name(dev));
675 goto err_rmdir;
676 }
677
678 if (!debugfs_create_file("atos", S_IWUSR, dir, ddev,
679 &iommu_debug_atos_fops)) {
680 pr_err("Couldn't create iommu/devices/%s/atos debugfs file\n",
681 dev_name(dev));
682 goto err_rmdir;
683 }
684
685 if (!debugfs_create_file("map", S_IWUSR, dir, ddev,
686 &iommu_debug_map_fops)) {
687 pr_err("Couldn't create iommu/devices/%s/map debugfs file\n",
688 dev_name(dev));
689 goto err_rmdir;
690 }
691
692 if (!debugfs_create_file("unmap", S_IWUSR, dir, ddev,
693 &iommu_debug_unmap_fops)) {
694 pr_err("Couldn't create iommu/devices/%s/unmap debugfs file\n",
695 dev_name(dev));
696 goto err_rmdir;
697 }
698
Mitchel Humpherys42296fb2015-06-23 16:29:16 -0700699 list_add(&ddev->list, &iommu_debug_devices);
700 return 0;
701
702err_rmdir:
703 debugfs_remove_recursive(dir);
704err:
705 kfree(ddev);
706 return 0;
707}
708
709static int iommu_debug_init_tests(void)
710{
711 debugfs_tests_dir = debugfs_create_dir("tests",
712 debugfs_top_dir);
713 if (!debugfs_tests_dir) {
714 pr_err("Couldn't create iommu/tests debugfs directory\n");
715 return -ENODEV;
716 }
717
718 return bus_for_each_dev(&platform_bus_type, NULL, NULL,
719 snarf_iommu_devices);
720}
721#else
722static inline int iommu_debug_init_tests(void) { return 0; }
723#endif
724
725static int iommu_debug_init(void)
726{
727 debugfs_top_dir = debugfs_create_dir("iommu", NULL);
728 if (!debugfs_top_dir) {
729 pr_err("Couldn't create iommu debugfs directory\n");
730 return -ENODEV;
731 }
732
733 if (iommu_debug_init_tracking())
734 goto err;
735
736 if (iommu_debug_init_tests())
737 goto err;
738
739 return 0;
740err:
741 debugfs_remove_recursive(debugfs_top_dir);
742 return -ENODEV;
743}
744
745static void iommu_debug_exit(void)
746{
747 debugfs_remove_recursive(debugfs_top_dir);
748}
749
750module_init(iommu_debug_init);
751module_exit(iommu_debug_exit);