]> git.proxmox.com Git - mirror_ubuntu-artful-kernel.git/blame - drivers/iommu/omap-iommu-debug.c
iommu/omap: Fix the permissions on nr_tlb_entries
[mirror_ubuntu-artful-kernel.git] / drivers / iommu / omap-iommu-debug.c
CommitLineData
14e0e679
HD
1/*
2 * omap iommu: debugfs interface
3 *
4 * Copyright (C) 2008-2009 Nokia Corporation
5 *
6 * Written by Hiroshi DOYU <Hiroshi.DOYU@nokia.com>
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License version 2 as
10 * published by the Free Software Foundation.
11 */
12
08f2e631 13#include <linux/module.h>
14e0e679
HD
14#include <linux/err.h>
15#include <linux/clk.h>
16#include <linux/io.h>
5a0e3ad6 17#include <linux/slab.h>
14e0e679
HD
18#include <linux/uaccess.h>
19#include <linux/platform_device.h>
20#include <linux/debugfs.h>
c8d35c84 21#include <linux/omap-iommu.h>
2ab7c848 22#include <linux/platform_data/iommu-omap.h>
14e0e679 23
2f7702af 24#include "omap-iopgtable.h"
ed1c7de2 25#include "omap-iommu.h"
14e0e679
HD
26
27#define MAXCOLUMN 100 /* for short messages */
28
29static DEFINE_MUTEX(iommu_debug_lock);
30
31static struct dentry *iommu_debug_root;
32
14e0e679
HD
33static ssize_t debug_read_regs(struct file *file, char __user *userbuf,
34 size_t count, loff_t *ppos)
35{
46451d62
OBC
36 struct device *dev = file->private_data;
37 struct omap_iommu *obj = dev_to_omap_iommu(dev);
14e0e679
HD
38 char *p, *buf;
39 ssize_t bytes;
40
41 buf = kmalloc(count, GFP_KERNEL);
42 if (!buf)
43 return -ENOMEM;
44 p = buf;
45
46 mutex_lock(&iommu_debug_lock);
47
6c32df43 48 bytes = omap_iommu_dump_ctx(obj, p, count);
14e0e679
HD
49 bytes = simple_read_from_buffer(userbuf, count, ppos, buf, bytes);
50
51 mutex_unlock(&iommu_debug_lock);
52 kfree(buf);
53
54 return bytes;
55}
56
57static ssize_t debug_read_tlb(struct file *file, char __user *userbuf,
58 size_t count, loff_t *ppos)
59{
46451d62
OBC
60 struct device *dev = file->private_data;
61 struct omap_iommu *obj = dev_to_omap_iommu(dev);
14e0e679
HD
62 char *p, *buf;
63 ssize_t bytes, rest;
64
65 buf = kmalloc(count, GFP_KERNEL);
66 if (!buf)
67 return -ENOMEM;
68 p = buf;
69
70 mutex_lock(&iommu_debug_lock);
71
72 p += sprintf(p, "%8s %8s\n", "cam:", "ram:");
73 p += sprintf(p, "-----------------------------------------\n");
74 rest = count - (p - buf);
6c32df43 75 p += omap_dump_tlb_entries(obj, p, rest);
14e0e679
HD
76
77 bytes = simple_read_from_buffer(userbuf, count, ppos, buf, p - buf);
78
79 mutex_unlock(&iommu_debug_lock);
80 kfree(buf);
81
82 return bytes;
83}
84
85static ssize_t debug_write_pagetable(struct file *file,
86 const char __user *userbuf, size_t count, loff_t *ppos)
87{
88 struct iotlb_entry e;
89 struct cr_regs cr;
90 int err;
46451d62
OBC
91 struct device *dev = file->private_data;
92 struct omap_iommu *obj = dev_to_omap_iommu(dev);
14e0e679
HD
93 char buf[MAXCOLUMN], *p = buf;
94
95 count = min(count, sizeof(buf));
96
97 mutex_lock(&iommu_debug_lock);
98 if (copy_from_user(p, userbuf, count)) {
99 mutex_unlock(&iommu_debug_lock);
100 return -EFAULT;
101 }
102
103 sscanf(p, "%x %x", &cr.cam, &cr.ram);
104 if (!cr.cam || !cr.ram) {
105 mutex_unlock(&iommu_debug_lock);
106 return -EINVAL;
107 }
108
6c32df43
OBC
109 omap_iotlb_cr_to_e(&cr, &e);
110 err = omap_iopgtable_store_entry(obj, &e);
14e0e679
HD
111 if (err)
112 dev_err(obj->dev, "%s: fail to store cr\n", __func__);
113
114 mutex_unlock(&iommu_debug_lock);
115 return count;
116}
117
118#define dump_ioptable_entry_one(lv, da, val) \
119 ({ \
120 int __err = 0; \
121 ssize_t bytes; \
122 const int maxcol = 22; \
123 const char *str = "%d: %08x %08x\n"; \
124 bytes = snprintf(p, maxcol, str, lv, da, val); \
125 p += bytes; \
126 len -= bytes; \
127 if (len < maxcol) \
128 __err = -ENOMEM; \
129 __err; \
130 })
131
6c32df43 132static ssize_t dump_ioptable(struct omap_iommu *obj, char *buf, ssize_t len)
14e0e679
HD
133{
134 int i;
135 u32 *iopgd;
136 char *p = buf;
137
138 spin_lock(&obj->page_table_lock);
139
140 iopgd = iopgd_offset(obj, 0);
141 for (i = 0; i < PTRS_PER_IOPGD; i++, iopgd++) {
142 int j, err;
143 u32 *iopte;
144 u32 da;
145
146 if (!*iopgd)
147 continue;
148
149 if (!(*iopgd & IOPGD_TABLE)) {
150 da = i << IOPGD_SHIFT;
151
152 err = dump_ioptable_entry_one(1, da, *iopgd);
153 if (err)
154 goto out;
155 continue;
156 }
157
158 iopte = iopte_offset(iopgd, 0);
159
160 for (j = 0; j < PTRS_PER_IOPTE; j++, iopte++) {
161 if (!*iopte)
162 continue;
163
164 da = (i << IOPGD_SHIFT) + (j << IOPTE_SHIFT);
165 err = dump_ioptable_entry_one(2, da, *iopgd);
166 if (err)
167 goto out;
168 }
169 }
170out:
171 spin_unlock(&obj->page_table_lock);
172
173 return p - buf;
174}
175
176static ssize_t debug_read_pagetable(struct file *file, char __user *userbuf,
177 size_t count, loff_t *ppos)
178{
46451d62
OBC
179 struct device *dev = file->private_data;
180 struct omap_iommu *obj = dev_to_omap_iommu(dev);
14e0e679
HD
181 char *p, *buf;
182 size_t bytes;
183
184 buf = (char *)__get_free_page(GFP_KERNEL);
185 if (!buf)
186 return -ENOMEM;
187 p = buf;
188
189 p += sprintf(p, "L: %8s %8s\n", "da:", "pa:");
190 p += sprintf(p, "-----------------------------------------\n");
191
192 mutex_lock(&iommu_debug_lock);
193
194 bytes = PAGE_SIZE - (p - buf);
195 p += dump_ioptable(obj, p, bytes);
196
197 bytes = simple_read_from_buffer(userbuf, count, ppos, buf, p - buf);
198
199 mutex_unlock(&iommu_debug_lock);
200 free_page((unsigned long)buf);
201
202 return bytes;
203}
204
14e0e679
HD
205#define DEBUG_FOPS(name) \
206 static const struct file_operations debug_##name##_fops = { \
234e3405 207 .open = simple_open, \
14e0e679
HD
208 .read = debug_read_##name, \
209 .write = debug_write_##name, \
c0b0aca0 210 .llseek = generic_file_llseek, \
14e0e679
HD
211 };
212
213#define DEBUG_FOPS_RO(name) \
214 static const struct file_operations debug_##name##_fops = { \
234e3405 215 .open = simple_open, \
14e0e679 216 .read = debug_read_##name, \
c0b0aca0 217 .llseek = generic_file_llseek, \
14e0e679
HD
218 };
219
14e0e679
HD
220DEBUG_FOPS_RO(regs);
221DEBUG_FOPS_RO(tlb);
222DEBUG_FOPS(pagetable);
14e0e679
HD
223
224#define __DEBUG_ADD_FILE(attr, mode) \
225 { \
226 struct dentry *dent; \
227 dent = debugfs_create_file(#attr, mode, parent, \
46451d62 228 dev, &debug_##attr##_fops); \
14e0e679
HD
229 if (!dent) \
230 return -ENOMEM; \
231 }
232
ff3a2b73
JP
233#define DEBUG_ADD_FILE(name) __DEBUG_ADD_FILE(name, 0600)
234#define DEBUG_ADD_FILE_RO(name) __DEBUG_ADD_FILE(name, 0400)
14e0e679
HD
235
236static int iommu_debug_register(struct device *dev, void *data)
237{
238 struct platform_device *pdev = to_platform_device(dev);
6c32df43 239 struct omap_iommu *obj = platform_get_drvdata(pdev);
46451d62 240 struct omap_iommu_arch_data *arch_data;
14e0e679
HD
241 struct dentry *d, *parent;
242
243 if (!obj || !obj->dev)
244 return -EINVAL;
245
46451d62
OBC
246 arch_data = kzalloc(sizeof(*arch_data), GFP_KERNEL);
247 if (!arch_data)
248 return -ENOMEM;
249
250 arch_data->iommu_dev = obj;
251
252 dev->archdata.iommu = arch_data;
253
14e0e679
HD
254 d = debugfs_create_dir(obj->name, iommu_debug_root);
255 if (!d)
46451d62 256 goto nomem;
14e0e679
HD
257 parent = d;
258
68570a74 259 d = debugfs_create_u8("nr_tlb_entries", 0400, parent,
14e0e679
HD
260 (u8 *)&obj->nr_tlb_entries);
261 if (!d)
46451d62 262 goto nomem;
14e0e679 263
14e0e679
HD
264 DEBUG_ADD_FILE_RO(regs);
265 DEBUG_ADD_FILE_RO(tlb);
266 DEBUG_ADD_FILE(pagetable);
14e0e679 267
46451d62
OBC
268 return 0;
269
270nomem:
271 kfree(arch_data);
272 return -ENOMEM;
273}
274
275static int iommu_debug_unregister(struct device *dev, void *data)
276{
277 if (!dev->archdata.iommu)
278 return 0;
279
280 kfree(dev->archdata.iommu);
281
282 dev->archdata.iommu = NULL;
283
14e0e679
HD
284 return 0;
285}
286
287static int __init iommu_debug_init(void)
288{
289 struct dentry *d;
290 int err;
291
292 d = debugfs_create_dir("iommu", NULL);
293 if (!d)
294 return -ENOMEM;
295 iommu_debug_root = d;
296
6c32df43 297 err = omap_foreach_iommu_device(d, iommu_debug_register);
14e0e679
HD
298 if (err)
299 goto err_out;
300 return 0;
301
302err_out:
303 debugfs_remove_recursive(iommu_debug_root);
304 return err;
305}
306module_init(iommu_debug_init)
307
308static void __exit iommu_debugfs_exit(void)
309{
310 debugfs_remove_recursive(iommu_debug_root);
46451d62 311 omap_foreach_iommu_device(NULL, iommu_debug_unregister);
14e0e679
HD
312}
313module_exit(iommu_debugfs_exit)
314
315MODULE_DESCRIPTION("omap iommu: debugfs interface");
316MODULE_AUTHOR("Hiroshi DOYU <Hiroshi.DOYU@nokia.com>");
317MODULE_LICENSE("GPL v2");