summaryrefslogtreecommitdiff
path: root/drivers/base
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/base')
-rw-r--r--drivers/base/attribute_container.c2
-rw-r--r--drivers/base/bus.c4
-rw-r--r--drivers/base/cacheinfo.c13
-rw-r--r--drivers/base/class.c2
-rw-r--r--drivers/base/core.c70
-rw-r--r--drivers/base/dd.c30
-rw-r--r--drivers/base/dma-mapping.c2
-rw-r--r--drivers/base/driver.c1
-rw-r--r--drivers/base/firmware_class.c49
-rw-r--r--drivers/base/map.c3
-rw-r--r--drivers/base/memory.c79
-rw-r--r--drivers/base/node.c28
-rw-r--r--drivers/base/platform.c11
-rw-r--r--drivers/base/power/domain.c70
-rw-r--r--drivers/base/power/main.c20
-rw-r--r--drivers/base/power/trace.c6
-rw-r--r--drivers/base/power/wakeup.c16
-rw-r--r--drivers/base/property.c200
-rw-r--r--drivers/base/regmap/Makefile3
-rw-r--r--drivers/base/regmap/regcache.c2
-rw-r--r--drivers/base/regmap/regmap.c2
-rw-r--r--drivers/base/regmap/trace.h257
-rw-r--r--drivers/base/soc.c10
23 files changed, 689 insertions, 191 deletions
diff --git a/drivers/base/attribute_container.c b/drivers/base/attribute_container.c
index 3ead3af4be61..2ba4cac080c5 100644
--- a/drivers/base/attribute_container.c
+++ b/drivers/base/attribute_container.c
@@ -94,6 +94,7 @@ int
attribute_container_unregister(struct attribute_container *cont)
{
int retval = -EBUSY;
+
mutex_lock(&attribute_container_mutex);
spin_lock(&cont->containers.k_lock);
if (!list_empty(&cont->containers.k_list))
@@ -349,6 +350,7 @@ int
attribute_container_add_class_device(struct device *classdev)
{
int error = device_add(classdev);
+
if (error)
return error;
return attribute_container_add_attrs(classdev);
diff --git a/drivers/base/bus.c b/drivers/base/bus.c
index 876bae5ade33..79bc203f51ef 100644
--- a/drivers/base/bus.c
+++ b/drivers/base/bus.c
@@ -515,11 +515,11 @@ int bus_add_device(struct device *dev)
goto out_put;
error = device_add_groups(dev, bus->dev_groups);
if (error)
- goto out_groups;
+ goto out_id;
error = sysfs_create_link(&bus->p->devices_kset->kobj,
&dev->kobj, dev_name(dev));
if (error)
- goto out_id;
+ goto out_groups;
error = sysfs_create_link(&dev->kobj,
&dev->bus->p->subsys.kobj, "subsystem");
if (error)
diff --git a/drivers/base/cacheinfo.c b/drivers/base/cacheinfo.c
index 6e64563361f0..9c2ba1c97c42 100644
--- a/drivers/base/cacheinfo.c
+++ b/drivers/base/cacheinfo.c
@@ -62,15 +62,21 @@ static int cache_setup_of_node(unsigned int cpu)
return -ENOENT;
}
- while (np && index < cache_leaves(cpu)) {
+ while (index < cache_leaves(cpu)) {
this_leaf = this_cpu_ci->info_list + index;
if (this_leaf->level != 1)
np = of_find_next_cache_node(np);
else
np = of_node_get(np);/* cpu node itself */
+ if (!np)
+ break;
this_leaf->of_node = np;
index++;
}
+
+ if (index != cache_leaves(cpu)) /* not all OF nodes populated */
+ return -ENOENT;
+
return 0;
}
@@ -189,8 +195,11 @@ static int detect_cache_attributes(unsigned int cpu)
* will be set up here only if they are not populated already
*/
ret = cache_shared_cpu_map_setup(cpu);
- if (ret)
+ if (ret) {
+ pr_warn("Unable to detect cache hierarcy from DT for CPU %d\n",
+ cpu);
goto free_ci;
+ }
return 0;
free_ci:
diff --git a/drivers/base/class.c b/drivers/base/class.c
index f96f70419a78..6e810881e48b 100644
--- a/drivers/base/class.c
+++ b/drivers/base/class.c
@@ -90,6 +90,7 @@ int class_create_file_ns(struct class *cls, const struct class_attribute *attr,
const void *ns)
{
int error;
+
if (cls)
error = sysfs_create_file_ns(&cls->p->subsys.kobj,
&attr->attr, ns);
@@ -488,6 +489,7 @@ ssize_t show_class_attr_string(struct class *class,
struct class_attribute *attr, char *buf)
{
struct class_attribute_string *cs;
+
cs = container_of(attr, struct class_attribute_string, attr);
return snprintf(buf, PAGE_SIZE, "%s\n", cs->str);
}
diff --git a/drivers/base/core.c b/drivers/base/core.c
index 07304a3b9ee2..21d13038534e 100644
--- a/drivers/base/core.c
+++ b/drivers/base/core.c
@@ -12,6 +12,7 @@
#include <linux/device.h>
#include <linux/err.h>
+#include <linux/fwnode.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/slab.h>
@@ -805,8 +806,16 @@ static void cleanup_device_parent(struct device *dev)
static int device_add_class_symlinks(struct device *dev)
{
+ struct device_node *of_node = dev_of_node(dev);
int error;
+ if (of_node) {
+ error = sysfs_create_link(&dev->kobj, &of_node->kobj,"of_node");
+ if (error)
+ dev_warn(dev, "Error %d creating of_node link\n",error);
+ /* An error here doesn't warrant bringing down the device */
+ }
+
if (!dev->class)
return 0;
@@ -814,7 +823,7 @@ static int device_add_class_symlinks(struct device *dev)
&dev->class->p->subsys.kobj,
"subsystem");
if (error)
- goto out;
+ goto out_devnode;
if (dev->parent && device_is_not_partition(dev)) {
error = sysfs_create_link(&dev->kobj, &dev->parent->kobj,
@@ -842,12 +851,16 @@ out_device:
out_subsys:
sysfs_remove_link(&dev->kobj, "subsystem");
-out:
+out_devnode:
+ sysfs_remove_link(&dev->kobj, "of_node");
return error;
}
static void device_remove_class_symlinks(struct device *dev)
{
+ if (dev_of_node(dev))
+ sysfs_remove_link(&dev->kobj, "of_node");
+
if (!dev->class)
return;
@@ -1095,8 +1108,7 @@ done:
kobject_del(&dev->kobj);
Error:
cleanup_device_parent(dev);
- if (parent)
- put_device(parent);
+ put_device(parent);
name_error:
kfree(dev->p);
dev->p = NULL;
@@ -2133,3 +2145,53 @@ define_dev_printk_level(dev_notice, KERN_NOTICE);
define_dev_printk_level(_dev_info, KERN_INFO);
#endif
+
+static inline bool fwnode_is_primary(struct fwnode_handle *fwnode)
+{
+ return fwnode && !IS_ERR(fwnode->secondary);
+}
+
+/**
+ * set_primary_fwnode - Change the primary firmware node of a given device.
+ * @dev: Device to handle.
+ * @fwnode: New primary firmware node of the device.
+ *
+ * Set the device's firmware node pointer to @fwnode, but if a secondary
+ * firmware node of the device is present, preserve it.
+ */
+void set_primary_fwnode(struct device *dev, struct fwnode_handle *fwnode)
+{
+ if (fwnode) {
+ struct fwnode_handle *fn = dev->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;
+ }
+}
+EXPORT_SYMBOL_GPL(set_primary_fwnode);
+
+/**
+ * set_secondary_fwnode - Change the secondary firmware node of a given device.
+ * @dev: Device to handle.
+ * @fwnode: New secondary firmware node of the device.
+ *
+ * If a primary firmware node of the device is present, set its secondary
+ * pointer to @fwnode. Otherwise, set the device's firmware node pointer to
+ * @fwnode.
+ */
+void set_secondary_fwnode(struct device *dev, struct fwnode_handle *fwnode)
+{
+ if (fwnode)
+ fwnode->secondary = ERR_PTR(-ENODEV);
+
+ if (fwnode_is_primary(dev->fwnode))
+ dev->fwnode->secondary = fwnode;
+ else
+ dev->fwnode = fwnode;
+}
diff --git a/drivers/base/dd.c b/drivers/base/dd.c
index cdc779cf79a3..e843fdbe4925 100644
--- a/drivers/base/dd.c
+++ b/drivers/base/dd.c
@@ -298,6 +298,12 @@ static int really_probe(struct device *dev, struct device_driver *drv)
goto probe_failed;
}
+ if (dev->pm_domain && dev->pm_domain->activate) {
+ ret = dev->pm_domain->activate(dev);
+ if (ret)
+ goto probe_failed;
+ }
+
if (dev->bus->probe) {
ret = dev->bus->probe(dev);
if (ret)
@@ -308,6 +314,9 @@ static int really_probe(struct device *dev, struct device_driver *drv)
goto probe_failed;
}
+ if (dev->pm_domain && dev->pm_domain->sync)
+ dev->pm_domain->sync(dev);
+
driver_bound(dev);
ret = 1;
pr_debug("bus: '%s': %s: bound device %s to driver %s\n",
@@ -319,22 +328,28 @@ probe_failed:
driver_sysfs_remove(dev);
dev->driver = NULL;
dev_set_drvdata(dev, NULL);
+ if (dev->pm_domain && dev->pm_domain->dismiss)
+ dev->pm_domain->dismiss(dev);
- if (ret == -EPROBE_DEFER) {
+ switch (ret) {
+ case -EPROBE_DEFER:
/* Driver requested deferred probing */
- dev_info(dev, "Driver %s requests probe deferral\n", drv->name);
+ 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();
- } else if (ret != -ENODEV && ret != -ENXIO) {
+ break;
+ case -ENODEV:
+ case -ENXIO:
+ pr_debug("%s: probe of %s rejects match %d\n",
+ drv->name, dev_name(dev), ret);
+ break;
+ default:
/* driver matched but the probe failed */
printk(KERN_WARNING
"%s: probe of %s failed with error %d\n",
drv->name, dev_name(dev), ret);
- } else {
- pr_debug("%s: probe of %s rejects match %d\n",
- drv->name, dev_name(dev), ret);
}
/*
* Ignore errors returned by ->probe so that the next driver can try
@@ -525,6 +540,9 @@ static void __device_release_driver(struct device *dev)
devres_release_all(dev);
dev->driver = NULL;
dev_set_drvdata(dev, NULL);
+ if (dev->pm_domain && dev->pm_domain->dismiss)
+ dev->pm_domain->dismiss(dev);
+
klist_remove(&dev->p->knode_driver);
if (dev->bus)
blocking_notifier_call_chain(&dev->bus->p->bus_notifier,
diff --git a/drivers/base/dma-mapping.c b/drivers/base/dma-mapping.c
index 9e8bbdd470ca..d95c5971c225 100644
--- a/drivers/base/dma-mapping.c
+++ b/drivers/base/dma-mapping.c
@@ -62,7 +62,7 @@ static int dmam_match(struct device *dev, void *res, void *match_data)
* RETURNS:
* Pointer to allocated memory on success, NULL on failure.
*/
-void * dmam_alloc_coherent(struct device *dev, size_t size,
+void *dmam_alloc_coherent(struct device *dev, size_t size,
dma_addr_t *dma_handle, gfp_t gfp)
{
struct dma_devres *dr;
diff --git a/drivers/base/driver.c b/drivers/base/driver.c
index 9e29943e56ca..4eabfe28d2b3 100644
--- a/drivers/base/driver.c
+++ b/drivers/base/driver.c
@@ -103,6 +103,7 @@ int driver_create_file(struct device_driver *drv,
const struct driver_attribute *attr)
{
int error;
+
if (drv)
error = sysfs_create_file(&drv->p->kobj, &attr->attr);
else
diff --git a/drivers/base/firmware_class.c b/drivers/base/firmware_class.c
index 6c5c9edf5ff6..171841ad1008 100644
--- a/drivers/base/firmware_class.c
+++ b/drivers/base/firmware_class.c
@@ -181,7 +181,7 @@ static struct firmware_buf *__allocate_fw_buf(const char *fw_name,
{
struct firmware_buf *buf;
- buf = kzalloc(sizeof(*buf) + strlen(fw_name) + 1 , GFP_ATOMIC);
+ buf = kzalloc(sizeof(*buf) + strlen(fw_name) + 1, GFP_ATOMIC);
if (!buf)
return buf;
@@ -835,6 +835,26 @@ static struct bin_attribute firmware_attr_data = {
.write = firmware_data_write,
};
+static struct attribute *fw_dev_attrs[] = {
+ &dev_attr_loading.attr,
+ NULL
+};
+
+static struct bin_attribute *fw_dev_bin_attrs[] = {
+ &firmware_attr_data,
+ NULL
+};
+
+static const struct attribute_group fw_dev_attr_group = {
+ .attrs = fw_dev_attrs,
+ .bin_attrs = fw_dev_bin_attrs,
+};
+
+static const struct attribute_group *fw_dev_attr_groups[] = {
+ &fw_dev_attr_group,
+ NULL
+};
+
static struct firmware_priv *
fw_create_instance(struct firmware *firmware, const char *fw_name,
struct device *device, unsigned int opt_flags)
@@ -856,6 +876,7 @@ fw_create_instance(struct firmware *firmware, const char *fw_name,
dev_set_name(f_dev, "%s", fw_name);
f_dev->parent = device;
f_dev->class = &firmware_class;
+ f_dev->groups = fw_dev_attr_groups;
exit:
return fw_priv;
}
@@ -879,25 +900,10 @@ static int _request_firmware_load(struct firmware_priv *fw_priv,
goto err_put_dev;
}
- retval = device_create_bin_file(f_dev, &firmware_attr_data);
- if (retval) {
- dev_err(f_dev, "%s: sysfs_create_bin_file failed\n", __func__);
- goto err_del_dev;
- }
-
mutex_lock(&fw_lock);
list_add(&buf->pending_list, &pending_fw_head);
mutex_unlock(&fw_lock);
- retval = device_create_file(f_dev, &dev_attr_loading);
- if (retval) {
- mutex_lock(&fw_lock);
- list_del_init(&buf->pending_list);
- mutex_unlock(&fw_lock);
- dev_err(f_dev, "%s: device_create_file failed\n", __func__);
- goto err_del_bin_attr;
- }
-
if (opt_flags & FW_OPT_UEVENT) {
buf->need_uevent = true;
dev_set_uevent_suppress(f_dev, false);
@@ -913,6 +919,8 @@ static int _request_firmware_load(struct firmware_priv *fw_priv,
mutex_lock(&fw_lock);
fw_load_abort(fw_priv);
mutex_unlock(&fw_lock);
+ } else if (retval > 0) {
+ retval = 0;
}
if (is_fw_load_aborted(buf))
@@ -920,10 +928,6 @@ static int _request_firmware_load(struct firmware_priv *fw_priv,
else if (!buf->data)
retval = -ENOMEM;
- device_remove_file(f_dev, &dev_attr_loading);
-err_del_bin_attr:
- device_remove_bin_file(f_dev, &firmware_attr_data);
-err_del_dev:
device_del(f_dev);
err_put_dev:
put_device(f_dev);
@@ -1168,7 +1172,7 @@ _request_firmware(const struct firmware **firmware_p, const char *name,
**/
int
request_firmware(const struct firmware **firmware_p, const char *name,
- struct device *device)
+ struct device *device)
{
int ret;
@@ -1196,6 +1200,7 @@ int request_firmware_direct(const struct firmware **firmware_p,
const char *name, struct device *device)
{
int ret;
+
__module_get(THIS_MODULE);
ret = _request_firmware(firmware_p, name, device,
FW_OPT_UEVENT | FW_OPT_NO_WARN);
@@ -1276,7 +1281,7 @@ request_firmware_nowait(
{
struct firmware_work *fw_work;
- fw_work = kzalloc(sizeof (struct firmware_work), gfp);
+ fw_work = kzalloc(sizeof(struct firmware_work), gfp);
if (!fw_work)
return -ENOMEM;
diff --git a/drivers/base/map.c b/drivers/base/map.c
index e87017f36853..c1d38234d725 100644
--- a/drivers/base/map.c
+++ b/drivers/base/map.c
@@ -41,8 +41,7 @@ int kobj_map(struct kobj_map *domain, dev_t dev, unsigned long range,
if (n > 255)
n = 255;
- p = kmalloc(sizeof(struct probe) * n, GFP_KERNEL);
-
+ p = kmalloc_array(n, sizeof(struct probe), GFP_KERNEL);
if (p == NULL)
return -ENOMEM;
diff --git a/drivers/base/memory.c b/drivers/base/memory.c
index 85be040a21c8..2804aed3f416 100644
--- a/drivers/base/memory.c
+++ b/drivers/base/memory.c
@@ -52,13 +52,13 @@ static BLOCKING_NOTIFIER_HEAD(memory_chain);
int register_memory_notifier(struct notifier_block *nb)
{
- return blocking_notifier_chain_register(&memory_chain, nb);
+ return blocking_notifier_chain_register(&memory_chain, nb);
}
EXPORT_SYMBOL(register_memory_notifier);
void unregister_memory_notifier(struct notifier_block *nb)
{
- blocking_notifier_chain_unregister(&memory_chain, nb);
+ blocking_notifier_chain_unregister(&memory_chain, nb);
}
EXPORT_SYMBOL(unregister_memory_notifier);
@@ -152,20 +152,20 @@ static ssize_t show_mem_state(struct device *dev,
* so that they're not open-coded
*/
switch (mem->state) {
- case MEM_ONLINE:
- len = sprintf(buf, "online\n");
- break;
- case MEM_OFFLINE:
- len = sprintf(buf, "offline\n");
- break;
- case MEM_GOING_OFFLINE:
- len = sprintf(buf, "going-offline\n");
- break;
- default:
- len = sprintf(buf, "ERROR-UNKNOWN-%ld\n",
- mem->state);
- WARN_ON(1);
- break;
+ case MEM_ONLINE:
+ len = sprintf(buf, "online\n");
+ break;
+ case MEM_OFFLINE:
+ len = sprintf(buf, "offline\n");
+ break;
+ case MEM_GOING_OFFLINE:
+ len = sprintf(buf, "going-offline\n");
+ break;
+ default:
+ len = sprintf(buf, "ERROR-UNKNOWN-%ld\n",
+ mem->state);
+ WARN_ON(1);
+ break;
}
return len;
@@ -219,6 +219,7 @@ static bool pages_correctly_reserved(unsigned long start_pfn)
/*
* MEMORY_HOTPLUG depends on SPARSEMEM in mm/Kconfig, so it is
* OK to have direct references to sparsemem variables in here.
+ * Must already be protected by mem_hotplug_begin().
*/
static int
memory_block_action(unsigned long phys_index, unsigned long action, int online_type)
@@ -228,23 +229,23 @@ memory_block_action(unsigned long phys_index, unsigned long action, int online_t
struct page *first_page;
int ret;
- start_pfn = phys_index << PFN_SECTION_SHIFT;
+ start_pfn = section_nr_to_pfn(phys_index);
first_page = pfn_to_page(start_pfn);
switch (action) {
- case MEM_ONLINE:
- if (!pages_correctly_reserved(start_pfn))
- return -EBUSY;
-
- ret = online_pages(start_pfn, nr_pages, online_type);
- break;
- case MEM_OFFLINE:
- ret = offline_pages(start_pfn, nr_pages);
- break;
- default:
- WARN(1, KERN_WARNING "%s(%ld, %ld) unknown action: "
- "%ld\n", __func__, phys_index, action, action);
- ret = -EINVAL;
+ case MEM_ONLINE:
+ if (!pages_correctly_reserved(start_pfn))
+ return -EBUSY;
+
+ ret = online_pages(start_pfn, nr_pages, online_type);
+ break;
+ case MEM_OFFLINE:
+ ret = offline_pages(start_pfn, nr_pages);
+ break;
+ default:
+ WARN(1, KERN_WARNING "%s(%ld, %ld) unknown action: "
+ "%ld\n", __func__, phys_index, action, action);
+ ret = -EINVAL;
}
return ret;
@@ -286,6 +287,7 @@ static int memory_subsys_online(struct device *dev)
if (mem->online_type < 0)
mem->online_type = MMOP_ONLINE_KEEP;
+ /* Already under protection of mem_hotplug_begin() */
ret = memory_block_change_state(mem, MEM_ONLINE, MEM_OFFLINE);
/* clear online_type */
@@ -328,17 +330,19 @@ store_mem_state(struct device *dev,
goto err;
}
+ /*
+ * Memory hotplug needs to hold mem_hotplug_begin() for probe to find
+ * the correct memory block to online before doing device_online(dev),
+ * which will take dev->mutex. Take the lock early to prevent an
+ * inversion, memory_subsys_online() callbacks will be implemented by
+ * assuming it's already protected.
+ */
+ mem_hotplug_begin();
+
switch (online_type) {
case MMOP_ONLINE_KERNEL:
case MMOP_ONLINE_MOVABLE:
case MMOP_ONLINE_KEEP:
- /*
- * mem->online_type is not protected so there can be a
- * race here. However, when racing online, the first
- * will succeed and the second will just return as the
- * block will already be online. The online type
- * could be either one, but that is expected.
- */
mem->online_type = online_type;
ret = device_online(&mem->dev);
break;
@@ -349,6 +353,7 @@ store_mem_state(struct device *dev,
ret = -EINVAL; /* should never happen */
}
+ mem_hotplug_done();
err:
unlock_device_hotplug();
diff --git a/drivers/base/node.c b/drivers/base/node.c
index 36fabe43cd44..a2aa65b4215d 100644
--- a/drivers/base/node.c
+++ b/drivers/base/node.c
@@ -180,7 +180,7 @@ static ssize_t node_read_vmstat(struct device *dev,
static DEVICE_ATTR(vmstat, S_IRUGO, node_read_vmstat, NULL);
static ssize_t node_read_distance(struct device *dev,
- struct device_attribute *attr, char * buf)
+ struct device_attribute *attr, char *buf)
{
int nid = dev->id;
int len = 0;
@@ -200,6 +200,17 @@ static ssize_t node_read_distance(struct device *dev,
}
static DEVICE_ATTR(distance, S_IRUGO, node_read_distance, NULL);
+static struct attribute *node_dev_attrs[] = {
+ &dev_attr_cpumap.attr,
+ &dev_attr_cpulist.attr,
+ &dev_attr_meminfo.attr,
+ &dev_attr_numastat.attr,
+ &dev_attr_distance.attr,
+ &dev_attr_vmstat.attr,
+ NULL
+};
+ATTRIBUTE_GROUPS(node_dev);
+
#ifdef CONFIG_HUGETLBFS
/*
* hugetlbfs per node attributes registration interface:
@@ -273,16 +284,10 @@ static int register_node(struct node *node, int num, struct node *parent)
node->dev.id = num;
node->dev.bus = &node_subsys;
node->dev.release = node_device_release;
+ node->dev.groups = node_dev_groups;
error = device_register(&node->dev);
if (!error){
- device_create_file(&node->dev, &dev_attr_cpumap);
- device_create_file(&node->dev, &dev_attr_cpulist);
- device_create_file(&node->dev, &dev_attr_meminfo);
- device_create_file(&node->dev, &dev_attr_numastat);
- device_create_file(&node->dev, &dev_attr_distance);
- device_create_file(&node->dev, &dev_attr_vmstat);
-
hugetlb_register_node(node);
compaction_register_node(node);
@@ -299,13 +304,6 @@ static int register_node(struct node *node, int num, struct node *parent)
*/
void unregister_node(struct node *node)
{
- device_remove_file(&node->dev, &dev_attr_cpumap);
- device_remove_file(&node->dev, &dev_attr_cpulist);
- device_remove_file(&node->dev, &dev_attr_meminfo);
- device_remove_file(&node->dev, &dev_attr_numastat);
- device_remove_file(&node->dev, &dev_attr_distance);
- device_remove_file(&node->dev, &dev_attr_vmstat);
-
hugetlb_unregister_node(node); /* no-op, if memoryless node */
device_unregister(&node->dev);
diff --git a/drivers/base/platform.c b/drivers/base/platform.c
index 9421fed40905..ebf034b97278 100644
--- a/drivers/base/platform.c
+++ b/drivers/base/platform.c
@@ -101,6 +101,15 @@ int platform_get_irq(struct platform_device *dev, unsigned int num)
}
r = platform_get_resource(dev, IORESOURCE_IRQ, num);
+ /*
+ * The resources may pass trigger flags to the irqs that need
+ * to be set up. It so happens that the trigger flags for
+ * IORESOURCE_BITS correspond 1-to-1 to the IRQF_TRIGGER*
+ * settings.
+ */
+ if (r && r->flags & IORESOURCE_BITS)
+ irqd_set_trigger_type(irq_get_irq_data(r->start),
+ r->flags & IORESOURCE_BITS);
return r ? r->start : -ENXIO;
#endif
@@ -454,7 +463,7 @@ struct platform_device *platform_device_register_full(
goto err_alloc;
pdev->dev.parent = pdevinfo->parent;
- ACPI_COMPANION_SET(&pdev->dev, pdevinfo->acpi_node.companion);
+ pdev->dev.fwnode = pdevinfo->fwnode;
if (pdevinfo->dma_mask) {
/*
diff --git a/drivers/base/power/domain.c b/drivers/base/power/domain.c
index 45937f88e77c..2327613d4539 100644
--- a/drivers/base/power/domain.c
+++ b/drivers/base/power/domain.c
@@ -68,7 +68,36 @@ static struct generic_pm_domain *pm_genpd_lookup_name(const char *domain_name)
return genpd;
}
-struct generic_pm_domain *dev_to_genpd(struct device *dev)
+/*
+ * Get the generic PM domain for a particular struct device.
+ * This validates the struct device pointer, the PM domain pointer,
+ * and checks that the PM domain pointer is a real generic PM domain.
+ * Any failure results in NULL being returned.
+ */
+struct generic_pm_domain *pm_genpd_lookup_dev(struct device *dev)
+{
+ struct generic_pm_domain *genpd = NULL, *gpd;
+
+ if (IS_ERR_OR_NULL(dev) || IS_ERR_OR_NULL(dev->pm_domain))
+ return NULL;
+
+ mutex_lock(&gpd_list_lock);
+ list_for_each_entry(gpd, &gpd_list, gpd_list_node) {
+ if (&gpd->domain == dev->pm_domain) {
+ genpd = gpd;
+ break;
+ }
+ }
+ mutex_unlock(&gpd_list_lock);
+
+ return genpd;
+}
+
+/*
+ * This should only be used where we are certain that the pm_domain
+ * attached to the device is a genpd domain.
+ */
+static struct generic_pm_domain *dev_to_genpd(struct device *dev)
{
if (IS_ERR_OR_NULL(dev->pm_domain))
return ERR_PTR(-EINVAL);
@@ -173,8 +202,8 @@ static int genpd_power_on(struct generic_pm_domain *genpd)
genpd->power_on_latency_ns = elapsed_ns;
genpd->max_off_time_changed = true;
genpd_recalc_cpu_exit_latency(genpd);
- pr_warn("%s: Power-%s latency exceeded, new value %lld ns\n",
- genpd->name, "on", elapsed_ns);
+ pr_debug("%s: Power-%s latency exceeded, new value %lld ns\n",
+ genpd->name, "on", elapsed_ns);
return ret;
}
@@ -199,8 +228,8 @@ static int genpd_power_off(struct generic_pm_domain *genpd)
genpd->power_off_latency_ns = elapsed_ns;
genpd->max_off_time_changed = true;
- pr_warn("%s: Power-%s latency exceeded, new value %lld ns\n",
- genpd->name, "off", elapsed_ns);
+ pr_debug("%s: Power-%s latency exceeded, new value %lld ns\n",
+ genpd->name, "off", elapsed_ns);
return ret;
}
@@ -1513,9 +1542,7 @@ int pm_genpd_remove_device(struct generic_pm_domain *genpd,
dev_dbg(dev, "%s()\n", __func__);
- if (IS_ERR_OR_NULL(genpd) || IS_ERR_OR_NULL(dev)
- || IS_ERR_OR_NULL(dev->pm_domain)
- || pd_to_genpd(dev->pm_domain) != genpd)
+ if (!genpd || genpd != pm_genpd_lookup_dev(dev))
return -EINVAL;
/* The above validation also means we have existing domain_data. */
@@ -2093,21 +2120,10 @@ EXPORT_SYMBOL_GPL(of_genpd_get_from_provider);
*/
static void genpd_dev_pm_detach(struct device *dev, bool power_off)
{
- struct generic_pm_domain *pd = NULL, *gpd;
+ struct generic_pm_domain *pd;
int ret = 0;
- if (!dev->pm_domain)
- return;
-
- mutex_lock(&gpd_list_lock);
- list_for_each_entry(gpd, &gpd_list, gpd_list_node) {
- if (&gpd->domain == dev->pm_domain) {
- pd = gpd;
- break;
- }
- }
- mutex_unlock(&gpd_list_lock);
-
+ pd = pm_genpd_lookup_dev(dev);
if (!pd)
return;
@@ -2130,6 +2146,17 @@ static void genpd_dev_pm_detach(struct device *dev, bool power_off)
genpd_queue_power_off_work(pd);
}
+static void genpd_dev_pm_sync(struct device *dev)
+{
+ struct generic_pm_domain *pd;
+
+ pd = dev_to_genpd(dev);
+ if (IS_ERR(pd))
+ return;
+
+ genpd_queue_power_off_work(pd);
+}
+
/**
* genpd_dev_pm_attach - Attach a device to its PM domain using DT.
* @dev: Device to attach.
@@ -2196,6 +2223,7 @@ int genpd_dev_pm_attach(struct device *dev)
}
dev->pm_domain->detach = genpd_dev_pm_detach;
+ dev->pm_domain->sync = genpd_dev_pm_sync;
pm_genpd_poweron(pd);
return 0;
diff --git a/drivers/base/power/main.c b/drivers/base/power/main.c
index 9717d5f20139..3d874eca7104 100644
--- a/drivers/base/power/main.c
+++ b/drivers/base/power/main.c
@@ -23,7 +23,7 @@
#include <linux/mutex.h>
#include <linux/pm.h>
#include <linux/pm_runtime.h>
-#include <linux/resume-trace.h>
+#include <linux/pm-trace.h>
#include <linux/interrupt.h>
#include <linux/sched.h>
#include <linux/async.h>
@@ -1017,6 +1017,9 @@ static int __device_suspend_noirq(struct device *dev, pm_message_t state, bool a
char *info = NULL;
int error = 0;
+ TRACE_DEVICE(dev);
+ TRACE_SUSPEND(0);
+
if (async_error)
goto Complete;
@@ -1057,6 +1060,7 @@ static int __device_suspend_noirq(struct device *dev, pm_message_t state, bool a
Complete:
complete_all(&dev->power.completion);
+ TRACE_SUSPEND(error);
return error;
}
@@ -1078,7 +1082,7 @@ static int device_suspend_noirq(struct device *dev)
{
reinit_completion(&dev->power.completion);
- if (pm_async_enabled && dev->power.async_suspend) {
+ if (is_async(dev)) {
get_device(dev);
async_schedule(async_suspend_noirq, dev);
return 0;
@@ -1157,6 +1161,9 @@ static int __device_suspend_late(struct device *dev, pm_message_t state, bool as
char *info = NULL;
int error = 0;
+ TRACE_DEVICE(dev);
+ TRACE_SUSPEND(0);
+
__pm_runtime_disable(dev, false);
if (async_error)
@@ -1198,6 +1205,7 @@ static int __device_suspend_late(struct device *dev, pm_message_t state, bool as
async_error = error;
Complete:
+ TRACE_SUSPEND(error);
complete_all(&dev->power.completion);
return error;
}
@@ -1219,7 +1227,7 @@ static int device_suspend_late(struct device *dev)
{
reinit_completion(&dev->power.completion);
- if (pm_async_enabled && dev->power.async_suspend) {
+ if (is_async(dev)) {
get_device(dev);
async_schedule(async_suspend_late, dev);
return 0;
@@ -1338,6 +1346,9 @@ static int __device_suspend(struct device *dev, pm_message_t state, bool async)
int error = 0;
DECLARE_DPM_WATCHDOG_ON_STACK(wd);
+ TRACE_DEVICE(dev);
+ TRACE_SUSPEND(0);
+
dpm_wait_for_children(dev, async);
if (async_error)
@@ -1444,6 +1455,7 @@ static int __device_suspend(struct device *dev, pm_message_t state, bool async)
if (error)
async_error = error;
+ TRACE_SUSPEND(error);
return error;
}
@@ -1465,7 +1477,7 @@ static int device_suspend(struct device *dev)
{
reinit_completion(&dev->power.completion);
- if (pm_async_enabled && dev->power.async_suspend) {
+ if (is_async(dev)) {
get_device(dev);
async_schedule(async_suspend, dev);
return 0;
diff --git a/drivers/base/power/trace.c b/drivers/base/power/trace.c
index d94a1f5121cf..a311cfa4c5bd 100644
--- a/drivers/base/power/trace.c
+++ b/drivers/base/power/trace.c
@@ -7,7 +7,7 @@
* devices may be working.
*/
-#include <linux/resume-trace.h>
+#include <linux/pm-trace.h>
#include <linux/export.h>
#include <linux/rtc.h>
@@ -154,7 +154,7 @@ EXPORT_SYMBOL(set_trace_device);
* it's not any guarantee, but it's a high _likelihood_ that
* the match is valid).
*/
-void generate_resume_trace(const void *tracedata, unsigned int user)
+void generate_pm_trace(const void *tracedata, unsigned int user)
{
unsigned short lineno = *(unsigned short *)tracedata;
const char *file = *(const char **)(tracedata + 2);
@@ -164,7 +164,7 @@ void generate_resume_trace(const void *tracedata, unsigned int user)
file_hash_value = hash_string(lineno, file, FILEHASH);
set_magic_time(user_hash_value, file_hash_value, dev_hash_value);
}
-EXPORT_SYMBOL(generate_resume_trace);
+EXPORT_SYMBOL(generate_pm_trace);
extern char __tracedata_start, __tracedata_end;
static int show_file_hash(unsigned int value)
diff --git a/drivers/base/power/wakeup.c b/drivers/base/power/wakeup.c
index aab7158d2afe..77262009f89d 100644
--- a/drivers/base/power/wakeup.c
+++ b/drivers/base/power/wakeup.c
@@ -843,7 +843,6 @@ static int print_wakeup_source_stats(struct seq_file *m,
unsigned long active_count;
ktime_t active_time;
ktime_t prevent_sleep_time;
- int ret;
spin_lock_irqsave(&ws->lock, flags);
@@ -866,17 +865,16 @@ static int print_wakeup_source_stats(struct seq_file *m,
active_time = ktime_set(0, 0);
}
- ret = seq_printf(m, "%-12s\t%lu\t\t%lu\t\t%lu\t\t%lu\t\t"
- "%lld\t\t%lld\t\t%lld\t\t%lld\t\t%lld\n",
- ws->name, active_count, ws->event_count,
- ws->wakeup_count, ws->expire_count,
- ktime_to_ms(active_time), ktime_to_ms(total_time),
- ktime_to_ms(max_time), ktime_to_ms(ws->last_time),
- ktime_to_ms(prevent_sleep_time));
+ seq_printf(m, "%-12s\t%lu\t\t%lu\t\t%lu\t\t%lu\t\t%lld\t\t%lld\t\t%lld\t\t%lld\t\t%lld\n",
+ ws->name, active_count, ws->event_count,
+ ws->wakeup_count, ws->expire_count,
+ ktime_to_ms(active_time), ktime_to_ms(total_time),
+ ktime_to_ms(max_time), ktime_to_ms(ws->last_time),
+ ktime_to_ms(prevent_sleep_time));
spin_unlock_irqrestore(&ws->lock, flags);
- return ret;
+ return 0;
}
/**
diff --git a/drivers/base/property.c b/drivers/base/property.c
index c45845874d4f..1d0b116cae95 100644
--- a/drivers/base/property.c
+++ b/drivers/base/property.c
@@ -10,10 +10,102 @@
* published by the Free Software Foundation.
*/
-#include <linux/property.h>
-#include <linux/export.h>
#include <linux/acpi.h>
+#include <linux/export.h>
+#include <linux/kernel.h>
#include <linux/of.h>
+#include <linux/property.h>
+
+/**
+ * device_add_property_set - Add a collection of properties to a device object.
+ * @dev: Device to add properties to.
+ * @pset: Collection of properties to add.
+ *
+ * Associate a collection of device properties represented by @pset with @dev
+ * as its secondary firmware node.
+ */
+void device_add_property_set(struct device *dev, struct property_set *pset)
+{
+ if (pset)
+ pset->fwnode.type = FWNODE_PDATA;
+
+ set_secondary_fwnode(dev, &pset->fwnode);
+}
+EXPORT_SYMBOL_GPL(device_add_property_set);
+
+static inline bool is_pset(struct fwnode_handle *fwnode)
+{
+ return fwnode && fwnode->type == FWNODE_PDATA;
+}
+
+static inline struct property_set *to_pset(struct fwnode_handle *fwnode)
+{
+ return is_pset(fwnode) ?
+ container_of(fwnode, struct property_set, fwnode) : NULL;
+}
+
+static struct property_entry *pset_prop_get(struct property_set *pset,
+ const char *name)
+{
+ struct property_entry *prop;
+
+ if (!pset || !pset->properties)
+ return NULL;
+
+ for (prop = pset->properties; prop->name; prop++)
+ if (!strcmp(name, prop->name))
+ return prop;
+
+ return NULL;
+}
+
+static int pset_prop_read_array(struct property_set *pset, const char *name,
+ enum dev_prop_type type, void *val, size_t nval)
+{
+ struct property_entry *prop;
+ unsigned int item_size;
+
+ prop = pset_prop_get(pset, name);
+ if (!prop)
+ return -ENODATA;
+
+ if (prop->type != type)
+ return -EPROTO;
+
+ if (!val)
+ return prop->nval;
+
+ if (prop->nval < nval)
+ return -EOVERFLOW;
+
+ switch (type) {
+ case DEV_PROP_U8:
+ item_size = sizeof(u8);
+ break;
+ case DEV_PROP_U16:
+ item_size = sizeof(u16);
+ break;
+ case DEV_PROP_U32:
+ item_size = sizeof(u32);
+ break;
+ case DEV_PROP_U64:
+ item_size = sizeof(u64);
+ break;
+ case DEV_PROP_STRING:
+ item_size = sizeof(const char *);
+ break;
+ default:
+ return -EINVAL;
+ }
+ memcpy(val, prop->value.raw_data, nval * item_size);
+ return 0;
+}
+
+static inline struct fwnode_handle *dev_fwnode(struct device *dev)
+{
+ return IS_ENABLED(CONFIG_OF) && dev->of_node ?
+ &dev->of_node->fwnode : dev->fwnode;
+}
/**
* device_property_present - check if a property of a device is present
@@ -24,10 +116,7 @@
*/
bool device_property_present(struct device *dev, const char *propname)
{
- if (IS_ENABLED(CONFIG_OF) && dev->of_node)
- return of_property_read_bool(dev->of_node, propname);
-
- return !acpi_dev_prop_get(ACPI_COMPANION(dev), propname, NULL);
+ return fwnode_property_present(dev_fwnode(dev), propname);
}
EXPORT_SYMBOL_GPL(device_property_present);
@@ -43,32 +132,22 @@ bool fwnode_property_present(struct fwnode_handle *fwnode, const char *propname)
else if (is_acpi_node(fwnode))
return !acpi_dev_prop_get(acpi_node(fwnode), propname, NULL);
- return false;
+ return !!pset_prop_get(to_pset(fwnode), propname);
}
EXPORT_SYMBOL_GPL(fwnode_property_present);
-#define OF_DEV_PROP_READ_ARRAY(node, propname, type, val, nval) \
- (val) ? of_property_read_##type##_array((node), (propname), (val), (nval)) \
- : of_property_count_elems_of_size((node), (propname), sizeof(type))
-
-#define DEV_PROP_READ_ARRAY(_dev_, _propname_, _type_, _proptype_, _val_, _nval_) \
- IS_ENABLED(CONFIG_OF) && _dev_->of_node ? \
- (OF_DEV_PROP_READ_ARRAY(_dev_->of_node, _propname_, _type_, \
- _val_, _nval_)) : \
- acpi_dev_prop_read(ACPI_COMPANION(_dev_), _propname_, \
- _proptype_, _val_, _nval_)
-
/**
* device_property_read_u8_array - return a u8 array property of a device
* @dev: Device to get the property of
* @propname: Name of the property
- * @val: The values are stored here
+ * @val: The values are stored here or %NULL to return the number of values
* @nval: Size of the @val array
*
* Function reads an array of u8 properties with @propname from the device
* firmware description and stores them to @val if found.
*
- * Return: %0 if the property was found (success),
+ * Return: number of values if @val was %NULL,
+ * %0 if the property was found (success),
* %-EINVAL if given arguments are not valid,
* %-ENODATA if the property does not have a value,
* %-EPROTO if the property is not an array of numbers,
@@ -77,7 +156,7 @@ EXPORT_SYMBOL_GPL(fwnode_property_present);
int device_property_read_u8_array(struct device *dev, const char *propname,
u8 *val, size_t nval)
{
- return DEV_PROP_READ_ARRAY(dev, propname, u8, DEV_PROP_U8, val, nval);
+ return fwnode_property_read_u8_array(dev_fwnode(dev), propname, val, nval);
}
EXPORT_SYMBOL_GPL(device_property_read_u8_array);
@@ -85,13 +164,14 @@ EXPORT_SYMBOL_GPL(device_property_read_u8_array);
* device_property_read_u16_array - return a u16 array property of a device
* @dev: Device to get the property of
* @propname: Name of the property
- * @val: The values are stored here
+ * @val: The values are stored here or %NULL to return the number of values
* @nval: Size of the @val array
*
* Function reads an array of u16 properties with @propname from the device
* firmware description and stores them to @val if found.
*
- * Return: %0 if the property was found (success),
+ * Return: number of values if @val was %NULL,
+ * %0 if the property was found (success),
* %-EINVAL if given arguments are not valid,
* %-ENODATA if the property does not have a value,
* %-EPROTO if the property is not an array of numbers,
@@ -100,7 +180,7 @@ EXPORT_SYMBOL_GPL(device_property_read_u8_array);
int device_property_read_u16_array(struct device *dev, const char *propname,
u16 *val, size_t nval)
{
- return DEV_PROP_READ_ARRAY(dev, propname, u16, DEV_PROP_U16, val, nval);
+ return fwnode_property_read_u16_array(dev_fwnode(dev), propname, val, nval);
}
EXPORT_SYMBOL_GPL(device_property_read_u16_array);
@@ -108,13 +188,14 @@ EXPORT_SYMBOL_GPL(device_property_read_u16_array);
* device_property_read_u32_array - return a u32 array property of a device
* @dev: Device to get the property of
* @propname: Name of the property
- * @val: The values are stored here
+ * @val: The values are stored here or %NULL to return the number of values
* @nval: Size of the @val array
*
* Function reads an array of u32 properties with @propname from the device
* firmware description and stores them to @val if found.
*
- * Return: %0 if the property was found (success),
+ * Return: number of values if @val was %NULL,
+ * %0 if the property was found (success),
* %-EINVAL if given arguments are not valid,
* %-ENODATA if the property does not have a value,
* %-EPROTO if the property is not an array of numbers,
@@ -123,7 +204,7 @@ EXPORT_SYMBOL_GPL(device_property_read_u16_array);
int device_property_read_u32_array(struct device *dev, const char *propname,
u32 *val, size_t nval)
{
- return DEV_PROP_READ_ARRAY(dev, propname, u32, DEV_PROP_U32, val, nval);
+ return fwnode_property_read_u32_array(dev_fwnode(dev), propname, val, nval);
}
EXPORT_SYMBOL_GPL(device_property_read_u32_array);
@@ -131,13 +212,14 @@ EXPORT_SYMBOL_GPL(device_property_read_u32_array);
* device_property_read_u64_array - return a u64 array property of a device
* @dev: Device to get the property of
* @propname: Name of the property
- * @val: The values are stored here
+ * @val: The values are stored here or %NULL to return the number of values
* @nval: Size of the @val array
*
* Function reads an array of u64 properties with @propname from the device
* firmware description and stores them to @val if found.
*
- * Return: %0 if the property was found (success),
+ * Return: number of values if @val was %NULL,
+ * %0 if the property was found (success),
* %-EINVAL if given arguments are not valid,
* %-ENODATA if the property does not have a value,
* %-EPROTO if the property is not an array of numbers,
@@ -146,7 +228,7 @@ EXPORT_SYMBOL_GPL(device_property_read_u32_array);
int device_property_read_u64_array(struct device *dev, const char *propname,
u64 *val, size_t nval)
{
- return DEV_PROP_READ_ARRAY(dev, propname, u64, DEV_PROP_U64, val, nval);
+ return fwnode_property_read_u64_array(dev_fwnode(dev), propname, val, nval);
}
EXPORT_SYMBOL_GPL(device_property_read_u64_array);
@@ -154,13 +236,14 @@ EXPORT_SYMBOL_GPL(device_property_read_u64_array);
* device_property_read_string_array - return a string array property of device
* @dev: Device to get the property of
* @propname: Name of the property
- * @val: The values are stored here
+ * @val: The values are stored here or %NULL to return the number of values
* @nval: Size of the @val array
*
* Function reads an array of string properties with @propname from the device
* firmware description and stores them to @val if found.
*
- * Return: %0 if the property was found (success),
+ * Return: number of values if @val was %NULL,
+ * %0 if the property was found (success),
* %-EINVAL if given arguments are not valid,
* %-ENODATA if the property does not have a value,
* %-EPROTO or %-EILSEQ if the property is not an array of strings,
@@ -169,10 +252,7 @@ EXPORT_SYMBOL_GPL(device_property_read_u64_array);
int device_property_read_string_array(struct device *dev, const char *propname,
const char **val, size_t nval)
{
- return IS_ENABLED(CONFIG_OF) && dev->of_node ?
- of_property_read_string_array(dev->of_node, propname, val, nval) :
- acpi_dev_prop_read(ACPI_COMPANION(dev), propname,
- DEV_PROP_STRING, val, nval);
+ return fwnode_property_read_string_array(dev_fwnode(dev), propname, val, nval);
}
EXPORT_SYMBOL_GPL(device_property_read_string_array);
@@ -193,13 +273,14 @@ EXPORT_SYMBOL_GPL(device_property_read_string_array);
int device_property_read_string(struct device *dev, const char *propname,
const char **val)
{
- return IS_ENABLED(CONFIG_OF) && dev->of_node ?
- of_property_read_string(dev->of_node, propname, val) :
- acpi_dev_prop_read(ACPI_COMPANION(dev), propname,
- DEV_PROP_STRING, val, 1);
+ return fwnode_property_read_string(dev_fwnode(dev), propname, val);
}
EXPORT_SYMBOL_GPL(device_property_read_string);
+#define OF_DEV_PROP_READ_ARRAY(node, propname, type, val, nval) \
+ (val) ? of_property_read_##type##_array((node), (propname), (val), (nval)) \
+ : of_property_count_elems_of_size((node), (propname), sizeof(type))
+
#define FWNODE_PROP_READ_ARRAY(_fwnode_, _propname_, _type_, _proptype_, _val_, _nval_) \
({ \
int _ret_; \
@@ -210,7 +291,8 @@ EXPORT_SYMBOL_GPL(device_property_read_string);
_ret_ = acpi_dev_prop_read(acpi_node(_fwnode_), _propname_, \
_proptype_, _val_, _nval_); \
else \
- _ret_ = -ENXIO; \
+ _ret_ = pset_prop_read_array(to_pset(_fwnode_), _propname_, \
+ _proptype_, _val_, _nval_); \
_ret_; \
})
@@ -218,13 +300,14 @@ EXPORT_SYMBOL_GPL(device_property_read_string);
* fwnode_property_read_u8_array - return a u8 array property of firmware node
* @fwnode: Firmware node to get the property of
* @propname: Name of the property
- * @val: The values are stored here
+ * @val: The values are stored here or %NULL to return the number of values
* @nval: Size of the @val array
*
* Read an array of u8 properties with @propname from @fwnode and stores them to
* @val if found.
*
- * Return: %0 if the property was found (success),
+ * Return: number of values if @val was %NULL,
+ * %0 if the property was found (success),
* %-EINVAL if given arguments are not valid,
* %-ENODATA if the property does not have a value,
* %-EPROTO if the property is not an array of numbers,
@@ -243,13 +326,14 @@ EXPORT_SYMBOL_GPL(fwnode_property_read_u8_array);
* fwnode_property_read_u16_array - return a u16 array property of firmware node
* @fwnode: Firmware node to get the property of
* @propname: Name of the property
- * @val: The values are stored here
+ * @val: The values are stored here or %NULL to return the number of values
* @nval: Size of the @val array
*
* Read an array of u16 properties with @propname from @fwnode and store them to
* @val if found.
*
- * Return: %0 if the property was found (success),
+ * Return: number of values if @val was %NULL,
+ * %0 if the property was found (success),
* %-EINVAL if given arguments are not valid,
* %-ENODATA if the property does not have a value,
* %-EPROTO if the property is not an array of numbers,
@@ -268,13 +352,14 @@ EXPORT_SYMBOL_GPL(fwnode_property_read_u16_array);
* fwnode_property_read_u32_array - return a u32 array property of firmware node
* @fwnode: Firmware node to get the property of
* @propname: Name of the property
- * @val: The values are stored here
+ * @val: The values are stored here or %NULL to return the number of values
* @nval: Size of the @val array
*
* Read an array of u32 properties with @propname from @fwnode store them to
* @val if found.
*
- * Return: %0 if the property was found (success),
+ * Return: number of values if @val was %NULL,
+ * %0 if the property was found (success),
* %-EINVAL if given arguments are not valid,
* %-ENODATA if the property does not have a value,
* %-EPROTO if the property is not an array of numbers,
@@ -293,13 +378,14 @@ EXPORT_SYMBOL_GPL(fwnode_property_read_u32_array);
* fwnode_property_read_u64_array - return a u64 array property firmware node
* @fwnode: Firmware node to get the property of
* @propname: Name of the property
- * @val: The values are stored here
+ * @val: The values are stored here or %NULL to return the number of values
* @nval: Size of the @val array
*
* Read an array of u64 properties with @propname from @fwnode and store them to
* @val if found.
*
- * Return: %0 if the property was found (success),
+ * Return: number of values if @val was %NULL,
+ * %0 if the property was found (success),
* %-EINVAL if given arguments are not valid,
* %-ENODATA if the property does not have a value,
* %-EPROTO if the property is not an array of numbers,
@@ -318,13 +404,14 @@ EXPORT_SYMBOL_GPL(fwnode_property_read_u64_array);
* fwnode_property_read_string_array - return string array property of a node
* @fwnode: Firmware node to get the property of
* @propname: Name of the property
- * @val: The values are stored here
+ * @val: The values are stored here or %NULL to return the number of values
* @nval: Size of the @val array
*
* Read an string list property @propname from the given firmware node and store
* them to @val if found.
*
- * Return: %0 if the property was found (success),
+ * Return: number of values if @val was %NULL,
+ * %0 if the property was found (success),
* %-EINVAL if given arguments are not valid,
* %-ENODATA if the property does not have a value,
* %-EPROTO if the property is not an array of strings,
@@ -336,13 +423,16 @@ int fwnode_property_read_string_array(struct fwnode_handle *fwnode,
size_t nval)
{
if (is_of_node(fwnode))
- return of_property_read_string_array(of_node(fwnode), propname,
- val, nval);
+ return val ?
+ of_property_read_string_array(of_node(fwnode), propname,
+ val, nval) :
+ of_property_count_strings(of_node(fwnode), propname);
else if (is_acpi_node(fwnode))
return acpi_dev_prop_read(acpi_node(fwnode), propname,
DEV_PROP_STRING, val, nval);
- return -ENXIO;
+ return pset_prop_read_array(to_pset(fwnode), propname,
+ DEV_PROP_STRING, val, nval);
}
EXPORT_SYMBOL_GPL(fwnode_property_read_string_array);
@@ -365,7 +455,7 @@ int fwnode_property_read_string(struct fwnode_handle *fwnode,
const char *propname, const char **val)
{
if (is_of_node(fwnode))
- return of_property_read_string(of_node(fwnode),propname, val);
+ return of_property_read_string(of_node(fwnode), propname, val);
else if (is_acpi_node(fwnode))
return acpi_dev_prop_read(acpi_node(fwnode), propname,
DEV_PROP_STRING, val, 1);
diff --git a/drivers/base/regmap/Makefile b/drivers/base/regmap/Makefile
index 0a533653ef3b..609e4c84f485 100644
--- a/drivers/base/regmap/Makefile
+++ b/drivers/base/regmap/Makefile
@@ -1,3 +1,6 @@
+# For include/trace/define_trace.h to include trace.h
+CFLAGS_regmap.o := -I$(src)
+
obj-$(CONFIG_REGMAP) += regmap.o regcache.o
obj-$(CONFIG_REGMAP) += regcache-rbtree.o regcache-lzo.o regcache-flat.o
obj-$(CONFIG_DEBUG_FS) += regmap-debugfs.o
diff --git a/drivers/base/regmap/regcache.c b/drivers/base/regmap/regcache.c
index 87db9893b463..7eb7b3b98794 100644
--- a/drivers/base/regmap/regcache.c
+++ b/drivers/base/regmap/regcache.c
@@ -15,8 +15,8 @@
#include <linux/export.h>
#include <linux/slab.h>
#include <linux/sort.h>
-#include <trace/events/regmap.h>
+#include "trace.h"
#include "internal.h"
static const struct regcache_ops *cache_types[] = {
diff --git a/drivers/base/regmap/regmap.c b/drivers/base/regmap/regmap.c
index dbfe6a69c3da..6273ff072f3e 100644
--- a/drivers/base/regmap/regmap.c
+++ b/drivers/base/regmap/regmap.c
@@ -20,7 +20,7 @@
#include <linux/sched.h>
#define CREATE_TRACE_POINTS
-#include <trace/events/regmap.h>
+#include "trace.h"
#include "internal.h"
diff --git a/drivers/base/regmap/trace.h b/drivers/base/regmap/trace.h
new file mode 100644
index 000000000000..64586a1c5a42
--- /dev/null
+++ b/drivers/base/regmap/trace.h
@@ -0,0 +1,257 @@
+#undef TRACE_SYSTEM
+#define TRACE_SYSTEM regmap
+
+#if !defined(_TRACE_REGMAP_H) || defined(TRACE_HEADER_MULTI_READ)
+#define _TRACE_REGMAP_H
+
+#include <linux/ktime.h>
+#include <linux/tracepoint.h>
+
+#include "internal.h"
+
+/*
+ * Log register events
+ */
+DECLARE_EVENT_CLASS(regmap_reg,
+
+ TP_PROTO(struct regmap *map, unsigned int reg,
+ unsigned int val),
+
+ TP_ARGS(map, reg, val),
+
+ TP_STRUCT__entry(
+ __string( name, regmap_name(map) )
+ __field( unsigned int, reg )
+ __field( unsigned int, val )
+ ),
+
+ TP_fast_assign(
+ __assign_str(name, regmap_name(map));
+ __entry->reg = reg;
+ __entry->val = val;
+ ),
+
+ TP_printk("%s reg=%x val=%x", __get_str(name),
+ (unsigned int)__entry->reg,
+ (unsigned int)__entry->val)
+);
+
+DEFINE_EVENT(regmap_reg, regmap_reg_write,
+
+ TP_PROTO(struct regmap *map, unsigned int reg,
+ unsigned int val),
+
+ TP_ARGS(map, reg, val)
+
+);
+
+DEFINE_EVENT(regmap_reg, regmap_reg_read,
+
+ TP_PROTO(struct regmap *map, unsigned int reg,
+ unsigned int val),
+
+ TP_ARGS(map, reg, val)
+
+);
+
+DEFINE_EVENT(regmap_reg, regmap_reg_read_cache,
+
+ TP_PROTO(struct regmap *map, unsigned int reg,
+ unsigned int val),
+
+ TP_ARGS(map, reg, val)
+
+);
+
+DECLARE_EVENT_CLASS(regmap_block,
+
+ TP_PROTO(struct regmap *map, unsigned int reg, int count),
+
+ TP_ARGS(map, reg, count),
+
+ TP_STRUCT__entry(
+ __string( name, regmap_name(map) )
+ __field( unsigned int, reg )
+ __field( int, count )
+ ),
+
+ TP_fast_assign(
+ __assign_str(name, regmap_name(map));
+ __entry->reg = reg;
+ __entry->count = count;
+ ),
+
+ TP_printk("%s reg=%x count=%d", __get_str(name),
+ (unsigned int)__entry->reg,
+ (int)__entry->count)
+);
+
+DEFINE_EVENT(regmap_block, regmap_hw_read_start,
+
+ TP_PROTO(struct regmap *map, unsigned int reg, int count),
+
+ TP_ARGS(map, reg, count)
+);
+
+DEFINE_EVENT(regmap_block, regmap_hw_read_done,
+
+ TP_PROTO(struct regmap *map, unsigned int reg, int count),
+
+ TP_ARGS(map, reg, count)
+);
+
+DEFINE_EVENT(regmap_block, regmap_hw_write_start,
+
+ TP_PROTO(struct regmap *map, unsigned int reg, int count),
+
+ TP_ARGS(map, reg, count)
+);
+
+DEFINE_EVENT(regmap_block, regmap_hw_write_done,
+
+ TP_PROTO(struct regmap *map, unsigned int reg, int count),
+
+ TP_ARGS(map, reg, count)
+);
+
+TRACE_EVENT(regcache_sync,
+
+ TP_PROTO(struct regmap *map, const char *type,
+ const char *status),
+
+ TP_ARGS(map, type, status),
+
+ TP_STRUCT__entry(
+ __string( name, regmap_name(map) )
+ __string( status, status )
+ __string( type, type )
+ __field( int, type )
+ ),
+
+ TP_fast_assign(
+ __assign_str(name, regmap_name(map));
+ __assign_str(status, status);
+ __assign_str(type, type);
+ ),
+
+ TP_printk("%s type=%s status=%s", __get_str(name),
+ __get_str(type), __get_str(status))
+);
+
+DECLARE_EVENT_CLASS(regmap_bool,
+
+ TP_PROTO(struct regmap *map, bool flag),
+
+ TP_ARGS(map, flag),
+
+ TP_STRUCT__entry(
+ __string( name, regmap_name(map) )
+ __field( int, flag )
+ ),
+
+ TP_fast_assign(
+ __assign_str(name, regmap_name(map));
+ __entry->flag = flag;
+ ),
+
+ TP_printk("%s flag=%d", __get_str(name),
+ (int)__entry->flag)
+);
+
+DEFINE_EVENT(regmap_bool, regmap_cache_only,
+
+ TP_PROTO(struct regmap *map, bool flag),
+
+ TP_ARGS(map, flag)
+
+);
+
+DEFINE_EVENT(regmap_bool, regmap_cache_bypass,
+
+ TP_PROTO(struct regmap *map, bool flag),
+
+ TP_ARGS(map, flag)
+
+);
+
+DECLARE_EVENT_CLASS(regmap_async,
+
+ TP_PROTO(struct regmap *map),
+
+ TP_ARGS(map),
+
+ TP_STRUCT__entry(
+ __string( name, regmap_name(map) )
+ ),
+
+ TP_fast_assign(
+ __assign_str(name, regmap_name(map));
+ ),
+
+ TP_printk("%s", __get_str(name))
+);
+
+DEFINE_EVENT(regmap_block, regmap_async_write_start,
+
+ TP_PROTO(struct regmap *map, unsigned int reg, int count),
+
+ TP_ARGS(map, reg, count)
+);
+
+DEFINE_EVENT(regmap_async, regmap_async_io_complete,
+
+ TP_PROTO(struct regmap *map),
+
+ TP_ARGS(map)
+
+);
+
+DEFINE_EVENT(regmap_async, regmap_async_complete_start,
+
+ TP_PROTO(struct regmap *map),
+
+ TP_ARGS(map)
+
+);
+
+DEFINE_EVENT(regmap_async, regmap_async_complete_done,
+
+ TP_PROTO(struct regmap *map),
+
+ TP_ARGS(map)
+
+);
+
+TRACE_EVENT(regcache_drop_region,
+
+ TP_PROTO(struct regmap *map, unsigned int from,
+ unsigned int to),
+
+ TP_ARGS(map, from, to),
+
+ TP_STRUCT__entry(
+ __string( name, regmap_name(map) )
+ __field( unsigned int, from )
+ __field( unsigned int, to )
+ ),
+
+ TP_fast_assign(
+ __assign_str(name, regmap_name(map));
+ __entry->from = from;
+ __entry->to = to;
+ ),
+
+ TP_printk("%s %u-%u", __get_str(name), (unsigned int)__entry->from,
+ (unsigned int)__entry->to)
+);
+
+#endif /* _TRACE_REGMAP_H */
+
+#undef TRACE_INCLUDE_PATH
+#define TRACE_INCLUDE_PATH .
+
+#undef TRACE_INCLUDE_FILE
+#define TRACE_INCLUDE_FILE trace
+
+/* This part must be outside protection */
+#include <trace/define_trace.h>
diff --git a/drivers/base/soc.c b/drivers/base/soc.c
index 72b5e7280d14..39fca01c8fa1 100644
--- a/drivers/base/soc.c
+++ b/drivers/base/soc.c
@@ -43,8 +43,8 @@ struct device *soc_device_to_device(struct soc_device *soc_dev)
}
static umode_t soc_attribute_mode(struct kobject *kobj,
- struct attribute *attr,
- int index)
+ struct attribute *attr,
+ int index)
{
struct device *dev = container_of(kobj, struct device, kobj);
struct soc_device *soc_dev = container_of(dev, struct soc_device, dev);
@@ -60,7 +60,7 @@ static umode_t soc_attribute_mode(struct kobject *kobj,
return attr->mode;
if ((attr == &dev_attr_soc_id.attr)
&& (soc_dev->attr->soc_id != NULL))
- return attr->mode;
+ return attr->mode;
/* Unknown or unfilled attribute. */
return 0;
@@ -117,7 +117,7 @@ struct soc_device *soc_device_register(struct soc_device_attribute *soc_dev_attr
soc_dev = kzalloc(sizeof(*soc_dev), GFP_KERNEL);
if (!soc_dev) {
- ret = -ENOMEM;
+ ret = -ENOMEM;
goto out1;
}
@@ -135,7 +135,7 @@ struct soc_device *soc_device_register(struct soc_device_attribute *soc_dev_attr
} while (ret == -EAGAIN);
if (ret)
- goto out2;
+ goto out2;
soc_dev->attr = soc_dev_attr;
soc_dev->dev.bus = &soc_bus_type;