diff mbox series

[net-next,v7,2/5] rust: net::phy add module_phy_driver macro

Message ID 20231026001050.1720612-3-fujita.tomonori@gmail.com (mailing list archive)
State Changes Requested
Delegated to: Netdev Maintainers
Headers show
Series Rust abstractions for network PHY drivers | expand

Checks

Context Check Description
netdev/series_format success Posting correctly formatted
netdev/tree_selection success Clearly marked for net-next
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: 9 this patch: 9
netdev/cc_maintainers warning 6 maintainers not CCed: bjorn3_gh@protonmail.com alex.gaynor@gmail.com aliceryhl@google.com gary@garyguo.net a.hindborg@samsung.com boqun.feng@gmail.com
netdev/build_clang success Errors and warnings before: 9 this patch: 9
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: 9 this patch: 9
netdev/checkpatch warning WARNING: line length of 81 exceeds 80 columns WARNING: line length of 82 exceeds 80 columns WARNING: line length of 83 exceeds 80 columns WARNING: line length of 84 exceeds 80 columns WARNING: line length of 87 exceeds 80 columns WARNING: line length of 92 exceeds 80 columns WARNING: line length of 98 exceeds 80 columns WARNING: line length of 99 exceeds 80 columns
netdev/kdoc success Errors and warnings before: 0 this patch: 0
netdev/source_inline success Was 0 now: 0

Commit Message

FUJITA Tomonori Oct. 26, 2023, 12:10 a.m. UTC
This macro creates an array of kernel's `struct phy_driver` and
registers it. This also corresponds to the kernel's
`MODULE_DEVICE_TABLE` macro, which embeds the information for module
loading into the module binary file.

A PHY driver should use this macro.

Signed-off-by: FUJITA Tomonori <fujita.tomonori@gmail.com>
---
 rust/kernel/net/phy.rs | 143 +++++++++++++++++++++++++++++++++++++++++
 1 file changed, 143 insertions(+)

Comments

Alice Ryhl Nov. 17, 2023, 9:39 a.m. UTC | #1
FUJITA Tomonori <fujita.tomonori@gmail.com> writes:
> This macro creates an array of kernel's `struct phy_driver` and
> registers it. This also corresponds to the kernel's
> `MODULE_DEVICE_TABLE` macro, which embeds the information for module
> loading into the module binary file.
> 
> A PHY driver should use this macro.
> 
> Signed-off-by: FUJITA Tomonori <fujita.tomonori@gmail.com>

Reviewed-by: Alice Ryhl <aliceryhl@google.com>

A few minor nits:

> +    (drivers: [$($driver:ident),+], device_table: [$($dev:expr),+], $($f:tt)*) => {

Here, you can add $(,)? to allow trailing commas when the macro is used.
Like this:

(drivers: [$($driver:ident),+ $(,)?], device_table: [$($dev:expr),+ $(,)?], $($f:tt)*) => {


> +            ::kernel::bindings::mdio_device_id {

Here, I recommend `$crate` instead of `::kernel`.


> +/// #[no_mangle]
> +/// static __mod_mdio__phydev_device_table: [::kernel::bindings::mdio_device_id; 2] = [
> +///     ::kernel::bindings::mdio_device_id {
> +///         phy_id: 0x003b1861,
> +///         phy_id_mask: 0xffffffff,
> +///     },
> +///     ::kernel::bindings::mdio_device_id {
> +///         phy_id: 0,
> +///         phy_id_mask: 0,
> +///     },
> +/// ];

I'd probably put a safety comment on the `#[no_mangle]` invocation to say that
"C will not read off the end of this constant since the last element is zero".

Alice
Boqun Feng Nov. 17, 2023, 10:21 p.m. UTC | #2
On Thu, Oct 26, 2023 at 09:10:47AM +0900, FUJITA Tomonori wrote:
[...]
> +
> +/// Declares a kernel module for PHYs drivers.
> +///
> +/// This creates a static array of kernel's `struct phy_driver` and registers it.
> +/// This also corresponds to the kernel's `MODULE_DEVICE_TABLE` macro, which embeds the information
> +/// for module loading into the module binary file. Every driver needs an entry in `device_table`.
> +///
> +/// # Examples
> +///
> +/// ```
> +/// # mod module_phy_driver_sample {
> +/// use kernel::c_str;
> +/// use kernel::net::phy::{self, DeviceId};
> +/// use kernel::prelude::*;
> +///
> +/// kernel::module_phy_driver! {
> +///     drivers: [PhyAX88772A],
> +///     device_table: [
> +///         DeviceId::new_with_driver::<PhyAX88772A>()
> +///     ],
> +///     name: "rust_asix_phy",
> +///     author: "Rust for Linux Contributors",
> +///     description: "Rust Asix PHYs driver",
> +///     license: "GPL",
> +/// }
> +///
> +/// struct PhyAX88772A;
> +///
> +/// #[vtable]
> +/// impl phy::Driver for PhyAX88772A {
> +///     const NAME: &'static CStr = c_str!("Asix Electronics AX88772A");
> +///     const PHY_DEVICE_ID: phy::DeviceId = phy::DeviceId::new_with_exact_mask(0x003b1861);
> +/// }
> +/// # }
> +/// ```

When run the following kunit command:

./tools/testing/kunit/kunit.py run --make_options LLVM=1 --arch x86_64 \
	--kconfig_add CONFIG_RUST=y \
	--kconfig_add CONFIG_RUST_PHYLIB_ABSTRACTIONS=y \
	--kconfig_add CONFIG_PHYLIB=y \
	--kconfig_add CONFIG_NETDEVICES=y \
	--kconfig_add CONFIG_NET=y \
	--kconfig_add CONFIG_AX88796B_RUST_PHY=y \
	--kconfig_add CONFIG_AX88796B_PHY=y

I got the following errors:

	ERROR:root:ld.lld: error: duplicate symbol: __rust_asix_phy_init
	>>> defined at doctests_kernel_generated.5ed8fd29a53cf22f-cgu.0
	>>>            rust/doctests_kernel_generated.o:(__rust_asix_phy_init) in archive vmlinux.a
	>>> defined at ax88796b_rust.37fb93aefca595fa-cgu.0
	>>>            drivers/net/phy/ax88796b_rust.o:(.text+0x160) in archive vmlinux.a

	ld.lld: error: duplicate symbol: __rust_asix_phy_exit
	>>> defined at doctests_kernel_generated.5ed8fd29a53cf22f-cgu.0
	>>>            rust/doctests_kernel_generated.o:(__rust_asix_phy_exit) in archive vmlinux.a
	>>> defined at ax88796b_rust.37fb93aefca595fa-cgu.0
	>>>            drivers/net/phy/ax88796b_rust.o:(.text+0x1E0) in archive vmlinux.a

	ld.lld: error: duplicate symbol: __mod_mdio__phydev_device_table
	>>> defined at doctests_kernel_generated.5ed8fd29a53cf22f-cgu.0
	>>>            rust/doctests_kernel_generated.o:(__mod_mdio__phydev_device_table) in archive vmlinux.a
	>>> defined at ax88796b_rust.37fb93aefca595fa-cgu.0
	>>>            drivers/net/phy/ax88796b_rust.o:(.rodata+0x58) in archive vmlinux.a

Because kunit will use the above doc test to generate test, and since
CONFIG_AX88796B_RUST_PHY is also selected, the `module_phy_driver!` has
been called twice, and causes duplicate symbols.

For "rust_asix_phy_*" symbols, it's easy to fix: just rename the usage
in the example. But for __mod_mdio__phydev_device_table, it's hard-coded
in `module_phy_driver!`, I don't have a quick fix right now. Also, does
it mean `module_phy_driver!` is only supposed to be "called" once for
the entire kernel?

Regards,
Boqun
Andrew Lunn Nov. 17, 2023, 10:54 p.m. UTC | #3
On Fri, Nov 17, 2023 at 02:21:38PM -0800, Boqun Feng wrote:
> On Thu, Oct 26, 2023 at 09:10:47AM +0900, FUJITA Tomonori wrote:
> [...]
> > +
> > +/// Declares a kernel module for PHYs drivers.
> > +///
> > +/// This creates a static array of kernel's `struct phy_driver` and registers it.
> > +/// This also corresponds to the kernel's `MODULE_DEVICE_TABLE` macro, which embeds the information
> > +/// for module loading into the module binary file. Every driver needs an entry in `device_table`.
> > +///
> > +/// # Examples
> > +///
> > +/// ```
> > +/// # mod module_phy_driver_sample {
> > +/// use kernel::c_str;
> > +/// use kernel::net::phy::{self, DeviceId};
> > +/// use kernel::prelude::*;
> > +///
> > +/// kernel::module_phy_driver! {
> > +///     drivers: [PhyAX88772A],
> > +///     device_table: [
> > +///         DeviceId::new_with_driver::<PhyAX88772A>()
> > +///     ],
> > +///     name: "rust_asix_phy",
> > +///     author: "Rust for Linux Contributors",
> > +///     description: "Rust Asix PHYs driver",
> > +///     license: "GPL",
> > +/// }
> > +///
> > +/// struct PhyAX88772A;
> > +///
> > +/// #[vtable]
> > +/// impl phy::Driver for PhyAX88772A {
> > +///     const NAME: &'static CStr = c_str!("Asix Electronics AX88772A");
> > +///     const PHY_DEVICE_ID: phy::DeviceId = phy::DeviceId::new_with_exact_mask(0x003b1861);
> > +/// }
> > +/// # }
> > +/// ```
> 
> When run the following kunit command:
> 
> ./tools/testing/kunit/kunit.py run --make_options LLVM=1 --arch x86_64 \
> 	--kconfig_add CONFIG_RUST=y \
> 	--kconfig_add CONFIG_RUST_PHYLIB_ABSTRACTIONS=y \
> 	--kconfig_add CONFIG_PHYLIB=y \
> 	--kconfig_add CONFIG_NETDEVICES=y \
> 	--kconfig_add CONFIG_NET=y \
> 	--kconfig_add CONFIG_AX88796B_RUST_PHY=y \
> 	--kconfig_add CONFIG_AX88796B_PHY=y
> 
> I got the following errors:
> 
> 	ERROR:root:ld.lld: error: duplicate symbol: __rust_asix_phy_init
> 	>>> defined at doctests_kernel_generated.5ed8fd29a53cf22f-cgu.0
> 	>>>            rust/doctests_kernel_generated.o:(__rust_asix_phy_init) in archive vmlinux.a
> 	>>> defined at ax88796b_rust.37fb93aefca595fa-cgu.0
> 	>>>            drivers/net/phy/ax88796b_rust.o:(.text+0x160) in archive vmlinux.a
> 
> 	ld.lld: error: duplicate symbol: __rust_asix_phy_exit
> 	>>> defined at doctests_kernel_generated.5ed8fd29a53cf22f-cgu.0
> 	>>>            rust/doctests_kernel_generated.o:(__rust_asix_phy_exit) in archive vmlinux.a
> 	>>> defined at ax88796b_rust.37fb93aefca595fa-cgu.0
> 	>>>            drivers/net/phy/ax88796b_rust.o:(.text+0x1E0) in archive vmlinux.a
> 
> 	ld.lld: error: duplicate symbol: __mod_mdio__phydev_device_table
> 	>>> defined at doctests_kernel_generated.5ed8fd29a53cf22f-cgu.0
> 	>>>            rust/doctests_kernel_generated.o:(__mod_mdio__phydev_device_table) in archive vmlinux.a
> 	>>> defined at ax88796b_rust.37fb93aefca595fa-cgu.0
> 	>>>            drivers/net/phy/ax88796b_rust.o:(.rodata+0x58) in archive vmlinux.a
> 
> Because kunit will use the above doc test to generate test, and since
> CONFIG_AX88796B_RUST_PHY is also selected, the `module_phy_driver!` has
> been called twice, and causes duplicate symbols.
> 
> For "rust_asix_phy_*" symbols, it's easy to fix: just rename the usage
> in the example. But for __mod_mdio__phydev_device_table, it's hard-coded
> in `module_phy_driver!`, I don't have a quick fix right now. Also, does
> it mean `module_phy_driver!` is only supposed to be "called" once for
> the entire kernel?

Each kernel module should be in its own symbol name space. The only
symbols which are visible outside of the module are those exported
using EXPORT_SYMBOL_GPL() or EXPORT_SYMBOL(). A PHY driver does not
export anything, in general.

Being built in also does not change this.

Neither drivers/net/phy/ax88796b_rust.o nor
rust/doctests_kernel_generated.o should have exported this symbol.

I've no idea how this actually works, i guess there are multiple
passes through the linker? Maybe once to resolve symbols across object
files within a module. Normal global symbols are then made local,
leaving only those exported with EXPORT_SYMBOL_GPL() or
EXPORT_SYMBOL()? A second pass through linker then links all the
exported symbols thorough the kernel?

	Andrew
Benno Lossin Nov. 17, 2023, 11:01 p.m. UTC | #4
On 11/17/23 23:54, Andrew Lunn wrote:
> Each kernel module should be in its own symbol name space. The only
> symbols which are visible outside of the module are those exported
> using EXPORT_SYMBOL_GPL() or EXPORT_SYMBOL(). A PHY driver does not
> export anything, in general.
> 
> Being built in also does not change this.
> 
> Neither drivers/net/phy/ax88796b_rust.o nor
> rust/doctests_kernel_generated.o should have exported this symbol.
> 
> I've no idea how this actually works, i guess there are multiple
> passes through the linker? Maybe once to resolve symbols across object
> files within a module. Normal global symbols are then made local,
> leaving only those exported with EXPORT_SYMBOL_GPL() or
> EXPORT_SYMBOL()? A second pass through linker then links all the
> exported symbols thorough the kernel?

I brought this issue up in [1], but I was a bit confused by your last
reply there, as I have no idea how the `EXPORT_SYMBOL` macros work.

IIRC on the Rust side all public items are automatically GPL exported.
But `#[no_mangle]` is probably a special case, since in userspace it
is usually used to do interop with C (and therefore the symbol is always
exported with the name not mangled).

One fix would be to make the name unique by using the type name supplied
in the macro.

[1]: https://lore.kernel.org/rust-for-linux/1aea7ddb-73b7-8228-161e-e2e4ff5bc98d@proton.me/
Andrew Lunn Nov. 17, 2023, 11:18 p.m. UTC | #5
On Fri, Nov 17, 2023 at 11:01:58PM +0000, Benno Lossin wrote:
> On 11/17/23 23:54, Andrew Lunn wrote:
> > Each kernel module should be in its own symbol name space. The only
> > symbols which are visible outside of the module are those exported
> > using EXPORT_SYMBOL_GPL() or EXPORT_SYMBOL(). A PHY driver does not
> > export anything, in general.
> > 
> > Being built in also does not change this.
> > 
> > Neither drivers/net/phy/ax88796b_rust.o nor
> > rust/doctests_kernel_generated.o should have exported this symbol.
> > 
> > I've no idea how this actually works, i guess there are multiple
> > passes through the linker? Maybe once to resolve symbols across object
> > files within a module. Normal global symbols are then made local,
> > leaving only those exported with EXPORT_SYMBOL_GPL() or
> > EXPORT_SYMBOL()? A second pass through linker then links all the
> > exported symbols thorough the kernel?
> 
> I brought this issue up in [1], but I was a bit confused by your last
> reply there, as I have no idea how the `EXPORT_SYMBOL` macros work.
> 
> IIRC on the Rust side all public items are automatically GPL exported.

So that sounds wrong to me. But as i said, i don't know how this
actually works.

In kernel C code, you effectively have three levels of symbol
visibility.

Anything static is not visible outside of the .o file.

Anything global within a module is visible across multiple compilation
units within that module, but not visible outside of the module.

Symbols marked with EXPORT_SYMBOL_GPL() or EXPORT_SYMBOL() are visible
through the entire kernel.

Device drivers generally don't have any EXPORT_SYMBOL* symbols. They
do however need to import symbols which are EXPORT_SYMBOL*.  Core
code, like phylib, has lots of EXPORT_SYMBOL*. You can also have
modules which are just libraries, and they use EXPORT_SYMBOL*. Other
modules will be linked to them.

> But `#[no_mangle]` is probably a special case, since in userspace it
> is usually used to do interop with C (and therefore the symbol is always
> exported with the name not mangled).

So you might need this for symbols which are EXPORT_SYMBOL*,
especially if they are going to be used by C code. If only other Rust
modules are going to use them, and the mangled name is predictable, i
suppose you could use the mangled name.

	Andrew
FUJITA Tomonori Nov. 19, 2023, 9:25 a.m. UTC | #6
On Fri, 17 Nov 2023 23:01:58 +0000
Benno Lossin <benno.lossin@proton.me> wrote:

> On 11/17/23 23:54, Andrew Lunn wrote:
>> Each kernel module should be in its own symbol name space. The only
>> symbols which are visible outside of the module are those exported
>> using EXPORT_SYMBOL_GPL() or EXPORT_SYMBOL(). A PHY driver does not
>> export anything, in general.
>> 
>> Being built in also does not change this.
>> 
>> Neither drivers/net/phy/ax88796b_rust.o nor
>> rust/doctests_kernel_generated.o should have exported this symbol.
>> 
>> I've no idea how this actually works, i guess there are multiple
>> passes through the linker? Maybe once to resolve symbols across object
>> files within a module. Normal global symbols are then made local,
>> leaving only those exported with EXPORT_SYMBOL_GPL() or
>> EXPORT_SYMBOL()? A second pass through linker then links all the
>> exported symbols thorough the kernel?
> 
> I brought this issue up in [1], but I was a bit confused by your last
> reply there, as I have no idea how the `EXPORT_SYMBOL` macros work.
> 
> IIRC on the Rust side all public items are automatically GPL exported.

Hmm, they are public but doesn't look like exported by EXPORT_SYMBOL()
or EXPORT_SYMBOL_GPL().


> But `#[no_mangle]` is probably a special case, since in userspace it
> is usually used to do interop with C (and therefore the symbol is always
> exported with the name not mangled).
> 
> One fix would be to make the name unique by using the type name supplied
> in the macro.
> 
> [1]: https://lore.kernel.org/rust-for-linux/1aea7ddb-73b7-8228-161e-e2e4ff5bc98d@proton.me/

I fixed this in a different way; declaring
__mod_mdio__phydev_device_table only when built as a module.

(@device_table [$($dev:expr),+]) => {
 +        #[cfg(MODULE)]
          #[no_mangle]
          static __mod_mdio__phydev_device_table: [::kernel::bindings::mdio_device_id;
              $crate::module_phy_driver!(@count_devices $($dev),+) + 1] = [

This is used for dynamic loading so when a phy driver is built-in, we
don't need this.

When a driver is built as a module, the user-space tool converts this
into moduole alias information. This __mod_mdio__phydev_device_table
isn't loaded into kernel so no conflict even when multiple phy drivers
are loaded.
FUJITA Tomonori Nov. 19, 2023, 9:41 a.m. UTC | #7
On Sat, 18 Nov 2023 00:18:10 +0100
Andrew Lunn <andrew@lunn.ch> wrote:

>> But `#[no_mangle]` is probably a special case, since in userspace it
>> is usually used to do interop with C (and therefore the symbol is always
>> exported with the name not mangled).
> 
> So you might need this for symbols which are EXPORT_SYMBOL*,
> especially if they are going to be used by C code. If only other Rust
> modules are going to use them, and the mangled name is predictable, i
> suppose you could use the mangled name.

This isn't loaded into the kernel. This is used only by the tool to
build a module. When built as a module, this information is converted
into module alias information for dynamic loading.
FUJITA Tomonori Nov. 19, 2023, 9:44 a.m. UTC | #8
On Fri, 17 Nov 2023 14:21:38 -0800
Boqun Feng <boqun.feng@gmail.com> wrote:

> When run the following kunit command:
> 
> ./tools/testing/kunit/kunit.py run --make_options LLVM=1 --arch x86_64 \
> 	--kconfig_add CONFIG_RUST=y \
> 	--kconfig_add CONFIG_RUST_PHYLIB_ABSTRACTIONS=y \
> 	--kconfig_add CONFIG_PHYLIB=y \
> 	--kconfig_add CONFIG_NETDEVICES=y \
> 	--kconfig_add CONFIG_NET=y \
> 	--kconfig_add CONFIG_AX88796B_RUST_PHY=y \
> 	--kconfig_add CONFIG_AX88796B_PHY=y
> 
> I got the following errors:
> 
> 	ERROR:root:ld.lld: error: duplicate symbol: __rust_asix_phy_init
> 	>>> defined at doctests_kernel_generated.5ed8fd29a53cf22f-cgu.0
> 	>>>            rust/doctests_kernel_generated.o:(__rust_asix_phy_init) in archive vmlinux.a
> 	>>> defined at ax88796b_rust.37fb93aefca595fa-cgu.0
> 	>>>            drivers/net/phy/ax88796b_rust.o:(.text+0x160) in archive vmlinux.a
> 
> 	ld.lld: error: duplicate symbol: __rust_asix_phy_exit
> 	>>> defined at doctests_kernel_generated.5ed8fd29a53cf22f-cgu.0
> 	>>>            rust/doctests_kernel_generated.o:(__rust_asix_phy_exit) in archive vmlinux.a
> 	>>> defined at ax88796b_rust.37fb93aefca595fa-cgu.0
> 	>>>            drivers/net/phy/ax88796b_rust.o:(.text+0x1E0) in archive vmlinux.a
> 
> 	ld.lld: error: duplicate symbol: __mod_mdio__phydev_device_table
> 	>>> defined at doctests_kernel_generated.5ed8fd29a53cf22f-cgu.0
> 	>>>            rust/doctests_kernel_generated.o:(__mod_mdio__phydev_device_table) in archive vmlinux.a
> 	>>> defined at ax88796b_rust.37fb93aefca595fa-cgu.0
> 	>>>            drivers/net/phy/ax88796b_rust.o:(.rodata+0x58) in archive vmlinux.a
> 
> Because kunit will use the above doc test to generate test, and since
> CONFIG_AX88796B_RUST_PHY is also selected, the `module_phy_driver!` has
> been called twice, and causes duplicate symbols.
> 
> For "rust_asix_phy_*" symbols, it's easy to fix: just rename the usage
> in the example.

Surely, done.

> But for __mod_mdio__phydev_device_table, it's hard-coded
> in `module_phy_driver!`, I don't have a quick fix right now. Also, does
> it mean `module_phy_driver!` is only supposed to be "called" once for
> the entire kernel?

As I wrote in another mail, I fixed this.
FUJITA Tomonori Nov. 19, 2023, 10:50 a.m. UTC | #9
On Fri, 17 Nov 2023 09:39:08 +0000
Alice Ryhl <aliceryhl@google.com> wrote:

> FUJITA Tomonori <fujita.tomonori@gmail.com> writes:
>> This macro creates an array of kernel's `struct phy_driver` and
>> registers it. This also corresponds to the kernel's
>> `MODULE_DEVICE_TABLE` macro, which embeds the information for module
>> loading into the module binary file.
>> 
>> A PHY driver should use this macro.
>> 
>> Signed-off-by: FUJITA Tomonori <fujita.tomonori@gmail.com>
> 
> Reviewed-by: Alice Ryhl <aliceryhl@google.com>
> 
> A few minor nits:
> 
>> +    (drivers: [$($driver:ident),+], device_table: [$($dev:expr),+], $($f:tt)*) => {
> 
> Here, you can add $(,)? to allow trailing commas when the macro is used.
> Like this:
> 
> (drivers: [$($driver:ident),+ $(,)?], device_table: [$($dev:expr),+ $(,)?], $($f:tt)*) => {

Updated.

> 
>> +            ::kernel::bindings::mdio_device_id {
> 
> Here, I recommend `$crate` instead of `::kernel`.

I copied the code that Benno wrote, IIRC. Either is fine by me. Why
`$crate` is better here?

Also better to replace other `::kernel` in this macro?


>> +/// #[no_mangle]
>> +/// static __mod_mdio__phydev_device_table: [::kernel::bindings::mdio_device_id; 2] = [
>> +///     ::kernel::bindings::mdio_device_id {
>> +///         phy_id: 0x003b1861,
>> +///         phy_id_mask: 0xffffffff,
>> +///     },
>> +///     ::kernel::bindings::mdio_device_id {
>> +///         phy_id: 0,
>> +///         phy_id_mask: 0,
>> +///     },
>> +/// ];
> 
> I'd probably put a safety comment on the `#[no_mangle]` invocation to say that
> "C will not read off the end of this constant since the last element is zero".

Added.

Thanks a lot!
Benno Lossin Nov. 19, 2023, 10:54 a.m. UTC | #10
On 19.11.23 11:50, FUJITA Tomonori wrote:
> On Fri, 17 Nov 2023 09:39:08 +0000
> Alice Ryhl <aliceryhl@google.com> wrote:
>> FUJITA Tomonori <fujita.tomonori@gmail.com> writes:
>>> +            ::kernel::bindings::mdio_device_id {
>>
>> Here, I recommend `$crate` instead of `::kernel`.
> 
> I copied the code that Benno wrote, IIRC. Either is fine by me. Why
> `$crate` is better here?

When I suggested that, I might have confused the location of the macro
being in the `macros` crate. There you cannot use `$crate`, since it
is not available for proc macros. But since this is in the `kernel`
crate, you can use `$crate`.

`$crate` is better, since it unambiguously refers to the current crate
and `::kernel` only works, because we named our crate `kernel`. So the
code using `$crate` is more portable.

> Also better to replace other `::kernel` in this macro?

Yes.
Andrew Lunn Nov. 19, 2023, 3:50 p.m. UTC | #11
On Sun, Nov 19, 2023 at 06:25:44PM +0900, FUJITA Tomonori wrote:
> On Fri, 17 Nov 2023 23:01:58 +0000
> Benno Lossin <benno.lossin@proton.me> wrote:
> 
> > On 11/17/23 23:54, Andrew Lunn wrote:
> >> Each kernel module should be in its own symbol name space. The only
> >> symbols which are visible outside of the module are those exported
> >> using EXPORT_SYMBOL_GPL() or EXPORT_SYMBOL(). A PHY driver does not
> >> export anything, in general.
> >> 
> >> Being built in also does not change this.
> >> 
> >> Neither drivers/net/phy/ax88796b_rust.o nor
> >> rust/doctests_kernel_generated.o should have exported this symbol.
> >> 
> >> I've no idea how this actually works, i guess there are multiple
> >> passes through the linker? Maybe once to resolve symbols across object
> >> files within a module. Normal global symbols are then made local,
> >> leaving only those exported with EXPORT_SYMBOL_GPL() or
> >> EXPORT_SYMBOL()? A second pass through linker then links all the
> >> exported symbols thorough the kernel?
> > 
> > I brought this issue up in [1], but I was a bit confused by your last
> > reply there, as I have no idea how the `EXPORT_SYMBOL` macros work.
> > 
> > IIRC on the Rust side all public items are automatically GPL exported.
> 
> Hmm, they are public but doesn't look like exported by EXPORT_SYMBOL()
> or EXPORT_SYMBOL_GPL().

Do they need to be public? Generally, a PHY driver does not export
anything. So you can probably make them private. We just however need
to ensure the compiler/linker does not think they are unused, so
throws them away.

I would however like to get an understanding how EXPORT_SYMBOL* is
supposed to work in rust. Can it really be hidden away? Or should
methods be explicitly marked like C code? What is the Rust equivalent
of the three levels of symbol scope we have in C?

	Andrew
FUJITA Tomonori Nov. 20, 2023, 1:54 p.m. UTC | #12
On Sun, 19 Nov 2023 16:50:34 +0100
Andrew Lunn <andrew@lunn.ch> wrote:

> On Sun, Nov 19, 2023 at 06:25:44PM +0900, FUJITA Tomonori wrote:
>> On Fri, 17 Nov 2023 23:01:58 +0000
>> Benno Lossin <benno.lossin@proton.me> wrote:
>> 
>> > On 11/17/23 23:54, Andrew Lunn wrote:
>> >> Each kernel module should be in its own symbol name space. The only
>> >> symbols which are visible outside of the module are those exported
>> >> using EXPORT_SYMBOL_GPL() or EXPORT_SYMBOL(). A PHY driver does not
>> >> export anything, in general.
>> >> 
>> >> Being built in also does not change this.
>> >> 
>> >> Neither drivers/net/phy/ax88796b_rust.o nor
>> >> rust/doctests_kernel_generated.o should have exported this symbol.
>> >> 
>> >> I've no idea how this actually works, i guess there are multiple
>> >> passes through the linker? Maybe once to resolve symbols across object
>> >> files within a module. Normal global symbols are then made local,
>> >> leaving only those exported with EXPORT_SYMBOL_GPL() or
>> >> EXPORT_SYMBOL()? A second pass through linker then links all the
>> >> exported symbols thorough the kernel?
>> > 
>> > I brought this issue up in [1], but I was a bit confused by your last
>> > reply there, as I have no idea how the `EXPORT_SYMBOL` macros work.
>> > 
>> > IIRC on the Rust side all public items are automatically GPL exported.
>> 
>> Hmm, they are public but doesn't look like exported by EXPORT_SYMBOL()
>> or EXPORT_SYMBOL_GPL().
> 
> Do they need to be public? Generally, a PHY driver does not export
> anything. So you can probably make them private. We just however need
> to ensure the compiler/linker does not think they are unused, so
> throws them away.

The Rust ax88796b driver doesn't export anything. The Rust and C
drivers handle the device_table in the same way when they are built as
a module.

$ grep __mod_mdio /proc/kallsyms
ffffffffa0358058 r __mod_mdio__phydev_device_table [ax88796b_rust]

$ grep __mod_mdio /proc/kallsyms
ffffffffa0288010 d __mod_mdio__asix_tbl_device_table	[ax88796b]

Note that when the Rust ax88796b driver is built-in,
__mod_mdio__phydev_device_table is not defined.

Sorry about my explanation, which leads to the confusion, I think.


> I would however like to get an understanding how EXPORT_SYMBOL* is
> supposed to work in rust. Can it really be hidden away? Or should
> methods be explicitly marked like C code? What is the Rust equivalent
> of the three levels of symbol scope we have in C?

If I understand correctly, there is no official way to export symbols
in Rust kernel modules; No equivalent to EXPORT_SYMBOL* for Rust code
built as a module yet.

Note that all core Rust functions are GPL exported so they are
available to Rust kernel modules.

`static` has a different meaning in Rust but I think that you can use
file scope and kernel-module scope in Rust.
Andrew Lunn Nov. 20, 2023, 2:13 p.m. UTC | #13
> The Rust ax88796b driver doesn't export anything. The Rust and C
> drivers handle the device_table in the same way when they are built as
> a module.
> 
> $ grep __mod_mdio /proc/kallsyms
> ffffffffa0358058 r __mod_mdio__phydev_device_table [ax88796b_rust]
> 
> $ grep __mod_mdio /proc/kallsyms
> ffffffffa0288010 d __mod_mdio__asix_tbl_device_table	[ax88796b]

I checked what r and d mean. If they are upper case, they are
exported. Lower case means they are not exported.

My laptop is using the realtek PHY driver:

0000000000000000 r __mod_mdio__realtek_tbl_device_table	[realtek]

Also lower r.

Looking at all the symbols for the realtek driver, all the symbols use
lower case. Nothing is exported.

Is that what you see for the ax88796b_rust?

	Andrew
FUJITA Tomonori Nov. 21, 2023, 12:49 a.m. UTC | #14
On Mon, 20 Nov 2023 15:13:23 +0100
Andrew Lunn <andrew@lunn.ch> wrote:

>> The Rust ax88796b driver doesn't export anything. The Rust and C
>> drivers handle the device_table in the same way when they are built as
>> a module.
>> 
>> $ grep __mod_mdio /proc/kallsyms
>> ffffffffa0358058 r __mod_mdio__phydev_device_table [ax88796b_rust]
>> 
>> $ grep __mod_mdio /proc/kallsyms
>> ffffffffa0288010 d __mod_mdio__asix_tbl_device_table	[ax88796b]
> 
> I checked what r and d mean. If they are upper case, they are
> exported. Lower case means they are not exported.
> 
> My laptop is using the realtek PHY driver:
> 
> 0000000000000000 r __mod_mdio__realtek_tbl_device_table	[realtek]
> 
> Also lower r.
> 
> Looking at all the symbols for the realtek driver, all the symbols use
> lower case. Nothing is exported.
> 
> Is that what you see for the ax88796b_rust?

Yes, all the symbols for ax88796b_rust use lower case.
diff mbox series

Patch

diff --git a/rust/kernel/net/phy.rs b/rust/kernel/net/phy.rs
index 61223f638bc6..145d0407fe31 100644
--- a/rust/kernel/net/phy.rs
+++ b/rust/kernel/net/phy.rs
@@ -723,3 +723,146 @@  const fn as_int(&self) -> u32 {
         }
     }
 }
+
+/// Declares a kernel module for PHYs drivers.
+///
+/// This creates a static array of kernel's `struct phy_driver` and registers it.
+/// This also corresponds to the kernel's `MODULE_DEVICE_TABLE` macro, which embeds the information
+/// for module loading into the module binary file. Every driver needs an entry in `device_table`.
+///
+/// # Examples
+///
+/// ```
+/// # mod module_phy_driver_sample {
+/// use kernel::c_str;
+/// use kernel::net::phy::{self, DeviceId};
+/// use kernel::prelude::*;
+///
+/// kernel::module_phy_driver! {
+///     drivers: [PhyAX88772A],
+///     device_table: [
+///         DeviceId::new_with_driver::<PhyAX88772A>()
+///     ],
+///     name: "rust_asix_phy",
+///     author: "Rust for Linux Contributors",
+///     description: "Rust Asix PHYs driver",
+///     license: "GPL",
+/// }
+///
+/// struct PhyAX88772A;
+///
+/// #[vtable]
+/// impl phy::Driver for PhyAX88772A {
+///     const NAME: &'static CStr = c_str!("Asix Electronics AX88772A");
+///     const PHY_DEVICE_ID: phy::DeviceId = phy::DeviceId::new_with_exact_mask(0x003b1861);
+/// }
+/// # }
+/// ```
+///
+/// This expands to the following code:
+///
+/// ```ignore
+/// use kernel::c_str;
+/// use kernel::net::phy::{self, DeviceId};
+/// use kernel::prelude::*;
+///
+/// struct Module {
+///     _reg: ::kernel::net::phy::Registration,
+/// }
+///
+/// module! {
+///     type: Module,
+///     name: "rust_asix_phy",
+///     author: "Rust for Linux Contributors",
+///     description: "Rust Asix PHYs driver",
+///     license: "GPL",
+/// }
+///
+/// struct PhyAX88772A;
+///
+/// #[vtable]
+/// impl phy::Driver for PhyAX88772A {
+///     const NAME: &'static CStr = c_str!("Asix Electronics AX88772A");
+///     const PHY_DEVICE_ID: phy::DeviceId = phy::DeviceId::new_with_exact_mask(0x003b1861);
+/// }
+///
+/// const _: () = {
+///     static mut DRIVERS: [::kernel::net::phy::DriverVTable; 1] =
+///         [::kernel::net::phy::create_phy_driver::<PhyAX88772A>()];
+///
+///     impl ::kernel::Module for Module {
+///         fn init(module: &'static ThisModule) -> Result<Self> {
+///             let drivers = unsafe { &mut DRIVERS };
+///             let mut reg = ::kernel::net::phy::Registration::register(
+///                 module,
+///                 ::core::pin::Pin::static_mut(drivers),
+///             )?;
+///             Ok(Module { _reg: reg })
+///         }
+///     }
+/// };
+///
+/// #[no_mangle]
+/// static __mod_mdio__phydev_device_table: [::kernel::bindings::mdio_device_id; 2] = [
+///     ::kernel::bindings::mdio_device_id {
+///         phy_id: 0x003b1861,
+///         phy_id_mask: 0xffffffff,
+///     },
+///     ::kernel::bindings::mdio_device_id {
+///         phy_id: 0,
+///         phy_id_mask: 0,
+///     },
+/// ];
+/// ```
+#[macro_export]
+macro_rules! module_phy_driver {
+    (@replace_expr $_t:tt $sub:expr) => {$sub};
+
+    (@count_devices $($x:expr),*) => {
+        0usize $(+ $crate::module_phy_driver!(@replace_expr $x 1usize))*
+    };
+
+    (@device_table [$($dev:expr),+]) => {
+        #[no_mangle]
+        static __mod_mdio__phydev_device_table: [::kernel::bindings::mdio_device_id;
+            $crate::module_phy_driver!(@count_devices $($dev),+) + 1] = [
+            $($dev.mdio_device_id()),+,
+            ::kernel::bindings::mdio_device_id {
+                phy_id: 0,
+                phy_id_mask: 0
+            }
+        ];
+    };
+
+    (drivers: [$($driver:ident),+], device_table: [$($dev:expr),+], $($f:tt)*) => {
+        struct Module {
+            _reg: ::kernel::net::phy::Registration,
+        }
+
+        $crate::prelude::module! {
+            type: Module,
+            $($f)*
+        }
+
+        const _: () = {
+            static mut DRIVERS: [::kernel::net::phy::DriverVTable;
+                $crate::module_phy_driver!(@count_devices $($driver),+)] =
+                [$(::kernel::net::phy::create_phy_driver::<$driver>()),+];
+
+            impl ::kernel::Module for Module {
+                fn init(module: &'static ThisModule) -> Result<Self> {
+                    // SAFETY: The anonymous constant guarantees that nobody else can access
+                    // the `DRIVERS` static. The array is used only in the C side.
+                    let drivers = unsafe { &mut DRIVERS };
+                    let mut reg = ::kernel::net::phy::Registration::register(
+                        module,
+                        ::core::pin::Pin::static_mut(drivers),
+                    )?;
+                    Ok(Module { _reg: reg })
+                }
+            }
+        };
+
+        $crate::module_phy_driver!(@device_table [$($dev),+]);
+    }
+}