From: Danilo Krummrich <dakr@kernel.org>
To: Michal Wilczynski <m.wilczynski@samsung.com>
Cc: "Uwe Kleine-König" <ukleinek@kernel.org>,
"Miguel Ojeda" <ojeda@kernel.org>,
"Alex Gaynor" <alex.gaynor@gmail.com>,
"Boqun Feng" <boqun.feng@gmail.com>,
"Gary Guo" <gary@garyguo.net>,
"Björn Roy Baron" <bjorn3_gh@protonmail.com>,
"Andreas Hindborg" <a.hindborg@kernel.org>,
"Alice Ryhl" <aliceryhl@google.com>,
"Trevor Gross" <tmgross@umich.edu>, "Guo Ren" <guoren@kernel.org>,
"Fu Wei" <wefu@redhat.com>, "Rob Herring" <robh@kernel.org>,
"Krzysztof Kozlowski" <krzk+dt@kernel.org>,
"Conor Dooley" <conor+dt@kernel.org>,
"Paul Walmsley" <paul.walmsley@sifive.com>,
"Palmer Dabbelt" <palmer@dabbelt.com>,
"Albert Ou" <aou@eecs.berkeley.edu>,
"Alexandre Ghiti" <alex@ghiti.fr>,
"Marek Szyprowski" <m.szyprowski@samsung.com>,
"Benno Lossin" <lossin@kernel.org>,
"Michael Turquette" <mturquette@baylibre.com>,
"Drew Fustini" <fustini@kernel.org>,
linux-kernel@vger.kernel.org, linux-pwm@vger.kernel.org,
rust-for-linux@vger.kernel.org, linux-riscv@lists.infradead.org,
devicetree@vger.kernel.org
Subject: Re: [PATCH v9 2/6] rust: pwm: Add complete abstraction layer
Date: Sun, 6 Jul 2025 14:23:04 +0200 [thread overview]
Message-ID: <aGpqqGMTU3a3O8cn@pollux> (raw)
In-Reply-To: <20250706-rust-next-pwm-working-fan-for-sending-v9-2-42b5ac2101c7@samsung.com>
On Sun, Jul 06, 2025 at 01:45:13PM +0200, Michal Wilczynski wrote:
> +/// Trait defining the operations for a PWM driver.
> +pub trait PwmOps: 'static + Sized {
> + /// The type of the owned driver data (e.g., `Pin<KBox<...>>`).
> + type DrvData: 'static + ForeignOwnable;
> + /// The driver-specific hardware representation of a waveform.
> + ///
> + /// This type must be [`Copy`], [`Default`], and fit within `PWM_WFHWSIZE`.
> + type WfHw: Copy + Default;
> +
> + /// Optional hook for when a PWM device is requested.
> + fn request(
> + _chip: &Chip<Self::DrvData>,
> + _pwm: &Device,
> + _parent_dev: &device::Device<Bound>,
> + ) -> Result {
> + Ok(())
> + }
> +
> + /// Optional hook for when a PWM device is freed.
> + fn free(_chip: &Chip<Self::DrvData>, _pwm: &Device, _parent_dev: &device::Device<Bound>) {}
NIT: I can't think of a case providing this callback in Rust is useful. Do you
have a clear use-case in mind? Otherwise, I'd not provide this callback until
you have one. Should be trivial to add later on.
> +impl<T: PwmOps> Adapter<T> {
<snip>
> + /// # Safety
> + ///
> + /// `dev` must be a valid pointer to a `bindings::device` embedded within a
> + /// `bindings::pwm_chip`. This function is called by the device core when the
> + /// last reference to the device is dropped.
> + unsafe extern "C" fn release_callback(dev: *mut bindings::device) {
> + // SAFETY: The function's contract guarantees that `dev` points to a `device`
> + // field embedded within a valid `pwm_chip`. `container_of!` can therefore
> + // safely calculate the address of the containing struct.
> + let c_chip_ptr = unsafe { container_of!(dev, bindings::pwm_chip, dev) };
> +
> + // SAFETY: `c_chip_ptr` is a valid pointer to a `pwm_chip` as established
> + // above. Calling this FFI function is safe.
> + let drvdata_ptr = unsafe { bindings::pwmchip_get_drvdata(c_chip_ptr) };
> +
> + if !drvdata_ptr.is_null() {
Is this check needed? I think one can't create a pwm::Chip instance without
providing a T, so this pointer can't be NULL I think.
> + // SAFETY: `drvdata_ptr` was stored by `Chip::new` from an owned `T::DrvData`
> + // and is guaranteed to be valid if non-null. `from_foreign` can safely
> + // reclaim ownership to allow Rust to drop and free the data.
> + let _owned_drvdata = unsafe { T::DrvData::from_foreign(drvdata_ptr.cast()) };
> + }
> + }
If you overwrite this callback (as you do below) you're leaking the memory
allocated by pwmchip_alloc().
The simple way to solve this would be to call pwmchip_release() from here.
<snip>
> +impl<T: 'static + ForeignOwnable> Chip<T> {
> + /// Allocates and wraps a PWM chip using `bindings::pwmchip_alloc`.
> + ///
> + /// Returns an [`ARef<Chip>`] managing the chip's lifetime via refcounting
> + /// on its embedded `struct device`.
> + pub fn new<O: PwmOps<DrvData = T>>(
> + parent_dev: &device::Device,
> + npwm: u32,
> + sizeof_priv: usize,
> + drvdata: T,
> + ) -> Result<ARef<Self>> {
> + // SAFETY: `parent_device_for_dev_field.as_raw()` is valid.
> + // `bindings::pwmchip_alloc` returns a valid `*mut bindings::pwm_chip` (refcount 1)
> + // or an ERR_PTR.
> + let c_chip_ptr_raw =
> + unsafe { bindings::pwmchip_alloc(parent_dev.as_raw(), npwm, sizeof_priv) };
> +
> + let c_chip_ptr: *mut bindings::pwm_chip = error::from_err_ptr(c_chip_ptr_raw)?;
> +
> + // Set the custom release function on the embedded device. This is the crucial step
> + // to ensure `drvdata` is freed when the chip's refcount reaches zero, regardless
> + // of whether `Registration::register` was called.
> + // SAFETY: `c_chip_ptr` points to a valid chip.
> + unsafe { (*c_chip_ptr).dev.release = Some(Adapter::<O>::release_callback); }
This overwrites [1].
[1] https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/drivers/pwm/core.c?h=v6.16-rc4#n1601
WARNING: multiple messages have this Message-ID (diff)
From: Danilo Krummrich <dakr@kernel.org>
To: Michal Wilczynski <m.wilczynski@samsung.com>
Cc: "Uwe Kleine-König" <ukleinek@kernel.org>,
"Miguel Ojeda" <ojeda@kernel.org>,
"Alex Gaynor" <alex.gaynor@gmail.com>,
"Boqun Feng" <boqun.feng@gmail.com>,
"Gary Guo" <gary@garyguo.net>,
"Björn Roy Baron" <bjorn3_gh@protonmail.com>,
"Andreas Hindborg" <a.hindborg@kernel.org>,
"Alice Ryhl" <aliceryhl@google.com>,
"Trevor Gross" <tmgross@umich.edu>, "Guo Ren" <guoren@kernel.org>,
"Fu Wei" <wefu@redhat.com>, "Rob Herring" <robh@kernel.org>,
"Krzysztof Kozlowski" <krzk+dt@kernel.org>,
"Conor Dooley" <conor+dt@kernel.org>,
"Paul Walmsley" <paul.walmsley@sifive.com>,
"Palmer Dabbelt" <palmer@dabbelt.com>,
"Albert Ou" <aou@eecs.berkeley.edu>,
"Alexandre Ghiti" <alex@ghiti.fr>,
"Marek Szyprowski" <m.szyprowski@samsung.com>,
"Benno Lossin" <lossin@kernel.org>,
"Michael Turquette" <mturquette@baylibre.com>,
"Drew Fustini" <fustini@kernel.org>,
linux-kernel@vger.kernel.org, linux-pwm@vger.kernel.org,
rust-for-linux@vger.kernel.org, linux-riscv@lists.infradead.org,
devicetree@vger.kernel.org
Subject: Re: [PATCH v9 2/6] rust: pwm: Add complete abstraction layer
Date: Sun, 6 Jul 2025 14:23:04 +0200 [thread overview]
Message-ID: <aGpqqGMTU3a3O8cn@pollux> (raw)
In-Reply-To: <20250706-rust-next-pwm-working-fan-for-sending-v9-2-42b5ac2101c7@samsung.com>
On Sun, Jul 06, 2025 at 01:45:13PM +0200, Michal Wilczynski wrote:
> +/// Trait defining the operations for a PWM driver.
> +pub trait PwmOps: 'static + Sized {
> + /// The type of the owned driver data (e.g., `Pin<KBox<...>>`).
> + type DrvData: 'static + ForeignOwnable;
> + /// The driver-specific hardware representation of a waveform.
> + ///
> + /// This type must be [`Copy`], [`Default`], and fit within `PWM_WFHWSIZE`.
> + type WfHw: Copy + Default;
> +
> + /// Optional hook for when a PWM device is requested.
> + fn request(
> + _chip: &Chip<Self::DrvData>,
> + _pwm: &Device,
> + _parent_dev: &device::Device<Bound>,
> + ) -> Result {
> + Ok(())
> + }
> +
> + /// Optional hook for when a PWM device is freed.
> + fn free(_chip: &Chip<Self::DrvData>, _pwm: &Device, _parent_dev: &device::Device<Bound>) {}
NIT: I can't think of a case providing this callback in Rust is useful. Do you
have a clear use-case in mind? Otherwise, I'd not provide this callback until
you have one. Should be trivial to add later on.
> +impl<T: PwmOps> Adapter<T> {
<snip>
> + /// # Safety
> + ///
> + /// `dev` must be a valid pointer to a `bindings::device` embedded within a
> + /// `bindings::pwm_chip`. This function is called by the device core when the
> + /// last reference to the device is dropped.
> + unsafe extern "C" fn release_callback(dev: *mut bindings::device) {
> + // SAFETY: The function's contract guarantees that `dev` points to a `device`
> + // field embedded within a valid `pwm_chip`. `container_of!` can therefore
> + // safely calculate the address of the containing struct.
> + let c_chip_ptr = unsafe { container_of!(dev, bindings::pwm_chip, dev) };
> +
> + // SAFETY: `c_chip_ptr` is a valid pointer to a `pwm_chip` as established
> + // above. Calling this FFI function is safe.
> + let drvdata_ptr = unsafe { bindings::pwmchip_get_drvdata(c_chip_ptr) };
> +
> + if !drvdata_ptr.is_null() {
Is this check needed? I think one can't create a pwm::Chip instance without
providing a T, so this pointer can't be NULL I think.
> + // SAFETY: `drvdata_ptr` was stored by `Chip::new` from an owned `T::DrvData`
> + // and is guaranteed to be valid if non-null. `from_foreign` can safely
> + // reclaim ownership to allow Rust to drop and free the data.
> + let _owned_drvdata = unsafe { T::DrvData::from_foreign(drvdata_ptr.cast()) };
> + }
> + }
If you overwrite this callback (as you do below) you're leaking the memory
allocated by pwmchip_alloc().
The simple way to solve this would be to call pwmchip_release() from here.
<snip>
> +impl<T: 'static + ForeignOwnable> Chip<T> {
> + /// Allocates and wraps a PWM chip using `bindings::pwmchip_alloc`.
> + ///
> + /// Returns an [`ARef<Chip>`] managing the chip's lifetime via refcounting
> + /// on its embedded `struct device`.
> + pub fn new<O: PwmOps<DrvData = T>>(
> + parent_dev: &device::Device,
> + npwm: u32,
> + sizeof_priv: usize,
> + drvdata: T,
> + ) -> Result<ARef<Self>> {
> + // SAFETY: `parent_device_for_dev_field.as_raw()` is valid.
> + // `bindings::pwmchip_alloc` returns a valid `*mut bindings::pwm_chip` (refcount 1)
> + // or an ERR_PTR.
> + let c_chip_ptr_raw =
> + unsafe { bindings::pwmchip_alloc(parent_dev.as_raw(), npwm, sizeof_priv) };
> +
> + let c_chip_ptr: *mut bindings::pwm_chip = error::from_err_ptr(c_chip_ptr_raw)?;
> +
> + // Set the custom release function on the embedded device. This is the crucial step
> + // to ensure `drvdata` is freed when the chip's refcount reaches zero, regardless
> + // of whether `Registration::register` was called.
> + // SAFETY: `c_chip_ptr` points to a valid chip.
> + unsafe { (*c_chip_ptr).dev.release = Some(Adapter::<O>::release_callback); }
This overwrites [1].
[1] https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/drivers/pwm/core.c?h=v6.16-rc4#n1601
_______________________________________________
linux-riscv mailing list
linux-riscv@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-riscv
next prev parent reply other threads:[~2025-07-06 12:23 UTC|newest]
Thread overview: 24+ messages / expand[flat|nested] mbox.gz Atom feed top
[not found] <CGME20250706114603eucas1p1f2a37072bdbcaa771ba8d822463bf420@eucas1p1.samsung.com>
2025-07-06 11:45 ` [PATCH v9 0/6] Rust Abstractions for PWM subsystem with TH1520 PWM driver Michal Wilczynski
2025-07-06 11:45 ` Michal Wilczynski
2025-07-06 11:45 ` [PATCH v9 1/6] rust: pwm: Add Kconfig and basic data structures Michal Wilczynski
2025-07-06 11:45 ` Michal Wilczynski
2025-07-06 11:45 ` [PATCH v9 2/6] rust: pwm: Add complete abstraction layer Michal Wilczynski
2025-07-06 11:45 ` Michal Wilczynski
2025-07-06 12:23 ` Danilo Krummrich [this message]
2025-07-06 12:23 ` Danilo Krummrich
2025-07-07 6:57 ` Uwe Kleine-König
2025-07-07 6:57 ` Uwe Kleine-König
2025-07-07 8:12 ` Michal Wilczynski
2025-07-07 8:12 ` Michal Wilczynski
2025-07-07 7:30 ` Michal Wilczynski
2025-07-07 7:30 ` Michal Wilczynski
2025-07-07 9:15 ` Danilo Krummrich
2025-07-07 9:15 ` Danilo Krummrich
2025-07-06 11:45 ` [PATCH v9 3/6] pwm: Add Rust driver for T-HEAD TH1520 SoC Michal Wilczynski
2025-07-06 11:45 ` Michal Wilczynski
2025-07-06 11:45 ` [PATCH v9 4/6] dt-bindings: pwm: thead: Add T-HEAD TH1520 PWM controller Michal Wilczynski
2025-07-06 11:45 ` Michal Wilczynski
2025-07-06 11:45 ` [PATCH v9 5/6] riscv: dts: thead: Add PWM controller node Michal Wilczynski
2025-07-06 11:45 ` Michal Wilczynski
2025-07-06 11:45 ` [PATCH v9 6/6] riscv: dts: thead: Add PWM fan and thermal control Michal Wilczynski
2025-07-06 11:45 ` Michal Wilczynski
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=aGpqqGMTU3a3O8cn@pollux \
--to=dakr@kernel.org \
--cc=a.hindborg@kernel.org \
--cc=alex.gaynor@gmail.com \
--cc=alex@ghiti.fr \
--cc=aliceryhl@google.com \
--cc=aou@eecs.berkeley.edu \
--cc=bjorn3_gh@protonmail.com \
--cc=boqun.feng@gmail.com \
--cc=conor+dt@kernel.org \
--cc=devicetree@vger.kernel.org \
--cc=fustini@kernel.org \
--cc=gary@garyguo.net \
--cc=guoren@kernel.org \
--cc=krzk+dt@kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-pwm@vger.kernel.org \
--cc=linux-riscv@lists.infradead.org \
--cc=lossin@kernel.org \
--cc=m.szyprowski@samsung.com \
--cc=m.wilczynski@samsung.com \
--cc=mturquette@baylibre.com \
--cc=ojeda@kernel.org \
--cc=palmer@dabbelt.com \
--cc=paul.walmsley@sifive.com \
--cc=robh@kernel.org \
--cc=rust-for-linux@vger.kernel.org \
--cc=tmgross@umich.edu \
--cc=ukleinek@kernel.org \
--cc=wefu@redhat.com \
/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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.