summaryrefslogtreecommitdiff
path: root/drivers/base
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/base')
-rw-r--r--drivers/base/Kconfig25
-rw-r--r--drivers/base/arch_topology.c2
-rw-r--r--drivers/base/core.c2
-rw-r--r--drivers/base/dd.c16
-rw-r--r--drivers/base/isa.c10
-rw-r--r--drivers/base/power/main.c15
-rw-r--r--drivers/base/power/runtime.c34
-rw-r--r--drivers/base/power/wakeup.c2
-rw-r--r--drivers/base/test/test_async_driver_probe.c6
9 files changed, 64 insertions, 48 deletions
diff --git a/drivers/base/Kconfig b/drivers/base/Kconfig
index 2f6614c9a229..bdc87907d6a1 100644
--- a/drivers/base/Kconfig
+++ b/drivers/base/Kconfig
@@ -91,22 +91,23 @@ config FIRMWARE_IN_KERNEL
depends on FW_LOADER
default y
help
- The kernel source tree includes a number of firmware 'blobs'
- that are used by various drivers. The recommended way to
- use these is to run "make firmware_install", which, after
- converting ihex files to binary, copies all of the needed
- binary files in firmware/ to /lib/firmware/ on your system so
- that they can be loaded by userspace helpers on request.
+ Various drivers in the kernel source tree may require firmware,
+ which is generally available in your distribution's linux-firmware
+ package.
+
+ The linux-firmware package should install firmware into
+ /lib/firmware/ on your system, so they can be loaded by userspace
+ helpers on request.
Enabling this option will build each required firmware blob
- into the kernel directly, where request_firmware() will find
- them without having to call out to userspace. This may be
- useful if your root file system requires a device that uses
- such firmware and do not wish to use an initrd.
+ specified by EXTRA_FIRMWARE into the kernel directly, where
+ request_firmware() will find them without having to call out to
+ userspace. This may be useful if your root file system requires a
+ device that uses such firmware and you do not wish to use an
+ initrd.
This single option controls the inclusion of firmware for
- every driver that uses request_firmware() and ships its
- firmware in the kernel source tree, which avoids a
+ every driver that uses request_firmware(), which avoids a
proliferation of 'Include firmware for xxx device' options.
Say 'N' and let firmware be loaded from userspace.
diff --git a/drivers/base/arch_topology.c b/drivers/base/arch_topology.c
index 0739c5b953bf..4de87b0b53c8 100644
--- a/drivers/base/arch_topology.c
+++ b/drivers/base/arch_topology.c
@@ -105,7 +105,7 @@ subsys_initcall(register_cpu_capacity_sysctl);
static u32 capacity_scale;
static u32 *raw_capacity;
-static int __init free_raw_capacity(void)
+static int free_raw_capacity(void)
{
kfree(raw_capacity);
raw_capacity = NULL;
diff --git a/drivers/base/core.c b/drivers/base/core.c
index a36cf1bd07a9..110230d86527 100644
--- a/drivers/base/core.c
+++ b/drivers/base/core.c
@@ -1958,7 +1958,6 @@ void device_del(struct device *dev)
blocking_notifier_call_chain(&dev->bus->p->bus_notifier,
BUS_NOTIFY_DEL_DEVICE, dev);
- device_links_purge(dev);
dpm_sysfs_remove(dev);
if (parent)
klist_del(&dev->p->knode_parent);
@@ -1986,6 +1985,7 @@ void device_del(struct device *dev)
device_pm_remove(dev);
driver_deferred_probe_del(dev);
device_remove_properties(dev);
+ device_links_purge(dev);
/* Notify the platform of the removal, in case they
* need to do anything...
diff --git a/drivers/base/dd.c b/drivers/base/dd.c
index 45575e134696..2c964f56dafe 100644
--- a/drivers/base/dd.c
+++ b/drivers/base/dd.c
@@ -350,6 +350,15 @@ EXPORT_SYMBOL_GPL(device_bind_driver);
static atomic_t probe_count = ATOMIC_INIT(0);
static DECLARE_WAIT_QUEUE_HEAD(probe_waitqueue);
+static void driver_deferred_probe_add_trigger(struct device *dev,
+ int local_trigger_count)
+{
+ driver_deferred_probe_add(dev);
+ /* Did a trigger occur while probing? Need to re-trigger if yes */
+ if (local_trigger_count != atomic_read(&deferred_trigger_count))
+ driver_deferred_probe_trigger();
+}
+
static int really_probe(struct device *dev, struct device_driver *drv)
{
int ret = -EPROBE_DEFER;
@@ -369,6 +378,8 @@ static int really_probe(struct device *dev, struct device_driver *drv)
}
ret = device_links_check_suppliers(dev);
+ if (ret == -EPROBE_DEFER)
+ driver_deferred_probe_add_trigger(dev, local_trigger_count);
if (ret)
return ret;
@@ -470,10 +481,7 @@ pinctrl_bind_failed:
case -EPROBE_DEFER:
/* Driver requested deferred probing */
dev_dbg(dev, "Driver %s requests probe deferral\n", drv->name);
- driver_deferred_probe_add(dev);
- /* Did a trigger occur while probing? Need to re-trigger if yes */
- if (local_trigger_count != atomic_read(&deferred_trigger_count))
- driver_deferred_probe_trigger();
+ driver_deferred_probe_add_trigger(dev, local_trigger_count);
break;
case -ENODEV:
case -ENXIO:
diff --git a/drivers/base/isa.c b/drivers/base/isa.c
index cd6ccdcf9df0..372d10af2600 100644
--- a/drivers/base/isa.c
+++ b/drivers/base/isa.c
@@ -39,7 +39,7 @@ static int isa_bus_probe(struct device *dev)
{
struct isa_driver *isa_driver = dev->platform_data;
- if (isa_driver->probe)
+ if (isa_driver && isa_driver->probe)
return isa_driver->probe(dev, to_isa_dev(dev)->id);
return 0;
@@ -49,7 +49,7 @@ static int isa_bus_remove(struct device *dev)
{
struct isa_driver *isa_driver = dev->platform_data;
- if (isa_driver->remove)
+ if (isa_driver && isa_driver->remove)
return isa_driver->remove(dev, to_isa_dev(dev)->id);
return 0;
@@ -59,7 +59,7 @@ static void isa_bus_shutdown(struct device *dev)
{
struct isa_driver *isa_driver = dev->platform_data;
- if (isa_driver->shutdown)
+ if (isa_driver && isa_driver->shutdown)
isa_driver->shutdown(dev, to_isa_dev(dev)->id);
}
@@ -67,7 +67,7 @@ static int isa_bus_suspend(struct device *dev, pm_message_t state)
{
struct isa_driver *isa_driver = dev->platform_data;
- if (isa_driver->suspend)
+ if (isa_driver && isa_driver->suspend)
return isa_driver->suspend(dev, to_isa_dev(dev)->id, state);
return 0;
@@ -77,7 +77,7 @@ static int isa_bus_resume(struct device *dev)
{
struct isa_driver *isa_driver = dev->platform_data;
- if (isa_driver->resume)
+ if (isa_driver && isa_driver->resume)
return isa_driver->resume(dev, to_isa_dev(dev)->id);
return 0;
diff --git a/drivers/base/power/main.c b/drivers/base/power/main.c
index db2f04415927..08744b572af6 100644
--- a/drivers/base/power/main.c
+++ b/drivers/base/power/main.c
@@ -526,6 +526,21 @@ static void dpm_watchdog_clear(struct dpm_watchdog *wd)
/*------------------------- Resume routines -------------------------*/
/**
+ * dev_pm_skip_next_resume_phases - Skip next system resume phases for device.
+ * @dev: Target device.
+ *
+ * Make the core skip the "early resume" and "resume" phases for @dev.
+ *
+ * This function can be called by middle-layer code during the "noirq" phase of
+ * system resume if necessary, but not by device drivers.
+ */
+void dev_pm_skip_next_resume_phases(struct device *dev)
+{
+ dev->power.is_late_suspended = false;
+ dev->power.is_suspended = false;
+}
+
+/**
* device_resume_noirq - Execute a "noirq resume" callback for given device.
* @dev: Device to handle.
* @state: PM transition of the system being carried out.
diff --git a/drivers/base/power/runtime.c b/drivers/base/power/runtime.c
index 2362b9e9701e..6e89b51ea3d9 100644
--- a/drivers/base/power/runtime.c
+++ b/drivers/base/power/runtime.c
@@ -276,7 +276,8 @@ static int rpm_get_suppliers(struct device *dev)
continue;
retval = pm_runtime_get_sync(link->supplier);
- if (retval < 0) {
+ /* Ignore suppliers with disabled runtime PM. */
+ if (retval < 0 && retval != -EACCES) {
pm_runtime_put_noidle(link->supplier);
return retval;
}
@@ -1101,29 +1102,13 @@ int __pm_runtime_set_status(struct device *dev, unsigned int status)
goto out;
}
- if (dev->power.runtime_status == status)
+ if (dev->power.runtime_status == status || !parent)
goto out_set;
if (status == RPM_SUSPENDED) {
- /*
- * It is invalid to suspend a device with an active child,
- * unless it has been set to ignore its children.
- */
- if (!dev->power.ignore_children &&
- atomic_read(&dev->power.child_count)) {
- dev_err(dev, "runtime PM trying to suspend device but active child\n");
- error = -EBUSY;
- goto out;
- }
-
- if (parent) {
- atomic_add_unless(&parent->power.child_count, -1, 0);
- notify_parent = !parent->power.ignore_children;
- }
- goto out_set;
- }
-
- if (parent) {
+ atomic_add_unless(&parent->power.child_count, -1, 0);
+ notify_parent = !parent->power.ignore_children;
+ } else {
spin_lock_nested(&parent->power.lock, SINGLE_DEPTH_NESTING);
/*
@@ -1307,6 +1292,13 @@ void pm_runtime_enable(struct device *dev)
else
dev_warn(dev, "Unbalanced %s!\n", __func__);
+ WARN(!dev->power.disable_depth &&
+ dev->power.runtime_status == RPM_SUSPENDED &&
+ !dev->power.ignore_children &&
+ atomic_read(&dev->power.child_count) > 0,
+ "Enabling runtime PM for inactive device (%s) with active children\n",
+ dev_name(dev));
+
spin_unlock_irqrestore(&dev->power.lock, flags);
}
EXPORT_SYMBOL_GPL(pm_runtime_enable);
diff --git a/drivers/base/power/wakeup.c b/drivers/base/power/wakeup.c
index 680ee1d36ac9..38559f04db2c 100644
--- a/drivers/base/power/wakeup.c
+++ b/drivers/base/power/wakeup.c
@@ -481,7 +481,7 @@ static bool wakeup_source_not_registered(struct wakeup_source *ws)
* Use timer struct to check if the given source is initialized
* by wakeup_source_add.
*/
- return ws->timer.function != (TIMER_FUNC_TYPE)pm_wakeup_timer_fn;
+ return ws->timer.function != pm_wakeup_timer_fn;
}
/*
diff --git a/drivers/base/test/test_async_driver_probe.c b/drivers/base/test/test_async_driver_probe.c
index 304d5c2bd5e9..a3355d66bc12 100644
--- a/drivers/base/test/test_async_driver_probe.c
+++ b/drivers/base/test/test_async_driver_probe.c
@@ -64,7 +64,7 @@ static int __init test_async_probe_init(void)
NULL, 0);
if (IS_ERR(async_dev_1)) {
error = PTR_ERR(async_dev_1);
- pr_err("failed to create async_dev_1: %d", error);
+ pr_err("failed to create async_dev_1: %d\n", error);
return error;
}
@@ -91,7 +91,7 @@ static int __init test_async_probe_init(void)
NULL, 0);
if (IS_ERR(async_dev_2)) {
error = PTR_ERR(async_dev_2);
- pr_err("failed to create async_dev_2: %d", error);
+ pr_err("failed to create async_dev_2: %d\n", error);
goto err_unregister_async_driver;
}
@@ -118,7 +118,7 @@ static int __init test_async_probe_init(void)
NULL, 0);
if (IS_ERR(sync_dev_1)) {
error = PTR_ERR(sync_dev_1);
- pr_err("failed to create sync_dev_1: %d", error);
+ pr_err("failed to create sync_dev_1: %d\n", error);
goto err_unregister_sync_driver;
}