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
+20
View File
@@ -7021,6 +7021,21 @@ F: drivers/devfreq/event/
F: include/dt-bindings/pmu/exynos_ppmu.h
F: include/linux/devfreq-event.h
DEVICE I/O & IRQ [RUST]
M: Danilo Krummrich <dakr@kernel.org>
M: Alice Ryhl <aliceryhl@google.com>
M: Daniel Almeida <daniel.almeida@collabora.com>
L: rust-for-linux@vger.kernel.org
S: Supported
W: https://rust-for-linux.com
B: https://github.com/Rust-for-Linux/linux/issues
C: https://rust-for-linux.zulipchat.com
T: git git://git.kernel.org/pub/scm/linux/kernel/git/driver-core/driver-core.git
F: rust/kernel/io.rs
F: rust/kernel/io/
F: rust/kernel/irq.rs
F: rust/kernel/irq/
DEVICE RESOURCE MANAGEMENT HELPERS
M: Hans de Goede <hansg@kernel.org>
R: Matti Vaittinen <mazziesaccount@gmail.com>
@@ -7472,6 +7487,8 @@ F: include/linux/kobj*
F: include/linux/property.h
F: include/linux/sysfs.h
F: lib/kobj*
F: rust/kernel/debugfs.rs
F: rust/kernel/debugfs/
F: rust/kernel/device.rs
F: rust/kernel/device/
F: rust/kernel/device_id.rs
@@ -7479,6 +7496,8 @@ F: rust/kernel/devres.rs
F: rust/kernel/driver.rs
F: rust/kernel/faux.rs
F: rust/kernel/platform.rs
F: samples/rust/rust_debugfs.rs
F: samples/rust/rust_debugfs_scoped.rs
F: samples/rust/rust_driver_platform.rs
F: samples/rust/rust_driver_faux.rs
@@ -19574,6 +19593,7 @@ C: irc://irc.oftc.net/linux-pci
T: git git://git.kernel.org/pub/scm/linux/kernel/git/pci/pci.git
F: rust/helpers/pci.c
F: rust/kernel/pci.rs
F: rust/kernel/pci/
F: samples/rust/rust_driver_pci.rs
PCIE BANDWIDTH CONTROLLER
+12 -15
View File
@@ -171,17 +171,18 @@
static const struct auxiliary_device_id *auxiliary_match_id(const struct auxiliary_device_id *id,
const struct auxiliary_device *auxdev)
{
const char *auxdev_name = dev_name(&auxdev->dev);
const char *p = strrchr(auxdev_name, '.');
int match_size;
if (!p)
return NULL;
match_size = p - auxdev_name;
for (; id->name[0]; id++) {
const char *p = strrchr(dev_name(&auxdev->dev), '.');
int match_size;
if (!p)
continue;
match_size = p - dev_name(&auxdev->dev);
/* use dev_name(&auxdev->dev) prefix before last '.' char to match to */
if (strlen(id->name) == match_size &&
!strncmp(dev_name(&auxdev->dev), id->name, match_size))
!strncmp(auxdev_name, id->name, match_size))
return id;
}
return NULL;
@@ -217,17 +218,14 @@ static int auxiliary_bus_probe(struct device *dev)
struct auxiliary_device *auxdev = to_auxiliary_dev(dev);
int ret;
ret = dev_pm_domain_attach(dev, PD_FLAG_ATTACH_POWER_ON);
ret = dev_pm_domain_attach(dev, PD_FLAG_ATTACH_POWER_ON |
PD_FLAG_DETACH_POWER_OFF);
if (ret) {
dev_warn(dev, "Failed to attach to PM Domain : %d\n", ret);
return ret;
}
ret = auxdrv->probe(auxdev, auxiliary_match_id(auxdrv->id_table, auxdev));
if (ret)
dev_pm_domain_detach(dev, true);
return ret;
return auxdrv->probe(auxdev, auxiliary_match_id(auxdrv->id_table, auxdev));
}
static void auxiliary_bus_remove(struct device *dev)
@@ -237,7 +235,6 @@ static void auxiliary_bus_remove(struct device *dev)
if (auxdrv->remove)
auxdrv->remove(auxdev);
dev_pm_domain_detach(dev, true);
}
static void auxiliary_bus_shutdown(struct device *dev)
+23 -4
View File
@@ -3994,8 +3994,8 @@ const char *device_get_devnode(const struct device *dev,
/**
* device_for_each_child - device child iterator.
* @parent: parent struct device.
* @fn: function to be called for each device.
* @data: data for the callback.
* @fn: function to be called for each device.
*
* Iterate over @parent's child devices, and call @fn for each,
* passing it @data.
@@ -4024,8 +4024,8 @@ EXPORT_SYMBOL_GPL(device_for_each_child);
/**
* device_for_each_child_reverse - device child iterator in reversed order.
* @parent: parent struct device.
* @fn: function to be called for each device.
* @data: data for the callback.
* @fn: function to be called for each device.
*
* Iterate over @parent's child devices, and call @fn for each,
* passing it @data.
@@ -4055,8 +4055,8 @@ EXPORT_SYMBOL_GPL(device_for_each_child_reverse);
* device_for_each_child_reverse_from - device child iterator in reversed order.
* @parent: parent struct device.
* @from: optional starting point in child list
* @fn: function to be called for each device.
* @data: data for the callback.
* @fn: function to be called for each device.
*
* Iterate over @parent's child devices, starting at @from, and call @fn
* for each, passing it @data. This helper is identical to
@@ -4089,8 +4089,8 @@ EXPORT_SYMBOL_GPL(device_for_each_child_reverse_from);
/**
* device_find_child - device iterator for locating a particular device.
* @parent: parent struct device
* @match: Callback function to check device
* @data: Data to pass to match function
* @match: Callback function to check device
*
* This is similar to the device_for_each_child() function above, but it
* returns a reference to a device that is 'found' for later use, as
@@ -5278,6 +5278,25 @@ void device_set_node(struct device *dev, struct fwnode_handle *fwnode)
}
EXPORT_SYMBOL_GPL(device_set_node);
/**
* get_dev_from_fwnode - Obtain a reference count of the struct device the
* struct fwnode_handle is associated with.
* @fwnode: The pointer to the struct fwnode_handle to obtain the struct device
* reference count of.
*
* This function obtains a reference count of the device the device pointer
* embedded in the struct fwnode_handle points to.
*
* Note that the struct device pointer embedded in struct fwnode_handle does
* *not* have a reference count of the struct device itself.
*
* Hence, it is a UAF (and thus a bug) to call this function if the caller can't
* guarantee that the last reference count of the corresponding struct device is
* not dropped concurrently.
*
* This is possible since struct fwnode_handle has its own reference count and
* hence can out-live the struct device it is associated with.
*/
struct device *get_dev_from_fwnode(struct fwnode_handle *fwnode)
{
return get_device((fwnode)->dev);
+1 -1
View File
@@ -325,7 +325,7 @@ static void cpu_device_release(struct device *dev)
* This is an empty function to prevent the driver core from spitting a
* warning at us. Yes, I know this is directly opposite of what the
* documentation for the driver core and kobjects say, and the author
* of this code has already been publically ridiculed for doing
* of this code has already been publicly ridiculed for doing
* something as foolish as this. However, at this point in time, it is
* the only way to handle the issue of statically allocated cpu
* devices. The different architectures will have their cpu device
+1
View File
@@ -155,6 +155,7 @@ struct faux_device *faux_device_create_with_groups(const char *name,
dev->parent = &faux_bus_root;
dev->bus = &faux_bus_type;
dev_set_name(dev, "%s", name);
device_set_pm_not_required(dev);
ret = device_add(dev);
if (ret) {
+2 -3
View File
@@ -844,7 +844,7 @@ swnode_register(const struct software_node *node, struct swnode *parent,
* of this function or by ordering the array such that parent comes before
* child.
*/
int software_node_register_node_group(const struct software_node **node_group)
int software_node_register_node_group(const struct software_node * const *node_group)
{
unsigned int i;
int ret;
@@ -877,8 +877,7 @@ EXPORT_SYMBOL_GPL(software_node_register_node_group);
* remove the nodes individually, in the correct order (child before
* parent).
*/
void software_node_unregister_node_group(
const struct software_node **node_group)
void software_node_unregister_node_group(const struct software_node * const *node_group)
{
unsigned int i = 0;
+28 -5
View File
@@ -1,6 +1,14 @@
// SPDX-License-Identifier: GPL-2.0
use kernel::{auxiliary, bindings, c_str, device::Core, pci, prelude::*, sizes::SZ_16M, sync::Arc};
use kernel::{
auxiliary, c_str,
device::Core,
pci,
pci::{Class, ClassMask, Vendor},
prelude::*,
sizes::SZ_16M,
sync::Arc,
};
use crate::gpu::Gpu;
@@ -18,10 +26,25 @@ kernel::pci_device_table!(
PCI_TABLE,
MODULE_PCI_TABLE,
<NovaCore as pci::Driver>::IdInfo,
[(
pci::DeviceId::from_id(bindings::PCI_VENDOR_ID_NVIDIA, bindings::PCI_ANY_ID as u32),
()
)]
[
// Modern NVIDIA GPUs will show up as either VGA or 3D controllers.
(
pci::DeviceId::from_class_and_vendor(
Class::DISPLAY_VGA,
ClassMask::ClassSubclass,
Vendor::NVIDIA
),
()
),
(
pci::DeviceId::from_class_and_vendor(
Class::DISPLAY_3D,
ClassMask::ClassSubclass,
Vendor::NVIDIA
),
()
),
]
);
impl pci::Driver for NovaCore {
+5 -17
View File
@@ -97,12 +97,9 @@ static ssize_t sysfs_kf_bin_read(struct kernfs_open_file *of, char *buf,
count = size - pos;
}
if (!battr->read && !battr->read_new)
if (!battr->read)
return -EIO;
if (battr->read_new)
return battr->read_new(of->file, kobj, battr, buf, pos, count);
return battr->read(of->file, kobj, battr, buf, pos, count);
}
@@ -161,12 +158,9 @@ static ssize_t sysfs_kf_bin_write(struct kernfs_open_file *of, char *buf,
if (!count)
return 0;
if (!battr->write && !battr->write_new)
if (!battr->write)
return -EIO;
if (battr->write_new)
return battr->write_new(of->file, kobj, battr, buf, pos, count);
return battr->write(of->file, kobj, battr, buf, pos, count);
}
@@ -335,19 +329,13 @@ int sysfs_add_bin_file_mode_ns(struct kernfs_node *parent,
const struct kernfs_ops *ops;
struct kernfs_node *kn;
if (battr->read && battr->read_new)
return -EINVAL;
if (battr->write && battr->write_new)
return -EINVAL;
if (battr->mmap)
ops = &sysfs_bin_kfops_mmap;
else if ((battr->read || battr->read_new) && (battr->write || battr->write_new))
else if (battr->read && battr->write)
ops = &sysfs_bin_kfops_rw;
else if (battr->read || battr->read_new)
else if (battr->read)
ops = &sysfs_bin_kfops_ro;
else if (battr->write || battr->write_new)
else if (battr->write)
ops = &sysfs_bin_kfops_wo;
else
ops = &sysfs_file_kfops_empty;
+3
View File
@@ -851,6 +851,9 @@ static inline bool device_pm_not_required(struct device *dev)
static inline void device_set_pm_not_required(struct device *dev)
{
dev->power.no_pm = true;
#ifdef CONFIG_PM
dev->power.no_callbacks = true;
#endif
}
static inline void dev_pm_syscore_device(struct device *dev, bool val)
+2 -2
View File
@@ -574,8 +574,8 @@ const struct software_node *
software_node_find_by_name(const struct software_node *parent,
const char *name);
int software_node_register_node_group(const struct software_node **node_group);
void software_node_unregister_node_group(const struct software_node **node_group);
int software_node_register_node_group(const struct software_node * const *node_group);
void software_node_unregister_node_group(const struct software_node * const *node_group);
int software_node_register(const struct software_node *node);
void software_node_unregister(const struct software_node *node);
+2 -9
View File
@@ -106,10 +106,7 @@ struct attribute_group {
const struct bin_attribute *,
int);
struct attribute **attrs;
union {
const struct bin_attribute *const *bin_attrs;
const struct bin_attribute *const *bin_attrs_new;
};
const struct bin_attribute *const *bin_attrs;
};
#define SYSFS_PREALLOC 010000
@@ -293,7 +290,7 @@ __ATTRIBUTE_GROUPS(_name)
#define BIN_ATTRIBUTE_GROUPS(_name) \
static const struct attribute_group _name##_group = { \
.bin_attrs_new = _name##_attrs, \
.bin_attrs = _name##_attrs, \
}; \
__ATTRIBUTE_GROUPS(_name)
@@ -308,12 +305,8 @@ struct bin_attribute {
struct address_space *(*f_mapping)(void);
ssize_t (*read)(struct file *, struct kobject *, const struct bin_attribute *,
char *, loff_t, size_t);
ssize_t (*read_new)(struct file *, struct kobject *, const struct bin_attribute *,
char *, loff_t, size_t);
ssize_t (*write)(struct file *, struct kobject *, const struct bin_attribute *,
char *, loff_t, size_t);
ssize_t (*write_new)(struct file *, struct kobject *,
const struct bin_attribute *, char *, loff_t, size_t);
loff_t (*llseek)(struct file *, struct kobject *, const struct bin_attribute *,
loff_t, int);
int (*mmap)(struct file *, struct kobject *, const struct bin_attribute *attr,
+1 -1
View File
@@ -12234,7 +12234,7 @@ static const struct attribute_group *pmu_dev_groups[] = {
};
static int pmu_bus_running;
static struct bus_type pmu_bus = {
static const struct bus_type pmu_bus = {
.name = "event_source",
.dev_groups = pmu_dev_groups,
};
+2
View File
@@ -46,12 +46,14 @@
#include <linux/cpufreq.h>
#include <linux/cpumask.h>
#include <linux/cred.h>
#include <linux/debugfs.h>
#include <linux/device/faux.h>
#include <linux/dma-mapping.h>
#include <linux/errname.h>
#include <linux/ethtool.h>
#include <linux/file.h>
#include <linux/firmware.h>
#include <linux/interrupt.h>
#include <linux/fs.h>
#include <linux/ioport.h>
#include <linux/jiffies.h>
+2
View File
@@ -24,6 +24,7 @@
#include "dma.c"
#include "drm.c"
#include "err.c"
#include "irq.c"
#include "fs.c"
#include "io.c"
#include "jump_label.c"
@@ -36,6 +37,7 @@
#include "pid_namespace.c"
#include "platform.c"
#include "poll.c"
#include "processor.c"
#include "property.c"
#include "rbtree.c"
#include "rcu.c"
+9
View File
@@ -0,0 +1,9 @@
// SPDX-License-Identifier: GPL-2.0
#include <linux/interrupt.h>
int rust_helper_request_irq(unsigned int irq, irq_handler_t handler,
unsigned long flags, const char *name, void *dev)
{
return request_irq(irq, handler, flags, name, dev);
}
+18
View File
@@ -2,6 +2,16 @@
#include <linux/pci.h>
u16 rust_helper_pci_dev_id(struct pci_dev *dev)
{
return PCI_DEVID(dev->bus->number, dev->devfn);
}
resource_size_t rust_helper_pci_resource_start(struct pci_dev *pdev, int bar)
{
return pci_resource_start(pdev, bar);
}
resource_size_t rust_helper_pci_resource_len(struct pci_dev *pdev, int bar)
{
return pci_resource_len(pdev, bar);
@@ -11,3 +21,11 @@ bool rust_helper_dev_is_pci(const struct device *dev)
{
return dev_is_pci(dev);
}
#ifndef CONFIG_PCI_MSI
int rust_helper_pci_irq_vector(struct pci_dev *pdev, unsigned int nvec)
{
return pci_irq_vector(pdev, nvec);
}
#endif
+8
View File
@@ -0,0 +1,8 @@
// SPDX-License-Identifier: GPL-2.0
#include <linux/processor.h>
void rust_helper_cpu_relax(void)
{
cpu_relax();
}
+2 -2
View File
@@ -55,7 +55,7 @@ impl<T: Driver + 'static> Adapter<T> {
extern "C" fn probe_callback(
adev: *mut bindings::auxiliary_device,
id: *const bindings::auxiliary_device_id,
) -> kernel::ffi::c_int {
) -> c_int {
// SAFETY: The auxiliary bus only ever calls the probe callback with a valid pointer to a
// `struct auxiliary_device`.
//
@@ -245,7 +245,7 @@ kernel::impl_device_context_deref!(unsafe { Device });
kernel::impl_device_context_into_aref!(Device);
// SAFETY: Instances of `Device` are always reference-counted.
unsafe impl crate::types::AlwaysRefCounted for Device {
unsafe impl crate::sync::aref::AlwaysRefCounted for Device {
fn inc_ref(&self) {
// SAFETY: The existence of a shared reference guarantees that the refcount is non-zero.
unsafe { bindings::get_device(self.as_ref().as_raw()) };
File diff suppressed because it is too large Load Diff
+122
View File
@@ -0,0 +1,122 @@
// SPDX-License-Identifier: GPL-2.0
// Copyright (C) 2025 Google LLC.
//! Adapters which allow the user to supply a write or read implementation as a value rather
//! than a trait implementation. If provided, it will override the trait implementation.
use super::{Reader, Writer};
use crate::prelude::*;
use crate::uaccess::UserSliceReader;
use core::fmt;
use core::fmt::Formatter;
use core::marker::PhantomData;
use core::ops::Deref;
/// # Safety
///
/// To implement this trait, it must be safe to cast a `&Self` to a `&Inner`.
/// It is intended for use in unstacking adapters out of `FileOps` backings.
pub(crate) unsafe trait Adapter {
type Inner;
}
/// Adapter to implement `Reader` via a callback with the same representation as `T`.
///
/// * Layer it on top of `WriterAdapter` if you want to add a custom callback for `write`.
/// * Layer it on top of `NoWriter` to pass through any support present on the underlying type.
///
/// # Invariants
///
/// If an instance for `WritableAdapter<_, W>` is constructed, `W` is inhabited.
#[repr(transparent)]
pub(crate) struct WritableAdapter<D, W> {
inner: D,
_writer: PhantomData<W>,
}
// SAFETY: Stripping off the adapter only removes constraints
unsafe impl<D, W> Adapter for WritableAdapter<D, W> {
type Inner = D;
}
impl<D: Writer, W> Writer for WritableAdapter<D, W> {
fn write(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
self.inner.write(fmt)
}
}
impl<D: Deref, W> Reader for WritableAdapter<D, W>
where
W: Fn(&D::Target, &mut UserSliceReader) -> Result + Send + Sync + 'static,
{
fn read_from_slice(&self, reader: &mut UserSliceReader) -> Result {
// SAFETY: WritableAdapter<_, W> can only be constructed if W is inhabited
let w: &W = unsafe { materialize_zst() };
w(self.inner.deref(), reader)
}
}
/// Adapter to implement `Writer` via a callback with the same representation as `T`.
///
/// # Invariants
///
/// If an instance for `FormatAdapter<_, F>` is constructed, `F` is inhabited.
#[repr(transparent)]
pub(crate) struct FormatAdapter<D, F> {
inner: D,
_formatter: PhantomData<F>,
}
impl<D, F> Deref for FormatAdapter<D, F> {
type Target = D;
fn deref(&self) -> &D {
&self.inner
}
}
impl<D, F> Writer for FormatAdapter<D, F>
where
F: Fn(&D, &mut Formatter<'_>) -> fmt::Result + 'static,
{
fn write(&self, fmt: &mut Formatter<'_>) -> fmt::Result {
// SAFETY: FormatAdapter<_, F> can only be constructed if F is inhabited
let f: &F = unsafe { materialize_zst() };
f(&self.inner, fmt)
}
}
// SAFETY: Stripping off the adapter only removes constraints
unsafe impl<D, F> Adapter for FormatAdapter<D, F> {
type Inner = D;
}
#[repr(transparent)]
pub(crate) struct NoWriter<D> {
inner: D,
}
// SAFETY: Stripping off the adapter only removes constraints
unsafe impl<D> Adapter for NoWriter<D> {
type Inner = D;
}
impl<D> Deref for NoWriter<D> {
type Target = D;
fn deref(&self) -> &D {
&self.inner
}
}
/// For types with a unique value, produce a static reference to it.
///
/// # Safety
///
/// The caller asserts that F is inhabited
unsafe fn materialize_zst<F>() -> &'static F {
const { assert!(core::mem::size_of::<F>() == 0) };
let zst_dangle: core::ptr::NonNull<F> = core::ptr::NonNull::dangling();
// SAFETY: While the pointer is dangling, it is a dangling pointer to a ZST, based on the
// assertion above. The type is also inhabited, by the caller's assertion. This means
// we can materialize it.
unsafe { zst_dangle.as_ref() }
}

Some files were not shown because too many files have changed in this diff Show More