Driver core changes for 5.9-rc1

Here is the "big" set of changes to the driver core, and some drivers
 using the changes, for 5.9-rc1.
 
 "Biggest" thing in here is the device link exposure in sysfs, to help
 to tame the madness that is SoC device tree representations and driver
 interactions with it.
 
 Other stuff in here that is interesting is:
 	- device probe log helper so that drivers can report problems in
 	  a unified way easier.
 	- devres functions added
 	- DEVICE_ATTR_ADMIN_* macro added to make it harder to write
 	  incorrect sysfs file permissions
 	- documentation cleanups
 	- ability for debugfs to be present in the kernel, yet not
 	  exposed to userspace.  Needed for systems that want it
 	  enabled, but do not trust users, so they can still use some
 	  kernel functions that were otherwise disabled.
 	- other minor fixes and cleanups
 
 The patches outside of drivers/base/ all have acks from the respective
 subsystem maintainers to go through this tree instead of theirs.
 
 All of these have been in linux-next with no reported issues.
 
 Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
 -----BEGIN PGP SIGNATURE-----
 
 iG0EABECAC0WIQT0tgzFv3jCIUoxPcsxR9QN2y37KQUCXylhOQ8cZ3JlZ0Brcm9h
 aC5jb20ACgkQMUfUDdst+ylGdACeKqxm8IIDZycj0QjLUlPiEwVIROgAnjpf5jAB
 mb4jMvgEGsB6/FwxypPG
 =RUss
 -----END PGP SIGNATURE-----

Merge tag 'driver-core-5.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 changes to the driver core, and some drivers
  using the changes, for 5.9-rc1.

  "Biggest" thing in here is the device link exposure in sysfs, to help
  to tame the madness that is SoC device tree representations and driver
  interactions with it.

  Other stuff in here that is interesting is:

   - device probe log helper so that drivers can report problems in a
     unified way easier.

   - devres functions added

   - DEVICE_ATTR_ADMIN_* macro added to make it harder to write
     incorrect sysfs file permissions

   - documentation cleanups

   - ability for debugfs to be present in the kernel, yet not exposed to
     userspace. Needed for systems that want it enabled, but do not
     trust users, so they can still use some kernel functions that were
     otherwise disabled.

   - other minor fixes and cleanups

  The patches outside of drivers/base/ all have acks from the respective
  subsystem maintainers to go through this tree instead of theirs.

  All of these have been in linux-next with no reported issues"

* tag 'driver-core-5.9-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/driver-core: (39 commits)
  drm/bridge: lvds-codec: simplify error handling
  drm/bridge/sii8620: fix resource acquisition error handling
  driver core: add deferring probe reason to devices_deferred property
  driver core: add device probe log helper
  driver core: Avoid binding drivers to dead devices
  Revert "test_firmware: Test platform fw loading on non-EFI systems"
  firmware_loader: EFI firmware loader must handle pre-allocated buffer
  selftest/firmware: Add selftest timeout in settings
  test_firmware: Test platform fw loading on non-EFI systems
  driver core: Change delimiter in devlink device's name to "--"
  debugfs: Add access restriction option
  tracefs: Remove unnecessary debug_fs checks.
  driver core: Fix probe_count imbalance in really_probe()
  kobject: remove unused KOBJ_MAX action
  driver core: Fix sleeping in invalid context during device link deletion
  driver core: Add waiting_for_supplier sysfs file for devices
  driver core: Add state_synced sysfs file for devices that support it
  driver core: Expose device link details in sysfs
  driver core: Drop mention of obsolete bus rwsem from kernel-doc
  debugfs: file: Remove unnecessary cast in kfree()
  ...
This commit is contained in:
Linus Torvalds 2020-08-05 11:52:17 -07:00
commit dd27111e32
35 changed files with 944 additions and 253 deletions

View File

@ -18,3 +18,13 @@ Description:
devices to opt-out of driver binding using a driver_override
name such as "none". Only a single driver may be specified in
the override, there is no support for parsing delimiters.
What: /sys/bus/platform/devices/.../numa_node
Date: June 2020
Contact: Barry Song <song.bao.hua@hisilicon.com>
Description:
This file contains the NUMA node to which the platform device
is attached. It won't be visible if the node is unknown. The
value comes from an ACPI _PXM method or a similar firmware
source. Initial users for this file would be devices like
arm smmu which are populated by arm64 acpi_iort.

View File

@ -0,0 +1,126 @@
What: /sys/class/devlink/.../
Date: May 2020
Contact: Saravana Kannan <saravanak@google.com>
Description:
Provide a place in sysfs for the device link objects in the
kernel at any given time. The name of a device link directory,
denoted as ... above, is of the form <supplier>--<consumer>
where <supplier> is the supplier device name and <consumer> is
the consumer device name.
What: /sys/class/devlink/.../auto_remove_on
Date: May 2020
Contact: Saravana Kannan <saravanak@google.com>
Description:
This file indicates if the device link will ever be
automatically removed by the driver core when the consumer and
supplier devices themselves are still present.
This will be one of the following strings:
'consumer unbind'
'supplier unbind'
'never'
'consumer unbind' means the device link will be removed when
the consumer's driver is unbound from the consumer device.
'supplier unbind' means the device link will be removed when
the supplier's driver is unbound from the supplier device.
'never' means the device link will not be automatically removed
when as long as the supplier and consumer devices themselves
are still present.
What: /sys/class/devlink/.../consumer
Date: May 2020
Contact: Saravana Kannan <saravanak@google.com>
Description:
This file is a symlink to the consumer device's sysfs directory.
What: /sys/class/devlink/.../runtime_pm
Date: May 2020
Contact: Saravana Kannan <saravanak@google.com>
Description:
This file indicates if the device link has any impact on the
runtime power management behavior of the consumer and supplier
devices. For example: Making sure the supplier doesn't enter
runtime suspend while the consumer is active.
This will be one of the following strings:
'0' - Does not affect runtime power management
'1' - Affects runtime power management
What: /sys/class/devlink/.../status
Date: May 2020
Contact: Saravana Kannan <saravanak@google.com>
Description:
This file indicates the status of the device link. The status
of a device link is affected by whether the supplier and
consumer devices have been bound to their corresponding
drivers. The status of a device link also affects the binding
and unbinding of the supplier and consumer devices with their
drivers and also affects whether the software state of the
supplier device is synced with the hardware state of the
supplier device after boot up.
See also: sysfs-devices-state_synced.
This will be one of the following strings:
'not tracked'
'dormant'
'available'
'consumer probing'
'active'
'supplier unbinding'
'unknown'
'not tracked' means this device link does not track the status
and has no impact on the binding, unbinding and syncing the
hardware and software device state.
'dormant' means the supplier and the consumer devices have not
bound to their driver.
'available' means the supplier has bound to its driver and is
available to supply resources to the consumer device.
'consumer probing' means the consumer device is currently
trying to bind to its driver.
'active' means the supplier and consumer devices have both
bound successfully to their drivers.
'supplier unbinding' means the supplier devices is currently in
the process of unbinding from its driver.
'unknown' means the state of the device link is not any of the
above. If this is ever the value, there's a bug in the kernel.
What: /sys/class/devlink/.../supplier
Date: May 2020
Contact: Saravana Kannan <saravanak@google.com>
Description:
This file is a symlink to the supplier device's sysfs directory.
What: /sys/class/devlink/.../sync_state_only
Date: May 2020
Contact: Saravana Kannan <saravanak@google.com>
Description:
This file indicates if the device link is limited to only
affecting the syncing of the hardware and software state of the
supplier device.
This will be one of the following strings:
'0'
'1' - Affects runtime power management
'0' means the device link can affect other device behaviors
like binding/unbinding, suspend/resume, runtime power
management, etc.
'1' means the device link will only affect the syncing of
hardware and software state of the supplier device after boot
up and doesn't not affect other behaviors of the devices.

View File

@ -0,0 +1,8 @@
What: /sys/devices/.../consumer:<consumer>
Date: May 2020
Contact: Saravana Kannan <saravanak@google.com>
Description:
The /sys/devices/.../consumer:<consumer> are symlinks to device
links where this device is the supplier. <consumer> denotes the
name of the consumer in that device link. There can be zero or
more of these symlinks for a given device.

View File

@ -0,0 +1,24 @@
What: /sys/devices/.../state_synced
Date: May 2020
Contact: Saravana Kannan <saravanak@google.com>
Description:
The /sys/devices/.../state_synced attribute is only present for
devices whose bus types or driver provides the .sync_state()
callback. The number read from it (0 or 1) reflects the value
of the device's 'state_synced' field. A value of 0 means the
.sync_state() callback hasn't been called yet. A value of 1
means the .sync_state() callback has been called.
Generally, if a device has sync_state() support and has some of
the resources it provides enabled at the time the kernel starts
(Eg: enabled by hardware reset or bootloader or anything that
run before the kernel starts), then it'll keep those resources
enabled and in a state that's compatible with the state they
were in at the start of the kernel. The device will stop doing
this only when the sync_state() callback has been called --
which happens only when all its consumer devices are registered
and have probed successfully. Resources that were left disabled
at the time the kernel starts are not affected or limited in
any way by sync_state() callbacks.

View File

@ -0,0 +1,8 @@
What: /sys/devices/.../supplier:<supplier>
Date: May 2020
Contact: Saravana Kannan <saravanak@google.com>
Description:
The /sys/devices/.../supplier:<supplier> are symlinks to device
links where this device is the consumer. <supplier> denotes the
name of the supplier in that device link. There can be zero or
more of these symlinks for a given device.

View File

@ -0,0 +1,17 @@
What: /sys/devices/.../waiting_for_supplier
Date: May 2020
Contact: Saravana Kannan <saravanak@google.com>
Description:
The /sys/devices/.../waiting_for_supplier attribute is only
present when fw_devlink kernel command line option is enabled
and is set to something stricter than "permissive". It is
removed once a device probes successfully (because the
information is no longer relevant). The number read from it (0
or 1) reflects whether the device is waiting for one or more
suppliers to be added and then linked to using device links
before the device can probe.
A value of 0 means the device is not waiting for any suppliers
to be added before it can probe. A value of 1 means the device
is waiting for one or more suppliers to be added before it can
probe.

View File

@ -832,6 +832,21 @@
useful to also enable the page_owner functionality.
on: enable the feature
debugfs= [KNL] This parameter enables what is exposed to userspace
and debugfs internal clients.
Format: { on, no-mount, off }
on: All functions are enabled.
no-mount:
Filesystem is not registered but kernel clients can
access APIs and a crashkernel can be used to read
its content. There is nothing to mount.
off: Filesystem is not registered and clients
get a -EPERM as result when trying to register files
or directories within debugfs.
This is equivalent of the runtime functionality if
debugfs was not enabled in the kernel at all.
Default value is set in build-time with a kernel configuration.
debugpat [X86] Enable PAT debugging
decnet.addr= [HW,NET]

View File

@ -108,7 +108,7 @@ field to hold additional information.
Embedded systems frequently need one or more clocks for platform devices,
which are normally kept off until they're actively needed (to save power).
System setup also associates those clocks with the device, so that that
System setup also associates those clocks with the device, so that
calls to clk_get(&pdev->dev, clock_name) return them as needed.

View File

@ -93,6 +93,7 @@ struct device_private {
struct klist_node knode_class;
struct list_head deferred_probe;
struct device_driver *async_driver;
char *deferred_probe_reason;
struct device *device;
u8 dead:1;
};
@ -134,6 +135,8 @@ extern void device_release_driver_internal(struct device *dev,
extern void driver_detach(struct device_driver *drv);
extern int driver_probe_device(struct device_driver *drv, struct device *dev);
extern void driver_deferred_probe_del(struct device *dev);
extern void device_set_deferred_probe_reason(const struct device *dev,
struct va_format *vaf);
static inline int driver_match_device(struct device_driver *drv,
struct device *dev)
{

View File

@ -236,6 +236,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 | \
@ -408,13 +612,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);
@ -424,6 +621,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;
@ -539,22 +755,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);
@ -567,7 +768,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)
@ -582,7 +783,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 */
@ -850,6 +1051,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.
@ -874,6 +1091,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();
@ -1160,6 +1378,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);
@ -1969,8 +2190,16 @@ static int device_add_attrs(struct device *dev)
goto err_remove_dev_groups;
}
if (fw_devlink_flags && !fw_devlink_is_permissive()) {
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:
@ -1988,6 +2217,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);
@ -3973,6 +4203,52 @@ define_dev_printk_level(_dev_info, KERN_INFO);
#endif
/**
* dev_err_probe - probe error check and log helper
* @dev: the pointer to the struct device
* @err: error value to test
* @fmt: printf-style format string
* @...: arguments as specified in the format string
*
* This helper implements common pattern present in probe functions for error
* checking: print debug or error message depending if the error value is
* -EPROBE_DEFER and propagate error upwards.
* In case of -EPROBE_DEFER it sets also defer probe reason, which can be
* checked later by reading devices_deferred debugfs attribute.
* It replaces code sequence:
* if (err != -EPROBE_DEFER)
* dev_err(dev, ...);
* else
* dev_dbg(dev, ...);
* return err;
* with
* return dev_err_probe(dev, err, ...);
*
* Returns @err.
*
*/
int dev_err_probe(const struct device *dev, int err, const char *fmt, ...)
{
struct va_format vaf;
va_list args;
va_start(args, fmt);
vaf.fmt = fmt;
vaf.va = &args;
if (err != -EPROBE_DEFER) {
dev_err(dev, "error %d: %pV", err, &vaf);
} else {
device_set_deferred_probe_reason(dev, &vaf);
dev_dbg(dev, "error %d: %pV", err, &vaf);
}
va_end(args);
return err;
}
EXPORT_SYMBOL_GPL(dev_err_probe);
static inline bool fwnode_is_primary(struct fwnode_handle *fwnode)
{
return fwnode && !IS_ERR(fwnode->secondary);

View File

@ -27,6 +27,7 @@
#include <linux/async.h>
#include <linux/pm_runtime.h>
#include <linux/pinctrl/devinfo.h>
#include <linux/slab.h>
#include "base.h"
#include "power/power.h"
@ -136,6 +137,8 @@ void driver_deferred_probe_del(struct device *dev)
if (!list_empty(&dev->p->deferred_probe)) {
dev_dbg(dev, "Removed from deferred list\n");
list_del_init(&dev->p->deferred_probe);
kfree(dev->p->deferred_probe_reason);
dev->p->deferred_probe_reason = NULL;
}
mutex_unlock(&deferred_probe_mutex);
}
@ -206,6 +209,23 @@ void device_unblock_probing(void)
driver_deferred_probe_trigger();
}
/**
* device_set_deferred_probe_reason() - Set defer probe reason message for device
* @dev: the pointer to the struct device
* @vaf: the pointer to va_format structure with message
*/
void device_set_deferred_probe_reason(const struct device *dev, struct va_format *vaf)
{
const char *drv = dev_driver_string(dev);
mutex_lock(&deferred_probe_mutex);
kfree(dev->p->deferred_probe_reason);
dev->p->deferred_probe_reason = kasprintf(GFP_KERNEL, "%s: %pV", drv, vaf);
mutex_unlock(&deferred_probe_mutex);
}
/*
* deferred_devs_show() - Show the devices in the deferred probe pending list.
*/
@ -216,7 +236,8 @@ static int deferred_devs_show(struct seq_file *s, void *data)
mutex_lock(&deferred_probe_mutex);
list_for_each_entry(curr, &deferred_probe_pending_list, deferred_probe)
seq_printf(s, "%s\n", dev_name(curr->device));
seq_printf(s, "%s\t%s", dev_name(curr->device),
curr->device->p->deferred_probe_reason ?: "\n");
mutex_unlock(&deferred_probe_mutex);
@ -276,7 +297,7 @@ static void deferred_probe_timeout_work_func(struct work_struct *work)
list_for_each_entry_safe(private, p, &deferred_probe_pending_list, deferred_probe)
dev_info(private->device, "deferred probe pending\n");
wake_up(&probe_timeout_waitqueue);
wake_up_all(&probe_timeout_waitqueue);
}
static DECLARE_DELAYED_WORK(deferred_probe_timeout_work, deferred_probe_timeout_work_func);
@ -425,10 +446,9 @@ static void driver_sysfs_remove(struct device *dev)
* Allow manual attachment of a driver to a device.
* Caller must have already set @dev->driver.
*
* Note that this does not modify the bus reference count
* nor take the bus's rwsem. Please verify those are accounted
* for before calling this. (It is ok to call with no other effort
* from a driver's probe() method.)
* Note that this does not modify the bus reference count.
* Please verify that is accounted for before calling this.
* (It is ok to call with no other effort from a driver's probe() method.)
*
* This function must be called with the device lock held.
*/
@ -458,6 +478,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;
@ -487,7 +519,8 @@ static int really_probe(struct device *dev, struct device_driver *drv)
drv->bus->name, __func__, drv->name, dev_name(dev));
if (!list_empty(&dev->devres_head)) {
dev_crit(dev, "Resources present before probing\n");
return -EBUSY;
ret = -EBUSY;
goto done;
}
re_probe:
@ -531,9 +564,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)
@ -563,6 +603,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);
@ -607,7 +649,7 @@ pinctrl_bind_failed:
ret = 0;
done:
atomic_dec(&probe_count);
wake_up(&probe_waitqueue);
wake_up_all(&probe_waitqueue);
return ret;
}
@ -843,7 +885,9 @@ static int __device_attach(struct device *dev, bool allow_async)
int ret = 0;
device_lock(dev);
if (dev->driver) {
if (dev->p->dead) {
goto out_unlock;
} else if (dev->driver) {
if (device_is_bound(dev)) {
ret = 1;
goto out_unlock;
@ -1100,6 +1144,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)

View File

@ -89,15 +89,23 @@ static struct devres_group * node_to_group(struct devres_node *node)
return NULL;
}
static bool check_dr_size(size_t size, size_t *tot_size)
{
/* We must catch any near-SIZE_MAX cases that could overflow. */
if (unlikely(check_add_overflow(sizeof(struct devres),
size, tot_size)))
return false;
return true;
}
static __always_inline struct devres * alloc_dr(dr_release_t release,
size_t size, gfp_t gfp, int nid)
{
size_t tot_size;
struct devres *dr;
/* We must catch any near-SIZE_MAX cases that could overflow. */
if (unlikely(check_add_overflow(sizeof(struct devres), size,
&tot_size)))
if (!check_dr_size(size, &tot_size))
return NULL;
dr = kmalloc_node_track_caller(tot_size, gfp, nid);
@ -807,10 +815,13 @@ static int devm_kmalloc_match(struct device *dev, void *res, void *data)
* RETURNS:
* Pointer to allocated memory on success, NULL on failure.
*/
void * devm_kmalloc(struct device *dev, size_t size, gfp_t gfp)
void *devm_kmalloc(struct device *dev, size_t size, gfp_t gfp)
{
struct devres *dr;
if (unlikely(!size))
return ZERO_SIZE_PTR;
/* use raw alloc_dr for kmalloc caller tracing */
dr = alloc_dr(devm_kmalloc_release, size, gfp, dev_to_node(dev));
if (unlikely(!dr))
@ -942,10 +953,10 @@ void devm_kfree(struct device *dev, const void *p)
int rc;
/*
* Special case: pointer to a string in .rodata returned by
* devm_kstrdup_const().
* Special cases: pointer to a string in .rodata returned by
* devm_kstrdup_const() or NULL/ZERO ptr.
*/
if (unlikely(is_kernel_rodata((unsigned long)p)))
if (unlikely(is_kernel_rodata((unsigned long)p) || ZERO_OR_NULL_PTR(p)))
return;
rc = devres_destroy(dev, devm_kmalloc_release,

View File

@ -158,12 +158,12 @@ int driver_register(struct device_driver *drv)
if ((drv->bus->probe && drv->probe) ||
(drv->bus->remove && drv->remove) ||
(drv->bus->shutdown && drv->shutdown))
printk(KERN_WARNING "Driver '%s' needs updating - please use "
pr_warn("Driver '%s' needs updating - please use "
"bus_type methods\n", drv->name);
other = driver_find(drv->name, drv->bus);
if (other) {
printk(KERN_ERR "Error: Driver '%s' is already registered, "
pr_err("Error: Driver '%s' is already registered, "
"aborting...\n", drv->name);
return -EBUSY;
}

View File

@ -25,7 +25,10 @@ int firmware_fallback_platform(struct fw_priv *fw_priv, u32 opt_flags)
if (rc)
return rc; /* rc == -ENOENT when the fw was not found */
fw_priv->data = vmalloc(size);
if (fw_priv->data && size > fw_priv->allocated_size)
return -ENOMEM;
if (!fw_priv->data)
fw_priv->data = vmalloc(size);
if (!fw_priv->data)
return -ENOMEM;

View File

@ -838,12 +838,12 @@ EXPORT_SYMBOL(request_firmware);
* @name: name of firmware file
* @device: device for which firmware is being loaded
*
* This function is similar in behaviour to request_firmware(), except
* it doesn't produce warning messages when the file is not found.
* The sysfs fallback mechanism is enabled if direct filesystem lookup fails,
* however, however failures to find the firmware file with it are still
* suppressed. It is therefore up to the driver to check for the return value
* of this call and to decide when to inform the users of errors.
* This function is similar in behaviour to request_firmware(), except it
* doesn't produce warning messages when the file is not found. The sysfs
* fallback mechanism is enabled if direct filesystem lookup fails. However,
* failures to find the firmware file with it are still suppressed. It is
* therefore up to the driver to check for the return value of this call and to
* decide when to inform the users of errors.
**/
int firmware_request_nowarn(const struct firmware **firmware, const char *name,
struct device *device)

View File

@ -50,14 +50,14 @@ int memhp_online_type_from_str(const char *str)
static int sections_per_block;
static inline unsigned long base_memory_block_id(unsigned long section_nr)
static inline unsigned long memory_block_id(unsigned long section_nr)
{
return section_nr / sections_per_block;
}
static inline unsigned long pfn_to_block_id(unsigned long pfn)
{
return base_memory_block_id(pfn_to_section_nr(pfn));
return memory_block_id(pfn_to_section_nr(pfn));
}
static inline unsigned long phys_to_block_id(unsigned long phys)
@ -517,7 +517,7 @@ static struct memory_block *find_memory_block_by_id(unsigned long block_id)
*/
struct memory_block *find_memory_block(struct mem_section *section)
{
unsigned long block_id = base_memory_block_id(__section_nr(section));
unsigned long block_id = memory_block_id(__section_nr(section));
return find_memory_block_by_id(block_id);
}
@ -570,8 +570,7 @@ int register_memory(struct memory_block *memory)
return ret;
}
static int init_memory_block(struct memory_block **memory,
unsigned long block_id, unsigned long state)
static int init_memory_block(unsigned long block_id, unsigned long state)
{
struct memory_block *mem;
unsigned long start_pfn;
@ -594,14 +593,12 @@ static int init_memory_block(struct memory_block **memory,
ret = register_memory(mem);
*memory = mem;
return ret;
}
static int add_memory_block(unsigned long base_section_nr)
{
int section_count = 0;
struct memory_block *mem;
unsigned long nr;
for (nr = base_section_nr; nr < base_section_nr + sections_per_block;
@ -611,7 +608,7 @@ static int add_memory_block(unsigned long base_section_nr)
if (section_count == 0)
return 0;
return init_memory_block(&mem, base_memory_block_id(base_section_nr),
return init_memory_block(memory_block_id(base_section_nr),
MEM_ONLINE);
}
@ -647,7 +644,7 @@ int create_memory_block_devices(unsigned long start, unsigned long size)
return -EINVAL;
for (block_id = start_block_id; block_id != end_block_id; block_id++) {
ret = init_memory_block(&mem, block_id, MEM_OFFLINE);
ret = init_memory_block(block_id, MEM_OFFLINE);
if (ret)
break;
}

View File

@ -1019,7 +1019,7 @@ static ssize_t modalias_show(struct device *dev, struct device_attribute *a,
if (len != -ENODEV)
return len;
len = acpi_device_modalias(dev, buf, PAGE_SIZE -1);
len = acpi_device_modalias(dev, buf, PAGE_SIZE - 1);
if (len != -ENODEV)
return len;
@ -1076,13 +1076,37 @@ static ssize_t driver_override_show(struct device *dev,
}
static DEVICE_ATTR_RW(driver_override);
static ssize_t numa_node_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
return sprintf(buf, "%d\n", dev_to_node(dev));
}
static DEVICE_ATTR_RO(numa_node);
static umode_t platform_dev_attrs_visible(struct kobject *kobj, struct attribute *a,
int n)
{
struct device *dev = container_of(kobj, typeof(*dev), kobj);
if (a == &dev_attr_numa_node.attr &&
dev_to_node(dev) == NUMA_NO_NODE)
return 0;
return a->mode;
}
static struct attribute *platform_dev_attrs[] = {
&dev_attr_modalias.attr,
&dev_attr_numa_node.attr,
&dev_attr_driver_override.attr,
NULL,
};
ATTRIBUTE_GROUPS(platform_dev);
static struct attribute_group platform_dev_group = {
.attrs = platform_dev_attrs,
.is_visible = platform_dev_attrs_visible,
};
__ATTRIBUTE_GROUPS(platform_dev);
static int platform_uevent(struct device *dev, struct kobj_uevent_env *env)
{

View File

@ -761,17 +761,13 @@ EXPORT_SYMBOL_GPL(software_node_register_node_group);
*/
void software_node_unregister_node_group(const struct software_node **node_group)
{
struct swnode *swnode;
unsigned int i;
if (!node_group)
return;
for (i = 0; node_group[i]; i++) {
swnode = software_node_to_swnode(node_group[i]);
if (swnode)
fwnode_remove_software_node(&swnode->fwnode);
}
for (i = 0; node_group[i]; i++)
software_node_unregister(node_group[i]);
}
EXPORT_SYMBOL_GPL(software_node_unregister_node_group);

View File

@ -133,7 +133,7 @@ static int topology_remove_dev(unsigned int cpu)
return 0;
}
static int topology_sysfs_init(void)
static int __init topology_sysfs_init(void)
{
return cpuhp_setup_state(CPUHP_TOPOLOGY_PREPARE,
"base/topology:prepare", topology_add_dev,

View File

@ -71,13 +71,9 @@ static int lvds_codec_probe(struct platform_device *pdev)
lvds_codec->connector_type = (uintptr_t)of_device_get_match_data(dev);
lvds_codec->powerdown_gpio = devm_gpiod_get_optional(dev, "powerdown",
GPIOD_OUT_HIGH);
if (IS_ERR(lvds_codec->powerdown_gpio)) {
int err = PTR_ERR(lvds_codec->powerdown_gpio);
if (err != -EPROBE_DEFER)
dev_err(dev, "powerdown GPIO failure: %d\n", err);
return err;
}
if (IS_ERR(lvds_codec->powerdown_gpio))
return dev_err_probe(dev, PTR_ERR(lvds_codec->powerdown_gpio),
"powerdown GPIO failure\n");
/* Locate the panel DT node. */
panel_node = of_graph_get_remote_node(dev->of_node, 1, 0);

View File

@ -2299,10 +2299,9 @@ static int sii8620_probe(struct i2c_client *client,
INIT_LIST_HEAD(&ctx->mt_queue);
ctx->clk_xtal = devm_clk_get(dev, "xtal");
if (IS_ERR(ctx->clk_xtal)) {
dev_err(dev, "failed to get xtal clock from DT\n");
return PTR_ERR(ctx->clk_xtal);
}
if (IS_ERR(ctx->clk_xtal))
return dev_err_probe(dev, PTR_ERR(ctx->clk_xtal),
"failed to get xtal clock from DT\n");
if (!client->irq) {
dev_err(dev, "no irq provided\n");
@ -2313,16 +2312,14 @@ static int sii8620_probe(struct i2c_client *client,
sii8620_irq_thread,
IRQF_TRIGGER_HIGH | IRQF_ONESHOT,
"sii8620", ctx);
if (ret < 0) {
dev_err(dev, "failed to install IRQ handler\n");
return ret;
}
if (ret < 0)
return dev_err_probe(dev, ret,
"failed to install IRQ handler\n");
ctx->gpio_reset = devm_gpiod_get(dev, "reset", GPIOD_OUT_HIGH);
if (IS_ERR(ctx->gpio_reset)) {
dev_err(dev, "failed to get reset gpio from DT\n");
return PTR_ERR(ctx->gpio_reset);
}
if (IS_ERR(ctx->gpio_reset))
return dev_err_probe(dev, PTR_ERR(ctx->gpio_reset),
"failed to get reset gpio from DT\n");
ctx->supplies[0].supply = "cvcc10";
ctx->supplies[1].supply = "iovcc18";

View File

@ -273,7 +273,7 @@ static int full_proxy_release(struct inode *inode, struct file *filp)
r = real_fops->release(inode, filp);
replace_fops(filp, d_inode(dentry)->i_fop);
kfree((void *)proxy_fops);
kfree(proxy_fops);
fops_put(real_fops);
return r;
}

View File

@ -35,6 +35,7 @@
static struct vfsmount *debugfs_mount;
static int debugfs_mount_count;
static bool debugfs_registered;
static unsigned int debugfs_allow = DEFAULT_DEBUGFS_ALLOW_BITS;
/*
* Don't allow access attributes to be changed whilst the kernel is locked down
@ -266,6 +267,9 @@ static struct dentry *debug_mount(struct file_system_type *fs_type,
int flags, const char *dev_name,
void *data)
{
if (!(debugfs_allow & DEBUGFS_ALLOW_API))
return ERR_PTR(-EPERM);
return mount_single(fs_type, flags, data, debug_fill_super);
}
@ -311,6 +315,9 @@ static struct dentry *start_creating(const char *name, struct dentry *parent)
struct dentry *dentry;
int error;
if (!(debugfs_allow & DEBUGFS_ALLOW_API))
return ERR_PTR(-EPERM);
pr_debug("creating file '%s'\n", name);
if (IS_ERR(parent))
@ -385,6 +392,11 @@ static struct dentry *__debugfs_create_file(const char *name, umode_t mode,
if (IS_ERR(dentry))
return dentry;
if (!(debugfs_allow & DEBUGFS_ALLOW_API)) {
failed_creating(dentry);
return ERR_PTR(-EPERM);
}
inode = debugfs_get_inode(dentry->d_sb);
if (unlikely(!inode)) {
pr_err("out of free dentries, can not create file '%s'\n",
@ -541,6 +553,11 @@ struct dentry *debugfs_create_dir(const char *name, struct dentry *parent)
if (IS_ERR(dentry))
return dentry;
if (!(debugfs_allow & DEBUGFS_ALLOW_API)) {
failed_creating(dentry);
return ERR_PTR(-EPERM);
}
inode = debugfs_get_inode(dentry->d_sb);
if (unlikely(!inode)) {
pr_err("out of free dentries, can not create directory '%s'\n",
@ -583,6 +600,11 @@ struct dentry *debugfs_create_automount(const char *name,
if (IS_ERR(dentry))
return dentry;
if (!(debugfs_allow & DEBUGFS_ALLOW_API)) {
failed_creating(dentry);
return ERR_PTR(-EPERM);
}
inode = debugfs_get_inode(dentry->d_sb);
if (unlikely(!inode)) {
pr_err("out of free dentries, can not create automount '%s'\n",
@ -786,10 +808,27 @@ bool debugfs_initialized(void)
}
EXPORT_SYMBOL_GPL(debugfs_initialized);
static int __init debugfs_kernel(char *str)
{
if (str) {
if (!strcmp(str, "on"))
debugfs_allow = DEBUGFS_ALLOW_API | DEBUGFS_ALLOW_MOUNT;
else if (!strcmp(str, "no-mount"))
debugfs_allow = DEBUGFS_ALLOW_API;
else if (!strcmp(str, "off"))
debugfs_allow = 0;
}
return 0;
}
early_param("debugfs", debugfs_kernel);
static int __init debugfs_init(void)
{
int retval;
if (!(debugfs_allow & DEBUGFS_ALLOW_MOUNT))
return -EPERM;
retval = sysfs_create_mount_point(kernel_kobj, "debug");
if (retval)
return retval;

View File

@ -29,4 +29,18 @@ struct debugfs_fsdata {
*/
#define DEBUGFS_FSDATA_IS_REAL_FOPS_BIT BIT(0)
/* Access BITS */
#define DEBUGFS_ALLOW_API BIT(0)
#define DEBUGFS_ALLOW_MOUNT BIT(1)
#ifdef CONFIG_DEBUG_FS_ALLOW_ALL
#define DEFAULT_DEBUGFS_ALLOW_BITS (DEBUGFS_ALLOW_MOUNT | DEBUGFS_ALLOW_API)
#endif
#ifdef CONFIG_DEBUG_FS_DISALLOW_MOUNT
#define DEFAULT_DEBUGFS_ALLOW_BITS (DEBUGFS_ALLOW_API)
#endif
#ifdef CONFIG_DEBUG_FS_ALLOW_NONE
#define DEFAULT_DEBUGFS_ALLOW_BITS (0)
#endif
#endif /* _DEBUGFS_INTERNAL_H_ */

View File

@ -129,8 +129,12 @@ ssize_t device_store_bool(struct device *dev, struct device_attribute *attr,
__ATTR_PREALLOC(_name, _mode, _show, _store)
#define DEVICE_ATTR_RW(_name) \
struct device_attribute dev_attr_##_name = __ATTR_RW(_name)
#define DEVICE_ATTR_ADMIN_RW(_name) \
struct device_attribute dev_attr_##_name = __ATTR_RW_MODE(_name, 0600)
#define DEVICE_ATTR_RO(_name) \
struct device_attribute dev_attr_##_name = __ATTR_RO(_name)
#define DEVICE_ATTR_ADMIN_RO(_name) \
struct device_attribute dev_attr_##_name = __ATTR_RO_MODE(_name, 0400)
#define DEVICE_ATTR_WO(_name) \
struct device_attribute dev_attr_##_name = __ATTR_WO(_name)
#define DEVICE_ULONG_ATTR(_name, _mode, _var) \
@ -146,68 +150,66 @@ ssize_t device_store_bool(struct device *dev, struct device_attribute *attr,
struct device_attribute dev_attr_##_name = \
__ATTR_IGNORE_LOCKDEP(_name, _mode, _show, _store)
extern int device_create_file(struct device *device,
const struct device_attribute *entry);
extern void device_remove_file(struct device *dev,
const struct device_attribute *attr);
extern bool device_remove_file_self(struct device *dev,
const struct device_attribute *attr);
extern int __must_check device_create_bin_file(struct device *dev,
int device_create_file(struct device *device,
const struct device_attribute *entry);
void device_remove_file(struct device *dev,
const struct device_attribute *attr);
bool device_remove_file_self(struct device *dev,
const struct device_attribute *attr);
int __must_check device_create_bin_file(struct device *dev,
const struct bin_attribute *attr);
extern void device_remove_bin_file(struct device *dev,
const struct bin_attribute *attr);
void device_remove_bin_file(struct device *dev,
const struct bin_attribute *attr);
/* device resource management */
typedef void (*dr_release_t)(struct device *dev, void *res);
typedef int (*dr_match_t)(struct device *dev, void *res, void *match_data);
#ifdef CONFIG_DEBUG_DEVRES
extern void *__devres_alloc_node(dr_release_t release, size_t size, gfp_t gfp,
int nid, const char *name) __malloc;
void *__devres_alloc_node(dr_release_t release, size_t size, gfp_t gfp,
int nid, const char *name) __malloc;
#define devres_alloc(release, size, gfp) \
__devres_alloc_node(release, size, gfp, NUMA_NO_NODE, #release)
#define devres_alloc_node(release, size, gfp, nid) \
__devres_alloc_node(release, size, gfp, nid, #release)
#else
extern void *devres_alloc_node(dr_release_t release, size_t size, gfp_t gfp,
int nid) __malloc;
void *devres_alloc_node(dr_release_t release, size_t size,
gfp_t gfp, int nid) __malloc;
static inline void *devres_alloc(dr_release_t release, size_t size, gfp_t gfp)
{
return devres_alloc_node(release, size, gfp, NUMA_NO_NODE);
}
#endif
extern void devres_for_each_res(struct device *dev, dr_release_t release,
dr_match_t match, void *match_data,
void (*fn)(struct device *, void *, void *),
void *data);
extern void devres_free(void *res);
extern void devres_add(struct device *dev, void *res);
extern void *devres_find(struct device *dev, dr_release_t release,
dr_match_t match, void *match_data);
extern void *devres_get(struct device *dev, void *new_res,
dr_match_t match, void *match_data);
extern void *devres_remove(struct device *dev, dr_release_t release,
dr_match_t match, void *match_data);
extern int devres_destroy(struct device *dev, dr_release_t release,
dr_match_t match, void *match_data);
extern int devres_release(struct device *dev, dr_release_t release,
dr_match_t match, void *match_data);
void devres_for_each_res(struct device *dev, dr_release_t release,
dr_match_t match, void *match_data,
void (*fn)(struct device *, void *, void *),
void *data);
void devres_free(void *res);
void devres_add(struct device *dev, void *res);
void *devres_find(struct device *dev, dr_release_t release,
dr_match_t match, void *match_data);
void *devres_get(struct device *dev, void *new_res,
dr_match_t match, void *match_data);
void *devres_remove(struct device *dev, dr_release_t release,
dr_match_t match, void *match_data);
int devres_destroy(struct device *dev, dr_release_t release,
dr_match_t match, void *match_data);
int devres_release(struct device *dev, dr_release_t release,
dr_match_t match, void *match_data);
/* devres group */
extern void * __must_check devres_open_group(struct device *dev, void *id,
gfp_t gfp);
extern void devres_close_group(struct device *dev, void *id);
extern void devres_remove_group(struct device *dev, void *id);
extern int devres_release_group(struct device *dev, void *id);
void * __must_check devres_open_group(struct device *dev, void *id, gfp_t gfp);
void devres_close_group(struct device *dev, void *id);
void devres_remove_group(struct device *dev, void *id);
int devres_release_group(struct device *dev, void *id);
/* managed devm_k.alloc/kfree for device drivers */
extern void *devm_kmalloc(struct device *dev, size_t size, gfp_t gfp) __malloc;
extern __printf(3, 0)
char *devm_kvasprintf(struct device *dev, gfp_t gfp, const char *fmt,
va_list ap) __malloc;
extern __printf(3, 4)
char *devm_kasprintf(struct device *dev, gfp_t gfp, const char *fmt, ...) __malloc;
void *devm_kmalloc(struct device *dev, size_t size, gfp_t gfp) __malloc;
__printf(3, 0) char *devm_kvasprintf(struct device *dev, gfp_t gfp,
const char *fmt, va_list ap) __malloc;
__printf(3, 4) char *devm_kasprintf(struct device *dev, gfp_t gfp,
const char *fmt, ...) __malloc;
static inline void *devm_kzalloc(struct device *dev, size_t size, gfp_t gfp)
{
return devm_kmalloc(dev, size, gfp | __GFP_ZERO);
@ -227,16 +229,14 @@ static inline void *devm_kcalloc(struct device *dev,
{
return devm_kmalloc_array(dev, n, size, flags | __GFP_ZERO);
}
extern void devm_kfree(struct device *dev, const void *p);
extern char *devm_kstrdup(struct device *dev, const char *s, gfp_t gfp) __malloc;
extern const char *devm_kstrdup_const(struct device *dev,
const char *s, gfp_t gfp);
extern void *devm_kmemdup(struct device *dev, const void *src, size_t len,
gfp_t gfp);
void devm_kfree(struct device *dev, const void *p);
char *devm_kstrdup(struct device *dev, const char *s, gfp_t gfp) __malloc;
const char *devm_kstrdup_const(struct device *dev, const char *s, gfp_t gfp);
void *devm_kmemdup(struct device *dev, const void *src, size_t len, gfp_t gfp);
extern unsigned long devm_get_free_pages(struct device *dev,
gfp_t gfp_mask, unsigned int order);
extern void devm_free_pages(struct device *dev, unsigned long addr);
unsigned long devm_get_free_pages(struct device *dev,
gfp_t gfp_mask, unsigned int order);
void devm_free_pages(struct device *dev, unsigned long addr);
void __iomem *devm_ioremap_resource(struct device *dev,
const struct resource *res);
@ -387,34 +387,6 @@ enum device_link_state {
#define DL_FLAG_MANAGED BIT(6)
#define DL_FLAG_SYNC_STATE_ONLY BIT(7)
/**
* struct device_link - Device link representation.
* @supplier: The device on the supplier end of the link.
* @s_node: Hook to the supplier device's list of links to consumers.
* @consumer: The device on the consumer end of the link.
* @c_node: Hook to the consumer device's list of links to suppliers.
* @status: The state of the link (with respect to the presence of drivers).
* @flags: Link flags.
* @rpm_active: Whether or not the consumer device is runtime-PM-active.
* @kref: Count repeated addition of the same link.
* @rcu_head: An RCU head to use for deferred execution of SRCU callbacks.
* @supplier_preactivated: Supplier has been made active before consumer probe.
*/
struct device_link {
struct device *supplier;
struct list_head s_node;
struct device *consumer;
struct list_head c_node;
enum device_link_state status;
u32 flags;
refcount_t rpm_active;
struct kref kref;
#ifdef CONFIG_SRCU
struct rcu_head rcu_head;
#endif
bool supplier_preactivated; /* Owned by consumer probe. */
};
/**
* enum dl_dev_state - Device driver presence tracking information.
* @DL_DEV_NO_DRIVER: There is no driver attached to the device.
@ -639,6 +611,36 @@ struct device {
#endif
};
/**
* struct device_link - Device link representation.
* @supplier: The device on the supplier end of the link.
* @s_node: Hook to the supplier device's list of links to consumers.
* @consumer: The device on the consumer end of the link.
* @c_node: Hook to the consumer device's list of links to suppliers.
* @link_dev: device used to expose link details in sysfs
* @status: The state of the link (with respect to the presence of drivers).
* @flags: Link flags.
* @rpm_active: Whether or not the consumer device is runtime-PM-active.
* @kref: Count repeated addition of the same link.
* @rcu_head: An RCU head to use for deferred execution of SRCU callbacks.
* @supplier_preactivated: Supplier has been made active before consumer probe.
*/
struct device_link {
struct device *supplier;
struct list_head s_node;
struct device *consumer;
struct list_head c_node;
struct device link_dev;
enum device_link_state status;
u32 flags;
refcount_t rpm_active;
struct kref kref;
#ifdef CONFIG_SRCU
struct rcu_head rcu_head;
#endif
bool supplier_preactivated; /* Owned by consumer probe. */
};
static inline struct device *kobj_to_dev(struct kobject *kobj)
{
return container_of(kobj, struct device, kobj);
@ -666,8 +668,7 @@ static inline const char *dev_name(const struct device *dev)
return kobject_name(&dev->kobj);
}
extern __printf(2, 3)
int dev_set_name(struct device *dev, const char *name, ...);
__printf(2, 3) int dev_set_name(struct device *dev, const char *name, ...);
#ifdef CONFIG_NUMA
static inline int dev_to_node(struct device *dev)
@ -824,39 +825,38 @@ static inline bool dev_has_sync_state(struct device *dev)
/*
* High level routines for use by the bus drivers
*/
extern int __must_check device_register(struct device *dev);
extern void device_unregister(struct device *dev);
extern void device_initialize(struct device *dev);
extern int __must_check device_add(struct device *dev);
extern void device_del(struct device *dev);
extern int device_for_each_child(struct device *dev, void *data,
int (*fn)(struct device *dev, void *data));
extern int device_for_each_child_reverse(struct device *dev, void *data,
int (*fn)(struct device *dev, void *data));
extern struct device *device_find_child(struct device *dev, void *data,
int (*match)(struct device *dev, void *data));
extern struct device *device_find_child_by_name(struct device *parent,
const char *name);
extern int device_rename(struct device *dev, const char *new_name);
extern int device_move(struct device *dev, struct device *new_parent,
enum dpm_order dpm_order);
extern int device_change_owner(struct device *dev, kuid_t kuid, kgid_t kgid);
extern const char *device_get_devnode(struct device *dev,
umode_t *mode, kuid_t *uid, kgid_t *gid,
const char **tmp);
int __must_check device_register(struct device *dev);
void device_unregister(struct device *dev);
void device_initialize(struct device *dev);
int __must_check device_add(struct device *dev);
void device_del(struct device *dev);
int device_for_each_child(struct device *dev, void *data,
int (*fn)(struct device *dev, void *data));
int device_for_each_child_reverse(struct device *dev, void *data,
int (*fn)(struct device *dev, void *data));
struct device *device_find_child(struct device *dev, void *data,
int (*match)(struct device *dev, void *data));
struct device *device_find_child_by_name(struct device *parent,
const char *name);
int device_rename(struct device *dev, const char *new_name);
int device_move(struct device *dev, struct device *new_parent,
enum dpm_order dpm_order);
int device_change_owner(struct device *dev, kuid_t kuid, kgid_t kgid);
const char *device_get_devnode(struct device *dev, umode_t *mode, kuid_t *uid,
kgid_t *gid, const char **tmp);
static inline bool device_supports_offline(struct device *dev)
{
return dev->bus && dev->bus->offline && dev->bus->online;
}
extern void lock_device_hotplug(void);
extern void unlock_device_hotplug(void);
extern int lock_device_hotplug_sysfs(void);
extern int device_offline(struct device *dev);
extern int device_online(struct device *dev);
extern void set_primary_fwnode(struct device *dev, struct fwnode_handle *fwnode);
extern void set_secondary_fwnode(struct device *dev, struct fwnode_handle *fwnode);
void lock_device_hotplug(void);
void unlock_device_hotplug(void);
int lock_device_hotplug_sysfs(void);
int device_offline(struct device *dev);
int device_online(struct device *dev);
void set_primary_fwnode(struct device *dev, struct fwnode_handle *fwnode);
void set_secondary_fwnode(struct device *dev, struct fwnode_handle *fwnode);
void device_set_of_node_from_dev(struct device *dev, const struct device *dev2);
static inline int dev_num_vf(struct device *dev)
@ -869,14 +869,13 @@ static inline int dev_num_vf(struct device *dev)
/*
* Root device objects for grouping under /sys/devices
*/
extern struct device *__root_device_register(const char *name,
struct module *owner);
struct device *__root_device_register(const char *name, struct module *owner);
/* This is a macro to avoid include problems with THIS_MODULE */
#define root_device_register(name) \
__root_device_register(name, THIS_MODULE)
extern void root_device_unregister(struct device *root);
void root_device_unregister(struct device *root);
static inline void *dev_get_platdata(const struct device *dev)
{
@ -887,33 +886,31 @@ static inline void *dev_get_platdata(const struct device *dev)
* Manual binding of a device to driver. See drivers/base/bus.c
* for information on use.
*/
extern int __must_check device_bind_driver(struct device *dev);
extern void device_release_driver(struct device *dev);
extern int __must_check device_attach(struct device *dev);
extern int __must_check driver_attach(struct device_driver *drv);
extern void device_initial_probe(struct device *dev);
extern int __must_check device_reprobe(struct device *dev);
int __must_check device_bind_driver(struct device *dev);
void device_release_driver(struct device *dev);
int __must_check device_attach(struct device *dev);
int __must_check driver_attach(struct device_driver *drv);
void device_initial_probe(struct device *dev);
int __must_check device_reprobe(struct device *dev);
extern bool device_is_bound(struct device *dev);
bool device_is_bound(struct device *dev);
/*
* Easy functions for dynamically creating devices on the fly
*/
extern __printf(5, 6)
struct device *device_create(struct class *cls, struct device *parent,
dev_t devt, void *drvdata,
const char *fmt, ...);
extern __printf(6, 7)
struct device *device_create_with_groups(struct class *cls,
struct device *parent, dev_t devt, void *drvdata,
const struct attribute_group **groups,
const char *fmt, ...);
extern void device_destroy(struct class *cls, dev_t devt);
__printf(5, 6) struct device *
device_create(struct class *cls, struct device *parent, dev_t devt,
void *drvdata, const char *fmt, ...);
__printf(6, 7) struct device *
device_create_with_groups(struct class *cls, struct device *parent, dev_t devt,
void *drvdata, const struct attribute_group **groups,
const char *fmt, ...);
void device_destroy(struct class *cls, dev_t devt);
extern int __must_check device_add_groups(struct device *dev,
const struct attribute_group **groups);
extern void device_remove_groups(struct device *dev,
const struct attribute_group **groups);
int __must_check device_add_groups(struct device *dev,
const struct attribute_group **groups);
void device_remove_groups(struct device *dev,
const struct attribute_group **groups);
static inline int __must_check device_add_group(struct device *dev,
const struct attribute_group *grp)
@ -931,14 +928,14 @@ static inline void device_remove_group(struct device *dev,
return device_remove_groups(dev, groups);
}
extern int __must_check devm_device_add_groups(struct device *dev,
int __must_check devm_device_add_groups(struct device *dev,
const struct attribute_group **groups);
extern void devm_device_remove_groups(struct device *dev,
const struct attribute_group **groups);
extern int __must_check devm_device_add_group(struct device *dev,
const struct attribute_group *grp);
extern void devm_device_remove_group(struct device *dev,
const struct attribute_group *grp);
void devm_device_remove_groups(struct device *dev,
const struct attribute_group **groups);
int __must_check devm_device_add_group(struct device *dev,
const struct attribute_group *grp);
void devm_device_remove_group(struct device *dev,
const struct attribute_group *grp);
/*
* Platform "fixup" functions - allow the platform to have their say
@ -955,21 +952,21 @@ extern int (*platform_notify_remove)(struct device *dev);
* get_device - atomically increment the reference count for the device.
*
*/
extern struct device *get_device(struct device *dev);
extern void put_device(struct device *dev);
extern bool kill_device(struct device *dev);
struct device *get_device(struct device *dev);
void put_device(struct device *dev);
bool kill_device(struct device *dev);
#ifdef CONFIG_DEVTMPFS
extern int devtmpfs_mount(void);
int devtmpfs_mount(void);
#else
static inline int devtmpfs_mount(void) { return 0; }
#endif
/* drivers/base/power/shutdown.c */
extern void device_shutdown(void);
void device_shutdown(void);
/* debugging and troubleshooting/diagnostic helpers. */
extern const char *dev_driver_string(const struct device *dev);
const char *dev_driver_string(const struct device *dev);
/* Device links interface. */
struct device_link *device_link_add(struct device *consumer,
@ -979,6 +976,9 @@ void device_link_remove(void *consumer, struct device *supplier);
void device_links_supplier_sync_state_pause(void);
void device_links_supplier_sync_state_resume(void);
extern __printf(3, 4)
int dev_err_probe(const struct device *dev, int err, const char *fmt, ...);
/* Create alias, so I can be autoloaded. */
#define MODULE_ALIAS_CHARDEV(major,minor) \
MODULE_ALIAS("char-major-" __stringify(major) "-" __stringify(minor))

View File

@ -59,7 +59,6 @@ enum kobject_action {
KOBJ_OFFLINE,
KOBJ_BIND,
KOBJ_UNBIND,
KOBJ_MAX
};
struct kobject {

View File

@ -123,6 +123,13 @@ struct attribute_group {
.show = _name##_show, \
}
#define __ATTR_RW_MODE(_name, _mode) { \
.attr = { .name = __stringify(_name), \
.mode = VERIFY_OCTAL_PERMISSIONS(_mode) }, \
.show = _name##_show, \
.store = _name##_store, \
}
#define __ATTR_WO(_name) { \
.attr = { .name = __stringify(_name), .mode = 0200 }, \
.store = _name##_store, \

View File

@ -8945,9 +8945,7 @@ struct dentry *tracing_init_dentry(void)
if (tr->dir)
return NULL;
if (WARN_ON(!tracefs_initialized()) ||
(IS_ENABLED(CONFIG_DEBUG_FS) &&
WARN_ON(!debugfs_initialized())))
if (WARN_ON(!tracefs_initialized()))
return ERR_PTR(-ENODEV);
/*

View File

@ -476,6 +476,38 @@ config DEBUG_FS
If unsure, say N.
choice
prompt "Debugfs default access"
depends on DEBUG_FS
default DEBUG_FS_ALLOW_ALL
help
This selects the default access restrictions for debugfs.
It can be overridden with kernel command line option
debugfs=[on,no-mount,off]. The restrictions apply for API access
and filesystem registration.
config DEBUG_FS_ALLOW_ALL
bool "Access normal"
help
No restrictions apply. Both API and filesystem registration
is on. This is the normal default operation.
config DEBUG_FS_DISALLOW_MOUNT
bool "Do not register debugfs as filesystem"
help
The API is open but filesystem is not loaded. Clients can still do
their work and read with debug tools that do not need
debugfs filesystem.
config DEBUG_FS_ALLOW_NONE
bool "No access"
help
Access is off. Clients get -PERM when trying to create nodes in
debugfs tree and debugfs is not registered as a filesystem.
Client can then back-off or continue without debugfs access.
endchoice
source "lib/Kconfig.kgdb"
source "lib/Kconfig.ubsan"
@ -844,10 +876,10 @@ config DEBUG_SHIRQ
bool "Debug shared IRQ handlers"
depends on DEBUG_KERNEL
help
Enable this to generate a spurious interrupt as soon as a shared
interrupt handler is registered, and just before one is deregistered.
Drivers ought to be able to handle interrupts coming in at those
points; some don't and need to be caught.
Enable this to generate a spurious interrupt just before a shared
interrupt handler is deregistered (generating one when registering
is currently disabled). Drivers need to handle this correctly. Some
don't and need to be caught.
menu "Debug Oops, Lockups and Hangs"

View File

@ -119,6 +119,7 @@ __devm_ioremap_resource(struct device *dev, const struct resource *res,
{
resource_size_t size;
void __iomem *dest_ptr;
char *pretty_name;
BUG_ON(!dev);
@ -129,7 +130,15 @@ __devm_ioremap_resource(struct device *dev, const struct resource *res,
size = resource_size(res);
if (!devm_request_mem_region(dev, res->start, size, dev_name(dev))) {
if (res->name)
pretty_name = devm_kasprintf(dev, GFP_KERNEL, "%s %s",
dev_name(dev), res->name);
else
pretty_name = devm_kstrdup(dev, dev_name(dev), GFP_KERNEL);
if (!pretty_name)
return IOMEM_ERR_PTR(-ENOMEM);
if (!devm_request_mem_region(dev, res->start, size, pretty_name)) {
dev_err(dev, "can't request region for resource %pR\n", res);
return IOMEM_ERR_PTR(-EBUSY);
}
@ -204,6 +213,12 @@ void __iomem *devm_ioremap_resource_wc(struct device *dev,
* base = devm_of_iomap(&pdev->dev, node, 0, NULL);
* if (IS_ERR(base))
* return PTR_ERR(base);
*
* Please Note: This is not a one-to-one replacement for of_iomap() because the
* of_iomap() function does not track whether the region is already mapped. If
* two drivers try to map the same memory, the of_iomap() function will succeed
* but the the devm_of_iomap() function will return -EBUSY.
*
*/
void __iomem *devm_of_iomap(struct device *dev, struct device_node *node, int index,
resource_size_t *size)

View File

@ -599,14 +599,7 @@ out:
}
EXPORT_SYMBOL_GPL(kobject_move);
/**
* kobject_del() - Unlink kobject from hierarchy.
* @kobj: object.
*
* This is the function that should be called to delete an object
* successfully added via kobject_add().
*/
void kobject_del(struct kobject *kobj)
static void __kobject_del(struct kobject *kobj)
{
struct kernfs_node *sd;
const struct kobj_type *ktype;
@ -632,9 +625,23 @@ void kobject_del(struct kobject *kobj)
kobj->state_in_sysfs = 0;
kobj_kset_leave(kobj);
kobject_put(kobj->parent);
kobj->parent = NULL;
}
/**
* kobject_del() - Unlink kobject from hierarchy.
* @kobj: object.
*
* This is the function that should be called to delete an object
* successfully added via kobject_add().
*/
void kobject_del(struct kobject *kobj)
{
struct kobject *parent = kobj->parent;
__kobject_del(kobj);
kobject_put(parent);
}
EXPORT_SYMBOL(kobject_del);
/**
@ -670,6 +677,7 @@ EXPORT_SYMBOL(kobject_get_unless_zero);
*/
static void kobject_cleanup(struct kobject *kobj)
{
struct kobject *parent = kobj->parent;
struct kobj_type *t = get_ktype(kobj);
const char *name = kobj->name;
@ -684,7 +692,10 @@ static void kobject_cleanup(struct kobject *kobj)
if (kobj->state_in_sysfs) {
pr_debug("kobject: '%s' (%p): auto cleanup kobject_del\n",
kobject_name(kobj), kobj);
kobject_del(kobj);
__kobject_del(kobj);
} else {
/* avoid dropping the parent reference unnecessarily */
parent = NULL;
}
if (t && t->release) {
@ -698,6 +709,8 @@ static void kobject_cleanup(struct kobject *kobj)
pr_debug("kobject: '%s': free name\n", name);
kfree_const(name);
}
kobject_put(parent);
}
#ifdef CONFIG_DEBUG_KOBJECT_RELEASE

View File

@ -6,6 +6,7 @@
/// add a missing namespace tag to a module source file.
///
virtual nsdeps
virtual report
@has_ns_import@
@ -16,10 +17,15 @@ MODULE_IMPORT_NS(ns);
// Add missing imports, but only adjacent to a MODULE_LICENSE statement.
// That ensures we are adding it only to the main module source file.
@do_import depends on !has_ns_import@
@do_import depends on !has_ns_import && nsdeps@
declarer name MODULE_LICENSE;
expression license;
identifier virtual.ns;
@@
MODULE_LICENSE(license);
+ MODULE_IMPORT_NS(ns);
// Dummy rule for report mode that would otherwise be empty and make spatch
// fail ("No rules apply.")
@script:python depends on report@
@@

View File

@ -29,7 +29,7 @@ fi
generate_deps_for_ns() {
$SPATCH --very-quiet --in-place --sp-file \
$srctree/scripts/coccinelle/misc/add_namespace.cocci -D ns=$1 $2
$srctree/scripts/coccinelle/misc/add_namespace.cocci -D nsdeps -D ns=$1 $2
}
generate_deps() {

View File

@ -0,0 +1,8 @@
# The async firmware timeout is set to 1 second (but ends up being effectively
# 2 seconds). There are 3 test configs, each done with and without firmware
# present, each with 2 "nowait" functions tested 5 times. Expected time for a
# normal execution should be 2 * 3 * 2 * 2 * 5 = 120 seconds for those alone.
# Additionally, fw_fallback may take 5 seconds for internal timeouts in each
# of the 3 configs, so at least another 15 seconds are needed. Add another
# 10 seconds for each testing config: 120 + 15 + 30
timeout=165

View File

@ -53,6 +53,10 @@ run_one()
settings="$BASE_DIR/$DIR/settings"
if [ -r "$settings" ] ; then
while read line ; do
# Skip comments.
if echo "$line" | grep -q '^#'; then
continue
fi
field=$(echo "$line" | cut -d= -f1)
value=$(echo "$line" | cut -d= -f2-)
eval "kselftest_$field"="$value"
@ -80,7 +84,7 @@ run_one()
echo "ok $test_num $TEST_HDR_MSG # SKIP"
elif [ $rc -eq $timeout_rc ]; then \
echo "#"
echo "not ok $test_num $TEST_HDR_MSG # TIMEOUT"
echo "not ok $test_num $TEST_HDR_MSG # TIMEOUT $kselftest_timeout seconds"
else
echo "not ok $test_num $TEST_HDR_MSG # exit=$rc"
fi)