mirror of
https://github.com/Dasharo/linux.git
synced 2026-03-06 15:25:10 -08:00
Merge tag 'driver-core-6.9-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/driver-core
Pull driver core updates from Greg KH:
"Here is the "big" set of driver core and kernfs changes for 6.9-rc1.
Nothing all that crazy here, just some good updates that include:
- automatic attribute group hiding from Dan Williams (he fixed up my
horrible attempt at doing this.)
- kobject lock contention fixes from Eric Dumazet
- driver core cleanups from Andy
- kernfs rcu work from Tejun
- fw_devlink changes to resolve some reported issues
- other minor changes, all details in the shortlog
All of these have been in linux-next for a long time with no reported
issues"
* tag 'driver-core-6.9-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/driver-core: (28 commits)
device: core: Log warning for devices pending deferred probe on timeout
driver: core: Use dev_* instead of pr_* so device metadata is added
driver: core: Log probe failure as error and with device metadata
of: property: fw_devlink: Add support for "post-init-providers" property
driver core: Add FWLINK_FLAG_IGNORE to completely ignore a fwnode link
driver core: Adds flags param to fwnode_link_add()
debugfs: fix wait/cancellation handling during remove
device property: Don't use "proxy" headers
device property: Move enum dev_dma_attr to fwnode.h
driver core: Move fw_devlink stuff to where it belongs
driver core: Drop unneeded 'extern' keyword in fwnode.h
firmware_loader: Suppress warning on FW_OPT_NO_WARN flag
sysfs:Addresses documentation in sysfs_merge_group and sysfs_unmerge_group.
firmware_loader: introduce __free() cleanup hanler
platform-msi: Remove usage of the deprecated ida_simple_xx() API
sysfs: Introduce DEFINE_SIMPLE_SYSFS_GROUP_VISIBLE()
sysfs: Document new "group visible" helpers
sysfs: Fix crash on empty group attributes array
sysfs: Introduce a mechanism to hide static attribute_groups
sysfs: Introduce a mechanism to hide static attribute_groups
...
This commit is contained in:
@@ -751,7 +751,7 @@ static int __component_add(struct device *dev, const struct component_ops *ops,
|
||||
* component_bind_all(). See also &struct component_ops.
|
||||
*
|
||||
* @subcomponent must be nonzero and is used to differentiate between multiple
|
||||
* components registerd on the same device @dev. These components are match
|
||||
* components registered on the same device @dev. These components are match
|
||||
* using component_match_add_typed().
|
||||
*
|
||||
* The component needs to be unregistered at driver unload/disconnect by
|
||||
@@ -781,7 +781,7 @@ EXPORT_SYMBOL_GPL(component_add_typed);
|
||||
* The component needs to be unregistered at driver unload/disconnect by
|
||||
* calling component_del().
|
||||
*
|
||||
* See also component_add_typed() for a variant that allows multipled different
|
||||
* See also component_add_typed() for a variant that allows multiple different
|
||||
* components on the same device.
|
||||
*/
|
||||
int component_add(struct device *dev, const struct component_ops *ops)
|
||||
|
||||
@@ -92,12 +92,13 @@ static int __fwnode_link_add(struct fwnode_handle *con,
|
||||
return 0;
|
||||
}
|
||||
|
||||
int fwnode_link_add(struct fwnode_handle *con, struct fwnode_handle *sup)
|
||||
int fwnode_link_add(struct fwnode_handle *con, struct fwnode_handle *sup,
|
||||
u8 flags)
|
||||
{
|
||||
int ret;
|
||||
|
||||
mutex_lock(&fwnode_link_lock);
|
||||
ret = __fwnode_link_add(con, sup, 0);
|
||||
ret = __fwnode_link_add(con, sup, flags);
|
||||
mutex_unlock(&fwnode_link_lock);
|
||||
return ret;
|
||||
}
|
||||
@@ -1011,7 +1012,8 @@ static struct fwnode_handle *fwnode_links_check_suppliers(
|
||||
return NULL;
|
||||
|
||||
list_for_each_entry(link, &fwnode->suppliers, c_hook)
|
||||
if (!(link->flags & FWLINK_FLAG_CYCLE))
|
||||
if (!(link->flags &
|
||||
(FWLINK_FLAG_CYCLE | FWLINK_FLAG_IGNORE)))
|
||||
return link->supplier;
|
||||
|
||||
return NULL;
|
||||
@@ -1871,6 +1873,7 @@ static void fw_devlink_unblock_consumers(struct device *dev)
|
||||
device_links_write_unlock();
|
||||
}
|
||||
|
||||
#define get_dev_from_fwnode(fwnode) get_device((fwnode)->dev)
|
||||
|
||||
static bool fwnode_init_without_drv(struct fwnode_handle *fwnode)
|
||||
{
|
||||
@@ -1901,6 +1904,63 @@ static bool fwnode_ancestor_init_without_drv(struct fwnode_handle *fwnode)
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* fwnode_is_ancestor_of - Test if @ancestor is ancestor of @child
|
||||
* @ancestor: Firmware which is tested for being an ancestor
|
||||
* @child: Firmware which is tested for being the child
|
||||
*
|
||||
* A node is considered an ancestor of itself too.
|
||||
*
|
||||
* Return: true if @ancestor is an ancestor of @child. Otherwise, returns false.
|
||||
*/
|
||||
static bool fwnode_is_ancestor_of(const struct fwnode_handle *ancestor,
|
||||
const struct fwnode_handle *child)
|
||||
{
|
||||
struct fwnode_handle *parent;
|
||||
|
||||
if (IS_ERR_OR_NULL(ancestor))
|
||||
return false;
|
||||
|
||||
if (child == ancestor)
|
||||
return true;
|
||||
|
||||
fwnode_for_each_parent_node(child, parent) {
|
||||
if (parent == ancestor) {
|
||||
fwnode_handle_put(parent);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* fwnode_get_next_parent_dev - Find device of closest ancestor fwnode
|
||||
* @fwnode: firmware node
|
||||
*
|
||||
* Given a firmware node (@fwnode), this function finds its closest ancestor
|
||||
* firmware node that has a corresponding struct device and returns that struct
|
||||
* device.
|
||||
*
|
||||
* The caller is responsible for calling put_device() on the returned device
|
||||
* pointer.
|
||||
*
|
||||
* Return: a pointer to the device of the @fwnode's closest ancestor.
|
||||
*/
|
||||
static struct device *fwnode_get_next_parent_dev(const struct fwnode_handle *fwnode)
|
||||
{
|
||||
struct fwnode_handle *parent;
|
||||
struct device *dev;
|
||||
|
||||
fwnode_for_each_parent_node(fwnode, parent) {
|
||||
dev = get_dev_from_fwnode(parent);
|
||||
if (dev) {
|
||||
fwnode_handle_put(parent);
|
||||
return dev;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* __fw_devlink_relax_cycles - Relax and mark dependency cycles.
|
||||
* @con: Potential consumer device.
|
||||
@@ -1962,6 +2022,9 @@ static bool __fw_devlink_relax_cycles(struct device *con,
|
||||
}
|
||||
|
||||
list_for_each_entry(link, &sup_handle->suppliers, c_hook) {
|
||||
if (link->flags & FWLINK_FLAG_IGNORE)
|
||||
continue;
|
||||
|
||||
if (__fw_devlink_relax_cycles(con, link->supplier)) {
|
||||
__fwnode_link_cycle(link);
|
||||
ret = true;
|
||||
@@ -2040,6 +2103,9 @@ static int fw_devlink_create_devlink(struct device *con,
|
||||
int ret = 0;
|
||||
u32 flags;
|
||||
|
||||
if (link->flags & FWLINK_FLAG_IGNORE)
|
||||
return 0;
|
||||
|
||||
if (con->fwnode == link->consumer)
|
||||
flags = fw_devlink_get_flags(link->flags);
|
||||
else
|
||||
|
||||
@@ -366,7 +366,7 @@ static int cpu_uevent(const struct device *dev, struct kobj_uevent_env *env)
|
||||
}
|
||||
#endif
|
||||
|
||||
struct bus_type cpu_subsys = {
|
||||
const struct bus_type cpu_subsys = {
|
||||
.name = "cpu",
|
||||
.dev_name = "cpu",
|
||||
.match = cpu_subsys_match,
|
||||
|
||||
@@ -313,7 +313,7 @@ static void deferred_probe_timeout_work_func(struct work_struct *work)
|
||||
|
||||
mutex_lock(&deferred_probe_mutex);
|
||||
list_for_each_entry(p, &deferred_probe_pending_list, deferred_probe)
|
||||
dev_info(p->device, "deferred probe pending: %s", p->deferred_probe_reason ?: "(reason unknown)\n");
|
||||
dev_warn(p->device, "deferred probe pending: %s", p->deferred_probe_reason ?: "(reason unknown)\n");
|
||||
mutex_unlock(&deferred_probe_mutex);
|
||||
|
||||
fw_devlink_probing_done();
|
||||
@@ -397,13 +397,12 @@ bool device_is_bound(struct device *dev)
|
||||
static void driver_bound(struct device *dev)
|
||||
{
|
||||
if (device_is_bound(dev)) {
|
||||
pr_warn("%s: device %s already bound\n",
|
||||
__func__, kobject_name(&dev->kobj));
|
||||
dev_warn(dev, "%s: device already bound\n", __func__);
|
||||
return;
|
||||
}
|
||||
|
||||
pr_debug("driver: '%s': %s: bound to device '%s'\n", dev->driver->name,
|
||||
__func__, dev_name(dev));
|
||||
dev_dbg(dev, "driver: '%s': %s: bound to device\n", dev->driver->name,
|
||||
__func__);
|
||||
|
||||
klist_add_tail(&dev->p->knode_driver, &dev->driver->p->klist_devices);
|
||||
device_links_driver_bound(dev);
|
||||
@@ -587,13 +586,13 @@ static int call_driver_probe(struct device *dev, struct device_driver *drv)
|
||||
break;
|
||||
case -ENODEV:
|
||||
case -ENXIO:
|
||||
pr_debug("%s: probe of %s rejects match %d\n",
|
||||
drv->name, dev_name(dev), ret);
|
||||
dev_dbg(dev, "probe with driver %s rejects match %d\n",
|
||||
drv->name, ret);
|
||||
break;
|
||||
default:
|
||||
/* driver matched but the probe failed */
|
||||
pr_warn("%s: probe of %s failed with error %d\n",
|
||||
drv->name, dev_name(dev), ret);
|
||||
dev_err(dev, "probe with driver %s failed with error %d\n",
|
||||
drv->name, ret);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -620,8 +619,8 @@ static int really_probe(struct device *dev, struct device_driver *drv)
|
||||
if (link_ret == -EPROBE_DEFER)
|
||||
return link_ret;
|
||||
|
||||
pr_debug("bus: '%s': %s: probing driver %s with device %s\n",
|
||||
drv->bus->name, __func__, drv->name, dev_name(dev));
|
||||
dev_dbg(dev, "bus: '%s': %s: probing driver %s with device\n",
|
||||
drv->bus->name, __func__, drv->name);
|
||||
if (!list_empty(&dev->devres_head)) {
|
||||
dev_crit(dev, "Resources present before probing\n");
|
||||
ret = -EBUSY;
|
||||
@@ -644,8 +643,7 @@ re_probe:
|
||||
|
||||
ret = driver_sysfs_add(dev);
|
||||
if (ret) {
|
||||
pr_err("%s: driver_sysfs_add(%s) failed\n",
|
||||
__func__, dev_name(dev));
|
||||
dev_err(dev, "%s: driver_sysfs_add failed\n", __func__);
|
||||
goto sysfs_failed;
|
||||
}
|
||||
|
||||
@@ -706,8 +704,8 @@ re_probe:
|
||||
dev->pm_domain->sync(dev);
|
||||
|
||||
driver_bound(dev);
|
||||
pr_debug("bus: '%s': %s: bound device %s to driver %s\n",
|
||||
drv->bus->name, __func__, dev_name(dev), drv->name);
|
||||
dev_dbg(dev, "bus: '%s': %s: bound device to driver %s\n",
|
||||
drv->bus->name, __func__, drv->name);
|
||||
goto done;
|
||||
|
||||
dev_sysfs_state_synced_failed:
|
||||
@@ -786,8 +784,8 @@ static int __driver_probe_device(struct device_driver *drv, struct device *dev)
|
||||
return -EBUSY;
|
||||
|
||||
dev->can_match = true;
|
||||
pr_debug("bus: '%s': %s: matched device %s with driver %s\n",
|
||||
drv->bus->name, __func__, dev_name(dev), drv->name);
|
||||
dev_dbg(dev, "bus: '%s': %s: matched device with driver %s\n",
|
||||
drv->bus->name, __func__, drv->name);
|
||||
|
||||
pm_runtime_get_suppliers(dev);
|
||||
if (dev->parent)
|
||||
|
||||
@@ -551,12 +551,16 @@ fw_get_filesystem_firmware(struct device *device, struct fw_priv *fw_priv,
|
||||
file_size_ptr,
|
||||
READING_FIRMWARE);
|
||||
if (rc < 0) {
|
||||
if (rc != -ENOENT)
|
||||
dev_warn(device, "loading %s failed with error %d\n",
|
||||
path, rc);
|
||||
else
|
||||
dev_dbg(device, "loading %s failed for no such file or directory.\n",
|
||||
path);
|
||||
if (!(fw_priv->opt_flags & FW_OPT_NO_WARN)) {
|
||||
if (rc != -ENOENT)
|
||||
dev_warn(device,
|
||||
"loading %s failed with error %d\n",
|
||||
path, rc);
|
||||
else
|
||||
dev_dbg(device,
|
||||
"loading %s failed for no such file or directory.\n",
|
||||
path);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
size = rc;
|
||||
|
||||
@@ -174,8 +174,8 @@ static int platform_msi_alloc_priv_data(struct device *dev, unsigned int nvec,
|
||||
if (!datap)
|
||||
return -ENOMEM;
|
||||
|
||||
datap->devid = ida_simple_get(&platform_msi_devid_ida,
|
||||
0, 1 << DEV_ID_SHIFT, GFP_KERNEL);
|
||||
datap->devid = ida_alloc_max(&platform_msi_devid_ida,
|
||||
(1 << DEV_ID_SHIFT) - 1, GFP_KERNEL);
|
||||
if (datap->devid < 0) {
|
||||
err = datap->devid;
|
||||
kfree(datap);
|
||||
@@ -193,7 +193,7 @@ static void platform_msi_free_priv_data(struct device *dev)
|
||||
struct platform_msi_priv_data *data = dev->msi.data->platform_data;
|
||||
|
||||
dev->msi.data->platform_data = NULL;
|
||||
ida_simple_remove(&platform_msi_devid_ida, data->devid);
|
||||
ida_free(&platform_msi_devid_ida, data->devid);
|
||||
kfree(data);
|
||||
}
|
||||
|
||||
|
||||
@@ -7,15 +7,16 @@
|
||||
* Mika Westerberg <mika.westerberg@linux.intel.com>
|
||||
*/
|
||||
|
||||
#include <linux/acpi.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/export.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/kconfig.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_address.h>
|
||||
#include <linux/of_graph.h>
|
||||
#include <linux/of_irq.h>
|
||||
#include <linux/property.h>
|
||||
#include <linux/phy.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/types.h>
|
||||
|
||||
struct fwnode_handle *__dev_fwnode(struct device *dev)
|
||||
{
|
||||
@@ -699,34 +700,6 @@ struct fwnode_handle *fwnode_get_next_parent(struct fwnode_handle *fwnode)
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(fwnode_get_next_parent);
|
||||
|
||||
/**
|
||||
* fwnode_get_next_parent_dev - Find device of closest ancestor fwnode
|
||||
* @fwnode: firmware node
|
||||
*
|
||||
* Given a firmware node (@fwnode), this function finds its closest ancestor
|
||||
* firmware node that has a corresponding struct device and returns that struct
|
||||
* device.
|
||||
*
|
||||
* The caller is responsible for calling put_device() on the returned device
|
||||
* pointer.
|
||||
*
|
||||
* Return: a pointer to the device of the @fwnode's closest ancestor.
|
||||
*/
|
||||
struct device *fwnode_get_next_parent_dev(const struct fwnode_handle *fwnode)
|
||||
{
|
||||
struct fwnode_handle *parent;
|
||||
struct device *dev;
|
||||
|
||||
fwnode_for_each_parent_node(fwnode, parent) {
|
||||
dev = get_dev_from_fwnode(parent);
|
||||
if (dev) {
|
||||
fwnode_handle_put(parent);
|
||||
return dev;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* fwnode_count_parents - Return the number of parents a node has
|
||||
* @fwnode: The node the parents of which are to be counted
|
||||
@@ -773,34 +746,6 @@ struct fwnode_handle *fwnode_get_nth_parent(struct fwnode_handle *fwnode,
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(fwnode_get_nth_parent);
|
||||
|
||||
/**
|
||||
* fwnode_is_ancestor_of - Test if @ancestor is ancestor of @child
|
||||
* @ancestor: Firmware which is tested for being an ancestor
|
||||
* @child: Firmware which is tested for being the child
|
||||
*
|
||||
* A node is considered an ancestor of itself too.
|
||||
*
|
||||
* Return: true if @ancestor is an ancestor of @child. Otherwise, returns false.
|
||||
*/
|
||||
bool fwnode_is_ancestor_of(const struct fwnode_handle *ancestor, const struct fwnode_handle *child)
|
||||
{
|
||||
struct fwnode_handle *parent;
|
||||
|
||||
if (IS_ERR_OR_NULL(ancestor))
|
||||
return false;
|
||||
|
||||
if (child == ancestor)
|
||||
return true;
|
||||
|
||||
fwnode_for_each_parent_node(child, parent) {
|
||||
if (parent == ancestor) {
|
||||
fwnode_handle_put(parent);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* fwnode_get_next_child_node - Return the next child node handle for a node
|
||||
* @fwnode: Firmware node to find the next child node for.
|
||||
|
||||
@@ -6,10 +6,21 @@
|
||||
* Author: Heikki Krogerus <heikki.krogerus@linux.intel.com>
|
||||
*/
|
||||
|
||||
#include <linux/container_of.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/export.h>
|
||||
#include <linux/idr.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/kobject.h>
|
||||
#include <linux/kstrtox.h>
|
||||
#include <linux/list.h>
|
||||
#include <linux/property.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/sysfs.h>
|
||||
#include <linux/types.h>
|
||||
|
||||
#include "base.h"
|
||||
|
||||
|
||||
@@ -336,7 +336,7 @@ static int efifb_add_links(struct fwnode_handle *fwnode)
|
||||
if (!sup_np)
|
||||
return 0;
|
||||
|
||||
fwnode_link_add(fwnode, of_fwnode_handle(sup_np));
|
||||
fwnode_link_add(fwnode, of_fwnode_handle(sup_np), 0);
|
||||
of_node_put(sup_np);
|
||||
|
||||
return 0;
|
||||
|
||||
@@ -1072,7 +1072,8 @@ of_fwnode_device_get_match_data(const struct fwnode_handle *fwnode,
|
||||
}
|
||||
|
||||
static void of_link_to_phandle(struct device_node *con_np,
|
||||
struct device_node *sup_np)
|
||||
struct device_node *sup_np,
|
||||
u8 flags)
|
||||
{
|
||||
struct device_node *tmp_np = of_node_get(sup_np);
|
||||
|
||||
@@ -1091,7 +1092,7 @@ static void of_link_to_phandle(struct device_node *con_np,
|
||||
tmp_np = of_get_next_parent(tmp_np);
|
||||
}
|
||||
|
||||
fwnode_link_add(of_fwnode_handle(con_np), of_fwnode_handle(sup_np));
|
||||
fwnode_link_add(of_fwnode_handle(con_np), of_fwnode_handle(sup_np), flags);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1204,6 +1205,8 @@ static struct device_node *parse_##fname(struct device_node *np, \
|
||||
* to a struct device, implement this ops so fw_devlink can use it
|
||||
* to find the true consumer.
|
||||
* @optional: Describes whether a supplier is mandatory or not
|
||||
* @fwlink_flags: Optional fwnode link flags to use when creating a fwnode link
|
||||
* for this property.
|
||||
*
|
||||
* Returns:
|
||||
* parse_prop() return values are
|
||||
@@ -1216,6 +1219,7 @@ struct supplier_bindings {
|
||||
const char *prop_name, int index);
|
||||
struct device_node *(*get_con_dev)(struct device_node *np);
|
||||
bool optional;
|
||||
u8 fwlink_flags;
|
||||
};
|
||||
|
||||
DEFINE_SIMPLE_PROP(clocks, "clocks", "#clock-cells")
|
||||
@@ -1247,6 +1251,7 @@ DEFINE_SIMPLE_PROP(leds, "leds", NULL)
|
||||
DEFINE_SIMPLE_PROP(backlight, "backlight", NULL)
|
||||
DEFINE_SIMPLE_PROP(panel, "panel", NULL)
|
||||
DEFINE_SIMPLE_PROP(msi_parent, "msi-parent", "#msi-cells")
|
||||
DEFINE_SIMPLE_PROP(post_init_providers, "post-init-providers", NULL)
|
||||
DEFINE_SUFFIX_PROP(regulators, "-supply", NULL)
|
||||
DEFINE_SUFFIX_PROP(gpio, "-gpio", "#gpio-cells")
|
||||
|
||||
@@ -1357,6 +1362,10 @@ static const struct supplier_bindings of_supplier_bindings[] = {
|
||||
{ .parse_prop = parse_regulators, },
|
||||
{ .parse_prop = parse_gpio, },
|
||||
{ .parse_prop = parse_gpios, },
|
||||
{
|
||||
.parse_prop = parse_post_init_providers,
|
||||
.fwlink_flags = FWLINK_FLAG_IGNORE,
|
||||
},
|
||||
{}
|
||||
};
|
||||
|
||||
@@ -1401,7 +1410,7 @@ static int of_link_property(struct device_node *con_np, const char *prop_name)
|
||||
: of_node_get(con_np);
|
||||
matched = true;
|
||||
i++;
|
||||
of_link_to_phandle(con_dev_np, phandle);
|
||||
of_link_to_phandle(con_dev_np, phandle, s->fwlink_flags);
|
||||
of_node_put(phandle);
|
||||
of_node_put(con_dev_np);
|
||||
}
|
||||
|
||||
@@ -751,13 +751,28 @@ static void __debugfs_file_removed(struct dentry *dentry)
|
||||
if ((unsigned long)fsd & DEBUGFS_FSDATA_IS_REAL_FOPS_BIT)
|
||||
return;
|
||||
|
||||
/* if we hit zero, just wait for all to finish */
|
||||
if (!refcount_dec_and_test(&fsd->active_users)) {
|
||||
wait_for_completion(&fsd->active_users_drained);
|
||||
/* if this was the last reference, we're done */
|
||||
if (refcount_dec_and_test(&fsd->active_users))
|
||||
return;
|
||||
}
|
||||
|
||||
/* if we didn't hit zero, try to cancel any we can */
|
||||
/*
|
||||
* If there's still a reference, the code that obtained it can
|
||||
* be in different states:
|
||||
* - The common case of not using cancellations, or already
|
||||
* after debugfs_leave_cancellation(), where we just need
|
||||
* to wait for debugfs_file_put() which signals the completion;
|
||||
* - inside a cancellation section, i.e. between
|
||||
* debugfs_enter_cancellation() and debugfs_leave_cancellation(),
|
||||
* in which case we need to trigger the ->cancel() function,
|
||||
* and then wait for debugfs_file_put() just like in the
|
||||
* previous case;
|
||||
* - before debugfs_enter_cancellation() (but obviously after
|
||||
* debugfs_file_get()), in which case we may not see the
|
||||
* cancellation in the list on the first round of the loop,
|
||||
* but debugfs_enter_cancellation() signals the completion
|
||||
* after adding it, so this code gets woken up to call the
|
||||
* ->cancel() function.
|
||||
*/
|
||||
while (refcount_read(&fsd->active_users)) {
|
||||
struct debugfs_cancellation *c;
|
||||
|
||||
|
||||
@@ -529,6 +529,20 @@ void kernfs_get(struct kernfs_node *kn)
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(kernfs_get);
|
||||
|
||||
static void kernfs_free_rcu(struct rcu_head *rcu)
|
||||
{
|
||||
struct kernfs_node *kn = container_of(rcu, struct kernfs_node, rcu);
|
||||
|
||||
kfree_const(kn->name);
|
||||
|
||||
if (kn->iattr) {
|
||||
simple_xattrs_free(&kn->iattr->xattrs, NULL);
|
||||
kmem_cache_free(kernfs_iattrs_cache, kn->iattr);
|
||||
}
|
||||
|
||||
kmem_cache_free(kernfs_node_cache, kn);
|
||||
}
|
||||
|
||||
/**
|
||||
* kernfs_put - put a reference count on a kernfs_node
|
||||
* @kn: the target kernfs_node
|
||||
@@ -557,16 +571,11 @@ void kernfs_put(struct kernfs_node *kn)
|
||||
if (kernfs_type(kn) == KERNFS_LINK)
|
||||
kernfs_put(kn->symlink.target_kn);
|
||||
|
||||
kfree_const(kn->name);
|
||||
|
||||
if (kn->iattr) {
|
||||
simple_xattrs_free(&kn->iattr->xattrs, NULL);
|
||||
kmem_cache_free(kernfs_iattrs_cache, kn->iattr);
|
||||
}
|
||||
spin_lock(&kernfs_idr_lock);
|
||||
idr_remove(&root->ino_idr, (u32)kernfs_ino(kn));
|
||||
spin_unlock(&kernfs_idr_lock);
|
||||
kmem_cache_free(kernfs_node_cache, kn);
|
||||
|
||||
call_rcu(&kn->rcu, kernfs_free_rcu);
|
||||
|
||||
kn = parent;
|
||||
if (kn) {
|
||||
@@ -575,7 +584,7 @@ void kernfs_put(struct kernfs_node *kn)
|
||||
} else {
|
||||
/* just released the root kn, free @root too */
|
||||
idr_destroy(&root->ino_idr);
|
||||
kfree(root);
|
||||
kfree_rcu(root, rcu);
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(kernfs_put);
|
||||
@@ -715,7 +724,7 @@ struct kernfs_node *kernfs_find_and_get_node_by_id(struct kernfs_root *root,
|
||||
ino_t ino = kernfs_id_ino(id);
|
||||
u32 gen = kernfs_id_gen(id);
|
||||
|
||||
spin_lock(&kernfs_idr_lock);
|
||||
rcu_read_lock();
|
||||
|
||||
kn = idr_find(&root->ino_idr, (u32)ino);
|
||||
if (!kn)
|
||||
@@ -739,10 +748,10 @@ struct kernfs_node *kernfs_find_and_get_node_by_id(struct kernfs_root *root,
|
||||
if (unlikely(!__kernfs_active(kn) || !atomic_inc_not_zero(&kn->count)))
|
||||
goto err_unlock;
|
||||
|
||||
spin_unlock(&kernfs_idr_lock);
|
||||
rcu_read_unlock();
|
||||
return kn;
|
||||
err_unlock:
|
||||
spin_unlock(&kernfs_idr_lock);
|
||||
rcu_read_unlock();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
@@ -483,9 +483,11 @@ static int kernfs_fop_mmap(struct file *file, struct vm_area_struct *vma)
|
||||
goto out_put;
|
||||
|
||||
rc = 0;
|
||||
of->mmapped = true;
|
||||
of_on(of)->nr_mmapped++;
|
||||
of->vm_ops = vma->vm_ops;
|
||||
if (!of->mmapped) {
|
||||
of->mmapped = true;
|
||||
of_on(of)->nr_mmapped++;
|
||||
of->vm_ops = vma->vm_ops;
|
||||
}
|
||||
vma->vm_ops = &kernfs_vm_ops;
|
||||
out_put:
|
||||
kernfs_put_active(of->kn);
|
||||
|
||||
@@ -49,6 +49,8 @@ struct kernfs_root {
|
||||
struct rw_semaphore kernfs_rwsem;
|
||||
struct rw_semaphore kernfs_iattr_rwsem;
|
||||
struct rw_semaphore kernfs_supers_rwsem;
|
||||
|
||||
struct rcu_head rcu;
|
||||
};
|
||||
|
||||
/* +1 to avoid triggering overflow warning when negating it */
|
||||
|
||||
@@ -31,6 +31,17 @@ static void remove_files(struct kernfs_node *parent,
|
||||
kernfs_remove_by_name(parent, (*bin_attr)->attr.name);
|
||||
}
|
||||
|
||||
static umode_t __first_visible(const struct attribute_group *grp, struct kobject *kobj)
|
||||
{
|
||||
if (grp->attrs && grp->attrs[0] && grp->is_visible)
|
||||
return grp->is_visible(kobj, grp->attrs[0], 0);
|
||||
|
||||
if (grp->bin_attrs && grp->bin_attrs[0] && grp->is_bin_visible)
|
||||
return grp->is_bin_visible(kobj, grp->bin_attrs[0], 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int create_files(struct kernfs_node *parent, struct kobject *kobj,
|
||||
kuid_t uid, kgid_t gid,
|
||||
const struct attribute_group *grp, int update)
|
||||
@@ -52,6 +63,7 @@ static int create_files(struct kernfs_node *parent, struct kobject *kobj,
|
||||
kernfs_remove_by_name(parent, (*attr)->name);
|
||||
if (grp->is_visible) {
|
||||
mode = grp->is_visible(kobj, *attr, i);
|
||||
mode &= ~SYSFS_GROUP_INVISIBLE;
|
||||
if (!mode)
|
||||
continue;
|
||||
}
|
||||
@@ -81,6 +93,7 @@ static int create_files(struct kernfs_node *parent, struct kobject *kobj,
|
||||
(*bin_attr)->attr.name);
|
||||
if (grp->is_bin_visible) {
|
||||
mode = grp->is_bin_visible(kobj, *bin_attr, i);
|
||||
mode &= ~SYSFS_GROUP_INVISIBLE;
|
||||
if (!mode)
|
||||
continue;
|
||||
}
|
||||
@@ -127,16 +140,31 @@ static int internal_create_group(struct kobject *kobj, int update,
|
||||
|
||||
kobject_get_ownership(kobj, &uid, &gid);
|
||||
if (grp->name) {
|
||||
umode_t mode = __first_visible(grp, kobj);
|
||||
|
||||
if (mode & SYSFS_GROUP_INVISIBLE)
|
||||
mode = 0;
|
||||
else
|
||||
mode = S_IRWXU | S_IRUGO | S_IXUGO;
|
||||
|
||||
if (update) {
|
||||
kn = kernfs_find_and_get(kobj->sd, grp->name);
|
||||
if (!kn) {
|
||||
pr_warn("Can't update unknown attr grp name: %s/%s\n",
|
||||
kobj->name, grp->name);
|
||||
return -EINVAL;
|
||||
pr_debug("attr grp %s/%s not created yet\n",
|
||||
kobj->name, grp->name);
|
||||
/* may have been invisible prior to this update */
|
||||
update = 0;
|
||||
} else if (!mode) {
|
||||
sysfs_remove_group(kobj, grp);
|
||||
kernfs_put(kn);
|
||||
return 0;
|
||||
}
|
||||
} else {
|
||||
kn = kernfs_create_dir_ns(kobj->sd, grp->name,
|
||||
S_IRWXU | S_IRUGO | S_IXUGO,
|
||||
}
|
||||
|
||||
if (!update) {
|
||||
if (!mode)
|
||||
return 0;
|
||||
kn = kernfs_create_dir_ns(kobj->sd, grp->name, mode,
|
||||
uid, gid, kobj, NULL);
|
||||
if (IS_ERR(kn)) {
|
||||
if (PTR_ERR(kn) == -EEXIST)
|
||||
@@ -279,9 +307,8 @@ void sysfs_remove_group(struct kobject *kobj,
|
||||
if (grp->name) {
|
||||
kn = kernfs_find_and_get(parent, grp->name);
|
||||
if (!kn) {
|
||||
WARN(!kn, KERN_WARNING
|
||||
"sysfs group '%s' not found for kobject '%s'\n",
|
||||
grp->name, kobject_name(kobj));
|
||||
pr_debug("sysfs group '%s' not found for kobject '%s'\n",
|
||||
grp->name, kobject_name(kobj));
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
@@ -318,13 +345,13 @@ void sysfs_remove_groups(struct kobject *kobj,
|
||||
EXPORT_SYMBOL_GPL(sysfs_remove_groups);
|
||||
|
||||
/**
|
||||
* sysfs_merge_group - merge files into a pre-existing attribute group.
|
||||
* sysfs_merge_group - merge files into a pre-existing named attribute group.
|
||||
* @kobj: The kobject containing the group.
|
||||
* @grp: The files to create and the attribute group they belong to.
|
||||
*
|
||||
* This function returns an error if the group doesn't exist or any of the
|
||||
* files already exist in that group, in which case none of the new files
|
||||
* are created.
|
||||
* This function returns an error if the group doesn't exist, the .name field is
|
||||
* NULL or any of the files already exist in that group, in which case none of
|
||||
* the new files are created.
|
||||
*/
|
||||
int sysfs_merge_group(struct kobject *kobj,
|
||||
const struct attribute_group *grp)
|
||||
@@ -356,7 +383,7 @@ int sysfs_merge_group(struct kobject *kobj,
|
||||
EXPORT_SYMBOL_GPL(sysfs_merge_group);
|
||||
|
||||
/**
|
||||
* sysfs_unmerge_group - remove files from a pre-existing attribute group.
|
||||
* sysfs_unmerge_group - remove files from a pre-existing named attribute group.
|
||||
* @kobj: The kobject containing the group.
|
||||
* @grp: The files to remove and the attribute group they belong to.
|
||||
*/
|
||||
|
||||
@@ -130,7 +130,7 @@ static inline void cpu_maps_update_done(void)
|
||||
static inline int add_cpu(unsigned int cpu) { return 0;}
|
||||
|
||||
#endif /* CONFIG_SMP */
|
||||
extern struct bus_type cpu_subsys;
|
||||
extern const struct bus_type cpu_subsys;
|
||||
|
||||
extern int lockdep_is_cpus_held(void);
|
||||
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
|
||||
#include <linux/types.h>
|
||||
#include <linux/compiler.h>
|
||||
#include <linux/cleanup.h>
|
||||
#include <linux/gfp.h>
|
||||
|
||||
#define FW_ACTION_NOUEVENT 0
|
||||
@@ -198,4 +199,6 @@ static inline void firmware_upload_unregister(struct fw_upload *fw_upload)
|
||||
|
||||
int firmware_request_cache(struct device *device, const char *name);
|
||||
|
||||
DEFINE_FREE(firmware, struct firmware *, release_firmware(_T))
|
||||
|
||||
#endif
|
||||
|
||||
@@ -9,10 +9,16 @@
|
||||
#ifndef _LINUX_FWNODE_H_
|
||||
#define _LINUX_FWNODE_H_
|
||||
|
||||
#include <linux/types.h>
|
||||
#include <linux/list.h>
|
||||
#include <linux/bits.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/list.h>
|
||||
#include <linux/types.h>
|
||||
|
||||
enum dev_dma_attr {
|
||||
DEV_DMA_NOT_SUPPORTED,
|
||||
DEV_DMA_NON_COHERENT,
|
||||
DEV_DMA_COHERENT,
|
||||
};
|
||||
|
||||
struct fwnode_operations;
|
||||
struct device;
|
||||
@@ -53,8 +59,10 @@ struct fwnode_handle {
|
||||
* fwnode link flags
|
||||
*
|
||||
* CYCLE: The fwnode link is part of a cycle. Don't defer probe.
|
||||
* IGNORE: Completely ignore this link, even during cycle detection.
|
||||
*/
|
||||
#define FWLINK_FLAG_CYCLE BIT(0)
|
||||
#define FWLINK_FLAG_IGNORE BIT(1)
|
||||
|
||||
struct fwnode_link {
|
||||
struct fwnode_handle *supplier;
|
||||
@@ -187,7 +195,6 @@ struct fwnode_operations {
|
||||
if (fwnode_has_op(fwnode, op)) \
|
||||
(fwnode)->ops->op(fwnode, ## __VA_ARGS__); \
|
||||
} while (false)
|
||||
#define get_dev_from_fwnode(fwnode) get_device((fwnode)->dev)
|
||||
|
||||
static inline void fwnode_init(struct fwnode_handle *fwnode,
|
||||
const struct fwnode_operations *ops)
|
||||
@@ -209,9 +216,10 @@ static inline void fwnode_dev_initialized(struct fwnode_handle *fwnode,
|
||||
fwnode->flags &= ~FWNODE_FLAG_INITIALIZED;
|
||||
}
|
||||
|
||||
extern bool fw_devlink_is_strict(void);
|
||||
int fwnode_link_add(struct fwnode_handle *con, struct fwnode_handle *sup);
|
||||
int fwnode_link_add(struct fwnode_handle *con, struct fwnode_handle *sup,
|
||||
u8 flags);
|
||||
void fwnode_links_purge(struct fwnode_handle *fwnode);
|
||||
void fw_devlink_purge_absent_suppliers(struct fwnode_handle *fwnode);
|
||||
bool fw_devlink_is_strict(void);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -206,23 +206,25 @@ struct kernfs_node {
|
||||
|
||||
const void *ns; /* namespace tag */
|
||||
unsigned int hash; /* ns + name hash */
|
||||
unsigned short flags;
|
||||
umode_t mode;
|
||||
|
||||
union {
|
||||
struct kernfs_elem_dir dir;
|
||||
struct kernfs_elem_symlink symlink;
|
||||
struct kernfs_elem_attr attr;
|
||||
};
|
||||
|
||||
void *priv;
|
||||
|
||||
/*
|
||||
* 64bit unique ID. On 64bit ino setups, id is the ino. On 32bit,
|
||||
* the low 32bits are ino and upper generation.
|
||||
*/
|
||||
u64 id;
|
||||
|
||||
unsigned short flags;
|
||||
umode_t mode;
|
||||
void *priv;
|
||||
struct kernfs_iattrs *iattr;
|
||||
|
||||
struct rcu_head rcu;
|
||||
};
|
||||
|
||||
/*
|
||||
|
||||
@@ -38,7 +38,7 @@ extern char uevent_helper[];
|
||||
#endif
|
||||
|
||||
/* counter to tag the uevent, read only except for the kobject core */
|
||||
extern u64 uevent_seqnum;
|
||||
extern atomic64_t uevent_seqnum;
|
||||
|
||||
/*
|
||||
* The actions here must match the index to the string array
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user