mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
From: Matteo Kloiber <kernel@matt3o12.de>
To: Alexandre Courbot <acourbot@nvidia.com>
Cc: Danilo Krummrich <dakr@kernel.org>, Gary Guo <gary@garyguo.net>,
	Robin Murphy <robin.murphy@arm.com>,
	aliceryhl@google.com, ojeda@kernel.org, airlied@gmail.com,
	simona@ffwll.ch, abdiel.janulgue@gmail.com,
	daniel.almeida@collabora.com, a.hindborg@kernel.org,
	nova-gpu@lists.linux.dev, dri-devel@lists.freedesktop.org,
	driver-core@lists.linux.dev, rust-for-linux@vger.kernel.org,
	linux-kernel@vger.kernel.org
Subject: Re: [PATCH 2/2] rust: scatterlist: honor the device's maximum segment size
Date: Mon, 28 Sep 2026 00:44:43 +0200	[thread overview]
Message-ID: <20260927224446.1053037-1-kernel@matt3o12.de> (raw)
In-Reply-To: <DLHH0K25NLX5.616R4D860TXU@nvidia.com>

First of all, thanks for merging my first two patches and sorry about my late reply.

What I think Alex meant and what I agree with is that the new API should focus on
making semantic bugs harder, not to necessarily make it easier to write safer
drivers. That being said, I think we can do both with this change.

The key change here is that we introduce a structure that defines dma
parameters for a device. This structure deliberately has no default
implementation and new fields should be added even if they require changes for
all dma drivers.

```
pub struct Params {
    pub streaming_mask: DmaMask,
    pub coherent_mask: DmaMask,
    pub max_seg_size: NonZeroU32,
}
```

Suppose, we didn't have `max_seg_size` before and only discovered it later. We
would add it and the compiler would guide us to any drivers that will need to
consider an appropriate value for `max_seg_size`.

If rust was bigger in the kernel, this could be quite a bit of work, requiring
coordination with other maintainers, but I would call this a feature because it
actually requires everyone to at least consider what the right value is instead
of forgetting to set it.

The same is also true for new drivers. Authors do not have to be omniscient of
all dma related settings and instead just fill out the struct and already have
some important ones set.

If a parameter is only important for some drivers but those drivers should not
forget it, we could make it an Option so that drivers that really don't need
a parameter can set it to `None`, but they had to think about it at least.

I think, instead of discussing different possibilities, it might be easier to
discuss code directly. Taking Alex's example, I went ahead and wrote a small
LLM assisted PoC. I'm happy to share it here or in another thread, but here are
the main changes:

1. The PCI and platform probe callbacks receive a unique setup token:

```rust
    fn probe<'bound>(
        dev: &'bound Device<device::Core<'_>>,
        dma: dma::Setup<'bound>,
        id_info: Option<&'bound Self::IdInfo>,
    ) -> impl PinInit<Self::Data<'bound>, Error> + 'bound;
```

The bus driver creates this token and drivers cannot obtain another one from
the device. 

2. `setup.configure(params)` consumes the token, applies the parameters through
   the C DMA setters, and returns a `dma::Handle<'bound>` on success.  This
   combines the setters and `finish()` from Alex's outline into one call.

```
pub fn configure(self, params: Params) -> Result<Handle<'bound>> {
    let dev = self.dev.as_raw();

    // SAFETY: `dev` is valid and its DMA parameters are initialized by the bus. The `Setup`
    // invariants exclude concurrent DMA operations and other parameter setters. Consuming
    // the unique token prevents reconfiguration after a handle has been issued.
    unsafe {
        to_result(bindings::dma_set_mask(dev, params.streaming_mask.value()))?;
        to_result(bindings::dma_set_coherent_mask(dev, params.coherent_mask.value()))?;
        bindings::dma_set_max_seg_size(dev, params.max_seg_size.get());
    }

    Ok(Handle { dev: self.dev })
}
```

3. The handle contains a bound device reference and is copyable, but provides
   no way to reconfigure DMA:

```rust
#[derive(Clone, Copy)]
pub struct Handle<'bound> {
  dev: &'bound device::Device<Bound>,
}
```

4. Allocation and mapping APIs now require a Handle. 

For example, scatter list now takes:

```
pub fn new<'a>(
  dma: dma::Handle<'a>,
  pages: P,
  dir: dma::DataDirection,
  flags: alloc::Flags,
) -> impl PinInit<Self, Error> + 'a {
```

The PoC uses Handle for coherent allocations, owned scatterlists, and DRM
scatterlist mappings.

5. Each pci/platform driver that uses DMA configures its own `Params`. Let's
   look at `samples/rust/rust_dma.rs`:

```rust
fn probe<'bound>(
    pdev: &'bound pci::Device<Core<'_>>,
    setup: dma::Setup<'bound>,
    _info: Option<&'bound Self::IdInfo>,
) -> impl PinInit<Self::Data<'bound>, Error> + 'bound {
    pin_init::pin_init_scope(move || {
        dev_info!(pdev, "Probe DMA test driver.\n");

        let mask = DmaMask::new::<64>();

        let dma = setup.configure(dma::Params {
            streaming_mask: mask,
            coherent_mask: mask,
            max_seg_size: const { NonZeroU32::new(u32::SZ_64K).unwrap() },
        })?;

        let ca: Coherent<'_, [MyStruct]> =
            Coherent::zeroed_slice(dma, TEST_VALUES.len(), GFP_KERNEL)?;

        for (i, value) in TEST_VALUES.into_iter().enumerate() {
            io_project!(ca, [panic: i]).copy_write(MyStruct::new(value.0, value.1));
        }

        let size = 4 * page::PAGE_SIZE;
        let pages = VVec::with_capacity(size, GFP_KERNEL)?;

        let sgt = SGTable::new(dma, pages, DataDirection::ToDevice, GFP_KERNEL);

        Ok(try_pin_init!(Self::Data {
            pdev,
            ca,
            sgt <- sgt,
        }))
    })
}
```

What I am not 100% sure about is how we should handle drivers that don't use
dma. Currently I just discarded the setup token like suggested, for example
`samples/rust/rust_driver_auxiliary.rs`:

```rust
impl pci::Driver for ParentDriver {
  fn probe<'bound>(
    pdev: &'bound pci::Device<Core<'_>>,
    _dma: kernel::dma::Setup<'bound>,
    _info: Option<&'bound Self::IdInfo>,
  ) -> impl PinInit<Self::Data<'bound>, Error> + 'bound { ... }
}
```

But maybe it would make sense to introduce a C API such as: `debug_no_dma` and
have the bus call it unless configure was called first. This would then trigger
a debug warning if a marked rust device calls any C APIs that use DMA
regardless. But this could also very well be a worthwhile follow up.

  reply	other threads:[~2026-09-27 22:53 UTC|newest]

Thread overview: 20+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-08-31 23:32 [PATCH 0/2] rust: honor the maximum DMA " 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-09-13 21:07     ` Matteo Kloiber
2026-08-31 23:32 ` [PATCH 2/2] rust: scatterlist: honor the device's maximum " Matteo Kloiber
2026-09-07  2:43   ` Alexandre Courbot
2026-09-13 21:08     ` Matteo Kloiber
2026-09-14  0:45       ` Alexandre Courbot
2026-09-14  9:58         ` Danilo Krummrich
2026-09-14 10:22           ` Gary Guo
2026-09-14 12:17             ` Robin Murphy
2026-09-14 13:17               ` Gary Guo
2026-09-14 13:57                 ` Danilo Krummrich
2026-09-17  9:06                   ` Alexandre Courbot
2026-09-27 22:44                     ` Matteo Kloiber [this message]
2026-09-28 15:05                       ` Alexandre Courbot
2026-09-28 17:39                         ` Gary Guo
2026-09-28 18:22                           ` Danilo Krummrich
2026-09-15  4:44             ` Alexandre Courbot
2026-09-15  4:52               ` Alexandre Courbot

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20260927224446.1053037-1-kernel@matt3o12.de \
    --to=kernel@matt3o12.de \
    --cc=a.hindborg@kernel.org \
    --cc=abdiel.janulgue@gmail.com \
    --cc=acourbot@nvidia.com \
    --cc=airlied@gmail.com \
    --cc=aliceryhl@google.com \
    --cc=dakr@kernel.org \
    --cc=daniel.almeida@collabora.com \
    --cc=dri-devel@lists.freedesktop.org \
    --cc=driver-core@lists.linux.dev \
    --cc=gary@garyguo.net \
    --cc=linux-kernel@vger.kernel.org \
    --cc=nova-gpu@lists.linux.dev \
    --cc=ojeda@kernel.org \
    --cc=robin.murphy@arm.com \
    --cc=rust-for-linux@vger.kernel.org \
    --cc=simona@ffwll.ch \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
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®