From nobody Sat Sep 26 08:48:41 2026 Received: from CH5PR02CU005.outbound.protection.outlook.com (mail-northcentralusazon11012035.outbound.protection.outlook.com [40.107.200.35]) (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 3BBEA34D4D6 for ; Thu, 3 Sep 2026 03:15:26 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=fail smtp.client-ip=40.107.200.35 ARC-Seal: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788405327; cv=fail; b=K9lQmPFUbTb/vC7dBF2WSfqEMTQMn+KEjeX2pfYx+EoI1MyUH/TR68dCusmK91UjUUshsXfqJ1xkDz6+6JDnjlmvzZ+hZ2FKR0PiZC2xEyRRynU8ZXSLQn6vWyNQsRpLQUaGLa2UXqC6AD+r1Zii8NxFTsKc/FASYYhNKbAU9ok= ARC-Message-Signature: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788405327; c=relaxed/simple; bh=KQ75yHSFfpsOyDfBhLjPMYd6QBwvnzKlPz0Ws/YtzJY=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: Content-Type:MIME-Version; b=lm9OxOUmWkc12eSgPD1bZjVoiZodq2WCzjefsWz9dgzD3hzMecnrHFET65F+fd7gD5OnZVewRWE7DvyU82wCfe2VHeHZi0iceERzyY9f6FS7ApisbG9TVZcWIPXGwwoR39Turvkh+Vi3p1G+tES/emH2HG+kbHrY8ndmrMrRdlc= 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=EISpLgEm; arc=fail smtp.client-ip=40.107.200.35 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="EISpLgEm" ARC-Seal: i=1; a=rsa-sha256; s=arcselector10001; d=microsoft.com; cv=none; b=czP1lrvGl2i4cDuen37FmiyvcDOL1Jr6MuzpH5T0kAlK709oQj5QkTToBdUtudWLCiw7YOUdxlJ2JEn62vbtYb2ZmsP76vNlchD3dzpfdspplYax2d/tGUVn+jJW1tKfC75IR+Wi1BOEPgrsRHvLByFPgW7EFVFP21bu8tnpfP5Nn64NWV5d4fftIEu+kvDNb5JXERjLKBaoibTIetxAhNm+Yo/uulDEwtfMF/Ht1fPEcZhJBAbNfON4v0ZibG67sFTypDR0KkCwsVrNYZi9qSUm88b+0zThlP47c2qf0dICuvEXJGaERNHGAYj8wi96yj4SH8l2sykmUEm7LP0w+A== 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=WwTDeNvt5DDrAccdOy4BGTB/gQVf6GhGCA9/1nCiSBNz5e2EF1oRVqKvUvcdBzzOsx3qcMI3EpJJTgzSVsWzgxoPr5gG5Q1CBe8FmDIXGALTW5iiWpG0QjzbgamFTY+3Gyr1Ep2SsQQLT02C5zc5pDPhxda4vXLPHEvlX4/PgH0DJo5bGOO9NMN2mE/VaKkA7dqhmQRU8ZVJNsgoMSbeTqDv/B4l+JM7AReq+NG+mmgtMCra0wpIiNz4r6g1LlpGX7MAMSOmqNNHAXQQ6y/Yp9SPua6Tz7GHHsOut4OsHBPZ357AJez+Dsal8hoU+ot/Y9eSWjvb7DPJYIxiB6Hr/w== 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=EISpLgEmtgbSzhitm+Gl6pvddE3YIeds0tVWOmemOw1ak0dw7O31l589vN/4/pIf2GJG5iO56M8327DZHEZQbMqhao6eSRe50Mynw3/oHSCy99Kr8nESgidmn7HbeR2CHemIPjtq+Qs2nByY/hsuRE2B0fNpByIvIndi91KmfUZbRtS3xaHyUDlFQH4XZByovEd1Ksfj0M1W5J8tMclqx+ik9X53BCXicAtH3kbkQQWPcSOWswAhleZvi+tfEx8Ne76FIxswX2ArzR8+EQ6/MFLihZcsVGYsv54Pp7ZZeEeLqg77QlslLbFMyXSUm5/7KlcgvlEybOCo79eQotXf6w== 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 SJ2PR12MB9138.namprd12.prod.outlook.com (2603:10b6:a03:565::9) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.21.360.13; Thu, 3 Sep 2026 03:15: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.0360.008; Thu, 3 Sep 2026 03:15: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 , John Hubbard Subject: [PATCH v3 01/14] rust: pci: declare IrqType and IrqTypes with impl_flags Date: Wed, 2 Sep 2026 20:15:00 -0700 Message-ID: <20260903031514.1515905-2-jhubbard@nvidia.com> X-Mailer: git-send-email 2.55.0 In-Reply-To: <20260903031514.1515905-1-jhubbard@nvidia.com> References: <20260903031514.1515905-1-jhubbard@nvidia.com> X-NVConfidentiality: public Content-Transfer-Encoding: quoted-printable X-ClientProxiedBy: SJ0PR05CA0101.namprd05.prod.outlook.com (2603:10b6:a03:334::16) 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_|SJ2PR12MB9138:EE_ X-MS-Office365-Filtering-Correlation-Id: 5cae20ec-3143-4c0e-4055-08df0969959f X-MS-Exchange-SenderADCheck: 1 X-MS-Exchange-AntiSpam-Relay: 0 X-Microsoft-Antispam: BCL:0;ARA:13230040|1800799024|366016|23010399003|376014|7416014|18002099003|22082099003|56012099006|3023799007|10067099003|11063799006; X-Microsoft-Antispam-Message-Info: XYlWSKQfq8vUflb+HDMk7AK31qVjDU1LDTGDJlol6Lf8e1QZYTVLPgmZTUjPcSlYxDkejXtk8BJwWpCL9IOB7kPdhfAeyZzZ5oUxlihR/3sjjo4EvZzZ8JOBEN6K3B5q81dMah8shMum5Mwx/IN7fuSvW8/BaQp5n653poCI5j2n7R20z6I5YOM0Uu9GHUWyzLjXovR6gSWM8lpXZ2KVprYiZWwtKNY+Zg6DjLWnMhRNsBNR1POXb3qSRvSGdRBa44kbkfDpG7yEBUDggnsxsBo2Y9BKMdcNFaBgLGRYJR3b6HhLRlc+Obwufqf/yaZCTSTxqdZZfQbTf5948ZppBawXmA+ylHQNz017nogzedruGjNDuUFKdlE1u8U8ua7pWUmOI2gBqlBUrUX4v4ZCL8iVWCppcQdV0SSbvLwwyVRg1WqT4zb0wNHiwJY43t/3Lg0HCzSK+6rUQ6eJdHbt/uMYsZs/mmCTbe+rKbiRgzcGl1U6IU9+QJy3QdUKS8iA02iHuNzUadDn2jWb+IO+3UuWJ7EE4ZBy8ydxH36DlTECaddh2XdRJzYgIsuzrF75GEyFrqjtWis46ubWZocUvMALUpls1a0NC2YD32+6+UB3lnXqh4M8hhUGsI72807nj511PvcXqb2w1ub2ZRl+OyUD7GEXznK/dKIKSG0T774= 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)(366016)(23010399003)(376014)(7416014)(18002099003)(22082099003)(56012099006)(3023799007)(10067099003)(11063799006);DIR:OUT;SFP:1101; X-MS-Exchange-AntiSpam-MessageData-ChunkCount: 1 X-MS-Exchange-AntiSpam-MessageData-0: =?us-ascii?Q?8g7uXTAQPohhilXJoer9jhTlo1kYZ6KM8EJCkq9cFNklMG9onL9XwOOzeACG?= =?us-ascii?Q?zsCNwMAilby4rKkQZ1CSrxWX+oPXhU2pzeIYyBkaJ/VOsL5o9rhWNQb9MJ4c?= =?us-ascii?Q?uljNWZP8rR931tRhv2RiSABpsJ6+WK+4dt50zh1CuGP2ofcFtKFOmRuApMqN?= =?us-ascii?Q?Stro8fOzoDLsfkjR0c7kVToOvla5BR8ZZ/vW/saaTql6Qh0/9melPWUomt1e?= =?us-ascii?Q?CEORyL1kGsHNrf7cQ/uoidhIRGcfTuo1/BRuvPjBQVjSjJYQbdx8q+/MNmq/?= =?us-ascii?Q?NmgjdzWTNHozfv1e3jmaMDbvU43WWUhuKc3z49ihHwXumVhNI14dcqlJOCFw?= =?us-ascii?Q?+4gQy59ez0OQ6SU9H8Q5uUi9Pe+KfOwTj7GqKmZQ8uhJE0s/dGIn2SmQQ3H3?= =?us-ascii?Q?Tl+LzRK1sp6oSZuQOM4w/rsZpE2ROtzaP6xcvyBDbM+Ba+rW9HSENCLEq+yP?= =?us-ascii?Q?ccBZtjcGdLh8HX5V7ylG6yy9jk4Ne8L0Xfhnc5Ql4Once9RJOp+6am2tN+LX?= =?us-ascii?Q?Wpozz8thCgMvVTNGKEEjRrZSSCxHqHEmvlc/18T1r5adGaMS7D+DsmsvVDFB?= =?us-ascii?Q?L2lWF/0UI1pbTj5IGlzLIryGkH8tEmO6mstcfJGS0RjUvvsWa3mWnnnBbJzn?= =?us-ascii?Q?09HmzkKnag1wsXUsIUb/Cl8Gmka2i3lcZgR9yg0tTbdyPbXbsPN14Kk7PxHX?= =?us-ascii?Q?/jqjMxD92ddZ0YK6GpYlq0fgWm1onbU/9RiNXdNlVOGCZU58XhxIkzDhVZ1C?= =?us-ascii?Q?7XdJvAZ/MFRROy0Nh2c73dTHJg7F/XQy+Qnba62l2dh6Q26Mx+xsrG2tVfFg?= =?us-ascii?Q?OLdzbvNJ84G33f3KqY5Gl+GBLV9fEkJUa46CQVL2uz5kjQrOwKh+mmtwoJ+T?= =?us-ascii?Q?poWPYglzr5dnUh3TyW7V3aoMDGC3plh0MvSZ5na6fxh1erP/yG/uo7ZyMwZH?= =?us-ascii?Q?qUrd+MSnM8cpZi7rb0mzay4eFmEQZ+kJi+YlJP73NaVDJuZvJ5FRj9p0WYRq?= =?us-ascii?Q?aau3URzA23vvjdilpeC7TviEVP6CG9Nl2bR1h4BLgfQpNcQhGhTIHCIpaS2z?= =?us-ascii?Q?TeLf667TlupMPJMFy+325jmdUIbHCFcfPdjbTANjHoi7EiSiYinAyVZwNuNJ?= =?us-ascii?Q?5v5WRNB/rbw+OLKBzwwDbUSDAR0QYwOpn/LP70az+RSCe5E2g0qpMpk7zrtP?= =?us-ascii?Q?ppxtnjsIipZHJZigNVt4kw4z+JE1eKVNH4M9J3J2Ic6qPwvGcDWOX4gqoCZS?= =?us-ascii?Q?wp7XfA1fEkeI6N4lj4TKL/VIB5WHNZSIWykJh8YCKGEMDKaDYO0pOLOae1aO?= =?us-ascii?Q?1PrCRsOcUhz5IPdC32oqD8rK7LTOZc7RDPjJHBVznpgOcy5k1jNyYSdpKBFr?= =?us-ascii?Q?4chdTnz0JJ5R2IAUP+yGZUGJ6iPdhcME9eMS/E41ptArgjiaw1POXnH7EDTi?= =?us-ascii?Q?Qvi5RSRo4PLc4/pzy+QoTLsvjeqH0WIAceHmB4166KPz4z8GfkkPUcy0lWXM?= =?us-ascii?Q?lSQZEgJzIpyz0iaHlf3rGJCxd+qkTP0uJ+PgswjnhRWiTcLk9PpavDA2nMcv?= =?us-ascii?Q?5TxOYYTBMeEiTYXiZ5JaqrTS9so9jr72DWS0ZE/mZYSQpSxQuLntBAnePQ9S?= =?us-ascii?Q?klr6xDnuCW+Pz06tilaPxIZM5FG/Kx6fhrMMqW6to6PCLgTRqQEx4hzLuZLJ?= =?us-ascii?Q?gaPHBy2ffWI4hA934CUxFgqAEv/WqQMum9dYM0QnL1vFGRo84p38e/mbQA3n?= =?us-ascii?Q?mUao14m8GQ=3D=3D?= X-OriginatorOrg: Nvidia.com X-MS-Exchange-CrossTenant-Network-Message-Id: 5cae20ec-3143-4c0e-4055-08df0969959f X-MS-Exchange-CrossTenant-AuthSource: DM3PR12MB9416.namprd12.prod.outlook.com X-MS-Exchange-CrossTenant-AuthAs: Internal X-MS-Exchange-CrossTenant-OriginalArrivalTime: 03 Sep 2026 03:15:19.7984 (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: g/FEpnMNc18otZg/MQtEVSLOuLxGhRknGbY4dgxBwTYdvginU+/vZtWqgcAtxFjxTpZMkpr5UXR2eczbbdfbBA== X-MS-Exchange-Transport-CrossTenantHeadersStamped: SJ2PR12MB9138 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 Sat Sep 26 08:48:41 2026 Received: from CH5PR02CU005.outbound.protection.outlook.com (mail-northcentralusazon11012035.outbound.protection.outlook.com [40.107.200.35]) (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 1045634A78E for ; Thu, 3 Sep 2026 03:15:28 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=fail smtp.client-ip=40.107.200.35 ARC-Seal: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788405329; cv=fail; b=WFC7wDf85GoHtlXWx6prvZz886udLu74NrVF5mojGQTh/yogwL7DvJTVOSPXI2453lvWkNcmYbG/s6CXnI6s/LPuJF+50YoI09keTyKGTbWVTuE+2h59kOvFU5ApGpmoY8hhRWpOQSn3D6RSG2SKHXYfTn9FHj0xqbc9CXJ7SkM= ARC-Message-Signature: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788405329; c=relaxed/simple; bh=PHEEgZlGUSJn8PS45RQxtqM2X4fC4Swm+aR3phUqYHA=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: Content-Type:MIME-Version; b=nxkhAlHuTCtSghxDnFNmp6PaumjehfwEMupwbJ0FK3cQGcVkquQWMAlzpwEUe/Els51lW/rZ4QIcBgPvFVFxu/Z4ZVAjwOzCfGoQQZybcpxqCAkp0reqhh3QbVZ4JO4mniAGo894V/wNiEOqKVkZetkeCOYAWJf+JYR9VB1Aphw= 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=HQ/cIJm5; arc=fail smtp.client-ip=40.107.200.35 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="HQ/cIJm5" ARC-Seal: i=1; a=rsa-sha256; s=arcselector10001; d=microsoft.com; cv=none; b=Rkqqp/OV4YNrJNga3wkK5bkzb1xV81B+q/Ya1co4Go+uyfxi/UBdDw2dWtPbmuaHwPChidX3bWdqLjCOv5TE7NboRGb+1eXvdvKvwTViJy+ofiy2wO4jNrISzysmtARwfj+wGDePAWvZ4Y8wwiHC2Jfw78i0Neu36qvPwCH2VNVlzSunbyQ/rHWpv9GP1Z/xrS4XrYFb8G7wrUpwE9BDn1v+XvQJNJZh0oRUo27mlLJe6+Qe7wBzTDj149WRsxdlGZan0DEJjVUCpuPdLdoY9EtxlTuvdnNXCoZ0QRHhFg0hEV5SRoHQsrUw3FIHcZ/VqPvGkQXpQboxsUMl7hrJnw== 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=zJpgMp5hHjjPrbx4I0I00OpHf3JtEeV0CF0VgqveXUFqELv92msTP11hgnA1EVgJ7r8CyxQKdlY3hCeTKGUxqY32JrEbWGpqOlGEj2neXvmJxh5b+Z5F0VWTQmxrb5O7AXZm3Yr8cljwsl/o0ry4JSdFMtqQvY6GWv93OeLxUk/ZGuwglWtRD/XRykoJA/0gDlhIDuhiOElinb/cWNzpQWcKOGCAFe/n/jauLckbF02FOFiZ1nkfi4NuvNn4qokerPqJjf3rVha8oywK2eG6I/wD3WSNOj6K9hXcmhYTjXC/D+FG6lEcPREN7ILXXjKZ4jgTOLSX/PC67wD3gZTPSg== 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=HQ/cIJm54823YeZCNWUDW9U6MepU8ajLGvg+/Gja25iW32dFlRQqRmNqKkcug78P97hYMAls9NzlXSz4Z1cFCpBk8ggvbGX1NXQOPUnG7QeTcErRPKOMDBHj4j5Ioy9Z/IHoAHxmeIVFtpJoJQ04DQr111uC7jLtyNJLExBnY95VwMP9mWMIdhj7gihziAXar1ejj5Tn6wBjCIkFmag9EUufAQBzDBpAU9413R9oDLH6LZZ8r/Vqn3tgKN9ZSTXwEaDxIkslzvHvuQLvpMBUhOtxs9kVgxRZm5Yt5mH3GEUrjAk9oyUqgp14NUzSUQoHFmI71pWdDxFH+Unxfclasw== 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 SJ2PR12MB9138.namprd12.prod.outlook.com (2603:10b6:a03:565::9) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.21.360.13; Thu, 3 Sep 2026 03:15: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.0360.008; Thu, 3 Sep 2026 03:15: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 , Joel Fernandes , John Hubbard Subject: [PATCH v3 02/14] rust: sync: completion: add wait_for_completion_timeout() Date: Wed, 2 Sep 2026 20:15:01 -0700 Message-ID: <20260903031514.1515905-3-jhubbard@nvidia.com> X-Mailer: git-send-email 2.55.0 In-Reply-To: <20260903031514.1515905-1-jhubbard@nvidia.com> References: <20260903031514.1515905-1-jhubbard@nvidia.com> X-NVConfidentiality: public Content-Transfer-Encoding: quoted-printable X-ClientProxiedBy: SJ0PR03CA0143.namprd03.prod.outlook.com (2603:10b6:a03:33c::28) 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_|SJ2PR12MB9138:EE_ X-MS-Office365-Filtering-Correlation-Id: 560296ca-3701-44c9-04bc-08df0969963e X-MS-Exchange-SenderADCheck: 1 X-MS-Exchange-AntiSpam-Relay: 0 X-Microsoft-Antispam: BCL:0;ARA:13230040|1800799024|366016|23010399003|376014|7416014|18002099003|22082099003|56012099006|10067099003|6133799003|11063799006; X-Microsoft-Antispam-Message-Info: mSTRl7aVhOaREij9r6Js0f8d8QRTCmdTFExiW4iqTNobQuMwAAgKOE+/lbpL9R/Es5vASUhshM+w1GHbKXanFtZNBnFU4lE7Oywi42x0enwNBeR6XqJP4rgDl2l9Yam35d82Eh5+4Va+6/jVdm8/ezeHxrGnlgkTqqhLr4M2VMqKgXkFMPVgo+W/qGtm0qrFNqviSD51v3mm93gi7YRQvPK3nuvvseF82iE8ez8cwcYbwpERhmbP3WrPQTfXHW5sJP39YkqsX1C0Oh5g3nTIxjS/n0BhxPWV2mfxhtx8Vpt9H4v0c7JnvfEJzGhoK2qKkOjDuhZQqdvWkGScVzLdSVHtAXr2jp23DJnQseRheQBeyRHoPZvDp1W7hhrrC1ZgtC3le/qTppXU5CAvFGSF+PQ8W+lY715OoySujTDs/uXNlOiZryC8EG1eDfz2uwZ7XgtAqYrUJjhQHqnG4qCPidO0hsdj2MtyDygN1wQC/3wKelL0IDaZ6osaMhNK7ay+X1nHvtedPAfnl7ug4OvJCpfu+WPAmkXeTxh5hqDF5cHEadIAZc8uj+eIZDtg6E8z/KQAVVfa9piyCc8bupCn2AxJwbuAVCb/SRQsOBEQHXPIv6xaKDlxWxDtJj4lax2Rzf6wNtQfUb3u2M9IbGHEIP0CiOOX8hzg/Yo7ymqnVlg= 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)(366016)(23010399003)(376014)(7416014)(18002099003)(22082099003)(56012099006)(10067099003)(6133799003)(11063799006);DIR:OUT;SFP:1101; X-MS-Exchange-AntiSpam-MessageData-ChunkCount: 1 X-MS-Exchange-AntiSpam-MessageData-0: =?us-ascii?Q?3MaRvl26RjlsoIAA20kFy4JXRnW0/etJkqgS8g/W5mhQc2SZPS27JdBbzEWi?= =?us-ascii?Q?Rq7a9mxP9dqZl+PCUztfdPN6Ny0+ioGUkJIx7Iq8dyfOsYj0Yu6TadE7KYHn?= =?us-ascii?Q?EBgsAiPVk9d/5+sUwfH5S1rwDH7QgzlTnTGu+/Akr4E6NoNqYGUeM+hqILSA?= =?us-ascii?Q?Pnk62X3PtkczRecdvatSllv4sM/QDVTq/rYNSBg85lhSPCsxLhw4loAtqv4h?= =?us-ascii?Q?HLLKpu6MrS1SjDqipQVPzvm5boagCIB3Ba/JJLAXqYdRCI6kDZh1ditbgxi8?= =?us-ascii?Q?b210XzI204egBzY6qrPnaAUxiJXHWLXJSAAedt2LX3EBYbqi+qB5xixzjwar?= =?us-ascii?Q?WmQXCKP6jpHWkoU1IUQXNGOJIkPoT0tJDEUDPCUr/RN5ZCObQBLvFLUjJjSx?= =?us-ascii?Q?iYEXjUkhMEgP68LuZNFeF1pgvsifHavn/sPy+7KD9AbDUMZfXIyJ9ZeoQJC8?= =?us-ascii?Q?RJAZ/1nfOI5IGlIbdPKZtlGLGkH/chy64kAeRdfUGVOV4/PCd6l2G0N3urAb?= =?us-ascii?Q?M/+0Yzjst8t+6F94N8f9o1Hxl/9k8Uaxx4k1l4vDHgzPt7g7mAgN+vXyoPnx?= =?us-ascii?Q?bwAukEkFc9FSqYXjc0t9AEMWXoFFhdN1MHz1JHWdjreqJAtJXWThTNU43o7/?= =?us-ascii?Q?0kD0RpfFzJPyihyGpwyRJHPcVAQJnSAajtce5huktG4m+oYYFzAkmL6vlMLc?= =?us-ascii?Q?RJq5w7YziedF8JXwVb9Frys8Wq+LqjNw7uVgVUtgOfSvUaOyREifRiJlO8t0?= =?us-ascii?Q?GtRio9G7ff4hm+i1UggfEnd2z1L2xji1hsYV4Nm6RiZkKFDXmT/K/8haIAZH?= =?us-ascii?Q?YfzTyhgkGQG86AxuQdaPOvOmFJGX9diqlESa5as6QwfhCUVZn4+DOpAiplLL?= =?us-ascii?Q?5XBjytfsTiREu5aOnMUOkoSJgXSuMVU0UmRFPLraciL85R7Xk77XKg6z5jqW?= =?us-ascii?Q?WytsAduMlSEqdkIaknb47zvlj2NjvObU02626DjzxgGMg16qK14VvSivr12d?= =?us-ascii?Q?vXKfkk8icYLKnSWwgP1hE8WMZS8h0LiWgq0UDgtZwwSXEn5z1vD+Zjgl8hp1?= =?us-ascii?Q?Ns1Or0KzsGZGpWn/QTYeYTuCZ4S5S9NPbH6G9wdHYHf9tSTSZSflKNXWBp7F?= =?us-ascii?Q?sEtWW7s1ub3zlie9AcC++2mKzB5FXRyvbnG6RnXwcr9Sw3/nZSVN80xOQUeR?= =?us-ascii?Q?Yugq+SlMQbftJkL/xc4pXohE7R2k5CuXwqrR55TjQREhzoioBPe4tKWmpSia?= =?us-ascii?Q?jFI97cFS/hm/iEte2Yd/dxAVjqNe3nFdr1p93yiuydvY5a0XxUpWDU0vIL9s?= =?us-ascii?Q?yiOdok4qEuoWSnXxHhX3XF2mI1JLSoh8ItQfsEBti+OP7uxCXhlIt2dQ4cOY?= =?us-ascii?Q?007woq3IxJTEviCuiQtjSpbneqbJ5/amk/wZvftNFedRkP3ye0gSV+GTMrdK?= =?us-ascii?Q?s5/8ZqsC4PaODgI2LCg0BlCotksv+0GrrrBKWwBXoMioh/S4QQkBQq5kLhfc?= =?us-ascii?Q?AP4RZRZDruzez7fl+Rms7cXsZFues+vzqKuy7ku87X4LGxLEaRGr4xptWvTN?= =?us-ascii?Q?TZ0iZGDb0G6j1Kfr9yuFqpivYkJWpMD4xDK2eW6DxOuixg7j0/v/oFLs8kry?= =?us-ascii?Q?YkyPS8SAW01H9PwSy/+lrLhmxCwfVJogx6Kd4ISkszn2uRzhjxtBOrpA7gHd?= =?us-ascii?Q?HYbwgH51qoSzZ1GYUlHSYO9h3aHoedFT0llc8oNsez+PaqZtOPORWs5A7h2q?= =?us-ascii?Q?ctT9U+0+gw=3D=3D?= X-OriginatorOrg: Nvidia.com X-MS-Exchange-CrossTenant-Network-Message-Id: 560296ca-3701-44c9-04bc-08df0969963e X-MS-Exchange-CrossTenant-AuthSource: DM3PR12MB9416.namprd12.prod.outlook.com X-MS-Exchange-CrossTenant-AuthAs: Internal X-MS-Exchange-CrossTenant-OriginalArrivalTime: 03 Sep 2026 03:15:20.8251 (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: Evg0KMH0ee/nhPMi3zW3tXihQ58vAFC0wv8KUFdVrWNR30qJKHaEpn2PhAqVIf4NBOAFdxDX/biMDXuVH6HL4w== X-MS-Exchange-Transport-CrossTenantHeadersStamped: SJ2PR12MB9138 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 Sat Sep 26 08:48:41 2026 Received: from CH5PR02CU005.outbound.protection.outlook.com (mail-northcentralusazon11012035.outbound.protection.outlook.com [40.107.200.35]) (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 B94B135C6AC for ; Thu, 3 Sep 2026 03:15:29 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=fail smtp.client-ip=40.107.200.35 ARC-Seal: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788405331; cv=fail; b=ZgkzDv5U50YTvpepiQtkirF92o90aNEbI+UOiMHUr4ExWqrUhhpZePzOGyltsO5edHIjhrSF6SUX3FQGobfNmwKiEvpIq9Pk+de/vKtpOReM4+McuY/gFl/EsMpLw/ETDTdSQ43n7fjKoJ/rGunzsVhF85b1yHpD46umcqPQJEQ= ARC-Message-Signature: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788405331; c=relaxed/simple; bh=TMCtK3bhy6CDfQh/0VCfVadB3nSflrRkl6GD9Y9iFng=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: Content-Type:MIME-Version; b=A0ORImbKYEJkuF8pj56jC6uJoK/DnPsZ/ZxDKXHmDFjJVR5dTeYH5tX40qrB9HDUDzElmkqqs6+c+gXXTsv29OHoEtigjtIPYE4EWIFX+RMAEjxHUI8Nr5ZkAzaWgeSR5I3qabYla/EeOuAPL+nP/VpTmYHhuj8zKsSHfUR3XeI= 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=CmqxuXKw; arc=fail smtp.client-ip=40.107.200.35 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="CmqxuXKw" ARC-Seal: i=1; a=rsa-sha256; s=arcselector10001; d=microsoft.com; cv=none; b=lc3pnxavs4xuIV4nzr173vNKGfHfHSBwHLiOS5nwLIxWyN9XaclWtZ6BbWTgkEFbg6NNshdBGFvc6M7KFyqyGvcWzacDJ01gEdITP6OZV3ygG0TACBZfqXE2urr+dPScCJ/Na/qvtMgAEGWO3aZmmHXxdT3lNmELuQ4jJE5gp2MovrGeznlJHFaLGl7N69lVHGKqcPVSoSdqS3nOpaq5LEa3iAXTHKmPMmPEvFFRUsTw7mEA7QeYsfqQVLXBkCmRj6h7Fly/xe3/S0c005Iv6msJYMcXn9NFU/HCatHYzV74j3C4qN0ANqepBGk55+1GnUp+ZGaxpUJZlSAm2zvkAw== 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=KRcAed072HK8PIwEgS6Atlmjfvm0yhBIa95GgSyYudA=; b=nGYB1K7ldoUSShW3P9e14w5CXTcJpTOBRH+bgyxpYE81SUIO2mpDjpeS5lm1PhSpkqrEAPKSukjXDbOVOnNHCj7KipaxXKKTzkMsAoXbfqEIZqJ4fzBTc3JE4M9FhxAJ/xEhOByZuIH9O85qLfeclR+phAoQ3Nj3BgmdEa88GJ3hcZ2R5y6j2lzFz+tIrBXpQZ1fa2wNagvjsWhEuPsO3cu8Jg5b6i1ELZMV0jv4apaHxes6ezCgol/6833V2mQvbB7WjuU3G6tf9lhA8HO6R3MDYOpruFZVdXNuwerwNW6DDm7obmeRPPzHlAExrVNqIicl2q3qBuuzQdcC99BQqg== 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=KRcAed072HK8PIwEgS6Atlmjfvm0yhBIa95GgSyYudA=; b=CmqxuXKwyaVSyQ4ocMfsLZ5hnozp/wDO+JuxCFG2NWfMMDZm41iippFr0SD1wn37FqY2KOSuefd1HpzLeEDdeWaDZtNEPteftvcOlNQ+Ut/xUbNpEaUZ7SLJmVYer1E5zEDfwBeZgC/YWKouuxrCh/ax9GDIVoJtkGt0RtkUvk0oU/eDw9w+h95pVcGCpzH+suHq/vmcNkweaP/wchz5A9DAuLs56dIKHLFB8tRl32qg7e4QMWz+Sp14Ur1TeIr615jlVf6Wi6Le76zfKjQpv85QHmX49lbuo0FLgLt0XRLied5Ui2k4rloAx88t3Bctd/D7Rhk8ABGISmnMGChHdA== 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 SJ2PR12MB9138.namprd12.prod.outlook.com (2603:10b6:a03:565::9) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.21.360.13; Thu, 3 Sep 2026 03:15: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.0360.008; Thu, 3 Sep 2026 03:15: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 Subject: [PATCH v3 03/14] gpu: nova-core: add the GIN vector and subtree newtypes Date: Wed, 2 Sep 2026 20:15:02 -0700 Message-ID: <20260903031514.1515905-4-jhubbard@nvidia.com> X-Mailer: git-send-email 2.55.0 In-Reply-To: <20260903031514.1515905-1-jhubbard@nvidia.com> References: <20260903031514.1515905-1-jhubbard@nvidia.com> X-NVConfidentiality: public Content-Transfer-Encoding: quoted-printable X-ClientProxiedBy: SJ0PR03CA0364.namprd03.prod.outlook.com (2603:10b6:a03:3a1::9) 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_|SJ2PR12MB9138:EE_ X-MS-Office365-Filtering-Correlation-Id: 37db1177-4471-4e2e-5ca0-08df096996df X-MS-Exchange-SenderADCheck: 1 X-MS-Exchange-AntiSpam-Relay: 0 X-Microsoft-Antispam: BCL:0;ARA:13230040|1800799024|366016|23010399003|376014|7416014|18002099003|22082099003|56012099006|10067099003|6133799003|11063799006; X-Microsoft-Antispam-Message-Info: 775EZc+kBbqNCmL9XjBZBuvrzULd6lir9bvk89O+u+nMQgl77VBe94kNO2umVlCgyO+RqXTZWxqeLo+EOdqx3YaEGW1j9x5UQ2JullT/uXqJVYZ5zeW09rleV0gVOUElMDf/URSc0qAx8/ix9ikthObrAmZ4pl7bnHkvc1ZLRtgyQrRqRno6O7e2aPp8s/GJKYdnQ8avCT98nfCbdsMDv8nUcyZNlJnGOOErbjAwSVP3kIYnBAjU3pJk3ie7ejVueFtDa5Cp05d1SGePTnaT4XoZoBfc/70K9FE2iniF2qcSoZ3YIXEOHz0I7uyROmlGUTnfpJEIlY5wLV3UhwPeld7Ss8rlNI7x4K+gpAv2pxGXPwLkZP5ONJ7A6g6Qmol8qliiYmtglEwnIPymr9EJJzNyrmEZBreezhcaxZYwlkOz6NXMPAhDdDjkq0M7SpHhhQOo7Hot1BShi0+wIBtqkdMDVLx5ugk+ZIZ4aP9Dt7eKBD4/Qg7bMwhVO5UcPatej+xF/ovw4QGfZ/N6bzXChPLtuY8X7eHakeln48WpH546PmpxppUFAKmitD10N3ZhnLfiaYcD77KBgekKzQob96/MdbQwNc+Kc5Zw631SVZOHg/fVPFFLYPOxgd7LxLFNEDwVd7Td5EOb0DrJJr0c/w6hlyI4IuyWvqsW+AKPEo8= 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)(366016)(23010399003)(376014)(7416014)(18002099003)(22082099003)(56012099006)(10067099003)(6133799003)(11063799006);DIR:OUT;SFP:1101; X-MS-Exchange-AntiSpam-MessageData-ChunkCount: 1 X-MS-Exchange-AntiSpam-MessageData-0: =?us-ascii?Q?k25R72raHA7WfxTVChhvMIgsrM/xZc4jZU3B0z1CpOjSpIdW3Wwn3nGF0it9?= =?us-ascii?Q?dEBt2hmVdk7EkfDLIRclEBs5IR3ZGJ0UaZHLZni9o/7dU+iO+noCgLG76b6j?= =?us-ascii?Q?yiPoGUh+VFble/ulMjpIjxNm6djRVoaBIIpqW0Be0a7DOOfZ4X5ZIg3ASyLe?= =?us-ascii?Q?U/0PjF3DXFxWpnajKZ+MHrNRdrcBt3cdBCul0LWTf2gmmEDOHtRoWRDN+olt?= =?us-ascii?Q?3mSvzf+T1sLg9QWX/ExTZ1pKNLip21ZKFUDlPV6BYNOOJXBBeeQMVZxqFsV8?= =?us-ascii?Q?mLh8tICfsQR9UQ5NWZFomG3XU2pFS/bdtLBqLr1lk+qSb74MWx/GBR2hpTq8?= =?us-ascii?Q?Z4bkKod+aG8esNqg8faRgkGzdD0I0HZ8FZ+RLz0+5tzOB3Tm3MV8ucZBHsv7?= =?us-ascii?Q?7Z11RfVb2cdjIbH8x9NAAet/UTCmx/K5tsnrJPLo3TV9bnycr2Gb1Dpv4iGy?= =?us-ascii?Q?aoICmzyNVYxjAm1ANloarXeRAJYYMryVuf04BP78Y3BK/+OMkR3Ay3aANL50?= =?us-ascii?Q?kx9c3k1sCVdvcpqCDKyAv372+2ku+HvvXHsCKxmorXsXvZ1CZEGjHUpOUOwN?= =?us-ascii?Q?Cm9hMou0h4oSHisKScCuKR9dQPZLaTW56rRTMsbFuoAw288pNl4bOUOB7BDa?= =?us-ascii?Q?nzu91g5EEpMBzPOpeIfCP0l3lH15QARIVfkT5xgjusCgHr08lTjEQO94xZsv?= =?us-ascii?Q?BDmIjCmhhWuSi3XVW4c2whWAPNutgR8lK7ysP7OMNQhfyk0Ix+OUadiQDXN/?= =?us-ascii?Q?iVxDTYLrZoV0jZ6VPR4ciugA8Hz5tWza2tEJGhq18J65r7QVuS3oOJXcSUQO?= =?us-ascii?Q?1i1MVzMnpcBOfD6EkAP7EvlbBpMxE5K4CU5G0qAVM9dBb0UEnx29VRQ5VB5p?= =?us-ascii?Q?G7g+nz9gBXGajoTpezTNDCfpPDBZO3pPDfqTzRdbpq767Q6KrP0ECnj0dEGL?= =?us-ascii?Q?nEbLhfPBYBYRIAd8FrfMl7OfdRll9KPktyjIBJPh9G2YaqjxbPshdleN0ZY6?= =?us-ascii?Q?mMTzYwpxHMb9kj1okoznFlYo3girgIvMfygumHOqqqOgCCtRhZdv7pI40Xuy?= =?us-ascii?Q?f67BJwZdS463fy0pviEbINVX7vAj+AcsHQwI960xEwE2OPP8doO7D1gGL65L?= =?us-ascii?Q?Q6XXq8/pLVrQBWB+j1zLx07/LWC/BwCEA0mJzABOw8V8hfkS6IRpRu9b/iPb?= =?us-ascii?Q?3qR8McnFt6wkvxYylzyc3cYfxHKFmtX1+loxmPgosAeaDtfbhOzzWPmVh7ZP?= =?us-ascii?Q?kPUIvuVbiTKf1TLo+zLHkF2QKOhR8k3k9P0NFIplifpyYeTee9lIcT9HqAJW?= =?us-ascii?Q?ot7VbIeqGbSYipmG3OFV92aPDZ19ypzB7Fq4VIPGW1uuQSm6A5N7ANSGJg0Z?= =?us-ascii?Q?932H5y/EhXnC1iSly9kbyOO5cnVnCSe8/h9/9D7B0/GnLLqT2rsTY5Ak03uU?= =?us-ascii?Q?ednGUZc+z93SN4vJwGS9Zw7+aUw9pD7DOqegx/PxIi4mpyLRiXEZ+Or5me+z?= =?us-ascii?Q?60aQPayh5RPBWMzDbLWvFCN4lPfw2vK5WD2f9GENrRpuy2vc8rNfjAn2cud9?= =?us-ascii?Q?NB4AldOogRdBWBPOom+AF935si7XnOyxwcbzfd9aWLPIPfw40zkVGieZoZAS?= =?us-ascii?Q?PVJ1A6iYf8zGFkGasRzMnPmCmWnB9g0tURy8mKdBxFFkjtM+ji2/spfPiV5P?= =?us-ascii?Q?eU2qyPFQ1wv0YPsZK3h62qxBfOt4YfT6Fa07k94s+xORlAn83Ie+ewFMHej4?= =?us-ascii?Q?YgD0accvkA=3D=3D?= X-OriginatorOrg: Nvidia.com X-MS-Exchange-CrossTenant-Network-Message-Id: 37db1177-4471-4e2e-5ca0-08df096996df X-MS-Exchange-CrossTenant-AuthSource: DM3PR12MB9416.namprd12.prod.outlook.com X-MS-Exchange-CrossTenant-AuthAs: Internal X-MS-Exchange-CrossTenant-OriginalArrivalTime: 03 Sep 2026 03:15:21.8446 (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: RbRPgvXLhzwkK0OV1ztp3QMjPl1VJlHX+oDn7zjv5ZQY4mTCxaJcNasnXSWwd2BHV/rPU288dvw7QjwA34NKbg== X-MS-Exchange-Transport-CrossTenantHeadersStamped: SJ2PR12MB9138 Content-Type: text/plain; charset="utf-8" A GIN vector's number fixes its position in the interrupt tree: it latches in leaf vector / 32 at bit vector % 32, in subtree vector / 64. A tree implements either 8 or 16 leaves, which sets both its subtree count and its highest usable vector. Each of those is a bare bit pattern, so a leaf mask and a TOP bit are interchangeable to the compiler. Add a type for each: a vector, a leaf index, a set of vectors within one leaf, one subtree, a set of subtrees, and a leaf count. A vector converts to its own leaf, bit and subtree. A leaf count yields the subtree set it implements. Suggested-by: Danilo Krummrich Signed-off-by: John Hubbard --- drivers/gpu/nova-core/irq.rs | 11 + drivers/gpu/nova-core/irq/interrupt_tree.rs | 242 ++++++++++++++++++++ drivers/gpu/nova-core/nova_core.rs | 2 + 3 files changed, 255 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..f27952ff747b --- /dev/null +++ b/drivers/gpu/nova-core/irq.rs @@ -0,0 +1,11 @@ +// 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: a two-level +//! tree of pending and enable registers, one tree per PCIe function. +//! +//! 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..5aa447cf0ec4 --- /dev/null +++ b/drivers/gpu/nova-core/irq/interrupt_tree.rs @@ -0,0 +1,242 @@ +// 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 vector's number fixes where it latches: leaf `vector / 32` at bit `v= ector % 32`, and that +//! leaf belongs to subtree `vector / 64`. The types here keep those three= views apart, so a leaf +//! index, a set of vectors within one leaf, and a `TOP` bit cannot stand = in for one another. + +use kernel::{ + num::Bounded, + prelude::*, // +}; + +use crate::num; + +/// Number of bits a leaf index occupies, covering the `0..16` leaf regist= er arrays. +const LEAF_INDEX_BITS: u32 =3D 4; + +/// Index of a leaf register, bounded to the `0..16` range covered by the = leaf register arrays. +pub(super) type LeafIndex =3D Bounded; + +/// Number of vectors one leaf register carries, one per bit. +const VECTORS_PER_LEAF: u32 =3D 32; + +/// Number of leaves one subtree covers. +const LEAVES_PER_SUBTREE: u32 =3D 2; + +/// Number of bits that address any vector the widest supported tree carri= es. +const VECTOR_BITS: u32 =3D 9; + +const _: () =3D assert!(1 << VECTOR_BITS =3D=3D LeafCount::Sixteen.vector_= count()); + +/// Width of the vector field in the leaf trigger register. +const TRIGGER_VECTOR_BITS: u32 =3D 12; + +/// Number of leaves a tree implements. +/// +/// Every supported part implements one of these two counts, and the inter= rupt HAL names the one +/// its architecture uses. +#[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 { + /// Returns the number of leaves. + pub(super) const fn into_u32(self) -> u32 { + // CAST: both discriminants are 16 or below. + self as u32 + } + + /// Returns the number of leaves, in the type that indexes the leaf re= gister arrays. + pub(super) const fn into_raw(self) -> usize { + num::u32_as_usize(self.into_u32()) + } + + /// Returns the number of subtrees, each of which covers two leaves. + 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 + } +} + +/// 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 of the leaf set. + pub(super) const fn all() -> Self { + Self(u32::MAX) + } + + /// Returns the mask holding the vectors set in `raw`. + pub(super) const fn from_raw(raw: u32) -> Self { + Self(raw) + } + + /// Returns the mask as the value the leaf registers take. + pub(super) const fn into_raw(self) -> u32 { + self.0 + } + + /// Returns whether no vector is set. + pub(super) const fn is_empty(self) -> bool { + self.0 =3D=3D 0 + } + + /// Returns whether every vector set in `other` is also set here. + pub(super) const fn contains(self, other: Self) -> bool { + self.0 & other.0 =3D=3D other.0 + } +} + +/// One subtree, named by its `TOP` bit. +/// +/// # Invariants +/// +/// Exactly one bit is set. +#[derive(Clone, Copy, Debug, Eq, PartialEq)] +pub(super) struct Subtree(u32); + +impl Subtree { + /// Returns this subtree's index within the tree. + /// + /// Under MSI-X this is also the index of the allocated entry the subt= ree raises. + pub(super) const fn index(self) -> u32 { + self.0.trailing_zeros() + } + + /// Returns the subtree as the value the `TOP` enable registers take. + pub(super) const fn into_raw(self) -> u32 { + self.0 + } +} + +/// Set of subtrees, one bit per subtree, in the layout the `TOP` enable r= egisters take. +#[derive(Clone, Copy, Debug, Eq, PartialEq)] +pub(super) struct SubtreeSet(u32); + +impl SubtreeSet { + /// Returns whether `subtree` belongs to this set. + pub(super) const fn contains(self, subtree: Subtree) -> bool { + self.0 & subtree.into_raw() !=3D 0 + } + + /// Returns whether the set holds no subtree. + pub(super) const fn is_empty(self) -> bool { + self.0 =3D=3D 0 + } + + /// Returns the subtrees present in both sets. + pub(super) const fn intersection(self, other: Self) -> Self { + Self(self.0 & other.0) + } + + /// Returns the number of subtrees counted from subtree `0` through th= e highest one in this + /// set, which is `0` for an empty set. + pub(super) const fn span(self) -> u32 { + u32::BITS - self.0.leading_zeros() + } +} + +impl From for SubtreeSet { + fn from(subtree: Subtree) -> Self { + Self(subtree.into_raw()) + } +} + +/// 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 the vector numbered `VECTOR`. + /// + /// Fails at build time if `VECTOR` lies outside the widest tree any s= upported part + /// implements. + pub(super) const fn new() -> Self { + Self(Bounded::::new::()) + } + + /// Returns the vector number. + pub(super) const fn into_raw(self) -> u32 { + self.0.get() + } + + /// Returns the leaf that carries this vector. + 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 the subtree that carries this vector. + pub(super) const fn subtree(self) -> Subtree { + // INVARIANT: a shift of `1` leaves exactly one bit set. + Subtree(1 << (self.0.get() / (VECTORS_PER_LEAF * LEAVES_PER_SUBTRE= E))) + } + + /// Checks that this vector lies within a tree of `leaves` leaves. + /// + /// # Errors + /// + /// `EINVAL` if the vector lies beyond the last leaf such a tree imple= ments. + pub(super) const fn validate(self, leaves: LeafCount) -> Result { + if self.0.get() >=3D leaves.vector_count() { + return Err(EINVAL); + } + + Ok(()) + } +} + +impl From> for LeafMask { + fn from(vectors: Bounded) -> Self { + Self(vectors.get()) + } +} + +impl From for Bounded { + fn from(vectors: LeafMask) -> Self { + vectors.0.into() + } +} + +impl From> for SubtreeSet { + fn from(subtrees: Bounded) -> Self { + Self(subtrees.get()) + } +} + +impl From for Bounded { + fn from(subtrees: SubtreeSet) -> Self { + subtrees.0.into() + } +} + +impl From for Bounded { + fn from(vector: GinVector) -> Self { + vector.0.extend() + } +} diff --git a/drivers/gpu/nova-core/nova_core.rs b/drivers/gpu/nova-core/nov= a_core.rs index 35a8b1214b0e..dfd11dfe562c 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; #[macro_use] mod num; --=20 2.55.0 From nobody Sat Sep 26 08:48:41 2026 Received: from CH5PR02CU005.outbound.protection.outlook.com (mail-northcentralusazon11012035.outbound.protection.outlook.com [40.107.200.35]) (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 E006735F192 for ; Thu, 3 Sep 2026 03:15:31 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=fail smtp.client-ip=40.107.200.35 ARC-Seal: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788405333; cv=fail; b=KhKOaxglt12DzeeXzfwiYTHNhcK9vtlvJBptrqbKN8uGL5s0ssmZtXCLR7HUqd0Ya9ZLjVbVMQPjpaPBJ03hiRxymeJXgEDxr/f49BGhTOaUu7/h7uSpKP+qZMy7CAuZWysEFF6edMRPIqKDsETB3sIGI/54qSKa6n8YVP8tJdk= ARC-Message-Signature: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788405333; c=relaxed/simple; bh=ACRAs1I42HQh8Z9E43NEitgwVNNeK8a2pDJrx4TL0xQ=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: Content-Type:MIME-Version; b=Q/npZfnZKC9As+wEluDye0An/ZrbHwj55BfzFl0qCk/bsTAsyLp36fDqBZOE+igCH945rnH8AMttWFL6b/w3Tyxz9uqKM2PpUREBdvZNBcvw06C7Fx/A08bSHk1w5gxEUAPWVIXsuOmgb64ltE/M2evYmoANlPCJQbB+Fbd8WyM= 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=nVo0RIFO; arc=fail smtp.client-ip=40.107.200.35 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="nVo0RIFO" ARC-Seal: i=1; a=rsa-sha256; s=arcselector10001; d=microsoft.com; cv=none; b=XY6/6uEmlIJHZ6yX2EJjtJqX/JeLnHpO3kQkFUw3inp5UzBHwHoFOCE7gYpNHtW2IU67BBwyrgb1zGwvNuz0+bt7eoifyYHtmwjjXOR1XgcZDUntWLokxWHge40S1/SG94suEjDjyCUNDsZe1BwOd5/KX6fimJA/DXBdkL/Br2onVNu2uK59UE/FRcJ5rvxv52xU2Xob3YXmtHObnMoeoLn4Ul3uEcXql2/f4PQs2MI9wQ0r8oWbhWPmgTtDxKyxKj7AdJetaM9runS7T+REti+ix5JC4a58u21919jmvKlMwQRVlwyx6KJv2/6ErvJRcT299HiXypgruzieR1AX1Q== 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=01NRJNxMW/KRrtZHh24YDLf7YmGRjv0RntqHt1X9Hw0=; b=QP4oTUIGoaSTbtPrrI2+en02x/25yN8eSLjMqHB3Y1GcRvHuDFCEBfmjCzX35vVO7dR72xNWg7alffedWWCqDyAh79RDTr+gOQAAsiVfnMOXYAI7Y6K2NGRzltOzxrJ8TVgfCyYrrUN8AGI5bL+pxHihE63zOWkHkGt6L1ILtuAOzkaLQjeLBS8a7FmgTNbyGcAcu3gJcEbwtycjC5d0v8STg0vTCQFqNbdyJOKFJFjjO53hHiYswVkXTPPxFjpAibrL/BEhSrm+RWMzFFQ0jDwn9Z9yxRRpatXoLGWq2S5tstgHHKxSZrAmt3Djtcq5rh8pysIcn9VruV5MeVBq8w== 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=01NRJNxMW/KRrtZHh24YDLf7YmGRjv0RntqHt1X9Hw0=; b=nVo0RIFOWLGUYvbU3EfwzrYfWXVy809FF4pNBVAzzXZptI0ITOBdV0Nh7l8vQSrOcBfogrcjY0lb+Xq07S6Nl/ooWOmTm6SHKC1EFQGgM7Gj6oJVMMgJenZaXoX5V3DydbX6UpA8kcVM/owi28ezEyON7HHlH3WrzALVawzSZ7ISQkUhEHmsRzVkDbQFZQM6jcGg4pSfpHnz4EBVx4R77zcR3ceXwwo861R2+K/bOpL4kel0jgsoV1tTg5uuAb22LzV0wlxSgHxSxmiat2Bq054RE8X4/enPYMqElz1tMtwc36J0KHXSQon0WD29+GznlD9dRpoXUMHfsHdUsNf50w== 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 SJ2PR12MB9138.namprd12.prod.outlook.com (2603:10b6:a03:565::9) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.21.360.13; Thu, 3 Sep 2026 03:15: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.0360.008; Thu, 3 Sep 2026 03:15: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 , Will Pierce Subject: [PATCH v3 04/14] gpu: nova-core: add the GIN CPU interrupt tree and MSI EOI registers Date: Wed, 2 Sep 2026 20:15:03 -0700 Message-ID: <20260903031514.1515905-5-jhubbard@nvidia.com> X-Mailer: git-send-email 2.55.0 In-Reply-To: <20260903031514.1515905-1-jhubbard@nvidia.com> References: <20260903031514.1515905-1-jhubbard@nvidia.com> X-NVConfidentiality: public Content-Transfer-Encoding: quoted-printable X-ClientProxiedBy: SJ0PR03CA0129.namprd03.prod.outlook.com (2603:10b6:a03:33c::14) 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_|SJ2PR12MB9138:EE_ X-MS-Office365-Filtering-Correlation-Id: edad4694-daa7-409c-2dbf-08df0969978e X-MS-Exchange-SenderADCheck: 1 X-MS-Exchange-AntiSpam-Relay: 0 X-Microsoft-Antispam: BCL:0;ARA:13230040|1800799024|366016|23010399003|376014|7416014|18002099003|22082099003|56012099006|10067099003|6133799003|5023799004|11063799006; X-Microsoft-Antispam-Message-Info: n3yJyiBQIO078ZcQKoLhoCYLClgm83xBK0+KLnRQngipaqKaJAF8UppDDVFSUv4ukHT/UgMJu+HF80XTy1cGeGPbss3+A0ni/5Wep/kJC4OCiZ+WccuJTvlg3oSrMjwT6zFvuJMoa9tnb10374aOgk0SwY+vN+iFpzsqcWnm1VAun/8JTr1z+KKbWRc5tAmevRJAi7gAIg2iWE8XCHoD5nfZ60/UwcdQIcxTdazf8hZ69lMSyHynHOY35N5+TP378mcUx2AxhLRXYRvqjg12znnEaaBTAoS4Fr0RU8kEtSegji9Sgz61lDOl98KIJPm9RxrebCu+qvp787NslrhqPO4saU9+KGhRR1/UEXBF7aPXHz0tC6OdwFqVqvl1vgzNt1TFFW+BJcLliDbQLleKhDNud6Fan7iiO86qk6mR2BbxDHzas6SdPzWfX3OzVsQyFnTMWhqL1TirD6Gjl5vxEFj2wenkCB0PhjBKrB319DKlIKXkM3gOb3V9mqHBzaRcyFUMvtlGW573LhqHB5YIF6Sk4SeEdhl5qrG123AsqUtQ4JSmUOb5ufaWA0/wZZk4BXZElXsk7vuC2UPLMk6QyfZ4B8p9WyBRRWJn2Fn243c5vOytbBYYVbVKrAN4KzdbMb1mEdPVdq+jcrlwQ1QhKq6/7bjQxLAt+ENsabplj6k= 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)(366016)(23010399003)(376014)(7416014)(18002099003)(22082099003)(56012099006)(10067099003)(6133799003)(5023799004)(11063799006);DIR:OUT;SFP:1101; X-MS-Exchange-AntiSpam-MessageData-ChunkCount: 1 X-MS-Exchange-AntiSpam-MessageData-0: =?us-ascii?Q?GNcXZ0+kGMsPWvQ1WApxopRexF9Ph8iwea91jNVdtiqknzZbhTQfUOAQoTwT?= =?us-ascii?Q?CQKyHb7tUu0npbDN9xUdQSFMorXBB4ueRuz+9wfppL3W7crP5H/nxsi9lP2Y?= =?us-ascii?Q?ErnPsoORuFy6/pMZOVRTQAJ+lq7LownpZFpvFnyZaNFh/KHY7Ts9VgQZp7PR?= =?us-ascii?Q?H3YDAfE1ervuKs8aJ8yRBml02mRKJqiiwo3NSIkPIQf/NsJXn15pphnu5DC6?= =?us-ascii?Q?Rq5Z7/x0cE/e/Nv6xA3hzUv8DV8tRJjf2ZaxcPbTYPlV5/NmglfOGcqYDahI?= =?us-ascii?Q?ePfjDTS9+xSeqDAWFNs4mvdoVORQor0OtuEKI1csAU54wh8IwD4mbxLIJXKo?= =?us-ascii?Q?GdP1ncd+kiYYKo9HUSF8nfWLEarWWy+hWgyWVFjKK5EsqmywM8knEaSoNoEG?= =?us-ascii?Q?V3NSY7IeJl1RzD3RKRbmWMae3waweGd9pTB2qsnwLfXNsf8wk5ZRdnbr2NJP?= =?us-ascii?Q?mp3Hkgjun+P4wyGLyrwFTtZuU5RULr/VXeUIb+0F1RjqB0P2Rx0JQ9P9j9LD?= =?us-ascii?Q?WgglFj9ULJ87GE5RRnXeBzw4iiToAIBs/ikfMekz7J0WDIs4ScZ1KGZXF7cO?= =?us-ascii?Q?jDX3GAVJ/Y0f8/dcLWkkM8I/wGqSHSMot73CLKypoURuPQV1js8KCpYYbtWG?= =?us-ascii?Q?JSChIspBVlE5YbtJjcxhPaEIW/1E/FqV3KvtkCT0+tluo7ePboJxmzGDs07Q?= =?us-ascii?Q?dUWhB+LA9tFJAU73bDppAo5hDvqLOrJPrGy2BGAA8XR+MlzdRqlHv1/9goxu?= =?us-ascii?Q?Acp+hZIjE/9lw5A6UuTfn50scPEfDSd+2slqUXsuYoSwEqJ7g54/+8M6aA1Y?= =?us-ascii?Q?V6Z6JeOcacGAmaJNMe1N9yGlkAvoc5aARMv/NrXIvclKkykPhcE974qUh7F6?= =?us-ascii?Q?YvGfgazqUC2nOv3lXZJo1iFanpQyKBm+G1lS+cQglgipcI7sUoVVD5wG/Qqv?= =?us-ascii?Q?DLIfPkCq5qmaDTS2FzqqFEyZdlzcOxbdXOovYGSWOgOIR8hzm46dFJT2GWRA?= =?us-ascii?Q?uFZOg2xFkWk34y13nXWI0PSgEIA6TKz82Er3fvXUNffvLYpFpUuvR6sMCQ/K?= =?us-ascii?Q?Pw8fVZEaiSYRweh7Z4TpeT7hS3WIwonOuc+nKILsZ5EIV4JZh9GI15xN/Cu+?= =?us-ascii?Q?VsZQgcxFLVOgSTBR7fgPTY/6Qb8OjPIjxTm/7nVYhV9uNK9An4w5aEduo+v/?= =?us-ascii?Q?80zn6spPtGQScR1cltbaIHNvw3K3pVyAmqbkTXTB3TsWfJlReP78clwIOsCT?= =?us-ascii?Q?xSR/ZL7tG7Q5dt4GBhD89M8cn6az4bfnzFttqPLLl5egYArCVjs4EkyrpQyL?= =?us-ascii?Q?/VkPPE40YBkxfYTTp5IzdQR9Tg942ERWzNyAFakKOx3pwG1tPuYBgnZLvVhP?= =?us-ascii?Q?GHcish8GzbtZd5GXWJDq436sp2rEqwiDzITi82M7yBUq7kPgad/H0XP9Yu0m?= =?us-ascii?Q?gaWpJYRAlaw7GCsgejCLr5ZOjYysm8WYvkQuRkyO1egV3T4A8etdmr+6dRcL?= =?us-ascii?Q?soX47AJ6BdpLNjrGZLW2HaWhJdop+A6pva8kGT93rsTORk95mfJlIF/WrDRG?= =?us-ascii?Q?EXRNSd6hWHJi/+434OxdkQr6umZ1qnGWdTgPA444wl1FW/rGA4lj4eRyiYKt?= =?us-ascii?Q?1qYBJO+1PBCJXwOorq7HlASLFFsY7sVPEDk7e0RvGIwY6jzsZBpgj7h+E4aY?= =?us-ascii?Q?4fmdvNwvDb122c9oVPwsQY6xf0Is6G3fEAr6/VJ4Q7J3eOmQ2ukPD6f7hTOo?= =?us-ascii?Q?IW+z3zFFAg=3D=3D?= X-OriginatorOrg: Nvidia.com X-MS-Exchange-CrossTenant-Network-Message-Id: edad4694-daa7-409c-2dbf-08df0969978e X-MS-Exchange-CrossTenant-AuthSource: DM3PR12MB9416.namprd12.prod.outlook.com X-MS-Exchange-CrossTenant-AuthAs: Internal X-MS-Exchange-CrossTenant-OriginalArrivalTime: 03 Sep 2026 03:15:23.0009 (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: hNSv9z5lb/2R/uvleOEUqMjTAUKYkoG6VvyNNB7hI5PUIy1t+hIZTFoflMRPUOwiz1yC1aDk0DajP+GWhCLT0w== X-MS-Exchange-Transport-CrossTenantHeadersStamped: SJ2PR12MB9138 Content-Type: text/plain; charset="utf-8" GIN is the GPU's interrupt controller. It records interrupt sources in a two-level tree and signals the CPU over PCI when an enabled vector becomes pending. Add the CPU tree registers needed to receive GSP interrupts and to run the software-triggered interrupt self-test. Declare each leaf and TOP field with the vector or subtree type it carries, so a set of subtrees cannot be written to a register that takes a leaf mask. A pre-Hopper GPU that signals over MSI requires delivery to be rearmed after each interrupt, by a write to the MSI end-of-interrupt register. Add that register. Assisted-by: Cursor:claude-opus-5 Reviewed-by: Will Pierce Signed-off-by: John Hubbard --- drivers/gpu/nova-core/irq.rs | 1 + drivers/gpu/nova-core/irq/regs.rs | 91 +++++++++++++++++++++++++++++++ 2 files changed, 92 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 f27952ff747b..3066ceeb850c 100644 --- a/drivers/gpu/nova-core/irq.rs +++ b/drivers/gpu/nova-core/irq.rs @@ -9,3 +9,4 @@ //! See `Documentation/gpu/nova/core/interrupts.rst`. =20 mod interrupt_tree; +mod regs; diff --git a/drivers/gpu/nova-core/irq/regs.rs b/drivers/gpu/nova-core/irq/= regs.rs new file mode 100644 index 000000000000..4bb7825207c9 --- /dev/null +++ b/drivers/gpu/nova-core/irq/regs.rs @@ -0,0 +1,91 @@ +// SPDX-License-Identifier: GPL-2.0 +// SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIA= TES. All rights reserved. + +use kernel::io::register; + +use super::interrupt_tree::{ + LeafMask, + SubtreeSet, // +}; + +// GIN, the GPU's interrupt controller: the CPU interrupt tree. +// +// These registers are the two-level CPU interrupt tree at the +// `NV_VIRTUAL_FUNCTION_PRIV` aperture (base `0x00b8_0000`), which any fun= ction +// uses to reach its own tree. The leaf arrays have 16 entries, the widest= tree +// on any supported part. Pre-Hopper parts implement the first eight, and = the +// interrupt HAL supplies the count for a given architecture. See +// `Documentation/gpu/nova/core/interrupts.rst`. + +register! { + /// Latched state of the 32 vectors that belong to one leaf, one bit p= er vector. + /// + /// A read yields the vectors currently latched in leaf `i`. Vector `v= ` occupies bit `v % 32` + /// of leaf `v / 32`. Each bit is write-1-to-clear, and a write of `0`= does not affect the + /// value. Each bit must be cleared before its vector is serviced. + pub(super) NV_VIRTUAL_FUNCTION_PRIV_CPU_INTR_LEAF(u32)[16] @ 0x00b8100= 0 { + /// Vectors latched in this leaf. + 31:0 vectors =3D> LeafMask; + } + + /// Enables individual vectors within one leaf. + /// + /// Each `1` written enables the matching vector for delivery to the C= PU. Zero bits leave + /// their vector 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 individual vectors within one leaf. + /// + /// Each `1` written disables the matching vector. The enable governs = delivery alone: a + /// disabled vector still latches in `LEAF`. + pub(super) NV_VIRTUAL_FUNCTION_PRIV_CPU_INTR_LEAF_EN_CLEAR(u32)[16] @ = 0x00b81400 { + /// Vectors to disable. + 31:0 vectors =3D> LeafMask; + } + + /// Enables whole subtrees at the top of the tree. + /// + /// Bit `N` covers subtree `N`, which spans leaves `2N` and `2N + 1`. = Each `1` written enables + /// that subtree for delivery to the CPU, and zero bits leave their su= btree as it was. + /// + /// Hardware defines a single-element array here, and its one element = covers subtrees 0 through + /// 31, every subtree of the widest supported tree. nova-core declares= it as 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 whole subtrees at the top of the tree. + /// + /// Bit `N` covers subtree `N`. Each `1` written disables that subtree= , and zero bits leave + /// their subtree as it was. + /// + /// Hardware defines a single-element array here, and its one element = covers subtrees 0 through + /// 31, every subtree of the widest supported tree. nova-core declares= it as a scalar. + 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. + /// + /// The vector named in the `vector` field latches in its `LEAF` regis= ter exactly as a hardware + /// source would latch it, and then reaches the CPU under the same ena= ble conditions. The + /// register is write-only. Every supported part implements it. + pub(super) NV_VIRTUAL_FUNCTION_PRIV_CPU_INTR_LEAF_TRIGGER(u32) @ 0x00b= 81640 { + /// Vector to latch. + 11:0 vector; + } +} + +// PCI configuration-space mirror, pre-Hopper only. + +register! { + /// MSI end-of-interrupt register. + /// + /// A `u32` write rearms MSI delivery on pre-Hopper GPUs. The value is= ignored. + pub(super) NV_XVE_CYA_2(u32) @ 0x0008_8704 {} +} --=20 2.55.0 From nobody Sat Sep 26 08:48:41 2026 Received: from CH5PR02CU005.outbound.protection.outlook.com (mail-northcentralusazon11012035.outbound.protection.outlook.com [40.107.200.35]) (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 E4D64366049 for ; Thu, 3 Sep 2026 03:15:33 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=fail smtp.client-ip=40.107.200.35 ARC-Seal: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788405335; cv=fail; b=o/dQNnNoRYYqOortnU+yDxblhk7F1qa1n6iWeoWIuASdBXCoLpx8tGIV0F846qM4jf+/xvNGNLzafhhxZLrsauDqxTmNAYP0bP3mrwXMbFAY0ljeBN3vGGnbTWvbLk9P3k5cYkYyERWbkfPuAXbPX50tCBwBYpWUGV9mI9mUeko= ARC-Message-Signature: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788405335; c=relaxed/simple; bh=yS53EgqjqKyUK5jYULyrqnUrVQW3g3NFYjbSM7NLF5g=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: Content-Type:MIME-Version; b=r8NQD2dzR0h92bLh4qHDjDAzipG2CG0OoEu82fQaBoS9viJsOxsgw765qceCki5szF8I6cGdTzPmZho2Tts/SXHyPPAYWABnMggIqJB78/3YaJaZGliwhbsYfTOw3NNfC2LYw8l4xZVjQ0IANbiZFt1qxBaIwyqxrSKThky/EYA= 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=LTNWD4OZ; arc=fail smtp.client-ip=40.107.200.35 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="LTNWD4OZ" ARC-Seal: i=1; a=rsa-sha256; s=arcselector10001; d=microsoft.com; cv=none; b=Sns1tZb35XYlPYAUhI7zEr01BpHEzk+SoJXKZRdd8i1iGKRNaxohm/OLdYTPl4dPTyX/+qpHYIduPxnRVCkkJ3udYi2HGGhxYOCjezMeE2TVMkagcYw5mMF8UAVb7w0h11Es4vbvbIRt3HtwP0QT9NZ6u2V+AyuN2lf/dKT3pg8/5YcWcErXisZ9/PSfovxxWFiCd73Z8gCtrzCyzYkAuiuWJnmEUemA+cQhheplzqWhgZx0MBpaZ1QBSkBLygY+Piwt37kTjL/w8c8PZwHCtBLR6heTZUMg0L/4vFPvAZ8QFGpLTcPoEEHC/srytOmAGa5NX1OKMogT4lFlH3QJKA== 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=SnMB7KFYkBt2xjdwExTVtqDdPU3xb3s3mhNfx8vasm8=; b=DWpwC8gRgphKT4O8JtxZYUeLzSLxB4QIY37IBUmGCetlfwkoJ9Il/EI5gMN3f3pKxTCaKXfnqsPUK6QhgMRJQgydkXqLA4zXia4mKJe2utPTfNxTghU/hnObCgBbrdEixmwjIBG4kwzl1RT4ULNreZeoU0RSUBBtTYeXSjfo1RK1xKkEPr8FuGE6QejfGFci/aqdW9OIl1gfCTOFIjKIm1OId0xXo3YzsXzcIynBZs6xpps9TRkNPy/ZvmwF+8jZvI9WBsXVY7UaUe2ir7JPs0Gqhe4aZQRvMFuUQmyrcbxmS06vt11ZC1fdhfLbjjzFs0Zejsv60RYpumwrswUzyQ== 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=SnMB7KFYkBt2xjdwExTVtqDdPU3xb3s3mhNfx8vasm8=; b=LTNWD4OZ6HWVVZ+cKLknsjop7qu2rdlHJx1k2R86z6Mr+cbGVYNlmB4NbQFcyMtGqqhr9ejBJDVScL4vniNJoaA8qOOKCh1EjqHl9/7gZ/e2xGu2CuaiOGOH00vS1sk6/ZUuCnV/13yeYyvm/atLeap9O/SpB5D+KQXu8uan/dyP85pDwUcH2HrFJMU3hFSxdpGk0yMxX4fP+MsJYc/netdgOR8yM35iGmuWyksIzo9HRFVu3oU4Olf9xPSl03fB+TIZSquv/8NGaxgPVAhV2bC2kV/MI17s5FpJK8u0QcyGyHMMRAmJEUlQh2KP6yElYyVTTylbRR5vGPfRvsDoqg== 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 SJ2PR12MB9138.namprd12.prod.outlook.com (2603:10b6:a03:565::9) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.21.360.13; Thu, 3 Sep 2026 03:15: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.0360.008; Thu, 3 Sep 2026 03:15: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 , Will Pierce Subject: [PATCH v3 05/14] gpu: nova-core: add the per-architecture GIN CPU interrupt HAL Date: Wed, 2 Sep 2026 20:15:04 -0700 Message-ID: <20260903031514.1515905-6-jhubbard@nvidia.com> X-Mailer: git-send-email 2.55.0 In-Reply-To: <20260903031514.1515905-1-jhubbard@nvidia.com> References: <20260903031514.1515905-1-jhubbard@nvidia.com> X-NVConfidentiality: public Content-Transfer-Encoding: quoted-printable X-ClientProxiedBy: SJ0PR05CA0106.namprd05.prod.outlook.com (2603:10b6:a03:334::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_|SJ2PR12MB9138:EE_ X-MS-Office365-Filtering-Correlation-Id: 96314496-591a-464e-02c4-08df0969985d X-MS-Exchange-SenderADCheck: 1 X-MS-Exchange-AntiSpam-Relay: 0 X-Microsoft-Antispam: BCL:0;ARA:13230040|1800799024|366016|23010399003|376014|7416014|18002099003|22082099003|56012099006|3023799007|10067099003|6133799003|5023799004|11063799006; X-Microsoft-Antispam-Message-Info: ES1ePwF7CkzoG9UD9AmMfspL5PaxarIXWKc8ja0zQ/zJRRUWublWR2zvtesJotKNf3mC9Rjcun7nhoBDQQ+x+c0DXbZoWqkTFeGz7snvgVJYUKsz6lEN8ihNVojVbuKMa0/0hadJZFGD4n8daY5z16TsvTxtw/KDi1L3enA7XR+eUTeT3eBb22tbmEpVMaKQoFzYwYuHb05lyNXhRnisRNNaWCjGTZ95DTQx37Z9FOPGODLL7uvxZCwvDQyM3rFcn7lKUI5kG0kR8Khkj+p2NbUIqsyJw36wQR+FPQyYY05fDQjRifU0aSzrQ0XrgS/QMH6T3PjvcY0oUuLos6T8vrVFsrcPXtm4PwJMtxotIXaPY7gXHp5wvw1JR22qcphApiBxXz/rbj7MWXaoUBzrfZFaAjihhhxLd6O4k3UMJ7UXNRPxMwjmvc4mHqcSuUfkQcId2FSQpSANvTZMPAXt20LVCWixD07DycfkfTrhmKm4IbjhptDehZnDu/LBOjdE2nLIB4wbUIgVWwID+8sNRY9hEA63SPEhOX3oxHfLL+5zVBqyrUkpFfPMfQuqUlUygcnVQ9vOld8uZc651Mf/Os7uFV52sn5MNiktHpb3NVdvTt5GoxqFoCarQG0LSiXExW++ii9JOucAkcF945wWADT0DaONfll6se8QOHntC00= 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)(366016)(23010399003)(376014)(7416014)(18002099003)(22082099003)(56012099006)(3023799007)(10067099003)(6133799003)(5023799004)(11063799006);DIR:OUT;SFP:1101; X-MS-Exchange-AntiSpam-MessageData-ChunkCount: 1 X-MS-Exchange-AntiSpam-MessageData-0: =?us-ascii?Q?UOkSlFE6WadkiBtMIa7Ofvti8ZgCz+V+H5spaiROi4wqfOUe6s/ganGpcLZ5?= =?us-ascii?Q?mWbUlXgT4+xMvpQVM2fV2D32gsBZwHa8KuPnWnTBQjBGgVSLGpcrc54og4gt?= =?us-ascii?Q?9uSoNMPwnNjY6R9KemorLQaKyC5/bfNfsh6pQDjhhtcTiF0uKFlU6bGij466?= =?us-ascii?Q?jHbT++xvQTlGwMlqen6/VFXjU1oxhmBAy6ZLc6jqg51aiGV36r9wcygi61qb?= =?us-ascii?Q?kxpadWSwgxulb3XK4+rbkpindfGzGJOs5HydZkvBtucFmLy6BacAoyZvt3hg?= =?us-ascii?Q?cAo/NV14BBevczsCuhCSuvDjYiOCNOPrfV5ghUgbgZJ/zwCR/60ruImrj9mK?= =?us-ascii?Q?jikovzq9fMFZT9zuwGAKZtQJK/y0Ba9hmciO4xmX35nIKvv+tHWuVTx7XPzY?= =?us-ascii?Q?bQg0y+zwrecWTbLVxrK+Z3JkhbjzvgQ7rCOkp+AQK6Pj0XDAcIUvT66pPBn8?= =?us-ascii?Q?Ce0/2gOec1o1dOnrAIlAZlDMJanXTDNJtY1pLj0eHZ9lkv6gnmOgXU4C385N?= =?us-ascii?Q?Io/bFfEZ87QjlebGfujlE06kRa80gPqizLgbiU6tdKPPZG2Mmem/3iIX8f5f?= =?us-ascii?Q?/HpCDFawP85WmaVsUI5886sTYJoxUC1uJ6bz+FaSKFOMJ7ZiDx6x8Q5IbEKE?= =?us-ascii?Q?xdQZBjzFjwaTA2gld6nYrck1jiBZ51D58i8SqQp4bLJDO1yzuxPVwJJ8/E/Z?= =?us-ascii?Q?IcP5HNwaHl9HbCKj9ingWYX7l7KpOGnv0RIQbxLBDMSPFdMhWFMR8/g2piq2?= =?us-ascii?Q?cT9jkwOtDoXOF25kdssXawuPuLg+Dl2mEvoG2ABxHmyJqb2eLGXqQhIWu/x8?= =?us-ascii?Q?3tP2NSOXyDoAkI6q5EFBPDTVnOvV8e6ej/66Mle1AifXrPPHDmgMLV9ZVe9W?= =?us-ascii?Q?BtkKzsy89bsuUaeL2lucquDvuwPvRabAXAny5zIS+SdpPbWT8GpgYXwfAont?= =?us-ascii?Q?aY/A52hlOn0n8YBNE3dECUHBCeqZpX93e7o65tTf1+Bls8PfW9xkHba5t38p?= =?us-ascii?Q?9Heu940Hs6PLQ4WWSKElRgjsaCW8n7G4txd1ju/QA73L5weSslmw2EpEI+q5?= =?us-ascii?Q?eKIg8I3pRfBQqpPRF9yUERdkfXhyJPYb8omydNINJihl0RUTt0zqLnnX0Tz5?= =?us-ascii?Q?ghBGTopr3z74GHaPf4ZWn476OYyfME3qlrl9VbQMavSBv8awdAQAGGv6Gpgt?= =?us-ascii?Q?K6CpnOi9vOJ3xMX1UIghw5IlYuUlcoJ9utf9wEyAt9SkaLdauoxtw0Oeu2J2?= =?us-ascii?Q?yLa30/nwT6X3puNUejA2wtRO0ZouA3fPjDOh+tUJmGPbkx4mBSOShRUxsWZ0?= =?us-ascii?Q?QS1/FawqT4Zv5jl0+IOh82kI6JmOsCkf6m8hzn6ojdAwlePt+hXCFK2dXVnr?= =?us-ascii?Q?yxiMFiXP8fEwSS4PRqOB028AhYvvfWtqSs4mJ/z7z+8QvU5RW35kIIp/640y?= =?us-ascii?Q?67QEI24RAGmPpjelJ/lh6DA2dbhHm3KSU4aYxXsM/ACmAiCS0jWKHzFZ/mlK?= =?us-ascii?Q?ey4dCpV46LC9v9Zy6oSpN3S5PfUDV58POYYBRoQfD4lP7R3U16NPcyYdzrJF?= =?us-ascii?Q?AbCyQMnIj3jf0OZQB8B6kHibalLmrSI0G8cw+tXc2MOAGRq2eePwuK+2uKJ3?= =?us-ascii?Q?MSF0bCn9xbjoChPtxH6aGkwnNiZEY7haUq8ZJ2AU7T1zNX3/IjfofGsax/4V?= =?us-ascii?Q?gPZbkLg7UEprXLkl4EyEXXeotDoHZBwCP5FYMJKCBE1mr5q5ufvCv9Vd7UbU?= =?us-ascii?Q?jvA5OYMUww=3D=3D?= X-OriginatorOrg: Nvidia.com X-MS-Exchange-CrossTenant-Network-Message-Id: 96314496-591a-464e-02c4-08df0969985d X-MS-Exchange-CrossTenant-AuthSource: DM3PR12MB9416.namprd12.prod.outlook.com X-MS-Exchange-CrossTenant-AuthAs: Internal X-MS-Exchange-CrossTenant-OriginalArrivalTime: 03 Sep 2026 03:15:24.3678 (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: suxZsT31Q4ua212xLmkDi5lyxoJClLN9IYGCeslVJMt8RuM5qj9a5sbpYMoRVEI6KM1N30AOrb3eB51oYnXZ9g== X-MS-Exchange-Transport-CrossTenantHeadersStamped: SJ2PR12MB9138 Content-Type: text/plain; charset="utf-8" GIN, the GPU Interrupt and Notification unit, is the GPU's interrupt controller. Each PCIe function has its own tree, whose leaf count depends on the GPU family. Message-signaled delivery stops after each edge until the CPU rearms it, and the rearm write differs by family and interrupt type: * Pre-Hopper MSI writes an EOI through the BAR0 PCI configuration space mirror. * MSI for Hopper and later cycles the TOP enable bits of every serviced subtree. * MSI-X on any family cycles the bits of the handler's own subtree. Provide the leaf count and the rearm method through a per-architecture interrupt HAL, and name the interrupt type with nova-core's own two variants rather than the PCI core's three, which include the level-triggered INTx that nova-core never allocates. Assisted-by: Cursor:claude-opus-5 Reviewed-by: Will Pierce Signed-off-by: John Hubbard --- drivers/gpu/nova-core/irq.rs | 14 ++++ drivers/gpu/nova-core/irq/hal.rs | 106 +++++++++++++++++++++++++ drivers/gpu/nova-core/irq/hal/gh100.rs | 29 +++++++ drivers/gpu/nova-core/irq/hal/tu102.rs | 28 +++++++ 4 files changed, 177 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 3066ceeb850c..d21dee1b89a0 100644 --- a/drivers/gpu/nova-core/irq.rs +++ b/drivers/gpu/nova-core/irq.rs @@ -8,5 +8,19 @@ //! //! See `Documentation/gpu/nova/core/interrupts.rst`. =20 +mod hal; mod interrupt_tree; mod regs; + +/// The message-signaled interrupt type a vector allocation obtained. +/// +/// nova-core allocates MSI-X or MSI and nothing else, so the level-trigge= red INTx that +/// [`kernel::pci::IrqType`] also names has no representation here. +#[derive(Clone, Copy, Debug, Eq, PartialEq)] +pub(crate) enum MsiType { + /// One message, raised by every subtree of the tree. + 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..1ea677e37e56 --- /dev/null +++ b/drivers/gpu/nova-core/irq/hal.rs @@ -0,0 +1,106 @@ +// 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. + +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, // +}; + +/// Register write that restores PCI interrupt delivery to the CPU. +/// +/// A message-signaled interrupt is delivered once per edge, and the PCI s= ide delivers no further +/// interrupt until the CPU rearms it. A handler that returns without this= write receives no more +/// interrupts. +#[derive(Clone, Copy, Debug, Eq, PartialEq)] +pub(super) enum PciIrqRearmMethod { + /// The MSI end-of-interrupt register in the BAR0 PCI configuration-sp= ace mirror, used by + /// MSI on pre-Hopper GPUs. + ConfigMirrorEoi, + + /// A clear then a set of the `TOP` enable bits of every serviced subt= ree, which produces the + /// edge that delivers the next interrupt. + /// + /// MSI has a single message that every subtree raises, so the rearm c= overs the whole serviced + /// set. + TopEnableCycleServiced, + + /// The same enable cycle, restricted to the one subtree the handler s= erves. + /// + /// MSI-X gives each subtree its own table entry and its own handler. + TopEnableCycleSubtree, +} + +impl PciIrqRearmMethod { + /// Performs this method's register write. + /// + /// `serviced` holds every subtree the driver services, and `subtree` = is the one subtree the + /// calling handler serves. Each method uses whichever of the two its = interrupt type delivers + /// on, so both are required. + pub(super) fn rearm(self, bar: Bar0<'_>, serviced: SubtreeSet, subtree= : Subtree) { + let subtrees =3D match self { + // The written value is ignored, so any write rearms delivery. + Self::ConfigMirrorEoi =3D> { + bar.write(regs::NV_XVE_CYA_2, 0u32.into()); + return; + } + Self::TopEnableCycleServiced =3D> serviced, + Self::TopEnableCycleSubtree =3D> SubtreeSet::from(subtree), + }; + + bar.write_reg( + regs::NV_VIRTUAL_FUNCTION_PRIV_CPU_INTR_TOP_EN_CLEAR::zeroed()= .with_subtrees(subtrees), + ); + bar.write_reg( + regs::NV_VIRTUAL_FUNCTION_PRIV_CPU_INTR_TOP_EN_SET::zeroed().w= ith_subtrees(subtrees), + ); + } +} + +/// Per-architecture properties of the GIN CPU interrupt tree. +/// +/// The tree size and the method that rearms PCI interrupt delivery differ= by family. +/// +/// See `Documentation/gpu/nova/core/interrupts.rst`. +pub(super) trait CpuInterruptHal { + /// Returns the number of leaves the CPU tree implements. + /// + /// [`LeafCount::subtree_set`] gives the subtrees behind them, and + /// [`LeafCount::vector_count`] the vectors they carry. + fn leaf_count(&self) -> LeafCount; + + /// Returns the method that rearms PCI interrupt delivery for `msi_typ= e`. + fn pci_irq_rearm_method(&self, msi_type: MsiType) -> PciIrqRearmMethod; +} + +/// Returns the [`CpuInterruptHal`] for `chipset`. +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..10744ac3ab77 --- /dev/null +++ b/drivers/gpu/nova-core/irq/hal/gh100.rs @@ -0,0 +1,29 @@ +// SPDX-License-Identifier: GPL-2.0 +// SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIA= TES. All rights reserved. + +use super::{ + CpuInterruptHal, + LeafCount, + MsiType, + PciIrqRearmMethod, // +}; + +/// GIN parameters for Hopper and Blackwell, which implement a 16-leaf CPU= tree. Only 12 leaves +/// carry sources. +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..fb8ded59c792 --- /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, // +}; + +/// GIN parameters for Turing, Ampere, and Ada, which implement an 8-leaf = CPU tree. +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 Sat Sep 26 08:48:41 2026 Received: from CO1PR03CU002.outbound.protection.outlook.com (mail-westus2azon11010063.outbound.protection.outlook.com [52.101.46.63]) (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 B49C83655E9 for ; Thu, 3 Sep 2026 03:15:38 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=fail smtp.client-ip=52.101.46.63 ARC-Seal: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788405341; cv=fail; b=XyGuOOxTq/Pz+Ny1eqOhqLBtI/D1GuwQLhxbEl+8y5dAV3RNo360vc7Uo+N6tbr6YK75Jifq/LfDfbxTFhtjlyxkbggMGKw8vnz2g4kf5W7zXufZusG9KfieaR7PU0LEBvtQW3qs41zMgKZ8oUjfgFOagTUZ3VHtpIwRg1EACRQ= ARC-Message-Signature: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788405341; c=relaxed/simple; bh=MY30eNGtjWkcQDDgdObkpfKys/WRo7YOpD1yjYJHjQM=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: Content-Type:MIME-Version; b=iAzqHsd5rGm328/SHL4/xXUHslyumvQDXVYz8PTE5Si2bWrIeRaztCP8e5FJTipZF02E62YF2Wjx6OLOE33Ttw1IOna/7s+18xPil8+xVa5GFcJku8zh8sJ5RFzM4emAiwD+XiLy0VQJ75BEj41yDv13GKClbSscfHLBnOvim88= 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=uhIMI9Bg; arc=fail smtp.client-ip=52.101.46.63 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="uhIMI9Bg" ARC-Seal: i=1; a=rsa-sha256; s=arcselector10001; d=microsoft.com; cv=none; b=C7hhIxtmK6ZdFrb2SxT4Y2W/Rwlr2t9IR4zHuQXmSgPzCaFHRKm8y3gL/mAgahmnd/50gFnpfIcWjFODms5aCXc1lJF8CNNF1bRvszCxBzc/Y3X0OurXoGaSosgPrwPv3LK3Lvw2sT4GRCPyAVA9xkh7tQWKk91Z1zkxTWj26/3vhdyJ+REYU2sqK/4K4v5z89ySoHr2mCTuUY+uFLC4HIFmhBWn59OMJLaAVyz2KghjRRFuTWt+/YhExe1l3eTBuSOKYanmFJ+BbynxPQZdMTqoCCTioDJkp5sP6d7FFWqGF87u8b7RNVu2fqODZWGYWc2BYzls37aDAZU+Cl9MrA== 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=BxxxT3H5QFYg9jSerL7EjghzHTsRmGNKX/NkXvyKkYk=; b=X7ULnRFOvdAiZ9/58q/ZnJq1BAapMmdB6XeOuiGKE8HwHQg4RiLPgqb93CVufhaFUStX4X9V7/BHoqwUfKrb88p/5RZIB7W9GTj3+NUIaeN2L1kfUaN/2VzRJgRB6CYDF4GnUXr3nvyWB1w9TEFeuO9XjIAFDpytADBuBIsEJ6GAwElyP+lyKeqALeFroJ2c+VkWCSYaIrwo6AkRSZyJJoB6uOF7u3oBALFgSYpDezvEAK1bGA+AmhFv1DQgvJTVYZvwwBLgtuARGKNeNGTRg8BrWs6fts1Cw33cEnk/3Xc5oHbu8xRA3MCN3l0qfOFXuWnTwiHkhoJF1Bj2lDNATw== 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=BxxxT3H5QFYg9jSerL7EjghzHTsRmGNKX/NkXvyKkYk=; b=uhIMI9BgzK+jn6Nd5Y3Bjp3QpUEWqMf5I2k2vc6v+lkt3fgJC+EE1h4RUA1WP5hhWoN+qW2Unidza8rbm5Iev46FrKeZHxv0N2xym6TosWAbE86SgvYKrllsLnuCyEE0dEjVjhwyeTDmpa2Kdd514t4n0yXHAa5rSF49NiBALJ2Kw57gd0VLkEPOBsae7LXgLXLbbhhAlXLbHKPG3bou1jhi64eMWNoB5kqwH5+hpbNL2io32avOD9oBDNa488ZgWQG2tEZYD02CnjmPayOzYLEEYksPuDSa8cZd+rMk+s/3OVQabNhFtYvEUbF7cPjDOKEe41c5OnYAVOTN3dJ1Ww== 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 SJ2PR12MB9138.namprd12.prod.outlook.com (2603:10b6:a03:565::9) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.21.360.13; Thu, 3 Sep 2026 03:15: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.0360.008; Thu, 3 Sep 2026 03:15: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 , Joel Fernandes , John Hubbard , Will Pierce Subject: [PATCH v3 06/14] gpu: nova-core: add the GIN interrupt tree and allocate its vectors Date: Wed, 2 Sep 2026 20:15:05 -0700 Message-ID: <20260903031514.1515905-7-jhubbard@nvidia.com> X-Mailer: git-send-email 2.55.0 In-Reply-To: <20260903031514.1515905-1-jhubbard@nvidia.com> References: <20260903031514.1515905-1-jhubbard@nvidia.com> X-NVConfidentiality: public Content-Transfer-Encoding: quoted-printable X-ClientProxiedBy: BYAPR21CA0027.namprd21.prod.outlook.com (2603:10b6:a03:114::37) 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_|SJ2PR12MB9138:EE_ X-MS-Office365-Filtering-Correlation-Id: fe73c6f0-4323-4ab4-01eb-08df09699909 X-MS-Exchange-SenderADCheck: 1 X-MS-Exchange-AntiSpam-Relay: 0 X-Microsoft-Antispam: BCL:0;ARA:13230040|1800799024|366016|23010399003|376014|7416014|18002099003|22082099003|56012099006|10067099003|6133799003|5023799004|11063799006; X-Microsoft-Antispam-Message-Info: bBcRN58l1pPziDvxuiV37zCDwsGqkZTXJB2Ckc89WlJ7DFfZzxf4ui9H59F6CC3cI1X4UcKG0fWD0YmVMAsFvBWMNLT0cuu/9gyb710z1vIgSjv8qJiFehqOO8Vv9vMKIE1Pcxp5mYXEmGRBrEkp6kt14SRZGDrv4UWONBsk3EKR+tyN+1roRfLEOQCV3SBj3fhGynOH2IAArMLii+rZUogSudJcT0zw+BZ60xZk4FS2AUH0DwOz5I74LSUSWYvntvbpYwsnTcuF5mVc92JwQ8H/0/RccTkcZRwlk1Xju2Fdb2mQHbxxqknH/ivSCp4wXRVyS94+xYjLX3tu7Ae4kk0t8hp2EeZAaEBm2TOTIqgLiLR4xjSRtS3B2aEbjVG8w11OYpnp0RPctS+Bemlrp5P1uYUaUYyXIRcYpI4lcPgt+Yt7z6wXNdt3SfEXZlMgK2W8vx74H6Gt9dWOBZY9oCLC5Pb7x7fGhGY2yviX/iRL4nev5mNHmPE1MfcncRJ5jhTVYANMosP7VC0Vf9RSxb4esxi8j1BCY6CyTbjxN5y/QFBp0ws4GdL0mLPHxXh2zJj55dH3y31UlVG8Y38H0GWR0sU11tavCLrSwxf5OTtyDDXupmPNlCGBUX3El4+s7eaZvgMKd4KVc7pJHrAEbUiTRRSK1yMsgRDux2Uz5W4= 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)(366016)(23010399003)(376014)(7416014)(18002099003)(22082099003)(56012099006)(10067099003)(6133799003)(5023799004)(11063799006);DIR:OUT;SFP:1101; X-MS-Exchange-AntiSpam-MessageData-ChunkCount: 1 X-MS-Exchange-AntiSpam-MessageData-0: =?us-ascii?Q?6ecctG0O44RktHRcm7gSoVgIYgkAwTJ9k4SEdc2my8UASVLzpyW3wP2rgcx9?= =?us-ascii?Q?aJXaZEc6mfX2I+DMNBGnCImRjxLPfaxM83pIYZ+T6dTx1iML/BJBtmM1ooci?= =?us-ascii?Q?bnutczJCDx6zs+ZKKKI828hy8HNLFbwxros14jp7yUBNb+RJeqzRod5++8E0?= =?us-ascii?Q?+i7HIeMDTFhuWgC489GNEdVjJFqXKLH/X9t8zjDLvn/wTyBdI9zqZ8RbOdLN?= =?us-ascii?Q?gvX8VSF30G7XpSXgk23r4gL0GYtAZmIrj/Y7dWWwq1aSEU+rj8l5OkNsrntP?= =?us-ascii?Q?po+YbrW3mYEYzSVIRU1sYGoFiUI992j5KRjI+sJVrFR7Hn8/LB82kK6ZOn87?= =?us-ascii?Q?yalXFQkwaec8BHZX7hgRBhk7wyS2JcisuWqd8yWeP9tthM+wPT0Ib4U6WrJU?= =?us-ascii?Q?9mfn9M85Bc10G4UJm37+Dw0/dH1ex3uOlclOhNZckPdg/RK+2CstfX+XbNaJ?= =?us-ascii?Q?69XoZtxckYdoQKyNXef8mdz/DmEMF/j1PI38ZxFIoxa+1TsjFEQ3eaJzY0ZP?= =?us-ascii?Q?fr2bTpGZgNNBdMv4DHhgAwffYfJ9uDRvtSPzL2RhYQda1vYZucGu4B5oR6I1?= =?us-ascii?Q?dy96GOku/NUGjcevYo3l4PQabLry9cS7SQJfZN48VGJx42zNlci5P/gpeB3/?= =?us-ascii?Q?Dew3rI9Fyf+Ux7tgfeIXM3CfVNQ8BQOm/q5ZrLr5murD3KeTlAVgw51klZGn?= =?us-ascii?Q?sWZvQGiUr0Zyv9Sp+woQD5d+clTL2Y95hEurpW7OSp028iHRe8hVERzrrGZi?= =?us-ascii?Q?dQEHlr7fGPm8/M9TSPvXvuZ1zIK7XFCz2iNsC5gmXlGSApvqwj4LVFdchgeV?= =?us-ascii?Q?BBhPgk3IQpeYatVfE0LO+hG03+les9RQyaOX/RDDjvC9k0knGY4jN01UrZ/m?= =?us-ascii?Q?nCMdZI7xuEktmFhKsjLRFuDym02Z0djOHDuDsk7v99uT5Ax1nx6MBGKgNEnV?= =?us-ascii?Q?06zTUq6afkH8jrjr8ZveoSg6kV3FkQ9rfCZFXSceUELnTRrwDlbeo3JLNYxm?= =?us-ascii?Q?ua278W2uX24V2Wa2Hu4/wDxegYy3cS1KS8NpLFzUHZIwH385gQFBz1PK7pUi?= =?us-ascii?Q?UJipcqDdT8EVbrMPYjSuyDN47P0/gyYOaGJh/GgKl+/LXrh+CmNcg+XApQz6?= =?us-ascii?Q?frFrGJ8JLLVvFaj9sO7USffRskgItQig69ee4GkDdMzc660J+CoV3XSmn90d?= =?us-ascii?Q?D9ZRE++LnOiMvR0AcKWO8H5ZjX2WOd38psg+fS0YIzYA/gvQk2ETZKQW19Yp?= =?us-ascii?Q?oClR57wh9IwiR9MfV5Ge+0SDbypLuezF64Q7JGXGUFxi/CbXUB9PEtoOrE3d?= =?us-ascii?Q?NQMsQra6TKscVdfRFhbYVt2YkXa+JPcdE+m7yY/eBvZFpKSPB2E4retXgNvN?= =?us-ascii?Q?cJLCU3kXeN87Lnb13dcJMTniOaANfhTdYtxaLsiYq7izuGsHj50bQdhn/PlN?= =?us-ascii?Q?QtZWeRxo95LIwkpdKBKgVo03J+nsIoTteFADE5bReRFPrU7/URyruXrBeEFe?= =?us-ascii?Q?9z1SvY72hVCFDdvKj2zQWjvkFhXg8QxXiuKqvk4rCaeAITAU75jcfV9tVUod?= =?us-ascii?Q?wDNiO9cElDBn29Z8B+awoM/913vS7QaQUH0hGPNP9IicqdLqSLlzc1MwH4Ju?= =?us-ascii?Q?ZXuMhpTVLv4wqBfa1YjjwgHy5HiC8wG8Zg2oRYznPpyMc4QL96aHxQbtwX99?= =?us-ascii?Q?K6eq0o11vXPXQzmZJ8p5885b6zuPqqsqD7CMvbVJMvEhvaMCWI4dHvrVNg57?= =?us-ascii?Q?TlJ5ZwoHvw=3D=3D?= X-OriginatorOrg: Nvidia.com X-MS-Exchange-CrossTenant-Network-Message-Id: fe73c6f0-4323-4ab4-01eb-08df09699909 X-MS-Exchange-CrossTenant-AuthSource: DM3PR12MB9416.namprd12.prod.outlook.com X-MS-Exchange-CrossTenant-AuthAs: Internal X-MS-Exchange-CrossTenant-OriginalArrivalTime: 03 Sep 2026 03:15:25.5334 (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: ayy6RJIDvzL7w94zz+mhdpvaVnsCTXeWQRTi7vyeN8aLRW0be4gSinPduEKRnbY5wO6qGNEMxcIukgLAG0UTcA== X-MS-Exchange-Transport-CrossTenantHeadersStamped: SJ2PR12MB9138 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 before reading it discards every vector latched in it, and nothing reports the loss. The driver must also allocate a PCI vector for every subtree it enables at TOP, and register a handler on that vector. MSI-X gives each subtree its own table entry. Linux masks every entry the driver did not allocate. An enabled subtree with no entry of its own raises interrupts that never arrive, and its leaf and TOP bits stay pending and enabled. MSI instead has one message that the whole tree raises, so a single entry serves every subtree. Add an API for one PCIe function's CPU interrupt tree, in which reading a leaf yields the handle that clears it, and building a tree fails if it names a subtree the architecture does not implement. Size the vector allocation to the serviced subtrees, requesting MSI-X entries up to the highest serviced subtree and falling back to a single MSI rather than a shared INTx line. Reviewed-by: Will Pierce Signed-off-by: Joel Fernandes [jhubbard: name the module interrupt_tree with a Tree type that owns the BAR mapping, use the canonical NV_VIRTUAL_FUNCTION_PRIV_CPU_INTR_* register names, express vectors, leaves and subtrees as newtypes, let the read of a leaf produce the handle that clears it, add the enable guards, take the leaf count and the rearm method from the interrupt HAL, and read every implemented leaf in drain() rather than descending from the TOP registers, which cannot see a vector that latched while disabled] Signed-off-by: John Hubbard --- drivers/gpu/nova-core/irq.rs | 95 +++++++ drivers/gpu/nova-core/irq/hal.rs | 8 +- drivers/gpu/nova-core/irq/interrupt_tree.rs | 291 +++++++++++++++++++- 3 files changed, 386 insertions(+), 8 deletions(-) diff --git a/drivers/gpu/nova-core/irq.rs b/drivers/gpu/nova-core/irq.rs index d21dee1b89a0..f6ba883d72c5 100644 --- a/drivers/gpu/nova-core/irq.rs +++ b/drivers/gpu/nova-core/irq.rs @@ -12,6 +12,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 a vector allocation obtained. /// /// nova-core allocates MSI-X or MSI and nothing else, so the level-trigge= red INTx that @@ -24,3 +41,81 @@ pub(crate) enum MsiType { /// One table entry per subtree. MsiX, } + +/// The PCI interrupt vector that delivers each serviced subtree. +/// +/// MSI-X raises a separate table entry per subtree, so subtree `N` arrive= s on entry `N`. MSI has a +/// single message that every subtree raises, so all of them arrive on the= one allocated entry. +pub(crate) struct SubtreeVectors<'a> { + vectors: pci::IrqVectorRegistration<'a>, + /// Every subtree nova-core services. + serviced: SubtreeSet, + /// The type [`alloc_vectors`] obtained, which fixes both the entry ea= ch subtree raises and the + /// rearm write its handler owes. + msi_type: MsiType, +} + +impl SubtreeVectors<'_> { + /// Returns the interrupt type these vectors were allocated as. + pub(crate) fn msi_type(&self) -> MsiType { + self.msi_type + } + + /// Returns an [`irq::IrqRequest`] for the vector that delivers `subtr= ee`. + /// + /// MSI-X gives subtree `N` its own table entry `N`. MSI raises its on= e message from every + /// subtree, and nova-core allocates a single entry for it. + /// + /// # Errors + /// + /// `EINVAL` if `subtree` is not one nova-core services. + pub(crate) 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 interrupt vectors that the subtrees in `serviced` requir= e. +/// +/// Every subtree nova-core enables at `TOP` must have an allocated vector= with a registered +/// handler, or the interrupts it raises are lost. Linux masks every MSI-X= entry a driver did not +/// allocate, so the MSI-X request covers every entry up to the highest se= rviced subtree. A part +/// whose MSI-X table is smaller than that falls back to a single MSI, whi= ch serves the whole tree. +/// +/// # Errors +/// +/// `EINVAL` if `serviced` is empty. The error from the MSI request if nei= ther type can be +/// allocated. +pub(crate) fn alloc_vectors( + pdev: &pci::Device, + serviced: SubtreeSet, +) -> Result> { + if serviced.is_empty() { + return Err(EINVAL); + } + + // One entry per subtree up to and including the highest serviced one. + 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/hal.rs b/drivers/gpu/nova-core/irq/h= al.rs index 1ea677e37e56..07604458dbbb 100644 --- a/drivers/gpu/nova-core/irq/hal.rs +++ b/drivers/gpu/nova-core/irq/hal.rs @@ -25,7 +25,7 @@ Subtree, SubtreeSet, // }, - regs, + regs::*, MsiType, // }; =20 @@ -63,7 +63,7 @@ pub(super) fn rearm(self, bar: Bar0<'_>, serviced: Subtre= eSet, subtree: Subtree) let subtrees =3D match self { // The written value is ignored, so any write rearms delivery. Self::ConfigMirrorEoi =3D> { - bar.write(regs::NV_XVE_CYA_2, 0u32.into()); + bar.write(NV_XVE_CYA_2, 0u32.into()); return; } Self::TopEnableCycleServiced =3D> serviced, @@ -71,10 +71,10 @@ pub(super) fn rearm(self, bar: Bar0<'_>, serviced: Subt= reeSet, subtree: Subtree) }; =20 bar.write_reg( - regs::NV_VIRTUAL_FUNCTION_PRIV_CPU_INTR_TOP_EN_CLEAR::zeroed()= .with_subtrees(subtrees), + NV_VIRTUAL_FUNCTION_PRIV_CPU_INTR_TOP_EN_CLEAR::zeroed().with_= subtrees(subtrees), ); bar.write_reg( - regs::NV_VIRTUAL_FUNCTION_PRIV_CPU_INTR_TOP_EN_SET::zeroed().w= ith_subtrees(subtrees), + NV_VIRTUAL_FUNCTION_PRIV_CPU_INTR_TOP_EN_SET::zeroed().with_su= btrees(subtrees), ); } } diff --git a/drivers/gpu/nova-core/irq/interrupt_tree.rs b/drivers/gpu/nova= -core/irq/interrupt_tree.rs index 5aa447cf0ec4..0b4dc2fc8ea8 100644 --- a/drivers/gpu/nova-core/irq/interrupt_tree.rs +++ b/drivers/gpu/nova-core/irq/interrupt_tree.rs @@ -1,18 +1,42 @@ // 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 vector's number fixes where it latches: leaf `vector / 32` at bit `v= ector % 32`, and that //! leaf belongs to subtree `vector / 64`. The types here keep those three= views apart, so a leaf //! index, a set of vectors within one leaf, and a `TOP` bit cannot stand = in for one another. +//! +//! Servicing a leaf has a required order: read its pending bits, then cle= ar them. Clearing a leaf +//! before reading it discards every vector latched in it, and nothing rep= orts the loss. Only +//! [`Tree::read_pending`] produces a [`LeafPending`], and only a [`LeafPe= nding`] can clear, so the +//! wrong order does not compile. +//! +//! Serializing access to the tree is the caller's responsibility. =20 use kernel::{ + io::{ + register::Array, + Io, // + }, num::Bounded, prelude::*, // }; =20 -use crate::num; +use crate::{ + driver::Bar0, + gpu::Chipset, + num, // +}; + +use super::{ + hal::{ + cpu_interrupt_hal, + PciIrqRearmMethod, // + }, + regs::*, + MsiType, // +}; =20 /// Number of bits a leaf index occupies, covering the `0..16` leaf regist= er arrays. const LEAF_INDEX_BITS: u32 =3D 4; @@ -113,7 +137,7 @@ pub(super) const fn contains(self, other: Self) -> bool= { /// /// 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 this subtree's index within the tree. @@ -131,7 +155,7 @@ pub(super) const fn into_raw(self) -> u32 { =20 /// Set of subtrees, one bit per subtree, in the layout the `TOP` enable r= egisters take. #[derive(Clone, Copy, Debug, Eq, PartialEq)] -pub(super) struct SubtreeSet(u32); +pub(crate) struct SubtreeSet(u32); =20 impl SubtreeSet { /// Returns whether `subtree` belongs to this set. @@ -240,3 +264,262 @@ fn from(vector: GinVector) -> Self { vector.0.extend() } } + +/// Clears the enables of the vectors set in `vectors` for `leaf` (`LEAF_E= N_CLEAR`). +/// +/// Shared by [`Tree::disable_leaf`] and by [`LeafEnableGuard`]'s [`Drop`]= , which has no tree to +/// reach through. +fn clear_leaf_enables(bar: Bar0<'_>, leaf: LeafIndex, vectors: LeafMask) { + bar.write( + NV_VIRTUAL_FUNCTION_PRIV_CPU_INTR_LEAF_EN_CLEAR::at(*leaf), + NV_VIRTUAL_FUNCTION_PRIV_CPU_INTR_LEAF_EN_CLEAR::zeroed().with_vec= tors(vectors), + ); +} + +/// Clears the `TOP` enables of every subtree in `serviced` (`TOP_EN_CLEAR= `). +fn clear_top_enables(bar: Bar0<'_>, serviced: SubtreeSet) { + bar.write_reg(NV_VIRTUAL_FUNCTION_PRIV_CPU_INTR_TOP_EN_CLEAR::zeroed()= .with_subtrees(serviced)); +} + +/// Clears the pending vectors set in `vectors` for `leaf` (write-1-to-cle= ar). +fn clear_leaf_pending(bar: Bar0<'_>, leaf: LeafIndex, vectors: LeafMask) { + if !vectors.is_empty() { + bar.write( + NV_VIRTUAL_FUNCTION_PRIV_CPU_INTR_LEAF::at(*leaf), + NV_VIRTUAL_FUNCTION_PRIV_CPU_INTR_LEAF::zeroed().with_vectors(= vectors), + ); + } +} + +/// Returns every leaf a tree of `leaves` leaves implements. +fn implemented_leaves(leaves: LeafCount) -> impl Iterator { + (0..leaves.into_raw()).filter_map(LeafIndex::try_new) +} + +/// The GIN CPU interrupt tree for a single PCIe function. +pub(super) struct Tree<'a> { + /// Borrowed BAR0, through which every tree register is reached. + bar: Bar0<'a>, + /// Number of leaves this tree implements. + leaves: LeafCount, + /// The subtrees this tree enables and services. + serviced: SubtreeSet, + /// Method that rearms PCI interrupt delivery. + rearm: PciIrqRearmMethod, +} + +impl<'a> Tree<'a> { + /// Creates a `Tree` for `chipset` covering `serviced`, with the rearm= method that `msi_type` + /// requires. + /// + /// Each serviced subtree must have an allocated PCI vector and a regi= stered handler, which + /// [`super::alloc_vectors`] sizes the allocation for. + /// + /// # Errors + /// + /// `EINVAL` if `serviced` names a subtree this architecture does not = implement. Such a subtree + /// has no `TOP` bit, so nothing would deliver the vectors behind it. + pub(super) fn new( + bar: Bar0<'a>, + chipset: Chipset, + msi_type: MsiType, + serviced: SubtreeSet, + ) -> Result { + let hal =3D cpu_interrupt_hal(chipset); + let leaves =3D hal.leaf_count(); + + if serviced.intersection(leaves.subtree_set()) !=3D serviced { + return Err(EINVAL); + } + + Ok(Self { + bar, + leaves, + serviced, + rearm: hal.pci_irq_rearm_method(msi_type), + }) + } + + /// Rearms PCI interrupt delivery to the CPU after servicing `subtree`= , the one subtree the + /// calling handler serves. + /// + /// A handler must call this before it returns, or it receives no furt= her interrupts. + pub(super) fn rearm_pci_irq(&self, subtree: Subtree) { + self.rearm.rearm(self.bar, self.serviced, subtree); + } + + /// Enables this tree's serviced subtrees (`TOP_EN_SET`). + 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 this tree's serviced subtrees (`TOP_EN_CLEAR`). + pub(super) fn disable_top(&self) { + clear_top_enables(self.bar, self.serviced); + } + + /// Enables this tree's serviced subtrees until the returned guard dro= ps. + pub(super) fn enable_top_guarded(&self) -> TopEnableGuard<'a> { + self.enable_top(); + + TopEnableGuard { + bar: self.bar, + serviced: self.serviced, + } + } + + /// Enables the vectors set in `vectors` for `leaf` (`LEAF_EN_SET`). + /// + /// This is the per-vector counterpart of [`Self::enable_top`], which = enables whole subtrees. + pub(super) fn enable_leaf(&self, leaf: LeafIndex, vectors: LeafMask) { + self.bar.write( + NV_VIRTUAL_FUNCTION_PRIV_CPU_INTR_LEAF_EN_SET::at(*leaf), + NV_VIRTUAL_FUNCTION_PRIV_CPU_INTR_LEAF_EN_SET::zeroed().with_v= ectors(vectors), + ); + } + + /// Disables the vectors set in `vectors` for `leaf` (`LEAF_EN_CLEAR`). + pub(super) fn disable_leaf(&self, leaf: LeafIndex, vectors: LeafMask) { + clear_leaf_enables(self.bar, leaf, vectors); + } + + /// Enables `vectors` for `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 vectors pending in `leaf`. + 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, + } + } + + /// Injects a software interrupt for `vector` via the trigger register. + /// + /// # Errors + /// + /// `EINVAL` if `vector` lies outside this tree. + // Only the interrupt self-test injects a software interrupt. + #[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 (`LEAF_EN_CLEAR`). + /// + /// Boot, or a driver that ran before this one, can leave leaf enables= set for vectors + /// nova-core does not service, and such a vector delivers to nova-cor= e's handler once its + /// subtree is enabled. + /// + /// This clears enables outside the subtrees nova-core services, so it= is a probe-time + /// operation only. + pub(super) fn disable_all_leaves(&self) { + for leaf in implemented_leaves(self.leaves) { + self.disable_leaf(leaf, LeafMask::all()); + } + } + + /// Clears every pending bit in every implemented leaf. + /// + /// Disables this tree's serviced subtrees at `TOP` for the walk and l= eaves them disabled, so a + /// caller that wants delivery enables them itself once it is ready to= receive. The leaves + /// cleared reach subtrees the driver does not service, and the `TOP_E= N` write does not. + /// + /// Call `drain()` only during probe. It must not run concurrently wit= h an interrupt handler. + pub(super) fn drain(&self) { + self.disable_top(); + + // `TOP` summarizes enabled leaf bits, so a vector that latched wh= ile it was disabled does + // not appear there. + for leaf in implemented_leaves(self.leaves) { + let pending =3D self.read_pending(leaf); + if !pending.vectors().is_empty() { + pending.clear(); + } + } + } +} + +/// The vectors read pending from one leaf. +/// +/// Holding one is the proof that the leaf was read, which is what [`Self:= :clear`] and +/// [`Self::clear_vectors`] require. +pub(super) struct LeafPending<'a> { + bar: Bar0<'a>, + leaf: LeafIndex, + pending: LeafMask, +} + +impl LeafPending<'_> { + /// Returns the vectors that were pending. + pub(super) fn vectors(&self) -> LeafMask { + self.pending + } + + /// Clears every vector that was pending, by writing its bits back (wr= ite-1-to-clear). + pub(super) fn clear(&self) { + self.clear_vectors(self.pending); + } + + /// Clears the vectors set in `vectors` (write-1-to-clear), leaving ev= ery other pending bit + /// set. + /// + /// A handler that services one vector uses this rather than [`Self::c= lear`], which clears + /// every vector the leaf had pending. + pub(super) fn clear_vectors(&self, vectors: LeafMask) { + clear_leaf_pending(self.bar, self.leaf, vectors); + } +} + +/// Keeps a leaf's vectors enabled for as long as it is held. +/// +/// Dropping it disables the same vectors, so an error path cannot leave a= source enabled with no +/// handler behind it. +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); + } +} + +/// Keeps a tree's serviced subtrees enabled at `TOP` for as long as it is= held. +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 Sat Sep 26 08:48:41 2026 Received: from CH1PR05CU001.outbound.protection.outlook.com (mail-northcentralusazon11010002.outbound.protection.outlook.com [52.101.193.2]) (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 0035E366048 for ; Thu, 3 Sep 2026 03:15:41 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=fail smtp.client-ip=52.101.193.2 ARC-Seal: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788405344; cv=fail; b=fHKtwN24wvRva6QYzTuewSZeQTgM+Frg9Dfvfl8CL4AhEW6upUiE9WxJrBn9wldSpQiKpezUaRNAkh8rzni3E5tYz7pO+A2m36Ny519vHC/qfOAwydlit3FnAEYNcQ2YbLKkpP+04zBEki6bL+UAcmuYgBMnqaLOepPBrEw4eBM= ARC-Message-Signature: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788405344; c=relaxed/simple; bh=LHFfDqrOD72XJt682WSkimM6/ZcJUMk3rqHOHgXDqPo=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: Content-Type:MIME-Version; b=PlHck3Y/kYn4Y2xA019fmELxoE681WRsBXec6v7RVBjA6iGW5H/p5gTy1QxMocEESHcVPdguetST/mbzRVn2jJFnBN+FOkeiuWJtLiJmAx/WbxpE2GoyF3EN564H3vatmfMhMGK72TqGdZD2IIe2cJTEpKBFyofAoEeTodqEpco= 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=GyQPmKle; arc=fail smtp.client-ip=52.101.193.2 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="GyQPmKle" ARC-Seal: i=1; a=rsa-sha256; s=arcselector10001; d=microsoft.com; cv=none; b=NEcM7peSXQglS9nLBcjN35W6oTzMPcNcCGHJXiVnUFKrD3reSNMonsoLLoxGSF1V9qPL61qCaySjCAf4vfYwNtoG1ZfN6S78nbKuqoScIvsoMB9SlREwlXiuyFOFpAjF4L9Ef92Pu1mRrjT6Ry4nyCSPakDtmYvQE6KJVElD9zuyno7JHLxXRU9IbgpBcVy9VqdlOkipk3RBEPD3f/Zx9a3ymxXIvqMWzseqgPHLX02A75+PjJs/w0iGC28v7aZfpr6LR7AmesPF7gEkWyJrBeG2UfWnvWcxw6ewn319dqv2eBtLWeovi00ROi6/0+QfmAMf8cGtXQRy/iGW3/SSfA== 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=u3NIyM4T03/IcIOIyWZJYWANN6av5BtR5UDvGJepkoQ=; b=IS5AQIpdqjwLPS7LNM1A8wlyJUkdCwuVqq7dSf4GZe++7/eXx5SG5CZQefRZRR/VSJ7tGbry3VUx9yh2xuCGEGm0s8C6spy+tX6G/LM7ZNXjEQgbKH1YeS2Pib8I5bBNuWQmxKmm0xipGM5Sj7oCPxaIlrlSWlj6+JhrOoWrmNW9SWxV8TTt6FppH0db1H8Smtnwwnn17XhgZjxs8IwJwi8oX0Xidch1GG+4IvTIOET/KFMVrxdHZSba+tQxuAgvJSx9EQlA6NNej/bvfqKs5X1XMmn/q5kN2A/7umF/XQNOySCJvKCODvUywltTMXJpQTdv7+nIU5Z/6876AO2z+Q== 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=u3NIyM4T03/IcIOIyWZJYWANN6av5BtR5UDvGJepkoQ=; b=GyQPmKle2kvgOYvg1AS3U7Xb8P77w71Dor9utF1sEyVlbfmu0PEZf/PZ00Out6QgtATHPfZu2UPF1JXjF6wCFwXPVT5+KWgyZH6fCYBCoCGy+5XDelGDTqGUa++CSVPYZL2OJrNP+GIcPcdczBDX/drJ9eqQPArwAJJrITDb76Jpn73QRxWGmE9e0lAV/FkEd6XlZxCnhhicnM3VEaQLJ1JwYcdCLPaGfqIIxsUt/BZ2+iLY2QXFGTOSKdn2y+77GL4z8DAUbQybLruMtvBnO3JPNBEVj8kNrpow9xMNK5FJQAo1qecgJG+JRscTadm8tnYS6QOi8EKDq07O1ki2AA== 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 SJ2PR12MB9138.namprd12.prod.outlook.com (2603:10b6:a03:565::9) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.21.360.13; Thu, 3 Sep 2026 03:15: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.0360.008; Thu, 3 Sep 2026 03:15: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 , Will Pierce , Joel Fernandes Subject: [PATCH v3 07/14] gpu: nova-core: add an interrupt delivery self-test Date: Wed, 2 Sep 2026 20:15:06 -0700 Message-ID: <20260903031514.1515905-8-jhubbard@nvidia.com> X-Mailer: git-send-email 2.55.0 In-Reply-To: <20260903031514.1515905-1-jhubbard@nvidia.com> References: <20260903031514.1515905-1-jhubbard@nvidia.com> X-NVConfidentiality: public Content-Transfer-Encoding: quoted-printable X-ClientProxiedBy: SJ0PR05CA0110.namprd05.prod.outlook.com (2603:10b6:a03:334::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_|SJ2PR12MB9138:EE_ X-MS-Office365-Filtering-Correlation-Id: fc3f18c7-e6b7-4dec-e202-08df096999aa X-MS-Exchange-SenderADCheck: 1 X-MS-Exchange-AntiSpam-Relay: 0 X-Microsoft-Antispam: BCL:0;ARA:13230040|1800799024|366016|23010399003|376014|7416014|18002099003|22082099003|11062099010|56012099006|7136999003|10067099003|6133799003|5023799004|11063799006; X-Microsoft-Antispam-Message-Info: GUi9sd82kbxMW6BFSMZUR0F55NkU4UsdKSQyaCdPAu6lC/73tOcDdLEHoK1j4ZJuM/HG63aJihP4PMZ2o4aC0j95qRlxxrz1DVrE3Wdjvqiy5SCdgqO3kNCrbm3mrYJQBB3wbm3zvttq7wTTdn5AcorSmGaMt4JgviarSOEK4Pn4Ax0EzAgxKHNy1LeJzGcls1+9WJ7Xa7VvmElvbkonp5DAsOai1PTG1z6qqnjMJRqb/D6HZygZPffh6RZZwYDr/ReU9uC4/BwE2aSXDQXcSjFBgbXCNzq663Vjp80zJlo0HzWlc4A14SzcQVJmLcPy0ggZhgr0Vj3z410K0cHLrh1uxH96jyF2bBIpJT/4hB1F3gJ9hjncgMTFf9N9OFA4E56fcV4bI8+1Q0kcDSBiLXWIy9PEM7q4W5u0wl/2sZzTTo/AlKEHwhAcTKG3uIRTwJzvvxunR7mHP+VG/wwKsrtR7vQSF4tBzD+K0IpWPHv3MVyvyOsqVGbiQnL59TZCIRxLIXa3vUfcM8FGQ5Kkf+fisBjjxs5pVMu2HIkpMU75Ckx1rD7EigU497ZoMuIYKekevWwqEUboBd9rPYlU3w2UdsxRyZ8hygwoJk03/JO8zPFQYlKUKJREUsec/eLkc5gqvHT6YPTGepvaUr8mvv5pFPR7++N5Qpfu2GEybEc= 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)(366016)(23010399003)(376014)(7416014)(18002099003)(22082099003)(11062099010)(56012099006)(7136999003)(10067099003)(6133799003)(5023799004)(11063799006);DIR:OUT;SFP:1101; X-MS-Exchange-AntiSpam-MessageData-ChunkCount: 1 X-MS-Exchange-AntiSpam-MessageData-0: =?us-ascii?Q?i62HtA9maeyqc4MM9LK3VfRDdE1rP23AYhpwVYjYmCBZhILSGyBghB85PDzb?= =?us-ascii?Q?AlecoSxmbluwTpRFtrFwaGd9tus3O1HrrSPcn0DEBKICuzZS3yPWf/DIfsN6?= =?us-ascii?Q?pMDthDcB0AmQvk8EMsfILTYUJcaAPpAoMgNN0bTWwjZGQ+Eq0+of8jrJ0X+O?= =?us-ascii?Q?RvA95WmPFLECzNJ9sbcF6x1WiUaG9js7FqxVkfDJ0WvC6pLHR3KsGGIvpZty?= =?us-ascii?Q?fLLSYuh9umC+AR9xZjeZ4FXEVMNOW0+Rm+XXzYyMzlxGW9ah9Yo2LjlRnDbU?= =?us-ascii?Q?r1zqZ/MOlOrNryZFNPk0P6HBe1U/r/RgOSkEQDAd37eyXOXs5d1zr3bx9bRl?= =?us-ascii?Q?awBYv5w/6e6Yfn9mgSO5WzGrKJ4fLKvMnrQWf0fVmisSgzz7ENZJv/E4zllV?= =?us-ascii?Q?SdAAQgmWDKKFW+vjDZ94ezy6nWcD6UgHcAgp9HZ9CrVyt+pWdklWoZvavhRv?= =?us-ascii?Q?PQGbzihh4NzOnKAYYq0nQ5V6cXjR1RAp69wD7UXCnvNSYRJ17dY2bM34V0oi?= =?us-ascii?Q?v/AyW3Ona6pU5bp18kklEqw0dr+fuVtv1AmcBaKMjxWLfJ4RdiFmjHRhOhdX?= =?us-ascii?Q?x3P3H2BmsZslfGFI8KYT7dhAbAuTIdpLWLNTlFmhc8B2AZPg/yEAAnDMrRQc?= =?us-ascii?Q?UI9NPL6zn31cy3/lmqaRyJwbOyAcUc2bVwtV2y+wXp8pcPQgtaAvJOoWewzH?= =?us-ascii?Q?HoeTz/tEKh5NNo7FZM/HtjaCOGp/DsTQe9Eavfok6G9Dzs4uj4BlTrbENTp9?= =?us-ascii?Q?ipDsa01Ys6qteM7g3f5ux9+DqW9Od4YCIUgZrg5xE/Wz88llf3UfdvBF67CS?= =?us-ascii?Q?VySCzLkK03FvwOocvtfO2Tj6sbv8Vm5NGFYS623A4cwmg02pGeY0KXMSShgE?= =?us-ascii?Q?d0jl6/83LwguAtnXIjr4CCldCDnpui58jJt0zN/56xGFrwP85RYQ4yVln/3Y?= =?us-ascii?Q?jJRVu5PLwyG3q7OneTkSkfhnNfLHJ9yUMDoJ6/KDLvKW8l5BGlGhd0K3JdQQ?= =?us-ascii?Q?pTzRM2ATil7kiEB8X6uV4GWnZBZBjgPO6aVNtoNYTfv/Vqgjwa2c0IKU3Vi2?= =?us-ascii?Q?fLc5w8faFJA86lFCBa6WneOhJ/5mycEAmr5x1gushEcWYGwBbaRoemYD3vlS?= =?us-ascii?Q?jyzZWAY94OkfM8TJ8ITC3eMhxKpKs8hCgY6kb6n88aJg22V3AD+pnv9guTo2?= =?us-ascii?Q?tPea5Lv8aq54yCgrQ5XemtCrfAwcynCfdbYI4KO7DOApkQs1+yttmfjS5Riy?= =?us-ascii?Q?igW1mTODSaYSaNCRzCblLX3k8tfKmAiZ3uxyUE4NziGSHwqLGxrPo2HGyNfA?= =?us-ascii?Q?vDCt8hBFMFVNKaLjeiuDezqnlmm1RtRh0E47kSl0prz66CGKpvdy2U4aR5T1?= =?us-ascii?Q?0y/uUZnaiXwn7p4w3njwbg8895Zx3ALkP08paiByhSt26LDFyQ6ybU7uAiC7?= =?us-ascii?Q?+KzESzVYcbDYRdrnUxtvpXQiDdckni9dfVAPPIhWrZ9EwFLytbyj7HB5/CTq?= =?us-ascii?Q?qIURzfS4nP2hb5LOJx7IzPPYSbZc6UCBQJGpUJwF0E/eBvenbzq1LScQv2IP?= =?us-ascii?Q?ZxF12CC73mvbEkOWmZfHC3B9OI+qeVcW76EIRoF8Jskn+VgNL2CumnFsOyd9?= =?us-ascii?Q?JuR5o+tsO1QvRR08k5xI/uERaEBt1xLswPmJv9k24FfjjP3k3CQX0fdhRQ1Q?= =?us-ascii?Q?ilL2KM20Sk+4dwxDklOoNCZyB6E3935Kf/7pjIoqfbNdHYk8ftuSTNSTxBv/?= =?us-ascii?Q?d6coQlWgwg=3D=3D?= X-OriginatorOrg: Nvidia.com X-MS-Exchange-CrossTenant-Network-Message-Id: fc3f18c7-e6b7-4dec-e202-08df096999aa X-MS-Exchange-CrossTenant-AuthSource: DM3PR12MB9416.namprd12.prod.outlook.com X-MS-Exchange-CrossTenant-AuthAs: Internal X-MS-Exchange-CrossTenant-OriginalArrivalTime: 03 Sep 2026 03:15:26.5778 (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: uA0+8n9TP6mL6Cz41BCTkxI7cAS0AU68Yg9+mAaCUfU6L++ar06XN2t0exB3fknFiNs30p9Jld5X/YdwQoAqRQ== X-MS-Exchange-Transport-CrossTenantHeadersStamped: SJ2PR12MB9138 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 enable bits, or in the rearm. Every one of those failures looks the same to the driver: no interrupt arrives, and nothing in the symptom says which one broke. Add an optional probe-time self-test that injects the CPU doorbell through the GIN software trigger. One injection would pass even with a broken rearm, because the first message-signaled interrupt arrives whether the driver rearms or not. The test injects twice, and waits for the first handler to rearm before it injects again. Run it before GSP boot on a quiesced tree, and fail probe unless exactly two deliveries arrive, each delivery finds only the doorbell pending, and the leaf ends clear. Under MSI-X the injected subtree has its own table entry, so the delivery exercises that entry too. Allocate the PCI interrupt vectors alongside the GPU's other resources rather than in the test, because the vectors are allocated once for the whole PCI device rather than per handler. The test takes the vector for the subtree it services. Assisted-by: Cursor:claude-opus-5 Reviewed-by: Will Pierce Co-developed-by: Joel Fernandes Signed-off-by: Joel Fernandes Signed-off-by: John Hubbard --- drivers/gpu/nova-core/Kconfig | 15 + drivers/gpu/nova-core/gpu.rs | 25 ++ drivers/gpu/nova-core/irq.rs | 9 + drivers/gpu/nova-core/irq/doorbell_test.rs | 301 ++++++++++++++++++++ drivers/gpu/nova-core/irq/interrupt_tree.rs | 2 +- drivers/gpu/nova-core/nova_core.rs | 2 +- 6 files changed, 352 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 f918f69e0599..7198fae6b6f4 100644 --- a/drivers/gpu/nova-core/Kconfig +++ b/drivers/gpu/nova-core/Kconfig @@ -15,3 +15,18 @@ config NOVA_CORE This driver is work in progress and may not be functional. =20 If M is selected, the module will be called nova-core. + +config NOVA_CORE_IRQ_SELFTEST + bool "Nova Core interrupt delivery self-test" + depends on NOVA_CORE + help + Run an interrupt delivery self-test during nova-core probe. It + injects a known vector through the GPU interrupt controller's + software trigger and confirms the interrupt reaches the driver's + handler, validating the PCI interrupt path from the GPU to the CPU + with no dependency on GSP firmware. The result is printed to dmesg. + + If the test fails, the PCI probe fails and the driver does not load. + + This is intended for driver bring-up and for debugging PCI, MSI, or + passthrough setups. If unsure, say N. diff --git a/drivers/gpu/nova-core/gpu.rs b/drivers/gpu/nova-core/gpu.rs index e1ac8ee9ba4d..8a9bc4baf9ac 100644 --- a/drivers/gpu/nova-core/gpu.rs +++ b/drivers/gpu/nova-core/gpu.rs @@ -29,6 +29,7 @@ Gsp, GspBootContext, // }, + irq::SubtreeVectors, vgpu::VgpuManager, // }; =20 @@ -292,6 +293,12 @@ 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>, + /// Self-referential borrow of `vectors`, so this does not have to be = repeated in the + /// constructor. Will go away with self-referential pin-init. + vectors_ref: &'gpu SubtreeVectors<'gpu>, + /// PCI interrupt vector allocation. Dropped last (struct field drop o= rder). + #[pin] + vectors: SubtreeVectors<'gpu>, } =20 #[pinned_drop] @@ -330,6 +337,12 @@ pub(crate) fn new<'a>( let dev =3D pdev.as_ref(); =20 try_pin_init!(Self { + vectors: crate::irq::alloc_vectors(pdev, crate::irq::SERVICED_= SUBTREE.into())?, + + // SAFETY: `vectors` is initialized above, lives at a pinned s= table 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); })?, @@ -347,6 +360,18 @@ pub(crate) fn new<'a>( .inspect_err(|_| dev_err!(dev, "GFW boot did not compl= ete\n"))?; }, =20 + // Validate the MSI interrupt path before booting GSP, when th= e self-test is + // enabled. This runs on a quiesced interrupt tree with no GSP= state present, so it + // never observes or clears GSP or PRIV_RING interrupts. + _: { + // `vectors_ref` exists for the self-test below, which thi= s configuration omits. + #[cfg(not(CONFIG_NOVA_CORE_IRQ_SELFTEST))] + let _ =3D vectors_ref; + + #[cfg(CONFIG_NOVA_CORE_IRQ_SELFTEST)] + crate::irq::doorbell_test::run_selftest(pdev, bar, spec.ch= ipset, vectors_ref)?; + }, + // Initialize this early because `gsp_resources` depends on it. sysmem_flush: SysmemFlush::register(dev, bar, spec.chipset)?, =20 diff --git a/drivers/gpu/nova-core/irq.rs b/drivers/gpu/nova-core/irq.rs index f6ba883d72c5..f44897692b74 100644 --- a/drivers/gpu/nova-core/irq.rs +++ b/drivers/gpu/nova-core/irq.rs @@ -8,6 +8,8 @@ //! //! See `Documentation/gpu/nova/core/interrupts.rst`. =20 +#[cfg(CONFIG_NOVA_CORE_IRQ_SELFTEST)] +pub(crate) mod doorbell_test; mod hal; mod interrupt_tree; mod regs; @@ -25,10 +27,17 @@ use crate::num; =20 use interrupt_tree::{ + GinVector, Subtree, SubtreeSet, // }; =20 +/// The subtree nova-core allocates PCI vectors for. +/// +/// Every source nova-core services latches in this one subtree, so a sing= le allocation covers all +/// of them. +pub(crate) const SERVICED_SUBTREE: Subtree =3D GinVector::new::<129>().sub= tree(); + /// The message-signaled interrupt type a vector allocation obtained. /// /// nova-core allocates MSI-X or MSI and nothing else, so the level-trigge= red INTx that 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..a232a83b62f6 --- /dev/null +++ b/drivers/gpu/nova-core/irq/doorbell_test.rs @@ -0,0 +1,301 @@ +// SPDX-License-Identifier: GPL-2.0 +// SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIA= TES. All rights reserved. + +//! Interrupt delivery self-test, driven through the CPU doorbell vector. +//! +//! Exercises the whole PCI interrupt path (GPU to PCIe to CPU to handler)= with no GSP dependency: +//! it injects a known vector through the GIN software trigger and confirm= s the handler runs. Two +//! interrupts are triggered one at a time, which also covers the rearm th= at every delivery after +//! the first depends on. Gated behind `CONFIG_NOVA_CORE_IRQ_SELFTEST` and= run before GSP boot, so +//! it never observes or clears GSP interrupt state. +//! +//! See `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, // + }, + SubtreeVectors, // +}; + +use crate::{ + driver::Bar0, + gpu::Chipset, // +}; + +/// Fixed vector for the CPU doorbell. +/// +/// The resource manager pins the CPU doorbell to this vector on every sup= ported chip, so nova-core +/// uses the constant directly instead of discovering it at runtime. +const DOORBELL_VECTOR: GinVector =3D GinVector::new::<129>(); + +/// Subtree carrying the doorbell vector, and the only subtree this test s= ervices. +/// +/// Derived from the vector so that changing `DOORBELL_VECTOR` moves the s= ubtree it enables and the +/// handler together. +const DOORBELL_SUBTREE: Subtree =3D DOORBELL_VECTOR.subtree(); + +/// Time allowed for each of the two deliveries to arrive. +const DELIVERY_TIMEOUT_MS: time::Msecs =3D 1000; + +/// Interrupt handler installed by the self-test. +/// +/// Services the doorbell the way a notification source is serviced: it cl= ears its own leaf bit and +/// rearms PCI interrupt delivery, leaving the rest of the tree untouched.= It records the leaf's +/// pending bits seen on each of the first two deliveries and signals the = matching completion. +#[pin_data] +struct DoorbellTestHandler<'a> { + /// The interrupt tree, which carries the borrowed BAR0 that register = access needs. + tree: Tree<'a>, + /// Signalled by the first delivery. + #[pin] + first: Completion, + /// Signalled by the second delivery. + #[pin] + second: Completion, + /// Count of deliveries this handler has serviced. + irq_count: Atomic, + /// Doorbell leaf's pending bits observed on the first delivery. + first_pending: Atomic, + /// Doorbell leaf's pending bits observed on the second delivery. + second_pending: Atomic, +} + +impl irq::Handler for DoorbellTestHandler<'_> { + fn handle(&self) -> irq::IrqReturn { + // Clear only this handler's own bit and leave `TOP_EN` alone. A f= ull walk disables and + // enables the tree, which produces a delivery edge by itself and = would hide a missing PCI + // interrupt rearm. + 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 signalling, so delivery is possible again by the t= ime the waiting thread + // triggers the next vector. + 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 + } +} + +/// Everything the running self-test owns, torn down in declaration order. +/// +/// That order is what every exit path, including an early error, needs: d= isabling the leaf stops +/// new deliveries, dropping the registration runs `free_irq()`, which wai= ts for a handler still in +/// flight, and only then are the tree's subtrees disabled, so a late hand= ler cannot rearm them. +struct SelftestResources<'a, 'r> { + _leaf_guard: LeafEnableGuard<'a>, + reg: Pin>>>, + _top_guard: TopEnableGuard<'a>, +} + +impl<'a> SelftestResources<'a, '_> { + /// Returns the registered handler. + fn handler(&self) -> &DoorbellTestHandler<'a> { + self.reg.handler() + } + + /// Disables the doorbell source and waits for a handler already runni= ng on another CPU. + /// + /// On return no further delivery can reach the handler, so its counte= rs and the doorbell + /// leaf hold their final values. + 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. +/// +/// Quiesces the interrupt tree, registers a temporary handler, and inject= s the doorbell vector +/// through the GIN software trigger twice, one delivery at a time. This v= alidates the PCI +/// interrupt path from GIN to the ISR without GSP firmware, including the= rearm without which only +/// the first interrupt would arrive. The handler, its IRQ registration, a= nd all tree state are +/// torn down before this returns. +/// +/// # Errors +/// +/// `EINVAL` if the doorbell's subtree is not one nova-core services. `EIO= ` if the doorbell is +/// already pending before the test, if the delivery count is not two, if = the doorbell bit is still +/// set once the source is stopped, or if either delivery found a pending = bit other than the +/// doorbell. `ETIMEDOUT` if either delivery does not arrive within the ti= meout. +pub(crate) fn run_selftest<'a>( + pdev: &'a pci::Device, + bar: Bar0<'a>, + chipset: Chipset, + vectors: &'a SubtreeVectors<'a>, +) -> Result { + // The interrupt type decides how the handler rearms delivery, so the = tree takes it from + // probe's allocation. + let request =3D vectors.request_for(DOORBELL_SUBTREE)?; + let msi_type =3D vectors.msi_type(); + let tree =3D Tree::new(bar, chipset, msi_type, DOORBELL_SUBTREE.into()= )?; + let doorbell =3D DOORBELL_VECTOR.leaf_index(); + let doorbell_mask =3D DOORBELL_VECTOR.leaf_mask(); + + // Under MSI-X the subtree index is also the table entry the delivery = arrives on, so a pass + // shows that the per-subtree routing works. Under MSI every subtree s= hares one entry. + dev_info!( + pdev.as_ref(), + "interrupt self-test: starting on vector {}, subtree {}, with {:?}= \n", + DOORBELL_VECTOR.into_raw(), + DOORBELL_SUBTREE.index(), + msi_type, + ); + + // No delivery may reach the CPU before a handler is registered, and a= vector left enabled by + // boot would fail the pending checks below. `drain` leaves the top le= vel disabled. + tree.disable_all_leaves(); + tree.drain(); + + // A delivery can be credited to the trigger below only if the vector = starts out clear, so + // refuse to run otherwise. + let pre_pending =3D tree.read_pending(doorbell).vectors(); + if pre_pending.contains(doorbell_mask) { + dev_warn!( + pdev.as_ref(), + "interrupt self-test: failed, vector {} already pending (leaf[= {}] pending {:#x})\n", + DOORBELL_VECTOR.into_raw(), + doorbell.get(), + pre_pending.into_raw(), + ); + return Err(EIO); + } + + 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); + + // Register the handler before allowing any source to fire. + let reg =3D KBox::pin_init( + // SAFETY: the registration is owned by `resources` below and drop= ped before this function + // returns, so its `Drop` (which calls `free_irq()`) always runs a= nd the registration is + // never leaked or `mem::forget`-ed. + unsafe { + irq::Registration::new( + request, + irq::Flags::TRIGGER_NONE, + c"nova-core", + handler_init, + ) + }, + GFP_KERNEL, + )?; + + // From here every exit must tear down the source, the registration, a= nd the tree. The fields + // are initialized in the order the hardware requires, which is the re= verse of the declaration + // order that tears them down: the handler is registered above before = either source is + // enabled, the leaf next, and the top level last. + 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(); + + // Trigger the second interrupt only once the first handler has cleare= d its leaf bit and + // rearmed, so the two cannot coalesce into one delivery and a handler= that never rearms + // cannot pass. + 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(); + } + + // Stop the source and wait out any handler still running, so the valu= es read below are the + // final ones. + 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(); + + // The self-test runs before GSP boot on a leaf that `drain` has just = cleared, and nothing + // triggers the vector after the second delivery, so each delivery mus= t find the doorbell bit + // and nothing else, and the leaf must end clear. + if completed + && count =3D=3D 2 + && first_pending =3D=3D doorbell_mask + && second_pending =3D=3D doorbell_mask + && !residual.contains(doorbell_mask) + { + dev_info!( + pdev.as_ref(), + "interrupt self-test: passed, subtree {}, {} deliveries\n", + DOORBELL_SUBTREE.index(), + count, + ); + Ok(()) + } else { + dev_warn!( + pdev.as_ref(), + "interrupt self-test: failed, {} of 2 deliveries, leaf[{}] pen= ding {:#x} and {:#x}, \ + {:#x} left set\n", + count, + doorbell.get(), + first_pending.into_raw(), + second_pending.into_raw(), + residual.into_raw(), + ); + Err(if completed { EIO } else { ETIMEDOUT }) + } +} diff --git a/drivers/gpu/nova-core/irq/interrupt_tree.rs b/drivers/gpu/nova= -core/irq/interrupt_tree.rs index 0b4dc2fc8ea8..f27f0137dffe 100644 --- a/drivers/gpu/nova-core/irq/interrupt_tree.rs +++ b/drivers/gpu/nova-core/irq/interrupt_tree.rs @@ -420,7 +420,7 @@ pub(super) fn read_pending(&self, leaf: LeafIndex) -> L= eafPending<'a> { /// /// `EINVAL` if `vector` lies outside this tree. // Only the interrupt self-test injects a software interrupt. - #[expect(dead_code)] + #[cfg_attr(not(CONFIG_NOVA_CORE_IRQ_SELFTEST), 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 dfd11dfe562c..65ce547bd44e 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_IRQ_SELFTEST), expect(dead_code))] mod irq; mod mctp; #[macro_use] --=20 2.55.0 From nobody Sat Sep 26 08:48:41 2026 Received: from CH1PR05CU001.outbound.protection.outlook.com (mail-northcentralusazon11010002.outbound.protection.outlook.com [52.101.193.2]) (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 2806836895D for ; Thu, 3 Sep 2026 03:15:36 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=fail smtp.client-ip=52.101.193.2 ARC-Seal: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788405339; cv=fail; b=CGhO6GxamjBOiG8+7f1wzHDsEZlZTPOQM/Ql5WS9gh8PkH9GfxgOZcD45KE9A5pbshgZ216g3nAJqN7FmPsoJBce2MGgk9Rcmrv3oe6wVlXO2UPAs3znMRR7XHt4s+aKVHdivlJIpdsdlMQoGkw3UhW3nfbFYnpH+rnwdD++P5s= ARC-Message-Signature: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788405339; c=relaxed/simple; bh=ORDPM3qqN5go9MYKtd30fqhdYxOpKkF7MOL7a5WUFP0=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: Content-Type:MIME-Version; b=Bauu5zvgjoaJvqZdwzU+mSy8K0Ja8mPBVwEVzfV7lDcwTF9gQoUgDC8+Qe/e56JH+i2UZLUNtfuTVCP+hoUSYNnTPJhYLnRhY1re8tTX+fGxvDiDOCBGX9hqlJoSKQ6rL7HPoJqYL1zCOdF7D1J1zKgssY7IoOD/HuzUIJPvGMg= 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=fvHON15J; arc=fail smtp.client-ip=52.101.193.2 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="fvHON15J" ARC-Seal: i=1; a=rsa-sha256; s=arcselector10001; d=microsoft.com; cv=none; b=A3mtPqFSWvXiUZim2UWYYGPvWIP0ompGukVVz/Agq5GGm6RzKjIniakvIgr1n8l9nKnGF55SPzbhksGw8nqKbJH6hgydsZoyhtYq6+TEPhX/soFXFEimHKcThdFCHlH+pMRUSj8gHL6n/zWrFeJFnyNWUt1T70EaeG/MDUMbNMhkz0jAb2FVtp5EsvSFWr0ZfiCiHX2K1pV/sSZHQDzK1UBjqz4F6Ktb791L0MQp7aNBj0tpVAe+iNmSdHFU0L9tLvbpYAogRlzsF7XJQ2FUClG2cL8LH9Ttw5bg7L01jW8rde4uNG/R7FOElXwVOs7rDKBe+At114LK0LpSYWEW7w== 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=qdWMgqDSFOq09fB5W3Swg+CqFxV/HlU2mEL/oM+HPFQ=; b=y8dEC3jfPQfdV5bScje6SKCKx96586w4mE9hY1VxIitGaP+sb3fXY+jf/m/T48Y6fbjlayi4CyCEUpPL6epgZpxfnZLbs74DNCQER5EPLbfCpzXPTsnNCykmCSyCLcoeMigOJqNRBggKCZtD+dys2nx1SDiYqnFec9fnkE2OlAcbZo8nUxa4+UQ4SBOfrCykuboxAumFWkkl5l6UR7URMQEkxyqLfqyaIzzsCg6JcC3GAke4XQKFicdgk5h3Qs5ZaWpPDy1jKvnfLegonmqFpUXadr2RYEkshel1ZbPP6uh/fi4Ic5F6IVkBAasPBnbPCKf910s2klZ69hIS66F9cA== 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=qdWMgqDSFOq09fB5W3Swg+CqFxV/HlU2mEL/oM+HPFQ=; b=fvHON15JMYAx6kdI1dyer3gQmZc0GtKChDW+cA8ZSPlc9eO/TNVwbrwTZKAwN9Y7SAsdGwvgmS4q0TOeGLyWEX8eJxJjaYNFfK4x0brl2cN/TFCG0GxkTy+CJjXbku0jvbJ7IiKvpd6WIJW3h6SM762RoEKCTIs9OclUCPiHh+VtY5/QR5V8+DTm7zJ2/If+KPSFNVcg7nKz/y5rfkzbCsht289vZjgqCGnohJXPW5Q6je1hzFFgl7jukJEfKSCkcL8yTr3i5wi0OK2h4pOLD9q65d+hbjNqJ69HOPTUfNiOSJDeytfUo0DxfgzcrpjsP023vL4/ug9NXgCjtD2UQg== 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 SJ2PR12MB9138.namprd12.prod.outlook.com (2603:10b6:a03:565::9) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.21.360.13; Thu, 3 Sep 2026 03:15: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.0360.008; Thu, 3 Sep 2026 03:15: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 v3 08/14] gpu: nova-core: log GSP events instead of discarding them Date: Wed, 2 Sep 2026 20:15:07 -0700 Message-ID: <20260903031514.1515905-9-jhubbard@nvidia.com> X-Mailer: git-send-email 2.55.0 In-Reply-To: <20260903031514.1515905-1-jhubbard@nvidia.com> References: <20260903031514.1515905-1-jhubbard@nvidia.com> X-NVConfidentiality: public Content-Transfer-Encoding: quoted-printable X-ClientProxiedBy: SJ0PR03CA0135.namprd03.prod.outlook.com (2603:10b6:a03:33c::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_|SJ2PR12MB9138:EE_ X-MS-Office365-Filtering-Correlation-Id: 386ebb82-0a57-4656-0169-08df09699a47 X-MS-Exchange-SenderADCheck: 1 X-MS-Exchange-AntiSpam-Relay: 0 X-Microsoft-Antispam: BCL:0;ARA:13230040|1800799024|366016|23010399003|376014|7416014|18002099003|22082099003|56012099006|10067099003|6133799003|11063799006; X-Microsoft-Antispam-Message-Info: DZ7Qo3dZHX2ezvJmH2OSPrGye4UN8/m0F/TayQJ5UntuVHslz+FRsc5HboEoBrFlfvv1XKk6LrpmU4ysTdWIA1bowd3xxYRc121UpOrZwSUtbH85T2b+KwyjeKXgB8CiXS7bIRDDTC7wxfkZpfuAdyFw6ZATjfS9SJ0jCYiJI61PJKINwma9/KPoXVHJfVeZZRj6nCdTN5MEKhgjE1oc7vdYOE6GkCN7aw1xY9vrcy4wstNSNWkZ0toijwvY0Z1i0ZwNhve/oeaB/nF5+YvxZjqgJ3fQ3eAEqULJyCShuaaJ4u+YTYedsB4wycZ/rkqyTidKTKGoxByMQ4jCuwKQdYWrSLWrRDyCHz2MxlJrRW/Vuyk+zOBC+Tw6/mnvMMGqGFuAKVmWnHjW10caELGSS2Rjp6BdHgnqmkm/uyHXg45NvHiCrE8pGznosXZ8Dzbeqw5muAfOodeEkRcr8HseRGUSfd+YNCp+A5zt+xWgZkH+XiwktOHVe6FrQPvsNf/Qg6TBAWTopnxrCVNlOo5tov5/qX96t9u+U32SGg0fL88HtgVLKbSKu7z2p6RlepAb8OcFfkHldtSA4bzmRk3f4luZmLFqMc3ZunBg0MvebrcVgwFsS3wsrLE+0PczKpglFKBXljn+DelBoWDa6wiR5ixAYczbQ+LaWz5Dnycsc1s= 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)(366016)(23010399003)(376014)(7416014)(18002099003)(22082099003)(56012099006)(10067099003)(6133799003)(11063799006);DIR:OUT;SFP:1101; X-MS-Exchange-AntiSpam-MessageData-ChunkCount: 1 X-MS-Exchange-AntiSpam-MessageData-0: =?us-ascii?Q?NTNt9cBxzr8rBfVWVsq3+i+xT9c1jh3vH3lc8dLgGfhjlK69nJYPkOJHDxEy?= =?us-ascii?Q?3/oL3ls2SokpZNTlCHcWtKJt1kDQwWXkTnZ54UCHyADkNCSCeetgbSsvpgvD?= =?us-ascii?Q?YTjXfa+I9ZG5ihlXwCRQNH6bgkYynyZAXUYeZqsuXd8Po7uZsr2Mlzfr2KeX?= =?us-ascii?Q?wVeJra/6xWxNMXWYZyjsTklc9J6kdl3hb2HUG3FJJFEOwd5FhZiNpAlX8rMM?= =?us-ascii?Q?z6HrukXHyHOoUSJRjT2zin5C+s8/yE2eQaLU+yzbrWjEgD4UQppFZXD92xDi?= =?us-ascii?Q?hWSK2CCruEk4x6B/taQDw96pKTL4R9mXNHla2XKyVjihaKveQNYSkQcmoklQ?= =?us-ascii?Q?GGanrwzCQp8SgZbOf1ojPLoHBTDqmn12SXT+ZO4F6fL647U7SewopsnT7u/m?= =?us-ascii?Q?+oGWkRfJBz4IZv/FLKKSq3Hp4epdU5eenM5z9AWUfjcIHg2T376+QNCkOfaf?= =?us-ascii?Q?PtlXG1qLNh09GVMuWTqjSZcQUzy/DcOAG7zFzS6Q6FZJMpDssdowoQ2N44Oi?= =?us-ascii?Q?J7LYf+kfqiwz1qNdxMjdI+G4vbwxs7ZmFldJQGo82OWMn6TLuNOyxnjRx5oY?= =?us-ascii?Q?czmKUu4XNNGYTDGrXaSznKaF+Po7a8cBY1YvzrbS7dNHsLzlDA8axepucZnR?= =?us-ascii?Q?wOmFZD7JzsvnxVH3+c+hjnJQoQpjfy/pBlgj3m1m86Svth1v0MEChHgs9SYf?= =?us-ascii?Q?+WNuDqVbvedGOIg3Fr3G0qw2olKM4XTDAECV2QqNjBhN/D1V5FIT8eBC4IPu?= =?us-ascii?Q?hOXWFrtJRTM2+F66HzHj46NXBE8qKhL/AZColxZWRgYBQfDHCLH9psja7xAL?= =?us-ascii?Q?wMbUxBDTOMBs1QfWwlYk0+KFiIyvRB5lgpm9W6VnKqv5AGP2iQ9G+/Y2C1Kx?= =?us-ascii?Q?XJhMU9msmCX/bjSjC6JPq5ioCrGFB5xTMwFLtKsMI6Hy6HKeF1qaZ6ZT3NNx?= =?us-ascii?Q?I1jrbc8V3nFDZJQyAIfGjFW+rnnZN7+V002PqIQZ6Xh0adDS11mMvtHSbIcT?= =?us-ascii?Q?5wCuivKJjgdeMCxtjRdIqfQ2/Bjcro2ueAF4J0Rs+xGCboMU8DItfg5898qQ?= =?us-ascii?Q?zd8r5Y0vyfCnXV10nbPI/Z2H+ZZMg4keDZXLxc9Q8OqLKqdlkzrYBMA7jirS?= =?us-ascii?Q?1O47AXCVirld1IIi056xIB5UYlSarNre7woj96e33Vk9xGS29igXu36Xttrd?= =?us-ascii?Q?YduBuGjB+2WnpDsDBeNjR6YP3RmUGcjNNxJXpqiYYQFVh41+f71l3jFVjMBa?= =?us-ascii?Q?RVu6nzPxHSFtm2y/O9AYyKCc3fm0l7gKhX4rsuAfE1lBfat4Z555Myk7XkrC?= =?us-ascii?Q?/PSMXnRSYZEwOrmWrkfG1xMlD8xIP4D3eKlf37Y2mvCGC0wwUyBs99M/JHHh?= =?us-ascii?Q?bermLL3UYNZi4qCNlBhE5vqv+tHeWUcGLGMmxxBfVBbi84Snfx+xRAiY4Kdc?= =?us-ascii?Q?RxnTzDVl9jBQ2S7fgdX1p2tbMVEtgmFCZ/f5rebp8MxZ6wRlGXi0otjmRlsk?= =?us-ascii?Q?VcbxMBm79khepk7bUQHr0XMcv9Hs7oJgW54UFVA4UsYNlGtGLn9cVY2aaLDN?= =?us-ascii?Q?0Ipwj+o98d1mT3KvfC998S2ne4zj46hpW16AIhi4evFlu0xWqPg2xg5ic9Gp?= =?us-ascii?Q?l4Ls20PjWAJqfgUO9nu6DaJl2jvBiBejPhGQRzwx3OCw6q5N1ZnDux9gInDN?= =?us-ascii?Q?d0OnSPSc8S1vR3tLOYuWa4Jk8SibhwFK4Uhe0vQdhFB+7D8eFNK5jBAIjCMJ?= =?us-ascii?Q?zMSOcfdE8g=3D=3D?= X-OriginatorOrg: Nvidia.com X-MS-Exchange-CrossTenant-Network-Message-Id: 386ebb82-0a57-4656-0169-08df09699a47 X-MS-Exchange-CrossTenant-AuthSource: DM3PR12MB9416.namprd12.prod.outlook.com X-MS-Exchange-CrossTenant-AuthAs: Internal X-MS-Exchange-CrossTenant-OriginalArrivalTime: 03 Sep 2026 03:15:27.5851 (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: BkfKkKJi6eXg7F8gz+3pDC6/LqXZ3Ep2Z6YdrCGm5dEhuRgfhe7alazhYNP3M3pg/Bi2a3SXgOy2CjpwDWHIeg== X-MS-Exchange-Transport-CrossTenantHeadersStamped: SJ2PR12MB9138 Content-Type: text/plain; charset="utf-8" The GSP posts unsolicited messages onto the same queue that carries command replies: logs, OS error and robust-channel records, and lifecycle notices. Anything that was not the reply a caller awaited was discarded, and an unrecognized function code aborted the in-flight command, so the GSP's error reports never reached the log. Log every non-reply message according to its function code, and leave the in-flight command waiting for its reply. The logging runs on the existing command and wait loops, so events reach the log during normal operation before any interrupt exists. Event payloads, such as XID numbers and log contents, are not decoded. Assisted-by: Cursor:claude-opus-5 Signed-off-by: John Hubbard --- drivers/gpu/nova-core/gsp/cmdq.rs | 58 +++++++++++++++++++++++++------ 1 file changed, 47 insertions(+), 11 deletions(-) diff --git a/drivers/gpu/nova-core/gsp/cmdq.rs b/drivers/gpu/nova-core/gsp/= cmdq.rs index 14a711307654..5572224db233 100644 --- a/drivers/gpu/nova-core/gsp/cmdq.rs +++ b/drivers/gpu/nova-core/gsp/cmdq.rs @@ -556,8 +556,8 @@ 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. + /// A message read while waiting that is not the reply is logged if it= is an error record, and + /// ignored otherwise. /// /// The queue is locked for the entire send+receive cycle to ensure th= at no other command can /// be interleaved. @@ -814,8 +814,10 @@ 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. + /// The expected message type is specified using the `M` generic param= eter. A message whose + /// function code matches is decoded and returned. Any other message, = whether its function code + /// is a different one or is unrecognized, goes to [`Self::classify_ev= ent`] and `ERANGE` is + /// returned. /// /// The read pointer is always advanced past the message, regardless o= f whether it matched. /// @@ -824,8 +826,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= @@ -834,11 +835,12 @@ 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 { + // Bind the result rather than returning early. The read pointer m= ust advance past this + // message on every path. + 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 @@ -849,11 +851,13 @@ fn receive_msg(&mut self, timeout:= Delta) -> Result dev_warn!( &self.dev, "GSP message {:?} has unprocessed data\n", - function + M::FUNCTION ); } }) } else { + self.classify_event(function, seq); + Err(ERANGE) }; =20 @@ -864,4 +868,36 @@ fn receive_msg(&mut self, timeout: = Delta) -> Result =20 result } + + /// Logs a GSP message that is not the reply a caller is waiting for, = according to what its + /// function code reports. + /// + /// GSP-reported errors are logged at error level and unrecognized fun= ction codes at warning + /// level. Every other known function code is consumed without a log l= ine, because the RPC + /// receive trace in [`Self::wait_for_msg`] already records its arriva= l. + fn classify_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 + ); + } + // GSP logs, libos prints, NoCat assertion records, and the ot= her known event codes. + // None of them requires action. + Ok(_) =3D> {} + Err(raw) =3D> { + dev_warn!( + &self.dev, + "unknown GSP message function {:#x} (seq {})\n", + raw, + seq + ); + } + } + } } --=20 2.55.0 From nobody Sat Sep 26 08:48:41 2026 Received: from CH1PR05CU001.outbound.protection.outlook.com (mail-northcentralusazon11010002.outbound.protection.outlook.com [52.101.193.2]) (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 964AD363C53 for ; Thu, 3 Sep 2026 03:15:39 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=fail smtp.client-ip=52.101.193.2 ARC-Seal: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788405341; cv=fail; b=SPavCCv1Pb0VGChW+NH4vUVsXEt6DiqvfGP5WyNjFe6d30Kvt0tyXpj3qwceSAeDZALitjKlMdBbpRAGCZtAjSIE8t35o7hM3T+BLu0d1jYyp2RhF/AzumFifk1dVSEV5qUn549BsJdB9fpVvfc7tCVcLiEsuF0KFdB7Pko7p/g= ARC-Message-Signature: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788405341; c=relaxed/simple; bh=Tywzt1Xq6u+u556aiaBSXLpXbBOgdCCI1IBa7TCj7nA=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: Content-Type:MIME-Version; b=RG1SkZloyhoHduwzFJ3Zas9TqTFTVT+jY+U6d5/IGtK+J19JsV9oEEVtM4cY6VU7hSRXOneaWhGTB31ycgC1f5ZdZOvXpDaby+N8xtQPZthQDwMeVP4WGtxs2GCw8BlxNjcjOZFXFknp9sgfDPUV/S0LyR2R5GbEk+4iAwDLceA= 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=RUkgbvH1; arc=fail smtp.client-ip=52.101.193.2 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="RUkgbvH1" ARC-Seal: i=1; a=rsa-sha256; s=arcselector10001; d=microsoft.com; cv=none; b=zSGGyRimnOBS8RoCJiuwxmNMTiwiniKosljqYOb+me5doboQ6I2oAg3+O05hSN5arVvmIaRtlESQtx9IjtAPow2aCOxmQzNb/rPwhVZTvLkWbUqQ7QcL80i991PLP8RQsodbLPtAngNowEuQlbq9ln8j3Gp4THnQXe5j1c6RfHDck7eLw+BvmswoEC+iMpxhACVy1To3lKvvO+ic6wGiCcP5IdHd1hlziIFCdxe8z1b5KOjv3caQuVq1Mx2FLIq9D5ikplbf9ZgpKNDk7fPyjnbXVrHurvrEBtXgEKb5UOoejVoHYTddriJcSXwAkcraJSZMz5rr4eMS5/Rp4JCPNg== 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=lF9yvtP5COXPlV+AlBxCKkCSkyF51vFfj6KUbVLo/8o=; b=tX/MqFvBu0CRi9ps+7+bDZJPq5v8vAp8we1BAfc/i5pkSB7k4jrnAoaddHnKZUUMLbvaGrJIyHsSx423R6uJeQjSP9tkNEqG/vPVWRY1yRDoUKTpM/3M0TbJunJAlXBnV3QRBJo61ZbMGYYl64GhR9+ncsstr6z5nLxLCuHt3EwuwZMA4WdEHEXLupkHym4ygm1FZKCsqIWp8eySFX6md3UE5Cpo+ei5zw3it0NWticciSlTDnrxuX0WX+6EJld6MUmhi/Ves8Pee5soM5Dtwa/do0sUgrGCl22I4A8WdGk+zTnbNxkjouaXp3nQ75rbFgnm9yE2ji9oKXptzgHdxA== 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=lF9yvtP5COXPlV+AlBxCKkCSkyF51vFfj6KUbVLo/8o=; b=RUkgbvH18W4MUcwCwA+KInl2uQlru8sjyH7oBWxZ+VlfNeT2ePnQM9XaPoit7zuotjNRFT0/d/H8zGXyGuB3CYN61qy9hPhs8zl4vWkrZnA8IdnaZx5WI/V5/1i7rDLeZ0I9i42kyuBboAlan51v3uzw06dwJXOBH+ni/pXC9aYB3DzkRu+in/bUa0tkqH+BIqnDfh5GZ3XvHktVf3LmceIENh2j6yiFIic0sYdyssBMeUbi5PFd3YXjrBkrDHyw221qJ6r3QtV9ms7mN+cA1I37j+ZRnaiXSEENbuKTx3q5UoAKGlqFHJihD9J2NMSucKVu67OyVrRfPaNEIhPIyg== 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 SJ2PR12MB9138.namprd12.prod.outlook.com (2603:10b6:a03:565::9) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.21.360.13; Thu, 3 Sep 2026 03:15: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.0360.008; Thu, 3 Sep 2026 03:15: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 v3 09/14] gpu: nova-core: recover the GSP receive path from corrupt framing Date: Wed, 2 Sep 2026 20:15:08 -0700 Message-ID: <20260903031514.1515905-10-jhubbard@nvidia.com> X-Mailer: git-send-email 2.55.0 In-Reply-To: <20260903031514.1515905-1-jhubbard@nvidia.com> References: <20260903031514.1515905-1-jhubbard@nvidia.com> X-NVConfidentiality: public Content-Transfer-Encoding: quoted-printable X-ClientProxiedBy: SJ0PR03CA0385.namprd03.prod.outlook.com (2603:10b6:a03:3a1::30) 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_|SJ2PR12MB9138:EE_ X-MS-Office365-Filtering-Correlation-Id: 662f28d1-4ae8-48ab-3b92-08df09699ae4 X-MS-Exchange-SenderADCheck: 1 X-MS-Exchange-AntiSpam-Relay: 0 X-Microsoft-Antispam: BCL:0;ARA:13230040|1800799024|366016|23010399003|376014|7416014|18002099003|22082099003|56012099006|3023799007|10067099003|11063799006; X-Microsoft-Antispam-Message-Info: do92NmOtW6Rx9ydTCIQTTcDUlI/7cr5BMkEyuKNzv2iM3YZk2FKj08vPssMPw7EqMjzVZ/MnrWFdoQanlG0kpyJcFwBDsVVi567o0nVwktzvd3EFi7jSi+ank+SIdv83rY8IH1gQ4IPO+OAvuANT+/u1OiK8PsBS0o4J+eP0PUoC8Ukv47m/WP1fGBwhgxC00tJg193YGN+XFKDRnqpvs6oGaCCyC6FQ1+lvdSPjd8dqXvnSif1K46egwTHHSq22k8WPn7HFNUxk7vKCglWgl6ElOUxysmb6f4kXXc6YZNkeTNZPlt6xzFof9Wm7p/aX7E7tCC3I0VEEeclzBK64ScSu7C6kIbGfRn3zTz37p+DFtrXco3GJJYItcY8fk57/6Qh/UFayeSzjZt/krOONijUci48UXvtqlaSUAz/J6QsVOI0amo9NsRqgTJBxtEZrIq6cWPRCOumfF9iQtc4hMOLcg1JgeVHkH6F5HA07okplQO1SOKZmwETPXhRGrT81UvZuJtDc4YXuv1AWbANw37kW2KaevkDf/H7UqoMUaN/OHdWm4wPdtoqwuUXVc2+G2OEScyd7Jr6TOH+NryYoXwocOkA325l1xMhX/hJcMN99npZrufvjtrJeuejrqlU/Kale6TBL3LxsdUshPACysyN+DuVzjXHWpD3wPdNGUUU= 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)(366016)(23010399003)(376014)(7416014)(18002099003)(22082099003)(56012099006)(3023799007)(10067099003)(11063799006);DIR:OUT;SFP:1101; X-MS-Exchange-AntiSpam-MessageData-ChunkCount: 1 X-MS-Exchange-AntiSpam-MessageData-0: =?us-ascii?Q?ixvFCuvdrbKWjqdsYtbevBxX4MgP10xCAbv6dYVTF13G3PIDjl9jUp8S5Ifq?= =?us-ascii?Q?p6/KcLj7tkmJEKzEy8IKm+FL8SNgQFSaM7VBH65bJB/7Bx3zXMe9oZcqJ99O?= =?us-ascii?Q?Wu+S6xpHfS1DUfY4zPQSmqjYY/O8rBaUpeawIUaoLwOtk5BLpMjegp5VHgwO?= =?us-ascii?Q?zpSYxv7IGrKqyFKhlPxy0CopJ1ZPf57uQYaWFAld/YCbgextK4Pwk9jOpOh0?= =?us-ascii?Q?i4ns31eutlZd0W8UWZQafR4vQgpr048zxM0Q+5tSW77J11zsP/FVkPL+16+1?= =?us-ascii?Q?JDvkLlA1OD6qWaovL8IW3srlRyK6S4xvFy2XFe7g6YjJi4NtbEfdihwEP+fU?= =?us-ascii?Q?tvq2CmpLBvm8QNWx8IfXFXIq3+4ok+f/6GhHrwyALyxcRDdbKj6DmikdU9ZL?= =?us-ascii?Q?Uefh/kfNwBKandgrmKbMCvvBvyTw6ClYdYuG9nEHityo1bDOdqFBSIT3viE9?= =?us-ascii?Q?nJDLV6U26n6jnIWD7HCsk7JR6B6fNJO0JqgeZtIkAcU/qpVTT4vy3vYyZsdz?= =?us-ascii?Q?W6ZXXz7jM/V6MOSsGhgE+jZckCU7lGe2LmzEPKEYiwYip/gHW9qiNiTi7CNE?= =?us-ascii?Q?+TW+sV3cIHiFL4FU5hbNzdhBIaCml27c4DT2lgMj9ueVonp8kIsG+sKWYzKn?= =?us-ascii?Q?CZxYrYbbvl8uhVxbTWnPP8piNNbAj9DQRKmlWYGeHD8zGJ3FthZS0JLu7owd?= =?us-ascii?Q?IKy+oGEXOpQvdfH6+II6cPEjXgsigGdo7GVjkAF/9lVQeW4mAPr7y06V7L00?= =?us-ascii?Q?6E6MjoSXEqlcFwwBvbfUYbhLiY+7CMkfMFjbPmbqywVZGz0SobAsEae+2AMV?= =?us-ascii?Q?5bqTMw6j9LYnYP9DMXVwCHPDpq1s7YpFcoOB/TfML5xT03qUOCLuxwg4ezaY?= =?us-ascii?Q?72OXA3LFXMV00jpQSpWzsSU92jqItuwwDTbZBPU973XHnfyMJGkTu/phAYkr?= =?us-ascii?Q?nYptiVkSXiRv67JF+jlbMU4C1e/zo7q+r3Z+m4fdR371Aoh1mBlIOGnab3st?= =?us-ascii?Q?uv71h32CbqnVH8q/sG2/N6N244tzp8kUwZUk9QcbWf8xUqU2Ov/xo4gGk0o+?= =?us-ascii?Q?iQKKsIcH09BD6h7Sfigv88sHLm59kOoY8lTa0MYZgvzxEtOalE6WDZDpwJef?= =?us-ascii?Q?tuVEV35p8zCpET7c9L4mNxcbJF6aqfhN+c97dkmYeC0RBDFoBYmojvnhsvHI?= =?us-ascii?Q?78A3w4viN7tIa0lcJgr5hHTwYZCpRapNJGyG63NzoNxuc6MVvXURYTw/4v9N?= =?us-ascii?Q?ruGlr11AkfbWtxl2XOURjjSPwC8GqOnw9oRARW6dEet5HHN0YzVkIZX55p/1?= =?us-ascii?Q?f6zl8CtsNlzW62k/d4F0q3TeJgh4cjVy79OPvKw9aVU8NPE73doW9TW1DoMV?= =?us-ascii?Q?pcc7JjOUgfQfVNDS+RzbgV0L85NALrPT82O0guQUm0RYNBnoQSAEbJCPDbez?= =?us-ascii?Q?Rp55+ZgdMdvQkdRXxmnyynIvrBhdqJDVOqFhqZ908I1cCWWZrBpIQeg1ZNAK?= =?us-ascii?Q?DHq+E3lFeyVC9ejhrvFrUttfSG5XjGIkqw0c98QE8p+hoouFhzfA6Q8hoKji?= =?us-ascii?Q?uaw8eYGmZ3LZtmTcs4bY3NQ9nCfhFznbX1CCEvGHUXi4lo1XoysWDgP7yJNr?= =?us-ascii?Q?a5RdI1ZM7YR8ALfKw+l/Tflgdwry7agx/A+mV5jEdv/NjvOggT0X/w+a5v2e?= =?us-ascii?Q?1TV7TwOCTthmsJ09dHfFrXYeA18QHX5JgtmJzPePQEKy94wi/G8soxqAYrUD?= =?us-ascii?Q?7EYvKqVUzw=3D=3D?= X-OriginatorOrg: Nvidia.com X-MS-Exchange-CrossTenant-Network-Message-Id: 662f28d1-4ae8-48ab-3b92-08df09699ae4 X-MS-Exchange-CrossTenant-AuthSource: DM3PR12MB9416.namprd12.prod.outlook.com X-MS-Exchange-CrossTenant-AuthAs: Internal X-MS-Exchange-CrossTenant-OriginalArrivalTime: 03 Sep 2026 03:15:28.6440 (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: RMILL8mLoisPJeFtf76l5wvIgrj2V/+fcCGgORCgCqV88WvxDZDK+xj2Ci30Vt41LZZtb8hklk4K/p6DLAyalQ== X-MS-Exchange-Transport-CrossTenantHeadersStamped: SJ2PR12MB9138 Content-Type: text/plain; charset="utf-8" A GSP message carries its length inside the checksummed region, so once the framing or the checksum fails, the length cannot be trusted to skip the message. Two paths left a bad message at the queue head. A framing or checksum failure returned without advancing the read pointer, so every later receive re-parsed the same message. 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 head is parsed once and recovery requires a reset. Advance the read pointer past a validly framed message whether or not its payload decodes. Assisted-by: Cursor:claude-opus-5 Signed-off-by: John Hubbard --- drivers/gpu/nova-core/gsp/cmdq.rs | 96 +++++++++++++++++++++---------- 1 file changed, 66 insertions(+), 30 deletions(-) diff --git a/drivers/gpu/nova-core/gsp/cmdq.rs b/drivers/gpu/nova-core/gsp/= cmdq.rs index 5572224db233..ce4d6a111e68 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, @@ -531,6 +535,7 @@ pub(crate) fn new(dev: &device::Device) = -> impl PinInit, /// Current command sequence number. seq: u32, + /// Set once a message with corrupt framing or a bad checksum is seen.= Such a message has an + /// untrusted length, so the queue cannot be advanced past it, and eve= ry later receive fails + /// until the queue is torn down and reset. + /// + /// A [`Cell`], so the shared-borrow read path [`Self::wait_for_msg`] = can set it. + poisoned: Cell, /// Memory area shared with the GSP for communicating commands and mes= sages. gsp_mem: DmaGspMem, } @@ -732,6 +743,19 @@ fn send_command(&mut self, bar: Bar0<'_>, command: = M) -> Result } } =20 + /// Marks the queue unusable and returns the error every later receive= fails with. + /// + /// `reason` names the inconsistency. Without it the failure is invisi= ble, because the queue + /// just stops producing messages. + /// + /// Takes `&self` so the shared-borrow read path [`Self::wait_for_msg`= ] can call it. + 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 +770,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 framing or the checksum is invalid, or the queue wa= s already poisoned by an + /// earlier such failure. Either failure poisons the queue, so recov= ery requires a reset. 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 +787,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 +806,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 +833,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 { @@ -824,8 +857,8 @@ fn wait_for_msg(&self, timeout: Delta) -> 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. + /// - `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,23 +871,26 @@ fn receive_msg(&mut self, timeout:= Delta) -> Result let function =3D message.header.function(); let seq =3D message.header.sequence(); =20 - // Bind the result rather than returning early. The read pointer m= ust advance past this - // message on every path. + // Every path must advance the read pointer past this message, inc= luding a failed decode. 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> Err(EIO), + } } else { self.classify_event(function, seq); =20 --=20 2.55.0 From nobody Sat Sep 26 08:48:41 2026 Received: from CO1PR03CU002.outbound.protection.outlook.com (mail-westus2azon11010063.outbound.protection.outlook.com [52.101.46.63]) (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 5F62334D4D6 for ; Thu, 3 Sep 2026 03:15:41 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=fail smtp.client-ip=52.101.46.63 ARC-Seal: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788405343; cv=fail; b=TohHVLqBNf0PCuRN9xzYjTixeQ6TRYyfmCnm6n5qehWW3X5GyGmcP0ANdvVo1PIKuRZitxKt94LKjo3F5RO+YXLTqi6WQPh/0UEZ4xJW26T+lYAVrFB5vd92WxeJGVVKScqtFhh4bRkQd73VEVLThTSJ00RHrSNoMDhUptR3TOA= ARC-Message-Signature: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788405343; c=relaxed/simple; bh=vVc533YQoWpovNGqf5uesjdH2wWdmDLpn3RFzGHOExE=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: Content-Type:MIME-Version; b=MtzuARM4uyMUm3YIMnIIqfkJn+knU5qAn7PECkR/i2hoPDd+swfUotxu5C4vkiV1lAjYYHkYUpR5f7GRT2dT3o+w3cKPRGHsr5WOEZD7NICLnA7Fsf+CaF1ellHp9BA1ig2tfhVCyrsZ6KcRpUW/sMSY0FXkxwGNvaMGMP0gZ/Q= 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=lqCaBNUy; arc=fail smtp.client-ip=52.101.46.63 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="lqCaBNUy" ARC-Seal: i=1; a=rsa-sha256; s=arcselector10001; d=microsoft.com; cv=none; b=SuaurlpJrwzIli1nJBttySKaY+/WJ4m1RPtqoF9DZsr6UJtUv06LNNm4FA+M9MCYYW3lPdydwqSGsObBncUs8R56MPQlOEb30CAfCj+ZOONk1HRMYzw4I6GcYfc1Ce5ZyYXq1Eg42H89IYnGro6tMDZxTzz+UBgG8qdjRpn+J0YejkEnOMd2QzB7mGGJCCsF43XN+Opiq3PD6RGHXapCzw7NzraTLB9kBKe54K948oGCZQEXsZcQ808fnUhGTHq8k7KILqV4edpBMKT3cBhHQcxZYHQigNo9gu2dl3Stq5eLVxZfk/e7h02CnXnmzU7oMbkdtmltEERI69CIB6alrw== 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=4Tsj0ijUjA5Fsg4HJ0I3dhbG6JZzOHS6YVWeH9jDtoU=; b=dwBz28Akz4NdxUsl+EznYCEs5nBiOCp2C8Uedx1+5Z6ldBIvaffm5wHvNUHtQarGPqF7wz2RN1WHdnmTczIZ74d04tZMz7IFRG+nrHwG558YSuo0AH2AZSu+U83gHGHSUh3VyUYb2Wwhu5KaF+CgU3b9AijEK2gter2kw5meWikphtv4iCk/7uU4NiHhT3uHE0JT7qhq0h1UwFVAuQlobX4G0V9OhKVmE2dqnTTZqq97G6Hs+KpXscrK3qrmdrjwMj0OKKVwwAgCgEeIZAJyejA+Gd3aE1SAlbEPUqDNilRNTbv8bhyKvz103zTufUNqmlE0f+Ap7uAUSGOsq/xPAw== 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=4Tsj0ijUjA5Fsg4HJ0I3dhbG6JZzOHS6YVWeH9jDtoU=; b=lqCaBNUyacdvnQSrf4AppgF91lF04uKUz3smt5gNepQa0/UiBiXlWPKmvlCX4gg7njSMScX4hss7BkJUqH1hs55QB7A70IhHHYPUEAW/fe8Kf16iN59PS5+ispkz7Wz6MuEiZrG4kDXBlqqrsxx/neUztmqMSnQbWYrWIKIbKXN2e3FHx7MwF9exA+fyWPaSbGR3r74zH+J4kwZ2lYkVT/i05pzICtwoDQiDwNxlyoqHajGVK5jj7IGtkOezDHnlcWjIgPrMoogELZ1ATZONyanKg6UFR5KaQ/VCweJ5oIHFXVcelalzRRN67HrQ6yot0ijwhDlU0zhYyajpBEXs0w== 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 SJ2PR12MB9138.namprd12.prod.outlook.com (2603:10b6:a03:565::9) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.21.360.13; Thu, 3 Sep 2026 03:15: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.0360.008; Thu, 3 Sep 2026 03:15: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 v3 10/14] gpu: nova-core: bound a GSP wait by a single deadline Date: Wed, 2 Sep 2026 20:15:09 -0700 Message-ID: <20260903031514.1515905-11-jhubbard@nvidia.com> X-Mailer: git-send-email 2.55.0 In-Reply-To: <20260903031514.1515905-1-jhubbard@nvidia.com> References: <20260903031514.1515905-1-jhubbard@nvidia.com> X-NVConfidentiality: public Content-Transfer-Encoding: quoted-printable X-ClientProxiedBy: SJ0PR05CA0120.namprd05.prod.outlook.com (2603:10b6:a03:334::35) 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_|SJ2PR12MB9138:EE_ X-MS-Office365-Filtering-Correlation-Id: 689a8b37-8ef7-46f8-ba8f-08df09699bde X-MS-Exchange-SenderADCheck: 1 X-MS-Exchange-AntiSpam-Relay: 0 X-Microsoft-Antispam: BCL:0;ARA:13230040|1800799024|366016|23010399003|376014|7416014|18002099003|22082099003|56012099006|3023799007|10067099003|6133799003|11063799006; X-Microsoft-Antispam-Message-Info: KRyT3AErNFcZeXH17D4SLE1s/ld/GcSMdMkhwW2nNZp3eLGN7zaIJOqstGz1R7SWPWejsoOQgByL2dHtnGi3NlZZPd7KYpybCApYp0G92nX3rSoKqs7F9uO1AUJWu+5TbZfVgiVjmqXGXrnyaa+4dKjFywOTRm0VnZrcDNRyt9Be6TU9UtST2oUjXOLpkMMBEDUXuhFk2l3y0FOycQS44UbJL+cJbMcgHNgqeBRQBHh9+iGQVszdpDoHeN6OpTVoP3Vll7FB5u+3nhqz41wI7emBawYP0BBCczLwFoyEQUxTHVplEruBrRYAGRpuWyw6vFdByd4EDPDX6PCNAFPMHlWmw3BWH10U1tZnsYoMR52HezslWDC7IpdUoj94N27QkI812wGHD8ZIFhsXtlaPAj4L3BwgoDxxhdDQ0DZuSusRu1dmUzh2PwXSqvX0gzetOC4ezQZLCF2z3v5VUoyVPPlUMxYv2d2shNW/imXupNmtxEAsPWqNJshEPpvsG1WtAGpnd43qQRXgff/eSZDHRWoeSudU4pDCQ4U7JG9ZAUfDGkX9yRnIiDf76ev5VIKXQs+dQJvmFogvCYyalC4LUGX2Op8nq6p9YIMH2v49YdHGDC4rZ09GcrkTpgqEfvKAcPly4k2OhHdJXuJuq3gtQtV8DTOSDd8Lys05+FU3LYI= 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)(366016)(23010399003)(376014)(7416014)(18002099003)(22082099003)(56012099006)(3023799007)(10067099003)(6133799003)(11063799006);DIR:OUT;SFP:1101; X-MS-Exchange-AntiSpam-MessageData-ChunkCount: 1 X-MS-Exchange-AntiSpam-MessageData-0: =?us-ascii?Q?Itva7d9TsrRdUMPDs6ZTpBQaOH55+IQthQl4HcOu+qwSNa4gM+R3zb8mYsef?= =?us-ascii?Q?1/kJytL9Uwrgc7IJ0QHA6IsMQjilJYS8cWEMr9fjv8ym5qWdtG73+ytOjGEe?= =?us-ascii?Q?5pebNCHp++3J2KOhF6DUE+d8Qt1GyLIHvEtGYqqaNb/v6LdPWIPSDKjc8xz7?= =?us-ascii?Q?5TDN2zHSHkkhN6gxwsi0wY+zUx3ZB+u8dRXV3lSqya6qHfx6RJ8NESuICu14?= =?us-ascii?Q?6IjZlaGnfc7YEC7BybILgJrNGhUVdE2B7ljcgXG+U3f47XnlmAhKeVRb+NKj?= =?us-ascii?Q?saF4JnUZXllSgmUg8VmYtsBiEnGKjt91p/ny8A57SrG2Nr900W54JSBfS2CF?= =?us-ascii?Q?siXU7oqWS1v3f4m9EJFgcz+znx8QYWrd1kxTwsA4CsNULhfMKRKU7pBPURPo?= =?us-ascii?Q?+qPWjiCpC+vPm/J58ouXusOafIs3G5YDXgvHsIXnCeUH1gkszRVaTR/BZuoN?= =?us-ascii?Q?p+kwIquWDTLVJVupsGLkUgT2REx3zybL7bhQ9jbWsDxdowcnZEbihRL4v85w?= =?us-ascii?Q?H75cVnfw+4GTeFC0zleOeEJZ75IClbjOlMDPRH6Jyb2juWRZlxdGWVAJb5gI?= =?us-ascii?Q?BI11RhTU928rzAt/gwVZu80cVo3pDkFKj23gXniGprY5Mrzelq6opNV63DbK?= =?us-ascii?Q?jKmerICo6uehBCGLRo6F3RVsTK6fmGgwbq9crvrkVCf4eNnxavBtHVyGJ32V?= =?us-ascii?Q?hCuqC2oM+sQqetnwfr1lLm/4TC6jC5h8gJ3GgGLKGep2wQSSQW0MKV6miaOD?= =?us-ascii?Q?YMQ+eSvcyFyDYjRXBjL/6GKL2m7zG4WAts62ftpGkKNb3KZD5sGImWfpH3SU?= =?us-ascii?Q?+NK1T7tj6aolAMd5ZFQ90C/6jR2M6qRkxy0aJcU5oESSOkAT1qr5XSIMUpo1?= =?us-ascii?Q?quG3BGxbRkJXFb5HO9IrToaX13b6Xtsv5NerSafH3y+FNOnHDsnnd0N9joab?= =?us-ascii?Q?g3xQua1W0Nr5HmT48ikyDMEQMO1hP3ioy6F9xgDuF4b6y4g2R/ZjMVl5bp5q?= =?us-ascii?Q?8bPNyIp8wYwUVYTWDjJUkaLsKHLqcUWeLAfHSsldLZDxhI8TvbzyP6ADcwG2?= =?us-ascii?Q?XTBwrYy1nLI/J7hgokOpkpmljD4RKDRSGwiY0EDWmDeTeIPNUXseVP7jbsjB?= =?us-ascii?Q?gtud/R/KvE2TEy+2mOXO5XXQOp8nolQvNRTlMZe/JuhvZltJN9OpTP/wtXEy?= =?us-ascii?Q?58Z4yC+Rf6gSKFSiqOHBZsR2ujwpjlr8wad3pyflO5D7grJHN6NS6sDRaJZj?= =?us-ascii?Q?CoukZYNswtC9MwcXLgbAP5yzp5MTgcTZtTCzM88UcJ3lObckVkAAqzOukE9B?= =?us-ascii?Q?165fjIykMnRrgVzMwZRaQKfWuR/3kfXe1NWB6tEzdy7KpfRFehlXUpeYN02d?= =?us-ascii?Q?rf0cDQcB2taC/SO5OfXmTCyd4ZUpiYTogtb4bRAlceDTnsFOU3pL/AhivRD/?= =?us-ascii?Q?+a4C6MxsEzvurRh/oJLyzd2PqluhrIkcW0iNznJ+wwbPXOQACXLLkfo9tc89?= =?us-ascii?Q?lqwTx3M+z2dCVF2KqdNP+xhoiVsWgtWWStRlQlinaJLydC6HgSLJUbwKGe7c?= =?us-ascii?Q?5mr7hLoaObULWKJQsC9pu2BsHrXGAqxNyhSCOlJaQ1HN6awZIhBjD90KfH+D?= =?us-ascii?Q?OYeptQXiTle8FuIHW7fNPiDmwUr4Gzn2MuxX+s8RYxMru286fGFR4HZmsnuc?= =?us-ascii?Q?oFZlkdLZM9FX2C4g4SN5pComRyNAfMgJ/AGie0Lu18VaV7tlpoDrWqWMICym?= =?us-ascii?Q?rI5j6UYoiA=3D=3D?= X-OriginatorOrg: Nvidia.com X-MS-Exchange-CrossTenant-Network-Message-Id: 689a8b37-8ef7-46f8-ba8f-08df09699bde X-MS-Exchange-CrossTenant-AuthSource: DM3PR12MB9416.namprd12.prod.outlook.com X-MS-Exchange-CrossTenant-AuthAs: Internal X-MS-Exchange-CrossTenant-OriginalArrivalTime: 03 Sep 2026 03:15:30.2393 (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: BWbez0FkrrSVB46nYIdtosIcQX+Dzy8yPKkFD7O3imjWllpFZ9ReEJTOcsUqfeu9nAZsUikpUQ81EFGJojM/yw== X-MS-Exchange-Transport-CrossTenantHeadersStamped: SJ2PR12MB9138 Content-Type: text/plain; charset="utf-8" The GSP posts unsolicited events on the same queue it posts replies on, so a caller waiting for one message logs whatever else arrives first and reads again. Each of those reads started a fresh five-second timeout, so a steady stream of events extended the wait without bound. The wait also released the queue lock between reads, so a command sent from another thread could consume the awaited event and leave the waiter to time out. Compute one absolute deadline when the wait begins and pass the time remaining to each read, and hold the queue lock across the whole wait, so the wait is bounded however many events arrive first and no other caller can take the event it waits for. GSP boot waits for two unsolicited events. Move that loop into a helper so both take the same bound. Assisted-by: Cursor:claude-opus-5 Signed-off-by: John Hubbard --- drivers/gpu/nova-core/gsp/cmdq.rs | 50 +++++++++++++++++++++----- drivers/gpu/nova-core/gsp/commands.rs | 8 +---- drivers/gpu/nova-core/gsp/sequencer.rs | 8 +---- 3 files changed, 44 insertions(+), 22 deletions(-) diff --git a/drivers/gpu/nova-core/gsp/cmdq.rs b/drivers/gpu/nova-core/gsp/= cmdq.rs index ce4d6a111e68..a0f995faaee5 100644 --- a/drivers/gpu/nova-core/gsp/cmdq.rs +++ b/drivers/gpu/nova-core/gsp/cmdq.rs @@ -33,7 +33,11 @@ }, Mutex, // }, - time::Delta, + time::{ + Delta, + Instant, + Monotonic, // + }, transmute::{ AsBytes, FromBytes, // @@ -569,8 +573,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,8 +590,13 @@ pub(crate) fn send_command(&self, bar: Bar0<'_>, co= mmand: M) -> Result::now() + Self::RECEIVE_TIMEO= UT; loop { - match inner.receive_msg::(Self::RECEIVE_TIMEOUT) { + let remaining =3D deadline - Instant::::now(); + if remaining.is_negative() { + break Err(ETIMEDOUT); + } + match inner.receive_msg::(remaining) { Ok(reply) =3D> break Ok(reply), Err(ERANGE) =3D> continue, Err(e) =3D> break Err(e), @@ -611,15 +621,39 @@ 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`, logging any other = event that arrives + /// first. + /// + /// The queue is locked for the whole wait, for up to [`Self::RECEIVE_= TIMEOUT`], so a + /// concurrent command cannot consume the awaited event. /// - /// 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 a message fails framing or che= cksum validation (see + /// [`CmdqInner::wait_for_msg`]). + /// + /// 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) + let mut inner =3D self.inner.lock(); + + let deadline =3D Instant::::now() + Self::RECEIVE_TIMEO= UT; + loop { + let remaining =3D deadline - Instant::::now(); + if remaining.is_negative() { + break Err(ETIMEDOUT); + } + match inner.receive_msg::(remaining) { + Ok(msg) =3D> break Ok(msg), + Err(ERANGE) =3D> continue, + Err(e) =3D> break Err(e), + } + } } } =20 diff --git a/drivers/gpu/nova-core/gsp/commands.rs b/drivers/gpu/nova-core/= gsp/commands.rs index ffc25fd8c47b..61fe93db9e7e 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(ERANGE) =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 bcad1421953a..e2f1da129d8f 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<[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(ERANGE) =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 Sat Sep 26 08:48:41 2026 Received: from CO1PR03CU002.outbound.protection.outlook.com (mail-westus2azon11010063.outbound.protection.outlook.com [52.101.46.63]) (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 60D33372B2F for ; Thu, 3 Sep 2026 03:15:43 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=fail smtp.client-ip=52.101.46.63 ARC-Seal: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788405346; cv=fail; b=MS2JdjYr5BEQm2Ym1/DZ5hf4DW6WKmDfIonpDvmLsDwWgteQ3uHbBv01VqcTflHbSzd/HE4lWTia/sHuYK3HlKT/yZH9d4lntw1eKR5V02ROcRwr7XrXW7RQ6/rKxLeJLGc9PZYP65pdK40wZWTfsEBwT4NmpQBMvilN3U7RGsE= ARC-Message-Signature: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788405346; c=relaxed/simple; bh=ZOuJl0OQOBWOjEcSjG1TFPmBJFkognUQLqa/hMnEZKA=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: Content-Type:MIME-Version; b=AbDbtaC94sFPvFQ9SGZgqgrL8F7YvvDYnGCknmd1P3pEAyAIIXMqPPCv8TO/wjUeLtLM4gKxfNc0hHXXUef5IqTnX43GPQ0hAW3kOhD88VVG98IOhk8Uw3AGoJ9EMWNkw3hVmKqEi30QaqPFqB4Rv5KDlerIp33hIXrS3hgB/Tc= 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=uMuVAwh8; arc=fail smtp.client-ip=52.101.46.63 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="uMuVAwh8" ARC-Seal: i=1; a=rsa-sha256; s=arcselector10001; d=microsoft.com; cv=none; b=HC9ImGJSeM6g/7XyEtgz5psvZ5Of1OwprfJICt7ZNpD+b9ilNxCkZub1WrEHwL0zMWuKE5t5PqIZFiOy6u/V3mEHRTOoZPaASmgR4wLTBUFiNFaEpDZa1yuVTiAb0WZPxY2rpSrT0W3KQgHrnRooA18JwHCPrbhYcdKLlNhX2NZMhWThXR/jHFMmcPIe+S5KR7/yBQPEl36saKP9SSuWT3TuEV5YQA0xZp2jM+5VIHOWJCrdJUaYSmCz7A0bUA1Ya1cKCtvp7TocuZdexFSPG0fOQHI1zDJ37KCh7dgjRiLm5oBjm31VmJWhSLoOBYejP9FyzvJYL4uDpqqfq0vobg== 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=EL72QSUOvclsmVyZVxl5HxKLfmNaFoeORzlHE5ARtGA=; b=Eup9HAaWAqGx5bB0Im071rdf7Bu/pdgbp4aJgZ/78MraTqD9VVKY0PyNqdNynrNouJE1Uh5DocRu/aw3IG7DT/xtoQVS8o7JkwFvNCXU46MwBQ5y2Vw3zCkbzCs0ih5Ae0rk6nArCunHx8ndeO9KNiIC7ePgGFR6LcPUl5aYmWt8oh1X62wu7mzs+eZ4m35Wp8nTBQ8JcdL0NsqxWR6I6qneNvOLVASR86o2kvd+x4N5xM5FnzqMxys/7SxS1NT6hUjSAGH1qU4MdCEg0x+kAQWEJOKuOGGqiVdh0TJpQ6iMeT0lpmpcQ6Q9thPHxddorjx5f+gUc8U8KgzOeS7Szg== 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=EL72QSUOvclsmVyZVxl5HxKLfmNaFoeORzlHE5ARtGA=; b=uMuVAwh8WVB+i8LHWe/DyWnupfVAttRpu/pdxndQJ702qquAe0IzTo6lQXv3wywtdfBSJAPYnz3+qmaCywI67V+TQJ+ocmfSK3PmqUvqo4jJH+fdMLGbOjsftmLJgGBVMSS+386VBJolAN2Twy6P6eGqLYTmhdyAR14hy6D4N2o0H8aUzaXbRcc2s/NbjbDuutAl5YEocXf7p8MGboJEerMIbSyvOzPcVG4sXCAoUzMVvdm0GxM4JCzG+BH4s6/Bxu+3pyuucY95p0kE1vzYzOHzGqjNhB6YYR6E/RL7mmsnlCToAeLzqMwM/QhNrB/xN9TLvj+2Wg9OsZXLKmotYw== 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 SJ2PR12MB9138.namprd12.prod.outlook.com (2603:10b6:a03:565::9) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.21.360.13; Thu, 3 Sep 2026 03:15: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.0360.008; Thu, 3 Sep 2026 03:15: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 , Will Pierce Subject: [PATCH v3 11/14] gpu: nova-core: add the falcon interrupt status and routing registers Date: Wed, 2 Sep 2026 20:15:10 -0700 Message-ID: <20260903031514.1515905-12-jhubbard@nvidia.com> X-Mailer: git-send-email 2.55.0 In-Reply-To: <20260903031514.1515905-1-jhubbard@nvidia.com> References: <20260903031514.1515905-1-jhubbard@nvidia.com> X-NVConfidentiality: public Content-Transfer-Encoding: quoted-printable X-ClientProxiedBy: SJ2P221CA0011.NAMP221.PROD.OUTLOOK.COM (2603:10b6:a03:5db::7) 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_|SJ2PR12MB9138:EE_ X-MS-Office365-Filtering-Correlation-Id: 59ebf472-7b84-4887-bf91-08df09699c9c X-MS-Exchange-SenderADCheck: 1 X-MS-Exchange-AntiSpam-Relay: 0 X-Microsoft-Antispam: BCL:0;ARA:13230040|1800799024|366016|23010399003|376014|7416014|18002099003|22082099003|56012099006|10067099003|6133799003|11063799006; X-Microsoft-Antispam-Message-Info: tTKxsD84SVVVo2lpjldHqZa8qe1FHeJ/yxickgsVA4kO4tYwbGU+fFO02jiQ7SjXSwGTxThtHHVp+/XpeSv1rx+wgJhC9JhWxJRsTqhWy6rcXtOhUQVAk6HZFj17W8Meq+/6FdSuPIl6u5q54F4ywPZI4/AUVy4HiOF0drj+2RXj8LSjc0Ds3DmeuSv+V3BOEHS02ue805NV2deEWL9/qNKofXVs7oGlB9Bv/RcsF8vp8hTDGEL/7QU93XwRnHkT/LIDKln5MyhwqBulGzEK4+DNuoVF+6VOMiU2bXyQGvp1X+LxlhBbkOUYoHBTFisDaU5PvEExS2gKohvHPJVQcqiopPEipM+aEyTdrSHcZ8FLjGD3C03wdKyuHInPEaZFSqdZxnXQi5/q8mrQuhvoIqR9wpjn9kniRR9gZfORQWcJulubz0wu5Jvu2CNI3h4NMEFoG1HHAcHaVWhJ5CjI9vXfS+zKCh15p+fddwYk9v9vWqDLjV8LqcjdVSn99DxlbSKw2om526O3IU1ljKtdhiTePgo7Ec9zjQZPLuk6YL9Pj1j4grB+DimEuRHo5ouPwROOj53i7+NmlsN1UEt9b9CbHs/9G98ECqXAWoZhHkkulDWlMZOl1NM3ygGhlUeci+DnSdOXTO3f+fmKmIcOH54XYk4d3q8x5tM70Qce6Tc= 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)(366016)(23010399003)(376014)(7416014)(18002099003)(22082099003)(56012099006)(10067099003)(6133799003)(11063799006);DIR:OUT;SFP:1101; X-MS-Exchange-AntiSpam-MessageData-ChunkCount: 1 X-MS-Exchange-AntiSpam-MessageData-0: =?us-ascii?Q?BT4p9ZTqmFzSMkk5/VNwhU9q6V+LtfBM+D5nXtXzrBG2PMWnRatH0/ua0dQ7?= =?us-ascii?Q?cKDBH93ll6NfoHS6K/m45cT2VzoaMSIN0rUTwJv3KnSdgEG0TCpd8z624JVb?= =?us-ascii?Q?FjDShGxeUiD3ZOJhV4MeSIZdL2uZjoiUs09hCvWFFlFLCFhRPdcevVC/nQ8+?= =?us-ascii?Q?ySemhxnE4fqV79O3uk3ZZjTPpPjL70vrujZCFylE181vaaJ0CnOsmsPajR0j?= =?us-ascii?Q?12StaqEEa+R8JxK8PpXXAlA3c1Utqi1gRekO53b8fDrGkEs5psGX1LygqN/A?= =?us-ascii?Q?ZCr3bFbUE3Nze6VyaIC4+epY7bJbzKvKk9UpPpNA927t2dTwktUJt7JpH4VW?= =?us-ascii?Q?w61VRAiNhRMSTEjF8M6ZAoyFQzN5mVlXXFbOtE4wm86yrZyRxHuOpByo+oFM?= =?us-ascii?Q?00ZgUUD0Lwq20Xi7E7IcVLWHqPXRoiJUxgk+XzZSh2/4Pwbr40ATvS2W5KHw?= =?us-ascii?Q?hsMtWybTw9HCC2w+XcnN2ZDKLFhdcd+q8ZefxWrOHy8SUkU+kJ6JMDOYBVbI?= =?us-ascii?Q?CmBK3aVM+QwNCaUNBfBR1IHAOcBqdMij7aZB0F+1v2D0TbdkfpY3a/yttCXg?= =?us-ascii?Q?6/I2qZsgVhgDFlzPFf3gLWU58YXNb4h4Dw3L5vmU1s3eWu7BW+ssYvw37+8A?= =?us-ascii?Q?tu7L2tqWlGi2hhHc/5q0dSEqxrXTb8RAr8Ija2Z7UH60yUZWTupkh95Zk93x?= =?us-ascii?Q?4WN93LMhgc6G6dIIPV2jRfDehHoiEMvR1XgTX1xN6FkJujP+2WnFMAOtqf5D?= =?us-ascii?Q?XgSeYNaKeAAqpCk46FdnJ4rCgGtJEEbcl+J3AWxWy0ZkxhSylrj2kQRa2IF5?= =?us-ascii?Q?JvCtX12KGhnHrLs+5NWMeN9/sG7meWV5p3G6+3AHeWrtp7g5wpTe6MmQZ2Dd?= =?us-ascii?Q?xUoVRKyzxykmsUaCg+oNz2Dk6LtoTf8vTRKthQ/8X5Ifg6TeXsfDdvSga5qw?= =?us-ascii?Q?D9C19FBlt6lSBn/gaWUvw+mXFnnIxqqp8LYOSuzkIN88Swn64uVWlKUEnO7L?= =?us-ascii?Q?Wwnn9Yu4hyGaoHWH5JATQLf/vslyFNwJS2GlXJVxI5CWeFEjSCkPfLgNUAvI?= =?us-ascii?Q?Q+hbzD/ILw21Dz3rvXwjhTg0lJTQHkLvuX2unapOMQHDRq+peAQlSh6Z6LWe?= =?us-ascii?Q?hwxEGo3ShQvqXRRmI3lFM78FILeWnFqC0Cli9IytHOMeks9S/gNH1B6HLKn5?= =?us-ascii?Q?F4JMtA0/21pdIdRL+YasM4O7/vMqPh6jlUMXJ3MLE0ODCljVb2HmduvzsZvt?= =?us-ascii?Q?ALNFTSaY+NSh2bdg6tB5M7UjDikgBCWOmpKUmaPEa6fEcXk0uiYE7cdfAVJf?= =?us-ascii?Q?hqzoTZN2rcXkJtGaczyy3QfOtQQWtSCq2+YIQcmhdymbAobKwBgj1a1m48S+?= =?us-ascii?Q?q8KNFRakA9KoHBznA2RG/uBgn4Y1yqrsM/pGliCs9VpE2E7Gqz3ReVU6KPk2?= =?us-ascii?Q?zq6k2dFL8ij8pbwa2gpktktSNdN6/9PYKYiMIr4HBJn0YJm3djCsI3iSjJjd?= =?us-ascii?Q?Wk1bsa+US0Y4LuH18sinN7fhCQ+mIKTZpZt7bX4AfCkFfv+S+MJr88rEG5m9?= =?us-ascii?Q?6ZoUD1PrnQq2qupCUnPEMm6/Sfqq0kTmDZFpZt29x8jCYxGyrULTkqzAOZrM?= =?us-ascii?Q?IN1+TR/YWt2N5ACfODjS3Sh0F7Mj6UHQxJMcSeKvchkGMnUw1+WBbkUmjr9J?= =?us-ascii?Q?CbYuR49TMx1wfo9ugLr5tsPYThLInamx6sbr3BpLqP8Fp65+ffUGLffcS2xu?= =?us-ascii?Q?CdjifMawNg=3D=3D?= X-OriginatorOrg: Nvidia.com X-MS-Exchange-CrossTenant-Network-Message-Id: 59ebf472-7b84-4887-bf91-08df09699c9c X-MS-Exchange-CrossTenant-AuthSource: DM3PR12MB9416.namprd12.prod.outlook.com X-MS-Exchange-CrossTenant-AuthAs: Internal X-MS-Exchange-CrossTenant-OriginalArrivalTime: 03 Sep 2026 03:15:31.5126 (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: i5Owa8jvwFHnPIzAK5srLtDlKhtykut1w0gidt2rQSeXaudl1klkOYwIYsvLBRg/F7H1juRwELrgQLfvxMtQSw== X-MS-Exchange-Transport-CrossTenantHeadersStamped: SJ2PR12MB9138 Content-Type: text/plain; charset="utf-8" A falcon latches every interrupt cause in IRQSTAT, whichever target the cause is routed to. On a RISC-V falcon each cause goes either to the core itself or to the host, and PRISCV_RISCV_IRQMASK and PRISCV_RISCV_IRQDEST select between them. Open RM intersects the three registers to get the causes pending for the host. A falcon signals the interrupt tree on a transition of the causes routed to the host, so a handler that clears the tree leaf while a cause is still latched leaves no transition behind. INTR_RETRIGGER supplies one, and Turing falcons do not implement it. Add all four, ahead of the GSP event handler that reads them. GA102 moved the routing pair and GA100 kept the Turing offsets, so those two go in per-chip register modules rather than the common one. Assisted-by: Cursor:claude-opus-5 Reviewed-by: Will Pierce Signed-off-by: John Hubbard --- drivers/gpu/nova-core/regs.rs | 66 +++++++++++++++++++++++++++++++++++ 1 file changed, 66 insertions(+) diff --git a/drivers/gpu/nova-core/regs.rs b/drivers/gpu/nova-core/regs.rs index 3422b49df7a7..502712e9c161 100644 --- a/drivers/gpu/nova-core/regs.rs +++ b/drivers/gpu/nova-core/regs.rs @@ -120,6 +120,14 @@ pub(crate) fn usable_fb_size(self) -> u64 { 4:4 halt =3D> bool; } =20 + /// Interrupt causes latched at the falcon, one bit per cause. + /// + /// A cause appears here whoever it is routed to, so a handler on the = host side has to + /// intersect it with the routing registers to get the causes routed t= o the host. + pub(crate) NV_PFALCON_FALCON_IRQSTAT(u32) @ PFalconBase + 0x00000008 { + 6:6 swgen0 =3D> bool; + } + pub(crate) NV_PFALCON_FALCON_MAILBOX0(u32) @ PFalconBase + 0x00000040 { 31:0 value =3D> u32; } @@ -247,6 +255,18 @@ pub(crate) fn usable_fb_size(self) -> u64 { 0:0 reset =3D> bool; } =20 + /// Re-emits the falcon's latched interrupt causes into the interrupt = tree. + /// + /// Write-only. A falcon signals the tree on a transition of the cause= s routed to the host, so + /// a handler that cleared the tree leaf while a cause was still latch= ed has left no + /// transition behind, and this write supplies one. Turing falcons do = not implement this + /// register. + /// + /// Open RM declares two elements and uses only the first. + pub(crate) NV_PFALCON_FALCON_INTR_RETRIGGER(u32)[2] @ PFalconBase + 0x= 000003e8 { + 0:0 trigger =3D> bool; + } + pub(crate) NV_PFALCON_FBIF_TRANSCFG(u32)[8] @ PFalconBase + 0x00000600= { 2:2 mem_type =3D> FalconFbifMemType; 1:0 target ?=3D> FalconFbifTarget; @@ -395,6 +415,29 @@ pub(crate) mod gm107 { } } =20 +pub(crate) mod tu102 { + use kernel::io::register; + + use crate::falcon::PFalcon2Base; + + // PRISCV + // + // The two registers below select which of a RISC-V falcon's interrupt= causes reach the host, + // in the layout of `NV_PFALCON_FALCON_IRQSTAT`. GA100 uses these offs= ets as well. + + register! { + /// Causes the RISC-V core enables. Read-only to the host. + pub(crate) NV_PRISCV_RISCV_IRQMASK(u32) @ PFalcon2Base + 0x000002b= 4 { + 31:0 value =3D> u32; + } + + /// Causes routed to the host rather than to the RISC-V core itsel= f. + pub(crate) NV_PRISCV_RISCV_IRQDEST(u32) @ PFalcon2Base + 0x000002b= 8 { + 31:0 value =3D> u32; + } + } +} + pub(crate) mod ga100 { use kernel::io::register; =20 @@ -407,6 +450,29 @@ pub(crate) mod ga100 { } } =20 +pub(crate) mod ga102 { + use kernel::io::register; + + use crate::falcon::PFalcon2Base; + + // PRISCV + // + // GA102 moved the two routing registers. GA100 kept the Turing offset= s, so this pair covers + // GA102 and later rather than the whole Ampere architecture. + + register! { + /// Causes the RISC-V core enables. Read-only to the host. + pub(crate) NV_PRISCV_RISCV_IRQMASK(u32) @ PFalcon2Base + 0x0000052= 8 { + 31:0 value =3D> u32; + } + + /// Causes routed to the host rather than to the RISC-V core itsel= f. + pub(crate) NV_PRISCV_RISCV_IRQDEST(u32) @ PFalcon2Base + 0x0000052= c { + 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 Sat Sep 26 08:48:41 2026 Received: from CH1PR05CU001.outbound.protection.outlook.com (mail-northcentralusazon11010002.outbound.protection.outlook.com [52.101.193.2]) (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 26DAE375F97 for ; Thu, 3 Sep 2026 03:15:45 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=fail smtp.client-ip=52.101.193.2 ARC-Seal: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788405348; cv=fail; b=CeGWQEPct0cJpFIHshkFCzD2CrS9tSnRs9fnSf5CCzdPMIDlHGOkodF0YjLA1k8LmPkXFQOFtg4SiPj7vpInZuseb9Gj5Awd2hx5BE9Kp3cu/kyGNCSCFIxTxsxW1dBdx6TgsQut/efVSk0gEBfQuri+RlXlmbZRNzzmRmd3Rdw= ARC-Message-Signature: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788405348; c=relaxed/simple; bh=U+wHtTOC4hfWPJd9F3XxCne+U69GM3vAKETLl/A0yag=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: Content-Type:MIME-Version; b=dZ17Sn7IhqG31mh4Xf29yMi4CdPGkvqB59XF1o/Emz6dd/ji0FOixm/UE3zeXObzrkNkpGAE7WxxO3GdUkdybvnpuf6xikbfslWKP0oc0gJYyE4qd7/8yT1ytUH8SyijxCpF1Ap5qjfrnUyNPTdgTEtGgwAKRRoIJdrLkqmVOtQ= 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=a3q+nQEd; arc=fail smtp.client-ip=52.101.193.2 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="a3q+nQEd" ARC-Seal: i=1; a=rsa-sha256; s=arcselector10001; d=microsoft.com; cv=none; b=VzHAuDmVNWXSQpx1vqdbJWDUl5whCdwW4RM3hqc9CrIRvCDPhJ/XtsCbDatLhGEpoCtnKjOzh+uAHmbm3h37e0sn2rTV6gGaBiwWOsqm+nk9Ftx3RZCQVtvU9SwlKMiDTaSjetZh2t2KyFTz2JM9biKIA98J91Y6czsePoyq4KXOfZAmQTXhdEV/IbTjRatixwFE97tR8TuEmSAQufjuQ69ehSx8t4HC+FSVptq862SB/gx97pp9xSNAe1scXxktcxFCc58f3VdLUMcOKNqlcsCNRPonkyOJiwo87zH+iFUiIb5N4aoLmLykPmc7W/4bINMAKvZx61aYeb+Mpf3K/A== 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=3bQvXNg+iaIzRghNyNScEIEHBPbjRI+YVJ1lgAf86D0=; b=Q/wDl9kvnWQpu7PYdIZW4u1s+y5qEipK7vW+4qrVH2y31EOMYvoBE8KNh1xBgXqIYl13fcCbe9BGIr92/0SB+BK+1GG0HyI1W4/IVD0OjuBah0i25omK5Mz0Gj7667tlUFtSrd2Yv/NoA0P9nhlqmnaoHFoHFiR+mvi18u+Z4mOU92Sxlqef7WQbKQOgV8qxyw1Sj1jA0V27obCuVWV+JIpHTIVQLKhUGZfiTcdjtGziHZYHgOJI+Qsv5ud6idzaimExp/aJDrOtx3Tpoj8vyEi+dpAoeS5yEbl6F4miAppNrSOG+dkEwHQpAVg1nwIunkJjd3DXDG1bn8tRRBuOhA== 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=3bQvXNg+iaIzRghNyNScEIEHBPbjRI+YVJ1lgAf86D0=; b=a3q+nQEdF/Bzf3lNGaJj7XPu5ekjehLHWy2vLNXn18TAH+pH5e4NbISQU36RPOTloxtbtA6RkRH84DGXClDu87wOmtne8HS48sv/Lsv/Ui5onvTrRSDL3Josgb8uag8b+fPEof9TTTvauCDqZbB4b3aVV6QT1VLKB5XSjwMYwc+zbCPPA7zq19sUv6O1KMN9xL1VR7f11E20eqPSxY8SC2y4iRpnDmyNPzv1DmBi8ekknaQrhgu44p8n9ldGuiiaqYeG8RvdZfFnq60cix9JPBA40vdIVs4hLiKGMFWNlmOZrZu/OvyxQz4NMy5KVCMK/M4RD12V9vAlRVClN1m3uw== 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 SJ2PR12MB9138.namprd12.prod.outlook.com (2603:10b6:a03:565::9) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.21.360.13; Thu, 3 Sep 2026 03:15:34 +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.0360.008; Thu, 3 Sep 2026 03:15:34 +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 v3 12/14] gpu: nova-core: drive GSP events with the SWGEN0 interrupt Date: Wed, 2 Sep 2026 20:15:11 -0700 Message-ID: <20260903031514.1515905-13-jhubbard@nvidia.com> X-Mailer: git-send-email 2.55.0 In-Reply-To: <20260903031514.1515905-1-jhubbard@nvidia.com> References: <20260903031514.1515905-1-jhubbard@nvidia.com> X-NVConfidentiality: public Content-Transfer-Encoding: quoted-printable X-ClientProxiedBy: BY3PR03CA0006.namprd03.prod.outlook.com (2603:10b6:a03:39a::11) 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_|SJ2PR12MB9138:EE_ X-MS-Office365-Filtering-Correlation-Id: 530501a5-464a-4185-732e-08df09699d62 X-MS-Exchange-SenderADCheck: 1 X-MS-Exchange-AntiSpam-Relay: 0 X-Microsoft-Antispam: BCL:0;ARA:13230040|1800799024|366016|23010399003|376014|7416014|18002099003|22082099003|11062099010|56012099006|3023799007|7136999003|10067099003|6133799003|5023799004|11063799006; X-Microsoft-Antispam-Message-Info: 3QNg27IyVJIGdUPtEVb/ua0SJ2XMgCSje/vmqp4qGyFWfKIpVpDppI5vlgY8X4PYg+9uubFEP0p5vWrXz9ghA0mdoHYFIVfsLN8wXfe4fQB5POqIxh4rwtAt0Jl55LC0wRn8ABNXnBkCkzgtz8SdGf68RiTI0JBWKJA3qzrJXxMcX/w8PoBeqBRkVxI9F8vgPKpzglQFr7lHTY4xe+x2E8knzJPPdvJST9350eiEy8o/oUvCBf8ayRbhDLtDaat3c6A/JM/0T2LbI0znlMxh15AKP9g5O2BUdcDJKjL2k7TPgBj/UwXHcaCYhUsFc3kgmqsdYImzl3yW39OE5M9szvSpMdcbXTgQtj32YfXv7HI+P5xxD5Wm623zEAvpnVui2t1QuqqUefMyWtvqL5j06GauNvgpnnO7gWWEQMIgLomeR7aMpcBlg0RnFKSHXpCHLYh0hy7Z6eUa2ao9KODABfjOjkKfUaP48f5G7EO8ufsSvF5hioJqKT/lJmmxPcIBDiwj1ZvpJ44vnWG2mWrbnMXxH7jniv4PU94C03NsMJusF9013Spek/r6PdhfBbCQIVd7QDIZDl9GuqIleuuZu8KRIwsRdNgVLgK4UJcFazvQyx44HXUFuKgsbC5KJcVVYDOsDWnX1FOJoB/F/T7cVrQnl/lhZWKu2UuWt2N7IBM= 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)(366016)(23010399003)(376014)(7416014)(18002099003)(22082099003)(11062099010)(56012099006)(3023799007)(7136999003)(10067099003)(6133799003)(5023799004)(11063799006);DIR:OUT;SFP:1101; X-MS-Exchange-AntiSpam-MessageData-ChunkCount: 1 X-MS-Exchange-AntiSpam-MessageData-0: =?us-ascii?Q?8sDIyT1+Fm7CCT1SWpkz8e86dFo8a/hEjcl394cDRPYxMGGEBThg8GT0ugOx?= =?us-ascii?Q?0onEeBqZF12c94rOa6jnXWeTmfW0vNkIiOxvgIwFl2O7Q1Bqy6+iG0M5W8OI?= =?us-ascii?Q?xo3ZyUTM34bGdTXk7HlH3n55l4pPjri3YOmi6R2tIKPbAgIhshf4Rnf31mpu?= =?us-ascii?Q?kdQluzmyaq499DjDPn5a4KkNmuU2pL98TLAvuL0V76FNu8Nhbtxa9JPsnXfm?= =?us-ascii?Q?/spFDhLVXV/ksYWTLZdPLE3HMaS9tanzo72642qNNqHfcikpg8qrhIEl2P8n?= =?us-ascii?Q?y5JY2LWHsJIADCICxib/ig2u8FnTCVueOxmB9QdqAg5w17/oZ3Sgs1NQmAGg?= =?us-ascii?Q?+mGeGpoNGQNtYZzu+UK+eRpnwdHLuXInTv8TW2xg6pqFDpqeyNGitCtw3req?= =?us-ascii?Q?5O/8Vf3XQTf7oTCpv9wCHqgUVTa5cUhcbc5nlhI1aIm71HiZ1+oU7ENbeUUA?= =?us-ascii?Q?0D+AmtEuiZhqiv74lJCanF8HY893GyS5YkvWqQhAZ1inGeFn0WvNctmNszcO?= =?us-ascii?Q?rMMkQ4GcWxvfat/PBFJxD8wulcygcYJmfH3Bs1TqjwXnX8AVSzlBabxxDV+8?= =?us-ascii?Q?Y6V/BMyrC9KV13RvKEd3h9hIGBsNTw/VWimYaE8BzfnpEeGqi+90Kh7p0JM4?= =?us-ascii?Q?+HM8CwDXuxOnTXqFo6pcOCg9fzauj4hIY0p8YeW9xABW9vZu2BqrlczBMA5K?= =?us-ascii?Q?cZRYk5YTsSwjyAwiYRvH/Wan/WwFM5vikJ/z0FEUNQmd7uDFuC5dDRok3c7M?= =?us-ascii?Q?8KSrWZnmszeNSTtgPllJEYrfkQxDFZcMaZWO4ywvA1VxrZktLp+cv6wpM6ww?= =?us-ascii?Q?ytUyUCKFLPkTIQr/O62GOXk7lFaQBHpkry+peMHvxQVt1xINOqq+l7+PNcbt?= =?us-ascii?Q?vRe573j8lvaqzwkvYTgnONMjE3xASHHP+VstTYL/KpI27N5wHvC5VT6d97A9?= =?us-ascii?Q?5ig9vOr8J+9uTCDcE2Ys7R0I7nkI9iOw6aDMfLBO8SRKa7Lmkj8Dtzj2oijt?= =?us-ascii?Q?ol7lCBO12qLBFlGbHy1aNtvppLLbqj6rZk1IGr6Tg0Spha+ig+V0ckEstRa5?= =?us-ascii?Q?5PR6RF/siqCAh8vMsnViM/LYMfWheU5AjzX4Oai/i4fGEU9oUDkowdaWzZMl?= =?us-ascii?Q?Dz/o/j/LFZgi33aMZmHjz5v42kXlRfTM2WCqRB80fCVabtojwIvLrxEp4i/B?= =?us-ascii?Q?YtQAw9KM0K52qnRCraxokHqqIzczF4E3fVCKSF6dDx/LqWWjFo17gH+vq0tg?= =?us-ascii?Q?BeS+DQm8IYgkweT3alyJIhw6bIxCYWI465ATEh+sH+XG+s36jiwyNbHHG5K8?= =?us-ascii?Q?GrTYdGo2X340W5/G83DhEQ3nZAp8659kpb3/kFiJW0815W5vGdVNHQmw1cOa?= =?us-ascii?Q?/JfuavJBb5Qh+BVwf+bjSUdhW4tj7MAfhK9sGZU7haj6xX99WSf/jJiHoVQO?= =?us-ascii?Q?NpPovcvQKKg7wfsiXMLh6wgnQkrFwzg9KFgTuMDzNE0rhQPuR7WvlZ5PiTYc?= =?us-ascii?Q?WAldhL5ks8cihuKXHiPDUabRD3xVyIg9pxOUbj5trOPhY1scLqUuzzWHAiIK?= =?us-ascii?Q?PmwPgefr68LXuGw/0oonIMUpnezYIVsrvMnBUdxXPNQLTSa8UjOO+axIjYpB?= =?us-ascii?Q?0QZjR0b1DmkasPynx8S0Gbpnez3J77sz38Nx8sZtCizP4DfZCjDtFGaeX+AL?= =?us-ascii?Q?rI0obarlVcu969jD9tjAYsHFJXl5tMFwaPY1FwHWTIXI5piAzhsdF+5twN2Y?= =?us-ascii?Q?re1fB9dVfw=3D=3D?= X-OriginatorOrg: Nvidia.com X-MS-Exchange-CrossTenant-Network-Message-Id: 530501a5-464a-4185-732e-08df09699d62 X-MS-Exchange-CrossTenant-AuthSource: DM3PR12MB9416.namprd12.prod.outlook.com X-MS-Exchange-CrossTenant-AuthAs: Internal X-MS-Exchange-CrossTenant-OriginalArrivalTime: 03 Sep 2026 03:15:32.8319 (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: Lgmt9faq3tfIm1BUlLPIVwmqCoCAB924/FjzmlH83Rg1BqWnqW1sd7Hy6OUYq7WkKqhxdR/B3OmsKXyeNglDwA== X-MS-Exchange-Transport-CrossTenantHeadersStamped: SJ2PR12MB9138 Content-Type: text/plain; charset="utf-8" The GSP posts events, logs and error records to the GSP-to-CPU queue and raises the falcon SWGEN0 output. A falcon signals the interrupt tree only on a transition of the causes it routes to the host, and IRQSTAT also reports the causes the falcon keeps for its own RISC-V core. GSP boot polls for its own notifications, so it leaves the SWGEN0 latch set and leaves pending bits behind in the tree. nova-core drained the queue only while polling for a command reply, so an event sat unread until the next command was sent. Service the queue from a threaded handler on the GSP notification vector. The top half runs in hard interrupt context and touches only registers: it clears the GIN leaf, takes the causes pending for the host, writes INTR_RETRIGGER so that a cause arriving while the top half runs still signals the tree, and rearms PCI delivery. Draining the queue takes the command-queue mutex, which can sleep, so the top half wakes the IRQ thread to do it. Intersect IRQSTAT with the RISC-V routing registers the way Open RM does, so the firmware's own causes are left alone. Clear the latch of a host cause that is not a posted message, since nova-core has no recovery path for one and the retrigger would raise it again. Put the interrupt setup on the GPU rather than in the driver's probe. The handler is then torn down before the queue it drains is freed, and before the GSP is unloaded. Quiesce the tree and clear the latch before registering, so no boot state reaches the handler, and keep the subtree enabled at TOP for as long as the handler is registered. Quiescing disables the subtree, and under pre-Hopper MSI the rearm is a configuration-space write that never enables it again. Assisted-by: Cursor:claude-opus-5 Reviewed-by: Will Pierce Signed-off-by: John Hubbard --- drivers/gpu/nova-core/falcon/gsp.rs | 71 +++++- drivers/gpu/nova-core/falcon/hal.rs | 49 +++- drivers/gpu/nova-core/gpu.rs | 47 +++- drivers/gpu/nova-core/gsp.rs | 2 +- drivers/gpu/nova-core/gsp/cmdq.rs | 41 ++++ drivers/gpu/nova-core/irq.rs | 51 ++++- drivers/gpu/nova-core/irq/gsp.rs | 239 ++++++++++++++++++++ drivers/gpu/nova-core/irq/interrupt_tree.rs | 8 + drivers/gpu/nova-core/nova_core.rs | 1 - 9 files changed, 483 insertions(+), 26 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 ae32f401aeb0..9e7d332fa77c 100644 --- a/drivers/gpu/nova-core/falcon/gsp.rs +++ b/drivers/gpu/nova-core/falcon/gsp.rs @@ -14,12 +14,15 @@ }; =20 use crate::{ + driver::Bar0, falcon::{ + hal, Falcon, FalconEngine, PFalcon2Base, PFalconBase, // }, + gpu::Chipset, regs, }; =20 @@ -36,16 +39,72 @@ impl RegisterBase for Gsp { =20 impl FalconEngine for Gsp {} =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.bar.write( - WithBase::of::(), +impl Gsp { + /// Clears the GSP falcon SWGEN0 interrupt latch. + /// + /// The latch holds until it is cleared, and the GSP drives no new edg= e into the interrupt + /// tree while it is set, so a caller that consumed a notification by = any means other than the + /// interrupt handler must clear it or no further notification is deli= vered. + pub(crate) fn clear_swgen0_intr(bar: Bar0<'_>) { + bar.write( + WithBase::of::(), regs::NV_PFALCON_FALCON_IRQSCLR::zeroed().with_swgen0(true), ); } =20 + /// Reads the GSP falcon interrupt causes pending for the host, cleari= ng the SWGEN0 latch if + /// it was set. + /// + /// Returns the causes as they were read, before the clear. The GSP ra= ises SWGEN0 when it has + /// posted messages in the GSP-to-CPU queue, so any other cause here i= s something else, for + /// example a HALT from a GSP crash. Causes the falcon routes to its o= wn RISC-V core belong to + /// the firmware and are excluded. + pub(crate) fn take_host_intr( + bar: Bar0<'_>, + chipset: Chipset, + ) -> regs::NV_PFALCON_FALCON_IRQSTAT { + let latched =3D bar.read(regs::NV_PFALCON_FALCON_IRQSTAT::of::()); + let status =3D regs::NV_PFALCON_FALCON_IRQSTAT::from( + latched.into_raw() & hal::host_intr_routing::(bar, chips= et), + ); + + if status.swgen0() { + Self::clear_swgen0_intr(bar); + } + + status + } + + /// Clears the latch of every interrupt cause set in `status`. + /// + /// A cause left latched holds the falcon's host-routed set non-empty,= and the falcon signals + /// the tree only on a transition of that set. + pub(crate) fn clear_intr(bar: Bar0<'_>, status: regs::NV_PFALCON_FALCO= N_IRQSTAT) { + bar.write( + WithBase::of::(), + regs::NV_PFALCON_FALCON_IRQSCLR::from(status.into_raw()), + ); + } + + /// Re-emits the falcon's host-routed interrupt causes into the interr= upt tree. + /// + /// The falcon signals the tree on a transition of those causes, so cl= earing the tree leaf + /// while a cause is still latched leaves no transition and no further= vector. + /// + /// Does nothing on Turing, whose falcons do not implement the registe= r. + pub(crate) fn retrigger_intr(bar: Bar0<'_>, chipset: Chipset) { + if !hal::has_intr_retrigger(chipset) { + return; + } + + bar.write( + WithBase::of::().at(0), + regs::NV_PFALCON_FALCON_INTR_RETRIGGER::zeroed().with_trigger(= true), + ); + } +} + +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 7e532889a1f4..5272b3b63ae4 100644 --- a/drivers/gpu/nova-core/falcon/hal.rs +++ b/drivers/gpu/nova-core/falcon/hal.rs @@ -1,8 +1,15 @@ // SPDX-License-Identifier: GPL-2.0 =20 -use kernel::prelude::*; +use kernel::{ + io::{ + register::WithBase, + Io, // + }, + prelude::*, // +}; =20 use crate::{ + driver::Bar0, falcon::{ Falcon, FalconBromParams, @@ -12,6 +19,7 @@ Architecture, Chipset, // }, + regs, }; =20 mod ga102; @@ -72,6 +80,45 @@ fn signature_reg_fuse_version( fn load_method(&self) -> LoadMethod; } =20 +/// Returns whether `chipset`'s falcons implement `NV_PFALCON_FALCON_INTR_= RETRIGGER`. +/// +/// Turing falcons do not. Ampere and later do, including GA100, whose fal= con otherwise uses the +/// Turing HAL, so this is keyed on the architecture rather than provided = through [`FalconHal`]. +pub(crate) fn has_intr_retrigger(chipset: Chipset) -> bool { + !matches!(chipset.arch(), Architecture::Turing) +} + +/// Returns whether `chipset` carries the RISC-V interrupt routing registe= rs at the Turing +/// offsets. +/// +/// GA102 moved `NV_PRISCV_RISCV_IRQMASK` and `NV_PRISCV_RISCV_IRQDEST`, a= nd GA100 kept the Turing +/// offsets, which is also why [`falcon_hal`] gives GA100 the Turing HAL. +fn has_turing_riscv_routing(chipset: Chipset) -> bool { + matches!(chipset.arch(), Architecture::Turing) || chipset =3D=3D Chips= et::GA100 +} + +/// Returns the interrupt causes a RISC-V falcon on `chipset` routes to th= e host, in the layout of +/// `NV_PFALCON_FALCON_IRQSTAT`. +/// +/// A cause reaches the host only if the RISC-V core both enables it and d= irects it there, which +/// `NV_PRISCV_RISCV_IRQMASK` and `NV_PRISCV_RISCV_IRQDEST` say. Every oth= er latched cause belongs +/// to the firmware running on the core. +pub(crate) fn host_intr_routing(bar: Bar0<'_>, chipset: C= hipset) -> u32 { + if has_turing_riscv_routing(chipset) { + bar.read(regs::tu102::NV_PRISCV_RISCV_IRQMASK::of::()) + .value() + & bar + .read(regs::tu102::NV_PRISCV_RISCV_IRQDEST::of::()) + .value() + } else { + bar.read(regs::ga102::NV_PRISCV_RISCV_IRQMASK::of::()) + .value() + & bar + .read(regs::ga102::NV_PRISCV_RISCV_IRQDEST::of::()) + .value() + } +} + /// 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/gpu.rs b/drivers/gpu/nova-core/gpu.rs index 8a9bc4baf9ac..763f1b633d32 100644 --- a/drivers/gpu/nova-core/gpu.rs +++ b/drivers/gpu/nova-core/gpu.rs @@ -29,7 +29,10 @@ Gsp, GspBootContext, // }, - irq::SubtreeVectors, + irq::{ + gsp::GspIrq, + SubtreeVectors, // + }, vgpu::VgpuManager, // }; =20 @@ -282,6 +285,12 @@ struct GspResources<'gpu> { #[pin_data] pub(crate) struct Gpu<'gpu> { spec: Spec, + /// GSP event interrupt registration. + /// + /// Declared before `gsp_resources` so it is dropped first: `free_irq`= runs, waiting out any + /// in-flight handler, before the queue it drains goes away and before= the GSP is unloaded. + #[pin] + _gsp_irq: GspIrq<'gpu>, /// Static GPU information as provided by the GSP. gsp_static_info: GetGspStaticInfoReply, /// GSP and its resources. @@ -337,7 +346,7 @@ pub(crate) fn new<'a>( let dev =3D pdev.as_ref(); =20 try_pin_init!(Self { - vectors: crate::irq::alloc_vectors(pdev, crate::irq::SERVICED_= SUBTREE.into())?, + vectors: crate::irq::alloc_vectors(pdev, crate::irq::gsp::GSP_= SUBTREE.into())?, =20 // SAFETY: `vectors` is initialized above, lives at a pinned s= table address, and is // dropped after every field that uses `vectors_ref` (struct f= ield drop order). @@ -382,12 +391,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 @@ -411,6 +415,33 @@ pub(crate) fn new<'a>( })?, }), =20 + // Clear the interrupt state GSP boot left behind, before regi= stering the handler + // below. + _: { + crate::irq::gsp::quiesce(bar, gsp_resources.spec.chipset, = vectors_ref)?; + }, + + // Register the permanent GSP SWGEN0 handler, which enables th= e interrupt. + // + // SAFETY: the command queue lives in `gsp_resources`, which i= s initialized above and + // pinned. `_gsp_irq` is declared before `gsp_resources` and `= vectors`, so it is + // dropped first, ensuring `free_irq` runs before either the q= ueue or the vectors go + // away. The registration is stored in `Gpu` and never leaked. + _gsp_irq <- unsafe { + GspIrq::new( + pdev, + vectors_ref, + bar, + &*core::ptr::from_ref(&gsp_resources.gsp.cmdq), + gsp_resources.spec.chipset, + ) + }, + + // Drain the messages the GSP posted during boot, before relyi= ng on the interrupt. + _: { + 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 13f361406a6c..47dfea78175d 100644 --- a/drivers/gpu/nova-core/gsp.rs +++ b/drivers/gpu/nova-core/gsp.rs @@ -152,7 +152,7 @@ pub(crate) struct 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, /// RM arguments. diff --git a/drivers/gpu/nova-core/gsp/cmdq.rs b/drivers/gpu/nova-core/gsp/= cmdq.rs index a0f995faaee5..ec254d6fe2c0 100644 --- a/drivers/gpu/nova-core/gsp/cmdq.rs +++ b/drivers/gpu/nova-core/gsp/cmdq.rs @@ -655,6 +655,18 @@ pub(crate) fn await_msg(&self) -> R= esult } } } + + /// Drains every message currently pending in the GSP-to-CPU queue. + /// + /// Logs each message the GSP has already posted according to its func= tion code, and returns + /// without waiting for more. + /// + /// # Errors + /// + /// Propagates a receive error, in particular the `EIO` of a queue poi= soned by corrupt framing. + pub(crate) fn drain(&self) -> Result { + self.inner.lock().drain() + } } =20 /// Inner mutex protected state of [`Cmdq`]. @@ -970,4 +982,33 @@ fn classify_event(&self, function: Result, seq: u32) { } } } + + /// Drains all messages currently pending in the GSP-to-CPU queue. + /// + /// Reads whatever the GSP has already posted and stops once the queue= is empty. There is no + /// awaited reply during a drain, so every message goes to [`Self::cla= ssify_event`]. + /// + /// # Errors + /// + /// Returns the receive error that stopped the drain, in particular th= e `EIO` of a queue + /// poisoned by corrupt framing (see [`Self::wait_for_msg`]). + 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.classify_event(function, seq); + } + + Ok(()) + } } diff --git a/drivers/gpu/nova-core/irq.rs b/drivers/gpu/nova-core/irq.rs index f44897692b74..50d8abb735c1 100644 --- a/drivers/gpu/nova-core/irq.rs +++ b/drivers/gpu/nova-core/irq.rs @@ -10,6 +10,7 @@ =20 #[cfg(CONFIG_NOVA_CORE_IRQ_SELFTEST)] pub(crate) mod doorbell_test; +pub(crate) mod gsp; mod hal; mod interrupt_tree; mod regs; @@ -24,20 +25,18 @@ prelude::*, // }; =20 -use crate::num; +use crate::{ + driver::Bar0, + gpu::Chipset, + num, // +}; =20 use interrupt_tree::{ - GinVector, Subtree, - SubtreeSet, // + SubtreeSet, + Tree, // }; =20 -/// The subtree nova-core allocates PCI vectors for. -/// -/// Every source nova-core services latches in this one subtree, so a sing= le allocation covers all -/// of them. -pub(crate) const SERVICED_SUBTREE: Subtree =3D GinVector::new::<129>().sub= tree(); - /// The message-signaled interrupt type a vector allocation obtained. /// /// nova-core allocates MSI-X or MSI and nothing else, so the level-trigge= red INTx that @@ -70,6 +69,40 @@ pub(crate) fn msi_type(&self) -> MsiType { self.msi_type } =20 + /// Returns the interrupt tree these vectors deliver, as `chipset` imp= lements it. + /// + /// # Errors + /// + /// `EINVAL` if this architecture does not implement a subtree these v= ectors service. + fn tree<'b>(&self, bar: Bar0<'b>, chipset: Chipset) -> Result= > { + Tree::new(bar, chipset, self.msi_type, self.serviced) + } + + /// Resets the interrupt tree these vectors deliver. + /// + /// Disables every vector in every implemented leaf, clears every pend= ing bit, and rearms PCI + /// interrupt delivery. On return no vector is enabled, so the tree de= livers nothing. + /// + /// The rearm covers pre-Hopper MSI, where an interrupt delivered befo= re probe leaves delivery + /// un-armed with no handler to have rearmed it. + /// + /// Call this only during probe. It must not run concurrently with an = interrupt handler. + /// + /// # Errors + /// + /// `EINVAL` if this architecture does not implement a subtree these v= ectors service. + 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 an [`irq::IrqRequest`] for the vector that delivers `subtr= ee`. /// /// MSI-X gives subtree `N` its own table entry `N`. MSI raises its on= e message from every 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..174488565f79 --- /dev/null +++ b/drivers/gpu/nova-core/irq/gsp.rs @@ -0,0 +1,239 @@ +// SPDX-License-Identifier: GPL-2.0 +// SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIA= TES. All rights reserved. + +//! GSP event (SWGEN0) interrupt handling. +//! +//! The GSP firmware raises SWGEN0 when it has posted messages in the GSP-= to-CPU queue. That +//! signal reaches the CPU as a PCI interrupt through the GIN tree. This m= odule provides the +//! threaded IRQ handler for it. The top half services the GIN leaf and th= e falcon's latched +//! causes, and the IRQ thread drains the message queue. +//! +//! See `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, // +}; + +/// Fixed GSP notification vector. +/// +/// GSP-RM pins the GSP SWGEN0 notification to this vector on every suppor= ted chip, so nova-core +/// uses the constant directly instead of discovering it at runtime. The l= eaf and bit serviced by +/// the handler are derived from it. +const GSP_INTR_0_VECTOR: GinVector =3D GinVector::new::<155>(); + +/// Subtree carrying the GSP notification vector, and the only subtree nov= a-core services. +/// +/// Probe allocates PCI vectors for this subtree, and the GSP handler name= s it as the subtree it +/// serves, both when it takes its vector and when it rearms. +pub(crate) const GSP_SUBTREE: Subtree =3D GSP_INTR_0_VECTOR.subtree(); + +/// Clears the interrupt state that GSP boot left behind. +/// +/// Resets the tree `vectors` covers, then clears the falcon's SWGEN0 latc= h. On return no vector +/// is enabled, so the tree delivers nothing. +/// +/// # Errors +/// +/// `EINVAL` if this architecture does not implement a subtree `vectors` s= ervices. +pub(crate) fn quiesce(bar: Bar0<'_>, chipset: Chipset, vectors: &SubtreeVe= ctors<'_>) -> Result { + vectors.reset_tree(bar, chipset)?; + // GSP boot consumes its notifications by polling the queue, which lea= ves SWGEN0 latched, and + // the GSP drives no new signal while it is set. The clear comes after= the tree reset, which + // erases every leaf bit and would erase the one a message posted sinc= e the clear had set. + GspFalcon::clear_swgen0_intr(bar); + + Ok(()) +} + +/// Threaded IRQ handler for the GSP SWGEN0 event. +/// +/// The top half clears the GIN leaf and takes the falcon causes pending f= or the host. The IRQ +/// thread drains the GSP-to-CPU message queue, which takes the command-qu= eue lock. +pub(crate) struct GspInterrupt<'a> { + /// Borrowed BAR0, for falcon register access from interrupt context. + bar: Bar0<'a>, + /// The GSP command queue, drained by the IRQ thread. + cmdq: &'a Cmdq, + /// The GIN interrupt tree for this chipset. + tree: Tree<'a>, + /// Chipset, for the falcon retrigger and the routing registers, which= both differ by + /// architecture. + chipset: Chipset, + /// Device, for logging from interrupt context without taking the comm= and-queue lock. + dev: &'a device::Device, +} + +impl<'a> GspInterrupt<'a> { + /// Creates the handler for `chipset`, borrowing `bar` and `cmdq` from= the rest of the driver. + fn new( + bar: Bar0<'a>, + cmdq: &'a Cmdq, + tree: Tree<'a>, + chipset: Chipset, + dev: &'a device::Device, + ) -> Self { + Self { + bar, + cmdq, + tree, + chipset, + dev, + } + } +} + +impl irq::ThreadedHandler for GspInterrupt<'_> { + /// Top half: clears the GIN leaf, takes every falcon cause pending fo= r the host, and rearms + /// PCI interrupt delivery. + fn handle(&self) -> irq::ThreadedIrqReturn { + let bar =3D self.bar; + + // Only service our own vector: require the GSP bit in the leaf an= d clear just that bit, so + // a co-pending vector in the same leaf stays pending for whoever = services it. The subtree + // stays enabled, so there is no whole-tree disable and enable. + let leaf =3D self.tree.read_pending(GSP_INTR_0_VECTOR.leaf_index()= ); + if !leaf.vectors().contains(GSP_INTR_0_VECTOR.leaf_mask()) { + // Nothing to service, but nova-core is the only consumer of t= his PCI interrupt, so + // skipping the rearm here would silence every later interrupt= as well. + 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); + + // A cause left latched holds the falcon's host-routed set non-emp= ty, and the falcon + // signals the tree only on a transition of that set, so no later = SWGEN0 would signal. + let unserviceable =3D status.with_swgen0(false); + if unserviceable.into_raw() !=3D 0 { + // nova-core has no recovery path for a cause other than a pos= ted message, for example + // a HALT from a GSP crash, so report it rather than discardin= g it. + dev_err!( + &self.dev, + "unserviceable GSP falcon interrupt, IRQSTAT {:#x}\n", + status.into_raw() + ); + GspFalcon::clear_intr(bar, unserviceable); + } + + // The leaf clear above consumed the tree's record of this interru= pt, and the falcon signals + // the tree only on a transition of its host-routed causes, so a c= ause that arrived while + // this handler ran would never reach the CPU. Re-emit to supply t= hat transition. + GspFalcon::retrigger_intr(bar, self.chipset); + + // Delivery resumes only after this, so it must happen on every pa= th that services the + // vector, including the fault path above. + self.tree.rearm_pci_irq(GSP_SUBTREE); + + // SWGEN0 is the message-queue notification, so wake the IRQ threa= d to drain it. + if status.swgen0() { + irq::ThreadedIrqReturn::WakeThread + } else { + irq::ThreadedIrqReturn::Handled + } + } + + /// IRQ thread: drains the GSP-to-CPU message queue. + fn handle_threaded(&self) -> irq::IrqReturn { + if let Err(e) =3D self.cmdq.drain() { + // A queue that fails to drain cannot advance past the message= that failed, so every + // later notification would repeat this failure. Disable the s= ource instead. + 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 interrupt. +/// +/// The fields tear down in declaration order, which is the order this nee= ds: disabling the leaf +/// stops new deliveries, `free_irq` then waits for a handler still in fli= ght, and only then is +/// the subtree disabled at `TOP`, so a late handler cannot rearm it. +#[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> { + /// Registers the GSP SWGEN0 threaded handler for the GSP subtree in `= vectors`, then enables + /// the subtree and the GSP notification vector. + /// + /// # Errors + /// + /// `EINVAL` if this architecture does not implement the subtree carry= ing the GSP + /// notification, or if `vectors` does not service it. + /// + /// # Safety + /// + /// The caller must not leak the returned value: its [`Drop`] runs `fr= ee_irq`. + pub(crate) unsafe fn new( + pdev: &'a pci::Device, + vectors: &'a SubtreeVectors<'a>, + bar: Bar0<'a>, + cmdq: &'a Cmdq, + chipset: Chipset, + ) -> impl PinInit + 'a { + let dev =3D pdev.as_ref(); + + // The fields below are initialized in the opposite order to the o= ne they are declared in, + // so that the handler is registered before anything it serves is = enabled. + try_pin_init!(Self { + // SAFETY: the caller guarantees the returned `GspIrq` is not = leaked, so this + // registration's `Drop` (`free_irq`) always 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, + )), + ) + }, + // Under pre-Hopper MSI the rearm is a configuration-space wri= te, so nothing else + // restores the `TOP` enables that the tree reset cleared. + _top_guard: reg.handler().tree.enable_top_guarded(), + // A message posted during `quiesce` latches this leaf bit whi= le the vector is still + // disabled, so enabling it raises that interrupt rather than = losing the message. + _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 f27f0137dffe..62c0bbda61b2 100644 --- a/drivers/gpu/nova-core/irq/interrupt_tree.rs +++ b/drivers/gpu/nova-core/irq/interrupt_tree.rs @@ -178,6 +178,14 @@ pub(super) const fn intersection(self, other: Self) ->= Self { pub(super) const fn span(self) -> u32 { u32::BITS - self.0.leading_zeros() } + + /// Returns the subtrees of this set, lowest index first. + pub(super) fn iter(self) -> impl Iterator { + // INVARIANT: a shift of `1` leaves exactly one bit set. + (0..u32::BITS) + .map(|index| Subtree(1 << index)) + .filter(move |subtree| self.contains(*subtree)) + } } =20 impl From for SubtreeSet { diff --git a/drivers/gpu/nova-core/nova_core.rs b/drivers/gpu/nova-core/nov= a_core.rs index 65ce547bd44e..68b5abfe494d 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_IRQ_SELFTEST), expect(dead_code))] mod irq; mod mctp; #[macro_use] --=20 2.55.0 From nobody Sat Sep 26 08:48:41 2026 Received: from BL2PR02CU003.outbound.protection.outlook.com (mail-eastusazon11011065.outbound.protection.outlook.com [52.101.52.65]) (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 A58BB3546FA for ; Thu, 3 Sep 2026 03:15:42 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=fail smtp.client-ip=52.101.52.65 ARC-Seal: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788405346; cv=fail; b=I5/+Dzal2qifcgLlIk0A63BOtKV5rcnvlnhE7gd0iXFbo4YUEkNBpdQngK4Dz67iNJHvic7aIWUsHVv6e2TSBw33kaf7xz1IT8Jdf5xyotDULgYRBIyjbtNDNyjz7qOqm8zBIkWaj5acASpoViSYq+8vLmsC2o8xs1QJfkqQt2A= ARC-Message-Signature: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788405346; c=relaxed/simple; bh=94DWsfvNnQwxHLozwDMnMXwnkpgcrDkAxOQSKrxsQCg=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: Content-Type:MIME-Version; b=mmp76Nk+L8FfdgyF3/2iCZBJq5nvbqit5GzQSurNtU8xbFjBNSe3HIrleCMxKct2JHJ+M9ZumsxJBvGxJGQ1qkRlPYAbJu2WNBZ8DwXcdToD6BzO2iq1AbStyZx7GrXELQd9I/DnJW6ps30/hfkn6LD1PQ+bJ34DywOTTdp36kw= 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=NMJfCZmk; arc=fail smtp.client-ip=52.101.52.65 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="NMJfCZmk" ARC-Seal: i=1; a=rsa-sha256; s=arcselector10001; d=microsoft.com; cv=none; b=Kl4+6xbG0w3sTzA+Oa0kMkDyCF1DDBLv1AxmXULXB0TBklA7oI8yx/pdFAAcFhY6/pB/0PIbvnRMr4fTcpj0f+x3EII0zVYcyppjHWNSZ/xOagRhDnHxIELSxygB7FOjTRvIUdC2aTliEtmh8EJ6R8usoqL4pKsYv8GFx+JZ7b1G0eiMAhrkInGmIAKthCS96VtUi4oKY1NDNv0Y9oUxzNmVMwS6zDuoTI0/VGMhYnb8Vf9znn1+s/Xk7fE+aMa+qFSMy7jPlz0lflHqhAwWN0xcSNHy7DtNXdA4kG6YyEhRjNQ7lnu6k2lQXIGmj2KSVzT0/NGBUQYhD4mi3Qo9XQ== 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=BwaKpc4UeqAEbuhPLhIP9D6qh4pSpgGkqZ3MVndj+wI=; b=nNiwDPZSRRWs49lz/eh/eH7gJ5mnBpYO/QkXKCzH6E2aldILMRfnL+X7MVqnw5xnx+AKk9waCH973etDIpOw9xdnHhPzxz4nBpoOQ5jYPiemIUJHeunNVkPZZ3s4xLDjfWoqxTdYNRd6CGLM0kVqrecuueiDekP+t30Oid+2zbxFYQltYWQwKAQ1Jq/IXBEhEtv6BeQa+9ZL3gV1ulnrRn9kCZFX4fGWjvr4BOqjIsVDGopzQ/3pL5KxNpf52MNSbGiplPpcY6iD8bUl/ccv1+VaOo8TbecT2rtPI8GyCWB5MH1WVtXxGTBo/npnsqHch7dmwazvtre/ynZ8/wZDjA== 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=BwaKpc4UeqAEbuhPLhIP9D6qh4pSpgGkqZ3MVndj+wI=; b=NMJfCZmkDJBcVMDg/TmC45qQJtDvTMI5kmTKo+ech/18xZFPevOJFhOsBe1bbQTZ1/7k4P5DPCHrKB174jXQGSyXrymCZqHJtIqPtZ4/NFjtdk3R0kR4/auWodE30r0SCmTgpqbK5lincJF8Pjrga+/ooAKos6di0/rofYB19Oh46c5Rr0CI4z2Q4vFlHczS5c+ToAVCEbqLwWFpgGMYJDITGldFNwCnSuajz2/sVaU34l9HFWQHfrT6fnxDEEvKPN1D3b15L8GwEu1XjQsMJBcxxyWxpPZIva2AO3MgRHA5QMN0SLdvZl0aZYbUTsUjdKtnxbh8TT9VanpWucXUhg== 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 CH0PR12MB8487.namprd12.prod.outlook.com (2603:10b6:610:18c::17) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.21.360.13; Thu, 3 Sep 2026 03:15:35 +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.0360.008; Thu, 3 Sep 2026 03:15:34 +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 v3 13/14] gpu: nova-core: add KUnit tests for the interrupt tree and HALs Date: Wed, 2 Sep 2026 20:15:12 -0700 Message-ID: <20260903031514.1515905-14-jhubbard@nvidia.com> X-Mailer: git-send-email 2.55.0 In-Reply-To: <20260903031514.1515905-1-jhubbard@nvidia.com> References: <20260903031514.1515905-1-jhubbard@nvidia.com> X-NVConfidentiality: public Content-Transfer-Encoding: quoted-printable X-ClientProxiedBy: SJ0PR03CA0255.namprd03.prod.outlook.com (2603:10b6:a03:3a0::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_|CH0PR12MB8487:EE_ X-MS-Office365-Filtering-Correlation-Id: 53c69edf-1cd2-4799-f592-08df09699e27 X-MS-Exchange-SenderADCheck: 1 X-MS-Exchange-AntiSpam-Relay: 0 X-Microsoft-Antispam: BCL:0;ARA:13230040|1800799024|7416014|376014|23010399003|366016|6133799003|3023799007|10067099003|56012099006|5023799004|22082099003|18002099003|11063799006; X-Microsoft-Antispam-Message-Info: bU5woDpqeG9WmcjQ6/eBT5qAc5gEvlUu4vGsxJMYBM2B/rRwobJoKdmbx5S7OORUjmnFrsjOaRMGItbI9AVpHj8KR0uiEVnCBh43yr7o0u5I4vJNgbm/K8xNzKOlLaiSAJ1hNboFTkSM2Uy66h6Yj40kOtVcAZ8VUT2n5TfZ86BIWVPUh0do5gqnHYEq9VXKQU7apCtIrguv9Py81lhrw7zFCiGTAAdHUZZOTTyWpKnSVrjRWZ6Ib2I7gZwN/TRXTFWcD63Dp3GhxzjJRmxrD/Ivv1kNSv1ntsv4T4NitXYiszm2PkVPk7C9v78e6Xxw7lFKPHimYM36duxxKpD2azqprbobYphAboTGim6PxbmhknQqKKniH674paaSx8s/7MOFm8SwT/x/RXThXVa0SL/bSaYNxMew7JnKBmVcDjPjsLJFl8IOpaNb7s7QNwryaSdn/RsfstG/p48WCNcKsjcFvFspoRqQBPVSpmN7G/DR3XgbavS0A3tcH991Rh+vTZJaRf9Lork7rsHB0XBxG7xHcVMtDweRv/0IkTHN226R3D8vkQSqod/bonbIupDMkgDOwFNDQ1U3jV4DDeTD2N6Vikoa3RysgHtxLu9FlIxGw6/Wi5JonPRrqsaQu2HJBcORiwgxWzK1ew34DMb1wKb13pbUc9xPKqIa6WLjzTw= 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)(6133799003)(3023799007)(10067099003)(56012099006)(5023799004)(22082099003)(18002099003)(11063799006);DIR:OUT;SFP:1101; X-MS-Exchange-AntiSpam-MessageData-ChunkCount: 1 X-MS-Exchange-AntiSpam-MessageData-0: =?us-ascii?Q?cJcVd7hqo0CWGrLatoC/Jl4vN5gp5uuA53OVA7AbKFE/YHutEhOuhCYmMGAC?= =?us-ascii?Q?cidVA/QQagTWsYCvJAayC7pL6mrjfD2RI5o0Cgq4LC7WVauG+JeI8HCKT/Sl?= =?us-ascii?Q?Ee77XJP0EEsGCyPUSHJWv66iJ83lMNVttIiwODvjQA0RTdwTCJOFxAofrGwC?= =?us-ascii?Q?TDOn6R0ip7UVsWBBWzorOU3KTRAWmt9GLJr1oOU00K9xfNIEdMKolXjkQsvz?= =?us-ascii?Q?0bowZMOacLetfdir+fR81drPkQkn619q62maJDAqjcozxo6j2UvSJS5VOFNe?= =?us-ascii?Q?73okBFO8fn3zi7OU3vYUSsK7cdEyQqThhNvqy36q5sNGWHHCfe0orXCq6fNV?= =?us-ascii?Q?5CzT4BRMlNeFAE/H8p6crIXRcsXESsXcb5MjEm8jfwVn1Lvu8r/AeNK1Lb9X?= =?us-ascii?Q?joHTBNOPwj9guTk5YWZCwUxsqbk/Ai6IYQ1v43PfCoOdIoPegYwhGC1RIqjR?= =?us-ascii?Q?2ahvROyrL64wEiLoqRzf841sxETdlE355v+Sh9k8We3rqiRzYAwaA/RF4HBK?= =?us-ascii?Q?H0GUt+fHVElp8zhvJU/CNfM5+eRJBeWFo+vIupV4nPUwGdzx1Fp0i8o+WUdR?= =?us-ascii?Q?QvwAboZ/rF0A6TkqLvThtJg9KSbtuI5S4+GHSuVHVzL6LMmZNGFwO5Ms+9m0?= =?us-ascii?Q?q6iXOP6VQl1j97RwvwCzfLhL5/FxlkGY7EzCITV467iis3dDas/2SltPm4jV?= =?us-ascii?Q?jHg3CWPKpkrpA2vFdgEVEqu2sa7rp2HrRyhGP8sLloYFPoRjffZ7nBLemBAv?= =?us-ascii?Q?niP4/6pxsxL7r1O1xMCGxeO8nuMFalO+TMjfcqdiRoa9eOtFyEi2YB/D3LVX?= =?us-ascii?Q?MifiPqFCNJcE7fw3jDICqLzRfxFhnpn2TWbt5haC9M6Co/Eyy16JXruR4R0o?= =?us-ascii?Q?g6rl/+alT7daOUFF4lPTyTvNU5BOgd1mC740kiX13li3ZarRg4ibw9kMs/Nl?= =?us-ascii?Q?BG6EPxG30dhwf5B1fy9ug6g+3p92A8NifB0ddXxf/EfWbN1C6H/Oi62q7xiE?= =?us-ascii?Q?aidf/HEOneBOVIozswI1Yb5laT7w6C0So50VzKnU8nRzRuAXUnpjFYQU3Vs2?= =?us-ascii?Q?pjOWmmEJpZN5DgbEQHcF8H57rOE2CTiL8euXgR8a0qp7+ptyVjQqZ5TEDDJk?= =?us-ascii?Q?lMaNJoqK1YtPrA8OeAP6Be8fJbdU3v7W6NZb/nRq0gKH2TtTmR4IvGv49rpK?= =?us-ascii?Q?wYGUj0yC3lUkPzgEXgXBfUimCKuMrdiCdwF4DMf8LnZRMGt8EipEv8CO1pA4?= =?us-ascii?Q?BmD3txEw0NchouODh06dQLFCypGuNIuw8Zv7caeYGbruJMIa7qHu3Gm5UZY9?= =?us-ascii?Q?94wO6NwRNi7lktyCIjtRtaUxhAQrJfKV/5ejjbVtb/slvS13XTmISHjcovC+?= =?us-ascii?Q?fMBnez43ikJqXVOTGh1BY98IjZqBKm9JLXDJNmU2UbS0evnWYHnDkf5wD37P?= =?us-ascii?Q?cdmZydLA+PZoyP6HADH7i4IvSdRVL8W+nCf0rwfNZGkyxM/Io6WDQkkBFdB5?= =?us-ascii?Q?RkONNBi4uVZR2fObvOeZyCrXM/NSRzufZwy3iS5yIFRbiUuLbBMvowCMMvWW?= =?us-ascii?Q?K/fwXUuZAFhFiR3t/HWs4yGb+J5CBxuwFjGsMhjv+ImDS0GpMe5B/nVaFYKL?= =?us-ascii?Q?sgYxZquHmQlJbq1DLBHSrsEgewLYqkebkGTBgLpVnV/d5Klj2Me+hsluVgf+?= =?us-ascii?Q?VQf3GkDU+lBmeieJT7AsYb3DwK00KqfIm2wzOirrue1bfHpjAHLu49SmniiI?= =?us-ascii?Q?uQrq9mX8zw=3D=3D?= X-OriginatorOrg: Nvidia.com X-MS-Exchange-CrossTenant-Network-Message-Id: 53c69edf-1cd2-4799-f592-08df09699e27 X-MS-Exchange-CrossTenant-AuthSource: DM3PR12MB9416.namprd12.prod.outlook.com X-MS-Exchange-CrossTenant-AuthAs: Internal X-MS-Exchange-CrossTenant-OriginalArrivalTime: 03 Sep 2026 03:15:34.0971 (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: F0k/55jD6j7KxhiNQMEaesS5IneQynLFdXbIMbC33LmK93FgzrbEln2Rv6hhKKgQsDgmGukA5o3M5vTXQiCA5A== X-MS-Exchange-Transport-CrossTenantHeadersStamped: CH0PR12MB8487 Content-Type: text/plain; charset="utf-8" Neither the per-architecture interrupt policy nor the vector arithmetic touches hardware, so KUnit can cover both without a GPU. Add three suites: * nova_core_gin_tree covers the vector arithmetic: the leaf index bounds, the leaves and subtrees a leaf count implies, the leaf and bit a vector maps to, the check that rejects a vector outside the tree, the subtree-set operations and iteration, and that every supported chipset implements the subtree carrying the GSP notification. * nova_core_gin_hal covers the tree size on each family, and the rearm method for each family and MSI type. * nova_core_falcon_hal covers two per-chipset falcon gates: whether the interrupt retrigger register exists, and where the RISC-V interrupt routing registers sit. GA100 falls on a different side of each, and shares the Turing HAL, so neither gate can be keyed on the HAL. Assisted-by: Cursor:claude-opus-5 Reviewed-by: Will Pierce Signed-off-by: John Hubbard --- drivers/gpu/nova-core/falcon/hal.rs | 43 +++++++ drivers/gpu/nova-core/irq/hal.rs | 64 ++++++++++ drivers/gpu/nova-core/irq/interrupt_tree.rs | 131 ++++++++++++++++++++ 3 files changed, 238 insertions(+) diff --git a/drivers/gpu/nova-core/falcon/hal.rs b/drivers/gpu/nova-core/fa= lcon/hal.rs index 5272b3b63ae4..aa89b553ef53 100644 --- a/drivers/gpu/nova-core/falcon/hal.rs +++ b/drivers/gpu/nova-core/falcon/hal.rs @@ -146,3 +146,46 @@ pub(super) fn falcon_hal( =20 Ok(hal) } + +#[kunit_tests(nova_core_falcon_hal)] +mod tests { + use super::*; + + /// Only Turing falcons lack the interrupt retrigger register. GA100 h= as it even though + /// [`falcon_hal`] gives GA100 the Turing HAL, which is why the gate i= s keyed on the + /// architecture instead. + #[test] + fn intr_retrigger_gate_per_arch() { + assert!(!has_intr_retrigger(Chipset::TU102)); + + for chipset in [ + Chipset::GA100, + Chipset::GA102, + Chipset::AD102, + Chipset::GH100, + Chipset::GB100, + Chipset::GB202, + ] { + assert!(has_intr_retrigger(chipset)); + } + } + + /// GA102 moved the RISC-V interrupt routing registers. GA100 kept the= Turing offsets even + /// though it is Ampere, so the two gates in this module do not agree = on GA100. + #[test] + fn riscv_routing_offsets_split_at_ga102() { + for chipset in [Chipset::TU102, Chipset::TU116, Chipset::GA100] { + assert!(has_turing_riscv_routing(chipset)); + } + + for chipset in [ + Chipset::GA102, + Chipset::AD102, + Chipset::GH100, + Chipset::GB100, + Chipset::GB202, + ] { + assert!(!has_turing_riscv_routing(chipset)); + } + } +} diff --git a/drivers/gpu/nova-core/irq/hal.rs b/drivers/gpu/nova-core/irq/h= al.rs index 07604458dbbb..e844ade089e5 100644 --- a/drivers/gpu/nova-core/irq/hal.rs +++ b/drivers/gpu/nova-core/irq/hal.rs @@ -104,3 +104,67 @@ pub(super) fn cpu_interrupt_hal(chipset: Chipset) -> &= 'static dyn CpuInterruptHa } } } + +#[kunit_tests(nova_core_gin_hal)] +mod tests { + use super::*; + + use crate::gpu::Chipset; + + /// Pre-Hopper parts have 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); + } + } + + /// Only pre-Hopper MSI rearms through the configuration-space mirror.= MSI on Hopper and later + /// cycles 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 gives each subtree its own table entry, so on every architec= ture its rearm cycles + /// only the subtree the handler serves. + #[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 62c0bbda61b2..a6da9900f9da 100644 --- a/drivers/gpu/nova-core/irq/interrupt_tree.rs +++ b/drivers/gpu/nova-core/irq/interrupt_tree.rs @@ -531,3 +531,134 @@ fn drop(&mut self) { clear_top_enables(self.bar, self.serviced); } } + +#[kunit_tests(nova_core_gin_tree)] +mod tests { + use super::*; + + /// A leaf index is a `Bounded`, so it accepts 0..=3D15 and = rejects 16. + #[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()); + } + + /// A leaf count yields one subtree per pair of leaves, and 32 vectors= per leaf. + #[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 it implements, in order, and no more. + #[test] + fn implemented_leaves_covers_the_tree() { + for (count, expected) in [(LeafCount::Eight, 8usize), (LeafCount::= Sixteen, 16)] { + let mut seen =3D 0; + + for (index, leaf) in implemented_leaves(count).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 fixed doorbell + /// (129) and GSP (155) vectors share a subtree, so one allocation and= one enabled subtree + /// serve both. + #[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 lie within the 8-leaf tree, so every supported = part carries 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 how far it ext= ends 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()); + + // Subtree 2 is the highest the GSP needs, so an MSI-X request cov= ers entries 0 through 2. + assert_eq!(SubtreeSet::from(gsp).span(), 3); + + // Hopper implements every subtree an 8-leaf tree does. + assert_eq!( + LeafCount::Sixteen + .subtree_set() + .intersection(LeafCount::Eight.subtree_set()), + LeafCount::Eight.subtree_set() + ); + } + + /// Iterating a subtree set yields each of its subtrees once, lowest i= ndex first, and yields + /// 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 notification. + #[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 Sat Sep 26 08:48:41 2026 Received: from BL2PR02CU003.outbound.protection.outlook.com (mail-eastusazon11011065.outbound.protection.outlook.com [52.101.52.65]) (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 604E9377006 for ; Thu, 3 Sep 2026 03:15:46 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=fail smtp.client-ip=52.101.52.65 ARC-Seal: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788405350; cv=fail; b=OUtcmL4Mk6Iob6gPg70C3fhJGSh7FOewuRbZJ5rgm5AEUct0jLrPFXU4jOkgJXzdaBG57kTvQZL8Uj1ehlUg3Lxvd3+PBf06e2PVUM9Mv1P4EABJfOkH+LBNpz28PXprEkBhKXjcOIJtpT89599DdLW/4Dj4PXzFiIuWx/T9VR0= ARC-Message-Signature: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788405350; c=relaxed/simple; bh=AFxwqI7KjrcR+Eyf9a2WbB3vDAoOVPq073knKzKOFQ0=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: Content-Type:MIME-Version; b=gzMBx2r5KKY0SOJ9EX5lCDybUNzJRoneXDvGvZ+3GAHTfudZNMUEuUGSuZ9X0YDr/46UsItDhg4cFZmTSUaDL/K/Pvp/T8qyh2NFpKs7SbdvbmRAJZtBzVlb4+XFAfhzGVrb9CZlFlkA/1iRAptufOeX/fqEqW1TP8n3AGwornw= 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=Kj5Tdr9Y; arc=fail smtp.client-ip=52.101.52.65 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="Kj5Tdr9Y" ARC-Seal: i=1; a=rsa-sha256; s=arcselector10001; d=microsoft.com; cv=none; b=i51bUwKOZcuz+e2Z3znIpePawfjgSgNg+DVbsWA4o6rGBwChRXNOtEIbKJvDdL0eJeoxDdmmpDbHqjiT/CuGvNb4EFFsm8n7MgYZbjNgeCafVOfNdUcfh0lS4bXf1ugRNj1irIyBlfGTnL71auDnxZRWGZoH1JTiu5/IPzlrpgZMQIdOb6fsFghkhfcbs1WzajP3lUbv2M2SlEHftgKznL+wiKSxD7Oy/fsrMlTAz9y9/daM8g3CDnqKGyoXvIEbCwqiMsjNbzpWISLhxY1Th9kWPyB0FoXRIkUArmowFIUyzPZcRNtHy0ciol9CAG7iMmw6fWS/mrcOwXr3+8mQZA== 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=CqZRNWEXr4MZ8J/zyTKQwZ123L7r1VsFnBdplwUnesg=; b=hTEjMD0jHbObbAKZ0DCPflLpdXL9gFo93KUohCb1JdUuzHg4IjkDDgwqOa3qZGe4JXAWfNRLBY8ZyEGBLRUyuJlyXF2EAE4rg61PazOMsAdFMxNYJ4XlFEIoWAI4IJDbJbYOOg0AEaMV35Me3gQNl4wU9Z93G/XoLwvg/mXrEtZ+A7ZWKrt6vxxnmUY6KOK55JT43VckR8jfDa4XmGq4vuHu8Ycxx+00B79YAYnodzu66eJdMfWKYmbFdr1D9XrSvNsEpcNzMjJU3mhAobOful0ry3A1QMADJK2d7A+I35hTUpgBhmgOzRzHZruuT09+2E2QrPcH5jX89C7e0uDJ0w== 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=CqZRNWEXr4MZ8J/zyTKQwZ123L7r1VsFnBdplwUnesg=; b=Kj5Tdr9YCtdLfWubnUC+OLPB4qgnTXLJXFSTLTLB5dGqWCYhAfiFYhGD+Dy8rdaMcJ6n34zFfuA4yt9FzsHuTVnMgMqNcxHutqBhqECR+zYlfwYlEQtVpNN6eZsO1teA1XHZV0/hgranOl5C8cdh2iJ6gWR71Zesu4mRMOmXwe4myk0DApVF2sIrAhRgQW5N69gPcyCGD4R/Vl3i+yF31ULLGDanmpZ80CSP61xUQiuZN8+cri9XCrWSrENOHo/gqGFWMk4gUFacJoWxv3AiAjtW7ube0ElST03Wol4aVEBDLMNKjvXr4Q21g5Q9z7R1mLr1lKcxVVivNQuaMl2tYg== 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 CH0PR12MB8487.namprd12.prod.outlook.com (2603:10b6:610:18c::17) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.21.360.13; Thu, 3 Sep 2026 03:15:35 +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.0360.008; Thu, 3 Sep 2026 03:15:35 +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 v3 14/14] gpu: nova-core: document the GIN interrupt controller and GSP events Date: Wed, 2 Sep 2026 20:15:13 -0700 Message-ID: <20260903031514.1515905-15-jhubbard@nvidia.com> X-Mailer: git-send-email 2.55.0 In-Reply-To: <20260903031514.1515905-1-jhubbard@nvidia.com> References: <20260903031514.1515905-1-jhubbard@nvidia.com> X-NVConfidentiality: public Content-Transfer-Encoding: quoted-printable X-ClientProxiedBy: SJ0PR05CA0193.namprd05.prod.outlook.com (2603:10b6:a03:330::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_|CH0PR12MB8487:EE_ X-MS-Office365-Filtering-Correlation-Id: c253784f-ebf4-4066-8ad5-08df09699eeb X-MS-Exchange-SenderADCheck: 1 X-MS-Exchange-AntiSpam-Relay: 0 X-Microsoft-Antispam: BCL:0;ARA:13230040|1800799024|7416014|376014|23010399003|366016|6133799003|3023799007|10067099003|56012099006|5023799004|22082099003|18002099003|11063799006; X-Microsoft-Antispam-Message-Info: OwRKXdislmfLARQDa28SBT415CnYCnmoR2zVvIvNdNggO2Ynn2i1/gkgc3ITds2Or2l0buz1yMQVgZJLPzO2Y+SK5GOgfs5npsVrgQmJGq/FbKU9pronLkb1wZZxGnRXvDe+fez15qW3YzjYEtbyJp5CvVgYaT2aGcmWZ44tLuam8EcT2wJo11zHejHG9EfMxC5bouqIT8txGpyaFda3f72yf8GEICB8wnl/+uFBxD0fU4qmWbKNA9SXf4JdyARVm6zxjMI/vMZ+BrAd5ouzUwWV7GP3nzbSc6caGjmygPg2GzCs+d/w004tXizVLkspWDcHAIZ2bfz0xmVR1NHNRWt+Sdi7BYz7f7fyjmALw/EemEM1ezvurtxuYky0yakNgTMtA/s1QZvOhrTKWqN7qkoL8tlF9HKsZOwq4r9qUy+Y65LzW+6dimhulEWYEd3A8nB7y4Z4wbj5nRUcFdtRyyqHMTj6Gy9S1IjUALkhGaNNMjAKIo/VY3GrW6grzGutiUXZmTheu22oBT+ABeLe39lA+5HKMPJh7DWW14OeE81k3r0O0G5ETGNI2GIDMqPxw3UpST6LpQaCv9VOlR5WGNQxsQzajSo0LzMwKy86W8HgiE1gAneMyA4FCv6/FQ19fIbHeft5ItTrclJFxZFOslWs0gjyKL5bahB55ssMXHI= 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)(6133799003)(3023799007)(10067099003)(56012099006)(5023799004)(22082099003)(18002099003)(11063799006);DIR:OUT;SFP:1101; X-MS-Exchange-AntiSpam-MessageData-ChunkCount: 1 X-MS-Exchange-AntiSpam-MessageData-0: =?us-ascii?Q?RewmNJc3wGMalvyM6efFDn+VThAPb1xDiP6EiCFfmWsBAPAoWt89VkjKdIa6?= =?us-ascii?Q?+7eTxBujjm8seQxes7ohGoXW75TS10CQc0RqtU14g3J/CosWuJbJEmcGZCvZ?= =?us-ascii?Q?XGw7xg1kJUYqePG7CYDctBHpV7JTX801yYB0r9QamqaqkBgO2kUaUErB1OQO?= =?us-ascii?Q?XMkxjsLy878SpQVevy+Vd9w5NofU8g4Mt/TL4tUt5cYv7wTlJjglzNFEcsDg?= =?us-ascii?Q?/kOCgjQr/WcXfAvWixLEnbBVLlBbzbhto7uyPrD/XfAroMoZexP8UAuQvXUp?= =?us-ascii?Q?nKl0MixbX40M7lPk9cgt936Ao2jxjmVPlSb2QMWtgnc7k+nbZNjZ48xL8SUR?= =?us-ascii?Q?2TOmBcmiTsDPwuSy2hujgw2VTXyS6TN9AyTZgWuiFi/yXaYqtEOpRa7vH1dt?= =?us-ascii?Q?fUfHpck6PQtYa31ymVCAsusHF9ABv18Hj6sWYpcX7PhHnGxb76RqkngDn5Ec?= =?us-ascii?Q?wzwy7XHCy9OCeNCy7w8+HSk9H88OzZamh3XI8rES2JnTU+kdNzgrhX2NvOC/?= =?us-ascii?Q?bD8m/dUJqvY8fpovqzR110XOrjHAtpd72wXopJc1lv3MSGkzdSJV3p90mx7e?= =?us-ascii?Q?K+x1PW+kFJ+wKh3GI1k8k7suquYF/+7L9kXy85YNIkVTRakXhXLvo2Y6bDAV?= =?us-ascii?Q?q2/UR7gpvwYM9COAJPj8o+9SL/z2b8fmXjiUG4l7+eLBOtBsBSCbgcX/v/6r?= =?us-ascii?Q?FLO3Lb+AZJY+FEEXApLNX4S/Di1DcwDJGE3oNPrhZl20Y6UfwIu9n3pGx5Gf?= =?us-ascii?Q?IO07+lyBSACqf8wh+mF4yykn4Bj/wcWpLhkadF22+UMz365V9K4qderon5Fj?= =?us-ascii?Q?QrYDNq/Cer7pe5/lCpK257Q1VI2cMFHV/weylG7Wcr07OVaB3ZHDUP2oEqQo?= =?us-ascii?Q?2n97Wh/X9nZctPWbJlvlzF97gaArp0FjKKHs9KsaG86jZsvhcoy6TVB7XNNT?= =?us-ascii?Q?KivsTbhkQMDqd74hZ9yVIXnSPzLVZGokUZhsAbsub95Xqpv+9ayURivRZR7x?= =?us-ascii?Q?rJDDRgUzYT8X3VUPMqcUqojLxge+vQVXOJ+Fq7MsaZDfbTV8BaahJVZwgpJH?= =?us-ascii?Q?5Bhds4VzDGtfreC/nQbQMQEHKzpEyOLrZ+8qcTq1Z5fb+utLJguAhuXf0w9e?= =?us-ascii?Q?8lMw0zVRzXFH7g8HNiUvUidrgL7KUdOVx9RTOQQzF6zzDSSbWXgiKtzO4vsn?= =?us-ascii?Q?QQVZGVHJPjeSy3JjoLPYsvvlzTzTAkVfOiBPbC8lz+M9S9dCX+y4pPEM5xVD?= =?us-ascii?Q?l5mdQihoLvKvp6GQqjQ9OEfmrVCUNdD/phNZTZ34Bya6Jh8Ngc4aoGiV1HS4?= =?us-ascii?Q?D9r9G1Mu7rIvfB3WXHuJ6oE3XI1tjxGEp+YD9FveHQNz3qRT5loNcD1b0+Yu?= =?us-ascii?Q?WU05pyDzNhpQH6ggz0Tgh1JUFy8pLwleppdlT8mu4Gd9pYEgvHae/CZ+Q/QO?= =?us-ascii?Q?lwN0zLUOCRQIdeGRRJus7hUHhxaHu+8QvThAW6OTzG6uzDYKYHMUIBSZ2/8T?= =?us-ascii?Q?ptR4V2XdoygprX9huncf67OYjaK2zDMXxWWlLYl/6HjwsjQWm9QSWAGEnR3L?= =?us-ascii?Q?tenZR7cTV3Qz+6o89p7FsQne/Ij3mV+mQ1ac+4WGn444Oq1KdrPYimOjggGp?= =?us-ascii?Q?XcYyRPF2WdMjStS5uF/rJp3GDWdI2Izzg1TxBa5WT2R3ucgYZ1OfskEbTRqn?= =?us-ascii?Q?ORcRTNmKBssM/4bYC5KzfF/mpFQ98QiTgRtHy09JTJ6Z+7YGCLk3S+bIApbR?= =?us-ascii?Q?PIKjuQw6ZQ=3D=3D?= X-OriginatorOrg: Nvidia.com X-MS-Exchange-CrossTenant-Network-Message-Id: c253784f-ebf4-4066-8ad5-08df09699eeb X-MS-Exchange-CrossTenant-AuthSource: DM3PR12MB9416.namprd12.prod.outlook.com X-MS-Exchange-CrossTenant-AuthAs: Internal X-MS-Exchange-CrossTenant-OriginalArrivalTime: 03 Sep 2026 03:15:35.4154 (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: PPhem9vuJk9beY/lp363qlhaZL8GiQ0IlDOxQvP6RzgKDZfd0VSLSqzN2cgSh9sUi26jfoQjtSefz8S/i0zUlQ== X-MS-Exchange-Transport-CrossTenantHeadersStamped: CH0PR12MB8487 Content-Type: text/plain; charset="utf-8" The hardware behind nova-core's interrupt support is not obvious from the code. Delivery is edge-triggered and needs a rearm after every interrupt. The rearm operation differs by GPU family and PCI interrupt type, and a vector that latched while disabled sets no bit in the TOP summary register. Three different numbers are also all called a vector, in GIN, the MSI-X table, and the Linux IRQ API. Add a design document covering the two-level register tree, how an interrupt reaches the CPU under MSI and MSI-X, and the rules that delivery imposes on a handler. It also covers the GSP event: which of the falcon's interrupt causes reach the host and which belong to the firmware, the falcon retrigger, the handoff from boot-time polling to interrupts, and how the GSP's messages are classified. A glossary defines the tree's three levels and names every other term after the register or the specification that owns it. Assisted-by: Cursor:claude-opus-5 Reviewed-by: Will Pierce Signed-off-by: John Hubbard --- Documentation/gpu/nova/core/interrupts.rst | 716 +++++++++++++++++++++ Documentation/gpu/nova/index.rst | 1 + 2 files changed, 717 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..60d24adbcf06 --- /dev/null +++ b/Documentation/gpu/nova/core/interrupts.rst @@ -0,0 +1,716 @@ +.. 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=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=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 interrupt. + +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, and the GSP (GPU System Processor) is one of them. + +The register names in this document are the names from the GPU hardware +reference headers. The CPU tree's registers are in the per-function +``NV_VIRTUAL_FUNCTION_PRIV_CPU_INTR_*`` aperture on every supported part, = and +the controller has a different name in the pre-Hopper headers (see "Regist= er +naming"). + +Terminology +=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D + +The GPU hardware documentation, Open RM, and the Linux PCI API all use the= word +"vector", each for a different number. This document gives each one its own +name, and a bare "vector" always means a GIN vector. + +GIN vector + The GPU-internal interrupt source number, 0 through 511 on Hopper. It + addresses one bit of one leaf (see "Mapping a vector to the tree"). Th= e CPU + doorbell is GIN vector 129 and the GSP event is GIN vector 155. + +MSI-X entry + An index into the device's MSI-X table. One entry covers one subtree, = so a + Hopper part uses entries 0 through 7. + +Linux IRQ number + What ``request_irq()`` takes, obtained from ``pci_irq_vector()``. Linu= x's + ``struct msix_entry`` calls this number ``.vector`` as well. + +The three levels of the controller itself, innermost first: + +leaf + One ``LEAF`` register. Each of its 32 bits is the pending bit of one G= IN + vector. A pre-Hopper tree has 8 leaves, and a Hopper-plus tree has 16. + +subtree + Two consecutive leaves, summarized by one bit of ``TOP``. A driver ena= bles + and disables whole subtrees, and under MSI-X every interrupt from one + subtree arrives on one MSI-X entry. + +tree + One ``TOP`` register and the leaves beneath it. Every PCIe function ha= s its + own tree, and nova-core drives the CPU tree of one function. + +The remaining terms, each named for the register or the specification that= owns +it: + +enable / disable a GIN 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 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 own= s, + and the falcon cause masks. It never names a GIN enable. + +latched, pending + Two names for one state, a ``LEAF`` bit that is set. The bit is set wh= en its + source asserts, whether or not the GIN vector is enabled. A pending bi= t for + a disabled vector does not set the subtree's bit in ``TOP``. + +clear a leaf vector + Write a 1 to the vector's bit in ``LEAF``. Open RM calls the same oper= ation + ``intrClearLeafVector_HAL``. + +pending bits + The plain bitmask value read from a ``LEAF`` register. + +unit + A generic interrupt-raising block. "Engine" is reserved for the blocks= that + do usermode work: GR, CE, NVDEC, and the like. + +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, copy engines, the graphics engi= ne, +video decode and encode, the MMU fault path, timers, and others. Each one = has a +GIN vector number, which is internal to the controller and is not a PCI ve= ctor +index. + +GIN records which vectors are pending in its own two-level register tree a= nd +raises the PCI interrupt when an enabled vector becomes pending in a subtr= ee +that had none pending. The CPU's handler reads that tree to tell the sourc= es +apart, clears the pending vectors, and runs the work for each. + +How the tree reaches the CPU over PCI +------------------------------------- + +How many PCI interrupt vectors the tree needs depends on the interrupt type +Linux grants. + +MSI has a single message, and every subtree raises that one message. One +allocated PCI vector serves the whole tree. + +MSI-X raises a separate table entry per subtree, so a subtree's interrupts +arrive on the table entry whose index is the subtree number. Linux leaves = an +entry masked until a driver requests its Linux IRQ number, and a masked en= try +sends no message: the GPU records the interrupt in the MSI-X pending-bit a= rray, +where it waits to be unmasked. An entry the driver never requests is never +unmasked, so a driver that enables a subtree without requesting that subtr= ee's +entry loses every interrupt from it, and loses them silently: the GIN leaf= and +TOP registers show the vector pending and enabled while no handler runs. + +The serviced-subtree invariant +------------------------------ + +Every subtree enabled at TOP must have an allocated PCI vector with a regi= stered +handler. + +MSI satisfies this with its single message. MSI-X needs one allocated, unm= asked +entry per serviced subtree, and a PCI allocation cannot be sparse, so it r= uns +from entry 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 the driver does not service costs nothing, +because the entry stays masked and a disabled subtree raises no interrupt. + +nova-core services exactly one subtree. Both vectors it uses, the GSP event +(155) and the self-test doorbell (129), are in leaf 4, which belongs to su= btree +2. That is also the subtree GSP-RM assigns to its ``UVM_SHARED`` interrupt +category on every chipset nova-core supports. + +Interrupt trees +=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D + +GIN keeps a separate interrupt tree for each place an interrupt can be sen= t to: + +* One tree per PCIe function. The Physical Function (PF) has a tree, and e= ach + Virtual Function (VF) has a tree. +* One tree per on-chip microcontroller that receives interrupts, starting = with + the GSP. + +Each destination reaches its own tree through its own register aperture and +cannot reach another destination's tree. GSP firmware selects the tree each +unit's interrupt is sent to. + +nova-core services the CPU tree of one function. A VF tree belongs to that +virtual function, and a microcontroller tree belongs to the firmware runni= ng on +that microcontroller. + +The two-level tree +=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D + +Each tree has two levels. The bottom level is the LEAF registers, which ho= ld one +pending bit per vector. The top level is the single TOP register, which +summarizes the leaves. + +* Each ``LEAF(i)`` is a 32-bit register holding the pending bits for vecto= rs + ``i * 32`` through ``i * 32 + 31``. A set bit means that vector is pendi= ng. +* ``TOP`` is a single 32-bit read-only register. Each of its bits summariz= es one + *subtree*, which is a pair of adjacent leaves. TOP bit ``N`` reflects + ``LEAF[2N]`` and ``LEAF[2N + 1]`` as filtered by their leaf enables, so a + vector that latched while disabled does not appear in TOP. + +A subtree is two leaves, so a part with L leaves has L / 2 subtrees and us= es +that many TOP bits. An 8-leaf part uses TOP bits 0 through 3 and a 16-leaf= part +uses bits 0 through 7. The remaining bits always read 0:: + + TOP (one 32-bit register, shown here for an 8-leaf part) + + bit 0 -> subtree 0 -> LEAF[0], LEAF[1] vectors 0..63 + bit 1 -> subtree 1 -> LEAF[2], LEAF[3] vectors 64..127 + bit 2 -> subtree 2 -> LEAF[4], LEAF[5] vectors 128..191 + bit 3 -> subtree 3 -> LEAF[6], LEAF[7] vectors 192..255 + + A LEAF is one 32-bit register, one bit per vector. For example, LEAF[4] + holds vectors 128..159: + + bit 1 =3D vector 129 (CPU doorbell) + bit 27 =3D vector 155 (GSP event) + +Mapping a vector to the tree +---------------------------- + +Each vector occupies one bit of one leaf, and each leaf belongs to one +subtree:: + + leaf =3D v / 32 + bit =3D v % 32 + subtree =3D leaf / 2 + +Registers +--------- + +All the registers are 32 bits, defined under the +``NV_VIRTUAL_FUNCTION_PRIV_CPU_INTR_*`` names in the ``irq`` module's +``regs.rs``. The leaf registers are arrays indexed by leaf number: + +* ``LEAF(i)`` holds the pending bits for the vectors in leaf ``i``. Reading + returns the pending bits, and writing a 1 to a bit clears that vector + (write-1-to-clear). A handler clears a bit before it services that vecto= r, + because clearing afterwards would discard an assertion that arrived whil= e the + handler ran. +* ``LEAF_EN_SET(i)`` and ``LEAF_EN_CLEAR(i)`` enable and disable individual + vectors in leaf ``i``. +* ``TOP`` is the read-only summary: bit N is set when an enabled vector is + pending in ``LEAF[2N]`` or ``LEAF[2N + 1]``. +* ``TOP_EN_SET`` and ``TOP_EN_CLEAR`` enable and disable whole subtrees. +* ``LEAF_TRIGGER`` makes a vector pending in software. The self-test uses = it. + +Each bit of a set or clear register acts on its own: writing a 1 performs = the +action for that bit, and writing a 0 leaves the bit's state alone. No call= er +ever needs a read-modify-write. + +A vector reaches the CPU only when both its leaf enable bit and its subtre= e's +TOP enable bit are set. The leaf enable governs delivery and the TOP summa= ry, +but not the latch: a disabled vector still latches its LEAF bit, and readi= ng the +leaf is the only way to see that bit. + +How a unit interrupt reaches the CPU +=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D + +A unit does not write a LEAF register itself. Each unit has an interrupt r= outing +register, and GSP firmware programs it once at boot. Firmware writes three +things into it: the unit's VECTOR (which leaf bit it uses), its GFID (whic= h tree +to post to: the PF or a specific VF), and its destination flags (which con= sumers +receive the interrupt: the CPU, the GSP, or another on-chip microcontrolle= r). + +Later, when a unit has an event, three things happen in turn:: + + 1. The unit sends an interrupt message to GIN, carrying the VECTOR, GF= ID, + and destination flags from its routing register. + 2. GIN sets bit (VECTOR % 32) in LEAF[VECTOR / 32], in the tree that t= he + GFID and destination flags select. + 3. If that vector is enabled and its subtree is enabled, GIN raises th= e PCI + interrupt to the CPU. + +Because firmware assigns the vectors, nova-core does not hardcode which ve= ctor +belongs to which unit, with two exceptions. Firmware pins the GSP event an= d the +CPU doorbell to fixed numbers on every supported chip, so nova-core names = both +by number (see "The GSP event vector" and "Self-test"). + +Edge behavior and rearm +=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D + +The pieces behave as follows: + +* A LEAF bit is a latch. It is set on the rising edge of its source and st= ays set + until the CPU writes a 1 to it. A source that stays high does not set th= e bit + again. +* TOP is read-only and reports the subtree's *enabled* pending state. +* LEAF_EN and TOP_EN are CPU-controlled enables that allow or block delive= ry. +* GIN raises the PCI interrupt for subtree N when the subtree's enabled pe= nding + 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 its 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 is applied after the TOP summary, so disabling a subtree stops + delivery without changing what TOP reports. + +Because a disabled vector is invisible in TOP, code that must find every p= ending +bit cannot descend from TOP. It has to read the leaves directly. Open RM d= oes +the same: its stalling-interrupt path never reads TOP, and instead reads t= he +LEAF registers of every subtree it implements. + +Because delivery is edge-triggered, writing ``TOP_EN_SET`` while an enable= d leaf +bit is still set produces a new edge. A ``TOP_EN`` cycle rearms delivery o= n that +edge, and a pending bit left uncleared delivers an interrupt as soon as its +subtree is enabled again. + +A unit that holds an internal level signal high does not produce a new lea= f edge +after the CPU clears the bit, so rearming alone does not re-deliver it. Su= ch +units have an ``INTR_RETRIGGER`` register that forces a new edge. + +Retriggering a falcon +--------------------- + +A falcon signals the tree when its set of host-routed interrupt causes goe= s from +empty to non-empty. Clearing the tree leaf while a host-routed cause is st= ill +latched keeps that set non-empty, so no further cause sets the vector and = the +interrupt is lost. Clearing the tree leaf first or the falcon latch first = makes +no difference to that loss, so a handler on a falcon vector writes +``INTR_RETRIGGER`` on every path that services the vector. + +``IRQSTAT`` latches every interrupt cause in the falcon, including the cau= ses +routed to the falcon's own RISC-V core and owned by the firmware running o= n it. +A host handler owns only the causes that both ``PRISCV_RISCV_IRQMASK`` and +``PRISCV_RISCV_IRQDEST`` select, so it intersects ``IRQSTAT`` with both of= them +before it reads a cause or clears one. Open RM computes the same intersect= ion in +``kflcnRiscvReadIntrStatus``. GA100 keeps the Turing offsets for both regi= sters +and GA102 moved them, so the offsets change at GA102 rather than at the Am= pere +boundary. + +The ``INTR_RETRIGGER`` write must not be able to raise a cause that nothing +clears. Before the re-emit, the handler uses ``IRQSCLR`` to clear the latc= h of +every host cause it read. The handler masks no cause: +``PRISCV_RISCV_IRQMASK`` is read-only to the host, and ``FALCON_IRQMASK`` = does +not gate host routing on a RISC-V falcon. + +``INTR_RETRIGGER`` is absent on Turing falcons and present from GA100 onwa= rd, so +the write is conditional on the architecture. A Turing handler cannot re-c= reate +a transition it has lost, so it must leave no host cause latched: it reads= the +host-routed status once and takes every cause that status reports, rather = than +stopping at the first one it recognizes. A cause left behind keeps the +host-routed set non-empty, and no later cause from that falcon signals the= tree +at all. + +One window stays open on Turing. A cause that arrives after the handler ha= s read +the status is not in the value the handler clears, so it stays latched aft= er the +tree leaf has been cleared. Open RM has the same window: ``kgspService_TU1= 02`` +ends with ``kflcnIntrRetrigger``, which is implemented from GA100 onward a= nd +does nothing on Turing. + +Rearming PCI interrupt delivery +------------------------------- + +Clearing the GIN state is not enough. A message-signaled interrupt is +delivered once per edge, and the PCI side delivers no further interrupt un= til the +CPU rearms it. Which operation does that 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 MSI forms cover every serviced subtree, because one message serves all= of +them. The MSI-X form covers one subtree, because each serviced subtree has= its +own table entry and its own handler. + +nova-core allocates MSI-X or MSI and nothing else. The level-triggered INT= x that +``kernel::pci::IrqType`` also names has no representation in the driver, s= o the +table above has no row for it. + +A handler must rearm once per delivered interrupt, on every path that serv= ices +one. A handler that skips the rearm receives no further interrupts at all. + +The rearm is separate from the TOP_EN writes a full tree walk performs. Th= e walk +clears TOP_EN on entry, so that it can read and clear the leaves with no n= ew +interrupts arriving, and it leaves TOP_EN cleared for its caller to enable= once +the caller is ready for deliveries. That clear is not a rearm, and pre-Hop= per +MSI rearms through the configuration mirror, which the walk never writes, = so the +startup sequence rearms explicitly after the walk. + +Servicing an interrupt +=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D + +nova-core services the tree in one of two ways, depending on which code ha= ndles +the interrupt. + +The GSP event handler services one vector, so it leaves its subtree enable= d and +reads and clears only its own leaf bit, touching a single leaf per interru= pt. + +The startup drain walks the whole tree instead, because it must clear what= ever is +pending across every subtree rather than one known vector. It disables the +subtrees, clears every pending leaf, and leaves the subtrees disabled. + +The drain reads every implemented leaf rather than descending from TOP, be= cause +sources latch vectors during boot while those vectors are still disabled, = and +TOP does not show those bits. + +The two paths as register operations:: + + Full tree walk (the one-time startup drain): + write TOP_EN_CLEAR =3D serviced disable, to stop new interr= upts + for each implemented leaf i: + pending =3D read LEAF[i] pending vectors in this leaf + write LEAF[i] =3D pending clear (write-1-to-clear) + (returns with TOP_EN still clear) + + Notification, subtree stays enabled (the GSP event handler, and the + self-test, which deliberately mirrors it): + pending =3D read LEAF[gsp_leaf] is the handler's bit set? + write LEAF[gsp_leaf] =3D gsp_bit clear that one bit + rearm PCI interrupt delivery see "Rearming PCI interrupt + delivery" + +The walk writes back every bit it read, so it clears every pending leaf bi= t, +including the bits nova-core does not handle. An uncleared bit holds its s= ubtree +in the pending state, and enabling that subtree again would deliver an int= errupt +straight away for a vector that no handler services. + +The notification path clears one bit, so a vector pending alongside it in = the +same leaf keeps its bit and stays pending for whoever services it. + +Both paths rearm PCI interrupt delivery. A handler rearms for the interrup= t it +has just serviced. The startup path rearms after the walk, because an inte= rrupt +delivered before probe would have left delivery un-armed, with no handler +present to rearm it. + +Interrupts and notifications +=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D + +Two kinds of source use the tree: + +* An interrupt means a unit needs servicing. +* A notification means a unit is reporting that something happened, such a= s a log + record or completed work. + +The GSP event is a notification, and its handler takes the notification pa= th +above. + +The hardware manuals also split the vector space into "stall" and "nonstal= l" +ranges. Those name address ranges rather than describing behavior. nova-co= re +does not service the stall range. + +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, and there= are +only two sizes, split 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 and later 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 + +Sources do not populate every leaf of a 16-leaf tree. The startup drain re= ads +every implemented leaf anyway, because a vector can be pending in any of t= hem. + +The implemented-subtree set is wider than the set nova-core enables, which= holds +only the subtrees it services. A subtree the architecture does not impleme= nt has +no TOP bit to deliver its vectors, so building a tree that services one fa= ils +with ``EINVAL``. + +The HAL provides the leaf count, and the subtree count (leaves / 2) and the +implemented-subtree set derive from it. The rearm method is the HAL's other +per-architecture value. + +Multi-die parts +=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D + +On multi-die parts the controller is replicated per die, with an aggregati= on +level above the per-die TOP registers. nova-core services the CPU tree of = one +function on a single-die part, so it does not drive the aggregation level. + +The GSP event +=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D + +When the GSP has output for the CPU (log records, error records, and other +events), it writes the messages into the GSP-to-CPU queue in shared memory= and +raises SWGEN0, one of the software-generated interrupt outputs of the GSP +microcontroller (a "falcon" in NVIDIA hardware). SWGEN0 is routed through = a GIN +vector, so it reaches the CPU as a PCI interrupt:: + + GSP writes messages into the GSP-to-CPU queue + GSP raises SWGEN0 + GIN sets the GSP leaf bit, and the subtree becomes pending + PCI interrupt -> Linux IRQ -> nova-core top half, in IRQ context, which + must not sleep: + read the GSP leaf bit and clear it (subtree stays enabled) + read the GSP falcon causes routed to the host, clearing SWGEN0 if = it + was set + for every other host cause the status reports: report it, then cle= ar + its latch + retrigger the falcon + rearm PCI interrupt delivery + wake the IRQ thread if SWGEN0 was set + IRQ thread, which may sleep: take the command-queue lock and drain the + GSP-to-CPU queue, routing each message + +A halt and a posted message can be pending together, so the top half handl= es +every cause the status reports rather than choosing between them (see +"Retriggering a falcon"). + +The interrupt is only the trigger to drain the queue. A thread polling for= a +command reply routes the messages it reads through the same classifier (see +"Draining and classifying the GSP-to-CPU queue"). + +If the drain fails, the queue cannot advance past the message it could not= parse, +so every later notification would repeat the same failure. The IRQ thread +disables the GSP vector and reports the failure, which leaves the queue +unserviced until the device is reset. + +Enabling the GSP event +---------------------- + +SWGEN0 is a latch, and the GSP drives no new edge into the tree while it s= tays +set. GSP boot consumes its notifications by polling the queue, which leave= s both +the latch set and stale state in the tree, so 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 (full walk) clear stale GIN state from boot + rearm PCI interrupt delivery required under pre-Hopper MSI, whe= re + nothing else does it + clear the SWGEN0 latch so the next assertion makes an edge + register the threaded IRQ handler nothing can reach it yet + enable the GSP subtree at TOP the walk left it disabled + enable the GSP vector at its leaf deliveries become possible here + drain the GSP-to-CPU queue messages posted before the clear + +Clearing the latch makes the first interrupt possible. Messages the GSP po= sted +before that clear produce no interrupt, so the queue drain follows. + +The tree is quiesced before the handler is registered. Registering unmasks= the +PCI interrupt, and a vector that boot left enabled would then deliver to a +handler that services one vector and has no way to service any other. Open= RM +clears all leaf enables at the same point for the same reason. + +The latch is cleared after the tree walk, not before. Clearing it first wo= uld +let a message posted before the walk set the latch again, along with the G= SP +leaf bit. The walk then erases the leaf bit while the latch stays set, and= a set +latch holds the falcon's host-routed set non-empty, so on Turing no later +message would signal the tree at all. Clearing last can instead leave the = GSP +vector pending with the latch already clear, so enabling the vector delive= rs one +interrupt whose ``IRQSTAT`` reads zero. The queue drain that follows reads= the +message. + +The subtree is enabled at ``TOP`` once the handler is registered, and disa= bled +again only after ``free_irq()`` has returned. Disabling it earlier would l= et a +handler still in flight rearm it, leaving the subtree enabled with no hand= ler +behind it. The explicit enable is required because the walk leaves ``TOP`` +disabled, and under pre-Hopper MSI the rearm is a configuration-space writ= e that +does not enable it again. + +The GSP event vector +-------------------- + +The GSP event uses a fixed vector, ``GSP_INTR_0_VECTOR`` (155), on Turing +through Blackwell. Vector 155 is leaf 4, bit 27, subtree 2. nova-core enab= les +that leaf bit and services it, with no runtime vector discovery. + +A full unit-to-vector table can be fetched from the GSP by RPC. nova-core = does +not fetch it, because a pinned vector needs no lookup. + +Draining and classifying the GSP-to-CPU queue +=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=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 queue carries both command replies and unsolicited events. Each messag= e is +routed by its function code into one of two classes: + +* The function code matches the awaited reply. The message is decoded and + returned to the caller that sent the command. +* Anything else is an unsolicited event. OS-error and robust-channel recor= ds are + logged at error level. An unrecognized function code is logged at warning + level. Other known events (GSP logs, libos prints, assertion records, + lifecycle notices) need no action, and the classifier does not log them, + because the RPC receive trace already records their arrival. + +The RPC sequence number appears in the receive trace and takes no part in = the +match, because the GSP does not echo the sequence number of the command on= every +reply. On r570 the reply to ``UnloadingGuestDriver`` carries sequence 0. + +The read pointer advances past the message in both cases, and also when a +matched message fails 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 carries its length inside the +region the checksum covers, so once the framing or the checksum fails ther= e is +no trustworthy length with which to skip the message. Such a failure poiso= ns the +queue, and every later receive fails. + +The classifier is a fixed set of function codes rather than a handler regi= stry, +and it logs the events that need attention. + +Both the polling path and the IRQ thread route messages through this class= ifier +under the command-queue lock. Replies and events share one queue and one s= et of +read pointers, so one lock covers the whole drain. A thread waiting for a = reply +passes each event that arrives before that reply to the classifier and kee= ps +waiting, under a single deadline for the whole wait rather than a fresh ti= meout +after each message. + +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. + +Design notes +=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D + +Register naming +--------------- + +nova-core uses the ``NV_VIRTUAL_FUNCTION_PRIV_CPU_INTR_*`` names for the C= PU +tree on both pre-Hopper and Hopper-plus parts. Any function reaches its ow= n tree +through that aperture. The Hopper-plus central aperture (``NV_GIN_CPU_INTR= _*``) +configures other functions and is not used by the CPU path. + +The controller has two names in the hardware headers and in Open RM. +``NV_CTRL`` names the tree on pre-Hopper parts, and ``NV_GIN`` names the +Hopper+ unit that contains the tree along with arbiter logic. This document +calls the controller GIN throughout, because the tree nova-core drives is = the +same on every supported part. + +Tree API +-------- + +Servicing a leaf has a required order: read its pending bits, then clear t= hem. +Reading a leaf produces the handle that clears it, so clearing a leaf befo= re +reading it does not compile. Enabling and disabling a vector or a subtree = has no +such order, so the tree provides those as methods of its own, with no hand= le +involved. + +The handle orders the calls that service one leaf. It is not a lock and it= does +not coordinate the tree as a whole. Nothing stops two walks from running a= gainst +the tree at once. nova-core does not run concurrent walks: the GSP event h= andler +touches only its own leaf and never walks the tree, and the only whole-tree +walk, the startup drain, runs once during probe. + +Threaded handler +---------------- + +The queue drain sleeps: it takes the command-queue mutex and walks shared +memory, so it cannot run in hard-IRQ context. nova-core uses a threaded IRQ +handler, and the sequence under "The GSP event" shows which work each half +does. The self-test does no sleeping work and uses a non-threaded handler = with a +completion. + +Shared BAR0 mapping +------------------- + +The GPU, the self-test, and the GSP event handler read the same BAR0 regis= ters. +nova-core keeps one BAR0 mapping and lets each of them borrow it. An inter= rupt +handler is torn down when the device unbinds, so it only runs while the ma= pping +is alive. + +Self-test +=3D=3D=3D=3D=3D=3D=3D=3D=3D + +The self-test runs during driver probe. It registers a real interrupt hand= ler +and confirms that an interrupt injected at the GPU is delivered all the wa= y to +that handler, so it needs a working GPU and PCI interrupt path. It is gate= d by +``CONFIG_NOVA_CORE_IRQ_SELFTEST`` and runs before GSP boot, so it never to= uches +GSP interrupt state. + +The parts with no hardware dependency are covered by KUnit tests instead: = the +vector encoding, the subtree and leaf arithmetic, and the per-architecture= rearm +policy. + +The test drives ``LEAF_TRIGGER``, a hardware register that every supported= part +implements. Writing a vector number to it latches that vector exactly as i= ts +unit would, after which the vector takes the ordinary path to the CPU unde= r the +ordinary enables. + +The test drives vector 129, at leaf 4 bit 1. It registers a handler for th= at +vector and triggers it twice, waiting for the first delivery before trigge= ring +the second. Its handler deliberately mirrors the notification path: it cle= ars +only its own leaf bit and rearms PCI interrupt delivery, rather than walki= ng the +tree. + +The two interrupts cannot coalesce into one, because the second is trigger= ed +only after the first handler has finished. A handler that fails to rearm t= imes +out on the second delivery instead of passing. One delivery would prove no= thing +about the rearm, and a handler that walked the tree would prove nothing ei= ther: +on every configuration except pre-Hopper MSI the rearm is a ``TOP_EN`` cyc= le, 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 one finds the doorbel= l bit +and nothing else pending in the leaf, and the doorbell bit is clear once t= he +source is stopped. Anything else fails probe. Requiring the exact mask on = the +second delivery shows that the first handler's clear reached the hardware.= The +test starts by disabling every vector in every implemented leaf and draini= ng the +tree, and it runs before GSP boot, so no other vector in the doorbell's le= af can +be active and the exact mask costs nothing. + +The test borrows the allocation that probe made for the serviced subtrees = rather +than allocating its own, and looks up the vector for the doorbell's own su= btree. +If the doorbell moved to a subtree nova-core does not service, that lookup +fails, and the self-test and probe fail with it. The interrupt is not misr= outed +silently. + +The test exercises the interrupt path from the GPU to the handler without = GSP +firmware, which is useful when bringing up PCI, MSI, MSI-X, and passthrough +setups. Under MSI-X a pass also shows that the per-subtree table entry rou= ting +works, since the delivery arrives on the entry belonging to the serviced +subtree. + +Virtualization +=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D + +The per-function trees, the GFID routing, and the central ``NV_GIN`` apert= ure +support virtualization: each VF gets its own tree, and the PF or firmware = routes +a unit's interrupt to the right function. MIG (multi-instance GPU) partiti= oning +adds more structure. nova-core services the CPU tree of one function, and +implements no VF tree management, GFID routing, or MIG support. + +References +=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D + +* nova-core source: the ``irq`` module holds the GIN register definitions,= the + interrupt HAL, and the tree API. The falcon interrupt registers are in t= he + top-level ``regs.rs``, and the GSP command queue is in the ``gsp`` modul= e. diff --git a/Documentation/gpu/nova/index.rst b/Documentation/gpu/nova/inde= x.rst index 2afa58e8f08d..2130d1caf4c3 100644 --- a/Documentation/gpu/nova/index.rst +++ b/Documentation/gpu/nova/index.rst @@ -34,3 +34,4 @@ vGPU manager VFIO driver and the nova-drm driver. core/fwsec core/falcon core/tlv + core/interrupts --=20 2.55.0