aboutsummaryrefslogtreecommitdiffstats
path: root/arch/sh/mm
diff options
context:
space:
mode:
authorPaul Mundt <lethal@linux-sh.org>2010-01-12 02:12:25 -0500
committerPaul Mundt <lethal@linux-sh.org>2010-01-12 02:12:25 -0500
commita99eae5417a09e0be66bf574a9a79a2a7388c967 (patch)
tree5024736c9afd76124e2f5f5424ecc153f6218c8e /arch/sh/mm
parent776258df925acd0563f471ee4b3f19bbffb3c04f (diff)
sh: Split out the unaligned counters and user bits.
This splits out the unaligned access counters and userspace bits in to their own generic interface, which will allow them to be wired up on sh64 too. Signed-off-by: Paul Mundt <lethal@linux-sh.org>
Diffstat (limited to 'arch/sh/mm')
-rw-r--r--arch/sh/mm/Makefile2
-rw-r--r--arch/sh/mm/alignment.c159
2 files changed, 160 insertions, 1 deletions
diff --git a/arch/sh/mm/Makefile b/arch/sh/mm/Makefile
index dd5010c708e0..9fa11d655044 100644
--- a/arch/sh/mm/Makefile
+++ b/arch/sh/mm/Makefile
@@ -2,7 +2,7 @@
2# Makefile for the Linux SuperH-specific parts of the memory manager. 2# Makefile for the Linux SuperH-specific parts of the memory manager.
3# 3#
4 4
5obj-y := cache.o init.o consistent.o mmap.o 5obj-y := alignment.o cache.o init.o consistent.o mmap.o
6 6
7cacheops-$(CONFIG_CPU_SH2) := cache-sh2.o 7cacheops-$(CONFIG_CPU_SH2) := cache-sh2.o
8cacheops-$(CONFIG_CPU_SH2A) := cache-sh2a.o 8cacheops-$(CONFIG_CPU_SH2A) := cache-sh2a.o
diff --git a/arch/sh/mm/alignment.c b/arch/sh/mm/alignment.c
new file mode 100644
index 000000000000..e615151eac3b
--- /dev/null
+++ b/arch/sh/mm/alignment.c
@@ -0,0 +1,159 @@
1/*
2 * Alignment access counters and corresponding user-space interfaces.
3 *
4 * Copyright (C) 2009 ST Microelectronics
5 * Copyright (C) 2009 - 2010 Paul Mundt
6 *
7 * This file is subject to the terms and conditions of the GNU General Public
8 * License. See the file "COPYING" in the main directory of this archive
9 * for more details.
10 */
11#include <linux/module.h>
12#include <linux/kernel.h>
13#include <linux/seq_file.h>
14#include <linux/proc_fs.h>
15#include <linux/uaccess.h>
16#include <asm/alignment.h>
17
18static unsigned long se_user;
19static unsigned long se_sys;
20static unsigned long se_half;
21static unsigned long se_word;
22static unsigned long se_dword;
23static unsigned long se_multi;
24/* bitfield: 1: warn 2: fixup 4: signal -> combinations 2|4 && 1|2|4 are not
25 valid! */
26static int se_usermode = UM_WARN | UM_FIXUP;
27/* 0: no warning 1: print a warning message, disabled by default */
28static int se_kernmode_warn;
29
30void inc_unaligned_byte_access(void)
31{
32 se_half++;
33}
34
35void inc_unaligned_word_access(void)
36{
37 se_word++;
38}
39
40void inc_unaligned_dword_access(void)
41{
42 se_dword++;
43}
44
45void inc_unaligned_multi_access(void)
46{
47 se_multi++;
48}
49
50void inc_unaligned_user_access(void)
51{
52 se_user++;
53}
54
55void inc_unaligned_kernel_access(void)
56{
57 se_sys++;
58}
59
60unsigned int unaligned_user_action(void)
61{
62 return se_usermode;
63}
64
65void unaligned_fixups_notify(struct task_struct *tsk, insn_size_t insn,
66 struct pt_regs *regs)
67{
68 if (user_mode(regs) && (se_usermode & UM_WARN) && printk_ratelimit())
69 pr_notice("Fixing up unaligned userspace access "
70 "in \"%s\" pid=%d pc=0x%p ins=0x%04hx\n",
71 tsk->comm, task_pid_nr(tsk),
72 (void *)regs->pc, insn);
73 else if (se_kernmode_warn && printk_ratelimit())
74 pr_notice("Fixing up unaligned kernel access "
75 "in \"%s\" pid=%d pc=0x%p ins=0x%04hx\n",
76 tsk->comm, task_pid_nr(tsk),
77 (void *)regs->pc, insn);
78}
79
80static const char *se_usermode_action[] = {
81 "ignored",
82 "warn",
83 "fixup",
84 "fixup+warn",
85 "signal",
86 "signal+warn"
87};
88
89static int alignment_proc_show(struct seq_file *m, void *v)
90{
91 seq_printf(m, "User:\t\t%lu\n", se_user);
92 seq_printf(m, "System:\t\t%lu\n", se_sys);
93 seq_printf(m, "Half:\t\t%lu\n", se_half);
94 seq_printf(m, "Word:\t\t%lu\n", se_word);
95 seq_printf(m, "DWord:\t\t%lu\n", se_dword);
96 seq_printf(m, "Multi:\t\t%lu\n", se_multi);
97 seq_printf(m, "User faults:\t%i (%s)\n", se_usermode,
98 se_usermode_action[se_usermode]);
99 seq_printf(m, "Kernel faults:\t%i (fixup%s)\n", se_kernmode_warn,
100 se_kernmode_warn ? "+warn" : "");
101 return 0;
102}
103
104static int alignment_proc_open(struct inode *inode, struct file *file)
105{
106 return single_open(file, alignment_proc_show, NULL);
107}
108
109static ssize_t alignment_proc_write(struct file *file,
110 const char __user *buffer, size_t count, loff_t *pos)
111{
112 int *data = PDE(file->f_path.dentry->d_inode)->data;
113 char mode;
114
115 if (count > 0) {
116 if (get_user(mode, buffer))
117 return -EFAULT;
118 if (mode >= '0' && mode <= '5')
119 *data = mode - '0';
120 }
121 return count;
122}
123
124static const struct file_operations alignment_proc_fops = {
125 .owner = THIS_MODULE,
126 .open = alignment_proc_open,
127 .read = seq_read,
128 .llseek = seq_lseek,
129 .release = single_release,
130 .write = alignment_proc_write,
131};
132
133/*
134 * This needs to be done after sysctl_init, otherwise sys/ will be
135 * overwritten. Actually, this shouldn't be in sys/ at all since
136 * it isn't a sysctl, and it doesn't contain sysctl information.
137 * We now locate it in /proc/cpu/alignment instead.
138 */
139static int __init alignment_init(void)
140{
141 struct proc_dir_entry *dir, *res;
142
143 dir = proc_mkdir("cpu", NULL);
144 if (!dir)
145 return -ENOMEM;
146
147 res = proc_create_data("alignment", S_IWUSR | S_IRUGO, dir,
148 &alignment_proc_fops, &se_usermode);
149 if (!res)
150 return -ENOMEM;
151
152 res = proc_create_data("kernel_alignment", S_IWUSR | S_IRUGO, dir,
153 &alignment_proc_fops, &se_kernmode_warn);
154 if (!res)
155 return -ENOMEM;
156
157 return 0;
158}
159fs_initcall(alignment_init);