* [PATCH 0/2] rust: honor the maximum DMA segment size @ 2026-08-31 23:32 Matteo Kloiber 2026-08-31 23:32 ` [PATCH 1/2] gpu: nova-core: declare unlimited DMA max " Matteo Kloiber 2026-08-31 23:32 ` [PATCH 2/2] rust: scatterlist: honor the device's maximum " Matteo Kloiber 0 siblings, 2 replies; 5+ messages in thread From: Matteo Kloiber @ 2026-08-31 23:32 UTC (permalink / raw) To: dakr, acourbot Cc: aliceryhl, ojeda, airlied, simona, abdiel.janulgue, daniel.almeida, robin.murphy, a.hindborg, nova-gpu, dri-devel, driver-core, rust-for-linux, linux-kernel, Matteo Kloiber Booting nova-core against a real GSP with CONFIG_DMA_API_DEBUG=y warns when the ~60 MiB firmware image is mapped as a scatter-gather table: DMA-API: nova-core 0000:00:03.0: mapping sg segment longer than device claims to support [len=62914560] [max=65536] There are two separate issues behind it. Patch 1 has nova-core declare the segment size it actually supports. It re-decomposes every segment into 4 KiB GSP page-table entries, so it has no upper bound on segment length. Furthermore, I also checked what other GPUs do, and most do the same: set the max segment size u32::MAX. So this should be the correct behavior for nova as well. Patch 2 has SGTable::new() honor dma_get_max_seg_size() in addition to dma_max_mapping_size(). The abstraction is generic, so a driver with a real hardware segment limit would otherwise silently be handed segments it cannot express in a single descriptor. Tested on an RTX 5080 (GB203) passed through to a QEMU guest via VFIO with CONFIG_DMA_API_DEBUG=y: the warning is gone, and GSP boot and RPC still work. Discussed on Zulip: https://rust-for-linux.zulipchat.com/#narrow/channel/509436-Nova/topic/nova.20core.3A.20DMA-API.3A.20nova-core.200000.3A00.3A03.2E0.3A.20mapping.20sg.20segme/with/618319830 Matteo Kloiber (2): gpu: nova-core: declare unlimited DMA max segment size rust: scatterlist: honor the device's maximum segment size drivers/gpu/nova-core/gpu.rs | 7 +++++++ rust/helpers/dma.c | 5 +++++ rust/kernel/scatterlist.rs | 12 ++++++++++-- 3 files changed, 22 insertions(+), 2 deletions(-) base-commit: cee9395acd8043be0644b25c34bfa86623f2b935 -- 2.51.2 ^ permalink raw reply [flat|nested] 5+ messages in thread
* [PATCH 1/2] gpu: nova-core: declare unlimited DMA max segment size 2026-08-31 23:32 [PATCH 0/2] rust: honor the maximum DMA segment size Matteo Kloiber @ 2026-08-31 23:32 ` Matteo Kloiber 2026-09-07 2:10 ` Alexandre Courbot 2026-08-31 23:32 ` [PATCH 2/2] rust: scatterlist: honor the device's maximum " Matteo Kloiber 1 sibling, 1 reply; 5+ messages in thread From: Matteo Kloiber @ 2026-08-31 23:32 UTC (permalink / raw) To: dakr, acourbot Cc: aliceryhl, ojeda, airlied, simona, abdiel.janulgue, daniel.almeida, robin.murphy, a.hindborg, nova-gpu, dri-devel, driver-core, rust-for-linux, linux-kernel, Matteo Kloiber The PCI default max_seg_size is 64 KiB. nova-core never raises it, so mapping the GSP firmware image (~60 MiB) as a scatter-gather table triggers a DMA-API debug warning when contiguous pages coalesce into segments that exceed the default: DMA-API: nova-core 0000:00:03.0: mapping sg segment longer than device claims to support [len=62914560] [max=65536] CONFIG_DMA_API_DEBUG=y is required to see this warning. Signed-off-by: Matteo Kloiber <kernel@matt3o12.de> Assisted-by: Claude:claude-opus-4-8 --- drivers/gpu/nova-core/gpu.rs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/drivers/gpu/nova-core/gpu.rs b/drivers/gpu/nova-core/gpu.rs index fd1414004dd0..233ef2dc9688 100644 --- a/drivers/gpu/nova-core/gpu.rs +++ b/drivers/gpu/nova-core/gpu.rs @@ -343,6 +343,13 @@ pub(crate) fn new<'a>( // still constructing it, so no concurrent DMA allocations can exist. unsafe { pdev.dma_set_mask_and_coherent(dma_mask)? }; + // Nova re-decomposes SG segments into 4 KiB page-table entries, so it + // has no upper bound on segment length; declare that to the DMA layer. + // + // SAFETY: same invariant as above -- still constructing, no concurrent + // DMA mapping can exist. + unsafe { pdev.dma_set_max_seg_size(u32::MAX) }; + hal.wait_gfw_boot_completion(bar) .inspect_err(|_| dev_err!(dev, "GFW boot did not complete\n"))?; }, -- 2.51.2 ^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: [PATCH 1/2] gpu: nova-core: declare unlimited DMA max segment size 2026-08-31 23:32 ` [PATCH 1/2] gpu: nova-core: declare unlimited DMA max " Matteo Kloiber @ 2026-09-07 2:10 ` Alexandre Courbot 0 siblings, 0 replies; 5+ messages in thread From: Alexandre Courbot @ 2026-09-07 2:10 UTC (permalink / raw) To: Matteo Kloiber Cc: dakr, aliceryhl, ojeda, airlied, simona, abdiel.janulgue, daniel.almeida, robin.murphy, a.hindborg, nova-gpu, dri-devel, driver-core, rust-for-linux, linux-kernel On Tue Sep 1, 2026 at 8:32 AM JST, Matteo Kloiber wrote: > The PCI default max_seg_size is 64 KiB. nova-core never raises it, so > mapping the GSP firmware image (~60 MiB) as a scatter-gather table > triggers a DMA-API debug warning when contiguous pages coalesce into > segments that exceed the default: > > DMA-API: nova-core 0000:00:03.0: mapping sg segment longer than > device claims to support [len=62914560] [max=65536] > > CONFIG_DMA_API_DEBUG=y is required to see this warning. > > Signed-off-by: Matteo Kloiber <kernel@matt3o12.de> > Assisted-by: Claude:claude-opus-4-8 Note: new kernel policy [1] asks that the specific model is not named, so this should just be `Assisted-by: LLM`. (also should be placed before your `Signed-off-by`) [1] https://docs.kernel.org/process/coding-assistants.html > --- > drivers/gpu/nova-core/gpu.rs | 7 +++++++ > 1 file changed, 7 insertions(+) > > diff --git a/drivers/gpu/nova-core/gpu.rs b/drivers/gpu/nova-core/gpu.rs > index fd1414004dd0..233ef2dc9688 100644 > --- a/drivers/gpu/nova-core/gpu.rs > +++ b/drivers/gpu/nova-core/gpu.rs > @@ -343,6 +343,13 @@ pub(crate) fn new<'a>( > // still constructing it, so no concurrent DMA allocations can exist. > unsafe { pdev.dma_set_mask_and_coherent(dma_mask)? }; > > + // Nova re-decomposes SG segments into 4 KiB page-table entries, so it > + // has no upper bound on segment length; declare that to the DMA layer. > + // > + // SAFETY: same invariant as above -- still constructing, no concurrent > + // DMA mapping can exist. > + unsafe { pdev.dma_set_max_seg_size(u32::MAX) }; Thanks, this patch looks correct and I would like to merge it early, but one thing about the comment: it carries way more context than needed and reads heavily, as is often the case when AI-generated. For instance, "declare that to the DMA layer" is obvious from the method we are calling. Make sure to give a human pass to such comments as they can make the code tedious when they accumulate. Conversely, `as above` is risky because the above in question might change and we then lose the reference, so here it's actually better to state the invariant in a self-contained way. Copy-pasting is ok. For instance: // Nova walks SG segments to build page tables, so their length is // irrelevant to the device. // // SAFETY: `Gpu` owns all DMA allocations for this device, and we are // still constructing it, so no concurrent DMA allocations can exist. Since this seems to be your first patch, this is a good opportunity to practice sending a v2. :) ^ permalink raw reply [flat|nested] 5+ messages in thread
* [PATCH 2/2] rust: scatterlist: honor the device's maximum segment size 2026-08-31 23:32 [PATCH 0/2] rust: honor the maximum DMA segment size Matteo Kloiber 2026-08-31 23:32 ` [PATCH 1/2] gpu: nova-core: declare unlimited DMA max " Matteo Kloiber @ 2026-08-31 23:32 ` Matteo Kloiber 2026-09-07 2:43 ` Alexandre Courbot 1 sibling, 1 reply; 5+ messages in thread From: Matteo Kloiber @ 2026-08-31 23:32 UTC (permalink / raw) To: dakr, acourbot Cc: aliceryhl, ojeda, airlied, simona, abdiel.janulgue, daniel.almeida, robin.murphy, a.hindborg, nova-gpu, dri-devel, driver-core, rust-for-linux, linux-kernel, Matteo Kloiber SGTable::new() caps segment length at dma_max_mapping_size() only, which limits the DMA mapping path (e.g. swiotlb), not the device itself. The per-device limit from dma_set_max_seg_size() is ignored, so contiguous page segments can be longer than the declared max segment size, potentially causing problems for future drivers that use this abstraction. nova-core declares an unlimited segment size, so this does not change its behavior. Fixes: 05aa6fb1c21d ("rust: scatterlist: Add abstraction for sg_table") Signed-off-by: Matteo Kloiber <kernel@matt3o12.de> --- rust/helpers/dma.c | 5 +++++ rust/kernel/scatterlist.rs | 12 ++++++++++-- 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/rust/helpers/dma.c b/rust/helpers/dma.c index 9fbeb507b08c..ff8f24dae9df 100644 --- a/rust/helpers/dma.c +++ b/rust/helpers/dma.c @@ -49,3 +49,8 @@ __rust_helper void rust_helper_dma_set_max_seg_size(struct device *dev, { dma_set_max_seg_size(dev, size); } + +__rust_helper unsigned int rust_helper_dma_get_max_seg_size(struct device *dev) +{ + return dma_get_max_seg_size(dev); +} diff --git a/rust/kernel/scatterlist.rs b/rust/kernel/scatterlist.rs index b83c468b5c63..d677dcbe7aac 100644 --- a/rust/kernel/scatterlist.rs +++ b/rust/kernel/scatterlist.rs @@ -350,15 +350,23 @@ fn new( page_vec.push(page.as_ptr(), flags)?; } + // Cap segments at both the DMA mapping-path limit and the device's declared + // max segment size. + // // `dma_max_mapping_size` returns `size_t`, but `sg_alloc_table_from_pages_segment()` takes // an `unsigned int`. // // SAFETY: `dev.as_raw()` is a valid pointer to a `struct device`. - let max_segment = match unsafe { bindings::dma_max_mapping_size(dev.as_raw()) } { + let max_mapping = match unsafe { bindings::dma_max_mapping_size(dev.as_raw()) } { 0 => u32::MAX, - max_segment => u32::try_from(max_segment).unwrap_or(u32::MAX), + max_mapping => u32::try_from(max_mapping).unwrap_or(u32::MAX), }; + // SAFETY: `dev.as_raw()` is a valid pointer to a `struct device`. + let max_seg_size = unsafe { bindings::dma_get_max_seg_size(dev.as_raw()) }; + + let max_segment = max_mapping.min(max_seg_size); + Ok(try_pin_init!(&this in Self { // SAFETY: // - `page_vec` is a `KVec` of valid `struct page *` obtained from `pages`. -- 2.51.2 ^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: [PATCH 2/2] rust: scatterlist: honor the device's maximum segment size 2026-08-31 23:32 ` [PATCH 2/2] rust: scatterlist: honor the device's maximum " Matteo Kloiber @ 2026-09-07 2:43 ` Alexandre Courbot 0 siblings, 0 replies; 5+ messages in thread From: Alexandre Courbot @ 2026-09-07 2:43 UTC (permalink / raw) To: Matteo Kloiber Cc: dakr, aliceryhl, ojeda, airlied, simona, abdiel.janulgue, daniel.almeida, robin.murphy, a.hindborg, nova-gpu, dri-devel, driver-core, rust-for-linux, linux-kernel On Tue Sep 1, 2026 at 8:32 AM JST, Matteo Kloiber wrote: > SGTable::new() caps segment length at dma_max_mapping_size() only, which > limits the DMA mapping path (e.g. swiotlb), not the device itself. The > per-device limit from dma_set_max_seg_size() is ignored, so contiguous > page segments can be longer than the declared max segment size, > potentially causing problems for future drivers that use this > abstraction. > > nova-core declares an unlimited segment size, so this does not change > its behavior. I guess what this last paragraph wants to state is that no user is affected by this patch? There is another subtle user though: the Rust DMA sample. In any case, this patch without patch 1 wouldn't break either of those (only waste a bit more memory in SG entries with nova-core), so maybe we can skip it. > > Fixes: 05aa6fb1c21d ("rust: scatterlist: Add abstraction for sg_table") > Signed-off-by: Matteo Kloiber <kernel@matt3o12.de> > --- > rust/helpers/dma.c | 5 +++++ > rust/kernel/scatterlist.rs | 12 ++++++++++-- > 2 files changed, 15 insertions(+), 2 deletions(-) > > diff --git a/rust/helpers/dma.c b/rust/helpers/dma.c > index 9fbeb507b08c..ff8f24dae9df 100644 > --- a/rust/helpers/dma.c > +++ b/rust/helpers/dma.c > @@ -49,3 +49,8 @@ __rust_helper void rust_helper_dma_set_max_seg_size(struct device *dev, > { > dma_set_max_seg_size(dev, size); > } > + > +__rust_helper unsigned int rust_helper_dma_get_max_seg_size(struct device *dev) > +{ > + return dma_get_max_seg_size(dev); > +} > diff --git a/rust/kernel/scatterlist.rs b/rust/kernel/scatterlist.rs > index b83c468b5c63..d677dcbe7aac 100644 > --- a/rust/kernel/scatterlist.rs > +++ b/rust/kernel/scatterlist.rs > @@ -350,15 +350,23 @@ fn new( > page_vec.push(page.as_ptr(), flags)?; > } > > + // Cap segments at both the DMA mapping-path limit and the device's declared > + // max segment size. > + // > // `dma_max_mapping_size` returns `size_t`, but `sg_alloc_table_from_pages_segment()` takes > // an `unsigned int`. > // > // SAFETY: `dev.as_raw()` is a valid pointer to a `struct device`. > - let max_segment = match unsafe { bindings::dma_max_mapping_size(dev.as_raw()) } { > + let max_mapping = match unsafe { bindings::dma_max_mapping_size(dev.as_raw()) } { > 0 => u32::MAX, > - max_segment => u32::try_from(max_segment).unwrap_or(u32::MAX), > + max_mapping => u32::try_from(max_mapping).unwrap_or(u32::MAX), nit: if we rename this variable, let's name it `max_mapping_size` for consistency. > }; > > + // SAFETY: `dev.as_raw()` is a valid pointer to a `struct device`. > + let max_seg_size = unsafe { bindings::dma_get_max_seg_size(dev.as_raw()) }; > + > + let max_segment = max_mapping.min(max_seg_size); This looks like the correct thing to do indeed. Reviewed-by: Alexandre Courbot <acourbot@nvidia.com> (the following is a related thought, not a request for this patch) It also means that without patch 1, nova-core would split the firmware into hundreds of 64KB SG entries, which is not breaking but still something we want to avoid. The correct fix is to make sure that `dma_set_max_seg_size` is called by the driver, and while we are at it we also want every driver to call `dma_set_mask_and_coherent`. Ideally we would use the type system to make sure that both functions are called before any DMA operation can take place (using a safe interface), but I'm not quite sure yet how we can do this. ^ permalink raw reply [flat|nested] 5+ messages in thread
end of thread, other threads:[~2026-09-07 2:43 UTC | newest] Thread overview: 5+ messages (download: mbox.gz / follow: Atom feed) -- links below jump to the message on this page -- 2026-08-31 23:32 [PATCH 0/2] rust: honor the maximum DMA segment size Matteo Kloiber 2026-08-31 23:32 ` [PATCH 1/2] gpu: nova-core: declare unlimited DMA max " Matteo Kloiber 2026-09-07 2:10 ` Alexandre Courbot 2026-08-31 23:32 ` [PATCH 2/2] rust: scatterlist: honor the device's maximum " Matteo Kloiber 2026-09-07 2:43 ` Alexandre Courbot
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®