From patchwork Thu Dec 6 18:11:06 2012 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Jon Medhurst (Tixy)" X-Patchwork-Id: 1846251 Return-Path: X-Original-To: patchwork-linux-arm@patchwork.kernel.org Delivered-To: patchwork-process-083081@patchwork2.kernel.org Received: from merlin.infradead.org (merlin.infradead.org [205.233.59.134]) by patchwork2.kernel.org (Postfix) with ESMTP id C6054DF2F9 for ; Thu, 6 Dec 2012 18:13:52 +0000 (UTC) Received: from localhost ([::1] helo=merlin.infradead.org) by merlin.infradead.org with esmtp (Exim 4.76 #1 (Red Hat Linux)) id 1Tgfur-0004Gm-DR; Thu, 06 Dec 2012 18:11:21 +0000 Received: from smarthost04.mail.zen.net.uk ([212.23.1.4]) by merlin.infradead.org with esmtp (Exim 4.76 #1 (Red Hat Linux)) id 1Tgfug-0004FX-Kw for linux-arm-kernel@lists.infradead.org; Thu, 06 Dec 2012 18:11:12 +0000 Received: from [82.69.122.217] (helo=[192.168.2.110]) by smarthost04.mail.zen.net.uk with esmtpsa (TLS1.0:RSA_AES_256_CBC_SHA1:32) (Exim 4.72) (envelope-from ) id 1Tgfuc-00022l-Lr; Thu, 06 Dec 2012 18:11:06 +0000 Message-ID: <1354817466.30905.13.camel@linaro1.home> Subject: [PATCH] ARM: ftrace: Ensure code modifications are synchronised across all cpus From: "Jon Medhurst (Tixy)" To: linux-arm-kernel@lists.infradead.org Date: Thu, 06 Dec 2012 18:11:06 +0000 X-Mailer: Evolution 3.4.4-1 Mime-Version: 1.0 X-Originating-Smarthost04-IP: [82.69.122.217] X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20121206_131111_023055_D2CFAEA9 X-CRM114-Status: GOOD ( 17.12 ) X-Spam-Score: -1.9 (-) X-Spam-Report: SpamAssassin version 3.3.2 on merlin.infradead.org summary: Content analysis details: (-1.9 points) pts rule name description ---- ---------------------- -------------------------------------------------- -0.0 RCVD_IN_DNSWL_NONE RBL: Sender listed at http://www.dnswl.org/, no trust [212.23.1.4 listed in list.dnswl.org] -1.9 BAYES_00 BODY: Bayes spam probability is 0 to 1% [score: 0.0000] Cc: Russell King , Frederic Weisbecker , linux-kernel@vger.kernel.org, Steven Rostedt , Rabin Vincent , Ingo Molnar X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: linux-arm-kernel-bounces@lists.infradead.org Errors-To: linux-arm-kernel-bounces+patchwork-linux-arm=patchwork.kernel.org@lists.infradead.org When the generic ftrace implementation modifies code for trace-points it uses stop_machine() to call ftrace_modify_all_code() on one CPU. This ultimately calls the ARM specific function ftrace_modify_code() which updates the instruction and then does flush_icache_range(). As this cache flushing only operates on the local CPU then other cores may end up executing the old instruction if it's still in their icaches. This may or may not cause problems for the use of ftrace on kernels compiled for ARM instructions. However, Thumb2 instructions can straddle two cache lines so its possible for half the old instruction to be in the cache and half the new one, leading to the CPU executing garbage. This patch fixes this situation by providing an arch-specific implementation of arch_ftrace_update_code() which ensures that after one core has modified all the code, the other cores invalidate their icaches before continuing. Signed-off-by: Jon Medhurst --- arch/arm/kernel/ftrace.c | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/arch/arm/kernel/ftrace.c b/arch/arm/kernel/ftrace.c index 34e5664..38b670c 100644 --- a/arch/arm/kernel/ftrace.c +++ b/arch/arm/kernel/ftrace.c @@ -14,6 +14,7 @@ #include #include +#include #include #include @@ -156,6 +157,39 @@ int ftrace_make_nop(struct module *mod, return ret; } +struct afmc_data { + int command; + atomic_t cpu; + atomic_t done; +}; + +static int __arch_ftrace_modify_code(void *data) +{ + struct afmc_data *afmcd = data; + + if (atomic_inc_return(&afmcd->cpu) == num_online_cpus()) { + /* Last cpu to get into this function does the actual work */ + ftrace_modify_all_code(afmcd->command); + wmb(); + atomic_set(&afmcd->done, true); + } else { + /* Other cpus wait for the code modifications to be done */ + rmb(); + while (!atomic_read(&afmcd->done)) + cpu_relax(); + /* Ensure icache is consistent with the code changes */ + __flush_icache_all(); + } + + return 0; +} + +void arch_ftrace_update_code(int command) +{ + struct afmc_data afmcd = { command }; + stop_machine(__arch_ftrace_modify_code, &afmcd, cpu_online_mask); +} + int __init ftrace_dyn_arch_init(void *data) { *(unsigned long *)data = 0;