Message ID | 20230111043614.27087-2-marcan@marcan.st |
---|---|
State | New |
Headers |
Return-Path: <linux-kernel-owner@vger.kernel.org> Delivered-To: ouuuleilei@gmail.com Received: by 2002:a5d:4e01:0:0:0:0:0 with SMTP id p1csp3124893wrt; Tue, 10 Jan 2023 20:39:26 -0800 (PST) X-Google-Smtp-Source: AMrXdXsFCx78gQcMV8b3ru0MuQA09EgdGof8AqOrz1slE4f56ImZLgO9pmgkWm1gFuwkOYcdnhfn X-Received: by 2002:a17:906:b7ce:b0:84d:411d:64a4 with SMTP id fy14-20020a170906b7ce00b0084d411d64a4mr9327269ejb.38.1673411965995; Tue, 10 Jan 2023 20:39:25 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1673411965; cv=none; d=google.com; s=arc-20160816; b=xQLjFd8R1gyU7XHutzjSD4O7dhdFbNeQBUIYRrCL+ikYjm2rxoFoigr6NR2iYRN2Rg XNDzfGqTiB53oPI6qwJ8nCjynefjF8P1ihO+imPOrFOXhw82qNbEwSK915JYzLjE+EUD 83kQZ/4WszbUETZ524N5QdApNXo2xDblws4SS9vZuHpu6K3aLlKDyPr7RImg0iGazGFG 6+N6jLvVTHkw1lo258PFGaa/R9Il1crtU8Mhr90yIXw3bjjjm4R0gjrjayTGn2cLh3oq UDiRGPMKAobNSceTW9CEXTOrzbkuwP+gLiApaIgWnc50yl4Ur8dBy7V2VDLiTDxe6Cy8 7HRg== 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 :dkim-signature; bh=DrGnilphed++uUZkhm3rd0G2c4sVV31GlOelQ1DnBls=; b=QgNG+Y/EcYi9enYlMz89CF8wEPamCN7nG31pxSw51AOe6Si/7xlF/bHUQlaiaTvVGV cA1V6KHUI3r6A/XbrJ7Mg6OLAdZjsV/VMKArM1uAoYTya/tzFo23YUfcFUBtzRXvH4VR IqqR4g7PlCLK0rXmIFLTxJ0ChTd6duLGM2oqyQZzJ8KVltENe0QmrWsNDs6NMdcSYeYT 5Qcb5IoA9gyaVh2zZk3ZhLmzs5RyjI8QN5H6LsmDBSHRgrc0ian+H00Hci99fTHpN9Pv +TU1j6L44RAtAqJBfWK6Zcql0ZzgFZ7FyGh0LH5rq7/sAOvpSchU2cXrz3G5DGKWPkT9 k2IQ== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@marcan.st header.s=default header.b=QY5tqf60; 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=QUARANTINE sp=QUARANTINE dis=NONE) header.from=marcan.st Received: from out1.vger.email (out1.vger.email. [2620:137:e000::1:20]) by mx.google.com with ESMTP id xe6-20020a170907318600b00780488c11bbsi13998879ejb.388.2023.01.10.20.39.03; Tue, 10 Jan 2023 20:39:25 -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=@marcan.st header.s=default header.b=QY5tqf60; 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=QUARANTINE sp=QUARANTINE dis=NONE) header.from=marcan.st Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S230015AbjAKEis (ORCPT <rfc822;syz17693488234@gmail.com> + 99 others); Tue, 10 Jan 2023 23:38:48 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:39936 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S231465AbjAKEi3 (ORCPT <rfc822;linux-kernel@vger.kernel.org>); Tue, 10 Jan 2023 23:38:29 -0500 Received: from mail.marcansoft.com (marcansoft.com [212.63.210.85]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 83F78643B for <linux-kernel@vger.kernel.org>; Tue, 10 Jan 2023 20:38:28 -0800 (PST) Received: from [127.0.0.1] (localhost [127.0.0.1]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (No client certificate requested) (Authenticated sender: sendonly@marcansoft.com) by mail.marcansoft.com (Postfix) with ESMTPSA id A9EC6422CC; Wed, 11 Jan 2023 04:38:23 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=marcan.st; s=default; t=1673411907; bh=Q3CUKLEywf+vR4+nGROpaJQqVS2PQmhEl5Il4+LejRo=; h=From:To:Cc:Subject:Date:In-Reply-To:References; b=QY5tqf60SZHxFaNdFYSzNvp4IdFLjD4OU8BawnpwU74nj7igN5fSFDF1+fcojF39A sOVlpJT9RhW6yM4BHm02nodGm1dFnVtmoqCnFikp1F9d/8cT3SuUqKczh83l09wMoo Zz+ydkC/lTC43zhbi3SjksPhqde146WnH3Ge1L59zI7Cg8TeHT4GQTiqLfm70xYxh7 LVdvZPRhSF4FctliGqXRgKXSjYPgtSRKMkB+ouZ2NiQ/4azKsNZx88fxEu31eKkYae js5/uMv+MwTL1AyrKdtdx76z3wHbPDiWP65rW7ZcORH+fhFmpmvHqNkiBHju5CgmAS FS6P8dLLiUcuA== From: Hector Martin <marcan@marcan.st> To: Keith Busch <kbusch@kernel.org>, Jens Axboe <axboe@fb.com>, Christoph Hellwig <hch@lst.de>, Sagi Grimberg <sagi@grimberg.me> Cc: Eric Curtin <ecurtin@redhat.com>, Janne Grunau <j@jannau.net>, Sven Peter <sven@svenpeter.dev>, Alyssa Rosenzweig <alyssa@rosenzweig.io>, asahi@lists.linux.dev, linux-arm-kernel@lists.infradead.org, linux-nvme@lists.infradead.org, linux-kernel@vger.kernel.org, Hector Martin <marcan@marcan.st> Subject: [PATCH 1/2] nvme-apple: Do not try to shut down the controller twice Date: Wed, 11 Jan 2023 13:36:13 +0900 Message-Id: <20230111043614.27087-2-marcan@marcan.st> X-Mailer: git-send-email 2.35.1 In-Reply-To: <20230111043614.27087-1-marcan@marcan.st> References: <20230111043614.27087-1-marcan@marcan.st> MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Spam-Status: No, score=-2.1 required=5.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,SPF_HELO_NONE,SPF_PASS 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: <linux-kernel.vger.kernel.org> X-Mailing-List: linux-kernel@vger.kernel.org X-getmail-retrieved-from-mailbox: =?utf-8?q?INBOX?= X-GMAIL-THRID: =?utf-8?q?1754699626000484204?= X-GMAIL-MSGID: =?utf-8?q?1754699626000484204?= |
Series |
nvme-apple: Fix suspend-resume regression
|
|
Commit Message
Hector Martin
Jan. 11, 2023, 4:36 a.m. UTC
The blamed commit stopped explicitly disabling the controller when we do
a controlled shutdown, but apple_nvme_reset_work was only checking for
the disable bit before deciding to issue another disable. Check for the
shutdown state too, to avoid breakage.
This issue does not affect nvme-pci, since it only issues controller
shutdowns when the system is actually shutting down anyway.
Fixes: c76b8308e4c9 ("nvme-apple: fix controller shutdown in apple_nvme_disable")
Signed-off-by: Hector Martin <marcan@marcan.st>
---
drivers/nvme/host/apple.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
Comments
On Wed, Jan 11, 2023 at 01:36:13PM +0900, Hector Martin wrote: > The blamed commit stopped explicitly disabling the controller when we do > a controlled shutdown, but apple_nvme_reset_work was only checking for > the disable bit before deciding to issue another disable. Check for the > shutdown state too, to avoid breakage. > > This issue does not affect nvme-pci, since it only issues controller > shutdowns when the system is actually shutting down anyway. There's a few other places where nvme-pci does a shutdown like probe/reset failure and most notably and mostly notably various power management scenarios. What path is causing a problem here for nvme-apple? I fear we're missing some highler level check here and getting further out of sync.
On 11/01/2023 13.54, Christoph Hellwig wrote: > On Wed, Jan 11, 2023 at 01:36:13PM +0900, Hector Martin wrote: >> The blamed commit stopped explicitly disabling the controller when we do >> a controlled shutdown, but apple_nvme_reset_work was only checking for >> the disable bit before deciding to issue another disable. Check for the >> shutdown state too, to avoid breakage. >> >> This issue does not affect nvme-pci, since it only issues controller >> shutdowns when the system is actually shutting down anyway. > > There's a few other places where nvme-pci does a shutdown like > probe/reset failure and most notably and mostly notably various > power management scenarios. > > What path is causing a problem here for nvme-apple? I fear we're > missing some highler level check here and getting further out of > sync. > OK, so the first question is who is responsible for resetting the controller after a shutdown? The spec requires a reset in order to bring it back up from that state. Indeed the PCIe code does an explicit disable right now (though, judging by the comment, it probably wasn't done with the intent of resetting after a shutdown, it just happens to work for that too :)) Right now, apple_nvme_reset_work() tries to check for the condition of an enabled controller (under the assumption that it's coming from a live controller, not considering shutdown/sleep) and issue an apple_nvme_disable(). However, this doesn't work when resuming because at that point the firmware coprocessor is shut down, so the device isn't usable (can't even get a disable command to complete properly). Perhaps a better conditional here would be to check for apple_rtkit_is_running(), since apple_nvme_disable() can't work otherwise. But then, even if we get past that, once apple_nvme_reset_work actually resets the firmware CPU and kicks things back online, the controller is still logically in the shutdown state. So something has to disable it in order for nvme_enable_ctrl() to work. An alternate patch would be to change the gate for apple_nvme_disable() in apple_nvme_reset_work() to check for apple_rtkit_is_running() on top of the controller enable state, and then add a further direct call to nvme_disable_ctrl(..., false) later in apple_nvme_reset_work, once the firmware is back up, to ensure we can enable it after. Thoughts? Alternatively, we could just revert to the prior behavior of always issuing a disable after a shutdown. We need to disable at some point to come back anyway, so it might as well be done early (before we shut down firmware, so it works). - Hector
On Wed, Jan 11, 2023 at 02:10:42PM +0900, Hector Martin wrote: > OK, so the first question is who is responsible for resetting the > controller after a shutdown? The spec requires a reset in order to bring > it back up from that state. Indeed the PCIe code does an explicit > disable right now (though, judging by the comment, it probably wasn't > done with the intent of resetting after a shutdown, it just happens to > work for that too :)) We need to do the reset before banging the registers to make sure the controller is in a sane state before starting to set it up. > Right now, apple_nvme_reset_work() tries to check for the condition of > an enabled controller (under the assumption that it's coming from a live > controller, not considering shutdown/sleep) and issue an > apple_nvme_disable(). However, this doesn't work when resuming because > at that point the firmware coprocessor is shut down, so the device isn't > usable (can't even get a disable command to complete properly). Perhaps > a better conditional here would be to check for > apple_rtkit_is_running(), since apple_nvme_disable() can't work otherwise. So on a resume the controller should have previously been shutdown properly, and this shouldn't be an issue. Does the apple implementation leave some weird state after a shut down? In that case the resume callback might want to do an explicit controller disable before doing the reset. > Alternatively, we could just revert to the prior behavior of always > issuing a disable after a shutdown. We need to disable at some point to > come back anyway, so it might as well be done early (before we shut down > firmware, so it works). So the disable before shutdown doesn't really make sense from the NVMe POV - the shutdown is to cleanly bring the device into a state where it can quickly recover. While a disable is an abprupt shutdown, which can have effects on recover time, and might also use way more P/E cycles than nessecary. So if you always want to do a disable, it should be after shutdown, and in doubt in the resume / setup path instead of the remove / suspend one.
On 11/01/2023 14.18, Christoph Hellwig wrote: > On Wed, Jan 11, 2023 at 02:10:42PM +0900, Hector Martin wrote: >> OK, so the first question is who is responsible for resetting the >> controller after a shutdown? The spec requires a reset in order to bring >> it back up from that state. Indeed the PCIe code does an explicit >> disable right now (though, judging by the comment, it probably wasn't >> done with the intent of resetting after a shutdown, it just happens to >> work for that too :)) > > We need to do the reset before banging the registers to make sure > the controller is in a sane state before starting to set it up. > >> Right now, apple_nvme_reset_work() tries to check for the condition of >> an enabled controller (under the assumption that it's coming from a live >> controller, not considering shutdown/sleep) and issue an >> apple_nvme_disable(). However, this doesn't work when resuming because >> at that point the firmware coprocessor is shut down, so the device isn't >> usable (can't even get a disable command to complete properly). Perhaps >> a better conditional here would be to check for >> apple_rtkit_is_running(), since apple_nvme_disable() can't work otherwise. > > So on a resume the controller should have previously been shutdown > properly, and this shouldn't be an issue. Does the apple implementation > leave some weird state after a shut down? In that case the resume > callback might want to do an explicit controller disable before doing > the reset. The controller is *shut down* but it's not *disabled*, and the existing code was only checking whether the controller is enabled to decide to issue another disable. The higher-level resume path can't do a disable since the firmware isn't up at that point, and the subsequent reset (which is shared with other conditions that cause a reset) is what brings the firmware back up. So the disable has to either happen in the suspend path, or in the shared reset path after we know the firmware is running. A shutdown but enabled controller is in "limbo"; the only way to know it's nonfunctional is explicitly checking the shutdown status bits. Other than that, it looks like a live controller that plays dead. This is documented in the spec as such. >> Alternatively, we could just revert to the prior behavior of always >> issuing a disable after a shutdown. We need to disable at some point to >> come back anyway, so it might as well be done early (before we shut down >> firmware, so it works). > > So the disable before shutdown doesn't really make sense from the > NVMe POV - the shutdown is to cleanly bring the device into a state > where it can quickly recover. While a disable is an abprupt shutdown, > which can have effects on recover time, and might also use way more > P/E cycles than nessecary. That's only if you issue a disable *in lieu* of a shutdown (and in fact if you do that on Apple controllers under some conditions, they crash). Issuing a disable *after* a shutdown is required by the NVMe spec if you want to use the controller again (and should basically do nothing at that point, since the controller is already cleanly shut down, but it is required to set EN to 0 such that the subsequent 0->1 transition actually kickstarts the controller again). If you don't do that, the controller never leaves the shutdown state (how would it know?). To be clear, the sequence I was attempting to describe (which is what we were doing before the patch that regressed this) was: (on sleep) - NVMe shutdown - NVMe disable - Firmware shutdown After the firmware shutdown, we can't do anything with NVMe again until we start firmware back up, which requires going through the reset flow. Right now we're doing: (on sleep) - NVMe shutdown - Firmware shutdown (wakeup) - Oops, NVMe is enabled, let's disable it! (times out due to FW being down but failure isn't propagated) - Firmware startup - NVMe enable (thinks it succeeds but actually the controller is still in the shutdown state since it was never disabled and this persists across the firmware cycle!) - I/O (never completes) - Hector
On Wed, Jan 11, 2023 at 02:44:42PM +0900, Hector Martin wrote: > The higher-level resume path can't do a disable since the firmware isn't > up at that point, and the subsequent reset (which is shared with other > conditions that cause a reset) is what brings the firmware back up. So > the disable has to either happen in the suspend path, or in the shared > reset path after we know the firmware is running. Ok, that's the weird part where nvme-apply really isn't nvme at all. Because for actual NVMe devices the register access must work all the time. > That's only if you issue a disable *in lieu* of a shutdown (and in fact > if you do that on Apple controllers under some conditions, they crash). > Issuing a disable *after* a shutdown is required by the NVMe spec if you > want to use the controller again (and should basically do nothing at > that point, since the controller is already cleanly shut down, but it is > required to set EN to 0 such that the subsequent 0->1 transition > actually kickstarts the controller again). If you don't do that, the > controller never leaves the shutdown state (how would it know?). Yes. Although I would not call this a disable after shutdown, but a disable (or rather reset) before using it again. > To be clear, the sequence I was attempting to describe (which is what we > were doing before the patch that regressed this) was: > > (on sleep) > - NVMe shutdown > - NVMe disable > - Firmware shutdown > > After the firmware shutdown, we can't do anything with NVMe again until > we start firmware back up, which requires going through the reset flow. > > Right now we're doing: > > (on sleep) > - NVMe shutdown > - Firmware shutdown > (wakeup) > - Oops, NVMe is enabled, let's disable it! (times out due to FW being > down but failure isn't propagated) > - Firmware startup > - NVMe enable (thinks it succeeds but actually the controller is still > in the shutdown state since it was never disabled and this persists > across the firmware cycle!) > - I/O (never completes) Yes, so I guess due to the weird firmware issues doing the disable after shutdown instead of before setting up might be the right thing for nvme-apple, unlike real NVMe. So I guess we need to do that in the driver, and add a big fat comment explaining why.
diff --git a/drivers/nvme/host/apple.c b/drivers/nvme/host/apple.c index e13a992b6096..1961376447dc 100644 --- a/drivers/nvme/host/apple.c +++ b/drivers/nvme/host/apple.c @@ -1023,7 +1023,8 @@ static void apple_nvme_reset_work(struct work_struct *work) goto out; } - if (anv->ctrl.ctrl_config & NVME_CC_ENABLE) + if (anv->ctrl.ctrl_config & NVME_CC_ENABLE && + !(anv->ctrl.ctrl_config & NVME_CC_SHN_MASK)) apple_nvme_disable(anv, false); /* RTKit must be shut down cleanly for the (soft)-reset to work */