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 | } | ||
