diff --git a/arch/arm/Kconfig.debug b/arch/arm/Kconfig.debug
index 259c0ca..95b85ee 100644
--- a/arch/arm/Kconfig.debug
+++ b/arch/arm/Kconfig.debug
@@ -39,9 +39,17 @@ config FRAME_POINTER
 	default y if !ARM_UNWIND || FUNCTION_GRAPH_TRACER
 	help
 	  If you say N here, the resulting kernel will be slightly smaller and
-	  faster. However, if neither FRAME_POINTER nor ARM_UNWIND are enabled,
-	  when a problem occurs with the kernel, the information that is
-	  reported is severely limited.
+	  faster. When ARM_UNWIND is disabled, enabling FRAME_POINTER alone is
+	  not sufficient to get meaningful information in case of a kernel bug;
+	  you will also need DEPRECATED_APCS_FRAME.
+
+config DEPRECATED_APCS_FRAME
+	bool "Enable deprecated frame format"
+	depends on FRAME_POINTER
+	default n
+	help
+	  Use the legacy APCS frame format. This is required for ftrace with
+	  GCC < 4.4, as well as stack traces without ARM_UNWIND.
 
 config ARM_UNWIND
 	bool "Enable stack unwinding support (EXPERIMENTAL)"
@@ -56,7 +64,7 @@ config ARM_UNWIND
 
 config OLD_MCOUNT
 	bool
-	depends on FUNCTION_TRACER && FRAME_POINTER
+	depends on FUNCTION_TRACER && DEPRECATED_APCS_FRAME
 	default y
 
 config DEBUG_USER
diff --git a/arch/arm/Makefile b/arch/arm/Makefile
index 2c2b28e..66a3adc 100644
--- a/arch/arm/Makefile
+++ b/arch/arm/Makefile
@@ -41,7 +41,11 @@ KBUILD_CFLAGS	+= $(call cc-option,-mno-unaligned-access)
 endif
 
 ifeq ($(CONFIG_FRAME_POINTER),y)
-KBUILD_CFLAGS	+=-fno-omit-frame-pointer -mapcs -mno-sched-prolog
+KBUILD_CFLAGS	+=-fno-omit-frame-pointer -mno-sched-prolog
+endif
+
+ifeq ($(CONFIG_DEPRECATED_APCS_FRAME),y)
+KBUILD_CFLAGS	+=-mapcs
 endif
 
 ifeq ($(CONFIG_CPU_BIG_ENDIAN),y)
diff --git a/arch/arm/include/asm/ftrace.h b/arch/arm/include/asm/ftrace.h
index bfe2a2f..a1ad19e 100644
--- a/arch/arm/include/asm/ftrace.h
+++ b/arch/arm/include/asm/ftrace.h
@@ -32,12 +32,12 @@ extern void ftrace_call_old(void);
 
 #ifndef __ASSEMBLY__
 
-#if defined(CONFIG_FRAME_POINTER) && !defined(CONFIG_ARM_UNWIND)
+#if defined(CONFIG_DEPRECATED_APCS_FRAME) && !defined(CONFIG_ARM_UNWIND)
 /*
  * return_address uses walk_stackframe to do it's work.  If both
- * CONFIG_FRAME_POINTER=y and CONFIG_ARM_UNWIND=y walk_stackframe uses unwind
- * information.  For this to work in the function tracer many functions would
- * have to be marked with __notrace.  So for now just depend on
+ * CONFIG_DEPRECATED_APCS_FRAME=y and CONFIG_ARM_UNWIND=y walk_stackframe uses
+ * unwind information.  For this to work in the function tracer many functions
+ * would have to be marked with __notrace.  So for now just depend on
  * !CONFIG_ARM_UNWIND.
  */
 
diff --git a/arch/arm/kernel/entry-ftrace.S b/arch/arm/kernel/entry-ftrace.S
index c73c403..b9984b5 100644
--- a/arch/arm/kernel/entry-ftrace.S
+++ b/arch/arm/kernel/entry-ftrace.S
@@ -53,7 +53,7 @@
 
 #ifndef CONFIG_OLD_MCOUNT
 #if (__GNUC__ < 4 || (__GNUC__ == 4 && __GNUC_MINOR__ < 4))
-#error Ftrace requires CONFIG_FRAME_POINTER=y with GCC older than 4.4.0.
+#error Ftrace requires CONFIG_DEPRECATED_APCS_FRAME=y with GCC older than 4.4.0.
 #endif
 #endif
 
diff --git a/arch/arm/kernel/return_address.c b/arch/arm/kernel/return_address.c
index 36ed350..3728026 100644
--- a/arch/arm/kernel/return_address.c
+++ b/arch/arm/kernel/return_address.c
@@ -11,7 +11,7 @@
 #include <linux/export.h>
 #include <linux/ftrace.h>
 
-#if defined(CONFIG_FRAME_POINTER) && !defined(CONFIG_ARM_UNWIND)
+#if defined(CONFIG_DEPRECATED_APCS_FRAME) && !defined(CONFIG_ARM_UNWIND)
 #include <linux/sched.h>
 
 #include <asm/stacktrace.h>
@@ -56,6 +56,6 @@ void *return_address(unsigned int level)
 		return NULL;
 }
 
-#endif /* if defined(CONFIG_FRAME_POINTER) && !defined(CONFIG_ARM_UNWIND) */
+#endif /* if defined(CONFIG_DEPRECATED_APCS_FRAME) && !defined(CONFIG_ARM_UNWIND) */
 
 EXPORT_SYMBOL_GPL(return_address);
diff --git a/arch/arm/kernel/stacktrace.c b/arch/arm/kernel/stacktrace.c
index 92b7237..20e9a7f 100644
--- a/arch/arm/kernel/stacktrace.c
+++ b/arch/arm/kernel/stacktrace.c
@@ -5,13 +5,14 @@
 #include <asm/stacktrace.h>
 #include <asm/traps.h>
 
-#if defined(CONFIG_FRAME_POINTER) && !defined(CONFIG_ARM_UNWIND)
+#ifndef CONFIG_ARM_UNWIND
+#ifdef CONFIG_DEPRECATED_APCS_FRAME
 /*
  * Unwind the current stack frame and store the new register values in the
  * structure passed as argument. Unwinding is equivalent to a function return,
  * hence the new PC value rather than LR should be used for backtrace.
  *
- * With framepointer enabled, a simple function prologue looks like this:
+ * With APCS frames enabled, a simple function prologue looks like this:
  *	mov	ip, sp
  *	stmdb	sp!, {fp, ip, lr, pc}
  *	sub	fp, ip, #4
@@ -19,7 +20,7 @@
  * A simple function epilogue looks like this:
  *	ldm	sp, {fp, sp, pc}
  *
- * Note that with framepointer enabled, even the leaf functions have the same
+ * Note that with APCS frames enabled, even the leaf functions have the same
  * prologue and epilogue, therefore we can ignore the LR value in this case.
  */
 int notrace unwind_frame(struct stackframe *frame)
@@ -42,7 +43,13 @@ int notrace unwind_frame(struct stackframe *frame)
 
 	return 0;
 }
+#else /* !defined(CONFIG_DEPRECATED_APCS_FRAME) */
+int notrace unwind_frame(struct stackframe *frame)
+{
+	return -EINVAL;
+}
 #endif
+#endif /* !defined(CONFIG_ARM_UNWIND) */
 
 void notrace walk_stackframe(struct stackframe *frame,
 		     int (*fn)(struct stackframe *, void *), void *data)
diff --git a/arch/arm/lib/backtrace.S b/arch/arm/lib/backtrace.S
index fab5a50..3041ccb 100644
--- a/arch/arm/lib/backtrace.S
+++ b/arch/arm/lib/backtrace.S
@@ -24,7 +24,7 @@
 
 ENTRY(c_backtrace)
 
-#if !defined(CONFIG_FRAME_POINTER) || !defined(CONFIG_PRINTK)
+#if !defined(CONFIG_DEPRECATED_APCS_FRAME) || !defined(CONFIG_PRINTK)
 		ret	lr
 ENDPROC(c_backtrace)
 #else
diff --git a/arch/arm/net/bpf_jit_32.c b/arch/arm/net/bpf_jit_32.c
index 93d0b6d..8f7b718 100644
--- a/arch/arm/net/bpf_jit_32.c
+++ b/arch/arm/net/bpf_jit_32.c
@@ -165,7 +165,7 @@ static u16 saved_regs(struct jit_ctx *ctx)
 	    (ctx->skf->insns[0].code == (BPF_RET | BPF_A)))
 		ret |= 1 << r_A;
 
-#ifdef CONFIG_FRAME_POINTER
+#ifdef CONFIG_DEPRECATED_APCS_FRAME
 	ret |= (1 << ARM_FP) | (1 << ARM_IP) | (1 << ARM_LR) | (1 << ARM_PC);
 #else
 	if (ctx->seen & SEEN_CALL)
@@ -200,7 +200,7 @@ static void build_prologue(struct jit_ctx *ctx)
 	u16 reg_set = saved_regs(ctx);
 	u16 off;
 
-#ifdef CONFIG_FRAME_POINTER
+#ifdef CONFIG_DEPRECATED_APCS_FRAME
 	emit(ARM_MOV_R(ARM_IP, ARM_SP), ctx);
 	emit(ARM_PUSH(reg_set), ctx);
 	emit(ARM_SUB_I(ARM_FP, ARM_IP, 4), ctx);
@@ -244,7 +244,7 @@ static void build_epilogue(struct jit_ctx *ctx)
 
 	reg_set &= ~(1 << ARM_LR);
 
-#ifdef CONFIG_FRAME_POINTER
+#ifdef CONFIG_DEPRECATED_APCS_FRAME
 	/* the first instruction of the prologue was: mov ip, sp */
 	reg_set &= ~(1 << ARM_IP);
 	reg_set |= (1 << ARM_SP);
