Commit fe151462 authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'driver-core-5.10-rc1' of...

Merge tag 'driver-core-5.10-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 driver core patches for 5.10-rc1

  They include a lot of different things, all related to the driver core
  and/or some driver logic:

   - sysfs common write functions to make it easier to audit sysfs
     attributes

   - device connection cleanups and fixes

   - devm helpers for a few functions

   - NOIO allocations for when devices are being removed

   - minor cleanups and fixes

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

* tag 'driver-core-5.10-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/driver-core: (31 commits)
  regmap: debugfs: use semicolons rather than commas to separate statements
  platform/x86: intel_pmc_core: do not create a static struct device
  drivers core: node: Use a more typical macro definition style for ACCESS_ATTR
  drivers core: Use sysfs_emit for shared_cpu_map_show and shared_cpu_list_show
  mm: and drivers core: Convert hugetlb_report_node_meminfo to sysfs_emit
  drivers core: Miscellaneous changes for sysfs_emit
  drivers core: Reindent a couple uses around sysfs_emit
  drivers core: Remove strcat uses around sysfs_emit and neaten
  drivers core: Use sysfs_emit and sysfs_emit_at for show(device *...) functions
  sysfs: Add sysfs_emit and sysfs_emit_at to format sysfs output
  dyndbg: use keyword, arg varnames for query term pairs
  driver core: force NOIO allocations during unplug
  platform_device: switch to simpler IDA interface
  driver core: platform: Document return type of more functions
  Revert "driver core: Annotate dev_err_probe() with __must_check"
  Revert "test_firmware: Test platform fw loading on non-EFI systems"
  iio: adc: xilinx-xadc: use devm_krealloc()
  hwmon: pmbus: use more devres helpers
  devres: provide devm_krealloc()
  syscore: Use pm_pr_dbg() for syscore_{suspend,resume}()
  ...
parents 5d6c413c ee490677
==================
Device connections
==================
Introduction
------------
Devices often have connections to other devices that are outside of the direct
child/parent relationship. A serial or network communication controller, which
could be a PCI device, may need to be able to get a reference to its PHY
component, which could be attached for example to the I2C bus. Some device
drivers need to be able to control the clocks or the GPIOs for their devices,
and so on.
Device connections are generic descriptions of any type of connection between
two separate devices.
Device connections alone do not create a dependency between the two devices.
They are only descriptions which are not tied to either of the devices directly.
A dependency between the two devices exists only if one of the two endpoint
devices requests a reference to the other. The descriptions themselves can be
defined in firmware (not yet supported) or they can be built-in.
Usage
-----
Device connections should exist before device ``->probe`` callback is called for
either endpoint device in the description. If the connections are defined in
firmware, this is not a problem. It should be considered if the connection
descriptions are "built-in", and need to be added separately.
The connection description consists of the names of the two devices with the
connection, i.e. the endpoints, and unique identifier for the connection which
is needed if there are multiple connections between the two devices.
After a description exists, the devices in it can request reference to the other
endpoint device, or they can request the description itself.
API
---
.. kernel-doc:: drivers/base/devcon.c
:functions: device_connection_find_match device_connection_find device_connection_add device_connection_remove
...@@ -354,6 +354,7 @@ MEM ...@@ -354,6 +354,7 @@ MEM
devm_kmalloc() devm_kmalloc()
devm_kmalloc_array() devm_kmalloc_array()
devm_kmemdup() devm_kmemdup()
devm_krealloc()
devm_kstrdup() devm_kstrdup()
devm_kvasprintf() devm_kvasprintf()
devm_kzalloc() devm_kzalloc()
......
...@@ -42,6 +42,7 @@ fallback mechanism: ...@@ -42,6 +42,7 @@ fallback mechanism:
supported for request_firmware_into_buf(). supported for request_firmware_into_buf().
* Firmware is not accessible through typical means: * Firmware is not accessible through typical means:
* It cannot be installed into the root filesystem * It cannot be installed into the root filesystem
* The firmware provides very unique device specific data tailored for * The firmware provides very unique device specific data tailored for
the unit gathered with local information. An example is calibration the unit gathered with local information. An example is calibration
......
...@@ -22,7 +22,6 @@ available subsections can be seen below. ...@@ -22,7 +22,6 @@ available subsections can be seen below.
pm/index pm/index
clk clk
device-io device-io
device_connection
dma-buf dma-buf
device_link device_link
component component
......
...@@ -241,12 +241,10 @@ Other notes: ...@@ -241,12 +241,10 @@ Other notes:
is 4096. is 4096.
- show() methods should return the number of bytes printed into the - show() methods should return the number of bytes printed into the
buffer. This is the return value of scnprintf(). buffer.
- show() must not use snprintf() when formatting the value to be - show() should only use sysfs_emit() or sysfs_emit_at() when formatting
returned to user space. If you can guarantee that an overflow the value to be returned to user space.
will never happen you can use sprintf() otherwise you must use
scnprintf().
- store() should return the number of bytes used from the buffer. If the - store() should return the number of bytes used from the buffer. If the
entire buffer has been used, just return the count argument. entire buffer has been used, just return the count argument.
......
...@@ -5023,6 +5023,12 @@ S: Maintained ...@@ -5023,6 +5023,12 @@ S: Maintained
F: drivers/base/devcoredump.c F: drivers/base/devcoredump.c
F: include/linux/devcoredump.h F: include/linux/devcoredump.h
DEVICE DEPENDENCY HELPER SCRIPT
M: Saravana Kannan <saravanak@google.com>
L: linux-kernel@vger.kernel.org
S: Maintained
F: scripts/dev-needs.sh
DEVICE DIRECT ACCESS (DAX) DEVICE DIRECT ACCESS (DAX)
M: Dan Williams <dan.j.williams@intel.com> M: Dan Williams <dan.j.williams@intel.com>
M: Vishal Verma <vishal.l.verma@intel.com> M: Vishal Verma <vishal.l.verma@intel.com>
......
...@@ -6,7 +6,7 @@ obj-y := component.o core.o bus.o dd.o syscore.o \ ...@@ -6,7 +6,7 @@ obj-y := component.o core.o bus.o dd.o syscore.o \
cpu.o firmware.o init.o map.o devres.o \ cpu.o firmware.o init.o map.o devres.o \
attribute_container.o transport_class.o \ attribute_container.o transport_class.o \
topology.o container.o property.o cacheinfo.o \ topology.o container.o property.o cacheinfo.o \
devcon.o swnode.o swnode.o
obj-$(CONFIG_DEVTMPFS) += devtmpfs.o obj-$(CONFIG_DEVTMPFS) += devtmpfs.o
obj-y += power/ obj-y += power/
obj-$(CONFIG_ISA_BUS_API) += isa.o obj-$(CONFIG_ISA_BUS_API) += isa.o
......
...@@ -80,7 +80,7 @@ static ssize_t cpu_capacity_show(struct device *dev, ...@@ -80,7 +80,7 @@ static ssize_t cpu_capacity_show(struct device *dev,
{ {
struct cpu *cpu = container_of(dev, struct cpu, dev); struct cpu *cpu = container_of(dev, struct cpu, dev);
return sprintf(buf, "%lu\n", topology_get_cpu_scale(cpu->dev.id)); return sysfs_emit(buf, "%lu\n", topology_get_cpu_scale(cpu->dev.id));
} }
static void update_topology_flags_workfn(struct work_struct *work); static void update_topology_flags_workfn(struct work_struct *work);
......
...@@ -229,7 +229,7 @@ static DRIVER_ATTR_IGNORE_LOCKDEP(bind, S_IWUSR, NULL, bind_store); ...@@ -229,7 +229,7 @@ static DRIVER_ATTR_IGNORE_LOCKDEP(bind, S_IWUSR, NULL, bind_store);
static ssize_t drivers_autoprobe_show(struct bus_type *bus, char *buf) static ssize_t drivers_autoprobe_show(struct bus_type *bus, char *buf)
{ {
return sprintf(buf, "%d\n", bus->p->drivers_autoprobe); return sysfs_emit(buf, "%d\n", bus->p->drivers_autoprobe);
} }
static ssize_t drivers_autoprobe_store(struct bus_type *bus, static ssize_t drivers_autoprobe_store(struct bus_type *bus,
......
...@@ -362,7 +362,7 @@ static ssize_t file_name##_show(struct device *dev, \ ...@@ -362,7 +362,7 @@ static ssize_t file_name##_show(struct device *dev, \
struct device_attribute *attr, char *buf) \ struct device_attribute *attr, char *buf) \
{ \ { \
struct cacheinfo *this_leaf = dev_get_drvdata(dev); \ struct cacheinfo *this_leaf = dev_get_drvdata(dev); \
return sprintf(buf, "%u\n", this_leaf->object); \ return sysfs_emit(buf, "%u\n", this_leaf->object); \
} }
show_one(id, id); show_one(id, id);
...@@ -377,44 +377,48 @@ static ssize_t size_show(struct device *dev, ...@@ -377,44 +377,48 @@ static ssize_t size_show(struct device *dev,
{ {
struct cacheinfo *this_leaf = dev_get_drvdata(dev); struct cacheinfo *this_leaf = dev_get_drvdata(dev);
return sprintf(buf, "%uK\n", this_leaf->size >> 10); return sysfs_emit(buf, "%uK\n", this_leaf->size >> 10);
} }
static ssize_t shared_cpumap_show_func(struct device *dev, bool list, char *buf) static ssize_t shared_cpu_map_show(struct device *dev,
struct device_attribute *attr, char *buf)
{ {
struct cacheinfo *this_leaf = dev_get_drvdata(dev); struct cacheinfo *this_leaf = dev_get_drvdata(dev);
const struct cpumask *mask = &this_leaf->shared_cpu_map; const struct cpumask *mask = &this_leaf->shared_cpu_map;
return cpumap_print_to_pagebuf(list, buf, mask); return sysfs_emit(buf, "%*pb\n", nr_cpu_ids, mask);
}
static ssize_t shared_cpu_map_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
return shared_cpumap_show_func(dev, false, buf);
} }
static ssize_t shared_cpu_list_show(struct device *dev, static ssize_t shared_cpu_list_show(struct device *dev,
struct device_attribute *attr, char *buf) struct device_attribute *attr, char *buf)
{ {
return shared_cpumap_show_func(dev, true, buf); struct cacheinfo *this_leaf = dev_get_drvdata(dev);
const struct cpumask *mask = &this_leaf->shared_cpu_map;
return sysfs_emit(buf, "%*pbl\n", nr_cpu_ids, mask);
} }
static ssize_t type_show(struct device *dev, static ssize_t type_show(struct device *dev,
struct device_attribute *attr, char *buf) struct device_attribute *attr, char *buf)
{ {
struct cacheinfo *this_leaf = dev_get_drvdata(dev); struct cacheinfo *this_leaf = dev_get_drvdata(dev);
const char *output;
switch (this_leaf->type) { switch (this_leaf->type) {
case CACHE_TYPE_DATA: case CACHE_TYPE_DATA:
return sprintf(buf, "Data\n"); output = "Data";
break;
case CACHE_TYPE_INST: case CACHE_TYPE_INST:
return sprintf(buf, "Instruction\n"); output = "Instruction";
break;
case CACHE_TYPE_UNIFIED: case CACHE_TYPE_UNIFIED:
return sprintf(buf, "Unified\n"); output = "Unified";
break;
default: default:
return -EINVAL; return -EINVAL;
} }
return sysfs_emit(buf, "%s\n", output);
} }
static ssize_t allocation_policy_show(struct device *dev, static ssize_t allocation_policy_show(struct device *dev,
...@@ -422,15 +426,18 @@ static ssize_t allocation_policy_show(struct device *dev, ...@@ -422,15 +426,18 @@ static ssize_t allocation_policy_show(struct device *dev,
{ {
struct cacheinfo *this_leaf = dev_get_drvdata(dev); struct cacheinfo *this_leaf = dev_get_drvdata(dev);
unsigned int ci_attr = this_leaf->attributes; unsigned int ci_attr = this_leaf->attributes;
int n = 0; const char *output;
if ((ci_attr & CACHE_READ_ALLOCATE) && (ci_attr & CACHE_WRITE_ALLOCATE)) if ((ci_attr & CACHE_READ_ALLOCATE) && (ci_attr & CACHE_WRITE_ALLOCATE))
n = sprintf(buf, "ReadWriteAllocate\n"); output = "ReadWriteAllocate";
else if (ci_attr & CACHE_READ_ALLOCATE) else if (ci_attr & CACHE_READ_ALLOCATE)
n = sprintf(buf, "ReadAllocate\n"); output = "ReadAllocate";
else if (ci_attr & CACHE_WRITE_ALLOCATE) else if (ci_attr & CACHE_WRITE_ALLOCATE)
n = sprintf(buf, "WriteAllocate\n"); output = "WriteAllocate";
return n; else
return 0;
return sysfs_emit(buf, "%s\n", output);
} }
static ssize_t write_policy_show(struct device *dev, static ssize_t write_policy_show(struct device *dev,
...@@ -441,9 +448,9 @@ static ssize_t write_policy_show(struct device *dev, ...@@ -441,9 +448,9 @@ static ssize_t write_policy_show(struct device *dev,
int n = 0; int n = 0;
if (ci_attr & CACHE_WRITE_THROUGH) if (ci_attr & CACHE_WRITE_THROUGH)
n = sprintf(buf, "WriteThrough\n"); n = sysfs_emit(buf, "WriteThrough\n");
else if (ci_attr & CACHE_WRITE_BACK) else if (ci_attr & CACHE_WRITE_BACK)
n = sprintf(buf, "WriteBack\n"); n = sysfs_emit(buf, "WriteBack\n");
return n; return n;
} }
......
...@@ -478,7 +478,7 @@ ssize_t show_class_attr_string(struct class *class, ...@@ -478,7 +478,7 @@ ssize_t show_class_attr_string(struct class *class,
struct class_attribute_string *cs; struct class_attribute_string *cs;
cs = container_of(attr, struct class_attribute_string, attr); cs = container_of(attr, struct class_attribute_string, attr);
return snprintf(buf, PAGE_SIZE, "%s\n", cs->str); return sysfs_emit(buf, "%s\n", cs->str);
} }
EXPORT_SYMBOL_GPL(show_class_attr_string); EXPORT_SYMBOL_GPL(show_class_attr_string);
......
...@@ -26,6 +26,7 @@ ...@@ -26,6 +26,7 @@
#include <linux/pm_runtime.h> #include <linux/pm_runtime.h>
#include <linux/netdevice.h> #include <linux/netdevice.h>
#include <linux/sched/signal.h> #include <linux/sched/signal.h>
#include <linux/sched/mm.h>
#include <linux/sysfs.h> #include <linux/sysfs.h>
#include "base.h" #include "base.h"
...@@ -239,27 +240,35 @@ void device_pm_move_to_tail(struct device *dev) ...@@ -239,27 +240,35 @@ void device_pm_move_to_tail(struct device *dev)
#define to_devlink(dev) container_of((dev), struct device_link, link_dev) #define to_devlink(dev) container_of((dev), struct device_link, link_dev)
static ssize_t status_show(struct device *dev, static ssize_t status_show(struct device *dev,
struct device_attribute *attr, char *buf) struct device_attribute *attr, char *buf)
{ {
char *status; const char *output;
switch (to_devlink(dev)->status) { switch (to_devlink(dev)->status) {
case DL_STATE_NONE: case DL_STATE_NONE:
status = "not tracked"; break; output = "not tracked";
break;
case DL_STATE_DORMANT: case DL_STATE_DORMANT:
status = "dormant"; break; output = "dormant";
break;
case DL_STATE_AVAILABLE: case DL_STATE_AVAILABLE:
status = "available"; break; output = "available";
break;
case DL_STATE_CONSUMER_PROBE: case DL_STATE_CONSUMER_PROBE:
status = "consumer probing"; break; output = "consumer probing";
break;
case DL_STATE_ACTIVE: case DL_STATE_ACTIVE:
status = "active"; break; output = "active";
break;
case DL_STATE_SUPPLIER_UNBIND: case DL_STATE_SUPPLIER_UNBIND:
status = "supplier unbinding"; break; output = "supplier unbinding";
break;
default: default:
status = "unknown"; break; output = "unknown";
break;
} }
return sprintf(buf, "%s\n", status);
return sysfs_emit(buf, "%s\n", output);
} }
static DEVICE_ATTR_RO(status); static DEVICE_ATTR_RO(status);
...@@ -267,16 +276,16 @@ static ssize_t auto_remove_on_show(struct device *dev, ...@@ -267,16 +276,16 @@ static ssize_t auto_remove_on_show(struct device *dev,
struct device_attribute *attr, char *buf) struct device_attribute *attr, char *buf)
{ {
struct device_link *link = to_devlink(dev); struct device_link *link = to_devlink(dev);
char *str; const char *output;
if (link->flags & DL_FLAG_AUTOREMOVE_SUPPLIER) if (link->flags & DL_FLAG_AUTOREMOVE_SUPPLIER)
str = "supplier unbind"; output = "supplier unbind";
else if (link->flags & DL_FLAG_AUTOREMOVE_CONSUMER) else if (link->flags & DL_FLAG_AUTOREMOVE_CONSUMER)
str = "consumer unbind"; output = "consumer unbind";
else else
str = "never"; output = "never";
return sprintf(buf, "%s\n", str); return sysfs_emit(buf, "%s\n", output);
} }
static DEVICE_ATTR_RO(auto_remove_on); static DEVICE_ATTR_RO(auto_remove_on);
...@@ -285,7 +294,7 @@ static ssize_t runtime_pm_show(struct device *dev, ...@@ -285,7 +294,7 @@ static ssize_t runtime_pm_show(struct device *dev,
{ {
struct device_link *link = to_devlink(dev); struct device_link *link = to_devlink(dev);
return sprintf(buf, "%d\n", !!(link->flags & DL_FLAG_PM_RUNTIME)); return sysfs_emit(buf, "%d\n", !!(link->flags & DL_FLAG_PM_RUNTIME));
} }
static DEVICE_ATTR_RO(runtime_pm); static DEVICE_ATTR_RO(runtime_pm);
...@@ -294,7 +303,8 @@ static ssize_t sync_state_only_show(struct device *dev, ...@@ -294,7 +303,8 @@ static ssize_t sync_state_only_show(struct device *dev,
{ {
struct device_link *link = to_devlink(dev); struct device_link *link = to_devlink(dev);
return sprintf(buf, "%d\n", !!(link->flags & DL_FLAG_SYNC_STATE_ONLY)); return sysfs_emit(buf, "%d\n",
!!(link->flags & DL_FLAG_SYNC_STATE_ONLY));
} }
static DEVICE_ATTR_RO(sync_state_only); static DEVICE_ATTR_RO(sync_state_only);
...@@ -1059,7 +1069,7 @@ static ssize_t waiting_for_supplier_show(struct device *dev, ...@@ -1059,7 +1069,7 @@ static ssize_t waiting_for_supplier_show(struct device *dev,
&& dev->links.need_for_probe; && dev->links.need_for_probe;
mutex_unlock(&wfs_lock); mutex_unlock(&wfs_lock);
device_unlock(dev); device_unlock(dev);
return sprintf(buf, "%u\n", val); return sysfs_emit(buf, "%u\n", val);
} }
static DEVICE_ATTR_RO(waiting_for_supplier); static DEVICE_ATTR_RO(waiting_for_supplier);
...@@ -1709,7 +1719,7 @@ ssize_t device_show_ulong(struct device *dev, ...@@ -1709,7 +1719,7 @@ ssize_t device_show_ulong(struct device *dev,
char *buf) char *buf)
{ {
struct dev_ext_attribute *ea = to_ext_attr(attr); struct dev_ext_attribute *ea = to_ext_attr(attr);
return snprintf(buf, PAGE_SIZE, "%lx\n", *(unsigned long *)(ea->var)); return sysfs_emit(buf, "%lx\n", *(unsigned long *)(ea->var));
} }
EXPORT_SYMBOL_GPL(device_show_ulong); EXPORT_SYMBOL_GPL(device_show_ulong);
...@@ -1739,7 +1749,7 @@ ssize_t device_show_int(struct device *dev, ...@@ -1739,7 +1749,7 @@ ssize_t device_show_int(struct device *dev,
{ {
struct dev_ext_attribute *ea = to_ext_attr(attr); struct dev_ext_attribute *ea = to_ext_attr(attr);
return snprintf(buf, PAGE_SIZE, "%d\n", *(int *)(ea->var)); return sysfs_emit(buf, "%d\n", *(int *)(ea->var));
} }
EXPORT_SYMBOL_GPL(device_show_int); EXPORT_SYMBOL_GPL(device_show_int);
...@@ -1760,7 +1770,7 @@ ssize_t device_show_bool(struct device *dev, struct device_attribute *attr, ...@@ -1760,7 +1770,7 @@ ssize_t device_show_bool(struct device *dev, struct device_attribute *attr,
{ {
struct dev_ext_attribute *ea = to_ext_attr(attr); struct dev_ext_attribute *ea = to_ext_attr(attr);
return snprintf(buf, PAGE_SIZE, "%d\n", *(bool *)(ea->var)); return sysfs_emit(buf, "%d\n", *(bool *)(ea->var));
} }
EXPORT_SYMBOL_GPL(device_show_bool); EXPORT_SYMBOL_GPL(device_show_bool);
...@@ -1932,7 +1942,7 @@ static ssize_t uevent_show(struct device *dev, struct device_attribute *attr, ...@@ -1932,7 +1942,7 @@ static ssize_t uevent_show(struct device *dev, struct device_attribute *attr,
struct kset *kset; struct kset *kset;
struct kobj_uevent_env *env = NULL; struct kobj_uevent_env *env = NULL;
int i; int i;
size_t count = 0; int len = 0;
int retval; int retval;
/* search the kset, the device belongs to */ /* search the kset, the device belongs to */
...@@ -1962,10 +1972,10 @@ static ssize_t uevent_show(struct device *dev, struct device_attribute *attr, ...@@ -1962,10 +1972,10 @@ static ssize_t uevent_show(struct device *dev, struct device_attribute *attr,
/* copy keys to file */ /* copy keys to file */
for (i = 0; i < env->envp_idx; i++) for (i = 0; i < env->envp_idx; i++)
count += sprintf(&buf[count], "%s\n", env->envp[i]); len += sysfs_emit_at(buf, len, "%s\n", env->envp[i]);
out: out:
kfree(env); kfree(env);
return count; return len;
} }
static ssize_t uevent_store(struct device *dev, struct device_attribute *attr, static ssize_t uevent_store(struct device *dev, struct device_attribute *attr,
...@@ -1992,7 +2002,7 @@ static ssize_t online_show(struct device *dev, struct device_attribute *attr, ...@@ -1992,7 +2002,7 @@ static ssize_t online_show(struct device *dev, struct device_attribute *attr,
device_lock(dev); device_lock(dev);
val = !dev->offline; val = !dev->offline;
device_unlock(dev); device_unlock(dev);
return sprintf(buf, "%u\n", val); return sysfs_emit(buf, "%u\n", val);
} }
static ssize_t online_store(struct device *dev, struct device_attribute *attr, static ssize_t online_store(struct device *dev, struct device_attribute *attr,
...@@ -3062,6 +3072,7 @@ void device_del(struct device *dev) ...@@ -3062,6 +3072,7 @@ void device_del(struct device *dev)
struct device *parent = dev->parent; struct device *parent = dev->parent;
struct kobject *glue_dir = NULL; struct kobject *glue_dir = NULL;
struct class_interface *class_intf; struct class_interface *class_intf;
unsigned int noio_flag;
device_lock(dev); device_lock(dev);
kill_device(dev); kill_device(dev);
...@@ -3073,6 +3084,7 @@ void device_del(struct device *dev) ...@@ -3073,6 +3084,7 @@ void device_del(struct device *dev)
/* Notify clients of device removal. This call must come /* Notify clients of device removal. This call must come
* before dpm_sysfs_remove(). * before dpm_sysfs_remove().
*/ */
noio_flag = memalloc_noio_save();
if (dev->bus) if (dev->bus)
blocking_notifier_call_chain(&dev->bus->p->bus_notifier, blocking_notifier_call_chain(&dev->bus->p->bus_notifier,
BUS_NOTIFY_DEL_DEVICE, dev); BUS_NOTIFY_DEL_DEVICE, dev);
...@@ -3114,6 +3126,7 @@ void device_del(struct device *dev) ...@@ -3114,6 +3126,7 @@ void device_del(struct device *dev)
glue_dir = get_glue_dir(dev); glue_dir = get_glue_dir(dev);
kobject_del(&dev->kobj); kobject_del(&dev->kobj);
cleanup_glue_dir(dev, glue_dir); cleanup_glue_dir(dev, glue_dir);
memalloc_noio_restore(noio_flag);
put_device(parent); put_device(parent);
} }
EXPORT_SYMBOL_GPL(device_del); EXPORT_SYMBOL_GPL(device_del);
......
...@@ -139,11 +139,11 @@ EXPORT_SYMBOL_GPL(cpu_subsys); ...@@ -139,11 +139,11 @@ EXPORT_SYMBOL_GPL(cpu_subsys);
#ifdef CONFIG_KEXEC #ifdef CONFIG_KEXEC
#include <linux/kexec.h> #include <linux/kexec.h>
static ssize_t show_crash_notes(struct device *dev, struct device_attribute *attr, static ssize_t crash_notes_show(struct device *dev,
struct device_attribute *attr,
char *buf) char *buf)
{ {
struct cpu *cpu = container_of(dev, struct cpu, dev); struct cpu *cpu = container_of(dev, struct cpu, dev);
ssize_t rc;
unsigned long long addr; unsigned long long addr;
int cpunum; int cpunum;
...@@ -156,21 +156,18 @@ static ssize_t show_crash_notes(struct device *dev, struct device_attribute *att ...@@ -156,21 +156,18 @@ static ssize_t show_crash_notes(struct device *dev, struct device_attribute *att
* operation should be safe. No locking required. * operation should be safe. No locking required.
*/ */
addr = per_cpu_ptr_to_phys(per_cpu_ptr(crash_notes, cpunum)); addr = per_cpu_ptr_to_phys(per_cpu_ptr(crash_notes, cpunum));
rc = sprintf(buf, "%Lx\n", addr);
return rc; return sysfs_emit(buf, "%llx\n", addr);
} }
static DEVICE_ATTR(crash_notes, 0400, show_crash_notes, NULL); static DEVICE_ATTR_ADMIN_RO(crash_notes);
static ssize_t show_crash_notes_size(struct device *dev, static ssize_t crash_notes_size_show(struct device *dev,
struct device_attribute *attr, struct device_attribute *attr,
char *buf) char *buf)
{ {
ssize_t rc; return sysfs_emit(buf, "%zu\n", sizeof(note_buf_t));
rc = sprintf(buf, "%zu\n", sizeof(note_buf_t));
return rc;
} }
static DEVICE_ATTR(crash_notes_size, 0400, show_crash_notes_size, NULL); static DEVICE_ATTR_ADMIN_RO(crash_notes_size);
static struct attribute *crash_note_cpu_attrs[] = { static struct attribute *crash_note_cpu_attrs[] = {
&dev_attr_crash_notes.attr, &dev_attr_crash_notes.attr,
...@@ -231,7 +228,7 @@ static struct cpu_attr cpu_attrs[] = { ...@@ -231,7 +228,7 @@ static struct cpu_attr cpu_attrs[] = {
static ssize_t print_cpus_kernel_max(struct device *dev, static ssize_t print_cpus_kernel_max(struct device *dev,
struct device_attribute *attr, char *buf) struct device_attribute *attr, char *buf)
{ {
return sprintf(buf, "%d\n", NR_CPUS - 1); return sysfs_emit(buf, "%d\n", NR_CPUS - 1);
} }
static DEVICE_ATTR(kernel_max, 0444, print_cpus_kernel_max, NULL); static DEVICE_ATTR(kernel_max, 0444, print_cpus_kernel_max, NULL);
...@@ -241,37 +238,37 @@ unsigned int total_cpus; ...@@ -241,37 +238,37 @@ unsigned int total_cpus;
static ssize_t print_cpus_offline(struct device *dev, static ssize_t print_cpus_offline(struct device *dev,
struct device_attribute *attr, char *buf) struct device_attribute *attr, char *buf)
{ {
int n = 0, len = PAGE_SIZE-2; int len = 0;
cpumask_var_t offline; cpumask_var_t offline;
/* display offline cpus < nr_cpu_ids */ /* display offline cpus < nr_cpu_ids */
if (!alloc_cpumask_var(&offline, GFP_KERNEL)) if (!alloc_cpumask_var(&offline, GFP_KERNEL))
return -ENOMEM; return -ENOMEM;
cpumask_andnot(offline, cpu_possible_mask, cpu_online_mask); cpumask_andnot(offline, cpu_possible_mask, cpu_online_mask);
n = scnprintf(buf, len, "%*pbl", cpumask_pr_args(offline)); len += sysfs_emit_at(buf, len, "%*pbl", cpumask_pr_args(offline));
free_cpumask_var(offline); free_cpumask_var(offline);
/* display offline cpus >= nr_cpu_ids */ /* display offline cpus >= nr_cpu_ids */
if (total_cpus && nr_cpu_ids < total_cpus) { if (total_cpus && nr_cpu_ids < total_cpus) {
if (n && n < len) len += sysfs_emit_at(buf, len, ",");
buf[n++] = ',';
if (nr_cpu_ids == total_cpus-1) if (nr_cpu_ids == total_cpus-1)
n += scnprintf(&buf[n], len - n, "%u", nr_cpu_ids); len += sysfs_emit_at(buf, len, "%u", nr_cpu_ids);
else else
n += scnprintf(&buf[n], len - n, "%u-%d", len += sysfs_emit_at(buf, len, "%u-%d",
nr_cpu_ids, total_cpus-1); nr_cpu_ids, total_cpus - 1);
} }
n += scnprintf(&buf[n], len - n, "\n"); len += sysfs_emit_at(buf, len, "\n");
return n;
return len;
} }
static DEVICE_ATTR(offline, 0444, print_cpus_offline, NULL); static DEVICE_ATTR(offline, 0444, print_cpus_offline, NULL);
static ssize_t print_cpus_isolated(struct device *dev, static ssize_t print_cpus_isolated(struct device *dev,
struct device_attribute *attr, char *buf) struct device_attribute *attr, char *buf)
{ {
int n; int len;
cpumask_var_t isolated; cpumask_var_t isolated;
if (!alloc_cpumask_var(&isolated, GFP_KERNEL)) if (!alloc_cpumask_var(&isolated, GFP_KERNEL))
...@@ -279,19 +276,19 @@ static ssize_t print_cpus_isolated(struct device *dev, ...@@ -279,19 +276,19 @@ static ssize_t print_cpus_isolated(struct device *dev,
cpumask_andnot(isolated, cpu_possible_mask, cpumask_andnot(isolated, cpu_possible_mask,
housekeeping_cpumask(HK_FLAG_DOMAIN)); housekeeping_cpumask(HK_FLAG_DOMAIN));
n = sprintf(buf, "%*pbl\n", cpumask_pr_args(isolated)); len = sysfs_emit(buf, "%*pbl\n", cpumask_pr_args(isolated));
free_cpumask_var(isolated); free_cpumask_var(isolated);
return n; return len;
} }
static DEVICE_ATTR(isolated, 0444, print_cpus_isolated, NULL); static DEVICE_ATTR(isolated, 0444, print_cpus_isolated, NULL);
#ifdef CONFIG_NO_HZ_FULL #ifdef CONFIG_NO_HZ_FULL
static ssize_t print_cpus_nohz_full(struct device *dev, static ssize_t print_cpus_nohz_full(struct device *dev,
struct device_attribute *attr, char *buf) struct device_attribute *attr, char *buf)
{ {
return sprintf(buf, "%*pbl\n", cpumask_pr_args(tick_nohz_full_mask)); return sysfs_emit(buf, "%*pbl\n", cpumask_pr_args(tick_nohz_full_mask));
} }
static DEVICE_ATTR(nohz_full, 0444, print_cpus_nohz_full, NULL); static DEVICE_ATTR(nohz_full, 0444, print_cpus_nohz_full, NULL);
#endif #endif
...@@ -320,22 +317,23 @@ static ssize_t print_cpu_modalias(struct device *dev, ...@@ -320,22 +317,23 @@ static ssize_t print_cpu_modalias(struct device *dev,
struct device_attribute *attr, struct device_attribute *attr,
char *buf) char *buf)
{ {
ssize_t n; int len = 0;
u32 i; u32 i;
n = sprintf(buf, "cpu:type:" CPU_FEATURE_TYPEFMT ":feature:", len += sysfs_emit_at(buf, len,
CPU_FEATURE_TYPEVAL); "cpu:type:" CPU_FEATURE_TYPEFMT ":feature:",
CPU_FEATURE_TYPEVAL);
for (i = 0; i < MAX_CPU_FEATURES; i++) for (i = 0; i < MAX_CPU_FEATURES; i++)
if (cpu_have_feature(i)) { if (cpu_have_feature(i)) {
if (PAGE_SIZE < n + sizeof(",XXXX\n")) { if (len + sizeof(",XXXX\n") >= PAGE_SIZE) {
WARN(1, "CPU features overflow page\n"); WARN(1, "CPU features overflow page\n");
break; break;
} }
n += sprintf(&buf[n], ",%04X", i); len += sysfs_emit_at(buf, len, ",%04X", i);
} }
buf[n++] = '\n'; len += sysfs_emit_at(buf, len, "\n");
return n; return len;
} }
static int cpu_uevent(struct device *dev, struct kobj_uevent_env *env) static int cpu_uevent(struct device *dev, struct kobj_uevent_env *env)
...@@ -516,56 +514,56 @@ static void __init cpu_dev_register_generic(void) ...@@ -516,56 +514,56 @@ static void __init cpu_dev_register_generic(void)
ssize_t __weak cpu_show_meltdown(struct device *dev, ssize_t __weak cpu_show_meltdown(struct device *dev,
struct device_attribute *attr, char *buf) struct device_attribute *attr, char *buf)
{ {
return sprintf(buf, "Not affected\n"); return sysfs_emit(buf, "Not affected\n");
} }
ssize_t __weak cpu_show_spectre_v1(struct device *dev, ssize_t __weak cpu_show_spectre_v1(struct device *dev,
struct device_attribute *attr, char *buf) struct device_attribute *attr, char *buf)
{ {
return sprintf(buf, "Not affected\n"); return sysfs_emit(buf, "Not affected\n");
} }
ssize_t __weak cpu_show_spectre_v2(struct device *dev, ssize_t __weak cpu_show_spectre_v2(struct device *dev,
struct device_attribute *attr, char *buf) struct device_attribute *attr, char *buf)
{ {
return sprintf(buf, "Not affected\n"); return sysfs_emit(buf, "Not affected\n");
} }
ssize_t __weak cpu_show_spec_store_bypass(struct device *dev, ssize_t __weak cpu_show_spec_store_bypass(struct device *dev,
struct device_attribute *attr, char *buf) struct device_attribute *attr, char *buf)
{ {
return sprintf(buf, "Not affected\n"); return sysfs_emit(buf, "Not affected\n");
} }
ssize_t __weak cpu_show_l1tf(struct device *dev, ssize_t __weak cpu_show_l1tf(struct device *dev,
struct device_attribute *attr, char *buf) struct device_attribute *attr, char *buf)
{ {
return sprintf(buf, "Not affected\n"); return sysfs_emit(buf, "Not affected\n");
} }
ssize_t __weak cpu_show_mds(struct device *dev, ssize_t __weak cpu_show_mds(struct device *dev,
struct device_attribute *attr, char *buf) struct device_attribute *attr, char *buf)
{ {
return sprintf(buf, "Not affected\n"); return sysfs_emit(buf, "Not affected\n");
} }
ssize_t __weak cpu_show_tsx_async_abort(struct device *dev, ssize_t __weak cpu_show_tsx_async_abort(struct device *dev,
struct device_attribute *attr, struct device_attribute *attr,
char *buf) char *buf)
{ {
return sprintf(buf, "Not affected\n"); return sysfs_emit(buf, "Not affected\n");
} }
ssize_t __weak cpu_show_itlb_multihit(struct device *dev, ssize_t __weak cpu_show_itlb_multihit(struct device *dev,
struct device_attribute *attr, char *buf) struct device_attribute *attr, char *buf)
{ {
return sprintf(buf, "Not affected\n"); return sysfs_emit(buf, "Not affected\n");
} }
ssize_t __weak cpu_show_srbds(struct device *dev, ssize_t __weak cpu_show_srbds(struct device *dev,
struct device_attribute *attr, char *buf) struct device_attribute *attr, char *buf)
{ {
return sprintf(buf, "Not affected\n"); return sysfs_emit(buf, "Not affected\n");
} }
static DEVICE_ATTR(meltdown, 0444, cpu_show_meltdown, NULL); static DEVICE_ATTR(meltdown, 0444, cpu_show_meltdown, NULL);
......
...@@ -486,7 +486,8 @@ static ssize_t state_synced_show(struct device *dev, ...@@ -486,7 +486,8 @@ static ssize_t state_synced_show(struct device *dev,
device_lock(dev); device_lock(dev);
val = dev->state_synced; val = dev->state_synced;
device_unlock(dev); device_unlock(dev);
return sprintf(buf, "%u\n", val);
return sysfs_emit(buf, "%u\n", val);
} }
static DEVICE_ATTR_RO(state_synced); static DEVICE_ATTR_RO(state_synced);
...@@ -658,15 +659,14 @@ static int really_probe(struct device *dev, struct device_driver *drv) ...@@ -658,15 +659,14 @@ static int really_probe(struct device *dev, struct device_driver *drv)
*/ */
static int really_probe_debug(struct device *dev, struct device_driver *drv) static int really_probe_debug(struct device *dev, struct device_driver *drv)
{ {
ktime_t calltime, delta, rettime; ktime_t calltime, rettime;
int ret; int ret;
calltime = ktime_get(); calltime = ktime_get();
ret = really_probe(dev, drv); ret = really_probe(dev, drv);
rettime = ktime_get(); rettime = ktime_get();
delta = ktime_sub(rettime, calltime);
pr_debug("probe of %s returned %d after %lld usecs\n", pr_debug("probe of %s returned %d after %lld usecs\n",
dev_name(dev), ret, (s64) ktime_to_us(delta)); dev_name(dev), ret, ktime_us_delta(rettime, calltime));
return ret; return ret;
} }
......
// SPDX-License-Identifier: GPL-2.0
/**
* Device connections
*
* Copyright (C) 2018 Intel Corporation
* Author: Heikki Krogerus <heikki.krogerus@linux.intel.com>
*/
#include <linux/device.h>
#include <linux/property.h>
static DEFINE_MUTEX(devcon_lock);
static LIST_HEAD(devcon_list);
static void *
fwnode_graph_devcon_match(struct fwnode_handle *fwnode, const char *con_id,
void *data, devcon_match_fn_t match)
{
struct device_connection con = { .id = con_id };
struct fwnode_handle *ep;
void *ret;
fwnode_graph_for_each_endpoint(fwnode, ep) {
con.fwnode = fwnode_graph_get_remote_port_parent(ep);
if (!fwnode_device_is_available(con.fwnode))
continue;
ret = match(&con, -1, data);
fwnode_handle_put(con.fwnode);
if (ret) {
fwnode_handle_put(ep);
return ret;
}
}
return NULL;
}
static void *
fwnode_devcon_match(struct fwnode_handle *fwnode, const char *con_id,
void *data, devcon_match_fn_t match)
{
struct device_connection con = { };
void *ret;
int i;
for (i = 0; ; i++) {
con.fwnode = fwnode_find_reference(fwnode, con_id, i);
if (IS_ERR(con.fwnode))
break;
ret = match(&con, -1, data);
fwnode_handle_put(con.fwnode);
if (ret)
return ret;
}
return NULL;
}
/**
* fwnode_connection_find_match - Find connection from a device node
* @fwnode: Device node with the connection
* @con_id: Identifier for the connection
* @data: Data for the match function
* @match: Function to check and convert the connection description
*
* Find a connection with unique identifier @con_id between @fwnode and another
* device node. @match will be used to convert the connection description to
* data the caller is expecting to be returned.
*/
void *fwnode_connection_find_match(struct fwnode_handle *fwnode,
const char *con_id, void *data,
devcon_match_fn_t match)
{
void *ret;
if (!fwnode || !match)
return NULL;
ret = fwnode_graph_devcon_match(fwnode, con_id, data, match);
if (ret)
return ret;
return fwnode_devcon_match(fwnode, con_id, data, match);
}
EXPORT_SYMBOL_GPL(fwnode_connection_find_match);
/**
* device_connection_find_match - Find physical connection to a device
* @dev: Device with the connection
* @con_id: Identifier for the connection
* @data: Data for the match function
* @match: Function to check and convert the connection description
*
* Find a connection with unique identifier @con_id between @dev and another
* device. @match will be used to convert the connection description to data the
* caller is expecting to be returned.
*/
void *device_connection_find_match(struct device *dev, const char *con_id,
void *data, devcon_match_fn_t match)
{
struct fwnode_handle *fwnode = dev_fwnode(dev);
const char *devname = dev_name(dev);
struct device_connection *con;
void *ret = NULL;
int ep;
if (!match)
return NULL;
ret = fwnode_connection_find_match(fwnode, con_id, data, match);
if (ret)
return ret;
mutex_lock(&devcon_lock);
list_for_each_entry(con, &devcon_list, list) {
ep = match_string(con->endpoint, 2, devname);
if (ep < 0)
continue;
if (con_id && strcmp(con->id, con_id))
continue;
ret = match(con, !ep, data);
if (ret)
break;
}
mutex_unlock(&devcon_lock);
return ret;
}
EXPORT_SYMBOL_GPL(device_connection_find_match);
extern struct bus_type platform_bus_type;
extern struct bus_type pci_bus_type;
extern struct bus_type i2c_bus_type;
extern struct bus_type spi_bus_type;
static struct bus_type *generic_match_buses[] = {
&platform_bus_type,
#ifdef CONFIG_PCI
&pci_bus_type,
#endif
#ifdef CONFIG_I2C
&i2c_bus_type,
#endif
#ifdef CONFIG_SPI_MASTER
&spi_bus_type,
#endif
NULL,
};
static void *device_connection_fwnode_match(struct device_connection *con)
{
struct bus_type *bus;
struct device *dev;
for (bus = generic_match_buses[0]; bus; bus++) {
dev = bus_find_device_by_fwnode(bus, con->fwnode);
if (dev && !strncmp(dev_name(dev), con->id, strlen(con->id)))
return dev;
put_device(dev);
}
return NULL;
}
/* This tries to find the device from the most common bus types by name. */
static void *generic_match(struct device_connection *con, int ep, void *data)
{
struct bus_type *bus;
struct device *dev;
if (con->fwnode)
return device_connection_fwnode_match(con);
for (bus = generic_match_buses[0]; bus; bus++) {
dev = bus_find_device_by_name(bus, NULL, con->endpoint[ep]);
if (dev)
return dev;
}
/*
* We only get called if a connection was found, tell the caller to
* wait for the other device to show up.
*/
return ERR_PTR(-EPROBE_DEFER);
}
/**
* device_connection_find - Find two devices connected together
* @dev: Device with the connection
* @con_id: Identifier for the connection
*
* Find a connection with unique identifier @con_id between @dev and
* another device. On success returns handle to the device that is connected
* to @dev, with the reference count for the found device incremented. Returns
* NULL if no matching connection was found, or ERR_PTR(-EPROBE_DEFER) when a
* connection was found but the other device has not been enumerated yet.
*/
struct device *device_connection_find(struct device *dev, const char *con_id)
{
return device_connection_find_match(dev, con_id, NULL, generic_match);
}
EXPORT_SYMBOL_GPL(device_connection_find);
/**
* device_connection_add - Register a connection description
* @con: The connection description to be registered
*/
void device_connection_add(struct device_connection *con)
{
mutex_lock(&devcon_lock);
list_add_tail(&con->list, &devcon_list);
mutex_unlock(&devcon_lock);
}
EXPORT_SYMBOL_GPL(device_connection_add);
/**
* device_connections_remove - Unregister connection description
* @con: The connection description to be unregistered
*/
void device_connection_remove(struct device_connection *con)
{
mutex_lock(&devcon_lock);
list_del(&con->list);
mutex_unlock(&devcon_lock);
}
EXPORT_SYMBOL_GPL(device_connection_remove);
...@@ -123,7 +123,7 @@ static int devcd_free(struct device *dev, void *data) ...@@ -123,7 +123,7 @@ static int devcd_free(struct device *dev, void *data)
static ssize_t disabled_show(struct class *class, struct class_attribute *attr, static ssize_t disabled_show(struct class *class, struct class_attribute *attr,
char *buf) char *buf)
{ {
return sprintf(buf, "%d\n", devcd_disabled); return sysfs_emit(buf, "%d\n", devcd_disabled);
} }
static ssize_t disabled_store(struct class *class, struct class_attribute *attr, static ssize_t disabled_store(struct class *class, struct class_attribute *attr,
......
...@@ -126,6 +126,14 @@ static void add_dr(struct device *dev, struct devres_node *node) ...@@ -126,6 +126,14 @@ static void add_dr(struct device *dev, struct devres_node *node)
list_add_tail(&node->entry, &dev->devres_head); list_add_tail(&node->entry, &dev->devres_head);
} }
static void replace_dr(struct device *dev,
struct devres_node *old, struct devres_node *new)
{
devres_log(dev, old, "REPLACE");
BUG_ON(!list_empty(&new->entry));
list_replace(&old->entry, &new->entry);
}
#ifdef CONFIG_DEBUG_DEVRES #ifdef CONFIG_DEBUG_DEVRES
void * __devres_alloc_node(dr_release_t release, size_t size, gfp_t gfp, int nid, void * __devres_alloc_node(dr_release_t release, size_t size, gfp_t gfp, int nid,
const char *name) const char *name)
...@@ -837,6 +845,103 @@ void *devm_kmalloc(struct device *dev, size_t size, gfp_t gfp) ...@@ -837,6 +845,103 @@ void *devm_kmalloc(struct device *dev, size_t size, gfp_t gfp)
} }
EXPORT_SYMBOL_GPL(devm_kmalloc); EXPORT_SYMBOL_GPL(devm_kmalloc);
/**
* devm_krealloc - Resource-managed krealloc()
* @dev: Device to re-allocate memory for
* @ptr: Pointer to the memory chunk to re-allocate
* @new_size: New allocation size
* @gfp: Allocation gfp flags
*
* Managed krealloc(). Resizes the memory chunk allocated with devm_kmalloc().
* Behaves similarly to regular krealloc(): if @ptr is NULL or ZERO_SIZE_PTR,
* it's the equivalent of devm_kmalloc(). If new_size is zero, it frees the
* previously allocated memory and returns ZERO_SIZE_PTR. This function doesn't
* change the order in which the release callback for the re-alloc'ed devres
* will be called (except when falling back to devm_kmalloc() or when freeing
* resources when new_size is zero). The contents of the memory are preserved
* up to the lesser of new and old sizes.
*/
void *devm_krealloc(struct device *dev, void *ptr, size_t new_size, gfp_t gfp)
{
size_t total_new_size, total_old_size;
struct devres *old_dr, *new_dr;
unsigned long flags;
if (unlikely(!new_size)) {
devm_kfree(dev, ptr);
return ZERO_SIZE_PTR;
}
if (unlikely(ZERO_OR_NULL_PTR(ptr)))
return devm_kmalloc(dev, new_size, gfp);
if (WARN_ON(is_kernel_rodata((unsigned long)ptr)))
/*
* We cannot reliably realloc a const string returned by
* devm_kstrdup_const().
*/
return NULL;
if (!check_dr_size(new_size, &total_new_size))
return NULL;
total_old_size = ksize(container_of(ptr, struct devres, data));
if (total_old_size == 0) {
WARN(1, "Pointer doesn't point to dynamically allocated memory.");
return NULL;
}
/*
* If new size is smaller or equal to the actual number of bytes
* allocated previously - just return the same pointer.
*/
if (total_new_size <= total_old_size)
return ptr;
/*
* Otherwise: allocate new, larger chunk. We need to allocate before
* taking the lock as most probably the caller uses GFP_KERNEL.
*/
new_dr = alloc_dr(devm_kmalloc_release,
total_new_size, gfp, dev_to_node(dev));
if (!new_dr)
return NULL;
/*
* The spinlock protects the linked list against concurrent
* modifications but not the resource itself.
*/
spin_lock_irqsave(&dev->devres_lock, flags);
old_dr = find_dr(dev, devm_kmalloc_release, devm_kmalloc_match, ptr);
if (!old_dr) {
spin_unlock_irqrestore(&dev->devres_lock, flags);
kfree(new_dr);
WARN(1, "Memory chunk not managed or managed by a different device.");
return NULL;
}
replace_dr(dev, &old_dr->node, &new_dr->node);
spin_unlock_irqrestore(&dev->devres_lock, flags);
/*
* We can copy the memory contents after releasing the lock as we're
* no longer modyfing the list links.
*/
memcpy(new_dr->data, old_dr->data,
total_old_size - offsetof(struct devres, data));
/*
* Same for releasing the old devres - it's now been removed from the
* list. This is also the reason why we must not use devm_kfree() - the
* links are no longer valid.
*/
kfree(old_dr);
return new_dr->data;
}
EXPORT_SYMBOL_GPL(devm_krealloc);
/** /**
* devm_kstrdup - Allocate resource managed space and * devm_kstrdup - Allocate resource managed space and
* copy an existing string into that. * copy an existing string into that.
......
...@@ -124,7 +124,7 @@ void kill_pending_fw_fallback_reqs(bool only_kill_custom) ...@@ -124,7 +124,7 @@ void kill_pending_fw_fallback_reqs(bool only_kill_custom)
static ssize_t timeout_show(struct class *class, struct class_attribute *attr, static ssize_t timeout_show(struct class *class, struct class_attribute *attr,
char *buf) char *buf)
{ {
return sprintf(buf, "%d\n", __firmware_loading_timeout()); return sysfs_emit(buf, "%d\n", __firmware_loading_timeout());
} }
/** /**
...@@ -219,7 +219,7 @@ static ssize_t firmware_loading_show(struct device *dev, ...@@ -219,7 +219,7 @@ static ssize_t firmware_loading_show(struct device *dev,
loading = fw_sysfs_loading(fw_sysfs->fw_priv); loading = fw_sysfs_loading(fw_sysfs->fw_priv);
mutex_unlock(&fw_lock); mutex_unlock(&fw_lock);
return sprintf(buf, "%d\n", loading); return sysfs_emit(buf, "%d\n", loading);
} }
/** /**
......
...@@ -119,7 +119,8 @@ static ssize_t phys_index_show(struct device *dev, ...@@ -119,7 +119,8 @@ static ssize_t phys_index_show(struct device *dev,
unsigned long phys_index; unsigned long phys_index;
phys_index = mem->start_section_nr / sections_per_block; phys_index = mem->start_section_nr / sections_per_block;
return sprintf(buf, "%08lx\n", phys_index);
return sysfs_emit(buf, "%08lx\n", phys_index);
} }
/* /*
...@@ -129,7 +130,7 @@ static ssize_t phys_index_show(struct device *dev, ...@@ -129,7 +130,7 @@ static ssize_t phys_index_show(struct device *dev,
static ssize_t removable_show(struct device *dev, struct device_attribute *attr, static ssize_t removable_show(struct device *dev, struct device_attribute *attr,
char *buf) char *buf)
{ {
return sprintf(buf, "%d\n", (int)IS_ENABLED(CONFIG_MEMORY_HOTREMOVE)); return sysfs_emit(buf, "%d\n", (int)IS_ENABLED(CONFIG_MEMORY_HOTREMOVE));
} }
/* /*
...@@ -139,7 +140,7 @@ static ssize_t state_show(struct device *dev, struct device_attribute *attr, ...@@ -139,7 +140,7 @@ static ssize_t state_show(struct device *dev, struct device_attribute *attr,
char *buf) char *buf)
{ {
struct memory_block *mem = to_memory_block(dev); struct memory_block *mem = to_memory_block(dev);
ssize_t len = 0; const char *output;
/* /*
* We can probably put these states in a nice little array * We can probably put these states in a nice little array
...@@ -147,22 +148,20 @@ static ssize_t state_show(struct device *dev, struct device_attribute *attr, ...@@ -147,22 +148,20 @@ static ssize_t state_show(struct device *dev, struct device_attribute *attr,
*/ */
switch (mem->state) { switch (mem->state) {
case MEM_ONLINE: case MEM_ONLINE:
len = sprintf(buf, "online\n"); output = "online";
break; break;
case MEM_OFFLINE: case MEM_OFFLINE:
len = sprintf(buf, "offline\n"); output = "offline";
break; break;
case MEM_GOING_OFFLINE: case MEM_GOING_OFFLINE:
len = sprintf(buf, "going-offline\n"); output = "going-offline";
break; break;
default: default:
len = sprintf(buf, "ERROR-UNKNOWN-%ld\n",
mem->state);
WARN_ON(1); WARN_ON(1);
break; return sysfs_emit(buf, "ERROR-UNKNOWN-%ld\n", mem->state);
} }
return len; return sysfs_emit(buf, "%s\n", output);
} }
int memory_notify(unsigned long val, void *v) int memory_notify(unsigned long val, void *v)
...@@ -303,21 +302,22 @@ static ssize_t phys_device_show(struct device *dev, ...@@ -303,21 +302,22 @@ static ssize_t phys_device_show(struct device *dev,
struct device_attribute *attr, char *buf) struct device_attribute *attr, char *buf)
{ {
struct memory_block *mem = to_memory_block(dev); struct memory_block *mem = to_memory_block(dev);
return sprintf(buf, "%d\n", mem->phys_device);
return sysfs_emit(buf, "%d\n", mem->phys_device);
} }
#ifdef CONFIG_MEMORY_HOTREMOVE #ifdef CONFIG_MEMORY_HOTREMOVE
static void print_allowed_zone(char *buf, int nid, unsigned long start_pfn, static int print_allowed_zone(char *buf, int len, int nid,
unsigned long nr_pages, int online_type, unsigned long start_pfn, unsigned long nr_pages,
struct zone *default_zone) int online_type, struct zone *default_zone)
{ {
struct zone *zone; struct zone *zone;
zone = zone_for_pfn_range(online_type, nid, start_pfn, nr_pages); zone = zone_for_pfn_range(online_type, nid, start_pfn, nr_pages);
if (zone != default_zone) { if (zone == default_zone)
strcat(buf, " "); return 0;
strcat(buf, zone->name);
} return sysfs_emit_at(buf, len, " %s", zone->name);
} }
static ssize_t valid_zones_show(struct device *dev, static ssize_t valid_zones_show(struct device *dev,
...@@ -327,6 +327,7 @@ static ssize_t valid_zones_show(struct device *dev, ...@@ -327,6 +327,7 @@ static ssize_t valid_zones_show(struct device *dev,
unsigned long start_pfn = section_nr_to_pfn(mem->start_section_nr); unsigned long start_pfn = section_nr_to_pfn(mem->start_section_nr);
unsigned long nr_pages = PAGES_PER_SECTION * sections_per_block; unsigned long nr_pages = PAGES_PER_SECTION * sections_per_block;
struct zone *default_zone; struct zone *default_zone;
int len = 0;
int nid; int nid;
/* /*
...@@ -341,24 +342,23 @@ static ssize_t valid_zones_show(struct device *dev, ...@@ -341,24 +342,23 @@ static ssize_t valid_zones_show(struct device *dev,
default_zone = test_pages_in_a_zone(start_pfn, default_zone = test_pages_in_a_zone(start_pfn,
start_pfn + nr_pages); start_pfn + nr_pages);
if (!default_zone) if (!default_zone)
return sprintf(buf, "none\n"); return sysfs_emit(buf, "%s\n", "none");
strcat(buf, default_zone->name); len += sysfs_emit_at(buf, len, "%s", default_zone->name);
goto out; goto out;
} }
nid = mem->nid; nid = mem->nid;
default_zone = zone_for_pfn_range(MMOP_ONLINE, nid, start_pfn, default_zone = zone_for_pfn_range(MMOP_ONLINE, nid, start_pfn,
nr_pages); nr_pages);
strcat(buf, default_zone->name);
print_allowed_zone(buf, nid, start_pfn, nr_pages, MMOP_ONLINE_KERNEL, len += sysfs_emit_at(buf, len, "%s", default_zone->name);
default_zone); len += print_allowed_zone(buf, len, nid, start_pfn, nr_pages,
print_allowed_zone(buf, nid, start_pfn, nr_pages, MMOP_ONLINE_MOVABLE, MMOP_ONLINE_KERNEL, default_zone);
default_zone); len += print_allowed_zone(buf, len, nid, start_pfn, nr_pages,
MMOP_ONLINE_MOVABLE, default_zone);
out: out:
strcat(buf, "\n"); len += sysfs_emit_at(buf, len, "\n");
return len;
return strlen(buf);
} }
static DEVICE_ATTR_RO(valid_zones); static DEVICE_ATTR_RO(valid_zones);
#endif #endif
...@@ -374,7 +374,7 @@ static DEVICE_ATTR_RO(removable); ...@@ -374,7 +374,7 @@ static DEVICE_ATTR_RO(removable);
static ssize_t block_size_bytes_show(struct device *dev, static ssize_t block_size_bytes_show(struct device *dev,
struct device_attribute *attr, char *buf) struct device_attribute *attr, char *buf)
{ {
return sprintf(buf, "%lx\n", memory_block_size_bytes()); return sysfs_emit(buf, "%lx\n", memory_block_size_bytes());
} }
static DEVICE_ATTR_RO(block_size_bytes); static DEVICE_ATTR_RO(block_size_bytes);
...@@ -386,8 +386,8 @@ static DEVICE_ATTR_RO(block_size_bytes); ...@@ -386,8 +386,8 @@ static DEVICE_ATTR_RO(block_size_bytes);
static ssize_t auto_online_blocks_show(struct device *dev, static ssize_t auto_online_blocks_show(struct device *dev,
struct device_attribute *attr, char *buf) struct device_attribute *attr, char *buf)
{ {
return sprintf(buf, "%s\n", return sysfs_emit(buf, "%s\n",
online_type_to_str[memhp_default_online_type]); online_type_to_str[memhp_default_online_type]);
} }
static ssize_t auto_online_blocks_store(struct device *dev, static ssize_t auto_online_blocks_store(struct device *dev,
......
This diff is collapsed.
...@@ -45,6 +45,8 @@ EXPORT_SYMBOL_GPL(platform_bus); ...@@ -45,6 +45,8 @@ EXPORT_SYMBOL_GPL(platform_bus);
* @dev: platform device * @dev: platform device
* @type: resource type * @type: resource type
* @num: resource index * @num: resource index
*
* Return: a pointer to the resource or NULL on failure.
*/ */
struct resource *platform_get_resource(struct platform_device *dev, struct resource *platform_get_resource(struct platform_device *dev,
unsigned int type, unsigned int num) unsigned int type, unsigned int num)
...@@ -70,6 +72,9 @@ EXPORT_SYMBOL_GPL(platform_get_resource); ...@@ -70,6 +72,9 @@ EXPORT_SYMBOL_GPL(platform_get_resource);
* resource management * resource management
* @index: resource index * @index: resource index
* @res: optional output parameter to store a pointer to the obtained resource. * @res: optional output parameter to store a pointer to the obtained resource.
*
* Return: a pointer to the remapped memory or an ERR_PTR() encoded error code
* on failure.
*/ */
void __iomem * void __iomem *
devm_platform_get_and_ioremap_resource(struct platform_device *pdev, devm_platform_get_and_ioremap_resource(struct platform_device *pdev,
...@@ -91,6 +96,9 @@ EXPORT_SYMBOL_GPL(devm_platform_get_and_ioremap_resource); ...@@ -91,6 +96,9 @@ EXPORT_SYMBOL_GPL(devm_platform_get_and_ioremap_resource);
* @pdev: platform device to use both for memory resource lookup as well as * @pdev: platform device to use both for memory resource lookup as well as
* resource management * resource management
* @index: resource index * @index: resource index
*
* Return: a pointer to the remapped memory or an ERR_PTR() encoded error code
* on failure.
*/ */
void __iomem *devm_platform_ioremap_resource(struct platform_device *pdev, void __iomem *devm_platform_ioremap_resource(struct platform_device *pdev,
unsigned int index) unsigned int index)
...@@ -106,6 +114,9 @@ EXPORT_SYMBOL_GPL(devm_platform_ioremap_resource); ...@@ -106,6 +114,9 @@ EXPORT_SYMBOL_GPL(devm_platform_ioremap_resource);
* @pdev: platform device to use both for memory resource lookup as well as * @pdev: platform device to use both for memory resource lookup as well as
* resource management * resource management
* @index: resource index * @index: resource index
*
* Return: a pointer to the remapped memory or an ERR_PTR() encoded error code
* on failure.
*/ */
void __iomem *devm_platform_ioremap_resource_wc(struct platform_device *pdev, void __iomem *devm_platform_ioremap_resource_wc(struct platform_device *pdev,
unsigned int index) unsigned int index)
...@@ -124,6 +135,9 @@ void __iomem *devm_platform_ioremap_resource_wc(struct platform_device *pdev, ...@@ -124,6 +135,9 @@ void __iomem *devm_platform_ioremap_resource_wc(struct platform_device *pdev,
* @pdev: platform device to use both for memory resource lookup as well as * @pdev: platform device to use both for memory resource lookup as well as
* resource management * resource management
* @name: name of the resource * @name: name of the resource
*
* Return: a pointer to the remapped memory or an ERR_PTR() encoded error code
* on failure.
*/ */
void __iomem * void __iomem *
devm_platform_ioremap_resource_byname(struct platform_device *pdev, devm_platform_ioremap_resource_byname(struct platform_device *pdev,
...@@ -559,7 +573,7 @@ int platform_device_add(struct platform_device *pdev) ...@@ -559,7 +573,7 @@ int platform_device_add(struct platform_device *pdev)
* that we remember it must be freed, and we append a suffix * that we remember it must be freed, and we append a suffix
* to avoid namespace collision with explicit IDs. * to avoid namespace collision with explicit IDs.
*/ */
ret = ida_simple_get(&platform_devid_ida, 0, 0, GFP_KERNEL); ret = ida_alloc(&platform_devid_ida, GFP_KERNEL);
if (ret < 0) if (ret < 0)
goto err_out; goto err_out;
pdev->id = ret; pdev->id = ret;
...@@ -600,7 +614,7 @@ int platform_device_add(struct platform_device *pdev) ...@@ -600,7 +614,7 @@ int platform_device_add(struct platform_device *pdev)
failed: failed:
if (pdev->id_auto) { if (pdev->id_auto) {
ida_simple_remove(&platform_devid_ida, pdev->id); ida_free(&platform_devid_ida, pdev->id);
pdev->id = PLATFORM_DEVID_AUTO; pdev->id = PLATFORM_DEVID_AUTO;
} }
...@@ -631,7 +645,7 @@ void platform_device_del(struct platform_device *pdev) ...@@ -631,7 +645,7 @@ void platform_device_del(struct platform_device *pdev)
device_del(&pdev->dev); device_del(&pdev->dev);
if (pdev->id_auto) { if (pdev->id_auto) {
ida_simple_remove(&platform_devid_ida, pdev->id); ida_free(&platform_devid_ida, pdev->id);
pdev->id = PLATFORM_DEVID_AUTO; pdev->id = PLATFORM_DEVID_AUTO;
} }
...@@ -1009,10 +1023,10 @@ EXPORT_SYMBOL_GPL(platform_unregister_drivers); ...@@ -1009,10 +1023,10 @@ EXPORT_SYMBOL_GPL(platform_unregister_drivers);
* (b) sysfs attribute lets new-style coldplug recover from hotplug events * (b) sysfs attribute lets new-style coldplug recover from hotplug events
* mishandled before system is fully running: "modprobe $(cat modalias)" * mishandled before system is fully running: "modprobe $(cat modalias)"
*/ */
static ssize_t modalias_show(struct device *dev, struct device_attribute *a, static ssize_t modalias_show(struct device *dev,
char *buf) struct device_attribute *attr, char *buf)
{ {
struct platform_device *pdev = to_platform_device(dev); struct platform_device *pdev = to_platform_device(dev);
int len; int len;
len = of_device_modalias(dev, buf, PAGE_SIZE); len = of_device_modalias(dev, buf, PAGE_SIZE);
...@@ -1023,9 +1037,7 @@ static ssize_t modalias_show(struct device *dev, struct device_attribute *a, ...@@ -1023,9 +1037,7 @@ static ssize_t modalias_show(struct device *dev, struct device_attribute *a,
if (len != -ENODEV) if (len != -ENODEV)
return len; return len;
len = snprintf(buf, PAGE_SIZE, "platform:%s\n", pdev->name); return sysfs_emit(buf, "platform:%s\n", pdev->name);
return (len >= PAGE_SIZE) ? (PAGE_SIZE - 1) : len;
} }
static DEVICE_ATTR_RO(modalias); static DEVICE_ATTR_RO(modalias);
...@@ -1070,16 +1082,17 @@ static ssize_t driver_override_show(struct device *dev, ...@@ -1070,16 +1082,17 @@ static ssize_t driver_override_show(struct device *dev,
ssize_t len; ssize_t len;
device_lock(dev); device_lock(dev);
len = sprintf(buf, "%s\n", pdev->driver_override); len = sysfs_emit(buf, "%s\n", pdev->driver_override);
device_unlock(dev); device_unlock(dev);
return len; return len;
} }
static DEVICE_ATTR_RW(driver_override); static DEVICE_ATTR_RW(driver_override);
static ssize_t numa_node_show(struct device *dev, static ssize_t numa_node_show(struct device *dev,
struct device_attribute *attr, char *buf) struct device_attribute *attr, char *buf)
{ {
return sprintf(buf, "%d\n", dev_to_node(dev)); return sysfs_emit(buf, "%d\n", dev_to_node(dev));
} }
static DEVICE_ATTR_RO(numa_node); static DEVICE_ATTR_RO(numa_node);
......
This diff is collapsed.
...@@ -26,7 +26,7 @@ static ssize_t _name##_show(struct device *dev, \ ...@@ -26,7 +26,7 @@ static ssize_t _name##_show(struct device *dev, \
{ \ { \
struct wakeup_source *ws = dev_get_drvdata(dev); \ struct wakeup_source *ws = dev_get_drvdata(dev); \
\ \
return sprintf(buf, "%lu\n", ws->_name); \ return sysfs_emit(buf, "%lu\n", ws->_name); \
} \ } \
static DEVICE_ATTR_RO(_name) static DEVICE_ATTR_RO(_name)
...@@ -42,7 +42,7 @@ static ssize_t active_time_ms_show(struct device *dev, ...@@ -42,7 +42,7 @@ static ssize_t active_time_ms_show(struct device *dev,
ktime_t active_time = ktime_t active_time =
ws->active ? ktime_sub(ktime_get(), ws->last_time) : 0; ws->active ? ktime_sub(ktime_get(), ws->last_time) : 0;
return sprintf(buf, "%lld\n", ktime_to_ms(active_time)); return sysfs_emit(buf, "%lld\n", ktime_to_ms(active_time));
} }
static DEVICE_ATTR_RO(active_time_ms); static DEVICE_ATTR_RO(active_time_ms);
...@@ -57,7 +57,8 @@ static ssize_t total_time_ms_show(struct device *dev, ...@@ -57,7 +57,8 @@ static ssize_t total_time_ms_show(struct device *dev,
active_time = ktime_sub(ktime_get(), ws->last_time); active_time = ktime_sub(ktime_get(), ws->last_time);
total_time = ktime_add(total_time, active_time); total_time = ktime_add(total_time, active_time);
} }
return sprintf(buf, "%lld\n", ktime_to_ms(total_time));
return sysfs_emit(buf, "%lld\n", ktime_to_ms(total_time));
} }
static DEVICE_ATTR_RO(total_time_ms); static DEVICE_ATTR_RO(total_time_ms);
...@@ -73,7 +74,8 @@ static ssize_t max_time_ms_show(struct device *dev, ...@@ -73,7 +74,8 @@ static ssize_t max_time_ms_show(struct device *dev,
if (active_time > max_time) if (active_time > max_time)
max_time = active_time; max_time = active_time;
} }
return sprintf(buf, "%lld\n", ktime_to_ms(max_time));
return sysfs_emit(buf, "%lld\n", ktime_to_ms(max_time));
} }
static DEVICE_ATTR_RO(max_time_ms); static DEVICE_ATTR_RO(max_time_ms);
...@@ -82,7 +84,7 @@ static ssize_t last_change_ms_show(struct device *dev, ...@@ -82,7 +84,7 @@ static ssize_t last_change_ms_show(struct device *dev,
{ {
struct wakeup_source *ws = dev_get_drvdata(dev); struct wakeup_source *ws = dev_get_drvdata(dev);
return sprintf(buf, "%lld\n", ktime_to_ms(ws->last_time)); return sysfs_emit(buf, "%lld\n", ktime_to_ms(ws->last_time));
} }
static DEVICE_ATTR_RO(last_change_ms); static DEVICE_ATTR_RO(last_change_ms);
...@@ -91,7 +93,7 @@ static ssize_t name_show(struct device *dev, struct device_attribute *attr, ...@@ -91,7 +93,7 @@ static ssize_t name_show(struct device *dev, struct device_attribute *attr,
{ {
struct wakeup_source *ws = dev_get_drvdata(dev); struct wakeup_source *ws = dev_get_drvdata(dev);
return sprintf(buf, "%s\n", ws->name); return sysfs_emit(buf, "%s\n", ws->name);
} }
static DEVICE_ATTR_RO(name); static DEVICE_ATTR_RO(name);
...@@ -106,7 +108,8 @@ static ssize_t prevent_suspend_time_ms_show(struct device *dev, ...@@ -106,7 +108,8 @@ static ssize_t prevent_suspend_time_ms_show(struct device *dev,
prevent_sleep_time = ktime_add(prevent_sleep_time, prevent_sleep_time = ktime_add(prevent_sleep_time,
ktime_sub(ktime_get(), ws->start_prevent_time)); ktime_sub(ktime_get(), ws->start_prevent_time));
} }
return sprintf(buf, "%lld\n", ktime_to_ms(prevent_sleep_time));
return sysfs_emit(buf, "%lld\n", ktime_to_ms(prevent_sleep_time));
} }
static DEVICE_ATTR_RO(prevent_suspend_time_ms); static DEVICE_ATTR_RO(prevent_suspend_time_ms);
......
...@@ -1184,3 +1184,76 @@ const void *device_get_match_data(struct device *dev) ...@@ -1184,3 +1184,76 @@ const void *device_get_match_data(struct device *dev)
return fwnode_call_ptr_op(dev_fwnode(dev), device_get_match_data, dev); return fwnode_call_ptr_op(dev_fwnode(dev), device_get_match_data, dev);
} }
EXPORT_SYMBOL_GPL(device_get_match_data); EXPORT_SYMBOL_GPL(device_get_match_data);
static void *
fwnode_graph_devcon_match(struct fwnode_handle *fwnode, const char *con_id,
void *data, devcon_match_fn_t match)
{
struct fwnode_handle *node;
struct fwnode_handle *ep;
void *ret;
fwnode_graph_for_each_endpoint(fwnode, ep) {
node = fwnode_graph_get_remote_port_parent(ep);
if (!fwnode_device_is_available(node))
continue;
ret = match(node, con_id, data);
fwnode_handle_put(node);
if (ret) {
fwnode_handle_put(ep);
return ret;
}
}
return NULL;
}
static void *
fwnode_devcon_match(struct fwnode_handle *fwnode, const char *con_id,
void *data, devcon_match_fn_t match)
{
struct fwnode_handle *node;
void *ret;
int i;
for (i = 0; ; i++) {
node = fwnode_find_reference(fwnode, con_id, i);
if (IS_ERR(node))
break;
ret = match(node, NULL, data);
fwnode_handle_put(node);
if (ret)
return ret;
}
return NULL;
}
/**
* fwnode_connection_find_match - Find connection from a device node
* @fwnode: Device node with the connection
* @con_id: Identifier for the connection
* @data: Data for the match function
* @match: Function to check and convert the connection description
*
* Find a connection with unique identifier @con_id between @fwnode and another
* device node. @match will be used to convert the connection description to
* data the caller is expecting to be returned.
*/
void *fwnode_connection_find_match(struct fwnode_handle *fwnode,
const char *con_id, void *data,
devcon_match_fn_t match)
{
void *ret;
if (!fwnode || !match)
return NULL;
ret = fwnode_graph_devcon_match(fwnode, con_id, data, match);
if (ret)
return ret;
return fwnode_devcon_match(fwnode, con_id, data, match);
}
EXPORT_SYMBOL_GPL(fwnode_connection_find_match);
...@@ -17,9 +17,9 @@ ...@@ -17,9 +17,9 @@
static DEFINE_IDA(soc_ida); static DEFINE_IDA(soc_ida);
static ssize_t soc_info_get(struct device *dev, /* Prototype to allow declarations of DEVICE_ATTR(<foo>) before soc_info_show */
struct device_attribute *attr, static ssize_t soc_info_show(struct device *dev, struct device_attribute *attr,
char *buf); char *buf);
struct soc_device { struct soc_device {
struct device dev; struct device dev;
...@@ -31,11 +31,11 @@ static struct bus_type soc_bus_type = { ...@@ -31,11 +31,11 @@ static struct bus_type soc_bus_type = {
.name = "soc", .name = "soc",
}; };
static DEVICE_ATTR(machine, S_IRUGO, soc_info_get, NULL); static DEVICE_ATTR(machine, 0444, soc_info_show, NULL);
static DEVICE_ATTR(family, S_IRUGO, soc_info_get, NULL); static DEVICE_ATTR(family, 0444, soc_info_show, NULL);
static DEVICE_ATTR(serial_number, S_IRUGO, soc_info_get, NULL); static DEVICE_ATTR(serial_number, 0444, soc_info_show, NULL);
static DEVICE_ATTR(soc_id, S_IRUGO, soc_info_get, NULL); static DEVICE_ATTR(soc_id, 0444, soc_info_show, NULL);
static DEVICE_ATTR(revision, S_IRUGO, soc_info_get, NULL); static DEVICE_ATTR(revision, 0444, soc_info_show, NULL);
struct device *soc_device_to_device(struct soc_device *soc_dev) struct device *soc_device_to_device(struct soc_device *soc_dev)
{ {
...@@ -49,45 +49,41 @@ static umode_t soc_attribute_mode(struct kobject *kobj, ...@@ -49,45 +49,41 @@ static umode_t soc_attribute_mode(struct kobject *kobj,
struct device *dev = kobj_to_dev(kobj); struct device *dev = kobj_to_dev(kobj);
struct soc_device *soc_dev = container_of(dev, struct soc_device, dev); struct soc_device *soc_dev = container_of(dev, struct soc_device, dev);
if ((attr == &dev_attr_machine.attr) if ((attr == &dev_attr_machine.attr) && soc_dev->attr->machine)
&& (soc_dev->attr->machine != NULL))
return attr->mode; return attr->mode;
if ((attr == &dev_attr_family.attr) if ((attr == &dev_attr_family.attr) && soc_dev->attr->family)
&& (soc_dev->attr->family != NULL))
return attr->mode; return attr->mode;
if ((attr == &dev_attr_revision.attr) if ((attr == &dev_attr_revision.attr) && soc_dev->attr->revision)
&& (soc_dev->attr->revision != NULL))
return attr->mode; return attr->mode;
if ((attr == &dev_attr_serial_number.attr) if ((attr == &dev_attr_serial_number.attr) && soc_dev->attr->serial_number)
&& (soc_dev->attr->serial_number != NULL))
return attr->mode; return attr->mode;
if ((attr == &dev_attr_soc_id.attr) if ((attr == &dev_attr_soc_id.attr) && soc_dev->attr->soc_id)
&& (soc_dev->attr->soc_id != NULL))
return attr->mode; return attr->mode;
/* Unknown or unfilled attribute. */ /* Unknown or unfilled attribute */
return 0; return 0;
} }
static ssize_t soc_info_get(struct device *dev, static ssize_t soc_info_show(struct device *dev, struct device_attribute *attr,
struct device_attribute *attr, char *buf)
char *buf)
{ {
struct soc_device *soc_dev = container_of(dev, struct soc_device, dev); struct soc_device *soc_dev = container_of(dev, struct soc_device, dev);
const char *output;
if (attr == &dev_attr_machine) if (attr == &dev_attr_machine)
return sprintf(buf, "%s\n", soc_dev->attr->machine); output = soc_dev->attr->machine;
if (attr == &dev_attr_family) else if (attr == &dev_attr_family)
return sprintf(buf, "%s\n", soc_dev->attr->family); output = soc_dev->attr->family;
if (attr == &dev_attr_revision) else if (attr == &dev_attr_revision)
return sprintf(buf, "%s\n", soc_dev->attr->revision); output = soc_dev->attr->revision;
if (attr == &dev_attr_serial_number) else if (attr == &dev_attr_serial_number)
return sprintf(buf, "%s\n", soc_dev->attr->serial_number); output = soc_dev->attr->serial_number;
if (attr == &dev_attr_soc_id) else if (attr == &dev_attr_soc_id)
return sprintf(buf, "%s\n", soc_dev->attr->soc_id); output = soc_dev->attr->soc_id;
else
return -EINVAL; return -EINVAL;
return sysfs_emit(buf, "%s\n", output);
} }
static struct attribute *soc_attr[] = { static struct attribute *soc_attr[] = {
......
...@@ -50,7 +50,7 @@ int syscore_suspend(void) ...@@ -50,7 +50,7 @@ int syscore_suspend(void)
int ret = 0; int ret = 0;
trace_suspend_resume(TPS("syscore_suspend"), 0, true); trace_suspend_resume(TPS("syscore_suspend"), 0, true);
pr_debug("Checking wakeup interrupts\n"); pm_pr_dbg("Checking wakeup interrupts\n");
/* Return error code if there are any wakeup interrupts pending. */ /* Return error code if there are any wakeup interrupts pending. */
if (pm_wakeup_pending()) if (pm_wakeup_pending())
...@@ -61,8 +61,7 @@ int syscore_suspend(void) ...@@ -61,8 +61,7 @@ int syscore_suspend(void)
list_for_each_entry_reverse(ops, &syscore_ops_list, node) list_for_each_entry_reverse(ops, &syscore_ops_list, node)
if (ops->suspend) { if (ops->suspend) {
if (initcall_debug) pm_pr_dbg("Calling %pS\n", ops->suspend);
pr_info("PM: Calling %pS\n", ops->suspend);
ret = ops->suspend(); ret = ops->suspend();
if (ret) if (ret)
goto err_out; goto err_out;
...@@ -99,8 +98,7 @@ void syscore_resume(void) ...@@ -99,8 +98,7 @@ void syscore_resume(void)
list_for_each_entry(ops, &syscore_ops_list, node) list_for_each_entry(ops, &syscore_ops_list, node)
if (ops->resume) { if (ops->resume) {
if (initcall_debug) pm_pr_dbg("Calling %pS\n", ops->resume);
pr_info("PM: Calling %pS\n", ops->resume);
ops->resume(); ops->resume();
WARN_ONCE(!irqs_disabled(), WARN_ONCE(!irqs_disabled(),
"Interrupts enabled after %pS\n", ops->resume); "Interrupts enabled after %pS\n", ops->resume);
......
...@@ -14,11 +14,11 @@ ...@@ -14,11 +14,11 @@
#include <linux/hardirq.h> #include <linux/hardirq.h>
#include <linux/topology.h> #include <linux/topology.h>
#define define_id_show_func(name) \ #define define_id_show_func(name) \
static ssize_t name##_show(struct device *dev, \ static ssize_t name##_show(struct device *dev, \
struct device_attribute *attr, char *buf) \ struct device_attribute *attr, char *buf) \
{ \ { \
return sprintf(buf, "%d\n", topology_##name(dev->id)); \ return sysfs_emit(buf, "%d\n", topology_##name(dev->id)); \
} }
#define define_siblings_show_map(name, mask) \ #define define_siblings_show_map(name, mask) \
......
...@@ -987,9 +987,9 @@ static int pmbus_add_attribute(struct pmbus_data *data, struct attribute *attr) ...@@ -987,9 +987,9 @@ static int pmbus_add_attribute(struct pmbus_data *data, struct attribute *attr)
{ {
if (data->num_attributes >= data->max_attributes - 1) { if (data->num_attributes >= data->max_attributes - 1) {
int new_max_attrs = data->max_attributes + PMBUS_ATTR_ALLOC_SIZE; int new_max_attrs = data->max_attributes + PMBUS_ATTR_ALLOC_SIZE;
void *new_attrs = krealloc(data->group.attrs, void *new_attrs = devm_krealloc(data->dev, data->group.attrs,
new_max_attrs * sizeof(void *), new_max_attrs * sizeof(void *),
GFP_KERNEL); GFP_KERNEL);
if (!new_attrs) if (!new_attrs)
return -ENOMEM; return -ENOMEM;
data->group.attrs = new_attrs; data->group.attrs = new_attrs;
...@@ -2578,7 +2578,7 @@ int pmbus_do_probe(struct i2c_client *client, struct pmbus_driver_info *info) ...@@ -2578,7 +2578,7 @@ int pmbus_do_probe(struct i2c_client *client, struct pmbus_driver_info *info)
ret = pmbus_find_attributes(client, data); ret = pmbus_find_attributes(client, data);
if (ret) if (ret)
goto out_kfree; return ret;
/* /*
* If there are no attributes, something is wrong. * If there are no attributes, something is wrong.
...@@ -2586,35 +2586,27 @@ int pmbus_do_probe(struct i2c_client *client, struct pmbus_driver_info *info) ...@@ -2586,35 +2586,27 @@ int pmbus_do_probe(struct i2c_client *client, struct pmbus_driver_info *info)
*/ */
if (!data->num_attributes) { if (!data->num_attributes) {
dev_err(dev, "No attributes found\n"); dev_err(dev, "No attributes found\n");
ret = -ENODEV; return -ENODEV;
goto out_kfree;
} }
data->groups[0] = &data->group; data->groups[0] = &data->group;
memcpy(data->groups + 1, info->groups, sizeof(void *) * groups_num); memcpy(data->groups + 1, info->groups, sizeof(void *) * groups_num);
data->hwmon_dev = hwmon_device_register_with_groups(dev, client->name, data->hwmon_dev = devm_hwmon_device_register_with_groups(dev,
data, data->groups); client->name, data, data->groups);
if (IS_ERR(data->hwmon_dev)) { if (IS_ERR(data->hwmon_dev)) {
ret = PTR_ERR(data->hwmon_dev);
dev_err(dev, "Failed to register hwmon device\n"); dev_err(dev, "Failed to register hwmon device\n");
goto out_kfree; return PTR_ERR(data->hwmon_dev);
} }
ret = pmbus_regulator_register(data); ret = pmbus_regulator_register(data);
if (ret) if (ret)
goto out_unregister; return ret;
ret = pmbus_init_debugfs(client, data); ret = pmbus_init_debugfs(client, data);
if (ret) if (ret)
dev_warn(dev, "Failed to register debugfs\n"); dev_warn(dev, "Failed to register debugfs\n");
return 0; return 0;
out_unregister:
hwmon_device_unregister(data->hwmon_dev);
out_kfree:
kfree(data->group.attrs);
return ret;
} }
EXPORT_SYMBOL_GPL(pmbus_do_probe); EXPORT_SYMBOL_GPL(pmbus_do_probe);
...@@ -2624,8 +2616,6 @@ int pmbus_do_remove(struct i2c_client *client) ...@@ -2624,8 +2616,6 @@ int pmbus_do_remove(struct i2c_client *client)
debugfs_remove_recursive(data->debugfs); debugfs_remove_recursive(data->debugfs);
hwmon_device_unregister(data->hwmon_dev);
kfree(data->group.attrs);
return 0; return 0;
} }
EXPORT_SYMBOL_GPL(pmbus_do_remove); EXPORT_SYMBOL_GPL(pmbus_do_remove);
......
...@@ -1092,6 +1092,7 @@ MODULE_DEVICE_TABLE(of, xadc_of_match_table); ...@@ -1092,6 +1092,7 @@ MODULE_DEVICE_TABLE(of, xadc_of_match_table);
static int xadc_parse_dt(struct iio_dev *indio_dev, struct device_node *np, static int xadc_parse_dt(struct iio_dev *indio_dev, struct device_node *np,
unsigned int *conf) unsigned int *conf)
{ {
struct device *dev = indio_dev->dev.parent;
struct xadc *xadc = iio_priv(indio_dev); struct xadc *xadc = iio_priv(indio_dev);
struct iio_chan_spec *channels, *chan; struct iio_chan_spec *channels, *chan;
struct device_node *chan_node, *child; struct device_node *chan_node, *child;
...@@ -1136,7 +1137,8 @@ static int xadc_parse_dt(struct iio_dev *indio_dev, struct device_node *np, ...@@ -1136,7 +1137,8 @@ static int xadc_parse_dt(struct iio_dev *indio_dev, struct device_node *np,
*conf |= XADC_CONF0_MUX | XADC_CONF0_CHAN(ext_mux_chan); *conf |= XADC_CONF0_MUX | XADC_CONF0_CHAN(ext_mux_chan);
} }
channels = kmemdup(xadc_channels, sizeof(xadc_channels), GFP_KERNEL); channels = devm_kmemdup(dev, xadc_channels,
sizeof(xadc_channels), GFP_KERNEL);
if (!channels) if (!channels)
return -ENOMEM; return -ENOMEM;
...@@ -1172,8 +1174,9 @@ static int xadc_parse_dt(struct iio_dev *indio_dev, struct device_node *np, ...@@ -1172,8 +1174,9 @@ static int xadc_parse_dt(struct iio_dev *indio_dev, struct device_node *np,
of_node_put(chan_node); of_node_put(chan_node);
indio_dev->num_channels = num_channels; indio_dev->num_channels = num_channels;
indio_dev->channels = krealloc(channels, sizeof(*channels) * indio_dev->channels = devm_krealloc(dev, channels,
num_channels, GFP_KERNEL); sizeof(*channels) * num_channels,
GFP_KERNEL);
/* If we can't resize the channels array, just use the original */ /* If we can't resize the channels array, just use the original */
if (!indio_dev->channels) if (!indio_dev->channels)
indio_dev->channels = channels; indio_dev->channels = channels;
...@@ -1225,14 +1228,14 @@ static int xadc_probe(struct platform_device *pdev) ...@@ -1225,14 +1228,14 @@ static int xadc_probe(struct platform_device *pdev)
ret = xadc_parse_dt(indio_dev, pdev->dev.of_node, &conf0); ret = xadc_parse_dt(indio_dev, pdev->dev.of_node, &conf0);
if (ret) if (ret)
goto err_device_free; return ret;
if (xadc->ops->flags & XADC_FLAGS_BUFFERED) { if (xadc->ops->flags & XADC_FLAGS_BUFFERED) {
ret = iio_triggered_buffer_setup(indio_dev, ret = iio_triggered_buffer_setup(indio_dev,
&iio_pollfunc_store_time, &xadc_trigger_handler, &iio_pollfunc_store_time, &xadc_trigger_handler,
&xadc_buffer_ops); &xadc_buffer_ops);
if (ret) if (ret)
goto err_device_free; return ret;
xadc->convst_trigger = xadc_alloc_trigger(indio_dev, "convst"); xadc->convst_trigger = xadc_alloc_trigger(indio_dev, "convst");
if (IS_ERR(xadc->convst_trigger)) { if (IS_ERR(xadc->convst_trigger)) {
...@@ -1350,8 +1353,6 @@ static int xadc_probe(struct platform_device *pdev) ...@@ -1350,8 +1353,6 @@ static int xadc_probe(struct platform_device *pdev)
err_triggered_buffer_cleanup: err_triggered_buffer_cleanup:
if (xadc->ops->flags & XADC_FLAGS_BUFFERED) if (xadc->ops->flags & XADC_FLAGS_BUFFERED)
iio_triggered_buffer_cleanup(indio_dev); iio_triggered_buffer_cleanup(indio_dev);
err_device_free:
kfree(indio_dev->channels);
return ret; return ret;
} }
...@@ -1371,7 +1372,6 @@ static int xadc_remove(struct platform_device *pdev) ...@@ -1371,7 +1372,6 @@ static int xadc_remove(struct platform_device *pdev)
cancel_delayed_work_sync(&xadc->zynq_unmask_work); cancel_delayed_work_sync(&xadc->zynq_unmask_work);
clk_disable_unprepare(xadc->clk); clk_disable_unprepare(xadc->clk);
kfree(xadc->data); kfree(xadc->data);
kfree(indio_dev->channels);
return 0; return 0;
} }
......
...@@ -87,19 +87,15 @@ enum usb_role usb_role_switch_get_role(struct usb_role_switch *sw) ...@@ -87,19 +87,15 @@ enum usb_role usb_role_switch_get_role(struct usb_role_switch *sw)
} }
EXPORT_SYMBOL_GPL(usb_role_switch_get_role); EXPORT_SYMBOL_GPL(usb_role_switch_get_role);
static void *usb_role_switch_match(struct device_connection *con, int ep, static void *usb_role_switch_match(struct fwnode_handle *fwnode, const char *id,
void *data) void *data)
{ {
struct device *dev; struct device *dev;
if (con->fwnode) { if (id && !fwnode_property_present(fwnode, id))
if (con->id && !fwnode_property_present(con->fwnode, con->id)) return NULL;
return NULL;
dev = class_find_device_by_fwnode(role_class, con->fwnode); dev = class_find_device_by_fwnode(role_class, fwnode);
} else {
dev = class_find_device_by_name(role_class, con->endpoint[ep]);
}
return dev ? to_role_switch(dev) : ERR_PTR(-EPROBE_DEFER); return dev ? to_role_switch(dev) : ERR_PTR(-EPROBE_DEFER);
} }
......
...@@ -34,15 +34,15 @@ static int switch_fwnode_match(struct device *dev, const void *fwnode) ...@@ -34,15 +34,15 @@ static int switch_fwnode_match(struct device *dev, const void *fwnode)
return dev_fwnode(dev) == fwnode && dev_name_ends_with(dev, "-switch"); return dev_fwnode(dev) == fwnode && dev_name_ends_with(dev, "-switch");
} }
static void *typec_switch_match(struct device_connection *con, int ep, static void *typec_switch_match(struct fwnode_handle *fwnode, const char *id,
void *data) void *data)
{ {
struct device *dev; struct device *dev;
if (con->id && !fwnode_property_present(con->fwnode, con->id)) if (id && !fwnode_property_present(fwnode, id))
return NULL; return NULL;
dev = class_find_device(&typec_mux_class, NULL, con->fwnode, dev = class_find_device(&typec_mux_class, NULL, fwnode,
switch_fwnode_match); switch_fwnode_match);
return dev ? to_typec_switch(dev) : ERR_PTR(-EPROBE_DEFER); return dev ? to_typec_switch(dev) : ERR_PTR(-EPROBE_DEFER);
...@@ -183,7 +183,8 @@ static int mux_fwnode_match(struct device *dev, const void *fwnode) ...@@ -183,7 +183,8 @@ static int mux_fwnode_match(struct device *dev, const void *fwnode)
return dev_fwnode(dev) == fwnode && dev_name_ends_with(dev, "-mux"); return dev_fwnode(dev) == fwnode && dev_name_ends_with(dev, "-mux");
} }
static void *typec_mux_match(struct device_connection *con, int ep, void *data) static void *typec_mux_match(struct fwnode_handle *fwnode, const char *id,
void *data)
{ {
const struct typec_altmode_desc *desc = data; const struct typec_altmode_desc *desc = data;
struct device *dev; struct device *dev;
...@@ -196,20 +197,20 @@ static void *typec_mux_match(struct device_connection *con, int ep, void *data) ...@@ -196,20 +197,20 @@ static void *typec_mux_match(struct device_connection *con, int ep, void *data)
* Check has the identifier already been "consumed". If it * Check has the identifier already been "consumed". If it
* has, no need to do any extra connection identification. * has, no need to do any extra connection identification.
*/ */
match = !con->id; match = !id;
if (match) if (match)
goto find_mux; goto find_mux;
/* Accessory Mode muxes */ /* Accessory Mode muxes */
if (!desc) { if (!desc) {
match = fwnode_property_present(con->fwnode, "accessory"); match = fwnode_property_present(fwnode, "accessory");
if (match) if (match)
goto find_mux; goto find_mux;
return NULL; return NULL;
} }
/* Alternate Mode muxes */ /* Alternate Mode muxes */
nval = fwnode_property_count_u16(con->fwnode, "svid"); nval = fwnode_property_count_u16(fwnode, "svid");
if (nval <= 0) if (nval <= 0)
return NULL; return NULL;
...@@ -217,7 +218,7 @@ static void *typec_mux_match(struct device_connection *con, int ep, void *data) ...@@ -217,7 +218,7 @@ static void *typec_mux_match(struct device_connection *con, int ep, void *data)
if (!val) if (!val)
return ERR_PTR(-ENOMEM); return ERR_PTR(-ENOMEM);
nval = fwnode_property_read_u16_array(con->fwnode, "svid", val, nval); nval = fwnode_property_read_u16_array(fwnode, "svid", val, nval);
if (nval < 0) { if (nval < 0) {
kfree(val); kfree(val);
return ERR_PTR(nval); return ERR_PTR(nval);
...@@ -234,7 +235,7 @@ static void *typec_mux_match(struct device_connection *con, int ep, void *data) ...@@ -234,7 +235,7 @@ static void *typec_mux_match(struct device_connection *con, int ep, void *data)
return NULL; return NULL;
find_mux: find_mux:
dev = class_find_device(&typec_mux_class, NULL, con->fwnode, dev = class_find_device(&typec_mux_class, NULL, fwnode,
mux_fwnode_match); mux_fwnode_match);
return dev ? to_typec_switch(dev) : ERR_PTR(-EPROBE_DEFER); return dev ? to_typec_switch(dev) : ERR_PTR(-EPROBE_DEFER);
......
...@@ -15,6 +15,7 @@ ...@@ -15,6 +15,7 @@
#include <linux/list.h> #include <linux/list.h>
#include <linux/mutex.h> #include <linux/mutex.h>
#include <linux/seq_file.h> #include <linux/seq_file.h>
#include <linux/mm.h>
#include "sysfs.h" #include "sysfs.h"
...@@ -707,3 +708,57 @@ int sysfs_change_owner(struct kobject *kobj, kuid_t kuid, kgid_t kgid) ...@@ -707,3 +708,57 @@ int sysfs_change_owner(struct kobject *kobj, kuid_t kuid, kgid_t kgid)
return 0; return 0;
} }
EXPORT_SYMBOL_GPL(sysfs_change_owner); EXPORT_SYMBOL_GPL(sysfs_change_owner);
/**
* sysfs_emit - scnprintf equivalent, aware of PAGE_SIZE buffer.
* @buf: start of PAGE_SIZE buffer.
* @fmt: format
* @...: optional arguments to @format
*
*
* Returns number of characters written to @buf.
*/
int sysfs_emit(char *buf, const char *fmt, ...)
{
va_list args;
int len;
if (WARN(!buf || offset_in_page(buf),
"invalid sysfs_emit: buf:%p\n", buf))
return 0;
va_start(args, fmt);
len = vscnprintf(buf, PAGE_SIZE, fmt, args);
va_end(args);
return len;
}
EXPORT_SYMBOL_GPL(sysfs_emit);
/**
* sysfs_emit_at - scnprintf equivalent, aware of PAGE_SIZE buffer.
* @buf: start of PAGE_SIZE buffer.
* @at: offset in @buf to start write in bytes
* @at must be >= 0 && < PAGE_SIZE
* @fmt: format
* @...: optional arguments to @fmt
*
*
* Returns number of characters written starting at &@buf[@at].
*/
int sysfs_emit_at(char *buf, int at, const char *fmt, ...)
{
va_list args;
int len;
if (WARN(!buf || offset_in_page(buf) || at < 0 || at >= PAGE_SIZE,
"invalid sysfs_emit_at: buf:%p at:%d\n", buf, at))
return 0;
va_start(args, fmt);
len = vscnprintf(buf + at, PAGE_SIZE - at, fmt, args);
va_end(args);
return len;
}
EXPORT_SYMBOL_GPL(sysfs_emit_at);
...@@ -206,6 +206,8 @@ int devres_release_group(struct device *dev, void *id); ...@@ -206,6 +206,8 @@ int devres_release_group(struct device *dev, void *id);
/* managed devm_k.alloc/kfree for device drivers */ /* managed devm_k.alloc/kfree for device drivers */
void *devm_kmalloc(struct device *dev, size_t size, gfp_t gfp) __malloc; void *devm_kmalloc(struct device *dev, size_t size, gfp_t gfp) __malloc;
void *devm_krealloc(struct device *dev, void *ptr, size_t size,
gfp_t gfp) __must_check;
__printf(3, 0) char *devm_kvasprintf(struct device *dev, gfp_t gfp, __printf(3, 0) char *devm_kvasprintf(struct device *dev, gfp_t gfp,
const char *fmt, va_list ap) __malloc; const char *fmt, va_list ap) __malloc;
__printf(3, 4) char *devm_kasprintf(struct device *dev, gfp_t gfp, __printf(3, 4) char *devm_kasprintf(struct device *dev, gfp_t gfp,
...@@ -292,62 +294,6 @@ struct device_dma_parameters { ...@@ -292,62 +294,6 @@ struct device_dma_parameters {
unsigned long segment_boundary_mask; unsigned long segment_boundary_mask;
}; };
/**
* struct device_connection - Device Connection Descriptor
* @fwnode: The device node of the connected device
* @endpoint: The names of the two devices connected together
* @id: Unique identifier for the connection
* @list: List head, private, for internal use only
*
* NOTE: @fwnode is not used together with @endpoint. @fwnode is used when
* platform firmware defines the connection. When the connection is registered
* with device_connection_add() @endpoint is used instead.
*/
struct device_connection {
struct fwnode_handle *fwnode;
const char *endpoint[2];
const char *id;
struct list_head list;
};
typedef void *(*devcon_match_fn_t)(struct device_connection *con, int ep,
void *data);
void *fwnode_connection_find_match(struct fwnode_handle *fwnode,
const char *con_id, void *data,
devcon_match_fn_t match);
void *device_connection_find_match(struct device *dev, const char *con_id,
void *data, devcon_match_fn_t match);
struct device *device_connection_find(struct device *dev, const char *con_id);
void device_connection_add(struct device_connection *con);
void device_connection_remove(struct device_connection *con);
/**
* device_connections_add - Add multiple device connections at once
* @cons: Zero terminated array of device connection descriptors
*/
static inline void device_connections_add(struct device_connection *cons)
{
struct device_connection *c;
for (c = cons; c->endpoint[0]; c++)
device_connection_add(c);
}
/**
* device_connections_remove - Remove multiple device connections at once
* @cons: Zero terminated array of device connection descriptors
*/
static inline void device_connections_remove(struct device_connection *cons)
{
struct device_connection *c;
for (c = cons; c->endpoint[0]; c++)
device_connection_remove(c);
}
/** /**
* enum device_link_state - Device link states. * enum device_link_state - Device link states.
* @DL_STATE_NONE: The presence of the drivers is not being tracked. * @DL_STATE_NONE: The presence of the drivers is not being tracked.
......
...@@ -129,7 +129,7 @@ void __unmap_hugepage_range(struct mmu_gather *tlb, struct vm_area_struct *vma, ...@@ -129,7 +129,7 @@ void __unmap_hugepage_range(struct mmu_gather *tlb, struct vm_area_struct *vma,
unsigned long start, unsigned long end, unsigned long start, unsigned long end,
struct page *ref_page); struct page *ref_page);
void hugetlb_report_meminfo(struct seq_file *); void hugetlb_report_meminfo(struct seq_file *);
int hugetlb_report_node_meminfo(int, char *); int hugetlb_report_node_meminfo(char *buf, int len, int nid);
void hugetlb_show_meminfo(void); void hugetlb_show_meminfo(void);
unsigned long hugetlb_total_pages(void); unsigned long hugetlb_total_pages(void);
vm_fault_t hugetlb_fault(struct mm_struct *mm, struct vm_area_struct *vma, vm_fault_t hugetlb_fault(struct mm_struct *mm, struct vm_area_struct *vma,
...@@ -245,7 +245,7 @@ static inline void hugetlb_report_meminfo(struct seq_file *m) ...@@ -245,7 +245,7 @@ static inline void hugetlb_report_meminfo(struct seq_file *m)
{ {
} }
static inline int hugetlb_report_node_meminfo(int nid, char *buf) static inline int hugetlb_report_node_meminfo(char *buf, int len, int nid)
{ {
return 0; return 0;
} }
......
...@@ -431,6 +431,20 @@ fwnode_graph_get_endpoint_by_id(const struct fwnode_handle *fwnode, ...@@ -431,6 +431,20 @@ fwnode_graph_get_endpoint_by_id(const struct fwnode_handle *fwnode,
int fwnode_graph_parse_endpoint(const struct fwnode_handle *fwnode, int fwnode_graph_parse_endpoint(const struct fwnode_handle *fwnode,
struct fwnode_endpoint *endpoint); struct fwnode_endpoint *endpoint);
typedef void *(*devcon_match_fn_t)(struct fwnode_handle *fwnode, const char *id,
void *data);
void *fwnode_connection_find_match(struct fwnode_handle *fwnode,
const char *con_id, void *data,
devcon_match_fn_t match);
static inline void *device_connection_find_match(struct device *dev,
const char *con_id, void *data,
devcon_match_fn_t match)
{
return fwnode_connection_find_match(dev_fwnode(dev), con_id, data, match);
}
/* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */
/* Software fwnode support - when HW description is incomplete or missing */ /* Software fwnode support - when HW description is incomplete or missing */
......
...@@ -329,6 +329,10 @@ int sysfs_groups_change_owner(struct kobject *kobj, ...@@ -329,6 +329,10 @@ int sysfs_groups_change_owner(struct kobject *kobj,
int sysfs_group_change_owner(struct kobject *kobj, int sysfs_group_change_owner(struct kobject *kobj,
const struct attribute_group *groups, kuid_t kuid, const struct attribute_group *groups, kuid_t kuid,
kgid_t kgid); kgid_t kgid);
__printf(2, 3)
int sysfs_emit(char *buf, const char *fmt, ...);
__printf(3, 4)
int sysfs_emit_at(char *buf, int at, const char *fmt, ...);
#else /* CONFIG_SYSFS */ #else /* CONFIG_SYSFS */
...@@ -576,6 +580,17 @@ static inline int sysfs_group_change_owner(struct kobject *kobj, ...@@ -576,6 +580,17 @@ static inline int sysfs_group_change_owner(struct kobject *kobj,
return 0; return 0;
} }
__printf(2, 3)
static inline int sysfs_emit(char *buf, const char *fmt, ...)
{
return 0;
}
__printf(3, 4)
static inline int sysfs_emit_at(char *buf, int at, const char *fmt, ...)
{
return 0;
}
#endif /* CONFIG_SYSFS */ #endif /* CONFIG_SYSFS */
static inline int __must_check sysfs_create_file(struct kobject *kobj, static inline int __must_check sysfs_create_file(struct kobject *kobj,
......
...@@ -162,13 +162,15 @@ __devm_ioremap_resource(struct device *dev, const struct resource *res, ...@@ -162,13 +162,15 @@ __devm_ioremap_resource(struct device *dev, const struct resource *res,
* region and ioremaps it. All operations are managed and will be undone * region and ioremaps it. All operations are managed and will be undone
* on driver detach. * on driver detach.
* *
* Returns a pointer to the remapped memory or an ERR_PTR() encoded error code * Usage example:
* on failure. Usage example:
* *
* res = platform_get_resource(pdev, IORESOURCE_MEM, 0); * res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
* base = devm_ioremap_resource(&pdev->dev, res); * base = devm_ioremap_resource(&pdev->dev, res);
* if (IS_ERR(base)) * if (IS_ERR(base))
* return PTR_ERR(base); * return PTR_ERR(base);
*
* Return: a pointer to the remapped memory or an ERR_PTR() encoded error code
* on failure.
*/ */
void __iomem *devm_ioremap_resource(struct device *dev, void __iomem *devm_ioremap_resource(struct device *dev,
const struct resource *res) const struct resource *res)
...@@ -183,8 +185,8 @@ EXPORT_SYMBOL(devm_ioremap_resource); ...@@ -183,8 +185,8 @@ EXPORT_SYMBOL(devm_ioremap_resource);
* @dev: generic device to handle the resource for * @dev: generic device to handle the resource for
* @res: resource to be handled * @res: resource to be handled
* *
* Returns a pointer to the remapped memory or an ERR_PTR() encoded error code * Return: a pointer to the remapped memory or an ERR_PTR() encoded error code
* on failure. Usage example: * on failure.
*/ */
void __iomem *devm_ioremap_resource_wc(struct device *dev, void __iomem *devm_ioremap_resource_wc(struct device *dev,
const struct resource *res) const struct resource *res)
...@@ -207,8 +209,8 @@ void __iomem *devm_ioremap_resource_wc(struct device *dev, ...@@ -207,8 +209,8 @@ void __iomem *devm_ioremap_resource_wc(struct device *dev,
* @node: The device-tree node where the resource resides * @node: The device-tree node where the resource resides
* @index: index of the MMIO range in the "reg" property * @index: index of the MMIO range in the "reg" property
* @size: Returns the size of the resource (pass NULL if not needed) * @size: Returns the size of the resource (pass NULL if not needed)
* Returns a pointer to the requested and mapped memory or an ERR_PTR() encoded *
* error code on failure. Usage example: * Usage example:
* *
* base = devm_of_iomap(&pdev->dev, node, 0, NULL); * base = devm_of_iomap(&pdev->dev, node, 0, NULL);
* if (IS_ERR(base)) * if (IS_ERR(base))
...@@ -217,8 +219,10 @@ void __iomem *devm_ioremap_resource_wc(struct device *dev, ...@@ -217,8 +219,10 @@ void __iomem *devm_ioremap_resource_wc(struct device *dev,
* Please Note: This is not a one-to-one replacement for of_iomap() because the * 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 * 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 * two drivers try to map the same memory, the of_iomap() function will succeed
* but the the devm_of_iomap() function will return -EBUSY. * but the devm_of_iomap() function will return -EBUSY.
* *
* Return: a pointer to the requested and mapped memory or an ERR_PTR() encoded
* error code on failure.
*/ */
void __iomem *devm_of_iomap(struct device *dev, struct device_node *node, int index, void __iomem *devm_of_iomap(struct device *dev, struct device_node *node, int index,
resource_size_t *size) resource_size_t *size)
...@@ -256,6 +260,8 @@ static int devm_ioport_map_match(struct device *dev, void *res, ...@@ -256,6 +260,8 @@ static int devm_ioport_map_match(struct device *dev, void *res,
* *
* Managed ioport_map(). Map is automatically unmapped on driver * Managed ioport_map(). Map is automatically unmapped on driver
* detach. * detach.
*
* Return: a pointer to the remapped memory or NULL on failure.
*/ */
void __iomem *devm_ioport_map(struct device *dev, unsigned long port, void __iomem *devm_ioport_map(struct device *dev, unsigned long port,
unsigned int nr) unsigned int nr)
......
...@@ -384,10 +384,13 @@ static int ddebug_parse_query(char *words[], int nwords, ...@@ -384,10 +384,13 @@ static int ddebug_parse_query(char *words[], int nwords,
query->module = modname; query->module = modname;
for (i = 0; i < nwords; i += 2) { for (i = 0; i < nwords; i += 2) {
if (!strcmp(words[i], "func")) { char *keyword = words[i];
rc = check_set(&query->function, words[i+1], "func"); char *arg = words[i+1];
} else if (!strcmp(words[i], "file")) {
if (check_set(&query->filename, words[i+1], "file")) if (!strcmp(keyword, "func")) {
rc = check_set(&query->function, arg, "func");
} else if (!strcmp(keyword, "file")) {
if (check_set(&query->filename, arg, "file"))
return -EINVAL; return -EINVAL;
/* tail :$info is function or line-range */ /* tail :$info is function or line-range */
...@@ -403,18 +406,18 @@ static int ddebug_parse_query(char *words[], int nwords, ...@@ -403,18 +406,18 @@ static int ddebug_parse_query(char *words[], int nwords,
if (parse_linerange(query, fline)) if (parse_linerange(query, fline))
return -EINVAL; return -EINVAL;
} }
} else if (!strcmp(words[i], "module")) { } else if (!strcmp(keyword, "module")) {
rc = check_set(&query->module, words[i+1], "module"); rc = check_set(&query->module, arg, "module");
} else if (!strcmp(words[i], "format")) { } else if (!strcmp(keyword, "format")) {
string_unescape_inplace(words[i+1], UNESCAPE_SPACE | string_unescape_inplace(arg, UNESCAPE_SPACE |
UNESCAPE_OCTAL | UNESCAPE_OCTAL |
UNESCAPE_SPECIAL); UNESCAPE_SPECIAL);
rc = check_set(&query->format, words[i+1], "format"); rc = check_set(&query->format, arg, "format");
} else if (!strcmp(words[i], "line")) { } else if (!strcmp(keyword, "line")) {
if (parse_linerange(query, words[i+1])) if (parse_linerange(query, arg))
return -EINVAL; return -EINVAL;
} else { } else {
pr_err("unknown keyword \"%s\"\n", words[i]); pr_err("unknown keyword \"%s\"\n", keyword);
return -EINVAL; return -EINVAL;
} }
if (rc) if (rc)
......
...@@ -3571,18 +3571,20 @@ void hugetlb_report_meminfo(struct seq_file *m) ...@@ -3571,18 +3571,20 @@ void hugetlb_report_meminfo(struct seq_file *m)
seq_printf(m, "Hugetlb: %8lu kB\n", total / 1024); seq_printf(m, "Hugetlb: %8lu kB\n", total / 1024);
} }
int hugetlb_report_node_meminfo(int nid, char *buf) int hugetlb_report_node_meminfo(char *buf, int len, int nid)
{ {
struct hstate *h = &default_hstate; struct hstate *h = &default_hstate;
if (!hugepages_supported()) if (!hugepages_supported())
return 0; return 0;
return sprintf(buf,
"Node %d HugePages_Total: %5u\n" return sysfs_emit_at(buf, len,
"Node %d HugePages_Free: %5u\n" "Node %d HugePages_Total: %5u\n"
"Node %d HugePages_Surp: %5u\n", "Node %d HugePages_Free: %5u\n"
nid, h->nr_huge_pages_node[nid], "Node %d HugePages_Surp: %5u\n",
nid, h->free_huge_pages_node[nid], nid, h->nr_huge_pages_node[nid],
nid, h->surplus_huge_pages_node[nid]); nid, h->free_huge_pages_node[nid],
nid, h->surplus_huge_pages_node[nid]);
} }
void hugetlb_show_meminfo(void) void hugetlb_show_meminfo(void)
......
#! /bin/sh
# SPDX-License-Identifier: GPL-2.0
# Copyright (c) 2020, Google LLC. All rights reserved.
# Author: Saravana Kannan <saravanak@google.com>
function help() {
cat << EOF
Usage: $(basename $0) [-c|-d|-m|-f] [filter options] <list of devices>
This script needs to be run on the target device once it has booted to a
shell.
The script takes as input a list of one or more device directories under
/sys/devices and then lists the probe dependency chain (suppliers and
parents) of these devices. It does a breadth first search of the dependency
chain, so the last entry in the output is close to the root of the
dependency chain.
By default it lists the full path to the devices under /sys/devices.
It also takes an optional modifier flag as the first parameter to change
what information is listed in the output. If the requested information is
not available, the device name is printed.
-c lists the compatible string of the dependencies
-d lists the driver name of the dependencies that have probed
-m lists the module name of the dependencies that have a module
-f list the firmware node path of the dependencies
-g list the dependencies as edges and nodes for graphviz
-t list the dependencies as edges for tsort
The filter options provide a way to filter out some dependencies:
--allow-no-driver By default dependencies that don't have a driver
attached are ignored. This is to avoid following
device links to "class" devices that are created
when the consumer probes (as in, not a probe
dependency). If you want to follow these links
anyway, use this flag.
--exclude-devlinks Don't follow device links when tracking probe
dependencies.
--exclude-parents Don't follow parent devices when tracking probe
dependencies.
EOF
}
function dev_to_detail() {
local i=0
while [ $i -lt ${#OUT_LIST[@]} ]
do
local C=${OUT_LIST[i]}
local S=${OUT_LIST[i+1]}
local D="'$(detail_chosen $C $S)'"
if [ ! -z "$D" ]
then
# This weirdness is needed to work with toybox when
# using the -t option.
printf '%05u\t%s\n' ${i} "$D" | tr -d \'
fi
i=$((i+2))
done
}
function already_seen() {
local i=0
while [ $i -lt ${#OUT_LIST[@]} ]
do
if [ "$1" = "${OUT_LIST[$i]}" ]
then
# if-statement treats 0 (no-error) as true
return 0
fi
i=$(($i+2))
done
# if-statement treats 1 (error) as false
return 1
}
# Return 0 (no-error/true) if parent was added
function add_parent() {
if [ ${ALLOW_PARENTS} -eq 0 ]
then
return 1
fi
local CON=$1
# $CON could be a symlink path. So, we need to find the real path and
# then go up one level to find the real parent.
local PARENT=$(realpath $CON/..)
while [ ! -e ${PARENT}/driver ]
do
if [ "$PARENT" = "/sys/devices" ]
then
return 1
fi
PARENT=$(realpath $PARENT/..)
done
CONSUMERS+=($PARENT)
OUT_LIST+=(${CON} ${PARENT})
return 0
}
# Return 0 (no-error/true) if one or more suppliers were added
function add_suppliers() {
local CON=$1
local RET=1
if [ ${ALLOW_DEVLINKS} -eq 0 ]
then
return 1
fi
SUPPLIER_LINKS=$(ls -1d $CON/supplier:* 2>/dev/null)
for SL in $SUPPLIER_LINKS;
do
SYNC_STATE=$(cat $SL/sync_state_only)
# sync_state_only links are proxy dependencies.
# They can also have cycles. So, don't follow them.
if [ "$SYNC_STATE" != '0' ]
then
continue
fi
SUPPLIER=$(realpath $SL/supplier)
if [ ! -e $SUPPLIER/driver -a ${ALLOW_NO_DRIVER} -eq 0 ]
then
continue
fi
CONSUMERS+=($SUPPLIER)
OUT_LIST+=(${CON} ${SUPPLIER})
RET=0
done
return $RET
}
function detail_compat() {
f=$1/of_node/compatible
if [ -e $f ]
then
echo -n $(cat $f)
else
echo -n $1
fi
}
function detail_module() {
f=$1/driver/module
if [ -e $f ]
then
echo -n $(basename $(realpath $f))
else
echo -n $1
fi
}
function detail_driver() {
f=$1/driver
if [ -e $f ]
then
echo -n $(basename $(realpath $f))
else
echo -n $1
fi
}
function detail_fwnode() {
f=$1/firmware_node
if [ ! -e $f ]
then
f=$1/of_node
fi
if [ -e $f ]
then
echo -n $(realpath $f)
else
echo -n $1
fi
}
function detail_graphviz() {
if [ "$2" != "ROOT" ]
then
echo -n "\"$(basename $2)\"->\"$(basename $1)\""
else
echo -n "\"$(basename $1)\""
fi
}
function detail_tsort() {
echo -n "\"$2\" \"$1\""
}
function detail_device() { echo -n $1; }
alias detail=detail_device
ALLOW_NO_DRIVER=0
ALLOW_DEVLINKS=1
ALLOW_PARENTS=1
while [ $# -gt 0 ]
do
ARG=$1
case $ARG in
--help)
help
exit 0
;;
-c)
alias detail=detail_compat
;;
-m)
alias detail=detail_module
;;
-d)
alias detail=detail_driver
;;
-f)
alias detail=detail_fwnode
;;
-g)
alias detail=detail_graphviz
;;
-t)
alias detail=detail_tsort
;;
--allow-no-driver)
ALLOW_NO_DRIVER=1
;;
--exclude-devlinks)
ALLOW_DEVLINKS=0
;;
--exclude-parents)
ALLOW_PARENTS=0
;;
*)
# Stop at the first argument that's not an option.
break
;;
esac
shift
done
function detail_chosen() {
detail $1 $2
}
if [ $# -eq 0 ]
then
help
exit 1
fi
CONSUMERS=($@)
OUT_LIST=()
# Do a breadth first, non-recursive tracking of suppliers. The parent is also
# considered a "supplier" as a device can't probe without its parent.
i=0
while [ $i -lt ${#CONSUMERS[@]} ]
do
CONSUMER=$(realpath ${CONSUMERS[$i]})
i=$(($i+1))
if already_seen ${CONSUMER}
then
continue
fi
# If this is not a device with a driver, we don't care about its
# suppliers.
if [ ! -e ${CONSUMER}/driver -a ${ALLOW_NO_DRIVER} -eq 0 ]
then
continue
fi
ROOT=1
# Add suppliers to CONSUMERS list and output the consumer details.
#
# We don't need to worry about a cycle in the dependency chain causing
# infinite loops. That's because the kernel doesn't allow cycles in
# device links unless it's a sync_state_only device link. And we ignore
# sync_state_only device links inside add_suppliers.
if add_suppliers ${CONSUMER}
then
ROOT=0
fi
if add_parent ${CONSUMER}
then
ROOT=0
fi
if [ $ROOT -eq 1 ]
then
OUT_LIST+=(${CONSUMER} "ROOT")
fi
done
# Can NOT combine sort and uniq using sort -suk2 because stable sort in toybox
# isn't really stable.
dev_to_detail | sort -k2 -k1 | uniq -f 1 | sort | cut -f2-
exit 0
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment