diff options
Diffstat (limited to 'arch/arc/kernel')
-rw-r--r-- | arch/arc/kernel/Makefile | 3 | ||||
-rw-r--r-- | arch/arc/kernel/entry-arcv2.S | 189 | ||||
-rw-r--r-- | arch/arc/kernel/head.S | 2 | ||||
-rw-r--r-- | arch/arc/kernel/process.c | 19 | ||||
-rw-r--r-- | arch/arc/kernel/ptrace.c | 2 | ||||
-rw-r--r-- | arch/arc/kernel/setup.c | 45 | ||||
-rw-r--r-- | arch/arc/kernel/signal.c | 6 | ||||
-rw-r--r-- | arch/arc/kernel/troubleshoot.c | 33 |
8 files changed, 278 insertions, 21 deletions
diff --git a/arch/arc/kernel/Makefile b/arch/arc/kernel/Makefile index cc929c0..0be7ba0 100644 --- a/arch/arc/kernel/Makefile +++ b/arch/arc/kernel/Makefile @@ -10,7 +10,8 @@ CFLAGS_ptrace.o += -DUTS_MACHINE='"$(UTS_MACHINE)"' obj-y := arcksyms.o setup.o irq.o time.o reset.o ptrace.o process.o devtree.o obj-y += signal.o traps.o sys.o troubleshoot.o stacktrace.o disasm.o clk.o -obj-y += entry-compact.o intc-compact.o +obj-$(CONFIG_ISA_ARCOMPACT) += entry-compact.o intc-compact.o +obj-$(CONFIG_ISA_ARCV2) += entry-arcv2.o intc-arcv2.o obj-$(CONFIG_MODULES) += arcksyms.o module.o obj-$(CONFIG_SMP) += smp.o diff --git a/arch/arc/kernel/entry-arcv2.S b/arch/arc/kernel/entry-arcv2.S new file mode 100644 index 0000000..c59a396 --- /dev/null +++ b/arch/arc/kernel/entry-arcv2.S @@ -0,0 +1,189 @@ +/* + * ARCv2 ISA based core Low Level Intr/Traps/Exceptions(non-TLB) Handling + * + * Copyright (C) 2013 Synopsys, Inc. (www.synopsys.com) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include <linux/linkage.h> /* ARC_{EXTRY,EXIT} */ +#include <asm/entry.h> /* SAVE_ALL_{INT1,INT2,TRAP...} */ +#include <asm/errno.h> +#include <asm/arcregs.h> +#include <asm/irqflags.h> + + .cpu HS + +#define VECTOR .word + +;############################ Vector Table ################################# + + .section .vector,"a",@progbits + .align 4 + +# Initial 16 slots are Exception Vectors +VECTOR stext ; Restart Vector (jump to entry point) +VECTOR mem_service ; Mem exception +VECTOR instr_service ; Instrn Error +VECTOR EV_MachineCheck ; Fatal Machine check +VECTOR EV_TLBMissI ; Intruction TLB miss +VECTOR EV_TLBMissD ; Data TLB miss +VECTOR EV_TLBProtV ; Protection Violation +VECTOR EV_PrivilegeV ; Privilege Violation +VECTOR EV_SWI ; Software Breakpoint +VECTOR EV_Trap ; Trap exception +VECTOR EV_Extension ; Extn Instruction Exception +VECTOR EV_DivZero ; Divide by Zero +VECTOR EV_DCError ; Data Cache Error +VECTOR EV_Misaligned ; Misaligned Data Access +VECTOR reserved ; Reserved slots +VECTOR reserved ; Reserved slots + +# Begin Interrupt Vectors +VECTOR handle_interrupt ; (16) Timer0 +VECTOR handle_interrupt ; unused (Timer1) +VECTOR handle_interrupt ; unused (WDT) +VECTOR handle_interrupt ; (19) ICI (inter core interrupt) +VECTOR handle_interrupt +VECTOR handle_interrupt +VECTOR handle_interrupt +VECTOR handle_interrupt ; (23) End of fixed IRQs + +.rept CONFIG_ARC_NUMBER_OF_INTERRUPTS - 8 + VECTOR handle_interrupt +.endr + + .section .text, "ax",@progbits + +res_service: ; processor restart + flag 0x1 ; not implemented + nop + nop + +reserved: ; processor restart + rtie ; jump to processor initializations + +;##################### Interrupt Handling ############################## + +ENTRY(handle_interrupt) + + INTERRUPT_PROLOGUE irq + + clri ; To make status32.IE agree with CPU internal state + + lr r0, [ICAUSE] + + mov blink, ret_from_exception + + b.d arch_do_IRQ + mov r1, sp + +END(handle_interrupt) + +;################### Non TLB Exception Handling ############################# + +ENTRY(EV_SWI) + flag 1 +END(EV_SWI) + +ENTRY(EV_DivZero) + flag 1 +END(EV_DivZero) + +ENTRY(EV_DCError) + flag 1 +END(EV_DCError) + +ENTRY(EV_Misaligned) + + EXCEPTION_PROLOGUE + + lr r0, [efa] ; Faulting Data address + mov r1, sp + + FAKE_RET_FROM_EXCPN + + SAVE_CALLEE_SAVED_USER + mov r2, sp ; callee_regs + + bl do_misaligned_access + + ; TBD: optimize - do this only if a callee reg was involved + ; either a dst of emulated LD/ST or src with address-writeback + RESTORE_CALLEE_SAVED_USER + + b ret_from_exception +END(EV_Misaligned) + +; --------------------------------------------- +; Protection Violation Exception Handler +; --------------------------------------------- + +ENTRY(EV_TLBProtV) + + EXCEPTION_PROLOGUE + + lr r0, [efa] ; Faulting Data address + mov r1, sp ; pt_regs + + FAKE_RET_FROM_EXCPN + + mov blink, ret_from_exception + b do_page_fault + +END(EV_TLBProtV) + +; From Linux standpoint Slow Path I/D TLB Miss is same a ProtV as they +; need to call do_page_fault(). +; ECR in pt_regs provides whether access was R/W/X + +.global call_do_page_fault +.set call_do_page_fault, EV_TLBProtV + +;############# Common Handlers for ARCompact and ARCv2 ############## + +#include "entry.S" + +;############# Return from Intr/Excp/Trap (ARCv2 ISA Specifics) ############## +; +; Restore the saved sys context (common exit-path for EXCPN/IRQ/Trap) +; IRQ shd definitely not happen between now and rtie +; All 2 entry points to here already disable interrupts + +.Lrestore_regs: + + ld r0, [sp, PT_status32] ; U/K mode at time of entry + lr r10, [AUX_IRQ_ACT] + + bmsk r11, r10, 15 ; AUX_IRQ_ACT.ACTIVE + breq r11, 0, .Lexcept_ret ; No intr active, ret from Exception + +;####### Return from Intr ####### + +debug_marker_l1: + ; Handle special case #1: (Entry via Exception, Return via IRQ) + ; + ; Exception in U mode, preempted in kernel, Intr taken (K mode), orig + ; task now returning to U mode (riding the Intr) + ; AUX_IRQ_ACTIVE won't have U bit set (since intr in K mode), hence SP + ; won't be switched to correct U mode value (from AUX_SP) + ; So force AUX_IRQ_ACT.U for such a case + + btst r0, STATUS_U_BIT ; Z flag set if K (Z clear for U) + bset.nz r11, r11, AUX_IRQ_ACT_BIT_U ; NZ means U + sr r11, [AUX_IRQ_ACT] + + INTERRUPT_EPILOGUE irq + rtie + +;####### Return from Exception / pure kernel mode ####### + +.Lexcept_ret: ; Expects r0 has PT_status32 + +debug_marker_syscall: + EXCEPTION_EPILOGUE + rtie + +END(ret_from_exception) diff --git a/arch/arc/kernel/head.S b/arch/arc/kernel/head.S index 64a92e0..812f95e 100644 --- a/arch/arc/kernel/head.S +++ b/arch/arc/kernel/head.S @@ -49,8 +49,6 @@ 1: .endm - .cpu A7 - .section .init.text, "ax",@progbits .type stext, @function .globl stext diff --git a/arch/arc/kernel/process.c b/arch/arc/kernel/process.c index b5426ba..5156043 100644 --- a/arch/arc/kernel/process.c +++ b/arch/arc/kernel/process.c @@ -44,7 +44,17 @@ SYSCALL_DEFINE0(arc_gettls) void arch_cpu_idle(void) { /* sleep, but enable all interrupts before committing */ - __asm__("sleep 0x3"); + if (is_isa_arcompact()) { + __asm__("sleep 0x3"); + } else { + /* default irq priority (<=) which can interrupt the doze */ + const int arg = 0x10 | ARCV2_IRQ_DEF_PRIO; + + __asm__ __volatile__( + "sleep %0 \n" + : + :"r"(arg)); + } } asmlinkage void ret_from_fork(void); @@ -166,7 +176,7 @@ void start_thread(struct pt_regs * regs, unsigned long pc, unsigned long usp) * [L] ZOL loop inhibited to begin with - cleared by a LP insn * Interrupts enabled */ - regs->status32 = STATUS_U_MASK | STATUS_L_MASK | STATUS_IE_MASK; + regs->status32 = STATUS_U_MASK | STATUS_L_MASK | ISA_INIT_STATUS_BITS; /* bogus seed values for debugging */ regs->lp_start = 0x10; @@ -196,8 +206,11 @@ int elf_check_arch(const struct elf32_hdr *x) { unsigned int eflags; - if (x->e_machine != EM_ARCOMPACT) + if (x->e_machine != EM_ARC_INUSE) { + pr_err("ELF not built for %s ISA\n", + is_isa_arcompact() ? "ARCompact":"ARCv2"); return 0; + } eflags = x->e_flags; if ((eflags & EF_ARC_OSABI_MSK) < EF_ARC_OSABI_CURRENT) { diff --git a/arch/arc/kernel/ptrace.c b/arch/arc/kernel/ptrace.c index 4dd9e3a..4442204 100644 --- a/arch/arc/kernel/ptrace.c +++ b/arch/arc/kernel/ptrace.c @@ -200,7 +200,7 @@ static const struct user_regset arc_regsets[] = { static const struct user_regset_view user_arc_view = { .name = UTS_MACHINE, - .e_machine = EM_ARCOMPACT, + .e_machine = EM_ARC_INUSE, .regsets = arc_regsets, .n = ARRAY_SIZE(arc_regsets) }; diff --git a/arch/arc/kernel/setup.c b/arch/arc/kernel/setup.c index 96d4480..d6fe800 100644 --- a/arch/arc/kernel/setup.c +++ b/arch/arc/kernel/setup.c @@ -96,7 +96,7 @@ static void read_arc_build_cfg_regs(void) read_decode_mmu_bcr(); read_decode_cache_bcr(); - { + if (is_isa_arcompact()) { struct bcr_fp_arcompact sp, dp; struct bcr_bpu_arcompact bpu; @@ -112,6 +112,19 @@ static void read_arc_build_cfg_regs(void) cpu->bpu.num_cache = 256 << (bpu.ent - 1); cpu->bpu.num_pred = 256 << (bpu.ent - 1); } + } else { + struct bcr_fp_arcv2 spdp; + struct bcr_bpu_arcv2 bpu; + + READ_BCR(ARC_REG_FP_V2_BCR, spdp); + cpu->extn.fpu_sp = spdp.sp ? 1 : 0; + cpu->extn.fpu_dp = spdp.dp ? 1 : 0; + + READ_BCR(ARC_REG_BPU_BCR, bpu); + cpu->bpu.ver = bpu.ver; + cpu->bpu.full = bpu.ft; + cpu->bpu.num_cache = 256 << bpu.bce; + cpu->bpu.num_pred = 2048 << bpu.pte; } READ_BCR(ARC_REG_AP_BCR, bcr); @@ -131,6 +144,7 @@ static const struct cpuinfo_data arc_cpu_tbl[] = { { {0x30, "ARC 700" }, 0x33}, { {0x34, "ARC 700 R4.10"}, 0x34}, { {0x35, "ARC 700 R4.11"}, 0x35}, + { {0x50, "ARC HS38" }, 0x51}, { {0x00, NULL } } }; @@ -149,13 +163,17 @@ static char *arc_cpu_mumbojumbo(int cpu_id, char *buf, int len) FIX_PTR(cpu); - { + if (is_isa_arcompact()) { isa_nm = "ARCompact"; be = IS_ENABLED(CONFIG_CPU_BIG_ENDIAN); atomic = cpu->isa.atomic1; if (!cpu->isa.ver) /* ISA BCR absent, use Kconfig info */ atomic = IS_ENABLED(CONFIG_ARC_HAS_LLSC); + } else { + isa_nm = "ARCv2"; + be = cpu->isa.be; + atomic = cpu->isa.atomic; } n += scnprintf(buf + n, len - n, @@ -184,14 +202,31 @@ static char *arc_cpu_mumbojumbo(int cpu_id, char *buf, int len) IS_AVAIL1(cpu->timers.t0, "Timer0 "), IS_AVAIL1(cpu->timers.t1, "Timer1 ")); - n += i = scnprintf(buf + n, len - n, "%s%s", - IS_AVAIL2(atomic, "atomic ", CONFIG_ARC_HAS_LLSC)); + n += i = scnprintf(buf + n, len - n, "%s%s%s%s%s", + IS_AVAIL2(atomic, "atomic ", CONFIG_ARC_HAS_LLSC), + IS_AVAIL2(cpu->isa.ldd, "ll64 ", CONFIG_ARC_HAS_LL64), + IS_AVAIL1(cpu->isa.unalign, "unalign (not used)")); if (i) n += scnprintf(buf + n, len - n, "\n\t\t: "); + if (cpu->extn_mpy.ver) { + if (cpu->extn_mpy.ver <= 0x2) { /* ARCompact */ + n += scnprintf(buf + n, len - n, "mpy "); + } else { + int opt = 2; /* stock MPY/MPYH */ + + if (cpu->extn_mpy.dsp) /* OPT 7-9 */ + opt = cpu->extn_mpy.dsp + 6; + + n += scnprintf(buf + n, len - n, "mpy[opt %d] ", opt); + } + n += scnprintf(buf + n, len - n, "%s", + IS_USED(CONFIG_ARC_HAS_HW_MPY)); + } + n += scnprintf(buf + n, len - n, "%s%s%s%s%s%s%s%s\n", - IS_AVAIL1(cpu->extn_mpy.ver, "mpy "), + IS_AVAIL1(cpu->isa.div_rem, "div_rem "), IS_AVAIL1(cpu->extn.norm, "norm "), IS_AVAIL1(cpu->extn.barrel, "barrel-shift "), IS_AVAIL1(cpu->extn.swap, "swap "), diff --git a/arch/arc/kernel/signal.c b/arch/arc/kernel/signal.c index b15d2fe..004b7f0 100644 --- a/arch/arc/kernel/signal.c +++ b/arch/arc/kernel/signal.c @@ -336,7 +336,7 @@ static void arc_restart_syscall(struct k_sigaction *ka, struct pt_regs *regs) * their orig user space value when we ret from kernel */ regs->r0 = regs->orig_r0; - regs->ret -= 4; + regs->ret -= is_isa_arcv2() ? 2 : 4; break; } } @@ -377,10 +377,10 @@ void do_signal(struct pt_regs *regs) if (regs->r0 == -ERESTARTNOHAND || regs->r0 == -ERESTARTSYS || regs->r0 == -ERESTARTNOINTR) { regs->r0 = regs->orig_r0; - regs->ret -= 4; + regs->ret -= is_isa_arcv2() ? 2 : 4; } else if (regs->r0 == -ERESTART_RESTARTBLOCK) { regs->r8 = __NR_restart_syscall; - regs->ret -= 4; + regs->ret -= is_isa_arcv2() ? 2 : 4; } syscall_wont_restart(regs); /* No more restarts */ } diff --git a/arch/arc/kernel/troubleshoot.c b/arch/arc/kernel/troubleshoot.c index e00a018..e0cf998 100644 --- a/arch/arc/kernel/troubleshoot.c +++ b/arch/arc/kernel/troubleshoot.c @@ -14,6 +14,7 @@ #include <linux/proc_fs.h> #include <linux/file.h> #include <asm/arcregs.h> +#include <asm/irqflags.h> /* * Common routine to print scratch regs (r0-r12) or callee regs (r13-r25) @@ -34,7 +35,10 @@ static noinline void print_reg_file(long *reg_rev, int start_num) n += scnprintf(buf + n, len - n, "\n"); /* because pt_regs has regs reversed: r12..r0, r25..r13 */ - reg_rev--; + if (is_isa_arcv2() && start_num == 0) + reg_rev++; + else + reg_rev--; } if (start_num != 0) @@ -152,6 +156,15 @@ static void show_ecr_verbose(struct pt_regs *regs) ((cause_code == 0x02) ? "Write" : "EX")); } else if (vec == ECR_V_INSN_ERR) { pr_cont("Illegal Insn\n"); +#ifdef CONFIG_ISA_ARCV2 + } else if (vec == ECR_V_MEM_ERR) { + if (cause_code == 0x00) + pr_cont("Bus Error from Insn Mem\n"); + else if (cause_code == 0x10) + pr_cont("Bus Error from Data Mem\n"); + else + pr_cont("Bus Error, check PRM\n"); +#endif } else { pr_cont("Check Programmer's Manual\n"); } @@ -185,12 +198,20 @@ void show_regs(struct pt_regs *regs) pr_info("[STAT32]: 0x%08lx", regs->status32); -#define STS_BIT(r, bit) r->status32 & STATUS_##bit##_MASK ? #bit : "" - if (!user_mode(regs)) - pr_cont(" : %2s %2s %2s %2s %2s\n", - STS_BIT(regs, AE), STS_BIT(regs, A2), STS_BIT(regs, A1), - STS_BIT(regs, E2), STS_BIT(regs, E1)); +#define STS_BIT(r, bit) r->status32 & STATUS_##bit##_MASK ? #bit" " : "" +#ifdef CONFIG_ISA_ARCOMPACT + pr_cont(" : %2s%2s%2s%2s%2s%2s%2s\n", + (regs->status32 & STATUS_U_MASK) ? "U " : "K ", + STS_BIT(regs, DE), STS_BIT(regs, AE), + STS_BIT(regs, A2), STS_BIT(regs, A1), + STS_BIT(regs, E2), STS_BIT(regs, E1)); +#else + pr_cont(" : %2s%2s%2s%2s\n", + STS_BIT(regs, IE), + (regs->status32 & STATUS_U_MASK) ? "U " : "K ", + STS_BIT(regs, DE), STS_BIT(regs, AE)); +#endif pr_info("BTA: 0x%08lx\t SP: 0x%08lx\t FP: 0x%08lx\n", regs->bta, regs->sp, regs->fp); pr_info("LPS: 0x%08lx\tLPE: 0x%08lx\tLPC: 0x%08lx\n", |