From nobody Fri Sep 25 13:19:17 2026 Received: from BYAPR05CU005.outbound.protection.outlook.com (mail-westusazon11010052.outbound.protection.outlook.com [52.101.85.52]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id BA8423546F0 for ; Sat, 12 Sep 2026 04:44:22 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=fail smtp.client-ip=52.101.85.52 ARC-Seal: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1789188264; cv=fail; b=C6NxXVN4gs2wnVHpPFaiwQhlqpcgcvaHQgW7DTmAAUf6IQ3OKCmD6T8lI/ov4mL9l5Ux6eLrGQ1Y/cgDVQz7nqb/AY+e5Z1K7LjO6G0wpswsUyYhP/f8C3S0rXurKfyRv01AmcubCqJ3GAlDgiN7o3C26Y7mopsrVF3hPZo00TY= ARC-Message-Signature: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1789188264; c=relaxed/simple; bh=KQ75yHSFfpsOyDfBhLjPMYd6QBwvnzKlPz0Ws/YtzJY=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: Content-Type:MIME-Version; b=iJO37VEgvpBTPAG3rfRPFcRnWHjBBZH7H4cW/cKebSZjbgEO2QUH7fP38v9LLxPNHQvc+TC8EPV1vi3Pn3YXOI/TAf4u3AHaN4heTsY+hXkojkWaWEl8R1ItfCciB7KODldvN2q/w5ieL1GYzDbfYmm1r1akZ+OidIiEZnSZdrw= ARC-Authentication-Results: i=2; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=nvidia.com; spf=fail smtp.mailfrom=nvidia.com; dkim=pass (2048-bit key) header.d=Nvidia.com header.i=@Nvidia.com header.b=DAxZ1zde; arc=fail smtp.client-ip=52.101.85.52 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=nvidia.com Authentication-Results: smtp.subspace.kernel.org; spf=fail smtp.mailfrom=nvidia.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=Nvidia.com header.i=@Nvidia.com header.b="DAxZ1zde" ARC-Seal: i=1; a=rsa-sha256; s=arcselector10001; d=microsoft.com; cv=none; b=OIB1EG1YES5LXPULnfLbCVU5B2lbS9gVNXyTknPKKHkoz/wwBVfGC/S3RmxVtZzIKAaX3kVPEK/cBiu7H2xys3VbmE/wD0/RoXVfDFPqu/62LZPp7CD4j17s9vdBJL314VUjTYjFOpVy0P8LEoj/Q4+E4fcVFtxuVCBTeCmr0LpY+0uaMPqorMpnIQTruCh9XY5AGGZ+IaFLdDa96AzCLgKrwBhFD7ATTr3YlsObD4+IGj0ErDyeq1kpJR19Ds5xcuE1g0TKw853MLYMnk+3FnCEV+WroUUipU9buDBKKK6qlB+ywJnKFtmGbQghRjOUyDw7V+Tqm5HMFhpElANb6Q== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=microsoft.com; s=arcselector10001; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-AntiSpam-MessageData-ChunkCount:X-MS-Exchange-AntiSpam-MessageData-0:X-MS-Exchange-AntiSpam-MessageData-1; bh=kE7LgGKlb/RH7lO7LGEGY+pNReRwFNpYsAGsVgNJLsY=; b=TFw6ME5ubhmmVT878MeCNf4Cxf4kGqT3g+RRy6b6zPfrgc7ZHOcXM3fek1Eb4HDb223hs2XkPPsBBTuWpYuEE4X/Ben3m921JAo2bQBs4AuXR6nxMcY0ufA4ec0H6lVVmOC+Kfdb0d57mdwTL7nz7l7XVW23Fc/EwFqtu3V9UB/00SpUz9ARWrZl2a5Xg4bqwULBb/lUpSAIluY0zaUR4gLYWOoV7pOA+6cVcfxJ9pfOp97jRvcNvKmn3fEQnO/AjH4Rd0QG60rMESFXQ9iwomkVxFS0DfM4WQqU2HrcWeQ8FQHnyU3WBD4oFKq1mpOezZnM635kw7RS785FDnPX8w== ARC-Authentication-Results: i=1; mx.microsoft.com 1; spf=pass smtp.mailfrom=nvidia.com; dmarc=pass action=none header.from=nvidia.com; dkim=pass header.d=nvidia.com; arc=none DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=Nvidia.com; s=selector2; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck; bh=kE7LgGKlb/RH7lO7LGEGY+pNReRwFNpYsAGsVgNJLsY=; b=DAxZ1zdeuIjaDJDyir8HNPYbBDAFO9i/CqHaHfs/2t/zIIBUkgsnu+KqMJMrX0zq1RZFh37jlgS5SR9UepXyTWd/uEpmjzAaPAu4g2DIKCWa/z+hWJivwNWMRztU1K3E1YlvnhhyiWMbNwNsy0zpI157fSOSXooxeFldgweQQzRVQZUvrrbSEGimSsepAsucYhoKeIKWQCUzxX9Km57Sb61MIbm4WvhfZvaJFAFaFCkO10zOaq4G+l9cLrbgjnpltRwoOJV1NorBXOHl1Ym8ja03YBWLG2eRokPXevpw29U0YNvUozknp8D/sRnE/KMNWqEnTZ4ajVFC7P1qjB6d0g== Authentication-Results: dkim=none (message not signed) header.d=none;dmarc=none action=none header.from=nvidia.com; Received: from DM3PR12MB9416.namprd12.prod.outlook.com (2603:10b6:0:4b::8) by PH8PR12MB7229.namprd12.prod.outlook.com (2603:10b6:510:227::20) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.21.406.10; Sat, 12 Sep 2026 04:44:16 +0000 Received: from DM3PR12MB9416.namprd12.prod.outlook.com ([fe80::8cdd:504c:7d2a:59c8]) by DM3PR12MB9416.namprd12.prod.outlook.com ([fe80::8cdd:504c:7d2a:59c8%4]) with mapi id 15.21.0406.007; Sat, 12 Sep 2026 04:44:16 +0000 From: John Hubbard To: Danilo Krummrich , Alexandre Courbot Cc: Timur Tabi , Alistair Popple , Eliot Courtney , Zhi Wang , David Airlie , Simona Vetter , Bjorn Helgaas , Miguel Ojeda , Alex Gaynor , Boqun Feng , Gary Guo , =?UTF-8?q?Bj=C3=B6rn=20Roy=20Baron?= , Benno Lossin , Andreas Hindborg , Alice Ryhl , Trevor Gross , nova-gpu@lists.linux.dev, LKML , John Hubbard Subject: [PATCH v4 01/17] rust: pci: declare IrqType and IrqTypes with impl_flags Date: Fri, 11 Sep 2026 21:43:44 -0700 Message-ID: <20260912044400.677097-2-jhubbard@nvidia.com> X-Mailer: git-send-email 2.55.0 In-Reply-To: <20260912044400.677097-1-jhubbard@nvidia.com> References: <20260912044400.677097-1-jhubbard@nvidia.com> X-NVConfidentiality: public Content-Transfer-Encoding: quoted-printable X-ClientProxiedBy: SJ0PR13CA0103.namprd13.prod.outlook.com (2603:10b6:a03:2c5::18) To DM3PR12MB9416.namprd12.prod.outlook.com (2603:10b6:0:4b::8) Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-MS-PublicTrafficType: Email X-MS-TrafficTypeDiagnostic: DM3PR12MB9416:EE_|PH8PR12MB7229:EE_ X-MS-Office365-Filtering-Correlation-Id: 3b4254eb-57da-47b7-f4f9-08df10887e97 X-MS-Exchange-SenderADCheck: 1 X-MS-Exchange-AntiSpam-Relay: 0 X-Microsoft-Antispam: BCL:0;ARA:13230040|1800799024|7416014|376014|23010399003|366016|10067099003|3023799007|18002099003|11063799006|56012099006|22082099003; X-Microsoft-Antispam-Message-Info: wxeVgriYkhv2zlzSJysltazAFPdhZKE/cn6Zz2l28AGEUNyWIagf/LQY83uSsTWHYVsPrRsaafm/xBykgkWqJT14IKjLUXhW0wDI0pcyeEPp8hbPa1eMW/rWtpxx+LTCANV9XBAsIwOW+xuKkIbn2uZNC/U2o3mThbL/zSY4wa+K0MNits4g98euPFrjaYROS0QcxLiLrlmAxD/tvDQCTUgSbQmWeSzOmVrODQ1zGdo4Xn/V5X8v1eMczo+BvSfXryi/INe2esMO0fqReFJRpRjMaE9WoR4WFnPxgPCnMz4FDkKGkB+RBUnCbybwNCvWi4Ih66pJfeCjMwSsqoDlpOUopNNvHVxmk2q2oEfSoimoin4HfBROXQHvG+8J2BG4RTyPo1v9hWRI+1C1OBuD4rnq9tAaAuAv59TX/U7UyOzHnhlwK5xiwbrqz/bnpVjJx+8y/9yk7ava20fhnkx4mAg/Dcz5f7Vv0WOGxZ4S+ZaCjb2Xtgo0Znq3W/x421kcO6rbAGH8wGCTmW4gjjWrou7EbeX47CmBlrK/V16mbKmFmL0LJtyxzul4ujGGlyfNb2cWz3/TkS36gaBPKvhjX8DGqb8w0iOGZjdjoB8S7KpKLXpNcfL2zmzxMZNIyrjnxzwzrlSpiF3rt8bJ1u9r1QG8qNSyn7Jlmnm3iNPQ+1A= X-Forefront-Antispam-Report: CIP:255.255.255.255;CTRY:;LANG:en;SCL:1;SRV:;IPV:NLI;SFV:NSPM;H:DM3PR12MB9416.namprd12.prod.outlook.com;PTR:;CAT:NONE;SFS:(13230040)(1800799024)(7416014)(376014)(23010399003)(366016)(10067099003)(3023799007)(18002099003)(11063799006)(56012099006)(22082099003);DIR:OUT;SFP:1101; X-MS-Exchange-AntiSpam-MessageData-ChunkCount: 1 X-MS-Exchange-AntiSpam-MessageData-0: =?us-ascii?Q?bGRGf++SNv+MmqPGNRmiCa+uYJk+7+zjpkq2NpH/d3BI+QhJUG8e7oaQ+RY6?= =?us-ascii?Q?CCOLwjqu1wnQrwZCMhwNuoA1slhdzwdRh9qSa6OyG/eEH+hEMNfhJkH8ChXT?= =?us-ascii?Q?2FsPGY5rB0bJJEqKd2sCU5kJY25+fKrtb9rIGXAZcwcB+kcPWoJ6UucnR4Zw?= =?us-ascii?Q?7BxQEY2xJJAg7AFP67X98RjcbsTlyjpV41MvpADvSYcUrCGKwC47dmCrUtlJ?= =?us-ascii?Q?+SyS52jK80bMWUOInBPvjDl01RsOTkitWYdmZyy0NQOYn06nZTu2hW+CCDDU?= =?us-ascii?Q?WD/qW0bYkbJM8CAaC5zx5U4vrYlGwGJ9ec3vrroCqck1GeFO7m/CyByrLehV?= =?us-ascii?Q?lSyHvjKZwQvXB51ih6iI2fsMNNfNyhvKV41YVW5+Ci9cmZ9VOJznWJyOYtE4?= =?us-ascii?Q?ZsxG5wX0MM1RE3057ERs3kFCnAmpsDwkhvE4dUmtnjOXrbFdSs6ZgxcF3l++?= =?us-ascii?Q?4FoQ9Si0JgBepYtBH1Bf0qbDjRGS2wUoCgemu5lm4zX3a6MIpsovYj7jesmT?= =?us-ascii?Q?+nLYtNQOQ/Rher+nutYUasE1ybjO81jjxf3XbIhg/pdy9oyqNvZ9rwkJvaWl?= =?us-ascii?Q?KBZPnW5ZZytCm8UIXxthMcvzJMP6dq0Ks5rFmzOFK71aDxYfysRnAPbw5MoP?= =?us-ascii?Q?PgTWEbBdqxEVpkUyoTO1N6iTeSqTkpKWy45o/n1emblHSOSB3cBjUXFjlApl?= =?us-ascii?Q?vqthMchod1O64X29QF0EFU+eOx/ShkSLB0IJt0TbSzGZ6fBEWYJUMej7Sdmo?= =?us-ascii?Q?J7o69HH1aaE+6VJMsebGXZ62Xo3S7HMlqmEpR45J07S1UTIbvdxK6A7VEOXf?= =?us-ascii?Q?qoEE9rfdZ9+fgFiLI968CZR3l/x8AfKgk/R3BsG0h/2UpWKY+IXHK+HZlX5R?= =?us-ascii?Q?9s33GyLadi5J0aq6HHE2XOLSuQV4dTCyjMRHyc627yzgKaL6fnuU+AvfXanb?= =?us-ascii?Q?kQQgt2c0jEhGVONO3O/q52VZn+QydxXduFxUb9wSZKk02A/96ot8EJRNYNl7?= =?us-ascii?Q?joUIM4zQxj2G4XYlivx1uJnGF1WGpCuTKvYmDfq2snY9ObfGqPF1aZZqWjUq?= =?us-ascii?Q?wfWCM9AYUbHrb5UGVg1eNTmcn6Lz6oE34XatnpsTtc6xiU7gYFA80ZAU/8NI?= =?us-ascii?Q?dXh+Uk7P7XlaGjF98rBx0t7OhDLuSR17V+xfA+ftIajKDKPbkKIAJ0JLQie8?= =?us-ascii?Q?Zm7LIGhJs95UTqyA/K9gLq60YWAq5HOOCBhRFikCEPF8/k7dMsmHy43whp9G?= =?us-ascii?Q?f1NZcTnENW78LXjMSXRZKw2hERlY+AbqXA7XPn8ZC7DiWWSTA24efUcDnvWe?= =?us-ascii?Q?nzaQSlenBe/hM2ZLbKdhBu+7z0KmeyN4WB6VNi9ApFNUO70PU7H5wdP2HVNu?= =?us-ascii?Q?2NNUH5nSKDGpRFfzdUVt/NVDc2TVcjfos6+COvWbosxecwPQwXqnPGTALx2z?= =?us-ascii?Q?6y3C74j1nX5cxPKewXxkyHL34DIKf9aWSGjBS6yvrK2joMVeD+ygvigtEroE?= =?us-ascii?Q?SEdfVc8YVi/z5Qr40QfENCeKghdkWhN/2vJIvDsUXgjYw6kSR3YG7jDwJ5QF?= =?us-ascii?Q?QWv/vi0c9jimvTvkXsWMkY/eykooKP/Vbd43kVph0BK4Vc32tEs4yDJSZNjz?= =?us-ascii?Q?o/hlCYQ6Qiu2+M1mD3qHmQef6uZl9S0OAMNiaTLf1T56Qxf1yMgO8rg+YDzw?= =?us-ascii?Q?8O2YjksdTI5U5FKMTTAHfKBZ67GhxF8q3A5Paq+qBxSPNIS7ZBo++uwdCXEj?= =?us-ascii?Q?yURbxeMWIA=3D=3D?= X-OriginatorOrg: Nvidia.com X-MS-Exchange-CrossTenant-Network-Message-Id: 3b4254eb-57da-47b7-f4f9-08df10887e97 X-MS-Exchange-CrossTenant-AuthSource: DM3PR12MB9416.namprd12.prod.outlook.com X-MS-Exchange-CrossTenant-AuthAs: Internal X-MS-Exchange-CrossTenant-OriginalArrivalTime: 12 Sep 2026 04:44:13.6779 (UTC) X-MS-Exchange-CrossTenant-FromEntityHeader: Hosted X-MS-Exchange-CrossTenant-Id: 43083d15-7273-40c1-b7db-39efd9ccc17a X-MS-Exchange-CrossTenant-MailboxType: HOSTED X-MS-Exchange-CrossTenant-UserPrincipalName: CwBD8x7HJHA75CzRIIMNwbr7OsnKMUEtdjrwT7yvKomMkijEFtszsuu/ZWudMPY1mDDA+RQ6mnxPiSR/gqvhwA== X-MS-Exchange-Transport-CrossTenantHeadersStamped: PH8PR12MB7229 Content-Type: text/plain; charset="utf-8" The kernel provides impl_flags! for declaring a bitmask type alongside the enum of its individual flags, generating the bit operators and the containment queries. IrqTypes open-coded that pattern with a with() builder, so a caller naming two interrupt types chained two calls onto IrqTypes::default(). Declare both types through impl_flags!, so the same set reads as IrqType::Msi | IrqType::MsiX. Suggested-by: Gary Guo Reviewed-by: Alexandre Courbot Signed-off-by: John Hubbard --- rust/kernel/pci/irq.rs | 68 +++++++++++++----------------------------- 1 file changed, 21 insertions(+), 47 deletions(-) diff --git a/rust/kernel/pci/irq.rs b/rust/kernel/pci/irq.rs index 6741046ec1c0..f074aad7f1d8 100644 --- a/rust/kernel/pci/irq.rs +++ b/rust/kernel/pci/irq.rs @@ -13,27 +13,26 @@ }; use core::num::NonZero; =20 -/// IRQ type flags for PCI interrupt allocation. -#[derive(Debug, Clone, Copy)] -pub enum IrqType { - /// INTx interrupts. - Intx, - /// Message Signaled Interrupts (MSI). - Msi, - /// Extended Message Signaled Interrupts (MSI-X). - MsiX, -} - -impl IrqType { - /// Convert to the corresponding kernel flags. - const fn as_raw(self) -> u32 { - match self { - IrqType::Intx =3D> bindings::PCI_IRQ_INTX, - IrqType::Msi =3D> bindings::PCI_IRQ_MSI, - IrqType::MsiX =3D> bindings::PCI_IRQ_MSIX, - } +crate::impl_flags!( + /// Set of IRQ types that can be used for PCI interrupt allocation. + #[derive(Debug, Clone, Copy, Default)] + pub struct IrqTypes(u32); + + /// IRQ type flags for PCI interrupt allocation. + #[derive(Debug, Clone, Copy)] + pub enum IrqType { + /// INTx interrupts. + Intx =3D bindings::PCI_IRQ_INTX, + + /// Message Signaled Interrupts (MSI). + Msi =3D bindings::PCI_IRQ_MSI, + + /// Extended Message Signaled Interrupts (MSI-X). + MsiX =3D bindings::PCI_IRQ_MSIX, } +); =20 +impl IrqType { /// Construct from raw value. #[inline] const fn from_raw(raw: u32) -> Self { @@ -45,33 +44,10 @@ const fn from_raw(raw: u32) -> Self { } } =20 -/// Set of IRQ types that can be used for PCI interrupt allocation. -#[derive(Debug, Clone, Copy, Default)] -pub struct IrqTypes(u32); - impl IrqTypes { /// Create a set containing all IRQ types (MSI-X, MSI, and INTx). pub const fn all() -> Self { - Self(bindings::PCI_IRQ_ALL_TYPES) - } - - /// Build a set of IRQ types. - /// - /// # Examples - /// - /// ```ignore - /// // Create a set with only MSI and MSI-X (no INTx interrupts). - /// let msi_only =3D IrqTypes::default() - /// .with(IrqType::Msi) - /// .with(IrqType::MsiX); - /// ``` - pub const fn with(self, irq_type: IrqType) -> Self { - Self(self.0 | irq_type.as_raw()) - } - - /// Get the raw flags value. - const fn as_raw(self) -> u32 { - self.0 + Self(Self::all_bits()) } } =20 @@ -203,9 +179,7 @@ impl Device { /// let vectors =3D dev.alloc_irq_vectors(1, 32, pci::IrqTypes::all())= ?; /// /// // Allocate MSI or MSI-X only (no INTx interrupts). - /// let msi_only =3D pci::IrqTypes::default() - /// .with(pci::IrqType::Msi) - /// .with(pci::IrqType::MsiX); + /// let msi_only =3D pci::IrqType::Msi | pci::IrqType::MsiX; /// let vectors =3D dev.alloc_irq_vectors(4, 16, msi_only)?; /// # Ok(()) /// # } @@ -222,7 +196,7 @@ pub fn alloc_irq_vectors( // - `pci_alloc_irq_vectors` internally validates all other parame= ters // and returns error codes. let ret =3D unsafe { - bindings::pci_alloc_irq_vectors(self.as_raw(), min_vecs, max_v= ecs, irq_types.as_raw()) + bindings::pci_alloc_irq_vectors(self.as_raw(), min_vecs, max_v= ecs, u32::from(irq_types)) }; to_result(ret)?; =20 --=20 2.55.0 From nobody Fri Sep 25 13:19:17 2026 Received: from BYAPR05CU005.outbound.protection.outlook.com (mail-westusazon11010052.outbound.protection.outlook.com [52.101.85.52]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 3563128030E for ; Sat, 12 Sep 2026 04:44:20 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=fail smtp.client-ip=52.101.85.52 ARC-Seal: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1789188262; cv=fail; b=rljORIFOVAyub1cZ6IKSNyfLKmxdx5QB1FsKWZAKI43d3ejQZTss3LXxSyOvu68/Irmb6K1AGp56gIKoKID1tSmn2uH6jjmLSgP7680pq6z3W+mlgPRoUqsE32JF9IY3WfCyY5Br1DA6IL+v5vX2QEQknsgj/Q5UUsZUWtIHZ6s= ARC-Message-Signature: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1789188262; c=relaxed/simple; bh=PHEEgZlGUSJn8PS45RQxtqM2X4fC4Swm+aR3phUqYHA=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: Content-Type:MIME-Version; b=QxTXixuK/rxDI6nDUKNjIx/CleqEXT4G2dENSfb94eB1pqaaeIbMHKkm/D97tgEMTiPa7WSWhPGy5Uqhv/e7pHtrNiRhTE5xNcw94dXeTo233WEpVpIIZe8h8TYGXqlFB2cCX86UCLAN0O5Jqw4LmXBbirJXAwTjmLZ6FYF4c7I= ARC-Authentication-Results: i=2; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=nvidia.com; spf=fail smtp.mailfrom=nvidia.com; dkim=pass (2048-bit key) header.d=Nvidia.com header.i=@Nvidia.com header.b=V+jpxNPt; arc=fail smtp.client-ip=52.101.85.52 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=nvidia.com Authentication-Results: smtp.subspace.kernel.org; spf=fail smtp.mailfrom=nvidia.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=Nvidia.com header.i=@Nvidia.com header.b="V+jpxNPt" ARC-Seal: i=1; a=rsa-sha256; s=arcselector10001; d=microsoft.com; cv=none; b=dgwpu+YKdDAH3JaLh6X3qwln6uLqL6teb9rXcyJATolxiIXaNtTVpF1Ghbjs/efA4h6853BIQ3xbROCLWr7T1NCF+2khXucI64MH2TmL320g376/RJX20n+EbCM/0npSosq6iuXWcxFZi3G/qm4xMGbbdH0IIc/lQVTqla6IAW6nvrqaSpU2xKaQ89qAm9q4HdsfCc7f6RCXnz/nlSZ6BA0P2JQTMYYB3KO6YeqeLUOAs+y4J9Z+XggZKdKofbMRtUxEp9ZM8w459lTITXK3iKPsAmOtIAjVVv9tChU+I/6+bcGodnxOOJo/oc32AIGHEVEqltB/bOJ8GWPuBwB/rw== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=microsoft.com; s=arcselector10001; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-AntiSpam-MessageData-ChunkCount:X-MS-Exchange-AntiSpam-MessageData-0:X-MS-Exchange-AntiSpam-MessageData-1; bh=xXmGQXXm1JUMMWqFnRtPDk3zWonekrtMqOZ1UvTJ4jk=; b=YWSCpMG6Em6vUgL9bmGap9/ZzALlnpKo0XwBguKNiBPJ7j7yoEaZnB+KK+k//ZO0z4qnnk9FJlsB+y2quCmQ0yYwaCMUpGA2cr75wbqVrTqMJMFj5UMP5XrtoYEmoKe+1oC64r7XGyPHUM3P+itLXC0Y0nranQIAOjZTbaZSz1f7P1bWF0zFxxCPiXzmFta4PmODOPlGbxRRrvjlSeC/AyCirmuPiSS5yoJFypC0onJ7jO1mXQQLVwbX6LPqNPD+DHGzmU2rmws3/i34UsFUJFpScmexaaSaUJ71+Qw9QTnmzTugpAtMHyK7wU+Y73kIrzxgg8dHuhFuzBiQm0xHLw== ARC-Authentication-Results: i=1; mx.microsoft.com 1; spf=pass smtp.mailfrom=nvidia.com; dmarc=pass action=none header.from=nvidia.com; dkim=pass header.d=nvidia.com; arc=none DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=Nvidia.com; s=selector2; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck; bh=xXmGQXXm1JUMMWqFnRtPDk3zWonekrtMqOZ1UvTJ4jk=; b=V+jpxNPtIvIFns45TzS1ZYk/aBlBvynRz0Z+bm2S+oyDXtWEQcBC3iWF0XEmSBNNM9rPi45QqeLe8pwQlZ+MDy/VVQ1kzvx8ll3ki4kU6nroUVaGxTvgnllVZ9EwULpikuLLE/fD4T3JwSOK+d9wlbFJSxFMvd0yBHo2pjvEr09FwvyQXkLdS1Fo17EiwiM2wajm2rBwDeVDBxn7yMLPP+gT1gCqgGh9F4A7DDo3yhRrh2L+kDvVhgxdYu+poJstFCThOoJ8MhbMS2zPI0/qenmUaCGghYQZ5zE4y+amGwV1Mw3mVfvH1CiyTbOMFmeMxLDRAXLMsyYFLqadHdE+8Q== Authentication-Results: dkim=none (message not signed) header.d=none;dmarc=none action=none header.from=nvidia.com; Received: from DM3PR12MB9416.namprd12.prod.outlook.com (2603:10b6:0:4b::8) by PH8PR12MB7229.namprd12.prod.outlook.com (2603:10b6:510:227::20) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.21.406.10; Sat, 12 Sep 2026 04:44:16 +0000 Received: from DM3PR12MB9416.namprd12.prod.outlook.com ([fe80::8cdd:504c:7d2a:59c8]) by DM3PR12MB9416.namprd12.prod.outlook.com ([fe80::8cdd:504c:7d2a:59c8%4]) with mapi id 15.21.0406.007; Sat, 12 Sep 2026 04:44:16 +0000 From: John Hubbard To: Danilo Krummrich , Alexandre Courbot Cc: Timur Tabi , Alistair Popple , Eliot Courtney , Zhi Wang , David Airlie , Simona Vetter , Bjorn Helgaas , Miguel Ojeda , Alex Gaynor , Boqun Feng , Gary Guo , =?UTF-8?q?Bj=C3=B6rn=20Roy=20Baron?= , Benno Lossin , Andreas Hindborg , Alice Ryhl , Trevor Gross , nova-gpu@lists.linux.dev, LKML , Joel Fernandes , John Hubbard Subject: [PATCH v4 02/17] rust: sync: completion: add wait_for_completion_timeout() Date: Fri, 11 Sep 2026 21:43:45 -0700 Message-ID: <20260912044400.677097-3-jhubbard@nvidia.com> X-Mailer: git-send-email 2.55.0 In-Reply-To: <20260912044400.677097-1-jhubbard@nvidia.com> References: <20260912044400.677097-1-jhubbard@nvidia.com> X-NVConfidentiality: public Content-Transfer-Encoding: quoted-printable X-ClientProxiedBy: BYAPR21CA0015.namprd21.prod.outlook.com (2603:10b6:a03:114::25) To DM3PR12MB9416.namprd12.prod.outlook.com (2603:10b6:0:4b::8) Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-MS-PublicTrafficType: Email X-MS-TrafficTypeDiagnostic: DM3PR12MB9416:EE_|PH8PR12MB7229:EE_ X-MS-Office365-Filtering-Correlation-Id: 67fc9aa2-da81-4e2e-b255-08df10887f57 X-MS-Exchange-SenderADCheck: 1 X-MS-Exchange-AntiSpam-Relay: 0 X-Microsoft-Antispam: BCL:0;ARA:13230040|1800799024|7416014|376014|23010399003|366016|10067099003|6133799003|18002099003|11063799006|56012099006|22082099003; X-Microsoft-Antispam-Message-Info: vernH6vjmFc7vbas4mGy3U9Kawhnxc7E2wDssnkM5NDQo5t5fGPH+M4l31RYwO+48KPPl076pXFnGnU0Vq9ARgvHFkE0zHKHnaucaivWMh7Z3BrE4Nn8ZOshBqJLfq+/R0MNiIb2S7SlPercZ9gur9zdY0zLrrM1IwjSONaxr+mWyVDg164bpzWj/841i/oXBA6al5xEA7wTKeJ5SqOOA3hbxruZ2W1ZcuobnpEVZwvfYrEjRotPzMKZnQEsf2aE5b2r2qGkbJZNlxXboDKhpBRXuYT82hHOOstH+ovo94nN0sArcpBdPQXeezAgCKZLED39ch5gDxMtr7T2kNF5Gv0mWTHr6elYV1q6maskY3IFog9MTdQKr7KO+g7v0wFLH7pVKxpEMaln1vA3w7AsUnMCvCCo2b/n2xR9BDqj1+qIe23WK9qRTLWRJI8XmEsHa35UmNg9HWcHrjkGodRIM9qbKOO2rey4F60YE8LvXbF6vqgxdLVMaoTk8w8+sND71T3lFWLiPsj1YL1VdEj7sddMaeOFukFk9KPyHGqAJn20a7gMFHrhK94HmNl1VK5JZldshrG3PtFvZqQU0l9iqTpRFXzI/j5UCcZeJpG3xqh3otnL9MDvoNnK9pT2T2C3ow0l0ZBKu4Fi+rs9/p+19WTFqaqKClEAGn0r8wUBvuo= X-Forefront-Antispam-Report: CIP:255.255.255.255;CTRY:;LANG:en;SCL:1;SRV:;IPV:NLI;SFV:NSPM;H:DM3PR12MB9416.namprd12.prod.outlook.com;PTR:;CAT:NONE;SFS:(13230040)(1800799024)(7416014)(376014)(23010399003)(366016)(10067099003)(6133799003)(18002099003)(11063799006)(56012099006)(22082099003);DIR:OUT;SFP:1101; X-MS-Exchange-AntiSpam-MessageData-ChunkCount: 1 X-MS-Exchange-AntiSpam-MessageData-0: =?us-ascii?Q?/1bZS2oP4ddLGvZAORnxe7Cs8Z5JhRJU1O+ecL+qCUn6cAev9vNyQOBHBo0q?= =?us-ascii?Q?SdeX6MEJGCXj+DQ2Vn5f8zwWPthT1Fb8gaqiKaIX8px/u1eVqFXFBj9i1cix?= =?us-ascii?Q?oq+GEeSl6ImZgz/Rd1yhg5cM9FM+lSClbBGJC5Gp0+EfOx24AHMogFpEvR2y?= =?us-ascii?Q?Pa3qn2Wr2+2vHNZfDJbN7CKFzFOcEXW6yJmn9pIEoENejQVwnGOpfWNKflwo?= =?us-ascii?Q?BKl4zmSvQvlJTvEJ+VKjhb0XhHknGmYkOzxIt9bXwkssuwJyC5MvcGAStyBd?= =?us-ascii?Q?w1wJh1OYOK9y/Co5GEFdZ8TRv5wbd9XAhUlJwkV4svEdHGlMBxNZ121JFo7L?= =?us-ascii?Q?QbN85Fk7QiWWanqsS7RUvYviiF86hMVw2/zfbS1eHVuIlaNsTPIt18PzRyST?= =?us-ascii?Q?XnKbEF2aViJd/v5grUyy4ZgkgYOJP4Xchw9hTnTafyFPYh3hx7Vcc72ytkPY?= =?us-ascii?Q?dfmfkt4rm9btQWtXkUN344p+GGda7bYuX/WPopZBhOjb/EEHr3HVq6Q9Xm/z?= =?us-ascii?Q?qtiIFhJ/BxmsV/SNBAhOFCiqBbnC4q0NhFGa5zaEPTOr54CuZV/KIkojS7UK?= =?us-ascii?Q?TenC6KFUgQlEfBz96e7YAwmi1gyKaQEooQHyC8pc9cZyBI75wfFkHYK8jmTD?= =?us-ascii?Q?G3fjjYg17iBCk9PPkDtPfS3YWUIdXvNNykQmvWJHJy21Gcbp5aVTpgEzFaHr?= =?us-ascii?Q?kMm4Dz4xs4YvF8tFonNM0SW4lzBmj+g2S9YevczDZXp3tdvsYEKHtMnSNsRx?= =?us-ascii?Q?L5seOA2cLEiV2xOPbsM5tuAP4qhjaJlFyAztgqVLEcZSETPYP9zZWKCLcOPX?= =?us-ascii?Q?kJPTrdhMI2YFWaIwHoiLJxEMWrr2Re7k9yoe7luBF7Ub4y6t6Li57OCN60/A?= =?us-ascii?Q?kBTh9wXM/i56TRf/JWdCNju2oZUqJ6iyaVfDTkiob9pTtGQ0Pwamr+Rn9OcT?= =?us-ascii?Q?jhbSXE3WsRR8CVJ5pwxsTGSlAjU5NpKr2HE1rvAoZ16C2y8rfR7HeOtnZIub?= =?us-ascii?Q?LoWPnWBdD7lG4muHy83U5tFcYvGGjmU9MM6yMs25fF0KW0z3J/P6naHAY6Pt?= =?us-ascii?Q?y2xXKYrLCsCA69DT58iKIdJUAbLz3zLF7Ed5Ndlk5AlV+G1FrZ55zgboYmuU?= =?us-ascii?Q?cGOKrHubhE/RMIqdaxSTK72gB5enuR+mLlJrtUrko3u/Kx5nXNNhCFdyrqU8?= =?us-ascii?Q?/+GA25npoMA2BWOr2+cwHV2vKlGdnLJbzZEjmeCq7Hf+C6r1EbDzzWjckfgE?= =?us-ascii?Q?vwdX8+cJtOkASAYbxLwgfK4XI2CfmZJvH1BW8ZXDxgE1KfVUj4k27tToKAqX?= =?us-ascii?Q?6nLtTD1ekDjHN62sJVM9eSKGXi4PFu9IPkRjxyWNVrM6HIVGH6Gxwa4vcixX?= =?us-ascii?Q?sqTWFEboV33f/pouw+isCbXW7f5Aaz33MP0dweMmUxqrwmdBbwS1O0ZYEYF1?= =?us-ascii?Q?quQem/AgrMJgHCBNAS2JSpvI2baeV01ZbRtL3pTsAQyDg95FRDO0Kj5vx1K+?= =?us-ascii?Q?MXtcJcXU9QSqzf+1zkndSMOsnUpfrTst+zAMCrtpxZjVwPubhP2Cu11/j34b?= =?us-ascii?Q?8VVmZadpDvhsRgyR6ncqwcSIprCHVGvXUBGgcr6St4wOUplfGG2evSak3jRW?= =?us-ascii?Q?s+aGMQvfOPi8a+nNAkObXMicH1bIcHZwj/TPEfxVmEOTBl7s5frugv/K94tP?= =?us-ascii?Q?hRdWclfrl5jWbS+xZe1CYF3e9noZcvHMJaKHclKkfrAZ3eTVk4/KBfvmCOO3?= =?us-ascii?Q?2Jt5xMA0+Q=3D=3D?= X-OriginatorOrg: Nvidia.com X-MS-Exchange-CrossTenant-Network-Message-Id: 67fc9aa2-da81-4e2e-b255-08df10887f57 X-MS-Exchange-CrossTenant-AuthSource: DM3PR12MB9416.namprd12.prod.outlook.com X-MS-Exchange-CrossTenant-AuthAs: Internal X-MS-Exchange-CrossTenant-OriginalArrivalTime: 12 Sep 2026 04:44:14.9143 (UTC) X-MS-Exchange-CrossTenant-FromEntityHeader: Hosted X-MS-Exchange-CrossTenant-Id: 43083d15-7273-40c1-b7db-39efd9ccc17a X-MS-Exchange-CrossTenant-MailboxType: HOSTED X-MS-Exchange-CrossTenant-UserPrincipalName: RuSIGm+ypTKVtd9TeEkuOesOKKq7foYxQZnlX1FxiT4N68RuZDgYplk5s4xcNgmxCb/1FHHwypSpi73UBN7BcA== X-MS-Exchange-Transport-CrossTenantHeadersStamped: PH8PR12MB7229 Content-Type: text/plain; charset="utf-8" From: Joel Fernandes A driver that runs an interrupt self-test during probe waits for the handler to fire. wait_for_completion() has no timeout, so a broken interrupt path stalls probe indefinitely. Add a timeout variant of wait_for_completion(). Reviewed-by: Alexandre Courbot Signed-off-by: Joel Fernandes [jhubbard: return the remaining jiffies] Signed-off-by: John Hubbard --- rust/kernel/sync/completion.rs | 23 ++++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/rust/kernel/sync/completion.rs b/rust/kernel/sync/completion.rs index 35ff049ff078..7e8b3c1c880e 100644 --- a/rust/kernel/sync/completion.rs +++ b/rust/kernel/sync/completion.rs @@ -6,7 +6,12 @@ //! //! C header: [`include/linux/completion.h`](srctree/include/linux/complet= ion.h) =20 -use crate::{bindings, prelude::*, types::Opaque}; +use crate::{ + bindings, + prelude::*, + time::Jiffies, + types::Opaque, // +}; =20 /// Synchronization primitive to signal when a certain task has been compl= eted. /// @@ -111,4 +116,20 @@ pub fn wait_for_completion(&self) { // SAFETY: `self.as_raw()` is a pointer to a valid `struct complet= ion`. unsafe { bindings::wait_for_completion(self.as_raw()) }; } + + /// Wait for completion of a task, with a timeout. + /// + /// This method waits for the completion of a task, or until `timeout`= elapses. It is not + /// interruptible. Returns the number of jiffies left when the task co= mpleted, or [`None`] if + /// `timeout` elapsed first. + /// + /// See also [`Completion::complete_all`]. + #[inline] + pub fn wait_for_completion_timeout(&self, timeout: Jiffies) -> Option<= Jiffies> { + // SAFETY: `self.as_raw()` is a pointer to a valid `struct complet= ion`. + match unsafe { bindings::wait_for_completion_timeout(self.as_raw()= , timeout) } { + 0 =3D> None, + remaining =3D> Some(remaining), + } + } } --=20 2.55.0 From nobody Fri Sep 25 13:19:17 2026 Received: from SN4PR2101CU001.outbound.protection.outlook.com (mail-southcentralusazon11012058.outbound.protection.outlook.com [40.93.195.58]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id B55D137C93C for ; Sat, 12 Sep 2026 04:44:26 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=fail smtp.client-ip=40.93.195.58 ARC-Seal: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1789188269; cv=fail; b=OZOgZebKzdsAsaV3eKkmJlUMJyGRfLCenf0O8FjNrCl+EhZYO19RWK1F8DtAZMAckjCnkGL/EUMcZIZu41m7pynlgSROVEB8qeQL5UcBI/BeBylLIONuun7T2VGYOlep+wUHXBgQtvPhHj6AQOiX6V6c+impW+idH+voLH/JL8k= ARC-Message-Signature: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1789188269; c=relaxed/simple; bh=+mp8ZRl04h43XtWeAqrNHsVOLkPUIp350sUE5zCJze0=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: Content-Type:MIME-Version; b=K8Q/n/X80MIeMIO/VYKiUQCZPOXdZulS7uiWRqjGKBtO70tlbgk4DPrO4ebKlhO/Xgw7YU9/x6dMbS3CGhi2jFrkXvbkCLeYdurhwGkStG4EZVusavvr5maEMj44TvoNs0JkK9kXnzAwDWcGu9tSbRJ3pE5pfdZ+ItjfAhtW0sw= ARC-Authentication-Results: i=2; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=nvidia.com; spf=fail smtp.mailfrom=nvidia.com; dkim=pass (2048-bit key) header.d=Nvidia.com header.i=@Nvidia.com header.b=tP7AuieW; arc=fail smtp.client-ip=40.93.195.58 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=nvidia.com Authentication-Results: smtp.subspace.kernel.org; spf=fail smtp.mailfrom=nvidia.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=Nvidia.com header.i=@Nvidia.com header.b="tP7AuieW" ARC-Seal: i=1; a=rsa-sha256; s=arcselector10001; d=microsoft.com; cv=none; b=J6xj5NRHYFVFkqGliPgpr2f9+87yc4ktsbyQMcg+0XAB+GtHcGoy92I1De6XahJxD37518CGr7CDOtLjo3WenS9QJzETSRqrZ3q5OzZVTHKdDiLwzsrOfhPFmc0/d30x09iPOzDV2mgwWTYnZSNvn8deN4RNV/4+RMGW+zmv6qTVfYrWDNSEGHj+koGgiWKsH4SMxRn55ryGd/Jz50dFiu0E+mVZtRk35o6PpT88FdJsDnWCIwv1Bq1oMu/POhVl3JmCQiRluEZx4vxL9JCLdfd8dmGsCgPL6u5JoxdsraTJDwjDToFpqy2vxduHaBdUTKXyEqFoFGH1fFsrZ1RIwA== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=microsoft.com; s=arcselector10001; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-AntiSpam-MessageData-ChunkCount:X-MS-Exchange-AntiSpam-MessageData-0:X-MS-Exchange-AntiSpam-MessageData-1; bh=IU8LWOQ81VC5ZAl1EvvDhpf1y1tsO4SubFFK1IPSW4o=; b=pqokwsCyYquzZqu4EqbE2gQwut7YXByKrsTVIIHMYYpe4RRWhDjWiVJ6n+knd61X4pzX2qcNSfvbgRhZfpd2bV5eU757LliGRoM2YS1MjzSRGSGlbwQB8QLvoAvWLpF1YZ7OWUSGuoriCOStgtm5pFJt1BhK0QiLaUX0hRyZ3XrG32lqP+9z9nwlVb4t3ca89akSeXSJkymuKQp1fZOQAJPkogo6+LqnML1gHmNsRh6p/VJB33PyiMI80G/iqCfdeXw6E9mQEC3AtIuBwo267qYEczkrSuG6sTEsjDI1UTQVRifFC89KuwuCez6d9C53SPR8oBwUt+Y18UszW5o5Fg== ARC-Authentication-Results: i=1; mx.microsoft.com 1; spf=pass smtp.mailfrom=nvidia.com; dmarc=pass action=none header.from=nvidia.com; dkim=pass header.d=nvidia.com; arc=none DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=Nvidia.com; s=selector2; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck; bh=IU8LWOQ81VC5ZAl1EvvDhpf1y1tsO4SubFFK1IPSW4o=; b=tP7AuieWyybNA2tU4avMNzWSXB8y+dvnL4TqFemPR0gJlqCXvO+L9yTlBr+OvlJ87kjFkxT3KvBwx2g1uO/OfY5pHuqKI5HMjubKI38x/Qp51JNmiSoX2hHbD0BvRIhSthK7RBK6mo/aKENAy/Cl2ohn5zUzrRJ/gdcvd6OgMYHihujU1/UpdFZx/IDVrRQq58+xR+7d/I+FMlTg5BcYR21XNLToy0U9wdV4jBGdcgfUY40C2E35yaExRJZhEojYzFdE2P8ER8Zdnb+BBqa7WxInpastLR7YA+0t9OYuQOO31ku140h4AmnkgRpNsR03WDft9iYIDjdgVXrEErO3Bg== Authentication-Results: dkim=none (message not signed) header.d=none;dmarc=none action=none header.from=nvidia.com; Received: from DM3PR12MB9416.namprd12.prod.outlook.com (2603:10b6:0:4b::8) by PH8PR12MB7229.namprd12.prod.outlook.com (2603:10b6:510:227::20) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.21.406.10; Sat, 12 Sep 2026 04:44:17 +0000 Received: from DM3PR12MB9416.namprd12.prod.outlook.com ([fe80::8cdd:504c:7d2a:59c8]) by DM3PR12MB9416.namprd12.prod.outlook.com ([fe80::8cdd:504c:7d2a:59c8%4]) with mapi id 15.21.0406.007; Sat, 12 Sep 2026 04:44:16 +0000 From: John Hubbard To: Danilo Krummrich , Alexandre Courbot Cc: Timur Tabi , Alistair Popple , Eliot Courtney , Zhi Wang , David Airlie , Simona Vetter , Bjorn Helgaas , Miguel Ojeda , Alex Gaynor , Boqun Feng , Gary Guo , =?UTF-8?q?Bj=C3=B6rn=20Roy=20Baron?= , Benno Lossin , Andreas Hindborg , Alice Ryhl , Trevor Gross , nova-gpu@lists.linux.dev, LKML , John Hubbard Subject: [PATCH v4 03/17] gpu: nova-core: add the GIN vector, leaf and subtree types Date: Fri, 11 Sep 2026 21:43:46 -0700 Message-ID: <20260912044400.677097-4-jhubbard@nvidia.com> X-Mailer: git-send-email 2.55.0 In-Reply-To: <20260912044400.677097-1-jhubbard@nvidia.com> References: <20260912044400.677097-1-jhubbard@nvidia.com> X-NVConfidentiality: public Content-Transfer-Encoding: quoted-printable X-ClientProxiedBy: BYAPR21CA0009.namprd21.prod.outlook.com (2603:10b6:a03:114::19) To DM3PR12MB9416.namprd12.prod.outlook.com (2603:10b6:0:4b::8) Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-MS-PublicTrafficType: Email X-MS-TrafficTypeDiagnostic: DM3PR12MB9416:EE_|PH8PR12MB7229:EE_ X-MS-Office365-Filtering-Correlation-Id: 7fe62112-8652-4baf-a3ab-08df10888005 X-MS-Exchange-SenderADCheck: 1 X-MS-Exchange-AntiSpam-Relay: 0 X-Microsoft-Antispam: BCL:0;ARA:13230040|1800799024|7416014|376014|23010399003|366016|10067099003|6133799003|18002099003|5023799004|11063799006|56012099006|22082099003; X-Microsoft-Antispam-Message-Info: tzUXNGFr+c8EWigLLyzS5tyfzRY7t4VCPH1HOHNgYr874zWJvBbMnB8fwNheCghiTDXUbjWtJJGPCBKzeIesQH1ixQRMRxx4/nzoFelMKANVALFuxR0Ga0b1ZG/oWUfGTFftmhQBDy279v09l4O2rxJU7QqQ+OrivHUmYEItkrCEvh7sWJK4/CJntQhaUSZvP7J4sZaWXQED4CJDawPqB03dsMnu4szeHEfdEpm0Fhns+behCJ4zTYf2FrXAtRI3BYhDq37PhtGBejK71IV4vDc6g+eEMo2o5Rjf/dIP7gyW1hj7q7jYxS+owsT5gzyhbzqmxUYcdn/pBsale06psfYjDW/xxzcYUtVqDjbkb3QRSDpapZsL3G2A44xcN1bjSRzZXKMslT3zVIBUHBIhmORKoW0Uljl+0RqRGa/8cgqT19152OLTcT+bNn3+wDlBfgdqX45ZJWMAbAEIUPogFONfkzesU3Ura61rfAN6V/TzZZV9obbJ0cXgt5KEj4j1mIPQNdsjC0A+jBMRFzEtODI9T6m5MrzLegealUGSeFj42th7fQ+DlFIwhvb6Sf7uD+Pybj/+w3C5vANeQqm79XVf7oYtul2wk5vTtSa1NxA9FrWtbvVTARPu6xDY5htxdaE7+Th0tZHSqW2ZJ99m4+gnr+bqYUHeNOH0hyB34to= X-Forefront-Antispam-Report: CIP:255.255.255.255;CTRY:;LANG:en;SCL:1;SRV:;IPV:NLI;SFV:NSPM;H:DM3PR12MB9416.namprd12.prod.outlook.com;PTR:;CAT:NONE;SFS:(13230040)(1800799024)(7416014)(376014)(23010399003)(366016)(10067099003)(6133799003)(18002099003)(5023799004)(11063799006)(56012099006)(22082099003);DIR:OUT;SFP:1101; X-MS-Exchange-AntiSpam-MessageData-ChunkCount: 1 X-MS-Exchange-AntiSpam-MessageData-0: =?us-ascii?Q?CwYvyQlskQfPn71R6LEoM7x1VYetQV9BMhG15c5jMizMgNRnvPHT237iM+Yc?= =?us-ascii?Q?I4bcI1nuU37uh3hOsunl7rZszadco1NR8Sxdktzui0g8QtbABQ2JAzHlAcvl?= =?us-ascii?Q?lukaiBBduZWWDrM+dldAPMkc/uYGc9fLFVdrJYnIUND6n3x58cjzAlIF3jJJ?= =?us-ascii?Q?Tzl6oGBrNtZfSMvpIK7FldBHHcszyokv3OwS3doLfJg0F1H8WDUF6kOLi4+e?= =?us-ascii?Q?7qt4gMwdPJQRr2LGdealqPItCk7IOU4ojinCXrZDjgVEg3e2Xs/1uytDeB72?= =?us-ascii?Q?iKYzPTnp/RcXikgipYMV6oa5nvm1Eb3fILhAJ0t3yUPOdvOpZWRBktEv7Leb?= =?us-ascii?Q?cLQRfXkl68heFTPrsy2muX2gC3iMPOuYufmPKBZFYBezQApYsU5sMLDqiHfz?= =?us-ascii?Q?puiodA36GoeS4sRhrzIxRtDrkYw0hlTB9g/DSQMFXMlqY5yGpeGO7Dg+/9bV?= =?us-ascii?Q?IysKNsBw9pMyRqh3aCiyC+SHQ0dpTa7P/N7VYleQGGLsPrV7MEwf6PEJCk3j?= =?us-ascii?Q?eWHDR535DlSK6ivu4CT40gijTAp8KNymotzGRnuc4D9+BX5d8jASUMR85bvL?= =?us-ascii?Q?RI7ubv6Sscsfuhl6UTgeSFj53sKt9hBD89VUk5P/8NeLoJrbBav1q9B0ToGo?= =?us-ascii?Q?Mj23nHGqBiKMun5Xg0gj+L+54HuWIL3rBLQhmUtl6h9U1pKaLl5OHrfDnxd/?= =?us-ascii?Q?gY4L2zFq0MQQPA8oN/RvaPT57lFPinEbsMjHoq7kzaK9ualWkxyqpAjMgf1D?= =?us-ascii?Q?HM2WVLgO3jv05n+0aF3ivg+X2WSD7/3y/gpRqB4lQw6KGUQLlEfurSHhmqai?= =?us-ascii?Q?coCa8jvzpVTsOcJjOoAbxIeFUS2+YLeyGwaPCsvTF0B2iuXVbjDOf/Tb+szN?= =?us-ascii?Q?utPZ4jxPouJ2hXXFVXkYFzvU1sWLuPquF6ypK+MSMn0B0vcUq8EOVT/XVtMY?= =?us-ascii?Q?5bqdnVNwASePuQQcsrbWZ07hXGsmOLOwatiL02bGm7A3NvrTLJPrZ2akX9Lr?= =?us-ascii?Q?zmfrnwqDyDfmcZ7I13+oBB1qe5F+NDTmwpXamxPtv98tSjWILsHuL/8xIV8J?= =?us-ascii?Q?/XUBTJYynS/IbkPweNzb6J/IC9hF8N8rApcIFaf5fI5uy9GRxa/LS44LihdL?= =?us-ascii?Q?gflbK8L7Zhh6czZl02kiXOaEEX7Fiav3C1RZZz6G2nEInO61FqnL+iuhSDYD?= =?us-ascii?Q?HBkeJlmlmQyvSrbvmqLKFSPgKHLKaDG4P58OwZcKevgvdhSCtjBlDyOnyiG1?= =?us-ascii?Q?DU54PgSKWDklt0ZebBiEKtby+nU9+3kHnWbV2rYSFYoNWAPDEiJsJadbKYKS?= =?us-ascii?Q?UGZGWYmm54wxFF5DKnX9LzZ1edyEvZ3tdZBW5xfHpBpljlKrFeHgzfZNtTRy?= =?us-ascii?Q?8DTWbMPaICXZxktKS74zzXeIrNrVOaHvnkDXF6EaqUl5A1zvoVSyeiWZg4I7?= =?us-ascii?Q?2BbT1q4TpEB0qAKzEOAoryTjA6YamLUhFQh7Msn0ir6ZK0qnSj2xxtTkyqQH?= =?us-ascii?Q?GtYdiNGUM01rDdvrtUNyHgc9es3mSjwSPDPgcSRjPAgvPyf1/R8e2vEj5NhZ?= =?us-ascii?Q?/VJiHgASfm0RFK2K7ftlPQSgFeXsGPLT/pBa/9p5qREk5Kjt8tIUIXt0bE22?= =?us-ascii?Q?edQdj1cOq48KahesHN6Ep5nKUKlSN4rV0gN9he0Ymz/Fuu3ZQ8Vb+tcD0wke?= =?us-ascii?Q?PeusEUNMBX2+QSopVbsnkJYp5Da6jzPlaaSbc/sDjejZhE0v70+BPpe2q3/O?= =?us-ascii?Q?2waG9MskcA=3D=3D?= X-OriginatorOrg: Nvidia.com X-MS-Exchange-CrossTenant-Network-Message-Id: 7fe62112-8652-4baf-a3ab-08df10888005 X-MS-Exchange-CrossTenant-AuthSource: DM3PR12MB9416.namprd12.prod.outlook.com X-MS-Exchange-CrossTenant-AuthAs: Internal X-MS-Exchange-CrossTenant-OriginalArrivalTime: 12 Sep 2026 04:44:16.1024 (UTC) X-MS-Exchange-CrossTenant-FromEntityHeader: Hosted X-MS-Exchange-CrossTenant-Id: 43083d15-7273-40c1-b7db-39efd9ccc17a X-MS-Exchange-CrossTenant-MailboxType: HOSTED X-MS-Exchange-CrossTenant-UserPrincipalName: UinGMVJupliC8RoSbuvp3wO91/HKWrdolL8b8MeXol3XB8G4IwRwXf4NbXiuxatEiEQ4CATpCS1vVcgfyFSAaQ== X-MS-Exchange-Transport-CrossTenantHeadersStamped: PH8PR12MB7229 Content-Type: text/plain; charset="utf-8" GIN, the GPU Interrupt and Notification unit, is the GPU's interrupt controller. Each interrupt source has a GIN vector number, and the controller latches a pending vector in a two-level tree: one bit of a LEAF register, summarized two leaves at a time by one bit of the TOP register. A vector's number fixes its position in that tree: leaf =3D vector / 32 bit =3D vector % 32 subtree =3D leaf / 2 A tree implements either 8 or 16 leaves, depending on the GPU family. The leaf count sets both the number of subtrees and the highest vector the tree carries. Without distinct types, a vector, a leaf index, a set of vectors within one leaf, a subtree and a set of subtrees are all plain integers. Nothing stops a caller from passing one where another belongs, or a register field from accepting the wrong one. Add a type for each of those, and for the leaf count. A vector converts to its own leaf, bit and subtree. Its constructor rejects, at build time, a number beyond the widest supported tree, and a validation method rejects, at run time, a number beyond the leaves that the current tree implements. A leaf count yields the set of subtrees it implements. Nothing uses the module yet. The following patches declare the tree registers and the tree itself in terms of these types. Suggested-by: Danilo Krummrich Signed-off-by: John Hubbard --- drivers/gpu/nova-core/irq.rs | 12 + drivers/gpu/nova-core/irq/interrupt_tree.rs | 238 ++++++++++++++++++++ drivers/gpu/nova-core/nova_core.rs | 2 + 3 files changed, 252 insertions(+) create mode 100644 drivers/gpu/nova-core/irq.rs create mode 100644 drivers/gpu/nova-core/irq/interrupt_tree.rs diff --git a/drivers/gpu/nova-core/irq.rs b/drivers/gpu/nova-core/irq.rs new file mode 100644 index 000000000000..f1323f633a03 --- /dev/null +++ b/drivers/gpu/nova-core/irq.rs @@ -0,0 +1,12 @@ +// SPDX-License-Identifier: GPL-2.0 +// SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIA= TES. All rights reserved. + +//! GPU interrupt support. +//! +//! GIN, the GPU Interrupt and Notification unit, is the GPU's interrupt c= ontroller. It latches +//! every interrupt source in a two-level register tree and delivers the t= ree to the CPU as a +//! message-signaled PCI interrupt. +//! +//! See `Documentation/gpu/nova/core/interrupts.rst`. + +mod interrupt_tree; diff --git a/drivers/gpu/nova-core/irq/interrupt_tree.rs b/drivers/gpu/nova= -core/irq/interrupt_tree.rs new file mode 100644 index 000000000000..24976a3146be --- /dev/null +++ b/drivers/gpu/nova-core/irq/interrupt_tree.rs @@ -0,0 +1,238 @@ +// SPDX-License-Identifier: GPL-2.0 +// SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIA= TES. All rights reserved. + +//! Vector addressing in the GIN CPU interrupt tree. +//! +//! A [`GinVector`] names an interrupt source, a [`LeafIndex`] the leaf re= gister that latches it, +//! a [`LeafMask`] a set of vectors within one leaf, and a [`Subtree`] one= `TOP` bit. The types +//! keep the four from being confused with one another. +//! +//! See `Documentation/gpu/nova/core/interrupts.rst`. + +use kernel::{ + num::Bounded, + prelude::*, // +}; + +use crate::num; + +/// Number of vectors one leaf register carries, one per bit. +const VECTORS_PER_LEAF: u32 =3D u32::BITS; + +/// Number of leaves one subtree covers. +const LEAVES_PER_SUBTREE: u32 =3D 2; + +/// Number of subtrees the widest supported tree implements. +const MAX_NUM_SUBTREES: u32 =3D 8; + +/// Number of leaves the widest supported tree implements. +const MAX_NUM_LEAVES: u32 =3D MAX_NUM_SUBTREES * LEAVES_PER_SUBTREE; + +/// Number of bits needed to address every vector in the widest supported = tree. +const VECTOR_BITS: u32 =3D (MAX_NUM_LEAVES * VECTORS_PER_LEAF).ilog2(); + +/// Index of a leaf register within the widest supported tree. An 8-leaf t= ree implements only the +/// lower half of the range. +pub(super) type LeafIndex =3D Bounded; + +/// Number of leaves a tree implements. +#[derive(Clone, Copy, Debug, Eq, PartialEq)] +#[repr(usize)] +pub(super) enum LeafCount { + /// Turing through Ada. + Eight =3D 8, + + /// Hopper and later. + Sixteen =3D 16, +} + +impl LeafCount { + pub(super) const fn into_u32(self) -> u32 { + // CAST: both discriminants are 16 or below. + self as u32 + } + + pub(super) const fn into_raw(self) -> usize { + num::u32_as_usize(self.into_u32()) + } + + /// Returns the number of subtrees a tree of this size implements. + pub(super) const fn subtree_count(self) -> u32 { + self.into_u32() / LEAVES_PER_SUBTREE + } + + /// Returns the set of every subtree a tree of this size implements. + pub(super) const fn subtree_set(self) -> SubtreeSet { + SubtreeSet((1u32 << self.subtree_count()) - 1) + } + + /// Returns the number of vectors a tree of this size carries. + pub(super) const fn vector_count(self) -> u32 { + self.into_u32() * VECTORS_PER_LEAF + } +} + +// `VECTOR_BITS` and `LeafCount::Sixteen` are written separately. This ass= ert keeps them in +// agreement about the widest supported tree. +static_assert!(1 << VECTOR_BITS =3D=3D LeafCount::Sixteen.vector_count()); + +/// Set of vectors within one leaf, one bit per vector. +#[derive(Clone, Copy, Debug, Eq, PartialEq)] +pub(super) struct LeafMask(u32); + +impl LeafMask { + /// Returns the mask with every vector set. + pub(super) const fn all() -> Self { + Self(u32::MAX) + } + + pub(super) const fn from_raw(raw: u32) -> Self { + Self(raw) + } + + pub(super) const fn into_raw(self) -> u32 { + self.0 + } + + pub(super) const fn is_empty(self) -> bool { + self.0 =3D=3D 0 + } + + /// Returns whether every vector in `other` is also in this mask. + pub(super) const fn contains(self, other: Self) -> bool { + self.0 & other.0 =3D=3D other.0 + } +} + +impl From> for LeafMask { + fn from(vectors: Bounded) -> Self { + Self(vectors.get()) + } +} + +impl From for Bounded { + fn from(vectors: LeafMask) -> Self { + vectors.0.into() + } +} + +/// One subtree, held as the `TOP` bit that covers it. +/// +/// # Invariants +/// +/// Exactly one bit is set. +#[derive(Clone, Copy, Debug, Eq, PartialEq)] +pub(super) struct Subtree(u32); + +impl Subtree { + /// Returns the subtree at index `idx`. + const fn new(idx: u32) -> Self { + // INVARIANT: shifting `1` left leaves exactly one bit set. + Self(1 << idx) + } + + /// Returns this subtree's index within the tree. + pub(super) const fn index(self) -> u32 { + self.0.trailing_zeros() + } + + pub(super) const fn into_raw(self) -> u32 { + self.0 + } +} + +/// Set of subtrees, one bit per subtree, in the layout of the `TOP` regis= ters. +#[derive(Clone, Copy, Debug, Eq, PartialEq)] +pub(super) struct SubtreeSet(u32); + +impl SubtreeSet { + pub(super) const fn contains(self, subtree: Subtree) -> bool { + self.0 & subtree.into_raw() !=3D 0 + } + + pub(super) const fn is_empty(self) -> bool { + self.0 =3D=3D 0 + } + + pub(super) const fn intersection(self, other: Self) -> Self { + Self(self.0 & other.0) + } + + /// Returns one more than the highest index in this set, or `0` for an= empty set. An MSI-X + /// allocation that covers the set needs this many entries. + pub(super) const fn span(self) -> u32 { + u32::BITS - self.0.leading_zeros() + } + + /// Returns the subtrees of this set, lowest index first. + #[expect(dead_code)] + pub(super) fn iter(self) -> impl Iterator { + (0..u32::BITS) + .map(Subtree::new) + .filter(move |subtree| self.contains(*subtree)) + } +} + +impl From for SubtreeSet { + fn from(subtree: Subtree) -> Self { + Self(subtree.into_raw()) + } +} + +impl From> for SubtreeSet { + fn from(subtrees: Bounded) -> Self { + Self(subtrees.get()) + } +} + +impl From for Bounded { + fn from(subtrees: SubtreeSet) -> Self { + subtrees.0.into() + } +} + +/// A GIN interrupt vector, bounded to the widest tree any supported part = implements. +#[derive(Clone, Copy, Debug, Eq, PartialEq)] +pub(super) struct GinVector(Bounded); + +impl GinVector { + /// Returns vector number `VECTOR`. + /// + /// Fails to compile if `VECTOR` is beyond the widest supported tree. + pub(super) const fn new() -> Self { + Self(Bounded::::new::()) + } + + pub(super) const fn into_raw(self) -> u32 { + self.0.get() + } + + /// Returns this vector's leaf. + pub(super) fn leaf_index(self) -> LeafIndex { + // CALC: `self.0 / VECTORS_PER_LEAF`. + self.0.shr::<{ VECTORS_PER_LEAF.ilog2() }, _>().cast() + } + + /// Returns this vector's bit within its leaf. + pub(super) const fn leaf_mask(self) -> LeafMask { + LeafMask(1 << (self.0.get() % VECTORS_PER_LEAF)) + } + + /// Returns this vector's subtree. + pub(super) const fn subtree(self) -> Subtree { + Subtree::new(self.0.get() / (VECTORS_PER_LEAF * LEAVES_PER_SUBTREE= )) + } + + /// Checks that a tree with `leaves` leaves implements this vector. + /// + /// # Errors + /// + /// `EINVAL` if it does not. + pub(super) const fn validate(self, leaves: LeafCount) -> Result { + if self.0.get() >=3D leaves.vector_count() { + return Err(EINVAL); + } + + Ok(()) + } +} diff --git a/drivers/gpu/nova-core/nova_core.rs b/drivers/gpu/nova-core/nov= a_core.rs index 1133c6ce5c55..5176a5fe2da2 100644 --- a/drivers/gpu/nova-core/nova_core.rs +++ b/drivers/gpu/nova-core/nova_core.rs @@ -17,6 +17,8 @@ mod fsp; mod gpu; mod gsp; +#[expect(dead_code)] +mod irq; mod mctp; mod mm; #[macro_use] --=20 2.55.0 From nobody Fri Sep 25 13:19:17 2026 Received: from BYAPR05CU005.outbound.protection.outlook.com (mail-westusazon11010052.outbound.protection.outlook.com [52.101.85.52]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 19DD037AA7E for ; Sat, 12 Sep 2026 04:44:27 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=fail smtp.client-ip=52.101.85.52 ARC-Seal: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1789188268; cv=fail; b=IsH15FxJ6SPtykq0iMY0IeaBldpPMV4TMnBNPqXaogDqc8K15mjYtz9DRgvbfJXefiy+NvvIlrgSYdMmxa8RD0UPNt/R1lWx6jIy50DzInkYg2LK3e/PqIl9kl7FIDuW2UwejQi09k1yU0w5vONxREvZpFkEETc5VSiSHkNVBKg= ARC-Message-Signature: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1789188268; c=relaxed/simple; bh=UykTYG0YOkCHWffM1BBNClwMKLZe7k2Hvd5zZi/Iu+A=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: Content-Type:MIME-Version; b=YLbLxiaEBeYwmrJj7tcCzz5n4YQWyHPqec1aV/QrhbxaUfsKlHGG9aLCOape9Acn7TtTYMn2lprysBl+gdrg6Qf49Welhe3DM7IhXVbl9hgln1kTlvnr5xh4vJXdvrh3FDWNhhwo+PFK5sxrX6jQAJpmw3R434x24R7KC9E9VCc= ARC-Authentication-Results: i=2; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=nvidia.com; spf=fail smtp.mailfrom=nvidia.com; dkim=pass (2048-bit key) header.d=Nvidia.com header.i=@Nvidia.com header.b=Z5d7tTVN; arc=fail smtp.client-ip=52.101.85.52 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=nvidia.com Authentication-Results: smtp.subspace.kernel.org; spf=fail smtp.mailfrom=nvidia.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=Nvidia.com header.i=@Nvidia.com header.b="Z5d7tTVN" ARC-Seal: i=1; a=rsa-sha256; s=arcselector10001; d=microsoft.com; cv=none; b=EZGx+jR+ilx9O02QrEaRdvEqSe3MDzcmD5VkoD0+72FTKfRqv0EvL3ebx1oFPpy12a9719fIY/k9pdYeM6mRnr3IiNf3iCog667MJSxZeHc+HotCllysazSXtnpdah52MX1bZn2SEjJIfNM3BEQYzvCOvxV1KP7r43iYZ+Cylt31RTImky9z0R82TSCplghJco4Z6dsRBN3Y58eXMaI6geQAGCisRchI8IYAx4u1oa+cv9T/1vECpSLJ+pySAIS7RQfS7FbcaPlMfpP3lGSub5jMws4hd+G4v6ctKVkl27pO497UwJuTzrdojy7QBGsKPa3J7XSymxgiACUS/x4uow== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=microsoft.com; s=arcselector10001; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-AntiSpam-MessageData-ChunkCount:X-MS-Exchange-AntiSpam-MessageData-0:X-MS-Exchange-AntiSpam-MessageData-1; bh=FjlN/Wl8y8Qn7wapsG5i9DL8ekpxtTIrk45J+3qvNAs=; b=ibUkp+IhAp9BxUridc6d5trWb6K3nALqO4KuQysAdPPr+4CaujQkdGYre9A0QNzlsvOKI459F5A7s8QY28tm6qVYvl4yuvLA+a6EESu4aWVQZyGIk2tpSfku54pCmTx3EccLSzDrsC7h26EhTUO9vAmhuy1tG08Xg1EVHmn51eRyKPC2euEjw+1hMnIH9ZLYKsqMqN1HynOr8ybA8iSfmQ3Y1K9YtkH2xrd0336F8e3OLVLl2zjIUyYFDNbGrrs6F8EjalOI5uW0i5Me9fgVqZeyz1RAxHpevrLr/VpfabA6oDftK/Kb3hyGV3oU/bR0xqpYA1x5gpTHEgW63tAd2g== ARC-Authentication-Results: i=1; mx.microsoft.com 1; spf=pass smtp.mailfrom=nvidia.com; dmarc=pass action=none header.from=nvidia.com; dkim=pass header.d=nvidia.com; arc=none DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=Nvidia.com; s=selector2; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck; bh=FjlN/Wl8y8Qn7wapsG5i9DL8ekpxtTIrk45J+3qvNAs=; b=Z5d7tTVN75tO2NlRFL/GVhYBw/CGBCglVLGzA1qzQKOXd3oj0YV/kvvCqu8z2qWtpHyY/MMQFjuchiUMMgg6pceQD8LfnuzONy0et2SHX5pTTlx3KfINMrEO7YUagDyh7GMJ5n8mwNjwiUcZ9wm6TS1nFJy4U9Dh0uJUIkmQyApwQfXwnEgjEEv0egA8FUH8kkQglHadEbYRBZYUBTZSUVWijDVE7BxV4bjmS7wQM1elV6ritgAfCQjnJiqe0EqmriDBY2R3z1DPgdJNfQdYTatJUaqiVN6Bov+TncNDIWDyIlRkLlP33gNYeMlXgyjVCza8GeFPXPRA5dwe8vWuYQ== Authentication-Results: dkim=none (message not signed) header.d=none;dmarc=none action=none header.from=nvidia.com; Received: from DM3PR12MB9416.namprd12.prod.outlook.com (2603:10b6:0:4b::8) by PH8PR12MB7229.namprd12.prod.outlook.com (2603:10b6:510:227::20) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.21.406.10; Sat, 12 Sep 2026 04:44:17 +0000 Received: from DM3PR12MB9416.namprd12.prod.outlook.com ([fe80::8cdd:504c:7d2a:59c8]) by DM3PR12MB9416.namprd12.prod.outlook.com ([fe80::8cdd:504c:7d2a:59c8%4]) with mapi id 15.21.0406.007; Sat, 12 Sep 2026 04:44:17 +0000 From: John Hubbard To: Danilo Krummrich , Alexandre Courbot Cc: Timur Tabi , Alistair Popple , Eliot Courtney , Zhi Wang , David Airlie , Simona Vetter , Bjorn Helgaas , Miguel Ojeda , Alex Gaynor , Boqun Feng , Gary Guo , =?UTF-8?q?Bj=C3=B6rn=20Roy=20Baron?= , Benno Lossin , Andreas Hindborg , Alice Ryhl , Trevor Gross , nova-gpu@lists.linux.dev, LKML , John Hubbard , Will Pierce Subject: [PATCH v4 04/17] gpu: nova-core: add the GIN CPU interrupt tree and MSI EOI registers Date: Fri, 11 Sep 2026 21:43:47 -0700 Message-ID: <20260912044400.677097-5-jhubbard@nvidia.com> X-Mailer: git-send-email 2.55.0 In-Reply-To: <20260912044400.677097-1-jhubbard@nvidia.com> References: <20260912044400.677097-1-jhubbard@nvidia.com> X-NVConfidentiality: public Content-Transfer-Encoding: quoted-printable X-ClientProxiedBy: SJ0PR13CA0164.namprd13.prod.outlook.com (2603:10b6:a03:2c7::19) To DM3PR12MB9416.namprd12.prod.outlook.com (2603:10b6:0:4b::8) Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-MS-PublicTrafficType: Email X-MS-TrafficTypeDiagnostic: DM3PR12MB9416:EE_|PH8PR12MB7229:EE_ X-MS-Office365-Filtering-Correlation-Id: 12292143-3f94-472c-171b-08df108880b3 X-MS-Exchange-SenderADCheck: 1 X-MS-Exchange-AntiSpam-Relay: 0 X-Microsoft-Antispam: BCL:0;ARA:13230040|1800799024|7416014|376014|23010399003|366016|10067099003|6133799003|18002099003|5023799004|11063799006|56012099006|22082099003; X-Microsoft-Antispam-Message-Info: K9vFKScVuZqnJ4ZBGbr/DpTkyKEUV893+tzZ0kxhw1ujgvjouT6R/50zhuGPHUGwFaujOeTaECw/TLt02on1snHK5dSGJ60Yw+RZcUtEtdfpc5xw7G7+nISqE6MfJGUTTjESJ8jk/rV4L+J+Gv0+HPmYXsvoBSCAE+IfNkjKzm7DpU1kIaxE+jnmIiHw18a7/M7i+opDOeBzLElSd+fHPN0Rd9bqbE2U0RtwOhH4nLG4NuRx7pUc6RWKPxOLR5elnCI8sl+1ehFqtF/VktZ/Z/2j2b06uar777cdQutoafFWZ7oCyimAs3Pn5GW40A078adkHL8oVkeBHabcSAM0DlRw96JgeVtMteo65DXwJ1Vc88qoqoYp21R50zskqdPQD8hGVq4eQBfkxISiaFxU+GXY5R0MK2oiZkcEeoEQ0JKtlqadLcYHhsSOwgUakh4SaLOcVmpXCwAW+0UmAqQq8A+sQT7peVJwK6CfJYla1fzhazkbz26JNxLl8nDurmNSg+XW49hda59HmT03UqYJi1O1SLUXmrOHa3Lgdxx6YRvtrKWsxiTgjJXeXagzwua15pLHeDqNTIXGiw9ReOgX0NmXD/4O3oiWHntTlvHRYRJ1tsOUnNxjgzqpVAuufuXpVHrz8LYPaLQ7ar0G7ZSqgF3S5lPzvl25i6pI968cifI= X-Forefront-Antispam-Report: CIP:255.255.255.255;CTRY:;LANG:en;SCL:1;SRV:;IPV:NLI;SFV:NSPM;H:DM3PR12MB9416.namprd12.prod.outlook.com;PTR:;CAT:NONE;SFS:(13230040)(1800799024)(7416014)(376014)(23010399003)(366016)(10067099003)(6133799003)(18002099003)(5023799004)(11063799006)(56012099006)(22082099003);DIR:OUT;SFP:1101; X-MS-Exchange-AntiSpam-MessageData-ChunkCount: 1 X-MS-Exchange-AntiSpam-MessageData-0: =?us-ascii?Q?jj7EybpZ0Z6jvwO+wLwRCCCVu2/p/7vLNFTEXsvEopTQReHIrN86TU//lSWl?= =?us-ascii?Q?tFA2hgoGnRJLjMgcaF8+0iv/bgadZ0nMX0kskhoUpoF12JEE0UWzYpSpr8cV?= =?us-ascii?Q?C/D9bAgNnG8Qy/1mbqsQgZLG3NRMcMIlf0fk6WI4t6k4QQeNtgkMfhrkAcx1?= =?us-ascii?Q?cXxwEDa/qCgRb+tjgu6XvVAWlVR7a77rmtdsn8NNbkbWqa9hGwuPpCGKABNA?= =?us-ascii?Q?bBfAkEtN0HBi5+9XxRytxfXn0Xrw/Myn7GhnCD4tucS6nub8xormrQgbpgWU?= =?us-ascii?Q?A8vfX+jrOY+gj9iZt8B4rWyqdGNMJJOWUoN2p8d5Kt2MWp16cCZK85blLaOw?= =?us-ascii?Q?zYmYVOccBVDFwr5DV/ZSl9UyumcHiGnv1YvrEm7sstF6S/n5SIiyPwhGdQF/?= =?us-ascii?Q?59sR5wUUFEjbBCHH9iNXpoJY8Wrwa2lIc+9shEir4NwrCQZ6LZFnzORB4I0A?= =?us-ascii?Q?Ag+OUwHp0pbxOuBzCBv4vHCG7gYdhZ5rVPEuVBaKQGwqkrtTAsWI0Bw2cxT0?= =?us-ascii?Q?9Qoy3PaHZufoUNIs+s09ZrJaO7EwNbVV+FrzXkr5MlOD/GmpU4Mxg0VBe03d?= =?us-ascii?Q?s+6tpKOl2fQnokUy+RSvFhsogtLVtDXD96MH8gRW/nEjI1+flW1e6WZBKufq?= =?us-ascii?Q?pqJUnx3gLa2FUVHZNdeDxXmmkjdzMtQj1OEogj14kaxEj1hWD8Iw6gCbBztN?= =?us-ascii?Q?Py5duK9Slw+IHFXwRXyirAsZP1747Z9D4W1tk1bi2rY82tvYwG5tgmWF9cfF?= =?us-ascii?Q?ErhTS0OfYHuCo1mmYb/deckWRNlfYUU0YbIMdX/p0lRq4jYKxevQ8PlS2Fbs?= =?us-ascii?Q?kt5AhC/8/KwQWiEl/6pJAv2ye4MUkPCPCPsk5HQ0EdDF+MOaL3iceF8xpDta?= =?us-ascii?Q?/GTAQDNT/+O3bsqZoSUAedUguczvZAg5R52DFd33n6tuSledeDNNE8qCLgTN?= =?us-ascii?Q?utNtTkmzd5UH3OkT+4bpcEKOuYTyBMOkOeWPm3qN5liyG9ANMxn7a+xe34+e?= =?us-ascii?Q?b9hvZNHsZyzQOhP7cUn5kQmnACXtcob1+hHjWQFBK8AmxEidAt/ZPWUcWvNF?= =?us-ascii?Q?yDDSvv8pboukh5XdaoZ1e3IHd4MgwUhodHZy8KWDuGUkaKp7hsFRK0O39GyD?= =?us-ascii?Q?9/47k5SBnE7WyxgyNH142xj4p8H6gQWeoOO/KBx01r+tUOYm1zPqieG6tmi0?= =?us-ascii?Q?JjXh2iCEaxhfWQNSV8wbMenjk3ABeyc6oOo9vVTTKIIk/VWSMO6LPSRQxJuK?= =?us-ascii?Q?3YY9u9ZBEJu0qaeRJWrJP728Hwf1KetD5c5dg0df9wj7bDW0u0ppAMQKpd6V?= =?us-ascii?Q?1s3lnzb4Mn5tawc0xlikJPI9AJjQv18BCrG+R11L1W9cGElbe+zOmKXX7jhZ?= =?us-ascii?Q?HXvGK0Mad4uKwgS1RlLHzrSA2Z8K0hOuvtfk87pUIDAWLquXc0CmCDKxXPEm?= =?us-ascii?Q?tvxW8StUZEtp74ncWWcucxnxmytn/fRVkqA2uhvhPMCnQ5C9x+vPPuDyhjQd?= =?us-ascii?Q?YaoYZXas497Pu1f8lxaNU2Y/PiW/5Ci3f55oDkhn+Wn6yRKgFObrvZ7UPbcy?= =?us-ascii?Q?H12H9upowRVTQRrTgVNzyH9KSo+GfFcy2VPKNU7SssO8fbN9rfWv8wheo8pY?= =?us-ascii?Q?YU8EhRQraestx7ZMQ7glbTX//u4N4MdaZk+wr9uvNj6JoRsun8xZXPH54mci?= =?us-ascii?Q?ZWCWtw+WBGLgGC9U0l6pCnhrWqQJuR2l4B7BXX7PLoYdZ4wJjVn4vFmSh+lE?= =?us-ascii?Q?k5ERX+aTEA=3D=3D?= X-OriginatorOrg: Nvidia.com X-MS-Exchange-CrossTenant-Network-Message-Id: 12292143-3f94-472c-171b-08df108880b3 X-MS-Exchange-CrossTenant-AuthSource: DM3PR12MB9416.namprd12.prod.outlook.com X-MS-Exchange-CrossTenant-AuthAs: Internal X-MS-Exchange-CrossTenant-OriginalArrivalTime: 12 Sep 2026 04:44:17.2107 (UTC) X-MS-Exchange-CrossTenant-FromEntityHeader: Hosted X-MS-Exchange-CrossTenant-Id: 43083d15-7273-40c1-b7db-39efd9ccc17a X-MS-Exchange-CrossTenant-MailboxType: HOSTED X-MS-Exchange-CrossTenant-UserPrincipalName: N81cBd5vThFEe+kktIiWxUyaG2RsNJuk2y4/vvOJ/Lp+iLCXt0A5Au97Nu14nMl7SDWB8WIRUozVQUku/hmBbA== X-MS-Exchange-Transport-CrossTenantHeadersStamped: PH8PR12MB7229 Content-Type: text/plain; charset="utf-8" GIN is the GPU's interrupt controller. It latches each interrupt source in a two-level tree of LEAF registers summarized by TOP, and raises the PCI interrupt when an enabled vector in an enabled subtree becomes pending. A message-signaled interrupt is delivered once per edge, and pre-Hopper MSI rearms delivery by writing the end-of-interrupt register in the BAR0 mirror of PCI configuration space. Add the CPU tree registers that receiving GSP interrupts and running the software-triggered self-test need: the leaf pending and enable arrays, the TOP enables, and the leaf trigger. Add the end-of-interrupt register, NV_XVE_CYA_2, alongside them. Use the NV_VIRTUAL_FUNCTION_PRIV_CPU_INTR_* names on every part. The pre-Hopper headers call the same tree NV_CTRL, but each function reaches its own tree through this aperture on both families. Declare the leaf arrays at 16 entries, the widest tree any supported part implements. Later patches bound every access by the part's leaf count. Leave the read-only TOP summary undeclared. A vector that latched while disabled does not appear in TOP, so nova-core never descends from it and reads every implemented leaf instead. Declare each leaf field as a set of vectors within one leaf and each TOP field as a set of subtrees, so a set of subtrees cannot be written to a leaf register, nor the reverse. The trigger register's vector field is 12 bits wide, wider than any GIN vector, so a vector converts into it infallibly. Assisted-by: LLM Reviewed-by: Will Pierce Signed-off-by: John Hubbard --- drivers/gpu/nova-core/irq.rs | 1 + drivers/gpu/nova-core/irq/interrupt_tree.rs | 14 ++++ drivers/gpu/nova-core/irq/regs.rs | 87 +++++++++++++++++++++ 3 files changed, 102 insertions(+) create mode 100644 drivers/gpu/nova-core/irq/regs.rs diff --git a/drivers/gpu/nova-core/irq.rs b/drivers/gpu/nova-core/irq.rs index f1323f633a03..1ec0bb055d3b 100644 --- a/drivers/gpu/nova-core/irq.rs +++ b/drivers/gpu/nova-core/irq.rs @@ -10,3 +10,4 @@ //! See `Documentation/gpu/nova/core/interrupts.rst`. =20 mod interrupt_tree; +mod regs; diff --git a/drivers/gpu/nova-core/irq/interrupt_tree.rs b/drivers/gpu/nova= -core/irq/interrupt_tree.rs index 24976a3146be..5c7829ea3bc5 100644 --- a/drivers/gpu/nova-core/irq/interrupt_tree.rs +++ b/drivers/gpu/nova-core/irq/interrupt_tree.rs @@ -16,6 +16,8 @@ =20 use crate::num; =20 +use super::regs::*; + /// Number of vectors one leaf register carries, one per bit. const VECTORS_PER_LEAF: u32 =3D u32::BITS; =20 @@ -31,6 +33,12 @@ /// Number of bits needed to address every vector in the widest supported = tree. const VECTOR_BITS: u32 =3D (MAX_NUM_LEAVES * VECTORS_PER_LEAF).ilog2(); =20 +/// Width of the vector field in the leaf trigger register. +const TRIGGER_VECTOR_BITS: u32 =3D { + let range =3D NV_VIRTUAL_FUNCTION_PRIV_CPU_INTR_LEAF_TRIGGER::VECTOR_R= ANGE; + num::u8_as_u32(*range.end() - *range.start() + 1) +}; + /// Index of a leaf register within the widest supported tree. An 8-leaf t= ree implements only the /// lower half of the range. pub(super) type LeafIndex =3D Bounded; @@ -236,3 +244,9 @@ pub(super) const fn validate(self, leaves: LeafCount) -= > Result { Ok(()) } } + +impl From for Bounded { + fn from(vector: GinVector) -> Self { + vector.0.extend() + } +} diff --git a/drivers/gpu/nova-core/irq/regs.rs b/drivers/gpu/nova-core/irq/= regs.rs new file mode 100644 index 000000000000..eef28425a74a --- /dev/null +++ b/drivers/gpu/nova-core/irq/regs.rs @@ -0,0 +1,87 @@ +// SPDX-License-Identifier: GPL-2.0 +// SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIA= TES. All rights reserved. + +use kernel::io::register; + +use crate::driver::NovaRegisters; + +use super::interrupt_tree::{ + LeafMask, + SubtreeSet, // +}; + +// The GIN CPU interrupt tree, reached through the `NV_VIRTUAL_FUNCTION_PR= IV` aperture. See +// "Register naming" in `Documentation/gpu/nova/core/interrupts.rst`. The = leaf arrays are declared +// with 16 entries, the widest tree any supported part implements. + +register! { + base: NovaRegisters; + + /// Pending bits of one leaf, one per vector. + /// + /// Vector `v` is bit `v % 32` of leaf `v / 32`. The bit is set when t= he vector's source + /// drives it, whether or not the vector is enabled. Writing a `1` cle= ars the bit, and a `0` + /// leaves it as it was. + pub(super) NV_VIRTUAL_FUNCTION_PRIV_CPU_INTR_LEAF(u32)[16] @ 0x00b8100= 0 { + /// The vectors pending in this leaf. + 31:0 vectors =3D> LeafMask; + } + + /// Enables vectors of one leaf. + /// + /// A `1` enables the matching vector, and a `0` leaves it as it was. + pub(super) NV_VIRTUAL_FUNCTION_PRIV_CPU_INTR_LEAF_EN_SET(u32)[16] @ 0x= 00b81200 { + /// Vectors to enable. + 31:0 vectors =3D> LeafMask; + } + + /// Disables vectors of one leaf. + /// + /// A `1` disables the matching vector, and a `0` leaves it as it was.= A disabled vector still + /// latches in `LEAF`, and `TOP` does not show it. + pub(super) NV_VIRTUAL_FUNCTION_PRIV_CPU_INTR_LEAF_EN_CLEAR(u32)[16] @ = 0x00b81400 { + /// Vectors to disable. + 31:0 vectors =3D> LeafMask; + } + + /// Enables subtrees. + /// + /// Bit `N` covers subtree `N`, which is leaves `2N` and `2N + 1`. A `= 1` enables the matching + /// subtree, and a `0` leaves it as it was. + /// + /// The hardware headers declare a one-element array, so nova-core dec= lares a scalar. + pub(super) NV_VIRTUAL_FUNCTION_PRIV_CPU_INTR_TOP_EN_SET(u32) @ 0x00b81= 608 { + /// Subtrees to enable. + 31:0 subtrees =3D> SubtreeSet; + } + + /// Disables subtrees, with the bit layout of `TOP_EN_SET`. + /// + /// A `1` disables the matching subtree, and a `0` leaves it as it was= . A disabled subtree + /// delivers nothing, and `TOP` still reports it. + pub(super) NV_VIRTUAL_FUNCTION_PRIV_CPU_INTR_TOP_EN_CLEAR(u32) @ 0x00b= 81610 { + /// Subtrees to disable. + 31:0 subtrees =3D> SubtreeSet; + } + + /// Latches a vector from software. Write-only. + /// + /// The written vector latches in its `LEAF` register as its own sourc= e would, and reaches the + /// CPU under the same enables. Implemented on every supported part. + pub(super) NV_VIRTUAL_FUNCTION_PRIV_CPU_INTR_LEAF_TRIGGER(u32) @ 0x00b= 81640 { + /// Vector to latch. + 11:0 vector; + } +} + +// PCI configuration-space mirror in BAR0. + +register! { + base: NovaRegisters; + + /// MSI end-of-interrupt register. Writing any value rearms MSI delive= ry. + /// + /// Only pre-Hopper MSI rearms through this register. See "Rearming PC= I interrupt delivery" + /// in `Documentation/gpu/nova/core/interrupts.rst`. + pub(super) NV_XVE_CYA_2(u32) @ 0x00088704 {} +} --=20 2.55.0 From nobody Fri Sep 25 13:19:17 2026 Received: from BYAPR05CU005.outbound.protection.outlook.com (mail-westusazon11010052.outbound.protection.outlook.com [52.101.85.52]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id EC043377561 for ; Sat, 12 Sep 2026 04:44:28 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=fail smtp.client-ip=52.101.85.52 ARC-Seal: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1789188270; cv=fail; b=mBj0+U7wEwqRiE1WgGTA5v/qHAbMP0I81eX3prtKYK5C7s8gdoxExRXyeOwApQmQagZycCq5OEF5/cccNDpj6YoSmhvN6zWRNM8DbcQRqSUDdKR0MV1ks9a4ZbRfwRo9/N/Qr+2Bu6LE4qoDeZGuj6QvcbO7Gs4Y21NQW/zltH0= ARC-Message-Signature: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1789188270; c=relaxed/simple; bh=ncuORM5I/wFkLOtgfTahuV/b6wiNVmajwVj2Dxq4fDs=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: Content-Type:MIME-Version; b=ZvAyJesQ/32ceWV6qB7mPGboYVKokQ2CB1q6SxokdhsZMAWxD54P7C1gWkiE4ZSnluVLlNZazrh2LwOql8tVovLyaZyt3j0+CkFGXOTMfDaNGfLKV+EpCQhCzx72mK6QDcUeT3h/Q//dx58xNjz7aAxu+hLfKV2mCRJ3Lq6+qOs= ARC-Authentication-Results: i=2; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=nvidia.com; spf=fail smtp.mailfrom=nvidia.com; dkim=pass (2048-bit key) header.d=Nvidia.com header.i=@Nvidia.com header.b=GhUQseT9; arc=fail smtp.client-ip=52.101.85.52 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=nvidia.com Authentication-Results: smtp.subspace.kernel.org; spf=fail smtp.mailfrom=nvidia.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=Nvidia.com header.i=@Nvidia.com header.b="GhUQseT9" ARC-Seal: i=1; a=rsa-sha256; s=arcselector10001; d=microsoft.com; cv=none; b=AxDVf6q7JQ6iI8XJbKGwGk99RKQYkhUF352b+URLUxYwfPbFS9oMuHLiTQTK2oYxtR1BpDwt7F/Gjo6Ag5w2iVGpiiWzEfSjpUrTsK3wYm/ncv9tEsd0rYFWWvkLrRQT0vR1OATs6ei6cwrWPr6uaGMsWP8tlW2BH+njmiOb/5N4y+fTdeaMzJ1MTLg/QD5Uuxoctv3hkZmbsHF5AlB43ZRJGAivDRJn7MKXTwdTWG43dEJwhlg7iAWvol2e1zhSMsMdDUDdXTeBLjDzxzOXcpZDsC1JKS2N9iWFrYGJhcOf00Nhx089x9LXS6c3lYS0d5aBxAxTRcpIBdzplVq0aQ== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=microsoft.com; s=arcselector10001; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-AntiSpam-MessageData-ChunkCount:X-MS-Exchange-AntiSpam-MessageData-0:X-MS-Exchange-AntiSpam-MessageData-1; bh=TXNSJIo648/BsZ8HBIDYNokMrPkgxRiMuNd3BXsEtBQ=; b=pieMwp2g7iLB+NtjiogEWWBfM0UKZ/bnMvc5vKVGwdiovYn/c40e/4PaMufVu0hcb8isFysKQgrsCGSdSOKu7MTvnTH5xvia8A5FkiPWG7ZUlKj9iX+HQn6mrP6rOK/HCmL2P57Y9xOW8fhiixQeoCByk9ofOX68797t2pDaYlZ9Rp72KCaDVYShxSfB80X2LA9jUKyvF9HfCAUf0JZU6YXWXxsfs/DlDCGV2xnKGW7/TUusCXxJ/6sAt8RGtKZ8BN1PoAsBznRYjzJblYvZZSQbaB/e+fdqvTjzr+f2q1VlBWm1ZdJvtvclW55O9KzwhViKi4Gdq12l5mOhh+LYnQ== ARC-Authentication-Results: i=1; mx.microsoft.com 1; spf=pass smtp.mailfrom=nvidia.com; dmarc=pass action=none header.from=nvidia.com; dkim=pass header.d=nvidia.com; arc=none DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=Nvidia.com; s=selector2; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck; bh=TXNSJIo648/BsZ8HBIDYNokMrPkgxRiMuNd3BXsEtBQ=; b=GhUQseT9jq0itR1MW0p7IBVSfdtW+8IhCpfYHKNw/sLKATcvTr0MZlDbhQZaFbE/xzA/QYlfr5TMTpbUre+YjPr67YuBVUNqonCLFDp6kygF/k+P3ycjb34QwEAgAK9nPVoYRrfxfOOtYO6TzxQsNGjJLicFOl26nXhFPUbZmsmpGDG2QZbHe7uazP87RHKsrWEGNkj2xIXeM4dmUmJsnXV1ZJH450AS1CzCLC5hVPLa2QII61ORXToPdtJQZIBJTJrMQL4FHyNFQsAGvDDbYh5eO9ZHtTIdBbB5kXZ1xm9MoHr0t3NI7tUzRT//QOJ++w9toBrVSEzODZ2Lrc0l6g== Authentication-Results: dkim=none (message not signed) header.d=none;dmarc=none action=none header.from=nvidia.com; Received: from DM3PR12MB9416.namprd12.prod.outlook.com (2603:10b6:0:4b::8) by PH8PR12MB7229.namprd12.prod.outlook.com (2603:10b6:510:227::20) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.21.406.10; Sat, 12 Sep 2026 04:44:18 +0000 Received: from DM3PR12MB9416.namprd12.prod.outlook.com ([fe80::8cdd:504c:7d2a:59c8]) by DM3PR12MB9416.namprd12.prod.outlook.com ([fe80::8cdd:504c:7d2a:59c8%4]) with mapi id 15.21.0406.007; Sat, 12 Sep 2026 04:44:18 +0000 From: John Hubbard To: Danilo Krummrich , Alexandre Courbot Cc: Timur Tabi , Alistair Popple , Eliot Courtney , Zhi Wang , David Airlie , Simona Vetter , Bjorn Helgaas , Miguel Ojeda , Alex Gaynor , Boqun Feng , Gary Guo , =?UTF-8?q?Bj=C3=B6rn=20Roy=20Baron?= , Benno Lossin , Andreas Hindborg , Alice Ryhl , Trevor Gross , nova-gpu@lists.linux.dev, LKML , John Hubbard , Will Pierce Subject: [PATCH v4 05/17] gpu: nova-core: add the per-architecture GIN CPU interrupt HAL Date: Fri, 11 Sep 2026 21:43:48 -0700 Message-ID: <20260912044400.677097-6-jhubbard@nvidia.com> X-Mailer: git-send-email 2.55.0 In-Reply-To: <20260912044400.677097-1-jhubbard@nvidia.com> References: <20260912044400.677097-1-jhubbard@nvidia.com> X-NVConfidentiality: public Content-Transfer-Encoding: quoted-printable X-ClientProxiedBy: BYAPR21CA0007.namprd21.prod.outlook.com (2603:10b6:a03:114::17) To DM3PR12MB9416.namprd12.prod.outlook.com (2603:10b6:0:4b::8) Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-MS-PublicTrafficType: Email X-MS-TrafficTypeDiagnostic: DM3PR12MB9416:EE_|PH8PR12MB7229:EE_ X-MS-Office365-Filtering-Correlation-Id: 00a7e667-4dc8-4681-8a5a-08df1088815b X-MS-Exchange-SenderADCheck: 1 X-MS-Exchange-AntiSpam-Relay: 0 X-Microsoft-Antispam: BCL:0;ARA:13230040|1800799024|7416014|376014|23010399003|366016|10067099003|6133799003|18002099003|5023799004|11063799006|56012099006|22082099003; X-Microsoft-Antispam-Message-Info: lh7b7KqV+on2D0Tc9arNiLpGCF+D7hw4skDhnSmbleY78ORFxvzQCdYU6vPt//BkbDux/Xf0otgqEBLPDxMQqitCCuJxXh4bz8ZgOeHBMmC6jJgQcxzctv9f/9qMF2P9QNRNN9lmp8YOOxrEp6Ct7OgFRHm9vpIhLoorH5rua/jKXxJlZkbHFX2R1JkvKKX/DQWIRzhmpYFpFeT0whjfCs0hh4ND2y2/TxlNJ5mJtNqBk30itry2WVnB5mKUYI/c6DYnuWzrwzNHfBbgbup+tD8x45N22eZCBviFw+leXsh8yHd9SvSg/gRC9FIfy9YrHgaNUIhawSxX9i9R1SlLs6nhzY+7dR6JM3ML3D2sTdzP4eKCBtBFnAYxSZ/4ZGJAnwN65r8vUKAlN/5VZHW0r8XgYSo82Re5qnqSIKEfWayigZJVIZWVOCtb4d8NpUawehDGWhBXYLdxXFcU3mA/5RpNrYrgg2jIWIX50we6B3bPo8SNXaJ0qqSnRocunt9syCLUqxKmmw3tPfcAGJjCFOjeJR6h8NHmS/RhlLIzoWZoqdfdkOSLcUHVKzzzEJg+b56VwbFPzSGxbAQiuC3cK/HqfqSyd7/DcFoyRIJkznH0t2f0xnDfaFiSZElkKyjG7C8POgtghDtJV+OeEKojFH9+POsAdMQUODUoMTiwYj8= X-Forefront-Antispam-Report: CIP:255.255.255.255;CTRY:;LANG:en;SCL:1;SRV:;IPV:NLI;SFV:NSPM;H:DM3PR12MB9416.namprd12.prod.outlook.com;PTR:;CAT:NONE;SFS:(13230040)(1800799024)(7416014)(376014)(23010399003)(366016)(10067099003)(6133799003)(18002099003)(5023799004)(11063799006)(56012099006)(22082099003);DIR:OUT;SFP:1101; X-MS-Exchange-AntiSpam-MessageData-ChunkCount: 1 X-MS-Exchange-AntiSpam-MessageData-0: =?us-ascii?Q?1axgLAAQ9AFK3IGOq1LSvQ+ISky3oJCTxjbDt/BNr0TEgguwnjuhCxkgvdlB?= =?us-ascii?Q?oF6TZH10PIB2dpC9X7GUe5uvqRRXlDkt2PXX7uoiQQmGb9EEVxa0xpln2G31?= =?us-ascii?Q?ZyDOoVF8xpjDYRnzJCVBfPz01ZNyQ/hIuofs01RqtdjagZnns2G2ufXqYzfi?= =?us-ascii?Q?DQrWBvMHfQgbsP1ZAtj6gfzEqBkJ12/7OteS2kuHrnmSgCvCcPcxHjFadf4C?= =?us-ascii?Q?AygePB4b/lI2hNSZDuzXJTGLntcirIUh0MtFp1FYaPbQOU0c/xkDxeaeJqqt?= =?us-ascii?Q?Me4QJCFfJknIqrc+Kd4hu8YT+vqAemJxCMgco0YsKW/ERFtPk9ux4JqCuGQf?= =?us-ascii?Q?xKPCfD3hZ5w0sPdOEtZtgnUlRuq8UlK1Ci1DT/8qo1+1Scuw9+/rO5cmXQ7G?= =?us-ascii?Q?9vm8ipeCLEAdjnSrWwocxneIyPi9urqzZjwNo/h2uhbqp4Zx45GXVyZFOqff?= =?us-ascii?Q?lT/DwRJ2QMt3Ur2944iqugWkeyYVap89IjcMchr9d1v89SXGB0nyK0eXP0bJ?= =?us-ascii?Q?JJp/q2p3uQbok+hOUucFRzCKVWoH+71dpKYRY+Dbdn2XPAuU3RD/snkgTbWy?= =?us-ascii?Q?KeJIRIfLlDJoB6weNvoYsYGbAnHEhIiYC8eKIPeKhHO/iANkh4KIL+5ONwfi?= =?us-ascii?Q?vaWnewODi+r3LiiUIr8AG1ZBsd3Nqn66hZyxQmQu66NQK53W3fMxFpu3mquA?= =?us-ascii?Q?BXiPj+tDxtNYjsob/58NTdqaYfjw6ikgtddDbA8an0TS1IDulrwF068Bmg3a?= =?us-ascii?Q?/25YAn+29zcROIFzeXO8FaudBr0sgWjxfL/H2O15u3CM5DnyUYZLYD4I+0Ke?= =?us-ascii?Q?A4fu3hOu2sE0E4DTS+JgPbwC6uGEkAgCe9woYmEx8ew2gqmKKAT2jTLIFiFG?= =?us-ascii?Q?qd43wJFW1hKTiKp10yJEBlecMDtS/nY7VI0rC4h7d6lq6RkZYSz0ZXI3rNv+?= =?us-ascii?Q?S2hCMs4HMBn2M7AcMwGVmQIA8Kzd1xrrvfmKc+en0vZKOYZGP8NUmEuI+/xc?= =?us-ascii?Q?DQFTYrt8lc56RMWmLmIxSk5CobzMWw/DuhafkLMHMDwKGJ3sO5DRNH0YIimj?= =?us-ascii?Q?K/wGB48kOsJrbim/bDA6K67Msmyu1hI/g3gqnVyCz2nnSc+yQjE3ua+bvzun?= =?us-ascii?Q?CQ91L+ZAy7UxHY09SgBh2oitSzpw+lDuvCmV3B0AS7ITj3NrFGQuXut6mUzf?= =?us-ascii?Q?H+cUski8yKQT/UafRYU3WoBglqjF36OKOSRp1WhCs5lSbC4gM2vl6TA82PTZ?= =?us-ascii?Q?mUeLLAp+TjUMuQVEFgVY6CM9KDwWOuF4Zllbggu+BTmCH3r+KIWR/xvr7eEi?= =?us-ascii?Q?4FFGavxl3xH3tqTbNxpfO6kFQt+2kDs6iQXIz6nb+3dNLoBlJeM6E/2WdoXI?= =?us-ascii?Q?u88Hwm3WunvDFRC1PAS2IUjAQiqIwcbbFyFgyhiHrqfYrhxeMFaBWzLctBU4?= =?us-ascii?Q?RYgFBwHqo87T1nWhjA+Fb3LAORrp9zzAMKPhaMCuw8d6Qgs8bvl6yKrkVfkm?= =?us-ascii?Q?KnlVeXJYm+7+d5xjUR4PTXcZ6OQXJfgAKUoZReJcFDuZeXAIJfcCqyqHtRaz?= =?us-ascii?Q?1umqblOtkmsShtlZmuyeLcHTKscUyxfW1GiA8+kd2/nNxtuZbWhfzrAmHmX3?= =?us-ascii?Q?vUrpwb9TSsm+Ii+4Nx8F9KqW274MpaXAoWXT5S80n+SmchM4EqmdA5sWVcNZ?= =?us-ascii?Q?flcTy9dbBmzTx/sc8tNVZ5q0xtfyNmPguVQ8B4dX4jnybjOq1mtg4SJXajh+?= =?us-ascii?Q?KvNBC88avA=3D=3D?= X-OriginatorOrg: Nvidia.com X-MS-Exchange-CrossTenant-Network-Message-Id: 00a7e667-4dc8-4681-8a5a-08df1088815b X-MS-Exchange-CrossTenant-AuthSource: DM3PR12MB9416.namprd12.prod.outlook.com X-MS-Exchange-CrossTenant-AuthAs: Internal X-MS-Exchange-CrossTenant-OriginalArrivalTime: 12 Sep 2026 04:44:18.3141 (UTC) X-MS-Exchange-CrossTenant-FromEntityHeader: Hosted X-MS-Exchange-CrossTenant-Id: 43083d15-7273-40c1-b7db-39efd9ccc17a X-MS-Exchange-CrossTenant-MailboxType: HOSTED X-MS-Exchange-CrossTenant-UserPrincipalName: k6lDPbIPBfpeDW23J9c/p8H+E5XjKDspsTQSKXIyDUGSOyvNuN5T8hXguuy+uhbwaekj6yYB+hf7fH5RU+TMWg== X-MS-Exchange-Transport-CrossTenantHeadersStamped: PH8PR12MB7229 Content-Type: text/plain; charset="utf-8" The GIN CPU interrupt tree differs by GPU family in two ways: * The size of the tree. Turing through Ada implement 8 leaves, and Hopper and later implement 16. * The write that rearms delivery. A message-signaled interrupt is delivered once per edge, and the PCI side delivers nothing more until the CPU rearms it. Before Hopper, MSI rearms by writing the end-of-interrupt register in the BAR0 mirror of PCI configuration space. On Hopper and later, MSI rearms by clearing and then setting the TOP enables of every serviced subtree, which produces a new edge. MSI-X rearms the same way on every family, but for the handler's own subtree only, since each subtree has its own table entry. Add an interrupt HAL that provides the leaf count and the rearm method for each family. Name the interrupt type with two variants, MSI and MSI-X, since nova-core never allocates the level-triggered INTx that the PCI core's type also names. Assisted-by: LLM Reviewed-by: Will Pierce Signed-off-by: John Hubbard --- drivers/gpu/nova-core/irq.rs | 13 ++++ drivers/gpu/nova-core/irq/hal.rs | 90 ++++++++++++++++++++++++++ drivers/gpu/nova-core/irq/hal/gh100.rs | 28 ++++++++ drivers/gpu/nova-core/irq/hal/tu102.rs | 28 ++++++++ 4 files changed, 159 insertions(+) create mode 100644 drivers/gpu/nova-core/irq/hal.rs create mode 100644 drivers/gpu/nova-core/irq/hal/gh100.rs create mode 100644 drivers/gpu/nova-core/irq/hal/tu102.rs diff --git a/drivers/gpu/nova-core/irq.rs b/drivers/gpu/nova-core/irq.rs index 1ec0bb055d3b..62c242b71dc8 100644 --- a/drivers/gpu/nova-core/irq.rs +++ b/drivers/gpu/nova-core/irq.rs @@ -9,5 +9,18 @@ //! //! See `Documentation/gpu/nova/core/interrupts.rst`. =20 +mod hal; mod interrupt_tree; mod regs; + +/// The message-signaled interrupt type that Linux granted. +/// +/// nova-core never requests INTx, so this has no variant for it, unlike [= `kernel::pci::IrqType`]. +#[derive(Clone, Copy, Debug, Eq, PartialEq)] +enum MsiType { + /// A single message, which every subtree raises. + Msi, + + /// One table entry per subtree. + MsiX, +} diff --git a/drivers/gpu/nova-core/irq/hal.rs b/drivers/gpu/nova-core/irq/h= al.rs new file mode 100644 index 000000000000..ede9a10ccda6 --- /dev/null +++ b/drivers/gpu/nova-core/irq/hal.rs @@ -0,0 +1,90 @@ +// SPDX-License-Identifier: GPL-2.0 +// SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIA= TES. All rights reserved. + +//! Per-architecture properties of the GIN CPU interrupt tree. +//! +//! See "Per-architecture differences" in `Documentation/gpu/nova/core/int= errupts.rst`. + +mod gh100; +mod tu102; + +use kernel::{ + io::Io, + prelude::*, // +}; + +use crate::{ + driver::Bar0, + gpu::{ + Architecture, + Chipset, // + }, // +}; + +use super::{ + interrupt_tree::{ + LeafCount, + Subtree, + SubtreeSet, // + }, + regs::*, + MsiType, // +}; + +/// The register write that rearms PCI interrupt delivery after an interru= pt. +/// +/// The GPU family and the interrupt type that Linux granted select the wr= ite. See "Rearming PCI +/// interrupt delivery" in `Documentation/gpu/nova/core/interrupts.rst`. +#[derive(Clone, Copy, Debug, Eq, PartialEq)] +pub(super) enum PciIrqRearmMethod { + /// Writes the MSI end-of-interrupt register, `NV_XVE_CYA_2`. Pre-Hopp= er MSI. + ConfigMirrorEoi, + + /// Clears and then sets the `TOP` enables of every serviced subtree. = Hopper-plus MSI. + TopEnableCycleServiced, + + /// Clears and then sets the `TOP` enable of the handler's own subtree= . MSI-X. + TopEnableCycleSubtree, +} + +impl PciIrqRearmMethod { + /// Rearms PCI interrupt delivery after a handler serviced `subtree`. + /// + /// `serviced` is every subtree that nova-core services, for the metho= d that cycles them all. + pub(super) fn rearm(self, bar: Bar0<'_>, serviced: SubtreeSet, subtree= : Subtree) { + let subtrees =3D match self { + Self::ConfigMirrorEoi =3D> { + bar.write(NV_XVE_CYA_2, 0u32.into()); + return; + } + Self::TopEnableCycleServiced =3D> serviced, + Self::TopEnableCycleSubtree =3D> SubtreeSet::from(subtree), + }; + + bar.write_reg( + NV_VIRTUAL_FUNCTION_PRIV_CPU_INTR_TOP_EN_CLEAR::zeroed().with_= subtrees(subtrees), + ); + bar.write_reg( + NV_VIRTUAL_FUNCTION_PRIV_CPU_INTR_TOP_EN_SET::zeroed().with_su= btrees(subtrees), + ); + } +} + +/// The properties of the GIN CPU tree that differ by GPU family. +pub(super) trait CpuInterruptHal { + /// Returns the number of leaves the tree implements. + fn leaf_count(&self) -> LeafCount; + + /// Returns the rearm method for `msi_type`. + fn pci_irq_rearm_method(&self, msi_type: MsiType) -> PciIrqRearmMethod; +} + +/// Returns the [`CpuInterruptHal`] for `chipset`'s architecture. +pub(super) fn cpu_interrupt_hal(chipset: Chipset) -> &'static dyn CpuInter= ruptHal { + match chipset.arch() { + Architecture::Turing | Architecture::Ampere | Architecture::Ada = =3D> tu102::TU102_HAL, + Architecture::Hopper | Architecture::BlackwellGB10x | Architecture= ::BlackwellGB20x =3D> { + gh100::GH100_HAL + } + } +} diff --git a/drivers/gpu/nova-core/irq/hal/gh100.rs b/drivers/gpu/nova-core= /irq/hal/gh100.rs new file mode 100644 index 000000000000..dd3d0d12d779 --- /dev/null +++ b/drivers/gpu/nova-core/irq/hal/gh100.rs @@ -0,0 +1,28 @@ +// SPDX-License-Identifier: GPL-2.0 +// SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIA= TES. All rights reserved. + +use super::{ + CpuInterruptHal, + LeafCount, + MsiType, + PciIrqRearmMethod, // +}; + +/// The CPU interrupt tree properties of Hopper and Blackwell. +struct Gh100; + +impl CpuInterruptHal for Gh100 { + fn leaf_count(&self) -> LeafCount { + LeafCount::Sixteen + } + + fn pci_irq_rearm_method(&self, msi_type: MsiType) -> PciIrqRearmMethod= { + match msi_type { + MsiType::Msi =3D> PciIrqRearmMethod::TopEnableCycleServiced, + MsiType::MsiX =3D> PciIrqRearmMethod::TopEnableCycleSubtree, + } + } +} + +const GH100: Gh100 =3D Gh100; +pub(super) const GH100_HAL: &dyn CpuInterruptHal =3D &GH100; diff --git a/drivers/gpu/nova-core/irq/hal/tu102.rs b/drivers/gpu/nova-core= /irq/hal/tu102.rs new file mode 100644 index 000000000000..121f5779accf --- /dev/null +++ b/drivers/gpu/nova-core/irq/hal/tu102.rs @@ -0,0 +1,28 @@ +// SPDX-License-Identifier: GPL-2.0 +// SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIA= TES. All rights reserved. + +use super::{ + CpuInterruptHal, + LeafCount, + MsiType, + PciIrqRearmMethod, // +}; + +/// The CPU interrupt tree properties of Turing, Ampere, and Ada. +struct Tu102; + +impl CpuInterruptHal for Tu102 { + fn leaf_count(&self) -> LeafCount { + LeafCount::Eight + } + + fn pci_irq_rearm_method(&self, msi_type: MsiType) -> PciIrqRearmMethod= { + match msi_type { + MsiType::Msi =3D> PciIrqRearmMethod::ConfigMirrorEoi, + MsiType::MsiX =3D> PciIrqRearmMethod::TopEnableCycleSubtree, + } + } +} + +const TU102: Tu102 =3D Tu102; +pub(super) const TU102_HAL: &dyn CpuInterruptHal =3D &TU102; --=20 2.55.0 From nobody Fri Sep 25 13:19:17 2026 Received: from SN4PR2101CU001.outbound.protection.outlook.com (mail-southcentralusazon11012058.outbound.protection.outlook.com [40.93.195.58]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 1578637F8AF for ; Sat, 12 Sep 2026 04:44:30 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=fail smtp.client-ip=40.93.195.58 ARC-Seal: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1789188272; cv=fail; b=tUSYPPjeJKyyOmChMscJYMexxcIoDhjMffSbCZ8QctguOpqKj7JsUMRT49FGDvM72dDYNPt3GUdAreF3gTxEl0BJtvh5ojMQyX6Am5hUiTv06W2POnz8admV/XXCZMu2EJ5D0nL/BfGtvEyl3l4SoEn2ueWnT/nfsyv5jyVlSkM= ARC-Message-Signature: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1789188272; c=relaxed/simple; bh=EBHFwJ7BHDAuR0RzIDavJ41sbypStEcdPgX6ApNtB6o=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: Content-Type:MIME-Version; b=WsFjHcLtvLy8xE1iOEExjECz7xLmBNndlMiiJnl5OjEI8ZBecJto2GWzGJbjBAxOdSWKVHl+IL3Xjv0HC/pS96AzEh5E+Wsttc5MaM6yyYKrAMTVQ112RDG/gKuoWOw9QReNmQLQ4PIJIAXX+W1CIc3MAiwqFpOA/ntbAwGc6xc= ARC-Authentication-Results: i=2; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=nvidia.com; spf=fail smtp.mailfrom=nvidia.com; dkim=pass (2048-bit key) header.d=Nvidia.com header.i=@Nvidia.com header.b=YF9u/Wf3; arc=fail smtp.client-ip=40.93.195.58 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=nvidia.com Authentication-Results: smtp.subspace.kernel.org; spf=fail smtp.mailfrom=nvidia.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=Nvidia.com header.i=@Nvidia.com header.b="YF9u/Wf3" ARC-Seal: i=1; a=rsa-sha256; s=arcselector10001; d=microsoft.com; cv=none; b=uq1b8/h2zOKzBUWde8umtwvE0/pZRiTsJW/P4XnksQ+WUAEMnp3+1wGjGHwZCQU4iIxquNJ1XrhChMi95ZpkTvuJGxkrpDEQRseKjI07UnuKdpZ7Se0YCa0Z9g3Itv1W9tW390s4226CgVqnVOz1YJkYu5slgREwo1AEpDONdUM981V2N6s/wZwfLtx1p9DFInrIohL9Ikr9w1ZjopUUNdF0ElkTpLHe+ywRuIt4uri9CpwZOSQcumy/ReCav68XK3lMjNHNqBLVbG8vREYSqazkVCV8svv75eTtiMa3D+xCwsrHP5R9T6hf52urn55zR2JLtCDVExYIwrzqEaB1VA== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=microsoft.com; s=arcselector10001; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-AntiSpam-MessageData-ChunkCount:X-MS-Exchange-AntiSpam-MessageData-0:X-MS-Exchange-AntiSpam-MessageData-1; bh=rgzhN9a2rZNUYk5btN/VPDiHOOMOd24ZRtOy5I2DGb4=; b=iyj1BmjSp9cltBmhRauvt9lZ3GxXXoqi/eqy41f+ine9+enbuB31yNbWtsHQ5MLGmtJ8c8oAKajkUFJa2ecRLCqoWOxeZxUCu9Z2KbwFZ9+0wfYbJurGxly0GaKW+ptNixUngTDxpBxywWXM7xxK8k6nkADhxb12XxoJgbAAZcwJo7W+D0YSRUHrCwNgKq12Zt9KvU384l7oIMcmcTeuq86IaDp4IVG4+kQDXYL6lUM4jbHMuuIiHEB+zhu0OvFz2m3oE03dGk94sSKN4JMoTiPY0STXxl2ExZm+CsgAOwbY6LgBTjqr95Hf6GpHKN/gOSHchCE3TTtvKVUxHYUvCQ== ARC-Authentication-Results: i=1; mx.microsoft.com 1; spf=pass smtp.mailfrom=nvidia.com; dmarc=pass action=none header.from=nvidia.com; dkim=pass header.d=nvidia.com; arc=none DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=Nvidia.com; s=selector2; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck; bh=rgzhN9a2rZNUYk5btN/VPDiHOOMOd24ZRtOy5I2DGb4=; b=YF9u/Wf3IzWmXxKKevvioEm8Hu68vVrj0DSrwd41rwQ8dYA6LqG2yAP9vjGnrj3U5ldIZJXntpcLIcyiMKt/qlqk31Rr4BLcsWuB9APigvQbWq+TG+TiCXzO0LU1C/T1ZjFjmVvNnz9h27RzlULhenuRCbCt2lfNbyZif2kSoWJxfAuIGNruQCRZ0RYJVSp/jV8UZe+Retg4H0nZbXShI6lFcrcui+2fO1T+meLDb0r+f3ZF1b3Mo0qMoUq8rl8qb6FyPLAg1LJaBwKUQjiJa21I+h9fa0FLc82hAAnorC8TwXyBx4qZgTP/dgH55XymAHjnbH9j+KTfTTk1oqLI/g== Authentication-Results: dkim=none (message not signed) header.d=none;dmarc=none action=none header.from=nvidia.com; Received: from DM3PR12MB9416.namprd12.prod.outlook.com (2603:10b6:0:4b::8) by PH8PR12MB7229.namprd12.prod.outlook.com (2603:10b6:510:227::20) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.21.406.10; Sat, 12 Sep 2026 04:44:19 +0000 Received: from DM3PR12MB9416.namprd12.prod.outlook.com ([fe80::8cdd:504c:7d2a:59c8]) by DM3PR12MB9416.namprd12.prod.outlook.com ([fe80::8cdd:504c:7d2a:59c8%4]) with mapi id 15.21.0406.007; Sat, 12 Sep 2026 04:44:19 +0000 From: John Hubbard To: Danilo Krummrich , Alexandre Courbot Cc: Timur Tabi , Alistair Popple , Eliot Courtney , Zhi Wang , David Airlie , Simona Vetter , Bjorn Helgaas , Miguel Ojeda , Alex Gaynor , Boqun Feng , Gary Guo , =?UTF-8?q?Bj=C3=B6rn=20Roy=20Baron?= , Benno Lossin , Andreas Hindborg , Alice Ryhl , Trevor Gross , nova-gpu@lists.linux.dev, LKML , Joel Fernandes , John Hubbard , Will Pierce Subject: [PATCH v4 06/17] gpu: nova-core: add the GIN interrupt tree and allocate its vectors Date: Fri, 11 Sep 2026 21:43:49 -0700 Message-ID: <20260912044400.677097-7-jhubbard@nvidia.com> X-Mailer: git-send-email 2.55.0 In-Reply-To: <20260912044400.677097-1-jhubbard@nvidia.com> References: <20260912044400.677097-1-jhubbard@nvidia.com> X-NVConfidentiality: public Content-Transfer-Encoding: quoted-printable X-ClientProxiedBy: BY5PR03CA0012.namprd03.prod.outlook.com (2603:10b6:a03:1e0::22) To DM3PR12MB9416.namprd12.prod.outlook.com (2603:10b6:0:4b::8) Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-MS-PublicTrafficType: Email X-MS-TrafficTypeDiagnostic: DM3PR12MB9416:EE_|PH8PR12MB7229:EE_ X-MS-Office365-Filtering-Correlation-Id: a9c880dd-008f-41d2-7b90-08df10888212 X-MS-Exchange-SenderADCheck: 1 X-MS-Exchange-AntiSpam-Relay: 0 X-Microsoft-Antispam: BCL:0;ARA:13230040|1800799024|7416014|376014|23010399003|366016|10067099003|6133799003|18002099003|5023799004|11063799006|56012099006|22082099003; X-Microsoft-Antispam-Message-Info: qiMg85cYYmur8V1o8n6Bwnd9+X53pOmBHgROcMK0ObhlQxxytr4x4DCRLpM64SyksiPQWOtDRZ9eFFmRN8KbPqa+uzrvzcfNrHDsEdsY9o0rRRLlNyJ/KaKRgNzepgOI1A+iw/lgqD35vWkHYEAD2ko1iQGIR9DS5LhNWvcE3qEF0MBtzBtG3XCsXuDrt9thok2AcpgH/IzNkew+c+nJJZjc3QmMMLLllmElPic+SGV406chjaVUuvpSTtbpTr6LAiA9la7JAb3uhcKYZawUTEGgz4prRAXPDBAApg8VTEJDk1WL9KqD+yMLDlDZVK9ILiA+VnRcSo67TbZJbgCHkEuo5EVLqzC4GVwYAOP6X8a3RNf/bLmVCqKT0nSsvbR6FqRJVbrAxUK6SgkSHJDqwgGmRFp+N84hvPnjAbopazb2O6OfU2r2QjczaYuhXz+4VaMJkJXL9wgyUt6FYHDUQDEtrZcu4tfH+NSInIcehUcuiXV0S0sqyYEf+3Jubd1Uox/pfIyodDoiwqG23qMIJ9viSjPyoRK8b3OAJbVYxEAWjUFS/x+lDM/38CMAh9x0LkNGm0QrpaVN9pNHFQjDS/Q9HvgZxUUxH6x1y4RBW2QHUy2NgzZNatPZfYgIE9y8tK1Hn4SsE9EuXBb1apC3CbHUecDpB/pxtirA93pb0xo= X-Forefront-Antispam-Report: CIP:255.255.255.255;CTRY:;LANG:en;SCL:1;SRV:;IPV:NLI;SFV:NSPM;H:DM3PR12MB9416.namprd12.prod.outlook.com;PTR:;CAT:NONE;SFS:(13230040)(1800799024)(7416014)(376014)(23010399003)(366016)(10067099003)(6133799003)(18002099003)(5023799004)(11063799006)(56012099006)(22082099003);DIR:OUT;SFP:1101; X-MS-Exchange-AntiSpam-MessageData-ChunkCount: 1 X-MS-Exchange-AntiSpam-MessageData-0: =?us-ascii?Q?yoNblMvN80uEkt4Lo3qIOJvu5lx5jMH/b7tqLBMMN+a4tTHjGWW8V/FDCWQ+?= =?us-ascii?Q?R9rWZWYSfgzfkmc27iJxnS3bS7Tn63tDTVFAmDy0KB6HOhdPVKsWiVkVlnYY?= =?us-ascii?Q?1w0mlRwOUCAcNaWJKAN9aUSRuLO+TExhTfrBcsRr7OVzF7QSeL2TzhSvNU2R?= =?us-ascii?Q?F5Whs7fSyOvClhq5TClvp4fm47hKV/SPEeFQ9CDrskQCFb8Z6FATcjyFat0t?= =?us-ascii?Q?+YxsGbnhd1q5nvXtSlIZfg+nGtuBEsQmz+iFD62F419vuqFs8xl87pxzVrxy?= =?us-ascii?Q?ZEvbj9pJb4/DJKeaQuYYj4qfwg3RyOJ79XR5aasgUkVxITgJmurry0jy7c3Z?= =?us-ascii?Q?+2vl223zNlU86kEoxpt0XgkrUSr42QyadDfJ2apczifDnDkboPUHxRIomKg1?= =?us-ascii?Q?XBc1siYR6F/S89BX+OC80xKctC0a+cUrFmbRifpmtWyHCG2c1DZj3iJoWvip?= =?us-ascii?Q?DqSUADQJoPUXDvMjWQ9ZJhye2HnHavdKTcCbKDStDUg4gHbBVBZ0GRvE9mMh?= =?us-ascii?Q?CDe3kZ9UFW06IkMEuabCxJGO/TVZ523Q/fCCUy8pucbeJGN61Fk6tTaXl9+6?= =?us-ascii?Q?RNJAt7mMqjvOD+sbCAKYEB+mmSrn6+uTX0YgXeeIFear7qzA0QHxx0KLN3n1?= =?us-ascii?Q?uswW4RsHToiJytL8ZBcZfPNWB/q+x60S5IhWte3lDvHdY8RFRHICEzqbSyGF?= =?us-ascii?Q?WKE6CbM/CW8V4qxSJ4UGKuPEWYrimuiOY4Znqvb9mmASyFgIGB2q0dluCrna?= =?us-ascii?Q?m1Y++xkqjj8tCrUZBIUoOP7mAYw5YIw1Qv5sTKzl2z955fDmc4rl0V5lDe+H?= =?us-ascii?Q?h+hHO6l98Iq2ltY6Y/mQoPwKrLPHFKfsR8tjFTX/9GSrBjJXPV/EPLU/mZAR?= =?us-ascii?Q?ZR4z6LkP6aq2f4TW+9s2Vf2APH0rLDAUNvULyTkDdciYrIGapwTJ0Z8eN6ue?= =?us-ascii?Q?qs4fAkoO5WrXQEZCe0nhq4RsAnGv6UZMO+EQxwZE4NvH/o/VTCSJ6WaVDAB0?= =?us-ascii?Q?mRjmZTs9ZFe5Lt8w1+7PuwLWhJPzZkHaWPp6gmvBFisBPndmpVmzKUvPToCy?= =?us-ascii?Q?EIwm1KyES/lk4XkJwcJTfQxrQHQC3Kay80aToN8IlZmGHQknqoyxKCCPnq4o?= =?us-ascii?Q?cvV4Tp14w2YkLiX9VfJ18mGMcwBoDFUcVSRhJABnjF7yDk2wYdCJz3FawcLd?= =?us-ascii?Q?00YF2wqHYiOlxMdbgdg0juKlr23957t/kC4+mAWXhtOgR7I5UjuelW85/++W?= =?us-ascii?Q?Vd9NP45Znk+V1US/BT8euLSYj7D/XcKnSGL6SdL9KpEABZPTnEX0lf1+i4pp?= =?us-ascii?Q?KedG8jq9X22/6lsA6qKkejf2O4zjhmRzLB6MUAg/sW2wTo2HVoIpuJucteHE?= =?us-ascii?Q?gbtoF/O37c3kr591dwJZGpOQO1VU4fSVWOuRGhrMUcnFSPYsWg4BJf4+zwHR?= =?us-ascii?Q?WM885SgpLcJzuzqb6a8/hzQkAr+34Y3h/bF0oOQpIQErn3bkGkp/2vI7fp/u?= =?us-ascii?Q?XYsQ45K2nFyKZ67a89Vwkb7sycvKorvCm/bTNDhPY0TmN+aZaswboBZVQMmw?= =?us-ascii?Q?zlM7d8WWx79RSFnE+bL+SBNHyrVimjNqaoo5D+fU2nZxezt57PFddcU9knKp?= =?us-ascii?Q?Bw4JkkM50lMatg4wtpVnPYpOtO6DNo9RiC3+PgD7GgJrRIej407XEv/wr4hk?= =?us-ascii?Q?w3JQZKEODX8ZMmnq55sWO3CWPIHj6+zN56XW/SHTvOrlDNEbq87cDlGXpQq3?= =?us-ascii?Q?bPEJzTY1Ow=3D=3D?= X-OriginatorOrg: Nvidia.com X-MS-Exchange-CrossTenant-Network-Message-Id: a9c880dd-008f-41d2-7b90-08df10888212 X-MS-Exchange-CrossTenant-AuthSource: DM3PR12MB9416.namprd12.prod.outlook.com X-MS-Exchange-CrossTenant-AuthAs: Internal X-MS-Exchange-CrossTenant-OriginalArrivalTime: 12 Sep 2026 04:44:19.5165 (UTC) X-MS-Exchange-CrossTenant-FromEntityHeader: Hosted X-MS-Exchange-CrossTenant-Id: 43083d15-7273-40c1-b7db-39efd9ccc17a X-MS-Exchange-CrossTenant-MailboxType: HOSTED X-MS-Exchange-CrossTenant-UserPrincipalName: mbrA4pz9qF4ocdncnMJYYKX2LloLhdmSzE/c02JbxPWWvN4hQ/AyRmKJZVQF6kq1W9pdl4uEXBgoZRhBARA7Tg== X-MS-Exchange-Transport-CrossTenantHeadersStamped: PH8PR12MB7229 Content-Type: text/plain; charset="utf-8" From: Joel Fernandes Servicing a GIN leaf has a required order: read its pending bits, then clear them. Clearing a leaf first discards every vector latched in it, and the hardware keeps no record of what was discarded. The interrupt never arrives, and no register shows that it was ever pending. Every subtree enabled at TOP also needs an allocated PCI vector with a handler registered on it. Under MSI-X each subtree has its own table entry. Linux masks every entry until a driver requests its IRQ, and a masked entry sends no message. An enabled subtree whose entry was never requested raises interrupts that never reach a handler, while the leaf and TOP registers show them pending and enabled. Under MSI the whole tree raises a single message, so one entry serves every subtree. Add the CPU interrupt tree of one PCIe function. Reading a leaf yields the handle that clears it, so the wrong order does not compile. Building a tree fails if it names a subtree that the GPU does not implement. Allocate the PCI vectors from the set of serviced subtrees. Request MSI-X entries 0 through the highest serviced subtree, since an MSI-X allocation cannot be sparse, and fall back to a single MSI message, never to INTx. Reviewed-by: Will Pierce Signed-off-by: Joel Fernandes [jhubbard: reworked on top of the GIN vector types: a leaf read yields the handle that clears it, enables are guarded, the leaf count and rearm method come from the interrupt HAL, and the drain reads every implemented leaf rather than descending from TOP] Signed-off-by: John Hubbard --- drivers/gpu/nova-core/irq.rs | 82 +++++++ drivers/gpu/nova-core/irq/interrupt_tree.rs | 252 +++++++++++++++++++- 2 files changed, 327 insertions(+), 7 deletions(-) diff --git a/drivers/gpu/nova-core/irq.rs b/drivers/gpu/nova-core/irq.rs index 62c242b71dc8..28f147641024 100644 --- a/drivers/gpu/nova-core/irq.rs +++ b/drivers/gpu/nova-core/irq.rs @@ -13,6 +13,23 @@ mod interrupt_tree; mod regs; =20 +use kernel::{ + device::Bound, + irq, + pci::{ + self, + IrqType, // + }, + prelude::*, // +}; + +use crate::num; + +use interrupt_tree::{ + Subtree, + SubtreeSet, // +}; + /// The message-signaled interrupt type that Linux granted. /// /// nova-core never requests INTx, so this has no variant for it, unlike [= `kernel::pci::IrqType`]. @@ -24,3 +41,68 @@ enum MsiType { /// One table entry per subtree. MsiX, } + +/// The PCI interrupt vectors allocated for the subtrees that nova-core se= rvices. +/// +/// A subtree may be enabled at `TOP` only once a vector is allocated for = it and a handler is +/// registered on that vector. See "The serviced-subtree invariant" in +/// `Documentation/gpu/nova/core/interrupts.rst`. +pub(crate) struct SubtreeVectors<'a> { + vectors: pci::IrqVectorRegistration<'a>, + serviced: SubtreeSet, + msi_type: MsiType, +} + +impl SubtreeVectors<'_> { + /// Returns the [`irq::IrqRequest`] for the PCI vector that delivers `= subtree`. + /// + /// # Errors + /// + /// `EINVAL` if `subtree` is not one of the serviced subtrees. + fn request_for(&self, subtree: Subtree) -> Result>= { + if !self.serviced.contains(subtree) { + return Err(EINVAL); + } + + let entry =3D match self.msi_type { + MsiType::MsiX =3D> num::u32_as_usize(subtree.index()), + MsiType::Msi =3D> 0, + }; + + self.vectors.index(entry).map(Into::into) + } +} + +/// Allocates the PCI interrupt vectors for the subtrees in `serviced`. +/// +/// Requests MSI-X entries `0` through the highest subtree in `serviced`, = since an allocation +/// cannot be sparse, and falls back to a single MSI message for the whole= tree. +/// +/// # Errors +/// +/// `EINVAL` if `serviced` is empty. Otherwise, when neither type could be= allocated, the error +/// from the MSI request. +pub(crate) fn alloc_vectors( + pdev: &pci::Device, + serviced: SubtreeSet, +) -> Result> { + if serviced.is_empty() { + return Err(EINVAL); + } + + let entries =3D serviced.span(); + + let (vectors, msi_type) =3D pdev + .alloc_irq_vectors(entries, entries, IrqType::MsiX.into()) + .map(|vectors| (vectors, MsiType::MsiX)) + .or_else(|_| { + pdev.alloc_irq_vectors(1, 1, IrqType::Msi.into()) + .map(|vectors| (vectors, MsiType::Msi)) + })?; + + Ok(SubtreeVectors { + vectors, + serviced, + msi_type, + }) +} diff --git a/drivers/gpu/nova-core/irq/interrupt_tree.rs b/drivers/gpu/nova= -core/irq/interrupt_tree.rs index 5c7829ea3bc5..2583b006019e 100644 --- a/drivers/gpu/nova-core/irq/interrupt_tree.rs +++ b/drivers/gpu/nova-core/irq/interrupt_tree.rs @@ -1,22 +1,40 @@ // SPDX-License-Identifier: GPL-2.0 // SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIA= TES. All rights reserved. =20 -//! Vector addressing in the GIN CPU interrupt tree. +//! The GIN CPU interrupt tree for one PCIe function. //! //! A [`GinVector`] names an interrupt source, a [`LeafIndex`] the leaf re= gister that latches it, -//! a [`LeafMask`] a set of vectors within one leaf, and a [`Subtree`] one= `TOP` bit. The types -//! keep the four from being confused with one another. +//! a [`LeafMask`] a set of vectors within one leaf, and a [`Subtree`] one= `TOP` bit. +//! +//! Servicing a leaf requires reading its pending bits before clearing the= m. Only +//! [`Tree::read_pending`] produces a [`LeafPending`], and only a [`LeafPe= nding`] clears a leaf, +//! so the wrong order does not compile. Nothing in this module serializes= access to the tree. //! //! See `Documentation/gpu/nova/core/interrupts.rst`. =20 use kernel::{ + io::{ + register::Array, + Io, // + }, num::Bounded, prelude::*, // }; =20 -use crate::num; +use crate::{ + driver::Bar0, + gpu::Chipset, + num, // +}; =20 -use super::regs::*; +use super::{ + hal::{ + cpu_interrupt_hal, + PciIrqRearmMethod, // + }, + regs::*, + SubtreeVectors, // +}; =20 /// Number of vectors one leaf register carries, one per bit. const VECTORS_PER_LEAF: u32 =3D u32::BITS; @@ -78,6 +96,11 @@ pub(super) const fn subtree_set(self) -> SubtreeSet { pub(super) const fn vector_count(self) -> u32 { self.into_u32() * VECTORS_PER_LEAF } + + /// Returns every leaf a tree of this size implements. + pub(super) fn iter(self) -> impl Iterator { + (0..self.into_raw()).filter_map(LeafIndex::try_new) + } } =20 // `VECTOR_BITS` and `LeafCount::Sixteen` are written separately. This ass= ert keeps them in @@ -130,7 +153,7 @@ fn from(vectors: LeafMask) -> Self { /// /// Exactly one bit is set. #[derive(Clone, Copy, Debug, Eq, PartialEq)] -pub(super) struct Subtree(u32); +pub(crate) struct Subtree(u32); =20 impl Subtree { /// Returns the subtree at index `idx`. @@ -151,7 +174,7 @@ pub(super) const fn into_raw(self) -> u32 { =20 /// Set of subtrees, one bit per subtree, in the layout of the `TOP` regis= ters. #[derive(Clone, Copy, Debug, Eq, PartialEq)] -pub(super) struct SubtreeSet(u32); +pub(crate) struct SubtreeSet(u32); =20 impl SubtreeSet { pub(super) const fn contains(self, subtree: Subtree) -> bool { @@ -250,3 +273,218 @@ fn from(vector: GinVector) -> Self { vector.0.extend() } } + +/// Disables `vectors` in `leaf`. +fn clear_leaf_enables(bar: Bar0<'_>, leaf: LeafIndex, vectors: LeafMask) { + bar.write( + Array::at(*leaf), + NV_VIRTUAL_FUNCTION_PRIV_CPU_INTR_LEAF_EN_CLEAR::zeroed().with_vec= tors(vectors), + ); +} + +/// Disables the subtrees in `serviced` at `TOP`. +fn clear_top_enables(bar: Bar0<'_>, serviced: SubtreeSet) { + bar.write_reg(NV_VIRTUAL_FUNCTION_PRIV_CPU_INTR_TOP_EN_CLEAR::zeroed()= .with_subtrees(serviced)); +} + +/// The CPU tree of one PCIe function, and the subtrees that nova-core ser= vices. +pub(super) struct Tree<'a> { + bar: Bar0<'a>, + leaves: LeafCount, + serviced: SubtreeSet, + rearm: PciIrqRearmMethod, +} + +impl<'a> Tree<'a> { + /// Creates the tree of `chipset`, covering the subtrees that `vectors= ` services. + /// + /// # Errors + /// + /// `EINVAL` if `chipset` does not implement every subtree that `vecto= rs` services. + pub(super) fn new( + bar: Bar0<'a>, + chipset: Chipset, + vectors: &SubtreeVectors<'_>, + ) -> Result { + let hal =3D cpu_interrupt_hal(chipset); + let leaves =3D hal.leaf_count(); + let serviced =3D vectors.serviced; + + if serviced.intersection(leaves.subtree_set()) !=3D serviced { + return Err(EINVAL); + } + + Ok(Self { + bar, + leaves, + serviced, + rearm: hal.pci_irq_rearm_method(vectors.msi_type), + }) + } + + /// Rearms PCI interrupt delivery to the CPU after servicing `subtree`= , the one subtree that + /// the calling handler serves. + /// + /// A handler must call this before returning, or it receives no furth= er interrupts. + pub(super) fn rearm_pci_irq(&self, subtree: Subtree) { + self.rearm.rearm(self.bar, self.serviced, subtree); + } + + /// Enables the serviced subtrees at `TOP`. + /// + /// Each of them must have a handler registered on its PCI vector. + pub(super) fn enable_top(&self) { + self.bar.write_reg( + NV_VIRTUAL_FUNCTION_PRIV_CPU_INTR_TOP_EN_SET::zeroed().with_su= btrees(self.serviced), + ); + } + + /// Disables the serviced subtrees at `TOP`. + pub(super) fn disable_top(&self) { + clear_top_enables(self.bar, self.serviced); + } + + /// Enables the serviced subtrees at `TOP` until the returned guard dr= ops. + pub(super) fn enable_top_guarded(&self) -> TopEnableGuard<'a> { + self.enable_top(); + + TopEnableGuard { + bar: self.bar, + serviced: self.serviced, + } + } + + /// Enables `vectors` in `leaf`. + pub(super) fn enable_leaf(&self, leaf: LeafIndex, vectors: LeafMask) { + self.bar.write( + Array::at(*leaf), + NV_VIRTUAL_FUNCTION_PRIV_CPU_INTR_LEAF_EN_SET::zeroed().with_v= ectors(vectors), + ); + } + + /// Disables `vectors` in `leaf`. + pub(super) fn disable_leaf(&self, leaf: LeafIndex, vectors: LeafMask) { + clear_leaf_enables(self.bar, leaf, vectors); + } + + /// Enables `vectors` in `leaf` until the returned guard drops. + pub(super) fn enable_leaf_guarded( + &self, + leaf: LeafIndex, + vectors: LeafMask, + ) -> LeafEnableGuard<'a> { + self.enable_leaf(leaf, vectors); + + LeafEnableGuard { + bar: self.bar, + leaf, + vectors, + } + } + + /// Reads the pending bits of `leaf`, and returns the handle that clea= rs them. + pub(super) fn read_pending(&self, leaf: LeafIndex) -> LeafPending<'a> { + let pending =3D self + .bar + .read(NV_VIRTUAL_FUNCTION_PRIV_CPU_INTR_LEAF::at(*leaf)) + .vectors(); + + LeafPending { + bar: self.bar, + leaf, + pending, + } + } + + /// Latches `vector` as its own source would. + /// + /// # Errors + /// + /// `EINVAL` if this tree does not implement `vector`. + // The interrupt self-test is the only caller. + #[expect(dead_code)] + pub(super) fn trigger(&self, vector: GinVector) -> Result { + vector.validate(self.leaves)?; + self.bar.write_reg( + NV_VIRTUAL_FUNCTION_PRIV_CPU_INTR_LEAF_TRIGGER::zeroed().with_= vector(vector), + ); + + Ok(()) + } + + /// Disables every vector in every implemented leaf, including the sub= trees that nova-core does + /// not service. Call this only during probe. + pub(super) fn disable_all_leaves(&self) { + for leaf in self.leaves.iter() { + self.disable_leaf(leaf, LeafMask::all()); + } + } + + /// Clears every pending bit in every implemented leaf, including the = subtrees that nova-core + /// does not service. + /// + /// The serviced subtrees are disabled at `TOP` on return. Call this o= nly during probe, with no + /// interrupt handler registered. + pub(super) fn drain(&self) { + self.disable_top(); + + // A vector that latched while disabled does not show in `TOP`, so= read every leaf rather + // than descending from it. + for leaf in self.leaves.iter() { + self.read_pending(leaf).clear(); + } + } +} + +/// The pending bits of one leaf as they were read, and the handle that cl= ears them. +pub(super) struct LeafPending<'a> { + bar: Bar0<'a>, + leaf: LeafIndex, + pending: LeafMask, +} + +impl LeafPending<'_> { + pub(super) fn vectors(&self) -> LeafMask { + self.pending + } + + /// Clears the vectors that were pending at the read. A vector that la= tched since stays pending. + pub(super) fn clear(&self) { + self.clear_vectors(self.pending); + } + + /// Clears `vectors` and no other bit. + pub(super) fn clear_vectors(&self, vectors: LeafMask) { + if !vectors.is_empty() { + self.bar.write( + Array::at(*self.leaf), + NV_VIRTUAL_FUNCTION_PRIV_CPU_INTR_LEAF::zeroed().with_vect= ors(vectors), + ); + } + } +} + +/// Disables a set of vectors in one leaf when dropped. +pub(super) struct LeafEnableGuard<'a> { + bar: Bar0<'a>, + leaf: LeafIndex, + vectors: LeafMask, +} + +impl Drop for LeafEnableGuard<'_> { + fn drop(&mut self) { + clear_leaf_enables(self.bar, self.leaf, self.vectors); + } +} + +/// Disables the serviced subtrees at `TOP` when dropped. +pub(super) struct TopEnableGuard<'a> { + bar: Bar0<'a>, + serviced: SubtreeSet, +} + +impl Drop for TopEnableGuard<'_> { + fn drop(&mut self) { + clear_top_enables(self.bar, self.serviced); + } +} --=20 2.55.0 From nobody Fri Sep 25 13:19:17 2026 Received: from BYAPR05CU005.outbound.protection.outlook.com (mail-westusazon11010052.outbound.protection.outlook.com [52.101.85.52]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id D71CC3803C3 for ; Sat, 12 Sep 2026 04:44:30 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=fail smtp.client-ip=52.101.85.52 ARC-Seal: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1789188272; cv=fail; b=ksK7IbujaI17E4MCYsfA/CewHTLLTJlFOCQeYQGljftvEuOfdkFX2ZxmM2NPWB9Y213QZrSlGGmC1dpyAxnZyQ3nna7Q0mx/VF3iad/L2UtGolWuzhwuc1yjuNam85QYJX8Fb95kmP/Czqkp67szwFBBJCHFSPdl+Ek8jQ2BoBM= ARC-Message-Signature: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1789188272; c=relaxed/simple; bh=yAqZQB17NPTN9gw3mLDBwn8KPDgc3pDD3TfXlUQJSjc=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: Content-Type:MIME-Version; b=p6cPV6hUUGCXNaUGGPpnfwtlHRFmRNMfLAFpnyJCxajw04vR8ABsi+nKfOfjJvcl8FqAq04lOT+Mt7F9ngGy3nhkwoZmG6JlLyJExvQ/12cX87c7I/9IoZofU+4k2P1kyZfZ+7oEKMrdaIVj+KQza0L+qGnmJbV1vzFviKekvWE= ARC-Authentication-Results: i=2; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=nvidia.com; spf=fail smtp.mailfrom=nvidia.com; dkim=pass (2048-bit key) header.d=Nvidia.com header.i=@Nvidia.com header.b=I5D7aal6; arc=fail smtp.client-ip=52.101.85.52 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=nvidia.com Authentication-Results: smtp.subspace.kernel.org; spf=fail smtp.mailfrom=nvidia.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=Nvidia.com header.i=@Nvidia.com header.b="I5D7aal6" ARC-Seal: i=1; a=rsa-sha256; s=arcselector10001; d=microsoft.com; cv=none; b=jf+Xtaq5/Xitd5HvwLUwJRAESOavxfsRhd8RrWJENQ9P2Dxhk+AljsAnkSQLPqiDQhVWrpvFW8CSBIStctuLZeTBBCf9+ixXZgi9QbeW0zWYI7+hfX8sSCfNM7Yxyt6Ja9gOs55JDNOJN4XpFo5/E2R6W5i4srg+HygvbJLzpsyzFw3Y7A06p5SLns1N4SNIY0Av/hHySo8DoKoqi3YjQTX1xca4oTpQwehI3Fu6OBdPpMQYWdQo+5lgZJGhvaV9jr/1IsShuOrAcYgkEpMzJPRo9DoGjjJVbV8ili6KI9qk/w139vFBWGrZdK476pPS6EN4tF7r4b0gJ/5sfFFVGA== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=microsoft.com; s=arcselector10001; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-AntiSpam-MessageData-ChunkCount:X-MS-Exchange-AntiSpam-MessageData-0:X-MS-Exchange-AntiSpam-MessageData-1; bh=o9057YJXIHyFmnegK6028OQiCvMEog1zkEo3h74dStk=; b=dWmJa28GHSJOYKIrDCzUtEjAWYhgPMdUr2Ga10ysAcmD+Do8sKeBc0FzUf9hYUeGV3H8fhwNRVCuWOmslUi5la1izzyW+RbxggJmU66mjsl8zwKR9s882knC8H8jt05upjSqwXriegoFxyYZJCZt3nEpIR7HBooUW5bZunJQ6dtQCkONAptzBkm9eokG2eXJcavSILG7SadzxjmTwIdtZhRHLxV/r1qmVlX2qsoPDbC6XwwJOQPGUDtfpMZdd0+jAY4ichAYtpgTwToQSM4FVOtgriSR51aBAgn6J3WefosAY00meDxkdguIOsg2lJcv+QfQr785SP1yombS7Ck6Bg== ARC-Authentication-Results: i=1; mx.microsoft.com 1; spf=pass smtp.mailfrom=nvidia.com; dmarc=pass action=none header.from=nvidia.com; dkim=pass header.d=nvidia.com; arc=none DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=Nvidia.com; s=selector2; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck; bh=o9057YJXIHyFmnegK6028OQiCvMEog1zkEo3h74dStk=; b=I5D7aal6j00kEGgek5uZc9j9gzvJinobsy0MqoVZlrI4jChb69ZHmskG+wr5eUhTbPz4UqN6tzk8tPH/sSeIQ/vYn+07Jit7ju2nqFY04OWgcQlZSJH03uzE8vJxyCycaLpSbBtRNy+3ezIyUSJPCeWxAFH1ITR50xzkaCozUHb1MbbINWVzHd6WQlYmaZZwDFOM9DY9Yo8zM3JWgTl2yHPgXczCo4CPd+3ZSuuTAC78f2crGdZIkx0qgxsg+wjzDkoF+ripbI49ng5xXOua1B7SSjZz3irEwrEbXYd5NE2t30pWPI4y+XnY96BnW6IYP7EJQR5cil11mQzawHmiLA== Authentication-Results: dkim=none (message not signed) header.d=none;dmarc=none action=none header.from=nvidia.com; Received: from DM3PR12MB9416.namprd12.prod.outlook.com (2603:10b6:0:4b::8) by PH8PR12MB7229.namprd12.prod.outlook.com (2603:10b6:510:227::20) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.21.406.10; Sat, 12 Sep 2026 04:44:20 +0000 Received: from DM3PR12MB9416.namprd12.prod.outlook.com ([fe80::8cdd:504c:7d2a:59c8]) by DM3PR12MB9416.namprd12.prod.outlook.com ([fe80::8cdd:504c:7d2a:59c8%4]) with mapi id 15.21.0406.007; Sat, 12 Sep 2026 04:44:20 +0000 From: John Hubbard To: Danilo Krummrich , Alexandre Courbot Cc: Timur Tabi , Alistair Popple , Eliot Courtney , Zhi Wang , David Airlie , Simona Vetter , Bjorn Helgaas , Miguel Ojeda , Alex Gaynor , Boqun Feng , Gary Guo , =?UTF-8?q?Bj=C3=B6rn=20Roy=20Baron?= , Benno Lossin , Andreas Hindborg , Alice Ryhl , Trevor Gross , nova-gpu@lists.linux.dev, LKML , John Hubbard Subject: [PATCH v4 07/17] gpu: nova-core: wait for GFW boot in probe, not in the Gpu constructor Date: Fri, 11 Sep 2026 21:43:50 -0700 Message-ID: <20260912044400.677097-8-jhubbard@nvidia.com> X-Mailer: git-send-email 2.55.0 In-Reply-To: <20260912044400.677097-1-jhubbard@nvidia.com> References: <20260912044400.677097-1-jhubbard@nvidia.com> X-NVConfidentiality: public Content-Transfer-Encoding: quoted-printable X-ClientProxiedBy: BYAPR21CA0010.namprd21.prod.outlook.com (2603:10b6:a03:114::20) To DM3PR12MB9416.namprd12.prod.outlook.com (2603:10b6:0:4b::8) Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-MS-PublicTrafficType: Email X-MS-TrafficTypeDiagnostic: DM3PR12MB9416:EE_|PH8PR12MB7229:EE_ X-MS-Office365-Filtering-Correlation-Id: 9937b1f9-615e-4f09-5016-08df108882cf X-MS-Exchange-SenderADCheck: 1 X-MS-Exchange-AntiSpam-Relay: 0 X-Microsoft-Antispam: BCL:0;ARA:13230040|1800799024|7416014|376014|23010399003|366016|10067099003|6133799003|18002099003|5023799004|11063799006|56012099006|22082099003; X-Microsoft-Antispam-Message-Info: 30kkApuRhFlg9nuyTP4ZCPW6vQrHsSpKWsoI+1J/sC6gvPV6LpE2qSyxoEYFfAYSquz+IfsTsQ9+xTqG858FviXJvB/Qo1B3Dt9O4LkWa55yue8BM1osp66v60Mh/nl27PEMevo0hvTe2PmAoHtirZTWg4V7U7d0iFxqIvUxweEL8XW+jrNKCfIX+nvxIJ03w4vwFDw9v7K0tbp9RWu6VgCOlWQr0SFpI3fexejTTybWHC79wS7QYC7HqY4AgxmQXeY2oZp3ijz3fSy3Q0ZZwOP7CJdD3+OIsLqfc1KEh1HfC83YxyA6cbMYROv4p862Na1zTgoqfT3N27bHRITIY3AMICRqMePi/D+Qai5LTErkyOB/zeT0o8xmzGkBDHDJxtNRdNl5yrUeVDTb3SRe2xcZO+pQ8XGNBIFxIOKMpXDKyySffESzA8Dc3CQL34UK63gI4E2bQthw5HUSDOc+Sc4Vrv6GSySnHuW9HK04fQLFzOu3OlOrBVJt3w2B6daqILo5mjvbMM7Gn3dFrhAShS0uSncoLXZ50RWexvxKzUL8Vk4sg3nNAE62c9wzdz4H2TkKB7NyEKhB0Ueu93pS4inHHq5EJ1bhoT2iP7BKJEt9C175i5C72lrdxdiGBwi+YUwg5Ci5ATEn7IPR4iZzO4SivjCPFdYd6BIYVanaxs4= X-Forefront-Antispam-Report: CIP:255.255.255.255;CTRY:;LANG:en;SCL:1;SRV:;IPV:NLI;SFV:NSPM;H:DM3PR12MB9416.namprd12.prod.outlook.com;PTR:;CAT:NONE;SFS:(13230040)(1800799024)(7416014)(376014)(23010399003)(366016)(10067099003)(6133799003)(18002099003)(5023799004)(11063799006)(56012099006)(22082099003);DIR:OUT;SFP:1101; X-MS-Exchange-AntiSpam-MessageData-ChunkCount: 1 X-MS-Exchange-AntiSpam-MessageData-0: =?us-ascii?Q?vChn3mWvtCANb+SMgqGuf7ZjCL9K5WUT3ZuRkH1D6lKseeFsm8pqz8lCBiX9?= =?us-ascii?Q?84IxlFsbfKN2vn28WfTfmuTS52mBAHWbgpWw3jjak1bc04AKJ70gXdqG0AMv?= =?us-ascii?Q?TLsjx0uU3v4MbKpqNhyii6af1dN+VnPCXzYhsWQY7OYLoGrv8NzKe8sAqYCI?= =?us-ascii?Q?4E1ZlR2e9twdIiTlYpTf0ny0jslob2ipNXvMATo9COBOhkLiF9RR/XWn4ZaG?= =?us-ascii?Q?Dl78DOekYTdqoRNypJLJXKE0X9w8DUVeThlkDuQkqpEqULo/s6gTQ0Yrlhc1?= =?us-ascii?Q?RDzVg6Gitj03tI9KkWz6XPrEbXyuvNIqj9K9prRn1paEf5kLAhyc4B1Qx4vP?= =?us-ascii?Q?dM6js7x/z9sFzrvrdT76az44ScApjAkfXnnx62yTeXhRTGhwd8B3raW8lTv6?= =?us-ascii?Q?qHNZOdEh2/FcWFbfOWeDZ1DLuMHUV3Pc+uuWmGzCriHFWD6s2epmizaiPhIL?= =?us-ascii?Q?EgxMQ9+wX1PcFTyKpoybVeSFrmBoFBrx+/vduxvLf3kLK+wNSpXO3lzkK4rT?= =?us-ascii?Q?Bxq3WasZzgQknuOhG0VS2lCj9c93hBaTKFIouYWwOXPMbAszFeLiZa4c/U7O?= =?us-ascii?Q?hS1dkRqCpFLHdJDua5oUVi/2hfyp7LN3HQtzPGJ5F3no8p/zvPWvZ2Znfjzw?= =?us-ascii?Q?IKl6rvMtJP2VMyFtz1lBGILDOiUZe6CAGg2CoZHJJojt1bEHFney6RiOP8z8?= =?us-ascii?Q?x3Xt1QKYcXGDxcQa0bV067XC7pbuAh6K6HTJtqHJ2sxAt/qKdb57+y8dpfDL?= =?us-ascii?Q?GepPbJ298BeTo+i2Ay9Q+U2BeUasznekJDT1qaO0n4PMtSFv69dIzopItzyA?= =?us-ascii?Q?5B6oyV0kHDH4Zc43fiBzEhptn6mOt25v6Wq7Y+NHSTOdjuFPSGWZhxqR/gwW?= =?us-ascii?Q?mWySQdnNI8ujz3BrD4FCxfH7PVzxA8eBP8AKrZRBT2CK2X8+WL9jrW+vjlQp?= =?us-ascii?Q?KXmrlk0wrBgkOhHdOrOu52ZDv0FpPzxkjKK9OO1tXF6PfdLwOHTkno4SRvpM?= =?us-ascii?Q?M1HeNE5E3TQSOI/xVHYWbZ6fPXm6K6eUvFyFKPFrgOVTZIBUfhLVYnsYlRFZ?= =?us-ascii?Q?JhMuzaye2OzA53CblD9Em5eVk11R3ElOaXVDXmpi7zQ2IBhZ1gcp+P1k2MOM?= =?us-ascii?Q?6ePPJrZt+OWCbfnDMhoPvml0MsY1Q4ehTbMWjCL+m7xO0Hj7E/oSWk87Pxer?= =?us-ascii?Q?wrYr+R4UI/tMAlRsVdr4aiNItTePc76tiYEcsrw7tdUd3nhy5+tPxJRykNvy?= =?us-ascii?Q?sejmPZUZZnM1GmRX4EAqc96WrV3/+p7YidrVc3DXpVZ0fH/x6iwCrRvS+soW?= =?us-ascii?Q?p4QJbur2MYC06U6iddluLqF9L9UbFodd8R/ukXBcjc3fv31UJYnBWaEBtFzx?= =?us-ascii?Q?0tenQ584dQY1urmsD75zJWVSZqxVW8nMHye5NEE37XYp9ZDZ+t0a7OiLzoji?= =?us-ascii?Q?YEXoCM6Rl2+ufwO+3nM+iE4m4vQxtguuEZ1A49oX3g33dID0hXmnL1ZSYhhe?= =?us-ascii?Q?TA7WlsyoHQp8yQOregT6thMDKEf6AInT+skk+xrUDXSnfm6WtQKRPbNhF9oc?= =?us-ascii?Q?ZXKWURHNOUBSsTo057crNUCHKbTF3m4aWkByhz/UOnh4sfevDIJCnB74NaUn?= =?us-ascii?Q?PRzhJPIoGBbnL71nouhGUekAMsxXkhICPjeL3iaZaiQEiY8Ym+iQBdVcad4g?= =?us-ascii?Q?wXleBqEtKKPhQrvAgdlupUdnBnwNIm5X4YKfmaXYOhnqkHAtkmVfIy3LIMU2?= =?us-ascii?Q?DkDXLZmA0w=3D=3D?= X-OriginatorOrg: Nvidia.com X-MS-Exchange-CrossTenant-Network-Message-Id: 9937b1f9-615e-4f09-5016-08df108882cf X-MS-Exchange-CrossTenant-AuthSource: DM3PR12MB9416.namprd12.prod.outlook.com X-MS-Exchange-CrossTenant-AuthAs: Internal X-MS-Exchange-CrossTenant-OriginalArrivalTime: 12 Sep 2026 04:44:20.7448 (UTC) X-MS-Exchange-CrossTenant-FromEntityHeader: Hosted X-MS-Exchange-CrossTenant-Id: 43083d15-7273-40c1-b7db-39efd9ccc17a X-MS-Exchange-CrossTenant-MailboxType: HOSTED X-MS-Exchange-CrossTenant-UserPrincipalName: e8F6XS8MXZna5M3X8oaofvqnPHKHS0EWXOkcc3NNUUOfv6I+07CgO3GNp5YZTFwYNUf8dXd7CKtne1E40ROmxA== X-MS-Exchange-Transport-CrossTenantHeadersStamped: PH8PR12MB7229 Content-Type: text/plain; charset="utf-8" The GPU boots its own firmware, GFW, out of reset, and nothing may program the GPU until GFW reports completion. nova-core waited for GFW inside the Gpu constructor, which also boots the GSP. Code that has to run after GFW and before GSP boot, such as a probe-time hardware self-test, had nowhere to go. Move the wait into probe, ahead of the Gpu constructor, and read the chipset there from a Spec that probe builds itself. Leave the DMA mask in the constructor, since it programs the host rather than the GPU. Assisted-by: LLM Signed-off-by: John Hubbard --- drivers/gpu/nova-core/driver.rs | 13 ++++++++++++- drivers/gpu/nova-core/gpu.rs | 28 ++++++++++++++++++++-------- 2 files changed, 32 insertions(+), 9 deletions(-) diff --git a/drivers/gpu/nova-core/driver.rs b/drivers/gpu/nova-core/driver= .rs index 0672a0707a71..15a44f9a6441 100644 --- a/drivers/gpu/nova-core/driver.rs +++ b/drivers/gpu/nova-core/driver.rs @@ -22,7 +22,13 @@ types::CovariantForLt, }; =20 -use crate::gpu::Gpu; +use crate::{ + gpu, + gpu::{ + Gpu, + Spec, // + }, // +}; =20 /// Counter for generating unique auxiliary device IDs. static AUXILIARY_ID_COUNTER: Atomic =3D Atomic::new(0); @@ -109,6 +115,11 @@ fn probe<'bound>( let bar1_idx =3D bar1_resource_index(pdev)?; pdev.iomap_region(bar1_idx, c"nova-core/bar1")? }, + _: { + let spec =3D Spec::new(pdev.as_ref(), bar)?; + + gpu::wait_gfw_boot_completion(pdev.as_ref(), bar, spec= .chipset)?; + }, // TODO: Use self-referential pin-init syntax once availab= le. gpu <- Gpu::new( pdev, diff --git a/drivers/gpu/nova-core/gpu.rs b/drivers/gpu/nova-core/gpu.rs index d763bc8d3827..3d796d6c7013 100644 --- a/drivers/gpu/nova-core/gpu.rs +++ b/drivers/gpu/nova-core/gpu.rs @@ -212,12 +212,12 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Res= ult { /// Structure holding a basic description of the GPU: `Chipset` and `Revis= ion`. #[derive(Clone, Copy)] pub(crate) struct Spec { - chipset: Chipset, + pub(crate) chipset: Chipset, revision: Revision, } =20 impl Spec { - fn new(dev: &device::Device, bar: Bar0<'_>) -> Result { + pub(crate) fn new(dev: &device::Device, bar: Bar0<'_>) -> Result= { // Some brief notes about boot0 and boot42, in chronological order: // // NV04 through NV50: @@ -362,17 +362,12 @@ pub(crate) fn new<'a>( dev_info!(dev,"NVIDIA ({})\n", spec); })?, =20 - // We must wait for GFW_BOOT completion before doing any signi= ficant setup on the GPU. _: { - let hal =3D hal::gpu_hal(spec.chipset); - let dma_mask =3D hal.dma_mask(); + let dma_mask =3D hal::gpu_hal(spec.chipset).dma_mask(); =20 // SAFETY: `Gpu` owns all DMA allocations for this device,= and we are // still constructing it, so no concurrent DMA allocations= can exist. unsafe { pdev.dma_set_mask_and_coherent(dma_mask)? }; - - hal.wait_gfw_boot_completion(bar) - .inspect_err(|_| dev_err!(dev, "GFW boot did not compl= ete\n"))?; }, =20 // Initialize this early because `gsp_resources` depends on it. @@ -495,6 +490,23 @@ pub(crate) fn run_selftests(self: Pin<&mut Self>, pdev= : &pci::Device, + bar: Bar0<'_>, + chipset: Chipset, +) -> Result { + hal::gpu_hal(chipset) + .wait_gfw_boot_completion(bar) + .inspect_err(|_| dev_err!(dev, "GFW boot did not complete\n")) +} + /// Reads the boot0 register and returns its raw value. pub(crate) fn boot_0_raw(bar: Bar0<'_>) -> u32 { bar.read(regs::NV_PMC_BOOT_0).into_raw() --=20 2.55.0 From nobody Fri Sep 25 13:19:17 2026 Received: from SN4PR2101CU001.outbound.protection.outlook.com (mail-southcentralusazon11012058.outbound.protection.outlook.com [40.93.195.58]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 339E437E5E3 for ; Sat, 12 Sep 2026 04:44:32 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=fail smtp.client-ip=40.93.195.58 ARC-Seal: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1789188274; cv=fail; b=elZYCFohk5XBXTiDYOptI5BPKqD6yIPFdCGEyhA3N+SniJNJ0NgKJGEAFIEVebWplQKPS6KAbE6F+8rTmUHC+EGjbx/duGwdFPEAUvDu1PlivuOdKVlADRUXa1ZYM0/zzJEljPW2uWs7HnNYUzJLdz8Qn/r+UQ6aNSdq6L8p13I= ARC-Message-Signature: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1789188274; c=relaxed/simple; bh=uucBPYsjvpMs6BC5eyn0gPXfCxhvFZNXXDxp+AJM3O8=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: Content-Type:MIME-Version; b=pD+vWseUphSVK28ooO4SjWIWosMeuRlhBmulac7vBJbbO0VDZkr2aExKJ/G9p7cg+UxaHBfMPQQGYxjVflXe9oZm7SO4QF7Yw5rnGsjlB6mCCpqIe+W1CYJkOB04UFheXRfQwa3xugg3u7d/+hewj2ZaBw9Oe1SNpnUO53w48tc= ARC-Authentication-Results: i=2; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=nvidia.com; spf=fail smtp.mailfrom=nvidia.com; dkim=pass (2048-bit key) header.d=Nvidia.com header.i=@Nvidia.com header.b=PbvvHv3a; arc=fail smtp.client-ip=40.93.195.58 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=nvidia.com Authentication-Results: smtp.subspace.kernel.org; spf=fail smtp.mailfrom=nvidia.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=Nvidia.com header.i=@Nvidia.com header.b="PbvvHv3a" ARC-Seal: i=1; a=rsa-sha256; s=arcselector10001; d=microsoft.com; cv=none; b=tQ1M+GY07orA0BPQdyaAx++/iJtdl77bpp7hx0NWmWENjYeKsDrrlH8msXej48ypPz+8j95PRldIukneP4+apuo1A3OvsU6TTREkDgLCUz7lZ9rVot+qXGN4UWq3LQzJmo4tAFLq5k1IpDT3nA5rdXfVQNzC+I31yN53hZggc4lkssddrA3HyoFuB9EayPD8RZ/N72HgDTicGdSgoeZHnQBJ4YZuwU379TSfvJBNH+itSF1jFFDotwY4B0EsSdElGi0ZPIIfUUCmazpb15yn+cNDcIR1A+FhHqQ3bH/aOo3mau73sN6jW/fIAzMAxFFFuUtr1rWCXvrCbzxk2V3oHQ== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=microsoft.com; s=arcselector10001; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-AntiSpam-MessageData-ChunkCount:X-MS-Exchange-AntiSpam-MessageData-0:X-MS-Exchange-AntiSpam-MessageData-1; bh=Dphgfae5pUaEKkRSGAjpjvZmaXfOQ0U4XEQOTzzDNsk=; b=a1MfWm/201LxvG0GH+SBzNZNcw+jBSJ/+GTRVXO5hg9VPk1yOnfBeoxeHyYjDC7n7cCleWpW3gaNEDH6fK2ZIKV2yHuS1d2wY4fhlbeFjRo9FGem1L3AVBGz+4ry45JnA6bYIn3ZOlqDTiWu2FYlwrMTPmyJEYOCCJFozSgxaUBv6DzyVvbdqUdEITYi4c8T8kYpeXLTo5DztHztzZOJwJViTqT7iK8RullJcZIHRfF2UqLXlz/XDAvaM/Aws0okfoj/J/OSFzS/z2mbGmmf7LepGFF5sH6zGIqvEvNas5FxaQ5gKCV2dZW3VQJZLVy5PoN9vmqgqq3O6DLRB9bk1g== ARC-Authentication-Results: i=1; mx.microsoft.com 1; spf=pass smtp.mailfrom=nvidia.com; dmarc=pass action=none header.from=nvidia.com; dkim=pass header.d=nvidia.com; arc=none DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=Nvidia.com; s=selector2; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck; bh=Dphgfae5pUaEKkRSGAjpjvZmaXfOQ0U4XEQOTzzDNsk=; b=PbvvHv3aCtMZf59oU3WekOGn7iaca3g+yv8iejfTdZ3v9WSpDWOXJk5HVR3lbV+cKN4xjksQYnL1NPgTXFwcbXitnB7DRs7JHoBs9/K7Es14CmQK6QPkVhSr3UVZqHiLfQM9s7dr4BoMrEWBfVTex5JTl8JNKCxDJWrcjmR7Ax7sqyTGjDXOgNldTQTJA8iXU8fAFDN3HM1GczZNozgtdJMryfjgHY31pFpMKo5Ih4p8tMBTCF3EhDbSwQtA4g2Q+YTZbu6RC2pGQjDqp3BAch86rMBKpVzD+HYyArQmj9TaUgL5dAslhaHHmPVHC4rUv20L3SQB5NX7ZSNNct88Hw== Authentication-Results: dkim=none (message not signed) header.d=none;dmarc=none action=none header.from=nvidia.com; Received: from DM3PR12MB9416.namprd12.prod.outlook.com (2603:10b6:0:4b::8) by PH8PR12MB7229.namprd12.prod.outlook.com (2603:10b6:510:227::20) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.21.406.10; Sat, 12 Sep 2026 04:44:22 +0000 Received: from DM3PR12MB9416.namprd12.prod.outlook.com ([fe80::8cdd:504c:7d2a:59c8]) by DM3PR12MB9416.namprd12.prod.outlook.com ([fe80::8cdd:504c:7d2a:59c8%4]) with mapi id 15.21.0406.007; Sat, 12 Sep 2026 04:44:22 +0000 From: John Hubbard To: Danilo Krummrich , Alexandre Courbot Cc: Timur Tabi , Alistair Popple , Eliot Courtney , Zhi Wang , David Airlie , Simona Vetter , Bjorn Helgaas , Miguel Ojeda , Alex Gaynor , Boqun Feng , Gary Guo , =?UTF-8?q?Bj=C3=B6rn=20Roy=20Baron?= , Benno Lossin , Andreas Hindborg , Alice Ryhl , Trevor Gross , nova-gpu@lists.linux.dev, LKML , John Hubbard , Joel Fernandes Subject: [PATCH v4 08/17] gpu: nova-core: add an interrupt delivery self-test Date: Fri, 11 Sep 2026 21:43:51 -0700 Message-ID: <20260912044400.677097-9-jhubbard@nvidia.com> X-Mailer: git-send-email 2.55.0 In-Reply-To: <20260912044400.677097-1-jhubbard@nvidia.com> References: <20260912044400.677097-1-jhubbard@nvidia.com> X-NVConfidentiality: public Content-Transfer-Encoding: quoted-printable X-ClientProxiedBy: BYAPR21CA0030.namprd21.prod.outlook.com (2603:10b6:a03:114::40) To DM3PR12MB9416.namprd12.prod.outlook.com (2603:10b6:0:4b::8) Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-MS-PublicTrafficType: Email X-MS-TrafficTypeDiagnostic: DM3PR12MB9416:EE_|PH8PR12MB7229:EE_ X-MS-Office365-Filtering-Correlation-Id: 003087e6-1039-42d3-4ebd-08df10888389 X-MS-Exchange-SenderADCheck: 1 X-MS-Exchange-AntiSpam-Relay: 0 X-Microsoft-Antispam: BCL:0;ARA:13230040|1800799024|7416014|376014|23010399003|366016|10067099003|6133799003|18002099003|5023799004|11063799006|56012099006|22082099003; X-Microsoft-Antispam-Message-Info: uVBHHBvnNV+1nvpXy+6/KxV0V9YtQIuJRrfhwzAhfU31YAmBqW1xkggd4jbRhrOsCii83jVerpmSdjVjpug2g8Q55uTnaLr5DAAZGinN2/oxFbdjIYB5yEpryiIVw3JtdhjdPrfVQNUxD29E/WHbnG311sFXXL9DZPFocrnKC3WLblDypw1ZvJzIXL52hDWMdHysQ67BawyrvZkD8GcBPL4EQ5hcnvyiMD4S97P4UFaitH/AkVoh97RA9BF6FHuSIFo7b1njvIZZWcrztfd6kv5JUd1zITw48d++J7EYwIhz9LKRIh2lSxV3cFeMg+g/Oo6zCGMWENWY9ezoRDzn8Am+xXldd++jYru99CZhxBiIgTzIAo2afJ3yT56bWJny5/tkkIAdengIgMiofCf+Dt8zH+4t3JwNoQGGhaGIkYKxzVcxCmv1yre3s0vuI7PsO6G6mI54omuHXW0IGhrd7EREVf332fy7KP009Ej6q1RSiaoKk6p8vRaaTFUF42z2LamVXdSBzNVUKud/QTPPGy3bBacK5eMV7o83pnYYhUjxkZVYKLn3p/3PMpaB1+h/qR6JZq/iXka+FKuMtbI36frTuVhoDowZ+1snbvyb3UYNTUE14g1ip9GVtPcQWcWs1TccDYzX8GW5EqA+u5vZE3gBm0DZ/Y0j1TI5iSQmn7A= X-Forefront-Antispam-Report: CIP:255.255.255.255;CTRY:;LANG:en;SCL:1;SRV:;IPV:NLI;SFV:NSPM;H:DM3PR12MB9416.namprd12.prod.outlook.com;PTR:;CAT:NONE;SFS:(13230040)(1800799024)(7416014)(376014)(23010399003)(366016)(10067099003)(6133799003)(18002099003)(5023799004)(11063799006)(56012099006)(22082099003);DIR:OUT;SFP:1101; X-MS-Exchange-AntiSpam-MessageData-ChunkCount: 1 X-MS-Exchange-AntiSpam-MessageData-0: =?us-ascii?Q?8BBdDn09UcIKpdy3r3FM/sRELP/McmtpDHbbO//By4c/B5fHIZcx4jbb8+Mq?= =?us-ascii?Q?0pBrKhhK81lsUxH31r5PbWYIIXJzuH2WCkGENYSPKLymPWDEUlbHauLHhuNf?= =?us-ascii?Q?6jIP6m6VTJggiVgu1mfySYf9yjN9xQPG33sr5F35MEUdbkiBYTr6kULfNm9g?= =?us-ascii?Q?ihtpihaoxg9KBwRFbLyDIJZ/U/jRwhEYbvoBozpZ3Hj8NcAGfGb9CcBs3wRW?= =?us-ascii?Q?ZUbC+HRoKU+v29A0X2Tu8QoQv2yAnDnlwKhZhcivvW1ylnDDaDafXW8QsP0z?= =?us-ascii?Q?xi9vShL7x8yVrpC3RbJmtmoyPt0cqJCxi7IUHyoubbOB1HGDS8lKRKU/8Wh/?= =?us-ascii?Q?EAL42M3hpR41t09bUzvFMLo5njj54eZLHgzVJymV7qzYR6Rm4xIycJwwTqU5?= =?us-ascii?Q?6yKhzYA9+naTglJNkVXDPLAwz6Yi0qoDxFMpGRbU5H5pYLOhLyQ9I2lnCQax?= =?us-ascii?Q?9//m+CQGlvg7XEPFHuyL2Ebyl6ypF+7S71fNFf5aFC4q4wdyN6ZuUEa7wc/s?= =?us-ascii?Q?71m1MgCyNbX7nevapkNp68ouiVx1rjA6KQVLGzmj57tTQH/NxgIL+ctREWHe?= =?us-ascii?Q?HZKnOnr0ot8ZycF/TJxZDxOAlgHUFjg38ZM3tYcp2E/r+6o1/SGW+n3cfrGh?= =?us-ascii?Q?5JShtd+oaYfVBlQTR3AbiCg2QD8xol+cUB4QK4sCZJPJKREZI3sNDX73tjvV?= =?us-ascii?Q?tsPDeu8CSGwolVjzFycL1rWv8ihoHOSS5QIC0aDHDFPEdcgRUhSw+MfUj6Ob?= =?us-ascii?Q?TgANCj0mPkSSkMuqAOaC63wB26eo3cj9OQFF4Y+jhuR7ejOeYqLjfAkMakan?= =?us-ascii?Q?Rsj5IiV7aJuClA34nnYFHrlfaDfoq0JaNil53oJ6VCTfz4778u/0fpd3UB06?= =?us-ascii?Q?n8+sFpMi9LgqIgrgPyIvVdtLkll7qlZ2/iMfR9vIKT19IN4SbhsY1J/C+AIv?= =?us-ascii?Q?wrqe/vXvRKwoBoI9ij85LjT+xOK7wwRhGF06S4BKLjNUU5h/6h3xxPj4lOaQ?= =?us-ascii?Q?OjKEYtWuL33LaQlyYaXHH9gu9zg4u7mNgGXuVwP+n5sFS/VkAvgP+VK0n6hl?= =?us-ascii?Q?7h34V8L0Mw+9RQqYs+yJfRClSXq7tOOx4+afpK65+L25Q+Cp2sacXlvnh5c9?= =?us-ascii?Q?BnXoLOPAay155TrIbDD818rXfG9uMK4IoRv3kExccycGlyB0dz1lhM4Bdjtd?= =?us-ascii?Q?IZuzyNlCV6mmjFJ/kN0rUFkNegbwPbz/9W31Mo9lPC5pKviyUbCKHLI2FuKt?= =?us-ascii?Q?lRvypEtNw4RAfmHQ0qDXabwm4+MNHUUqPVq5j0sOLIWlJmVZOxdXzP2b1PSR?= =?us-ascii?Q?LyFI2YA76go3sWHPD2T5MD6sHlbYSj2n7wd/UVANPWex980w/VF3V8GraVEU?= =?us-ascii?Q?qhODrhGmbERh0Arrd2MTxjywd8o97u8762hMZH+Y70iN+rNg4owCTeRaitRp?= =?us-ascii?Q?x7SgCiIQh0ocG7Hwov2kvCSEVlm7E1cQP3oPq65cjxzxPSQAJD/KApEiwe4v?= =?us-ascii?Q?DeeN7z2Uk/TLyJwTqMyTiZclsz+g50YXIbCAXekHPA64LSiD5pJXfzNiWC1x?= =?us-ascii?Q?UKURaUQeXYzJlDKDC5r6yeP2p1zAyfzEBTl/DXT4Fz7seVVjamWjKm6XDv9q?= =?us-ascii?Q?pwbjLQAJ1K9jLC+dm8L6Jyd3i1JYKwtuQXTNmjXYRYw7xPcFCxPeUaUDBBxX?= =?us-ascii?Q?kiD7sjiX8o99VJ9VYUa0MjZCcho4uvLgqNUNLTSUn9Gvp2raGGro1vZzQq3O?= =?us-ascii?Q?uYplFbISlA=3D=3D?= X-OriginatorOrg: Nvidia.com X-MS-Exchange-CrossTenant-Network-Message-Id: 003087e6-1039-42d3-4ebd-08df10888389 X-MS-Exchange-CrossTenant-AuthSource: DM3PR12MB9416.namprd12.prod.outlook.com X-MS-Exchange-CrossTenant-AuthAs: Internal X-MS-Exchange-CrossTenant-OriginalArrivalTime: 12 Sep 2026 04:44:21.9788 (UTC) X-MS-Exchange-CrossTenant-FromEntityHeader: Hosted X-MS-Exchange-CrossTenant-Id: 43083d15-7273-40c1-b7db-39efd9ccc17a X-MS-Exchange-CrossTenant-MailboxType: HOSTED X-MS-Exchange-CrossTenant-UserPrincipalName: rJrHoQHht2lxI15q5r6CYhM2CcU80n2ZvvB11A6rk8yM0G/6xVf4QC+xGC0Jxj2as79ZsklxjR9SIGA6gOnUBg== X-MS-Exchange-Transport-CrossTenantHeadersStamped: PH8PR12MB7229 Content-Type: text/plain; charset="utf-8" A GPU interrupt can be lost in the MSI or MSI-X allocation, in the GIN tree's enables, or in the rearm, and every one of those failures looks the same: no interrupt arrives, and nothing says which one broke. Add a probe-time self-test, built under NOVA_CORE_SELFTESTS, that latches the CPU doorbell vector through the GIN software trigger and waits for a registered handler to service it. One delivery would pass with a broken rearm, because the first message-signaled interrupt arrives whether or not the driver rearms, so the test triggers twice and waits for the first handler to finish before the second trigger. It runs after GFW boot and before GSP boot, on a quiesced tree, and fails probe unless both deliveries arrive, each finds only the doorbell pending, and the leaf ends clear. The doorbell has the same vector on every supported GPU, so the test names it without asking GSP-RM. It allocates the PCI vectors for the doorbell's subtree and releases them before returning, so under MSI-X the delivery also exercises that subtree's table entry. Assisted-by: LLM Co-developed-by: Joel Fernandes Signed-off-by: Joel Fernandes Signed-off-by: John Hubbard --- drivers/gpu/nova-core/Kconfig | 5 + drivers/gpu/nova-core/driver.rs | 5 + drivers/gpu/nova-core/irq.rs | 2 + drivers/gpu/nova-core/irq/doorbell_test.rs | 266 ++++++++++++++++++++ drivers/gpu/nova-core/irq/interrupt_tree.rs | 2 +- drivers/gpu/nova-core/nova_core.rs | 2 +- 6 files changed, 280 insertions(+), 2 deletions(-) create mode 100644 drivers/gpu/nova-core/irq/doorbell_test.rs diff --git a/drivers/gpu/nova-core/Kconfig b/drivers/gpu/nova-core/Kconfig index 1934f17baa8b..2e11e46c99c7 100644 --- a/drivers/gpu/nova-core/Kconfig +++ b/drivers/gpu/nova-core/Kconfig @@ -24,4 +24,9 @@ config NOVA_CORE_SELFTESTS help Build the driver self-tests and run them when the GPU is probed. =20 + If the interrupt delivery test fails, the probe fails and the driver + does not bind to the GPU. A broken interrupt path would otherwise + show up later as a hang, far from its cause. Every other self-test + logs its failure and lets the probe continue. + If unsure, say N. diff --git a/drivers/gpu/nova-core/driver.rs b/drivers/gpu/nova-core/driver= .rs index 15a44f9a6441..4400cae8c8ce 100644 --- a/drivers/gpu/nova-core/driver.rs +++ b/drivers/gpu/nova-core/driver.rs @@ -119,6 +119,11 @@ fn probe<'bound>( let spec =3D Spec::new(pdev.as_ref(), bar)?; =20 gpu::wait_gfw_boot_completion(pdev.as_ref(), bar, spec= .chipset)?; + + // The self-test disables and drains the whole tree, s= o it has to run before + // `Gpu::new` boots the GSP. + #[cfg(CONFIG_NOVA_CORE_SELFTESTS)] + crate::irq::doorbell_test::run_selftest(pdev, bar, spe= c.chipset)?; }, // TODO: Use self-referential pin-init syntax once availab= le. gpu <- Gpu::new( diff --git a/drivers/gpu/nova-core/irq.rs b/drivers/gpu/nova-core/irq.rs index 28f147641024..7fb7d9f2e237 100644 --- a/drivers/gpu/nova-core/irq.rs +++ b/drivers/gpu/nova-core/irq.rs @@ -9,6 +9,8 @@ //! //! See `Documentation/gpu/nova/core/interrupts.rst`. =20 +#[cfg(CONFIG_NOVA_CORE_SELFTESTS)] +pub(crate) mod doorbell_test; mod hal; mod interrupt_tree; mod regs; diff --git a/drivers/gpu/nova-core/irq/doorbell_test.rs b/drivers/gpu/nova-= core/irq/doorbell_test.rs new file mode 100644 index 000000000000..a1f8b3cc377b --- /dev/null +++ b/drivers/gpu/nova-core/irq/doorbell_test.rs @@ -0,0 +1,266 @@ +// SPDX-License-Identifier: GPL-2.0 +// SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIA= TES. All rights reserved. + +//! Interrupt delivery self-test. +//! +//! The test triggers the CPU doorbell vector from software, twice, and ch= ecks that each trigger +//! reaches a registered handler. It runs during probe under `CONFIG_NOVA_= CORE_SELFTESTS`. +//! +//! See "Self-test" in `Documentation/gpu/nova/core/interrupts.rst`. + +use core::pin::Pin; + +use kernel::{ + device::Bound, + irq, + pci, + prelude::*, + sync::{ + atomic::{ + Atomic, + Relaxed, // + }, + Completion, // + }, + time, // +}; + +use super::interrupt_tree::{ + GinVector, + LeafEnableGuard, + LeafMask, + Subtree, + TopEnableGuard, + Tree, // +}; + +use crate::{ + driver::Bar0, + gpu::Chipset, + selftest_assert, + selftest_assert_eq, // +}; + +/// The CPU doorbell vector. Every supported GPU uses this number, so the = test needs nothing from +/// GSP-RM, which is not running yet. +const DOORBELL_VECTOR: GinVector =3D GinVector::new::<129>(); + +/// The only subtree that this test services. +const DOORBELL_SUBTREE: Subtree =3D DOORBELL_VECTOR.subtree(); + +/// Time allowed for each delivery to arrive. +const DELIVERY_TIMEOUT_MS: time::Msecs =3D 1000; + +/// The self-test's interrupt handler. +/// +/// It clears only the doorbell's bit, rearms delivery, and never walks th= e tree. A missing rearm +/// shows up as a timeout on the second delivery. +#[pin_data] +struct DoorbellTestHandler<'a> { + tree: Tree<'a>, + /// Completed by the first delivery. + #[pin] + first: Completion, + /// Completed by the second delivery. + #[pin] + second: Completion, + /// Deliveries that found the doorbell bit set. + irq_count: Atomic, + /// The doorbell leaf's pending bits, as read by the first delivery. + first_pending: Atomic, + /// The doorbell leaf's pending bits, as read by the second delivery. + second_pending: Atomic, +} + +impl irq::Handler for DoorbellTestHandler<'_> { + fn handle(&self) -> irq::IrqReturn { + let leaf =3D self.tree.read_pending(DOORBELL_VECTOR.leaf_index()); + let pending =3D leaf.vectors(); + if !pending.contains(DOORBELL_VECTOR.leaf_mask()) { + self.tree.rearm_pci_irq(DOORBELL_SUBTREE); + return irq::IrqReturn::None; + } + leaf.clear_vectors(DOORBELL_VECTOR.leaf_mask()); + + let count =3D self.irq_count.fetch_add(1, Relaxed); + + // Rearm before completing, since the waiting thread triggers the = next doorbell as soon as + // it wakes. + self.tree.rearm_pci_irq(DOORBELL_SUBTREE); + + match count { + 0 =3D> { + self.first_pending.store(pending.into_raw(), Relaxed); + self.first.complete_all(); + } + 1 =3D> { + self.second_pending.store(pending.into_raw(), Relaxed); + self.second.complete_all(); + } + _ =3D> (), + } + + irq::IrqReturn::Handled + } +} + +/// The self-test's handler registration and the enables that deliver to i= t. +/// +/// Drops in the order that "Enabling the GSP event" in +/// `Documentation/gpu/nova/core/interrupts.rst` requires: the vector is d= isabled, then the +/// handler is freed, then the subtree is disabled. +struct SelftestResources<'a, 'r> { + _leaf_guard: LeafEnableGuard<'a>, + reg: Pin>>>, + _top_guard: TopEnableGuard<'a>, +} + +impl<'a> SelftestResources<'a, '_> { + fn handler(&self) -> &DoorbellTestHandler<'a> { + self.reg.handler() + } + + /// Disables the doorbell vector and waits for a handler in flight on = another CPU to finish. + /// + /// The handler's counters and the leaf's pending bits are final on re= turn. + fn quiesce_source(&self) { + self.handler() + .tree + .disable_leaf(DOORBELL_VECTOR.leaf_index(), DOORBELL_VECTOR.le= af_mask()); + self.reg.synchronize(); + } +} + +/// Runs the interrupt delivery self-test. +/// +/// Call this only during probe, before GSP boot: it disables every vector= in the tree and clears +/// every pending bit. On return, the doorbell's subtree is disabled at `T= OP`, and the test's PCI +/// vectors and handler are released. +/// +/// # Errors +/// +/// `EINVAL` if `chipset` does not implement the doorbell's subtree. `ETIM= EDOUT` if a delivery +/// does not arrive within [`DELIVERY_TIMEOUT_MS`]. `EIO` if a self-test a= ssertion fails. +/// Otherwise the error from allocating the PCI vectors or registering the= handler. +pub(crate) fn run_selftest(pdev: &pci::Device, bar: Bar0<'_>, chips= et: Chipset) -> Result { + let dev =3D pdev.as_ref(); + + let vectors =3D super::alloc_vectors(pdev, DOORBELL_SUBTREE.into())?; + let request =3D vectors.request_for(DOORBELL_SUBTREE)?; + let tree =3D Tree::new(bar, chipset, &vectors)?; + let doorbell =3D DOORBELL_VECTOR.leaf_index(); + let doorbell_mask =3D DOORBELL_VECTOR.leaf_mask(); + + dev_info!( + dev, + "interrupt self-test: starting on vector {}, subtree {}, with {:?}= \n", + DOORBELL_VECTOR.into_raw(), + DOORBELL_SUBTREE.index(), + vectors.msi_type, + ); + + // GFW boot can leave vectors enabled and pending. Registering a handl= er unmasks the PCI + // interrupt, and they would be delivered to a handler that services o= nly the doorbell. + tree.disable_all_leaves(); + tree.drain(); + + // A delivery proves nothing unless the doorbell bit starts out clear. + let pre_pending =3D tree.read_pending(doorbell).vectors(); + selftest_assert!( + dev, + !pre_pending.contains(doorbell_mask), + "vector {} already pending, leaf[{}] is {:#x}", + DOORBELL_VECTOR.into_raw(), + doorbell.get(), + pre_pending.into_raw() + ); + + let handler_init =3D try_pin_init!(DoorbellTestHandler { + tree, + first <- Completion::new(), + second <- Completion::new(), + irq_count: Atomic::new(0), + first_pending: Atomic::new(0), + second_pending: Atomic::new(0), + }? Error); + + // Registration must precede any enable, or a delivery reaches no hand= ler. + let reg =3D KBox::pin_init( + // SAFETY: this registration is dropped before the enclosing funct= ion returns, so its + // `Drop`, which calls `free_irq()`, always runs. + unsafe { + irq::Registration::new( + request, + irq::Flags::TRIGGER_NONE, + c"nova-core-selftest", + handler_init, + ) + }, + GFP_KERNEL, + )?; + + let resources =3D SelftestResources { + _leaf_guard: reg + .handler() + .tree + .enable_leaf_guarded(doorbell, doorbell_mask), + _top_guard: reg.handler().tree.enable_top_guarded(), + reg, + }; + let handler =3D resources.handler(); + + handler.tree.trigger(DOORBELL_VECTOR)?; + let mut completed =3D handler + .first + .wait_for_completion_timeout(time::msecs_to_jiffies(DELIVERY_TIMEO= UT_MS)) + .is_some(); + + // The second trigger waits for the first delivery, or the two could c= oalesce. + if completed { + handler.tree.trigger(DOORBELL_VECTOR)?; + completed =3D handler + .second + .wait_for_completion_timeout(time::msecs_to_jiffies(DELIVERY_T= IMEOUT_MS)) + .is_some(); + } + + resources.quiesce_source(); + + let count =3D handler.irq_count.load(Relaxed); + let first_pending =3D LeafMask::from_raw(handler.first_pending.load(Re= laxed)); + let second_pending =3D LeafMask::from_raw(handler.second_pending.load(= Relaxed)); + let residual =3D handler.tree.read_pending(doorbell).vectors(); + + if !completed { + dev_err!( + dev, + "interrupt self-test: only {} of 2 deliveries arrived within {= } ms\n", + count, + DELIVERY_TIMEOUT_MS, + ); + return Err(ETIMEDOUT); + } + + selftest_assert_eq!(dev, count, 2, "delivery count"); + + // Every other vector in the leaf is disabled and was drained, so requ= ire the exact mask. + selftest_assert_eq!(dev, first_pending, doorbell_mask, "first delivery= "); + selftest_assert_eq!(dev, second_pending, doorbell_mask, "second delive= ry"); + selftest_assert!( + dev, + !residual.contains(doorbell_mask), + "vector {} still pending, leaf[{}] is {:#x}", + DOORBELL_VECTOR.into_raw(), + doorbell.get(), + residual.into_raw() + ); + + dev_info!( + dev, + "interrupt self-test: passed, subtree {}, {} deliveries\n", + DOORBELL_SUBTREE.index(), + count, + ); + + Ok(()) +} diff --git a/drivers/gpu/nova-core/irq/interrupt_tree.rs b/drivers/gpu/nova= -core/irq/interrupt_tree.rs index 2583b006019e..f77920a3b30a 100644 --- a/drivers/gpu/nova-core/irq/interrupt_tree.rs +++ b/drivers/gpu/nova-core/irq/interrupt_tree.rs @@ -402,7 +402,7 @@ pub(super) fn read_pending(&self, leaf: LeafIndex) -> L= eafPending<'a> { /// /// `EINVAL` if this tree does not implement `vector`. // The interrupt self-test is the only caller. - #[expect(dead_code)] + #[cfg_attr(not(CONFIG_NOVA_CORE_SELFTESTS), expect(dead_code))] pub(super) fn trigger(&self, vector: GinVector) -> Result { vector.validate(self.leaves)?; self.bar.write_reg( diff --git a/drivers/gpu/nova-core/nova_core.rs b/drivers/gpu/nova-core/nov= a_core.rs index 5176a5fe2da2..abafe4f2968d 100644 --- a/drivers/gpu/nova-core/nova_core.rs +++ b/drivers/gpu/nova-core/nova_core.rs @@ -17,7 +17,7 @@ mod fsp; mod gpu; mod gsp; -#[expect(dead_code)] +#[cfg_attr(not(CONFIG_NOVA_CORE_SELFTESTS), expect(dead_code))] mod irq; mod mctp; mod mm; --=20 2.55.0 From nobody Fri Sep 25 13:19:17 2026 Received: from BYAPR05CU005.outbound.protection.outlook.com (mail-westusazon11010052.outbound.protection.outlook.com [52.101.85.52]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id B88A437B41E for ; Sat, 12 Sep 2026 04:44:32 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=fail smtp.client-ip=52.101.85.52 ARC-Seal: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1789188274; cv=fail; b=L3ZYe/3slyv7VcC7lgxwN5Y47EvEBSMwCnDHJd+gdg/926Fz9gcNGCN55mkNoLqKR61HSVNmhRe4nvwltGMcX+Gv4ghkYvikwYzmklsK67JVdtbZzZtQDGj3yKR9bVYTZPx9XKYA1Kb5Z6gATc0/IZN6SGleMBtxw7PGUYs8PKg= ARC-Message-Signature: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1789188274; c=relaxed/simple; bh=O/FR7xhvvFs6Rf4UOYXrjcJCUxK3F5G3FKsdIKvp5Cg=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: Content-Type:MIME-Version; b=LaB8AZxlsi6NL2uBCuvj8bm212rqhW8qZbf4j7qZRkGIAUGN912ZHbllJZpgiPpQc8kwTFnyFcE96qpjr0GQljZD6OaxuQKWWarSYJSKW5gyTI6YWweGvUWzmPuX15Ij626Z4wzVgQGLD5U5lDgn+bUdv8ZAlWHi55CRmq7lX0s= ARC-Authentication-Results: i=2; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=nvidia.com; spf=fail smtp.mailfrom=nvidia.com; dkim=pass (2048-bit key) header.d=Nvidia.com header.i=@Nvidia.com header.b=rZh+2xU+; arc=fail smtp.client-ip=52.101.85.52 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=nvidia.com Authentication-Results: smtp.subspace.kernel.org; spf=fail smtp.mailfrom=nvidia.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=Nvidia.com header.i=@Nvidia.com header.b="rZh+2xU+" ARC-Seal: i=1; a=rsa-sha256; s=arcselector10001; d=microsoft.com; cv=none; b=gTX3B4ijrTt/+bWNNBg5fMfe2UOVW3KfIkV1vDDhXCZNNJrZYLWWEMepY+oKTPJeeGfjnlm9H1UEKRv+JodicJg6YUGCM8HIxSPtfRrwhAHUpjMc51cu4Sk6CF+7/s4Tj9aNnGLEqVqEHwJpOD/mDC5BjkuTFbUtBnAqy0qhv33eHddhtjUyVO0OwAGLToYT8zkaURNFeL/4Ve21YpBX3GOWi+iaIdrjKPKqXsxtuzDe+U2BuNnUmqm+9UvXwGG9GoPFnRoRcBDeB3pkXkORvT36uvtgYjwRMNwAii6GbaeQOWY5E4nwWUQ2RNEUCjofWmoFhTZb2VSX1Y9xdxjowg== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=microsoft.com; s=arcselector10001; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-AntiSpam-MessageData-ChunkCount:X-MS-Exchange-AntiSpam-MessageData-0:X-MS-Exchange-AntiSpam-MessageData-1; bh=e8xHDPOhB/UlseLs0Wc74QXcMaevqA4WDI+EbLisdcQ=; b=w0praGf8bD4kaUfiKqzEGDUWHgRSuAiJlf1H7FeKIrQ0AajfxmlZl4TvnInZqRFp9MsO15GDYuIP3YCoE1oXN0o72EQAxMvBnXPxGXESWYPy4RLCN84pUrllq8wOei5UVyTk3rNAVKVB1Y3aGo9LJH8vvgX8hlLdDnAh6OYcELzE2OBEq/4vcF8RUyotdaeU72Lvc8csGPkfMJYhZFTjYGlnFvCyxasdpHELzKlK3Y7Au2oK1UCjlihr+AUU+zuxCW4Gct0gapdhNuJuvNhvOgrE07GaRH5eNIIaM+CgN11rwhGP6XPxrx8Lais+CKp9HU7ONdrXKNwYUdhk9nPheg== ARC-Authentication-Results: i=1; mx.microsoft.com 1; spf=pass smtp.mailfrom=nvidia.com; dmarc=pass action=none header.from=nvidia.com; dkim=pass header.d=nvidia.com; arc=none DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=Nvidia.com; s=selector2; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck; bh=e8xHDPOhB/UlseLs0Wc74QXcMaevqA4WDI+EbLisdcQ=; b=rZh+2xU+10xL6Fracm79mJ9zEe/2CstA2PUUFaZR0HeoTkECNJMTQ86Gt8whR/HEnOYY3CJeoqcR98vkYnuCB3ULX79fhW/zwCcQ/5C5R/hc8EPMeLp9+kTZQqtQQZZJHfdqSIPjFIDftn2d88Nn10unqX5rVKqAkk/ai8ybpYbyIvIjYGa6NQ4vlIN4b4Nx+QcfAv++67Icp7HkQD0BJIXwKbkDRObRRSHerjKOHVyV57cZ6TV8bUZLu6jQrUIOEtELe+64RyF1mJheoJu5YMuZjEAYi1txB8GKnWLMNpChMIRyuayDGBiRCjWjILo63PF8SKQnALRZ35pXNamV8Q== Authentication-Results: dkim=none (message not signed) header.d=none;dmarc=none action=none header.from=nvidia.com; Received: from DM3PR12MB9416.namprd12.prod.outlook.com (2603:10b6:0:4b::8) by PH8PR12MB7229.namprd12.prod.outlook.com (2603:10b6:510:227::20) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.21.406.10; Sat, 12 Sep 2026 04:44:23 +0000 Received: from DM3PR12MB9416.namprd12.prod.outlook.com ([fe80::8cdd:504c:7d2a:59c8]) by DM3PR12MB9416.namprd12.prod.outlook.com ([fe80::8cdd:504c:7d2a:59c8%4]) with mapi id 15.21.0406.007; Sat, 12 Sep 2026 04:44:23 +0000 From: John Hubbard To: Danilo Krummrich , Alexandre Courbot Cc: Timur Tabi , Alistair Popple , Eliot Courtney , Zhi Wang , David Airlie , Simona Vetter , Bjorn Helgaas , Miguel Ojeda , Alex Gaynor , Boqun Feng , Gary Guo , =?UTF-8?q?Bj=C3=B6rn=20Roy=20Baron?= , Benno Lossin , Andreas Hindborg , Alice Ryhl , Trevor Gross , nova-gpu@lists.linux.dev, LKML , John Hubbard Subject: [PATCH v4 09/17] gpu: nova-core: log GSP events instead of discarding them Date: Fri, 11 Sep 2026 21:43:52 -0700 Message-ID: <20260912044400.677097-10-jhubbard@nvidia.com> X-Mailer: git-send-email 2.55.0 In-Reply-To: <20260912044400.677097-1-jhubbard@nvidia.com> References: <20260912044400.677097-1-jhubbard@nvidia.com> X-NVConfidentiality: public Content-Transfer-Encoding: quoted-printable X-ClientProxiedBy: SJ0PR13CA0109.namprd13.prod.outlook.com (2603:10b6:a03:2c5::24) To DM3PR12MB9416.namprd12.prod.outlook.com (2603:10b6:0:4b::8) Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-MS-PublicTrafficType: Email X-MS-TrafficTypeDiagnostic: DM3PR12MB9416:EE_|PH8PR12MB7229:EE_ X-MS-Office365-Filtering-Correlation-Id: c4d87f80-f4fc-414b-599f-08df10888447 X-MS-Exchange-SenderADCheck: 1 X-MS-Exchange-AntiSpam-Relay: 0 X-Microsoft-Antispam: BCL:0;ARA:13230040|1800799024|7416014|376014|23010399003|366016|10067099003|6133799003|18002099003|5023799004|11063799006|56012099006|22082099003; X-Microsoft-Antispam-Message-Info: cBkf0N+XblJ4DOwITtEdMYkaQze4xK3RYmZO4N9hslDKZfpGZQXMYtzIlVRCUISa1uYKz3qlZx6z/F4I+cGF1IZOKS8YEb7HmXYaGdXMf+sw4Zgi0u/ziChbx+GVKgCTHL15PfBDKZrdOwWumrJCGc7RmtmfXzaKEEAvr1vmo+vYZJebeUHIShTX6bvavrgxntWiL7VJz0sz653V39SkUZi84smRzrQS0nc2v9GX4RbeE6rEeJIZmMmEKpxSX2ImjCW85XJFh/zICPT64IxYBEJqXKVL1S/1ejyzOX5t4t7t7iNnBUCuSvH+tI96RsfqaF82bWD0BuzvRVfA2Ff9upcsUPNkYFLQVOZ69xApnsuQogC1zw8LYGf8vkxUZuCZ8l65W0N77i6bIl5B3RhnUjqPM5NKdsKBGde/rbu0W59feFTd+H5+VZYiY9+x8OS0o7WnkK7a2kdc2rBiVpvXOkVBpKons4PqfgTisDj0v4C6qZVsqft1/mqWhzF968LYjmRPG5GCodEMWQhhszJgZICYUr0pocaHqc4LtAstshlobBTuG9+gKoBWmKo9xfCDa3hRFULWgPbkScLCA1cqGxhomhgqLMIv+khuAA5c89AWByrQct/7ujJVdJfNU/KB8FudW4BBHU/kU61NbSLknZ/c+pbJOvyi1KUvFjTvTrk= X-Forefront-Antispam-Report: CIP:255.255.255.255;CTRY:;LANG:en;SCL:1;SRV:;IPV:NLI;SFV:NSPM;H:DM3PR12MB9416.namprd12.prod.outlook.com;PTR:;CAT:NONE;SFS:(13230040)(1800799024)(7416014)(376014)(23010399003)(366016)(10067099003)(6133799003)(18002099003)(5023799004)(11063799006)(56012099006)(22082099003);DIR:OUT;SFP:1101; X-MS-Exchange-AntiSpam-MessageData-ChunkCount: 1 X-MS-Exchange-AntiSpam-MessageData-0: =?us-ascii?Q?fvGjF4PfUgkIlOPJzzCs56e7ItXIq85d8tOSHxzXNQAiAxbepGsD9nvvRflk?= =?us-ascii?Q?8u9EpdrYhGXKBWNSuDP79YFlaFzqCqojVI87U7iJCErwgJ32SF4UpJCFCX5q?= =?us-ascii?Q?O7q014EbflPs6kLcYzlLqqrDYaee32swxntRf5J7TY+THai9vvQ2Ah1e6cr4?= =?us-ascii?Q?VrR078jTo/B9Le7dJuI7z25LY555ezp8Ae1hlld8QjOmOvx94tQjoqrngJ7b?= =?us-ascii?Q?hhFQVehmdfQ/t9wtRrUTYF+6/S+ftA886zMsfKTySBJ9p49URiaQQYFVW46g?= =?us-ascii?Q?1YrC/azYw/4JMOqNYLyfCW9x44ag0LchBapK5fxYycnbmTdAHuEui7if7NoY?= =?us-ascii?Q?4SQoETPoGPjidn2P+FolwD/UmBJt5D9TNpClVdX4TTEAVtyCsJtmmv08OKj5?= =?us-ascii?Q?YXO+XxOAahlElZRjFt4u4rqfBHhBMr7kSElJLh2cCTYqFcBQvF4a1G1xbPYx?= =?us-ascii?Q?R6m5bIJAiVXEePDsiwljzigjDfaj0tpYSxAPTq+DDg8MswGWip2y49GXKG3y?= =?us-ascii?Q?HijRRUh2uZJSXrBTqs6mxE9RAtNhAXzzspYK4fS3/6bmUvReg/Naxn8OypV1?= =?us-ascii?Q?lKdfo9HDcU5w4XMflAYqE7Ku8jp1G6zqxeM25qGKw0cIegZHg0CqpmlpLrKp?= =?us-ascii?Q?MJvW1rat+vRTg7U4aV7L6EUlHza9Aof+NgYQXtZ93DHYTeuqVYKRmpwxipGB?= =?us-ascii?Q?u8JVpz7M2zXF0Tvu9Wf0Mp4qjVGz3pkgnGp99bKl/Fge/efCQXF4Zzd4bhh5?= =?us-ascii?Q?T+sB/eT1UrsLHIepo9cZna0RL6I4igd4rVPYLzvAj9gneIEQUQ5WvRoWrfnY?= =?us-ascii?Q?PNG5Qm96jhbwvfAt+KKjYbMc3h4WAUqEUnbtstRqW/q2C8E3kEe2ga5IxQay?= =?us-ascii?Q?oFwebqTIe2tXru9/SZPKaG62GfsJLZvgFAs7CvJxHnd+pbTUnn+o72qnWCNX?= =?us-ascii?Q?VBuSFxzOypxCRWSbRrW/iqcTbkwX+Xyks5/rRsMwXoX6eT9vCBRbwtwK8n+L?= =?us-ascii?Q?hZL9C7+ZbUIkKz6asz5yxqJakPBo3tQCfo7ytOGXFhFmL4UeXCf3+DwTaLge?= =?us-ascii?Q?CdNlv8wNeJSWU+hTJgo5XXX3fROKzinKOUhSKYIE6XjvSgDLEQ/ZPc2NA5bO?= =?us-ascii?Q?cz8+lbe1TTiBk9XC3/dbEryXGp3ZHEB6nvij58KONIpILsbOeVv356SpVlOU?= =?us-ascii?Q?PbPM/LTA0YrYM+QZW01LHsTfFk2v+Ia9/CdXTihOuYAtrkwUMR3cy6Bu2LuJ?= =?us-ascii?Q?MKVc+RDCfys3VIEpUClKubAugkdjB0GQuElvTbp2N6M5xOkPu62ryGsElcEX?= =?us-ascii?Q?3TL5kxngReCfd0m8Rb/6AUn3zsD8ahchoYpiEDnLi8h9kuYpDLi2GUcpxu4E?= =?us-ascii?Q?3GjYg9EH9rcAkTu+jRaZBTYzcmcBUZDjp4yUam1fXG2P+a3TLYCPN4qWUSop?= =?us-ascii?Q?+/pEvwXi0jBwTymZUngRJtB7EKqGQTFVgaS+U0uVsgEYdvRsg33MOYY4Cg6W?= =?us-ascii?Q?pmF/gfT/Gxaf4YlzeA3i+kQgqHVjpP953MRr4WKbXQu731k5dMiba0cxFiir?= =?us-ascii?Q?gVNUSzceXJEjYqx05ulHPh/JUVtub2cL4UQTyRmNhedRlX8OqXLj8DzJCfiS?= =?us-ascii?Q?GiHi4aBxvgr6Ee+b+zE4w+gaocUv861mwSSb1h4LvJdvCLwYfwlziM822CfA?= =?us-ascii?Q?ENlK1OpW8KLGu7KgjoVXCojk82JOXGVL+Sjox7r6feAOwvCDQe1aUmrDGymO?= =?us-ascii?Q?BN/DusPF0A=3D=3D?= X-OriginatorOrg: Nvidia.com X-MS-Exchange-CrossTenant-Network-Message-Id: c4d87f80-f4fc-414b-599f-08df10888447 X-MS-Exchange-CrossTenant-AuthSource: DM3PR12MB9416.namprd12.prod.outlook.com X-MS-Exchange-CrossTenant-AuthAs: Internal X-MS-Exchange-CrossTenant-OriginalArrivalTime: 12 Sep 2026 04:44:23.2261 (UTC) X-MS-Exchange-CrossTenant-FromEntityHeader: Hosted X-MS-Exchange-CrossTenant-Id: 43083d15-7273-40c1-b7db-39efd9ccc17a X-MS-Exchange-CrossTenant-MailboxType: HOSTED X-MS-Exchange-CrossTenant-UserPrincipalName: yYkDC9OyQ6t+NvXUhuqmKRYmWZfdPAW941wphGhxtHRY7/wTs4RcVPoMcBggejMPCM6gP79a8HMyRjcNiogNmA== X-MS-Exchange-Transport-CrossTenantHeadersStamped: PH8PR12MB7229 Content-Type: text/plain; charset="utf-8" The GSP posts unsolicited messages on the same queue that carries command replies: log records, OS error and robust-channel records, and lifecycle notices. nova-core discarded every message that was not the reply a caller was waiting for, and an unrecognized function code aborted the in-flight command. The GSP's error reports never reached the kernel log. Log every non-reply message according to its function code, on the receive path that already reads it, and leave the in-flight command waiting for its reply. Event payloads, such as XID numbers and log contents, are not decoded. Assisted-by: LLM Signed-off-by: John Hubbard --- drivers/gpu/nova-core/gsp/cmdq.rs | 52 ++++++++++++++++++++++++------- 1 file changed, 41 insertions(+), 11 deletions(-) diff --git a/drivers/gpu/nova-core/gsp/cmdq.rs b/drivers/gpu/nova-core/gsp/= cmdq.rs index 9f99e6bbb4fa..340760e384d0 100644 --- a/drivers/gpu/nova-core/gsp/cmdq.rs +++ b/drivers/gpu/nova-core/gsp/cmdq.rs @@ -557,8 +557,7 @@ fn notify_gsp(bar: Bar0<'_>) { =20 /// Sends `command` to the GSP and waits for the reply. /// - /// Messages with non-matching function codes are silently consumed un= til the expected reply - /// arrives. + /// Events that arrive before the reply are logged and consumed. /// /// The queue is locked for the entire send+receive cycle to ensure th= at no other command can /// be interleaved. @@ -815,8 +814,8 @@ fn wait_for_msg(&self, timeout: Delta) -> Result> { =20 /// Receive a message from the GSP. /// - /// The expected message type is specified using the `M` generic param= eter. If the pending - /// message has a different function code, `ERANGE` is returned and th= e message is consumed. + /// A message whose function code is `M::FUNCTION` is decoded and retu= rned. Any other message + /// is logged as an event. /// /// The read pointer is always advanced past the message, regardless o= f whether it matched. /// @@ -825,8 +824,7 @@ fn wait_for_msg(&self, timeout: Delta) -> Result> { /// - `ETIMEDOUT` if `timeout` has elapsed before any message becomes = available. /// - `EIO` if there was some inconsistency (e.g. message shorter than= advertised) on the /// message queue. - /// - `EINVAL` if the function code of the message was not recognized. - /// - `ERANGE` if the message had a recognized but non-matching functi= on code. + /// - `ERANGE` if the message was not the awaited reply. /// /// Error codes returned by [`MessageFromGsp::read`] are propagated as= -is. fn receive_msg(&mut self, timeout: Delta) -> Result= @@ -835,11 +833,11 @@ fn receive_msg(&mut self, timeout:= Delta) -> Result Error: From, { let message =3D self.wait_for_msg(timeout)?; - let function =3D message.header.function().map_err(|_| EINVAL)?; + let function =3D message.header.function(); + let seq =3D message.header.sequence(); =20 - // Extract the message. Store the result as we want to advance the= read pointer even in - // case of failure. - let result =3D if function =3D=3D M::FUNCTION { + // An early return here would leave the read pointer on this messa= ge. + let result =3D if matches!(function, Ok(f) if f =3D=3D M::FUNCTION= ) { let (cmd, contents_1) =3D M::Message::from_bytes_prefix(messag= e.contents.0).ok_or(EIO)?; let mut sbuffer =3D SBufferIter::new_reader([contents_1, messa= ge.contents.1]); =20 @@ -850,11 +848,13 @@ fn receive_msg(&mut self, timeout:= Delta) -> Result dev_warn!( &self.dev, "GSP message {:?} has unprocessed data\n", - function + M::FUNCTION ); } }) } else { + self.log_event(function, seq); + Err(ERANGE) }; =20 @@ -865,4 +865,34 @@ fn receive_msg(&mut self, timeout: = Delta) -> Result =20 result } + + /// Logs an event, meaning a message that no caller was waiting for. + /// + /// An OS error or robust-channel record is logged at error level and = an unknown function code + /// at warning level. Every other event is recorded only by the receiv= e trace in + /// [`Self::wait_for_msg`]. + fn log_event(&self, function: Result, seq: u32) { + match function { + Ok(MsgFunction::OsErrorLog) =3D> { + dev_err!(&self.dev, "GSP reported an OS error (seq {})\n",= seq); + } + Ok(MsgFunction::RcTriggered) =3D> { + dev_err!( + &self.dev, + "GSP triggered robust-channel recovery (seq {})\n", + seq + ); + } + // Nothing to do for the remaining known function codes. + Ok(_) =3D> {} + Err(raw) =3D> { + dev_warn!( + &self.dev, + "unknown GSP message function {:#x} (seq {})\n", + raw, + seq + ); + } + } + } } --=20 2.55.0 From nobody Fri Sep 25 13:19:17 2026 Received: from SN4PR2101CU001.outbound.protection.outlook.com (mail-southcentralusazon11012058.outbound.protection.outlook.com [40.93.195.58]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id D0085389452 for ; Sat, 12 Sep 2026 04:44:36 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=fail smtp.client-ip=40.93.195.58 ARC-Seal: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1789188278; cv=fail; b=PjFIroy4KFHZvwTxA9Zxh++f8/6N5LOs1TinsSneLAO4u8s+k6QUL6jxWddbsghjcmmk61IZjpTKf9L4mI/4IKH/J/x/drU7vcdTNe5Gli1phf31x1CRyXVWwBjZLVUbcT43OSZCmpvKWKh8e8GKVcA55Ta/sPz5TZfxfitUWVI= ARC-Message-Signature: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1789188278; c=relaxed/simple; bh=WW/Y3KA7WPwMtUKPxBo0pXLLlTnzqK7aBeuxJOwjfAM=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: Content-Type:MIME-Version; b=gww+UKj0t5obFHAKhnW7XcIJGe6BlL5cz26uCT3QiwMl8ahxlBZqgSW0LnZEemvFBLyF2I8veZsLOShCDH2LjeFlWG+HmCzMUp2lipXI+rgVzyta7pHO0uI7bC4M+wNQ/4RQN1z2NpdjfUogINUlOnRZsLzWsW95CGtG2k4Tv3M= ARC-Authentication-Results: i=2; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=nvidia.com; spf=fail smtp.mailfrom=nvidia.com; dkim=pass (2048-bit key) header.d=Nvidia.com header.i=@Nvidia.com header.b=RFcfSUTH; arc=fail smtp.client-ip=40.93.195.58 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=nvidia.com Authentication-Results: smtp.subspace.kernel.org; spf=fail smtp.mailfrom=nvidia.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=Nvidia.com header.i=@Nvidia.com header.b="RFcfSUTH" ARC-Seal: i=1; a=rsa-sha256; s=arcselector10001; d=microsoft.com; cv=none; b=uDFK0AyxaAYURA31QThqIsC8a6Y7zFnjzf3YjVxNJzYkC6VaU37pctk5vJ3bKxqe294cJr3NcmvIbwVxyCg8U4d6yicIC9L6DWOL8p1xffOBe3lc/lbM3kCAAg2nAFKfdLMQLU9sGXinvSgFsE82N09qR0I4UaimKNb02PmN0GpNAAz+fKK3A2bOUHx9Otnj+mA1A10/JuBnPuI1JuJViNoNHTxjBEnn44UBFGcVU+qnVtSiRXwB36Kdlegd4trF1nuVaeif1E5L/EYfCFzKUiK/j22P/9COh4T22PitkxJjwzCyP++8F1Z28I5H7NGX/1lRS6gQ8ud7Gjj4yl3/MQ== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=microsoft.com; s=arcselector10001; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-AntiSpam-MessageData-ChunkCount:X-MS-Exchange-AntiSpam-MessageData-0:X-MS-Exchange-AntiSpam-MessageData-1; bh=xn2ufhsvt20onXv5PQfiCwyQUfw4qw2c39BcxDi7LFs=; b=WeqErB5MzJAFhLaSLtih4z5C+0jnthHhPmi15Wmd3x7VpFF4cD0Y/kWrltNk+KAoZ2xy21f3aAzfo7tndEUY784g6IMr8j1bllf+vDinSRgoTz+BERl7zIwi0WFGvt878Rrsl//l5Kv2NP68vS6GCh1ca0MI9F/s36DaHsm9PxfsBUtykxAKKBqkU7WdE4xvoK7rOLY+vfnykMIRIYGnBxQFYGs+5hr5/ounvTXbvShmVfrCe1WtXI3hJ4+RKjIh/UuO9bmdfiCVd1YFed9LmcP4uTn9P/5zqlmZrm70dkKTk69M08/VO/9Uw/WhxmhRifmwjgyFpj/tZ4v7aXScaw== ARC-Authentication-Results: i=1; mx.microsoft.com 1; spf=pass smtp.mailfrom=nvidia.com; dmarc=pass action=none header.from=nvidia.com; dkim=pass header.d=nvidia.com; arc=none DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=Nvidia.com; s=selector2; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck; bh=xn2ufhsvt20onXv5PQfiCwyQUfw4qw2c39BcxDi7LFs=; b=RFcfSUTHiCrmzzdBCHdtPsZa9wmCTrJWIT7znsATLlyBc7+SbFb6danthQFd9hKAhjJfPR0Ry8WxiOL0qcwR9dekg2DKWWO+IShK6rInBSXARV0xjEP6+hXiXoEal6vQmscgNhrHXPWVBtm7E03BldPPw7Eia/iK+NoOyYzi2LHl19MsWQ6BucSCOxg+2PuXRozxRFpSaXw521gyKz/AM/GoNZGMwCv0icoRqsb3+9s0KlLdYeOqFibWC3yIGzMjfyQD7n2QBgcIuJyptKUc+PZEQXrLzqvjYu61OIkt9RUIBPPA2JQvsBugoEerlA8zfMa/LCX50NgZcHDGMyydpQ== Authentication-Results: dkim=none (message not signed) header.d=none;dmarc=none action=none header.from=nvidia.com; Received: from DM3PR12MB9416.namprd12.prod.outlook.com (2603:10b6:0:4b::8) by PH8PR12MB7229.namprd12.prod.outlook.com (2603:10b6:510:227::20) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.21.406.10; Sat, 12 Sep 2026 04:44:24 +0000 Received: from DM3PR12MB9416.namprd12.prod.outlook.com ([fe80::8cdd:504c:7d2a:59c8]) by DM3PR12MB9416.namprd12.prod.outlook.com ([fe80::8cdd:504c:7d2a:59c8%4]) with mapi id 15.21.0406.007; Sat, 12 Sep 2026 04:44:24 +0000 From: John Hubbard To: Danilo Krummrich , Alexandre Courbot Cc: Timur Tabi , Alistair Popple , Eliot Courtney , Zhi Wang , David Airlie , Simona Vetter , Bjorn Helgaas , Miguel Ojeda , Alex Gaynor , Boqun Feng , Gary Guo , =?UTF-8?q?Bj=C3=B6rn=20Roy=20Baron?= , Benno Lossin , Andreas Hindborg , Alice Ryhl , Trevor Gross , nova-gpu@lists.linux.dev, LKML , John Hubbard Subject: [PATCH v4 10/17] gpu: nova-core: stop re-parsing a bad GSP message Date: Fri, 11 Sep 2026 21:43:53 -0700 Message-ID: <20260912044400.677097-11-jhubbard@nvidia.com> X-Mailer: git-send-email 2.55.0 In-Reply-To: <20260912044400.677097-1-jhubbard@nvidia.com> References: <20260912044400.677097-1-jhubbard@nvidia.com> X-NVConfidentiality: public Content-Transfer-Encoding: quoted-printable X-ClientProxiedBy: BY5PR03CA0015.namprd03.prod.outlook.com (2603:10b6:a03:1e0::25) To DM3PR12MB9416.namprd12.prod.outlook.com (2603:10b6:0:4b::8) Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-MS-PublicTrafficType: Email X-MS-TrafficTypeDiagnostic: DM3PR12MB9416:EE_|PH8PR12MB7229:EE_ X-MS-Office365-Filtering-Correlation-Id: 32f85a85-480f-470b-2e14-08df1088850d X-MS-Exchange-SenderADCheck: 1 X-MS-Exchange-AntiSpam-Relay: 0 X-Microsoft-Antispam: BCL:0;ARA:13230040|1800799024|7416014|376014|23010399003|366016|10067099003|3023799007|18002099003|11063799006|56012099006|22082099003; X-Microsoft-Antispam-Message-Info: /v5JsaYrRl7DrTdSqAhoJ68T1RLcgfo0867h+mMwc5bZisbCpjMI0tl6pX5vKgmQsbHBsB24LcsBs0ox0LnwIyTU2ed2ws8WsdJy5zvN5Payyn87dksiJupIcoDdQF3UMTh8MZaGSnoht13IG+hgmUCCEE1mFn4l3QjVlGvwZkCnvrJ2gyaiNOWN+lSOyQGWsyDVaqUSY1pvWxUSnTg9hkh/XjDoVt2wyAwz4phxBiDfB/vBweStV9pe6mrYP/xAr9fnMrNxA3Nn9SRny5sNdrkt3L0zcvdjikox/N4OskrHK28vcGZCSBHlWzPg89h2P2jzQELobQOnpT39b8uPN0cwncwrQAZESEI0OrYEHJEOKMY1vuuHLZ+ynTOfaT73xFRfOWOLIFnxj4qHgemQ6K8PcaxJ9XyDcK+Utrb5CwPWjZyGWkzSp8aHFRFqgCJ8P9LL9tWYxUIKObLRoSYAtl0n1D/O2/3TLIoa98sai/HJ3bixPI0nE18ELsPMruHYXeK6CUF2CNY+OzKxxEOIL3Dv4OXp1KfIEITw1Z+lsRAvB8KT3ZAS+Jsy/ga7rBnErSQqlqtHHpD3mEwZQ15Ws71F4zzBWPcfLdNrD5JXyGI+CU12Z1OxuvoNZjsIQQ7QixF5+s4DBxYmw6z4JL+zDFqqsCt7OsL94RMTlXO/Cg4= X-Forefront-Antispam-Report: CIP:255.255.255.255;CTRY:;LANG:en;SCL:1;SRV:;IPV:NLI;SFV:NSPM;H:DM3PR12MB9416.namprd12.prod.outlook.com;PTR:;CAT:NONE;SFS:(13230040)(1800799024)(7416014)(376014)(23010399003)(366016)(10067099003)(3023799007)(18002099003)(11063799006)(56012099006)(22082099003);DIR:OUT;SFP:1101; X-MS-Exchange-AntiSpam-MessageData-ChunkCount: 1 X-MS-Exchange-AntiSpam-MessageData-0: =?us-ascii?Q?jPgP57zGoFcsfJUHKdCud5a/gBzDF+7SH1vc3IUTamvYqJ0nenqiHF5sBVbk?= =?us-ascii?Q?1WayrPBlhRi5zVtoK4x1ujmBWDUGvsGbzjgfzDG7DeR7e8dJSeVTMQXxo1fQ?= =?us-ascii?Q?8T0tD/zs4G6fnpP6CImOALfEL/+hTM5DkjSXLsD6vE5/l7aK7Q7kDaX1zLSz?= =?us-ascii?Q?s8mu4L/odsRJ7Nx/4kQRd+ZfPQB8CbrNlaYzA7HAeqdXPnbSlFafIuL/K8JB?= =?us-ascii?Q?BATumW3y2f3+xkRfALnImnThr29GFobGsbsfCkamuLVbL8+nK7rKmU+0EWv+?= =?us-ascii?Q?khhj8XXVuf6Eo0LOONJgRRpO6+61fRHub7eriqNiiw5iVfSm29u+9iW0S6gn?= =?us-ascii?Q?Grk6rOCH4Yik6oiwiQyUXIYnjDF40VieZl1xlk77p1HYJiUWdM7tsvHZd0Pm?= =?us-ascii?Q?EyuZ722nhTEcSP2OQJ1c8Y6W+wUMGwXCxE2NSYNqVxGV228TSnT5RW2trDcn?= =?us-ascii?Q?7mRWilvghy/nP8C3a6C8GYyN6kFx7BMOz12GCYt8WIOlxsGF7yyrk+8284nt?= =?us-ascii?Q?WFapijhSIOd4KupHUm73KXOC3nE+ufjQh6We+wewzytV+LLgCaA9vS5iauDQ?= =?us-ascii?Q?TBZs+HufChc6qjnPkncHoXPM/ZOsFT8v2YAb7dcqdvb02OG4r43bgys1IAsO?= =?us-ascii?Q?kUGa8iAlClZOLiWRUczbQEbUwcUmfSsmCJOg8XveXBlAuGmFcZsR28ZrOs5z?= =?us-ascii?Q?yfF2H/prBPkUQAPuJesYSXb9VRHc1tWSeIatpiMOS2gk9E7zf7masILz/FMb?= =?us-ascii?Q?0LYtfNAOKjz7tPaNA4FCecKKDPCSSQ53nGxiSTHP1ETGbGqCmGvjh97z+J/p?= =?us-ascii?Q?eX1IDrrR89KoEPXDT7CLDvGJBdAjGTpMHRnfWQHjKTqqAgYcquW0/4lRIzLH?= =?us-ascii?Q?xN9rHlirbRl6i5yUrokG7BNvjD3B7Rzqu00zQKGhPyFMURhnRylYmDMixz1G?= =?us-ascii?Q?zi3Sf9TYOVl7rNv6+mZsUjYan24pK90OYryjF/pWuGO8v7XnTgEkftmOXZWq?= =?us-ascii?Q?WFY7M0kD+kkgaXenGfaWLErkOFBEsht7TrG0GGrIpbX6S5vF8PbnOVnVsmu8?= =?us-ascii?Q?1g4ajGf7NQj7gQoFHswnmgLtKRRmlmDCX/6mXOQmtK7AoZ7xqlm89rkhYTdF?= =?us-ascii?Q?y8mT3ENovleEYCnDnOH1NPx679xOq5ECfaKIeVgi1slI6GQ1hDMZoVb7qPpv?= =?us-ascii?Q?OMyLi6//RlIEyvjHDm2gintWHApJ+2G7kgH12flPMssNlNDxbCj8E0xD6bFR?= =?us-ascii?Q?vQwo3lrjkv5nUxpXaveiAccjRYC7jo0wa5jjLX16mVtZM60WhDJEeXc6ph5X?= =?us-ascii?Q?JrhBPNO9LoGZ+gCGM/3mRkIoW0hTezjJoVPGazRlcp2pxOX7L4AKSrWKzr4y?= =?us-ascii?Q?58Yxp4FATSUkfl5e0Vr5S+9InARot5uoxadYwT6csm92a8cRdhkxRxKPB9kU?= =?us-ascii?Q?Mpht9T9Sv6M8MmAUPi95vYQqwdccFJANqsP7MowHeHw9tuwnB866fs2LmuDm?= =?us-ascii?Q?aoynY8GPzWDoYadtagoMFapoX/QRCOOEzc5EHADL07tf5+N9PDSCMvxw0jJs?= =?us-ascii?Q?GRANqmcHnf4FhBBNQXssSiYWE+tf8/2m7DiHkMII2te8bvms8VqmI19mW4MA?= =?us-ascii?Q?NM/XfCJNzagSHEltgccd9Hui0J54hH+82v96UcBGRs5gZbUAQT+CW9s6z+3u?= =?us-ascii?Q?A4jcnjUONe8a1nIytRai1bpEqr9UX6XzY1ireMC7BgVMGuM1wTOdUmSeWBBE?= =?us-ascii?Q?lZX4x0L+WA=3D=3D?= X-OriginatorOrg: Nvidia.com X-MS-Exchange-CrossTenant-Network-Message-Id: 32f85a85-480f-470b-2e14-08df1088850d X-MS-Exchange-CrossTenant-AuthSource: DM3PR12MB9416.namprd12.prod.outlook.com X-MS-Exchange-CrossTenant-AuthAs: Internal X-MS-Exchange-CrossTenant-OriginalArrivalTime: 12 Sep 2026 04:44:24.5103 (UTC) X-MS-Exchange-CrossTenant-FromEntityHeader: Hosted X-MS-Exchange-CrossTenant-Id: 43083d15-7273-40c1-b7db-39efd9ccc17a X-MS-Exchange-CrossTenant-MailboxType: HOSTED X-MS-Exchange-CrossTenant-UserPrincipalName: qJZCFweTxahwAgnFckE7yftUgw1g3sxOtR1q+D09Yg/ShxKWCKAZZ5726a1JFlI1UeezvYqRVf2jR0K6neyHuQ== X-MS-Exchange-Transport-CrossTenantHeadersStamped: PH8PR12MB7229 Content-Type: text/plain; charset="utf-8" A GSP message carries its length inside the checksummed region. Once the framing or the checksum fails, there is no trustworthy length with which to skip the message. Two failures left a bad message at the queue head. A framing or checksum failure returned without advancing the read pointer, so every later receive parsed the same message again. A validly framed message whose typed payload failed to decode returned early and did the same. Poison the queue on a framing or checksum failure: log what was inconsistent and fail every later receive, so the bad message is parsed once and recovery takes a device reset. Advance the read pointer past a validly framed message whether or not its payload decodes, and warn when the payload is shorter than the type it decodes into. Assisted-by: LLM Signed-off-by: John Hubbard --- drivers/gpu/nova-core/gsp/cmdq.rs | 93 +++++++++++++++++++++---------- 1 file changed, 64 insertions(+), 29 deletions(-) diff --git a/drivers/gpu/nova-core/gsp/cmdq.rs b/drivers/gpu/nova-core/gsp/= cmdq.rs index 340760e384d0..855c5a708525 100644 --- a/drivers/gpu/nova-core/gsp/cmdq.rs +++ b/drivers/gpu/nova-core/gsp/cmdq.rs @@ -2,7 +2,10 @@ =20 mod continuation; =20 -use core::mem; +use core::{ + cell::Cell, + mem, // +}; =20 use kernel::{ device, @@ -11,6 +14,7 @@ CoherentBox, DmaAddress, // }, + fmt, io::{ io_project, poll::read_poll_timeout, @@ -532,6 +536,7 @@ pub(crate) fn new( dev, gsp_mem, seq: 0, + poisoned: Cell::new(false), }), })) }) @@ -624,6 +629,12 @@ struct CmdqInner<'a> { dev: &'a device::Device, /// Current command sequence number. seq: u32, + /// Set once a message fails framing or checksum validation. Every lat= er receive fails, since + /// the bad message cannot be skipped. See "Draining the GSP-to-CPU qu= eue" in + /// `Documentation/gpu/nova/core/interrupts.rst`. + /// + /// A [`Cell`] because [`Self::wait_for_msg`] sets it through `&self`. + poisoned: Cell, /// Memory area shared with the GSP for communicating commands and mes= sages. gsp_mem: DmaGspMem<'a>, } @@ -732,6 +743,14 @@ fn send_command(&mut self, bar: Bar0<'_>, command: = M) -> Result } } =20 + /// Logs `reason`, poisons the queue, and returns `EIO` for the caller= to propagate. + fn poison(&self, reason: fmt::Arguments<'_>) -> Error { + dev_err!(&self.dev, "GSP RPC: receive: queue poisoned: {}\n", reas= on); + self.poisoned.set(true); + + EIO + } + /// Wait for a message to become available on the message queue. /// /// This works purely at the transport layer and does not interpret or= validate the message @@ -746,11 +765,13 @@ fn send_command(&mut self, bar: Bar0<'_>, command:= M) -> Result /// # Errors /// /// - `ETIMEDOUT` if `timeout` has elapsed before any message becomes = available. - /// - `EIO` if there was some inconsistency (e.g. message shorter than= advertised) on the - /// message queue. - /// - /// Error codes returned by the message constructor are propagated as-= is. + /// - `EIO` if the queue is already poisoned, or if the framing or the= checksum is invalid, + /// which poisons it (see [`Self::poisoned`]). fn wait_for_msg(&self, timeout: Delta) -> Result> { + if self.poisoned.get() { + return Err(EIO); + } + // Wait for a message to arrive from the GSP. let (slice_1, slice_2) =3D read_poll_timeout( || Ok(self.gsp_mem.driver_read_area()), @@ -761,7 +782,12 @@ fn wait_for_msg(&self, timeout: Delta) -> Result> { .map(|(slice_1, slice_2)| (slice_1.as_flattened(), slice_2.as_flat= tened()))?; =20 // Extract the `GspMsgElement`. - let (header, slice_1) =3D GspMsgElement::from_bytes_prefix(slice_1= ).ok_or(EIO)?; + let Some((header, slice_1)) =3D GspMsgElement::from_bytes_prefix(s= lice_1) else { + return Err(self.poison(fmt!( + "read area of {} bytes is shorter than a message header", + slice_1.len() + ))); + }; =20 dev_dbg!( &self.dev, @@ -775,7 +801,11 @@ fn wait_for_msg(&self, timeout: Delta) -> Result> { =20 // Check that the driver read area is large enough for the message. if slice_1.len() + slice_2.len() < payload_length { - return Err(EIO); + return Err(self.poison(fmt!( + "message advertises {} payload bytes but only {} are reada= ble", + payload_length, + slice_1.len() + slice_2.len() + ))); } =20 // Cut the message slices down to the actual length of the message. @@ -798,12 +828,10 @@ fn wait_for_msg(&self, timeout: Delta) -> Result> { slice_2, ])) !=3D 0 { - dev_err!( - &self.dev, - "GSP RPC: receive: Call {} - bad checksum\n", + return Err(self.poison(fmt!( + "message with sequence {} has a bad checksum", header.sequence() - ); - return Err(EIO); + ))); } =20 Ok(GspMessage { @@ -817,13 +845,13 @@ fn wait_for_msg(&self, timeout: Delta) -> Result> { /// A message whose function code is `M::FUNCTION` is decoded and retu= rned. Any other message /// is logged as an event. /// - /// The read pointer is always advanced past the message, regardless o= f whether it matched. + /// The read pointer advances past the message in every case, includin= g a decode failure. /// /// # Errors /// /// - `ETIMEDOUT` if `timeout` has elapsed before any message becomes = available. - /// - `EIO` if there was some inconsistency (e.g. message shorter than= advertised) on the - /// message queue. + /// - `EIO` if the queue is poisoned or the message fails framing or c= hecksum validation (see + /// [`Self::wait_for_msg`]), or if the matched message is too short = for `M::Message`. /// - `ERANGE` if the message was not the awaited reply. /// /// Error codes returned by [`MessageFromGsp::read`] are propagated as= -is. @@ -838,20 +866,27 @@ fn receive_msg(&mut self, timeout:= Delta) -> Result =20 // An early return here would leave the read pointer on this messa= ge. let result =3D if matches!(function, Ok(f) if f =3D=3D M::FUNCTION= ) { - let (cmd, contents_1) =3D M::Message::from_bytes_prefix(messag= e.contents.0).ok_or(EIO)?; - let mut sbuffer =3D SBufferIter::new_reader([contents_1, messa= ge.contents.1]); - - M::read(cmd, &mut sbuffer) - .map_err(|e| e.into()) - .inspect(|_| { - if !sbuffer.is_empty() { - dev_warn!( - &self.dev, - "GSP message {:?} has unprocessed data\n", - M::FUNCTION - ); - } - }) + match M::Message::from_bytes_prefix(message.contents.0) { + Some((cmd, contents_1)) =3D> { + let mut sbuffer =3D SBufferIter::new_reader([contents_= 1, message.contents.1]); + + M::read(cmd, &mut sbuffer) + .map_err(|e| e.into()) + .inspect(|_| { + if !sbuffer.is_empty() { + dev_warn!( + &self.dev, + "GSP message {:?} has unprocessed data= \n", + M::FUNCTION + ); + } + }) + } + None =3D> { + dev_warn!(&self.dev, "GSP message {:?} too short\n", M= ::FUNCTION); + Err(EIO) + } + } } else { self.log_event(function, seq); =20 --=20 2.55.0 From nobody Fri Sep 25 13:19:17 2026 Received: from SN4PR2101CU001.outbound.protection.outlook.com (mail-southcentralusazon11012058.outbound.protection.outlook.com [40.93.195.58]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id B2755386C18 for ; Sat, 12 Sep 2026 04:44:34 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=fail smtp.client-ip=40.93.195.58 ARC-Seal: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1789188276; cv=fail; b=sS9oJ3YX/ns/RJrRceBuO2OSI3XocMmKGdOu7oUVb8xlgDF9vHZY562cvVSKgy5DrQi5gNIUJ7E/ed8C3E+f2/0Fcwyu8EQzVBCL97VzYeqnM6iWqq+IqFnfVLRAqyRu4cj5swfBQuGU78uvJrn2OuOJ2v5/4sGMcmdKz/syQA0= ARC-Message-Signature: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1789188276; c=relaxed/simple; bh=PNjtLV5cPLI3FYnokO/JndTY9/4noVNcjsVrqqYlVKU=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: Content-Type:MIME-Version; b=hDtFdgTuFM6SS6OGuCpT7cCQGn3EBMZFT41HFmlYbbeviNgXXbRWK1pOa3gW1RbUfOBwqBi6pk1fKvd8KS2rFThgwxWpSmm1oA60ouBKgx1xk7MminQn1STrNZ8/Smpf3L+pLpmkxPe9Rs6xFiV60ZRoxYy0Gh/5woZ8ReWS+Rc= ARC-Authentication-Results: i=2; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=nvidia.com; spf=fail smtp.mailfrom=nvidia.com; dkim=pass (2048-bit key) header.d=Nvidia.com header.i=@Nvidia.com header.b=f97/RJUH; arc=fail smtp.client-ip=40.93.195.58 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=nvidia.com Authentication-Results: smtp.subspace.kernel.org; spf=fail smtp.mailfrom=nvidia.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=Nvidia.com header.i=@Nvidia.com header.b="f97/RJUH" ARC-Seal: i=1; a=rsa-sha256; s=arcselector10001; d=microsoft.com; cv=none; b=wBGDxftSqZ4pPaGdZtDxXuzeG0I/bk7CuWLsc1PlSN68ZlPK5+bBnyiYktkzhLGzppUkmNiZAWTj2L6xaU/QpwIFwgIS1LFu/onQpaCCN2+WrZpNWXNWplYguO5uDO0ZcKbyq37TMr5INicmx1Kl/imLpUH3Dcf9M+U5av5UdLcNNx12YqlKHIQ6jZCezb+WMJQyYMOXQ7yZMrG8veYD+anh5tkMaZC+wEMih5Q3DGyThARUrGcfnKoL8lSFnj91/XqHgAJCdMhcNpxVm0cxBsnf5gzmZ4EKAo33wA4VcfXv5wgKEz7ebzAqVwflL/C4OncQHVU8PohVtkiojgnRhQ== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=microsoft.com; s=arcselector10001; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-AntiSpam-MessageData-ChunkCount:X-MS-Exchange-AntiSpam-MessageData-0:X-MS-Exchange-AntiSpam-MessageData-1; bh=QLGGnm5er6ZVOnOlxYg9GztoA97c9MGWeY3sRGaPkIE=; b=ebyni0t8ezI/4E0mGCupXRfV2gPD9ojXjvpF/KclRSqNmV4aKoQLzkYt9EXZp+YQQkyVELRhL7KYTt44PguWZAQeQHUoxPjiKb61J32R4CMsxjeJj6jaaaEW6+AdPpStYz5nkFNSM+ZDFHT6+J62h5ObzT2H8zGmBncxQR2KztH0TRAzxNpgvOUF8rBSqaJ7nT1nVs4mve7rYV0nn+hP44FWbSZg8RGowTcdTa3z1WDiea60+1jMflC8T5HonYVZPKUk7fPIe1nV8s/LZkHXMiV5UFyyWjBkqAzv/8RWfLV7DZ6QqoUKI52KxKmqSrHSyl/mhS8d0dq6+sOss04ZxQ== ARC-Authentication-Results: i=1; mx.microsoft.com 1; spf=pass smtp.mailfrom=nvidia.com; dmarc=pass action=none header.from=nvidia.com; dkim=pass header.d=nvidia.com; arc=none DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=Nvidia.com; s=selector2; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck; bh=QLGGnm5er6ZVOnOlxYg9GztoA97c9MGWeY3sRGaPkIE=; b=f97/RJUHgWXwkVoW/E3twaXv0NsurC8IpVS+G69OektlJ4WxafgeS9+jVRnsJOQkBsygawWQPf7R5JOJt4oMCOxES+hn/MHAWtFm9egV0p1BlCmGAt1TiNtZCRhDrpG/6SDFhEnKu+Jhn023+Y0l3rqs2cwS+b76FNPFjaNrCmwUOkw5OIyTL55u+GaYlrcZGyd2MAh6bq1JUX7yD+BuybKQtn60Sk6tr8vBk7RaT1/gJpfx93/BhCjQotF5CppsJ3qwvvDPSZ9Al5H2q3nUZ28ifNyngInFtvijoVuPISyDdFVUFHcwQY55BpjN948xnnjybMR2rv51oxalgAGNHw== Authentication-Results: dkim=none (message not signed) header.d=none;dmarc=none action=none header.from=nvidia.com; Received: from DM3PR12MB9416.namprd12.prod.outlook.com (2603:10b6:0:4b::8) by PH8PR12MB7229.namprd12.prod.outlook.com (2603:10b6:510:227::20) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.21.406.10; Sat, 12 Sep 2026 04:44:25 +0000 Received: from DM3PR12MB9416.namprd12.prod.outlook.com ([fe80::8cdd:504c:7d2a:59c8]) by DM3PR12MB9416.namprd12.prod.outlook.com ([fe80::8cdd:504c:7d2a:59c8%4]) with mapi id 15.21.0406.007; Sat, 12 Sep 2026 04:44:25 +0000 From: John Hubbard To: Danilo Krummrich , Alexandre Courbot Cc: Timur Tabi , Alistair Popple , Eliot Courtney , Zhi Wang , David Airlie , Simona Vetter , Bjorn Helgaas , Miguel Ojeda , Alex Gaynor , Boqun Feng , Gary Guo , =?UTF-8?q?Bj=C3=B6rn=20Roy=20Baron?= , Benno Lossin , Andreas Hindborg , Alice Ryhl , Trevor Gross , nova-gpu@lists.linux.dev, LKML , John Hubbard Subject: [PATCH v4 11/17] gpu: nova-core: return ENOMSG for an unmatched GSP message Date: Fri, 11 Sep 2026 21:43:54 -0700 Message-ID: <20260912044400.677097-12-jhubbard@nvidia.com> X-Mailer: git-send-email 2.55.0 In-Reply-To: <20260912044400.677097-1-jhubbard@nvidia.com> References: <20260912044400.677097-1-jhubbard@nvidia.com> X-NVConfidentiality: public Content-Transfer-Encoding: quoted-printable X-ClientProxiedBy: SJ0PR05CA0029.namprd05.prod.outlook.com (2603:10b6:a03:33b::34) To DM3PR12MB9416.namprd12.prod.outlook.com (2603:10b6:0:4b::8) Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-MS-PublicTrafficType: Email X-MS-TrafficTypeDiagnostic: DM3PR12MB9416:EE_|PH8PR12MB7229:EE_ X-MS-Office365-Filtering-Correlation-Id: 72e94632-2ef6-47d1-8f72-08df108885ca X-MS-Exchange-SenderADCheck: 1 X-MS-Exchange-AntiSpam-Relay: 0 X-Microsoft-Antispam: BCL:0;ARA:13230040|1800799024|7416014|376014|23010399003|366016|10067099003|3023799007|18002099003|5023799004|11063799006|56012099006|22082099003; X-Microsoft-Antispam-Message-Info: hUc6N0wQoJry50gbPqqCgIR0EGnrTB2rgyHQGSIibJAq87r/IyTSWoFYk2VJcodpqga4imhLjEfz19f/i6cpFitsaAjdV+NZLWHaIDtI2wOqSGzrlriDO6xX1gwmi1+O9j/+UVNA6eQJfWNttKcWwTMAH2t2pSmpNQDVk94xXgxlxU9UQY8CwuDGlq13rroqHQq5T2yx+Fgjlca0BkCUkoyjHZJfpRtjutuQX2+wNkQWJtqvmfyHI2V6oSoxAWFI0rnwQJaV3HnVvlr9hSSut56G1OC35iRVd/WUitw8MXkp4hN4qSwAo2H5X90GtPIDAzdidfDy+Yjzg+AjroODc4+0Od3XVV2VraBRuoHczSdTZ/V+vWgIVuz8QF9KvU+jXHoQoLBlgxnojsKApf3QObBIJJUejhS7BgiplRlhu9ZZTVVhbBU9c78AXpRleii28hrOOSHvRXA7FAMHll3SuF9hrASgecTTX8DuXPSCq9sGeOf7X9mOpyZ6SbAZPR96VfJzMYy3AeEAwpzRzqWjDzE+vYnO2WJH0sMW2DWbh1rQuiOUoVR38jwajsbrpZw+csbl56rpofEMUZUpELxRs/8zcg9+nY9SqAYDjZA2kfACoHRyorjBEwJJjeLt2uhHNnjX/x4nhmr/opsZMM4CqInGwnu5ifMTPqxEmJp0qpM= X-Forefront-Antispam-Report: CIP:255.255.255.255;CTRY:;LANG:en;SCL:1;SRV:;IPV:NLI;SFV:NSPM;H:DM3PR12MB9416.namprd12.prod.outlook.com;PTR:;CAT:NONE;SFS:(13230040)(1800799024)(7416014)(376014)(23010399003)(366016)(10067099003)(3023799007)(18002099003)(5023799004)(11063799006)(56012099006)(22082099003);DIR:OUT;SFP:1101; X-MS-Exchange-AntiSpam-MessageData-ChunkCount: 1 X-MS-Exchange-AntiSpam-MessageData-0: =?us-ascii?Q?uaqZBITFpchc5k7eNizhM/4hTphXNFuYcNbH8rvPyWAOM7FQTwhIIjdNO3Ij?= =?us-ascii?Q?BZWy+yjL76r9fHogUS9cG+I2B4Nzy3q8BffJZ01bV3VSyInHnEyAqfx6kfet?= =?us-ascii?Q?90337k9cEeFT0p7UvU+ij2U+QlKK7BLULBlCa1G+OXU1EeGEUgKuQCy9d2ye?= =?us-ascii?Q?EmqmJvwL+kFoT+WuSBns7EMpyjdcalsTFlUj65J3O/WaNrmUh++hR+F1JN6A?= =?us-ascii?Q?Z21MoWFIZywMMlT3q4kKTFPD6auWAR6IJWGH19AXnsgpDWcLaG2W3P1kkKX9?= =?us-ascii?Q?eBvzgibWlEjEVHnY7y6Gb75arLRJYFNli2k0kOwQSwj4NAfrxlW0T09/Q46C?= =?us-ascii?Q?N97U8fnT/zUUoQsqn5qc2GZ+V8xFtxgZJz1tpHUR72xV4tU/7B2PSbgiz2uL?= =?us-ascii?Q?cUDVSWIqW0aOvhy4TFMhFtLBQMyWg6XOk8QTkhNC04XY4TSLGk2lsRuTyzKR?= =?us-ascii?Q?VyCK+wvNSfvw3NQIuANUl9eUDmukuQeXhY/o9epOTq1rpP187d1v/kX3P//M?= =?us-ascii?Q?pP1wgTq5IR/ZxGJZd1Vl7KRPjzfL2+2vISSqCGGsUR2uD+5hxGpzO4xsw3Wj?= =?us-ascii?Q?gX/DkcAcPKhyOlbdOL5HallOW2isdUws4xelW9i52RLVms/zw/JjSO/XS2Kj?= =?us-ascii?Q?ti3345VA6dtM5CAqDQZZJW7PA29AD+zD/WZMmfaIJ3i0dqrQCtFDHKVG3ntI?= =?us-ascii?Q?XYOkcBfASdiTYswMgia6RZsihYsEREIrH/LUd/JtQ08iCa+QU8ch4J3GELg5?= =?us-ascii?Q?iSJ3nh2WdBbjd50bJLwonAbXW08yILocfuTv/CsIaAtZo6dIb6MXjSu/hHft?= =?us-ascii?Q?nTaze8GFjBZjMQnwIRqRcAn9w8eXBLb1/Qdd4U+HsM4nji8OxlqpnQ3KE6ei?= =?us-ascii?Q?gFU1SaHuC7M38Jc+ggAp41DoturqTHhchajQbAZ+/1VUzb6QrciJjb8BnvKu?= =?us-ascii?Q?NLsjrp2DSIYHv7zu0pdaxKoZQKn8jtOx+V5PbdONwgNjmE7JNRVe+BoArn0G?= =?us-ascii?Q?QiDpL06QUaTTjHdkU/Cwm43EUt2bruEjj2SWED/JgUI2cv0kAKYvoWfBM5q2?= =?us-ascii?Q?2ogOvluW/d7CUqgGUNS8YZChIT1uKuR7XrmXkJHSSlqETgRqc3MYXuofym63?= =?us-ascii?Q?w3b09f0m1FARwP4mvm6czHiKMMftMO6b11fyrLLAk+jp1sRh9U36Hl98OBMp?= =?us-ascii?Q?jKCXCcRjKbgA/03A6cpOPtn+EX7xgfE0t3iA2mgEdqUx0YNHrx7A1HvOozGV?= =?us-ascii?Q?R0QurPAFE3TpO395dtSR6dhRLJFOf1oMEMqpGMIxzqJRnyZhGEudmubq+nt7?= =?us-ascii?Q?bGWvR9uUI4BgdGmju46aL0tDeFU5XS9VDXN974qoq4QYkWqyzbaoN3kNRXYX?= =?us-ascii?Q?Gq/LJVM0cKy8U1ti7yTvCQDexeamYPZUHrRUyl9KaipYtZAnGpVTGIKTMG/e?= =?us-ascii?Q?190y2/su/wr7cTQgaac3e+cqU9kUNTdQWqSJyPUZoFLz40IE0Yv95UONYICE?= =?us-ascii?Q?mRxk+tzK7TM7OHxDYap4YEh7CsN+ky1U6+FJgC07CR01UQwgD3NOPVYxLT5r?= =?us-ascii?Q?4RQZSb+s6IPxw/jk57DDCFLXFofLdoUbfkcbvAvSuTQRHFr9w8LvTw/SIbTU?= =?us-ascii?Q?3fKZ+xdkblz1HnLx8NK4g0z9IokUkqHzYg7CNATP2ngQ9aM1qHqfULvZQtRI?= =?us-ascii?Q?9qNcfxaJjWHpht+vVhjI3PYzeFOPUZZ5iRR9ELiFKY2O8xXIvDbh4c36+i17?= =?us-ascii?Q?T4T/7vRZXA=3D=3D?= X-OriginatorOrg: Nvidia.com X-MS-Exchange-CrossTenant-Network-Message-Id: 72e94632-2ef6-47d1-8f72-08df108885ca X-MS-Exchange-CrossTenant-AuthSource: DM3PR12MB9416.namprd12.prod.outlook.com X-MS-Exchange-CrossTenant-AuthAs: Internal X-MS-Exchange-CrossTenant-OriginalArrivalTime: 12 Sep 2026 04:44:25.7899 (UTC) X-MS-Exchange-CrossTenant-FromEntityHeader: Hosted X-MS-Exchange-CrossTenant-Id: 43083d15-7273-40c1-b7db-39efd9ccc17a X-MS-Exchange-CrossTenant-MailboxType: HOSTED X-MS-Exchange-CrossTenant-UserPrincipalName: p81jcNXZrjKNPSojO+LnYDgIw1WJMZKgMWQUdV8c/vMTbkzmp0mSY3M7zeIBZ/DGETjg/rLlV5Ef29MK0DdhUQ== X-MS-Exchange-Transport-CrossTenantHeadersStamped: PH8PR12MB7229 Content-Type: text/plain; charset="utf-8" The GSP posts unsolicited events on the same queue as command replies, so a receive that asks for one message type has to report that the message at the queue head was a different one. That case returned ERANGE, which means a value outside a valid range and says nothing about a message. Return ENOMSG, no message of the desired type, instead. Suggested-by: Gary Guo Suggested-by: Alexandre Courbot Assisted-by: LLM Signed-off-by: John Hubbard --- drivers/gpu/nova-core/gsp/cmdq.rs | 6 +++--- drivers/gpu/nova-core/gsp/commands.rs | 2 +- drivers/gpu/nova-core/gsp/sequencer.rs | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/nova-core/gsp/cmdq.rs b/drivers/gpu/nova-core/gsp/= cmdq.rs index 855c5a708525..45c3c3aea8f9 100644 --- a/drivers/gpu/nova-core/gsp/cmdq.rs +++ b/drivers/gpu/nova-core/gsp/cmdq.rs @@ -588,7 +588,7 @@ pub(crate) fn send_command(&self, bar: Bar0<'_>, com= mand: M) -> Result(Self::RECEIVE_TIMEOUT) { Ok(reply) =3D> break Ok(reply), - Err(ERANGE) =3D> continue, + Err(ENOMSG) =3D> continue, Err(e) =3D> break Err(e), } } @@ -852,7 +852,7 @@ fn wait_for_msg(&self, timeout: Delta) -> Result> { /// - `ETIMEDOUT` if `timeout` has elapsed before any message becomes = available. /// - `EIO` if the queue is poisoned or the message fails framing or c= hecksum validation (see /// [`Self::wait_for_msg`]), or if the matched message is too short = for `M::Message`. - /// - `ERANGE` if the message was not the awaited reply. + /// - `ENOMSG` if the message was not the awaited reply. /// /// Error codes returned by [`MessageFromGsp::read`] are propagated as= -is. fn receive_msg(&mut self, timeout: Delta) -> Result= @@ -890,7 +890,7 @@ fn receive_msg(&mut self, timeout: D= elta) -> Result } else { self.log_event(function, seq); =20 - Err(ERANGE) + Err(ENOMSG) }; =20 // Advance the read pointer past this message. diff --git a/drivers/gpu/nova-core/gsp/commands.rs b/drivers/gpu/nova-core/= gsp/commands.rs index e087c9e8c35c..d1c80cf3c452 100644 --- a/drivers/gpu/nova-core/gsp/commands.rs +++ b/drivers/gpu/nova-core/gsp/commands.rs @@ -191,7 +191,7 @@ pub(crate) fn wait_gsp_init_done(cmdq: &Cmdq<'_>) -> Re= sult { loop { match cmdq.receive_msg::(Cmdq::RECEIVE_TIMEOUT) { Ok(_) =3D> break Ok(()), - Err(ERANGE) =3D> continue, + Err(ENOMSG) =3D> continue, Err(e) =3D> break Err(e), } } diff --git a/drivers/gpu/nova-core/gsp/sequencer.rs b/drivers/gpu/nova-core= /gsp/sequencer.rs index dae34c11eb05..1782ed7d7ca6 100644 --- a/drivers/gpu/nova-core/gsp/sequencer.rs +++ b/drivers/gpu/nova-core/gsp/sequencer.rs @@ -346,7 +346,7 @@ pub(crate) fn run( let seq_info =3D loop { match cmdq.receive_msg::(Cmdq::RECEIVE_TIMEOUT) { Ok(seq_info) =3D> break seq_info, - Err(ERANGE) =3D> continue, + Err(ENOMSG) =3D> continue, Err(e) =3D> return Err(e), } }; --=20 2.55.0 From nobody Fri Sep 25 13:19:17 2026 Received: from BYAPR05CU005.outbound.protection.outlook.com (mail-westusazon11010052.outbound.protection.outlook.com [52.101.85.52]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id C3E88386C2A for ; Sat, 12 Sep 2026 04:44:34 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=fail smtp.client-ip=52.101.85.52 ARC-Seal: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1789188277; cv=fail; b=ftJ+CAcX5b9a7QkY+yYDHdgusIOgYh57EPFbBekkKiNMAXYMOGGwYHWku++Gz56nsT67vtm5Qo5qd5iOUDl969aQyQxZ/yz4geWJDZ0BdXmaNKid/9SH4O41FK8rMQdFyOPiPd/JmHmUIUT9X1JsCTZK9iCHZpiVwYmZRrPn0Sc= ARC-Message-Signature: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1789188277; c=relaxed/simple; bh=TY/Ul6SCR/VeNHfRTc4jRHN3qA+Ku8l2Wn/XRKNJpIg=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: Content-Type:MIME-Version; b=Od/H+nynlLM8z50K8YTCrA/KbOUldm0MfRKMIF2A6BqqbuB7Dy34drd/OI6KEYpgSzSFBWhTwU7FpZdbNj30FJX00Sqgvxel9zD/+hWj31LLlYEKNixu7bZEOkcfJPPPRMXqbYn79Xe2DV7bn3VpEP9P/HH0mCTwTbEjBOOrrvg= ARC-Authentication-Results: i=2; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=nvidia.com; spf=fail smtp.mailfrom=nvidia.com; dkim=pass (2048-bit key) header.d=Nvidia.com header.i=@Nvidia.com header.b=du3MA6yS; arc=fail smtp.client-ip=52.101.85.52 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=nvidia.com Authentication-Results: smtp.subspace.kernel.org; spf=fail smtp.mailfrom=nvidia.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=Nvidia.com header.i=@Nvidia.com header.b="du3MA6yS" ARC-Seal: i=1; a=rsa-sha256; s=arcselector10001; d=microsoft.com; cv=none; b=P5pFf3yn0tvR5E5S3ROOTpH6kX+uv6/hrFPXxiDxjIq53UTj+Wu3PyOsaNbJP0zlX+R5iy9NNBGCuJiUoFFkzS8nxPfHNY7dyp0A6IUoqM3tFnW3RYmWiXmaz8DFsuLzcMBP+EtrmmGlX3e2rOobcLBtBALwo8D1Cm3h6g9e69UnMKtt+uXdazIxEVlWEGGwC+zMbZVwxoTkDHXN97EGIzquegiWVk2O+Qj7rkJmlEQEu4Bavbxxp7/PYTBN1flIBy3zzRB5jPlAQjGf5iwtvc+YELhDjUphn4rD7ul2WTNUfdPQiD8qcfQ7R61hygtRv1tLntHEkNGCCDrHc0WpuQ== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=microsoft.com; s=arcselector10001; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-AntiSpam-MessageData-ChunkCount:X-MS-Exchange-AntiSpam-MessageData-0:X-MS-Exchange-AntiSpam-MessageData-1; bh=6zZRYnMqUlO41XvVDuDcMK0R8bJogtrwni3GLpGEhXA=; b=MEgOSxrp+8NNxvf7RckQojLh2kJsSwRE4Wq3/qZC87n8pbWNxPZ1Ks3N0n8spHKO6ie0NXPXRySsAyZiGnZUWgj/26O9SguCnYuFsjwusL6u6tfeEorUYR7ojQPo77HVu8Dy2dT3izqVwjUZu90MbH6MEGA9RPTltuMw5ABYfmVN25vrBMVVM0cCg0DDYDpoyvIjicdlph1oj1Zcg8AhhHbkRqYQeTBrOI9t9/KemFmlZuX6rYfQZb9W+RavUj+bOAADMptH41ndsv8TMuCbqMb9HYZ1m5b7y6/UwoRqPJytt1cmD+aVzTGI+BSfjlEjS3nP/smI0HzwtpKxdQeTXA== ARC-Authentication-Results: i=1; mx.microsoft.com 1; spf=pass smtp.mailfrom=nvidia.com; dmarc=pass action=none header.from=nvidia.com; dkim=pass header.d=nvidia.com; arc=none DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=Nvidia.com; s=selector2; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck; bh=6zZRYnMqUlO41XvVDuDcMK0R8bJogtrwni3GLpGEhXA=; b=du3MA6yS6JUQsPz1fTysCWQuKqwFFAfuWf2GqXtxfzZ/iqaPYZycqDuGcu62yXCzsFumUKiTEhPoThjGwwjqasCLOjj43ExRyvHrnwRNvc4fRlbNOICogl7nIZfrS06t3/JJg6znFultqyg89v+Gw7UFqx9M+h+RgjPB7aNnOw9uKPthc8FtYiQ8touMtr7KFJ7MWRQjKCeTBUJ2rNPOboNHBd3ikNdCDdGcGD8zrQIm4sauBcrt1FSLQL3dXbVTDaBnfJwBE9C69J8+XBsoj+5warzE7XSkj/PypJjxzuTl8BgH3P5Kif4kDCAAMh539h1iHRNaot0b29AR2iUYBQ== Authentication-Results: dkim=none (message not signed) header.d=none;dmarc=none action=none header.from=nvidia.com; Received: from DM3PR12MB9416.namprd12.prod.outlook.com (2603:10b6:0:4b::8) by PH8PR12MB7229.namprd12.prod.outlook.com (2603:10b6:510:227::20) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.21.406.10; Sat, 12 Sep 2026 04:44:27 +0000 Received: from DM3PR12MB9416.namprd12.prod.outlook.com ([fe80::8cdd:504c:7d2a:59c8]) by DM3PR12MB9416.namprd12.prod.outlook.com ([fe80::8cdd:504c:7d2a:59c8%4]) with mapi id 15.21.0406.007; Sat, 12 Sep 2026 04:44:27 +0000 From: John Hubbard To: Danilo Krummrich , Alexandre Courbot Cc: Timur Tabi , Alistair Popple , Eliot Courtney , Zhi Wang , David Airlie , Simona Vetter , Bjorn Helgaas , Miguel Ojeda , Alex Gaynor , Boqun Feng , Gary Guo , =?UTF-8?q?Bj=C3=B6rn=20Roy=20Baron?= , Benno Lossin , Andreas Hindborg , Alice Ryhl , Trevor Gross , nova-gpu@lists.linux.dev, LKML , John Hubbard Subject: [PATCH v4 12/17] gpu: nova-core: bound a GSP wait by a single deadline Date: Fri, 11 Sep 2026 21:43:55 -0700 Message-ID: <20260912044400.677097-13-jhubbard@nvidia.com> X-Mailer: git-send-email 2.55.0 In-Reply-To: <20260912044400.677097-1-jhubbard@nvidia.com> References: <20260912044400.677097-1-jhubbard@nvidia.com> X-NVConfidentiality: public Content-Transfer-Encoding: quoted-printable X-ClientProxiedBy: SJ0PR03CA0035.namprd03.prod.outlook.com (2603:10b6:a03:33e::10) To DM3PR12MB9416.namprd12.prod.outlook.com (2603:10b6:0:4b::8) Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-MS-PublicTrafficType: Email X-MS-TrafficTypeDiagnostic: DM3PR12MB9416:EE_|PH8PR12MB7229:EE_ X-MS-Office365-Filtering-Correlation-Id: 2eb8433f-75cb-46ce-4812-08df1088868f X-MS-Exchange-SenderADCheck: 1 X-MS-Exchange-AntiSpam-Relay: 0 X-Microsoft-Antispam: BCL:0;ARA:13230040|1800799024|7416014|376014|23010399003|366016|10067099003|6133799003|3023799007|18002099003|11063799006|56012099006|22082099003; X-Microsoft-Antispam-Message-Info: uQspEa8ps8TmtgL/J2vNyUUDKDFNNfMeazetfeBBwTn5ADEMIwkXJXgaHGlCDhNAvfYMIzz6CM+cTHig7pBFmoNNdS5B7uZIxHJY5hM+yuVbD4HVc/Cz9I5aFrOOpfVyXwfJQ3VfShfd1VBjnnO2FGhEJ1zJZcys5uMlEqyULmtI7unQdQ6O4a6GQGsOaVUmiEyP3dc7ktX93yoA4s/7zAau1wl5SNKiCijKj9Bpf4uu50a2kjcq+0STDO11PVBoL3gsQqXthUeUkoy413lrmcwDc1Nb++N4AIeuuWsjLDmzqX3px657rjZ6upXXP2Sp4TLKc/cyh3LrGAgG8gPZ1xRAsvKd7/ar1ogcYc+bJHH7PamePObWPq3BMi37fa/nygeYMlXCcPPKcX0jD69z8MTB39zMi/ZsET4j9HQZONWULz9xCrz2U7LXSiL4EWIoAyLaVTzXFFqlNu+43gqhD2U+r2TS689kl6rIKAj0Ws0+eU2rFcyK736IhHu+UWQVXPSRDdJgdIJ6yrw8sygZOeV5uaaSwP9hwNHIc5g9TDcNaOanvyJgsEDbfmroQEwNBGEM1QbLiH/PBwkCrJw2dgr75jtsA41MbI/QUKO7OAXtIxPO/axjnZpJA6/nkYmuBqIpoE3HjS4yq3mMcafc3mrP74ascx3EuIfO4HePwA4= X-Forefront-Antispam-Report: CIP:255.255.255.255;CTRY:;LANG:en;SCL:1;SRV:;IPV:NLI;SFV:NSPM;H:DM3PR12MB9416.namprd12.prod.outlook.com;PTR:;CAT:NONE;SFS:(13230040)(1800799024)(7416014)(376014)(23010399003)(366016)(10067099003)(6133799003)(3023799007)(18002099003)(11063799006)(56012099006)(22082099003);DIR:OUT;SFP:1101; X-MS-Exchange-AntiSpam-MessageData-ChunkCount: 1 X-MS-Exchange-AntiSpam-MessageData-0: =?us-ascii?Q?f7rqMV2J/uBsD1rZ4eEePSZpnX//0QiEbmBC1igaT0zXfIJVyshZ/r/j+9uR?= =?us-ascii?Q?XOID9s4ZyF/HUfYrYozjsPNFuz19fD0b7eWHrEb5fRWP7WF2aoVbalYSvu8M?= =?us-ascii?Q?Cpc/iiZQQ4tC9EybPDm0n0UA2TDDRlxJ6TzPQRSDfqEiGG7L0h4aLX71Ir9v?= =?us-ascii?Q?e7Ku3cGJEd+tafb4HhKrIGpLhtTWLMY3wEk11wECr5PX2Wjvf7Zropiq2pyA?= =?us-ascii?Q?OdwvLnyOKkLgYDaytZJ0OFKW70TRv1UrJg7W0iXog1c6X9PC5u89EFpxhr0G?= =?us-ascii?Q?FRGTUD4cl0WhOvl6qx80WqPEr+ceUHzGsX/GnrFSUcNjD7xBzdm/IH/hKZ7d?= =?us-ascii?Q?rBBbYoZYzoDiPkNdxGp1K12rUtTksyjh0Asqif8Sk0vpRg+R1onxnxCAudQY?= =?us-ascii?Q?Qjbycsb1BI9JTrH2jQ00K82sCJdRhbzLgZMrYahsBb7872kjTaFeb/SWAvql?= =?us-ascii?Q?Je3Z0Kc9mpCje+4wyPjgyHGwJBob6yOKq3ywULorzbIDtcgoxxjs+iE6FxRj?= =?us-ascii?Q?5HerCVT/qX1Lt3YwgxHDF6XS18pTktCDpF0xy8zEqWcfkJ5UgjOXJZKaVL1I?= =?us-ascii?Q?Am7BAMtvc3iK4829Pj4AIaIBFjDrmKopudeAPptngQ5vNEGKhPc+NzAxnYeS?= =?us-ascii?Q?FoPXCvU6VMT5v2at7yFbm9YqzNGaPw95j7r0/QzFYOBUd4NAQqJNDPFg9142?= =?us-ascii?Q?3UmbcWNFn1vS/s6oaAwcG4gIOu+tfgENaNud+sOtxqPrugOQ2x6tiZ+XHTIA?= =?us-ascii?Q?gNcPwwAqpCQ4R9QCLj4nSDUkENUA8kxyOkR3nfmPeDDHvuk68UyLIWM332oq?= =?us-ascii?Q?AlkpgrSsHPnEZuctlvlcfOnAhadWgwL7k+4bzPp9TyhYo+dnjYLLm6kTr+2m?= =?us-ascii?Q?lcm1k657iGbBDUsXHlbkaI+ukb2MSVhtGSLA6j37LQMsJ1nhSOMgzxpwEm4t?= =?us-ascii?Q?zaNaSzW+F8MV1/JyXalz6KJG4+2zhZmYE0Ott7Ez1IG2tWahg+DDP/YyRz0m?= =?us-ascii?Q?vNTnX0HgRNBfXjil4pi6NTtHjP1PUPvKtujeicZrM0y0AsIpd+z4R3VsRaz4?= =?us-ascii?Q?EY1BdUmVEbsnxHaMTRF6/DhxzMqm3/AMiTMNlVruTsXPkVoZKupWqSok/43r?= =?us-ascii?Q?Ua7Uey+L0gEIC3z/Qc8o4D+1AyFbM1iL2sIc4NA5FyhRatkYDIVHzH0QkfR/?= =?us-ascii?Q?1vFG1kUqrGI3rgTsLu6Mqy9XpXt+S8XiEiCUN35y89hNS291DE0+jd4NPUrz?= =?us-ascii?Q?k5W0A4JHcS2FtCMw+nInSal9HxgOGigKiy8fUsD5DOcJawsx7HFEBo3DYFtC?= =?us-ascii?Q?Ci0O5Zn3d6Kkn4d74zBWw4pDrPuc0gQQtaDbCMWbbmHIXpbyVRYS+B7jsGt4?= =?us-ascii?Q?VGDM7Qjs1m02pyqsArAOa0U6Ge25Ps3P49skbAFprHN3ZMVyEO5vn1+oMzNA?= =?us-ascii?Q?rJqRp/w9g0YRqs+QzmRntLGXpFixXsst4JU/eyb8iyF7vRkqJU9/w+CuJp1Q?= =?us-ascii?Q?lKy4ldB6Pk/f/qR+/+80gVW6jKT8liRU56luLTNZntvmwhPhyiTwI1s43RxQ?= =?us-ascii?Q?XnSv2qlVcw5yba0mX1e0KCBu4RL0P3W68SY3x1XMZWLjEXird3tmUiRiWxgW?= =?us-ascii?Q?tGjSHs7vcIvWgil9taP2jARoBcbmzrwsOrpxDC6ipT+q0WLGfkTIP12Psok7?= =?us-ascii?Q?S+FS7PnChK191tgz0p+xhZAEXt/0x3Raxn5aT86BYkR2Nt0MSi+ppqc9BxMr?= =?us-ascii?Q?UbbHubLMvw=3D=3D?= X-OriginatorOrg: Nvidia.com X-MS-Exchange-CrossTenant-Network-Message-Id: 2eb8433f-75cb-46ce-4812-08df1088868f X-MS-Exchange-CrossTenant-AuthSource: DM3PR12MB9416.namprd12.prod.outlook.com X-MS-Exchange-CrossTenant-AuthAs: Internal X-MS-Exchange-CrossTenant-OriginalArrivalTime: 12 Sep 2026 04:44:27.0642 (UTC) X-MS-Exchange-CrossTenant-FromEntityHeader: Hosted X-MS-Exchange-CrossTenant-Id: 43083d15-7273-40c1-b7db-39efd9ccc17a X-MS-Exchange-CrossTenant-MailboxType: HOSTED X-MS-Exchange-CrossTenant-UserPrincipalName: i1G25WFQaCp0iQTSse7/HU8N6HsvKCOP4MqLaizdTlIz1JJhSfEW4PO26j/ZKcFrhQjlHdb2SuSfCAw3UvMYVQ== X-MS-Exchange-Transport-CrossTenantHeadersStamped: PH8PR12MB7229 Content-Type: text/plain; charset="utf-8" The GSP posts unsolicited events on the same queue as command replies, so a caller waiting for one message consumes whatever arrives first and reads again. Every read started a fresh five-second timeout, so a steady stream of events extended the wait without bound. The two boot-time waits for an unsolicited event also released the queue mutex between reads, so a command sent from another thread could consume the event and leave the waiter to time out. Compute one deadline when the wait begins and pass the time remaining to each read, and hold the queue mutex across the whole wait. Put the loop in one helper that the command reply wait and both boot-time event waits share. Assisted-by: LLM Signed-off-by: John Hubbard --- drivers/gpu/nova-core/gsp/cmdq.rs | 73 ++++++++++++++++++++------ drivers/gpu/nova-core/gsp/commands.rs | 8 +-- drivers/gpu/nova-core/gsp/sequencer.rs | 8 +-- 3 files changed, 60 insertions(+), 29 deletions(-) diff --git a/drivers/gpu/nova-core/gsp/cmdq.rs b/drivers/gpu/nova-core/gsp/= cmdq.rs index 45c3c3aea8f9..4595aa2176e5 100644 --- a/drivers/gpu/nova-core/gsp/cmdq.rs +++ b/drivers/gpu/nova-core/gsp/cmdq.rs @@ -32,7 +32,11 @@ }, Mutex, // }, - time::Delta, + time::{ + Delta, + Instant, + Monotonic, // + }, transmute::{ AsBytes, FromBytes, // @@ -134,7 +138,9 @@ fn size(&self) -> usize { =20 /// Trait representing messages received from the GSP. /// -/// This trait tells [`Cmdq::receive_msg`] how it can receive a given type= of message. +/// A reply that [`Cmdq::send_command`] waits for, or an event that [`Cmdq= ::await_msg`] waits for. +/// The receiver matches a message's function code against [`Self::FUNCTIO= N`] and decodes the +/// message with [`Self::read`]. pub(crate) trait MessageFromGsp: Sized { /// Function identifying this message from the GSP. const FUNCTION: MsgFunction; @@ -569,8 +575,9 @@ fn notify_gsp(bar: Bar0<'_>) { /// /// # Errors /// - /// - `ETIMEDOUT` if space does not become available to send the comma= nd, or if the reply is - /// not received within the timeout. + /// - `ETIMEDOUT` if space does not become available to send the comma= nd, or if the reply does + /// not arrive within [`Self::RECEIVE_TIMEOUT`] of the send, however= many events arrive + /// while waiting. /// - `EIO` if the variable payload requested by the command has not b= een entirely /// written to by its [`CommandToGsp::init_variable_payload`] method. /// @@ -585,13 +592,7 @@ pub(crate) fn send_command(&self, bar: Bar0<'_>, co= mmand: M) -> Result(Self::RECEIVE_TIMEOUT) { - Ok(reply) =3D> break Ok(reply), - Err(ENOMSG) =3D> continue, - Err(e) =3D> break Err(e), - } - } + inner.await_msg() } =20 /// Sends `command` to the GSP without waiting for a reply. @@ -611,15 +612,25 @@ pub(crate) fn send_command_no_wait(&self, bar: Bar= 0<'_>, command: M) -> Resul self.inner.lock().send_command(bar, command) } =20 - /// Receive a message from the GSP. + /// Waits for an unsolicited GSP event of type `M`. Events that arrive= before it are logged and + /// consumed. + /// + /// The queue mutex is held for the whole wait, up to [`Self::RECEIVE_= TIMEOUT`], so no other + /// caller can send a command or consume an event meanwhile. /// - /// See [`CmdqInner::receive_msg`] for details. - pub(crate) fn receive_msg(&self, timeout: Delta) ->= Result + /// # Errors + /// + /// - `ETIMEDOUT` if the event does not arrive within [`Self::RECEIVE_= TIMEOUT`] of the call, + /// however many other events arrive while waiting. + /// - `EIO` if the queue is poisoned, or if a message fails framing or= checksum validation. + /// + /// Error codes returned by [`MessageFromGsp::read`] are propagated as= -is. + pub(crate) fn await_msg(&self) -> Result where // This allows all error types, including `Infallible`, to be used= for `M::InitError`. Error: From, { - self.inner.lock().receive_msg(timeout) + self.inner.lock().await_msg() } } =20 @@ -901,6 +912,38 @@ fn receive_msg(&mut self, timeout: = Delta) -> Result result } =20 + /// Receives a message of type `M`, waiting up to [`Cmdq::RECEIVE_TIME= OUT`] from the call. + /// + /// Any other message that arrives first is logged as an event and doe= s not extend the + /// deadline. + /// + /// # Errors + /// + /// - `ETIMEDOUT` if no message of type `M` arrives before the deadlin= e, however many other + /// messages arrive while waiting. + /// - `EIO` if the queue is poisoned or a message fails framing or che= cksum validation (see + /// [`Self::wait_for_msg`]). + /// + /// Error codes returned by [`MessageFromGsp::read`] are propagated as= -is. + fn await_msg(&mut self) -> Result + where + // This allows all error types, including `Infallible`, to be used= for `M::InitError`. + Error: From, + { + let deadline =3D Instant::::now() + Cmdq::RECEIVE_TIMEO= UT; + loop { + let remaining =3D deadline - Instant::::now(); + if remaining.is_negative() { + break Err(ETIMEDOUT); + } + match self.receive_msg::(remaining) { + Ok(msg) =3D> break Ok(msg), + Err(ENOMSG) =3D> continue, + Err(e) =3D> break Err(e), + } + } + } + /// Logs an event, meaning a message that no caller was waiting for. /// /// An OS error or robust-channel record is logged at error level and = an unknown function code diff --git a/drivers/gpu/nova-core/gsp/commands.rs b/drivers/gpu/nova-core/= gsp/commands.rs index d1c80cf3c452..a01ab14299c6 100644 --- a/drivers/gpu/nova-core/gsp/commands.rs +++ b/drivers/gpu/nova-core/gsp/commands.rs @@ -188,13 +188,7 @@ fn read( =20 /// Waits for GSP initialization to complete. pub(crate) fn wait_gsp_init_done(cmdq: &Cmdq<'_>) -> Result { - loop { - match cmdq.receive_msg::(Cmdq::RECEIVE_TIMEOUT) { - Ok(_) =3D> break Ok(()), - Err(ENOMSG) =3D> continue, - Err(e) =3D> break Err(e), - } - } + cmdq.await_msg::().map(|_| ()) } =20 /// The `GetGspStaticInfo` command. diff --git a/drivers/gpu/nova-core/gsp/sequencer.rs b/drivers/gpu/nova-core= /gsp/sequencer.rs index 1782ed7d7ca6..250adc9fe74f 100644 --- a/drivers/gpu/nova-core/gsp/sequencer.rs +++ b/drivers/gpu/nova-core/gsp/sequencer.rs @@ -343,13 +343,7 @@ pub(crate) fn run( libos: &'a Coherent<'a, [LibosMemoryRegionInitArgument]>, bootloader_app_version: u32, ) -> Result { - let seq_info =3D loop { - match cmdq.receive_msg::(Cmdq::RECEIVE_TIMEOUT) { - Ok(seq_info) =3D> break seq_info, - Err(ENOMSG) =3D> continue, - Err(e) =3D> return Err(e), - } - }; + let seq_info =3D cmdq.await_msg::()?; =20 let sequencer =3D GspSequencer { bar: ctx.bar, --=20 2.55.0 From nobody Fri Sep 25 13:19:17 2026 Received: from BYAPR05CU005.outbound.protection.outlook.com (mail-westusazon11010052.outbound.protection.outlook.com [52.101.85.52]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 3993837E5E9 for ; Sat, 12 Sep 2026 04:44:37 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=fail smtp.client-ip=52.101.85.52 ARC-Seal: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1789188279; cv=fail; b=qx49if01Tb3Mj1eYb+jsMlOo7hUhVaU0aU/h9l3iRwaZcoqadLyXX+kDSVi6CaI33sYG0+B7LTl7hq0y7DjLF9zNFiQ6uDbTkWfGYYO0womR8S0Nkmb+QiEC7EB3yfwYQC9WSvZHxEQGeYBtBd3y+zVogvOaSa+BlovCwqi/Omk= ARC-Message-Signature: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1789188279; c=relaxed/simple; bh=DnzfH71oI8wmg8ygH93I6BfFKJfvWyeC0r1QS5rbMho=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: Content-Type:MIME-Version; b=bBG8oUoPW/IMKyJjiakP/sTF9mRgIekJWU8UW9dtSp/+4WNGleR2TtjPktQgWTQy75bLmdYOUysaYHWvmCks36x/l3fc1gX0luh3BIr0fRkRxRMmgqOfFu7+eiyBaUHKCulioPIkKxZHHAL3DbKhtiLUKSvKvFs5gXxJKpgk9Ek= ARC-Authentication-Results: i=2; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=nvidia.com; spf=fail smtp.mailfrom=nvidia.com; dkim=pass (2048-bit key) header.d=Nvidia.com header.i=@Nvidia.com header.b=hDRKSoFL; arc=fail smtp.client-ip=52.101.85.52 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=nvidia.com Authentication-Results: smtp.subspace.kernel.org; spf=fail smtp.mailfrom=nvidia.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=Nvidia.com header.i=@Nvidia.com header.b="hDRKSoFL" ARC-Seal: i=1; a=rsa-sha256; s=arcselector10001; d=microsoft.com; cv=none; b=KnG59Lb0LOQSZcLpeY9AZ/6urvlBfWcbA+yFXvr8q4JREhzeXU3dduq7Jmrqa45c2chsGJfMk5kMXS8C2apAVDTo7kf2ZHavnqEiXJ6nseDkkCrh2Ufa7ngejjcF5xSqW+p7ZXvNPXC2yNIkBgG9bgOUsO7znNVOF5cORgFAhc14q74SDLHRwW8J1YWPYvCluqCT/yeR/Kyrm6NPFSvR7tvF4xCeSmPKvwzJbZuFAdSnxEK9PiZLEoy9ageEQStrO4M+Op3G4/JS8jTsim8H3D+owfv/kH0rSqEPWVL+7q8rg2hdEpypo/F+8jIlj8O4IOVrVbLoSWP6k5UNyQ6Hcg== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=microsoft.com; s=arcselector10001; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-AntiSpam-MessageData-ChunkCount:X-MS-Exchange-AntiSpam-MessageData-0:X-MS-Exchange-AntiSpam-MessageData-1; bh=FVvcaEi1cOJmE6u5fY0SxSXv55Es7YY2jRBzvxzklEY=; b=YlxUIPt4P5MquTTxRxJgKJM/Wwyi7fU5KQPeuKHdYh0ZVlQ/nqBUgPsbFTijVoLZkvofH2xvSW10LHav+Jkd0L27pwQIBo00j1kn7TBdEp201zpxHV3ucHgE8oJ1rEH6hK/AUFkffabWE97pXiaCsAFKXjF7/KRG4Zrb2a2vlR4DQhMOUw64TzhsG5LXaryxoDPU3WNIG6kMRpEWt8ZgcPhpOvUqbH2rrLsfvYdyhJZod5eTh2AkiPK8Sx+AodfFk85hSWqElbc+zSG+d+zulU9mMQYPA7mpdaknGc5kEJZcpG3DhPQD9EUL/Lbf+HtoJdVu2DVXEMoYgT13aEwOuQ== ARC-Authentication-Results: i=1; mx.microsoft.com 1; spf=pass smtp.mailfrom=nvidia.com; dmarc=pass action=none header.from=nvidia.com; dkim=pass header.d=nvidia.com; arc=none DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=Nvidia.com; s=selector2; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck; bh=FVvcaEi1cOJmE6u5fY0SxSXv55Es7YY2jRBzvxzklEY=; b=hDRKSoFL+W6gcV58BMLG9EH+qRFX1ZTE5PnslHwF/or7NLHc4HK8L4wIQLqyp4REZ/zxtXFnpar6XkaLgC+dyu94nn/j2Jj5iTTSprTAk74xN64bC4I33jxuCtzr7riiZoBzIIqoBJ9u3UFsAhcbFivyI8F1kGafOodQV/rX+gPjnYphU/Esl7KIuP/CN5TxgIhi/C0dF5Z825StKz1bDR4sAL5kpENM/lIvoZra+rBOD31nmSIMyZv2iJG54HglLGCgLaLfbKf0Re9XsUHBVVuizlFVhNdFJi8+5zMgKA0zaE2ulegiXdhNxKo+aHs7xfCIjBhC31EB6SJR1mLgqg== Authentication-Results: dkim=none (message not signed) header.d=none;dmarc=none action=none header.from=nvidia.com; Received: from DM3PR12MB9416.namprd12.prod.outlook.com (2603:10b6:0:4b::8) by PH8PR12MB7229.namprd12.prod.outlook.com (2603:10b6:510:227::20) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.21.406.10; Sat, 12 Sep 2026 04:44:28 +0000 Received: from DM3PR12MB9416.namprd12.prod.outlook.com ([fe80::8cdd:504c:7d2a:59c8]) by DM3PR12MB9416.namprd12.prod.outlook.com ([fe80::8cdd:504c:7d2a:59c8%4]) with mapi id 15.21.0406.007; Sat, 12 Sep 2026 04:44:28 +0000 From: John Hubbard To: Danilo Krummrich , Alexandre Courbot Cc: Timur Tabi , Alistair Popple , Eliot Courtney , Zhi Wang , David Airlie , Simona Vetter , Bjorn Helgaas , Miguel Ojeda , Alex Gaynor , Boqun Feng , Gary Guo , =?UTF-8?q?Bj=C3=B6rn=20Roy=20Baron?= , Benno Lossin , Andreas Hindborg , Alice Ryhl , Trevor Gross , nova-gpu@lists.linux.dev, LKML , John Hubbard Subject: [PATCH v4 13/17] gpu: nova-core: add a GSP message queue drain Date: Fri, 11 Sep 2026 21:43:56 -0700 Message-ID: <20260912044400.677097-14-jhubbard@nvidia.com> X-Mailer: git-send-email 2.55.0 In-Reply-To: <20260912044400.677097-1-jhubbard@nvidia.com> References: <20260912044400.677097-1-jhubbard@nvidia.com> X-NVConfidentiality: public Content-Transfer-Encoding: quoted-printable X-ClientProxiedBy: SJ0PR13CA0089.namprd13.prod.outlook.com (2603:10b6:a03:2c4::34) To DM3PR12MB9416.namprd12.prod.outlook.com (2603:10b6:0:4b::8) Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-MS-PublicTrafficType: Email X-MS-TrafficTypeDiagnostic: DM3PR12MB9416:EE_|PH8PR12MB7229:EE_ X-MS-Office365-Filtering-Correlation-Id: 8b5df4de-d265-451c-07ed-08df10888742 X-MS-Exchange-SenderADCheck: 1 X-MS-Exchange-AntiSpam-Relay: 0 X-Microsoft-Antispam: BCL:0;ARA:13230040|1800799024|7416014|376014|23010399003|366016|10067099003|18002099003|5023799004|11063799006|56012099006|22082099003; X-Microsoft-Antispam-Message-Info: DDaoc1LrA4zg+8ISzBqoliuiZFyft4nXwLx8bpEBo/cIouSzZE9EpORq+8vmIGFS8C2f5FnCmzPUnZEnp7QVSQOIoOe0Vx6ZCx0cDQXa4Zj3PqBog4Rbpyyy3TKhZ5r8rwnm076kCe/k9EK2ZIO1aMLiTRb5eI930ucxAm6LB2nDT99sbDedjhywHtjqyH33txHDQK7HYbSxMHB0cRRBSBup5JTJBZEpMh6FAUUui53UEN2sRDUasco9+DIw5hAqzg+YAOe8uD3FkKoEvDGjvYd/vw3q1coVIynKPP6b5qO4MRGtwlUx695kSiZAswCDS8elCAbwYpYW3m5cPgfAF7tZX1TYY/G6892f/+337uds6JSakvvDw5OlN7BdFe3L0z699Jx8f+qoawvQ0PvrMounJ69NRo4pQ1VerxRqpUi1XWoHUOyn8dWTFEl01dSRKZUwqVg/Ti2QAO9S/HBY+UmG3+lVeZ1045QY/1LZqlXFMldjwWBlHIKRLFoFnz/pdv9rCXG2gawl/sXexMYlxhal7dPXP46/v21/JWkW+ejAicDM5N7a/vIL+CWkWpvnkLTNlksgoefUh9z8kd8h3s+mPF4AS0dsl+LQ/z7htR/aNyV9ZBfB9KLxH7/LteVUqP3msEF0p/qBa7CjHw597c3d+4lW9bi05vTPUqRNfWA= X-Forefront-Antispam-Report: CIP:255.255.255.255;CTRY:;LANG:en;SCL:1;SRV:;IPV:NLI;SFV:NSPM;H:DM3PR12MB9416.namprd12.prod.outlook.com;PTR:;CAT:NONE;SFS:(13230040)(1800799024)(7416014)(376014)(23010399003)(366016)(10067099003)(18002099003)(5023799004)(11063799006)(56012099006)(22082099003);DIR:OUT;SFP:1101; X-MS-Exchange-AntiSpam-MessageData-ChunkCount: 1 X-MS-Exchange-AntiSpam-MessageData-0: =?us-ascii?Q?7BKqw/euFll8Khq0PX+DYEzCxc6lG7zMVxlwgytLCeqVc2ijFqmh8KeOQMon?= =?us-ascii?Q?Skf6h+RVP2+IHXacC6B0HjyihxYnhohrmXzW/2aZ6rQCmCDZaKUiLjInEDW7?= =?us-ascii?Q?HJwFwtIwWukQoHN+31vihURkX1FMKlAoBrLdX/r4VZv6tGOU0xt/N/AwTtJy?= =?us-ascii?Q?q75TwpkStExlELtjJVtBOU0ZO5xsLrIc5o+HpMz9bTpunhH4HAG10HESCQZw?= =?us-ascii?Q?hFWRrp4jhzHfzOJlgD6458f61G3M2wcDhwOpSkR7n4LyPjcVAytPICI2IL0S?= =?us-ascii?Q?v/eQAfPGMLHu3qZA7Xg9V8ORi0dvW40+HFesXz1FgxwsaJhgnJe7KoIrDgar?= =?us-ascii?Q?7TdhbMaCz5/roVs/044Q8i4qMJ2A+CikgUUl86SbZjhQb7+Gv5tSOFH0jYk5?= =?us-ascii?Q?I+vpx7AydNOB+4ANC0cAKeA5Vt5bfmCbVg5CTlgvEobZ3An2Ib6fL50PetAe?= =?us-ascii?Q?o2YMLCzWU28ztzWeFDDaw4A2t1ga9iw8PV7XC53wxBhiOr3ZIC+s8YMIk5+l?= =?us-ascii?Q?iAzjrJC7IkH48Cy7XkvqKD+a+Ylsm1AITAwxUXMg/pRL4cS5MobS83unzuUf?= =?us-ascii?Q?I9SJgaHjJVZ73U2C9thGg6LcCvBDOU9VOSKV5rt2IKyBan/i6QpGGCjH23D0?= =?us-ascii?Q?/D5PDGQSd2SatVkekkBSGmi6UGEo6gZJ+gs7cwMb/rOJH8pX6cv7HYcg721/?= =?us-ascii?Q?YNSWfMDwMH+8o9JDmtRZboikKA58BCPxVjdm9E3OJ81D46G4a4zoJLf66cx5?= =?us-ascii?Q?W5/CGePJprCocKNp3aP58jxvy0ZaX9Vy6m5cRkwcL+mBEHkhE5QbEHXnVxhe?= =?us-ascii?Q?QEazLoSl7uGxkmELP4XwmbINmuyvMIGpbq0iEpUDxdjzHP64wlmYYx9L2ijI?= =?us-ascii?Q?Qxv4s9xEcRL9fFaAnx3N8S38wUf8cbo1C2WIBxtMXNYXGhdQq3oAP1e0ADw3?= =?us-ascii?Q?mgQU3pBbmZc25KKyizPsL913fYcg2fLcy+Aug6AEIeGdRRpy8qRF4xe9IVde?= =?us-ascii?Q?mBR5WGYqF44gevuN/abuyPo/CzRWWocUabxx3yen4THqO7hueDNhjiaZrum5?= =?us-ascii?Q?sAhociT1Fcc+4TJdN1Zqqz2gZwxtHjuFCTqL5BUV0+MWryepH/ootmzqpi/d?= =?us-ascii?Q?fBSd6TnaOgsIUfnKHfogH5D4kIEc6eNVp+G/kkNc/BJxEenGAct3xELxIHFP?= =?us-ascii?Q?3/y3uCKYEopbbQpbRdweyLArWr1M/yBFowPoIs/tsFs8y1M5M6sx9j2NASYi?= =?us-ascii?Q?sm8zIJAaFAl8TpJ83lnjaou8dKDMszkTPYaJ9mz0x130irYlm83WCwO9bYHO?= =?us-ascii?Q?NpXUeYzosKDjrhpxkP+Pcyfun05k+/ghTir4suAYPJBr4jRcgouglhVmYGD3?= =?us-ascii?Q?w4ZK+v3LMH9qKKjBVxjPDApCEGqNyo3SM7Qz478Py+KNjQYEgIQSUlQSJ6VY?= =?us-ascii?Q?jCFY+wB8VdQbSCNaR2iaFEDRScRjkgw/7/6LAjnvU/D+6jPFoX2NK/w/W96T?= =?us-ascii?Q?txJpQu0ozdk2p4n9jarnUZFnTvpMh6Eig/SE09zTYmpJtY1Sjb5El8WhIVr5?= =?us-ascii?Q?xVpsFequDjkDnHQzvHve2K0YKgJLBplp4dWf7zM9Htr7w7wxLMpJIuo8gzmW?= =?us-ascii?Q?HLnR4tz70aIbxyD+EYucED7W7YGZJqpe8AFUo5pKB1Tf7kiaXkRYpMehenS8?= =?us-ascii?Q?Kk6q4A4Wi6h2Ac3wy/XesdE10iVo8jjujg225K39JmVaHqRF1AxTTx/zX/Gy?= =?us-ascii?Q?rtJqlA32ew=3D=3D?= X-OriginatorOrg: Nvidia.com X-MS-Exchange-CrossTenant-Network-Message-Id: 8b5df4de-d265-451c-07ed-08df10888742 X-MS-Exchange-CrossTenant-AuthSource: DM3PR12MB9416.namprd12.prod.outlook.com X-MS-Exchange-CrossTenant-AuthAs: Internal X-MS-Exchange-CrossTenant-OriginalArrivalTime: 12 Sep 2026 04:44:28.2314 (UTC) X-MS-Exchange-CrossTenant-FromEntityHeader: Hosted X-MS-Exchange-CrossTenant-Id: 43083d15-7273-40c1-b7db-39efd9ccc17a X-MS-Exchange-CrossTenant-MailboxType: HOSTED X-MS-Exchange-CrossTenant-UserPrincipalName: 1U2jl4k/FoRnFUSVGJf4Kl1fCzXl5fjLiIKx1s7WzqmrzTo58lcWFChAFsDXR6SqUJxlK52ukcu0+p3AckzKVw== X-MS-Exchange-Transport-CrossTenantHeadersStamped: PH8PR12MB7229 Content-Type: text/plain; charset="utf-8" The GSP posts unsolicited events on the GSP-to-CPU queue whenever it has something to report, whether or not a caller is waiting for a reply. Every existing way to read the queue asks for one message type and waits on a deadline. A caller that only wants to empty the queue had nothing to call. Add a drain that logs and consumes whatever the GSP has already posted and returns as soon as the queue is empty, without waiting. It holds the queue mutex, so no reply is among the messages it reads, and it treats every one of them as an event. Assisted-by: LLM Signed-off-by: John Hubbard --- drivers/gpu/nova-core/gsp/cmdq.rs | 41 +++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) diff --git a/drivers/gpu/nova-core/gsp/cmdq.rs b/drivers/gpu/nova-core/gsp/= cmdq.rs index 4595aa2176e5..acee444e898d 100644 --- a/drivers/gpu/nova-core/gsp/cmdq.rs +++ b/drivers/gpu/nova-core/gsp/cmdq.rs @@ -632,6 +632,21 @@ pub(crate) fn await_msg(&self) -> R= esult { self.inner.lock().await_msg() } + + /// Logs and consumes every message the GSP has already posted, and re= turns without waiting for + /// more. + /// + /// No caller is waiting for a reply while this holds the queue mutex,= so every message is + /// logged as an event. See "Draining the GSP-to-CPU queue" in + /// `Documentation/gpu/nova/core/interrupts.rst`. + /// + /// # Errors + /// + /// `EIO` if the queue is poisoned, or if a message fails framing or c= hecksum validation. + #[expect(dead_code)] + pub(crate) fn drain(&self) -> Result { + self.inner.lock().drain() + } } =20 /// Inner mutex protected state of [`Cmdq`]. @@ -973,4 +988,30 @@ fn log_event(&self, function: Result= , seq: u32) { } } } + + /// Logs and consumes every message the queue holds. + /// + /// # Errors + /// + /// `EIO` if the queue is poisoned, a message fails framing or checksu= m validation, or a + /// message's page count overflows a `u32`. + fn drain(&mut self) -> Result { + while !self.gsp_mem.driver_read_area().0.is_empty() { + // A message is available, so this returns without waiting. + let msg =3D self.wait_for_msg(Delta::ZERO)?; + + let pages =3D + u32::try_from(msg.header.length().div_ceil(GSP_PAGE_SIZE))= .map_err(|_| { + dev_err!(&self.dev, "GSP drain: message length overflo= w\n"); + EIO + })?; + let function =3D msg.header.function(); + let seq =3D msg.header.sequence(); + + self.gsp_mem.advance_cpu_read_ptr(pages); + self.log_event(function, seq); + } + + Ok(()) + } } --=20 2.55.0 From nobody Fri Sep 25 13:19:17 2026 Received: from SN4PR2101CU001.outbound.protection.outlook.com (mail-southcentralusazon11012058.outbound.protection.outlook.com [40.93.195.58]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id F045438E100 for ; Sat, 12 Sep 2026 04:44:38 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=fail smtp.client-ip=40.93.195.58 ARC-Seal: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1789188281; cv=fail; b=AljUJQLy3LSoxLENGD+iTdz6SB1b2sSgpE1La3kN6ekvvwvUyEd/CAmwivDhbS6YtM0Z4jlKaJpqLtyEWuwlEDtVUZCr/o828+CN1uHKKr4/J218oO73ZEDWY9tFXU7du6e6mUSrs/iOAwHhDvf57S9obOJtYoonMzaRyVcoKfY= ARC-Message-Signature: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1789188281; c=relaxed/simple; bh=0ZFat5/5PNWi7nAsNvdgiSxqeoHfYpp2B8y0E8JoYaM=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: Content-Type:MIME-Version; b=u+GyHnJykpAIh1oFeHBMx21jwco8BuI+cRmY7ADYJt0DDb593tUUvx0FuSaRMO+K3GYJSyCKWQW8fUNJ92ln73OdTWBLSdRw2q8WcCVnOMAAXXSIBHe9fWhfNnCKsDZpn5KWl6Jnl9msHiI1EqLpqWLUs0rrPV7MoesLa72paUM= ARC-Authentication-Results: i=2; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=nvidia.com; spf=fail smtp.mailfrom=nvidia.com; dkim=pass (2048-bit key) header.d=Nvidia.com header.i=@Nvidia.com header.b=HCGGkS+N; arc=fail smtp.client-ip=40.93.195.58 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=nvidia.com Authentication-Results: smtp.subspace.kernel.org; spf=fail smtp.mailfrom=nvidia.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=Nvidia.com header.i=@Nvidia.com header.b="HCGGkS+N" ARC-Seal: i=1; a=rsa-sha256; s=arcselector10001; d=microsoft.com; cv=none; b=x0VR7LV760EV4iVoZBtv/k+A2xxPI8QZxuO9VKxEVHML5xyhi4lJU1foGV7CoidnDw6PMT9VC5n9UYJTsVptXQVluQIEjK7y2tQ9r1yTKS5/FUzqpV8qtDtaAWT8cgZiOuQ68VJ+xBr291bwmtS/0xjBjudNtgNEVA3varosLT99KVWefu2uej3uB3ebkYt7ISY/C3Tz/oixBQbG2wQNjJBM8JxfKq7NR/4rV1I+w87vuWPrTnOQ0BFieFezZU3mPpQCUMXzUqqoGRCeMW8T2cAMsoOwaK051vIcCdVlQPIu12XIprVr56jDm7+enLd6e5hlAjXeT6jdsWQi5gXcUg== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=microsoft.com; s=arcselector10001; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-AntiSpam-MessageData-ChunkCount:X-MS-Exchange-AntiSpam-MessageData-0:X-MS-Exchange-AntiSpam-MessageData-1; bh=xn+ThUXOhWoF/HAFKQveMKP3va628g6WbuEiE9af/H8=; b=W10vYTXV+/ggv3rOabciAomGZEZbrZth69XB5FYJVk8m5IAz/KfFG/1xE6uWSoTRivEBuQOnTnAkx96e3tH/ovegmSlngzvt+bRuYtglez5Va2q+OBRyO2NhYv0amwOJzmWpM5pGFLCBcV4jmW9Bqq6+yVg1T7JaW/8Chn0JjbywlkO2xDE7sv9gCFoFAQsXK/uvDGWD7OWzbsjJKNkNi2VPZiWQE/2rQexLfLzzWC8FMFtlQgYKqtZsqpNFu4PaxGQnoEihUewfR0bL9bzpezqk5z7wK2At94KwmwD7/xZWgufXJ1BWCFR4uJUSqkNmuxS95WYAGYyt6lXJe3FHTw== ARC-Authentication-Results: i=1; mx.microsoft.com 1; spf=pass smtp.mailfrom=nvidia.com; dmarc=pass action=none header.from=nvidia.com; dkim=pass header.d=nvidia.com; arc=none DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=Nvidia.com; s=selector2; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck; bh=xn+ThUXOhWoF/HAFKQveMKP3va628g6WbuEiE9af/H8=; b=HCGGkS+N/klPHN0TYT9H+tksAFQbsY5HRUgfya0Sroxc8EaW6CeEMWgkbm1YEc9aW/V9jTTHG7rigPohYG3OSVd5JRYgy2fTzPliovBOaHKh0TmLeNlvBlH+i8jkotzFxdsPFaZ4hGjZN8KaFyI/4PDjP27yvc2gVdmry8Gqow9qTZ4xm/Zm7Q4qzM0Efw41Z7mmL2hnNFapaJtXDuaxkp96LO1OuymunPTpTSzmPQNDMz9Jik5QjuLrXhaVNFQ5q/4HyXQ7amBWN5NhboGa13A0+xi51X6E5JmGm2gE6LQZxJ4/KrwdFR+xL/jIQk7pddhDuTHdkkVoTxqCb3UzNw== Authentication-Results: dkim=none (message not signed) header.d=none;dmarc=none action=none header.from=nvidia.com; Received: from DM3PR12MB9416.namprd12.prod.outlook.com (2603:10b6:0:4b::8) by PH8PR12MB7229.namprd12.prod.outlook.com (2603:10b6:510:227::20) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.21.406.10; Sat, 12 Sep 2026 04:44:29 +0000 Received: from DM3PR12MB9416.namprd12.prod.outlook.com ([fe80::8cdd:504c:7d2a:59c8]) by DM3PR12MB9416.namprd12.prod.outlook.com ([fe80::8cdd:504c:7d2a:59c8%4]) with mapi id 15.21.0406.007; Sat, 12 Sep 2026 04:44:29 +0000 From: John Hubbard To: Danilo Krummrich , Alexandre Courbot Cc: Timur Tabi , Alistair Popple , Eliot Courtney , Zhi Wang , David Airlie , Simona Vetter , Bjorn Helgaas , Miguel Ojeda , Alex Gaynor , Boqun Feng , Gary Guo , =?UTF-8?q?Bj=C3=B6rn=20Roy=20Baron?= , Benno Lossin , Andreas Hindborg , Alice Ryhl , Trevor Gross , nova-gpu@lists.linux.dev, LKML , John Hubbard Subject: [PATCH v4 14/17] gpu: nova-core: add the falcon interrupt registers and their HAL Date: Fri, 11 Sep 2026 21:43:57 -0700 Message-ID: <20260912044400.677097-15-jhubbard@nvidia.com> X-Mailer: git-send-email 2.55.0 In-Reply-To: <20260912044400.677097-1-jhubbard@nvidia.com> References: <20260912044400.677097-1-jhubbard@nvidia.com> X-NVConfidentiality: public Content-Transfer-Encoding: quoted-printable X-ClientProxiedBy: SJ0PR13CA0192.namprd13.prod.outlook.com (2603:10b6:a03:2c3::17) To DM3PR12MB9416.namprd12.prod.outlook.com (2603:10b6:0:4b::8) Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-MS-PublicTrafficType: Email X-MS-TrafficTypeDiagnostic: DM3PR12MB9416:EE_|PH8PR12MB7229:EE_ X-MS-Office365-Filtering-Correlation-Id: 24e27e2f-ab19-4f8d-0ca8-08df10888801 X-MS-Exchange-SenderADCheck: 1 X-MS-Exchange-AntiSpam-Relay: 0 X-Microsoft-Antispam: BCL:0;ARA:13230040|1800799024|7416014|376014|23010399003|366016|10067099003|6133799003|18002099003|11063799006|56012099006|22082099003; X-Microsoft-Antispam-Message-Info: 0gArYxy/8S6pCcsa1RyRHPqz5znko8PTfNrYQ0OPKr6nA/yDbgMvPB5WDpIoacOoWoXJEBN/ZvwNYNrMEr/ygBWJ27HE8Wgvi6MrzVuPFGGsbjYd0dZicgg4OeoNsdoVLV1Q0NNiTG0osK9JORMMmkUu4xnZAFvwckAQRg503y+5UIiI7jPt3c7kXFq6ZYriO2uRtQ/7QWGlg0TA3eMk+A88Qa9mF5MvcSD+u3iHg/yFG72bCJlUOvBuLTNvliR+AuwGyhw0aPFHLZa6lS370CTZEz636CJ8gSL/v43KhcQaiIEHAyiQp7yAI0qRgkLIVI5mhcKC/QSDCFurUsFPOJK/C25VMEUWQqg7E0UWmiqV80X8hRKFRKKpTgid+vbvzkxUg6LVh6sNPqb5WXj2152i3W8wOYdkcmlCOqealQWl93NYxCdsY9oenmQZInEbRf1Wp0uCCVUlxJeAmBeAKE3huOjQHQNg5SwtYAZR/NgqMK+/suK7xWer7LSXshiNwwHB5u+wc01BRaSEoMlplZVSZyn8Gp6cPEMyUJCdh9H7hfuZ4riLyefSEELifhRno8dgF6fnO3MwXFdAOj5VzIEUR8Tto8QzwxQWo1IcJ5jL45LFgS0P1+J2nig4OSeqLEiMrBxM4i6GBaSGhUynHCjne7e+vGKpi4V5XEnZ3fc= X-Forefront-Antispam-Report: CIP:255.255.255.255;CTRY:;LANG:en;SCL:1;SRV:;IPV:NLI;SFV:NSPM;H:DM3PR12MB9416.namprd12.prod.outlook.com;PTR:;CAT:NONE;SFS:(13230040)(1800799024)(7416014)(376014)(23010399003)(366016)(10067099003)(6133799003)(18002099003)(11063799006)(56012099006)(22082099003);DIR:OUT;SFP:1101; X-MS-Exchange-AntiSpam-MessageData-ChunkCount: 1 X-MS-Exchange-AntiSpam-MessageData-0: =?us-ascii?Q?KBVIVKEFliUABM1X773A7Xe7A1QWMlq7hgrkQDpoUoZcGAfa8uiVQ8UyA2LT?= =?us-ascii?Q?sjpQmRbcu7dNqEcKfjl62FQ6GmVbn/ANp+2XSbL/FDzuzQYAOA3OxN0jPEoK?= =?us-ascii?Q?tkNGesUOO6q92YI+gGbKL8qHRR7GSfzV58tKJZOSoF2Io+8BR4kaFjKz16NP?= =?us-ascii?Q?aZLstoDFCcqL/hS6NUls5chdwFv6gjecNdS3mDQHhUm8iSQ6+G495+03AknZ?= =?us-ascii?Q?JfLRaH6ttkZ+1CBXV572vlGKA7v6hi97ILXUBzCk2OvfwmPRFiLKk7vO9mWM?= =?us-ascii?Q?VaBngXklI5ch9ZeFfalO49ilyau/sMJtqqbDfZ68W+03DzAKBLZApU7L4ibW?= =?us-ascii?Q?4jW35mKQJx+Nj3BGR/5X8GvBYYf+HNkiJqfB/FciZiU16uANa9kghAuLLsQr?= =?us-ascii?Q?WjRCUNVuJISNy7HigGLB/mtgnjmAysGUoK/wFhettVbZmS4I2hGer6EEVAQf?= =?us-ascii?Q?slLvSHcnptD8kjNcbtbU3S7eohNENigcpHQNiPTW8jIluPmLFGBkA3ikNa1A?= =?us-ascii?Q?AIIAx0qSiV1YfPbECcb10rZC4uYjHm81zi4OpTlhF5fRXafWI9MtfqK4xWsX?= =?us-ascii?Q?ejYMxGHGfkGLCCutePMvMwonVHUmeUbrBJ0+XdxfEZ3D/ZWqr4OmaIKf4ssy?= =?us-ascii?Q?b3go1yOVl/xqMwft4c7GXSlXc3c6cxyN6Xsok/PM1po618nP6PiJYQPHlvEd?= =?us-ascii?Q?9Oy54/EyDCO9coJZsueUVzNkFiU05jIP1MIhl2lJF49kjEv/2K5DzVGnif8L?= =?us-ascii?Q?AuEZNnQgK4Qf5zKPFb60otK9399VoL1rRxqDEu6yB9QkCO67ntv4XeS8a+kS?= =?us-ascii?Q?tmqe0VwG9RNLkw4VriEqA6mpOWCoZnpz2bE9JCvV9QY3jAbPtEYDmBnQ2zme?= =?us-ascii?Q?KrWGpn7gZ+PjdWW/ornSUP+w//eKOJ2cR8cpyDZ1mnHrmBg0orW4M76DwkXC?= =?us-ascii?Q?VgpZkQTBOF+mm1+xjEoZ1BQdmhSsN1w0XlPfyqHOYpiLyDUA2ZkZyIbgajo5?= =?us-ascii?Q?UBIuSW3qxuyXVG/bnvjTMWMPX353SKOvuKjcbLCVqj4TvUy+99N4uP6JP78h?= =?us-ascii?Q?hJUWtH8AVZIiqi1BrhAfgXVQMJgsEwpegbMrehj/xZ9QKT25F1Yqfrl6ZVnu?= =?us-ascii?Q?KRTA2BdCG69GTmt9rARcqQL6/GwTs8XMAvc5R6YGWYY5GPrkUSPBlG7uY/bS?= =?us-ascii?Q?fLdzfHiQ2rsfA/eVm3xiuaojCLZkf+v4R2ATQjXW9rAJZG29GsZGrdoux/lk?= =?us-ascii?Q?kbIL+RDlv90ro1hL6rmiZArxBDjgFcw9PtHtVyzQdbTXmZ/Ln7SU7WCPCEfQ?= =?us-ascii?Q?r+9bs6gvW19wgex9Wbx2lWWpaVoEso/zlcgM/x6idilnUrHKhFZrspmdYzrg?= =?us-ascii?Q?g/sqPxFPg5kWmGIs97j9IX7/44XDLc19itCJvYU5vpvbVIB7awwRoPFF7zf8?= =?us-ascii?Q?1IOWiKV3kJNFPDAFeZ90XAZRuu5sIha6kJhN0nE04/I2yQ0DC/dJWVKNhXCr?= =?us-ascii?Q?yQyYKsAleb99IShPYIbhhrdGr5tq8NvODXvem+hW5csexMVMi3rItybex3ZU?= =?us-ascii?Q?EQ4n49E8HrXcuPQ1LoEL3mHiwVcK4n5Poqt9yPs1pqr+JyLPWqMsKioerTYc?= =?us-ascii?Q?0anP/ekUl+PsPFrx0d/V0n80NdffiLSMEqtXD5KYhDXC0NdmWW0A2e7JHuSO?= =?us-ascii?Q?AJZN/KqgOnfSSLaMZx7YA5L98XU3D/eCW+Z4LYne09nXnteqhHGvrITLTkY3?= =?us-ascii?Q?wfBMM+X0fA=3D=3D?= X-OriginatorOrg: Nvidia.com X-MS-Exchange-CrossTenant-Network-Message-Id: 24e27e2f-ab19-4f8d-0ca8-08df10888801 X-MS-Exchange-CrossTenant-AuthSource: DM3PR12MB9416.namprd12.prod.outlook.com X-MS-Exchange-CrossTenant-AuthAs: Internal X-MS-Exchange-CrossTenant-OriginalArrivalTime: 12 Sep 2026 04:44:29.4883 (UTC) X-MS-Exchange-CrossTenant-FromEntityHeader: Hosted X-MS-Exchange-CrossTenant-Id: 43083d15-7273-40c1-b7db-39efd9ccc17a X-MS-Exchange-CrossTenant-MailboxType: HOSTED X-MS-Exchange-CrossTenant-UserPrincipalName: CkZYGNssOcDdqbqUiiK6hkl006Uzir+ukaLe+YMhxY//0Y370ptmfl+/v5UHmGwCHAwRq6IkwO+PeFzVnOteaA== X-MS-Exchange-Transport-CrossTenantHeadersStamped: PH8PR12MB7229 Content-Type: text/plain; charset="utf-8" A falcon has a set of interrupt causes, and it latches each one that is raised in its IRQSTAT register. On a RISC-V falcon, each cause is routed either to the host, meaning the CPU, or to the falcon's own RISC-V core, and IRQSTAT holds the causes of both. Two more registers say which is which: PRISCV_RISCV_IRQMASK holds the enabled causes, and PRISCV_RISCV_IRQDEST holds the causes routed to the host. Open RM intersects the three to get the causes that the host has to service, and nova-core does the same. A falcon signals the interrupt tree only when its set of host-routed causes goes from empty to non-empty. A handler that clears the tree leaf while a cause is still latched in the falcon leaves that set non-empty, so no later cause produces a transition, and the falcon's interrupts stop arriving. INTR_RETRIGGER makes the falcon re-emit its host-routed causes into the tree, which supplies the missing transition. Turing falcons do not implement it. IRQSCLR clears a cause's latch, but it cannot end the source behind the cause. A cause driven from outside the falcon, such as a fault containment or ECC error on Blackwell, stays set through the write. Add the four registers: IRQSTAT, INTR_RETRIGGER, and the two routing registers. Record the IRQSCLR limit on its existing definition. The routing registers go in per-chip modules, because their offsets move at GA102 rather than at the Turing-to-Ampere boundary. Add a HAL for the two properties that follow, the retrigger register and the routing offsets, which split the chipsets three ways: * Turing falcons have no retrigger register. * GA100 has the retrigger register, and keeps the Turing routing offsets. * GA102 and later have the retrigger register, and their routing registers moved. Keep this HAL apart from the falcon boot HAL. The boot HAL is generic over the falcon's engine type, so obtaining one is a heap allocation, and the interrupt handler that needs these two properties runs in hard interrupt context, where it cannot allocate. Assisted-by: LLM Signed-off-by: John Hubbard --- drivers/gpu/nova-core/falcon/hal.rs | 80 ++++++++++++++++++++++- drivers/gpu/nova-core/falcon/hal/ga102.rs | 21 +++++- drivers/gpu/nova-core/falcon/hal/tu102.rs | 36 +++++++++- drivers/gpu/nova-core/regs.rs | 69 +++++++++++++++++++ 4 files changed, 202 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/nova-core/falcon/hal.rs b/drivers/gpu/nova-core/fa= lcon/hal.rs index 7e532889a1f4..052610c4a4da 100644 --- a/drivers/gpu/nova-core/falcon/hal.rs +++ b/drivers/gpu/nova-core/falcon/hal.rs @@ -1,17 +1,25 @@ // SPDX-License-Identifier: GPL-2.0 =20 -use kernel::prelude::*; +use kernel::{ + io::{ + Io, + Mmio, // + }, + prelude::*, // +}; =20 use crate::{ falcon::{ Falcon, FalconBromParams, - FalconEngine, // + FalconEngine, + PFalcon2Registers, // }, gpu::{ Architecture, Chipset, // }, + regs, }; =20 mod ga102; @@ -72,6 +80,74 @@ fn signature_reg_fuse_version( fn load_method(&self) -> LoadMethod; } =20 +/// Offsets of a falcon's RISC-V interrupt routing registers. +#[derive(Clone, Copy, Debug, Eq, PartialEq)] +#[expect(dead_code)] +pub(crate) enum RiscvRouting { + /// The Turing offsets. GA100 uses them too. + Tu102, + + /// The offsets from GA102 on. + Ga102, +} + +impl RiscvRouting { + /// Returns the causes in `latched` that are routed to the host, meani= ng the CPU, rather than + /// to the falcon's own RISC-V core. + /// + /// The causes routed to the core belong to the firmware running on it= , and the host does not + /// service them. + #[expect(dead_code)] + pub(crate) fn host_routed_causes( + self, + pfalcon2: Mmio<'_, PFalcon2Registers>, + latched: regs::NV_PFALCON_FALCON_IRQSTAT, + ) -> regs::NV_PFALCON_FALCON_IRQSTAT { + let (mask, dest) =3D match self { + Self::Tu102 =3D> ( + pfalcon2.read(regs::tu102::NV_PRISCV_RISCV_IRQMASK).value(= ), + pfalcon2.read(regs::tu102::NV_PRISCV_RISCV_IRQDEST).value(= ), + ), + Self::Ga102 =3D> ( + pfalcon2.read(regs::ga102::NV_PRISCV_RISCV_IRQMASK).value(= ), + pfalcon2.read(regs::ga102::NV_PRISCV_RISCV_IRQDEST).value(= ), + ), + }; + + regs::NV_PFALCON_FALCON_IRQSTAT::from(latched.into_raw() & mask & = dest) + } +} + +/// Interrupt properties of a falcon that differ by GPU family. +/// +/// Separate from [`FalconHal`] because the GSP event handler calls these = from hard interrupt +/// context, where it cannot make the heap allocation that a `FalconHal` t= akes. +#[expect(dead_code)] +pub(crate) trait FalconIntrHal { + /// Returns whether these falcons implement `NV_PFALCON_FALCON_INTR_RE= TRIGGER`. + fn has_intr_retrigger(&self) -> bool; + + /// Returns the offsets of `PRISCV_RISCV_IRQMASK` and `PRISCV_RISCV_IR= QDEST`. + fn riscv_routing(&self) -> RiscvRouting; +} + +/// Returns the [`FalconIntrHal`] for `chipset`. +/// +/// GA100 has its own arm: it has the retrigger register, which Turing lac= ks, and the Turing +/// routing offsets, which GA102 moved. +#[expect(dead_code)] +pub(crate) fn falcon_intr_hal(chipset: Chipset) -> &'static dyn FalconIntr= Hal { + match chipset.arch() { + Architecture::Turing =3D> tu102::TU102_INTR_HAL, + Architecture::Ampere if chipset =3D=3D Chipset::GA100 =3D> tu102::= GA100_INTR_HAL, + Architecture::Ampere + | Architecture::Ada + | Architecture::Hopper + | Architecture::BlackwellGB10x + | Architecture::BlackwellGB20x =3D> ga102::GA102_INTR_HAL, + } +} + /// Returns a boxed falcon HAL adequate for `chipset`. /// /// We use a heap-allocated trait object instead of a statically defined o= ne because the diff --git a/drivers/gpu/nova-core/falcon/hal/ga102.rs b/drivers/gpu/nova-c= ore/falcon/hal/ga102.rs index f9a8444cf840..ff97983f22fe 100644 --- a/drivers/gpu/nova-core/falcon/hal/ga102.rs +++ b/drivers/gpu/nova-core/falcon/hal/ga102.rs @@ -28,7 +28,11 @@ regs, }; =20 -use super::FalconHal; +use super::{ + FalconHal, + FalconIntrHal, + RiscvRouting, // +}; =20 fn select_core_ga102(pfalcon2: Mmio<'_, PFalcon2Registers>) -> Result { let bcr_ctrl =3D pfalcon2.read(regs::NV_PRISCV_RISCV_BCR_CTRL); @@ -170,3 +174,18 @@ fn load_method(&self) -> LoadMethod { LoadMethod::Dma } } + +/// The falcon interrupt properties of GA102 and later. +struct Ga102Intr; + +impl FalconIntrHal for Ga102Intr { + fn has_intr_retrigger(&self) -> bool { + true + } + + fn riscv_routing(&self) -> RiscvRouting { + RiscvRouting::Ga102 + } +} + +pub(super) const GA102_INTR_HAL: &dyn FalconIntrHal =3D &Ga102Intr; diff --git a/drivers/gpu/nova-core/falcon/hal/tu102.rs b/drivers/gpu/nova-c= ore/falcon/hal/tu102.rs index 7fc6e83c2566..f79aa85e6a62 100644 --- a/drivers/gpu/nova-core/falcon/hal/tu102.rs +++ b/drivers/gpu/nova-core/falcon/hal/tu102.rs @@ -21,7 +21,11 @@ regs, // }; =20 -use super::FalconHal; +use super::{ + FalconHal, + FalconIntrHal, + RiscvRouting, // +}; =20 pub(super) struct Tu102(PhantomData); =20 @@ -80,3 +84,33 @@ fn load_method(&self) -> LoadMethod { LoadMethod::Pio } } + +/// The falcon interrupt properties of Turing. +struct Tu102Intr; + +impl FalconIntrHal for Tu102Intr { + fn has_intr_retrigger(&self) -> bool { + false + } + + fn riscv_routing(&self) -> RiscvRouting { + RiscvRouting::Tu102 + } +} + +pub(super) const TU102_INTR_HAL: &dyn FalconIntrHal =3D &Tu102Intr; + +/// GA100's falcon interrupt properties: the Turing routing offsets and th= e retrigger register. +struct Ga100Intr; + +impl FalconIntrHal for Ga100Intr { + fn has_intr_retrigger(&self) -> bool { + true + } + + fn riscv_routing(&self) -> RiscvRouting { + RiscvRouting::Tu102 + } +} + +pub(super) const GA100_INTR_HAL: &dyn FalconIntrHal =3D &Ga100Intr; diff --git a/drivers/gpu/nova-core/regs.rs b/drivers/gpu/nova-core/regs.rs index 9978fb2803b0..c6ba226dcfe3 100644 --- a/drivers/gpu/nova-core/regs.rs +++ b/drivers/gpu/nova-core/regs.rs @@ -124,11 +124,25 @@ pub(crate) fn usable_fb_size(self) -> u64 { register! { base: PFalconRegisters; =20 + /// Clears the latch of every cause whose bit is written as `1`. Write= -only. + /// + /// The write ends the latch and not the source, so a cause driven fro= m outside the falcon + /// stays set. "Retriggering a falcon" in `Documentation/gpu/nova/core= /interrupts.rst` names + /// those causes. pub(crate) NV_PFALCON_FALCON_IRQSCLR(u32) @ 0x00000004 { 6:6 swgen0 =3D> bool; 4:4 halt =3D> bool; } =20 + /// Interrupt causes latched in the falcon, one bit per cause, whichev= er target each is routed + /// to. + /// + /// The causes routed to the host are the ones also set in `NV_PRISCV_= RISCV_IRQMASK` and + /// `NV_PRISCV_RISCV_IRQDEST`. + pub(crate) NV_PFALCON_FALCON_IRQSTAT(u32) @ 0x00000008 { + 6:6 swgen0 =3D> bool; + } + pub(crate) NV_PFALCON_FALCON_MAILBOX0(u32) @ 0x00000040 { 31:0 value =3D> u32; } @@ -256,6 +270,16 @@ pub(crate) fn usable_fb_size(self) -> u64 { 0:0 reset =3D> bool; } =20 + /// Makes the falcon re-emit its host-routed causes into the interrupt= tree. Write-only. + /// + /// Present from GA100 on. See "Retriggering a falcon" in + /// `Documentation/gpu/nova/core/interrupts.rst`. + /// + /// The hardware headers declare two elements, and Open RM writes only= the first. + pub(crate) NV_PFALCON_FALCON_INTR_RETRIGGER(u32)[2] @ 0x000003e8 { + 0:0 trigger =3D> bool; + } + pub(crate) NV_PFALCON_FBIF_TRANSCFG(u32)[8] @ 0x00000600 { 2:2 mem_type =3D> FalconFbifMemType; 1:0 target ?=3D> FalconFbifTarget; @@ -414,6 +438,29 @@ pub(crate) mod gm107 { } } =20 +pub(crate) mod tu102 { + use kernel::io::register; + + use crate::falcon::PFalcon2Registers; + + // The RISC-V interrupt routing registers, at the offsets that Turing = and GA100 use. + + register! { + base: PFalcon2Registers; + + /// Enabled causes, one bit per cause. Read-only to the host. + pub(crate) NV_PRISCV_RISCV_IRQMASK(u32) @ 0x000002b4 { + 31:0 value =3D> u32; + } + + /// Causes routed to the host, one bit per cause. A clear bit rout= es the cause to the + /// RISC-V core. + pub(crate) NV_PRISCV_RISCV_IRQDEST(u32) @ 0x000002b8 { + 31:0 value =3D> u32; + } + } +} + pub(crate) mod ga100 { use kernel::io::register; =20 @@ -430,6 +477,28 @@ pub(crate) mod ga100 { } } =20 +pub(crate) mod ga102 { + use kernel::io::register; + + use crate::falcon::PFalcon2Registers; + + // The RISC-V interrupt routing registers, at the offsets that GA102 a= nd later use. + + register! { + base: PFalcon2Registers; + + /// Same as [`super::tu102::NV_PRISCV_RISCV_IRQMASK`], at the GA10= 2 offset. + pub(crate) NV_PRISCV_RISCV_IRQMASK(u32) @ 0x00000528 { + 31:0 value =3D> u32; + } + + /// Same as [`super::tu102::NV_PRISCV_RISCV_IRQDEST`], at the GA10= 2 offset. + pub(crate) NV_PRISCV_RISCV_IRQDEST(u32) @ 0x0000052c { + 31:0 value =3D> u32; + } + } +} + pub(crate) const NV_THERM_I2CS_SCRATCH_FSP_BOOT_COMPLETE_STATUS_SUCCESS: u= 32 =3D 0xff; =20 pub(crate) mod gh100 { --=20 2.55.0 From nobody Fri Sep 25 13:19:17 2026 Received: from SN4PR2101CU001.outbound.protection.outlook.com (mail-southcentralusazon11012058.outbound.protection.outlook.com [40.93.195.58]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id B9AEC3806C9 for ; Sat, 12 Sep 2026 04:44:41 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=fail smtp.client-ip=40.93.195.58 ARC-Seal: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1789188285; cv=fail; b=ZcnXWxZr0FAcRp+fzbD5zcaTS/jB7XvWqZoNYG+c2EC0aKXcgaJx9q5hUC4tm+hhX83SjAManN1q7snmW3llqNd1iujS8GbNCKhpl6WqTplZVQEQQO/mJ9VNElk0mhMBWpjcKScWrW1ALAKL55/KvwJp3PzY0Zlnzpc1pAFtBbM= ARC-Message-Signature: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1789188285; c=relaxed/simple; bh=o+GsA3oYh+ONmBwRn+/sUONCB9cg7kLmGRzi089Fuk4=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: Content-Type:MIME-Version; b=e9GGpINjCGmhJs94E4c/gENfrE1jLQxBDluMVkTf3wgLzwRhKOwCsij4DahqBrEf3aRfGxYjrveYjZ/hdOLV6LhET+IBKLnf708vjPJ4VssJ0Akce4TtzvzsIuZGuqrDIgQNtJam6uU6YX3ohp5nT2hYxX/3j5YTmn/bwWGTK5s= ARC-Authentication-Results: i=2; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=nvidia.com; spf=fail smtp.mailfrom=nvidia.com; dkim=pass (2048-bit key) header.d=Nvidia.com header.i=@Nvidia.com header.b=upt2t4ct; arc=fail smtp.client-ip=40.93.195.58 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=nvidia.com Authentication-Results: smtp.subspace.kernel.org; spf=fail smtp.mailfrom=nvidia.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=Nvidia.com header.i=@Nvidia.com header.b="upt2t4ct" ARC-Seal: i=1; a=rsa-sha256; s=arcselector10001; d=microsoft.com; cv=none; b=rKZBG67K/JIkrjFPr7ct29eT/FfxlBRKm+0PqEQTzOZJgcvm6MdAw9HnPuX3hLmeB8FEuBq3zkcfNo2G4dGCBtFNXGVtknp8yrDfK+xS+7iUBs/oLhCCqjSAHJqjvB+jBau8/xYDy+nQfdARHo6AaokVFCHrUKv8QB5KLXF5W20XamjkOYVftY6cpOUVSJ98nuJjEZkIJswqV0xfh2VC8qMBCqIzU1rfm5higRpImk4tCK6CO5t/51G8S03JePYm5xcOvDFcPjV5zxD3LOPWxucmHNjFIBxmDjQ1m+yhYlj9mc/pIKwZj0kCZbQThM/2E8BgiAkxqH4sVjASsw1/Sw== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=microsoft.com; s=arcselector10001; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-AntiSpam-MessageData-ChunkCount:X-MS-Exchange-AntiSpam-MessageData-0:X-MS-Exchange-AntiSpam-MessageData-1; bh=f6TOBXuwLLnQOT6UlYObEVbB5C/Y6mAIrB2weR/PR2I=; b=o7vgHjNSI/ahCnyhEEcIMEXM0Ba4wirkjv4iYf5sTunfks9mLfs0gmoarIxlSq4FJ+IHaLi/eocfygEcsJHC2ULN1WXuAnwe8QatYZnEwh90+35jFB+7yjw5OfO3eBnX2w3wjDT9ZVP4/841I7hOm2v7BP+hijsgAJFBEPFtovNOUHiML20Jh9hxIb8QWcucziX4vQiPPwmm3HiYDnza/bIcSQ8rHLvrWSdCMTxUk6l9SlEoEk0Yz5qiQF4K0cWw288+sxu4K6G9qdjlhpKeCRCLd1A8cM+Iw/XMKcBv8CTj1E9Bk0mfbJfJqB5pUzqKh0TIefRTPANlDj6aN+lRGg== ARC-Authentication-Results: i=1; mx.microsoft.com 1; spf=pass smtp.mailfrom=nvidia.com; dmarc=pass action=none header.from=nvidia.com; dkim=pass header.d=nvidia.com; arc=none DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=Nvidia.com; s=selector2; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck; bh=f6TOBXuwLLnQOT6UlYObEVbB5C/Y6mAIrB2weR/PR2I=; b=upt2t4cti9o4uwpOaS7jOQC2PxXuil84+CL/bwr+0a9/MjOJsc70eAaX9dkRKQkEgqjuThLJHEx/+V1kbvar5adS6b9K0tS96rJZw78MAy8JVZVsehhdlImqKMBeUqjRS8r+z16OmB3kD38e0ZoJPKRm2v0CaVwIeuUDJU3BMAuUIuNV9vKe+p45vBhwIqR84/wUWoMjgCqsAx8rMHh2c1BSd1+HAE5DGicolI2W74o4PFICSV8KRKfjmuPUOZemFjss7lSpyIBypyuGzM23SOwo69/uiRXQHflseYzsxBCsOy/zJmKzhq5HTJDSKFM+yOaIEVGUxiEBSZFFKube1w== Authentication-Results: dkim=none (message not signed) header.d=none;dmarc=none action=none header.from=nvidia.com; Received: from DM3PR12MB9416.namprd12.prod.outlook.com (2603:10b6:0:4b::8) by PH8PR12MB7229.namprd12.prod.outlook.com (2603:10b6:510:227::20) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.21.406.10; Sat, 12 Sep 2026 04:44:31 +0000 Received: from DM3PR12MB9416.namprd12.prod.outlook.com ([fe80::8cdd:504c:7d2a:59c8]) by DM3PR12MB9416.namprd12.prod.outlook.com ([fe80::8cdd:504c:7d2a:59c8%4]) with mapi id 15.21.0406.007; Sat, 12 Sep 2026 04:44:30 +0000 From: John Hubbard To: Danilo Krummrich , Alexandre Courbot Cc: Timur Tabi , Alistair Popple , Eliot Courtney , Zhi Wang , David Airlie , Simona Vetter , Bjorn Helgaas , Miguel Ojeda , Alex Gaynor , Boqun Feng , Gary Guo , =?UTF-8?q?Bj=C3=B6rn=20Roy=20Baron?= , Benno Lossin , Andreas Hindborg , Alice Ryhl , Trevor Gross , nova-gpu@lists.linux.dev, LKML , John Hubbard Subject: [PATCH v4 15/17] gpu: nova-core: service GSP events from the SWGEN0 interrupt Date: Fri, 11 Sep 2026 21:43:58 -0700 Message-ID: <20260912044400.677097-16-jhubbard@nvidia.com> X-Mailer: git-send-email 2.55.0 In-Reply-To: <20260912044400.677097-1-jhubbard@nvidia.com> References: <20260912044400.677097-1-jhubbard@nvidia.com> X-NVConfidentiality: public Content-Transfer-Encoding: quoted-printable X-ClientProxiedBy: SJ0PR03CA0288.namprd03.prod.outlook.com (2603:10b6:a03:39e::23) To DM3PR12MB9416.namprd12.prod.outlook.com (2603:10b6:0:4b::8) Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-MS-PublicTrafficType: Email X-MS-TrafficTypeDiagnostic: DM3PR12MB9416:EE_|PH8PR12MB7229:EE_ X-MS-Office365-Filtering-Correlation-Id: 54212a59-cca2-43f1-849e-08df108888be X-MS-Exchange-SenderADCheck: 1 X-MS-Exchange-AntiSpam-Relay: 0 X-Microsoft-Antispam: BCL:0;ARA:13230040|1800799024|7416014|376014|23010399003|366016|10067099003|7136999003|6133799003|3023799007|18002099003|11062099010|5023799004|11063799006|56012099006|22082099003; X-Microsoft-Antispam-Message-Info: wNtA+U+C1m9SG8DL1nL7v/N7oqbA5FiqscGX5j774LvX2jrRdZBhEOohuxIE8Pja6Ca/MTRhy9JnHxs6gv5j/w3lgInV1DNOVpQT2ArHE1PZHEmsj5s8aNbTPfJu0IwcKcWKGvoAdUAXsvnwb40Hrv5v4Q8b1n/MRhWVhwN5v/w0nnQ/GgLbmxlqkg8B7Qazir/lMWNBy2A3eEa8X+L4Vd41Ru1hW+sieDzqfhH/WhktD+JNpqaJHqGjOk92riQhf5lw5LJycmOqVffyZhmQ8U/v35rgoRWBNZqA0iv/C3goSOXcWKSQqj6W888aeXbGmKh3jQiqG1lD57Z9dzjlrpdX5YqzQt7NQm72xZWOI61HTvHJhXZnWj2kTV1rf2PV3oxGnM1BNv7ZYqqT0pL2rIyuuFM6UhWOK2vzHb6agvwb1Qa0zPm9d6YqqcOKwtioeJIlsDIiKGziEYW09X5ZPsytiG34Pa8UvVXLXttiwC0+ANf2KLV/Zl8g5920wpgFN2lo6X40qOzsOrjbC2g0ZUdlb+DBj3ut42gup1wE4x1bn9Zvyc3uZ0PMMqqJzkJ8mIiKV9rrsGr7Icqcqt4fj+cnQjVYQZSzpQ/tW1AsDyITw469s9rIx/cWs4e2B4qTwUw2XFGdBIx0hRTX9ix43YPgLKGB8/ZZMaOwfdx9Q3s= X-Forefront-Antispam-Report: CIP:255.255.255.255;CTRY:;LANG:en;SCL:1;SRV:;IPV:NLI;SFV:NSPM;H:DM3PR12MB9416.namprd12.prod.outlook.com;PTR:;CAT:NONE;SFS:(13230040)(1800799024)(7416014)(376014)(23010399003)(366016)(10067099003)(7136999003)(6133799003)(3023799007)(18002099003)(11062099010)(5023799004)(11063799006)(56012099006)(22082099003);DIR:OUT;SFP:1101; X-MS-Exchange-AntiSpam-MessageData-ChunkCount: 1 X-MS-Exchange-AntiSpam-MessageData-0: =?us-ascii?Q?Awn5rDE26uxPzGmVr1PMWjArwrjeg328TaP5lyJgu3cujTbCoq78N89i3gfi?= =?us-ascii?Q?AE8IWpjMJ8foge8n91AgUfx4N7Jm/PF/l1pMcUXePxkn4mtXU+PSvTHsFN70?= =?us-ascii?Q?/t8J5uBRDnrhOOaT9SrLRC08RRX4pVNsVpLt19uykxw3w28nZ6uFwNlEmv+F?= =?us-ascii?Q?C2rHS34Mj32FIu9c/bR/RXQE3L/KqsUbhi2NaO6rS+ZEfLNePVm2codoIM4t?= =?us-ascii?Q?vqCH3mTVSkV3O9hFh0Ida0rUBnGV44CXOdEjwbc8DsaGhn7MW+CE2jFKu9RB?= =?us-ascii?Q?ieM+1n0bNCxMRh/Vk/cFgr/wLov34a2Uf3RTItHZRYCiDoGOpHuVhCWrTGKy?= =?us-ascii?Q?GhAuKWpiQ2ZxCd3tMeff6uZNGnhLMycdaB5fcmlZHlGAUN4JF6US+Cp8kGVN?= =?us-ascii?Q?o6XVT1NhwhtoVCvcJNP/8afytl4pM8sJReDBOxXPo9xNGEUMJFvdiB3Q2q4/?= =?us-ascii?Q?t8pjp3MbZwEe0xPkb2xb2ShnyBIC4G1amSfpCKzpkWwQPD96ANGxPu2VfcF7?= =?us-ascii?Q?5wGLcu7ZFYGNUQzvfxkM5Mpv4eVEj5azR5NjiDVe/DQdJss7Ntyik1anwJCX?= =?us-ascii?Q?ah+Eleg1NK6/yQdGBdrlwRKNo2dx6jmkXxUMsblW6zTDSuseAFh/npv/tZyq?= =?us-ascii?Q?FInOPmJauedAv74Ynb2/As505ZXtv3GqDfWEF5naY5Wlri06N7/5LODzJGsn?= =?us-ascii?Q?HzfCAveOrE/Y2qxCiBRePSfiCPqPtMouoFEser/C/aWBZCSSUIOydcQuL9gf?= =?us-ascii?Q?UKQ5oKJA63ibYThO/TxFSFKXQA6YOWufbyWE/4eByXxNICjVG419jlFh5vhz?= =?us-ascii?Q?BTIomDvb25UdhYltj8CmtZWkiEJZkQBGcbVp0d2YffssQJozQCLaGVOysb8B?= =?us-ascii?Q?vvM1bvgxxMcUkYXwlUh4Z9YUA1UsTjiPmMuuBa9BMjgfEy6GQ9giP1Twb1fN?= =?us-ascii?Q?UvRiqJeFG2/YHLpPLLrNu1+M6uWgSZUgOKOGfPkP6sCxw0T1zsWDOhclOkjw?= =?us-ascii?Q?cSsE4BBImR9FVDEJwbypXl/sX5j/SGlidfA9eGibiy4oiMv1x3ag/ZuOKvhR?= =?us-ascii?Q?U9OtvIiLRjvk0zjFGYJZJE79KCnDSNuBEa37XVHqOVp7h33Gv/JgFzlE2ycz?= =?us-ascii?Q?0kx8BZVZz5kqcFmOKgBqVwDKrTARD2t9AjwNI3skFkHUcX9gDDjf6Rs7gxD8?= =?us-ascii?Q?VsVQKpWISB+g6Bnuyq4ITXPi95YOrCNJJNndQcWf9qzDnVB7RwWe+obnH/04?= =?us-ascii?Q?z3yA85uFMrKWXh7O2RiiXVrWces6sNfRKiI2RcDeB3fomlLBasanppCZUahJ?= =?us-ascii?Q?wqynCZW4/9PGhbLPyf++YH77fQDc7tlCO7XW2UhxgX8Y2Afz6/P3DMon2GuP?= =?us-ascii?Q?Q0gDw4XrR2Ik4HQ7wQUp0+Bu/hwhp+h0CsPfyZTRRIOLr/kKuohK/KaQ2n+Y?= =?us-ascii?Q?9a9CMuahBZo0BbZzvv2K1noibbOYMZXKdE0jXHE51nK2NhRt7iHlGy4aXqqv?= =?us-ascii?Q?izZ++Av6CaRwFksveHzILZKNhg93mT9S1UCw7SQRGU7GKjwfkjlycJPgMk9A?= =?us-ascii?Q?LfIxYNjxW+xyaAT1FQ2Q6iGLZshvW47xu8vTp7JpHQ3VXWA8+tB8gWaRX49L?= =?us-ascii?Q?4YqMRwtvZJnM6w3bi8TCS6ndKlWM7fwsmadNZDbA2BapHpL4Q6pqMf/wcTE3?= =?us-ascii?Q?yJ+u2Nmlm0LJDcZ/w4SqIn0Y7Kww9ZvyWioNMOM7R4R48NJzkTiUO3mX3e6s?= =?us-ascii?Q?h8Uk6/Mbhw=3D=3D?= X-OriginatorOrg: Nvidia.com X-MS-Exchange-CrossTenant-Network-Message-Id: 54212a59-cca2-43f1-849e-08df108888be X-MS-Exchange-CrossTenant-AuthSource: DM3PR12MB9416.namprd12.prod.outlook.com X-MS-Exchange-CrossTenant-AuthAs: Internal X-MS-Exchange-CrossTenant-OriginalArrivalTime: 12 Sep 2026 04:44:30.7811 (UTC) X-MS-Exchange-CrossTenant-FromEntityHeader: Hosted X-MS-Exchange-CrossTenant-Id: 43083d15-7273-40c1-b7db-39efd9ccc17a X-MS-Exchange-CrossTenant-MailboxType: HOSTED X-MS-Exchange-CrossTenant-UserPrincipalName: 1xCOUMioG3qx9YjEzHsndNib50birEZA8Qz31EB+szArnedzIa5aABBjNjn6zWadYO554r3eFGme8PPv+RHTyA== X-MS-Exchange-Transport-CrossTenantHeadersStamped: PH8PR12MB7229 Content-Type: text/plain; charset="utf-8" When the GSP has something for the CPU, it posts a message to the GSP-to-CPU queue and raises SWGEN0, a software-generated interrupt cause of its falcon. SWGEN0 is routed to the host and reaches the CPU on GIN vector 155. It is a latch: while it stays set, the GSP cannot signal the tree again. GSP boot consumes the GSP's notifications by polling the queue, so it leaves the latch set and pending bits behind in the tree. nova-core read the queue only while a caller was waiting for a command reply, so an event posted between commands sat unread until the next command was sent. Register a threaded handler on the GSP vector. The top half runs in hard interrupt context and touches only registers: * Read the GSP vector's leaf and clear its bit, leaving any other vector in the leaf pending. * Read the falcon causes routed to the host, and clear the SWGEN0 latch if it is set. * Clear the latch of every other host cause, then retrigger the falcon or disable the vector, as described below. * Rearm PCI interrupt delivery. Draining the queue takes the command-queue mutex, which can sleep, and walks shared memory, so the top half leaves it to the IRQ thread and wakes the thread when SWGEN0 was set. A host cause other than SWGEN0 reports a GSP fault. IRQSCLR clears a cause's latch but cannot end the source behind it, and on Blackwell the fault-containment and ECC causes are driven from outside the falcon, so they stay set through the write. A retrigger would then re-emit them at once, and the CPU would take the same interrupt again and again. So after clearing the fault latches, read the host causes back. If the clear ended every one of them, retrigger the falcon, so that a cause latched in the meantime still signals the tree. If a cause is still set, disable the GSP vector at its leaf instead and log that the device needs a reset. Disabling loses nothing: while a cause stays set, the falcon signals nothing further either way. Make the handler registration one of the GPU's resources, rather than something probe registers, so that it drops before the command queue the handler drains is freed and before the GSP is unloaded. Before registering, quiesce the tree and clear the SWGEN0 latch, so nothing left over from boot reaches a handler that services one vector and cannot service any other. The quiesce leaves the GSP subtree disabled at TOP, and the pre-Hopper MSI rearm is a configuration-space write that does not enable it again, so enable the subtree explicitly. Keep it enabled for as long as the handler is registered, and disable it only after the handler is freed, since a handler still in flight would enable it again through its rearm. Once the handler is in place, drain the queue once: a message posted before the latch was cleared produced no interrupt. Assisted-by: LLM Signed-off-by: John Hubbard --- drivers/gpu/nova-core/falcon/gsp.rs | 73 +++++- drivers/gpu/nova-core/falcon/hal.rs | 4 - drivers/gpu/nova-core/gpu.rs | 57 ++++- drivers/gpu/nova-core/gsp.rs | 2 +- drivers/gpu/nova-core/gsp/cmdq.rs | 1 - drivers/gpu/nova-core/irq.rs | 43 +++- drivers/gpu/nova-core/irq/gsp.rs | 236 ++++++++++++++++++++ drivers/gpu/nova-core/irq/interrupt_tree.rs | 4 +- drivers/gpu/nova-core/nova_core.rs | 1 - 9 files changed, 399 insertions(+), 22 deletions(-) create mode 100644 drivers/gpu/nova-core/irq/gsp.rs diff --git a/drivers/gpu/nova-core/falcon/gsp.rs b/drivers/gpu/nova-core/fa= lcon/gsp.rs index 4c96ae325fda..dfa08bc6867c 100644 --- a/drivers/gpu/nova-core/falcon/gsp.rs +++ b/drivers/gpu/nova-core/falcon/gsp.rs @@ -5,6 +5,7 @@ io_project, poll::read_poll_timeout, register, + register::Array, Io, Mmio, // }, @@ -18,9 +19,11 @@ NovaRegisters, // }, falcon::{ + hal, Falcon, FalconEngine, // }, + gpu::Chipset, regs, }; =20 @@ -46,14 +49,72 @@ fn pfalcon2(io: Bar0<'_>) -> Mmio<'_, super::PFalcon2Re= gisters> { } } =20 -impl<'a> Falcon<'a, Gsp> { - /// Clears the SWGEN0 bit in the Falcon's IRQ status clear register to - /// allow GSP to signal CPU for processing new messages in message que= ue. - pub(crate) fn clear_swgen0_intr(&self) { - self.pfalcon - .write_reg(regs::NV_PFALCON_FALCON_IRQSCLR::zeroed().with_swge= n0(true)); +impl Gsp { + /// Clears the SWGEN0 latch in the GSP falcon. + /// + /// While the latch is set, no later message signals the tree, so a ca= ller that consumed a + /// notification by polling must clear it. + pub(crate) fn clear_swgen0_intr(bar: Bar0<'_>) { + Self::pfalcon(bar).write_reg(regs::NV_PFALCON_FALCON_IRQSCLR::zero= ed().with_swgen0(true)); + } + + /// Reads the GSP falcon causes that are routed to the host, without c= learing any latch. + /// + /// Every one of them other than SWGEN0 reports a GSP fault. + pub(crate) fn read_host_intr( + bar: Bar0<'_>, + chipset: Chipset, + ) -> regs::NV_PFALCON_FALCON_IRQSTAT { + let latched =3D Self::pfalcon(bar).read(regs::NV_PFALCON_FALCON_IR= QSTAT); + + hal::falcon_intr_hal(chipset) + .riscv_routing() + .host_routed_causes(Self::pfalcon2(bar), latched) + } + + /// Reads the host-routed causes and clears the SWGEN0 latch if it was= set. + /// + /// Returns the causes as read, before the clear. No other latch chang= es. + pub(crate) fn take_host_intr( + bar: Bar0<'_>, + chipset: Chipset, + ) -> regs::NV_PFALCON_FALCON_IRQSTAT { + let status =3D Self::read_host_intr(bar, chipset); + + if status.swgen0() { + Self::clear_swgen0_intr(bar); + } + + status + } + + /// Clears the latch of every interrupt cause set in `status`. + /// + /// A cause driven from outside the falcon is still set on return, and + /// [`Self::read_host_intr`] reports the causes that remain. + pub(crate) fn clear_intr(bar: Bar0<'_>, status: regs::NV_PFALCON_FALCO= N_IRQSTAT) { + Self::pfalcon(bar).write_reg(regs::NV_PFALCON_FALCON_IRQSCLR::from= (status.into_raw())); + } + + /// Retriggers the GSP falcon, which then re-emits its host-routed cau= ses into the tree. + /// + /// Call this only once every host cause is clear. A cause still set i= s re-emitted at once, and + /// its vector arrives again as soon as delivery is rearmed. + /// + /// Does nothing on Turing, whose falcons have no retrigger register. + pub(crate) fn retrigger_intr(bar: Bar0<'_>, chipset: Chipset) { + if !hal::falcon_intr_hal(chipset).has_intr_retrigger() { + return; + } + + Self::pfalcon(bar).write( + Array::at(0), + regs::NV_PFALCON_FALCON_INTR_RETRIGGER::zeroed().with_trigger(= true), + ); } +} =20 +impl<'a> Falcon<'a, Gsp> { /// Checks if GSP reload/resume has completed during the boot process. pub(crate) fn check_reload_completed(&self, timeout: Delta) -> Result<= bool> { read_poll_timeout( diff --git a/drivers/gpu/nova-core/falcon/hal.rs b/drivers/gpu/nova-core/fa= lcon/hal.rs index 052610c4a4da..3f1f509eccbd 100644 --- a/drivers/gpu/nova-core/falcon/hal.rs +++ b/drivers/gpu/nova-core/falcon/hal.rs @@ -82,7 +82,6 @@ fn signature_reg_fuse_version( =20 /// Offsets of a falcon's RISC-V interrupt routing registers. #[derive(Clone, Copy, Debug, Eq, PartialEq)] -#[expect(dead_code)] pub(crate) enum RiscvRouting { /// The Turing offsets. GA100 uses them too. Tu102, @@ -97,7 +96,6 @@ impl RiscvRouting { /// /// The causes routed to the core belong to the firmware running on it= , and the host does not /// service them. - #[expect(dead_code)] pub(crate) fn host_routed_causes( self, pfalcon2: Mmio<'_, PFalcon2Registers>, @@ -122,7 +120,6 @@ pub(crate) fn host_routed_causes( /// /// Separate from [`FalconHal`] because the GSP event handler calls these = from hard interrupt /// context, where it cannot make the heap allocation that a `FalconHal` t= akes. -#[expect(dead_code)] pub(crate) trait FalconIntrHal { /// Returns whether these falcons implement `NV_PFALCON_FALCON_INTR_RE= TRIGGER`. fn has_intr_retrigger(&self) -> bool; @@ -135,7 +132,6 @@ pub(crate) trait FalconIntrHal { /// /// GA100 has its own arm: it has the retrigger register, which Turing lac= ks, and the Turing /// routing offsets, which GA102 moved. -#[expect(dead_code)] pub(crate) fn falcon_intr_hal(chipset: Chipset) -> &'static dyn FalconIntr= Hal { match chipset.arch() { Architecture::Turing =3D> tu102::TU102_INTR_HAL, diff --git a/drivers/gpu/nova-core/gpu.rs b/drivers/gpu/nova-core/gpu.rs index 3d796d6c7013..d1e0da7b8682 100644 --- a/drivers/gpu/nova-core/gpu.rs +++ b/drivers/gpu/nova-core/gpu.rs @@ -38,6 +38,11 @@ Gsp, GspBootContext, // }, + irq::{ + self, + gsp::GspIrq, + SubtreeVectors, // + }, mm::{ bar_user::BarUser, pagetable::MmuVersion, @@ -301,6 +306,13 @@ struct GspResources<'gpu> { #[pin_data] pub(crate) struct Gpu<'gpu> { spec: Spec, + /// GSP event interrupt registration. + /// + /// Must be kept declared *before* `gsp_resources`, so that the handle= r is unregistered, and + /// any in-flight run of it has finished, before the command queue it = drains is freed and + /// before the GSP is unloaded. + #[pin] + _gsp_irq: GspIrq<'gpu>, /// Static GPU information as provided by the GSP. gsp_static_info: GetGspStaticInfoReply, /// GPU memory manager owning memory management resources. @@ -319,6 +331,14 @@ pub(crate) struct Gpu<'gpu> { /// Must be kept declared *after* `gsp_resources`, as the latter's `Pi= nnedDrop` implementation /// requires the sysmem flush page to be in place. sysmem_flush: SysmemFlush<'gpu>, + /// Borrow of `vectors` that `_gsp_irq` holds. A field that borrows a = sibling field is + /// self-referential, which `pin_init` cannot express, so the borrow i= s taken by hand. + vectors_ref: &'gpu SubtreeVectors<'gpu>, + /// PCI interrupt vector allocation. + /// + /// Must be kept declared *after* `_gsp_irq`, which holds a borrow of = it. + #[pin] + vectors: SubtreeVectors<'gpu>, } =20 #[pinned_drop] @@ -358,6 +378,12 @@ pub(crate) fn new<'a>( let dev =3D pdev.as_ref(); =20 try_pin_init!(Self { + vectors: irq::alloc_vectors(pdev, irq::gsp::GSP_SUBTREE.into()= )?, + + // SAFETY: `vectors` is initialized above, is pinned at a stab= le address, and is + // dropped after every field that uses `vectors_ref` (struct f= ield drop order). + vectors_ref: unsafe { &*core::ptr::from_ref(vectors.as_ref().g= et_ref()) }, + spec: Spec::new(dev, bar).inspect(|spec| { dev_info!(dev,"NVIDIA ({})\n", spec); })?, @@ -380,12 +406,7 @@ pub(crate) fn new<'a>( =20 bar, =20 - gsp_falcon: Falcon::new( - dev, - spec.chipset, - bar - ) - .inspect(|falcon| falcon.clear_swgen0_intr())?, + gsp_falcon: Falcon::new(dev, spec.chipset, bar)?, =20 sec2_falcon: Falcon::new(dev, spec.chipset, bar)?, =20 @@ -409,6 +430,30 @@ pub(crate) fn new<'a>( })?, }), =20 + _: { + irq::gsp::quiesce(bar, gsp_resources.spec.chipset, vectors= _ref)?; + }, + + // SAFETY: the command queue is a field of `gsp_resources`, wh= ich is initialized + // above and pinned, so the reference outlives the registratio= n. The registration is + // a field of `Gpu` and is never leaked, so its `Drop` runs, a= nd field drop order + // runs it before the queue is freed. + _gsp_irq <- unsafe { + GspIrq::new( + pdev, + vectors_ref, + bar, + &*core::ptr::from_ref(&gsp_resources.gsp.cmdq), + gsp_resources.spec.chipset, + ) + }, + + // No interrupt announces the messages that the GSP posted dur= ing boot, before the + // SWGEN0 latch was cleared. + _: { + gsp_resources.gsp.cmdq.drain()?; + }, + gsp_static_info: { // Obtain and display basic GPU information. let info =3D gsp_resources.gsp.get_static_info(bar)?; diff --git a/drivers/gpu/nova-core/gsp.rs b/drivers/gpu/nova-core/gsp.rs index 25ea43f1cbe9..fcfb4210d435 100644 --- a/drivers/gpu/nova-core/gsp.rs +++ b/drivers/gpu/nova-core/gsp.rs @@ -152,7 +152,7 @@ pub(crate) struct Gsp<'gsp> { /// Log buffers, optionally exposed via debugfs. #[pin] logs: debugfs::Scope>, - /// Command queue. + /// Command queue, borrowed by the GSP event interrupt handler. #[pin] pub(crate) cmdq: Cmdq<'gsp>, /// RM arguments. diff --git a/drivers/gpu/nova-core/gsp/cmdq.rs b/drivers/gpu/nova-core/gsp/= cmdq.rs index acee444e898d..f1231569aa33 100644 --- a/drivers/gpu/nova-core/gsp/cmdq.rs +++ b/drivers/gpu/nova-core/gsp/cmdq.rs @@ -643,7 +643,6 @@ pub(crate) fn await_msg(&self) -> Re= sult /// # Errors /// /// `EIO` if the queue is poisoned, or if a message fails framing or c= hecksum validation. - #[expect(dead_code)] pub(crate) fn drain(&self) -> Result { self.inner.lock().drain() } diff --git a/drivers/gpu/nova-core/irq.rs b/drivers/gpu/nova-core/irq.rs index 7fb7d9f2e237..cafcc613770a 100644 --- a/drivers/gpu/nova-core/irq.rs +++ b/drivers/gpu/nova-core/irq.rs @@ -11,6 +11,7 @@ =20 #[cfg(CONFIG_NOVA_CORE_SELFTESTS)] pub(crate) mod doorbell_test; +pub(crate) mod gsp; mod hal; mod interrupt_tree; mod regs; @@ -25,11 +26,16 @@ prelude::*, // }; =20 -use crate::num; +use crate::{ + driver::Bar0, + gpu::Chipset, + num, // +}; =20 use interrupt_tree::{ Subtree, - SubtreeSet, // + SubtreeSet, + Tree, // }; =20 /// The message-signaled interrupt type that Linux granted. @@ -56,6 +62,39 @@ pub(crate) struct SubtreeVectors<'a> { } =20 impl SubtreeVectors<'_> { + /// Returns the tree of `chipset`, covering the serviced subtrees. + /// + /// # Errors + /// + /// `EINVAL` if `chipset` does not implement every serviced subtree. + fn tree<'b>(&self, bar: Bar0<'b>, chipset: Chipset) -> Result= > { + Tree::new(bar, chipset, self) + } + + /// Disables every vector in the tree, clears every pending bit, and r= earms PCI interrupt + /// delivery. + /// + /// On return, the serviced subtrees are enabled at `TOP` under a `TOP= ` rearm method and + /// disabled under the configuration-space one. A caller that needs de= livery enables them + /// itself. + /// + /// Call this only during probe, with no interrupt handler registered. + /// + /// # Errors + /// + /// `EINVAL` if `chipset` does not implement every serviced subtree. + pub(crate) fn reset_tree(&self, bar: Bar0<'_>, chipset: Chipset) -> Re= sult { + let tree =3D self.tree(bar, chipset)?; + + tree.disable_all_leaves(); + tree.drain(); + for subtree in self.serviced.iter() { + tree.rearm_pci_irq(subtree); + } + + Ok(()) + } + /// Returns the [`irq::IrqRequest`] for the PCI vector that delivers `= subtree`. /// /// # Errors diff --git a/drivers/gpu/nova-core/irq/gsp.rs b/drivers/gpu/nova-core/irq/g= sp.rs new file mode 100644 index 000000000000..8996f4215e40 --- /dev/null +++ b/drivers/gpu/nova-core/irq/gsp.rs @@ -0,0 +1,236 @@ +// SPDX-License-Identifier: GPL-2.0 +// SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIA= TES. All rights reserved. + +//! The GSP event interrupt. +//! +//! The GSP posts messages to the GSP-to-CPU queue and raises SWGEN0, a so= ftware-generated cause +//! of its falcon. A threaded handler services it: the top half clears the= tree and falcon state, +//! and the IRQ thread drains the queue. +//! +//! See "The GSP event" in `Documentation/gpu/nova/core/interrupts.rst`. + +use kernel::{ + device, + irq, + pci, + prelude::*, // +}; + +use super::{ + interrupt_tree::{ + GinVector, + LeafEnableGuard, + Subtree, + TopEnableGuard, + Tree, // + }, + SubtreeVectors, // +}; +use crate::{ + driver::Bar0, + falcon::gsp::Gsp as GspFalcon, + gpu::Chipset, + gsp::cmdq::Cmdq, + regs, // +}; + +/// The GSP event vector, which has the same number on every supported GPU. +const GSP_INTR_0_VECTOR: GinVector =3D GinVector::new::<155>(); + +/// The GSP event's subtree, the only one that nova-core services. +pub(crate) const GSP_SUBTREE: Subtree =3D GSP_INTR_0_VECTOR.subtree(); + +/// Clears the tree and falcon interrupt state that GSP boot leaves behind= , and rearms PCI +/// interrupt delivery. +/// +/// On return, no vector is enabled at its leaf and the SWGEN0 latch is cl= ear, so the next message +/// that the GSP posts signals the tree. +/// +/// # Errors +/// +/// `EINVAL` if `chipset` does not implement every subtree that `vectors` = services. +pub(crate) fn quiesce(bar: Bar0<'_>, chipset: Chipset, vectors: &SubtreeVe= ctors<'_>) -> Result { + vectors.reset_tree(bar, chipset)?; + // The latch is cleared after the tree reset. The other order can leav= e the latch set with its + // leaf bit cleared. See "Enabling the GSP event" in interrupts.rst. + GspFalcon::clear_swgen0_intr(bar); + + Ok(()) +} + +/// Threaded IRQ handler for the GSP event. +pub(crate) struct GspInterrupt<'a> { + /// For the GSP falcon's registers. The tree holds its own copy. + bar: Bar0<'a>, + cmdq: &'a Cmdq<'a>, + tree: Tree<'a>, + /// Selects the falcon's retrigger and routing registers, which differ= by family. + chipset: Chipset, + /// For logging. The command queue's device reference is behind its mu= tex, which the top half + /// cannot take. + dev: &'a device::Device, +} + +impl<'a> GspInterrupt<'a> { + fn new( + bar: Bar0<'a>, + cmdq: &'a Cmdq<'a>, + tree: Tree<'a>, + chipset: Chipset, + dev: &'a device::Device, + ) -> Self { + Self { + bar, + cmdq, + tree, + chipset, + dev, + } + } + + /// Clears the latch of every host-routed cause in `status` other than= SWGEN0, and logs them. + /// + /// Returns the causes still set after the clear. A cause driven from = outside the falcon stays + /// set, and only a device reset ends it. + fn clear_faults( + &self, + status: regs::NV_PFALCON_FALCON_IRQSTAT, + ) -> regs::NV_PFALCON_FALCON_IRQSTAT { + let faults =3D status.with_swgen0(false); + if faults.into_raw() =3D=3D 0 { + return faults; + } + + dev_err!( + &self.dev, + "unserviceable GSP falcon interrupt, IRQSTAT {:#x}\n", + status.into_raw() + ); + GspFalcon::clear_intr(self.bar, faults); + + GspFalcon::read_host_intr(self.bar, self.chipset).with_swgen0(fals= e) + } +} + +impl irq::ThreadedHandler for GspInterrupt<'_> { + /// Top half, in hard interrupt context. Services the GSP vector only,= so another vector + /// pending in the same leaf stays pending. + fn handle(&self) -> irq::ThreadedIrqReturn { + let bar =3D self.bar; + + let leaf =3D self.tree.read_pending(GSP_INTR_0_VECTOR.leaf_index()= ); + if !leaf.vectors().contains(GSP_INTR_0_VECTOR.leaf_mask()) { + self.tree.rearm_pci_irq(GSP_SUBTREE); + return irq::ThreadedIrqReturn::None; + } + leaf.clear_vectors(GSP_INTR_0_VECTOR.leaf_mask()); + + let status =3D GspFalcon::take_host_intr(bar, self.chipset); + + let remaining_faults =3D self.clear_faults(status); + if remaining_faults.into_raw() =3D=3D 0 { + GspFalcon::retrigger_intr(bar, self.chipset); + } else { + // Disabling the vector loses no notification: the falcon sign= als nothing further + // while a cause stays set. See "Retriggering a falcon" in int= errupts.rst. + self.tree.disable_leaf( + GSP_INTR_0_VECTOR.leaf_index(), + GSP_INTR_0_VECTOR.leaf_mask(), + ); + dev_err!( + &self.dev, + "GSP falcon cause {:#x} needs a device reset, GSP events a= re no longer serviced\n", + remaining_faults.into_raw() + ); + } + + self.tree.rearm_pci_irq(GSP_SUBTREE); + + if status.swgen0() { + irq::ThreadedIrqReturn::WakeThread + } else { + irq::ThreadedIrqReturn::Handled + } + } + + /// IRQ thread. Drains the GSP-to-CPU queue, which may sleep. + fn handle_threaded(&self) -> irq::IrqReturn { + if let Err(e) =3D self.cmdq.drain() { + // A poisoned queue fails every later drain the same way. + self.tree.disable_leaf( + GSP_INTR_0_VECTOR.leaf_index(), + GSP_INTR_0_VECTOR.leaf_mask(), + ); + dev_err!( + &self.dev, + "GSP event drain failed ({:?}), the message queue is no lo= nger serviced\n", + e + ); + } + irq::IrqReturn::Handled + } +} + +/// The registered GSP event handler and the enables that deliver to it. +/// +/// The declaration order is the drop order, and it is required: the vecto= r is disabled first, +/// `free_irq` runs second, and the subtree is disabled last. See "Enablin= g the GSP event" in +/// `Documentation/gpu/nova/core/interrupts.rst`. +#[pin_data] +pub(crate) struct GspIrq<'a> { + _leaf_guard: LeafEnableGuard<'a>, + #[pin] + reg: irq::ThreadedRegistration<'a, GspInterrupt<'a>>, + _top_guard: TopEnableGuard<'a>, +} + +impl<'a> GspIrq<'a> { + /// Returns an initializer that registers the threaded handler and the= n enables the GSP + /// subtree at `TOP` and the GSP vector at its leaf. + /// + /// An event that latched while the vector was disabled is delivered a= s soon as the vector is + /// enabled. + /// + /// # Errors + /// + /// `EINVAL` if `vectors` does not service the GSP subtree, or if `chi= pset` does not implement + /// every subtree that `vectors` services. Otherwise the error from `r= equest_threaded_irq`. + /// + /// # Safety + /// + /// Callers must not `mem::forget()` the initialized `GspIrq` or other= wise prevent its [`Drop`] + /// implementation, which runs `free_irq`, from running. + pub(crate) unsafe fn new( + pdev: &'a pci::Device, + vectors: &'a SubtreeVectors<'a>, + bar: Bar0<'a>, + cmdq: &'a Cmdq<'a>, + chipset: Chipset, + ) -> impl PinInit + 'a { + let dev =3D pdev.as_ref(); + + try_pin_init!(Self { + // SAFETY: this function's caller must not leak the `GspIrq` t= hat owns this + // registration, so the registration's `Drop` runs. + reg <- unsafe { + irq::ThreadedRegistration::new( + vectors.request_for(GSP_SUBTREE)?, + irq::Flags::TRIGGER_NONE, + c"nova-core", + Ok(GspInterrupt::new( + bar, + cmdq, + vectors.tree(bar, chipset)?, + chipset, + dev, + )), + ) + }, + _top_guard: reg.handler().tree.enable_top_guarded(), + _leaf_guard: reg.handler().tree.enable_leaf_guarded( + GSP_INTR_0_VECTOR.leaf_index(), + GSP_INTR_0_VECTOR.leaf_mask(), + ), + }) + } +} diff --git a/drivers/gpu/nova-core/irq/interrupt_tree.rs b/drivers/gpu/nova= -core/irq/interrupt_tree.rs index f77920a3b30a..eae1a1d4b933 100644 --- a/drivers/gpu/nova-core/irq/interrupt_tree.rs +++ b/drivers/gpu/nova-core/irq/interrupt_tree.rs @@ -117,10 +117,12 @@ pub(super) const fn all() -> Self { Self(u32::MAX) } =20 + #[cfg_attr(not(CONFIG_NOVA_CORE_SELFTESTS), expect(dead_code))] pub(super) const fn from_raw(raw: u32) -> Self { Self(raw) } =20 + #[cfg_attr(not(CONFIG_NOVA_CORE_SELFTESTS), expect(dead_code))] pub(super) const fn into_raw(self) -> u32 { self.0 } @@ -196,7 +198,6 @@ pub(super) const fn span(self) -> u32 { } =20 /// Returns the subtrees of this set, lowest index first. - #[expect(dead_code)] pub(super) fn iter(self) -> impl Iterator { (0..u32::BITS) .map(Subtree::new) @@ -234,6 +235,7 @@ pub(super) const fn new() -> Self { Self(Bounded::::new::()) } =20 + #[cfg_attr(not(CONFIG_NOVA_CORE_SELFTESTS), expect(dead_code))] pub(super) const fn into_raw(self) -> u32 { self.0.get() } diff --git a/drivers/gpu/nova-core/nova_core.rs b/drivers/gpu/nova-core/nov= a_core.rs index abafe4f2968d..cbaef6d3d9f1 100644 --- a/drivers/gpu/nova-core/nova_core.rs +++ b/drivers/gpu/nova-core/nova_core.rs @@ -17,7 +17,6 @@ mod fsp; mod gpu; mod gsp; -#[cfg_attr(not(CONFIG_NOVA_CORE_SELFTESTS), expect(dead_code))] mod irq; mod mctp; mod mm; --=20 2.55.0 From nobody Fri Sep 25 13:19:17 2026 Received: from BYAPR05CU005.outbound.protection.outlook.com (mail-westusazon11010052.outbound.protection.outlook.com [52.101.85.52]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 2EF1E38E8B9 for ; Sat, 12 Sep 2026 04:44:39 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=fail smtp.client-ip=52.101.85.52 ARC-Seal: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1789188282; cv=fail; b=UIZEwz/GZVx109KtKjqJ9/wdwvybo2ZpZwPAa4kx5jwhZj+rmkg+A+CPn/Iko95osUi6Ck00wdwdslIDDfsqIAJ/nX/we9eKCgl6jOG/4iNT9qopnGklbiKY1q0BcCftNO0kF9dG9K6Yozm+iPHD4bxzMGjoebMFG8PYVf8UGjA= ARC-Message-Signature: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1789188282; c=relaxed/simple; bh=DIy25/b2/wnur/yt33Wq6vHne3nNQyI9BEBRTr587NE=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: Content-Type:MIME-Version; b=ht+zyP0ks+II8dMZNTHR3EdtzqipLTxfCJqi9sL6dGNXE/K9eenozuBcpjAudF9tc5d8OgnUFAUvN1Xdq1tmGEQv8gXzFTbMOlLlVxCz2pzbeW7VOWUzP5K5eZoHJWqrwqmlTOTSX/4VDAI/KgJzj9MwFRBjZSK2MbrR0211lw8= ARC-Authentication-Results: i=2; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=nvidia.com; spf=fail smtp.mailfrom=nvidia.com; dkim=pass (2048-bit key) header.d=Nvidia.com header.i=@Nvidia.com header.b=Dz5ENJ3U; arc=fail smtp.client-ip=52.101.85.52 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=nvidia.com Authentication-Results: smtp.subspace.kernel.org; spf=fail smtp.mailfrom=nvidia.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=Nvidia.com header.i=@Nvidia.com header.b="Dz5ENJ3U" ARC-Seal: i=1; a=rsa-sha256; s=arcselector10001; d=microsoft.com; cv=none; b=rkJ2lhnYVt9JbSigYUxX12Cq1U4XaoFUy519YmPS7zlI+D6mm6zmI20hX3RUmd8MpeKus69BGdYdAMI1Y4vdCwRCCwTgCfZLCFTLtTM/1ug8FuqITudmjgUOQ8BgrIoT4BSivgidvMf1ZuuU10XLDrdUWvmpPyqLxaPkSnLqU/wgXKWd+/al8SG9dMq5narQLWqtGNMCNCP3Qja6QPpZeWWsRZiLdIoJ43YgVHczNme/0a7OZbZJRWHfJ+w0u0ARhXKO4FODvvhHAe/qABB4aUm4++6F1BP+h8Snzp1Djkshjy4lMPf+VvWx1HhtQXk7scOKgPKWuEwvqW21M+FY9g== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=microsoft.com; s=arcselector10001; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-AntiSpam-MessageData-ChunkCount:X-MS-Exchange-AntiSpam-MessageData-0:X-MS-Exchange-AntiSpam-MessageData-1; bh=dv7/7+9hTIe95WgqSRK8NGJCl639mvRp2nzqcSFDqZM=; b=uJ9SNM/mxZJ2+mco9gND7XD6VDVInvP5G5FBEGLCzMCYLzGATwXVJl3yySHtBTjB65R6I+sqkTc/jQUApaWSFES3SoeaUDPYYIsz1c+wd8gGwhdUI3CMuv5YozhysqIGnNOS+dDwap3XuYi9MEqFtF6mC1pHq0QXkc9AnwW8CKEEVZ3YtlT8NVTzKxQGBnXJ1ChHluO2wLUJiIruEt7fIGETiIzF3DhQLijbyv2oG2XBLs+gjqUSkmfAj80dQNUzV7d1L66A77omC5EqHOsiCUctdWBuj0w4UI//T/FKC7qutZK+ueFmTXBIQe0PfWq26GlAfq+l8UEJcxZEtQTmGg== ARC-Authentication-Results: i=1; mx.microsoft.com 1; spf=pass smtp.mailfrom=nvidia.com; dmarc=pass action=none header.from=nvidia.com; dkim=pass header.d=nvidia.com; arc=none DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=Nvidia.com; s=selector2; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck; bh=dv7/7+9hTIe95WgqSRK8NGJCl639mvRp2nzqcSFDqZM=; b=Dz5ENJ3UK8alsncLsL26D74yqV4BYWNCSr1DeE6n3xrOpFtGVyV9zKiUWGIYH+ErBIfr56odlr7xijiTBeBYSuWttAXR6OmSnVDaDsiEgtzEOGiQOqNndpApM74DNoNgp8XSWTDr28djrA4vVixev9/ZyHT9TQpNugprkTZQFV6RZAutjBJ5KF5n/2/vIDPqDg/pM0OseYowxbYX1s7WhjJUBp+mZQZMfk6GTo/scpaFReUSBDXZ2+u87TAUCDSZLB89JDrgstIHSZbXd1tPK7MQSZYaKnGx3K8uyT+7TBL43ykz+ZekWNLb114c0Qk7GjluL0x3Qnb8U6xgj122LA== Authentication-Results: dkim=none (message not signed) header.d=none;dmarc=none action=none header.from=nvidia.com; Received: from DM3PR12MB9416.namprd12.prod.outlook.com (2603:10b6:0:4b::8) by PH8PR12MB7229.namprd12.prod.outlook.com (2603:10b6:510:227::20) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.21.406.10; Sat, 12 Sep 2026 04:44:32 +0000 Received: from DM3PR12MB9416.namprd12.prod.outlook.com ([fe80::8cdd:504c:7d2a:59c8]) by DM3PR12MB9416.namprd12.prod.outlook.com ([fe80::8cdd:504c:7d2a:59c8%4]) with mapi id 15.21.0406.007; Sat, 12 Sep 2026 04:44:32 +0000 From: John Hubbard To: Danilo Krummrich , Alexandre Courbot Cc: Timur Tabi , Alistair Popple , Eliot Courtney , Zhi Wang , David Airlie , Simona Vetter , Bjorn Helgaas , Miguel Ojeda , Alex Gaynor , Boqun Feng , Gary Guo , =?UTF-8?q?Bj=C3=B6rn=20Roy=20Baron?= , Benno Lossin , Andreas Hindborg , Alice Ryhl , Trevor Gross , nova-gpu@lists.linux.dev, LKML , John Hubbard Subject: [PATCH v4 16/17] gpu: nova-core: add KUnit tests for the interrupt tree and HALs Date: Fri, 11 Sep 2026 21:43:59 -0700 Message-ID: <20260912044400.677097-17-jhubbard@nvidia.com> X-Mailer: git-send-email 2.55.0 In-Reply-To: <20260912044400.677097-1-jhubbard@nvidia.com> References: <20260912044400.677097-1-jhubbard@nvidia.com> X-NVConfidentiality: public Content-Transfer-Encoding: quoted-printable X-ClientProxiedBy: BY3PR05CA0016.namprd05.prod.outlook.com (2603:10b6:a03:254::21) To DM3PR12MB9416.namprd12.prod.outlook.com (2603:10b6:0:4b::8) Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-MS-PublicTrafficType: Email X-MS-TrafficTypeDiagnostic: DM3PR12MB9416:EE_|PH8PR12MB7229:EE_ X-MS-Office365-Filtering-Correlation-Id: 883037ec-661a-4a92-8fc1-08df1088899b X-MS-Exchange-SenderADCheck: 1 X-MS-Exchange-AntiSpam-Relay: 0 X-Microsoft-Antispam: BCL:0;ARA:13230040|1800799024|7416014|376014|23010399003|366016|10067099003|6133799003|3023799007|18002099003|5023799004|11063799006|56012099006|22082099003; X-Microsoft-Antispam-Message-Info: ThVuRg8F9klSqn2w4T4OYCcZOs1W41TFaPrftFJCNWGSPflr2tXTESIUUmB3StEEjfBnbocUxjSX6P28exG0QlysNqe/t75RGmWasp34ieieCkLSGiJi6CFDZNpfVE8Kp2prLpsqbgYZp4as0KPYzB9MWqmykjBSpX4oKm/jnkGg+Hd/19a/l/pUpnvlrSmQ9psfoQXCKE8UuBFRbGXEZO+5frOCu/E/kqSOe3oyi9PstmQuiW6CEHR2MzF6qrJANSGFVVGtiikodB+sX+da2/pvTsGNqwDtUP+cNLinYrm9YnjZBXVRvefecpor78pkWwkPkYCK06MdHnVbfwrWLcyJLBMk00ZLMZirvjNTErmlxGXkc+Xv8LssS0dXW7gp9cGa4Vvh77ODo12dJLQgWn38ULOPgeHZu2k/rbhzFmerwOxl+2qzesvv220rgFHxN7IVW/YZXxN7AQvbFqwu5TCCeg9p4xi0rBHXRFZTsqmj/x5KO6MtHH12xMA0Rm0KyK+EEAzmV50vkRpjxOXxEgn/1/AKbooBnDdxiruC3orjn3J+UBGbYmL8ZLJJaenJrnHb1jr7kukSMcE8GdM2LxvLP0xbQCGrJ6Iva5/yVFlK53x36qZDz66UgCs1WriX17CV57OJtmqwTRhaF7JR7/ltzIeouKu38rWgG67tkBc= X-Forefront-Antispam-Report: CIP:255.255.255.255;CTRY:;LANG:en;SCL:1;SRV:;IPV:NLI;SFV:NSPM;H:DM3PR12MB9416.namprd12.prod.outlook.com;PTR:;CAT:NONE;SFS:(13230040)(1800799024)(7416014)(376014)(23010399003)(366016)(10067099003)(6133799003)(3023799007)(18002099003)(5023799004)(11063799006)(56012099006)(22082099003);DIR:OUT;SFP:1101; X-MS-Exchange-AntiSpam-MessageData-ChunkCount: 1 X-MS-Exchange-AntiSpam-MessageData-0: =?us-ascii?Q?d+budcKFwYWvajXD4NMyuxrf/iyIACNbVhCLyjyV5fb/4ZN0UBXXeJY4OIl3?= =?us-ascii?Q?ym3JxfSFtg5AUEvycyA6JVjquUSd7QZW4m+lkKsthX0gnJ9l0UrVQRtrquZZ?= =?us-ascii?Q?N8sHnS4FjyTy3RZmxhCdpqx7NnMWxS6ExO3JGGy9HdN6m3cYoTS7kZBJq7LS?= =?us-ascii?Q?FacWgiZqjje6I6dZ5PBb9swI8lNOhEaodjoyUXTp/bH7faPU6Z1j97T985M7?= =?us-ascii?Q?P6ib1OT91hA7+68C/T+NuoxBK4uXY2cs1vAf5poKb20/+T9/6/qOqISf3OXt?= =?us-ascii?Q?h0aWJT1V7YlnsZKyyD+VKHlztLpKv8G/pMlox4nahZz1pka3h5dvP3eNv1HA?= =?us-ascii?Q?ukEu5vL7K+Kza//cDDpopMqNP8wJpoKXi3ZEpnXuBCT7xDrEscIryGmBYtre?= =?us-ascii?Q?4x9jMX7Hb4IA60gRiZ/oot/8PB6p2h1Pmq24hoEQTCZthyTGUG1yZchwqJgC?= =?us-ascii?Q?YzwqqCWU7YPzHDtVi1HWG7cD2Ji9ESAESsYSYpKO239xA4w/ZTNdfnNQ1Kkr?= =?us-ascii?Q?YMVRPZj2UxN11pqcr6lT03uoD7p6TfTzW2QfixcDJaJ102kn3xoyCACb0oAl?= =?us-ascii?Q?pNx0UFwaeRQ3I3XCNsHmCf/p8jPtKC8AsRT6Jy2X+bcBfTA96NydDZZGGZX+?= =?us-ascii?Q?3uuqSDQOruERcg8td5b1wwW67oK2y9qZ6i8YMOGaJWCyM1vWXE9QEhrad4PB?= =?us-ascii?Q?bQbO8c9NYY7ho3GFQfqvGF7IBAaYWUXRDyJWWOWgZ/Th6M/+/2uyr34rkT9Y?= =?us-ascii?Q?bil8Zkap41akhe3IcYq0ncc/gdPjhE08KrleZw32ciCu59ryxg+ANfoagZgB?= =?us-ascii?Q?9iRZ2WEGLtthzaa5zChzVPKYAB1eEodkvILLULWBcakohbXc6xWL9x4gtF2i?= =?us-ascii?Q?CtzsBu0B70NXJREMP4mz0kZFn0k1JGw+EvfD6FH4KJ3jfZ66DCF5lgJwoEBU?= =?us-ascii?Q?8uNju4NPQ6IwKEq2ZXg46QLs7UO4STQNlfpfslDPxWvapxFDNBEtT1lcuJH7?= =?us-ascii?Q?S3w6BwXv7JSE+ViudWQFVkdZNjv81X+4T8pj2wsxdR6GCCX6QXr0O2r5L6uh?= =?us-ascii?Q?dGOCjzMplBMyG6bjsoD1jiTEpzOK7nyUAgA8y5CH18myc54QnNZUr7uoO4oR?= =?us-ascii?Q?3uPgrkfuYoD6D4Qy+Gd2FhM08Wwhd3kptc5tYFAeeVFHSFh+DCTgqVSxywTA?= =?us-ascii?Q?y3YgzSjCtujRtXMX/Lz5QTH7+Ix+kknLT20Bs1lvOO6rLJ8ZgR5MJzq/4r2r?= =?us-ascii?Q?rR3BKJJK3VdAsxubl1UkcN6Ipu6Pq2opQplc9eMc97IRb8vKFtB1bu876oq2?= =?us-ascii?Q?PJcm0pVt++QRnJe5CG27yTFgwXtP9Y53oZ9xVHHaCR9GmDkDpqBWWWEV1UJg?= =?us-ascii?Q?5UCuQeDrOoL9rDRu4CBKma8a0Esfnw1XKZTtjCmsfwDEknMcDlEDMNCfDfIK?= =?us-ascii?Q?5x7gvAtbYBmsb44M9dkf3Dk+9qmDMq7sq8MNCz3bV0AcC5dw7EK91A4Sd0nN?= =?us-ascii?Q?X9pe6t3786SlDCPniaGKZ+eDWt1m0kO9sAGFO+SL7YGRIMVWXBD/FxxhJ+Ei?= =?us-ascii?Q?zcqKrwc5MXWkl9IHy3QTUVABHp0unWC0iEhJ95L3mfBE8+T7JNuEqm1U0TIU?= =?us-ascii?Q?Eo6+QcOOTR/mgcSS4ah/cvQb5fkEqwU/GabI5nSI7tIOyC2tdcSKlroi2Jm1?= =?us-ascii?Q?qHwT7NrV852Zl+7ZP3gc/+2IHHRvwGeZj6TS0QPIzBr0ltqkTlS/QZGAMdAZ?= =?us-ascii?Q?ZW2LceMrNQ=3D=3D?= X-OriginatorOrg: Nvidia.com X-MS-Exchange-CrossTenant-Network-Message-Id: 883037ec-661a-4a92-8fc1-08df1088899b X-MS-Exchange-CrossTenant-AuthSource: DM3PR12MB9416.namprd12.prod.outlook.com X-MS-Exchange-CrossTenant-AuthAs: Internal X-MS-Exchange-CrossTenant-OriginalArrivalTime: 12 Sep 2026 04:44:32.2507 (UTC) X-MS-Exchange-CrossTenant-FromEntityHeader: Hosted X-MS-Exchange-CrossTenant-Id: 43083d15-7273-40c1-b7db-39efd9ccc17a X-MS-Exchange-CrossTenant-MailboxType: HOSTED X-MS-Exchange-CrossTenant-UserPrincipalName: oemG6qSS86hiulwEZzJE+KzSudY8KDD++6FG+cfmNqS60/G496iVfnXFn7bl5puuNMPAG1vs+tRbqFD1WceVtg== X-MS-Exchange-Transport-CrossTenantHeadersStamped: PH8PR12MB7229 Content-Type: text/plain; charset="utf-8" The vector arithmetic and the per-architecture interrupt properties touch no hardware, so KUnit can cover both without a GPU. A wrong leaf count or rearm method for one family would otherwise show up only on that family's hardware. Add three suites: * nova_core_gin_tree covers the vector types. It checks that a leaf index stops at the widest supported tree, that a leaf count implies the right number of subtrees and vectors and enumerates every leaf in order, that a vector maps to the right leaf, bit and subtree, and that a vector beyond an 8-leaf tree is rejected there and accepted in a 16-leaf tree. It also exercises the subtree set operations and checks that every supported chipset implements the subtree that carries the GSP event. * nova_core_gin_hal covers the CPU interrupt HAL: the 8-leaf tree on Turing through Ada and the 16-leaf tree on Hopper and later, the configuration-space rearm for pre-Hopper MSI, the TOP-enable rearm for Hopper-plus MSI, and the single-subtree rearm for MSI-X on every family. * nova_core_falcon_hal covers the falcon interrupt HAL: which chipsets have the retrigger register, and which routing offsets each uses. GA100 appears on the Turing side of one split and the Ampere side of the other, because it has the retrigger register but keeps the Turing routing offsets. Assisted-by: LLM Signed-off-by: John Hubbard --- drivers/gpu/nova-core/falcon/hal.rs | 48 +++++++ drivers/gpu/nova-core/irq/hal.rs | 64 ++++++++++ drivers/gpu/nova-core/irq/interrupt_tree.rs | 135 +++++++++++++++++++- 3 files changed, 246 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/nova-core/falcon/hal.rs b/drivers/gpu/nova-core/fa= lcon/hal.rs index 3f1f509eccbd..70bddcaf4266 100644 --- a/drivers/gpu/nova-core/falcon/hal.rs +++ b/drivers/gpu/nova-core/falcon/hal.rs @@ -171,3 +171,51 @@ pub(super) fn falcon_hal( =20 Ok(hal) } + +#[kunit_tests(nova_core_falcon_hal)] +mod tests { + use super::*; + + /// Turing falcons have no retrigger register. GA100 and every later c= hipset have it. + #[test] + fn intr_retrigger_gate_per_arch() { + for chipset in [Chipset::TU102, Chipset::TU116] { + assert!(!falcon_intr_hal(chipset).has_intr_retrigger()); + } + + for chipset in [ + Chipset::GA100, + Chipset::GA102, + Chipset::AD102, + Chipset::GH100, + Chipset::GB100, + Chipset::GB202, + ] { + assert!(falcon_intr_hal(chipset).has_intr_retrigger()); + } + } + + /// The RISC-V routing offsets change at GA102, so GA100 still uses th= e Turing ones. + #[test] + fn riscv_routing_offsets_split_at_ga102() { + for chipset in [Chipset::TU102, Chipset::TU116, Chipset::GA100] { + assert_eq!( + falcon_intr_hal(chipset).riscv_routing(), + RiscvRouting::Tu102 + ); + } + + for chipset in [ + Chipset::GA102, + Chipset::AD102, + Chipset::GH100, + Chipset::GB100, + Chipset::GB202, + ] { + assert_eq!( + falcon_intr_hal(chipset).riscv_routing(), + RiscvRouting::Ga102 + ); + } + } +} diff --git a/drivers/gpu/nova-core/irq/hal.rs b/drivers/gpu/nova-core/irq/h= al.rs index ede9a10ccda6..03852918013d 100644 --- a/drivers/gpu/nova-core/irq/hal.rs +++ b/drivers/gpu/nova-core/irq/hal.rs @@ -88,3 +88,67 @@ pub(super) fn cpu_interrupt_hal(chipset: Chipset) -> &'s= tatic dyn CpuInterruptHa } } } + +#[kunit_tests(nova_core_gin_hal)] +mod tests { + use super::*; + + use crate::gpu::Chipset; + + /// Turing through Ada implement an 8-leaf tree. + #[test] + fn pre_hopper_tree_size() { + for chipset in [Chipset::TU102, Chipset::GA102, Chipset::AD102] { + assert_eq!(cpu_interrupt_hal(chipset).leaf_count(), LeafCount:= :Eight); + } + } + + /// Hopper and later implement a 16-leaf tree. + #[test] + fn hopper_plus_tree_size() { + for chipset in [Chipset::GH100, Chipset::GB100, Chipset::GB202] { + assert_eq!(cpu_interrupt_hal(chipset).leaf_count(), LeafCount:= :Sixteen); + } + } + + /// MSI rearms through the configuration-space mirror only before Hopp= er. Hopper and later + /// cycle the `TOP` enables of every serviced subtree. + #[test] + fn msi_rearm_method_per_arch() { + for chipset in [Chipset::TU102, Chipset::GA102, Chipset::AD102] { + let hal =3D cpu_interrupt_hal(chipset); + assert_eq!( + hal.pci_irq_rearm_method(MsiType::Msi), + PciIrqRearmMethod::ConfigMirrorEoi + ); + } + + for chipset in [Chipset::GH100, Chipset::GB100, Chipset::GB202] { + let hal =3D cpu_interrupt_hal(chipset); + assert_eq!( + hal.pci_irq_rearm_method(MsiType::Msi), + PciIrqRearmMethod::TopEnableCycleServiced + ); + } + } + + /// MSI-X rearms one subtree on every architecture, since each subtree= has its own table + /// entry. + #[test] + fn msix_rearms_one_subtree_on_every_arch() { + for chipset in [ + Chipset::TU102, + Chipset::GA102, + Chipset::AD102, + Chipset::GH100, + Chipset::GB100, + Chipset::GB202, + ] { + let hal =3D cpu_interrupt_hal(chipset); + assert_eq!( + hal.pci_irq_rearm_method(MsiType::MsiX), + PciIrqRearmMethod::TopEnableCycleSubtree + ); + } + } +} diff --git a/drivers/gpu/nova-core/irq/interrupt_tree.rs b/drivers/gpu/nova= -core/irq/interrupt_tree.rs index eae1a1d4b933..66b7d2b16454 100644 --- a/drivers/gpu/nova-core/irq/interrupt_tree.rs +++ b/drivers/gpu/nova-core/irq/interrupt_tree.rs @@ -122,7 +122,10 @@ pub(super) const fn from_raw(raw: u32) -> Self { Self(raw) } =20 - #[cfg_attr(not(CONFIG_NOVA_CORE_SELFTESTS), expect(dead_code))] + #[cfg_attr( + not(any(CONFIG_NOVA_CORE_SELFTESTS, CONFIG_KUNIT =3D "y")), + expect(dead_code) + )] pub(super) const fn into_raw(self) -> u32 { self.0 } @@ -490,3 +493,133 @@ fn drop(&mut self) { clear_top_enables(self.bar, self.serviced); } } + +#[kunit_tests(nova_core_gin_tree)] +mod tests { + use super::*; + + /// A leaf index cannot name a leaf beyond the widest supported tree. + #[test] + fn leaf_index_bounds() { + assert!(LeafIndex::try_new(0).is_some()); + assert!(LeafIndex::try_new(15).is_some()); + assert!(LeafIndex::try_new(16).is_none()); + } + + /// The subtree count, the implemented-subtree set, and the vector cou= nt follow the leaf count. + #[test] + fn leaf_count_derives_subtrees_and_vectors() { + assert_eq!(LeafCount::Eight.subtree_count(), 4); + assert_eq!( + Bounded::::from(LeafCount::Eight.subtree_set()).get(), + 0x0f + ); + assert_eq!(LeafCount::Eight.vector_count(), 256); + + assert_eq!(LeafCount::Sixteen.subtree_count(), 8); + assert_eq!( + Bounded::::from(LeafCount::Sixteen.subtree_set()).get= (), + 0xff + ); + assert_eq!(LeafCount::Sixteen.vector_count(), 512); + } + + /// A tree enumerates every leaf that it implements, in order, and no = more. + #[test] + fn leaf_count_iter_covers_the_tree() { + for (count, expected) in [(LeafCount::Eight, 8usize), (LeafCount::= Sixteen, 16)] { + let mut seen =3D 0; + + for (index, leaf) in count.iter().enumerate() { + assert_eq!(leaf.get(), index); + seen +=3D 1; + } + + assert_eq!(seen, expected); + } + } + + /// A vector maps to its leaf, its bit within that leaf, and its subtr= ee. The doorbell (129) + /// and the GSP event (155) share a subtree. + #[test] + fn vector_maps_to_leaf_bit_and_subtree() { + let doorbell =3D GinVector::new::<129>(); + let gsp =3D GinVector::new::<155>(); + + assert_eq!(doorbell.leaf_index().get(), 4); + assert_eq!(doorbell.leaf_mask().into_raw(), 1 << 1); + assert_eq!(doorbell.subtree().index(), 2); + + assert_eq!(gsp.leaf_index().get(), 4); + assert_eq!(gsp.leaf_mask().into_raw(), 1 << 27); + assert_eq!(gsp.subtree().index(), 2); + + assert_eq!(doorbell.subtree(), gsp.subtree()); + } + + /// Both fixed vectors are within the 8-leaf tree, so every supported = part implements them. + #[test] + fn fixed_vectors_fit_the_narrowest_tree() { + assert!(GinVector::new::<129>().validate(LeafCount::Eight).is_ok()= ); + assert!(GinVector::new::<155>().validate(LeafCount::Eight).is_ok()= ); + + // The first vector beyond an 8-leaf tree. + assert!(GinVector::new::<256>().validate(LeafCount::Eight).is_err(= )); + assert!(GinVector::new::<256>().validate(LeafCount::Sixteen).is_ok= ()); + } + + /// A subtree set reports membership, intersection, and its span from = subtree 0. + #[test] + fn subtree_set_operations() { + let gsp =3D GinVector::new::<155>().subtree(); + + assert!(LeafCount::Eight.subtree_set().contains(gsp)); + assert!(!LeafCount::Eight.subtree_set().is_empty()); + + // The GSP needs no subtree above 2, so an MSI-X request covers en= tries 0 through 2. + assert_eq!(SubtreeSet::from(gsp).span(), 3); + + // A 16-leaf tree implements every subtree that an 8-leaf tree doe= s. + assert_eq!( + LeafCount::Sixteen + .subtree_set() + .intersection(LeafCount::Eight.subtree_set()), + LeafCount::Eight.subtree_set() + ); + } + + /// Iterating a subtree set yields each subtree once, lowest index fir= st, and nothing for an + /// empty set. + #[test] + fn subtree_set_iterates_its_members() { + assert!(LeafCount::Eight + .subtree_set() + .iter() + .map(Subtree::index) + .eq([0u32, 1, 2, 3])); + + let gsp =3D SubtreeSet::from(GinVector::new::<155>().subtree()); + assert!(gsp.iter().map(Subtree::index).eq([2u32])); + + let empty =3D SubtreeSet::from(Bounded::::new::<0>()); + assert_eq!(empty.iter().count(), 0); + } + + /// Every supported chipset implements the subtree that carries the GS= P event. + #[test] + fn gsp_subtree_is_implemented_everywhere() { + for chipset in [ + Chipset::TU102, + Chipset::GA102, + Chipset::AD102, + Chipset::GH100, + Chipset::GB100, + Chipset::GB202, + ] { + assert!(cpu_interrupt_hal(chipset) + .leaf_count() + .subtree_set() + .contains(crate::irq::gsp::GSP_SUBTREE)); + } + } +} --=20 2.55.0 From nobody Fri Sep 25 13:19:17 2026 Received: from BYAPR05CU005.outbound.protection.outlook.com (mail-westusazon11010052.outbound.protection.outlook.com [52.101.85.52]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 8F7F338D404 for ; Sat, 12 Sep 2026 04:44:42 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=fail smtp.client-ip=52.101.85.52 ARC-Seal: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1789188286; cv=fail; b=FDqsG9XruWunkyXjq027ecYM0CbTvg8XqnwKT0UUlS2VnDVyyEjNUF9F//Wc3qlgEi7+JcWvHBwyvo9PJQEFzM6VtUmQWGyTo2k0mz+ZTzccCDssxNvpE+41yVxhZza1nAr2mJgzRPxIDpKkk0tXgzi5+w6GldJu26cdjeg/1VU= ARC-Message-Signature: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1789188286; c=relaxed/simple; bh=7aG5s6ZR/t9r2fJfFYwcOSUJjuDnLWTqdlwo0HC2fDM=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: Content-Type:MIME-Version; b=KkfMoegwd4x9+cRp5acAY6IaDCm/5v0FqVhJ2aNYOTFQpPLbs/Vf7XY8p8YVVV0/ehKaOMlFfvA9WbBXva6Pnmc/3+y/KFT4ErXCAE12sK/+zJuocIDV7NxJggA4H6ZfZ6uDmNfySnCg0b8uM3H4DJJ37AVI1yx8fdVnxFYvVKM= ARC-Authentication-Results: i=2; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=nvidia.com; spf=fail smtp.mailfrom=nvidia.com; dkim=pass (2048-bit key) header.d=Nvidia.com header.i=@Nvidia.com header.b=NNsn95yt; arc=fail smtp.client-ip=52.101.85.52 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=nvidia.com Authentication-Results: smtp.subspace.kernel.org; spf=fail smtp.mailfrom=nvidia.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=Nvidia.com header.i=@Nvidia.com header.b="NNsn95yt" ARC-Seal: i=1; a=rsa-sha256; s=arcselector10001; d=microsoft.com; cv=none; b=vLJQntc9Z9s7587AHixIrWwgKO92micsplXOfT4hpgMD01onz69H/Mylfps8yKike3BDiVcjo8zcZgif1i3C9ScmMSsCKdSi32copfKe8wxgqfnHh08Z2FktYubdCT0zXbjv9HlFl8gDx6LayTgRgs4+KBNf8xOVtqntd0RGSqv3u48iGeQqI2e/UO1YJkgAWJqslTaqls98urbkDtcNaZJppHkS6NeMx+dOVs5ozySPldxJaDPJw6S022NRBsH6eBxUrLz+ZE/oxKE3gzIN9AfUusuNmoPKP5QBrSDso1cCcnLcKNqepYd101J81uPepAfcyMtS82NBJsRTO2/StQ== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=microsoft.com; s=arcselector10001; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-AntiSpam-MessageData-ChunkCount:X-MS-Exchange-AntiSpam-MessageData-0:X-MS-Exchange-AntiSpam-MessageData-1; bh=8utSJMd2yh8EG++UJe5MUi34LE9z5XPkP8R7WQS4s4U=; b=dBFajXhBLsxIe8OvgH9o3NE5dLjmj1bKkHaeUoyCKzJlCS9PbJ8fzoDCJCZg+ou0kvA6eiLw6zhobVeoa25gauaBYHcKYMoRviTlny2ogGPP01AVpRiUvVpwqBY/BHJVroTt/U4x9YvKk+FoLP846/ZmK6Z2GsEJjuMPnQPLKnw9rtaCVA1qaqJoSSgd5qEKrBpgrBhGJJd5vgd/P8g4Clxm+tFB/lfDJqBCst0of8ILaFpvz0EWCzwV+BY3bUfnOIZ34M3el39RbZ5E/zrXfrtxtMpLgSXVbjxfgpq5O3aXR2TfVSpJq6p1A4qw3YXqCGtdbySmaQCnNuk4SAaBMA== ARC-Authentication-Results: i=1; mx.microsoft.com 1; spf=pass smtp.mailfrom=nvidia.com; dmarc=pass action=none header.from=nvidia.com; dkim=pass header.d=nvidia.com; arc=none DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=Nvidia.com; s=selector2; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck; bh=8utSJMd2yh8EG++UJe5MUi34LE9z5XPkP8R7WQS4s4U=; b=NNsn95ytMRD2vh+loh741KKFWHTEDW7dav15qdauvc9NMvft6HDOzlp89rcJcX6tkKHXTlEQ37mdGFlOzIKkeu+S8J6q51TclLGSx5MgX0F3AsYR+0HbQr7krfJeN/3WsFdIIv4Z80zUcMIukf+M3a+hARSbRKbegrYb0VHAG+GRqk2/xFXqzt3AjBAo2EHm63e0kEvOFZSw4WyvkAKPUhCyrDvI+WH1vw3rRzNYxPpDUVwu8yqCgttfxv58BB7sWg/XokPtbaC1ovYH93R5QROnv24Z5wKmllVLRV6H9tcqJ2BZOd5UIc/QVZ6WzJ2djYaywbsBqmJbxJvtYngjJg== Authentication-Results: dkim=none (message not signed) header.d=none;dmarc=none action=none header.from=nvidia.com; Received: from DM3PR12MB9416.namprd12.prod.outlook.com (2603:10b6:0:4b::8) by PH8PR12MB7229.namprd12.prod.outlook.com (2603:10b6:510:227::20) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.21.406.10; Sat, 12 Sep 2026 04:44:33 +0000 Received: from DM3PR12MB9416.namprd12.prod.outlook.com ([fe80::8cdd:504c:7d2a:59c8]) by DM3PR12MB9416.namprd12.prod.outlook.com ([fe80::8cdd:504c:7d2a:59c8%4]) with mapi id 15.21.0406.007; Sat, 12 Sep 2026 04:44:33 +0000 From: John Hubbard To: Danilo Krummrich , Alexandre Courbot Cc: Timur Tabi , Alistair Popple , Eliot Courtney , Zhi Wang , David Airlie , Simona Vetter , Bjorn Helgaas , Miguel Ojeda , Alex Gaynor , Boqun Feng , Gary Guo , =?UTF-8?q?Bj=C3=B6rn=20Roy=20Baron?= , Benno Lossin , Andreas Hindborg , Alice Ryhl , Trevor Gross , nova-gpu@lists.linux.dev, LKML , John Hubbard Subject: [PATCH v4 17/17] gpu: nova-core: document the GIN interrupt controller and GSP events Date: Fri, 11 Sep 2026 21:44:00 -0700 Message-ID: <20260912044400.677097-18-jhubbard@nvidia.com> X-Mailer: git-send-email 2.55.0 In-Reply-To: <20260912044400.677097-1-jhubbard@nvidia.com> References: <20260912044400.677097-1-jhubbard@nvidia.com> X-NVConfidentiality: public Content-Transfer-Encoding: quoted-printable X-ClientProxiedBy: SJ0PR13CA0185.namprd13.prod.outlook.com (2603:10b6:a03:2c3::10) To DM3PR12MB9416.namprd12.prod.outlook.com (2603:10b6:0:4b::8) Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-MS-PublicTrafficType: Email X-MS-TrafficTypeDiagnostic: DM3PR12MB9416:EE_|PH8PR12MB7229:EE_ X-MS-Office365-Filtering-Correlation-Id: fe2de470-661d-4b4c-011d-08df10888a6e X-MS-Exchange-SenderADCheck: 1 X-MS-Exchange-AntiSpam-Relay: 0 X-Microsoft-Antispam: BCL:0;ARA:13230040|1800799024|7416014|376014|23010399003|366016|10067099003|6133799003|3023799007|18002099003|5023799004|11063799006|56012099006|22082099003; X-Microsoft-Antispam-Message-Info: 4pXchQkMQsEoN/JhIvnS2FY55Hr17W8rSdzqQuViVbAuE/aev+9RBwwh2GbCbCZrUG9s75ZN8Jd7NobO3i0bNihe3Dw19j8M4k1aTnRJHgS5idKzDuE8uUFTPG4RFdTbJRgHPE4gVnk1KoNtHOYAnyJu8+T+8ZxtYHvv1a/9Lpa2BgzsRVb0h80Z3OSiHXpaTyZkJ1VqjLKGalt+qcx7s1QS8iU8bBQagBDLpL85jta8FzpTcMkcyyfk2pZG3jv/3vvPuKbVP+V1Zrka3kpoU+AsO8HbhkJPQ1I495/BxbOZCsEkHpLpcNUeTwGvFfc9wM482Ujn6BL8fOSsOkJ8xzkPIP8LqyYMbnaYWyc3lPDSKFbqrzRuQ0NpSmxBe1BqrgZ1mZX3Wx3JsH6AN1DUiTOdXLfGBskJUOcb3FgZSVUd0GMmFxnmbp3vuF2AdLKt5YfUpBOd86e/xUE2ovtNm9+5x4f5DhX0g5o5k1kLI2B52+2EzTxheYTfc7ivtorFZgCYy+qNa8Ui9TIDC1l+Rvnl+Xn3mjMlJTmXnUKKdsBcC+YtZrC6jqUoklmVEqeSJ13RREdT1mWgz39m2P/2XqKQsxt0jNsVirOLQt1kAGJNLimF/SIaq4h0pgH9wDu/dwqqkEZIzxxI/MKd34zPY6Y1UE8S417qRfvhs/zKjBI= X-Forefront-Antispam-Report: CIP:255.255.255.255;CTRY:;LANG:en;SCL:1;SRV:;IPV:NLI;SFV:NSPM;H:DM3PR12MB9416.namprd12.prod.outlook.com;PTR:;CAT:NONE;SFS:(13230040)(1800799024)(7416014)(376014)(23010399003)(366016)(10067099003)(6133799003)(3023799007)(18002099003)(5023799004)(11063799006)(56012099006)(22082099003);DIR:OUT;SFP:1101; X-MS-Exchange-AntiSpam-MessageData-ChunkCount: 1 X-MS-Exchange-AntiSpam-MessageData-0: =?us-ascii?Q?+/dfvqQ4C0YlnkvHOvA7wT+XUOmzGyg4+wsZjjLOkZu5Eh4auuqvA/XB+5Co?= =?us-ascii?Q?DFQ5Lh4IQvlZyjDduZH29JbReKxsDeyrGZkojtgC8mpG669FEqKNt99ayaiD?= =?us-ascii?Q?Tc11L9fWOdafrRDtMpE4ILZaKiKbFRs9NgLm4CBjRFIBw+uhjEWIP1BiYu4w?= =?us-ascii?Q?LAf3R0zKkS5gG3tgu7sH7k3895lfRJGJ55hN0bZBiUWDbHhvSinV96fUYUoi?= =?us-ascii?Q?p6rK3019NzQPsSmcy5A36gKDmYRRw5Mk/spDWFvEhqZ419dqXooGZTtLmemw?= =?us-ascii?Q?/7eoqLqhNM2LdQXDMuJO2a5QqLE2JlcNfrjVTUGeEr+JKEMKtpKd1JJAL1dX?= =?us-ascii?Q?B8QR3dA2v/goXQI/26FHMuSrUnvl1bGBClo0coRPDSlHeH10GEghBiu5R9Uw?= =?us-ascii?Q?xsh2xB7yi7CHNVORFfoKAVLS/ryuDGwgbMBgG+C9gP0F2jlqvJg7cdCCTVFt?= =?us-ascii?Q?HxpcIof7S7KKnOSALh1WO8UQWasVRrZaLkGLxGyjIDB2UzihsBgj4hGByYwV?= =?us-ascii?Q?teHWRUOsM+ed72gwWOCer/V1vSAnuS9z9NaSWxTnDlleQsK95gLMUiqcy0l0?= =?us-ascii?Q?X3Zcd/WI4agb8KQTcXCKeXKplSUriQMzNBCUh1T9uqt8dYp+rgNyHwYknAkd?= =?us-ascii?Q?9uybFHs5YtxxfkpEpfofQvgGhejLb3JEKqepknFYBhgQ/olhSRgvgbVsGlcq?= =?us-ascii?Q?XZG/3CRHLEuXU6WSqlO9cE+90r6lDWtaG+Wf9RIeMonc3BOj4zUTutTHqB6h?= =?us-ascii?Q?zcI00o4aqJXtua2xpVNqotDGnmP8lqKNtwRQgodhZEE3H71/EdTirvtbG9jO?= =?us-ascii?Q?mlprBdfhezepeR/ROdrxnQt1kDS2y/SrFcJ6ulHlXC729bVEADyeHFcfMPTI?= =?us-ascii?Q?N1axKzmiRxE8xn3E1dXlhVTykBtnrI6j4k2T8GsiN02u5mLlK9jGoq8M2Nyb?= =?us-ascii?Q?n70IoKViXMoZVhFLyGUWu7YDmFbGJ9UG02Qr+pkmkPclyr46MdIQWZSv0OYv?= =?us-ascii?Q?2RG0jyaN9JmdMMAQJOOUSN9AuHTUOUz18OZWEL7mTa2lwUgm9d+NIWt5AkSw?= =?us-ascii?Q?0Joyigk0jLChq4ZT0+gyL24PYi4jDBUtEzpm0LqVRNb63/+Uz9+b86SFsEk6?= =?us-ascii?Q?xaYosztPsK+ypXaQow5VJ9Uuqh/lPht0Tmg6HZEzWMxVa7JBFbHFD1Gt3rGb?= =?us-ascii?Q?szZ/3VCUYSVAHkFNsgu5V30Yz2U0KC3E4LRzzLcaSK8f3HLuDyQCuusPpPDO?= =?us-ascii?Q?tP7HADFVkj2RHDqEeG8grhzQK/uMbbWEHUs7kMbMZtP0BiIgT0Nadl9EkX2k?= =?us-ascii?Q?M2oucSxPoV3F2E+YFIC6v8uKB6ukyYP9zgev7TCbdRxMH47P62fXvY08GMTf?= =?us-ascii?Q?mtcjLvC/cdw5o6UV/gCWAyR/exKESOV9BYYLV3wdK/ybSQxXfLJhWE/NuXfN?= =?us-ascii?Q?LmKNApA5RoySN+t4RsdKJVY63XxtODxKgIOnCN4M+Tr+0Cgd/Zcw1iJbEYpX?= =?us-ascii?Q?kSLAKsvn1kdzZzcfxPKj29KGkfoTV4a2dyNqfZv8FBhFa0m2ajfcWxhulWsI?= =?us-ascii?Q?ZG3AvGx5sFyx2Yp9qhXGQFpla9x2ssgE25LxU50g/B6aHKoSHS/iFx6hI57n?= =?us-ascii?Q?w4XurzGHHQR6JqL/hjzoRQKNPYI1HdkLbDvXwNN4VZB9Q+B6SlHIZsfjBB0n?= =?us-ascii?Q?+yzdpNxlqghaRC0rdHvh6YV7SZoObL1ZEuc3mtoLLMDLlNV1EEGH7TUWKD3K?= =?us-ascii?Q?6HFWiP1/5g=3D=3D?= X-OriginatorOrg: Nvidia.com X-MS-Exchange-CrossTenant-Network-Message-Id: fe2de470-661d-4b4c-011d-08df10888a6e X-MS-Exchange-CrossTenant-AuthSource: DM3PR12MB9416.namprd12.prod.outlook.com X-MS-Exchange-CrossTenant-AuthAs: Internal X-MS-Exchange-CrossTenant-OriginalArrivalTime: 12 Sep 2026 04:44:33.5816 (UTC) X-MS-Exchange-CrossTenant-FromEntityHeader: Hosted X-MS-Exchange-CrossTenant-Id: 43083d15-7273-40c1-b7db-39efd9ccc17a X-MS-Exchange-CrossTenant-MailboxType: HOSTED X-MS-Exchange-CrossTenant-UserPrincipalName: WeT/a6ixQgp/zRXKBiAzfhksZ/dOpZWsIfXEH+wmY4xnkTXBV9Wo6fNscuU/7rXvrelOQwHUN5gHxnkzWrUgAw== X-MS-Exchange-Transport-CrossTenantHeadersStamped: PH8PR12MB7229 Content-Type: text/plain; charset="utf-8" The interrupt code rests on hardware behavior that the code cannot show on its own: how GIN, the GPU's interrupt controller, records and delivers interrupts, what edge-triggered delivery requires of a handler, and how the GSP signals the CPU. Some of those requirements come from Open RM rather than from the hardware manuals. Add a design document that records that behavior, the rules nova-core follows because of it, and the terms the code uses for it. The code comments cite the document by section rather than repeating it. Assisted-by: LLM Signed-off-by: John Hubbard --- Documentation/gpu/nova/core/interrupts.rst | 674 +++++++++++++++++++++ Documentation/gpu/nova/index.rst | 1 + 2 files changed, 675 insertions(+) create mode 100644 Documentation/gpu/nova/core/interrupts.rst diff --git a/Documentation/gpu/nova/core/interrupts.rst b/Documentation/gpu= /nova/core/interrupts.rst new file mode 100644 index 000000000000..280dcf97688a --- /dev/null +++ b/Documentation/gpu/nova/core/interrupts.rst @@ -0,0 +1,674 @@ +.. SPDX-License-Identifier: GPL-2.0 +.. SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIA= TES. All rights reserved. + +=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D +GPU interrupt handling: GIN and the GSP event +=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D + +This document describes how nova-core receives interrupts from the GPU on = Turing +and later parts. It covers the GPU Interrupt and Notification unit (GIN), = which +is the GPU's interrupt controller, and the GSP event, the interrupt that +nova-core services in normal operation. + +Throughout, *CPU* means the CPU and the nova-core driver running on it. Th= e GPU +also has on-chip processors that run their own firmware and receive their = own +interrupts. The GSP (GPU System Processor) is one of them. + +Register names are the names from the GPU hardware reference headers. The +pre-Hopper headers call the controller ``NV_CTRL`` and the Hopper-plus hea= ders +call it ``NV_GIN``. This document calls it GIN throughout, because the tre= e that +nova-core services is the same on every supported part. "Register naming" = at +the end says how the names map onto the headers. Open RM, NVIDIA's open-so= urce +GPU kernel driver, is cited wherever nova-core follows it. + +Terminology +=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D + +The three levels of the controller, innermost first: + +leaf + One ``LEAF`` register. Each of its 32 bits is the pending bit of one + interrupt source. A Turing, Ampere, or Ada tree has 8 leaves. A Hopper= or + Blackwell tree has 16. + +subtree + Two consecutive leaves, summarized by one bit of ``TOP``. A subtree is= the + unit of enabling at ``TOP``, and under MSI-X it is the unit of deliver= y: + every interrupt from one subtree arrives on one MSI-X entry. + +tree + One ``TOP`` register and the leaves under it. Every PCIe function has = its + own tree, and nova-core services the CPU tree of one function. + +The hardware headers, Open RM, and the Linux PCI API all use the word "vec= tor", +each for a different number. This document gives each one its own name, an= d a +bare "vector" always means a GIN vector. + +GIN vector + The GPU-internal interrupt source number. It addresses one bit of one = leaf. + A 16-leaf tree holds vectors 0 through 511, and an 8-leaf tree holds 0 + through 255. The CPU doorbell is vector 129 and the GSP event is vector + 155. + +MSI-X entry + An index into the device's MSI-X table. One entry serves one subtree. + +PCI vector + One of the interrupts that ``pci_alloc_irq_vectors()`` allocates: an M= SI-X + entry, or the single MSI message. + +Linux IRQ number + What ``request_irq()`` takes, obtained from ``pci_irq_vector()`` for a= PCI + vector. Linux's ``struct msix_entry`` calls this number ``.vector`` as + well. + +The remaining terms, each named for the register or the specification that +defines it: + +enable, disable a vector + Writes to ``LEAF_EN_SET`` and ``LEAF_EN_CLEAR``. + +enable, disable a subtree + Writes to ``TOP_EN_SET`` and ``TOP_EN_CLEAR``. + +serviced subtree + A subtree that nova-core enables and has a handler for. + +rearm + Restoring PCI interrupt delivery after servicing an interrupt. See + "Rearming PCI interrupt delivery". + +mask + Reserved for the two places where hardware and the PCI specification u= se + the word: the MSI-X per-entry Vector Control mask bit, which Linux + controls, and the falcon interrupt masks. It never names a GIN enable. + +latched, pending + Two names for one state, a set ``LEAF`` bit. The vector's source sets = the + bit whether or not the vector is enabled. + +clear a vector + Write a 1 to the vector's bit in ``LEAF``. Open RM calls the same oper= ation + ``intrClearLeafVector_HAL``. + +pending bits + The plain 32-bit value read from a ``LEAF`` register. + +notification + An interrupt whose only content is that something happened, such as a + posted message. Servicing a notification means reading what it announc= es. + The unit that raised it needs no attention. The GSP event is one. + +unit + Any block that raises an interrupt. "Engine" is reserved for the blocks + that do user work: GR, CE, NVDEC, and the like. + +falcon + One of the GPU's microcontrollers (see + Documentation/gpu/nova/core/falcon.rst). The GSP runs on the RISC-V co= re + inside its falcon. A falcon latches each of its interrupt causes and r= outes + it either to the host, meaning the CPU, or to its own core. + +The GIN controller +=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D + +A GPU has many interrupt sources: the GSP, the copy engines, the graphics +engine, video decode and encode, the MMU fault path, timers, and others. G= IN +records which of them are pending and raises the PCI interrupt to the CPU. + +Trees +----- + +GIN keeps one tree for each destination it can deliver an interrupt to. Th= e CPU +has one tree per PCIe function, so the physical function and each virtual +function have their own. The GSP has a tree, and so do the other on-chip +processors that receive interrupts. Every tree has the same two-level layo= ut, +and a function reaches its own tree through the per-function register aper= ture. + +nova-core services the CPU tree of one function. A virtual function's tree +belongs to that function's driver, and a processor's tree belongs to the +firmware running on that processor. + +The two-level tree +------------------ + +A tree is a set of ``LEAF`` registers and one ``TOP`` register. + +* ``LEAF(i)`` is a 32-bit register that holds the pending bits of vectors + ``32i`` through ``32i + 31``. A set bit is a pending vector. +* ``TOP`` is a 32-bit read-only register. Bit ``N`` summarizes subtree ``N= ``, + which is ``LEAF(2N)`` and ``LEAF(2N + 1)``. The bit is set when an enabl= ed + vector is pending in either leaf. + +A tree with L leaves has L / 2 subtrees and uses TOP bits 0 through L / 2 = - 1. +The other TOP bits read 0. The leaves and subtrees that a part has are its +implemented leaves and subtrees, and "Per-architecture differences" gives = the +counts. For an 8-leaf tree:: + + TOP bit 0 -> subtree 0 -> LEAF(0), LEAF(1) vectors 0..63 + TOP bit 1 -> subtree 1 -> LEAF(2), LEAF(3) vectors 64..127 + TOP bit 2 -> subtree 2 -> LEAF(4), LEAF(5) vectors 128..191 + TOP bit 3 -> subtree 3 -> LEAF(6), LEAF(7) vectors 192..255 + + LEAF(4), one bit per vector, holds vectors 128..159: + + bit 1 =3D vector 129 (CPU doorbell) + bit 27 =3D vector 155 (GSP event) + +A vector's number fixes its place in the tree:: + + leaf =3D vector / 32 + bit =3D vector % 32 + subtree =3D leaf / 2 + +Registers +--------- + +nova-core defines the tree's registers in the ``irq`` module's ``regs.rs``= . The +leaf registers are arrays indexed by leaf number. + +* ``LEAF(i)`` reads as the pending bits of leaf ``i``. Writing a 1 to a bit + clears that vector, and a 0 leaves the bit as it was. +* ``LEAF_EN_SET(i)`` and ``LEAF_EN_CLEAR(i)`` enable and disable the vecto= rs + of leaf ``i``, one bit per vector. +* ``TOP_EN_SET`` and ``TOP_EN_CLEAR`` enable and disable subtrees, one bit= per + subtree. +* ``LEAF_TRIGGER`` takes a vector number and latches that vector, exactly = as + the vector's own source would. It is write-only. The self-test uses it. + +nova-core does not read ``TOP``. "Servicing the tree" says why. + +Every set and clear register acts per bit: a 1 performs the action for that +bit, and a 0 leaves the bit alone. No register needs a read-modify-write. + +GIN delivers a vector to the CPU only when its leaf enable bit and its +subtree's TOP enable bit are both set. The enables do not affect the latch= . The +source of a disabled vector still sets its ``LEAF`` bit. ``TOP`` does not = show +that bit, so reading the leaf is the only way to see it. + +How a unit interrupt reaches the CPU +------------------------------------ + +A unit does not write a ``LEAF`` register. Each unit has an interrupt cont= rol +register that GSP firmware programs. The control register holds the unit's +vector, the GFID that identifies the PCIe function whose tree receives the +interrupt, and one enable bit per destination: the CPU, the GSP, and the o= ther +on-chip processors. When the unit has an event:: + + 1. The unit sends GIN an interrupt message carrying the vector, the GF= ID, + and the destination enables from its control register. + 2. In the tree of each destination that the message selects, GIN sets = bit + (vector % 32) of LEAF(vector / 32). + 3. If the vector and its subtree are enabled in the CPU tree, GIN rais= es + the PCI interrupt. + +Because firmware assigns the vectors, nova-core does not hardcode which ve= ctor +belongs to which unit, with two exceptions. The hardware headers of every +supported part define the GSP event as vector 155, and GSP firmware's own +interrupt table uses that definition. The CPU doorbell is vector 129. Pre-= Hopper +hardware fixes that number, and GSP firmware keeps it on Hopper and later. +nova-core names both by number. A driver can fetch the full unit-to-vector +table from the GSP by RPC, and nouveau does. nova-core does not, because a +fixed vector needs no lookup. + +Edge-triggered delivery +----------------------- + +A ``LEAF`` bit is a latch. Its source sets it on a rising edge, and it sta= ys set +until the CPU clears it. A source that stays high does not set the bit aga= in. + +GIN raises the PCI interrupt for a subtree when the subtree's enabled pend= ing +state goes from low to high:: + + Per vector, in leaf i at bit b: + LEAF(i)[b] AND LEAF_EN(i)[b] + + Per subtree N, across leaves 2N and 2N + 1: + OR of every enabled pending bit -> TOP[N] + + Delivery for subtree N: + TOP[N] AND TOP_EN[N] -> rising edge -> PCI interrupt + +``TOP_EN`` applies after the summary, so disabling a subtree stops delivery +without changing what ``TOP`` reports. + +Three consequences: + +* Code that must find every pending vector reads the leaves. A vector that + latched while disabled is not in ``TOP``. +* Writing ``TOP_EN_SET`` for a subtree with an enabled pending bit produce= s a + new edge. GIN delivers an interrupt for a pending bit left uncleared as = soon + as its subtree is enabled again. +* A source that holds its signal high produces no new edge after the CPU + clears the leaf bit. Such a source has to re-emit its interrupt. The fal= cons + do that through ``INTR_RETRIGGER`` (see "Retriggering a falcon"). + +Delivery over PCI +=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D + +GIN delivers the tree's interrupts to the CPU as MSI or MSI-X, whichever L= inux +grants. nova-core requests MSI-X first and falls back to MSI, and never us= es +INTx. + +MSI has a single message, and every subtree raises that one message, so one +Linux IRQ serves the whole tree. + +MSI-X gives each subtree its own table entry, at the index equal to the su= btree +number. Linux masks every entry until a driver requests its Linux IRQ numb= er, +and a masked entry sends no message: the GPU records the interrupt in the = MSI-X +pending bit array, where it stays until Linux unmasks the entry. An entry = that +the driver never requests is never unmasked. A driver that enables a subtr= ee +without requesting that subtree's entry loses every interrupt from that +subtree, with nothing reported: the leaf and TOP registers show the vector +pending and enabled while no handler runs. + +The serviced-subtree invariant +------------------------------ + +Every subtree enabled at ``TOP`` has an allocated PCI vector with a regist= ered +handler. + +MSI satisfies this with its single message. MSI-X needs one allocated entr= y per +serviced subtree, and a PCI allocation cannot be sparse, so nova-core requ= ests +entries 0 through the highest serviced subtree:: + + MSI-X, with subtree 2 serviced: + + subtree 0 -> entry 0 allocated, no handler, stays masked + subtree 1 -> entry 1 allocated, no handler, stays masked + subtree 2 -> entry 2 handler here, and its rearm covers subtree 2 + + MSI, with any serviced set: + + every serviced subtree -> the one allocated PCI vector, whose + handler's rearm covers the whole service= d set + +An allocated entry whose subtree nova-core does not service costs nothing.= The +entry stays masked, and a disabled subtree raises no interrupt. + +nova-core services one subtree. The GSP event, vector 155, is in leaf 4, w= hich +is in subtree 2. Open RM's headers place its UVM_SHARED interrupt category= in +subtree 2 on every part nova-core supports. The self-test doorbell, vector= 129, +is in the same leaf, and the test allocates its own vectors for it (see +"Self-test"). + +Rearming PCI interrupt delivery +------------------------------- + +A message-signaled interrupt is delivered once per edge, and the PCI side +delivers no further interrupt until the CPU rearms it. The rearm operation +depends on the GPU family and on the interrupt type Linux granted: + +=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D =3D=3D=3D=3D=3D = =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D +Architecture Type Rearm operation +=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D =3D=3D=3D=3D=3D = =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D +Turing through Ada MSI write the configuration-mirror EOI register +Hopper and later MSI clear then set the serviced TOP enables +Any MSI-X clear then set the handler's own TOP enable +=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D =3D=3D=3D=3D=3D = =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D + +The end-of-interrupt register is ``NV_XVE_CYA_2`` in the BAR0 mirror of PCI +configuration space, and the value written does not matter. The ``TOP_EN`` +cycle produces a new delivery edge. The MSI forms cover every serviced sub= tree, +because one message serves all of them. The MSI-X form covers one subtree, +because each serviced subtree has its own entry and its own handler. + +A handler rearms once per delivered interrupt, on every path, including the +path where it finds its vector not pending. A handler that skips the rearm +receives no further interrupts. + +Open RM makes the same split. It writes the configuration-space EOI for MS= I on +pre-Hopper parts, and cycles the TOP enables of the subtrees it services f= or +Hopper-plus MSI and for MSI-X. + +Servicing the tree +=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D + +Servicing a leaf has a required order: read its pending bits, then clear t= hem. +Clearing a leaf before reading it discards every vector latched in it, and +nothing reports the loss. In nova-core, reading a leaf produces the handle= that +clears it, so the wrong order does not compile. The handle clears exactly = the +bits it read, so a vector that latched after the read stays pending. + +A handler clears its bit before it services the vector. Clearing afterwards +would discard an interrupt that the source raised while the handler ran. + +nova-core services the tree in two ways. + +The notification path services one vector. It reads the vector's leaf, cle= ars +only the vector's bit, and rearms. The subtree stays enabled, and a vector +pending beside it in the same leaf keeps its bit set for the code that ser= vices +that vector. The GSP event handler takes this path, and so does the self-t= est +handler. + +The startup drain walks the whole tree, because it must clear whatever is +pending across every subtree rather than one known vector. It disables the +serviced subtrees at ``TOP``, reads and clears every implemented leaf, and +leaves the subtrees disabled for its caller to enable once the caller is r= eady +for deliveries. The drain reads every leaf rather than descending from ``T= OP``, +because sources latch vectors during boot while those vectors are disabled= , and +``TOP`` does not show them. Open RM's stall-interrupt path reads every lea= f for +the same reason. + +The two paths as register operations:: + + Startup drain, run once during probe: + write TOP_EN_CLEAR =3D serviced stop new deliveries + for each implemented leaf i: + pending =3D read LEAF(i) + write LEAF(i) =3D pending clear what was read + (returns with TOP_EN still clear) + + Notification, the subtree stays enabled: + pending =3D read LEAF(leaf) is the handler's bit set? + write LEAF(leaf) =3D bit clear that one bit + rearm PCI interrupt delivery + +The drain clears every pending bit, including bits that nova-core never +services. An uncleared bit holds its subtree in the pending state, and ena= bling +that subtree again would deliver an interrupt for a vector that no handler +services. + +The drain's ``TOP_EN_CLEAR`` is not a rearm, and pre-Hopper MSI rearms thr= ough +the configuration mirror, which the drain never writes. An interrupt deliv= ered +before probe had no handler to rearm it, so the startup sequence rearms +explicitly after the drain. + +Nothing in nova-core serializes access to the tree. The GSP event handler +touches only its own leaf, and the drain runs during probe, before that ha= ndler +is registered. + +Per-architecture differences +=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D + +The tree is the same on every supported GPU except for its size, which cha= nges +at Hopper: + +=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D =3D=3D=3D=3D=3D= =3D =3D=3D=3D=3D=3D=3D=3D=3D =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D +GPUs Leaves Subtrees Implemented subtrees +=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D =3D=3D=3D=3D=3D= =3D =3D=3D=3D=3D=3D=3D=3D=3D =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D +Turing, Ampere, Ada 8 4 ``0x0f`` +Hopper, Blackwell 16 8 ``0xff`` +=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D =3D=3D=3D=3D=3D= =3D =3D=3D=3D=3D=3D=3D=3D=3D =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D + +The interrupt HAL provides the leaf count, and the subtree count and the +implemented-subtree set derive from it. A subtree that the part does not +implement has no TOP bit, so building a tree that services one fails with +``EINVAL``. Vectors 129 and 155 are in the 8-leaf tree, so every supported= part +has them. + +Open RM's headers assign every interrupt category of a 16-leaf tree to lea= ves 0 +through 11. The drain reads all 16, because a vector can be latched in any +implemented leaf. + +The HAL's other value is the rearm method (see "Rearming PCI interrupt +delivery"). Two falcon properties also differ by family and have a HAL of = their +own. Turing falcons have no ``INTR_RETRIGGER``, and the RISC-V routing +registers moved at GA102 (see "Retriggering a falcon"). + +The GSP event +=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D + +When the GSP has output for the CPU, it writes messages into the GSP-to-CPU +queue in shared memory and raises SWGEN0, one of the software-generated +interrupt causes of the GSP falcon. SWGEN0 is routed to the host, at vector +155, leaf 4 bit 27, in subtree 2. + +The queue carries notifications (log records, error records, lifecycle eve= nts) +and command replies. A thread waiting for a reply reads the queue itself, = so +the interrupt is only the trigger to drain the queue (see "Draining the +GSP-to-CPU queue"). + +The falcon latches every cause it raises, SWGEN0 among them, in its +``IRQSTAT`` register. The handler services the host-routed causes and clea= rs +their latches, and then it writes ``INTR_RETRIGGER`` so that the falcon +re-emits any cause that latched in the meantime. "Retriggering a falcon" h= as +the details. + +Draining the queue takes the command-queue mutex and walks shared memory, = so it +cannot run in hard interrupt context. nova-core registers a threaded handl= er, +under the name ``nova-core`` in ``/proc/interrupts``. The top half runs in= hard +interrupt context and reads and writes only registers, and it wakes the IRQ +thread to drain the queue:: + + GSP writes messages into the GSP-to-CPU queue + GSP raises SWGEN0 + GIN sets bit 27 of LEAF(4), and subtree 2 becomes pending + PCI interrupt -> Linux IRQ -> top half, in hard interrupt context: + read LEAF(4), and if bit 27 is clear, rearm and return + clear bit 27 (the subtree stays enabled) + read the falcon causes routed to the host, clearing SWGEN0 if set + for every other host cause: log it, clear its latch, and read the + host causes back + if the clear ended all of them: retrigger the falcon + otherwise: disable vector 155 at its leaf and skip the retrigger + rearm PCI interrupt delivery + wake the IRQ thread if SWGEN0 was set + IRQ thread, which may sleep: + take the command-queue mutex and drain the GSP-to-CPU queue + +A halt and a posted message can be pending together, so the top half servi= ces +every cause that the status reports. + +A drain fails when a message's framing or checksum is bad, which poisons t= he +queue (see "Draining the GSP-to-CPU queue"). Every later event would fail = the +same way, so the IRQ thread disables vector 155 and logs the failure, which +leaves the queue unserviced until the device is reset. + +The handler, the self-test, and the rest of the driver read BAR0 through o= ne +shared mapping. nova-core unregisters an interrupt handler when the device +unbinds, so a handler runs only while the mapping exists. + +Retriggering a falcon +--------------------- + +A falcon signals the tree when its set of host-routed causes goes from emp= ty to +non-empty. A cause left latched keeps the set non-empty, so no later cause +signals the tree, and the vector is lost. For a cause that stays latched, = the +handler can clear the tree leaf first or the falcon latch first, and the l= oss +is the same. + +``IRQSTAT`` latches every cause in the falcon, including the causes routed= to +the falcon's own RISC-V core and owned by the firmware running on it. A ho= st +handler owns only the causes that ``PRISCV_RISCV_IRQMASK`` and +``PRISCV_RISCV_IRQDEST`` both select, so it intersects ``IRQSTAT`` with bo= th +before it reads or clears a cause. Open RM computes the same intersection = in +``kflcnRiscvReadIntrStatus``. GA100 keeps the Turing offsets of the two ro= uting +registers and GA102 moves them, so the offsets change at GA102 rather than= at +the Ampere boundary. The handler masks no cause: ``PRISCV_RISCV_IRQMASK`` = is +read-only to the host, and ``FALCON_IRQMASK`` has no effect on host routin= g on +a RISC-V falcon. + +``INTR_RETRIGGER`` makes the falcon re-emit its host-routed causes into the +tree, which supplies the transition that clearing the leaf lost. The handl= er +writes ``INTR_RETRIGGER`` only on a path where it ended every cause that it +read, because a re-emitted cause that nothing clears arrives again at once= and +on every pass after that. + +``IRQSCLR`` ends a latch and does not end the source behind it, so a cause +driven from outside the falcon stays set after the write. On Blackwell the +fault-containment and ECC causes are driven that way: they appear in +``IRQSTAT`` but come from ``PRISCV_RISCV_FAULT_CONTAINMENT_SRCSTAT`` and +``PGSP_ECC_INTR_STATUS``, and only a device reset ends them. So the handler +clears the latch of every host cause other than SWGEN0, reads the host cau= ses +back, and retriggers only when the read-back is empty. When a cause is sti= ll +set, the handler disables vector 155 instead and reports that the device n= eeds +a reset. Disabling loses no notification: the cause that is still set hold= s the +host-routed set non-empty, so the falcon would signal nothing further eith= er +way. Open RM makes the same choice, and ``kgspService_TU102`` skips +``kflcnIntrRetrigger`` once it has recorded a fatal error. + +A fault cause that arrives after the clear cannot be told apart from one t= hat +the clear failed to end, so the handler disables the vector in that case t= oo. +Both mean the GSP has faulted. + +Turing falcons have no ``INTR_RETRIGGER``, so a Turing handler cannot re-c= reate +a transition it has lost. It must leave no host cause latched: it reads the +host-routed status once and takes every cause that the status reports, rat= her +than stopping at the first one it recognizes. One window stays open. A cau= se +that arrives after the handler has read the status is not in the value the +handler clears, so it stays latched after the leaf has been cleared, and no +later cause from that falcon signals the tree. Open RM has the same window= on +Turing, where ``kflcnIntrRetrigger`` does nothing. + +Enabling the GSP event +---------------------- + +SWGEN0 is a latch, and the GSP drives no new edge into the tree while it s= tays +set. nova-core's GSP boot code consumes the GSP's notifications by polling= the +queue, which leaves the latch set and leaves pending bits in the tree. The +handoff from polling to interrupts has a required order:: + + disable every implemented vector drop enables left by boot, or by a + driver that ran before this one + drain the tree clear stale pending bits + rearm PCI interrupt delivery required under pre-Hopper MSI, whe= re + nothing else does it + clear the SWGEN0 latch so the next message makes an edge + register the threaded handler nothing can reach it yet + enable subtree 2 at TOP the drain left it disabled + enable vector 155 at LEAF(4) deliveries become possible here + drain the GSP-to-CPU queue messages posted before the clear + +nova-core quiesces the tree before it registers the handler. Registering +unmasks the PCI interrupt, and GIN would then deliver a vector that boot l= eft +enabled to a handler that services one vector and has no way to service any +other. Open RM clears every leaf enable at the same point for the same rea= son. + +nova-core clears the latch after the drain. If nova-core cleared the latch +first, a message posted before the drain could set it again, along with bi= t 27 +of LEAF(4). The drain would then clear the leaf bit while the latch stays = set, +and no later message would signal the tree. Clearing after the drain can +instead leave the leaf bit pending with the latch already clear. Enabling = the +vector then delivers one interrupt whose ``IRQSTAT`` reads zero. The top h= alf +clears the leaf bit, rearms, and does not wake the IRQ thread, and the que= ue +drain that follows reads the message. + +Clearing the latch makes the first interrupt possible. A message that the = GSP +posted before that clear produces no interrupt, so the sequence ends by +draining the queue. + +The subtree is enabled at ``TOP`` once the handler is registered. The drain +left it disabled, and under pre-Hopper MSI the rearm is a configuration-sp= ace +write that does not enable it again, so the enable is explicit. On teardown +nova-core disables the vector at its leaf, so that nothing in the subtree = can +be delivered, then calls ``free_irq()``, and disables the subtree last. +Disabling the subtree earlier would let a handler still in flight enable it +again through the ``TOP_EN`` cycle of its rearm, which would leave the sub= tree +enabled with no handler registered. nova-core tears down the registration +before it frees the queue that the handler drains and before it unloads the +GSP. + +Draining the GSP-to-CPU queue +----------------------------- + +The queue carries command replies and unsolicited events, and a message's +function code says which it is. + +* A function code that matches the awaited reply: the message is decoded a= nd + returned to the caller that sent the command. +* Anything else is an event. An OS error record and a robust-channel record + are logged at error level, and an unrecognized function code at warning + level. The other known events (GSP logs, libos prints, assertion records, + lifecycle notices) need no action and get no line of their own, because = the + receive trace at debug level already records every message's arrival with + its sequence number, function code, and length. + +The sequence number takes no part in the match, because the GSP does not e= cho +the command's sequence number on every reply. On r570 the reply to +``UnloadingGuestDriver`` carries sequence 0. + +The read pointer advances past every message, whether it matched, was an e= vent, +or matched but failed to decode, so a message is never left at the queue h= ead +for the next receive to parse again. + +Corrupt framing is the exception. A message's length is inside the region = that +the checksum covers, so once the framing or the checksum fails there is no +trustworthy length with which to skip the message. Such a failure poisons = the +queue: nova-core logs it once, and every later receive fails with ``EIO`` = until +the device is reset. + +The polling path and the IRQ thread both read the queue under the command-= queue +mutex. Replies and events share one queue and one read pointer, so one loc= k is +held across the whole drain. A thread waiting for a reply logs each event = that +arrives before the reply and keeps waiting. One deadline of 5 seconds appl= ies +to the whole wait, rather than a fresh timeout after each message, and the +thread holds the mutex for the whole wait, so no other caller consumes the +message it waits for. + +With one lock, a drain waits for an in-flight command's receive to finish = or +time out. For log and error records that delay does not matter. + +Self-test +=3D=3D=3D=3D=3D=3D=3D=3D=3D + +The self-test confirms that an interrupt injected at the GPU is delivered = to a +registered handler. It runs during probe, after the GPU's boot firmware, G= FW, +has completed, and before nova-core boots the GSP, because the test disabl= es +and drains the whole tree, including the GSP's leaf. The test is built only +under ``CONFIG_NOVA_CORE_SELFTESTS``, like the other probe-time hardware t= ests. +Those other tests log a failure and let probe continue. A failed delivery = test +fails probe, because an interrupt path that does not work leaves the driver +unable to make progress later, in a place that says nothing about the caus= e. + +The test writes ``LEAF_TRIGGER`` with vector 129, the CPU doorbell, at lea= f 4 +bit 1. The vector then takes the ordinary path to the CPU under the ordina= ry +enables. The doorbell keeps the same number on every supported part, so the +test names it without asking the GSP, which is not running yet. + +The test allocates PCI vectors for subtree 2, disables every vector, drain= s the +tree, and checks that the doorbell bit starts out clear. It registers a +non-threaded handler with a completion, under the name ``nova-core-selftes= t`` +in ``/proc/interrupts``, and enables the vector and the subtree. It trigge= rs +the doorbell, waits up to 1000 ms for the first delivery, triggers it agai= n, +and waits up to 1000 ms for the second. The handler takes the notification +path: it clears only its own bit and rearms, and never walks the tree. + +The test triggers twice, and the second trigger waits for the first handle= r to +finish. One delivery would prove nothing about the rearm, because the first +message-signaled interrupt arrives whether the driver rearms or not, and t= wo +triggers in a row could coalesce into one delivery. A handler that walked = the +tree would prove nothing either: on every configuration except pre-Hopper = MSI +the rearm is a ``TOP_EN`` cycle, so a walk that enabled ``TOP`` again would +rearm delivery whether the handler asked for it or not. + +The test passes only if both deliveries arrive, each finds the doorbell bi= t and +nothing else pending in leaf 4, and the bit is clear once the vector is +disabled. Anything else fails probe. Requiring the exact pending bits on t= he +second delivery shows that the first handler's clear reached the hardware.= No +other vector in leaf 4 can be pending, because the test disabled every vec= tor +and runs before GSP boot. + +The test releases its PCI vectors and its handler before returning, so the +driver's own allocation covers the GSP subtree and nothing else. Sharing t= he +driver's allocation would have let the test pass only because the doorbell= and +the GSP event happen to be in the same subtree. + +The test exercises the path from the GPU to the handler without GSP firmwa= re, +which helps when bringing up PCI, MSI, MSI-X, and passthrough setups. Under +MSI-X a pass also shows that the delivery arrived on the entry belonging t= o the +serviced subtree. + +The parts with no hardware dependency have KUnit tests instead: the vector +arithmetic, the leaf and subtree sets, the per-architecture leaf count and +rearm method, and the falcon retrigger and routing HAL. + +Register naming +=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D + +nova-core uses the ``NV_VIRTUAL_FUNCTION_PRIV_CPU_INTR_*`` names for the C= PU +tree on every supported part. That is the per-function aperture: each PCIe +function reaches its own tree through it, at the same offsets. The control= ler +also has a central aperture that exposes every function's tree. The pre-Ho= pper +headers name it ``NV_CTRL_CPU_INTR_*`` and the Hopper-plus headers +``NV_GIN_CPU_INTR_*``. nova-core does not use it. Open RM's kernel-side co= de +for the controller is the ``Intr`` object. + +Scope +=3D=3D=3D=3D=3D + +nova-core services the CPU tree of one function and nothing else. It imple= ments +no virtual-function tree management and no GFID routing, which belong to t= he +physical function's driver or to firmware in a virtualized setup, and no M= IG +(multi-instance GPU) support. It services none of the subtrees that the +hardware headers reserve for the stall interrupts of the host-driven engin= es. diff --git a/Documentation/gpu/nova/index.rst b/Documentation/gpu/nova/inde= x.rst index 59b206238498..224caef9ea42 100644 --- a/Documentation/gpu/nova/index.rst +++ b/Documentation/gpu/nova/index.rst @@ -35,3 +35,4 @@ vGPU manager VFIO driver and the nova-drm driver. core/falcon core/tlv core/pramin + core/interrupts --=20 2.55.0