driver core patches for 4.13-rc1
Here is the big driver core update for 4.13-rc1. The large majority of this is a lot of cleanup of old fields in the driver core structures and their remaining usages in random drivers. All of those fixes have been reviewed by the various subsystem maintainers. There's also some small firmware updates in here, a new kobject uevent api interface that makes userspace interaction easier, and a few other minor things. All of these have been in linux-next for a long while with no reported issues. Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> -----BEGIN PGP SIGNATURE----- iG0EABECAC0WIQT0tgzFv3jCIUoxPcsxR9QN2y37KQUCWVpX4A8cZ3JlZ0Brcm9h aC5jb20ACgkQMUfUDdst+ymobgCfd0d13IfpZoq1N41wc6z2Z0xD7cwAnRMeH1/p kEeISGpHPYP9f8PBh9FO =Hfqt -----END PGP SIGNATURE----- Merge tag 'driver-core-4.13-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 driver core update for 4.13-rc1. The large majority of this is a lot of cleanup of old fields in the driver core structures and their remaining usages in random drivers. All of those fixes have been reviewed by the various subsystem maintainers. There's also some small firmware updates in here, a new kobject uevent api interface that makes userspace interaction easier, and a few other minor things. All of these have been in linux-next for a long while with no reported issues" * tag 'driver-core-4.13-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/driver-core: (56 commits) arm: mach-rpc: ecard: fix build error zram: convert remaining CLASS_ATTR() to CLASS_ATTR_RO() driver-core: remove struct bus_type.dev_attrs powerpc: vio_cmo: use dev_groups and not dev_attrs for bus_type powerpc: vio: use dev_groups and not dev_attrs for bus_type USB: usbip: convert to use DRIVER_ATTR_RW s390: drivers: convert to use DRIVER_ATTR_RO/WO platform: thinkpad_acpi: convert to use DRIVER_ATTR_RO/RW pcmcia: ds: convert to use DRIVER_ATTR_RO wireless: ipw2x00: convert to use DRIVER_ATTR_RW net: ehea: convert to use DRIVER_ATTR_RO net: caif: convert to use DRIVER_ATTR_RO TTY: hvc: convert to use DRIVER_ATTR_RW PCI: pci-driver: convert to use DRIVER_ATTR_WO IB: nes: convert to use DRIVER_ATTR_RW HID: hid-core: convert to use DRIVER_ATTR_RO and drv_groups arm: ecard: fix dev_groups patch typo tty: serdev: use dev_groups and not dev_attrs for bus_type sparc: vio: use dev_groups and not dev_attrs for bus_type hid: intel-ish-hid: use dev_groups and not dev_attrs for bus_type ...
This commit is contained in:
commit
974668417b
|
@ -0,0 +1,47 @@
|
|||
What: /sys/.../uevent
|
||||
Date: May 2017
|
||||
KernelVersion: 4.13
|
||||
Contact: Linux kernel mailing list <linux-kernel@vger.kernel.org>
|
||||
Description:
|
||||
Enable passing additional variables for synthetic uevents that
|
||||
are generated by writing /sys/.../uevent file.
|
||||
|
||||
Recognized extended format is ACTION [UUID [KEY=VALUE ...].
|
||||
|
||||
The ACTION is compulsory - it is the name of the uevent action
|
||||
("add", "change", "remove"). There is no change compared to
|
||||
previous functionality here. The rest of the extended format
|
||||
is optional.
|
||||
|
||||
You need to pass UUID first before any KEY=VALUE pairs.
|
||||
The UUID must be in "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
|
||||
format where 'x' is a hex digit. The UUID is considered to be
|
||||
a transaction identifier so it's possible to use the same UUID
|
||||
value for one or more synthetic uevents in which case we
|
||||
logically group these uevents together for any userspace
|
||||
listeners. The UUID value appears in uevent as
|
||||
"SYNTH_UUID=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" environment
|
||||
variable.
|
||||
|
||||
If UUID is not passed in, the generated synthetic uevent gains
|
||||
"SYNTH_UUID=0" environment variable automatically.
|
||||
|
||||
The KEY=VALUE pairs can contain alphanumeric characters only.
|
||||
It's possible to define zero or more pairs - each pair is then
|
||||
delimited by a space character ' '. Each pair appears in
|
||||
synthetic uevent as "SYNTH_ARG_KEY=VALUE". That means the KEY
|
||||
name gains "SYNTH_ARG_" prefix to avoid possible collisions
|
||||
with existing variables.
|
||||
|
||||
Example of valid sequence written to the uevent file:
|
||||
|
||||
add fe4d7c9d-b8c6-4a70-9ef1-3d8a58d18eed A=1 B=abc
|
||||
|
||||
This generates synthetic uevent including these variables:
|
||||
|
||||
ACTION=add
|
||||
SYNTH_ARG_A=1
|
||||
SYNTH_ARG_B=abc
|
||||
SYNTH_UUID=fe4d7c9d-b8c6-4a70-9ef1-3d8a58d18eed
|
||||
Users:
|
||||
udev, userspace tools generating synthetic uevents
|
|
@ -249,7 +249,7 @@ nodes to be present and contain the properties described below.
|
|||
Usage: Optional
|
||||
Value type: <u32>
|
||||
Definition:
|
||||
# u32 value representing CPU capacity [3] in
|
||||
# u32 value representing CPU capacity [4] in
|
||||
DMIPS/MHz, relative to highest capacity-dmips-mhz
|
||||
in the system.
|
||||
|
||||
|
@ -476,5 +476,5 @@ cpus {
|
|||
[2] arm/msm/qcom,kpss-acc.txt
|
||||
[3] ARM Linux kernel documentation - idle states bindings
|
||||
Documentation/devicetree/bindings/arm/idle-states.txt
|
||||
[3] ARM Linux kernel documentation - cpu capacity bindings
|
||||
[4] ARM Linux kernel documentation - cpu capacity bindings
|
||||
Documentation/devicetree/bindings/arm/cpu-capacity.txt
|
||||
|
|
|
@ -44,6 +44,17 @@ request_firmware_nowait
|
|||
.. kernel-doc:: drivers/base/firmware_class.c
|
||||
:functions: request_firmware_nowait
|
||||
|
||||
Considerations for suspend and resume
|
||||
=====================================
|
||||
|
||||
During suspend and resume only the built-in firmware and the firmware cache
|
||||
elements of the firmware API can be used. This is managed by fw_pm_notify().
|
||||
|
||||
fw_pm_notify
|
||||
------------
|
||||
.. kernel-doc:: drivers/base/firmware_class.c
|
||||
:functions: fw_pm_notify
|
||||
|
||||
request firmware API expected driver use
|
||||
========================================
|
||||
|
||||
|
|
|
@ -25,6 +25,7 @@ config ARM
|
|||
select EDAC_SUPPORT
|
||||
select EDAC_ATOMIC_SCRUB
|
||||
select GENERIC_ALLOCATOR
|
||||
select GENERIC_ARCH_TOPOLOGY if ARM_CPU_TOPOLOGY
|
||||
select GENERIC_ATOMIC64 if (CPU_V7M || CPU_V6 || !CPU_32v6K || !AEABI)
|
||||
select GENERIC_CLOCKEVENTS_BROADCAST if SMP
|
||||
select GENERIC_CPU_AUTOPROBE
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
* for more details.
|
||||
*/
|
||||
|
||||
#include <linux/arch_topology.h>
|
||||
#include <linux/cpu.h>
|
||||
#include <linux/cpufreq.h>
|
||||
#include <linux/cpumask.h>
|
||||
|
@ -44,77 +45,6 @@
|
|||
* to run the rebalance_domains for all idle cores and the cpu_capacity can be
|
||||
* updated during this sequence.
|
||||
*/
|
||||
static DEFINE_PER_CPU(unsigned long, cpu_scale) = SCHED_CAPACITY_SCALE;
|
||||
static DEFINE_MUTEX(cpu_scale_mutex);
|
||||
|
||||
unsigned long arch_scale_cpu_capacity(struct sched_domain *sd, int cpu)
|
||||
{
|
||||
return per_cpu(cpu_scale, cpu);
|
||||
}
|
||||
|
||||
static void set_capacity_scale(unsigned int cpu, unsigned long capacity)
|
||||
{
|
||||
per_cpu(cpu_scale, cpu) = capacity;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PROC_SYSCTL
|
||||
static ssize_t cpu_capacity_show(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
struct cpu *cpu = container_of(dev, struct cpu, dev);
|
||||
|
||||
return sprintf(buf, "%lu\n",
|
||||
arch_scale_cpu_capacity(NULL, cpu->dev.id));
|
||||
}
|
||||
|
||||
static ssize_t cpu_capacity_store(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
const char *buf,
|
||||
size_t count)
|
||||
{
|
||||
struct cpu *cpu = container_of(dev, struct cpu, dev);
|
||||
int this_cpu = cpu->dev.id, i;
|
||||
unsigned long new_capacity;
|
||||
ssize_t ret;
|
||||
|
||||
if (count) {
|
||||
ret = kstrtoul(buf, 0, &new_capacity);
|
||||
if (ret)
|
||||
return ret;
|
||||
if (new_capacity > SCHED_CAPACITY_SCALE)
|
||||
return -EINVAL;
|
||||
|
||||
mutex_lock(&cpu_scale_mutex);
|
||||
for_each_cpu(i, &cpu_topology[this_cpu].core_sibling)
|
||||
set_capacity_scale(i, new_capacity);
|
||||
mutex_unlock(&cpu_scale_mutex);
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
static DEVICE_ATTR_RW(cpu_capacity);
|
||||
|
||||
static int register_cpu_capacity_sysctl(void)
|
||||
{
|
||||
int i;
|
||||
struct device *cpu;
|
||||
|
||||
for_each_possible_cpu(i) {
|
||||
cpu = get_cpu_device(i);
|
||||
if (!cpu) {
|
||||
pr_err("%s: too early to get CPU%d device!\n",
|
||||
__func__, i);
|
||||
continue;
|
||||
}
|
||||
device_create_file(cpu, &dev_attr_cpu_capacity);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
subsys_initcall(register_cpu_capacity_sysctl);
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_OF
|
||||
struct cpu_efficiency {
|
||||
|
@ -143,145 +73,6 @@ static unsigned long *__cpu_capacity;
|
|||
|
||||
static unsigned long middle_capacity = 1;
|
||||
static bool cap_from_dt = true;
|
||||
static u32 *raw_capacity;
|
||||
static bool cap_parsing_failed;
|
||||
static u32 capacity_scale;
|
||||
|
||||
static int __init parse_cpu_capacity(struct device_node *cpu_node, int cpu)
|
||||
{
|
||||
int ret = 1;
|
||||
u32 cpu_capacity;
|
||||
|
||||
if (cap_parsing_failed)
|
||||
return !ret;
|
||||
|
||||
ret = of_property_read_u32(cpu_node,
|
||||
"capacity-dmips-mhz",
|
||||
&cpu_capacity);
|
||||
if (!ret) {
|
||||
if (!raw_capacity) {
|
||||
raw_capacity = kcalloc(num_possible_cpus(),
|
||||
sizeof(*raw_capacity),
|
||||
GFP_KERNEL);
|
||||
if (!raw_capacity) {
|
||||
pr_err("cpu_capacity: failed to allocate memory for raw capacities\n");
|
||||
cap_parsing_failed = true;
|
||||
return !ret;
|
||||
}
|
||||
}
|
||||
capacity_scale = max(cpu_capacity, capacity_scale);
|
||||
raw_capacity[cpu] = cpu_capacity;
|
||||
pr_debug("cpu_capacity: %s cpu_capacity=%u (raw)\n",
|
||||
cpu_node->full_name, raw_capacity[cpu]);
|
||||
} else {
|
||||
if (raw_capacity) {
|
||||
pr_err("cpu_capacity: missing %s raw capacity\n",
|
||||
cpu_node->full_name);
|
||||
pr_err("cpu_capacity: partial information: fallback to 1024 for all CPUs\n");
|
||||
}
|
||||
cap_parsing_failed = true;
|
||||
kfree(raw_capacity);
|
||||
}
|
||||
|
||||
return !ret;
|
||||
}
|
||||
|
||||
static void normalize_cpu_capacity(void)
|
||||
{
|
||||
u64 capacity;
|
||||
int cpu;
|
||||
|
||||
if (!raw_capacity || cap_parsing_failed)
|
||||
return;
|
||||
|
||||
pr_debug("cpu_capacity: capacity_scale=%u\n", capacity_scale);
|
||||
mutex_lock(&cpu_scale_mutex);
|
||||
for_each_possible_cpu(cpu) {
|
||||
capacity = (raw_capacity[cpu] << SCHED_CAPACITY_SHIFT)
|
||||
/ capacity_scale;
|
||||
set_capacity_scale(cpu, capacity);
|
||||
pr_debug("cpu_capacity: CPU%d cpu_capacity=%lu\n",
|
||||
cpu, arch_scale_cpu_capacity(NULL, cpu));
|
||||
}
|
||||
mutex_unlock(&cpu_scale_mutex);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_CPU_FREQ
|
||||
static cpumask_var_t cpus_to_visit;
|
||||
static bool cap_parsing_done;
|
||||
static void parsing_done_workfn(struct work_struct *work);
|
||||
static DECLARE_WORK(parsing_done_work, parsing_done_workfn);
|
||||
|
||||
static int
|
||||
init_cpu_capacity_callback(struct notifier_block *nb,
|
||||
unsigned long val,
|
||||
void *data)
|
||||
{
|
||||
struct cpufreq_policy *policy = data;
|
||||
int cpu;
|
||||
|
||||
if (cap_parsing_failed || cap_parsing_done)
|
||||
return 0;
|
||||
|
||||
switch (val) {
|
||||
case CPUFREQ_NOTIFY:
|
||||
pr_debug("cpu_capacity: init cpu capacity for CPUs [%*pbl] (to_visit=%*pbl)\n",
|
||||
cpumask_pr_args(policy->related_cpus),
|
||||
cpumask_pr_args(cpus_to_visit));
|
||||
cpumask_andnot(cpus_to_visit,
|
||||
cpus_to_visit,
|
||||
policy->related_cpus);
|
||||
for_each_cpu(cpu, policy->related_cpus) {
|
||||
raw_capacity[cpu] = arch_scale_cpu_capacity(NULL, cpu) *
|
||||
policy->cpuinfo.max_freq / 1000UL;
|
||||
capacity_scale = max(raw_capacity[cpu], capacity_scale);
|
||||
}
|
||||
if (cpumask_empty(cpus_to_visit)) {
|
||||
normalize_cpu_capacity();
|
||||
kfree(raw_capacity);
|
||||
pr_debug("cpu_capacity: parsing done\n");
|
||||
cap_parsing_done = true;
|
||||
schedule_work(&parsing_done_work);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct notifier_block init_cpu_capacity_notifier = {
|
||||
.notifier_call = init_cpu_capacity_callback,
|
||||
};
|
||||
|
||||
static int __init register_cpufreq_notifier(void)
|
||||
{
|
||||
if (cap_parsing_failed)
|
||||
return -EINVAL;
|
||||
|
||||
if (!alloc_cpumask_var(&cpus_to_visit, GFP_KERNEL)) {
|
||||
pr_err("cpu_capacity: failed to allocate memory for cpus_to_visit\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
cpumask_copy(cpus_to_visit, cpu_possible_mask);
|
||||
|
||||
return cpufreq_register_notifier(&init_cpu_capacity_notifier,
|
||||
CPUFREQ_POLICY_NOTIFIER);
|
||||
}
|
||||
core_initcall(register_cpufreq_notifier);
|
||||
|
||||
static void parsing_done_workfn(struct work_struct *work)
|
||||
{
|
||||
cpufreq_unregister_notifier(&init_cpu_capacity_notifier,
|
||||
CPUFREQ_POLICY_NOTIFIER);
|
||||
}
|
||||
|
||||
#else
|
||||
static int __init free_raw_capacity(void)
|
||||
{
|
||||
kfree(raw_capacity);
|
||||
|
||||
return 0;
|
||||
}
|
||||
core_initcall(free_raw_capacity);
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Iterate all CPUs' descriptor in DT and compute the efficiency
|
||||
|
@ -320,7 +111,7 @@ static void __init parse_dt_topology(void)
|
|||
continue;
|
||||
}
|
||||
|
||||
if (parse_cpu_capacity(cn, cpu)) {
|
||||
if (topology_parse_cpu_capacity(cn, cpu)) {
|
||||
of_node_put(cn);
|
||||
continue;
|
||||
}
|
||||
|
@ -368,8 +159,8 @@ static void __init parse_dt_topology(void)
|
|||
middle_capacity = ((max_capacity / 3)
|
||||
>> (SCHED_CAPACITY_SHIFT-1)) + 1;
|
||||
|
||||
if (cap_from_dt && !cap_parsing_failed)
|
||||
normalize_cpu_capacity();
|
||||
if (cap_from_dt)
|
||||
topology_normalize_cpu_scale();
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -382,10 +173,10 @@ static void update_cpu_capacity(unsigned int cpu)
|
|||
if (!cpu_capacity(cpu) || cap_from_dt)
|
||||
return;
|
||||
|
||||
set_capacity_scale(cpu, cpu_capacity(cpu) / middle_capacity);
|
||||
topology_set_cpu_scale(cpu, cpu_capacity(cpu) / middle_capacity);
|
||||
|
||||
pr_info("CPU%u: update cpu_capacity %lu\n",
|
||||
cpu, arch_scale_cpu_capacity(NULL, cpu));
|
||||
cpu, topology_get_cpu_scale(NULL, cpu));
|
||||
}
|
||||
|
||||
#else
|
||||
|
|
|
@ -761,19 +761,21 @@ static struct expansion_card *__init ecard_alloc_card(int type, int slot)
|
|||
return ec;
|
||||
}
|
||||
|
||||
static ssize_t ecard_show_irq(struct device *dev, struct device_attribute *attr, char *buf)
|
||||
static ssize_t irq_show(struct device *dev, struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct expansion_card *ec = ECARD_DEV(dev);
|
||||
return sprintf(buf, "%u\n", ec->irq);
|
||||
}
|
||||
static DEVICE_ATTR_RO(irq);
|
||||
|
||||
static ssize_t ecard_show_dma(struct device *dev, struct device_attribute *attr, char *buf)
|
||||
static ssize_t dma_show(struct device *dev, struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct expansion_card *ec = ECARD_DEV(dev);
|
||||
return sprintf(buf, "%u\n", ec->dma);
|
||||
}
|
||||
static DEVICE_ATTR_RO(dma);
|
||||
|
||||
static ssize_t ecard_show_resources(struct device *dev, struct device_attribute *attr, char *buf)
|
||||
static ssize_t resource_show(struct device *dev, struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct expansion_card *ec = ECARD_DEV(dev);
|
||||
char *str = buf;
|
||||
|
@ -787,35 +789,39 @@ static ssize_t ecard_show_resources(struct device *dev, struct device_attribute
|
|||
|
||||
return str - buf;
|
||||
}
|
||||
static DEVICE_ATTR_RO(resource);
|
||||
|
||||
static ssize_t ecard_show_vendor(struct device *dev, struct device_attribute *attr, char *buf)
|
||||
static ssize_t vendor_show(struct device *dev, struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct expansion_card *ec = ECARD_DEV(dev);
|
||||
return sprintf(buf, "%u\n", ec->cid.manufacturer);
|
||||
}
|
||||
static DEVICE_ATTR_RO(vendor);
|
||||
|
||||
static ssize_t ecard_show_device(struct device *dev, struct device_attribute *attr, char *buf)
|
||||
static ssize_t device_show(struct device *dev, struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct expansion_card *ec = ECARD_DEV(dev);
|
||||
return sprintf(buf, "%u\n", ec->cid.product);
|
||||
}
|
||||
static DEVICE_ATTR_RO(device);
|
||||
|
||||
static ssize_t ecard_show_type(struct device *dev, struct device_attribute *attr, char *buf)
|
||||
static ssize_t type_show(struct device *dev, struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct expansion_card *ec = ECARD_DEV(dev);
|
||||
return sprintf(buf, "%s\n", ec->easi ? "EASI" : "IOC");
|
||||
}
|
||||
static DEVICE_ATTR_RO(type);
|
||||
|
||||
static struct device_attribute ecard_dev_attrs[] = {
|
||||
__ATTR(device, S_IRUGO, ecard_show_device, NULL),
|
||||
__ATTR(dma, S_IRUGO, ecard_show_dma, NULL),
|
||||
__ATTR(irq, S_IRUGO, ecard_show_irq, NULL),
|
||||
__ATTR(resource, S_IRUGO, ecard_show_resources, NULL),
|
||||
__ATTR(type, S_IRUGO, ecard_show_type, NULL),
|
||||
__ATTR(vendor, S_IRUGO, ecard_show_vendor, NULL),
|
||||
__ATTR_NULL,
|
||||
static struct attribute *ecard_dev_attrs[] = {
|
||||
&dev_attr_device.attr,
|
||||
&dev_attr_dma.attr,
|
||||
&dev_attr_irq.attr,
|
||||
&dev_attr_resource.attr,
|
||||
&dev_attr_type.attr,
|
||||
&dev_attr_vendor.attr,
|
||||
NULL,
|
||||
};
|
||||
|
||||
ATTRIBUTE_GROUPS(ecard_dev);
|
||||
|
||||
int ecard_request_resources(struct expansion_card *ec)
|
||||
{
|
||||
|
@ -1120,7 +1126,7 @@ static int ecard_match(struct device *_dev, struct device_driver *_drv)
|
|||
|
||||
struct bus_type ecard_bus_type = {
|
||||
.name = "ecard",
|
||||
.dev_attrs = ecard_dev_attrs,
|
||||
.dev_groups = ecard_dev_groups,
|
||||
.match = ecard_match,
|
||||
.probe = ecard_drv_probe,
|
||||
.remove = ecard_drv_remove,
|
||||
|
|
|
@ -41,6 +41,7 @@ config ARM64
|
|||
select EDAC_SUPPORT
|
||||
select FRAME_POINTER
|
||||
select GENERIC_ALLOCATOR
|
||||
select GENERIC_ARCH_TOPOLOGY
|
||||
select GENERIC_CLOCKEVENTS
|
||||
select GENERIC_CLOCKEVENTS_BROADCAST
|
||||
select GENERIC_CPU_AUTOPROBE
|
||||
|
|
|
@ -11,7 +11,7 @@
|
|||
* for more details.
|
||||
*/
|
||||
|
||||
#include <linux/acpi.h>
|
||||
#include <linux/arch_topology.h>
|
||||
#include <linux/cpu.h>
|
||||
#include <linux/cpumask.h>
|
||||
#include <linux/init.h>
|
||||
|
@ -23,227 +23,11 @@
|
|||
#include <linux/sched/topology.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/cpufreq.h>
|
||||
|
||||
#include <asm/cpu.h>
|
||||
#include <asm/cputype.h>
|
||||
#include <asm/topology.h>
|
||||
|
||||
static DEFINE_PER_CPU(unsigned long, cpu_scale) = SCHED_CAPACITY_SCALE;
|
||||
static DEFINE_MUTEX(cpu_scale_mutex);
|
||||
|
||||
unsigned long arch_scale_cpu_capacity(struct sched_domain *sd, int cpu)
|
||||
{
|
||||
return per_cpu(cpu_scale, cpu);
|
||||
}
|
||||
|
||||
static void set_capacity_scale(unsigned int cpu, unsigned long capacity)
|
||||
{
|
||||
per_cpu(cpu_scale, cpu) = capacity;
|
||||
}
|
||||
|
||||
static ssize_t cpu_capacity_show(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
struct cpu *cpu = container_of(dev, struct cpu, dev);
|
||||
|
||||
return sprintf(buf, "%lu\n",
|
||||
arch_scale_cpu_capacity(NULL, cpu->dev.id));
|
||||
}
|
||||
|
||||
static ssize_t cpu_capacity_store(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
const char *buf,
|
||||
size_t count)
|
||||
{
|
||||
struct cpu *cpu = container_of(dev, struct cpu, dev);
|
||||
int this_cpu = cpu->dev.id, i;
|
||||
unsigned long new_capacity;
|
||||
ssize_t ret;
|
||||
|
||||
if (count) {
|
||||
ret = kstrtoul(buf, 0, &new_capacity);
|
||||
if (ret)
|
||||
return ret;
|
||||
if (new_capacity > SCHED_CAPACITY_SCALE)
|
||||
return -EINVAL;
|
||||
|
||||
mutex_lock(&cpu_scale_mutex);
|
||||
for_each_cpu(i, &cpu_topology[this_cpu].core_sibling)
|
||||
set_capacity_scale(i, new_capacity);
|
||||
mutex_unlock(&cpu_scale_mutex);
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
static DEVICE_ATTR_RW(cpu_capacity);
|
||||
|
||||
static int register_cpu_capacity_sysctl(void)
|
||||
{
|
||||
int i;
|
||||
struct device *cpu;
|
||||
|
||||
for_each_possible_cpu(i) {
|
||||
cpu = get_cpu_device(i);
|
||||
if (!cpu) {
|
||||
pr_err("%s: too early to get CPU%d device!\n",
|
||||
__func__, i);
|
||||
continue;
|
||||
}
|
||||
device_create_file(cpu, &dev_attr_cpu_capacity);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
subsys_initcall(register_cpu_capacity_sysctl);
|
||||
|
||||
static u32 capacity_scale;
|
||||
static u32 *raw_capacity;
|
||||
static bool cap_parsing_failed;
|
||||
|
||||
static void __init parse_cpu_capacity(struct device_node *cpu_node, int cpu)
|
||||
{
|
||||
int ret;
|
||||
u32 cpu_capacity;
|
||||
|
||||
if (cap_parsing_failed)
|
||||
return;
|
||||
|
||||
ret = of_property_read_u32(cpu_node,
|
||||
"capacity-dmips-mhz",
|
||||
&cpu_capacity);
|
||||
if (!ret) {
|
||||
if (!raw_capacity) {
|
||||
raw_capacity = kcalloc(num_possible_cpus(),
|
||||
sizeof(*raw_capacity),
|
||||
GFP_KERNEL);
|
||||
if (!raw_capacity) {
|
||||
pr_err("cpu_capacity: failed to allocate memory for raw capacities\n");
|
||||
cap_parsing_failed = true;
|
||||
return;
|
||||
}
|
||||
}
|
||||
capacity_scale = max(cpu_capacity, capacity_scale);
|
||||
raw_capacity[cpu] = cpu_capacity;
|
||||
pr_debug("cpu_capacity: %s cpu_capacity=%u (raw)\n",
|
||||
cpu_node->full_name, raw_capacity[cpu]);
|
||||
} else {
|
||||
if (raw_capacity) {
|
||||
pr_err("cpu_capacity: missing %s raw capacity\n",
|
||||
cpu_node->full_name);
|
||||
pr_err("cpu_capacity: partial information: fallback to 1024 for all CPUs\n");
|
||||
}
|
||||
cap_parsing_failed = true;
|
||||
kfree(raw_capacity);
|
||||
}
|
||||
}
|
||||
|
||||
static void normalize_cpu_capacity(void)
|
||||
{
|
||||
u64 capacity;
|
||||
int cpu;
|
||||
|
||||
if (!raw_capacity || cap_parsing_failed)
|
||||
return;
|
||||
|
||||
pr_debug("cpu_capacity: capacity_scale=%u\n", capacity_scale);
|
||||
mutex_lock(&cpu_scale_mutex);
|
||||
for_each_possible_cpu(cpu) {
|
||||
pr_debug("cpu_capacity: cpu=%d raw_capacity=%u\n",
|
||||
cpu, raw_capacity[cpu]);
|
||||
capacity = (raw_capacity[cpu] << SCHED_CAPACITY_SHIFT)
|
||||
/ capacity_scale;
|
||||
set_capacity_scale(cpu, capacity);
|
||||
pr_debug("cpu_capacity: CPU%d cpu_capacity=%lu\n",
|
||||
cpu, arch_scale_cpu_capacity(NULL, cpu));
|
||||
}
|
||||
mutex_unlock(&cpu_scale_mutex);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_CPU_FREQ
|
||||
static cpumask_var_t cpus_to_visit;
|
||||
static bool cap_parsing_done;
|
||||
static void parsing_done_workfn(struct work_struct *work);
|
||||
static DECLARE_WORK(parsing_done_work, parsing_done_workfn);
|
||||
|
||||
static int
|
||||
init_cpu_capacity_callback(struct notifier_block *nb,
|
||||
unsigned long val,
|
||||
void *data)
|
||||
{
|
||||
struct cpufreq_policy *policy = data;
|
||||
int cpu;
|
||||
|
||||
if (cap_parsing_failed || cap_parsing_done)
|
||||
return 0;
|
||||
|
||||
switch (val) {
|
||||
case CPUFREQ_NOTIFY:
|
||||
pr_debug("cpu_capacity: init cpu capacity for CPUs [%*pbl] (to_visit=%*pbl)\n",
|
||||
cpumask_pr_args(policy->related_cpus),
|
||||
cpumask_pr_args(cpus_to_visit));
|
||||
cpumask_andnot(cpus_to_visit,
|
||||
cpus_to_visit,
|
||||
policy->related_cpus);
|
||||
for_each_cpu(cpu, policy->related_cpus) {
|
||||
raw_capacity[cpu] = arch_scale_cpu_capacity(NULL, cpu) *
|
||||
policy->cpuinfo.max_freq / 1000UL;
|
||||
capacity_scale = max(raw_capacity[cpu], capacity_scale);
|
||||
}
|
||||
if (cpumask_empty(cpus_to_visit)) {
|
||||
normalize_cpu_capacity();
|
||||
kfree(raw_capacity);
|
||||
pr_debug("cpu_capacity: parsing done\n");
|
||||
cap_parsing_done = true;
|
||||
schedule_work(&parsing_done_work);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct notifier_block init_cpu_capacity_notifier = {
|
||||
.notifier_call = init_cpu_capacity_callback,
|
||||
};
|
||||
|
||||
static int __init register_cpufreq_notifier(void)
|
||||
{
|
||||
/*
|
||||
* on ACPI-based systems we need to use the default cpu capacity
|
||||
* until we have the necessary code to parse the cpu capacity, so
|
||||
* skip registering cpufreq notifier.
|
||||
*/
|
||||
if (!acpi_disabled || cap_parsing_failed)
|
||||
return -EINVAL;
|
||||
|
||||
if (!alloc_cpumask_var(&cpus_to_visit, GFP_KERNEL)) {
|
||||
pr_err("cpu_capacity: failed to allocate memory for cpus_to_visit\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
cpumask_copy(cpus_to_visit, cpu_possible_mask);
|
||||
|
||||
return cpufreq_register_notifier(&init_cpu_capacity_notifier,
|
||||
CPUFREQ_POLICY_NOTIFIER);
|
||||
}
|
||||
core_initcall(register_cpufreq_notifier);
|
||||
|
||||
static void parsing_done_workfn(struct work_struct *work)
|
||||
{
|
||||
cpufreq_unregister_notifier(&init_cpu_capacity_notifier,
|
||||
CPUFREQ_POLICY_NOTIFIER);
|
||||
}
|
||||
|
||||
#else
|
||||
static int __init free_raw_capacity(void)
|
||||
{
|
||||
kfree(raw_capacity);
|
||||
|
||||
return 0;
|
||||
}
|
||||
core_initcall(free_raw_capacity);
|
||||
#endif
|
||||
|
||||
static int __init get_cpu_for_node(struct device_node *node)
|
||||
{
|
||||
struct device_node *cpu_node;
|
||||
|
@ -255,7 +39,7 @@ static int __init get_cpu_for_node(struct device_node *node)
|
|||
|
||||
for_each_possible_cpu(cpu) {
|
||||
if (of_get_cpu_node(cpu, NULL) == cpu_node) {
|
||||
parse_cpu_capacity(cpu_node, cpu);
|
||||
topology_parse_cpu_capacity(cpu_node, cpu);
|
||||
of_node_put(cpu_node);
|
||||
return cpu;
|
||||
}
|
||||
|
@ -400,16 +184,14 @@ static int __init parse_dt_topology(void)
|
|||
* cluster with restricted subnodes.
|
||||
*/
|
||||
map = of_get_child_by_name(cn, "cpu-map");
|
||||
if (!map) {
|
||||
cap_parsing_failed = true;
|
||||
if (!map)
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = parse_cluster(map, 0);
|
||||
if (ret != 0)
|
||||
goto out_map;
|
||||
|
||||
normalize_cpu_capacity();
|
||||
topology_normalize_cpu_scale();
|
||||
|
||||
/*
|
||||
* Check that all cores are in the topology; the SMP code will
|
||||
|
|
|
@ -169,6 +169,7 @@ static ssize_t modalias_show(struct device *dev, struct device_attribute *a,
|
|||
|
||||
return (len >= PAGE_SIZE) ? (PAGE_SIZE - 1) : len;
|
||||
}
|
||||
static DEVICE_ATTR_RO(modalias);
|
||||
|
||||
static ssize_t name_show(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
|
@ -178,6 +179,7 @@ static ssize_t name_show(struct device *dev,
|
|||
giodev = to_gio_device(dev);
|
||||
return sprintf(buf, "%s", giodev->name);
|
||||
}
|
||||
static DEVICE_ATTR_RO(name);
|
||||
|
||||
static ssize_t id_show(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
|
@ -187,13 +189,15 @@ static ssize_t id_show(struct device *dev,
|
|||
giodev = to_gio_device(dev);
|
||||
return sprintf(buf, "%x", giodev->id.id);
|
||||
}
|
||||
static DEVICE_ATTR_RO(id);
|
||||
|
||||
static struct device_attribute gio_dev_attrs[] = {
|
||||
__ATTR_RO(modalias),
|
||||
__ATTR_RO(name),
|
||||
__ATTR_RO(id),
|
||||
__ATTR_NULL,
|
||||
static struct attribute *gio_dev_attrs[] = {
|
||||
&dev_attr_modalias.attr,
|
||||
&dev_attr_name.attr,
|
||||
&dev_attr_id.attr,
|
||||
NULL,
|
||||
};
|
||||
ATTRIBUTE_GROUPS(gio_dev);
|
||||
|
||||
static int gio_device_uevent(struct device *dev, struct kobj_uevent_env *env)
|
||||
{
|
||||
|
@ -374,7 +378,7 @@ static void ip22_check_gio(int slotno, unsigned long addr, int irq)
|
|||
|
||||
static struct bus_type gio_bus_type = {
|
||||
.name = "gio",
|
||||
.dev_attrs = gio_dev_attrs,
|
||||
.dev_groups = gio_dev_groups,
|
||||
.match = gio_bus_match,
|
||||
.probe = gio_device_probe,
|
||||
.remove = gio_device_remove,
|
||||
|
|
|
@ -575,7 +575,8 @@ static ssize_t name##_show(struct device *dev, struct device_attribute *attr, ch
|
|||
{ \
|
||||
struct parisc_device *padev = to_parisc_device(dev); \
|
||||
return sprintf(buf, format_string, padev->field); \
|
||||
}
|
||||
} \
|
||||
static DEVICE_ATTR_RO(name);
|
||||
|
||||
#define pa_dev_attr_id(field, format) pa_dev_attr(field, id.field, format)
|
||||
|
||||
|
@ -589,22 +590,24 @@ static ssize_t modalias_show(struct device *dev, struct device_attribute *attr,
|
|||
{
|
||||
return make_modalias(dev, buf);
|
||||
}
|
||||
static DEVICE_ATTR_RO(modalias);
|
||||
|
||||
static struct device_attribute parisc_device_attrs[] = {
|
||||
__ATTR_RO(irq),
|
||||
__ATTR_RO(hw_type),
|
||||
__ATTR_RO(rev),
|
||||
__ATTR_RO(hversion),
|
||||
__ATTR_RO(sversion),
|
||||
__ATTR_RO(modalias),
|
||||
__ATTR_NULL,
|
||||
static struct attribute *parisc_device_attrs[] = {
|
||||
&dev_attr_irq.attr,
|
||||
&dev_attr_hw_type.attr,
|
||||
&dev_attr_rev.attr,
|
||||
&dev_attr_hversion.attr,
|
||||
&dev_attr_sversion.attr,
|
||||
&dev_attr_modalias.attr,
|
||||
NULL,
|
||||
};
|
||||
ATTRIBUTE_GROUPS(parisc_device);
|
||||
|
||||
struct bus_type parisc_bus_type = {
|
||||
.name = "parisc",
|
||||
.match = parisc_generic_match,
|
||||
.uevent = parisc_uevent,
|
||||
.dev_attrs = parisc_device_attrs,
|
||||
.dev_groups = parisc_device_groups,
|
||||
.probe = parisc_driver_probe,
|
||||
.remove = parisc_driver_remove,
|
||||
};
|
||||
|
|
|
@ -471,11 +471,13 @@ static ssize_t modalias_show(struct device *_dev, struct device_attribute *a,
|
|||
|
||||
return (len >= PAGE_SIZE) ? (PAGE_SIZE - 1) : len;
|
||||
}
|
||||
static DEVICE_ATTR_RO(modalias);
|
||||
|
||||
static struct device_attribute ps3_system_bus_dev_attrs[] = {
|
||||
__ATTR_RO(modalias),
|
||||
__ATTR_NULL,
|
||||
static struct attribute *ps3_system_bus_dev_attrs[] = {
|
||||
&dev_attr_modalias.attr,
|
||||
NULL,
|
||||
};
|
||||
ATTRIBUTE_GROUPS(ps3_system_bus_dev);
|
||||
|
||||
struct bus_type ps3_system_bus_type = {
|
||||
.name = "ps3_system_bus",
|
||||
|
@ -484,7 +486,7 @@ struct bus_type ps3_system_bus_type = {
|
|||
.probe = ps3_system_bus_probe,
|
||||
.remove = ps3_system_bus_remove,
|
||||
.shutdown = ps3_system_bus_shutdown,
|
||||
.dev_attrs = ps3_system_bus_dev_attrs,
|
||||
.dev_groups = ps3_system_bus_dev_groups,
|
||||
};
|
||||
|
||||
static int __init ps3_system_bus_init(void)
|
||||
|
|
|
@ -588,7 +588,7 @@ static ssize_t dlpar_show(struct class *class, struct class_attribute *attr,
|
|||
return sprintf(buf, "%s\n", "memory,cpu");
|
||||
}
|
||||
|
||||
static CLASS_ATTR(dlpar, S_IWUSR | S_IRUSR, dlpar_show, dlpar_store);
|
||||
static CLASS_ATTR_RW(dlpar);
|
||||
|
||||
static int __init pseries_dlpar_init(void)
|
||||
{
|
||||
|
|
|
@ -397,6 +397,7 @@ static ssize_t devspec_show(struct device *dev,
|
|||
ofdev = to_platform_device(dev);
|
||||
return sprintf(buf, "%s\n", ofdev->dev.of_node->full_name);
|
||||
}
|
||||
static DEVICE_ATTR_RO(devspec);
|
||||
|
||||
static ssize_t name_show(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
|
@ -406,19 +407,22 @@ static ssize_t name_show(struct device *dev,
|
|||
ofdev = to_platform_device(dev);
|
||||
return sprintf(buf, "%s\n", ofdev->dev.of_node->name);
|
||||
}
|
||||
static DEVICE_ATTR_RO(name);
|
||||
|
||||
static ssize_t modalias_show(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
return of_device_modalias(dev, buf, PAGE_SIZE);
|
||||
}
|
||||
static DEVICE_ATTR_RO(modalias);
|
||||
|
||||
static struct device_attribute ibmebus_bus_device_attrs[] = {
|
||||
__ATTR_RO(devspec),
|
||||
__ATTR_RO(name),
|
||||
__ATTR_RO(modalias),
|
||||
__ATTR_NULL
|
||||
static struct attribute *ibmebus_bus_device_attrs[] = {
|
||||
&dev_attr_devspec.attr,
|
||||
&dev_attr_name.attr,
|
||||
&dev_attr_modalias.attr,
|
||||
NULL,
|
||||
};
|
||||
ATTRIBUTE_GROUPS(ibmebus_bus_device);
|
||||
|
||||
struct bus_type ibmebus_bus_type = {
|
||||
.name = "ibmebus",
|
||||
|
@ -428,7 +432,7 @@ struct bus_type ibmebus_bus_type = {
|
|||
.probe = ibmebus_bus_device_probe,
|
||||
.remove = ibmebus_bus_device_remove,
|
||||
.shutdown = ibmebus_bus_device_shutdown,
|
||||
.dev_attrs = ibmebus_bus_device_attrs,
|
||||
.dev_groups = ibmebus_bus_device_groups,
|
||||
};
|
||||
EXPORT_SYMBOL(ibmebus_bus_type);
|
||||
|
||||
|
|
|
@ -349,8 +349,9 @@ void post_mobility_fixup(void)
|
|||
return;
|
||||
}
|
||||
|
||||
static ssize_t migrate_store(struct class *class, struct class_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
static ssize_t migration_store(struct class *class,
|
||||
struct class_attribute *attr, const char *buf,
|
||||
size_t count)
|
||||
{
|
||||
u64 streamid;
|
||||
int rc;
|
||||
|
@ -380,7 +381,7 @@ static ssize_t migrate_store(struct class *class, struct class_attribute *attr,
|
|||
*/
|
||||
#define MIGRATION_API_VERSION 1
|
||||
|
||||
static CLASS_ATTR(migration, S_IWUSR, NULL, migrate_store);
|
||||
static CLASS_ATTR_WO(migration);
|
||||
static CLASS_ATTR_STRING(api_version, S_IRUGO, __stringify(MIGRATION_API_VERSION));
|
||||
|
||||
static int __init mobility_sysfs_init(void)
|
||||
|
|
|
@ -948,21 +948,21 @@ static void vio_cmo_bus_init(void)
|
|||
/* sysfs device functions and data structures for CMO */
|
||||
|
||||
#define viodev_cmo_rd_attr(name) \
|
||||
static ssize_t viodev_cmo_##name##_show(struct device *dev, \
|
||||
static ssize_t cmo_##name##_show(struct device *dev, \
|
||||
struct device_attribute *attr, \
|
||||
char *buf) \
|
||||
{ \
|
||||
return sprintf(buf, "%lu\n", to_vio_dev(dev)->cmo.name); \
|
||||
}
|
||||
|
||||
static ssize_t viodev_cmo_allocs_failed_show(struct device *dev,
|
||||
static ssize_t cmo_allocs_failed_show(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct vio_dev *viodev = to_vio_dev(dev);
|
||||
return sprintf(buf, "%d\n", atomic_read(&viodev->cmo.allocs_failed));
|
||||
}
|
||||
|
||||
static ssize_t viodev_cmo_allocs_failed_reset(struct device *dev,
|
||||
static ssize_t cmo_allocs_failed_store(struct device *dev,
|
||||
struct device_attribute *attr, const char *buf, size_t count)
|
||||
{
|
||||
struct vio_dev *viodev = to_vio_dev(dev);
|
||||
|
@ -970,7 +970,7 @@ static ssize_t viodev_cmo_allocs_failed_reset(struct device *dev,
|
|||
return count;
|
||||
}
|
||||
|
||||
static ssize_t viodev_cmo_desired_set(struct device *dev,
|
||||
static ssize_t cmo_desired_store(struct device *dev,
|
||||
struct device_attribute *attr, const char *buf, size_t count)
|
||||
{
|
||||
struct vio_dev *viodev = to_vio_dev(dev);
|
||||
|
@ -993,27 +993,37 @@ static ssize_t name_show(struct device *, struct device_attribute *, char *);
|
|||
static ssize_t devspec_show(struct device *, struct device_attribute *, char *);
|
||||
static ssize_t modalias_show(struct device *dev, struct device_attribute *attr,
|
||||
char *buf);
|
||||
static struct device_attribute vio_cmo_dev_attrs[] = {
|
||||
__ATTR_RO(name),
|
||||
__ATTR_RO(devspec),
|
||||
__ATTR_RO(modalias),
|
||||
__ATTR(cmo_desired, S_IWUSR|S_IRUSR|S_IWGRP|S_IRGRP|S_IROTH,
|
||||
viodev_cmo_desired_show, viodev_cmo_desired_set),
|
||||
__ATTR(cmo_entitled, S_IRUGO, viodev_cmo_entitled_show, NULL),
|
||||
__ATTR(cmo_allocated, S_IRUGO, viodev_cmo_allocated_show, NULL),
|
||||
__ATTR(cmo_allocs_failed, S_IWUSR|S_IRUSR|S_IWGRP|S_IRGRP|S_IROTH,
|
||||
viodev_cmo_allocs_failed_show, viodev_cmo_allocs_failed_reset),
|
||||
__ATTR_NULL
|
||||
|
||||
static struct device_attribute dev_attr_name;
|
||||
static struct device_attribute dev_attr_devspec;
|
||||
static struct device_attribute dev_attr_modalias;
|
||||
|
||||
static DEVICE_ATTR_RO(cmo_entitled);
|
||||
static DEVICE_ATTR_RO(cmo_allocated);
|
||||
static DEVICE_ATTR_RW(cmo_desired);
|
||||
static DEVICE_ATTR_RW(cmo_allocs_failed);
|
||||
|
||||
static struct attribute *vio_cmo_dev_attrs[] = {
|
||||
&dev_attr_name.attr,
|
||||
&dev_attr_devspec.attr,
|
||||
&dev_attr_modalias.attr,
|
||||
&dev_attr_cmo_entitled.attr,
|
||||
&dev_attr_cmo_allocated.attr,
|
||||
&dev_attr_cmo_desired.attr,
|
||||
&dev_attr_cmo_allocs_failed.attr,
|
||||
NULL,
|
||||
};
|
||||
ATTRIBUTE_GROUPS(vio_cmo_dev);
|
||||
|
||||
/* sysfs bus functions and data structures for CMO */
|
||||
|
||||
#define viobus_cmo_rd_attr(name) \
|
||||
static ssize_t cmo_##name##_show(struct bus_type *bt, char *buf) \
|
||||
static ssize_t cmo_bus_##name##_show(struct bus_type *bt, char *buf) \
|
||||
{ \
|
||||
return sprintf(buf, "%lu\n", vio_cmo.name); \
|
||||
} \
|
||||
static BUS_ATTR_RO(cmo_##name)
|
||||
static struct bus_attribute bus_attr_cmo_bus_##name = \
|
||||
__ATTR(cmo_##name, S_IRUGO, cmo_bus_##name##_show, NULL)
|
||||
|
||||
#define viobus_cmo_pool_rd_attr(name, var) \
|
||||
static ssize_t \
|
||||
|
@ -1051,11 +1061,11 @@ static ssize_t cmo_high_store(struct bus_type *bt, const char *buf,
|
|||
static BUS_ATTR_RW(cmo_high);
|
||||
|
||||
static struct attribute *vio_bus_attrs[] = {
|
||||
&bus_attr_cmo_entitled.attr,
|
||||
&bus_attr_cmo_spare.attr,
|
||||
&bus_attr_cmo_min.attr,
|
||||
&bus_attr_cmo_desired.attr,
|
||||
&bus_attr_cmo_curr.attr,
|
||||
&bus_attr_cmo_bus_entitled.attr,
|
||||
&bus_attr_cmo_bus_spare.attr,
|
||||
&bus_attr_cmo_bus_min.attr,
|
||||
&bus_attr_cmo_bus_desired.attr,
|
||||
&bus_attr_cmo_bus_curr.attr,
|
||||
&bus_attr_cmo_high.attr,
|
||||
&bus_attr_cmo_reserve_size.attr,
|
||||
&bus_attr_cmo_excess_size.attr,
|
||||
|
@ -1066,7 +1076,7 @@ ATTRIBUTE_GROUPS(vio_bus);
|
|||
|
||||
static void vio_cmo_sysfs_init(void)
|
||||
{
|
||||
vio_bus_type.dev_attrs = vio_cmo_dev_attrs;
|
||||
vio_bus_type.dev_groups = vio_cmo_dev_groups;
|
||||
vio_bus_type.bus_groups = vio_bus_groups;
|
||||
}
|
||||
#else /* CONFIG_PPC_SMLPAR */
|
||||
|
@ -1537,6 +1547,7 @@ static ssize_t name_show(struct device *dev,
|
|||
{
|
||||
return sprintf(buf, "%s\n", to_vio_dev(dev)->name);
|
||||
}
|
||||
static DEVICE_ATTR_RO(name);
|
||||
|
||||
static ssize_t devspec_show(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
|
@ -1545,6 +1556,7 @@ static ssize_t devspec_show(struct device *dev,
|
|||
|
||||
return sprintf(buf, "%s\n", of_node_full_name(of_node));
|
||||
}
|
||||
static DEVICE_ATTR_RO(devspec);
|
||||
|
||||
static ssize_t modalias_show(struct device *dev, struct device_attribute *attr,
|
||||
char *buf)
|
||||
|
@ -1566,13 +1578,15 @@ static ssize_t modalias_show(struct device *dev, struct device_attribute *attr,
|
|||
|
||||
return sprintf(buf, "vio:T%sS%s\n", vio_dev->type, cp);
|
||||
}
|
||||
static DEVICE_ATTR_RO(modalias);
|
||||
|
||||
static struct device_attribute vio_dev_attrs[] = {
|
||||
__ATTR_RO(name),
|
||||
__ATTR_RO(devspec),
|
||||
__ATTR_RO(modalias),
|
||||
__ATTR_NULL
|
||||
static struct attribute *vio_dev_attrs[] = {
|
||||
&dev_attr_name.attr,
|
||||
&dev_attr_devspec.attr,
|
||||
&dev_attr_modalias.attr,
|
||||
NULL,
|
||||
};
|
||||
ATTRIBUTE_GROUPS(vio_dev);
|
||||
|
||||
void vio_unregister_device(struct vio_dev *viodev)
|
||||
{
|
||||
|
@ -1608,7 +1622,7 @@ static int vio_hotplug(struct device *dev, struct kobj_uevent_env *env)
|
|||
|
||||
struct bus_type vio_bus_type = {
|
||||
.name = "vio",
|
||||
.dev_attrs = vio_dev_attrs,
|
||||
.dev_groups = vio_dev_groups,
|
||||
.uevent = vio_hotplug,
|
||||
.match = vio_bus_match,
|
||||
.probe = vio_bus_probe,
|
||||
|
|
|
@ -105,6 +105,7 @@ static ssize_t devspec_show(struct device *dev,
|
|||
|
||||
return sprintf(buf, "%s\n", str);
|
||||
}
|
||||
static DEVICE_ATTR_RO(devspec);
|
||||
|
||||
static ssize_t type_show(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
|
@ -112,6 +113,7 @@ static ssize_t type_show(struct device *dev,
|
|||
struct vio_dev *vdev = to_vio_dev(dev);
|
||||
return sprintf(buf, "%s\n", vdev->type);
|
||||
}
|
||||
static DEVICE_ATTR_RO(type);
|
||||
|
||||
static ssize_t modalias_show(struct device *dev, struct device_attribute *attr,
|
||||
char *buf)
|
||||
|
@ -120,17 +122,19 @@ static ssize_t modalias_show(struct device *dev, struct device_attribute *attr,
|
|||
|
||||
return sprintf(buf, "vio:T%sS%s\n", vdev->type, vdev->compat);
|
||||
}
|
||||
static DEVICE_ATTR_RO(modalias);
|
||||
|
||||
static struct device_attribute vio_dev_attrs[] = {
|
||||
__ATTR_RO(devspec),
|
||||
__ATTR_RO(type),
|
||||
__ATTR_RO(modalias),
|
||||
__ATTR_NULL
|
||||
};
|
||||
static struct attribute *vio_dev_attrs[] = {
|
||||
&dev_attr_devspec.attr,
|
||||
&dev_attr_type.attr,
|
||||
&dev_attr_modalias.attr,
|
||||
NULL,
|
||||
};
|
||||
ATTRIBUTE_GROUPS(vio_dev);
|
||||
|
||||
static struct bus_type vio_bus_type = {
|
||||
.name = "vio",
|
||||
.dev_attrs = vio_dev_attrs,
|
||||
.dev_groups = vio_dev_groups,
|
||||
.uevent = vio_hotplug,
|
||||
.match = vio_bus_match,
|
||||
.probe = vio_device_probe,
|
||||
|
|
|
@ -105,6 +105,7 @@ static ssize_t driver_override_store(struct device *_dev,
|
|||
|
||||
return count;
|
||||
}
|
||||
static DEVICE_ATTR_RW(driver_override);
|
||||
|
||||
#define amba_attr_func(name,fmt,arg...) \
|
||||
static ssize_t name##_show(struct device *_dev, \
|
||||
|
@ -112,25 +113,23 @@ static ssize_t name##_show(struct device *_dev, \
|
|||
{ \
|
||||
struct amba_device *dev = to_amba_device(_dev); \
|
||||
return sprintf(buf, fmt, arg); \
|
||||
}
|
||||
|
||||
#define amba_attr(name,fmt,arg...) \
|
||||
amba_attr_func(name,fmt,arg) \
|
||||
static DEVICE_ATTR(name, S_IRUGO, name##_show, NULL)
|
||||
} \
|
||||
static DEVICE_ATTR_RO(name)
|
||||
|
||||
amba_attr_func(id, "%08x\n", dev->periphid);
|
||||
amba_attr(irq0, "%u\n", dev->irq[0]);
|
||||
amba_attr(irq1, "%u\n", dev->irq[1]);
|
||||
amba_attr_func(irq0, "%u\n", dev->irq[0]);
|
||||
amba_attr_func(irq1, "%u\n", dev->irq[1]);
|
||||
amba_attr_func(resource, "\t%016llx\t%016llx\t%016lx\n",
|
||||
(unsigned long long)dev->res.start, (unsigned long long)dev->res.end,
|
||||
dev->res.flags);
|
||||
|
||||
static struct device_attribute amba_dev_attrs[] = {
|
||||
__ATTR_RO(id),
|
||||
__ATTR_RO(resource),
|
||||
__ATTR_RW(driver_override),
|
||||
__ATTR_NULL,
|
||||
static struct attribute *amba_dev_attrs[] = {
|
||||
&dev_attr_id.attr,
|
||||
&dev_attr_resource.attr,
|
||||
&dev_attr_driver_override.attr,
|
||||
NULL,
|
||||
};
|
||||
ATTRIBUTE_GROUPS(amba_dev);
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
/*
|
||||
|
@ -192,7 +191,7 @@ static const struct dev_pm_ops amba_pm = {
|
|||
*/
|
||||
struct bus_type amba_bustype = {
|
||||
.name = "amba",
|
||||
.dev_attrs = amba_dev_attrs,
|
||||
.dev_groups = amba_dev_groups,
|
||||
.match = amba_match,
|
||||
.uevent = amba_uevent,
|
||||
.pm = &amba_pm,
|
||||
|
|
|
@ -339,4 +339,12 @@ config CMA_ALIGNMENT
|
|||
|
||||
endif
|
||||
|
||||
config GENERIC_ARCH_TOPOLOGY
|
||||
bool
|
||||
help
|
||||
Enable support for architectures common topology code: e.g., parsing
|
||||
CPU capacity information from DT, usage of such information for
|
||||
appropriate scaling, sysfs interface for changing capacity values at
|
||||
runtime.
|
||||
|
||||
endmenu
|
||||
|
|
|
@ -23,6 +23,7 @@ obj-$(CONFIG_SOC_BUS) += soc.o
|
|||
obj-$(CONFIG_PINCTRL) += pinctrl.o
|
||||
obj-$(CONFIG_DEV_COREDUMP) += devcoredump.o
|
||||
obj-$(CONFIG_GENERIC_MSI_IRQ_DOMAIN) += platform-msi.o
|
||||
obj-$(CONFIG_GENERIC_ARCH_TOPOLOGY) += arch_topology.o
|
||||
|
||||
obj-y += test/
|
||||
|
||||
|
|
|
@ -0,0 +1,243 @@
|
|||
/*
|
||||
* Arch specific cpu topology information
|
||||
*
|
||||
* Copyright (C) 2016, ARM Ltd.
|
||||
* Written by: Juri Lelli, ARM Ltd.
|
||||
*
|
||||
* This file is subject to the terms and conditions of the GNU General Public
|
||||
* License. See the file "COPYING" in the main directory of this archive
|
||||
* for more details.
|
||||
*
|
||||
* Released under the GPLv2 only.
|
||||
* SPDX-License-Identifier: GPL-2.0
|
||||
*/
|
||||
|
||||
#include <linux/acpi.h>
|
||||
#include <linux/arch_topology.h>
|
||||
#include <linux/cpu.h>
|
||||
#include <linux/cpufreq.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/sched/topology.h>
|
||||
|
||||
static DEFINE_MUTEX(cpu_scale_mutex);
|
||||
static DEFINE_PER_CPU(unsigned long, cpu_scale) = SCHED_CAPACITY_SCALE;
|
||||
|
||||
unsigned long topology_get_cpu_scale(struct sched_domain *sd, int cpu)
|
||||
{
|
||||
return per_cpu(cpu_scale, cpu);
|
||||
}
|
||||
|
||||
void topology_set_cpu_scale(unsigned int cpu, unsigned long capacity)
|
||||
{
|
||||
per_cpu(cpu_scale, cpu) = capacity;
|
||||
}
|
||||
|
||||
static ssize_t cpu_capacity_show(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
struct cpu *cpu = container_of(dev, struct cpu, dev);
|
||||
|
||||
return sprintf(buf, "%lu\n",
|
||||
topology_get_cpu_scale(NULL, cpu->dev.id));
|
||||
}
|
||||
|
||||
static ssize_t cpu_capacity_store(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
const char *buf,
|
||||
size_t count)
|
||||
{
|
||||
struct cpu *cpu = container_of(dev, struct cpu, dev);
|
||||
int this_cpu = cpu->dev.id;
|
||||
int i;
|
||||
unsigned long new_capacity;
|
||||
ssize_t ret;
|
||||
|
||||
if (!count)
|
||||
return 0;
|
||||
|
||||
ret = kstrtoul(buf, 0, &new_capacity);
|
||||
if (ret)
|
||||
return ret;
|
||||
if (new_capacity > SCHED_CAPACITY_SCALE)
|
||||
return -EINVAL;
|
||||
|
||||
mutex_lock(&cpu_scale_mutex);
|
||||
for_each_cpu(i, &cpu_topology[this_cpu].core_sibling)
|
||||
topology_set_cpu_scale(i, new_capacity);
|
||||
mutex_unlock(&cpu_scale_mutex);
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
static DEVICE_ATTR_RW(cpu_capacity);
|
||||
|
||||
static int register_cpu_capacity_sysctl(void)
|
||||
{
|
||||
int i;
|
||||
struct device *cpu;
|
||||
|
||||
for_each_possible_cpu(i) {
|
||||
cpu = get_cpu_device(i);
|
||||
if (!cpu) {
|
||||
pr_err("%s: too early to get CPU%d device!\n",
|
||||
__func__, i);
|
||||
continue;
|
||||
}
|
||||
device_create_file(cpu, &dev_attr_cpu_capacity);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
subsys_initcall(register_cpu_capacity_sysctl);
|
||||
|
||||
static u32 capacity_scale;
|
||||
static u32 *raw_capacity;
|
||||
static bool cap_parsing_failed;
|
||||
|
||||
void topology_normalize_cpu_scale(void)
|
||||
{
|
||||
u64 capacity;
|
||||
int cpu;
|
||||
|
||||
if (!raw_capacity || cap_parsing_failed)
|
||||
return;
|
||||
|
||||
pr_debug("cpu_capacity: capacity_scale=%u\n", capacity_scale);
|
||||
mutex_lock(&cpu_scale_mutex);
|
||||
for_each_possible_cpu(cpu) {
|
||||
pr_debug("cpu_capacity: cpu=%d raw_capacity=%u\n",
|
||||
cpu, raw_capacity[cpu]);
|
||||
capacity = (raw_capacity[cpu] << SCHED_CAPACITY_SHIFT)
|
||||
/ capacity_scale;
|
||||
topology_set_cpu_scale(cpu, capacity);
|
||||
pr_debug("cpu_capacity: CPU%d cpu_capacity=%lu\n",
|
||||
cpu, topology_get_cpu_scale(NULL, cpu));
|
||||
}
|
||||
mutex_unlock(&cpu_scale_mutex);
|
||||
}
|
||||
|
||||
int __init topology_parse_cpu_capacity(struct device_node *cpu_node, int cpu)
|
||||
{
|
||||
int ret = 1;
|
||||
u32 cpu_capacity;
|
||||
|
||||
if (cap_parsing_failed)
|
||||
return !ret;
|
||||
|
||||
ret = of_property_read_u32(cpu_node,
|
||||
"capacity-dmips-mhz",
|
||||
&cpu_capacity);
|
||||
if (!ret) {
|
||||
if (!raw_capacity) {
|
||||
raw_capacity = kcalloc(num_possible_cpus(),
|
||||
sizeof(*raw_capacity),
|
||||
GFP_KERNEL);
|
||||
if (!raw_capacity) {
|
||||
pr_err("cpu_capacity: failed to allocate memory for raw capacities\n");
|
||||
cap_parsing_failed = true;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
capacity_scale = max(cpu_capacity, capacity_scale);
|
||||
raw_capacity[cpu] = cpu_capacity;
|
||||
pr_debug("cpu_capacity: %s cpu_capacity=%u (raw)\n",
|
||||
cpu_node->full_name, raw_capacity[cpu]);
|
||||
} else {
|
||||
if (raw_capacity) {
|
||||
pr_err("cpu_capacity: missing %s raw capacity\n",
|
||||
cpu_node->full_name);
|
||||
pr_err("cpu_capacity: partial information: fallback to 1024 for all CPUs\n");
|
||||
}
|
||||
cap_parsing_failed = true;
|
||||
kfree(raw_capacity);
|
||||
}
|
||||
|
||||
return !ret;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_CPU_FREQ
|
||||
static cpumask_var_t cpus_to_visit;
|
||||
static bool cap_parsing_done;
|
||||
static void parsing_done_workfn(struct work_struct *work);
|
||||
static DECLARE_WORK(parsing_done_work, parsing_done_workfn);
|
||||
|
||||
static int
|
||||
init_cpu_capacity_callback(struct notifier_block *nb,
|
||||
unsigned long val,
|
||||
void *data)
|
||||
{
|
||||
struct cpufreq_policy *policy = data;
|
||||
int cpu;
|
||||
|
||||
if (cap_parsing_failed || cap_parsing_done)
|
||||
return 0;
|
||||
|
||||
switch (val) {
|
||||
case CPUFREQ_NOTIFY:
|
||||
pr_debug("cpu_capacity: init cpu capacity for CPUs [%*pbl] (to_visit=%*pbl)\n",
|
||||
cpumask_pr_args(policy->related_cpus),
|
||||
cpumask_pr_args(cpus_to_visit));
|
||||
cpumask_andnot(cpus_to_visit,
|
||||
cpus_to_visit,
|
||||
policy->related_cpus);
|
||||
for_each_cpu(cpu, policy->related_cpus) {
|
||||
raw_capacity[cpu] = topology_get_cpu_scale(NULL, cpu) *
|
||||
policy->cpuinfo.max_freq / 1000UL;
|
||||
capacity_scale = max(raw_capacity[cpu], capacity_scale);
|
||||
}
|
||||
if (cpumask_empty(cpus_to_visit)) {
|
||||
topology_normalize_cpu_scale();
|
||||
kfree(raw_capacity);
|
||||
pr_debug("cpu_capacity: parsing done\n");
|
||||
cap_parsing_done = true;
|
||||
schedule_work(&parsing_done_work);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct notifier_block init_cpu_capacity_notifier = {
|
||||
.notifier_call = init_cpu_capacity_callback,
|
||||
};
|
||||
|
||||
static int __init register_cpufreq_notifier(void)
|
||||
{
|
||||
/*
|
||||
* on ACPI-based systems we need to use the default cpu capacity
|
||||
* until we have the necessary code to parse the cpu capacity, so
|
||||
* skip registering cpufreq notifier.
|
||||
*/
|
||||
if (!acpi_disabled || !raw_capacity)
|
||||
return -EINVAL;
|
||||
|
||||
if (!alloc_cpumask_var(&cpus_to_visit, GFP_KERNEL)) {
|
||||
pr_err("cpu_capacity: failed to allocate memory for cpus_to_visit\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
cpumask_copy(cpus_to_visit, cpu_possible_mask);
|
||||
|
||||
return cpufreq_register_notifier(&init_cpu_capacity_notifier,
|
||||
CPUFREQ_POLICY_NOTIFIER);
|
||||
}
|
||||
core_initcall(register_cpufreq_notifier);
|
||||
|
||||
static void parsing_done_workfn(struct work_struct *work)
|
||||
{
|
||||
cpufreq_unregister_notifier(&init_cpu_capacity_notifier,
|
||||
CPUFREQ_POLICY_NOTIFIER);
|
||||
}
|
||||
|
||||
#else
|
||||
static int __init free_raw_capacity(void)
|
||||
{
|
||||
kfree(raw_capacity);
|
||||
|
||||
return 0;
|
||||
}
|
||||
core_initcall(free_raw_capacity);
|
||||
#endif
|
|
@ -466,35 +466,6 @@ int bus_for_each_drv(struct bus_type *bus, struct device_driver *start,
|
|||
}
|
||||
EXPORT_SYMBOL_GPL(bus_for_each_drv);
|
||||
|
||||
static int device_add_attrs(struct bus_type *bus, struct device *dev)
|
||||
{
|
||||
int error = 0;
|
||||
int i;
|
||||
|
||||
if (!bus->dev_attrs)
|
||||
return 0;
|
||||
|
||||
for (i = 0; bus->dev_attrs[i].attr.name; i++) {
|
||||
error = device_create_file(dev, &bus->dev_attrs[i]);
|
||||
if (error) {
|
||||
while (--i >= 0)
|
||||
device_remove_file(dev, &bus->dev_attrs[i]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return error;
|
||||
}
|
||||
|
||||
static void device_remove_attrs(struct bus_type *bus, struct device *dev)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (bus->dev_attrs) {
|
||||
for (i = 0; bus->dev_attrs[i].attr.name; i++)
|
||||
device_remove_file(dev, &bus->dev_attrs[i]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* bus_add_device - add device to bus
|
||||
* @dev: device being added
|
||||
|
@ -510,12 +481,9 @@ int bus_add_device(struct device *dev)
|
|||
|
||||
if (bus) {
|
||||
pr_debug("bus: '%s': add device %s\n", bus->name, dev_name(dev));
|
||||
error = device_add_attrs(bus, dev);
|
||||
if (error)
|
||||
goto out_put;
|
||||
error = device_add_groups(dev, bus->dev_groups);
|
||||
if (error)
|
||||
goto out_id;
|
||||
goto out_put;
|
||||
error = sysfs_create_link(&bus->p->devices_kset->kobj,
|
||||
&dev->kobj, dev_name(dev));
|
||||
if (error)
|
||||
|
@ -532,8 +500,6 @@ out_subsys:
|
|||
sysfs_remove_link(&bus->p->devices_kset->kobj, dev_name(dev));
|
||||
out_groups:
|
||||
device_remove_groups(dev, bus->dev_groups);
|
||||
out_id:
|
||||
device_remove_attrs(bus, dev);
|
||||
out_put:
|
||||
bus_put(dev->bus);
|
||||
return error;
|
||||
|
@ -590,7 +556,6 @@ void bus_remove_device(struct device *dev)
|
|||
sysfs_remove_link(&dev->kobj, "subsystem");
|
||||
sysfs_remove_link(&dev->bus->p->devices_kset->kobj,
|
||||
dev_name(dev));
|
||||
device_remove_attrs(dev->bus, dev);
|
||||
device_remove_groups(dev, dev->bus->dev_groups);
|
||||
if (klist_node_attached(&dev->p->knode_bus))
|
||||
klist_del(&dev->p->knode_bus);
|
||||
|
@ -648,10 +613,7 @@ static void remove_probe_files(struct bus_type *bus)
|
|||
static ssize_t uevent_store(struct device_driver *drv, const char *buf,
|
||||
size_t count)
|
||||
{
|
||||
enum kobject_action action;
|
||||
|
||||
if (kobject_action_type(buf, count, &action) == 0)
|
||||
kobject_uevent(&drv->p->kobj, action);
|
||||
kobject_synth_uevent(&drv->p->kobj, buf, count);
|
||||
return count;
|
||||
}
|
||||
static DRIVER_ATTR_WO(uevent);
|
||||
|
@ -868,10 +830,7 @@ static void klist_devices_put(struct klist_node *n)
|
|||
static ssize_t bus_uevent_store(struct bus_type *bus,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
enum kobject_action action;
|
||||
|
||||
if (kobject_action_type(buf, count, &action) == 0)
|
||||
kobject_uevent(&bus->p->subsys.kobj, action);
|
||||
kobject_synth_uevent(&bus->p->subsys.kobj, buf, count);
|
||||
return count;
|
||||
}
|
||||
static BUS_ATTR(uevent, S_IWUSR, NULL, bus_uevent_store);
|
||||
|
|
|
@ -119,36 +119,6 @@ static void class_put(struct class *cls)
|
|||
kset_put(&cls->p->subsys);
|
||||
}
|
||||
|
||||
static int add_class_attrs(struct class *cls)
|
||||
{
|
||||
int i;
|
||||
int error = 0;
|
||||
|
||||
if (cls->class_attrs) {
|
||||
for (i = 0; cls->class_attrs[i].attr.name; i++) {
|
||||
error = class_create_file(cls, &cls->class_attrs[i]);
|
||||
if (error)
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
done:
|
||||
return error;
|
||||
error:
|
||||
while (--i >= 0)
|
||||
class_remove_file(cls, &cls->class_attrs[i]);
|
||||
goto done;
|
||||
}
|
||||
|
||||
static void remove_class_attrs(struct class *cls)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (cls->class_attrs) {
|
||||
for (i = 0; cls->class_attrs[i].attr.name; i++)
|
||||
class_remove_file(cls, &cls->class_attrs[i]);
|
||||
}
|
||||
}
|
||||
|
||||
static void klist_class_dev_get(struct klist_node *n)
|
||||
{
|
||||
struct device *dev = container_of(n, struct device, knode_class);
|
||||
|
@ -217,8 +187,6 @@ int __class_register(struct class *cls, struct lock_class_key *key)
|
|||
}
|
||||
error = class_add_groups(class_get(cls), cls->class_groups);
|
||||
class_put(cls);
|
||||
error = add_class_attrs(class_get(cls));
|
||||
class_put(cls);
|
||||
return error;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(__class_register);
|
||||
|
@ -226,7 +194,6 @@ EXPORT_SYMBOL_GPL(__class_register);
|
|||
void class_unregister(struct class *cls)
|
||||
{
|
||||
pr_debug("device class '%s': unregistering\n", cls->name);
|
||||
remove_class_attrs(cls);
|
||||
class_remove_groups(cls, cls->class_groups);
|
||||
kset_unregister(&cls->p->subsys);
|
||||
}
|
||||
|
|
|
@ -981,12 +981,9 @@ out:
|
|||
static ssize_t uevent_store(struct device *dev, struct device_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
enum kobject_action action;
|
||||
if (kobject_synth_uevent(&dev->kobj, buf, count))
|
||||
dev_err(dev, "uevent: failed to send synthetic uevent\n");
|
||||
|
||||
if (kobject_action_type(buf, count, &action) == 0)
|
||||
kobject_uevent(&dev->kobj, action);
|
||||
else
|
||||
dev_err(dev, "uevent: unknown action-string\n");
|
||||
return count;
|
||||
}
|
||||
static DEVICE_ATTR_RW(uevent);
|
||||
|
|
|
@ -275,6 +275,24 @@ int dma_common_mmap(struct device *dev, struct vm_area_struct *vma,
|
|||
EXPORT_SYMBOL(dma_common_mmap);
|
||||
|
||||
#ifdef CONFIG_MMU
|
||||
static struct vm_struct *__dma_common_pages_remap(struct page **pages,
|
||||
size_t size, unsigned long vm_flags, pgprot_t prot,
|
||||
const void *caller)
|
||||
{
|
||||
struct vm_struct *area;
|
||||
|
||||
area = get_vm_area_caller(size, vm_flags, caller);
|
||||
if (!area)
|
||||
return NULL;
|
||||
|
||||
if (map_vm_area(area, prot, pages)) {
|
||||
vunmap(area->addr);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return area;
|
||||
}
|
||||
|
||||
/*
|
||||
* remaps an array of PAGE_SIZE pages into another vm_area
|
||||
* Cannot be used in non-sleeping contexts
|
||||
|
@ -285,17 +303,12 @@ void *dma_common_pages_remap(struct page **pages, size_t size,
|
|||
{
|
||||
struct vm_struct *area;
|
||||
|
||||
area = get_vm_area_caller(size, vm_flags, caller);
|
||||
area = __dma_common_pages_remap(pages, size, vm_flags, prot, caller);
|
||||
if (!area)
|
||||
return NULL;
|
||||
|
||||
area->pages = pages;
|
||||
|
||||
if (map_vm_area(area, prot, pages)) {
|
||||
vunmap(area->addr);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return area->addr;
|
||||
}
|
||||
|
||||
|
@ -310,7 +323,7 @@ void *dma_common_contiguous_remap(struct page *page, size_t size,
|
|||
{
|
||||
int i;
|
||||
struct page **pages;
|
||||
void *ptr;
|
||||
struct vm_struct *area;
|
||||
|
||||
pages = kmalloc(sizeof(struct page *) << get_order(size), GFP_KERNEL);
|
||||
if (!pages)
|
||||
|
@ -319,11 +332,13 @@ void *dma_common_contiguous_remap(struct page *page, size_t size,
|
|||
for (i = 0; i < (size >> PAGE_SHIFT); i++)
|
||||
pages[i] = nth_page(page, i);
|
||||
|
||||
ptr = dma_common_pages_remap(pages, size, vm_flags, prot, caller);
|
||||
area = __dma_common_pages_remap(pages, size, vm_flags, prot, caller);
|
||||
|
||||
kfree(pages);
|
||||
|
||||
return ptr;
|
||||
if (!area)
|
||||
return NULL;
|
||||
return area->addr;
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
@ -260,6 +260,38 @@ static int fw_cache_piggyback_on_request(const char *name);
|
|||
* guarding for corner cases a global lock should be OK */
|
||||
static DEFINE_MUTEX(fw_lock);
|
||||
|
||||
static bool __enable_firmware = false;
|
||||
|
||||
static void enable_firmware(void)
|
||||
{
|
||||
mutex_lock(&fw_lock);
|
||||
__enable_firmware = true;
|
||||
mutex_unlock(&fw_lock);
|
||||
}
|
||||
|
||||
static void disable_firmware(void)
|
||||
{
|
||||
mutex_lock(&fw_lock);
|
||||
__enable_firmware = false;
|
||||
mutex_unlock(&fw_lock);
|
||||
}
|
||||
|
||||
/*
|
||||
* When disabled only the built-in firmware and the firmware cache will be
|
||||
* used to look for firmware.
|
||||
*/
|
||||
static bool firmware_enabled(void)
|
||||
{
|
||||
bool enabled = false;
|
||||
|
||||
mutex_lock(&fw_lock);
|
||||
if (__enable_firmware)
|
||||
enabled = true;
|
||||
mutex_unlock(&fw_lock);
|
||||
|
||||
return enabled;
|
||||
}
|
||||
|
||||
static struct firmware_cache fw_cache;
|
||||
|
||||
static struct firmware_buf *__allocate_fw_buf(const char *fw_name,
|
||||
|
@ -523,6 +555,44 @@ static int fw_add_devm_name(struct device *dev, const char *name)
|
|||
}
|
||||
#endif
|
||||
|
||||
static int assign_firmware_buf(struct firmware *fw, struct device *device,
|
||||
unsigned int opt_flags)
|
||||
{
|
||||
struct firmware_buf *buf = fw->priv;
|
||||
|
||||
mutex_lock(&fw_lock);
|
||||
if (!buf->size || fw_state_is_aborted(&buf->fw_st)) {
|
||||
mutex_unlock(&fw_lock);
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
/*
|
||||
* add firmware name into devres list so that we can auto cache
|
||||
* and uncache firmware for device.
|
||||
*
|
||||
* device may has been deleted already, but the problem
|
||||
* should be fixed in devres or driver core.
|
||||
*/
|
||||
/* don't cache firmware handled without uevent */
|
||||
if (device && (opt_flags & FW_OPT_UEVENT) &&
|
||||
!(opt_flags & FW_OPT_NOCACHE))
|
||||
fw_add_devm_name(device, buf->fw_id);
|
||||
|
||||
/*
|
||||
* After caching firmware image is started, let it piggyback
|
||||
* on request firmware.
|
||||
*/
|
||||
if (!(opt_flags & FW_OPT_NOCACHE) &&
|
||||
buf->fwc->state == FW_LOADER_START_CACHE) {
|
||||
if (fw_cache_piggyback_on_request(buf->fw_id))
|
||||
kref_get(&buf->ref);
|
||||
}
|
||||
|
||||
/* pass the pages buffer to driver at the last minute */
|
||||
fw_set_page_data(buf, fw);
|
||||
mutex_unlock(&fw_lock);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* user-mode helper code
|
||||
|
@ -562,22 +632,18 @@ static void fw_load_abort(struct firmware_priv *fw_priv)
|
|||
|
||||
static LIST_HEAD(pending_fw_head);
|
||||
|
||||
/* reboot notifier for avoid deadlock with usermode_lock */
|
||||
static int fw_shutdown_notify(struct notifier_block *unused1,
|
||||
unsigned long unused2, void *unused3)
|
||||
static void kill_pending_fw_fallback_reqs(bool only_kill_custom)
|
||||
{
|
||||
mutex_lock(&fw_lock);
|
||||
while (!list_empty(&pending_fw_head))
|
||||
__fw_load_abort(list_first_entry(&pending_fw_head,
|
||||
struct firmware_buf,
|
||||
pending_list));
|
||||
mutex_unlock(&fw_lock);
|
||||
return NOTIFY_DONE;
|
||||
}
|
||||
struct firmware_buf *buf;
|
||||
struct firmware_buf *next;
|
||||
|
||||
static struct notifier_block fw_shutdown_nb = {
|
||||
.notifier_call = fw_shutdown_notify,
|
||||
};
|
||||
mutex_lock(&fw_lock);
|
||||
list_for_each_entry_safe(buf, next, &pending_fw_head, pending_list) {
|
||||
if (!buf->need_uevent || !only_kill_custom)
|
||||
__fw_load_abort(buf);
|
||||
}
|
||||
mutex_unlock(&fw_lock);
|
||||
}
|
||||
|
||||
static ssize_t timeout_show(struct class *class, struct class_attribute *attr,
|
||||
char *buf)
|
||||
|
@ -1036,46 +1102,56 @@ err_put_dev:
|
|||
|
||||
static int fw_load_from_user_helper(struct firmware *firmware,
|
||||
const char *name, struct device *device,
|
||||
unsigned int opt_flags, long timeout)
|
||||
unsigned int opt_flags)
|
||||
{
|
||||
struct firmware_priv *fw_priv;
|
||||
long timeout;
|
||||
int ret;
|
||||
|
||||
timeout = firmware_loading_timeout();
|
||||
if (opt_flags & FW_OPT_NOWAIT) {
|
||||
timeout = usermodehelper_read_lock_wait(timeout);
|
||||
if (!timeout) {
|
||||
dev_dbg(device, "firmware: %s loading timed out\n",
|
||||
name);
|
||||
return -EBUSY;
|
||||
}
|
||||
} else {
|
||||
ret = usermodehelper_read_trylock();
|
||||
if (WARN_ON(ret)) {
|
||||
dev_err(device, "firmware: %s will not be loaded\n",
|
||||
name);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
fw_priv = fw_create_instance(firmware, name, device, opt_flags);
|
||||
if (IS_ERR(fw_priv))
|
||||
return PTR_ERR(fw_priv);
|
||||
if (IS_ERR(fw_priv)) {
|
||||
ret = PTR_ERR(fw_priv);
|
||||
goto out_unlock;
|
||||
}
|
||||
|
||||
fw_priv->buf = firmware->priv;
|
||||
return _request_firmware_load(fw_priv, opt_flags, timeout);
|
||||
}
|
||||
ret = _request_firmware_load(fw_priv, opt_flags, timeout);
|
||||
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
/* kill pending requests without uevent to avoid blocking suspend */
|
||||
static void kill_requests_without_uevent(void)
|
||||
{
|
||||
struct firmware_buf *buf;
|
||||
struct firmware_buf *next;
|
||||
if (!ret)
|
||||
ret = assign_firmware_buf(firmware, device, opt_flags);
|
||||
|
||||
mutex_lock(&fw_lock);
|
||||
list_for_each_entry_safe(buf, next, &pending_fw_head, pending_list) {
|
||||
if (!buf->need_uevent)
|
||||
__fw_load_abort(buf);
|
||||
}
|
||||
mutex_unlock(&fw_lock);
|
||||
out_unlock:
|
||||
usermodehelper_read_unlock();
|
||||
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
|
||||
#else /* CONFIG_FW_LOADER_USER_HELPER */
|
||||
static inline int
|
||||
fw_load_from_user_helper(struct firmware *firmware, const char *name,
|
||||
struct device *device, unsigned int opt_flags,
|
||||
long timeout)
|
||||
struct device *device, unsigned int opt_flags)
|
||||
{
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
static inline void kill_requests_without_uevent(void) { }
|
||||
#endif
|
||||
static inline void kill_pending_fw_fallback_reqs(bool only_kill_custom) { }
|
||||
|
||||
#endif /* CONFIG_FW_LOADER_USER_HELPER */
|
||||
|
||||
|
@ -1124,45 +1200,6 @@ _request_firmware_prepare(struct firmware **firmware_p, const char *name,
|
|||
return 1; /* need to load */
|
||||
}
|
||||
|
||||
static int assign_firmware_buf(struct firmware *fw, struct device *device,
|
||||
unsigned int opt_flags)
|
||||
{
|
||||
struct firmware_buf *buf = fw->priv;
|
||||
|
||||
mutex_lock(&fw_lock);
|
||||
if (!buf->size || fw_state_is_aborted(&buf->fw_st)) {
|
||||
mutex_unlock(&fw_lock);
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
/*
|
||||
* add firmware name into devres list so that we can auto cache
|
||||
* and uncache firmware for device.
|
||||
*
|
||||
* device may has been deleted already, but the problem
|
||||
* should be fixed in devres or driver core.
|
||||
*/
|
||||
/* don't cache firmware handled without uevent */
|
||||
if (device && (opt_flags & FW_OPT_UEVENT) &&
|
||||
!(opt_flags & FW_OPT_NOCACHE))
|
||||
fw_add_devm_name(device, buf->fw_id);
|
||||
|
||||
/*
|
||||
* After caching firmware image is started, let it piggyback
|
||||
* on request firmware.
|
||||
*/
|
||||
if (!(opt_flags & FW_OPT_NOCACHE) &&
|
||||
buf->fwc->state == FW_LOADER_START_CACHE) {
|
||||
if (fw_cache_piggyback_on_request(buf->fw_id))
|
||||
kref_get(&buf->ref);
|
||||
}
|
||||
|
||||
/* pass the pages buffer to driver at the last minute */
|
||||
fw_set_page_data(buf, fw);
|
||||
mutex_unlock(&fw_lock);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* called from request_firmware() and request_firmware_work_func() */
|
||||
static int
|
||||
_request_firmware(const struct firmware **firmware_p, const char *name,
|
||||
|
@ -1170,7 +1207,6 @@ _request_firmware(const struct firmware **firmware_p, const char *name,
|
|||
unsigned int opt_flags)
|
||||
{
|
||||
struct firmware *fw = NULL;
|
||||
long timeout;
|
||||
int ret;
|
||||
|
||||
if (!firmware_p)
|
||||
|
@ -1185,23 +1221,10 @@ _request_firmware(const struct firmware **firmware_p, const char *name,
|
|||
if (ret <= 0) /* error or already assigned */
|
||||
goto out;
|
||||
|
||||
ret = 0;
|
||||
timeout = firmware_loading_timeout();
|
||||
if (opt_flags & FW_OPT_NOWAIT) {
|
||||
timeout = usermodehelper_read_lock_wait(timeout);
|
||||
if (!timeout) {
|
||||
dev_dbg(device, "firmware: %s loading timed out\n",
|
||||
name);
|
||||
ret = -EBUSY;
|
||||
goto out;
|
||||
}
|
||||
} else {
|
||||
ret = usermodehelper_read_trylock();
|
||||
if (WARN_ON(ret)) {
|
||||
dev_err(device, "firmware: %s will not be loaded\n",
|
||||
name);
|
||||
goto out;
|
||||
}
|
||||
if (!firmware_enabled()) {
|
||||
WARN(1, "firmware request while host is not available\n");
|
||||
ret = -EHOSTDOWN;
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = fw_get_filesystem_firmware(device, fw->priv);
|
||||
|
@ -1213,15 +1236,11 @@ _request_firmware(const struct firmware **firmware_p, const char *name,
|
|||
if (opt_flags & FW_OPT_USERHELPER) {
|
||||
dev_warn(device, "Falling back to user helper\n");
|
||||
ret = fw_load_from_user_helper(fw, name, device,
|
||||
opt_flags, timeout);
|
||||
opt_flags);
|
||||
}
|
||||
}
|
||||
|
||||
if (!ret)
|
||||
} else
|
||||
ret = assign_firmware_buf(fw, device, opt_flags);
|
||||
|
||||
usermodehelper_read_unlock();
|
||||
|
||||
out:
|
||||
if (ret < 0) {
|
||||
release_firmware(fw);
|
||||
|
@ -1717,6 +1736,62 @@ static void device_uncache_fw_images_delay(unsigned long delay)
|
|||
msecs_to_jiffies(delay));
|
||||
}
|
||||
|
||||
/**
|
||||
* fw_pm_notify - notifier for suspend/resume
|
||||
* @notify_block: unused
|
||||
* @mode: mode we are switching to
|
||||
* @unused: unused
|
||||
*
|
||||
* Used to modify the firmware_class state as we move in between states.
|
||||
* The firmware_class implements a firmware cache to enable device driver
|
||||
* to fetch firmware upon resume before the root filesystem is ready. We
|
||||
* disable API calls which do not use the built-in firmware or the firmware
|
||||
* cache when we know these calls will not work.
|
||||
*
|
||||
* The inner logic behind all this is a bit complex so it is worth summarizing
|
||||
* the kernel's own suspend/resume process with context and focus on how this
|
||||
* can impact the firmware API.
|
||||
*
|
||||
* First a review on how we go to suspend::
|
||||
*
|
||||
* pm_suspend() --> enter_state() -->
|
||||
* sys_sync()
|
||||
* suspend_prepare() -->
|
||||
* __pm_notifier_call_chain(PM_SUSPEND_PREPARE, ...);
|
||||
* suspend_freeze_processes() -->
|
||||
* freeze_processes() -->
|
||||
* __usermodehelper_set_disable_depth(UMH_DISABLED);
|
||||
* freeze all tasks ...
|
||||
* freeze_kernel_threads()
|
||||
* suspend_devices_and_enter() -->
|
||||
* dpm_suspend_start() -->
|
||||
* dpm_prepare()
|
||||
* dpm_suspend()
|
||||
* suspend_enter() -->
|
||||
* platform_suspend_prepare()
|
||||
* dpm_suspend_late()
|
||||
* freeze_enter()
|
||||
* syscore_suspend()
|
||||
*
|
||||
* When we resume we bail out of a loop from suspend_devices_and_enter() and
|
||||
* unwind back out to the caller enter_state() where we were before as follows::
|
||||
*
|
||||
* enter_state() -->
|
||||
* suspend_devices_and_enter() --> (bail from loop)
|
||||
* dpm_resume_end() -->
|
||||
* dpm_resume()
|
||||
* dpm_complete()
|
||||
* suspend_finish() -->
|
||||
* suspend_thaw_processes() -->
|
||||
* thaw_processes() -->
|
||||
* __usermodehelper_set_disable_depth(UMH_FREEZING);
|
||||
* thaw_workqueues();
|
||||
* thaw all processes ...
|
||||
* usermodehelper_enable();
|
||||
* pm_notifier_call_chain(PM_POST_SUSPEND);
|
||||
*
|
||||
* fw_pm_notify() works through pm_notifier_call_chain().
|
||||
*/
|
||||
static int fw_pm_notify(struct notifier_block *notify_block,
|
||||
unsigned long mode, void *unused)
|
||||
{
|
||||
|
@ -1724,8 +1799,13 @@ static int fw_pm_notify(struct notifier_block *notify_block,
|
|||
case PM_HIBERNATION_PREPARE:
|
||||
case PM_SUSPEND_PREPARE:
|
||||
case PM_RESTORE_PREPARE:
|
||||
kill_requests_without_uevent();
|
||||
/*
|
||||
* kill pending fallback requests with a custom fallback
|
||||
* to avoid stalling suspend.
|
||||
*/
|
||||
kill_pending_fw_fallback_reqs(true);
|
||||
device_cache_fw_images();
|
||||
disable_firmware();
|
||||
break;
|
||||
|
||||
case PM_POST_SUSPEND:
|
||||
|
@ -1738,6 +1818,7 @@ static int fw_pm_notify(struct notifier_block *notify_block,
|
|||
mutex_lock(&fw_lock);
|
||||
fw_cache.state = FW_LOADER_NO_CACHE;
|
||||
mutex_unlock(&fw_lock);
|
||||
enable_firmware();
|
||||
|
||||
device_uncache_fw_images_delay(10 * MSEC_PER_SEC);
|
||||
break;
|
||||
|
@ -1783,11 +1864,29 @@ static void __init fw_cache_init(void)
|
|||
#endif
|
||||
}
|
||||
|
||||
static int fw_shutdown_notify(struct notifier_block *unused1,
|
||||
unsigned long unused2, void *unused3)
|
||||
{
|
||||
disable_firmware();
|
||||
/*
|
||||
* Kill all pending fallback requests to avoid both stalling shutdown,
|
||||
* and avoid a deadlock with the usermode_lock.
|
||||
*/
|
||||
kill_pending_fw_fallback_reqs(false);
|
||||
|
||||
return NOTIFY_DONE;
|
||||
}
|
||||
|
||||
static struct notifier_block fw_shutdown_nb = {
|
||||
.notifier_call = fw_shutdown_notify,
|
||||
};
|
||||
|
||||
static int __init firmware_class_init(void)
|
||||
{
|
||||
enable_firmware();
|
||||
fw_cache_init();
|
||||
#ifdef CONFIG_FW_LOADER_USER_HELPER
|
||||
register_reboot_notifier(&fw_shutdown_nb);
|
||||
#ifdef CONFIG_FW_LOADER_USER_HELPER
|
||||
return class_register(&firmware_class);
|
||||
#else
|
||||
return 0;
|
||||
|
@ -1796,12 +1895,13 @@ static int __init firmware_class_init(void)
|
|||
|
||||
static void __exit firmware_class_exit(void)
|
||||
{
|
||||
disable_firmware();
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
unregister_syscore_ops(&fw_syscore_ops);
|
||||
unregister_pm_notifier(&fw_cache.pm_notify);
|
||||
#endif
|
||||
#ifdef CONFIG_FW_LOADER_USER_HELPER
|
||||
unregister_reboot_notifier(&fw_shutdown_nb);
|
||||
#ifdef CONFIG_FW_LOADER_USER_HELPER
|
||||
class_unregister(&firmware_class);
|
||||
#endif
|
||||
}
|
||||
|
|
|
@ -866,7 +866,7 @@ static ssize_t driver_override_store(struct device *dev,
|
|||
const char *buf, size_t count)
|
||||
{
|
||||
struct platform_device *pdev = to_platform_device(dev);
|
||||
char *driver_override, *old = pdev->driver_override, *cp;
|
||||
char *driver_override, *old, *cp;
|
||||
|
||||
if (count > PATH_MAX)
|
||||
return -EINVAL;
|
||||
|
@ -879,12 +879,15 @@ static ssize_t driver_override_store(struct device *dev,
|
|||
if (cp)
|
||||
*cp = '\0';
|
||||
|
||||
device_lock(dev);
|
||||
old = pdev->driver_override;
|
||||
if (strlen(driver_override)) {
|
||||
pdev->driver_override = driver_override;
|
||||
} else {
|
||||
kfree(driver_override);
|
||||
pdev->driver_override = NULL;
|
||||
}
|
||||
device_unlock(dev);
|
||||
|
||||
kfree(old);
|
||||
|
||||
|
@ -895,8 +898,12 @@ static ssize_t driver_override_show(struct device *dev,
|
|||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct platform_device *pdev = to_platform_device(dev);
|
||||
ssize_t len;
|
||||
|
||||
return sprintf(buf, "%s\n", pdev->driver_override);
|
||||
device_lock(dev);
|
||||
len = sprintf(buf, "%s\n", pdev->driver_override);
|
||||
device_unlock(dev);
|
||||
return len;
|
||||
}
|
||||
static DEVICE_ATTR_RW(driver_override);
|
||||
|
||||
|
|
|
@ -349,9 +349,9 @@ static void class_pktcdvd_release(struct class *cls)
|
|||
{
|
||||
kfree(cls);
|
||||
}
|
||||
static ssize_t class_pktcdvd_show_map(struct class *c,
|
||||
struct class_attribute *attr,
|
||||
char *data)
|
||||
|
||||
static ssize_t device_map_show(struct class *c, struct class_attribute *attr,
|
||||
char *data)
|
||||
{
|
||||
int n = 0;
|
||||
int idx;
|
||||
|
@ -369,11 +369,10 @@ static ssize_t class_pktcdvd_show_map(struct class *c,
|
|||
mutex_unlock(&ctl_mutex);
|
||||
return n;
|
||||
}
|
||||
static CLASS_ATTR_RO(device_map);
|
||||
|
||||
static ssize_t class_pktcdvd_store_add(struct class *c,
|
||||
struct class_attribute *attr,
|
||||
const char *buf,
|
||||
size_t count)
|
||||
static ssize_t add_store(struct class *c, struct class_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
unsigned int major, minor;
|
||||
|
||||
|
@ -391,11 +390,10 @@ static ssize_t class_pktcdvd_store_add(struct class *c,
|
|||
|
||||
return -EINVAL;
|
||||
}
|
||||
static CLASS_ATTR_WO(add);
|
||||
|
||||
static ssize_t class_pktcdvd_store_remove(struct class *c,
|
||||
struct class_attribute *attr,
|
||||
const char *buf,
|
||||
size_t count)
|
||||
static ssize_t remove_store(struct class *c, struct class_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
unsigned int major, minor;
|
||||
if (sscanf(buf, "%u:%u", &major, &minor) == 2) {
|
||||
|
@ -404,14 +402,15 @@ static ssize_t class_pktcdvd_store_remove(struct class *c,
|
|||
}
|
||||
return -EINVAL;
|
||||
}
|
||||
static CLASS_ATTR_WO(remove);
|
||||
|
||||
static struct class_attribute class_pktcdvd_attrs[] = {
|
||||
__ATTR(add, 0200, NULL, class_pktcdvd_store_add),
|
||||
__ATTR(remove, 0200, NULL, class_pktcdvd_store_remove),
|
||||
__ATTR(device_map, 0444, class_pktcdvd_show_map, NULL),
|
||||
__ATTR_NULL
|
||||
static struct attribute *class_pktcdvd_attrs[] = {
|
||||
&class_attr_add.attr,
|
||||
&class_attr_remove.attr,
|
||||
&class_attr_device_map.attr,
|
||||
NULL,
|
||||
};
|
||||
|
||||
ATTRIBUTE_GROUPS(class_pktcdvd);
|
||||
|
||||
static int pkt_sysfs_init(void)
|
||||
{
|
||||
|
@ -427,7 +426,7 @@ static int pkt_sysfs_init(void)
|
|||
class_pktcdvd->name = DRIVER_NAME;
|
||||
class_pktcdvd->owner = THIS_MODULE;
|
||||
class_pktcdvd->class_release = class_pktcdvd_release;
|
||||
class_pktcdvd->class_attrs = class_pktcdvd_attrs;
|
||||
class_pktcdvd->class_groups = class_pktcdvd_groups;
|
||||
ret = class_register(class_pktcdvd);
|
||||
if (ret) {
|
||||
kfree(class_pktcdvd);
|
||||
|
|
|
@ -1272,6 +1272,13 @@ static int zram_remove(struct zram *zram)
|
|||
}
|
||||
|
||||
/* zram-control sysfs attributes */
|
||||
|
||||
/*
|
||||
* NOTE: hot_add attribute is not the usual read-only sysfs attribute. In a
|
||||
* sense that reading from this file does alter the state of your system -- it
|
||||
* creates a new un-initialized zram device and returns back this device's
|
||||
* device_id (or an error code if it fails to create a new device).
|
||||
*/
|
||||
static ssize_t hot_add_show(struct class *class,
|
||||
struct class_attribute *attr,
|
||||
char *buf)
|
||||
|
@ -1286,6 +1293,7 @@ static ssize_t hot_add_show(struct class *class,
|
|||
return ret;
|
||||
return scnprintf(buf, PAGE_SIZE, "%d\n", ret);
|
||||
}
|
||||
static CLASS_ATTR_RO(hot_add);
|
||||
|
||||
static ssize_t hot_remove_store(struct class *class,
|
||||
struct class_attribute *attr,
|
||||
|
@ -1316,23 +1324,19 @@ static ssize_t hot_remove_store(struct class *class,
|
|||
mutex_unlock(&zram_index_mutex);
|
||||
return ret ? ret : count;
|
||||
}
|
||||
static CLASS_ATTR_WO(hot_remove);
|
||||
|
||||
/*
|
||||
* NOTE: hot_add attribute is not the usual read-only sysfs attribute. In a
|
||||
* sense that reading from this file does alter the state of your system -- it
|
||||
* creates a new un-initialized zram device and returns back this device's
|
||||
* device_id (or an error code if it fails to create a new device).
|
||||
*/
|
||||
static struct class_attribute zram_control_class_attrs[] = {
|
||||
__ATTR(hot_add, 0400, hot_add_show, NULL),
|
||||
__ATTR_WO(hot_remove),
|
||||
__ATTR_NULL,
|
||||
static struct attribute *zram_control_class_attrs[] = {
|
||||
&class_attr_hot_add.attr,
|
||||
&class_attr_hot_remove.attr,
|
||||
NULL,
|
||||
};
|
||||
ATTRIBUTE_GROUPS(zram_control_class);
|
||||
|
||||
static struct class zram_control_class = {
|
||||
.name = "zram-control",
|
||||
.owner = THIS_MODULE,
|
||||
.class_attrs = zram_control_class_attrs,
|
||||
.class_groups = zram_control_class_groups,
|
||||
};
|
||||
|
||||
static int zram_remove_cb(int id, void *ptr, void *data)
|
||||
|
|
|
@ -479,6 +479,7 @@ done:
|
|||
pr_debug("%s: status %d\n", __func__, status);
|
||||
return status ? : len;
|
||||
}
|
||||
static CLASS_ATTR_WO(export);
|
||||
|
||||
static ssize_t unexport_store(struct class *class,
|
||||
struct class_attribute *attr,
|
||||
|
@ -514,18 +515,20 @@ done:
|
|||
pr_debug("%s: status %d\n", __func__, status);
|
||||
return status ? : len;
|
||||
}
|
||||
static CLASS_ATTR_WO(unexport);
|
||||
|
||||
static struct class_attribute gpio_class_attrs[] = {
|
||||
__ATTR(export, 0200, NULL, export_store),
|
||||
__ATTR(unexport, 0200, NULL, unexport_store),
|
||||
__ATTR_NULL,
|
||||
static struct attribute *gpio_class_attrs[] = {
|
||||
&class_attr_export.attr,
|
||||
&class_attr_unexport.attr,
|
||||
NULL,
|
||||
};
|
||||
ATTRIBUTE_GROUPS(gpio_class);
|
||||
|
||||
static struct class gpio_class = {
|
||||
.name = "gpio",
|
||||
.owner = THIS_MODULE,
|
||||
|
||||
.class_attrs = gpio_class_attrs,
|
||||
.class_groups = gpio_class_groups,
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -2307,7 +2307,7 @@ struct hid_dynid {
|
|||
* Adds a new dynamic hid device ID to this driver,
|
||||
* and causes the driver to probe for all devices again.
|
||||
*/
|
||||
static ssize_t store_new_id(struct device_driver *drv, const char *buf,
|
||||
static ssize_t new_id_store(struct device_driver *drv, const char *buf,
|
||||
size_t count)
|
||||
{
|
||||
struct hid_driver *hdrv = to_hid_driver(drv);
|
||||
|
@ -2339,7 +2339,13 @@ static ssize_t store_new_id(struct device_driver *drv, const char *buf,
|
|||
|
||||
return ret ? : count;
|
||||
}
|
||||
static DRIVER_ATTR(new_id, S_IWUSR, NULL, store_new_id);
|
||||
static DRIVER_ATTR_WO(new_id);
|
||||
|
||||
static struct attribute *hid_drv_attrs[] = {
|
||||
&driver_attr_new_id.attr,
|
||||
NULL,
|
||||
};
|
||||
ATTRIBUTE_GROUPS(hid_drv);
|
||||
|
||||
static void hid_free_dynids(struct hid_driver *hdrv)
|
||||
{
|
||||
|
@ -2503,6 +2509,7 @@ static int hid_uevent(struct device *dev, struct kobj_uevent_env *env)
|
|||
static struct bus_type hid_bus_type = {
|
||||
.name = "hid",
|
||||
.dev_groups = hid_dev_groups,
|
||||
.drv_groups = hid_drv_groups,
|
||||
.match = hid_bus_match,
|
||||
.probe = hid_device_probe,
|
||||
.remove = hid_device_remove,
|
||||
|
@ -2942,8 +2949,6 @@ EXPORT_SYMBOL_GPL(hid_destroy_device);
|
|||
int __hid_register_driver(struct hid_driver *hdrv, struct module *owner,
|
||||
const char *mod_name)
|
||||
{
|
||||
int ret;
|
||||
|
||||
hdrv->driver.name = hdrv->name;
|
||||
hdrv->driver.bus = &hid_bus_type;
|
||||
hdrv->driver.owner = owner;
|
||||
|
@ -2952,21 +2957,12 @@ int __hid_register_driver(struct hid_driver *hdrv, struct module *owner,
|
|||
INIT_LIST_HEAD(&hdrv->dyn_list);
|
||||
spin_lock_init(&hdrv->dyn_lock);
|
||||
|
||||
ret = driver_register(&hdrv->driver);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = driver_create_file(&hdrv->driver, &driver_attr_new_id);
|
||||
if (ret)
|
||||
driver_unregister(&hdrv->driver);
|
||||
|
||||
return ret;
|
||||
return driver_register(&hdrv->driver);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(__hid_register_driver);
|
||||
|
||||
void hid_unregister_driver(struct hid_driver *hdrv)
|
||||
{
|
||||
driver_remove_file(&hdrv->driver, &driver_attr_new_id);
|
||||
driver_unregister(&hdrv->driver);
|
||||
hid_free_dynids(hdrv);
|
||||
}
|
||||
|
|
|
@ -321,11 +321,13 @@ static ssize_t modalias_show(struct device *dev, struct device_attribute *a,
|
|||
len = snprintf(buf, PAGE_SIZE, "ishtp:%s\n", dev_name(dev));
|
||||
return (len >= PAGE_SIZE) ? (PAGE_SIZE - 1) : len;
|
||||
}
|
||||
static DEVICE_ATTR_RO(modalias);
|
||||
|
||||
static struct device_attribute ishtp_cl_dev_attrs[] = {
|
||||
__ATTR_RO(modalias),
|
||||
__ATTR_NULL,
|
||||
static struct attribute *ishtp_cl_dev_attrs[] = {
|
||||
&dev_attr_modalias.attr,
|
||||
NULL,
|
||||
};
|
||||
ATTRIBUTE_GROUPS(ishtp_cl_dev);
|
||||
|
||||
static int ishtp_cl_uevent(struct device *dev, struct kobj_uevent_env *env)
|
||||
{
|
||||
|
@ -346,7 +348,7 @@ static const struct dev_pm_ops ishtp_cl_bus_dev_pm_ops = {
|
|||
|
||||
static struct bus_type ishtp_cl_bus_type = {
|
||||
.name = "ishtp",
|
||||
.dev_attrs = ishtp_cl_dev_attrs,
|
||||
.dev_groups = ishtp_cl_dev_groups,
|
||||
.probe = ishtp_cl_device_probe,
|
||||
.remove = ishtp_cl_device_remove,
|
||||
.pm = &ishtp_cl_bus_dev_pm_ops,
|
||||
|
|
|
@ -139,7 +139,6 @@ static int intel_th_remove(struct device *dev)
|
|||
|
||||
static struct bus_type intel_th_bus = {
|
||||
.name = "intel_th",
|
||||
.dev_attrs = NULL,
|
||||
.match = intel_th_match,
|
||||
.probe = intel_th_probe,
|
||||
.remove = intel_th_remove,
|
||||
|
|
|
@ -815,7 +815,7 @@ static struct pci_driver nes_pci_driver = {
|
|||
.remove = nes_remove,
|
||||
};
|
||||
|
||||
static ssize_t nes_show_adapter(struct device_driver *ddp, char *buf)
|
||||
static ssize_t adapter_show(struct device_driver *ddp, char *buf)
|
||||
{
|
||||
unsigned int devfn = 0xffffffff;
|
||||
unsigned char bus_number = 0xff;
|
||||
|
@ -834,7 +834,7 @@ static ssize_t nes_show_adapter(struct device_driver *ddp, char *buf)
|
|||
return snprintf(buf, PAGE_SIZE, "%x:%x\n", bus_number, devfn);
|
||||
}
|
||||
|
||||
static ssize_t nes_store_adapter(struct device_driver *ddp,
|
||||
static ssize_t adapter_store(struct device_driver *ddp,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
char *p = (char *)buf;
|
||||
|
@ -843,7 +843,7 @@ static ssize_t nes_store_adapter(struct device_driver *ddp,
|
|||
return strnlen(buf, count);
|
||||
}
|
||||
|
||||
static ssize_t nes_show_ee_cmd(struct device_driver *ddp, char *buf)
|
||||
static ssize_t eeprom_cmd_show(struct device_driver *ddp, char *buf)
|
||||
{
|
||||
u32 eeprom_cmd = 0xdead;
|
||||
u32 i = 0;
|
||||
|
@ -859,7 +859,7 @@ static ssize_t nes_show_ee_cmd(struct device_driver *ddp, char *buf)
|
|||
return snprintf(buf, PAGE_SIZE, "0x%x\n", eeprom_cmd);
|
||||
}
|
||||
|
||||
static ssize_t nes_store_ee_cmd(struct device_driver *ddp,
|
||||
static ssize_t eeprom_cmd_store(struct device_driver *ddp,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
char *p = (char *)buf;
|
||||
|
@ -880,7 +880,7 @@ static ssize_t nes_store_ee_cmd(struct device_driver *ddp,
|
|||
return strnlen(buf, count);
|
||||
}
|
||||
|
||||
static ssize_t nes_show_ee_data(struct device_driver *ddp, char *buf)
|
||||
static ssize_t eeprom_data_show(struct device_driver *ddp, char *buf)
|
||||
{
|
||||
u32 eeprom_data = 0xdead;
|
||||
u32 i = 0;
|
||||
|
@ -897,7 +897,7 @@ static ssize_t nes_show_ee_data(struct device_driver *ddp, char *buf)
|
|||
return snprintf(buf, PAGE_SIZE, "0x%x\n", eeprom_data);
|
||||
}
|
||||
|
||||
static ssize_t nes_store_ee_data(struct device_driver *ddp,
|
||||
static ssize_t eeprom_data_store(struct device_driver *ddp,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
char *p = (char *)buf;
|
||||
|
@ -918,7 +918,7 @@ static ssize_t nes_store_ee_data(struct device_driver *ddp,
|
|||
return strnlen(buf, count);
|
||||
}
|
||||
|
||||
static ssize_t nes_show_flash_cmd(struct device_driver *ddp, char *buf)
|
||||
static ssize_t flash_cmd_show(struct device_driver *ddp, char *buf)
|
||||
{
|
||||
u32 flash_cmd = 0xdead;
|
||||
u32 i = 0;
|
||||
|
@ -935,7 +935,7 @@ static ssize_t nes_show_flash_cmd(struct device_driver *ddp, char *buf)
|
|||
return snprintf(buf, PAGE_SIZE, "0x%x\n", flash_cmd);
|
||||
}
|
||||
|
||||
static ssize_t nes_store_flash_cmd(struct device_driver *ddp,
|
||||
static ssize_t flash_cmd_store(struct device_driver *ddp,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
char *p = (char *)buf;
|
||||
|
@ -956,7 +956,7 @@ static ssize_t nes_store_flash_cmd(struct device_driver *ddp,
|
|||
return strnlen(buf, count);
|
||||
}
|
||||
|
||||
static ssize_t nes_show_flash_data(struct device_driver *ddp, char *buf)
|
||||
static ssize_t flash_data_show(struct device_driver *ddp, char *buf)
|
||||
{
|
||||
u32 flash_data = 0xdead;
|
||||
u32 i = 0;
|
||||
|
@ -973,7 +973,7 @@ static ssize_t nes_show_flash_data(struct device_driver *ddp, char *buf)
|
|||
return snprintf(buf, PAGE_SIZE, "0x%x\n", flash_data);
|
||||
}
|
||||
|
||||
static ssize_t nes_store_flash_data(struct device_driver *ddp,
|
||||
static ssize_t flash_data_store(struct device_driver *ddp,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
char *p = (char *)buf;
|
||||
|
@ -994,12 +994,12 @@ static ssize_t nes_store_flash_data(struct device_driver *ddp,
|
|||
return strnlen(buf, count);
|
||||
}
|
||||
|
||||
static ssize_t nes_show_nonidx_addr(struct device_driver *ddp, char *buf)
|
||||
static ssize_t nonidx_addr_show(struct device_driver *ddp, char *buf)
|
||||
{
|
||||
return snprintf(buf, PAGE_SIZE, "0x%x\n", sysfs_nonidx_addr);
|
||||
}
|
||||
|
||||
static ssize_t nes_store_nonidx_addr(struct device_driver *ddp,
|
||||
static ssize_t nonidx_addr_store(struct device_driver *ddp,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
char *p = (char *)buf;
|
||||
|
@ -1010,7 +1010,7 @@ static ssize_t nes_store_nonidx_addr(struct device_driver *ddp,
|
|||
return strnlen(buf, count);
|
||||
}
|
||||
|
||||
static ssize_t nes_show_nonidx_data(struct device_driver *ddp, char *buf)
|
||||
static ssize_t nonidx_data_show(struct device_driver *ddp, char *buf)
|
||||
{
|
||||
u32 nonidx_data = 0xdead;
|
||||
u32 i = 0;
|
||||
|
@ -1027,7 +1027,7 @@ static ssize_t nes_show_nonidx_data(struct device_driver *ddp, char *buf)
|
|||
return snprintf(buf, PAGE_SIZE, "0x%x\n", nonidx_data);
|
||||
}
|
||||
|
||||
static ssize_t nes_store_nonidx_data(struct device_driver *ddp,
|
||||
static ssize_t nonidx_data_store(struct device_driver *ddp,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
char *p = (char *)buf;
|
||||
|
@ -1048,12 +1048,12 @@ static ssize_t nes_store_nonidx_data(struct device_driver *ddp,
|
|||
return strnlen(buf, count);
|
||||
}
|
||||
|
||||
static ssize_t nes_show_idx_addr(struct device_driver *ddp, char *buf)
|
||||
static ssize_t idx_addr_show(struct device_driver *ddp, char *buf)
|
||||
{
|
||||
return snprintf(buf, PAGE_SIZE, "0x%x\n", sysfs_idx_addr);
|
||||
}
|
||||
|
||||
static ssize_t nes_store_idx_addr(struct device_driver *ddp,
|
||||
static ssize_t idx_addr_store(struct device_driver *ddp,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
char *p = (char *)buf;
|
||||
|
@ -1064,7 +1064,7 @@ static ssize_t nes_store_idx_addr(struct device_driver *ddp,
|
|||
return strnlen(buf, count);
|
||||
}
|
||||
|
||||
static ssize_t nes_show_idx_data(struct device_driver *ddp, char *buf)
|
||||
static ssize_t idx_data_show(struct device_driver *ddp, char *buf)
|
||||
{
|
||||
u32 idx_data = 0xdead;
|
||||
u32 i = 0;
|
||||
|
@ -1081,7 +1081,7 @@ static ssize_t nes_show_idx_data(struct device_driver *ddp, char *buf)
|
|||
return snprintf(buf, PAGE_SIZE, "0x%x\n", idx_data);
|
||||
}
|
||||
|
||||
static ssize_t nes_store_idx_data(struct device_driver *ddp,
|
||||
static ssize_t idx_data_store(struct device_driver *ddp,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
char *p = (char *)buf;
|
||||
|
@ -1102,11 +1102,7 @@ static ssize_t nes_store_idx_data(struct device_driver *ddp,
|
|||
return strnlen(buf, count);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* nes_show_wqm_quanta
|
||||
*/
|
||||
static ssize_t nes_show_wqm_quanta(struct device_driver *ddp, char *buf)
|
||||
static ssize_t wqm_quanta_show(struct device_driver *ddp, char *buf)
|
||||
{
|
||||
u32 wqm_quanta_value = 0xdead;
|
||||
u32 i = 0;
|
||||
|
@ -1123,12 +1119,8 @@ static ssize_t nes_show_wqm_quanta(struct device_driver *ddp, char *buf)
|
|||
return snprintf(buf, PAGE_SIZE, "0x%X\n", wqm_quanta_value);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* nes_store_wqm_quanta
|
||||
*/
|
||||
static ssize_t nes_store_wqm_quanta(struct device_driver *ddp,
|
||||
const char *buf, size_t count)
|
||||
static ssize_t wqm_quanta_store(struct device_driver *ddp, const char *buf,
|
||||
size_t count)
|
||||
{
|
||||
unsigned long wqm_quanta_value;
|
||||
u32 wqm_config1;
|
||||
|
@ -1153,26 +1145,16 @@ static ssize_t nes_store_wqm_quanta(struct device_driver *ddp,
|
|||
return strnlen(buf, count);
|
||||
}
|
||||
|
||||
static DRIVER_ATTR(adapter, S_IRUSR | S_IWUSR,
|
||||
nes_show_adapter, nes_store_adapter);
|
||||
static DRIVER_ATTR(eeprom_cmd, S_IRUSR | S_IWUSR,
|
||||
nes_show_ee_cmd, nes_store_ee_cmd);
|
||||
static DRIVER_ATTR(eeprom_data, S_IRUSR | S_IWUSR,
|
||||
nes_show_ee_data, nes_store_ee_data);
|
||||
static DRIVER_ATTR(flash_cmd, S_IRUSR | S_IWUSR,
|
||||
nes_show_flash_cmd, nes_store_flash_cmd);
|
||||
static DRIVER_ATTR(flash_data, S_IRUSR | S_IWUSR,
|
||||
nes_show_flash_data, nes_store_flash_data);
|
||||
static DRIVER_ATTR(nonidx_addr, S_IRUSR | S_IWUSR,
|
||||
nes_show_nonidx_addr, nes_store_nonidx_addr);
|
||||
static DRIVER_ATTR(nonidx_data, S_IRUSR | S_IWUSR,
|
||||
nes_show_nonidx_data, nes_store_nonidx_data);
|
||||
static DRIVER_ATTR(idx_addr, S_IRUSR | S_IWUSR,
|
||||
nes_show_idx_addr, nes_store_idx_addr);
|
||||
static DRIVER_ATTR(idx_data, S_IRUSR | S_IWUSR,
|
||||
nes_show_idx_data, nes_store_idx_data);
|
||||
static DRIVER_ATTR(wqm_quanta, S_IRUSR | S_IWUSR,
|
||||
nes_show_wqm_quanta, nes_store_wqm_quanta);
|
||||
static DRIVER_ATTR_RW(adapter);
|
||||
static DRIVER_ATTR_RW(eeprom_cmd);
|
||||
static DRIVER_ATTR_RW(eeprom_data);
|
||||
static DRIVER_ATTR_RW(flash_cmd);
|
||||
static DRIVER_ATTR_RW(flash_data);
|
||||
static DRIVER_ATTR_RW(nonidx_addr);
|
||||
static DRIVER_ATTR_RW(nonidx_data);
|
||||
static DRIVER_ATTR_RW(idx_addr);
|
||||
static DRIVER_ATTR_RW(idx_data);
|
||||
static DRIVER_ATTR_RW(wqm_quanta);
|
||||
|
||||
static int nes_create_driver_sysfs(struct pci_driver *drv)
|
||||
{
|
||||
|
|
|
@ -133,7 +133,7 @@ static int macio_device_resume(struct device * dev)
|
|||
return 0;
|
||||
}
|
||||
|
||||
extern struct device_attribute macio_dev_attrs[];
|
||||
extern const struct attribute_group *macio_dev_groups[];
|
||||
|
||||
struct bus_type macio_bus_type = {
|
||||
.name = "macio",
|
||||
|
@ -144,7 +144,7 @@ struct bus_type macio_bus_type = {
|
|||
.shutdown = macio_device_shutdown,
|
||||
.suspend = macio_device_suspend,
|
||||
.resume = macio_device_resume,
|
||||
.dev_attrs = macio_dev_attrs,
|
||||
.dev_groups = macio_dev_groups,
|
||||
};
|
||||
|
||||
static int __init macio_bus_driver_init(void)
|
||||
|
|
|
@ -10,7 +10,8 @@ field##_show (struct device *dev, struct device_attribute *attr, \
|
|||
{ \
|
||||
struct macio_dev *mdev = to_macio_device (dev); \
|
||||
return sprintf (buf, format_string, mdev->ofdev.dev.of_node->field); \
|
||||
}
|
||||
} \
|
||||
static DEVICE_ATTR_RO(field);
|
||||
|
||||
static ssize_t
|
||||
compatible_show (struct device *dev, struct device_attribute *attr, char *buf)
|
||||
|
@ -37,6 +38,7 @@ compatible_show (struct device *dev, struct device_attribute *attr, char *buf)
|
|||
|
||||
return length;
|
||||
}
|
||||
static DEVICE_ATTR_RO(compatible);
|
||||
|
||||
static ssize_t modalias_show (struct device *dev, struct device_attribute *attr,
|
||||
char *buf)
|
||||
|
@ -52,15 +54,26 @@ static ssize_t devspec_show(struct device *dev,
|
|||
ofdev = to_platform_device(dev);
|
||||
return sprintf(buf, "%s\n", ofdev->dev.of_node->full_name);
|
||||
}
|
||||
static DEVICE_ATTR_RO(modalias);
|
||||
static DEVICE_ATTR_RO(devspec);
|
||||
|
||||
macio_config_of_attr (name, "%s\n");
|
||||
macio_config_of_attr (type, "%s\n");
|
||||
|
||||
struct device_attribute macio_dev_attrs[] = {
|
||||
__ATTR_RO(name),
|
||||
__ATTR_RO(type),
|
||||
__ATTR_RO(compatible),
|
||||
__ATTR_RO(modalias),
|
||||
__ATTR_RO(devspec),
|
||||
__ATTR_NULL
|
||||
static struct attribute *macio_dev_attrs[] = {
|
||||
&dev_attr_name.attr,
|
||||
&dev_attr_type.attr,
|
||||
&dev_attr_compatible.attr,
|
||||
&dev_attr_modalias.attr,
|
||||
&dev_attr_devspec.attr,
|
||||
NULL,
|
||||
};
|
||||
|
||||
static const struct attribute_group macio_dev_group = {
|
||||
.attrs = macio_dev_attrs,
|
||||
};
|
||||
|
||||
const struct attribute_group *macio_dev_groups[] = {
|
||||
&macio_dev_group,
|
||||
NULL,
|
||||
};
|
||||
|
|
|
@ -104,23 +104,25 @@ DEFINE_MUTEX(ubi_devices_mutex);
|
|||
static DEFINE_SPINLOCK(ubi_devices_lock);
|
||||
|
||||
/* "Show" method for files in '/<sysfs>/class/ubi/' */
|
||||
static ssize_t ubi_version_show(struct class *class,
|
||||
struct class_attribute *attr, char *buf)
|
||||
/* UBI version attribute ('/<sysfs>/class/ubi/version') */
|
||||
static ssize_t version_show(struct class *class, struct class_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
return sprintf(buf, "%d\n", UBI_VERSION);
|
||||
}
|
||||
static CLASS_ATTR_RO(version);
|
||||
|
||||
/* UBI version attribute ('/<sysfs>/class/ubi/version') */
|
||||
static struct class_attribute ubi_class_attrs[] = {
|
||||
__ATTR(version, S_IRUGO, ubi_version_show, NULL),
|
||||
__ATTR_NULL
|
||||
static struct attribute *ubi_class_attrs[] = {
|
||||
&class_attr_version.attr,
|
||||
NULL,
|
||||
};
|
||||
ATTRIBUTE_GROUPS(ubi_class);
|
||||
|
||||
/* Root UBI "class" object (corresponds to '/<sysfs>/class/ubi/') */
|
||||
struct class ubi_class = {
|
||||
.name = UBI_NAME_STR,
|
||||
.owner = THIS_MODULE,
|
||||
.class_attrs = ubi_class_attrs,
|
||||
.class_groups = ubi_class_groups,
|
||||
};
|
||||
|
||||
static ssize_t dev_attribute_show(struct device *dev,
|
||||
|
|
|
@ -289,44 +289,44 @@ static LIST_HEAD(cfspi_list);
|
|||
static spinlock_t cfspi_list_lock;
|
||||
|
||||
/* SPI uplink head alignment. */
|
||||
static ssize_t show_up_head_align(struct device_driver *driver, char *buf)
|
||||
static ssize_t up_head_align_show(struct device_driver *driver, char *buf)
|
||||
{
|
||||
return sprintf(buf, "%d\n", spi_up_head_align);
|
||||
}
|
||||
|
||||
static DRIVER_ATTR(up_head_align, S_IRUSR, show_up_head_align, NULL);
|
||||
static DRIVER_ATTR_RO(up_head_align);
|
||||
|
||||
/* SPI uplink tail alignment. */
|
||||
static ssize_t show_up_tail_align(struct device_driver *driver, char *buf)
|
||||
static ssize_t up_tail_align_show(struct device_driver *driver, char *buf)
|
||||
{
|
||||
return sprintf(buf, "%d\n", spi_up_tail_align);
|
||||
}
|
||||
|
||||
static DRIVER_ATTR(up_tail_align, S_IRUSR, show_up_tail_align, NULL);
|
||||
static DRIVER_ATTR_RO(up_tail_align);
|
||||
|
||||
/* SPI downlink head alignment. */
|
||||
static ssize_t show_down_head_align(struct device_driver *driver, char *buf)
|
||||
static ssize_t down_head_align_show(struct device_driver *driver, char *buf)
|
||||
{
|
||||
return sprintf(buf, "%d\n", spi_down_head_align);
|
||||
}
|
||||
|
||||
static DRIVER_ATTR(down_head_align, S_IRUSR, show_down_head_align, NULL);
|
||||
static DRIVER_ATTR_RO(down_head_align);
|
||||
|
||||
/* SPI downlink tail alignment. */
|
||||
static ssize_t show_down_tail_align(struct device_driver *driver, char *buf)
|
||||
static ssize_t down_tail_align_show(struct device_driver *driver, char *buf)
|
||||
{
|
||||
return sprintf(buf, "%d\n", spi_down_tail_align);
|
||||
}
|
||||
|
||||
static DRIVER_ATTR(down_tail_align, S_IRUSR, show_down_tail_align, NULL);
|
||||
static DRIVER_ATTR_RO(down_tail_align);
|
||||
|
||||
/* SPI frame alignment. */
|
||||
static ssize_t show_frame_align(struct device_driver *driver, char *buf)
|
||||
static ssize_t frame_align_show(struct device_driver *driver, char *buf)
|
||||
{
|
||||
return sprintf(buf, "%d\n", spi_frm_align);
|
||||
}
|
||||
|
||||
static DRIVER_ATTR(frame_align, S_IRUSR, show_frame_align, NULL);
|
||||
static DRIVER_ATTR_RO(frame_align);
|
||||
|
||||
int cfspi_xmitfrm(struct cfspi *cfspi, u8 *buf, size_t len)
|
||||
{
|
||||
|
|
|
@ -3553,14 +3553,12 @@ static int check_module_parm(void)
|
|||
return ret;
|
||||
}
|
||||
|
||||
static ssize_t ehea_show_capabilities(struct device_driver *drv,
|
||||
char *buf)
|
||||
static ssize_t capabilities_show(struct device_driver *drv, char *buf)
|
||||
{
|
||||
return sprintf(buf, "%d", EHEA_CAPABILITIES);
|
||||
}
|
||||
|
||||
static DRIVER_ATTR(capabilities, S_IRUSR | S_IRGRP | S_IROTH,
|
||||
ehea_show_capabilities, NULL);
|
||||
static DRIVER_ATTR_RO(capabilities);
|
||||
|
||||
static int __init ehea_module_init(void)
|
||||
{
|
||||
|
|
|
@ -4160,12 +4160,12 @@ static ssize_t show_bssinfo(struct device *d, struct device_attribute *attr,
|
|||
static DEVICE_ATTR(bssinfo, S_IRUGO, show_bssinfo, NULL);
|
||||
|
||||
#ifdef CONFIG_IPW2100_DEBUG
|
||||
static ssize_t show_debug_level(struct device_driver *d, char *buf)
|
||||
static ssize_t debug_level_show(struct device_driver *d, char *buf)
|
||||
{
|
||||
return sprintf(buf, "0x%08X\n", ipw2100_debug_level);
|
||||
}
|
||||
|
||||
static ssize_t store_debug_level(struct device_driver *d,
|
||||
static ssize_t debug_level_store(struct device_driver *d,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
u32 val;
|
||||
|
@ -4179,9 +4179,7 @@ static ssize_t store_debug_level(struct device_driver *d,
|
|||
|
||||
return strnlen(buf, count);
|
||||
}
|
||||
|
||||
static DRIVER_ATTR(debug_level, S_IWUSR | S_IRUGO, show_debug_level,
|
||||
store_debug_level);
|
||||
static DRIVER_ATTR_RW(debug_level);
|
||||
#endif /* CONFIG_IPW2100_DEBUG */
|
||||
|
||||
static ssize_t show_fatal_error(struct device *d,
|
||||
|
|
|
@ -1195,12 +1195,12 @@ static void ipw_led_shutdown(struct ipw_priv *priv)
|
|||
*
|
||||
* See the level definitions in ipw for details.
|
||||
*/
|
||||
static ssize_t show_debug_level(struct device_driver *d, char *buf)
|
||||
static ssize_t debug_level_show(struct device_driver *d, char *buf)
|
||||
{
|
||||
return sprintf(buf, "0x%08X\n", ipw_debug_level);
|
||||
}
|
||||
|
||||
static ssize_t store_debug_level(struct device_driver *d, const char *buf,
|
||||
static ssize_t debug_level_store(struct device_driver *d, const char *buf,
|
||||
size_t count)
|
||||
{
|
||||
char *p = (char *)buf;
|
||||
|
@ -1221,9 +1221,7 @@ static ssize_t store_debug_level(struct device_driver *d, const char *buf,
|
|||
|
||||
return strnlen(buf, count);
|
||||
}
|
||||
|
||||
static DRIVER_ATTR(debug_level, S_IWUSR | S_IRUGO,
|
||||
show_debug_level, store_debug_level);
|
||||
static DRIVER_ATTR_RW(debug_level);
|
||||
|
||||
static inline u32 ipw_get_event_log_len(struct ipw_priv *priv)
|
||||
{
|
||||
|
|
|
@ -96,7 +96,7 @@ static void pci_free_dynids(struct pci_driver *drv)
|
|||
*
|
||||
* Allow PCI IDs to be added to an existing driver via sysfs.
|
||||
*/
|
||||
static ssize_t store_new_id(struct device_driver *driver, const char *buf,
|
||||
static ssize_t new_id_store(struct device_driver *driver, const char *buf,
|
||||
size_t count)
|
||||
{
|
||||
struct pci_driver *pdrv = to_pci_driver(driver);
|
||||
|
@ -154,7 +154,7 @@ static ssize_t store_new_id(struct device_driver *driver, const char *buf,
|
|||
return retval;
|
||||
return count;
|
||||
}
|
||||
static DRIVER_ATTR(new_id, S_IWUSR, NULL, store_new_id);
|
||||
static DRIVER_ATTR_WO(new_id);
|
||||
|
||||
/**
|
||||
* store_remove_id - remove a PCI device ID from this driver
|
||||
|
@ -164,7 +164,7 @@ static DRIVER_ATTR(new_id, S_IWUSR, NULL, store_new_id);
|
|||
*
|
||||
* Removes a dynamic pci device ID to this driver.
|
||||
*/
|
||||
static ssize_t store_remove_id(struct device_driver *driver, const char *buf,
|
||||
static ssize_t remove_id_store(struct device_driver *driver, const char *buf,
|
||||
size_t count)
|
||||
{
|
||||
struct pci_dynid *dynid, *n;
|
||||
|
@ -198,7 +198,7 @@ static ssize_t store_remove_id(struct device_driver *driver, const char *buf,
|
|||
|
||||
return retval;
|
||||
}
|
||||
static DRIVER_ATTR(remove_id, S_IWUSR, NULL, store_remove_id);
|
||||
static DRIVER_ATTR_WO(remove_id);
|
||||
|
||||
static struct attribute *pci_drv_attrs[] = {
|
||||
&driver_attr_new_id.attr,
|
||||
|
|
|
@ -95,7 +95,7 @@ struct pcmcia_dynid {
|
|||
* and causes the driver to probe for all devices again.
|
||||
*/
|
||||
static ssize_t
|
||||
pcmcia_store_new_id(struct device_driver *driver, const char *buf, size_t count)
|
||||
new_id_store(struct device_driver *driver, const char *buf, size_t count)
|
||||
{
|
||||
struct pcmcia_dynid *dynid;
|
||||
struct pcmcia_driver *pdrv = to_pcmcia_drv(driver);
|
||||
|
@ -133,7 +133,7 @@ pcmcia_store_new_id(struct device_driver *driver, const char *buf, size_t count)
|
|||
return retval;
|
||||
return count;
|
||||
}
|
||||
static DRIVER_ATTR(new_id, S_IWUSR, NULL, pcmcia_store_new_id);
|
||||
static DRIVER_ATTR_WO(new_id);
|
||||
|
||||
static void
|
||||
pcmcia_free_dynids(struct pcmcia_driver *drv)
|
||||
|
|
|
@ -1438,25 +1438,20 @@ static int tpacpi_rfk_procfs_write(const enum tpacpi_rfk_id id, char *buf)
|
|||
*/
|
||||
|
||||
/* interface_version --------------------------------------------------- */
|
||||
static ssize_t tpacpi_driver_interface_version_show(
|
||||
struct device_driver *drv,
|
||||
char *buf)
|
||||
static ssize_t interface_version_show(struct device_driver *drv, char *buf)
|
||||
{
|
||||
return snprintf(buf, PAGE_SIZE, "0x%08x\n", TPACPI_SYSFS_VERSION);
|
||||
}
|
||||
|
||||
static DRIVER_ATTR(interface_version, S_IRUGO,
|
||||
tpacpi_driver_interface_version_show, NULL);
|
||||
static DRIVER_ATTR_RO(interface_version);
|
||||
|
||||
/* debug_level --------------------------------------------------------- */
|
||||
static ssize_t tpacpi_driver_debug_show(struct device_driver *drv,
|
||||
char *buf)
|
||||
static ssize_t debug_level_show(struct device_driver *drv, char *buf)
|
||||
{
|
||||
return snprintf(buf, PAGE_SIZE, "0x%04x\n", dbg_level);
|
||||
}
|
||||
|
||||
static ssize_t tpacpi_driver_debug_store(struct device_driver *drv,
|
||||
const char *buf, size_t count)
|
||||
static ssize_t debug_level_store(struct device_driver *drv, const char *buf,
|
||||
size_t count)
|
||||
{
|
||||
unsigned long t;
|
||||
|
||||
|
@ -1467,34 +1462,28 @@ static ssize_t tpacpi_driver_debug_store(struct device_driver *drv,
|
|||
|
||||
return count;
|
||||
}
|
||||
|
||||
static DRIVER_ATTR(debug_level, S_IWUSR | S_IRUGO,
|
||||
tpacpi_driver_debug_show, tpacpi_driver_debug_store);
|
||||
static DRIVER_ATTR_RW(debug_level);
|
||||
|
||||
/* version ------------------------------------------------------------- */
|
||||
static ssize_t tpacpi_driver_version_show(struct device_driver *drv,
|
||||
char *buf)
|
||||
static ssize_t version_show(struct device_driver *drv, char *buf)
|
||||
{
|
||||
return snprintf(buf, PAGE_SIZE, "%s v%s\n",
|
||||
TPACPI_DESC, TPACPI_VERSION);
|
||||
}
|
||||
|
||||
static DRIVER_ATTR(version, S_IRUGO,
|
||||
tpacpi_driver_version_show, NULL);
|
||||
static DRIVER_ATTR_RO(version);
|
||||
|
||||
/* --------------------------------------------------------------------- */
|
||||
|
||||
#ifdef CONFIG_THINKPAD_ACPI_DEBUGFACILITIES
|
||||
|
||||
/* wlsw_emulstate ------------------------------------------------------ */
|
||||
static ssize_t tpacpi_driver_wlsw_emulstate_show(struct device_driver *drv,
|
||||
char *buf)
|
||||
static ssize_t wlsw_emulstate_show(struct device_driver *drv, char *buf)
|
||||
{
|
||||
return snprintf(buf, PAGE_SIZE, "%d\n", !!tpacpi_wlsw_emulstate);
|
||||
}
|
||||
|
||||
static ssize_t tpacpi_driver_wlsw_emulstate_store(struct device_driver *drv,
|
||||
const char *buf, size_t count)
|
||||
static ssize_t wlsw_emulstate_store(struct device_driver *drv, const char *buf,
|
||||
size_t count)
|
||||
{
|
||||
unsigned long t;
|
||||
|
||||
|
@ -1508,22 +1497,16 @@ static ssize_t tpacpi_driver_wlsw_emulstate_store(struct device_driver *drv,
|
|||
|
||||
return count;
|
||||
}
|
||||
|
||||
static DRIVER_ATTR(wlsw_emulstate, S_IWUSR | S_IRUGO,
|
||||
tpacpi_driver_wlsw_emulstate_show,
|
||||
tpacpi_driver_wlsw_emulstate_store);
|
||||
static DRIVER_ATTR_RW(wlsw_emulstate);
|
||||
|
||||
/* bluetooth_emulstate ------------------------------------------------- */
|
||||
static ssize_t tpacpi_driver_bluetooth_emulstate_show(
|
||||
struct device_driver *drv,
|
||||
char *buf)
|
||||
static ssize_t bluetooth_emulstate_show(struct device_driver *drv, char *buf)
|
||||
{
|
||||
return snprintf(buf, PAGE_SIZE, "%d\n", !!tpacpi_bluetooth_emulstate);
|
||||
}
|
||||
|
||||
static ssize_t tpacpi_driver_bluetooth_emulstate_store(
|
||||
struct device_driver *drv,
|
||||
const char *buf, size_t count)
|
||||
static ssize_t bluetooth_emulstate_store(struct device_driver *drv,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
unsigned long t;
|
||||
|
||||
|
@ -1534,22 +1517,16 @@ static ssize_t tpacpi_driver_bluetooth_emulstate_store(
|
|||
|
||||
return count;
|
||||
}
|
||||
|
||||
static DRIVER_ATTR(bluetooth_emulstate, S_IWUSR | S_IRUGO,
|
||||
tpacpi_driver_bluetooth_emulstate_show,
|
||||
tpacpi_driver_bluetooth_emulstate_store);
|
||||
static DRIVER_ATTR_RW(bluetooth_emulstate);
|
||||
|
||||
/* wwan_emulstate ------------------------------------------------- */
|
||||
static ssize_t tpacpi_driver_wwan_emulstate_show(
|
||||
struct device_driver *drv,
|
||||
char *buf)
|
||||
static ssize_t wwan_emulstate_show(struct device_driver *drv, char *buf)
|
||||
{
|
||||
return snprintf(buf, PAGE_SIZE, "%d\n", !!tpacpi_wwan_emulstate);
|
||||
}
|
||||
|
||||
static ssize_t tpacpi_driver_wwan_emulstate_store(
|
||||
struct device_driver *drv,
|
||||
const char *buf, size_t count)
|
||||
static ssize_t wwan_emulstate_store(struct device_driver *drv, const char *buf,
|
||||
size_t count)
|
||||
{
|
||||
unsigned long t;
|
||||
|
||||
|
@ -1560,22 +1537,16 @@ static ssize_t tpacpi_driver_wwan_emulstate_store(
|
|||
|
||||
return count;
|
||||
}
|
||||
|
||||
static DRIVER_ATTR(wwan_emulstate, S_IWUSR | S_IRUGO,
|
||||
tpacpi_driver_wwan_emulstate_show,
|
||||
tpacpi_driver_wwan_emulstate_store);
|
||||
static DRIVER_ATTR_RW(wwan_emulstate);
|
||||
|
||||
/* uwb_emulstate ------------------------------------------------- */
|
||||
static ssize_t tpacpi_driver_uwb_emulstate_show(
|
||||
struct device_driver *drv,
|
||||
char *buf)
|
||||
static ssize_t uwb_emulstate_show(struct device_driver *drv, char *buf)
|
||||
{
|
||||
return snprintf(buf, PAGE_SIZE, "%d\n", !!tpacpi_uwb_emulstate);
|
||||
}
|
||||
|
||||
static ssize_t tpacpi_driver_uwb_emulstate_store(
|
||||
struct device_driver *drv,
|
||||
const char *buf, size_t count)
|
||||
static ssize_t uwb_emulstate_store(struct device_driver *drv, const char *buf,
|
||||
size_t count)
|
||||
{
|
||||
unsigned long t;
|
||||
|
||||
|
@ -1586,10 +1557,7 @@ static ssize_t tpacpi_driver_uwb_emulstate_store(
|
|||
|
||||
return count;
|
||||
}
|
||||
|
||||
static DRIVER_ATTR(uwb_emulstate, S_IWUSR | S_IRUGO,
|
||||
tpacpi_driver_uwb_emulstate_show,
|
||||
tpacpi_driver_uwb_emulstate_store);
|
||||
static DRIVER_ATTR_RW(uwb_emulstate);
|
||||
#endif
|
||||
|
||||
/* --------------------------------------------------------------------- */
|
||||
|
@ -8606,14 +8574,13 @@ static ssize_t fan_fan2_input_show(struct device *dev,
|
|||
static DEVICE_ATTR(fan2_input, S_IRUGO, fan_fan2_input_show, NULL);
|
||||
|
||||
/* sysfs fan fan_watchdog (hwmon driver) ------------------------------- */
|
||||
static ssize_t fan_fan_watchdog_show(struct device_driver *drv,
|
||||
char *buf)
|
||||
static ssize_t fan_watchdog_show(struct device_driver *drv, char *buf)
|
||||
{
|
||||
return snprintf(buf, PAGE_SIZE, "%u\n", fan_watchdog_maxinterval);
|
||||
}
|
||||
|
||||
static ssize_t fan_fan_watchdog_store(struct device_driver *drv,
|
||||
const char *buf, size_t count)
|
||||
static ssize_t fan_watchdog_store(struct device_driver *drv, const char *buf,
|
||||
size_t count)
|
||||
{
|
||||
unsigned long t;
|
||||
|
||||
|
@ -8630,9 +8597,7 @@ static ssize_t fan_fan_watchdog_store(struct device_driver *drv,
|
|||
|
||||
return count;
|
||||
}
|
||||
|
||||
static DRIVER_ATTR(fan_watchdog, S_IWUSR | S_IRUGO,
|
||||
fan_fan_watchdog_show, fan_fan_watchdog_store);
|
||||
static DRIVER_ATTR_RW(fan_watchdog);
|
||||
|
||||
/* --------------------------------------------------------------------- */
|
||||
static struct attribute *fan_attributes[] = {
|
||||
|
|
|
@ -330,7 +330,8 @@ field##_show(struct device *dev, \
|
|||
struct rpmsg_device *rpdev = to_rpmsg_device(dev); \
|
||||
\
|
||||
return sprintf(buf, format_string, rpdev->path); \
|
||||
}
|
||||
} \
|
||||
static DEVICE_ATTR_RO(field);
|
||||
|
||||
/* for more info, see Documentation/ABI/testing/sysfs-bus-rpmsg */
|
||||
rpmsg_show_attr(name, id.name, "%s\n");
|
||||
|
@ -345,15 +346,17 @@ static ssize_t modalias_show(struct device *dev,
|
|||
|
||||
return sprintf(buf, RPMSG_DEVICE_MODALIAS_FMT "\n", rpdev->id.name);
|
||||
}
|
||||
static DEVICE_ATTR_RO(modalias);
|
||||
|
||||
static struct device_attribute rpmsg_dev_attrs[] = {
|
||||
__ATTR_RO(name),
|
||||
__ATTR_RO(modalias),
|
||||
__ATTR_RO(dst),
|
||||
__ATTR_RO(src),
|
||||
__ATTR_RO(announce),
|
||||
__ATTR_NULL
|
||||
static struct attribute *rpmsg_dev_attrs[] = {
|
||||
&dev_attr_name.attr,
|
||||
&dev_attr_modalias.attr,
|
||||
&dev_attr_dst.attr,
|
||||
&dev_attr_src.attr,
|
||||
&dev_attr_announce.attr,
|
||||
NULL,
|
||||
};
|
||||
ATTRIBUTE_GROUPS(rpmsg_dev);
|
||||
|
||||
/* rpmsg devices and drivers are matched using the service name */
|
||||
static inline int rpmsg_id_match(const struct rpmsg_device *rpdev,
|
||||
|
@ -455,7 +458,7 @@ static int rpmsg_dev_remove(struct device *dev)
|
|||
static struct bus_type rpmsg_bus = {
|
||||
.name = "rpmsg",
|
||||
.match = rpmsg_dev_match,
|
||||
.dev_attrs = rpmsg_dev_attrs,
|
||||
.dev_groups = rpmsg_dev_groups,
|
||||
.uevent = rpmsg_uevent,
|
||||
.probe = rpmsg_dev_probe,
|
||||
.remove = rpmsg_dev_remove,
|
||||
|
|
|
@ -1096,26 +1096,26 @@ static const struct dev_pm_ops sclp_pm_ops = {
|
|||
.restore = sclp_restore,
|
||||
};
|
||||
|
||||
static ssize_t sclp_show_console_pages(struct device_driver *dev, char *buf)
|
||||
static ssize_t con_pages_show(struct device_driver *dev, char *buf)
|
||||
{
|
||||
return sprintf(buf, "%i\n", sclp_console_pages);
|
||||
}
|
||||
|
||||
static DRIVER_ATTR(con_pages, S_IRUSR, sclp_show_console_pages, NULL);
|
||||
static DRIVER_ATTR_RO(con_pages);
|
||||
|
||||
static ssize_t sclp_show_con_drop(struct device_driver *dev, char *buf)
|
||||
static ssize_t con_drop_show(struct device_driver *dev, char *buf)
|
||||
{
|
||||
return sprintf(buf, "%i\n", sclp_console_drop);
|
||||
}
|
||||
|
||||
static DRIVER_ATTR(con_drop, S_IRUSR, sclp_show_con_drop, NULL);
|
||||
static DRIVER_ATTR_RO(con_drop);
|
||||
|
||||
static ssize_t sclp_show_console_full(struct device_driver *dev, char *buf)
|
||||
static ssize_t con_full_show(struct device_driver *dev, char *buf)
|
||||
{
|
||||
return sprintf(buf, "%lu\n", sclp_console_full);
|
||||
}
|
||||
|
||||
static DRIVER_ATTR(con_full, S_IRUSR, sclp_show_console_full, NULL);
|
||||
static DRIVER_ATTR_RO(con_full);
|
||||
|
||||
static struct attribute *sclp_drv_attrs[] = {
|
||||
&driver_attr_con_pages.attr,
|
||||
|
|
|
@ -641,10 +641,8 @@ static ssize_t vmlogrdr_recording_store(struct device * dev,
|
|||
static DEVICE_ATTR(recording, 0200, NULL, vmlogrdr_recording_store);
|
||||
|
||||
|
||||
static ssize_t vmlogrdr_recording_status_show(struct device_driver *driver,
|
||||
char *buf)
|
||||
static ssize_t recording_status_show(struct device_driver *driver, char *buf)
|
||||
{
|
||||
|
||||
static const char cp_command[] = "QUERY RECORDING ";
|
||||
int len;
|
||||
|
||||
|
@ -652,8 +650,7 @@ static ssize_t vmlogrdr_recording_status_show(struct device_driver *driver,
|
|||
len = strlen(buf);
|
||||
return len;
|
||||
}
|
||||
static DRIVER_ATTR(recording_status, 0444, vmlogrdr_recording_status_show,
|
||||
NULL);
|
||||
static DRIVER_ATTR_RO(recording_status);
|
||||
static struct attribute *vmlogrdr_drv_attrs[] = {
|
||||
&driver_attr_recording_status.attr,
|
||||
NULL,
|
||||
|
|
|
@ -1770,15 +1770,15 @@ static struct ccwgroup_driver ctcm_group_driver = {
|
|||
.restore = ctcm_pm_resume,
|
||||
};
|
||||
|
||||
static ssize_t ctcm_driver_group_store(struct device_driver *ddrv,
|
||||
const char *buf, size_t count)
|
||||
static ssize_t group_store(struct device_driver *ddrv, const char *buf,
|
||||
size_t count)
|
||||
{
|
||||
int err;
|
||||
|
||||
err = ccwgroup_create_dev(ctcm_root_dev, &ctcm_group_driver, 2, buf);
|
||||
return err ? err : count;
|
||||
}
|
||||
static DRIVER_ATTR(group, 0200, NULL, ctcm_driver_group_store);
|
||||
static DRIVER_ATTR_WO(group);
|
||||
|
||||
static struct attribute *ctcm_drv_attrs[] = {
|
||||
&driver_attr_group.attr,
|
||||
|
|
|
@ -2411,14 +2411,14 @@ static struct ccwgroup_driver lcs_group_driver = {
|
|||
.restore = lcs_restore,
|
||||
};
|
||||
|
||||
static ssize_t lcs_driver_group_store(struct device_driver *ddrv,
|
||||
const char *buf, size_t count)
|
||||
static ssize_t group_store(struct device_driver *ddrv, const char *buf,
|
||||
size_t count)
|
||||
{
|
||||
int err;
|
||||
err = ccwgroup_create_dev(lcs_root_dev, &lcs_group_driver, 2, buf);
|
||||
return err ? err : count;
|
||||
}
|
||||
static DRIVER_ATTR(group, 0200, NULL, lcs_driver_group_store);
|
||||
static DRIVER_ATTR_WO(group);
|
||||
|
||||
static struct attribute *lcs_drv_attrs[] = {
|
||||
&driver_attr_group.attr,
|
||||
|
|
|
@ -2020,8 +2020,8 @@ out_netdev:
|
|||
return NULL;
|
||||
}
|
||||
|
||||
static ssize_t conn_write(struct device_driver *drv,
|
||||
const char *buf, size_t count)
|
||||
static ssize_t connection_store(struct device_driver *drv, const char *buf,
|
||||
size_t count)
|
||||
{
|
||||
char username[9];
|
||||
char userdata[17];
|
||||
|
@ -2082,11 +2082,10 @@ out_free_ndev:
|
|||
netiucv_free_netdevice(dev);
|
||||
return rc;
|
||||
}
|
||||
static DRIVER_ATTR_WO(connection);
|
||||
|
||||
static DRIVER_ATTR(connection, 0200, NULL, conn_write);
|
||||
|
||||
static ssize_t remove_write (struct device_driver *drv,
|
||||
const char *buf, size_t count)
|
||||
static ssize_t remove_store(struct device_driver *drv, const char *buf,
|
||||
size_t count)
|
||||
{
|
||||
struct iucv_connection *cp;
|
||||
struct net_device *ndev;
|
||||
|
@ -2132,8 +2131,7 @@ static ssize_t remove_write (struct device_driver *drv,
|
|||
IUCV_DBF_TEXT(data, 2, "remove_write: unknown device\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static DRIVER_ATTR(remove, 0200, NULL, remove_write);
|
||||
static DRIVER_ATTR_WO(remove);
|
||||
|
||||
static struct attribute * netiucv_drv_attrs[] = {
|
||||
&driver_attr_connection.attr,
|
||||
|
|
|
@ -5800,8 +5800,8 @@ static struct ccwgroup_driver qeth_core_ccwgroup_driver = {
|
|||
.restore = qeth_core_restore,
|
||||
};
|
||||
|
||||
static ssize_t qeth_core_driver_group_store(struct device_driver *ddrv,
|
||||
const char *buf, size_t count)
|
||||
static ssize_t group_store(struct device_driver *ddrv, const char *buf,
|
||||
size_t count)
|
||||
{
|
||||
int err;
|
||||
|
||||
|
@ -5810,7 +5810,7 @@ static ssize_t qeth_core_driver_group_store(struct device_driver *ddrv,
|
|||
|
||||
return err ? err : count;
|
||||
}
|
||||
static DRIVER_ATTR(group, 0200, NULL, qeth_core_driver_group_store);
|
||||
static DRIVER_ATTR_WO(group);
|
||||
|
||||
static struct attribute *qeth_drv_attrs[] = {
|
||||
&driver_attr_group.attr,
|
||||
|
|
|
@ -3934,10 +3934,6 @@ static const struct target_core_fabric_ops ibmvscsis_ops = {
|
|||
|
||||
static void ibmvscsis_dev_release(struct device *dev) {};
|
||||
|
||||
static struct class_attribute ibmvscsis_class_attrs[] = {
|
||||
__ATTR_NULL,
|
||||
};
|
||||
|
||||
static struct device_attribute dev_attr_system_id =
|
||||
__ATTR(system_id, S_IRUGO, system_id_show, NULL);
|
||||
|
||||
|
@ -3957,7 +3953,6 @@ ATTRIBUTE_GROUPS(ibmvscsis_dev);
|
|||
static struct class ibmvscsis_class = {
|
||||
.name = "ibmvscsis",
|
||||
.dev_release = ibmvscsis_dev_release,
|
||||
.class_attrs = ibmvscsis_class_attrs,
|
||||
.dev_groups = ibmvscsis_dev_groups,
|
||||
};
|
||||
|
||||
|
|
|
@ -19,7 +19,8 @@ static ssize_t name##_show(struct device *dev, struct device_attribute *attr, ch
|
|||
{ \
|
||||
struct superhyway_device *s = to_superhyway_device(dev); \
|
||||
return sprintf(buf, fmt, s->field); \
|
||||
}
|
||||
} \
|
||||
static DEVICE_ATTR_RO(name);
|
||||
|
||||
/* VCR flags */
|
||||
superhyway_ro_attr(perr_flags, "0x%02x\n", vcr.perr_flags);
|
||||
|
@ -32,14 +33,22 @@ superhyway_ro_attr(top_mb, "0x%02x\n", vcr.top_mb);
|
|||
/* Misc */
|
||||
superhyway_ro_attr(resource, "0x%08lx\n", resource[0].start);
|
||||
|
||||
struct device_attribute superhyway_dev_attrs[] = {
|
||||
__ATTR_RO(perr_flags),
|
||||
__ATTR_RO(merr_flags),
|
||||
__ATTR_RO(mod_vers),
|
||||
__ATTR_RO(mod_id),
|
||||
__ATTR_RO(bot_mb),
|
||||
__ATTR_RO(top_mb),
|
||||
__ATTR_RO(resource),
|
||||
__ATTR_NULL,
|
||||
static struct attribute *superhyway_dev_attrs[] = {
|
||||
&dev_attr_perr_flags.attr,
|
||||
&dev_attr_merr_flags.attr,
|
||||
&dev_attr_mod_vers.attr,
|
||||
&dev_attr_mod_id.attr,
|
||||
&dev_attr_bot_mb.attr,
|
||||
&dev_attr_top_mb.attr,
|
||||
&dev_attr_resource.attr,
|
||||
NULL,
|
||||
};
|
||||
|
||||
static const struct attribute_group superhyway_dev_group = {
|
||||
.attrs = superhyway_dev_attrs,
|
||||
};
|
||||
|
||||
const struct attribute_group *superhyway_dev_groups[] = {
|
||||
&superhyway_dev_group,
|
||||
NULL,
|
||||
};
|
||||
|
|
|
@ -209,7 +209,7 @@ struct bus_type superhyway_bus_type = {
|
|||
.name = "superhyway",
|
||||
.match = superhyway_bus_match,
|
||||
#ifdef CONFIG_SYSFS
|
||||
.dev_attrs = superhyway_dev_attrs,
|
||||
.dev_groups = superhyway_dev_groups,
|
||||
#endif
|
||||
.probe = superhyway_device_probe,
|
||||
.remove = superhyway_device_remove,
|
||||
|
|
|
@ -484,13 +484,13 @@ static struct attribute_group hvcs_attr_group = {
|
|||
.attrs = hvcs_attrs,
|
||||
};
|
||||
|
||||
static ssize_t hvcs_rescan_show(struct device_driver *ddp, char *buf)
|
||||
static ssize_t rescan_show(struct device_driver *ddp, char *buf)
|
||||
{
|
||||
/* A 1 means it is updating, a 0 means it is done updating */
|
||||
return snprintf(buf, PAGE_SIZE, "%d\n", hvcs_rescan_status);
|
||||
}
|
||||
|
||||
static ssize_t hvcs_rescan_store(struct device_driver *ddp, const char * buf,
|
||||
static ssize_t rescan_store(struct device_driver *ddp, const char * buf,
|
||||
size_t count)
|
||||
{
|
||||
if ((simple_strtol(buf, NULL, 0) != 1)
|
||||
|
@ -505,8 +505,7 @@ static ssize_t hvcs_rescan_store(struct device_driver *ddp, const char * buf,
|
|||
return count;
|
||||
}
|
||||
|
||||
static DRIVER_ATTR(rescan,
|
||||
S_IRUGO | S_IWUSR, hvcs_rescan_show, hvcs_rescan_store);
|
||||
static DRIVER_ATTR_RW(rescan);
|
||||
|
||||
static void hvcs_kick(void)
|
||||
{
|
||||
|
|
|
@ -262,11 +262,13 @@ static ssize_t modalias_show(struct device *dev,
|
|||
{
|
||||
return of_device_modalias(dev, buf, PAGE_SIZE);
|
||||
}
|
||||
DEVICE_ATTR_RO(modalias);
|
||||
|
||||
static struct device_attribute serdev_device_attrs[] = {
|
||||
__ATTR_RO(modalias),
|
||||
__ATTR_NULL
|
||||
static struct attribute *serdev_device_attrs[] = {
|
||||
&dev_attr_modalias.attr,
|
||||
NULL,
|
||||
};
|
||||
ATTRIBUTE_GROUPS(serdev_device);
|
||||
|
||||
static struct bus_type serdev_bus_type = {
|
||||
.name = "serial",
|
||||
|
@ -274,7 +276,7 @@ static struct bus_type serdev_bus_type = {
|
|||
.probe = serdev_drv_probe,
|
||||
.remove = serdev_drv_remove,
|
||||
.uevent = serdev_uevent,
|
||||
.dev_attrs = serdev_device_attrs,
|
||||
.dev_groups = serdev_device_groups,
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
@ -134,7 +134,7 @@ out:
|
|||
return ret;
|
||||
}
|
||||
|
||||
static ssize_t show_match_busid(struct device_driver *drv, char *buf)
|
||||
static ssize_t match_busid_show(struct device_driver *drv, char *buf)
|
||||
{
|
||||
int i;
|
||||
char *out = buf;
|
||||
|
@ -149,7 +149,7 @@ static ssize_t show_match_busid(struct device_driver *drv, char *buf)
|
|||
return out - buf;
|
||||
}
|
||||
|
||||
static ssize_t store_match_busid(struct device_driver *dev, const char *buf,
|
||||
static ssize_t match_busid_store(struct device_driver *dev, const char *buf,
|
||||
size_t count)
|
||||
{
|
||||
int len;
|
||||
|
@ -181,8 +181,7 @@ static ssize_t store_match_busid(struct device_driver *dev, const char *buf,
|
|||
|
||||
return -EINVAL;
|
||||
}
|
||||
static DRIVER_ATTR(match_busid, S_IRUSR | S_IWUSR, show_match_busid,
|
||||
store_match_busid);
|
||||
static DRIVER_ATTR_RW(match_busid);
|
||||
|
||||
static ssize_t rebind_store(struct device_driver *dev, const char *buf,
|
||||
size_t count)
|
||||
|
|
|
@ -94,17 +94,18 @@ ssize_t beacon_timeout_ms_store(struct class *class,
|
|||
beacon_timeout_ms = bt;
|
||||
return size;
|
||||
}
|
||||
static CLASS_ATTR_RW(beacon_timeout_ms);
|
||||
|
||||
static struct class_attribute uwb_class_attrs[] = {
|
||||
__ATTR(beacon_timeout_ms, S_IWUSR | S_IRUGO,
|
||||
beacon_timeout_ms_show, beacon_timeout_ms_store),
|
||||
__ATTR_NULL,
|
||||
static struct attribute *uwb_class_attrs[] = {
|
||||
&class_attr_beacon_timeout_ms.attr,
|
||||
NULL,
|
||||
};
|
||||
ATTRIBUTE_GROUPS(uwb_class);
|
||||
|
||||
/** Device model classes */
|
||||
struct class uwb_rc_class = {
|
||||
.name = "uwb_rc",
|
||||
.class_attrs = uwb_class_attrs,
|
||||
.class_groups = uwb_class_groups,
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -0,0 +1,17 @@
|
|||
/*
|
||||
* include/linux/arch_topology.h - arch specific cpu topology information
|
||||
*/
|
||||
#ifndef _LINUX_ARCH_TOPOLOGY_H_
|
||||
#define _LINUX_ARCH_TOPOLOGY_H_
|
||||
|
||||
void topology_normalize_cpu_scale(void);
|
||||
|
||||
struct device_node;
|
||||
int topology_parse_cpu_capacity(struct device_node *cpu_node, int cpu);
|
||||
|
||||
struct sched_domain;
|
||||
unsigned long topology_get_cpu_scale(struct sched_domain *sd, int cpu);
|
||||
|
||||
void topology_set_cpu_scale(unsigned int cpu, unsigned long capacity);
|
||||
|
||||
#endif /* _LINUX_ARCH_TOPOLOGY_H_ */
|
|
@ -66,7 +66,6 @@ extern void bus_remove_file(struct bus_type *, struct bus_attribute *);
|
|||
* @name: The name of the bus.
|
||||
* @dev_name: Used for subsystems to enumerate devices like ("foo%u", dev->id).
|
||||
* @dev_root: Default device to use as the parent.
|
||||
* @dev_attrs: Default attributes of the devices on the bus.
|
||||
* @bus_groups: Default attributes of the bus.
|
||||
* @dev_groups: Default attributes of the devices on the bus.
|
||||
* @drv_groups: Default attributes of the device drivers on the bus.
|
||||
|
@ -112,7 +111,6 @@ struct bus_type {
|
|||
const char *name;
|
||||
const char *dev_name;
|
||||
struct device *dev_root;
|
||||
struct device_attribute *dev_attrs; /* use dev_groups instead */
|
||||
const struct attribute_group **bus_groups;
|
||||
const struct attribute_group **dev_groups;
|
||||
const struct attribute_group **drv_groups;
|
||||
|
@ -365,7 +363,6 @@ int subsys_virtual_register(struct bus_type *subsys,
|
|||
* struct class - device classes
|
||||
* @name: Name of the class.
|
||||
* @owner: The module owner.
|
||||
* @class_attrs: Default attributes of this class.
|
||||
* @class_groups: Default attributes of this class.
|
||||
* @dev_groups: Default attributes of the devices that belong to the class.
|
||||
* @dev_kobj: The kobject that represents this class and links it into the hierarchy.
|
||||
|
@ -394,7 +391,6 @@ struct class {
|
|||
const char *name;
|
||||
struct module *owner;
|
||||
|
||||
struct class_attribute *class_attrs;
|
||||
const struct attribute_group **class_groups;
|
||||
const struct attribute_group **dev_groups;
|
||||
struct kobject *dev_kobj;
|
||||
|
@ -465,8 +461,6 @@ struct class_attribute {
|
|||
const char *buf, size_t count);
|
||||
};
|
||||
|
||||
#define CLASS_ATTR(_name, _mode, _show, _store) \
|
||||
struct class_attribute class_attr_##_name = __ATTR(_name, _mode, _show, _store)
|
||||
#define CLASS_ATTR_RW(_name) \
|
||||
struct class_attribute class_attr_##_name = __ATTR_RW(_name)
|
||||
#define CLASS_ATTR_RO(_name) \
|
||||
|
|
|
@ -217,11 +217,9 @@ extern struct kobject *firmware_kobj;
|
|||
int kobject_uevent(struct kobject *kobj, enum kobject_action action);
|
||||
int kobject_uevent_env(struct kobject *kobj, enum kobject_action action,
|
||||
char *envp[]);
|
||||
int kobject_synth_uevent(struct kobject *kobj, const char *buf, size_t count);
|
||||
|
||||
__printf(2, 3)
|
||||
int add_uevent_var(struct kobj_uevent_env *env, const char *format, ...);
|
||||
|
||||
int kobject_action_type(const char *buf, size_t count,
|
||||
enum kobject_action *type);
|
||||
|
||||
#endif /* _KOBJECT_H_ */
|
||||
|
|
|
@ -101,7 +101,7 @@ int superhyway_add_device(unsigned long base, struct superhyway_device *, struct
|
|||
int superhyway_add_devices(struct superhyway_bus *bus, struct superhyway_device **devices, int nr_devices);
|
||||
|
||||
/* drivers/sh/superhyway/superhyway-sysfs.c */
|
||||
extern struct device_attribute superhyway_dev_attrs[];
|
||||
extern const struct attribute_group *superhyway_dev_groups[];
|
||||
|
||||
#endif /* __LINUX_SUPERHYWAY_H */
|
||||
|
||||
|
|
|
@ -512,7 +512,7 @@ static inline void sysfs_notify_dirent(struct kernfs_node *kn)
|
|||
}
|
||||
|
||||
static inline struct kernfs_node *sysfs_get_dirent(struct kernfs_node *parent,
|
||||
const unsigned char *name)
|
||||
const char *name)
|
||||
{
|
||||
return kernfs_find_and_get(parent, name);
|
||||
}
|
||||
|
|
|
@ -1202,10 +1202,7 @@ static ssize_t store_uevent(struct module_attribute *mattr,
|
|||
struct module_kobject *mk,
|
||||
const char *buffer, size_t count)
|
||||
{
|
||||
enum kobject_action action;
|
||||
|
||||
if (kobject_action_type(buffer, count, &action) == 0)
|
||||
kobject_uevent(&mk->kobj, action);
|
||||
kobject_synth_uevent(&mk->kobj, buffer, count);
|
||||
return count;
|
||||
}
|
||||
|
||||
|
|
|
@ -23,6 +23,8 @@
|
|||
#include <linux/socket.h>
|
||||
#include <linux/skbuff.h>
|
||||
#include <linux/netlink.h>
|
||||
#include <linux/uuid.h>
|
||||
#include <linux/ctype.h>
|
||||
#include <net/sock.h>
|
||||
#include <net/net_namespace.h>
|
||||
|
||||
|
@ -52,19 +54,13 @@ static const char *kobject_actions[] = {
|
|||
[KOBJ_OFFLINE] = "offline",
|
||||
};
|
||||
|
||||
/**
|
||||
* kobject_action_type - translate action string to numeric type
|
||||
*
|
||||
* @buf: buffer containing the action string, newline is ignored
|
||||
* @count: length of buffer
|
||||
* @type: pointer to the location to store the action type
|
||||
*
|
||||
* Returns 0 if the action string was recognized.
|
||||
*/
|
||||
int kobject_action_type(const char *buf, size_t count,
|
||||
enum kobject_action *type)
|
||||
static int kobject_action_type(const char *buf, size_t count,
|
||||
enum kobject_action *type,
|
||||
const char **args)
|
||||
{
|
||||
enum kobject_action action;
|
||||
size_t count_first;
|
||||
const char *args_start;
|
||||
int ret = -EINVAL;
|
||||
|
||||
if (count && (buf[count-1] == '\n' || buf[count-1] == '\0'))
|
||||
|
@ -73,11 +69,20 @@ int kobject_action_type(const char *buf, size_t count,
|
|||
if (!count)
|
||||
goto out;
|
||||
|
||||
args_start = strnchr(buf, count, ' ');
|
||||
if (args_start) {
|
||||
count_first = args_start - buf;
|
||||
args_start = args_start + 1;
|
||||
} else
|
||||
count_first = count;
|
||||
|
||||
for (action = 0; action < ARRAY_SIZE(kobject_actions); action++) {
|
||||
if (strncmp(kobject_actions[action], buf, count) != 0)
|
||||
if (strncmp(kobject_actions[action], buf, count_first) != 0)
|
||||
continue;
|
||||
if (kobject_actions[action][count] != '\0')
|
||||
if (kobject_actions[action][count_first] != '\0')
|
||||
continue;
|
||||
if (args)
|
||||
*args = args_start;
|
||||
*type = action;
|
||||
ret = 0;
|
||||
break;
|
||||
|
@ -86,6 +91,142 @@ out:
|
|||
return ret;
|
||||
}
|
||||
|
||||
static const char *action_arg_word_end(const char *buf, const char *buf_end,
|
||||
char delim)
|
||||
{
|
||||
const char *next = buf;
|
||||
|
||||
while (next <= buf_end && *next != delim)
|
||||
if (!isalnum(*next++))
|
||||
return NULL;
|
||||
|
||||
if (next == buf)
|
||||
return NULL;
|
||||
|
||||
return next;
|
||||
}
|
||||
|
||||
static int kobject_action_args(const char *buf, size_t count,
|
||||
struct kobj_uevent_env **ret_env)
|
||||
{
|
||||
struct kobj_uevent_env *env = NULL;
|
||||
const char *next, *buf_end, *key;
|
||||
int key_len;
|
||||
int r = -EINVAL;
|
||||
|
||||
if (count && (buf[count - 1] == '\n' || buf[count - 1] == '\0'))
|
||||
count--;
|
||||
|
||||
if (!count)
|
||||
return -EINVAL;
|
||||
|
||||
env = kzalloc(sizeof(*env), GFP_KERNEL);
|
||||
if (!env)
|
||||
return -ENOMEM;
|
||||
|
||||
/* first arg is UUID */
|
||||
if (count < UUID_STRING_LEN || !uuid_is_valid(buf) ||
|
||||
add_uevent_var(env, "SYNTH_UUID=%.*s", UUID_STRING_LEN, buf))
|
||||
goto out;
|
||||
|
||||
/*
|
||||
* the rest are custom environment variables in KEY=VALUE
|
||||
* format with ' ' delimiter between each KEY=VALUE pair
|
||||
*/
|
||||
next = buf + UUID_STRING_LEN;
|
||||
buf_end = buf + count - 1;
|
||||
|
||||
while (next <= buf_end) {
|
||||
if (*next != ' ')
|
||||
goto out;
|
||||
|
||||
/* skip the ' ', key must follow */
|
||||
key = ++next;
|
||||
if (key > buf_end)
|
||||
goto out;
|
||||
|
||||
buf = next;
|
||||
next = action_arg_word_end(buf, buf_end, '=');
|
||||
if (!next || next > buf_end || *next != '=')
|
||||
goto out;
|
||||
key_len = next - buf;
|
||||
|
||||
/* skip the '=', value must follow */
|
||||
if (++next > buf_end)
|
||||
goto out;
|
||||
|
||||
buf = next;
|
||||
next = action_arg_word_end(buf, buf_end, ' ');
|
||||
if (!next)
|
||||
goto out;
|
||||
|
||||
if (add_uevent_var(env, "SYNTH_ARG_%.*s=%.*s",
|
||||
key_len, key, (int) (next - buf), buf))
|
||||
goto out;
|
||||
}
|
||||
|
||||
r = 0;
|
||||
out:
|
||||
if (r)
|
||||
kfree(env);
|
||||
else
|
||||
*ret_env = env;
|
||||
return r;
|
||||
}
|
||||
|
||||
/**
|
||||
* kobject_synth_uevent - send synthetic uevent with arguments
|
||||
*
|
||||
* @kobj: struct kobject for which synthetic uevent is to be generated
|
||||
* @buf: buffer containing action type and action args, newline is ignored
|
||||
* @count: length of buffer
|
||||
*
|
||||
* Returns 0 if kobject_synthetic_uevent() is completed with success or the
|
||||
* corresponding error when it fails.
|
||||
*/
|
||||
int kobject_synth_uevent(struct kobject *kobj, const char *buf, size_t count)
|
||||
{
|
||||
char *no_uuid_envp[] = { "SYNTH_UUID=0", NULL };
|
||||
enum kobject_action action;
|
||||
const char *action_args;
|
||||
struct kobj_uevent_env *env;
|
||||
const char *msg = NULL, *devpath;
|
||||
int r;
|
||||
|
||||
r = kobject_action_type(buf, count, &action, &action_args);
|
||||
if (r) {
|
||||
msg = "unknown uevent action string\n";
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (!action_args) {
|
||||
r = kobject_uevent_env(kobj, action, no_uuid_envp);
|
||||
goto out;
|
||||
}
|
||||
|
||||
r = kobject_action_args(action_args,
|
||||
count - (action_args - buf), &env);
|
||||
if (r == -EINVAL) {
|
||||
msg = "incorrect uevent action arguments\n";
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (r)
|
||||
goto out;
|
||||
|
||||
r = kobject_uevent_env(kobj, action, env->envp);
|
||||
kfree(env);
|
||||
out:
|
||||
if (r) {
|
||||
devpath = kobject_get_path(kobj, GFP_KERNEL);
|
||||
printk(KERN_WARNING "synth uevent: %s: %s",
|
||||
devpath ?: "unknown device",
|
||||
msg ?: "failed to send uevent");
|
||||
kfree(devpath);
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_NET
|
||||
static int kobj_bcast_filter(struct sock *dsk, struct sk_buff *skb, void *data)
|
||||
{
|
||||
|
|
Loading…
Reference in New Issue