From nobody Sat Sep 26 18:54:16 2026 Received: from mail-pl1-f169.google.com (mail-pl1-f169.google.com [209.85.214.169]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 6EA9230569B for ; Mon, 31 Aug 2026 13:03:46 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.214.169 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788181428; cv=none; b=Trln/4tLsVLh44ViJxA57Fycrrri6uXvVY+FWD3c776fjo1MJZeCgrTCZ4J/kGWlORMnl2e2yvS+AVfKMRRGU/btxYwDZ/c/zcFoa4yHSq4B7NpFbedr+6tyBWCfBvhSDWxtStsHOuZYUAyz3yuQDVY2GhiiPXzXFsqB4RPHSeQ= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788181428; c=relaxed/simple; bh=JtRrT10yzm9fRrctsX/tmvcSl2xfmZY5ICiRplDLZlM=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=QMfvGS+Dk7icw6K1mz7Gy/khS8MMMQZovqStAaYsVtbXfvi4zt0sMyiPq6+kf6tdUj1Njn8wjA0aPWj1PkBSlNlzM8T61HeRD9Dr5Ufnh7Fi2voF3qpqM3mesTo8QP2Qd4sJUjNtY0o0DqLpxoIRzBzFpkz0QB2LGNuaFE9Y1pg= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com; spf=pass smtp.mailfrom=gmail.com; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b=fgaAJ54Z; arc=none smtp.client-ip=209.85.214.169 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=gmail.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="fgaAJ54Z" Received: by mail-pl1-f169.google.com with SMTP id d9443c01a7336-2d590f4c291so10025665ad.0 for ; Mon, 31 Aug 2026 06:03:46 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1788181426; x=1788786226; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to:content-type; bh=GI4/mZK5VgpY291BuG3CaB2hCTJccyuWSOR/bez6Oyc=; b=fgaAJ54ZHiPW3n3jZ2H1zio3wiWl16E5Vasn1OvdyaXUI7bmpU5m75I80AmOfhbEp3 +tI4NP/JEFZYtID3j3aayU4BMEG1aZ99BtGB1JL9Rc3i8bcwxBeGVWKM4B2uvdsk1KQn GzSr90r/35At9b3gelvO8HGR73byY5uaVthYy4H9bwxCNuZzjThYtlvz9BVfd5iWeDQF hbPOT6ib6HxSKKh+K95yyDPcLPtRJ1ZkK3GZrxqU340vG4hAOr8yTXszfEpIuxWpSLHg 36lBsSHfoWfT/zQJCKtaJ1GqpTZZN0HugfE5ykKLqeW1X1N0BlOaf9VwjLl2KwmOkVrU Fhaw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1788181426; x=1788786226; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to:content-type; bh=GI4/mZK5VgpY291BuG3CaB2hCTJccyuWSOR/bez6Oyc=; b=g6MteosH3O5swuOFCGPKCcpWJ2SWXWitmAmiOPmSQ6s60mDscX9uSIXnovb+Y28gW1 iKOcsfybkETaYJTGGGYF4KOYpzBr6NZ5PinW13/TpYB6ve+LBI1AoT45n/hfoY45/5sl kXvEQSCfUIsc6yIs/GrLuLlwO1m7YtzMOp3KhqRA5zEHx2GqQkncc9Dk0UmM3uQhAkAY EI8v3FD8aZHjrYRvM2XevuFz6fnjSqKk4gGNZGBe+HsfgslwWCAIOJvr6f7zx20lVJ3F h3agHreboH41SrzIb/eO9zP3Q7wuY98ev/HUbKMSgq2z2UGDWj8Znk1Ht68N+6Qv9Oyo Jm5A== X-Forwarded-Encrypted: i=1; AKwUvByWZPAxBPM/tWODEHuD6PKrwSxJSqiEwQAuPW0KsyxZF/yYxXmPtpjIBnyj7JlfYDFfrjigRnmEqeqDLkc=@vger.kernel.org X-Gm-Message-State: AFuF++kzw3moge7HsavOAEI2rgvQwGoW5pLVTDgAQ2QMevKXK74n8kDs N7pumxeUx8aN4KYW3voXAQPvin3+O4KU05LxiEOH1g696ONouV3+DG8r X-Gm-Gg: AYBFou1MyW6jqXXxiyR/VW4FWLobvHXCOgcoHCdqmNhAMv2AwWcwtKyi286+S3eMwQL o17cvh3oTegw/AP+9y6tNgHbuUr52O17gaKPMdOiZ4wXFV/Czjw4Srbg4GiMDsyR6e3KFcdUyu+ pYLOEqByJ9YcodVEYWzM9pz5/N4SNZBwGk8JpRzEQZ+Ri98daBnnwJRroFPib0qBKJDUAyhH1+o zx7jwnbMmr6L14db2xVbDPZ9O9Vkykc+eWGGuS1zj2nY3pIfgRg/zJxMdU2IN6og+VlL8nxqVQp AowX8Ehd/NQCN37/9RHXoU+Qqv1VE3sK/nQYQcTHF971yaYMXwK6RNxDMEotECVLW8USpwL9Q0Z 7ajeipdYwCJMVTpi9bYNKyNIp54FDgFCciozuNJLbYxzquvIAVnnoiJJv4UtSjqi7siVAYOaz8M 5XEiqTD1tIAySc/fpzuaTW5bx8IZfEef5/lMlcc0bJXxBMqnEre1ufxmN2FlLGAip5uXf1a4ZUd 9V8mgBaBqecv+LIfZc/IrsjMXgC X-Received: by 2002:a17:903:1104:b0:2c9:8287:fd0d with SMTP id d9443c01a7336-2d74df62ccemr213174865ad.3.1788181425049; Mon, 31 Aug 2026 06:03:45 -0700 (PDT) Received: from cachyos-aura ([45.112.149.37]) by smtp.gmail.com with ESMTPSA id 5a478bee46e88-3286f7bf283sm32567749eec.8.2026.08.31.06.03.40 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 31 Aug 2026 06:03:44 -0700 (PDT) From: Navon John Lukose To: Miri Korenblit , linux-wireless@vger.kernel.org Cc: Johannes Berg , Emmanuel Grumbach , Nika Krasnova , Bjorn Helgaas , Mark Pearson , Mark Pearson , linux-pci@vger.kernel.org, linux-kernel@vger.kernel.org, stable@vger.kernel.org Subject: [PATCH wireless v2 1/3] wifi: iwlwifi: pcie: don't infer CSME presence from a failed read Date: Mon, 31 Aug 2026 18:33:30 +0530 Message-ID: <20260831130332.323549-2-navonjohnlukose@gmail.com> X-Mailer: git-send-email 2.55.0 In-Reply-To: <20260831130332.323549-1-navonjohnlukose@gmail.com> References: <20260831130332.323549-1-navonjohnlukose@gmail.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" iwl_pcie_check_me_status() decides whether WiAMT/CSME is present from two register reads, without checking that either read reached the device. iwl_read_prph() returns 0x5a5a5a5a when it cannot grab NIC access, and that value has CNVI_SCU_REG_FOR_ECO_1_WIAMT_KNOWN set and CNVI_SCU_REG_FOR_ECO_1_WIAMT_PRESENT clear. A read that never reached the hardware is therefore taken as a positive statement that there is no CSME, and the function returns without scheduling the recheck. That is reachable at probe: iwl_pci_gen1_2_probe() carries on when iwl_pcie_prepare_card_hw() fails, and iwl_pcie_check_me_status() then runs against a card it cannot talk to. The second read has the mirror-image problem: an all-ones CSR_HW_IF_CONFIG_REG has both ME_OWN and IAMT_UP set, so a device that has fallen off the bus latches me_present to 1. So does the one in iwl_pcie_recheck_me_status(), which runs a second after probe with no guarantee that the device is still answering. me_present is never recomputed after that, and any non-zero value makes iwl_trans_pcie_reset() downgrade IWL_RESET_MODE_PROD_RESET to IWL_RESET_MODE_FUNC_RESET, so one bad read permanently weakens the recovery. In the 0x5a5a5a5a case it goes the other way and permits a product reset on a machine that may well have CSME. Don't take those values as data. iwl_trans_is_hw_error_value() matches 0x5a5a5a5[0-f] and 0xa5a5a5a[0-f] but not ~0, so the prph read in iwl_pcie_check_me_status() needs both tests, the way iwl_pcie_irq_handler() does; the two CSR reads only need the ~0 one. At probe that leaves me_present at -1 (unknown) and still schedules the recheck; in the recheck it keeps the previous value. This does change the reset ladder in the poisoned-read case, and -1 is truthy: a product reset that iwl_trans_pcie_reset() used to allow - because 0x5a5a5a5a had been read as me_present =3D 0 - is now downgraded to a function level reset. That is the conservative direction, and the 0 was never a reading, but it is a behaviour change and not a no-op. Cc: stable@vger.kernel.org Fixes: 41fff83fe6cd ("wifi: iwlwifi: pcie: check for WiAMT/CSME presence") Signed-off-by: Navon John Lukose --- Backport note: the bug arrived in v6.14, so the affected branches that are still supported are 6.18.y, 7.1.y and 7.2.y. All three have the code in pcie/gen1_2/trans.c as trans_pcie->me_present, so this applies as posted with no rewrite. Only if you care about anything older that has the bug - v6.14 through v6.17, all EOL now: v6.16 and below have both functions in pcie/drv.c (377edee91b89 "wifi: iwlwifi: pcie move gen1_2 probe to gen1_2/trans.c" moved them), and v6.15 and below spell the field trans->me_present (cd6d6de694e2 "wifi: iwlwifi: pcie: move ME check data to pcie" renamed it). The hunks are otherwise identical; iwl_trans_is_hw_error_value() exists in every affected release. .../net/wireless/intel/iwlwifi/pcie/gen1_2/trans.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/gen1_2/trans.c b/drive= rs/net/wireless/intel/iwlwifi/pcie/gen1_2/trans.c index 28b276c..c6a771e 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/gen1_2/trans.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/gen1_2/trans.c @@ -4194,7 +4194,8 @@ static void iwl_pcie_recheck_me_status(struct work_st= ruct *wk) u32 val; =20 val =3D iwl_read32(trans_pcie->trans, CSR_HW_IF_CONFIG_REG); - trans_pcie->me_present =3D !!(val & CSR_HW_IF_CONFIG_REG_IAMT_UP); + if (val !=3D ~0U) + trans_pcie->me_present =3D !!(val & CSR_HW_IF_CONFIG_REG_IAMT_UP); } =20 static void iwl_pcie_check_me_status(struct iwl_trans *trans) @@ -4212,15 +4213,19 @@ static void iwl_pcie_check_me_status(struct iwl_tra= ns *trans) return; =20 val =3D iwl_read_prph(trans, CNVI_SCU_REG_FOR_ECO_1); - if (val & CNVI_SCU_REG_FOR_ECO_1_WIAMT_KNOWN) { + /* iwl_read_prph() returns 0x5a5a5a5a if it never reached the NIC, and + * that value has WIAMT_KNOWN set and WIAMT_PRESENT clear + */ + if (val !=3D ~0U && !iwl_trans_is_hw_error_value(val) && + (val & CNVI_SCU_REG_FOR_ECO_1_WIAMT_KNOWN)) { trans_pcie->me_present =3D !!(val & CNVI_SCU_REG_FOR_ECO_1_WIAMT_PRESENT); return; } =20 val =3D iwl_read32(trans, CSR_HW_IF_CONFIG_REG); - if (val & (CSR_HW_IF_CONFIG_REG_ME_OWN | - CSR_HW_IF_CONFIG_REG_IAMT_UP)) { + if (val !=3D ~0U && (val & (CSR_HW_IF_CONFIG_REG_ME_OWN | + CSR_HW_IF_CONFIG_REG_IAMT_UP))) { trans_pcie->me_present =3D 1; return; } --=20 2.55.0 From nobody Sat Sep 26 18:54:16 2026 Received: from mail-pl1-f173.google.com (mail-pl1-f173.google.com [209.85.214.173]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 2D5043264CE for ; Mon, 31 Aug 2026 13:03:50 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.214.173 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788181433; cv=none; b=iTf8KIPdAvZr4eHUMrOatgGEiNmlguTjhApuLkngeJAMF/8N33hyX6Z9m0eaNpFrtKPyKYwMOL4GCco4b4LyH/O/VVPSRDAykQdKxrPeBvU1toVlVcFF3n2u302ZEYJzyplXsAZHH34DWEDhtro7hJMzERC7j1lHxByzM7tEc4E= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788181433; c=relaxed/simple; bh=V//q0jtU9XTTbMl5NPi6UcTLSaqr0Evx37P5sMiaSJ4=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=c542yedSYc99bTXskQ2x8lLNLeT97yGqZzfvA4jGzyfb+EcRmareSZHrLBxibmfSctZGADzGug8ISRoEADZDVCmqC9KXkj7xaTsHUE+pxNvjRi6dC5WU/QEw0Av4TnJ9Qd0MyYWQDtIgGJ8mrB1M8rCZHwkRnDV+YkauMzHIE2Y= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com; spf=pass smtp.mailfrom=gmail.com; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b=DxKPQpjb; arc=none smtp.client-ip=209.85.214.173 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=gmail.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="DxKPQpjb" Received: by mail-pl1-f173.google.com with SMTP id d9443c01a7336-2d6fec3c1adso4039135ad.3 for ; Mon, 31 Aug 2026 06:03:50 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1788181430; x=1788786230; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to:content-type; bh=RIkEaTsAou/6x2ZpYenzr6Kjhqg+r06MkNAF+XMgBd8=; b=DxKPQpjbegPTpugshIwSDtMDpy+IWy8STxYwpvacmGquHLR3FStiBIvcOAovzr1eXB 84RtL43V9rcMH5cSz93AMxFIwjgHMntKi6hGF+++1uO6e+UuwAvwkt0Le8ROMDNTH3Jd uXBueXeEjQu9qegDp0KfqwLsuEm/kleGtLwizmlEHYBQwUAWpy/IB5dicayxU13Ywi+h lmV+Q7N/CsZ9JYKvBF14qR0GrZ4DA2MlLqLcka86xOCbelviVNEDIbshSa1yF2bpaTvs cchAMIdPx92qiC9OhTWLzk+chWiTiW31dQ/62pqnrzguWGAQ9WrAvAjIscy8DKEj/aba tQ6g== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1788181430; x=1788786230; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to:content-type; bh=RIkEaTsAou/6x2ZpYenzr6Kjhqg+r06MkNAF+XMgBd8=; b=M7oDEsNLXf5zG8MPJFwqTVPGasqa6RaN3FSl1W1sTUDPJNRZhxFnupMMIBFtd8c680 rw4oyiYFjbAHd8IC42I4gF42LKjrmH7f1NlBsPwSnOoh9V5cyHRnY1yG1SARVM0gHfjQ 2FHe8bsje2oUU0W6nuveBxWY9Hdh4Si3Y3ZisVU6cllOuGQWoY2oP6aCQ6b8lmQt0s9q OmyeuDQlsDO36Bss4Lvf3ZNFsVTm72bBrnzcPy5IF2fjNXtKhEnEWTqa1kofZvMNakjF WWEKVYDR1F5mmewxyKOBL7qtIr0/poOQj/faYObG6arUzzLGMCwpSzsIXMtD2McHAFVR UOfg== X-Forwarded-Encrypted: i=1; AKwUvBywfTvrC3siHCBMkQs0X6cL0tBY6ba3B5iF/0/TRJ1UcIBM4iQXRv8xdrafkw3ZOl6lvIq7bYEomxQ9UKA=@vger.kernel.org X-Gm-Message-State: AFuF++mpAT6JAxY4RBW+T77gHVdiQMprzFkdPeUwCupCmZTo17qDeD7u WFIpTBaKR2URsLiQVT5IGdRtbzGGf8/I7Oy7/heIqQGtgVLQ6NDKiPki X-Gm-Gg: AYBFou02mr+39jx2F2uQEynYRIbHEl+mrFYTh4vfNTUMtmnHKIae99/hKN3GCbnPGnh fOHry+Nh2sAaznCa6WEYk/go20kSYms+Pt/L53HK5bH62sQcOPot9cW89ByP2x/9j1OJEHc11+z 0ktyJJQd+IuSQM2b6F7fNk5DJe94Ycb8ko/RkpNxunWv3YQotmsECI/m1lG/vhvM3x31WyOwu/p iiQY2xeyECA8tSKQJa0vfkrHXJaYwaYSWieKav1Wz3UjyAGKPZQ8bHo4ggS5Sfy44f82lKc86OO 0mH1COOuJOp9fO3zEapSRaEEFzjBKWHiU2sQvkBbdsGJYJilN0kBTF+1BUzM1wsK1Fhf8KR1y7O 5EKcXui2mh9P88KclipuZL6cxYn/STEmgC3JScmJPkmG82hzriUouBgAFdjQ6k5iHDUZai+BEvn PD55auY7HIFNm7MP39I4RdwAo2o8Ns/iYFjTnHKqBuD9qyXpYo+lNarOND23cfjA/SfcoYkATDb DYe9KQyJ52u3UV3zM8lwx3mHmV3 X-Received: by 2002:a17:903:1106:b0:2d6:f09a:da1f with SMTP id d9443c01a7336-2d74e0bab6emr217965675ad.4.1788181429982; Mon, 31 Aug 2026 06:03:49 -0700 (PDT) Received: from cachyos-aura ([45.112.149.37]) by smtp.gmail.com with ESMTPSA id 5a478bee46e88-3286f7bf283sm32567749eec.8.2026.08.31.06.03.45 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 31 Aug 2026 06:03:49 -0700 (PDT) From: Navon John Lukose To: Miri Korenblit , linux-wireless@vger.kernel.org Cc: Johannes Berg , Emmanuel Grumbach , Nika Krasnova , Bjorn Helgaas , Mark Pearson , Mark Pearson , linux-pci@vger.kernel.org, linux-kernel@vger.kernel.org, stable@vger.kernel.org Subject: [PATCH wireless v2 2/3] wifi: iwlwifi: pcie: deselect the product reset mode at probe Date: Mon, 31 Aug 2026 18:33:31 +0530 Message-ID: <20260831130332.323549-3-navonjohnlukose@gmail.com> X-Mailer: git-send-email 2.55.0 In-Reply-To: <20260831130332.323549-1-navonjohnlukose@gmail.com> References: <20260831130332.323549-1-navonjohnlukose@gmail.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" The mode that iwl_trans_pcie_set_product_reset() selects lives in the platform's ACPI namespace, not in the device, and nothing deselects it on the product-reset path. iwl_trans_pcie_removal_wk() selects it, evaluates _RST via _PRR and removes the device; the rescan re-probes, and probe only reads the mode back for the log rather than clearing it, so it is still selected. (A later removal with a lesser mode does pass enable=3Dfalse, but that is the path that does not need it.) It is plain namespace state - on the platform I have it is a named integer written by the vendor DSM and read back by the reset method - so it survives S3 and s2idle. Neither the driver nor _RST clears it. That has a consequence. _RST branches on the mode variable, does not clear it, and iwl_trans_pcie_reset() takes the caller's word for which reset to run. So after any product reset the next escalation can do the wrong thing: iwl_trans_determine_restart_mode() asks for IWL_RESET_MODE_FUNC_RESET on rung four of the ladder, no CSME involved, iwl_trans_pcie_removal_wk() skips the Bluetooth teardown because the mode it was passed is not IWL_RESET_MODE_PROD_RESET, tries to deselect, and if the device has stopped answering by then that deselect fails silently - the DSM is gated on AML reading the device's PCI ID out of config space. iwl_trans_pcie_call_reset() then runs a full product reset, Bluetooth kill GPIO and all, with the Bluetooth function still bound. Deselect at probe, after the two calls that already read the mode and the previous reset's status back for the log - so the inherited mode is still what gets logged. That bounds the window to a single driver lifetime. Note that on discrete devices this is not literally a write of zero: iwl_trans_pcie_set_product_reset() also sets EN_WIFI_FLR and EN_BT_OFF_ON unconditionally for !integrated, so the write is 0x6. EN_PROD_RESET is the bit the platform's reset method branches on, and that is the one being cleared. Cc: stable@vger.kernel.org Fixes: 9673c35486d4 ("wifi: iwlwifi: implement product reset for TOP errors= ") Signed-off-by: Navon John Lukose --- Patch 3 also depends on this: it is the only thing that clears the mode if the rescan after a recovery reset does not bring the device back. That dependency runs patch 3 -> patch 2, not the other way about, so this one stands alone as a fix and is tagged for stable while patch 3 is not. drivers/net/wireless/intel/iwlwifi/pcie/gen1_2/trans.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/gen1_2/trans.c b/drive= rs/net/wireless/intel/iwlwifi/pcie/gen1_2/trans.c index c6a771e..df89fb3 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/gen1_2/trans.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/gen1_2/trans.c @@ -4256,6 +4256,8 @@ int iwl_pci_gen1_2_probe(struct pci_dev *pdev, =20 iwl_trans_pcie_check_product_reset_status(pdev); iwl_trans_pcie_check_product_reset_mode(pdev); + /* a previous trans may have left the mode selected */ + iwl_trans_pcie_set_product_reset(pdev, false, mac_cfg->integrated); =20 /* set the things we know so far for the grab NIC access */ iwl_trans_set_info(iwl_trans, &info); --=20 2.55.0 From nobody Sat Sep 26 18:54:16 2026 Received: from mail-pl1-f172.google.com (mail-pl1-f172.google.com [209.85.214.172]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 4B32B32AAA0 for ; Mon, 31 Aug 2026 13:03:56 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.214.172 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788181439; cv=none; b=JvUQQFf7QhdZOria3TQhjBrZIuA2gDPV3eQxnF+CyJiHSPvagLdCuJx6gqA+bt2rMRACXTx02r7ZLOBDPt9ggi/3cBbimqZfFrU33ZZHOsTVj7Y+UKOGJ/QeCRQ5IPCpsBS/UOHtrd/+GUGbiz6ccsbh3mJWaXw9NtJeIQ5GsnA= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788181439; c=relaxed/simple; bh=4Hin49XJlZ0lLoWqEMqdDZWbMuhWHVSDat0+ikbQ5Ng=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=MnyVAQDzwvEcwUeIqRyrIgNQcrz/TW6+sSKvtWCUCausVkA7j43cB2YYCwq8Xeo2dCC7VnKVj9wUivhhZl+GppUrIAiQLhUrHIVyoxBNU6Igd8Swswue+WD8BIvjudKyxcP5QP1plNC+xwRLfM01cH2LIEHlSJCpzzNtD3cJICM= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com; spf=pass smtp.mailfrom=gmail.com; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b=fIvM9j6S; arc=none smtp.client-ip=209.85.214.172 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=gmail.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="fIvM9j6S" Received: by mail-pl1-f172.google.com with SMTP id d9443c01a7336-2cecdc24b1cso3145555ad.1 for ; Mon, 31 Aug 2026 06:03:56 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1788181436; x=1788786236; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to:content-type; bh=DYUzL/NOcSCyj5tsm/2slVASn+9KBY8PpawGtrxxCAE=; b=fIvM9j6S8r51AYN8UxuDMnuNJi/V273Ywozx4zNocVyuQSqAJXowJPIdmkG2f95soe e5dUYH4cDxnQDPPC8+NaHf0ktgGqil4k+xYp4niLN3SYhdqUPvW1fbtYknsTUgGftFjT 2He29L1BLmC4MZM0wDbGXqIjphM4sp22gk9wJfS0oAiFS9M6EFO0P5IhRCiKvgZUegUR GC96PtSD6Cy8AgtaD11/stxSXuvMs3wbcX7UzNQdj5dmA6oCE5ULAllHrmZjK+r9W8gB sJJK/ILEMHu7z2XeInppChxh6I21/IY/z3HI6Lz62B5sgFSeHyxT1rZjepDnLj/ZsKT1 59CA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1788181436; x=1788786236; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to:content-type; bh=DYUzL/NOcSCyj5tsm/2slVASn+9KBY8PpawGtrxxCAE=; b=VZ+So1XmIo86SbCcW+O6ZD5TDJkolTSxf0kO3aRf48xRtz9LOBLsUURpzDkNi+bZlT mCnWPgqEFeE/vIqS/3OJhEnx3iG0ao4wRWVEyI5ZW/WApueVxRTP0GfJk5ZAUfHXQ8PH ds/M65Faw8iGMcJzUXVa8m9kg0Ho/mHi0A8sVp4/Seh/Qt7u15wrJReX0K0IcTE53wZA QWjlZx3lUWchG4z7FLuzkkp7cGSuPXNKR3mmCAWXRxRomHFV2AR6Kj9xeMGDBoVjAidJ k+/kwNVXMv4RtR+xpETZwk/EasEAFvp9WLyj/HCqauLNYGbOiuuE7LRFC0AOijkDRuXO LJNw== X-Forwarded-Encrypted: i=1; AKwUvBx1tpTtU2DKEs0VtxShFNo/NbNuIN0kgsXRNx3Jd+LpMRKFd8Miy5NVnkEt6+pi3aGyPDRCUUP0KVrjJ3g=@vger.kernel.org X-Gm-Message-State: AFuF++lSTi8+ZwU98pK3/misUqDUK6/NuYm/6sd2WuQHp0zUW0RhzzOo IG5B3UzRkzdqapc2GWRc19WrkJkoO22AXv7LNyL6z37Pi/u5+nZrSHZv X-Gm-Gg: AYBFou3DjEwEe1TGfe1cDlA+fVPA0JPRNCvkmwpGfJ8Yh7OaCJFQeGHI6GUpIPlRI2h BIOgz7d/d8wtTBf3n/4kb4BADlYCfpjzMzfrQJmefnDK349DMXV4xFegwcDociypVOeA1nu/oqH 99MlZAMrT+K/rNnvzgWQERXp6fuS77EPMnfRDTvMO57Skb37fDOYgSWpXfeAZVo5ULGeojZnl1j qVuk+2LOan9igzEceAOvpT1UPCYzIA3gBXbpZpXsQFY4XxhFn/3yCMP2PSe3GvcrsVb8WKchwbI vBqmp8cU8EnGQFI4yeazjVQ9NYRHbuoVt+9oPjeNqfvzN7naB/S+IVHGq9HF2qim+1HaLsdqzz+ WN5z4yjom4rweDEJwDod3JNxWfHaCa1LzTX5e2gAMa5+gDsQPwiZuwVM+E9zpkPDIpiCGKIOauK ARVyS4+KFFapLKQ39NshLlLWPlTqAQdohn+cIL4FT0UXFjewu2pgrqyzQXq2LXEBjSPOnAjeMWX EpvbfpcY+J46zveYyjQac8uyaP9 X-Received: by 2002:a17:902:d2d0:b0:2c7:ef84:c58e with SMTP id d9443c01a7336-2d74dc08a13mr234387445ad.1.1788181435321; Mon, 31 Aug 2026 06:03:55 -0700 (PDT) Received: from cachyos-aura ([45.112.149.37]) by smtp.gmail.com with ESMTPSA id 5a478bee46e88-3286f7bf283sm32567749eec.8.2026.08.31.06.03.50 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 31 Aug 2026 06:03:54 -0700 (PDT) From: Navon John Lukose To: Miri Korenblit , linux-wireless@vger.kernel.org Cc: Johannes Berg , Emmanuel Grumbach , Nika Krasnova , Bjorn Helgaas , Mark Pearson , Mark Pearson , linux-pci@vger.kernel.org, linux-kernel@vger.kernel.org, stable+noautosel@kernel.org Subject: [PATCH wireless v2 3/3] wifi: iwlwifi: pcie: recover a device that lost power in D3cold Date: Mon, 31 Aug 2026 18:33:32 +0530 Message-ID: <20260831130332.323549-4-navonjohnlukose@gmail.com> X-Mailer: git-send-email 2.55.0 In-Reply-To: <20260831130332.323549-1-navonjohnlukose@gmail.com> References: <20260831130332.323549-1-navonjohnlukose@gmail.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" On a Lenovo Yoga Pro 7 14IAH10 (Arrow Lake-H) with a discrete BE200 (8086:272b), D3cold removes the module's power rail and the device does not restart when the rail and PERST# are restored. After _ON the power-enable and PERST# GPIO pad registers read correct and the link still never trains; config space reads all ones until reboot. The platform can recover it, with a WLAN-specific reset line driven by the object _PRR returns - which is exactly the product reset the driver already implements. The problem is ordering: AML only dispatches the vendor DSM that selects that mode after reading the device's PCI ID back out of config space, Method (WIST) { Switch (ToInteger (VDID)) { Case (0x272B8086) {...} } } Method (_DSM) { ... If (WIST ()) { ... Return (IFUN (...)) } ... } so once the device is off the bus acpi_check_dsm() fails and the mode stays deselected. iwl_trans_pcie_removal_wk() is the only place that selects it today, and by then it is too late: _RST takes its other branch and issues a function level reset to a device that is not there. So arm the mode in .suspend, while the device still answers, and disarm it again in .resume. Treat the device as gone only when two independent signals agree: the mode we armed can no longer be disarmed (so the platform cannot see the device either) and CSR_HW_REV reads all ones (so neither can we). Either alone is not enough - a DSM can fail for transient ACPI reasons on a healthy adapter, and a false positive costs a remove, a platform reset and a rescan on every resume. The order of the terms is load bearing: a device in D3hot answers config cycles but does not decode its BARs, so the DSM would still work while CSR_HW_REV read all ones. The disarm has to short-circuit. Recovery goes through the existing iwl_trans_pcie_reset() path, which only queues a work item, so the remove, the _RST and the rescan happen after .resume has returned and the PM core has dropped the device lock. The op_mode is not notified beyond the STATUS_TRANS_DEAD that iwl_trans_pcie_reset() sets; as today, it finds out by having its own resume fail against the dead device. Taking this path also skips the handshake timeouts and the bogus ADVANCED_SYSASSERT dump the driver otherwise produces against absent hardware, which on this machine cost about two seconds on every failed resume. Arming is confined to discrete modules: on integrated CNVi parts iwl_trans_pcie_set_product_reset() sends EN_PROD_RESET on its own, which lands in \_SB.PC00.CNVW.RSTT and is what the CNVi _RST branches on before killing Bluetooth and issuing the PLDR. Arming that from .suspend on hardware I cannot test is not worth it, so the integrated mask stays as unexercised as it is today. iwl_trans_pcie_set_product_reset() now reports whether the DSM took, and its error on failure becomes a debug message: .suspend would otherwise log an error on every suspend on every discrete machine without this DSM. So iwl_trans_pcie_removal_wk() no longer logs at error level when it cannot arm, which on the recovery path is every time, since the device is off the bus by then. The cost is that a genuine product reset on a live device with no DSM support is now silent at error level too. One known limitation: where me_present is not 0, iwl_trans_pcie_reset() downgrades the request to IWL_RESET_MODE_FUNC_RESET. The device still comes back, because the mode is already armed and _RST does the product reset regardless, but the Bluetooth function is not torn down first. Cc: stable+noautosel@kernel.org # new suspend/resume behaviour, one machine Link: https://bugzilla.kernel.org/show_bug.cgi?id=3D221695 Link: https://lore.kernel.org/all/20260722021321.68902-1-nika@nikableh.moe/ Link: https://lore.kernel.org/all/20260829093922.37103-1-navonjohnlukose@gm= ail.com/ Signed-off-by: Navon John Lukose --- The bugzilla and the first lore Link: are other BE200/GL reports of the same 0xffffffff-until-reboot, on machines I do not have; neither is claimed as fixed, hence Link: and not Closes:. The assert in the bugzilla report is the dump against absent hardware this patch skips, not a firmware bug it fixes. The second lore Link: is my own analysis of this machine's AML. Lenovo Yoga Pro 7 14IAH10 (Arrow Lake-H, Core Ultra 9 285H), BIOS QGCN35WW, discrete BE200 SUBSYS_00F48086, Bluetooth on USB, no CSME, stock ACPI tables. This machine ships a udev rule forcing d3cold_allowed to 0, which would have made the test vacuous. It was moved aside for the whole run and d3cold_allowed written back to 1 before every cycle, so the device really did reach D3cold: detection fired on all five cycles, which cannot happen otherwise. Before the patch every cycle left the device dead until reboot; with it the device recovered on all five, four with wifi connected at suspend and one with the radio down, the case where .suspend runs with no op_mode. With the reset skipped and nothing else changed it stayed absent, so it is the reset that recovers it and not the remove/rescan. With debug=3D0x100 one cycle logs the intended path end to end: iwl_trans_pcie_set_product_reset Enabled product reset via DSM iwl_trans_pcie_check_product_reset_mode product reset mode is 0x1 iwl_trans_pcie_set_product_reset can't disable product reset via DSM (-= 19) device not responding after resume scheduling reset (mode=3D6) iwl_trans_pcie_set_product_reset can't enable product reset via DSM (-1= 9) iwl_trans_pcie_call_reset called _RST on _PRR object mode=3D6 is IWL_RESET_MODE_PROD_RESET, so the request was not downgraded. The link trained in 64-76 ms and the interface was usable 5.00-5.05 s after .resume returned; end to end it is closer to 7 s, because the PCI core spends ~2 s retraining a link that cannot train before .resume is called. 4.365 s of the rest is one _RST evaluation against a 4.320 s floor computed from the Sleep() operators in the AML, so essentially all of it is platform AML, and asking for a product reset is not what costs it: both arms of _RST fall through to the same two 2000 ms sleeps and the product arm adds only 2 x RDLY (160 ms each here). What is untested or untestable with one machine: - .suspend and .resume are untouched on integrated/CNVi: the arming helper returns early there, so prod_reset_set is never set. (The error-level demotion does apply to integrated parts on the removal_wk() path.) Getting the CNVi case working needs someone with the hardware. - Where me_present is non-zero - including the permanent -1 that iwl_pcie_check_me_status() leaves on everything below IWL_DEVICE_FAMILY_BZ, which is four of the five Intel IDs this AML accepts - the request is downgraded to IWL_RESET_MODE_FUNC_RESET. The device still comes back, because the mode is armed and _RST does the product reset anyway, but Bluetooth is not torn down first. That is the pre-existing hazard the previous patch describes, now reachable from resume. me_present is a real 0 here, so this is reasoned, not observed. - If the disarm fails transiently on a live device, the code clears prod_reset_set and carries on while the platform's mode stays selected until the next probe, which re-opens that same hazard. Retrying the disarm would narrow it; I did not, because a retry loop around an AML method on the resume path needs a bound I cannot justify from one machine. - Only s2idle was tested. The same callback is .freeze and .poweroff, so hibernate arms too and the image is snapshotted while armed, meaning a restore kernel disarms a mode a previous boot selected. Harmless as far as I can reason it, but unexercised. A device that dies at runtime is still unrecoverable; that needs the same thing on runtime PM, which iwlwifi does not implement. - Only one BIOS. On mine the reset method branches solely on the mode variable, never on WIST()/VDID, which is what makes the downgrade above survivable. I cannot claim that for every implementation. - On a platform with the arming DSM but no usable _PRR, iwl_trans_pcie_call_reset() falls back to pci_reset_function() against a device that is gone, and pci_dev_wait() polls config space for up to ~65 s per reset method with pci_lock_rescan_remove() held. That is the cost of a true positive, not a false one: a false positive still answers config cycles, so pci_dev_wait() returns on its first read. - iwl_trans_pcie_removal_wk() holds pci_lock_rescan_remove() across the whole reset, so it is now held for ~4.3 s during system resume on a machine that also has Thunderbolt wanting it. Pre-existing, but this patch is what puts it on the resume path. The arming mask is heavier than the recovery needs - only EN_PROD_RESET drives the GPIO - but I kept it so the reset armed from .suspend is bit for bit the one iwl_trans_pcie_removal_wk() already arms. Narrowing it is an easy follow-up. drivers/net/wireless/intel/iwlwifi/pcie/drv.c | 24 +++++++++++++++++++ .../intel/iwlwifi/pcie/gen1_2/internal.h | 4 ++++ .../intel/iwlwifi/pcie/gen1_2/trans.c | 24 ++++++++++++++----- 3 files changed, 46 insertions(+), 6 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/drv.c b/drivers/net/wi= reless/intel/iwlwifi/pcie/drv.c index 7a7b101..5d01a4d 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/drv.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/drv.c @@ -1203,11 +1203,19 @@ static void iwl_pci_remove(struct pci_dev *pdev) =20 static int iwl_pci_suspend(struct device *device) { + struct iwl_trans *trans =3D pci_get_drvdata(to_pci_dev(device)); + /* Before you put code here, think about WoWLAN. You cannot check here * whether WoWLAN is enabled or not, and your code will run even if * WoWLAN is enabled - don't kill the NIC, someone may need it in Sx. */ =20 + /* Has to be here, while the device still answers: AML gates this DSM + * on reading the device's PCI ID out of config space. It doesn't touch + * the NIC. + */ + iwl_trans_pcie_arm_product_reset(trans, true); + return 0; } =20 @@ -1229,6 +1237,22 @@ static int _iwl_pci_resume(struct device *device, bo= ol restore) */ pci_write_config_byte(pdev, PCI_CFG_RETRY_TIMEOUT, 0x00); =20 + /* Two signals that it didn't come back from D3cold: the platform can't + * deselect the mode armed in .suspend (so it can't see the device + * either), and the device doesn't answer. Before the op_mode test: the + * firmware may never have been loaded. + */ + if (trans_pcie->prod_reset_set) { + iwl_trans_pcie_arm_product_reset(trans, false); + if (trans_pcie->prod_reset_set && + iwl_read32(trans, CSR_HW_REV) =3D=3D ~0U) { + IWL_ERR(trans, "device not responding after resume\n"); + iwl_trans_pcie_reset(trans, IWL_RESET_MODE_PROD_RESET); + return 0; + } + trans_pcie->prod_reset_set =3D false; + } + if (!trans->op_mode) return 0; =20 diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/gen1_2/internal.h b/dr= ivers/net/wireless/intel/iwlwifi/pcie/gen1_2/internal.h index d84c7c1..1caaff9 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/gen1_2/internal.h +++ b/drivers/net/wireless/intel/iwlwifi/pcie/gen1_2/internal.h @@ -495,6 +495,8 @@ struct iwl_pcie_txqs { * @isr_stats: interrupt statistics * @napi_dev: (fake) netdev for NAPI registration * @txqs: transport tx queues data. + * @prod_reset_set: the product reset mode is selected in the platform; + * system suspend/resume only, so process context only * @me_present: WiAMT/CSME is detected as present (1), not present (0) * or unknown (-1, so can still use it as a boolean safely) * @me_recheck_wk: worker to recheck WiAMT/CSME presence @@ -605,6 +607,7 @@ struct iwl_trans_pcie { =20 struct iwl_pcie_txqs txqs; =20 + bool prod_reset_set; s8 me_present; struct delayed_work me_recheck_wk; =20 @@ -657,6 +660,7 @@ bool _iwl_trans_pcie_grab_nic_access(struct iwl_trans *= trans, bool silent); =20 void iwl_trans_pcie_check_product_reset_status(struct pci_dev *pdev); void iwl_trans_pcie_check_product_reset_mode(struct pci_dev *pdev); +void iwl_trans_pcie_arm_product_reset(struct iwl_trans *trans, bool arm); =20 /***************************************************** * RX diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/gen1_2/trans.c b/drive= rs/net/wireless/intel/iwlwifi/pcie/gen1_2/trans.c index df89fb3..56eb35d 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/gen1_2/trans.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/gen1_2/trans.c @@ -2075,7 +2075,7 @@ void iwl_trans_pcie_check_product_reset_mode(struct p= ci_dev *pdev) ACPI_FREE(res); } =20 -static void iwl_trans_pcie_set_product_reset(struct pci_dev *pdev, bool en= able, +static bool iwl_trans_pcie_set_product_reset(struct pci_dev *pdev, bool en= able, bool integrated) { union acpi_object *res; @@ -2089,17 +2089,29 @@ static void iwl_trans_pcie_set_product_reset(struct= pci_dev *pdev, bool enable, DSM_INTERNAL_PLDR_CMD_SET_MODE, mode); if (IS_ERR(res)) { - if (enable) - IWL_ERR_DEV(&pdev->dev, - "ACPI _DSM not available (%d), cannot do product reset\n", - (int)PTR_ERR(res)); - return; + IWL_DEBUG_DEV_POWER(&pdev->dev, + "can't %sable product reset via DSM (%d)\n", + enable ? "en" : "dis", (int)PTR_ERR(res)); + return false; } =20 ACPI_FREE(res); IWL_DEBUG_DEV_POWER(&pdev->dev, "%sabled product reset via DSM\n", enable ? "En" : "Dis"); iwl_trans_pcie_check_product_reset_mode(pdev); + return true; +} + +void iwl_trans_pcie_arm_product_reset(struct iwl_trans *trans, bool arm) +{ + struct iwl_trans_pcie *trans_pcie =3D IWL_TRANS_GET_PCIE_TRANS(trans); + + /* discrete only: the integrated arming mask is untested */ + if (trans->mac_cfg->integrated) + return; + + if (iwl_trans_pcie_set_product_reset(trans_pcie->pci_dev, arm, false)) + trans_pcie->prod_reset_set =3D arm; } =20 void iwl_trans_pcie_check_product_reset_status(struct pci_dev *pdev) --=20 2.55.0