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