diff options
Diffstat (limited to 'arch/sh/kernel')
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 | ||
7 | obj-y := process.o signal.o entry.o traps.o irq.o \ | 7 | obj-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 | ||
11 | obj-y += cpu/ timers/ | 11 | obj-y += cpu/ timers/ |
12 | obj-$(CONFIG_VSYSCALL) += vsyscall/ | ||
12 | 13 | ||
13 | obj-$(CONFIG_SMP) += smp.o | 14 | obj-$(CONFIG_SMP) += smp.o |
14 | obj-$(CONFIG_CF_ENABLER) += cf-enabler.o | 15 | obj-$(CONFIG_CF_ENABLER) += cf-enabler.o |
@@ -18,3 +19,5 @@ obj-$(CONFIG_SH_CPU_FREQ) += cpufreq.o | |||
18 | obj-$(CONFIG_MODULES) += module.o | 19 | obj-$(CONFIG_MODULES) += module.o |
19 | obj-$(CONFIG_EARLY_PRINTK) += early_printk.o | 20 | obj-$(CONFIG_EARLY_PRINTK) += early_printk.o |
20 | obj-$(CONFIG_KEXEC) += machine_kexec.o relocate_kernel.o | 21 | obj-$(CONFIG_KEXEC) += machine_kexec.o relocate_kernel.o |
22 | obj-$(CONFIG_APM) += apm.o | ||
23 | obj-$(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 | |||
44 | struct 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 | */ | ||
53 | struct 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 | */ | ||
74 | static int suspends_pending; | ||
75 | |||
76 | static DECLARE_WAIT_QUEUE_HEAD(apm_waitqueue); | ||
77 | static DECLARE_WAIT_QUEUE_HEAD(apm_suspend_waitqueue); | ||
78 | |||
79 | /* | ||
80 | * This is a list of everyone who has opened /dev/apm_bios | ||
81 | */ | ||
82 | static DECLARE_RWSEM(user_list_lock); | ||
83 | static 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 | */ | ||
90 | static DECLARE_WAIT_QUEUE_HEAD(kapmd_wait); | ||
91 | static DECLARE_COMPLETION(kapmd_exit); | ||
92 | static DEFINE_SPINLOCK(kapmd_queue_lock); | ||
93 | static struct apm_queue kapmd_queue; | ||
94 | |||
95 | int apm_suspended; | ||
96 | EXPORT_SYMBOL(apm_suspended); | ||
97 | |||
98 | /* Platform-specific apm_read_proc(). */ | ||
99 | int (*apm_get_info)(char *buf, char **start, off_t fpos, int length); | ||
100 | EXPORT_SYMBOL(apm_get_info); | ||
101 | |||
102 | /* | ||
103 | * APM event queue management. | ||
104 | */ | ||
105 | static inline int queue_empty(struct apm_queue *q) | ||
106 | { | ||
107 | return q->event_head == q->event_tail; | ||
108 | } | ||
109 | |||
110 | static 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 | |||
116 | static 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 | |||
130 | static 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 | |||
151 | static 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 | */ | ||
177 | void 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 | } | ||
185 | EXPORT_SYMBOL(apm_queue_event); | ||
186 | |||
187 | static 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 | |||
215 | static 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 | |||
250 | static 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 | */ | ||
268 | static int | ||
269 | apm_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 | |||
337 | static 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 | |||
362 | static 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 | |||
389 | static 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 | |||
398 | static 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 | */ | ||
444 | static 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 | |||
453 | static 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 | |||
498 | static 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 | |||
524 | static 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 | |||
534 | module_init(apm_init); | ||
535 | module_exit(apm_exit); | ||
536 | |||
537 | MODULE_AUTHOR("Stephen Rothwell, Andriy Skulysh"); | ||
538 | MODULE_DESCRIPTION("Advanced Power Management"); | ||
539 | MODULE_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 */ | ||
45 | extern 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*/ |
48 | void *cf_io_base; | 44 | void *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/ | |||
8 | obj-$(CONFIG_CPU_SH3) += sh3/ | 8 | obj-$(CONFIG_CPU_SH3) += sh3/ |
9 | obj-$(CONFIG_CPU_SH4) += sh4/ | 9 | obj-$(CONFIG_CPU_SH4) += sh4/ |
10 | 10 | ||
11 | obj-$(CONFIG_SH_RTC) += rtc.o | ||
12 | obj-$(CONFIG_UBC_WAKEUP) += ubc.o | 11 | obj-$(CONFIG_UBC_WAKEUP) += ubc.o |
13 | obj-$(CONFIG_SH_ADC) += adc.o | 12 | obj-$(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 | ||
25 | static LIST_HEAD(clock_list); | 26 | static LIST_HEAD(clock_list); |
26 | static DEFINE_SPINLOCK(clock_lock); | 27 | static DEFINE_SPINLOCK(clock_lock); |
27 | static DECLARE_MUTEX(clock_list_sem); | 28 | static 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 | ||
141 | int clk_register(struct clk *clk) | 142 | int 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 | ||
153 | void clk_unregister(struct clk *clk) | 154 | void 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 | ||
160 | inline unsigned long clk_get_rate(struct clk *clk) | 161 | inline 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 | # |
4 | obj-y += ipr.o imask.o | 4 | obj-y += ipr.o imask.o |
5 | 5 | ||
6 | obj-$(CONFIG_CPU_HAS_PINT_IRQ) += pint.o | 6 | obj-$(CONFIG_CPU_HAS_PINT_IRQ) += pint.o |
7 | obj-$(CONFIG_CPU_HAS_INTC2_IRQ) += intc2.o | 7 | obj-$(CONFIG_CPU_HAS_MASKREG_IRQ) += maskreg.o |
8 | obj-$(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 | ||
58 | static void disable_ipr_irq(unsigned int irq) | 58 | static 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 | ||
72 | static void enable_ipr_irq(unsigned int irq) | 70 | static 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 | ||
87 | static void mask_and_ack_ipr(unsigned int irq) | 83 | static 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 */ | ||
20 | unsigned long irq_mask_register; | ||
21 | |||
22 | /* forward declaration */ | ||
23 | static unsigned int startup_maskreg_irq(unsigned int irq); | ||
24 | static void shutdown_maskreg_irq(unsigned int irq); | ||
25 | static void enable_maskreg_irq(unsigned int irq); | ||
26 | static void disable_maskreg_irq(unsigned int irq); | ||
27 | static void mask_and_ack_maskreg(unsigned int); | ||
28 | static void end_maskreg_irq(unsigned int irq); | ||
29 | |||
30 | /* hw_interrupt_type */ | ||
31 | static 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 */ | ||
42 | static unsigned int startup_maskreg_irq(unsigned int irq) | ||
43 | { | ||
44 | enable_maskreg_irq(irq); | ||
45 | return 0; /* never anything pending */ | ||
46 | } | ||
47 | |||
48 | static void shutdown_maskreg_irq(unsigned int irq) | ||
49 | { | ||
50 | disable_maskreg_irq(irq); | ||
51 | } | ||
52 | |||
53 | static 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 | |||
65 | static 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 | |||
77 | static void mask_and_ack_maskreg(unsigned int irq) | ||
78 | { | ||
79 | disable_maskreg_irq(irq); | ||
80 | } | ||
81 | |||
82 | static 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 | |||
88 | void 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 | ||
49 | static void disable_pint_irq(unsigned int irq) | 49 | static 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 | ||
61 | static void enable_pint_irq(unsigned int irq) | 59 | static 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 | ||
73 | static void mask_and_ack_pint(unsigned int irq) | 69 | static 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 | |||
16 | void 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 | */ | ||
88 | int 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 | ||
5 | obj-y := ex.o probe.o | 5 | obj-y := ex.o probe.o |
6 | 6 | ||
7 | # CPU subtype setup | ||
8 | obj-$(CONFIG_CPU_SUBTYPE_SH7705) += setup-sh7705.o | ||
9 | obj-$(CONFIG_CPU_SUBTYPE_SH7706) += setup-sh7709.o | ||
10 | obj-$(CONFIG_CPU_SUBTYPE_SH7707) += setup-sh7709.o | ||
11 | obj-$(CONFIG_CPU_SUBTYPE_SH7708) += setup-sh7708.o | ||
12 | obj-$(CONFIG_CPU_SUBTYPE_SH7709) += setup-sh7709.o | ||
13 | obj-$(CONFIG_CPU_SUBTYPE_SH7300) += setup-sh7300.o | ||
14 | obj-$(CONFIG_CPU_SUBTYPE_SH7710) += setup-sh7710.o | ||
15 | |||
16 | # Primary on-chip clocks (common) | ||
7 | clock-$(CONFIG_CPU_SH3) := clock-sh3.o | 17 | clock-$(CONFIG_CPU_SH3) := clock-sh3.o |
8 | clock-$(CONFIG_CPU_SUBTYPE_SH7300) := clock-sh7300.o | 18 | clock-$(CONFIG_CPU_SUBTYPE_SH7300) := clock-sh7300.o |
9 | clock-$(CONFIG_CPU_SUBTYPE_SH7705) := clock-sh7705.o | 19 | clock-$(CONFIG_CPU_SUBTYPE_SH7705) := clock-sh7705.o |
20 | clock-$(CONFIG_CPU_SUBTYPE_SH7706) := clock-sh7706.o | ||
10 | clock-$(CONFIG_CPU_SUBTYPE_SH7709) := clock-sh7709.o | 21 | clock-$(CONFIG_CPU_SUBTYPE_SH7709) := clock-sh7709.o |
22 | clock-$(CONFIG_CPU_SUBTYPE_SH7710) := clock-sh7300.o | ||
11 | 23 | ||
12 | obj-y += $(clock-y) | 24 | obj-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 | |||
21 | static int stc_multipliers[] = { 1, 2, 4, 1, 3, 6, 1, 1 }; | ||
22 | static int ifc_divisors[] = { 1, 2, 4, 1, 3, 1, 1, 1 }; | ||
23 | static int pfc_divisors[] = { 1, 2, 4, 1, 3, 6, 1, 1 }; | ||
24 | |||
25 | static 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 | |||
33 | static struct clk_ops sh7706_master_clk_ops = { | ||
34 | .init = master_clk_init, | ||
35 | }; | ||
36 | |||
37 | static 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 | |||
45 | static struct clk_ops sh7706_module_clk_ops = { | ||
46 | .recalc = module_clk_recalc, | ||
47 | }; | ||
48 | |||
49 | static 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 | |||
57 | static struct clk_ops sh7706_bus_clk_ops = { | ||
58 | .recalc = bus_clk_recalc, | ||
59 | }; | ||
60 | |||
61 | static 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 | |||
69 | static struct clk_ops sh7706_cpu_clk_ops = { | ||
70 | .recalc = cpu_clk_recalc, | ||
71 | }; | ||
72 | |||
73 | static 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 | |||
80 | void __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 | |||
15 | static 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 | |||
26 | static struct platform_device sci_device = { | ||
27 | .name = "sh-sci", | ||
28 | .id = -1, | ||
29 | .dev = { | ||
30 | .platform_data = sci_platform_data, | ||
31 | }, | ||
32 | }; | ||
33 | |||
34 | static struct platform_device *sh7300_devices[] __initdata = { | ||
35 | &sci_device, | ||
36 | }; | ||
37 | |||
38 | static 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 | |||
15 | static 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 | |||
31 | static struct platform_device sci_device = { | ||
32 | .name = "sh-sci", | ||
33 | .id = -1, | ||
34 | .dev = { | ||
35 | .platform_data = sci_platform_data, | ||
36 | }, | ||
37 | }; | ||
38 | |||
39 | static struct platform_device *sh7705_devices[] __initdata = { | ||
40 | &sci_device, | ||
41 | }; | ||
42 | |||
43 | static 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 | |||
15 | static 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 | |||
26 | static struct platform_device sci_device = { | ||
27 | .name = "sh-sci", | ||
28 | .id = -1, | ||
29 | .dev = { | ||
30 | .platform_data = sci_platform_data, | ||
31 | }, | ||
32 | }; | ||
33 | |||
34 | static struct platform_device *sh7708_devices[] __initdata = { | ||
35 | &sci_device, | ||
36 | }; | ||
37 | |||
38 | static 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 | |||
15 | static 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 | |||
36 | static struct platform_device sci_device = { | ||
37 | .name = "sh-sci", | ||
38 | .id = -1, | ||
39 | .dev = { | ||
40 | .platform_data = sci_platform_data, | ||
41 | }, | ||
42 | }; | ||
43 | |||
44 | static struct platform_device *sh7709_devices[] __initdata = { | ||
45 | &sci_device, | ||
46 | }; | ||
47 | |||
48 | static 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 | |||
15 | static 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 | |||
26 | static struct platform_device sci_device = { | ||
27 | .name = "sh-sci", | ||
28 | .id = -1, | ||
29 | .dev = { | ||
30 | .platform_data = sci_platform_data, | ||
31 | }, | ||
32 | }; | ||
33 | |||
34 | static struct platform_device *sh7710_devices[] __initdata = { | ||
35 | &sci_device, | ||
36 | }; | ||
37 | |||
38 | static 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 | |||
7 | obj-$(CONFIG_SH_FPU) += fpu.o | 7 | obj-$(CONFIG_SH_FPU) += fpu.o |
8 | obj-$(CONFIG_SH_STORE_QUEUES) += sq.o | 8 | obj-$(CONFIG_SH_STORE_QUEUES) += sq.o |
9 | 9 | ||
10 | # CPU subtype setup | ||
11 | obj-$(CONFIG_CPU_SUBTYPE_SH7750) += setup-sh7750.o | ||
12 | obj-$(CONFIG_CPU_SUBTYPE_SH7751) += setup-sh7750.o | ||
13 | obj-$(CONFIG_CPU_SUBTYPE_SH7760) += setup-sh7760.o | ||
14 | obj-$(CONFIG_CPU_SUBTYPE_SH7770) += setup-sh7770.o | ||
15 | obj-$(CONFIG_CPU_SUBTYPE_SH7780) += setup-sh7780.o | ||
16 | obj-$(CONFIG_CPU_SUBTYPE_SH73180) += setup-sh73180.o | ||
17 | obj-$(CONFIG_CPU_SUBTYPE_SH7343) += setup-sh7343.o | ||
18 | obj-$(CONFIG_CPU_SUBTYPE_SH4_202) += setup-sh4-202.o | ||
19 | |||
10 | # Primary on-chip clocks (common) | 20 | # Primary on-chip clocks (common) |
11 | clock-$(CONFIG_CPU_SH4) := clock-sh4.o | 21 | clock-$(CONFIG_CPU_SH4) := clock-sh4.o |
12 | clock-$(CONFIG_CPU_SUBTYPE_SH73180) := clock-sh73180.o | 22 | clock-$(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 | |||
15 | static 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 | |||
26 | static struct platform_device sci_device = { | ||
27 | .name = "sh-sci", | ||
28 | .id = -1, | ||
29 | .dev = { | ||
30 | .platform_data = sci_platform_data, | ||
31 | }, | ||
32 | }; | ||
33 | |||
34 | static struct platform_device *sh4202_devices[] __initdata = { | ||
35 | &sci_device, | ||
36 | }; | ||
37 | |||
38 | static 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 | |||
15 | static 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 | |||
26 | static struct platform_device sci_device = { | ||
27 | .name = "sh-sci", | ||
28 | .id = -1, | ||
29 | .dev = { | ||
30 | .platform_data = sci_platform_data, | ||
31 | }, | ||
32 | }; | ||
33 | |||
34 | static struct platform_device *sh73180_devices[] __initdata = { | ||
35 | &sci_device, | ||
36 | }; | ||
37 | |||
38 | static 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 | |||
15 | static 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 | |||
26 | static struct platform_device sci_device = { | ||
27 | .name = "sh-sci", | ||
28 | .id = -1, | ||
29 | .dev = { | ||
30 | .platform_data = sci_platform_data, | ||
31 | }, | ||
32 | }; | ||
33 | |||
34 | static struct platform_device *sh7343_devices[] __initdata = { | ||
35 | &sci_device, | ||
36 | }; | ||
37 | |||
38 | static 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 | |||
15 | static 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 | |||
31 | static struct platform_device sci_device = { | ||
32 | .name = "sh-sci", | ||
33 | .id = -1, | ||
34 | .dev = { | ||
35 | .platform_data = sci_platform_data, | ||
36 | }, | ||
37 | }; | ||
38 | |||
39 | static struct platform_device *sh7750_devices[] __initdata = { | ||
40 | &sci_device, | ||
41 | }; | ||
42 | |||
43 | static 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 | |||
15 | static 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 | |||
36 | static struct platform_device sci_device = { | ||
37 | .name = "sh-sci", | ||
38 | .id = -1, | ||
39 | .dev = { | ||
40 | .platform_data = sci_platform_data, | ||
41 | }, | ||
42 | }; | ||
43 | |||
44 | static struct platform_device *sh7760_devices[] __initdata = { | ||
45 | &sci_device, | ||
46 | }; | ||
47 | |||
48 | static 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 | |||
15 | static 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 | |||
36 | static struct platform_device sci_device = { | ||
37 | .name = "sh-sci", | ||
38 | .id = -1, | ||
39 | .dev = { | ||
40 | .platform_data = sci_platform_data, | ||
41 | }, | ||
42 | }; | ||
43 | |||
44 | static struct platform_device *sh7770_devices[] __initdata = { | ||
45 | &sci_device, | ||
46 | }; | ||
47 | |||
48 | static 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 | |||
15 | static 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 | |||
38 | static 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 | |||
45 | static 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 | |||
61 | static struct platform_device sci_device = { | ||
62 | .name = "sh-sci", | ||
63 | .id = -1, | ||
64 | .dev = { | ||
65 | .platform_data = sci_platform_data, | ||
66 | }, | ||
67 | }; | ||
68 | |||
69 | static struct platform_device *sh7780_devices[] __initdata = { | ||
70 | &rtc_device, | ||
71 | &sci_device, | ||
72 | }; | ||
73 | |||
74 | static 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 | ||
33 | static LIST_HEAD(sq_mapping_list); | 27 | struct sq_mapping; |
28 | |||
29 | struct 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 | |||
39 | static struct sq_mapping *sq_mapping_list; | ||
34 | static DEFINE_SPINLOCK(sq_mapping_lock); | 40 | static DEFINE_SPINLOCK(sq_mapping_lock); |
41 | static kmem_cache_t *sq_cache; | ||
42 | static unsigned long *sq_bitmap; | ||
35 | 43 | ||
36 | /** | 44 | #define store_queue_barrier() \ |
37 | * sq_flush - Flush (prefetch) the store queue cache | 45 | do { \ |
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 | */ | ||
43 | inline 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) | |||
56 | void sq_flush_range(unsigned long start, unsigned int len) | 59 | void 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 | ||
72 | static struct sq_mapping *__sq_alloc_mapping(unsigned long virt, unsigned long phys, unsigned long size, const char *name) | 71 | static 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 | ||
95 | static unsigned long __sq_get_next_addr(void) | 87 | static 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 | /** | 102 | static 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 | */ | ||
131 | static 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 | */ |
221 | struct sq_mapping *sq_remap(unsigned long phys, unsigned int size, const char *name) | 142 | unsigned 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); | 192 | out: |
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 | */ |
258 | void sq_unmap(struct sq_mapping *map) | 205 | void 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 | */ | ||
275 | void 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 | */ |
298 | static void sq_vma_unmap(struct vm_area_struct *area, | 248 | static 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) { | 250 | struct 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) { | 258 | static 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 | /** | 269 | static 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 | */ | ||
338 | static 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 | ||
346 | static struct vm_operations_struct sq_vma_ops = { | 280 | static 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 | */ | 293 | static ssize_t mapping_store(const char *buf, size_t count) |
360 | static 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"); | 312 | static 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, | 315 | static 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; | 320 | static struct sysfs_ops sq_sysfs_ops = { |
321 | .show = sq_sysfs_show, | ||
322 | .store = sq_sysfs_store, | ||
323 | }; | ||
386 | 324 | ||
387 | return 0; | 325 | static 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 | 330 | static int __devinit sq_sysdev_add(struct sys_device *sysdev) |
391 | static 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 | ||
411 | static struct file_operations sq_fops = { | 347 | static 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 | ||
416 | static 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 | |
356 | static struct sysdev_driver sq_sysdev_driver = { | ||
357 | .add = sq_sysdev_add, | ||
358 | .remove = __devexit_p(sq_sysdev_remove), | ||
420 | }; | 359 | }; |
421 | 360 | ||
422 | static int __init sq_api_init(void) | 361 | static 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 | |||
385 | out: | ||
386 | kfree(sq_bitmap); | ||
387 | kmem_cache_destroy(sq_cache); | ||
432 | 388 | ||
433 | return ret; | 389 | return ret; |
434 | } | 390 | } |
435 | 391 | ||
436 | static void __exit sq_api_exit(void) | 392 | static 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 | ||
442 | module_init(sq_api_init); | 399 | module_init(sq_api_init); |
@@ -445,11 +402,7 @@ module_exit(sq_api_exit); | |||
445 | MODULE_AUTHOR("Paul Mundt <lethal@linux-sh.org>, M. R. Brown <mrbrown@0xd6.org>"); | 402 | MODULE_AUTHOR("Paul Mundt <lethal@linux-sh.org>, M. R. Brown <mrbrown@0xd6.org>"); |
446 | MODULE_DESCRIPTION("Simple API for SH-4 integrated Store Queues"); | 403 | MODULE_DESCRIPTION("Simple API for SH-4 integrated Store Queues"); |
447 | MODULE_LICENSE("GPL"); | 404 | MODULE_LICENSE("GPL"); |
448 | MODULE_ALIAS_MISCDEV(STORE_QUEUE_MINOR); | ||
449 | 405 | ||
450 | EXPORT_SYMBOL(sq_remap); | 406 | EXPORT_SYMBOL(sq_remap); |
451 | EXPORT_SYMBOL(sq_unmap); | 407 | EXPORT_SYMBOL(sq_unmap); |
452 | EXPORT_SYMBOL(sq_clear); | ||
453 | EXPORT_SYMBOL(sq_flush); | ||
454 | EXPORT_SYMBOL(sq_flush_range); | 408 | EXPORT_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 | ||
52 | static struct console early_console = { | 52 | static 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 | |||
73 | static struct uart_port scif_port = { | ||
74 | .mapbase = SCIF_REG, | ||
75 | .membase = (char __iomem *)SCIF_REG, | ||
76 | }; | ||
63 | 77 | ||
64 | static void scif_sercon_putc(int c) | 78 | static 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 | ||
75 | static void scif_sercon_flush(void) | 94 | static 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 | |||
84 | static 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 | ||
92 | static int __init scif_sercon_setup(struct console *con, char *options) | 101 | static 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 | ||
99 | static struct console early_console = { | 108 | static 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 | ||
107 | void scif_sercon_init(int baud) | 116 | static 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 | ||
125 | void __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 | */ | ||
138 | static 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 | |||
148 | static int __initdata keep_early; | ||
149 | |||
150 | int __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 | ||
133 | void disable_early_printk(void) | 184 | void __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 |
327 | ret_from_exception: | 309 | ret_from_exception: |
328 | preempt_stop() | 310 | preempt_stop() |
329 | ret_from_irq: | 311 | ENTRY(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 |
393 | work_notifysig: | 375 | work_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 |
433 | 1: .long schedule | 416 | 1: .long schedule |
434 | 2: .long do_signal | 417 | 2: .long do_notify_resume |
435 | 418 | ||
436 | .align 2 | 419 | .align 2 |
437 | syscall_exit_work: | 420 | syscall_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 | ! |
557 | syscall_exit: | 541 | syscall_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 |
725 | handle_exception: | 709 | ENTRY(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 | ||
842 | ENTRY(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" |
16 | ENTRY(empty_zero_page) | 28 | ENTRY(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) | |||
62 | 9: cmp/hs r2, r1 | 81 | 9: 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 |
71 | 1: .long 0x400080F0 ! MD=1, RB=0, BL=0, FD=1, IMASK=0xF | 98 | 1: .long 0x400080F0 ! MD=1, RB=0, BL=0, FD=1, IMASK=0xF |
72 | 2: .long stack | 99 | 2: .long init_thread_union+THREAD_SIZE |
73 | 3: .long __bss_start | 100 | 3: .long __bss_start |
74 | 4: .long _end | 101 | 4: .long _end |
75 | 5: .long start_kernel | 102 | 5: .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 | } |
62 | EXPORT_SYMBOL(memset_io); | 62 | EXPORT_SYMBOL(memset_io); |
63 | 63 | ||
64 | void __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 | } | ||
111 | EXPORT_SYMBOL(__raw_readsl); | ||
112 | |||
113 | void __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 | } | ||
129 | EXPORT_SYMBOL(__raw_writesl); | ||
130 | |||
64 | void __iomem *ioport_map(unsigned long port, unsigned int nr) | 131 | void __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 | */ | ||
68 | union irq_ctx { | ||
69 | struct thread_info tinfo; | ||
70 | u32 stack[THREAD_SIZE/sizeof(u32)]; | ||
71 | }; | ||
72 | |||
73 | static union irq_ctx *hardirq_ctx[NR_CPUS]; | ||
74 | static union irq_ctx *softirq_ctx[NR_CPUS]; | ||
75 | #endif | ||
63 | 76 | ||
64 | asmlinkage int do_IRQ(unsigned long r4, unsigned long r5, | 77 | asmlinkage 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, ®s); | 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" (®s), "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, ®s); | ||
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 | */ | ||
169 | static char softirq_stack[NR_CPUS * THREAD_SIZE] | ||
170 | __attribute__((__aligned__(THREAD_SIZE))); | ||
171 | |||
172 | static 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 | */ | ||
178 | void 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 | |||
207 | void irq_ctx_exit(int cpu) | ||
208 | { | ||
209 | hardirq_ctx[cpu] = NULL; | ||
210 | } | ||
211 | |||
212 | extern asmlinkage void __do_softirq(void); | ||
213 | |||
214 | asmlinkage 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 | } | ||
252 | EXPORT_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 */ |
116 | kgdb_debug_hook_t *kgdb_debug_hook; | 117 | kgdb_debug_hook_t *kgdb_debug_hook; |
@@ -240,7 +241,6 @@ static jmp_buf rem_com_env; | |||
240 | /* Misc static */ | 241 | /* Misc static */ |
241 | static int stepped_address; | 242 | static int stepped_address; |
242 | static short stepped_opcode; | 243 | static short stepped_opcode; |
243 | static const char hexchars[] = "0123456789abcdef"; | ||
244 | static char in_buffer[BUFMAX]; | 244 | static char in_buffer[BUFMAX]; |
245 | static char out_buffer[OUTBUFMAX]; | 245 | static 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 */ | ||
257 | static inline unsigned int ctrl_inl(const unsigned long addr) | ||
258 | { | ||
259 | return *(volatile unsigned long *) addr; | ||
260 | } | ||
261 | |||
262 | /* Correctly set *addr using volatile */ | ||
263 | static 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 */ | ||
269 | static char highhex(const int x) | ||
270 | { | ||
271 | return hexchars[(x >> 4) & 0xf]; | ||
272 | } | ||
273 | |||
274 | /* Get low hex bits */ | ||
275 | static char lowhex(const int x) | ||
276 | { | ||
277 | return hexchars[x & 0xf]; | ||
278 | } | ||
279 | 256 | ||
280 | /* Convert ch to hex */ | 257 | /* Convert ch to hex */ |
281 | static int hex(const char ch) | 258 | static 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[]; | |||
29 | extern const unsigned int relocate_new_kernel_size; | 29 | extern const unsigned int relocate_new_kernel_size; |
30 | extern void *gdb_vbr_vector; | 30 | extern 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 | */ | ||
36 | void *crash_notes = NULL; | ||
37 | |||
38 | void machine_shutdown(void) | 32 | void 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 | |||
31 | void 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 | ||
82 | void machine_restart(char * __unused) | 82 | void 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 | ||
17 | spinlock_t semaphore_wake_lock; | 17 | DEFINE_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 | */ |
45 | struct sh_cpuinfo boot_cpu_data = { CPU_SH_NONE, 10000000, }; | 45 | struct sh_cpuinfo boot_cpu_data = { CPU_SH_NONE, 10000000, }; |
46 | #ifdef CONFIG_VT | ||
46 | struct screen_info screen_info; | 47 | struct screen_info screen_info; |
48 | #endif | ||
47 | 49 | ||
48 | #if defined(CONFIG_SH_UNKNOWN) | 50 | #if defined(CONFIG_SH_UNKNOWN) |
49 | struct sh_machine_vector sh_mv; | 51 | struct sh_machine_vector sh_mv; |
50 | #endif | 52 | #endif |
51 | 53 | ||
52 | /* We need this to satisfy some external references. */ | ||
53 | struct 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 | |||
65 | extern void platform_setup(void); | ||
66 | extern char *get_system_type(void); | ||
67 | extern int root_mountflags; | 54 | extern 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 | ||
91 | static char command_line[COMMAND_LINE_SIZE] = { 0, }; | 78 | static char command_line[COMMAND_LINE_SIZE] = { 0, }; |
92 | 79 | ||
93 | struct resource standard_io_resources[] = { | 80 | static struct resource code_resource = { .name = "Kernel code", }; |
94 | { "dma1", 0x00, 0x1f }, | 81 | static 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]) | ||
109 | static 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 | ||
117 | unsigned long memory_start, memory_end; | 83 | unsigned 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 | ||
376 | struct sh_machine_vector* __init get_mv_byname(const char* name) | 359 | struct 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) | |||
410 | subsys_initcall(topology_init); | 392 | subsys_initcall(topology_init); |
411 | 393 | ||
412 | static const char *cpu_name[] = { | 394 | static 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 */ | ||
441 | static const char *cpu_flags[] = { | 417 | static 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 | ||
445 | static void show_cpuflags(struct seq_file *m) | 422 | static 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 | ||
463 | static void show_cacheinfo(struct seq_file *m, const char *type, struct cache_info info) | 440 | static 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 */ |
29 | EXPORT_SYMBOL(dump_fpu); | 29 | EXPORT_SYMBOL(dump_fpu); |
30 | EXPORT_SYMBOL(iounmap); | ||
31 | EXPORT_SYMBOL(enable_irq); | ||
32 | EXPORT_SYMBOL(disable_irq); | ||
33 | EXPORT_SYMBOL(probe_irq_mask); | ||
34 | EXPORT_SYMBOL(kernel_thread); | 30 | EXPORT_SYMBOL(kernel_thread); |
35 | EXPORT_SYMBOL(disable_irq_nosync); | ||
36 | EXPORT_SYMBOL(irq_desc); | 31 | EXPORT_SYMBOL(irq_desc); |
37 | EXPORT_SYMBOL(no_irq_type); | 32 | EXPORT_SYMBOL(no_irq_type); |
38 | 33 | ||
39 | EXPORT_SYMBOL(strstr); | ||
40 | EXPORT_SYMBOL(strlen); | 34 | EXPORT_SYMBOL(strlen); |
41 | EXPORT_SYMBOL(strnlen); | ||
42 | EXPORT_SYMBOL(strchr); | ||
43 | EXPORT_SYMBOL(strcat); | ||
44 | EXPORT_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 */ |
53 | EXPORT_SYMBOL(memchr); | 43 | EXPORT_SYMBOL(memchr); |
54 | EXPORT_SYMBOL(memcpy); | 44 | EXPORT_SYMBOL(memcpy); |
55 | EXPORT_SYMBOL(memcpy_fromio); | ||
56 | EXPORT_SYMBOL(memcpy_toio); | ||
57 | EXPORT_SYMBOL(memset); | 45 | EXPORT_SYMBOL(memset); |
58 | EXPORT_SYMBOL(memset_io); | ||
59 | EXPORT_SYMBOL(memmove); | 46 | EXPORT_SYMBOL(memmove); |
60 | EXPORT_SYMBOL(memcmp); | ||
61 | EXPORT_SYMBOL(memscan); | ||
62 | EXPORT_SYMBOL(__copy_user); | 47 | EXPORT_SYMBOL(__copy_user); |
63 | EXPORT_SYMBOL(boot_cpu_data); | 48 | EXPORT_SYMBOL(boot_cpu_data); |
64 | 49 | ||
@@ -94,7 +79,9 @@ EXPORT_SYMBOL(strcpy); | |||
94 | DECLARE_EXPORT(__movstr_i4_even); | 79 | DECLARE_EXPORT(__movstr_i4_even); |
95 | DECLARE_EXPORT(__movstr_i4_odd); | 80 | DECLARE_EXPORT(__movstr_i4_odd); |
96 | DECLARE_EXPORT(__movstrSI12_i4); | 81 | DECLARE_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 */ |
99 | EXPORT_SYMBOL(flush_cache_all); | 86 | EXPORT_SYMBOL(flush_cache_all); |
100 | EXPORT_SYMBOL(flush_cache_range); | 87 | EXPORT_SYMBOL(flush_cache_range); |
@@ -102,11 +89,9 @@ EXPORT_SYMBOL(flush_dcache_page); | |||
102 | EXPORT_SYMBOL(__flush_purge_region); | 89 | EXPORT_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) || \ |
106 | EXPORT_SYMBOL(flush_cache_all); | 93 | defined(CONFIG_SH7705_CACHE_32KB)) |
107 | EXPORT_SYMBOL(flush_cache_range); | 94 | EXPORT_SYMBOL(clear_user_page); |
108 | EXPORT_SYMBOL(flush_dcache_page); | ||
109 | EXPORT_SYMBOL(__flush_purge_region); | ||
110 | #endif | 95 | #endif |
111 | 96 | ||
112 | EXPORT_SYMBOL(flush_tlb_page); | 97 | EXPORT_SYMBOL(flush_tlb_page); |
@@ -116,7 +101,12 @@ EXPORT_SYMBOL(__down_trylock); | |||
116 | EXPORT_SYMBOL(synchronize_irq); | 101 | EXPORT_SYMBOL(synchronize_irq); |
117 | #endif | 102 | #endif |
118 | 103 | ||
104 | #ifdef CONFIG_PM | ||
105 | EXPORT_SYMBOL(pm_suspend); | ||
106 | #endif | ||
107 | |||
119 | EXPORT_SYMBOL(csum_partial); | 108 | EXPORT_SYMBOL(csum_partial); |
109 | #ifdef CONFIG_IPV6 | ||
120 | EXPORT_SYMBOL(csum_ipv6_magic); | 110 | EXPORT_SYMBOL(csum_ipv6_magic); |
121 | EXPORT_SYMBOL(consistent_sync); | 111 | #endif |
122 | EXPORT_SYMBOL(clear_page); | 112 | EXPORT_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 | ||
36 | asmlinkage 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(¤t->sighand->siglock); | 43 | spin_lock_irq(¤t->sighand->siglock); |
50 | saveset = current->blocked; | 44 | current->saved_sigmask = current->blocked; |
51 | siginitset(¤t->blocked, mask); | 45 | siginitset(¤t->blocked, mask); |
52 | recalc_sigpending(); | 46 | recalc_sigpending(); |
53 | spin_unlock_irq(¤t->sighand->siglock); | 47 | spin_unlock_irq(¤t->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(®s, &saveset)) | ||
60 | return -EINTR; | ||
61 | } | ||
62 | } | ||
63 | |||
64 | asmlinkage int | ||
65 | sys_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(¤t->sighand->siglock); | ||
79 | saveset = current->blocked; | ||
80 | current->blocked = newset; | ||
81 | recalc_sigpending(); | ||
82 | spin_unlock_irq(¤t->sighand->siglock); | ||
83 | |||
84 | regs.regs[0] = -EINTR; | ||
85 | while (1) { | ||
86 | current->state = TASK_INTERRUPTIBLE; | ||
87 | schedule(); | ||
88 | if (do_signal(®s, &saveset)) | ||
89 | return -EINTR; | ||
90 | } | ||
91 | } | 53 | } |
92 | 54 | ||
93 | asmlinkage int | 55 | asmlinkage 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 | ||
351 | static 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. */ | ||
315 | extern void __user __kernel_sigreturn; | ||
316 | extern void __user __kernel_rt_sigreturn; | ||
317 | |||
318 | static 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 | ||
415 | give_sigsegv: | 385 | give_sigsegv: |
416 | force_sigsegv(sig, current); | 386 | force_sigsegv(sig, current); |
387 | return -EFAULT; | ||
417 | } | 388 | } |
418 | 389 | ||
419 | static void setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, | 390 | static 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 | ||
490 | give_sigsegv: | 465 | give_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 | ||
498 | static void | 474 | static int |
499 | handle_signal(unsigned long sig, struct k_sigaction *ka, siginfo_t *info, | 475 | handle_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(¤t->sighand->siglock); | 527 | if (ret == 0) { |
550 | sigorsets(¤t->blocked,¤t->blocked,&ka->sa.sa_mask); | 528 | spin_lock_irq(¤t->sighand->siglock); |
551 | if (!(ka->sa.sa_flags & SA_NODEFER)) | 529 | sigorsets(¤t->blocked,¤t->blocked,&ka->sa.sa_mask); |
552 | sigaddset(¤t->blocked,sig); | 530 | if (!(ka->sa.sa_flags & SA_NODEFER)) |
553 | recalc_sigpending(); | 531 | sigaddset(¤t->blocked,sig); |
554 | spin_unlock_irq(¤t->sighand->siglock); | 532 | recalc_sigpending(); |
533 | spin_unlock_irq(¤t->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 | */ |
566 | int do_signal(struct pt_regs *regs, sigset_t *oldset) | 548 | static 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 = ¤t->saved_sigmask; | ||
569 | else | ||
585 | oldset = ¤t->blocked; | 570 | oldset = ¤t->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, ¤t->saved_sigmask, NULL); | ||
605 | } | ||
606 | } | ||
607 | |||
608 | asmlinkage 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) | 48 | unsigned long shm_align_mask = PAGE_SIZE - 1; /* Sane caches */ |
49 | |||
50 | EXPORT_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 | ||
53 | unsigned long arch_get_unmapped_area(struct file *filp, unsigned long addr, | 59 | unsigned 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 | ||
92 | full_search: | 102 | full_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 | ||
124 | static inline long | 138 | static inline long |
125 | do_mmap2(unsigned long addr, unsigned long len, unsigned long prot, | 139 | do_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 | ||
36 | ENTRY(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; | |||
26 | DEFINE_SPINLOCK(rtc_lock); | 25 | DEFINE_SPINLOCK(rtc_lock); |
27 | EXPORT_SYMBOL(rtc_lock); | 26 | EXPORT_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... */ | 29 | static void null_rtc_get_time(struct timespec *tv) |
31 | #ifdef CONFIG_SH_RTC | 30 | { |
32 | void (*rtc_get_time)(struct timespec *) = sh_rtc_gettimeofday; | 31 | tv->tv_sec = mktime(2000, 1, 1, 0, 0, 0); |
33 | int (*rtc_set_time)(const time_t) = sh_rtc_settimeofday; | 32 | tv->tv_nsec = 0; |
34 | #else | 33 | } |
35 | void (*rtc_get_time)(struct timespec *); | 34 | |
36 | int (*rtc_set_time)(const time_t); | 35 | static int null_rtc_set_time(const time_t secs) |
37 | #endif | 36 | { |
37 | return 0; | ||
38 | } | ||
39 | |||
40 | void (*rtc_sh_get_time)(struct timespec *) = null_rtc_get_time; | ||
41 | int (*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 | |||
74 | EXPORT_SYMBOL(do_gettimeofday); | 77 | EXPORT_SYMBOL(do_gettimeofday); |
75 | 78 | ||
76 | int do_settimeofday(struct timespec *tv) | 79 | int 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 | |||
107 | EXPORT_SYMBOL(do_settimeofday); | 109 | EXPORT_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 | ||
149 | int 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 | |||
158 | int 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 | |||
146 | static struct sysdev_class timer_sysclass = { | 171 | static 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 | ||
150 | static int __init timer_init_sysfs(void) | 177 | static 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 | |||
160 | device_initcall(timer_init_sysfs); | 186 | device_initcall(timer_init_sysfs); |
161 | 187 | ||
162 | void (*board_time_init)(void); | 188 | void (*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 | ||
191 | static int tmu_timer_start(void) | ||
192 | { | ||
193 | ctrl_outb(TMU_TSTR_INIT, TMU_TSTR); | ||
194 | return 0; | ||
195 | } | ||
196 | |||
197 | static int tmu_timer_stop(void) | ||
198 | { | ||
199 | ctrl_outb(0, TMU_TSTR); | ||
200 | return 0; | ||
201 | } | ||
202 | |||
191 | static int tmu_timer_init(void) | 203 | static 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 | ||
219 | struct sys_timer_ops tmu_timer_ops = { | 231 | struct 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) \ | ||
51 | asmlinkage 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(®s)) { \ | ||
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(®s); \ | ||
69 | force_sig(signr, tsk); \ | ||
70 | die_if_no_fixup(str,®s,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 | ||
89 | spinlock_t die_lock; | 64 | DEFINE_SPINLOCK(die_lock); |
90 | 65 | ||
91 | void die(const char * str, struct pt_regs * regs, long err) | 66 | void 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 | ||
578 | DO_ERROR(TRAP_RESERVED_INST, SIGILL, "reserved instruction", reserved_inst, current) | 553 | extern int do_fpu_inst(unsigned short, struct pt_regs*); |
579 | DO_ERROR(TRAP_ILLEGAL_SLOT_INST, SIGILL, "illegal slot instruction", illegal_slot_inst, current) | 554 | |
555 | asmlinkage 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, ®s); | ||
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(®s)) { | ||
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(®s); | ||
590 | force_sig(SIGILL, tsk); | ||
591 | die_if_no_fixup("reserved instruction", ®s, error_code); | ||
592 | } | ||
593 | |||
594 | #ifdef CONFIG_SH_FPU_EMU | ||
595 | static 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 | |||
637 | asmlinkage 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, ®s)) { | ||
648 | get_user(inst, (unsigned short *)regs.pc); | ||
649 | if (!emulate_branch(inst, ®s)) | ||
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(®s); | ||
661 | force_sig(SIGILL, tsk); | ||
662 | die_if_no_fixup("illegal slot instruction", ®s, error_code); | ||
663 | } | ||
580 | 664 | ||
581 | asmlinkage void do_exception_error(unsigned long r4, unsigned long r5, | 665 | asmlinkage 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) | |||
13 | ENTRY(_start) | 14 | ENTRY(_start) |
14 | SECTIONS | 15 | SECTIONS |
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 @@ | |||
1 | obj-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 | ||
7 | targets += $(foreach F,trapa,vsyscall-$F.o vsyscall-$F.so) | ||
8 | targets += vsyscall-note.o vsyscall.lds | ||
9 | |||
10 | # The DSO images are built using a special linker script | ||
11 | quiet_cmd_syscall = SYSCALL $@ | ||
12 | cmd_syscall = $(CC) -nostdlib $(SYSCFLAGS_$(@F)) \ | ||
13 | -Wl,-T,$(filter-out FORCE,$^) -o $@ | ||
14 | |||
15 | export CPPFLAGS_vsyscall.lds += -P -C -Ush | ||
16 | |||
17 | vsyscall-flags = -shared -s -Wl,-soname=linux-gate.so.1 \ | ||
18 | $(call ld-option, -Wl$(comma)--hash-style=sysv) | ||
19 | |||
20 | SYSCFLAGS_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. | ||
29 | extra-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 | |||
33 | SYSCFLAGS_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 */ \ | ||
15 | 0: .asciz vendor; /* vendor name */ \ | ||
16 | 1: .balign 4; \ | ||
17 | 2: | ||
18 | |||
19 | #define ASM_ELF_NOTE_END \ | ||
20 | 3: .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 | |||
17 | 1: .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 | |||
34 | 1: .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 | ||
6 | vsyscall_trapa_start: | ||
7 | .incbin "arch/sh/kernel/vsyscall/vsyscall-trapa.so" | ||
8 | vsyscall_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 | */ | ||
25 | unsigned int __read_mostly vdso_enabled = 1; | ||
26 | EXPORT_SYMBOL_GPL(vdso_enabled); | ||
27 | |||
28 | static 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 | */ | ||
39 | extern const char vsyscall_trapa_start, vsyscall_trapa_end; | ||
40 | static void *syscall_page; | ||
41 | |||
42 | int __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 | |||
58 | static 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 */ | ||
75 | static void syscall_vma_close(struct vm_area_struct *vma) | ||
76 | { | ||
77 | } | ||
78 | |||
79 | static 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 */ | ||
85 | int 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++; | ||
124 | up_fail: | ||
125 | up_write(&mm->mmap_sem); | ||
126 | return ret; | ||
127 | } | ||
128 | |||
129 | const 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 | |||
137 | struct vm_area_struct *get_gate_vma(struct task_struct *task) | ||
138 | { | ||
139 | return NULL; | ||
140 | } | ||
141 | |||
142 | int in_gate_area(struct task_struct *task, unsigned long address) | ||
143 | { | ||
144 | return 0; | ||
145 | } | ||
146 | |||
147 | int 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 | ||
9 | OUTPUT_FORMAT("elf32-sh-linux", "elf32-sh-linux", "elf32-sh-linux") | ||
10 | #else | ||
11 | OUTPUT_FORMAT("elf32-shbig-linux", "elf32-shbig-linux", "elf32-shbig-linux") | ||
12 | #endif | ||
13 | OUTPUT_ARCH(sh) | ||
14 | |||
15 | /* The ELF entry point can be used to set the AT_SYSINFO value. */ | ||
16 | ENTRY(__kernel_vsyscall); | ||
17 | |||
18 | SECTIONS | ||
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 | */ | ||
53 | PHDRS | ||
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 | */ | ||
64 | VERSION | ||
65 | { | ||
66 | LINUX_2.6 { | ||
67 | global: | ||
68 | __kernel_vsyscall; | ||
69 | __kernel_sigreturn; | ||
70 | __kernel_rt_sigreturn; | ||
71 | |||
72 | local: *; | ||
73 | }; | ||
74 | } | ||