blob: 79dd81713bb7a4cc83fe38c1da4740d65d71c5e2 [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 Humpherysbc367fd2015-10-05 14:44:58 -070025#include <linux/dma-contiguous.h>
Mitchel Humpherys5e991f12015-07-30 19:25:54 -070026#include <soc/qcom/secure_buffer.h>
Mitchel Humpherys42296fb2015-06-23 16:29:16 -070027
Mitchel Humpherysbc367fd2015-10-05 14:44:58 -070028static const char *iommu_debug_attr_to_string(enum iommu_attr attr)
29{
30 switch (attr) {
31 case DOMAIN_ATTR_GEOMETRY:
32 return "DOMAIN_ATTR_GEOMETRY";
33 case DOMAIN_ATTR_PAGING:
34 return "DOMAIN_ATTR_PAGING";
35 case DOMAIN_ATTR_WINDOWS:
36 return "DOMAIN_ATTR_WINDOWS";
37 case DOMAIN_ATTR_FSL_PAMU_STASH:
38 return "DOMAIN_ATTR_FSL_PAMU_STASH";
39 case DOMAIN_ATTR_FSL_PAMU_ENABLE:
40 return "DOMAIN_ATTR_FSL_PAMU_ENABLE";
41 case DOMAIN_ATTR_FSL_PAMUV1:
42 return "DOMAIN_ATTR_FSL_PAMUV1";
43 case DOMAIN_ATTR_NESTING:
44 return "DOMAIN_ATTR_NESTING";
45 case DOMAIN_ATTR_PT_BASE_ADDR:
46 return "DOMAIN_ATTR_PT_BASE_ADDR";
47 case DOMAIN_ATTR_SECURE_VMID:
48 return "DOMAIN_ATTR_SECURE_VMID";
49 case DOMAIN_ATTR_ATOMIC:
50 return "DOMAIN_ATTR_ATOMIC";
51 case DOMAIN_ATTR_CONTEXT_BANK:
52 return "DOMAIN_ATTR_CONTEXT_BANK";
53 case DOMAIN_ATTR_TTBR0:
54 return "DOMAIN_ATTR_TTBR0";
55 case DOMAIN_ATTR_CONTEXTIDR:
56 return "DOMAIN_ATTR_CONTEXTIDR";
57 case DOMAIN_ATTR_PROCID:
58 return "DOMAIN_ATTR_PROCID";
59 case DOMAIN_ATTR_DYNAMIC:
60 return "DOMAIN_ATTR_DYNAMIC";
61 case DOMAIN_ATTR_NON_FATAL_FAULTS:
62 return "DOMAIN_ATTR_NON_FATAL_FAULTS";
63 case DOMAIN_ATTR_S1_BYPASS:
64 return "DOMAIN_ATTR_S1_BYPASS";
65 case DOMAIN_ATTR_FAST:
66 return "DOMAIN_ATTR_FAST";
67 default:
68 return "Unknown attr!";
69 }
70}
71
Mitchel Humpherys42296fb2015-06-23 16:29:16 -070072#ifdef CONFIG_IOMMU_DEBUG_TRACKING
73
74static DEFINE_MUTEX(iommu_debug_attachments_lock);
75static LIST_HEAD(iommu_debug_attachments);
76static struct dentry *debugfs_attachments_dir;
77
78struct iommu_debug_attachment {
79 struct iommu_domain *domain;
80 struct device *dev;
81 struct dentry *dentry;
82 struct list_head list;
Mitchel Humpherys0dc04de2015-08-21 14:08:40 -070083 unsigned long reg_offset;
Mitchel Humpherys42296fb2015-06-23 16:29:16 -070084};
85
Mitchel Humpherys088cc582015-07-09 15:02:03 -070086static int iommu_debug_attachment_info_show(struct seq_file *s, void *ignored)
Mitchel Humpherys42296fb2015-06-23 16:29:16 -070087{
88 struct iommu_debug_attachment *attach = s->private;
Mitchel Humpherys5e991f12015-07-30 19:25:54 -070089 int secure_vmid;
Mitchel Humpherys42296fb2015-06-23 16:29:16 -070090
91 seq_printf(s, "Domain: 0x%p\n", attach->domain);
Mitchel Humpherys5e991f12015-07-30 19:25:54 -070092
93 seq_puts(s, "SECURE_VMID: ");
94 if (iommu_domain_get_attr(attach->domain,
95 DOMAIN_ATTR_SECURE_VMID,
96 &secure_vmid))
97 seq_puts(s, "(Unknown)\n");
98 else
99 seq_printf(s, "%s (0x%x)\n",
100 msm_secure_vmid_to_string(secure_vmid), secure_vmid);
101
Mitchel Humpherys42296fb2015-06-23 16:29:16 -0700102 return 0;
103}
104
Mitchel Humpherys088cc582015-07-09 15:02:03 -0700105static int iommu_debug_attachment_info_open(struct inode *inode,
106 struct file *file)
Mitchel Humpherys42296fb2015-06-23 16:29:16 -0700107{
Mitchel Humpherys088cc582015-07-09 15:02:03 -0700108 return single_open(file, iommu_debug_attachment_info_show,
109 inode->i_private);
Mitchel Humpherys42296fb2015-06-23 16:29:16 -0700110}
111
Mitchel Humpherys088cc582015-07-09 15:02:03 -0700112static const struct file_operations iommu_debug_attachment_info_fops = {
113 .open = iommu_debug_attachment_info_open,
Mitchel Humpherys42296fb2015-06-23 16:29:16 -0700114 .read = seq_read,
115 .llseek = seq_lseek,
116 .release = single_release,
117};
118
Mitchel Humpherys288086e2015-07-09 16:55:08 -0700119static ssize_t iommu_debug_attachment_trigger_fault_write(
120 struct file *file, const char __user *ubuf, size_t count,
121 loff_t *offset)
122{
123 struct iommu_debug_attachment *attach = file->private_data;
124 unsigned long flags;
125
126 if (kstrtoul_from_user(ubuf, count, 0, &flags)) {
127 pr_err("Invalid flags format\n");
128 return -EFAULT;
129 }
130
131 iommu_trigger_fault(attach->domain, flags);
132
133 return count;
134}
135
136static const struct file_operations
137iommu_debug_attachment_trigger_fault_fops = {
138 .open = simple_open,
139 .write = iommu_debug_attachment_trigger_fault_write,
140};
141
Mitchel Humpherys0dc04de2015-08-21 14:08:40 -0700142static ssize_t iommu_debug_attachment_reg_offset_write(
143 struct file *file, const char __user *ubuf, size_t count,
144 loff_t *offset)
145{
146 struct iommu_debug_attachment *attach = file->private_data;
147 unsigned long reg_offset;
148
149 if (kstrtoul_from_user(ubuf, count, 0, &reg_offset)) {
150 pr_err("Invalid reg_offset format\n");
151 return -EFAULT;
152 }
153
154 attach->reg_offset = reg_offset;
155
156 return count;
157}
158
159static const struct file_operations iommu_debug_attachment_reg_offset_fops = {
160 .open = simple_open,
161 .write = iommu_debug_attachment_reg_offset_write,
162};
163
164static ssize_t iommu_debug_attachment_reg_read_read(
165 struct file *file, char __user *ubuf, size_t count, loff_t *offset)
166{
167 struct iommu_debug_attachment *attach = file->private_data;
168 unsigned long val;
169 char *val_str;
170 ssize_t val_str_len;
171
172 if (*offset)
173 return 0;
174
175 val = iommu_reg_read(attach->domain, attach->reg_offset);
176 val_str = kasprintf(GFP_KERNEL, "0x%lx\n", val);
177 if (!val_str)
178 return -ENOMEM;
179 val_str_len = strlen(val_str);
180
181 if (copy_to_user(ubuf, val_str, val_str_len)) {
182 pr_err("copy_to_user failed\n");
183 val_str_len = -EFAULT;
184 goto out;
185 }
186 *offset = 1; /* non-zero means we're done */
187
188out:
189 kfree(val_str);
190 return val_str_len;
191}
192
193static const struct file_operations iommu_debug_attachment_reg_read_fops = {
194 .open = simple_open,
195 .read = iommu_debug_attachment_reg_read_read,
196};
197
198static ssize_t iommu_debug_attachment_reg_write_write(
199 struct file *file, const char __user *ubuf, size_t count,
200 loff_t *offset)
201{
202 struct iommu_debug_attachment *attach = file->private_data;
203 unsigned long val;
204
205 if (kstrtoul_from_user(ubuf, count, 0, &val)) {
206 pr_err("Invalid val format\n");
207 return -EFAULT;
208 }
209
210 iommu_reg_write(attach->domain, attach->reg_offset, val);
211
212 return count;
213}
214
215static const struct file_operations iommu_debug_attachment_reg_write_fops = {
216 .open = simple_open,
217 .write = iommu_debug_attachment_reg_write_write,
218};
219
Mitchel Humpherysa05b2522015-07-14 14:30:33 -0700220/* should be called with iommu_debug_attachments_lock locked */
221static int iommu_debug_attach_add_debugfs(
222 struct iommu_debug_attachment *attach)
Mitchel Humpherys42296fb2015-06-23 16:29:16 -0700223{
Mitchel Humpherys54379212015-08-26 11:52:57 -0700224 const char *attach_name;
Mitchel Humpherysa05b2522015-07-14 14:30:33 -0700225 struct device *dev = attach->dev;
226 struct iommu_domain *domain = attach->domain;
Mitchel Humpherys54379212015-08-26 11:52:57 -0700227 int is_dynamic;
Mitchel Humpherys42296fb2015-06-23 16:29:16 -0700228
Mitchel Humpherys54379212015-08-26 11:52:57 -0700229 if (iommu_domain_get_attr(domain, DOMAIN_ATTR_DYNAMIC, &is_dynamic))
230 is_dynamic = 0;
231
232 if (is_dynamic) {
233 uuid_le uuid;
234
235 uuid_le_gen(&uuid);
236 attach_name = kasprintf(GFP_KERNEL, "%s-%pUl", dev_name(dev),
237 uuid.b);
238 if (!attach_name)
239 return -ENOMEM;
240 } else {
241 attach_name = dev_name(dev);
242 }
Mitchel Humpherys42296fb2015-06-23 16:29:16 -0700243
Mitchel Humpherys088cc582015-07-09 15:02:03 -0700244 attach->dentry = debugfs_create_dir(attach_name,
245 debugfs_attachments_dir);
Mitchel Humpherys42296fb2015-06-23 16:29:16 -0700246 if (!attach->dentry) {
Mitchel Humpherys088cc582015-07-09 15:02:03 -0700247 pr_err("Couldn't create iommu/attachments/%s debugfs directory for domain 0x%p\n",
Mitchel Humpherys876e2be2015-07-10 11:56:56 -0700248 attach_name, domain);
Mitchel Humpherys54379212015-08-26 11:52:57 -0700249 if (is_dynamic)
250 kfree(attach_name);
Mitchel Humpherysa05b2522015-07-14 14:30:33 -0700251 return -EIO;
Mitchel Humpherys42296fb2015-06-23 16:29:16 -0700252 }
Mitchel Humpherys54379212015-08-26 11:52:57 -0700253
254 if (is_dynamic)
255 kfree(attach_name);
Mitchel Humpherys42296fb2015-06-23 16:29:16 -0700256
Mitchel Humpherys088cc582015-07-09 15:02:03 -0700257 if (!debugfs_create_file(
258 "info", S_IRUSR, attach->dentry, attach,
259 &iommu_debug_attachment_info_fops)) {
260 pr_err("Couldn't create iommu/attachments/%s/info debugfs file for domain 0x%p\n",
261 dev_name(dev), domain);
Mitchel Humpherysa05b2522015-07-14 14:30:33 -0700262 goto err_rmdir;
Mitchel Humpherys088cc582015-07-09 15:02:03 -0700263 }
264
Mitchel Humpherys288086e2015-07-09 16:55:08 -0700265 if (!debugfs_create_file(
266 "trigger_fault", S_IRUSR, attach->dentry, attach,
267 &iommu_debug_attachment_trigger_fault_fops)) {
268 pr_err("Couldn't create iommu/attachments/%s/trigger_fault debugfs file for domain 0x%p\n",
269 dev_name(dev), domain);
270 goto err_rmdir;
Mitchel Humpherys0dc04de2015-08-21 14:08:40 -0700271 }
272
273 if (!debugfs_create_file(
274 "reg_offset", S_IRUSR, attach->dentry, attach,
275 &iommu_debug_attachment_reg_offset_fops)) {
276 pr_err("Couldn't create iommu/attachments/%s/reg_offset debugfs file for domain 0x%p\n",
277 dev_name(dev), domain);
278 goto err_rmdir;
279 }
280
281 if (!debugfs_create_file(
282 "reg_read", S_IRUSR, attach->dentry, attach,
283 &iommu_debug_attachment_reg_read_fops)) {
284 pr_err("Couldn't create iommu/attachments/%s/reg_read debugfs file for domain 0x%p\n",
285 dev_name(dev), domain);
286 goto err_rmdir;
287 }
288
289 if (!debugfs_create_file(
290 "reg_write", S_IRUSR, attach->dentry, attach,
291 &iommu_debug_attachment_reg_write_fops)) {
292 pr_err("Couldn't create iommu/attachments/%s/reg_write debugfs file for domain 0x%p\n",
293 dev_name(dev), domain);
294 goto err_rmdir;
295 }
296
Mitchel Humpherysa05b2522015-07-14 14:30:33 -0700297 return 0;
298
299err_rmdir:
300 debugfs_remove_recursive(attach->dentry);
301 return -EIO;
302}
303
Susheel Khianie66aa5b2015-08-25 17:25:42 +0530304void iommu_debug_domain_add(struct iommu_domain *domain)
Mitchel Humpherysa05b2522015-07-14 14:30:33 -0700305{
306 struct iommu_debug_attachment *attach;
307
308 mutex_lock(&iommu_debug_attachments_lock);
309
310 attach = kmalloc(sizeof(*attach), GFP_KERNEL);
311 if (!attach)
312 goto out_unlock;
313
314 attach->domain = domain;
Susheel Khianie66aa5b2015-08-25 17:25:42 +0530315 attach->dev = NULL;
Mitchel Humpherys42296fb2015-06-23 16:29:16 -0700316 list_add(&attach->list, &iommu_debug_attachments);
Susheel Khianie66aa5b2015-08-25 17:25:42 +0530317
Mitchel Humpherysa05b2522015-07-14 14:30:33 -0700318out_unlock:
Mitchel Humpherys42296fb2015-06-23 16:29:16 -0700319 mutex_unlock(&iommu_debug_attachments_lock);
320}
321
Susheel Khianie66aa5b2015-08-25 17:25:42 +0530322void iommu_debug_domain_remove(struct iommu_domain *domain)
323{
324 struct iommu_debug_attachment *it;
325
326 mutex_lock(&iommu_debug_attachments_lock);
327 list_for_each_entry(it, &iommu_debug_attachments, list)
328 if (it->domain == domain && it->dev == NULL)
329 break;
330
331 if (&it->list == &iommu_debug_attachments) {
332 WARN(1, "Couldn't find debug attachment for domain=0x%p",
333 domain);
334 } else {
335 list_del(&it->list);
336 kfree(it);
337 }
338 mutex_unlock(&iommu_debug_attachments_lock);
339}
340
341void iommu_debug_attach_device(struct iommu_domain *domain,
342 struct device *dev)
343{
344 struct iommu_debug_attachment *attach;
345
346 mutex_lock(&iommu_debug_attachments_lock);
347
348 list_for_each_entry(attach, &iommu_debug_attachments, list)
349 if (attach->domain == domain && attach->dev == NULL)
350 break;
351
352 if (&attach->list == &iommu_debug_attachments) {
353 WARN(1, "Couldn't find debug attachment for domain=0x%p dev=%s",
354 domain, dev_name(dev));
355 } else {
356 attach->dev = dev;
357
358 /*
359 * we might not init until after other drivers start calling
360 * iommu_attach_device. Only set up the debugfs nodes if we've
361 * already init'd to avoid polluting the top-level debugfs
362 * directory (by calling debugfs_create_dir with a NULL
363 * parent). These will be flushed out later once we init.
364 */
365
366 if (debugfs_attachments_dir)
367 iommu_debug_attach_add_debugfs(attach);
368 }
369
370 mutex_unlock(&iommu_debug_attachments_lock);
371}
372
Mitchel Humpherys42296fb2015-06-23 16:29:16 -0700373void iommu_debug_detach_device(struct iommu_domain *domain,
374 struct device *dev)
375{
376 struct iommu_debug_attachment *it;
377
378 mutex_lock(&iommu_debug_attachments_lock);
379 list_for_each_entry(it, &iommu_debug_attachments, list)
380 if (it->domain == domain && it->dev == dev)
381 break;
382
383 if (&it->list == &iommu_debug_attachments) {
384 WARN(1, "Couldn't find debug attachment for domain=0x%p dev=%s",
385 domain, dev_name(dev));
386 } else {
Susheel Khianie66aa5b2015-08-25 17:25:42 +0530387 /*
388 * Just remove debugfs entry and mark dev as NULL on
389 * iommu_detach call. We would remove the actual
390 * attachment entry from the list only on domain_free call.
391 * This is to ensure we keep track of unattached domains too.
392 */
393
Mitchel Humpherys42296fb2015-06-23 16:29:16 -0700394 debugfs_remove_recursive(it->dentry);
Susheel Khianie66aa5b2015-08-25 17:25:42 +0530395 it->dev = NULL;
Mitchel Humpherys42296fb2015-06-23 16:29:16 -0700396 }
397 mutex_unlock(&iommu_debug_attachments_lock);
398}
399
400static int iommu_debug_init_tracking(void)
401{
Mitchel Humpherysa05b2522015-07-14 14:30:33 -0700402 int ret = 0;
403 struct iommu_debug_attachment *attach;
404
405 mutex_lock(&iommu_debug_attachments_lock);
Mitchel Humpherys42296fb2015-06-23 16:29:16 -0700406 debugfs_attachments_dir = debugfs_create_dir("attachments",
Mitchel Humpherysc75ae492015-07-15 18:27:36 -0700407 iommu_debugfs_top);
Mitchel Humpherys42296fb2015-06-23 16:29:16 -0700408 if (!debugfs_attachments_dir) {
409 pr_err("Couldn't create iommu/attachments debugfs directory\n");
Mitchel Humpherysa05b2522015-07-14 14:30:33 -0700410 ret = -ENODEV;
411 goto out_unlock;
Mitchel Humpherys42296fb2015-06-23 16:29:16 -0700412 }
413
Mitchel Humpherysa05b2522015-07-14 14:30:33 -0700414 /* set up debugfs entries for attachments made during early boot */
415 list_for_each_entry(attach, &iommu_debug_attachments, list)
Susheel Khianie66aa5b2015-08-25 17:25:42 +0530416 if (attach->dev)
417 iommu_debug_attach_add_debugfs(attach);
Mitchel Humpherysa05b2522015-07-14 14:30:33 -0700418
419out_unlock:
420 mutex_unlock(&iommu_debug_attachments_lock);
421 return ret;
Mitchel Humpherys42296fb2015-06-23 16:29:16 -0700422}
Mitchel Humpherysc75ae492015-07-15 18:27:36 -0700423
424static void iommu_debug_destroy_tracking(void)
425{
426 debugfs_remove_recursive(debugfs_attachments_dir);
427}
Mitchel Humpherys42296fb2015-06-23 16:29:16 -0700428#else
429static inline int iommu_debug_init_tracking(void) { return 0; }
Mitchel Humpherysc75ae492015-07-15 18:27:36 -0700430static inline void iommu_debug_destroy_tracking(void) { }
Mitchel Humpherys42296fb2015-06-23 16:29:16 -0700431#endif
432
433#ifdef CONFIG_IOMMU_TESTS
434
435static LIST_HEAD(iommu_debug_devices);
436static struct dentry *debugfs_tests_dir;
Patrick Dalye4e39862015-11-20 20:00:50 -0800437static u32 iters_per_op = 1;
Mitchel Humpherys42296fb2015-06-23 16:29:16 -0700438
439struct iommu_debug_device {
440 struct device *dev;
Mitchel Humpherys0fe337d2015-07-06 15:21:24 -0700441 struct iommu_domain *domain;
442 u64 iova;
443 u64 phys;
444 size_t len;
Mitchel Humpherys42296fb2015-06-23 16:29:16 -0700445 struct list_head list;
446};
447
448static int iommu_debug_build_phoney_sg_table(struct device *dev,
449 struct sg_table *table,
450 unsigned long total_size,
451 unsigned long chunk_size)
452{
453 unsigned long nents = total_size / chunk_size;
454 struct scatterlist *sg;
455 int i;
456 struct page *page;
457
458 if (!IS_ALIGNED(total_size, PAGE_SIZE))
459 return -EINVAL;
460 if (!IS_ALIGNED(total_size, chunk_size))
461 return -EINVAL;
462 if (sg_alloc_table(table, nents, GFP_KERNEL))
463 return -EINVAL;
464 page = alloc_pages(GFP_KERNEL, get_order(chunk_size));
465 if (!page)
466 goto free_table;
467
468 /* all the same page... why not. */
469 for_each_sg(table->sgl, sg, table->nents, i)
470 sg_set_page(sg, page, chunk_size, 0);
471
472 return 0;
473
474free_table:
475 sg_free_table(table);
476 return -ENOMEM;
477}
478
479static void iommu_debug_destroy_phoney_sg_table(struct device *dev,
480 struct sg_table *table,
481 unsigned long chunk_size)
482{
483 __free_pages(sg_page(table->sgl), get_order(chunk_size));
484 sg_free_table(table);
485}
486
487static const char * const _size_to_string(unsigned long size)
488{
489 switch (size) {
490 case SZ_4K:
491 return "4K";
Mitchel Humpherysbc367fd2015-10-05 14:44:58 -0700492 case SZ_8K:
493 return "8K";
494 case SZ_16K:
495 return "16K";
Mitchel Humpherys42296fb2015-06-23 16:29:16 -0700496 case SZ_64K:
497 return "64K";
498 case SZ_2M:
499 return "2M";
500 case SZ_1M * 12:
501 return "12M";
502 case SZ_1M * 20:
503 return "20M";
504 }
505 return "unknown size, please add to _size_to_string";
506}
507
Patrick Dalye4e39862015-11-20 20:00:50 -0800508static int nr_iters_set(void *data, u64 val)
509{
510 if (!val)
511 val = 1;
512 if (val > 10000)
513 val = 10000;
514 *(u32 *)data = val;
515 return 0;
516}
517
518static int nr_iters_get(void *data, u64 *val)
519{
520 *val = *(u32 *)data;
521 return 0;
522}
523
524DEFINE_SIMPLE_ATTRIBUTE(iommu_debug_nr_iters_ops,
525 nr_iters_get, nr_iters_set, "%llu\n");
Mitchel Humpherys1c47bb52015-10-02 16:17:57 -0700526
Mitchel Humpherys020f90f2015-10-02 16:02:31 -0700527static void iommu_debug_device_profiling(struct seq_file *s, struct device *dev,
Mitchel Humpherysbc367fd2015-10-05 14:44:58 -0700528 enum iommu_attr attrs[],
529 void *attr_values[], int nattrs,
530 const unsigned long sizes[])
Mitchel Humpherys42296fb2015-06-23 16:29:16 -0700531{
Mitchel Humpherysbc367fd2015-10-05 14:44:58 -0700532 int i;
533 const unsigned long *sz;
Mitchel Humpherys42296fb2015-06-23 16:29:16 -0700534 struct iommu_domain *domain;
535 unsigned long iova = 0x10000;
536 phys_addr_t paddr = 0xa000;
537
538 domain = iommu_domain_alloc(&platform_bus_type);
539 if (!domain) {
540 seq_puts(s, "Couldn't allocate domain\n");
541 return;
542 }
543
Mitchel Humpherysbc367fd2015-10-05 14:44:58 -0700544 seq_puts(s, "Domain attributes: [ ");
545 for (i = 0; i < nattrs; ++i) {
546 /* not all attrs are ints, but this will get us by for now */
547 seq_printf(s, "%s=%d%s", iommu_debug_attr_to_string(attrs[i]),
548 *((int *)attr_values[i]),
549 i < nattrs ? " " : "");
Mitchel Humpherys679567c2015-08-28 10:51:24 -0700550 }
Mitchel Humpherysbc367fd2015-10-05 14:44:58 -0700551 seq_puts(s, "]\n");
552 for (i = 0; i < nattrs; ++i) {
553 if (iommu_domain_set_attr(domain, attrs[i], attr_values[i])) {
554 seq_printf(s, "Couldn't set %d to the value at %p\n",
555 attrs[i], attr_values[i]);
Mitchel Humpherys020f90f2015-10-02 16:02:31 -0700556 goto out_domain_free;
557 }
558 }
559
Mitchel Humpherys42296fb2015-06-23 16:29:16 -0700560 if (iommu_attach_device(domain, dev)) {
561 seq_puts(s,
562 "Couldn't attach new domain to device. Is it already attached?\n");
563 goto out_domain_free;
564 }
565
Patrick Dalye4e39862015-11-20 20:00:50 -0800566 seq_printf(s, "(average over %d iterations)\n", iters_per_op);
Patrick Daly3ca31e32015-11-20 20:33:04 -0800567 seq_printf(s, "%8s %19s %16s\n", "size", "iommu_map", "iommu_unmap");
Mitchel Humpherys42296fb2015-06-23 16:29:16 -0700568 for (sz = sizes; *sz; ++sz) {
569 unsigned long size = *sz;
570 size_t unmapped;
Patrick Daly3ca31e32015-11-20 20:33:04 -0800571 u64 map_elapsed_ns = 0, unmap_elapsed_ns = 0;
Mitchel Humpherys1c47bb52015-10-02 16:17:57 -0700572 u64 map_elapsed_us = 0, unmap_elapsed_us = 0;
Patrick Daly3ca31e32015-11-20 20:33:04 -0800573 u32 map_elapsed_rem = 0, unmap_elapsed_rem = 0;
Mitchel Humpherys42296fb2015-06-23 16:29:16 -0700574 struct timespec tbefore, tafter, diff;
Mitchel Humpherys1c47bb52015-10-02 16:17:57 -0700575 int i;
Mitchel Humpherys42296fb2015-06-23 16:29:16 -0700576
Patrick Dalye4e39862015-11-20 20:00:50 -0800577 for (i = 0; i < iters_per_op; ++i) {
Mitchel Humpherys1c47bb52015-10-02 16:17:57 -0700578 getnstimeofday(&tbefore);
579 if (iommu_map(domain, iova, paddr, size,
580 IOMMU_READ | IOMMU_WRITE)) {
581 seq_puts(s, "Failed to map\n");
582 continue;
583 }
584 getnstimeofday(&tafter);
585 diff = timespec_sub(tafter, tbefore);
Patrick Daly3ca31e32015-11-20 20:33:04 -0800586 map_elapsed_ns += timespec_to_ns(&diff);
Mitchel Humpherys42296fb2015-06-23 16:29:16 -0700587
Mitchel Humpherys1c47bb52015-10-02 16:17:57 -0700588 getnstimeofday(&tbefore);
589 unmapped = iommu_unmap(domain, iova, size);
590 if (unmapped != size) {
591 seq_printf(s,
592 "Only unmapped %zx instead of %zx\n",
593 unmapped, size);
594 continue;
595 }
596 getnstimeofday(&tafter);
597 diff = timespec_sub(tafter, tbefore);
Patrick Daly3ca31e32015-11-20 20:33:04 -0800598 unmap_elapsed_ns += timespec_to_ns(&diff);
Mitchel Humpherys42296fb2015-06-23 16:29:16 -0700599 }
Mitchel Humpherys1c47bb52015-10-02 16:17:57 -0700600
Patrick Daly3ca31e32015-11-20 20:33:04 -0800601 map_elapsed_ns /= iters_per_op;
602 unmap_elapsed_ns /= iters_per_op;
Mitchel Humpherys42296fb2015-06-23 16:29:16 -0700603
Patrick Daly3ca31e32015-11-20 20:33:04 -0800604 map_elapsed_us = div_u64_rem(map_elapsed_ns, 1000,
605 &map_elapsed_rem);
606 unmap_elapsed_us = div_u64_rem(unmap_elapsed_ns, 1000,
607 &unmap_elapsed_rem);
608
609 seq_printf(s, "%8s %12lld.%03d us %9lld.%03d us\n",
610 _size_to_string(size),
611 map_elapsed_us, map_elapsed_rem,
612 unmap_elapsed_us, unmap_elapsed_rem);
Mitchel Humpherys42296fb2015-06-23 16:29:16 -0700613 }
614
615 seq_putc(s, '\n');
Patrick Daly3ca31e32015-11-20 20:33:04 -0800616 seq_printf(s, "%8s %19s %16s\n", "size", "iommu_map_sg", "iommu_unmap");
Mitchel Humpherys42296fb2015-06-23 16:29:16 -0700617 for (sz = sizes; *sz; ++sz) {
618 unsigned long size = *sz;
619 size_t unmapped;
Patrick Daly3ca31e32015-11-20 20:33:04 -0800620 u64 map_elapsed_ns = 0, unmap_elapsed_ns = 0;
Mitchel Humpherys1c47bb52015-10-02 16:17:57 -0700621 u64 map_elapsed_us = 0, unmap_elapsed_us = 0;
Patrick Daly3ca31e32015-11-20 20:33:04 -0800622 u32 map_elapsed_rem = 0, unmap_elapsed_rem = 0;
Mitchel Humpherys42296fb2015-06-23 16:29:16 -0700623 struct timespec tbefore, tafter, diff;
624 struct sg_table table;
625 unsigned long chunk_size = SZ_4K;
Mitchel Humpherys1c47bb52015-10-02 16:17:57 -0700626 int i;
Mitchel Humpherys42296fb2015-06-23 16:29:16 -0700627
628 if (iommu_debug_build_phoney_sg_table(dev, &table, size,
629 chunk_size)) {
630 seq_puts(s,
631 "couldn't build phoney sg table! bailing...\n");
632 goto out_detach;
633 }
634
Patrick Dalye4e39862015-11-20 20:00:50 -0800635 for (i = 0; i < iters_per_op; ++i) {
Mitchel Humpherys1c47bb52015-10-02 16:17:57 -0700636 getnstimeofday(&tbefore);
637 if (iommu_map_sg(domain, iova, table.sgl, table.nents,
638 IOMMU_READ | IOMMU_WRITE) != size) {
639 seq_puts(s, "Failed to map_sg\n");
640 goto next;
641 }
642 getnstimeofday(&tafter);
643 diff = timespec_sub(tafter, tbefore);
Patrick Daly3ca31e32015-11-20 20:33:04 -0800644 map_elapsed_ns += timespec_to_ns(&diff);
Mitchel Humpherys42296fb2015-06-23 16:29:16 -0700645
Mitchel Humpherys1c47bb52015-10-02 16:17:57 -0700646 getnstimeofday(&tbefore);
647 unmapped = iommu_unmap(domain, iova, size);
648 if (unmapped != size) {
649 seq_printf(s,
650 "Only unmapped %zx instead of %zx\n",
651 unmapped, size);
652 goto next;
653 }
654 getnstimeofday(&tafter);
655 diff = timespec_sub(tafter, tbefore);
Patrick Daly3ca31e32015-11-20 20:33:04 -0800656 unmap_elapsed_ns += timespec_to_ns(&diff);
Mitchel Humpherys42296fb2015-06-23 16:29:16 -0700657 }
Mitchel Humpherys1c47bb52015-10-02 16:17:57 -0700658
Patrick Daly3ca31e32015-11-20 20:33:04 -0800659 map_elapsed_ns /= iters_per_op;
660 unmap_elapsed_ns /= iters_per_op;
Mitchel Humpherys42296fb2015-06-23 16:29:16 -0700661
Patrick Daly3ca31e32015-11-20 20:33:04 -0800662 map_elapsed_us = div_u64_rem(map_elapsed_ns, 1000,
663 &map_elapsed_rem);
664 unmap_elapsed_us = div_u64_rem(unmap_elapsed_ns, 1000,
665 &unmap_elapsed_rem);
666
667 seq_printf(s, "%8s %12lld.%03d us %9lld.%03d us\n",
668 _size_to_string(size),
669 map_elapsed_us, map_elapsed_rem,
670 unmap_elapsed_us, unmap_elapsed_rem);
Mitchel Humpherys42296fb2015-06-23 16:29:16 -0700671
672next:
673 iommu_debug_destroy_phoney_sg_table(dev, &table, chunk_size);
674 }
675
676out_detach:
677 iommu_detach_device(domain, dev);
678out_domain_free:
679 iommu_domain_free(domain);
680}
681
Mitchel Humpherys7cc56e42015-07-06 14:58:23 -0700682static int iommu_debug_profiling_show(struct seq_file *s, void *ignored)
Mitchel Humpherys42296fb2015-06-23 16:29:16 -0700683{
684 struct iommu_debug_device *ddev = s->private;
Mitchel Humpherysbc367fd2015-10-05 14:44:58 -0700685 const unsigned long sizes[] = { SZ_4K, SZ_64K, SZ_2M, SZ_1M * 12,
686 SZ_1M * 20, 0 };
687 enum iommu_attr attrs[] = {
688 DOMAIN_ATTR_ATOMIC,
689 };
690 int htw_disable = 1, atomic = 1;
691 void *attr_values[] = { &htw_disable, &atomic };
Mitchel Humpherys42296fb2015-06-23 16:29:16 -0700692
Mitchel Humpherysbc367fd2015-10-05 14:44:58 -0700693 iommu_debug_device_profiling(s, ddev->dev, attrs, attr_values,
694 ARRAY_SIZE(attrs), sizes);
Mitchel Humpherys42296fb2015-06-23 16:29:16 -0700695
696 return 0;
697}
698
Mitchel Humpherys7cc56e42015-07-06 14:58:23 -0700699static int iommu_debug_profiling_open(struct inode *inode, struct file *file)
Mitchel Humpherys42296fb2015-06-23 16:29:16 -0700700{
Mitchel Humpherys7cc56e42015-07-06 14:58:23 -0700701 return single_open(file, iommu_debug_profiling_show, inode->i_private);
Mitchel Humpherys42296fb2015-06-23 16:29:16 -0700702}
703
Mitchel Humpherys7cc56e42015-07-06 14:58:23 -0700704static const struct file_operations iommu_debug_profiling_fops = {
705 .open = iommu_debug_profiling_open,
Mitchel Humpherys42296fb2015-06-23 16:29:16 -0700706 .read = seq_read,
707 .llseek = seq_lseek,
708 .release = single_release,
709};
710
Mitchel Humpherys020f90f2015-10-02 16:02:31 -0700711static int iommu_debug_secure_profiling_show(struct seq_file *s, void *ignored)
712{
713 struct iommu_debug_device *ddev = s->private;
Mitchel Humpherysbc367fd2015-10-05 14:44:58 -0700714 const unsigned long sizes[] = { SZ_4K, SZ_64K, SZ_2M, SZ_1M * 12,
715 SZ_1M * 20, 0 };
Mitchel Humpherys020f90f2015-10-02 16:02:31 -0700716
Mitchel Humpherysbc367fd2015-10-05 14:44:58 -0700717 enum iommu_attr attrs[] = {
718 DOMAIN_ATTR_ATOMIC,
719 DOMAIN_ATTR_SECURE_VMID,
720 };
721 int one = 1, secure_vmid = VMID_CP_PIXEL;
722 void *attr_values[] = { &one, &secure_vmid };
723
724 iommu_debug_device_profiling(s, ddev->dev, attrs, attr_values,
725 ARRAY_SIZE(attrs), sizes);
Mitchel Humpherys020f90f2015-10-02 16:02:31 -0700726
727 return 0;
728}
729
730static int iommu_debug_secure_profiling_open(struct inode *inode,
731 struct file *file)
732{
733 return single_open(file, iommu_debug_secure_profiling_show,
734 inode->i_private);
735}
736
737static const struct file_operations iommu_debug_secure_profiling_fops = {
738 .open = iommu_debug_secure_profiling_open,
739 .read = seq_read,
740 .llseek = seq_lseek,
741 .release = single_release,
742};
743
Mitchel Humpherysbc367fd2015-10-05 14:44:58 -0700744static int iommu_debug_profiling_fast_show(struct seq_file *s, void *ignored)
745{
746 struct iommu_debug_device *ddev = s->private;
747 size_t sizes[] = {SZ_4K, SZ_8K, SZ_16K, SZ_64K, 0};
748 enum iommu_attr attrs[] = {
749 DOMAIN_ATTR_FAST,
750 DOMAIN_ATTR_ATOMIC,
751 };
752 int one = 1;
753 void *attr_values[] = { &one, &one };
754
755 iommu_debug_device_profiling(s, ddev->dev, attrs, attr_values,
756 ARRAY_SIZE(attrs), sizes);
757
758 return 0;
759}
760
761static int iommu_debug_profiling_fast_open(struct inode *inode,
762 struct file *file)
763{
764 return single_open(file, iommu_debug_profiling_fast_show,
765 inode->i_private);
766}
767
768static const struct file_operations iommu_debug_profiling_fast_fops = {
769 .open = iommu_debug_profiling_fast_open,
770 .read = seq_read,
771 .llseek = seq_lseek,
772 .release = single_release,
773};
774
Mitchel Humpherysac4c38b2015-07-30 19:40:21 -0700775static int iommu_debug_attach_do_attach(struct iommu_debug_device *ddev,
776 int val, bool is_secure)
Mitchel Humpherys0fe337d2015-07-06 15:21:24 -0700777{
778 ddev->domain = iommu_domain_alloc(&platform_bus_type);
779 if (!ddev->domain) {
780 pr_err("Couldn't allocate domain\n");
781 return -ENOMEM;
782 }
783
Mitchel Humpherysac4c38b2015-07-30 19:40:21 -0700784 if (is_secure && iommu_domain_set_attr(ddev->domain,
785 DOMAIN_ATTR_SECURE_VMID,
786 &val)) {
787 pr_err("Couldn't set secure vmid to %d\n", val);
788 goto out_domain_free;
789 }
790
Mitchel Humpherys0fe337d2015-07-06 15:21:24 -0700791 if (iommu_attach_device(ddev->domain, ddev->dev)) {
792 pr_err("Couldn't attach new domain to device. Is it already attached?\n");
793 goto out_domain_free;
794 }
795
796 return 0;
797
798out_domain_free:
799 iommu_domain_free(ddev->domain);
800 ddev->domain = NULL;
801 return -EIO;
802}
803
Mitchel Humpherysac4c38b2015-07-30 19:40:21 -0700804static ssize_t __iommu_debug_attach_write(struct file *file,
805 const char __user *ubuf,
806 size_t count, loff_t *offset,
807 bool is_secure)
Mitchel Humpherys0fe337d2015-07-06 15:21:24 -0700808{
809 struct iommu_debug_device *ddev = file->private_data;
810 ssize_t retval;
Mitchel Humpherysac4c38b2015-07-30 19:40:21 -0700811 int val;
Mitchel Humpherys0fe337d2015-07-06 15:21:24 -0700812
Mitchel Humpherysac4c38b2015-07-30 19:40:21 -0700813 if (kstrtoint_from_user(ubuf, count, 0, &val)) {
814 pr_err("Invalid format. Expected a hex or decimal integer");
Mitchel Humpherys0fe337d2015-07-06 15:21:24 -0700815 retval = -EFAULT;
816 goto out;
817 }
818
Mitchel Humpherysac4c38b2015-07-30 19:40:21 -0700819 if (val) {
Mitchel Humpherys0fe337d2015-07-06 15:21:24 -0700820 if (ddev->domain) {
821 pr_err("Already attached.\n");
822 retval = -EINVAL;
823 goto out;
824 }
825 if (WARN(ddev->dev->archdata.iommu,
826 "Attachment tracking out of sync with device\n")) {
827 retval = -EINVAL;
828 goto out;
829 }
Mitchel Humpherysac4c38b2015-07-30 19:40:21 -0700830 if (iommu_debug_attach_do_attach(ddev, val, is_secure)) {
Mitchel Humpherys0fe337d2015-07-06 15:21:24 -0700831 retval = -EIO;
832 goto out;
833 }
834 pr_err("Attached\n");
Mitchel Humpherysac4c38b2015-07-30 19:40:21 -0700835 } else {
Mitchel Humpherys0fe337d2015-07-06 15:21:24 -0700836 if (!ddev->domain) {
837 pr_err("No domain. Did you already attach?\n");
838 retval = -EINVAL;
839 goto out;
840 }
841 iommu_detach_device(ddev->domain, ddev->dev);
842 iommu_domain_free(ddev->domain);
843 ddev->domain = NULL;
844 pr_err("Detached\n");
Mitchel Humpherys0fe337d2015-07-06 15:21:24 -0700845 }
846
847 retval = count;
848out:
849 return retval;
850}
851
Mitchel Humpherysac4c38b2015-07-30 19:40:21 -0700852static ssize_t iommu_debug_attach_write(struct file *file,
853 const char __user *ubuf,
854 size_t count, loff_t *offset)
855{
856 return __iommu_debug_attach_write(file, ubuf, count, offset,
857 false);
858
859}
860
Mitchel Humpherys0fe337d2015-07-06 15:21:24 -0700861static ssize_t iommu_debug_attach_read(struct file *file, char __user *ubuf,
862 size_t count, loff_t *offset)
863{
864 struct iommu_debug_device *ddev = file->private_data;
865 char c[2];
866
867 if (*offset)
868 return 0;
869
870 c[0] = ddev->domain ? '1' : '0';
871 c[1] = '\n';
872 if (copy_to_user(ubuf, &c, 2)) {
873 pr_err("copy_to_user failed\n");
874 return -EFAULT;
875 }
876 *offset = 1; /* non-zero means we're done */
877
878 return 2;
879}
880
881static const struct file_operations iommu_debug_attach_fops = {
882 .open = simple_open,
883 .write = iommu_debug_attach_write,
884 .read = iommu_debug_attach_read,
885};
886
Mitchel Humpherysac4c38b2015-07-30 19:40:21 -0700887static ssize_t iommu_debug_attach_write_secure(struct file *file,
888 const char __user *ubuf,
889 size_t count, loff_t *offset)
890{
891 return __iommu_debug_attach_write(file, ubuf, count, offset,
892 true);
893
894}
895
896static const struct file_operations iommu_debug_secure_attach_fops = {
897 .open = simple_open,
898 .write = iommu_debug_attach_write_secure,
899 .read = iommu_debug_attach_read,
900};
901
Mitchel Humpherys0fe337d2015-07-06 15:21:24 -0700902static ssize_t iommu_debug_atos_write(struct file *file,
903 const char __user *ubuf,
904 size_t count, loff_t *offset)
905{
906 struct iommu_debug_device *ddev = file->private_data;
907 dma_addr_t iova;
908
909 if (kstrtoll_from_user(ubuf, count, 0, &iova)) {
910 pr_err("Invalid format for iova\n");
911 ddev->iova = 0;
912 return -EINVAL;
913 }
914
915 ddev->iova = iova;
916 pr_err("Saved iova=%pa for future ATOS commands\n", &iova);
917 return count;
918}
919
920static ssize_t iommu_debug_atos_read(struct file *file, char __user *ubuf,
921 size_t count, loff_t *offset)
922{
923 struct iommu_debug_device *ddev = file->private_data;
924 phys_addr_t phys;
925 char buf[100];
926 ssize_t retval;
927 size_t buflen;
928
929 if (!ddev->domain) {
930 pr_err("No domain. Did you already attach?\n");
931 return -EINVAL;
932 }
933
934 if (*offset)
935 return 0;
936
937 memset(buf, 0, 100);
938
939 phys = iommu_iova_to_phys_hard(ddev->domain, ddev->iova);
940 if (!phys)
941 strlcpy(buf, "FAIL\n", 100);
942 else
943 snprintf(buf, 100, "%pa\n", &phys);
944
945 buflen = strlen(buf);
946 if (copy_to_user(ubuf, buf, buflen)) {
947 pr_err("Couldn't copy_to_user\n");
948 retval = -EFAULT;
949 } else {
950 *offset = 1; /* non-zero means we're done */
951 retval = buflen;
952 }
953
954 return retval;
955}
956
957static const struct file_operations iommu_debug_atos_fops = {
958 .open = simple_open,
959 .write = iommu_debug_atos_write,
960 .read = iommu_debug_atos_read,
961};
962
963static ssize_t iommu_debug_map_write(struct file *file, const char __user *ubuf,
964 size_t count, loff_t *offset)
965{
966 ssize_t retval;
967 int ret;
968 char *comma1, *comma2, *comma3;
969 char buf[100];
970 dma_addr_t iova;
971 phys_addr_t phys;
972 size_t size;
973 int prot;
974 struct iommu_debug_device *ddev = file->private_data;
975
976 if (count >= 100) {
977 pr_err("Value too large\n");
978 return -EINVAL;
979 }
980
981 if (!ddev->domain) {
982 pr_err("No domain. Did you already attach?\n");
983 return -EINVAL;
984 }
985
986 memset(buf, 0, 100);
987
988 if (copy_from_user(buf, ubuf, count)) {
989 pr_err("Couldn't copy from user\n");
990 retval = -EFAULT;
991 }
992
993 comma1 = strnchr(buf, count, ',');
994 if (!comma1)
995 goto invalid_format;
996
997 comma2 = strnchr(comma1 + 1, count, ',');
998 if (!comma2)
999 goto invalid_format;
1000
1001 comma3 = strnchr(comma2 + 1, count, ',');
1002 if (!comma3)
1003 goto invalid_format;
1004
1005 /* split up the words */
1006 *comma1 = *comma2 = *comma3 = '\0';
1007
1008 if (kstrtou64(buf, 0, &iova))
1009 goto invalid_format;
1010
1011 if (kstrtou64(comma1 + 1, 0, &phys))
1012 goto invalid_format;
1013
1014 if (kstrtoul(comma2 + 1, 0, &size))
1015 goto invalid_format;
1016
1017 if (kstrtoint(comma3 + 1, 0, &prot))
1018 goto invalid_format;
1019
1020 ret = iommu_map(ddev->domain, iova, phys, size, prot);
1021 if (ret) {
1022 pr_err("iommu_map failed with %d\n", ret);
1023 retval = -EIO;
1024 goto out;
1025 }
1026
1027 retval = count;
1028 pr_err("Mapped %pa to %pa (len=0x%zx, prot=0x%x)\n",
1029 &iova, &phys, size, prot);
1030out:
1031 return retval;
1032
1033invalid_format:
1034 pr_err("Invalid format. Expected: iova,phys,len,prot where `prot' is the bitwise OR of IOMMU_READ, IOMMU_WRITE, etc.\n");
1035 return -EINVAL;
1036}
1037
1038static const struct file_operations iommu_debug_map_fops = {
1039 .open = simple_open,
1040 .write = iommu_debug_map_write,
1041};
1042
1043static ssize_t iommu_debug_unmap_write(struct file *file,
1044 const char __user *ubuf,
1045 size_t count, loff_t *offset)
1046{
1047 ssize_t retval = 0;
1048 char *comma1;
1049 char buf[100];
1050 dma_addr_t iova;
1051 size_t size;
1052 size_t unmapped;
1053 struct iommu_debug_device *ddev = file->private_data;
1054
1055 if (count >= 100) {
1056 pr_err("Value too large\n");
1057 return -EINVAL;
1058 }
1059
1060 if (!ddev->domain) {
1061 pr_err("No domain. Did you already attach?\n");
1062 return -EINVAL;
1063 }
1064
1065 memset(buf, 0, 100);
1066
1067 if (copy_from_user(buf, ubuf, count)) {
1068 pr_err("Couldn't copy from user\n");
1069 retval = -EFAULT;
1070 goto out;
1071 }
1072
1073 comma1 = strnchr(buf, count, ',');
1074 if (!comma1)
1075 goto invalid_format;
1076
1077 /* split up the words */
1078 *comma1 = '\0';
1079
1080 if (kstrtou64(buf, 0, &iova))
1081 goto invalid_format;
1082
Mitchel Humpherys70b75112015-07-29 12:45:29 -07001083 if (kstrtoul(comma1 + 1, 0, &size))
Mitchel Humpherys0fe337d2015-07-06 15:21:24 -07001084 goto invalid_format;
1085
1086 unmapped = iommu_unmap(ddev->domain, iova, size);
1087 if (unmapped != size) {
1088 pr_err("iommu_unmap failed. Expected to unmap: 0x%zx, unmapped: 0x%zx",
1089 size, unmapped);
1090 return -EIO;
1091 }
1092
1093 retval = count;
1094 pr_err("Unmapped %pa (len=0x%zx)\n", &iova, size);
1095out:
1096 return retval;
1097
1098invalid_format:
1099 pr_err("Invalid format. Expected: iova,len\n");
1100 return retval;
1101}
1102
1103static const struct file_operations iommu_debug_unmap_fops = {
1104 .open = simple_open,
1105 .write = iommu_debug_unmap_write,
1106};
1107
Mitchel Humpherys42296fb2015-06-23 16:29:16 -07001108/*
1109 * The following will only work for drivers that implement the generic
1110 * device tree bindings described in
1111 * Documentation/devicetree/bindings/iommu/iommu.txt
1112 */
1113static int snarf_iommu_devices(struct device *dev, void *ignored)
1114{
1115 struct iommu_debug_device *ddev;
Mitchel Humpherys0fe337d2015-07-06 15:21:24 -07001116 struct dentry *dir;
Mitchel Humpherys42296fb2015-06-23 16:29:16 -07001117
1118 if (!of_find_property(dev->of_node, "iommus", NULL))
1119 return 0;
1120
Mitchel Humpherys89924fd2015-07-09 14:50:22 -07001121 ddev = kzalloc(sizeof(*ddev), GFP_KERNEL);
Mitchel Humpherys42296fb2015-06-23 16:29:16 -07001122 if (!ddev)
1123 return -ENODEV;
1124 ddev->dev = dev;
1125 dir = debugfs_create_dir(dev_name(dev), debugfs_tests_dir);
1126 if (!dir) {
1127 pr_err("Couldn't create iommu/devices/%s debugfs dir\n",
1128 dev_name(dev));
1129 goto err;
1130 }
Mitchel Humpherys0fe337d2015-07-06 15:21:24 -07001131
Patrick Dalye4e39862015-11-20 20:00:50 -08001132 if (!debugfs_create_file("nr_iters", S_IRUSR, dir, &iters_per_op,
1133 &iommu_debug_nr_iters_ops)) {
1134 pr_err("Couldn't create iommu/devices/%s/nr_iters debugfs file\n",
1135 dev_name(dev));
1136 goto err_rmdir;
1137 }
1138
Mitchel Humpherys0fe337d2015-07-06 15:21:24 -07001139 if (!debugfs_create_file("profiling", S_IRUSR, dir, ddev,
1140 &iommu_debug_profiling_fops)) {
Mitchel Humpherys42296fb2015-06-23 16:29:16 -07001141 pr_err("Couldn't create iommu/devices/%s/profiling debugfs file\n",
1142 dev_name(dev));
1143 goto err_rmdir;
1144 }
1145
Mitchel Humpherys020f90f2015-10-02 16:02:31 -07001146 if (!debugfs_create_file("secure_profiling", S_IRUSR, dir, ddev,
1147 &iommu_debug_secure_profiling_fops)) {
1148 pr_err("Couldn't create iommu/devices/%s/secure_profiling debugfs file\n",
1149 dev_name(dev));
1150 goto err_rmdir;
1151 }
1152
Mitchel Humpherysbc367fd2015-10-05 14:44:58 -07001153 if (!debugfs_create_file("profiling_fast", S_IRUSR, dir, ddev,
1154 &iommu_debug_profiling_fast_fops)) {
1155 pr_err("Couldn't create iommu/devices/%s/profiling_fast debugfs file\n",
1156 dev_name(dev));
1157 goto err_rmdir;
1158 }
1159
Mitchel Humpherys0fe337d2015-07-06 15:21:24 -07001160 if (!debugfs_create_file("attach", S_IRUSR, dir, ddev,
1161 &iommu_debug_attach_fops)) {
1162 pr_err("Couldn't create iommu/devices/%s/attach debugfs file\n",
1163 dev_name(dev));
1164 goto err_rmdir;
1165 }
1166
Mitchel Humpherysac4c38b2015-07-30 19:40:21 -07001167 if (!debugfs_create_file("secure_attach", S_IRUSR, dir, ddev,
1168 &iommu_debug_secure_attach_fops)) {
1169 pr_err("Couldn't create iommu/devices/%s/secure_attach debugfs file\n",
1170 dev_name(dev));
1171 goto err_rmdir;
1172 }
1173
Mitchel Humpherys0fe337d2015-07-06 15:21:24 -07001174 if (!debugfs_create_file("atos", S_IWUSR, dir, ddev,
1175 &iommu_debug_atos_fops)) {
1176 pr_err("Couldn't create iommu/devices/%s/atos debugfs file\n",
1177 dev_name(dev));
1178 goto err_rmdir;
1179 }
1180
1181 if (!debugfs_create_file("map", S_IWUSR, dir, ddev,
1182 &iommu_debug_map_fops)) {
1183 pr_err("Couldn't create iommu/devices/%s/map debugfs file\n",
1184 dev_name(dev));
1185 goto err_rmdir;
1186 }
1187
1188 if (!debugfs_create_file("unmap", S_IWUSR, dir, ddev,
1189 &iommu_debug_unmap_fops)) {
1190 pr_err("Couldn't create iommu/devices/%s/unmap debugfs file\n",
1191 dev_name(dev));
1192 goto err_rmdir;
1193 }
1194
Mitchel Humpherys42296fb2015-06-23 16:29:16 -07001195 list_add(&ddev->list, &iommu_debug_devices);
1196 return 0;
1197
1198err_rmdir:
1199 debugfs_remove_recursive(dir);
1200err:
1201 kfree(ddev);
1202 return 0;
1203}
1204
1205static int iommu_debug_init_tests(void)
1206{
1207 debugfs_tests_dir = debugfs_create_dir("tests",
Mitchel Humpherysc75ae492015-07-15 18:27:36 -07001208 iommu_debugfs_top);
Mitchel Humpherys42296fb2015-06-23 16:29:16 -07001209 if (!debugfs_tests_dir) {
1210 pr_err("Couldn't create iommu/tests debugfs directory\n");
1211 return -ENODEV;
1212 }
1213
1214 return bus_for_each_dev(&platform_bus_type, NULL, NULL,
1215 snarf_iommu_devices);
1216}
Mitchel Humpherysc75ae492015-07-15 18:27:36 -07001217
1218static void iommu_debug_destroy_tests(void)
1219{
1220 debugfs_remove_recursive(debugfs_tests_dir);
1221}
Mitchel Humpherys42296fb2015-06-23 16:29:16 -07001222#else
1223static inline int iommu_debug_init_tests(void) { return 0; }
Mitchel Humpherysc75ae492015-07-15 18:27:36 -07001224static inline void iommu_debug_destroy_tests(void) { }
Mitchel Humpherys42296fb2015-06-23 16:29:16 -07001225#endif
1226
Mitchel Humpherys93f7eef2016-04-13 17:08:49 -07001227/*
1228 * This isn't really a "driver", we just need something in the device tree
1229 * so that our tests can run without any client drivers, and our tests rely
1230 * on parsing the device tree for nodes with the `iommus' property.
1231 */
1232static int iommu_debug_pass(struct platform_device *pdev)
1233{
1234 return 0;
1235}
1236
1237static const struct of_device_id iommu_debug_of_match[] = {
1238 { .compatible = "iommu-debug-test" },
1239 { },
1240};
1241
1242static struct platform_driver iommu_debug_driver = {
1243 .probe = iommu_debug_pass,
1244 .remove = iommu_debug_pass,
1245 .driver = {
1246 .name = "iommu-debug",
1247 .of_match_table = iommu_debug_of_match,
1248 },
1249};
1250
Mitchel Humpherys42296fb2015-06-23 16:29:16 -07001251static int iommu_debug_init(void)
1252{
Mitchel Humpherys42296fb2015-06-23 16:29:16 -07001253 if (iommu_debug_init_tracking())
Mitchel Humpherysc75ae492015-07-15 18:27:36 -07001254 return -ENODEV;
Mitchel Humpherys42296fb2015-06-23 16:29:16 -07001255
1256 if (iommu_debug_init_tests())
Mitchel Humpherysc75ae492015-07-15 18:27:36 -07001257 return -ENODEV;
Mitchel Humpherys42296fb2015-06-23 16:29:16 -07001258
Mitchel Humpherys93f7eef2016-04-13 17:08:49 -07001259 return platform_driver_register(&iommu_debug_driver);
Mitchel Humpherys42296fb2015-06-23 16:29:16 -07001260}
1261
1262static void iommu_debug_exit(void)
1263{
Mitchel Humpherys93f7eef2016-04-13 17:08:49 -07001264 platform_driver_unregister(&iommu_debug_driver);
Mitchel Humpherysc75ae492015-07-15 18:27:36 -07001265 iommu_debug_destroy_tracking();
1266 iommu_debug_destroy_tests();
Mitchel Humpherys42296fb2015-06-23 16:29:16 -07001267}
1268
1269module_init(iommu_debug_init);
1270module_exit(iommu_debug_exit);