mirror of
https://github.com/BobTheBlinker/android_kernel_motorola_sm6375.git
synced 2026-10-28 02:32:09 -04:00
Merge android11-5.4.57 (3f413d0) into msm-5.4
* refs/heads/tmp-3f413d0: Linux 5.4.57 bpf: sockmap: Require attach_bpf_fd when detaching a program selftests: bpf: Fix detach from sockmap tests ext4: fix direct I/O read error arm64: Workaround circular dependency in pointer_auth.h random32: move the pseudo-random 32-bit definitions to prandom.h random32: remove net_rand_state from the latent entropy gcc plugin random: fix circular include dependency on arm64 after addition of percpu.h ARM: percpu.h: fix build error random32: update the net random state on interrupt and activity ANDROID: Update ABI xml UPSTREAM: of: property: Add device link support for pinctrl-0 through pinctrl-8 UPSTREAM: of: property: Add device link support for multiple DT bindings UPSTREAM: of: property: Add device link support for extcon UPSTREAM: driver core: Change delimiter in devlink device's name to "--" UPSTREAM: driver core: Fix sleeping in invalid context during device link deletion BACKPORT: driver core: Add waiting_for_supplier sysfs file for devices UPSTREAM: driver core: Add state_synced sysfs file for devices that support it UPSTREAM: driver core: Expose device link details in sysfs UPSTREAM: driver core: Avoid deferred probe due to fw_devlink_pause/resume() UPSTREAM: driver core: Rename dev_links_info.defer_sync to defer_hook UPSTREAM: driver core: Don't do deferred probe in parallel with kernel_init thread UPSTREAM: arm64/module: Optimize module load time by optimizing PLT counting FROMGIT: scsi: block: pm: Simplify resume handling Change-Id: Ide67c767b3a0f455ab5cec4b571ab599eae813d5 Signed-off-by: Blagovest Kolenichev <[email protected]>
This commit is contained in:
commit
33a0fb78c7
29 changed files with 7201 additions and 6239 deletions
|
|
@ -142,7 +142,6 @@ extern char *make_class_name(const char *name, struct kobject *kobj);
|
|||
extern int devres_release_all(struct device *dev);
|
||||
extern void device_block_probing(void);
|
||||
extern void device_unblock_probing(void);
|
||||
extern void driver_deferred_probe_force_trigger(void);
|
||||
|
||||
/* /sys/devices directory */
|
||||
extern struct kset *devices_kset;
|
||||
|
|
|
|||
|
|
@ -50,6 +50,7 @@ static DEFINE_MUTEX(wfs_lock);
|
|||
static LIST_HEAD(deferred_sync);
|
||||
static unsigned int defer_sync_state_count = 1;
|
||||
static unsigned int defer_fw_devlink_count;
|
||||
static LIST_HEAD(deferred_fw_devlink);
|
||||
static DEFINE_MUTEX(defer_fw_devlink_lock);
|
||||
|
||||
#ifdef CONFIG_SRCU
|
||||
|
|
@ -234,6 +235,210 @@ void device_pm_move_to_tail(struct device *dev)
|
|||
device_links_read_unlock(idx);
|
||||
}
|
||||
|
||||
#define to_devlink(dev) container_of((dev), struct device_link, link_dev)
|
||||
|
||||
static ssize_t status_show(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
char *status;
|
||||
|
||||
switch (to_devlink(dev)->status) {
|
||||
case DL_STATE_NONE:
|
||||
status = "not tracked"; break;
|
||||
case DL_STATE_DORMANT:
|
||||
status = "dormant"; break;
|
||||
case DL_STATE_AVAILABLE:
|
||||
status = "available"; break;
|
||||
case DL_STATE_CONSUMER_PROBE:
|
||||
status = "consumer probing"; break;
|
||||
case DL_STATE_ACTIVE:
|
||||
status = "active"; break;
|
||||
case DL_STATE_SUPPLIER_UNBIND:
|
||||
status = "supplier unbinding"; break;
|
||||
default:
|
||||
status = "unknown"; break;
|
||||
}
|
||||
return sprintf(buf, "%s\n", status);
|
||||
}
|
||||
static DEVICE_ATTR_RO(status);
|
||||
|
||||
static ssize_t auto_remove_on_show(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct device_link *link = to_devlink(dev);
|
||||
char *str;
|
||||
|
||||
if (link->flags & DL_FLAG_AUTOREMOVE_SUPPLIER)
|
||||
str = "supplier unbind";
|
||||
else if (link->flags & DL_FLAG_AUTOREMOVE_CONSUMER)
|
||||
str = "consumer unbind";
|
||||
else
|
||||
str = "never";
|
||||
|
||||
return sprintf(buf, "%s\n", str);
|
||||
}
|
||||
static DEVICE_ATTR_RO(auto_remove_on);
|
||||
|
||||
static ssize_t runtime_pm_show(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct device_link *link = to_devlink(dev);
|
||||
|
||||
return sprintf(buf, "%d\n", !!(link->flags & DL_FLAG_PM_RUNTIME));
|
||||
}
|
||||
static DEVICE_ATTR_RO(runtime_pm);
|
||||
|
||||
static ssize_t sync_state_only_show(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct device_link *link = to_devlink(dev);
|
||||
|
||||
return sprintf(buf, "%d\n", !!(link->flags & DL_FLAG_SYNC_STATE_ONLY));
|
||||
}
|
||||
static DEVICE_ATTR_RO(sync_state_only);
|
||||
|
||||
static struct attribute *devlink_attrs[] = {
|
||||
&dev_attr_status.attr,
|
||||
&dev_attr_auto_remove_on.attr,
|
||||
&dev_attr_runtime_pm.attr,
|
||||
&dev_attr_sync_state_only.attr,
|
||||
NULL,
|
||||
};
|
||||
ATTRIBUTE_GROUPS(devlink);
|
||||
|
||||
static void device_link_free(struct device_link *link)
|
||||
{
|
||||
while (refcount_dec_not_one(&link->rpm_active))
|
||||
pm_runtime_put(link->supplier);
|
||||
|
||||
put_device(link->consumer);
|
||||
put_device(link->supplier);
|
||||
kfree(link);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_SRCU
|
||||
static void __device_link_free_srcu(struct rcu_head *rhead)
|
||||
{
|
||||
device_link_free(container_of(rhead, struct device_link, rcu_head));
|
||||
}
|
||||
|
||||
static void devlink_dev_release(struct device *dev)
|
||||
{
|
||||
struct device_link *link = to_devlink(dev);
|
||||
|
||||
call_srcu(&device_links_srcu, &link->rcu_head, __device_link_free_srcu);
|
||||
}
|
||||
#else
|
||||
static void devlink_dev_release(struct device *dev)
|
||||
{
|
||||
device_link_free(to_devlink(dev));
|
||||
}
|
||||
#endif
|
||||
|
||||
static struct class devlink_class = {
|
||||
.name = "devlink",
|
||||
.owner = THIS_MODULE,
|
||||
.dev_groups = devlink_groups,
|
||||
.dev_release = devlink_dev_release,
|
||||
};
|
||||
|
||||
static int devlink_add_symlinks(struct device *dev,
|
||||
struct class_interface *class_intf)
|
||||
{
|
||||
int ret;
|
||||
size_t len;
|
||||
struct device_link *link = to_devlink(dev);
|
||||
struct device *sup = link->supplier;
|
||||
struct device *con = link->consumer;
|
||||
char *buf;
|
||||
|
||||
len = max(strlen(dev_name(sup)), strlen(dev_name(con)));
|
||||
len += strlen("supplier:") + 1;
|
||||
buf = kzalloc(len, GFP_KERNEL);
|
||||
if (!buf)
|
||||
return -ENOMEM;
|
||||
|
||||
ret = sysfs_create_link(&link->link_dev.kobj, &sup->kobj, "supplier");
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
ret = sysfs_create_link(&link->link_dev.kobj, &con->kobj, "consumer");
|
||||
if (ret)
|
||||
goto err_con;
|
||||
|
||||
snprintf(buf, len, "consumer:%s", dev_name(con));
|
||||
ret = sysfs_create_link(&sup->kobj, &link->link_dev.kobj, buf);
|
||||
if (ret)
|
||||
goto err_con_dev;
|
||||
|
||||
snprintf(buf, len, "supplier:%s", dev_name(sup));
|
||||
ret = sysfs_create_link(&con->kobj, &link->link_dev.kobj, buf);
|
||||
if (ret)
|
||||
goto err_sup_dev;
|
||||
|
||||
goto out;
|
||||
|
||||
err_sup_dev:
|
||||
snprintf(buf, len, "consumer:%s", dev_name(con));
|
||||
sysfs_remove_link(&sup->kobj, buf);
|
||||
err_con_dev:
|
||||
sysfs_remove_link(&link->link_dev.kobj, "consumer");
|
||||
err_con:
|
||||
sysfs_remove_link(&link->link_dev.kobj, "supplier");
|
||||
out:
|
||||
kfree(buf);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void devlink_remove_symlinks(struct device *dev,
|
||||
struct class_interface *class_intf)
|
||||
{
|
||||
struct device_link *link = to_devlink(dev);
|
||||
size_t len;
|
||||
struct device *sup = link->supplier;
|
||||
struct device *con = link->consumer;
|
||||
char *buf;
|
||||
|
||||
sysfs_remove_link(&link->link_dev.kobj, "consumer");
|
||||
sysfs_remove_link(&link->link_dev.kobj, "supplier");
|
||||
|
||||
len = max(strlen(dev_name(sup)), strlen(dev_name(con)));
|
||||
len += strlen("supplier:") + 1;
|
||||
buf = kzalloc(len, GFP_KERNEL);
|
||||
if (!buf) {
|
||||
WARN(1, "Unable to properly free device link symlinks!\n");
|
||||
return;
|
||||
}
|
||||
|
||||
snprintf(buf, len, "supplier:%s", dev_name(sup));
|
||||
sysfs_remove_link(&con->kobj, buf);
|
||||
snprintf(buf, len, "consumer:%s", dev_name(con));
|
||||
sysfs_remove_link(&sup->kobj, buf);
|
||||
kfree(buf);
|
||||
}
|
||||
|
||||
static struct class_interface devlink_class_intf = {
|
||||
.class = &devlink_class,
|
||||
.add_dev = devlink_add_symlinks,
|
||||
.remove_dev = devlink_remove_symlinks,
|
||||
};
|
||||
|
||||
static int __init devlink_class_init(void)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = class_register(&devlink_class);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = class_interface_register(&devlink_class_intf);
|
||||
if (ret)
|
||||
class_unregister(&devlink_class);
|
||||
|
||||
return ret;
|
||||
}
|
||||
postcore_initcall(devlink_class_init);
|
||||
|
||||
#define DL_MANAGED_LINK_FLAGS (DL_FLAG_AUTOREMOVE_CONSUMER | \
|
||||
DL_FLAG_AUTOREMOVE_SUPPLIER | \
|
||||
DL_FLAG_AUTOPROBE_CONSUMER | \
|
||||
|
|
@ -406,13 +611,6 @@ struct device_link *device_link_add(struct device *consumer,
|
|||
|
||||
refcount_set(&link->rpm_active, 1);
|
||||
|
||||
if (flags & DL_FLAG_PM_RUNTIME) {
|
||||
if (flags & DL_FLAG_RPM_ACTIVE)
|
||||
refcount_inc(&link->rpm_active);
|
||||
|
||||
pm_runtime_new_link(consumer);
|
||||
}
|
||||
|
||||
get_device(supplier);
|
||||
link->supplier = supplier;
|
||||
INIT_LIST_HEAD(&link->s_node);
|
||||
|
|
@ -422,6 +620,25 @@ struct device_link *device_link_add(struct device *consumer,
|
|||
link->flags = flags;
|
||||
kref_init(&link->kref);
|
||||
|
||||
link->link_dev.class = &devlink_class;
|
||||
device_set_pm_not_required(&link->link_dev);
|
||||
dev_set_name(&link->link_dev, "%s--%s",
|
||||
dev_name(supplier), dev_name(consumer));
|
||||
if (device_register(&link->link_dev)) {
|
||||
put_device(consumer);
|
||||
put_device(supplier);
|
||||
kfree(link);
|
||||
link = NULL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (flags & DL_FLAG_PM_RUNTIME) {
|
||||
if (flags & DL_FLAG_RPM_ACTIVE)
|
||||
refcount_inc(&link->rpm_active);
|
||||
|
||||
pm_runtime_new_link(consumer);
|
||||
}
|
||||
|
||||
/* Determine the initial link state. */
|
||||
if (flags & DL_FLAG_STATELESS)
|
||||
link->status = DL_STATE_NONE;
|
||||
|
|
@ -537,22 +754,7 @@ static void device_link_add_missing_supplier_links(void)
|
|||
mutex_unlock(&wfs_lock);
|
||||
}
|
||||
|
||||
static void device_link_free(struct device_link *link)
|
||||
{
|
||||
while (refcount_dec_not_one(&link->rpm_active))
|
||||
pm_runtime_put(link->supplier);
|
||||
|
||||
put_device(link->consumer);
|
||||
put_device(link->supplier);
|
||||
kfree(link);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_SRCU
|
||||
static void __device_link_free_srcu(struct rcu_head *rhead)
|
||||
{
|
||||
device_link_free(container_of(rhead, struct device_link, rcu_head));
|
||||
}
|
||||
|
||||
static void __device_link_del(struct kref *kref)
|
||||
{
|
||||
struct device_link *link = container_of(kref, struct device_link, kref);
|
||||
|
|
@ -565,7 +767,7 @@ static void __device_link_del(struct kref *kref)
|
|||
|
||||
list_del_rcu(&link->s_node);
|
||||
list_del_rcu(&link->c_node);
|
||||
call_srcu(&device_links_srcu, &link->rcu_head, __device_link_free_srcu);
|
||||
device_unregister(&link->link_dev);
|
||||
}
|
||||
#else /* !CONFIG_SRCU */
|
||||
static void __device_link_del(struct kref *kref)
|
||||
|
|
@ -580,7 +782,7 @@ static void __device_link_del(struct kref *kref)
|
|||
|
||||
list_del(&link->s_node);
|
||||
list_del(&link->c_node);
|
||||
device_link_free(link);
|
||||
device_unregister(&link->link_dev);
|
||||
}
|
||||
#endif /* !CONFIG_SRCU */
|
||||
|
||||
|
|
@ -753,11 +955,11 @@ static void __device_links_queue_sync_state(struct device *dev,
|
|||
*/
|
||||
dev->state_synced = true;
|
||||
|
||||
if (WARN_ON(!list_empty(&dev->links.defer_sync)))
|
||||
if (WARN_ON(!list_empty(&dev->links.defer_hook)))
|
||||
return;
|
||||
|
||||
get_device(dev);
|
||||
list_add_tail(&dev->links.defer_sync, list);
|
||||
list_add_tail(&dev->links.defer_hook, list);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -775,8 +977,8 @@ static void device_links_flush_sync_list(struct list_head *list,
|
|||
{
|
||||
struct device *dev, *tmp;
|
||||
|
||||
list_for_each_entry_safe(dev, tmp, list, links.defer_sync) {
|
||||
list_del_init(&dev->links.defer_sync);
|
||||
list_for_each_entry_safe(dev, tmp, list, links.defer_hook) {
|
||||
list_del_init(&dev->links.defer_hook);
|
||||
|
||||
if (dev != dont_lock_dev)
|
||||
device_lock(dev);
|
||||
|
|
@ -814,12 +1016,12 @@ void device_links_supplier_sync_state_resume(void)
|
|||
if (defer_sync_state_count)
|
||||
goto out;
|
||||
|
||||
list_for_each_entry_safe(dev, tmp, &deferred_sync, links.defer_sync) {
|
||||
list_for_each_entry_safe(dev, tmp, &deferred_sync, links.defer_hook) {
|
||||
/*
|
||||
* Delete from deferred_sync list before queuing it to
|
||||
* sync_list because defer_sync is used for both lists.
|
||||
* sync_list because defer_hook is used for both lists.
|
||||
*/
|
||||
list_del_init(&dev->links.defer_sync);
|
||||
list_del_init(&dev->links.defer_hook);
|
||||
__device_links_queue_sync_state(dev, &sync_list);
|
||||
}
|
||||
out:
|
||||
|
|
@ -837,8 +1039,8 @@ late_initcall(sync_state_resume_initcall);
|
|||
|
||||
static void __device_links_supplier_defer_sync(struct device *sup)
|
||||
{
|
||||
if (list_empty(&sup->links.defer_sync) && dev_has_sync_state(sup))
|
||||
list_add_tail(&sup->links.defer_sync, &deferred_sync);
|
||||
if (list_empty(&sup->links.defer_hook) && dev_has_sync_state(sup))
|
||||
list_add_tail(&sup->links.defer_hook, &deferred_sync);
|
||||
}
|
||||
|
||||
static void device_link_drop_managed(struct device_link *link)
|
||||
|
|
@ -848,6 +1050,22 @@ static void device_link_drop_managed(struct device_link *link)
|
|||
kref_put(&link->kref, __device_link_del);
|
||||
}
|
||||
|
||||
static ssize_t waiting_for_supplier_show(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
bool val;
|
||||
|
||||
device_lock(dev);
|
||||
mutex_lock(&wfs_lock);
|
||||
val = !list_empty(&dev->links.needs_suppliers)
|
||||
&& dev->links.need_for_probe;
|
||||
mutex_unlock(&wfs_lock);
|
||||
device_unlock(dev);
|
||||
return sprintf(buf, "%u\n", val);
|
||||
}
|
||||
static DEVICE_ATTR_RO(waiting_for_supplier);
|
||||
|
||||
/**
|
||||
* device_links_driver_bound - Update device links after probing its driver.
|
||||
* @dev: Device to update the links for.
|
||||
|
|
@ -872,6 +1090,7 @@ void device_links_driver_bound(struct device *dev)
|
|||
mutex_lock(&wfs_lock);
|
||||
list_del_init(&dev->links.needs_suppliers);
|
||||
mutex_unlock(&wfs_lock);
|
||||
device_remove_file(dev, &dev_attr_waiting_for_supplier);
|
||||
|
||||
device_links_write_lock();
|
||||
|
||||
|
|
@ -1051,7 +1270,7 @@ void device_links_driver_cleanup(struct device *dev)
|
|||
WRITE_ONCE(link->status, DL_STATE_DORMANT);
|
||||
}
|
||||
|
||||
list_del_init(&dev->links.defer_sync);
|
||||
list_del_init(&dev->links.defer_hook);
|
||||
__device_links_no_driver(dev);
|
||||
|
||||
device_links_write_unlock();
|
||||
|
|
@ -1158,6 +1377,9 @@ static void device_links_purge(struct device *dev)
|
|||
{
|
||||
struct device_link *link, *ln;
|
||||
|
||||
if (dev->class == &devlink_class)
|
||||
return;
|
||||
|
||||
mutex_lock(&wfs_lock);
|
||||
list_del(&dev->links.needs_suppliers);
|
||||
mutex_unlock(&wfs_lock);
|
||||
|
|
@ -1208,6 +1430,12 @@ static void fw_devlink_link_device(struct device *dev)
|
|||
fw_ret = fwnode_call_int_op(dev->fwnode, add_links, dev);
|
||||
} else {
|
||||
fw_ret = -ENODEV;
|
||||
/*
|
||||
* defer_hook is not used to add device to deferred_sync list
|
||||
* until device is bound. Since deferred fw devlink also blocks
|
||||
* probing, same list hook can be used for deferred_fw_devlink.
|
||||
*/
|
||||
list_add_tail(&dev->links.defer_hook, &deferred_fw_devlink);
|
||||
}
|
||||
|
||||
if (fw_ret == -ENODEV)
|
||||
|
|
@ -1276,6 +1504,9 @@ void fw_devlink_pause(void)
|
|||
*/
|
||||
void fw_devlink_resume(void)
|
||||
{
|
||||
struct device *dev, *tmp;
|
||||
LIST_HEAD(probe_list);
|
||||
|
||||
mutex_lock(&defer_fw_devlink_lock);
|
||||
if (!defer_fw_devlink_count) {
|
||||
WARN(true, "Unmatched fw_devlink pause/resume!");
|
||||
|
|
@ -1287,9 +1518,19 @@ void fw_devlink_resume(void)
|
|||
goto out;
|
||||
|
||||
device_link_add_missing_supplier_links();
|
||||
driver_deferred_probe_force_trigger();
|
||||
list_splice_tail_init(&deferred_fw_devlink, &probe_list);
|
||||
out:
|
||||
mutex_unlock(&defer_fw_devlink_lock);
|
||||
|
||||
/*
|
||||
* bus_probe_device() can cause new devices to get added and they'll
|
||||
* try to grab defer_fw_devlink_lock. So, this needs to be done outside
|
||||
* the defer_fw_devlink_lock.
|
||||
*/
|
||||
list_for_each_entry_safe(dev, tmp, &probe_list, links.defer_hook) {
|
||||
list_del_init(&dev->links.defer_hook);
|
||||
bus_probe_device(dev);
|
||||
}
|
||||
}
|
||||
/* Device links support end. */
|
||||
|
||||
|
|
@ -1925,8 +2166,14 @@ static int device_add_attrs(struct device *dev)
|
|||
goto err_remove_dev_groups;
|
||||
}
|
||||
|
||||
error = device_create_file(dev, &dev_attr_waiting_for_supplier);
|
||||
if (error)
|
||||
goto err_remove_dev_online;
|
||||
|
||||
return 0;
|
||||
|
||||
err_remove_dev_online:
|
||||
device_remove_file(dev, &dev_attr_online);
|
||||
err_remove_dev_groups:
|
||||
device_remove_groups(dev, dev->groups);
|
||||
err_remove_type_groups:
|
||||
|
|
@ -1944,6 +2191,7 @@ static void device_remove_attrs(struct device *dev)
|
|||
struct class *class = dev->class;
|
||||
const struct device_type *type = dev->type;
|
||||
|
||||
device_remove_file(dev, &dev_attr_waiting_for_supplier);
|
||||
device_remove_file(dev, &dev_attr_online);
|
||||
device_remove_groups(dev, dev->groups);
|
||||
|
||||
|
|
@ -2148,7 +2396,7 @@ void device_initialize(struct device *dev)
|
|||
INIT_LIST_HEAD(&dev->links.consumers);
|
||||
INIT_LIST_HEAD(&dev->links.suppliers);
|
||||
INIT_LIST_HEAD(&dev->links.needs_suppliers);
|
||||
INIT_LIST_HEAD(&dev->links.defer_sync);
|
||||
INIT_LIST_HEAD(&dev->links.defer_hook);
|
||||
dev->links.status = DL_DEV_NO_DRIVER;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(device_initialize);
|
||||
|
|
|
|||
|
|
@ -164,11 +164,6 @@ static void driver_deferred_probe_trigger(void)
|
|||
if (!driver_deferred_probe_enable)
|
||||
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
|
||||
* should be triggered to be reprobed. Move all the deferred devices
|
||||
|
|
@ -494,6 +489,18 @@ static void driver_deferred_probe_add_trigger(struct device *dev,
|
|||
driver_deferred_probe_trigger();
|
||||
}
|
||||
|
||||
static ssize_t state_synced_show(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
bool val;
|
||||
|
||||
device_lock(dev);
|
||||
val = dev->state_synced;
|
||||
device_unlock(dev);
|
||||
return sprintf(buf, "%u\n", val);
|
||||
}
|
||||
static DEVICE_ATTR_RO(state_synced);
|
||||
|
||||
static int really_probe(struct device *dev, struct device_driver *drv)
|
||||
{
|
||||
int ret = -EPROBE_DEFER;
|
||||
|
|
@ -567,9 +574,16 @@ re_probe:
|
|||
goto dev_groups_failed;
|
||||
}
|
||||
|
||||
if (dev_has_sync_state(dev) &&
|
||||
device_create_file(dev, &dev_attr_state_synced)) {
|
||||
dev_err(dev, "state_synced sysfs add failed\n");
|
||||
goto dev_sysfs_state_synced_failed;
|
||||
}
|
||||
|
||||
if (test_remove) {
|
||||
test_remove = false;
|
||||
|
||||
device_remove_file(dev, &dev_attr_state_synced);
|
||||
device_remove_groups(dev, drv->dev_groups);
|
||||
|
||||
if (dev->bus->remove)
|
||||
|
|
@ -599,6 +613,8 @@ re_probe:
|
|||
drv->bus->name, __func__, dev_name(dev), drv->name);
|
||||
goto done;
|
||||
|
||||
dev_sysfs_state_synced_failed:
|
||||
device_remove_groups(dev, drv->dev_groups);
|
||||
dev_groups_failed:
|
||||
if (dev->bus->remove)
|
||||
dev->bus->remove(dev);
|
||||
|
|
@ -1134,6 +1150,7 @@ static void __device_release_driver(struct device *dev, struct device *parent)
|
|||
|
||||
pm_runtime_put_sync(dev);
|
||||
|
||||
device_remove_file(dev, &dev_attr_state_synced);
|
||||
device_remove_groups(dev, drv->dev_groups);
|
||||
|
||||
if (dev->bus && dev->bus->remove)
|
||||
|
|
|
|||
Loading…
Reference in a new issue