From: "Danilo Krummrich" <dakr@kernel.org>
To: "Alexandre Belloni" <alexandre.belloni@bootlin.com>
Cc: "Rafael J. Wysocki" <rafael@kernel.org>,
"Alvin Sun" <alvin.sun@linux.dev>,
"Miguel Ojeda" <ojeda@kernel.org>,
"Boqun Feng" <boqun.feng@gmail.com>,
"Gary Guo" <gary@garyguo.net>,
"Björn Roy Baron" <bjorn3_gh@protonmail.com>,
"Benno Lossin" <lossin@kernel.org>,
"Andreas Hindborg" <a.hindborg@kernel.org>,
"Alice Ryhl" <aliceryhl@google.com>,
"Trevor Gross" <tmgross@umich.edu>,
linux-rtc@vger.kernel.org, rust-for-linux@vger.kernel.org,
"Greg Kroah-Hartman" <gregkh@linuxfoundation.org>
Subject: Re: [RFC PATCH v3 1/5] rtc: add device selector for rtc_class_ops callbacks
Date: Sun, 22 Feb 2026 13:49:35 +0100 [thread overview]
Message-ID: <DGLI4H9M0T6D.25RTLDVU5JRBE@kernel.org> (raw)
In-Reply-To: <20260222000556ea1938c0@mail.local>
On Sun Feb 22, 2026 at 1:05 AM CET, Alexandre Belloni wrote:
> On 21/02/2026 15:33:48+0100, Danilo Krummrich wrote:
>> (2) Bus device private data vs. class device private data.
>>
>> The change to pass a struct rtc_device in class device callbacks of RTC,
>> rather than the base struct device of the corresponding bus device (e.g. AMBA,
>> platform, etc.) should not aim at storing all data in rtc->dev.private_data
>> that was previously stored in rtc->dev.parent->private_data.
>>
>
> But what you explain here is that the drive is forbidden to use
> rtc->dev.parent->private_data at all because the rust core is already
> using it. What I'm saying is that it won't work because more than half
> of the drivers currently need it.
I think I was explaining the exact opposite, i.e. the driver's bus device
private data is stored in the exact same way as in C, but it has a defined
lifetime (from probe() until remove() and all devres callbacks have been
completed) and is managed by the driver-core.
Look at this example:
// The bus device private data.
struct SampleDriver {
foo: u32,
bar: u32,
}
impl pci::Driver for SampleDriver {
fn probe(pdev: &pci::Device<Core>, info: &Self::IdInfo) -> impl PinInit<Self, Error> {
// Return the driver's bus device private data. The driver-core
// will do all the work for us and eventually call
// `dev_set_drvdata()` on the base `struct device` of `pdev`.
Ok(Foo {
foo: 42,
bar: 24,
})
}
fn unbind(pdev: &pci::Device<Core>, self: Pin<&Self>) {
// Use the driver's device private data from the method's `self` argument.
dev_info!(pdev, "foo: {}, bar: {}\n", self.foo, self.bar);
// There's also the `Device<Bound>::drvdata()` accessor, let's
// use that as well.
// Get a generic `device::Device` from the `pci::Device`.
let dev = pdev.as_ref();
// Get the `drvdata`; we have to assert the type and let the driver-core
// validate that the asserted type is correct.
let drvdata = dev.drvdata::<SampleDriver>()?;
dev_info!(pdev, "foo: {}, bar: {}\n", drvdata.foo, drvdata.bar);
}
}
>> This thread seems to contain quite a bit of confusion and misunderstandings --
>> let me try to clarify.
>>
>> (1) How Rust handles bus device private data.
>>
>> In Rust the probe() function of a bus implementation (platform, PCI, etc.)
>> returns an initializer (impl PinInit<T, Error>) for the driver's device
>> private data.
>>
>> The bus implementation takes this initializer and passes it (together with the
>> underlying struct device) to the driver-core. The driver-core allocates the
>> required memory, initializes the memory with the given initializer and stores
>> a pointer to the corresponding object with dev_set_drvdata().
>>
>> So, technically, in Rust all platform drivers call platform_set_drvdata().
>>
>> (Note that this is also true when the driver's device private data type is
>> empty (i.e. it has no fields). In this case it could still have a destructor
>> that must be called when the device private data structure is destroyed. Of
>> course there is no real memory allocation when the struct's size is zero.)
>>
>> The driver's device private data can only be accessed when the bus device is
>> bound to the driver, i.e. the driver can only access it with a &Device<Bound>;
>> it (the driver's device private data) is automatically freed by the
>> driver-core when remove() and all devres callbacks have been completed.
>>
>> I.e. the rules are - of course - the same as on the C side, but they are
>> enforced by the type system and the driver-core code.
>>
>
> This still doesn't explain how you get the class private data that you
> need when you are in a driver callback that is called from the bus (e.g.
> suspend/resume) from what you explain, the driver doesn't have any
> chance to pass it. The whole goal of a device driver is to be the glue
> between a class device and a bus device as essentially this is the exact
> physical device, just represented differently.
It is not always as simple as "one bus device corresponds to one class device".
Sometimes drivers have to deal with multiple class devices for a single bus
device, sometimes they are separated through the auxiliary bus or MFD.
For instance, take struct net_device. In the context of cfg80211 wireless
drivers may create arbitrary struct net_device instances, depending on how often
the add_virtual_intf() callback is called (through netlink); example in [1].
Now, regarding your question "How to access class device private data from bus
device callbacks?". Nothing prevents a driver from embedding the class device in
its bus device private data in one or the other way.
In the net device example above, the driver would probably keep a list (or
xarray, etc.) of net devices in its bus device private data, as they can be
created and removed at any point of time.
(Note that this is also a good example for when the class device private data
lives shorter than the bus device private data.)
Here is an example of this looks like in code using a DRM device as class
device.
struct SampleIrqData;
// The class device private data.
struct SampleDrm {
sched: drm::GpuScheduler,
}
// The bus device private data.
#[pin_data]
struct SampleDriver {
#[pin]
irq: irq::Registration<SampleIrqData>,
drm: ARef<drm::Device<SampleDrm>, // Refcount of a `drm::Device`.
}
impl pci::Driver for SampleDriver {
fn probe(pdev: &pci::Device<Core>, info: &Self::IdInfo) -> impl PinInit<Self, Error> {
let dev = pdev.as_ref();
let drm = drm::Device::new(dev, SampleDrm::new()?)?;
drm.register();
Ok(impl_pin_init!(Self {
irq <- irq::Registration::new(...);
drm,
})
}
fn unbind(pdev: &pci::Device<Core>, self: Pin<&Self>) {
self.irq.synchronize();
self.drm.flush_scheduler();
}
}
Note that the irq::Registration is dropped when the bus device is unbound,
whereas the GpuScheduler is dropped when the DRM device is dropped.
Of course, depending on the actual class device this difference may be more or
less important, i.e. absolutely crucial in the net device example, less
important for RTC apparently. But it is always good to be precise about
ownership and lifetime of data.
As I already mentioned, I don't think it is good to fold ownership and lifetime
for bus and class devices together in cases where it happens that they are
mostly identical, i.e.:
>> I think it would be good to keep driver authors finding a common pattern,
>> where class device callbacks carry the corresponding class device struct
>> (instead of the parent base struct device).
>>
>> Especially on the Rust side we now have the chance to make the experience
>> of writing drivers as consistent as possible, which should help (new)
>> driver authors a lot in terms of learning the driver lifetime patterns.
[1] https://elixir.bootlin.com/linux/v6.19.2/source/drivers/net/wireless/microchip/wilc1000/netdev.c#L948
next prev parent reply other threads:[~2026-02-22 12:49 UTC|newest]
Thread overview: 43+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-01-16 16:21 [RFC PATCH v3 0/5] rust: Add RTC driver support Ke Sun
2026-01-16 16:21 ` [RFC PATCH v3 1/5] rtc: add device selector for rtc_class_ops callbacks Ke Sun
2026-01-16 16:24 ` Ke Sun
2026-01-19 14:32 ` Danilo Krummrich
2026-01-20 8:01 ` Ke Sun
2026-02-20 22:53 ` Alexandre Belloni
2026-02-21 9:31 ` Alvin Sun
2026-02-21 11:16 ` Alexandre Belloni
2026-02-21 11:19 ` Rafael J. Wysocki
2026-02-21 14:33 ` Danilo Krummrich
2026-02-22 0:05 ` Alexandre Belloni
2026-02-22 12:49 ` Danilo Krummrich [this message]
2026-02-22 14:01 ` Rafael J. Wysocki
2026-02-22 16:13 ` Danilo Krummrich
2026-02-24 0:12 ` Danilo Krummrich
2026-02-24 13:28 ` Rafael J. Wysocki
2026-02-24 14:57 ` Alexandre Belloni
2026-02-24 15:23 ` Rafael J. Wysocki
2026-02-24 15:36 ` Danilo Krummrich
2026-02-24 15:01 ` Alexandre Belloni
2026-02-24 16:35 ` Danilo Krummrich
2026-02-24 16:42 ` Danilo Krummrich
2026-02-24 17:28 ` Alexandre Belloni
2026-02-24 22:23 ` Danilo Krummrich
2026-02-24 22:44 ` Alexandre Belloni
2026-02-25 3:19 ` Gary Guo
2026-02-25 13:33 ` Rafael J. Wysocki
2026-02-25 16:26 ` Danilo Krummrich
2026-02-25 21:15 ` Rafael J. Wysocki
2026-02-26 12:28 ` Rafael J. Wysocki
2026-02-27 15:09 ` Benno Lossin
2026-02-22 12:25 ` Rafael J. Wysocki
2026-02-22 14:24 ` Rafael J. Wysocki
2026-02-22 15:29 ` Danilo Krummrich
2026-02-22 15:43 ` Rafael J. Wysocki
2026-02-21 16:32 ` Alvin Sun
2026-02-21 17:53 ` Danilo Krummrich
2026-01-16 16:22 ` [RFC PATCH v3 2/5] rust: add AMBA bus driver support Ke Sun
2026-01-16 16:22 ` [RFC PATCH v3 3/5] rust: add device wakeup capability support Ke Sun
2026-01-17 0:44 ` Ke Sun
2026-01-16 16:22 ` [RFC PATCH v3 4/5] rust: add RTC core abstractions and data structures Ke Sun
2026-01-16 16:34 ` [RFC PATCH v3 5/5] rust: add PL031 RTC driver Ke Sun
2026-01-19 9:12 ` Ke Sun
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=DGLI4H9M0T6D.25RTLDVU5JRBE@kernel.org \
--to=dakr@kernel.org \
--cc=a.hindborg@kernel.org \
--cc=alexandre.belloni@bootlin.com \
--cc=aliceryhl@google.com \
--cc=alvin.sun@linux.dev \
--cc=bjorn3_gh@protonmail.com \
--cc=boqun.feng@gmail.com \
--cc=gary@garyguo.net \
--cc=gregkh@linuxfoundation.org \
--cc=linux-rtc@vger.kernel.org \
--cc=lossin@kernel.org \
--cc=ojeda@kernel.org \
--cc=rafael@kernel.org \
--cc=rust-for-linux@vger.kernel.org \
--cc=tmgross@umich.edu \
/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