Received: by 2002:a05:6a10:7420:0:0:0:0 with SMTP id hk32csp3945205pxb; Mon, 21 Feb 2022 08:50:03 -0800 (PST) X-Google-Smtp-Source: ABdhPJwZYDzEL4S8yI+78UgTED6whAkoNdCx4O2jyiYe4waYbrXe1lW3/OCi4coI3/B5VpLUrNRL X-Received: by 2002:a17:907:8688:b0:6d2:c19:e1a0 with SMTP id qa8-20020a170907868800b006d20c19e1a0mr617502ejc.249.1645462202871; Mon, 21 Feb 2022 08:50:02 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1645462202; cv=none; d=google.com; s=arc-20160816; b=CeHVoZRfi8eolXm1AnzZnUqZAKFLlxSW6vDqS2FXdBM+I+4adcLpil4Dq9BGegf9Xk Hv5A9DyzxBH1JehbUGvpTgu1kB5EhG1TS3CdOBwrwnu9hugVWdqKMf1NkQItW7406ec5 ElWemrksu8vS/b/TBgZ4UqQbxu7OsdR78jo/Pm9mR7o/SJt+vIggvW9E9ujQtcX4phUF x4uqLCAveFYzFYsBWTh+JwSj2BH1B5gLBpdExOEHNSCtZDudvnr7epsLIEwlEDuHpTt0 DXVtIkf5T/29LncIhiKuDsWZQeAwlkndgXTe6pK4UXV7o3nBDe9kAbD3BrjCj+ERUnL8 8ndQ== 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 :user-agent:references:in-reply-to:message-id:date:subject:cc:to :from:dkim-signature; bh=ZKFP9CBp4/sjz2m10DAuTR3yYvy06OI38zrOlOvpbRo=; b=BwAyQBfIYWem0vkBe0dO5FnHTAAjB4lV7SxPTMUUg7N9Z3HqNo/jqawYOgKaOapnz+ rVKo87z+u+GVGTHGb0PKmuE7+SNVcHm4ltgwo6iH1asT2X4gG7QLKpG7bGAAqf66UAgD ZLs+W47czJuZTdtQxw3b/FbtS/OEuqCWHVuJL8YMiyF0pYjbgTHt29fDNnldFgYWy34H ItYyoBZaFAckG+CojwQCIIRsML9azJoNDKbIdzwsUafbWGPDepjlxvciBozNeJ53oy7M iqnjsPbkmpxjIw1YNlMq7gxk+l7Q5wKlq93Com9PWHa6FD10OrHjCrh9q+fDTtMAV0yy MKfg== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@linuxfoundation.org header.s=korg header.b=HWaTeu9f; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=linuxfoundation.org Return-Path: Received: from out1.vger.email (out1.vger.email. [2620:137:e000::1:20]) by mx.google.com with ESMTP id l7si6754775edb.211.2022.02.21.08.49.40; Mon, 21 Feb 2022 08:50:02 -0800 (PST) Received-SPF: pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) client-ip=2620:137:e000::1:20; Authentication-Results: mx.google.com; dkim=pass header.i=@linuxfoundation.org header.s=korg header.b=HWaTeu9f; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=linuxfoundation.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1352414AbiBUJr0 (ORCPT + 99 others); Mon, 21 Feb 2022 04:47:26 -0500 Received: from mxb-00190b01.gslb.pphosted.com ([23.128.96.19]:48728 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1350639AbiBUJkR (ORCPT ); Mon, 21 Feb 2022 04:40:17 -0500 Received: from dfw.source.kernel.org (dfw.source.kernel.org [139.178.84.217]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 528EC3C49C; Mon, 21 Feb 2022 01:17:22 -0800 (PST) Received: from smtp.kernel.org (relay.kernel.org [52.25.139.140]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by dfw.source.kernel.org (Postfix) with ESMTPS id 68D3560C1D; Mon, 21 Feb 2022 09:17:13 +0000 (UTC) Received: by smtp.kernel.org (Postfix) with ESMTPSA id 4F546C340E9; Mon, 21 Feb 2022 09:17:12 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=linuxfoundation.org; s=korg; t=1645435032; bh=vHXmZrYjVOaObrg4ML6zdoLWrXLbnePNNkLvDDJKdQg=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=HWaTeu9fFGbsMbYtau9Fa3n7srtjUkit5TZnxW6+lFeyb5v6W0VRhOD35IgRc5XqP 5vVI/tyhHlPHmp3+S8bCE6TGie+nClBYYQHy7zTkZYngK68074BUB8pgI4IK/YG59l Un1GfZ0AN8QDeTX/Agozjry+c09+WLysMI7yGSwg= From: Greg Kroah-Hartman To: linux-kernel@vger.kernel.org Cc: Greg Kroah-Hartman , stable@vger.kernel.org, Daniel Thompson , Douglas Anderson , Jiri Kosina Subject: [PATCH 5.16 021/227] HID: i2c-hid: goodix: Fix a lockdep splat Date: Mon, 21 Feb 2022 09:47:20 +0100 Message-Id: <20220221084935.549461287@linuxfoundation.org> X-Mailer: git-send-email 2.35.1 In-Reply-To: <20220221084934.836145070@linuxfoundation.org> References: <20220221084934.836145070@linuxfoundation.org> User-Agent: quilt/0.66 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-Spam-Status: No, score=-7.1 required=5.0 tests=BAYES_00,DKIMWL_WL_HIGH, DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,RCVD_IN_DNSWL_HI, SPF_HELO_NONE,SPF_PASS,T_SCC_BODY_TEXT_LINE autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on lindbergh.monkeyblade.net Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org From: Daniel Thompson commit 2787710f73fcce4a9bdab540aaf1aef778a27462 upstream. I'm was on the receiving end of a lockdep splat from this driver and after scratching my head I couldn't be entirely sure it was a false positive given we would also have to think about whether the regulator locking is safe (since the notifier is called whilst holding regulator locks which are also needed for regulator_is_enabled() ). Regardless of whether it is a real bug or not, the mutex isn't needed. We can use reference counting tricks instead to avoid races with the notifier calls. The observed splat follows: ------------------------------------------------------ kworker/u16:3/127 is trying to acquire lock: ffff00008021fb20 (&ihid_goodix->regulator_mutex){+.+.}-{4:4}, at: ihid_goodix_vdd_notify+0x30/0x94 but task is already holding lock: ffff0000835c60c0 (&(&rdev->notifier)->rwsem){++++}-{4:4}, at: blocking_notifier_call_chain+0x30/0x70 which lock already depends on the new lock. the existing dependency chain (in reverse order) is: -> #1 (&(&rdev->notifier)->rwsem){++++}-{4:4}: down_write+0x68/0x8c blocking_notifier_chain_register+0x54/0x70 regulator_register_notifier+0x1c/0x24 devm_regulator_register_notifier+0x58/0x98 i2c_hid_of_goodix_probe+0xdc/0x158 i2c_device_probe+0x25d/0x270 really_probe+0x174/0x2cc __driver_probe_device+0xc0/0xd8 driver_probe_device+0x50/0xe4 __device_attach_driver+0xa8/0xc0 bus_for_each_drv+0x9c/0xc0 __device_attach_async_helper+0x6c/0xbc async_run_entry_fn+0x38/0x100 process_one_work+0x294/0x438 worker_thread+0x180/0x258 kthread+0x120/0x130 ret_from_fork+0x10/0x20 -> #0 (&ihid_goodix->regulator_mutex){+.+.}-{4:4}: __lock_acquire+0xd24/0xfe8 lock_acquire+0x288/0x2f4 __mutex_lock+0xa0/0x338 mutex_lock_nested+0x3c/0x5c ihid_goodix_vdd_notify+0x30/0x94 notifier_call_chain+0x6c/0x8c blocking_notifier_call_chain+0x48/0x70 _notifier_call_chain.isra.0+0x18/0x20 _regulator_enable+0xc0/0x178 regulator_enable+0x40/0x7c goodix_i2c_hid_power_up+0x18/0x20 i2c_hid_core_power_up.isra.0+0x1c/0x2c i2c_hid_core_probe+0xd8/0x3d4 i2c_hid_of_goodix_probe+0x14c/0x158 i2c_device_probe+0x25c/0x270 really_probe+0x174/0x2cc __driver_probe_device+0xc0/0xd8 driver_probe_device+0x50/0xe4 __device_attach_driver+0xa8/0xc0 bus_for_each_drv+0x9c/0xc0 __device_attach_async_helper+0x6c/0xbc async_run_entry_fn+0x38/0x100 process_one_work+0x294/0x438 worker_thread+0x180/0x258 kthread+0x120/0x130 ret_from_fork+0x10/0x20 other info that might help us debug this: Possible unsafe locking scenario: CPU0 CPU1 ---- ---- lock(&(&rdev->notifier)->rwsem); lock(&ihid_goodix->regulator_mutex); lock(&(&rdev->notifier)->rwsem); lock(&ihid_goodix->regulator_mutex); *** DEADLOCK *** Signed-off-by: Daniel Thompson Fixes: 18eeef46d359 ("HID: i2c-hid: goodix: Tie the reset line to true state of the regulator") Reviewed-by: Douglas Anderson Signed-off-by: Jiri Kosina Signed-off-by: Greg Kroah-Hartman --- drivers/hid/i2c-hid/i2c-hid-of-goodix.c | 28 ++++++++++++---------------- 1 file changed, 12 insertions(+), 16 deletions(-) --- a/drivers/hid/i2c-hid/i2c-hid-of-goodix.c +++ b/drivers/hid/i2c-hid/i2c-hid-of-goodix.c @@ -27,7 +27,6 @@ struct i2c_hid_of_goodix { struct regulator *vdd; struct notifier_block nb; - struct mutex regulator_mutex; struct gpio_desc *reset_gpio; const struct goodix_i2c_hid_timing_data *timings; }; @@ -67,8 +66,6 @@ static int ihid_goodix_vdd_notify(struct container_of(nb, struct i2c_hid_of_goodix, nb); int ret = NOTIFY_OK; - mutex_lock(&ihid_goodix->regulator_mutex); - switch (event) { case REGULATOR_EVENT_PRE_DISABLE: gpiod_set_value_cansleep(ihid_goodix->reset_gpio, 1); @@ -87,8 +84,6 @@ static int ihid_goodix_vdd_notify(struct break; } - mutex_unlock(&ihid_goodix->regulator_mutex); - return ret; } @@ -102,8 +97,6 @@ static int i2c_hid_of_goodix_probe(struc if (!ihid_goodix) return -ENOMEM; - mutex_init(&ihid_goodix->regulator_mutex); - ihid_goodix->ops.power_up = goodix_i2c_hid_power_up; ihid_goodix->ops.power_down = goodix_i2c_hid_power_down; @@ -130,25 +123,28 @@ static int i2c_hid_of_goodix_probe(struc * long. Holding the controller in reset apparently draws extra * power. */ - mutex_lock(&ihid_goodix->regulator_mutex); ihid_goodix->nb.notifier_call = ihid_goodix_vdd_notify; ret = devm_regulator_register_notifier(ihid_goodix->vdd, &ihid_goodix->nb); - if (ret) { - mutex_unlock(&ihid_goodix->regulator_mutex); + if (ret) return dev_err_probe(&client->dev, ret, "regulator notifier request failed\n"); - } /* * If someone else is holding the regulator on (or the regulator is * an always-on one) we might never be told to deassert reset. Do it - * now. Here we'll assume that someone else might have _just - * barely_ turned the regulator on so we'll do the full - * "post_power_delay" just in case. + * now... and temporarily bump the regulator reference count just to + * make sure it is impossible for this to race with our own notifier! + * We also assume that someone else might have _just barely_ turned + * the regulator on so we'll do the full "post_power_delay" just in + * case. */ - if (ihid_goodix->reset_gpio && regulator_is_enabled(ihid_goodix->vdd)) + if (ihid_goodix->reset_gpio && regulator_is_enabled(ihid_goodix->vdd)) { + ret = regulator_enable(ihid_goodix->vdd); + if (ret) + return ret; goodix_i2c_hid_deassert_reset(ihid_goodix, true); - mutex_unlock(&ihid_goodix->regulator_mutex); + regulator_disable(ihid_goodix->vdd); + } return i2c_hid_core_probe(client, &ihid_goodix->ops, 0x0001, 0); }