rust-for-linux.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: Benno Lossin <benno.lossin@proton.me>
To: FUJITA Tomonori <fujita.tomonori@gmail.com>
Cc: netdev@vger.kernel.org, rust-for-linux@vger.kernel.org,
	andrew@lunn.ch, miguel.ojeda.sandonis@gmail.com,
	tmgross@umich.edu, boqun.feng@gmail.com, wedsonaf@gmail.com,
	greg@kroah.com
Subject: Re: [PATCH net-next v5 1/5] rust: core abstractions for network PHY drivers
Date: Thu, 19 Oct 2023 13:45:27 +0000	[thread overview]
Message-ID: <0e8d2538-284b-4811-a2e7-99151338c255@proton.me> (raw)
In-Reply-To: <20231019.092436.1433321157817125498.fujita.tomonori@gmail.com>

On 19.10.23 02:24, FUJITA Tomonori wrote:
> On Wed, 18 Oct 2023 15:07:52 +0000
> Benno Lossin <benno.lossin@proton.me> wrote:
> 
>>> diff --git a/rust/kernel/net/phy.rs b/rust/kernel/net/phy.rs
>>> new file mode 100644
>>> index 000000000000..7d4927ece32f
>>> --- /dev/null
>>> +++ b/rust/kernel/net/phy.rs
>>> @@ -0,0 +1,701 @@
>>> +// SPDX-License-Identifier: GPL-2.0
>>> +
>>> +// Copyright (C) 2023 FUJITA Tomonori <fujita.tomonori@gmail.com>
>>> +
>>> +//! Network PHY device.
>>> +//!
>>> +//! C headers: [`include/linux/phy.h`](../../../../include/linux/phy.h).
>>> +//!
>>
>> Add a new section "# Abstraction Overview" or similar.
> 
> With the rest of comments on this secsion addressed, how about the following?
> 
> //! Network PHY device.
> //!
> //! C headers: [`include/linux/phy.h`](../../../../include/linux/phy.h).
> //!
> //! # Abstraction Overview
> //!
> //! "During the calls to most functions in [`Driver`], the C side (`PHYLIB`) holds a lock that is unique

Please remove the quotes ", they were intended to separate my comments
from my suggestion.

> //! for every instance of [`Device`]". `PHYLIB` uses a different serialization technique for
> //! [`Driver::resume`] and [`Driver::suspend`]: `PHYLIB` updates `phy_device`'s state with the lock hold,

hold -> held

> //! to guarantee that [`Driver::resume`] accesses to the instance exclusively. [`Driver::resume`] and

to guarantee -> thus guaranteeing
accesses to the instance exclusively. -> has exclusive access to the instance.

> //! [`Driver::suspend`] also are called where only one thread can access to the instance.
> //!
> //! All the PHYLIB helper functions for [`Device`] modify some members in [`Device`]. Except for

PHYLIB -> `PHYLIB`

> //! getter functions, [`Device`] methods take `&mut self`. This also applied to `[Device::read]`,

`[Device::read]` -> [`Device::read`]

> //! which reads a hardware register and updates the stats.

Otherwise this looks good.

[...]

>>> +impl Device {
>>> +    /// Creates a new [`Device`] instance from a raw pointer.
>>> +    ///
>>> +    /// # Safety
>>> +    ///
>>> +    /// This function must only be called from the callbacks in `phy_driver`. PHYLIB guarantees
>>> +    /// the exclusive access for the duration of the lifetime `'a`.
>>
>> I would not put the second sentence in the `# Safety` section. Just move it
>> above. The reason behind this is the following: the second sentence is not
>> a precondition needed to call the function.
> 
> Where is the `above`? You meant the following?
> 
> impl Device {
>      /// Creates a new [`Device`] instance from a raw pointer.
>      ///
>      /// `PHYLIB` guarantees the exclusive access for the duration of the lifetime `'a`.
>      ///
>      /// # Safety
>      ///
>      /// This function must only be called from the callbacks in `phy_driver`.
>      unsafe fn from_raw<'a>(ptr: *mut bindings::phy_device) -> &'a  mut Self {

Yes this is what I had in mind. Although now that I see it in code,
I am not so sure that this comment is needed. If you feel the same
way, just remove it.

That being said, I am not too happy with the safety requirement of this
function. It does not really match with the safety comment in the function
body. Since I have not yet finished my safety standardization, I think we
can defer that problem until it is finished. Unless some other reviewer
wants to change this, you can keep it as is.

>>> +    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>();
>>> +        // SAFETY: by the function requirements the pointer is valid and we have unique access for
>>> +        // the duration of `'a`.
>>> +        unsafe { &mut *ptr }
>>> +    }
>>> +
>>> +    /// Gets the id of the PHY.
>>> +    pub fn phy_id(&self) -> u32 {
>>> +        let phydev = self.0.get();
>>> +        // SAFETY: `phydev` is pointing to a valid object by the type invariant of `Self`.
>>> +        unsafe { (*phydev).phy_id }
>>> +    }
>>> +
>>> +    /// Gets the state of the PHY.
>>> +    pub fn state(&self) -> DeviceState {
>>> +        let phydev = self.0.get();
>>> +        // SAFETY: `phydev` is pointing to a valid object by the type invariant of `Self`.
>>> +        let state = unsafe { (*phydev).state };
>>> +        // TODO: this conversion code will be replaced with automatically generated code by bindgen
>>> +        // when it becomes possible.
>>> +        // better to call WARN_ONCE() when the state is out-of-range (needs to add WARN_ONCE support).
>>> +        match state {
>>> +            bindings::phy_state_PHY_DOWN => DeviceState::Down,
>>> +            bindings::phy_state_PHY_READY => DeviceState::Ready,
>>> +            bindings::phy_state_PHY_HALTED => DeviceState::Halted,
>>> +            bindings::phy_state_PHY_ERROR => DeviceState::Error,
>>> +            bindings::phy_state_PHY_UP => DeviceState::Up,
>>> +            bindings::phy_state_PHY_RUNNING => DeviceState::Running,
>>> +            bindings::phy_state_PHY_NOLINK => DeviceState::NoLink,
>>> +            bindings::phy_state_PHY_CABLETEST => DeviceState::CableTest,
>>> +            _ => DeviceState::Error,
>>> +        }
>>> +    }
>>> +
>>> +    /// Returns true if the link is up.
>>> +    pub fn get_link(&self) -> bool {
>>
>> I still think this name should be changed. My response at [1] has not yet
>> been replied to. This has already been discussed before:
>> - https://lore.kernel.org/rust-for-linux/2023100237-satirical-prance-bd57@gregkh/
>> - https://lore.kernel.org/rust-for-linux/20231004.084644.50784533959398755.fujita.tomonori@gmail.com/
>> - https://lore.kernel.org/rust-for-linux/CALNs47syMxiZBUwKLk3vKxzmCbX0FS5A37FjwUzZO9Fn-iPaoA@mail.gmail.com/
>>
>> And I want to suggest to change it to `is_link_up`.
>>
>> Reasons why I do not like the name:
>> - `get_`/`put_` are used for ref counting on the C side, I would like to
>>     avoid confusion.
>> - `get` in Rust is often used to fetch a value from e.g. a datastructure
>>     such as a hashmap, so I expect the call to do some computation.
>> - getters in Rust usually are not prefixed with `get_`, but rather are
>>     just the name of the field.
>> - in this case I like the name `is_link_up` much better, since code becomes
>>     a lot more readable with that.
>> - I do not want this pattern as an example for other drivers.
>>
>> [1]: https://lore.kernel.org/rust-for-linux/f5878806-5ba2-d932-858d-dda3f55ceb67@proton.me/
> 
> IIRC, Andrew suggested the current name. If the change is fine by him,
> I'll rename.
> 
> 
>>> +/// An instance of a PHY driver.
>>> +///
>>> +/// Wraps the kernel's `struct phy_driver`.
>>> +///
>>> +/// # Invariants
>>> +///
>>> +/// `self.0` is always in a valid state.
>>> +#[repr(transparent)]
>>> +pub struct DriverType(Opaque<bindings::phy_driver>);
>>
>> I think `DriverVTable` is a better name.
> 
> Renamed.
> 
>>> +/// Creates the kernel's `phy_driver` instance.
>>
>> This function returns a `DriverType`, not a `phy_driver`.
> 
> How about?
> 
> /// Creates the [`DriverVTable`] instance from [`Driver`] trait.

Sounds good, but to this sounds a bit more natural:

     /// Creates a [`DriverVTable`] instance from a [`Driver`].

>>> +///
>>> +/// This is used by [`module_phy_driver`] macro to create a static array of `phy_driver`.
>>> +///
>>> +/// [`module_phy_driver`]: crate::module_phy_driver
>>> +pub const fn create_phy_driver<T: Driver>() -> DriverType {
>>> +    // All the fields of `struct phy_driver` are initialized properly.
>>> +    // It ensures the invariants.
>>
>> Use `// INVARIANT: `.
> 
> Oops,
> 
> // INVARIANT: All the fields of `struct phy_driver` are initialized properly.
> DriverVTable(Opaque::new(bindings::phy_driver {
>      name: T::NAME.as_char_ptr().cast_mut(),

Seems good.

> 
> 
>>> +/// Registration structure for a PHY driver.
>>> +///
>>> +/// # Invariants
>>> +///
>>> +/// The `drivers` slice are currently registered to the kernel via `phy_drivers_register`.
>>> +pub struct Registration {
>>> +    drivers: &'static [DriverType],
>>> +}
>>
>> You did not reply to my suggestion [2] to remove this type,
>> what do you think?
>>
>> [2]: https://lore.kernel.org/rust-for-linux/85d5c498-efbc-4c1a-8d12-f1eca63c45cf@proton.me/
> 
> I tried before but I'm not sure it simplifies the implementation.
> 
> Firstly, instead of Reservation, we need a public function like
> 
> pub fn phy_drivers_register(module: &'static crate::ThisModule, drivers: &[DriverVTable]) -> Result {
>      to_result(unsafe {
>          bindings::phy_drivers_register(drivers[0].0.get(), drivers.len().try_into()?, module.0)
>      })
> }
> 
> This is because module.0 is private.

Why can't this be part of the macro?

> Also if we keep DriverVtable.0 private, we need another public function.
> 
> pub unsafe fn phy_drivers_unregister(drivers: &'static [DriverVTable])
> {
>      unsafe {
>          bindings::phy_drivers_unregister(drivers[0].0.get(), drivers.len() as i32)
>      };
> }
> 
> DriverVTable isn't guaranteed to be registered to the kernel so needs
> to be unsafe, I guesss.

In one of the options I suggest to make that an invariant of `DriverVTable`.

> 
> Also Module trait support exit()?

Yes, just implement `Drop` and do the cleanup there.

In the two options that I suggested there is a trade off. I do not know
which option is better, I hoped that you or Andrew would know more:
Option 1:
* advantages:
   - manual creation of a phy driver module becomes possible.
   - less complex `module_phy_driver` macro.
   - no static variable needed.
* disadvantages:
   - calls `phy_drivers_register` for every driver on module
     initialization.
   - calls `phy_drivers_unregister` for every driver on module
     exit.

Option 2:
* advantages:
   - less complex `module_phy_driver` macro.
   - no static variable needed.
   - only a single call to
     `phy_drivers_register`/`phy_drivers_unregister`.
* disadvantages:
   - no safe manual creation of phy drivers possible, the only safe
     way is to use the `module_phy_driver` macro.

I suppose that it would be ok to call the register function multiple
times, since it only is on module startup/shutdown and it is not
performance critical.

-- 
Cheers,
Benno



  reply	other threads:[~2023-10-19 13:45 UTC|newest]

Thread overview: 65+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2023-10-17 11:30 [PATCH net-next v5 0/5] Rust abstractions for network PHY drivers FUJITA Tomonori
2023-10-17 11:30 ` [PATCH net-next v5 1/5] rust: core " FUJITA Tomonori
2023-10-18 15:07   ` Benno Lossin
2023-10-19  0:24     ` FUJITA Tomonori
2023-10-19 13:45       ` Benno Lossin [this message]
2023-10-19 14:42         ` FUJITA Tomonori
2023-10-19 15:20           ` Benno Lossin
2023-10-19 15:32             ` FUJITA Tomonori
2023-10-19 16:37               ` Benno Lossin
2023-10-19 21:51                 ` FUJITA Tomonori
2023-10-21  7:21                   ` Benno Lossin
2023-10-20  0:34             ` FUJITA Tomonori
2023-10-20 12:54               ` FUJITA Tomonori
2023-10-21  7:25                 ` Benno Lossin
2023-10-21  7:30                   ` FUJITA Tomonori
2023-10-21  8:37                     ` Benno Lossin
2023-10-21 10:27                       ` FUJITA Tomonori
2023-10-21 11:21                         ` Benno Lossin
2023-10-21 11:36                           ` FUJITA Tomonori
2023-10-21 12:13                             ` Benno Lossin
2023-10-21 12:38                               ` FUJITA Tomonori
2023-10-21 12:50                                 ` Benno Lossin
2023-10-21 13:00                                   ` FUJITA Tomonori
2023-10-21 13:05                                     ` Benno Lossin
2023-10-21 13:31                                       ` FUJITA Tomonori
2023-10-21 13:35                                         ` Benno Lossin
2023-10-21 21:45                                           ` FUJITA Tomonori
2023-10-23  6:35                                             ` Benno Lossin
2023-10-23  6:37                                               ` Benno Lossin
2023-10-21 15:57                                       ` Andrew Lunn
2023-10-21 16:31                                         ` Benno Lossin
2023-10-21 15:41                             ` Andrew Lunn
2023-10-20 18:42     ` Andrew Lunn
2023-10-21  4:44       ` FUJITA Tomonori
2023-10-21  7:36       ` Benno Lossin
2023-10-21 12:47       ` Miguel Ojeda
2023-10-22  9:47         ` FUJITA Tomonori
2023-10-22 11:37           ` Miguel Ojeda
2023-10-22 15:34             ` Andrew Lunn
2023-10-24  1:37               ` FUJITA Tomonori
2023-10-24  8:48               ` Miguel Ojeda
2023-10-18 20:27   ` Andrew Lunn
2023-10-19  0:41     ` FUJITA Tomonori
2023-10-19 13:57       ` Benno Lossin
2023-10-20 19:50         ` Andrew Lunn
2023-10-21  8:01           ` Benno Lossin
2023-10-21 15:35             ` Andrew Lunn
2023-10-20 17:26   ` Andreas Hindborg (Samsung)
2023-10-20 17:56     ` Benno Lossin
2023-10-20 19:59     ` Andrew Lunn
2023-10-20 20:30       ` Andreas Hindborg (Samsung)
2023-10-21  3:49         ` FUJITA Tomonori
2023-10-21  4:01     ` FUJITA Tomonori
2023-10-17 11:30 ` [PATCH net-next v5 2/5] rust: net::phy add module_phy_driver macro FUJITA Tomonori
2023-10-17 11:30 ` [PATCH net-next v5 3/5] WIP rust: add second `bindgen` pass for enum exhaustiveness checking FUJITA Tomonori
2023-10-20 11:37   ` Andreas Hindborg (Samsung)
2023-10-20 12:34     ` Miguel Ojeda
2023-10-20 12:35       ` Miguel Ojeda
2023-10-23  8:57       ` Andreas Hindborg (Samsung)
2023-10-21  3:51     ` FUJITA Tomonori
2023-10-21 12:05       ` Miguel Ojeda
2023-10-22  6:30         ` FUJITA Tomonori
2023-10-23  8:58         ` Andreas Hindborg (Samsung)
2023-10-17 11:30 ` [PATCH net-next v5 4/5] MAINTAINERS: add Rust PHY abstractions for ETHERNET PHY LIBRARY FUJITA Tomonori
2023-10-17 11:30 ` [PATCH net-next v5 5/5] net: phy: add Rust Asix PHY driver FUJITA Tomonori

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=0e8d2538-284b-4811-a2e7-99151338c255@proton.me \
    --to=benno.lossin@proton.me \
    --cc=andrew@lunn.ch \
    --cc=boqun.feng@gmail.com \
    --cc=fujita.tomonori@gmail.com \
    --cc=greg@kroah.com \
    --cc=miguel.ojeda.sandonis@gmail.com \
    --cc=netdev@vger.kernel.org \
    --cc=rust-for-linux@vger.kernel.org \
    --cc=tmgross@umich.edu \
    --cc=wedsonaf@gmail.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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).