Skip to content
Navigation Menu
Toggle navigation
Sign in
In this repository
All GitHub Enterprise
↵
Jump to
↵
No suggested jump to results
In this repository
All GitHub Enterprise
↵
Jump to
↵
In this organization
All GitHub Enterprise
↵
Jump to
↵
In this repository
All GitHub Enterprise
↵
Jump to
↵
Sign in
Reseting focus
You signed in with another tab or window.
Reload
to refresh your session.
You signed out in another tab or window.
Reload
to refresh your session.
You switched accounts on another tab or window.
Reload
to refresh your session.
Dismiss alert
{{ message }}
mariux64
/
linux
Public
Notifications
You must be signed in to change notification settings
Fork
0
Star
0
Code
Issues
2
Pull requests
0
Actions
Projects
0
Wiki
Security
Insights
Additional navigation options
Code
Issues
Pull requests
Actions
Projects
Wiki
Security
Insights
Files
87997aa
Documentation
arch
block
crypto
drivers
accessibility
acpi
amba
ata
atm
auxdisplay
base
bcma
block
bluetooth
cdrom
char
clk
clocksource
connector
cpufreq
cpuidle
crypto
dca
devfreq
dio
dma
edac
eisa
firewire
firmware
gpio
gpu
hid
hv
hwmon
hwspinlock
i2c
ide
idle
ieee802154
infiniband
input
iommu
Kconfig
Makefile
amd_iommu.c
amd_iommu_init.c
amd_iommu_proto.h
amd_iommu_types.h
amd_iommu_v2.c
dmar.c
intel-iommu.c
intr_remapping.c
intr_remapping.h
iommu.c
iova.c
msm_iommu.c
msm_iommu_dev.c
omap-iommu-debug.c
omap-iommu.c
omap-iovmm.c
isdn
leds
lguest
macintosh
mca
md
media
memstick
message
mfd
misc
mmc
mtd
net
nfc
nubus
of
oprofile
parisc
parport
pci
pcmcia
pinctrl
platform
pnp
power
pps
ps3
ptp
rapidio
regulator
rtc
s390
sbus
scsi
sfi
sh
sn
spi
ssb
staging
target
tc
telephony
thermal
tty
uio
usb
uwb
vhost
video
virt
virtio
vlynq
w1
watchdog
xen
zorro
Kconfig
Makefile
firmware
fs
include
init
ipc
kernel
lib
mm
net
samples
scripts
security
sound
tools
usr
virt
.gitignore
.mailmap
COPYING
CREDITS
Kbuild
Kconfig
MAINTAINERS
Makefile
README
REPORTING-BUGS
Breadcrumbs
linux
/
drivers
/
iommu
/
omap-iommu-debug.c
Blame
Blame
Latest commit
Ohad Ben-Cohen
and
Joerg Roedel
iommu/omap: fix NULL pointer dereference
Feb 24, 2012
87997aa
·
Feb 24, 2012
History
History
450 lines (353 loc) · 9.78 KB
Breadcrumbs
linux
/
drivers
/
iommu
/
omap-iommu-debug.c
Top
File metadata and controls
Code
Blame
450 lines (353 loc) · 9.78 KB
Raw
/* * omap iommu: debugfs interface * * Copyright (C) 2008-2009 Nokia Corporation * * Written by Hiroshi DOYU <Hiroshi.DOYU@nokia.com> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. */ #include <linux/module.h> #include <linux/err.h> #include <linux/clk.h> #include <linux/io.h> #include <linux/slab.h> #include <linux/uaccess.h> #include <linux/platform_device.h> #include <linux/debugfs.h> #include <plat/iommu.h> #include <plat/iovmm.h> #include <plat/iopgtable.h> #define MAXCOLUMN 100 /* for short messages */ static DEFINE_MUTEX(iommu_debug_lock); static struct dentry *iommu_debug_root; static ssize_t debug_read_ver(struct file *file, char __user *userbuf, size_t count, loff_t *ppos) { u32 ver = omap_iommu_arch_version(); char buf[MAXCOLUMN], *p = buf; p += sprintf(p, "H/W version: %d.%d\n", (ver >> 4) & 0xf , ver & 0xf); return simple_read_from_buffer(userbuf, count, ppos, buf, p - buf); } static ssize_t debug_read_regs(struct file *file, char __user *userbuf, size_t count, loff_t *ppos) { struct device *dev = file->private_data; struct omap_iommu *obj = dev_to_omap_iommu(dev); char *p, *buf; ssize_t bytes; buf = kmalloc(count, GFP_KERNEL); if (!buf) return -ENOMEM; p = buf; mutex_lock(&iommu_debug_lock); bytes = omap_iommu_dump_ctx(obj, p, count); bytes = simple_read_from_buffer(userbuf, count, ppos, buf, bytes); mutex_unlock(&iommu_debug_lock); kfree(buf); return bytes; } static ssize_t debug_read_tlb(struct file *file, char __user *userbuf, size_t count, loff_t *ppos) { struct device *dev = file->private_data; struct omap_iommu *obj = dev_to_omap_iommu(dev); char *p, *buf; ssize_t bytes, rest; buf = kmalloc(count, GFP_KERNEL); if (!buf) return -ENOMEM; p = buf; mutex_lock(&iommu_debug_lock); p += sprintf(p, "%8s %8s\n", "cam:", "ram:"); p += sprintf(p, "-----------------------------------------\n"); rest = count - (p - buf); p += omap_dump_tlb_entries(obj, p, rest); bytes = simple_read_from_buffer(userbuf, count, ppos, buf, p - buf); mutex_unlock(&iommu_debug_lock); kfree(buf); return bytes; } static ssize_t debug_write_pagetable(struct file *file, const char __user *userbuf, size_t count, loff_t *ppos) { struct iotlb_entry e; struct cr_regs cr; int err; struct device *dev = file->private_data; struct omap_iommu *obj = dev_to_omap_iommu(dev); char buf[MAXCOLUMN], *p = buf; count = min(count, sizeof(buf)); mutex_lock(&iommu_debug_lock); if (copy_from_user(p, userbuf, count)) { mutex_unlock(&iommu_debug_lock); return -EFAULT; } sscanf(p, "%x %x", &cr.cam, &cr.ram); if (!cr.cam || !cr.ram) { mutex_unlock(&iommu_debug_lock); return -EINVAL; } omap_iotlb_cr_to_e(&cr, &e); err = omap_iopgtable_store_entry(obj, &e); if (err) dev_err(obj->dev, "%s: fail to store cr\n", __func__); mutex_unlock(&iommu_debug_lock); return count; } #define dump_ioptable_entry_one(lv, da, val) \ ({ \ int __err = 0; \ ssize_t bytes; \ const int maxcol = 22; \ const char *str = "%d: %08x %08x\n"; \ bytes = snprintf(p, maxcol, str, lv, da, val); \ p += bytes; \ len -= bytes; \ if (len < maxcol) \ __err = -ENOMEM; \ __err; \ }) static ssize_t dump_ioptable(struct omap_iommu *obj, char *buf, ssize_t len) { int i; u32 *iopgd; char *p = buf; spin_lock(&obj->page_table_lock); iopgd = iopgd_offset(obj, 0); for (i = 0; i < PTRS_PER_IOPGD; i++, iopgd++) { int j, err; u32 *iopte; u32 da; if (!*iopgd) continue; if (!(*iopgd & IOPGD_TABLE)) { da = i << IOPGD_SHIFT; err = dump_ioptable_entry_one(1, da, *iopgd); if (err) goto out; continue; } iopte = iopte_offset(iopgd, 0); for (j = 0; j < PTRS_PER_IOPTE; j++, iopte++) { if (!*iopte) continue; da = (i << IOPGD_SHIFT) + (j << IOPTE_SHIFT); err = dump_ioptable_entry_one(2, da, *iopgd); if (err) goto out; } } out: spin_unlock(&obj->page_table_lock); return p - buf; } static ssize_t debug_read_pagetable(struct file *file, char __user *userbuf, size_t count, loff_t *ppos) { struct device *dev = file->private_data; struct omap_iommu *obj = dev_to_omap_iommu(dev); char *p, *buf; size_t bytes; buf = (char *)__get_free_page(GFP_KERNEL); if (!buf) return -ENOMEM; p = buf; p += sprintf(p, "L: %8s %8s\n", "da:", "pa:"); p += sprintf(p, "-----------------------------------------\n"); mutex_lock(&iommu_debug_lock); bytes = PAGE_SIZE - (p - buf); p += dump_ioptable(obj, p, bytes); bytes = simple_read_from_buffer(userbuf, count, ppos, buf, p - buf); mutex_unlock(&iommu_debug_lock); free_page((unsigned long)buf); return bytes; } static ssize_t debug_read_mmap(struct file *file, char __user *userbuf, size_t count, loff_t *ppos) { struct device *dev = file->private_data; struct omap_iommu *obj = dev_to_omap_iommu(dev); char *p, *buf; struct iovm_struct *tmp; int uninitialized_var(i); ssize_t bytes; buf = (char *)__get_free_page(GFP_KERNEL); if (!buf) return -ENOMEM; p = buf; p += sprintf(p, "%-3s %-8s %-8s %6s %8s\n", "No", "start", "end", "size", "flags"); p += sprintf(p, "-------------------------------------------------\n"); mutex_lock(&iommu_debug_lock); list_for_each_entry(tmp, &obj->mmap, list) { size_t len; const char *str = "%3d %08x-%08x %6x %8x\n"; const int maxcol = 39; len = tmp->da_end - tmp->da_start; p += snprintf(p, maxcol, str, i, tmp->da_start, tmp->da_end, len, tmp->flags); if (PAGE_SIZE - (p - buf) < maxcol) break; i++; } bytes = simple_read_from_buffer(userbuf, count, ppos, buf, p - buf); mutex_unlock(&iommu_debug_lock); free_page((unsigned long)buf); return bytes; } static ssize_t debug_read_mem(struct file *file, char __user *userbuf, size_t count, loff_t *ppos) { struct device *dev = file->private_data; char *p, *buf; struct iovm_struct *area; ssize_t bytes; count = min_t(ssize_t, count, PAGE_SIZE); buf = (char *)__get_free_page(GFP_KERNEL); if (!buf) return -ENOMEM; p = buf; mutex_lock(&iommu_debug_lock); area = omap_find_iovm_area(dev, (u32)ppos); if (!area) { bytes = -EINVAL; goto err_out; } memcpy(p, area->va, count); p += count; bytes = simple_read_from_buffer(userbuf, count, ppos, buf, p - buf); err_out: mutex_unlock(&iommu_debug_lock); free_page((unsigned long)buf); return bytes; } static ssize_t debug_write_mem(struct file *file, const char __user *userbuf, size_t count, loff_t *ppos) { struct device *dev = file->private_data; struct iovm_struct *area; char *p, *buf; count = min_t(size_t, count, PAGE_SIZE); buf = (char *)__get_free_page(GFP_KERNEL); if (!buf) return -ENOMEM; p = buf; mutex_lock(&iommu_debug_lock); if (copy_from_user(p, userbuf, count)) { count = -EFAULT; goto err_out; } area = omap_find_iovm_area(dev, (u32)ppos); if (!area) { count = -EINVAL; goto err_out; } memcpy(area->va, p, count); err_out: mutex_unlock(&iommu_debug_lock); free_page((unsigned long)buf); return count; } static int debug_open_generic(struct inode *inode, struct file *file) { file->private_data = inode->i_private; return 0; } #define DEBUG_FOPS(name) \ static const struct file_operations debug_##name##_fops = { \ .open = debug_open_generic, \ .read = debug_read_##name, \ .write = debug_write_##name, \ .llseek = generic_file_llseek, \ }; #define DEBUG_FOPS_RO(name) \ static const struct file_operations debug_##name##_fops = { \ .open = debug_open_generic, \ .read = debug_read_##name, \ .llseek = generic_file_llseek, \ }; DEBUG_FOPS_RO(ver); DEBUG_FOPS_RO(regs); DEBUG_FOPS_RO(tlb); DEBUG_FOPS(pagetable); DEBUG_FOPS_RO(mmap); DEBUG_FOPS(mem); #define __DEBUG_ADD_FILE(attr, mode) \ { \ struct dentry *dent; \ dent = debugfs_create_file(#attr, mode, parent, \ dev, &debug_##attr##_fops); \ if (!dent) \ return -ENOMEM; \ } #define DEBUG_ADD_FILE(name) __DEBUG_ADD_FILE(name, 600) #define DEBUG_ADD_FILE_RO(name) __DEBUG_ADD_FILE(name, 400) static int iommu_debug_register(struct device *dev, void *data) { struct platform_device *pdev = to_platform_device(dev); struct omap_iommu *obj = platform_get_drvdata(pdev); struct omap_iommu_arch_data *arch_data; struct dentry *d, *parent; if (!obj || !obj->dev) return -EINVAL; arch_data = kzalloc(sizeof(*arch_data), GFP_KERNEL); if (!arch_data) return -ENOMEM; arch_data->iommu_dev = obj; dev->archdata.iommu = arch_data; d = debugfs_create_dir(obj->name, iommu_debug_root); if (!d) goto nomem; parent = d; d = debugfs_create_u8("nr_tlb_entries", 400, parent, (u8 *)&obj->nr_tlb_entries); if (!d) goto nomem; DEBUG_ADD_FILE_RO(ver); DEBUG_ADD_FILE_RO(regs); DEBUG_ADD_FILE_RO(tlb); DEBUG_ADD_FILE(pagetable); DEBUG_ADD_FILE_RO(mmap); DEBUG_ADD_FILE(mem); return 0; nomem: kfree(arch_data); return -ENOMEM; } static int iommu_debug_unregister(struct device *dev, void *data) { if (!dev->archdata.iommu) return 0; kfree(dev->archdata.iommu); dev->archdata.iommu = NULL; return 0; } static int __init iommu_debug_init(void) { struct dentry *d; int err; d = debugfs_create_dir("iommu", NULL); if (!d) return -ENOMEM; iommu_debug_root = d; err = omap_foreach_iommu_device(d, iommu_debug_register); if (err) goto err_out; return 0; err_out: debugfs_remove_recursive(iommu_debug_root); return err; } module_init(iommu_debug_init) static void __exit iommu_debugfs_exit(void) { debugfs_remove_recursive(iommu_debug_root); omap_foreach_iommu_device(NULL, iommu_debug_unregister); } module_exit(iommu_debugfs_exit) MODULE_DESCRIPTION("omap iommu: debugfs interface"); MODULE_AUTHOR("Hiroshi DOYU <Hiroshi.DOYU@nokia.com>"); MODULE_LICENSE("GPL v2");
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
You can’t perform that action at this time.