aboutsummaryrefslogtreecommitdiffstats
path: root/arch/sh/kernel
diff options
context:
space:
mode:
Diffstat (limited to 'arch/sh/kernel')
-rw-r--r--arch/sh/kernel/Makefile5
-rw-r--r--arch/sh/kernel/apm.c539
-rw-r--r--arch/sh/kernel/cf-enabler.c12
-rw-r--r--arch/sh/kernel/cpu/Makefile1
-rw-r--r--arch/sh/kernel/cpu/clock.c19
-rw-r--r--arch/sh/kernel/cpu/init.c21
-rw-r--r--arch/sh/kernel/cpu/irq/Makefile5
-rw-r--r--arch/sh/kernel/cpu/irq/intc2.c6
-rw-r--r--arch/sh/kernel/cpu/irq/ipr.c14
-rw-r--r--arch/sh/kernel/cpu/irq/maskreg.c93
-rw-r--r--arch/sh/kernel/cpu/irq/pint.c8
-rw-r--r--arch/sh/kernel/cpu/rtc.c128
-rw-r--r--arch/sh/kernel/cpu/sh3/Makefile13
-rw-r--r--arch/sh/kernel/cpu/sh3/clock-sh7706.c84
-rw-r--r--arch/sh/kernel/cpu/sh3/ex.S54
-rw-r--r--arch/sh/kernel/cpu/sh3/probe.c6
-rw-r--r--arch/sh/kernel/cpu/sh3/setup-sh7300.c43
-rw-r--r--arch/sh/kernel/cpu/sh3/setup-sh7705.c48
-rw-r--r--arch/sh/kernel/cpu/sh3/setup-sh7708.c43
-rw-r--r--arch/sh/kernel/cpu/sh3/setup-sh7709.c53
-rw-r--r--arch/sh/kernel/cpu/sh3/setup-sh7710.c43
-rw-r--r--arch/sh/kernel/cpu/sh4/Makefile10
-rw-r--r--arch/sh/kernel/cpu/sh4/ex.S176
-rw-r--r--arch/sh/kernel/cpu/sh4/probe.c138
-rw-r--r--arch/sh/kernel/cpu/sh4/setup-sh4-202.c43
-rw-r--r--arch/sh/kernel/cpu/sh4/setup-sh73180.c43
-rw-r--r--arch/sh/kernel/cpu/sh4/setup-sh7343.c43
-rw-r--r--arch/sh/kernel/cpu/sh4/setup-sh7750.c48
-rw-r--r--arch/sh/kernel/cpu/sh4/setup-sh7760.c53
-rw-r--r--arch/sh/kernel/cpu/sh4/setup-sh7770.c53
-rw-r--r--arch/sh/kernel/cpu/sh4/setup-sh7780.c79
-rw-r--r--arch/sh/kernel/cpu/sh4/sq.c543
-rw-r--r--arch/sh/kernel/early_printk.c106
-rw-r--r--arch/sh/kernel/entry.S333
-rw-r--r--arch/sh/kernel/head.S43
-rw-r--r--arch/sh/kernel/io.c67
-rw-r--r--arch/sh/kernel/irq.c168
-rw-r--r--arch/sh/kernel/kgdb_stub.c33
-rw-r--r--arch/sh/kernel/machine_kexec.c6
-rw-r--r--arch/sh/kernel/pm.c88
-rw-r--r--arch/sh/kernel/process.c28
-rw-r--r--arch/sh/kernel/ptrace.c1
-rw-r--r--arch/sh/kernel/semaphore.c2
-rw-r--r--arch/sh/kernel/setup.c117
-rw-r--r--arch/sh/kernel/sh_ksyms.c32
-rw-r--r--arch/sh/kernel/signal.c158
-rw-r--r--arch/sh/kernel/sys_sh.c56
-rw-r--r--arch/sh/kernel/syscalls.S353
-rw-r--r--arch/sh/kernel/time.c68
-rw-r--r--arch/sh/kernel/timers/timer-tmu.c24
-rw-r--r--arch/sh/kernel/traps.c184
-rw-r--r--arch/sh/kernel/vmlinux.lds.S17
-rw-r--r--arch/sh/kernel/vsyscall/Makefile36
-rw-r--r--arch/sh/kernel/vsyscall/vsyscall-note.S25
-rw-r--r--arch/sh/kernel/vsyscall/vsyscall-sigreturn.S39
-rw-r--r--arch/sh/kernel/vsyscall/vsyscall-syscall.S10
-rw-r--r--arch/sh/kernel/vsyscall/vsyscall-trapa.S42
-rw-r--r--arch/sh/kernel/vsyscall/vsyscall.c150
-rw-r--r--arch/sh/kernel/vsyscall/vsyscall.lds.S74
59 files changed, 3552 insertions, 1175 deletions
diff --git a/arch/sh/kernel/Makefile b/arch/sh/kernel/Makefile
index f05cd96f8867..5da88a43d350 100644
--- a/arch/sh/kernel/Makefile
+++ b/arch/sh/kernel/Makefile
@@ -6,9 +6,10 @@ extra-y := head.o init_task.o vmlinux.lds
6 6
7obj-y := process.o signal.o entry.o traps.o irq.o \ 7obj-y := process.o signal.o entry.o traps.o irq.o \
8 ptrace.o setup.o time.o sys_sh.o semaphore.o \ 8 ptrace.o setup.o time.o sys_sh.o semaphore.o \
9 io.o io_generic.o sh_ksyms.o 9 io.o io_generic.o sh_ksyms.o syscalls.o
10 10
11obj-y += cpu/ timers/ 11obj-y += cpu/ timers/
12obj-$(CONFIG_VSYSCALL) += vsyscall/
12 13
13obj-$(CONFIG_SMP) += smp.o 14obj-$(CONFIG_SMP) += smp.o
14obj-$(CONFIG_CF_ENABLER) += cf-enabler.o 15obj-$(CONFIG_CF_ENABLER) += cf-enabler.o
@@ -18,3 +19,5 @@ obj-$(CONFIG_SH_CPU_FREQ) += cpufreq.o
18obj-$(CONFIG_MODULES) += module.o 19obj-$(CONFIG_MODULES) += module.o
19obj-$(CONFIG_EARLY_PRINTK) += early_printk.o 20obj-$(CONFIG_EARLY_PRINTK) += early_printk.o
20obj-$(CONFIG_KEXEC) += machine_kexec.o relocate_kernel.o 21obj-$(CONFIG_KEXEC) += machine_kexec.o relocate_kernel.o
22obj-$(CONFIG_APM) += apm.o
23obj-$(CONFIG_PM) += pm.o
diff --git a/arch/sh/kernel/apm.c b/arch/sh/kernel/apm.c
new file mode 100644
index 000000000000..871e7d640002
--- /dev/null
+++ b/arch/sh/kernel/apm.c
@@ -0,0 +1,539 @@
1/*
2 * bios-less APM driver for hp680
3 *
4 * Copyright 2005 (c) Andriy Skulysh <askulysh@gmail.com>
5 *
6 * based on ARM APM driver by
7 * Jamey Hicks <jamey@crl.dec.com>
8 *
9 * adapted from the APM BIOS driver for Linux by
10 * Stephen Rothwell (sfr@linuxcare.com)
11 *
12 * APM 1.2 Reference:
13 * Intel Corporation, Microsoft Corporation. Advanced Power Management
14 * (APM) BIOS Interface Specification, Revision 1.2, February 1996.
15 *
16 * [This document is available from Microsoft at:
17 * http://www.microsoft.com/hwdev/busbios/amp_12.htm]
18 */
19#include <linux/config.h>
20#include <linux/module.h>
21#include <linux/poll.h>
22#include <linux/timer.h>
23#include <linux/slab.h>
24#include <linux/proc_fs.h>
25#include <linux/miscdevice.h>
26#include <linux/apm_bios.h>
27#include <linux/pm.h>
28#include <linux/pm_legacy.h>
29#include <asm/apm.h>
30
31#define MODNAME "apm"
32
33/*
34 * The apm_bios device is one of the misc char devices.
35 * This is its minor number.
36 */
37#define APM_MINOR_DEV 134
38
39/*
40 * Maximum number of events stored
41 */
42#define APM_MAX_EVENTS 16
43
44struct apm_queue {
45 unsigned int event_head;
46 unsigned int event_tail;
47 apm_event_t events[APM_MAX_EVENTS];
48};
49
50/*
51 * The per-file APM data
52 */
53struct apm_user {
54 struct list_head list;
55
56 unsigned int suser: 1;
57 unsigned int writer: 1;
58 unsigned int reader: 1;
59
60 int suspend_result;
61 unsigned int suspend_state;
62#define SUSPEND_NONE 0 /* no suspend pending */
63#define SUSPEND_PENDING 1 /* suspend pending read */
64#define SUSPEND_READ 2 /* suspend read, pending ack */
65#define SUSPEND_ACKED 3 /* suspend acked */
66#define SUSPEND_DONE 4 /* suspend completed */
67
68 struct apm_queue queue;
69};
70
71/*
72 * Local variables
73 */
74static int suspends_pending;
75
76static DECLARE_WAIT_QUEUE_HEAD(apm_waitqueue);
77static DECLARE_WAIT_QUEUE_HEAD(apm_suspend_waitqueue);
78
79/*
80 * This is a list of everyone who has opened /dev/apm_bios
81 */
82static DECLARE_RWSEM(user_list_lock);
83static LIST_HEAD(apm_user_list);
84
85/*
86 * kapmd info. kapmd provides us a process context to handle
87 * "APM" events within - specifically necessary if we're going
88 * to be suspending the system.
89 */
90static DECLARE_WAIT_QUEUE_HEAD(kapmd_wait);
91static DECLARE_COMPLETION(kapmd_exit);
92static DEFINE_SPINLOCK(kapmd_queue_lock);
93static struct apm_queue kapmd_queue;
94
95int apm_suspended;
96EXPORT_SYMBOL(apm_suspended);
97
98/* Platform-specific apm_read_proc(). */
99int (*apm_get_info)(char *buf, char **start, off_t fpos, int length);
100EXPORT_SYMBOL(apm_get_info);
101
102/*
103 * APM event queue management.
104 */
105static inline int queue_empty(struct apm_queue *q)
106{
107 return q->event_head == q->event_tail;
108}
109
110static inline apm_event_t queue_get_event(struct apm_queue *q)
111{
112 q->event_tail = (q->event_tail + 1) % APM_MAX_EVENTS;
113 return q->events[q->event_tail];
114}
115
116static void queue_add_event(struct apm_queue *q, apm_event_t event)
117{
118 q->event_head = (q->event_head + 1) % APM_MAX_EVENTS;
119 if (q->event_head == q->event_tail) {
120 static int notified;
121
122 if (notified++ == 0)
123 printk(KERN_ERR "apm: an event queue overflowed\n");
124
125 q->event_tail = (q->event_tail + 1) % APM_MAX_EVENTS;
126 }
127 q->events[q->event_head] = event;
128}
129
130static void queue_event_one_user(struct apm_user *as, apm_event_t event)
131{
132 if (as->suser && as->writer) {
133 switch (event) {
134 case APM_SYS_SUSPEND:
135 case APM_USER_SUSPEND:
136 /*
137 * If this user already has a suspend pending,
138 * don't queue another one.
139 */
140 if (as->suspend_state != SUSPEND_NONE)
141 return;
142
143 as->suspend_state = SUSPEND_PENDING;
144 suspends_pending++;
145 break;
146 }
147 }
148 queue_add_event(&as->queue, event);
149}
150
151static void queue_event(apm_event_t event, struct apm_user *sender)
152{
153 struct apm_user *as;
154
155 down_read(&user_list_lock);
156
157 list_for_each_entry(as, &apm_user_list, list)
158 if (as != sender && as->reader)
159 queue_event_one_user(as, event);
160
161 up_read(&user_list_lock);
162 wake_up_interruptible(&apm_waitqueue);
163}
164
165/**
166 * apm_queue_event - queue an APM event for kapmd
167 * @event: APM event
168 *
169 * Queue an APM event for kapmd to process and ultimately take the
170 * appropriate action. Only a subset of events are handled:
171 * %APM_LOW_BATTERY
172 * %APM_POWER_STATUS_CHANGE
173 * %APM_USER_SUSPEND
174 * %APM_SYS_SUSPEND
175 * %APM_CRITICAL_SUSPEND
176 */
177void apm_queue_event(apm_event_t event)
178{
179 spin_lock_irq(&kapmd_queue_lock);
180 queue_add_event(&kapmd_queue, event);
181 spin_unlock_irq(&kapmd_queue_lock);
182
183 wake_up_interruptible(&kapmd_wait);
184}
185EXPORT_SYMBOL(apm_queue_event);
186
187static void apm_suspend(void)
188{
189 struct apm_user *as;
190 int err;
191
192 apm_suspended = 1;
193 err = pm_suspend(PM_SUSPEND_MEM);
194
195 /*
196 * Anyone on the APM queues will think we're still suspended.
197 * Send a message so everyone knows we're now awake again.
198 */
199 queue_event(APM_NORMAL_RESUME, NULL);
200
201 /*
202 * Finally, wake up anyone who is sleeping on the suspend.
203 */
204 down_read(&user_list_lock);
205 list_for_each_entry(as, &apm_user_list, list) {
206 as->suspend_result = err;
207 as->suspend_state = SUSPEND_DONE;
208 }
209 up_read(&user_list_lock);
210
211 wake_up(&apm_suspend_waitqueue);
212 apm_suspended = 0;
213}
214
215static ssize_t apm_read(struct file *fp, char __user *buf,
216 size_t count, loff_t *ppos)
217{
218 struct apm_user *as = fp->private_data;
219 apm_event_t event;
220 int i = count, ret = 0;
221
222 if (count < sizeof(apm_event_t))
223 return -EINVAL;
224
225 if (queue_empty(&as->queue) && fp->f_flags & O_NONBLOCK)
226 return -EAGAIN;
227
228 wait_event_interruptible(apm_waitqueue, !queue_empty(&as->queue));
229
230 while ((i >= sizeof(event)) && !queue_empty(&as->queue)) {
231 event = queue_get_event(&as->queue);
232
233 ret = -EFAULT;
234 if (copy_to_user(buf, &event, sizeof(event)))
235 break;
236
237 if (event == APM_SYS_SUSPEND || event == APM_USER_SUSPEND)
238 as->suspend_state = SUSPEND_READ;
239
240 buf += sizeof(event);
241 i -= sizeof(event);
242 }
243
244 if (i < count)
245 ret = count - i;
246
247 return ret;
248}
249
250static unsigned int apm_poll(struct file *fp, poll_table * wait)
251{
252 struct apm_user *as = fp->private_data;
253
254 poll_wait(fp, &apm_waitqueue, wait);
255 return queue_empty(&as->queue) ? 0 : POLLIN | POLLRDNORM;
256}
257
258/*
259 * apm_ioctl - handle APM ioctl
260 *
261 * APM_IOC_SUSPEND
262 * This IOCTL is overloaded, and performs two functions. It is used to:
263 * - initiate a suspend
264 * - acknowledge a suspend read from /dev/apm_bios.
265 * Only when everyone who has opened /dev/apm_bios with write permission
266 * has acknowledge does the actual suspend happen.
267 */
268static int
269apm_ioctl(struct inode * inode, struct file *filp, u_int cmd, u_long arg)
270{
271 struct apm_user *as = filp->private_data;
272 unsigned long flags;
273 int err = -EINVAL;
274
275 if (!as->suser || !as->writer)
276 return -EPERM;
277
278 switch (cmd) {
279 case APM_IOC_SUSPEND:
280 as->suspend_result = -EINTR;
281
282 if (as->suspend_state == SUSPEND_READ) {
283 /*
284 * If we read a suspend command from /dev/apm_bios,
285 * then the corresponding APM_IOC_SUSPEND ioctl is
286 * interpreted as an acknowledge.
287 */
288 as->suspend_state = SUSPEND_ACKED;
289 suspends_pending--;
290 } else {
291 /*
292 * Otherwise it is a request to suspend the system.
293 * Queue an event for all readers, and expect an
294 * acknowledge from all writers who haven't already
295 * acknowledged.
296 */
297 queue_event(APM_USER_SUSPEND, as);
298 }
299
300 /*
301 * If there are no further acknowledges required, suspend
302 * the system.
303 */
304 if (suspends_pending == 0)
305 apm_suspend();
306
307 /*
308 * Wait for the suspend/resume to complete. If there are
309 * pending acknowledges, we wait here for them.
310 *
311 * Note that we need to ensure that the PM subsystem does
312 * not kick us out of the wait when it suspends the threads.
313 */
314 flags = current->flags;
315 current->flags |= PF_NOFREEZE;
316
317 /*
318 * Note: do not allow a thread which is acking the suspend
319 * to escape until the resume is complete.
320 */
321 if (as->suspend_state == SUSPEND_ACKED)
322 wait_event(apm_suspend_waitqueue,
323 as->suspend_state == SUSPEND_DONE);
324 else
325 wait_event_interruptible(apm_suspend_waitqueue,
326 as->suspend_state == SUSPEND_DONE);
327
328 current->flags = flags;
329 err = as->suspend_result;
330 as->suspend_state = SUSPEND_NONE;
331 break;
332 }
333
334 return err;
335}
336
337static int apm_release(struct inode * inode, struct file * filp)
338{
339 struct apm_user *as = filp->private_data;
340 filp->private_data = NULL;
341
342 down_write(&user_list_lock);
343 list_del(&as->list);
344 up_write(&user_list_lock);
345
346 /*
347 * We are now unhooked from the chain. As far as new
348 * events are concerned, we no longer exist. However, we
349 * need to balance suspends_pending, which means the
350 * possibility of sleeping.
351 */
352 if (as->suspend_state != SUSPEND_NONE) {
353 suspends_pending -= 1;
354 if (suspends_pending == 0)
355 apm_suspend();
356 }
357
358 kfree(as);
359 return 0;
360}
361
362static int apm_open(struct inode * inode, struct file * filp)
363{
364 struct apm_user *as;
365
366 as = kzalloc(sizeof(*as), GFP_KERNEL);
367 if (as) {
368 /*
369 * XXX - this is a tiny bit broken, when we consider BSD
370 * process accounting. If the device is opened by root, we
371 * instantly flag that we used superuser privs. Who knows,
372 * we might close the device immediately without doing a
373 * privileged operation -- cevans
374 */
375 as->suser = capable(CAP_SYS_ADMIN);
376 as->writer = (filp->f_mode & FMODE_WRITE) == FMODE_WRITE;
377 as->reader = (filp->f_mode & FMODE_READ) == FMODE_READ;
378
379 down_write(&user_list_lock);
380 list_add(&as->list, &apm_user_list);
381 up_write(&user_list_lock);
382
383 filp->private_data = as;
384 }
385
386 return as ? 0 : -ENOMEM;
387}
388
389static struct file_operations apm_bios_fops = {
390 .owner = THIS_MODULE,
391 .read = apm_read,
392 .poll = apm_poll,
393 .ioctl = apm_ioctl,
394 .open = apm_open,
395 .release = apm_release,
396};
397
398static struct miscdevice apm_device = {
399 .minor = APM_MINOR_DEV,
400 .name = "apm_bios",
401 .fops = &apm_bios_fops
402};
403
404
405#ifdef CONFIG_PROC_FS
406/*
407 * Arguments, with symbols from linux/apm_bios.h.
408 *
409 * 0) Linux driver version (this will change if format changes)
410 * 1) APM BIOS Version. Usually 1.0, 1.1 or 1.2.
411 * 2) APM flags from APM Installation Check (0x00):
412 * bit 0: APM_16_BIT_SUPPORT
413 * bit 1: APM_32_BIT_SUPPORT
414 * bit 2: APM_IDLE_SLOWS_CLOCK
415 * bit 3: APM_BIOS_DISABLED
416 * bit 4: APM_BIOS_DISENGAGED
417 * 3) AC line status
418 * 0x00: Off-line
419 * 0x01: On-line
420 * 0x02: On backup power (BIOS >= 1.1 only)
421 * 0xff: Unknown
422 * 4) Battery status
423 * 0x00: High
424 * 0x01: Low
425 * 0x02: Critical
426 * 0x03: Charging
427 * 0x04: Selected battery not present (BIOS >= 1.2 only)
428 * 0xff: Unknown
429 * 5) Battery flag
430 * bit 0: High
431 * bit 1: Low
432 * bit 2: Critical
433 * bit 3: Charging
434 * bit 7: No system battery
435 * 0xff: Unknown
436 * 6) Remaining battery life (percentage of charge):
437 * 0-100: valid
438 * -1: Unknown
439 * 7) Remaining battery life (time units):
440 * Number of remaining minutes or seconds
441 * -1: Unknown
442 * 8) min = minutes; sec = seconds
443 */
444static int apm_read_proc(char *buf, char **start, off_t fpos, int length)
445{
446 if (likely(apm_get_info))
447 return apm_get_info(buf, start, fpos, length);
448
449 return -EINVAL;
450}
451#endif
452
453static int kapmd(void *arg)
454{
455 daemonize("kapmd");
456 current->flags |= PF_NOFREEZE;
457
458 do {
459 apm_event_t event;
460
461 wait_event_interruptible(kapmd_wait,
462 !queue_empty(&kapmd_queue) || !pm_active);
463
464 if (!pm_active)
465 break;
466
467 spin_lock_irq(&kapmd_queue_lock);
468 event = 0;
469 if (!queue_empty(&kapmd_queue))
470 event = queue_get_event(&kapmd_queue);
471 spin_unlock_irq(&kapmd_queue_lock);
472
473 switch (event) {
474 case 0:
475 break;
476
477 case APM_LOW_BATTERY:
478 case APM_POWER_STATUS_CHANGE:
479 queue_event(event, NULL);
480 break;
481
482 case APM_USER_SUSPEND:
483 case APM_SYS_SUSPEND:
484 queue_event(event, NULL);
485 if (suspends_pending == 0)
486 apm_suspend();
487 break;
488
489 case APM_CRITICAL_SUSPEND:
490 apm_suspend();
491 break;
492 }
493 } while (1);
494
495 complete_and_exit(&kapmd_exit, 0);
496}
497
498static int __init apm_init(void)
499{
500 int ret;
501
502 pm_active = 1;
503
504 ret = kernel_thread(kapmd, NULL, CLONE_KERNEL);
505 if (unlikely(ret < 0)) {
506 pm_active = 0;
507 return ret;
508 }
509
510 create_proc_info_entry("apm", 0, NULL, apm_read_proc);
511
512 ret = misc_register(&apm_device);
513 if (unlikely(ret != 0)) {
514 remove_proc_entry("apm", NULL);
515
516 pm_active = 0;
517 wake_up(&kapmd_wait);
518 wait_for_completion(&kapmd_exit);
519 }
520
521 return ret;
522}
523
524static void __exit apm_exit(void)
525{
526 misc_deregister(&apm_device);
527 remove_proc_entry("apm", NULL);
528
529 pm_active = 0;
530 wake_up(&kapmd_wait);
531 wait_for_completion(&kapmd_exit);
532}
533
534module_init(apm_init);
535module_exit(apm_exit);
536
537MODULE_AUTHOR("Stephen Rothwell, Andriy Skulysh");
538MODULE_DESCRIPTION("Advanced Power Management");
539MODULE_LICENSE("GPL");
diff --git a/arch/sh/kernel/cf-enabler.c b/arch/sh/kernel/cf-enabler.c
index f1f9ab87f0b0..3e5fa1e24df0 100644
--- a/arch/sh/kernel/cf-enabler.c
+++ b/arch/sh/kernel/cf-enabler.c
@@ -10,7 +10,8 @@
10 */ 10 */
11 11
12#include <linux/init.h> 12#include <linux/init.h>
13 13#include <linux/mm.h>
14#include <linux/vmalloc.h>
14#include <asm/io.h> 15#include <asm/io.h>
15#include <asm/irq.h> 16#include <asm/irq.h>
16 17
@@ -32,8 +33,6 @@
32/* SH4 can't access PCMCIA interface through P2 area. 33/* SH4 can't access PCMCIA interface through P2 area.
33 * we must remap it with appropreate attribute bit of the page set. 34 * we must remap it with appropreate attribute bit of the page set.
34 * this part is based on Greg Banks' hd64465_ss.c implementation - Masahiro Abe */ 35 * this part is based on Greg Banks' hd64465_ss.c implementation - Masahiro Abe */
35#include <linux/mm.h>
36#include <linux/vmalloc.h>
37 36
38#if defined(CONFIG_CF_AREA6) 37#if defined(CONFIG_CF_AREA6)
39#define slot_no 0 38#define slot_no 0
@@ -41,9 +40,6 @@
41#define slot_no 1 40#define slot_no 1
42#endif 41#endif
43 42
44/* defined in mm/ioremap.c */
45extern void * p3_ioremap(unsigned long phys_addr, unsigned long size, unsigned long flags);
46
47/* use this pointer to access to directly connected compact flash io area*/ 43/* use this pointer to access to directly connected compact flash io area*/
48void *cf_io_base; 44void *cf_io_base;
49 45
@@ -62,7 +58,7 @@ static int __init allocate_cf_area(void)
62 return -ENOMEM; 58 return -ENOMEM;
63 } 59 }
64/* printk("p3_ioremap(paddr=0x%08lx, psize=0x%08lx, prot=0x%08lx)=0x%08lx\n", 60/* printk("p3_ioremap(paddr=0x%08lx, psize=0x%08lx, prot=0x%08lx)=0x%08lx\n",
65 paddrbase, psize, prot.pgprot, cf_io_base);*/ 61 paddrbase, psize, prot.pgprot, cf_io_base);*/
66 62
67 /* XXX : do we need attribute and common-memory area also? */ 63 /* XXX : do we need attribute and common-memory area also? */
68 64
@@ -87,7 +83,7 @@ static int __init cf_init_default(void)
87} 83}
88 84
89#if defined(CONFIG_SH_SOLUTION_ENGINE) 85#if defined(CONFIG_SH_SOLUTION_ENGINE)
90#include <asm/se/se.h> 86#include <asm/se.h>
91 87
92/* 88/*
93 * SolutionEngine 89 * SolutionEngine
diff --git a/arch/sh/kernel/cpu/Makefile b/arch/sh/kernel/cpu/Makefile
index 59d5b748752f..fb5dac069382 100644
--- a/arch/sh/kernel/cpu/Makefile
+++ b/arch/sh/kernel/cpu/Makefile
@@ -8,6 +8,5 @@ obj-$(CONFIG_CPU_SH2) += sh2/
8obj-$(CONFIG_CPU_SH3) += sh3/ 8obj-$(CONFIG_CPU_SH3) += sh3/
9obj-$(CONFIG_CPU_SH4) += sh4/ 9obj-$(CONFIG_CPU_SH4) += sh4/
10 10
11obj-$(CONFIG_SH_RTC) += rtc.o
12obj-$(CONFIG_UBC_WAKEUP) += ubc.o 11obj-$(CONFIG_UBC_WAKEUP) += ubc.o
13obj-$(CONFIG_SH_ADC) += adc.o 12obj-$(CONFIG_SH_ADC) += adc.o
diff --git a/arch/sh/kernel/cpu/clock.c b/arch/sh/kernel/cpu/clock.c
index 97fa37f42b84..51ec64cdf348 100644
--- a/arch/sh/kernel/cpu/clock.c
+++ b/arch/sh/kernel/cpu/clock.c
@@ -1,7 +1,7 @@
1/* 1/*
2 * arch/sh/kernel/cpu/clock.c - SuperH clock framework 2 * arch/sh/kernel/cpu/clock.c - SuperH clock framework
3 * 3 *
4 * Copyright (C) 2005 Paul Mundt 4 * Copyright (C) 2005, 2006 Paul Mundt
5 * 5 *
6 * This clock framework is derived from the OMAP version by: 6 * This clock framework is derived from the OMAP version by:
7 * 7 *
@@ -15,6 +15,7 @@
15#include <linux/kernel.h> 15#include <linux/kernel.h>
16#include <linux/init.h> 16#include <linux/init.h>
17#include <linux/module.h> 17#include <linux/module.h>
18#include <linux/mutex.h>
18#include <linux/list.h> 19#include <linux/list.h>
19#include <linux/kref.h> 20#include <linux/kref.h>
20#include <linux/seq_file.h> 21#include <linux/seq_file.h>
@@ -24,7 +25,7 @@
24 25
25static LIST_HEAD(clock_list); 26static LIST_HEAD(clock_list);
26static DEFINE_SPINLOCK(clock_lock); 27static DEFINE_SPINLOCK(clock_lock);
27static DECLARE_MUTEX(clock_list_sem); 28static DEFINE_MUTEX(clock_list_sem);
28 29
29/* 30/*
30 * Each subtype is expected to define the init routines for these clocks, 31 * Each subtype is expected to define the init routines for these clocks,
@@ -140,21 +141,21 @@ void clk_disable(struct clk *clk)
140 141
141int clk_register(struct clk *clk) 142int clk_register(struct clk *clk)
142{ 143{
143 down(&clock_list_sem); 144 mutex_lock(&clock_list_sem);
144 145
145 list_add(&clk->node, &clock_list); 146 list_add(&clk->node, &clock_list);
146 kref_init(&clk->kref); 147 kref_init(&clk->kref);
147 148
148 up(&clock_list_sem); 149 mutex_unlock(&clock_list_sem);
149 150
150 return 0; 151 return 0;
151} 152}
152 153
153void clk_unregister(struct clk *clk) 154void clk_unregister(struct clk *clk)
154{ 155{
155 down(&clock_list_sem); 156 mutex_lock(&clock_list_sem);
156 list_del(&clk->node); 157 list_del(&clk->node);
157 up(&clock_list_sem); 158 mutex_unlock(&clock_list_sem);
158} 159}
159 160
160inline unsigned long clk_get_rate(struct clk *clk) 161inline unsigned long clk_get_rate(struct clk *clk)
@@ -198,14 +199,14 @@ struct clk *clk_get(const char *id)
198{ 199{
199 struct clk *p, *clk = ERR_PTR(-ENOENT); 200 struct clk *p, *clk = ERR_PTR(-ENOENT);
200 201
201 down(&clock_list_sem); 202 mutex_lock(&clock_list_sem);
202 list_for_each_entry(p, &clock_list, node) { 203 list_for_each_entry(p, &clock_list, node) {
203 if (strcmp(id, p->name) == 0 && try_module_get(p->owner)) { 204 if (strcmp(id, p->name) == 0 && try_module_get(p->owner)) {
204 clk = p; 205 clk = p;
205 break; 206 break;
206 } 207 }
207 } 208 }
208 up(&clock_list_sem); 209 mutex_unlock(&clock_list_sem);
209 210
210 return clk; 211 return clk;
211} 212}
@@ -225,7 +226,7 @@ int __init clk_init(void)
225{ 226{
226 int i, ret = 0; 227 int i, ret = 0;
227 228
228 BUG_ON(unlikely(!master_clk.rate)); 229 BUG_ON(!master_clk.rate);
229 230
230 for (i = 0; i < ARRAY_SIZE(onchip_clocks); i++) { 231 for (i = 0; i < ARRAY_SIZE(onchip_clocks); i++) {
231 struct clk *clk = onchip_clocks[i]; 232 struct clk *clk = onchip_clocks[i];
diff --git a/arch/sh/kernel/cpu/init.c b/arch/sh/kernel/cpu/init.c
index 868e68b28880..bfb90eb0b7a6 100644
--- a/arch/sh/kernel/cpu/init.c
+++ b/arch/sh/kernel/cpu/init.c
@@ -4,6 +4,7 @@
4 * CPU init code 4 * CPU init code
5 * 5 *
6 * Copyright (C) 2002, 2003 Paul Mundt 6 * Copyright (C) 2002, 2003 Paul Mundt
7 * Copyright (C) 2003 Richard Curnow
7 * 8 *
8 * This file is subject to the terms and conditions of the GNU General Public 9 * This file is subject to the terms and conditions of the GNU General Public
9 * License. See the file "COPYING" in the main directory of this archive 10 * License. See the file "COPYING" in the main directory of this archive
@@ -13,6 +14,7 @@
13#include <linux/kernel.h> 14#include <linux/kernel.h>
14#include <asm/processor.h> 15#include <asm/processor.h>
15#include <asm/uaccess.h> 16#include <asm/uaccess.h>
17#include <asm/page.h>
16#include <asm/system.h> 18#include <asm/system.h>
17#include <asm/cacheflush.h> 19#include <asm/cacheflush.h>
18#include <asm/cache.h> 20#include <asm/cache.h>
@@ -51,7 +53,15 @@ static void __init cache_init(void)
51 ccr = ctrl_inl(CCR); 53 ccr = ctrl_inl(CCR);
52 54
53 /* 55 /*
54 * If the cache is already enabled .. flush it. 56 * At this point we don't know whether the cache is enabled or not - a
57 * bootloader may have enabled it. There are at least 2 things that
58 * could be dirty in the cache at this point:
59 * 1. kernel command line set up by boot loader
60 * 2. spilled registers from the prolog of this function
61 * => before re-initialising the cache, we must do a purge of the whole
62 * cache out to memory for safety. As long as nothing is spilled
63 * during the loop to lines that have already been done, this is safe.
64 * - RPC
55 */ 65 */
56 if (ccr & CCR_CACHE_ENABLE) { 66 if (ccr & CCR_CACHE_ENABLE) {
57 unsigned long ways, waysize, addrstart; 67 unsigned long ways, waysize, addrstart;
@@ -98,6 +108,8 @@ static void __init cache_init(void)
98 /* Force EMODE if possible */ 108 /* Force EMODE if possible */
99 if (cpu_data->dcache.ways > 1) 109 if (cpu_data->dcache.ways > 1)
100 flags |= CCR_CACHE_EMODE; 110 flags |= CCR_CACHE_EMODE;
111 else
112 flags &= ~CCR_CACHE_EMODE;
101#endif 113#endif
102 114
103#ifdef CONFIG_SH_WRITETHROUGH 115#ifdef CONFIG_SH_WRITETHROUGH
@@ -112,6 +124,9 @@ static void __init cache_init(void)
112 /* Turn on OCRAM -- halve the OC */ 124 /* Turn on OCRAM -- halve the OC */
113 flags |= CCR_CACHE_ORA; 125 flags |= CCR_CACHE_ORA;
114 cpu_data->dcache.sets >>= 1; 126 cpu_data->dcache.sets >>= 1;
127
128 cpu_data->dcache.way_size = cpu_data->dcache.sets *
129 cpu_data->dcache.linesz;
115#endif 130#endif
116 131
117 ctrl_outl(flags, CCR); 132 ctrl_outl(flags, CCR);
@@ -184,6 +199,10 @@ asmlinkage void __init sh_cpu_init(void)
184 /* Init the cache */ 199 /* Init the cache */
185 cache_init(); 200 cache_init();
186 201
202 shm_align_mask = max_t(unsigned long,
203 cpu_data->dcache.way_size - 1,
204 PAGE_SIZE - 1);
205
187 /* Disable the FPU */ 206 /* Disable the FPU */
188 if (fpu_disabled) { 207 if (fpu_disabled) {
189 printk("FPU Disabled\n"); 208 printk("FPU Disabled\n");
diff --git a/arch/sh/kernel/cpu/irq/Makefile b/arch/sh/kernel/cpu/irq/Makefile
index e3cccea15e1d..1c034c283f59 100644
--- a/arch/sh/kernel/cpu/irq/Makefile
+++ b/arch/sh/kernel/cpu/irq/Makefile
@@ -3,5 +3,6 @@
3# 3#
4obj-y += ipr.o imask.o 4obj-y += ipr.o imask.o
5 5
6obj-$(CONFIG_CPU_HAS_PINT_IRQ) += pint.o 6obj-$(CONFIG_CPU_HAS_PINT_IRQ) += pint.o
7obj-$(CONFIG_CPU_HAS_INTC2_IRQ) += intc2.o 7obj-$(CONFIG_CPU_HAS_MASKREG_IRQ) += maskreg.o
8obj-$(CONFIG_CPU_HAS_INTC2_IRQ) += intc2.o
diff --git a/arch/sh/kernel/cpu/irq/intc2.c b/arch/sh/kernel/cpu/irq/intc2.c
index 30064bf6e154..e30e4b7aa70e 100644
--- a/arch/sh/kernel/cpu/irq/intc2.c
+++ b/arch/sh/kernel/cpu/irq/intc2.c
@@ -241,9 +241,9 @@ static struct intc2_init {
241 /* 110-111 reserved/unused */ 241 /* 110-111 reserved/unused */
242#elif defined(CONFIG_CPU_SUBTYPE_SH7780) 242#elif defined(CONFIG_CPU_SUBTYPE_SH7780)
243 { TIMER_IRQ, 0, 24, 0, INTC_TMU0_MSK, 2}, 243 { TIMER_IRQ, 0, 24, 0, INTC_TMU0_MSK, 2},
244#ifdef CONFIG_SH_RTC 244 { 21, 1, 0, 0, INTC_RTC_MSK, TIMER_PRIORITY },
245 { RTC_IRQ, 4, 0, 0, INTC_RTC_MSK, TIMER_PRIORITY }, 245 { 22, 1, 1, 0, INTC_RTC_MSK, TIMER_PRIORITY },
246#endif 246 { 23, 1, 2, 0, INTC_RTC_MSK, TIMER_PRIORITY },
247 { SCIF0_ERI_IRQ, 8, 24, 0, INTC_SCIF0_MSK, SCIF0_PRIORITY }, 247 { SCIF0_ERI_IRQ, 8, 24, 0, INTC_SCIF0_MSK, SCIF0_PRIORITY },
248 { SCIF0_RXI_IRQ, 8, 24, 0, INTC_SCIF0_MSK, SCIF0_PRIORITY }, 248 { SCIF0_RXI_IRQ, 8, 24, 0, INTC_SCIF0_MSK, SCIF0_PRIORITY },
249 { SCIF0_BRI_IRQ, 8, 24, 0, INTC_SCIF0_MSK, SCIF0_PRIORITY }, 249 { SCIF0_BRI_IRQ, 8, 24, 0, INTC_SCIF0_MSK, SCIF0_PRIORITY },
diff --git a/arch/sh/kernel/cpu/irq/ipr.c b/arch/sh/kernel/cpu/irq/ipr.c
index 0f545941fb4f..f785822cd5de 100644
--- a/arch/sh/kernel/cpu/irq/ipr.c
+++ b/arch/sh/kernel/cpu/irq/ipr.c
@@ -57,31 +57,27 @@ static struct hw_interrupt_type ipr_irq_type = {
57 57
58static void disable_ipr_irq(unsigned int irq) 58static void disable_ipr_irq(unsigned int irq)
59{ 59{
60 unsigned long val, flags; 60 unsigned long val;
61 unsigned int addr = ipr_data[irq].addr; 61 unsigned int addr = ipr_data[irq].addr;
62 unsigned short mask = 0xffff ^ (0x0f << ipr_data[irq].shift); 62 unsigned short mask = 0xffff ^ (0x0f << ipr_data[irq].shift);
63 63
64 /* Set the priority in IPR to 0 */ 64 /* Set the priority in IPR to 0 */
65 local_irq_save(flags);
66 val = ctrl_inw(addr); 65 val = ctrl_inw(addr);
67 val &= mask; 66 val &= mask;
68 ctrl_outw(val, addr); 67 ctrl_outw(val, addr);
69 local_irq_restore(flags);
70} 68}
71 69
72static void enable_ipr_irq(unsigned int irq) 70static void enable_ipr_irq(unsigned int irq)
73{ 71{
74 unsigned long val, flags; 72 unsigned long val;
75 unsigned int addr = ipr_data[irq].addr; 73 unsigned int addr = ipr_data[irq].addr;
76 int priority = ipr_data[irq].priority; 74 int priority = ipr_data[irq].priority;
77 unsigned short value = (priority << ipr_data[irq].shift); 75 unsigned short value = (priority << ipr_data[irq].shift);
78 76
79 /* Set priority in IPR back to original value */ 77 /* Set priority in IPR back to original value */
80 local_irq_save(flags);
81 val = ctrl_inw(addr); 78 val = ctrl_inw(addr);
82 val |= value; 79 val |= value;
83 ctrl_outw(val, addr); 80 ctrl_outw(val, addr);
84 local_irq_restore(flags);
85} 81}
86 82
87static void mask_and_ack_ipr(unsigned int irq) 83static void mask_and_ack_ipr(unsigned int irq)
@@ -89,6 +85,7 @@ static void mask_and_ack_ipr(unsigned int irq)
89 disable_ipr_irq(irq); 85 disable_ipr_irq(irq);
90 86
91#if defined(CONFIG_CPU_SUBTYPE_SH7707) || defined(CONFIG_CPU_SUBTYPE_SH7709) || \ 87#if defined(CONFIG_CPU_SUBTYPE_SH7707) || defined(CONFIG_CPU_SUBTYPE_SH7709) || \
88 defined(CONFIG_CPU_SUBTYPE_SH7706) || \
92 defined(CONFIG_CPU_SUBTYPE_SH7300) || defined(CONFIG_CPU_SUBTYPE_SH7705) 89 defined(CONFIG_CPU_SUBTYPE_SH7300) || defined(CONFIG_CPU_SUBTYPE_SH7705)
93 /* This is needed when we use edge triggered setting */ 90 /* This is needed when we use edge triggered setting */
94 /* XXX: Is it really needed? */ 91 /* XXX: Is it really needed? */
@@ -123,7 +120,7 @@ void __init init_IRQ(void)
123#ifndef CONFIG_CPU_SUBTYPE_SH7780 120#ifndef CONFIG_CPU_SUBTYPE_SH7780
124 make_ipr_irq(TIMER_IRQ, TIMER_IPR_ADDR, TIMER_IPR_POS, TIMER_PRIORITY); 121 make_ipr_irq(TIMER_IRQ, TIMER_IPR_ADDR, TIMER_IPR_POS, TIMER_PRIORITY);
125 make_ipr_irq(TIMER1_IRQ, TIMER1_IPR_ADDR, TIMER1_IPR_POS, TIMER1_PRIORITY); 122 make_ipr_irq(TIMER1_IRQ, TIMER1_IPR_ADDR, TIMER1_IPR_POS, TIMER1_PRIORITY);
126#if defined(CONFIG_SH_RTC) 123#ifdef RTC_IRQ
127 make_ipr_irq(RTC_IRQ, RTC_IPR_ADDR, RTC_IPR_POS, RTC_PRIORITY); 124 make_ipr_irq(RTC_IRQ, RTC_IPR_ADDR, RTC_IPR_POS, RTC_PRIORITY);
128#endif 125#endif
129 126
@@ -162,6 +159,7 @@ void __init init_IRQ(void)
162#endif 159#endif
163 160
164#if defined(CONFIG_CPU_SUBTYPE_SH7707) || defined(CONFIG_CPU_SUBTYPE_SH7709) || \ 161#if defined(CONFIG_CPU_SUBTYPE_SH7707) || defined(CONFIG_CPU_SUBTYPE_SH7709) || \
162 defined(CONFIG_CPU_SUBTYPE_SH7706) || \
165 defined(CONFIG_CPU_SUBTYPE_SH7300) || defined(CONFIG_CPU_SUBTYPE_SH7705) 163 defined(CONFIG_CPU_SUBTYPE_SH7300) || defined(CONFIG_CPU_SUBTYPE_SH7705)
166 /* 164 /*
167 * Initialize the Interrupt Controller (INTC) 165 * Initialize the Interrupt Controller (INTC)
@@ -192,6 +190,8 @@ void __init init_IRQ(void)
192 /* Perform the machine specific initialisation */ 190 /* Perform the machine specific initialisation */
193 if (sh_mv.mv_init_irq != NULL) 191 if (sh_mv.mv_init_irq != NULL)
194 sh_mv.mv_init_irq(); 192 sh_mv.mv_init_irq();
193
194 irq_ctx_init(smp_processor_id());
195} 195}
196 196
197#if !defined(CONFIG_CPU_HAS_PINT_IRQ) 197#if !defined(CONFIG_CPU_HAS_PINT_IRQ)
diff --git a/arch/sh/kernel/cpu/irq/maskreg.c b/arch/sh/kernel/cpu/irq/maskreg.c
new file mode 100644
index 000000000000..492db31b3cab
--- /dev/null
+++ b/arch/sh/kernel/cpu/irq/maskreg.c
@@ -0,0 +1,93 @@
1/*
2 * Interrupt handling for Simple external interrupt mask register
3 *
4 * Copyright (C) 2001 A&D Co., Ltd. <http://www.aandd.co.jp>
5 *
6 * This is for the machine which have single 16 bit register
7 * for masking external IRQ individually.
8 * Each bit of the register is for masking each interrupt.
9 *
10 * This file may be copied or modified under the terms of the GNU
11 * General Public License. See linux/COPYING for more information.
12 */
13#include <linux/kernel.h>
14#include <linux/init.h>
15#include <linux/irq.h>
16#include <asm/system.h>
17#include <asm/io.h>
18
19/* address of external interrupt mask register */
20unsigned long irq_mask_register;
21
22/* forward declaration */
23static unsigned int startup_maskreg_irq(unsigned int irq);
24static void shutdown_maskreg_irq(unsigned int irq);
25static void enable_maskreg_irq(unsigned int irq);
26static void disable_maskreg_irq(unsigned int irq);
27static void mask_and_ack_maskreg(unsigned int);
28static void end_maskreg_irq(unsigned int irq);
29
30/* hw_interrupt_type */
31static struct hw_interrupt_type maskreg_irq_type = {
32 .typename = "Mask Register",
33 .startup = startup_maskreg_irq,
34 .shutdown = shutdown_maskreg_irq,
35 .enable = enable_maskreg_irq,
36 .disable = disable_maskreg_irq,
37 .ack = mask_and_ack_maskreg,
38 .end = end_maskreg_irq
39};
40
41/* actual implementatin */
42static unsigned int startup_maskreg_irq(unsigned int irq)
43{
44 enable_maskreg_irq(irq);
45 return 0; /* never anything pending */
46}
47
48static void shutdown_maskreg_irq(unsigned int irq)
49{
50 disable_maskreg_irq(irq);
51}
52
53static void disable_maskreg_irq(unsigned int irq)
54{
55 unsigned short val, mask = 0x01 << irq;
56
57 BUG_ON(!irq_mask_register);
58
59 /* Set "irq"th bit */
60 val = ctrl_inw(irq_mask_register);
61 val |= mask;
62 ctrl_outw(val, irq_mask_register);
63}
64
65static void enable_maskreg_irq(unsigned int irq)
66{
67 unsigned short val, mask = ~(0x01 << irq);
68
69 BUG_ON(!irq_mask_register);
70
71 /* Clear "irq"th bit */
72 val = ctrl_inw(irq_mask_register);
73 val &= mask;
74 ctrl_outw(val, irq_mask_register);
75}
76
77static void mask_and_ack_maskreg(unsigned int irq)
78{
79 disable_maskreg_irq(irq);
80}
81
82static void end_maskreg_irq(unsigned int irq)
83{
84 if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS)))
85 enable_maskreg_irq(irq);
86}
87
88void make_maskreg_irq(unsigned int irq)
89{
90 disable_irq_nosync(irq);
91 irq_desc[irq].handler = &maskreg_irq_type;
92 disable_maskreg_irq(irq);
93}
diff --git a/arch/sh/kernel/cpu/irq/pint.c b/arch/sh/kernel/cpu/irq/pint.c
index 80cd8108d36a..17f47b373d6e 100644
--- a/arch/sh/kernel/cpu/irq/pint.c
+++ b/arch/sh/kernel/cpu/irq/pint.c
@@ -48,26 +48,22 @@ static struct hw_interrupt_type pint_irq_type = {
48 48
49static void disable_pint_irq(unsigned int irq) 49static void disable_pint_irq(unsigned int irq)
50{ 50{
51 unsigned long val, flags; 51 unsigned long val;
52 52
53 local_irq_save(flags);
54 val = ctrl_inw(INTC_INTER); 53 val = ctrl_inw(INTC_INTER);
55 val &= ~(1 << (irq - PINT_IRQ_BASE)); 54 val &= ~(1 << (irq - PINT_IRQ_BASE));
56 ctrl_outw(val, INTC_INTER); /* disable PINTn */ 55 ctrl_outw(val, INTC_INTER); /* disable PINTn */
57 portcr_mask &= ~(3 << (irq - PINT_IRQ_BASE)*2); 56 portcr_mask &= ~(3 << (irq - PINT_IRQ_BASE)*2);
58 local_irq_restore(flags);
59} 57}
60 58
61static void enable_pint_irq(unsigned int irq) 59static void enable_pint_irq(unsigned int irq)
62{ 60{
63 unsigned long val, flags; 61 unsigned long val;
64 62
65 local_irq_save(flags);
66 val = ctrl_inw(INTC_INTER); 63 val = ctrl_inw(INTC_INTER);
67 val |= 1 << (irq - PINT_IRQ_BASE); 64 val |= 1 << (irq - PINT_IRQ_BASE);
68 ctrl_outw(val, INTC_INTER); /* enable PINTn */ 65 ctrl_outw(val, INTC_INTER); /* enable PINTn */
69 portcr_mask |= 3 << (irq - PINT_IRQ_BASE)*2; 66 portcr_mask |= 3 << (irq - PINT_IRQ_BASE)*2;
70 local_irq_restore(flags);
71} 67}
72 68
73static void mask_and_ack_pint(unsigned int irq) 69static void mask_and_ack_pint(unsigned int irq)
diff --git a/arch/sh/kernel/cpu/rtc.c b/arch/sh/kernel/cpu/rtc.c
deleted file mode 100644
index 4304cf75cfa2..000000000000
--- a/arch/sh/kernel/cpu/rtc.c
+++ /dev/null
@@ -1,128 +0,0 @@
1/*
2 * linux/arch/sh/kernel/rtc.c -- SH3 / SH4 on-chip RTC support
3 *
4 * Copyright (C) 2000 Philipp Rumpf <prumpf@tux.org>
5 * Copyright (C) 1999 Tetsuya Okada & Niibe Yutaka
6 */
7
8#include <linux/init.h>
9#include <linux/kernel.h>
10#include <linux/sched.h>
11#include <linux/time.h>
12#include <linux/bcd.h>
13#include <asm/io.h>
14#include <asm/rtc.h>
15
16void sh_rtc_gettimeofday(struct timespec *ts)
17{
18 unsigned int sec128, sec, sec2, min, hr, wk, day, mon, yr, yr100, cf_bit;
19 unsigned long flags;
20
21 again:
22 do {
23 local_irq_save(flags);
24 ctrl_outb(0, RCR1); /* Clear CF-bit */
25 sec128 = ctrl_inb(R64CNT);
26 sec = ctrl_inb(RSECCNT);
27 min = ctrl_inb(RMINCNT);
28 hr = ctrl_inb(RHRCNT);
29 wk = ctrl_inb(RWKCNT);
30 day = ctrl_inb(RDAYCNT);
31 mon = ctrl_inb(RMONCNT);
32#if defined(CONFIG_CPU_SH4)
33 yr = ctrl_inw(RYRCNT);
34 yr100 = (yr >> 8);
35 yr &= 0xff;
36#else
37 yr = ctrl_inb(RYRCNT);
38 yr100 = (yr == 0x99) ? 0x19 : 0x20;
39#endif
40 sec2 = ctrl_inb(R64CNT);
41 cf_bit = ctrl_inb(RCR1) & RCR1_CF;
42 local_irq_restore(flags);
43 } while (cf_bit != 0 || ((sec128 ^ sec2) & RTC_BIT_INVERTED) != 0);
44
45 BCD_TO_BIN(yr100);
46 BCD_TO_BIN(yr);
47 BCD_TO_BIN(mon);
48 BCD_TO_BIN(day);
49 BCD_TO_BIN(hr);
50 BCD_TO_BIN(min);
51 BCD_TO_BIN(sec);
52
53 if (yr > 99 || mon < 1 || mon > 12 || day > 31 || day < 1 ||
54 hr > 23 || min > 59 || sec > 59) {
55 printk(KERN_ERR
56 "SH RTC: invalid value, resetting to 1 Jan 2000\n");
57 local_irq_save(flags);
58 ctrl_outb(RCR2_RESET, RCR2); /* Reset & Stop */
59 ctrl_outb(0, RSECCNT);
60 ctrl_outb(0, RMINCNT);
61 ctrl_outb(0, RHRCNT);
62 ctrl_outb(6, RWKCNT);
63 ctrl_outb(1, RDAYCNT);
64 ctrl_outb(1, RMONCNT);
65#if defined(CONFIG_CPU_SH4)
66 ctrl_outw(0x2000, RYRCNT);
67#else
68 ctrl_outb(0, RYRCNT);
69#endif
70 ctrl_outb(RCR2_RTCEN|RCR2_START, RCR2); /* Start */
71 goto again;
72 }
73
74#if RTC_BIT_INVERTED != 0
75 if ((sec128 & RTC_BIT_INVERTED))
76 sec--;
77#endif
78
79 ts->tv_sec = mktime(yr100 * 100 + yr, mon, day, hr, min, sec);
80 ts->tv_nsec = ((sec128 * 1000000) / 128) * 1000;
81}
82
83/*
84 * Changed to only care about tv_sec, and not the full timespec struct
85 * (i.e. tv_nsec). It can easily be switched to timespec for future cpus
86 * that support setting usec or nsec RTC values.
87 */
88int sh_rtc_settimeofday(const time_t secs)
89{
90 int retval = 0;
91 int real_seconds, real_minutes, cmos_minutes;
92 unsigned long flags;
93
94 local_irq_save(flags);
95 ctrl_outb(RCR2_RESET, RCR2); /* Reset pre-scaler & stop RTC */
96
97 cmos_minutes = ctrl_inb(RMINCNT);
98 BCD_TO_BIN(cmos_minutes);
99
100 /*
101 * since we're only adjusting minutes and seconds,
102 * don't interfere with hour overflow. This avoids
103 * messing with unknown time zones but requires your
104 * RTC not to be off by more than 15 minutes
105 */
106 real_seconds = secs % 60;
107 real_minutes = secs / 60;
108 if (((abs(real_minutes - cmos_minutes) + 15)/30) & 1)
109 real_minutes += 30; /* correct for half hour time zone */
110 real_minutes %= 60;
111
112 if (abs(real_minutes - cmos_minutes) < 30) {
113 BIN_TO_BCD(real_seconds);
114 BIN_TO_BCD(real_minutes);
115 ctrl_outb(real_seconds, RSECCNT);
116 ctrl_outb(real_minutes, RMINCNT);
117 } else {
118 printk(KERN_WARNING
119 "set_rtc_time: can't update from %d to %d\n",
120 cmos_minutes, real_minutes);
121 retval = -1;
122 }
123
124 ctrl_outb(RCR2_RTCEN|RCR2_START, RCR2); /* Start RTC */
125 local_irq_restore(flags);
126
127 return retval;
128}
diff --git a/arch/sh/kernel/cpu/sh3/Makefile b/arch/sh/kernel/cpu/sh3/Makefile
index b54dbb9a0c86..58d3815695ff 100644
--- a/arch/sh/kernel/cpu/sh3/Makefile
+++ b/arch/sh/kernel/cpu/sh3/Makefile
@@ -4,10 +4,21 @@
4 4
5obj-y := ex.o probe.o 5obj-y := ex.o probe.o
6 6
7# CPU subtype setup
8obj-$(CONFIG_CPU_SUBTYPE_SH7705) += setup-sh7705.o
9obj-$(CONFIG_CPU_SUBTYPE_SH7706) += setup-sh7709.o
10obj-$(CONFIG_CPU_SUBTYPE_SH7707) += setup-sh7709.o
11obj-$(CONFIG_CPU_SUBTYPE_SH7708) += setup-sh7708.o
12obj-$(CONFIG_CPU_SUBTYPE_SH7709) += setup-sh7709.o
13obj-$(CONFIG_CPU_SUBTYPE_SH7300) += setup-sh7300.o
14obj-$(CONFIG_CPU_SUBTYPE_SH7710) += setup-sh7710.o
15
16# Primary on-chip clocks (common)
7clock-$(CONFIG_CPU_SH3) := clock-sh3.o 17clock-$(CONFIG_CPU_SH3) := clock-sh3.o
8clock-$(CONFIG_CPU_SUBTYPE_SH7300) := clock-sh7300.o 18clock-$(CONFIG_CPU_SUBTYPE_SH7300) := clock-sh7300.o
9clock-$(CONFIG_CPU_SUBTYPE_SH7705) := clock-sh7705.o 19clock-$(CONFIG_CPU_SUBTYPE_SH7705) := clock-sh7705.o
20clock-$(CONFIG_CPU_SUBTYPE_SH7706) := clock-sh7706.o
10clock-$(CONFIG_CPU_SUBTYPE_SH7709) := clock-sh7709.o 21clock-$(CONFIG_CPU_SUBTYPE_SH7709) := clock-sh7709.o
22clock-$(CONFIG_CPU_SUBTYPE_SH7710) := clock-sh7300.o
11 23
12obj-y += $(clock-y) 24obj-y += $(clock-y)
13
diff --git a/arch/sh/kernel/cpu/sh3/clock-sh7706.c b/arch/sh/kernel/cpu/sh3/clock-sh7706.c
new file mode 100644
index 000000000000..0cf96f9833bc
--- /dev/null
+++ b/arch/sh/kernel/cpu/sh3/clock-sh7706.c
@@ -0,0 +1,84 @@
1/*
2 * arch/sh/kernel/cpu/sh3/clock-sh7706.c
3 *
4 * SH7706 support for the clock framework
5 *
6 * Copyright (C) 2006 Takashi YOSHII
7 *
8 * Based on arch/sh/kernel/cpu/sh3/clock-sh7709.c
9 * Copyright (C) 2005 Andriy Skulysh
10 *
11 * This file is subject to the terms and conditions of the GNU General Public
12 * License. See the file "COPYING" in the main directory of this archive
13 * for more details.
14 */
15#include <linux/init.h>
16#include <linux/kernel.h>
17#include <asm/clock.h>
18#include <asm/freq.h>
19#include <asm/io.h>
20
21static int stc_multipliers[] = { 1, 2, 4, 1, 3, 6, 1, 1 };
22static int ifc_divisors[] = { 1, 2, 4, 1, 3, 1, 1, 1 };
23static int pfc_divisors[] = { 1, 2, 4, 1, 3, 6, 1, 1 };
24
25static void master_clk_init(struct clk *clk)
26{
27 int frqcr = ctrl_inw(FRQCR);
28 int idx = ((frqcr & 0x2000) >> 11) | (frqcr & 0x0003);
29
30 clk->rate *= pfc_divisors[idx];
31}
32
33static struct clk_ops sh7706_master_clk_ops = {
34 .init = master_clk_init,
35};
36
37static void module_clk_recalc(struct clk *clk)
38{
39 int frqcr = ctrl_inw(FRQCR);
40 int idx = ((frqcr & 0x2000) >> 11) | (frqcr & 0x0003);
41
42 clk->rate = clk->parent->rate / pfc_divisors[idx];
43}
44
45static struct clk_ops sh7706_module_clk_ops = {
46 .recalc = module_clk_recalc,
47};
48
49static void bus_clk_recalc(struct clk *clk)
50{
51 int frqcr = ctrl_inw(FRQCR);
52 int idx = ((frqcr & 0x8000) >> 13) | ((frqcr & 0x0030) >> 4);
53
54 clk->rate = clk->parent->rate / stc_multipliers[idx];
55}
56
57static struct clk_ops sh7706_bus_clk_ops = {
58 .recalc = bus_clk_recalc,
59};
60
61static void cpu_clk_recalc(struct clk *clk)
62{
63 int frqcr = ctrl_inw(FRQCR);
64 int idx = ((frqcr & 0x4000) >> 12) | ((frqcr & 0x000c) >> 2);
65
66 clk->rate = clk->parent->rate / ifc_divisors[idx];
67}
68
69static struct clk_ops sh7706_cpu_clk_ops = {
70 .recalc = cpu_clk_recalc,
71};
72
73static struct clk_ops *sh7706_clk_ops[] = {
74 &sh7706_master_clk_ops,
75 &sh7706_module_clk_ops,
76 &sh7706_bus_clk_ops,
77 &sh7706_cpu_clk_ops,
78};
79
80void __init arch_init_clk_ops(struct clk_ops **ops, int idx)
81{
82 if (idx < ARRAY_SIZE(sh7706_clk_ops))
83 *ops = sh7706_clk_ops[idx];
84}
diff --git a/arch/sh/kernel/cpu/sh3/ex.S b/arch/sh/kernel/cpu/sh3/ex.S
index cc04e9e239ff..44daf44833f9 100644
--- a/arch/sh/kernel/cpu/sh3/ex.S
+++ b/arch/sh/kernel/cpu/sh3/ex.S
@@ -84,8 +84,12 @@ ENTRY(interrupt_table)
84 .long do_IRQ ! rovi 84 .long do_IRQ ! rovi
85 .long do_IRQ 85 .long do_IRQ
86 .long do_IRQ /* 5E0 */ 86 .long do_IRQ /* 5E0 */
87#if defined(CONFIG_CPU_SUBTYPE_SH7707) || defined(CONFIG_CPU_SUBTYPE_SH7709) || \ 87#if defined(CONFIG_CPU_SUBTYPE_SH7707) || \
88 defined(CONFIG_CPU_SUBTYPE_SH7300) || defined(CONFIG_CPU_SUBTYPE_SH7705) 88 defined(CONFIG_CPU_SUBTYPE_SH7709) || \
89 defined(CONFIG_CPU_SUBTYPE_SH7706) || \
90 defined(CONFIG_CPU_SUBTYPE_SH7300) || \
91 defined(CONFIG_CPU_SUBTYPE_SH7705) || \
92 defined(CONFIG_CPU_SUBTYPE_SH7710)
89 .long do_IRQ ! 32 IRQ irq0 /* 600 */ 93 .long do_IRQ ! 32 IRQ irq0 /* 600 */
90 .long do_IRQ ! 33 irq1 94 .long do_IRQ ! 33 irq1
91 .long do_IRQ ! 34 irq2 95 .long do_IRQ ! 34 irq2
@@ -147,6 +151,51 @@ ENTRY(interrupt_table)
147 .long do_IRQ ! 62 PCC pcc0i 151 .long do_IRQ ! 62 PCC pcc0i
148 .long do_IRQ ! 63 pcc1i /* 9E0 */ 152 .long do_IRQ ! 63 pcc1i /* 9E0 */
149#endif 153#endif
154#if defined(CONFIG_CPU_SUBTYPE_SH7710)
155 .long exception_none ! 61 /* 9A0 */
156 .long exception_none ! 62
157 .long exception_none ! 63
158 .long exception_none ! 64 /* A00 */
159 .long exception_none ! 65
160 .long exception_none ! 66
161 .long exception_none ! 67
162 .long exception_none ! 68
163 .long exception_none ! 69
164 .long exception_none ! 70
165 .long exception_none ! 71
166 .long exception_none ! 72 /* B00 */
167 .long exception_none ! 73
168 .long exception_none ! 74
169 .long exception_none ! 75
170 .long do_IRQ ! 76 DMAC2 dei4 /* B80 */
171 .long do_IRQ ! 77 DMAC2 dei5
172 .long exception_none ! 78
173 .long do_IRQ ! 79 IPSEC ipseci /* BE0 */
174 .long do_IRQ ! 80 EDMAC eint0 /* C00 */
175 .long do_IRQ ! 81 EDMAC eint1
176 .long do_IRQ ! 82 EDMAC eint2
177 .long exception_none ! 83 /* C60 */
178 .long exception_none ! 84
179 .long exception_none ! 85
180 .long exception_none ! 86
181 .long exception_none ! 87
182 .long exception_none ! 88 /* D00 */
183 .long exception_none ! 89
184 .long exception_none ! 90
185 .long exception_none ! 91
186 .long exception_none ! 92
187 .long exception_none ! 93
188 .long exception_none ! 94
189 .long exception_none ! 95
190 .long do_IRQ ! 96 SIOF eri0 /* E00 */
191 .long do_IRQ ! 97 txi0
192 .long do_IRQ ! 98 rxi0
193 .long do_IRQ ! 99 cci0
194 .long do_IRQ ! 100 eri1 /* E80 */
195 .long do_IRQ ! 101 txi1
196 .long do_IRQ ! 102 rxi2
197 .long do_IRQ ! 103 cci3
198#endif
150#if defined(CONFIG_CPU_SUBTYPE_SH7300) 199#if defined(CONFIG_CPU_SUBTYPE_SH7300)
151 .long do_IRQ ! 64 200 .long do_IRQ ! 64
152 .long do_IRQ ! 65 201 .long do_IRQ ! 65
@@ -195,4 +244,3 @@ ENTRY(interrupt_table)
195 .long do_IRQ ! 108 244 .long do_IRQ ! 108
196#endif 245#endif
197#endif 246#endif
198
diff --git a/arch/sh/kernel/cpu/sh3/probe.c b/arch/sh/kernel/cpu/sh3/probe.c
index 5cdc88638601..e67098836290 100644
--- a/arch/sh/kernel/cpu/sh3/probe.c
+++ b/arch/sh/kernel/cpu/sh3/probe.c
@@ -72,6 +72,12 @@ int __init detect_cpu_and_cache_system(void)
72 cpu_data->dcache.sets = 256; 72 cpu_data->dcache.sets = 256;
73 cpu_data->type = CPU_SH7729; 73 cpu_data->type = CPU_SH7729;
74 74
75#if defined(CONFIG_CPU_SUBTYPE_SH7706)
76 cpu_data->type = CPU_SH7706;
77#endif
78#if defined(CONFIG_CPU_SUBTYPE_SH7710)
79 cpu_data->type = CPU_SH7710;
80#endif
75#if defined(CONFIG_CPU_SUBTYPE_SH7705) 81#if defined(CONFIG_CPU_SUBTYPE_SH7705)
76 cpu_data->type = CPU_SH7705; 82 cpu_data->type = CPU_SH7705;
77 83
diff --git a/arch/sh/kernel/cpu/sh3/setup-sh7300.c b/arch/sh/kernel/cpu/sh3/setup-sh7300.c
new file mode 100644
index 000000000000..ab4d204bfba5
--- /dev/null
+++ b/arch/sh/kernel/cpu/sh3/setup-sh7300.c
@@ -0,0 +1,43 @@
1/*
2 * SH7300 Setup
3 *
4 * Copyright (C) 2006 Paul Mundt
5 *
6 * This file is subject to the terms and conditions of the GNU General Public
7 * License. See the file "COPYING" in the main directory of this archive
8 * for more details.
9 */
10#include <linux/platform_device.h>
11#include <linux/init.h>
12#include <linux/serial.h>
13#include <asm/sci.h>
14
15static struct plat_sci_port sci_platform_data[] = {
16 {
17 .mapbase = 0xa4430000,
18 .flags = UPF_BOOT_AUTOCONF,
19 .type = PORT_SCI,
20 .irqs = { 80, 80, 80, 80 },
21 }, {
22 .flags = 0,
23 }
24};
25
26static struct platform_device sci_device = {
27 .name = "sh-sci",
28 .id = -1,
29 .dev = {
30 .platform_data = sci_platform_data,
31 },
32};
33
34static struct platform_device *sh7300_devices[] __initdata = {
35 &sci_device,
36};
37
38static int __init sh7300_devices_setup(void)
39{
40 return platform_add_devices(sh7300_devices,
41 ARRAY_SIZE(sh7300_devices));
42}
43__initcall(sh7300_devices_setup);
diff --git a/arch/sh/kernel/cpu/sh3/setup-sh7705.c b/arch/sh/kernel/cpu/sh3/setup-sh7705.c
new file mode 100644
index 000000000000..a8e41c5241fa
--- /dev/null
+++ b/arch/sh/kernel/cpu/sh3/setup-sh7705.c
@@ -0,0 +1,48 @@
1/*
2 * SH7705 Setup
3 *
4 * Copyright (C) 2006 Paul Mundt
5 *
6 * This file is subject to the terms and conditions of the GNU General Public
7 * License. See the file "COPYING" in the main directory of this archive
8 * for more details.
9 */
10#include <linux/platform_device.h>
11#include <linux/init.h>
12#include <linux/serial.h>
13#include <asm/sci.h>
14
15static struct plat_sci_port sci_platform_data[] = {
16 {
17 .mapbase = 0xa4400000,
18 .flags = UPF_BOOT_AUTOCONF,
19 .type = PORT_SCIF,
20 .irqs = { 52, 53, 55, 54 },
21 }, {
22 .mapbase = 0xa4410000,
23 .flags = UPF_BOOT_AUTOCONF,
24 .type = PORT_SCIF,
25 .irqs = { 56, 57, 59, 58 },
26 }, {
27 .flags = 0,
28 }
29};
30
31static struct platform_device sci_device = {
32 .name = "sh-sci",
33 .id = -1,
34 .dev = {
35 .platform_data = sci_platform_data,
36 },
37};
38
39static struct platform_device *sh7705_devices[] __initdata = {
40 &sci_device,
41};
42
43static int __init sh7705_devices_setup(void)
44{
45 return platform_add_devices(sh7705_devices,
46 ARRAY_SIZE(sh7705_devices));
47}
48__initcall(sh7705_devices_setup);
diff --git a/arch/sh/kernel/cpu/sh3/setup-sh7708.c b/arch/sh/kernel/cpu/sh3/setup-sh7708.c
new file mode 100644
index 000000000000..f933723911ca
--- /dev/null
+++ b/arch/sh/kernel/cpu/sh3/setup-sh7708.c
@@ -0,0 +1,43 @@
1/*
2 * SH7708 Setup
3 *
4 * Copyright (C) 2006 Paul Mundt
5 *
6 * This file is subject to the terms and conditions of the GNU General Public
7 * License. See the file "COPYING" in the main directory of this archive
8 * for more details.
9 */
10#include <linux/platform_device.h>
11#include <linux/init.h>
12#include <linux/serial.h>
13#include <asm/sci.h>
14
15static struct plat_sci_port sci_platform_data[] = {
16 {
17 .mapbase = 0xfffffe80,
18 .flags = UPF_BOOT_AUTOCONF,
19 .type = PORT_SCI,
20 .irqs = { 23, 24, 25, 0 },
21 }, {
22 .flags = 0,
23 }
24};
25
26static struct platform_device sci_device = {
27 .name = "sh-sci",
28 .id = -1,
29 .dev = {
30 .platform_data = sci_platform_data,
31 },
32};
33
34static struct platform_device *sh7708_devices[] __initdata = {
35 &sci_device,
36};
37
38static int __init sh7708_devices_setup(void)
39{
40 return platform_add_devices(sh7708_devices,
41 ARRAY_SIZE(sh7708_devices));
42}
43__initcall(sh7708_devices_setup);
diff --git a/arch/sh/kernel/cpu/sh3/setup-sh7709.c b/arch/sh/kernel/cpu/sh3/setup-sh7709.c
new file mode 100644
index 000000000000..ff43ef2a1f0c
--- /dev/null
+++ b/arch/sh/kernel/cpu/sh3/setup-sh7709.c
@@ -0,0 +1,53 @@
1/*
2 * SH7707/SH7709 Setup
3 *
4 * Copyright (C) 2006 Paul Mundt
5 *
6 * This file is subject to the terms and conditions of the GNU General Public
7 * License. See the file "COPYING" in the main directory of this archive
8 * for more details.
9 */
10#include <linux/platform_device.h>
11#include <linux/init.h>
12#include <linux/serial.h>
13#include <asm/sci.h>
14
15static struct plat_sci_port sci_platform_data[] = {
16 {
17 .mapbase = 0xfffffe80,
18 .flags = UPF_BOOT_AUTOCONF,
19 .type = PORT_SCI,
20 .irqs = { 23, 24, 25, 0 },
21 }, {
22 .mapbase = 0xa4000150,
23 .flags = UPF_BOOT_AUTOCONF,
24 .type = PORT_SCIF,
25 .irqs = { 56, 57, 59, 58 },
26 }, {
27 .mapbase = 0xa4000140,
28 .flags = UPF_BOOT_AUTOCONF,
29 .type = PORT_IRDA,
30 .irqs = { 52, 53, 55, 54 },
31 }, {
32 .flags = 0,
33 }
34};
35
36static struct platform_device sci_device = {
37 .name = "sh-sci",
38 .id = -1,
39 .dev = {
40 .platform_data = sci_platform_data,
41 },
42};
43
44static struct platform_device *sh7709_devices[] __initdata = {
45 &sci_device,
46};
47
48static int __init sh7709_devices_setup(void)
49{
50 return platform_add_devices(sh7709_devices,
51 ARRAY_SIZE(sh7709_devices));
52}
53__initcall(sh7709_devices_setup);
diff --git a/arch/sh/kernel/cpu/sh3/setup-sh7710.c b/arch/sh/kernel/cpu/sh3/setup-sh7710.c
new file mode 100644
index 000000000000..895f99ee6a95
--- /dev/null
+++ b/arch/sh/kernel/cpu/sh3/setup-sh7710.c
@@ -0,0 +1,43 @@
1/*
2 * SH7710 Setup
3 *
4 * Copyright (C) 2006 Paul Mundt
5 *
6 * This file is subject to the terms and conditions of the GNU General Public
7 * License. See the file "COPYING" in the main directory of this archive
8 * for more details.
9 */
10#include <linux/platform_device.h>
11#include <linux/init.h>
12#include <linux/serial.h>
13#include <asm/sci.h>
14
15static struct plat_sci_port sci_platform_data[] = {
16 {
17 .mapbase = 0xa4400000,
18 .flags = UPF_BOOT_AUTOCONF,
19 .type = PORT_SCIF,
20 .irqs = { 52, 53, 55, 54 },
21 }, {
22 .flags = 0,
23 }
24};
25
26static struct platform_device sci_device = {
27 .name = "sh-sci",
28 .id = -1,
29 .dev = {
30 .platform_data = sci_platform_data,
31 },
32};
33
34static struct platform_device *sh7710_devices[] __initdata = {
35 &sci_device,
36};
37
38static int __init sh7710_devices_setup(void)
39{
40 return platform_add_devices(sh7710_devices,
41 ARRAY_SIZE(sh7710_devices));
42}
43__initcall(sh7710_devices_setup);
diff --git a/arch/sh/kernel/cpu/sh4/Makefile b/arch/sh/kernel/cpu/sh4/Makefile
index 3d5cafc71ae3..8dbf3895ece7 100644
--- a/arch/sh/kernel/cpu/sh4/Makefile
+++ b/arch/sh/kernel/cpu/sh4/Makefile
@@ -7,6 +7,16 @@ obj-y := ex.o probe.o
7obj-$(CONFIG_SH_FPU) += fpu.o 7obj-$(CONFIG_SH_FPU) += fpu.o
8obj-$(CONFIG_SH_STORE_QUEUES) += sq.o 8obj-$(CONFIG_SH_STORE_QUEUES) += sq.o
9 9
10# CPU subtype setup
11obj-$(CONFIG_CPU_SUBTYPE_SH7750) += setup-sh7750.o
12obj-$(CONFIG_CPU_SUBTYPE_SH7751) += setup-sh7750.o
13obj-$(CONFIG_CPU_SUBTYPE_SH7760) += setup-sh7760.o
14obj-$(CONFIG_CPU_SUBTYPE_SH7770) += setup-sh7770.o
15obj-$(CONFIG_CPU_SUBTYPE_SH7780) += setup-sh7780.o
16obj-$(CONFIG_CPU_SUBTYPE_SH73180) += setup-sh73180.o
17obj-$(CONFIG_CPU_SUBTYPE_SH7343) += setup-sh7343.o
18obj-$(CONFIG_CPU_SUBTYPE_SH4_202) += setup-sh4-202.o
19
10# Primary on-chip clocks (common) 20# Primary on-chip clocks (common)
11clock-$(CONFIG_CPU_SH4) := clock-sh4.o 21clock-$(CONFIG_CPU_SH4) := clock-sh4.o
12clock-$(CONFIG_CPU_SUBTYPE_SH73180) := clock-sh73180.o 22clock-$(CONFIG_CPU_SUBTYPE_SH73180) := clock-sh73180.o
diff --git a/arch/sh/kernel/cpu/sh4/ex.S b/arch/sh/kernel/cpu/sh4/ex.S
index 26a27df06505..7146893a6cca 100644
--- a/arch/sh/kernel/cpu/sh4/ex.S
+++ b/arch/sh/kernel/cpu/sh4/ex.S
@@ -72,6 +72,7 @@ ENTRY(interrupt_table)
72 .long do_IRQ ! 1110 72 .long do_IRQ ! 1110
73 .long exception_error 73 .long exception_error
74 ! Internal hardware 74 ! Internal hardware
75#ifndef CONFIG_CPU_SUBTYPE_SH7780
75 .long do_IRQ ! TMU0 tuni0 /* 400 */ 76 .long do_IRQ ! TMU0 tuni0 /* 400 */
76 .long do_IRQ ! TMU1 tuni1 77 .long do_IRQ ! TMU1 tuni1
77 .long do_IRQ ! TMU2 tuni2 78 .long do_IRQ ! TMU2 tuni2
@@ -122,6 +123,13 @@ ENTRY(interrupt_table)
122 .long do_IRQ ! 45 dmte5 123 .long do_IRQ ! 45 dmte5
123 .long do_IRQ ! 46 dmte6 124 .long do_IRQ ! 46 dmte6
124 .long do_IRQ ! 47 dmte7 /* 7E0 */ 125 .long do_IRQ ! 47 dmte7 /* 7E0 */
126#elif defined(CONFIG_CPU_SUBTYPE_SH7343)
127 .long do_IRQ ! 44 IIC1 ali /* 780 */
128 .long do_IRQ ! 45 tacki
129 .long do_IRQ ! 46 waiti
130 .long do_IRQ ! 47 dtei /* 7E0 */
131 .long do_IRQ ! 48 DMAC dei0 /* 800 */
132 .long do_IRQ ! 49 dei1 /* 820 */
125#else 133#else
126 .long exception_error ! 44 /* 780 */ 134 .long exception_error ! 44 /* 780 */
127 .long exception_error ! 45 135 .long exception_error ! 45
@@ -131,7 +139,8 @@ ENTRY(interrupt_table)
131#if defined(CONFIG_SH_FPU) 139#if defined(CONFIG_SH_FPU)
132 .long do_fpu_state_restore ! 48 /* 800 */ 140 .long do_fpu_state_restore ! 48 /* 800 */
133 .long do_fpu_state_restore ! 49 /* 820 */ 141 .long do_fpu_state_restore ! 49 /* 820 */
134#else 142#elif !defined(CONFIG_CPU_SUBTYPE_SH7343) && \
143 !defined(CONFIG_CPU_SUBTYPE_SH73180)
135 .long exception_error 144 .long exception_error
136 .long exception_error 145 .long exception_error
137#endif 146#endif
@@ -224,7 +233,7 @@ ENTRY(interrupt_table)
224 .long exception_error 233 .long exception_error
225 .long do_IRQ ! ADC adi 234 .long do_IRQ ! ADC adi
226 .long do_IRQ ! CMT cmti /* FA0 */ 235 .long do_IRQ ! CMT cmti /* FA0 */
227#elif defined(CONFIG_CPU_SUBTYPE_SH73180) 236#elif defined(CONFIG_CPU_SUBTYPE_SH73180) || defined(CONFIG_CPU_SUBTYPE_SH7343)
228 .long do_IRQ ! 50 0x840 237 .long do_IRQ ! 50 0x840
229 .long do_IRQ ! 51 0x860 238 .long do_IRQ ! 51 0x860
230 .long do_IRQ ! 52 0x880 239 .long do_IRQ ! 52 0x880
@@ -379,5 +388,168 @@ ENTRY(interrupt_table)
379 .long exception_error ! 141 0x13a0 388 .long exception_error ! 141 0x13a0
380 .long exception_error ! 142 0x13c0 389 .long exception_error ! 142 0x13c0
381 .long exception_error ! 143 0x13e0 390 .long exception_error ! 143 0x13e0
391#elif defined(CONFIG_CPU_SUBTYPE_SH7770)
392 .long do_IRQ ! 50 0x840
393 .long do_IRQ ! 51 0x860
394 .long do_IRQ ! 52 0x880
395 .long do_IRQ ! 53 0x8a0
396 .long do_IRQ ! 54 0x8c0
397 .long do_IRQ ! 55 0x8e0
398 .long do_IRQ ! 56 0x900
399 .long do_IRQ ! 57 0x920
400 .long do_IRQ ! 58 0x940
401 .long do_IRQ ! 59 0x960
402 .long do_IRQ ! 60 0x980
403 .long do_IRQ ! 61 0x9a0
404 .long do_IRQ ! 62 0x9c0
405 .long do_IRQ ! 63 0x9e0
406 .long do_IRQ ! 64 0xa00
407 .long do_IRQ ! 65 0xa20
408 .long do_IRQ ! 66 0xa4d
409 .long do_IRQ ! 67 0xa60
410 .long do_IRQ ! 68 0xa80
411 .long do_IRQ ! 69 0xaa0
412 .long do_IRQ ! 70 0xac0
413 .long do_IRQ ! 71 0xae0
414 .long do_IRQ ! 72 0xb00
415 .long do_IRQ ! 73 0xb20
416 .long do_IRQ ! 74 0xb40
417 .long do_IRQ ! 75 0xb60
418 .long do_IRQ ! 76 0xb80
419 .long do_IRQ ! 77 0xba0
420 .long do_IRQ ! 78 0xbc0
421 .long do_IRQ ! 79 0xbe0
422 .long do_IRQ ! 80 0xc00
423 .long do_IRQ ! 81 0xc20
424 .long do_IRQ ! 82 0xc40
425 .long do_IRQ ! 83 0xc60
426 .long do_IRQ ! 84 0xc80
427 .long do_IRQ ! 85 0xca0
428 .long do_IRQ ! 86 0xcc0
429 .long do_IRQ ! 87 0xce0
430 .long do_IRQ ! 88 0xd00
431 .long do_IRQ ! 89 0xd20
432 .long do_IRQ ! 90 0xd40
433 .long do_IRQ ! 91 0xd60
434 .long do_IRQ ! 92 0xd80
435 .long do_IRQ ! 93 0xda0
436 .long do_IRQ ! 94 0xdc0
437 .long do_IRQ ! 95 0xde0
438 .long do_IRQ ! 96 0xe00
439 .long do_IRQ ! 97 0xe20
440 .long do_IRQ ! 98 0xe40
441 .long do_IRQ ! 99 0xe60
442 .long do_IRQ ! 100 0xe80
443 .long do_IRQ ! 101 0xea0
444 .long do_IRQ ! 102 0xec0
445 .long do_IRQ ! 103 0xee0
446 .long do_IRQ ! 104 0xf00
447 .long do_IRQ ! 105 0xf20
448 .long do_IRQ ! 106 0xf40
449 .long do_IRQ ! 107 0xf60
450 .long do_IRQ ! 108 0xf80
451#endif
452#else
453 .long exception_error /* 400 */
454 .long exception_error
455 .long exception_error
456 .long exception_error
457 .long do_IRQ ! RTC ati
458 .long do_IRQ ! pri
459 .long do_IRQ ! cui
460 .long exception_error
461 .long exception_error /* 500 */
462 .long exception_error
463 .long exception_error
464 .long do_IRQ ! WDT iti /* 560 */
465 .long do_IRQ ! TMU-ch0
466 .long do_IRQ ! TMU-ch1
467 .long do_IRQ ! TMU-ch2
468 .long do_IRQ ! ticpi2 /* 5E0 */
469 .long do_IRQ ! 32 Hitachi UDI /* 600 */
470 .long exception_error
471 .long do_IRQ ! 34 DMAC dmte0
472 .long do_IRQ ! 35 dmte1
473 .long do_IRQ ! 36 dmte2
474 .long do_IRQ ! 37 dmte3
475 .long do_IRQ ! 38 dmae
476 .long exception_error ! 39 /* 6E0 */
477 .long do_IRQ ! 40 SCIF-ch0 eri /* 700 */
478 .long do_IRQ ! 41 rxi
479 .long do_IRQ ! 42 bri
480 .long do_IRQ ! 43 txi
481 .long do_IRQ ! 44 DMAC dmte4 /* 780 */
482 .long do_IRQ ! 45 dmte5
483 .long do_IRQ ! 46 dmte6
484 .long do_IRQ ! 47 dmte7 /* 7E0 */
485#if defined(CONFIG_SH_FPU)
486 .long do_fpu_state_restore ! 48 /* 800 */
487 .long do_fpu_state_restore ! 49 /* 820 */
488#else
489 .long exception_error
490 .long exception_error
491#endif
492 .long exception_error /* 840 */
493 .long exception_error
494 .long exception_error
495 .long exception_error
496 .long exception_error
497 .long exception_error
498 .long do_IRQ ! 56 CMT /* 900 */
499 .long exception_error
500 .long exception_error
501 .long exception_error
502 .long do_IRQ ! 60 HAC
503 .long exception_error
504 .long exception_error
505 .long exception_error
506 .long do_IRQ ! PCI serr /* A00 */
507 .long do_IRQ ! INTA
508 .long do_IRQ ! INTB
509 .long do_IRQ ! INTC
510 .long do_IRQ ! INTD
511 .long do_IRQ ! err
512 .long do_IRQ ! pwd3
513 .long do_IRQ ! pwd2
514 .long do_IRQ ! pwd1 /* B00 */
515 .long do_IRQ ! pwd0
516 .long exception_error
517 .long exception_error
518 .long do_IRQ ! SCIF-ch1 eri /* B80 */
519 .long do_IRQ ! rxi
520 .long do_IRQ ! bri
521 .long do_IRQ ! txi
522 .long do_IRQ ! SIOF /* C00 */
523 .long exception_error
524 .long exception_error
525 .long exception_error
526 .long do_IRQ ! HSPI /* C80 */
527 .long exception_error
528 .long exception_error
529 .long exception_error
530 .long do_IRQ ! MMCIF fatat /* D00 */
531 .long do_IRQ ! tran
532 .long do_IRQ ! err
533 .long do_IRQ ! frdy
534 .long do_IRQ ! DMAC dmint8 /* D80 */
535 .long do_IRQ ! dmint9
536 .long do_IRQ ! dmint10
537 .long do_IRQ ! dmint11
538 .long do_IRQ ! TMU-ch3 /* E00 */
539 .long do_IRQ ! TMU-ch4
540 .long do_IRQ ! TMU-ch5
541 .long exception_error
542 .long do_IRQ ! SSI
543 .long exception_error
544 .long exception_error
545 .long exception_error
546 .long do_IRQ ! FLCTL flste /* F00 */
547 .long do_IRQ ! fltend
548 .long do_IRQ ! fltrq0
549 .long do_IRQ ! fltrq1
550 .long do_IRQ ! GPIO gpioi0 /* F80 */
551 .long do_IRQ ! gpioi1
552 .long do_IRQ ! gpioi2
553 .long do_IRQ ! gpioi3
382#endif 554#endif
383 555
diff --git a/arch/sh/kernel/cpu/sh4/probe.c b/arch/sh/kernel/cpu/sh4/probe.c
index 42427b79697b..c294de1e14a3 100644
--- a/arch/sh/kernel/cpu/sh4/probe.c
+++ b/arch/sh/kernel/cpu/sh4/probe.c
@@ -3,7 +3,7 @@
3 * 3 *
4 * CPU Subtype Probing for SH-4. 4 * CPU Subtype Probing for SH-4.
5 * 5 *
6 * Copyright (C) 2001, 2002, 2003, 2004 Paul Mundt 6 * Copyright (C) 2001 - 2006 Paul Mundt
7 * Copyright (C) 2003 Richard Curnow 7 * Copyright (C) 2003 Richard Curnow
8 * 8 *
9 * This file is subject to the terms and conditions of the GNU General Public 9 * This file is subject to the terms and conditions of the GNU General Public
@@ -29,7 +29,7 @@ int __init detect_cpu_and_cache_system(void)
29 [9] = (1 << 16) 29 [9] = (1 << 16)
30 }; 30 };
31 31
32 pvr = (ctrl_inl(CCN_PVR) >> 8) & 0xffff; 32 pvr = (ctrl_inl(CCN_PVR) >> 8) & 0xffffff;
33 prr = (ctrl_inl(CCN_PRR) >> 4) & 0xff; 33 prr = (ctrl_inl(CCN_PRR) >> 4) & 0xff;
34 cvr = (ctrl_inl(CCN_CVR)); 34 cvr = (ctrl_inl(CCN_CVR));
35 35
@@ -38,7 +38,6 @@ int __init detect_cpu_and_cache_system(void)
38 */ 38 */
39 cpu_data->icache.way_incr = (1 << 13); 39 cpu_data->icache.way_incr = (1 << 13);
40 cpu_data->icache.entry_shift = 5; 40 cpu_data->icache.entry_shift = 5;
41 cpu_data->icache.entry_mask = 0x1fe0;
42 cpu_data->icache.sets = 256; 41 cpu_data->icache.sets = 256;
43 cpu_data->icache.ways = 1; 42 cpu_data->icache.ways = 1;
44 cpu_data->icache.linesz = L1_CACHE_BYTES; 43 cpu_data->icache.linesz = L1_CACHE_BYTES;
@@ -48,13 +47,29 @@ int __init detect_cpu_and_cache_system(void)
48 */ 47 */
49 cpu_data->dcache.way_incr = (1 << 14); 48 cpu_data->dcache.way_incr = (1 << 14);
50 cpu_data->dcache.entry_shift = 5; 49 cpu_data->dcache.entry_shift = 5;
51 cpu_data->dcache.entry_mask = 0x3fe0;
52 cpu_data->dcache.sets = 512; 50 cpu_data->dcache.sets = 512;
53 cpu_data->dcache.ways = 1; 51 cpu_data->dcache.ways = 1;
54 cpu_data->dcache.linesz = L1_CACHE_BYTES; 52 cpu_data->dcache.linesz = L1_CACHE_BYTES;
55 53
56 /* Set the FPU flag, virtually all SH-4's have one */ 54 /*
57 cpu_data->flags |= CPU_HAS_FPU; 55 * Setup some generic flags we can probe
56 * (L2 and DSP detection only work on SH-4A)
57 */
58 if (((pvr >> 16) & 0xff) == 0x10) {
59 if ((cvr & 0x02000000) == 0)
60 cpu_data->flags |= CPU_HAS_L2_CACHE;
61 if ((cvr & 0x10000000) == 0)
62 cpu_data->flags |= CPU_HAS_DSP;
63
64 cpu_data->flags |= CPU_HAS_LLSC;
65 }
66
67 /* FPU detection works for everyone */
68 if ((cvr & 0x20000000) == 1)
69 cpu_data->flags |= CPU_HAS_FPU;
70
71 /* Mask off the upper chip ID */
72 pvr &= 0xffff;
58 73
59 /* 74 /*
60 * Probe the underlying processor version/revision and 75 * Probe the underlying processor version/revision and
@@ -63,56 +78,101 @@ int __init detect_cpu_and_cache_system(void)
63 switch (pvr) { 78 switch (pvr) {
64 case 0x205: 79 case 0x205:
65 cpu_data->type = CPU_SH7750; 80 cpu_data->type = CPU_SH7750;
66 cpu_data->flags |= CPU_HAS_P2_FLUSH_BUG | CPU_HAS_PERF_COUNTER; 81 cpu_data->flags |= CPU_HAS_P2_FLUSH_BUG | CPU_HAS_FPU |
82 CPU_HAS_PERF_COUNTER | CPU_HAS_PTEA;
67 break; 83 break;
68 case 0x206: 84 case 0x206:
69 cpu_data->type = CPU_SH7750S; 85 cpu_data->type = CPU_SH7750S;
70 cpu_data->flags |= CPU_HAS_P2_FLUSH_BUG | CPU_HAS_PERF_COUNTER; 86 cpu_data->flags |= CPU_HAS_P2_FLUSH_BUG | CPU_HAS_FPU |
87 CPU_HAS_PERF_COUNTER | CPU_HAS_PTEA;
71 break; 88 break;
72 case 0x1100: 89 case 0x1100:
73 cpu_data->type = CPU_SH7751; 90 cpu_data->type = CPU_SH7751;
91 cpu_data->flags |= CPU_HAS_FPU | CPU_HAS_PTEA;
74 break; 92 break;
75 case 0x2000: 93 case 0x2000:
76 cpu_data->type = CPU_SH73180; 94 cpu_data->type = CPU_SH73180;
77 cpu_data->icache.ways = 4; 95 cpu_data->icache.ways = 4;
78 cpu_data->dcache.ways = 4; 96 cpu_data->dcache.ways = 4;
79 cpu_data->flags &= ~CPU_HAS_FPU; 97 cpu_data->flags |= CPU_HAS_LLSC;
98 break;
99 case 0x2001:
100 case 0x2004:
101 cpu_data->type = CPU_SH7770;
102 cpu_data->icache.ways = 4;
103 cpu_data->dcache.ways = 4;
104
105 cpu_data->flags |= CPU_HAS_FPU | CPU_HAS_LLSC;
106 break;
107 case 0x2006:
108 case 0x200A:
109 if (prr == 0x61)
110 cpu_data->type = CPU_SH7781;
111 else
112 cpu_data->type = CPU_SH7780;
113
114 cpu_data->icache.ways = 4;
115 cpu_data->dcache.ways = 4;
116
117 cpu_data->flags |= CPU_HAS_FPU | CPU_HAS_PERF_COUNTER |
118 CPU_HAS_LLSC;
119 break;
120 case 0x3000:
121 case 0x3003:
122 cpu_data->type = CPU_SH7343;
123 cpu_data->icache.ways = 4;
124 cpu_data->dcache.ways = 4;
125 cpu_data->flags |= CPU_HAS_LLSC;
80 break; 126 break;
81 case 0x8000: 127 case 0x8000:
82 cpu_data->type = CPU_ST40RA; 128 cpu_data->type = CPU_ST40RA;
129 cpu_data->flags |= CPU_HAS_FPU | CPU_HAS_PTEA;
83 break; 130 break;
84 case 0x8100: 131 case 0x8100:
85 cpu_data->type = CPU_ST40GX1; 132 cpu_data->type = CPU_ST40GX1;
133 cpu_data->flags |= CPU_HAS_FPU | CPU_HAS_PTEA;
86 break; 134 break;
87 case 0x700: 135 case 0x700:
88 cpu_data->type = CPU_SH4_501; 136 cpu_data->type = CPU_SH4_501;
89 cpu_data->icache.ways = 2; 137 cpu_data->icache.ways = 2;
90 cpu_data->dcache.ways = 2; 138 cpu_data->dcache.ways = 2;
91 139 cpu_data->flags |= CPU_HAS_PTEA;
92 /* No FPU on the SH4-500 series.. */
93 cpu_data->flags &= ~CPU_HAS_FPU;
94 break; 140 break;
95 case 0x600: 141 case 0x600:
96 cpu_data->type = CPU_SH4_202; 142 cpu_data->type = CPU_SH4_202;
97 cpu_data->icache.ways = 2; 143 cpu_data->icache.ways = 2;
98 cpu_data->dcache.ways = 2; 144 cpu_data->dcache.ways = 2;
145 cpu_data->flags |= CPU_HAS_FPU | CPU_HAS_PTEA;
99 break; 146 break;
100 case 0x500 ... 0x501: 147 case 0x500 ... 0x501:
101 switch (prr) { 148 switch (prr) {
102 case 0x10: cpu_data->type = CPU_SH7750R; break; 149 case 0x10:
103 case 0x11: cpu_data->type = CPU_SH7751R; break; 150 cpu_data->type = CPU_SH7750R;
104 case 0x50: cpu_data->type = CPU_SH7760; break; 151 break;
152 case 0x11:
153 cpu_data->type = CPU_SH7751R;
154 break;
155 case 0x50 ... 0x5f:
156 cpu_data->type = CPU_SH7760;
157 break;
105 } 158 }
106 159
107 cpu_data->icache.ways = 2; 160 cpu_data->icache.ways = 2;
108 cpu_data->dcache.ways = 2; 161 cpu_data->dcache.ways = 2;
109 162
163 cpu_data->flags |= CPU_HAS_FPU | CPU_HAS_PTEA;
164
110 break; 165 break;
111 default: 166 default:
112 cpu_data->type = CPU_SH_NONE; 167 cpu_data->type = CPU_SH_NONE;
113 break; 168 break;
114 } 169 }
115 170
171#ifdef CONFIG_SH_DIRECT_MAPPED
172 cpu_data->icache.ways = 1;
173 cpu_data->dcache.ways = 1;
174#endif
175
116 /* 176 /*
117 * On anything that's not a direct-mapped cache, look to the CVR 177 * On anything that's not a direct-mapped cache, look to the CVR
118 * for I/D-cache specifics. 178 * for I/D-cache specifics.
@@ -121,18 +181,56 @@ int __init detect_cpu_and_cache_system(void)
121 size = sizes[(cvr >> 20) & 0xf]; 181 size = sizes[(cvr >> 20) & 0xf];
122 cpu_data->icache.way_incr = (size >> 1); 182 cpu_data->icache.way_incr = (size >> 1);
123 cpu_data->icache.sets = (size >> 6); 183 cpu_data->icache.sets = (size >> 6);
124 cpu_data->icache.entry_mask = 184
125 (cpu_data->icache.way_incr - (1 << 5));
126 } 185 }
127 186
187 /* Setup the rest of the I-cache info */
188 cpu_data->icache.entry_mask = cpu_data->icache.way_incr -
189 cpu_data->icache.linesz;
190
191 cpu_data->icache.way_size = cpu_data->icache.sets *
192 cpu_data->icache.linesz;
193
194 /* And the rest of the D-cache */
128 if (cpu_data->dcache.ways > 1) { 195 if (cpu_data->dcache.ways > 1) {
129 size = sizes[(cvr >> 16) & 0xf]; 196 size = sizes[(cvr >> 16) & 0xf];
130 cpu_data->dcache.way_incr = (size >> 1); 197 cpu_data->dcache.way_incr = (size >> 1);
131 cpu_data->dcache.sets = (size >> 6); 198 cpu_data->dcache.sets = (size >> 6);
132 cpu_data->dcache.entry_mask = 199 }
133 (cpu_data->dcache.way_incr - (1 << 5)); 200
201 cpu_data->dcache.entry_mask = cpu_data->dcache.way_incr -
202 cpu_data->dcache.linesz;
203
204 cpu_data->dcache.way_size = cpu_data->dcache.sets *
205 cpu_data->dcache.linesz;
206
207 /*
208 * Setup the L2 cache desc
209 *
210 * SH-4A's have an optional PIPT L2.
211 */
212 if (cpu_data->flags & CPU_HAS_L2_CACHE) {
213 /*
214 * Size calculation is much more sensible
215 * than it is for the L1.
216 *
217 * Sizes are 128KB, 258KB, 512KB, and 1MB.
218 */
219 size = (cvr & 0xf) << 17;
220
221 BUG_ON(!size);
222
223 cpu_data->scache.way_incr = (1 << 16);
224 cpu_data->scache.entry_shift = 5;
225 cpu_data->scache.ways = 4;
226 cpu_data->scache.linesz = L1_CACHE_BYTES;
227 cpu_data->scache.entry_mask =
228 (cpu_data->scache.way_incr - cpu_data->scache.linesz);
229 cpu_data->scache.sets = size /
230 (cpu_data->scache.linesz * cpu_data->scache.ways);
231 cpu_data->scache.way_size =
232 (cpu_data->scache.sets * cpu_data->scache.linesz);
134 } 233 }
135 234
136 return 0; 235 return 0;
137} 236}
138
diff --git a/arch/sh/kernel/cpu/sh4/setup-sh4-202.c b/arch/sh/kernel/cpu/sh4/setup-sh4-202.c
new file mode 100644
index 000000000000..6e4e96541358
--- /dev/null
+++ b/arch/sh/kernel/cpu/sh4/setup-sh4-202.c
@@ -0,0 +1,43 @@
1/*
2 * SH4-202 Setup
3 *
4 * Copyright (C) 2006 Paul Mundt
5 *
6 * This file is subject to the terms and conditions of the GNU General Public
7 * License. See the file "COPYING" in the main directory of this archive
8 * for more details.
9 */
10#include <linux/platform_device.h>
11#include <linux/init.h>
12#include <linux/serial.h>
13#include <asm/sci.h>
14
15static struct plat_sci_port sci_platform_data[] = {
16 {
17 .mapbase = 0xffe80000,
18 .flags = UPF_BOOT_AUTOCONF,
19 .type = PORT_SCIF,
20 .irqs = { 40, 41, 43, 42 },
21 }, {
22 .flags = 0,
23 }
24};
25
26static struct platform_device sci_device = {
27 .name = "sh-sci",
28 .id = -1,
29 .dev = {
30 .platform_data = sci_platform_data,
31 },
32};
33
34static struct platform_device *sh4202_devices[] __initdata = {
35 &sci_device,
36};
37
38static int __init sh4202_devices_setup(void)
39{
40 return platform_add_devices(sh4202_devices,
41 ARRAY_SIZE(sh4202_devices));
42}
43__initcall(sh4202_devices_setup);
diff --git a/arch/sh/kernel/cpu/sh4/setup-sh73180.c b/arch/sh/kernel/cpu/sh4/setup-sh73180.c
new file mode 100644
index 000000000000..cc9ea1e2e5df
--- /dev/null
+++ b/arch/sh/kernel/cpu/sh4/setup-sh73180.c
@@ -0,0 +1,43 @@
1/*
2 * SH73180 Setup
3 *
4 * Copyright (C) 2006 Paul Mundt
5 *
6 * This file is subject to the terms and conditions of the GNU General Public
7 * License. See the file "COPYING" in the main directory of this archive
8 * for more details.
9 */
10#include <linux/platform_device.h>
11#include <linux/init.h>
12#include <linux/serial.h>
13#include <asm/sci.h>
14
15static struct plat_sci_port sci_platform_data[] = {
16 {
17 .mapbase = 0xffe80000,
18 .flags = UPF_BOOT_AUTOCONF,
19 .type = PORT_SCIF,
20 .irqs = { 80, 81, 83, 82 },
21 }, {
22 .flags = 0,
23 }
24};
25
26static struct platform_device sci_device = {
27 .name = "sh-sci",
28 .id = -1,
29 .dev = {
30 .platform_data = sci_platform_data,
31 },
32};
33
34static struct platform_device *sh73180_devices[] __initdata = {
35 &sci_device,
36};
37
38static int __init sh73180_devices_setup(void)
39{
40 return platform_add_devices(sh73180_devices,
41 ARRAY_SIZE(sh73180_devices));
42}
43__initcall(sh73180_devices_setup);
diff --git a/arch/sh/kernel/cpu/sh4/setup-sh7343.c b/arch/sh/kernel/cpu/sh4/setup-sh7343.c
new file mode 100644
index 000000000000..91d61cf91ba1
--- /dev/null
+++ b/arch/sh/kernel/cpu/sh4/setup-sh7343.c
@@ -0,0 +1,43 @@
1/*
2 * SH7343 Setup
3 *
4 * Copyright (C) 2006 Paul Mundt
5 *
6 * This file is subject to the terms and conditions of the GNU General Public
7 * License. See the file "COPYING" in the main directory of this archive
8 * for more details.
9 */
10#include <linux/platform_device.h>
11#include <linux/init.h>
12#include <linux/serial.h>
13#include <asm/sci.h>
14
15static struct plat_sci_port sci_platform_data[] = {
16 {
17 .mapbase = 0xffe00000,
18 .flags = UPF_BOOT_AUTOCONF,
19 .type = PORT_SCIF,
20 .irqs = { 80, 81, 83, 82 },
21 }, {
22 .flags = 0,
23 }
24};
25
26static struct platform_device sci_device = {
27 .name = "sh-sci",
28 .id = -1,
29 .dev = {
30 .platform_data = sci_platform_data,
31 },
32};
33
34static struct platform_device *sh7343_devices[] __initdata = {
35 &sci_device,
36};
37
38static int __init sh7343_devices_setup(void)
39{
40 return platform_add_devices(sh7343_devices,
41 ARRAY_SIZE(sh7343_devices));
42}
43__initcall(sh7343_devices_setup);
diff --git a/arch/sh/kernel/cpu/sh4/setup-sh7750.c b/arch/sh/kernel/cpu/sh4/setup-sh7750.c
new file mode 100644
index 000000000000..50812d57c1c1
--- /dev/null
+++ b/arch/sh/kernel/cpu/sh4/setup-sh7750.c
@@ -0,0 +1,48 @@
1/*
2 * SH7750/SH7751 Setup
3 *
4 * Copyright (C) 2006 Paul Mundt
5 *
6 * This file is subject to the terms and conditions of the GNU General Public
7 * License. See the file "COPYING" in the main directory of this archive
8 * for more details.
9 */
10#include <linux/platform_device.h>
11#include <linux/init.h>
12#include <linux/serial.h>
13#include <asm/sci.h>
14
15static struct plat_sci_port sci_platform_data[] = {
16 {
17 .mapbase = 0xffe00000,
18 .flags = UPF_BOOT_AUTOCONF,
19 .type = PORT_SCI,
20 .irqs = { 23, 24, 25, 0 },
21 }, {
22 .mapbase = 0xffe80000,
23 .flags = UPF_BOOT_AUTOCONF,
24 .type = PORT_SCIF,
25 .irqs = { 40, 41, 43, 42 },
26 }, {
27 .flags = 0,
28 }
29};
30
31static struct platform_device sci_device = {
32 .name = "sh-sci",
33 .id = -1,
34 .dev = {
35 .platform_data = sci_platform_data,
36 },
37};
38
39static struct platform_device *sh7750_devices[] __initdata = {
40 &sci_device,
41};
42
43static int __init sh7750_devices_setup(void)
44{
45 return platform_add_devices(sh7750_devices,
46 ARRAY_SIZE(sh7750_devices));
47}
48__initcall(sh7750_devices_setup);
diff --git a/arch/sh/kernel/cpu/sh4/setup-sh7760.c b/arch/sh/kernel/cpu/sh4/setup-sh7760.c
new file mode 100644
index 000000000000..97f1c9af35d6
--- /dev/null
+++ b/arch/sh/kernel/cpu/sh4/setup-sh7760.c
@@ -0,0 +1,53 @@
1/*
2 * SH7760 Setup
3 *
4 * Copyright (C) 2006 Paul Mundt
5 *
6 * This file is subject to the terms and conditions of the GNU General Public
7 * License. See the file "COPYING" in the main directory of this archive
8 * for more details.
9 */
10#include <linux/platform_device.h>
11#include <linux/init.h>
12#include <linux/serial.h>
13#include <asm/sci.h>
14
15static struct plat_sci_port sci_platform_data[] = {
16 {
17 .mapbase = 0xfe600000,
18 .flags = UPF_BOOT_AUTOCONF,
19 .type = PORT_SCIF,
20 .irqs = { 52, 53, 55, 54 },
21 }, {
22 .mapbase = 0xfe610000,
23 .flags = UPF_BOOT_AUTOCONF,
24 .type = PORT_SCIF,
25 .irqs = { 72, 73, 75, 74 },
26 }, {
27 .mapbase = 0xfe620000,
28 .flags = UPF_BOOT_AUTOCONF,
29 .type = PORT_SCIF,
30 .irqs = { 76, 77, 79, 78 },
31 }, {
32 .flags = 0,
33 }
34};
35
36static struct platform_device sci_device = {
37 .name = "sh-sci",
38 .id = -1,
39 .dev = {
40 .platform_data = sci_platform_data,
41 },
42};
43
44static struct platform_device *sh7760_devices[] __initdata = {
45 &sci_device,
46};
47
48static int __init sh7760_devices_setup(void)
49{
50 return platform_add_devices(sh7760_devices,
51 ARRAY_SIZE(sh7760_devices));
52}
53__initcall(sh7760_devices_setup);
diff --git a/arch/sh/kernel/cpu/sh4/setup-sh7770.c b/arch/sh/kernel/cpu/sh4/setup-sh7770.c
new file mode 100644
index 000000000000..6a04cc5f5aca
--- /dev/null
+++ b/arch/sh/kernel/cpu/sh4/setup-sh7770.c
@@ -0,0 +1,53 @@
1/*
2 * SH7770 Setup
3 *
4 * Copyright (C) 2006 Paul Mundt
5 *
6 * This file is subject to the terms and conditions of the GNU General Public
7 * License. See the file "COPYING" in the main directory of this archive
8 * for more details.
9 */
10#include <linux/platform_device.h>
11#include <linux/init.h>
12#include <linux/serial.h>
13#include <asm/sci.h>
14
15static struct plat_sci_port sci_platform_data[] = {
16 {
17 .mapbase = 0xff923000,
18 .flags = UPF_BOOT_AUTOCONF,
19 .type = PORT_SCIF,
20 .irqs = { 61, 61, 61, 61 },
21 }, {
22 .mapbase = 0xff924000,
23 .flags = UPF_BOOT_AUTOCONF,
24 .type = PORT_SCIF,
25 .irqs = { 62, 62, 62, 62 },
26 }, {
27 .mapbase = 0xff925000,
28 .flags = UPF_BOOT_AUTOCONF,
29 .type = PORT_SCIF,
30 .irqs = { 63, 63, 63, 63 },
31 }, {
32 .flags = 0,
33 }
34};
35
36static struct platform_device sci_device = {
37 .name = "sh-sci",
38 .id = -1,
39 .dev = {
40 .platform_data = sci_platform_data,
41 },
42};
43
44static struct platform_device *sh7770_devices[] __initdata = {
45 &sci_device,
46};
47
48static int __init sh7770_devices_setup(void)
49{
50 return platform_add_devices(sh7770_devices,
51 ARRAY_SIZE(sh7770_devices));
52}
53__initcall(sh7770_devices_setup);
diff --git a/arch/sh/kernel/cpu/sh4/setup-sh7780.c b/arch/sh/kernel/cpu/sh4/setup-sh7780.c
new file mode 100644
index 000000000000..72493f259edc
--- /dev/null
+++ b/arch/sh/kernel/cpu/sh4/setup-sh7780.c
@@ -0,0 +1,79 @@
1/*
2 * SH7780 Setup
3 *
4 * Copyright (C) 2006 Paul Mundt
5 *
6 * This file is subject to the terms and conditions of the GNU General Public
7 * License. See the file "COPYING" in the main directory of this archive
8 * for more details.
9 */
10#include <linux/platform_device.h>
11#include <linux/init.h>
12#include <linux/serial.h>
13#include <asm/sci.h>
14
15static struct resource rtc_resources[] = {
16 [0] = {
17 .start = 0xffe80000,
18 .end = 0xffe80000 + 0x58 - 1,
19 .flags = IORESOURCE_IO,
20 },
21 [1] = {
22 /* Period IRQ */
23 .start = 21,
24 .flags = IORESOURCE_IRQ,
25 },
26 [2] = {
27 /* Carry IRQ */
28 .start = 22,
29 .flags = IORESOURCE_IRQ,
30 },
31 [3] = {
32 /* Alarm IRQ */
33 .start = 23,
34 .flags = IORESOURCE_IRQ,
35 },
36};
37
38static struct platform_device rtc_device = {
39 .name = "sh-rtc",
40 .id = -1,
41 .num_resources = ARRAY_SIZE(rtc_resources),
42 .resource = rtc_resources,
43};
44
45static struct plat_sci_port sci_platform_data[] = {
46 {
47 .mapbase = 0xffe00000,
48 .flags = UPF_BOOT_AUTOCONF,
49 .type = PORT_SCIF,
50 .irqs = { 40, 41, 43, 42 },
51 }, {
52 .mapbase = 0xffe10000,
53 .flags = UPF_BOOT_AUTOCONF,
54 .type = PORT_SCIF,
55 .irqs = { 76, 77, 79, 78 },
56 }, {
57 .flags = 0,
58 }
59};
60
61static struct platform_device sci_device = {
62 .name = "sh-sci",
63 .id = -1,
64 .dev = {
65 .platform_data = sci_platform_data,
66 },
67};
68
69static struct platform_device *sh7780_devices[] __initdata = {
70 &rtc_device,
71 &sci_device,
72};
73
74static int __init sh7780_devices_setup(void)
75{
76 return platform_add_devices(sh7780_devices,
77 ARRAY_SIZE(sh7780_devices));
78}
79__initcall(sh7780_devices_setup);
diff --git a/arch/sh/kernel/cpu/sh4/sq.c b/arch/sh/kernel/cpu/sh4/sq.c
index b09805f3ee23..7bcc73f9b8df 100644
--- a/arch/sh/kernel/cpu/sh4/sq.c
+++ b/arch/sh/kernel/cpu/sh4/sq.c
@@ -1,49 +1,52 @@
1/* 1/*
2 * arch/sh/kernel/cpu/sq.c 2 * arch/sh/kernel/cpu/sh4/sq.c
3 * 3 *
4 * General management API for SH-4 integrated Store Queues 4 * General management API for SH-4 integrated Store Queues
5 * 5 *
6 * Copyright (C) 2001, 2002, 2003, 2004 Paul Mundt 6 * Copyright (C) 2001 - 2006 Paul Mundt
7 * Copyright (C) 2001, 2002 M. R. Brown 7 * Copyright (C) 2001, 2002 M. R. Brown
8 * 8 *
9 * Some of this code has been adopted directly from the old arch/sh/mm/sq.c
10 * hack that was part of the LinuxDC project. For all intents and purposes,
11 * this is a completely new interface that really doesn't have much in common
12 * with the old zone-based approach at all. In fact, it's only listed here for
13 * general completeness.
14 *
15 * This file is subject to the terms and conditions of the GNU General Public 9 * This file is subject to the terms and conditions of the GNU General Public
16 * License. See the file "COPYING" in the main directory of this archive 10 * License. See the file "COPYING" in the main directory of this archive
17 * for more details. 11 * for more details.
18 */ 12 */
19#include <linux/init.h> 13#include <linux/init.h>
14#include <linux/cpu.h>
15#include <linux/bitmap.h>
16#include <linux/sysdev.h>
20#include <linux/kernel.h> 17#include <linux/kernel.h>
21#include <linux/module.h> 18#include <linux/module.h>
22#include <linux/slab.h> 19#include <linux/slab.h>
23#include <linux/list.h>
24#include <linux/proc_fs.h>
25#include <linux/miscdevice.h>
26#include <linux/vmalloc.h> 20#include <linux/vmalloc.h>
27 21#include <linux/mm.h>
28#include <asm/io.h> 22#include <asm/io.h>
29#include <asm/page.h> 23#include <asm/page.h>
30#include <asm/mmu_context.h> 24#include <asm/cacheflush.h>
31#include <asm/cpu/sq.h> 25#include <asm/cpu/sq.h>
32 26
33static LIST_HEAD(sq_mapping_list); 27struct sq_mapping;
28
29struct sq_mapping {
30 const char *name;
31
32 unsigned long sq_addr;
33 unsigned long addr;
34 unsigned int size;
35
36 struct sq_mapping *next;
37};
38
39static struct sq_mapping *sq_mapping_list;
34static DEFINE_SPINLOCK(sq_mapping_lock); 40static DEFINE_SPINLOCK(sq_mapping_lock);
41static kmem_cache_t *sq_cache;
42static unsigned long *sq_bitmap;
35 43
36/** 44#define store_queue_barrier() \
37 * sq_flush - Flush (prefetch) the store queue cache 45do { \
38 * @addr: the store queue address to flush 46 (void)ctrl_inl(P4SEG_STORE_QUE); \
39 * 47 ctrl_outl(0, P4SEG_STORE_QUE + 0); \
40 * Executes a prefetch instruction on the specified store queue cache, 48 ctrl_outl(0, P4SEG_STORE_QUE + 8); \
41 * so that the cached data is written to physical memory. 49} while (0);
42 */
43inline void sq_flush(void *addr)
44{
45 __asm__ __volatile__ ("pref @%0" : : "r" (addr) : "memory");
46}
47 50
48/** 51/**
49 * sq_flush_range - Flush (prefetch) a specific SQ range 52 * sq_flush_range - Flush (prefetch) a specific SQ range
@@ -56,152 +59,73 @@ inline void sq_flush(void *addr)
56void sq_flush_range(unsigned long start, unsigned int len) 59void sq_flush_range(unsigned long start, unsigned int len)
57{ 60{
58 volatile unsigned long *sq = (unsigned long *)start; 61 volatile unsigned long *sq = (unsigned long *)start;
59 unsigned long dummy;
60 62
61 /* Flush the queues */ 63 /* Flush the queues */
62 for (len >>= 5; len--; sq += 8) 64 for (len >>= 5; len--; sq += 8)
63 sq_flush((void *)sq); 65 prefetchw((void *)sq);
64 66
65 /* Wait for completion */ 67 /* Wait for completion */
66 dummy = ctrl_inl(P4SEG_STORE_QUE); 68 store_queue_barrier();
67
68 ctrl_outl(0, P4SEG_STORE_QUE + 0);
69 ctrl_outl(0, P4SEG_STORE_QUE + 8);
70} 69}
71 70
72static struct sq_mapping *__sq_alloc_mapping(unsigned long virt, unsigned long phys, unsigned long size, const char *name) 71static inline void sq_mapping_list_add(struct sq_mapping *map)
73{ 72{
74 struct sq_mapping *map; 73 struct sq_mapping **p, *tmp;
75
76 if (virt + size > SQ_ADDRMAX)
77 return ERR_PTR(-ENOSPC);
78
79 map = kmalloc(sizeof(struct sq_mapping), GFP_KERNEL);
80 if (!map)
81 return ERR_PTR(-ENOMEM);
82 74
83 INIT_LIST_HEAD(&map->list); 75 spin_lock_irq(&sq_mapping_lock);
84 76
85 map->sq_addr = virt; 77 p = &sq_mapping_list;
86 map->addr = phys; 78 while ((tmp = *p) != NULL)
87 map->size = size + 1; 79 p = &tmp->next;
88 map->name = name;
89 80
90 list_add(&map->list, &sq_mapping_list); 81 map->next = tmp;
82 *p = map;
91 83
92 return map; 84 spin_unlock_irq(&sq_mapping_lock);
93} 85}
94 86
95static unsigned long __sq_get_next_addr(void) 87static inline void sq_mapping_list_del(struct sq_mapping *map)
96{ 88{
97 if (!list_empty(&sq_mapping_list)) { 89 struct sq_mapping **p, *tmp;
98 struct list_head *pos, *tmp; 90
99 91 spin_lock_irq(&sq_mapping_lock);
100 /* 92
101 * Read one off the list head, as it will have the highest 93 for (p = &sq_mapping_list; (tmp = *p); p = &tmp->next)
102 * mapped allocation. Set the next one up right above it. 94 if (tmp == map) {
103 * 95 *p = tmp->next;
104 * This is somewhat sub-optimal, as we don't look at 96 break;
105 * gaps between allocations or anything lower then the
106 * highest-level allocation.
107 *
108 * However, in the interest of performance and the general
109 * lack of desire to do constant list rebalancing, we don't
110 * worry about it.
111 */
112 list_for_each_safe(pos, tmp, &sq_mapping_list) {
113 struct sq_mapping *entry;
114
115 entry = list_entry(pos, typeof(*entry), list);
116
117 return entry->sq_addr + entry->size;
118 } 97 }
119 }
120 98
121 return P4SEG_STORE_QUE; 99 spin_unlock_irq(&sq_mapping_lock);
122} 100}
123 101
124/** 102static int __sq_remap(struct sq_mapping *map, unsigned long flags)
125 * __sq_remap - Perform a translation from the SQ to a phys addr
126 * @map: sq mapping containing phys and store queue addresses.
127 *
128 * Maps the store queue address specified in the mapping to the physical
129 * address specified in the mapping.
130 */
131static struct sq_mapping *__sq_remap(struct sq_mapping *map)
132{ 103{
133 unsigned long flags, pteh, ptel; 104#if defined(CONFIG_MMU)
134 struct vm_struct *vma; 105 struct vm_struct *vma;
135 pgprot_t pgprot;
136
137 /*
138 * Without an MMU (or with it turned off), this is much more
139 * straightforward, as we can just load up each queue's QACR with
140 * the physical address appropriately masked.
141 */
142
143 ctrl_outl(((map->addr >> 26) << 2) & 0x1c, SQ_QACR0);
144 ctrl_outl(((map->addr >> 26) << 2) & 0x1c, SQ_QACR1);
145 106
146#ifdef CONFIG_MMU
147 /*
148 * With an MMU on the other hand, things are slightly more involved.
149 * Namely, we have to have a direct mapping between the SQ addr and
150 * the associated physical address in the UTLB by way of setting up
151 * a virt<->phys translation by hand. We do this by simply specifying
152 * the SQ addr in UTLB.VPN and the associated physical address in
153 * UTLB.PPN.
154 *
155 * Notably, even though this is a special case translation, and some
156 * of the configuration bits are meaningless, we're still required
157 * to have a valid ASID context in PTEH.
158 *
159 * We could also probably get by without explicitly setting PTEA, but
160 * we do it here just for good measure.
161 */
162 spin_lock_irqsave(&sq_mapping_lock, flags);
163
164 pteh = map->sq_addr;
165 ctrl_outl((pteh & MMU_VPN_MASK) | get_asid(), MMU_PTEH);
166
167 ptel = map->addr & PAGE_MASK;
168 ctrl_outl(((ptel >> 28) & 0xe) | (ptel & 0x1), MMU_PTEA);
169
170 pgprot = pgprot_noncached(PAGE_KERNEL);
171
172 ptel &= _PAGE_FLAGS_HARDWARE_MASK;
173 ptel |= pgprot_val(pgprot);
174 ctrl_outl(ptel, MMU_PTEL);
175
176 __asm__ __volatile__ ("ldtlb" : : : "memory");
177
178 spin_unlock_irqrestore(&sq_mapping_lock, flags);
179
180 /*
181 * Next, we need to map ourselves in the kernel page table, so that
182 * future accesses after a TLB flush will be handled when we take a
183 * page fault.
184 *
185 * Theoretically we could just do this directly and not worry about
186 * setting up the translation by hand ahead of time, but for the
187 * cases where we want a one-shot SQ mapping followed by a quick
188 * writeout before we hit the TLB flush, we do it anyways. This way
189 * we at least save ourselves the initial page fault overhead.
190 */
191 vma = __get_vm_area(map->size, VM_ALLOC, map->sq_addr, SQ_ADDRMAX); 107 vma = __get_vm_area(map->size, VM_ALLOC, map->sq_addr, SQ_ADDRMAX);
192 if (!vma) 108 if (!vma)
193 return ERR_PTR(-ENOMEM); 109 return -ENOMEM;
194 110
195 vma->phys_addr = map->addr; 111 vma->phys_addr = map->addr;
196 112
197 if (remap_area_pages((unsigned long)vma->addr, vma->phys_addr, 113 if (remap_area_pages((unsigned long)vma->addr, vma->phys_addr,
198 map->size, pgprot_val(pgprot))) { 114 map->size, flags)) {
199 vunmap(vma->addr); 115 vunmap(vma->addr);
200 return NULL; 116 return -EAGAIN;
201 } 117 }
202#endif /* CONFIG_MMU */ 118#else
119 /*
120 * Without an MMU (or with it turned off), this is much more
121 * straightforward, as we can just load up each queue's QACR with
122 * the physical address appropriately masked.
123 */
124 ctrl_outl(((map->addr >> 26) << 2) & 0x1c, SQ_QACR0);
125 ctrl_outl(((map->addr >> 26) << 2) & 0x1c, SQ_QACR1);
126#endif
203 127
204 return map; 128 return 0;
205} 129}
206 130
207/** 131/**
@@ -209,42 +133,65 @@ static struct sq_mapping *__sq_remap(struct sq_mapping *map)
209 * @phys: Physical address of mapping. 133 * @phys: Physical address of mapping.
210 * @size: Length of mapping. 134 * @size: Length of mapping.
211 * @name: User invoking mapping. 135 * @name: User invoking mapping.
136 * @flags: Protection flags.
212 * 137 *
213 * Remaps the physical address @phys through the next available store queue 138 * Remaps the physical address @phys through the next available store queue
214 * address of @size length. @name is logged at boot time as well as through 139 * address of @size length. @name is logged at boot time as well as through
215 * the procfs interface. 140 * the sysfs interface.
216 *
217 * A pre-allocated and filled sq_mapping pointer is returned, and must be
218 * cleaned up with a call to sq_unmap() when the user is done with the
219 * mapping.
220 */ 141 */
221struct sq_mapping *sq_remap(unsigned long phys, unsigned int size, const char *name) 142unsigned long sq_remap(unsigned long phys, unsigned int size,
143 const char *name, unsigned long flags)
222{ 144{
223 struct sq_mapping *map; 145 struct sq_mapping *map;
224 unsigned long virt, end; 146 unsigned long end;
225 unsigned int psz; 147 unsigned int psz;
148 int ret, page;
226 149
227 /* Don't allow wraparound or zero size */ 150 /* Don't allow wraparound or zero size */
228 end = phys + size - 1; 151 end = phys + size - 1;
229 if (!size || end < phys) 152 if (unlikely(!size || end < phys))
230 return NULL; 153 return -EINVAL;
231 /* Don't allow anyone to remap normal memory.. */ 154 /* Don't allow anyone to remap normal memory.. */
232 if (phys < virt_to_phys(high_memory)) 155 if (unlikely(phys < virt_to_phys(high_memory)))
233 return NULL; 156 return -EINVAL;
234 157
235 phys &= PAGE_MASK; 158 phys &= PAGE_MASK;
159 size = PAGE_ALIGN(end + 1) - phys;
160
161 map = kmem_cache_alloc(sq_cache, GFP_KERNEL);
162 if (unlikely(!map))
163 return -ENOMEM;
164
165 map->addr = phys;
166 map->size = size;
167 map->name = name;
168
169 page = bitmap_find_free_region(sq_bitmap, 0x04000000,
170 get_order(map->size));
171 if (unlikely(page < 0)) {
172 ret = -ENOSPC;
173 goto out;
174 }
175
176 map->sq_addr = P4SEG_STORE_QUE + (page << PAGE_SHIFT);
177
178 ret = __sq_remap(map, flags);
179 if (unlikely(ret != 0))
180 goto out;
181
182 psz = (size + (PAGE_SIZE - 1)) >> PAGE_SHIFT;
183 pr_info("sqremap: %15s [%4d page%s] va 0x%08lx pa 0x%08lx\n",
184 likely(map->name) ? map->name : "???",
185 psz, psz == 1 ? " " : "s",
186 map->sq_addr, map->addr);
236 187
237 size = PAGE_ALIGN(end + 1) - phys; 188 sq_mapping_list_add(map);
238 virt = __sq_get_next_addr();
239 psz = (size + (PAGE_SIZE - 1)) / PAGE_SIZE;
240 map = __sq_alloc_mapping(virt, phys, size, name);
241 189
242 printk("sqremap: %15s [%4d page%s] va 0x%08lx pa 0x%08lx\n", 190 return map->sq_addr;
243 map->name ? map->name : "???",
244 psz, psz == 1 ? " " : "s",
245 map->sq_addr, map->addr);
246 191
247 return __sq_remap(map); 192out:
193 kmem_cache_free(sq_cache, map);
194 return ret;
248} 195}
249 196
250/** 197/**
@@ -255,188 +202,198 @@ struct sq_mapping *sq_remap(unsigned long phys, unsigned int size, const char *n
255 * sq_remap(). Also frees up the pte that was previously inserted into 202 * sq_remap(). Also frees up the pte that was previously inserted into
256 * the kernel page table and discards the UTLB translation. 203 * the kernel page table and discards the UTLB translation.
257 */ 204 */
258void sq_unmap(struct sq_mapping *map) 205void sq_unmap(unsigned long vaddr)
259{ 206{
260 if (map->sq_addr > (unsigned long)high_memory) 207 struct sq_mapping **p, *map;
261 vfree((void *)(map->sq_addr & PAGE_MASK)); 208 struct vm_struct *vma;
209 int page;
262 210
263 list_del(&map->list); 211 for (p = &sq_mapping_list; (map = *p); p = &map->next)
264 kfree(map); 212 if (map->sq_addr == vaddr)
265} 213 break;
266 214
267/** 215 if (unlikely(!map)) {
268 * sq_clear - Clear a store queue range 216 printk("%s: bad store queue address 0x%08lx\n",
269 * @addr: Address to start clearing from. 217 __FUNCTION__, vaddr);
270 * @len: Length to clear. 218 return;
271 * 219 }
272 * A quick zero-fill implementation for clearing out memory that has been
273 * remapped through the store queues.
274 */
275void sq_clear(unsigned long addr, unsigned int len)
276{
277 int i;
278 220
279 /* Clear out both queues linearly */ 221 page = (map->sq_addr - P4SEG_STORE_QUE) >> PAGE_SHIFT;
280 for (i = 0; i < 8; i++) { 222 bitmap_release_region(sq_bitmap, page, get_order(map->size));
281 ctrl_outl(0, addr + i + 0); 223
282 ctrl_outl(0, addr + i + 8); 224#ifdef CONFIG_MMU
225 vma = remove_vm_area((void *)(map->sq_addr & PAGE_MASK));
226 if (!vma) {
227 printk(KERN_ERR "%s: bad address 0x%08lx\n",
228 __FUNCTION__, map->sq_addr);
229 return;
283 } 230 }
231#endif
232
233 sq_mapping_list_del(map);
284 234
285 sq_flush_range(addr, len); 235 kmem_cache_free(sq_cache, map);
286} 236}
287 237
288/** 238/*
289 * sq_vma_unmap - Unmap a VMA range 239 * Needlessly complex sysfs interface. Unfortunately it doesn't seem like
290 * @area: VMA containing range. 240 * there is any other easy way to add things on a per-cpu basis without
291 * @addr: Start of range. 241 * putting the directory entries somewhere stupid and having to create
292 * @len: Length of range. 242 * links in sysfs by hand back in to the per-cpu directories.
293 * 243 *
294 * Searches the sq_mapping_list for a mapping matching the sq addr @addr, 244 * Some day we may want to have an additional abstraction per store
295 * and subsequently frees up the entry. Further cleanup is done by generic 245 * queue, but considering the kobject hell we already have to deal with,
296 * code. 246 * it's simply not worth the trouble.
297 */ 247 */
298static void sq_vma_unmap(struct vm_area_struct *area, 248static struct kobject *sq_kobject[NR_CPUS];
299 unsigned long addr, size_t len)
300{
301 struct list_head *pos, *tmp;
302 249
303 list_for_each_safe(pos, tmp, &sq_mapping_list) { 250struct sq_sysfs_attr {
304 struct sq_mapping *entry; 251 struct attribute attr;
252 ssize_t (*show)(char *buf);
253 ssize_t (*store)(const char *buf, size_t count);
254};
305 255
306 entry = list_entry(pos, typeof(*entry), list); 256#define to_sq_sysfs_attr(attr) container_of(attr, struct sq_sysfs_attr, attr)
307 257
308 if (entry->sq_addr == addr) { 258static ssize_t sq_sysfs_show(struct kobject *kobj, struct attribute *attr,
309 /* 259 char *buf)
310 * We could probably get away without doing the tlb flush 260{
311 * here, as generic code should take care of most of this 261 struct sq_sysfs_attr *sattr = to_sq_sysfs_attr(attr);
312 * when unmapping the rest of the VMA range for us. Leave
313 * it in for added sanity for the time being..
314 */
315 __flush_tlb_page(get_asid(), entry->sq_addr & PAGE_MASK);
316 262
317 list_del(&entry->list); 263 if (likely(sattr->show))
318 kfree(entry); 264 return sattr->show(buf);
319 265
320 return; 266 return -EIO;
321 }
322 }
323} 267}
324 268
325/** 269static ssize_t sq_sysfs_store(struct kobject *kobj, struct attribute *attr,
326 * sq_vma_sync - Sync a VMA range 270 const char *buf, size_t count)
327 * @area: VMA containing range.
328 * @start: Start of range.
329 * @len: Length of range.
330 * @flags: Additional flags.
331 *
332 * Synchronizes an sq mapped range by flushing the store queue cache for
333 * the duration of the mapping.
334 *
335 * Used internally for user mappings, which must use msync() to prefetch
336 * the store queue cache.
337 */
338static int sq_vma_sync(struct vm_area_struct *area,
339 unsigned long start, size_t len, unsigned int flags)
340{ 271{
341 sq_flush_range(start, len); 272 struct sq_sysfs_attr *sattr = to_sq_sysfs_attr(attr);
342 273
343 return 0; 274 if (likely(sattr->store))
275 return sattr->store(buf, count);
276
277 return -EIO;
344} 278}
345 279
346static struct vm_operations_struct sq_vma_ops = { 280static ssize_t mapping_show(char *buf)
347 .unmap = sq_vma_unmap, 281{
348 .sync = sq_vma_sync, 282 struct sq_mapping **list, *entry;
349}; 283 char *p = buf;
350 284
351/** 285 for (list = &sq_mapping_list; (entry = *list); list = &entry->next)
352 * sq_mmap - mmap() for /dev/cpu/sq 286 p += sprintf(p, "%08lx-%08lx [%08lx]: %s\n",
353 * @file: unused. 287 entry->sq_addr, entry->sq_addr + entry->size,
354 * @vma: VMA to remap. 288 entry->addr, entry->name);
355 * 289
356 * Remap the specified vma @vma through the store queues, and setup associated 290 return p - buf;
357 * information for the new mapping. Also build up the page tables for the new 291}
358 * area. 292
359 */ 293static ssize_t mapping_store(const char *buf, size_t count)
360static int sq_mmap(struct file *file, struct vm_area_struct *vma)
361{ 294{
362 unsigned long offset = vma->vm_pgoff << PAGE_SHIFT; 295 unsigned long base = 0, len = 0;
363 unsigned long size = vma->vm_end - vma->vm_start;
364 struct sq_mapping *map;
365 296
366 /* 297 sscanf(buf, "%lx %lx", &base, &len);
367 * We're not interested in any arbitrary virtual address that has 298 if (!base)
368 * been stuck in the VMA, as we already know what addresses we 299 return -EIO;
369 * want. Save off the size, and reposition the VMA to begin at
370 * the next available sq address.
371 */
372 vma->vm_start = __sq_get_next_addr();
373 vma->vm_end = vma->vm_start + size;
374 300
375 vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); 301 if (likely(len)) {
302 int ret = sq_remap(base, len, "Userspace",
303 pgprot_val(PAGE_SHARED));
304 if (ret < 0)
305 return ret;
306 } else
307 sq_unmap(base);
376 308
377 vma->vm_flags |= VM_IO | VM_RESERVED; 309 return count;
310}
378 311
379 map = __sq_alloc_mapping(vma->vm_start, offset, size, "Userspace"); 312static struct sq_sysfs_attr mapping_attr =
313 __ATTR(mapping, 0644, mapping_show, mapping_store);
380 314
381 if (io_remap_pfn_range(vma, map->sq_addr, map->addr >> PAGE_SHIFT, 315static struct attribute *sq_sysfs_attrs[] = {
382 size, vma->vm_page_prot)) 316 &mapping_attr.attr,
383 return -EAGAIN; 317 NULL,
318};
384 319
385 vma->vm_ops = &sq_vma_ops; 320static struct sysfs_ops sq_sysfs_ops = {
321 .show = sq_sysfs_show,
322 .store = sq_sysfs_store,
323};
386 324
387 return 0; 325static struct kobj_type ktype_percpu_entry = {
388} 326 .sysfs_ops = &sq_sysfs_ops,
327 .default_attrs = sq_sysfs_attrs,
328};
389 329
390#ifdef CONFIG_PROC_FS 330static int __devinit sq_sysdev_add(struct sys_device *sysdev)
391static int sq_mapping_read_proc(char *buf, char **start, off_t off,
392 int len, int *eof, void *data)
393{ 331{
394 struct list_head *pos; 332 unsigned int cpu = sysdev->id;
395 char *p = buf; 333 struct kobject *kobj;
396 334
397 list_for_each_prev(pos, &sq_mapping_list) { 335 sq_kobject[cpu] = kzalloc(sizeof(struct kobject), GFP_KERNEL);
398 struct sq_mapping *entry; 336 if (unlikely(!sq_kobject[cpu]))
337 return -ENOMEM;
399 338
400 entry = list_entry(pos, typeof(*entry), list); 339 kobj = sq_kobject[cpu];
340 kobj->parent = &sysdev->kobj;
341 kobject_set_name(kobj, "%s", "sq");
342 kobj->ktype = &ktype_percpu_entry;
401 343
402 p += sprintf(p, "%08lx-%08lx [%08lx]: %s\n", entry->sq_addr, 344 return kobject_register(kobj);
403 entry->sq_addr + entry->size - 1, entry->addr,
404 entry->name);
405 }
406
407 return p - buf;
408} 345}
409#endif
410 346
411static struct file_operations sq_fops = { 347static int __devexit sq_sysdev_remove(struct sys_device *sysdev)
412 .owner = THIS_MODULE, 348{
413 .mmap = sq_mmap, 349 unsigned int cpu = sysdev->id;
414}; 350 struct kobject *kobj = sq_kobject[cpu];
415 351
416static struct miscdevice sq_dev = { 352 kobject_unregister(kobj);
417 .minor = STORE_QUEUE_MINOR, 353 return 0;
418 .name = "sq", 354}
419 .fops = &sq_fops, 355
356static struct sysdev_driver sq_sysdev_driver = {
357 .add = sq_sysdev_add,
358 .remove = __devexit_p(sq_sysdev_remove),
420}; 359};
421 360
422static int __init sq_api_init(void) 361static int __init sq_api_init(void)
423{ 362{
424 int ret; 363 unsigned int nr_pages = 0x04000000 >> PAGE_SHIFT;
364 unsigned int size = (nr_pages + (BITS_PER_LONG - 1)) / BITS_PER_LONG;
365 int ret = -ENOMEM;
366
425 printk(KERN_NOTICE "sq: Registering store queue API.\n"); 367 printk(KERN_NOTICE "sq: Registering store queue API.\n");
426 368
427 create_proc_read_entry("sq_mapping", 0, 0, sq_mapping_read_proc, 0); 369 sq_cache = kmem_cache_create("store_queue_cache",
370 sizeof(struct sq_mapping), 0, 0,
371 NULL, NULL);
372 if (unlikely(!sq_cache))
373 return ret;
428 374
429 ret = misc_register(&sq_dev); 375 sq_bitmap = kzalloc(size, GFP_KERNEL);
430 if (ret) 376 if (unlikely(!sq_bitmap))
431 remove_proc_entry("sq_mapping", NULL); 377 goto out;
378
379 ret = sysdev_driver_register(&cpu_sysdev_class, &sq_sysdev_driver);
380 if (unlikely(ret != 0))
381 goto out;
382
383 return 0;
384
385out:
386 kfree(sq_bitmap);
387 kmem_cache_destroy(sq_cache);
432 388
433 return ret; 389 return ret;
434} 390}
435 391
436static void __exit sq_api_exit(void) 392static void __exit sq_api_exit(void)
437{ 393{
438 misc_deregister(&sq_dev); 394 sysdev_driver_unregister(&cpu_sysdev_class, &sq_sysdev_driver);
439 remove_proc_entry("sq_mapping", NULL); 395 kfree(sq_bitmap);
396 kmem_cache_destroy(sq_cache);
440} 397}
441 398
442module_init(sq_api_init); 399module_init(sq_api_init);
@@ -445,11 +402,7 @@ module_exit(sq_api_exit);
445MODULE_AUTHOR("Paul Mundt <lethal@linux-sh.org>, M. R. Brown <mrbrown@0xd6.org>"); 402MODULE_AUTHOR("Paul Mundt <lethal@linux-sh.org>, M. R. Brown <mrbrown@0xd6.org>");
446MODULE_DESCRIPTION("Simple API for SH-4 integrated Store Queues"); 403MODULE_DESCRIPTION("Simple API for SH-4 integrated Store Queues");
447MODULE_LICENSE("GPL"); 404MODULE_LICENSE("GPL");
448MODULE_ALIAS_MISCDEV(STORE_QUEUE_MINOR);
449 405
450EXPORT_SYMBOL(sq_remap); 406EXPORT_SYMBOL(sq_remap);
451EXPORT_SYMBOL(sq_unmap); 407EXPORT_SYMBOL(sq_unmap);
452EXPORT_SYMBOL(sq_clear);
453EXPORT_SYMBOL(sq_flush);
454EXPORT_SYMBOL(sq_flush_range); 408EXPORT_SYMBOL(sq_flush_range);
455
diff --git a/arch/sh/kernel/early_printk.c b/arch/sh/kernel/early_printk.c
index 1378db375e17..a00022722e9e 100644
--- a/arch/sh/kernel/early_printk.c
+++ b/arch/sh/kernel/early_printk.c
@@ -3,7 +3,7 @@
3 * 3 *
4 * Copyright (C) 1999, 2000 Niibe Yutaka 4 * Copyright (C) 1999, 2000 Niibe Yutaka
5 * Copyright (C) 2002 M. R. Brown 5 * Copyright (C) 2002 M. R. Brown
6 * Copyright (C) 2004 Paul Mundt 6 * Copyright (C) 2004 - 2006 Paul Mundt
7 * 7 *
8 * This file is subject to the terms and conditions of the GNU General Public 8 * This file is subject to the terms and conditions of the GNU General Public
9 * License. See the file "COPYING" in the main directory of this archive 9 * License. See the file "COPYING" in the main directory of this archive
@@ -49,7 +49,7 @@ static int __init sh_console_setup(struct console *co, char *options)
49 return 0; 49 return 0;
50} 50}
51 51
52static struct console early_console = { 52static struct console bios_console = {
53 .name = "bios", 53 .name = "bios",
54 .write = sh_console_write, 54 .write = sh_console_write,
55 .setup = sh_console_setup, 55 .setup = sh_console_setup,
@@ -59,34 +59,43 @@ static struct console early_console = {
59#endif 59#endif
60 60
61#ifdef CONFIG_EARLY_SCIF_CONSOLE 61#ifdef CONFIG_EARLY_SCIF_CONSOLE
62#include <linux/serial_core.h>
63#include "../../../drivers/serial/sh-sci.h"
64
65#ifdef CONFIG_CPU_SH4
62#define SCIF_REG 0xffe80000 66#define SCIF_REG 0xffe80000
67#elif defined(CONFIG_CPU_SUBTYPE_SH72060)
68#define SCIF_REG 0xfffe9800
69#else
70#error "Undefined SCIF for this subtype"
71#endif
72
73static struct uart_port scif_port = {
74 .mapbase = SCIF_REG,
75 .membase = (char __iomem *)SCIF_REG,
76};
63 77
64static void scif_sercon_putc(int c) 78static void scif_sercon_putc(int c)
65{ 79{
66 while (!(ctrl_inw(SCIF_REG + 0x10) & 0x20)) ; 80 while (((sci_in(&scif_port, SCFDR) & 0x1f00 >> 8) == 16))
81 ;
67 82
68 ctrl_outb(c, SCIF_REG + 12); 83 sci_out(&scif_port, SCxTDR, c);
69 ctrl_outw((ctrl_inw(SCIF_REG + 0x10) & 0x9f), SCIF_REG + 0x10); 84 sci_in(&scif_port, SCxSR);
85 sci_out(&scif_port, SCxSR, 0xf3 & ~(0x20 | 0x40));
86
87 while ((sci_in(&scif_port, SCxSR) & 0x40) == 0);
88 ;
70 89
71 if (c == '\n') 90 if (c == '\n')
72 scif_sercon_putc('\r'); 91 scif_sercon_putc('\r');
73} 92}
74 93
75static void scif_sercon_flush(void) 94static void scif_sercon_write(struct console *con, const char *s,
76{ 95 unsigned count)
77 ctrl_outw((ctrl_inw(SCIF_REG + 0x10) & 0xbf), SCIF_REG + 0x10);
78
79 while (!(ctrl_inw(SCIF_REG + 0x10) & 0x40)) ;
80
81 ctrl_outw((ctrl_inw(SCIF_REG + 0x10) & 0xbf), SCIF_REG + 0x10);
82}
83
84static void scif_sercon_write(struct console *con, const char *s, unsigned count)
85{ 96{
86 while (count-- > 0) 97 while (count-- > 0)
87 scif_sercon_putc(*s++); 98 scif_sercon_putc(*s++);
88
89 scif_sercon_flush();
90} 99}
91 100
92static int __init scif_sercon_setup(struct console *con, char *options) 101static int __init scif_sercon_setup(struct console *con, char *options)
@@ -96,7 +105,7 @@ static int __init scif_sercon_setup(struct console *con, char *options)
96 return 0; 105 return 0;
97} 106}
98 107
99static struct console early_console = { 108static struct console scif_console = {
100 .name = "sercon", 109 .name = "sercon",
101 .write = scif_sercon_write, 110 .write = scif_sercon_write,
102 .setup = scif_sercon_setup, 111 .setup = scif_sercon_setup,
@@ -104,7 +113,7 @@ static struct console early_console = {
104 .index = -1, 113 .index = -1,
105}; 114};
106 115
107void scif_sercon_init(int baud) 116static void scif_sercon_init(int baud)
108{ 117{
109 ctrl_outw(0, SCIF_REG + 8); 118 ctrl_outw(0, SCIF_REG + 8);
110 ctrl_outw(0, SCIF_REG); 119 ctrl_outw(0, SCIF_REG);
@@ -122,16 +131,61 @@ void scif_sercon_init(int baud)
122} 131}
123#endif 132#endif
124 133
125void __init enable_early_printk(void) 134/*
135 * Setup a default console, if more than one is compiled in, rely on the
136 * earlyprintk= parsing to give priority.
137 */
138static struct console *early_console =
139#ifdef CONFIG_SH_STANDARD_BIOS
140 &bios_console
141#elif defined(CONFIG_EARLY_SCIF_CONSOLE)
142 &scif_console
143#else
144 NULL
145#endif
146 ;
147
148static int __initdata keep_early;
149
150int __init setup_early_printk(char *opt)
126{ 151{
127#ifdef CONFIG_EARLY_SCIF_CONSOLE 152 char *space;
128 scif_sercon_init(115200); 153 char buf[256];
154
155 strlcpy(buf, opt, sizeof(buf));
156 space = strchr(buf, ' ');
157 if (space)
158 *space = 0;
159
160 if (strstr(buf, "keep"))
161 keep_early = 1;
162
163#ifdef CONFIG_SH_STANDARD_BIOS
164 if (!strncmp(buf, "bios", 4))
165 early_console = &bios_console;
166#endif
167#if defined(CONFIG_EARLY_SCIF_CONSOLE)
168 if (!strncmp(buf, "serial", 6)) {
169 early_console = &scif_console;
170
171#ifdef CONFIG_CPU_SH4
172 scif_sercon_init(115200);
173#endif
174 }
129#endif 175#endif
130 register_console(&early_console); 176
177 if (likely(early_console))
178 register_console(early_console);
179
180 return 1;
131} 181}
182__setup("earlyprintk=", setup_early_printk);
132 183
133void disable_early_printk(void) 184void __init disable_early_printk(void)
134{ 185{
135 unregister_console(&early_console); 186 if (!keep_early) {
187 printk("disabling early console\n");
188 unregister_console(early_console);
189 } else
190 printk("keeping early console\n");
136} 191}
137
diff --git a/arch/sh/kernel/entry.S b/arch/sh/kernel/entry.S
index 7dfd2ba75f7f..fe8221855b28 100644
--- a/arch/sh/kernel/entry.S
+++ b/arch/sh/kernel/entry.S
@@ -18,24 +18,6 @@
18#include <asm/cpu/mmu_context.h> 18#include <asm/cpu/mmu_context.h>
19#include <asm/unistd.h> 19#include <asm/unistd.h>
20 20
21#if !defined(CONFIG_NFSD) && !defined(CONFIG_NFSD_MODULE)
22#define sys_nfsservctl sys_ni_syscall
23#endif
24
25#if !defined(CONFIG_MMU)
26#define sys_madvise sys_ni_syscall
27#define sys_readahead sys_ni_syscall
28#define sys_mprotect sys_ni_syscall
29#define sys_msync sys_ni_syscall
30#define sys_mlock sys_ni_syscall
31#define sys_munlock sys_ni_syscall
32#define sys_mlockall sys_ni_syscall
33#define sys_munlockall sys_ni_syscall
34#define sys_mremap sys_ni_syscall
35#define sys_mincore sys_ni_syscall
36#define sys_remap_file_pages sys_ni_syscall
37#endif
38
39! NOTE: 21! NOTE:
40! GNU as (as of 2.9.1) changes bf/s into bt/s and bra, when the address 22! GNU as (as of 2.9.1) changes bf/s into bt/s and bra, when the address
41! to be jumped is too far, but it causes illegal slot exception. 23! to be jumped is too far, but it causes illegal slot exception.
@@ -326,7 +308,7 @@ ENTRY(exception_error)
326 .align 2 308 .align 2
327ret_from_exception: 309ret_from_exception:
328 preempt_stop() 310 preempt_stop()
329ret_from_irq: 311ENTRY(ret_from_irq)
330 ! 312 !
331 mov #OFF_SR, r0 313 mov #OFF_SR, r0
332 mov.l @(r0,r15), r0 ! get status register 314 mov.l @(r0,r15), r0 ! get status register
@@ -389,11 +371,12 @@ work_pending:
389 ! r8: current_thread_info 371 ! r8: current_thread_info
390 ! t: result of "tst #_TIF_NEED_RESCHED, r0" 372 ! t: result of "tst #_TIF_NEED_RESCHED, r0"
391 bf/s work_resched 373 bf/s work_resched
392 tst #_TIF_SIGPENDING, r0 374 tst #(_TIF_SIGPENDING | _TIF_RESTORE_SIGMASK), r0
393work_notifysig: 375work_notifysig:
394 bt/s restore_all 376 bt/s restore_all
395 mov r15, r4 377 mov r15, r4
396 mov #0, r5 378 mov r12, r5 ! set arg1(save_r0)
379 mov r0, r6
397 mov.l 2f, r1 380 mov.l 2f, r1
398 mova restore_all, r0 381 mova restore_all, r0
399 jmp @r1 382 jmp @r1
@@ -431,7 +414,7 @@ work_resched:
431 414
432 .align 2 415 .align 2
4331: .long schedule 4161: .long schedule
4342: .long do_signal 4172: .long do_notify_resume
435 418
436 .align 2 419 .align 2
437syscall_exit_work: 420syscall_exit_work:
@@ -552,6 +535,7 @@ syscall_call:
552 mov.l @r9, r8 535 mov.l @r9, r8
553 jsr @r8 ! jump to specific syscall handler 536 jsr @r8 ! jump to specific syscall handler
554 nop 537 nop
538 mov.l @(OFF_R0,r15), r12 ! save r0
555 mov.l r0, @(OFF_R0,r15) ! save the return value 539 mov.l r0, @(OFF_R0,r15) ! save the return value
556 ! 540 !
557syscall_exit: 541syscall_exit:
@@ -644,7 +628,7 @@ skip_restore:
644 ! 628 !
645#if defined(CONFIG_KGDB_NMI) 629#if defined(CONFIG_KGDB_NMI)
646 ! Clear in_nmi 630 ! Clear in_nmi
647 mov.l 4f, k0 631 mov.l 6f, k0
648 mov #0, k1 632 mov #0, k1
649 mov.b k1, @k0 633 mov.b k1, @k0
650#endif 634#endif
@@ -722,7 +706,7 @@ interrupt:
722! 706!
723! 707!
724 .align 2 708 .align 2
725handle_exception: 709ENTRY(handle_exception)
726 ! Using k0, k1 for scratch registers (r0_bank1, r1_bank), 710 ! Using k0, k1 for scratch registers (r0_bank1, r1_bank),
727 ! save all registers onto stack. 711 ! save all registers onto stack.
728 ! 712 !
@@ -732,8 +716,8 @@ handle_exception:
732 bt/s 1f ! It's a kernel to kernel transition. 716 bt/s 1f ! It's a kernel to kernel transition.
733 mov r15, k0 ! save original stack to k0 717 mov r15, k0 ! save original stack to k0
734 /* User space to kernel */ 718 /* User space to kernel */
735 mov #0x20, k1 719 mov #(THREAD_SIZE >> 8), k1
736 shll8 k1 ! k1 := 8192 (== THREAD_SIZE) 720 shll8 k1 ! k1 := THREAD_SIZE
737 add current, k1 721 add current, k1
738 mov k1, r15 ! change to kernel stack 722 mov k1, r15 ! change to kernel stack
739 ! 723 !
@@ -838,300 +822,3 @@ ENTRY(exception_none)
838 rts 822 rts
839 nop 823 nop
840 824
841 .data
842ENTRY(sys_call_table)
843 .long sys_ni_syscall /* 0 - old "setup()" system call*/
844 .long sys_exit
845 .long sys_fork
846 .long sys_read
847 .long sys_write
848 .long sys_open /* 5 */
849 .long sys_close
850 .long sys_waitpid
851 .long sys_creat
852 .long sys_link
853 .long sys_unlink /* 10 */
854 .long sys_execve
855 .long sys_chdir
856 .long sys_time
857 .long sys_mknod
858 .long sys_chmod /* 15 */
859 .long sys_lchown16
860 .long sys_ni_syscall /* old break syscall holder */
861 .long sys_stat
862 .long sys_lseek
863 .long sys_getpid /* 20 */
864 .long sys_mount
865 .long sys_oldumount
866 .long sys_setuid16
867 .long sys_getuid16
868 .long sys_stime /* 25 */
869 .long sys_ptrace
870 .long sys_alarm
871 .long sys_fstat
872 .long sys_pause
873 .long sys_utime /* 30 */
874 .long sys_ni_syscall /* old stty syscall holder */
875 .long sys_ni_syscall /* old gtty syscall holder */
876 .long sys_access
877 .long sys_nice
878 .long sys_ni_syscall /* 35 */ /* old ftime syscall holder */
879 .long sys_sync
880 .long sys_kill
881 .long sys_rename
882 .long sys_mkdir
883 .long sys_rmdir /* 40 */
884 .long sys_dup
885 .long sys_pipe
886 .long sys_times
887 .long sys_ni_syscall /* old prof syscall holder */
888 .long sys_brk /* 45 */
889 .long sys_setgid16
890 .long sys_getgid16
891 .long sys_signal
892 .long sys_geteuid16
893 .long sys_getegid16 /* 50 */
894 .long sys_acct
895 .long sys_umount /* recycled never used phys() */
896 .long sys_ni_syscall /* old lock syscall holder */
897 .long sys_ioctl
898 .long sys_fcntl /* 55 */
899 .long sys_ni_syscall /* old mpx syscall holder */
900 .long sys_setpgid
901 .long sys_ni_syscall /* old ulimit syscall holder */
902 .long sys_ni_syscall /* sys_olduname */
903 .long sys_umask /* 60 */
904 .long sys_chroot
905 .long sys_ustat
906 .long sys_dup2
907 .long sys_getppid
908 .long sys_getpgrp /* 65 */
909 .long sys_setsid
910 .long sys_sigaction
911 .long sys_sgetmask
912 .long sys_ssetmask
913 .long sys_setreuid16 /* 70 */
914 .long sys_setregid16
915 .long sys_sigsuspend
916 .long sys_sigpending
917 .long sys_sethostname
918 .long sys_setrlimit /* 75 */
919 .long sys_old_getrlimit
920 .long sys_getrusage
921 .long sys_gettimeofday
922 .long sys_settimeofday
923 .long sys_getgroups16 /* 80 */
924 .long sys_setgroups16
925 .long sys_ni_syscall /* sys_oldselect */
926 .long sys_symlink
927 .long sys_lstat
928 .long sys_readlink /* 85 */
929 .long sys_uselib
930 .long sys_swapon
931 .long sys_reboot
932 .long old_readdir
933 .long old_mmap /* 90 */
934 .long sys_munmap
935 .long sys_truncate
936 .long sys_ftruncate
937 .long sys_fchmod
938 .long sys_fchown16 /* 95 */
939 .long sys_getpriority
940 .long sys_setpriority
941 .long sys_ni_syscall /* old profil syscall holder */
942 .long sys_statfs
943 .long sys_fstatfs /* 100 */
944 .long sys_ni_syscall /* ioperm */
945 .long sys_socketcall
946 .long sys_syslog
947 .long sys_setitimer
948 .long sys_getitimer /* 105 */
949 .long sys_newstat
950 .long sys_newlstat
951 .long sys_newfstat
952 .long sys_uname
953 .long sys_ni_syscall /* 110 */ /* iopl */
954 .long sys_vhangup
955 .long sys_ni_syscall /* idle */
956 .long sys_ni_syscall /* vm86old */
957 .long sys_wait4
958 .long sys_swapoff /* 115 */
959 .long sys_sysinfo
960 .long sys_ipc
961 .long sys_fsync
962 .long sys_sigreturn
963 .long sys_clone /* 120 */
964 .long sys_setdomainname
965 .long sys_newuname
966 .long sys_ni_syscall /* sys_modify_ldt */
967 .long sys_adjtimex
968 .long sys_mprotect /* 125 */
969 .long sys_sigprocmask
970 .long sys_ni_syscall /* old "create_module" */
971 .long sys_init_module
972 .long sys_delete_module
973 .long sys_ni_syscall /* 130: old "get_kernel_syms" */
974 .long sys_quotactl
975 .long sys_getpgid
976 .long sys_fchdir
977 .long sys_bdflush
978 .long sys_sysfs /* 135 */
979 .long sys_personality
980 .long sys_ni_syscall /* for afs_syscall */
981 .long sys_setfsuid16
982 .long sys_setfsgid16
983 .long sys_llseek /* 140 */
984 .long sys_getdents
985 .long sys_select
986 .long sys_flock
987 .long sys_msync
988 .long sys_readv /* 145 */
989 .long sys_writev
990 .long sys_getsid
991 .long sys_fdatasync
992 .long sys_sysctl
993 .long sys_mlock /* 150 */
994 .long sys_munlock
995 .long sys_mlockall
996 .long sys_munlockall
997 .long sys_sched_setparam
998 .long sys_sched_getparam /* 155 */
999 .long sys_sched_setscheduler
1000 .long sys_sched_getscheduler
1001 .long sys_sched_yield
1002 .long sys_sched_get_priority_max
1003 .long sys_sched_get_priority_min /* 160 */
1004 .long sys_sched_rr_get_interval
1005 .long sys_nanosleep
1006 .long sys_mremap
1007 .long sys_setresuid16
1008 .long sys_getresuid16 /* 165 */
1009 .long sys_ni_syscall /* vm86 */
1010 .long sys_ni_syscall /* old "query_module" */
1011 .long sys_poll
1012 .long sys_nfsservctl
1013 .long sys_setresgid16 /* 170 */
1014 .long sys_getresgid16
1015 .long sys_prctl
1016 .long sys_rt_sigreturn
1017 .long sys_rt_sigaction
1018 .long sys_rt_sigprocmask /* 175 */
1019 .long sys_rt_sigpending
1020 .long sys_rt_sigtimedwait
1021 .long sys_rt_sigqueueinfo
1022 .long sys_rt_sigsuspend
1023 .long sys_pread_wrapper /* 180 */
1024 .long sys_pwrite_wrapper
1025 .long sys_chown16
1026 .long sys_getcwd
1027 .long sys_capget
1028 .long sys_capset /* 185 */
1029 .long sys_sigaltstack
1030 .long sys_sendfile
1031 .long sys_ni_syscall /* streams1 */
1032 .long sys_ni_syscall /* streams2 */
1033 .long sys_vfork /* 190 */
1034 .long sys_getrlimit
1035 .long sys_mmap2
1036 .long sys_truncate64
1037 .long sys_ftruncate64
1038 .long sys_stat64 /* 195 */
1039 .long sys_lstat64
1040 .long sys_fstat64
1041 .long sys_lchown
1042 .long sys_getuid
1043 .long sys_getgid /* 200 */
1044 .long sys_geteuid
1045 .long sys_getegid
1046 .long sys_setreuid
1047 .long sys_setregid
1048 .long sys_getgroups /* 205 */
1049 .long sys_setgroups
1050 .long sys_fchown
1051 .long sys_setresuid
1052 .long sys_getresuid
1053 .long sys_setresgid /* 210 */
1054 .long sys_getresgid
1055 .long sys_chown
1056 .long sys_setuid
1057 .long sys_setgid
1058 .long sys_setfsuid /* 215 */
1059 .long sys_setfsgid
1060 .long sys_pivot_root
1061 .long sys_mincore
1062 .long sys_madvise
1063 .long sys_getdents64 /* 220 */
1064 .long sys_fcntl64
1065 .long sys_ni_syscall /* reserved for TUX */
1066 .long sys_ni_syscall /* Reserved for Security */
1067 .long sys_gettid
1068 .long sys_readahead /* 225 */
1069 .long sys_setxattr
1070 .long sys_lsetxattr
1071 .long sys_fsetxattr
1072 .long sys_getxattr
1073 .long sys_lgetxattr /* 230 */
1074 .long sys_fgetxattr
1075 .long sys_listxattr
1076 .long sys_llistxattr
1077 .long sys_flistxattr
1078 .long sys_removexattr /* 235 */
1079 .long sys_lremovexattr
1080 .long sys_fremovexattr
1081 .long sys_tkill
1082 .long sys_sendfile64
1083 .long sys_futex /* 240 */
1084 .long sys_sched_setaffinity
1085 .long sys_sched_getaffinity
1086 .long sys_ni_syscall
1087 .long sys_ni_syscall
1088 .long sys_io_setup /* 245 */
1089 .long sys_io_destroy
1090 .long sys_io_getevents
1091 .long sys_io_submit
1092 .long sys_io_cancel
1093 .long sys_fadvise64 /* 250 */
1094 .long sys_ni_syscall
1095 .long sys_exit_group
1096 .long sys_lookup_dcookie
1097 .long sys_epoll_create
1098 .long sys_epoll_ctl /* 255 */
1099 .long sys_epoll_wait
1100 .long sys_remap_file_pages
1101 .long sys_set_tid_address
1102 .long sys_timer_create
1103 .long sys_timer_settime /* 260 */
1104 .long sys_timer_gettime
1105 .long sys_timer_getoverrun
1106 .long sys_timer_delete
1107 .long sys_clock_settime
1108 .long sys_clock_gettime /* 265 */
1109 .long sys_clock_getres
1110 .long sys_clock_nanosleep
1111 .long sys_statfs64
1112 .long sys_fstatfs64
1113 .long sys_tgkill /* 270 */
1114 .long sys_utimes
1115 .long sys_fadvise64_64_wrapper
1116 .long sys_ni_syscall /* Reserved for vserver */
1117 .long sys_ni_syscall /* Reserved for mbind */
1118 .long sys_ni_syscall /* 275 - get_mempolicy */
1119 .long sys_ni_syscall /* set_mempolicy */
1120 .long sys_mq_open
1121 .long sys_mq_unlink
1122 .long sys_mq_timedsend
1123 .long sys_mq_timedreceive /* 280 */
1124 .long sys_mq_notify
1125 .long sys_mq_getsetattr
1126 .long sys_ni_syscall /* Reserved for kexec */
1127 .long sys_waitid
1128 .long sys_add_key /* 285 */
1129 .long sys_request_key
1130 .long sys_keyctl
1131 .long sys_ioprio_set
1132 .long sys_ioprio_get
1133 .long sys_inotify_init /* 290 */
1134 .long sys_inotify_add_watch
1135 .long sys_inotify_rm_watch
1136
1137/* End of entry.S */
diff --git a/arch/sh/kernel/head.S b/arch/sh/kernel/head.S
index 9b9e6ef626ce..f5f53d14f245 100644
--- a/arch/sh/kernel/head.S
+++ b/arch/sh/kernel/head.S
@@ -11,6 +11,18 @@
11 * Head.S contains the SH exception handlers and startup code. 11 * Head.S contains the SH exception handlers and startup code.
12 */ 12 */
13#include <linux/linkage.h> 13#include <linux/linkage.h>
14#include <asm/thread_info.h>
15
16#ifdef CONFIG_CPU_SH4A
17#define SYNCO() synco
18
19#define PREFI(label, reg) \
20 mov.l label, reg; \
21 prefi @reg
22#else
23#define SYNCO()
24#define PREFI(label, reg)
25#endif
14 26
15 .section .empty_zero_page, "aw" 27 .section .empty_zero_page, "aw"
16ENTRY(empty_zero_page) 28ENTRY(empty_zero_page)
@@ -42,18 +54,25 @@ ENTRY(_stext)
42 ! Initialize global interrupt mask 54 ! Initialize global interrupt mask
43 mov #0, r0 55 mov #0, r0
44 ldc r0, r6_bank 56 ldc r0, r6_bank
57
58 /*
59 * Prefetch if possible to reduce cache miss penalty.
60 *
61 * We do this early on for SH-4A as a micro-optimization,
62 * as later on we will have speculative execution enabled
63 * and this will become less of an issue.
64 */
65 PREFI(5f, r0)
66 PREFI(6f, r0)
67
45 ! 68 !
46 mov.l 2f, r0 69 mov.l 2f, r0
47 mov r0, r15 ! Set initial r15 (stack pointer) 70 mov r0, r15 ! Set initial r15 (stack pointer)
48 mov #0x20, r1 ! 71 mov #(THREAD_SIZE >> 8), r1
49 shll8 r1 ! r1 = 8192 72 shll8 r1 ! r1 = THREAD_SIZE
50 sub r1, r0 ! 73 sub r1, r0 !
51 ldc r0, r7_bank ! ... and initial thread_info 74 ldc r0, r7_bank ! ... and initial thread_info
52 ! 75
53 ! Additional CPU initialization
54 mov.l 6f, r0
55 jsr @r0
56 nop
57 ! Clear BSS area 76 ! Clear BSS area
58 mov.l 3f, r1 77 mov.l 3f, r1
59 add #4, r1 78 add #4, r1
@@ -62,6 +81,14 @@ ENTRY(_stext)
629: cmp/hs r2, r1 819: cmp/hs r2, r1
63 bf/s 9b ! while (r1 < r2) 82 bf/s 9b ! while (r1 < r2)
64 mov.l r0,@-r2 83 mov.l r0,@-r2
84
85 ! Additional CPU initialization
86 mov.l 6f, r0
87 jsr @r0
88 nop
89
90 SYNCO() ! Wait for pending instructions..
91
65 ! Start kernel 92 ! Start kernel
66 mov.l 5f, r0 93 mov.l 5f, r0
67 jmp @r0 94 jmp @r0
@@ -69,7 +96,7 @@ ENTRY(_stext)
69 96
70 .balign 4 97 .balign 4
711: .long 0x400080F0 ! MD=1, RB=0, BL=0, FD=1, IMASK=0xF 981: .long 0x400080F0 ! MD=1, RB=0, BL=0, FD=1, IMASK=0xF
722: .long stack 992: .long init_thread_union+THREAD_SIZE
733: .long __bss_start 1003: .long __bss_start
744: .long _end 1014: .long _end
755: .long start_kernel 1025: .long start_kernel
diff --git a/arch/sh/kernel/io.c b/arch/sh/kernel/io.c
index 71c9fde2fd90..501fe03e3715 100644
--- a/arch/sh/kernel/io.c
+++ b/arch/sh/kernel/io.c
@@ -61,6 +61,73 @@ void memset_io(volatile void __iomem *dst, int c, unsigned long count)
61} 61}
62EXPORT_SYMBOL(memset_io); 62EXPORT_SYMBOL(memset_io);
63 63
64void __raw_readsl(unsigned long addr, void *datap, int len)
65{
66 u32 *data;
67
68 for (data = datap; (len != 0) && (((u32)data & 0x1f) != 0); len--)
69 *data++ = ctrl_inl(addr);
70
71 if (likely(len >= (0x20 >> 2))) {
72 int tmp2, tmp3, tmp4, tmp5, tmp6;
73
74 __asm__ __volatile__(
75 "1: \n\t"
76 "mov.l @%7, r0 \n\t"
77 "mov.l @%7, %2 \n\t"
78#ifdef CONFIG_CPU_SH4
79 "movca.l r0, @%0 \n\t"
80#else
81 "mov.l r0, @%0 \n\t"
82#endif
83 "mov.l @%7, %3 \n\t"
84 "mov.l @%7, %4 \n\t"
85 "mov.l @%7, %5 \n\t"
86 "mov.l @%7, %6 \n\t"
87 "mov.l @%7, r7 \n\t"
88 "mov.l @%7, r0 \n\t"
89 "mov.l %2, @(0x04,%0) \n\t"
90 "mov #0x20>>2, %2 \n\t"
91 "mov.l %3, @(0x08,%0) \n\t"
92 "sub %2, %1 \n\t"
93 "mov.l %4, @(0x0c,%0) \n\t"
94 "cmp/hi %1, %2 ! T if 32 > len \n\t"
95 "mov.l %5, @(0x10,%0) \n\t"
96 "mov.l %6, @(0x14,%0) \n\t"
97 "mov.l r7, @(0x18,%0) \n\t"
98 "mov.l r0, @(0x1c,%0) \n\t"
99 "bf.s 1b \n\t"
100 " add #0x20, %0 \n\t"
101 : "=&r" (data), "=&r" (len),
102 "=&r" (tmp2), "=&r" (tmp3), "=&r" (tmp4),
103 "=&r" (tmp5), "=&r" (tmp6)
104 : "r"(addr), "0" (data), "1" (len)
105 : "r0", "r7", "t", "memory");
106 }
107
108 for (; len != 0; len--)
109 *data++ = ctrl_inl(addr);
110}
111EXPORT_SYMBOL(__raw_readsl);
112
113void __raw_writesl(unsigned long addr, const void *data, int len)
114{
115 if (likely(len != 0)) {
116 int tmp1;
117
118 __asm__ __volatile__ (
119 "1: \n\t"
120 "mov.l @%0+, %1 \n\t"
121 "dt %3 \n\t"
122 "bf.s 1b \n\t"
123 " mov.l %1, @%4 \n\t"
124 : "=&r" (data), "=&r" (tmp1)
125 : "0" (data), "r" (len), "r"(addr)
126 : "t", "memory");
127 }
128}
129EXPORT_SYMBOL(__raw_writesl);
130
64void __iomem *ioport_map(unsigned long port, unsigned int nr) 131void __iomem *ioport_map(unsigned long port, unsigned int nr)
65{ 132{
66 return sh_mv.mv_ioport_map(port, nr); 133 return sh_mv.mv_ioport_map(port, nr);
diff --git a/arch/sh/kernel/irq.c b/arch/sh/kernel/irq.c
index c2e07f7f3496..c7ebd6aec951 100644
--- a/arch/sh/kernel/irq.c
+++ b/arch/sh/kernel/irq.c
@@ -1,5 +1,4 @@
1/* $Id: irq.c,v 1.20 2004/01/13 05:52:11 kkojima Exp $ 1/*
2 *
3 * linux/arch/sh/kernel/irq.c 2 * linux/arch/sh/kernel/irq.c
4 * 3 *
5 * Copyright (C) 1992, 1998 Linus Torvalds, Ingo Molnar 4 * Copyright (C) 1992, 1998 Linus Torvalds, Ingo Molnar
@@ -7,13 +6,15 @@
7 * 6 *
8 * SuperH version: Copyright (C) 1999 Niibe Yutaka 7 * SuperH version: Copyright (C) 1999 Niibe Yutaka
9 */ 8 */
10
11#include <linux/irq.h> 9#include <linux/irq.h>
12#include <linux/interrupt.h> 10#include <linux/interrupt.h>
11#include <linux/module.h>
13#include <linux/kernel_stat.h> 12#include <linux/kernel_stat.h>
14#include <linux/seq_file.h> 13#include <linux/seq_file.h>
15#include <asm/irq.h> 14#include <asm/irq.h>
16#include <asm/processor.h> 15#include <asm/processor.h>
16#include <asm/uaccess.h>
17#include <asm/thread_info.h>
17#include <asm/cpu/mmu_context.h> 18#include <asm/cpu/mmu_context.h>
18 19
19/* 20/*
@@ -60,15 +61,46 @@ unlock:
60} 61}
61#endif 62#endif
62 63
64#ifdef CONFIG_4KSTACKS
65/*
66 * per-CPU IRQ handling contexts (thread information and stack)
67 */
68union irq_ctx {
69 struct thread_info tinfo;
70 u32 stack[THREAD_SIZE/sizeof(u32)];
71};
72
73static union irq_ctx *hardirq_ctx[NR_CPUS];
74static union irq_ctx *softirq_ctx[NR_CPUS];
75#endif
63 76
64asmlinkage int do_IRQ(unsigned long r4, unsigned long r5, 77asmlinkage int do_IRQ(unsigned long r4, unsigned long r5,
65 unsigned long r6, unsigned long r7, 78 unsigned long r6, unsigned long r7,
66 struct pt_regs regs) 79 struct pt_regs regs)
67{ 80{
68 int irq = r4; 81 int irq = r4;
82#ifdef CONFIG_4KSTACKS
83 union irq_ctx *curctx, *irqctx;
84#endif
69 85
70 irq_enter(); 86 irq_enter();
71 87
88#ifdef CONFIG_DEBUG_STACKOVERFLOW
89 /* Debugging check for stack overflow: is there less than 1KB free? */
90 {
91 long sp;
92
93 __asm__ __volatile__ ("and r15, %0" :
94 "=r" (sp) : "0" (THREAD_SIZE - 1));
95
96 if (unlikely(sp < (sizeof(struct thread_info) + STACK_WARN))) {
97 printk("do_IRQ: stack overflow: %ld\n",
98 sp - sizeof(struct thread_info));
99 dump_stack();
100 }
101 }
102#endif
103
72#ifdef CONFIG_CPU_HAS_INTEVT 104#ifdef CONFIG_CPU_HAS_INTEVT
73 __asm__ __volatile__ ( 105 __asm__ __volatile__ (
74#ifdef CONFIG_CPU_HAS_SR_RB 106#ifdef CONFIG_CPU_HAS_SR_RB
@@ -87,7 +119,135 @@ asmlinkage int do_IRQ(unsigned long r4, unsigned long r5,
87#endif 119#endif
88 120
89 irq = irq_demux(irq); 121 irq = irq_demux(irq);
90 __do_IRQ(irq, &regs); 122
123#ifdef CONFIG_4KSTACKS
124 curctx = (union irq_ctx *)current_thread_info();
125 irqctx = hardirq_ctx[smp_processor_id()];
126
127 /*
128 * this is where we switch to the IRQ stack. However, if we are
129 * already using the IRQ stack (because we interrupted a hardirq
130 * handler) we can't do that and just have to keep using the
131 * current stack (which is the irq stack already after all)
132 */
133 if (curctx != irqctx) {
134 u32 *isp;
135
136 isp = (u32 *)((char *)irqctx + sizeof(*irqctx));
137 irqctx->tinfo.task = curctx->tinfo.task;
138 irqctx->tinfo.previous_sp = current_stack_pointer;
139
140 __asm__ __volatile__ (
141 "mov %0, r4 \n"
142 "mov %1, r5 \n"
143 "mov r15, r9 \n"
144 "jsr @%2 \n"
145 /* swith to the irq stack */
146 " mov %3, r15 \n"
147 /* restore the stack (ring zero) */
148 "mov r9, r15 \n"
149 : /* no outputs */
150 : "r" (irq), "r" (&regs), "r" (__do_IRQ), "r" (isp)
151 /* XXX: A somewhat excessive clobber list? -PFM */
152 : "memory", "r0", "r1", "r2", "r3", "r4",
153 "r5", "r6", "r7", "r8", "t", "pr"
154 );
155 } else
156#endif
157 __do_IRQ(irq, &regs);
158
91 irq_exit(); 159 irq_exit();
160
92 return 1; 161 return 1;
93} 162}
163
164#ifdef CONFIG_4KSTACKS
165/*
166 * These should really be __section__(".bss.page_aligned") as well, but
167 * gcc's 3.0 and earlier don't handle that correctly.
168 */
169static char softirq_stack[NR_CPUS * THREAD_SIZE]
170 __attribute__((__aligned__(THREAD_SIZE)));
171
172static char hardirq_stack[NR_CPUS * THREAD_SIZE]
173 __attribute__((__aligned__(THREAD_SIZE)));
174
175/*
176 * allocate per-cpu stacks for hardirq and for softirq processing
177 */
178void irq_ctx_init(int cpu)
179{
180 union irq_ctx *irqctx;
181
182 if (hardirq_ctx[cpu])
183 return;
184
185 irqctx = (union irq_ctx *)&hardirq_stack[cpu * THREAD_SIZE];
186 irqctx->tinfo.task = NULL;
187 irqctx->tinfo.exec_domain = NULL;
188 irqctx->tinfo.cpu = cpu;
189 irqctx->tinfo.preempt_count = HARDIRQ_OFFSET;
190 irqctx->tinfo.addr_limit = MAKE_MM_SEG(0);
191
192 hardirq_ctx[cpu] = irqctx;
193
194 irqctx = (union irq_ctx *)&softirq_stack[cpu * THREAD_SIZE];
195 irqctx->tinfo.task = NULL;
196 irqctx->tinfo.exec_domain = NULL;
197 irqctx->tinfo.cpu = cpu;
198 irqctx->tinfo.preempt_count = SOFTIRQ_OFFSET;
199 irqctx->tinfo.addr_limit = MAKE_MM_SEG(0);
200
201 softirq_ctx[cpu] = irqctx;
202
203 printk("CPU %u irqstacks, hard=%p soft=%p\n",
204 cpu, hardirq_ctx[cpu], softirq_ctx[cpu]);
205}
206
207void irq_ctx_exit(int cpu)
208{
209 hardirq_ctx[cpu] = NULL;
210}
211
212extern asmlinkage void __do_softirq(void);
213
214asmlinkage void do_softirq(void)
215{
216 unsigned long flags;
217 struct thread_info *curctx;
218 union irq_ctx *irqctx;
219 u32 *isp;
220
221 if (in_interrupt())
222 return;
223
224 local_irq_save(flags);
225
226 if (local_softirq_pending()) {
227 curctx = current_thread_info();
228 irqctx = softirq_ctx[smp_processor_id()];
229 irqctx->tinfo.task = curctx->task;
230 irqctx->tinfo.previous_sp = current_stack_pointer;
231
232 /* build the stack frame on the softirq stack */
233 isp = (u32 *)((char *)irqctx + sizeof(*irqctx));
234
235 __asm__ __volatile__ (
236 "mov r15, r9 \n"
237 "jsr @%0 \n"
238 /* switch to the softirq stack */
239 " mov %1, r15 \n"
240 /* restore the thread stack */
241 "mov r9, r15 \n"
242 : /* no outputs */
243 : "r" (__do_softirq), "r" (isp)
244 /* XXX: A somewhat excessive clobber list? -PFM */
245 : "memory", "r0", "r1", "r2", "r3", "r4",
246 "r5", "r6", "r7", "r8", "r9", "r15", "t", "pr"
247 );
248 }
249
250 local_irq_restore(flags);
251}
252EXPORT_SYMBOL(do_softirq);
253#endif
diff --git a/arch/sh/kernel/kgdb_stub.c b/arch/sh/kernel/kgdb_stub.c
index 42638b92b51c..9c6315f0335d 100644
--- a/arch/sh/kernel/kgdb_stub.c
+++ b/arch/sh/kernel/kgdb_stub.c
@@ -101,16 +101,17 @@
101#include <linux/linkage.h> 101#include <linux/linkage.h>
102#include <linux/init.h> 102#include <linux/init.h>
103 103
104#ifdef CONFIG_SH_KGDB_CONSOLE
105#include <linux/console.h>
106#endif
107
104#include <asm/system.h> 108#include <asm/system.h>
105#include <asm/current.h> 109#include <asm/current.h>
106#include <asm/signal.h> 110#include <asm/signal.h>
107#include <asm/pgtable.h> 111#include <asm/pgtable.h>
108#include <asm/ptrace.h> 112#include <asm/ptrace.h>
109#include <asm/kgdb.h> 113#include <asm/kgdb.h>
110 114#include <asm/io.h>
111#ifdef CONFIG_SH_KGDB_CONSOLE
112#include <linux/console.h>
113#endif
114 115
115/* Function pointers for linkage */ 116/* Function pointers for linkage */
116kgdb_debug_hook_t *kgdb_debug_hook; 117kgdb_debug_hook_t *kgdb_debug_hook;
@@ -240,7 +241,6 @@ static jmp_buf rem_com_env;
240/* Misc static */ 241/* Misc static */
241static int stepped_address; 242static int stepped_address;
242static short stepped_opcode; 243static short stepped_opcode;
243static const char hexchars[] = "0123456789abcdef";
244static char in_buffer[BUFMAX]; 244static char in_buffer[BUFMAX];
245static char out_buffer[OUTBUFMAX]; 245static char out_buffer[OUTBUFMAX];
246 246
@@ -253,29 +253,6 @@ typedef unsigned char threadref[8];
253#define BUF_THREAD_ID_SIZE 16 253#define BUF_THREAD_ID_SIZE 16
254#endif 254#endif
255 255
256/* Return addr as a real volatile address */
257static inline unsigned int ctrl_inl(const unsigned long addr)
258{
259 return *(volatile unsigned long *) addr;
260}
261
262/* Correctly set *addr using volatile */
263static inline void ctrl_outl(const unsigned int b, unsigned long addr)
264{
265 *(volatile unsigned long *) addr = b;
266}
267
268/* Get high hex bits */
269static char highhex(const int x)
270{
271 return hexchars[(x >> 4) & 0xf];
272}
273
274/* Get low hex bits */
275static char lowhex(const int x)
276{
277 return hexchars[x & 0xf];
278}
279 256
280/* Convert ch to hex */ 257/* Convert ch to hex */
281static int hex(const char ch) 258static int hex(const char ch)
diff --git a/arch/sh/kernel/machine_kexec.c b/arch/sh/kernel/machine_kexec.c
index 6bcd8d92399f..08587cdb64d6 100644
--- a/arch/sh/kernel/machine_kexec.c
+++ b/arch/sh/kernel/machine_kexec.c
@@ -29,12 +29,6 @@ extern const unsigned char relocate_new_kernel[];
29extern const unsigned int relocate_new_kernel_size; 29extern const unsigned int relocate_new_kernel_size;
30extern void *gdb_vbr_vector; 30extern void *gdb_vbr_vector;
31 31
32/*
33 * Provide a dummy crash_notes definition while crash dump arrives to ppc.
34 * This prevents breakage of crash_notes attribute in kernel/ksysfs.c.
35 */
36void *crash_notes = NULL;
37
38void machine_shutdown(void) 32void machine_shutdown(void)
39{ 33{
40} 34}
diff --git a/arch/sh/kernel/pm.c b/arch/sh/kernel/pm.c
new file mode 100644
index 000000000000..10ab62c9aede
--- /dev/null
+++ b/arch/sh/kernel/pm.c
@@ -0,0 +1,88 @@
1/*
2 * Generic Power Management Routine
3 *
4 * Copyright (c) 2006 Andriy Skulysh <askulsyh@gmail.com>
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License.
8 */
9#include <linux/suspend.h>
10#include <linux/delay.h>
11#include <linux/gfp.h>
12#include <asm/freq.h>
13#include <asm/io.h>
14#include <asm/watchdog.h>
15#include <asm/pm.h>
16
17#define INTR_OFFSET 0x600
18
19#define STBCR 0xffffff82
20#define STBCR2 0xffffff88
21
22#define STBCR_STBY 0x80
23#define STBCR_MSTP2 0x04
24
25#define MCR 0xffffff68
26#define RTCNT 0xffffff70
27
28#define MCR_RMODE 2
29#define MCR_RFSH 4
30
31void pm_enter(void)
32{
33 u8 stbcr, csr;
34 u16 frqcr, mcr;
35 u32 vbr_new, vbr_old;
36
37 set_bl_bit();
38
39 /* set wdt */
40 csr = sh_wdt_read_csr();
41 csr &= ~WTCSR_TME;
42 csr |= WTCSR_CKS_4096;
43 sh_wdt_write_csr(csr);
44 csr = sh_wdt_read_csr();
45 sh_wdt_write_cnt(0);
46
47 /* disable PLL1 */
48 frqcr = ctrl_inw(FRQCR);
49 frqcr &= ~(FRQCR_PLLEN | FRQCR_PSTBY);
50 ctrl_outw(frqcr, FRQCR);
51
52 /* enable standby */
53 stbcr = ctrl_inb(STBCR);
54 ctrl_outb(stbcr | STBCR_STBY | STBCR_MSTP2, STBCR);
55
56 /* set self-refresh */
57 mcr = ctrl_inw(MCR);
58 ctrl_outw(mcr & ~MCR_RFSH, MCR);
59
60 /* set interrupt handler */
61 asm volatile("stc vbr, %0" : "=r" (vbr_old));
62 vbr_new = get_zeroed_page(GFP_ATOMIC);
63 udelay(50);
64 memcpy((void*)(vbr_new + INTR_OFFSET),
65 &wakeup_start, &wakeup_end - &wakeup_start);
66 asm volatile("ldc %0, vbr" : : "r" (vbr_new));
67
68 ctrl_outw(0, RTCNT);
69 ctrl_outw(mcr | MCR_RFSH | MCR_RMODE, MCR);
70
71 cpu_sleep();
72
73 asm volatile("ldc %0, vbr" : : "r" (vbr_old));
74
75 free_page(vbr_new);
76
77 /* enable PLL1 */
78 frqcr = ctrl_inw(FRQCR);
79 frqcr |= FRQCR_PSTBY;
80 ctrl_outw(frqcr, FRQCR);
81 udelay(50);
82 frqcr |= FRQCR_PLLEN;
83 ctrl_outw(frqcr, FRQCR);
84
85 ctrl_outb(stbcr, STBCR);
86
87 clear_bl_bit();
88}
diff --git a/arch/sh/kernel/process.c b/arch/sh/kernel/process.c
index f2031314cb2b..0b1d5dd7a93b 100644
--- a/arch/sh/kernel/process.c
+++ b/arch/sh/kernel/process.c
@@ -81,16 +81,6 @@ void cpu_idle(void)
81 81
82void machine_restart(char * __unused) 82void machine_restart(char * __unused)
83{ 83{
84
85#ifdef CONFIG_KEXEC
86 struct kimage *image;
87 image = xchg(&kexec_image, 0);
88 if (image) {
89 machine_shutdown();
90 machine_kexec(image);
91 }
92#endif
93
94 /* SR.BL=1 and invoke address error to let CPU reset (manual reset) */ 84 /* SR.BL=1 and invoke address error to let CPU reset (manual reset) */
95 asm volatile("ldc %0, sr\n\t" 85 asm volatile("ldc %0, sr\n\t"
96 "mov.l @%1, %0" : : "r" (0x10000000), "r" (0x80000001)); 86 "mov.l @%1, %0" : : "r" (0x10000000), "r" (0x80000001));
@@ -263,6 +253,7 @@ int copy_thread(int nr, unsigned long clone_flags, unsigned long usp,
263 unsigned long unused, 253 unsigned long unused,
264 struct task_struct *p, struct pt_regs *regs) 254 struct task_struct *p, struct pt_regs *regs)
265{ 255{
256 struct thread_info *ti = task_thread_info(p);
266 struct pt_regs *childregs; 257 struct pt_regs *childregs;
267#if defined(CONFIG_SH_FPU) 258#if defined(CONFIG_SH_FPU)
268 struct task_struct *tsk = current; 259 struct task_struct *tsk = current;
@@ -277,8 +268,10 @@ int copy_thread(int nr, unsigned long clone_flags, unsigned long usp,
277 268
278 if (user_mode(regs)) { 269 if (user_mode(regs)) {
279 childregs->regs[15] = usp; 270 childregs->regs[15] = usp;
271 ti->addr_limit = USER_DS;
280 } else { 272 } else {
281 childregs->regs[15] = (unsigned long)task_stack_page(p) + THREAD_SIZE; 273 childregs->regs[15] = (unsigned long)task_stack_page(p) + THREAD_SIZE;
274 ti->addr_limit = KERNEL_DS;
282 } 275 }
283 if (clone_flags & CLONE_SETTLS) { 276 if (clone_flags & CLONE_SETTLS) {
284 childregs->gbr = childregs->regs[0]; 277 childregs->gbr = childregs->regs[0];
@@ -299,13 +292,15 @@ ubc_set_tracing(int asid, unsigned long pc)
299{ 292{
300 ctrl_outl(pc, UBC_BARA); 293 ctrl_outl(pc, UBC_BARA);
301 294
295#ifdef CONFIG_MMU
302 /* We don't have any ASID settings for the SH-2! */ 296 /* We don't have any ASID settings for the SH-2! */
303 if (cpu_data->type != CPU_SH7604) 297 if (cpu_data->type != CPU_SH7604)
304 ctrl_outb(asid, UBC_BASRA); 298 ctrl_outb(asid, UBC_BASRA);
299#endif
305 300
306 ctrl_outl(0, UBC_BAMRA); 301 ctrl_outl(0, UBC_BAMRA);
307 302
308 if (cpu_data->type == CPU_SH7729) { 303 if (cpu_data->type == CPU_SH7729 || cpu_data->type == CPU_SH7710) {
309 ctrl_outw(BBR_INST | BBR_READ | BBR_CPU, UBC_BBRA); 304 ctrl_outw(BBR_INST | BBR_READ | BBR_CPU, UBC_BBRA);
310 ctrl_outl(BRCR_PCBA | BRCR_PCTE, UBC_BRCR); 305 ctrl_outl(BRCR_PCBA | BRCR_PCTE, UBC_BRCR);
311 } else { 306 } else {
@@ -344,6 +339,7 @@ struct task_struct *__switch_to(struct task_struct *prev, struct task_struct *ne
344 } 339 }
345#endif 340#endif
346 341
342#ifdef CONFIG_MMU
347 /* 343 /*
348 * Restore the kernel mode register 344 * Restore the kernel mode register
349 * k7 (r7_bank1) 345 * k7 (r7_bank1)
@@ -351,19 +347,21 @@ struct task_struct *__switch_to(struct task_struct *prev, struct task_struct *ne
351 asm volatile("ldc %0, r7_bank" 347 asm volatile("ldc %0, r7_bank"
352 : /* no output */ 348 : /* no output */
353 : "r" (task_thread_info(next))); 349 : "r" (task_thread_info(next)));
350#endif
354 351
355#ifdef CONFIG_MMU
356 /* If no tasks are using the UBC, we're done */ 352 /* If no tasks are using the UBC, we're done */
357 if (ubc_usercnt == 0) 353 if (ubc_usercnt == 0)
358 /* If no tasks are using the UBC, we're done */; 354 /* If no tasks are using the UBC, we're done */;
359 else if (next->thread.ubc_pc && next->mm) { 355 else if (next->thread.ubc_pc && next->mm) {
360 ubc_set_tracing(next->mm->context & MMU_CONTEXT_ASID_MASK, 356 int asid = 0;
361 next->thread.ubc_pc); 357#ifdef CONFIG_MMU
358 asid |= next->mm->context.id & MMU_CONTEXT_ASID_MASK;
359#endif
360 ubc_set_tracing(asid, next->thread.ubc_pc);
362 } else { 361 } else {
363 ctrl_outw(0, UBC_BBRA); 362 ctrl_outw(0, UBC_BBRA);
364 ctrl_outw(0, UBC_BBRB); 363 ctrl_outw(0, UBC_BBRB);
365 } 364 }
366#endif
367 365
368 return prev; 366 return prev;
369} 367}
diff --git a/arch/sh/kernel/ptrace.c b/arch/sh/kernel/ptrace.c
index f7eebbde3291..04ca13a041c1 100644
--- a/arch/sh/kernel/ptrace.c
+++ b/arch/sh/kernel/ptrace.c
@@ -224,7 +224,6 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
224 224
225 case PTRACE_SETDSPREGS: { 225 case PTRACE_SETDSPREGS: {
226 unsigned long dp; 226 unsigned long dp;
227 int i;
228 227
229 ret = -EIO; 228 ret = -EIO;
230 dp = ((unsigned long) child) + THREAD_SIZE - 229 dp = ((unsigned long) child) + THREAD_SIZE -
diff --git a/arch/sh/kernel/semaphore.c b/arch/sh/kernel/semaphore.c
index a3c24dcbf01d..184119eeae56 100644
--- a/arch/sh/kernel/semaphore.c
+++ b/arch/sh/kernel/semaphore.c
@@ -14,7 +14,7 @@
14#include <asm/semaphore.h> 14#include <asm/semaphore.h>
15#include <asm/semaphore-helper.h> 15#include <asm/semaphore-helper.h>
16 16
17spinlock_t semaphore_wake_lock; 17DEFINE_SPINLOCK(semaphore_wake_lock);
18 18
19/* 19/*
20 * Semaphores are implemented using a two-way counter: 20 * Semaphores are implemented using a two-way counter:
diff --git a/arch/sh/kernel/setup.c b/arch/sh/kernel/setup.c
index e75189cb1db7..5f587332234a 100644
--- a/arch/sh/kernel/setup.c
+++ b/arch/sh/kernel/setup.c
@@ -43,27 +43,14 @@ extern void * __rd_start, * __rd_end;
43 * The bigger value means no problem. 43 * The bigger value means no problem.
44 */ 44 */
45struct sh_cpuinfo boot_cpu_data = { CPU_SH_NONE, 10000000, }; 45struct sh_cpuinfo boot_cpu_data = { CPU_SH_NONE, 10000000, };
46#ifdef CONFIG_VT
46struct screen_info screen_info; 47struct screen_info screen_info;
48#endif
47 49
48#if defined(CONFIG_SH_UNKNOWN) 50#if defined(CONFIG_SH_UNKNOWN)
49struct sh_machine_vector sh_mv; 51struct sh_machine_vector sh_mv;
50#endif 52#endif
51 53
52/* We need this to satisfy some external references. */
53struct screen_info screen_info = {
54 0, 25, /* orig-x, orig-y */
55 0, /* unused */
56 0, /* orig-video-page */
57 0, /* orig-video-mode */
58 80, /* orig-video-cols */
59 0,0,0, /* ega_ax, ega_bx, ega_cx */
60 25, /* orig-video-lines */
61 0, /* orig-video-isVGA */
62 16 /* orig-video-points */
63};
64
65extern void platform_setup(void);
66extern char *get_system_type(void);
67extern int root_mountflags; 54extern int root_mountflags;
68 55
69#define MV_NAME_SIZE 32 56#define MV_NAME_SIZE 32
@@ -90,29 +77,8 @@ static struct sh_machine_vector* __init get_mv_byname(const char* name);
90 77
91static char command_line[COMMAND_LINE_SIZE] = { 0, }; 78static char command_line[COMMAND_LINE_SIZE] = { 0, };
92 79
93struct resource standard_io_resources[] = { 80static struct resource code_resource = { .name = "Kernel code", };
94 { "dma1", 0x00, 0x1f }, 81static struct resource data_resource = { .name = "Kernel data", };
95 { "pic1", 0x20, 0x3f },
96 { "timer", 0x40, 0x5f },
97 { "keyboard", 0x60, 0x6f },
98 { "dma page reg", 0x80, 0x8f },
99 { "pic2", 0xa0, 0xbf },
100 { "dma2", 0xc0, 0xdf },
101 { "fpu", 0xf0, 0xff }
102};
103
104#define STANDARD_IO_RESOURCES (sizeof(standard_io_resources)/sizeof(struct resource))
105
106/* System RAM - interrupted by the 640kB-1M hole */
107#define code_resource (ram_resources[3])
108#define data_resource (ram_resources[4])
109static struct resource ram_resources[] = {
110 { "System RAM", 0x000000, 0x09ffff, IORESOURCE_BUSY },
111 { "System RAM", 0x100000, 0x100000, IORESOURCE_BUSY },
112 { "Video RAM area", 0x0a0000, 0x0bffff },
113 { "Kernel code", 0x100000, 0 },
114 { "Kernel data", 0, 0 }
115};
116 82
117unsigned long memory_start, memory_end; 83unsigned long memory_start, memory_end;
118 84
@@ -145,6 +111,24 @@ static inline void parse_cmdline (char ** cmdline_p, char mv_name[MV_NAME_SIZE],
145 memory_end = memory_start + mem_size; 111 memory_end = memory_start + mem_size;
146 } 112 }
147 } 113 }
114
115#ifdef CONFIG_EARLY_PRINTK
116 if (c == ' ' && !memcmp(from, "earlyprintk=", 12)) {
117 char *ep_end;
118
119 if (to != command_line)
120 to--;
121
122 from += 12;
123 ep_end = strchr(from, ' ');
124
125 setup_early_printk(from);
126 printk("early console enabled\n");
127
128 from = ep_end;
129 }
130#endif
131
148 if (c == ' ' && !memcmp(from, "sh_mv=", 6)) { 132 if (c == ' ' && !memcmp(from, "sh_mv=", 6)) {
149 char* mv_end; 133 char* mv_end;
150 char* mv_comma; 134 char* mv_comma;
@@ -237,6 +221,9 @@ static int __init sh_mv_setup(char **cmdline_p)
237 __set_io_port_base(mv_io_base); 221 __set_io_port_base(mv_io_base);
238#endif 222#endif
239 223
224 if (!sh_mv.mv_nr_irqs)
225 sh_mv.mv_nr_irqs = NR_IRQS;
226
240 return 0; 227 return 0;
241} 228}
242 229
@@ -245,11 +232,6 @@ void __init setup_arch(char **cmdline_p)
245 unsigned long bootmap_size; 232 unsigned long bootmap_size;
246 unsigned long start_pfn, max_pfn, max_low_pfn; 233 unsigned long start_pfn, max_pfn, max_low_pfn;
247 234
248#ifdef CONFIG_EARLY_PRINTK
249 extern void enable_early_printk(void);
250
251 enable_early_printk();
252#endif
253#ifdef CONFIG_CMDLINE_BOOL 235#ifdef CONFIG_CMDLINE_BOOL
254 strcpy(COMMAND_LINE, CONFIG_CMDLINE); 236 strcpy(COMMAND_LINE, CONFIG_CMDLINE);
255#endif 237#endif
@@ -368,14 +350,14 @@ void __init setup_arch(char **cmdline_p)
368#endif 350#endif
369 351
370 /* Perform the machine specific initialisation */ 352 /* Perform the machine specific initialisation */
371 platform_setup(); 353 if (likely(sh_mv.mv_setup))
354 sh_mv.mv_setup(cmdline_p);
372 355
373 paging_init(); 356 paging_init();
374} 357}
375 358
376struct sh_machine_vector* __init get_mv_byname(const char* name) 359struct sh_machine_vector* __init get_mv_byname(const char* name)
377{ 360{
378 extern int strcasecmp(const char *, const char *);
379 extern long __machvec_start, __machvec_end; 361 extern long __machvec_start, __machvec_end;
380 struct sh_machine_vector *all_vecs = 362 struct sh_machine_vector *all_vecs =
381 (struct sh_machine_vector *)&__machvec_start; 363 (struct sh_machine_vector *)&__machvec_start;
@@ -410,25 +392,18 @@ static int __init topology_init(void)
410subsys_initcall(topology_init); 392subsys_initcall(topology_init);
411 393
412static const char *cpu_name[] = { 394static const char *cpu_name[] = {
413 [CPU_SH7604] = "SH7604", 395 [CPU_SH7604] = "SH7604", [CPU_SH7300] = "SH7300",
414 [CPU_SH7705] = "SH7705", 396 [CPU_SH7705] = "SH7705", [CPU_SH7706] = "SH7706",
415 [CPU_SH7708] = "SH7708", 397 [CPU_SH7707] = "SH7707", [CPU_SH7708] = "SH7708",
416 [CPU_SH7729] = "SH7729", 398 [CPU_SH7709] = "SH7709", [CPU_SH7710] = "SH7710",
417 [CPU_SH7300] = "SH7300", 399 [CPU_SH7729] = "SH7729", [CPU_SH7750] = "SH7750",
418 [CPU_SH7750] = "SH7750", 400 [CPU_SH7750S] = "SH7750S", [CPU_SH7750R] = "SH7750R",
419 [CPU_SH7750S] = "SH7750S", 401 [CPU_SH7751] = "SH7751", [CPU_SH7751R] = "SH7751R",
420 [CPU_SH7750R] = "SH7750R", 402 [CPU_SH7760] = "SH7760", [CPU_SH73180] = "SH73180",
421 [CPU_SH7751] = "SH7751", 403 [CPU_ST40RA] = "ST40RA", [CPU_ST40GX1] = "ST40GX1",
422 [CPU_SH7751R] = "SH7751R", 404 [CPU_SH4_202] = "SH4-202", [CPU_SH4_501] = "SH4-501",
423 [CPU_SH7760] = "SH7760", 405 [CPU_SH7770] = "SH7770", [CPU_SH7780] = "SH7780",
424 [CPU_SH73180] = "SH73180", 406 [CPU_SH7781] = "SH7781", [CPU_SH7343] = "SH7343",
425 [CPU_ST40RA] = "ST40RA",
426 [CPU_ST40GX1] = "ST40GX1",
427 [CPU_SH4_202] = "SH4-202",
428 [CPU_SH4_501] = "SH4-501",
429 [CPU_SH7770] = "SH7770",
430 [CPU_SH7780] = "SH7780",
431 [CPU_SH7781] = "SH7781",
432 [CPU_SH_NONE] = "Unknown" 407 [CPU_SH_NONE] = "Unknown"
433}; 408};
434 409
@@ -438,8 +413,10 @@ const char *get_cpu_subtype(void)
438} 413}
439 414
440#ifdef CONFIG_PROC_FS 415#ifdef CONFIG_PROC_FS
416/* Symbolic CPU flags, keep in sync with asm/cpu-features.h */
441static const char *cpu_flags[] = { 417static const char *cpu_flags[] = {
442 "none", "fpu", "p2flush", "mmuassoc", "dsp", "perfctr", "ptea", NULL 418 "none", "fpu", "p2flush", "mmuassoc", "dsp", "perfctr",
419 "ptea", "llsc", "l2", NULL
443}; 420};
444 421
445static void show_cpuflags(struct seq_file *m) 422static void show_cpuflags(struct seq_file *m)
@@ -460,7 +437,8 @@ static void show_cpuflags(struct seq_file *m)
460 seq_printf(m, "\n"); 437 seq_printf(m, "\n");
461} 438}
462 439
463static void show_cacheinfo(struct seq_file *m, const char *type, struct cache_info info) 440static void show_cacheinfo(struct seq_file *m, const char *type,
441 struct cache_info info)
464{ 442{
465 unsigned int cache_size; 443 unsigned int cache_size;
466 444
@@ -493,7 +471,7 @@ static int show_cpuinfo(struct seq_file *m, void *v)
493 * unified cache on the SH-2 and SH-3, as well as the harvard 471 * unified cache on the SH-2 and SH-3, as well as the harvard
494 * style cache on the SH-4. 472 * style cache on the SH-4.
495 */ 473 */
496 if (test_bit(SH_CACHE_COMBINED, &(boot_cpu_data.icache.flags))) { 474 if (boot_cpu_data.icache.flags & SH_CACHE_COMBINED) {
497 seq_printf(m, "unified\n"); 475 seq_printf(m, "unified\n");
498 show_cacheinfo(m, "cache", boot_cpu_data.icache); 476 show_cacheinfo(m, "cache", boot_cpu_data.icache);
499 } else { 477 } else {
@@ -502,6 +480,10 @@ static int show_cpuinfo(struct seq_file *m, void *v)
502 show_cacheinfo(m, "dcache", boot_cpu_data.dcache); 480 show_cacheinfo(m, "dcache", boot_cpu_data.dcache);
503 } 481 }
504 482
483 /* Optional secondary cache */
484 if (boot_cpu_data.flags & CPU_HAS_L2_CACHE)
485 show_cacheinfo(m, "scache", boot_cpu_data.scache);
486
505 seq_printf(m, "bogomips\t: %lu.%02lu\n", 487 seq_printf(m, "bogomips\t: %lu.%02lu\n",
506 boot_cpu_data.loops_per_jiffy/(500000/HZ), 488 boot_cpu_data.loops_per_jiffy/(500000/HZ),
507 (boot_cpu_data.loops_per_jiffy/(5000/HZ)) % 100); 489 (boot_cpu_data.loops_per_jiffy/(5000/HZ)) % 100);
@@ -617,4 +599,3 @@ static int __init kgdb_parse_options(char *options)
617} 599}
618__setup("kgdb=", kgdb_parse_options); 600__setup("kgdb=", kgdb_parse_options);
619#endif /* CONFIG_SH_KGDB */ 601#endif /* CONFIG_SH_KGDB */
620
diff --git a/arch/sh/kernel/sh_ksyms.c b/arch/sh/kernel/sh_ksyms.c
index 245ed8f945e8..d3cbfa2ad4a7 100644
--- a/arch/sh/kernel/sh_ksyms.c
+++ b/arch/sh/kernel/sh_ksyms.c
@@ -27,21 +27,11 @@ EXPORT_SYMBOL(sh_mv);
27 27
28/* platform dependent support */ 28/* platform dependent support */
29EXPORT_SYMBOL(dump_fpu); 29EXPORT_SYMBOL(dump_fpu);
30EXPORT_SYMBOL(iounmap);
31EXPORT_SYMBOL(enable_irq);
32EXPORT_SYMBOL(disable_irq);
33EXPORT_SYMBOL(probe_irq_mask);
34EXPORT_SYMBOL(kernel_thread); 30EXPORT_SYMBOL(kernel_thread);
35EXPORT_SYMBOL(disable_irq_nosync);
36EXPORT_SYMBOL(irq_desc); 31EXPORT_SYMBOL(irq_desc);
37EXPORT_SYMBOL(no_irq_type); 32EXPORT_SYMBOL(no_irq_type);
38 33
39EXPORT_SYMBOL(strstr);
40EXPORT_SYMBOL(strlen); 34EXPORT_SYMBOL(strlen);
41EXPORT_SYMBOL(strnlen);
42EXPORT_SYMBOL(strchr);
43EXPORT_SYMBOL(strcat);
44EXPORT_SYMBOL(strncat);
45 35
46/* PCI exports */ 36/* PCI exports */
47#ifdef CONFIG_PCI 37#ifdef CONFIG_PCI
@@ -52,13 +42,8 @@ EXPORT_SYMBOL(pci_free_consistent);
52/* mem exports */ 42/* mem exports */
53EXPORT_SYMBOL(memchr); 43EXPORT_SYMBOL(memchr);
54EXPORT_SYMBOL(memcpy); 44EXPORT_SYMBOL(memcpy);
55EXPORT_SYMBOL(memcpy_fromio);
56EXPORT_SYMBOL(memcpy_toio);
57EXPORT_SYMBOL(memset); 45EXPORT_SYMBOL(memset);
58EXPORT_SYMBOL(memset_io);
59EXPORT_SYMBOL(memmove); 46EXPORT_SYMBOL(memmove);
60EXPORT_SYMBOL(memcmp);
61EXPORT_SYMBOL(memscan);
62EXPORT_SYMBOL(__copy_user); 47EXPORT_SYMBOL(__copy_user);
63EXPORT_SYMBOL(boot_cpu_data); 48EXPORT_SYMBOL(boot_cpu_data);
64 49
@@ -94,7 +79,9 @@ EXPORT_SYMBOL(strcpy);
94DECLARE_EXPORT(__movstr_i4_even); 79DECLARE_EXPORT(__movstr_i4_even);
95DECLARE_EXPORT(__movstr_i4_odd); 80DECLARE_EXPORT(__movstr_i4_odd);
96DECLARE_EXPORT(__movstrSI12_i4); 81DECLARE_EXPORT(__movstrSI12_i4);
82#endif
97 83
84#if defined(CONFIG_CPU_SH4) || defined(CONFIG_SH7705_CACHE_32KB)
98/* needed by some modules */ 85/* needed by some modules */
99EXPORT_SYMBOL(flush_cache_all); 86EXPORT_SYMBOL(flush_cache_all);
100EXPORT_SYMBOL(flush_cache_range); 87EXPORT_SYMBOL(flush_cache_range);
@@ -102,11 +89,9 @@ EXPORT_SYMBOL(flush_dcache_page);
102EXPORT_SYMBOL(__flush_purge_region); 89EXPORT_SYMBOL(__flush_purge_region);
103#endif 90#endif
104 91
105#if defined(CONFIG_SH7705_CACHE_32KB) 92#if defined(CONFIG_MMU) && (defined(CONFIG_CPU_SH4) || \
106EXPORT_SYMBOL(flush_cache_all); 93 defined(CONFIG_SH7705_CACHE_32KB))
107EXPORT_SYMBOL(flush_cache_range); 94EXPORT_SYMBOL(clear_user_page);
108EXPORT_SYMBOL(flush_dcache_page);
109EXPORT_SYMBOL(__flush_purge_region);
110#endif 95#endif
111 96
112EXPORT_SYMBOL(flush_tlb_page); 97EXPORT_SYMBOL(flush_tlb_page);
@@ -116,7 +101,12 @@ EXPORT_SYMBOL(__down_trylock);
116EXPORT_SYMBOL(synchronize_irq); 101EXPORT_SYMBOL(synchronize_irq);
117#endif 102#endif
118 103
104#ifdef CONFIG_PM
105EXPORT_SYMBOL(pm_suspend);
106#endif
107
119EXPORT_SYMBOL(csum_partial); 108EXPORT_SYMBOL(csum_partial);
109#ifdef CONFIG_IPV6
120EXPORT_SYMBOL(csum_ipv6_magic); 110EXPORT_SYMBOL(csum_ipv6_magic);
121EXPORT_SYMBOL(consistent_sync); 111#endif
122EXPORT_SYMBOL(clear_page); 112EXPORT_SYMBOL(clear_page);
diff --git a/arch/sh/kernel/signal.c b/arch/sh/kernel/signal.c
index b475c4d2405f..5213f5bc6ce0 100644
--- a/arch/sh/kernel/signal.c
+++ b/arch/sh/kernel/signal.c
@@ -8,7 +8,6 @@
8 * SuperH version: Copyright (C) 1999, 2000 Niibe Yutaka & Kaz Kojima 8 * SuperH version: Copyright (C) 1999, 2000 Niibe Yutaka & Kaz Kojima
9 * 9 *
10 */ 10 */
11
12#include <linux/sched.h> 11#include <linux/sched.h>
13#include <linux/mm.h> 12#include <linux/mm.h>
14#include <linux/smp.h> 13#include <linux/smp.h>
@@ -21,6 +20,7 @@
21#include <linux/unistd.h> 20#include <linux/unistd.h>
22#include <linux/stddef.h> 21#include <linux/stddef.h>
23#include <linux/tty.h> 22#include <linux/tty.h>
23#include <linux/elf.h>
24#include <linux/personality.h> 24#include <linux/personality.h>
25#include <linux/binfmts.h> 25#include <linux/binfmts.h>
26 26
@@ -29,12 +29,8 @@
29#include <asm/pgtable.h> 29#include <asm/pgtable.h>
30#include <asm/cacheflush.h> 30#include <asm/cacheflush.h>
31 31
32#define DEBUG_SIG 0
33
34#define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP))) 32#define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP)))
35 33
36asmlinkage int do_signal(struct pt_regs *regs, sigset_t *oldset);
37
38/* 34/*
39 * Atomically swap in the new signal mask, and wait for a signal. 35 * Atomically swap in the new signal mask, and wait for a signal.
40 */ 36 */
@@ -43,51 +39,17 @@ sys_sigsuspend(old_sigset_t mask,
43 unsigned long r5, unsigned long r6, unsigned long r7, 39 unsigned long r5, unsigned long r6, unsigned long r7,
44 struct pt_regs regs) 40 struct pt_regs regs)
45{ 41{
46 sigset_t saveset;
47
48 mask &= _BLOCKABLE; 42 mask &= _BLOCKABLE;
49 spin_lock_irq(&current->sighand->siglock); 43 spin_lock_irq(&current->sighand->siglock);
50 saveset = current->blocked; 44 current->saved_sigmask = current->blocked;
51 siginitset(&current->blocked, mask); 45 siginitset(&current->blocked, mask);
52 recalc_sigpending(); 46 recalc_sigpending();
53 spin_unlock_irq(&current->sighand->siglock); 47 spin_unlock_irq(&current->sighand->siglock);
54 48
55 regs.regs[0] = -EINTR; 49 current->state = TASK_INTERRUPTIBLE;
56 while (1) { 50 schedule();
57 current->state = TASK_INTERRUPTIBLE; 51 set_thread_flag(TIF_RESTORE_SIGMASK);
58 schedule(); 52 return -ERESTARTNOHAND;
59 if (do_signal(&regs, &saveset))
60 return -EINTR;
61 }
62}
63
64asmlinkage int
65sys_rt_sigsuspend(sigset_t *unewset, size_t sigsetsize,
66 unsigned long r6, unsigned long r7,
67 struct pt_regs regs)
68{
69 sigset_t saveset, newset;
70
71 /* XXX: Don't preclude handling different sized sigset_t's. */
72 if (sigsetsize != sizeof(sigset_t))
73 return -EINVAL;
74
75 if (copy_from_user(&newset, unewset, sizeof(newset)))
76 return -EFAULT;
77 sigdelsetmask(&newset, ~_BLOCKABLE);
78 spin_lock_irq(&current->sighand->siglock);
79 saveset = current->blocked;
80 current->blocked = newset;
81 recalc_sigpending();
82 spin_unlock_irq(&current->sighand->siglock);
83
84 regs.regs[0] = -EINTR;
85 while (1) {
86 current->state = TASK_INTERRUPTIBLE;
87 schedule();
88 if (do_signal(&regs, &saveset))
89 return -EINTR;
90 }
91} 53}
92 54
93asmlinkage int 55asmlinkage int
@@ -348,7 +310,12 @@ get_sigframe(struct k_sigaction *ka, unsigned long sp, size_t frame_size)
348 return (void __user *)((sp - frame_size) & -8ul); 310 return (void __user *)((sp - frame_size) & -8ul);
349} 311}
350 312
351static void setup_frame(int sig, struct k_sigaction *ka, 313/* These symbols are defined with the addresses in the vsyscall page.
314 See vsyscall-trapa.S. */
315extern void __user __kernel_sigreturn;
316extern void __user __kernel_rt_sigreturn;
317
318static int setup_frame(int sig, struct k_sigaction *ka,
352 sigset_t *set, struct pt_regs *regs) 319 sigset_t *set, struct pt_regs *regs)
353{ 320{
354 struct sigframe __user *frame; 321 struct sigframe __user *frame;
@@ -368,15 +335,18 @@ static void setup_frame(int sig, struct k_sigaction *ka,
368 335
369 err |= setup_sigcontext(&frame->sc, regs, set->sig[0]); 336 err |= setup_sigcontext(&frame->sc, regs, set->sig[0]);
370 337
371 if (_NSIG_WORDS > 1) { 338 if (_NSIG_WORDS > 1)
372 err |= __copy_to_user(frame->extramask, &set->sig[1], 339 err |= __copy_to_user(frame->extramask, &set->sig[1],
373 sizeof(frame->extramask)); 340 sizeof(frame->extramask));
374 }
375 341
376 /* Set up to return from userspace. If provided, use a stub 342 /* Set up to return from userspace. If provided, use a stub
377 already in userspace. */ 343 already in userspace. */
378 if (ka->sa.sa_flags & SA_RESTORER) { 344 if (ka->sa.sa_flags & SA_RESTORER) {
379 regs->pr = (unsigned long) ka->sa.sa_restorer; 345 regs->pr = (unsigned long) ka->sa.sa_restorer;
346#ifdef CONFIG_VSYSCALL
347 } else if (likely(current->mm->context.vdso)) {
348 regs->pr = VDSO_SYM(&__kernel_sigreturn);
349#endif
380 } else { 350 } else {
381 /* Generate return code (system call to sigreturn) */ 351 /* Generate return code (system call to sigreturn) */
382 err |= __put_user(MOVW(7), &frame->retcode[0]); 352 err |= __put_user(MOVW(7), &frame->retcode[0]);
@@ -402,21 +372,22 @@ static void setup_frame(int sig, struct k_sigaction *ka,
402 372
403 set_fs(USER_DS); 373 set_fs(USER_DS);
404 374
405#if DEBUG_SIG 375 pr_debug("SIG deliver (%s:%d): sp=%p pc=%08lx pr=%08lx\n",
406 printk("SIG deliver (%s:%d): sp=%p pc=%08lx pr=%08lx\n", 376 current->comm, current->pid, frame, regs->pc, regs->pr);
407 current->comm, current->pid, frame, regs->pc, regs->pr);
408#endif
409 377
410 flush_cache_sigtramp(regs->pr); 378 flush_cache_sigtramp(regs->pr);
379
411 if ((-regs->pr & (L1_CACHE_BYTES-1)) < sizeof(frame->retcode)) 380 if ((-regs->pr & (L1_CACHE_BYTES-1)) < sizeof(frame->retcode))
412 flush_cache_sigtramp(regs->pr + L1_CACHE_BYTES); 381 flush_cache_sigtramp(regs->pr + L1_CACHE_BYTES);
413 return; 382
383 return 0;
414 384
415give_sigsegv: 385give_sigsegv:
416 force_sigsegv(sig, current); 386 force_sigsegv(sig, current);
387 return -EFAULT;
417} 388}
418 389
419static void setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, 390static int setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
420 sigset_t *set, struct pt_regs *regs) 391 sigset_t *set, struct pt_regs *regs)
421{ 392{
422 struct rt_sigframe __user *frame; 393 struct rt_sigframe __user *frame;
@@ -452,6 +423,10 @@ static void setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
452 already in userspace. */ 423 already in userspace. */
453 if (ka->sa.sa_flags & SA_RESTORER) { 424 if (ka->sa.sa_flags & SA_RESTORER) {
454 regs->pr = (unsigned long) ka->sa.sa_restorer; 425 regs->pr = (unsigned long) ka->sa.sa_restorer;
426#ifdef CONFIG_VSYSCALL
427 } else if (likely(current->mm->context.vdso)) {
428 regs->pr = VDSO_SYM(&__kernel_rt_sigreturn);
429#endif
455 } else { 430 } else {
456 /* Generate return code (system call to rt_sigreturn) */ 431 /* Generate return code (system call to rt_sigreturn) */
457 err |= __put_user(MOVW(7), &frame->retcode[0]); 432 err |= __put_user(MOVW(7), &frame->retcode[0]);
@@ -477,28 +452,31 @@ static void setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
477 452
478 set_fs(USER_DS); 453 set_fs(USER_DS);
479 454
480#if DEBUG_SIG 455 pr_debug("SIG deliver (%s:%d): sp=%p pc=%08lx pr=%08lx\n",
481 printk("SIG deliver (%s:%d): sp=%p pc=%08lx pr=%08lx\n", 456 current->comm, current->pid, frame, regs->pc, regs->pr);
482 current->comm, current->pid, frame, regs->pc, regs->pr);
483#endif
484 457
485 flush_cache_sigtramp(regs->pr); 458 flush_cache_sigtramp(regs->pr);
459
486 if ((-regs->pr & (L1_CACHE_BYTES-1)) < sizeof(frame->retcode)) 460 if ((-regs->pr & (L1_CACHE_BYTES-1)) < sizeof(frame->retcode))
487 flush_cache_sigtramp(regs->pr + L1_CACHE_BYTES); 461 flush_cache_sigtramp(regs->pr + L1_CACHE_BYTES);
488 return; 462
463 return 0;
489 464
490give_sigsegv: 465give_sigsegv:
491 force_sigsegv(sig, current); 466 force_sigsegv(sig, current);
467 return -EFAULT;
492} 468}
493 469
494/* 470/*
495 * OK, we're invoking a handler 471 * OK, we're invoking a handler
496 */ 472 */
497 473
498static void 474static int
499handle_signal(unsigned long sig, struct k_sigaction *ka, siginfo_t *info, 475handle_signal(unsigned long sig, struct k_sigaction *ka, siginfo_t *info,
500 sigset_t *oldset, struct pt_regs *regs) 476 sigset_t *oldset, struct pt_regs *regs)
501{ 477{
478 int ret;
479
502 /* Are we from a system call? */ 480 /* Are we from a system call? */
503 if (regs->tra >= 0) { 481 if (regs->tra >= 0) {
504 /* If so, check system call restarting.. */ 482 /* If so, check system call restarting.. */
@@ -539,19 +517,23 @@ handle_signal(unsigned long sig, struct k_sigaction *ka, siginfo_t *info,
539 517
540 /* Set up the stack frame */ 518 /* Set up the stack frame */
541 if (ka->sa.sa_flags & SA_SIGINFO) 519 if (ka->sa.sa_flags & SA_SIGINFO)
542 setup_rt_frame(sig, ka, info, oldset, regs); 520 ret = setup_rt_frame(sig, ka, info, oldset, regs);
543 else 521 else
544 setup_frame(sig, ka, oldset, regs); 522 ret = setup_frame(sig, ka, oldset, regs);
545 523
546 if (ka->sa.sa_flags & SA_ONESHOT) 524 if (ka->sa.sa_flags & SA_ONESHOT)
547 ka->sa.sa_handler = SIG_DFL; 525 ka->sa.sa_handler = SIG_DFL;
548 526
549 spin_lock_irq(&current->sighand->siglock); 527 if (ret == 0) {
550 sigorsets(&current->blocked,&current->blocked,&ka->sa.sa_mask); 528 spin_lock_irq(&current->sighand->siglock);
551 if (!(ka->sa.sa_flags & SA_NODEFER)) 529 sigorsets(&current->blocked,&current->blocked,&ka->sa.sa_mask);
552 sigaddset(&current->blocked,sig); 530 if (!(ka->sa.sa_flags & SA_NODEFER))
553 recalc_sigpending(); 531 sigaddset(&current->blocked,sig);
554 spin_unlock_irq(&current->sighand->siglock); 532 recalc_sigpending();
533 spin_unlock_irq(&current->sighand->siglock);
534 }
535
536 return ret;
555} 537}
556 538
557/* 539/*
@@ -563,11 +545,12 @@ handle_signal(unsigned long sig, struct k_sigaction *ka, siginfo_t *info,
563 * the kernel can handle, and then we build all the user-level signal handling 545 * the kernel can handle, and then we build all the user-level signal handling
564 * stack-frames in one go after that. 546 * stack-frames in one go after that.
565 */ 547 */
566int do_signal(struct pt_regs *regs, sigset_t *oldset) 548static void do_signal(struct pt_regs *regs, unsigned int save_r0)
567{ 549{
568 siginfo_t info; 550 siginfo_t info;
569 int signr; 551 int signr;
570 struct k_sigaction ka; 552 struct k_sigaction ka;
553 sigset_t *oldset;
571 554
572 /* 555 /*
573 * We want the common case to go fast, which 556 * We want the common case to go fast, which
@@ -576,19 +559,27 @@ int do_signal(struct pt_regs *regs, sigset_t *oldset)
576 * if so. 559 * if so.
577 */ 560 */
578 if (!user_mode(regs)) 561 if (!user_mode(regs))
579 return 1; 562 return;
580 563
581 if (try_to_freeze()) 564 if (try_to_freeze())
582 goto no_signal; 565 goto no_signal;
583 566
584 if (!oldset) 567 if (test_thread_flag(TIF_RESTORE_SIGMASK))
568 oldset = &current->saved_sigmask;
569 else
585 oldset = &current->blocked; 570 oldset = &current->blocked;
586 571
587 signr = get_signal_to_deliver(&info, &ka, regs, NULL); 572 signr = get_signal_to_deliver(&info, &ka, regs, NULL);
588 if (signr > 0) { 573 if (signr > 0) {
589 /* Whee! Actually deliver the signal. */ 574 /* Whee! Actually deliver the signal. */
590 handle_signal(signr, &ka, &info, oldset, regs); 575 if (handle_signal(signr, &ka, &info, oldset, regs) == 0) {
591 return 1; 576 /* a signal was successfully delivered; the saved
577 * sigmask will have been stored in the signal frame,
578 * and will be restored by sigreturn, so we can simply
579 * clear the TIF_RESTORE_SIGMASK flag */
580 if (test_thread_flag(TIF_RESTORE_SIGMASK))
581 clear_thread_flag(TIF_RESTORE_SIGMASK);
582 }
592 } 583 }
593 584
594 no_signal: 585 no_signal:
@@ -597,10 +588,27 @@ int do_signal(struct pt_regs *regs, sigset_t *oldset)
597 /* Restart the system call - no handlers present */ 588 /* Restart the system call - no handlers present */
598 if (regs->regs[0] == -ERESTARTNOHAND || 589 if (regs->regs[0] == -ERESTARTNOHAND ||
599 regs->regs[0] == -ERESTARTSYS || 590 regs->regs[0] == -ERESTARTSYS ||
600 regs->regs[0] == -ERESTARTNOINTR || 591 regs->regs[0] == -ERESTARTNOINTR) {
601 regs->regs[0] == -ERESTART_RESTARTBLOCK) { 592 regs->regs[0] = save_r0;
593 regs->pc -= 2;
594 } else if (regs->regs[0] == -ERESTART_RESTARTBLOCK) {
602 regs->pc -= 2; 595 regs->pc -= 2;
596 regs->regs[3] = __NR_restart_syscall;
603 } 597 }
604 } 598 }
605 return 0; 599
600 /* if there's no signal to deliver, we just put the saved sigmask
601 * back */
602 if (test_thread_flag(TIF_RESTORE_SIGMASK)) {
603 clear_thread_flag(TIF_RESTORE_SIGMASK);
604 sigprocmask(SIG_SETMASK, &current->saved_sigmask, NULL);
605 }
606}
607
608asmlinkage void do_notify_resume(struct pt_regs *regs, unsigned int save_r0,
609 __u32 thread_info_flags)
610{
611 /* deal with pending signal delivery */
612 if (thread_info_flags & (_TIF_SIGPENDING | _TIF_RESTORE_SIGMASK))
613 do_signal(regs, save_r0);
606} 614}
diff --git a/arch/sh/kernel/sys_sh.c b/arch/sh/kernel/sys_sh.c
index 917b2f32f260..b68ff705f067 100644
--- a/arch/sh/kernel/sys_sh.c
+++ b/arch/sh/kernel/sys_sh.c
@@ -21,7 +21,8 @@
21#include <linux/mman.h> 21#include <linux/mman.h>
22#include <linux/file.h> 22#include <linux/file.h>
23#include <linux/utsname.h> 23#include <linux/utsname.h>
24 24#include <linux/module.h>
25#include <asm/cacheflush.h>
25#include <asm/uaccess.h> 26#include <asm/uaccess.h>
26#include <asm/ipc.h> 27#include <asm/ipc.h>
27 28
@@ -44,11 +45,16 @@ asmlinkage int sys_pipe(unsigned long r4, unsigned long r5,
44 return error; 45 return error;
45} 46}
46 47
47#if defined(HAVE_ARCH_UNMAPPED_AREA) 48unsigned long shm_align_mask = PAGE_SIZE - 1; /* Sane caches */
49
50EXPORT_SYMBOL(shm_align_mask);
51
48/* 52/*
49 * To avoid cache alias, we map the shard page with same color. 53 * To avoid cache aliases, we map the shared page with same color.
50 */ 54 */
51#define COLOUR_ALIGN(addr) (((addr)+SHMLBA-1)&~(SHMLBA-1)) 55#define COLOUR_ALIGN(addr, pgoff) \
56 ((((addr) + shm_align_mask) & ~shm_align_mask) + \
57 (((pgoff) << PAGE_SHIFT) & shm_align_mask))
52 58
53unsigned long arch_get_unmapped_area(struct file *filp, unsigned long addr, 59unsigned long arch_get_unmapped_area(struct file *filp, unsigned long addr,
54 unsigned long len, unsigned long pgoff, unsigned long flags) 60 unsigned long len, unsigned long pgoff, unsigned long flags)
@@ -56,43 +62,52 @@ unsigned long arch_get_unmapped_area(struct file *filp, unsigned long addr,
56 struct mm_struct *mm = current->mm; 62 struct mm_struct *mm = current->mm;
57 struct vm_area_struct *vma; 63 struct vm_area_struct *vma;
58 unsigned long start_addr; 64 unsigned long start_addr;
65 int do_colour_align;
59 66
60 if (flags & MAP_FIXED) { 67 if (flags & MAP_FIXED) {
61 /* We do not accept a shared mapping if it would violate 68 /* We do not accept a shared mapping if it would violate
62 * cache aliasing constraints. 69 * cache aliasing constraints.
63 */ 70 */
64 if ((flags & MAP_SHARED) && (addr & (SHMLBA - 1))) 71 if ((flags & MAP_SHARED) && (addr & shm_align_mask))
65 return -EINVAL; 72 return -EINVAL;
66 return addr; 73 return addr;
67 } 74 }
68 75
69 if (len > TASK_SIZE) 76 if (unlikely(len > TASK_SIZE))
70 return -ENOMEM; 77 return -ENOMEM;
71 78
79 do_colour_align = 0;
80 if (filp || (flags & MAP_SHARED))
81 do_colour_align = 1;
82
72 if (addr) { 83 if (addr) {
73 if (flags & MAP_PRIVATE) 84 if (do_colour_align)
74 addr = PAGE_ALIGN(addr); 85 addr = COLOUR_ALIGN(addr, pgoff);
75 else 86 else
76 addr = COLOUR_ALIGN(addr); 87 addr = PAGE_ALIGN(addr);
88
77 vma = find_vma(mm, addr); 89 vma = find_vma(mm, addr);
78 if (TASK_SIZE - len >= addr && 90 if (TASK_SIZE - len >= addr &&
79 (!vma || addr + len <= vma->vm_start)) 91 (!vma || addr + len <= vma->vm_start))
80 return addr; 92 return addr;
81 } 93 }
82 if (len <= mm->cached_hole_size) { 94
95 if (len > mm->cached_hole_size) {
96 start_addr = addr = mm->free_area_cache;
97 } else {
83 mm->cached_hole_size = 0; 98 mm->cached_hole_size = 0;
84 mm->free_area_cache = TASK_UNMAPPED_BASE; 99 start_addr = addr = TASK_UNMAPPED_BASE;
85 } 100 }
86 if (flags & MAP_PRIVATE)
87 addr = PAGE_ALIGN(mm->free_area_cache);
88 else
89 addr = COLOUR_ALIGN(mm->free_area_cache);
90 start_addr = addr;
91 101
92full_search: 102full_search:
103 if (do_colour_align)
104 addr = COLOUR_ALIGN(addr, pgoff);
105 else
106 addr = PAGE_ALIGN(mm->free_area_cache);
107
93 for (vma = find_vma(mm, addr); ; vma = vma->vm_next) { 108 for (vma = find_vma(mm, addr); ; vma = vma->vm_next) {
94 /* At this point: (!vma || addr < vma->vm_end). */ 109 /* At this point: (!vma || addr < vma->vm_end). */
95 if (TASK_SIZE - len < addr) { 110 if (unlikely(TASK_SIZE - len < addr)) {
96 /* 111 /*
97 * Start a new search - just in case we missed 112 * Start a new search - just in case we missed
98 * some holes. 113 * some holes.
@@ -104,7 +119,7 @@ full_search:
104 } 119 }
105 return -ENOMEM; 120 return -ENOMEM;
106 } 121 }
107 if (!vma || addr + len <= vma->vm_start) { 122 if (likely(!vma || addr + len <= vma->vm_start)) {
108 /* 123 /*
109 * Remember the place where we stopped the search: 124 * Remember the place where we stopped the search:
110 */ 125 */
@@ -115,11 +130,10 @@ full_search:
115 mm->cached_hole_size = vma->vm_start - addr; 130 mm->cached_hole_size = vma->vm_start - addr;
116 131
117 addr = vma->vm_end; 132 addr = vma->vm_end;
118 if (!(flags & MAP_PRIVATE)) 133 if (do_colour_align)
119 addr = COLOUR_ALIGN(addr); 134 addr = COLOUR_ALIGN(addr, pgoff);
120 } 135 }
121} 136}
122#endif
123 137
124static inline long 138static inline long
125do_mmap2(unsigned long addr, unsigned long len, unsigned long prot, 139do_mmap2(unsigned long addr, unsigned long len, unsigned long prot,
diff --git a/arch/sh/kernel/syscalls.S b/arch/sh/kernel/syscalls.S
new file mode 100644
index 000000000000..768334e95075
--- /dev/null
+++ b/arch/sh/kernel/syscalls.S
@@ -0,0 +1,353 @@
1/*
2 * arch/sh/kernel/syscalls.S
3 *
4 * System call table for SuperH
5 *
6 * Copyright (C) 1999, 2000, 2002 Niibe Yutaka
7 * Copyright (C) 2003 Paul Mundt
8 *
9 * This file is subject to the terms and conditions of the GNU General Public
10 * License. See the file "COPYING" in the main directory of this archive
11 * for more details.
12 *
13 */
14#include <linux/sys.h>
15#include <linux/linkage.h>
16
17#if !defined(CONFIG_NFSD) && !defined(CONFIG_NFSD_MODULE)
18#define sys_nfsservctl sys_ni_syscall
19#endif
20
21#if !defined(CONFIG_MMU)
22#define sys_madvise sys_ni_syscall
23#define sys_readahead sys_ni_syscall
24#define sys_mprotect sys_ni_syscall
25#define sys_msync sys_ni_syscall
26#define sys_mlock sys_ni_syscall
27#define sys_munlock sys_ni_syscall
28#define sys_mlockall sys_ni_syscall
29#define sys_munlockall sys_ni_syscall
30#define sys_mremap sys_ni_syscall
31#define sys_mincore sys_ni_syscall
32#define sys_remap_file_pages sys_ni_syscall
33#endif
34
35 .data
36ENTRY(sys_call_table)
37 .long sys_restart_syscall /* 0 - old "setup()" system call*/
38 .long sys_exit
39 .long sys_fork
40 .long sys_read
41 .long sys_write
42 .long sys_open /* 5 */
43 .long sys_close
44 .long sys_waitpid
45 .long sys_creat
46 .long sys_link
47 .long sys_unlink /* 10 */
48 .long sys_execve
49 .long sys_chdir
50 .long sys_time
51 .long sys_mknod
52 .long sys_chmod /* 15 */
53 .long sys_lchown16
54 .long sys_ni_syscall /* old break syscall holder */
55 .long sys_stat
56 .long sys_lseek
57 .long sys_getpid /* 20 */
58 .long sys_mount
59 .long sys_oldumount
60 .long sys_setuid16
61 .long sys_getuid16
62 .long sys_stime /* 25 */
63 .long sys_ptrace
64 .long sys_alarm
65 .long sys_fstat
66 .long sys_pause
67 .long sys_utime /* 30 */
68 .long sys_ni_syscall /* old stty syscall holder */
69 .long sys_ni_syscall /* old gtty syscall holder */
70 .long sys_access
71 .long sys_nice
72 .long sys_ni_syscall /* 35 */ /* old ftime syscall holder */
73 .long sys_sync
74 .long sys_kill
75 .long sys_rename
76 .long sys_mkdir
77 .long sys_rmdir /* 40 */
78 .long sys_dup
79 .long sys_pipe
80 .long sys_times
81 .long sys_ni_syscall /* old prof syscall holder */
82 .long sys_brk /* 45 */
83 .long sys_setgid16
84 .long sys_getgid16
85 .long sys_signal
86 .long sys_geteuid16
87 .long sys_getegid16 /* 50 */
88 .long sys_acct
89 .long sys_umount /* recycled never used phys() */
90 .long sys_ni_syscall /* old lock syscall holder */
91 .long sys_ioctl
92 .long sys_fcntl /* 55 */
93 .long sys_ni_syscall /* old mpx syscall holder */
94 .long sys_setpgid
95 .long sys_ni_syscall /* old ulimit syscall holder */
96 .long sys_ni_syscall /* sys_olduname */
97 .long sys_umask /* 60 */
98 .long sys_chroot
99 .long sys_ustat
100 .long sys_dup2
101 .long sys_getppid
102 .long sys_getpgrp /* 65 */
103 .long sys_setsid
104 .long sys_sigaction
105 .long sys_sgetmask
106 .long sys_ssetmask
107 .long sys_setreuid16 /* 70 */
108 .long sys_setregid16
109 .long sys_sigsuspend
110 .long sys_sigpending
111 .long sys_sethostname
112 .long sys_setrlimit /* 75 */
113 .long sys_old_getrlimit
114 .long sys_getrusage
115 .long sys_gettimeofday
116 .long sys_settimeofday
117 .long sys_getgroups16 /* 80 */
118 .long sys_setgroups16
119 .long sys_ni_syscall /* sys_oldselect */
120 .long sys_symlink
121 .long sys_lstat
122 .long sys_readlink /* 85 */
123 .long sys_uselib
124 .long sys_swapon
125 .long sys_reboot
126 .long old_readdir
127 .long old_mmap /* 90 */
128 .long sys_munmap
129 .long sys_truncate
130 .long sys_ftruncate
131 .long sys_fchmod
132 .long sys_fchown16 /* 95 */
133 .long sys_getpriority
134 .long sys_setpriority
135 .long sys_ni_syscall /* old profil syscall holder */
136 .long sys_statfs
137 .long sys_fstatfs /* 100 */
138 .long sys_ni_syscall /* ioperm */
139 .long sys_socketcall
140 .long sys_syslog
141 .long sys_setitimer
142 .long sys_getitimer /* 105 */
143 .long sys_newstat
144 .long sys_newlstat
145 .long sys_newfstat
146 .long sys_uname
147 .long sys_ni_syscall /* 110 */ /* iopl */
148 .long sys_vhangup
149 .long sys_ni_syscall /* idle */
150 .long sys_ni_syscall /* vm86old */
151 .long sys_wait4
152 .long sys_swapoff /* 115 */
153 .long sys_sysinfo
154 .long sys_ipc
155 .long sys_fsync
156 .long sys_sigreturn
157 .long sys_clone /* 120 */
158 .long sys_setdomainname
159 .long sys_newuname
160 .long sys_ni_syscall /* sys_modify_ldt */
161 .long sys_adjtimex
162 .long sys_mprotect /* 125 */
163 .long sys_sigprocmask
164 .long sys_ni_syscall /* old "create_module" */
165 .long sys_init_module
166 .long sys_delete_module
167 .long sys_ni_syscall /* 130: old "get_kernel_syms" */
168 .long sys_quotactl
169 .long sys_getpgid
170 .long sys_fchdir
171 .long sys_bdflush
172 .long sys_sysfs /* 135 */
173 .long sys_personality
174 .long sys_ni_syscall /* for afs_syscall */
175 .long sys_setfsuid16
176 .long sys_setfsgid16
177 .long sys_llseek /* 140 */
178 .long sys_getdents
179 .long sys_select
180 .long sys_flock
181 .long sys_msync
182 .long sys_readv /* 145 */
183 .long sys_writev
184 .long sys_getsid
185 .long sys_fdatasync
186 .long sys_sysctl
187 .long sys_mlock /* 150 */
188 .long sys_munlock
189 .long sys_mlockall
190 .long sys_munlockall
191 .long sys_sched_setparam
192 .long sys_sched_getparam /* 155 */
193 .long sys_sched_setscheduler
194 .long sys_sched_getscheduler
195 .long sys_sched_yield
196 .long sys_sched_get_priority_max
197 .long sys_sched_get_priority_min /* 160 */
198 .long sys_sched_rr_get_interval
199 .long sys_nanosleep
200 .long sys_mremap
201 .long sys_setresuid16
202 .long sys_getresuid16 /* 165 */
203 .long sys_ni_syscall /* vm86 */
204 .long sys_ni_syscall /* old "query_module" */
205 .long sys_poll
206 .long sys_nfsservctl
207 .long sys_setresgid16 /* 170 */
208 .long sys_getresgid16
209 .long sys_prctl
210 .long sys_rt_sigreturn
211 .long sys_rt_sigaction
212 .long sys_rt_sigprocmask /* 175 */
213 .long sys_rt_sigpending
214 .long sys_rt_sigtimedwait
215 .long sys_rt_sigqueueinfo
216 .long sys_rt_sigsuspend
217 .long sys_pread_wrapper /* 180 */
218 .long sys_pwrite_wrapper
219 .long sys_chown16
220 .long sys_getcwd
221 .long sys_capget
222 .long sys_capset /* 185 */
223 .long sys_sigaltstack
224 .long sys_sendfile
225 .long sys_ni_syscall /* streams1 */
226 .long sys_ni_syscall /* streams2 */
227 .long sys_vfork /* 190 */
228 .long sys_getrlimit
229 .long sys_mmap2
230 .long sys_truncate64
231 .long sys_ftruncate64
232 .long sys_stat64 /* 195 */
233 .long sys_lstat64
234 .long sys_fstat64
235 .long sys_lchown
236 .long sys_getuid
237 .long sys_getgid /* 200 */
238 .long sys_geteuid
239 .long sys_getegid
240 .long sys_setreuid
241 .long sys_setregid
242 .long sys_getgroups /* 205 */
243 .long sys_setgroups
244 .long sys_fchown
245 .long sys_setresuid
246 .long sys_getresuid
247 .long sys_setresgid /* 210 */
248 .long sys_getresgid
249 .long sys_chown
250 .long sys_setuid
251 .long sys_setgid
252 .long sys_setfsuid /* 215 */
253 .long sys_setfsgid
254 .long sys_pivot_root
255 .long sys_mincore
256 .long sys_madvise
257 .long sys_getdents64 /* 220 */
258 .long sys_fcntl64
259 .long sys_ni_syscall /* reserved for TUX */
260 .long sys_ni_syscall /* Reserved for Security */
261 .long sys_gettid
262 .long sys_readahead /* 225 */
263 .long sys_setxattr
264 .long sys_lsetxattr
265 .long sys_fsetxattr
266 .long sys_getxattr
267 .long sys_lgetxattr /* 230 */
268 .long sys_fgetxattr
269 .long sys_listxattr
270 .long sys_llistxattr
271 .long sys_flistxattr
272 .long sys_removexattr /* 235 */
273 .long sys_lremovexattr
274 .long sys_fremovexattr
275 .long sys_tkill
276 .long sys_sendfile64
277 .long sys_futex /* 240 */
278 .long sys_sched_setaffinity
279 .long sys_sched_getaffinity
280 .long sys_ni_syscall
281 .long sys_ni_syscall
282 .long sys_io_setup /* 245 */
283 .long sys_io_destroy
284 .long sys_io_getevents
285 .long sys_io_submit
286 .long sys_io_cancel
287 .long sys_fadvise64 /* 250 */
288 .long sys_ni_syscall
289 .long sys_exit_group
290 .long sys_lookup_dcookie
291 .long sys_epoll_create
292 .long sys_epoll_ctl /* 255 */
293 .long sys_epoll_wait
294 .long sys_remap_file_pages
295 .long sys_set_tid_address
296 .long sys_timer_create
297 .long sys_timer_settime /* 260 */
298 .long sys_timer_gettime
299 .long sys_timer_getoverrun
300 .long sys_timer_delete
301 .long sys_clock_settime
302 .long sys_clock_gettime /* 265 */
303 .long sys_clock_getres
304 .long sys_clock_nanosleep
305 .long sys_statfs64
306 .long sys_fstatfs64
307 .long sys_tgkill /* 270 */
308 .long sys_utimes
309 .long sys_fadvise64_64_wrapper
310 .long sys_ni_syscall /* Reserved for vserver */
311 .long sys_ni_syscall /* Reserved for mbind */
312 .long sys_ni_syscall /* 275 - get_mempolicy */
313 .long sys_ni_syscall /* set_mempolicy */
314 .long sys_mq_open
315 .long sys_mq_unlink
316 .long sys_mq_timedsend
317 .long sys_mq_timedreceive /* 280 */
318 .long sys_mq_notify
319 .long sys_mq_getsetattr
320 .long sys_kexec_load
321 .long sys_waitid
322 .long sys_ni_syscall /* 285 */
323 .long sys_add_key
324 .long sys_request_key
325 .long sys_keyctl
326 .long sys_ioprio_set
327 .long sys_ioprio_get /* 290 */
328 .long sys_inotify_init
329 .long sys_inotify_add_watch
330 .long sys_inotify_rm_watch
331 .long sys_migrate_pages
332 .long sys_openat /* 295 */
333 .long sys_mkdirat
334 .long sys_mknodat
335 .long sys_fchownat
336 .long sys_futimesat
337 .long sys_fstatat64 /* 300 */
338 .long sys_unlinkat
339 .long sys_renameat
340 .long sys_linkat
341 .long sys_symlinkat
342 .long sys_readlinkat /* 305 */
343 .long sys_fchmodat
344 .long sys_faccessat
345 .long sys_pselect6
346 .long sys_ppoll
347 .long sys_unshare /* 310 */
348 .long sys_set_robust_list
349 .long sys_get_robust_list
350 .long sys_splice
351 .long sys_sync_file_range
352 .long sys_tee /* 315 */
353 .long sys_vmsplice
diff --git a/arch/sh/kernel/time.c b/arch/sh/kernel/time.c
index a1589f85499d..149d9713eddf 100644
--- a/arch/sh/kernel/time.c
+++ b/arch/sh/kernel/time.c
@@ -3,13 +3,12 @@
3 * 3 *
4 * Copyright (C) 1999 Tetsuya Okada & Niibe Yutaka 4 * Copyright (C) 1999 Tetsuya Okada & Niibe Yutaka
5 * Copyright (C) 2000 Philipp Rumpf <prumpf@tux.org> 5 * Copyright (C) 2000 Philipp Rumpf <prumpf@tux.org>
6 * Copyright (C) 2002, 2003, 2004, 2005 Paul Mundt 6 * Copyright (C) 2002 - 2006 Paul Mundt
7 * Copyright (C) 2002 M. R. Brown <mrbrown@linux-sh.org> 7 * Copyright (C) 2002 M. R. Brown <mrbrown@linux-sh.org>
8 * 8 *
9 * Some code taken from i386 version. 9 * Some code taken from i386 version.
10 * Copyright (C) 1991, 1992, 1995 Linus Torvalds 10 * Copyright (C) 1991, 1992, 1995 Linus Torvalds
11 */ 11 */
12
13#include <linux/kernel.h> 12#include <linux/kernel.h>
14#include <linux/module.h> 13#include <linux/module.h>
15#include <linux/init.h> 14#include <linux/init.h>
@@ -26,15 +25,20 @@ struct sys_timer *sys_timer;
26DEFINE_SPINLOCK(rtc_lock); 25DEFINE_SPINLOCK(rtc_lock);
27EXPORT_SYMBOL(rtc_lock); 26EXPORT_SYMBOL(rtc_lock);
28 27
29/* XXX: Can we initialize this in a routine somewhere? Dreamcast doesn't want 28/* Dummy RTC ops */
30 * these routines anywhere... */ 29static void null_rtc_get_time(struct timespec *tv)
31#ifdef CONFIG_SH_RTC 30{
32void (*rtc_get_time)(struct timespec *) = sh_rtc_gettimeofday; 31 tv->tv_sec = mktime(2000, 1, 1, 0, 0, 0);
33int (*rtc_set_time)(const time_t) = sh_rtc_settimeofday; 32 tv->tv_nsec = 0;
34#else 33}
35void (*rtc_get_time)(struct timespec *); 34
36int (*rtc_set_time)(const time_t); 35static int null_rtc_set_time(const time_t secs)
37#endif 36{
37 return 0;
38}
39
40void (*rtc_sh_get_time)(struct timespec *) = null_rtc_get_time;
41int (*rtc_sh_set_time)(const time_t) = null_rtc_set_time;
38 42
39/* 43/*
40 * Scheduler clock - returns current time in nanosec units. 44 * Scheduler clock - returns current time in nanosec units.
@@ -70,7 +74,6 @@ void do_gettimeofday(struct timeval *tv)
70 tv->tv_sec = sec; 74 tv->tv_sec = sec;
71 tv->tv_usec = usec; 75 tv->tv_usec = usec;
72} 76}
73
74EXPORT_SYMBOL(do_gettimeofday); 77EXPORT_SYMBOL(do_gettimeofday);
75 78
76int do_settimeofday(struct timespec *tv) 79int do_settimeofday(struct timespec *tv)
@@ -103,7 +106,6 @@ int do_settimeofday(struct timespec *tv)
103 106
104 return 0; 107 return 0;
105} 108}
106
107EXPORT_SYMBOL(do_settimeofday); 109EXPORT_SYMBOL(do_settimeofday);
108 110
109/* last time the RTC clock got updated */ 111/* last time the RTC clock got updated */
@@ -135,7 +137,7 @@ void handle_timer_tick(struct pt_regs *regs)
135 xtime.tv_sec > last_rtc_update + 660 && 137 xtime.tv_sec > last_rtc_update + 660 &&
136 (xtime.tv_nsec / 1000) >= 500000 - ((unsigned) TICK_SIZE) / 2 && 138 (xtime.tv_nsec / 1000) >= 500000 - ((unsigned) TICK_SIZE) / 2 &&
137 (xtime.tv_nsec / 1000) <= 500000 + ((unsigned) TICK_SIZE) / 2) { 139 (xtime.tv_nsec / 1000) <= 500000 + ((unsigned) TICK_SIZE) / 2) {
138 if (rtc_set_time(xtime.tv_sec) == 0) 140 if (rtc_sh_set_time(xtime.tv_sec) == 0)
139 last_rtc_update = xtime.tv_sec; 141 last_rtc_update = xtime.tv_sec;
140 else 142 else
141 /* do it again in 60s */ 143 /* do it again in 60s */
@@ -143,8 +145,33 @@ void handle_timer_tick(struct pt_regs *regs)
143 } 145 }
144} 146}
145 147
148#ifdef CONFIG_PM
149int timer_suspend(struct sys_device *dev, pm_message_t state)
150{
151 struct sys_timer *sys_timer = container_of(dev, struct sys_timer, dev);
152
153 sys_timer->ops->stop();
154
155 return 0;
156}
157
158int timer_resume(struct sys_device *dev)
159{
160 struct sys_timer *sys_timer = container_of(dev, struct sys_timer, dev);
161
162 sys_timer->ops->start();
163
164 return 0;
165}
166#else
167#define timer_suspend NULL
168#define timer_resume NULL
169#endif
170
146static struct sysdev_class timer_sysclass = { 171static struct sysdev_class timer_sysclass = {
147 set_kset_name("timer"), 172 set_kset_name("timer"),
173 .suspend = timer_suspend,
174 .resume = timer_resume,
148}; 175};
149 176
150static int __init timer_init_sysfs(void) 177static int __init timer_init_sysfs(void)
@@ -156,7 +183,6 @@ static int __init timer_init_sysfs(void)
156 sys_timer->dev.cls = &timer_sysclass; 183 sys_timer->dev.cls = &timer_sysclass;
157 return sysdev_register(&sys_timer->dev); 184 return sysdev_register(&sys_timer->dev);
158} 185}
159
160device_initcall(timer_init_sysfs); 186device_initcall(timer_init_sysfs);
161 187
162void (*board_time_init)(void); 188void (*board_time_init)(void);
@@ -168,15 +194,9 @@ void __init time_init(void)
168 194
169 clk_init(); 195 clk_init();
170 196
171 if (rtc_get_time) { 197 rtc_sh_get_time(&xtime);
172 rtc_get_time(&xtime); 198 set_normalized_timespec(&wall_to_monotonic,
173 } else { 199 -xtime.tv_sec, -xtime.tv_nsec);
174 xtime.tv_sec = mktime(2000, 1, 1, 0, 0, 0);
175 xtime.tv_nsec = 0;
176 }
177
178 set_normalized_timespec(&wall_to_monotonic,
179 -xtime.tv_sec, -xtime.tv_nsec);
180 200
181 /* 201 /*
182 * Find the timer to use as the system timer, it will be 202 * Find the timer to use as the system timer, it will be
diff --git a/arch/sh/kernel/timers/timer-tmu.c b/arch/sh/kernel/timers/timer-tmu.c
index d4212add53b2..205816fcf0da 100644
--- a/arch/sh/kernel/timers/timer-tmu.c
+++ b/arch/sh/kernel/timers/timer-tmu.c
@@ -132,17 +132,17 @@ static unsigned long tmu_timer_get_frequency(void)
132 ctrl_outl(0xffffffff, TMU0_TCOR); 132 ctrl_outl(0xffffffff, TMU0_TCOR);
133 ctrl_outl(0xffffffff, TMU0_TCNT); 133 ctrl_outl(0xffffffff, TMU0_TCNT);
134 134
135 rtc_get_time(&ts2); 135 rtc_sh_get_time(&ts2);
136 136
137 do { 137 do {
138 rtc_get_time(&ts1); 138 rtc_sh_get_time(&ts1);
139 } while (ts1.tv_nsec == ts2.tv_nsec && ts1.tv_sec == ts2.tv_sec); 139 } while (ts1.tv_nsec == ts2.tv_nsec && ts1.tv_sec == ts2.tv_sec);
140 140
141 /* actually start the timer */ 141 /* actually start the timer */
142 ctrl_outb(TMU_TSTR_INIT, TMU_TSTR); 142 ctrl_outb(TMU_TSTR_INIT, TMU_TSTR);
143 143
144 do { 144 do {
145 rtc_get_time(&ts2); 145 rtc_sh_get_time(&ts2);
146 } while (ts1.tv_nsec == ts2.tv_nsec && ts1.tv_sec == ts2.tv_sec); 146 } while (ts1.tv_nsec == ts2.tv_nsec && ts1.tv_sec == ts2.tv_sec);
147 147
148 freq = 0xffffffff - ctrl_inl(TMU0_TCNT); 148 freq = 0xffffffff - ctrl_inl(TMU0_TCNT);
@@ -188,6 +188,18 @@ static struct clk tmu0_clk = {
188 .ops = &tmu_clk_ops, 188 .ops = &tmu_clk_ops,
189}; 189};
190 190
191static int tmu_timer_start(void)
192{
193 ctrl_outb(TMU_TSTR_INIT, TMU_TSTR);
194 return 0;
195}
196
197static int tmu_timer_stop(void)
198{
199 ctrl_outb(0, TMU_TSTR);
200 return 0;
201}
202
191static int tmu_timer_init(void) 203static int tmu_timer_init(void)
192{ 204{
193 unsigned long interval; 205 unsigned long interval;
@@ -197,7 +209,7 @@ static int tmu_timer_init(void)
197 tmu0_clk.parent = clk_get("module_clk"); 209 tmu0_clk.parent = clk_get("module_clk");
198 210
199 /* Start TMU0 */ 211 /* Start TMU0 */
200 ctrl_outb(0, TMU_TSTR); 212 tmu_timer_stop();
201#if !defined(CONFIG_CPU_SUBTYPE_SH7300) && !defined(CONFIG_CPU_SUBTYPE_SH7760) 213#if !defined(CONFIG_CPU_SUBTYPE_SH7300) && !defined(CONFIG_CPU_SUBTYPE_SH7760)
202 ctrl_outb(TMU_TOCR_INIT, TMU_TOCR); 214 ctrl_outb(TMU_TOCR_INIT, TMU_TOCR);
203#endif 215#endif
@@ -211,13 +223,15 @@ static int tmu_timer_init(void)
211 ctrl_outl(interval, TMU0_TCOR); 223 ctrl_outl(interval, TMU0_TCOR);
212 ctrl_outl(interval, TMU0_TCNT); 224 ctrl_outl(interval, TMU0_TCNT);
213 225
214 ctrl_outb(TMU_TSTR_INIT, TMU_TSTR); 226 tmu_timer_start();
215 227
216 return 0; 228 return 0;
217} 229}
218 230
219struct sys_timer_ops tmu_timer_ops = { 231struct sys_timer_ops tmu_timer_ops = {
220 .init = tmu_timer_init, 232 .init = tmu_timer_init,
233 .start = tmu_timer_start,
234 .stop = tmu_timer_stop,
221 .get_frequency = tmu_timer_get_frequency, 235 .get_frequency = tmu_timer_get_frequency,
222 .get_offset = tmu_timer_get_offset, 236 .get_offset = tmu_timer_get_offset,
223}; 237};
diff --git a/arch/sh/kernel/traps.c b/arch/sh/kernel/traps.c
index d9db1180f770..c2c597e09482 100644
--- a/arch/sh/kernel/traps.c
+++ b/arch/sh/kernel/traps.c
@@ -36,40 +36,15 @@
36 36
37#ifdef CONFIG_SH_KGDB 37#ifdef CONFIG_SH_KGDB
38#include <asm/kgdb.h> 38#include <asm/kgdb.h>
39#define CHK_REMOTE_DEBUG(regs) \ 39#define CHK_REMOTE_DEBUG(regs) \
40{ \ 40{ \
41 if ((kgdb_debug_hook != (kgdb_debug_hook_t *) NULL) && (!user_mode(regs))) \ 41 if (kgdb_debug_hook && !user_mode(regs))\
42 { \ 42 (*kgdb_debug_hook)(regs); \
43 (*kgdb_debug_hook)(regs); \
44 } \
45} 43}
46#else 44#else
47#define CHK_REMOTE_DEBUG(regs) 45#define CHK_REMOTE_DEBUG(regs)
48#endif 46#endif
49 47
50#define DO_ERROR(trapnr, signr, str, name, tsk) \
51asmlinkage void do_##name(unsigned long r4, unsigned long r5, \
52 unsigned long r6, unsigned long r7, \
53 struct pt_regs regs) \
54{ \
55 unsigned long error_code; \
56 \
57 /* Check if it's a DSP instruction */ \
58 if (is_dsp_inst(&regs)) { \
59 /* Enable DSP mode, and restart instruction. */ \
60 regs.sr |= SR_DSP; \
61 return; \
62 } \
63 \
64 asm volatile("stc r2_bank, %0": "=r" (error_code)); \
65 local_irq_enable(); \
66 tsk->thread.error_code = error_code; \
67 tsk->thread.trap_no = trapnr; \
68 CHK_REMOTE_DEBUG(&regs); \
69 force_sig(signr, tsk); \
70 die_if_no_fixup(str,&regs,error_code); \
71}
72
73#ifdef CONFIG_CPU_SH2 48#ifdef CONFIG_CPU_SH2
74#define TRAP_RESERVED_INST 4 49#define TRAP_RESERVED_INST 4
75#define TRAP_ILLEGAL_SLOT_INST 6 50#define TRAP_ILLEGAL_SLOT_INST 6
@@ -86,7 +61,7 @@ asmlinkage void do_##name(unsigned long r4, unsigned long r5, \
86#define VMALLOC_OFFSET (8*1024*1024) 61#define VMALLOC_OFFSET (8*1024*1024)
87#define MODULE_RANGE (8*1024*1024) 62#define MODULE_RANGE (8*1024*1024)
88 63
89spinlock_t die_lock; 64DEFINE_SPINLOCK(die_lock);
90 65
91void die(const char * str, struct pt_regs * regs, long err) 66void die(const char * str, struct pt_regs * regs, long err)
92{ 67{
@@ -575,8 +550,117 @@ int is_dsp_inst(struct pt_regs *regs)
575#define is_dsp_inst(regs) (0) 550#define is_dsp_inst(regs) (0)
576#endif /* CONFIG_SH_DSP */ 551#endif /* CONFIG_SH_DSP */
577 552
578DO_ERROR(TRAP_RESERVED_INST, SIGILL, "reserved instruction", reserved_inst, current) 553extern int do_fpu_inst(unsigned short, struct pt_regs*);
579DO_ERROR(TRAP_ILLEGAL_SLOT_INST, SIGILL, "illegal slot instruction", illegal_slot_inst, current) 554
555asmlinkage void do_reserved_inst(unsigned long r4, unsigned long r5,
556 unsigned long r6, unsigned long r7,
557 struct pt_regs regs)
558{
559 unsigned long error_code;
560 struct task_struct *tsk = current;
561
562#ifdef CONFIG_SH_FPU_EMU
563 unsigned short inst;
564 int err;
565
566 get_user(inst, (unsigned short*)regs.pc);
567
568 err = do_fpu_inst(inst, &regs);
569 if (!err) {
570 regs.pc += 2;
571 return;
572 }
573 /* not a FPU inst. */
574#endif
575
576#ifdef CONFIG_SH_DSP
577 /* Check if it's a DSP instruction */
578 if (is_dsp_inst(&regs)) {
579 /* Enable DSP mode, and restart instruction. */
580 regs.sr |= SR_DSP;
581 return;
582 }
583#endif
584
585 asm volatile("stc r2_bank, %0": "=r" (error_code));
586 local_irq_enable();
587 tsk->thread.error_code = error_code;
588 tsk->thread.trap_no = TRAP_RESERVED_INST;
589 CHK_REMOTE_DEBUG(&regs);
590 force_sig(SIGILL, tsk);
591 die_if_no_fixup("reserved instruction", &regs, error_code);
592}
593
594#ifdef CONFIG_SH_FPU_EMU
595static int emulate_branch(unsigned short inst, struct pt_regs* regs)
596{
597 /*
598 * bfs: 8fxx: PC+=d*2+4;
599 * bts: 8dxx: PC+=d*2+4;
600 * bra: axxx: PC+=D*2+4;
601 * bsr: bxxx: PC+=D*2+4 after PR=PC+4;
602 * braf:0x23: PC+=Rn*2+4;
603 * bsrf:0x03: PC+=Rn*2+4 after PR=PC+4;
604 * jmp: 4x2b: PC=Rn;
605 * jsr: 4x0b: PC=Rn after PR=PC+4;
606 * rts: 000b: PC=PR;
607 */
608 if ((inst & 0xfd00) == 0x8d00) {
609 regs->pc += SH_PC_8BIT_OFFSET(inst);
610 return 0;
611 }
612
613 if ((inst & 0xe000) == 0xa000) {
614 regs->pc += SH_PC_12BIT_OFFSET(inst);
615 return 0;
616 }
617
618 if ((inst & 0xf0df) == 0x0003) {
619 regs->pc += regs->regs[(inst & 0x0f00) >> 8] + 4;
620 return 0;
621 }
622
623 if ((inst & 0xf0df) == 0x400b) {
624 regs->pc = regs->regs[(inst & 0x0f00) >> 8];
625 return 0;
626 }
627
628 if ((inst & 0xffff) == 0x000b) {
629 regs->pc = regs->pr;
630 return 0;
631 }
632
633 return 1;
634}
635#endif
636
637asmlinkage void do_illegal_slot_inst(unsigned long r4, unsigned long r5,
638 unsigned long r6, unsigned long r7,
639 struct pt_regs regs)
640{
641 unsigned long error_code;
642 struct task_struct *tsk = current;
643#ifdef CONFIG_SH_FPU_EMU
644 unsigned short inst;
645
646 get_user(inst, (unsigned short *)regs.pc + 1);
647 if (!do_fpu_inst(inst, &regs)) {
648 get_user(inst, (unsigned short *)regs.pc);
649 if (!emulate_branch(inst, &regs))
650 return;
651 /* fault in branch.*/
652 }
653 /* not a FPU inst. */
654#endif
655
656 asm volatile("stc r2_bank, %0": "=r" (error_code));
657 local_irq_enable();
658 tsk->thread.error_code = error_code;
659 tsk->thread.trap_no = TRAP_RESERVED_INST;
660 CHK_REMOTE_DEBUG(&regs);
661 force_sig(SIGILL, tsk);
662 die_if_no_fixup("illegal slot instruction", &regs, error_code);
663}
580 664
581asmlinkage void do_exception_error(unsigned long r4, unsigned long r5, 665asmlinkage void do_exception_error(unsigned long r4, unsigned long r5,
582 unsigned long r6, unsigned long r7, 666 unsigned long r6, unsigned long r7,
@@ -634,14 +718,16 @@ void __init trap_init(void)
634 exception_handling_table[TRAP_ILLEGAL_SLOT_INST] 718 exception_handling_table[TRAP_ILLEGAL_SLOT_INST]
635 = (void *)do_illegal_slot_inst; 719 = (void *)do_illegal_slot_inst;
636 720
637#ifdef CONFIG_CPU_SH4 721#if defined(CONFIG_CPU_SH4) && !defined(CONFIG_SH_FPU) || \
638 if (!(cpu_data->flags & CPU_HAS_FPU)) { 722 defined(CONFIG_SH_FPU_EMU)
639 /* For SH-4 lacking an FPU, treat floating point instructions 723 /*
640 as reserved. */ 724 * For SH-4 lacking an FPU, treat floating point instructions as
641 /* entry 64 corresponds to EXPEVT=0x800 */ 725 * reserved. They'll be handled in the math-emu case, or faulted on
642 exception_handling_table[64] = (void *)do_reserved_inst; 726 * otherwise.
643 exception_handling_table[65] = (void *)do_illegal_slot_inst; 727 */
644 } 728 /* entry 64 corresponds to EXPEVT=0x800 */
729 exception_handling_table[64] = (void *)do_reserved_inst;
730 exception_handling_table[65] = (void *)do_illegal_slot_inst;
645#endif 731#endif
646 732
647 /* Setup VBR for boot cpu */ 733 /* Setup VBR for boot cpu */
@@ -655,20 +741,12 @@ void show_stack(struct task_struct *tsk, unsigned long *sp)
655 unsigned long module_end = VMALLOC_END; 741 unsigned long module_end = VMALLOC_END;
656 int i = 1; 742 int i = 1;
657 743
658 if (tsk && !sp) { 744 if (!tsk)
745 tsk = current;
746 if (tsk == current)
747 sp = (unsigned long *)current_stack_pointer;
748 else
659 sp = (unsigned long *)tsk->thread.sp; 749 sp = (unsigned long *)tsk->thread.sp;
660 }
661
662 if (!sp) {
663 __asm__ __volatile__ (
664 "mov r15, %0\n\t"
665 "stc r7_bank, %1\n\t"
666 : "=r" (module_start),
667 "=r" (module_end)
668 );
669
670 sp = (unsigned long *)module_start;
671 }
672 750
673 stack = sp; 751 stack = sp;
674 752
diff --git a/arch/sh/kernel/vmlinux.lds.S b/arch/sh/kernel/vmlinux.lds.S
index 95fdd9135fcf..5eb930918186 100644
--- a/arch/sh/kernel/vmlinux.lds.S
+++ b/arch/sh/kernel/vmlinux.lds.S
@@ -2,6 +2,7 @@
2 * ld script to make SuperH Linux kernel 2 * ld script to make SuperH Linux kernel
3 * Written by Niibe Yutaka 3 * Written by Niibe Yutaka
4 */ 4 */
5#include <asm/thread_info.h>
5#include <asm-generic/vmlinux.lds.h> 6#include <asm-generic/vmlinux.lds.h>
6 7
7#ifdef CONFIG_CPU_LITTLE_ENDIAN 8#ifdef CONFIG_CPU_LITTLE_ENDIAN
@@ -13,7 +14,7 @@ OUTPUT_ARCH(sh)
13ENTRY(_start) 14ENTRY(_start)
14SECTIONS 15SECTIONS
15{ 16{
16 . = 0x80000000 + CONFIG_MEMORY_START + CONFIG_ZERO_PAGE_OFFSET; 17 . = CONFIG_PAGE_OFFSET + CONFIG_MEMORY_START + CONFIG_ZERO_PAGE_OFFSET;
17 _text = .; /* Text and read-only data */ 18 _text = .; /* Text and read-only data */
18 text = .; /* Text and read-only data */ 19 text = .; /* Text and read-only data */
19 .empty_zero_page : { 20 .empty_zero_page : {
@@ -40,16 +41,16 @@ SECTIONS
40 *(.data) 41 *(.data)
41 42
42 /* Align the initial ramdisk image (INITRD) on page boundaries. */ 43 /* Align the initial ramdisk image (INITRD) on page boundaries. */
43 . = ALIGN(4096); 44 . = ALIGN(PAGE_SIZE);
44 __rd_start = .; 45 __rd_start = .;
45 *(.initrd) 46 *(.initrd)
46 . = ALIGN(4096); 47 . = ALIGN(PAGE_SIZE);
47 __rd_end = .; 48 __rd_end = .;
48 49
49 CONSTRUCTORS 50 CONSTRUCTORS
50 } 51 }
51 52
52 . = ALIGN(4096); 53 . = ALIGN(PAGE_SIZE);
53 .data.page_aligned : { *(.data.idt) } 54 .data.page_aligned : { *(.data.idt) }
54 55
55 . = ALIGN(32); 56 . = ALIGN(32);
@@ -60,12 +61,10 @@ SECTIONS
60 61
61 _edata = .; /* End of data section */ 62 _edata = .; /* End of data section */
62 63
63 . = ALIGN(8192); /* init_task */ 64 . = ALIGN(THREAD_SIZE); /* init_task */
64 .data.init_task : { *(.data.init_task) } 65 .data.init_task : { *(.data.init_task) }
65 /* stack */
66 .stack : { stack = .; _stack = .; }
67 66
68 . = ALIGN(4096); /* Init code and data */ 67 . = ALIGN(PAGE_SIZE); /* Init code and data */
69 __init_begin = .; 68 __init_begin = .;
70 _sinittext = .; 69 _sinittext = .;
71 .init.text : { *(.init.text) } 70 .init.text : { *(.init.text) }
@@ -96,7 +95,7 @@ SECTIONS
96 __machvec_start = .; 95 __machvec_start = .;
97 .init.machvec : { *(.init.machvec) } 96 .init.machvec : { *(.init.machvec) }
98 __machvec_end = .; 97 __machvec_end = .;
99 . = ALIGN(4096); 98 . = ALIGN(PAGE_SIZE);
100 __init_end = .; 99 __init_end = .;
101 100
102 . = ALIGN(4); 101 . = ALIGN(4);
diff --git a/arch/sh/kernel/vsyscall/Makefile b/arch/sh/kernel/vsyscall/Makefile
new file mode 100644
index 000000000000..4bbce1cfa359
--- /dev/null
+++ b/arch/sh/kernel/vsyscall/Makefile
@@ -0,0 +1,36 @@
1obj-y += vsyscall.o vsyscall-syscall.o
2
3$(obj)/vsyscall-syscall.o: \
4 $(foreach F,trapa,$(obj)/vsyscall-$F.so)
5
6# Teach kbuild about targets
7targets += $(foreach F,trapa,vsyscall-$F.o vsyscall-$F.so)
8targets += vsyscall-note.o vsyscall.lds
9
10# The DSO images are built using a special linker script
11quiet_cmd_syscall = SYSCALL $@
12 cmd_syscall = $(CC) -nostdlib $(SYSCFLAGS_$(@F)) \
13 -Wl,-T,$(filter-out FORCE,$^) -o $@
14
15export CPPFLAGS_vsyscall.lds += -P -C -Ush
16
17vsyscall-flags = -shared -s -Wl,-soname=linux-gate.so.1 \
18 $(call ld-option, -Wl$(comma)--hash-style=sysv)
19
20SYSCFLAGS_vsyscall-trapa.so = $(vsyscall-flags)
21
22$(obj)/vsyscall-trapa.so: \
23$(obj)/vsyscall-%.so: $(src)/vsyscall.lds $(obj)/vsyscall-%.o FORCE
24 $(call if_changed,syscall)
25
26# We also create a special relocatable object that should mirror the symbol
27# table and layout of the linked DSO. With ld -R we can then refer to
28# these symbols in the kernel code rather than hand-coded addresses.
29extra-y += vsyscall-syms.o
30$(obj)/built-in.o: $(obj)/vsyscall-syms.o
31$(obj)/built-in.o: ld_flags += -R $(obj)/vsyscall-syms.o
32
33SYSCFLAGS_vsyscall-syms.o = -r
34$(obj)/vsyscall-syms.o: $(src)/vsyscall.lds \
35 $(obj)/vsyscall-trapa.o $(obj)/vsyscall-note.o FORCE
36 $(call if_changed,syscall)
diff --git a/arch/sh/kernel/vsyscall/vsyscall-note.S b/arch/sh/kernel/vsyscall/vsyscall-note.S
new file mode 100644
index 000000000000..d4b5be4f3d5f
--- /dev/null
+++ b/arch/sh/kernel/vsyscall/vsyscall-note.S
@@ -0,0 +1,25 @@
1/*
2 * This supplies .note.* sections to go into the PT_NOTE inside the vDSO text.
3 * Here we can supply some information useful to userland.
4 */
5
6#include <linux/uts.h>
7#include <linux/version.h>
8
9#define ASM_ELF_NOTE_BEGIN(name, flags, vendor, type) \
10 .section name, flags; \
11 .balign 4; \
12 .long 1f - 0f; /* name length */ \
13 .long 3f - 2f; /* data length */ \
14 .long type; /* note type */ \
150: .asciz vendor; /* vendor name */ \
161: .balign 4; \
172:
18
19#define ASM_ELF_NOTE_END \
203: .balign 4; /* pad out section */ \
21 .previous
22
23 ASM_ELF_NOTE_BEGIN(".note.kernel-version", "a", UTS_SYSNAME, 0)
24 .long LINUX_VERSION_CODE
25 ASM_ELF_NOTE_END
diff --git a/arch/sh/kernel/vsyscall/vsyscall-sigreturn.S b/arch/sh/kernel/vsyscall/vsyscall-sigreturn.S
new file mode 100644
index 000000000000..555a64f124ca
--- /dev/null
+++ b/arch/sh/kernel/vsyscall/vsyscall-sigreturn.S
@@ -0,0 +1,39 @@
1#include <asm/unistd.h>
2
3 .text
4 .balign 32
5 .globl __kernel_sigreturn
6 .type __kernel_sigreturn,@function
7__kernel_sigreturn:
8.LSTART_sigreturn:
9 mov.w 1f, r3
10 trapa #0x10
11 or r0, r0
12 or r0, r0
13 or r0, r0
14 or r0, r0
15 or r0, r0
16
171: .short __NR_sigreturn
18.LEND_sigreturn:
19 .size __kernel_sigreturn,.-.LSTART_sigreturn
20
21 .balign 32
22 .globl __kernel_rt_sigreturn
23 .type __kernel_rt_sigreturn,@function
24__kernel_rt_sigreturn:
25.LSTART_rt_sigreturn:
26 mov.w 1f, r3
27 trapa #0x10
28 or r0, r0
29 or r0, r0
30 or r0, r0
31 or r0, r0
32 or r0, r0
33
341: .short __NR_rt_sigreturn
35.LEND_rt_sigreturn:
36 .size __kernel_rt_sigreturn,.-.LSTART_rt_sigreturn
37
38 .section .eh_frame,"a",@progbits
39 .previous
diff --git a/arch/sh/kernel/vsyscall/vsyscall-syscall.S b/arch/sh/kernel/vsyscall/vsyscall-syscall.S
new file mode 100644
index 000000000000..c2ac7f0282b3
--- /dev/null
+++ b/arch/sh/kernel/vsyscall/vsyscall-syscall.S
@@ -0,0 +1,10 @@
1#include <linux/init.h>
2
3__INITDATA
4
5 .globl vsyscall_trapa_start, vsyscall_trapa_end
6vsyscall_trapa_start:
7 .incbin "arch/sh/kernel/vsyscall/vsyscall-trapa.so"
8vsyscall_trapa_end:
9
10__FINIT
diff --git a/arch/sh/kernel/vsyscall/vsyscall-trapa.S b/arch/sh/kernel/vsyscall/vsyscall-trapa.S
new file mode 100644
index 000000000000..3b6eb34c43fa
--- /dev/null
+++ b/arch/sh/kernel/vsyscall/vsyscall-trapa.S
@@ -0,0 +1,42 @@
1 .text
2 .globl __kernel_vsyscall
3 .type __kernel_vsyscall,@function
4__kernel_vsyscall:
5.LSTART_vsyscall:
6 /* XXX: We'll have to do something here once we opt to use the vDSO
7 * page for something other than the signal trampoline.. as well as
8 * fill out .eh_frame -- PFM. */
9.LEND_vsyscall:
10 .size __kernel_vsyscall,.-.LSTART_vsyscall
11 .previous
12
13 .section .eh_frame,"a",@progbits
14.LCIE:
15 .ualong .LCIE_end - .LCIE_start
16.LCIE_start:
17 .ualong 0 /* CIE ID */
18 .byte 0x1 /* Version number */
19 .string "zRS" /* NUL-terminated augmentation string */
20 .uleb128 0x1 /* Code alignment factor */
21 .sleb128 -4 /* Data alignment factor */
22 .byte 0x11 /* Return address register column */
23 /* Augmentation length and data (none) */
24 .byte 0xc /* DW_CFA_def_cfa */
25 .uleb128 0xf /* r15 */
26 .uleb128 0x0 /* offset 0 */
27
28 .align 2
29.LCIE_end:
30
31 .ualong .LFDE_end-.LFDE_start /* Length FDE */
32.LFDE_start:
33 .ualong .LCIE /* CIE pointer */
34 .ualong .LSTART_vsyscall-. /* start address */
35 .ualong .LEND_vsyscall-.LSTART_vsyscall
36 .uleb128 0
37 .align 2
38.LFDE_end:
39 .previous
40
41/* Get the common code for the sigreturn entry points */
42#include "vsyscall-sigreturn.S"
diff --git a/arch/sh/kernel/vsyscall/vsyscall.c b/arch/sh/kernel/vsyscall/vsyscall.c
new file mode 100644
index 000000000000..075d6cc1a2d7
--- /dev/null
+++ b/arch/sh/kernel/vsyscall/vsyscall.c
@@ -0,0 +1,150 @@
1/*
2 * arch/sh/kernel/vsyscall.c
3 *
4 * Copyright (C) 2006 Paul Mundt
5 *
6 * vDSO randomization
7 * Copyright(C) 2005-2006, Red Hat, Inc., Ingo Molnar
8 *
9 * This file is subject to the terms and conditions of the GNU General Public
10 * License. See the file "COPYING" in the main directory of this archive
11 * for more details.
12 */
13#include <linux/mm.h>
14#include <linux/slab.h>
15#include <linux/kernel.h>
16#include <linux/init.h>
17#include <linux/gfp.h>
18#include <linux/module.h>
19#include <linux/elf.h>
20
21/*
22 * Should the kernel map a VDSO page into processes and pass its
23 * address down to glibc upon exec()?
24 */
25unsigned int __read_mostly vdso_enabled = 1;
26EXPORT_SYMBOL_GPL(vdso_enabled);
27
28static int __init vdso_setup(char *s)
29{
30 vdso_enabled = simple_strtoul(s, NULL, 0);
31 return 1;
32}
33__setup("vdso=", vdso_setup);
34
35/*
36 * These symbols are defined by vsyscall.o to mark the bounds
37 * of the ELF DSO images included therein.
38 */
39extern const char vsyscall_trapa_start, vsyscall_trapa_end;
40static void *syscall_page;
41
42int __init vsyscall_init(void)
43{
44 syscall_page = (void *)get_zeroed_page(GFP_ATOMIC);
45
46 /*
47 * XXX: Map this page to a fixmap entry if we get around
48 * to adding the page to ELF core dumps
49 */
50
51 memcpy(syscall_page,
52 &vsyscall_trapa_start,
53 &vsyscall_trapa_end - &vsyscall_trapa_start);
54
55 return 0;
56}
57
58static struct page *syscall_vma_nopage(struct vm_area_struct *vma,
59 unsigned long address, int *type)
60{
61 unsigned long offset = address - vma->vm_start;
62 struct page *page;
63
64 if (address < vma->vm_start || address > vma->vm_end)
65 return NOPAGE_SIGBUS;
66
67 page = virt_to_page(syscall_page + offset);
68
69 get_page(page);
70
71 return page;
72}
73
74/* Prevent VMA merging */
75static void syscall_vma_close(struct vm_area_struct *vma)
76{
77}
78
79static struct vm_operations_struct syscall_vm_ops = {
80 .nopage = syscall_vma_nopage,
81 .close = syscall_vma_close,
82};
83
84/* Setup a VMA at program startup for the vsyscall page */
85int arch_setup_additional_pages(struct linux_binprm *bprm,
86 int executable_stack)
87{
88 struct vm_area_struct *vma;
89 struct mm_struct *mm = current->mm;
90 unsigned long addr;
91 int ret;
92
93 down_write(&mm->mmap_sem);
94 addr = get_unmapped_area(NULL, 0, PAGE_SIZE, 0, 0);
95 if (IS_ERR_VALUE(addr)) {
96 ret = addr;
97 goto up_fail;
98 }
99
100 vma = kmem_cache_zalloc(vm_area_cachep, SLAB_KERNEL);
101 if (!vma) {
102 ret = -ENOMEM;
103 goto up_fail;
104 }
105
106 vma->vm_start = addr;
107 vma->vm_end = addr + PAGE_SIZE;
108 /* MAYWRITE to allow gdb to COW and set breakpoints */
109 vma->vm_flags = VM_READ|VM_EXEC|VM_MAYREAD|VM_MAYEXEC|VM_MAYWRITE;
110 vma->vm_flags |= mm->def_flags;
111 vma->vm_page_prot = protection_map[vma->vm_flags & 7];
112 vma->vm_ops = &syscall_vm_ops;
113 vma->vm_mm = mm;
114
115 ret = insert_vm_struct(mm, vma);
116 if (unlikely(ret)) {
117 kmem_cache_free(vm_area_cachep, vma);
118 goto up_fail;
119 }
120
121 current->mm->context.vdso = (void *)addr;
122
123 mm->total_vm++;
124up_fail:
125 up_write(&mm->mmap_sem);
126 return ret;
127}
128
129const char *arch_vma_name(struct vm_area_struct *vma)
130{
131 if (vma->vm_mm && vma->vm_start == (long)vma->vm_mm->context.vdso)
132 return "[vdso]";
133
134 return NULL;
135}
136
137struct vm_area_struct *get_gate_vma(struct task_struct *task)
138{
139 return NULL;
140}
141
142int in_gate_area(struct task_struct *task, unsigned long address)
143{
144 return 0;
145}
146
147int in_gate_area_no_task(unsigned long address)
148{
149 return 0;
150}
diff --git a/arch/sh/kernel/vsyscall/vsyscall.lds.S b/arch/sh/kernel/vsyscall/vsyscall.lds.S
new file mode 100644
index 000000000000..b13c3d439fee
--- /dev/null
+++ b/arch/sh/kernel/vsyscall/vsyscall.lds.S
@@ -0,0 +1,74 @@
1/*
2 * Linker script for vsyscall DSO. The vsyscall page is an ELF shared
3 * object prelinked to its virtual address, and with only one read-only
4 * segment (that fits in one page). This script controls its layout.
5 */
6#include <asm/asm-offsets.h>
7
8#ifdef CONFIG_CPU_LITTLE_ENDIAN
9OUTPUT_FORMAT("elf32-sh-linux", "elf32-sh-linux", "elf32-sh-linux")
10#else
11OUTPUT_FORMAT("elf32-shbig-linux", "elf32-shbig-linux", "elf32-shbig-linux")
12#endif
13OUTPUT_ARCH(sh)
14
15/* The ELF entry point can be used to set the AT_SYSINFO value. */
16ENTRY(__kernel_vsyscall);
17
18SECTIONS
19{
20 . = SIZEOF_HEADERS;
21
22 .hash : { *(.hash) } :text
23 .gnu.hash : { *(.gnu.hash) }
24 .dynsym : { *(.dynsym) }
25 .dynstr : { *(.dynstr) }
26 .gnu.version : { *(.gnu.version) }
27 .gnu.version_d : { *(.gnu.version_d) }
28 .gnu.version_r : { *(.gnu.version_r) }
29
30 /* This linker script is used both with -r and with -shared.
31 For the layouts to match, we need to skip more than enough
32 space for the dynamic symbol table et al. If this amount
33 is insufficient, ld -shared will barf. Just increase it here. */
34 . = 0x400;
35
36 .text : { *(.text) } :text =0x90909090
37 .note : { *(.note.*) } :text :note
38 .eh_frame_hdr : { *(.eh_frame_hdr) } :text :eh_frame_hdr
39 .eh_frame : { KEEP (*(.eh_frame)) } :text
40 .dynamic : { *(.dynamic) } :text :dynamic
41 .useless : {
42 *(.got.plt) *(.got)
43 *(.data .data.* .gnu.linkonce.d.*)
44 *(.dynbss)
45 *(.bss .bss.* .gnu.linkonce.b.*)
46 } :text
47}
48
49/*
50 * We must supply the ELF program headers explicitly to get just one
51 * PT_LOAD segment, and set the flags explicitly to make segments read-only.
52 */
53PHDRS
54{
55 text PT_LOAD FILEHDR PHDRS FLAGS(5); /* PF_R|PF_X */
56 dynamic PT_DYNAMIC FLAGS(4); /* PF_R */
57 note PT_NOTE FLAGS(4); /* PF_R */
58 eh_frame_hdr 0x6474e550; /* PT_GNU_EH_FRAME, but ld doesn't match the name */
59}
60
61/*
62 * This controls what symbols we export from the DSO.
63 */
64VERSION
65{
66 LINUX_2.6 {
67 global:
68 __kernel_vsyscall;
69 __kernel_sigreturn;
70 __kernel_rt_sigreturn;
71
72 local: *;
73 };
74}