blob: 5b79fe24b384de7c78378893c3156754406fa089 [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 Humpherysbe3060c2015-10-08 15:08:01 -070027#include <linux/dma-mapping.h>
28#include <asm/cacheflush.h>
29#include <asm/dma-iommu.h>
Mitchel Humpherys42296fb2015-06-23 16:29:16 -070030
Mitchel Humpherysbc367fd2015-10-05 14:44:58 -070031static const char *iommu_debug_attr_to_string(enum iommu_attr attr)
32{
33 switch (attr) {
34 case DOMAIN_ATTR_GEOMETRY:
35 return "DOMAIN_ATTR_GEOMETRY";
36 case DOMAIN_ATTR_PAGING:
37 return "DOMAIN_ATTR_PAGING";
38 case DOMAIN_ATTR_WINDOWS:
39 return "DOMAIN_ATTR_WINDOWS";
40 case DOMAIN_ATTR_FSL_PAMU_STASH:
41 return "DOMAIN_ATTR_FSL_PAMU_STASH";
42 case DOMAIN_ATTR_FSL_PAMU_ENABLE:
43 return "DOMAIN_ATTR_FSL_PAMU_ENABLE";
44 case DOMAIN_ATTR_FSL_PAMUV1:
45 return "DOMAIN_ATTR_FSL_PAMUV1";
46 case DOMAIN_ATTR_NESTING:
47 return "DOMAIN_ATTR_NESTING";
48 case DOMAIN_ATTR_PT_BASE_ADDR:
49 return "DOMAIN_ATTR_PT_BASE_ADDR";
50 case DOMAIN_ATTR_SECURE_VMID:
51 return "DOMAIN_ATTR_SECURE_VMID";
52 case DOMAIN_ATTR_ATOMIC:
53 return "DOMAIN_ATTR_ATOMIC";
54 case DOMAIN_ATTR_CONTEXT_BANK:
55 return "DOMAIN_ATTR_CONTEXT_BANK";
56 case DOMAIN_ATTR_TTBR0:
57 return "DOMAIN_ATTR_TTBR0";
58 case DOMAIN_ATTR_CONTEXTIDR:
59 return "DOMAIN_ATTR_CONTEXTIDR";
60 case DOMAIN_ATTR_PROCID:
61 return "DOMAIN_ATTR_PROCID";
62 case DOMAIN_ATTR_DYNAMIC:
63 return "DOMAIN_ATTR_DYNAMIC";
64 case DOMAIN_ATTR_NON_FATAL_FAULTS:
65 return "DOMAIN_ATTR_NON_FATAL_FAULTS";
66 case DOMAIN_ATTR_S1_BYPASS:
67 return "DOMAIN_ATTR_S1_BYPASS";
68 case DOMAIN_ATTR_FAST:
69 return "DOMAIN_ATTR_FAST";
70 default:
71 return "Unknown attr!";
72 }
73}
74
Mitchel Humpherys42296fb2015-06-23 16:29:16 -070075#ifdef CONFIG_IOMMU_DEBUG_TRACKING
76
77static DEFINE_MUTEX(iommu_debug_attachments_lock);
78static LIST_HEAD(iommu_debug_attachments);
79static struct dentry *debugfs_attachments_dir;
80
81struct iommu_debug_attachment {
82 struct iommu_domain *domain;
83 struct device *dev;
84 struct dentry *dentry;
85 struct list_head list;
Mitchel Humpherys0dc04de2015-08-21 14:08:40 -070086 unsigned long reg_offset;
Mitchel Humpherys42296fb2015-06-23 16:29:16 -070087};
88
Mitchel Humpherys088cc582015-07-09 15:02:03 -070089static int iommu_debug_attachment_info_show(struct seq_file *s, void *ignored)
Mitchel Humpherys42296fb2015-06-23 16:29:16 -070090{
91 struct iommu_debug_attachment *attach = s->private;
Mitchel Humpherys5e991f12015-07-30 19:25:54 -070092 int secure_vmid;
Mitchel Humpherys42296fb2015-06-23 16:29:16 -070093
94 seq_printf(s, "Domain: 0x%p\n", attach->domain);
Mitchel Humpherys5e991f12015-07-30 19:25:54 -070095
96 seq_puts(s, "SECURE_VMID: ");
97 if (iommu_domain_get_attr(attach->domain,
98 DOMAIN_ATTR_SECURE_VMID,
99 &secure_vmid))
100 seq_puts(s, "(Unknown)\n");
101 else
102 seq_printf(s, "%s (0x%x)\n",
103 msm_secure_vmid_to_string(secure_vmid), secure_vmid);
104
Mitchel Humpherys42296fb2015-06-23 16:29:16 -0700105 return 0;
106}
107
Mitchel Humpherys088cc582015-07-09 15:02:03 -0700108static int iommu_debug_attachment_info_open(struct inode *inode,
109 struct file *file)
Mitchel Humpherys42296fb2015-06-23 16:29:16 -0700110{
Mitchel Humpherys088cc582015-07-09 15:02:03 -0700111 return single_open(file, iommu_debug_attachment_info_show,
112 inode->i_private);
Mitchel Humpherys42296fb2015-06-23 16:29:16 -0700113}
114
Mitchel Humpherys088cc582015-07-09 15:02:03 -0700115static const struct file_operations iommu_debug_attachment_info_fops = {
116 .open = iommu_debug_attachment_info_open,
Mitchel Humpherys42296fb2015-06-23 16:29:16 -0700117 .read = seq_read,
118 .llseek = seq_lseek,
119 .release = single_release,
120};
121
Mitchel Humpherys288086e2015-07-09 16:55:08 -0700122static ssize_t iommu_debug_attachment_trigger_fault_write(
123 struct file *file, const char __user *ubuf, size_t count,
124 loff_t *offset)
125{
126 struct iommu_debug_attachment *attach = file->private_data;
127 unsigned long flags;
128
129 if (kstrtoul_from_user(ubuf, count, 0, &flags)) {
130 pr_err("Invalid flags format\n");
131 return -EFAULT;
132 }
133
134 iommu_trigger_fault(attach->domain, flags);
135
136 return count;
137}
138
139static const struct file_operations
140iommu_debug_attachment_trigger_fault_fops = {
141 .open = simple_open,
142 .write = iommu_debug_attachment_trigger_fault_write,
143};
144
Mitchel Humpherys0dc04de2015-08-21 14:08:40 -0700145static ssize_t iommu_debug_attachment_reg_offset_write(
146 struct file *file, const char __user *ubuf, size_t count,
147 loff_t *offset)
148{
149 struct iommu_debug_attachment *attach = file->private_data;
150 unsigned long reg_offset;
151
152 if (kstrtoul_from_user(ubuf, count, 0, &reg_offset)) {
153 pr_err("Invalid reg_offset format\n");
154 return -EFAULT;
155 }
156
157 attach->reg_offset = reg_offset;
158
159 return count;
160}
161
162static const struct file_operations iommu_debug_attachment_reg_offset_fops = {
163 .open = simple_open,
164 .write = iommu_debug_attachment_reg_offset_write,
165};
166
167static ssize_t iommu_debug_attachment_reg_read_read(
168 struct file *file, char __user *ubuf, size_t count, loff_t *offset)
169{
170 struct iommu_debug_attachment *attach = file->private_data;
171 unsigned long val;
172 char *val_str;
173 ssize_t val_str_len;
174
175 if (*offset)
176 return 0;
177
178 val = iommu_reg_read(attach->domain, attach->reg_offset);
179 val_str = kasprintf(GFP_KERNEL, "0x%lx\n", val);
180 if (!val_str)
181 return -ENOMEM;
182 val_str_len = strlen(val_str);
183
184 if (copy_to_user(ubuf, val_str, val_str_len)) {
185 pr_err("copy_to_user failed\n");
186 val_str_len = -EFAULT;
187 goto out;
188 }
189 *offset = 1; /* non-zero means we're done */
190
191out:
192 kfree(val_str);
193 return val_str_len;
194}
195
196static const struct file_operations iommu_debug_attachment_reg_read_fops = {
197 .open = simple_open,
198 .read = iommu_debug_attachment_reg_read_read,
199};
200
201static ssize_t iommu_debug_attachment_reg_write_write(
202 struct file *file, const char __user *ubuf, size_t count,
203 loff_t *offset)
204{
205 struct iommu_debug_attachment *attach = file->private_data;
206 unsigned long val;
207
208 if (kstrtoul_from_user(ubuf, count, 0, &val)) {
209 pr_err("Invalid val format\n");
210 return -EFAULT;
211 }
212
213 iommu_reg_write(attach->domain, attach->reg_offset, val);
214
215 return count;
216}
217
218static const struct file_operations iommu_debug_attachment_reg_write_fops = {
219 .open = simple_open,
220 .write = iommu_debug_attachment_reg_write_write,
221};
222
Mitchel Humpherysa05b2522015-07-14 14:30:33 -0700223/* should be called with iommu_debug_attachments_lock locked */
224static int iommu_debug_attach_add_debugfs(
225 struct iommu_debug_attachment *attach)
Mitchel Humpherys42296fb2015-06-23 16:29:16 -0700226{
Mitchel Humpherys54379212015-08-26 11:52:57 -0700227 const char *attach_name;
Mitchel Humpherysa05b2522015-07-14 14:30:33 -0700228 struct device *dev = attach->dev;
229 struct iommu_domain *domain = attach->domain;
Mitchel Humpherys54379212015-08-26 11:52:57 -0700230 int is_dynamic;
Mitchel Humpherys42296fb2015-06-23 16:29:16 -0700231
Mitchel Humpherys54379212015-08-26 11:52:57 -0700232 if (iommu_domain_get_attr(domain, DOMAIN_ATTR_DYNAMIC, &is_dynamic))
233 is_dynamic = 0;
234
235 if (is_dynamic) {
236 uuid_le uuid;
237
238 uuid_le_gen(&uuid);
239 attach_name = kasprintf(GFP_KERNEL, "%s-%pUl", dev_name(dev),
240 uuid.b);
241 if (!attach_name)
242 return -ENOMEM;
243 } else {
244 attach_name = dev_name(dev);
245 }
Mitchel Humpherys42296fb2015-06-23 16:29:16 -0700246
Mitchel Humpherys088cc582015-07-09 15:02:03 -0700247 attach->dentry = debugfs_create_dir(attach_name,
248 debugfs_attachments_dir);
Mitchel Humpherys42296fb2015-06-23 16:29:16 -0700249 if (!attach->dentry) {
Mitchel Humpherys088cc582015-07-09 15:02:03 -0700250 pr_err("Couldn't create iommu/attachments/%s debugfs directory for domain 0x%p\n",
Mitchel Humpherys876e2be2015-07-10 11:56:56 -0700251 attach_name, domain);
Mitchel Humpherys54379212015-08-26 11:52:57 -0700252 if (is_dynamic)
253 kfree(attach_name);
Mitchel Humpherysa05b2522015-07-14 14:30:33 -0700254 return -EIO;
Mitchel Humpherys42296fb2015-06-23 16:29:16 -0700255 }
Mitchel Humpherys54379212015-08-26 11:52:57 -0700256
257 if (is_dynamic)
258 kfree(attach_name);
Mitchel Humpherys42296fb2015-06-23 16:29:16 -0700259
Mitchel Humpherys088cc582015-07-09 15:02:03 -0700260 if (!debugfs_create_file(
261 "info", S_IRUSR, attach->dentry, attach,
262 &iommu_debug_attachment_info_fops)) {
263 pr_err("Couldn't create iommu/attachments/%s/info debugfs file for domain 0x%p\n",
264 dev_name(dev), domain);
Mitchel Humpherysa05b2522015-07-14 14:30:33 -0700265 goto err_rmdir;
Mitchel Humpherys088cc582015-07-09 15:02:03 -0700266 }
267
Mitchel Humpherys288086e2015-07-09 16:55:08 -0700268 if (!debugfs_create_file(
269 "trigger_fault", S_IRUSR, attach->dentry, attach,
270 &iommu_debug_attachment_trigger_fault_fops)) {
271 pr_err("Couldn't create iommu/attachments/%s/trigger_fault debugfs file for domain 0x%p\n",
272 dev_name(dev), domain);
273 goto err_rmdir;
Mitchel Humpherys0dc04de2015-08-21 14:08:40 -0700274 }
275
276 if (!debugfs_create_file(
277 "reg_offset", S_IRUSR, attach->dentry, attach,
278 &iommu_debug_attachment_reg_offset_fops)) {
279 pr_err("Couldn't create iommu/attachments/%s/reg_offset debugfs file for domain 0x%p\n",
280 dev_name(dev), domain);
281 goto err_rmdir;
282 }
283
284 if (!debugfs_create_file(
285 "reg_read", S_IRUSR, attach->dentry, attach,
286 &iommu_debug_attachment_reg_read_fops)) {
287 pr_err("Couldn't create iommu/attachments/%s/reg_read debugfs file for domain 0x%p\n",
288 dev_name(dev), domain);
289 goto err_rmdir;
290 }
291
292 if (!debugfs_create_file(
293 "reg_write", S_IRUSR, attach->dentry, attach,
294 &iommu_debug_attachment_reg_write_fops)) {
295 pr_err("Couldn't create iommu/attachments/%s/reg_write debugfs file for domain 0x%p\n",
296 dev_name(dev), domain);
297 goto err_rmdir;
298 }
299
Mitchel Humpherysa05b2522015-07-14 14:30:33 -0700300 return 0;
301
302err_rmdir:
303 debugfs_remove_recursive(attach->dentry);
304 return -EIO;
305}
306
Susheel Khianie66aa5b2015-08-25 17:25:42 +0530307void iommu_debug_domain_add(struct iommu_domain *domain)
Mitchel Humpherysa05b2522015-07-14 14:30:33 -0700308{
309 struct iommu_debug_attachment *attach;
310
311 mutex_lock(&iommu_debug_attachments_lock);
312
313 attach = kmalloc(sizeof(*attach), GFP_KERNEL);
314 if (!attach)
315 goto out_unlock;
316
317 attach->domain = domain;
Susheel Khianie66aa5b2015-08-25 17:25:42 +0530318 attach->dev = NULL;
Mitchel Humpherys42296fb2015-06-23 16:29:16 -0700319 list_add(&attach->list, &iommu_debug_attachments);
Susheel Khianie66aa5b2015-08-25 17:25:42 +0530320
Mitchel Humpherysa05b2522015-07-14 14:30:33 -0700321out_unlock:
Mitchel Humpherys42296fb2015-06-23 16:29:16 -0700322 mutex_unlock(&iommu_debug_attachments_lock);
323}
324
Susheel Khianie66aa5b2015-08-25 17:25:42 +0530325void iommu_debug_domain_remove(struct iommu_domain *domain)
326{
327 struct iommu_debug_attachment *it;
328
329 mutex_lock(&iommu_debug_attachments_lock);
330 list_for_each_entry(it, &iommu_debug_attachments, list)
331 if (it->domain == domain && it->dev == NULL)
332 break;
333
334 if (&it->list == &iommu_debug_attachments) {
335 WARN(1, "Couldn't find debug attachment for domain=0x%p",
336 domain);
337 } else {
338 list_del(&it->list);
339 kfree(it);
340 }
341 mutex_unlock(&iommu_debug_attachments_lock);
342}
343
344void iommu_debug_attach_device(struct iommu_domain *domain,
345 struct device *dev)
346{
347 struct iommu_debug_attachment *attach;
348
349 mutex_lock(&iommu_debug_attachments_lock);
350
351 list_for_each_entry(attach, &iommu_debug_attachments, list)
352 if (attach->domain == domain && attach->dev == NULL)
353 break;
354
355 if (&attach->list == &iommu_debug_attachments) {
356 WARN(1, "Couldn't find debug attachment for domain=0x%p dev=%s",
357 domain, dev_name(dev));
358 } else {
359 attach->dev = dev;
360
361 /*
362 * we might not init until after other drivers start calling
363 * iommu_attach_device. Only set up the debugfs nodes if we've
364 * already init'd to avoid polluting the top-level debugfs
365 * directory (by calling debugfs_create_dir with a NULL
366 * parent). These will be flushed out later once we init.
367 */
368
369 if (debugfs_attachments_dir)
370 iommu_debug_attach_add_debugfs(attach);
371 }
372
373 mutex_unlock(&iommu_debug_attachments_lock);
374}
375
Mitchel Humpherys42296fb2015-06-23 16:29:16 -0700376void iommu_debug_detach_device(struct iommu_domain *domain,
377 struct device *dev)
378{
379 struct iommu_debug_attachment *it;
380
381 mutex_lock(&iommu_debug_attachments_lock);
382 list_for_each_entry(it, &iommu_debug_attachments, list)
383 if (it->domain == domain && it->dev == dev)
384 break;
385
386 if (&it->list == &iommu_debug_attachments) {
387 WARN(1, "Couldn't find debug attachment for domain=0x%p dev=%s",
388 domain, dev_name(dev));
389 } else {
Susheel Khianie66aa5b2015-08-25 17:25:42 +0530390 /*
391 * Just remove debugfs entry and mark dev as NULL on
392 * iommu_detach call. We would remove the actual
393 * attachment entry from the list only on domain_free call.
394 * This is to ensure we keep track of unattached domains too.
395 */
396
Mitchel Humpherys42296fb2015-06-23 16:29:16 -0700397 debugfs_remove_recursive(it->dentry);
Susheel Khianie66aa5b2015-08-25 17:25:42 +0530398 it->dev = NULL;
Mitchel Humpherys42296fb2015-06-23 16:29:16 -0700399 }
400 mutex_unlock(&iommu_debug_attachments_lock);
401}
402
403static int iommu_debug_init_tracking(void)
404{
Mitchel Humpherysa05b2522015-07-14 14:30:33 -0700405 int ret = 0;
406 struct iommu_debug_attachment *attach;
407
408 mutex_lock(&iommu_debug_attachments_lock);
Mitchel Humpherys42296fb2015-06-23 16:29:16 -0700409 debugfs_attachments_dir = debugfs_create_dir("attachments",
Mitchel Humpherysc75ae492015-07-15 18:27:36 -0700410 iommu_debugfs_top);
Mitchel Humpherys42296fb2015-06-23 16:29:16 -0700411 if (!debugfs_attachments_dir) {
412 pr_err("Couldn't create iommu/attachments debugfs directory\n");
Mitchel Humpherysa05b2522015-07-14 14:30:33 -0700413 ret = -ENODEV;
414 goto out_unlock;
Mitchel Humpherys42296fb2015-06-23 16:29:16 -0700415 }
416
Mitchel Humpherysa05b2522015-07-14 14:30:33 -0700417 /* set up debugfs entries for attachments made during early boot */
418 list_for_each_entry(attach, &iommu_debug_attachments, list)
Susheel Khianie66aa5b2015-08-25 17:25:42 +0530419 if (attach->dev)
420 iommu_debug_attach_add_debugfs(attach);
Mitchel Humpherysa05b2522015-07-14 14:30:33 -0700421
422out_unlock:
423 mutex_unlock(&iommu_debug_attachments_lock);
424 return ret;
Mitchel Humpherys42296fb2015-06-23 16:29:16 -0700425}
Mitchel Humpherysc75ae492015-07-15 18:27:36 -0700426
427static void iommu_debug_destroy_tracking(void)
428{
429 debugfs_remove_recursive(debugfs_attachments_dir);
430}
Mitchel Humpherys42296fb2015-06-23 16:29:16 -0700431#else
432static inline int iommu_debug_init_tracking(void) { return 0; }
Mitchel Humpherysc75ae492015-07-15 18:27:36 -0700433static inline void iommu_debug_destroy_tracking(void) { }
Mitchel Humpherys42296fb2015-06-23 16:29:16 -0700434#endif
435
436#ifdef CONFIG_IOMMU_TESTS
437
438static LIST_HEAD(iommu_debug_devices);
439static struct dentry *debugfs_tests_dir;
Patrick Dalye4e39862015-11-20 20:00:50 -0800440static u32 iters_per_op = 1;
Mitchel Humpherys42296fb2015-06-23 16:29:16 -0700441
442struct iommu_debug_device {
443 struct device *dev;
Mitchel Humpherys0fe337d2015-07-06 15:21:24 -0700444 struct iommu_domain *domain;
445 u64 iova;
446 u64 phys;
447 size_t len;
Mitchel Humpherys42296fb2015-06-23 16:29:16 -0700448 struct list_head list;
449};
450
451static int iommu_debug_build_phoney_sg_table(struct device *dev,
452 struct sg_table *table,
453 unsigned long total_size,
454 unsigned long chunk_size)
455{
456 unsigned long nents = total_size / chunk_size;
457 struct scatterlist *sg;
458 int i;
459 struct page *page;
460
461 if (!IS_ALIGNED(total_size, PAGE_SIZE))
462 return -EINVAL;
463 if (!IS_ALIGNED(total_size, chunk_size))
464 return -EINVAL;
465 if (sg_alloc_table(table, nents, GFP_KERNEL))
466 return -EINVAL;
467 page = alloc_pages(GFP_KERNEL, get_order(chunk_size));
468 if (!page)
469 goto free_table;
470
471 /* all the same page... why not. */
472 for_each_sg(table->sgl, sg, table->nents, i)
473 sg_set_page(sg, page, chunk_size, 0);
474
475 return 0;
476
477free_table:
478 sg_free_table(table);
479 return -ENOMEM;
480}
481
482static void iommu_debug_destroy_phoney_sg_table(struct device *dev,
483 struct sg_table *table,
484 unsigned long chunk_size)
485{
486 __free_pages(sg_page(table->sgl), get_order(chunk_size));
487 sg_free_table(table);
488}
489
490static const char * const _size_to_string(unsigned long size)
491{
492 switch (size) {
493 case SZ_4K:
494 return "4K";
Mitchel Humpherysbc367fd2015-10-05 14:44:58 -0700495 case SZ_8K:
496 return "8K";
497 case SZ_16K:
498 return "16K";
Mitchel Humpherys42296fb2015-06-23 16:29:16 -0700499 case SZ_64K:
500 return "64K";
501 case SZ_2M:
502 return "2M";
503 case SZ_1M * 12:
504 return "12M";
505 case SZ_1M * 20:
506 return "20M";
507 }
508 return "unknown size, please add to _size_to_string";
509}
510
Patrick Dalye4e39862015-11-20 20:00:50 -0800511static int nr_iters_set(void *data, u64 val)
512{
513 if (!val)
514 val = 1;
515 if (val > 10000)
516 val = 10000;
517 *(u32 *)data = val;
518 return 0;
519}
520
521static int nr_iters_get(void *data, u64 *val)
522{
523 *val = *(u32 *)data;
524 return 0;
525}
526
527DEFINE_SIMPLE_ATTRIBUTE(iommu_debug_nr_iters_ops,
528 nr_iters_get, nr_iters_set, "%llu\n");
Mitchel Humpherys1c47bb52015-10-02 16:17:57 -0700529
Mitchel Humpherys020f90f2015-10-02 16:02:31 -0700530static void iommu_debug_device_profiling(struct seq_file *s, struct device *dev,
Mitchel Humpherysbc367fd2015-10-05 14:44:58 -0700531 enum iommu_attr attrs[],
532 void *attr_values[], int nattrs,
533 const unsigned long sizes[])
Mitchel Humpherys42296fb2015-06-23 16:29:16 -0700534{
Mitchel Humpherysbc367fd2015-10-05 14:44:58 -0700535 int i;
536 const unsigned long *sz;
Mitchel Humpherys42296fb2015-06-23 16:29:16 -0700537 struct iommu_domain *domain;
538 unsigned long iova = 0x10000;
539 phys_addr_t paddr = 0xa000;
540
541 domain = iommu_domain_alloc(&platform_bus_type);
542 if (!domain) {
543 seq_puts(s, "Couldn't allocate domain\n");
544 return;
545 }
546
Mitchel Humpherysbc367fd2015-10-05 14:44:58 -0700547 seq_puts(s, "Domain attributes: [ ");
548 for (i = 0; i < nattrs; ++i) {
549 /* not all attrs are ints, but this will get us by for now */
550 seq_printf(s, "%s=%d%s", iommu_debug_attr_to_string(attrs[i]),
551 *((int *)attr_values[i]),
552 i < nattrs ? " " : "");
Mitchel Humpherys679567c2015-08-28 10:51:24 -0700553 }
Mitchel Humpherysbc367fd2015-10-05 14:44:58 -0700554 seq_puts(s, "]\n");
555 for (i = 0; i < nattrs; ++i) {
556 if (iommu_domain_set_attr(domain, attrs[i], attr_values[i])) {
557 seq_printf(s, "Couldn't set %d to the value at %p\n",
558 attrs[i], attr_values[i]);
Mitchel Humpherys020f90f2015-10-02 16:02:31 -0700559 goto out_domain_free;
560 }
561 }
562
Mitchel Humpherys42296fb2015-06-23 16:29:16 -0700563 if (iommu_attach_device(domain, dev)) {
564 seq_puts(s,
565 "Couldn't attach new domain to device. Is it already attached?\n");
566 goto out_domain_free;
567 }
568
Patrick Dalye4e39862015-11-20 20:00:50 -0800569 seq_printf(s, "(average over %d iterations)\n", iters_per_op);
Patrick Daly3ca31e32015-11-20 20:33:04 -0800570 seq_printf(s, "%8s %19s %16s\n", "size", "iommu_map", "iommu_unmap");
Mitchel Humpherys42296fb2015-06-23 16:29:16 -0700571 for (sz = sizes; *sz; ++sz) {
572 unsigned long size = *sz;
573 size_t unmapped;
Patrick Daly3ca31e32015-11-20 20:33:04 -0800574 u64 map_elapsed_ns = 0, unmap_elapsed_ns = 0;
Mitchel Humpherys1c47bb52015-10-02 16:17:57 -0700575 u64 map_elapsed_us = 0, unmap_elapsed_us = 0;
Patrick Daly3ca31e32015-11-20 20:33:04 -0800576 u32 map_elapsed_rem = 0, unmap_elapsed_rem = 0;
Mitchel Humpherys42296fb2015-06-23 16:29:16 -0700577 struct timespec tbefore, tafter, diff;
Mitchel Humpherys1c47bb52015-10-02 16:17:57 -0700578 int i;
Mitchel Humpherys42296fb2015-06-23 16:29:16 -0700579
Patrick Dalye4e39862015-11-20 20:00:50 -0800580 for (i = 0; i < iters_per_op; ++i) {
Mitchel Humpherys1c47bb52015-10-02 16:17:57 -0700581 getnstimeofday(&tbefore);
582 if (iommu_map(domain, iova, paddr, size,
583 IOMMU_READ | IOMMU_WRITE)) {
584 seq_puts(s, "Failed to map\n");
585 continue;
586 }
587 getnstimeofday(&tafter);
588 diff = timespec_sub(tafter, tbefore);
Patrick Daly3ca31e32015-11-20 20:33:04 -0800589 map_elapsed_ns += timespec_to_ns(&diff);
Mitchel Humpherys42296fb2015-06-23 16:29:16 -0700590
Mitchel Humpherys1c47bb52015-10-02 16:17:57 -0700591 getnstimeofday(&tbefore);
592 unmapped = iommu_unmap(domain, iova, size);
593 if (unmapped != size) {
594 seq_printf(s,
595 "Only unmapped %zx instead of %zx\n",
596 unmapped, size);
597 continue;
598 }
599 getnstimeofday(&tafter);
600 diff = timespec_sub(tafter, tbefore);
Patrick Daly3ca31e32015-11-20 20:33:04 -0800601 unmap_elapsed_ns += timespec_to_ns(&diff);
Mitchel Humpherys42296fb2015-06-23 16:29:16 -0700602 }
Mitchel Humpherys1c47bb52015-10-02 16:17:57 -0700603
Patrick Daly3ca31e32015-11-20 20:33:04 -0800604 map_elapsed_ns /= iters_per_op;
605 unmap_elapsed_ns /= iters_per_op;
Mitchel Humpherys42296fb2015-06-23 16:29:16 -0700606
Patrick Daly3ca31e32015-11-20 20:33:04 -0800607 map_elapsed_us = div_u64_rem(map_elapsed_ns, 1000,
608 &map_elapsed_rem);
609 unmap_elapsed_us = div_u64_rem(unmap_elapsed_ns, 1000,
610 &unmap_elapsed_rem);
611
612 seq_printf(s, "%8s %12lld.%03d us %9lld.%03d us\n",
613 _size_to_string(size),
614 map_elapsed_us, map_elapsed_rem,
615 unmap_elapsed_us, unmap_elapsed_rem);
Mitchel Humpherys42296fb2015-06-23 16:29:16 -0700616 }
617
618 seq_putc(s, '\n');
Patrick Daly3ca31e32015-11-20 20:33:04 -0800619 seq_printf(s, "%8s %19s %16s\n", "size", "iommu_map_sg", "iommu_unmap");
Mitchel Humpherys42296fb2015-06-23 16:29:16 -0700620 for (sz = sizes; *sz; ++sz) {
621 unsigned long size = *sz;
622 size_t unmapped;
Patrick Daly3ca31e32015-11-20 20:33:04 -0800623 u64 map_elapsed_ns = 0, unmap_elapsed_ns = 0;
Mitchel Humpherys1c47bb52015-10-02 16:17:57 -0700624 u64 map_elapsed_us = 0, unmap_elapsed_us = 0;
Patrick Daly3ca31e32015-11-20 20:33:04 -0800625 u32 map_elapsed_rem = 0, unmap_elapsed_rem = 0;
Mitchel Humpherys42296fb2015-06-23 16:29:16 -0700626 struct timespec tbefore, tafter, diff;
627 struct sg_table table;
628 unsigned long chunk_size = SZ_4K;
Mitchel Humpherys1c47bb52015-10-02 16:17:57 -0700629 int i;
Mitchel Humpherys42296fb2015-06-23 16:29:16 -0700630
631 if (iommu_debug_build_phoney_sg_table(dev, &table, size,
632 chunk_size)) {
633 seq_puts(s,
634 "couldn't build phoney sg table! bailing...\n");
635 goto out_detach;
636 }
637
Patrick Dalye4e39862015-11-20 20:00:50 -0800638 for (i = 0; i < iters_per_op; ++i) {
Mitchel Humpherys1c47bb52015-10-02 16:17:57 -0700639 getnstimeofday(&tbefore);
640 if (iommu_map_sg(domain, iova, table.sgl, table.nents,
641 IOMMU_READ | IOMMU_WRITE) != size) {
642 seq_puts(s, "Failed to map_sg\n");
643 goto next;
644 }
645 getnstimeofday(&tafter);
646 diff = timespec_sub(tafter, tbefore);
Patrick Daly3ca31e32015-11-20 20:33:04 -0800647 map_elapsed_ns += timespec_to_ns(&diff);
Mitchel Humpherys42296fb2015-06-23 16:29:16 -0700648
Mitchel Humpherys1c47bb52015-10-02 16:17:57 -0700649 getnstimeofday(&tbefore);
650 unmapped = iommu_unmap(domain, iova, size);
651 if (unmapped != size) {
652 seq_printf(s,
653 "Only unmapped %zx instead of %zx\n",
654 unmapped, size);
655 goto next;
656 }
657 getnstimeofday(&tafter);
658 diff = timespec_sub(tafter, tbefore);
Patrick Daly3ca31e32015-11-20 20:33:04 -0800659 unmap_elapsed_ns += timespec_to_ns(&diff);
Mitchel Humpherys42296fb2015-06-23 16:29:16 -0700660 }
Mitchel Humpherys1c47bb52015-10-02 16:17:57 -0700661
Patrick Daly3ca31e32015-11-20 20:33:04 -0800662 map_elapsed_ns /= iters_per_op;
663 unmap_elapsed_ns /= iters_per_op;
Mitchel Humpherys42296fb2015-06-23 16:29:16 -0700664
Patrick Daly3ca31e32015-11-20 20:33:04 -0800665 map_elapsed_us = div_u64_rem(map_elapsed_ns, 1000,
666 &map_elapsed_rem);
667 unmap_elapsed_us = div_u64_rem(unmap_elapsed_ns, 1000,
668 &unmap_elapsed_rem);
669
670 seq_printf(s, "%8s %12lld.%03d us %9lld.%03d us\n",
671 _size_to_string(size),
672 map_elapsed_us, map_elapsed_rem,
673 unmap_elapsed_us, unmap_elapsed_rem);
Mitchel Humpherys42296fb2015-06-23 16:29:16 -0700674
675next:
676 iommu_debug_destroy_phoney_sg_table(dev, &table, chunk_size);
677 }
678
679out_detach:
680 iommu_detach_device(domain, dev);
681out_domain_free:
682 iommu_domain_free(domain);
683}
684
Mitchel Humpherys7cc56e42015-07-06 14:58:23 -0700685static int iommu_debug_profiling_show(struct seq_file *s, void *ignored)
Mitchel Humpherys42296fb2015-06-23 16:29:16 -0700686{
687 struct iommu_debug_device *ddev = s->private;
Mitchel Humpherysbc367fd2015-10-05 14:44:58 -0700688 const unsigned long sizes[] = { SZ_4K, SZ_64K, SZ_2M, SZ_1M * 12,
689 SZ_1M * 20, 0 };
690 enum iommu_attr attrs[] = {
691 DOMAIN_ATTR_ATOMIC,
692 };
693 int htw_disable = 1, atomic = 1;
694 void *attr_values[] = { &htw_disable, &atomic };
Mitchel Humpherys42296fb2015-06-23 16:29:16 -0700695
Mitchel Humpherysbc367fd2015-10-05 14:44:58 -0700696 iommu_debug_device_profiling(s, ddev->dev, attrs, attr_values,
697 ARRAY_SIZE(attrs), sizes);
Mitchel Humpherys42296fb2015-06-23 16:29:16 -0700698
699 return 0;
700}
701
Mitchel Humpherys7cc56e42015-07-06 14:58:23 -0700702static int iommu_debug_profiling_open(struct inode *inode, struct file *file)
Mitchel Humpherys42296fb2015-06-23 16:29:16 -0700703{
Mitchel Humpherys7cc56e42015-07-06 14:58:23 -0700704 return single_open(file, iommu_debug_profiling_show, inode->i_private);
Mitchel Humpherys42296fb2015-06-23 16:29:16 -0700705}
706
Mitchel Humpherys7cc56e42015-07-06 14:58:23 -0700707static const struct file_operations iommu_debug_profiling_fops = {
708 .open = iommu_debug_profiling_open,
Mitchel Humpherys42296fb2015-06-23 16:29:16 -0700709 .read = seq_read,
710 .llseek = seq_lseek,
711 .release = single_release,
712};
713
Mitchel Humpherys020f90f2015-10-02 16:02:31 -0700714static int iommu_debug_secure_profiling_show(struct seq_file *s, void *ignored)
715{
716 struct iommu_debug_device *ddev = s->private;
Mitchel Humpherysbc367fd2015-10-05 14:44:58 -0700717 const unsigned long sizes[] = { SZ_4K, SZ_64K, SZ_2M, SZ_1M * 12,
718 SZ_1M * 20, 0 };
Mitchel Humpherys020f90f2015-10-02 16:02:31 -0700719
Mitchel Humpherysbc367fd2015-10-05 14:44:58 -0700720 enum iommu_attr attrs[] = {
721 DOMAIN_ATTR_ATOMIC,
722 DOMAIN_ATTR_SECURE_VMID,
723 };
724 int one = 1, secure_vmid = VMID_CP_PIXEL;
725 void *attr_values[] = { &one, &secure_vmid };
726
727 iommu_debug_device_profiling(s, ddev->dev, attrs, attr_values,
728 ARRAY_SIZE(attrs), sizes);
Mitchel Humpherys020f90f2015-10-02 16:02:31 -0700729
730 return 0;
731}
732
733static int iommu_debug_secure_profiling_open(struct inode *inode,
734 struct file *file)
735{
736 return single_open(file, iommu_debug_secure_profiling_show,
737 inode->i_private);
738}
739
740static const struct file_operations iommu_debug_secure_profiling_fops = {
741 .open = iommu_debug_secure_profiling_open,
742 .read = seq_read,
743 .llseek = seq_lseek,
744 .release = single_release,
745};
746
Mitchel Humpherysbc367fd2015-10-05 14:44:58 -0700747static int iommu_debug_profiling_fast_show(struct seq_file *s, void *ignored)
748{
749 struct iommu_debug_device *ddev = s->private;
750 size_t sizes[] = {SZ_4K, SZ_8K, SZ_16K, SZ_64K, 0};
751 enum iommu_attr attrs[] = {
752 DOMAIN_ATTR_FAST,
753 DOMAIN_ATTR_ATOMIC,
754 };
755 int one = 1;
756 void *attr_values[] = { &one, &one };
757
758 iommu_debug_device_profiling(s, ddev->dev, attrs, attr_values,
759 ARRAY_SIZE(attrs), sizes);
760
761 return 0;
762}
763
764static int iommu_debug_profiling_fast_open(struct inode *inode,
765 struct file *file)
766{
767 return single_open(file, iommu_debug_profiling_fast_show,
768 inode->i_private);
769}
770
771static const struct file_operations iommu_debug_profiling_fast_fops = {
772 .open = iommu_debug_profiling_fast_open,
773 .read = seq_read,
774 .llseek = seq_lseek,
775 .release = single_release,
776};
777
Mitchel Humpherysbe3060c2015-10-08 15:08:01 -0700778static int iommu_debug_profiling_fast_dma_api_show(struct seq_file *s,
779 void *ignored)
780{
781 int i, experiment;
782 struct iommu_debug_device *ddev = s->private;
783 struct device *dev = ddev->dev;
784 u64 map_elapsed_ns[10], unmap_elapsed_ns[10];
785 struct dma_iommu_mapping *mapping;
786 dma_addr_t dma_addr;
787 void *virt;
788 int fast = 1;
789 const char * const extra_labels[] = {
790 "not coherent",
791 "coherent",
792 };
793 unsigned long extra_attrs[] = {
794 0,
795 DMA_ATTR_SKIP_CPU_SYNC,
796 };
797
798 virt = kmalloc(1518, GFP_KERNEL);
799 if (!virt)
800 goto out;
801
802 mapping = arm_iommu_create_mapping(&platform_bus_type, 0, SZ_1G * 4ULL);
803 if (!mapping) {
804 seq_puts(s, "fast_smmu_create_mapping failed\n");
805 goto out_kfree;
806 }
807
808 if (iommu_domain_set_attr(mapping->domain, DOMAIN_ATTR_FAST, &fast)) {
809 seq_puts(s, "iommu_domain_set_attr failed\n");
810 goto out_release_mapping;
811 }
812
813 if (arm_iommu_attach_device(dev, mapping)) {
814 seq_puts(s, "fast_smmu_attach_device failed\n");
815 goto out_release_mapping;
816 }
817
818 if (iommu_enable_config_clocks(mapping->domain)) {
819 seq_puts(s, "Couldn't enable clocks\n");
820 goto out_detach;
821 }
822 for (experiment = 0; experiment < 2; ++experiment) {
823 u64 map_avg = 0, unmap_avg = 0;
824
825 for (i = 0; i < 10; ++i) {
826 struct timespec tbefore, tafter, diff;
827 u64 ns;
828
829 getnstimeofday(&tbefore);
830 dma_addr = dma_map_single_attrs(
831 dev, virt, SZ_4K, DMA_TO_DEVICE,
832 extra_attrs[experiment]);
833 getnstimeofday(&tafter);
834 diff = timespec_sub(tafter, tbefore);
835 ns = timespec_to_ns(&diff);
836 if (dma_mapping_error(dev, dma_addr)) {
837 seq_puts(s, "dma_map_single failed\n");
838 goto out_disable_config_clocks;
839 }
840 map_elapsed_ns[i] = ns;
841
842 getnstimeofday(&tbefore);
843 dma_unmap_single_attrs(
844 dev, dma_addr, SZ_4K, DMA_TO_DEVICE,
845 extra_attrs[experiment]);
846 getnstimeofday(&tafter);
847 diff = timespec_sub(tafter, tbefore);
848 ns = timespec_to_ns(&diff);
849 unmap_elapsed_ns[i] = ns;
850 }
851
852 seq_printf(s, "%13s %24s (ns): [", extra_labels[experiment],
853 "dma_map_single_attrs");
854 for (i = 0; i < 10; ++i) {
855 map_avg += map_elapsed_ns[i];
856 seq_printf(s, "%5llu%s", map_elapsed_ns[i],
857 i < 9 ? ", " : "");
858 }
859 map_avg /= 10;
860 seq_printf(s, "] (avg: %llu)\n", map_avg);
861
862 seq_printf(s, "%13s %24s (ns): [", extra_labels[experiment],
863 "dma_unmap_single_attrs");
864 for (i = 0; i < 10; ++i) {
865 unmap_avg += unmap_elapsed_ns[i];
866 seq_printf(s, "%5llu%s", unmap_elapsed_ns[i],
867 i < 9 ? ", " : "");
868 }
869 unmap_avg /= 10;
870 seq_printf(s, "] (avg: %llu)\n", unmap_avg);
871 }
872
873out_disable_config_clocks:
874 iommu_disable_config_clocks(mapping->domain);
875out_detach:
876 arm_iommu_detach_device(dev);
877out_release_mapping:
878 arm_iommu_release_mapping(mapping);
879out_kfree:
880 kfree(virt);
881out:
882 return 0;
883}
884
885static int iommu_debug_profiling_fast_dma_api_open(struct inode *inode,
886 struct file *file)
887{
888 return single_open(file, iommu_debug_profiling_fast_dma_api_show,
889 inode->i_private);
890}
891
892static const struct file_operations iommu_debug_profiling_fast_dma_api_fops = {
893 .open = iommu_debug_profiling_fast_dma_api_open,
894 .read = seq_read,
895 .llseek = seq_lseek,
896 .release = single_release,
897};
898
Mitchel Humpherysac4c38b2015-07-30 19:40:21 -0700899static int iommu_debug_attach_do_attach(struct iommu_debug_device *ddev,
900 int val, bool is_secure)
Mitchel Humpherys0fe337d2015-07-06 15:21:24 -0700901{
902 ddev->domain = iommu_domain_alloc(&platform_bus_type);
903 if (!ddev->domain) {
904 pr_err("Couldn't allocate domain\n");
905 return -ENOMEM;
906 }
907
Mitchel Humpherysac4c38b2015-07-30 19:40:21 -0700908 if (is_secure && iommu_domain_set_attr(ddev->domain,
909 DOMAIN_ATTR_SECURE_VMID,
910 &val)) {
911 pr_err("Couldn't set secure vmid to %d\n", val);
912 goto out_domain_free;
913 }
914
Mitchel Humpherys0fe337d2015-07-06 15:21:24 -0700915 if (iommu_attach_device(ddev->domain, ddev->dev)) {
916 pr_err("Couldn't attach new domain to device. Is it already attached?\n");
917 goto out_domain_free;
918 }
919
920 return 0;
921
922out_domain_free:
923 iommu_domain_free(ddev->domain);
924 ddev->domain = NULL;
925 return -EIO;
926}
927
Mitchel Humpherysac4c38b2015-07-30 19:40:21 -0700928static ssize_t __iommu_debug_attach_write(struct file *file,
929 const char __user *ubuf,
930 size_t count, loff_t *offset,
931 bool is_secure)
Mitchel Humpherys0fe337d2015-07-06 15:21:24 -0700932{
933 struct iommu_debug_device *ddev = file->private_data;
934 ssize_t retval;
Mitchel Humpherysac4c38b2015-07-30 19:40:21 -0700935 int val;
Mitchel Humpherys0fe337d2015-07-06 15:21:24 -0700936
Mitchel Humpherysac4c38b2015-07-30 19:40:21 -0700937 if (kstrtoint_from_user(ubuf, count, 0, &val)) {
938 pr_err("Invalid format. Expected a hex or decimal integer");
Mitchel Humpherys0fe337d2015-07-06 15:21:24 -0700939 retval = -EFAULT;
940 goto out;
941 }
942
Mitchel Humpherysac4c38b2015-07-30 19:40:21 -0700943 if (val) {
Mitchel Humpherys0fe337d2015-07-06 15:21:24 -0700944 if (ddev->domain) {
945 pr_err("Already attached.\n");
946 retval = -EINVAL;
947 goto out;
948 }
949 if (WARN(ddev->dev->archdata.iommu,
950 "Attachment tracking out of sync with device\n")) {
951 retval = -EINVAL;
952 goto out;
953 }
Mitchel Humpherysac4c38b2015-07-30 19:40:21 -0700954 if (iommu_debug_attach_do_attach(ddev, val, is_secure)) {
Mitchel Humpherys0fe337d2015-07-06 15:21:24 -0700955 retval = -EIO;
956 goto out;
957 }
958 pr_err("Attached\n");
Mitchel Humpherysac4c38b2015-07-30 19:40:21 -0700959 } else {
Mitchel Humpherys0fe337d2015-07-06 15:21:24 -0700960 if (!ddev->domain) {
961 pr_err("No domain. Did you already attach?\n");
962 retval = -EINVAL;
963 goto out;
964 }
965 iommu_detach_device(ddev->domain, ddev->dev);
966 iommu_domain_free(ddev->domain);
967 ddev->domain = NULL;
968 pr_err("Detached\n");
Mitchel Humpherys0fe337d2015-07-06 15:21:24 -0700969 }
970
971 retval = count;
972out:
973 return retval;
974}
975
Mitchel Humpherysac4c38b2015-07-30 19:40:21 -0700976static ssize_t iommu_debug_attach_write(struct file *file,
977 const char __user *ubuf,
978 size_t count, loff_t *offset)
979{
980 return __iommu_debug_attach_write(file, ubuf, count, offset,
981 false);
982
983}
984
Mitchel Humpherys0fe337d2015-07-06 15:21:24 -0700985static ssize_t iommu_debug_attach_read(struct file *file, char __user *ubuf,
986 size_t count, loff_t *offset)
987{
988 struct iommu_debug_device *ddev = file->private_data;
989 char c[2];
990
991 if (*offset)
992 return 0;
993
994 c[0] = ddev->domain ? '1' : '0';
995 c[1] = '\n';
996 if (copy_to_user(ubuf, &c, 2)) {
997 pr_err("copy_to_user failed\n");
998 return -EFAULT;
999 }
1000 *offset = 1; /* non-zero means we're done */
1001
1002 return 2;
1003}
1004
1005static const struct file_operations iommu_debug_attach_fops = {
1006 .open = simple_open,
1007 .write = iommu_debug_attach_write,
1008 .read = iommu_debug_attach_read,
1009};
1010
Mitchel Humpherysac4c38b2015-07-30 19:40:21 -07001011static ssize_t iommu_debug_attach_write_secure(struct file *file,
1012 const char __user *ubuf,
1013 size_t count, loff_t *offset)
1014{
1015 return __iommu_debug_attach_write(file, ubuf, count, offset,
1016 true);
1017
1018}
1019
1020static const struct file_operations iommu_debug_secure_attach_fops = {
1021 .open = simple_open,
1022 .write = iommu_debug_attach_write_secure,
1023 .read = iommu_debug_attach_read,
1024};
1025
Mitchel Humpherys0fe337d2015-07-06 15:21:24 -07001026static ssize_t iommu_debug_atos_write(struct file *file,
1027 const char __user *ubuf,
1028 size_t count, loff_t *offset)
1029{
1030 struct iommu_debug_device *ddev = file->private_data;
1031 dma_addr_t iova;
1032
1033 if (kstrtoll_from_user(ubuf, count, 0, &iova)) {
1034 pr_err("Invalid format for iova\n");
1035 ddev->iova = 0;
1036 return -EINVAL;
1037 }
1038
1039 ddev->iova = iova;
1040 pr_err("Saved iova=%pa for future ATOS commands\n", &iova);
1041 return count;
1042}
1043
1044static ssize_t iommu_debug_atos_read(struct file *file, char __user *ubuf,
1045 size_t count, loff_t *offset)
1046{
1047 struct iommu_debug_device *ddev = file->private_data;
1048 phys_addr_t phys;
1049 char buf[100];
1050 ssize_t retval;
1051 size_t buflen;
1052
1053 if (!ddev->domain) {
1054 pr_err("No domain. Did you already attach?\n");
1055 return -EINVAL;
1056 }
1057
1058 if (*offset)
1059 return 0;
1060
1061 memset(buf, 0, 100);
1062
1063 phys = iommu_iova_to_phys_hard(ddev->domain, ddev->iova);
1064 if (!phys)
1065 strlcpy(buf, "FAIL\n", 100);
1066 else
1067 snprintf(buf, 100, "%pa\n", &phys);
1068
1069 buflen = strlen(buf);
1070 if (copy_to_user(ubuf, buf, buflen)) {
1071 pr_err("Couldn't copy_to_user\n");
1072 retval = -EFAULT;
1073 } else {
1074 *offset = 1; /* non-zero means we're done */
1075 retval = buflen;
1076 }
1077
1078 return retval;
1079}
1080
1081static const struct file_operations iommu_debug_atos_fops = {
1082 .open = simple_open,
1083 .write = iommu_debug_atos_write,
1084 .read = iommu_debug_atos_read,
1085};
1086
1087static ssize_t iommu_debug_map_write(struct file *file, const char __user *ubuf,
1088 size_t count, loff_t *offset)
1089{
1090 ssize_t retval;
1091 int ret;
1092 char *comma1, *comma2, *comma3;
1093 char buf[100];
1094 dma_addr_t iova;
1095 phys_addr_t phys;
1096 size_t size;
1097 int prot;
1098 struct iommu_debug_device *ddev = file->private_data;
1099
1100 if (count >= 100) {
1101 pr_err("Value too large\n");
1102 return -EINVAL;
1103 }
1104
1105 if (!ddev->domain) {
1106 pr_err("No domain. Did you already attach?\n");
1107 return -EINVAL;
1108 }
1109
1110 memset(buf, 0, 100);
1111
1112 if (copy_from_user(buf, ubuf, count)) {
1113 pr_err("Couldn't copy from user\n");
1114 retval = -EFAULT;
1115 }
1116
1117 comma1 = strnchr(buf, count, ',');
1118 if (!comma1)
1119 goto invalid_format;
1120
1121 comma2 = strnchr(comma1 + 1, count, ',');
1122 if (!comma2)
1123 goto invalid_format;
1124
1125 comma3 = strnchr(comma2 + 1, count, ',');
1126 if (!comma3)
1127 goto invalid_format;
1128
1129 /* split up the words */
1130 *comma1 = *comma2 = *comma3 = '\0';
1131
1132 if (kstrtou64(buf, 0, &iova))
1133 goto invalid_format;
1134
1135 if (kstrtou64(comma1 + 1, 0, &phys))
1136 goto invalid_format;
1137
1138 if (kstrtoul(comma2 + 1, 0, &size))
1139 goto invalid_format;
1140
1141 if (kstrtoint(comma3 + 1, 0, &prot))
1142 goto invalid_format;
1143
1144 ret = iommu_map(ddev->domain, iova, phys, size, prot);
1145 if (ret) {
1146 pr_err("iommu_map failed with %d\n", ret);
1147 retval = -EIO;
1148 goto out;
1149 }
1150
1151 retval = count;
1152 pr_err("Mapped %pa to %pa (len=0x%zx, prot=0x%x)\n",
1153 &iova, &phys, size, prot);
1154out:
1155 return retval;
1156
1157invalid_format:
1158 pr_err("Invalid format. Expected: iova,phys,len,prot where `prot' is the bitwise OR of IOMMU_READ, IOMMU_WRITE, etc.\n");
1159 return -EINVAL;
1160}
1161
1162static const struct file_operations iommu_debug_map_fops = {
1163 .open = simple_open,
1164 .write = iommu_debug_map_write,
1165};
1166
1167static ssize_t iommu_debug_unmap_write(struct file *file,
1168 const char __user *ubuf,
1169 size_t count, loff_t *offset)
1170{
1171 ssize_t retval = 0;
1172 char *comma1;
1173 char buf[100];
1174 dma_addr_t iova;
1175 size_t size;
1176 size_t unmapped;
1177 struct iommu_debug_device *ddev = file->private_data;
1178
1179 if (count >= 100) {
1180 pr_err("Value too large\n");
1181 return -EINVAL;
1182 }
1183
1184 if (!ddev->domain) {
1185 pr_err("No domain. Did you already attach?\n");
1186 return -EINVAL;
1187 }
1188
1189 memset(buf, 0, 100);
1190
1191 if (copy_from_user(buf, ubuf, count)) {
1192 pr_err("Couldn't copy from user\n");
1193 retval = -EFAULT;
1194 goto out;
1195 }
1196
1197 comma1 = strnchr(buf, count, ',');
1198 if (!comma1)
1199 goto invalid_format;
1200
1201 /* split up the words */
1202 *comma1 = '\0';
1203
1204 if (kstrtou64(buf, 0, &iova))
1205 goto invalid_format;
1206
Mitchel Humpherys70b75112015-07-29 12:45:29 -07001207 if (kstrtoul(comma1 + 1, 0, &size))
Mitchel Humpherys0fe337d2015-07-06 15:21:24 -07001208 goto invalid_format;
1209
1210 unmapped = iommu_unmap(ddev->domain, iova, size);
1211 if (unmapped != size) {
1212 pr_err("iommu_unmap failed. Expected to unmap: 0x%zx, unmapped: 0x%zx",
1213 size, unmapped);
1214 return -EIO;
1215 }
1216
1217 retval = count;
1218 pr_err("Unmapped %pa (len=0x%zx)\n", &iova, size);
1219out:
1220 return retval;
1221
1222invalid_format:
1223 pr_err("Invalid format. Expected: iova,len\n");
1224 return retval;
1225}
1226
1227static const struct file_operations iommu_debug_unmap_fops = {
1228 .open = simple_open,
1229 .write = iommu_debug_unmap_write,
1230};
1231
Mitchel Humpherys42296fb2015-06-23 16:29:16 -07001232/*
1233 * The following will only work for drivers that implement the generic
1234 * device tree bindings described in
1235 * Documentation/devicetree/bindings/iommu/iommu.txt
1236 */
1237static int snarf_iommu_devices(struct device *dev, void *ignored)
1238{
1239 struct iommu_debug_device *ddev;
Mitchel Humpherys0fe337d2015-07-06 15:21:24 -07001240 struct dentry *dir;
Mitchel Humpherys42296fb2015-06-23 16:29:16 -07001241
1242 if (!of_find_property(dev->of_node, "iommus", NULL))
1243 return 0;
1244
Mitchel Humpherys89924fd2015-07-09 14:50:22 -07001245 ddev = kzalloc(sizeof(*ddev), GFP_KERNEL);
Mitchel Humpherys42296fb2015-06-23 16:29:16 -07001246 if (!ddev)
1247 return -ENODEV;
1248 ddev->dev = dev;
1249 dir = debugfs_create_dir(dev_name(dev), debugfs_tests_dir);
1250 if (!dir) {
1251 pr_err("Couldn't create iommu/devices/%s debugfs dir\n",
1252 dev_name(dev));
1253 goto err;
1254 }
Mitchel Humpherys0fe337d2015-07-06 15:21:24 -07001255
Patrick Dalye4e39862015-11-20 20:00:50 -08001256 if (!debugfs_create_file("nr_iters", S_IRUSR, dir, &iters_per_op,
1257 &iommu_debug_nr_iters_ops)) {
1258 pr_err("Couldn't create iommu/devices/%s/nr_iters debugfs file\n",
1259 dev_name(dev));
1260 goto err_rmdir;
1261 }
1262
Mitchel Humpherys0fe337d2015-07-06 15:21:24 -07001263 if (!debugfs_create_file("profiling", S_IRUSR, dir, ddev,
1264 &iommu_debug_profiling_fops)) {
Mitchel Humpherys42296fb2015-06-23 16:29:16 -07001265 pr_err("Couldn't create iommu/devices/%s/profiling debugfs file\n",
1266 dev_name(dev));
1267 goto err_rmdir;
1268 }
1269
Mitchel Humpherys020f90f2015-10-02 16:02:31 -07001270 if (!debugfs_create_file("secure_profiling", S_IRUSR, dir, ddev,
1271 &iommu_debug_secure_profiling_fops)) {
1272 pr_err("Couldn't create iommu/devices/%s/secure_profiling debugfs file\n",
1273 dev_name(dev));
1274 goto err_rmdir;
1275 }
1276
Mitchel Humpherysbc367fd2015-10-05 14:44:58 -07001277 if (!debugfs_create_file("profiling_fast", S_IRUSR, dir, ddev,
1278 &iommu_debug_profiling_fast_fops)) {
1279 pr_err("Couldn't create iommu/devices/%s/profiling_fast debugfs file\n",
1280 dev_name(dev));
1281 goto err_rmdir;
1282 }
1283
Mitchel Humpherysbe3060c2015-10-08 15:08:01 -07001284 if (!debugfs_create_file("profiling_fast_dma_api", S_IRUSR, dir, ddev,
1285 &iommu_debug_profiling_fast_dma_api_fops)) {
1286 pr_err("Couldn't create iommu/devices/%s/profiling_fast_dma_api debugfs file\n",
1287 dev_name(dev));
1288 goto err_rmdir;
1289 }
1290
Mitchel Humpherys0fe337d2015-07-06 15:21:24 -07001291 if (!debugfs_create_file("attach", S_IRUSR, dir, ddev,
1292 &iommu_debug_attach_fops)) {
1293 pr_err("Couldn't create iommu/devices/%s/attach debugfs file\n",
1294 dev_name(dev));
1295 goto err_rmdir;
1296 }
1297
Mitchel Humpherysac4c38b2015-07-30 19:40:21 -07001298 if (!debugfs_create_file("secure_attach", S_IRUSR, dir, ddev,
1299 &iommu_debug_secure_attach_fops)) {
1300 pr_err("Couldn't create iommu/devices/%s/secure_attach debugfs file\n",
1301 dev_name(dev));
1302 goto err_rmdir;
1303 }
1304
Mitchel Humpherys0fe337d2015-07-06 15:21:24 -07001305 if (!debugfs_create_file("atos", S_IWUSR, dir, ddev,
1306 &iommu_debug_atos_fops)) {
1307 pr_err("Couldn't create iommu/devices/%s/atos debugfs file\n",
1308 dev_name(dev));
1309 goto err_rmdir;
1310 }
1311
1312 if (!debugfs_create_file("map", S_IWUSR, dir, ddev,
1313 &iommu_debug_map_fops)) {
1314 pr_err("Couldn't create iommu/devices/%s/map debugfs file\n",
1315 dev_name(dev));
1316 goto err_rmdir;
1317 }
1318
1319 if (!debugfs_create_file("unmap", S_IWUSR, dir, ddev,
1320 &iommu_debug_unmap_fops)) {
1321 pr_err("Couldn't create iommu/devices/%s/unmap debugfs file\n",
1322 dev_name(dev));
1323 goto err_rmdir;
1324 }
1325
Mitchel Humpherys42296fb2015-06-23 16:29:16 -07001326 list_add(&ddev->list, &iommu_debug_devices);
1327 return 0;
1328
1329err_rmdir:
1330 debugfs_remove_recursive(dir);
1331err:
1332 kfree(ddev);
1333 return 0;
1334}
1335
1336static int iommu_debug_init_tests(void)
1337{
1338 debugfs_tests_dir = debugfs_create_dir("tests",
Mitchel Humpherysc75ae492015-07-15 18:27:36 -07001339 iommu_debugfs_top);
Mitchel Humpherys42296fb2015-06-23 16:29:16 -07001340 if (!debugfs_tests_dir) {
1341 pr_err("Couldn't create iommu/tests debugfs directory\n");
1342 return -ENODEV;
1343 }
1344
1345 return bus_for_each_dev(&platform_bus_type, NULL, NULL,
1346 snarf_iommu_devices);
1347}
Mitchel Humpherysc75ae492015-07-15 18:27:36 -07001348
1349static void iommu_debug_destroy_tests(void)
1350{
1351 debugfs_remove_recursive(debugfs_tests_dir);
1352}
Mitchel Humpherys42296fb2015-06-23 16:29:16 -07001353#else
1354static inline int iommu_debug_init_tests(void) { return 0; }
Mitchel Humpherysc75ae492015-07-15 18:27:36 -07001355static inline void iommu_debug_destroy_tests(void) { }
Mitchel Humpherys42296fb2015-06-23 16:29:16 -07001356#endif
1357
Mitchel Humpherys93f7eef2016-04-13 17:08:49 -07001358/*
1359 * This isn't really a "driver", we just need something in the device tree
1360 * so that our tests can run without any client drivers, and our tests rely
1361 * on parsing the device tree for nodes with the `iommus' property.
1362 */
1363static int iommu_debug_pass(struct platform_device *pdev)
1364{
1365 return 0;
1366}
1367
1368static const struct of_device_id iommu_debug_of_match[] = {
1369 { .compatible = "iommu-debug-test" },
1370 { },
1371};
1372
1373static struct platform_driver iommu_debug_driver = {
1374 .probe = iommu_debug_pass,
1375 .remove = iommu_debug_pass,
1376 .driver = {
1377 .name = "iommu-debug",
1378 .of_match_table = iommu_debug_of_match,
1379 },
1380};
1381
Mitchel Humpherys42296fb2015-06-23 16:29:16 -07001382static int iommu_debug_init(void)
1383{
Mitchel Humpherys42296fb2015-06-23 16:29:16 -07001384 if (iommu_debug_init_tracking())
Mitchel Humpherysc75ae492015-07-15 18:27:36 -07001385 return -ENODEV;
Mitchel Humpherys42296fb2015-06-23 16:29:16 -07001386
1387 if (iommu_debug_init_tests())
Mitchel Humpherysc75ae492015-07-15 18:27:36 -07001388 return -ENODEV;
Mitchel Humpherys42296fb2015-06-23 16:29:16 -07001389
Mitchel Humpherys93f7eef2016-04-13 17:08:49 -07001390 return platform_driver_register(&iommu_debug_driver);
Mitchel Humpherys42296fb2015-06-23 16:29:16 -07001391}
1392
1393static void iommu_debug_exit(void)
1394{
Mitchel Humpherys93f7eef2016-04-13 17:08:49 -07001395 platform_driver_unregister(&iommu_debug_driver);
Mitchel Humpherysc75ae492015-07-15 18:27:36 -07001396 iommu_debug_destroy_tracking();
1397 iommu_debug_destroy_tests();
Mitchel Humpherys42296fb2015-06-23 16:29:16 -07001398}
1399
1400module_init(iommu_debug_init);
1401module_exit(iommu_debug_exit);