mirror of
git://git.yoctoproject.org/linux-yocto.git
synced 2025-10-23 07:23:12 +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>
|
M: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
|
||||||
R: Dave Ertman <david.m.ertman@intel.com>
|
R: Dave Ertman <david.m.ertman@intel.com>
|
||||||
R: Ira Weiny <ira.weiny@intel.com>
|
R: Ira Weiny <ira.weiny@intel.com>
|
||||||
|
R: Leon Romanovsky <leon@kernel.org>
|
||||||
S: Supported
|
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: Documentation/driver-api/auxiliary_bus.rst
|
||||||
F: drivers/base/auxiliary.c
|
F: drivers/base/auxiliary.c
|
||||||
F: include/linux/auxiliary_bus.h
|
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: "Rafael J. Wysocki" <rafael@kernel.org>
|
||||||
M: Danilo Krummrich <dakr@kernel.org>
|
M: Danilo Krummrich <dakr@kernel.org>
|
||||||
S: Supported
|
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: Documentation/core-api/kobject.rst
|
||||||
F: drivers/base/
|
F: drivers/base/
|
||||||
F: fs/debugfs/
|
F: fs/debugfs/
|
||||||
|
@ -13118,7 +13119,7 @@ KERNFS
|
||||||
M: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
|
M: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
|
||||||
M: Tejun Heo <tj@kernel.org>
|
M: Tejun Heo <tj@kernel.org>
|
||||||
S: Supported
|
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: fs/kernfs/
|
||||||
F: include/linux/kernfs.h
|
F: include/linux/kernfs.h
|
||||||
|
|
||||||
|
@ -18750,6 +18751,16 @@ F: include/asm-generic/pci*
|
||||||
F: include/linux/of_pci.h
|
F: include/linux/of_pci.h
|
||||||
F: include/linux/pci*
|
F: include/linux/pci*
|
||||||
F: include/uapi/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: rust/kernel/pci.rs
|
||||||
F: samples/rust/rust_driver_pci.rs
|
F: samples/rust/rust_driver_pci.rs
|
||||||
|
|
||||||
|
|
|
@ -156,6 +156,16 @@
|
||||||
* },
|
* },
|
||||||
* .ops = my_custom_ops,
|
* .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,
|
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);
|
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 subsys_private *class_to_subsys(const struct class *class);
|
||||||
|
|
||||||
struct driver_private {
|
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 driver_remove_groups(const struct device_driver *drv, const struct attribute_group **groups);
|
||||||
void device_driver_detach(struct device *dev);
|
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);
|
int devres_release_all(struct device *dev);
|
||||||
void device_block_probing(void);
|
void device_block_probing(void);
|
||||||
void device_unblock_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
|
* NULL. A call to subsys_put() must be done when finished with the pointer in
|
||||||
* order for it to be properly freed.
|
* 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 subsys_private *sp = NULL;
|
||||||
struct kobject *kobj;
|
struct kobject *kobj;
|
||||||
|
|
|
@ -2624,6 +2624,35 @@ static const char *dev_uevent_name(const struct kobject *kobj)
|
||||||
return NULL;
|
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)
|
static int dev_uevent(const struct kobject *kobj, struct kobj_uevent_env *env)
|
||||||
{
|
{
|
||||||
const struct device *dev = kobj_to_dev(kobj);
|
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)
|
if (dev->type && dev->type->name)
|
||||||
add_uevent_var(env, "DEVTYPE=%s", dev->type->name);
|
add_uevent_var(env, "DEVTYPE=%s", dev->type->name);
|
||||||
|
|
||||||
if (dev->driver)
|
/* Add "DRIVER=%s" variable if the device is bound to a driver */
|
||||||
add_uevent_var(env, "DRIVER=%s", dev->driver->name);
|
dev_driver_uevent(dev, env);
|
||||||
|
|
||||||
/* Add common DT information about the device */
|
/* Add common DT information about the device */
|
||||||
of_device_uevent(dev, env);
|
of_device_uevent(dev, env);
|
||||||
|
@ -2726,11 +2755,8 @@ static ssize_t uevent_show(struct device *dev, struct device_attribute *attr,
|
||||||
if (!env)
|
if (!env)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
/* Synchronize with really_probe() */
|
|
||||||
device_lock(dev);
|
|
||||||
/* let the kset specific function add its keys */
|
/* let the kset specific function add its keys */
|
||||||
retval = kset->uevent_ops->uevent(&dev->kobj, env);
|
retval = kset->uevent_ops->uevent(&dev->kobj, env);
|
||||||
device_unlock(dev);
|
|
||||||
if (retval)
|
if (retval)
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
|
@ -3700,7 +3726,7 @@ done:
|
||||||
device_pm_remove(dev);
|
device_pm_remove(dev);
|
||||||
dpm_sysfs_remove(dev);
|
dpm_sysfs_remove(dev);
|
||||||
DPMError:
|
DPMError:
|
||||||
dev->driver = NULL;
|
device_set_driver(dev, NULL);
|
||||||
bus_remove_device(dev);
|
bus_remove_device(dev);
|
||||||
BusError:
|
BusError:
|
||||||
device_remove_attrs(dev);
|
device_remove_attrs(dev);
|
||||||
|
|
|
@ -550,7 +550,7 @@ static void device_unbind_cleanup(struct device *dev)
|
||||||
arch_teardown_dma_ops(dev);
|
arch_teardown_dma_ops(dev);
|
||||||
kfree(dev->dma_range_map);
|
kfree(dev->dma_range_map);
|
||||||
dev->dma_range_map = NULL;
|
dev->dma_range_map = NULL;
|
||||||
dev->driver = NULL;
|
device_set_driver(dev, NULL);
|
||||||
dev_set_drvdata(dev, NULL);
|
dev_set_drvdata(dev, NULL);
|
||||||
if (dev->pm_domain && dev->pm_domain->dismiss)
|
if (dev->pm_domain && dev->pm_domain->dismiss)
|
||||||
dev->pm_domain->dismiss(dev);
|
dev->pm_domain->dismiss(dev);
|
||||||
|
@ -629,8 +629,7 @@ static int really_probe(struct device *dev, const struct device_driver *drv)
|
||||||
}
|
}
|
||||||
|
|
||||||
re_probe:
|
re_probe:
|
||||||
// FIXME - this cast should not be needed "soon"
|
device_set_driver(dev, drv);
|
||||||
dev->driver = (struct device_driver *)drv;
|
|
||||||
|
|
||||||
/* If using pinctrl, bind pins now before probing */
|
/* If using pinctrl, bind pins now before probing */
|
||||||
ret = pinctrl_bind_pins(dev);
|
ret = pinctrl_bind_pins(dev);
|
||||||
|
@ -1014,7 +1013,7 @@ static int __device_attach(struct device *dev, bool allow_async)
|
||||||
if (ret == 0)
|
if (ret == 0)
|
||||||
ret = 1;
|
ret = 1;
|
||||||
else {
|
else {
|
||||||
dev->driver = NULL;
|
device_set_driver(dev, NULL);
|
||||||
ret = 0;
|
ret = 0;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -816,21 +816,6 @@ static int add_memory_block(unsigned long block_id, unsigned long state,
|
||||||
return 0;
|
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,
|
static int add_hotplug_memory_block(unsigned long block_id,
|
||||||
struct vmem_altmap *altmap,
|
struct vmem_altmap *altmap,
|
||||||
struct memory_group *group)
|
struct memory_group *group)
|
||||||
|
@ -957,7 +942,7 @@ static const struct attribute_group *memory_root_attr_groups[] = {
|
||||||
void __init memory_dev_init(void)
|
void __init memory_dev_init(void)
|
||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
unsigned long block_sz, nr;
|
unsigned long block_sz, block_id, nr;
|
||||||
|
|
||||||
/* Validate the configured memory block size */
|
/* Validate the configured memory block size */
|
||||||
block_sz = memory_block_size_bytes();
|
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);
|
panic("%s() failed to register subsystem: %d\n", __func__, ret);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Create entries for memory sections that were found
|
* Create entries for memory sections that were found during boot
|
||||||
* during boot and have been initialized
|
* 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;
|
block_id = ULONG_MAX;
|
||||||
nr += sections_per_block) {
|
for_each_present_section_nr(0, nr) {
|
||||||
ret = add_boot_memory_block(nr);
|
if (block_id != ULONG_MAX && memory_block_id(nr) == block_id)
|
||||||
if (ret)
|
continue;
|
||||||
panic("%s() failed to add memory block: %d\n", __func__,
|
|
||||||
ret);
|
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)
|
if (!swnode)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
kobject_get(&swnode->kobj);
|
||||||
ret = sysfs_create_link(&dev->kobj, &swnode->kobj, "software_node");
|
ret = sysfs_create_link(&dev->kobj, &swnode->kobj, "software_node");
|
||||||
if (ret)
|
if (ret)
|
||||||
return;
|
return;
|
||||||
|
@ -1089,8 +1090,6 @@ void software_node_notify(struct device *dev)
|
||||||
sysfs_remove_link(&dev->kobj, "software_node");
|
sysfs_remove_link(&dev->kobj, "software_node");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
kobject_get(&swnode->kobj);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void software_node_notify_remove(struct device *dev)
|
void software_node_notify_remove(struct device *dev)
|
||||||
|
|
|
@ -2,6 +2,11 @@
|
||||||
/*
|
/*
|
||||||
* fwnode.h - Firmware device node object handle type definition.
|
* 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
|
* Copyright (C) 2015, Intel Corporation
|
||||||
* Author: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
|
* Author: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
//!
|
//!
|
||||||
//! C header: [`include/linux/firmware.h`](srctree/include/linux/firmware.h)
|
//! 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;
|
use core::ptr::NonNull;
|
||||||
|
|
||||||
/// # Invariants
|
/// # Invariants
|
||||||
|
@ -12,7 +12,11 @@ use core::ptr::NonNull;
|
||||||
/// One of the following: `bindings::request_firmware`, `bindings::firmware_request_nowarn`,
|
/// One of the following: `bindings::request_firmware`, `bindings::firmware_request_nowarn`,
|
||||||
/// `bindings::firmware_request_platform`, `bindings::request_firmware_direct`.
|
/// `bindings::firmware_request_platform`, `bindings::request_firmware_direct`.
|
||||||
struct FwFunc(
|
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 {
|
impl FwFunc {
|
||||||
|
|
Loading…
Reference in New Issue
Block a user