mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-02-28 19:06:51 +01:00
Pull driver core updates from Danilo Krummrich:
"Bus:
- Ensure bus->match() is consistently called with the device lock
held
- Improve type safety of bus_find_device_by_acpi_dev()
Devtmpfs:
- Parse 'devtmpfs.mount=' boot parameter with kstrtoint() instead of
simple_strtoul()
- Avoid sparse warning by making devtmpfs_context_ops static
IOMMU:
- Do not register the qcom_smmu_tbu_driver in arm_smmu_device_probe()
MAINTAINERS:
- Add the new driver-core mailing list (driver-core@lists.linux.dev)
to all relevant entries
- Add missing tree location for "FIRMWARE LOADER (request_firmware)"
- Add driver-model documentation to the "DRIVER CORE" entry
- Add missing driver-core maintainers to the "AUXILIARY BUS" entry
Misc:
- Change return type of attribute_container_register() to void; it
has always been infallible
- Do not export sysfs_change_owner(), sysfs_file_change_owner() and
device_change_owner()
- Move devres_for_each_res() from the public devres header to
drivers/base/base.h
- Do not use a static struct device for the faux bus; allocate it
dynamically
Revocable:
- Patches for the revocable synchronization primitive have been
scheduled for v7.0-rc1, but have been reverted as they need some
more refinement
Rust:
- Device:
- Support dev_printk on all device types, not just the core Device
struct; remove now-redundant .as_ref() calls in dev_* print
calls
- Devres:
- Introduce an internal reference count in Devres<T> to avoid a
deadlock condition in case of (indirect) nesting
- DMA:
- Allow drivers to tune the maximum DMA segment size via
dma_set_max_seg_size()
- I/O:
- Introduce the concept of generic I/O backends to handle
different kinds of device shared memory through a common
interface.
This enables higher-level concepts such as register
abstractions, I/O slices, and field projections to be built
generically on top.
In a first step, introduce the Io, IoCapable<T>, and IoKnownSize
trait hierarchy for sharing a common interface supporting offset
validation and bound-checking logic between I/O backends.
- Refactor MMIO to use the common I/O backend infrastructure
- Misc:
- Add __rust_helper annotations to C helpers for inlining into
Rust code
- Use "kernel vertical" style for imports
- Replace kernel::c_str! with C string literals
- Update ARef imports to use sync::aref
- Use pin_init::zeroed() for struct auxiliary_device_id and
debugfs file_operations initialization
- Use LKMM atomic types in debugfs doc-tests
- Various minor comment and documentation fixes
- PCI:
- Implement PCI configuration space accessors using the common I/O
backend infrastructure
- Document pci::Bar device endianness assumptions
- SoC:
- Abstractions for struct soc_device and struct soc_device_attribute
- Sample driver for soc::Device"
* tag 'driver-core-7.0-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/driver-core/driver-core: (79 commits)
rust: devres: fix race condition due to nesting
rust: dma: add missing __rust_helper annotations
samples: rust: pci: Remove some additional `.as_ref()` for `dev_*` print
Revert "revocable: Revocable resource management"
Revert "revocable: Add Kunit test cases"
Revert "selftests: revocable: Add kselftest cases"
driver core: remove device_change_owner() export
sysfs: remove exports of sysfs_*change_owner()
driver core: disable revocable code from build
revocable: Add KUnit test for concurrent access
revocable: fix SRCU index corruption by requiring caller-provided storage
revocable: Add KUnit test for provider lifetime races
revocable: Fix races in revocable_alloc() using RCU
driver core: fix inverted "locked" suffix of driver_match_device()
rust: io: move MIN_SIZE and io_addr_assert to IoKnownSize
rust: pci: re-export ConfigSpace
rust: dma: allow drivers to tune max segment size
gpu: tyr: remove redundant `.as_ref()` for `dev_*` print
rust: auxiliary: use `pin_init::zeroed()` for device ID
rust: debugfs: use pin_init::zeroed() for file_operations
...
171 lines
5.8 KiB
Rust
171 lines
5.8 KiB
Rust
// SPDX-License-Identifier: GPL-2.0
|
|
// Copyright (C) 2025 Google LLC.
|
|
|
|
use crate::{
|
|
debugfs::file_ops::FileOps,
|
|
prelude::*,
|
|
str::{
|
|
CStr,
|
|
CStrExt as _, //
|
|
},
|
|
sync::Arc,
|
|
};
|
|
|
|
use core::marker::PhantomData;
|
|
|
|
/// Owning handle to a DebugFS entry.
|
|
///
|
|
/// # Invariants
|
|
///
|
|
/// The wrapped pointer will always be `NULL`, an error, or an owned DebugFS `dentry`.
|
|
pub(crate) struct Entry<'a> {
|
|
entry: *mut bindings::dentry,
|
|
// If we were created with an owning parent, this is the keep-alive
|
|
_parent: Option<Arc<Entry<'static>>>,
|
|
// If we were created with a non-owning parent, this prevents us from outliving it
|
|
_phantom: PhantomData<&'a ()>,
|
|
}
|
|
|
|
// SAFETY: [`Entry`] is just a `dentry` under the hood, which the API promises can be transferred
|
|
// between threads.
|
|
unsafe impl Send for Entry<'_> {}
|
|
|
|
// SAFETY: All the C functions we call on the `dentry` pointer are threadsafe.
|
|
unsafe impl Sync for Entry<'_> {}
|
|
|
|
impl Entry<'static> {
|
|
pub(crate) fn dynamic_dir(name: &CStr, parent: Option<Arc<Self>>) -> Self {
|
|
let parent_ptr = match &parent {
|
|
Some(entry) => entry.as_ptr(),
|
|
None => core::ptr::null_mut(),
|
|
};
|
|
// SAFETY: The invariants of this function's arguments ensure the safety of this call.
|
|
// * `name` is a valid C string by the invariants of `&CStr`.
|
|
// * `parent_ptr` is either `NULL` (if `parent` is `None`), or a pointer to a valid
|
|
// `dentry` by our invariant. `debugfs_create_dir` handles `NULL` pointers correctly.
|
|
let entry = unsafe { bindings::debugfs_create_dir(name.as_char_ptr(), parent_ptr) };
|
|
|
|
Entry {
|
|
entry,
|
|
_parent: parent,
|
|
_phantom: PhantomData,
|
|
}
|
|
}
|
|
|
|
/// # Safety
|
|
///
|
|
/// * `data` must outlive the returned `Entry`.
|
|
pub(crate) unsafe fn dynamic_file<T>(
|
|
name: &CStr,
|
|
parent: Arc<Self>,
|
|
data: &T,
|
|
file_ops: &'static FileOps<T>,
|
|
) -> Self {
|
|
// SAFETY: The invariants of this function's arguments ensure the safety of this call.
|
|
// * `name` is a valid C string by the invariants of `&CStr`.
|
|
// * `parent.as_ptr()` is a pointer to a valid `dentry` by invariant.
|
|
// * The caller guarantees that `data` will outlive the returned `Entry`.
|
|
// * The guarantees on `FileOps` assert the vtable will be compatible with the data we have
|
|
// provided.
|
|
let entry = unsafe {
|
|
bindings::debugfs_create_file_full(
|
|
name.as_char_ptr(),
|
|
file_ops.mode(),
|
|
parent.as_ptr(),
|
|
core::ptr::from_ref(data) as *mut c_void,
|
|
core::ptr::null(),
|
|
&**file_ops,
|
|
)
|
|
};
|
|
|
|
Entry {
|
|
entry,
|
|
_parent: Some(parent),
|
|
_phantom: PhantomData,
|
|
}
|
|
}
|
|
}
|
|
|
|
impl<'a> Entry<'a> {
|
|
pub(crate) fn dir(name: &CStr, parent: Option<&'a Entry<'_>>) -> Self {
|
|
let parent_ptr = match &parent {
|
|
Some(entry) => entry.as_ptr(),
|
|
None => core::ptr::null_mut(),
|
|
};
|
|
// SAFETY: The invariants of this function's arguments ensure the safety of this call.
|
|
// * `name` is a valid C string by the invariants of `&CStr`.
|
|
// * `parent_ptr` is either `NULL` (if `parent` is `None`), or a pointer to a valid
|
|
// `dentry` (because `parent` is a valid reference to an `Entry`). The lifetime `'a`
|
|
// ensures that the parent outlives this entry.
|
|
let entry = unsafe { bindings::debugfs_create_dir(name.as_char_ptr(), parent_ptr) };
|
|
|
|
Entry {
|
|
entry,
|
|
_parent: None,
|
|
_phantom: PhantomData,
|
|
}
|
|
}
|
|
|
|
pub(crate) fn file<T>(
|
|
name: &CStr,
|
|
parent: &'a Entry<'_>,
|
|
data: &'a T,
|
|
file_ops: &FileOps<T>,
|
|
) -> Self {
|
|
// SAFETY: The invariants of this function's arguments ensure the safety of this call.
|
|
// * `name` is a valid C string by the invariants of `&CStr`.
|
|
// * `parent.as_ptr()` is a pointer to a valid `dentry` because we have `&'a Entry`.
|
|
// * `data` is a valid pointer to `T` for lifetime `'a`.
|
|
// * The returned `Entry` has lifetime `'a`, so it cannot outlive `parent` or `data`.
|
|
// * The caller guarantees that `vtable` is compatible with `data`.
|
|
// * The guarantees on `FileOps` assert the vtable will be compatible with the data we have
|
|
// provided.
|
|
let entry = unsafe {
|
|
bindings::debugfs_create_file_full(
|
|
name.as_char_ptr(),
|
|
file_ops.mode(),
|
|
parent.as_ptr(),
|
|
core::ptr::from_ref(data) as *mut c_void,
|
|
core::ptr::null(),
|
|
&**file_ops,
|
|
)
|
|
};
|
|
|
|
Entry {
|
|
entry,
|
|
_parent: None,
|
|
_phantom: PhantomData,
|
|
}
|
|
}
|
|
}
|
|
|
|
impl Entry<'_> {
|
|
/// Constructs a placeholder DebugFS [`Entry`].
|
|
pub(crate) fn empty() -> Self {
|
|
Self {
|
|
entry: core::ptr::null_mut(),
|
|
_parent: None,
|
|
_phantom: PhantomData,
|
|
}
|
|
}
|
|
|
|
/// Returns the pointer representation of the DebugFS directory.
|
|
///
|
|
/// # Guarantees
|
|
///
|
|
/// Due to the type invariant, the value returned from this function will always be an error
|
|
/// code, `NULL`, or a live DebugFS directory. If it is live, it will remain live at least as
|
|
/// long as this entry lives.
|
|
pub(crate) fn as_ptr(&self) -> *mut bindings::dentry {
|
|
self.entry
|
|
}
|
|
}
|
|
|
|
impl Drop for Entry<'_> {
|
|
fn drop(&mut self) {
|
|
// SAFETY: `debugfs_remove` can take `NULL`, error values, and legal DebugFS dentries.
|
|
// `as_ptr` guarantees that the pointer is of this form.
|
|
unsafe { bindings::debugfs_remove(self.as_ptr()) }
|
|
}
|
|
}
|