Merge tag 'driver-core-6.18-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/driver-core/driver-core

Pull driver core updates from Danilo Krummrich:
 "Auxiliary:
   - Drop call to dev_pm_domain_detach() in auxiliary_bus_probe()
   - Optimize logic of auxiliary_match_id()

  Rust:
   - Auxiliary:
      - Use primitive C types from prelude

   - DebugFs:
      - Add debugfs support for simple read/write files and custom
        callbacks through a File-type-based and directory-scope-based
        API
      - Sample driver code for the File-type-based API
      - Sample module code for the directory-scope-based API

   - I/O:
      - Add io::poll module and implement Rust specific
        read_poll_timeout() helper

   - IRQ:
      - Implement support for threaded and non-threaded device IRQs
        based on (&Device<Bound>, IRQ number) tuples (IrqRequest)
      - Provide &Device<Bound> cookie in IRQ handlers

   - PCI:
      - Support IRQ requests from IRQ vectors for a specific
        pci::Device<Bound>
      - Implement accessors for subsystem IDs, revision, devid and
        resource start
      - Provide dedicated pci::Vendor and pci::Class types for vendor
        and class ID numbers
      - Implement Display to print actual vendor and class names; Debug
        to print the raw ID numbers
      - Add pci::DeviceId::from_class_and_vendor() helper
      - Use primitive C types from prelude
      - Various minor inline and (safety) comment improvements

   - Platform:
      - Support IRQ requests from IRQ vectors for a specific
        platform::Device<Bound>

   - Nova:
      - Use pci::DeviceId::from_class_and_vendor() to avoid probing
        non-display/compute PCI functions

   - Misc:
      - Add helper for cpu_relax()
      - Update ARef import from sync::aref

  sysfs:
   - Remove bin_attrs_new field from struct attribute_group
   - Remove read_new() and write_new() from struct bin_attribute

  Misc:
   - Document potential race condition in get_dev_from_fwnode()
   - Constify node_group argument in software node registration
     functions
   - Fix order of kernel-doc parameters in various functions
   - Set power.no_pm flag for faux devices
   - Set power.no_callbacks flag along with the power.no_pm flag
   - Constify the pmu_bus bus type
   - Minor spelling fixes"

* tag 'driver-core-6.18-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/driver-core/driver-core: (43 commits)
  rust: pci: display symbolic PCI vendor names
  rust: pci: display symbolic PCI class names
  rust: pci: fix incorrect platform reference in PCI driver probe doc comment
  rust: pci: fix incorrect platform reference in PCI driver unbind doc comment
  perf: make pmu_bus const
  samples: rust: Add scoped debugfs sample driver
  rust: debugfs: Add support for scoped directories
  samples: rust: Add debugfs sample driver
  rust: debugfs: Add support for callback-based files
  rust: debugfs: Add support for writable files
  rust: debugfs: Add support for read-only files
  rust: debugfs: Add initial support for directories
  driver core: auxiliary bus: Optimize logic of auxiliary_match_id()
  driver core: auxiliary bus: Drop dev_pm_domain_detach() call
  driver core: Fix order of the kernel-doc parameters
  driver core: get_dev_from_fwnode(): document potential race
  drivers: base: fix "publically"->"publicly"
  driver core/PM: Set power.no_callbacks along with power.no_pm
  driver core: faux: Set power.no_pm for faux devices
  rust: pci: inline several tiny functions
  ...
This commit is contained in:
Linus Torvalds
2025-10-01 08:39:23 -07:00
43 changed files with 3392 additions and 99 deletions

View File

@@ -62,6 +62,28 @@ config SAMPLE_RUST_DMA
If unsure, say N.
config SAMPLE_RUST_DEBUGFS
tristate "DebugFS Test Module"
depends on DEBUG_FS
help
This option builds the Rust DebugFS Test module sample.
To compile this as a module, choose M here:
the module will be called rust_debugfs.
If unsure, say N.
config SAMPLE_RUST_DEBUGFS_SCOPED
tristate "Scoped DebugFS Test Module"
depends on DEBUG_FS
help
This option builds the Rust Scoped DebugFS Test module sample.
To compile this as a module, choose M here:
the module will be called rust_debugfs_scoped.
If unsure, say N.
config SAMPLE_RUST_DRIVER_PCI
tristate "PCI Driver"
depends on PCI

View File

@@ -4,6 +4,8 @@ ccflags-y += -I$(src) # needed for trace events
obj-$(CONFIG_SAMPLE_RUST_MINIMAL) += rust_minimal.o
obj-$(CONFIG_SAMPLE_RUST_MISC_DEVICE) += rust_misc_device.o
obj-$(CONFIG_SAMPLE_RUST_PRINT) += rust_print.o
obj-$(CONFIG_SAMPLE_RUST_DEBUGFS) += rust_debugfs.o
obj-$(CONFIG_SAMPLE_RUST_DEBUGFS_SCOPED) += rust_debugfs_scoped.o
obj-$(CONFIG_SAMPLE_RUST_DMA) += rust_dma.o
obj-$(CONFIG_SAMPLE_RUST_DRIVER_PCI) += rust_driver_pci.o
obj-$(CONFIG_SAMPLE_RUST_DRIVER_PLATFORM) += rust_driver_platform.o

View File

@@ -0,0 +1,151 @@
// SPDX-License-Identifier: GPL-2.0
// Copyright (C) 2025 Google LLC.
//! Sample DebugFS exporting platform driver
//!
//! To successfully probe this driver with ACPI, use an ssdt that looks like
//!
//! ```dsl
//! DefinitionBlock ("", "SSDT", 2, "TEST", "VIRTACPI", 0x00000001)
//! {
//! Scope (\_SB)
//! {
//! Device (T432)
//! {
//! Name (_HID, "LNUXBEEF") // ACPI hardware ID to match
//! Name (_UID, 1)
//! Name (_STA, 0x0F) // Device present, enabled
//! Name (_DSD, Package () { // Sample attribute
//! ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"),
//! Package() {
//! Package(2) {"compatible", "sample-debugfs"}
//! }
//! })
//! Name (_CRS, ResourceTemplate ()
//! {
//! Memory32Fixed (ReadWrite, 0xFED00000, 0x1000)
//! })
//! }
//! }
//! }
//! ```
use core::str::FromStr;
use core::sync::atomic::AtomicUsize;
use core::sync::atomic::Ordering;
use kernel::c_str;
use kernel::debugfs::{Dir, File};
use kernel::new_mutex;
use kernel::prelude::*;
use kernel::sync::Mutex;
use kernel::{acpi, device::Core, of, platform, str::CString, types::ARef};
kernel::module_platform_driver! {
type: RustDebugFs,
name: "rust_debugfs",
authors: ["Matthew Maurer"],
description: "Rust DebugFS usage sample",
license: "GPL",
}
#[pin_data]
struct RustDebugFs {
pdev: ARef<platform::Device>,
// As we only hold these for drop effect (to remove the directory/files) we have a leading
// underscore to indicate to the compiler that we don't expect to use this field directly.
_debugfs: Dir,
#[pin]
_compatible: File<CString>,
#[pin]
counter: File<AtomicUsize>,
#[pin]
inner: File<Mutex<Inner>>,
}
#[derive(Debug)]
struct Inner {
x: u32,
y: u32,
}
impl FromStr for Inner {
type Err = Error;
fn from_str(s: &str) -> Result<Self> {
let mut parts = s.split_whitespace();
let x = parts
.next()
.ok_or(EINVAL)?
.parse::<u32>()
.map_err(|_| EINVAL)?;
let y = parts
.next()
.ok_or(EINVAL)?
.parse::<u32>()
.map_err(|_| EINVAL)?;
if parts.next().is_some() {
return Err(EINVAL);
}
Ok(Inner { x, y })
}
}
kernel::acpi_device_table!(
ACPI_TABLE,
MODULE_ACPI_TABLE,
<RustDebugFs as platform::Driver>::IdInfo,
[(acpi::DeviceId::new(c_str!("LNUXBEEF")), ())]
);
impl platform::Driver for RustDebugFs {
type IdInfo = ();
const OF_ID_TABLE: Option<of::IdTable<Self::IdInfo>> = None;
const ACPI_ID_TABLE: Option<acpi::IdTable<Self::IdInfo>> = Some(&ACPI_TABLE);
fn probe(
pdev: &platform::Device<Core>,
_info: Option<&Self::IdInfo>,
) -> Result<Pin<KBox<Self>>> {
let result = KBox::try_pin_init(RustDebugFs::new(pdev), GFP_KERNEL)?;
// We can still mutate fields through the files which are atomic or mutexed:
result.counter.store(91, Ordering::Relaxed);
{
let mut guard = result.inner.lock();
guard.x = guard.y;
guard.y = 42;
}
Ok(result)
}
}
impl RustDebugFs {
fn build_counter(dir: &Dir) -> impl PinInit<File<AtomicUsize>> + '_ {
dir.read_write_file(c_str!("counter"), AtomicUsize::new(0))
}
fn build_inner(dir: &Dir) -> impl PinInit<File<Mutex<Inner>>> + '_ {
dir.read_write_file(c_str!("pair"), new_mutex!(Inner { x: 3, y: 10 }))
}
fn new(pdev: &platform::Device<Core>) -> impl PinInit<Self, Error> + '_ {
let debugfs = Dir::new(c_str!("sample_debugfs"));
let dev = pdev.as_ref();
try_pin_init! {
Self {
_compatible <- debugfs.read_only_file(
c_str!("compatible"),
dev.fwnode()
.ok_or(ENOENT)?
.property_read::<CString>(c_str!("compatible"))
.required_by(dev)?,
),
counter <- Self::build_counter(&debugfs),
inner <- Self::build_inner(&debugfs),
_debugfs: debugfs,
pdev: pdev.into(),
}
}
}
}

View File

@@ -0,0 +1,134 @@
// SPDX-License-Identifier: GPL-2.0
// Copyright (C) 2025 Google LLC.
//! Sample DebugFS exporting platform driver that demonstrates the use of
//! `Scope::dir` to create a variety of files without the need to separately
//! track them all.
use core::sync::atomic::AtomicUsize;
use kernel::debugfs::{Dir, Scope};
use kernel::prelude::*;
use kernel::sync::Mutex;
use kernel::{c_str, new_mutex, str::CString};
module! {
type: RustScopedDebugFs,
name: "rust_debugfs_scoped",
authors: ["Matthew Maurer"],
description: "Rust Scoped DebugFS usage sample",
license: "GPL",
}
fn remove_file_write(
mod_data: &ModuleData,
reader: &mut kernel::uaccess::UserSliceReader,
) -> Result {
let mut buf = [0u8; 128];
if reader.len() >= buf.len() {
return Err(EINVAL);
}
let n = reader.len();
reader.read_slice(&mut buf[..n])?;
let s = core::str::from_utf8(&buf[..n]).map_err(|_| EINVAL)?.trim();
let nul_idx = s.len();
buf[nul_idx] = 0;
let to_remove = CStr::from_bytes_with_nul(&buf[..nul_idx + 1]).map_err(|_| EINVAL)?;
mod_data
.devices
.lock()
.retain(|device| device.name.as_bytes() != to_remove.as_bytes());
Ok(())
}
fn create_file_write(
mod_data: &ModuleData,
reader: &mut kernel::uaccess::UserSliceReader,
) -> Result {
let mut buf = [0u8; 128];
if reader.len() > buf.len() {
return Err(EINVAL);
}
let n = reader.len();
reader.read_slice(&mut buf[..n])?;
let mut nums = KVec::new();
let s = core::str::from_utf8(&buf[..n]).map_err(|_| EINVAL)?.trim();
let mut items = s.split_whitespace();
let name_str = items.next().ok_or(EINVAL)?;
let name = CString::try_from_fmt(fmt!("{name_str}"))?;
let file_name = CString::try_from_fmt(fmt!("{name_str}"))?;
for sub in items {
nums.push(
AtomicUsize::new(sub.parse().map_err(|_| EINVAL)?),
GFP_KERNEL,
)?;
}
let scope = KBox::pin_init(
mod_data
.device_dir
.scope(DeviceData { name, nums }, &file_name, |dev_data, dir| {
for (idx, val) in dev_data.nums.iter().enumerate() {
let Ok(name) = CString::try_from_fmt(fmt!("{idx}")) else {
return;
};
dir.read_write_file(&name, val);
}
}),
GFP_KERNEL,
)?;
(*mod_data.devices.lock()).push(scope, GFP_KERNEL)?;
Ok(())
}
struct RustScopedDebugFs {
_data: Pin<KBox<Scope<ModuleData>>>,
}
#[pin_data]
struct ModuleData {
device_dir: Dir,
#[pin]
devices: Mutex<KVec<Pin<KBox<Scope<DeviceData>>>>>,
}
impl ModuleData {
fn init(device_dir: Dir) -> impl PinInit<Self> {
pin_init! {
Self {
device_dir: device_dir,
devices <- new_mutex!(KVec::new())
}
}
}
}
struct DeviceData {
name: CString,
nums: KVec<AtomicUsize>,
}
fn init_control(base_dir: &Dir, dyn_dirs: Dir) -> impl PinInit<Scope<ModuleData>> + '_ {
base_dir.scope(
ModuleData::init(dyn_dirs),
c_str!("control"),
|data, dir| {
dir.write_only_callback_file(c_str!("create"), data, &create_file_write);
dir.write_only_callback_file(c_str!("remove"), data, &remove_file_write);
},
)
}
impl kernel::Module for RustScopedDebugFs {
fn init(_module: &'static kernel::ThisModule) -> Result<Self> {
let base_dir = Dir::new(c_str!("rust_scoped_debugfs"));
let dyn_dirs = base_dir.subdir(c_str!("dynamic"));
Ok(Self {
_data: KBox::pin_init(init_control(&base_dir, dyn_dirs), GFP_KERNEL)?,
})
}
}

View File

@@ -5,7 +5,6 @@
//! To make this driver probe, QEMU must be run with `-device pci-testdev`.
use kernel::{
bindings,
device::Core,
dma::{CoherentAllocation, Device, DmaMask},
pci,
@@ -45,10 +44,7 @@ kernel::pci_device_table!(
PCI_TABLE,
MODULE_PCI_TABLE,
<DmaSampleDriver as pci::Driver>::IdInfo,
[(
pci::DeviceId::from_id(bindings::PCI_VENDOR_ID_REDHAT, 0x5),
()
)]
[(pci::DeviceId::from_id(pci::Vendor::REDHAT, 0x5), ())]
);
impl pci::Driver for DmaSampleDriver {

View File

@@ -5,7 +5,7 @@
//! To make this driver probe, QEMU must be run with `-device pci-testdev`.
use kernel::{
auxiliary, bindings, c_str, device::Core, driver, error::Error, pci, prelude::*, InPlaceModule,
auxiliary, c_str, device::Core, driver, error::Error, pci, prelude::*, InPlaceModule,
};
use pin_init::PinInit;
@@ -50,10 +50,7 @@ kernel::pci_device_table!(
PCI_TABLE,
MODULE_PCI_TABLE,
<ParentDriver as pci::Driver>::IdInfo,
[(
pci::DeviceId::from_id(bindings::PCI_VENDOR_ID_REDHAT, 0x5),
()
)]
[(pci::DeviceId::from_id(pci::Vendor::REDHAT, 0x5), ())]
);
impl pci::Driver for ParentDriver {
@@ -81,11 +78,12 @@ impl ParentDriver {
let parent = adev.parent().ok_or(EINVAL)?;
let pdev: &pci::Device = parent.try_into()?;
let vendor = pdev.vendor_id();
dev_info!(
adev.as_ref(),
"Connect auxiliary {} with parent: VendorID={:#x}, DeviceID={:#x}\n",
"Connect auxiliary {} with parent: VendorID={}, DeviceID={:#x}\n",
adev.id(),
pdev.vendor_id(),
vendor,
pdev.device_id()
);

View File

@@ -4,7 +4,7 @@
//!
//! To make this driver probe, QEMU must be run with `-device pci-testdev`.
use kernel::{bindings, c_str, device::Core, devres::Devres, pci, prelude::*, types::ARef};
use kernel::{c_str, device::Core, devres::Devres, pci, prelude::*, sync::aref::ARef};
struct Regs;
@@ -38,7 +38,7 @@ kernel::pci_device_table!(
MODULE_PCI_TABLE,
<SampleDriver as pci::Driver>::IdInfo,
[(
pci::DeviceId::from_id(bindings::PCI_VENDOR_ID_REDHAT, 0x5),
pci::DeviceId::from_id(pci::Vendor::REDHAT, 0x5),
TestIndex::NO_EVENTFD
)]
);
@@ -66,10 +66,11 @@ impl pci::Driver for SampleDriver {
const ID_TABLE: pci::IdTable<Self::IdInfo> = &PCI_TABLE;
fn probe(pdev: &pci::Device<Core>, info: &Self::IdInfo) -> Result<Pin<KBox<Self>>> {
let vendor = pdev.vendor_id();
dev_dbg!(
pdev.as_ref(),
"Probe Rust PCI driver sample (PCI ID: 0x{:x}, 0x{:x}).\n",
pdev.vendor_id(),
"Probe Rust PCI driver sample (PCI ID: {}, 0x{:x}).\n",
vendor,
pdev.device_id()
);

View File

@@ -72,7 +72,7 @@ use kernel::{
of, platform,
prelude::*,
str::CString,
types::ARef,
sync::aref::ARef,
};
struct SampleDriver {