Skip to content

Commit

Permalink
[Blackfin] arch: Remove the circular buffering mechanism for exceptions
Browse files Browse the repository at this point in the history
Remove the circular buffering mechanism for exceptions.  Instead, point RETX
at a safe location from which to fetch three NOPs.

This safe location is now in the fixed code area, and also used for certain
anomaly workarounds, to ensure that user space can find a valid ICPLB when
things are built with CONFIG_MPU.

Also, save I/DCPLB_FAULT_ADDRESS when lowering to level 5, since the hardware
reg is valid only at exception level.

Signed-off-by: Bernd Schmidt <bernds_cb1@t-online.de>
Signed-off-by: Bryan Wu <cooloney@kernel.org>
  • Loading branch information
Bernd Schmidt authored and Bryan Wu committed Apr 24, 2008
1 parent 00d205a commit 5d750b9
Show file tree
Hide file tree
Showing 3 changed files with 40 additions and 98 deletions.
15 changes: 7 additions & 8 deletions arch/blackfin/kernel/traps.c
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,8 @@ void __init trap_init(void)
CSYNC();
}

void *saved_icplb_fault_addr, *saved_dcplb_fault_addr;

int kstack_depth_to_print = 48;

static void decode_address(char *buf, unsigned long address)
Expand Down Expand Up @@ -703,10 +705,7 @@ void dump_bfin_mem(struct pt_regs *fp)
unsigned short *addr, *erraddr, val = 0, err = 0;
char sti = 0, buf[6];

if (unlikely((fp->seqstat & SEQSTAT_EXCAUSE) == VEC_HWERR))
erraddr = (void *)fp->pc;
else
erraddr = (void *)fp->retx;
erraddr = (void *)fp->pc;

printk(KERN_NOTICE "return address: [0x%p]; contents of:", erraddr);

Expand Down Expand Up @@ -830,9 +829,9 @@ void show_regs(struct pt_regs *fp)

if (((long)fp->seqstat & SEQSTAT_EXCAUSE) &&
(((long)fp->seqstat & SEQSTAT_EXCAUSE) != VEC_HWERR)) {
decode_address(buf, bfin_read_DCPLB_FAULT_ADDR());
decode_address(buf, saved_dcplb_fault_addr);
printk(KERN_NOTICE "DCPLB_FAULT_ADDR: %s\n", buf);
decode_address(buf, bfin_read_ICPLB_FAULT_ADDR());
decode_address(buf, saved_icplb_fault_addr);
printk(KERN_NOTICE "ICPLB_FAULT_ADDR: %s\n", buf);
}

Expand Down Expand Up @@ -940,8 +939,8 @@ void panic_cplb_error(int cplb_panic, struct pt_regs *fp)

oops_in_progress = 1;

printk(KERN_EMERG "DCPLB_FAULT_ADDR=%p\n", (void *)bfin_read_DCPLB_FAULT_ADDR());
printk(KERN_EMERG "ICPLB_FAULT_ADDR=%p\n", (void *)bfin_read_ICPLB_FAULT_ADDR());
printk(KERN_EMERG "DCPLB_FAULT_ADDR=%p\n", saved_dcplb_fault_addr);
printk(KERN_EMERG "ICPLB_FAULT_ADDR=%p\n", saved_icplb_fault_addr);
dump_bfin_process(fp);
dump_bfin_mem(fp);
show_regs(fp);
Expand Down
121 changes: 33 additions & 88 deletions arch/blackfin/mach-common/entry.S
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@
#include <linux/unistd.h>
#include <asm/blackfin.h>
#include <asm/errno.h>
#include <asm/fixed_code.h>
#include <asm/thread_info.h> /* TIF_NEED_RESCHED */
#include <asm/asm-offsets.h>
#include <asm/trace.h>
Expand All @@ -52,15 +53,6 @@
# define EX_SCRATCH_REG CYCLES
#endif

#if ANOMALY_05000281
ENTRY(_safe_speculative_execution)
NOP;
NOP;
NOP;
jump _safe_speculative_execution;
ENDPROC(_safe_speculative_execution)
#endif

#ifdef CONFIG_EXCPT_IRQ_SYSC_L1
.section .l1.text
#else
Expand Down Expand Up @@ -230,6 +222,26 @@ ENTRY(_ex_trap_c)
[p4] = p5;
csync;

p4.l = lo(DCPLB_FAULT_ADDR);
p4.h = hi(DCPLB_FAULT_ADDR);
r7 = [p4];
p5.h = _saved_dcplb_fault_addr;
p5.l = _saved_dcplb_fault_addr;
[p5] = r7;

r7 = [p4 + (ICPLB_FAULT_ADDR - DCPLB_FAULT_ADDR)];
p5.h = _saved_icplb_fault_addr;
p5.l = _saved_icplb_fault_addr;
[p5] = r7;

p4.l = __retx;
p4.h = __retx;
r6 = retx;
[p4] = r6;
p4.l = lo(SAFE_USER_INSTRUCTION);
p4.h = hi(SAFE_USER_INSTRUCTION);
retx = p4;

/* Disable all interrupts, but make sure level 5 is enabled so
* we can switch to that level. Save the old mask. */
cli r6;
Expand All @@ -239,23 +251,6 @@ ENTRY(_ex_trap_c)
r6 = 0x3f;
sti r6;

/* Save the excause into a circular buffer, in case the instruction
* which caused this excecptions causes others.
*/
P5.l = _in_ptr_excause;
P5.h = _in_ptr_excause;
R7 = [P5];
R7 += 4;
R6 = 0xF;
R7 = R7 & R6;
[P5] = R7;
R6.l = _excause_circ_buf;
R6.h = _excause_circ_buf;
R7 = R7 + R6;
p5 = R7;
R6 = SEQSTAT;
[P5] = R6;

(R7:6,P5:4) = [sp++];
ASTAT = [sp++];
SP = EX_SCRATCH_REG;
Expand Down Expand Up @@ -312,6 +307,11 @@ ENDPROC(_double_fault)
ENTRY(_exception_to_level5)
SAVE_ALL_SYS

p4.l = __retx;
p4.h = __retx;
r6 = [p4];
[sp + PT_PC] = r6;

/* Restore interrupt mask. We haven't pushed RETI, so this
* doesn't enable interrupts until we return from this handler. */
p4.l = _excpt_saved_imask;
Expand All @@ -333,42 +333,11 @@ ENTRY(_exception_to_level5)
r0 = [p2]; /* Read current IPEND */
[sp + PT_IPEND] = r0; /* Store IPEND */

/* Pop the excause from the circular buffer and push it on the stack
* (in the right place - if you change the location of SEQSTAT, you
* must change this offset.
*/
.L_excep_to_5_again:
P5.l = _out_ptr_excause;
P5.h = _out_ptr_excause;
R7 = [P5];
R7 += 4;
R6 = 0xF;
R7 = R7 & R6;
[P5] = R7;
R6.l = _excause_circ_buf;
R6.h = _excause_circ_buf;
R7 = R7 + R6;
P5 = R7;
R1 = [P5];
[SP + PT_SEQSTAT] = r1;

r0 = sp; /* stack frame pt_regs pointer argument ==> r0 */
SP += -12;
call _trap_c;
SP += 12;

/* See if anything else is in the exception buffer
* if there is, process it
*/
P5.l = _out_ptr_excause;
P5.h = _out_ptr_excause;
P4.l = _in_ptr_excause;
P4.h = _in_ptr_excause;
R6 = [P5];
R7 = [P4];
CC = R6 == R7;
if ! CC JUMP .L_excep_to_5_again

call _ret_from_exception;
RESTORE_ALL_SYS
rti;
Expand Down Expand Up @@ -732,8 +701,8 @@ ENTRY(_return_from_int)
[p0] = p1;
csync;
#if ANOMALY_05000281
r0.l = _safe_speculative_execution;
r0.h = _safe_speculative_execution;
r0.l = lo(SAFE_USER_INSTRUCTION);
r0.h = hi(SAFE_USER_INSTRUCTION);
reti = r0;
#endif
r0 = 0x801f (z);
Expand All @@ -746,8 +715,8 @@ ENDPROC(_return_from_int)

ENTRY(_lower_to_irq14)
#if ANOMALY_05000281
r0.l = _safe_speculative_execution;
r0.h = _safe_speculative_execution;
r0.l = lo(SAFE_USER_INSTRUCTION);
r0.h = hi(SAFE_USER_INSTRUCTION);
reti = r0;
#endif
r0 = 0x401f;
Expand Down Expand Up @@ -814,20 +783,6 @@ _schedule_and_signal:
rti;
ENDPROC(_lower_to_irq14)

/* Make sure when we start, that the circular buffer is initialized properly
* R0 and P0 are call clobbered, so we can use them here.
*/
ENTRY(_init_exception_buff)
r0 = 0;
p0.h = _in_ptr_excause;
p0.l = _in_ptr_excause;
[p0] = r0;
p0.h = _out_ptr_excause;
p0.l = _out_ptr_excause;
[p0] = r0;
rts;
ENDPROC(_init_exception_buff)

/* We handle this 100% in exception space - to reduce overhead
* Only potiential problem is if the software buffer gets swapped out of the
* CPLB table - then double fault. - so we don't let this happen in other places
Expand Down Expand Up @@ -1403,17 +1358,7 @@ _exception_stack_top:
_last_cplb_fault_retx:
.long 0;
#endif
/*
* Single instructions can have multiple faults, which need to be
* handled by traps.c, in irq5. We store the exception cause to ensure
* we don't miss a double fault condition
*/
ENTRY(_in_ptr_excause)
.long 0;
ENTRY(_out_ptr_excause)
/* Used to save the real RETX when temporarily storing a safe
* return address. */
__retx:
.long 0;
ALIGN
ENTRY(_excause_circ_buf)
.rept 4
.long 0
.endr
2 changes: 0 additions & 2 deletions arch/blackfin/mach-common/ints-priority.c
Original file line number Diff line number Diff line change
Expand Up @@ -939,8 +939,6 @@ int __init init_arch_irq(void)

local_irq_disable();

init_exception_buff();

#ifdef CONFIG_BF54x
# ifdef CONFIG_PINTx_REASSIGN
pint[0]->assign = CONFIG_PINT0_ASSIGN;
Expand Down

0 comments on commit 5d750b9

Please sign in to comment.