From patchwork Fri Aug 23 19:45:12 2013 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Colin Cross X-Patchwork-Id: 2849033 Return-Path: X-Original-To: patchwork-linux-pm@patchwork.kernel.org Delivered-To: patchwork-parsemail@patchwork1.web.kernel.org Received: from mail.kernel.org (mail.kernel.org [198.145.19.201]) by patchwork1.web.kernel.org (Postfix) with ESMTP id C40BE9F239 for ; Fri, 23 Aug 2013 19:46:14 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id B456B204D1 for ; Fri, 23 Aug 2013 19:46:13 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id C4BFA204AF for ; Fri, 23 Aug 2013 19:46:12 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1756365Ab3HWTpU (ORCPT ); Fri, 23 Aug 2013 15:45:20 -0400 Received: from mail-gh0-f202.google.com ([209.85.160.202]:36278 "EHLO mail-gh0-f202.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1756353Ab3HWTpQ (ORCPT ); Fri, 23 Aug 2013 15:45:16 -0400 Received: by mail-gh0-f202.google.com with SMTP id g24so102242ghb.5 for ; Fri, 23 Aug 2013 12:45:15 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20120113; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=MNYO7FBWfUmPR+b/mq9wpeTrdoa7XC1zzQlxawn6es0=; b=mn5TQOc5YcHs6hxjHaAOtW1kWxE9OU3hVqkQQ1Er9FAQj6CmkE9pvfjRnPSo6hrzSC wsFRizktjE/n3lGyuvY4XoWJr+8Xb7/IPDra1BWuVLHuF7gQ1yk8gk0EaB+d2QEJL0Eo BrinelufFogiD6aGG7zHkJwaZkeDsAAiSqfqsuNX4CLuySRCI8u0MeopqxxC5kedTXzs HoHr31Lm8IGQM3GsHsjRUKo/BqpvlV4yH+32VQfwqaoZUG6ityUk31SgX5Znl4wrEGfn vZ4kyLFtQMYahzcBeaEl0Xv3WTqhZHlkHqYYu3D3oFr3SA2IdvIaw1i6IVKbcsizsw4c exRA== X-Gm-Message-State: ALoCoQk9mG8Xa3OPXJEa/Fg8XxpxOz+M6t3uNDjvAWVN8dgEa5NNLmv2wXp4TzzVDhiZEbY+UM91Pp4ddn4P2n8sfzKf4o5QryV3KCbjEvDPVXorQ1baLbbQwcDJShzW+ZTkJeOuQLSbzNavT4/uxHU6oUlB+LSEXALvmmtp4kZzBCIZhDs0nhFOw6nvIo/e9TkhRqLRTqnNgENT8qlmqtbxp54a2CrAXg== X-Received: by 10.236.174.232 with SMTP id x68mr425428yhl.42.1377287115877; Fri, 23 Aug 2013 12:45:15 -0700 (PDT) Received: from corp2gmr1-1.hot.corp.google.com (corp2gmr1-1.hot.corp.google.com [172.24.189.92]) by gmr-mx.google.com with ESMTPS id a49si95431yhc.5.1969.12.31.16.00.00 (version=TLSv1.1 cipher=AES128-SHA bits=128/128); Fri, 23 Aug 2013 12:45:15 -0700 (PDT) Received: from walnut.mtv.corp.google.com (walnut.mtv.corp.google.com [172.18.120.100]) by corp2gmr1-1.hot.corp.google.com (Postfix) with ESMTP id AB50031C1C6; Fri, 23 Aug 2013 12:45:15 -0700 (PDT) Received: by walnut.mtv.corp.google.com (Postfix, from userid 99897) id 597D5160F83; Fri, 23 Aug 2013 12:45:15 -0700 (PDT) From: Colin Cross To: linux-pm@vger.kernel.org Cc: linux-kernel@vger.kernel.org, Neil Zhang , Joseph Lo , linux-tegra@vger.kernel.org, Colin Cross , stable@vger.kernel.org, "Rafael J. Wysocki" , Daniel Lezcano Subject: [PATCH 3/3] cpuidle: coupled: fix race condition between pokes and safe state Date: Fri, 23 Aug 2013 12:45:12 -0700 Message-Id: <1377287112-12018-3-git-send-email-ccross@android.com> X-Mailer: git-send-email 1.8.3 In-Reply-To: <1377287112-12018-1-git-send-email-ccross@android.com> References: <1377287112-12018-1-git-send-email-ccross@android.com> Sender: linux-pm-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-pm@vger.kernel.org X-Spam-Status: No, score=-9.7 required=5.0 tests=BAYES_00, RCVD_IN_DNSWL_HI, RP_MATCHES_RCVD, UNPARSEABLE_RELAY autolearn=unavailable version=3.3.1 X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on mail.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP The coupled cpuidle waiting loop clears pending pokes before entering the safe state. If a poke arrives just before the pokes are cleared, but after the while loop condition checks, the poke will be lost and the cpu will stay in the safe state until another interrupt arrives. This may cause the cpu that sent the poke to spin in the ready loop with interrupts off until another cpu receives an interrupt, and if no other cpus have interrupts routed to them it can spin forever. Change the return value of cpuidle_coupled_clear_pokes to return if a poke was cleared, and move the need_resched() checks into the callers. In the waiting loop, if a poke was cleared restart the loop to repeat the while condition checks. Reported-by: Neil Zhang CC: stable@vger.kernel.org Signed-off-by: Colin Cross --- drivers/cpuidle/coupled.c | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/drivers/cpuidle/coupled.c b/drivers/cpuidle/coupled.c index bbc4ba5..c91230b 100644 --- a/drivers/cpuidle/coupled.c +++ b/drivers/cpuidle/coupled.c @@ -408,19 +408,22 @@ static void cpuidle_coupled_set_done(int cpu, struct cpuidle_coupled *coupled) * been processed and the poke bit has been cleared. * * Other interrupts may also be processed while interrupts are enabled, so - * need_resched() must be tested after turning interrupts off again to make sure + * need_resched() must be tested after this function returns to make sure * the interrupt didn't schedule work that should take the cpu out of idle. * - * Returns 0 if need_resched was false, -EINTR if need_resched was true. + * Returns 0 if no poke was pending, 1 if a poke was cleared. */ static int cpuidle_coupled_clear_pokes(int cpu) { + if (!cpumask_test_cpu(cpu, &cpuidle_coupled_poke_pending)) + return 0; + local_irq_enable(); while (cpumask_test_cpu(cpu, &cpuidle_coupled_poke_pending)) cpu_relax(); local_irq_disable(); - return need_resched() ? -EINTR : 0; + return 1; } static bool cpuidle_coupled_any_pokes_pending(struct cpuidle_coupled *coupled) @@ -464,7 +467,8 @@ int cpuidle_enter_state_coupled(struct cpuidle_device *dev, return -EINVAL; while (coupled->prevent) { - if (cpuidle_coupled_clear_pokes(dev->cpu)) { + cpuidle_coupled_clear_pokes(dev->cpu); + if (need_resched()) { local_irq_enable(); return entered_state; } @@ -503,7 +507,10 @@ retry: */ while (!cpuidle_coupled_cpus_waiting(coupled) || !cpumask_test_cpu(dev->cpu, &cpuidle_coupled_poked)) { - if (cpuidle_coupled_clear_pokes(dev->cpu)) { + if (cpuidle_coupled_clear_pokes(dev->cpu)) + continue; + + if (need_resched()) { cpuidle_coupled_set_not_waiting(dev->cpu, coupled); goto out; } @@ -518,7 +525,8 @@ retry: local_irq_disable(); } - if (cpuidle_coupled_clear_pokes(dev->cpu)) { + cpuidle_coupled_clear_pokes(dev->cpu); + if (need_resched()) { cpuidle_coupled_set_not_waiting(dev->cpu, coupled); goto out; }