From patchwork Tue Feb 7 15:53:04 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ulf Hansson X-Patchwork-Id: 9560489 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork.web.codeaurora.org (Postfix) with ESMTP id B54D96047A for ; Tue, 7 Feb 2017 15:53:12 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id A78B92841D for ; Tue, 7 Feb 2017 15:53:12 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 9C4762843A; Tue, 7 Feb 2017 15:53:12 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-6.3 required=2.0 tests=BAYES_00,DKIM_SIGNED, RCVD_IN_DNSWL_HI, RCVD_IN_SORBS_SPAM, T_DKIM_INVALID autolearn=ham version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 022842841D for ; Tue, 7 Feb 2017 15:53:12 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1754869AbdBGPxL (ORCPT ); Tue, 7 Feb 2017 10:53:11 -0500 Received: from mail-lf0-f53.google.com ([209.85.215.53]:32840 "EHLO mail-lf0-f53.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1754778AbdBGPxK (ORCPT ); Tue, 7 Feb 2017 10:53:10 -0500 Received: by mail-lf0-f53.google.com with SMTP id x1so65504548lff.0 for ; Tue, 07 Feb 2017 07:53:09 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; h=from:to:cc:subject:date:message-id; bh=ohcWXC9HMD6La3TNSZvFSPlP+UKvK0diYwJ09jbbrxo=; b=Xsa6T/u4Mqv8N22owBFXVbRcEdY7msjmMZlatJk1R2ep2emOIdzHOZcELt2DFNN6RV Tl/x8AS2b5N5pJ+4xTE7hGDmNW3UTGmSF+TAiSgOTx2E5zekT2Cr08s6+HTATeckJTsz BwagvaS/gCwWQei2lhDnY6iOwN+P9mDBii4PI= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id; bh=ohcWXC9HMD6La3TNSZvFSPlP+UKvK0diYwJ09jbbrxo=; b=RoCfIRjKrM0SV4Y2wKBH/l1bwONdrbmHQM22Mez3MCHgaSKbDhNjjT0FNwig7tb9MJ ysIkE1nFb3Dj/AL0ORypxUUHz6CGuNLJA9TTpSq/YRHtvzGELyt5R1Kh3TL5F5zBX3XE LhZM7AGQ3hr9kHHEh/w0Fz3frGV6/9R8SoL37L87NeA2lIY6Au6Z08g3IE4oVSF05AGK lDfnVYGXw75rOvLnVmMdyVpyMj6yZ85Bw/i7M2VMie8rWD3kRZYC9xl8BTUq/8O092ag FwrBXK54rjp2EQPH4sVbDgyJWdTT3/F2RpzYZikHQHUu+nVh22XbERS5W6+UyQr9jKDd K9pg== X-Gm-Message-State: AIkVDXJyNg7Yo439G0rBKvjLp8k4/wXigktDiy59TcKv5noV+s7dUu7Kdx7CC6a4mJ/69E68 X-Received: by 10.25.87.5 with SMTP id l5mr5846004lfb.87.1486482788745; Tue, 07 Feb 2017 07:53:08 -0800 (PST) Received: from localhost.localdomain (h-155-4-221-67.na.cust.bahnhof.se. [155.4.221.67]) by smtp.gmail.com with ESMTPSA id j129sm1434290lfg.24.2017.02.07.07.53.07 (version=TLS1_2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Tue, 07 Feb 2017 07:53:07 -0800 (PST) From: Ulf Hansson To: "Rafael J. Wysocki" , Ulf Hansson , linux-pm@vger.kernel.org Cc: Len Brown , Pavel Machek , Kevin Hilman , Geert Uytterhoeven , Lina Iyer , Jon Hunter , Marek Szyprowski , Brian Norris Subject: [PATCH] PM / Domains: Restore lock-less behaviour for the genpd syscore APIs Date: Tue, 7 Feb 2017 16:53:04 +0100 Message-Id: <1486482784-31734-1-git-send-email-ulf.hansson@linaro.org> X-Mailer: git-send-email 1.9.1 Sender: linux-pm-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-pm@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP The commit ef4f7e2c8335 ("PM / Domains: Fix asynchronous execution of *noirq() callbacks") went too far, as it not only changed to use locks for the *noirq callbacks, but also for the genpd syscore APIs. This cause the following error, reported by Geert Uytterhoeven: "This causes the following BUG on all my Renesas arm32 boards, where the system timer is an IRQ safe device: BUG: sleeping function called from invalid context at kernel/locking/mutex.c:232 in_atomic(): 0, irqs_disabled(): 128, pid: 1751, name: s2ram CPU: 0 PID: 1751 Comm: s2ram Not tainted 4.10.0-rc7-koelsch-05643-g27f4c73972a614fe #3354 Hardware name: Generic R8A7791 (Flattened Device Tree) [] (unwind_backtrace) from [] (show_stack+0x10/0x14) [] (show_stack) from [] (dump_stack+0x7c/0x9c) [] (dump_stack) from [] (___might_sleep+0x124/0x160) [] (___might_sleep) from [] (mutex_lock+0x18/0x60) [] (mutex_lock) from [] (genpd_syscore_switch+0x2c/0x7c) [] (genpd_syscore_switch) from [] (sh_cmt_clock_event_suspend+0x18/0x28) [] (sh_cmt_clock_event_suspend) from [] (clockevents_suspend+0x40/0x54) [] (clockevents_suspend) from [] (timekeeping_suspend+0x23c/0x278) [] (timekeeping_suspend) from [] (syscore_suspend+0x88/0x138) [] (syscore_suspend) from [] (suspend_devices_and_enter+0x290/0x470) [] (suspend_devices_and_enter) from [] (pm_suspend+0x228/0x280) [] (pm_suspend) from [] (state_store+0xac/0xcc) [] (state_store) from [] (kernfs_fop_write+0x160/0x19c) [] (kernfs_fop_write) from [] (__vfs_write+0x20/0x108) [] (__vfs_write) from [] (vfs_write+0xb8/0x144) [] (vfs_write) from [] (SyS_write+0x40/0x80) [] (SyS_write) from [] (ret_fast_syscall+0x0/0x34)" To fix this problem, restore the lock-less behaviour. However only for the genpd syscore APIs. Reported-by: Geert Uytterhoeven Fixes: ef4f7e2c8335 ("PM / Domains: Fix asynchronous execution of *noirq() callbacks") Signed-off-by: Ulf Hansson Tested-by: Geert Uytterhoeven --- drivers/base/power/domain.c | 48 +++++++++++++++++++++++++-------------------- 1 file changed, 27 insertions(+), 21 deletions(-) diff --git a/drivers/base/power/domain.c b/drivers/base/power/domain.c index 271e208..3a75fb1 100644 --- a/drivers/base/power/domain.c +++ b/drivers/base/power/domain.c @@ -729,16 +729,17 @@ static bool genpd_dev_active_wakeup(struct generic_pm_domain *genpd, /** * genpd_sync_power_off - Synchronously power off a PM domain and its masters. * @genpd: PM domain to power off, if possible. + * @use_lock: use the lock. * @depth: nesting count for lockdep. * * Check if the given PM domain can be powered off (during system suspend or * hibernation) and do that if so. Also, in that case propagate to its masters. * * This function is only called in "noirq" and "syscore" stages of system power - * transitions, but since the "noirq" callbacks may be executed asynchronously, - * the lock must be held. + * transitions. The "noirq" callbacks may be executed asynchronously, thus in + * these cases the lock must be held. */ -static void genpd_sync_power_off(struct generic_pm_domain *genpd, +static void genpd_sync_power_off(struct generic_pm_domain *genpd, bool use_lock, unsigned int depth) { struct gpd_link *link; @@ -759,22 +760,27 @@ static void genpd_sync_power_off(struct generic_pm_domain *genpd, list_for_each_entry(link, &genpd->slave_links, slave_node) { genpd_sd_counter_dec(link->master); - genpd_lock_nested(link->master, depth + 1); - genpd_sync_power_off(link->master, depth + 1); - genpd_unlock(link->master); + if (use_lock) + genpd_lock_nested(link->master, depth + 1); + + genpd_sync_power_off(link->master, use_lock, depth + 1); + + if (use_lock) + genpd_unlock(link->master); } } /** * genpd_sync_power_on - Synchronously power on a PM domain and its masters. * @genpd: PM domain to power on. + * @use_lock: use the lock. * @depth: nesting count for lockdep. * * This function is only called in "noirq" and "syscore" stages of system power - * transitions, but since the "noirq" callbacks may be executed asynchronously, - * the lock must be held. + * transitions. The "noirq" callbacks may be executed asynchronously, thus in + * these cases the lock must be held. */ -static void genpd_sync_power_on(struct generic_pm_domain *genpd, +static void genpd_sync_power_on(struct generic_pm_domain *genpd, bool use_lock, unsigned int depth) { struct gpd_link *link; @@ -785,9 +791,13 @@ static void genpd_sync_power_on(struct generic_pm_domain *genpd, list_for_each_entry(link, &genpd->slave_links, slave_node) { genpd_sd_counter_inc(link->master); - genpd_lock_nested(link->master, depth + 1); - genpd_sync_power_on(link->master, depth + 1); - genpd_unlock(link->master); + if (use_lock) + genpd_lock_nested(link->master, depth + 1); + + genpd_sync_power_on(link->master, use_lock, depth + 1); + + if (use_lock) + genpd_unlock(link->master); } _genpd_power_on(genpd, false); @@ -898,7 +908,7 @@ static int pm_genpd_suspend_noirq(struct device *dev) genpd_lock(genpd); genpd->suspended_count++; - genpd_sync_power_off(genpd, 0); + genpd_sync_power_off(genpd, true, 0); genpd_unlock(genpd); return 0; @@ -925,7 +935,7 @@ static int pm_genpd_resume_noirq(struct device *dev) return 0; genpd_lock(genpd); - genpd_sync_power_on(genpd, 0); + genpd_sync_power_on(genpd, true, 0); genpd->suspended_count--; genpd_unlock(genpd); @@ -1016,7 +1026,7 @@ static int pm_genpd_restore_noirq(struct device *dev) */ genpd->status = GPD_STATE_POWER_OFF; - genpd_sync_power_on(genpd, 0); + genpd_sync_power_on(genpd, true, 0); genpd_unlock(genpd); if (genpd->dev_ops.stop && genpd->dev_ops.start) @@ -1070,17 +1080,13 @@ static void genpd_syscore_switch(struct device *dev, bool suspend) if (!pm_genpd_present(genpd)) return; - genpd_lock(genpd); - if (suspend) { genpd->suspended_count++; - genpd_sync_power_off(genpd, 0); + genpd_sync_power_off(genpd, false, 0); } else { - genpd_sync_power_on(genpd, 0); + genpd_sync_power_on(genpd, false, 0); genpd->suspended_count--; } - - genpd_unlock(genpd); } void pm_genpd_syscore_poweroff(struct device *dev)