Commit 84928ce3 authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'driver-core-5.15-rc4' of...

Merge tag 'driver-core-5.15-rc4' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/driver-core

Pull driver core fixes from Greg KH:
 "Here are some driver core and kernfs fixes for reported issues for
  5.15-rc4. These fixes include:

   - kernfs positive dentry bugfix

   - debugfs_create_file_size error path fix

   - cpumask sysfs file bugfix to preserve the user/kernel abi (has been
     reported multiple times.)

   - devlink fixes for mdiobus devices as reported by the subsystem
     maintainers.

  Also included in here are some devlink debugging changes to make it
  easier for people to report problems when asked. They have already
  helped with the mdiobus and other subsystems reporting issues.

  All of these have been linux-next for a while with no reported issues"

* tag 'driver-core-5.15-rc4' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/driver-core:
  kernfs: also call kernfs_set_rev() for positive dentry
  driver core: Add debug logs when fwnode links are added/deleted
  driver core: Create __fwnode_link_del() helper function
  driver core: Set deferred probe reason when deferred by driver core
  net: mdiobus: Set FWNODE_FLAG_NEEDS_CHILD_BOUND_ON_ADD for mdiobus parents
  driver core: fw_devlink: Add support for FWNODE_FLAG_NEEDS_CHILD_BOUND_ON_ADD
  driver core: fw_devlink: Improve handling of cyclic dependencies
  cpumask: Omit terminating null byte in cpumap_print_{list,bitmask}_to_buf
  debugfs: debugfs_create_file_size(): use IS_ERR to check for error
parents 777feaba df38d852
...@@ -95,12 +95,29 @@ int fwnode_link_add(struct fwnode_handle *con, struct fwnode_handle *sup) ...@@ -95,12 +95,29 @@ int fwnode_link_add(struct fwnode_handle *con, struct fwnode_handle *sup)
list_add(&link->s_hook, &sup->consumers); list_add(&link->s_hook, &sup->consumers);
list_add(&link->c_hook, &con->suppliers); list_add(&link->c_hook, &con->suppliers);
pr_debug("%pfwP Linked as a fwnode consumer to %pfwP\n",
con, sup);
out: out:
mutex_unlock(&fwnode_link_lock); mutex_unlock(&fwnode_link_lock);
return ret; return ret;
} }
/**
* __fwnode_link_del - Delete a link between two fwnode_handles.
* @link: the fwnode_link to be deleted
*
* The fwnode_link_lock needs to be held when this function is called.
*/
static void __fwnode_link_del(struct fwnode_link *link)
{
pr_debug("%pfwP Dropping the fwnode link to %pfwP\n",
link->consumer, link->supplier);
list_del(&link->s_hook);
list_del(&link->c_hook);
kfree(link);
}
/** /**
* fwnode_links_purge_suppliers - Delete all supplier links of fwnode_handle. * fwnode_links_purge_suppliers - Delete all supplier links of fwnode_handle.
* @fwnode: fwnode whose supplier links need to be deleted * @fwnode: fwnode whose supplier links need to be deleted
...@@ -112,11 +129,8 @@ static void fwnode_links_purge_suppliers(struct fwnode_handle *fwnode) ...@@ -112,11 +129,8 @@ static void fwnode_links_purge_suppliers(struct fwnode_handle *fwnode)
struct fwnode_link *link, *tmp; struct fwnode_link *link, *tmp;
mutex_lock(&fwnode_link_lock); mutex_lock(&fwnode_link_lock);
list_for_each_entry_safe(link, tmp, &fwnode->suppliers, c_hook) { list_for_each_entry_safe(link, tmp, &fwnode->suppliers, c_hook)
list_del(&link->s_hook); __fwnode_link_del(link);
list_del(&link->c_hook);
kfree(link);
}
mutex_unlock(&fwnode_link_lock); mutex_unlock(&fwnode_link_lock);
} }
...@@ -131,11 +145,8 @@ static void fwnode_links_purge_consumers(struct fwnode_handle *fwnode) ...@@ -131,11 +145,8 @@ static void fwnode_links_purge_consumers(struct fwnode_handle *fwnode)
struct fwnode_link *link, *tmp; struct fwnode_link *link, *tmp;
mutex_lock(&fwnode_link_lock); mutex_lock(&fwnode_link_lock);
list_for_each_entry_safe(link, tmp, &fwnode->consumers, s_hook) { list_for_each_entry_safe(link, tmp, &fwnode->consumers, s_hook)
list_del(&link->s_hook); __fwnode_link_del(link);
list_del(&link->c_hook);
kfree(link);
}
mutex_unlock(&fwnode_link_lock); mutex_unlock(&fwnode_link_lock);
} }
...@@ -975,6 +986,7 @@ int device_links_check_suppliers(struct device *dev) ...@@ -975,6 +986,7 @@ int device_links_check_suppliers(struct device *dev)
{ {
struct device_link *link; struct device_link *link;
int ret = 0; int ret = 0;
struct fwnode_handle *sup_fw;
/* /*
* Device waiting for supplier to become available is not allowed to * Device waiting for supplier to become available is not allowed to
...@@ -983,10 +995,11 @@ int device_links_check_suppliers(struct device *dev) ...@@ -983,10 +995,11 @@ int device_links_check_suppliers(struct device *dev)
mutex_lock(&fwnode_link_lock); mutex_lock(&fwnode_link_lock);
if (dev->fwnode && !list_empty(&dev->fwnode->suppliers) && if (dev->fwnode && !list_empty(&dev->fwnode->suppliers) &&
!fw_devlink_is_permissive()) { !fw_devlink_is_permissive()) {
dev_dbg(dev, "probe deferral - wait for supplier %pfwP\n", sup_fw = list_first_entry(&dev->fwnode->suppliers,
list_first_entry(&dev->fwnode->suppliers, struct fwnode_link,
struct fwnode_link, c_hook)->supplier;
c_hook)->supplier); dev_err_probe(dev, -EPROBE_DEFER, "wait for supplier %pfwP\n",
sup_fw);
mutex_unlock(&fwnode_link_lock); mutex_unlock(&fwnode_link_lock);
return -EPROBE_DEFER; return -EPROBE_DEFER;
} }
...@@ -1001,8 +1014,9 @@ int device_links_check_suppliers(struct device *dev) ...@@ -1001,8 +1014,9 @@ int device_links_check_suppliers(struct device *dev)
if (link->status != DL_STATE_AVAILABLE && if (link->status != DL_STATE_AVAILABLE &&
!(link->flags & DL_FLAG_SYNC_STATE_ONLY)) { !(link->flags & DL_FLAG_SYNC_STATE_ONLY)) {
device_links_missing_supplier(dev); device_links_missing_supplier(dev);
dev_dbg(dev, "probe deferral - supplier %s not ready\n", dev_err_probe(dev, -EPROBE_DEFER,
dev_name(link->supplier)); "supplier %s not ready\n",
dev_name(link->supplier));
ret = -EPROBE_DEFER; ret = -EPROBE_DEFER;
break; break;
} }
...@@ -1722,6 +1736,25 @@ static int fw_devlink_create_devlink(struct device *con, ...@@ -1722,6 +1736,25 @@ static int fw_devlink_create_devlink(struct device *con,
struct device *sup_dev; struct device *sup_dev;
int ret = 0; int ret = 0;
/*
* In some cases, a device P might also be a supplier to its child node
* C. However, this would defer the probe of C until the probe of P
* completes successfully. This is perfectly fine in the device driver
* model. device_add() doesn't guarantee probe completion of the device
* by the time it returns.
*
* However, there are a few drivers that assume C will finish probing
* as soon as it's added and before P finishes probing. So, we provide
* a flag to let fw_devlink know not to delay the probe of C until the
* probe of P completes successfully.
*
* When such a flag is set, we can't create device links where P is the
* supplier of C as that would delay the probe of C.
*/
if (sup_handle->flags & FWNODE_FLAG_NEEDS_CHILD_BOUND_ON_ADD &&
fwnode_is_ancestor_of(sup_handle, con->fwnode))
return -EINVAL;
sup_dev = get_dev_from_fwnode(sup_handle); sup_dev = get_dev_from_fwnode(sup_handle);
if (sup_dev) { if (sup_dev) {
/* /*
...@@ -1772,14 +1805,21 @@ static int fw_devlink_create_devlink(struct device *con, ...@@ -1772,14 +1805,21 @@ static int fw_devlink_create_devlink(struct device *con,
* be broken by applying logic. Check for these types of cycles and * be broken by applying logic. Check for these types of cycles and
* break them so that devices in the cycle probe properly. * break them so that devices in the cycle probe properly.
* *
* If the supplier's parent is dependent on the consumer, then * If the supplier's parent is dependent on the consumer, then the
* the consumer-supplier dependency is a false dependency. So, * consumer and supplier have a cyclic dependency. Since fw_devlink
* treat it as an invalid link. * can't tell which of the inferred dependencies are incorrect, don't
* enforce probe ordering between any of the devices in this cyclic
* dependency. Do this by relaxing all the fw_devlink device links in
* this cycle and by treating the fwnode link between the consumer and
* the supplier as an invalid dependency.
*/ */
sup_dev = fwnode_get_next_parent_dev(sup_handle); sup_dev = fwnode_get_next_parent_dev(sup_handle);
if (sup_dev && device_is_dependent(con, sup_dev)) { if (sup_dev && device_is_dependent(con, sup_dev)) {
dev_dbg(con, "Not linking to %pfwP - False link\n", dev_info(con, "Fixing up cyclic dependency with %pfwP (%s)\n",
sup_handle); sup_handle, dev_name(sup_dev));
device_links_write_lock();
fw_devlink_relax_cycle(con, sup_dev);
device_links_write_unlock();
ret = -EINVAL; ret = -EINVAL;
} else { } else {
/* /*
...@@ -1858,9 +1898,7 @@ static void __fw_devlink_link_to_consumers(struct device *dev) ...@@ -1858,9 +1898,7 @@ static void __fw_devlink_link_to_consumers(struct device *dev)
if (!own_link || ret == -EAGAIN) if (!own_link || ret == -EAGAIN)
continue; continue;
list_del(&link->s_hook); __fwnode_link_del(link);
list_del(&link->c_hook);
kfree(link);
} }
} }
...@@ -1912,9 +1950,7 @@ static void __fw_devlink_link_to_suppliers(struct device *dev, ...@@ -1912,9 +1950,7 @@ static void __fw_devlink_link_to_suppliers(struct device *dev,
if (!own_link || ret == -EAGAIN) if (!own_link || ret == -EAGAIN)
continue; continue;
list_del(&link->s_hook); __fwnode_link_del(link);
list_del(&link->c_hook);
kfree(link);
/* If no device link was created, nothing more to do. */ /* If no device link was created, nothing more to do. */
if (ret) if (ret)
......
...@@ -525,6 +525,10 @@ int __mdiobus_register(struct mii_bus *bus, struct module *owner) ...@@ -525,6 +525,10 @@ int __mdiobus_register(struct mii_bus *bus, struct module *owner)
NULL == bus->read || NULL == bus->write) NULL == bus->read || NULL == bus->write)
return -EINVAL; return -EINVAL;
if (bus->parent && bus->parent->of_node)
bus->parent->of_node->fwnode.flags |=
FWNODE_FLAG_NEEDS_CHILD_BOUND_ON_ADD;
BUG_ON(bus->state != MDIOBUS_ALLOCATED && BUG_ON(bus->state != MDIOBUS_ALLOCATED &&
bus->state != MDIOBUS_UNREGISTERED); bus->state != MDIOBUS_UNREGISTERED);
......
...@@ -528,7 +528,7 @@ void debugfs_create_file_size(const char *name, umode_t mode, ...@@ -528,7 +528,7 @@ void debugfs_create_file_size(const char *name, umode_t mode,
{ {
struct dentry *de = debugfs_create_file(name, mode, parent, data, fops); struct dentry *de = debugfs_create_file(name, mode, parent, data, fops);
if (de) if (!IS_ERR(de))
d_inode(de)->i_size = file_size; d_inode(de)->i_size = file_size;
} }
EXPORT_SYMBOL_GPL(debugfs_create_file_size); EXPORT_SYMBOL_GPL(debugfs_create_file_size);
......
...@@ -1116,8 +1116,13 @@ static struct dentry *kernfs_iop_lookup(struct inode *dir, ...@@ -1116,8 +1116,13 @@ static struct dentry *kernfs_iop_lookup(struct inode *dir,
if (!inode) if (!inode)
inode = ERR_PTR(-ENOMEM); inode = ERR_PTR(-ENOMEM);
} }
/* Needed only for negative dentry validation */ /*
if (!inode) * Needed for negative dentry validation.
* The negative dentry can be created in kernfs_iop_lookup()
* or transforms from positive dentry in dentry_unlink_inode()
* called from vfs_rmdir().
*/
if (!IS_ERR(inode))
kernfs_set_rev(parent, dentry); kernfs_set_rev(parent, dentry);
up_read(&kernfs_rwsem); up_read(&kernfs_rwsem);
......
...@@ -996,14 +996,15 @@ cpumap_print_to_pagebuf(bool list, char *buf, const struct cpumask *mask) ...@@ -996,14 +996,15 @@ cpumap_print_to_pagebuf(bool list, char *buf, const struct cpumask *mask)
* cpumask; Typically used by bin_attribute to export cpumask bitmask * cpumask; Typically used by bin_attribute to export cpumask bitmask
* ABI. * ABI.
* *
* Returns the length of how many bytes have been copied. * Returns the length of how many bytes have been copied, excluding
* terminating '\0'.
*/ */
static inline ssize_t static inline ssize_t
cpumap_print_bitmask_to_buf(char *buf, const struct cpumask *mask, cpumap_print_bitmask_to_buf(char *buf, const struct cpumask *mask,
loff_t off, size_t count) loff_t off, size_t count)
{ {
return bitmap_print_bitmask_to_buf(buf, cpumask_bits(mask), return bitmap_print_bitmask_to_buf(buf, cpumask_bits(mask),
nr_cpu_ids, off, count); nr_cpu_ids, off, count) - 1;
} }
/** /**
...@@ -1018,7 +1019,7 @@ cpumap_print_list_to_buf(char *buf, const struct cpumask *mask, ...@@ -1018,7 +1019,7 @@ cpumap_print_list_to_buf(char *buf, const struct cpumask *mask,
loff_t off, size_t count) loff_t off, size_t count)
{ {
return bitmap_print_list_to_buf(buf, cpumask_bits(mask), return bitmap_print_list_to_buf(buf, cpumask_bits(mask),
nr_cpu_ids, off, count); nr_cpu_ids, off, count) - 1;
} }
#if NR_CPUS <= BITS_PER_LONG #if NR_CPUS <= BITS_PER_LONG
......
...@@ -22,10 +22,15 @@ struct device; ...@@ -22,10 +22,15 @@ struct device;
* LINKS_ADDED: The fwnode has already be parsed to add fwnode links. * LINKS_ADDED: The fwnode has already be parsed to add fwnode links.
* NOT_DEVICE: The fwnode will never be populated as a struct device. * NOT_DEVICE: The fwnode will never be populated as a struct device.
* INITIALIZED: The hardware corresponding to fwnode has been initialized. * INITIALIZED: The hardware corresponding to fwnode has been initialized.
* NEEDS_CHILD_BOUND_ON_ADD: For this fwnode/device to probe successfully, its
* driver needs its child devices to be bound with
* their respective drivers as soon as they are
* added.
*/ */
#define FWNODE_FLAG_LINKS_ADDED BIT(0) #define FWNODE_FLAG_LINKS_ADDED BIT(0)
#define FWNODE_FLAG_NOT_DEVICE BIT(1) #define FWNODE_FLAG_NOT_DEVICE BIT(1)
#define FWNODE_FLAG_INITIALIZED BIT(2) #define FWNODE_FLAG_INITIALIZED BIT(2)
#define FWNODE_FLAG_NEEDS_CHILD_BOUND_ON_ADD BIT(3)
struct fwnode_handle { struct fwnode_handle {
struct fwnode_handle *secondary; struct fwnode_handle *secondary;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment