mirror of
git://git.yoctoproject.org/linux-yocto.git
synced 2025-10-22 15:03:53 +02:00
Driver core fixes for 6.15-rc4
Here are some small driver core fixes to resolve a number of reported problems. Included in here are: - driver core sync fix revert to resolve a much reported problem, hopefully this is finally resolved - MAINTAINERS file update, documenting that the driver-core tree is now under a "shared" maintainership model, thanks to Rafael and Danilo for offering to do this! - auxbus documentation and MAINTAINERS file update - MAINTAINERS file update for Rust PCI code - firmware rust binding fixup - software node link fix All of these have been in linux-next for over a week with no reported issues. Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> -----BEGIN PGP SIGNATURE----- iG0EABECAC0WIQT0tgzFv3jCIUoxPcsxR9QN2y37KQUCaAuR4g8cZ3JlZ0Brcm9h aC5jb20ACgkQMUfUDdst+ynU0wCg2YmcO0R7M4+g5SPHEFN0jy2xcaAAn1rMLbAY E4U8Wo13hNMRtzMeI814 =YKYd -----END PGP SIGNATURE----- Merge tag 'driver-core-6.15-rc4' of git://git.kernel.org/pub/scm/linux/kernel/git/driver-core/driver-core Pull driver core fixes from Greg KH: "Here are some small driver core fixes to resolve a number of reported problems. Included in here are: - driver core sync fix revert to resolve a much reported problem, hopefully this is finally resolved - MAINTAINERS file update, documenting that the driver-core tree is now under a "shared" maintainership model, thanks to Rafael and Danilo for offering to do this! - auxbus documentation and MAINTAINERS file update - MAINTAINERS file update for Rust PCI code - firmware rust binding fixup - software node link fix All of these have been in linux-next for over a week with no reported issues" * tag 'driver-core-6.15-rc4' of git://git.kernel.org/pub/scm/linux/kernel/git/driver-core/driver-core: drivers/base/memory: Avoid overhead from for_each_present_section_nr() software node: Prevent link creation failure from causing kobj reference count imbalance device property: Add a note to the fwnode.h drivers/base: Add myself as auxiliary bus reviewer drivers/base: Extend documentation with preferred way to use auxbus driver core: fix potential NULL pointer dereference in dev_uevent() driver core: introduce device_set_driver() helper Revert "drivers: core: synchronize really_probe() and dev_uevent()" MAINTAINERS: update the location of the driver-core git tree rust: firmware: Use `ffi::c_char` type in `FwFunc` MAINTAINERS: pci: add entry for Rust PCI code
This commit is contained in:
commit
3ae7f5093e
17
MAINTAINERS
17
MAINTAINERS
|
@ -3873,8 +3873,9 @@ AUXILIARY BUS DRIVER
|
|||
M: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
|
||||
R: Dave Ertman <david.m.ertman@intel.com>
|
||||
R: Ira Weiny <ira.weiny@intel.com>
|
||||
R: Leon Romanovsky <leon@kernel.org>
|
||||
S: Supported
|
||||
T: git git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/driver-core.git
|
||||
T: git git://git.kernel.org/pub/scm/linux/kernel/git/driver-core/driver-core.git
|
||||
F: Documentation/driver-api/auxiliary_bus.rst
|
||||
F: drivers/base/auxiliary.c
|
||||
F: include/linux/auxiliary_bus.h
|
||||
|
@ -7233,7 +7234,7 @@ M: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
|
|||
M: "Rafael J. Wysocki" <rafael@kernel.org>
|
||||
M: Danilo Krummrich <dakr@kernel.org>
|
||||
S: Supported
|
||||
T: git git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/driver-core.git
|
||||
T: git git://git.kernel.org/pub/scm/linux/kernel/git/driver-core/driver-core.git
|
||||
F: Documentation/core-api/kobject.rst
|
||||
F: drivers/base/
|
||||
F: fs/debugfs/
|
||||
|
@ -13118,7 +13119,7 @@ KERNFS
|
|||
M: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
|
||||
M: Tejun Heo <tj@kernel.org>
|
||||
S: Supported
|
||||
T: git git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/driver-core.git
|
||||
T: git git://git.kernel.org/pub/scm/linux/kernel/git/driver-core/driver-core.git
|
||||
F: fs/kernfs/
|
||||
F: include/linux/kernfs.h
|
||||
|
||||
|
@ -18750,6 +18751,16 @@ F: include/asm-generic/pci*
|
|||
F: include/linux/of_pci.h
|
||||
F: include/linux/pci*
|
||||
F: include/uapi/linux/pci*
|
||||
|
||||
PCI SUBSYSTEM [RUST]
|
||||
M: Danilo Krummrich <dakr@kernel.org>
|
||||
R: Bjorn Helgaas <bhelgaas@google.com>
|
||||
R: Krzysztof Wilczyński <kwilczynski@kernel.org>
|
||||
L: linux-pci@vger.kernel.org
|
||||
S: Maintained
|
||||
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: samples/rust/rust_driver_pci.rs
|
||||
|
||||
|
|
|
@ -156,6 +156,16 @@
|
|||
* },
|
||||
* .ops = my_custom_ops,
|
||||
* };
|
||||
*
|
||||
* Please note that such custom ops approach is valid, but it is hard to implement
|
||||
* it right without global locks per-device to protect from auxiliary_drv removal
|
||||
* during call to that ops. In addition, this implementation lacks proper module
|
||||
* dependency, which causes to load/unload races between auxiliary parent and devices
|
||||
* modules.
|
||||
*
|
||||
* The most easiest way to provide these ops reliably without needing to
|
||||
* have a lock is to EXPORT_SYMBOL*() them and rely on already existing
|
||||
* modules infrastructure for validity and correct dependencies chains.
|
||||
*/
|
||||
|
||||
static const struct auxiliary_device_id *auxiliary_match_id(const struct auxiliary_device_id *id,
|
||||
|
|
|
@ -73,6 +73,7 @@ static inline void subsys_put(struct subsys_private *sp)
|
|||
kset_put(&sp->subsys);
|
||||
}
|
||||
|
||||
struct subsys_private *bus_to_subsys(const struct bus_type *bus);
|
||||
struct subsys_private *class_to_subsys(const struct class *class);
|
||||
|
||||
struct driver_private {
|
||||
|
@ -180,6 +181,22 @@ int driver_add_groups(const struct device_driver *drv, const struct attribute_gr
|
|||
void driver_remove_groups(const struct device_driver *drv, const struct attribute_group **groups);
|
||||
void device_driver_detach(struct device *dev);
|
||||
|
||||
static inline void device_set_driver(struct device *dev, const struct device_driver *drv)
|
||||
{
|
||||
/*
|
||||
* Majority (all?) read accesses to dev->driver happens either
|
||||
* while holding device lock or in bus/driver code that is only
|
||||
* invoked when the device is bound to a driver and there is no
|
||||
* concern of the pointer being changed while it is being read.
|
||||
* However when reading device's uevent file we read driver pointer
|
||||
* without taking device lock (so we do not block there for
|
||||
* arbitrary amount of time). We use WRITE_ONCE() here to prevent
|
||||
* tearing so that READ_ONCE() can safely be used in uevent code.
|
||||
*/
|
||||
// FIXME - this cast should not be needed "soon"
|
||||
WRITE_ONCE(dev->driver, (struct device_driver *)drv);
|
||||
}
|
||||
|
||||
int devres_release_all(struct device *dev);
|
||||
void device_block_probing(void);
|
||||
void device_unblock_probing(void);
|
||||
|
|
|
@ -57,7 +57,7 @@ static int __must_check bus_rescan_devices_helper(struct device *dev,
|
|||
* NULL. A call to subsys_put() must be done when finished with the pointer in
|
||||
* order for it to be properly freed.
|
||||
*/
|
||||
static struct subsys_private *bus_to_subsys(const struct bus_type *bus)
|
||||
struct subsys_private *bus_to_subsys(const struct bus_type *bus)
|
||||
{
|
||||
struct subsys_private *sp = NULL;
|
||||
struct kobject *kobj;
|
||||
|
|
|
@ -2624,6 +2624,35 @@ static const char *dev_uevent_name(const struct kobject *kobj)
|
|||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Try filling "DRIVER=<name>" uevent variable for a device. Because this
|
||||
* function may race with binding and unbinding the device from a driver,
|
||||
* we need to be careful. Binding is generally safe, at worst we miss the
|
||||
* fact that the device is already bound to a driver (but the driver
|
||||
* information that is delivered through uevents is best-effort, it may
|
||||
* become obsolete as soon as it is generated anyways). Unbinding is more
|
||||
* risky as driver pointer is transitioning to NULL, so READ_ONCE() should
|
||||
* be used to make sure we are dealing with the same pointer, and to
|
||||
* ensure that driver structure is not going to disappear from under us
|
||||
* we take bus' drivers klist lock. The assumption that only registered
|
||||
* driver can be bound to a device, and to unregister a driver bus code
|
||||
* will take the same lock.
|
||||
*/
|
||||
static void dev_driver_uevent(const struct device *dev, struct kobj_uevent_env *env)
|
||||
{
|
||||
struct subsys_private *sp = bus_to_subsys(dev->bus);
|
||||
|
||||
if (sp) {
|
||||
scoped_guard(spinlock, &sp->klist_drivers.k_lock) {
|
||||
struct device_driver *drv = READ_ONCE(dev->driver);
|
||||
if (drv)
|
||||
add_uevent_var(env, "DRIVER=%s", drv->name);
|
||||
}
|
||||
|
||||
subsys_put(sp);
|
||||
}
|
||||
}
|
||||
|
||||
static int dev_uevent(const struct kobject *kobj, struct kobj_uevent_env *env)
|
||||
{
|
||||
const struct device *dev = kobj_to_dev(kobj);
|
||||
|
@ -2655,8 +2684,8 @@ static int dev_uevent(const struct kobject *kobj, struct kobj_uevent_env *env)
|
|||
if (dev->type && dev->type->name)
|
||||
add_uevent_var(env, "DEVTYPE=%s", dev->type->name);
|
||||
|
||||
if (dev->driver)
|
||||
add_uevent_var(env, "DRIVER=%s", dev->driver->name);
|
||||
/* Add "DRIVER=%s" variable if the device is bound to a driver */
|
||||
dev_driver_uevent(dev, env);
|
||||
|
||||
/* Add common DT information about the device */
|
||||
of_device_uevent(dev, env);
|
||||
|
@ -2726,11 +2755,8 @@ static ssize_t uevent_show(struct device *dev, struct device_attribute *attr,
|
|||
if (!env)
|
||||
return -ENOMEM;
|
||||
|
||||
/* Synchronize with really_probe() */
|
||||
device_lock(dev);
|
||||
/* let the kset specific function add its keys */
|
||||
retval = kset->uevent_ops->uevent(&dev->kobj, env);
|
||||
device_unlock(dev);
|
||||
if (retval)
|
||||
goto out;
|
||||
|
||||
|
@ -3700,7 +3726,7 @@ done:
|
|||
device_pm_remove(dev);
|
||||
dpm_sysfs_remove(dev);
|
||||
DPMError:
|
||||
dev->driver = NULL;
|
||||
device_set_driver(dev, NULL);
|
||||
bus_remove_device(dev);
|
||||
BusError:
|
||||
device_remove_attrs(dev);
|
||||
|
|
|
@ -550,7 +550,7 @@ static void device_unbind_cleanup(struct device *dev)
|
|||
arch_teardown_dma_ops(dev);
|
||||
kfree(dev->dma_range_map);
|
||||
dev->dma_range_map = NULL;
|
||||
dev->driver = NULL;
|
||||
device_set_driver(dev, NULL);
|
||||
dev_set_drvdata(dev, NULL);
|
||||
if (dev->pm_domain && dev->pm_domain->dismiss)
|
||||
dev->pm_domain->dismiss(dev);
|
||||
|
@ -629,8 +629,7 @@ static int really_probe(struct device *dev, const struct device_driver *drv)
|
|||
}
|
||||
|
||||
re_probe:
|
||||
// FIXME - this cast should not be needed "soon"
|
||||
dev->driver = (struct device_driver *)drv;
|
||||
device_set_driver(dev, drv);
|
||||
|
||||
/* If using pinctrl, bind pins now before probing */
|
||||
ret = pinctrl_bind_pins(dev);
|
||||
|
@ -1014,7 +1013,7 @@ static int __device_attach(struct device *dev, bool allow_async)
|
|||
if (ret == 0)
|
||||
ret = 1;
|
||||
else {
|
||||
dev->driver = NULL;
|
||||
device_set_driver(dev, NULL);
|
||||
ret = 0;
|
||||
}
|
||||
} else {
|
||||
|
|
|
@ -816,21 +816,6 @@ static int add_memory_block(unsigned long block_id, unsigned long state,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int __init add_boot_memory_block(unsigned long base_section_nr)
|
||||
{
|
||||
unsigned long nr;
|
||||
|
||||
for_each_present_section_nr(base_section_nr, nr) {
|
||||
if (nr >= (base_section_nr + sections_per_block))
|
||||
break;
|
||||
|
||||
return add_memory_block(memory_block_id(base_section_nr),
|
||||
MEM_ONLINE, NULL, NULL);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int add_hotplug_memory_block(unsigned long block_id,
|
||||
struct vmem_altmap *altmap,
|
||||
struct memory_group *group)
|
||||
|
@ -957,7 +942,7 @@ static const struct attribute_group *memory_root_attr_groups[] = {
|
|||
void __init memory_dev_init(void)
|
||||
{
|
||||
int ret;
|
||||
unsigned long block_sz, nr;
|
||||
unsigned long block_sz, block_id, nr;
|
||||
|
||||
/* Validate the configured memory block size */
|
||||
block_sz = memory_block_size_bytes();
|
||||
|
@ -970,15 +955,23 @@ void __init memory_dev_init(void)
|
|||
panic("%s() failed to register subsystem: %d\n", __func__, ret);
|
||||
|
||||
/*
|
||||
* Create entries for memory sections that were found
|
||||
* during boot and have been initialized
|
||||
* Create entries for memory sections that were found during boot
|
||||
* and have been initialized. Use @block_id to track the last
|
||||
* handled block and initialize it to an invalid value (ULONG_MAX)
|
||||
* to bypass the block ID matching check for the first present
|
||||
* block so that it can be covered.
|
||||
*/
|
||||
for (nr = 0; nr <= __highest_present_section_nr;
|
||||
nr += sections_per_block) {
|
||||
ret = add_boot_memory_block(nr);
|
||||
if (ret)
|
||||
panic("%s() failed to add memory block: %d\n", __func__,
|
||||
ret);
|
||||
block_id = ULONG_MAX;
|
||||
for_each_present_section_nr(0, nr) {
|
||||
if (block_id != ULONG_MAX && memory_block_id(nr) == block_id)
|
||||
continue;
|
||||
|
||||
block_id = memory_block_id(nr);
|
||||
ret = add_memory_block(block_id, MEM_ONLINE, NULL, NULL);
|
||||
if (ret) {
|
||||
panic("%s() failed to add memory block: %d\n",
|
||||
__func__, ret);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1080,6 +1080,7 @@ void software_node_notify(struct device *dev)
|
|||
if (!swnode)
|
||||
return;
|
||||
|
||||
kobject_get(&swnode->kobj);
|
||||
ret = sysfs_create_link(&dev->kobj, &swnode->kobj, "software_node");
|
||||
if (ret)
|
||||
return;
|
||||
|
@ -1089,8 +1090,6 @@ void software_node_notify(struct device *dev)
|
|||
sysfs_remove_link(&dev->kobj, "software_node");
|
||||
return;
|
||||
}
|
||||
|
||||
kobject_get(&swnode->kobj);
|
||||
}
|
||||
|
||||
void software_node_notify_remove(struct device *dev)
|
||||
|
|
|
@ -2,6 +2,11 @@
|
|||
/*
|
||||
* fwnode.h - Firmware device node object handle type definition.
|
||||
*
|
||||
* This header file provides low-level data types and definitions for firmware
|
||||
* and device property providers. The respective API header files supplied by
|
||||
* them should contain all of the requisite data types and definitions for end
|
||||
* users, so including it directly should not be necessary.
|
||||
*
|
||||
* Copyright (C) 2015, Intel Corporation
|
||||
* Author: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
|
||||
*/
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
//!
|
||||
//! C header: [`include/linux/firmware.h`](srctree/include/linux/firmware.h)
|
||||
|
||||
use crate::{bindings, device::Device, error::Error, error::Result, str::CStr};
|
||||
use crate::{bindings, device::Device, error::Error, error::Result, ffi, str::CStr};
|
||||
use core::ptr::NonNull;
|
||||
|
||||
/// # Invariants
|
||||
|
@ -12,7 +12,11 @@ use core::ptr::NonNull;
|
|||
/// One of the following: `bindings::request_firmware`, `bindings::firmware_request_nowarn`,
|
||||
/// `bindings::firmware_request_platform`, `bindings::request_firmware_direct`.
|
||||
struct FwFunc(
|
||||
unsafe extern "C" fn(*mut *const bindings::firmware, *const u8, *mut bindings::device) -> i32,
|
||||
unsafe extern "C" fn(
|
||||
*mut *const bindings::firmware,
|
||||
*const ffi::c_char,
|
||||
*mut bindings::device,
|
||||
) -> i32,
|
||||
);
|
||||
|
||||
impl FwFunc {
|
||||
|
|
Loading…
Reference in New Issue
Block a user