aboutsummaryrefslogtreecommitdiffstats
path: root/arch/frv/kernel
diff options
context:
space:
mode:
Diffstat (limited to 'arch/frv/kernel')
-rw-r--r--arch/frv/kernel/Makefile2
-rw-r--r--arch/frv/kernel/entry-table.S8
-rw-r--r--arch/frv/kernel/entry.S20
-rw-r--r--arch/frv/kernel/frv_ksyms.c1
-rw-r--r--arch/frv/kernel/head.inc2
-rw-r--r--arch/frv/kernel/pm.c8
-rw-r--r--arch/frv/kernel/semaphore.c155
-rw-r--r--arch/frv/kernel/switch_to.S7
-rw-r--r--arch/frv/kernel/traps.c240
9 files changed, 263 insertions, 180 deletions
diff --git a/arch/frv/kernel/Makefile b/arch/frv/kernel/Makefile
index e8f73ed28b5..c36f70b6699 100644
--- a/arch/frv/kernel/Makefile
+++ b/arch/frv/kernel/Makefile
@@ -9,7 +9,7 @@ extra-y:= head.o init_task.o vmlinux.lds
9 9
10obj-y := $(heads-y) entry.o entry-table.o break.o switch_to.o kernel_thread.o \ 10obj-y := $(heads-y) entry.o entry-table.o break.o switch_to.o kernel_thread.o \
11 kernel_execve.o process.o traps.o ptrace.o signal.o dma.o \ 11 kernel_execve.o process.o traps.o ptrace.o signal.o dma.o \
12 sys_frv.o time.o semaphore.o setup.o frv_ksyms.o \ 12 sys_frv.o time.o setup.o frv_ksyms.o \
13 debug-stub.o irq.o sleep.o uaccess.o 13 debug-stub.o irq.o sleep.o uaccess.o
14 14
15obj-$(CONFIG_GDBSTUB) += gdb-stub.o gdb-io.o 15obj-$(CONFIG_GDBSTUB) += gdb-stub.o gdb-io.o
diff --git a/arch/frv/kernel/entry-table.S b/arch/frv/kernel/entry-table.S
index d3b9253d862..bf35f33e48c 100644
--- a/arch/frv/kernel/entry-table.S
+++ b/arch/frv/kernel/entry-table.S
@@ -316,8 +316,14 @@ __trap_fixup_kernel_data_tlb_miss:
316 .section .trap.vector 316 .section .trap.vector
317 .org TBR_TT_TRAP0 >> 2 317 .org TBR_TT_TRAP0 >> 2
318 .long system_call 318 .long system_call
319 .rept 126 319 .rept 119
320 .long __entry_unsupported_trap 320 .long __entry_unsupported_trap
321 .endr 321 .endr
322
323 # userspace atomic op emulation, traps 120-126
324 .rept 7
325 .long __entry_atomic_op
326 .endr
327
322 .org TBR_TT_BREAK >> 2 328 .org TBR_TT_BREAK >> 2
323 .long __entry_debug_exception 329 .long __entry_debug_exception
diff --git a/arch/frv/kernel/entry.S b/arch/frv/kernel/entry.S
index f36d7f4a7c2..b8a4b94779b 100644
--- a/arch/frv/kernel/entry.S
+++ b/arch/frv/kernel/entry.S
@@ -656,6 +656,26 @@ __entry_debug_exception:
656 656
657############################################################################### 657###############################################################################
658# 658#
659# handle atomic operation emulation for userspace
660#
661###############################################################################
662 .globl __entry_atomic_op
663__entry_atomic_op:
664 LEDS 0x6012
665 sethi.p %hi(atomic_operation),gr5
666 setlo %lo(atomic_operation),gr5
667 movsg esfr1,gr8
668 movsg epcr0,gr9
669 movsg esr0,gr10
670
671 # now that we've accessed the exception regs, we can enable exceptions
672 movsg psr,gr4
673 ori gr4,#PSR_ET,gr4
674 movgs gr4,psr
675 jmpl @(gr5,gr0) ; call atomic_operation(esfr1,epcr0,esr0)
676
677###############################################################################
678#
659# handle media exception 679# handle media exception
660# 680#
661############################################################################### 681###############################################################################
diff --git a/arch/frv/kernel/frv_ksyms.c b/arch/frv/kernel/frv_ksyms.c
index f772704b3d2..0316b3c50ef 100644
--- a/arch/frv/kernel/frv_ksyms.c
+++ b/arch/frv/kernel/frv_ksyms.c
@@ -12,7 +12,6 @@
12#include <asm/pgalloc.h> 12#include <asm/pgalloc.h>
13#include <asm/irq.h> 13#include <asm/irq.h>
14#include <asm/io.h> 14#include <asm/io.h>
15#include <asm/semaphore.h>
16#include <asm/checksum.h> 15#include <asm/checksum.h>
17#include <asm/hardirq.h> 16#include <asm/hardirq.h>
18#include <asm/cacheflush.h> 17#include <asm/cacheflush.h>
diff --git a/arch/frv/kernel/head.inc b/arch/frv/kernel/head.inc
index d424cd2eb21..bff66628b99 100644
--- a/arch/frv/kernel/head.inc
+++ b/arch/frv/kernel/head.inc
@@ -46,5 +46,5 @@
46#ifdef CONFIG_MMU 46#ifdef CONFIG_MMU
47__sdram_base = 0x00000000 /* base address to which SDRAM relocated */ 47__sdram_base = 0x00000000 /* base address to which SDRAM relocated */
48#else 48#else
49__sdram_base = 0xc0000000 /* base address to which SDRAM relocated */ 49__sdram_base = __page_offset /* base address to which SDRAM relocated */
50#endif 50#endif
diff --git a/arch/frv/kernel/pm.c b/arch/frv/kernel/pm.c
index c57ce3f1f2e..73f3aeefd20 100644
--- a/arch/frv/kernel/pm.c
+++ b/arch/frv/kernel/pm.c
@@ -163,14 +163,11 @@ static int sysctl_pm_do_suspend(ctl_table *ctl, int write, struct file *filp,
163 if ((mode != 1) && (mode != 5)) 163 if ((mode != 1) && (mode != 5))
164 return -EINVAL; 164 return -EINVAL;
165 165
166 retval = pm_send_all(PM_SUSPEND, (void *)3);
167
168 if (retval == 0) { 166 if (retval == 0) {
169 if (mode == 5) 167 if (mode == 5)
170 retval = pm_do_bus_sleep(); 168 retval = pm_do_bus_sleep();
171 else 169 else
172 retval = pm_do_suspend(); 170 retval = pm_do_suspend();
173 pm_send_all(PM_RESUME, (void *)0);
174 } 171 }
175 172
176 return retval; 173 return retval;
@@ -183,9 +180,6 @@ static int try_set_cmode(int new_cmode)
183 if (!(clock_cmodes_permitted & (1<<new_cmode))) 180 if (!(clock_cmodes_permitted & (1<<new_cmode)))
184 return -EINVAL; 181 return -EINVAL;
185 182
186 /* tell all the drivers we're suspending */
187 pm_send_all(PM_SUSPEND, (void *)3);
188
189 /* now change cmode */ 183 /* now change cmode */
190 local_irq_disable(); 184 local_irq_disable();
191 frv_dma_pause_all(); 185 frv_dma_pause_all();
@@ -201,8 +195,6 @@ static int try_set_cmode(int new_cmode)
201 frv_dma_resume_all(); 195 frv_dma_resume_all();
202 local_irq_enable(); 196 local_irq_enable();
203 197
204 /* tell all the drivers we're resuming */
205 pm_send_all(PM_RESUME, (void *)0);
206 return 0; 198 return 0;
207} 199}
208 200
diff --git a/arch/frv/kernel/semaphore.c b/arch/frv/kernel/semaphore.c
deleted file mode 100644
index 7ee3a147b47..00000000000
--- a/arch/frv/kernel/semaphore.c
+++ /dev/null
@@ -1,155 +0,0 @@
1/* semaphore.c: FR-V semaphores
2 *
3 * Copyright (C) 2003 Red Hat, Inc. All Rights Reserved.
4 * Written by David Howells (dhowells@redhat.com)
5 * - Derived from lib/rwsem-spinlock.c
6 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation; either version
10 * 2 of the License, or (at your option) any later version.
11 */
12
13#include <linux/sched.h>
14#include <linux/module.h>
15#include <asm/semaphore.h>
16
17struct sem_waiter {
18 struct list_head list;
19 struct task_struct *task;
20};
21
22#ifdef CONFIG_DEBUG_SEMAPHORE
23void semtrace(struct semaphore *sem, const char *str)
24{
25 if (sem->debug)
26 printk("[%d] %s({%d,%d})\n",
27 current->pid,
28 str,
29 sem->counter,
30 list_empty(&sem->wait_list) ? 0 : 1);
31}
32#else
33#define semtrace(SEM,STR) do { } while(0)
34#endif
35
36/*
37 * wait for a token to be granted from a semaphore
38 * - entered with lock held and interrupts disabled
39 */
40void __down(struct semaphore *sem, unsigned long flags)
41{
42 struct task_struct *tsk = current;
43 struct sem_waiter waiter;
44
45 semtrace(sem, "Entering __down");
46
47 /* set up my own style of waitqueue */
48 waiter.task = tsk;
49 get_task_struct(tsk);
50
51 list_add_tail(&waiter.list, &sem->wait_list);
52
53 /* we don't need to touch the semaphore struct anymore */
54 spin_unlock_irqrestore(&sem->wait_lock, flags);
55
56 /* wait to be given the semaphore */
57 set_task_state(tsk, TASK_UNINTERRUPTIBLE);
58
59 for (;;) {
60 if (list_empty(&waiter.list))
61 break;
62 schedule();
63 set_task_state(tsk, TASK_UNINTERRUPTIBLE);
64 }
65
66 tsk->state = TASK_RUNNING;
67 semtrace(sem, "Leaving __down");
68}
69
70EXPORT_SYMBOL(__down);
71
72/*
73 * interruptibly wait for a token to be granted from a semaphore
74 * - entered with lock held and interrupts disabled
75 */
76int __down_interruptible(struct semaphore *sem, unsigned long flags)
77{
78 struct task_struct *tsk = current;
79 struct sem_waiter waiter;
80 int ret;
81
82 semtrace(sem,"Entering __down_interruptible");
83
84 /* set up my own style of waitqueue */
85 waiter.task = tsk;
86 get_task_struct(tsk);
87
88 list_add_tail(&waiter.list, &sem->wait_list);
89
90 /* we don't need to touch the semaphore struct anymore */
91 set_task_state(tsk, TASK_INTERRUPTIBLE);
92
93 spin_unlock_irqrestore(&sem->wait_lock, flags);
94
95 /* wait to be given the semaphore */
96 ret = 0;
97 for (;;) {
98 if (list_empty(&waiter.list))
99 break;
100 if (unlikely(signal_pending(current)))
101 goto interrupted;
102 schedule();
103 set_task_state(tsk, TASK_INTERRUPTIBLE);
104 }
105
106 out:
107 tsk->state = TASK_RUNNING;
108 semtrace(sem, "Leaving __down_interruptible");
109 return ret;
110
111 interrupted:
112 spin_lock_irqsave(&sem->wait_lock, flags);
113
114 if (!list_empty(&waiter.list)) {
115 list_del(&waiter.list);
116 ret = -EINTR;
117 }
118
119 spin_unlock_irqrestore(&sem->wait_lock, flags);
120 if (ret == -EINTR)
121 put_task_struct(current);
122 goto out;
123}
124
125EXPORT_SYMBOL(__down_interruptible);
126
127/*
128 * release a single token back to a semaphore
129 * - entered with lock held and interrupts disabled
130 */
131void __up(struct semaphore *sem)
132{
133 struct task_struct *tsk;
134 struct sem_waiter *waiter;
135
136 semtrace(sem,"Entering __up");
137
138 /* grant the token to the process at the front of the queue */
139 waiter = list_entry(sem->wait_list.next, struct sem_waiter, list);
140
141 /* We must be careful not to touch 'waiter' after we set ->task = NULL.
142 * It is allocated on the waiter's stack and may become invalid at
143 * any time after that point (due to a wakeup from another source).
144 */
145 list_del_init(&waiter->list);
146 tsk = waiter->task;
147 mb();
148 waiter->task = NULL;
149 wake_up_process(tsk);
150 put_task_struct(tsk);
151
152 semtrace(sem,"Leaving __up");
153}
154
155EXPORT_SYMBOL(__up);
diff --git a/arch/frv/kernel/switch_to.S b/arch/frv/kernel/switch_to.S
index b5275fa9cd0..b06668670fc 100644
--- a/arch/frv/kernel/switch_to.S
+++ b/arch/frv/kernel/switch_to.S
@@ -102,13 +102,6 @@ __switch_to:
102 movgs gr14,lr 102 movgs gr14,lr
103 bar 103 bar
104 104
105 srli gr15,#28,gr5
106 subicc gr5,#0xc,gr0,icc0
107 beq icc0,#0,111f
108 break
109 nop
110111:
111
112 # jump to __switch_back or ret_from_fork as appropriate 105 # jump to __switch_back or ret_from_fork as appropriate
113 # - move prev to GR8 106 # - move prev to GR8
114 movgs gr4,psr 107 movgs gr4,psr
diff --git a/arch/frv/kernel/traps.c b/arch/frv/kernel/traps.c
index 2e6098c8557..a40df80b2eb 100644
--- a/arch/frv/kernel/traps.c
+++ b/arch/frv/kernel/traps.c
@@ -49,7 +49,7 @@ asmlinkage void insn_access_error(unsigned long esfr1, unsigned long epcr0, unsi
49 info.si_signo = SIGSEGV; 49 info.si_signo = SIGSEGV;
50 info.si_code = SEGV_ACCERR; 50 info.si_code = SEGV_ACCERR;
51 info.si_errno = 0; 51 info.si_errno = 0;
52 info.si_addr = (void *) ((epcr0 & EPCR0_V) ? (epcr0 & EPCR0_PC) : __frame->pc); 52 info.si_addr = (void __user *) ((epcr0 & EPCR0_V) ? (epcr0 & EPCR0_PC) : __frame->pc);
53 53
54 force_sig_info(info.si_signo, &info, current); 54 force_sig_info(info.si_signo, &info, current);
55} /* end insn_access_error() */ 55} /* end insn_access_error() */
@@ -73,7 +73,7 @@ asmlinkage void illegal_instruction(unsigned long esfr1, unsigned long epcr0, un
73 epcr0, esr0, esfr1); 73 epcr0, esr0, esfr1);
74 74
75 info.si_errno = 0; 75 info.si_errno = 0;
76 info.si_addr = (void *) ((epcr0 & EPCR0_PC) ? (epcr0 & EPCR0_PC) : __frame->pc); 76 info.si_addr = (void __user *) ((epcr0 & EPCR0_V) ? (epcr0 & EPCR0_PC) : __frame->pc);
77 77
78 switch (__frame->tbr & TBR_TT) { 78 switch (__frame->tbr & TBR_TT) {
79 case TBR_TT_ILLEGAL_INSTR: 79 case TBR_TT_ILLEGAL_INSTR:
@@ -102,6 +102,234 @@ asmlinkage void illegal_instruction(unsigned long esfr1, unsigned long epcr0, un
102 102
103/*****************************************************************************/ 103/*****************************************************************************/
104/* 104/*
105 * handle atomic operations with errors
106 * - arguments in gr8, gr9, gr10
107 * - original memory value placed in gr5
108 * - replacement memory value placed in gr9
109 */
110asmlinkage void atomic_operation(unsigned long esfr1, unsigned long epcr0,
111 unsigned long esr0)
112{
113 static DEFINE_SPINLOCK(atomic_op_lock);
114 unsigned long x, y, z;
115 unsigned long __user *p;
116 mm_segment_t oldfs;
117 siginfo_t info;
118 int ret;
119
120 y = 0;
121 z = 0;
122
123 oldfs = get_fs();
124 if (!user_mode(__frame))
125 set_fs(KERNEL_DS);
126
127 switch (__frame->tbr & TBR_TT) {
128 /* TIRA gr0,#120
129 * u32 __atomic_user_cmpxchg32(u32 *ptr, u32 test, u32 new)
130 */
131 case TBR_TT_ATOMIC_CMPXCHG32:
132 p = (unsigned long __user *) __frame->gr8;
133 x = __frame->gr9;
134 y = __frame->gr10;
135
136 for (;;) {
137 ret = get_user(z, p);
138 if (ret < 0)
139 goto error;
140
141 if (z != x)
142 goto done;
143
144 spin_lock_irq(&atomic_op_lock);
145
146 if (__get_user(z, p) == 0) {
147 if (z != x)
148 goto done2;
149
150 if (__put_user(y, p) == 0)
151 goto done2;
152 goto error2;
153 }
154
155 spin_unlock_irq(&atomic_op_lock);
156 }
157
158 /* TIRA gr0,#121
159 * u32 __atomic_kernel_xchg32(void *v, u32 new)
160 */
161 case TBR_TT_ATOMIC_XCHG32:
162 p = (unsigned long __user *) __frame->gr8;
163 y = __frame->gr9;
164
165 for (;;) {
166 ret = get_user(z, p);
167 if (ret < 0)
168 goto error;
169
170 spin_lock_irq(&atomic_op_lock);
171
172 if (__get_user(z, p) == 0) {
173 if (__put_user(y, p) == 0)
174 goto done2;
175 goto error2;
176 }
177
178 spin_unlock_irq(&atomic_op_lock);
179 }
180
181 /* TIRA gr0,#122
182 * ulong __atomic_kernel_XOR_return(ulong i, ulong *v)
183 */
184 case TBR_TT_ATOMIC_XOR:
185 p = (unsigned long __user *) __frame->gr8;
186 x = __frame->gr9;
187
188 for (;;) {
189 ret = get_user(z, p);
190 if (ret < 0)
191 goto error;
192
193 spin_lock_irq(&atomic_op_lock);
194
195 if (__get_user(z, p) == 0) {
196 y = x ^ z;
197 if (__put_user(y, p) == 0)
198 goto done2;
199 goto error2;
200 }
201
202 spin_unlock_irq(&atomic_op_lock);
203 }
204
205 /* TIRA gr0,#123
206 * ulong __atomic_kernel_OR_return(ulong i, ulong *v)
207 */
208 case TBR_TT_ATOMIC_OR:
209 p = (unsigned long __user *) __frame->gr8;
210 x = __frame->gr9;
211
212 for (;;) {
213 ret = get_user(z, p);
214 if (ret < 0)
215 goto error;
216
217 spin_lock_irq(&atomic_op_lock);
218
219 if (__get_user(z, p) == 0) {
220 y = x ^ z;
221 if (__put_user(y, p) == 0)
222 goto done2;
223 goto error2;
224 }
225
226 spin_unlock_irq(&atomic_op_lock);
227 }
228
229 /* TIRA gr0,#124
230 * ulong __atomic_kernel_AND_return(ulong i, ulong *v)
231 */
232 case TBR_TT_ATOMIC_AND:
233 p = (unsigned long __user *) __frame->gr8;
234 x = __frame->gr9;
235
236 for (;;) {
237 ret = get_user(z, p);
238 if (ret < 0)
239 goto error;
240
241 spin_lock_irq(&atomic_op_lock);
242
243 if (__get_user(z, p) == 0) {
244 y = x & z;
245 if (__put_user(y, p) == 0)
246 goto done2;
247 goto error2;
248 }
249
250 spin_unlock_irq(&atomic_op_lock);
251 }
252
253 /* TIRA gr0,#125
254 * int __atomic_user_sub_return(atomic_t *v, int i)
255 */
256 case TBR_TT_ATOMIC_SUB:
257 p = (unsigned long __user *) __frame->gr8;
258 x = __frame->gr9;
259
260 for (;;) {
261 ret = get_user(z, p);
262 if (ret < 0)
263 goto error;
264
265 spin_lock_irq(&atomic_op_lock);
266
267 if (__get_user(z, p) == 0) {
268 y = z - x;
269 if (__put_user(y, p) == 0)
270 goto done2;
271 goto error2;
272 }
273
274 spin_unlock_irq(&atomic_op_lock);
275 }
276
277 /* TIRA gr0,#126
278 * int __atomic_user_add_return(atomic_t *v, int i)
279 */
280 case TBR_TT_ATOMIC_ADD:
281 p = (unsigned long __user *) __frame->gr8;
282 x = __frame->gr9;
283
284 for (;;) {
285 ret = get_user(z, p);
286 if (ret < 0)
287 goto error;
288
289 spin_lock_irq(&atomic_op_lock);
290
291 if (__get_user(z, p) == 0) {
292 y = z + x;
293 if (__put_user(y, p) == 0)
294 goto done2;
295 goto error2;
296 }
297
298 spin_unlock_irq(&atomic_op_lock);
299 }
300
301 default:
302 BUG();
303 }
304
305done2:
306 spin_unlock_irq(&atomic_op_lock);
307done:
308 if (!user_mode(__frame))
309 set_fs(oldfs);
310 __frame->gr5 = z;
311 __frame->gr9 = y;
312 return;
313
314error2:
315 spin_unlock_irq(&atomic_op_lock);
316error:
317 if (!user_mode(__frame))
318 set_fs(oldfs);
319 __frame->pc -= 4;
320
321 die_if_kernel("-- Atomic Op Error --\n");
322
323 info.si_signo = SIGSEGV;
324 info.si_code = SEGV_ACCERR;
325 info.si_errno = 0;
326 info.si_addr = (void __user *) __frame->pc;
327
328 force_sig_info(info.si_signo, &info, current);
329}
330
331/*****************************************************************************/
332/*
105 * 333 *
106 */ 334 */
107asmlinkage void media_exception(unsigned long msr0, unsigned long msr1) 335asmlinkage void media_exception(unsigned long msr0, unsigned long msr1)
@@ -116,7 +344,7 @@ asmlinkage void media_exception(unsigned long msr0, unsigned long msr1)
116 info.si_signo = SIGFPE; 344 info.si_signo = SIGFPE;
117 info.si_code = FPE_MDAOVF; 345 info.si_code = FPE_MDAOVF;
118 info.si_errno = 0; 346 info.si_errno = 0;
119 info.si_addr = (void *) __frame->pc; 347 info.si_addr = (void __user *) __frame->pc;
120 348
121 force_sig_info(info.si_signo, &info, current); 349 force_sig_info(info.si_signo, &info, current);
122} /* end media_exception() */ 350} /* end media_exception() */
@@ -156,7 +384,7 @@ asmlinkage void memory_access_exception(unsigned long esr0,
156 info.si_addr = NULL; 384 info.si_addr = NULL;
157 385
158 if ((esr0 & (ESRx_VALID | ESR0_EAV)) == (ESRx_VALID | ESR0_EAV)) 386 if ((esr0 & (ESRx_VALID | ESR0_EAV)) == (ESRx_VALID | ESR0_EAV))
159 info.si_addr = (void *) ear0; 387 info.si_addr = (void __user *) ear0;
160 388
161 force_sig_info(info.si_signo, &info, current); 389 force_sig_info(info.si_signo, &info, current);
162 390
@@ -185,7 +413,7 @@ asmlinkage void data_access_error(unsigned long esfr1, unsigned long esr15, unsi
185 info.si_signo = SIGSEGV; 413 info.si_signo = SIGSEGV;
186 info.si_code = SEGV_ACCERR; 414 info.si_code = SEGV_ACCERR;
187 info.si_errno = 0; 415 info.si_errno = 0;
188 info.si_addr = (void *) 416 info.si_addr = (void __user *)
189 (((esr15 & (ESRx_VALID|ESR15_EAV)) == (ESRx_VALID|ESR15_EAV)) ? ear15 : 0); 417 (((esr15 & (ESRx_VALID|ESR15_EAV)) == (ESRx_VALID|ESR15_EAV)) ? ear15 : 0);
190 418
191 force_sig_info(info.si_signo, &info, current); 419 force_sig_info(info.si_signo, &info, current);
@@ -219,7 +447,7 @@ asmlinkage void division_exception(unsigned long esfr1, unsigned long esr0, unsi
219 info.si_signo = SIGFPE; 447 info.si_signo = SIGFPE;
220 info.si_code = FPE_INTDIV; 448 info.si_code = FPE_INTDIV;
221 info.si_errno = 0; 449 info.si_errno = 0;
222 info.si_addr = (void *) __frame->pc; 450 info.si_addr = (void __user *) __frame->pc;
223 451
224 force_sig_info(info.si_signo, &info, current); 452 force_sig_info(info.si_signo, &info, current);
225} /* end division_exception() */ 453} /* end division_exception() */