summaryrefslogtreecommitdiffstats
path: root/arch/arc
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2019-07-17 00:07:51 +0200
committerLinus Torvalds <torvalds@linux-foundation.org>2019-07-17 00:07:51 +0200
commit3eb514866f20c5eb74637279774b6d73b855480a (patch)
tree72506a3ee7caf658db86a63d1f21a483f8a5d6d6 /arch/arc
parentMerge tag 'docs/v5.3-1' of git://git.kernel.org/pub/scm/linux/kernel/git/mche... (diff)
parentARC: [plat-hsdk]: Enable AXI DW DMAC in defconfig (diff)
downloadlinux-3eb514866f20c5eb74637279774b6d73b855480a.tar.xz
linux-3eb514866f20c5eb74637279774b6d73b855480a.zip
Merge tag 'arc-5.3-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/vgupta/arc
Pull ARC updates from Vineet Gupta: - long due rewrite of do_page_fault - refactoring of entry/exit code to utilize the double load/store instructions - hsdk platform updates * tag 'arc-5.3-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/vgupta/arc: ARC: [plat-hsdk]: Enable AXI DW DMAC in defconfig ARC: [plat-hsdk]: enable DW SPI controller ARC: hide unused function unw_hdr_alloc ARC: [haps] Add Virtio support ARCv2: entry: simplify return to Delay Slot via interrupt ARC: entry: EV_Trap expects r10 (vs. r9) to have exception cause ARCv2: entry: rewrite to enable use of double load/stores LDD/STD ARCv2: entry: avoid a branch ARCv2: entry: push out the Z flag unclobber from common EXCEPTION_PROLOGUE ARCv2: entry: comments about hardware auto-save on taken interrupts ARC: mm: do_page_fault refactor #8: release mmap_sem sooner ARC: mm: do_page_fault refactor #7: fold the various error handling ARC: mm: do_page_fault refactor #6: error handlers to use same pattern ARC: mm: do_page_fault refactor #5: scoot no_context to end ARC: mm: do_page_fault refactor #4: consolidate retry related logic ARC: mm: do_page_fault refactor #3: tidyup vma access permission code ARC: mm: do_page_fault refactor #2: remove short lived variable ARC: mm: do_page_fault refactor #1: remove label @good_area
Diffstat (limited to 'arch/arc')
-rw-r--r--arch/arc/boot/dts/haps_hs.dts30
-rw-r--r--arch/arc/boot/dts/hsdk.dts14
-rw-r--r--arch/arc/configs/haps_hs_defconfig5
-rw-r--r--arch/arc/configs/hsdk_defconfig5
-rw-r--r--arch/arc/include/asm/entry-arcv2.h361
-rw-r--r--arch/arc/include/asm/entry-compact.h4
-rw-r--r--arch/arc/include/asm/linkage.h18
-rw-r--r--arch/arc/kernel/asm-offsets.c7
-rw-r--r--arch/arc/kernel/entry-arcv2.S62
-rw-r--r--arch/arc/kernel/entry-compact.S2
-rw-r--r--arch/arc/kernel/entry.S4
-rw-r--r--arch/arc/kernel/unwind.c9
-rw-r--r--arch/arc/mm/fault.c185
-rw-r--r--arch/arc/mm/tlbex.S11
14 files changed, 377 insertions, 340 deletions
diff --git a/arch/arc/boot/dts/haps_hs.dts b/arch/arc/boot/dts/haps_hs.dts
index 1ebfa046492b..44bc522fdec8 100644
--- a/arch/arc/boot/dts/haps_hs.dts
+++ b/arch/arc/boot/dts/haps_hs.dts
@@ -62,5 +62,35 @@
#interrupt-cells = <1>;
interrupts = <20>;
};
+
+ virtio0: virtio@f0100000 {
+ compatible = "virtio,mmio";
+ reg = <0xf0100000 0x2000>;
+ interrupts = <31>;
+ };
+
+ virtio1: virtio@f0102000 {
+ compatible = "virtio,mmio";
+ reg = <0xf0102000 0x2000>;
+ interrupts = <32>;
+ };
+
+ virtio2: virtio@f0104000 {
+ compatible = "virtio,mmio";
+ reg = <0xf0104000 0x2000>;
+ interrupts = <33>;
+ };
+
+ virtio3: virtio@f0106000 {
+ compatible = "virtio,mmio";
+ reg = <0xf0106000 0x2000>;
+ interrupts = <34>;
+ };
+
+ virtio4: virtio@f0108000 {
+ compatible = "virtio,mmio";
+ reg = <0xf0108000 0x2000>;
+ interrupts = <35>;
+ };
};
};
diff --git a/arch/arc/boot/dts/hsdk.dts b/arch/arc/boot/dts/hsdk.dts
index 9a45cb093096..bfc7f5f5d6f2 100644
--- a/arch/arc/boot/dts/hsdk.dts
+++ b/arch/arc/boot/dts/hsdk.dts
@@ -8,6 +8,7 @@
*/
/dts-v1/;
+#include <dt-bindings/gpio/gpio.h>
#include <dt-bindings/reset/snps,hsdk-reset.h>
/ {
@@ -252,6 +253,19 @@
dma-coherent;
};
+ spi0: spi@20000 {
+ compatible = "snps,dw-apb-ssi";
+ reg = <0x20000 0x100>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ interrupts = <16>;
+ num-cs = <2>;
+ reg-io-width = <4>;
+ clocks = <&input_clk>;
+ cs-gpios = <&creg_gpio 0 GPIO_ACTIVE_LOW>,
+ <&creg_gpio 1 GPIO_ACTIVE_LOW>;
+ };
+
creg_gpio: gpio@14b0 {
compatible = "snps,creg-gpio-hsdk";
reg = <0x14b0 0x4>;
diff --git a/arch/arc/configs/haps_hs_defconfig b/arch/arc/configs/haps_hs_defconfig
index b117e6c16d41..436f2135bdc1 100644
--- a/arch/arc/configs/haps_hs_defconfig
+++ b/arch/arc/configs/haps_hs_defconfig
@@ -35,10 +35,12 @@ CONFIG_INET=y
# CONFIG_IPV6 is not set
# CONFIG_WIRELESS is not set
CONFIG_DEVTMPFS=y
+CONFIG_DEVTMPFS_MOUNT=y
# CONFIG_STANDALONE is not set
# CONFIG_PREVENT_FIRMWARE_BUILD is not set
-# CONFIG_BLK_DEV is not set
+CONFIG_VIRTIO_BLK=y
CONFIG_NETDEVICES=y
+CONFIG_VIRTIO_NET=y
# CONFIG_NET_VENDOR_ARC is not set
# CONFIG_NET_VENDOR_BROADCOM is not set
# CONFIG_NET_VENDOR_INTEL is not set
@@ -68,6 +70,7 @@ CONFIG_FRAMEBUFFER_CONSOLE=y
CONFIG_LOGO=y
# CONFIG_HID is not set
# CONFIG_USB_SUPPORT is not set
+CONFIG_VIRTIO_MMIO=y
# CONFIG_IOMMU_SUPPORT is not set
CONFIG_EXT2_FS=y
CONFIG_EXT2_FS_XATTR=y
diff --git a/arch/arc/configs/hsdk_defconfig b/arch/arc/configs/hsdk_defconfig
index c8fb5d60c53f..403125d9c9a3 100644
--- a/arch/arc/configs/hsdk_defconfig
+++ b/arch/arc/configs/hsdk_defconfig
@@ -46,6 +46,9 @@ CONFIG_SERIAL_8250_CONSOLE=y
CONFIG_SERIAL_8250_DW=y
CONFIG_SERIAL_OF_PLATFORM=y
# CONFIG_HW_RANDOM is not set
+CONFIG_SPI=y
+CONFIG_SPI_DESIGNWARE=y
+CONFIG_SPI_DW_MMIO=y
CONFIG_GPIOLIB=y
CONFIG_GPIO_SYSFS=y
CONFIG_GPIO_DWAPB=y
@@ -66,6 +69,8 @@ CONFIG_MMC=y
CONFIG_MMC_SDHCI=y
CONFIG_MMC_SDHCI_PLTFM=y
CONFIG_MMC_DW=y
+CONFIG_DMADEVICES=y
+CONFIG_DW_AXI_DMAC=y
CONFIG_EXT3_FS=y
CONFIG_VFAT_FS=y
CONFIG_TMPFS=y
diff --git a/arch/arc/include/asm/entry-arcv2.h b/arch/arc/include/asm/entry-arcv2.h
index 225e7df2d8ed..f5ae394ebe06 100644
--- a/arch/arc/include/asm/entry-arcv2.h
+++ b/arch/arc/include/asm/entry-arcv2.h
@@ -7,232 +7,251 @@
#include <asm/irqflags-arcv2.h>
#include <asm/thread_info.h> /* For THREAD_SIZE */
+/*
+ * Interrupt/Exception stack layout (pt_regs) for ARCv2
+ * (End of struct aligned to end of page [unless nested])
+ *
+ * INTERRUPT EXCEPTION
+ *
+ * manual --------------------- manual
+ * | orig_r0 |
+ * | event/ECR |
+ * | bta |
+ * | user_r25 |
+ * | gp |
+ * | fp |
+ * | sp |
+ * | r12 |
+ * | r30 |
+ * | r58 |
+ * | r59 |
+ * hw autosave ---------------------
+ * optional | r0 |
+ * | r1 |
+ * ~ ~
+ * | r9 |
+ * | r10 |
+ * | r11 |
+ * | blink |
+ * | lpe |
+ * | lps |
+ * | lpc |
+ * | ei base |
+ * | ldi base |
+ * | jli base |
+ * ---------------------
+ * hw autosave | pc / eret |
+ * mandatory | stat32 / erstatus |
+ * ---------------------
+ */
+
/*------------------------------------------------------------------------*/
-.macro INTERRUPT_PROLOGUE called_from
+.macro INTERRUPT_PROLOGUE
- ; Before jumping to Interrupt Vector, hardware micro-ops did following:
+ ; (A) Before jumping to Interrupt Vector, hardware micro-ops did following:
; 1. SP auto-switched to kernel mode stack
- ; 2. STATUS32.Z flag set to U mode at time of interrupt (U:1, K:0)
- ; 3. Auto saved: r0-r11, blink, LPE,LPS,LPC, JLI,LDI,EI, PC, STAT32
+ ; 2. STATUS32.Z flag set if in U mode at time of interrupt (U:1,K:0)
+ ; 3. Auto save: (mandatory) Push PC and STAT32 on stack
+ ; hardware does even if CONFIG_ARC_IRQ_NO_AUTOSAVE
+ ; 4. Auto save: (optional) r0-r11, blink, LPE,LPS,LPC, JLI,LDI,EI
;
- ; Now manually save: r12, sp, fp, gp, r25
+ ; (B) Manually saved some regs: r12,r25,r30, sp,fp,gp, ACCL pair
#ifdef CONFIG_ARC_IRQ_NO_AUTOSAVE
-.ifnc \called_from, exception
- st.as r9, [sp, -10] ; save r9 in it's final stack slot
- sub sp, sp, 12 ; skip JLI, LDI, EI
-
- PUSH lp_count
- PUSHAX lp_start
- PUSHAX lp_end
- PUSH blink
-
- PUSH r11
- PUSH r10
-
- sub sp, sp, 4 ; skip r9
-
- PUSH r8
- PUSH r7
- PUSH r6
- PUSH r5
- PUSH r4
- PUSH r3
- PUSH r2
- PUSH r1
- PUSH r0
-.endif
-#endif
+ ; carve pt_regs on stack (case #3), PC/STAT32 already on stack
+ sub sp, sp, SZ_PT_REGS - 8
-#ifdef CONFIG_ARC_HAS_ACCL_REGS
- PUSH r59
- PUSH r58
+ __SAVE_REGFILE_HARD
+#else
+ ; carve pt_regs on stack (case #4), which grew partially already
+ sub sp, sp, PT_r0
#endif
- PUSH r30
- PUSH r12
+ __SAVE_REGFILE_SOFT
+.endm
+
+/*------------------------------------------------------------------------*/
+.macro EXCEPTION_PROLOGUE
+
+ ; (A) Before jumping to Exception Vector, hardware micro-ops did following:
+ ; 1. SP auto-switched to kernel mode stack
+ ; 2. STATUS32.Z flag set if in U mode at time of exception (U:1,K:0)
+ ;
+ ; (B) Manually save the complete reg file below
+
+ sub sp, sp, SZ_PT_REGS ; carve pt_regs
+
+ ; _HARD saves r10 clobbered by _SOFT as scratch hence comes first
+
+ __SAVE_REGFILE_HARD
+ __SAVE_REGFILE_SOFT
+
+ st r0, [sp] ; orig_r0
+
+ lr r10, [eret]
+ lr r11, [erstatus]
+ ST2 r10, r11, PT_ret
+
+ lr r10, [ecr]
+ lr r11, [erbta]
+ ST2 r10, r11, PT_event
+
+ ; OUTPUT: r10 has ECR expected by EV_Trap
+.endm
+
+/*------------------------------------------------------------------------
+ * This macro saves the registers manually which would normally be autosaved
+ * by hardware on taken interrupts. It is used by
+ * - exception handlers (which don't have autosave)
+ * - interrupt autosave disabled due to CONFIG_ARC_IRQ_NO_AUTOSAVE
+ */
+.macro __SAVE_REGFILE_HARD
+
+ ST2 r0, r1, PT_r0
+ ST2 r2, r3, PT_r2
+ ST2 r4, r5, PT_r4
+ ST2 r6, r7, PT_r6
+ ST2 r8, r9, PT_r8
+ ST2 r10, r11, PT_r10
+
+ st blink, [sp, PT_blink]
+
+ lr r10, [lp_end]
+ lr r11, [lp_start]
+ ST2 r10, r11, PT_lpe
+
+ st lp_count, [sp, PT_lpc]
+
+ ; skip JLI, LDI, EI for now
+.endm
+
+/*------------------------------------------------------------------------
+ * This macros saves a bunch of other registers which can't be autosaved for
+ * various reasons:
+ * - r12: the last caller saved scratch reg since hardware saves in pairs so r0-r11
+ * - r30: free reg, used by gcc as scratch
+ * - ACCL/ACCH pair when they exist
+ */
+.macro __SAVE_REGFILE_SOFT
+
+ ST2 gp, fp, PT_r26 ; gp (r26), fp (r27)
+
+ st r12, [sp, PT_sp + 4]
+ st r30, [sp, PT_sp + 8]
; Saving pt_regs->sp correctly requires some extra work due to the way
; Auto stack switch works
; - U mode: retrieve it from AUX_USER_SP
; - K mode: add the offset from current SP where H/w starts auto push
;
- ; Utilize the fact that Z bit is set if Intr taken in U mode
- mov.nz r9, sp
- add.nz r9, r9, SZ_PT_REGS - PT_sp - 4
- bnz 1f
+ ; 1. Utilize the fact that Z bit is set if Intr taken in U mode
+ ; 2. Upon entry SP is always saved (for any inspection, unwinding etc),
+ ; but on return, restored only if U mode
- lr r9, [AUX_USER_SP]
-1:
- PUSH r9 ; SP
+ lr r10, [AUX_USER_SP] ; U mode SP
+
+ ; ISA requires ADD.nz to have same dest and src reg operands
+ mov.nz r10, sp
+ add.nz r10, r10, SZ_PT_REGS ; K mode SP
- PUSH fp
- PUSH gp
+ st r10, [sp, PT_sp] ; SP (pt_regs->sp)
#ifdef CONFIG_ARC_CURR_IN_REG
- PUSH r25 ; user_r25
+ st r25, [sp, PT_user_r25]
GET_CURR_TASK_ON_CPU r25
-#else
- sub sp, sp, 4
#endif
-.ifnc \called_from, exception
- sub sp, sp, 12 ; BTA/ECR/orig_r0 placeholder per pt_regs
-.endif
+#ifdef CONFIG_ARC_HAS_ACCL_REGS
+ ST2 r58, r59, PT_sp + 12
+#endif
.endm
/*------------------------------------------------------------------------*/
-.macro INTERRUPT_EPILOGUE called_from
+.macro __RESTORE_REGFILE_SOFT
-.ifnc \called_from, exception
- add sp, sp, 12 ; skip BTA/ECR/orig_r0 placeholderss
-.endif
+ LD2 gp, fp, PT_r26 ; gp (r26), fp (r27)
-#ifdef CONFIG_ARC_CURR_IN_REG
- POP r25
-#else
- add sp, sp, 4
-#endif
+ ld r12, [sp, PT_sp + 4]
+ ld r30, [sp, PT_sp + 8]
- POP gp
- POP fp
-
- ; Don't touch AUX_USER_SP if returning to K mode (Z bit set)
- ; (Z bit set on K mode is inverse of INTERRUPT_PROLOGUE)
- add.z sp, sp, 4
+ ; Restore SP (into AUX_USER_SP) only if returning to U mode
+ ; - for K mode, it will be implicitly restored as stack is unwound
+ ; - Z flag set on K is inverse of what hardware does on interrupt entry
+ ; but that doesn't really matter
bz 1f
- POPAX AUX_USER_SP
+ ld r10, [sp, PT_sp] ; SP (pt_regs->sp)
+ sr r10, [AUX_USER_SP]
1:
- POP r12
- POP r30
-#ifdef CONFIG_ARC_HAS_ACCL_REGS
- POP r58
- POP r59
+#ifdef CONFIG_ARC_CURR_IN_REG
+ ld r25, [sp, PT_user_r25]
#endif
-#ifdef CONFIG_ARC_IRQ_NO_AUTOSAVE
-.ifnc \called_from, exception
- POP r0
- POP r1
- POP r2
- POP r3
- POP r4
- POP r5
- POP r6
- POP r7
- POP r8
- POP r9
- POP r10
- POP r11
-
- POP blink
- POPAX lp_end
- POPAX lp_start
-
- POP r9
- mov lp_count, r9
-
- add sp, sp, 12 ; skip JLI, LDI, EI
- ld.as r9, [sp, -10] ; reload r9 which got clobbered
-.endif
+#ifdef CONFIG_ARC_HAS_ACCL_REGS
+ LD2 r58, r59, PT_sp + 12
#endif
+.endm
+/*------------------------------------------------------------------------*/
+.macro __RESTORE_REGFILE_HARD
+
+ ld blink, [sp, PT_blink]
+
+ LD2 r10, r11, PT_lpe
+ sr r10, [lp_end]
+ sr r11, [lp_start]
+
+ ld r10, [sp, PT_lpc] ; lp_count can't be target of LD
+ mov lp_count, r10
+
+ LD2 r0, r1, PT_r0
+ LD2 r2, r3, PT_r2
+ LD2 r4, r5, PT_r4
+ LD2 r6, r7, PT_r6
+ LD2 r8, r9, PT_r8
+ LD2 r10, r11, PT_r10
.endm
+
/*------------------------------------------------------------------------*/
-.macro EXCEPTION_PROLOGUE
+.macro INTERRUPT_EPILOGUE
- ; Before jumping to Exception Vector, hardware micro-ops did following:
- ; 1. SP auto-switched to kernel mode stack
- ; 2. STATUS32.Z flag set to U mode at time of interrupt (U:1,K:0)
- ;
- ; Now manually save the complete reg file
-
- PUSH r9 ; freeup a register: slot of erstatus
-
- PUSHAX eret
- sub sp, sp, 12 ; skip JLI, LDI, EI
- PUSH lp_count
- PUSHAX lp_start
- PUSHAX lp_end
- PUSH blink
-
- PUSH r11
- PUSH r10
-
- ld.as r9, [sp, 10] ; load stashed r9 (status32 stack slot)
- lr r10, [erstatus]
- st.as r10, [sp, 10] ; save status32 at it's right stack slot
-
- PUSH r9
- PUSH r8
- PUSH r7
- PUSH r6
- PUSH r5
- PUSH r4
- PUSH r3
- PUSH r2
- PUSH r1
- PUSH r0
-
- ; -- for interrupts, regs above are auto-saved by h/w in that order --
- ; Now do what ISR prologue does (manually save r12, sp, fp, gp, r25)
- ;
- ; Set Z flag if this was from U mode (expected by INTERRUPT_PROLOGUE)
- ; Although H/w exception micro-ops do set Z flag for U mode (just like
- ; for interrupts), it could get clobbered in case we soft land here from
- ; a TLB Miss exception handler (tlbex.S)
+ ; INPUT: r0 has STAT32 of calling context
+ ; INPUT: Z flag set if returning to K mode
- and r10, r10, STATUS_U_MASK
- xor.f 0, r10, STATUS_U_MASK
+ ; _SOFT clobbers r10 restored by _HARD hence the order
- INTERRUPT_PROLOGUE exception
+ __RESTORE_REGFILE_SOFT
- PUSHAX erbta
- PUSHAX ecr ; r9 contains ECR, expected by EV_Trap
+#ifdef CONFIG_ARC_IRQ_NO_AUTOSAVE
+ __RESTORE_REGFILE_HARD
+ add sp, sp, SZ_PT_REGS - 8
+#else
+ add sp, sp, PT_r0
+#endif
- PUSH r0 ; orig_r0
.endm
/*------------------------------------------------------------------------*/
.macro EXCEPTION_EPILOGUE
- ; Assumes r0 has PT_status32
- btst r0, STATUS_U_BIT ; Z flag set if K, used in INTERRUPT_EPILOGUE
-
- add sp, sp, 8 ; orig_r0/ECR don't need restoring
- POPAX erbta
-
- INTERRUPT_EPILOGUE exception
+ ; INPUT: r0 has STAT32 of calling context
- POP r0
- POP r1
- POP r2
- POP r3
- POP r4
- POP r5
- POP r6
- POP r7
- POP r8
- POP r9
- POP r10
- POP r11
+ btst r0, STATUS_U_BIT ; Z flag set if K, used in restoring SP
- POP blink
- POPAX lp_end
- POPAX lp_start
+ ld r10, [sp, PT_event + 4]
+ sr r10, [erbta]
- POP r9
- mov lp_count, r9
+ LD2 r10, r11, PT_ret
+ sr r10, [eret]
+ sr r11, [erstatus]
- add sp, sp, 12 ; skip JLI, LDI, EI
- POPAX eret
- POPAX erstatus
+ __RESTORE_REGFILE_SOFT
+ __RESTORE_REGFILE_HARD
- ld.as r9, [sp, -12] ; reload r9 which got clobbered
+ add sp, sp, SZ_PT_REGS
.endm
.macro FAKE_RET_FROM_EXCPN
diff --git a/arch/arc/include/asm/entry-compact.h b/arch/arc/include/asm/entry-compact.h
index 66ba1bf21d28..66a292335ee6 100644
--- a/arch/arc/include/asm/entry-compact.h
+++ b/arch/arc/include/asm/entry-compact.h
@@ -195,8 +195,8 @@
PUSHAX CTOP_AUX_EFLAGS
#endif
- lr r9, [ecr]
- st r9, [sp, PT_event] /* EV_Trap expects r9 to have ECR */
+ lr r10, [ecr]
+ st r10, [sp, PT_event] /* EV_Trap expects r10 to have ECR */
.endm
/*--------------------------------------------------------------
diff --git a/arch/arc/include/asm/linkage.h b/arch/arc/include/asm/linkage.h
index 54f5ec5c1759..a0eeb9f8f0a9 100644
--- a/arch/arc/include/asm/linkage.h
+++ b/arch/arc/include/asm/linkage.h
@@ -10,6 +10,24 @@
#ifdef __ASSEMBLY__
+.macro ST2 e, o, off
+#ifdef CONFIG_ARC_HAS_LL64
+ std \e, [sp, \off]
+#else
+ st \e, [sp, \off]
+ st \o, [sp, \off+4]
+#endif
+.endm
+
+.macro LD2 e, o, off
+#ifdef CONFIG_ARC_HAS_LL64
+ ldd \e, [sp, \off]
+#else
+ ld \e, [sp, \off]
+ ld \o, [sp, \off+4]
+#endif
+.endm
+
#define ASM_NL ` /* use '`' to mark new line in macro */
/* annotation for data we want in DCCM - if enabled in .config */
diff --git a/arch/arc/kernel/asm-offsets.c b/arch/arc/kernel/asm-offsets.c
index dba116535005..1f621e416521 100644
--- a/arch/arc/kernel/asm-offsets.c
+++ b/arch/arc/kernel/asm-offsets.c
@@ -55,7 +55,14 @@ int main(void)
DEFINE(PT_r5, offsetof(struct pt_regs, r5));
DEFINE(PT_r6, offsetof(struct pt_regs, r6));
DEFINE(PT_r7, offsetof(struct pt_regs, r7));
+ DEFINE(PT_r8, offsetof(struct pt_regs, r8));
+ DEFINE(PT_r10, offsetof(struct pt_regs, r10));
+ DEFINE(PT_r26, offsetof(struct pt_regs, r26));
DEFINE(PT_ret, offsetof(struct pt_regs, ret));
+ DEFINE(PT_blink, offsetof(struct pt_regs, blink));
+ DEFINE(PT_lpe, offsetof(struct pt_regs, lp_end));
+ DEFINE(PT_lpc, offsetof(struct pt_regs, lp_count));
+ DEFINE(PT_user_r25, offsetof(struct pt_regs, user_r25));
DEFINE(SZ_CALLEE_REGS, sizeof(struct callee_regs));
DEFINE(SZ_PT_REGS, sizeof(struct pt_regs));
diff --git a/arch/arc/kernel/entry-arcv2.S b/arch/arc/kernel/entry-arcv2.S
index 14254b866fdc..12d5f12d10d2 100644
--- a/arch/arc/kernel/entry-arcv2.S
+++ b/arch/arc/kernel/entry-arcv2.S
@@ -67,7 +67,7 @@ reserved:
ENTRY(handle_interrupt)
- INTERRUPT_PROLOGUE irq
+ INTERRUPT_PROLOGUE
# irq control APIs local_irq_save/restore/disable/enable fiddle with
# global interrupt enable bits in STATUS32 (.IE for 1 prio, .E[] for 2 prio)
@@ -79,7 +79,7 @@ ENTRY(handle_interrupt)
#
# Note this disable is only for consistent book-keeping as further interrupts
# will be disabled anyways even w/o this. Hardware tracks active interrupts
- # seperately in AUX_IRQ_ACTIVE.active and will not take new interrupts
+ # seperately in AUX_IRQ_ACT.active and will not take new interrupts
# unless this one returns (or higher prio becomes pending in 2-prio scheme)
IRQ_DISABLE
@@ -200,17 +200,18 @@ restore_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
+ bmsk r11, r10, 15 ; extract AUX_IRQ_ACT.active
breq r11, 0, .Lexcept_ret ; No intr active, ret from Exception
;####### Return from Intr #######
+.Lisr_ret:
+
debug_marker_l1:
; bbit1.nt r0, STATUS_DE_BIT, .Lintr_ret_to_delay_slot
btst r0, STATUS_DE_BIT ; Z flag set if bit clear
bnz .Lintr_ret_to_delay_slot ; branch if STATUS_DE_BIT set
-.Lisr_ret_fast_path:
; Handle special case #1: (Entry via Exception, Return via IRQ)
;
; Exception in U mode, preempted in kernel, Intr taken (K mode), orig
@@ -223,7 +224,7 @@ debug_marker_l1:
bset.nz r11, r11, AUX_IRQ_ACT_BIT_U ; NZ means U
sr r11, [AUX_IRQ_ACT]
- INTERRUPT_EPILOGUE irq
+ INTERRUPT_EPILOGUE
rtie
;####### Return from Exception / pure kernel mode #######
@@ -244,8 +245,8 @@ debug_marker_syscall:
;
; IRQ RTIE won't reliably restore DE bit and/or BTA, needs workaround
;
-; Solution is return from Intr w/o any delay slot quirks into a kernel trampoline
-; and from pure kernel mode return to delay slot which handles DS bit/BTA correctly
+; Solution is to drop out of interrupt context into pure kernel mode
+; and return from pure kernel mode which does right things for delay slot
.Lintr_ret_to_delay_slot:
debug_marker_ds:
@@ -254,48 +255,9 @@ debug_marker_ds:
add r2, r2, 1
st r2, [@intr_to_DE_cnt]
- ld r2, [sp, PT_ret]
- ld r3, [sp, PT_status32]
-
- ; STAT32 for Int return created from scratch
- ; (No delay dlot, disable Further intr in trampoline)
-
- bic r0, r3, STATUS_U_MASK|STATUS_DE_MASK|STATUS_IE_MASK|STATUS_L_MASK
- st r0, [sp, PT_status32]
-
- mov r1, .Lintr_ret_to_delay_slot_2
- st r1, [sp, PT_ret]
-
- ; Orig exception PC/STAT32 safekept @orig_r0 and @event stack slots
- st r2, [sp, 0]
- st r3, [sp, 4]
-
- b .Lisr_ret_fast_path
-
-.Lintr_ret_to_delay_slot_2:
- ; Trampoline to restore orig exception PC/STAT32/BTA/AUX_USER_SP
- sub sp, sp, SZ_PT_REGS
- st r9, [sp, -4]
-
- ld r9, [sp, 0]
- sr r9, [eret]
-
- ld r9, [sp, 4]
- sr r9, [erstatus]
-
- ; restore AUX_USER_SP if returning to U mode
- bbit0 r9, STATUS_U_BIT, 1f
- ld r9, [sp, PT_sp]
- sr r9, [AUX_USER_SP]
-
-1:
- ld r9, [sp, 8]
- sr r9, [erbta]
-
- ld r9, [sp, -4]
- add sp, sp, SZ_PT_REGS
-
- ; return from pure kernel mode to delay slot
- rtie
+ ; drop out of interrupt context (clear AUX_IRQ_ACT.active)
+ bmskn r11, r10, 15
+ sr r11, [AUX_IRQ_ACT]
+ b .Lexcept_ret
END(ret_from_exception)
diff --git a/arch/arc/kernel/entry-compact.S b/arch/arc/kernel/entry-compact.S
index 7fe59880c16b..5cb0cd7e4eab 100644
--- a/arch/arc/kernel/entry-compact.S
+++ b/arch/arc/kernel/entry-compact.S
@@ -256,7 +256,7 @@ ENTRY(EV_TLBProtV)
EXCEPTION_PROLOGUE
- mov r2, r9 ; ECR set into r9 already
+ mov r2, r10 ; ECR set into r10 already
lr r0, [efa] ; Faulting Data address (not part of pt_regs saved above)
; Exception auto-disables further Intr/exceptions.
diff --git a/arch/arc/kernel/entry.S b/arch/arc/kernel/entry.S
index a2bfacbcfce1..72be01270e24 100644
--- a/arch/arc/kernel/entry.S
+++ b/arch/arc/kernel/entry.S
@@ -232,8 +232,8 @@ ENTRY(EV_Trap)
EXCEPTION_PROLOGUE
;============ TRAP 1 :breakpoints
- ; Check ECR for trap with arg (PROLOGUE ensures r9 has ECR)
- bmsk.f 0, r9, 7
+ ; Check ECR for trap with arg (PROLOGUE ensures r10 has ECR)
+ bmsk.f 0, r10, 7
bnz trap_with_param
;============ TRAP (no param): syscall top level
diff --git a/arch/arc/kernel/unwind.c b/arch/arc/kernel/unwind.c
index 182ce67dfe10..c2663fce7f6c 100644
--- a/arch/arc/kernel/unwind.c
+++ b/arch/arc/kernel/unwind.c
@@ -181,11 +181,6 @@ static void *__init unw_hdr_alloc_early(unsigned long sz)
return memblock_alloc_from(sz, sizeof(unsigned int), MAX_DMA_ADDRESS);
}
-static void *unw_hdr_alloc(unsigned long sz)
-{
- return kmalloc(sz, GFP_KERNEL);
-}
-
static void init_unwind_table(struct unwind_table *table, const char *name,
const void *core_start, unsigned long core_size,
const void *init_start, unsigned long init_size,
@@ -366,6 +361,10 @@ ret_err:
}
#ifdef CONFIG_MODULES
+static void *unw_hdr_alloc(unsigned long sz)
+{
+ return kmalloc(sz, GFP_KERNEL);
+}
static struct unwind_table *last_table;
diff --git a/arch/arc/mm/fault.c b/arch/arc/mm/fault.c
index 81e84426fe21..3861543b66a0 100644
--- a/arch/arc/mm/fault.c
+++ b/arch/arc/mm/fault.c
@@ -63,24 +63,19 @@ void do_page_fault(unsigned long address, struct pt_regs *regs)
struct vm_area_struct *vma = NULL;
struct task_struct *tsk = current;
struct mm_struct *mm = tsk->mm;
- int si_code = SEGV_MAPERR;
- int ret;
- vm_fault_t fault;
- int write = regs->ecr_cause & ECR_C_PROTV_STORE; /* ST/EX */
- unsigned int flags = FAULT_FLAG_ALLOW_RETRY | FAULT_FLAG_KILLABLE;
+ int sig, si_code = SEGV_MAPERR;
+ unsigned int write = 0, exec = 0, mask;
+ vm_fault_t fault = VM_FAULT_SIGSEGV; /* handle_mm_fault() output */
+ unsigned int flags; /* handle_mm_fault() input */
/*
- * We fault-in kernel-space virtual memory on-demand. The
- * 'reference' page table is init_mm.pgd.
- *
* NOTE! We MUST NOT take any locks for this case. We may
* be in an interrupt or a critical region, and should
* only copy the information from the master page table,
* nothing more.
*/
if (address >= VMALLOC_START && !user_mode(regs)) {
- ret = handle_kernel_vaddr_fault(address);
- if (unlikely(ret))
+ if (unlikely(handle_kernel_vaddr_fault(address)))
goto no_context;
else
return;
@@ -93,143 +88,117 @@ void do_page_fault(unsigned long address, struct pt_regs *regs)
if (faulthandler_disabled() || !mm)
goto no_context;
+ if (regs->ecr_cause & ECR_C_PROTV_STORE) /* ST/EX */
+ write = 1;
+ else if ((regs->ecr_vec == ECR_V_PROTV) &&
+ (regs->ecr_cause == ECR_C_PROTV_INST_FETCH))
+ exec = 1;
+
+ flags = FAULT_FLAG_ALLOW_RETRY | FAULT_FLAG_KILLABLE;
if (user_mode(regs))
flags |= FAULT_FLAG_USER;
+ if (write)
+ flags |= FAULT_FLAG_WRITE;
+
retry:
down_read(&mm->mmap_sem);
+
vma = find_vma(mm, address);
if (!vma)
goto bad_area;
- if (vma->vm_start <= address)
- goto good_area;
- if (!(vma->vm_flags & VM_GROWSDOWN))
- goto bad_area;
- if (expand_stack(vma, address))
- goto bad_area;
+ if (unlikely(address < vma->vm_start)) {
+ if (!(vma->vm_flags & VM_GROWSDOWN) || expand_stack(vma, address))
+ goto bad_area;
+ }
/*
- * Ok, we have a good vm_area for this memory access, so
- * we can handle it..
+ * vm_area is good, now check permissions for this memory access
*/
-good_area:
- si_code = SEGV_ACCERR;
-
- /* Handle protection violation, execute on heap or stack */
-
- if ((regs->ecr_vec == ECR_V_PROTV) &&
- (regs->ecr_cause == ECR_C_PROTV_INST_FETCH))
+ mask = VM_READ;
+ if (write)
+ mask = VM_WRITE;
+ if (exec)
+ mask = VM_EXEC;
+
+ if (!(vma->vm_flags & mask)) {
+ si_code = SEGV_ACCERR;
goto bad_area;
-
- if (write) {
- if (!(vma->vm_flags & VM_WRITE))
- goto bad_area;
- flags |= FAULT_FLAG_WRITE;
- } else {
- if (!(vma->vm_flags & (VM_READ | VM_EXEC)))
- goto bad_area;
}
- /*
- * If for any reason at all we couldn't handle the fault,
- * make sure we exit gracefully rather than endlessly redo
- * the fault.
- */
fault = handle_mm_fault(vma, address, flags);
- if (fatal_signal_pending(current)) {
+ /*
+ * Fault retry nuances
+ */
+ if (unlikely(fault & VM_FAULT_RETRY)) {
/*
- * if fault retry, mmap_sem already relinquished by core mm
- * so OK to return to user mode (with signal handled first)
+ * If fault needs to be retried, handle any pending signals
+ * first (by returning to user mode).
+ * mmap_sem already relinquished by core mm for RETRY case
*/
- if (fault & VM_FAULT_RETRY) {
+ if (fatal_signal_pending(current)) {
if (!user_mode(regs))
goto no_context;
return;
}
- }
-
- perf_sw_event(PERF_COUNT_SW_PAGE_FAULTS, 1, regs, address);
-
- if (likely(!(fault & VM_FAULT_ERROR))) {
+ /*
+ * retry state machine
+ */
if (flags & FAULT_FLAG_ALLOW_RETRY) {
- /* To avoid updating stats twice for retry case */
- if (fault & VM_FAULT_MAJOR) {
- tsk->maj_flt++;
- perf_sw_event(PERF_COUNT_SW_PAGE_FAULTS_MAJ, 1,
- regs, address);
- } else {
- tsk->min_flt++;
- perf_sw_event(PERF_COUNT_SW_PAGE_FAULTS_MIN, 1,
- regs, address);
- }
-
- if (fault & VM_FAULT_RETRY) {
- flags &= ~FAULT_FLAG_ALLOW_RETRY;
- flags |= FAULT_FLAG_TRIED;
- goto retry;
- }
+ flags &= ~FAULT_FLAG_ALLOW_RETRY;
+ flags |= FAULT_FLAG_TRIED;
+ goto retry;
}
-
- /* Fault Handled Gracefully */
- up_read(&mm->mmap_sem);
- return;
}
- if (fault & VM_FAULT_OOM)
- goto out_of_memory;
- else if (fault & VM_FAULT_SIGSEGV)
- goto bad_area;
- else if (fault & VM_FAULT_SIGBUS)
- goto do_sigbus;
-
- /* no man's land */
- BUG();
+bad_area:
+ up_read(&mm->mmap_sem);
/*
- * Something tried to access memory that isn't in our memory map..
- * Fix it, but check if it's kernel or user first..
+ * Major/minor page fault accounting
+ * (in case of retry we only land here once)
*/
-bad_area:
- up_read(&mm->mmap_sem);
+ perf_sw_event(PERF_COUNT_SW_PAGE_FAULTS, 1, regs, address);
- /* User mode accesses just cause a SIGSEGV */
- if (user_mode(regs)) {
- tsk->thread.fault_address = address;
- force_sig_fault(SIGSEGV, si_code, (void __user *)address);
- return;
- }
+ if (likely(!(fault & VM_FAULT_ERROR))) {
+ if (fault & VM_FAULT_MAJOR) {
+ tsk->maj_flt++;
+ perf_sw_event(PERF_COUNT_SW_PAGE_FAULTS_MAJ, 1,
+ regs, address);
+ } else {
+ tsk->min_flt++;
+ perf_sw_event(PERF_COUNT_SW_PAGE_FAULTS_MIN, 1,
+ regs, address);
+ }
-no_context:
- /* Are we prepared to handle this kernel fault?
- *
- * (The kernel has valid exception-points in the source
- * when it accesses user-memory. When it fails in one
- * of those points, we find it in a table and do a jump
- * to some fixup code that loads an appropriate error
- * code)
- */
- if (fixup_exception(regs))
+ /* Normal return path: fault Handled Gracefully */
return;
+ }
- die("Oops", regs, address);
-
-out_of_memory:
- up_read(&mm->mmap_sem);
+ if (!user_mode(regs))
+ goto no_context;
- if (user_mode(regs)) {
+ if (fault & VM_FAULT_OOM) {
pagefault_out_of_memory();
return;
}
- goto no_context;
+ if (fault & VM_FAULT_SIGBUS) {
+ sig = SIGBUS;
+ si_code = BUS_ADRERR;
+ }
+ else {
+ sig = SIGSEGV;
+ }
-do_sigbus:
- up_read(&mm->mmap_sem);
+ tsk->thread.fault_address = address;
+ force_sig_fault(sig, si_code, (void __user *)address);
+ return;
- if (!user_mode(regs))
- goto no_context;
+no_context:
+ if (fixup_exception(regs))
+ return;
- tsk->thread.fault_address = address;
- force_sig_fault(SIGBUS, BUS_ADRERR, (void __user *)address);
+ die("Oops", regs, address);
}
diff --git a/arch/arc/mm/tlbex.S b/arch/arc/mm/tlbex.S
index 471a97bf492d..c55d95dd2f39 100644
--- a/arch/arc/mm/tlbex.S
+++ b/arch/arc/mm/tlbex.S
@@ -393,6 +393,17 @@ EV_TLBMissD_fast_ret: ; additional label for VDK OS-kit instrumentation
;-------- Common routine to call Linux Page Fault Handler -----------
do_slow_path_pf:
+#ifdef CONFIG_ISA_ARCV2
+ ; Set Z flag if exception in U mode. Hardware micro-ops do this on any
+ ; taken interrupt/exception, and thus is already the case at the entry
+ ; above, but ensuing code would have already clobbered.
+ ; EXCEPTION_PROLOGUE called in slow path, relies on correct Z flag set
+
+ lr r2, [erstatus]
+ and r2, r2, STATUS_U_MASK
+ bxor.f 0, r2, STATUS_U_BIT
+#endif
+
; Restore the 4-scratch regs saved by fast path miss handler
TLBMISS_RESTORE_REGS