From nobody Thu Sep 24 13:39:05 2026 Received: from mail-pz2-f43.google.com (mail-pz2-f43.google.com [74.125.228.43]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 7D61B3D7D77 for ; Wed, 23 Sep 2026 04:56:18 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=74.125.228.43 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1790139393; cv=none; b=Mf0sOzqa771Pqu+2yxgbtNTqr/6mXl6FBxSqdeprG5r3qe3VJusej11+VGXrwMdyM2So3dB5kGGaT7EJrHa2AIqUZOPFwFwm2Q32oqpxqb0O5PcZrPnd+IFBOuWkgaeyBSM+8wurB64a66H6vfmW/haaFRtNSXepxiMcgkvZi7Y= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1790139393; c=relaxed/simple; bh=V86MNPLWnsX5Ccyw79DrEJWhumxSriG1Mfudp02+rr4=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=htpmDrGvmmRdpxqKrLwT3+8X9BwiKVhucmZddyzHGH5hLkiz0JAnELwv1MRqorlnsWPBvgUuq0qLyrwBj25Ct9afwCLDi3XQrcl0RIrWE4SPGY/8Xu9m54lE2eVTGVueAAMbQqrwQ4hSIs97qt9qvMJklZC3cqtmjH0wxu6Xv9I= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com; spf=pass smtp.mailfrom=gmail.com; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b=PsJaBu1c; arc=none smtp.client-ip=74.125.228.43 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=gmail.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="PsJaBu1c" Received: by mail-pz2-f43.google.com with SMTP id d2e1a72fcca58-8674704dab1so579950b3a.2 for ; Tue, 22 Sep 2026 21:56:16 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1790139373; x=1790744173; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to:content-type; bh=/sjzjwfKOPK+68pn0ND2VFCH5pb05Tmcgf4f+gG+DjE=; b=PsJaBu1cnccvgbxgC1tjOV4G11ajr5oyWDYyZ4TK6jFbWA8qVQyOsK/EGi3nl5hgo3 H3WDPzy/mhaf4xrw8vBk4v0bJj82eK8LNKwV3L2EkHsv3PFhzeo8sIDytf51rARxj6So enS68IbVSDNGiOo1fYrFM2NkKlVVrkcBRkrjrpBBrF5oKICJUo8V2oaLnwmdY11mR0sd 55x4bpZlVFigjF+lGGmpaoDN4aR+JPJPPVSTn7are9muryXHm6V2+zm1uqmEHuvmkMBB hfIwICaTI6jS51ocbhy5ZvXziFb0r3jhGc00QhWIQQsgqULTrNxz9ykavhHMGSu3yFXN b8Cw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20260707; t=1790139373; x=1790744173; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to:content-type; bh=/sjzjwfKOPK+68pn0ND2VFCH5pb05Tmcgf4f+gG+DjE=; b=QHf7MR+1H0Zae5C3oB7D2FYw9bt20DExhB+qcmztnT1Qs4rJX/YQuv5/j2RG5EEnjJ Ivx0Vr01kLfXtzjXnh9v4MA2YiW184o39w/vTjHF9nIPv0hZ5iOuwoT1PnDAbc0oaaOq 8TSCXUg0LnimBZN/vyoGlvIQb6mttUQJKcJbb4bnNBa5WUAZNhvurMcxbWqVl7fTuGo7 SGvvRwhIhkpUYGzThtVBvP+vibXWCL0YnZAMTLHvXP/Do6/LuQ1YWiMiWgpVW4hRUZKN KIgFGboJ/g8x/PMaCYjD7TNubz9aw010ZfW4d6bC+SkoMr81Yk1KoC/LdxfZ1H3bHUh3 4TUw== X-Forwarded-Encrypted: i=1; AKwUvBzdn2j/wk0bdvAGB9/NKUFM7LRcjLxcF7flkfhaJABH0AeAV01pgmz+db+SxRVnJXfUvwhOkmm/s/yF79Y=@vger.kernel.org X-Gm-Message-State: AFuF++nNHuWHrxXtGQbAzHeLUkzqZzSPRzSCnXdYc2wCcPndQhCDX/9p AM7SpfAMqCQypgqt72ULDZWoHSi64evWelVAUUbYe59kRQVATjAY0YVH X-Gm-Gg: AYBFou3u6oay7lWcL1+zbjwhlE693gAaEf5Oph4dnYZbTic42qIwn78z+LyFZtdHcAI 0f7SzZ2tBWW5TAVhVbWuF09rFAQAHN4KH7bCvrYwJaiCv+udkxjYWketXCvwnaCIJ7r5FYvjL3n XFRDUoayhVDvcHGGQavDmjCfpAYjAStAP5tjArmKOGAxzeVJBj5rgZcnsVkWWrZkZlDgqQ/0bqw tD4qDxKqozxRkFe0ajxk7LwTQcDkpSZHwGHhA5EUXlIEfUtRD7zId6/fqsupUMBTJctPdNr+TOu Q1E2etV9GSj+CitV6oLxL4Jcj0OpFik7BPNblRkvmaQyefUjC9EKrIbL40XB0E3SSfXVCKq+IrM bcI3nGQwyb6l2Qk9BqA0JNj5VZWHxWeSr6sr2k4dLDbk+BiBUh6dUq77ICMHwfgOFhlP5kMGHf9 QfuP/vxPRkRDjpVJNjUk4YXdFd4GhJpxXn5UKWNKgbwzM+g4ZHc3XKfQjtG4OEp4x+r542mX1r7 vfw84qmNZdDMDw= X-Received: by 2002:a05:6a00:1586:b0:87d:3894:1986 with SMTP id d2e1a72fcca58-87d389421e7mr1072428b3a.31.1790139371407; Tue, 22 Sep 2026 21:56:11 -0700 (PDT) Received: from localhost ([95.190.82.222]) by smtp.gmail.com with ESMTPSA id d2e1a72fcca58-87d1cec2d34sm664129b3a.14.2026.09.22.21.56.04 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 22 Sep 2026 21:56:10 -0700 (PDT) From: Vladislav Zaharov To: dakr@kernel.org, jhubbard@nvidia.com Cc: acourbot@nvidia.com, aliceryhl@google.com, ttabi@nvidia.com, gary@garyguo.net, nova-gpu@lists.linux.dev, dri-devel@lists.freedesktop.org, linux-kernel@vger.kernel.org, linux-doc@vger.kernel.org, Vladislav Zaharov Subject: [PATCH v5 1/3] gpu: nova-core: move the debugfs root into the module data Date: Wed, 23 Sep 2026 11:55:49 +0700 Message-ID: <20260923045551.229259-2-vladazaharova2018@gmail.com> X-Mailer: git-send-email 2.55.0 In-Reply-To: <20260923045551.229259-1-vladazaharova2018@gmail.com> References: <20260923045551.229259-1-vladazaharova2018@gmail.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" The debugfs root lives in a static that init() fills in and a guard field of the module data clears again. That costs a `static mut`, an unsafe write on each side and a guard type whose only job is to undo the write. It also leaks. try_pin_init! drops only the fields it has already built, and the guard is written after the Registration, so a registration that fails leaves the guard unbuilt and the static set. Statics are never dropped, and the module is unloaded right away, so the directory outlives everything that could remove it. The next load then finds the name taken: debugfs_create_dir() returns -EEXIST, which Entry keeps as it would any other pointer, and the driver comes up with no debugfs at all until the machine is rebooted. Have the module data own a DebugfsData instead, built before the registration and dropped after it, and keep only a pointer to it in the static, for devices that have no other way to reach the data of their module. What is left is one unsafe read for the users and a single write when the data is built, with no guard type. A registration that fails now drops the data that was built before it, and the directory goes with it. Assisted-by: LLM Signed-off-by: Vladislav Zaharov --- drivers/gpu/nova-core/gsp.rs | 10 +--- drivers/gpu/nova-core/nova_core.rs | 73 ++++++++++++++++++++++-------- 2 files changed, 55 insertions(+), 28 deletions(-) diff --git a/drivers/gpu/nova-core/gsp.rs b/drivers/gpu/nova-core/gsp.rs index dda58095f40b..01ed4adffe93 100644 --- a/drivers/gpu/nova-core/gsp.rs +++ b/drivers/gpu/nova-core/gsp.rs @@ -199,15 +199,7 @@ pub(crate) fn new( logrm, }; =20 - #[allow(static_mut_refs)] - // SAFETY: `DEBUGFS_ROOT` is created before driver reg= istration and cleared - // after driver unregistration, so no probe() can race= with its modification. - // - // PANIC: `DEBUGFS_ROOT` cannot be `None` here. It is= set before driver - // registration and cleared after driver unregistratio= n, so it is always - // `Some` for the entire lifetime that probe() can be = called. - let log_parent: &debugfs::Dir =3D unsafe { crate::DEBU= GFS_ROOT.as_ref() } - .expect("DEBUGFS_ROOT not initialized"); + let log_parent: &debugfs::Dir =3D crate::debugfs_data(= dev).root(); =20 log_parent.scope(log_buffers, dev.name(), |logs, dir| { dir.read_binary_file(c"loginit", &logs.loginit.0); diff --git a/drivers/gpu/nova-core/nova_core.rs b/drivers/gpu/nova-core/nov= a_core.rs index 1133c6ce5c55..08509f64770e 100644 --- a/drivers/gpu/nova-core/nova_core.rs +++ b/drivers/gpu/nova-core/nova_core.rs @@ -4,6 +4,7 @@ =20 use kernel::{ debugfs, + device, driver::Registration, pci, prelude::*, @@ -30,40 +31,74 @@ =20 pub(crate) const MODULE_NAME: &core::ffi::CStr =3D ::NAME; =20 -// TODO: Move this into per-module data once that exists. -static mut DEBUGFS_ROOT: Option =3D None; +/// Pointer to the [`DebugfsData`] the module owns. +/// +/// A device has no way to reach the data of its module, so code running o= n behalf of a bound +/// device goes through here instead. +/// Written once, while the module data is built, and never again: what it= points at is dropped +/// only after the driver is unregistered, so it is good for as long as an= y device is bound, and +/// is not read outside of that. +// TODO: Drop this once devices can reach the data of their module. +static mut DEBUGFS_DATA: *const DebugfsData =3D core::ptr::null(); =20 -/// Guard that clears `DEBUGFS_ROOT` when dropped. -struct DebugfsRootGuard; +/// Data the module shares with every GPU it drives. +/// +/// Reached from a device through [`debugfs_data()`]. +#[pin_data] +pub(crate) struct DebugfsData { + /// Root directory of the driver in debugfs. + root: debugfs::Dir, +} + +impl DebugfsData { + /// Creates the shared data. + fn new() -> impl PinInit { + pin_init!(Self { + root: debugfs::Dir::new(c"nova-core"), + }) + } =20 -impl Drop for DebugfsRootGuard { - fn drop(&mut self) { - // SAFETY: This guard is dropped after `_driver` (due to field ord= er), - // so the driver is unregistered and no probe() can be running. - unsafe { DEBUGFS_ROOT =3D None }; + /// Returns the root directory of the driver in debugfs. + pub(crate) fn root(&self) -> &debugfs::Dir { + &self.root } } =20 +/// Returns the data the module shares with its devices. +/// +/// The bound device is what makes this sound: the data is built before th= e driver is registered +/// and dropped after it is unregistered, so it outlives every device that= is bound, and the +/// returned reference cannot be held past the one it is taken for. +pub(crate) fn debugfs_data<'a>(_dev: &'a device::Device) ->= &'a DebugfsData { + // SAFETY: A device can only be bound once the driver is registered, w= hich happens after + // `DEBUGFS_DATA` is written, so it points at the data of this module,= which lives at least + // as long as the caller's device is bound. + unsafe { &*DEBUGFS_DATA } +} + #[pin_data] struct NovaCoreModule { - // Fields are dropped in declaration order, so `_driver` is dropped fi= rst, - // then `_debugfs_guard` clears `DEBUGFS_ROOT`. + // Fields are dropped in declaration order, so the registration goes f= irst and no probe() can + // still be running once the shared data is torn down. `init()` builds= them the other way + // round, as the data has to be there before the first probe() reaches= for it. #[pin] _driver: Registration>, - _debugfs_guard: DebugfsRootGuard, + #[pin] + _debugfs: DebugfsData, } =20 impl InPlaceModule for NovaCoreModule { fn init(module: &'static kernel::ThisModule) -> impl PinInit { - let dir =3D debugfs::Dir::new(c"nova-core"); - - // SAFETY: We are the only driver code running during init, so the= re - // cannot be any concurrent access to `DEBUGFS_ROOT`. - unsafe { DEBUGFS_ROOT =3D Some(dir) }; - try_pin_init!(Self { + _debugfs <- DebugfsData::new(), + _: { + // SAFETY: Nothing reads `DEBUGFS_DATA` before a device is= bound, which cannot + // happen until the driver is registered below. What it po= ints at is dropped only + // once the driver is unregistered, so it is valid for as = long as any device is + // bound, and nothing reads it outside of that. + unsafe { DEBUGFS_DATA =3D &*_debugfs }; + }, _driver <- Registration::new(MODULE_NAME, module), - _debugfs_guard: DebugfsRootGuard, }) } } --=20 2.55.0 From nobody Thu Sep 24 13:39:05 2026 Received: from mail-pz2-f43.google.com (mail-pz2-f43.google.com [74.125.228.43]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id F41C43E63AE for ; Wed, 23 Sep 2026 04:56:21 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=74.125.228.43 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1790139398; cv=none; b=RM7sdymndf2Pt1mmlICSbVVkeYiGbhr/xO1BNiYzeKMh5Q2C0TXxvnX3b9LVSfXn79EtVLNxzRnKm/su1Q55Bgb+l2QHSFh7uZ088yldb+xHk8vV/yMaI7rfsufMBSG2Y2YZZ601mRHI65IMOdWgTqs/yKjpS3nOfMKpeF8S9qQ= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1790139398; c=relaxed/simple; bh=YjdBU19SgV1Y9vfg0l5EHp63mWHtXanPinn5rOw6LQU=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=YJiowIsdj8vcmlH1VjtF3kcvXUFBqJmgAUCTvtuJiuKHV+uqSdLZszsJm0heSCdbB7cq/Pvfdy4ofDK6GkMNijUhFWqSGERrpipar6c17iWgELA/KkvAoqsb4q/vGs7tcVCNDWP65T67bSYjnYKtScYTbVYLF8tC43/kbhEHSu0= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com; spf=pass smtp.mailfrom=gmail.com; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b=ne+PCsh0; arc=none smtp.client-ip=74.125.228.43 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=gmail.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="ne+PCsh0" Received: by mail-pz2-f43.google.com with SMTP id d2e1a72fcca58-85469f204f6so319403b3a.2 for ; Tue, 22 Sep 2026 21:56:21 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1790139380; x=1790744180; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to:content-type; bh=mwJzYusT65HvhnYbkq7feitpnxm95NlY/pIrZm1wqZA=; b=ne+PCsh04H4gIu1hkq1CFVW5TR8nXavw8mVGqkpnpNHd7I/27R0cczFPvph4l3tDT5 Yp01edI4sLbio+wJaSGO49iL72jFmvCKgpqrlvN8MwIvCmHa9kP7huDH+Q6vwFvOeBVA dhDc7/sAeNvg9thK6F9A2o1zSWEE0cinUXBPLH5lEIIJX31WOrjRe1orclNDHEQElkAC tw9CHLxrMXVs/H05J8Yfp/2EQ8/yXwmJwmLYbtduuqWPi/LBSk4v1QLYxU8hEgEymn0Y gSvyVPK2QUYPUz0m3L9gGmd+Y5qP7sOmRJ/WyEq0mJESQC5VZ8nVhILLAyEvyPHeUg1L 26dw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20260707; t=1790139380; x=1790744180; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to:content-type; bh=mwJzYusT65HvhnYbkq7feitpnxm95NlY/pIrZm1wqZA=; b=uw2bPAruX6N19ecv2+fuWYwEpsweXeoT4CjkXg+E83cPxmw2kE0p46+CTg8pWU61NV 0bJwTbT6OKsooeifuHXEf/346C0gJQPlde2E1n3y+jXzADnqhzFetxaerXHhL4m0eEEr TlPLBwu8bQ4ZMx8IJuCorD+lcrtHnRc9fWEzsMXiiWtyX5AW1evRUV8L6MPACnlWu3Hg oaiGglTEPm1lHhx3Gw7dk4ZKayrsXweL47yTkXZSRIPtJPbofErU4rGA+4UXhmojpG/J 2Nfo+Qaq5PcZB8KkKb9BcEw/cL6tAtm0DbY3mr4oupLVVzCsrrzvdj+Q8i/KdsdftAbx 3eog== X-Forwarded-Encrypted: i=1; AKwUvBw1IkkdAFe/J4gWysRC876ruA39YJ02QH4HaeXJ1PhfaNo/KA72pnx2i9J7Xwo7VA/Z8q2+S1EP1FOz2MY=@vger.kernel.org X-Gm-Message-State: AFuF++nibvjpNRJq9AdpxL0cftWC3KcPg6SVuuqC094yFPt2kiwxVlhR heT2/4a33vDmHt7+vrH0i2hGHhfQurmu0uul7qmwiUdYb5mauejdbNHfEwQxBZAgK/yYIA== X-Gm-Gg: AYBFou37vhG06rKyMdIR0xpx5qRmreIpILD2yUKITSEqDyrO+kb/D44riRwbBnSD5Xw N4nReyy4dgtEJ4clHmpmsen+cchZ8hEAo/y8Ycgk1QxyEliyQSJstUpXvqh2jhv86Q1AtLU29IN 83Je5nC6a1ya0SWadyEQbMrFWFONcEI2aKgoOruLCYHBXa89T0/FG5TEtSj+UoU+NM1qWyyI1uq 8inoDXV2em5N8HdCxwymNH2v57M4q9eRPyxFF5DGbK6zXmHRXUFcLmKTj3ZzgpuUkT6TWw8Z1pr xS0dAdzBbjWgUcDZ/gzY3HugJ0Ux8kLNZGd9wPdhjvE17cDfTdxR/q8LcQ2A/PRB2xekwjBryeP s0iPvSJP8Y5sp4uhseMyQAjC/8gZGfAMuq8KhX/Cp85q9aYTA+xntU+QoyqqF/KBE1eHRdMvJ+c CU1euedE1I7hXk8YVRwslYcVqFB3vZu38uonl77YHOgkAGWl4sKtx8LdlChLwQ+biokAA5JgGdZ UW/xQ== X-Received: by 2002:a05:6a00:928c:b0:87b:3bcc:bce2 with SMTP id d2e1a72fcca58-87d1c9b8d83mr1483524b3a.33.1790139378874; Tue, 22 Sep 2026 21:56:18 -0700 (PDT) Received: from localhost ([95.190.82.222]) by smtp.gmail.com with ESMTPSA id d2e1a72fcca58-87d1cec2d34sm664129b3a.14.2026.09.22.21.56.11 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 22 Sep 2026 21:56:18 -0700 (PDT) From: Vladislav Zaharov To: dakr@kernel.org, jhubbard@nvidia.com Cc: acourbot@nvidia.com, aliceryhl@google.com, ttabi@nvidia.com, gary@garyguo.net, nova-gpu@lists.linux.dev, dri-devel@lists.freedesktop.org, linux-kernel@vger.kernel.org, linux-doc@vger.kernel.org, Vladislav Zaharov Subject: [PATCH v5 2/3] gpu: nova-core: gsp: retain the GSP-RM log buffers after unbind Date: Wed, 23 Sep 2026 11:55:50 +0700 Message-ID: <20260923045551.229259-3-vladazaharova2018@gmail.com> X-Mailer: git-send-email 2.55.0 In-Reply-To: <20260923045551.229259-1-vladazaharova2018@gmail.com> References: <20260923045551.229259-1-vladazaharova2018@gmail.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" The GSP-RM log buffers are exposed through debugfs, but the Scope that owns them lives in Gsp, inside GspResources, inside the Gpu built by probe(). They are DMA allocations of the device and cannot outlive it, so the entries go away as soon as the GPU is unbound - and, more to the point, as soon as probe() fails, which is exactly when the log of a GSP that did not come up is the thing one wants to read. Add a gsp_keep_logs module parameter. When it is set, dropping the log buffers copies whatever the GSP wrote into memory owned by the module and exposes the copies until the module is unloaded. A buffer whose "put" pointer is still zero was never written to and is skipped. The GSP has normally been stopped by the time the buffers are dropped, but a boot that timed out can leave it still appending, so a DMA read barrier orders the read of the "put" pointer before the copy. The copies belong to the module data next to the debugfs root, and live in a "retained" directory created during module init rather than on first use, which keeps the teardown path of a device from having to create anything. Keeping them out of the directory used by bound GPUs also means a device coming back does not find its debugfs name taken by its own history; nouveau, which recreates the entries under the name of the GPU that just went away, has that problem. While at it, move the log buffer code out of gsp.rs into gsp/logbuffer.rs. Assisted-by: LLM Signed-off-by: Vladislav Zaharov --- drivers/gpu/nova-core/gsp.rs | 92 ++------- drivers/gpu/nova-core/gsp/logbuffer.rs | 247 +++++++++++++++++++++++++ drivers/gpu/nova-core/nova_core.rs | 29 ++- 3 files changed, 294 insertions(+), 74 deletions(-) create mode 100644 drivers/gpu/nova-core/gsp/logbuffer.rs diff --git a/drivers/gpu/nova-core/gsp.rs b/drivers/gpu/nova-core/gsp.rs index 01ed4adffe93..72752c6bd6c0 100644 --- a/drivers/gpu/nova-core/gsp.rs +++ b/drivers/gpu/nova-core/gsp.rs @@ -12,11 +12,7 @@ CoherentView, DmaAddress, // }, - io::{ - io_project, - io_write, - Io, // - }, + io::io_write, pci, prelude::*, // }; @@ -24,9 +20,13 @@ pub(crate) mod cmdq; pub(crate) mod commands; mod fw; +mod logbuffer; mod regs; mod sequencer; =20 +use logbuffer::LogBuffers; +pub(crate) use logbuffer::RetainedLogs; + pub(crate) use fw::{ GspFmcBootParams, GspFwWprMeta, @@ -77,10 +77,6 @@ pub(crate) fn dev(&self) -> &'gpu device::Device { } } =20 -/// Number of GSP pages to use in a RM log buffer. -const RM_LOG_BUFFER_NUM_PAGES: usize =3D 0x10; -const LOG_BUFFER_SIZE: usize =3D RM_LOG_BUFFER_NUM_PAGES * GSP_PAGE_SIZE; - /// Array of page table entries, as understood by the GSP bootloader. #[repr(C)] #[derive(FromBytes, IntoBytes)] @@ -101,49 +97,6 @@ fn init(view: CoherentView<'_, Self>, start: DmaAddress= ) -> Result<()> { } } =20 -/// The logging buffers are byte queues that contain encoded printf-like -/// messages from GSP-RM. They need to be decoded by a special application -/// that can parse the buffers. -/// -/// The 'loginit' buffer contains logs from early GSP-RM init and -/// exception dumps. The 'logrm' buffer contains the subsequent logs. Bot= h are -/// written to directly by GSP-RM and can be any multiple of GSP_PAGE_SIZE. -/// -/// The physical address map for the log buffer is stored in the buffer -/// itself, starting with offset 1. Offset 0 contains the "put" pointer (p= p). -/// Initially, pp is equal to 0. If the buffer has valid logging data in i= t, -/// then pp points to index into the buffer where the next logging entry w= ill -/// be written. Therefore, the logging data is valid if: -/// 1 <=3D pp < sizeof(buffer)/sizeof(u64) -struct LogBuffer<'a>(Coherent<'a, [u8; LOG_BUFFER_SIZE]>); - -impl<'a> LogBuffer<'a> { - /// Creates a new `LogBuffer` mapped on `dev`. - fn new(dev: &'a device::Device) -> Result { - let obj =3D Self(Coherent::zeroed(dev, GFP_KERNEL)?); - - let start_addr =3D obj.0.dma_address(); - - let pte_view =3D io_project!( - obj.0, - [build: size_of::()..][build: ..RM_LOG_BUFFER_NUM_PAGES *= size_of::()] - ) - .try_cast::>()?; - PteArray::init(pte_view, start_addr)?; - - Ok(obj) - } -} - -struct LogBuffers<'a> { - /// Init log buffer. - loginit: LogBuffer<'a>, - /// Interrupts log buffer. - logintr: LogBuffer<'a>, - /// RM log buffer. - logrm: LogBuffer<'a>, -} - /// GSP runtime data. #[pin_data] pub(crate) struct Gsp<'gsp> { @@ -168,9 +121,7 @@ pub(crate) fn new( pin_init::pin_init_scope(move || { let dev =3D pdev.as_ref(); =20 - let loginit =3D LogBuffer::new(dev)?; - let logintr =3D LogBuffer::new(dev)?; - let logrm =3D LogBuffer::new(dev)?; + let log_buffers =3D LogBuffers::new(dev)?; =20 // Initialise the logging structures. The OpenRM equivalents a= re in: // _kgspInitLibosLoggingStructures (allocates memory for buffe= rs) @@ -185,28 +136,23 @@ pub(crate) fn new( GFP_KERNEL, )?; =20 - libos.init_at(0, LibosMemoryRegionInitArgument::new("L= OGINIT", &loginit.0))?; - libos.init_at(1, LibosMemoryRegionInitArgument::new("L= OGINTR", &logintr.0))?; - libos.init_at(2, LibosMemoryRegionInitArgument::new("L= OGRM", &logrm.0))?; + libos.init_at( + 0, + LibosMemoryRegionInitArgument::new("LOGINIT", &log= _buffers.loginit.0), + )?; + libos.init_at( + 1, + LibosMemoryRegionInitArgument::new("LOGINTR", &log= _buffers.logintr.0), + )?; + libos.init_at( + 2, + LibosMemoryRegionInitArgument::new("LOGRM", &log_b= uffers.logrm.0), + )?; libos.init_at(3, LibosMemoryRegionInitArgument::new("R= MARGS", rmargs))?; =20 libos.into() }, - logs <- { - let log_buffers =3D LogBuffers { - loginit, - logintr, - logrm, - }; - - let log_parent: &debugfs::Dir =3D crate::debugfs_data(= dev).root(); - - log_parent.scope(log_buffers, dev.name(), |logs, dir| { - dir.read_binary_file(c"loginit", &logs.loginit.0); - dir.read_binary_file(c"logintr", &logs.logintr.0); - dir.read_binary_file(c"logrm", &logs.logrm.0); - }) - }, + logs <- log_buffers.scope(), })) }) } diff --git a/drivers/gpu/nova-core/gsp/logbuffer.rs b/drivers/gpu/nova-core= /gsp/logbuffer.rs new file mode 100644 index 000000000000..b1f912fb3fae --- /dev/null +++ b/drivers/gpu/nova-core/gsp/logbuffer.rs @@ -0,0 +1,247 @@ +// SPDX-License-Identifier: GPL-2.0 + +//! GSP-RM log buffers, and the debugfs entries exposing them. + +use core::convert::Infallible; + +use kernel::{ + debugfs, + device, + dma::Coherent, + io::{ + io_project, + Io, // + }, + prelude::*, + str::CString, + sync::barrier::{ + dma_mb, + Read, // + }, // +}; + +use crate::gsp::{ + PteArray, + GSP_PAGE_SIZE, // +}; + +/// Number of GSP pages to use in a RM log buffer. +const RM_LOG_BUFFER_NUM_PAGES: usize =3D 0x10; +const LOG_BUFFER_SIZE: usize =3D RM_LOG_BUFFER_NUM_PAGES * GSP_PAGE_SIZE; + +/// The logging buffers are byte queues that contain encoded printf-like +/// messages from GSP-RM. They need to be decoded by a special application +/// that can parse the buffers. +/// +/// The 'loginit' buffer contains logs from early GSP-RM init and +/// exception dumps. The 'logrm' buffer contains the subsequent logs. Bot= h are +/// written to directly by GSP-RM and can be any multiple of GSP_PAGE_SIZE. +/// +/// The physical address map for the log buffer is stored in the buffer +/// itself, starting with offset 1. Offset 0 contains the "put" pointer (p= p). +/// Initially, pp is equal to 0. If the buffer has valid logging data in i= t, +/// then pp points to index into the buffer where the next logging entry w= ill +/// be written. Therefore, the logging data is valid if: +/// 1 <=3D pp < sizeof(buffer)/sizeof(u64) +pub(super) struct LogBuffer<'a>(pub(super) Coherent<'a, [u8; LOG_BUFFER_SI= ZE]>); + +impl<'a> LogBuffer<'a> { + /// Creates a new `LogBuffer` mapped on `dev`. + fn new(dev: &'a device::Device) -> Result { + let obj =3D Self(Coherent::zeroed(dev, GFP_KERNEL)?); + + let start_addr =3D obj.0.dma_address(); + + let pte_view =3D io_project!( + obj.0, + [build: size_of::()..][build: ..RM_LOG_BUFFER_NUM_PAGES *= size_of::()] + ) + .try_cast::>()?; + PteArray::init(pte_view, start_addr)?; + + Ok(obj) + } + + /// Copies the contents of this buffer into memory that does not belon= g to the device. + /// + /// A buffer the GSP never wrote to yields an empty vector, as it hold= s nothing worth keeping. + fn snapshot(&self) -> Result> { + // Offset 0 holds the "put" pointer, which the GSP advances as it = appends entries. It is + // still zero if nothing was ever logged, which is all that is tes= ted here: a buffer that + // was written to is copied whole, and making sense of "put" is le= ft to the decoder. + let put =3D io_project!(self.0, [build: ..size_of::()]).try_c= ast::()?; + if put.read_val() =3D=3D 0 { + return Ok(VVec::new()); + } + + // ORDERING: LOAD->LOAD ordering needed to order the "put" read be= fore the data read. The + // GSP has normally been stopped by the time this runs, but a boot= that timed out can leave + // it still appending. + dma_mb(Read); + + let mut snapshot =3D VVec::zeroed(LOG_BUFFER_SIZE, GFP_KERNEL)?; + io_project!(self.0, [build: ..]).copy_to_slice(&mut snapshot); + + Ok(snapshot) + } +} + +/// The log buffers of a GPU, for as long as it is bound to the driver. +pub(super) struct LogBuffers<'a> { + /// Device the buffers belong to. Also names their debugfs directory. + dev: &'a device::Device, + /// Init log buffer. + pub(super) loginit: LogBuffer<'a>, + /// Interrupts log buffer. + pub(super) logintr: LogBuffer<'a>, + /// RM log buffer. + pub(super) logrm: LogBuffer<'a>, +} + +impl<'a> LogBuffers<'a> { + /// Allocates the three log buffers of `dev`. + pub(super) fn new(dev: &'a device::Device) -> Result { + Ok(Self { + dev, + loginit: LogBuffer::new(dev)?, + logintr: LogBuffer::new(dev)?, + logrm: LogBuffer::new(dev)?, + }) + } + + /// Creates an initializer exposing these buffers under a directory na= med after their device. + pub(super) fn scope(self) -> impl PinInit, Infall= ible> + 'a { + let dev =3D self.dev; + + let log_parent: &debugfs::Dir =3D crate::debugfs_data(dev).root(); + + log_parent.scope(self, dev.name(), |logs, dir| { + dir.read_binary_file(c"loginit", &logs.loginit.0); + dir.read_binary_file(c"logintr", &logs.logintr.0); + dir.read_binary_file(c"logrm", &logs.logrm.0); + }) + } + + /// Preserves whatever the GSP logged, so it can still be read once th= e GPU is gone. + /// + /// The buffers are DMA allocations of the device and cannot outlive i= t, so their contents are + /// copied into memory owned by the module and exposed through fresh d= ebugfs entries. Those + /// live until the module is unloaded. + /// + /// Does nothing if `gsp_keep_logs` was not set when the module was lo= aded, as there is then + /// no directory to put the copies in. + fn retain(&self) -> Result { + let data =3D crate::debugfs_data(self.dev); + + // The directory is taken here and the lock dropped again right aw= ay: what follows + // allocates 64 KiB three times, and no other device should have t= o wait for that. + let Some(dir) =3D data.retained_logs().lock().dir.clone() else { + return Ok(()); + }; + + let logs =3D RetainedLogBuffers { + name: CString::try_from_fmt(fmt!("{}", self.dev.name()))?, + loginit: self.loginit.snapshot()?, + logintr: self.logintr.snapshot()?, + logrm: self.logrm.snapshot()?, + }; + + // Nothing was ever logged, so there is nothing to keep. A copy fr= om an earlier run of + // this device is deliberately left alone: logs from a run that fa= iled are worth more + // than the silence of one that did not. A run that did log someth= ing does replace it, + // even where what it replaces came from a run that failed: nothin= g here can tell the two + // apart, and keeping the older copy would mean never seeing anyth= ing newer. + if logs.loginit.is_empty() && logs.logintr.is_empty() && logs.logr= m.is_empty() { + return Ok(()); + } + + // Make every allocation of our own that can fail before the previ= ous copy of this device + // is dropped, so that none of them failing can leave it with no l= ogs at all. + let scope =3D KBox::>::new_unin= it(GFP_KERNEL)?; + + let mut retained =3D data.retained_logs().lock(); + + retained.gpus.reserve(1, GFP_KERNEL)?; + + // An earlier run of the same device may have left a copy behind, = and its directory + // carries the name about to be used again, so it has to go first.= Nothing below can + // fail, so the replacement is guaranteed to take its place. + retained.gpus.retain(|gpu| *gpu.name !=3D *logs.name); + + let scope =3D scope.write_pin_init(dir.scope(logs, self.dev.name()= , |logs, dir| { + if !logs.loginit.is_empty() { + dir.read_binary_file(c"loginit", &logs.loginit); + } + if !logs.logintr.is_empty() { + dir.read_binary_file(c"logintr", &logs.logintr); + } + if !logs.logrm.is_empty() { + dir.read_binary_file(c"logrm", &logs.logrm); + } + }))?; + + retained.gpus.push(scope, GFP_KERNEL)?; + + dev_dbg!(self.dev, "GSP-RM log buffers retained\n"); + + Ok(()) + } +} + +impl Drop for LogBuffers<'_> { + fn drop(&mut self) { + if let Err(e) =3D self.retain() { + dev_warn!(self.dev, "failed to retain GSP-RM log buffers: {:?}= \n", e); + } + } +} + +/// Copies of the log buffers of a GPU that is no longer around. +struct RetainedLogBuffers { + /// Name of the device the buffers came from, which also names their d= irectory. + /// + /// A copy rather than a reference to the device, so that a GPU that i= s gone does not stay + /// allocated for as long as its logs are kept. + name: CString, + /// Contents of the init log buffer, empty if it was never written to. + loginit: VVec, + /// Contents of the interrupts log buffer, empty if it was never writt= en to. + logintr: VVec, + /// Contents of the RM log buffer, empty if it was never written to. + logrm: VVec, +} + +/// Log buffers of GPUs that are gone, and the debugfs entries exposing th= em. +/// +/// The copies live under a `retained` directory of their own instead of n= ext to the entries of +/// the GPUs that are actually bound, so that a device coming back does no= t find its name taken. +pub(crate) struct RetainedLogs { + /// One entry per GPU. + /// + /// Declared before `dir`, as the copies live below it. + gpus: KVec>>>, + /// Parent directory of all copies. `None` unless retaining was asked = for. + dir: Option, +} + +impl RetainedLogs { + /// Creates an empty set of retained log buffers, retaining disabled. + pub(crate) const fn new() -> Self { + Self { + gpus: KVec::new(), + dir: None, + } + } + + /// Creates the directory the copies will live in, enabling retaining. + /// + /// Does nothing without `CONFIG_DEBUG_FS`, where a [`debugfs::Dir`] i= s a zero-sized type and + /// the copies could never be read back. + pub(crate) fn enable(&mut self, parent: &debugfs::Dir) { + if !cfg!(CONFIG_DEBUG_FS) { + return; + } + + self.dir =3D Some(parent.subdir(c"retained")); + } +} diff --git a/drivers/gpu/nova-core/nova_core.rs b/drivers/gpu/nova-core/nov= a_core.rs index 08509f64770e..14509d764d0b 100644 --- a/drivers/gpu/nova-core/nova_core.rs +++ b/drivers/gpu/nova-core/nova_core.rs @@ -8,6 +8,7 @@ driver::Registration, pci, prelude::*, + sync::Mutex, InPlaceModule, // }; =20 @@ -46,6 +47,11 @@ /// Reached from a device through [`debugfs_data()`]. #[pin_data] pub(crate) struct DebugfsData { + /// Copies of the log buffers of GPUs that are gone. + /// + /// Declared before `root`, as the copies live below it. + #[pin] + retained_logs: Mutex, /// Root directory of the driver in debugfs. root: debugfs::Dir, } @@ -53,8 +59,18 @@ pub(crate) struct DebugfsData { impl DebugfsData { /// Creates the shared data. fn new() -> impl PinInit { + let root =3D debugfs::Dir::new(c"nova-core"); + + // Deciding here, rather than when the first GPU goes away, keeps = the teardown path of a + // device from having to create anything. + let mut retained_logs =3D gsp::RetainedLogs::new(); + if module_parameters::gsp_keep_logs.value() { + retained_logs.enable(&root); + } + pin_init!(Self { - root: debugfs::Dir::new(c"nova-core"), + retained_logs <- kernel::new_mutex!(retained_logs), + root, }) } =20 @@ -62,6 +78,11 @@ fn new() -> impl PinInit { pub(crate) fn root(&self) -> &debugfs::Dir { &self.root } + + /// Returns the copies of the log buffers of GPUs that are gone. + pub(crate) fn retained_logs(&self) -> &Mutex { + &self.retained_logs + } } =20 /// Returns the data the module shares with its devices. @@ -110,6 +131,12 @@ fn init(module: &'static kernel::ThisModule) -> impl P= inInit { description: "Nova Core GPU driver", license: "GPL v2", firmware: [], + params: { + gsp_keep_logs: bool { + default: false, + description: "Keep the GSP-RM log buffers in debugfs after the= ir GPU is gone", + }, + }, } =20 kernel::module_firmware!(firmware::ModInfoBuilder); --=20 2.55.0 From nobody Thu Sep 24 13:39:05 2026 Received: from mail-pz2-f41.google.com (mail-pz2-f41.google.com [74.125.228.41]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 05A5E3EC81B for ; Wed, 23 Sep 2026 04:56:29 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=74.125.228.41 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1790139397; cv=none; b=XV50yAoVjtwjp/b4eIOEjKtPq4IvwB96zc1+IGjaSRBBbR8T8HR/mrnQxf95DGclaKgtsBqm55uO0mBpPFe8i4puTUZupxFad3A+JWiqKR2NKYcxQFxcfwozOF0zAMk1LO/Gl0gDKjk1prFndik6Kg/2Xhv4zEUC1USYPuYSB6k= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1790139397; c=relaxed/simple; bh=i+9Kd1wcuXXlxSDwbur+MJoqMUdg4kpmkXMrI0+T3eI=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=CZk1JlCLbFaYDd3SpsACt6pfv5xcdHGTG5jWJGXNMxzYriVLxvH7w0zfweA6ewkBHC2avkle/HcroVkqPgo/UBoIXacsv7WwdWlR8dn4+iXm7S4LeeUSzxJW5ORjyCc5XBU2GbxQaAzvkvoienc45G8S+fFsSLxuPOG2VQjOSyE= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com; spf=pass smtp.mailfrom=gmail.com; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b=of9+bqSs; arc=none smtp.client-ip=74.125.228.41 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=gmail.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="of9+bqSs" Received: by mail-pz2-f41.google.com with SMTP id d2e1a72fcca58-85469f204f6so319425b3a.2 for ; Tue, 22 Sep 2026 21:56:29 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1790139386; x=1790744186; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to:content-type; bh=qra++7QT1u/2cZF1D+tg8w8VOq0NYWF4+x38DgQtB7M=; b=of9+bqSssdYNRkk+UXpJY230Th16Gvy5rnrFpH5neKMzQKK2igP5NoowLchLab8HuT JyZXWsVsLAJP8UDXt6rlLRFU1dPcCPSseOskypHh6yizokhDTGn2g9/EG5Vxep/dSsxl xgEUEcJ7QLXyvN9h0kRkMceM+EYSC4QmKrKY8KHPJcKVGYi8A8ZxYj/KOY7Q7bifvLOh +VwatlaB1npSP0bR3Rfk4tJXMAPBI8rPjiGSASLwu0b7U8ndm2U6LyhKY5zh9Ri8TSAe IFWJT25dZAUmFWLIVedXlyKZqVrnyedDTvquL+PXY2BO+xyh5kNX6j492dx+7YhTGkQL nmkg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20260707; t=1790139386; x=1790744186; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to:content-type; bh=qra++7QT1u/2cZF1D+tg8w8VOq0NYWF4+x38DgQtB7M=; b=h0yKF4OkrxR15wl3jXq3Zm7SOsU8H0s2lo+cTjpR2BEoXo4bd7zfFwmRW6laJUrX02 1mo3lQper3+fBGqAeiEHX0PACB3iYKh7XAC9CjWdp2k+71mZNw/MsV6wwhfcR5oO2pD8 IFz3iRDjkt9SX7iwN3qaz9IWJegMDBkUi70Cww6BX8X8osvLQRnXNK01/MFAMquQ6rtp dk/uIvffMKdYoXb23RSCCpig98Qzq0Br5TCI6PqJU3X68qgYAxrlMuoXbAPX1/RSCJ8U mSgsXtJ4LjltyQqxN84FtBgtOcnaJSpUseaJKGcXgpTaWygXQNuZqxfGgxlb9I9Woee2 kYMw== X-Forwarded-Encrypted: i=1; AKwUvBwPq2EVAa4Rq3vU39nIT076KXyvjW9swqO37FWF28Td/RDs8yC0gtlWEb4W4aOyMw1tv6TqphvzEdoJnhc=@vger.kernel.org X-Gm-Message-State: AFuF++mXLOPMBjg89jgm4nwMN1kgX6ovUGQGNcyYEw3QqAfwS339//WF f14Fdd6jniWXzgYhEd895i6eyqfxI7hrbDWsgyq7JGtL3HZXwcWXZk84 X-Gm-Gg: AYBFou2wcy00kZmkA8RK1jJLf+MggNTFSp0v6opWuaRbn+yyoQEo2+GReZeg2VHSqpQ AtJvJbt+ZA53pdAt5LCSb3VrPieRhq5N4YdM8Yh1wlmL97xSMgEBFgx/7ItlaVtFqMaCvg5yBJ1 ETmDp6GHQX3FnBvIBrpoDvBzDj2c6k3PY2QnfR2xusg6oFifrF24ej3Dsf2O630Yic1OG6NhJnH TBctjDUiEHA75Y4J5VjsS/pmFr1eNUNXPDP2EKORAornKb2g4bp//7R+7NkMwt6CvA0PJPdEnHi 246PovxkLmtTuajFfFR/PFWEPb31VEI6XHIX0wlY30KoGBx1uYwhRPEOmz2tp7QuN1ZXlkUjVrK lQ5b1oZFngUByMLSVtfR1liCfWJBaf+jAt1SG0svaE2OXkfX95QGMp6ctWPPBG+wR5QygQwZ0l1 Eu4Hyv2wD6hAIIJ7D4asyV6FWFe+TE9hkpvsuvxNkv33jf9t7JSRMZiHSZizQEUfGrhd0s2fHYy bfj X-Received: by 2002:a05:6a00:2354:b0:87c:d00a:f350 with SMTP id d2e1a72fcca58-87d1d6c1be0mr1485300b3a.48.1790139385958; Tue, 22 Sep 2026 21:56:25 -0700 (PDT) Received: from localhost ([95.190.82.222]) by smtp.gmail.com with ESMTPSA id d2e1a72fcca58-87d1cec2d34sm664129b3a.14.2026.09.22.21.56.19 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 22 Sep 2026 21:56:25 -0700 (PDT) From: Vladislav Zaharov To: dakr@kernel.org, jhubbard@nvidia.com Cc: acourbot@nvidia.com, aliceryhl@google.com, ttabi@nvidia.com, gary@garyguo.net, nova-gpu@lists.linux.dev, dri-devel@lists.freedesktop.org, linux-kernel@vger.kernel.org, linux-doc@vger.kernel.org, Vladislav Zaharov Subject: [PATCH v5 3/3] Documentation: nova: remove completed GSP log buffer task Date: Wed, 23 Sep 2026 11:55:51 +0700 Message-ID: <20260923045551.229259-4-vladazaharova2018@gmail.com> X-Mailer: git-send-email 2.55.0 In-Reply-To: <20260923045551.229259-1-vladazaharova2018@gmail.com> References: <20260923045551.229259-1-vladazaharova2018@gmail.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Exposing the GSP-RM log buffers through debugfs is implemented, and with the gsp_keep_logs module parameter they now also survive a failed probe, which was the part of the task that was still missing. Assisted-by: LLM Signed-off-by: Vladislav Zaharov --- Documentation/gpu/nova/core/todo.rst | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/Documentation/gpu/nova/core/todo.rst b/Documentation/gpu/nova/= core/todo.rst index a01c362b1be0..28fc7329d56b 100644 --- a/Documentation/gpu/nova/core/todo.rst +++ b/Documentation/gpu/nova/core/todo.rst @@ -141,18 +141,6 @@ Implement support for instmem (bar2) used to store pag= e tables. GPU System Processor (GSP) =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D =20 -Export GSP log buffers ----------------------- - -Recent patches from Timur Tabi [1] added support to expose GSP-RM log buff= ers -(even after failure to probe the driver) through debugfs. - -This is also an interesting feature for nova-core, especially in the early= days. - -| Link: https://lore.kernel.org/nouveau/20241030202952.694055-2-ttabi@nvid= ia.com/ [1] -| Reference: Debugfs abstractions -| Complexity: Intermediate - GSP firmware abstraction ------------------------ =20 --=20 2.55.0