From nobody Wed Sep 30 12:58:54 2026 Received: from SN4PR0501CU005.outbound.protection.outlook.com (mail-southcentralusazon11011067.outbound.protection.outlook.com [40.93.194.67]) (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 650352D7DDB for ; Sat, 8 Aug 2026 03:11:30 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=fail smtp.client-ip=40.93.194.67 ARC-Seal: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1786158691; cv=fail; b=tf4yCNBhnD7164rjhTS6xUiUxA3l8s/XuHtUNwVkyFCwrCGIECEB8bOWvatjBMm2EY+UbdH4gwYmGz49r4Spqytcr3R9Jr0k8PpiJKZUY4Id/hf1+GspgVMdgzZ0dhiWlVHTfsk82LDAovfQbgBQ0Sl42JHuOB9e0S/iv3LpCDs= ARC-Message-Signature: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1786158691; c=relaxed/simple; bh=cHSldXBlxIsxVe/1gLI51UUSEuF/ON0EqflutVnojd4=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: Content-Type:MIME-Version; b=g9VYS9iTjs51FyrJcOE5oDQc+7iq0JCx2z5/Kb/ZFmF5w0wFE7Hqc5+F4tRiDTJGxy9n0fMlU18XRy3vZT5cabaAuQRGvne/iCCbaFp+ik1Qw9i3Jh8nQWi141YhzbGeVHHZKnwif9t8uap5EySLzN069tEHbZATUHW1bzVo6mM= 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=Ebg9uB23; arc=fail smtp.client-ip=40.93.194.67 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="Ebg9uB23" ARC-Seal: i=1; a=rsa-sha256; s=arcselector10001; d=microsoft.com; cv=none; b=uB729+ZPnq8ng2JiUS8jAR9DOl1BAk5NhAJOEsfMvcc1B0GBBzst1wIdIgbDTQLyLOqjpRF+RsmBmaxxXh3aix6OTkvkJtE97Kd8XDE4FpYEPHW+HAGn+8ZXkPblm3ffMcUIIEF0bplrevpSVRsf38tY4my+DhKdS9LUU9857Inqv/yY6/TlX+if0RsEzb2geIJyc6opfNtasn9dl1ftmJE51eVLLPlwKWbmsEosViHhHjXScmnzNnj9wXql7y8y1JrruO3ESAwobyXUxn8eU4KTWWaAbCBZJhtbzELoH9zT7SQmAhzTtpr3EFDeqtAy+LI3RhkXbCMp4yz2givlSg== 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=sz726U65Hs7GYeJzuW8oLJsEyPQvc+4fuQtWr/2kCPA=; b=divC7XFWWGydKWVLxH/SOuxiJl+PdgNLIpzUBHTWQEJVzjfBMs9QHs9IWfKspJN5Nq3FWlZqEwT3YHrfllpXBwF2HDp8lEFD8YulMFywhV1tpzTgogMZuWS2gw9WRtbseDqdMVHlsLQZyiVodfwF95Ml/c7VbJgZX++9UcAXMiSqahOl3UC01u5ehWj6Hu0qmKD06Zugl2Vae7WuRl2TdUeqS4tf96oWxhlAxhKkXWstxF2AoiC3x7ETQWvEOuZvD9k/nbYS5+quxJYJz64Ayn1CxPIjqdIrRIwPmcEjl9huLCU8vlWFKMK8M9JcxZvo7m2t2VR0A7HHp08kKKvgpA== 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=sz726U65Hs7GYeJzuW8oLJsEyPQvc+4fuQtWr/2kCPA=; b=Ebg9uB23UHvGwkKwoc35ozbcRv39ef2ax4fzXFz9Q1V6GEGvNiSZIsYelY+zZ4m1xYZKW2qrN7u5zIUjsVoCRGjJTzyIEoFVRDy3vBdk/PySPuesiBEjsycZmvakzsSTkypYU7DSDVQZ4kRfRl64lbJqELUTIKnSjC/Q76RaL8TT6PTekNIdkApjUkbZB6s6bJto33fxhzUAcXyCCdKVzU1dV1lB3o2eSUdasE2LlRHeLaqy5FEfd7mqKSRQiaDid2uVU2U3J3ZOP8E3Wae4TPomRaXqgE824Tdhf+tYq2g47JGgRx3/PYlHW/P4X/BK4K3cb0cZPwRU2/Fvg4ioJg== 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 CH2PR12MB4198.namprd12.prod.outlook.com (2603:10b6:610:7e::23) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.21.292.21; Sat, 8 Aug 2026 03:11: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.0292.022; Sat, 8 Aug 2026 03:11:23 +0000 From: John Hubbard To: Danilo Krummrich , Joel Fernandes , Alexandre Courbot Cc: Timur Tabi , Alistair Popple , Eliot Courtney , Shashank Sharma , 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 01/17] rust: sync: completion: add wait_for_completion_timeout() Date: Fri, 7 Aug 2026 20:11:03 -0700 Message-ID: <20260808031120.363869-2-jhubbard@nvidia.com> X-Mailer: git-send-email 2.55.0 In-Reply-To: <20260808031120.363869-1-jhubbard@nvidia.com> References: <20260808031120.363869-1-jhubbard@nvidia.com> X-NVConfidentiality: public Content-Transfer-Encoding: quoted-printable X-ClientProxiedBy: SJ2P221CA0001.NAMP221.PROD.OUTLOOK.COM (2603:10b6:a03:5db::15) 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_|CH2PR12MB4198:EE_ X-MS-Office365-Filtering-Correlation-Id: d56def53-2c93-4724-d84b-08def4faba0b X-MS-Exchange-SenderADCheck: 1 X-MS-Exchange-AntiSpam-Relay: 0 X-Microsoft-Antispam: BCL:0;ARA:13230040|23010399003|366016|376014|1800799024|7416014|10067099003|6133799003|56012099006|11063799006|18002099003|22082099003; X-Microsoft-Antispam-Message-Info: 9mamXxYxpb6mvS8mGbTTzigBRTzYSBcrvMVsPqUavaLzRU8pMyFG9CjXcNaZuqVWvIjX7E2qj8LAEOMU1MltsrkQgX0VhkHJJjPPdvcpsaX2a3tKppjb7fCNl33JLYyUCM3yV5fWNTdA4Mv83teM+n1XEiEzsrB+PK1b8cIxwwAPfk1qgYURDws8MYbrjMFsDPnuqvfLGl9GyzuKpG3JBj2DnDhJVHieaXVUK6P/Uv7vbXz/njDorCbKBRM2S1PYNTxIpzTVe84G2BiZoMeVrMopDnG5a6BJUWZoKOplwUIr61omAPc67BOxpCC+BlQlWff/VW9M4rME4uKyMSd2dJoZC7zQ/QoBgBW5xioGFM3DCWzqPAghIwmeShy4cBV+0C2qXMoBZC74z+Ix10gYk/UwC9Lpnv4rESzIoC+Rb1SGyLeHxKMkikvqmsNbHjtFGVl16PqSilfa9RHBgsdLJ4xHfdSpxD478hw3LxEBrXmNEEBkZ6xkNor+rmDef4JvNeonlfMfTP1l/ewyeM7VuHVBXPMVPnA285NYbgDkz7L4aVwQcIIIjEgAKb6FAVcZm5x5JQjWNJ8JiU265tetc+NkhQx6eNJFqMHO1y1KGTP+PAzqTTr84pZWkfMauz1aarito3dyYbGmsiahCw+KOb0n3Rk8BF2aYTd+1oDxhW8= 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)(23010399003)(366016)(376014)(1800799024)(7416014)(10067099003)(6133799003)(56012099006)(11063799006)(18002099003)(22082099003);DIR:OUT;SFP:1101; X-MS-Exchange-AntiSpam-MessageData-ChunkCount: 1 X-MS-Exchange-AntiSpam-MessageData-0: =?us-ascii?Q?WL4FJ9OAdEcADAVHDMCyrehNSFxLPBTtJmioQ9Pr96xQtKDrMQCdyJkS4sYv?= =?us-ascii?Q?x+PEQ+Fupa9DkjfMgtRYRI6oCweygLyxr4gFCCuVzJRmX6deqMCydPc7hJcd?= =?us-ascii?Q?pQEjAIzQBNoP4VzJTgcSNJl4YHLvdYnQa8aHzADlm5/HzdNEwTBbU+3g9r7i?= =?us-ascii?Q?kXAIarOyPe9SSleFQh1Usf44RdSo87dI8wBcFg1Z2Zbg9ay4u3IYCW/oT9rf?= =?us-ascii?Q?HpAOiJG7rxR8o1YkZmiLU8L2V3S8bGz1nHb7uSqMTe3h7lffNuTzJV742mqW?= =?us-ascii?Q?gJhaiw4WbVED+55/k7exhIY46raO+mLqlizTVJAHJ1Uwe4wIwGh7K42IywDE?= =?us-ascii?Q?1h/5nCwOKiIMxgLgLSpGEdrzuuZm+fw6gVJIVwzOea2djsf5+yW5XJQeAD1S?= =?us-ascii?Q?s0Ri5kT5BQeAQyBap3ukYW9+kbNkFwhM67ai9bg4C0RcLhEsEXfeQXNY68iz?= =?us-ascii?Q?vQAap+BYA61VkECRQ/kKf1KCnE59cM3ooL8bGluOpRLLNytsqhCuoF/okPAB?= =?us-ascii?Q?m3Gt1+Flw35PP/4e3LgVc/7kLC0b0FSLVlx+0PpMUybRBUB98RkFmb7WZy2J?= =?us-ascii?Q?rwBH4QRevc3UeXAsPK4lW14LykgPfesxDaZVCI2eRx612YxADMY/Rf0rpywc?= =?us-ascii?Q?21eAELmm7vLKLcEX+PDyYIkYn3RlYNdepRybgTq03c+80M+Zhjrc2diC3R0M?= =?us-ascii?Q?twIQgH1C7C96jdCXElPXxfN69KzCs+Y1E3qxO4S1YRyJ/V/9/sj4ZX9NMmt3?= =?us-ascii?Q?umkX2FowpqlJrScnzcWWiNxKdzt8leicroiRl6Bmq7ADFPr4D/k8J2BxQJiE?= =?us-ascii?Q?ey5L3FeXjmplq5m/XUtdOdqIRVcXlXThYbodmHgNZ8/HXUppeb3vvyPXeNSj?= =?us-ascii?Q?r1xPVTTqwEk6bQc4jTgHMjEiKgaq7wZM7HmTOM/bihUoiHc66LRKrU6wSPb+?= =?us-ascii?Q?wmE7DDnAMu8wAH5JnnkMKNFCUDfbxpv/QtI9N0W2DIilCxbEeN9DVsMc65HJ?= =?us-ascii?Q?ky75eUxOVv9kYG+MgYeE+CVEBB9DId+UxHkqdML4UcgarUuwLV9wLy4FAMLQ?= =?us-ascii?Q?bg9JiOo3AMQF7W4YY5UlmaUd61xuvaV9jbHvhZbdtqu7jgY3JO9MMT0sMar5?= =?us-ascii?Q?X0Pdc8N002RANB7vE0bMt7NCe3qoijxuTWVLcdxkstp7hUbzxkyDg1hzKFHT?= =?us-ascii?Q?tjrdFLOdNjeCK0GEiacXa+xGerVGPgM+NQte3qLK3iHqkfJ8w5iXHM5+QrzG?= =?us-ascii?Q?QvtRkx70Z/7VfpiJ8LJIvJH/rdjLVebJDeNgNN+XpGmVxUdrqYvzWLC0pmPP?= =?us-ascii?Q?6/bznxih1sZGT7Ry1+ibz1jNzw5Kkh/z/pfLFL3U5SA7Fqk1AH9Y4r+UjR3k?= =?us-ascii?Q?brwMjCqOVTSbYXrOg9m1R5S9R8IrkGV7rikvnDx6U3BZLfPuKBIxhndz6Lwq?= =?us-ascii?Q?wA42D+COZrEUlYP6m8CpJGpm7yQXrFU5jBwLvcfuZS6ECWAiMI+4pvJ0qINI?= =?us-ascii?Q?PbpEC39HDagsjd83PLO8VxNdwReHN1JIeFY/6zs0jTsIEWlKhMoa5l7awq2X?= =?us-ascii?Q?G1XZln9oEANiD6DcGpw2l36QaVGrWguUXyjiBBySWnFTRQEgfBKeCgqcfTBh?= =?us-ascii?Q?rgfJ18HenbYCikLN8u1JHaPsgQy5IwlWHT8rTI9brLFLb0IfCyyryMd8xKvf?= =?us-ascii?Q?2/c2hdDAaJRdaHLia1qPkugEOkNlFfJMCAQSZqsroBqt1IrfmkETZhSZWNE2?= =?us-ascii?Q?xqHqwu2z4w=3D=3D?= X-OriginatorOrg: Nvidia.com X-MS-Exchange-CrossTenant-Network-Message-Id: d56def53-2c93-4724-d84b-08def4faba0b X-MS-Exchange-CrossTenant-AuthSource: DM3PR12MB9416.namprd12.prod.outlook.com X-MS-Exchange-CrossTenant-AuthAs: Internal X-MS-Exchange-CrossTenant-OriginalArrivalTime: 08 Aug 2026 03:11:23.4648 (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: 6eXQMwFxGpZl/bMZpfd9tCb7FyePKZt+UF0IUw5UOmkEItRs8TmTcwqLxdE3Msvfv8Vhgo7aSn1+yCHMPReqLQ== X-MS-Exchange-Transport-CrossTenantHeadersStamped: CH2PR12MB4198 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(). Document the type invariant that Completion always holds an initialized struct completion, and cite it in the SAFETY comments. Signed-off-by: Joel Fernandes [jhubbard: return the remaining jiffies, document the type invariant, cite it in the SAFETY comments] Signed-off-by: John Hubbard --- rust/kernel/sync/completion.rs | 34 +++++++++++++++++++++++++++++++--- 1 file changed, 31 insertions(+), 3 deletions(-) diff --git a/rust/kernel/sync/completion.rs b/rust/kernel/sync/completion.rs index 35ff049ff078..b443c4999493 100644 --- a/rust/kernel/sync/completion.rs +++ b/rust/kernel/sync/completion.rs @@ -6,13 +6,22 @@ //! //! 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. /// /// The [`Completion`] synchronization primitive signals when a certain ta= sk has been completed by /// waking up other tasks that have been queued up to wait for the [`Compl= etion`] to be completed. /// +/// # Invariants +/// +/// `inner` always holds an initialized `struct completion`. +/// /// # Examples /// /// ``` @@ -96,7 +105,8 @@ fn as_raw(&self) -> *mut bindings::completion { /// completion is permanently done, i.e. signals all current and futur= e waiters. #[inline] pub fn complete_all(&self) { - // SAFETY: `self.as_raw()` is a pointer to a valid `struct complet= ion`. + // SAFETY: By the type invariant, `self.as_raw()` is a pointer to = an initialized + // `struct completion`. unsafe { bindings::complete_all(self.as_raw()) }; } =20 @@ -108,7 +118,25 @@ pub fn complete_all(&self) { /// See also [`Completion::complete_all`]. #[inline] pub fn wait_for_completion(&self) { - // SAFETY: `self.as_raw()` is a pointer to a valid `struct complet= ion`. + // SAFETY: By the type invariant, `self.as_raw()` is a pointer to = an initialized + // `struct completion`. 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: By the type invariant, `self.as_raw()` is a pointer to = an initialized + // `struct completion`. + match unsafe { bindings::wait_for_completion_timeout(self.as_raw()= , timeout) } { + 0 =3D> None, + remaining =3D> Some(remaining), + } + } } --=20 2.55.0 From nobody Wed Sep 30 12:58:54 2026 Received: from SN4PR0501CU005.outbound.protection.outlook.com (mail-southcentralusazon11011067.outbound.protection.outlook.com [40.93.194.67]) (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 EFDB63750D6 for ; Sat, 8 Aug 2026 03:11:31 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=fail smtp.client-ip=40.93.194.67 ARC-Seal: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1786158693; cv=fail; b=J4W27DmP3VkE5aXhTxOeUJoxDdGf8Vogs8/N13UJdX/udYZuVVMo7g01yWn8BiXVGvjfJbE/jqwnfsVIqEq1yfN6ApizB2wX/mrPx/5SgJvDmVoDU/TNYwJ9cW518J2w5Sls2+/hTgU0k/eD5Z05MVDH7E+QZmNyHW//ng8cKbU= ARC-Message-Signature: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1786158693; c=relaxed/simple; bh=KMf8CGs+ritcMe8nOsf/RUcnZ0lItMcGiIDLGHNFyOk=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: Content-Type:MIME-Version; b=CrNZHFPBI7giPbcxPFrlz0oZXFD0RnDT7JJy4vMV0gupEcCZL5gfR0focIj3rW4VvPS/ZL6wnQ65Y4BDCv0NKvNG5dYUy4z+7E2SmOjF9MKH+r2fT4SoO5DEBJ2tDf3oDe2XWvo9luJmO6u1j5vXBJ9atKKsjePjTQ3BKylOO4U= 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=SV6yFMlu; arc=fail smtp.client-ip=40.93.194.67 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="SV6yFMlu" ARC-Seal: i=1; a=rsa-sha256; s=arcselector10001; d=microsoft.com; cv=none; b=PnUGHZoBq0fCtuNCbQpjnp6XnfGIX8OtjYrzUFXAPFarMmIGMmB8ahpDGl74DyVfOGqB5BRTyVqLDV6LWb2TjMtw5P1w3YhnXsPXHXgu273QyzfGoC8IWoDrqc9EHuwihEsgcauRwZeaxW8tsYk6Gln2zTGB66/9yoaaWjUu5LktUZRbLpgRMWTSfvchhF1X/zwYFiPj1nKB84N51U47+GQJNHdIp4UmmpEtkygWmsKyVndrpd8Btn8aqFRgC3PmWgpTDMd0ZcCfcKL+ioFbqdBlOSbVQP7qQzOI7k7cdOz5LvOK3dY3HO7gbIp732AIOUyt+QbiYGpT9/gCR0hasQ== 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=AMKUuJEGQkZDOQTYiJtatdTjcCjJVi1EjbX26h5Rc94=; b=CeIfOGgfV5eTurdb3IY/lFufPxaei4M4ASyxG3DhMPfsDAHkqxS0johH+2sSz6FS4AIXuIMx0F/v3yPIPR1y894SL0AO5h6fnIln17IjyoiM0akvd0NwG+8RJxPfqZgZYgKZzHrJudSdUzNvnMqih1UlHrlHvnSkNfMo9OrREoMdxZ6QIdVfWbf93OnPX1/5cbVl+owLQAVpvF+k+E6cP5IWOOLaOSYGtYoTBKHv/7MjFoGZEIrUoUUk/WSc6opB9m/fRz0n5z9AU4Ww//LCezdGeq9Zs5LH2o84WhFehIYkum2fXAdOe5yzxZPyHq3iWP+ZCGzOo3P+yXjjM+bkYw== 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=AMKUuJEGQkZDOQTYiJtatdTjcCjJVi1EjbX26h5Rc94=; b=SV6yFMlu6dm2sS7LzQfX8E2Ho2MoqbE/cK9H+6lLJmaaqzJNmUaDJgdnQ7DywVED+fVpMiJQ5COLnpamSak72IXvnalEkHNftO2qgHdiDcWZ6cii0qi5Yb0emjIzzxYHkqRgLn+/TEFi6Db8ENYLMf8qcuEPQSEFmexKSSwpB5yofaZb3kfXqfjJ5nVDpzgv19TIH25F/euqLTpXaElQwYsqXXzX+PEJtW05AD5RPktMJx5z7XP2P6cQVkPvIZMPB/BquM/LsBFmquabhX55PwFvSStzma+ageksaucI9UpDxWApGVisc4LyJTMEjrX3wGn9WzS8wFiTa9ouYNyF/A== 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 CH2PR12MB4198.namprd12.prod.outlook.com (2603:10b6:610:7e::23) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.21.292.21; Sat, 8 Aug 2026 03:11: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.0292.022; Sat, 8 Aug 2026 03:11:24 +0000 From: John Hubbard To: Danilo Krummrich , Joel Fernandes , Alexandre Courbot Cc: Timur Tabi , Alistair Popple , Eliot Courtney , Shashank Sharma , 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 02/17] rust: pci: expose the whole interrupt vector allocation Date: Fri, 7 Aug 2026 20:11:04 -0700 Message-ID: <20260808031120.363869-3-jhubbard@nvidia.com> X-Mailer: git-send-email 2.55.0 In-Reply-To: <20260808031120.363869-1-jhubbard@nvidia.com> References: <20260808031120.363869-1-jhubbard@nvidia.com> X-NVConfidentiality: public Content-Transfer-Encoding: quoted-printable X-ClientProxiedBy: SJ0PR03CA0338.namprd03.prod.outlook.com (2603:10b6:a03:39c::13) 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_|CH2PR12MB4198:EE_ X-MS-Office365-Filtering-Correlation-Id: 654c80f8-6f40-4677-cd79-08def4fabaa0 X-MS-Exchange-SenderADCheck: 1 X-MS-Exchange-AntiSpam-Relay: 0 X-Microsoft-Antispam: BCL:0;ARA:13230040|23010399003|366016|376014|1800799024|7416014|10067099003|6133799003|56012099006|11063799006|18002099003|22082099003; X-Microsoft-Antispam-Message-Info: UE2ABUtGi3lLyxZW8E/tDJANJEeURLuCyIEL92tPZaidMe7HYup1yeuQOluMo1ixCeiIBD8xWZn60UwF0WmOgenOw6mP6VfBTCKR6N1FHauuZ6CE4GTKp2QgufcNWXdV2GEAiq7GyUkVDwr71OPk6P+AdGwI4s3maAjYkdCia4GyShE6b2QB/XpnfIoP60KxoIJN2U0sXTwCufAUFck1OimBOMdSyXx85e74EfMhVBkYclRCp8lvoFG7KgDOXmOg2H8QEsjpiFQHQe9rvz2ivVH6qgI8ZDAIdJqRaykn8AfgG0X+zCdJN/0Tcj9wtEy0sMc0Zq9CresFm5nGiaH9nb2DNS02AxY2GjuphKKJ4RXFmNrIOsydBLBfGtV8tz3U4lmHWJZ9chyHdwDPZTspRXsSChS+dZ8iir+hFQF4ei83jCM+h9PRSE3kmyESpjC5p5aK5/4nIuLZnEossAythURG3p1P8lmxvfWaxKA5n2mCBOk2f9LGpRpp8IQtmbHc0I5SUDYb5MOw+vDbOZhOfy7dc+mXUOoVzTeiWSJF8OyQ9uS+xidwnwTKX5Fi3Rd28J3N0xHwmDVvfJsJGAsXv3izE0ZY9xdJv4hB1Bwz1xCisxw1yiNMxMItpqBXjd+A5Zggh9KarljtND9Xi2e1Oup8VLGtZ8qzTHNqDOZCFCI= 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)(23010399003)(366016)(376014)(1800799024)(7416014)(10067099003)(6133799003)(56012099006)(11063799006)(18002099003)(22082099003);DIR:OUT;SFP:1101; X-MS-Exchange-AntiSpam-MessageData-ChunkCount: 1 X-MS-Exchange-AntiSpam-MessageData-0: =?us-ascii?Q?k50XHko8lNeqT486E4pI01gpwyVWO1WF75TR9mhYHLBzbQ186UR/5qYI/uux?= =?us-ascii?Q?V6o4EBTfRDO3SpGuVLRCTw99R8/c8p8kGybSskBRjOQODu4Xf56IXBZpkK91?= =?us-ascii?Q?UIjhigfaov1ezKVLV/KAYAP1GBDWJDAAfYuCosJj9ny2Fvwy64QI3Hb8N3pt?= =?us-ascii?Q?TRdAcuGEwDX3s3jHA9vKK5u+I/LL7arFPPEAOB9ybgW30Cfq8YV5rfkSsO4P?= =?us-ascii?Q?QJv5ZHFlob+4m32JKTYcn/hYYA5XxIpMTBphodcXSP66lmgTvfoFEL30T6OM?= =?us-ascii?Q?FNqo0HS2nGtr7w8Y3ZLpltUCX7fAR16sSTX+XFgbQscfH33iA9383l8jrFK8?= =?us-ascii?Q?ea/OZcz/nSFtbPy6be4bWNnDTXqXZzO78l02Dg+ab9xnSlYuxsBv/ImObQoA?= =?us-ascii?Q?DX9k2NrK2s/zLIcAyPcnwyNXqoz9Vg1bggCt++ku7jnrPDMxLGaBNIYKQMv9?= =?us-ascii?Q?PpolVfg1GxM5e1AhzAih8AuUbkcesogA7eXgMVkUaVl0YZx15/qF1cQq3Fcp?= =?us-ascii?Q?GH376WEn0k0CZYdesY8WvtQZwNwMpUYvoCCnRXy+h3MRrfibHjns5D3D0WKc?= =?us-ascii?Q?CFc9arEB3/uAi1DaesnxMv92kJaqHEyl2hgnGBGtgz2j3eFgh8mt0zo2dAbb?= =?us-ascii?Q?lo1YbFgFePhuhNYf6mE8GUqMrExnqBZ95ZbdBHSYQUPDp5FUClNq+XRz9Mpv?= =?us-ascii?Q?kQ6ShfGeS9uyhEtMWUpr5ALbOQapRSN6S8oq2cndphMhA6FZC/7rapqbmDXx?= =?us-ascii?Q?cZH1xRIUFx1f5QYYQ6TSIcxeQwNkvvHXATW0cUaneM6kOYsVE95JvtU/xzkA?= =?us-ascii?Q?gtRRLmYgp/0DfN7ljSVtdCCnDWhyK/fHR13vClYr9D4xX4JVuu+JVePhiEkn?= =?us-ascii?Q?AUz3QoBbc9hB1ubLUiUUX1Xi77Q8WUD9XvZx+pRezDh1pofsZJBeOH8L2HWK?= =?us-ascii?Q?5cS6N1WdL0J4WDuUAUZKNykM+2KjNNsGoYS3aBMP+aAIoYgxoX2rucZuBKyy?= =?us-ascii?Q?3xz+JvH7XJ6hhGxx+XIqKD2XIFBGzSZGzttmLDVTDtfRMBm+Rzzddoi1SQII?= =?us-ascii?Q?bOxjKvg7XFnJgA7quL/jPK7h8nIU/92K6+KuHX+JWLUYnqg3ZcvhfKjRP9Qh?= =?us-ascii?Q?kdHgM/st0rK0aXbhNao+MajWypy0sZly8x3NtDdp1xAOCpj7bg0Uk58oqn/D?= =?us-ascii?Q?P21EWUkrOyRRKK3I+1wvT99cTkk1iJTyz3D89BgjPSjrX5P2FwY0MmRiLoa3?= =?us-ascii?Q?uaCxMxVrLj878sXOqlG0qsBbQCXomGq9nq0qiSfKiIz0xlchqQ8gGZoahAHy?= =?us-ascii?Q?nUP6g9zjX70u8kTwUVn2MCk1ln1UqBgKdD2vtJNjOFChq8/fuIq+/rZvw5PF?= =?us-ascii?Q?M7DCuXnXPts1PDSFbI+bItzIHXjwL7TUYW74LXx7+whNzdVVRxRo5mhfFzXd?= =?us-ascii?Q?0Le2tVMK0kRybtrXBls3m8Xx0W6+S09hpMuXbE6wOaeobfZclMaAvpy2wabX?= =?us-ascii?Q?u28hQ002r5Um5BqMTHMELp7TTT2nth/3d2o2vvsWQrwUXG98ShQgA63vGmMo?= =?us-ascii?Q?/KWgoS0JSV69IFVVkfx6WO29DdN789/JZfkrodkk7H2qoMWGUGJ61Gc80cfs?= =?us-ascii?Q?8BopG87j/swxqyzD8vbhMlArfeWUaN7J2DnZKkiBkvEG6kk5iZXD5dkXpT0U?= =?us-ascii?Q?ZGneVPoRnrqNLA6+mEwdFFcEe9v4P12VLKNvNXZ3lQShpDBz0OT8lZWpki1p?= =?us-ascii?Q?jcCbid68iQ=3D=3D?= X-OriginatorOrg: Nvidia.com X-MS-Exchange-CrossTenant-Network-Message-Id: 654c80f8-6f40-4677-cd79-08def4fabaa0 X-MS-Exchange-CrossTenant-AuthSource: DM3PR12MB9416.namprd12.prod.outlook.com X-MS-Exchange-CrossTenant-AuthAs: Internal X-MS-Exchange-CrossTenant-OriginalArrivalTime: 08 Aug 2026 03:11:24.4617 (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: Ft/n+Cep7zMS34150S1wh+dWLY+cX0E46Bjsa15SQA2zQZkL48uBy2k7/a18wmHR0IjPcbcbdOJdy2gcg1UeeA== X-MS-Exchange-Transport-CrossTenantHeadersStamped: CH2PR12MB4198 Content-Type: text/plain; charset="utf-8" A PCI driver that allocates several interrupt vectors registers one handler per vector, so it needs the number of vectors the PCI core allocated and access to each vector. The Rust abstraction discarded the count and returned only the first and last vector. Return a handle to the allocation. The handle reports how many vectors there are, and resolves a vector index to the Linux IRQ number a handler is registered on. Assisted-by: Cursor:claude-opus-5 Signed-off-by: John Hubbard --- rust/kernel/pci.rs | 1 + rust/kernel/pci/irq.rs | 123 ++++++++++++++++++++++++----------------- 2 files changed, 74 insertions(+), 50 deletions(-) diff --git a/rust/kernel/pci.rs b/rust/kernel/pci.rs index 9f19ccd5905c..2f58b284efff 100644 --- a/rust/kernel/pci.rs +++ b/rust/kernel/pci.rs @@ -49,6 +49,7 @@ Normal, // }; pub use self::irq::{ + IrqAllocation, IrqType, IrqTypes, IrqVector, // diff --git a/rust/kernel/pci/irq.rs b/rust/kernel/pci/irq.rs index fea484dcf9cf..66723a43491b 100644 --- a/rust/kernel/pci/irq.rs +++ b/rust/kernel/pci/irq.rs @@ -17,7 +17,7 @@ str::CStr, sync::aref::ARef, // }; -use core::ops::RangeInclusive; +use core::num::NonZero; =20 /// IRQ type flags for PCI interrupt allocation. #[derive(Debug, Clone, Copy)] @@ -71,44 +71,72 @@ const fn as_raw(self) -> u32 { } } =20 -/// Represents an allocated IRQ vector for a specific PCI device. +/// A Linux IRQ number belonging to one PCI device's interrupt allocation. /// -/// This type ties an IRQ vector to the device it was allocated for, -/// ensuring the vector is only used with the correct device. +/// [`IrqAllocation::vector`] resolves a vector index to one of these, and +/// [`Device::request_irq`] or [`Device::request_threaded_irq`] registers = a handler on it. +/// +/// # Invariants +/// +/// `irq` is a Linux IRQ number of `dev`. #[derive(Clone, Copy)] pub struct IrqVector<'a> { dev: &'a Device, - index: u32, + irq: u32, } =20 -impl<'a> IrqVector<'a> { - /// Creates a new [`IrqVector`] for the given device and index. - /// - /// # Safety - /// - /// - `index` must be a valid IRQ vector index for `dev`. - /// - `dev` must point to a [`Device`] that has successfully allocated= IRQ vectors. - unsafe fn new(dev: &'a Device, index: u32) -> Self { - Self { dev, index } +impl<'a> From> for IrqRequest<'a> { + fn from(vector: IrqVector<'a>) -> Self { + // SAFETY: By the type invariant, `irq` is a Linux IRQ number of `= dev`. + unsafe { IrqRequest::new(vector.dev.as_ref(), vector.irq) } } +} =20 - /// Returns the raw vector index. - fn index(&self) -> u32 { - self.index - } +/// An allocation of PCI interrupt vectors for a device. +/// +/// [`Device::alloc_irq_vectors`] allocates the vectors and returns this h= andle. The vectors are +/// numbered `0..count`, and [`Self::vector`] resolves one of those indice= s to the Linux IRQ +/// number that delivers it. +/// +/// # Invariants +/// +/// `dev` has an allocation of `count` interrupt vectors. +#[derive(Clone, Copy)] +pub struct IrqAllocation<'a> { + dev: &'a Device, + count: NonZero, } =20 -impl<'a> TryInto> for IrqVector<'a> { - type Error =3D Error; +impl<'a> IrqAllocation<'a> { + /// Returns the number of vectors that were allocated. + /// + /// This is at least the `min_vecs` that [`Device::alloc_irq_vectors`]= was asked for. + pub fn count(&self) -> NonZero { + self.count + } =20 - fn try_into(self) -> Result> { - // SAFETY: `self.as_raw` returns a valid pointer to a `struct pci_= dev`. - let irq =3D unsafe { bindings::pci_irq_vector(self.dev.as_raw(), s= elf.index()) }; + /// Resolves the vector at `index` to the Linux IRQ number that delive= rs it. + /// + /// # Errors + /// + /// - `EINVAL` if `index` is outside the allocation. + /// - The error `pci_irq_vector()` returns if the PCI core has no IRQ = number for `index`. + pub fn vector(&self, index: u32) -> Result> { + if index >=3D self.count.get() { + return Err(EINVAL); + } + + // SAFETY: `self.dev.as_raw()` is a valid pointer to a `struct pci= _dev`. + let irq =3D unsafe { bindings::pci_irq_vector(self.dev.as_raw(), i= ndex) }; if irq < 0 { return Err(crate::error::Error::from_errno(irq)); } - // SAFETY: `irq` is guaranteed to be a valid IRQ number for `&self= `. - Ok(unsafe { IrqRequest::new(self.dev.as_ref(), irq as u32) }) + + // INVARIANT: `pci_irq_vector` returned a Linux IRQ number of `dev= `. + Ok(IrqVector { + dev: self.dev, + irq: irq as u32, + }) } } =20 @@ -128,13 +156,13 @@ impl IrqVectorRegistration { /// Allocate and register IRQ vectors for the given PCI device. /// /// Allocates IRQ vectors and registers them with devres for automatic= cleanup. - /// Returns a range of valid IRQ vectors. + /// Returns a handle to the allocated IRQ vectors. fn register<'a>( dev: &'a Device, min_vecs: u32, max_vecs: u32, irq_types: IrqTypes, - ) -> Result>> { + ) -> Result> { // SAFETY: // - `dev.as_raw()` is guaranteed to be a valid pointer to a `stru= ct pci_dev` // by the type invariant of `Device`. @@ -145,20 +173,19 @@ fn register<'a>( }; =20 to_result(ret)?; - let count =3D ret as u32; =20 - // SAFETY: - // - `pci_alloc_irq_vectors` returns the number of allocated vecto= rs on success. - // - Vectors are 0-based, so valid indices are [0, count-1]. - // - `pci_alloc_irq_vectors` guarantees `count >=3D min_vecs > 0`,= so both `0` and - // `count - 1` are valid IRQ vector indices for `dev`. - let range =3D unsafe { IrqVector::new(dev, 0)..=3DIrqVector::new(d= ev, count - 1) }; + // `pci_alloc_irq_vectors` returns the number of vectors it alloca= ted. + let count =3D NonZero::new(ret as u32).ok_or(EINVAL)?; + + // INVARIANT: `pci_alloc_irq_vectors` allocated `count` vectors fo= r `dev`, numbered + // from 0. + let vectors =3D IrqAllocation { dev, count }; =20 // INVARIANT: The IRQ vector allocation for `dev` above was succes= sful. let irq_vecs =3D Self { dev: dev.into() }; devres::register(dev.as_ref(), irq_vecs, GFP_KERNEL)?; =20 - Ok(range) + Ok(vectors) } } =20 @@ -185,12 +212,8 @@ pub unsafe fn request_irq<'a, T: crate::irq::Handler += 'a>( name: &'static CStr, handler: impl PinInit + 'a, ) -> impl PinInit, Error> + 'a { - pin_init::pin_init_scope(move || { - let request =3D vector.try_into()?; - - // SAFETY: Caller guarantees the Registration will not be leak= ed. - Ok(unsafe { irq::Registration::::new(request, flags, name, = handler) }) - }) + // SAFETY: Caller guarantees the Registration will not be leaked. + unsafe { irq::Registration::::new(vector.into(), flags, name, h= andler) } } =20 /// Returns a [`kernel::irq::ThreadedRegistration`] for the given IRQ = vector. @@ -206,12 +229,8 @@ pub unsafe fn request_threaded_irq<'a, T: crate::irq::= ThreadedHandler + 'a>( name: &'static CStr, handler: impl PinInit + 'a, ) -> impl PinInit, Error> + 'a { - pin_init::pin_init_scope(move || { - let request =3D vector.try_into()?; - - // SAFETY: Caller guarantees the Registration will not be leak= ed. - Ok(unsafe { irq::ThreadedRegistration::::new(request, flags= , name, handler) }) - }) + // SAFETY: Caller guarantees the Registration will not be leaked. + unsafe { irq::ThreadedRegistration::::new(vector.into(), flags,= name, handler) } } =20 /// Allocate IRQ vectors for this PCI device with automatic cleanup. @@ -232,8 +251,7 @@ pub unsafe fn request_threaded_irq<'a, T: crate::irq::T= hreadedHandler + 'a>( /// /// # Returns /// - /// Returns a range of IRQ vectors that were successfully allocated, o= r an error if the - /// allocation fails or cannot meet the minimum requirement. + /// Returns the IRQ vector allocation, or an error if `min_vecs` vecto= rs cannot be allocated. /// /// # Examples /// @@ -248,6 +266,11 @@ pub unsafe fn request_threaded_irq<'a, T: crate::irq::= ThreadedHandler + 'a>( /// .with(pci::IrqType::Msi) /// .with(pci::IrqType::MsiX); /// let vectors =3D dev.alloc_irq_vectors(4, 16, msi_only)?; + /// + /// // Resolve every allocated vector to the IRQ number a handler is r= egistered on. + /// for index in 0..vectors.count().get() { + /// let _vector =3D vectors.vector(index)?; + /// } /// # Ok(()) /// # } /// ``` @@ -256,7 +279,7 @@ pub fn alloc_irq_vectors( min_vecs: u32, max_vecs: u32, irq_types: IrqTypes, - ) -> Result>> { + ) -> Result> { IrqVectorRegistration::register(self, min_vecs, max_vecs, irq_type= s) } } --=20 2.55.0 From nobody Wed Sep 30 12:58:54 2026 Received: from SN4PR0501CU005.outbound.protection.outlook.com (mail-southcentralusazon11011067.outbound.protection.outlook.com [40.93.194.67]) (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 CEFE73815F3 for ; Sat, 8 Aug 2026 03:11:33 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=fail smtp.client-ip=40.93.194.67 ARC-Seal: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1786158695; cv=fail; b=QEpJkqjdY8r+RynlA1nwD0x9xnblUyDkzwSZCrumUhSXwFjVuxIjOokME2NnEN9FHxOTI7H4R8XXwk47aVBsNqT8wqwndNJsq5PqtLZQUbk5vCj3ZA8rKK3aImC/U7npgUB21hI/6qGqty1mam6trrVHCi0sZ16h0R7gApywStg= ARC-Message-Signature: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1786158695; c=relaxed/simple; bh=fpljWYF8QtgdsWnsIS9EeoHhyzskLuChnSgdLi/hZRM=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: Content-Type:MIME-Version; b=sOk2tAmdRZwb6arX3roWtyHG7UKVDCWji7B9/2kzG43OPIJ+2AsHcRYVlUOPCIMtdWA1dQM5CscI0h1SDfnb50bThgwybJsPJS/SEITnM6+1XMk6SlL+9bbg6pXU6N/t0OmhgZ3VBq/Dhv/BHv8+r5FV/bZdyJqPWkNEbVHcNGI= 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=WvpF/xUu; arc=fail smtp.client-ip=40.93.194.67 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="WvpF/xUu" ARC-Seal: i=1; a=rsa-sha256; s=arcselector10001; d=microsoft.com; cv=none; b=LqyInxEszjyUcpmRNjF23Q6ePCPtmvreacXbs/YJqxIFcj6byCQThnUJMrwh4njTTGaBCNWSYCGCyUZaNtwNy86xBzAOrNHXQfCM845NHf88mp5R73MStWPwDM7nmMOWaG1aXxku86YPDABaECdJ9aF+zBQa14+QchqgxQJWyF63J7Q4Y7ye1JX+g59PZqrOJDi9pNDbR5wDTGhiEqstZfCuijTCYqyl/xpb0G15rJ07leIbF+iEesaZF7iHYzFqeHjHpMipp+hrvxVEQTlsfThYHdGqXlfnYtc751f0ZtjdtKOcbRSwHzeAMLRp0RS42V86sbK4mtiYN5tm8hJScw== 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=gvhPW9Owio7hC33Pa+tHDUC0Tg3274OS+AgM875laDg=; b=pvSCCW4+P9Ee7NlqT1hCMmm5B4LxeqWhmnxmiMVPVBxSHOGsahMBXVmCnhQn/zPPpxX/0Z4qMReOqkIWnSGzExjiID9qUXtVqZlbE+jS4aJI5E45D+g6twNxbkchf8PqR+hMjjWorAYFC4LIW/OET+Eu++58jkXwyS9b8eT6/Rs90kA5i2yPXN7EWk1iygHj3V34OUyKUFN0h/tgSHWpNHwiNOV/Sx3/sq7vftV69xDnIlTH+9ZnXVMSM2HEp2BNrjTlVjdpKrU3CYcTzK+NzGnTWqDo/tpqyvSvHRpUr71NcrORA1YkHqeJtWIXHnWOIoZPF2Vpd1fdrDpd12hpBw== 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=gvhPW9Owio7hC33Pa+tHDUC0Tg3274OS+AgM875laDg=; b=WvpF/xUu4MIz20qanIT9V+MuPPAaIBFTlAa3bXNW2YvqkowZEUDgcrjf0BmFYqEmryru2oBJ1OSLlshFojY0AJKlCA1PPUPEJauC/N0tv9AAJ/tdJZZGVXtEHL8uFIZdT10GV/6+qarZjuDxThcqBjeC6lI0RdUbi7wcPTrTuu3lhoYuiHyUHNVVFy3uR5XO8WxrPb0xIt1dqqpO6Dco6LiArzgwlk2N2xvKUQHIESNJ3w62kFzlcfTdVBP2ylz6psAGLmJXoufuR7TW9jAcqtrMI6SXMtRbN205P4D4r/Hr8AgbpMacLroizsbUENcuwuwcPpbo5EJtZ9Mn6+nhVw== 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 CH2PR12MB4198.namprd12.prod.outlook.com (2603:10b6:610:7e::23) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.21.292.21; Sat, 8 Aug 2026 03:11:25 +0000 Received: from DM3PR12MB9416.namprd12.prod.outlook.com ([fe80::8cdd:504c:7d2a:59c8]) by DM3PR12MB9416.namprd12.prod.outlook.com ([fe80::8cdd:504c:7d2a:59c8%4]) with mapi id 15.21.0292.022; Sat, 8 Aug 2026 03:11:25 +0000 From: John Hubbard To: Danilo Krummrich , Joel Fernandes , Alexandre Courbot Cc: Timur Tabi , Alistair Popple , Eliot Courtney , Shashank Sharma , 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 03/17] rust: pci: expose the allocated interrupt type Date: Fri, 7 Aug 2026 20:11:05 -0700 Message-ID: <20260808031120.363869-4-jhubbard@nvidia.com> X-Mailer: git-send-email 2.55.0 In-Reply-To: <20260808031120.363869-1-jhubbard@nvidia.com> References: <20260808031120.363869-1-jhubbard@nvidia.com> X-NVConfidentiality: public Content-Transfer-Encoding: quoted-printable X-ClientProxiedBy: SJ2P221CA0009.NAMP221.PROD.OUTLOOK.COM (2603:10b6:a03:5db::13) 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_|CH2PR12MB4198:EE_ X-MS-Office365-Filtering-Correlation-Id: 1754a4e0-3821-4947-e2e6-08def4fabb4e X-MS-Exchange-SenderADCheck: 1 X-MS-Exchange-AntiSpam-Relay: 0 X-Microsoft-Antispam: BCL:0;ARA:13230040|23010399003|366016|376014|1800799024|7416014|10067099003|6133799003|56012099006|11063799006|18002099003|22082099003; X-Microsoft-Antispam-Message-Info: jxzxDpwZnFH9lqao9hrIJ3efgsiH5WOhGqH6KnOrgbE4VvTpW9lMDuoBvaPtl0U12i1F1XQ536COsy0ewnzgCAy7i8HEUWMGaDSi0goPoRbxSl5UtPCzJo9lmEammrPzlPPqH6K50EN4fMgG6opagSFHch779LG/dv0YvLIJq4L19tI2BjZsF64oNj203itHNtRoL5Xy0DOjMdFpYoGCSUcr+QuuTGQ/1sQFaGvXZPEqZdb8pdXg3/8CFWhR000TX/S+2sgoBL386mqy97RIYmzeFsnDogxpfuQXEh4EDsE0FlmMDwH/2gxHUQKnNp7cnAGEXZs0166ugA1d1nswPL3LMpdjdMIZMvp2X2rCwAbrAsyV6yv1GrX2FEEQ9+mvnA1ygXxASCnLukTmbVSo70sJvnSYNzzrUljnNPNfcx9r5kTB/9PodMMRXerGDG/A0kJxLfT25Lhr15sefe0rHnCbKor26vvC2agQjudeuwOCmtziUBcK0gtsJ+9z4iYKkZDQpPpPNkoP0i9Zre+cAmjG9hdtv43GtkK8L+t0ZqnvMaUdsrqqQfzultXoQNCH9nmTgsYVc6xHVYHIpfdpUTchkJAA3hi278oaOiWL86wCTbjoi9Dcv7f7iLmOmqfEDVJuOeHliqxgWkkhv9BGnUkxw4gId4ydFV9GmbuUoRM= 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)(23010399003)(366016)(376014)(1800799024)(7416014)(10067099003)(6133799003)(56012099006)(11063799006)(18002099003)(22082099003);DIR:OUT;SFP:1101; X-MS-Exchange-AntiSpam-MessageData-ChunkCount: 1 X-MS-Exchange-AntiSpam-MessageData-0: =?us-ascii?Q?38aYkC/uzdczRuIhkWjxYagt74EDJSrxSGBixlTnjq58lv40XggetCeMY4mO?= =?us-ascii?Q?NomPf1S3suxNPMKCiU0TakCdayPeEPYGnq5epOQragKshIQe2/iK4st2LY8U?= =?us-ascii?Q?xUoZVrY3WzpRQtH4Qqw5N/Cn+nEKN2kWqGMjIjfZ5CZtgsQTdTOwby+3guFW?= =?us-ascii?Q?DgorcQXrLokMTUGvWsA0GdU5r8hNcdUfcn0YsMa64RjvC6+ss9byS1+YmNa1?= =?us-ascii?Q?3Olh8fbGzzGpkdedb9ZnMK70CxBWYlYoSFElLkRVfI0uFEgC5ywA/7BVILZ4?= =?us-ascii?Q?eD0BxyU98rNTZF/WbagNiIY8LrqO+w7/2HdOGBEmlj8jVLEd7r1vP1JPn7pz?= =?us-ascii?Q?JrsE69AKJ1vvap+piTHC6dp4ZXoRhqPEwwlT2wSCAxz2A8qxy30zNiSckU9u?= =?us-ascii?Q?an8GB0lRmg8yrbxQlMAr8R2B99c4fiDiD6Mdu9O3sUcIeyUBXrIxfwxAtQ+u?= =?us-ascii?Q?Tb3XYkLqahCoizgRHF6JYE4yQHYk8LV9xGdy5pSB5sSqGtiHtyhksECtFuIZ?= =?us-ascii?Q?NRVOXu3FcOS4x3+tXTnFRiiEslzQkpauCMT+azytIwrmMa9E3vDfLocfympg?= =?us-ascii?Q?ZnYGXMuGKo6z++DzsoNDONg4ypy7ePrXvAxEGNFiww5UwCBl7KB7rR9N7ahP?= =?us-ascii?Q?8mLL11rpFz3pDUK/ISFBj9ehaf5R0M44Ko9zktvJORJoK7+eUtkmznBYDXkA?= =?us-ascii?Q?HoX7oTNXYrDA/qLt7MMwNAuQ1XDJzSX1/zIb7owNJB1wVmOon+IqpU163fRs?= =?us-ascii?Q?Sbh6vMtaSe4PtaOGs0TL1q9L220X0K1HTR6XgIJoOxOEc3BgjLui+LgECtm0?= =?us-ascii?Q?8lz4e8sa3V+UzDST4vvw3gi+s/p70TuuArv1/DBCQRynjzLNLipXd6MXcQdN?= =?us-ascii?Q?ZzCPNQpi3SYrMsoC33X8K8z1UGgXs5CrmyPQHwnP//aFKMXd3tNMl5cBwgOa?= =?us-ascii?Q?vaAKp7/vXeivv2ykpxwB74I4oS4ubEZNqYXhFkzY4E23rDTPSWmYauf6FYzC?= =?us-ascii?Q?DzNIfpx/WnFq9IufIs9mIdJHUy4chm2Vkm8TbgDyPApxCW6r2nDO7cTTalow?= =?us-ascii?Q?eNsj5Bi++lFL2UYzicwahp+zfiI/yc/oAncC7F26AkDOK2qpse/spSkdwK9P?= =?us-ascii?Q?HQYIS4QvtvTf6QWRP4qSe171Z1yOgHZ7jSJBpM9iP+FpIx8g/gcbIJsRKdr3?= =?us-ascii?Q?iHQMxkuLKG75EyClaoCY42mLq9OHwWUcfMJYTmGUr2KZKlT94mJ88W5UO5EQ?= =?us-ascii?Q?mM9LmOJVpRJfbDN0+YcK1YZVWt481W9EhmV9BWasYrhV+tntkeuKwMWYkmSe?= =?us-ascii?Q?P7o9WRY3MIMEXRMTkn1aa9ZN52sk1VwQMT0ESPqfYeBQKsU9b76P+DCAsewk?= =?us-ascii?Q?Ih4lwN+O06oQptmOLr8bjMJCQFuVhOM31WuutHF64CQJ/gVgughBlpHxldMZ?= =?us-ascii?Q?CRgZBn/EaIhNHBQf2XNs3oWOkJO5H7XgmVGbJC4l1rlySg3gPCWS0WxSU8RJ?= =?us-ascii?Q?ZkVS1+uJ40FEolTIH6YWgbkjNRa9z0p3B/QqHgj8aCXLcLXbkXOAmTZtYgSl?= =?us-ascii?Q?gIbkbSEGUfYIBTS+RQGFRGupbthV/w7/10dhtWlbP+3CITgvDvxR9uCXUw5d?= =?us-ascii?Q?oTbY9WYgPymj+wRIfU+sR6/LwzshmX0yUuMQpUBi6/9TQyFsVeo6Oe3PTKgQ?= =?us-ascii?Q?COXZk4vJFA+maT2LY++6T55dZpPhFMRF523NxeT1LQkjNcpup4ryR6a8e98n?= =?us-ascii?Q?Gbkjc4JiOg=3D=3D?= X-OriginatorOrg: Nvidia.com X-MS-Exchange-CrossTenant-Network-Message-Id: 1754a4e0-3821-4947-e2e6-08def4fabb4e X-MS-Exchange-CrossTenant-AuthSource: DM3PR12MB9416.namprd12.prod.outlook.com X-MS-Exchange-CrossTenant-AuthAs: Internal X-MS-Exchange-CrossTenant-OriginalArrivalTime: 08 Aug 2026 03:11:25.6008 (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: GtNzy2JH07wz8oQPbayPc3iMbpym4Ce8RSTxM8C9zC8meBOKFD6xXuzRfucEdDNQzcACrBOI+py6vl+ldVithA== X-MS-Exchange-Transport-CrossTenantHeadersStamped: CH2PR12MB4198 Content-Type: text/plain; charset="utf-8" A PCI driver can accept INTx, MSI, or MSI-X, and how it acknowledges an interrupt can depend on which one the PCI core picks. The Rust abstraction never reported the choice, so a driver had to assume, and of course a wrong assumption would lead to a broken interrupt delivery setup. Report the type that the PCI core selected. Assisted-by: Cursor:claude-opus-5 Signed-off-by: John Hubbard --- rust/helpers/pci.c | 11 +++++++++++ rust/kernel/pci/irq.rs | 30 ++++++++++++++++++++++++++---- 2 files changed, 37 insertions(+), 4 deletions(-) diff --git a/rust/helpers/pci.c b/rust/helpers/pci.c index 4ebf256dff23..87ccd0cec69f 100644 --- a/rust/helpers/pci.c +++ b/rust/helpers/pci.c @@ -24,6 +24,17 @@ __rust_helper bool rust_helper_dev_is_pci(const struct d= evice *dev) return dev_is_pci(dev); } =20 +__rust_helper unsigned int rust_helper_pci_irq_type(struct pci_dev *pdev) +{ + if (pdev->msix_enabled) + return PCI_IRQ_MSIX; + + if (pdev->msi_enabled) + return PCI_IRQ_MSI; + + return PCI_IRQ_INTX; +} + #ifndef CONFIG_PCI_IOV __rust_helper unsigned int rust_helper_pci_sriov_get_totalvfs(struct pci_dev *pdev) diff --git a/rust/kernel/pci/irq.rs b/rust/kernel/pci/irq.rs index 66723a43491b..10c728cd139e 100644 --- a/rust/kernel/pci/irq.rs +++ b/rust/kernel/pci/irq.rs @@ -100,11 +100,12 @@ fn from(vector: IrqVector<'a>) -> Self { /// /// # Invariants /// -/// `dev` has an allocation of `count` interrupt vectors. +/// `dev` has an allocation of `count` interrupt vectors of type `irq_type= `. #[derive(Clone, Copy)] pub struct IrqAllocation<'a> { dev: &'a Device, count: NonZero, + irq_type: IrqType, } =20 impl<'a> IrqAllocation<'a> { @@ -115,6 +116,15 @@ pub fn count(&self) -> NonZero { self.count } =20 + /// Returns the interrupt type the PCI core selected. + /// + /// [`Device::alloc_irq_vectors`] takes a set of acceptable types and = picks one of them, so a + /// driver whose behavior depends on the type asks for it here rather = than assuming. Every + /// vector of the allocation has this type. + pub fn irq_type(&self) -> IrqType { + self.irq_type + } + /// Resolves the vector at `index` to the Linux IRQ number that delive= rs it. /// /// # Errors @@ -177,9 +187,21 @@ fn register<'a>( // `pci_alloc_irq_vectors` returns the number of vectors it alloca= ted. let count =3D NonZero::new(ret as u32).ok_or(EINVAL)?; =20 - // INVARIANT: `pci_alloc_irq_vectors` allocated `count` vectors fo= r `dev`, numbered - // from 0. - let vectors =3D IrqAllocation { dev, count }; + // SAFETY: `dev.as_raw()` is a valid pointer to a `struct pci_dev`. + let irq_type =3D match unsafe { bindings::pci_irq_type(dev.as_raw(= )) } { + bindings::PCI_IRQ_MSIX =3D> IrqType::MsiX, + bindings::PCI_IRQ_MSI =3D> IrqType::Msi, + // The helper returns `PCI_IRQ_INTX` when neither MSI nor MSI-= X is enabled. + _ =3D> IrqType::Intx, + }; + + // INVARIANT: `pci_alloc_irq_vectors` allocated `count` vectors of= `irq_type` for `dev`, + // numbered from 0. + let vectors =3D IrqAllocation { + dev, + count, + irq_type, + }; =20 // INVARIANT: The IRQ vector allocation for `dev` above was succes= sful. let irq_vecs =3D Self { dev: dev.into() }; --=20 2.55.0 From nobody Wed Sep 30 12:58:54 2026 Received: from SN4PR0501CU005.outbound.protection.outlook.com (mail-southcentralusazon11011067.outbound.protection.outlook.com [40.93.194.67]) (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 9E676382295 for ; Sat, 8 Aug 2026 03:11:35 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=fail smtp.client-ip=40.93.194.67 ARC-Seal: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1786158697; cv=fail; b=HJ4CyD3u6WtSmIGlRFXuN6BE8uiarAIwkhjS9n0PVGizqwjCXzCNDDi07MP3bUV2jzhYQ0RoGCy1CnHAgkwpy4AIt5gbOkSsTq3FkSXt4rF7TQQgeg/1bJ7MxierbK55u1reabG7J1wNqWa1Uu0tDPhEvFVRasZIBnWvxXVmwx8= ARC-Message-Signature: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1786158697; c=relaxed/simple; bh=S4s1g482o2JbyMPq7AWP/AYvOIzSFD+6Zzrqmiq1lkQ=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: Content-Type:MIME-Version; b=YSZH7m+o+DpWKdUZiyE9QFFE8NVPSV7i8vJtbzOrb0JRTMe6681IOfPR0aLT2Nk47tV1PZWZN3SCz4ruc3BZQMMFHXDOtJPlt7UOP03p53vxGWw+bFrExm2ARSMV0XeRNdHf5sxPWrhYuFg2UDkj3pk2y8OH2MXOFhcqnWCj+5c= 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=RvQGaMwX; arc=fail smtp.client-ip=40.93.194.67 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="RvQGaMwX" ARC-Seal: i=1; a=rsa-sha256; s=arcselector10001; d=microsoft.com; cv=none; b=TJ4s8LVJG/cIHe5BdT8zjDvGJqJNkxDHJL0bko55y49LZ0YoMovfbnlBbUcTKpPOhpeenVDxCDLjqfd4V3aYdGx2iAD5PYdEYKE9zHrgaeB6mFJZNrGgWqvZmB1elgXohe+4LwGQE2FutvQ3zf8/TrTYxYIRd7hUvyQKP7TCE4vH2sBe/Id4N30Jy6sQPNitx0WuYiV1ERvEUuINxbJCQsv7YfglwopDtVm7YDzQlREYEeya6+NF5DUamPMpA+MLDyYNCLbs6WYYRIuxlh5QF6KDslwN4uoRYnri6N6k58GV9hgkZre0BGYB19etDvjpE9Vu+Dhi0Kf5RCuogVjdNQ== 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=1hniMuy6167k+jpTK1ZsKcQASQ4K9jlIEUZm4WnkAmA=; b=PcTOOvjRlOUjTOjLoJ8fz3T+GHSUHzGfh+u9Zq59VYtCFPltJfNXD9/sc6sEA3kAVbJZ9kWDWJzg3snuaJS5HtPkQIMPJz6coZ7UA54RTwugILJRfp4vTHCKNhTxQnWXSQp4YhPUt5vQe7tPmscKi8OgS6SCU+8rr25b3a5BjBoKqgFXRjGxOQYpKLL4Iu/uEqhvkauWD9V6sHrD8GFSoARijAOy40MditjuKykGA3fonr/sy9BTF9A95Hi6JX+sONE9K60LWuMQVmAHEMqd0rL7PuXxMX18pBCFXMzMru9AdwLXthT1PyaGKWEivpTrsd4HgPfRjrOK90ifI9u5LA== 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=1hniMuy6167k+jpTK1ZsKcQASQ4K9jlIEUZm4WnkAmA=; b=RvQGaMwXU4ZteM8IZOWmCPKiin4txEJ5wAoFLT13+hgZX6rGULg1ZR7V+JmEYfwl3f9IFYepQ6jbRtwcwVLEUvxmnn5wb6dMYZWooZkbXZAt990BJJJXjbnXK99YDah22JJZpxhy+Sj/6scyPRHOdG3bN5oaAwPaIXr7oSlQ5B8mXTGOdGKHfPzQtOyMUMTMBAutFTZcylqAotfuzmH47VoCsMVqJxwFAu912KjezmiKDaZ1fecNzBm8q5z6nwfjFLdThYLYg+coXcjOgbBJgV0D4/8zfu7Yh0iHgyEnnq6TQSynnb94CEwJ9QV0ZF0FFlynepTG/xix1zW8Oag8LA== 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 CH2PR12MB4198.namprd12.prod.outlook.com (2603:10b6:610:7e::23) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.21.292.21; Sat, 8 Aug 2026 03:11:26 +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.0292.022; Sat, 8 Aug 2026 03:11:26 +0000 From: John Hubbard To: Danilo Krummrich , Joel Fernandes , Alexandre Courbot Cc: Timur Tabi , Alistair Popple , Eliot Courtney , Shashank Sharma , 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 04/17] gpu: nova-core: allocate PCI MSI vector during probe Date: Fri, 7 Aug 2026 20:11:06 -0700 Message-ID: <20260808031120.363869-5-jhubbard@nvidia.com> X-Mailer: git-send-email 2.55.0 In-Reply-To: <20260808031120.363869-1-jhubbard@nvidia.com> References: <20260808031120.363869-1-jhubbard@nvidia.com> X-NVConfidentiality: public Content-Transfer-Encoding: quoted-printable X-ClientProxiedBy: BY3PR05CA0047.namprd05.prod.outlook.com (2603:10b6:a03:39b::22) To DM3PR12MB9416.namprd12.prod.outlook.com (2603:10b6:0:4b::8) Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-MS-PublicTrafficType: Email X-MS-TrafficTypeDiagnostic: DM3PR12MB9416:EE_|CH2PR12MB4198:EE_ X-MS-Office365-Filtering-Correlation-Id: d9d84f80-4fe0-471c-41c5-08def4fabc02 X-MS-Exchange-SenderADCheck: 1 X-MS-Exchange-AntiSpam-Relay: 0 X-Microsoft-Antispam: BCL:0;ARA:13230040|23010399003|366016|376014|1800799024|7416014|10067099003|56012099006|11063799006|18002099003|22082099003; X-Microsoft-Antispam-Message-Info: Ntmggekv6K0Ndm4C9FG0zhJFz29yXbwVr/EylsyU9rngo3X+od+unE98+b5ExrdmbDJPYetmtXGxk1ks4D0qlHYeHq34SqAIg86sqqGrcysE7p+8za+ygoFk/DRk/kco8i/5bIOr8EMyD/iRcz4Fy2Wtvgc+mX4tCgBxVs59Qwnxzq41+V1rVnR9PqQlPGE9AWG8CfcAW6WZLjZ2hQNHwxINyiXJ+JJogG6kaWZmzClk54OXhQO4iBPLjkfsn2LKa2oulFEAZCc62Ky/iBAfcWyxxqwof/jDikD8lJFQeFxF5zo0KUp+xKLzGhhx9O4H71+Z/1FeDui3ciUeUHEVbYhB5DaUByH8nh6m/9egwaNWUR00ml8TfTsbZCwumGRaNTMqsAfMDF6Vx5KjOvEMpqJBb1VVcSimuR1tv6H7UWB/4nTjlv5hoFW+l5r/lYhMVyE+zYYFb9zvQBr0K8EOuVlc98lstEWb0q1NuW0R3zaRT7cdWgJ/YPHziHShLhSBcrZt5X0OjLlpS1EayhQ6qjR5UbRt+4hQL0ZB0EPoyJUdEwEIakeHIS5WwvNxYAbYW+w2t2cczrQ8h2Pnrs8L8G62rCjJpvjyF1sK8A+2xkBvlhVqwIpwwQYruIYvwjV+2As0UqbyhDyrxZr++aBjpefY1wNvOT6C6r3Qfqrsa2g= 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)(23010399003)(366016)(376014)(1800799024)(7416014)(10067099003)(56012099006)(11063799006)(18002099003)(22082099003);DIR:OUT;SFP:1101; X-MS-Exchange-AntiSpam-MessageData-ChunkCount: 1 X-MS-Exchange-AntiSpam-MessageData-0: =?us-ascii?Q?kMirjouKp8tGRVBaut47sXBNNNWbsW4emK6m+x5uw8TCxsWdQZpBEHhpCKYH?= =?us-ascii?Q?uTV0ui3V4I7n3lYJOgD6U2G1KfUHLEOJ6tx4L8CvBzikLg84GT+nMhh1CM3S?= =?us-ascii?Q?3an2N0dBIZvAiBwKu9OKC3hZnBnU+LUZoIaXkldQEyAr8HDYWnw+7PGFXMba?= =?us-ascii?Q?1p00sy7c3DFZpx/NCdK+6Vu5vQ4kRFU2Zfrk+9FkVVvuSRNDIv7noqnzOol+?= =?us-ascii?Q?gBCoy5KH9T4NxiOmrguEZBp9QL2Q/RwYE8weGUo3Po5jPUZz9k5QyPnOP5XW?= =?us-ascii?Q?xardJ/tGfAxeaHjV/wiUr7GOIZBwXpB4Gl6zfn7TAx/b+Qas3uRfHK/4LLSD?= =?us-ascii?Q?kB5nfnPO/HmJTKB1Rfq5UtZvwewhEixD9EaEr/OMvHTbq4i1VA/wr9xUvYH6?= =?us-ascii?Q?DAKafKDrFostsKTDHXWWEYwRRShx5cUl0i2G1xebQGcQRDPkaQj/z7M7KXwE?= =?us-ascii?Q?3YTVFf2lwsCphXiXUap3lSAY+3dFZpAdXUnvvPufE4ohcfQ3+eSPK0qW4Sg1?= =?us-ascii?Q?OvIldRO6p8EETIIta2s0xfA/7LslW7kCxmuzZ4WGLF+m/T46F8V5vaapFh1R?= =?us-ascii?Q?P5BvGdrK94ZjSii2O+b4qsTP5gCTIKptCDmI+MKQLwTo/T6NfpJ8kL/p9XER?= =?us-ascii?Q?h9EuYSozTX8G4U5xyit2YwLSZB0DFFitDwt8kjy7qEBha4BaaFFAbHrPNzjn?= =?us-ascii?Q?rtu7nNpcxLfE4u9WQoY9O1VDTnK5i1I9c4V7IMmvE9hTAI8oZ0i2HPQEtyyv?= =?us-ascii?Q?6HI3T8Z4xMOZelVi6tn6XZOwKwZb5t3G0HeN9J/IBMSRKsVRQ8PMf0rMd0Zx?= =?us-ascii?Q?UBxmxxM2s9815WXUJji4sgKYpdSYDbctZtvPANLW6En2a+pl3a1ozjU5n/fj?= =?us-ascii?Q?JOEI0hKxFTnwnIGurAlc2kS927O8Wrkf3SQTIGXAHvqeEPiNahvB3oyCk4MP?= =?us-ascii?Q?t5D/BdXnDq5UAphrMGPoGjlZh8IR63o/c73L9aO3JaLcfL+h3Vu1ECnkfKUS?= =?us-ascii?Q?u5n21zWk+vTcd6zopT7AvVPMk7N1jJlqgO3TFWE83anDbQTJv1u+6BBPRhW8?= =?us-ascii?Q?cPQoLiKhEt6kQJyK3oEbZ+4XiALFkvdvIK3vVSbK3n+pwtHDyo6NLo0thgSI?= =?us-ascii?Q?95iO02P5QVJc6i+uHCi+nzaTQl1XB7P4bFWgrviFI7LArBYGawCwVv1UJunU?= =?us-ascii?Q?qrCZJ7zVGZCe0+SnlaKh3JXgMhPbTrghRAH//3t6BWPUkGOHRPwNInlnkM5w?= =?us-ascii?Q?Veh7inj0liy21+rxgn2H3MdKKayR8rYlXKse7zQ9mSFZxKfe1NgOVSc0GU4d?= =?us-ascii?Q?eM17oeAnI9loHsG30g1YQhQyZviF8jfjqUNeEwJBtkdGPawUeVuKAMuKEH34?= =?us-ascii?Q?0BZD6XpKbrItBWbBIFfoxaUkVQUndot+HA9sKSH17gfjcxfThamhHb5HIPlD?= =?us-ascii?Q?UTHUrnex0MbPD35Z2ASCoZMLIvnLeTPBFdH9asQs/bY9ZbHNyJDOSZHvkPoO?= =?us-ascii?Q?yLMLM3eEl7bCl1pClAvEpMJc8ssRCZ4VfZTwyPPB+XZRyVq34YG1QkoZsaTZ?= =?us-ascii?Q?V+NN9tuQuSBbrF/f8pFypKpiiDfhxO9oGw6QE4jnmOBnIUvDj8Tk+MQR7QAy?= =?us-ascii?Q?mbR+IUDLcA+jxkHRCkLnf4x/D/NMBvSbP3WBfhvm4YBQ6Ty31Fm/F2ISqSjM?= =?us-ascii?Q?Dm4RHUUbRDwAML7dsMM4lgFGVD+SDEr5R61d7MYwmKT3EYKMEpH+DI8JDpTc?= =?us-ascii?Q?1nuiee+5zw=3D=3D?= X-OriginatorOrg: Nvidia.com X-MS-Exchange-CrossTenant-Network-Message-Id: d9d84f80-4fe0-471c-41c5-08def4fabc02 X-MS-Exchange-CrossTenant-AuthSource: DM3PR12MB9416.namprd12.prod.outlook.com X-MS-Exchange-CrossTenant-AuthAs: Internal X-MS-Exchange-CrossTenant-OriginalArrivalTime: 08 Aug 2026 03:11:26.8020 (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: ErVaTGKje1kwVUt7ZnSkHxv8hhaJNzebuvUdXu+AaeqxhENEVfZAP6U4fBf5SZlzPP9rDn5ImxPNifhMg0Oc5Q== X-MS-Exchange-Transport-CrossTenantHeadersStamped: CH2PR12MB4198 Content-Type: text/plain; charset="utf-8" From: Joel Fernandes Allocate a single PCI MSI interrupt vector in the probe path. Try MSI/MSI-X first. If that fails (possible in broken VFIO setups), fall back to INTx with a dev_warn so the issue is visible in dmesg. The allocation is devres-managed and automatically freed on unbind. Reviewed-by: Will Pierce Signed-off-by: Joel Fernandes Signed-off-by: John Hubbard --- drivers/gpu/nova-core/gpu.rs | 6 ++++++ drivers/gpu/nova-core/irq.rs | 26 ++++++++++++++++++++++++++ drivers/gpu/nova-core/nova_core.rs | 1 + 3 files changed, 33 insertions(+) create mode 100644 drivers/gpu/nova-core/irq.rs diff --git a/drivers/gpu/nova-core/gpu.rs b/drivers/gpu/nova-core/gpu.rs index 42a4cd7971fa..5efeba056f1b 100644 --- a/drivers/gpu/nova-core/gpu.rs +++ b/drivers/gpu/nova-core/gpu.rs @@ -29,6 +29,7 @@ Gsp, GspBootContext, // }, + irq, regs, vgpu::VgpuManager, // }; @@ -386,6 +387,11 @@ pub(crate) fn new( })?, }), =20 + // Allocate a PCI interrupt vector. + _: { + let _irq_vector =3D irq::alloc_vector(pdev)?; + }, + 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/irq.rs b/drivers/gpu/nova-core/irq.rs new file mode 100644 index 000000000000..48900c734cb6 --- /dev/null +++ b/drivers/gpu/nova-core/irq.rs @@ -0,0 +1,26 @@ +// SPDX-License-Identifier: GPL-2.0 +// SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIA= TES. All rights reserved. + +use kernel::{ + device::Bound, + pci::{ + self, + IrqType, + IrqTypes, // + }, + prelude::*, +}; + +pub(crate) fn alloc_vector(pdev: &pci::Device) -> Result> { + let msi_types =3D IrqTypes::default().with(IrqType::Msi).with(IrqType:= :MsiX); + + let irq_vectors =3D match pdev.alloc_irq_vectors(1, 1, msi_types) { + Ok(vecs) =3D> vecs, + Err(_) =3D> { + dev_warn!(pdev.as_ref(), "MSI not available, falling back to I= NTx\n"); + pdev.alloc_irq_vectors(1, 1, IrqTypes::default().with(IrqType:= :Intx))? + } + }; + + irq_vectors.vector(0) +} diff --git a/drivers/gpu/nova-core/nova_core.rs b/drivers/gpu/nova-core/nov= a_core.rs index 35a8b1214b0e..68b5abfe494d 100644 --- a/drivers/gpu/nova-core/nova_core.rs +++ b/drivers/gpu/nova-core/nova_core.rs @@ -17,6 +17,7 @@ mod fsp; mod gpu; mod gsp; +mod irq; mod mctp; #[macro_use] mod num; --=20 2.55.0 From nobody Wed Sep 30 12:58:54 2026 Received: from SN4PR0501CU005.outbound.protection.outlook.com (mail-southcentralusazon11011067.outbound.protection.outlook.com [40.93.194.67]) (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 4FE47382383 for ; Sat, 8 Aug 2026 03:11:37 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=fail smtp.client-ip=40.93.194.67 ARC-Seal: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1786158698; cv=fail; b=unulWCqga2Aa36jFRoavebBhiVjbo0/Uzdm7CkbhP1eNpHN3rYgD8So7ryiGAX431ovo+45ZllQhdD+Xf2PbnvAnk93sXuhDAfqxbpYU1Dcji5KgIEUCjEBnmcG1AGXBvNNdY7I5M/c5cZSiKJETKyH25YYoWzNN74XXOPXVO7I= ARC-Message-Signature: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1786158698; c=relaxed/simple; bh=u9/aNXzBFCNoOvVrnR5pNHyp6udmABnJSoLqqF+0ozM=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: Content-Type:MIME-Version; b=Sy54H9+yTA220cfJ9bNX2FH7Kmcy5EeTyWBNMsJ+ukH+lfiiMz7Edr3IJRLOpufKQancLb9wIXY+tvEy/+p8DXGR3gzoBPz83qPp5Oi/ienHJ+SPdPqRuJt33gtwhuKeUhucir7EjxkpTIFNpG0dpcnlF/2F2yedT0Wbs3F1r20= 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=JTP6XvF0; arc=fail smtp.client-ip=40.93.194.67 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="JTP6XvF0" ARC-Seal: i=1; a=rsa-sha256; s=arcselector10001; d=microsoft.com; cv=none; b=fqN6f30xMcQZJBQPsuyy0AD+c8n9KA+LjYj6jBqfvmUy7Tu6DYI3nl68aZD1oxs3RMjGKo2AACh/hGVhtIKn5nRQNweZMzrFXK2rLh0Y5R82pJYxcTjbxrzatPQ+tBkba1wjG0IwqPDutR5l38uC3YknEtY2g5e7lPwJIvDi7RMZa6s0TFT3EVU9D5TEuVWpKGceh5zgNhek68NUjc1HdEwCWKH5x/gSmivYmCq3S5QkvdvjwzOUKwSLgjBSGj5SdEzLR9sVPoco3QpB0msSe1lpzkt8sa9Cg3vbS1O8OT9Ogr0+Xa/emI6RXOzyaUbztrYHmReWzSZBLFtFwPuE+w== 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=DEIIErvbUiC7A9rylDVf2dYikUaWNY3AY1VgeydB62A=; b=jSGD7rDEO66HwszQSkRkprFclgo06ovo1IHeu7VUWz2qTSSs7FRHWFicIT51l+JYBJzig+mmQqdeS/Z7On8yGWhclnW7PPA+cGIsHGc6lNvAFClPP5gNaDJaB5A57QLTE2zYBdxVNoCQ30SEI2i7xMXryVHClrqOB2nLLUtFquEVYgU4x7eqTWwnUG7rwIN1n370fcnksfdCutBVcmUnhnH+E332r0UONFsdfbfDEMl1CU7IgZwwrInLALXXhm0oKbCXAcNlGA9JKAE5alQtO8dmh2caIdnmo0x1130WBqMZJPBiLtJ78Nb4NnmdUOrXarB6TtBqibc/4lokOTdkHA== 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=DEIIErvbUiC7A9rylDVf2dYikUaWNY3AY1VgeydB62A=; b=JTP6XvF01niVTDdI1K5qNY7rzxMG7syUdoXLQV4PhN+cbm1xF/u9kNdPEEEMuvXQrjWiVGFs+VOttrZmcEuBK7l+h1jGe5EvNspdxSgQ5lnf9divtNyfyFsGAJY47XWD1DtVJYgTv89tFWEn84NkoxhBzxStgjv2A4vzrtpPs1H6QTV/goItffPCiJ4Km89EnMXrpUCHvIjXkjZzsc0V5CBREfb4ocHI/Aj60xlpD9nwooG3GriVotbsHZvkVLJmLUd0v2YcS4Ji8L+CKiIwEdKiK/cPdGuwYmGIANtLZi8Rg++gU/NWFumo5DhU8fkSEC/VLzpyjoiB2qJ8dxMGkQ== 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 CH2PR12MB4198.namprd12.prod.outlook.com (2603:10b6:610:7e::23) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.21.292.21; Sat, 8 Aug 2026 03:11:28 +0000 Received: from DM3PR12MB9416.namprd12.prod.outlook.com ([fe80::8cdd:504c:7d2a:59c8]) by DM3PR12MB9416.namprd12.prod.outlook.com ([fe80::8cdd:504c:7d2a:59c8%4]) with mapi id 15.21.0292.022; Sat, 8 Aug 2026 03:11:27 +0000 From: John Hubbard To: Danilo Krummrich , Joel Fernandes , Alexandre Courbot Cc: Timur Tabi , Alistair Popple , Eliot Courtney , Shashank Sharma , 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 05/17] gpu: nova-core: add the GIN CPU interrupt tree and MSI EOI registers Date: Fri, 7 Aug 2026 20:11:07 -0700 Message-ID: <20260808031120.363869-6-jhubbard@nvidia.com> X-Mailer: git-send-email 2.55.0 In-Reply-To: <20260808031120.363869-1-jhubbard@nvidia.com> References: <20260808031120.363869-1-jhubbard@nvidia.com> X-NVConfidentiality: public Content-Transfer-Encoding: quoted-printable X-ClientProxiedBy: SJ0PR13CA0219.namprd13.prod.outlook.com (2603:10b6:a03:2c1::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_|CH2PR12MB4198:EE_ X-MS-Office365-Filtering-Correlation-Id: 19b45592-cd29-4c50-9e8a-08def4fabca6 X-MS-Exchange-SenderADCheck: 1 X-MS-Exchange-AntiSpam-Relay: 0 X-Microsoft-Antispam: BCL:0;ARA:13230040|23010399003|366016|376014|1800799024|7416014|10067099003|6133799003|56012099006|5023799004|11063799006|18002099003|22082099003; X-Microsoft-Antispam-Message-Info: V8ZtmjUKVpBxv3gIwFkxP0hb6j87j6f+DAt+Vn9hQNDxuW+rAIxOb9k2WbY/mSJ6RvjSSI/ZtVbbxDCvlHmMxevGVdb8jAZdH5ZG3R3t8MYDOeWlO8oNjwPrsZ7HMXakIzHgN7SBhzTJuC6dFHIr24XoI9LDTYIeT78DDjJbML8GNjrh4VeT9jQykZWjYyf6zEKt+FOqdoxWo5EbRGqivb6Dbju6Ec0LDTC6Biz8cTiXEhJ32b0cvEA7lekj+vnCtRSfw3q78CxmRzHJtSJvr1kD2sv+pIJcCHnvGdTFkv9n2JcXYiPIVCQ/uTy2mvhq+xO8UoAMQNVA9fe+YpAhpo1QU6KCnPtnwnm1ixODYGp2YnXUjR3uQQbgJWcTUcifzmS+4didUbpddmWL1/Xf/DITYz1VRuWYCTFiAn39XTfQij5vogbgS5oxN3AenEsoiQ5CDrC0kBJOc/x5VYG+0nc9vUTAsH0k6Qf6mjHGa1F85c2r9J6RTL8HcftmtvKAnK0CouZXKZ4qLWpBJp/X0XwlLUO6zYa9V56e9DVXGvlSTu4X0Oc/uembfBho7paBpUeteu9VW9V0YzdKykEPiBGiUe6zK6+9mUdrVFQDpAXmNIvyXLegRFeOd+r47NHxZakW8qxxk/95N/StxIJFOqQ3L2x4M3UV5SWJTh3gxcU= 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)(23010399003)(366016)(376014)(1800799024)(7416014)(10067099003)(6133799003)(56012099006)(5023799004)(11063799006)(18002099003)(22082099003);DIR:OUT;SFP:1101; X-MS-Exchange-AntiSpam-MessageData-ChunkCount: 1 X-MS-Exchange-AntiSpam-MessageData-0: =?us-ascii?Q?aXkCdP6JctiDNu/iT3PlnRjN7p1EsROeZ7A3byavNAbw2FKofLD/bZJLC5BU?= =?us-ascii?Q?uMWTfd0oUr2Rg/WfuoZFg/nfPaaiNmYLfFCmV0HGG/v18l+jsWi13CIc4gSf?= =?us-ascii?Q?RRCwMheO88qvT6tkkOwFHzr1vdShL0b4cvv4WmoFRitXL4XDWErCfAG/RnyC?= =?us-ascii?Q?P2gqISAnF2gGEJ83RcXJAw01CIi47xc72TLYghrzr0nVJ9aHT2lEHGfENvat?= =?us-ascii?Q?SiJoue0Wi/YcNMsS/kxoJePGMANu4XfqCTI+RKobOG0tfA13pXpqie+i/jq4?= =?us-ascii?Q?M3jtpJwj1gMvrb5bfuiJ8iKQ/tjdBDckvKD9MRVIlLwDBZOZGJZJH5qewC0Q?= =?us-ascii?Q?A4SHd9PJ1EXoVErLKYXPAzOlz9dKQTpom1HVHdgfaLLH6RsgDLg5uQS8Jsy+?= =?us-ascii?Q?o0mKfB9kbCUuN5DlBUFwXa31qTdu7JDYFk+KKp7dk+MQCTqty9uA1rSe35LZ?= =?us-ascii?Q?JeQoqD4Gu7e3guG1YC+lI/qei/2ZleqLLfKyRYsp2yaflH++xL1+/X0Ogfm/?= =?us-ascii?Q?udzDZNr+wsJFDRhdJqi0/WhcnVjI2iA4ZDtpgdaSCDGPOGFtYMrVIpvVvkHi?= =?us-ascii?Q?VjACyqyOBcTyfqVR0nn+yEpt818WWaKx9vwVaCnNg3jyU7dOGbS2du4xo4EE?= =?us-ascii?Q?oKTjhQ7gMYG52tZwjppbi6HY/vW0Y2TGHelwxwxyZfbTbqIpxKypieUvcKnt?= =?us-ascii?Q?JuqVcwte0f1c1ZFmpb1DWK5oesYxY9GDbNJjSiQt3d0ZKcERJ98DxdkavYaU?= =?us-ascii?Q?6gZmk6ygeApoWTqCbp1tXY4QATjJHJgKVkxcKOy87hC97wxPyvkAK84U5X9Y?= =?us-ascii?Q?oMXiKK6jLQTFZP908KLLlwfqfV5VGi4E7wybHejkZPdaui/MG4PvhXfdj5C7?= =?us-ascii?Q?oHSe0ki6EjAE23TI60tMWnOS/fWKqZkm0HJ0OKiqN2MRnZffmcZs/lF+DUK0?= =?us-ascii?Q?GADHgdn45PQCdJTm+ggQWlvnTyBQ7s7BudkVwEvUl7UDqtptWArELrGeoecE?= =?us-ascii?Q?f9EV1dqXh8TbfBYlNqpNWZetIU4t6m+QErMc08ZJLAQ2ELrb57c46ptvG86T?= =?us-ascii?Q?KoGAAisc0sb0nIECitejRaB+EzlClTyyhN9FCsC5pMwzJxBqmqHP8SduoUGI?= =?us-ascii?Q?I1B75lsWleuUrRD5dmAnrkT9A0O4AT05NGeN8x2PocF62ZmwaxKDDTX8IrCp?= =?us-ascii?Q?ET2yj0pGdb98JOvVMzZKScoBexdzZpo/V6OkxsbKnC4Qv1iSw9tZLKsEaStf?= =?us-ascii?Q?hy7iM+fEAwsN9BNhyeapu3jqwMEXRVXFPeq32KrYYYnrq2y1zKbMAbOn1n6R?= =?us-ascii?Q?Igr0gt/nfTvC1gybMMwW2DWLVA3oXl4vGOb/sMk7nIyFoROkPLfQDXc5fjE5?= =?us-ascii?Q?5SYQ3XEKHvqVNKTtzG5T7NtNgZUYjOxLqfV5/oepkYSOasvEOtLqhflD9AFq?= =?us-ascii?Q?SzFjCTJ16K7u6cJ5kLvU9u9Ka27RtigODOILmiv1N/0JnVpzghSAXUZGrakU?= =?us-ascii?Q?KzbWwDwqK8kGrdLZfgJ6qrtbeReD4zO7kXKQNVst4sWLY52DkiGU8QUczA++?= =?us-ascii?Q?9Zg3uum4oUMz6X9UaDwQ7k0q+C6q9Vf74w6Qln0iPWCTK+CyyGqhNhHLlmZd?= =?us-ascii?Q?NJjCKgQq9gURpogxxMAxVwEO7gqL2an8vGlGmBDILU2t2qWYN8ZlQVix3FSN?= =?us-ascii?Q?oZGN8bM9vpGLT42csIIImOFSVA8AaSwlP5F1+aibUAxxYoitPORn+K3uiToM?= =?us-ascii?Q?feuD0SLCbQ=3D=3D?= X-OriginatorOrg: Nvidia.com X-MS-Exchange-CrossTenant-Network-Message-Id: 19b45592-cd29-4c50-9e8a-08def4fabca6 X-MS-Exchange-CrossTenant-AuthSource: DM3PR12MB9416.namprd12.prod.outlook.com X-MS-Exchange-CrossTenant-AuthAs: Internal X-MS-Exchange-CrossTenant-OriginalArrivalTime: 08 Aug 2026 03:11:27.8944 (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: 0JT3u8kgRZkXjmHX2z29OZIDsKkD9khhmgfhtKsdSzrGmJc6J+81DVQmNvD9rjDorpPgz5OseAVDRHX/ZDILDg== X-MS-Exchange-Transport-CrossTenantHeadersStamped: CH2PR12MB4198 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. 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/regs.rs | 71 +++++++++++++++++++++++++++++++++++ 1 file changed, 71 insertions(+) diff --git a/drivers/gpu/nova-core/regs.rs b/drivers/gpu/nova-core/regs.rs index caeef4d85874..1db92d36c5ac 100644 --- a/drivers/gpu/nova-core/regs.rs +++ b/drivers/gpu/nova-core/regs.rs @@ -456,6 +456,64 @@ pub(crate) fn mem_scrubbing_done(self) -> bool { } } =20 +// 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(crate) NV_VIRTUAL_FUNCTION_PRIV_CPU_INTR_LEAF(u32)[16] @ 0x00b8100= 0 {} + + /// 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(crate) NV_VIRTUAL_FUNCTION_PRIV_CPU_INTR_LEAF_EN_SET(u32)[16] @ 0x= 00b81200 {} + + /// 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(crate) NV_VIRTUAL_FUNCTION_PRIV_CPU_INTR_LEAF_EN_CLEAR(u32)[16] @ = 0x00b81400 {} + + /// 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(crate) NV_VIRTUAL_FUNCTION_PRIV_CPU_INTR_TOP_EN_SET(u32) @ 0x00b81= 608 {} + + /// 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(crate) NV_VIRTUAL_FUNCTION_PRIV_CPU_INTR_TOP_EN_CLEAR(u32) @ 0x00b= 81610 {} + + /// 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(crate) NV_VIRTUAL_FUNCTION_PRIV_CPU_INTR_LEAF_TRIGGER(u32) @ 0x00b= 81640 { + /// Vector to latch. + 11:0 vector; + } +} + // The modules below provide registers that are not identical on all suppo= rted chips. They should // only be used in HAL modules. =20 @@ -471,6 +529,19 @@ pub(crate) mod gm107 { } } =20 +pub(crate) mod tu102 { + use kernel::io::register; + + // PCI configuration-space mirror. + + register! { + /// MSI end-of-interrupt register. + /// + /// A `u32` write rearms MSI delivery on pre-Hopper GPUs. The valu= e is ignored. + pub(crate) NV_XVE_CYA_2(u32) @ 0x0008_8704 {} + } +} + pub(crate) mod ga100 { use kernel::io::register; =20 --=20 2.55.0 From nobody Wed Sep 30 12:58:54 2026 Received: from SN4PR0501CU005.outbound.protection.outlook.com (mail-southcentralusazon11011067.outbound.protection.outlook.com [40.93.194.67]) (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 13696383C7C for ; Sat, 8 Aug 2026 03:11:39 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=fail smtp.client-ip=40.93.194.67 ARC-Seal: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1786158700; cv=fail; b=cF3qavODIR8UQREUZ0L/syFvcfA7O6jVWLlRTvuX2YOkp+qUofNWqskgZ4E+EhejyGrcYuGDUfMquT4xt/rq1piCowwdwsTR4jEWImPWfVrHm4Uy1pWPEhzu/Qdu9LRVn3Q0Om9M1JQshdJX2doC+JR2NOPZjNZneNhI2og2hag= ARC-Message-Signature: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1786158700; c=relaxed/simple; bh=9RKvGvjfIUD8hTkV+kAGEqWuENZFuGHDKDrmSgbvQME=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: Content-Type:MIME-Version; b=HHs7nBDU8R4hJmN1uekfK4jw0aOpwxUci6lXjK3hc5jvivOGVFtl74bnGp9e5vHJ9EefhsEvBtgTMm2IlQMi7SGnQ3HZl5dPfYsbd+KP6FPzPl3rexYk3EcWMQbhGFBQuht6EJBhQdlyVcWxbdYY/SYPgOPVbkpPbIsPAfiHf7c= 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=rWPROYt6; arc=fail smtp.client-ip=40.93.194.67 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="rWPROYt6" ARC-Seal: i=1; a=rsa-sha256; s=arcselector10001; d=microsoft.com; cv=none; b=i4dcIpb8EQ2/2szoWMEaIADR4wZG+nDCdCVW+9M+DHvEm32uWsDcY7O5DVojbX3rBDmURMavtoeOm1vR3Iy/Xl0Cd1WeZHZYP4xU8+qkKOuEYwSkRYXKjPwEzLkc77aecp1SSFs8KduzxhGk4jtU7lRApQeK6TF2qaT0O2DDaKKddaO5Aq+d9fnwQD3H+w6M8uML3tx+bKGzVlq31KPV6SR3U1yRuXppBoSNrhu3FDzXoH989Zo30wPhB0FUOnmgoRazfKKq7KSYqw/MqTChDZhA6RetVN5RC6dnYY2xfWlqxgni0qXi4yG++JcyiVgJi1rvu6E6HyuB0EafF2Z80A== 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=vK64GauwbJsSoSvWAOkiD2Jj9LRTrLTXTuHkHcAV3Uw=; b=dTWA8Nv3pBGd2JFWWvAJqczrxkjb54I1Ut/OkjGT9W+P6Z5b0euzU+lWlntv/coZnTv7ERlwass6UiWGFt0jlRE38uz6T1CtSZe7lkbL7E/5C3nEIVE926H56vnPqOKzQSbA6RZJjch07xH+sMNjknyXHcTzPkvae6zsF2VR8+s/9vwi0F0gypE8QgaEFO8lMHapV8r4MtBZYCcZVOt1LmUhaJhDHBq7K7APY0CZW4O1hNUoqBZ1lno2qMZnNB6ha4hE30lw4op6VUUUURzB1F4OEpYHrr1Ee+wDeXLDUQzyfFAd338s557qExWVKyiF8d690VU9jr11O5Y9sBtVeQ== 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=vK64GauwbJsSoSvWAOkiD2Jj9LRTrLTXTuHkHcAV3Uw=; b=rWPROYt6b+vxVYGycC+vVDmDYeBd7XDo13U3sIAfmKrIMc0hOpM5oRDF6d0AEpociA3+XU5xt+UheU6gvinLUghW8PjAFWeG+n5c7vdqLw9l5NgBsaTNrVwMxfBVXxT16uwM22KfQyUUaioXBwbYS78ONGBy+VE1WLNv/5br4c/a0FQWbQvMGbjN62hSB+VGooDA9+V/cDSeOHuVs6upczo/dwHS0Q+urSzyfHsUmt721ywyzROSqwZTkJhCimfFH52OUj26CbX5C8pFv6L3YxarpXAhEXyouPW59LD5nJJGBSZY3wN4hvLe+8ZNBzC07T1eM8uBCfPlcD1DjCSW6A== 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 CH2PR12MB4198.namprd12.prod.outlook.com (2603:10b6:610:7e::23) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.21.292.21; Sat, 8 Aug 2026 03:11:29 +0000 Received: from DM3PR12MB9416.namprd12.prod.outlook.com ([fe80::8cdd:504c:7d2a:59c8]) by DM3PR12MB9416.namprd12.prod.outlook.com ([fe80::8cdd:504c:7d2a:59c8%4]) with mapi id 15.21.0292.022; Sat, 8 Aug 2026 03:11:29 +0000 From: John Hubbard To: Danilo Krummrich , Joel Fernandes , Alexandre Courbot Cc: Timur Tabi , Alistair Popple , Eliot Courtney , Shashank Sharma , 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 06/17] gpu: nova-core: add the GIN interrupt tree API Date: Fri, 7 Aug 2026 20:11:08 -0700 Message-ID: <20260808031120.363869-7-jhubbard@nvidia.com> X-Mailer: git-send-email 2.55.0 In-Reply-To: <20260808031120.363869-1-jhubbard@nvidia.com> References: <20260808031120.363869-1-jhubbard@nvidia.com> X-NVConfidentiality: public Content-Transfer-Encoding: quoted-printable X-ClientProxiedBy: BY5PR04CA0018.namprd04.prod.outlook.com (2603:10b6:a03:1d0::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_|CH2PR12MB4198:EE_ X-MS-Office365-Filtering-Correlation-Id: 14ab554c-f383-4d25-b300-08def4fabd7f X-MS-Exchange-SenderADCheck: 1 X-MS-Exchange-AntiSpam-Relay: 0 X-Microsoft-Antispam: BCL:0;ARA:13230040|23010399003|366016|376014|1800799024|7416014|10067099003|6133799003|56012099006|5023799004|11063799006|18002099003|22082099003; X-Microsoft-Antispam-Message-Info: QP7mtFgGcpiBwSJ3EboCyf/y6CkFG14a6ql80wMROyRPjdDD/RxhQzsG57Mo/fGCiC67hnK1R7WM1gEAE73ATwD7tUVCwFDPqRAD/lye3/xXMyOLudvQQvh3U6v/Mw8gaPuHxQBvmSspfhtIf+Kd2D5b6SGH0pvarCf8UWIBwV/yJ+KdIPMK/7o+3brScyCdHu4cEKCGhFX7O7gSF1ZamWQus94IQDtYCNF+rkPxKRUdSNooPilzKFuR56Jgb6RVFSO45KK12h0ySiO03QPW7BqjibaC3duif1obqihC6Sg/gg6YaStD+cx2LQwzBMkdoPjaTBwSMaPHlEGvzGETfUWDJRyAldEk44XoqaAh9jx+E15VjYzeWCEpZxrfDDwnx+kjBM25TvASmpUF75vBRb3g9pRtvpdZREg8x8erpYG7SJawqhvS+G+u3zaYuRQk/ZqVrkHfRafRk7H+5DblGeh6Fw9nXHEGnwNROUMO73cRNOVF45Qfj+3MmskPFWZm9hNBZaYcScufs5xkf4QTLhK9x+r1QsjRN/5W6qynDTtBKGCS4JbkqXr1hoCmZMPNCFIumD2KmgngkBVnrNeoCaStO98A8zIdO09HgzMI4u/qGTcw8UjnYIOKXUGDHv5tHdX2B2BuFEmEPLEit1ZYiB2GENEszuj4pYFBV3PfSh8= 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)(23010399003)(366016)(376014)(1800799024)(7416014)(10067099003)(6133799003)(56012099006)(5023799004)(11063799006)(18002099003)(22082099003);DIR:OUT;SFP:1101; X-MS-Exchange-AntiSpam-MessageData-ChunkCount: 1 X-MS-Exchange-AntiSpam-MessageData-0: =?us-ascii?Q?VSK2OSn34wK4XxF58hM0G05UUzapOI4ee76MYiu2lj91OxeXLIvn8uaOWxl7?= =?us-ascii?Q?rwVOZ6AMXS9a/sxyKkyR01mi0Id9LVFDQ2rql0QNPIlQm0pH9lzyPz3TA+L0?= =?us-ascii?Q?RsvK/khb1s9JJYwxJ53bmaAJlpZy1NymuvpfU/UfJWMhyIM95teheqUZOG5S?= =?us-ascii?Q?XmlNDONEjxE5Emb4KfdFcDNGl2zBJOwRLDP+LW1Y5BXA0c11V3G4+hV0uzsP?= =?us-ascii?Q?tvDzZmqPHkhwXe9tD9yUjBHzB1g1wIyCSW0PQfn6T/hU1pxAhbN1j1wBCuy2?= =?us-ascii?Q?w1S9zp89SFUUxV/pSSEBAH7ol2vxKz9lnlDuIzvaJxbreXHmde/aQ7k1fW/4?= =?us-ascii?Q?LYMLw3L46tiJ94ui9GgOgWmFjEyn/uGgKx56Yus6TlWgKQ4VJHQe2SPyXCG7?= =?us-ascii?Q?MgoehKPKKY/IGujfqoNnjKV+DZtnh4p5vFYmN20QH2MKZM31d6GgzdXn72sh?= =?us-ascii?Q?zuL77W5fYsL9v5Y69R9y8JCzR233ug1xnDT/ELmI7g1i7meAPVy3RNopAg6t?= =?us-ascii?Q?VEtWPRV8mrf3hGTOvEd2+lYo1zze1R6RR+iL1K7XVyrJrTvmsKiiMDzSSLfJ?= =?us-ascii?Q?AC699SR1oEB/EA5K9+d1gV8iNP22jOEHgDe5doKB0UYAbOo47zfzJ0P8zKdt?= =?us-ascii?Q?byYVDbIhbd7gkUSxszo7kenY0FV8g7dChKAJebSSJKK4DajwEulVpR78XH8E?= =?us-ascii?Q?kof4E0jZiGcq8+gFd/mfobOblwWPY3JLMbYAyhqdSCGIGqqT8TNtuT570DVL?= =?us-ascii?Q?rVoiFWuso24twmfcee2vMHn/QCDVu0l+3ilo27T6DC+dKSmP9mfLNqbaMrQC?= =?us-ascii?Q?IVqXGuwrNYs+g6Rhgg4t/ZUPB177hb+1nuMkkctQ6GSV94hcQMT6BHkk7d5u?= =?us-ascii?Q?e4if/gSJCEwDrwuGJ1p/f04fggrgoxNH0yJ3pJXs7I33WkMViR8Rm1EuclCL?= =?us-ascii?Q?ETwVNhqrts+6m7gDc2Ybgt8YQq5SQShiccDbUOsmcBNT08/g+R4B4yb9j7nZ?= =?us-ascii?Q?Ik/PWhqAPRMppqiVewDby9Oq/uOJnpjLLWaaqpS+eHkFZshYElHSpnShPRR6?= =?us-ascii?Q?pTJoG3SYt6ik9okWTtXSwDUDAsHSzV+UVy8Jebr55n5Prk4ZncKpiHU6Sj7e?= =?us-ascii?Q?7tfx/a3gYiTTyovshTaFlxtUMS1jXcyctJIpa9aJtun9w0qJ7Tj56p+L7euo?= =?us-ascii?Q?TF94WYP2km4is/fE4zxJvbefrVlgPgUP3tWHFaxzzwT820NpubwL4dpZ4op5?= =?us-ascii?Q?ugknbfPXnDV+zNDwWO11Xw6PIlpHnXqLdfaO4R8BVfQctX0a/Rss4o2HPbLW?= =?us-ascii?Q?Yw/XxzzTtoVuHQQEitD4fAQscR+NYeUYOEAjrH5RKIkcmHafi4/GZsuR/36s?= =?us-ascii?Q?Ffz4wAcB+cfg1BAW2ip9i6PUwvbFo8IO97U7vXghnqmNZ17lP2rPPSU3e1Th?= =?us-ascii?Q?G7Ldp424KC4+Qd4BQVqacKYWNlSZ0tsgZVJ6W5dvLF22BIrMguHf345QI8om?= =?us-ascii?Q?iPu2Hij4abP6ITCtdzDTqXU+qeo3S53qHuZmxx4JIt6kV2Tn/pbJJf0buQBT?= =?us-ascii?Q?WR2qT7tzEsKqZmxxIRO0hZPHozfTBrKkir68X/QhnO15Ja7qJ2yqYLx4pn6e?= =?us-ascii?Q?tr+DIE8uY5fpMV5HTVFhzsS1kMkHWgxj0/Wg6mePZqq/A4GxrRRrLqvNBSso?= =?us-ascii?Q?QdF/wJUxI1Lh6a3k+0A+M8ePIazvn1/WWFFG0e1qKexaeX4BqC66aH1S+99w?= =?us-ascii?Q?TrRLAaLmGg=3D=3D?= X-OriginatorOrg: Nvidia.com X-MS-Exchange-CrossTenant-Network-Message-Id: 14ab554c-f383-4d25-b300-08def4fabd7f X-MS-Exchange-CrossTenant-AuthSource: DM3PR12MB9416.namprd12.prod.outlook.com X-MS-Exchange-CrossTenant-AuthAs: Internal X-MS-Exchange-CrossTenant-OriginalArrivalTime: 08 Aug 2026 03:11:29.2886 (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: I8YYWk+Tudb8vjTA15j1k9g1XPztEUh6031okYh/Ers4RORGa55VRZ4hYm7UcYuSU5KNtduYxUd1xhbSVefEqw== X-MS-Exchange-Transport-CrossTenantHeadersStamped: CH2PR12MB4198 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. Add an API for one PCIe function's CPU interrupt tree. The leaf handle carries that order as a type state, so the wrong order does not compile. The CPU doorbell self-test added later in this series is the first user. Reviewed-by: Will Pierce Signed-off-by: Joel Fernandes [jhubbard: use the canonical NV_VIRTUAL_FUNCTION_PRIV_CPU_INTR_* register names, name the module interrupt_tree with a Tree type, drop the type state from the Top handle, take the leaf count from the chipset, define the vector encoding here, reject a trigger for a vector outside the tree, 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 | 2 + drivers/gpu/nova-core/irq/interrupt_tree.rs | 257 ++++++++++++++++++++ drivers/gpu/nova-core/nova_core.rs | 1 + 3 files changed, 260 insertions(+) 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 index 48900c734cb6..b70efc239334 100644 --- a/drivers/gpu/nova-core/irq.rs +++ b/drivers/gpu/nova-core/irq.rs @@ -11,6 +11,8 @@ prelude::*, }; =20 +mod interrupt_tree; + pub(crate) fn alloc_vector(pdev: &pci::Device) -> Result> { let msi_types =3D IrqTypes::default().with(IrqType::Msi).with(IrqType:= :MsiX); =20 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..9f6cfed89bec --- /dev/null +++ b/drivers/gpu/nova-core/irq/interrupt_tree.rs @@ -0,0 +1,257 @@ +// SPDX-License-Identifier: GPL-2.0 +// SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIA= TES. All rights reserved. + +//! Type-state API for walking the GIN CPU interrupt tree. +//! +//! Each PCIe function has its own interrupt tree, and this module drives = one function's CPU tree. +//! A [`Leaf`] carries a type state, `Idle` -> `Pending`, so that clearing= one before reading it +//! fails to compile. +//! +//! The type state orders the operations on one [`Leaf`] value. Serializin= g access to the tree is +//! the caller's responsibility. + +use kernel::{ + io::{ + register::Array, + Io, // + }, + num::Bounded, + prelude::*, +}; + +use crate::{ + driver::Bar0, + gpu::{ + Architecture, + Chipset, // + }, + regs::{ + NV_VIRTUAL_FUNCTION_PRIV_CPU_INTR_LEAF as CPU_INTR_LEAF, + NV_VIRTUAL_FUNCTION_PRIV_CPU_INTR_LEAF_EN_CLEAR as CPU_INTR_LEAF_E= N_CLEAR, + NV_VIRTUAL_FUNCTION_PRIV_CPU_INTR_LEAF_EN_SET as CPU_INTR_LEAF_EN_= SET, + NV_VIRTUAL_FUNCTION_PRIV_CPU_INTR_LEAF_TRIGGER as CPU_INTR_LEAF_TR= IGGER, + NV_VIRTUAL_FUNCTION_PRIV_CPU_INTR_TOP_EN_CLEAR as CPU_INTR_TOP_EN_= CLEAR, + NV_VIRTUAL_FUNCTION_PRIV_CPU_INTR_TOP_EN_SET as CPU_INTR_TOP_EN_SE= T, // + }, +}; + +/// Index of a leaf register, bounded to the `0..16` range covered by the = leaf register arrays. +pub(super) type LeafIndex =3D Bounded; + +/// Maps an interrupt `vector` to its position in the tree: the leaf that = carries it +/// (`vector / 32`) and the bit index within that leaf (`vector % 32`). +/// +/// The returned leaf is a raw index. [`LeafIndex::try_new`] bounds it to = the leaf register +/// arrays, and the architecture's leaf count is a separate, narrower boun= d. +pub(super) const fn vector_leaf_bit(vector: u32) -> (usize, u32) { + (crate::num::u32_as_usize(vector / 32), vector % 32) +} + +/// Maps an interrupt `vector` to the `TOP` enable mask of the subtree tha= t carries it. +/// +/// A subtree covers two adjacent leaves, so the vector's leaf is in subtr= ee `vector / 64`. The +/// result has that subtree's bit set, in the form `TOP_EN_SET` and `TOP_E= N_CLEAR` take as a +/// value. +/// +/// The result is not validated against the subtrees that the architecture= supports. +pub(super) const fn vector_subtree_mask(vector: u32) -> u32 { + 1 << (vector / 64) +} + +/// Type state of a [`Leaf`] handle: `Idle` before its pending bits are re= ad, `Pending` after. +pub(super) trait State: private::Sealed {} + +/// State in which the handle holds no pending bits. +pub(super) struct Idle; +impl State for Idle {} + +/// State holding the pending bits read from hardware. +pub(super) struct Pending { + pending_bits: u32, +} +impl State for Pending {} + +mod private { + pub(in crate::irq) trait Sealed {} + impl Sealed for super::Idle {} + impl Sealed for super::Pending {} +} + +/// The GIN CPU interrupt tree for a single PCIe function. +#[derive(Clone)] +pub(super) struct Tree { + /// Number of implemented leaves in this tree, either 8 or 16. + num_leaves: usize, + /// Mask of subtree bits the architecture implements. + subtree_mask: u32, +} + +impl Tree { + /// Creates a `Tree` sized for `chipset`. + pub(super) fn new(chipset: Chipset) -> Self { + let num_leaves =3D match chipset.arch() { + Architecture::Turing | Architecture::Ampere | Architecture::Ad= a =3D> 8, + Architecture::Hopper | Architecture::BlackwellGB10x | Architec= ture::BlackwellGB20x =3D> { + 16 + } + }; + + Self { + num_leaves, + // Each subtree covers two leaves, so one bit per pair of leav= es. + subtree_mask: (1u32 << (num_leaves / 2)) - 1, + } + } + + /// Returns a [`Top`] handle for this tree. + pub(super) fn top(&self) -> Top { + Top { + subtree_mask: self.subtree_mask, + } + } + + /// Returns a [`Leaf`] handle in the [`Idle`] state for `index`. + pub(super) fn leaf(&self, index: LeafIndex) -> Leaf { + Leaf::from_index(index) + } + + /// Injects a software interrupt for `vector` via the trigger register. + /// + /// # Errors + /// + /// `EINVAL` if `vector` lies outside this tree (`vector >=3D num_leav= es * 32`). `EOVERFLOW` if + /// `vector` does not fit in the trigger register's vector field. + pub(super) fn trigger(&self, bar: Bar0<'_>, vector: u32) -> Result { + if crate::num::u32_as_usize(vector) >=3D self.num_leaves * 32 { + return Err(EINVAL); + } + bar.write_reg(CPU_INTR_LEAF_TRIGGER::zeroed().try_with_vector(vect= or)?); + Ok(()) + } + + /// Clears every pending bit in every implemented leaf. + /// + /// The walk runs with every implemented subtree disabled at `TOP`, an= d every implemented + /// subtree is enabled on return, whatever its state on entry. The lea= ves cleared and the + /// `TOP_EN` writes both reach subtrees the driver does not service. + /// + /// Call `drain()` only during probe. It must not run concurrently wit= h an interrupt handler. + pub(super) fn drain(&self, bar: Bar0<'_>) { + self.top().disable(bar); + + // `TOP` summarizes enabled leaf bits, so a vector that latched wh= ile it was disabled does + // not appear there. + for index in 0..(self.num_leaves / 2) { + for leaf in (Subtree { index }).iter_pending_leaves(self, bar)= { + leaf.clear_pending(bar); + } + } + + self.top().enable(bar); + } +} + +/// Top-level view of the interrupt tree, enabling and disabling whole sub= trees. +pub(super) struct Top { + subtree_mask: u32, +} + +impl Top { + /// Enables interrupt delivery for every implemented subtree (`TOP_EN_= SET`). + pub(super) fn enable(self, bar: Bar0<'_>) { + bar.write(CPU_INTR_TOP_EN_SET, self.subtree_mask.into()); + } + + /// Disables interrupt delivery for every implemented subtree (`TOP_EN= _CLEAR`). + pub(super) fn disable(self, bar: Bar0<'_>) { + bar.write(CPU_INTR_TOP_EN_CLEAR, self.subtree_mask.into()); + } +} + +/// One subtree of the interrupt tree, covering two adjacent leaves. +#[derive(Clone, Copy)] +pub(super) struct Subtree { + index: usize, +} + +impl Subtree { + /// Yields the two [`Leaf`] handles covered by this subtree. + fn iter_leaves<'a>(self, tree: &'a Tree) -> impl Iterator> + 'a { + // A `Subtree` is constructed only for an implemented index. `Leaf= Index::try_new` drops + // any index beyond the leaf register arrays instead of panicking. + (0..2usize).filter_map(move |offset| { + let idx =3D self.index * 2 + offset; + LeafIndex::try_new(idx).map(|idx| tree.leaf(idx)) + }) + } + + /// Like [`Self::iter_leaves`], but keeps only leaves with non-zero pe= nding bits. + pub(super) fn iter_pending_leaves<'a>( + self, + tree: &'a Tree, + bar: Bar0<'a>, + ) -> impl Iterator> + 'a { + self.iter_leaves(tree).filter_map(move |idle| { + let pending =3D idle.read_pending(bar); + (pending.pending_bits() !=3D 0).then_some(pending) + }) + } +} + +/// View of a single interrupt leaf. +pub(super) struct Leaf { + index: LeafIndex, + state: S, +} + +// The `try_at(...)` calls below cannot fail: `LeafIndex` is `Bounded`, so its value is +// in 0..16, and every leaf register array has 16 elements. +impl Leaf { + /// Creates a [`Leaf`] handle for `index`. + pub(super) fn from_index(index: LeafIndex) -> Self { + Leaf { index, state: Idle } + } + + /// Enables the vectors set in `vectors` for this leaf (`LEAF_EN_SET`). + /// + /// This is the per-vector counterpart of [`Top::enable`], which enabl= es a whole subtree. + pub(super) fn enable(&self, bar: Bar0<'_>, vectors: u32) { + if let Some(loc) =3D CPU_INTR_LEAF_EN_SET::try_at(self.index.get()= ) { + bar.write(loc, vectors.into()); + } + } + + /// Disables the vectors set in `vectors` for this leaf (`LEAF_EN_CLEA= R`). + pub(super) fn disable(&self, bar: Bar0<'_>, vectors: u32) { + if let Some(loc) =3D CPU_INTR_LEAF_EN_CLEAR::try_at(self.index.get= ()) { + bar.write(loc, vectors.into()); + } + } + + /// Reads this leaf's pending bits and transitions to [`Pending`]. + pub(super) fn read_pending(self, bar: Bar0<'_>) -> Leaf { + let pending_bits =3D CPU_INTR_LEAF::try_at(self.index.get()) + .map(|loc| bar.read(loc).into_raw()) + .unwrap_or(0); + Leaf { + index: self.index, + state: Pending { pending_bits }, + } + } +} + +impl Leaf { + /// Returns the pending bits read from hardware. + pub(super) fn pending_bits(&self) -> u32 { + self.state.pending_bits + } + + /// Clears every pending vector by writing its bits back (write-1-to-c= lear). + pub(super) fn clear_pending(&self, bar: Bar0<'_>) { + if self.state.pending_bits !=3D 0 { + if let Some(loc) =3D CPU_INTR_LEAF::try_at(self.index.get()) { + bar.write(loc, self.state.pending_bits.into()); + } + } + } +} diff --git a/drivers/gpu/nova-core/nova_core.rs b/drivers/gpu/nova-core/nov= a_core.rs index 68b5abfe494d..dfd11dfe562c 100644 --- a/drivers/gpu/nova-core/nova_core.rs +++ b/drivers/gpu/nova-core/nova_core.rs @@ -17,6 +17,7 @@ mod fsp; mod gpu; mod gsp; +#[expect(dead_code)] mod irq; mod mctp; #[macro_use] --=20 2.55.0 From nobody Wed Sep 30 12:58:54 2026 Received: from SN4PR0501CU005.outbound.protection.outlook.com (mail-southcentralusazon11011067.outbound.protection.outlook.com [40.93.194.67]) (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 24E643859D4 for ; Sat, 8 Aug 2026 03:11:41 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=fail smtp.client-ip=40.93.194.67 ARC-Seal: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1786158702; cv=fail; b=iZESV1q9rPs6LnhvMgW5vb+9PYGtPYg0TrkUeJmK0NG7QGjhb0rfagmzZJlNqylZUxJiQF0qTI50j6UT/udkI1UuFa53/AnrKSFD1xWcwEA1P2lmU0vfaFMgKNtYj+Nzcy6lU/xiKUnLtChQmn36lEK79Ck73TqN4A+V9lQZAYk= ARC-Message-Signature: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1786158702; c=relaxed/simple; bh=rpz/zpn5KN4dvNZzKkLz8dhZ+IKLpV63LhpWYU4pFnM=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: Content-Type:MIME-Version; b=IUIHDsKm8v4W40Kqcxj3crehl9XXp/PfCNgyCL6z2Pb3FIfTrNkbdpiJuZYOu+gywGbwiKYk9yk14BXKtVbvjNGACCNV1htWw6KD7aANzSxquMbEe/Aj17AdtSd0/6g1jMCtRd/ZLfd9osLPDZaQTBDsSfx2fHRqML2zWs9Nihk= 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=jfGMm9Iu; arc=fail smtp.client-ip=40.93.194.67 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="jfGMm9Iu" ARC-Seal: i=1; a=rsa-sha256; s=arcselector10001; d=microsoft.com; cv=none; b=LsPkLmxD5kXIZRJipkbXQPJS9V1pBlKoW4OraEgjFT0m97wlnJIaRJ/NrjjmIF/I2g0AveagNAHQqIVtaTGnUk0Sm+iKylU2oADCCbcnJ1tPxSQXU/mmuO6xmFCZdml8l3wqf0AQnapJPpEGCpomhMvYrF/JcDxpFbW4ZWVMKPpQI7xXYqaNZSGj9h71it67D6UZRUNbU2pu4jzrXsyg2XUP49bjOWGZ4qlW4SfZRqpO3RI8dRs3NF8GVmScGbzxBCOyMpB0Mz+uoLDDoVTVjxqh2K4uG/AJ1Zin2VmgWwqGx8rPNgpLxClqjxxw5puedY1YjMmIlUxI5CVBdxbKGA== 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=pzyRTmlgi1WKG68wyPfL0NHQjFNuPBFMcKTYgjfJcgs=; b=F3vSjrl8x0vxgqCOki1k4+IWQIcTn7Kf7IctnLzFC6nH+RUNRpcHzl4Gn73lsE8eNQ65swAad/M4DMZEzHaAhXMpuhTcKM62EPnTrkMRJ551j+wl4Y00xVilCeVeGFFGghluKgDjeH4IbQJsMg4mPDYtzs27IT56yjWWODhgaRpyaq7CZGHcQkp9rtu20ss8tiZn//2FG5/KLnkvvuGVR5x7OA8HYMuplZfxsmrs1lsiQ3horzZE6phOQL8JcAg3uekdX6Cf0EqkykH1KzlXG4HzUqSxxT9PSPV2nyM3esMHtnZJQ1orc7iRt1k6UJhUwk4JfUAjdttueP2y/7s+dQ== 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=pzyRTmlgi1WKG68wyPfL0NHQjFNuPBFMcKTYgjfJcgs=; b=jfGMm9Iu2+E220AqDyXFMl9Gf+i7Q9kDzVF+QkwbLI4HHEm7dEHAbnV3dCwnjm/AGapgUsP5+AYScnf31vzBfSCu/+rK2JE8DPElaAeEV2/j1ZXD0AHEfHYcjiDU39eM8VgX1RElFdfb2DkRxu+QHTwz2vz3OnD2xhK09ouibHVLEIwSF6AuYO7oMtL7RWeOSJsnPXAsyOjLIZ6PRTeUjZFXmZaep9911WRLzJ4n6akwoRPaAiQ11Tfnu1OwmGcWkhsEIK3EEQ5OZLG/DuVvnBle2RIY+2qgpwzWm1I97238haFfLvCJosoJaS1gGKzUIgh0kMkSa5sWRYfzIWBOEQ== 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 CH2PR12MB4198.namprd12.prod.outlook.com (2603:10b6:610:7e::23) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.21.292.21; Sat, 8 Aug 2026 03:11:30 +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.0292.022; Sat, 8 Aug 2026 03:11:30 +0000 From: John Hubbard To: Danilo Krummrich , Joel Fernandes , Alexandre Courbot Cc: Timur Tabi , Alistair Popple , Eliot Courtney , Shashank Sharma , 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 07/17] gpu: nova-core: add the per-architecture GIN CPU interrupt HAL Date: Fri, 7 Aug 2026 20:11:09 -0700 Message-ID: <20260808031120.363869-8-jhubbard@nvidia.com> X-Mailer: git-send-email 2.55.0 In-Reply-To: <20260808031120.363869-1-jhubbard@nvidia.com> References: <20260808031120.363869-1-jhubbard@nvidia.com> X-NVConfidentiality: public Content-Transfer-Encoding: quoted-printable X-ClientProxiedBy: SJ0P220CA0024.NAMP220.PROD.OUTLOOK.COM (2603:10b6:a03:41b::32) 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_|CH2PR12MB4198:EE_ X-MS-Office365-Filtering-Correlation-Id: 560c0f79-8c1c-4d7f-2859-08def4fabe39 X-MS-Exchange-SenderADCheck: 1 X-MS-Exchange-AntiSpam-Relay: 0 X-Microsoft-Antispam: BCL:0;ARA:13230040|23010399003|366016|376014|1800799024|7416014|10067099003|6133799003|56012099006|11063799006|18002099003|22082099003|3023799007; X-Microsoft-Antispam-Message-Info: eqT2DhZVP67QveHEo6JpgvU+Ul1d5GoOOeKjmWGH0mwpUKh0hkLVseTL66sEBFGVbGWP61UAKiqA/6IVTLGQC9idfd0yaFv3gPzX3V392NA1ctkRXHjBjl/vJri6ZWtvsg9KzsUJWD9dh10ID/wkdOWrMFEbjOc9pKsE5YV7RHaB0enuzazBUF49LG+7AJ7NseHwe5nmzjYePxvmzxpJXtpCsZ5M7zvcjG2hNauC7qv48dgXgoCipwll8uTt8lOJFNngGXJ6AwcuGhgtKMXLmZHFb5ztL/dftq8Ph72pL2mEvOHY1g46KNN6pcl/uFqaskDDyKsgg7jz69W5IvAaBzX7apbWjnP+i4WjJTh+pxcbI4HuGnnvMuCKR7RHIcf657q/bGxRBT89kAG77rG/B0IvDMDIyafzt+2q1My3EwkSemEsLlkCNWtnTw9Ex6omWBoHYoiCOR3eXu48oP3Gyky3Abu4VoBPlZF9IPzim2gz0zKPqFC8rtEHBSin0/j1fr+epQRNiArbHl/g6OMpoRgNiPT0pRpdP2ojY51Mpmdvwh4umWn2D5hKSUO6p8soS9l/bKLNc16ON9iyWavA7seKOPYHjV18rhqNGw1F+QWjzEnS+dEdr6F2Xw+k5PcYDmdoj5OY+HNvK8NPeLkQJiyXGT40fzP+zZ5C9jdFV24= 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)(23010399003)(366016)(376014)(1800799024)(7416014)(10067099003)(6133799003)(56012099006)(11063799006)(18002099003)(22082099003)(3023799007);DIR:OUT;SFP:1101; X-MS-Exchange-AntiSpam-MessageData-ChunkCount: 1 X-MS-Exchange-AntiSpam-MessageData-0: =?us-ascii?Q?L6U5wEkaT2vX3WDJlkDQ86j2OXErpoYAkiWH5ss7QIq5Smsai/xYND+3Y/sq?= =?us-ascii?Q?stbjD/DnQzJuqK7ViEqdOhpQvexWlb/s+r34DG04YvNWzxHS0MIB4VAXcvdJ?= =?us-ascii?Q?rF8We87sOjYkhBTg3izQ6AGqALnYlIFl2sLdHpkmhtP2E2c0zdxeG967lgar?= =?us-ascii?Q?8H+P3235MJFRUhLRljJaqCTIxEtIsCZ4rS4auSMNZA07eECN9VCp2EIjy8p7?= =?us-ascii?Q?lr3WcbH0Qzp3mYm21Cd/CHh3zPmCdFfM6vPQKEDhG7lj6jC/Nx39ZyhoSmvB?= =?us-ascii?Q?4Idj12MUzni83FM1VlwK6/x9sucemrS4o0KxYXEAa2y452uDqAt/XsRE7o7j?= =?us-ascii?Q?LDdPkG/csNFUwDiBB4DMzfbGeITEgDsvMRD/YwZBMJMpVBnw/4QVKdXKwfzA?= =?us-ascii?Q?9w8MBYoNXjSHrugwmjsdneCzrt5rJHSX8GwIB33SWjH7YGn+of4NWptAMlha?= =?us-ascii?Q?RsugcJMF4RPA4AyA7wGtwpgOmmZZKcBGOsJIwrS/WNhgaxuiPSpo1CJijboz?= =?us-ascii?Q?8mk5VlSvHIhaoFoqzLAruMAIaYlWclc4SI8lA2k5Xq7JdoSgzoK9fB6Hb6nU?= =?us-ascii?Q?gj88a45cvLEKqrncRWOS6RtWcMTzUcE79uNZj4ySlzfV8wwROZT3ofKH1tjk?= =?us-ascii?Q?wUlsGn5jEU8tBoJnOzb45orc4AlaX88wZKbHzp3QbtznAXEDmPKJ04fl+93B?= =?us-ascii?Q?6eyYZyULJ9AN/fCurn7R7BEUsFzt+8UV4VOKmBydObIgkwib/WGGziL0Q+/i?= =?us-ascii?Q?DcZ8chOHsMvVwDamAZyUyAMgxAc5FnyG4IJFWER5tQJvvqEhJDoz83lbsr6e?= =?us-ascii?Q?a9D9WjDwwbNmR9N3ZZ/aqEtrSt8zDHXYm2Av9qg6pzQkkrhY5LdyxOZ6UV8Q?= =?us-ascii?Q?He4ke3hLpSOHe7dYLofWxGB3CAI1h2LrKcAKjATmvq/WIsnUt+YoY+rrp6gJ?= =?us-ascii?Q?pvZt7fjcBvGQmJ95ElcAsDAeMINd6RiV8Jl7bosPiro9T+uIJl2lCaQV8pjt?= =?us-ascii?Q?IvnqsY/A5Lq+oB848MvWdCqFUvRDBLLCSqJlW7mXsTVYC4jVPGgzxSC8O1eP?= =?us-ascii?Q?T+H01iTpB3eLdQO0yQ6ej7jVCj2KSxKLwGdyI2Up61kt5gvn5ZUi1JL+abHw?= =?us-ascii?Q?AeA8Bj10LWT21Vu7/sv/WcRcgawSFTf4/E+2/+n9EUygDD8+4s/WV20QeoOm?= =?us-ascii?Q?WlwcfsSjoIxKrc161ZUz/c0MO3NQCFLKzH/ZRkGtIr8EOShiGe8p+kExjdCW?= =?us-ascii?Q?PU0GYekvL46FEu7Nu5XTSEW2ymc2Qvq9wKQhj91jPZcvl3QmTbULGM06InoR?= =?us-ascii?Q?eGLotQgWQBsxbuFic32tT2x6GAN4LU1PwPYwQa7seuwmm+Yl0LuJn0mvRa7m?= =?us-ascii?Q?fQxDPj7i6/ROHp8OPFsYCP3DpD3CMW5XOA5zno1RgwOo1AmPNFTQG1nF2dI7?= =?us-ascii?Q?cWoKDOmlhKq+NEWcwMtX4jQ2AsXvV3xC44f+ktRnllZNjyk+R+ZhdKwZg9KU?= =?us-ascii?Q?C/bIpKsgwP4d8H7SZmakAP33z7LeYY3BSDKFMFzH8rrg4jXm11qTdygmOWA9?= =?us-ascii?Q?VVqpVDzZrIMxFxNnEyegfc0S0s3GxMNiSEbuDc8MoA6JQV58xWFejRlSqqbH?= =?us-ascii?Q?okuJoddVZLyj/GNi2pO1usqrrXqQcY0yJCzkSXR+jWSw1K8gT1IvvwVvWeaF?= =?us-ascii?Q?XHs63oPp7Zo8hNWzJSUkfZycGJ6S1NEkmbm3aRY9bCmuofrogjhtPnIJiPR9?= =?us-ascii?Q?zcwxWrZ9fg=3D=3D?= X-OriginatorOrg: Nvidia.com X-MS-Exchange-CrossTenant-Network-Message-Id: 560c0f79-8c1c-4d7f-2859-08def4fabe39 X-MS-Exchange-CrossTenant-AuthSource: DM3PR12MB9416.namprd12.prod.outlook.com X-MS-Exchange-CrossTenant-AuthAs: Internal X-MS-Exchange-CrossTenant-OriginalArrivalTime: 08 Aug 2026 03:11:30.5239 (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: 5ALE3kIuTn15++ah2o7AlcTteoShRD3GgjO38VUkjGfxd7cv60VT0xi4qAsnBJa7RwuRKmXJIp43K6ROUoIwUg== X-MS-Exchange-Transport-CrossTenantHeadersStamped: CH2PR12MB4198 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. Assisted-by: Cursor:claude-opus-5 Reviewed-by: Will Pierce Signed-off-by: John Hubbard --- drivers/gpu/nova-core/irq.rs | 12 ++- drivers/gpu/nova-core/irq/hal.rs | 113 +++++++++++++++++++++++++ drivers/gpu/nova-core/irq/hal/gh100.rs | 30 +++++++ drivers/gpu/nova-core/irq/hal/tu102.rs | 29 +++++++ 4 files changed, 182 insertions(+), 2 deletions(-) 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 b70efc239334..ef77066e0514 100644 --- a/drivers/gpu/nova-core/irq.rs +++ b/drivers/gpu/nova-core/irq.rs @@ -1,6 +1,16 @@ // SPDX-License-Identifier: GPL-2.0 // SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIA= TES. All rights reserved. =20 +//! 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 hal; +mod interrupt_tree; + use kernel::{ device::Bound, pci::{ @@ -11,8 +21,6 @@ prelude::*, }; =20 -mod interrupt_tree; - pub(crate) fn alloc_vector(pdev: &pci::Device) -> Result> { let msi_types =3D IrqTypes::default().with(IrqType::Msi).with(IrqType:= :MsiX); =20 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..8de2f6e536c2 --- /dev/null +++ b/drivers/gpu/nova-core/irq/hal.rs @@ -0,0 +1,113 @@ +// 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, + pci::IrqType, // +}; + +use crate::{ + driver::Bar0, + gpu::{ + Architecture, + Chipset, // + }, + regs, // +}; + +/// 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 the `TOP` bit of every subtree the driver service= s, and `subtree` holds + /// the bit of the one subtree the calling handler serves. Each method= uses whichever of the + /// two its interrupt type delivers on, so both are required. + #[expect(dead_code)] + pub(super) fn rearm(self, bar: Bar0<'_>, serviced: u32, subtree: u32) { + let subtrees =3D match self { + // The written value is ignored, so any write rearms delivery. + Self::ConfigMirrorEoi =3D> { + bar.write(regs::tu102::NV_XVE_CYA_2, 0u32.into()); + return; + } + Self::TopEnableCycleServiced =3D> serviced, + Self::TopEnableCycleSubtree =3D> subtree, + }; + + bar.write( + regs::NV_VIRTUAL_FUNCTION_PRIV_CPU_INTR_TOP_EN_CLEAR, + subtrees.into(), + ); + bar.write( + regs::NV_VIRTUAL_FUNCTION_PRIV_CPU_INTR_TOP_EN_SET, + subtrees.into(), + ); + } +} + +/// Per-architecture properties of the GIN CPU interrupt tree. +/// +/// The tree size and the method that rearms PCI interrupt delivery differ= by family. The tree +/// walk, the vector encoding, and the read-and-clear sequence do not, and= are in generic code. +/// +/// See `Documentation/gpu/nova/core/interrupts.rst`. +pub(super) trait CpuInterruptHal { + /// Returns the number of implemented interrupt leaves in the CPU tree. + /// + /// Each leaf is a 32-bit register, so the tree carries `num_leaves * = 32` vectors. + fn num_leaves(&self) -> usize; + + /// Returns the subtrees this architecture implements. + /// + /// Each `TOP` bit covers two adjacent leaves, so the tree has `num_le= aves / 2` subtrees and + /// the result has one bit set for each. Bits outside the result are n= ot meaningful in + /// `TOP_EN_SET` or `TOP_EN_CLEAR`. + fn implemented_subtrees(&self) -> u32 { + (1u32 << (self.num_leaves() / 2)) - 1 + } + + /// Returns the method that rearms PCI interrupt delivery for `irq_typ= e`. + /// + /// `None` means that `irq_type` needs no rearm write. That is the cas= e for `INTx`, which is + /// level-triggered, and which nova-core does not allocate. + #[expect(dead_code)] + fn pci_irq_rearm_method(&self, irq_type: IrqType) -> Option; +} + +/// 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..69bd092e38b5 --- /dev/null +++ b/drivers/gpu/nova-core/irq/hal/gh100.rs @@ -0,0 +1,30 @@ +// SPDX-License-Identifier: GPL-2.0 +// SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIA= TES. All rights reserved. + +use kernel::pci::IrqType; + +use super::{ + CpuInterruptHal, + 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 num_leaves(&self) -> usize { + 16 + } + + fn pci_irq_rearm_method(&self, irq_type: IrqType) -> Option { + match irq_type { + IrqType::Intx =3D> None, + IrqType::Msi =3D> Some(PciIrqRearmMethod::TopEnableCycleServic= ed), + IrqType::MsiX =3D> Some(PciIrqRearmMethod::TopEnableCycleSubtr= ee), + } + } +} + +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..590f0dc9a701 --- /dev/null +++ b/drivers/gpu/nova-core/irq/hal/tu102.rs @@ -0,0 +1,29 @@ +// SPDX-License-Identifier: GPL-2.0 +// SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIA= TES. All rights reserved. + +use kernel::pci::IrqType; + +use super::{ + CpuInterruptHal, + PciIrqRearmMethod, // +}; + +/// GIN parameters for Turing, Ampere, and Ada, which implement an 8-leaf = CPU tree. +struct Tu102; + +impl CpuInterruptHal for Tu102 { + fn num_leaves(&self) -> usize { + 8 + } + + fn pci_irq_rearm_method(&self, irq_type: IrqType) -> Option { + match irq_type { + IrqType::Intx =3D> None, + IrqType::Msi =3D> Some(PciIrqRearmMethod::ConfigMirrorEoi), + IrqType::MsiX =3D> Some(PciIrqRearmMethod::TopEnableCycleSubtr= ee), + } + } +} + +const TU102: Tu102 =3D Tu102; +pub(super) const TU102_HAL: &dyn CpuInterruptHal =3D &TU102; --=20 2.55.0 From nobody Wed Sep 30 12:58:54 2026 Received: from SN4PR0501CU005.outbound.protection.outlook.com (mail-southcentralusazon11011067.outbound.protection.outlook.com [40.93.194.67]) (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 1F08C386552 for ; Sat, 8 Aug 2026 03:11:43 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=fail smtp.client-ip=40.93.194.67 ARC-Seal: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1786158705; cv=fail; b=umvGPyUNDsixJUdIgV2LFK1StH0uNhMfzQz1P6btRLGoew+xcuC4BnHRHffDNQWr/fTv5TPIz0uiO7AiR0ZTy4FRTUINz/SUEiJcWLzGndZy8YJKkCZXa/bIETkRA38EvYiSWmidaFPuwuQY44V02VcLFxRtdDsqMG+tL8pAlZg= ARC-Message-Signature: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1786158705; c=relaxed/simple; bh=8KCF724iRLYCWGSoe2Ym3arkjE/Gr3YnmPjaObwKHd8=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: Content-Type:MIME-Version; b=PZR4lOIWoh8sC9V21cUCuDAkeyIG0lSpRGRV631W7vTcrbCgqWTgkdrQ4m2hFwILhcfS9opAwkA9FTJPiHkryHvt1G5tnBLjfMueSnbNhQ4/GaaoAYSbFcHPbYnkseqYiVllyZg5zhUYUd92iTnhOjb8b6GUO9VJuFjXWSzb13w= 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=J3D0sL14; arc=fail smtp.client-ip=40.93.194.67 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="J3D0sL14" ARC-Seal: i=1; a=rsa-sha256; s=arcselector10001; d=microsoft.com; cv=none; b=Y4VRYHU8xPMDfaG6BYIgEhDD9XxNcMKNL2nq3tsi3Xil+3m01019lwAFtkIKYka/oKv2a+CAOtNwdA3lgxsmu/3aBA0SFbLcFR+99FzQ8Ga5NxS4EMgbdeXeg+smSrh2As9mBXMMajnwUQM+2IiWF4EU7KvsTh0tfz7YbhlstJoW3qoHQpbZtU350UV+pMSCG3UT96z+aGjSAmBoAtYw0cLeuFnZ64o+4iZ+AM3k2VliTRuufrFYqQ1CphTLtFj85FB4nrBNzTbffTgpNICmad6Nw6wiuK3kwOwggUXyc37tkGtiCbKdho97sgVu0spSWkUTFRkrSM6pLDx00a7P0A== 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=wEwJM9Ej0oH8QMzktQxFkZB128Wrrk3AsPVSGFUtTak=; b=TrpK63eY53+9AiWPNpPzh4zhsbfsKyKPdfEmg/yX/UE5TQAcgPpHfZl6ic7PEU7FGf4xvpnti0Bil6Xz2CdnTXtjLKGVWQ8Foo2JighFZ7CsFNRjGVLyrtoi089RG5PdvtVChvxUsbe/DTNIGhuEfHrtKK6FKHnQAB4KOCRHdODxDkEiQsU8QnVce7uJFpGUsp9tOb/zVIYvwtxxlkOeZERFFrohofssjB8RnlESktDMVG10W9dqBEb/TgNorTHEyEaOPXU8PAgac9ck8M9xqS0Te2mROWnQOKR7pberEXBK6LWei2OC89ClRNEhc4eBeNhthjkkYX8SIfZ/74xscw== 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=wEwJM9Ej0oH8QMzktQxFkZB128Wrrk3AsPVSGFUtTak=; b=J3D0sL14O91Bec6pRuTnhQFoKDI5iQaM9fOSrhZPTi7QPmEjqSch8UOT8LixkjEwFWQCGkxa85JJXUxVdbyqfN2yXG2RY5PeWY2BmJNp8ityXnhw9Lb5QV2fmPzWaW7Pe7gdTQTpCQarD1rqDGsZ4fdDeS6PFrqYEfPPqVpIRCRrgw3KtWr8BMKYuCmIeIRkRzcSDpLUts5PCDdeZXnBsDDoLcECXdRj9x8PG19P8b7kqilgpFsItiJOJIy3uO01yyKw+5iM6CdXFM55Crq185pqDLewtVSDhN0Aujl1UYbewcT9lbUzVmlz0iVIn6bw4bdLl36UDYeF3it4AMo7BA== 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 CH2PR12MB4198.namprd12.prod.outlook.com (2603:10b6:610:7e::23) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.21.292.21; Sat, 8 Aug 2026 03:11: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.0292.022; Sat, 8 Aug 2026 03:11:31 +0000 From: John Hubbard To: Danilo Krummrich , Joel Fernandes , Alexandre Courbot Cc: Timur Tabi , Alistair Popple , Eliot Courtney , Shashank Sharma , 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 08/17] gpu: nova-core: allocate interrupt vectors for the serviced subtrees Date: Fri, 7 Aug 2026 20:11:10 -0700 Message-ID: <20260808031120.363869-9-jhubbard@nvidia.com> X-Mailer: git-send-email 2.55.0 In-Reply-To: <20260808031120.363869-1-jhubbard@nvidia.com> References: <20260808031120.363869-1-jhubbard@nvidia.com> X-NVConfidentiality: public Content-Transfer-Encoding: quoted-printable X-ClientProxiedBy: SJ2P220CA0009.NAMP220.PROD.OUTLOOK.COM (2603:10b6:a03:5da::8) 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_|CH2PR12MB4198:EE_ X-MS-Office365-Filtering-Correlation-Id: ea37f320-0ea8-495b-d6ea-08def4fabef6 X-MS-Exchange-SenderADCheck: 1 X-MS-Exchange-AntiSpam-Relay: 0 X-Microsoft-Antispam: BCL:0;ARA:13230040|23010399003|366016|376014|1800799024|7416014|10067099003|6133799003|56012099006|11063799006|18002099003|22082099003; X-Microsoft-Antispam-Message-Info: N45K2Z6t+lSVQYBdGxycDinDBakjpcTe7sAhElIeOlNL2hm9BKLIvV97gNn6T3WPq0K1HMtb5QJDSX7YqFdIWuZ6gQoG68FoCfEf+TDTBJjAKJU5yvZmYJdEPipzjOnqAbe4WxxRVIcsa1ZOGePe2i3L7kB/3x7sSMn1q4UV1DaUj8LbbzF164HzvqltBgzhdzYCZ6fblHBB+W7G0qOTGUT2nktZcNsYMJXfF/WqWWPpRrOi9n7aHz+GmMSDyCvzDiloBPflmAOr2vwlLDejbJXvtKMdmbLXvN8NtFnzNjm/WmFTGYZ3A+J6dIO0WAziTHRptUTC34Z1I0kqPGdjCT6ZEMki3350ETD/9jXiyxhVsYMMe0+kwYhC3d+t+nkKs8vXyXOx597NJaaUuSWDd9kdVZfYXMU23+CG8MOis4z1riDNDoS92dH6TkVB7KX22bK6gqH4fZ2k40Ep5yzDs7wgU/Z/M5amyTTOdfJvwM9c35Ks1SaLMUGkV7qQfNXnm8IaLZ+fsvFFqN6UjSKym5MPkBFrlw2LsL9hNob38YpW1iVvxA/dCQ/fOeyZRg2c/EzgnEWjeS+UtHiCXy+M8U91B4E4yk8fTop60cvbBQ9K0OcPxfw1AHGWeM9duC9VVFGftufxXcppj1OnIXVzwb/6lrDrX6vd06mCS9JwVck= 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)(23010399003)(366016)(376014)(1800799024)(7416014)(10067099003)(6133799003)(56012099006)(11063799006)(18002099003)(22082099003);DIR:OUT;SFP:1101; X-MS-Exchange-AntiSpam-MessageData-ChunkCount: 1 X-MS-Exchange-AntiSpam-MessageData-0: =?us-ascii?Q?kxxW1c7GIg1RFC6EkYvgHXXyGra2ZBtntX31zKAxjEWqc9ZzCtQFcS+sb+Bv?= =?us-ascii?Q?Mn4kLNa38OhXdd8EVn75LS1vg2VIOMGhkl29GxzN+Ue9mJyTfdHI8rlHqRCO?= =?us-ascii?Q?H4ynXEFFlReX3ZVPHe1H8nvWNYlBOtIXauVhlDvzZ78trhR1Lmp5SjVe+sPI?= =?us-ascii?Q?Gwgah/jtfD7fhFMQx2W0Q/FqPsP11qrmH2u1pPVSZddJbHkYXv+9DMRPtaZ8?= =?us-ascii?Q?IOwYvVQkTE8JtapMcZUSrtVW3N376M7xSBWJnjMOHrxTBkxG0Ib+5826k9d3?= =?us-ascii?Q?f9r59+4y+kheLmA+QyV5huffR6ElYbzRqoASvM02BTLkNkt79bX5JDy0LHI+?= =?us-ascii?Q?yErxGYcHNbq2iH1fsuDWeIg3+xvcidqBrGSZ9pqAdgnMCRug+B5dSecN7fCT?= =?us-ascii?Q?8vDD6w8qG82Ult9LjtNu8icy3oEHmg7GeTnEb0LMDLoWF6dXOdYqfvd7QeV0?= =?us-ascii?Q?d9pMTp1XXVqCF0dCFMhjllEa8f7kFCzJqgrqoltciiZhJU4NCS/oLLssCVAQ?= =?us-ascii?Q?GOXlxJ3dyaRbyPFqzMV0sUS6fB6aP9km8jMbVDTiVloGu+YGzKV1DsVYxX7k?= =?us-ascii?Q?RynZrYNEK+qEqYIAAK0CS5QHtdi7t+HAxZWX3eAueYpZOe84DfQ7VCkl+EJL?= =?us-ascii?Q?si7S9YMMjuegf2Y13yq6qRyf7r8XZRXoc+4tqUK63MFHCZxxkzYgaPEu2bdF?= =?us-ascii?Q?iO8lFCGFQ5LJNkOZthXt+LX9uGN7rAXE3fU/eLTUtp54dqNrMW/Hc9WZrMv5?= =?us-ascii?Q?RPIJnANM/N2UQf/GnVc8SV6RAupO5uJwD7VJnuqIhlK6eN4Flay1bXtugGCe?= =?us-ascii?Q?Am5XM15yJXnxhMDKAYViZthfefiQnO5fsDObnumitvYQKJkgsOHg8v2Dmb/s?= =?us-ascii?Q?k5fQy4YxTcCFPMaBAeXaztZV1lvHxXkLWk6w2CYa2++++yhXkXb75jh/9RwS?= =?us-ascii?Q?iRgqXELI0oz8TKdVZZiMXwTTlSoaBsi/bKQp7xCEwwisg58VXg1NOd6BgJiL?= =?us-ascii?Q?rokFBSt3C6VDQB2XvKaB28PApzRj14YNF4TFhgj1VdVaVQLbKy8FQRMNmAjT?= =?us-ascii?Q?3yeTJKSa2JR9qnpCFSMq9PNxSzz/8pzsq6ExNhdKUsF/vZTle3SKOiTeUupK?= =?us-ascii?Q?dyQ+1m6pcMfmJRpuZv1HurqxuPC0nc3uiQ8erZ5xfrlBrWhCZex3JAkfeT1w?= =?us-ascii?Q?+5AfEbCrkqFJVpeVx5AlV749dPfW09AXGeB0MEC7RK23niybbrvwi9u0rJ8K?= =?us-ascii?Q?ZfcYkM30RUbhdFyvIP0c/V41iHm50YSuKRy+rp6CdWeDDxJe4qhUZCaSnlcl?= =?us-ascii?Q?BI7Gd4+IoDGZYkB6Jb/mo2TfqpGaMgTR6g8pUZ8kqYFoQKUYp8gh85gu9Kpb?= =?us-ascii?Q?D5r6JEiVFYNr/TRHxUSKtIEL6Ij9z1PDt0GISiSEtMbjy1dd0X1BuqviZ8SR?= =?us-ascii?Q?PAgHqGbjkTq9984L/WNnt0nOh/gibXAp+4h1hrPWpTtBgzgh5xJb0dU5A0lH?= =?us-ascii?Q?145sgffpGQ27HBn0G6bJQfQ6vfp1xt0uV+Pk7StJ1tlqliP7c9mY1XTmdzic?= =?us-ascii?Q?euZEtzDXTGS4fbw8sbJlG1D8EqSy6j+5ilqSiVqeGt+h/59kbIaHqo8ZGjiT?= =?us-ascii?Q?EMmM04qj3NuGelDVlIYxFk88oucF4IzN5gzuouz5ECJ9g1vXCDLjN8uvbH//?= =?us-ascii?Q?6tkTeo03+Br0cs0PXWmcLmAk8vr5xbAIJTUaJG/1H7el8edd0ZV9TYJNkWvE?= =?us-ascii?Q?cL4jwiH68A=3D=3D?= X-OriginatorOrg: Nvidia.com X-MS-Exchange-CrossTenant-Network-Message-Id: ea37f320-0ea8-495b-d6ea-08def4fabef6 X-MS-Exchange-CrossTenant-AuthSource: DM3PR12MB9416.namprd12.prod.outlook.com X-MS-Exchange-CrossTenant-AuthAs: Internal X-MS-Exchange-CrossTenant-OriginalArrivalTime: 08 Aug 2026 03:11:31.8097 (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: eIcyze+djaMUyu26mHUlkyclZBAoLSUc3PAH7VhoiE7wilaE1D8/RQDXuwfanKKk0Tm7ka1Mc2XY8BxBAJzBDw== X-MS-Exchange-Transport-CrossTenantHeadersStamped: CH2PR12MB4198 Content-Type: text/plain; charset="utf-8" Every subtree nova-core enables at TOP needs an allocated PCI vector with a handler on it. How many vectors that takes depends on the type the PCI core grants. MSI has one message that every subtree raises, so one vector serves the whole tree. MSI-X gives each subtree its own table entry, and Linux masks every entry a driver does not allocate. A serviced subtree with no entry of its own loses the interrupts it raises, while its GIN leaf and TOP bits read pending and enabled. nova-core allocated one vector at probe, and the tree enabled every implemented subtree. Size the allocation to the serviced set: MSI-X entries up to the highest serviced subtree, falling back to a single MSI. Drop the INTx fallback, since nova-core does not share a level-triggered line. Enable only the serviced subtrees at TOP, and take the leaf count and the rearm method from the interrupt HAL when the tree is built. Assisted-by: Cursor:claude-opus-5 Reviewed-by: Will Pierce Signed-off-by: John Hubbard --- drivers/gpu/nova-core/gpu.rs | 6 -- drivers/gpu/nova-core/irq.rs | 78 ++++++++++++++++++--- drivers/gpu/nova-core/irq/hal.rs | 2 - drivers/gpu/nova-core/irq/interrupt_tree.rs | 68 +++++++++++------- 4 files changed, 111 insertions(+), 43 deletions(-) diff --git a/drivers/gpu/nova-core/gpu.rs b/drivers/gpu/nova-core/gpu.rs index 5efeba056f1b..42a4cd7971fa 100644 --- a/drivers/gpu/nova-core/gpu.rs +++ b/drivers/gpu/nova-core/gpu.rs @@ -29,7 +29,6 @@ Gsp, GspBootContext, // }, - irq, regs, vgpu::VgpuManager, // }; @@ -387,11 +386,6 @@ pub(crate) fn new( })?, }), =20 - // Allocate a PCI interrupt vector. - _: { - let _irq_vector =3D irq::alloc_vector(pdev)?; - }, - 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/irq.rs b/drivers/gpu/nova-core/irq.rs index ef77066e0514..2f0e2644b9bd 100644 --- a/drivers/gpu/nova-core/irq.rs +++ b/drivers/gpu/nova-core/irq.rs @@ -21,16 +21,76 @@ prelude::*, }; =20 -pub(crate) fn alloc_vector(pdev: &pci::Device) -> Result> { - let msi_types =3D IrqTypes::default().with(IrqType::Msi).with(IrqType:= :MsiX); - - let irq_vectors =3D match pdev.alloc_irq_vectors(1, 1, msi_types) { - Ok(vecs) =3D> vecs, - Err(_) =3D> { - dev_warn!(pdev.as_ref(), "MSI not available, falling back to I= NTx\n"); - pdev.alloc_irq_vectors(1, 1, IrqTypes::default().with(IrqType:= :Intx))? +/// 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. +#[derive(Clone, Copy)] +pub(crate) struct SubtreeVectors<'a> { + vectors: pci::IrqAllocation<'a>, + /// `TOP` bit of every subtree nova-core services. + serviced: u32, +} + +impl<'a> SubtreeVectors<'a> { + /// Returns the interrupt type the PCI core selected for these vectors. + pub(crate) fn irq_type(&self) -> IrqType { + self.vectors.irq_type() + } + + /// Returns the vector that delivers `subtree`, a single `TOP` bit of = the form + /// `interrupt_tree::vector_subtree_mask` returns. + /// + /// # Errors + /// + /// `EINVAL` if `subtree` names anything other than a single subtree n= ova-core services. + pub(crate) fn vector_for(&self, subtree: u32) -> Result> { + if subtree.count_ones() !=3D 1 || subtree & self.serviced =3D=3D 0= { + return Err(EINVAL); } + + self.vectors.vector(entry_index(self.irq_type(), subtree)) + } +} + +/// Returns the index of the allocated entry that `subtree` raises. +/// +/// MSI-X gives subtree `N` its own table entry `N`. MSI raises its one me= ssage from every subtree, +/// and nova-core allocates a single entry for it. nova-core never allocat= es INTx. +fn entry_index(irq_type: IrqType, subtree: u32) -> u32 { + match irq_type { + IrqType::MsiX =3D> subtree.trailing_zeros(), + IrqType::Msi | IrqType::Intx =3D> 0, + } +} + +/// 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. +/// nova-core does not fall back to a shared INTx line. +/// +/// # 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: u32, +) -> Result> { + // One entry per subtree up to and including the highest serviced one. + let msix_count =3D u32::BITS - serviced.leading_zeros(); + if msix_count =3D=3D 0 { + return Err(EINVAL); + } + + let msix =3D IrqTypes::default().with(IrqType::MsiX); + let vectors =3D match pdev.alloc_irq_vectors(msix_count, msix_count, m= six) { + Ok(vectors) =3D> vectors, + Err(_) =3D> pdev.alloc_irq_vectors(1, 1, IrqTypes::default().with(= IrqType::Msi))?, }; =20 - irq_vectors.vector(0) + Ok(SubtreeVectors { vectors, serviced }) } diff --git a/drivers/gpu/nova-core/irq/hal.rs b/drivers/gpu/nova-core/irq/h= al.rs index 8de2f6e536c2..cf2d1aa080fa 100644 --- a/drivers/gpu/nova-core/irq/hal.rs +++ b/drivers/gpu/nova-core/irq/hal.rs @@ -50,7 +50,6 @@ impl PciIrqRearmMethod { /// `serviced` holds the `TOP` bit of every subtree the driver service= s, and `subtree` holds /// the bit of the one subtree the calling handler serves. Each method= uses whichever of the /// two its interrupt type delivers on, so both are required. - #[expect(dead_code)] pub(super) fn rearm(self, bar: Bar0<'_>, serviced: u32, subtree: u32) { let subtrees =3D match self { // The written value is ignored, so any write rearms delivery. @@ -98,7 +97,6 @@ fn implemented_subtrees(&self) -> u32 { /// /// `None` means that `irq_type` needs no rearm write. That is the cas= e for `INTx`, which is /// level-triggered, and which nova-core does not allocate. - #[expect(dead_code)] fn pci_irq_rearm_method(&self, irq_type: IrqType) -> Option; } =20 diff --git a/drivers/gpu/nova-core/irq/interrupt_tree.rs b/drivers/gpu/nova= -core/irq/interrupt_tree.rs index 9f6cfed89bec..51add9f33c89 100644 --- a/drivers/gpu/nova-core/irq/interrupt_tree.rs +++ b/drivers/gpu/nova-core/irq/interrupt_tree.rs @@ -16,14 +16,16 @@ Io, // }, num::Bounded, + pci::IrqType, prelude::*, }; =20 use crate::{ driver::Bar0, - gpu::{ - Architecture, - Chipset, // + gpu::Chipset, + irq::hal::{ + cpu_interrupt_hal, + PciIrqRearmMethod, // }, regs::{ NV_VIRTUAL_FUNCTION_PRIV_CPU_INTR_LEAF as CPU_INTR_LEAF, @@ -82,31 +84,43 @@ impl Sealed for super::Pending {} pub(super) struct Tree { /// Number of implemented leaves in this tree, either 8 or 16. num_leaves: usize, - /// Mask of subtree bits the architecture implements. - subtree_mask: u32, + /// The subtrees this tree enables and services. + serviced_subtrees: u32, + /// Method that rearms PCI interrupt delivery, or `None` if the interr= upt type needs no rearm + /// write. + rearm_method: Option, } =20 impl Tree { - /// Creates a `Tree` sized for `chipset`. - pub(super) fn new(chipset: Chipset) -> Self { - let num_leaves =3D match chipset.arch() { - Architecture::Turing | Architecture::Ampere | Architecture::Ad= a =3D> 8, - Architecture::Hopper | Architecture::BlackwellGB10x | Architec= ture::BlackwellGB20x =3D> { - 16 - } - }; - + /// Creates a `Tree` for `chipset` covering `serviced_subtrees`, with = the rearm method that + /// `irq_type` requires. + /// + /// Each serviced subtree must have an allocated PCI vector and a regi= stered handler, which + /// [`super::alloc_vectors`] sizes the allocation for. Bits outside th= e subtrees the + /// architecture implements are dropped. + pub(super) fn new(chipset: Chipset, irq_type: IrqType, serviced_subtre= es: u32) -> Self { + let hal =3D cpu_interrupt_hal(chipset); Self { - num_leaves, - // Each subtree covers two leaves, so one bit per pair of leav= es. - subtree_mask: (1u32 << (num_leaves / 2)) - 1, + num_leaves: hal.num_leaves(), + serviced_subtrees: serviced_subtrees & hal.implemented_subtree= s(), + rearm_method: hal.pci_irq_rearm_method(irq_type), + } + } + + /// Rearms PCI interrupt delivery to the CPU after servicing `subtree`= , the `TOP` bit of 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, bar: Bar0<'_>, subtree: u32) { + if let Some(method) =3D self.rearm_method { + method.rearm(bar, self.serviced_subtrees, subtree); } } =20 /// Returns a [`Top`] handle for this tree. pub(super) fn top(&self) -> Top { Top { - subtree_mask: self.subtree_mask, + serviced_subtrees: self.serviced_subtrees, } } =20 @@ -131,9 +145,9 @@ pub(super) fn trigger(&self, bar: Bar0<'_>, vector: u32= ) -> Result { =20 /// Clears every pending bit in every implemented leaf. /// - /// The walk runs with every implemented subtree disabled at `TOP`, an= d every implemented - /// subtree is enabled on return, whatever its state on entry. The lea= ves cleared and the - /// `TOP_EN` writes both reach subtrees the driver does not service. + /// Disables this tree's serviced subtrees at `TOP` across the walk, t= hen enables them, + /// whatever their state on entry. The leaves cleared reach subtrees t= he driver does not + /// service, and the `TOP_EN` writes do not. /// /// Call `drain()` only during probe. It must not run concurrently wit= h an interrupt handler. pub(super) fn drain(&self, bar: Bar0<'_>) { @@ -152,19 +166,21 @@ pub(super) fn drain(&self, bar: Bar0<'_>) { } =20 /// Top-level view of the interrupt tree, enabling and disabling whole sub= trees. +/// +/// Both writes cover the serviced subtrees alone, leaving the rest of the= tree as it was. pub(super) struct Top { - subtree_mask: u32, + serviced_subtrees: u32, } =20 impl Top { - /// Enables interrupt delivery for every implemented subtree (`TOP_EN_= SET`). + /// Enables this tree's serviced subtrees (`TOP_EN_SET`). pub(super) fn enable(self, bar: Bar0<'_>) { - bar.write(CPU_INTR_TOP_EN_SET, self.subtree_mask.into()); + bar.write(CPU_INTR_TOP_EN_SET, self.serviced_subtrees.into()); } =20 - /// Disables interrupt delivery for every implemented subtree (`TOP_EN= _CLEAR`). + /// Disables this tree's serviced subtrees (`TOP_EN_CLEAR`). pub(super) fn disable(self, bar: Bar0<'_>) { - bar.write(CPU_INTR_TOP_EN_CLEAR, self.subtree_mask.into()); + bar.write(CPU_INTR_TOP_EN_CLEAR, self.serviced_subtrees.into()); } } =20 --=20 2.55.0 From nobody Wed Sep 30 12:58:54 2026 Received: from SN4PR0501CU005.outbound.protection.outlook.com (mail-southcentralusazon11011067.outbound.protection.outlook.com [40.93.194.67]) (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 4A8ED385D97 for ; Sat, 8 Aug 2026 03:11:45 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=fail smtp.client-ip=40.93.194.67 ARC-Seal: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1786158707; cv=fail; b=LFR5OSUL4ASukkXx5/3rSuFbxyvMS0cG2nMXAgIp2tEVoFNlVInZYNwdEcxgL5gD+wiI7xjNGn8vx+7gsg52thUteRqA+8lclfBSkvhNUhaMp+sDiBIcHswUuVq62k3+jZ/yvP4/FX/IhoaL2HPq8SUjh5LXKIl/Ex64QMul97g= ARC-Message-Signature: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1786158707; c=relaxed/simple; bh=h/OEvV6mHB2cRCJ1fu61N3g3vvab0X8aNxBLbhmM2Cw=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: Content-Type:MIME-Version; b=qb6FhhIwIpyVoCvrEyOWT9kOSwYzuJfHN0dXtg2mYq7J7fXPgno/jkTn7CoIOvdd8LBxlZnTbaNtMUxbUhclRdbowo3AOARL5V9Gq1Rm35dvWpWFxC73a3jh5L1i8VdtBaixJlstA3vlgwTh9A+OH+m5ZlfCY4HJhLCB3vbcx5o= 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=cBMrV5jQ; arc=fail smtp.client-ip=40.93.194.67 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="cBMrV5jQ" ARC-Seal: i=1; a=rsa-sha256; s=arcselector10001; d=microsoft.com; cv=none; b=y5MtDcSZqB6LEYNvCm74ZZMH61qDlm5Hz8c/QxKSWib0JL5tFi78Y4AZP5SQ7lGRp3NCUiIVP8ZvrcGSovDfIPtoL2Jk36V2aaqTNnYRssrh6mxELDK9QgWKZX20U57HfSnBQ11NewXkdc2EEE/40NMNN405oDRp7fgJWs+DS938gppR4Sw8O7nBgR25qgH/c3msB5jSQOAblxYLNUJVPpES4GWNtrIMAMAdF084pRKfmXrGKezGaJbnFbJU8cU3u+NIX7FqP+eFpd5FbaRgMQN9o6aiC/Sd8UJ86UWDBEZZy/FQ1C74zVU5Y/MJ26gZqP3fWXBtKN8YTGTEWP1uYw== 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=Fm/yXqP5fHfSDpWEZU7/kpj9Jsp8R4UxSErzsc6Id2E=; b=eFWYyuaCNA4Rl70dDM6jy3oDWzupV4n0PohdTAfwyKGkJQn4pJd5NQ9O8vdWchPH69MYoS7m7KoXEJ5k4ZomQiAImt6dE2e7sbSLpODStj/5DxZMnRMR4PjPQy4kfhjDqDL4YbnV+L2EjtGvnegi5XHP8xZyu0ob8uwErBK1wHTyDYDgfNegzCtx075lGCsOVhpMbwOk1Ztsq70awFva6g79hZirpWNP6fwi6KfjwCoqMRsq247kEJ8h5YG36pfGRO++rauCkFyiLsrL174zrbg/mOEFS5z+Kc7a+sAmv7hGAHRbLyrJKwxa1De1y/SIWsfohAxAxZK9BKAgSlYcPQ== 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=Fm/yXqP5fHfSDpWEZU7/kpj9Jsp8R4UxSErzsc6Id2E=; b=cBMrV5jQMiK8jIEUtMUPcnteo+U6jbyxy7NdW5G1l7rhMGWFtDkMaHqvWJrNQvuZc2RyqaWsg/TOIFcR4otjsMv7cfeTFXVPFVKTIzTMHtSaPrkkMFxQcne7LAqHWTcamI364hapX1xQ8/5ko66Yg6Xgrlf1AAK/6S7M2KGxMpCLLVNDrXTC01f5vw7iDTyY49Fkme400qG8b6udEACdhnuWI02Za6KMdVINWfN1gWAhWCTdMha04Fk3K4KiAG68H/DuNcqVvbMpN9yD8+lZGHi2l11apLESd5DGRD6rkLFQog53XceM2wPGhKdeBODZ6mG0VY61XwYsLOr2qlP9ow== 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 CH2PR12MB4198.namprd12.prod.outlook.com (2603:10b6:610:7e::23) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.21.292.21; Sat, 8 Aug 2026 03:11: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.0292.022; Sat, 8 Aug 2026 03:11:32 +0000 From: John Hubbard To: Danilo Krummrich , Joel Fernandes , Alexandre Courbot Cc: Timur Tabi , Alistair Popple , Eliot Courtney , Shashank Sharma , 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 09/17] gpu: nova-core: add an interrupt delivery self-test Date: Fri, 7 Aug 2026 20:11:11 -0700 Message-ID: <20260808031120.363869-10-jhubbard@nvidia.com> X-Mailer: git-send-email 2.55.0 In-Reply-To: <20260808031120.363869-1-jhubbard@nvidia.com> References: <20260808031120.363869-1-jhubbard@nvidia.com> X-NVConfidentiality: public Content-Transfer-Encoding: quoted-printable X-ClientProxiedBy: SJ2P221CA0013.NAMP221.PROD.OUTLOOK.COM (2603:10b6:a03:5db::8) 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_|CH2PR12MB4198:EE_ X-MS-Office365-Filtering-Correlation-Id: 48c241bb-0b6b-4ae0-3f7b-08def4fabf9d X-MS-Exchange-SenderADCheck: 1 X-MS-Exchange-AntiSpam-Relay: 0 X-Microsoft-Antispam: BCL:0;ARA:13230040|23010399003|366016|376014|1800799024|7416014|10067099003|6133799003|56012099006|5023799004|11063799006|18002099003|22082099003; X-Microsoft-Antispam-Message-Info: qIMqoXxOJ5rlsTIVPSc9GN85eVykDnkfkKkrjqLckqAFSP8AewSKpBGd+F0Nfc44Ms6tVrpgxlUJ6Jw255FAOX0wwl/8BCO57CS4qye4aHyeg958HHZZV9MXlDgIcXQ/54ZMRs+WZ17K01NBfq7k5BVrnjpQeQ+ybuItWYQ1JvdVpHExCwZUX167xCQOTmeIOilH+TRTixjzhmWMG5sFidF04cwVP992ic5NCr3mbDD+crfzYf6qMpTmOWiUWRuCvKFbvEbuhxXu5R4PwFvmaAcjJ3v5nuftbASL7YnZkAUkAAxtmh8FhdA3ee1DN3phRboTIk7Y1EGs9eAp4WaaqfJjhHYXMRjYVLHnnkln+YvkLxE7LQY+nbZfEqttqt1jy3WM21LZfKyTft9rUHTjsTX2K8h6CJPBmUvgjvmvNATfCzF6598zPwPeMHAs+NXa8LRd393ruyblVOv8Ag9Gq3CaqXH9Gjmtoe5zoE6/WyKumZaa6K198KlLQAkXnFNzQ6ArBMJt5JwV99vz62AeMz0Ul+NKE2f00DjIS5RD7ANPgct+rhB/ouYWrT9r3ZAqI0SxhEd55q26opBS7emDrJ+MTkf0eTRBogiX9LddBdE81bHaGYMELPxth0K4a5QJ0360COQZLVi+t09c5cbmEqZQ3updoOO6Z0ommLWHdSQ= 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)(23010399003)(366016)(376014)(1800799024)(7416014)(10067099003)(6133799003)(56012099006)(5023799004)(11063799006)(18002099003)(22082099003);DIR:OUT;SFP:1101; X-MS-Exchange-AntiSpam-MessageData-ChunkCount: 1 X-MS-Exchange-AntiSpam-MessageData-0: =?us-ascii?Q?7zlOpZctvk1b140lXaj9mVOcXSEX1MyxQfIzMS9Jafl1qUs50wiSNiNb+xX5?= =?us-ascii?Q?mV/MwO/E8mffk46otcc9CWKNUCzrNTjFz0zIy/5LPdV6HiM3A0BEhDhheRoq?= =?us-ascii?Q?iCN10tuCZcWm3Bkom8VDJx65KqknCtMy//qWkzXl1pUML0XqdhVaJd5DltJQ?= =?us-ascii?Q?dsuubXpA+GFe9266sTXLfNd2kjUZvYEzyT0Rg3r+i1pag1YEpaopWHPdzb4A?= =?us-ascii?Q?OQRRFbKNdNXzMbXCJnaAq2f8/ozElvRc10dCUQkLExOBryyOs7nbDgLfndoG?= =?us-ascii?Q?qrtNOAiq6oczcHyQcuTlGp3njfb9+JAupniQdj+s01j3w9wDQXf+9Yd50lOY?= =?us-ascii?Q?MGVQ602U6oqQUdZgsDsbtioH2GxYmPAp95KL1L4UrRmxSZqOnZi5fJowp/At?= =?us-ascii?Q?PGxOPTcV4ahDstsCIoif0DBkIfF4IsHbltEFyIRavxYDpTSNEkYFQNDbAeQ0?= =?us-ascii?Q?wIC2PW95nGrYP2IzXs2+77AvVwjkwJ5tewRoqJPQNYsK4rXqfiF3fzOdC3D8?= =?us-ascii?Q?ItZ/Hy5fUtPSDpeOHjWwiVcdX9KRVJo/kK1+Habeo08wTTTEB3GVsp78A9e2?= =?us-ascii?Q?Vn79hKvdyzfYb4BNuHm8g/DlirNSWg3UqSIsmCEz+WL5oSxXpMn0bemLBUZT?= =?us-ascii?Q?R09tZTgiHptdbSM2aMOu+va8RoiiZBfdO3RoFG8ly08HnCyh4DPz28VEO6Eh?= =?us-ascii?Q?7IfNNt9fEqFo1pJURuxLZq+KxlvvmxNUo/L8MCsysdOJYwryW2kBazp1FgyC?= =?us-ascii?Q?xB9EZrCQv+GaQIEUM/RPFIDpOV8XNjJyTtsC4a30PsPXMcPKPnqIeD2K+N85?= =?us-ascii?Q?55PTFkFbcr7KLataW4jj6NWhZzn0uvpYDza5QEakpZgt+/EmtScqBVegvIlt?= =?us-ascii?Q?lAPgne+7/ZwxxW4gYMw5xsUb5NZ3iKV+ta+GSKNoXcTZahfJrsdwb8XLIzvg?= =?us-ascii?Q?1KwTg4GaRgqyxeGPvvb8uO70TYdVsrT5daF4EnKFWA5EPwPxTW7vrASjkI3y?= =?us-ascii?Q?vg22DYpPl3wOV3hm4eMISQqTUkuge6jnd1ozzfaBzq+sF3633uH0zzVEa/3Q?= =?us-ascii?Q?NjMf1jce3W176rcuh2NlG6ItnOZUM/0C1giHqa68SzUQfaWVX1OOGUW/gXsy?= =?us-ascii?Q?hp82gk/Ofw++uEEio0BAi9S142ZeexviO24DR/UIiTPTJk0o+cP5FFr8sbgI?= =?us-ascii?Q?Xj9RyLjdUik1CIDV1bBnGB6S01eHeW0ESmhBHp/3bdUYpkqgMbBYmmp6/0zP?= =?us-ascii?Q?HdyK0nKP0MM9fJ3bSJi2j7Qp54y0DGqJfidkRn8le3NOFy1UqoOziiv1I6zD?= =?us-ascii?Q?N/28yYW6sH6H1T2X6GVdg4kO9RCid4xMS/ZAY3uGoWGBtz9BcyRIxnEWiTi4?= =?us-ascii?Q?0hJCcoXBj1Flu3/ZBDvIhLpFATX7F5e3QDyQxl92UPaWb5RPRPwoXhmMQ6xQ?= =?us-ascii?Q?9WIATqIlKvKjX8g978bylXzeSCtfmgq2J0+U7P1GDxBzPw3QJQ3HhRJF4r8r?= =?us-ascii?Q?lrHlA2L13U3DvydRkLv2wg8xj29ppwuNisd2kaWGzHsYHewUptVYfhI+Jmbh?= =?us-ascii?Q?g9DRBipEf3Rp0r30ThMQI4VfI2rngNaNKIPb6Xj7PsSDdfx+moa1uTx80XWc?= =?us-ascii?Q?ySui1zvLaSRwfpmcYwdF91TG4imMpBl/DSSbzpC2V2hSIYye6J4hp9JcH1BR?= =?us-ascii?Q?wBNe/T/5AiQrZB91tDL+azBok5D+KZ4hNCgPJArbnmtZaG/INL0BLbD7YNsZ?= =?us-ascii?Q?6d4kq1Db8w=3D=3D?= X-OriginatorOrg: Nvidia.com X-MS-Exchange-CrossTenant-Network-Message-Id: 48c241bb-0b6b-4ae0-3f7b-08def4fabf9d X-MS-Exchange-CrossTenant-AuthSource: DM3PR12MB9416.namprd12.prod.outlook.com X-MS-Exchange-CrossTenant-AuthAs: Internal X-MS-Exchange-CrossTenant-OriginalArrivalTime: 08 Aug 2026 03:11:32.8600 (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: LPO39b2j1ud7h6yypK8Mf8mtAkoG3to4EAhlpjQvEbN/yxGKdOR1/UhzBnSRLoPkhmUKvGsBr3713Hnj26rBJw== X-MS-Exchange-Transport-CrossTenantHeadersStamped: CH2PR12MB4198 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. 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 | 8 + drivers/gpu/nova-core/irq.rs | 2 + drivers/gpu/nova-core/irq/doorbell_test.rs | 324 ++++++++++++++++++++ drivers/gpu/nova-core/irq/interrupt_tree.rs | 13 + drivers/gpu/nova-core/nova_core.rs | 2 +- 6 files changed, 363 insertions(+), 1 deletion(-) 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 42a4cd7971fa..d5df0ebf67ae 100644 --- a/drivers/gpu/nova-core/gpu.rs +++ b/drivers/gpu/nova-core/gpu.rs @@ -347,6 +347,14 @@ pub(crate) fn new( .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. + _: { + #[cfg(CONFIG_NOVA_CORE_IRQ_SELFTEST)] + crate::irq::doorbell_test::run_selftest(pdev, bar, spec.ch= ipset)?; + }, + // 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 2f0e2644b9bd..5b449759b333 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; =20 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..fae770339fd7 --- /dev/null +++ b/drivers/gpu/nova-core/irq/doorbell_test.rs @@ -0,0 +1,324 @@ +// 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::{ + vector_leaf_bit, + vector_subtree_mask, + LeafIndex, + Tree, // +}; +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: u32 =3D 129; + +/// Leaf and bit index of the doorbell vector within the interrupt tree. +const DOORBELL_LOC: (usize, u32) =3D vector_leaf_bit(DOORBELL_VECTOR); + +/// Leaf holding the doorbell vector. +const DOORBELL_LEAF: usize =3D DOORBELL_LOC.0; + +/// Bit of the doorbell vector within its leaf. +const DOORBELL_BIT: u32 =3D 1 << DOORBELL_LOC.1; + +/// Subtree carrying the doorbell vector, and the only subtree this test s= ervices. +/// +/// Derived from the vector so that changing `DOORBELL_VECTOR` moves the a= llocation, the subtree it +/// enables, and the handler together. +const DOORBELL_SUBTREE: u32 =3D vector_subtree_mask(DOORBELL_VECTOR); + +/// Index of the subtree carrying the doorbell vector. Under MSI-X this is= also the index of the +/// table entry that subtree raises. +const DOORBELL_SUBTREE_INDEX: u32 =3D DOORBELL_SUBTREE.trailing_zeros(); + +/// 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> { + /// Borrowed BAR0, for register access from interrupt context. + bar: Bar0<'a>, + tree: Tree, + /// 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 { + let bar =3D self.bar; + + // 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 + .leaf(LeafIndex::new::()) + .read_pending(bar); + let pending =3D leaf.pending_bits(); + if pending & DOORBELL_BIT =3D=3D 0 { + self.tree.rearm_pci_irq(bar, DOORBELL_SUBTREE); + return irq::IrqReturn::None; + } + leaf.clear_vectors(bar, DOORBELL_BIT); + + 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(bar, DOORBELL_SUBTREE); + + match count { + 0 =3D> { + self.first_pending.store(pending, Relaxed); + self.first.complete_all(); + } + 1 =3D> { + self.second_pending.store(pending, Relaxed); + self.second.complete_all(); + } + _ =3D> (), + } + + irq::IrqReturn::Handled + } +} + +/// Teardown guard for the self-test. +/// +/// Owns the IRQ registration so that every exit path, including an early = error, tears down the +/// interrupt in this order: disabling the leaf stops new deliveries, drop= ping the registration +/// runs `free_irq()`, which waits for a handler still in flight, and only= then are the tree's +/// subtrees disabled, so a late handler cannot rearm them. +struct SelftestGuard<'a, 'r> { + bar: Bar0<'a>, + tree: Tree, + doorbell: LeafIndex, + reg: Option>>>>, +} + +impl<'a, 'r> SelftestGuard<'a, 'r> { + /// Returns the registered handler. + fn handler(&self) -> &DoorbellTestHandler<'a> { + // `reg` is `Some` for the whole lifetime of the guard. Only `drop= ` clears it. + self.reg.as_ref().unwrap().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.tree + .leaf(self.doorbell) + .disable(self.bar, DOORBELL_BIT); + // `reg` is `Some` for the whole lifetime of the guard. Only `drop= ` clears it. + self.reg.as_ref().unwrap().synchronize(); + } +} + +impl Drop for SelftestGuard<'_, '_> { + fn drop(&mut self) { + self.tree + .leaf(self.doorbell) + .disable(self.bar, DOORBELL_BIT); + self.reg =3D None; + self.tree.top().disable(self.bar); + } +} + +/// 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 +/// +/// `EIO` if the doorbell is already pending before the test, if the deliv= ery 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 a= rrive within the timeout. +pub(crate) fn run_selftest<'a>( + pdev: &'a pci::Device, + bar: Bar0<'a>, + chipset: Chipset, +) -> Result { + // The allocated interrupt type decides how the handler rearms deliver= y, so the vectors are + // allocated before the tree is built. + let vectors =3D super::alloc_vectors(pdev, DOORBELL_SUBTREE)?; + let vector =3D vectors.vector_for(DOORBELL_SUBTREE)?; + let irq_type =3D vectors.irq_type(); + let tree =3D Tree::new(chipset, irq_type, DOORBELL_SUBTREE); + let doorbell =3D LeafIndex::new::(); + + // 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, + DOORBELL_SUBTREE_INDEX, + irq_type, + ); + + // No delivery may reach the CPU before a handler is registered. `drai= n` enables the top level + // as the last step of its cycle, so disable it again afterward. + tree.leaf(doorbell).disable(bar, DOORBELL_BIT); + tree.drain(bar); + tree.top().disable(bar); + + // 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.leaf(doorbell).read_pending(bar).pending_bits= (); + if pre_pending & DOORBELL_BIT !=3D 0 { + dev_warn!( + pdev.as_ref(), + "interrupt self-test: failed, vector {} already pending (leaf[= {}] pending {:#x})\n", + DOORBELL_VECTOR, + DOORBELL_LEAF, + pre_pending, + ); + return Err(EIO); + } + + // `try_pin_init!` moves its captures, so the handler takes a clone an= d `tree` stays available + // for the guard below. + let handler_tree =3D tree.clone(); + let handler_init =3D try_pin_init!(DoorbellTestHandler { + bar, + tree: handler_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 `guard` below and dropped = 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 { pdev.request_irq(vector, 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, so hand the + // registration to a guard that does so on drop. + let guard =3D SelftestGuard { + bar, + tree: tree.clone(), + doorbell, + reg: Some(reg), + }; + let handler =3D guard.handler(); + + // The handler is registered, so the source can be enabled. + handler.tree.leaf(doorbell).enable(bar, DOORBELL_BIT); + handler.tree.top().enable(bar); + + handler.tree.trigger(bar, 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(bar, 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. + guard.quiesce_source(); + + let count =3D handler.irq_count.load(Relaxed); + let first_pending =3D handler.first_pending.load(Relaxed); + let second_pending =3D handler.second_pending.load(Relaxed); + let residual =3D tree.leaf(doorbell).read_pending(bar).pending_bits(); + + // 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_BIT + && second_pending =3D=3D DOORBELL_BIT + && residual & DOORBELL_BIT =3D=3D 0 + { + 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_LEAF, + first_pending, + second_pending, + residual, + ); + 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 51add9f33c89..73f5afadea3e 100644 --- a/drivers/gpu/nova-core/irq/interrupt_tree.rs +++ b/drivers/gpu/nova-core/irq/interrupt_tree.rs @@ -270,4 +270,17 @@ pub(super) fn clear_pending(&self, bar: Bar0<'_>) { } } } + + /// 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_pending`], which + /// clears every vector the leaf had pending. + pub(super) fn clear_vectors(&self, bar: Bar0<'_>, vectors: u32) { + if vectors !=3D 0 { + if let Some(loc) =3D CPU_INTR_LEAF::try_at(self.index.get()) { + bar.write(loc, vectors.into()); + } + } + } } 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 Wed Sep 30 12:58:54 2026 Received: from CO1PR03CU002.outbound.protection.outlook.com (mail-westus2azon11010069.outbound.protection.outlook.com [52.101.46.69]) (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 DCCD3388E7A for ; Sat, 8 Aug 2026 03:11:46 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=fail smtp.client-ip=52.101.46.69 ARC-Seal: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1786158709; cv=fail; b=JB1nXqgPrFEZplO0pwIZAn0pfRRCfIv7Z+trCSjCCNTOQlrOtErmosUv3s9SdOfygcKBKniFsBGbgq6FwbLKm/NR/PcMp4r7kJCQFjmTEk8hSZv5zwO+L1m1mzM3T5IlcGNpVaK7BgPCVWmV5/hmqGSAc/OB4DrFUJSDnfXRcB4= ARC-Message-Signature: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1786158709; c=relaxed/simple; bh=b9HzY3kJVVTLGqS0zdMEDaHaL2S8Rmd+KC/3NRetZTc=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: Content-Type:MIME-Version; b=NuLHqNYAKQGd1JpqNVBcM7zctzNAS4qcP2CuiSctNuboGs9Nllnon79Ul/tNeAxSAMEsqhHaJM6Hir+i9yIghcCNEVbUHzp504wwPZEkLNPrqCdWzxIuEZhOjXA10Y1kdaCBtQ9DMjsG+Nd/R5njP1oeMIFVYmR4O27eFVr2ydE= 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=fzkGGis5; arc=fail smtp.client-ip=52.101.46.69 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="fzkGGis5" ARC-Seal: i=1; a=rsa-sha256; s=arcselector10001; d=microsoft.com; cv=none; b=pps3sonoKbMCxH5i6192wyNFP7ZNxstsv9AnNjCpIouK8zc7e0fjkCu6aPsQ523WgZERWNhmpkU5uOrZq5BqpjsaYsswaKnsOP1jANyzXbnedT8W3Hkoc7ckmE6IAvx9FCdowJNPXgv4NDzEwLPl+XdrLU5SqeUyaJKTiusUNN/ijIOEcgN1bnAKtUni9XcDzn9vW/USuqdNRUmmN4lyTmlcTKf6+G2pdWocuV7AOiF+JJ31Nfv45fUl1yPdIAnR1H+RjAZLsL6lM+D96kZMGdBHNe80hD8Lv2IaW34KyhI32XXFLt8lNThkPW5SgV7coEQi8qvkMlnFW1xryh0N7w== 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=Mlk5ak3/7QCGT1Ud2zxMof2+83i8+FVYy8dkXQSeS1U=; b=GFSzWHbj11DB1FvDVHfY6DYHDXKr/eDB5S9A3siIWn4JugS7LocxYwFU9bG8UMhyLKz9x8D10CdDi1NhajbPq5EVcnIJXlFVBZfW8czlE2CaEpSKHLuPtcUZxp7qxT3qTKtdP61Dc3JgFVIUgcNSBAL3cJVE/teRGqmIZ4kDGG7Mt0e9aCY61GM4k+0Yx3iQwG3CFTVOXwazIF+SnOxTPq3227JDwEQ6sCxYkNcoP2rh7E7hAIEdEVd0/QiuQ7UAffvzjw3XNzTlAw+8zDHPGZpng4q/HFN76CxWPjnyFSOZXS0+mvLUQbG5cghhwYdkGJm5k2mRxTeB4P/YFyUVGg== 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=Mlk5ak3/7QCGT1Ud2zxMof2+83i8+FVYy8dkXQSeS1U=; b=fzkGGis5lbnpcHygkGWLKnnWputA3tmBqng1OooXki2vbDNr6KO3ZwiUaWTtqnFAvNLu4Vdz/xIprKZDWWVHqbWT4BLMnQDsUFkvRLW8SQ4W2krwbfeUsPpN+b739AhjFah7Tr6pkJ7SP3ftgK/epqY6AQUj9O3/WpmopxfHTmCWmje2zZrEZBOQCxNsNU/aLFm9FHbUB4R7rWOSZp3ddjROs3bShUh1ClZusAalSDTdXA4E7SqhTenrmMSPxZ4x/Jdf4OAZt42FL0dLPOwQtsAl4DW4sOqP7s3CVkAwWd7dJAWg6zJ1xfc7miKDZG2d+m4EO2iVud948q+W+vZdzw== 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 CH2PR12MB4198.namprd12.prod.outlook.com (2603:10b6:610:7e::23) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.21.292.21; Sat, 8 Aug 2026 03:11: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.0292.022; Sat, 8 Aug 2026 03:11:34 +0000 From: John Hubbard To: Danilo Krummrich , Joel Fernandes , Alexandre Courbot Cc: Timur Tabi , Alistair Popple , Eliot Courtney , Shashank Sharma , 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 10/17] gpu: nova-core: dispatch GSP events instead of discarding them Date: Fri, 7 Aug 2026 20:11:12 -0700 Message-ID: <20260808031120.363869-11-jhubbard@nvidia.com> X-Mailer: git-send-email 2.55.0 In-Reply-To: <20260808031120.363869-1-jhubbard@nvidia.com> References: <20260808031120.363869-1-jhubbard@nvidia.com> X-NVConfidentiality: public Content-Transfer-Encoding: quoted-printable X-ClientProxiedBy: SJ0P220CA0009.NAMP220.PROD.OUTLOOK.COM (2603:10b6:a03:41b::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_|CH2PR12MB4198:EE_ X-MS-Office365-Filtering-Correlation-Id: ac985e98-5aac-47b6-8d48-08def4fac07a X-MS-Exchange-SenderADCheck: 1 X-MS-Exchange-AntiSpam-Relay: 0 X-Microsoft-Antispam: BCL:0;ARA:13230040|23010399003|366016|376014|1800799024|7416014|10067099003|6133799003|56012099006|11063799006|18002099003|22082099003; X-Microsoft-Antispam-Message-Info: +KRCqMsjCnDBLlutniEwBcBpM56DC+yX0HlLxofFVUggnWZO+j1Y16uovDOd7tNkb1cqhYVsoGydSku+Gcl4BMvXMj/pn+7/C1N06iFO20KBtYgBmeYyw2kDEXDpnZokfvFsYEPzlVnNbpXRHYvRKHw9AK/ovrnuob54hcFaMosYNc19AQ1HNoUNST6hKKksfOvdsj9lBL1VPo78pemBiovW+jxcKUxbVrnEKddMnDFF4P/nUvbnU6+IeIYxLMhxi5oR0/N+quo0CJX/Ggx/aD72EhgTcpk4drbpgf1DX4BYU82OeXExAPXhBp8GzNFLmgNzxauYPZloPDqeGukRfsgG3illX138pJF9e1nAdk+kZ4UrCdayCZwPjndKgUbP7J4U6Iq6vMjryqykwIUvfjGoVrcUNbpOzjXRu+vxEtLCNO9mryyy4z6cTcAdgEF3eh0tx4IToLkhhmMiUCju/ysdMjxAigwyM/aKcg3QSdOFCkuDMSS9hwT0vM6Ea+J6R/jqf10rtb1F19PnjRPTjLi4QKGn07vpFI4oq/XKWZYKmzG3YOag9dPyWWiozglmIvetg5qF623pe/6DQwSBiKO9qh2ZVOdTOyRXxgA8zYumSEoRw5OhcHixiCIL18pfbGFpQqq/vKZVzHFFhrzW+WZPDaRHmWsU85aJjj9Hs+g= 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)(23010399003)(366016)(376014)(1800799024)(7416014)(10067099003)(6133799003)(56012099006)(11063799006)(18002099003)(22082099003);DIR:OUT;SFP:1101; X-MS-Exchange-AntiSpam-MessageData-ChunkCount: 1 X-MS-Exchange-AntiSpam-MessageData-0: =?us-ascii?Q?Nu5tzc2EfG/r16HU/BjLU9AzfDVdacTOVEBDXPmx/k4uuh91svrz4amzObLp?= =?us-ascii?Q?TjMaet3L6riwPMnC05CxX0kTuiW7EgXS8mX3oJcAiR3UN57ORJMNSnAINACy?= =?us-ascii?Q?zE+XL41zWjH87ORdBTKTJIaLg3zwXlNpzpRLn+dizpFb+AJi6qxaGYZ4KJVw?= =?us-ascii?Q?6fpEWM4ordyz7Bvt4jyHdH7ldy4Nlb1etZgkrghSajywOhpqL2AksBR2/vim?= =?us-ascii?Q?SIR03ZnArsdrT5ZNLKKSEkNGSsST2QejrHZtNVUDvXkD2zVcPncOW37csx9l?= =?us-ascii?Q?0t0NPXEZZz2vQAy45cATMJsjButHaTrS6NqnOZmMVcGpk3KvIDNpFuGkFCv+?= =?us-ascii?Q?Sp6j8zxezHHohbSzXzj+Kv8Se3HuhmXJo40xWmiE8qWf60F+UnWY/OQG52Xt?= =?us-ascii?Q?pZ8AKpv9JxCO3BD8tV8VHrZtZZBtq7B37VSlWdsdOqRq+X831hkqII+vAIGX?= =?us-ascii?Q?sHo5/VOt8xhTeWkZnyalUTmkpvUIqTuc8Eap8Ax4TXHVc3BRATfD4THVLvjF?= =?us-ascii?Q?gnYBglPhwg0PMjEmyL2cCEbgo4zGA+zEW9ib74vh6E0mw5wlxwFHM5fy+Ulb?= =?us-ascii?Q?45/QGwKD5G8NebK8S/zPSIBedPJ4/G+ZmQF2z147F6DSSCzmbbOuG+1Q6FOI?= =?us-ascii?Q?gNavZPrIKMRA591XR9mUQw0mT7ZXTnjWntD+yrWO4z2TGmfrUDLGiO347zjb?= =?us-ascii?Q?eEyxMX/bj1jGeyVnSzGNRtdyf+Neq7P1lJhEa91xvutTkiAsqv8d8/eevXXF?= =?us-ascii?Q?LAQUABA48Rz5xqeWUEx83oR9GV1y8LL8KDVNypcnQweTM9RVqjOtlEB199a+?= =?us-ascii?Q?J2MBv4CJEMozbRD3W6KQKdoiIS8CYS8jcDyd15UUH2JGCF76FLSOvZixljLq?= =?us-ascii?Q?DWeO1ZHKvxiF6DIuD9xoXDW7856hRS9VLQstX540wA/DxjeM50DTccLgDuiZ?= =?us-ascii?Q?mocdwo1aChp96z8cRO/ACU/FExV063cqmGw8X5PYv22sFy9ksXz5xJBjI/A8?= =?us-ascii?Q?rUK3sYvJ/mIxmgCgoi1tzvqTE4Z5u1imFEZJffyFjOsG0+bf8u6IVgiqE+Mp?= =?us-ascii?Q?EuqcfEywPmDagq9QhrQolJLW3tFuM/+eXuXO5r+A6ozYiDraOyKW3iAruW8M?= =?us-ascii?Q?WDKRKrrO/KCP8XwJci2ZiTifPlhDzqHRYwSU3PnGgv3CLSTAoDxukpjwy7uX?= =?us-ascii?Q?IbrfK3za2AGOHiLdsQ6yv0jTh1+xu2VIeD1kwefXMsXK0HzMOVUTe66dTdpI?= =?us-ascii?Q?GobWYYM8xTRMtfFIRooYWzBws3ZIv9pu5eB4hVLQ+nQ9t3FEieaHFUIYd6S+?= =?us-ascii?Q?QQcmJuDwc5lFFv6RbZp/F6IhUBv6v/2tKcnsm4F8sha2mAINNOpHSuob6Uzl?= =?us-ascii?Q?Lu2S9CDGZqurMP9X+odv2L3cgnpuWzxhZpzgTCybqenrM/jROjIQ1Yada4+S?= =?us-ascii?Q?K+aWyzZAZkl4qt+BSIe/GP0cNNSPGRXCWRpsbBOssmQZQ83/JodM+D24uCT6?= =?us-ascii?Q?gy7wNMC/Ug5xe+Fra5bVNMwbVfDNxuzpFTxEZwSi0i1ppTEwbwCRhc1ldouk?= =?us-ascii?Q?pbqwlb7i63+/Hriids5YEPPMjh5ipz6os7h0CFS0wSRTbHrMvWWStwlPjAaD?= =?us-ascii?Q?labXjsWY0EgV3AjZJqPWxJ1BWefCAyT7aDIg3INcYC0OwgCWe2WEbylOJu4T?= =?us-ascii?Q?J8qHnq2mRsGA4rJUsyNShcXlAy+6uUrlE2lXCb8zCUpmJY3IpwR++/Ns8RIR?= =?us-ascii?Q?0SI4pL4Kaw=3D=3D?= X-OriginatorOrg: Nvidia.com X-MS-Exchange-CrossTenant-Network-Message-Id: ac985e98-5aac-47b6-8d48-08def4fac07a X-MS-Exchange-CrossTenant-AuthSource: DM3PR12MB9416.namprd12.prod.outlook.com X-MS-Exchange-CrossTenant-AuthAs: Internal X-MS-Exchange-CrossTenant-OriginalArrivalTime: 08 Aug 2026 03:11:34.3240 (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: zWIzZuIttv49Lc92pS+M0gQB+yBWH1E27KyttgY/o8CeD8HEZ85Pvzdk5RGj4whWjv/SheX68g39u1jBC/m+Ug== X-MS-Exchange-Transport-CrossTenantHeadersStamped: CH2PR12MB4198 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. Route every non-reply message to a dispatcher, which logs the error records and leaves the in-flight command waiting for its reply. The dispatch runs on the existing command and wait loops, so events are handled 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 | 64 ++++++++++++++++++++++++------- 1 file changed, 51 insertions(+), 13 deletions(-) diff --git a/drivers/gpu/nova-core/gsp/cmdq.rs b/drivers/gpu/nova-core/gsp/= cmdq.rs index f0f28b6ded7a..0df52df1da89 100644 --- a/drivers/gpu/nova-core/gsp/cmdq.rs +++ b/drivers/gpu/nova-core/gsp/cmdq.rs @@ -547,11 +547,11 @@ 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 goes to + /// [`CmdqInner::dispatch_event`]. /// - /// The queue is locked for the entire send+receive cycle to ensure th= at no other command can - /// be interleaved. + /// The queue is locked for the entire send+receive cycle, so no other= command can be + /// interleaved. /// /// # Errors /// @@ -805,8 +805,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::dispatch_ev= ent`] and `ERANGE` is + /// returned. /// /// The read pointer is always advanced past the message, regardless o= f whether it matched. /// @@ -815,8 +817,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= @@ -825,11 +826,13 @@ 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(); + let matched =3D matches!(function, Ok(f) if f =3D=3D M::FUNCTION); =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 matched { 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 @@ -840,7 +843,7 @@ fn receive_msg(&mut self, timeout: D= elta) -> Result dev_warn!( &self.dev, "GSP message {:?} has unprocessed data\n", - function + M::FUNCTION ); } }) @@ -853,6 +856,41 @@ fn receive_msg(&mut self, timeout: = Delta) -> Result message.header.length().div_ceil(GSP_PAGE_SIZE), )?); =20 + if !matched { + self.dispatch_event(function, seq); + } + result } + + /// Routes a GSP message that is not the reply a caller is waiting for. + /// + /// 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 dispatch_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 Wed Sep 30 12:58:54 2026 Received: from SN4PR0501CU005.outbound.protection.outlook.com (mail-southcentralusazon11011067.outbound.protection.outlook.com [40.93.194.67]) (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 DD9A3389118 for ; Sat, 8 Aug 2026 03:11:47 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=fail smtp.client-ip=40.93.194.67 ARC-Seal: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1786158710; cv=fail; b=HUja4w/S1Is7ecbNid5Y1M8aPNYHAlwMZO01mVxbfWqU9FbZP21EcNf/SKAK0hSwhjrZNbIdYNu1HkDunQAUSmyifuk7221BCulkB6fk0ZpZN3d2X2/JgEIiedRWaRB8RtDbYaO9Ts9C4HpC2Bn4BG8DpVVPNR0eP50heiHyIyo= ARC-Message-Signature: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1786158710; c=relaxed/simple; bh=pht1DVQLuulETVRWMNi0PSOyv8J5sl57fBGUg9r7jM4=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: Content-Type:MIME-Version; b=hOFApRQOEWKwv7d07HEQgfaP7vRcUxb8vlgSroSbagBABZC4q+w5hbdUMMlU9GrntoEkdETvmFuGxfCjviz3EL5vFiSJ4ewgnneBXnRk7Yt3BDY6VXredSNmtsdZzMLhWLKTDifkjujb0UrTcsI2tvc8qPtbo7HEXhPaC5PA8Wc= 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=KClrL3C5; arc=fail smtp.client-ip=40.93.194.67 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="KClrL3C5" ARC-Seal: i=1; a=rsa-sha256; s=arcselector10001; d=microsoft.com; cv=none; b=r1KMFDpdyMChZF255RTglnhnP9epdvBokRQ7dzQgKvaLDAKgMKnRr9G3XxrdAses+118NKYeTU6x/tsuVvRJU7pvxsRoH7GJB8z/h4y7nYlfzbD7MOx5l5prDQCwf6dQNw+QCivhPGx5NapYUckAj+UuVC3L9zzJol0ixcTGI0iGfrAA/f4zlVTsxrehi0mk+YKLURTX5Ysw/drud4qXBd9VnkXMTvG2mqfz78z0tK6sYZlCxtAOhPKtCxX6u/lWVySWFN2gSUUQXTBWUg8Rj/CQWI4j/aIridlll6eMFrLG0IgZXkVbTvMIg1wmYw4VKifi1U+S188WJGUqAKgxEw== 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=wHz3y5DKMJJ+2f2yTsIvFfnrNYxw/0un4RdJnBO8EFo=; b=v4Qan4PEQOzLzZjR8ZIs+cpIBUPq9ryJWGpIbEVC4X1QLTFv9xa8m2WHjBMDsFJtXo6Vm3ds5AFzQNPQrNz5GzxozUr/NagM8/4myV4M18n13V3LlDfU/X//++CNWvIhdYBoD5MsLnu1tp18TSJ2cFRM2jYbDdYHVJOrNnuzQxIhtqB5zXZHkuqZshMmG/uKjP3x+4vZ/D/zZr76EWd4g83IeaIVRgmwD+7ogsyckl4LTvWiGJTOrXb65lMDCy6mapiOBz6J+5Qnz2ZB9KKBRW9ETH7ThCK4LklfxCqRdHcvF1PCyXtyptOmoB8Yq2um3+ZTbJHP8pwzoe1XNN+7uA== 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=wHz3y5DKMJJ+2f2yTsIvFfnrNYxw/0un4RdJnBO8EFo=; b=KClrL3C5xBNgto1BHTQ2OnBWpq3l8j8OjZhDK3LobwpCIWAqrciT3ePFH3kzOxDhMBpa5u9Qi2gNhw1zP9apk2HWwnKng284T18ia3csYX95oqjqOWSFnyMHHB7RC7mwmjgOleFFmasFiKmkRGQCo5i/4mNCRcUWWooNVLegxFTQwVgH8LIZfR9UkfBGeQXFf9Mv971bQxj2wec40gvDyxpmoRW8fKNBhUjXQDj4lK5Sq/D8mua5nkFAAcJFU6+49g/VD/nmgH97rP96ET9tXuT75dWHxKg9IBUKr1fsB/mG367QnDPBROclh1lsk6GEb32Pnv6bROJSK0SAjUgFNw== 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 CH2PR12MB4198.namprd12.prod.outlook.com (2603:10b6:610:7e::23) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.21.292.21; Sat, 8 Aug 2026 03:11: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.0292.022; Sat, 8 Aug 2026 03:11:35 +0000 From: John Hubbard To: Danilo Krummrich , Joel Fernandes , Alexandre Courbot Cc: Timur Tabi , Alistair Popple , Eliot Courtney , Shashank Sharma , 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 11/17] gpu: nova-core: match GSP RPC replies by sequence, not just function Date: Fri, 7 Aug 2026 20:11:13 -0700 Message-ID: <20260808031120.363869-12-jhubbard@nvidia.com> X-Mailer: git-send-email 2.55.0 In-Reply-To: <20260808031120.363869-1-jhubbard@nvidia.com> References: <20260808031120.363869-1-jhubbard@nvidia.com> X-NVConfidentiality: public Content-Transfer-Encoding: quoted-printable X-ClientProxiedBy: SJ2P220CA0007.NAMP220.PROD.OUTLOOK.COM (2603:10b6:a03:5da::13) 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_|CH2PR12MB4198:EE_ X-MS-Office365-Filtering-Correlation-Id: 3bbd7a27-db10-4da7-de01-08def4fac15b X-MS-Exchange-SenderADCheck: 1 X-MS-Exchange-AntiSpam-Relay: 0 X-Microsoft-Antispam: BCL:0;ARA:13230040|23010399003|366016|376014|1800799024|7416014|10067099003|6133799003|56012099006|11063799006|18002099003|22082099003|3023799007; X-Microsoft-Antispam-Message-Info: 5qTDe+kxshXroin7ho1SBofa0XAwU7SsXlUmCbWEDkzRoVp8vVQmGp/yTU+7uMWzBHkI26URQYBZZik3ysSG0V3AJgJ+wQfc9ZUDOwPpZSRLvuNSd72BFthKFNgyOF/5Wyb0CzeY6qPGokMtlG/VdXW9IWPWLTy/3S6ZkY6LDD6LrU+KCL8Wjgg76MTBszbbeFsort3N3nrEehIlaJd9n55eXRTCYjEDzwjZ1BlaAH20v5+6zFxhE2uvjQbsOT6G9GDc2IstvNELDbnRhNMuJUyazmjF/JO+jcDDnENvwqQIADE0Doh0Zh6WIeBlaaAOK37Vhb7CnatEZPbBU6WwRvFdFtXkuccJkcuZHEFMci1gNzzaBSMDJSe70fe49aFfjBEroKCYcgcjXIj2XIzsuDPYhxqECa9B0fsVWXsf7wYAoYQ1iuif0x9G34Ddiv1aDIgaWBacbhBHr7N9IelBziAD82A7xmDzZRRukriaNJBSbVIum0RbtLwIqhHUjMIRR0PHEjwFirVqC68aaB73qPf3jh2Id+GP2+eVT7AkPY4rVfOamPztazdaNP41F0lZZ8s7K34axQmrgbk0wToRMVyN7d+YKBhT/D5INNkEsE43HTzuCZe3UN/KTI2j+n179pTjTN8TH3PL287kmbnqZEuFOMlreo1WP1sdH95fx0Q= 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)(23010399003)(366016)(376014)(1800799024)(7416014)(10067099003)(6133799003)(56012099006)(11063799006)(18002099003)(22082099003)(3023799007);DIR:OUT;SFP:1101; X-MS-Exchange-AntiSpam-MessageData-ChunkCount: 1 X-MS-Exchange-AntiSpam-MessageData-0: =?us-ascii?Q?TAjif8YBXNbUp7WGo1TwhH5ag5MurrQkyBADkIPRUiQ/2uxcsDz0GrhBRB6S?= =?us-ascii?Q?OLCe5YCKxf0QiGVSqad6O/fq/vwR/1c0kLSfqlvngCoFRpZ9IKpf72Od8t3L?= =?us-ascii?Q?sWkg+rBI5Hk+bVTmlNWGerKudVhTbRaBvXEpUrx7vCYGbTQ+4MfWVP7jzgbk?= =?us-ascii?Q?c8ywzYhyHFPa19oscjcIYz0fws9vSbVJVLXA2eV4QArcChfn4fwNwrXiNsb+?= =?us-ascii?Q?wpMJyedPUtvp47xaasM87dxiYuPu1diby0bCoAG/uMDVFBc3QF854Cy0amgu?= =?us-ascii?Q?IrJ1ONM0eAciTmUkfraChRCgicd3UCyrh/aEgfKncpx2ojygdkyfOVP/nBu5?= =?us-ascii?Q?NiQkG7ZGOZzHsjmo6zl47Y4QwbskQ9YfUODLKZIo9tsluoWjkKJI0wJZLtAY?= =?us-ascii?Q?JQ0gg9oyRvZt3gNEH87z6kQg5MS8JPmcvOmRlOe6+0cANLMT1NHStWiYmOrn?= =?us-ascii?Q?W6kjK7PDUsl7J7dqCBKu2BGgr79kFPfx1dsB9j4iyjpB2FFgvs9ILpZHc/oH?= =?us-ascii?Q?HiYvWfMm8JKXHKuEn95Llp6wIwlxrTLgq/KWHNX0aY+V5QPEPANxae+o7DRy?= =?us-ascii?Q?rJS51WkuJpM6+2KXK9LqtXcuL6lTA3nngLpwsGbqlFP/7xlRMIl+Gt1zDihz?= =?us-ascii?Q?BVUi1wsZklDwisn7BiMv1Kd/6ujvUts30m+RHBrKAwC+OUxFoi/FSZBqZMdG?= =?us-ascii?Q?8bTZpe+U/Zi6DpawLJUP1sLKN0LM/rpadDd/OUgN78vvNfpMfCMTX+X6xS9x?= =?us-ascii?Q?qr/Z+4obpg5EGGOGhsnjfUC683GIwqogkJFILFbEHwC8tJCQPY5HPVuyn82b?= =?us-ascii?Q?Vgvdj+ZAusgpRS0UD3IQLvPMU/Esjoim1HHWV6bR1Yp6pCpxUpePK0z6O6gn?= =?us-ascii?Q?6dEFtUgX4T5NEQNR6pT+5ft1H57x0q0aJ4CDyN8PdaTORWUinPZPGCEs4GXt?= =?us-ascii?Q?Lq5Q//DN7FJDu/2EljHYX/kSquxagRTeVrqYsXAe9xWnFko5mYU5jIUSET25?= =?us-ascii?Q?kCEuPQ4DDg89FLrfX3EhTeja4tIP3KT2k3xDaY7VqZysoLeqLc50xmY6ByPm?= =?us-ascii?Q?jvFNH8aNOztYZkH7SFPGHvwdBYWhPduAzCHOSPuTC/xkH+dxXesEjGXLgvgv?= =?us-ascii?Q?prhWEusAmvv1PTJEihOwF6oFPtHoJweQnFQffSTs1i4Qqz5h5zI0ZqnJz3Kr?= =?us-ascii?Q?I6YJTD/l7OAsvOYdJKjWxwSWl1G5ZP5qAVK+boRVBhii6dsf7tkxHFl936nR?= =?us-ascii?Q?DfmYTA8yux//BtVP9qyiNUvr+yfFr9twGOEqvWPmnAlZpEPaEP4deaiO42eo?= =?us-ascii?Q?vKJnGIdKLGyB8stck71ttSfk72qWxoyXUTa0vBL26sxFGmAOSe5uepPG56Hc?= =?us-ascii?Q?77TxYO+3ro/P1VlHCn73cP3clpEHRdvdI9ZoehxcuEyWTg1Bts1pjtZLyoE8?= =?us-ascii?Q?8d8HTMuwVKOwFd/1xMKXbCVlbeShjd4uN57AbxoB5ZjhB3MANZCKq1IEAjCO?= =?us-ascii?Q?x+CyaBkh625lqbHUXF0pryaS+fifNtRxt6ZNoUD+IZs9YbD/tEjYFhuyrwpI?= =?us-ascii?Q?7NCoEPwN1belIlX23Z9cUrLy7rF9LRIKzaPmvjsPUolch/c5ugjgstJFSDSB?= =?us-ascii?Q?IbA9hlfzj6dzTQBZC3SYTEob2MNlNKIGEj3R4BM/moClvGGzomcNn511yqI2?= =?us-ascii?Q?QLZ2PvAKJasmeU9SyFTbv++xAhxFsBLLga+W/wpF7e/r49zm16yfOj9VWN+N?= =?us-ascii?Q?6+Utz947tA=3D=3D?= X-OriginatorOrg: Nvidia.com X-MS-Exchange-CrossTenant-Network-Message-Id: 3bbd7a27-db10-4da7-de01-08def4fac15b X-MS-Exchange-CrossTenant-AuthSource: DM3PR12MB9416.namprd12.prod.outlook.com X-MS-Exchange-CrossTenant-AuthAs: Internal X-MS-Exchange-CrossTenant-OriginalArrivalTime: 08 Aug 2026 03:11:35.8306 (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: Wa9UGz7cZaQjNpejo4PPNhM8DQKrAqCWSoDrDexqaBmMwLWW7TD0Gmsa5GW8D6+aDiGuEBtKRdSdWFVc02gtig== X-MS-Exchange-Transport-CrossTenantHeadersStamped: CH2PR12MB4198 Content-Type: text/plain; charset="utf-8" The GSP replies to a command by echoing that command's function code and its RPC sequence number. nova-core matched replies on the function alone and never set the sequence, so a reply for a command that had already timed out could satisfy a later command using the same function. Give the RPC sequence its own counter, separate from the per-element transport sequence, set it on every command, and require both the function and the sequence to match before accepting a reply. A message with the expected function but a stale sequence is logged and dropped, not mistaken for the reply or dispatched as an event. A caller awaiting an unsolicited event still matches on the function alone. Assisted-by: Cursor:claude-opus-5 Signed-off-by: John Hubbard --- drivers/gpu/nova-core/gsp/cmdq.rs | 89 ++++++++++++++++++++----------- drivers/gpu/nova-core/gsp/fw.rs | 13 +++-- 2 files changed, 67 insertions(+), 35 deletions(-) diff --git a/drivers/gpu/nova-core/gsp/cmdq.rs b/drivers/gpu/nova-core/gsp/= cmdq.rs index 0df52df1da89..3224079abf7e 100644 --- a/drivers/gpu/nova-core/gsp/cmdq.rs +++ b/drivers/gpu/nova-core/gsp/cmdq.rs @@ -521,7 +521,8 @@ pub(crate) fn new(dev: &device::Device) = -> impl PinInit(&self, bar: Bar0<'_>, c= ommand: M) -> Result::InitError>, { let mut inner =3D self.inner.lock(); - inner.send_command(bar, command)?; + let expected_seq =3D inner.send_command(bar, command)?; =20 loop { - match inner.receive_msg::(Self::RECEIVE_TIMEOUT) { + match inner.receive_msg::(Self::RECEIVE_TIMEOUT, Som= e(expected_seq)) { Ok(reply) =3D> break Ok(reply), Err(ERANGE) =3D> continue, Err(e) =3D> break Err(e), @@ -594,18 +595,19 @@ pub(crate) fn send_command_no_wait(&self, bar: Bar= 0<'_>, command: M) -> Resul M: CommandToGsp, Error: From, { - self.inner.lock().send_command(bar, command) + self.inner.lock().send_command(bar, command).map(|_| ()) } =20 /// Receive a message from the GSP. /// - /// See [`CmdqInner::receive_msg`] for details. + /// Matches on the function code alone, for a caller awaiting an unsol= icited GSP event rather + /// than a reply to a command. See [`CmdqInner::receive_msg`]. pub(crate) fn receive_msg(&self, timeout: Delta) ->= Result where // This allows all error types, including `Infallible`, to be used= for `M::InitError`. Error: From, { - self.inner.lock().receive_msg(timeout) + self.inner.lock().receive_msg(timeout, None) } } =20 @@ -613,8 +615,13 @@ pub(crate) fn receive_msg(&self, ti= meout: Delta) -> Result struct CmdqInner { /// Device this command queue belongs to. dev: ARef, - /// Current command sequence number. - seq: u32, + /// Next transport sequence number for a queue element (the `seqNum` f= ield). Advances once per + /// queue element, including each continuation record. + elem_seq: u32, + /// Next RPC sequence number. The GSP echoes it in a command's reply, = which lets + /// [`CmdqInner::receive_msg`] match that reply to the awaiting comman= d. Advances once per + /// logical command. + rpc_seq: u32, /// Memory area shared with the GSP for communicating commands and mes= sages. gsp_mem: DmaGspMem, } @@ -633,7 +640,7 @@ impl CmdqInner { /// written to by its [`CommandToGsp::init_variable_payload`] method. /// /// Error codes returned by the command initializers are propagated as= -is. - fn send_single_command(&mut self, bar: Bar0<'_>, command: M) -> Res= ult + fn send_single_command(&mut self, bar: Bar0<'_>, command: M, rpc_se= q: u32) -> Result where M: CommandToGsp, // This allows all error types, including `Infallible`, to be used= for `M::InitError`. @@ -650,7 +657,7 @@ fn send_single_command(&mut self, bar: Bar0<'_>, com= mand: M) -> Result let (cmd, payload_1) =3D M::Command::from_bytes_mut_prefix(dst.con= tents.0).ok_or(EIO)?; =20 // Fill the header and command in-place. - let msg_element =3D GspMsgElement::init(self.seq, size_in_bytes, M= ::FUNCTION); + let msg_element =3D GspMsgElement::init(self.elem_seq, rpc_seq, si= ze_in_bytes, M::FUNCTION); // SAFETY: `msg_header` and `cmd` are valid references, and not to= uched if the initializer // fails. unsafe { @@ -678,23 +685,25 @@ fn send_single_command(&mut self, bar: Bar0<'_>, c= ommand: M) -> Result dev_dbg!( &self.dev, "GSP RPC: send: seq# {}, function=3D{:?}, length=3D0x{:x}\n", - self.seq, + rpc_seq, M::FUNCTION, dst.header.length(), ); =20 // All set - update the write pointer and inform the GSP of the ne= w command. let elem_count =3D dst.header.element_count(); - self.seq +=3D 1; + self.elem_seq =3D self.elem_seq.wrapping_add(1); self.gsp_mem.advance_cpu_write_ptr(elem_count); Cmdq::notify_gsp(bar); =20 Ok(()) } =20 - /// Sends `command` to the GSP. + /// Sends `command` to the GSP and returns the RPC sequence number ass= igned to it. /// - /// The command may be split into multiple messages if it is large. + /// The command may be split into multiple messages if it is large. Th= e GSP echoes the + /// sequence number in the reply, so a caller passes it to [`Self::rec= eive_msg`] to match the + /// reply to this command. /// /// # Errors /// @@ -703,24 +712,26 @@ fn send_single_command(&mut self, bar: Bar0<'_>, c= ommand: M) -> Result /// written to by its [`CommandToGsp::init_variable_payload`] method. /// /// Error codes returned by the command initializers are propagated as= -is. - fn send_command(&mut self, bar: Bar0<'_>, command: M) -> Result + fn send_command(&mut self, bar: Bar0<'_>, command: M) -> Result where M: CommandToGsp, Error: From, { + let rpc_seq =3D self.rpc_seq; + self.rpc_seq =3D self.rpc_seq.wrapping_add(1); + match SplitState::new(command)? { - SplitState::Single(command) =3D> self.send_single_command(bar,= command), + SplitState::Single(command) =3D> self.send_single_command(bar,= command, rpc_seq)?, SplitState::Split(command, mut continuations) =3D> { - self.send_single_command(bar, command)?; + self.send_single_command(bar, command, rpc_seq)?; =20 while let Some(continuation) =3D continuations.next() { - // Turbofish needed because the compiler cannot infer = M here. - self.send_single_command::>(bar= , continuation)?; + self.send_single_command::>(bar= , continuation, rpc_seq)?; } - - Ok(()) } } + + Ok(rpc_seq) } =20 /// Wait for a message to become available on the message queue. @@ -805,10 +816,14 @@ 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. 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::dispatch_ev= ent`] and `ERANGE` is - /// returned. + /// The expected message type is given by the `M` generic parameter. W= ith `expected_seq` set, + /// the message must also carry that RPC sequence number to count as t= he awaited reply. With + /// `None`, the function code alone decides the match. + /// + /// A matching message is decoded and returned. A message carrying the= expected function code + /// with a different sequence is a stale reply to a command that alrea= dy timed out, and is + /// logged and dropped. Any other message goes to [`Self::dispatch_eve= nt`]. Both non-matching + /// cases return `ERANGE`. /// /// The read pointer is always advanced past the message, regardless o= f whether it matched. /// @@ -820,7 +835,11 @@ fn wait_for_msg(&self, timeout: Delta) -> Result> { /// - `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= + fn receive_msg( + &mut self, + timeout: Delta, + expected_seq: Option, + ) -> Result where // This allows all error types, including `Infallible`, to be used= for `M::InitError`. Error: From, @@ -828,10 +847,10 @@ fn receive_msg(&mut self, timeout:= Delta) -> Result let message =3D self.wait_for_msg(timeout)?; let function =3D message.header.function(); let seq =3D message.header.sequence(); - let matched =3D matches!(function, Ok(f) if f =3D=3D M::FUNCTION); + let func_matches =3D matches!(function, Ok(f) if f =3D=3D M::FUNCT= ION); + let matched =3D func_matches && expected_seq.is_none_or(|expected|= seq =3D=3D expected); =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. let result =3D if matched { 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]); @@ -857,7 +876,17 @@ fn receive_msg(&mut self, timeout: = Delta) -> Result )?); =20 if !matched { - self.dispatch_event(function, seq); + if func_matches { + dev_warn!( + &self.dev, + "GSP RPC: dropping stale {:?} reply (seq {}, awaiting = {:?})\n", + M::FUNCTION, + seq, + expected_seq, + ); + } else { + self.dispatch_event(function, seq); + } } =20 result diff --git a/drivers/gpu/nova-core/gsp/fw.rs b/drivers/gpu/nova-core/gsp/fw= .rs index 05f54fee6186..0b01c81ec092 100644 --- a/drivers/gpu/nova-core/gsp/fw.rs +++ b/drivers/gpu/nova-core/gsp/fw.rs @@ -782,13 +782,14 @@ fn new() -> Self { } =20 impl bindings::rpc_message_header_v { - fn init(cmd_size: usize, function: MsgFunction) -> impl Init { + fn init(sequence: u32, cmd_size: usize, function: MsgFunction) -> impl= Init { type RpcMessageHeader =3D bindings::rpc_message_header_v; =20 try_init!(RpcMessageHeader { header_version: MsgHeaderVersion::new().into(), signature: bindings::NV_VGPU_MSG_SIGNATURE_VALID, function: function.into(), + sequence, length: size_of::() .checked_add(cmd_size) .ok_or(EOVERFLOW) @@ -813,25 +814,27 @@ impl GspMsgElement { /// /// # Arguments /// - /// * `sequence` - Sequence number of the message. + /// * `elem_seq` - Transport sequence number of the queue element (`se= qNum`). + /// * `rpc_seq` - RPC sequence number, echoed by the GSP in the reply. /// * `cmd_size` - Size of the command (not including the message elem= ent), in bytes. /// * `function` - Function of the message. pub(crate) fn init( - sequence: u32, + elem_seq: u32, + rpc_seq: u32, cmd_size: usize, function: MsgFunction, ) -> impl Init { type RpcMessageHeader =3D bindings::rpc_message_header_v; type InnerGspMsgElement =3D bindings::GSP_MSG_QUEUE_ELEMENT; let init_inner =3D try_init!(InnerGspMsgElement { - seqNum: sequence, + seqNum: elem_seq, elemCount: size_of::() .checked_add(cmd_size) .ok_or(EOVERFLOW)? .div_ceil(GSP_PAGE_SIZE) .try_into() .map_err(|_| EOVERFLOW)?, - rpc <- RpcMessageHeader::init(cmd_size, function), + rpc <- RpcMessageHeader::init(rpc_seq, cmd_size, function), ..Zeroable::init_zeroed() }); =20 --=20 2.55.0 From nobody Wed Sep 30 12:58:54 2026 Received: from CO1PR03CU002.outbound.protection.outlook.com (mail-westus2azon11010069.outbound.protection.outlook.com [52.101.46.69]) (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 6B954382F33 for ; Sat, 8 Aug 2026 03:11:49 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=fail smtp.client-ip=52.101.46.69 ARC-Seal: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1786158711; cv=fail; b=SG0fvI/XLJFRjO4/F1YyqV56fXNunMEMXVbVgyGFrmT3jJQEZKm3jHD8ViQUneBvqHNkm9ZuDckcAlHxqqk56Ljyrjullh6w+q3u/mMApdMUW3LRYBdcHhc4abp5nTQB1oyXdibS26enuSoPRUOSlPwUgMZBQacQ3TTZGssr4RA= ARC-Message-Signature: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1786158711; c=relaxed/simple; bh=cb1BJP5hFXYyjNUy0wLD91cq88LIXOpAhchYphk88Mc=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: Content-Type:MIME-Version; b=fEt9gPw7n5f32WU6hOY26ZS1+meqr+XGNqwypaT4c+R8tBKmBEHl4RuflHmM7/PSFNGEfDs6W8wkvVFkZnYw5Hi/1peuT9ihQ7F73ADg74UnnlrVeUUuc+lIZkdNf8kPOqi7ScmOx/czypnysvMkFqvrIkKQ8ls6cBbbfdiiF1E= 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=RRMHopd4; arc=fail smtp.client-ip=52.101.46.69 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="RRMHopd4" ARC-Seal: i=1; a=rsa-sha256; s=arcselector10001; d=microsoft.com; cv=none; b=lD3kCTI94kuHi6CMWLCqfGurzda39J16gVcNPT49yzKUC4BOZ26TC4jf1pscxyA1CPSO1yIuuQBbUMC4rNXWmYlOhPhnZXYQ9sBREy40MjewAK0Jdgnv6In/JCDh82a3m00g+TT4EkOacOtDXDfEyTLg+F1Fj/XpvA7omaQWk+VbR86viucEbLA0JJEdjpHAkOMsEFw5kccxPNbHuPWqWLrsgZZbZi1VEFdt9ysFmJ8oBhTsv7n/t+y6UobkE6YLAAp43nEX/AWuBFfHtjgecPtQ8VvPd/q2HKsqsIqTYLWsEqCAL2Gnq/2lS0Kt3jpVlM2bTAwqamo0jn9x+dmbiQ== 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=sOClEYn0U6XqlU0chrPSSjOr5hlhCqX8US9UPEIyJH8=; b=R7eIZ+Q1KeYvM3CKJvyQtAm2fe4g9PElASIjFEJ6RyTE0RArylxIUsa1vFAhn9jdVBlm22xW6smsaS48MvcTndHHFPjKbtwomaRvMASC3hqhrQNGxIymsKDvOOldXu6i9K5pADrZsjQKFdPxEkYgnWMGyxBZLoaoTVWf1VTty33q2h2Kipkmk9fuQEvaPIpmA2DXm6mZyum8tPai8sj5Joyy8Muc3paEwHL6JYohBX7Wd+IzKHTuvmrODqhgbOPf4dB8jyCCVOZueMxTdXGXJRC+/PX5qEcxih0qaRzrFF5y3+IydBjBKOWU9MRYbvfnfEjoGCj0QOtjHJSBIWpUEA== 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=sOClEYn0U6XqlU0chrPSSjOr5hlhCqX8US9UPEIyJH8=; b=RRMHopd44rkDEr5WhUsc9r/0UWnpLD9LFrpP2NZ3LuTwVYZkkoYrR6wEMBje4o0mTDk3SHpmJYrHo1SGLkwN9BPE66fyBtNl0kZIJz4SkzfmZv8LqJEnJYIn+zYBly2tT/rUExil8EacPdwqkuvOOFVcwgsLuHtCQvnMjWjAxIYBrojm9uDpaNZyuku33nc1nmNfbCSABzUY0I1hGkuRudxREsJQ0dVtpHCKFckS1lZ/rebWRjCGP9BoPArRrb3PN9dGmAd8Naz/k4n46xtQVnW9aJzV2tmPalrAEEFbkqYiUMeEeT6+ELtpzpjH2n2RjTmxktkr4ATJYaSsJTINaw== 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 CH2PR12MB4198.namprd12.prod.outlook.com (2603:10b6:610:7e::23) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.21.292.21; Sat, 8 Aug 2026 03:11:37 +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.0292.022; Sat, 8 Aug 2026 03:11:37 +0000 From: John Hubbard To: Danilo Krummrich , Joel Fernandes , Alexandre Courbot Cc: Timur Tabi , Alistair Popple , Eliot Courtney , Shashank Sharma , 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 12/17] gpu: nova-core: recover the GSP receive path from corrupt framing Date: Fri, 7 Aug 2026 20:11:14 -0700 Message-ID: <20260808031120.363869-13-jhubbard@nvidia.com> X-Mailer: git-send-email 2.55.0 In-Reply-To: <20260808031120.363869-1-jhubbard@nvidia.com> References: <20260808031120.363869-1-jhubbard@nvidia.com> X-NVConfidentiality: public Content-Transfer-Encoding: quoted-printable X-ClientProxiedBy: BY5PR04CA0014.namprd04.prod.outlook.com (2603:10b6:a03:1d0::24) To DM3PR12MB9416.namprd12.prod.outlook.com (2603:10b6:0:4b::8) Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-MS-PublicTrafficType: Email X-MS-TrafficTypeDiagnostic: DM3PR12MB9416:EE_|CH2PR12MB4198:EE_ X-MS-Office365-Filtering-Correlation-Id: 59b16b30-a37a-403c-629c-08def4fac22b X-MS-Exchange-SenderADCheck: 1 X-MS-Exchange-AntiSpam-Relay: 0 X-Microsoft-Antispam: BCL:0;ARA:13230040|23010399003|366016|376014|1800799024|7416014|10067099003|56012099006|11063799006|18002099003|22082099003|3023799007; X-Microsoft-Antispam-Message-Info: 7NLcoI3/+Lu0Wpyqk0TMmEo6/v9yOVuqO8FbrWXICWM87ZxP/p3yr+2jBZkqkmNZXLsypIOpYpRxMkHAfAMf47wOm+qOhzH/X4uWXd8ZscB+Fr42zoQoKZ0y9CvPPALpjrPWbSR9UgAvQpXdTMZYBuJk4cJPhIlvlEQHPrS4FW7AObPOTujz/c+DvZNDBTvjKW5qptEI2NmQA5+8TGUAvA/8mUkVl5q4qCQhaL+Cs+8UAyxM5AIK/zVCaTxnYC8B9kTYZJzJ1y/TCay/tIU9mk5Mr3FxWmZbUtDSundtjEpbWTtjgVbHQkfVhLGQ1YoGT2migig5JjRaa/hF0M3x0Mq0qDXmhI6n1bZvxn/FhBS/hh3dlAK1sQiy/POV1X/L3iB004nfFrYirDK4bKd5JXkmoBCnqvL0OHILz0HHvuWi71JVwscY7x5GIqFwp/nQiiC3sQPrv7Jmm5qYtuxuZX0k/b7aUBLiuqaJvSLA0209tqe7UVJ4MzI7Ga6DEzLDuNbLT1HwQhhmv0rnd03jTU9XUZK88L6Aenu7yLj7ntryUcQo23/UaVNplkI4Tnmb1BiB5gKlwQ+ZMC9OF5EFywk/GguXCWUQPwoD8Im840x6ML2FQMspnpK58XtkeNsQPziRJ9aLC1jMHalH4GLytA1yDGnz/ZAt2imeoXw9gqw= 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)(23010399003)(366016)(376014)(1800799024)(7416014)(10067099003)(56012099006)(11063799006)(18002099003)(22082099003)(3023799007);DIR:OUT;SFP:1101; X-MS-Exchange-AntiSpam-MessageData-ChunkCount: 1 X-MS-Exchange-AntiSpam-MessageData-0: =?us-ascii?Q?K/OIeYdHZxl92WGbur/o8SN4iMQBkH5vslfngDUOeIxXt+HG0MqPvLdM6uc2?= =?us-ascii?Q?v/acx/P/hb59J0zhkMS8t0ybqCY2Jcba1UizqZDbe1E5n9EUiozVhobpXhU/?= =?us-ascii?Q?9Ss+MXgO3eUDgXJyn5okf5vtVXkxCAXMUERvMgG3xKwtz+3z6JpBQNV7zDfl?= =?us-ascii?Q?h61fRdNqbLvR0yzzddOnZt7C8s/aDg07WuSVk4qbhStI/kfv+VNtG1ql2kkp?= =?us-ascii?Q?gYAkw6BpNpGmqm8+q/IkBvGt9noZ2mkbqWEPYTff8ZywSQxFQZzxl01n7kl6?= =?us-ascii?Q?ZhXNV987pYeRSbvTwzQQHOGs8Gml7LsxraoI+A3c/R+Ujj4jMu7vK/OkMsVV?= =?us-ascii?Q?zw1vDG1ew0oQ0FHj4/BWPf7LtPGQN0cWDJR13n2L43+1cBhDN9FZmN5ajJvt?= =?us-ascii?Q?L76r2kpjrp+Pyd6svwG52fvvnWW3LuSO7tWiNN+C7ls0iID/m23IWZE/nPkO?= =?us-ascii?Q?nFXMu7iE8Zp0MZZdIvpzpDmHvknnl8c1NQ+quz17CmWqzNheCWb/uhmESW3R?= =?us-ascii?Q?w5YuKp0SPqoEJcBjCoGuCnDyKwcMgOo0+WzbRoc/XMr8jD9bYffCp0F8uyX2?= =?us-ascii?Q?ujRhcPzqo3GDU+CDIa5AlF7eGQ6tKoB1cxM0ICmtkfauWCssn3PNGRsA1NSZ?= =?us-ascii?Q?kBVr3eSaGzFXlOAnJalzVSWBqNMlW/9ZAtg+9aw3InbhDGb3EPMMXvoQG5BZ?= =?us-ascii?Q?C42n7Rzev9Whn97yT8JdyGhaMVmVvKsjju9KqWTOYoZDO8FlQaPx2QM044fn?= =?us-ascii?Q?xXljh6mzYMDU+qG+U97dpcC+raFoB4wHSoRlLEaLyI6XrgX8HA9bVkTIHS7J?= =?us-ascii?Q?xX5I0TXBcNZbZK72kqPbR0r8dfTnrrJE2MRr/YtA6SXZ98wf4snBL2YFejCx?= =?us-ascii?Q?mGZYo0/fcyl9UPkI5X2bMXSrtdg0tZhYLydc0a1IG5u65psznycfKaedb12m?= =?us-ascii?Q?/8Cbsr5c6/KrRxPLliWV4YwUViGEYRpBA7Y5gvNKP4olWz8XSQBBOyNpY14e?= =?us-ascii?Q?rW5J++aRrid0+xHi0mRClurxrwtuGvRLiahgI1HCreg0y3tARyXA9NgJZj9T?= =?us-ascii?Q?gCRaiGhPI1PTrGrT90ftfjr8Oxc00tJttmOPsK1mB82lc++6xW3lDRx7ussj?= =?us-ascii?Q?Nxp/aD5/7mXacSCoMEkLvywNW9p4IbDtwL2NApCjSMdVI1QEDZ75xAnq+2LN?= =?us-ascii?Q?rC9fsfAyU76m27z8dvKucwwHqeQwvmWy9zuellCNhuvrQBzKKA404wMXq2G2?= =?us-ascii?Q?nr12v6pUERE4eBMbRu2uSA2fuHaDYNZPoEsR2+asgDBi5jQ+NeAUuHiFninc?= =?us-ascii?Q?AwXMsPwL/RWvmHN5ZhTZxHfmGuw+SeCbj7L1IFMai94GtN5Eqfz/mVIrQNgK?= =?us-ascii?Q?rx+f9SRGY5L/MGAHoKjuifAEl36NM8DZNXW6OkCJSNyCW5fMaBjKnRdtrVEG?= =?us-ascii?Q?ipu8GoAeeDVF+Cq400PiLnIqSy4yYxLOkEqEr4/ucqKrmWlgLeylF9sYhCqC?= =?us-ascii?Q?I1KJM+y9TFFuaCf7G+sSK6l5MH9GvXy/fFvBDP47RrGhNe2/b1QYt3vsXdmB?= =?us-ascii?Q?Lqs3iUeaDlhCPGQNI7h2cyxdNJsiWqGrLUj/QxCBwqVM+1qjhUFKvT7gszh0?= =?us-ascii?Q?rQY/lIsmidGPGFYPIzcE0lC3SI2HStuGrVVwo168n9yvjfSqpAbs3D47n+LT?= =?us-ascii?Q?fYdBOtXl0KYrpMbRXtRMDKXEk5lkd0XNq9/AJZ9AhOu705n2BCEx5AIyWwQp?= =?us-ascii?Q?KOMK0IZblg=3D=3D?= X-OriginatorOrg: Nvidia.com X-MS-Exchange-CrossTenant-Network-Message-Id: 59b16b30-a37a-403c-629c-08def4fac22b X-MS-Exchange-CrossTenant-AuthSource: DM3PR12MB9416.namprd12.prod.outlook.com X-MS-Exchange-CrossTenant-AuthAs: Internal X-MS-Exchange-CrossTenant-OriginalArrivalTime: 08 Aug 2026 03:11:37.2040 (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: 7jPWXookl5+d5G/czKcV4TQc9EXPZzcj8t1y3zSYBtNl6HTl7cHBISfoZSKgqFqbc8W8+5Xrs+i0cpXv8OO3eg== X-MS-Exchange-Transport-CrossTenantHeadersStamped: CH2PR12MB4198 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, 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 | 63 ++++++++++++++++++++----------- 1 file changed, 41 insertions(+), 22 deletions(-) diff --git a/drivers/gpu/nova-core/gsp/cmdq.rs b/drivers/gpu/nova-core/gsp/= cmdq.rs index 3224079abf7e..fc4c229b8b9a 100644 --- a/drivers/gpu/nova-core/gsp/cmdq.rs +++ b/drivers/gpu/nova-core/gsp/cmdq.rs @@ -3,6 +3,7 @@ mod continuation; =20 use core::{ + cell::Cell, mem, sync::atomic::{ fence, @@ -523,6 +524,7 @@ pub(crate) fn new(dev: &device::Device) = -> impl PinInit, /// Memory area shared with the GSP for communicating commands and mes= sages. gsp_mem: DmaGspMem, } @@ -748,11 +756,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()), @@ -763,7 +773,10 @@ 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 { + self.poisoned.set(true); + return Err(EIO); + }; =20 dev_dbg!( &self.dev, @@ -777,6 +790,7 @@ 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 { + self.poisoned.set(true); return Err(EIO); } =20 @@ -805,6 +819,7 @@ fn wait_for_msg(&self, timeout: Delta) -> Result> { "GSP RPC: receive: Call {} - bad checksum\n", header.sequence() ); + self.poisoned.set(true); return Err(EIO); } =20 @@ -830,8 +845,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. @@ -850,22 +865,26 @@ fn receive_msg( let func_matches =3D matches!(function, Ok(f) if f =3D=3D M::FUNCT= ION); let matched =3D func_matches && expected_seq.is_none_or(|expected|= seq =3D=3D expected); =20 - // Every path must advance the read pointer past this message. + // Every path must advance the read pointer past this message, inc= luding a failed decode. let result =3D if matched { - 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 { Err(ERANGE) }; --=20 2.55.0 From nobody Wed Sep 30 12:58:54 2026 Received: from SN4PR0501CU005.outbound.protection.outlook.com (mail-southcentralusazon11011067.outbound.protection.outlook.com [40.93.194.67]) (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 9FB9838B7D9 for ; Sat, 8 Aug 2026 03:11:50 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=fail smtp.client-ip=40.93.194.67 ARC-Seal: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1786158712; cv=fail; b=PVa+gsCnzs7DUWQ1THZmGkET7rQbCSeQaYCbHYpun+bncNAgnqVuDA6ZydzEEaUodTWY7UEsgJvaJIcffUryQE75ToQsa0Mi+IXa7vUZ4XrKXvW5LTobLJT9yYppeMQTlSTYltpEXOlG3eAV67YWVZI8/7eO/BTxAngn0E0KL5M= ARC-Message-Signature: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1786158712; c=relaxed/simple; bh=3CeLMBPZmxuRg51AqB4jsGXZfAyw9ThhLPbdWhV6nyA=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: Content-Type:MIME-Version; b=TrJIrVWo/SX5kbIO59g4hfupNHsGgtX6x6GFvw3I8Q6cHHQXyAevhd32w9nhO1BwkmjBmc1uegLYRFiSbIO6/ByyB0gB9cfaapw5WS77vrbABqVj47WqaF3HptQVcIu1mVyGBvSpJmuKgLFH8mSHF3Ubdbs5V/vTDwCZ+XzsK+o= 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=qVBbqdB5; arc=fail smtp.client-ip=40.93.194.67 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="qVBbqdB5" ARC-Seal: i=1; a=rsa-sha256; s=arcselector10001; d=microsoft.com; cv=none; b=LMmZUFXyhzVOGlwChCbjyqTcXOAa7oyzskU2WWokGXI2ejswW6i82lgpRLv/chxr/O1A7ys2E19G+ilYD/XkX+xiqirGD7ehA0lA2/xkqeIAF0EjwgOMXB1qY7COmVQQw1slWEkdG960MAmvyXDSDJpu5325C5i3je6lZ8l02HCjex0VmTqSKg+yMN+UctrDTgyGw49tx9CEfHvaaffVOgNXUnIYTR3ADmk/2Rh7W4zFzhUMnRj9YJF44hQDIt4Esi3EqsV6HjQL0Zs7PVnloI1mFTvV6v9O/DZw9gunOYXggLj8aB0krG6HIXPM/OgqjeURJIEnxrmMYa+p5e9lJw== 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=w8aoowABUSYK/7YfMaZ7uWcOpXQNcL1ywTtScIJ6bSk=; b=YKQkA63uxLqqcFGTeVV1oEHBm4AddMPXsmlvpHcrh3BsHbaOVY5XDmO+HJMv5lbluDp9LlGIR2+ijZAmijxWwv6FUAqeVZQP1xHkk5+84w6dF473sXmmSj+e6qVoHjqabG1031aGLa9eP5q4eEke8KsuNxtL0wKBoq2CbUJKaRk5Hy0rHW/WSgxkQKmhC4+4uglN9XBaCI4Mo8vJKF0vJYOqlgxy+Tutif2TleiCF9xbIumkilIDPNLb1T6EJJhM+o0QwPKneIOIwIGe5SeLp1bLCABW7ny0f22NXJjMaopWQcQnnzNOgjEyknyPmKq++krR6OW0ETi3/Dve2lzdkA== 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=w8aoowABUSYK/7YfMaZ7uWcOpXQNcL1ywTtScIJ6bSk=; b=qVBbqdB5TWgu4sW9rFuZMMuqElSMoh/SVqKUUVMksQ3F5TqhmQx+WH2GMaUfsYYFcFd8I1RZbHxL6L1hRzb72hO5ERSRAthibn0Q8XAEKx+q8L1xuvIstRtu07wRNYfuOrkvPE48zepAT4+30ZcGk4+naxSZwYAhtFyerS2YCV1E10PXFCQtyHnAnfNJQJv9UZcOgJFCW+8xIB4lmGKyIf3Tf5rqQjxcwOzvJJgATX9TfWK9WqTbou6NTTTB8Ce+rHAMeeqnf1yR4uXuTUs1oRkemMxv13LtVSZHabE4QIr42+hHi8DIpXLvDNPgAq6M3JPdUWcUG2SuoNguUUeQeg== 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 CH2PR12MB4198.namprd12.prod.outlook.com (2603:10b6:610:7e::23) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.21.292.21; Sat, 8 Aug 2026 03:11:38 +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.0292.022; Sat, 8 Aug 2026 03:11:38 +0000 From: John Hubbard To: Danilo Krummrich , Joel Fernandes , Alexandre Courbot Cc: Timur Tabi , Alistair Popple , Eliot Courtney , Shashank Sharma , 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 13/17] gpu: nova-core: bound a GSP wait by a single deadline Date: Fri, 7 Aug 2026 20:11:15 -0700 Message-ID: <20260808031120.363869-14-jhubbard@nvidia.com> X-Mailer: git-send-email 2.55.0 In-Reply-To: <20260808031120.363869-1-jhubbard@nvidia.com> References: <20260808031120.363869-1-jhubbard@nvidia.com> X-NVConfidentiality: public Content-Transfer-Encoding: quoted-printable X-ClientProxiedBy: SJ0P220CA0015.NAMP220.PROD.OUTLOOK.COM (2603:10b6:a03:41b::19) To DM3PR12MB9416.namprd12.prod.outlook.com (2603:10b6:0:4b::8) Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-MS-PublicTrafficType: Email X-MS-TrafficTypeDiagnostic: DM3PR12MB9416:EE_|CH2PR12MB4198:EE_ X-MS-Office365-Filtering-Correlation-Id: 2fd90b7b-c1b7-462d-eaaf-08def4fac2f2 X-MS-Exchange-SenderADCheck: 1 X-MS-Exchange-AntiSpam-Relay: 0 X-Microsoft-Antispam: BCL:0;ARA:13230040|23010399003|366016|376014|1800799024|7416014|10067099003|6133799003|56012099006|11063799006|18002099003|22082099003|3023799007; X-Microsoft-Antispam-Message-Info: 1h5sghRgAb7dNS1EM8qrDOXTW2WExBgKBH6AW6uzRTUYi1iGdSnU854pcOJ2Jdhn7Zafgw4lD1PTHhEXzu09nhA9a25lbJ0UgPCL6ibf6JOnufDCoxxSw538Xdr2XLHam1NF/5a/w2VlscqKsYnAgHeZPw38sKOdGeqfYNNr4lhoQVIPxmuiu+wGlBrdzUygtQhL4N4l2+FzDWoe2n7VdVYAjvR3ta20++azZSl7lXipfjQ7SiXq83ARG5xhPZw6ZgksWVbscUJZpFo7d394P3VHMIToXOU6kDn3+XbN3TxhIY9pjhg3YYk7c6e+rl9s1RsAEXZkgo6sswMdKCapHAIPcU6GrRTzOxa4B7BWdPC3DFCKxCgnzS+DKpbzrwv9uq76VGHDBoV2QqNwuxgeqTdP0E0rajI3iQb56XzRsaYf4rrCig/Sw1zsUuyRHFYoVuQFUDuXHT6wXMhFDsmREwbGmDYTmE3XkEa2MEO35fagOj1Zm+aahEiQ2E/8fZfYbWgkvlXIzt/HBscrTYNDpdPp7G1NgIby45NnOGjFc/Gl+sVW6OoiwJWyhCK7AUI8WT2c/TjzB2dgHvkmIBeCEXkq0mPSEWweCEJaT0KBCoya8tflnemTS9wkNgl8Xg73s+M4R1X9e3/y2x/Fa/LTMtY5ZKXRYKNXt0LQ5gNpffw= 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)(23010399003)(366016)(376014)(1800799024)(7416014)(10067099003)(6133799003)(56012099006)(11063799006)(18002099003)(22082099003)(3023799007);DIR:OUT;SFP:1101; X-MS-Exchange-AntiSpam-MessageData-ChunkCount: 1 X-MS-Exchange-AntiSpam-MessageData-0: =?us-ascii?Q?ebO9hx8qzDInn4TUN4EniFBRy28UcSE125VVcB/N1xl0syIQpUvyaRIMkmaV?= =?us-ascii?Q?WxGrLj3ucKDvqsPVFtSr1KqFcnBJ3xs65g+4kPDQVfHF77iK6Ub9fy2kILGy?= =?us-ascii?Q?T2mJYpPgCTH3tQtsa+nn0++IvN376EQNlCLqLUQWtrYrmT9yLYVtwYacUHse?= =?us-ascii?Q?QxazlaGkURWPXa7mQyABkWqjRhhcu/Mm3hXIzBURJG5rBDLLwqwEEg4UPEul?= =?us-ascii?Q?OYz3sPgPeHPpGgVNH2zKWGH2MvS42fx+V8ajBZN+Cbxct/YvrSTxFasJx0/z?= =?us-ascii?Q?x4pYQCZx0QIbbIuUM2AcuK68Wv7J0b8ZmQefru3RTVAPU6fyY3MT78JTnriz?= =?us-ascii?Q?3X2//Rm1tQaqpO24ubPA8EN8hhzD83eLIiq5/aly3T+DuQ56d8zX1w2Y7Hbo?= =?us-ascii?Q?UdJYyNJlVDp3GvSfRf7CTXhaaYQGNk/XQQKoLjkH6w5Tr5+lbaQYVgNn016k?= =?us-ascii?Q?b0iN5DfmkF0XOJRRMAUx8qEIqindDIqWA4NQwBhiQeGkzDGvxihMfJhepFXu?= =?us-ascii?Q?mp8Nzcbms3hj6QfqxJgVIwLgYnKTfbxLgXzZntsBoXEU3M7nImgK3YUx46Ix?= =?us-ascii?Q?Hi/CqOJZ6A2rU+AUQjhcCCfb6cn3z/GSRqDhGiJf6DsAJZFBCR3XPCCn+di/?= =?us-ascii?Q?ji962R/meB9N8Diw3eBZFgiH0ln3iFL348mG7vg6Bxty/3v1K2nnP6be4Foe?= =?us-ascii?Q?ZzDx0hqmY1HOGtaE8LBStoPPMZxmDSppjflWdJQHvAqHE4pjYirwkVHL4ssn?= =?us-ascii?Q?ts1Gd7FVSVU/InHak2oBnAOThQcs4FLrnlRUIeCScgPqerquGQzvgSHYAYUk?= =?us-ascii?Q?0Oqs8eHNagScTH+mAoB+ZGiBQFQnaIf++mJqo9K8lDNPtF3T2naHE3uipYdA?= =?us-ascii?Q?P4zpEYMW8b5TTFXgESzYTGPF1UuWB0hm9TRFzEvc2U5RQEPrrnREzNgf/33r?= =?us-ascii?Q?mdzq2RB65VYJoQ5OX1z5czenSlHuW2ORNEZk3vOTSzFqswfCguNPwbFqQfkI?= =?us-ascii?Q?BmYUh82LsilsgVXVAIUC+/EnBNxNQhP5g4gcdqGZ46Z8ksLgV8Wro4i73pea?= =?us-ascii?Q?KzPIjimHHVK83nkJlWEX1zK+h+oc6xxc5/2rIcf/LUJncdfbKgFApVRffAVU?= =?us-ascii?Q?qtJpl2Yh+Wg0CeZfnEr5tlN2YuDn2P7vMmfFPULpYzN8z6kmIoCfCJHdpkDm?= =?us-ascii?Q?xvMCdXoL0cECT+dbDaesUoykydtiEAmVQ0vzrvlkqM9wDpC3Mp6Iu3Vh5bRW?= =?us-ascii?Q?Sd6EAYZuBqUJZL+G95zXqE5SOa8JFsD7CsetVyNQsQn8Qc//+w/zF3s3BCX3?= =?us-ascii?Q?Ko8ncKx24hFBD538qS+14ZQN6Hgab+AFUBA4eCMqrQBmBOadKbZi9EKCl2Sg?= =?us-ascii?Q?VBcnXp78gAIOhKI9T2a0Kl3txuXq6gWSLqgFpL04ezufY9p/q0O4fs1d0qRK?= =?us-ascii?Q?zyzbHmQbBLGOgcddgZW06wUMBxaVUsIRlke1jdEfMscLUXE1gXHUjWdfBpZI?= =?us-ascii?Q?snXdZuCXXZojGNAI9VjWN20OGVDuORMFQpecssa5A/jYw+CERxJt0E2jj3Yr?= =?us-ascii?Q?VXgnlG1b6TKK4Y3pr9h8psHejbwOm6xQCsH3JQGk9orWc5z+FGUfVAp7+Dfr?= =?us-ascii?Q?Ue6LM/3UwsfozBqFekI+bm7xqLMEVRJDQiAtsi8Wp6R0G5fWyJi7TdbnXYRK?= =?us-ascii?Q?G0joJ/0Igbjw7KNmzL+nNXSihJnEbaRu6fsfvsjpP3h0qui8pysS7SSG+FrX?= =?us-ascii?Q?/huuhFjcLg=3D=3D?= X-OriginatorOrg: Nvidia.com X-MS-Exchange-CrossTenant-Network-Message-Id: 2fd90b7b-c1b7-462d-eaaf-08def4fac2f2 X-MS-Exchange-CrossTenant-AuthSource: DM3PR12MB9416.namprd12.prod.outlook.com X-MS-Exchange-CrossTenant-AuthAs: Internal X-MS-Exchange-CrossTenant-OriginalArrivalTime: 08 Aug 2026 03:11:38.4466 (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: KzwzAqsIs0mAaEm9ShXZzk93iZh33peY85jcBgExgBytri7TRlYOV929Bbz/I1eFFP4q3hffyZQla2ver50T7Q== X-MS-Exchange-Transport-CrossTenantHeadersStamped: CH2PR12MB4198 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 dispatches 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. Compute one absolute deadline when the wait begins and pass the time remaining to each read, so the whole wait is bounded however many events arrive first. 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 | 52 ++++++++++++++++++++++---- drivers/gpu/nova-core/gsp/commands.rs | 8 +--- drivers/gpu/nova-core/gsp/sequencer.rs | 8 +--- 3 files changed, 46 insertions(+), 22 deletions(-) diff --git a/drivers/gpu/nova-core/gsp/cmdq.rs b/drivers/gpu/nova-core/gsp/= cmdq.rs index fc4c229b8b9a..76d51155c49f 100644 --- a/drivers/gpu/nova-core/gsp/cmdq.rs +++ b/drivers/gpu/nova-core/gsp/cmdq.rs @@ -30,7 +30,11 @@ aref::ARef, Mutex, // }, - time::Delta, + time::{ + Delta, + Instant, + Monotonic, // + }, transmute::{ AsBytes, FromBytes, // @@ -558,8 +562,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 are + /// dispatched 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. /// @@ -574,8 +579,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, Som= e(expected_seq)) { + let remaining =3D deadline - Instant::::now(); + if remaining.is_negative() { + break Err(ETIMEDOUT); + } + match inner.receive_msg::(remaining, Some(expected_s= eq)) { Ok(reply) =3D> break Ok(reply), Err(ERANGE) =3D> continue, Err(e) =3D> break Err(e), @@ -600,17 +610,43 @@ pub(crate) fn send_command_no_wait(&self, bar: Bar= 0<'_>, command: M) -> Resul self.inner.lock().send_command(bar, command).map(|_| ()) } =20 - /// Receive a message from the GSP. + /// Receive a message from the GSP, matching on the function code alon= e. /// - /// Matches on the function code alone, for a caller awaiting an unsol= icited GSP event rather - /// than a reply to a command. See [`CmdqInner::receive_msg`]. - pub(crate) fn receive_msg(&self, timeout: Delta) ->= Result + /// Returns `ERANGE` if the message that arrives is not of type `M`. S= ee + /// [`CmdqInner::receive_msg`]. + fn receive_msg(&self, timeout: Delta) -> Result where // This allows all error types, including `Infallible`, to be used= for `M::InitError`. Error: From, { self.inner.lock().receive_msg(timeout, None) } + + /// Waits for an unsolicited GSP event of type `M`, dispatching any ot= her event that arrives + /// first. + /// + /// # Errors + /// + /// - `ETIMEDOUT` if the event does not arrive within [`Self::RECEIVE_= TIMEOUT`] of the call, + /// however many other events are dispatched while waiting. + pub(crate) fn await_msg(&self) -> Result + where + // This allows all error types, including `Infallible`, to be used= for `M::InitError`. + Error: From, + { + let deadline =3D Instant::::now() + Self::RECEIVE_TIMEO= UT; + loop { + let remaining =3D deadline - Instant::::now(); + if remaining.is_negative() { + break Err(ETIMEDOUT); + } + match self.receive_msg::(remaining) { + Ok(msg) =3D> break Ok(msg), + Err(ERANGE) =3D> continue, + Err(e) =3D> break Err(e), + } + } + } } =20 /// Inner mutex protected state of [`Cmdq`]. 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 Wed Sep 30 12:58:54 2026 Received: from CO1PR03CU002.outbound.protection.outlook.com (mail-westus2azon11010069.outbound.protection.outlook.com [52.101.46.69]) (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 9E07638E8BB for ; Sat, 8 Aug 2026 03:11:55 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=fail smtp.client-ip=52.101.46.69 ARC-Seal: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1786158719; cv=fail; b=YNOk05JK7POLSiZNJ4CEfdNKFHzEJzeCU/RPjfikF7An4tRtarXQVO33Mbu2PigkhqB8lnFy+zy7EvYb96I96WBEz6WD15A7UDMmugE0wvFHlhODNADkBAoMZdCvTZjXiFf/0kMIinWtsHNzp4nNbdZQg+XFKYkC7Y4UFLVoKQI= ARC-Message-Signature: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1786158719; c=relaxed/simple; bh=a8ZAZSugf0VJ7yO6Jm4Ulkwb/9LQJjcPDILD/wJmxTM=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: Content-Type:MIME-Version; b=bS6ldTktq/9PfbV+fLaocGZcCUS9WRYe/ApmB4UbwgdF0zFhhMbzN/+ByCk3JPJX939D+vfuPAd9Wu82iMEhkn2IQs5ODhZpagL5jumyhRbp+syv3ay4ejffs8VqGWuMHRjcng87S4Cl07+XfT//Y66ZBYfkTih0RJYEhGagTik= 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=OmZXvQdv; arc=fail smtp.client-ip=52.101.46.69 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="OmZXvQdv" ARC-Seal: i=1; a=rsa-sha256; s=arcselector10001; d=microsoft.com; cv=none; b=oAzs3m7h4vffSjeUIGT40FhBYq2qObecTm9rnfQToU0N8SMC6Q5pgf29ZYS5T7CBkuWIbgqIgUKQMCX+C0KxI2Ta0ClQ+hIcU7tGYp/YNlzMkLQSgIR0rsEUM7JzPLARwH/63jPanZoxq3QspV31UeNIamGNXfrhpbNrkKUAlqtdeSmTmoltt/Ek8krlJhqC3h36JDGRe0AFpG8qVBfzECzl9Vwy0LGP2OMMlZEuWgeXKpfyo8NFgstDjugFlw21BoFR6VZdGbywyuxNkaQe4C+Z6+O4I4ByfpDbl0g3sWBNRL+aPZKrjKOeoVtUUq07fm7PrxlPaZNtzLxGwmJNXg== 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=tKHPP3vp4p6e224uudtoDkHbPQb2z0AiAZYy3ybFZc0=; b=P21Fy1T2hAm76UGrJIgOzobWuATSZd6zcwNZrztS/jJcviPa/ZtS9Sqzu6uGrDOsonbPGry7Cmf8o50y3g8Z+POc1mLdquhvOsQLmEX4iNFEn9b7uZ8vJhbAqGWjIIhZ0ibVG2bshoL02XL/6SR1LmQimVqbRHtVLI4tBGJkdM1Cd80KzBA5vsC+ywpITyn1XlFviwP9WWlXue9130FczTfRvCD2OUGtW1888rUmuLPJeAuKXLxunnfEzJMzBo/w0MMRLbptUxFKO0rLVBS6nSGKLDLw6OpLS7mRiIW/eWuy/800A9a1Div1yQudkBcat5XA6ZyhL+5wL211PDYsfw== 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=tKHPP3vp4p6e224uudtoDkHbPQb2z0AiAZYy3ybFZc0=; b=OmZXvQdvOwCmuOR1OsTp2jTqRcR3dxz1RtgzeroLrts93GXvCro65qeKSTjf3euASNpYmjRNorXkCzwm/rfygjpHbSJ/xOreowUtAE+DzuMDs9a9vJ2bsnUdlu8i/qXgMRB0KucZqm/Goa45CmHp/PoT5F2RCUCiPoGb1uSruHyhE/FvCxWBmsH+34+d32RpsuEXQ4aMZ3U1rlK7543QA9srcPXEavZnPjI4Kvaj16Soc3gTwkBqEK01u4WuJgfKNH/MsQhWe+E0rggkAieLBeboJPLDnjOiJm30w9RQ1t0r7ngcWKIObQptIqKUkVdXr2uatfdg5YNFtNnJqLsNGQ== 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 CH2PR12MB4198.namprd12.prod.outlook.com (2603:10b6:610:7e::23) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.21.292.21; Sat, 8 Aug 2026 03:11:40 +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.0292.022; Sat, 8 Aug 2026 03:11:40 +0000 From: John Hubbard To: Danilo Krummrich , Joel Fernandes , Alexandre Courbot Cc: Timur Tabi , Alistair Popple , Eliot Courtney , Shashank Sharma , 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 14/17] gpu: nova-core: drive GSP events with the SWGEN0 interrupt Date: Fri, 7 Aug 2026 20:11:16 -0700 Message-ID: <20260808031120.363869-15-jhubbard@nvidia.com> X-Mailer: git-send-email 2.55.0 In-Reply-To: <20260808031120.363869-1-jhubbard@nvidia.com> References: <20260808031120.363869-1-jhubbard@nvidia.com> X-NVConfidentiality: public Content-Transfer-Encoding: quoted-printable X-ClientProxiedBy: BY3PR05CA0036.namprd05.prod.outlook.com (2603:10b6:a03:39b::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_|CH2PR12MB4198:EE_ X-MS-Office365-Filtering-Correlation-Id: ab31e852-f8d6-4fbb-40a1-08def4fac3d3 X-MS-Exchange-SenderADCheck: 1 X-MS-Exchange-AntiSpam-Relay: 0 X-Microsoft-Antispam: BCL:0;ARA:13230040|23010399003|366016|376014|1800799024|7416014|7136999003|10067099003|6133799003|56012099006|5023799004|11063799006|18002099003|11062099010|22082099003|3023799007; X-Microsoft-Antispam-Message-Info: eTs5t1cjw+mUn5nKAIO7tPTCQkJxtErASWAn8k81wcyCxiibhyIR2Q1F1Bca/xagCtqKM/aSbYv8qGYqw2GIWENN5wovoJomzPPPw5YWCGNDDbR4QvvTfQPJsqmWaNwUMTRmpH8vvsCP+CEKhTVXHxxntXwnNsSh2cJcTj/vICMZxD7GcC3JV/I25+AQLBT+eICkZOYLrdMKyL3CJEyiT/5Bk5dIJLGluojJ9hj26m6AhjtyhsNTe2iTgXb82r/Nlsu50kCp+RNkR+93Kla65BgB8Z5le0eO2LlmbxJ07j+2rEjwZrEbQfAGeL2jfVj9dkLpObzWm+vUa/HGg3EHwSpMoNSdyNBzWt9umWbwaJ8iLd+B/CzG4EFLQc0Ne3qmQL3Xm5uXnI1x0ltMjuYsLQOuuGcodc3KvrcwJSdGd9in3lhEs5+joNtBd5IY8tf6tCtIWHq4C+FuTWi45XvnJp9+kNj4HvUNCOECz4T1wHWYuJBwJZuBcdWik7Op7UxYpwlgqRZbX/pVSBG3TplpSWgM1rcJNfYMPav7uDzgWj/RCbabuLp85zYhF/x9Th2RaTb9xh7RcSGLaBdwABZausyWGwmokWmB/avEogUQktwXHVN95RKUU4NO7j7xg2X7wpE9sStpXzrEjLfNXeeJlXLQVikDPkdV9iP0Ld0pc18= 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)(23010399003)(366016)(376014)(1800799024)(7416014)(7136999003)(10067099003)(6133799003)(56012099006)(5023799004)(11063799006)(18002099003)(11062099010)(22082099003)(3023799007);DIR:OUT;SFP:1101; X-MS-Exchange-AntiSpam-MessageData-ChunkCount: 1 X-MS-Exchange-AntiSpam-MessageData-0: =?us-ascii?Q?yq1tm8J+Zmao7sZ+WXMvABW0tfD7etuPIl1PcgpzMbQZ/urnRDEHB8v+28Eo?= =?us-ascii?Q?3L8GtNggqNyu7grAU7Y2fol+Ilypykv/td+VKmene/hSXlpAURhZqnqF+slO?= =?us-ascii?Q?o70R3E2SYLXuf1Zzau5RCs60zKpOG0BNeiG1UQDMO/Yb6zYOKFL8uJypuI/D?= =?us-ascii?Q?+rpR1vjT9piMp7cnyxIFpd7j/jX7s141v6LNOtzFk7J9slgwaArJAa3AYkDL?= =?us-ascii?Q?AvSR5bDD9AJ5Dg9K4LY7OYTPYDeTLWTGOr4HHaJ30tkXA0E0lcY2nlZ07ENx?= =?us-ascii?Q?wg+r9tvCXMmfZfhm5CklHBG+JHmb22GrfvoeNtkV1gatOql1ZpbHpEYSIua5?= =?us-ascii?Q?FWS1jTSyieA4S5jGZidx4ndfZAZ25wP48HLCeZpN1Fo78R5c5JzNL9x6rmEn?= =?us-ascii?Q?eOUoJylp/ORz62mnplA5eeGswzmm6oAVAV//jA2/g2ej8cLP9DVe54Yr6IIC?= =?us-ascii?Q?Vc1F3oV9BbONFh8OcSygPFsff3ZoyIitkepKggGCXvBZr93SEjDErV7/X3lK?= =?us-ascii?Q?63zZ1XakzXFXrva3majt9s7mhcJ5ZJDw7prLuyxqGOI9JqyUbqVrgKb+t6+J?= =?us-ascii?Q?xMHtWaIG1Q6rneN12sS/1JHocsi6upfHi0HAyXempXWINMlKboAhUf+9MaZf?= =?us-ascii?Q?0mBzTQ89Pw8Ylr59C5hKJzaf0EmSUT2Q/GoUdMxBuVhbHl2s+baROrGQsqQ2?= =?us-ascii?Q?oH7baCjdDIIWbf1tU8s+lwClYxj9HxspnvZ6maRKSU+6C63y71AVY5p+zajU?= =?us-ascii?Q?xtOpP5F8SYOyqi2Wf6WQHVxOzdWDE8wNUw+BCFVqagNZ5hALB6SBMJNV9uEx?= =?us-ascii?Q?GXrGJrmG4okEato0kYNxfG4Y6qJrFUnTG13th1uFhozmD/m1aThjzdfknMkK?= =?us-ascii?Q?MZcLmQooYVLv+wcCMwyaxr72jp74Ma1VRZJJOsAP6+udh+vFEvQnGmy/l4ld?= =?us-ascii?Q?ndybhNFMAcBUHwYktlUaxILuayTWQmP513nDM3n1r9oUnE2Mn0wpiegPikfi?= =?us-ascii?Q?6LdkzoSaID3LKqu3BxnHvJ6b3z0bx8uNAYCSPIiI7qNdaW3ivuMOGGLKLnNf?= =?us-ascii?Q?2LWAmLsOGaq7ubj9wvz+WcPcWqxKj5wZLlAloRmHQjkgb8zUrljycgQu+bLF?= =?us-ascii?Q?eEoB2xZPqPLBobS7lN8HdLS5kR5GTgROyuiel1RRlW9uqwH6wOrO2enRcBBu?= =?us-ascii?Q?c2OwV3ViQ1BPkTAZRqBQFy+TkYaz/qbadNXy3l72R238PKZ8pWhVmxLBLXp7?= =?us-ascii?Q?WZd1Ha79MzrU9961laWZrZzm03/vy+dloaGFzJsKPilq95BZ7doVyiHHdOLl?= =?us-ascii?Q?93+pMdmodQuHa3FwmsSTHe82oErgPWbvSawVufDw6JysGP31uszkL/1oGy09?= =?us-ascii?Q?6xUJh7VktqHL6XIF3KTS7Uzpl7+NlWmHcXWpjnovgVkS+SmechjIfVaK7jM2?= =?us-ascii?Q?Bsmr5+8FQ8FlsxAQSHY+B9c3D0Ebn0A01DkZVA1tYyhFKAXUY81xStA6OGc2?= =?us-ascii?Q?fla+hjI6OWLDp76x9Xx20aO7d62RKZmcX5U5/IbvuHBwfZl7cFE3GctJus/P?= =?us-ascii?Q?soD/6yhJXtsljjGQUXHxtn8M3ftUrEr0axYdPXKzA2khp7kBV6DwO1zH0mUQ?= =?us-ascii?Q?ByRKMu7TEbjxtJoGrzNUSNjEXS3vJLNjZjiCCBkwAWfnPfR/4CtWpRJJE6aU?= =?us-ascii?Q?Tc4arvWVo0YNqAQUCoLbN1quK/JrwVhogKgJOZP5hHks4FGSbP7bzFA8/3DD?= =?us-ascii?Q?DNdnwVRZrA=3D=3D?= X-OriginatorOrg: Nvidia.com X-MS-Exchange-CrossTenant-Network-Message-Id: ab31e852-f8d6-4fbb-40a1-08def4fac3d3 X-MS-Exchange-CrossTenant-AuthSource: DM3PR12MB9416.namprd12.prod.outlook.com X-MS-Exchange-CrossTenant-AuthAs: Internal X-MS-Exchange-CrossTenant-OriginalArrivalTime: 08 Aug 2026 03:11:40.0883 (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: criVTmNYPYgKluSNhZssFbsFqwlF8ck0tpAoFVf7e+BVevb9iztG6j2m4oG4CD+zH6g84/ly7t+IJm9JrNcxLw== X-MS-Exchange-Transport-CrossTenantHeadersStamped: CH2PR12MB4198 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. GSP boot polls for its own notifications, which leaves the latch set and pending bits 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 falcon's SWGEN0 latch 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. Quiesce the tree, clear the latch and rearm PCI delivery before registering the handler, so none of that boot state reaches it. Pre-Hopper MSI rearms through a configuration-space write that the tree drain does not perform, and an interrupt delivered before probe leaves delivery un-armed. Move the vector allocation out of the self-test and into probe, because the vectors are allocated once for the whole PCI device rather than per handler. The self-test and the GSP handler each take the vector for the subtree they service. Assisted-by: Cursor:claude-opus-5 Reviewed-by: Will Pierce Signed-off-by: John Hubbard --- drivers/gpu/nova-core/driver.rs | 54 ++++- drivers/gpu/nova-core/falcon/gsp.rs | 35 ++- drivers/gpu/nova-core/gpu.rs | 22 +- drivers/gpu/nova-core/gsp.rs | 17 +- drivers/gpu/nova-core/gsp/cmdq.rs | 42 ++++ drivers/gpu/nova-core/irq.rs | 1 + drivers/gpu/nova-core/irq/doorbell_test.rs | 30 +-- drivers/gpu/nova-core/irq/gsp.rs | 239 ++++++++++++++++++++ drivers/gpu/nova-core/irq/interrupt_tree.rs | 18 ++ drivers/gpu/nova-core/nova_core.rs | 1 - drivers/gpu/nova-core/regs.rs | 4 + 11 files changed, 433 insertions(+), 30 deletions(-) create mode 100644 drivers/gpu/nova-core/irq/gsp.rs diff --git a/drivers/gpu/nova-core/driver.rs b/drivers/gpu/nova-core/driver= .rs index 5738d4ac521b..3fbf117a99ee 100644 --- a/drivers/gpu/nova-core/driver.rs +++ b/drivers/gpu/nova-core/driver.rs @@ -18,13 +18,22 @@ types::ForLt, }; =20 -use crate::gpu::Gpu; +use crate::{ + gpu::Gpu, + irq::gsp::GspIrq, // +}; =20 /// Counter for generating unique auxiliary device IDs. static AUXILIARY_ID_COUNTER: Atomic =3D Atomic::new(0); =20 #[pin_data] pub(crate) struct NovaCore<'bound> { + /// GSP event interrupt registration. + /// + /// Declared first so it is dropped first: `free_irq` runs (waiting ou= t any in-flight handler) + /// before the GSP is unloaded (`gpu`) or the BAR mapping is released = (`bar`). + #[pin] + _gsp_irq: GspIrq<'bound>, #[pin] pub(crate) gpu: Gpu<'bound>, bar: pci::Bar<'bound, BAR0_SIZE>, @@ -78,14 +87,51 @@ fn probe<'bound>( pdev.enable_device_mem()?; pdev.set_master(); =20 + // A PCI device has one interrupt vector allocation, so it is = made here for every + // subtree nova-core services, and each handler takes the vect= or for its own subtree. + let vectors =3D crate::irq::alloc_vectors(pdev, crate::irq::gs= p::GSP_SUBTREE)?; + let gsp_vector =3D vectors.vector_for(crate::irq::gsp::GSP_SUB= TREE)?; + let irq_type =3D vectors.irq_type(); + Ok(try_pin_init!(NovaCore { bar: pdev.iomap_region_sized::(0, c"nova-core/b= ar0")?, // TODO: Use `&bar` self-referential pin-init syntax once = available. // // SAFETY: `bar` is initialized before this expression is = evaluated - // (`try_pin_init!()` initializes fields in declaration or= der), lives at a pinned - // stable address, and is dropped after `gpu` (struct fiel= d drop order). - gpu <- Gpu::new(pdev, unsafe { &*core::ptr::from_ref(bar) = }), + // (`try_pin_init!()` initializes fields in the order they= appear here), lives at a + // pinned stable address, and is dropped after `gpu` (stru= ct field drop order). + gpu <- Gpu::new(pdev, unsafe { &*core::ptr::from_ref(bar) = }, vectors), + // Quiesce the interrupt tree before registering the handl= er below. + _: { + // SAFETY: as for the `bar` borrow above. + let bar =3D unsafe { &*core::ptr::from_ref(bar) }; + crate::irq::gsp::quiesce(bar, gpu.chipset(), irq_type); + }, + // Register the permanent GSP SWGEN0 handler before enabli= ng the interrupt. + // + // SAFETY: `bar` is initialized before this expression is = evaluated, lives at a + // pinned stable address, and is dropped after `_gsp_irq` = (declared first, so + // dropped first), so the handler's borrow stays valid for= its whole lifetime. + // `_gsp_irq` is stored in `NovaCore`, whose `Drop` runs `= free_irq`, so the + // registration is never leaked. + _gsp_irq <- unsafe { + GspIrq::new( + pdev, + gsp_vector, + irq_type, + &*core::ptr::from_ref(bar), + gpu.cmdq(), + gpu.chipset(), + ) + }, + // Enable the GSP notification now that the handler is reg= istered, then drain any + // messages the GSP posted during boot before relying on t= he interrupt. + _: { + // SAFETY: as for the `bar` borrow above. + let bar =3D unsafe { &*core::ptr::from_ref(bar) }; + crate::irq::gsp::enable(bar, gpu.chipset(), irq_type); + gpu.cmdq().drain()?; + }, _reg: auxiliary::Registration::new( pdev.as_ref(), c"nova-drm", diff --git a/drivers/gpu/nova-core/falcon/gsp.rs b/drivers/gpu/nova-core/fa= lcon/gsp.rs index ae32f401aeb0..f9d9e8e0386b 100644 --- a/drivers/gpu/nova-core/falcon/gsp.rs +++ b/drivers/gpu/nova-core/falcon/gsp.rs @@ -14,6 +14,7 @@ }; =20 use crate::{ + driver::Bar0, falcon::{ Falcon, FalconEngine, @@ -36,14 +37,40 @@ impl RegisterBase for Gsp { =20 impl FalconEngine for Gsp {} =20 +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), + ); + } + + /// Reads the GSP falcon interrupt status, clearing the SWGEN0 latch i= f it was set. + /// + /// Returns the status as it was read, before the clear. The GSP raise= s SWGEN0 when it has + /// posted messages in the GSP-to-CPU queue. The interrupt tree routes= every falcon cause to + /// a single vector, so the rest of the status identifies a cause othe= r than a posted message. + pub(crate) fn take_swgen0_intr(bar: Bar0<'_>) -> regs::NV_PFALCON_FALC= ON_IRQSTAT { + let status =3D bar.read(regs::NV_PFALCON_FALCON_IRQSTAT::of::()); + + if status.swgen0() { + Self::clear_swgen0_intr(bar); + } + + status + } +} + 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::(), - regs::NV_PFALCON_FALCON_IRQSCLR::zeroed().with_swgen0(true), - ); + Gsp::clear_swgen0_intr(self.bar); } =20 /// Checks if GSP reload/resume has completed during the boot process. diff --git a/drivers/gpu/nova-core/gpu.rs b/drivers/gpu/nova-core/gpu.rs index d5df0ebf67ae..9700eff6db86 100644 --- a/drivers/gpu/nova-core/gpu.rs +++ b/drivers/gpu/nova-core/gpu.rs @@ -10,7 +10,8 @@ num::Bounded, pci, prelude::*, - sizes::SizeConstants, // + sizes::SizeConstants, + sync::Arc, // }; =20 use crate::{ @@ -25,10 +26,12 @@ fsp::Fsp, gsp::{ self, + cmdq::Cmdq, commands::GetGspStaticInfoReply, Gsp, GspBootContext, // }, + irq::SubtreeVectors, regs, vgpu::VgpuManager, // }; @@ -323,12 +326,27 @@ fn drop(self: Pin<&mut Self>) { } =20 impl<'gpu> Gpu<'gpu> { + /// Returns the chipset this GPU was identified as. + pub(crate) fn chipset(&self) -> Chipset { + self.spec.chipset + } + + /// Returns a shared handle to the GSP command queue. + pub(crate) fn cmdq(&self) -> Arc { + self.gsp_resources.gsp.cmdq() + } + pub(crate) fn new( pdev: &'gpu pci::Device>, bar: Bar0<'gpu>, + vectors: SubtreeVectors<'gpu>, ) -> impl PinInit + 'gpu { let dev =3D pdev.as_ref(); =20 + // `vectors` exists for the interrupt self-test below, which this = configuration omits. + #[cfg(not(CONFIG_NOVA_CORE_IRQ_SELFTEST))] + let _ =3D vectors; + try_pin_init!(Self { spec: Spec::new(dev, bar).inspect(|spec| { dev_info!(dev,"NVIDIA ({})\n", spec); @@ -352,7 +370,7 @@ pub(crate) fn new( // never observes or clears GSP or PRIV_RING interrupts. _: { #[cfg(CONFIG_NOVA_CORE_IRQ_SELFTEST)] - crate::irq::doorbell_test::run_selftest(pdev, bar, spec.ch= ipset)?; + crate::irq::doorbell_test::run_selftest(pdev, bar, spec.ch= ipset, vectors)?; }, =20 // Initialize this early because `gsp_resources` depends on it. diff --git a/drivers/gpu/nova-core/gsp.rs b/drivers/gpu/nova-core/gsp.rs index 13f361406a6c..43eec3f4f573 100644 --- a/drivers/gpu/nova-core/gsp.rs +++ b/drivers/gpu/nova-core/gsp.rs @@ -18,7 +18,8 @@ Io, // }, pci, - prelude::*, // + prelude::*, + sync::Arc, // }; =20 pub(crate) mod cmdq; @@ -152,9 +153,8 @@ pub(crate) struct Gsp { /// Log buffers, optionally exposed via debugfs. #[pin] logs: debugfs::Scope, - /// Command queue. - #[pin] - pub(crate) cmdq: Cmdq, + /// Command queue, shared with the GSP event interrupt handler. + pub(crate) cmdq: Arc, /// RM arguments. rmargs: Coherent, } @@ -173,8 +173,8 @@ pub(crate) fn new(pdev: &pci::Device) ->= impl PinInit) -= > impl PinInit) -> Result { self.cmdq.send_command(bar, commands::GetGspStaticInfo) } + + /// Returns a shared handle to the GSP command queue. + pub(crate) fn cmdq(&self) -> Arc { + self.cmdq.clone() + } } =20 /// Opaque bundle required to unload the GSP. Created by [`Gsp::boot`], co= nsumed by [`Gsp::unload`]. diff --git a/drivers/gpu/nova-core/gsp/cmdq.rs b/drivers/gpu/nova-core/gsp/= cmdq.rs index 76d51155c49f..ac3e6642031a 100644 --- a/drivers/gpu/nova-core/gsp/cmdq.rs +++ b/drivers/gpu/nova-core/gsp/cmdq.rs @@ -647,6 +647,18 @@ pub(crate) fn await_msg(&self) -> R= esult } } } + + /// Drains and dispatches every message currently pending in the GSP-t= o-CPU queue. + /// + /// Routes each message the GSP has already posted through [`CmdqInner= ::dispatch_event`] 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`]. @@ -977,4 +989,34 @@ fn dispatch_event(&self, function: Result, seq: u32) { } } } + + /// Drains and dispatches all messages currently pending in the GSP-to= -CPU queue. + /// + /// Processes whatever the GSP has already posted, dispatching each me= ssage as an event, and + /// stops once the queue is empty. There is no awaited reply during a = drain, so every message + /// is routed to [`Self::dispatch_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.dispatch_event(function, seq); + } + + Ok(()) + } } diff --git a/drivers/gpu/nova-core/irq.rs b/drivers/gpu/nova-core/irq.rs index 5b449759b333..ddf322f2e623 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; =20 diff --git a/drivers/gpu/nova-core/irq/doorbell_test.rs b/drivers/gpu/nova-= core/irq/doorbell_test.rs index fae770339fd7..bfdfee732892 100644 --- a/drivers/gpu/nova-core/irq/doorbell_test.rs +++ b/drivers/gpu/nova-core/irq/doorbell_test.rs @@ -28,11 +28,14 @@ time, // }; =20 -use super::interrupt_tree::{ - vector_leaf_bit, - vector_subtree_mask, - LeafIndex, - Tree, // +use super::{ + interrupt_tree::{ + vector_leaf_bit, + vector_subtree_mask, + LeafIndex, + Tree, // + }, + SubtreeVectors, // }; use crate::{ driver::Bar0, @@ -56,8 +59,8 @@ =20 /// Subtree carrying the doorbell vector, and the only subtree this test s= ervices. /// -/// Derived from the vector so that changing `DOORBELL_VECTOR` moves the a= llocation, the subtree it -/// enables, and the handler together. +/// Derived from the vector so that changing `DOORBELL_VECTOR` moves the s= ubtree it enables and the +/// handler together. const DOORBELL_SUBTREE: u32 =3D vector_subtree_mask(DOORBELL_VECTOR); =20 /// Index of the subtree carrying the doorbell vector. Under MSI-X this is= also the index of the @@ -184,17 +187,18 @@ fn drop(&mut self) { /// /// # Errors /// -/// `EIO` if the doorbell is already pending before the test, if the deliv= ery 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 a= rrive within the timeout. +/// `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: SubtreeVectors<'_>, ) -> Result { - // The allocated interrupt type decides how the handler rearms deliver= y, so the vectors are - // allocated before the tree is built. - let vectors =3D super::alloc_vectors(pdev, DOORBELL_SUBTREE)?; + // The interrupt type decides how the handler rearms delivery, so the = tree takes it from + // probe's allocation. let vector =3D vectors.vector_for(DOORBELL_SUBTREE)?; let irq_type =3D vectors.irq_type(); let tree =3D Tree::new(chipset, irq_type, DOORBELL_SUBTREE); 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..1fce315410f3 --- /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 SWGEN0 latch, +//! and the IRQ thread drains the message queue. +//! +//! See `Documentation/gpu/nova/core/interrupts.rst`. + +use kernel::{ + device, irq, pci, + prelude::*, + sync::{ + aref::ARef, + Arc, // + }, +}; + +use super::interrupt_tree::{ + LeafIndex, + Tree, // +}; +use crate::{ + driver::Bar0, + falcon::gsp::Gsp as GspFalcon, + gpu::Chipset, + gsp::cmdq::Cmdq, // +}; + +/// Fixed GSP notification vector. +/// +/// The resource manager pins the GSP SWGEN0 notification to this vector o= n every supported chip, +/// so nova-core uses the constant directly instead of discovering it at r= untime. The leaf and bit +/// serviced by the handler are derived from it. +pub(crate) const GSP_INTR_0_VECTOR: u32 =3D 155; + +/// Leaf and bit index of the GSP notification vector within the interrupt= tree. +const GSP_LOC: (usize, u32) =3D super::interrupt_tree::vector_leaf_bit(GSP= _INTR_0_VECTOR); + +/// Leaf holding the GSP notification vector. +const GSP_LEAF: usize =3D GSP_LOC.0; + +/// Bit of the GSP notification vector within its leaf. +const GSP_BIT: u32 =3D 1 << GSP_LOC.1; + +/// 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: u32 =3D super::interrupt_tree::vector_subtre= e_mask(GSP_INTR_0_VECTOR); + +/// Clears the interrupt state that GSP boot left behind. +/// +/// Disables every vector in every implemented leaf, clears the falcon's S= WGEN0 latch, clears the +/// tree's pending bits, and rearms PCI interrupt delivery. On return no v= ector is enabled, so the +/// tree delivers nothing. +pub(crate) fn quiesce(bar: Bar0<'_>, chipset: Chipset, irq_type: pci::IrqT= ype) { + let tree =3D Tree::new(chipset, irq_type, GSP_SUBTREE); + tree.disable_all_leaves(bar); + // GSP boot consumes its notifications by polling the queue, which lea= ves SWGEN0 latched. + // Clear it before the tree drain below, so the drain clears the tree = state the clear sets. + // Messages already posted raise no interrupt of their own, and the ca= ller's queue drain + // covers them. + GspFalcon::clear_swgen0_intr(bar); + tree.drain(bar); + // The `TOP_EN` cycle in `drain` is the rearm for the two enable-cycle= methods, but pre-Hopper + // MSI rearms through a configuration-space write instead. An interrup= t delivered before probe + // leaves delivery un-armed on that path, with no handler to have rear= med it. + tree.rearm_pci_irq(bar, GSP_SUBTREE); +} + +/// Enables the GSP notification vector at its leaf. +/// +/// The GSP interrupt is delivered from this point on. +pub(crate) fn enable(bar: Bar0<'_>, chipset: Chipset, irq_type: pci::IrqTy= pe) { + let tree =3D Tree::new(chipset, irq_type, GSP_SUBTREE); + // A message posted after `quiesce` latches this leaf bit while the ve= ctor is still disabled, + // so enabling the vector raises that interrupt rather than losing the= message. + tree.leaf(LeafIndex::new::()).enable(bar, GSP_BIT); +} + +/// Threaded IRQ handler for the GSP SWGEN0 event. +/// +/// The top half clears the GIN leaf and reads the falcon SWGEN0 latch. Th= e IRQ thread drains the +/// GSP-to-CPU message queue, which takes the command-queue lock. +#[pin_data] +pub(crate) struct GspInterrupt<'a> { + /// Borrowed BAR0, for GIN and falcon register access from interrupt c= ontext. + bar: Bar0<'a>, + /// The GSP command queue, drained by the IRQ thread. + cmdq: Arc, + /// The GIN interrupt tree for this chipset. + tree: Tree, + /// Device, for logging from interrupt context without taking the comm= and-queue lock. + dev: ARef, +} + +impl<'a> GspInterrupt<'a> { + /// Creates the handler for `chipset`, borrowing `bar` and sharing `cm= dq` with the rest of the + /// driver. + pub(crate) fn new( + bar: Bar0<'a>, + cmdq: Arc, + chipset: Chipset, + irq_type: pci::IrqType, + dev: ARef, + ) -> impl PinInit + 'a { + try_pin_init!(Self { + bar, + cmdq, + tree: Tree::new(chipset, irq_type, GSP_SUBTREE), + dev, + }? Error) + } +} + +impl irq::ThreadedHandler for GspInterrupt<'_> { + /// Top half: clears the GIN leaf, takes the falcon SWGEN0 latch, 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 + .leaf(LeafIndex::new::()) + .read_pending(bar); + if leaf.pending_bits() & GSP_BIT =3D=3D 0 { + // 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(bar, GSP_SUBTREE); + return irq::ThreadedIrqReturn::None; + } + leaf.clear_vectors(bar, GSP_BIT); + + // SWGEN0 is the message-queue notification, so wake the IRQ threa= d to drain it. + let status =3D GspFalcon::take_swgen0_intr(bar); + let ret =3D if status.swgen0() { + irq::ThreadedIrqReturn::WakeThread + } else { + // The tree routes every falcon cause to this vector, so somet= hing other than a posted + // message fired it, for example a HALT from a GSP crash. Ther= e is no recovery path for + // those causes, so report the status rather than discarding i= t. + dev_err!( + &self.dev, + "GSP interrupt with no SWGEN0, falcon IRQSTAT {:#x}\n", + status.into_raw() + ); + irq::ThreadedIrqReturn::Handled + }; + + // 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(bar, GSP_SUBTREE); + + ret + } + + /// IRQ thread: drains and dispatches 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 + .leaf(LeafIndex::new::()) + .disable(self.bar, GSP_BIT); + 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. +/// +/// Wraps the threaded IRQ registration so that teardown disables the GSP = source at the interrupt +/// tree before `free_irq` runs. This closes the window, including a probe= partial-unwind, in which +/// an interrupt could be delivered to a handler that is being freed. +#[pin_data(PinnedDrop)] +pub(crate) struct GspIrq<'a> { + #[pin] + reg: irq::ThreadedRegistration<'a, GspInterrupt<'a>>, + /// Borrowed BAR0 and the interrupt tree, used by the teardown to disa= ble the GSP source. + bar: Bar0<'a>, + tree: Tree, +} + +impl<'a> GspIrq<'a> { + /// Registers the GSP SWGEN0 threaded handler on `vector`. + /// + /// # Safety + /// + /// The caller must not leak the returned value: its [`Drop`] runs `fr= ee_irq`. + pub(crate) unsafe fn new( + pdev: &'a pci::Device, + vector: pci::IrqVector<'a>, + irq_type: pci::IrqType, + bar: Bar0<'a>, + cmdq: Arc, + chipset: Chipset, + ) -> impl PinInit + 'a { + let dev: ARef =3D pdev.as_ref().into(); + 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 { + pdev.request_threaded_irq( + vector, + irq::Flags::TRIGGER_NONE, + c"nova-core", + GspInterrupt::new(bar, cmdq, chipset, irq_type, dev), + ) + }, + bar, + tree: Tree::new(chipset, irq_type, GSP_SUBTREE), + }) + } +} + +#[pinned_drop] +impl PinnedDrop for GspIrq<'_> { + fn drop(self: Pin<&mut Self>) { + // Disable the GSP source before `reg` drops and runs `free_irq`, = so no interrupt reaches a + // handler being torn down. This `PinnedDrop` runs before any fiel= d drops, so the order is + // disable-then-free_irq. + let this =3D self.project(); + this.tree + .leaf(LeafIndex::new::()) + .disable(this.bar, GSP_BIT); + } +} diff --git a/drivers/gpu/nova-core/irq/interrupt_tree.rs b/drivers/gpu/nova= -core/irq/interrupt_tree.rs index 73f5afadea3e..f4f1494cddba 100644 --- a/drivers/gpu/nova-core/irq/interrupt_tree.rs +++ b/drivers/gpu/nova-core/irq/interrupt_tree.rs @@ -135,6 +135,8 @@ pub(super) fn leaf(&self, index: LeafIndex) -> Leaf { /// /// `EINVAL` if `vector` lies outside this tree (`vector >=3D num_leav= es * 32`). `EOVERFLOW` if /// `vector` does not fit in the trigger register's vector field. + // Only the interrupt self-test injects a software interrupt. + #[cfg_attr(not(CONFIG_NOVA_CORE_IRQ_SELFTEST), expect(dead_code))] pub(super) fn trigger(&self, bar: Bar0<'_>, vector: u32) -> Result { if crate::num::u32_as_usize(vector) >=3D self.num_leaves * 32 { return Err(EINVAL); @@ -143,6 +145,22 @@ pub(super) fn trigger(&self, bar: Bar0<'_>, vector: u3= 2) -> Result { Ok(()) } =20 + /// 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, bar: Bar0<'_>) { + for index in 0..self.num_leaves { + if let Some(index) =3D LeafIndex::try_new(index) { + self.leaf(index).disable(bar, u32::MAX); + } + } + } + /// Clears every pending bit in every implemented leaf. /// /// Disables this tree's serviced subtrees at `TOP` across the walk, t= hen enables them, 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] diff --git a/drivers/gpu/nova-core/regs.rs b/drivers/gpu/nova-core/regs.rs index 1db92d36c5ac..2a0489472a66 100644 --- a/drivers/gpu/nova-core/regs.rs +++ b/drivers/gpu/nova-core/regs.rs @@ -196,6 +196,10 @@ pub(crate) fn usable_fb_size(self) -> u64 { 4:4 halt =3D> bool; } =20 + 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; } --=20 2.55.0 From nobody Wed Sep 30 12:58:54 2026 Received: from CO1PR03CU002.outbound.protection.outlook.com (mail-westus2azon11010069.outbound.protection.outlook.com [52.101.46.69]) (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 B071838C421 for ; Sat, 8 Aug 2026 03:11:51 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=fail smtp.client-ip=52.101.46.69 ARC-Seal: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1786158715; cv=fail; b=QykT2bCVEwhJw7yljjPLwNhEwAcAO24ut0+f8DauzXo1bXy6/qdpAWlBB6Kq7riYiPjYNAKhOz7v1btX2TRtjqpXZVHa8JELlgi7Cg7AbgPQmSPY2JvQy1SKi48V5d4Rx4nnDcJfJpoX+8n6wSnq3kfzuMqc8EFe5hNuCPitUBU= ARC-Message-Signature: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1786158715; c=relaxed/simple; bh=HQWuOFoT++h0cnFD0geb/TyA9SzYG/1gLleQcGkSPVY=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: Content-Type:MIME-Version; b=SwSgDKsla99maupbjRa42ASGRuo+Z9tgUlLlgFyYU0uG6LXVqksi3m/V3VDC1II16vT5oi92k5gPLmKiKS51NLLdtu4xS8fmTleTiH/OLOPQ1xgcFVg8Y/o1sPzCjbmcJ8T1+htYpMCXowgp7b85xTp1ZMXatbHVzhVoZp1qRWs= 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=RwyJDNeg; arc=fail smtp.client-ip=52.101.46.69 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="RwyJDNeg" ARC-Seal: i=1; a=rsa-sha256; s=arcselector10001; d=microsoft.com; cv=none; b=oXVLH8w3jF1gTVOlUN2hE7CPC87FnGXICRSFiHOcF8ueAZMhJgxGG6hpbL4OJ/OOCp4o7+Ba0hIEO4WvXUko7N7rgo4DkEKgxTPYPAPw4a4Jb/wABWILM+mm215idvhKRrqZMsRneBm9m7Ehr3sh/fGKt3fqBYKh0cURuDtLhCurpnYXmGgqXhEA6YvM4qz4u+aFiOt79jHUUBROUAxdVT09mFH7jbQ0jbPoxiCrKoLR2oZrdAYUl9jce70tD8kD2ecUofHHjuzrZizZSKYmxW0DARz07xaiqFeTh1OVhhwg08GOB8PNvZS9r/NK+0C84zs2BTFue5dOxWjBlaqc/w== 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=ScoaxebdDeSKwNmFRzea1gkoY1lrp1Yc3MscNYzN8m0=; b=QTQOdlohKYDggM7DWKpAvJOHe7pxjcpUCFKIj52xXCpkVrZ58Hy7jLwu8pF/Q/OHTcrf3F8402XCruOQa8E5X9jh+WLvoNOOQXK18TPZ9LpQnzkeIXnNDB6Z1bMEOV33hUSIcf3+5SRvGRFh21o/8ZOfi+CotK/QARWhVxHDcNpNvBdxojG7cgpvqo9sJtTtwVMPwyIeHVAWlE53VDwrP+xT7RwltoLFfII5U7AZg5DN0328+pXumS91XoBn5nQRvchpIYzA0jl0HtVtilk62BoPZOSRjN0aUbO3N15b1EsoZYo/F769G2iXJGG+1obS5VACp5vhMYObfg7oI2VdhQ== 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=ScoaxebdDeSKwNmFRzea1gkoY1lrp1Yc3MscNYzN8m0=; b=RwyJDNeg+1tJE5petxc71IwrHfMKa/Ak9wJ2UwnMaDJUQVinfWd+Csn1VNh3VXL9iOQAhevebK7S7bS8KzDOf1v0G9d8YtCu6Ywep7OwTFlyrPZ4n9GLYST8GK14aEcw9VcRP2HLA4kCmYjMfCYN7pXEPWZPuD8nFTXFhdZgjRdijbLZ/DZG4YcRZL/ZT/P5t3nntiFDfGdNzP+wzsmeVOMLKridVs8q56jxF28mJ2GSJ7kpMtE1fTrH4m9ZulRMI9UH3Rhi8bTRnaX+outR2IsQgR97QGMg7YKkcrWA9G8kCSa9T4FdL0gvMVc83QOWQmebyI1visVTOgwp34GLhA== 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 CH2PR12MB4198.namprd12.prod.outlook.com (2603:10b6:610:7e::23) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.21.292.21; Sat, 8 Aug 2026 03:11:41 +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.0292.022; Sat, 8 Aug 2026 03:11:41 +0000 From: John Hubbard To: Danilo Krummrich , Joel Fernandes , Alexandre Courbot Cc: Timur Tabi , Alistair Popple , Eliot Courtney , Shashank Sharma , 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 15/17] gpu: nova-core: retrigger the GSP falcon and clear every latched cause Date: Fri, 7 Aug 2026 20:11:17 -0700 Message-ID: <20260808031120.363869-16-jhubbard@nvidia.com> X-Mailer: git-send-email 2.55.0 In-Reply-To: <20260808031120.363869-1-jhubbard@nvidia.com> References: <20260808031120.363869-1-jhubbard@nvidia.com> X-NVConfidentiality: public Content-Transfer-Encoding: quoted-printable X-ClientProxiedBy: SJ2P220CA0009.NAMP220.PROD.OUTLOOK.COM (2603:10b6:a03:5da::8) 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_|CH2PR12MB4198:EE_ X-MS-Office365-Filtering-Correlation-Id: 5fc81f02-64ed-4035-5d3f-08def4fac49f X-MS-Exchange-SenderADCheck: 1 X-MS-Exchange-AntiSpam-Relay: 0 X-Microsoft-Antispam: BCL:0;ARA:13230040|23010399003|366016|376014|1800799024|7416014|10067099003|6133799003|56012099006|5023799004|11063799006|18002099003|22082099003; X-Microsoft-Antispam-Message-Info: cCX6gwEC1VjrFpWMqjzzmQq2Cae/UWm+GNBiRifnq+V30elkhppsJTCc3ONmLVabxV5PRB2wQd6cYuNfELDJYQoDnTT9/Li6TfVfwpACuEza0kOv1c9TEMbZ+DxUUUjNXR7rOY2Bm7c7zCX3IzJo0fTb8j7QlruQuc6LZuSfJsFAaQc79qiF2yhzTp+gSk90IJDG+1hsflchohhDvKPeO8O9MtOEYvRIYDHvDNbpSbFf9Zh0+OhuLgJzDW6pm5fSlkVgqeQwurFNynREYEFP7j3vIyQ5ltcuHsBbxPdA4GR1rQDHdAM1Lvxt3pFhNMQIOqzzMUTWApNO+0rMMH7Fr2XVvEgyGWHSQS7ax9cHNl4y/BuR/pqCTxZnkpNx8xMZyp9UQIUl1+W4Pu8mgEaJxgwAK+PHGZp3D33lkutrs9lwb5qiXqVV05ICcy22Fxo7oVWz3w2tv1TtdJ6HGK6JFj4cjl6z9xyN0BdMr2Q0aD5i8Ez1Da8U55KHwFhHKxj/OX0AqA3JE0y4I3RdPgoj+aPEeNjd7iL317gN2ONZ/QuW3yoCsnE5dIhEeu/kxz8nqP6ewXy94aRaKtn3NkR/w2vUEB+x7pCPY31UnwTSQ9dZVIwhhpl7Hods3IcFSjl5auWiS09wsb1npA3NyWWHOKwPArcm280R15DD48GNg5M= 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)(23010399003)(366016)(376014)(1800799024)(7416014)(10067099003)(6133799003)(56012099006)(5023799004)(11063799006)(18002099003)(22082099003);DIR:OUT;SFP:1101; X-MS-Exchange-AntiSpam-MessageData-ChunkCount: 1 X-MS-Exchange-AntiSpam-MessageData-0: =?us-ascii?Q?MklkvGorkGODk5ttKgBUSfuuHZRC+0vHkIY+TmI6t9llWLBBFgxqKzFXsCXp?= =?us-ascii?Q?5jpQMzBpq4usjNOkor1gGjKQIRYqCWokHjRZHb6Extltug+PHLetBdSMZzpK?= =?us-ascii?Q?1b+yUhANjS3t1oYzdfl0cI/ORCsAa17LPSVrJWKL6PcgpSRmkoiXtx2s4s06?= =?us-ascii?Q?u5Rp9hgpQAFhGzH6fhlf93MHMXrIdL1G9jGBNzq61qmcFnbwIm9IRAKvzxw6?= =?us-ascii?Q?ZUXt7VXT4BGWfy6PBbF2EuLdLqVpULtIIByrYvcK8N+aLWLPmFXinlWBzrJ0?= =?us-ascii?Q?Lr+49tROWjljyJpO/V2M/5wfP7JWGRA323zknVWOrBu7A2aDfXKKr7ehraLb?= =?us-ascii?Q?lVCCzF461VVcGzvUY4TQ13pBWnmDhV8Mfhg4CW8cWs30KtcdAisdEzQYXu2s?= =?us-ascii?Q?B4op6xzOLqg+FTMEM2+225kJwGNtw/Xoby8dzWka0IqciSavJI9EvT1FCyLv?= =?us-ascii?Q?kW5rlovgn7f6XfHnL1MfpxzYHWK4AN1yGjqwuw3vHESvmUNdD76xaOk1ov3C?= =?us-ascii?Q?9ilvV/KlDb82WwKO/Vud83qhS6e5XWAnZ6ya6/PhkGFhv4NzVCw/FXjLagG3?= =?us-ascii?Q?nrj57MdTxR5Z859tgZDZO3PPhfIQIqY56Qm51IrySor5xL86nbWUbFUZLsH4?= =?us-ascii?Q?JAOjO8soXo+FPr021S4z4M96CE0bQ2reG0bWgaEdpVOPSfGz8GDpQsyzWx1K?= =?us-ascii?Q?zQcBVoANdvWkmnnrtDGe8WVPRKbRLJV+slFu3Pxy6teP3od3SneKRJXhJtwi?= =?us-ascii?Q?49RnB5oHFQYZjsopYScm+creKXu+5k+Hv4LAhgtfg6dEfXGSWZui2gxV4cJp?= =?us-ascii?Q?vxK6Z1TZOTqlXCkxo0VKHGy2b/R+tZzZBIXNCmd7J0Vlt+QQ/9T4FuR/OVDb?= =?us-ascii?Q?1gJWgeaurR+cUl1lHjHl2UePrEQY890gBpIMJj42F+hNXGhlk7gvhljo8Q2U?= =?us-ascii?Q?EgmvrJ7W8f/GUfDGtl0EYOV3t8MnxGtio4vQIaGDlkmuSsJupkzLaU6bTjE7?= =?us-ascii?Q?rQpDXZoFIeaQoh7b+6056BiPaOR9whjXsKw3v0ZBR3sh3S+jm+N7zrZqBrRt?= =?us-ascii?Q?QKVbL9SNiutIny5mCE9WQcGPSUUtrSA9dilIgXxvWll5oqYQ98gZhhLFvL4J?= =?us-ascii?Q?ysBtm0ZY7xO+BTIdVCo7CQMVpS/QVqg9N6XW2C7dMZIAA6Uf7qcFPfilVdLd?= =?us-ascii?Q?3gJ/+Kqiet0pTV2mK0nKfvSkMD4+C64E/DiZMPHXzEu7O8ESjfYPp421XyEm?= =?us-ascii?Q?PwkfCVBuYWQERRRIar4IlhvdemDVo556XsefesVimF7+gPliry6PoDuUwyjz?= =?us-ascii?Q?uQ6bhTjdIjD1ORPSCCUO45rQb7GJjwlm03R78q23bALOcbVpIbNUUlvWC3to?= =?us-ascii?Q?oxFKAQ6HIrN6cvWHraO6/DQPfsUr9Wsd46/JUZJVNjhuwVUuol2lo22UalI+?= =?us-ascii?Q?D52ouoCdbVwksy+tvNlJh48oSULvUzVvk/eQ/OdH5HVVo/nsQ2Bf+mJplDda?= =?us-ascii?Q?KtYM6qg5DCqcjHMUIWXwmFgMxtpL1tVnlrkt92RGlidtl/Lo19BwmOMKHkRQ?= =?us-ascii?Q?7p/ubMzfPoSVh302vRlTqK8ki4bY7LnUpBRbZiEQKvZe8Pe2bInAcfk+OuQk?= =?us-ascii?Q?Bjoea3f7z6rzQihIQKuoGd/iu7FnguMW5ojHrm42hRz6wb+K470vrmIEh834?= =?us-ascii?Q?DH1YNG00PIzvZMzJLz5EaP7oDFQhL7nw7mq2pPlspcquAFGweupUJ7RpolYj?= =?us-ascii?Q?TPypRIwhIA=3D=3D?= X-OriginatorOrg: Nvidia.com X-MS-Exchange-CrossTenant-Network-Message-Id: 5fc81f02-64ed-4035-5d3f-08def4fac49f X-MS-Exchange-CrossTenant-AuthSource: DM3PR12MB9416.namprd12.prod.outlook.com X-MS-Exchange-CrossTenant-AuthAs: Internal X-MS-Exchange-CrossTenant-OriginalArrivalTime: 08 Aug 2026 03:11:41.2463 (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: Bb+IV5Z3m1YEyF5Vy6mKln2DZMEnT/Ujc4kVCRfdwRMYqWH3He0Kk4sIxUAlZ7Wt+ayf44MYWEZ3BMOh9jtz5A== X-MS-Exchange-Transport-CrossTenantHeadersStamped: CH2PR12MB4198 Content-Type: text/plain; charset="utf-8" A falcon signals the interrupt tree when its set of enabled causes goes from empty to non-empty. While any enabled cause stays latched, later causes produce no signal, and Turing falcons have no INTR_RETRIGGER register with which to supply one. The GSP handler cleared its GIN leaf bit and then cleared the falcon's SWGEN0 latch. A cause that arrived between the two left no record: the leaf clear discarded it, and the falcon had nothing left to signal. Swapping the two clears moves the window rather than closing it. The handler serviced SWGEN0 or reported an unserviceable cause, never both, so a HALT co-pending with SWGEN0 stayed latched. nova-core's probe cleared the SWGEN0 latch before draining the tree, so a message posted in between set a leaf bit that the drain then erased. In every case the GSP went silent for the life of the device. Write the falcon's INTR_RETRIGGER register after every clear of the GSP vector. That supplies the missing signal from whatever causes remain enabled. Turing falcons have no such register, so skip the write there. Handle every cause the falcon reports on one invocation, masking the ones with no recovery path so the re-emit does not raise them again. Clear the SWGEN0 latch after the tree drain instead of before it. Neither of these depends on INTR_RETRIGGER, so both apply on Turing. Assisted-by: Cursor:claude-opus-5 Reviewed-by: Will Pierce Signed-off-by: John Hubbard --- drivers/gpu/nova-core/falcon/gsp.rs | 36 ++++++++++++++++++ drivers/gpu/nova-core/falcon/hal.rs | 8 ++++ drivers/gpu/nova-core/irq/gsp.rs | 57 ++++++++++++++++++----------- drivers/gpu/nova-core/regs.rs | 20 ++++++++++ 4 files changed, 100 insertions(+), 21 deletions(-) diff --git a/drivers/gpu/nova-core/falcon/gsp.rs b/drivers/gpu/nova-core/fa= lcon/gsp.rs index f9d9e8e0386b..6ee5c1ef1af7 100644 --- a/drivers/gpu/nova-core/falcon/gsp.rs +++ b/drivers/gpu/nova-core/falcon/gsp.rs @@ -16,11 +16,13 @@ use crate::{ driver::Bar0, falcon::{ + hal, Falcon, FalconEngine, PFalcon2Base, PFalconBase, // }, + gpu::Chipset, regs, }; =20 @@ -64,6 +66,40 @@ pub(crate) fn take_swgen0_intr(bar: Bar0<'_>) -> regs::N= V_PFALCON_FALCON_IRQSTAT =20 status } + + /// Masks and clears every interrupt cause set in `status`. + /// + /// A masked cause leaves the falcon's enabled set, so it neither rais= es the tree again nor + /// holds that set non-empty. + pub(crate) fn mask_and_clear_intr(bar: Bar0<'_>, status: regs::NV_PFAL= CON_FALCON_IRQSTAT) { + let causes =3D status.into_raw(); + + bar.write( + WithBase::of::(), + regs::NV_PFALCON_FALCON_IRQMCLR::zeroed().with_value(causes), + ); + bar.write( + WithBase::of::(), + regs::NV_PFALCON_FALCON_IRQSCLR::from(causes), + ); + } + + /// Re-emits the falcon's enabled interrupt causes into the interrupt = tree. + /// + /// The falcon signals the tree on a transition of its enabled causes,= so clearing the tree + /// leaf while a cause is still latched leaves no transition and no fu= rther 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), + ); + } } =20 impl<'a> Falcon<'a, Gsp> { diff --git a/drivers/gpu/nova-core/falcon/hal.rs b/drivers/gpu/nova-core/fa= lcon/hal.rs index 7e532889a1f4..f0828b32aebb 100644 --- a/drivers/gpu/nova-core/falcon/hal.rs +++ b/drivers/gpu/nova-core/falcon/hal.rs @@ -72,6 +72,14 @@ 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 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/irq/gsp.rs b/drivers/gpu/nova-core/irq/g= sp.rs index 1fce315410f3..ecd716b92d4e 100644 --- a/drivers/gpu/nova-core/irq/gsp.rs +++ b/drivers/gpu/nova-core/irq/gsp.rs @@ -54,18 +54,17 @@ =20 /// Clears the interrupt state that GSP boot left behind. /// -/// Disables every vector in every implemented leaf, clears the falcon's S= WGEN0 latch, clears the -/// tree's pending bits, and rearms PCI interrupt delivery. On return no v= ector is enabled, so the -/// tree delivers nothing. +/// Disables every vector in every implemented leaf, clears the tree's pen= ding bits, clears the +/// falcon's SWGEN0 latch, and rearms PCI interrupt delivery. On return no= vector is enabled, so +/// the tree delivers nothing. pub(crate) fn quiesce(bar: Bar0<'_>, chipset: Chipset, irq_type: pci::IrqT= ype) { let tree =3D Tree::new(chipset, irq_type, GSP_SUBTREE); tree.disable_all_leaves(bar); - // GSP boot consumes its notifications by polling the queue, which lea= ves SWGEN0 latched. - // Clear it before the tree drain below, so the drain clears the tree = state the clear sets. - // Messages already posted raise no interrupt of their own, and the ca= ller's queue drain - // covers them. - GspFalcon::clear_swgen0_intr(bar); tree.drain(bar); + // 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. Clear it after the tr= ee drain, which erases + // every leaf bit and would erase the one a message posted since the c= lear had set. + GspFalcon::clear_swgen0_intr(bar); // The `TOP_EN` cycle in `drain` is the rearm for the two enable-cycle= methods, but pre-Hopper // MSI rearms through a configuration-space write instead. An interrup= t delivered before probe // leaves delivery un-armed on that path, with no handler to have rear= med it. @@ -94,6 +93,8 @@ pub(crate) struct GspInterrupt<'a> { cmdq: Arc, /// The GIN interrupt tree for this chipset. tree: Tree, + /// Chipset, for the falcon retrigger, which Turing does not implement. + chipset: Chipset, /// Device, for logging from interrupt context without taking the comm= and-queue lock. dev: ARef, } @@ -112,14 +113,15 @@ pub(crate) fn new( bar, cmdq, tree: Tree::new(chipset, irq_type, GSP_SUBTREE), + chipset, dev, }? Error) } } =20 impl irq::ThreadedHandler for GspInterrupt<'_> { - /// Top half: clears the GIN leaf, takes the falcon SWGEN0 latch, and = rearms PCI interrupt - /// delivery. + /// Top half: clears the GIN leaf, takes every cause the falcon report= s, and rearms PCI + /// interrupt delivery. fn handle(&self) -> irq::ThreadedIrqReturn { let bar =3D self.bar; =20 @@ -138,27 +140,40 @@ fn handle(&self) -> irq::ThreadedIrqReturn { } leaf.clear_vectors(bar, GSP_BIT); =20 - // SWGEN0 is the message-queue notification, so wake the IRQ threa= d to drain it. let status =3D GspFalcon::take_swgen0_intr(bar); - let ret =3D if status.swgen0() { - irq::ThreadedIrqReturn::WakeThread - } else { - // The tree routes every falcon cause to this vector, so somet= hing other than a posted - // message fired it, for example a HALT from a GSP crash. Ther= e is no recovery path for - // those causes, so report the status rather than discarding i= t. + + // Every cause the falcon reports leaves the falcon's enabled set = on this invocation. A + // cause left latched holds that set non-empty, and the falcon sig= nals the tree only on a + // transition of the set, so no later SWGEN0 would signal at all. + let unserviceable =3D status.with_swgen0(false); + if unserviceable.into_raw() !=3D 0 { + // The tree routes every falcon cause to this vector, so a cau= se other than a posted + // message also arrives here, for example a HALT from a GSP cr= ash. nova-core has no + // recovery path for those, so report the status rather than d= iscarding it, then mask + // the cause. dev_err!( &self.dev, - "GSP interrupt with no SWGEN0, falcon IRQSTAT {:#x}\n", + "unserviceable GSP falcon interrupt, IRQSTAT {:#x}\n", status.into_raw() ); - irq::ThreadedIrqReturn::Handled - }; + GspFalcon::mask_and_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 enabled causes, so a cause= that arrived while this + // handler ran would never reach the CPU. Re-emit to supply that t= ransition. + GspFalcon::retrigger_intr(bar, self.chipset); =20 // 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(bar, GSP_SUBTREE); =20 - ret + // 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 + } } =20 /// IRQ thread: drains and dispatches the GSP-to-CPU message queue. diff --git a/drivers/gpu/nova-core/regs.rs b/drivers/gpu/nova-core/regs.rs index 2a0489472a66..01fde2c5e5a6 100644 --- a/drivers/gpu/nova-core/regs.rs +++ b/drivers/gpu/nova-core/regs.rs @@ -200,6 +200,15 @@ pub(crate) fn usable_fb_size(self) -> u64 { 6:6 swgen0 =3D> bool; } =20 + /// Masks interrupt causes at the falcon, one bit per cause, in the la= yout of + /// `NV_PFALCON_FALCON_IRQSTAT`. + /// + /// A masked cause is excluded from the enabled set the falcon signals= on, so it cannot be + /// raised again by `NV_PFALCON_FALCON_INTR_RETRIGGER`. + pub(crate) NV_PFALCON_FALCON_IRQMCLR(u32) @ PFalconBase + 0x00000014 { + 31:0 value =3D> u32; + } + pub(crate) NV_PFALCON_FALCON_MAILBOX0(u32) @ PFalconBase + 0x00000040 { 31:0 value =3D> u32; } @@ -327,6 +336,17 @@ pub(crate) fn usable_fb_size(self) -> u64 { 0:0 reset =3D> bool; } =20 + /// Re-emits the falcon's enabled interrupt causes into the interrupt = tree. + /// + /// Write-only. A falcon signals the tree on a transition of its enabl= ed causes, so a handler + /// that cleared the tree leaf while a cause was still latched has lef= t no transition behind, + /// and this write supplies one. Turing falcons do not implement this = register. + /// + /// OpenRM 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; --=20 2.55.0 From nobody Wed Sep 30 12:58:54 2026 Received: from SN4PR0501CU005.outbound.protection.outlook.com (mail-southcentralusazon11011067.outbound.protection.outlook.com [40.93.194.67]) (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 4A6E538425A for ; Sat, 8 Aug 2026 03:11:55 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=fail smtp.client-ip=40.93.194.67 ARC-Seal: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1786158717; cv=fail; b=LANV7tYwiMsn70PbFmHaAPMbMnbchUEuCdIbmhX0IECrooH3uMwynyY98iIr+MLlRyqknQHcYR8P0LXRMDELCaSQouDUE3N7wC9VCyN8p2j5RaKkrqbWbOsh9n5RhhfTpsibrzdf1OWnST0oaSaE6crOhjzmSRpHJT5ihcuD0iQ= ARC-Message-Signature: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1786158717; c=relaxed/simple; bh=h4eq9NB9uEDcy2xOoxP6d93Q72R4t6DNrGLfaTOMhF8=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: Content-Type:MIME-Version; b=NilDd0hJfZFiQXq+xM3FvRkRh6GGR3S6a+a7VA7fC4q13GWoEDjeEgWE8CqHt1u8otM4BPkE7C4iSLJbEBTtiD9ow0+KPBzq3x5ki1cSXCJLMLA7z5osY2XuDCplnw91JRmCb5KX0wzUtXrKslA/T7zMqNg895PfTbYnG6h6CeY= 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=Y4EK8ZqZ; arc=fail smtp.client-ip=40.93.194.67 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="Y4EK8ZqZ" ARC-Seal: i=1; a=rsa-sha256; s=arcselector10001; d=microsoft.com; cv=none; b=w18uPdudQIosvPXY3fxJtpnBqVm6oc/o6KjYYtM9YUDD3liWE7x4wu0Qm37QYSCKuzmzIJ3rsccJCmb+mvPoXte2XedN44nO0sStfIiWjvqzZbOifoMI3SQrkNsG3ong12aDwYjRlqBLQmtIIZO2AV85dX5pU2d4KlCEmpYFkeUJU8vUIvmxIzPhV1/kRwvD9zPPOwRqwdXvCbnNpQbnRmJwd3X9KlnYTj0bLfYTRBUbTH9z2a9nvEWv7kjFrBUgQ5LW4bBf5SK99c+dRajD+3AmTEJ2zAVHrpWLxSMnK40/j20fv7gW0bMSHqUPwfWldNIynXATPa+bAHlcRZnYqQ== 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=dvjToK9qKyJuDHO/ZlyLQR+0MXwXOfiDXbSzMcDvSDU=; b=dqeS3izav+VSh4+lEdamIr3pALJeCamP3hXdW0xiCyAnHHkXONDOhEhSknOz6txcrFGqsJpEkmcZLKkD8u3fs4R7nV6VM9bRhRmfVyCepfeH/7/fTBArC5qeqbpIV2v5ovoQltU3FKIoyq+3Sxvi5GPvb+WI+ZVjSo1uTr+LSVqaZsGsrRrvncjwLuN8HEps8PHih8ZzVjtzIMGShW3E+Qrnz2BGiK0WuKN4CTQJ/yp9VgTTxjkiKvrT8mzFqHCywuntzV5ZuLs+YwIvwEQisNpXlUB3ObFliu1VHGhugAeOLu31zJbrtkORXFT3vhhikAKjT0RlfNUXuUwENjIo5Q== 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=dvjToK9qKyJuDHO/ZlyLQR+0MXwXOfiDXbSzMcDvSDU=; b=Y4EK8ZqZA1Qh0QDV121vb6NXCh6HI94opAR7fv4kkr5h3DJyxzC3SeOcfK9Idr683jYZmhGgrJesySZCTOlDQA1P9XAyVBsbFzNl9fThRTn0Ppu+6Qb8Aca/CM0d5hMWFC6dr6rnnDhN9J4DCZzRYWJa/sg00JI9HUcLSiSOoDvF9fXTAOs6YGQxfN8N/bIeQxD51FN5OcZAkXZK+c1s6vmJPxTzXl4H4JuJbYvY8lcdQm9eiLJHotRV+MhRam8qgLZGTcS2GQCQ+TUf9CVhc3GyXcjbv47h08eLSiT/k/e8PdcXfxQGJqmuLnEKCIR8mWjRKn6Dfx/cQUgsMx58MQ== 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 CH2PR12MB4198.namprd12.prod.outlook.com (2603:10b6:610:7e::23) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.21.292.21; Sat, 8 Aug 2026 03:11:42 +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.0292.022; Sat, 8 Aug 2026 03:11:42 +0000 From: John Hubbard To: Danilo Krummrich , Joel Fernandes , Alexandre Courbot Cc: Timur Tabi , Alistair Popple , Eliot Courtney , Shashank Sharma , 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 16/17] gpu: nova-core: add KUnit tests for the interrupt tree and HALs Date: Fri, 7 Aug 2026 20:11:18 -0700 Message-ID: <20260808031120.363869-17-jhubbard@nvidia.com> X-Mailer: git-send-email 2.55.0 In-Reply-To: <20260808031120.363869-1-jhubbard@nvidia.com> References: <20260808031120.363869-1-jhubbard@nvidia.com> X-NVConfidentiality: public Content-Transfer-Encoding: quoted-printable X-ClientProxiedBy: SJ0PR13CA0216.namprd13.prod.outlook.com (2603:10b6:a03:2c1::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_|CH2PR12MB4198:EE_ X-MS-Office365-Filtering-Correlation-Id: eee15560-af60-42f7-6117-08def4fac53c X-MS-Exchange-SenderADCheck: 1 X-MS-Exchange-AntiSpam-Relay: 0 X-Microsoft-Antispam: BCL:0;ARA:13230040|23010399003|366016|376014|1800799024|7416014|10067099003|6133799003|56012099006|11063799006|18002099003|22082099003; X-Microsoft-Antispam-Message-Info: C1w4mbdeRkgjzhkAV7lH9UlbvgkTMO46W31yq33YVlfnsRZNApeyZdPQ9e+ysFksLvcWAzjj8Ey3O/vZQoxB+XME2zJEBCBmdhwprO79Svpd2rbg6QSpE4P4tACH/w0LHXgjXKjf5MPQXHfuJ+U5YBBSPrSPYmQoDRdrRR157QF1uxej020vCUosQujyapQeNvCYfja9o/TqvEtUr+vDrMGNy9mqzsHIovsnBI+Hu7m60hk8PE9WRL0fcVYqbKO8cgBgcEc6C/iGraKLXSmWVZeIkIH4Oo65t73L4j2YLQen4dJYnoJohutKkxpLgCW3gYuLuvebTlUr2DYfPPEYj9dVEAYgWsNBUt+ccRPvDTqfl8S1XNXUSFkoTmfDJIJjFVr3n7iwMsPetw/Y4C1ZtgZuAdyZ/1LxyoLNGE7y6uOAPWD9/yVNb6KfLUA9zcaQHIsy+oSdwd8sbqjwcCgutvz5jyF/NHfE8gZy+tiJuvn564KP345JPiC8qbrEEXtq6uXVLc1z57IPulA8Guz2zS3zjizFDeyOp5FslIRR5nu7nl37DPivmKZs+hdgwJDhRm2eTfgazG2jgrFUqaMquuBpqz+ca3p9y6vbVfvuLZiZODeRPXx6Sybo8Ti4zofFrab06R8TMyYJ9zJxMOO5PmjfHgQxvL4PknzIZ+nymVQ= 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)(23010399003)(366016)(376014)(1800799024)(7416014)(10067099003)(6133799003)(56012099006)(11063799006)(18002099003)(22082099003);DIR:OUT;SFP:1101; X-MS-Exchange-AntiSpam-MessageData-ChunkCount: 1 X-MS-Exchange-AntiSpam-MessageData-0: =?us-ascii?Q?xhmJHkQB49mlen9uSbx2GQtKshlRZMEY4K4Pc6oDx8J5vCZ8T+CxCAQQemzn?= =?us-ascii?Q?W7RLdrL3f0ZawjbgWg9a8AsSrRCmFWU542Jxc9iUS/uQbIYPDW020LdrNaJn?= =?us-ascii?Q?vyLj7hQvxRzY12Sxg9sZH+UoBfhAr6ijSVwabBtYxIL5ZngwDfZMt+93Go6J?= =?us-ascii?Q?0lNTYZ+FSdN1H0OpXeHYFWo1wVxuc5Y/HjraSHUJficsbKlSXv4KZtHolV9G?= =?us-ascii?Q?r380Kv2wmibp1CI8JKUDgoI0+P6MZQY1+CDrcb5Dv7L61PMjb7fN6cDRBnwP?= =?us-ascii?Q?aD5UygDVZsxp/As27pGgvVSiR5lVP/xpM85YoLEiApyL96nNrTmDlgfN0tnh?= =?us-ascii?Q?BghZwNhMOfEiIUh2WNH8oG2xChZB51wHC13TsSnJRYtKyoaGZ9fdPUN14eJv?= =?us-ascii?Q?/OCbL/lwUQpWHvXEjEniS3iXXEDB+uZpBUzeqU8k9o8tMMij7MlNMzmyHbdi?= =?us-ascii?Q?A269Fcn1gevpQgh92oHRrFJMgDtnISUnLs63SO+/2Ajum8njBrrbbbGwkBNI?= =?us-ascii?Q?xiP6C+D23sQgJTz+QVUKITtFAZUXWMqnyvNSI9tLk4Wb3To66pNrP4/U+AkG?= =?us-ascii?Q?Ty1fiWBjKVvW21JTq6yPHclYfJMd1MPpIhA8ktBU1C4xFGRzxwRaPcJNMuiz?= =?us-ascii?Q?bb5w20Ih3u28M4WtK+uM2vd66QHw/XlSqZ1wqGUijzH08po1fZz8HVidNiWH?= =?us-ascii?Q?S7ldW0ELn/euUu4OWvPSHsxn2CjLwryxlnXniud0e4rEmxIHuuVzol6OZhzn?= =?us-ascii?Q?pPDuYkVJGSFN/sKCl+3YzwIcrJkl+BfpSN/NTVzfnFAK698PJLP5Mkf02n7d?= =?us-ascii?Q?53STtV/TR7WbN9UM1c2slpFqSVFEHjHj1dUxqXL1lsl6l0YkqphWXkhVctKm?= =?us-ascii?Q?VGPAGvmevj+Gn6tYiAchDxhmwfkBlD1b4iV/dCwN1TO0SrMyJVYmdKJCEYwM?= =?us-ascii?Q?UEQqpaMdGWylFjtRX9CfGsKNYthnonUErO4KYzcGYgd89fA6B+WgFA7JSn4G?= =?us-ascii?Q?JCijIUe9IXcuOJIaCv5YSf0S8X6TD63F0CeZ25pFVAP6wiV1XYQxx67N1+vJ?= =?us-ascii?Q?e0mEk4yUkdMPUtUjsTnnxUxH1hhuri2nPGsgKKcxrxFgD6OVtS/lFi1dbf3t?= =?us-ascii?Q?SxIhPKdDuMW+A0oKRAYAMOOuBI9kGJAU+B3rq27Xtoqw4wi8qmJEbxiTGqlh?= =?us-ascii?Q?QuQjjXyGx8nua35bzx4GWGL14C4paraXFRWAigqUqthwMfti8PkdphhX13Vg?= =?us-ascii?Q?LPV7jIcbGd4QvN/1+NkYFgo/7Mg8JAyceIz5ZRAcorc8eQC9GLaGohxM4HGg?= =?us-ascii?Q?PB0z1hG3XbpMPhqi6svToaj0rRyPW/lLN4Ue+kEnk5z9p0MhHn0qbiYuX3qy?= =?us-ascii?Q?Zzpd4yllCyLuTEzYj1LkskptEnj1KOJk+FhmfqHRexM1IQ9B6m4quxpFubaI?= =?us-ascii?Q?9uSmN8SS8WHtZj4/Cb+rOU4tOwSQ6i/rQxzwYGbObzcy1o16bz8Ej1+uZYQG?= =?us-ascii?Q?XnKQkx9ktbFRIr3L4t57LFHdVjvNzYC3ktebS1DB5rOtvtfy/vQWI2QCW/TQ?= =?us-ascii?Q?mbiolodCGAcldX7CEbH7BAoekH/L9ws/p/tDTkXRGJZJCkd2nPB0O/SJ5bZQ?= =?us-ascii?Q?frVQmLZ2IGk31I0YLhkkISBsVuSbYAxHgdrP+gW0wvcIxcUgY1gKZb8qgkBj?= =?us-ascii?Q?YK3fFKS/0u1rshM2dQp7UssPzKidTsxsp72czwGawSc+0OuiNbJo3xcMJqe6?= =?us-ascii?Q?j9eRRQG9Gw=3D=3D?= X-OriginatorOrg: Nvidia.com X-MS-Exchange-CrossTenant-Network-Message-Id: eee15560-af60-42f7-6117-08def4fac53c X-MS-Exchange-CrossTenant-AuthSource: DM3PR12MB9416.namprd12.prod.outlook.com X-MS-Exchange-CrossTenant-AuthAs: Internal X-MS-Exchange-CrossTenant-OriginalArrivalTime: 08 Aug 2026 03:11:42.2899 (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: 9H24m9QB6EUkV7L11ywjAJn6llu/m2Pm0b4KlRt90jJZEL7l2b1/uXfw1kHlhpqNBCj5r+3T2l9FheIeliR+fA== X-MS-Exchange-Transport-CrossTenantHeadersStamped: CH2PR12MB4198 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 leaf index bounds, the subtree-to-leaf mapping and its out-of-range filtering, the vector encoding, the masking of subtrees an architecture does not implement, 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 combination of family and interrupt type. * nova_core_falcon_hal covers the falcon retrigger gate. It is keyed on the architecture rather than the HAL, because GA100 shares the Turing HAL but does have the register. Assisted-by: Cursor:claude-opus-5 Reviewed-by: Will Pierce Signed-off-by: John Hubbard --- drivers/gpu/nova-core/falcon/hal.rs | 24 ++++ drivers/gpu/nova-core/irq/hal.rs | 106 ++++++++++++++++- drivers/gpu/nova-core/irq/interrupt_tree.rs | 121 ++++++++++++++++++++ 3 files changed, 250 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/nova-core/falcon/hal.rs b/drivers/gpu/nova-core/fa= lcon/hal.rs index f0828b32aebb..6bff9fea1a79 100644 --- a/drivers/gpu/nova-core/falcon/hal.rs +++ b/drivers/gpu/nova-core/falcon/hal.rs @@ -107,3 +107,27 @@ 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)); + } + } +} diff --git a/drivers/gpu/nova-core/irq/hal.rs b/drivers/gpu/nova-core/irq/h= al.rs index cf2d1aa080fa..1993e2ef5143 100644 --- a/drivers/gpu/nova-core/irq/hal.rs +++ b/drivers/gpu/nova-core/irq/hal.rs @@ -8,7 +8,8 @@ =20 use kernel::{ io::Io, - pci::IrqType, // + pci::IrqType, + prelude::*, // }; =20 use crate::{ @@ -109,3 +110,106 @@ 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, so 4 subtrees and `0x0f`. + #[test] + fn pre_hopper_tree_size() { + for chipset in [Chipset::TU102, Chipset::GA102, Chipset::AD102] { + let hal =3D cpu_interrupt_hal(chipset); + assert_eq!(hal.num_leaves(), 8); + assert_eq!(hal.implemented_subtrees(), 0x0f); + } + } + + /// Hopper and later implement a 16-leaf tree, so 8 subtrees and `0xff= `. + #[test] + fn hopper_plus_tree_size() { + for chipset in [Chipset::GH100, Chipset::GB100, Chipset::GB202] { + let hal =3D cpu_interrupt_hal(chipset); + assert_eq!(hal.num_leaves(), 16); + assert_eq!(hal.implemented_subtrees(), 0xff); + } + } + + /// The implemented subtrees always number exactly `num_leaves / 2`, o= ne per subtree. + #[test] + fn implemented_subtrees_matches_leaf_count() { + 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.implemented_subtrees().count_ones() as usize, + hal.num_leaves() / 2 + ); + } + } + + /// 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(IrqType::Msi), + Some(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(IrqType::Msi), + Some(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(IrqType::MsiX), + Some(PciIrqRearmMethod::TopEnableCycleSubtree) + ); + } + } + + /// `INTx` is level-triggered and needs no rearm write on any architec= ture. + #[test] + fn intx_needs_no_rearm() { + 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(IrqType::Intx), None); + } + } +} diff --git a/drivers/gpu/nova-core/irq/interrupt_tree.rs b/drivers/gpu/nova= -core/irq/interrupt_tree.rs index f4f1494cddba..42e72fa8089e 100644 --- a/drivers/gpu/nova-core/irq/interrupt_tree.rs +++ b/drivers/gpu/nova-core/irq/interrupt_tree.rs @@ -302,3 +302,124 @@ pub(super) fn clear_vectors(&self, bar: Bar0<'_>, vec= tors: u32) { } } } + +#[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()); + } + + /// Subtree `N` covers the two adjacent leaves `2N` and `2N + 1`. + #[test] + fn subtree_covers_two_adjacent_leaves() { + let tree =3D Tree { + num_leaves: 16, + serviced_subtrees: 0xff, + rearm_method: None, + }; + + for index in 0..8usize { + let mut leaves =3D Subtree { index }.iter_leaves(&tree); + assert_eq!(leaves.next().map(|leaf| leaf.index.get()), Some(in= dex * 2)); + assert_eq!( + leaves.next().map(|leaf| leaf.index.get()), + Some(index * 2 + 1) + ); + assert!(leaves.next().is_none()); + } + } + + /// Leaves that fall outside the addressable range are filtered out, n= ever panicking. The + /// filter is the [`LeafIndex`] bound, not the tree's leaf count, so t= his holds even on the + /// widest tree. + #[test] + fn subtree_leaves_out_of_range_are_filtered() { + let tree =3D Tree { + num_leaves: 16, + serviced_subtrees: 0xff, + rearm_method: None, + }; + + // Subtree 8 would cover leaves 16 and 17, both beyond the leaf in= dex range. + assert!(Subtree { index: 8 }.iter_leaves(&tree).next().is_none()); + } + + /// The production [`vector_leaf_bit`] maps every vector to a `(leaf, = bit)` pair, valid leaves + /// stay within [`LeafIndex`], and the fixed doorbell (129) and GSP (1= 55) vectors land where + /// the handlers expect. + #[test] + fn vector_maps_to_leaf_and_bit() { + // Every vector of a 16-leaf tree maps to an addressable leaf and = a bit in 0..32. + for vector in 0u32..(16 * 32) { + let (leaf, bit) =3D vector_leaf_bit(vector); + + assert!(LeafIndex::try_new(leaf).is_some()); + assert!(bit < 32); + assert_eq!(leaf as u32 * 32 + bit, vector); + } + + // The fixed vectors the handlers rely on: CPU doorbell 129 and GS= P notification 155, both + // in leaf 4, which is present on both the 8-leaf (pre-Hopper) and= 16-leaf trees. + assert_eq!(vector_leaf_bit(129), (4, 1)); + assert_eq!(vector_leaf_bit(155), (4, 27)); + assert!(LeafIndex::try_new(vector_leaf_bit(155).0).is_some()); + + // The first vector beyond the 16-leaf tree lands in leaf 16, whic= h is out of range. + assert!(LeafIndex::try_new(vector_leaf_bit(16 * 32).0).is_none()); + } + + /// [`vector_subtree_mask`] agrees with [`vector_leaf_bit`] on which s= ubtree holds a vector, + /// and the doorbell (129) and GSP (155) vectors share one, so a singl= e allocation and a single + /// enabled subtree serve both. + #[test] + fn vector_maps_to_subtree() { + for vector in 0u32..(16 * 32) { + let (leaf, _) =3D vector_leaf_bit(vector); + + assert_eq!(vector_subtree_mask(vector), 1u32 << (leaf / 2)); + } + + assert_eq!(vector_subtree_mask(155), 1 << 2); + assert_eq!(vector_subtree_mask(129), vector_subtree_mask(155)); + } + + /// [`Tree::new`] drops subtrees the architecture does not implement, = so a caller cannot enable + /// a `TOP` bit with no leaves behind it. + #[test] + fn tree_new_masks_unimplemented_subtrees() { + assert_eq!( + Tree::new(Chipset::TU102, IrqType::Msi, 0xff).serviced_subtree= s, + 0x0f + ); + assert_eq!( + Tree::new(Chipset::GH100, IrqType::Msi, 0xff).serviced_subtree= s, + 0xff + ); + } + + /// Every supported chipset implements the subtree that carries the GS= P notification. + #[test] + fn serviced_subtree_is_implemented_everywhere() { + let serviced =3D crate::irq::gsp::GSP_SUBTREE; + + for chipset in [ + Chipset::TU102, + Chipset::GA102, + Chipset::AD102, + Chipset::GH100, + Chipset::GB100, + Chipset::GB202, + ] { + assert_eq!( + serviced & !cpu_interrupt_hal(chipset).implemented_subtree= s(), + 0 + ); + } + } +} --=20 2.55.0 From nobody Wed Sep 30 12:58:54 2026 Received: from SN4PR0501CU005.outbound.protection.outlook.com (mail-southcentralusazon11011067.outbound.protection.outlook.com [40.93.194.67]) (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 200263914ED for ; Sat, 8 Aug 2026 03:11:58 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=fail smtp.client-ip=40.93.194.67 ARC-Seal: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1786158721; cv=fail; b=OGNwMQaZX3a1dUYR8J5TO1dmMb4iJ4iJc/Z2Qk8X9SoUPlBAUnGkZWXjHlZqtZ8bs5HpcVHJi5gkpH7suWzP3FYHhLMEWwi4gzxLdKdJr2Ibf4YM59qj1TOib0q65UJeaOCwlHTqc9RvkNbXVNzQ52vacBnoCcVbuqbHmVUzOOU= ARC-Message-Signature: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1786158721; c=relaxed/simple; bh=evnDeYWsbDECJwSflo7XxRmeh+7kIQG4DoXHKKaYeTM=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: Content-Type:MIME-Version; b=XpYvYH1bLfWq91hhHdnpqW4yfImCshxBdVolJ4I1pdlpjEMALzgnA3c6ilbIQLfATXaHP/bQnXmMOD6nPYOE806p8WJAD0r4OiABHmlGFtpYw0uLbJGlVGXhZR8JbUlURdlWgpmDgj/ey9C3QYuhVQwxhXKf16ls8gByPCUcRFY= 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=YKkSNP2F; arc=fail smtp.client-ip=40.93.194.67 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="YKkSNP2F" ARC-Seal: i=1; a=rsa-sha256; s=arcselector10001; d=microsoft.com; cv=none; b=JFhMIjGx6etfch3hLIAHs2r+VpkFC7c0eQP7LlKnp/usQfHqs58NMwtndk65x1ppI71g0824BzDMsOVupTtdPFEEHyGRKs97Gt5wev04FtXtG5Gn3rZRPe0nMIlQ7O6Afvc/mniiMcpqut2a4q4bBw064zhgNjF2r6JZ4HfHBcg1hLs9pEOrh1WmWmRYi2nvLG6FQwm1jh+Ij4aKOkzh7fAQF0ATtNRNf6tatYuBCTdEKkUU/x9fdN5bI0O9sQ03S9czFOGW5llcquzlQj0SMbQ7FzxQz8syPDQD7vb5bGOwHtY+4MkeYbvuA3hsCO5ZqJhuVinmgBHdVwWIoTWI8w== 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=n/X1cb403rOEFwBmvsVJiAiU5RIpM+v9EPxNBHtCrUs=; b=P/eR3n2b9VgNQiP5pfAtKQSFABTlTLPv6WRcKCXiN2lH+p9FRlzjVvxWIuFPxS2vH6U8PsUESy+ZXaHl2LVNd70EI4f8Yfnx9y9pLP9XtKzIQpHyVaDsAXpgMiFz1UzPmgzQdUnXMVRFJ9I/gY+/43Su++T4wdpe5HPDaAdE5IVCfgAX4va9miUeTokmienWaZ0AKzPyR4zxO5Re2NF4CAdXcQPjhZtSGscpGmkwbDOHUqyY2+pLK7hTpt1o/y7MEqZeGR4qJpIpm4Nnz6ZIL586Rnwp6RAaeelyQuGcxyWEUWwRSIiQHpUpgUquCwPVmYc42GIckj8idAfUHh2WUA== 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=n/X1cb403rOEFwBmvsVJiAiU5RIpM+v9EPxNBHtCrUs=; b=YKkSNP2F+ohxg37+j2lsyRuMbmgpU7NrbGCGn3Zo4y2YuKlyyIKJ3rx/BJMCZ8fk9XTIcS/f4FjH//16fajgYP+XfFE6oh+YrDUfdffAc3aoIzJWOfuKE8rUWDUsHW8R4u35Co5FuOTXYlqBG5MQtdQeo4lE20jCfJbUwTD6grv70ePc4INsOEnxQGwP6fpwopahrnoc8V3CNy5c7zTuweIYlH98DVTmxgWbVOgQP6yWO9HvPMna6yaOlVg1M2VcWxpfYy6/ON2LEK0tmrUpHzTSRcM47JMe0Zm6DOfRj9cZl+jSfGNvjIlvVcz2wCCYj+uGI0wAvdDqFsn/AxxfsA== 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 CH2PR12MB4198.namprd12.prod.outlook.com (2603:10b6:610:7e::23) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.21.292.21; Sat, 8 Aug 2026 03:11:43 +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.0292.022; Sat, 8 Aug 2026 03:11:43 +0000 From: John Hubbard To: Danilo Krummrich , Joel Fernandes , Alexandre Courbot Cc: Timur Tabi , Alistair Popple , Eliot Courtney , Shashank Sharma , 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 17/17] gpu: nova-core: document the GIN interrupt controller and GSP events Date: Fri, 7 Aug 2026 20:11:19 -0700 Message-ID: <20260808031120.363869-18-jhubbard@nvidia.com> X-Mailer: git-send-email 2.55.0 In-Reply-To: <20260808031120.363869-1-jhubbard@nvidia.com> References: <20260808031120.363869-1-jhubbard@nvidia.com> X-NVConfidentiality: public Content-Transfer-Encoding: quoted-printable X-ClientProxiedBy: SJ0PR03CA0336.namprd03.prod.outlook.com (2603:10b6:a03:39c::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_|CH2PR12MB4198:EE_ X-MS-Office365-Filtering-Correlation-Id: fd158c0b-b7dc-4d2e-b50e-08def4fac61d X-MS-Exchange-SenderADCheck: 1 X-MS-Exchange-AntiSpam-Relay: 0 X-Microsoft-Antispam: BCL:0;ARA:13230040|23010399003|366016|376014|1800799024|7416014|10067099003|6133799003|56012099006|5023799004|11063799006|18002099003|22082099003|3023799007; X-Microsoft-Antispam-Message-Info: KRcMbcm7YDwHux0tn2Uupm7JUV1PxlaTa64CP/SwgMIaUr3RlrENMORTOdKzMze/z2AigotDyrd6El3+D8iP37xLgXU5LHhrnDO2o/n+hBxyjJFhYmfvDvvZniorJ3yQjrpJvH+H+zbvJaRAf8AA5s6AVtxbUbliPmWfx+KQ03SAYpvS5WCjhvrH3ZbdDrNzdCaEU4GMLGNF54VCo11VOKk+N4KJ/1p2r5Wgqbig1kjZy+J5ot3KXSg6OYNiv4UW1M/Lf7NqA4pW3TDX8L3X5jKN2gu583fw0HKJDWyNzeJvCiOhQRUyVvjcL0j0l6YHVRh18gL7A9ieBnSm2bnmMlClXQOBITlJsq36j/YaazetIm9cOXU0g0LkrcsaCvf36kpCwW7CwuxsTePcQLeDYXqkY/i2oyuLilzaSn2WUsN7PfrK8/6sLr5YNs6U8RQiT/sl3YKFAVAIgM5Y4ZfDMLt+q+PZN8A60i2RT2piiHWpe4yEP0SHrtFLKEBAlTNaEKnyZ8fhNR0PybZ59JFdRigyGfNbRQ5jdy2NIJq8kG2wpoiKW6/yth/DZ0X9NFNlsNkR21EPPOVM/Gi3Xqi6UCNmSaxqaIROiHQUC/DgE+ZS4ufKgY9VO8zoT4Or3jCHgqj2cHnZxy48YpspDRpS5Va96bg8/q9wCc1WZn9UPC8= 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)(23010399003)(366016)(376014)(1800799024)(7416014)(10067099003)(6133799003)(56012099006)(5023799004)(11063799006)(18002099003)(22082099003)(3023799007);DIR:OUT;SFP:1101; X-MS-Exchange-AntiSpam-MessageData-ChunkCount: 1 X-MS-Exchange-AntiSpam-MessageData-0: =?us-ascii?Q?bytvzvEzikjp2h7a1nqvehCRZUhFiCw2/wdyBJzgB0Iv0MYqj07bLJLQZr9k?= =?us-ascii?Q?CZcYkuVozP0a/QChgCFQpNnA3xTLxT8lA9n9j3xLtUcQ18TWxoRfi7NYemvl?= =?us-ascii?Q?XCfpwa0rPj0NXm+6CZNmB2d3nwo9oG08SgFgNNja2Zsx2Fzq/8sFklgWo9aS?= =?us-ascii?Q?8/DgimRtVFVuQxs4oUe85o5MSRXvlXA7W8amjOnuLiuKNVESCKeaxcDWDjp5?= =?us-ascii?Q?VfF3yw7nfIKi3zYtvxXn58b50OH6ldlCES80HCA2k0CD+dA0MKQgmptc7Gmd?= =?us-ascii?Q?ATJM8/ssjrwor4iiITdkhE8o4yG/Tyws0ZPJ2MJGeKeGWiC1EQw63+3bFznX?= =?us-ascii?Q?c4qrysuTfQkK0yQJnNQ8bA5oVQ2fF48cklmW0uh6cri15WBRCxhtaHov3Azs?= =?us-ascii?Q?Y30BsMyyP+XGncn+TpvuJRxLT2ZR1x6lDa9tGjkSMJHtuWAeEgi4KZ46AqzY?= =?us-ascii?Q?+IlRCCYc9qGuARGVBWkrg0+J/uNEq9ws77sZpB2TmUIsucAiy7mhJTMprMtJ?= =?us-ascii?Q?AezB3Rzxqx+I++8TxDy8MXU62Y7OdeDpGK4uSNg4TyZL8l2rJ+mE7JmC6WqE?= =?us-ascii?Q?MJMPi7w1JcLRvoCNlpcGGlcEJnbhXXpMnBB7d13oZ3U9svm0d42yur4H7SaP?= =?us-ascii?Q?/LRMKmNT4Z+xlPSZ7nhjRzQGY76cx9dnF6+gtVolE4oY1GVIPBIyxUOFc0hU?= =?us-ascii?Q?6plJbssaM5T0iSZwzdj1njidEhaFFrh51OiHgXxEyO7pFhfD4eyL4yralbWO?= =?us-ascii?Q?jr+ZSQaIl657i9msLGaLMA0WV8m6bQaOsZ1KiovQs3/HyeOjZwzctOVRrtqx?= =?us-ascii?Q?xjS3GBmK+2CGl96kS/ZiuR0QS5cO4CsohJTFsBXT3Gaywl57a31TbOf1qnCf?= =?us-ascii?Q?xBnGkiEPijIjxLl0hAASE6K6ydeXIIKUZ34Y1JcHJ6i3nqFALmH7eCCi1z89?= =?us-ascii?Q?D3aeP+yVJa0peDUCce/w+KGgTlYEhaJ8WztTPaszoO4hW744CHSaIcYNEc+B?= =?us-ascii?Q?WKLvGD42H6bDXkvvoiq6ytDCfR7cf8FLUb+Nap2LBlj10eNk66vfLlXzS3Fc?= =?us-ascii?Q?9vC7tfXgzQFXcsQ6wT+c37oXOOd0dhQ8WLsg6isunWEp5afrEwbydiFVpKYS?= =?us-ascii?Q?B07nHnyd0LI4sN/lquLTrdlpwRq0zDAui7MoynKPExk3Pd0LaHD2/xxO56Y7?= =?us-ascii?Q?HjIzTD4mm9XsKRl8k4Ag8CygBX2f/wfRY6XH/+vPfkU6I3vWpCt/Mu2iaUQE?= =?us-ascii?Q?EU8kqoVXH5JhrYJetd5+bnAN+BY65TpEokCIBnPxFaOEeiNSPhtK9EqdZzTM?= =?us-ascii?Q?D+9PQXWt/MJcxYHBs69PWrYJA9kDILdUomjQZx/RYIiAIWbUv+I+l91X7IHg?= =?us-ascii?Q?7by364z13Oh9RWZs5M/DnfsCc1kmzzDfl+esKkdQlLGoVKMUusV7rYJtrVRV?= =?us-ascii?Q?9qGabGZFtrhGNAHT76PBN9V8GX62A1B0LRLkUIkhUh2C0u9tYoGWJEfGg5NN?= =?us-ascii?Q?MCENdomPTEpLKLYPXSONhfVTUJFkkYDU7NLhLy7hZE5gSc73JFabb2v7JFPJ?= =?us-ascii?Q?xmH6i4MOYh0CgnLk6JUDp6SrzgAcCiqykqKSEyqbyj+H8KAaF0qRK72EXk8u?= =?us-ascii?Q?FHCQMhi9+XJZfiBI1pj1/KJo6Yx81LUUeDeVWCyfH1zfn9mmhSsNoafxzWot?= =?us-ascii?Q?uI+g5JHR+1h9xxq5rrdrZ2Hyu/XspkKg3n3kLaJ1+ihsZpxtqlSUbJNaZKG4?= =?us-ascii?Q?0OnisXRHCA=3D=3D?= X-OriginatorOrg: Nvidia.com X-MS-Exchange-CrossTenant-Network-Message-Id: fd158c0b-b7dc-4d2e-b50e-08def4fac61d X-MS-Exchange-CrossTenant-AuthSource: DM3PR12MB9416.namprd12.prod.outlook.com X-MS-Exchange-CrossTenant-AuthAs: Internal X-MS-Exchange-CrossTenant-OriginalArrivalTime: 08 Aug 2026 03:11:43.7859 (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: In0eOx/lgVn3uyax1Fw3K9XsifWaUxTeFl+Y51XctIOBnE0kDzzcB1xxXWeJmacmmax1m6/StcyEmCNzuk2wYw== X-MS-Exchange-Transport-CrossTenantHeadersStamped: CH2PR12MB4198 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 is invisible 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 it reaches the CPU under MSI and MSI-X, and the rules those behaviors impose on a handler. It also covers the GSP event: the falcon retrigger, the handoff from boot-time polling to interrupts, and how its messages are classified. A glossary names each term after the register or the specification that defines it. Assisted-by: Cursor:claude-opus-5 Reviewed-by: Will Pierce Signed-off-by: John Hubbard --- Documentation/gpu/nova/core/interrupts.rst | 686 +++++++++++++++++++++ Documentation/gpu/nova/index.rst | 1 + 2 files changed, 687 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..d7ddbfd6a0af --- /dev/null +++ b/Documentation/gpu/nova/core/interrupts.rst @@ -0,0 +1,686 @@ +.. 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 live in the per-function +``NV_VIRTUAL_FUNCTION_PRIV_CPU_INTR_*`` aperture on every supported part, = and +the controller itself has a second name on pre-Hopper parts (see "Register +naming"). + +Terminology +=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D + +Three different numbers are all called a "vector" in the surrounding mater= ial. +This document gives each one its own name and never uses "vector" on its o= wn. + +GIN vector + The GPU-internal interrupt source number, 0 through 511 on Hopper. It = is a + bit address within the tree: leaf ``vector / 32``, bit ``vector % 32``= . The + 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, 0 through 7 on Hopper. Linux's + ``struct msix_entry`` names its Linux IRQ number ``.vector``, which is= a + third meaning. + +Linux IRQ number + What ``request_irq()`` takes, obtained from ``pci_irq_vector()``. + +The remaining terms, each named for the register or the specification that= owns +it: + +enable / disable a GIN vector + ``LEAF_EN_SET`` and ``LEAF_EN_CLEAR``. + +enable / disable a subtree + ``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. It is a + ``TOP_EN`` disable-then-enable cycle everywhere except under pre-Hopper + MSI, where it is a write to the end-of-interrupt (EOI) register in the= BAR0 + configuration-space mirror (see "Rearming PCI interrupt delivery"). + +mask + Reserved for the two places hardware and the PCI specification use the + word: the MSI-X per-entry Vector Control mask bit, which Linux owns, a= nd + the falcon cause masks. It never names a GIN enable. + +latched, pending + A ``LEAF`` bit records its source whether or not the GIN vector is ena= bled. + A disabled vector's pending bit never appears in ``TOP``. + +clear a leaf vector + Write a 1 to the vector's bit in ``LEAF``. Open RM spells the same + operation ``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. The CPU's +handler reads that tree to tell the sources apart, clears the pending vect= ors, +and runs the work for each. + +How the tree reaches the CPU over PCI +------------------------------------- + +How many PCI interrupts the tree needs depends on the interrupt type Linux +grants. + +MSI has a single message, and every subtree raises that one message. One +allocated 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 masks e= ach +table entry a driver did not allocate, and a masked entry sends no message= : the +request sets a bit in the pending-bit array and waits for an unmask that n= ever +comes. A driver that leaves out the entry its subtree raises loses every +interrupt on that subtree, and loses it silently, with the GIN leaf and TOP +registers showing 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 one message that every subtree raises. MSI-X needs= one +allocated, unmasked entry per serviced subtree, and a PCI allocation canno= t be +sparse, so it runs 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 vector, whose handler's + rearm covers the whole serviced set + +The entries allocated below a serviced subtree that the driver does not se= rvice +cost nothing: Linux unmasks an entry only when its interrupt is requested,= and a +disabled subtree raises nothing. + +nova-core services exactly one subtree, subtree 2, because both the vector= s it +uses are in leaf 4: the GSP event (155) and the self-test doorbell (129). = That +is also the subtree the resource manager assigns to its ``UVM_SHARED`` int= errupt +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 BAR0 and cannot reac= h any +other tree. GSP firmware selects the tree each unit's interrupt is sent to. + +nova-core services the CPU tree of one function. The VF trees and the +microcontroller trees belong to firmware or to virtual functions. + +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 the othe= r 28 +bits always read 0. A 16-leaf part uses TOP bits 0 through 7:: + + TOP (one 32-bit register, and an 8-leaf part uses only bits 0..3) + + 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 + bits 4..31: always 0 on an 8-leaf part (a 16-leaf part uses bits 0..= 7) + + 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) + +Registers +--------- + +All the registers are 32 bits, defined in ``regs.rs`` under the +``NV_VIRTUAL_FUNCTION_PRIV_CPU_INTR_*`` names. The leaf registers are arra= ys +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). +* ``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]``. A vector that latched while= its + leaf enable was clear does not appear. +* ``TOP_EN_SET`` and ``TOP_EN_CLEAR`` enable and disable subtrees. +* ``LEAF_TRIGGER`` makes a vector pending in software. The self-test uses = it. + +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 + +Both of the vectors nova-core names by number fall in leaf 4: vector 129 a= t bit +1 and vector 155 at bit 27, so both arrive under subtree 2. + +Enabling and clearing +--------------------- + +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. + +* ``LEAF(i)`` is write-1-to-clear. Reading returns the pending bits. Each = bit + must be cleared before its vector is serviced. +* ``LEAF_EN_SET(i)`` and ``LEAF_EN_CLEAR(i)`` enable and disable individual + vectors in a leaf. +* ``TOP_EN_SET`` and ``TOP_EN_CLEAR`` enable and disable whole subtrees. + +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 that = bit is +visible only by reading the leaf directly. + +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 +get it: the CPU, the GSP, or another on-chip microcontroller). + +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. The one exception nova-core relies on is the GSP ev= ent +vector, which firmware pins to a fixed number (see "The GSP event vector"). + +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. A ve= ctor + that latched while its leaf enable was clear does not appear in TOP. +* 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 applies below TOP, so disabling a subtree halts delivery and le= aves + what TOP reports unchanged. + +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 walks e= very +subtree it implements reading LEAF registers. + +Because delivery is edge-triggered, writing ``TOP_EN_SET`` while an enable= d leaf +bit is still set produces a new edge. A full tree walk uses this: after it +clears the leaves, it writes ``TOP_EN_SET`` so an interrupt that arrived d= uring +servicing is still delivered. + +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 on a transition of its enabled interrupt causes. +Clearing the tree leaf while a cause is still latched leaves no transition= , so +the vector stays clear however many further causes arrive. Both clear orde= rs +have that window, so a handler on a falcon vector writes ``INTR_RETRIGGER`= ` on +every path that services the vector. + +That re-emit must not be able to raise a cause that nothing clears. A caus= e the +handler does not service is removed from the falcon's enabled set with +``IRQMCLR`` and cleared with ``IRQSCLR`` before the re-emit. + +``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 supp= ly a +transition that went missing, so it must leave no cause latched: it reads = the +status once and takes every cause that status reports, rather than stoppin= g at +the first one it recognizes. A cause left behind holds the falcon's enable= d 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 between the status r= ead +and the clears is not in the status, so it stays latched after the tree le= af has +been cleared. Open RM has the same window: ``kgspService_TU102`` ends with +``kflcnIntrRetrigger``, which is implemented from GA100 onward and does no= thing +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. + +INTx is level-triggered and needs no rearm write. nova-core does not alloc= ate it, +so it never reaches a handler. + +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 restore at the end of a full tree walk,= even +though two of the three forms write the same registers. The walk clears TO= P_EN +on entry so that it can read and clear without new interrupts arriving, an= d sets +it again on exit. For the two enable-cycle forms that restore also rearms,= but +pre-Hopper MSI rearms through the configuration mirror, which the walk nev= er +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, then enables them again. + +The drain reads every implemented leaf rather than descending from TOP. Bo= ot +latches vectors while they are still disabled, and those bits do not appea= r in +TOP, so a TOP-driven walk would skip exactly the state the drain has to cl= ear. + +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 subtree N, for i in {2N, 2N+1}: + pending =3D read LEAF[i] pending vectors in this leaf + write LEAF[i] =3D pending clear (write-1-to-clear) + write TOP_EN_SET =3D serviced restore TOP_EN + + Notification, subtree stays enabled (the GSP event handler, and the + self-test, which deliberately mirrors it): + pending =3D read LEAF[gsp_leaf] is our vector's bit set? + write LEAF[gsp_leaf] =3D GSP_BIT clear only our bit + rearm PCI interrupt delivery see "Rearming PCI interrupt + delivery" + +Two rules for the full walk: + +* Clear every pending leaf bit, including bits nova-core does not handle. = An + uncleared bit holds its subtree in the pending state, and restoring TOP_= EN + over it produces a delivery edge straight away. The walk writes back eve= ry bit + it read. +* Restore TOP_EN only after clearing every pending leaf. Otherwise a still= -set + bit raises the interrupt again while the walk is still running. + +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 pa= ths +must rearm PCI delivery for the interrupt they serviced. + +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. Its handler leaves the subtree enabled and +clears only the GSP leaf bit. + +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 + +Only the lower eight leaves exist before Hopper, so TOP bits 4 through 31 = read +zero there. Hopper and later have 16 leaves, though sources do not populat= e all +of them. + +The implemented subtrees bound which TOP bits mean anything. That set is w= ider +than the set nova-core enables, which is the subtrees it services, per the +serviced-subtree invariant. The startup drain still reads every implemented +leaf, because a vector that latched while disabled is invisible in TOP and= can +be in any leaf. + +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 IRQ status, clearing SWGEN0 if it was set + for every other cause that status reports: report it, then remove = it + from the falcon's enabled set and clear it + 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 before reporting the failure, which leaves the que= ue +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 the +latch set and leaves 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 + clear the SWGEN0 latch so the next assertion makes an edge + rearm PCI interrupt delivery the walk does not do it under + pre-Hopper MSI + register the threaded IRQ handler nothing can reach it yet + 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 leaf enable that boot left set would reach 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. The walk erases ever= y leaf +bit, so a message posted between an earlier clear and the walk would leave= the +latch set with nothing in the tree to show for it, and 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 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 and its RPC sequence number, into one of three +classes: + +* Function code and sequence both match the awaited reply. The message is + decoded and returned to the caller that sent the command. +* The function code matches but the sequence does not. This is a reply to a + command that already timed out, so it is logged at warning level and dro= pped + rather than satisfying a later command that reused the same function cod= e. +* 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 are not logged again, because the = RPC + receive trace already records their arrival. + +The read pointer advances past the message in all three cases, and also wh= en 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, which the IRQ thread reports before +disabling the GSP vector. + +The classifier is a fixed set of function codes rather than a handler regi= stry. +The events that need action are handled directly in it. + +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 +dispatches any event it reads first and keeps waiting, under a single dead= line +for the whole wait rather than a fresh timeout after each message. + +One lock means 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. + +Type-state tree API +------------------- + +Servicing a leaf has a required order: read its pending bits, then clear t= hem. +The code encodes the two stages as distinct types (``Idle`` and ``Pending`= `) so +that clearing a leaf before reading it does not compile. ``Top`` carries n= o type +state, because enabling and disabling a subtree can happen in any order. + +The types order the calls on a single handle. They are not a lock and they= do +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 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. The= top +half clears the GIN leaf, takes every cause the falcon reports, rearms del= ivery, +and wakes the IRQ thread if SWGEN0 was among them. The thread takes the lo= ck and +drains the queue. The self-test does no sleeping work and uses a non-threa= ded +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. A single delivery serviced = by a +full tree walk cannot detect that, because the walk's own TOP_EN restore +produces an edge by itself. + +The test passes only if both deliveries arrive, each one finds the doorbel= l bit +and nothing else pending in the leaf, and the leaf is clear once the sourc= e 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 te= st +runs before GSP boot on a leaf the drain has just cleared, so no other vec= tor in +that leaf 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. +A doorbell vector moved to a subtree nova-core does not service fails that +lookup, and with it the self-test and probe, rather than being misrouted +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 register definitions in ``regs.rs``, the interrupt= HAL + and tree API in the ``irq`` module, and the GSP command queue in the ``g= sp`` + module. 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