blob: febd9225a676dfb586e4a5d82c5ae982b9ffe441 [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 Humpherys5e991f12015-07-30 19:25:54 -070025#include <soc/qcom/secure_buffer.h>
Mitchel Humpherys42296fb2015-06-23 16:29:16 -070026
Mitchel Humpherys42296fb2015-06-23 16:29:16 -070027#ifdef CONFIG_IOMMU_DEBUG_TRACKING
28
29static DEFINE_MUTEX(iommu_debug_attachments_lock);
30static LIST_HEAD(iommu_debug_attachments);
31static struct dentry *debugfs_attachments_dir;
32
33struct iommu_debug_attachment {
34 struct iommu_domain *domain;
35 struct device *dev;
36 struct dentry *dentry;
37 struct list_head list;
Mitchel Humpherys0dc04de2015-08-21 14:08:40 -070038 unsigned long reg_offset;
Mitchel Humpherys42296fb2015-06-23 16:29:16 -070039};
40
Mitchel Humpherys088cc582015-07-09 15:02:03 -070041static int iommu_debug_attachment_info_show(struct seq_file *s, void *ignored)
Mitchel Humpherys42296fb2015-06-23 16:29:16 -070042{
43 struct iommu_debug_attachment *attach = s->private;
Mitchel Humpherys5e991f12015-07-30 19:25:54 -070044 int secure_vmid;
Mitchel Humpherys42296fb2015-06-23 16:29:16 -070045
46 seq_printf(s, "Domain: 0x%p\n", attach->domain);
Mitchel Humpherys5e991f12015-07-30 19:25:54 -070047
48 seq_puts(s, "SECURE_VMID: ");
49 if (iommu_domain_get_attr(attach->domain,
50 DOMAIN_ATTR_SECURE_VMID,
51 &secure_vmid))
52 seq_puts(s, "(Unknown)\n");
53 else
54 seq_printf(s, "%s (0x%x)\n",
55 msm_secure_vmid_to_string(secure_vmid), secure_vmid);
56
Mitchel Humpherys42296fb2015-06-23 16:29:16 -070057 return 0;
58}
59
Mitchel Humpherys088cc582015-07-09 15:02:03 -070060static int iommu_debug_attachment_info_open(struct inode *inode,
61 struct file *file)
Mitchel Humpherys42296fb2015-06-23 16:29:16 -070062{
Mitchel Humpherys088cc582015-07-09 15:02:03 -070063 return single_open(file, iommu_debug_attachment_info_show,
64 inode->i_private);
Mitchel Humpherys42296fb2015-06-23 16:29:16 -070065}
66
Mitchel Humpherys088cc582015-07-09 15:02:03 -070067static const struct file_operations iommu_debug_attachment_info_fops = {
68 .open = iommu_debug_attachment_info_open,
Mitchel Humpherys42296fb2015-06-23 16:29:16 -070069 .read = seq_read,
70 .llseek = seq_lseek,
71 .release = single_release,
72};
73
Mitchel Humpherys288086e2015-07-09 16:55:08 -070074static ssize_t iommu_debug_attachment_trigger_fault_write(
75 struct file *file, const char __user *ubuf, size_t count,
76 loff_t *offset)
77{
78 struct iommu_debug_attachment *attach = file->private_data;
79 unsigned long flags;
80
81 if (kstrtoul_from_user(ubuf, count, 0, &flags)) {
82 pr_err("Invalid flags format\n");
83 return -EFAULT;
84 }
85
86 iommu_trigger_fault(attach->domain, flags);
87
88 return count;
89}
90
91static const struct file_operations
92iommu_debug_attachment_trigger_fault_fops = {
93 .open = simple_open,
94 .write = iommu_debug_attachment_trigger_fault_write,
95};
96
Mitchel Humpherys0dc04de2015-08-21 14:08:40 -070097static ssize_t iommu_debug_attachment_reg_offset_write(
98 struct file *file, const char __user *ubuf, size_t count,
99 loff_t *offset)
100{
101 struct iommu_debug_attachment *attach = file->private_data;
102 unsigned long reg_offset;
103
104 if (kstrtoul_from_user(ubuf, count, 0, &reg_offset)) {
105 pr_err("Invalid reg_offset format\n");
106 return -EFAULT;
107 }
108
109 attach->reg_offset = reg_offset;
110
111 return count;
112}
113
114static const struct file_operations iommu_debug_attachment_reg_offset_fops = {
115 .open = simple_open,
116 .write = iommu_debug_attachment_reg_offset_write,
117};
118
119static ssize_t iommu_debug_attachment_reg_read_read(
120 struct file *file, char __user *ubuf, size_t count, loff_t *offset)
121{
122 struct iommu_debug_attachment *attach = file->private_data;
123 unsigned long val;
124 char *val_str;
125 ssize_t val_str_len;
126
127 if (*offset)
128 return 0;
129
130 val = iommu_reg_read(attach->domain, attach->reg_offset);
131 val_str = kasprintf(GFP_KERNEL, "0x%lx\n", val);
132 if (!val_str)
133 return -ENOMEM;
134 val_str_len = strlen(val_str);
135
136 if (copy_to_user(ubuf, val_str, val_str_len)) {
137 pr_err("copy_to_user failed\n");
138 val_str_len = -EFAULT;
139 goto out;
140 }
141 *offset = 1; /* non-zero means we're done */
142
143out:
144 kfree(val_str);
145 return val_str_len;
146}
147
148static const struct file_operations iommu_debug_attachment_reg_read_fops = {
149 .open = simple_open,
150 .read = iommu_debug_attachment_reg_read_read,
151};
152
153static ssize_t iommu_debug_attachment_reg_write_write(
154 struct file *file, const char __user *ubuf, size_t count,
155 loff_t *offset)
156{
157 struct iommu_debug_attachment *attach = file->private_data;
158 unsigned long val;
159
160 if (kstrtoul_from_user(ubuf, count, 0, &val)) {
161 pr_err("Invalid val format\n");
162 return -EFAULT;
163 }
164
165 iommu_reg_write(attach->domain, attach->reg_offset, val);
166
167 return count;
168}
169
170static const struct file_operations iommu_debug_attachment_reg_write_fops = {
171 .open = simple_open,
172 .write = iommu_debug_attachment_reg_write_write,
173};
174
Mitchel Humpherysa05b2522015-07-14 14:30:33 -0700175/* should be called with iommu_debug_attachments_lock locked */
176static int iommu_debug_attach_add_debugfs(
177 struct iommu_debug_attachment *attach)
Mitchel Humpherys42296fb2015-06-23 16:29:16 -0700178{
Mitchel Humpherys54379212015-08-26 11:52:57 -0700179 const char *attach_name;
Mitchel Humpherysa05b2522015-07-14 14:30:33 -0700180 struct device *dev = attach->dev;
181 struct iommu_domain *domain = attach->domain;
Mitchel Humpherys54379212015-08-26 11:52:57 -0700182 int is_dynamic;
Mitchel Humpherys42296fb2015-06-23 16:29:16 -0700183
Mitchel Humpherys54379212015-08-26 11:52:57 -0700184 if (iommu_domain_get_attr(domain, DOMAIN_ATTR_DYNAMIC, &is_dynamic))
185 is_dynamic = 0;
186
187 if (is_dynamic) {
188 uuid_le uuid;
189
190 uuid_le_gen(&uuid);
191 attach_name = kasprintf(GFP_KERNEL, "%s-%pUl", dev_name(dev),
192 uuid.b);
193 if (!attach_name)
194 return -ENOMEM;
195 } else {
196 attach_name = dev_name(dev);
197 }
Mitchel Humpherys42296fb2015-06-23 16:29:16 -0700198
Mitchel Humpherys088cc582015-07-09 15:02:03 -0700199 attach->dentry = debugfs_create_dir(attach_name,
200 debugfs_attachments_dir);
Mitchel Humpherys42296fb2015-06-23 16:29:16 -0700201 if (!attach->dentry) {
Mitchel Humpherys088cc582015-07-09 15:02:03 -0700202 pr_err("Couldn't create iommu/attachments/%s debugfs directory for domain 0x%p\n",
Mitchel Humpherys876e2be2015-07-10 11:56:56 -0700203 attach_name, domain);
Mitchel Humpherys54379212015-08-26 11:52:57 -0700204 if (is_dynamic)
205 kfree(attach_name);
Mitchel Humpherysa05b2522015-07-14 14:30:33 -0700206 return -EIO;
Mitchel Humpherys42296fb2015-06-23 16:29:16 -0700207 }
Mitchel Humpherys54379212015-08-26 11:52:57 -0700208
209 if (is_dynamic)
210 kfree(attach_name);
Mitchel Humpherys42296fb2015-06-23 16:29:16 -0700211
Mitchel Humpherys088cc582015-07-09 15:02:03 -0700212 if (!debugfs_create_file(
213 "info", S_IRUSR, attach->dentry, attach,
214 &iommu_debug_attachment_info_fops)) {
215 pr_err("Couldn't create iommu/attachments/%s/info debugfs file for domain 0x%p\n",
216 dev_name(dev), domain);
Mitchel Humpherysa05b2522015-07-14 14:30:33 -0700217 goto err_rmdir;
Mitchel Humpherys088cc582015-07-09 15:02:03 -0700218 }
219
Mitchel Humpherys288086e2015-07-09 16:55:08 -0700220 if (!debugfs_create_file(
221 "trigger_fault", S_IRUSR, attach->dentry, attach,
222 &iommu_debug_attachment_trigger_fault_fops)) {
223 pr_err("Couldn't create iommu/attachments/%s/trigger_fault debugfs file for domain 0x%p\n",
224 dev_name(dev), domain);
225 goto err_rmdir;
Mitchel Humpherys0dc04de2015-08-21 14:08:40 -0700226 }
227
228 if (!debugfs_create_file(
229 "reg_offset", S_IRUSR, attach->dentry, attach,
230 &iommu_debug_attachment_reg_offset_fops)) {
231 pr_err("Couldn't create iommu/attachments/%s/reg_offset debugfs file for domain 0x%p\n",
232 dev_name(dev), domain);
233 goto err_rmdir;
234 }
235
236 if (!debugfs_create_file(
237 "reg_read", S_IRUSR, attach->dentry, attach,
238 &iommu_debug_attachment_reg_read_fops)) {
239 pr_err("Couldn't create iommu/attachments/%s/reg_read debugfs file for domain 0x%p\n",
240 dev_name(dev), domain);
241 goto err_rmdir;
242 }
243
244 if (!debugfs_create_file(
245 "reg_write", S_IRUSR, attach->dentry, attach,
246 &iommu_debug_attachment_reg_write_fops)) {
247 pr_err("Couldn't create iommu/attachments/%s/reg_write debugfs file for domain 0x%p\n",
248 dev_name(dev), domain);
249 goto err_rmdir;
250 }
251
Mitchel Humpherysa05b2522015-07-14 14:30:33 -0700252 return 0;
253
254err_rmdir:
255 debugfs_remove_recursive(attach->dentry);
256 return -EIO;
257}
258
Susheel Khianie66aa5b2015-08-25 17:25:42 +0530259void iommu_debug_domain_add(struct iommu_domain *domain)
Mitchel Humpherysa05b2522015-07-14 14:30:33 -0700260{
261 struct iommu_debug_attachment *attach;
262
263 mutex_lock(&iommu_debug_attachments_lock);
264
265 attach = kmalloc(sizeof(*attach), GFP_KERNEL);
266 if (!attach)
267 goto out_unlock;
268
269 attach->domain = domain;
Susheel Khianie66aa5b2015-08-25 17:25:42 +0530270 attach->dev = NULL;
Mitchel Humpherys42296fb2015-06-23 16:29:16 -0700271 list_add(&attach->list, &iommu_debug_attachments);
Susheel Khianie66aa5b2015-08-25 17:25:42 +0530272
Mitchel Humpherysa05b2522015-07-14 14:30:33 -0700273out_unlock:
Mitchel Humpherys42296fb2015-06-23 16:29:16 -0700274 mutex_unlock(&iommu_debug_attachments_lock);
275}
276
Susheel Khianie66aa5b2015-08-25 17:25:42 +0530277void iommu_debug_domain_remove(struct iommu_domain *domain)
278{
279 struct iommu_debug_attachment *it;
280
281 mutex_lock(&iommu_debug_attachments_lock);
282 list_for_each_entry(it, &iommu_debug_attachments, list)
283 if (it->domain == domain && it->dev == NULL)
284 break;
285
286 if (&it->list == &iommu_debug_attachments) {
287 WARN(1, "Couldn't find debug attachment for domain=0x%p",
288 domain);
289 } else {
290 list_del(&it->list);
291 kfree(it);
292 }
293 mutex_unlock(&iommu_debug_attachments_lock);
294}
295
296void iommu_debug_attach_device(struct iommu_domain *domain,
297 struct device *dev)
298{
299 struct iommu_debug_attachment *attach;
300
301 mutex_lock(&iommu_debug_attachments_lock);
302
303 list_for_each_entry(attach, &iommu_debug_attachments, list)
304 if (attach->domain == domain && attach->dev == NULL)
305 break;
306
307 if (&attach->list == &iommu_debug_attachments) {
308 WARN(1, "Couldn't find debug attachment for domain=0x%p dev=%s",
309 domain, dev_name(dev));
310 } else {
311 attach->dev = dev;
312
313 /*
314 * we might not init until after other drivers start calling
315 * iommu_attach_device. Only set up the debugfs nodes if we've
316 * already init'd to avoid polluting the top-level debugfs
317 * directory (by calling debugfs_create_dir with a NULL
318 * parent). These will be flushed out later once we init.
319 */
320
321 if (debugfs_attachments_dir)
322 iommu_debug_attach_add_debugfs(attach);
323 }
324
325 mutex_unlock(&iommu_debug_attachments_lock);
326}
327
Mitchel Humpherys42296fb2015-06-23 16:29:16 -0700328void iommu_debug_detach_device(struct iommu_domain *domain,
329 struct device *dev)
330{
331 struct iommu_debug_attachment *it;
332
333 mutex_lock(&iommu_debug_attachments_lock);
334 list_for_each_entry(it, &iommu_debug_attachments, list)
335 if (it->domain == domain && it->dev == dev)
336 break;
337
338 if (&it->list == &iommu_debug_attachments) {
339 WARN(1, "Couldn't find debug attachment for domain=0x%p dev=%s",
340 domain, dev_name(dev));
341 } else {
Susheel Khianie66aa5b2015-08-25 17:25:42 +0530342 /*
343 * Just remove debugfs entry and mark dev as NULL on
344 * iommu_detach call. We would remove the actual
345 * attachment entry from the list only on domain_free call.
346 * This is to ensure we keep track of unattached domains too.
347 */
348
Mitchel Humpherys42296fb2015-06-23 16:29:16 -0700349 debugfs_remove_recursive(it->dentry);
Susheel Khianie66aa5b2015-08-25 17:25:42 +0530350 it->dev = NULL;
Mitchel Humpherys42296fb2015-06-23 16:29:16 -0700351 }
352 mutex_unlock(&iommu_debug_attachments_lock);
353}
354
355static int iommu_debug_init_tracking(void)
356{
Mitchel Humpherysa05b2522015-07-14 14:30:33 -0700357 int ret = 0;
358 struct iommu_debug_attachment *attach;
359
360 mutex_lock(&iommu_debug_attachments_lock);
Mitchel Humpherys42296fb2015-06-23 16:29:16 -0700361 debugfs_attachments_dir = debugfs_create_dir("attachments",
Mitchel Humpherysc75ae492015-07-15 18:27:36 -0700362 iommu_debugfs_top);
Mitchel Humpherys42296fb2015-06-23 16:29:16 -0700363 if (!debugfs_attachments_dir) {
364 pr_err("Couldn't create iommu/attachments debugfs directory\n");
Mitchel Humpherysa05b2522015-07-14 14:30:33 -0700365 ret = -ENODEV;
366 goto out_unlock;
Mitchel Humpherys42296fb2015-06-23 16:29:16 -0700367 }
368
Mitchel Humpherysa05b2522015-07-14 14:30:33 -0700369 /* set up debugfs entries for attachments made during early boot */
370 list_for_each_entry(attach, &iommu_debug_attachments, list)
Susheel Khianie66aa5b2015-08-25 17:25:42 +0530371 if (attach->dev)
372 iommu_debug_attach_add_debugfs(attach);
Mitchel Humpherysa05b2522015-07-14 14:30:33 -0700373
374out_unlock:
375 mutex_unlock(&iommu_debug_attachments_lock);
376 return ret;
Mitchel Humpherys42296fb2015-06-23 16:29:16 -0700377}
Mitchel Humpherysc75ae492015-07-15 18:27:36 -0700378
379static void iommu_debug_destroy_tracking(void)
380{
381 debugfs_remove_recursive(debugfs_attachments_dir);
382}
Mitchel Humpherys42296fb2015-06-23 16:29:16 -0700383#else
384static inline int iommu_debug_init_tracking(void) { return 0; }
Mitchel Humpherysc75ae492015-07-15 18:27:36 -0700385static inline void iommu_debug_destroy_tracking(void) { }
Mitchel Humpherys42296fb2015-06-23 16:29:16 -0700386#endif
387
388#ifdef CONFIG_IOMMU_TESTS
389
390static LIST_HEAD(iommu_debug_devices);
391static struct dentry *debugfs_tests_dir;
Patrick Dalye4e39862015-11-20 20:00:50 -0800392static u32 iters_per_op = 1;
Mitchel Humpherys42296fb2015-06-23 16:29:16 -0700393
394struct iommu_debug_device {
395 struct device *dev;
Mitchel Humpherys0fe337d2015-07-06 15:21:24 -0700396 struct iommu_domain *domain;
397 u64 iova;
398 u64 phys;
399 size_t len;
Mitchel Humpherys42296fb2015-06-23 16:29:16 -0700400 struct list_head list;
401};
402
403static int iommu_debug_build_phoney_sg_table(struct device *dev,
404 struct sg_table *table,
405 unsigned long total_size,
406 unsigned long chunk_size)
407{
408 unsigned long nents = total_size / chunk_size;
409 struct scatterlist *sg;
410 int i;
411 struct page *page;
412
413 if (!IS_ALIGNED(total_size, PAGE_SIZE))
414 return -EINVAL;
415 if (!IS_ALIGNED(total_size, chunk_size))
416 return -EINVAL;
417 if (sg_alloc_table(table, nents, GFP_KERNEL))
418 return -EINVAL;
419 page = alloc_pages(GFP_KERNEL, get_order(chunk_size));
420 if (!page)
421 goto free_table;
422
423 /* all the same page... why not. */
424 for_each_sg(table->sgl, sg, table->nents, i)
425 sg_set_page(sg, page, chunk_size, 0);
426
427 return 0;
428
429free_table:
430 sg_free_table(table);
431 return -ENOMEM;
432}
433
434static void iommu_debug_destroy_phoney_sg_table(struct device *dev,
435 struct sg_table *table,
436 unsigned long chunk_size)
437{
438 __free_pages(sg_page(table->sgl), get_order(chunk_size));
439 sg_free_table(table);
440}
441
442static const char * const _size_to_string(unsigned long size)
443{
444 switch (size) {
445 case SZ_4K:
446 return "4K";
447 case SZ_64K:
448 return "64K";
449 case SZ_2M:
450 return "2M";
451 case SZ_1M * 12:
452 return "12M";
453 case SZ_1M * 20:
454 return "20M";
455 }
456 return "unknown size, please add to _size_to_string";
457}
458
Patrick Dalye4e39862015-11-20 20:00:50 -0800459static int nr_iters_set(void *data, u64 val)
460{
461 if (!val)
462 val = 1;
463 if (val > 10000)
464 val = 10000;
465 *(u32 *)data = val;
466 return 0;
467}
468
469static int nr_iters_get(void *data, u64 *val)
470{
471 *val = *(u32 *)data;
472 return 0;
473}
474
475DEFINE_SIMPLE_ATTRIBUTE(iommu_debug_nr_iters_ops,
476 nr_iters_get, nr_iters_set, "%llu\n");
Mitchel Humpherys1c47bb52015-10-02 16:17:57 -0700477
Mitchel Humpherys020f90f2015-10-02 16:02:31 -0700478static void iommu_debug_device_profiling(struct seq_file *s, struct device *dev,
479 bool secure)
Mitchel Humpherys42296fb2015-06-23 16:29:16 -0700480{
481 unsigned long sizes[] = { SZ_4K, SZ_64K, SZ_2M, SZ_1M * 12,
482 SZ_1M * 20, 0 };
483 unsigned long *sz;
484 struct iommu_domain *domain;
485 unsigned long iova = 0x10000;
486 phys_addr_t paddr = 0xa000;
Mitchel Humpherys679567c2015-08-28 10:51:24 -0700487 int atomic_domain = 1;
Mitchel Humpherys42296fb2015-06-23 16:29:16 -0700488
489 domain = iommu_domain_alloc(&platform_bus_type);
490 if (!domain) {
491 seq_puts(s, "Couldn't allocate domain\n");
492 return;
493 }
494
Mitchel Humpherys679567c2015-08-28 10:51:24 -0700495 if (iommu_domain_set_attr(domain, DOMAIN_ATTR_ATOMIC,
496 &atomic_domain)) {
497 seq_printf(s, "Couldn't set atomic_domain to %d\n",
498 atomic_domain);
499 goto out_domain_free;
500 }
501
Mitchel Humpherys020f90f2015-10-02 16:02:31 -0700502 if (secure) {
503 int secure_vmid = VMID_CP_PIXEL;
504
505 if (iommu_domain_set_attr(domain, DOMAIN_ATTR_SECURE_VMID,
506 &secure_vmid)) {
507 seq_printf(s, "Couldn't set secure vmid to %d\n",
508 secure_vmid);
509 goto out_domain_free;
510 }
511 }
512
Mitchel Humpherys42296fb2015-06-23 16:29:16 -0700513 if (iommu_attach_device(domain, dev)) {
514 seq_puts(s,
515 "Couldn't attach new domain to device. Is it already attached?\n");
516 goto out_domain_free;
517 }
518
Patrick Dalye4e39862015-11-20 20:00:50 -0800519 seq_printf(s, "(average over %d iterations)\n", iters_per_op);
Patrick Daly3ca31e32015-11-20 20:33:04 -0800520 seq_printf(s, "%8s %19s %16s\n", "size", "iommu_map", "iommu_unmap");
Mitchel Humpherys42296fb2015-06-23 16:29:16 -0700521 for (sz = sizes; *sz; ++sz) {
522 unsigned long size = *sz;
523 size_t unmapped;
Patrick Daly3ca31e32015-11-20 20:33:04 -0800524 u64 map_elapsed_ns = 0, unmap_elapsed_ns = 0;
Mitchel Humpherys1c47bb52015-10-02 16:17:57 -0700525 u64 map_elapsed_us = 0, unmap_elapsed_us = 0;
Patrick Daly3ca31e32015-11-20 20:33:04 -0800526 u32 map_elapsed_rem = 0, unmap_elapsed_rem = 0;
Mitchel Humpherys42296fb2015-06-23 16:29:16 -0700527 struct timespec tbefore, tafter, diff;
Mitchel Humpherys1c47bb52015-10-02 16:17:57 -0700528 int i;
Mitchel Humpherys42296fb2015-06-23 16:29:16 -0700529
Patrick Dalye4e39862015-11-20 20:00:50 -0800530 for (i = 0; i < iters_per_op; ++i) {
Mitchel Humpherys1c47bb52015-10-02 16:17:57 -0700531 getnstimeofday(&tbefore);
532 if (iommu_map(domain, iova, paddr, size,
533 IOMMU_READ | IOMMU_WRITE)) {
534 seq_puts(s, "Failed to map\n");
535 continue;
536 }
537 getnstimeofday(&tafter);
538 diff = timespec_sub(tafter, tbefore);
Patrick Daly3ca31e32015-11-20 20:33:04 -0800539 map_elapsed_ns += timespec_to_ns(&diff);
Mitchel Humpherys42296fb2015-06-23 16:29:16 -0700540
Mitchel Humpherys1c47bb52015-10-02 16:17:57 -0700541 getnstimeofday(&tbefore);
542 unmapped = iommu_unmap(domain, iova, size);
543 if (unmapped != size) {
544 seq_printf(s,
545 "Only unmapped %zx instead of %zx\n",
546 unmapped, size);
547 continue;
548 }
549 getnstimeofday(&tafter);
550 diff = timespec_sub(tafter, tbefore);
Patrick Daly3ca31e32015-11-20 20:33:04 -0800551 unmap_elapsed_ns += timespec_to_ns(&diff);
Mitchel Humpherys42296fb2015-06-23 16:29:16 -0700552 }
Mitchel Humpherys1c47bb52015-10-02 16:17:57 -0700553
Patrick Daly3ca31e32015-11-20 20:33:04 -0800554 map_elapsed_ns /= iters_per_op;
555 unmap_elapsed_ns /= iters_per_op;
Mitchel Humpherys42296fb2015-06-23 16:29:16 -0700556
Patrick Daly3ca31e32015-11-20 20:33:04 -0800557 map_elapsed_us = div_u64_rem(map_elapsed_ns, 1000,
558 &map_elapsed_rem);
559 unmap_elapsed_us = div_u64_rem(unmap_elapsed_ns, 1000,
560 &unmap_elapsed_rem);
561
562 seq_printf(s, "%8s %12lld.%03d us %9lld.%03d us\n",
563 _size_to_string(size),
564 map_elapsed_us, map_elapsed_rem,
565 unmap_elapsed_us, unmap_elapsed_rem);
Mitchel Humpherys42296fb2015-06-23 16:29:16 -0700566 }
567
568 seq_putc(s, '\n');
Patrick Daly3ca31e32015-11-20 20:33:04 -0800569 seq_printf(s, "%8s %19s %16s\n", "size", "iommu_map_sg", "iommu_unmap");
Mitchel Humpherys42296fb2015-06-23 16:29:16 -0700570 for (sz = sizes; *sz; ++sz) {
571 unsigned long size = *sz;
572 size_t unmapped;
Patrick Daly3ca31e32015-11-20 20:33:04 -0800573 u64 map_elapsed_ns = 0, unmap_elapsed_ns = 0;
Mitchel Humpherys1c47bb52015-10-02 16:17:57 -0700574 u64 map_elapsed_us = 0, unmap_elapsed_us = 0;
Patrick Daly3ca31e32015-11-20 20:33:04 -0800575 u32 map_elapsed_rem = 0, unmap_elapsed_rem = 0;
Mitchel Humpherys42296fb2015-06-23 16:29:16 -0700576 struct timespec tbefore, tafter, diff;
577 struct sg_table table;
578 unsigned long chunk_size = SZ_4K;
Mitchel Humpherys1c47bb52015-10-02 16:17:57 -0700579 int i;
Mitchel Humpherys42296fb2015-06-23 16:29:16 -0700580
581 if (iommu_debug_build_phoney_sg_table(dev, &table, size,
582 chunk_size)) {
583 seq_puts(s,
584 "couldn't build phoney sg table! bailing...\n");
585 goto out_detach;
586 }
587
Patrick Dalye4e39862015-11-20 20:00:50 -0800588 for (i = 0; i < iters_per_op; ++i) {
Mitchel Humpherys1c47bb52015-10-02 16:17:57 -0700589 getnstimeofday(&tbefore);
590 if (iommu_map_sg(domain, iova, table.sgl, table.nents,
591 IOMMU_READ | IOMMU_WRITE) != size) {
592 seq_puts(s, "Failed to map_sg\n");
593 goto next;
594 }
595 getnstimeofday(&tafter);
596 diff = timespec_sub(tafter, tbefore);
Patrick Daly3ca31e32015-11-20 20:33:04 -0800597 map_elapsed_ns += timespec_to_ns(&diff);
Mitchel Humpherys42296fb2015-06-23 16:29:16 -0700598
Mitchel Humpherys1c47bb52015-10-02 16:17:57 -0700599 getnstimeofday(&tbefore);
600 unmapped = iommu_unmap(domain, iova, size);
601 if (unmapped != size) {
602 seq_printf(s,
603 "Only unmapped %zx instead of %zx\n",
604 unmapped, size);
605 goto next;
606 }
607 getnstimeofday(&tafter);
608 diff = timespec_sub(tafter, tbefore);
Patrick Daly3ca31e32015-11-20 20:33:04 -0800609 unmap_elapsed_ns += timespec_to_ns(&diff);
Mitchel Humpherys42296fb2015-06-23 16:29:16 -0700610 }
Mitchel Humpherys1c47bb52015-10-02 16:17:57 -0700611
Patrick Daly3ca31e32015-11-20 20:33:04 -0800612 map_elapsed_ns /= iters_per_op;
613 unmap_elapsed_ns /= iters_per_op;
Mitchel Humpherys42296fb2015-06-23 16:29:16 -0700614
Patrick Daly3ca31e32015-11-20 20:33:04 -0800615 map_elapsed_us = div_u64_rem(map_elapsed_ns, 1000,
616 &map_elapsed_rem);
617 unmap_elapsed_us = div_u64_rem(unmap_elapsed_ns, 1000,
618 &unmap_elapsed_rem);
619
620 seq_printf(s, "%8s %12lld.%03d us %9lld.%03d us\n",
621 _size_to_string(size),
622 map_elapsed_us, map_elapsed_rem,
623 unmap_elapsed_us, unmap_elapsed_rem);
Mitchel Humpherys42296fb2015-06-23 16:29:16 -0700624
625next:
626 iommu_debug_destroy_phoney_sg_table(dev, &table, chunk_size);
627 }
628
629out_detach:
630 iommu_detach_device(domain, dev);
631out_domain_free:
632 iommu_domain_free(domain);
633}
634
Mitchel Humpherys7cc56e42015-07-06 14:58:23 -0700635static int iommu_debug_profiling_show(struct seq_file *s, void *ignored)
Mitchel Humpherys42296fb2015-06-23 16:29:16 -0700636{
637 struct iommu_debug_device *ddev = s->private;
638
Mitchel Humpherys020f90f2015-10-02 16:02:31 -0700639 iommu_debug_device_profiling(s, ddev->dev, false);
Mitchel Humpherys42296fb2015-06-23 16:29:16 -0700640
641 return 0;
642}
643
Mitchel Humpherys7cc56e42015-07-06 14:58:23 -0700644static int iommu_debug_profiling_open(struct inode *inode, struct file *file)
Mitchel Humpherys42296fb2015-06-23 16:29:16 -0700645{
Mitchel Humpherys7cc56e42015-07-06 14:58:23 -0700646 return single_open(file, iommu_debug_profiling_show, inode->i_private);
Mitchel Humpherys42296fb2015-06-23 16:29:16 -0700647}
648
Mitchel Humpherys7cc56e42015-07-06 14:58:23 -0700649static const struct file_operations iommu_debug_profiling_fops = {
650 .open = iommu_debug_profiling_open,
Mitchel Humpherys42296fb2015-06-23 16:29:16 -0700651 .read = seq_read,
652 .llseek = seq_lseek,
653 .release = single_release,
654};
655
Mitchel Humpherys020f90f2015-10-02 16:02:31 -0700656static int iommu_debug_secure_profiling_show(struct seq_file *s, void *ignored)
657{
658 struct iommu_debug_device *ddev = s->private;
659
660 iommu_debug_device_profiling(s, ddev->dev, true);
661
662 return 0;
663}
664
665static int iommu_debug_secure_profiling_open(struct inode *inode,
666 struct file *file)
667{
668 return single_open(file, iommu_debug_secure_profiling_show,
669 inode->i_private);
670}
671
672static const struct file_operations iommu_debug_secure_profiling_fops = {
673 .open = iommu_debug_secure_profiling_open,
674 .read = seq_read,
675 .llseek = seq_lseek,
676 .release = single_release,
677};
678
Mitchel Humpherysac4c38b2015-07-30 19:40:21 -0700679static int iommu_debug_attach_do_attach(struct iommu_debug_device *ddev,
680 int val, bool is_secure)
Mitchel Humpherys0fe337d2015-07-06 15:21:24 -0700681{
682 ddev->domain = iommu_domain_alloc(&platform_bus_type);
683 if (!ddev->domain) {
684 pr_err("Couldn't allocate domain\n");
685 return -ENOMEM;
686 }
687
Mitchel Humpherysac4c38b2015-07-30 19:40:21 -0700688 if (is_secure && iommu_domain_set_attr(ddev->domain,
689 DOMAIN_ATTR_SECURE_VMID,
690 &val)) {
691 pr_err("Couldn't set secure vmid to %d\n", val);
692 goto out_domain_free;
693 }
694
Mitchel Humpherys0fe337d2015-07-06 15:21:24 -0700695 if (iommu_attach_device(ddev->domain, ddev->dev)) {
696 pr_err("Couldn't attach new domain to device. Is it already attached?\n");
697 goto out_domain_free;
698 }
699
700 return 0;
701
702out_domain_free:
703 iommu_domain_free(ddev->domain);
704 ddev->domain = NULL;
705 return -EIO;
706}
707
Mitchel Humpherysac4c38b2015-07-30 19:40:21 -0700708static ssize_t __iommu_debug_attach_write(struct file *file,
709 const char __user *ubuf,
710 size_t count, loff_t *offset,
711 bool is_secure)
Mitchel Humpherys0fe337d2015-07-06 15:21:24 -0700712{
713 struct iommu_debug_device *ddev = file->private_data;
714 ssize_t retval;
Mitchel Humpherysac4c38b2015-07-30 19:40:21 -0700715 int val;
Mitchel Humpherys0fe337d2015-07-06 15:21:24 -0700716
Mitchel Humpherysac4c38b2015-07-30 19:40:21 -0700717 if (kstrtoint_from_user(ubuf, count, 0, &val)) {
718 pr_err("Invalid format. Expected a hex or decimal integer");
Mitchel Humpherys0fe337d2015-07-06 15:21:24 -0700719 retval = -EFAULT;
720 goto out;
721 }
722
Mitchel Humpherysac4c38b2015-07-30 19:40:21 -0700723 if (val) {
Mitchel Humpherys0fe337d2015-07-06 15:21:24 -0700724 if (ddev->domain) {
725 pr_err("Already attached.\n");
726 retval = -EINVAL;
727 goto out;
728 }
729 if (WARN(ddev->dev->archdata.iommu,
730 "Attachment tracking out of sync with device\n")) {
731 retval = -EINVAL;
732 goto out;
733 }
Mitchel Humpherysac4c38b2015-07-30 19:40:21 -0700734 if (iommu_debug_attach_do_attach(ddev, val, is_secure)) {
Mitchel Humpherys0fe337d2015-07-06 15:21:24 -0700735 retval = -EIO;
736 goto out;
737 }
738 pr_err("Attached\n");
Mitchel Humpherysac4c38b2015-07-30 19:40:21 -0700739 } else {
Mitchel Humpherys0fe337d2015-07-06 15:21:24 -0700740 if (!ddev->domain) {
741 pr_err("No domain. Did you already attach?\n");
742 retval = -EINVAL;
743 goto out;
744 }
745 iommu_detach_device(ddev->domain, ddev->dev);
746 iommu_domain_free(ddev->domain);
747 ddev->domain = NULL;
748 pr_err("Detached\n");
Mitchel Humpherys0fe337d2015-07-06 15:21:24 -0700749 }
750
751 retval = count;
752out:
753 return retval;
754}
755
Mitchel Humpherysac4c38b2015-07-30 19:40:21 -0700756static ssize_t iommu_debug_attach_write(struct file *file,
757 const char __user *ubuf,
758 size_t count, loff_t *offset)
759{
760 return __iommu_debug_attach_write(file, ubuf, count, offset,
761 false);
762
763}
764
Mitchel Humpherys0fe337d2015-07-06 15:21:24 -0700765static ssize_t iommu_debug_attach_read(struct file *file, char __user *ubuf,
766 size_t count, loff_t *offset)
767{
768 struct iommu_debug_device *ddev = file->private_data;
769 char c[2];
770
771 if (*offset)
772 return 0;
773
774 c[0] = ddev->domain ? '1' : '0';
775 c[1] = '\n';
776 if (copy_to_user(ubuf, &c, 2)) {
777 pr_err("copy_to_user failed\n");
778 return -EFAULT;
779 }
780 *offset = 1; /* non-zero means we're done */
781
782 return 2;
783}
784
785static const struct file_operations iommu_debug_attach_fops = {
786 .open = simple_open,
787 .write = iommu_debug_attach_write,
788 .read = iommu_debug_attach_read,
789};
790
Mitchel Humpherysac4c38b2015-07-30 19:40:21 -0700791static ssize_t iommu_debug_attach_write_secure(struct file *file,
792 const char __user *ubuf,
793 size_t count, loff_t *offset)
794{
795 return __iommu_debug_attach_write(file, ubuf, count, offset,
796 true);
797
798}
799
800static const struct file_operations iommu_debug_secure_attach_fops = {
801 .open = simple_open,
802 .write = iommu_debug_attach_write_secure,
803 .read = iommu_debug_attach_read,
804};
805
Mitchel Humpherys0fe337d2015-07-06 15:21:24 -0700806static ssize_t iommu_debug_atos_write(struct file *file,
807 const char __user *ubuf,
808 size_t count, loff_t *offset)
809{
810 struct iommu_debug_device *ddev = file->private_data;
811 dma_addr_t iova;
812
813 if (kstrtoll_from_user(ubuf, count, 0, &iova)) {
814 pr_err("Invalid format for iova\n");
815 ddev->iova = 0;
816 return -EINVAL;
817 }
818
819 ddev->iova = iova;
820 pr_err("Saved iova=%pa for future ATOS commands\n", &iova);
821 return count;
822}
823
824static ssize_t iommu_debug_atos_read(struct file *file, char __user *ubuf,
825 size_t count, loff_t *offset)
826{
827 struct iommu_debug_device *ddev = file->private_data;
828 phys_addr_t phys;
829 char buf[100];
830 ssize_t retval;
831 size_t buflen;
832
833 if (!ddev->domain) {
834 pr_err("No domain. Did you already attach?\n");
835 return -EINVAL;
836 }
837
838 if (*offset)
839 return 0;
840
841 memset(buf, 0, 100);
842
843 phys = iommu_iova_to_phys_hard(ddev->domain, ddev->iova);
844 if (!phys)
845 strlcpy(buf, "FAIL\n", 100);
846 else
847 snprintf(buf, 100, "%pa\n", &phys);
848
849 buflen = strlen(buf);
850 if (copy_to_user(ubuf, buf, buflen)) {
851 pr_err("Couldn't copy_to_user\n");
852 retval = -EFAULT;
853 } else {
854 *offset = 1; /* non-zero means we're done */
855 retval = buflen;
856 }
857
858 return retval;
859}
860
861static const struct file_operations iommu_debug_atos_fops = {
862 .open = simple_open,
863 .write = iommu_debug_atos_write,
864 .read = iommu_debug_atos_read,
865};
866
867static ssize_t iommu_debug_map_write(struct file *file, const char __user *ubuf,
868 size_t count, loff_t *offset)
869{
870 ssize_t retval;
871 int ret;
872 char *comma1, *comma2, *comma3;
873 char buf[100];
874 dma_addr_t iova;
875 phys_addr_t phys;
876 size_t size;
877 int prot;
878 struct iommu_debug_device *ddev = file->private_data;
879
880 if (count >= 100) {
881 pr_err("Value too large\n");
882 return -EINVAL;
883 }
884
885 if (!ddev->domain) {
886 pr_err("No domain. Did you already attach?\n");
887 return -EINVAL;
888 }
889
890 memset(buf, 0, 100);
891
892 if (copy_from_user(buf, ubuf, count)) {
893 pr_err("Couldn't copy from user\n");
894 retval = -EFAULT;
895 }
896
897 comma1 = strnchr(buf, count, ',');
898 if (!comma1)
899 goto invalid_format;
900
901 comma2 = strnchr(comma1 + 1, count, ',');
902 if (!comma2)
903 goto invalid_format;
904
905 comma3 = strnchr(comma2 + 1, count, ',');
906 if (!comma3)
907 goto invalid_format;
908
909 /* split up the words */
910 *comma1 = *comma2 = *comma3 = '\0';
911
912 if (kstrtou64(buf, 0, &iova))
913 goto invalid_format;
914
915 if (kstrtou64(comma1 + 1, 0, &phys))
916 goto invalid_format;
917
918 if (kstrtoul(comma2 + 1, 0, &size))
919 goto invalid_format;
920
921 if (kstrtoint(comma3 + 1, 0, &prot))
922 goto invalid_format;
923
924 ret = iommu_map(ddev->domain, iova, phys, size, prot);
925 if (ret) {
926 pr_err("iommu_map failed with %d\n", ret);
927 retval = -EIO;
928 goto out;
929 }
930
931 retval = count;
932 pr_err("Mapped %pa to %pa (len=0x%zx, prot=0x%x)\n",
933 &iova, &phys, size, prot);
934out:
935 return retval;
936
937invalid_format:
938 pr_err("Invalid format. Expected: iova,phys,len,prot where `prot' is the bitwise OR of IOMMU_READ, IOMMU_WRITE, etc.\n");
939 return -EINVAL;
940}
941
942static const struct file_operations iommu_debug_map_fops = {
943 .open = simple_open,
944 .write = iommu_debug_map_write,
945};
946
947static ssize_t iommu_debug_unmap_write(struct file *file,
948 const char __user *ubuf,
949 size_t count, loff_t *offset)
950{
951 ssize_t retval = 0;
952 char *comma1;
953 char buf[100];
954 dma_addr_t iova;
955 size_t size;
956 size_t unmapped;
957 struct iommu_debug_device *ddev = file->private_data;
958
959 if (count >= 100) {
960 pr_err("Value too large\n");
961 return -EINVAL;
962 }
963
964 if (!ddev->domain) {
965 pr_err("No domain. Did you already attach?\n");
966 return -EINVAL;
967 }
968
969 memset(buf, 0, 100);
970
971 if (copy_from_user(buf, ubuf, count)) {
972 pr_err("Couldn't copy from user\n");
973 retval = -EFAULT;
974 goto out;
975 }
976
977 comma1 = strnchr(buf, count, ',');
978 if (!comma1)
979 goto invalid_format;
980
981 /* split up the words */
982 *comma1 = '\0';
983
984 if (kstrtou64(buf, 0, &iova))
985 goto invalid_format;
986
Mitchel Humpherys70b75112015-07-29 12:45:29 -0700987 if (kstrtoul(comma1 + 1, 0, &size))
Mitchel Humpherys0fe337d2015-07-06 15:21:24 -0700988 goto invalid_format;
989
990 unmapped = iommu_unmap(ddev->domain, iova, size);
991 if (unmapped != size) {
992 pr_err("iommu_unmap failed. Expected to unmap: 0x%zx, unmapped: 0x%zx",
993 size, unmapped);
994 return -EIO;
995 }
996
997 retval = count;
998 pr_err("Unmapped %pa (len=0x%zx)\n", &iova, size);
999out:
1000 return retval;
1001
1002invalid_format:
1003 pr_err("Invalid format. Expected: iova,len\n");
1004 return retval;
1005}
1006
1007static const struct file_operations iommu_debug_unmap_fops = {
1008 .open = simple_open,
1009 .write = iommu_debug_unmap_write,
1010};
1011
Mitchel Humpherys42296fb2015-06-23 16:29:16 -07001012/*
1013 * The following will only work for drivers that implement the generic
1014 * device tree bindings described in
1015 * Documentation/devicetree/bindings/iommu/iommu.txt
1016 */
1017static int snarf_iommu_devices(struct device *dev, void *ignored)
1018{
1019 struct iommu_debug_device *ddev;
Mitchel Humpherys0fe337d2015-07-06 15:21:24 -07001020 struct dentry *dir;
Mitchel Humpherys42296fb2015-06-23 16:29:16 -07001021
1022 if (!of_find_property(dev->of_node, "iommus", NULL))
1023 return 0;
1024
Mitchel Humpherys89924fd2015-07-09 14:50:22 -07001025 ddev = kzalloc(sizeof(*ddev), GFP_KERNEL);
Mitchel Humpherys42296fb2015-06-23 16:29:16 -07001026 if (!ddev)
1027 return -ENODEV;
1028 ddev->dev = dev;
1029 dir = debugfs_create_dir(dev_name(dev), debugfs_tests_dir);
1030 if (!dir) {
1031 pr_err("Couldn't create iommu/devices/%s debugfs dir\n",
1032 dev_name(dev));
1033 goto err;
1034 }
Mitchel Humpherys0fe337d2015-07-06 15:21:24 -07001035
Patrick Dalye4e39862015-11-20 20:00:50 -08001036 if (!debugfs_create_file("nr_iters", S_IRUSR, dir, &iters_per_op,
1037 &iommu_debug_nr_iters_ops)) {
1038 pr_err("Couldn't create iommu/devices/%s/nr_iters debugfs file\n",
1039 dev_name(dev));
1040 goto err_rmdir;
1041 }
1042
Mitchel Humpherys0fe337d2015-07-06 15:21:24 -07001043 if (!debugfs_create_file("profiling", S_IRUSR, dir, ddev,
1044 &iommu_debug_profiling_fops)) {
Mitchel Humpherys42296fb2015-06-23 16:29:16 -07001045 pr_err("Couldn't create iommu/devices/%s/profiling debugfs file\n",
1046 dev_name(dev));
1047 goto err_rmdir;
1048 }
1049
Mitchel Humpherys020f90f2015-10-02 16:02:31 -07001050 if (!debugfs_create_file("secure_profiling", S_IRUSR, dir, ddev,
1051 &iommu_debug_secure_profiling_fops)) {
1052 pr_err("Couldn't create iommu/devices/%s/secure_profiling debugfs file\n",
1053 dev_name(dev));
1054 goto err_rmdir;
1055 }
1056
Mitchel Humpherys0fe337d2015-07-06 15:21:24 -07001057 if (!debugfs_create_file("attach", S_IRUSR, dir, ddev,
1058 &iommu_debug_attach_fops)) {
1059 pr_err("Couldn't create iommu/devices/%s/attach debugfs file\n",
1060 dev_name(dev));
1061 goto err_rmdir;
1062 }
1063
Mitchel Humpherysac4c38b2015-07-30 19:40:21 -07001064 if (!debugfs_create_file("secure_attach", S_IRUSR, dir, ddev,
1065 &iommu_debug_secure_attach_fops)) {
1066 pr_err("Couldn't create iommu/devices/%s/secure_attach debugfs file\n",
1067 dev_name(dev));
1068 goto err_rmdir;
1069 }
1070
Mitchel Humpherys0fe337d2015-07-06 15:21:24 -07001071 if (!debugfs_create_file("atos", S_IWUSR, dir, ddev,
1072 &iommu_debug_atos_fops)) {
1073 pr_err("Couldn't create iommu/devices/%s/atos debugfs file\n",
1074 dev_name(dev));
1075 goto err_rmdir;
1076 }
1077
1078 if (!debugfs_create_file("map", S_IWUSR, dir, ddev,
1079 &iommu_debug_map_fops)) {
1080 pr_err("Couldn't create iommu/devices/%s/map debugfs file\n",
1081 dev_name(dev));
1082 goto err_rmdir;
1083 }
1084
1085 if (!debugfs_create_file("unmap", S_IWUSR, dir, ddev,
1086 &iommu_debug_unmap_fops)) {
1087 pr_err("Couldn't create iommu/devices/%s/unmap debugfs file\n",
1088 dev_name(dev));
1089 goto err_rmdir;
1090 }
1091
Mitchel Humpherys42296fb2015-06-23 16:29:16 -07001092 list_add(&ddev->list, &iommu_debug_devices);
1093 return 0;
1094
1095err_rmdir:
1096 debugfs_remove_recursive(dir);
1097err:
1098 kfree(ddev);
1099 return 0;
1100}
1101
1102static int iommu_debug_init_tests(void)
1103{
1104 debugfs_tests_dir = debugfs_create_dir("tests",
Mitchel Humpherysc75ae492015-07-15 18:27:36 -07001105 iommu_debugfs_top);
Mitchel Humpherys42296fb2015-06-23 16:29:16 -07001106 if (!debugfs_tests_dir) {
1107 pr_err("Couldn't create iommu/tests debugfs directory\n");
1108 return -ENODEV;
1109 }
1110
1111 return bus_for_each_dev(&platform_bus_type, NULL, NULL,
1112 snarf_iommu_devices);
1113}
Mitchel Humpherysc75ae492015-07-15 18:27:36 -07001114
1115static void iommu_debug_destroy_tests(void)
1116{
1117 debugfs_remove_recursive(debugfs_tests_dir);
1118}
Mitchel Humpherys42296fb2015-06-23 16:29:16 -07001119#else
1120static inline int iommu_debug_init_tests(void) { return 0; }
Mitchel Humpherysc75ae492015-07-15 18:27:36 -07001121static inline void iommu_debug_destroy_tests(void) { }
Mitchel Humpherys42296fb2015-06-23 16:29:16 -07001122#endif
1123
1124static int iommu_debug_init(void)
1125{
Mitchel Humpherys42296fb2015-06-23 16:29:16 -07001126 if (iommu_debug_init_tracking())
Mitchel Humpherysc75ae492015-07-15 18:27:36 -07001127 return -ENODEV;
Mitchel Humpherys42296fb2015-06-23 16:29:16 -07001128
1129 if (iommu_debug_init_tests())
Mitchel Humpherysc75ae492015-07-15 18:27:36 -07001130 return -ENODEV;
Mitchel Humpherys42296fb2015-06-23 16:29:16 -07001131
1132 return 0;
Mitchel Humpherys42296fb2015-06-23 16:29:16 -07001133}
1134
1135static void iommu_debug_exit(void)
1136{
Mitchel Humpherysc75ae492015-07-15 18:27:36 -07001137 iommu_debug_destroy_tracking();
1138 iommu_debug_destroy_tests();
Mitchel Humpherys42296fb2015-06-23 16:29:16 -07001139}
1140
1141module_init(iommu_debug_init);
1142module_exit(iommu_debug_exit);