summary refs log tree commit diff
path: root/arch/arc/kernel
diff options
context:
space:
mode:
Diffstat (limited to 'arch/arc/kernel')
-rw-r--r--arch/arc/kernel/asm-offsets.c7
-rw-r--r--arch/arc/kernel/ctx_sw.c14
-rw-r--r--arch/arc/kernel/entry.S103
-rw-r--r--arch/arc/kernel/head.S2
-rw-r--r--arch/arc/kernel/irq.c16
-rw-r--r--arch/arc/kernel/kgdb.c4
-rw-r--r--arch/arc/kernel/kprobes.c5
-rw-r--r--arch/arc/kernel/process.c9
-rw-r--r--arch/arc/kernel/ptrace.c14
-rw-r--r--arch/arc/kernel/setup.c18
-rw-r--r--arch/arc/kernel/smp.c4
-rw-r--r--arch/arc/kernel/stacktrace.c2
-rw-r--r--arch/arc/kernel/time.c17
-rw-r--r--arch/arc/kernel/traps.c52
-rw-r--r--arch/arc/kernel/troubleshoot.c31
-rw-r--r--arch/arc/kernel/unaligned.c2
-rw-r--r--arch/arc/kernel/unwind.c2
-rw-r--r--arch/arc/kernel/vmlinux.lds.S24
18 files changed, 158 insertions, 168 deletions
diff --git a/arch/arc/kernel/asm-offsets.c b/arch/arc/kernel/asm-offsets.c
index 7dcda7025241..6c3aa0edb9b5 100644
--- a/arch/arc/kernel/asm-offsets.c
+++ b/arch/arc/kernel/asm-offsets.c
@@ -24,9 +24,6 @@ int main(void)
 
 	DEFINE(THREAD_KSP, offsetof(struct thread_struct, ksp));
 	DEFINE(THREAD_CALLEE_REG, offsetof(struct thread_struct, callee_reg));
-#ifdef CONFIG_ARC_CURR_IN_REG
-	DEFINE(THREAD_USER_R25, offsetof(struct thread_struct, user_r25));
-#endif
 	DEFINE(THREAD_FAULT_ADDR,
 	       offsetof(struct thread_struct, fault_address));
 
@@ -49,7 +46,7 @@ int main(void)
 	BLANK();
 
 	DEFINE(PT_status32, offsetof(struct pt_regs, status32));
-	DEFINE(PT_orig_r8, offsetof(struct pt_regs, orig_r8_word));
+	DEFINE(PT_event, offsetof(struct pt_regs, event));
 	DEFINE(PT_sp, offsetof(struct pt_regs, sp));
 	DEFINE(PT_r0, offsetof(struct pt_regs, r0));
 	DEFINE(PT_r1, offsetof(struct pt_regs, r1));
@@ -60,5 +57,7 @@ int main(void)
 	DEFINE(PT_r6, offsetof(struct pt_regs, r6));
 	DEFINE(PT_r7, offsetof(struct pt_regs, r7));
 
+	DEFINE(SZ_CALLEE_REGS, sizeof(struct callee_regs));
+	DEFINE(SZ_PT_REGS, sizeof(struct pt_regs));
 	return 0;
 }
diff --git a/arch/arc/kernel/ctx_sw.c b/arch/arc/kernel/ctx_sw.c
index 60844dac6132..34410eb1a308 100644
--- a/arch/arc/kernel/ctx_sw.c
+++ b/arch/arc/kernel/ctx_sw.c
@@ -23,10 +23,6 @@ __switch_to(struct task_struct *prev_task, struct task_struct *next_task)
 	unsigned int tmp;
 	unsigned int prev = (unsigned int)prev_task;
 	unsigned int next = (unsigned int)next_task;
-	int num_words_to_skip = 1;
-#ifdef CONFIG_ARC_CURR_IN_REG
-	num_words_to_skip++;
-#endif
 
 	__asm__ __volatile__(
 		/* FP/BLINK save generated by gcc (standard function prologue */
@@ -44,8 +40,9 @@ __switch_to(struct task_struct *prev_task, struct task_struct *next_task)
 		"st.a    r24, [sp, -4]   \n\t"
 #ifndef CONFIG_ARC_CURR_IN_REG
 		"st.a    r25, [sp, -4]   \n\t"
+#else
+		"sub     sp, sp, 4      \n\t"	/* usual r25 placeholder */
 #endif
-		"sub     sp, sp, %4      \n\t"	/* create gutter at top */
 
 		/* set ksp of outgoing task in tsk->thread.ksp */
 		"st.as   sp, [%3, %1]    \n\t"
@@ -76,10 +73,10 @@ __switch_to(struct task_struct *prev_task, struct task_struct *next_task)
 
 		/* start loading it's CALLEE reg file */
 
-		"add    sp, sp, %4     \n\t"	/* skip gutter at top */
-
 #ifndef CONFIG_ARC_CURR_IN_REG
 		"ld.ab   r25, [sp, 4]   \n\t"
+#else
+		"add    sp, sp, 4       \n\t"
 #endif
 		"ld.ab   r24, [sp, 4]   \n\t"
 		"ld.ab   r23, [sp, 4]   \n\t"
@@ -100,8 +97,7 @@ __switch_to(struct task_struct *prev_task, struct task_struct *next_task)
 		/* FP/BLINK restore generated by gcc (standard func epilogue */
 
 		: "=r"(tmp)
-		: "n"((TASK_THREAD + THREAD_KSP) / 4), "r"(next), "r"(prev),
-		  "n"(num_words_to_skip * 4)
+		: "n"((TASK_THREAD + THREAD_KSP) / 4), "r"(next), "r"(prev)
 		: "blink"
 	);
 
diff --git a/arch/arc/kernel/entry.S b/arch/arc/kernel/entry.S
index 0c6d664d4a83..1d7165156e17 100644
--- a/arch/arc/kernel/entry.S
+++ b/arch/arc/kernel/entry.S
@@ -142,7 +142,7 @@ VECTOR   reserved                ; Reserved Exceptions
 .endr
 
 #include <linux/linkage.h>   /* ARC_{EXTRY,EXIT} */
-#include <asm/entry.h>       /* SAVE_ALL_{INT1,INT2,TRAP...} */
+#include <asm/entry.h>       /* SAVE_ALL_{INT1,INT2,SYS...} */
 #include <asm/errno.h>
 #include <asm/arcregs.h>
 #include <asm/irqflags.h>
@@ -274,10 +274,8 @@ ARC_ENTRY instr_service
 	SWITCH_TO_KERNEL_STK
 	SAVE_ALL_SYS
 
-	lr  r0, [ecr]
-	lr  r1, [efa]
-
-	mov r2, sp
+	lr  r0, [efa]
+	mov r1, sp
 
 	FAKE_RET_FROM_EXCPN r9
 
@@ -298,9 +296,8 @@ ARC_ENTRY mem_service
 	SWITCH_TO_KERNEL_STK
 	SAVE_ALL_SYS
 
-	lr  r0, [ecr]
-	lr  r1, [efa]
-	mov r2, sp
+	lr  r0, [efa]
+	mov r1, sp
 	bl  do_memory_error
 	b   ret_from_exception
 ARC_EXIT mem_service
@@ -317,11 +314,14 @@ ARC_ENTRY EV_MachineCheck
 	SWITCH_TO_KERNEL_STK
 	SAVE_ALL_SYS
 
-	lr  r0, [ecr]
-	lr  r1, [efa]
-	mov r2, sp
+	lr  r2, [ecr]
+	lr  r0, [efa]
+	mov r1, sp
+
+	lsr  	r3, r2, 8
+	bmsk 	r3, r3, 7
+	brne    r3, ECR_C_MCHK_DUP_TLB, 1f
 
-	brne    r0, 0x200100, 1f
 	bl      do_tlb_overlap_fault
 	b       ret_from_exception
 
@@ -355,8 +355,8 @@ ARC_ENTRY EV_TLBProtV
 	;  ecr and efa were not saved in case an Intr sneaks in
 	;  after fake rtie
 	;
-	lr  r3, [ecr]
-	lr  r4, [efa]
+	lr  r2, [ecr]
+	lr  r1, [efa]	; Faulting Data address
 
 	; --------(4) Return from CPU Exception Mode ---------
 	;  Fake a rtie, but rtie to next label
@@ -368,31 +368,25 @@ ARC_ENTRY EV_TLBProtV
 	;------ (5) Type of Protection Violation? ----------
 	;
 	; ProtV Hardware Exception is triggered for Access Faults of 2 types
-	;   -Access Violaton (WRITE to READ ONLY Page) - for linux COW
-	;   -Unaligned Access (READ/WRITE on odd boundary)
+	;   -Access Violaton	: 00_23_(00|01|02|03)_00
+	;			         x  r  w  r+w
+	;   -Unaligned Access	: 00_23_04_00
 	;
-	cmp r3, 0x230400    ; Misaligned data access ?
-	beq 4f
+	bbit1 r2, ECR_C_BIT_PROTV_MISALIG_DATA, 4f
 
 	;========= (6a) Access Violation Processing ========
-	cmp r3, 0x230100
-	mov r1, 0x0              ; if LD exception ? write = 0
-	mov.ne r1, 0x1           ; else write = 1
-
-	mov r2, r4              ; faulting address
 	mov r0, sp              ; pt_regs
 	bl  do_page_fault
 	b   ret_from_exception
 
 	;========== (6b) Non aligned access ============
 4:
-	mov r0, r3              ; cause code
-	mov r1, r4              ; faulting address
-	mov r2, sp              ; pt_regs
+	mov r0, r1
+	mov r1, sp              ; pt_regs
 
 #ifdef  CONFIG_ARC_MISALIGN_ACCESS
 	SAVE_CALLEE_SAVED_USER
-	mov r3, sp              ; callee_regs
+	mov r2, sp              ; callee_regs
 
 	bl  do_misaligned_access
 
@@ -419,9 +413,8 @@ ARC_ENTRY EV_PrivilegeV
 	SWITCH_TO_KERNEL_STK
 	SAVE_ALL_SYS
 
-	lr  r0, [ecr]
-	lr  r1, [efa]
-	mov r2, sp
+	lr  r0, [efa]
+	mov r1, sp
 
 	FAKE_RET_FROM_EXCPN r9
 
@@ -440,9 +433,8 @@ ARC_ENTRY EV_Extension
 	SWITCH_TO_KERNEL_STK
 	SAVE_ALL_SYS
 
-	lr  r0, [ecr]
-	lr  r1, [efa]
-	mov r2, sp
+	lr  r0, [efa]
+	mov r1, sp
 	bl  do_extension_fault
 	b   ret_from_exception
 ARC_EXIT EV_Extension
@@ -498,11 +490,8 @@ tracesys_exit:
 trap_with_param:
 
 	; stop_pc info by gdb needs this info
-	stw orig_r8_IS_BRKPT, [sp, PT_orig_r8]
-
-	mov r0, r12
-	lr  r1, [efa]
-	mov r2, sp
+	lr  r0, [efa]
+	mov r1, sp
 
 	; Now that we have read EFA, its safe to do "fake" rtie
 	;   and get out of CPU exception mode
@@ -544,11 +533,11 @@ ARC_ENTRY EV_Trap
 	lr  r9, [erstatus]
 
 	SWITCH_TO_KERNEL_STK
-	SAVE_ALL_TRAP
+	SAVE_ALL_SYS
 
 	;------- (4) What caused the Trap --------------
 	lr     r12, [ecr]
-	and.f  0, r12, ECR_PARAM_MASK
+	bmsk.f 0, r12, 7
 	bnz    trap_with_param
 
 	; ======= (5a) Trap is due to System Call ========
@@ -589,11 +578,7 @@ ARC_ENTRY ret_from_exception
 	; Pre-{IRQ,Trap,Exception} K/U mode from pt_regs->status32
 	ld  r8, [sp, PT_status32]   ; returning to User/Kernel Mode
 
-#ifdef CONFIG_PREEMPT
 	bbit0  r8, STATUS_U_BIT, resume_kernel_mode
-#else
-	bbit0  r8, STATUS_U_BIT, restore_regs
-#endif
 
 	; Before returning to User mode check-for-and-complete any pending work
 	; such as rescheduling/signal-delivery etc.
@@ -653,10 +638,10 @@ resume_user_mode_begin:
 	b      resume_user_mode_begin	; unconditionally back to U mode ret chks
 					; for single exit point from this block
 
-#ifdef CONFIG_PREEMPT
-
 resume_kernel_mode:
 
+#ifdef CONFIG_PREEMPT
+
 	; Can't preempt if preemption disabled
 	GET_CURR_THR_INFO_FROM_SP   r10
 	ld  r8, [r10, THREAD_INFO_PREEMPT_COUNT]
@@ -687,17 +672,6 @@ restore_regs :
 	; XXX can this be optimised out
 	IRQ_DISABLE_SAVE    r9, r10	;@r10 has prisitine (pre-disable) copy
 
-#ifdef CONFIG_ARC_CURR_IN_REG
-	; Restore User R25
-	; Earlier this used to be only for returning to user mode
-	; However with 2 levels of IRQ this can also happen even if
-	; in kernel mode
-	ld r9, [sp, PT_sp]
-	brhs r9, VMALLOC_START, 8f
-	RESTORE_USER_R25
-8:
-#endif
-
 	; Restore REG File. In case multiple Events outstanding,
 	; use the same priorty as rtie: EXCPN, L2 IRQ, L1 IRQ, None
 	; Note that we use realtime STATUS32 (not pt_regs->status32) to
@@ -714,28 +688,33 @@ not_exception:
 
 #ifdef CONFIG_ARC_COMPACT_IRQ_LEVELS
 
+	; Level 2 interrupt return Path - from hardware standpoint
 	bbit0  r10, STATUS_A2_BIT, not_level2_interrupt
 
 	;------------------------------------------------------------------
+	; However the context returning might not have taken L2 intr itself
+	; e.g. Task'A' user-code -> L2 intr -> schedule -> 'B' user-code ret
+	; Special considerations needed for the context which took L2 intr
+
+	ld   r9, [sp, PT_event]        ; Ensure this is L2 intr context
+	brne r9, event_IRQ2, 149f
+
+	;------------------------------------------------------------------
 	; if L2 IRQ interrupted a L1 ISR,  we'd disbaled preemption earlier
 	; so that sched doesnt move to new task, causing L1 to be delayed
 	; undeterministically. Now that we've achieved that, lets reset
 	; things to what they were, before returning from L2 context
 	;----------------------------------------------------------------
 
-	ldw  r9, [sp, PT_orig_r8]      ; get orig_r8 to make sure it is
-	brne r9, orig_r8_IS_IRQ2, 149f ; infact a L2 ISR ret path
-
 	ld r9, [sp, PT_status32]       ; get statu32_l2 (saved in pt_regs)
 	bbit0 r9, STATUS_A1_BIT, 149f  ; L1 not active when L2 IRQ, so normal
 
-	; A1 is set in status32_l2
 	; decrement thread_info->preempt_count (re-enable preemption)
 	GET_CURR_THR_INFO_FROM_SP   r10
 	ld      r9, [r10, THREAD_INFO_PREEMPT_COUNT]
 
 	; paranoid check, given A1 was active when A2 happened, preempt count
-	; must not be 0 beccause we would have incremented it.
+	; must not be 0 because we would have incremented it.
 	; If this does happen we simply HALT as it means a BUG !!!
 	cmp     r9, 0
 	bnz     2f
diff --git a/arch/arc/kernel/head.S b/arch/arc/kernel/head.S
index 006dec3fc353..2a913f85a747 100644
--- a/arch/arc/kernel/head.S
+++ b/arch/arc/kernel/head.S
@@ -27,6 +27,8 @@ stext:
 	; Don't clobber r0-r4 yet. It might have bootloader provided info
 	;-------------------------------------------------------------------
 
+	sr	@_int_vec_base_lds, [AUX_INTR_VEC_BASE]
+
 #ifdef CONFIG_SMP
 	; Only Boot (Master) proceeds. Others wait in platform dependent way
 	;	IDENTITY Reg [ 3  2  1  0 ]
diff --git a/arch/arc/kernel/irq.c b/arch/arc/kernel/irq.c
index 8115fa531575..305b3f866aa7 100644
--- a/arch/arc/kernel/irq.c
+++ b/arch/arc/kernel/irq.c
@@ -28,25 +28,17 @@
  * -Disable all IRQs (on CPU side)
  * -Optionally, setup the High priority Interrupts as Level 2 IRQs
  */
-void __cpuinit arc_init_IRQ(void)
+void arc_init_IRQ(void)
 {
 	int level_mask = 0;
 
-	write_aux_reg(AUX_INTR_VEC_BASE, _int_vec_base_lds);
-
 	/* Disable all IRQs: enable them as devices request */
 	write_aux_reg(AUX_IENABLE, 0);
 
        /* setup any high priority Interrupts (Level2 in ARCompact jargon) */
-#ifdef CONFIG_ARC_IRQ3_LV2
-	level_mask |= (1 << 3);
-#endif
-#ifdef CONFIG_ARC_IRQ5_LV2
-	level_mask |= (1 << 5);
-#endif
-#ifdef CONFIG_ARC_IRQ6_LV2
-	level_mask |= (1 << 6);
-#endif
+	level_mask |= IS_ENABLED(CONFIG_ARC_IRQ3_LV2) << 3;
+	level_mask |= IS_ENABLED(CONFIG_ARC_IRQ5_LV2) << 5;
+	level_mask |= IS_ENABLED(CONFIG_ARC_IRQ6_LV2) << 6;
 
 	if (level_mask) {
 		pr_info("Level-2 interrupts bitset %x\n", level_mask);
diff --git a/arch/arc/kernel/kgdb.c b/arch/arc/kernel/kgdb.c
index 52bdc83c1495..a7698fb14818 100644
--- a/arch/arc/kernel/kgdb.c
+++ b/arch/arc/kernel/kgdb.c
@@ -169,7 +169,7 @@ int kgdb_arch_init(void)
 	return 0;
 }
 
-void kgdb_trap(struct pt_regs *regs, int param)
+void kgdb_trap(struct pt_regs *regs)
 {
 	/* trap_s 3 is used for breakpoints that overwrite existing
 	 * instructions, while trap_s 4 is used for compiled breakpoints.
@@ -181,7 +181,7 @@ void kgdb_trap(struct pt_regs *regs, int param)
 	 * with trap_s 4 (compiled) breakpoints, continuation needs to
 	 * start after the breakpoint.
 	 */
-	if (param == 3)
+	if (regs->ecr_param == 3)
 		instruction_pointer(regs) -= BREAK_INSTR_SIZE;
 
 	kgdb_handle_exception(1, SIGTRAP, 0, regs);
diff --git a/arch/arc/kernel/kprobes.c b/arch/arc/kernel/kprobes.c
index 5a7b80e2d883..72f97822784a 100644
--- a/arch/arc/kernel/kprobes.c
+++ b/arch/arc/kernel/kprobes.c
@@ -517,8 +517,7 @@ int __kprobes arch_trampoline_kprobe(struct kprobe *p)
 	return 0;
 }
 
-void trap_is_kprobe(unsigned long cause, unsigned long address,
-		    struct pt_regs *regs)
+void trap_is_kprobe(unsigned long address, struct pt_regs *regs)
 {
-	notify_die(DIE_TRAP, "kprobe_trap", regs, address, cause, SIGTRAP);
+	notify_die(DIE_TRAP, "kprobe_trap", regs, address, 0, SIGTRAP);
 }
diff --git a/arch/arc/kernel/process.c b/arch/arc/kernel/process.c
index cad66851e0c4..07a3a968fe49 100644
--- a/arch/arc/kernel/process.c
+++ b/arch/arc/kernel/process.c
@@ -55,10 +55,8 @@ asmlinkage void ret_from_fork(void);
  * |     ...        |
  * |    unused      |
  * |                |
- * ------------------  <==== top of Stack (thread.ksp)
- * |   UNUSED 1 word|
  * ------------------
- * |     r25        |
+ * |     r25        |   <==== top of Stack (thread.ksp)
  * ~                ~
  * |    --to--      |   (CALLEE Regs of user mode)
  * |     r13        |
@@ -76,7 +74,10 @@ asmlinkage void ret_from_fork(void);
  * |    --to--      |   (scratch Regs of user mode)
  * |     r0         |
  * ------------------
- * |   UNUSED 1 word|
+ * |      SP        |
+ * |    orig_r0     |
+ * |    event/ECR   |
+ * |    user_r25    |
  * ------------------  <===== END of PAGE
  */
 int copy_thread(unsigned long clone_flags,
diff --git a/arch/arc/kernel/ptrace.c b/arch/arc/kernel/ptrace.c
index c6a81c58d0f3..333238564b67 100644
--- a/arch/arc/kernel/ptrace.c
+++ b/arch/arc/kernel/ptrace.c
@@ -40,7 +40,15 @@ static int genregs_get(struct task_struct *target,
 			offsetof(struct user_regs_struct, LOC), \
 			offsetof(struct user_regs_struct, LOC) + 4);
 
+#define REG_O_ZERO(LOC)		\
+	if (!ret)		\
+		ret = user_regset_copyout_zero(&pos, &count, &kbuf, &ubuf, \
+			offsetof(struct user_regs_struct, LOC), \
+			offsetof(struct user_regs_struct, LOC) + 4);
+
+	REG_O_ZERO(pad);
 	REG_O_CHUNK(scratch, callee, ptregs);
+	REG_O_ZERO(pad2);
 	REG_O_CHUNK(callee, efa, cregs);
 	REG_O_CHUNK(efa, stop_pc, &target->thread.fault_address);
 
@@ -88,8 +96,10 @@ static int genregs_set(struct task_struct *target,
 			offsetof(struct user_regs_struct, LOC), \
 			offsetof(struct user_regs_struct, LOC) + 4);
 
-	/* TBD: disallow updates to STATUS32, orig_r8 etc*/
-	REG_IN_CHUNK(scratch, callee, ptregs);	/* pt_regs[bta..orig_r8] */
+	REG_IGNORE_ONE(pad);
+	/* TBD: disallow updates to STATUS32 etc*/
+	REG_IN_CHUNK(scratch, pad2, ptregs);	/* pt_regs[bta..sp] */
+	REG_IGNORE_ONE(pad2);
 	REG_IN_CHUNK(callee, efa, cregs);	/* callee_regs[r25..r13] */
 	REG_IGNORE_ONE(efa);			/* efa update invalid */
 	REG_IN_ONE(stop_pc, &ptregs->ret);	/* stop_pc: PC update */
diff --git a/arch/arc/kernel/setup.c b/arch/arc/kernel/setup.c
index b2b3731dd1e9..6b083454d039 100644
--- a/arch/arc/kernel/setup.c
+++ b/arch/arc/kernel/setup.c
@@ -31,14 +31,14 @@
 int running_on_hw = 1;	/* vs. on ISS */
 
 char __initdata command_line[COMMAND_LINE_SIZE];
-struct machine_desc *machine_desc __cpuinitdata;
+struct machine_desc *machine_desc;
 
 struct task_struct *_current_task[NR_CPUS];	/* For stack switching */
 
 struct cpuinfo_arc cpuinfo_arc700[NR_CPUS];
 
 
-void __cpuinit read_arc_build_cfg_regs(void)
+void read_arc_build_cfg_regs(void)
 {
 	struct bcr_perip uncached_space;
 	struct cpuinfo_arc *cpu = &cpuinfo_arc700[smp_processor_id()];
@@ -182,7 +182,7 @@ char *arc_extn_mumbojumbo(int cpu_id, char *buf, int len)
 	FIX_PTR(cpu);
 #define IS_AVAIL1(var, str)	((var) ? str : "")
 #define IS_AVAIL2(var, str)	((var == 0x2) ? str : "")
-#define IS_USED(var)		((var) ? "(in-use)" : "(not used)")
+#define IS_USED(cfg)		(IS_ENABLED(cfg) ? "(in-use)" : "(not used)")
 
 	n += scnprintf(buf + n, len - n,
 		       "Extn [700-Base]\t: %s %s %s %s %s %s\n",
@@ -202,9 +202,9 @@ char *arc_extn_mumbojumbo(int cpu_id, char *buf, int len)
 	if (cpu->core.family == 0x34) {
 		n += scnprintf(buf + n, len - n,
 		"Extn [700-4.10]\t: LLOCK/SCOND %s, SWAPE %s, RTSC %s\n",
-			       IS_USED(__CONFIG_ARC_HAS_LLSC_VAL),
-			       IS_USED(__CONFIG_ARC_HAS_SWAPE_VAL),
-			       IS_USED(__CONFIG_ARC_HAS_RTSC_VAL));
+			       IS_USED(CONFIG_ARC_HAS_LLSC),
+			       IS_USED(CONFIG_ARC_HAS_SWAPE),
+			       IS_USED(CONFIG_ARC_HAS_RTSC));
 	}
 
 	n += scnprintf(buf + n, len - n, "Extn [CCM]\t: %s",
@@ -237,7 +237,7 @@ char *arc_extn_mumbojumbo(int cpu_id, char *buf, int len)
 	return buf;
 }
 
-void __cpuinit arc_chk_ccms(void)
+void arc_chk_ccms(void)
 {
 #if defined(CONFIG_ARC_HAS_DCCM) || defined(CONFIG_ARC_HAS_ICCM)
 	struct cpuinfo_arc *cpu = &cpuinfo_arc700[smp_processor_id()];
@@ -272,7 +272,7 @@ void __cpuinit arc_chk_ccms(void)
  * hardware has dedicated regs which need to be saved/restored on ctx-sw
  * (Single Precision uses core regs), thus kernel is kind of oblivious to it
  */
-void __cpuinit arc_chk_fpu(void)
+void arc_chk_fpu(void)
 {
 	struct cpuinfo_arc *cpu = &cpuinfo_arc700[smp_processor_id()];
 
@@ -293,7 +293,7 @@ void __cpuinit arc_chk_fpu(void)
  *    such as only for boot CPU etc
  */
 
-void __cpuinit setup_processor(void)
+void setup_processor(void)
 {
 	char str[512];
 	int cpu_id = smp_processor_id();
diff --git a/arch/arc/kernel/smp.c b/arch/arc/kernel/smp.c
index 5c7fd603d216..bca3052c956d 100644
--- a/arch/arc/kernel/smp.c
+++ b/arch/arc/kernel/smp.c
@@ -117,7 +117,7 @@ const char *arc_platform_smp_cpuinfo(void)
  * Called from asm stub in head.S
  * "current"/R25 already setup by low level boot code
  */
-void __cpuinit start_kernel_secondary(void)
+void start_kernel_secondary(void)
 {
 	struct mm_struct *mm = &init_mm;
 	unsigned int cpu = smp_processor_id();
@@ -154,7 +154,7 @@ void __cpuinit start_kernel_secondary(void)
  *
  * Essential requirements being where to run from (PC) and stack (SP)
 */
-int __cpuinit __cpu_up(unsigned int cpu, struct task_struct *idle)
+int __cpu_up(unsigned int cpu, struct task_struct *idle)
 {
 	unsigned long wait_till;
 
diff --git a/arch/arc/kernel/stacktrace.c b/arch/arc/kernel/stacktrace.c
index ca0207b9d5b6..f8b7d880304d 100644
--- a/arch/arc/kernel/stacktrace.c
+++ b/arch/arc/kernel/stacktrace.c
@@ -79,7 +79,7 @@ static void seed_unwind_frame_info(struct task_struct *tsk,
 		 * assembly code
 		 */
 		frame_info->regs.r27 = 0;
-		frame_info->regs.r28 += 64;
+		frame_info->regs.r28 += 60;
 		frame_info->call_frame = 0;
 
 	} else {
diff --git a/arch/arc/kernel/time.c b/arch/arc/kernel/time.c
index 09f4309aa2c0..0e51e69cf30d 100644
--- a/arch/arc/kernel/time.c
+++ b/arch/arc/kernel/time.c
@@ -44,13 +44,24 @@
 #include <asm/clk.h>
 #include <asm/mach_desc.h>
 
+/* Timer related Aux registers */
+#define ARC_REG_TIMER0_LIMIT	0x23	/* timer 0 limit */
+#define ARC_REG_TIMER0_CTRL	0x22	/* timer 0 control */
+#define ARC_REG_TIMER0_CNT	0x21	/* timer 0 count */
+#define ARC_REG_TIMER1_LIMIT	0x102	/* timer 1 limit */
+#define ARC_REG_TIMER1_CTRL	0x101	/* timer 1 control */
+#define ARC_REG_TIMER1_CNT	0x100	/* timer 1 count */
+
+#define TIMER_CTRL_IE		(1 << 0) /* Interupt when Count reachs limit */
+#define TIMER_CTRL_NH		(1 << 1) /* Count only when CPU NOT halted */
+
 #define ARC_TIMER_MAX	0xFFFFFFFF
 
 /********** Clock Source Device *********/
 
 #ifdef CONFIG_ARC_HAS_RTSC
 
-int __cpuinit arc_counter_setup(void)
+int arc_counter_setup(void)
 {
 	/* RTSC insn taps into cpu clk, needs no setup */
 
@@ -105,7 +116,7 @@ static bool is_usable_as_clocksource(void)
 /*
  * set 32bit TIMER1 to keep counting monotonically and wraparound
  */
-int __cpuinit arc_counter_setup(void)
+int arc_counter_setup(void)
 {
 	write_aux_reg(ARC_REG_TIMER1_LIMIT, ARC_TIMER_MAX);
 	write_aux_reg(ARC_REG_TIMER1_CNT, 0);
@@ -212,7 +223,7 @@ static struct irqaction arc_timer_irq = {
  * Setup the local event timer for @cpu
  * N.B. weak so that some exotic ARC SoCs can completely override it
  */
-void __attribute__((weak)) __cpuinit arc_local_timer_setup(unsigned int cpu)
+void __attribute__((weak)) arc_local_timer_setup(unsigned int cpu)
 {
 	struct clock_event_device *clk = &per_cpu(arc_clockevent_device, cpu);
 
diff --git a/arch/arc/kernel/traps.c b/arch/arc/kernel/traps.c
index 0471d9c9dd54..e21692d2fdab 100644
--- a/arch/arc/kernel/traps.c
+++ b/arch/arc/kernel/traps.c
@@ -28,10 +28,9 @@ void __init trap_init(void)
 	return;
 }
 
-void die(const char *str, struct pt_regs *regs, unsigned long address,
-	 unsigned long cause_reg)
+void die(const char *str, struct pt_regs *regs, unsigned long address)
 {
-	show_kernel_fault_diag(str, regs, address, cause_reg);
+	show_kernel_fault_diag(str, regs, address);
 
 	/* DEAD END */
 	__asm__("flag 1");
@@ -42,14 +41,13 @@ void die(const char *str, struct pt_regs *regs, unsigned long address,
  *  -for user faults enqueues requested signal
  *  -for kernel, chk if due to copy_(to|from)_user, otherwise die()
  */
-static noinline int handle_exception(unsigned long cause, char *str,
-				     struct pt_regs *regs, siginfo_t *info)
+static noinline int
+handle_exception(const char *str, struct pt_regs *regs, siginfo_t *info)
 {
 	if (user_mode(regs)) {
 		struct task_struct *tsk = current;
 
 		tsk->thread.fault_address = (__force unsigned int)info->si_addr;
-		tsk->thread.cause_code = cause;
 
 		force_sig_info(info->si_signo, info, tsk);
 
@@ -58,14 +56,14 @@ static noinline int handle_exception(unsigned long cause, char *str,
 		if (fixup_exception(regs))
 			return 0;
 
-		die(str, regs, (unsigned long)info->si_addr, cause);
+		die(str, regs, (unsigned long)info->si_addr);
 	}
 
 	return 1;
 }
 
 #define DO_ERROR_INFO(signr, str, name, sicode) \
-int name(unsigned long cause, unsigned long address, struct pt_regs *regs) \
+int name(unsigned long address, struct pt_regs *regs) \
 {						\
 	siginfo_t info = {			\
 		.si_signo = signr,		\
@@ -73,7 +71,7 @@ int name(unsigned long cause, unsigned long address, struct pt_regs *regs) \
 		.si_code  = sicode,		\
 		.si_addr = (void __user *)address,	\
 	};					\
-	return handle_exception(cause, str, regs, &info);\
+	return handle_exception(str, regs, &info);\
 }
 
 /*
@@ -90,11 +88,11 @@ DO_ERROR_INFO(SIGBUS, "Misaligned Access", do_misaligned_error, BUS_ADRALN)
 /*
  * Entry Point for Misaligned Data access Exception, for emulating in software
  */
-int do_misaligned_access(unsigned long cause, unsigned long address,
-			 struct pt_regs *regs, struct callee_regs *cregs)
+int do_misaligned_access(unsigned long address, struct pt_regs *regs,
+			 struct callee_regs *cregs)
 {
-	if (misaligned_fixup(address, regs, cause, cregs) != 0)
-		return do_misaligned_error(cause, address, regs);
+	if (misaligned_fixup(address, regs, cregs) != 0)
+		return do_misaligned_error(address, regs);
 
 	return 0;
 }
@@ -104,10 +102,9 @@ int do_misaligned_access(unsigned long cause, unsigned long address,
  * Entry point for miscll errors such as Nested Exceptions
  *  -Duplicate TLB entry is handled seperately though
  */
-void do_machine_check_fault(unsigned long cause, unsigned long address,
-			    struct pt_regs *regs)
+void do_machine_check_fault(unsigned long address, struct pt_regs *regs)
 {
-	die("Machine Check Exception", regs, address, cause);
+	die("Machine Check Exception", regs, address);
 }
 
 
@@ -120,23 +117,22 @@ void do_machine_check_fault(unsigned long cause, unsigned long address,
  *  -1 used for software breakpointing (gdb)
  *  -2 used by kprobes
  */
-void do_non_swi_trap(unsigned long cause, unsigned long address,
-			struct pt_regs *regs)
+void do_non_swi_trap(unsigned long address, struct pt_regs *regs)
 {
-	unsigned int param = cause & 0xff;
+	unsigned int param = regs->ecr_param;
 
 	switch (param) {
 	case 1:
-		trap_is_brkpt(cause, address, regs);
+		trap_is_brkpt(address, regs);
 		break;
 
 	case 2:
-		trap_is_kprobe(param, address, regs);
+		trap_is_kprobe(address, regs);
 		break;
 
 	case 3:
 	case 4:
-		kgdb_trap(regs, param);
+		kgdb_trap(regs);
 		break;
 
 	default:
@@ -149,14 +145,14 @@ void do_non_swi_trap(unsigned long cause, unsigned long address,
  *  -For a corner case, ARC kprobes implementation resorts to using
  *   this exception, hence the check
  */
-void do_insterror_or_kprobe(unsigned long cause,
-				       unsigned long address,
-				       struct pt_regs *regs)
+void do_insterror_or_kprobe(unsigned long address, struct pt_regs *regs)
 {
+	int rc;
+
 	/* Check if this exception is caused by kprobes */
-	if (notify_die(DIE_IERR, "kprobe_ierr", regs, address,
-		       cause, SIGILL) == NOTIFY_STOP)
+	rc = notify_die(DIE_IERR, "kprobe_ierr", regs, address, 0, SIGILL);
+	if (rc == NOTIFY_STOP)
 		return;
 
-	insterror_is_error(cause, address, regs);
+	insterror_is_error(address, regs);
 }
diff --git a/arch/arc/kernel/troubleshoot.c b/arch/arc/kernel/troubleshoot.c
index a03528ecd276..73a7450ee622 100644
--- a/arch/arc/kernel/troubleshoot.c
+++ b/arch/arc/kernel/troubleshoot.c
@@ -117,23 +117,22 @@ static void show_faulting_vma(unsigned long address, char *buf)
 
 static void show_ecr_verbose(struct pt_regs *regs)
 {
-	unsigned int vec, cause_code, cause_reg;
+	unsigned int vec, cause_code;
 	unsigned long address;
 
-	cause_reg = current->thread.cause_code;
-	pr_info("\n[ECR   ]: 0x%08x => ", cause_reg);
+	pr_info("\n[ECR   ]: 0x%08lx => ", regs->event);
 
 	/* For Data fault, this is data address not instruction addr */
 	address = current->thread.fault_address;
 
-	vec = cause_reg >> 16;
-	cause_code = (cause_reg >> 8) & 0xFF;
+	vec = regs->ecr_vec;
+	cause_code = regs->ecr_cause;
 
 	/* For DTLB Miss or ProtV, display the memory involved too */
 	if (vec == ECR_V_DTLB_MISS) {
-		pr_cont("Invalid %s 0x%08lx by insn @ 0x%08lx\n",
-		       (cause_code == 0x01) ? "Read From" :
-		       ((cause_code == 0x02) ? "Write to" : "EX"),
+		pr_cont("Invalid %s @ 0x%08lx by insn @ 0x%08lx\n",
+		       (cause_code == 0x01) ? "Read" :
+		       ((cause_code == 0x02) ? "Write" : "EX"),
 		       address, regs->ret);
 	} else if (vec == ECR_V_ITLB_MISS) {
 		pr_cont("Insn could not be fetched\n");
@@ -144,14 +143,12 @@ static void show_ecr_verbose(struct pt_regs *regs)
 	} else if (vec == ECR_V_PROTV) {
 		if (cause_code == ECR_C_PROTV_INST_FETCH)
 			pr_cont("Execute from Non-exec Page\n");
-		else if (cause_code == ECR_C_PROTV_LOAD)
-			pr_cont("Read from Non-readable Page\n");
-		else if (cause_code == ECR_C_PROTV_STORE)
-			pr_cont("Write to Non-writable Page\n");
-		else if (cause_code == ECR_C_PROTV_XCHG)
-			pr_cont("Data exchange protection violation\n");
 		else if (cause_code == ECR_C_PROTV_MISALIG_DATA)
 			pr_cont("Misaligned r/w from 0x%08lx\n", address);
+		else
+			pr_cont("%s access not allowed on page\n",
+				(cause_code == 0x01) ? "Read" :
+				((cause_code == 0x02) ? "Write" : "EX"));
 	} else if (vec == ECR_V_INSN_ERR) {
 		pr_cont("Illegal Insn\n");
 	} else {
@@ -176,8 +173,7 @@ void show_regs(struct pt_regs *regs)
 	print_task_path_n_nm(tsk, buf);
 	show_regs_print_info(KERN_INFO);
 
-	if (current->thread.cause_code)
-		show_ecr_verbose(regs);
+	show_ecr_verbose(regs);
 
 	pr_info("[EFA   ]: 0x%08lx\n[BLINK ]: %pS\n[ERET  ]: %pS\n",
 		current->thread.fault_address,
@@ -213,10 +209,9 @@ void show_regs(struct pt_regs *regs)
 }
 
 void show_kernel_fault_diag(const char *str, struct pt_regs *regs,
-			    unsigned long address, unsigned long cause_reg)
+			    unsigned long address)
 {
 	current->thread.fault_address = address;
-	current->thread.cause_code = cause_reg;
 
 	/* Caller and Callee regs */
 	show_regs(regs);
diff --git a/arch/arc/kernel/unaligned.c b/arch/arc/kernel/unaligned.c
index 4cd81633febd..c0f832f595d3 100644
--- a/arch/arc/kernel/unaligned.c
+++ b/arch/arc/kernel/unaligned.c
@@ -187,7 +187,7 @@ fault:	state->fault = 1;
  * Returns 0 if successfully handled, 1 if some error happened
  */
 int misaligned_fixup(unsigned long address, struct pt_regs *regs,
-		     unsigned long cause, struct callee_regs *cregs)
+		     struct callee_regs *cregs)
 {
 	struct disasm_state state;
 	char buf[TASK_COMM_LEN];
diff --git a/arch/arc/kernel/unwind.c b/arch/arc/kernel/unwind.c
index a8d02223da44..e550b117ec4f 100644
--- a/arch/arc/kernel/unwind.c
+++ b/arch/arc/kernel/unwind.c
@@ -289,6 +289,8 @@ static void __init setup_unwind_table(struct unwind_table *table,
 			 * instead of the initial loc addr
 			 * return;
 			 */
+			WARN(1, "unwinder: FDE->initial_location NULL %p\n",
+				(const u8 *)(fde + 1) + *fde);
 		}
 		++n;
 	}
diff --git a/arch/arc/kernel/vmlinux.lds.S b/arch/arc/kernel/vmlinux.lds.S
index d3c92f52d444..2555f5886af6 100644
--- a/arch/arc/kernel/vmlinux.lds.S
+++ b/arch/arc/kernel/vmlinux.lds.S
@@ -125,6 +125,11 @@ SECTIONS
 		*(.debug_frame)
 		__end_unwind = .;
 	}
+	/*
+	 * gcc 4.8 generates this for -fasynchonous-unwind-tables,
+	 * while we still use the .debug_frame based unwinder
+	 */
+	/DISCARD/ : {	*(.eh_frame) }
 #else
 	/DISCARD/ : {	*(.debug_frame) }
 #endif
@@ -142,15 +147,18 @@ SECTIONS
 		*(.arcextmap.*)
 	}
 
+#ifndef CONFIG_DEBUG_INFO
 	/* open-coded because we need .debug_frame seperately for unwinding */
-	.debug_aranges 0 : { *(.debug_aranges) }
-	.debug_pubnames 0 : { *(.debug_pubnames) }
-	.debug_info 0 : { *(.debug_info) }
-	.debug_abbrev 0 : { *(.debug_abbrev) }
-	.debug_line 0 : { *(.debug_line) }
-	.debug_str 0 : { *(.debug_str) }
-	.debug_loc 0 : { *(.debug_loc) }
-	.debug_macinfo 0 : { *(.debug_macinfo) }
+	/DISCARD/ : { *(.debug_aranges) }
+	/DISCARD/ : { *(.debug_pubnames) }
+	/DISCARD/ : { *(.debug_info) }
+	/DISCARD/ : { *(.debug_abbrev) }
+	/DISCARD/ : { *(.debug_line) }
+	/DISCARD/ : { *(.debug_str) }
+	/DISCARD/ : { *(.debug_loc) }
+	/DISCARD/ : { *(.debug_macinfo) }
+	/DISCARD/ : { *(.debug_ranges) }
+#endif
 
 #ifdef CONFIG_ARC_HAS_DCCM
 	. = CONFIG_ARC_DCCM_BASE;