summaryrefslogtreecommitdiff
path: root/drivers/base
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/base')
-rw-r--r--drivers/base/Kconfig1
-rw-r--r--drivers/base/core.c15
-rw-r--r--drivers/base/cpu.c8
-rw-r--r--drivers/base/dd.c8
-rw-r--r--drivers/base/firmware_class.c8
-rw-r--r--drivers/base/isa.c2
-rw-r--r--drivers/base/platform.c2
-rw-r--r--drivers/base/power/main.c41
-rw-r--r--drivers/base/power/wakeirq.c14
-rw-r--r--drivers/base/power/wakeup.c7
-rw-r--r--drivers/base/regmap/regcache-rbtree.c7
-rw-r--r--drivers/base/regmap/regmap-debugfs.c6
-rw-r--r--drivers/base/regmap/regmap.c2
13 files changed, 87 insertions, 34 deletions
diff --git a/drivers/base/Kconfig b/drivers/base/Kconfig
index 602cbb04bee8..a4e8a2d26f6e 100644
--- a/drivers/base/Kconfig
+++ b/drivers/base/Kconfig
@@ -239,7 +239,6 @@ source "drivers/base/regmap/Kconfig"
config DMA_SHARED_BUFFER
bool
default n
- select ANON_INODES
help
This option enables the framework for buffer-sharing between
multiple drivers. A buffer is associated with a file using driver
diff --git a/drivers/base/core.c b/drivers/base/core.c
index 146d8c081695..014b892263c5 100644
--- a/drivers/base/core.c
+++ b/drivers/base/core.c
@@ -715,6 +715,7 @@ void device_initialize(struct device *dev)
device_pm_init(dev);
set_dev_node(dev, -1);
#ifdef CONFIG_GENERIC_MSI_IRQ
+ raw_spin_lock_init(&dev->msi_lock);
INIT_LIST_HEAD(&dev->msi_list);
#endif
}
@@ -2349,17 +2350,23 @@ static inline bool fwnode_is_primary(struct fwnode_handle *fwnode)
*/
void set_primary_fwnode(struct device *dev, struct fwnode_handle *fwnode)
{
- if (fwnode) {
- struct fwnode_handle *fn = dev->fwnode;
+ struct device *parent = dev->parent;
+ struct fwnode_handle *fn = dev->fwnode;
+ if (fwnode) {
if (fwnode_is_primary(fn))
fn = fn->secondary;
fwnode->secondary = fn;
dev->fwnode = fwnode;
} else {
- dev->fwnode = fwnode_is_primary(dev->fwnode) ?
- dev->fwnode->secondary : NULL;
+ if (fwnode_is_primary(fn)) {
+ dev->fwnode = fn->secondary;
+ if (!(parent && fn == parent->fwnode))
+ fn->secondary = NULL;
+ } else {
+ dev->fwnode = NULL;
+ }
}
}
EXPORT_SYMBOL_GPL(set_primary_fwnode);
diff --git a/drivers/base/cpu.c b/drivers/base/cpu.c
index 2a5aad29c8a3..128bbe8da649 100644
--- a/drivers/base/cpu.c
+++ b/drivers/base/cpu.c
@@ -724,6 +724,12 @@ ssize_t __weak cpu_show_itlb_multihit(struct device *dev,
return sprintf(buf, "Not affected\n");
}
+ssize_t __weak cpu_show_srbds(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ return sprintf(buf, "Not affected\n");
+}
+
static DEVICE_ATTR(meltdown, 0444, cpu_show_meltdown, NULL);
static DEVICE_ATTR(spectre_v1, 0444, cpu_show_spectre_v1, NULL);
static DEVICE_ATTR(spectre_v2, 0444, cpu_show_spectre_v2, NULL);
@@ -732,6 +738,7 @@ static DEVICE_ATTR(l1tf, 0444, cpu_show_l1tf, NULL);
static DEVICE_ATTR(mds, 0444, cpu_show_mds, NULL);
static DEVICE_ATTR(tsx_async_abort, 0444, cpu_show_tsx_async_abort, NULL);
static DEVICE_ATTR(itlb_multihit, 0444, cpu_show_itlb_multihit, NULL);
+static DEVICE_ATTR(srbds, 0444, cpu_show_srbds, NULL);
static struct attribute *cpu_root_vulnerabilities_attrs[] = {
&dev_attr_meltdown.attr,
@@ -742,6 +749,7 @@ static struct attribute *cpu_root_vulnerabilities_attrs[] = {
&dev_attr_mds.attr,
&dev_attr_tsx_async_abort.attr,
&dev_attr_itlb_multihit.attr,
+ &dev_attr_srbds.attr,
NULL
};
diff --git a/drivers/base/dd.c b/drivers/base/dd.c
index 0ab3a8d36ad4..cc6bf344b5c4 100644
--- a/drivers/base/dd.c
+++ b/drivers/base/dd.c
@@ -309,7 +309,11 @@ static int really_probe(struct device *dev, struct device_driver *drv)
atomic_inc(&probe_count);
pr_debug("bus: '%s': %s: probing driver %s with device %s\n",
drv->bus->name, __func__, drv->name, dev_name(dev));
- WARN_ON(!list_empty(&dev->devres_head));
+ if (!list_empty(&dev->devres_head)) {
+ dev_crit(dev, "Resources present before probing\n");
+ ret = -EBUSY;
+ goto done;
+ }
dev->driver = drv;
@@ -386,7 +390,7 @@ probe_failed:
ret = 0;
done:
atomic_dec(&probe_count);
- wake_up(&probe_waitqueue);
+ wake_up_all(&probe_waitqueue);
return ret;
}
diff --git a/drivers/base/firmware_class.c b/drivers/base/firmware_class.c
index c1093c0d4dea..991d07b219cb 100644
--- a/drivers/base/firmware_class.c
+++ b/drivers/base/firmware_class.c
@@ -1303,15 +1303,17 @@ static int assign_firmware_buf(struct firmware *fw, struct device *device,
/* called from request_firmware() and request_firmware_work_func() */
static int _request_firmware(struct fw_desc *desc)
{
- struct firmware *fw;
+ struct firmware *fw = NULL;
long timeout;
int ret;
if (!desc->firmware_p)
return -EINVAL;
- if (!desc->name || desc->name[0] == '\0')
- return -EINVAL;
+ if (!desc->name || desc->name[0] == '\0') {
+ ret = -EINVAL;
+ goto out;
+ }
ret = _request_firmware_prepare(&fw, desc);
if (ret <= 0) /* error or already assigned */
diff --git a/drivers/base/isa.c b/drivers/base/isa.c
index 901d8185309e..372d10af2600 100644
--- a/drivers/base/isa.c
+++ b/drivers/base/isa.c
@@ -180,4 +180,4 @@ static int __init isa_bus_init(void)
return error;
}
-device_initcall(isa_bus_init);
+postcore_initcall(isa_bus_init);
diff --git a/drivers/base/platform.c b/drivers/base/platform.c
index 0ed3d8381840..d757beb36040 100644
--- a/drivers/base/platform.c
+++ b/drivers/base/platform.c
@@ -658,6 +658,8 @@ int __init_or_module __platform_driver_probe(struct platform_driver *drv,
/* temporary section violation during probe() */
drv->probe = probe;
retval = code = __platform_driver_register(drv, module);
+ if (retval)
+ return retval;
/*
* Fixup that section violation, being paranoid about code scanning
diff --git a/drivers/base/power/main.c b/drivers/base/power/main.c
index 4192e46eda37..63100949e50d 100644
--- a/drivers/base/power/main.c
+++ b/drivers/base/power/main.c
@@ -1058,11 +1058,13 @@ static int __device_suspend_noirq(struct device *dev, pm_message_t state, bool a
}
error = dpm_run_callback(callback, dev, state, info);
- if (!error)
+ if (!error) {
dev->power.is_noirq_suspended = true;
- else
+ } else {
+ log_suspend_abort_reason("Callback failed on %s in %pF returned %d",
+ dev_name(dev), callback, error);
async_error = error;
-
+ }
Complete:
complete_all(&dev->power.completion);
TRACE_SUSPEND(error);
@@ -1205,10 +1207,13 @@ static int __device_suspend_late(struct device *dev, pm_message_t state, bool as
}
error = dpm_run_callback(callback, dev, state, info);
- if (!error)
+ if (!error) {
dev->power.is_late_suspended = true;
- else
+ } else {
+ log_suspend_abort_reason("Callback failed on %s in %pF returned %d",
+ dev_name(dev), callback, error);
async_error = error;
+ }
Complete:
TRACE_SUSPEND(error);
@@ -1351,7 +1356,6 @@ static int __device_suspend(struct device *dev, pm_message_t state, bool async)
pm_callback_t callback = NULL;
char *info = NULL;
int error = 0;
- char suspend_abort[MAX_SUSPEND_ABORT_LEN];
DECLARE_DPM_WATCHDOG_ON_STACK(wd);
TRACE_DEVICE(dev);
@@ -1365,18 +1369,19 @@ static int __device_suspend(struct device *dev, pm_message_t state, bool async)
}
/*
- * If a device configured to wake up the system from sleep states
- * has been suspended at run time and there's a resume request pending
- * for it, this is equivalent to the device signaling wakeup, so the
- * system suspend operation should be aborted.
+ * Wait for possible runtime PM transitions of the device in progress
+ * to complete and if there's a runtime resume request pending for it,
+ * resume it before proceeding with invoking the system-wide suspend
+ * callbacks for it.
+ *
+ * If the system-wide suspend callbacks below change the configuration
+ * of the device, they must disable runtime PM for it or otherwise
+ * ensure that its runtime-resume callbacks will not be confused by that
+ * change in case they are invoked going forward.
*/
- if (pm_runtime_barrier(dev) && device_may_wakeup(dev))
- pm_wakeup_event(dev, 0);
+ pm_runtime_barrier(dev);
if (pm_wakeup_pending()) {
- pm_get_active_wakeup_sources(suspend_abort,
- MAX_SUSPEND_ABORT_LEN);
- log_suspend_abort_reason(suspend_abort);
dev->power.direct_complete = false;
async_error = -EBUSY;
goto Complete;
@@ -1463,6 +1468,9 @@ static int __device_suspend(struct device *dev, pm_message_t state, bool async)
spin_unlock_irq(&parent->power.lock);
}
+ } else {
+ log_suspend_abort_reason("Callback failed on %s in %pF returned %d",
+ dev_name(dev), callback, error);
}
device_unlock(dev);
@@ -1666,6 +1674,9 @@ int dpm_prepare(pm_message_t state)
printk(KERN_INFO "PM: Device %s not prepared "
"for power transition: code %d\n",
dev_name(dev), error);
+ log_suspend_abort_reason("Device %s not prepared "
+ "for power transition: code %d",
+ dev_name(dev), error);
put_device(dev);
break;
}
diff --git a/drivers/base/power/wakeirq.c b/drivers/base/power/wakeirq.c
index feba1b211898..8c05e7a5e777 100644
--- a/drivers/base/power/wakeirq.c
+++ b/drivers/base/power/wakeirq.c
@@ -319,8 +319,13 @@ void dev_pm_arm_wake_irq(struct wake_irq *wirq)
if (!wirq)
return;
- if (device_may_wakeup(wirq->dev))
+ if (device_may_wakeup(wirq->dev)) {
+ if (wirq->status & WAKE_IRQ_DEDICATED_ALLOCATED &&
+ !pm_runtime_status_suspended(wirq->dev))
+ enable_irq(wirq->irq);
+
enable_irq_wake(wirq->irq);
+ }
}
/**
@@ -335,6 +340,11 @@ void dev_pm_disarm_wake_irq(struct wake_irq *wirq)
if (!wirq)
return;
- if (device_may_wakeup(wirq->dev))
+ if (device_may_wakeup(wirq->dev)) {
disable_irq_wake(wirq->irq);
+
+ if (wirq->status & WAKE_IRQ_DEDICATED_ALLOCATED &&
+ !pm_runtime_status_suspended(wirq->dev))
+ disable_irq_nosync(wirq->irq);
+ }
}
diff --git a/drivers/base/power/wakeup.c b/drivers/base/power/wakeup.c
index 37658ff761ed..5f3bd234c4be 100644
--- a/drivers/base/power/wakeup.c
+++ b/drivers/base/power/wakeup.c
@@ -16,6 +16,7 @@
#include <linux/debugfs.h>
#include <linux/pm_wakeirq.h>
#include <linux/types.h>
+#include <linux/wakeup_reason.h>
#include <trace/events/power.h>
#include "power.h"
@@ -884,6 +885,7 @@ bool pm_wakeup_pending(void)
{
unsigned long flags;
bool ret = false;
+ char suspend_abort[MAX_SUSPEND_ABORT_LEN];
spin_lock_irqsave(&events_lock, flags);
if (events_check_enabled) {
@@ -897,7 +899,10 @@ bool pm_wakeup_pending(void)
if (ret) {
pr_info("PM: Wakeup pending, aborting suspend\n");
- pm_print_active_wakeup_sources();
+ pm_get_active_wakeup_sources(suspend_abort,
+ MAX_SUSPEND_ABORT_LEN);
+ log_suspend_abort_reason(suspend_abort);
+ pr_info("PM: %s\n", suspend_abort);
}
return ret || pm_abort_suspend;
diff --git a/drivers/base/regmap/regcache-rbtree.c b/drivers/base/regmap/regcache-rbtree.c
index 56486d92c4e7..f868dda30da0 100644
--- a/drivers/base/regmap/regcache-rbtree.c
+++ b/drivers/base/regmap/regcache-rbtree.c
@@ -296,14 +296,14 @@ static int regcache_rbtree_insert_to_block(struct regmap *map,
if (!blk)
return -ENOMEM;
+ rbnode->block = blk;
+
if (BITS_TO_LONGS(blklen) > BITS_TO_LONGS(rbnode->blklen)) {
present = krealloc(rbnode->cache_present,
BITS_TO_LONGS(blklen) * sizeof(*present),
GFP_KERNEL);
- if (!present) {
- kfree(blk);
+ if (!present)
return -ENOMEM;
- }
memset(present + BITS_TO_LONGS(rbnode->blklen), 0,
(BITS_TO_LONGS(blklen) - BITS_TO_LONGS(rbnode->blklen))
@@ -320,7 +320,6 @@ static int regcache_rbtree_insert_to_block(struct regmap *map,
}
/* update the rbnode block, its size and the base register */
- rbnode->block = blk;
rbnode->blklen = blklen;
rbnode->base_reg = base_reg;
rbnode->cache_present = present;
diff --git a/drivers/base/regmap/regmap-debugfs.c b/drivers/base/regmap/regmap-debugfs.c
index 3120bdc84fce..52d6bf710e74 100644
--- a/drivers/base/regmap/regmap-debugfs.c
+++ b/drivers/base/regmap/regmap-debugfs.c
@@ -194,6 +194,9 @@ static ssize_t regmap_read_debugfs(struct regmap *map, unsigned int from,
if (*ppos < 0 || !count)
return -EINVAL;
+ if (count > (PAGE_SIZE << (MAX_ORDER - 1)))
+ count = PAGE_SIZE << (MAX_ORDER - 1);
+
buf = kmalloc(count, GFP_KERNEL);
if (!buf)
return -ENOMEM;
@@ -402,6 +405,9 @@ static ssize_t regmap_reg_ranges_read_file(struct file *file,
if (*ppos < 0 || !count)
return -EINVAL;
+ if (count > (PAGE_SIZE << (MAX_ORDER - 1)))
+ count = PAGE_SIZE << (MAX_ORDER - 1);
+
buf = kmalloc(count, GFP_KERNEL);
if (!buf)
return -ENOMEM;
diff --git a/drivers/base/regmap/regmap.c b/drivers/base/regmap/regmap.c
index 6b96ebb9b440..a9ca3cee3990 100644
--- a/drivers/base/regmap/regmap.c
+++ b/drivers/base/regmap/regmap.c
@@ -1106,7 +1106,7 @@ static int dev_get_regmap_match(struct device *dev, void *res, void *data)
/* If the user didn't specify a name match any */
if (data)
- return (*r)->name == data;
+ return !strcmp((*r)->name, data);
else
return 1;
}