mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/next/linux-next.git
synced 2025-01-07 14:32:23 +00:00
Driver Core patches for 5.10-rc1
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. Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> -----BEGIN PGP SIGNATURE----- iG0EABECAC0WIQT0tgzFv3jCIUoxPcsxR9QN2y37KQUCX4c4yA8cZ3JlZ0Brcm9h aC5jb20ACgkQMUfUDdst+ylS7gCfcS+7/PE42eXxMY0z8rBX8aDMadIAn2DVEghA Eoh9UoMEW4g1uMKORA0c =CVAW -----END PGP SIGNATURE----- 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}() ...
This commit is contained in:
commit
fe151462bd
@ -1,43 +0,0 @@
|
||||
==================
|
||||
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
|
||||
devm_kmalloc()
|
||||
devm_kmalloc_array()
|
||||
devm_kmemdup()
|
||||
devm_krealloc()
|
||||
devm_kstrdup()
|
||||
devm_kvasprintf()
|
||||
devm_kzalloc()
|
||||
|
@ -42,6 +42,7 @@ fallback mechanism:
|
||||
supported for request_firmware_into_buf().
|
||||
|
||||
* Firmware is not accessible through typical means:
|
||||
|
||||
* It cannot be installed into the root filesystem
|
||||
* The firmware provides very unique device specific data tailored for
|
||||
the unit gathered with local information. An example is calibration
|
||||
|
@ -22,7 +22,6 @@ available subsections can be seen below.
|
||||
pm/index
|
||||
clk
|
||||
device-io
|
||||
device_connection
|
||||
dma-buf
|
||||
device_link
|
||||
component
|
||||
|
@ -241,12 +241,10 @@ Other notes:
|
||||
is 4096.
|
||||
|
||||
- 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
|
||||
returned to user space. If you can guarantee that an overflow
|
||||
will never happen you can use sprintf() otherwise you must use
|
||||
scnprintf().
|
||||
- show() should only use sysfs_emit() or sysfs_emit_at() when formatting
|
||||
the value to be returned to user space.
|
||||
|
||||
- store() should return the number of bytes used from the buffer. If the
|
||||
entire buffer has been used, just return the count argument.
|
||||
|
@ -5023,6 +5023,12 @@ S: Maintained
|
||||
F: drivers/base/devcoredump.c
|
||||
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)
|
||||
M: Dan Williams <dan.j.williams@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 \
|
||||
cpu.o firmware.o init.o map.o devres.o \
|
||||
attribute_container.o transport_class.o \
|
||||
topology.o container.o property.o cacheinfo.o \
|
||||
devcon.o swnode.o
|
||||
swnode.o
|
||||
obj-$(CONFIG_DEVTMPFS) += devtmpfs.o
|
||||
obj-y += power/
|
||||
obj-$(CONFIG_ISA_BUS_API) += isa.o
|
||||
|
@ -80,7 +80,7 @@ static ssize_t cpu_capacity_show(struct device *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);
|
||||
|
@ -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)
|
||||
{
|
||||
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,
|
||||
|
@ -362,7 +362,7 @@ static ssize_t file_name##_show(struct device *dev, \
|
||||
struct device_attribute *attr, char *buf) \
|
||||
{ \
|
||||
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);
|
||||
@ -377,44 +377,48 @@ static ssize_t size_show(struct device *dev,
|
||||
{
|
||||
struct cacheinfo *this_leaf = dev_get_drvdata(dev);
|
||||
|
||||
return sprintf(buf, "%uK\n", this_leaf->size >> 10);
|
||||
}
|
||||
|
||||
static ssize_t shared_cpumap_show_func(struct device *dev, bool list, char *buf)
|
||||
{
|
||||
struct cacheinfo *this_leaf = dev_get_drvdata(dev);
|
||||
const struct cpumask *mask = &this_leaf->shared_cpu_map;
|
||||
|
||||
return cpumap_print_to_pagebuf(list, buf, mask);
|
||||
return sysfs_emit(buf, "%uK\n", this_leaf->size >> 10);
|
||||
}
|
||||
|
||||
static ssize_t shared_cpu_map_show(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
return shared_cpumap_show_func(dev, false, buf);
|
||||
struct cacheinfo *this_leaf = dev_get_drvdata(dev);
|
||||
const struct cpumask *mask = &this_leaf->shared_cpu_map;
|
||||
|
||||
return sysfs_emit(buf, "%*pb\n", nr_cpu_ids, mask);
|
||||
}
|
||||
|
||||
static ssize_t shared_cpu_list_show(struct device *dev,
|
||||
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,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct cacheinfo *this_leaf = dev_get_drvdata(dev);
|
||||
const char *output;
|
||||
|
||||
switch (this_leaf->type) {
|
||||
case CACHE_TYPE_DATA:
|
||||
return sprintf(buf, "Data\n");
|
||||
output = "Data";
|
||||
break;
|
||||
case CACHE_TYPE_INST:
|
||||
return sprintf(buf, "Instruction\n");
|
||||
output = "Instruction";
|
||||
break;
|
||||
case CACHE_TYPE_UNIFIED:
|
||||
return sprintf(buf, "Unified\n");
|
||||
output = "Unified";
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return sysfs_emit(buf, "%s\n", output);
|
||||
}
|
||||
|
||||
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);
|
||||
unsigned int ci_attr = this_leaf->attributes;
|
||||
int n = 0;
|
||||
const char *output;
|
||||
|
||||
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)
|
||||
n = sprintf(buf, "ReadAllocate\n");
|
||||
output = "ReadAllocate";
|
||||
else if (ci_attr & CACHE_WRITE_ALLOCATE)
|
||||
n = sprintf(buf, "WriteAllocate\n");
|
||||
return n;
|
||||
output = "WriteAllocate";
|
||||
else
|
||||
return 0;
|
||||
|
||||
return sysfs_emit(buf, "%s\n", output);
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
if (ci_attr & CACHE_WRITE_THROUGH)
|
||||
n = sprintf(buf, "WriteThrough\n");
|
||||
n = sysfs_emit(buf, "WriteThrough\n");
|
||||
else if (ci_attr & CACHE_WRITE_BACK)
|
||||
n = sprintf(buf, "WriteBack\n");
|
||||
n = sysfs_emit(buf, "WriteBack\n");
|
||||
return n;
|
||||
}
|
||||
|
||||
|
@ -478,7 +478,7 @@ ssize_t show_class_attr_string(struct class *class,
|
||||
struct class_attribute_string *cs;
|
||||
|
||||
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);
|
||||
|
@ -26,6 +26,7 @@
|
||||
#include <linux/pm_runtime.h>
|
||||
#include <linux/netdevice.h>
|
||||
#include <linux/sched/signal.h>
|
||||
#include <linux/sched/mm.h>
|
||||
#include <linux/sysfs.h>
|
||||
|
||||
#include "base.h"
|
||||
@ -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)
|
||||
|
||||
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) {
|
||||
case DL_STATE_NONE:
|
||||
status = "not tracked"; break;
|
||||
output = "not tracked";
|
||||
break;
|
||||
case DL_STATE_DORMANT:
|
||||
status = "dormant"; break;
|
||||
output = "dormant";
|
||||
break;
|
||||
case DL_STATE_AVAILABLE:
|
||||
status = "available"; break;
|
||||
output = "available";
|
||||
break;
|
||||
case DL_STATE_CONSUMER_PROBE:
|
||||
status = "consumer probing"; break;
|
||||
output = "consumer probing";
|
||||
break;
|
||||
case DL_STATE_ACTIVE:
|
||||
status = "active"; break;
|
||||
output = "active";
|
||||
break;
|
||||
case DL_STATE_SUPPLIER_UNBIND:
|
||||
status = "supplier unbinding"; break;
|
||||
output = "supplier unbinding";
|
||||
break;
|
||||
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);
|
||||
|
||||
@ -267,16 +276,16 @@ static ssize_t auto_remove_on_show(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct device_link *link = to_devlink(dev);
|
||||
char *str;
|
||||
const char *output;
|
||||
|
||||
if (link->flags & DL_FLAG_AUTOREMOVE_SUPPLIER)
|
||||
str = "supplier unbind";
|
||||
output = "supplier unbind";
|
||||
else if (link->flags & DL_FLAG_AUTOREMOVE_CONSUMER)
|
||||
str = "consumer unbind";
|
||||
output = "consumer unbind";
|
||||
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);
|
||||
|
||||
@ -285,7 +294,7 @@ static ssize_t runtime_pm_show(struct device *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);
|
||||
|
||||
@ -294,7 +303,8 @@ static ssize_t sync_state_only_show(struct device *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);
|
||||
|
||||
@ -1059,7 +1069,7 @@ static ssize_t waiting_for_supplier_show(struct device *dev,
|
||||
&& dev->links.need_for_probe;
|
||||
mutex_unlock(&wfs_lock);
|
||||
device_unlock(dev);
|
||||
return sprintf(buf, "%u\n", val);
|
||||
return sysfs_emit(buf, "%u\n", val);
|
||||
}
|
||||
static DEVICE_ATTR_RO(waiting_for_supplier);
|
||||
|
||||
@ -1709,7 +1719,7 @@ ssize_t device_show_ulong(struct device *dev,
|
||||
char *buf)
|
||||
{
|
||||
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);
|
||||
|
||||
@ -1739,7 +1749,7 @@ ssize_t device_show_int(struct device *dev,
|
||||
{
|
||||
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);
|
||||
|
||||
@ -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);
|
||||
|
||||
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);
|
||||
|
||||
@ -1932,7 +1942,7 @@ static ssize_t uevent_show(struct device *dev, struct device_attribute *attr,
|
||||
struct kset *kset;
|
||||
struct kobj_uevent_env *env = NULL;
|
||||
int i;
|
||||
size_t count = 0;
|
||||
int len = 0;
|
||||
int retval;
|
||||
|
||||
/* search the kset, the device belongs to */
|
||||
@ -1962,10 +1972,10 @@ static ssize_t uevent_show(struct device *dev, struct device_attribute *attr,
|
||||
|
||||
/* copy keys to file */
|
||||
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:
|
||||
kfree(env);
|
||||
return count;
|
||||
return len;
|
||||
}
|
||||
|
||||
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,
|
||||
device_lock(dev);
|
||||
val = !dev->offline;
|
||||
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,
|
||||
@ -3062,6 +3072,7 @@ void device_del(struct device *dev)
|
||||
struct device *parent = dev->parent;
|
||||
struct kobject *glue_dir = NULL;
|
||||
struct class_interface *class_intf;
|
||||
unsigned int noio_flag;
|
||||
|
||||
device_lock(dev);
|
||||
kill_device(dev);
|
||||
@ -3073,6 +3084,7 @@ void device_del(struct device *dev)
|
||||
/* Notify clients of device removal. This call must come
|
||||
* before dpm_sysfs_remove().
|
||||
*/
|
||||
noio_flag = memalloc_noio_save();
|
||||
if (dev->bus)
|
||||
blocking_notifier_call_chain(&dev->bus->p->bus_notifier,
|
||||
BUS_NOTIFY_DEL_DEVICE, dev);
|
||||
@ -3114,6 +3126,7 @@ void device_del(struct device *dev)
|
||||
glue_dir = get_glue_dir(dev);
|
||||
kobject_del(&dev->kobj);
|
||||
cleanup_glue_dir(dev, glue_dir);
|
||||
memalloc_noio_restore(noio_flag);
|
||||
put_device(parent);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(device_del);
|
||||
|
@ -139,11 +139,11 @@ EXPORT_SYMBOL_GPL(cpu_subsys);
|
||||
#ifdef CONFIG_KEXEC
|
||||
#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)
|
||||
{
|
||||
struct cpu *cpu = container_of(dev, struct cpu, dev);
|
||||
ssize_t rc;
|
||||
unsigned long long addr;
|
||||
int cpunum;
|
||||
|
||||
@ -156,21 +156,18 @@ static ssize_t show_crash_notes(struct device *dev, struct device_attribute *att
|
||||
* operation should be safe. No locking required.
|
||||
*/
|
||||
addr = per_cpu_ptr_to_phys(per_cpu_ptr(crash_notes, cpunum));
|
||||
rc = sprintf(buf, "%Lx\n", addr);
|
||||
return rc;
|
||||
}
|
||||
static DEVICE_ATTR(crash_notes, 0400, show_crash_notes, NULL);
|
||||
|
||||
static ssize_t show_crash_notes_size(struct device *dev,
|
||||
return sysfs_emit(buf, "%llx\n", addr);
|
||||
}
|
||||
static DEVICE_ATTR_ADMIN_RO(crash_notes);
|
||||
|
||||
static ssize_t crash_notes_size_show(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
ssize_t rc;
|
||||
|
||||
rc = sprintf(buf, "%zu\n", sizeof(note_buf_t));
|
||||
return rc;
|
||||
return sysfs_emit(buf, "%zu\n", sizeof(note_buf_t));
|
||||
}
|
||||
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[] = {
|
||||
&dev_attr_crash_notes.attr,
|
||||
@ -231,7 +228,7 @@ static struct cpu_attr cpu_attrs[] = {
|
||||
static ssize_t print_cpus_kernel_max(struct device *dev,
|
||||
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);
|
||||
|
||||
@ -241,37 +238,37 @@ unsigned int total_cpus;
|
||||
static ssize_t print_cpus_offline(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
int n = 0, len = PAGE_SIZE-2;
|
||||
int len = 0;
|
||||
cpumask_var_t offline;
|
||||
|
||||
/* display offline cpus < nr_cpu_ids */
|
||||
if (!alloc_cpumask_var(&offline, GFP_KERNEL))
|
||||
return -ENOMEM;
|
||||
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);
|
||||
|
||||
/* display offline cpus >= nr_cpu_ids */
|
||||
if (total_cpus && nr_cpu_ids < total_cpus) {
|
||||
if (n && n < len)
|
||||
buf[n++] = ',';
|
||||
len += sysfs_emit_at(buf, len, ",");
|
||||
|
||||
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
|
||||
n += scnprintf(&buf[n], len - n, "%u-%d",
|
||||
nr_cpu_ids, total_cpus-1);
|
||||
len += sysfs_emit_at(buf, len, "%u-%d",
|
||||
nr_cpu_ids, total_cpus - 1);
|
||||
}
|
||||
|
||||
n += scnprintf(&buf[n], len - n, "\n");
|
||||
return n;
|
||||
len += sysfs_emit_at(buf, len, "\n");
|
||||
|
||||
return len;
|
||||
}
|
||||
static DEVICE_ATTR(offline, 0444, print_cpus_offline, NULL);
|
||||
|
||||
static ssize_t print_cpus_isolated(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
int n;
|
||||
int len;
|
||||
cpumask_var_t isolated;
|
||||
|
||||
if (!alloc_cpumask_var(&isolated, GFP_KERNEL))
|
||||
@ -279,19 +276,19 @@ static ssize_t print_cpus_isolated(struct device *dev,
|
||||
|
||||
cpumask_andnot(isolated, cpu_possible_mask,
|
||||
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);
|
||||
|
||||
return n;
|
||||
return len;
|
||||
}
|
||||
static DEVICE_ATTR(isolated, 0444, print_cpus_isolated, NULL);
|
||||
|
||||
#ifdef CONFIG_NO_HZ_FULL
|
||||
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);
|
||||
#endif
|
||||
@ -320,22 +317,23 @@ static ssize_t print_cpu_modalias(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
ssize_t n;
|
||||
int len = 0;
|
||||
u32 i;
|
||||
|
||||
n = sprintf(buf, "cpu:type:" CPU_FEATURE_TYPEFMT ":feature:",
|
||||
CPU_FEATURE_TYPEVAL);
|
||||
len += sysfs_emit_at(buf, len,
|
||||
"cpu:type:" CPU_FEATURE_TYPEFMT ":feature:",
|
||||
CPU_FEATURE_TYPEVAL);
|
||||
|
||||
for (i = 0; i < MAX_CPU_FEATURES; 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");
|
||||
break;
|
||||
}
|
||||
n += sprintf(&buf[n], ",%04X", i);
|
||||
len += sysfs_emit_at(buf, len, ",%04X", i);
|
||||
}
|
||||
buf[n++] = '\n';
|
||||
return n;
|
||||
len += sysfs_emit_at(buf, len, "\n");
|
||||
return len;
|
||||
}
|
||||
|
||||
static int cpu_uevent(struct device *dev, struct kobj_uevent_env *env)
|
||||
@ -516,56 +514,56 @@ static void __init cpu_dev_register_generic(void)
|
||||
ssize_t __weak cpu_show_meltdown(struct device *dev,
|
||||
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,
|
||||
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,
|
||||
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,
|
||||
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,
|
||||
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,
|
||||
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,
|
||||
struct device_attribute *attr,
|
||||
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,
|
||||
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,
|
||||
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);
|
||||
|
@ -486,7 +486,8 @@ static ssize_t state_synced_show(struct device *dev,
|
||||
device_lock(dev);
|
||||
val = dev->state_synced;
|
||||
device_unlock(dev);
|
||||
return sprintf(buf, "%u\n", val);
|
||||
|
||||
return sysfs_emit(buf, "%u\n", val);
|
||||
}
|
||||
static DEVICE_ATTR_RO(state_synced);
|
||||
|
||||
@ -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)
|
||||
{
|
||||
ktime_t calltime, delta, rettime;
|
||||
ktime_t calltime, rettime;
|
||||
int ret;
|
||||
|
||||
calltime = ktime_get();
|
||||
ret = really_probe(dev, drv);
|
||||
rettime = ktime_get();
|
||||
delta = ktime_sub(rettime, calltime);
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -1,231 +0,0 @@
|
||||
// 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)
|
||||
static ssize_t disabled_show(struct class *class, struct class_attribute *attr,
|
||||
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,
|
||||
|
@ -126,6 +126,14 @@ static void add_dr(struct device *dev, struct devres_node *node)
|
||||
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
|
||||
void * __devres_alloc_node(dr_release_t release, size_t size, gfp_t gfp, int nid,
|
||||
const char *name)
|
||||
@ -837,6 +845,103 @@ void *devm_kmalloc(struct device *dev, size_t size, gfp_t gfp)
|
||||
}
|
||||
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
|
||||
* copy an existing string into that.
|
||||
|
@ -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,
|
||||
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,
|
||||
loading = fw_sysfs_loading(fw_sysfs->fw_priv);
|
||||
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,
|
||||
unsigned long phys_index;
|
||||
|
||||
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,
|
||||
static ssize_t removable_show(struct device *dev, struct device_attribute *attr,
|
||||
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,
|
||||
char *buf)
|
||||
{
|
||||
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
|
||||
@ -147,22 +148,20 @@ static ssize_t state_show(struct device *dev, struct device_attribute *attr,
|
||||
*/
|
||||
switch (mem->state) {
|
||||
case MEM_ONLINE:
|
||||
len = sprintf(buf, "online\n");
|
||||
output = "online";
|
||||
break;
|
||||
case MEM_OFFLINE:
|
||||
len = sprintf(buf, "offline\n");
|
||||
output = "offline";
|
||||
break;
|
||||
case MEM_GOING_OFFLINE:
|
||||
len = sprintf(buf, "going-offline\n");
|
||||
output = "going-offline";
|
||||
break;
|
||||
default:
|
||||
len = sprintf(buf, "ERROR-UNKNOWN-%ld\n",
|
||||
mem->state);
|
||||
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)
|
||||
@ -303,21 +302,22 @@ static ssize_t phys_device_show(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
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
|
||||
static void print_allowed_zone(char *buf, int nid, unsigned long start_pfn,
|
||||
unsigned long nr_pages, int online_type,
|
||||
struct zone *default_zone)
|
||||
static int print_allowed_zone(char *buf, int len, int nid,
|
||||
unsigned long start_pfn, unsigned long nr_pages,
|
||||
int online_type, struct zone *default_zone)
|
||||
{
|
||||
struct zone *zone;
|
||||
|
||||
zone = zone_for_pfn_range(online_type, nid, start_pfn, nr_pages);
|
||||
if (zone != default_zone) {
|
||||
strcat(buf, " ");
|
||||
strcat(buf, zone->name);
|
||||
}
|
||||
if (zone == default_zone)
|
||||
return 0;
|
||||
|
||||
return sysfs_emit_at(buf, len, " %s", zone->name);
|
||||
}
|
||||
|
||||
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 nr_pages = PAGES_PER_SECTION * sections_per_block;
|
||||
struct zone *default_zone;
|
||||
int len = 0;
|
||||
int nid;
|
||||
|
||||
/*
|
||||
@ -341,24 +342,23 @@ static ssize_t valid_zones_show(struct device *dev,
|
||||
default_zone = test_pages_in_a_zone(start_pfn,
|
||||
start_pfn + nr_pages);
|
||||
if (!default_zone)
|
||||
return sprintf(buf, "none\n");
|
||||
strcat(buf, default_zone->name);
|
||||
return sysfs_emit(buf, "%s\n", "none");
|
||||
len += sysfs_emit_at(buf, len, "%s", default_zone->name);
|
||||
goto out;
|
||||
}
|
||||
|
||||
nid = mem->nid;
|
||||
default_zone = zone_for_pfn_range(MMOP_ONLINE, nid, start_pfn,
|
||||
nr_pages);
|
||||
strcat(buf, default_zone->name);
|
||||
|
||||
print_allowed_zone(buf, nid, start_pfn, nr_pages, MMOP_ONLINE_KERNEL,
|
||||
default_zone);
|
||||
print_allowed_zone(buf, nid, start_pfn, nr_pages, MMOP_ONLINE_MOVABLE,
|
||||
default_zone);
|
||||
len += sysfs_emit_at(buf, len, "%s", default_zone->name);
|
||||
len += print_allowed_zone(buf, len, nid, start_pfn, nr_pages,
|
||||
MMOP_ONLINE_KERNEL, default_zone);
|
||||
len += print_allowed_zone(buf, len, nid, start_pfn, nr_pages,
|
||||
MMOP_ONLINE_MOVABLE, default_zone);
|
||||
out:
|
||||
strcat(buf, "\n");
|
||||
|
||||
return strlen(buf);
|
||||
len += sysfs_emit_at(buf, len, "\n");
|
||||
return len;
|
||||
}
|
||||
static DEVICE_ATTR_RO(valid_zones);
|
||||
#endif
|
||||
@ -374,7 +374,7 @@ static DEVICE_ATTR_RO(removable);
|
||||
static ssize_t block_size_bytes_show(struct device *dev,
|
||||
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);
|
||||
@ -386,8 +386,8 @@ static DEVICE_ATTR_RO(block_size_bytes);
|
||||
static ssize_t auto_online_blocks_show(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
return sprintf(buf, "%s\n",
|
||||
online_type_to_str[memhp_default_online_type]);
|
||||
return sysfs_emit(buf, "%s\n",
|
||||
online_type_to_str[memhp_default_online_type]);
|
||||
}
|
||||
|
||||
static ssize_t auto_online_blocks_store(struct device *dev,
|
||||
|
@ -46,19 +46,23 @@ static ssize_t node_read_cpumap(struct device *dev, bool list, char *buf)
|
||||
return n;
|
||||
}
|
||||
|
||||
static inline ssize_t node_read_cpumask(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
static inline ssize_t cpumap_show(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
return node_read_cpumap(dev, false, buf);
|
||||
}
|
||||
static inline ssize_t node_read_cpulist(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
|
||||
static DEVICE_ATTR_RO(cpumap);
|
||||
|
||||
static inline ssize_t cpulist_show(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
return node_read_cpumap(dev, true, buf);
|
||||
}
|
||||
|
||||
static DEVICE_ATTR(cpumap, S_IRUGO, node_read_cpumask, NULL);
|
||||
static DEVICE_ATTR(cpulist, S_IRUGO, node_read_cpulist, NULL);
|
||||
static DEVICE_ATTR_RO(cpulist);
|
||||
|
||||
/**
|
||||
* struct node_access_nodes - Access class device to hold user visible
|
||||
@ -153,19 +157,20 @@ static struct node_access_nodes *node_init_node_access(struct node *node,
|
||||
}
|
||||
|
||||
#ifdef CONFIG_HMEM_REPORTING
|
||||
#define ACCESS_ATTR(name) \
|
||||
static ssize_t name##_show(struct device *dev, \
|
||||
struct device_attribute *attr, \
|
||||
char *buf) \
|
||||
{ \
|
||||
return sprintf(buf, "%u\n", to_access_nodes(dev)->hmem_attrs.name); \
|
||||
} \
|
||||
static DEVICE_ATTR_RO(name);
|
||||
#define ACCESS_ATTR(name) \
|
||||
static ssize_t name##_show(struct device *dev, \
|
||||
struct device_attribute *attr, \
|
||||
char *buf) \
|
||||
{ \
|
||||
return sysfs_emit(buf, "%u\n", \
|
||||
to_access_nodes(dev)->hmem_attrs.name); \
|
||||
} \
|
||||
static DEVICE_ATTR_RO(name)
|
||||
|
||||
ACCESS_ATTR(read_bandwidth)
|
||||
ACCESS_ATTR(read_latency)
|
||||
ACCESS_ATTR(write_bandwidth)
|
||||
ACCESS_ATTR(write_latency)
|
||||
ACCESS_ATTR(read_bandwidth);
|
||||
ACCESS_ATTR(read_latency);
|
||||
ACCESS_ATTR(write_bandwidth);
|
||||
ACCESS_ATTR(write_latency);
|
||||
|
||||
static struct attribute *access_attrs[] = {
|
||||
&dev_attr_read_bandwidth.attr,
|
||||
@ -225,7 +230,8 @@ static ssize_t name##_show(struct device *dev, \
|
||||
struct device_attribute *attr, \
|
||||
char *buf) \
|
||||
{ \
|
||||
return sprintf(buf, fmt "\n", to_cache_info(dev)->cache_attrs.name);\
|
||||
return sysfs_emit(buf, fmt "\n", \
|
||||
to_cache_info(dev)->cache_attrs.name); \
|
||||
} \
|
||||
DEVICE_ATTR_RO(name);
|
||||
|
||||
@ -361,7 +367,7 @@ static void node_remove_caches(struct node *node) { }
|
||||
static ssize_t node_read_meminfo(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
int n;
|
||||
int len = 0;
|
||||
int nid = dev->id;
|
||||
struct pglist_data *pgdat = NODE_DATA(nid);
|
||||
struct sysinfo i;
|
||||
@ -370,128 +376,128 @@ static ssize_t node_read_meminfo(struct device *dev,
|
||||
si_meminfo_node(&i, nid);
|
||||
sreclaimable = node_page_state_pages(pgdat, NR_SLAB_RECLAIMABLE_B);
|
||||
sunreclaimable = node_page_state_pages(pgdat, NR_SLAB_UNRECLAIMABLE_B);
|
||||
n = sprintf(buf,
|
||||
"Node %d MemTotal: %8lu kB\n"
|
||||
"Node %d MemFree: %8lu kB\n"
|
||||
"Node %d MemUsed: %8lu kB\n"
|
||||
"Node %d Active: %8lu kB\n"
|
||||
"Node %d Inactive: %8lu kB\n"
|
||||
"Node %d Active(anon): %8lu kB\n"
|
||||
"Node %d Inactive(anon): %8lu kB\n"
|
||||
"Node %d Active(file): %8lu kB\n"
|
||||
"Node %d Inactive(file): %8lu kB\n"
|
||||
"Node %d Unevictable: %8lu kB\n"
|
||||
"Node %d Mlocked: %8lu kB\n",
|
||||
nid, K(i.totalram),
|
||||
nid, K(i.freeram),
|
||||
nid, K(i.totalram - i.freeram),
|
||||
nid, K(node_page_state(pgdat, NR_ACTIVE_ANON) +
|
||||
node_page_state(pgdat, NR_ACTIVE_FILE)),
|
||||
nid, K(node_page_state(pgdat, NR_INACTIVE_ANON) +
|
||||
node_page_state(pgdat, NR_INACTIVE_FILE)),
|
||||
nid, K(node_page_state(pgdat, NR_ACTIVE_ANON)),
|
||||
nid, K(node_page_state(pgdat, NR_INACTIVE_ANON)),
|
||||
nid, K(node_page_state(pgdat, NR_ACTIVE_FILE)),
|
||||
nid, K(node_page_state(pgdat, NR_INACTIVE_FILE)),
|
||||
nid, K(node_page_state(pgdat, NR_UNEVICTABLE)),
|
||||
nid, K(sum_zone_node_page_state(nid, NR_MLOCK)));
|
||||
len = sysfs_emit_at(buf, len,
|
||||
"Node %d MemTotal: %8lu kB\n"
|
||||
"Node %d MemFree: %8lu kB\n"
|
||||
"Node %d MemUsed: %8lu kB\n"
|
||||
"Node %d Active: %8lu kB\n"
|
||||
"Node %d Inactive: %8lu kB\n"
|
||||
"Node %d Active(anon): %8lu kB\n"
|
||||
"Node %d Inactive(anon): %8lu kB\n"
|
||||
"Node %d Active(file): %8lu kB\n"
|
||||
"Node %d Inactive(file): %8lu kB\n"
|
||||
"Node %d Unevictable: %8lu kB\n"
|
||||
"Node %d Mlocked: %8lu kB\n",
|
||||
nid, K(i.totalram),
|
||||
nid, K(i.freeram),
|
||||
nid, K(i.totalram - i.freeram),
|
||||
nid, K(node_page_state(pgdat, NR_ACTIVE_ANON) +
|
||||
node_page_state(pgdat, NR_ACTIVE_FILE)),
|
||||
nid, K(node_page_state(pgdat, NR_INACTIVE_ANON) +
|
||||
node_page_state(pgdat, NR_INACTIVE_FILE)),
|
||||
nid, K(node_page_state(pgdat, NR_ACTIVE_ANON)),
|
||||
nid, K(node_page_state(pgdat, NR_INACTIVE_ANON)),
|
||||
nid, K(node_page_state(pgdat, NR_ACTIVE_FILE)),
|
||||
nid, K(node_page_state(pgdat, NR_INACTIVE_FILE)),
|
||||
nid, K(node_page_state(pgdat, NR_UNEVICTABLE)),
|
||||
nid, K(sum_zone_node_page_state(nid, NR_MLOCK)));
|
||||
|
||||
#ifdef CONFIG_HIGHMEM
|
||||
n += sprintf(buf + n,
|
||||
"Node %d HighTotal: %8lu kB\n"
|
||||
"Node %d HighFree: %8lu kB\n"
|
||||
"Node %d LowTotal: %8lu kB\n"
|
||||
"Node %d LowFree: %8lu kB\n",
|
||||
nid, K(i.totalhigh),
|
||||
nid, K(i.freehigh),
|
||||
nid, K(i.totalram - i.totalhigh),
|
||||
nid, K(i.freeram - i.freehigh));
|
||||
len += sysfs_emit_at(buf, len,
|
||||
"Node %d HighTotal: %8lu kB\n"
|
||||
"Node %d HighFree: %8lu kB\n"
|
||||
"Node %d LowTotal: %8lu kB\n"
|
||||
"Node %d LowFree: %8lu kB\n",
|
||||
nid, K(i.totalhigh),
|
||||
nid, K(i.freehigh),
|
||||
nid, K(i.totalram - i.totalhigh),
|
||||
nid, K(i.freeram - i.freehigh));
|
||||
#endif
|
||||
n += sprintf(buf + n,
|
||||
"Node %d Dirty: %8lu kB\n"
|
||||
"Node %d Writeback: %8lu kB\n"
|
||||
"Node %d FilePages: %8lu kB\n"
|
||||
"Node %d Mapped: %8lu kB\n"
|
||||
"Node %d AnonPages: %8lu kB\n"
|
||||
"Node %d Shmem: %8lu kB\n"
|
||||
"Node %d KernelStack: %8lu kB\n"
|
||||
len += sysfs_emit_at(buf, len,
|
||||
"Node %d Dirty: %8lu kB\n"
|
||||
"Node %d Writeback: %8lu kB\n"
|
||||
"Node %d FilePages: %8lu kB\n"
|
||||
"Node %d Mapped: %8lu kB\n"
|
||||
"Node %d AnonPages: %8lu kB\n"
|
||||
"Node %d Shmem: %8lu kB\n"
|
||||
"Node %d KernelStack: %8lu kB\n"
|
||||
#ifdef CONFIG_SHADOW_CALL_STACK
|
||||
"Node %d ShadowCallStack:%8lu kB\n"
|
||||
"Node %d ShadowCallStack:%8lu kB\n"
|
||||
#endif
|
||||
"Node %d PageTables: %8lu kB\n"
|
||||
"Node %d NFS_Unstable: %8lu kB\n"
|
||||
"Node %d Bounce: %8lu kB\n"
|
||||
"Node %d WritebackTmp: %8lu kB\n"
|
||||
"Node %d KReclaimable: %8lu kB\n"
|
||||
"Node %d Slab: %8lu kB\n"
|
||||
"Node %d SReclaimable: %8lu kB\n"
|
||||
"Node %d SUnreclaim: %8lu kB\n"
|
||||
"Node %d PageTables: %8lu kB\n"
|
||||
"Node %d NFS_Unstable: %8lu kB\n"
|
||||
"Node %d Bounce: %8lu kB\n"
|
||||
"Node %d WritebackTmp: %8lu kB\n"
|
||||
"Node %d KReclaimable: %8lu kB\n"
|
||||
"Node %d Slab: %8lu kB\n"
|
||||
"Node %d SReclaimable: %8lu kB\n"
|
||||
"Node %d SUnreclaim: %8lu kB\n"
|
||||
#ifdef CONFIG_TRANSPARENT_HUGEPAGE
|
||||
"Node %d AnonHugePages: %8lu kB\n"
|
||||
"Node %d ShmemHugePages: %8lu kB\n"
|
||||
"Node %d ShmemPmdMapped: %8lu kB\n"
|
||||
"Node %d FileHugePages: %8lu kB\n"
|
||||
"Node %d FilePmdMapped: %8lu kB\n"
|
||||
"Node %d AnonHugePages: %8lu kB\n"
|
||||
"Node %d ShmemHugePages: %8lu kB\n"
|
||||
"Node %d ShmemPmdMapped: %8lu kB\n"
|
||||
"Node %d FileHugePages: %8lu kB\n"
|
||||
"Node %d FilePmdMapped: %8lu kB\n"
|
||||
#endif
|
||||
,
|
||||
nid, K(node_page_state(pgdat, NR_FILE_DIRTY)),
|
||||
nid, K(node_page_state(pgdat, NR_WRITEBACK)),
|
||||
nid, K(node_page_state(pgdat, NR_FILE_PAGES)),
|
||||
nid, K(node_page_state(pgdat, NR_FILE_MAPPED)),
|
||||
nid, K(node_page_state(pgdat, NR_ANON_MAPPED)),
|
||||
nid, K(i.sharedram),
|
||||
nid, node_page_state(pgdat, NR_KERNEL_STACK_KB),
|
||||
,
|
||||
nid, K(node_page_state(pgdat, NR_FILE_DIRTY)),
|
||||
nid, K(node_page_state(pgdat, NR_WRITEBACK)),
|
||||
nid, K(node_page_state(pgdat, NR_FILE_PAGES)),
|
||||
nid, K(node_page_state(pgdat, NR_FILE_MAPPED)),
|
||||
nid, K(node_page_state(pgdat, NR_ANON_MAPPED)),
|
||||
nid, K(i.sharedram),
|
||||
nid, node_page_state(pgdat, NR_KERNEL_STACK_KB),
|
||||
#ifdef CONFIG_SHADOW_CALL_STACK
|
||||
nid, node_page_state(pgdat, NR_KERNEL_SCS_KB),
|
||||
nid, node_page_state(pgdat, NR_KERNEL_SCS_KB),
|
||||
#endif
|
||||
nid, K(sum_zone_node_page_state(nid, NR_PAGETABLE)),
|
||||
nid, 0UL,
|
||||
nid, K(sum_zone_node_page_state(nid, NR_BOUNCE)),
|
||||
nid, K(node_page_state(pgdat, NR_WRITEBACK_TEMP)),
|
||||
nid, K(sreclaimable +
|
||||
node_page_state(pgdat, NR_KERNEL_MISC_RECLAIMABLE)),
|
||||
nid, K(sreclaimable + sunreclaimable),
|
||||
nid, K(sreclaimable),
|
||||
nid, K(sunreclaimable)
|
||||
nid, K(sum_zone_node_page_state(nid, NR_PAGETABLE)),
|
||||
nid, 0UL,
|
||||
nid, K(sum_zone_node_page_state(nid, NR_BOUNCE)),
|
||||
nid, K(node_page_state(pgdat, NR_WRITEBACK_TEMP)),
|
||||
nid, K(sreclaimable +
|
||||
node_page_state(pgdat, NR_KERNEL_MISC_RECLAIMABLE)),
|
||||
nid, K(sreclaimable + sunreclaimable),
|
||||
nid, K(sreclaimable),
|
||||
nid, K(sunreclaimable)
|
||||
#ifdef CONFIG_TRANSPARENT_HUGEPAGE
|
||||
,
|
||||
nid, K(node_page_state(pgdat, NR_ANON_THPS) *
|
||||
HPAGE_PMD_NR),
|
||||
nid, K(node_page_state(pgdat, NR_SHMEM_THPS) *
|
||||
HPAGE_PMD_NR),
|
||||
nid, K(node_page_state(pgdat, NR_SHMEM_PMDMAPPED) *
|
||||
HPAGE_PMD_NR),
|
||||
nid, K(node_page_state(pgdat, NR_FILE_THPS) *
|
||||
HPAGE_PMD_NR),
|
||||
nid, K(node_page_state(pgdat, NR_FILE_PMDMAPPED) *
|
||||
HPAGE_PMD_NR)
|
||||
,
|
||||
nid, K(node_page_state(pgdat, NR_ANON_THPS) *
|
||||
HPAGE_PMD_NR),
|
||||
nid, K(node_page_state(pgdat, NR_SHMEM_THPS) *
|
||||
HPAGE_PMD_NR),
|
||||
nid, K(node_page_state(pgdat, NR_SHMEM_PMDMAPPED) *
|
||||
HPAGE_PMD_NR),
|
||||
nid, K(node_page_state(pgdat, NR_FILE_THPS) *
|
||||
HPAGE_PMD_NR),
|
||||
nid, K(node_page_state(pgdat, NR_FILE_PMDMAPPED) *
|
||||
HPAGE_PMD_NR)
|
||||
#endif
|
||||
);
|
||||
n += hugetlb_report_node_meminfo(nid, buf + n);
|
||||
return n;
|
||||
);
|
||||
len += hugetlb_report_node_meminfo(buf, len, nid);
|
||||
return len;
|
||||
}
|
||||
|
||||
#undef K
|
||||
static DEVICE_ATTR(meminfo, S_IRUGO, node_read_meminfo, NULL);
|
||||
static DEVICE_ATTR(meminfo, 0444, node_read_meminfo, NULL);
|
||||
|
||||
static ssize_t node_read_numastat(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
return sprintf(buf,
|
||||
"numa_hit %lu\n"
|
||||
"numa_miss %lu\n"
|
||||
"numa_foreign %lu\n"
|
||||
"interleave_hit %lu\n"
|
||||
"local_node %lu\n"
|
||||
"other_node %lu\n",
|
||||
sum_zone_numa_state(dev->id, NUMA_HIT),
|
||||
sum_zone_numa_state(dev->id, NUMA_MISS),
|
||||
sum_zone_numa_state(dev->id, NUMA_FOREIGN),
|
||||
sum_zone_numa_state(dev->id, NUMA_INTERLEAVE_HIT),
|
||||
sum_zone_numa_state(dev->id, NUMA_LOCAL),
|
||||
sum_zone_numa_state(dev->id, NUMA_OTHER));
|
||||
return sysfs_emit(buf,
|
||||
"numa_hit %lu\n"
|
||||
"numa_miss %lu\n"
|
||||
"numa_foreign %lu\n"
|
||||
"interleave_hit %lu\n"
|
||||
"local_node %lu\n"
|
||||
"other_node %lu\n",
|
||||
sum_zone_numa_state(dev->id, NUMA_HIT),
|
||||
sum_zone_numa_state(dev->id, NUMA_MISS),
|
||||
sum_zone_numa_state(dev->id, NUMA_FOREIGN),
|
||||
sum_zone_numa_state(dev->id, NUMA_INTERLEAVE_HIT),
|
||||
sum_zone_numa_state(dev->id, NUMA_LOCAL),
|
||||
sum_zone_numa_state(dev->id, NUMA_OTHER));
|
||||
}
|
||||
static DEVICE_ATTR(numastat, S_IRUGO, node_read_numastat, NULL);
|
||||
static DEVICE_ATTR(numastat, 0444, node_read_numastat, NULL);
|
||||
|
||||
static ssize_t node_read_vmstat(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
@ -499,28 +505,31 @@ static ssize_t node_read_vmstat(struct device *dev,
|
||||
int nid = dev->id;
|
||||
struct pglist_data *pgdat = NODE_DATA(nid);
|
||||
int i;
|
||||
int n = 0;
|
||||
int len = 0;
|
||||
|
||||
for (i = 0; i < NR_VM_ZONE_STAT_ITEMS; i++)
|
||||
n += sprintf(buf+n, "%s %lu\n", zone_stat_name(i),
|
||||
sum_zone_node_page_state(nid, i));
|
||||
len += sysfs_emit_at(buf, len, "%s %lu\n",
|
||||
zone_stat_name(i),
|
||||
sum_zone_node_page_state(nid, i));
|
||||
|
||||
#ifdef CONFIG_NUMA
|
||||
for (i = 0; i < NR_VM_NUMA_STAT_ITEMS; i++)
|
||||
n += sprintf(buf+n, "%s %lu\n", numa_stat_name(i),
|
||||
sum_zone_numa_state(nid, i));
|
||||
len += sysfs_emit_at(buf, len, "%s %lu\n",
|
||||
numa_stat_name(i),
|
||||
sum_zone_numa_state(nid, i));
|
||||
|
||||
#endif
|
||||
|
||||
for (i = 0; i < NR_VM_NODE_STAT_ITEMS; i++)
|
||||
n += sprintf(buf+n, "%s %lu\n", node_stat_name(i),
|
||||
node_page_state_pages(pgdat, i));
|
||||
len += sysfs_emit_at(buf, len, "%s %lu\n",
|
||||
node_stat_name(i),
|
||||
node_page_state_pages(pgdat, i));
|
||||
|
||||
return n;
|
||||
return len;
|
||||
}
|
||||
static DEVICE_ATTR(vmstat, S_IRUGO, node_read_vmstat, NULL);
|
||||
static DEVICE_ATTR(vmstat, 0444, node_read_vmstat, NULL);
|
||||
|
||||
static ssize_t node_read_distance(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
int nid = dev->id;
|
||||
int len = 0;
|
||||
@ -532,13 +541,15 @@ static ssize_t node_read_distance(struct device *dev,
|
||||
*/
|
||||
BUILD_BUG_ON(MAX_NUMNODES * 4 > PAGE_SIZE);
|
||||
|
||||
for_each_online_node(i)
|
||||
len += sprintf(buf + len, "%s%d", i ? " " : "", node_distance(nid, i));
|
||||
for_each_online_node(i) {
|
||||
len += sysfs_emit_at(buf, len, "%s%d",
|
||||
i ? " " : "", node_distance(nid, i));
|
||||
}
|
||||
|
||||
len += sprintf(buf + len, "\n");
|
||||
len += sysfs_emit_at(buf, len, "\n");
|
||||
return len;
|
||||
}
|
||||
static DEVICE_ATTR(distance, S_IRUGO, node_read_distance, NULL);
|
||||
static DEVICE_ATTR(distance, 0444, node_read_distance, NULL);
|
||||
|
||||
static struct attribute *node_dev_attrs[] = {
|
||||
&dev_attr_cpumap.attr,
|
||||
@ -970,17 +981,6 @@ void unregister_one_node(int nid)
|
||||
* node states attributes
|
||||
*/
|
||||
|
||||
static ssize_t print_nodes_state(enum node_states state, char *buf)
|
||||
{
|
||||
int n;
|
||||
|
||||
n = scnprintf(buf, PAGE_SIZE - 1, "%*pbl",
|
||||
nodemask_pr_args(&node_states[state]));
|
||||
buf[n++] = '\n';
|
||||
buf[n] = '\0';
|
||||
return n;
|
||||
}
|
||||
|
||||
struct node_attr {
|
||||
struct device_attribute attr;
|
||||
enum node_states state;
|
||||
@ -990,7 +990,9 @@ static ssize_t show_node_state(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct node_attr *na = container_of(attr, struct node_attr, attr);
|
||||
return print_nodes_state(na->state, buf);
|
||||
|
||||
return sysfs_emit(buf, "%*pbl\n",
|
||||
nodemask_pr_args(&node_states[na->state]));
|
||||
}
|
||||
|
||||
#define _NODE_ATTR(name, state) \
|
||||
|
@ -45,6 +45,8 @@ EXPORT_SYMBOL_GPL(platform_bus);
|
||||
* @dev: platform device
|
||||
* @type: resource type
|
||||
* @num: resource index
|
||||
*
|
||||
* Return: a pointer to the resource or NULL on failure.
|
||||
*/
|
||||
struct resource *platform_get_resource(struct platform_device *dev,
|
||||
unsigned int type, unsigned int num)
|
||||
@ -70,6 +72,9 @@ EXPORT_SYMBOL_GPL(platform_get_resource);
|
||||
* resource management
|
||||
* @index: resource index
|
||||
* @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 *
|
||||
devm_platform_get_and_ioremap_resource(struct platform_device *pdev,
|
||||
@ -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
|
||||
* resource management
|
||||
* @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,
|
||||
unsigned int index)
|
||||
@ -106,6 +114,9 @@ EXPORT_SYMBOL_GPL(devm_platform_ioremap_resource);
|
||||
* @pdev: platform device to use both for memory resource lookup as well as
|
||||
* resource management
|
||||
* @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,
|
||||
unsigned int index)
|
||||
@ -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
|
||||
* resource management
|
||||
* @name: name of the resource
|
||||
*
|
||||
* Return: a pointer to the remapped memory or an ERR_PTR() encoded error code
|
||||
* on failure.
|
||||
*/
|
||||
void __iomem *
|
||||
devm_platform_ioremap_resource_byname(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
|
||||
* 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)
|
||||
goto err_out;
|
||||
pdev->id = ret;
|
||||
@ -600,7 +614,7 @@ int platform_device_add(struct platform_device *pdev)
|
||||
|
||||
failed:
|
||||
if (pdev->id_auto) {
|
||||
ida_simple_remove(&platform_devid_ida, pdev->id);
|
||||
ida_free(&platform_devid_ida, pdev->id);
|
||||
pdev->id = PLATFORM_DEVID_AUTO;
|
||||
}
|
||||
|
||||
@ -631,7 +645,7 @@ void platform_device_del(struct platform_device *pdev)
|
||||
device_del(&pdev->dev);
|
||||
|
||||
if (pdev->id_auto) {
|
||||
ida_simple_remove(&platform_devid_ida, pdev->id);
|
||||
ida_free(&platform_devid_ida, pdev->id);
|
||||
pdev->id = PLATFORM_DEVID_AUTO;
|
||||
}
|
||||
|
||||
@ -1009,10 +1023,10 @@ EXPORT_SYMBOL_GPL(platform_unregister_drivers);
|
||||
* (b) sysfs attribute lets new-style coldplug recover from hotplug events
|
||||
* mishandled before system is fully running: "modprobe $(cat modalias)"
|
||||
*/
|
||||
static ssize_t modalias_show(struct device *dev, struct device_attribute *a,
|
||||
char *buf)
|
||||
static ssize_t modalias_show(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct platform_device *pdev = to_platform_device(dev);
|
||||
struct platform_device *pdev = to_platform_device(dev);
|
||||
int len;
|
||||
|
||||
len = of_device_modalias(dev, buf, PAGE_SIZE);
|
||||
@ -1023,9 +1037,7 @@ static ssize_t modalias_show(struct device *dev, struct device_attribute *a,
|
||||
if (len != -ENODEV)
|
||||
return len;
|
||||
|
||||
len = snprintf(buf, PAGE_SIZE, "platform:%s\n", pdev->name);
|
||||
|
||||
return (len >= PAGE_SIZE) ? (PAGE_SIZE - 1) : len;
|
||||
return sysfs_emit(buf, "platform:%s\n", pdev->name);
|
||||
}
|
||||
static DEVICE_ATTR_RO(modalias);
|
||||
|
||||
@ -1070,16 +1082,17 @@ static ssize_t driver_override_show(struct device *dev,
|
||||
ssize_t len;
|
||||
|
||||
device_lock(dev);
|
||||
len = sprintf(buf, "%s\n", pdev->driver_override);
|
||||
len = sysfs_emit(buf, "%s\n", pdev->driver_override);
|
||||
device_unlock(dev);
|
||||
|
||||
return len;
|
||||
}
|
||||
static DEVICE_ATTR_RW(driver_override);
|
||||
|
||||
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);
|
||||
|
||||
|
@ -101,8 +101,8 @@ static const char ctrl_on[] = "on";
|
||||
static ssize_t control_show(struct device *dev, struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
return sprintf(buf, "%s\n",
|
||||
dev->power.runtime_auto ? ctrl_auto : ctrl_on);
|
||||
return sysfs_emit(buf, "%s\n",
|
||||
dev->power.runtime_auto ? ctrl_auto : ctrl_on);
|
||||
}
|
||||
|
||||
static ssize_t control_store(struct device * dev, struct device_attribute *attr,
|
||||
@ -122,67 +122,71 @@ static ssize_t control_store(struct device * dev, struct device_attribute *attr,
|
||||
static DEVICE_ATTR_RW(control);
|
||||
|
||||
static ssize_t runtime_active_time_show(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
int ret;
|
||||
u64 tmp = pm_runtime_active_time(dev);
|
||||
|
||||
do_div(tmp, NSEC_PER_MSEC);
|
||||
ret = sprintf(buf, "%llu\n", tmp);
|
||||
return ret;
|
||||
|
||||
return sysfs_emit(buf, "%llu\n", tmp);
|
||||
}
|
||||
|
||||
static DEVICE_ATTR_RO(runtime_active_time);
|
||||
|
||||
static ssize_t runtime_suspended_time_show(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
int ret;
|
||||
u64 tmp = pm_runtime_suspended_time(dev);
|
||||
|
||||
do_div(tmp, NSEC_PER_MSEC);
|
||||
ret = sprintf(buf, "%llu\n", tmp);
|
||||
return ret;
|
||||
|
||||
return sysfs_emit(buf, "%llu\n", tmp);
|
||||
}
|
||||
|
||||
static DEVICE_ATTR_RO(runtime_suspended_time);
|
||||
|
||||
static ssize_t runtime_status_show(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
const char *p;
|
||||
const char *output;
|
||||
|
||||
if (dev->power.runtime_error) {
|
||||
p = "error\n";
|
||||
output = "error";
|
||||
} else if (dev->power.disable_depth) {
|
||||
p = "unsupported\n";
|
||||
output = "unsupported";
|
||||
} else {
|
||||
switch (dev->power.runtime_status) {
|
||||
case RPM_SUSPENDED:
|
||||
p = "suspended\n";
|
||||
output = "suspended";
|
||||
break;
|
||||
case RPM_SUSPENDING:
|
||||
p = "suspending\n";
|
||||
output = "suspending";
|
||||
break;
|
||||
case RPM_RESUMING:
|
||||
p = "resuming\n";
|
||||
output = "resuming";
|
||||
break;
|
||||
case RPM_ACTIVE:
|
||||
p = "active\n";
|
||||
output = "active";
|
||||
break;
|
||||
default:
|
||||
return -EIO;
|
||||
}
|
||||
}
|
||||
return sprintf(buf, p);
|
||||
return sysfs_emit(buf, "%s\n", output);
|
||||
}
|
||||
|
||||
static DEVICE_ATTR_RO(runtime_status);
|
||||
|
||||
static ssize_t autosuspend_delay_ms_show(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
if (!dev->power.use_autosuspend)
|
||||
return -EIO;
|
||||
return sprintf(buf, "%d\n", dev->power.autosuspend_delay);
|
||||
|
||||
return sysfs_emit(buf, "%d\n", dev->power.autosuspend_delay);
|
||||
}
|
||||
|
||||
static ssize_t autosuspend_delay_ms_store(struct device *dev,
|
||||
@ -211,11 +215,11 @@ static ssize_t pm_qos_resume_latency_us_show(struct device *dev,
|
||||
s32 value = dev_pm_qos_requested_resume_latency(dev);
|
||||
|
||||
if (value == 0)
|
||||
return sprintf(buf, "n/a\n");
|
||||
return sysfs_emit(buf, "n/a\n");
|
||||
if (value == PM_QOS_RESUME_LATENCY_NO_CONSTRAINT)
|
||||
value = 0;
|
||||
|
||||
return sprintf(buf, "%d\n", value);
|
||||
return sysfs_emit(buf, "%d\n", value);
|
||||
}
|
||||
|
||||
static ssize_t pm_qos_resume_latency_us_store(struct device *dev,
|
||||
@ -255,11 +259,11 @@ static ssize_t pm_qos_latency_tolerance_us_show(struct device *dev,
|
||||
s32 value = dev_pm_qos_get_user_latency_tolerance(dev);
|
||||
|
||||
if (value < 0)
|
||||
return sprintf(buf, "auto\n");
|
||||
return sysfs_emit(buf, "%s\n", "auto");
|
||||
if (value == PM_QOS_LATENCY_ANY)
|
||||
return sprintf(buf, "any\n");
|
||||
return sysfs_emit(buf, "%s\n", "any");
|
||||
|
||||
return sprintf(buf, "%d\n", value);
|
||||
return sysfs_emit(buf, "%d\n", value);
|
||||
}
|
||||
|
||||
static ssize_t pm_qos_latency_tolerance_us_store(struct device *dev,
|
||||
@ -291,8 +295,8 @@ static ssize_t pm_qos_no_power_off_show(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
return sprintf(buf, "%d\n", !!(dev_pm_qos_requested_flags(dev)
|
||||
& PM_QOS_FLAG_NO_POWER_OFF));
|
||||
return sysfs_emit(buf, "%d\n", !!(dev_pm_qos_requested_flags(dev)
|
||||
& PM_QOS_FLAG_NO_POWER_OFF));
|
||||
}
|
||||
|
||||
static ssize_t pm_qos_no_power_off_store(struct device *dev,
|
||||
@ -320,9 +324,9 @@ static const char _disabled[] = "disabled";
|
||||
static ssize_t wakeup_show(struct device *dev, struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
return sprintf(buf, "%s\n", device_can_wakeup(dev)
|
||||
? (device_may_wakeup(dev) ? _enabled : _disabled)
|
||||
: "");
|
||||
return sysfs_emit(buf, "%s\n", device_can_wakeup(dev)
|
||||
? (device_may_wakeup(dev) ? _enabled : _disabled)
|
||||
: "");
|
||||
}
|
||||
|
||||
static ssize_t wakeup_store(struct device *dev, struct device_attribute *attr,
|
||||
@ -345,7 +349,7 @@ static DEVICE_ATTR_RW(wakeup);
|
||||
static ssize_t wakeup_count_show(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
unsigned long count = 0;
|
||||
unsigned long count;
|
||||
bool enabled = false;
|
||||
|
||||
spin_lock_irq(&dev->power.lock);
|
||||
@ -354,7 +358,10 @@ static ssize_t wakeup_count_show(struct device *dev,
|
||||
enabled = true;
|
||||
}
|
||||
spin_unlock_irq(&dev->power.lock);
|
||||
return enabled ? sprintf(buf, "%lu\n", count) : sprintf(buf, "\n");
|
||||
|
||||
if (!enabled)
|
||||
return sysfs_emit(buf, "\n");
|
||||
return sysfs_emit(buf, "%lu\n", count);
|
||||
}
|
||||
|
||||
static DEVICE_ATTR_RO(wakeup_count);
|
||||
@ -363,7 +370,7 @@ static ssize_t wakeup_active_count_show(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
unsigned long count = 0;
|
||||
unsigned long count;
|
||||
bool enabled = false;
|
||||
|
||||
spin_lock_irq(&dev->power.lock);
|
||||
@ -372,7 +379,10 @@ static ssize_t wakeup_active_count_show(struct device *dev,
|
||||
enabled = true;
|
||||
}
|
||||
spin_unlock_irq(&dev->power.lock);
|
||||
return enabled ? sprintf(buf, "%lu\n", count) : sprintf(buf, "\n");
|
||||
|
||||
if (!enabled)
|
||||
return sysfs_emit(buf, "\n");
|
||||
return sysfs_emit(buf, "%lu\n", count);
|
||||
}
|
||||
|
||||
static DEVICE_ATTR_RO(wakeup_active_count);
|
||||
@ -381,7 +391,7 @@ static ssize_t wakeup_abort_count_show(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
unsigned long count = 0;
|
||||
unsigned long count;
|
||||
bool enabled = false;
|
||||
|
||||
spin_lock_irq(&dev->power.lock);
|
||||
@ -390,7 +400,10 @@ static ssize_t wakeup_abort_count_show(struct device *dev,
|
||||
enabled = true;
|
||||
}
|
||||
spin_unlock_irq(&dev->power.lock);
|
||||
return enabled ? sprintf(buf, "%lu\n", count) : sprintf(buf, "\n");
|
||||
|
||||
if (!enabled)
|
||||
return sysfs_emit(buf, "\n");
|
||||
return sysfs_emit(buf, "%lu\n", count);
|
||||
}
|
||||
|
||||
static DEVICE_ATTR_RO(wakeup_abort_count);
|
||||
@ -399,7 +412,7 @@ static ssize_t wakeup_expire_count_show(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
unsigned long count = 0;
|
||||
unsigned long count;
|
||||
bool enabled = false;
|
||||
|
||||
spin_lock_irq(&dev->power.lock);
|
||||
@ -408,7 +421,10 @@ static ssize_t wakeup_expire_count_show(struct device *dev,
|
||||
enabled = true;
|
||||
}
|
||||
spin_unlock_irq(&dev->power.lock);
|
||||
return enabled ? sprintf(buf, "%lu\n", count) : sprintf(buf, "\n");
|
||||
|
||||
if (!enabled)
|
||||
return sysfs_emit(buf, "\n");
|
||||
return sysfs_emit(buf, "%lu\n", count);
|
||||
}
|
||||
|
||||
static DEVICE_ATTR_RO(wakeup_expire_count);
|
||||
@ -416,7 +432,7 @@ static DEVICE_ATTR_RO(wakeup_expire_count);
|
||||
static ssize_t wakeup_active_show(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
unsigned int active = 0;
|
||||
unsigned int active;
|
||||
bool enabled = false;
|
||||
|
||||
spin_lock_irq(&dev->power.lock);
|
||||
@ -425,7 +441,10 @@ static ssize_t wakeup_active_show(struct device *dev,
|
||||
enabled = true;
|
||||
}
|
||||
spin_unlock_irq(&dev->power.lock);
|
||||
return enabled ? sprintf(buf, "%u\n", active) : sprintf(buf, "\n");
|
||||
|
||||
if (!enabled)
|
||||
return sysfs_emit(buf, "\n");
|
||||
return sysfs_emit(buf, "%u\n", active);
|
||||
}
|
||||
|
||||
static DEVICE_ATTR_RO(wakeup_active);
|
||||
@ -434,7 +453,7 @@ static ssize_t wakeup_total_time_ms_show(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
s64 msec = 0;
|
||||
s64 msec;
|
||||
bool enabled = false;
|
||||
|
||||
spin_lock_irq(&dev->power.lock);
|
||||
@ -443,7 +462,10 @@ static ssize_t wakeup_total_time_ms_show(struct device *dev,
|
||||
enabled = true;
|
||||
}
|
||||
spin_unlock_irq(&dev->power.lock);
|
||||
return enabled ? sprintf(buf, "%lld\n", msec) : sprintf(buf, "\n");
|
||||
|
||||
if (!enabled)
|
||||
return sysfs_emit(buf, "\n");
|
||||
return sysfs_emit(buf, "%lld\n", msec);
|
||||
}
|
||||
|
||||
static DEVICE_ATTR_RO(wakeup_total_time_ms);
|
||||
@ -451,7 +473,7 @@ static DEVICE_ATTR_RO(wakeup_total_time_ms);
|
||||
static ssize_t wakeup_max_time_ms_show(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
s64 msec = 0;
|
||||
s64 msec;
|
||||
bool enabled = false;
|
||||
|
||||
spin_lock_irq(&dev->power.lock);
|
||||
@ -460,7 +482,10 @@ static ssize_t wakeup_max_time_ms_show(struct device *dev,
|
||||
enabled = true;
|
||||
}
|
||||
spin_unlock_irq(&dev->power.lock);
|
||||
return enabled ? sprintf(buf, "%lld\n", msec) : sprintf(buf, "\n");
|
||||
|
||||
if (!enabled)
|
||||
return sysfs_emit(buf, "\n");
|
||||
return sysfs_emit(buf, "%lld\n", msec);
|
||||
}
|
||||
|
||||
static DEVICE_ATTR_RO(wakeup_max_time_ms);
|
||||
@ -469,7 +494,7 @@ static ssize_t wakeup_last_time_ms_show(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
s64 msec = 0;
|
||||
s64 msec;
|
||||
bool enabled = false;
|
||||
|
||||
spin_lock_irq(&dev->power.lock);
|
||||
@ -478,7 +503,10 @@ static ssize_t wakeup_last_time_ms_show(struct device *dev,
|
||||
enabled = true;
|
||||
}
|
||||
spin_unlock_irq(&dev->power.lock);
|
||||
return enabled ? sprintf(buf, "%lld\n", msec) : sprintf(buf, "\n");
|
||||
|
||||
if (!enabled)
|
||||
return sysfs_emit(buf, "\n");
|
||||
return sysfs_emit(buf, "%lld\n", msec);
|
||||
}
|
||||
|
||||
static inline int dpm_sysfs_wakeup_change_owner(struct device *dev, kuid_t kuid,
|
||||
@ -496,7 +524,7 @@ static ssize_t wakeup_prevent_sleep_time_ms_show(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
s64 msec = 0;
|
||||
s64 msec;
|
||||
bool enabled = false;
|
||||
|
||||
spin_lock_irq(&dev->power.lock);
|
||||
@ -505,7 +533,10 @@ static ssize_t wakeup_prevent_sleep_time_ms_show(struct device *dev,
|
||||
enabled = true;
|
||||
}
|
||||
spin_unlock_irq(&dev->power.lock);
|
||||
return enabled ? sprintf(buf, "%lld\n", msec) : sprintf(buf, "\n");
|
||||
|
||||
if (!enabled)
|
||||
return sysfs_emit(buf, "\n");
|
||||
return sysfs_emit(buf, "%lld\n", msec);
|
||||
}
|
||||
|
||||
static DEVICE_ATTR_RO(wakeup_prevent_sleep_time_ms);
|
||||
@ -522,7 +553,7 @@ static inline int dpm_sysfs_wakeup_change_owner(struct device *dev, kuid_t kuid,
|
||||
static ssize_t runtime_usage_show(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
return sprintf(buf, "%d\n", atomic_read(&dev->power.usage_count));
|
||||
return sysfs_emit(buf, "%d\n", atomic_read(&dev->power.usage_count));
|
||||
}
|
||||
static DEVICE_ATTR_RO(runtime_usage);
|
||||
|
||||
@ -530,21 +561,26 @@ static ssize_t runtime_active_kids_show(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
return sprintf(buf, "%d\n", dev->power.ignore_children ?
|
||||
0 : atomic_read(&dev->power.child_count));
|
||||
return sysfs_emit(buf, "%d\n", dev->power.ignore_children ?
|
||||
0 : atomic_read(&dev->power.child_count));
|
||||
}
|
||||
static DEVICE_ATTR_RO(runtime_active_kids);
|
||||
|
||||
static ssize_t runtime_enabled_show(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
if (dev->power.disable_depth && (dev->power.runtime_auto == false))
|
||||
return sprintf(buf, "disabled & forbidden\n");
|
||||
if (dev->power.disable_depth)
|
||||
return sprintf(buf, "disabled\n");
|
||||
if (dev->power.runtime_auto == false)
|
||||
return sprintf(buf, "forbidden\n");
|
||||
return sprintf(buf, "enabled\n");
|
||||
const char *output;
|
||||
|
||||
if (dev->power.disable_depth && !dev->power.runtime_auto)
|
||||
output = "disabled & forbidden";
|
||||
else if (dev->power.disable_depth)
|
||||
output = "disabled";
|
||||
else if (!dev->power.runtime_auto)
|
||||
output = "forbidden";
|
||||
else
|
||||
output = "enabled";
|
||||
|
||||
return sysfs_emit(buf, "%s\n", output);
|
||||
}
|
||||
static DEVICE_ATTR_RO(runtime_enabled);
|
||||
|
||||
@ -552,9 +588,9 @@ static DEVICE_ATTR_RO(runtime_enabled);
|
||||
static ssize_t async_show(struct device *dev, struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
return sprintf(buf, "%s\n",
|
||||
device_async_suspend_enabled(dev) ?
|
||||
_enabled : _disabled);
|
||||
return sysfs_emit(buf, "%s\n",
|
||||
device_async_suspend_enabled(dev) ?
|
||||
_enabled : _disabled);
|
||||
}
|
||||
|
||||
static ssize_t async_store(struct device *dev, struct device_attribute *attr,
|
||||
|
@ -26,7 +26,7 @@ static ssize_t _name##_show(struct device *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)
|
||||
|
||||
@ -42,7 +42,7 @@ static ssize_t active_time_ms_show(struct device *dev,
|
||||
ktime_t active_time =
|
||||
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);
|
||||
|
||||
@ -57,7 +57,8 @@ static ssize_t total_time_ms_show(struct device *dev,
|
||||
active_time = ktime_sub(ktime_get(), ws->last_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);
|
||||
|
||||
@ -73,7 +74,8 @@ static ssize_t max_time_ms_show(struct device *dev,
|
||||
if (active_time > max_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);
|
||||
|
||||
@ -82,7 +84,7 @@ static ssize_t last_change_ms_show(struct device *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);
|
||||
|
||||
@ -91,7 +93,7 @@ static ssize_t name_show(struct device *dev, struct device_attribute *attr,
|
||||
{
|
||||
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);
|
||||
|
||||
@ -106,7 +108,8 @@ static ssize_t prevent_suspend_time_ms_show(struct device *dev,
|
||||
prevent_sleep_time = ktime_add(prevent_sleep_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);
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
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 @@
|
||||
|
||||
static DEFINE_IDA(soc_ida);
|
||||
|
||||
static ssize_t soc_info_get(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
char *buf);
|
||||
/* Prototype to allow declarations of DEVICE_ATTR(<foo>) before soc_info_show */
|
||||
static ssize_t soc_info_show(struct device *dev, struct device_attribute *attr,
|
||||
char *buf);
|
||||
|
||||
struct soc_device {
|
||||
struct device dev;
|
||||
@ -31,11 +31,11 @@ static struct bus_type soc_bus_type = {
|
||||
.name = "soc",
|
||||
};
|
||||
|
||||
static DEVICE_ATTR(machine, S_IRUGO, soc_info_get, NULL);
|
||||
static DEVICE_ATTR(family, S_IRUGO, soc_info_get, NULL);
|
||||
static DEVICE_ATTR(serial_number, S_IRUGO, soc_info_get, NULL);
|
||||
static DEVICE_ATTR(soc_id, S_IRUGO, soc_info_get, NULL);
|
||||
static DEVICE_ATTR(revision, S_IRUGO, soc_info_get, NULL);
|
||||
static DEVICE_ATTR(machine, 0444, soc_info_show, NULL);
|
||||
static DEVICE_ATTR(family, 0444, soc_info_show, NULL);
|
||||
static DEVICE_ATTR(serial_number, 0444, soc_info_show, NULL);
|
||||
static DEVICE_ATTR(soc_id, 0444, soc_info_show, NULL);
|
||||
static DEVICE_ATTR(revision, 0444, soc_info_show, NULL);
|
||||
|
||||
struct device *soc_device_to_device(struct soc_device *soc_dev)
|
||||
{
|
||||
@ -49,45 +49,41 @@ static umode_t soc_attribute_mode(struct kobject *kobj,
|
||||
struct device *dev = kobj_to_dev(kobj);
|
||||
struct soc_device *soc_dev = container_of(dev, struct soc_device, dev);
|
||||
|
||||
if ((attr == &dev_attr_machine.attr)
|
||||
&& (soc_dev->attr->machine != NULL))
|
||||
if ((attr == &dev_attr_machine.attr) && soc_dev->attr->machine)
|
||||
return attr->mode;
|
||||
if ((attr == &dev_attr_family.attr)
|
||||
&& (soc_dev->attr->family != NULL))
|
||||
if ((attr == &dev_attr_family.attr) && soc_dev->attr->family)
|
||||
return attr->mode;
|
||||
if ((attr == &dev_attr_revision.attr)
|
||||
&& (soc_dev->attr->revision != NULL))
|
||||
if ((attr == &dev_attr_revision.attr) && soc_dev->attr->revision)
|
||||
return attr->mode;
|
||||
if ((attr == &dev_attr_serial_number.attr)
|
||||
&& (soc_dev->attr->serial_number != NULL))
|
||||
if ((attr == &dev_attr_serial_number.attr) && soc_dev->attr->serial_number)
|
||||
return attr->mode;
|
||||
if ((attr == &dev_attr_soc_id.attr)
|
||||
&& (soc_dev->attr->soc_id != NULL))
|
||||
if ((attr == &dev_attr_soc_id.attr) && soc_dev->attr->soc_id)
|
||||
return attr->mode;
|
||||
|
||||
/* Unknown or unfilled attribute. */
|
||||
/* Unknown or unfilled attribute */
|
||||
return 0;
|
||||
}
|
||||
|
||||
static ssize_t soc_info_get(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
char *buf)
|
||||
static ssize_t soc_info_show(struct device *dev, struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
struct soc_device *soc_dev = container_of(dev, struct soc_device, dev);
|
||||
const char *output;
|
||||
|
||||
if (attr == &dev_attr_machine)
|
||||
return sprintf(buf, "%s\n", soc_dev->attr->machine);
|
||||
if (attr == &dev_attr_family)
|
||||
return sprintf(buf, "%s\n", soc_dev->attr->family);
|
||||
if (attr == &dev_attr_revision)
|
||||
return sprintf(buf, "%s\n", soc_dev->attr->revision);
|
||||
if (attr == &dev_attr_serial_number)
|
||||
return sprintf(buf, "%s\n", soc_dev->attr->serial_number);
|
||||
if (attr == &dev_attr_soc_id)
|
||||
return sprintf(buf, "%s\n", soc_dev->attr->soc_id);
|
||||
|
||||
return -EINVAL;
|
||||
output = soc_dev->attr->machine;
|
||||
else if (attr == &dev_attr_family)
|
||||
output = soc_dev->attr->family;
|
||||
else if (attr == &dev_attr_revision)
|
||||
output = soc_dev->attr->revision;
|
||||
else if (attr == &dev_attr_serial_number)
|
||||
output = soc_dev->attr->serial_number;
|
||||
else if (attr == &dev_attr_soc_id)
|
||||
output = soc_dev->attr->soc_id;
|
||||
else
|
||||
return -EINVAL;
|
||||
|
||||
return sysfs_emit(buf, "%s\n", output);
|
||||
}
|
||||
|
||||
static struct attribute *soc_attr[] = {
|
||||
|
@ -50,7 +50,7 @@ int syscore_suspend(void)
|
||||
int ret = 0;
|
||||
|
||||
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. */
|
||||
if (pm_wakeup_pending())
|
||||
@ -61,8 +61,7 @@ int syscore_suspend(void)
|
||||
|
||||
list_for_each_entry_reverse(ops, &syscore_ops_list, node)
|
||||
if (ops->suspend) {
|
||||
if (initcall_debug)
|
||||
pr_info("PM: Calling %pS\n", ops->suspend);
|
||||
pm_pr_dbg("Calling %pS\n", ops->suspend);
|
||||
ret = ops->suspend();
|
||||
if (ret)
|
||||
goto err_out;
|
||||
@ -99,8 +98,7 @@ void syscore_resume(void)
|
||||
|
||||
list_for_each_entry(ops, &syscore_ops_list, node)
|
||||
if (ops->resume) {
|
||||
if (initcall_debug)
|
||||
pr_info("PM: Calling %pS\n", ops->resume);
|
||||
pm_pr_dbg("Calling %pS\n", ops->resume);
|
||||
ops->resume();
|
||||
WARN_ONCE(!irqs_disabled(),
|
||||
"Interrupts enabled after %pS\n", ops->resume);
|
||||
|
@ -14,11 +14,11 @@
|
||||
#include <linux/hardirq.h>
|
||||
#include <linux/topology.h>
|
||||
|
||||
#define define_id_show_func(name) \
|
||||
static ssize_t name##_show(struct device *dev, \
|
||||
struct device_attribute *attr, char *buf) \
|
||||
{ \
|
||||
return sprintf(buf, "%d\n", topology_##name(dev->id)); \
|
||||
#define define_id_show_func(name) \
|
||||
static ssize_t name##_show(struct device *dev, \
|
||||
struct device_attribute *attr, char *buf) \
|
||||
{ \
|
||||
return sysfs_emit(buf, "%d\n", topology_##name(dev->id)); \
|
||||
}
|
||||
|
||||
#define define_siblings_show_map(name, mask) \
|
||||
|
@ -987,9 +987,9 @@ static int pmbus_add_attribute(struct pmbus_data *data, struct attribute *attr)
|
||||
{
|
||||
if (data->num_attributes >= data->max_attributes - 1) {
|
||||
int new_max_attrs = data->max_attributes + PMBUS_ATTR_ALLOC_SIZE;
|
||||
void *new_attrs = krealloc(data->group.attrs,
|
||||
new_max_attrs * sizeof(void *),
|
||||
GFP_KERNEL);
|
||||
void *new_attrs = devm_krealloc(data->dev, data->group.attrs,
|
||||
new_max_attrs * sizeof(void *),
|
||||
GFP_KERNEL);
|
||||
if (!new_attrs)
|
||||
return -ENOMEM;
|
||||
data->group.attrs = new_attrs;
|
||||
@ -2578,7 +2578,7 @@ int pmbus_do_probe(struct i2c_client *client, struct pmbus_driver_info *info)
|
||||
|
||||
ret = pmbus_find_attributes(client, data);
|
||||
if (ret)
|
||||
goto out_kfree;
|
||||
return ret;
|
||||
|
||||
/*
|
||||
* 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)
|
||||
*/
|
||||
if (!data->num_attributes) {
|
||||
dev_err(dev, "No attributes found\n");
|
||||
ret = -ENODEV;
|
||||
goto out_kfree;
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
data->groups[0] = &data->group;
|
||||
memcpy(data->groups + 1, info->groups, sizeof(void *) * groups_num);
|
||||
data->hwmon_dev = hwmon_device_register_with_groups(dev, client->name,
|
||||
data, data->groups);
|
||||
data->hwmon_dev = devm_hwmon_device_register_with_groups(dev,
|
||||
client->name, data, data->groups);
|
||||
if (IS_ERR(data->hwmon_dev)) {
|
||||
ret = PTR_ERR(data->hwmon_dev);
|
||||
dev_err(dev, "Failed to register hwmon device\n");
|
||||
goto out_kfree;
|
||||
return PTR_ERR(data->hwmon_dev);
|
||||
}
|
||||
|
||||
ret = pmbus_regulator_register(data);
|
||||
if (ret)
|
||||
goto out_unregister;
|
||||
return ret;
|
||||
|
||||
ret = pmbus_init_debugfs(client, data);
|
||||
if (ret)
|
||||
dev_warn(dev, "Failed to register debugfs\n");
|
||||
|
||||
return 0;
|
||||
|
||||
out_unregister:
|
||||
hwmon_device_unregister(data->hwmon_dev);
|
||||
out_kfree:
|
||||
kfree(data->group.attrs);
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(pmbus_do_probe);
|
||||
|
||||
@ -2624,8 +2616,6 @@ int pmbus_do_remove(struct i2c_client *client)
|
||||
|
||||
debugfs_remove_recursive(data->debugfs);
|
||||
|
||||
hwmon_device_unregister(data->hwmon_dev);
|
||||
kfree(data->group.attrs);
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(pmbus_do_remove);
|
||||
|
@ -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,
|
||||
unsigned int *conf)
|
||||
{
|
||||
struct device *dev = indio_dev->dev.parent;
|
||||
struct xadc *xadc = iio_priv(indio_dev);
|
||||
struct iio_chan_spec *channels, *chan;
|
||||
struct device_node *chan_node, *child;
|
||||
@ -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);
|
||||
}
|
||||
|
||||
channels = kmemdup(xadc_channels, sizeof(xadc_channels), GFP_KERNEL);
|
||||
channels = devm_kmemdup(dev, xadc_channels,
|
||||
sizeof(xadc_channels), GFP_KERNEL);
|
||||
if (!channels)
|
||||
return -ENOMEM;
|
||||
|
||||
@ -1172,8 +1174,9 @@ static int xadc_parse_dt(struct iio_dev *indio_dev, struct device_node *np,
|
||||
of_node_put(chan_node);
|
||||
|
||||
indio_dev->num_channels = num_channels;
|
||||
indio_dev->channels = krealloc(channels, sizeof(*channels) *
|
||||
num_channels, GFP_KERNEL);
|
||||
indio_dev->channels = devm_krealloc(dev, channels,
|
||||
sizeof(*channels) * num_channels,
|
||||
GFP_KERNEL);
|
||||
/* If we can't resize the channels array, just use the original */
|
||||
if (!indio_dev->channels)
|
||||
indio_dev->channels = channels;
|
||||
@ -1225,14 +1228,14 @@ static int xadc_probe(struct platform_device *pdev)
|
||||
|
||||
ret = xadc_parse_dt(indio_dev, pdev->dev.of_node, &conf0);
|
||||
if (ret)
|
||||
goto err_device_free;
|
||||
return ret;
|
||||
|
||||
if (xadc->ops->flags & XADC_FLAGS_BUFFERED) {
|
||||
ret = iio_triggered_buffer_setup(indio_dev,
|
||||
&iio_pollfunc_store_time, &xadc_trigger_handler,
|
||||
&xadc_buffer_ops);
|
||||
if (ret)
|
||||
goto err_device_free;
|
||||
return ret;
|
||||
|
||||
xadc->convst_trigger = xadc_alloc_trigger(indio_dev, "convst");
|
||||
if (IS_ERR(xadc->convst_trigger)) {
|
||||
@ -1350,8 +1353,6 @@ static int xadc_probe(struct platform_device *pdev)
|
||||
err_triggered_buffer_cleanup:
|
||||
if (xadc->ops->flags & XADC_FLAGS_BUFFERED)
|
||||
iio_triggered_buffer_cleanup(indio_dev);
|
||||
err_device_free:
|
||||
kfree(indio_dev->channels);
|
||||
|
||||
return ret;
|
||||
}
|
||||
@ -1371,7 +1372,6 @@ static int xadc_remove(struct platform_device *pdev)
|
||||
cancel_delayed_work_sync(&xadc->zynq_unmask_work);
|
||||
clk_disable_unprepare(xadc->clk);
|
||||
kfree(xadc->data);
|
||||
kfree(indio_dev->channels);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -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);
|
||||
|
||||
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)
|
||||
{
|
||||
struct device *dev;
|
||||
|
||||
if (con->fwnode) {
|
||||
if (con->id && !fwnode_property_present(con->fwnode, con->id))
|
||||
return NULL;
|
||||
if (id && !fwnode_property_present(fwnode, id))
|
||||
return NULL;
|
||||
|
||||
dev = class_find_device_by_fwnode(role_class, con->fwnode);
|
||||
} else {
|
||||
dev = class_find_device_by_name(role_class, con->endpoint[ep]);
|
||||
}
|
||||
dev = class_find_device_by_fwnode(role_class, fwnode);
|
||||
|
||||
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)
|
||||
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)
|
||||
{
|
||||
struct device *dev;
|
||||
|
||||
if (con->id && !fwnode_property_present(con->fwnode, con->id))
|
||||
if (id && !fwnode_property_present(fwnode, id))
|
||||
return NULL;
|
||||
|
||||
dev = class_find_device(&typec_mux_class, NULL, con->fwnode,
|
||||
dev = class_find_device(&typec_mux_class, NULL, fwnode,
|
||||
switch_fwnode_match);
|
||||
|
||||
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)
|
||||
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;
|
||||
struct device *dev;
|
||||
@ -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
|
||||
* has, no need to do any extra connection identification.
|
||||
*/
|
||||
match = !con->id;
|
||||
match = !id;
|
||||
if (match)
|
||||
goto find_mux;
|
||||
|
||||
/* Accessory Mode muxes */
|
||||
if (!desc) {
|
||||
match = fwnode_property_present(con->fwnode, "accessory");
|
||||
match = fwnode_property_present(fwnode, "accessory");
|
||||
if (match)
|
||||
goto find_mux;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Alternate Mode muxes */
|
||||
nval = fwnode_property_count_u16(con->fwnode, "svid");
|
||||
nval = fwnode_property_count_u16(fwnode, "svid");
|
||||
if (nval <= 0)
|
||||
return NULL;
|
||||
|
||||
@ -217,7 +218,7 @@ static void *typec_mux_match(struct device_connection *con, int ep, void *data)
|
||||
if (!val)
|
||||
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) {
|
||||
kfree(val);
|
||||
return ERR_PTR(nval);
|
||||
@ -234,7 +235,7 @@ static void *typec_mux_match(struct device_connection *con, int ep, void *data)
|
||||
return NULL;
|
||||
|
||||
find_mux:
|
||||
dev = class_find_device(&typec_mux_class, NULL, con->fwnode,
|
||||
dev = class_find_device(&typec_mux_class, NULL, fwnode,
|
||||
mux_fwnode_match);
|
||||
|
||||
return dev ? to_typec_switch(dev) : ERR_PTR(-EPROBE_DEFER);
|
||||
|
@ -15,6 +15,7 @@
|
||||
#include <linux/list.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/seq_file.h>
|
||||
#include <linux/mm.h>
|
||||
|
||||
#include "sysfs.h"
|
||||
|
||||
@ -707,3 +708,57 @@ int sysfs_change_owner(struct kobject *kobj, kuid_t kuid, kgid_t kgid)
|
||||
return 0;
|
||||
}
|
||||
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);
|
||||
|
||||
/* managed devm_k.alloc/kfree for device drivers */
|
||||
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,
|
||||
const char *fmt, va_list ap) __malloc;
|
||||
__printf(3, 4) char *devm_kasprintf(struct device *dev, gfp_t gfp,
|
||||
@ -292,62 +294,6 @@ struct device_dma_parameters {
|
||||
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.
|
||||
* @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,
|
||||
unsigned long start, unsigned long end,
|
||||
struct page *ref_page);
|
||||
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);
|
||||
unsigned long hugetlb_total_pages(void);
|
||||
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)
|
||||
{
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
@ -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,
|
||||
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 */
|
||||
|
||||
|
@ -329,6 +329,10 @@ int sysfs_groups_change_owner(struct kobject *kobj,
|
||||
int sysfs_group_change_owner(struct kobject *kobj,
|
||||
const struct attribute_group *groups, kuid_t kuid,
|
||||
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 */
|
||||
|
||||
@ -576,6 +580,17 @@ static inline int sysfs_group_change_owner(struct kobject *kobj,
|
||||
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 */
|
||||
|
||||
static inline int __must_check sysfs_create_file(struct kobject *kobj,
|
||||
|
20
lib/devres.c
20
lib/devres.c
@ -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
|
||||
* on driver detach.
|
||||
*
|
||||
* Returns a pointer to the remapped memory or an ERR_PTR() encoded error code
|
||||
* on failure. Usage example:
|
||||
* Usage example:
|
||||
*
|
||||
* res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
* base = devm_ioremap_resource(&pdev->dev, res);
|
||||
* if (IS_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,
|
||||
const struct resource *res)
|
||||
@ -183,8 +185,8 @@ EXPORT_SYMBOL(devm_ioremap_resource);
|
||||
* @dev: generic device to handle the resource for
|
||||
* @res: resource to be handled
|
||||
*
|
||||
* Returns a pointer to the remapped memory or an ERR_PTR() encoded error code
|
||||
* on failure. Usage example:
|
||||
* Return: a pointer to the remapped memory or an ERR_PTR() encoded error code
|
||||
* on failure.
|
||||
*/
|
||||
void __iomem *devm_ioremap_resource_wc(struct device *dev,
|
||||
const struct resource *res)
|
||||
@ -207,8 +209,8 @@ void __iomem *devm_ioremap_resource_wc(struct device *dev,
|
||||
* @node: The device-tree node where the resource resides
|
||||
* @index: index of the MMIO range in the "reg" property
|
||||
* @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);
|
||||
* if (IS_ERR(base))
|
||||
@ -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
|
||||
* of_iomap() function does not track whether the region is already mapped. If
|
||||
* two drivers try to map the same memory, the of_iomap() function will succeed
|
||||
* but the the devm_of_iomap() function will return -EBUSY.
|
||||
* 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,
|
||||
resource_size_t *size)
|
||||
@ -256,6 +260,8 @@ static int devm_ioport_map_match(struct device *dev, void *res,
|
||||
*
|
||||
* Managed ioport_map(). Map is automatically unmapped on driver
|
||||
* detach.
|
||||
*
|
||||
* Return: a pointer to the remapped memory or NULL on failure.
|
||||
*/
|
||||
void __iomem *devm_ioport_map(struct device *dev, unsigned long port,
|
||||
unsigned int nr)
|
||||
|
@ -384,10 +384,13 @@ static int ddebug_parse_query(char *words[], int nwords,
|
||||
query->module = modname;
|
||||
|
||||
for (i = 0; i < nwords; i += 2) {
|
||||
if (!strcmp(words[i], "func")) {
|
||||
rc = check_set(&query->function, words[i+1], "func");
|
||||
} else if (!strcmp(words[i], "file")) {
|
||||
if (check_set(&query->filename, words[i+1], "file"))
|
||||
char *keyword = words[i];
|
||||
char *arg = words[i+1];
|
||||
|
||||
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;
|
||||
|
||||
/* tail :$info is function or line-range */
|
||||
@ -403,18 +406,18 @@ static int ddebug_parse_query(char *words[], int nwords,
|
||||
if (parse_linerange(query, fline))
|
||||
return -EINVAL;
|
||||
}
|
||||
} else if (!strcmp(words[i], "module")) {
|
||||
rc = check_set(&query->module, words[i+1], "module");
|
||||
} else if (!strcmp(words[i], "format")) {
|
||||
string_unescape_inplace(words[i+1], UNESCAPE_SPACE |
|
||||
} else if (!strcmp(keyword, "module")) {
|
||||
rc = check_set(&query->module, arg, "module");
|
||||
} else if (!strcmp(keyword, "format")) {
|
||||
string_unescape_inplace(arg, UNESCAPE_SPACE |
|
||||
UNESCAPE_OCTAL |
|
||||
UNESCAPE_SPECIAL);
|
||||
rc = check_set(&query->format, words[i+1], "format");
|
||||
} else if (!strcmp(words[i], "line")) {
|
||||
if (parse_linerange(query, words[i+1]))
|
||||
rc = check_set(&query->format, arg, "format");
|
||||
} else if (!strcmp(keyword, "line")) {
|
||||
if (parse_linerange(query, arg))
|
||||
return -EINVAL;
|
||||
} else {
|
||||
pr_err("unknown keyword \"%s\"\n", words[i]);
|
||||
pr_err("unknown keyword \"%s\"\n", keyword);
|
||||
return -EINVAL;
|
||||
}
|
||||
if (rc)
|
||||
|
18
mm/hugetlb.c
18
mm/hugetlb.c
@ -3571,18 +3571,20 @@ void hugetlb_report_meminfo(struct seq_file *m)
|
||||
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;
|
||||
|
||||
if (!hugepages_supported())
|
||||
return 0;
|
||||
return sprintf(buf,
|
||||
"Node %d HugePages_Total: %5u\n"
|
||||
"Node %d HugePages_Free: %5u\n"
|
||||
"Node %d HugePages_Surp: %5u\n",
|
||||
nid, h->nr_huge_pages_node[nid],
|
||||
nid, h->free_huge_pages_node[nid],
|
||||
nid, h->surplus_huge_pages_node[nid]);
|
||||
|
||||
return sysfs_emit_at(buf, len,
|
||||
"Node %d HugePages_Total: %5u\n"
|
||||
"Node %d HugePages_Free: %5u\n"
|
||||
"Node %d HugePages_Surp: %5u\n",
|
||||
nid, h->nr_huge_pages_node[nid],
|
||||
nid, h->free_huge_pages_node[nid],
|
||||
nid, h->surplus_huge_pages_node[nid]);
|
||||
}
|
||||
|
||||
void hugetlb_show_meminfo(void)
|
||||
|
315
scripts/dev-needs.sh
Executable file
315
scripts/dev-needs.sh
Executable file
@ -0,0 +1,315 @@
|
||||
#! /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
|
Loading…
Reference in New Issue
Block a user