aboutsummaryrefslogtreecommitdiffstats
path: root/arch/tile
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2015-04-17 16:03:05 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2015-04-17 16:03:05 -0400
commit6b6e177d632ee251c7c78d8f266a851ab9704879 (patch)
tree6feec072e7dd7eb32249369a1a80e6a904307e34 /arch/tile
parentbfaf245022b4b8661af2e35f467cf0e91943c24c (diff)
parent128f3cb9398b5eeb4ee04b60bd5e314f5c122821 (diff)
Merge git://git.kernel.org/pub/scm/linux/kernel/git/cmetcalf/linux-tile
Pull arch/tile updates from Chris Metcalf: "These are mostly nohz_full changes, plus a smattering of minor fixes (notably a couple for ftrace)" * git://git.kernel.org/pub/scm/linux/kernel/git/cmetcalf/linux-tile: tile: nohz: warn if nohz_full uses hypervisor shared cores tile: ftrace: fix function_graph tracer issues tile: map data region shadow of kernel as R/W tile: support CONTEXT_TRACKING and thus NOHZ_FULL tile: support arch_irq_work_raise arch: tile: fix null pointer dereference on pt_regs pointer tile/elf: reorganize notify_exec() tile: use si_int instead of si_ptr for compat_siginfo
Diffstat (limited to 'arch/tile')
-rw-r--r--arch/tile/Kconfig1
-rw-r--r--arch/tile/include/asm/Kbuild1
-rw-r--r--arch/tile/include/asm/ftrace.h2
-rw-r--r--arch/tile/include/asm/irq_work.h14
-rw-r--r--arch/tile/include/asm/smp.h1
-rw-r--r--arch/tile/include/asm/thread_info.h9
-rw-r--r--arch/tile/include/hv/hypervisor.h6
-rw-r--r--arch/tile/kernel/compat_signal.c11
-rw-r--r--arch/tile/kernel/ftrace.c6
-rw-r--r--arch/tile/kernel/mcount_64.S7
-rw-r--r--arch/tile/kernel/process.c12
-rw-r--r--arch/tile/kernel/ptrace.c22
-rw-r--r--arch/tile/kernel/setup.c23
-rw-r--r--arch/tile/kernel/single_step.c3
-rw-r--r--arch/tile/kernel/smp.c32
-rw-r--r--arch/tile/kernel/stack.c15
-rw-r--r--arch/tile/kernel/traps.c16
-rw-r--r--arch/tile/kernel/unaligned.c22
-rw-r--r--arch/tile/mm/elf.c47
-rw-r--r--arch/tile/mm/fault.c10
-rw-r--r--arch/tile/mm/init.c7
21 files changed, 201 insertions, 66 deletions
diff --git a/arch/tile/Kconfig b/arch/tile/Kconfig
index 0142d578b5a8..a07e31b50d3f 100644
--- a/arch/tile/Kconfig
+++ b/arch/tile/Kconfig
@@ -27,6 +27,7 @@ config TILE
27 select ARCH_HAS_ATOMIC64_DEC_IF_POSITIVE 27 select ARCH_HAS_ATOMIC64_DEC_IF_POSITIVE
28 select HAVE_DEBUG_STACKOVERFLOW 28 select HAVE_DEBUG_STACKOVERFLOW
29 select ARCH_WANT_FRAME_POINTERS 29 select ARCH_WANT_FRAME_POINTERS
30 select HAVE_CONTEXT_TRACKING
30 31
31# FIXME: investigate whether we need/want these options. 32# FIXME: investigate whether we need/want these options.
32# select HAVE_IOREMAP_PROT 33# select HAVE_IOREMAP_PROT
diff --git a/arch/tile/include/asm/Kbuild b/arch/tile/include/asm/Kbuild
index b4c488b65745..f5433e0e34e0 100644
--- a/arch/tile/include/asm/Kbuild
+++ b/arch/tile/include/asm/Kbuild
@@ -16,7 +16,6 @@ generic-y += ioctl.h
16generic-y += ioctls.h 16generic-y += ioctls.h
17generic-y += ipcbuf.h 17generic-y += ipcbuf.h
18generic-y += irq_regs.h 18generic-y += irq_regs.h
19generic-y += irq_work.h
20generic-y += local.h 19generic-y += local.h
21generic-y += local64.h 20generic-y += local64.h
22generic-y += mcs_spinlock.h 21generic-y += mcs_spinlock.h
diff --git a/arch/tile/include/asm/ftrace.h b/arch/tile/include/asm/ftrace.h
index 13a9bb81a8ab..738d239b792f 100644
--- a/arch/tile/include/asm/ftrace.h
+++ b/arch/tile/include/asm/ftrace.h
@@ -23,6 +23,8 @@
23#ifndef __ASSEMBLY__ 23#ifndef __ASSEMBLY__
24extern void __mcount(void); 24extern void __mcount(void);
25 25
26#define ARCH_SUPPORTS_FTRACE_OPS 1
27
26#ifdef CONFIG_DYNAMIC_FTRACE 28#ifdef CONFIG_DYNAMIC_FTRACE
27static inline unsigned long ftrace_call_adjust(unsigned long addr) 29static inline unsigned long ftrace_call_adjust(unsigned long addr)
28{ 30{
diff --git a/arch/tile/include/asm/irq_work.h b/arch/tile/include/asm/irq_work.h
new file mode 100644
index 000000000000..48af33a61a2c
--- /dev/null
+++ b/arch/tile/include/asm/irq_work.h
@@ -0,0 +1,14 @@
1#ifndef __ASM_IRQ_WORK_H
2#define __ASM_IRQ_WORK_H
3
4static inline bool arch_irq_work_has_interrupt(void)
5{
6#ifdef CONFIG_SMP
7 extern bool self_interrupt_ok;
8 return self_interrupt_ok;
9#else
10 return false;
11#endif
12}
13
14#endif /* __ASM_IRQ_WORK_H */
diff --git a/arch/tile/include/asm/smp.h b/arch/tile/include/asm/smp.h
index 9a326b64f7ae..735e7f144733 100644
--- a/arch/tile/include/asm/smp.h
+++ b/arch/tile/include/asm/smp.h
@@ -69,6 +69,7 @@ static inline int xy_to_cpu(int x, int y)
69#define MSG_TAG_STOP_CPU 2 69#define MSG_TAG_STOP_CPU 2
70#define MSG_TAG_CALL_FUNCTION_MANY 3 70#define MSG_TAG_CALL_FUNCTION_MANY 3
71#define MSG_TAG_CALL_FUNCTION_SINGLE 4 71#define MSG_TAG_CALL_FUNCTION_SINGLE 4
72#define MSG_TAG_IRQ_WORK 5
72 73
73/* Hook for the generic smp_call_function_many() routine. */ 74/* Hook for the generic smp_call_function_many() routine. */
74static inline void arch_send_call_function_ipi_mask(struct cpumask *mask) 75static inline void arch_send_call_function_ipi_mask(struct cpumask *mask)
diff --git a/arch/tile/include/asm/thread_info.h b/arch/tile/include/asm/thread_info.h
index 98ee10a0ae89..f804c39a5e4d 100644
--- a/arch/tile/include/asm/thread_info.h
+++ b/arch/tile/include/asm/thread_info.h
@@ -124,6 +124,7 @@ extern void _cpu_idle(void);
124#define TIF_NOTIFY_RESUME 8 /* callback before returning to user */ 124#define TIF_NOTIFY_RESUME 8 /* callback before returning to user */
125#define TIF_SYSCALL_TRACEPOINT 9 /* syscall tracepoint instrumentation */ 125#define TIF_SYSCALL_TRACEPOINT 9 /* syscall tracepoint instrumentation */
126#define TIF_POLLING_NRFLAG 10 /* idle is polling for TIF_NEED_RESCHED */ 126#define TIF_POLLING_NRFLAG 10 /* idle is polling for TIF_NEED_RESCHED */
127#define TIF_NOHZ 11 /* in adaptive nohz mode */
127 128
128#define _TIF_SIGPENDING (1<<TIF_SIGPENDING) 129#define _TIF_SIGPENDING (1<<TIF_SIGPENDING)
129#define _TIF_NEED_RESCHED (1<<TIF_NEED_RESCHED) 130#define _TIF_NEED_RESCHED (1<<TIF_NEED_RESCHED)
@@ -136,14 +137,16 @@ extern void _cpu_idle(void);
136#define _TIF_NOTIFY_RESUME (1<<TIF_NOTIFY_RESUME) 137#define _TIF_NOTIFY_RESUME (1<<TIF_NOTIFY_RESUME)
137#define _TIF_SYSCALL_TRACEPOINT (1<<TIF_SYSCALL_TRACEPOINT) 138#define _TIF_SYSCALL_TRACEPOINT (1<<TIF_SYSCALL_TRACEPOINT)
138#define _TIF_POLLING_NRFLAG (1<<TIF_POLLING_NRFLAG) 139#define _TIF_POLLING_NRFLAG (1<<TIF_POLLING_NRFLAG)
140#define _TIF_NOHZ (1<<TIF_NOHZ)
139 141
140/* Work to do on any return to user space. */ 142/* Work to do on any return to user space. */
141#define _TIF_ALLWORK_MASK \ 143#define _TIF_ALLWORK_MASK \
142 (_TIF_SIGPENDING|_TIF_NEED_RESCHED|_TIF_SINGLESTEP|\ 144 (_TIF_SIGPENDING | _TIF_NEED_RESCHED | _TIF_SINGLESTEP | \
143 _TIF_ASYNC_TLB|_TIF_NOTIFY_RESUME) 145 _TIF_ASYNC_TLB | _TIF_NOTIFY_RESUME | _TIF_NOHZ)
144 146
145/* Work to do at syscall entry. */ 147/* Work to do at syscall entry. */
146#define _TIF_SYSCALL_ENTRY_WORK (_TIF_SYSCALL_TRACE | _TIF_SYSCALL_TRACEPOINT) 148#define _TIF_SYSCALL_ENTRY_WORK \
149 (_TIF_SYSCALL_TRACE | _TIF_SYSCALL_TRACEPOINT | _TIF_NOHZ)
147 150
148/* Work to do at syscall exit. */ 151/* Work to do at syscall exit. */
149#define _TIF_SYSCALL_EXIT_WORK (_TIF_SYSCALL_TRACE | _TIF_SYSCALL_TRACEPOINT) 152#define _TIF_SYSCALL_EXIT_WORK (_TIF_SYSCALL_TRACE | _TIF_SYSCALL_TRACEPOINT)
diff --git a/arch/tile/include/hv/hypervisor.h b/arch/tile/include/hv/hypervisor.h
index dfcdeb61ba34..e0e6af4e783b 100644
--- a/arch/tile/include/hv/hypervisor.h
+++ b/arch/tile/include/hv/hypervisor.h
@@ -961,7 +961,11 @@ typedef enum {
961 HV_INQ_TILES_HFH_CACHE = 2, 961 HV_INQ_TILES_HFH_CACHE = 2,
962 962
963 /** The set of tiles that can be legally used as a LOTAR for a PTE. */ 963 /** The set of tiles that can be legally used as a LOTAR for a PTE. */
964 HV_INQ_TILES_LOTAR = 3 964 HV_INQ_TILES_LOTAR = 3,
965
966 /** The set of "shared" driver tiles that the hypervisor may
967 * periodically interrupt. */
968 HV_INQ_TILES_SHARED = 4
965} HV_InqTileSet; 969} HV_InqTileSet;
966 970
967/** Returns specific information about various sets of tiles within the 971/** Returns specific information about various sets of tiles within the
diff --git a/arch/tile/kernel/compat_signal.c b/arch/tile/kernel/compat_signal.c
index 5cbc864398d3..e8c2c04143cd 100644
--- a/arch/tile/kernel/compat_signal.c
+++ b/arch/tile/kernel/compat_signal.c
@@ -68,7 +68,7 @@ int copy_siginfo_to_user32(struct compat_siginfo __user *to, const siginfo_t *fr
68 if (from->si_code < 0) { 68 if (from->si_code < 0) {
69 err |= __put_user(from->si_pid, &to->si_pid); 69 err |= __put_user(from->si_pid, &to->si_pid);
70 err |= __put_user(from->si_uid, &to->si_uid); 70 err |= __put_user(from->si_uid, &to->si_uid);
71 err |= __put_user(ptr_to_compat(from->si_ptr), &to->si_ptr); 71 err |= __put_user(from->si_int, &to->si_int);
72 } else { 72 } else {
73 /* 73 /*
74 * First 32bits of unions are always present: 74 * First 32bits of unions are always present:
@@ -93,8 +93,7 @@ int copy_siginfo_to_user32(struct compat_siginfo __user *to, const siginfo_t *fr
93 break; 93 break;
94 case __SI_TIMER >> 16: 94 case __SI_TIMER >> 16:
95 err |= __put_user(from->si_overrun, &to->si_overrun); 95 err |= __put_user(from->si_overrun, &to->si_overrun);
96 err |= __put_user(ptr_to_compat(from->si_ptr), 96 err |= __put_user(from->si_int, &to->si_int);
97 &to->si_ptr);
98 break; 97 break;
99 /* This is not generated by the kernel as of now. */ 98 /* This is not generated by the kernel as of now. */
100 case __SI_RT >> 16: 99 case __SI_RT >> 16:
@@ -110,19 +109,19 @@ int copy_siginfo_to_user32(struct compat_siginfo __user *to, const siginfo_t *fr
110int copy_siginfo_from_user32(siginfo_t *to, struct compat_siginfo __user *from) 109int copy_siginfo_from_user32(siginfo_t *to, struct compat_siginfo __user *from)
111{ 110{
112 int err; 111 int err;
113 u32 ptr32;
114 112
115 if (!access_ok(VERIFY_READ, from, sizeof(struct compat_siginfo))) 113 if (!access_ok(VERIFY_READ, from, sizeof(struct compat_siginfo)))
116 return -EFAULT; 114 return -EFAULT;
117 115
116 memset(to, 0, sizeof(*to));
117
118 err = __get_user(to->si_signo, &from->si_signo); 118 err = __get_user(to->si_signo, &from->si_signo);
119 err |= __get_user(to->si_errno, &from->si_errno); 119 err |= __get_user(to->si_errno, &from->si_errno);
120 err |= __get_user(to->si_code, &from->si_code); 120 err |= __get_user(to->si_code, &from->si_code);
121 121
122 err |= __get_user(to->si_pid, &from->si_pid); 122 err |= __get_user(to->si_pid, &from->si_pid);
123 err |= __get_user(to->si_uid, &from->si_uid); 123 err |= __get_user(to->si_uid, &from->si_uid);
124 err |= __get_user(ptr32, &from->si_ptr); 124 err |= __get_user(to->si_int, &from->si_int);
125 to->si_ptr = compat_ptr(ptr32);
126 125
127 return err; 126 return err;
128} 127}
diff --git a/arch/tile/kernel/ftrace.c b/arch/tile/kernel/ftrace.c
index 8d52d83cc516..0c0996175b1e 100644
--- a/arch/tile/kernel/ftrace.c
+++ b/arch/tile/kernel/ftrace.c
@@ -74,7 +74,11 @@ static unsigned long ftrace_gen_branch(unsigned long pc, unsigned long addr,
74 create_JumpOff_X1(pcrel_by_instr); 74 create_JumpOff_X1(pcrel_by_instr);
75 } 75 }
76 76
77 if (addr == FTRACE_ADDR) { 77 /*
78 * Also put { move r10, lr; jal ftrace_stub } in a bundle, which
79 * is used to replace the instruction in address ftrace_call.
80 */
81 if (addr == FTRACE_ADDR || addr == (unsigned long)ftrace_stub) {
78 /* opcode: or r10, lr, zero */ 82 /* opcode: or r10, lr, zero */
79 opcode_x0 = 83 opcode_x0 =
80 create_Dest_X0(10) | 84 create_Dest_X0(10) |
diff --git a/arch/tile/kernel/mcount_64.S b/arch/tile/kernel/mcount_64.S
index 3c2b8d5e1d1a..6c6702451962 100644
--- a/arch/tile/kernel/mcount_64.S
+++ b/arch/tile/kernel/mcount_64.S
@@ -81,7 +81,12 @@ STD_ENTRY(ftrace_caller)
81 81
82 /* arg1: self return address */ 82 /* arg1: self return address */
83 /* arg2: parent's return address */ 83 /* arg2: parent's return address */
84 { move r0, lr; move r1, r10 } 84 /* arg3: ftrace_ops */
85 /* arg4: regs (but make it NULL) */
86 { move r0, lr; moveli r2, hw2_last(function_trace_op) }
87 { move r1, r10; shl16insli r2, r2, hw1(function_trace_op) }
88 { movei r3, 0; shl16insli r2, r2, hw0(function_trace_op) }
89 ld r2,r2
85 90
86 .global ftrace_call 91 .global ftrace_call
87ftrace_call: 92ftrace_call:
diff --git a/arch/tile/kernel/process.c b/arch/tile/kernel/process.c
index 48e5773dd0b7..b403c2e3e263 100644
--- a/arch/tile/kernel/process.c
+++ b/arch/tile/kernel/process.c
@@ -27,6 +27,7 @@
27#include <linux/kernel.h> 27#include <linux/kernel.h>
28#include <linux/tracehook.h> 28#include <linux/tracehook.h>
29#include <linux/signal.h> 29#include <linux/signal.h>
30#include <linux/context_tracking.h>
30#include <asm/stack.h> 31#include <asm/stack.h>
31#include <asm/switch_to.h> 32#include <asm/switch_to.h>
32#include <asm/homecache.h> 33#include <asm/homecache.h>
@@ -474,6 +475,8 @@ int do_work_pending(struct pt_regs *regs, u32 thread_info_flags)
474 if (!user_mode(regs)) 475 if (!user_mode(regs))
475 return 0; 476 return 0;
476 477
478 user_exit();
479
477 /* Enable interrupts; they are disabled again on return to caller. */ 480 /* Enable interrupts; they are disabled again on return to caller. */
478 local_irq_enable(); 481 local_irq_enable();
479 482
@@ -496,11 +499,12 @@ int do_work_pending(struct pt_regs *regs, u32 thread_info_flags)
496 tracehook_notify_resume(regs); 499 tracehook_notify_resume(regs);
497 return 1; 500 return 1;
498 } 501 }
499 if (thread_info_flags & _TIF_SINGLESTEP) { 502 if (thread_info_flags & _TIF_SINGLESTEP)
500 single_step_once(regs); 503 single_step_once(regs);
501 return 0; 504
502 } 505 user_enter();
503 panic("work_pending: bad flags %#x\n", thread_info_flags); 506
507 return 0;
504} 508}
505 509
506unsigned long get_wchan(struct task_struct *p) 510unsigned long get_wchan(struct task_struct *p)
diff --git a/arch/tile/kernel/ptrace.c b/arch/tile/kernel/ptrace.c
index de98c6ddf136..f84eed8243da 100644
--- a/arch/tile/kernel/ptrace.c
+++ b/arch/tile/kernel/ptrace.c
@@ -22,6 +22,7 @@
22#include <linux/regset.h> 22#include <linux/regset.h>
23#include <linux/elf.h> 23#include <linux/elf.h>
24#include <linux/tracehook.h> 24#include <linux/tracehook.h>
25#include <linux/context_tracking.h>
25#include <asm/traps.h> 26#include <asm/traps.h>
26#include <arch/chip.h> 27#include <arch/chip.h>
27 28
@@ -252,12 +253,21 @@ long compat_arch_ptrace(struct task_struct *child, compat_long_t request,
252 253
253int do_syscall_trace_enter(struct pt_regs *regs) 254int do_syscall_trace_enter(struct pt_regs *regs)
254{ 255{
255 if (test_thread_flag(TIF_SYSCALL_TRACE)) { 256 u32 work = ACCESS_ONCE(current_thread_info()->flags);
257
258 /*
259 * If TIF_NOHZ is set, we are required to call user_exit() before
260 * doing anything that could touch RCU.
261 */
262 if (work & _TIF_NOHZ)
263 user_exit();
264
265 if (work & _TIF_SYSCALL_TRACE) {
256 if (tracehook_report_syscall_entry(regs)) 266 if (tracehook_report_syscall_entry(regs))
257 regs->regs[TREG_SYSCALL_NR] = -1; 267 regs->regs[TREG_SYSCALL_NR] = -1;
258 } 268 }
259 269
260 if (test_thread_flag(TIF_SYSCALL_TRACEPOINT)) 270 if (work & _TIF_SYSCALL_TRACEPOINT)
261 trace_sys_enter(regs, regs->regs[TREG_SYSCALL_NR]); 271 trace_sys_enter(regs, regs->regs[TREG_SYSCALL_NR]);
262 272
263 return regs->regs[TREG_SYSCALL_NR]; 273 return regs->regs[TREG_SYSCALL_NR];
@@ -268,6 +278,12 @@ void do_syscall_trace_exit(struct pt_regs *regs)
268 long errno; 278 long errno;
269 279
270 /* 280 /*
281 * We may come here right after calling schedule_user()
282 * in which case we can be in RCU user mode.
283 */
284 user_exit();
285
286 /*
271 * The standard tile calling convention returns the value (or negative 287 * The standard tile calling convention returns the value (or negative
272 * errno) in r0, and zero (or positive errno) in r1. 288 * errno) in r0, and zero (or positive errno) in r1.
273 * It saves a couple of cycles on the hot path to do this work in 289 * It saves a couple of cycles on the hot path to do this work in
@@ -303,5 +319,7 @@ void send_sigtrap(struct task_struct *tsk, struct pt_regs *regs)
303/* Handle synthetic interrupt delivered only by the simulator. */ 319/* Handle synthetic interrupt delivered only by the simulator. */
304void __kprobes do_breakpoint(struct pt_regs* regs, int fault_num) 320void __kprobes do_breakpoint(struct pt_regs* regs, int fault_num)
305{ 321{
322 enum ctx_state prev_state = exception_enter();
306 send_sigtrap(current, regs); 323 send_sigtrap(current, regs);
324 exception_exit(prev_state);
307} 325}
diff --git a/arch/tile/kernel/setup.c b/arch/tile/kernel/setup.c
index f1f579914952..7833b2ccdfbc 100644
--- a/arch/tile/kernel/setup.c
+++ b/arch/tile/kernel/setup.c
@@ -32,6 +32,7 @@
32#include <linux/hugetlb.h> 32#include <linux/hugetlb.h>
33#include <linux/start_kernel.h> 33#include <linux/start_kernel.h>
34#include <linux/screen_info.h> 34#include <linux/screen_info.h>
35#include <linux/tick.h>
35#include <asm/setup.h> 36#include <asm/setup.h>
36#include <asm/sections.h> 37#include <asm/sections.h>
37#include <asm/cacheflush.h> 38#include <asm/cacheflush.h>
@@ -1390,6 +1391,28 @@ static int __init dataplane(char *str)
1390 1391
1391early_param("dataplane", dataplane); 1392early_param("dataplane", dataplane);
1392 1393
1394#ifdef CONFIG_NO_HZ_FULL
1395/* Warn if hypervisor shared cpus are marked as nohz_full. */
1396static int __init check_nohz_full_cpus(void)
1397{
1398 struct cpumask shared;
1399 int cpu;
1400
1401 if (hv_inquire_tiles(HV_INQ_TILES_SHARED,
1402 (HV_VirtAddr) shared.bits, sizeof(shared)) < 0) {
1403 pr_warn("WARNING: No support for inquiring hv shared tiles\n");
1404 return 0;
1405 }
1406 for_each_cpu(cpu, &shared) {
1407 if (tick_nohz_full_cpu(cpu))
1408 pr_warn("WARNING: nohz_full cpu %d receives hypervisor interrupts!\n",
1409 cpu);
1410 }
1411 return 0;
1412}
1413arch_initcall(check_nohz_full_cpus);
1414#endif
1415
1393#ifdef CONFIG_CMDLINE_BOOL 1416#ifdef CONFIG_CMDLINE_BOOL
1394static char __initdata builtin_cmdline[COMMAND_LINE_SIZE] = CONFIG_CMDLINE; 1417static char __initdata builtin_cmdline[COMMAND_LINE_SIZE] = CONFIG_CMDLINE;
1395#endif 1418#endif
diff --git a/arch/tile/kernel/single_step.c b/arch/tile/kernel/single_step.c
index 862973074bf9..53f7b9def07b 100644
--- a/arch/tile/kernel/single_step.c
+++ b/arch/tile/kernel/single_step.c
@@ -23,6 +23,7 @@
23#include <linux/types.h> 23#include <linux/types.h>
24#include <linux/err.h> 24#include <linux/err.h>
25#include <linux/prctl.h> 25#include <linux/prctl.h>
26#include <linux/context_tracking.h>
26#include <asm/cacheflush.h> 27#include <asm/cacheflush.h>
27#include <asm/traps.h> 28#include <asm/traps.h>
28#include <asm/uaccess.h> 29#include <asm/uaccess.h>
@@ -738,6 +739,7 @@ static DEFINE_PER_CPU(unsigned long, ss_saved_pc);
738 739
739void gx_singlestep_handle(struct pt_regs *regs, int fault_num) 740void gx_singlestep_handle(struct pt_regs *regs, int fault_num)
740{ 741{
742 enum ctx_state prev_state = exception_enter();
741 unsigned long *ss_pc = this_cpu_ptr(&ss_saved_pc); 743 unsigned long *ss_pc = this_cpu_ptr(&ss_saved_pc);
742 struct thread_info *info = (void *)current_thread_info(); 744 struct thread_info *info = (void *)current_thread_info();
743 int is_single_step = test_ti_thread_flag(info, TIF_SINGLESTEP); 745 int is_single_step = test_ti_thread_flag(info, TIF_SINGLESTEP);
@@ -754,6 +756,7 @@ void gx_singlestep_handle(struct pt_regs *regs, int fault_num)
754 __insn_mtspr(SPR_SINGLE_STEP_CONTROL_K, control); 756 __insn_mtspr(SPR_SINGLE_STEP_CONTROL_K, control);
755 send_sigtrap(current, regs); 757 send_sigtrap(current, regs);
756 } 758 }
759 exception_exit(prev_state);
757} 760}
758 761
759 762
diff --git a/arch/tile/kernel/smp.c b/arch/tile/kernel/smp.c
index d3c4ed780ce2..07e3ff5cc740 100644
--- a/arch/tile/kernel/smp.c
+++ b/arch/tile/kernel/smp.c
@@ -18,6 +18,7 @@
18#include <linux/interrupt.h> 18#include <linux/interrupt.h>
19#include <linux/io.h> 19#include <linux/io.h>
20#include <linux/irq.h> 20#include <linux/irq.h>
21#include <linux/irq_work.h>
21#include <linux/module.h> 22#include <linux/module.h>
22#include <asm/cacheflush.h> 23#include <asm/cacheflush.h>
23#include <asm/homecache.h> 24#include <asm/homecache.h>
@@ -33,6 +34,8 @@ EXPORT_SYMBOL(smp_topology);
33static unsigned long __iomem *ipi_mappings[NR_CPUS]; 34static unsigned long __iomem *ipi_mappings[NR_CPUS];
34#endif 35#endif
35 36
37/* Does messaging work correctly to the local cpu? */
38bool self_interrupt_ok;
36 39
37/* 40/*
38 * Top-level send_IPI*() functions to send messages to other cpus. 41 * Top-level send_IPI*() functions to send messages to other cpus.
@@ -147,6 +150,10 @@ void evaluate_message(int tag)
147 generic_smp_call_function_single_interrupt(); 150 generic_smp_call_function_single_interrupt();
148 break; 151 break;
149 152
153 case MSG_TAG_IRQ_WORK: /* Invoke IRQ work */
154 irq_work_run();
155 break;
156
150 default: 157 default:
151 panic("Unknown IPI message tag %d", tag); 158 panic("Unknown IPI message tag %d", tag);
152 break; 159 break;
@@ -186,6 +193,15 @@ void flush_icache_range(unsigned long start, unsigned long end)
186EXPORT_SYMBOL(flush_icache_range); 193EXPORT_SYMBOL(flush_icache_range);
187 194
188 195
196#ifdef CONFIG_IRQ_WORK
197void arch_irq_work_raise(void)
198{
199 if (arch_irq_work_has_interrupt())
200 send_IPI_single(smp_processor_id(), MSG_TAG_IRQ_WORK);
201}
202#endif
203
204
189/* Called when smp_send_reschedule() triggers IRQ_RESCHEDULE. */ 205/* Called when smp_send_reschedule() triggers IRQ_RESCHEDULE. */
190static irqreturn_t handle_reschedule_ipi(int irq, void *token) 206static irqreturn_t handle_reschedule_ipi(int irq, void *token)
191{ 207{
@@ -203,8 +219,22 @@ static struct irqaction resched_action = {
203 219
204void __init ipi_init(void) 220void __init ipi_init(void)
205{ 221{
222 int cpu = smp_processor_id();
223 HV_Recipient recip = { .y = cpu_y(cpu), .x = cpu_x(cpu),
224 .state = HV_TO_BE_SENT };
225 int tag = MSG_TAG_CALL_FUNCTION_SINGLE;
226
227 /*
228 * Test if we can message ourselves for arch_irq_work_raise.
229 * This functionality is only available in the Tilera hypervisor
230 * in versions 4.3.4 and following.
231 */
232 if (hv_send_message(&recip, 1, (HV_VirtAddr)&tag, sizeof(tag)) == 1)
233 self_interrupt_ok = true;
234 else
235 pr_warn("Older hypervisor: disabling fast irq_work_raise\n");
236
206#if CHIP_HAS_IPI() 237#if CHIP_HAS_IPI()
207 int cpu;
208 /* Map IPI trigger MMIO addresses. */ 238 /* Map IPI trigger MMIO addresses. */
209 for_each_possible_cpu(cpu) { 239 for_each_possible_cpu(cpu) {
210 HV_Coord tile; 240 HV_Coord tile;
diff --git a/arch/tile/kernel/stack.c b/arch/tile/kernel/stack.c
index 7ff5afdbd3aa..c42dce50acd8 100644
--- a/arch/tile/kernel/stack.c
+++ b/arch/tile/kernel/stack.c
@@ -108,14 +108,15 @@ static struct pt_regs *valid_fault_handler(struct KBacktraceIterator* kbt)
108 p->sp < PAGE_OFFSET && p->sp != 0) { 108 p->sp < PAGE_OFFSET && p->sp != 0) {
109 if (kbt->verbose) 109 if (kbt->verbose)
110 pr_err(" <%s while in user mode>\n", fault); 110 pr_err(" <%s while in user mode>\n", fault);
111 } else if (kbt->verbose) { 111 } else {
112 pr_err(" (odd fault: pc %#lx, sp %#lx, ex1 %#lx?)\n", 112 if (kbt->verbose)
113 p->pc, p->sp, p->ex1); 113 pr_err(" (odd fault: pc %#lx, sp %#lx, ex1 %#lx?)\n",
114 p = NULL; 114 p->pc, p->sp, p->ex1);
115 return NULL;
115 } 116 }
116 if (!kbt->profile || ((1ULL << p->faultnum) & QUEUED_INTERRUPTS) == 0) 117 if (kbt->profile && ((1ULL << p->faultnum) & QUEUED_INTERRUPTS) != 0)
117 return p; 118 return NULL;
118 return NULL; 119 return p;
119} 120}
120 121
121/* Is the pc pointing to a sigreturn trampoline? */ 122/* Is the pc pointing to a sigreturn trampoline? */
diff --git a/arch/tile/kernel/traps.c b/arch/tile/kernel/traps.c
index bf841ca517bb..312fc134c1cb 100644
--- a/arch/tile/kernel/traps.c
+++ b/arch/tile/kernel/traps.c
@@ -20,6 +20,7 @@
20#include <linux/reboot.h> 20#include <linux/reboot.h>
21#include <linux/uaccess.h> 21#include <linux/uaccess.h>
22#include <linux/ptrace.h> 22#include <linux/ptrace.h>
23#include <linux/context_tracking.h>
23#include <asm/stack.h> 24#include <asm/stack.h>
24#include <asm/traps.h> 25#include <asm/traps.h>
25#include <asm/setup.h> 26#include <asm/setup.h>
@@ -253,6 +254,7 @@ static int do_bpt(struct pt_regs *regs)
253void __kprobes do_trap(struct pt_regs *regs, int fault_num, 254void __kprobes do_trap(struct pt_regs *regs, int fault_num,
254 unsigned long reason) 255 unsigned long reason)
255{ 256{
257 enum ctx_state prev_state = exception_enter();
256 siginfo_t info = { 0 }; 258 siginfo_t info = { 0 };
257 int signo, code; 259 int signo, code;
258 unsigned long address = 0; 260 unsigned long address = 0;
@@ -261,7 +263,7 @@ void __kprobes do_trap(struct pt_regs *regs, int fault_num,
261 263
262 /* Handle breakpoints, etc. */ 264 /* Handle breakpoints, etc. */
263 if (is_kernel && fault_num == INT_ILL && do_bpt(regs)) 265 if (is_kernel && fault_num == INT_ILL && do_bpt(regs))
264 return; 266 goto done;
265 267
266 /* Re-enable interrupts, if they were previously enabled. */ 268 /* Re-enable interrupts, if they were previously enabled. */
267 if (!(regs->flags & PT_FLAGS_DISABLE_IRQ)) 269 if (!(regs->flags & PT_FLAGS_DISABLE_IRQ))
@@ -275,7 +277,7 @@ void __kprobes do_trap(struct pt_regs *regs, int fault_num,
275 const char *name; 277 const char *name;
276 char buf[100]; 278 char buf[100];
277 if (fixup_exception(regs)) /* ILL_TRANS or UNALIGN_DATA */ 279 if (fixup_exception(regs)) /* ILL_TRANS or UNALIGN_DATA */
278 return; 280 goto done;
279 if (fault_num >= 0 && 281 if (fault_num >= 0 &&
280 fault_num < ARRAY_SIZE(int_name) && 282 fault_num < ARRAY_SIZE(int_name) &&
281 int_name[fault_num] != NULL) 283 int_name[fault_num] != NULL)
@@ -294,7 +296,6 @@ void __kprobes do_trap(struct pt_regs *regs, int fault_num,
294 fault_num, name, regs->pc, buf); 296 fault_num, name, regs->pc, buf);
295 show_regs(regs); 297 show_regs(regs);
296 do_exit(SIGKILL); /* FIXME: implement i386 die() */ 298 do_exit(SIGKILL); /* FIXME: implement i386 die() */
297 return;
298 } 299 }
299 300
300 switch (fault_num) { 301 switch (fault_num) {
@@ -308,7 +309,6 @@ void __kprobes do_trap(struct pt_regs *regs, int fault_num,
308 pr_err("Unreadable instruction for INT_ILL: %#lx\n", 309 pr_err("Unreadable instruction for INT_ILL: %#lx\n",
309 regs->pc); 310 regs->pc);
310 do_exit(SIGKILL); 311 do_exit(SIGKILL);
311 return;
312 } 312 }
313 if (!special_ill(instr, &signo, &code)) { 313 if (!special_ill(instr, &signo, &code)) {
314 signo = SIGILL; 314 signo = SIGILL;
@@ -319,7 +319,7 @@ void __kprobes do_trap(struct pt_regs *regs, int fault_num,
319 case INT_GPV: 319 case INT_GPV:
320#if CHIP_HAS_TILE_DMA() 320#if CHIP_HAS_TILE_DMA()
321 if (retry_gpv(reason)) 321 if (retry_gpv(reason))
322 return; 322 goto done;
323#endif 323#endif
324 /*FALLTHROUGH*/ 324 /*FALLTHROUGH*/
325 case INT_UDN_ACCESS: 325 case INT_UDN_ACCESS:
@@ -346,7 +346,7 @@ void __kprobes do_trap(struct pt_regs *regs, int fault_num,
346 if (!state || 346 if (!state ||
347 (void __user *)(regs->pc) != state->buffer) { 347 (void __user *)(regs->pc) != state->buffer) {
348 single_step_once(regs); 348 single_step_once(regs);
349 return; 349 goto done;
350 } 350 }
351 } 351 }
352#endif 352#endif
@@ -380,7 +380,6 @@ void __kprobes do_trap(struct pt_regs *regs, int fault_num,
380#endif 380#endif
381 default: 381 default:
382 panic("Unexpected do_trap interrupt number %d", fault_num); 382 panic("Unexpected do_trap interrupt number %d", fault_num);
383 return;
384 } 383 }
385 384
386 info.si_signo = signo; 385 info.si_signo = signo;
@@ -391,6 +390,9 @@ void __kprobes do_trap(struct pt_regs *regs, int fault_num,
391 if (signo != SIGTRAP) 390 if (signo != SIGTRAP)
392 trace_unhandled_signal("trap", regs, address, signo); 391 trace_unhandled_signal("trap", regs, address, signo);
393 force_sig_info(signo, &info, current); 392 force_sig_info(signo, &info, current);
393
394done:
395 exception_exit(prev_state);
394} 396}
395 397
396void kernel_double_fault(int dummy, ulong pc, ulong lr, ulong sp, ulong r52) 398void kernel_double_fault(int dummy, ulong pc, ulong lr, ulong sp, ulong r52)
diff --git a/arch/tile/kernel/unaligned.c b/arch/tile/kernel/unaligned.c
index 7d9a83be0aca..d075f92ccee0 100644
--- a/arch/tile/kernel/unaligned.c
+++ b/arch/tile/kernel/unaligned.c
@@ -25,6 +25,7 @@
25#include <linux/module.h> 25#include <linux/module.h>
26#include <linux/compat.h> 26#include <linux/compat.h>
27#include <linux/prctl.h> 27#include <linux/prctl.h>
28#include <linux/context_tracking.h>
28#include <asm/cacheflush.h> 29#include <asm/cacheflush.h>
29#include <asm/traps.h> 30#include <asm/traps.h>
30#include <asm/uaccess.h> 31#include <asm/uaccess.h>
@@ -1448,6 +1449,7 @@ void jit_bundle_gen(struct pt_regs *regs, tilegx_bundle_bits bundle,
1448 1449
1449void do_unaligned(struct pt_regs *regs, int vecnum) 1450void do_unaligned(struct pt_regs *regs, int vecnum)
1450{ 1451{
1452 enum ctx_state prev_state = exception_enter();
1451 tilegx_bundle_bits __user *pc; 1453 tilegx_bundle_bits __user *pc;
1452 tilegx_bundle_bits bundle; 1454 tilegx_bundle_bits bundle;
1453 struct thread_info *info = current_thread_info(); 1455 struct thread_info *info = current_thread_info();
@@ -1487,12 +1489,11 @@ void do_unaligned(struct pt_regs *regs, int vecnum)
1487 (int)unaligned_fixup, 1489 (int)unaligned_fixup,
1488 (unsigned long long)regs->ex1, 1490 (unsigned long long)regs->ex1,
1489 (unsigned long long)regs->pc); 1491 (unsigned long long)regs->pc);
1490 return; 1492 } else {
1493 /* Not fixable. Go panic. */
1494 panic("Unalign exception in Kernel. pc=%lx",
1495 regs->pc);
1491 } 1496 }
1492 /* Not fixable. Go panic. */
1493 panic("Unalign exception in Kernel. pc=%lx",
1494 regs->pc);
1495 return;
1496 } else { 1497 } else {
1497 /* 1498 /*
1498 * Try to fix the exception. If we can't, panic the 1499 * Try to fix the exception. If we can't, panic the
@@ -1501,8 +1502,8 @@ void do_unaligned(struct pt_regs *regs, int vecnum)
1501 bundle = GX_INSN_BSWAP( 1502 bundle = GX_INSN_BSWAP(
1502 *((tilegx_bundle_bits *)(regs->pc))); 1503 *((tilegx_bundle_bits *)(regs->pc)));
1503 jit_bundle_gen(regs, bundle, align_ctl); 1504 jit_bundle_gen(regs, bundle, align_ctl);
1504 return;
1505 } 1505 }
1506 goto done;
1506 } 1507 }
1507 1508
1508 /* 1509 /*
@@ -1526,7 +1527,7 @@ void do_unaligned(struct pt_regs *regs, int vecnum)
1526 1527
1527 trace_unhandled_signal("unaligned fixup trap", regs, 0, SIGBUS); 1528 trace_unhandled_signal("unaligned fixup trap", regs, 0, SIGBUS);
1528 force_sig_info(info.si_signo, &info, current); 1529 force_sig_info(info.si_signo, &info, current);
1529 return; 1530 goto done;
1530 } 1531 }
1531 1532
1532 1533
@@ -1543,7 +1544,7 @@ void do_unaligned(struct pt_regs *regs, int vecnum)
1543 trace_unhandled_signal("segfault in unalign fixup", regs, 1544 trace_unhandled_signal("segfault in unalign fixup", regs,
1544 (unsigned long)info.si_addr, SIGSEGV); 1545 (unsigned long)info.si_addr, SIGSEGV);
1545 force_sig_info(info.si_signo, &info, current); 1546 force_sig_info(info.si_signo, &info, current);
1546 return; 1547 goto done;
1547 } 1548 }
1548 1549
1549 if (!info->unalign_jit_base) { 1550 if (!info->unalign_jit_base) {
@@ -1578,7 +1579,7 @@ void do_unaligned(struct pt_regs *regs, int vecnum)
1578 1579
1579 if (IS_ERR((void __force *)user_page)) { 1580 if (IS_ERR((void __force *)user_page)) {
1580 pr_err("Out of kernel pages trying do_mmap\n"); 1581 pr_err("Out of kernel pages trying do_mmap\n");
1581 return; 1582 goto done;
1582 } 1583 }
1583 1584
1584 /* Save the address in the thread_info struct */ 1585 /* Save the address in the thread_info struct */
@@ -1591,6 +1592,9 @@ void do_unaligned(struct pt_regs *regs, int vecnum)
1591 1592
1592 /* Generate unalign JIT */ 1593 /* Generate unalign JIT */
1593 jit_bundle_gen(regs, GX_INSN_BSWAP(bundle), align_ctl); 1594 jit_bundle_gen(regs, GX_INSN_BSWAP(bundle), align_ctl);
1595
1596done:
1597 exception_exit(prev_state);
1594} 1598}
1595 1599
1596#endif /* __tilegx__ */ 1600#endif /* __tilegx__ */
diff --git a/arch/tile/mm/elf.c b/arch/tile/mm/elf.c
index 23f044e8a7ab..f7ddae3725a4 100644
--- a/arch/tile/mm/elf.c
+++ b/arch/tile/mm/elf.c
@@ -17,6 +17,7 @@
17#include <linux/binfmts.h> 17#include <linux/binfmts.h>
18#include <linux/compat.h> 18#include <linux/compat.h>
19#include <linux/mman.h> 19#include <linux/mman.h>
20#include <linux/file.h>
20#include <linux/elf.h> 21#include <linux/elf.h>
21#include <asm/pgtable.h> 22#include <asm/pgtable.h>
22#include <asm/pgalloc.h> 23#include <asm/pgalloc.h>
@@ -39,30 +40,34 @@ static void sim_notify_exec(const char *binary_name)
39 40
40static int notify_exec(struct mm_struct *mm) 41static int notify_exec(struct mm_struct *mm)
41{ 42{
43 int ret = 0;
42 char *buf, *path; 44 char *buf, *path;
43 struct vm_area_struct *vma; 45 struct vm_area_struct *vma;
46 struct file *exe_file;
44 47
45 if (!sim_is_simulator()) 48 if (!sim_is_simulator())
46 return 1; 49 return 1;
47 50
48 if (mm->exe_file == NULL)
49 return 0;
50
51 for (vma = current->mm->mmap; ; vma = vma->vm_next) {
52 if (vma == NULL)
53 return 0;
54 if (vma->vm_file == mm->exe_file)
55 break;
56 }
57
58 buf = (char *) __get_free_page(GFP_KERNEL); 51 buf = (char *) __get_free_page(GFP_KERNEL);
59 if (buf == NULL) 52 if (buf == NULL)
60 return 0; 53 return 0;
61 54
62 path = d_path(&mm->exe_file->f_path, buf, PAGE_SIZE); 55 exe_file = get_mm_exe_file(mm);
63 if (IS_ERR(path)) { 56 if (exe_file == NULL)
64 free_page((unsigned long)buf); 57 goto done_free;
65 return 0; 58
59 path = d_path(&exe_file->f_path, buf, PAGE_SIZE);
60 if (IS_ERR(path))
61 goto done_put;
62
63 down_read(&mm->mmap_sem);
64 for (vma = current->mm->mmap; ; vma = vma->vm_next) {
65 if (vma == NULL) {
66 up_read(&mm->mmap_sem);
67 goto done_put;
68 }
69 if (vma->vm_file == exe_file)
70 break;
66 } 71 }
67 72
68 /* 73 /*
@@ -80,14 +85,20 @@ static int notify_exec(struct mm_struct *mm)
80 __insn_mtspr(SPR_SIM_CONTROL, 85 __insn_mtspr(SPR_SIM_CONTROL,
81 (SIM_CONTROL_DLOPEN 86 (SIM_CONTROL_DLOPEN
82 | (c << _SIM_CONTROL_OPERATOR_BITS))); 87 | (c << _SIM_CONTROL_OPERATOR_BITS)));
83 if (c == '\0') 88 if (c == '\0') {
89 ret = 1; /* success */
84 break; 90 break;
91 }
85 } 92 }
86 } 93 }
94 up_read(&mm->mmap_sem);
87 95
88 sim_notify_exec(path); 96 sim_notify_exec(path);
97done_put:
98 fput(exe_file);
99done_free:
89 free_page((unsigned long)buf); 100 free_page((unsigned long)buf);
90 return 1; 101 return ret;
91} 102}
92 103
93/* Notify a running simulator, if any, that we loaded an interpreter. */ 104/* Notify a running simulator, if any, that we loaded an interpreter. */
@@ -109,8 +120,6 @@ int arch_setup_additional_pages(struct linux_binprm *bprm,
109 struct mm_struct *mm = current->mm; 120 struct mm_struct *mm = current->mm;
110 int retval = 0; 121 int retval = 0;
111 122
112 down_write(&mm->mmap_sem);
113
114 /* 123 /*
115 * Notify the simulator that an exec just occurred. 124 * Notify the simulator that an exec just occurred.
116 * If we can't find the filename of the mapping, just use 125 * If we can't find the filename of the mapping, just use
@@ -119,6 +128,8 @@ int arch_setup_additional_pages(struct linux_binprm *bprm,
119 if (!notify_exec(mm)) 128 if (!notify_exec(mm))
120 sim_notify_exec(bprm->filename); 129 sim_notify_exec(bprm->filename);
121 130
131 down_write(&mm->mmap_sem);
132
122 retval = setup_vdso_pages(); 133 retval = setup_vdso_pages();
123 134
124#ifndef __tilegx__ 135#ifndef __tilegx__
diff --git a/arch/tile/mm/fault.c b/arch/tile/mm/fault.c
index 0f61a73534e6..e83cc999da02 100644
--- a/arch/tile/mm/fault.c
+++ b/arch/tile/mm/fault.c
@@ -35,6 +35,7 @@
35#include <linux/syscalls.h> 35#include <linux/syscalls.h>
36#include <linux/uaccess.h> 36#include <linux/uaccess.h>
37#include <linux/kdebug.h> 37#include <linux/kdebug.h>
38#include <linux/context_tracking.h>
38 39
39#include <asm/pgalloc.h> 40#include <asm/pgalloc.h>
40#include <asm/sections.h> 41#include <asm/sections.h>
@@ -702,6 +703,7 @@ void do_page_fault(struct pt_regs *regs, int fault_num,
702 unsigned long address, unsigned long write) 703 unsigned long address, unsigned long write)
703{ 704{
704 int is_page_fault; 705 int is_page_fault;
706 enum ctx_state prev_state = exception_enter();
705 707
706#ifdef CONFIG_KPROBES 708#ifdef CONFIG_KPROBES
707 /* 709 /*
@@ -711,7 +713,7 @@ void do_page_fault(struct pt_regs *regs, int fault_num,
711 */ 713 */
712 if (notify_die(DIE_PAGE_FAULT, "page fault", regs, -1, 714 if (notify_die(DIE_PAGE_FAULT, "page fault", regs, -1,
713 regs->faultnum, SIGSEGV) == NOTIFY_STOP) 715 regs->faultnum, SIGSEGV) == NOTIFY_STOP)
714 return; 716 goto done;
715#endif 717#endif
716 718
717#ifdef __tilegx__ 719#ifdef __tilegx__
@@ -750,7 +752,6 @@ void do_page_fault(struct pt_regs *regs, int fault_num,
750 current->comm, current->pid, pc, address); 752 current->comm, current->pid, pc, address);
751 show_regs(regs); 753 show_regs(regs);
752 do_group_exit(SIGKILL); 754 do_group_exit(SIGKILL);
753 return;
754 } 755 }
755 } 756 }
756#else 757#else
@@ -834,12 +835,15 @@ void do_page_fault(struct pt_regs *regs, int fault_num,
834 async->is_fault = is_page_fault; 835 async->is_fault = is_page_fault;
835 async->is_write = write; 836 async->is_write = write;
836 async->address = address; 837 async->address = address;
837 return; 838 goto done;
838 } 839 }
839 } 840 }
840#endif 841#endif
841 842
842 handle_page_fault(regs, fault_num, is_page_fault, address, write); 843 handle_page_fault(regs, fault_num, is_page_fault, address, write);
844
845done:
846 exception_exit(prev_state);
843} 847}
844 848
845 849
diff --git a/arch/tile/mm/init.c b/arch/tile/mm/init.c
index ace32d7d3864..5bd252e3fdc5 100644
--- a/arch/tile/mm/init.c
+++ b/arch/tile/mm/init.c
@@ -233,9 +233,12 @@ static pgprot_t __init init_pgprot(ulong address)
233 if (kdata_huge) 233 if (kdata_huge)
234 return construct_pgprot(PAGE_KERNEL, PAGE_HOME_HASH); 234 return construct_pgprot(PAGE_KERNEL, PAGE_HOME_HASH);
235 235
236 /* We map the aliased pages of permanent text inaccessible. */ 236 /*
237 * We map the aliased pages of permanent text so we can
238 * update them if necessary, for ftrace, etc.
239 */
237 if (address < (ulong) _sinittext - CODE_DELTA) 240 if (address < (ulong) _sinittext - CODE_DELTA)
238 return PAGE_NONE; 241 return construct_pgprot(PAGE_KERNEL, PAGE_HOME_HASH);
239 242
240 /* We map read-only data non-coherent for performance. */ 243 /* We map read-only data non-coherent for performance. */
241 if ((address >= (ulong) __start_rodata && 244 if ((address >= (ulong) __start_rodata &&