Received: by 2002:a05:6a10:c604:0:0:0:0 with SMTP id y4csp16176pxt; Wed, 11 Aug 2021 13:20:15 -0700 (PDT) X-Google-Smtp-Source: ABdhPJyet0zhcdlK2kkR8kHvbAUt3/KqdTY/pEkipFw6sZbwDN9MX2yFNxoYAhcCqvbDqiXVUuLY X-Received: by 2002:a17:907:16a1:: with SMTP id hc33mr293778ejc.536.1628713215190; Wed, 11 Aug 2021 13:20:15 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1628713215; cv=none; d=google.com; s=arc-20160816; b=Ou7rw7koR421Gxm4Z6ICwXXSE11s/9UyJ9xk3v0l8E5QKMIv27eu4tzST7xT7jlweE IlFQew1KF8mSZ+feyyBQHpNMRFMJEmcHC+F/MidrmSSLqObGwX50U8kAW22OzOYjCnNp 0fm4rPuDuA1R/wlJEVkT1rYRdKSVyGwe0T5EkgFo5bPF9gzr4Cor72HmYKb8ToJ36ejg W5YIdqGIbsidx0ls9Wlb9cQLijKRBvOejKeAEoTWA8A/qDovly29B+Ts772EGFfDY7vL hb1B9wELIg2osdnTj09XRiraOzYNWDUY4Mcexhvuv5ICKwuU1wzHXwwLWlZptEPqD+Os Wq8Q== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:content-transfer-encoding:mime-version :references:in-reply-to:message-id:date:subject:cc:to:from; bh=RTf4FpchmeCDcPwQguplSHgcVRtNuXysDIqocRANe54=; b=hX/wBrcAyp7G1QGmivqQBBiMUleeYGe5mxvidN51r45fpAs5HuG/K5rL40Ev7onPkT u3FV0rzaErSbkew8kESmJv007Re5M2tlOAMhM6l5WCridO6xTBZMtunegLKuSDR0Gl9n SwO1xHZHHyolwKPet1TiyUX1mAZVxgKs8kAinAz/FESF5JcJmHLLZ0hEx0kNMSjP3UK5 ykz8VloJOQbXg00l2vqEyCI7IiV4ee9Evt92eGQ417aw4eNNZnA5Mb0GzMrJoBbRYiW1 8HvcD34+GVAlCP+cpV61+HnUVp+VFFWfcedwWvia8CzdZjbJuGF5OyGz6EEcMaYnQhXe sqRw== ARC-Authentication-Results: i=1; mx.google.com; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.18 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=arm.com Return-Path: Received: from vger.kernel.org (vger.kernel.org. [23.128.96.18]) by mx.google.com with ESMTP id e9si385203edz.204.2021.08.11.13.19.49; Wed, 11 Aug 2021 13:20:15 -0700 (PDT) Received-SPF: pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.18 as permitted sender) client-ip=23.128.96.18; Authentication-Results: mx.google.com; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.18 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=arm.com Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S232176AbhHKUPJ (ORCPT + 99 others); Wed, 11 Aug 2021 16:15:09 -0400 Received: from foss.arm.com ([217.140.110.172]:57866 "EHLO foss.arm.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S231948AbhHKUPI (ORCPT ); Wed, 11 Aug 2021 16:15:08 -0400 Received: from usa-sjc-imap-foss1.foss.arm.com (unknown [10.121.207.14]) by usa-sjc-mx-foss1.foss.arm.com (Postfix) with ESMTP id AFBA5D6E; Wed, 11 Aug 2021 13:14:43 -0700 (PDT) Received: from e113632-lin.cambridge.arm.com (e113632-lin.cambridge.arm.com [10.1.194.46]) by usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPA id 5FD2B3F40C; Wed, 11 Aug 2021 13:14:42 -0700 (PDT) From: Valentin Schneider To: linux-kernel@vger.kernel.org, linux-rt-users@vger.kernel.org, linux-pm@vger.kernel.org Cc: Thomas Gleixner , Peter Zijlstra , Sebastian Andrzej Siewior , Daniel Bristot de Oliveira , Ingo Molnar , "Rafael J. Wysocki" Subject: [PATCH v3 1/2] cpu_pm: Make notifier chain use a raw_spinlock_t Date: Wed, 11 Aug 2021 21:14:31 +0100 Message-Id: <20210811201432.1976916-2-valentin.schneider@arm.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20210811201432.1976916-1-valentin.schneider@arm.com> References: <20210811201432.1976916-1-valentin.schneider@arm.com> MIME-Version: 1.0 Content-Transfer-Encoding: 8bit Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Invoking atomic_notifier_chain_notify() requires acquiring a spinlock_t, which can block under CONFIG_PREEMPT_RT. Notifications for members of the cpu_pm notification chain will be issued by the idle task, which can never block. Making *all* atomic_notifiers use a raw_spinlock is too big of a hammer, as only notifications issued by the idle task are problematic. Special-case cpu_pm_notifier_chain by kludging a raw_notifier and raw_spinlock_t together, matching the atomic_notifier behavior with a raw_spinlock_t. Fixes: 70d932985757 ("notifier: Fix broken error handling pattern") Signed-off-by: Valentin Schneider --- kernel/cpu_pm.c | 50 +++++++++++++++++++++++++++++++++++++------------ 1 file changed, 38 insertions(+), 12 deletions(-) diff --git a/kernel/cpu_pm.c b/kernel/cpu_pm.c index f7e1d0eccdbc..246efc74e3f3 100644 --- a/kernel/cpu_pm.c +++ b/kernel/cpu_pm.c @@ -13,19 +13,32 @@ #include #include -static ATOMIC_NOTIFIER_HEAD(cpu_pm_notifier_chain); +/* + * atomic_notifiers use a spinlock_t, which can block under PREEMPT_RT. + * Notifications for cpu_pm will be issued by the idle task itself, which can + * never block, IOW it requires using a raw_spinlock_t. + */ +static struct { + struct raw_notifier_head chain; + raw_spinlock_t lock; +} cpu_pm_notifier = { + .chain = RAW_NOTIFIER_INIT(cpu_pm_notifier.chain), + .lock = __RAW_SPIN_LOCK_UNLOCKED(cpu_pm_notifier.lock), +}; static int cpu_pm_notify(enum cpu_pm_event event) { int ret; /* - * atomic_notifier_call_chain has a RCU read critical section, which - * could be disfunctional in cpu idle. Copy RCU_NONIDLE code to let - * RCU know this. + * This introduces a RCU read critical section, which could be + * disfunctional in cpu idle. Copy RCU_NONIDLE code to let RCU know + * this. */ rcu_irq_enter_irqson(); - ret = atomic_notifier_call_chain(&cpu_pm_notifier_chain, event, NULL); + rcu_read_lock(); + ret = raw_notifier_call_chain(&cpu_pm_notifier.chain, event, NULL); + rcu_read_unlock(); rcu_irq_exit_irqson(); return notifier_to_errno(ret); @@ -33,10 +46,13 @@ static int cpu_pm_notify(enum cpu_pm_event event) static int cpu_pm_notify_robust(enum cpu_pm_event event_up, enum cpu_pm_event event_down) { + unsigned long flags; int ret; rcu_irq_enter_irqson(); - ret = atomic_notifier_call_chain_robust(&cpu_pm_notifier_chain, event_up, event_down, NULL); + raw_spin_lock_irqsave(&cpu_pm_notifier.lock, flags); + ret = raw_notifier_call_chain_robust(&cpu_pm_notifier.chain, event_up, event_down, NULL); + raw_spin_unlock_irqrestore(&cpu_pm_notifier.lock, flags); rcu_irq_exit_irqson(); return notifier_to_errno(ret); @@ -49,12 +65,17 @@ static int cpu_pm_notify_robust(enum cpu_pm_event event_up, enum cpu_pm_event ev * Add a driver to a list of drivers that are notified about * CPU and CPU cluster low power entry and exit. * - * This function may sleep, and has the same return conditions as - * raw_notifier_chain_register. + * This function has the same return conditions as raw_notifier_chain_register. */ int cpu_pm_register_notifier(struct notifier_block *nb) { - return atomic_notifier_chain_register(&cpu_pm_notifier_chain, nb); + unsigned long flags; + int ret; + + raw_spin_lock_irqsave(&cpu_pm_notifier.lock, flags); + ret = raw_notifier_chain_register(&cpu_pm_notifier.chain, nb); + raw_spin_unlock_irqrestore(&cpu_pm_notifier.lock, flags); + return ret; } EXPORT_SYMBOL_GPL(cpu_pm_register_notifier); @@ -64,12 +85,17 @@ EXPORT_SYMBOL_GPL(cpu_pm_register_notifier); * * Remove a driver from the CPU PM notifier list. * - * This function may sleep, and has the same return conditions as - * raw_notifier_chain_unregister. + * This function has the same return conditions as raw_notifier_chain_unregister. */ int cpu_pm_unregister_notifier(struct notifier_block *nb) { - return atomic_notifier_chain_unregister(&cpu_pm_notifier_chain, nb); + unsigned long flags; + int ret; + + raw_spin_lock_irqsave(&cpu_pm_notifier.lock, flags); + ret = raw_notifier_chain_unregister(&cpu_pm_notifier.chain, nb); + raw_spin_unlock_irqrestore(&cpu_pm_notifier.lock, flags); + return ret; } EXPORT_SYMBOL_GPL(cpu_pm_unregister_notifier); -- 2.25.1