mirror of
https://github.com/AuxXxilium/linux_dsm_epyc7002.git
synced 2024-11-24 01:20:52 +07:00
Driver core patches for 5.8-rc1
Here is the set of driver core patches for 5.8-rc1. Not all that huge this release, just a number of small fixes and updates: - software node fixes - kobject now sends KOBJ_REMOVE when it is removed from sysfs, not when it is removed from memory (which could come much later) - device link additions and fixes based on testing on more devices - firmware core cleanups - other minor changes, full details in the shortlog All have been in linux-next for a while with no reported issues. Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> -----BEGIN PGP SIGNATURE----- iG0EABECAC0WIQT0tgzFv3jCIUoxPcsxR9QN2y37KQUCXtzmXg8cZ3JlZ0Brcm9h aC5jb20ACgkQMUfUDdst+ymaAQCfZZ9prH3AMLF7DIkG3vMw0njLXt0An2FxrKYU wetHRG4KL9vTkdz7+TqU =t5LE -----END PGP SIGNATURE----- Merge tag 'driver-core-5.8-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/driver-core Pull driver core updates from Greg KH: "Here is the set of driver core patches for 5.8-rc1. Not all that huge this release, just a number of small fixes and updates: - software node fixes - kobject now sends KOBJ_REMOVE when it is removed from sysfs, not when it is removed from memory (which could come much later) - device link additions and fixes based on testing on more devices - firmware core cleanups - other minor changes, full details in the shortlog All have been in linux-next for a while with no reported issues" * tag 'driver-core-5.8-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/driver-core: (23 commits) driver core: Update device link status correctly for SYNC_STATE_ONLY links firmware_loader: change enum fw_opt to u32 software node: implement software_node_unregister() kobject: send KOBJ_REMOVE uevent when the object is removed from sysfs driver core: Remove unnecessary is_fwnode_dev variable in device_add() drivers property: When no children in primary, try secondary driver core: platform: Fix spelling errors in platform.c driver core: Remove check in driver_deferred_probe_force_trigger() of: platform: Batch fwnode parsing when adding all top level devices driver core: fw_devlink: Add support for batching fwnode parsing driver core: Look for waiting consumers only for a fwnode's primary device driver core: Move code to the right part of the file Revert "Revert "driver core: Set fw_devlink to "permissive" behavior by default"" drivers: base: Fix NULL pointer exception in __platform_driver_probe() if a driver developer is foolish firmware_loader: move fw_fallback_config to a private kernel symbol namespace driver core: Add missing '\n' in log messages driver/base/soc: Use kobj_to_dev() API Add documentation on meaning of -EPROBE_DEFER driver core: platform: remove redundant assignment to variable ret debugfs: Use the correct style for SPDX License Identifier ...
This commit is contained in:
commit
f558b8364e
@ -4,7 +4,6 @@ Device Drivers
|
|||||||
|
|
||||||
See the kerneldoc for the struct device_driver.
|
See the kerneldoc for the struct device_driver.
|
||||||
|
|
||||||
|
|
||||||
Allocation
|
Allocation
|
||||||
~~~~~~~~~~
|
~~~~~~~~~~
|
||||||
|
|
||||||
@ -167,9 +166,26 @@ the driver to that device.
|
|||||||
|
|
||||||
A driver's probe() may return a negative errno value to indicate that
|
A driver's probe() may return a negative errno value to indicate that
|
||||||
the driver did not bind to this device, in which case it should have
|
the driver did not bind to this device, in which case it should have
|
||||||
released all resources it allocated::
|
released all resources it allocated.
|
||||||
|
|
||||||
void (*sync_state)(struct device *dev);
|
Optionally, probe() may return -EPROBE_DEFER if the driver depends on
|
||||||
|
resources that are not yet available (e.g., supplied by a driver that
|
||||||
|
hasn't initialized yet). The driver core will put the device onto the
|
||||||
|
deferred probe list and will try to call it again later. If a driver
|
||||||
|
must defer, it should return -EPROBE_DEFER as early as possible to
|
||||||
|
reduce the amount of time spent on setup work that will need to be
|
||||||
|
unwound and reexecuted at a later time.
|
||||||
|
|
||||||
|
.. warning::
|
||||||
|
-EPROBE_DEFER must not be returned if probe() has already created
|
||||||
|
child devices, even if those child devices are removed again
|
||||||
|
in a cleanup path. If -EPROBE_DEFER is returned after a child
|
||||||
|
device has been registered, it may result in an infinite loop of
|
||||||
|
.probe() calls to the same driver.
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
void (*sync_state) (struct device *dev);
|
||||||
|
|
||||||
sync_state is called only once for a device. It's called when all the consumer
|
sync_state is called only once for a device. It's called when all the consumer
|
||||||
devices of the device have successfully probed. The list of consumers of the
|
devices of the device have successfully probed. The list of consumers of the
|
||||||
@ -212,6 +228,8 @@ over management of devices from the bootloader, the usage of sync_state() is
|
|||||||
not restricted to that. Use it whenever it makes sense to take an action after
|
not restricted to that. Use it whenever it makes sense to take an action after
|
||||||
all the consumers of a device have probed::
|
all the consumers of a device have probed::
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
int (*remove) (struct device *dev);
|
int (*remove) (struct device *dev);
|
||||||
|
|
||||||
remove is called to unbind a driver from a device. This may be
|
remove is called to unbind a driver from a device. This may be
|
||||||
@ -224,11 +242,15 @@ not. It should free any resources allocated specifically for the
|
|||||||
device; i.e. anything in the device's driver_data field.
|
device; i.e. anything in the device's driver_data field.
|
||||||
|
|
||||||
If the device is still present, it should quiesce the device and place
|
If the device is still present, it should quiesce the device and place
|
||||||
it into a supported low-power state::
|
it into a supported low-power state.
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
int (*suspend) (struct device *dev, pm_message_t state);
|
int (*suspend) (struct device *dev, pm_message_t state);
|
||||||
|
|
||||||
suspend is called to put the device in a low power state::
|
suspend is called to put the device in a low power state.
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
int (*resume) (struct device *dev);
|
int (*resume) (struct device *dev);
|
||||||
|
|
||||||
|
@ -153,6 +153,7 @@ extern char *make_class_name(const char *name, struct kobject *kobj);
|
|||||||
extern int devres_release_all(struct device *dev);
|
extern int devres_release_all(struct device *dev);
|
||||||
extern void device_block_probing(void);
|
extern void device_block_probing(void);
|
||||||
extern void device_unblock_probing(void);
|
extern void device_unblock_probing(void);
|
||||||
|
extern void driver_deferred_probe_force_trigger(void);
|
||||||
|
|
||||||
/* /sys/devices directory */
|
/* /sys/devices directory */
|
||||||
extern struct kset *devices_kset;
|
extern struct kset *devices_kset;
|
||||||
|
@ -49,6 +49,9 @@ static LIST_HEAD(wait_for_suppliers);
|
|||||||
static DEFINE_MUTEX(wfs_lock);
|
static DEFINE_MUTEX(wfs_lock);
|
||||||
static LIST_HEAD(deferred_sync);
|
static LIST_HEAD(deferred_sync);
|
||||||
static unsigned int defer_sync_state_count = 1;
|
static unsigned int defer_sync_state_count = 1;
|
||||||
|
static unsigned int defer_fw_devlink_count;
|
||||||
|
static DEFINE_MUTEX(defer_fw_devlink_lock);
|
||||||
|
static bool fw_devlink_is_permissive(void);
|
||||||
|
|
||||||
#ifdef CONFIG_SRCU
|
#ifdef CONFIG_SRCU
|
||||||
static DEFINE_MUTEX(device_links_lock);
|
static DEFINE_MUTEX(device_links_lock);
|
||||||
@ -529,7 +532,7 @@ static void device_link_add_missing_supplier_links(void)
|
|||||||
int ret = fwnode_call_int_op(dev->fwnode, add_links, dev);
|
int ret = fwnode_call_int_op(dev->fwnode, add_links, dev);
|
||||||
if (!ret)
|
if (!ret)
|
||||||
list_del_init(&dev->links.needs_suppliers);
|
list_del_init(&dev->links.needs_suppliers);
|
||||||
else if (ret != -ENODEV)
|
else if (ret != -ENODEV || fw_devlink_is_permissive())
|
||||||
dev->links.need_for_probe = false;
|
dev->links.need_for_probe = false;
|
||||||
}
|
}
|
||||||
mutex_unlock(&wfs_lock);
|
mutex_unlock(&wfs_lock);
|
||||||
@ -643,9 +646,17 @@ static void device_links_missing_supplier(struct device *dev)
|
|||||||
{
|
{
|
||||||
struct device_link *link;
|
struct device_link *link;
|
||||||
|
|
||||||
list_for_each_entry(link, &dev->links.suppliers, c_node)
|
list_for_each_entry(link, &dev->links.suppliers, c_node) {
|
||||||
if (link->status == DL_STATE_CONSUMER_PROBE)
|
if (link->status != DL_STATE_CONSUMER_PROBE)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (link->supplier->links.status == DL_DEV_DRIVER_BOUND) {
|
||||||
WRITE_ONCE(link->status, DL_STATE_AVAILABLE);
|
WRITE_ONCE(link->status, DL_STATE_AVAILABLE);
|
||||||
|
} else {
|
||||||
|
WARN_ON(!(link->flags & DL_FLAG_SYNC_STATE_ONLY));
|
||||||
|
WRITE_ONCE(link->status, DL_STATE_DORMANT);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -684,11 +695,11 @@ int device_links_check_suppliers(struct device *dev)
|
|||||||
device_links_write_lock();
|
device_links_write_lock();
|
||||||
|
|
||||||
list_for_each_entry(link, &dev->links.suppliers, c_node) {
|
list_for_each_entry(link, &dev->links.suppliers, c_node) {
|
||||||
if (!(link->flags & DL_FLAG_MANAGED) ||
|
if (!(link->flags & DL_FLAG_MANAGED))
|
||||||
link->flags & DL_FLAG_SYNC_STATE_ONLY)
|
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (link->status != DL_STATE_AVAILABLE) {
|
if (link->status != DL_STATE_AVAILABLE &&
|
||||||
|
!(link->flags & DL_FLAG_SYNC_STATE_ONLY)) {
|
||||||
device_links_missing_supplier(dev);
|
device_links_missing_supplier(dev);
|
||||||
ret = -EPROBE_DEFER;
|
ret = -EPROBE_DEFER;
|
||||||
break;
|
break;
|
||||||
@ -949,11 +960,21 @@ static void __device_links_no_driver(struct device *dev)
|
|||||||
if (!(link->flags & DL_FLAG_MANAGED))
|
if (!(link->flags & DL_FLAG_MANAGED))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (link->flags & DL_FLAG_AUTOREMOVE_CONSUMER)
|
if (link->flags & DL_FLAG_AUTOREMOVE_CONSUMER) {
|
||||||
device_link_drop_managed(link);
|
device_link_drop_managed(link);
|
||||||
else if (link->status == DL_STATE_CONSUMER_PROBE ||
|
continue;
|
||||||
link->status == DL_STATE_ACTIVE)
|
}
|
||||||
|
|
||||||
|
if (link->status != DL_STATE_CONSUMER_PROBE &&
|
||||||
|
link->status != DL_STATE_ACTIVE)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (link->supplier->links.status == DL_DEV_DRIVER_BOUND) {
|
||||||
WRITE_ONCE(link->status, DL_STATE_AVAILABLE);
|
WRITE_ONCE(link->status, DL_STATE_AVAILABLE);
|
||||||
|
} else {
|
||||||
|
WARN_ON(!(link->flags & DL_FLAG_SYNC_STATE_ONLY));
|
||||||
|
WRITE_ONCE(link->status, DL_STATE_DORMANT);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
dev->links.status = DL_DEV_NO_DRIVER;
|
dev->links.status = DL_DEV_NO_DRIVER;
|
||||||
@ -1162,6 +1183,150 @@ static void device_links_purge(struct device *dev)
|
|||||||
device_links_write_unlock();
|
device_links_write_unlock();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static u32 fw_devlink_flags = DL_FLAG_SYNC_STATE_ONLY;
|
||||||
|
static int __init fw_devlink_setup(char *arg)
|
||||||
|
{
|
||||||
|
if (!arg)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
if (strcmp(arg, "off") == 0) {
|
||||||
|
fw_devlink_flags = 0;
|
||||||
|
} else if (strcmp(arg, "permissive") == 0) {
|
||||||
|
fw_devlink_flags = DL_FLAG_SYNC_STATE_ONLY;
|
||||||
|
} else if (strcmp(arg, "on") == 0) {
|
||||||
|
fw_devlink_flags = DL_FLAG_AUTOPROBE_CONSUMER;
|
||||||
|
} else if (strcmp(arg, "rpm") == 0) {
|
||||||
|
fw_devlink_flags = DL_FLAG_AUTOPROBE_CONSUMER |
|
||||||
|
DL_FLAG_PM_RUNTIME;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
early_param("fw_devlink", fw_devlink_setup);
|
||||||
|
|
||||||
|
u32 fw_devlink_get_flags(void)
|
||||||
|
{
|
||||||
|
return fw_devlink_flags;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool fw_devlink_is_permissive(void)
|
||||||
|
{
|
||||||
|
return fw_devlink_flags == DL_FLAG_SYNC_STATE_ONLY;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void fw_devlink_link_device(struct device *dev)
|
||||||
|
{
|
||||||
|
int fw_ret;
|
||||||
|
|
||||||
|
if (!fw_devlink_flags)
|
||||||
|
return;
|
||||||
|
|
||||||
|
mutex_lock(&defer_fw_devlink_lock);
|
||||||
|
if (!defer_fw_devlink_count)
|
||||||
|
device_link_add_missing_supplier_links();
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The device's fwnode not having add_links() doesn't affect if other
|
||||||
|
* consumers can find this device as a supplier. So, this check is
|
||||||
|
* intentionally placed after device_link_add_missing_supplier_links().
|
||||||
|
*/
|
||||||
|
if (!fwnode_has_op(dev->fwnode, add_links))
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If fw_devlink is being deferred, assume all devices have mandatory
|
||||||
|
* suppliers they need to link to later. Then, when the fw_devlink is
|
||||||
|
* resumed, all these devices will get a chance to try and link to any
|
||||||
|
* suppliers they have.
|
||||||
|
*/
|
||||||
|
if (!defer_fw_devlink_count) {
|
||||||
|
fw_ret = fwnode_call_int_op(dev->fwnode, add_links, dev);
|
||||||
|
if (fw_ret == -ENODEV && fw_devlink_is_permissive())
|
||||||
|
fw_ret = -EAGAIN;
|
||||||
|
} else {
|
||||||
|
fw_ret = -ENODEV;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fw_ret == -ENODEV)
|
||||||
|
device_link_wait_for_mandatory_supplier(dev);
|
||||||
|
else if (fw_ret)
|
||||||
|
device_link_wait_for_optional_supplier(dev);
|
||||||
|
|
||||||
|
out:
|
||||||
|
mutex_unlock(&defer_fw_devlink_lock);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* fw_devlink_pause - Pause parsing of fwnode to create device links
|
||||||
|
*
|
||||||
|
* Calling this function defers any fwnode parsing to create device links until
|
||||||
|
* fw_devlink_resume() is called. Both these functions are ref counted and the
|
||||||
|
* caller needs to match the calls.
|
||||||
|
*
|
||||||
|
* While fw_devlink is paused:
|
||||||
|
* - Any device that is added won't have its fwnode parsed to create device
|
||||||
|
* links.
|
||||||
|
* - The probe of the device will also be deferred during this period.
|
||||||
|
* - Any devices that were already added, but waiting for suppliers won't be
|
||||||
|
* able to link to newly added devices.
|
||||||
|
*
|
||||||
|
* Once fw_devlink_resume():
|
||||||
|
* - All the fwnodes that was not parsed will be parsed.
|
||||||
|
* - All the devices that were deferred probing will be reattempted if they
|
||||||
|
* aren't waiting for any more suppliers.
|
||||||
|
*
|
||||||
|
* This pair of functions, is mainly meant to optimize the parsing of fwnodes
|
||||||
|
* when a lot of devices that need to link to each other are added in a short
|
||||||
|
* interval of time. For example, adding all the top level devices in a system.
|
||||||
|
*
|
||||||
|
* For example, if N devices are added and:
|
||||||
|
* - All the consumers are added before their suppliers
|
||||||
|
* - All the suppliers of the N devices are part of the N devices
|
||||||
|
*
|
||||||
|
* Then:
|
||||||
|
*
|
||||||
|
* - With the use of fw_devlink_pause() and fw_devlink_resume(), each device
|
||||||
|
* will only need one parsing of its fwnode because it is guaranteed to find
|
||||||
|
* all the supplier devices already registered and ready to link to. It won't
|
||||||
|
* have to do another pass later to find one or more suppliers it couldn't
|
||||||
|
* find in the first parse of the fwnode. So, we'll only need O(N) fwnode
|
||||||
|
* parses.
|
||||||
|
*
|
||||||
|
* - Without the use of fw_devlink_pause() and fw_devlink_resume(), we would
|
||||||
|
* end up doing O(N^2) parses of fwnodes because every device that's added is
|
||||||
|
* guaranteed to trigger a parse of the fwnode of every device added before
|
||||||
|
* it. This O(N^2) parse is made worse by the fact that when a fwnode of a
|
||||||
|
* device is parsed, all it descendant devices might need to have their
|
||||||
|
* fwnodes parsed too (even if the devices themselves aren't added).
|
||||||
|
*/
|
||||||
|
void fw_devlink_pause(void)
|
||||||
|
{
|
||||||
|
mutex_lock(&defer_fw_devlink_lock);
|
||||||
|
defer_fw_devlink_count++;
|
||||||
|
mutex_unlock(&defer_fw_devlink_lock);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** fw_devlink_resume - Resume parsing of fwnode to create device links
|
||||||
|
*
|
||||||
|
* This function is used in conjunction with fw_devlink_pause() and is ref
|
||||||
|
* counted. See documentation for fw_devlink_pause() for more details.
|
||||||
|
*/
|
||||||
|
void fw_devlink_resume(void)
|
||||||
|
{
|
||||||
|
mutex_lock(&defer_fw_devlink_lock);
|
||||||
|
if (!defer_fw_devlink_count) {
|
||||||
|
WARN(true, "Unmatched fw_devlink pause/resume!");
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
defer_fw_devlink_count--;
|
||||||
|
if (defer_fw_devlink_count)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
device_link_add_missing_supplier_links();
|
||||||
|
driver_deferred_probe_force_trigger();
|
||||||
|
out:
|
||||||
|
mutex_unlock(&defer_fw_devlink_lock);
|
||||||
|
}
|
||||||
/* Device links support end. */
|
/* Device links support end. */
|
||||||
|
|
||||||
int (*platform_notify)(struct device *dev) = NULL;
|
int (*platform_notify)(struct device *dev) = NULL;
|
||||||
@ -2364,36 +2529,6 @@ static int device_private_init(struct device *dev)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static u32 fw_devlink_flags;
|
|
||||||
static int __init fw_devlink_setup(char *arg)
|
|
||||||
{
|
|
||||||
if (!arg)
|
|
||||||
return -EINVAL;
|
|
||||||
|
|
||||||
if (strcmp(arg, "off") == 0) {
|
|
||||||
fw_devlink_flags = 0;
|
|
||||||
} else if (strcmp(arg, "permissive") == 0) {
|
|
||||||
fw_devlink_flags = DL_FLAG_SYNC_STATE_ONLY;
|
|
||||||
} else if (strcmp(arg, "on") == 0) {
|
|
||||||
fw_devlink_flags = DL_FLAG_AUTOPROBE_CONSUMER;
|
|
||||||
} else if (strcmp(arg, "rpm") == 0) {
|
|
||||||
fw_devlink_flags = DL_FLAG_AUTOPROBE_CONSUMER |
|
|
||||||
DL_FLAG_PM_RUNTIME;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
early_param("fw_devlink", fw_devlink_setup);
|
|
||||||
|
|
||||||
u32 fw_devlink_get_flags(void)
|
|
||||||
{
|
|
||||||
return fw_devlink_flags;
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool fw_devlink_is_permissive(void)
|
|
||||||
{
|
|
||||||
return fw_devlink_flags == DL_FLAG_SYNC_STATE_ONLY;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* device_add - add device to device hierarchy.
|
* device_add - add device to device hierarchy.
|
||||||
* @dev: device.
|
* @dev: device.
|
||||||
@ -2426,9 +2561,8 @@ int device_add(struct device *dev)
|
|||||||
struct device *parent;
|
struct device *parent;
|
||||||
struct kobject *kobj;
|
struct kobject *kobj;
|
||||||
struct class_interface *class_intf;
|
struct class_interface *class_intf;
|
||||||
int error = -EINVAL, fw_ret;
|
int error = -EINVAL;
|
||||||
struct kobject *glue_dir = NULL;
|
struct kobject *glue_dir = NULL;
|
||||||
bool is_fwnode_dev = false;
|
|
||||||
|
|
||||||
dev = get_device(dev);
|
dev = get_device(dev);
|
||||||
if (!dev)
|
if (!dev)
|
||||||
@ -2526,11 +2660,6 @@ int device_add(struct device *dev)
|
|||||||
|
|
||||||
kobject_uevent(&dev->kobj, KOBJ_ADD);
|
kobject_uevent(&dev->kobj, KOBJ_ADD);
|
||||||
|
|
||||||
if (dev->fwnode && !dev->fwnode->dev) {
|
|
||||||
dev->fwnode->dev = dev;
|
|
||||||
is_fwnode_dev = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Check if any of the other devices (consumers) have been waiting for
|
* Check if any of the other devices (consumers) have been waiting for
|
||||||
* this device (supplier) to be added so that they can create a device
|
* this device (supplier) to be added so that they can create a device
|
||||||
@ -2539,19 +2668,13 @@ int device_add(struct device *dev)
|
|||||||
* This needs to happen after device_pm_add() because device_link_add()
|
* This needs to happen after device_pm_add() because device_link_add()
|
||||||
* requires the supplier be registered before it's called.
|
* requires the supplier be registered before it's called.
|
||||||
*
|
*
|
||||||
* But this also needs to happe before bus_probe_device() to make sure
|
* But this also needs to happen before bus_probe_device() to make sure
|
||||||
* waiting consumers can link to it before the driver is bound to the
|
* waiting consumers can link to it before the driver is bound to the
|
||||||
* device and the driver sync_state callback is called for this device.
|
* device and the driver sync_state callback is called for this device.
|
||||||
*/
|
*/
|
||||||
device_link_add_missing_supplier_links();
|
if (dev->fwnode && !dev->fwnode->dev) {
|
||||||
|
dev->fwnode->dev = dev;
|
||||||
if (fw_devlink_flags && is_fwnode_dev &&
|
fw_devlink_link_device(dev);
|
||||||
fwnode_has_op(dev->fwnode, add_links)) {
|
|
||||||
fw_ret = fwnode_call_int_op(dev->fwnode, add_links, dev);
|
|
||||||
if (fw_ret == -ENODEV && !fw_devlink_is_permissive())
|
|
||||||
device_link_wait_for_mandatory_supplier(dev);
|
|
||||||
else if (fw_ret)
|
|
||||||
device_link_wait_for_optional_supplier(dev);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bus_probe_device(dev);
|
bus_probe_device(dev);
|
||||||
|
@ -164,6 +164,11 @@ static void driver_deferred_probe_trigger(void)
|
|||||||
if (!driver_deferred_probe_enable)
|
if (!driver_deferred_probe_enable)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
driver_deferred_probe_force_trigger();
|
||||||
|
}
|
||||||
|
|
||||||
|
void driver_deferred_probe_force_trigger(void)
|
||||||
|
{
|
||||||
/*
|
/*
|
||||||
* A successful probe means that all the devices in the pending list
|
* A successful probe means that all the devices in the pending list
|
||||||
* should be triggered to be reprobed. Move all the deferred devices
|
* should be triggered to be reprobed. Move all the deferred devices
|
||||||
@ -254,12 +259,12 @@ __setup("deferred_probe_timeout=", deferred_probe_timeout_setup);
|
|||||||
int driver_deferred_probe_check_state(struct device *dev)
|
int driver_deferred_probe_check_state(struct device *dev)
|
||||||
{
|
{
|
||||||
if (!IS_ENABLED(CONFIG_MODULES) && initcalls_done) {
|
if (!IS_ENABLED(CONFIG_MODULES) && initcalls_done) {
|
||||||
dev_warn(dev, "ignoring dependency for device, assuming no driver");
|
dev_warn(dev, "ignoring dependency for device, assuming no driver\n");
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!driver_deferred_probe_timeout && initcalls_done) {
|
if (!driver_deferred_probe_timeout && initcalls_done) {
|
||||||
dev_warn(dev, "deferred probe timeout, ignoring dependency");
|
dev_warn(dev, "deferred probe timeout, ignoring dependency\n");
|
||||||
return -ETIMEDOUT;
|
return -ETIMEDOUT;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -275,7 +280,7 @@ static void deferred_probe_timeout_work_func(struct work_struct *work)
|
|||||||
flush_work(&deferred_probe_work);
|
flush_work(&deferred_probe_work);
|
||||||
|
|
||||||
list_for_each_entry_safe(private, p, &deferred_probe_pending_list, deferred_probe)
|
list_for_each_entry_safe(private, p, &deferred_probe_pending_list, deferred_probe)
|
||||||
dev_info(private->device, "deferred probe pending");
|
dev_info(private->device, "deferred probe pending\n");
|
||||||
wake_up(&probe_timeout_waitqueue);
|
wake_up(&probe_timeout_waitqueue);
|
||||||
}
|
}
|
||||||
static DECLARE_DELAYED_WORK(deferred_probe_timeout_work, deferred_probe_timeout_work_func);
|
static DECLARE_DELAYED_WORK(deferred_probe_timeout_work, deferred_probe_timeout_work_func);
|
||||||
@ -336,7 +341,7 @@ bool device_is_bound(struct device *dev)
|
|||||||
static void driver_bound(struct device *dev)
|
static void driver_bound(struct device *dev)
|
||||||
{
|
{
|
||||||
if (device_is_bound(dev)) {
|
if (device_is_bound(dev)) {
|
||||||
printk(KERN_WARNING "%s: device %s already bound\n",
|
pr_warn("%s: device %s already bound\n",
|
||||||
__func__, kobject_name(&dev->kobj));
|
__func__, kobject_name(&dev->kobj));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -505,8 +510,8 @@ static int really_probe(struct device *dev, struct device_driver *drv)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (driver_sysfs_add(dev)) {
|
if (driver_sysfs_add(dev)) {
|
||||||
printk(KERN_ERR "%s: driver_sysfs_add(%s) failed\n",
|
pr_err("%s: driver_sysfs_add(%s) failed\n",
|
||||||
__func__, dev_name(dev));
|
__func__, dev_name(dev));
|
||||||
goto probe_failed;
|
goto probe_failed;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -597,9 +602,8 @@ static int really_probe(struct device *dev, struct device_driver *drv)
|
|||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
/* driver matched but the probe failed */
|
/* driver matched but the probe failed */
|
||||||
printk(KERN_WARNING
|
pr_warn("%s: probe of %s failed with error %d\n",
|
||||||
"%s: probe of %s failed with error %d\n",
|
drv->name, dev_name(dev), ret);
|
||||||
drv->name, dev_name(dev), ret);
|
|
||||||
}
|
}
|
||||||
/*
|
/*
|
||||||
* Ignore errors returned by ->probe so that the next driver can try
|
* Ignore errors returned by ->probe so that the next driver can try
|
||||||
@ -624,8 +628,8 @@ static int really_probe_debug(struct device *dev, struct device_driver *drv)
|
|||||||
ret = really_probe(dev, drv);
|
ret = really_probe(dev, drv);
|
||||||
rettime = ktime_get();
|
rettime = ktime_get();
|
||||||
delta = ktime_sub(rettime, calltime);
|
delta = ktime_sub(rettime, calltime);
|
||||||
printk(KERN_DEBUG "probe of %s returned %d after %lld usecs\n",
|
pr_debug("probe of %s returned %d after %lld usecs\n",
|
||||||
dev_name(dev), ret, (s64) ktime_to_us(delta));
|
dev_name(dev), ret, (s64) ktime_to_us(delta));
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -713,8 +717,7 @@ static inline bool cmdline_requested_async_probing(const char *drv_name)
|
|||||||
static int __init save_async_options(char *buf)
|
static int __init save_async_options(char *buf)
|
||||||
{
|
{
|
||||||
if (strlen(buf) >= ASYNC_DRV_NAMES_MAX_LEN)
|
if (strlen(buf) >= ASYNC_DRV_NAMES_MAX_LEN)
|
||||||
printk(KERN_WARNING
|
pr_warn("Too long list of driver names for 'driver_async_probe'!\n");
|
||||||
"Too long list of driver names for 'driver_async_probe'!\n");
|
|
||||||
|
|
||||||
strlcpy(async_probe_drv_names, buf, ASYNC_DRV_NAMES_MAX_LEN);
|
strlcpy(async_probe_drv_names, buf, ASYNC_DRV_NAMES_MAX_LEN);
|
||||||
return 0;
|
return 0;
|
||||||
@ -789,7 +792,7 @@ static int __device_attach_driver(struct device_driver *drv, void *_data)
|
|||||||
dev_dbg(dev, "Device match requests probe deferral\n");
|
dev_dbg(dev, "Device match requests probe deferral\n");
|
||||||
driver_deferred_probe_add(dev);
|
driver_deferred_probe_add(dev);
|
||||||
} else if (ret < 0) {
|
} else if (ret < 0) {
|
||||||
dev_dbg(dev, "Bus failed to match device: %d", ret);
|
dev_dbg(dev, "Bus failed to match device: %d\n", ret);
|
||||||
return ret;
|
return ret;
|
||||||
} /* ret > 0 means positive match */
|
} /* ret > 0 means positive match */
|
||||||
|
|
||||||
@ -1022,7 +1025,7 @@ static int __driver_attach(struct device *dev, void *data)
|
|||||||
dev_dbg(dev, "Device match requests probe deferral\n");
|
dev_dbg(dev, "Device match requests probe deferral\n");
|
||||||
driver_deferred_probe_add(dev);
|
driver_deferred_probe_add(dev);
|
||||||
} else if (ret < 0) {
|
} else if (ret < 0) {
|
||||||
dev_dbg(dev, "Bus failed to match device: %d", ret);
|
dev_dbg(dev, "Bus failed to match device: %d\n", ret);
|
||||||
return ret;
|
return ret;
|
||||||
} /* ret > 0 means positive match */
|
} /* ret > 0 means positive match */
|
||||||
|
|
||||||
|
@ -9,6 +9,7 @@
|
|||||||
#include <linux/umh.h>
|
#include <linux/umh.h>
|
||||||
#include <linux/sysctl.h>
|
#include <linux/sysctl.h>
|
||||||
#include <linux/vmalloc.h>
|
#include <linux/vmalloc.h>
|
||||||
|
#include <linux/module.h>
|
||||||
|
|
||||||
#include "fallback.h"
|
#include "fallback.h"
|
||||||
#include "firmware.h"
|
#include "firmware.h"
|
||||||
@ -17,6 +18,8 @@
|
|||||||
* firmware fallback mechanism
|
* firmware fallback mechanism
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
MODULE_IMPORT_NS(FIRMWARE_LOADER_PRIVATE);
|
||||||
|
|
||||||
extern struct firmware_fallback_config fw_fallback_config;
|
extern struct firmware_fallback_config fw_fallback_config;
|
||||||
|
|
||||||
/* These getters are vetted to use int properly */
|
/* These getters are vetted to use int properly */
|
||||||
@ -460,7 +463,7 @@ static const struct attribute_group *fw_dev_attr_groups[] = {
|
|||||||
|
|
||||||
static struct fw_sysfs *
|
static struct fw_sysfs *
|
||||||
fw_create_instance(struct firmware *firmware, const char *fw_name,
|
fw_create_instance(struct firmware *firmware, const char *fw_name,
|
||||||
struct device *device, enum fw_opt opt_flags)
|
struct device *device, u32 opt_flags)
|
||||||
{
|
{
|
||||||
struct fw_sysfs *fw_sysfs;
|
struct fw_sysfs *fw_sysfs;
|
||||||
struct device *f_dev;
|
struct device *f_dev;
|
||||||
@ -493,7 +496,7 @@ fw_create_instance(struct firmware *firmware, const char *fw_name,
|
|||||||
* In charge of constructing a sysfs fallback interface for firmware loading.
|
* In charge of constructing a sysfs fallback interface for firmware loading.
|
||||||
**/
|
**/
|
||||||
static int fw_load_sysfs_fallback(struct fw_sysfs *fw_sysfs,
|
static int fw_load_sysfs_fallback(struct fw_sysfs *fw_sysfs,
|
||||||
enum fw_opt opt_flags, long timeout)
|
u32 opt_flags, long timeout)
|
||||||
{
|
{
|
||||||
int retval = 0;
|
int retval = 0;
|
||||||
struct device *f_dev = &fw_sysfs->dev;
|
struct device *f_dev = &fw_sysfs->dev;
|
||||||
@ -547,7 +550,7 @@ static int fw_load_sysfs_fallback(struct fw_sysfs *fw_sysfs,
|
|||||||
|
|
||||||
static int fw_load_from_user_helper(struct firmware *firmware,
|
static int fw_load_from_user_helper(struct firmware *firmware,
|
||||||
const char *name, struct device *device,
|
const char *name, struct device *device,
|
||||||
enum fw_opt opt_flags)
|
u32 opt_flags)
|
||||||
{
|
{
|
||||||
struct fw_sysfs *fw_sysfs;
|
struct fw_sysfs *fw_sysfs;
|
||||||
long timeout;
|
long timeout;
|
||||||
@ -588,7 +591,7 @@ static int fw_load_from_user_helper(struct firmware *firmware,
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool fw_force_sysfs_fallback(enum fw_opt opt_flags)
|
static bool fw_force_sysfs_fallback(u32 opt_flags)
|
||||||
{
|
{
|
||||||
if (fw_fallback_config.force_sysfs_fallback)
|
if (fw_fallback_config.force_sysfs_fallback)
|
||||||
return true;
|
return true;
|
||||||
@ -597,7 +600,7 @@ static bool fw_force_sysfs_fallback(enum fw_opt opt_flags)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool fw_run_sysfs_fallback(enum fw_opt opt_flags)
|
static bool fw_run_sysfs_fallback(u32 opt_flags)
|
||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
@ -640,7 +643,7 @@ static bool fw_run_sysfs_fallback(enum fw_opt opt_flags)
|
|||||||
**/
|
**/
|
||||||
int firmware_fallback_sysfs(struct firmware *fw, const char *name,
|
int firmware_fallback_sysfs(struct firmware *fw, const char *name,
|
||||||
struct device *device,
|
struct device *device,
|
||||||
enum fw_opt opt_flags,
|
u32 opt_flags,
|
||||||
int ret)
|
int ret)
|
||||||
{
|
{
|
||||||
if (!fw_run_sysfs_fallback(opt_flags))
|
if (!fw_run_sysfs_fallback(opt_flags))
|
||||||
|
@ -33,7 +33,7 @@ struct firmware_fallback_config {
|
|||||||
#ifdef CONFIG_FW_LOADER_USER_HELPER
|
#ifdef CONFIG_FW_LOADER_USER_HELPER
|
||||||
int firmware_fallback_sysfs(struct firmware *fw, const char *name,
|
int firmware_fallback_sysfs(struct firmware *fw, const char *name,
|
||||||
struct device *device,
|
struct device *device,
|
||||||
enum fw_opt opt_flags,
|
u32 opt_flags,
|
||||||
int ret);
|
int ret);
|
||||||
void kill_pending_fw_fallback_reqs(bool only_kill_custom);
|
void kill_pending_fw_fallback_reqs(bool only_kill_custom);
|
||||||
|
|
||||||
@ -45,7 +45,7 @@ void unregister_sysfs_loader(void);
|
|||||||
#else /* CONFIG_FW_LOADER_USER_HELPER */
|
#else /* CONFIG_FW_LOADER_USER_HELPER */
|
||||||
static inline int firmware_fallback_sysfs(struct firmware *fw, const char *name,
|
static inline int firmware_fallback_sysfs(struct firmware *fw, const char *name,
|
||||||
struct device *device,
|
struct device *device,
|
||||||
enum fw_opt opt_flags,
|
u32 opt_flags,
|
||||||
int ret)
|
int ret)
|
||||||
{
|
{
|
||||||
/* Keep carrying over the same error */
|
/* Keep carrying over the same error */
|
||||||
@ -67,10 +67,10 @@ static inline void unregister_sysfs_loader(void)
|
|||||||
#endif /* CONFIG_FW_LOADER_USER_HELPER */
|
#endif /* CONFIG_FW_LOADER_USER_HELPER */
|
||||||
|
|
||||||
#ifdef CONFIG_EFI_EMBEDDED_FIRMWARE
|
#ifdef CONFIG_EFI_EMBEDDED_FIRMWARE
|
||||||
int firmware_fallback_platform(struct fw_priv *fw_priv, enum fw_opt opt_flags);
|
int firmware_fallback_platform(struct fw_priv *fw_priv, u32 opt_flags);
|
||||||
#else
|
#else
|
||||||
static inline int firmware_fallback_platform(struct fw_priv *fw_priv,
|
static inline int firmware_fallback_platform(struct fw_priv *fw_priv,
|
||||||
enum fw_opt opt_flags)
|
u32 opt_flags)
|
||||||
{
|
{
|
||||||
return -ENOENT;
|
return -ENOENT;
|
||||||
}
|
}
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
#include "fallback.h"
|
#include "fallback.h"
|
||||||
#include "firmware.h"
|
#include "firmware.h"
|
||||||
|
|
||||||
int firmware_fallback_platform(struct fw_priv *fw_priv, enum fw_opt opt_flags)
|
int firmware_fallback_platform(struct fw_priv *fw_priv, u32 opt_flags)
|
||||||
{
|
{
|
||||||
const u8 *data;
|
const u8 *data;
|
||||||
size_t size;
|
size_t size;
|
||||||
|
@ -21,7 +21,7 @@ struct firmware_fallback_config fw_fallback_config = {
|
|||||||
.loading_timeout = 60,
|
.loading_timeout = 60,
|
||||||
.old_timeout = 60,
|
.old_timeout = 60,
|
||||||
};
|
};
|
||||||
EXPORT_SYMBOL_GPL(fw_fallback_config);
|
EXPORT_SYMBOL_NS_GPL(fw_fallback_config, FIRMWARE_LOADER_PRIVATE);
|
||||||
|
|
||||||
#ifdef CONFIG_SYSCTL
|
#ifdef CONFIG_SYSCTL
|
||||||
struct ctl_table firmware_config_table[] = {
|
struct ctl_table firmware_config_table[] = {
|
||||||
|
@ -136,8 +136,7 @@ static inline void fw_state_done(struct fw_priv *fw_priv)
|
|||||||
__fw_state_set(fw_priv, FW_STATUS_DONE);
|
__fw_state_set(fw_priv, FW_STATUS_DONE);
|
||||||
}
|
}
|
||||||
|
|
||||||
int assign_fw(struct firmware *fw, struct device *device,
|
int assign_fw(struct firmware *fw, struct device *device, u32 opt_flags);
|
||||||
enum fw_opt opt_flags);
|
|
||||||
|
|
||||||
#ifdef CONFIG_FW_LOADER_PAGED_BUF
|
#ifdef CONFIG_FW_LOADER_PAGED_BUF
|
||||||
void fw_free_paged_buf(struct fw_priv *fw_priv);
|
void fw_free_paged_buf(struct fw_priv *fw_priv);
|
||||||
|
@ -210,7 +210,7 @@ static struct fw_priv *__lookup_fw_priv(const char *fw_name)
|
|||||||
static int alloc_lookup_fw_priv(const char *fw_name,
|
static int alloc_lookup_fw_priv(const char *fw_name,
|
||||||
struct firmware_cache *fwc,
|
struct firmware_cache *fwc,
|
||||||
struct fw_priv **fw_priv, void *dbuf,
|
struct fw_priv **fw_priv, void *dbuf,
|
||||||
size_t size, enum fw_opt opt_flags)
|
size_t size, u32 opt_flags)
|
||||||
{
|
{
|
||||||
struct fw_priv *tmp;
|
struct fw_priv *tmp;
|
||||||
|
|
||||||
@ -548,9 +548,6 @@ static void firmware_free_data(const struct firmware *fw)
|
|||||||
static void fw_set_page_data(struct fw_priv *fw_priv, struct firmware *fw)
|
static void fw_set_page_data(struct fw_priv *fw_priv, struct firmware *fw)
|
||||||
{
|
{
|
||||||
fw->priv = fw_priv;
|
fw->priv = fw_priv;
|
||||||
#ifdef CONFIG_FW_LOADER_USER_HELPER
|
|
||||||
fw->pages = fw_priv->pages;
|
|
||||||
#endif
|
|
||||||
fw->size = fw_priv->size;
|
fw->size = fw_priv->size;
|
||||||
fw->data = fw_priv->data;
|
fw->data = fw_priv->data;
|
||||||
|
|
||||||
@ -635,8 +632,7 @@ static int fw_add_devm_name(struct device *dev, const char *name)
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
int assign_fw(struct firmware *fw, struct device *device,
|
int assign_fw(struct firmware *fw, struct device *device, u32 opt_flags)
|
||||||
enum fw_opt opt_flags)
|
|
||||||
{
|
{
|
||||||
struct fw_priv *fw_priv = fw->priv;
|
struct fw_priv *fw_priv = fw->priv;
|
||||||
int ret;
|
int ret;
|
||||||
@ -687,7 +683,7 @@ int assign_fw(struct firmware *fw, struct device *device,
|
|||||||
static int
|
static int
|
||||||
_request_firmware_prepare(struct firmware **firmware_p, const char *name,
|
_request_firmware_prepare(struct firmware **firmware_p, const char *name,
|
||||||
struct device *device, void *dbuf, size_t size,
|
struct device *device, void *dbuf, size_t size,
|
||||||
enum fw_opt opt_flags)
|
u32 opt_flags)
|
||||||
{
|
{
|
||||||
struct firmware *firmware;
|
struct firmware *firmware;
|
||||||
struct fw_priv *fw_priv;
|
struct fw_priv *fw_priv;
|
||||||
@ -753,7 +749,7 @@ static void fw_abort_batch_reqs(struct firmware *fw)
|
|||||||
static int
|
static int
|
||||||
_request_firmware(const struct firmware **firmware_p, const char *name,
|
_request_firmware(const struct firmware **firmware_p, const char *name,
|
||||||
struct device *device, void *buf, size_t size,
|
struct device *device, void *buf, size_t size,
|
||||||
enum fw_opt opt_flags)
|
u32 opt_flags)
|
||||||
{
|
{
|
||||||
struct firmware *fw = NULL;
|
struct firmware *fw = NULL;
|
||||||
int ret;
|
int ret;
|
||||||
@ -990,7 +986,7 @@ struct firmware_work {
|
|||||||
struct device *device;
|
struct device *device;
|
||||||
void *context;
|
void *context;
|
||||||
void (*cont)(const struct firmware *fw, void *context);
|
void (*cont)(const struct firmware *fw, void *context);
|
||||||
enum fw_opt opt_flags;
|
u32 opt_flags;
|
||||||
};
|
};
|
||||||
|
|
||||||
static void request_firmware_work_func(struct work_struct *work)
|
static void request_firmware_work_func(struct work_struct *work)
|
||||||
|
@ -682,7 +682,7 @@ EXPORT_SYMBOL_GPL(platform_device_unregister);
|
|||||||
struct platform_device *platform_device_register_full(
|
struct platform_device *platform_device_register_full(
|
||||||
const struct platform_device_info *pdevinfo)
|
const struct platform_device_info *pdevinfo)
|
||||||
{
|
{
|
||||||
int ret = -ENOMEM;
|
int ret;
|
||||||
struct platform_device *pdev;
|
struct platform_device *pdev;
|
||||||
|
|
||||||
pdev = platform_device_alloc(pdevinfo->name, pdevinfo->id);
|
pdev = platform_device_alloc(pdevinfo->name, pdevinfo->id);
|
||||||
@ -863,6 +863,8 @@ int __init_or_module __platform_driver_probe(struct platform_driver *drv,
|
|||||||
/* temporary section violation during probe() */
|
/* temporary section violation during probe() */
|
||||||
drv->probe = probe;
|
drv->probe = probe;
|
||||||
retval = code = __platform_driver_register(drv, module);
|
retval = code = __platform_driver_register(drv, module);
|
||||||
|
if (retval)
|
||||||
|
return retval;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Fixup that section violation, being paranoid about code scanning
|
* Fixup that section violation, being paranoid about code scanning
|
||||||
@ -987,7 +989,7 @@ EXPORT_SYMBOL_GPL(__platform_register_drivers);
|
|||||||
* @drivers: an array of drivers to unregister
|
* @drivers: an array of drivers to unregister
|
||||||
* @count: the number of drivers to unregister
|
* @count: the number of drivers to unregister
|
||||||
*
|
*
|
||||||
* Unegisters platform drivers specified by an array. This is typically used
|
* Unregisters platform drivers specified by an array. This is typically used
|
||||||
* to complement an earlier call to platform_register_drivers(). Drivers are
|
* to complement an earlier call to platform_register_drivers(). Drivers are
|
||||||
* unregistered in the reverse order in which they were registered.
|
* unregistered in the reverse order in which they were registered.
|
||||||
*/
|
*/
|
||||||
|
@ -708,14 +708,23 @@ struct fwnode_handle *device_get_next_child_node(struct device *dev,
|
|||||||
struct fwnode_handle *child)
|
struct fwnode_handle *child)
|
||||||
{
|
{
|
||||||
struct acpi_device *adev = ACPI_COMPANION(dev);
|
struct acpi_device *adev = ACPI_COMPANION(dev);
|
||||||
struct fwnode_handle *fwnode = NULL;
|
struct fwnode_handle *fwnode = NULL, *next;
|
||||||
|
|
||||||
if (dev->of_node)
|
if (dev->of_node)
|
||||||
fwnode = &dev->of_node->fwnode;
|
fwnode = &dev->of_node->fwnode;
|
||||||
else if (adev)
|
else if (adev)
|
||||||
fwnode = acpi_fwnode_handle(adev);
|
fwnode = acpi_fwnode_handle(adev);
|
||||||
|
|
||||||
return fwnode_get_next_child_node(fwnode, child);
|
/* Try to find a child in primary fwnode */
|
||||||
|
next = fwnode_get_next_child_node(fwnode, child);
|
||||||
|
if (next)
|
||||||
|
return next;
|
||||||
|
|
||||||
|
/* When no more children in primary, continue with secondary */
|
||||||
|
if (!IS_ERR_OR_NULL(fwnode->secondary))
|
||||||
|
next = fwnode_get_next_child_node(fwnode->secondary, child);
|
||||||
|
|
||||||
|
return next;
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(device_get_next_child_node);
|
EXPORT_SYMBOL_GPL(device_get_next_child_node);
|
||||||
|
|
||||||
|
@ -46,7 +46,7 @@ static umode_t soc_attribute_mode(struct kobject *kobj,
|
|||||||
struct attribute *attr,
|
struct attribute *attr,
|
||||||
int index)
|
int index)
|
||||||
{
|
{
|
||||||
struct device *dev = container_of(kobj, struct device, kobj);
|
struct device *dev = kobj_to_dev(kobj);
|
||||||
struct soc_device *soc_dev = container_of(dev, struct soc_device, dev);
|
struct soc_device *soc_dev = container_of(dev, struct soc_device, dev);
|
||||||
|
|
||||||
if ((attr == &dev_attr_machine.attr)
|
if ((attr == &dev_attr_machine.attr)
|
||||||
|
@ -712,17 +712,18 @@ EXPORT_SYMBOL_GPL(software_node_register_nodes);
|
|||||||
* @nodes: Zero terminated array of software nodes to be unregistered
|
* @nodes: Zero terminated array of software nodes to be unregistered
|
||||||
*
|
*
|
||||||
* Unregister multiple software nodes at once.
|
* Unregister multiple software nodes at once.
|
||||||
|
*
|
||||||
|
* NOTE: Be careful using this call if the nodes had parent pointers set up in
|
||||||
|
* them before registering. If so, it is wiser to remove the nodes
|
||||||
|
* individually, in the correct order (child before parent) instead of relying
|
||||||
|
* on the sequential order of the list of nodes in the array.
|
||||||
*/
|
*/
|
||||||
void software_node_unregister_nodes(const struct software_node *nodes)
|
void software_node_unregister_nodes(const struct software_node *nodes)
|
||||||
{
|
{
|
||||||
struct swnode *swnode;
|
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
for (i = 0; nodes[i].name; i++) {
|
for (i = 0; nodes[i].name; i++)
|
||||||
swnode = software_node_to_swnode(&nodes[i]);
|
software_node_unregister(&nodes[i]);
|
||||||
if (swnode)
|
|
||||||
fwnode_remove_software_node(&swnode->fwnode);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(software_node_unregister_nodes);
|
EXPORT_SYMBOL_GPL(software_node_unregister_nodes);
|
||||||
|
|
||||||
@ -789,6 +790,20 @@ int software_node_register(const struct software_node *node)
|
|||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(software_node_register);
|
EXPORT_SYMBOL_GPL(software_node_register);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* software_node_unregister - Unregister static software node
|
||||||
|
* @node: The software node to be unregistered
|
||||||
|
*/
|
||||||
|
void software_node_unregister(const struct software_node *node)
|
||||||
|
{
|
||||||
|
struct swnode *swnode;
|
||||||
|
|
||||||
|
swnode = software_node_to_swnode(node);
|
||||||
|
if (swnode)
|
||||||
|
fwnode_remove_software_node(&swnode->fwnode);
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL_GPL(software_node_unregister);
|
||||||
|
|
||||||
struct fwnode_handle *
|
struct fwnode_handle *
|
||||||
fwnode_create_software_node(const struct property_entry *properties,
|
fwnode_create_software_node(const struct property_entry *properties,
|
||||||
const struct fwnode_handle *parent)
|
const struct fwnode_handle *parent)
|
||||||
|
@ -538,7 +538,9 @@ static int __init of_platform_default_populate_init(void)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Populate everything else. */
|
/* Populate everything else. */
|
||||||
|
fw_devlink_pause();
|
||||||
of_platform_default_populate(NULL, NULL, NULL);
|
of_platform_default_populate(NULL, NULL, NULL);
|
||||||
|
fw_devlink_resume();
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
// SPDX-License-Identifier: GPL-2.0
|
/* SPDX-License-Identifier: GPL-2.0 */
|
||||||
/*
|
/*
|
||||||
* internal.h - declarations internal to debugfs
|
* internal.h - declarations internal to debugfs
|
||||||
*
|
*
|
||||||
|
@ -1010,7 +1010,7 @@ struct kernfs_node *__kernfs_create_file(struct kernfs_node *parent,
|
|||||||
|
|
||||||
#ifdef CONFIG_DEBUG_LOCK_ALLOC
|
#ifdef CONFIG_DEBUG_LOCK_ALLOC
|
||||||
if (key) {
|
if (key) {
|
||||||
lockdep_init_map(&kn->dep_map, "kn->count", key, 0);
|
lockdep_init_map(&kn->dep_map, "kn->active", key, 0);
|
||||||
kn->flags |= KERNFS_LOCKDEP;
|
kn->flags |= KERNFS_LOCKDEP;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
@ -12,7 +12,6 @@
|
|||||||
struct firmware {
|
struct firmware {
|
||||||
size_t size;
|
size_t size;
|
||||||
const u8 *data;
|
const u8 *data;
|
||||||
struct page **pages;
|
|
||||||
|
|
||||||
/* firmware loader private fields */
|
/* firmware loader private fields */
|
||||||
void *priv;
|
void *priv;
|
||||||
|
@ -171,5 +171,7 @@ struct fwnode_operations {
|
|||||||
#define get_dev_from_fwnode(fwnode) get_device((fwnode)->dev)
|
#define get_dev_from_fwnode(fwnode) get_device((fwnode)->dev)
|
||||||
|
|
||||||
extern u32 fw_devlink_get_flags(void);
|
extern u32 fw_devlink_get_flags(void);
|
||||||
|
void fw_devlink_pause(void);
|
||||||
|
void fw_devlink_resume(void);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -444,6 +444,7 @@ int software_node_register_node_group(const struct software_node **node_group);
|
|||||||
void software_node_unregister_node_group(const struct software_node **node_group);
|
void software_node_unregister_node_group(const struct software_node **node_group);
|
||||||
|
|
||||||
int software_node_register(const struct software_node *node);
|
int software_node_register(const struct software_node *node);
|
||||||
|
void software_node_unregister(const struct software_node *node);
|
||||||
|
|
||||||
int software_node_notify(struct device *dev, unsigned long action);
|
int software_node_notify(struct device *dev, unsigned long action);
|
||||||
|
|
||||||
|
@ -620,6 +620,13 @@ void kobject_del(struct kobject *kobj)
|
|||||||
if (ktype)
|
if (ktype)
|
||||||
sysfs_remove_groups(kobj, ktype->default_groups);
|
sysfs_remove_groups(kobj, ktype->default_groups);
|
||||||
|
|
||||||
|
/* send "remove" if the caller did not do it but sent "add" */
|
||||||
|
if (kobj->state_add_uevent_sent && !kobj->state_remove_uevent_sent) {
|
||||||
|
pr_debug("kobject: '%s' (%p): auto cleanup 'remove' event\n",
|
||||||
|
kobject_name(kobj), kobj);
|
||||||
|
kobject_uevent(kobj, KOBJ_REMOVE);
|
||||||
|
}
|
||||||
|
|
||||||
sysfs_remove_dir(kobj);
|
sysfs_remove_dir(kobj);
|
||||||
sysfs_put(sd);
|
sysfs_put(sd);
|
||||||
|
|
||||||
@ -673,13 +680,6 @@ static void kobject_cleanup(struct kobject *kobj)
|
|||||||
pr_debug("kobject: '%s' (%p): does not have a release() function, it is broken and must be fixed. See Documentation/core-api/kobject.rst.\n",
|
pr_debug("kobject: '%s' (%p): does not have a release() function, it is broken and must be fixed. See Documentation/core-api/kobject.rst.\n",
|
||||||
kobject_name(kobj), kobj);
|
kobject_name(kobj), kobj);
|
||||||
|
|
||||||
/* send "remove" if the caller did not do it but sent "add" */
|
|
||||||
if (kobj->state_add_uevent_sent && !kobj->state_remove_uevent_sent) {
|
|
||||||
pr_debug("kobject: '%s' (%p): auto cleanup 'remove' event\n",
|
|
||||||
kobject_name(kobj), kobj);
|
|
||||||
kobject_uevent(kobj, KOBJ_REMOVE);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* remove from sysfs if the caller did not do it */
|
/* remove from sysfs if the caller did not do it */
|
||||||
if (kobj->state_in_sysfs) {
|
if (kobj->state_in_sysfs) {
|
||||||
pr_debug("kobject: '%s' (%p): auto cleanup kobject_del\n",
|
pr_debug("kobject: '%s' (%p): auto cleanup kobject_del\n",
|
||||||
|
@ -310,27 +310,13 @@ static int test_dev_config_update_bool(const char *buf, size_t size,
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static ssize_t
|
static ssize_t test_dev_config_show_bool(char *buf, bool val)
|
||||||
test_dev_config_show_bool(char *buf,
|
|
||||||
bool config)
|
|
||||||
{
|
{
|
||||||
bool val;
|
|
||||||
|
|
||||||
mutex_lock(&test_fw_mutex);
|
|
||||||
val = config;
|
|
||||||
mutex_unlock(&test_fw_mutex);
|
|
||||||
|
|
||||||
return snprintf(buf, PAGE_SIZE, "%d\n", val);
|
return snprintf(buf, PAGE_SIZE, "%d\n", val);
|
||||||
}
|
}
|
||||||
|
|
||||||
static ssize_t test_dev_config_show_int(char *buf, int cfg)
|
static ssize_t test_dev_config_show_int(char *buf, int val)
|
||||||
{
|
{
|
||||||
int val;
|
|
||||||
|
|
||||||
mutex_lock(&test_fw_mutex);
|
|
||||||
val = cfg;
|
|
||||||
mutex_unlock(&test_fw_mutex);
|
|
||||||
|
|
||||||
return snprintf(buf, PAGE_SIZE, "%d\n", val);
|
return snprintf(buf, PAGE_SIZE, "%d\n", val);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -354,14 +340,8 @@ static int test_dev_config_update_u8(const char *buf, size_t size, u8 *cfg)
|
|||||||
return size;
|
return size;
|
||||||
}
|
}
|
||||||
|
|
||||||
static ssize_t test_dev_config_show_u8(char *buf, u8 cfg)
|
static ssize_t test_dev_config_show_u8(char *buf, u8 val)
|
||||||
{
|
{
|
||||||
u8 val;
|
|
||||||
|
|
||||||
mutex_lock(&test_fw_mutex);
|
|
||||||
val = cfg;
|
|
||||||
mutex_unlock(&test_fw_mutex);
|
|
||||||
|
|
||||||
return snprintf(buf, PAGE_SIZE, "%u\n", val);
|
return snprintf(buf, PAGE_SIZE, "%u\n", val);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -644,7 +644,9 @@ static void __init fwnode_pointer(void)
|
|||||||
test(second_name, "%pfwP", software_node_fwnode(&softnodes[1]));
|
test(second_name, "%pfwP", software_node_fwnode(&softnodes[1]));
|
||||||
test(third_name, "%pfwP", software_node_fwnode(&softnodes[2]));
|
test(third_name, "%pfwP", software_node_fwnode(&softnodes[2]));
|
||||||
|
|
||||||
software_node_unregister_nodes(softnodes);
|
software_node_unregister(&softnodes[2]);
|
||||||
|
software_node_unregister(&softnodes[1]);
|
||||||
|
software_node_unregister(&softnodes[0]);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void __init
|
static void __init
|
||||||
|
Loading…
Reference in New Issue
Block a user