diff options
Diffstat (limited to 'arch/arm/kernel')
-rw-r--r-- | arch/arm/kernel/Makefile | 4 | ||||
-rw-r--r-- | arch/arm/kernel/apm.c | 187 | ||||
-rw-r--r-- | arch/arm/kernel/asm-offsets.c | 1 | ||||
-rw-r--r-- | arch/arm/kernel/calls.S | 13 | ||||
-rw-r--r-- | arch/arm/kernel/ecard.c | 10 | ||||
-rw-r--r-- | arch/arm/kernel/entry-armv.S | 9 | ||||
-rw-r--r-- | arch/arm/kernel/head-nommu.S | 1 | ||||
-rw-r--r-- | arch/arm/kernel/head.S | 20 | ||||
-rw-r--r-- | arch/arm/kernel/irq.c | 8 | ||||
-rw-r--r-- | arch/arm/kernel/iwmmxt-notifier.c | 63 | ||||
-rw-r--r-- | arch/arm/kernel/process.c | 61 | ||||
-rw-r--r-- | arch/arm/kernel/setup.c | 17 | ||||
-rw-r--r-- | arch/arm/kernel/signal.c | 2 | ||||
-rw-r--r-- | arch/arm/kernel/traps.c | 7 | ||||
-rw-r--r-- | arch/arm/kernel/xscale-cp0.c | 179 |
15 files changed, 357 insertions, 225 deletions
diff --git a/arch/arm/kernel/Makefile b/arch/arm/kernel/Makefile index 1320a0efca73..ab06a86e85d5 100644 --- a/arch/arm/kernel/Makefile +++ b/arch/arm/kernel/Makefile | |||
@@ -24,7 +24,9 @@ obj-$(CONFIG_OABI_COMPAT) += sys_oabi-compat.o | |||
24 | obj-$(CONFIG_CRUNCH) += crunch.o crunch-bits.o | 24 | obj-$(CONFIG_CRUNCH) += crunch.o crunch-bits.o |
25 | AFLAGS_crunch-bits.o := -Wa,-mcpu=ep9312 | 25 | AFLAGS_crunch-bits.o := -Wa,-mcpu=ep9312 |
26 | 26 | ||
27 | obj-$(CONFIG_IWMMXT) += iwmmxt.o iwmmxt-notifier.o | 27 | obj-$(CONFIG_CPU_XSCALE) += xscale-cp0.o |
28 | obj-$(CONFIG_CPU_XSC3) += xscale-cp0.o | ||
29 | obj-$(CONFIG_IWMMXT) += iwmmxt.o | ||
28 | AFLAGS_iwmmxt.o := -Wa,-mcpu=iwmmxt | 30 | AFLAGS_iwmmxt.o := -Wa,-mcpu=iwmmxt |
29 | 31 | ||
30 | ifneq ($(CONFIG_ARCH_EBSA110),y) | 32 | ifneq ($(CONFIG_ARCH_EBSA110),y) |
diff --git a/arch/arm/kernel/apm.c b/arch/arm/kernel/apm.c index ecf4f9472d94..a11fb9a40c04 100644 --- a/arch/arm/kernel/apm.c +++ b/arch/arm/kernel/apm.c | |||
@@ -12,7 +12,6 @@ | |||
12 | */ | 12 | */ |
13 | #include <linux/module.h> | 13 | #include <linux/module.h> |
14 | #include <linux/poll.h> | 14 | #include <linux/poll.h> |
15 | #include <linux/timer.h> | ||
16 | #include <linux/slab.h> | 15 | #include <linux/slab.h> |
17 | #include <linux/proc_fs.h> | 16 | #include <linux/proc_fs.h> |
18 | #include <linux/miscdevice.h> | 17 | #include <linux/miscdevice.h> |
@@ -26,6 +25,7 @@ | |||
26 | #include <linux/init.h> | 25 | #include <linux/init.h> |
27 | #include <linux/completion.h> | 26 | #include <linux/completion.h> |
28 | #include <linux/kthread.h> | 27 | #include <linux/kthread.h> |
28 | #include <linux/delay.h> | ||
29 | 29 | ||
30 | #include <asm/apm.h> /* apm_power_info */ | 30 | #include <asm/apm.h> /* apm_power_info */ |
31 | #include <asm/system.h> | 31 | #include <asm/system.h> |
@@ -71,7 +71,8 @@ struct apm_user { | |||
71 | #define SUSPEND_PENDING 1 /* suspend pending read */ | 71 | #define SUSPEND_PENDING 1 /* suspend pending read */ |
72 | #define SUSPEND_READ 2 /* suspend read, pending ack */ | 72 | #define SUSPEND_READ 2 /* suspend read, pending ack */ |
73 | #define SUSPEND_ACKED 3 /* suspend acked */ | 73 | #define SUSPEND_ACKED 3 /* suspend acked */ |
74 | #define SUSPEND_DONE 4 /* suspend completed */ | 74 | #define SUSPEND_WAIT 4 /* waiting for suspend */ |
75 | #define SUSPEND_DONE 5 /* suspend completed */ | ||
75 | 76 | ||
76 | struct apm_queue queue; | 77 | struct apm_queue queue; |
77 | }; | 78 | }; |
@@ -101,6 +102,7 @@ static DECLARE_WAIT_QUEUE_HEAD(kapmd_wait); | |||
101 | static DEFINE_SPINLOCK(kapmd_queue_lock); | 102 | static DEFINE_SPINLOCK(kapmd_queue_lock); |
102 | static struct apm_queue kapmd_queue; | 103 | static struct apm_queue kapmd_queue; |
103 | 104 | ||
105 | static DEFINE_MUTEX(state_lock); | ||
104 | 106 | ||
105 | static const char driver_version[] = "1.13"; /* no spaces */ | 107 | static const char driver_version[] = "1.13"; /* no spaces */ |
106 | 108 | ||
@@ -148,38 +150,60 @@ static void queue_add_event(struct apm_queue *q, apm_event_t event) | |||
148 | q->events[q->event_head] = event; | 150 | q->events[q->event_head] = event; |
149 | } | 151 | } |
150 | 152 | ||
151 | static void queue_event_one_user(struct apm_user *as, apm_event_t event) | 153 | static void queue_event(apm_event_t event) |
152 | { | 154 | { |
153 | if (as->suser && as->writer) { | 155 | struct apm_user *as; |
154 | switch (event) { | ||
155 | case APM_SYS_SUSPEND: | ||
156 | case APM_USER_SUSPEND: | ||
157 | /* | ||
158 | * If this user already has a suspend pending, | ||
159 | * don't queue another one. | ||
160 | */ | ||
161 | if (as->suspend_state != SUSPEND_NONE) | ||
162 | return; | ||
163 | 156 | ||
164 | as->suspend_state = SUSPEND_PENDING; | 157 | down_read(&user_list_lock); |
165 | suspends_pending++; | 158 | list_for_each_entry(as, &apm_user_list, list) { |
166 | break; | 159 | if (as->reader) |
167 | } | 160 | queue_add_event(&as->queue, event); |
168 | } | 161 | } |
169 | queue_add_event(&as->queue, event); | 162 | up_read(&user_list_lock); |
163 | wake_up_interruptible(&apm_waitqueue); | ||
170 | } | 164 | } |
171 | 165 | ||
172 | static void queue_event(apm_event_t event, struct apm_user *sender) | 166 | /* |
167 | * queue_suspend_event - queue an APM suspend event. | ||
168 | * | ||
169 | * Check that we're in a state where we can suspend. If not, | ||
170 | * return -EBUSY. Otherwise, queue an event to all "writer" | ||
171 | * users. If there are no "writer" users, return '1' to | ||
172 | * indicate that we can immediately suspend. | ||
173 | */ | ||
174 | static int queue_suspend_event(apm_event_t event, struct apm_user *sender) | ||
173 | { | 175 | { |
174 | struct apm_user *as; | 176 | struct apm_user *as; |
177 | int ret = 1; | ||
175 | 178 | ||
179 | mutex_lock(&state_lock); | ||
176 | down_read(&user_list_lock); | 180 | down_read(&user_list_lock); |
181 | |||
182 | /* | ||
183 | * If a thread is still processing, we can't suspend, so reject | ||
184 | * the request. | ||
185 | */ | ||
177 | list_for_each_entry(as, &apm_user_list, list) { | 186 | list_for_each_entry(as, &apm_user_list, list) { |
178 | if (as != sender && as->reader) | 187 | if (as != sender && as->reader && as->writer && as->suser && |
179 | queue_event_one_user(as, event); | 188 | as->suspend_state != SUSPEND_NONE) { |
189 | ret = -EBUSY; | ||
190 | goto out; | ||
191 | } | ||
180 | } | 192 | } |
193 | |||
194 | list_for_each_entry(as, &apm_user_list, list) { | ||
195 | if (as != sender && as->reader && as->writer && as->suser) { | ||
196 | as->suspend_state = SUSPEND_PENDING; | ||
197 | suspends_pending++; | ||
198 | queue_add_event(&as->queue, event); | ||
199 | ret = 0; | ||
200 | } | ||
201 | } | ||
202 | out: | ||
181 | up_read(&user_list_lock); | 203 | up_read(&user_list_lock); |
204 | mutex_unlock(&state_lock); | ||
182 | wake_up_interruptible(&apm_waitqueue); | 205 | wake_up_interruptible(&apm_waitqueue); |
206 | return ret; | ||
183 | } | 207 | } |
184 | 208 | ||
185 | static void apm_suspend(void) | 209 | static void apm_suspend(void) |
@@ -191,17 +215,22 @@ static void apm_suspend(void) | |||
191 | * Anyone on the APM queues will think we're still suspended. | 215 | * Anyone on the APM queues will think we're still suspended. |
192 | * Send a message so everyone knows we're now awake again. | 216 | * Send a message so everyone knows we're now awake again. |
193 | */ | 217 | */ |
194 | queue_event(APM_NORMAL_RESUME, NULL); | 218 | queue_event(APM_NORMAL_RESUME); |
195 | 219 | ||
196 | /* | 220 | /* |
197 | * Finally, wake up anyone who is sleeping on the suspend. | 221 | * Finally, wake up anyone who is sleeping on the suspend. |
198 | */ | 222 | */ |
223 | mutex_lock(&state_lock); | ||
199 | down_read(&user_list_lock); | 224 | down_read(&user_list_lock); |
200 | list_for_each_entry(as, &apm_user_list, list) { | 225 | list_for_each_entry(as, &apm_user_list, list) { |
201 | as->suspend_result = err; | 226 | if (as->suspend_state == SUSPEND_WAIT || |
202 | as->suspend_state = SUSPEND_DONE; | 227 | as->suspend_state == SUSPEND_ACKED) { |
228 | as->suspend_result = err; | ||
229 | as->suspend_state = SUSPEND_DONE; | ||
230 | } | ||
203 | } | 231 | } |
204 | up_read(&user_list_lock); | 232 | up_read(&user_list_lock); |
233 | mutex_unlock(&state_lock); | ||
205 | 234 | ||
206 | wake_up(&apm_suspend_waitqueue); | 235 | wake_up(&apm_suspend_waitqueue); |
207 | } | 236 | } |
@@ -227,8 +256,11 @@ static ssize_t apm_read(struct file *fp, char __user *buf, size_t count, loff_t | |||
227 | if (copy_to_user(buf, &event, sizeof(event))) | 256 | if (copy_to_user(buf, &event, sizeof(event))) |
228 | break; | 257 | break; |
229 | 258 | ||
230 | if (event == APM_SYS_SUSPEND || event == APM_USER_SUSPEND) | 259 | mutex_lock(&state_lock); |
260 | if (as->suspend_state == SUSPEND_PENDING && | ||
261 | (event == APM_SYS_SUSPEND || event == APM_USER_SUSPEND)) | ||
231 | as->suspend_state = SUSPEND_READ; | 262 | as->suspend_state = SUSPEND_READ; |
263 | mutex_unlock(&state_lock); | ||
232 | 264 | ||
233 | buf += sizeof(event); | 265 | buf += sizeof(event); |
234 | i -= sizeof(event); | 266 | i -= sizeof(event); |
@@ -270,9 +302,13 @@ apm_ioctl(struct inode * inode, struct file *filp, u_int cmd, u_long arg) | |||
270 | 302 | ||
271 | switch (cmd) { | 303 | switch (cmd) { |
272 | case APM_IOC_SUSPEND: | 304 | case APM_IOC_SUSPEND: |
305 | mutex_lock(&state_lock); | ||
306 | |||
273 | as->suspend_result = -EINTR; | 307 | as->suspend_result = -EINTR; |
274 | 308 | ||
275 | if (as->suspend_state == SUSPEND_READ) { | 309 | if (as->suspend_state == SUSPEND_READ) { |
310 | int pending; | ||
311 | |||
276 | /* | 312 | /* |
277 | * If we read a suspend command from /dev/apm_bios, | 313 | * If we read a suspend command from /dev/apm_bios, |
278 | * then the corresponding APM_IOC_SUSPEND ioctl is | 314 | * then the corresponding APM_IOC_SUSPEND ioctl is |
@@ -280,47 +316,73 @@ apm_ioctl(struct inode * inode, struct file *filp, u_int cmd, u_long arg) | |||
280 | */ | 316 | */ |
281 | as->suspend_state = SUSPEND_ACKED; | 317 | as->suspend_state = SUSPEND_ACKED; |
282 | suspends_pending--; | 318 | suspends_pending--; |
319 | pending = suspends_pending == 0; | ||
320 | mutex_unlock(&state_lock); | ||
321 | |||
322 | /* | ||
323 | * If there are no further acknowledges required, | ||
324 | * suspend the system. | ||
325 | */ | ||
326 | if (pending) | ||
327 | apm_suspend(); | ||
328 | |||
329 | /* | ||
330 | * Wait for the suspend/resume to complete. If there | ||
331 | * are pending acknowledges, we wait here for them. | ||
332 | * | ||
333 | * Note: we need to ensure that the PM subsystem does | ||
334 | * not kick us out of the wait when it suspends the | ||
335 | * threads. | ||
336 | */ | ||
337 | flags = current->flags; | ||
338 | current->flags |= PF_NOFREEZE; | ||
339 | |||
340 | wait_event(apm_suspend_waitqueue, | ||
341 | as->suspend_state == SUSPEND_DONE); | ||
283 | } else { | 342 | } else { |
343 | as->suspend_state = SUSPEND_WAIT; | ||
344 | mutex_unlock(&state_lock); | ||
345 | |||
284 | /* | 346 | /* |
285 | * Otherwise it is a request to suspend the system. | 347 | * Otherwise it is a request to suspend the system. |
286 | * Queue an event for all readers, and expect an | 348 | * Queue an event for all readers, and expect an |
287 | * acknowledge from all writers who haven't already | 349 | * acknowledge from all writers who haven't already |
288 | * acknowledged. | 350 | * acknowledged. |
289 | */ | 351 | */ |
290 | queue_event(APM_USER_SUSPEND, as); | 352 | err = queue_suspend_event(APM_USER_SUSPEND, as); |
291 | } | 353 | if (err < 0) { |
292 | 354 | /* | |
293 | /* | 355 | * Avoid taking the lock here - this |
294 | * If there are no further acknowledges required, suspend | 356 | * should be fine. |
295 | * the system. | 357 | */ |
296 | */ | 358 | as->suspend_state = SUSPEND_NONE; |
297 | if (suspends_pending == 0) | 359 | break; |
298 | apm_suspend(); | 360 | } |
361 | |||
362 | if (err > 0) | ||
363 | apm_suspend(); | ||
299 | 364 | ||
300 | /* | 365 | /* |
301 | * Wait for the suspend/resume to complete. If there are | 366 | * Wait for the suspend/resume to complete. If there |
302 | * pending acknowledges, we wait here for them. | 367 | * are pending acknowledges, we wait here for them. |
303 | * | 368 | * |
304 | * Note that we need to ensure that the PM subsystem does | 369 | * Note: we need to ensure that the PM subsystem does |
305 | * not kick us out of the wait when it suspends the threads. | 370 | * not kick us out of the wait when it suspends the |
306 | */ | 371 | * threads. |
307 | flags = current->flags; | 372 | */ |
308 | current->flags |= PF_NOFREEZE; | 373 | flags = current->flags; |
374 | current->flags |= PF_NOFREEZE; | ||
309 | 375 | ||
310 | /* | ||
311 | * Note: do not allow a thread which is acking the suspend | ||
312 | * to escape until the resume is complete. | ||
313 | */ | ||
314 | if (as->suspend_state == SUSPEND_ACKED) | ||
315 | wait_event(apm_suspend_waitqueue, | ||
316 | as->suspend_state == SUSPEND_DONE); | ||
317 | else | ||
318 | wait_event_interruptible(apm_suspend_waitqueue, | 376 | wait_event_interruptible(apm_suspend_waitqueue, |
319 | as->suspend_state == SUSPEND_DONE); | 377 | as->suspend_state == SUSPEND_DONE); |
378 | } | ||
320 | 379 | ||
321 | current->flags = flags; | 380 | current->flags = flags; |
381 | |||
382 | mutex_lock(&state_lock); | ||
322 | err = as->suspend_result; | 383 | err = as->suspend_result; |
323 | as->suspend_state = SUSPEND_NONE; | 384 | as->suspend_state = SUSPEND_NONE; |
385 | mutex_unlock(&state_lock); | ||
324 | break; | 386 | break; |
325 | } | 387 | } |
326 | 388 | ||
@@ -330,6 +392,8 @@ apm_ioctl(struct inode * inode, struct file *filp, u_int cmd, u_long arg) | |||
330 | static int apm_release(struct inode * inode, struct file * filp) | 392 | static int apm_release(struct inode * inode, struct file * filp) |
331 | { | 393 | { |
332 | struct apm_user *as = filp->private_data; | 394 | struct apm_user *as = filp->private_data; |
395 | int pending = 0; | ||
396 | |||
333 | filp->private_data = NULL; | 397 | filp->private_data = NULL; |
334 | 398 | ||
335 | down_write(&user_list_lock); | 399 | down_write(&user_list_lock); |
@@ -342,11 +406,14 @@ static int apm_release(struct inode * inode, struct file * filp) | |||
342 | * need to balance suspends_pending, which means the | 406 | * need to balance suspends_pending, which means the |
343 | * possibility of sleeping. | 407 | * possibility of sleeping. |
344 | */ | 408 | */ |
409 | mutex_lock(&state_lock); | ||
345 | if (as->suspend_state != SUSPEND_NONE) { | 410 | if (as->suspend_state != SUSPEND_NONE) { |
346 | suspends_pending -= 1; | 411 | suspends_pending -= 1; |
347 | if (suspends_pending == 0) | 412 | pending = suspends_pending == 0; |
348 | apm_suspend(); | ||
349 | } | 413 | } |
414 | mutex_unlock(&state_lock); | ||
415 | if (pending) | ||
416 | apm_suspend(); | ||
350 | 417 | ||
351 | kfree(as); | 418 | kfree(as); |
352 | return 0; | 419 | return 0; |
@@ -470,6 +537,7 @@ static int kapmd(void *arg) | |||
470 | { | 537 | { |
471 | do { | 538 | do { |
472 | apm_event_t event; | 539 | apm_event_t event; |
540 | int ret; | ||
473 | 541 | ||
474 | wait_event_interruptible(kapmd_wait, | 542 | wait_event_interruptible(kapmd_wait, |
475 | !queue_empty(&kapmd_queue) || kthread_should_stop()); | 543 | !queue_empty(&kapmd_queue) || kthread_should_stop()); |
@@ -489,13 +557,20 @@ static int kapmd(void *arg) | |||
489 | 557 | ||
490 | case APM_LOW_BATTERY: | 558 | case APM_LOW_BATTERY: |
491 | case APM_POWER_STATUS_CHANGE: | 559 | case APM_POWER_STATUS_CHANGE: |
492 | queue_event(event, NULL); | 560 | queue_event(event); |
493 | break; | 561 | break; |
494 | 562 | ||
495 | case APM_USER_SUSPEND: | 563 | case APM_USER_SUSPEND: |
496 | case APM_SYS_SUSPEND: | 564 | case APM_SYS_SUSPEND: |
497 | queue_event(event, NULL); | 565 | ret = queue_suspend_event(event, NULL); |
498 | if (suspends_pending == 0) | 566 | if (ret < 0) { |
567 | /* | ||
568 | * We were busy. Try again in 50ms. | ||
569 | */ | ||
570 | queue_add_event(&kapmd_queue, event); | ||
571 | msleep(50); | ||
572 | } | ||
573 | if (ret > 0) | ||
499 | apm_suspend(); | 574 | apm_suspend(); |
500 | break; | 575 | break; |
501 | 576 | ||
diff --git a/arch/arm/kernel/asm-offsets.c b/arch/arm/kernel/asm-offsets.c index cc2d58d028e1..3c078e346753 100644 --- a/arch/arm/kernel/asm-offsets.c +++ b/arch/arm/kernel/asm-offsets.c | |||
@@ -15,6 +15,7 @@ | |||
15 | #include <asm/mach/arch.h> | 15 | #include <asm/mach/arch.h> |
16 | #include <asm/thread_info.h> | 16 | #include <asm/thread_info.h> |
17 | #include <asm/memory.h> | 17 | #include <asm/memory.h> |
18 | #include <asm/procinfo.h> | ||
18 | 19 | ||
19 | /* | 20 | /* |
20 | * Make sure that the compiler and target are compatible. | 21 | * Make sure that the compiler and target are compatible. |
diff --git a/arch/arm/kernel/calls.S b/arch/arm/kernel/calls.S index 3173924a9b60..e8f74363328c 100644 --- a/arch/arm/kernel/calls.S +++ b/arch/arm/kernel/calls.S | |||
@@ -331,6 +331,19 @@ | |||
331 | CALL(sys_mbind) | 331 | CALL(sys_mbind) |
332 | /* 320 */ CALL(sys_get_mempolicy) | 332 | /* 320 */ CALL(sys_get_mempolicy) |
333 | CALL(sys_set_mempolicy) | 333 | CALL(sys_set_mempolicy) |
334 | CALL(sys_openat) | ||
335 | CALL(sys_mkdirat) | ||
336 | CALL(sys_mknodat) | ||
337 | /* 325 */ CALL(sys_fchownat) | ||
338 | CALL(sys_futimesat) | ||
339 | CALL(sys_fstatat64) | ||
340 | CALL(sys_unlinkat) | ||
341 | CALL(sys_renameat) | ||
342 | /* 330 */ CALL(sys_linkat) | ||
343 | CALL(sys_symlinkat) | ||
344 | CALL(sys_readlinkat) | ||
345 | CALL(sys_fchmodat) | ||
346 | CALL(sys_faccessat) | ||
334 | #ifndef syscalls_counted | 347 | #ifndef syscalls_counted |
335 | .equ syscalls_padding, ((NR_syscalls + 3) & ~3) - NR_syscalls | 348 | .equ syscalls_padding, ((NR_syscalls + 3) & ~3) - NR_syscalls |
336 | #define syscalls_counted | 349 | #define syscalls_counted |
diff --git a/arch/arm/kernel/ecard.c b/arch/arm/kernel/ecard.c index b27513a0f11e..a786f769035d 100644 --- a/arch/arm/kernel/ecard.c +++ b/arch/arm/kernel/ecard.c | |||
@@ -529,7 +529,7 @@ static void ecard_dump_irq_state(void) | |||
529 | } | 529 | } |
530 | } | 530 | } |
531 | 531 | ||
532 | static void ecard_check_lockup(struct irqdesc *desc) | 532 | static void ecard_check_lockup(struct irq_desc *desc) |
533 | { | 533 | { |
534 | static unsigned long last; | 534 | static unsigned long last; |
535 | static int lockup; | 535 | static int lockup; |
@@ -567,7 +567,7 @@ static void ecard_check_lockup(struct irqdesc *desc) | |||
567 | } | 567 | } |
568 | 568 | ||
569 | static void | 569 | static void |
570 | ecard_irq_handler(unsigned int irq, struct irqdesc *desc) | 570 | ecard_irq_handler(unsigned int irq, struct irq_desc *desc) |
571 | { | 571 | { |
572 | ecard_t *ec; | 572 | ecard_t *ec; |
573 | int called = 0; | 573 | int called = 0; |
@@ -585,7 +585,7 @@ ecard_irq_handler(unsigned int irq, struct irqdesc *desc) | |||
585 | pending = ecard_default_ops.irqpending(ec); | 585 | pending = ecard_default_ops.irqpending(ec); |
586 | 586 | ||
587 | if (pending) { | 587 | if (pending) { |
588 | struct irqdesc *d = irq_desc + ec->irq; | 588 | struct irq_desc *d = irq_desc + ec->irq; |
589 | desc_handle_irq(ec->irq, d); | 589 | desc_handle_irq(ec->irq, d); |
590 | called ++; | 590 | called ++; |
591 | } | 591 | } |
@@ -609,7 +609,7 @@ static unsigned char first_set[] = | |||
609 | }; | 609 | }; |
610 | 610 | ||
611 | static void | 611 | static void |
612 | ecard_irqexp_handler(unsigned int irq, struct irqdesc *desc) | 612 | ecard_irqexp_handler(unsigned int irq, struct irq_desc *desc) |
613 | { | 613 | { |
614 | const unsigned int statusmask = 15; | 614 | const unsigned int statusmask = 15; |
615 | unsigned int status; | 615 | unsigned int status; |
@@ -1022,7 +1022,7 @@ ecard_probe(int slot, card_type_t type) | |||
1022 | if (slot < 8) { | 1022 | if (slot < 8) { |
1023 | ec->irq = 32 + slot; | 1023 | ec->irq = 32 + slot; |
1024 | set_irq_chip(ec->irq, &ecard_chip); | 1024 | set_irq_chip(ec->irq, &ecard_chip); |
1025 | set_irq_handler(ec->irq, do_level_IRQ); | 1025 | set_irq_handler(ec->irq, handle_level_irq); |
1026 | set_irq_flags(ec->irq, IRQF_VALID); | 1026 | set_irq_flags(ec->irq, IRQF_VALID); |
1027 | } | 1027 | } |
1028 | 1028 | ||
diff --git a/arch/arm/kernel/entry-armv.S b/arch/arm/kernel/entry-armv.S index bd623b73445f..2db42b18f53f 100644 --- a/arch/arm/kernel/entry-armv.S +++ b/arch/arm/kernel/entry-armv.S | |||
@@ -589,10 +589,6 @@ ENTRY(__switch_to) | |||
589 | strex r5, r4, [ip] @ Clear exclusive monitor | 589 | strex r5, r4, [ip] @ Clear exclusive monitor |
590 | #endif | 590 | #endif |
591 | #endif | 591 | #endif |
592 | #if defined(CONFIG_CPU_XSCALE) && !defined(CONFIG_IWMMXT) | ||
593 | mra r4, r5, acc0 | ||
594 | stmia ip, {r4, r5} | ||
595 | #endif | ||
596 | #if defined(CONFIG_HAS_TLS_REG) | 592 | #if defined(CONFIG_HAS_TLS_REG) |
597 | mcr p15, 0, r3, c13, c0, 3 @ set TLS register | 593 | mcr p15, 0, r3, c13, c0, 3 @ set TLS register |
598 | #elif !defined(CONFIG_TLS_REG_EMUL) | 594 | #elif !defined(CONFIG_TLS_REG_EMUL) |
@@ -602,11 +598,6 @@ ENTRY(__switch_to) | |||
602 | #ifdef CONFIG_MMU | 598 | #ifdef CONFIG_MMU |
603 | mcr p15, 0, r6, c3, c0, 0 @ Set domain register | 599 | mcr p15, 0, r6, c3, c0, 0 @ Set domain register |
604 | #endif | 600 | #endif |
605 | #if defined(CONFIG_CPU_XSCALE) && !defined(CONFIG_IWMMXT) | ||
606 | add r4, r2, #TI_CPU_DOMAIN + 40 @ cpu_context_save->extra | ||
607 | ldmib r4, {r4, r5} | ||
608 | mar acc0, r4, r5 | ||
609 | #endif | ||
610 | mov r5, r0 | 601 | mov r5, r0 |
611 | add r4, r2, #TI_CPU_SAVE | 602 | add r4, r2, #TI_CPU_SAVE |
612 | ldr r0, =thread_notify_head | 603 | ldr r0, =thread_notify_head |
diff --git a/arch/arm/kernel/head-nommu.S b/arch/arm/kernel/head-nommu.S index f359a189dcf2..0119c0d5f978 100644 --- a/arch/arm/kernel/head-nommu.S +++ b/arch/arm/kernel/head-nommu.S | |||
@@ -16,7 +16,6 @@ | |||
16 | 16 | ||
17 | #include <asm/assembler.h> | 17 | #include <asm/assembler.h> |
18 | #include <asm/mach-types.h> | 18 | #include <asm/mach-types.h> |
19 | #include <asm/procinfo.h> | ||
20 | #include <asm/ptrace.h> | 19 | #include <asm/ptrace.h> |
21 | #include <asm/asm-offsets.h> | 20 | #include <asm/asm-offsets.h> |
22 | #include <asm/thread_info.h> | 21 | #include <asm/thread_info.h> |
diff --git a/arch/arm/kernel/head.S b/arch/arm/kernel/head.S index ebc3e74a7947..d994561816a1 100644 --- a/arch/arm/kernel/head.S +++ b/arch/arm/kernel/head.S | |||
@@ -16,37 +16,37 @@ | |||
16 | 16 | ||
17 | #include <asm/assembler.h> | 17 | #include <asm/assembler.h> |
18 | #include <asm/domain.h> | 18 | #include <asm/domain.h> |
19 | #include <asm/procinfo.h> | ||
20 | #include <asm/ptrace.h> | 19 | #include <asm/ptrace.h> |
21 | #include <asm/asm-offsets.h> | 20 | #include <asm/asm-offsets.h> |
22 | #include <asm/memory.h> | 21 | #include <asm/memory.h> |
23 | #include <asm/thread_info.h> | 22 | #include <asm/thread_info.h> |
24 | #include <asm/system.h> | 23 | #include <asm/system.h> |
25 | 24 | ||
26 | #define KERNEL_RAM_ADDR (PAGE_OFFSET + TEXT_OFFSET) | 25 | #define KERNEL_RAM_VADDR (PAGE_OFFSET + TEXT_OFFSET) |
26 | #define KERNEL_RAM_PADDR (PHYS_OFFSET + TEXT_OFFSET) | ||
27 | 27 | ||
28 | /* | 28 | /* |
29 | * swapper_pg_dir is the virtual address of the initial page table. | 29 | * swapper_pg_dir is the virtual address of the initial page table. |
30 | * We place the page tables 16K below KERNEL_RAM_ADDR. Therefore, we must | 30 | * We place the page tables 16K below KERNEL_RAM_VADDR. Therefore, we must |
31 | * make sure that KERNEL_RAM_ADDR is correctly set. Currently, we expect | 31 | * make sure that KERNEL_RAM_VADDR is correctly set. Currently, we expect |
32 | * the least significant 16 bits to be 0x8000, but we could probably | 32 | * the least significant 16 bits to be 0x8000, but we could probably |
33 | * relax this restriction to KERNEL_RAM_ADDR >= PAGE_OFFSET + 0x4000. | 33 | * relax this restriction to KERNEL_RAM_VADDR >= PAGE_OFFSET + 0x4000. |
34 | */ | 34 | */ |
35 | #if (KERNEL_RAM_ADDR & 0xffff) != 0x8000 | 35 | #if (KERNEL_RAM_VADDR & 0xffff) != 0x8000 |
36 | #error KERNEL_RAM_ADDR must start at 0xXXXX8000 | 36 | #error KERNEL_RAM_VADDR must start at 0xXXXX8000 |
37 | #endif | 37 | #endif |
38 | 38 | ||
39 | .globl swapper_pg_dir | 39 | .globl swapper_pg_dir |
40 | .equ swapper_pg_dir, KERNEL_RAM_ADDR - 0x4000 | 40 | .equ swapper_pg_dir, KERNEL_RAM_VADDR - 0x4000 |
41 | 41 | ||
42 | .macro pgtbl, rd | 42 | .macro pgtbl, rd |
43 | ldr \rd, =(__virt_to_phys(KERNEL_RAM_ADDR - 0x4000)) | 43 | ldr \rd, =(KERNEL_RAM_PADDR - 0x4000) |
44 | .endm | 44 | .endm |
45 | 45 | ||
46 | #ifdef CONFIG_XIP_KERNEL | 46 | #ifdef CONFIG_XIP_KERNEL |
47 | #define TEXTADDR XIP_VIRT_ADDR(CONFIG_XIP_PHYS_ADDR) | 47 | #define TEXTADDR XIP_VIRT_ADDR(CONFIG_XIP_PHYS_ADDR) |
48 | #else | 48 | #else |
49 | #define TEXTADDR KERNEL_RAM_ADDR | 49 | #define TEXTADDR KERNEL_RAM_VADDR |
50 | #endif | 50 | #endif |
51 | 51 | ||
52 | /* | 52 | /* |
diff --git a/arch/arm/kernel/irq.c b/arch/arm/kernel/irq.c index 2c4ff1cbe334..ec01f08f5642 100644 --- a/arch/arm/kernel/irq.c +++ b/arch/arm/kernel/irq.c | |||
@@ -112,7 +112,7 @@ static struct irq_desc bad_irq_desc = { | |||
112 | asmlinkage void asm_do_IRQ(unsigned int irq, struct pt_regs *regs) | 112 | asmlinkage void asm_do_IRQ(unsigned int irq, struct pt_regs *regs) |
113 | { | 113 | { |
114 | struct pt_regs *old_regs = set_irq_regs(regs); | 114 | struct pt_regs *old_regs = set_irq_regs(regs); |
115 | struct irqdesc *desc = irq_desc + irq; | 115 | struct irq_desc *desc = irq_desc + irq; |
116 | 116 | ||
117 | /* | 117 | /* |
118 | * Some hardware gives randomly wrong interrupts. Rather | 118 | * Some hardware gives randomly wrong interrupts. Rather |
@@ -134,7 +134,7 @@ asmlinkage void asm_do_IRQ(unsigned int irq, struct pt_regs *regs) | |||
134 | 134 | ||
135 | void set_irq_flags(unsigned int irq, unsigned int iflags) | 135 | void set_irq_flags(unsigned int irq, unsigned int iflags) |
136 | { | 136 | { |
137 | struct irqdesc *desc; | 137 | struct irq_desc *desc; |
138 | unsigned long flags; | 138 | unsigned long flags; |
139 | 139 | ||
140 | if (irq >= NR_IRQS) { | 140 | if (irq >= NR_IRQS) { |
@@ -171,7 +171,7 @@ void __init init_IRQ(void) | |||
171 | 171 | ||
172 | #ifdef CONFIG_HOTPLUG_CPU | 172 | #ifdef CONFIG_HOTPLUG_CPU |
173 | 173 | ||
174 | static void route_irq(struct irqdesc *desc, unsigned int irq, unsigned int cpu) | 174 | static void route_irq(struct irq_desc *desc, unsigned int irq, unsigned int cpu) |
175 | { | 175 | { |
176 | pr_debug("IRQ%u: moving from cpu%u to cpu%u\n", irq, desc->cpu, cpu); | 176 | pr_debug("IRQ%u: moving from cpu%u to cpu%u\n", irq, desc->cpu, cpu); |
177 | 177 | ||
@@ -190,7 +190,7 @@ void migrate_irqs(void) | |||
190 | unsigned int i, cpu = smp_processor_id(); | 190 | unsigned int i, cpu = smp_processor_id(); |
191 | 191 | ||
192 | for (i = 0; i < NR_IRQS; i++) { | 192 | for (i = 0; i < NR_IRQS; i++) { |
193 | struct irqdesc *desc = irq_desc + i; | 193 | struct irq_desc *desc = irq_desc + i; |
194 | 194 | ||
195 | if (desc->cpu == cpu) { | 195 | if (desc->cpu == cpu) { |
196 | unsigned int newcpu = any_online_cpu(desc->affinity); | 196 | unsigned int newcpu = any_online_cpu(desc->affinity); |
diff --git a/arch/arm/kernel/iwmmxt-notifier.c b/arch/arm/kernel/iwmmxt-notifier.c deleted file mode 100644 index 0d1a1db40062..000000000000 --- a/arch/arm/kernel/iwmmxt-notifier.c +++ /dev/null | |||
@@ -1,63 +0,0 @@ | |||
1 | /* | ||
2 | * linux/arch/arm/kernel/iwmmxt-notifier.c | ||
3 | * | ||
4 | * XScale iWMMXt (Concan) context switching and handling | ||
5 | * | ||
6 | * Initial code: | ||
7 | * Copyright (c) 2003, Intel Corporation | ||
8 | * | ||
9 | * Full lazy switching support, optimizations and more, by Nicolas Pitre | ||
10 | * Copyright (c) 2003-2004, MontaVista Software, Inc. | ||
11 | * | ||
12 | * This program is free software; you can redistribute it and/or modify | ||
13 | * it under the terms of the GNU General Public License version 2 as | ||
14 | * published by the Free Software Foundation. | ||
15 | */ | ||
16 | |||
17 | #include <linux/module.h> | ||
18 | #include <linux/types.h> | ||
19 | #include <linux/kernel.h> | ||
20 | #include <linux/signal.h> | ||
21 | #include <linux/sched.h> | ||
22 | #include <linux/init.h> | ||
23 | #include <asm/thread_notify.h> | ||
24 | #include <asm/io.h> | ||
25 | |||
26 | static int iwmmxt_do(struct notifier_block *self, unsigned long cmd, void *t) | ||
27 | { | ||
28 | struct thread_info *thread = t; | ||
29 | |||
30 | switch (cmd) { | ||
31 | case THREAD_NOTIFY_FLUSH: | ||
32 | /* | ||
33 | * flush_thread() zeroes thread->fpstate, so no need | ||
34 | * to do anything here. | ||
35 | * | ||
36 | * FALLTHROUGH: Ensure we don't try to overwrite our newly | ||
37 | * initialised state information on the first fault. | ||
38 | */ | ||
39 | |||
40 | case THREAD_NOTIFY_RELEASE: | ||
41 | iwmmxt_task_release(thread); | ||
42 | break; | ||
43 | |||
44 | case THREAD_NOTIFY_SWITCH: | ||
45 | iwmmxt_task_switch(thread); | ||
46 | break; | ||
47 | } | ||
48 | |||
49 | return NOTIFY_DONE; | ||
50 | } | ||
51 | |||
52 | static struct notifier_block iwmmxt_notifier_block = { | ||
53 | .notifier_call = iwmmxt_do, | ||
54 | }; | ||
55 | |||
56 | static int __init iwmmxt_init(void) | ||
57 | { | ||
58 | thread_register_notifier(&iwmmxt_notifier_block); | ||
59 | |||
60 | return 0; | ||
61 | } | ||
62 | |||
63 | late_initcall(iwmmxt_init); | ||
diff --git a/arch/arm/kernel/process.c b/arch/arm/kernel/process.c index bf35c178a877..a9e8f7e55fd6 100644 --- a/arch/arm/kernel/process.c +++ b/arch/arm/kernel/process.c | |||
@@ -281,67 +281,6 @@ void show_fpregs(struct user_fp *regs) | |||
281 | } | 281 | } |
282 | 282 | ||
283 | /* | 283 | /* |
284 | * Task structure and kernel stack allocation. | ||
285 | */ | ||
286 | struct thread_info_list { | ||
287 | unsigned long *head; | ||
288 | unsigned int nr; | ||
289 | }; | ||
290 | |||
291 | static DEFINE_PER_CPU(struct thread_info_list, thread_info_list) = { NULL, 0 }; | ||
292 | |||
293 | #define EXTRA_TASK_STRUCT 4 | ||
294 | |||
295 | struct thread_info *alloc_thread_info(struct task_struct *task) | ||
296 | { | ||
297 | struct thread_info *thread = NULL; | ||
298 | |||
299 | if (EXTRA_TASK_STRUCT) { | ||
300 | struct thread_info_list *th = &get_cpu_var(thread_info_list); | ||
301 | unsigned long *p = th->head; | ||
302 | |||
303 | if (p) { | ||
304 | th->head = (unsigned long *)p[0]; | ||
305 | th->nr -= 1; | ||
306 | } | ||
307 | put_cpu_var(thread_info_list); | ||
308 | |||
309 | thread = (struct thread_info *)p; | ||
310 | } | ||
311 | |||
312 | if (!thread) | ||
313 | thread = (struct thread_info *) | ||
314 | __get_free_pages(GFP_KERNEL, THREAD_SIZE_ORDER); | ||
315 | |||
316 | #ifdef CONFIG_DEBUG_STACK_USAGE | ||
317 | /* | ||
318 | * The stack must be cleared if you want SYSRQ-T to | ||
319 | * give sensible stack usage information | ||
320 | */ | ||
321 | if (thread) | ||
322 | memzero(thread, THREAD_SIZE); | ||
323 | #endif | ||
324 | return thread; | ||
325 | } | ||
326 | |||
327 | void free_thread_info(struct thread_info *thread) | ||
328 | { | ||
329 | if (EXTRA_TASK_STRUCT) { | ||
330 | struct thread_info_list *th = &get_cpu_var(thread_info_list); | ||
331 | if (th->nr < EXTRA_TASK_STRUCT) { | ||
332 | unsigned long *p = (unsigned long *)thread; | ||
333 | p[0] = (unsigned long)th->head; | ||
334 | th->head = p; | ||
335 | th->nr += 1; | ||
336 | put_cpu_var(thread_info_list); | ||
337 | return; | ||
338 | } | ||
339 | put_cpu_var(thread_info_list); | ||
340 | } | ||
341 | free_pages((unsigned long)thread, THREAD_SIZE_ORDER); | ||
342 | } | ||
343 | |||
344 | /* | ||
345 | * Free current thread data structures etc.. | 284 | * Free current thread data structures etc.. |
346 | */ | 285 | */ |
347 | void exit_thread(void) | 286 | void exit_thread(void) |
diff --git a/arch/arm/kernel/setup.c b/arch/arm/kernel/setup.c index 29efc9f82057..cf2bd4242803 100644 --- a/arch/arm/kernel/setup.c +++ b/arch/arm/kernel/setup.c | |||
@@ -354,12 +354,6 @@ static void __init setup_processor(void) | |||
354 | #ifndef CONFIG_ARM_THUMB | 354 | #ifndef CONFIG_ARM_THUMB |
355 | elf_hwcap &= ~HWCAP_THUMB; | 355 | elf_hwcap &= ~HWCAP_THUMB; |
356 | #endif | 356 | #endif |
357 | #ifndef CONFIG_VFP | ||
358 | elf_hwcap &= ~HWCAP_VFP; | ||
359 | #endif | ||
360 | #ifndef CONFIG_IWMMXT | ||
361 | elf_hwcap &= ~HWCAP_IWMMXT; | ||
362 | #endif | ||
363 | 357 | ||
364 | cpu_proc_init(); | 358 | cpu_proc_init(); |
365 | } | 359 | } |
@@ -441,16 +435,19 @@ __early_param("initrd=", early_initrd); | |||
441 | 435 | ||
442 | static void __init arm_add_memory(unsigned long start, unsigned long size) | 436 | static void __init arm_add_memory(unsigned long start, unsigned long size) |
443 | { | 437 | { |
438 | struct membank *bank; | ||
439 | |||
444 | /* | 440 | /* |
445 | * Ensure that start/size are aligned to a page boundary. | 441 | * Ensure that start/size are aligned to a page boundary. |
446 | * Size is appropriately rounded down, start is rounded up. | 442 | * Size is appropriately rounded down, start is rounded up. |
447 | */ | 443 | */ |
448 | size -= start & ~PAGE_MASK; | 444 | size -= start & ~PAGE_MASK; |
449 | 445 | ||
450 | meminfo.bank[meminfo.nr_banks].start = PAGE_ALIGN(start); | 446 | bank = &meminfo.bank[meminfo.nr_banks++]; |
451 | meminfo.bank[meminfo.nr_banks].size = size & PAGE_MASK; | 447 | |
452 | meminfo.bank[meminfo.nr_banks].node = PHYS_TO_NID(start); | 448 | bank->start = PAGE_ALIGN(start); |
453 | meminfo.nr_banks += 1; | 449 | bank->size = size & PAGE_MASK; |
450 | bank->node = PHYS_TO_NID(start); | ||
454 | } | 451 | } |
455 | 452 | ||
456 | /* | 453 | /* |
diff --git a/arch/arm/kernel/signal.c b/arch/arm/kernel/signal.c index 48cf7fffddf2..3843d3bab2dd 100644 --- a/arch/arm/kernel/signal.c +++ b/arch/arm/kernel/signal.c | |||
@@ -11,7 +11,9 @@ | |||
11 | #include <linux/signal.h> | 11 | #include <linux/signal.h> |
12 | #include <linux/ptrace.h> | 12 | #include <linux/ptrace.h> |
13 | #include <linux/personality.h> | 13 | #include <linux/personality.h> |
14 | #include <linux/freezer.h> | ||
14 | 15 | ||
16 | #include <asm/elf.h> | ||
15 | #include <asm/cacheflush.h> | 17 | #include <asm/cacheflush.h> |
16 | #include <asm/ucontext.h> | 18 | #include <asm/ucontext.h> |
17 | #include <asm/uaccess.h> | 19 | #include <asm/uaccess.h> |
diff --git a/arch/arm/kernel/traps.c b/arch/arm/kernel/traps.c index bede380c07a9..042a12982e98 100644 --- a/arch/arm/kernel/traps.c +++ b/arch/arm/kernel/traps.c | |||
@@ -631,12 +631,9 @@ baddataabort(int code, unsigned long instr, struct pt_regs *regs) | |||
631 | notify_die("unknown data abort code", regs, &info, instr, 0); | 631 | notify_die("unknown data abort code", regs, &info, instr, 0); |
632 | } | 632 | } |
633 | 633 | ||
634 | void __attribute__((noreturn)) __bug(const char *file, int line, void *data) | 634 | void __attribute__((noreturn)) __bug(const char *file, int line) |
635 | { | 635 | { |
636 | printk(KERN_CRIT"kernel BUG at %s:%d!", file, line); | 636 | printk(KERN_CRIT"kernel BUG at %s:%d!\n", file, line); |
637 | if (data) | ||
638 | printk(" - extra data = %p", data); | ||
639 | printk("\n"); | ||
640 | *(int *)0 = 0; | 637 | *(int *)0 = 0; |
641 | 638 | ||
642 | /* Avoid "noreturn function does return" */ | 639 | /* Avoid "noreturn function does return" */ |
diff --git a/arch/arm/kernel/xscale-cp0.c b/arch/arm/kernel/xscale-cp0.c new file mode 100644 index 000000000000..180000bfdc8f --- /dev/null +++ b/arch/arm/kernel/xscale-cp0.c | |||
@@ -0,0 +1,179 @@ | |||
1 | /* | ||
2 | * linux/arch/arm/kernel/xscale-cp0.c | ||
3 | * | ||
4 | * XScale DSP and iWMMXt coprocessor context switching and handling | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License version 2 as | ||
8 | * published by the Free Software Foundation. | ||
9 | */ | ||
10 | |||
11 | #include <linux/module.h> | ||
12 | #include <linux/types.h> | ||
13 | #include <linux/kernel.h> | ||
14 | #include <linux/signal.h> | ||
15 | #include <linux/sched.h> | ||
16 | #include <linux/init.h> | ||
17 | #include <asm/thread_notify.h> | ||
18 | #include <asm/io.h> | ||
19 | |||
20 | static inline void dsp_save_state(u32 *state) | ||
21 | { | ||
22 | __asm__ __volatile__ ( | ||
23 | "mrrc p0, 0, %0, %1, c0\n" | ||
24 | : "=r" (state[0]), "=r" (state[1])); | ||
25 | } | ||
26 | |||
27 | static inline void dsp_load_state(u32 *state) | ||
28 | { | ||
29 | __asm__ __volatile__ ( | ||
30 | "mcrr p0, 0, %0, %1, c0\n" | ||
31 | : : "r" (state[0]), "r" (state[1])); | ||
32 | } | ||
33 | |||
34 | static int dsp_do(struct notifier_block *self, unsigned long cmd, void *t) | ||
35 | { | ||
36 | struct thread_info *thread = t; | ||
37 | |||
38 | switch (cmd) { | ||
39 | case THREAD_NOTIFY_FLUSH: | ||
40 | thread->cpu_context.extra[0] = 0; | ||
41 | thread->cpu_context.extra[1] = 0; | ||
42 | break; | ||
43 | |||
44 | case THREAD_NOTIFY_SWITCH: | ||
45 | dsp_save_state(current_thread_info()->cpu_context.extra); | ||
46 | dsp_load_state(thread->cpu_context.extra); | ||
47 | break; | ||
48 | } | ||
49 | |||
50 | return NOTIFY_DONE; | ||
51 | } | ||
52 | |||
53 | static struct notifier_block dsp_notifier_block = { | ||
54 | .notifier_call = dsp_do, | ||
55 | }; | ||
56 | |||
57 | |||
58 | #ifdef CONFIG_IWMMXT | ||
59 | static int iwmmxt_do(struct notifier_block *self, unsigned long cmd, void *t) | ||
60 | { | ||
61 | struct thread_info *thread = t; | ||
62 | |||
63 | switch (cmd) { | ||
64 | case THREAD_NOTIFY_FLUSH: | ||
65 | /* | ||
66 | * flush_thread() zeroes thread->fpstate, so no need | ||
67 | * to do anything here. | ||
68 | * | ||
69 | * FALLTHROUGH: Ensure we don't try to overwrite our newly | ||
70 | * initialised state information on the first fault. | ||
71 | */ | ||
72 | |||
73 | case THREAD_NOTIFY_RELEASE: | ||
74 | iwmmxt_task_release(thread); | ||
75 | break; | ||
76 | |||
77 | case THREAD_NOTIFY_SWITCH: | ||
78 | iwmmxt_task_switch(thread); | ||
79 | break; | ||
80 | } | ||
81 | |||
82 | return NOTIFY_DONE; | ||
83 | } | ||
84 | |||
85 | static struct notifier_block iwmmxt_notifier_block = { | ||
86 | .notifier_call = iwmmxt_do, | ||
87 | }; | ||
88 | #endif | ||
89 | |||
90 | |||
91 | static u32 __init xscale_cp_access_read(void) | ||
92 | { | ||
93 | u32 value; | ||
94 | |||
95 | __asm__ __volatile__ ( | ||
96 | "mrc p15, 0, %0, c15, c1, 0\n\t" | ||
97 | : "=r" (value)); | ||
98 | |||
99 | return value; | ||
100 | } | ||
101 | |||
102 | static void __init xscale_cp_access_write(u32 value) | ||
103 | { | ||
104 | u32 temp; | ||
105 | |||
106 | __asm__ __volatile__ ( | ||
107 | "mcr p15, 0, %1, c15, c1, 0\n\t" | ||
108 | "mrc p15, 0, %0, c15, c1, 0\n\t" | ||
109 | "mov %0, %0\n\t" | ||
110 | "sub pc, pc, #4\n\t" | ||
111 | : "=r" (temp) : "r" (value)); | ||
112 | } | ||
113 | |||
114 | /* | ||
115 | * Detect whether we have a MAC coprocessor (40 bit register) or an | ||
116 | * iWMMXt coprocessor (64 bit registers) by loading 00000100:00000000 | ||
117 | * into a coprocessor register and reading it back, and checking | ||
118 | * whether the upper word survived intact. | ||
119 | */ | ||
120 | static int __init cpu_has_iwmmxt(void) | ||
121 | { | ||
122 | u32 lo; | ||
123 | u32 hi; | ||
124 | |||
125 | /* | ||
126 | * This sequence is interpreted by the DSP coprocessor as: | ||
127 | * mar acc0, %2, %3 | ||
128 | * mra %0, %1, acc0 | ||
129 | * | ||
130 | * And by the iWMMXt coprocessor as: | ||
131 | * tmcrr wR0, %2, %3 | ||
132 | * tmrrc %0, %1, wR0 | ||
133 | */ | ||
134 | __asm__ __volatile__ ( | ||
135 | "mcrr p0, 0, %2, %3, c0\n" | ||
136 | "mrrc p0, 0, %0, %1, c0\n" | ||
137 | : "=r" (lo), "=r" (hi) | ||
138 | : "r" (0), "r" (0x100)); | ||
139 | |||
140 | return !!hi; | ||
141 | } | ||
142 | |||
143 | |||
144 | /* | ||
145 | * If we detect that the CPU has iWMMXt (and CONFIG_IWMMXT=y), we | ||
146 | * disable CP0/CP1 on boot, and let call_fpe() and the iWMMXt lazy | ||
147 | * switch code handle iWMMXt context switching. If on the other | ||
148 | * hand the CPU has a DSP coprocessor, we keep access to CP0 enabled | ||
149 | * all the time, and save/restore acc0 on context switch in non-lazy | ||
150 | * fashion. | ||
151 | */ | ||
152 | static int __init xscale_cp0_init(void) | ||
153 | { | ||
154 | u32 cp_access; | ||
155 | |||
156 | cp_access = xscale_cp_access_read() & ~3; | ||
157 | xscale_cp_access_write(cp_access | 1); | ||
158 | |||
159 | if (cpu_has_iwmmxt()) { | ||
160 | #ifndef CONFIG_IWMMXT | ||
161 | printk(KERN_WARNING "CAUTION: XScale iWMMXt coprocessor " | ||
162 | "detected, but kernel support is missing.\n"); | ||
163 | #else | ||
164 | printk(KERN_INFO "XScale iWMMXt coprocessor detected.\n"); | ||
165 | elf_hwcap |= HWCAP_IWMMXT; | ||
166 | thread_register_notifier(&iwmmxt_notifier_block); | ||
167 | #endif | ||
168 | } else { | ||
169 | printk(KERN_INFO "XScale DSP coprocessor detected.\n"); | ||
170 | thread_register_notifier(&dsp_notifier_block); | ||
171 | cp_access |= 1; | ||
172 | } | ||
173 | |||
174 | xscale_cp_access_write(cp_access); | ||
175 | |||
176 | return 0; | ||
177 | } | ||
178 | |||
179 | late_initcall(xscale_cp0_init); | ||