diff options
Diffstat (limited to 'arch/blackfin/mach-common/entry.S')
-rw-r--r-- | arch/blackfin/mach-common/entry.S | 189 |
1 files changed, 130 insertions, 59 deletions
diff --git a/arch/blackfin/mach-common/entry.S b/arch/blackfin/mach-common/entry.S index 847c172a99eb..90c7397036ed 100644 --- a/arch/blackfin/mach-common/entry.S +++ b/arch/blackfin/mach-common/entry.S | |||
@@ -129,6 +129,18 @@ ENTRY(_ex_icplb_miss) | |||
129 | #else | 129 | #else |
130 | call __cplb_hdr; | 130 | call __cplb_hdr; |
131 | #endif | 131 | #endif |
132 | |||
133 | #ifdef CONFIG_DEBUG_DOUBLEFAULT | ||
134 | /* While we were processing this, did we double fault? */ | ||
135 | r7 = SEQSTAT; /* reason code is in bit 5:0 */ | ||
136 | r6.l = lo(SEQSTAT_EXCAUSE); | ||
137 | r6.h = hi(SEQSTAT_EXCAUSE); | ||
138 | r7 = r7 & r6; | ||
139 | r6 = 0x25; | ||
140 | CC = R7 == R6; | ||
141 | if CC JUMP _double_fault; | ||
142 | #endif | ||
143 | |||
132 | DEBUG_HWTRACE_RESTORE(p5, r7) | 144 | DEBUG_HWTRACE_RESTORE(p5, r7) |
133 | RESTORE_ALL_SYS | 145 | RESTORE_ALL_SYS |
134 | SP = EX_SCRATCH_REG; | 146 | SP = EX_SCRATCH_REG; |
@@ -136,11 +148,8 @@ ENTRY(_ex_icplb_miss) | |||
136 | ENDPROC(_ex_icplb_miss) | 148 | ENDPROC(_ex_icplb_miss) |
137 | 149 | ||
138 | ENTRY(_ex_syscall) | 150 | ENTRY(_ex_syscall) |
139 | (R7:6,P5:4) = [sp++]; | ||
140 | ASTAT = [sp++]; | ||
141 | raise 15; /* invoked by TRAP #0, for sys call */ | 151 | raise 15; /* invoked by TRAP #0, for sys call */ |
142 | sp = EX_SCRATCH_REG; | 152 | jump.s _bfin_return_from_exception; |
143 | rtx | ||
144 | ENDPROC(_ex_syscall) | 153 | ENDPROC(_ex_syscall) |
145 | 154 | ||
146 | ENTRY(_ex_soft_bp) | 155 | ENTRY(_ex_soft_bp) |
@@ -250,6 +259,29 @@ ENTRY(_bfin_return_from_exception) | |||
250 | R7=LC1; | 259 | R7=LC1; |
251 | LC1=R7; | 260 | LC1=R7; |
252 | #endif | 261 | #endif |
262 | |||
263 | #ifdef CONFIG_DEBUG_DOUBLEFAULT | ||
264 | /* While we were processing the current exception, | ||
265 | * did we cause another, and double fault? | ||
266 | */ | ||
267 | r7 = SEQSTAT; /* reason code is in bit 5:0 */ | ||
268 | r6.l = lo(SEQSTAT_EXCAUSE); | ||
269 | r6.h = hi(SEQSTAT_EXCAUSE); | ||
270 | r7 = r7 & r6; | ||
271 | r6 = 0x25; | ||
272 | CC = R7 == R6; | ||
273 | if CC JUMP _double_fault; | ||
274 | |||
275 | /* Did we cause a HW error? */ | ||
276 | p5.l = lo(ILAT); | ||
277 | p5.h = hi(ILAT); | ||
278 | r6 = [p5]; | ||
279 | r7 = 0x20; /* Did I just cause anther HW error? */ | ||
280 | r7 = r7 & r1; | ||
281 | CC = R7 == R6; | ||
282 | if CC JUMP _double_fault; | ||
283 | #endif | ||
284 | |||
253 | (R7:6,P5:4) = [sp++]; | 285 | (R7:6,P5:4) = [sp++]; |
254 | ASTAT = [sp++]; | 286 | ASTAT = [sp++]; |
255 | sp = EX_SCRATCH_REG; | 287 | sp = EX_SCRATCH_REG; |
@@ -292,6 +324,14 @@ ENTRY(_ex_trap_c) | |||
292 | [p4] = p5; | 324 | [p4] = p5; |
293 | csync; | 325 | csync; |
294 | 326 | ||
327 | #ifndef CONFIG_DEBUG_DOUBLEFAULT | ||
328 | /* | ||
329 | * Save these registers, as they are only valid in exception context | ||
330 | * (where we are now - as soon as we defer to IRQ5, they can change) | ||
331 | * DCPLB_STATUS and ICPLB_STATUS are also only valid in EVT3, | ||
332 | * but they are not very interesting, so don't save them | ||
333 | */ | ||
334 | |||
295 | p4.l = lo(DCPLB_FAULT_ADDR); | 335 | p4.l = lo(DCPLB_FAULT_ADDR); |
296 | p4.h = hi(DCPLB_FAULT_ADDR); | 336 | p4.h = hi(DCPLB_FAULT_ADDR); |
297 | r7 = [p4]; | 337 | r7 = [p4]; |
@@ -304,12 +344,11 @@ ENTRY(_ex_trap_c) | |||
304 | p5.l = _saved_icplb_fault_addr; | 344 | p5.l = _saved_icplb_fault_addr; |
305 | [p5] = r7; | 345 | [p5] = r7; |
306 | 346 | ||
307 | p4.l = _excpt_saved_stuff; | ||
308 | p4.h = _excpt_saved_stuff; | ||
309 | |||
310 | r6 = retx; | 347 | r6 = retx; |
348 | p4.l = _saved_retx; | ||
349 | p4.h = _saved_retx; | ||
311 | [p4] = r6; | 350 | [p4] = r6; |
312 | 351 | #endif | |
313 | r6 = SYSCFG; | 352 | r6 = SYSCFG; |
314 | [p4 + 4] = r6; | 353 | [p4 + 4] = r6; |
315 | BITCLR(r6, 0); | 354 | BITCLR(r6, 0); |
@@ -327,59 +366,56 @@ ENTRY(_ex_trap_c) | |||
327 | r6 = 0x3f; | 366 | r6 = 0x3f; |
328 | sti r6; | 367 | sti r6; |
329 | 368 | ||
330 | (R7:6,P5:4) = [sp++]; | ||
331 | ASTAT = [sp++]; | ||
332 | SP = EX_SCRATCH_REG; | ||
333 | raise 5; | 369 | raise 5; |
334 | rtx; | 370 | jump.s _bfin_return_from_exception; |
335 | ENDPROC(_ex_trap_c) | 371 | ENDPROC(_ex_trap_c) |
336 | 372 | ||
337 | /* We just realized we got an exception, while we were processing a different | 373 | /* We just realized we got an exception, while we were processing a different |
338 | * exception. This is a unrecoverable event, so crash | 374 | * exception. This is a unrecoverable event, so crash |
339 | */ | 375 | */ |
340 | ENTRY(_double_fault) | 376 | ENTRY(_double_fault) |
341 | /* Turn caches & protection off, to ensure we don't get any more | 377 | /* Turn caches & protection off, to ensure we don't get any more |
342 | * double exceptions | 378 | * double exceptions |
343 | */ | 379 | */ |
344 | 380 | ||
345 | P4.L = LO(IMEM_CONTROL); | 381 | P4.L = LO(IMEM_CONTROL); |
346 | P4.H = HI(IMEM_CONTROL); | 382 | P4.H = HI(IMEM_CONTROL); |
347 | 383 | ||
348 | R5 = [P4]; /* Control Register*/ | 384 | R5 = [P4]; /* Control Register*/ |
349 | BITCLR(R5,ENICPLB_P); | 385 | BITCLR(R5,ENICPLB_P); |
350 | SSYNC; /* SSYNC required before writing to IMEM_CONTROL. */ | 386 | SSYNC; /* SSYNC required before writing to IMEM_CONTROL. */ |
351 | .align 8; | 387 | .align 8; |
352 | [P4] = R5; | 388 | [P4] = R5; |
353 | SSYNC; | 389 | SSYNC; |
354 | 390 | ||
355 | P4.L = LO(DMEM_CONTROL); | 391 | P4.L = LO(DMEM_CONTROL); |
356 | P4.H = HI(DMEM_CONTROL); | 392 | P4.H = HI(DMEM_CONTROL); |
357 | R5 = [P4]; | 393 | R5 = [P4]; |
358 | BITCLR(R5,ENDCPLB_P); | 394 | BITCLR(R5,ENDCPLB_P); |
359 | SSYNC; /* SSYNC required before writing to DMEM_CONTROL. */ | 395 | SSYNC; /* SSYNC required before writing to DMEM_CONTROL. */ |
360 | .align 8; | 396 | .align 8; |
361 | [P4] = R5; | 397 | [P4] = R5; |
362 | SSYNC; | 398 | SSYNC; |
363 | 399 | ||
364 | /* Fix up the stack */ | 400 | /* Fix up the stack */ |
365 | (R7:6,P5:4) = [sp++]; | 401 | (R7:6,P5:4) = [sp++]; |
366 | ASTAT = [sp++]; | 402 | ASTAT = [sp++]; |
367 | SP = EX_SCRATCH_REG; | 403 | SP = EX_SCRATCH_REG; |
368 | 404 | ||
369 | /* We should be out of the exception stack, and back down into | 405 | /* We should be out of the exception stack, and back down into |
370 | * kernel or user space stack | 406 | * kernel or user space stack |
371 | */ | 407 | */ |
372 | SAVE_ALL_SYS | 408 | SAVE_ALL_SYS |
373 | 409 | ||
374 | /* The dumping functions expect the return address in the RETI | 410 | /* The dumping functions expect the return address in the RETI |
375 | * slot. */ | 411 | * slot. */ |
376 | r6 = retx; | 412 | r6 = retx; |
377 | [sp + PT_PC] = r6; | 413 | [sp + PT_PC] = r6; |
378 | 414 | ||
379 | r0 = sp; /* stack frame pt_regs pointer argument ==> r0 */ | 415 | r0 = sp; /* stack frame pt_regs pointer argument ==> r0 */ |
380 | SP += -12; | 416 | SP += -12; |
381 | call _double_fault_c; | 417 | call _double_fault_c; |
382 | SP += 12; | 418 | SP += 12; |
383 | .L_double_fault_panic: | 419 | .L_double_fault_panic: |
384 | JUMP .L_double_fault_panic | 420 | JUMP .L_double_fault_panic |
385 | 421 | ||
@@ -388,8 +424,8 @@ ENDPROC(_double_fault) | |||
388 | ENTRY(_exception_to_level5) | 424 | ENTRY(_exception_to_level5) |
389 | SAVE_ALL_SYS | 425 | SAVE_ALL_SYS |
390 | 426 | ||
391 | p4.l = _excpt_saved_stuff; | 427 | p4.l = _saved_retx; |
392 | p4.h = _excpt_saved_stuff; | 428 | p4.h = _saved_retx; |
393 | r6 = [p4]; | 429 | r6 = [p4]; |
394 | [sp + PT_PC] = r6; | 430 | [sp + PT_PC] = r6; |
395 | 431 | ||
@@ -420,6 +456,17 @@ ENTRY(_exception_to_level5) | |||
420 | call _trap_c; | 456 | call _trap_c; |
421 | SP += 12; | 457 | SP += 12; |
422 | 458 | ||
459 | #ifdef CONFIG_DEBUG_DOUBLEFAULT | ||
460 | /* Grab ILAT */ | ||
461 | p2.l = lo(ILAT); | ||
462 | p2.h = hi(ILAT); | ||
463 | r0 = [p2]; | ||
464 | r1 = 0x20; /* Did I just cause anther HW error? */ | ||
465 | r0 = r0 & r1; | ||
466 | CC = R0 == R1; | ||
467 | if CC JUMP _double_fault; | ||
468 | #endif | ||
469 | |||
423 | call _ret_from_exception; | 470 | call _ret_from_exception; |
424 | RESTORE_ALL_SYS | 471 | RESTORE_ALL_SYS |
425 | rti; | 472 | rti; |
@@ -436,7 +483,39 @@ ENTRY(_trap) /* Exception: 4th entry into system event table(supervisor mode)*/ | |||
436 | /* Try to deal with syscalls quickly. */ | 483 | /* Try to deal with syscalls quickly. */ |
437 | [--sp] = ASTAT; | 484 | [--sp] = ASTAT; |
438 | [--sp] = (R7:6,P5:4); | 485 | [--sp] = (R7:6,P5:4); |
486 | |||
487 | #ifdef CONFIG_DEBUG_DOUBLEFAULT | ||
488 | /* | ||
489 | * Save these registers, as they are only valid in exception context | ||
490 | * (where we are now - as soon as we defer to IRQ5, they can change) | ||
491 | * DCPLB_STATUS and ICPLB_STATUS are also only valid in EVT3, | ||
492 | * but they are not very interesting, so don't save them | ||
493 | */ | ||
494 | |||
495 | p4.l = lo(DCPLB_FAULT_ADDR); | ||
496 | p4.h = hi(DCPLB_FAULT_ADDR); | ||
497 | r7 = [p4]; | ||
498 | p5.h = _saved_dcplb_fault_addr; | ||
499 | p5.l = _saved_dcplb_fault_addr; | ||
500 | [p5] = r7; | ||
501 | |||
502 | r7 = [p4 + (ICPLB_FAULT_ADDR - DCPLB_FAULT_ADDR)]; | ||
503 | p5.h = _saved_icplb_fault_addr; | ||
504 | p5.l = _saved_icplb_fault_addr; | ||
505 | [p5] = r7; | ||
506 | |||
507 | p4.l = _saved_retx; | ||
508 | p4.h = _saved_retx; | ||
509 | r6 = retx; | ||
510 | [p4] = r6; | ||
511 | |||
439 | r7 = SEQSTAT; /* reason code is in bit 5:0 */ | 512 | r7 = SEQSTAT; /* reason code is in bit 5:0 */ |
513 | p4.l = _saved_seqstat; | ||
514 | p4.h = _saved_seqstat; | ||
515 | [p4] = r7; | ||
516 | #else | ||
517 | r7 = SEQSTAT; /* reason code is in bit 5:0 */ | ||
518 | #endif | ||
440 | r6.l = lo(SEQSTAT_EXCAUSE); | 519 | r6.l = lo(SEQSTAT_EXCAUSE); |
441 | r6.h = hi(SEQSTAT_EXCAUSE); | 520 | r6.h = hi(SEQSTAT_EXCAUSE); |
442 | r7 = r7 & r6; | 521 | r7 = r7 & r6; |
@@ -1432,15 +1511,7 @@ ENTRY(_sys_call_table) | |||
1432 | .rept NR_syscalls-(.-_sys_call_table)/4 | 1511 | .rept NR_syscalls-(.-_sys_call_table)/4 |
1433 | .long _sys_ni_syscall | 1512 | .long _sys_ni_syscall |
1434 | .endr | 1513 | .endr |
1435 | 1514 | END(_sys_call_table) | |
1436 | /* | ||
1437 | * Used to save the real RETX, IMASK and SYSCFG when temporarily | ||
1438 | * storing safe values across the transition from exception to IRQ5. | ||
1439 | */ | ||
1440 | _excpt_saved_stuff: | ||
1441 | .long 0; | ||
1442 | .long 0; | ||
1443 | .long 0; | ||
1444 | 1515 | ||
1445 | _exception_stack: | 1516 | _exception_stack: |
1446 | .rept 1024 | 1517 | .rept 1024 |