diff mbox series

[net-next,v4,3/6] rust: net::phy implement AsRef<kernel::device::Device> trait

Message ID 20240817051939.77735-4-fujita.tomonori@gmail.com (mailing list archive)
State Superseded
Delegated to: Netdev Maintainers
Headers show
Series net: phy: add Applied Micro QT2025 PHY driver | expand

Checks

Context Check Description
netdev/series_format success Posting correctly formatted
netdev/tree_selection success Clearly marked for net-next
netdev/ynl success Generated files up to date; no warnings/errors; no diff in generated;
netdev/fixes_present success Fixes tag not required for -next series
netdev/header_inline success No static functions without inline keyword in header files
netdev/build_32bit success Errors and warnings before: 7 this patch: 7
netdev/build_tools success No tools touched, skip
netdev/cc_maintainers warning 6 maintainers not CCed: wedsonaf@gmail.com alex.gaynor@gmail.com gary@garyguo.net bjorn3_gh@protonmail.com boqun.feng@gmail.com a.hindborg@samsung.com
netdev/build_clang success Errors and warnings before: 7 this patch: 7
netdev/verify_signedoff success Signed-off-by tag matches author and committer
netdev/deprecated_api success None detected
netdev/check_selftest success No net selftest shell script
netdev/verify_fixes success No Fixes tag
netdev/build_allmodconfig_warn success Errors and warnings before: 7 this patch: 7
netdev/checkpatch warning WARNING: line length of 83 exceeds 80 columns
netdev/build_clang_rust fail Link
netdev/kdoc success Errors and warnings before: 0 this patch: 0
netdev/source_inline success Was 0 now: 0
netdev/contest success net-next-2024-08-17--18-00 (tests: 709)

Commit Message

FUJITA Tomonori Aug. 17, 2024, 5:19 a.m. UTC
Implement AsRef<kernel::device::Device> trait for Device. A PHY driver
needs a reference to device::Device to call the firmware API.

Reviewed-by: Alice Ryhl <aliceryhl@google.com>
Reviewed-by: Andrew Lunn <andrew@lunn.ch>
Signed-off-by: FUJITA Tomonori <fujita.tomonori@gmail.com>
---
 rust/kernel/net/phy.rs | 12 ++++++++++--
 1 file changed, 10 insertions(+), 2 deletions(-)

Comments

Benno Lossin Aug. 17, 2024, 1:30 p.m. UTC | #1
On 17.08.24 07:19, FUJITA Tomonori wrote:
> Implement AsRef<kernel::device::Device> trait for Device. A PHY driver
> needs a reference to device::Device to call the firmware API.
> 
> Reviewed-by: Alice Ryhl <aliceryhl@google.com>
> Reviewed-by: Andrew Lunn <andrew@lunn.ch>
> Signed-off-by: FUJITA Tomonori <fujita.tomonori@gmail.com>
> ---
>  rust/kernel/net/phy.rs | 12 ++++++++++--
>  1 file changed, 10 insertions(+), 2 deletions(-)
> 
> diff --git a/rust/kernel/net/phy.rs b/rust/kernel/net/phy.rs
> index 5e8137a1972f..569dd3beef9c 100644
> --- a/rust/kernel/net/phy.rs
> +++ b/rust/kernel/net/phy.rs
> @@ -7,8 +7,7 @@
>  //! C headers: [`include/linux/phy.h`](srctree/include/linux/phy.h).
> 
>  use crate::{error::*, prelude::*, types::Opaque};
> -
> -use core::marker::PhantomData;
> +use core::{marker::PhantomData, ptr::addr_of_mut};
> 
>  /// PHY state machine states.
>  ///
> @@ -302,6 +301,15 @@ pub fn genphy_read_abilities(&mut self) -> Result {
>      }
>  }
> 
> +impl AsRef<kernel::device::Device> for Device {
> +    fn as_ref(&self) -> &kernel::device::Device {
> +        let phydev = self.0.get();
> +        // SAFETY: The struct invariant ensures that we may access
> +        // this field without additional synchronization.

I don't see this invariant on `phy::Device`.

---
Cheers,
Benno

> +        unsafe { kernel::device::Device::as_ref(addr_of_mut!((*phydev).mdio.dev)) }
> +    }
> +}
> +
>  /// Defines certain other features this PHY supports (like interrupts).
>  ///
>  /// These flag values are used in [`Driver::FLAGS`].
> --
> 2.34.1
>
FUJITA Tomonori Aug. 18, 2024, 2:13 a.m. UTC | #2
On Sat, 17 Aug 2024 13:30:15 +0000
Benno Lossin <benno.lossin@proton.me> wrote:

>> +impl AsRef<kernel::device::Device> for Device {
>> +    fn as_ref(&self) -> &kernel::device::Device {
>> +        let phydev = self.0.get();
>> +        // SAFETY: The struct invariant ensures that we may access
>> +        // this field without additional synchronization.
> 
> I don't see this invariant on `phy::Device`.

You meant that `phy::Device` Invariants says that all methods defined
on this struct are safe to call; not about accessing a field so the
above SAFETY comment isn't correct, right?

> ---
> Cheers,
> Benno
> 
>> +        unsafe { kernel::device::Device::as_ref(addr_of_mut!((*phydev).mdio.dev)) }
>> +    }
>> +}

SAFETY: A valid `phy_device` always have a valid `mdio.dev`.

Better?
Benno Lossin Aug. 18, 2024, 6:01 a.m. UTC | #3
On 18.08.24 04:13, FUJITA Tomonori wrote:
> On Sat, 17 Aug 2024 13:30:15 +0000
> Benno Lossin <benno.lossin@proton.me> wrote:
> 
>>> +impl AsRef<kernel::device::Device> for Device {
>>> +    fn as_ref(&self) -> &kernel::device::Device {
>>> +        let phydev = self.0.get();
>>> +        // SAFETY: The struct invariant ensures that we may access
>>> +        // this field without additional synchronization.
>>
>> I don't see this invariant on `phy::Device`.
> 
> You meant that `phy::Device` Invariants says that all methods defined
> on this struct are safe to call; not about accessing a field so the
> above SAFETY comment isn't correct, right?

Correct.

>> ---
>> Cheers,
>> Benno
>>
>>> +        unsafe { kernel::device::Device::as_ref(addr_of_mut!((*phydev).mdio.dev)) }
>>> +    }
>>> +}
> 
> SAFETY: A valid `phy_device` always have a valid `mdio.dev`.
> 
> Better?

It would be nice if you could add this on the invariants on
`phy::Device` (you will also have to extend the INVAIRANTS comment that
creates a `&'a mut Device`)

---
Cheers,
Benno
FUJITA Tomonori Aug. 18, 2024, 7:36 a.m. UTC | #4
On Sun, 18 Aug 2024 06:01:27 +0000
Benno Lossin <benno.lossin@proton.me> wrote:

>>>> +impl AsRef<kernel::device::Device> for Device {
>>>> +    fn as_ref(&self) -> &kernel::device::Device {
>>>> +        let phydev = self.0.get();
>>>> +        // SAFETY: The struct invariant ensures that we may access
>>>> +        // this field without additional synchronization.
>>>
>>> I don't see this invariant on `phy::Device`.
>> 
>> You meant that `phy::Device` Invariants says that all methods defined
>> on this struct are safe to call; not about accessing a field so the
>> above SAFETY comment isn't correct, right?
> 
> Correct.

Understood.

>>>> +        unsafe { kernel::device::Device::as_ref(addr_of_mut!((*phydev).mdio.dev)) }
>>>> +    }
>>>> +}
>> 
>> SAFETY: A valid `phy_device` always have a valid `mdio.dev`.
>> 
>> Better?
> 
> It would be nice if you could add this on the invariants on
> `phy::Device` (you will also have to extend the INVAIRANTS comment that
> creates a `&'a mut Device`)

How about the followings?

diff --git a/rust/kernel/net/phy.rs b/rust/kernel/net/phy.rs
index 5e8137a1972f..3e1d6c43ca33 100644
--- a/rust/kernel/net/phy.rs
+++ b/rust/kernel/net/phy.rs
@@ -7,8 +7,7 @@
 //! C headers: [`include/linux/phy.h`](srctree/include/linux/phy.h).
 
 use crate::{error::*, prelude::*, types::Opaque};
-
-use core::marker::PhantomData;
+use core::{marker::PhantomData, ptr::addr_of_mut};
 
 /// PHY state machine states.
 ///
@@ -60,6 +59,7 @@ pub enum DuplexMode {
 ///
 /// Referencing a `phy_device` using this struct asserts that you are in
 /// a context where all methods defined on this struct are safe to call.
+/// This struct always has a valid `mdio.dev`.
 ///
 /// [`struct phy_device`]: srctree/include/linux/phy.h
 // During the calls to most functions in [`Driver`], the C side (`PHYLIB`) holds a lock that is
@@ -76,9 +76,9 @@ impl Device {
     ///
     /// # Safety
     ///
-    /// For the duration of 'a, the pointer must point at a valid `phy_device`,
-    /// and the caller must be in a context where all methods defined on this struct
-    /// are safe to call.
+    /// For the duration of 'a, the pointer must point at a valid `phy_device` with
+    /// a valid `mdio.dev`, and the caller must be in a context where all methods
+    /// defined on this struct are safe to call.
     unsafe fn from_raw<'a>(ptr: *mut bindings::phy_device) -> &'a mut Self {
         // CAST: `Self` is a `repr(transparent)` wrapper around `bindings::phy_device`.
         let ptr = ptr.cast::<Self>();
@@ -302,6 +302,14 @@ pub fn genphy_read_abilities(&mut self) -> Result {
     }
 }
 
+impl AsRef<kernel::device::Device> for Device {
+    fn as_ref(&self) -> &kernel::device::Device {
+        let phydev = self.0.get();
+        // SAFETY: The struct invariant ensures that `mdio.dev` is valid.
+        unsafe { kernel::device::Device::as_ref(addr_of_mut!((*phydev).mdio.dev)) }
+    }
+}
+
 /// Defines certain other features this PHY supports (like interrupts).
 ///
 /// These flag values are used in [`Driver::FLAGS`].
Benno Lossin Aug. 18, 2024, 9:03 a.m. UTC | #5
On 18.08.24 09:36, FUJITA Tomonori wrote:
> On Sun, 18 Aug 2024 06:01:27 +0000
> Benno Lossin <benno.lossin@proton.me> wrote:
>>>>> +        unsafe { kernel::device::Device::as_ref(addr_of_mut!((*phydev).mdio.dev)) }
>>>>> +    }
>>>>> +}
>>>
>>> SAFETY: A valid `phy_device` always have a valid `mdio.dev`.
>>>
>>> Better?
>>
>> It would be nice if you could add this on the invariants on
>> `phy::Device` (you will also have to extend the INVAIRANTS comment that
>> creates a `&'a mut Device`)
> 
> How about the followings?
> 
> diff --git a/rust/kernel/net/phy.rs b/rust/kernel/net/phy.rs
> index 5e8137a1972f..3e1d6c43ca33 100644
> --- a/rust/kernel/net/phy.rs
> +++ b/rust/kernel/net/phy.rs
> @@ -7,8 +7,7 @@
>  //! C headers: [`include/linux/phy.h`](srctree/include/linux/phy.h).
> 
>  use crate::{error::*, prelude::*, types::Opaque};
> -
> -use core::marker::PhantomData;
> +use core::{marker::PhantomData, ptr::addr_of_mut};
> 
>  /// PHY state machine states.
>  ///
> @@ -60,6 +59,7 @@ pub enum DuplexMode {
>  ///
>  /// Referencing a `phy_device` using this struct asserts that you are in
>  /// a context where all methods defined on this struct are safe to call.
> +/// This struct always has a valid `mdio.dev`.

Please turn this into a bullet point list.

>  ///
>  /// [`struct phy_device`]: srctree/include/linux/phy.h
>  // During the calls to most functions in [`Driver`], the C side (`PHYLIB`) holds a lock that is
> @@ -76,9 +76,9 @@ impl Device {
>      ///
>      /// # Safety
>      ///
> -    /// For the duration of 'a, the pointer must point at a valid `phy_device`,
> -    /// and the caller must be in a context where all methods defined on this struct
> -    /// are safe to call.
> +    /// For the duration of 'a, the pointer must point at a valid `phy_device` with
> +    /// a valid `mdio.dev`, and the caller must be in a context where all methods
> +    /// defined on this struct are safe to call.

Also here.

>      unsafe fn from_raw<'a>(ptr: *mut bindings::phy_device) -> &'a mut Self {
>          // CAST: `Self` is a `repr(transparent)` wrapper around `bindings::phy_device`.
>          let ptr = ptr.cast::<Self>();
> @@ -302,6 +302,14 @@ pub fn genphy_read_abilities(&mut self) -> Result {
>      }
>  }
> 
> +impl AsRef<kernel::device::Device> for Device {
> +    fn as_ref(&self) -> &kernel::device::Device {
> +        let phydev = self.0.get();
> +        // SAFETY: The struct invariant ensures that `mdio.dev` is valid.
> +        unsafe { kernel::device::Device::as_ref(addr_of_mut!((*phydev).mdio.dev)) }
> +    }

Just to be sure: the `phydev.mdio.dev` struct is refcounted and
incrementing the refcount is fine, right?

---
Cheers,
Benno

> +}
> +
>  /// Defines certain other features this PHY supports (like interrupts).
>  ///
>  /// These flag values are used in [`Driver::FLAGS`].
FUJITA Tomonori Aug. 18, 2024, 9:15 a.m. UTC | #6
On Sun, 18 Aug 2024 09:03:01 +0000
Benno Lossin <benno.lossin@proton.me> wrote:

>>  /// PHY state machine states.
>>  ///
>> @@ -60,6 +59,7 @@ pub enum DuplexMode {
>>  ///
>>  /// Referencing a `phy_device` using this struct asserts that you are in
>>  /// a context where all methods defined on this struct are safe to call.
>> +/// This struct always has a valid `mdio.dev`.
> 
> Please turn this into a bullet point list.

/// - Referencing a `phy_device` using this struct asserts that you are in
///   a context where all methods defined on this struct are safe to call.
/// - This struct always has a valid `mdio.dev`.

Looks fine?

>>  ///
>>  /// [`struct phy_device`]: srctree/include/linux/phy.h
>>  // During the calls to most functions in [`Driver`], the C side (`PHYLIB`) holds a lock that is
>> @@ -76,9 +76,9 @@ impl Device {
>>      ///
>>      /// # Safety
>>      ///
>> -    /// For the duration of 'a, the pointer must point at a valid `phy_device`,
>> -    /// and the caller must be in a context where all methods defined on this struct
>> -    /// are safe to call.
>> +    /// For the duration of 'a, the pointer must point at a valid `phy_device` with
>> +    /// a valid `mdio.dev`, and the caller must be in a context where all methods
>> +    /// defined on this struct are safe to call.
> 
> Also here.

/// # Safety
///
/// For the duration of 'a,
/// - the pointer must point at a valid `phy_device`, and the caller
///   must be in a context where all methods defined on this struct
///   are safe to call.
/// - 'mdio.dev' must be a valid.

Better?

>> +impl AsRef<kernel::device::Device> for Device {
>> +    fn as_ref(&self) -> &kernel::device::Device {
>> +        let phydev = self.0.get();
>> +        // SAFETY: The struct invariant ensures that `mdio.dev` is valid.
>> +        unsafe { kernel::device::Device::as_ref(addr_of_mut!((*phydev).mdio.dev)) }
>> +    }
> 
> Just to be sure: the `phydev.mdio.dev` struct is refcounted and
> incrementing the refcount is fine, right?

phydev.mdio.dev is valid after phydev is initialized.

struct phy_device {
	struct mdio_device mdio;
	...

struct mdio_device {
	struct device dev;
	...
Benno Lossin Aug. 18, 2024, 10:42 a.m. UTC | #7
On 18.08.24 11:15, FUJITA Tomonori wrote:
> On Sun, 18 Aug 2024 09:03:01 +0000
> Benno Lossin <benno.lossin@proton.me> wrote:
> 
>>>  /// PHY state machine states.
>>>  ///
>>> @@ -60,6 +59,7 @@ pub enum DuplexMode {
>>>  ///
>>>  /// Referencing a `phy_device` using this struct asserts that you are in
>>>  /// a context where all methods defined on this struct are safe to call.
>>> +/// This struct always has a valid `mdio.dev`.
>>
>> Please turn this into a bullet point list.
> 
> /// - Referencing a `phy_device` using this struct asserts that you are in
> ///   a context where all methods defined on this struct are safe to call.
> /// - This struct always has a valid `mdio.dev`.

Hmm, I think `self.0.mdio.dev` would be clearer.

> 
> Looks fine?
> 
>>>  ///
>>>  /// [`struct phy_device`]: srctree/include/linux/phy.h
>>>  // During the calls to most functions in [`Driver`], the C side (`PHYLIB`) holds a lock that is
>>> @@ -76,9 +76,9 @@ impl Device {
>>>      ///
>>>      /// # Safety
>>>      ///
>>> -    /// For the duration of 'a, the pointer must point at a valid `phy_device`,
>>> -    /// and the caller must be in a context where all methods defined on this struct
>>> -    /// are safe to call.
>>> +    /// For the duration of 'a, the pointer must point at a valid `phy_device` with
>>> +    /// a valid `mdio.dev`, and the caller must be in a context where all methods
>>> +    /// defined on this struct are safe to call.
>>
>> Also here.
> 
> /// # Safety
> ///
> /// For the duration of 'a,
> /// - the pointer must point at a valid `phy_device`, and the caller
> ///   must be in a context where all methods defined on this struct
> ///   are safe to call.
> /// - 'mdio.dev' must be a valid.

Also here: `(*ptr).mdio.dev`.

---
Cheers,
Benno

> 
> Better?
> 
>>> +impl AsRef<kernel::device::Device> for Device {
>>> +    fn as_ref(&self) -> &kernel::device::Device {
>>> +        let phydev = self.0.get();
>>> +        // SAFETY: The struct invariant ensures that `mdio.dev` is valid.
>>> +        unsafe { kernel::device::Device::as_ref(addr_of_mut!((*phydev).mdio.dev)) }
>>> +    }
>>
>> Just to be sure: the `phydev.mdio.dev` struct is refcounted and
>> incrementing the refcount is fine, right?
> 
> phydev.mdio.dev is valid after phydev is initialized.
> 
> struct phy_device {
> 	struct mdio_device mdio;
> 	...
> 
> struct mdio_device {
> 	struct device dev;
> 	...
>
FUJITA Tomonori Aug. 18, 2024, 11:25 a.m. UTC | #8
On Sun, 18 Aug 2024 10:42:32 +0000
Benno Lossin <benno.lossin@proton.me> wrote:

>> /// - Referencing a `phy_device` using this struct asserts that you are in
>> ///   a context where all methods defined on this struct are safe to call.
>> /// - This struct always has a valid `mdio.dev`.
> 
> Hmm, I think `self.0.mdio.dev` would be clearer.

Sure, fixed.

>> /// # Safety
>> ///
>> /// For the duration of 'a,
>> /// - the pointer must point at a valid `phy_device`, and the caller
>> ///   must be in a context where all methods defined on this struct
>> ///   are safe to call.
>> /// - 'mdio.dev' must be a valid.
> 
> Also here: `(*ptr).mdio.dev`.

Thanks, looks better.

Here's an updated patch.

diff --git a/rust/kernel/net/phy.rs b/rust/kernel/net/phy.rs
index 5e8137a1972f..ec337cbd391b 100644
--- a/rust/kernel/net/phy.rs
+++ b/rust/kernel/net/phy.rs
@@ -7,8 +7,7 @@
 //! C headers: [`include/linux/phy.h`](srctree/include/linux/phy.h).
 
 use crate::{error::*, prelude::*, types::Opaque};
-
-use core::marker::PhantomData;
+use core::{marker::PhantomData, ptr::addr_of_mut};
 
 /// PHY state machine states.
 ///
@@ -58,8 +57,9 @@ pub enum DuplexMode {
 ///
 /// # Invariants
 ///
-/// Referencing a `phy_device` using this struct asserts that you are in
-/// a context where all methods defined on this struct are safe to call.
+/// - Referencing a `phy_device` using this struct asserts that you are in
+///   a context where all methods defined on this struct are safe to call.
+/// - This struct always has a valid `self.0.mdio.dev`.
 ///
 /// [`struct phy_device`]: srctree/include/linux/phy.h
 // During the calls to most functions in [`Driver`], the C side (`PHYLIB`) holds a lock that is
@@ -76,9 +76,11 @@ impl Device {
     ///
     /// # Safety
     ///
-    /// For the duration of 'a, the pointer must point at a valid `phy_device`,
-    /// and the caller must be in a context where all methods defined on this struct
-    /// are safe to call.
+    /// For the duration of 'a,
+    /// - the pointer must point at a valid `phy_device`, and the caller
+    ///   must be in a context where all methods defined on this struct
+    ///   are safe to call.
+    /// - `(*ptr).mdio.dev` must be a valid.
     unsafe fn from_raw<'a>(ptr: *mut bindings::phy_device) -> &'a mut Self {
         // CAST: `Self` is a `repr(transparent)` wrapper around `bindings::phy_device`.
         let ptr = ptr.cast::<Self>();
@@ -302,6 +304,14 @@ pub fn genphy_read_abilities(&mut self) -> Result {
     }
 }
 
+impl AsRef<kernel::device::Device> for Device {
+    fn as_ref(&self) -> &kernel::device::Device {
+        let phydev = self.0.get();
+        // SAFETY: The struct invariant ensures that `mdio.dev` is valid.
+        unsafe { kernel::device::Device::as_ref(addr_of_mut!((*phydev).mdio.dev)) }
+    }
+}
+
 /// Defines certain other features this PHY supports (like interrupts).
 ///
 /// These flag values are used in [`Driver::FLAGS`].
Andrew Lunn Aug. 18, 2024, 3:38 p.m. UTC | #9
> Just to be sure: the `phydev.mdio.dev` struct is refcounted and
> incrementing the refcount is fine, right?

There is nothing special here. PHY devices are just normal Linux
devices. The device core is responsible for calling .probe() and
.remove() on a device, and these should be the first and last
operation on a device. The device core provides refcounting of the
struct device, so it should always be valid.

So i have to wounder if you are solving this at the correct
level. This should be generic to any device, so the Rust concept of a
device should be stating these guarantees, not each specific type of
device.

	Andrew
Greg Kroah-Hartman Aug. 18, 2024, 3:45 p.m. UTC | #10
On Sun, Aug 18, 2024 at 05:38:01PM +0200, Andrew Lunn wrote:
> > Just to be sure: the `phydev.mdio.dev` struct is refcounted and
> > incrementing the refcount is fine, right?
> 
> There is nothing special here. PHY devices are just normal Linux
> devices. The device core is responsible for calling .probe() and
> .remove() on a device, and these should be the first and last
> operation on a device. The device core provides refcounting of the
> struct device, so it should always be valid.
> 
> So i have to wounder if you are solving this at the correct
> level. This should be generic to any device, so the Rust concept of a
> device should be stating these guarantees, not each specific type of
> device.

It should, why isn't it using the rust binding to Device that we already
have:
	https://rust.docs.kernel.org/kernel/device/struct.Device.html
or is it?  I'm confused now...

thanks,

greg k-h
Benno Lossin Aug. 18, 2024, 3:54 p.m. UTC | #11
On 18.08.24 17:45, Greg KH wrote:
> On Sun, Aug 18, 2024 at 05:38:01PM +0200, Andrew Lunn wrote:
>>> Just to be sure: the `phydev.mdio.dev` struct is refcounted and
>>> incrementing the refcount is fine, right?
>>
>> There is nothing special here. PHY devices are just normal Linux
>> devices. The device core is responsible for calling .probe() and
>> .remove() on a device, and these should be the first and last
>> operation on a device. The device core provides refcounting of the
>> struct device, so it should always be valid.

Thanks that's good to know.

>> So i have to wounder if you are solving this at the correct
>> level. This should be generic to any device, so the Rust concept of a
>> device should be stating these guarantees, not each specific type of
>> device.
> 
> It should, why isn't it using the rust binding to Device that we already
> have:
> 	https://rust.docs.kernel.org/kernel/device/struct.Device.html
> or is it?  I'm confused now...

It is using that one.
I wanted to verify that we can use that one, since using this
implementation users can freely increment the refcount of the device
(without decrementing it before control is given back to PHYLIB). Since
that seems to be the case, all is fine.

---
Cheers,
Benno
Benno Lossin Aug. 18, 2024, 3:55 p.m. UTC | #12
On 18.08.24 13:25, FUJITA Tomonori wrote:
> On Sun, 18 Aug 2024 10:42:32 +0000
> Benno Lossin <benno.lossin@proton.me> wrote:
> 
>>> /// - Referencing a `phy_device` using this struct asserts that you are in
>>> ///   a context where all methods defined on this struct are safe to call.
>>> /// - This struct always has a valid `mdio.dev`.
>>
>> Hmm, I think `self.0.mdio.dev` would be clearer.
> 
> Sure, fixed.
> 
>>> /// # Safety
>>> ///
>>> /// For the duration of 'a,
>>> /// - the pointer must point at a valid `phy_device`, and the caller
>>> ///   must be in a context where all methods defined on this struct
>>> ///   are safe to call.
>>> /// - 'mdio.dev' must be a valid.
>>
>> Also here: `(*ptr).mdio.dev`.
> 
> Thanks, looks better.
> 
> Here's an updated patch.
> 
> diff --git a/rust/kernel/net/phy.rs b/rust/kernel/net/phy.rs
> index 5e8137a1972f..ec337cbd391b 100644
> --- a/rust/kernel/net/phy.rs
> +++ b/rust/kernel/net/phy.rs
> @@ -7,8 +7,7 @@
>  //! C headers: [`include/linux/phy.h`](srctree/include/linux/phy.h).
> 
>  use crate::{error::*, prelude::*, types::Opaque};
> -
> -use core::marker::PhantomData;
> +use core::{marker::PhantomData, ptr::addr_of_mut};
> 
>  /// PHY state machine states.
>  ///
> @@ -58,8 +57,9 @@ pub enum DuplexMode {
>  ///
>  /// # Invariants
>  ///
> -/// Referencing a `phy_device` using this struct asserts that you are in
> -/// a context where all methods defined on this struct are safe to call.
> +/// - Referencing a `phy_device` using this struct asserts that you are in
> +///   a context where all methods defined on this struct are safe to call.
> +/// - This struct always has a valid `self.0.mdio.dev`.
>  ///
>  /// [`struct phy_device`]: srctree/include/linux/phy.h
>  // During the calls to most functions in [`Driver`], the C side (`PHYLIB`) holds a lock that is
> @@ -76,9 +76,11 @@ impl Device {
>      ///
>      /// # Safety
>      ///
> -    /// For the duration of 'a, the pointer must point at a valid `phy_device`,
> -    /// and the caller must be in a context where all methods defined on this struct
> -    /// are safe to call.
> +    /// For the duration of 'a,
> +    /// - the pointer must point at a valid `phy_device`, and the caller
> +    ///   must be in a context where all methods defined on this struct
> +    ///   are safe to call.
> +    /// - `(*ptr).mdio.dev` must be a valid.
>      unsafe fn from_raw<'a>(ptr: *mut bindings::phy_device) -> &'a mut Self {
>          // CAST: `Self` is a `repr(transparent)` wrapper around `bindings::phy_device`.
>          let ptr = ptr.cast::<Self>();
> @@ -302,6 +304,14 @@ pub fn genphy_read_abilities(&mut self) -> Result {
>      }
>  }
> 
> +impl AsRef<kernel::device::Device> for Device {
> +    fn as_ref(&self) -> &kernel::device::Device {
> +        let phydev = self.0.get();
> +        // SAFETY: The struct invariant ensures that `mdio.dev` is valid.
> +        unsafe { kernel::device::Device::as_ref(addr_of_mut!((*phydev).mdio.dev)) }
> +    }
> +}
> +
>  /// Defines certain other features this PHY supports (like interrupts).
>  ///
>  /// These flag values are used in [`Driver::FLAGS`].
> --
> 2.34.1
> 

This looks, good, if you want, you can add my reviewed-by on this patch.

---
Cheers,
Benno
Andrew Lunn Aug. 18, 2024, 4:16 p.m. UTC | #13
> Thanks that's good to know.
> 
> >> So i have to wounder if you are solving this at the correct
> >> level. This should be generic to any device, so the Rust concept of a
> >> device should be stating these guarantees, not each specific type of
> >> device.
> > 
> > It should, why isn't it using the rust binding to Device that we already
> > have:
> > 	https://rust.docs.kernel.org/kernel/device/struct.Device.html
> > or is it?  I'm confused now...
> 
> It is using that one.
> I wanted to verify that we can use that one, since using this
> implementation users can freely increment the refcount of the device
> (without decrementing it before control is given back to PHYLIB). Since
> that seems to be the case, all is fine.

Any driver which is not using the device core is broken, and no amount
of SAFETY is going to fix it.

	Andrew
Benno Lossin Aug. 18, 2024, 4:19 p.m. UTC | #14
On 18.08.24 18:16, Andrew Lunn wrote:
>> Thanks that's good to know.
>>
>>>> So i have to wounder if you are solving this at the correct
>>>> level. This should be generic to any device, so the Rust concept of a
>>>> device should be stating these guarantees, not each specific type of
>>>> device.
>>>
>>> It should, why isn't it using the rust binding to Device that we already
>>> have:
>>> 	https://rust.docs.kernel.org/kernel/device/struct.Device.html
>>> or is it?  I'm confused now...
>>
>> It is using that one.
>> I wanted to verify that we can use that one, since using this
>> implementation users can freely increment the refcount of the device
>> (without decrementing it before control is given back to PHYLIB). Since
>> that seems to be the case, all is fine.
> 
> Any driver which is not using the device core is broken, and no amount
> of SAFETY is going to fix it.

This is what I did not know, and I asked to ensure that we don't
introduce miscommunication with the C side. (i.e. can we rely
in our SAFETY comments that devices are always used in this way)

---
Cheers,
Benno
diff mbox series

Patch

diff --git a/rust/kernel/net/phy.rs b/rust/kernel/net/phy.rs
index 5e8137a1972f..569dd3beef9c 100644
--- a/rust/kernel/net/phy.rs
+++ b/rust/kernel/net/phy.rs
@@ -7,8 +7,7 @@ 
 //! C headers: [`include/linux/phy.h`](srctree/include/linux/phy.h).
 
 use crate::{error::*, prelude::*, types::Opaque};
-
-use core::marker::PhantomData;
+use core::{marker::PhantomData, ptr::addr_of_mut};
 
 /// PHY state machine states.
 ///
@@ -302,6 +301,15 @@  pub fn genphy_read_abilities(&mut self) -> Result {
     }
 }
 
+impl AsRef<kernel::device::Device> for Device {
+    fn as_ref(&self) -> &kernel::device::Device {
+        let phydev = self.0.get();
+        // SAFETY: The struct invariant ensures that we may access
+        // this field without additional synchronization.
+        unsafe { kernel::device::Device::as_ref(addr_of_mut!((*phydev).mdio.dev)) }
+    }
+}
+
 /// Defines certain other features this PHY supports (like interrupts).
 ///
 /// These flag values are used in [`Driver::FLAGS`].