summaryrefslogtreecommitdiffstats
path: root/rust
diff options
context:
space:
mode:
Diffstat (limited to 'rust')
-rw-r--r--rust/Makefile9
-rw-r--r--rust/alloc/alloc.rs32
-rw-r--r--rust/alloc/lib.rs6
-rw-r--r--rust/alloc/slice.rs2
-rw-r--r--rust/alloc/vec/mod.rs87
-rw-r--r--rust/bindings/bindings_helper.h9
-rw-r--r--rust/bindings/lib.rs3
-rw-r--r--rust/exports.c2
-rw-r--r--rust/kernel/allocator.rs2
-rw-r--r--rust/kernel/error.rs6
-rw-r--r--rust/kernel/init.rs11
-rw-r--r--rust/kernel/ioctl.rs2
-rw-r--r--rust/kernel/kunit.rs2
-rw-r--r--rust/kernel/lib.rs5
-rw-r--r--rust/kernel/net.rs6
-rw-r--r--rust/kernel/net/phy.rs905
-rw-r--r--rust/kernel/print.rs8
-rw-r--r--rust/kernel/str.rs6
-rw-r--r--rust/kernel/sync/condvar.rs30
-rw-r--r--rust/kernel/sync/lock/mutex.rs2
-rw-r--r--rust/kernel/sync/lock/spinlock.rs2
-rw-r--r--rust/kernel/task.rs2
-rw-r--r--rust/kernel/workqueue.rs2
-rw-r--r--rust/macros/lib.rs74
-rw-r--r--rust/macros/paste.rs10
-rw-r--r--rust/uapi/uapi_helper.h2
26 files changed, 1150 insertions, 77 deletions
diff --git a/rust/Makefile b/rust/Makefile
index 543b37f6c7..cd9e5e3fce 100644
--- a/rust/Makefile
+++ b/rust/Makefile
@@ -78,6 +78,7 @@ quiet_cmd_rustdoc = RUSTDOC $(if $(rustdoc_host),H, ) $<
$(rustc_target_flags) -L$(objtree)/$(obj) \
--output $(rustdoc_output) \
--crate-name $(subst rustdoc-,,$@) \
+ $(if $(rustdoc_host),,--sysroot=/dev/null) \
@$(objtree)/include/generated/rustc_cfg $<
# The `html_logo_url` and `html_favicon_url` forms of the `doc` attribute
@@ -98,7 +99,8 @@ rustdoc: rustdoc-core rustdoc-macros rustdoc-compiler_builtins \
$(Q)find $(rustdoc_output) -name '*.html' -type f -print0 | xargs -0 sed -Ei \
-e 's:rust-logo-[0-9a-f]+\.svg:logo.svg:g' \
-e 's:favicon-[0-9a-f]+\.svg:logo.svg:g' \
- -e 's:<link rel="alternate icon" type="image/png" href="[/.]+/static\.files/favicon-(16x16|32x32)-[0-9a-f]+\.png">::g'
+ -e 's:<link rel="alternate icon" type="image/png" href="[/.]+/static\.files/favicon-(16x16|32x32)-[0-9a-f]+\.png">::g' \
+ -e 's:<a href="srctree/([^"]+)">:<a href="$(abs_srctree)/\1">:g'
$(Q)for f in $(rustdoc_output)/static.files/rustdoc-*.css; do \
echo ".logo-container > img { object-fit: contain; }" >> $$f; done
@@ -173,11 +175,11 @@ quiet_cmd_rustdoc_test_kernel = RUSTDOC TK $<
mkdir -p $(objtree)/$(obj)/test/doctests/kernel; \
OBJTREE=$(abspath $(objtree)) \
$(RUSTDOC) --test $(rust_flags) \
- @$(objtree)/include/generated/rustc_cfg \
-L$(objtree)/$(obj) --extern alloc --extern kernel \
--extern build_error --extern macros \
--extern bindings --extern uapi \
--no-run --crate-name kernel -Zunstable-options \
+ --sysroot=/dev/null \
--test-builder $(objtree)/scripts/rustdoc_test_builder \
$< $(rustdoc_test_kernel_quiet); \
$(objtree)/scripts/rustdoc_test_gen
@@ -337,6 +339,8 @@ quiet_cmd_bindgen = BINDGEN $@
$(obj)/bindings/bindings_generated.rs: private bindgen_target_flags = \
$(shell grep -Ev '^#|^$$' $(srctree)/$(src)/bindgen_parameters)
+$(obj)/bindings/bindings_generated.rs: private bindgen_target_extra = ; \
+ sed -Ei 's/pub const RUST_CONST_HELPER_([a-zA-Z0-9_]*)/pub const \1/g' $@
$(obj)/bindings/bindings_generated.rs: $(src)/bindings/bindings_helper.h \
$(src)/bindgen_parameters FORCE
$(call if_changed_dep,bindgen)
@@ -402,6 +406,7 @@ quiet_cmd_rustc_library = $(if $(skip_clippy),RUSTC,$(RUSTC_OR_CLIPPY_QUIET)) L
--emit=metadata=$(dir $@)$(patsubst %.o,lib%.rmeta,$(notdir $@)) \
--crate-type rlib -L$(objtree)/$(obj) \
--crate-name $(patsubst %.o,%,$(notdir $@)) $< \
+ --sysroot=/dev/null \
$(if $(rustc_objcopy),;$(OBJCOPY) $(rustc_objcopy) $@)
rust-analyzer:
diff --git a/rust/alloc/alloc.rs b/rust/alloc/alloc.rs
index 8cb4a31cf6..150e13750f 100644
--- a/rust/alloc/alloc.rs
+++ b/rust/alloc/alloc.rs
@@ -345,18 +345,31 @@ extern "Rust" {
fn __rust_alloc_error_handler(size: usize, align: usize) -> !;
}
-/// Abort on memory allocation error or failure.
+/// Signal a memory allocation error.
///
-/// Callers of memory allocation APIs wishing to abort computation
+/// Callers of memory allocation APIs wishing to cease execution
/// in response to an allocation error are encouraged to call this function,
-/// rather than directly invoking `panic!` or similar.
+/// rather than directly invoking [`panic!`] or similar.
///
-/// The default behavior of this function is to print a message to standard error
-/// and abort the process.
-/// It can be replaced with [`set_alloc_error_hook`] and [`take_alloc_error_hook`].
+/// This function is guaranteed to diverge (not return normally with a value), but depending on
+/// global configuration, it may either panic (resulting in unwinding or aborting as per
+/// configuration for all panics), or abort the process (with no unwinding).
+///
+/// The default behavior is:
+///
+/// * If the binary links against `std` (typically the case), then
+/// print a message to standard error and abort the process.
+/// This behavior can be replaced with [`set_alloc_error_hook`] and [`take_alloc_error_hook`].
+/// Future versions of Rust may panic by default instead.
+///
+/// * If the binary does not link against `std` (all of its crates are marked
+/// [`#![no_std]`][no_std]), then call [`panic!`] with a message.
+/// [The panic handler] applies as to any panic.
///
/// [`set_alloc_error_hook`]: ../../std/alloc/fn.set_alloc_error_hook.html
/// [`take_alloc_error_hook`]: ../../std/alloc/fn.take_alloc_error_hook.html
+/// [The panic handler]: https://doc.rust-lang.org/reference/runtime.html#the-panic_handler-attribute
+/// [no_std]: https://doc.rust-lang.org/reference/names/preludes.html#the-no_std-attribute
#[stable(feature = "global_alloc", since = "1.28.0")]
#[rustc_const_unstable(feature = "const_alloc_error", issue = "92523")]
#[cfg(all(not(no_global_oom_handling), not(test)))]
@@ -397,9 +410,10 @@ pub mod __alloc_error_handler {
if unsafe { __rust_alloc_error_handler_should_panic != 0 } {
panic!("memory allocation of {size} bytes failed")
} else {
- core::panicking::panic_nounwind_fmt(format_args!(
- "memory allocation of {size} bytes failed"
- ))
+ core::panicking::panic_nounwind_fmt(
+ format_args!("memory allocation of {size} bytes failed"),
+ /* force_no_backtrace */ false,
+ )
}
}
}
diff --git a/rust/alloc/lib.rs b/rust/alloc/lib.rs
index 73b9ffd845..9c7ea73da1 100644
--- a/rust/alloc/lib.rs
+++ b/rust/alloc/lib.rs
@@ -90,8 +90,8 @@
#![warn(missing_docs)]
#![allow(explicit_outlives_requirements)]
#![warn(multiple_supertrait_upcastable)]
-#![cfg_attr(not(bootstrap), allow(internal_features))]
-#![cfg_attr(not(bootstrap), allow(rustdoc::redundant_explicit_links))]
+#![allow(internal_features)]
+#![allow(rustdoc::redundant_explicit_links)]
//
// Library features:
// tidy-alphabetical-start
@@ -122,6 +122,7 @@
#![feature(const_waker)]
#![feature(core_intrinsics)]
#![feature(core_panic)]
+#![feature(deprecated_suggestion)]
#![feature(dispatch_from_dyn)]
#![feature(error_generic_member_access)]
#![feature(error_in_core)]
@@ -145,7 +146,6 @@
#![feature(ptr_metadata)]
#![feature(ptr_sub_ptr)]
#![feature(receiver_trait)]
-#![feature(saturating_int_impl)]
#![feature(set_ptr_value)]
#![feature(sized_type_properties)]
#![feature(slice_from_ptr_range)]
diff --git a/rust/alloc/slice.rs b/rust/alloc/slice.rs
index 6ac463bd3e..1181836da5 100644
--- a/rust/alloc/slice.rs
+++ b/rust/alloc/slice.rs
@@ -594,7 +594,7 @@ impl<T> [T] {
/// ```
#[rustc_allow_incoherent_impl]
#[stable(feature = "rust1", since = "1.0.0")]
- #[deprecated(since = "1.3.0", note = "renamed to join")]
+ #[deprecated(since = "1.3.0", note = "renamed to join", suggestion = "join")]
pub fn connect<Separator>(&self, sep: Separator) -> <Self as Join<Separator>>::Output
where
Self: Join<Separator>,
diff --git a/rust/alloc/vec/mod.rs b/rust/alloc/vec/mod.rs
index 209a88cfe5..41ca71805e 100644
--- a/rust/alloc/vec/mod.rs
+++ b/rust/alloc/vec/mod.rs
@@ -1228,8 +1228,8 @@ impl<T, A: Allocator> Vec<T, A> {
/// Shortens the vector, keeping the first `len` elements and dropping
/// the rest.
///
- /// If `len` is greater than the vector's current length, this has no
- /// effect.
+ /// If `len` is greater or equal to the vector's current length, this has
+ /// no effect.
///
/// The [`drain`] method can emulate `truncate`, but causes the excess
/// elements to be returned instead of dropped.
@@ -1336,6 +1336,15 @@ impl<T, A: Allocator> Vec<T, A> {
/// is never written to (except inside an `UnsafeCell`) using this pointer or any pointer
/// derived from it. If you need to mutate the contents of the slice, use [`as_mut_ptr`].
///
+ /// This method guarantees that for the purpose of the aliasing model, this method
+ /// does not materialize a reference to the underlying slice, and thus the returned pointer
+ /// will remain valid when mixed with other calls to [`as_ptr`] and [`as_mut_ptr`].
+ /// Note that calling other methods that materialize mutable references to the slice,
+ /// or mutable references to specific elements you are planning on accessing through this pointer,
+ /// as well as writing to those elements, may still invalidate this pointer.
+ /// See the second example below for how this guarantee can be used.
+ ///
+ ///
/// # Examples
///
/// ```
@@ -1349,8 +1358,25 @@ impl<T, A: Allocator> Vec<T, A> {
/// }
/// ```
///
+ /// Due to the aliasing guarantee, the following code is legal:
+ ///
+ /// ```rust
+ /// unsafe {
+ /// let mut v = vec![0, 1, 2];
+ /// let ptr1 = v.as_ptr();
+ /// let _ = ptr1.read();
+ /// let ptr2 = v.as_mut_ptr().offset(2);
+ /// ptr2.write(2);
+ /// // Notably, the write to `ptr2` did *not* invalidate `ptr1`
+ /// // because it mutated a different element:
+ /// let _ = ptr1.read();
+ /// }
+ /// ```
+ ///
/// [`as_mut_ptr`]: Vec::as_mut_ptr
+ /// [`as_ptr`]: Vec::as_ptr
#[stable(feature = "vec_as_ptr", since = "1.37.0")]
+ #[cfg_attr(not(bootstrap), rustc_never_returns_null_ptr)]
#[inline]
pub fn as_ptr(&self) -> *const T {
// We shadow the slice method of the same name to avoid going through
@@ -1366,6 +1392,15 @@ impl<T, A: Allocator> Vec<T, A> {
/// Modifying the vector may cause its buffer to be reallocated,
/// which would also make any pointers to it invalid.
///
+ /// This method guarantees that for the purpose of the aliasing model, this method
+ /// does not materialize a reference to the underlying slice, and thus the returned pointer
+ /// will remain valid when mixed with other calls to [`as_ptr`] and [`as_mut_ptr`].
+ /// Note that calling other methods that materialize references to the slice,
+ /// or references to specific elements you are planning on accessing through this pointer,
+ /// may still invalidate this pointer.
+ /// See the second example below for how this guarantee can be used.
+ ///
+ ///
/// # Examples
///
/// ```
@@ -1383,7 +1418,25 @@ impl<T, A: Allocator> Vec<T, A> {
/// }
/// assert_eq!(&*x, &[0, 1, 2, 3]);
/// ```
+ ///
+ /// Due to the aliasing guarantee, the following code is legal:
+ ///
+ /// ```rust
+ /// unsafe {
+ /// let mut v = vec![0];
+ /// let ptr1 = v.as_mut_ptr();
+ /// ptr1.write(1);
+ /// let ptr2 = v.as_mut_ptr();
+ /// ptr2.write(2);
+ /// // Notably, the write to `ptr2` did *not* invalidate `ptr1`:
+ /// ptr1.write(3);
+ /// }
+ /// ```
+ ///
+ /// [`as_mut_ptr`]: Vec::as_mut_ptr
+ /// [`as_ptr`]: Vec::as_ptr
#[stable(feature = "vec_as_ptr", since = "1.37.0")]
+ #[cfg_attr(not(bootstrap), rustc_never_returns_null_ptr)]
#[inline]
pub fn as_mut_ptr(&mut self) -> *mut T {
// We shadow the slice method of the same name to avoid going through
@@ -3404,6 +3457,36 @@ impl<T: Clone> From<&mut [T]> for Vec<T> {
}
#[cfg(not(no_global_oom_handling))]
+#[stable(feature = "vec_from_array_ref", since = "1.74.0")]
+impl<T: Clone, const N: usize> From<&[T; N]> for Vec<T> {
+ /// Allocate a `Vec<T>` and fill it by cloning `s`'s items.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// assert_eq!(Vec::from(&[1, 2, 3]), vec![1, 2, 3]);
+ /// ```
+ fn from(s: &[T; N]) -> Vec<T> {
+ Self::from(s.as_slice())
+ }
+}
+
+#[cfg(not(no_global_oom_handling))]
+#[stable(feature = "vec_from_array_ref", since = "1.74.0")]
+impl<T: Clone, const N: usize> From<&mut [T; N]> for Vec<T> {
+ /// Allocate a `Vec<T>` and fill it by cloning `s`'s items.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// assert_eq!(Vec::from(&mut [1, 2, 3]), vec![1, 2, 3]);
+ /// ```
+ fn from(s: &mut [T; N]) -> Vec<T> {
+ Self::from(s.as_mut_slice())
+ }
+}
+
+#[cfg(not(no_global_oom_handling))]
#[stable(feature = "vec_from_array", since = "1.44.0")]
impl<T, const N: usize> From<[T; N]> for Vec<T> {
/// Allocate a `Vec<T>` and move `s`'s items into it.
diff --git a/rust/bindings/bindings_helper.h b/rust/bindings/bindings_helper.h
index 85f013ed4c..c0cb4b05b9 100644
--- a/rust/bindings/bindings_helper.h
+++ b/rust/bindings/bindings_helper.h
@@ -8,6 +8,9 @@
#include <kunit/test.h>
#include <linux/errname.h>
+#include <linux/ethtool.h>
+#include <linux/mdio.h>
+#include <linux/phy.h>
#include <linux/slab.h>
#include <linux/refcount.h>
#include <linux/wait.h>
@@ -15,6 +18,6 @@
#include <linux/workqueue.h>
/* `bindgen` gets confused at certain things. */
-const size_t BINDINGS_ARCH_SLAB_MINALIGN = ARCH_SLAB_MINALIGN;
-const gfp_t BINDINGS_GFP_KERNEL = GFP_KERNEL;
-const gfp_t BINDINGS___GFP_ZERO = __GFP_ZERO;
+const size_t RUST_CONST_HELPER_ARCH_SLAB_MINALIGN = ARCH_SLAB_MINALIGN;
+const gfp_t RUST_CONST_HELPER_GFP_KERNEL = GFP_KERNEL;
+const gfp_t RUST_CONST_HELPER___GFP_ZERO = __GFP_ZERO;
diff --git a/rust/bindings/lib.rs b/rust/bindings/lib.rs
index 9bcbea04da..40ddaee50d 100644
--- a/rust/bindings/lib.rs
+++ b/rust/bindings/lib.rs
@@ -48,6 +48,3 @@ mod bindings_helper {
}
pub use bindings_raw::*;
-
-pub const GFP_KERNEL: gfp_t = BINDINGS_GFP_KERNEL;
-pub const __GFP_ZERO: gfp_t = BINDINGS___GFP_ZERO;
diff --git a/rust/exports.c b/rust/exports.c
index 83e2a7070c..3803c21d14 100644
--- a/rust/exports.c
+++ b/rust/exports.c
@@ -11,7 +11,7 @@
* accidentally exposed.
*/
-#include <linux/module.h>
+#include <linux/export.h>
#define EXPORT_SYMBOL_RUST_GPL(sym) extern int sym; EXPORT_SYMBOL_GPL(sym)
diff --git a/rust/kernel/allocator.rs b/rust/kernel/allocator.rs
index a8f3d5be1a..4b057e8373 100644
--- a/rust/kernel/allocator.rs
+++ b/rust/kernel/allocator.rs
@@ -21,7 +21,7 @@ unsafe fn krealloc_aligned(ptr: *mut u8, new_layout: Layout, flags: bindings::gf
let mut size = layout.size();
- if layout.align() > bindings::BINDINGS_ARCH_SLAB_MINALIGN {
+ if layout.align() > bindings::ARCH_SLAB_MINALIGN {
// The alignment requirement exceeds the slab guarantee, thus try to enlarge the size
// to use the "power-of-two" size/alignment guarantee (see comments in `kmalloc()` for
// more information).
diff --git a/rust/kernel/error.rs b/rust/kernel/error.rs
index 032b645439..4f0c1edd63 100644
--- a/rust/kernel/error.rs
+++ b/rust/kernel/error.rs
@@ -2,7 +2,7 @@
//! Kernel errors.
//!
-//! C header: [`include/uapi/asm-generic/errno-base.h`](../../../include/uapi/asm-generic/errno-base.h)
+//! C header: [`include/uapi/asm-generic/errno-base.h`](srctree/include/uapi/asm-generic/errno-base.h)
use crate::str::CStr;
@@ -335,3 +335,7 @@ where
Err(e) => T::from(e.to_errno() as i16),
}
}
+
+/// Error message for calling a default function of a [`#[vtable]`](macros::vtable) trait.
+pub const VTABLE_DEFAULT_ERROR: &str =
+ "This function must not be called, see the #[vtable] documentation.";
diff --git a/rust/kernel/init.rs b/rust/kernel/init.rs
index 65be9ae57b..cf9575f156 100644
--- a/rust/kernel/init.rs
+++ b/rust/kernel/init.rs
@@ -1292,8 +1292,15 @@ impl_zeroable! {
i8, i16, i32, i64, i128, isize,
f32, f64,
- // SAFETY: These are ZSTs, there is nothing to zero.
- {<T: ?Sized>} PhantomData<T>, core::marker::PhantomPinned, Infallible, (),
+ // Note: do not add uninhabited types (such as `!` or `core::convert::Infallible`) to this list;
+ // creating an instance of an uninhabited type is immediate undefined behavior. For more on
+ // uninhabited/empty types, consult The Rustonomicon:
+ // <https://doc.rust-lang.org/stable/nomicon/exotic-sizes.html#empty-types>. The Rust Reference
+ // also has information on undefined behavior:
+ // <https://doc.rust-lang.org/stable/reference/behavior-considered-undefined.html>.
+ //
+ // SAFETY: These are inhabited ZSTs; there is nothing to zero and a valid value exists.
+ {<T: ?Sized>} PhantomData<T>, core::marker::PhantomPinned, (),
// SAFETY: Type is allowed to take any value, including all zeros.
{<T>} MaybeUninit<T>,
diff --git a/rust/kernel/ioctl.rs b/rust/kernel/ioctl.rs
index c49e1a8d3f..f1d42ab699 100644
--- a/rust/kernel/ioctl.rs
+++ b/rust/kernel/ioctl.rs
@@ -2,7 +2,7 @@
//! ioctl() number definitions
//!
-//! C header: [`include/asm-generic/ioctl.h`](../../../../include/asm-generic/ioctl.h)
+//! C header: [`include/asm-generic/ioctl.h`](srctree/include/asm-generic/ioctl.h)
#![allow(non_snake_case)]
diff --git a/rust/kernel/kunit.rs b/rust/kernel/kunit.rs
index 722655b2d6..0ba77276ae 100644
--- a/rust/kernel/kunit.rs
+++ b/rust/kernel/kunit.rs
@@ -2,7 +2,7 @@
//! KUnit-based macros for Rust unit tests.
//!
-//! C header: [`include/kunit/test.h`](../../../../../include/kunit/test.h)
+//! C header: [`include/kunit/test.h`](srctree/include/kunit/test.h)
//!
//! Reference: <https://docs.kernel.org/dev-tools/kunit/index.html>
diff --git a/rust/kernel/lib.rs b/rust/kernel/lib.rs
index e6aff80b52..75efe47522 100644
--- a/rust/kernel/lib.rs
+++ b/rust/kernel/lib.rs
@@ -14,6 +14,7 @@
#![no_std]
#![feature(allocator_api)]
#![feature(coerce_unsized)]
+#![feature(const_maybe_uninit_zeroed)]
#![feature(dispatch_from_dyn)]
#![feature(new_uninit)]
#![feature(offset_of)]
@@ -38,6 +39,8 @@ pub mod init;
pub mod ioctl;
#[cfg(CONFIG_KUNIT)]
pub mod kunit;
+#[cfg(CONFIG_NET)]
+pub mod net;
pub mod prelude;
pub mod print;
mod static_assert;
@@ -63,7 +66,7 @@ const __LOG_PREFIX: &[u8] = b"rust_kernel\0";
/// The top level entrypoint to implementing a kernel module.
///
/// For any teardown or cleanup operations, your type may implement [`Drop`].
-pub trait Module: Sized + Sync {
+pub trait Module: Sized + Sync + Send {
/// Called at module initialization time.
///
/// Use this method to perform whatever setup or registration your module
diff --git a/rust/kernel/net.rs b/rust/kernel/net.rs
new file mode 100644
index 0000000000..fe415cb369
--- /dev/null
+++ b/rust/kernel/net.rs
@@ -0,0 +1,6 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Networking.
+
+#[cfg(CONFIG_RUST_PHYLIB_ABSTRACTIONS)]
+pub mod phy;
diff --git a/rust/kernel/net/phy.rs b/rust/kernel/net/phy.rs
new file mode 100644
index 0000000000..869797745b
--- /dev/null
+++ b/rust/kernel/net/phy.rs
@@ -0,0 +1,905 @@
+// 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).
+
+use crate::{bindings, error::*, prelude::*, str::CStr, types::Opaque};
+
+use core::marker::PhantomData;
+
+/// PHY state machine states.
+///
+/// Corresponds to the kernel's [`enum phy_state`].
+///
+/// Some of PHY drivers access to the state of PHY's software state machine.
+///
+/// [`enum phy_state`]: ../../../../../../../include/linux/phy.h
+#[derive(PartialEq, Eq)]
+pub enum DeviceState {
+ /// PHY device and driver are not ready for anything.
+ Down,
+ /// PHY is ready to send and receive packets.
+ Ready,
+ /// PHY is up, but no polling or interrupts are done.
+ Halted,
+ /// PHY is up, but is in an error state.
+ Error,
+ /// PHY and attached device are ready to do work.
+ Up,
+ /// PHY is currently running.
+ Running,
+ /// PHY is up, but not currently plugged in.
+ NoLink,
+ /// PHY is performing a cable test.
+ CableTest,
+}
+
+/// A mode of Ethernet communication.
+///
+/// PHY drivers get duplex information from hardware and update the current state.
+pub enum DuplexMode {
+ /// PHY is in full-duplex mode.
+ Full,
+ /// PHY is in half-duplex mode.
+ Half,
+ /// PHY is in unknown duplex mode.
+ Unknown,
+}
+
+/// An instance of a PHY device.
+///
+/// Wraps the kernel's [`struct phy_device`].
+///
+/// A [`Device`] instance is created when a callback in [`Driver`] is executed. A PHY driver
+/// executes [`Driver`]'s methods during the callback.
+///
+/// # 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.
+///
+/// [`struct phy_device`]: ../../../../../../../include/linux/phy.h
+// During the calls to most functions in [`Driver`], the C side (`PHYLIB`) holds a lock that is
+// unique 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 held, thus guaranteeing that [`Driver::resume`] has exclusive access to the instance.
+// [`Driver::resume`] and [`Driver::suspend`] also are called where only one thread can access
+// to the instance.
+#[repr(transparent)]
+pub struct Device(Opaque<bindings::phy_device>);
+
+impl Device {
+ /// Creates a new [`Device`] instance from a raw pointer.
+ ///
+ /// # 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.
+ 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: The struct invariant ensures that we may access
+ // this field without additional synchronization.
+ unsafe { (*phydev).phy_id }
+ }
+
+ /// Gets the state of PHY state machine states.
+ pub fn state(&self) -> DeviceState {
+ let phydev = self.0.get();
+ // SAFETY: The struct invariant ensures that we may access
+ // this field without additional synchronization.
+ let state = unsafe { (*phydev).state };
+ // TODO: this conversion code will be replaced with automatically generated code by bindgen
+ // when it becomes possible.
+ 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,
+ }
+ }
+
+ /// Gets the current link state.
+ ///
+ /// It returns true if the link is up.
+ pub fn is_link_up(&self) -> bool {
+ const LINK_IS_UP: u64 = 1;
+ // TODO: the code to access to the bit field will be replaced with automatically
+ // generated code by bindgen when it becomes possible.
+ // SAFETY: The struct invariant ensures that we may access
+ // this field without additional synchronization.
+ let bit_field = unsafe { &(*self.0.get())._bitfield_1 };
+ bit_field.get(14, 1) == LINK_IS_UP
+ }
+
+ /// Gets the current auto-negotiation configuration.
+ ///
+ /// It returns true if auto-negotiation is enabled.
+ pub fn is_autoneg_enabled(&self) -> bool {
+ // TODO: the code to access to the bit field will be replaced with automatically
+ // generated code by bindgen when it becomes possible.
+ // SAFETY: The struct invariant ensures that we may access
+ // this field without additional synchronization.
+ let bit_field = unsafe { &(*self.0.get())._bitfield_1 };
+ bit_field.get(13, 1) == bindings::AUTONEG_ENABLE as u64
+ }
+
+ /// Gets the current auto-negotiation state.
+ ///
+ /// It returns true if auto-negotiation is completed.
+ pub fn is_autoneg_completed(&self) -> bool {
+ const AUTONEG_COMPLETED: u64 = 1;
+ // TODO: the code to access to the bit field will be replaced with automatically
+ // generated code by bindgen when it becomes possible.
+ // SAFETY: The struct invariant ensures that we may access
+ // this field without additional synchronization.
+ let bit_field = unsafe { &(*self.0.get())._bitfield_1 };
+ bit_field.get(15, 1) == AUTONEG_COMPLETED
+ }
+
+ /// Sets the speed of the PHY.
+ pub fn set_speed(&mut self, speed: u32) {
+ let phydev = self.0.get();
+ // SAFETY: The struct invariant ensures that we may access
+ // this field without additional synchronization.
+ unsafe { (*phydev).speed = speed as i32 };
+ }
+
+ /// Sets duplex mode.
+ pub fn set_duplex(&mut self, mode: DuplexMode) {
+ let phydev = self.0.get();
+ let v = match mode {
+ DuplexMode::Full => bindings::DUPLEX_FULL as i32,
+ DuplexMode::Half => bindings::DUPLEX_HALF as i32,
+ DuplexMode::Unknown => bindings::DUPLEX_UNKNOWN as i32,
+ };
+ // SAFETY: The struct invariant ensures that we may access
+ // this field without additional synchronization.
+ unsafe { (*phydev).duplex = v };
+ }
+
+ /// Reads a given C22 PHY register.
+ // This function reads a hardware register and updates the stats so takes `&mut self`.
+ pub fn read(&mut self, regnum: u16) -> Result<u16> {
+ let phydev = self.0.get();
+ // SAFETY: `phydev` is pointing to a valid object by the type invariant of `Self`.
+ // So it's just an FFI call, open code of `phy_read()` with a valid `phy_device` pointer
+ // `phydev`.
+ let ret = unsafe {
+ bindings::mdiobus_read((*phydev).mdio.bus, (*phydev).mdio.addr, regnum.into())
+ };
+ if ret < 0 {
+ Err(Error::from_errno(ret))
+ } else {
+ Ok(ret as u16)
+ }
+ }
+
+ /// Writes a given C22 PHY register.
+ pub fn write(&mut self, regnum: u16, val: u16) -> Result {
+ let phydev = self.0.get();
+ // SAFETY: `phydev` is pointing to a valid object by the type invariant of `Self`.
+ // So it's just an FFI call, open code of `phy_write()` with a valid `phy_device` pointer
+ // `phydev`.
+ to_result(unsafe {
+ bindings::mdiobus_write((*phydev).mdio.bus, (*phydev).mdio.addr, regnum.into(), val)
+ })
+ }
+
+ /// Reads a paged register.
+ pub fn read_paged(&mut self, page: u16, regnum: u16) -> Result<u16> {
+ let phydev = self.0.get();
+ // SAFETY: `phydev` is pointing to a valid object by the type invariant of `Self`.
+ // So it's just an FFI call.
+ let ret = unsafe { bindings::phy_read_paged(phydev, page.into(), regnum.into()) };
+ if ret < 0 {
+ Err(Error::from_errno(ret))
+ } else {
+ Ok(ret as u16)
+ }
+ }
+
+ /// Resolves the advertisements into PHY settings.
+ pub fn resolve_aneg_linkmode(&mut self) {
+ let phydev = self.0.get();
+ // SAFETY: `phydev` is pointing to a valid object by the type invariant of `Self`.
+ // So it's just an FFI call.
+ unsafe { bindings::phy_resolve_aneg_linkmode(phydev) };
+ }
+
+ /// Executes software reset the PHY via `BMCR_RESET` bit.
+ pub fn genphy_soft_reset(&mut self) -> Result {
+ let phydev = self.0.get();
+ // SAFETY: `phydev` is pointing to a valid object by the type invariant of `Self`.
+ // So it's just an FFI call.
+ to_result(unsafe { bindings::genphy_soft_reset(phydev) })
+ }
+
+ /// Initializes the PHY.
+ pub fn init_hw(&mut self) -> Result {
+ let phydev = self.0.get();
+ // SAFETY: `phydev` is pointing to a valid object by the type invariant of `Self`.
+ // So it's just an FFI call.
+ to_result(unsafe { bindings::phy_init_hw(phydev) })
+ }
+
+ /// Starts auto-negotiation.
+ pub fn start_aneg(&mut self) -> Result {
+ let phydev = self.0.get();
+ // SAFETY: `phydev` is pointing to a valid object by the type invariant of `Self`.
+ // So it's just an FFI call.
+ to_result(unsafe { bindings::_phy_start_aneg(phydev) })
+ }
+
+ /// Resumes the PHY via `BMCR_PDOWN` bit.
+ pub fn genphy_resume(&mut self) -> Result {
+ let phydev = self.0.get();
+ // SAFETY: `phydev` is pointing to a valid object by the type invariant of `Self`.
+ // So it's just an FFI call.
+ to_result(unsafe { bindings::genphy_resume(phydev) })
+ }
+
+ /// Suspends the PHY via `BMCR_PDOWN` bit.
+ pub fn genphy_suspend(&mut self) -> Result {
+ let phydev = self.0.get();
+ // SAFETY: `phydev` is pointing to a valid object by the type invariant of `Self`.
+ // So it's just an FFI call.
+ to_result(unsafe { bindings::genphy_suspend(phydev) })
+ }
+
+ /// Checks the link status and updates current link state.
+ pub fn genphy_read_status(&mut self) -> Result<u16> {
+ let phydev = self.0.get();
+ // SAFETY: `phydev` is pointing to a valid object by the type invariant of `Self`.
+ // So it's just an FFI call.
+ let ret = unsafe { bindings::genphy_read_status(phydev) };
+ if ret < 0 {
+ Err(Error::from_errno(ret))
+ } else {
+ Ok(ret as u16)
+ }
+ }
+
+ /// Updates the link status.
+ pub fn genphy_update_link(&mut self) -> Result {
+ let phydev = self.0.get();
+ // SAFETY: `phydev` is pointing to a valid object by the type invariant of `Self`.
+ // So it's just an FFI call.
+ to_result(unsafe { bindings::genphy_update_link(phydev) })
+ }
+
+ /// Reads link partner ability.
+ pub fn genphy_read_lpa(&mut self) -> Result {
+ let phydev = self.0.get();
+ // SAFETY: `phydev` is pointing to a valid object by the type invariant of `Self`.
+ // So it's just an FFI call.
+ to_result(unsafe { bindings::genphy_read_lpa(phydev) })
+ }
+
+ /// Reads PHY abilities.
+ pub fn genphy_read_abilities(&mut self) -> Result {
+ let phydev = self.0.get();
+ // SAFETY: `phydev` is pointing to a valid object by the type invariant of `Self`.
+ // So it's just an FFI call.
+ to_result(unsafe { bindings::genphy_read_abilities(phydev) })
+ }
+}
+
+/// Defines certain other features this PHY supports (like interrupts).
+///
+/// These flag values are used in [`Driver::FLAGS`].
+pub mod flags {
+ /// PHY is internal.
+ pub const IS_INTERNAL: u32 = bindings::PHY_IS_INTERNAL;
+ /// PHY needs to be reset after the refclk is enabled.
+ pub const RST_AFTER_CLK_EN: u32 = bindings::PHY_RST_AFTER_CLK_EN;
+ /// Polling is used to detect PHY status changes.
+ pub const POLL_CABLE_TEST: u32 = bindings::PHY_POLL_CABLE_TEST;
+ /// Don't suspend.
+ pub const ALWAYS_CALL_SUSPEND: u32 = bindings::PHY_ALWAYS_CALL_SUSPEND;
+}
+
+/// An adapter for the registration of a PHY driver.
+struct Adapter<T: Driver> {
+ _p: PhantomData<T>,
+}
+
+impl<T: Driver> Adapter<T> {
+ /// # Safety
+ ///
+ /// `phydev` must be passed by the corresponding callback in `phy_driver`.
+ unsafe extern "C" fn soft_reset_callback(
+ phydev: *mut bindings::phy_device,
+ ) -> core::ffi::c_int {
+ from_result(|| {
+ // SAFETY: This callback is called only in contexts
+ // where we hold `phy_device->lock`, so the accessors on
+ // `Device` are okay to call.
+ let dev = unsafe { Device::from_raw(phydev) };
+ T::soft_reset(dev)?;
+ Ok(0)
+ })
+ }
+
+ /// # Safety
+ ///
+ /// `phydev` must be passed by the corresponding callback in `phy_driver`.
+ unsafe extern "C" fn get_features_callback(
+ phydev: *mut bindings::phy_device,
+ ) -> core::ffi::c_int {
+ from_result(|| {
+ // SAFETY: This callback is called only in contexts
+ // where we hold `phy_device->lock`, so the accessors on
+ // `Device` are okay to call.
+ let dev = unsafe { Device::from_raw(phydev) };
+ T::get_features(dev)?;
+ Ok(0)
+ })
+ }
+
+ /// # Safety
+ ///
+ /// `phydev` must be passed by the corresponding callback in `phy_driver`.
+ unsafe extern "C" fn suspend_callback(phydev: *mut bindings::phy_device) -> core::ffi::c_int {
+ from_result(|| {
+ // SAFETY: The C core code ensures that the accessors on
+ // `Device` are okay to call even though `phy_device->lock`
+ // might not be held.
+ let dev = unsafe { Device::from_raw(phydev) };
+ T::suspend(dev)?;
+ Ok(0)
+ })
+ }
+
+ /// # Safety
+ ///
+ /// `phydev` must be passed by the corresponding callback in `phy_driver`.
+ unsafe extern "C" fn resume_callback(phydev: *mut bindings::phy_device) -> core::ffi::c_int {
+ from_result(|| {
+ // SAFETY: The C core code ensures that the accessors on
+ // `Device` are okay to call even though `phy_device->lock`
+ // might not be held.
+ let dev = unsafe { Device::from_raw(phydev) };
+ T::resume(dev)?;
+ Ok(0)
+ })
+ }
+
+ /// # Safety
+ ///
+ /// `phydev` must be passed by the corresponding callback in `phy_driver`.
+ unsafe extern "C" fn config_aneg_callback(
+ phydev: *mut bindings::phy_device,
+ ) -> core::ffi::c_int {
+ from_result(|| {
+ // SAFETY: This callback is called only in contexts
+ // where we hold `phy_device->lock`, so the accessors on
+ // `Device` are okay to call.
+ let dev = unsafe { Device::from_raw(phydev) };
+ T::config_aneg(dev)?;
+ Ok(0)
+ })
+ }
+
+ /// # Safety
+ ///
+ /// `phydev` must be passed by the corresponding callback in `phy_driver`.
+ unsafe extern "C" fn read_status_callback(
+ phydev: *mut bindings::phy_device,
+ ) -> core::ffi::c_int {
+ from_result(|| {
+ // SAFETY: This callback is called only in contexts
+ // where we hold `phy_device->lock`, so the accessors on
+ // `Device` are okay to call.
+ let dev = unsafe { Device::from_raw(phydev) };
+ T::read_status(dev)?;
+ Ok(0)
+ })
+ }
+
+ /// # Safety
+ ///
+ /// `phydev` must be passed by the corresponding callback in `phy_driver`.
+ unsafe extern "C" fn match_phy_device_callback(
+ phydev: *mut bindings::phy_device,
+ ) -> core::ffi::c_int {
+ // SAFETY: This callback is called only in contexts
+ // where we hold `phy_device->lock`, so the accessors on
+ // `Device` are okay to call.
+ let dev = unsafe { Device::from_raw(phydev) };
+ T::match_phy_device(dev) as i32
+ }
+
+ /// # Safety
+ ///
+ /// `phydev` must be passed by the corresponding callback in `phy_driver`.
+ unsafe extern "C" fn read_mmd_callback(
+ phydev: *mut bindings::phy_device,
+ devnum: i32,
+ regnum: u16,
+ ) -> i32 {
+ from_result(|| {
+ // SAFETY: This callback is called only in contexts
+ // where we hold `phy_device->lock`, so the accessors on
+ // `Device` are okay to call.
+ let dev = unsafe { Device::from_raw(phydev) };
+ // CAST: the C side verifies devnum < 32.
+ let ret = T::read_mmd(dev, devnum as u8, regnum)?;
+ Ok(ret.into())
+ })
+ }
+
+ /// # Safety
+ ///
+ /// `phydev` must be passed by the corresponding callback in `phy_driver`.
+ unsafe extern "C" fn write_mmd_callback(
+ phydev: *mut bindings::phy_device,
+ devnum: i32,
+ regnum: u16,
+ val: u16,
+ ) -> i32 {
+ from_result(|| {
+ // SAFETY: This callback is called only in contexts
+ // where we hold `phy_device->lock`, so the accessors on
+ // `Device` are okay to call.
+ let dev = unsafe { Device::from_raw(phydev) };
+ T::write_mmd(dev, devnum as u8, regnum, val)?;
+ Ok(0)
+ })
+ }
+
+ /// # Safety
+ ///
+ /// `phydev` must be passed by the corresponding callback in `phy_driver`.
+ unsafe extern "C" fn link_change_notify_callback(phydev: *mut bindings::phy_device) {
+ // SAFETY: This callback is called only in contexts
+ // where we hold `phy_device->lock`, so the accessors on
+ // `Device` are okay to call.
+ let dev = unsafe { Device::from_raw(phydev) };
+ T::link_change_notify(dev);
+ }
+}
+
+/// Driver structure for a particular PHY type.
+///
+/// Wraps the kernel's [`struct phy_driver`].
+/// This is used to register a driver for a particular PHY type with the kernel.
+///
+/// # Invariants
+///
+/// `self.0` is always in a valid state.
+///
+/// [`struct phy_driver`]: ../../../../../../../include/linux/phy.h
+#[repr(transparent)]
+pub struct DriverVTable(Opaque<bindings::phy_driver>);
+
+// SAFETY: `DriverVTable` doesn't expose any &self method to access internal data, so it's safe to
+// share `&DriverVTable` across execution context boundries.
+unsafe impl Sync for DriverVTable {}
+
+/// Creates a [`DriverVTable`] instance from [`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>() -> DriverVTable {
+ // 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(),
+ flags: T::FLAGS,
+ phy_id: T::PHY_DEVICE_ID.id,
+ phy_id_mask: T::PHY_DEVICE_ID.mask_as_int(),
+ soft_reset: if T::HAS_SOFT_RESET {
+ Some(Adapter::<T>::soft_reset_callback)
+ } else {
+ None
+ },
+ get_features: if T::HAS_GET_FEATURES {
+ Some(Adapter::<T>::get_features_callback)
+ } else {
+ None
+ },
+ match_phy_device: if T::HAS_MATCH_PHY_DEVICE {
+ Some(Adapter::<T>::match_phy_device_callback)
+ } else {
+ None
+ },
+ suspend: if T::HAS_SUSPEND {
+ Some(Adapter::<T>::suspend_callback)
+ } else {
+ None
+ },
+ resume: if T::HAS_RESUME {
+ Some(Adapter::<T>::resume_callback)
+ } else {
+ None
+ },
+ config_aneg: if T::HAS_CONFIG_ANEG {
+ Some(Adapter::<T>::config_aneg_callback)
+ } else {
+ None
+ },
+ read_status: if T::HAS_READ_STATUS {
+ Some(Adapter::<T>::read_status_callback)
+ } else {
+ None
+ },
+ read_mmd: if T::HAS_READ_MMD {
+ Some(Adapter::<T>::read_mmd_callback)
+ } else {
+ None
+ },
+ write_mmd: if T::HAS_WRITE_MMD {
+ Some(Adapter::<T>::write_mmd_callback)
+ } else {
+ None
+ },
+ link_change_notify: if T::HAS_LINK_CHANGE_NOTIFY {
+ Some(Adapter::<T>::link_change_notify_callback)
+ } else {
+ None
+ },
+ // SAFETY: The rest is zeroed out to initialize `struct phy_driver`,
+ // sets `Option<&F>` to be `None`.
+ ..unsafe { core::mem::MaybeUninit::<bindings::phy_driver>::zeroed().assume_init() }
+ }))
+}
+
+/// Driver implementation for a particular PHY type.
+///
+/// This trait is used to create a [`DriverVTable`].
+#[vtable]
+pub trait Driver {
+ /// Defines certain other features this PHY supports.
+ /// It is a combination of the flags in the [`flags`] module.
+ const FLAGS: u32 = 0;
+
+ /// The friendly name of this PHY type.
+ const NAME: &'static CStr;
+
+ /// This driver only works for PHYs with IDs which match this field.
+ /// The default id and mask are zero.
+ const PHY_DEVICE_ID: DeviceId = DeviceId::new_with_custom_mask(0, 0);
+
+ /// Issues a PHY software reset.
+ fn soft_reset(_dev: &mut Device) -> Result {
+ Err(code::ENOTSUPP)
+ }
+
+ /// Probes the hardware to determine what abilities it has.
+ fn get_features(_dev: &mut Device) -> Result {
+ Err(code::ENOTSUPP)
+ }
+
+ /// Returns true if this is a suitable driver for the given phydev.
+ /// If not implemented, matching is based on [`Driver::PHY_DEVICE_ID`].
+ fn match_phy_device(_dev: &Device) -> bool {
+ false
+ }
+
+ /// Configures the advertisement and resets auto-negotiation
+ /// if auto-negotiation is enabled.
+ fn config_aneg(_dev: &mut Device) -> Result {
+ Err(code::ENOTSUPP)
+ }
+
+ /// Determines the negotiated speed and duplex.
+ fn read_status(_dev: &mut Device) -> Result<u16> {
+ Err(code::ENOTSUPP)
+ }
+
+ /// Suspends the hardware, saving state if needed.
+ fn suspend(_dev: &mut Device) -> Result {
+ Err(code::ENOTSUPP)
+ }
+
+ /// Resumes the hardware, restoring state if needed.
+ fn resume(_dev: &mut Device) -> Result {
+ Err(code::ENOTSUPP)
+ }
+
+ /// Overrides the default MMD read function for reading a MMD register.
+ fn read_mmd(_dev: &mut Device, _devnum: u8, _regnum: u16) -> Result<u16> {
+ Err(code::ENOTSUPP)
+ }
+
+ /// Overrides the default MMD write function for writing a MMD register.
+ fn write_mmd(_dev: &mut Device, _devnum: u8, _regnum: u16, _val: u16) -> Result {
+ Err(code::ENOTSUPP)
+ }
+
+ /// Callback for notification of link change.
+ fn link_change_notify(_dev: &mut Device) {}
+}
+
+/// Registration structure for PHY drivers.
+///
+/// Registers [`DriverVTable`] instances with the kernel. They will be unregistered when dropped.
+///
+/// # Invariants
+///
+/// The `drivers` slice are currently registered to the kernel via `phy_drivers_register`.
+pub struct Registration {
+ drivers: Pin<&'static mut [DriverVTable]>,
+}
+
+// SAFETY: The only action allowed in a `Registration` instance is dropping it, which is safe to do
+// from any thread because `phy_drivers_unregister` can be called from any thread context.
+unsafe impl Send for Registration {}
+
+impl Registration {
+ /// Registers a PHY driver.
+ pub fn register(
+ module: &'static crate::ThisModule,
+ drivers: Pin<&'static mut [DriverVTable]>,
+ ) -> Result<Self> {
+ if drivers.is_empty() {
+ return Err(code::EINVAL);
+ }
+ // SAFETY: The type invariants of [`DriverVTable`] ensure that all elements of
+ // the `drivers` slice are initialized properly. `drivers` will not be moved.
+ // So it's just an FFI call.
+ to_result(unsafe {
+ bindings::phy_drivers_register(drivers[0].0.get(), drivers.len().try_into()?, module.0)
+ })?;
+ // INVARIANT: The `drivers` slice is successfully registered to the kernel via `phy_drivers_register`.
+ Ok(Registration { drivers })
+ }
+}
+
+impl Drop for Registration {
+ fn drop(&mut self) {
+ // SAFETY: The type invariants guarantee that `self.drivers` is valid.
+ // So it's just an FFI call.
+ unsafe {
+ bindings::phy_drivers_unregister(self.drivers[0].0.get(), self.drivers.len() as i32)
+ };
+ }
+}
+
+/// An identifier for PHY devices on an MDIO/MII bus.
+///
+/// Represents the kernel's `struct mdio_device_id`. This is used to find an appropriate
+/// PHY driver.
+pub struct DeviceId {
+ id: u32,
+ mask: DeviceMask,
+}
+
+impl DeviceId {
+ /// Creates a new instance with the exact match mask.
+ pub const fn new_with_exact_mask(id: u32) -> Self {
+ DeviceId {
+ id,
+ mask: DeviceMask::Exact,
+ }
+ }
+
+ /// Creates a new instance with the model match mask.
+ pub const fn new_with_model_mask(id: u32) -> Self {
+ DeviceId {
+ id,
+ mask: DeviceMask::Model,
+ }
+ }
+
+ /// Creates a new instance with the vendor match mask.
+ pub const fn new_with_vendor_mask(id: u32) -> Self {
+ DeviceId {
+ id,
+ mask: DeviceMask::Vendor,
+ }
+ }
+
+ /// Creates a new instance with a custom match mask.
+ pub const fn new_with_custom_mask(id: u32, mask: u32) -> Self {
+ DeviceId {
+ id,
+ mask: DeviceMask::Custom(mask),
+ }
+ }
+
+ /// Creates a new instance from [`Driver`].
+ pub const fn new_with_driver<T: Driver>() -> Self {
+ T::PHY_DEVICE_ID
+ }
+
+ /// Get a `mask` as u32.
+ pub const fn mask_as_int(&self) -> u32 {
+ self.mask.as_int()
+ }
+
+ // macro use only
+ #[doc(hidden)]
+ pub const fn mdio_device_id(&self) -> bindings::mdio_device_id {
+ bindings::mdio_device_id {
+ phy_id: self.id,
+ phy_id_mask: self.mask.as_int(),
+ }
+ }
+}
+
+enum DeviceMask {
+ Exact,
+ Model,
+ Vendor,
+ Custom(u32),
+}
+
+impl DeviceMask {
+ const MASK_EXACT: u32 = !0;
+ const MASK_MODEL: u32 = !0 << 4;
+ const MASK_VENDOR: u32 = !0 << 10;
+
+ const fn as_int(&self) -> u32 {
+ match self {
+ DeviceMask::Exact => Self::MASK_EXACT,
+ DeviceMask::Model => Self::MASK_MODEL,
+ DeviceMask::Vendor => Self::MASK_VENDOR,
+ DeviceMask::Custom(mask) => *mask,
+ }
+ }
+}
+
+/// 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: [PhySample],
+/// device_table: [
+/// DeviceId::new_with_driver::<PhySample>()
+/// ],
+/// name: "rust_sample_phy",
+/// author: "Rust for Linux Contributors",
+/// description: "Rust sample PHYs driver",
+/// license: "GPL",
+/// }
+///
+/// struct PhySample;
+///
+/// #[vtable]
+/// impl phy::Driver for PhySample {
+/// const NAME: &'static CStr = c_str!("PhySample");
+/// const PHY_DEVICE_ID: phy::DeviceId = phy::DeviceId::new_with_exact_mask(0x00000001);
+/// }
+/// # }
+/// ```
+///
+/// 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_sample_phy",
+/// author: "Rust for Linux Contributors",
+/// description: "Rust sample PHYs driver",
+/// license: "GPL",
+/// }
+///
+/// struct PhySample;
+///
+/// #[vtable]
+/// impl phy::Driver for PhySample {
+/// const NAME: &'static CStr = c_str!("PhySample");
+/// const PHY_DEVICE_ID: phy::DeviceId = phy::DeviceId::new_with_exact_mask(0x00000001);
+/// }
+///
+/// const _: () = {
+/// static mut DRIVERS: [::kernel::net::phy::DriverVTable; 1] =
+/// [::kernel::net::phy::create_phy_driver::<PhySample>()];
+///
+/// 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 })
+/// }
+/// }
+/// };
+///
+/// #[cfg(MODULE)]
+/// #[no_mangle]
+/// static __mod_mdio__phydev_device_table: [::kernel::bindings::mdio_device_id; 2] = [
+/// ::kernel::bindings::mdio_device_id {
+/// phy_id: 0x00000001,
+/// 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),+]) => {
+ // SAFETY: C will not read off the end of this constant since the last element is zero.
+ #[cfg(MODULE)]
+ #[no_mangle]
+ static __mod_mdio__phydev_device_table: [$crate::bindings::mdio_device_id;
+ $crate::module_phy_driver!(@count_devices $($dev),+) + 1] = [
+ $($dev.mdio_device_id()),+,
+ $crate::bindings::mdio_device_id {
+ phy_id: 0,
+ phy_id_mask: 0
+ }
+ ];
+ };
+
+ (drivers: [$($driver:ident),+ $(,)?], device_table: [$($dev:expr),+ $(,)?], $($f:tt)*) => {
+ struct Module {
+ _reg: $crate::net::phy::Registration,
+ }
+
+ $crate::prelude::module! {
+ type: Module,
+ $($f)*
+ }
+
+ const _: () = {
+ static mut DRIVERS: [$crate::net::phy::DriverVTable;
+ $crate::module_phy_driver!(@count_devices $($driver),+)] =
+ [$($crate::net::phy::create_phy_driver::<$driver>()),+];
+
+ impl $crate::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 = $crate::net::phy::Registration::register(
+ module,
+ ::core::pin::Pin::static_mut(drivers),
+ )?;
+ Ok(Module { _reg: reg })
+ }
+ }
+ };
+
+ $crate::module_phy_driver!(@device_table [$($dev),+]);
+ }
+}
diff --git a/rust/kernel/print.rs b/rust/kernel/print.rs
index f48926e3e9..9b13aca832 100644
--- a/rust/kernel/print.rs
+++ b/rust/kernel/print.rs
@@ -2,7 +2,7 @@
//! Printing facilities.
//!
-//! C header: [`include/linux/printk.h`](../../../../include/linux/printk.h)
+//! C header: [`include/linux/printk.h`](srctree/include/linux/printk.h)
//!
//! Reference: <https://www.kernel.org/doc/html/latest/core-api/printk-basics.html>
@@ -48,7 +48,7 @@ pub mod format_strings {
/// The format string is always the same for a given level, i.e. for a
/// given `prefix`, which are the kernel's `KERN_*` constants.
///
- /// [`_printk`]: ../../../../include/linux/printk.h
+ /// [`_printk`]: srctree/include/linux/printk.h
const fn generate(is_cont: bool, prefix: &[u8; 3]) -> [u8; LENGTH] {
// Ensure the `KERN_*` macros are what we expect.
assert!(prefix[0] == b'\x01');
@@ -97,7 +97,7 @@ pub mod format_strings {
/// The format string must be one of the ones in [`format_strings`], and
/// the module name must be null-terminated.
///
-/// [`_printk`]: ../../../../include/linux/_printk.h
+/// [`_printk`]: srctree/include/linux/_printk.h
#[doc(hidden)]
#[cfg_attr(not(CONFIG_PRINTK), allow(unused_variables))]
pub unsafe fn call_printk(
@@ -120,7 +120,7 @@ pub unsafe fn call_printk(
///
/// Public but hidden since it should only be used from public macros.
///
-/// [`_printk`]: ../../../../include/linux/printk.h
+/// [`_printk`]: srctree/include/linux/printk.h
#[doc(hidden)]
#[cfg_attr(not(CONFIG_PRINTK), allow(unused_variables))]
pub fn call_printk_cont(args: fmt::Arguments<'_>) {
diff --git a/rust/kernel/str.rs b/rust/kernel/str.rs
index c41607b2e4..7d848b83ad 100644
--- a/rust/kernel/str.rs
+++ b/rust/kernel/str.rs
@@ -608,6 +608,12 @@ impl<'a> TryFrom<&'a CStr> for CString {
}
}
+impl fmt::Debug for CString {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ fmt::Debug::fmt(&**self, f)
+ }
+}
+
/// A convenience alias for [`core::format_args`].
#[macro_export]
macro_rules! fmt {
diff --git a/rust/kernel/sync/condvar.rs b/rust/kernel/sync/condvar.rs
index b679b6f6db..f65e19d5a3 100644
--- a/rust/kernel/sync/condvar.rs
+++ b/rust/kernel/sync/condvar.rs
@@ -50,7 +50,7 @@ macro_rules! new_condvar {
/// fn wait_for_value(e: &Example, v: u32) {
/// let mut guard = e.value.lock();
/// while *guard != v {
-/// e.value_changed.wait_uninterruptible(&mut guard);
+/// e.value_changed.wait(&mut guard);
/// }
/// }
///
@@ -69,7 +69,7 @@ macro_rules! new_condvar {
/// }
/// ```
///
-/// [`struct wait_queue_head`]: ../../../include/linux/wait.h
+/// [`struct wait_queue_head`]: srctree/include/linux/wait.h
#[pin_data]
pub struct CondVar {
#[pin]
@@ -120,28 +120,28 @@ impl CondVar {
unsafe { bindings::finish_wait(self.wait_list.get(), wait.get()) };
}
- /// Releases the lock and waits for a notification in interruptible mode.
+ /// Releases the lock and waits for a notification in uninterruptible mode.
///
/// Atomically releases the given lock (whose ownership is proven by the guard) and puts the
/// thread to sleep, reacquiring the lock on wake up. It wakes up when notified by
- /// [`CondVar::notify_one`] or [`CondVar::notify_all`], or when the thread receives a signal.
- /// It may also wake up spuriously.
+ /// [`CondVar::notify_one`] or [`CondVar::notify_all`]. Note that it may also wake up
+ /// spuriously.
+ pub fn wait<T: ?Sized, B: Backend>(&self, guard: &mut Guard<'_, T, B>) {
+ self.wait_internal(bindings::TASK_UNINTERRUPTIBLE, guard);
+ }
+
+ /// Releases the lock and waits for a notification in interruptible mode.
+ ///
+ /// Similar to [`CondVar::wait`], except that the wait is interruptible. That is, the thread may
+ /// wake up due to signals. It may also wake up spuriously.
///
/// Returns whether there is a signal pending.
- #[must_use = "wait returns if a signal is pending, so the caller must check the return value"]
- pub fn wait<T: ?Sized, B: Backend>(&self, guard: &mut Guard<'_, T, B>) -> bool {
+ #[must_use = "wait_interruptible returns if a signal is pending, so the caller must check the return value"]
+ pub fn wait_interruptible<T: ?Sized, B: Backend>(&self, guard: &mut Guard<'_, T, B>) -> bool {
self.wait_internal(bindings::TASK_INTERRUPTIBLE, guard);
crate::current!().signal_pending()
}
- /// Releases the lock and waits for a notification in uninterruptible mode.
- ///
- /// Similar to [`CondVar::wait`], except that the wait is not interruptible. That is, the
- /// thread won't wake up due to signals. It may, however, wake up supirously.
- pub fn wait_uninterruptible<T: ?Sized, B: Backend>(&self, guard: &mut Guard<'_, T, B>) {
- self.wait_internal(bindings::TASK_UNINTERRUPTIBLE, guard)
- }
-
/// Calls the kernel function to notify the appropriate number of threads with the given flags.
fn notify(&self, count: i32, flags: u32) {
// SAFETY: `wait_list` points to valid memory.
diff --git a/rust/kernel/sync/lock/mutex.rs b/rust/kernel/sync/lock/mutex.rs
index 09276fedc0..8c524a3ec4 100644
--- a/rust/kernel/sync/lock/mutex.rs
+++ b/rust/kernel/sync/lock/mutex.rs
@@ -84,7 +84,7 @@ macro_rules! new_mutex {
/// }
/// ```
///
-/// [`struct mutex`]: ../../../../include/linux/mutex.h
+/// [`struct mutex`]: srctree/include/linux/mutex.h
pub type Mutex<T> = super::Lock<T, MutexBackend>;
/// A kernel `struct mutex` lock backend.
diff --git a/rust/kernel/sync/lock/spinlock.rs b/rust/kernel/sync/lock/spinlock.rs
index 91eb2c9e91..068535ce1b 100644
--- a/rust/kernel/sync/lock/spinlock.rs
+++ b/rust/kernel/sync/lock/spinlock.rs
@@ -82,7 +82,7 @@ macro_rules! new_spinlock {
/// }
/// ```
///
-/// [`spinlock_t`]: ../../../../include/linux/spinlock.h
+/// [`spinlock_t`]: srctree/include/linux/spinlock.h
pub type SpinLock<T> = super::Lock<T, SpinLockBackend>;
/// A kernel `spinlock_t` lock backend.
diff --git a/rust/kernel/task.rs b/rust/kernel/task.rs
index b2299bc7ac..9451932d5d 100644
--- a/rust/kernel/task.rs
+++ b/rust/kernel/task.rs
@@ -2,7 +2,7 @@
//! Tasks (threads and processes).
//!
-//! C header: [`include/linux/sched.h`](../../../../include/linux/sched.h).
+//! C header: [`include/linux/sched.h`](srctree/include/linux/sched.h).
use crate::{bindings, types::Opaque};
use core::{marker::PhantomData, ops::Deref, ptr};
diff --git a/rust/kernel/workqueue.rs b/rust/kernel/workqueue.rs
index b67fb1ba16..4983978773 100644
--- a/rust/kernel/workqueue.rs
+++ b/rust/kernel/workqueue.rs
@@ -132,7 +132,7 @@
//! }
//! ```
//!
-//! C header: [`include/linux/workqueue.h`](../../../../include/linux/workqueue.h)
+//! C header: [`include/linux/workqueue.h`](srctree/include/linux/workqueue.h)
use crate::{bindings, prelude::*, sync::Arc, sync::LockClassKey, types::Opaque};
use alloc::alloc::AllocError;
diff --git a/rust/macros/lib.rs b/rust/macros/lib.rs
index c42105c2ff..520eae5fd7 100644
--- a/rust/macros/lib.rs
+++ b/rust/macros/lib.rs
@@ -20,7 +20,7 @@ use proc_macro::TokenStream;
/// The `type` argument should be a type which implements the [`Module`]
/// trait. Also accepts various forms of kernel metadata.
///
-/// C header: [`include/linux/moduleparam.h`](../../../include/linux/moduleparam.h)
+/// C header: [`include/linux/moduleparam.h`](srctree/include/linux/moduleparam.h)
///
/// [`Module`]: ../kernel/trait.Module.html
///
@@ -35,18 +35,6 @@ use proc_macro::TokenStream;
/// author: "Rust for Linux Contributors",
/// description: "My very own kernel module!",
/// license: "GPL",
-/// params: {
-/// my_i32: i32 {
-/// default: 42,
-/// permissions: 0o000,
-/// description: "Example of i32",
-/// },
-/// writeable_i32: i32 {
-/// default: 42,
-/// permissions: 0o644,
-/// description: "Example of i32",
-/// },
-/// },
/// }
///
/// struct MyModule;
@@ -87,27 +75,49 @@ pub fn module(ts: TokenStream) -> TokenStream {
/// implementation could just return `Error::EINVAL`); Linux typically use C
/// `NULL` pointers to represent these functions.
///
-/// This attribute is intended to close the gap. Traits can be declared and
-/// implemented with the `#[vtable]` attribute, and a `HAS_*` associated constant
-/// will be generated for each method in the trait, indicating if the implementor
-/// has overridden a method.
+/// This attribute closes that gap. A trait can be annotated with the
+/// `#[vtable]` attribute. Implementers of the trait will then also have to
+/// annotate the trait with `#[vtable]`. This attribute generates a `HAS_*`
+/// associated constant bool for each method in the trait that is set to true if
+/// the implementer has overridden the associated method.
+///
+/// For a trait method to be optional, it must have a default implementation.
+/// This is also the case for traits annotated with `#[vtable]`, but in this
+/// case the default implementation will never be executed. The reason for this
+/// is that the functions will be called through function pointers installed in
+/// C side vtables. When an optional method is not implemented on a `#[vtable]`
+/// trait, a NULL entry is installed in the vtable. Thus the default
+/// implementation is never called. Since these traits are not designed to be
+/// used on the Rust side, it should not be possible to call the default
+/// implementation. This is done to ensure that we call the vtable methods
+/// through the C vtable, and not through the Rust vtable. Therefore, the
+/// default implementation should call `kernel::build_error`, which prevents
+/// calls to this function at compile time:
+///
+/// ```compile_fail
+/// # use kernel::error::VTABLE_DEFAULT_ERROR;
+/// kernel::build_error(VTABLE_DEFAULT_ERROR)
+/// ```
+///
+/// Note that you might need to import [`kernel::error::VTABLE_DEFAULT_ERROR`].
///
-/// This attribute is not needed if all methods are required.
+/// This macro should not be used when all functions are required.
///
/// # Examples
///
/// ```ignore
+/// use kernel::error::VTABLE_DEFAULT_ERROR;
/// use kernel::prelude::*;
///
/// // Declares a `#[vtable]` trait
/// #[vtable]
/// pub trait Operations: Send + Sync + Sized {
/// fn foo(&self) -> Result<()> {
-/// Err(EINVAL)
+/// kernel::build_error(VTABLE_DEFAULT_ERROR)
/// }
///
/// fn bar(&self) -> Result<()> {
-/// Err(EINVAL)
+/// kernel::build_error(VTABLE_DEFAULT_ERROR)
/// }
/// }
///
@@ -125,6 +135,8 @@ pub fn module(ts: TokenStream) -> TokenStream {
/// assert_eq!(<Foo as Operations>::HAS_FOO, true);
/// assert_eq!(<Foo as Operations>::HAS_BAR, false);
/// ```
+///
+/// [`kernel::error::VTABLE_DEFAULT_ERROR`]: ../kernel/error/constant.VTABLE_DEFAULT_ERROR.html
#[proc_macro_attribute]
pub fn vtable(attr: TokenStream, ts: TokenStream) -> TokenStream {
vtable::vtable(attr, ts)
@@ -254,8 +266,8 @@ pub fn pinned_drop(args: TokenStream, input: TokenStream) -> TokenStream {
/// Within the `paste!` macro, identifiers inside `[<` and `>]` are concatenated together to form a
/// single identifier.
///
-/// This is similar to the [`paste`] crate, but with pasting feature limited to identifiers
-/// (literals, lifetimes and documentation strings are not supported). There is a difference in
+/// This is similar to the [`paste`] crate, but with pasting feature limited to identifiers and
+/// literals (lifetimes and documentation strings are not supported). There is a difference in
/// supported modifiers as well.
///
/// # Example
@@ -337,6 +349,24 @@ pub fn pinned_drop(args: TokenStream, input: TokenStream) -> TokenStream {
/// assert_eq!(br_ok(), binder_driver_return_protocol_BR_OK);
/// ```
///
+/// # Literals
+///
+/// Literals can also be concatenated with other identifiers:
+///
+/// ```ignore
+/// macro_rules! create_numbered_fn {
+/// ($name:literal, $val:literal) => {
+/// kernel::macros::paste! {
+/// fn [<some_ $name _fn $val>]() -> u32 { $val }
+/// }
+/// };
+/// }
+///
+/// create_numbered_fn!("foo", 100);
+///
+/// assert_eq!(some_foo_fn100(), 100)
+/// ```
+///
/// [`paste`]: https://docs.rs/paste/
#[proc_macro]
pub fn paste(input: TokenStream) -> TokenStream {
diff --git a/rust/macros/paste.rs b/rust/macros/paste.rs
index 385a784342..f40d42b35b 100644
--- a/rust/macros/paste.rs
+++ b/rust/macros/paste.rs
@@ -9,7 +9,15 @@ fn concat(tokens: &[TokenTree], group_span: Span) -> TokenTree {
loop {
match tokens.next() {
None => break,
- Some(TokenTree::Literal(lit)) => segments.push((lit.to_string(), lit.span())),
+ Some(TokenTree::Literal(lit)) => {
+ // Allow us to concat string literals by stripping quotes
+ let mut value = lit.to_string();
+ if value.starts_with('"') && value.ends_with('"') {
+ value.remove(0);
+ value.pop();
+ }
+ segments.push((value, lit.span()));
+ }
Some(TokenTree::Ident(ident)) => {
let mut value = ident.to_string();
if value.starts_with("r#") {
diff --git a/rust/uapi/uapi_helper.h b/rust/uapi/uapi_helper.h
index 301f5207f0..08f5e9334c 100644
--- a/rust/uapi/uapi_helper.h
+++ b/rust/uapi/uapi_helper.h
@@ -7,3 +7,5 @@
*/
#include <uapi/asm-generic/ioctl.h>
+#include <uapi/linux/mii.h>
+#include <uapi/linux/ethtool.h>