diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2017-07-03 20:27:48 -0700 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2017-07-03 20:27:48 -0700 |
commit | 974668417b74ec5f68df2411f53b3d3812565059 (patch) | |
tree | c76be88bc72bf6b0abe8843f418e4e2518053947 | |
parent | 9a715cd54347948e74f1a597da22884af287727d (diff) | |
parent | d565ed38d045793b76f022565a50793a3535bdbd (diff) | |
download | talos-obmc-linux-974668417b74ec5f68df2411f53b3d3812565059.tar.gz talos-obmc-linux-974668417b74ec5f68df2411f53b3d3812565059.zip |
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
...
64 files changed, 1116 insertions, 1040 deletions
diff --git a/Documentation/ABI/testing/sysfs-uevent b/Documentation/ABI/testing/sysfs-uevent new file mode 100644 index 000000000000..aa39f8d7bcdf --- /dev/null +++ b/Documentation/ABI/testing/sysfs-uevent @@ -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 diff --git a/Documentation/devicetree/bindings/arm/cpus.txt b/Documentation/devicetree/bindings/arm/cpus.txt index 1030f5f50207..2713aadb7411 100644 --- a/Documentation/devicetree/bindings/arm/cpus.txt +++ b/Documentation/devicetree/bindings/arm/cpus.txt @@ -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 diff --git a/Documentation/driver-api/firmware/request_firmware.rst b/Documentation/driver-api/firmware/request_firmware.rst index cc0aea880824..1c2c4967cd43 100644 --- a/Documentation/driver-api/firmware/request_firmware.rst +++ b/Documentation/driver-api/firmware/request_firmware.rst @@ -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 ======================================== diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index 6281c3e5a673..43f45d3b40e8 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig @@ -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 diff --git a/arch/arm/kernel/topology.c b/arch/arm/kernel/topology.c index f8a3ab82e77f..bf949a763dbe 100644 --- a/arch/arm/kernel/topology.c +++ b/arch/arm/kernel/topology.c @@ -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 diff --git a/arch/arm/mach-rpc/ecard.c b/arch/arm/mach-rpc/ecard.c index 6b279d037774..bdb5ec1cf560 100644 --- a/arch/arm/mach-rpc/ecard.c +++ b/arch/arm/mach-rpc/ecard.c @@ -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 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 DEVICE_ATTR_RO(type); + +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, diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig index 95c7ed392003..300146dc8433 100644 --- a/arch/arm64/Kconfig +++ b/arch/arm64/Kconfig @@ -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 diff --git a/arch/arm64/kernel/topology.c b/arch/arm64/kernel/topology.c index 08243533e5ee..79244c75eaec 100644 --- a/arch/arm64/kernel/topology.c +++ b/arch/arm64/kernel/topology.c @@ -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 diff --git a/arch/mips/sgi-ip22/ip22-gio.c b/arch/mips/sgi-ip22/ip22-gio.c index cdf187600010..b225033aade6 100644 --- a/arch/mips/sgi-ip22/ip22-gio.c +++ b/arch/mips/sgi-ip22/ip22-gio.c @@ -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, diff --git a/arch/parisc/kernel/drivers.c b/arch/parisc/kernel/drivers.c index fa78419100c8..d8f77358e2ba 100644 --- a/arch/parisc/kernel/drivers.c +++ b/arch/parisc/kernel/drivers.c @@ -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, }; diff --git a/arch/powerpc/platforms/ps3/system-bus.c b/arch/powerpc/platforms/ps3/system-bus.c index 2d2e5f80a3d3..5cc35d6b94b6 100644 --- a/arch/powerpc/platforms/ps3/system-bus.c +++ b/arch/powerpc/platforms/ps3/system-bus.c @@ -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) diff --git a/arch/powerpc/platforms/pseries/dlpar.c b/arch/powerpc/platforms/pseries/dlpar.c index bda18d8e1674..39187696ee74 100644 --- a/arch/powerpc/platforms/pseries/dlpar.c +++ b/arch/powerpc/platforms/pseries/dlpar.c @@ -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) { diff --git a/arch/powerpc/platforms/pseries/ibmebus.c b/arch/powerpc/platforms/pseries/ibmebus.c index b363e439ddb9..52146b1356d2 100644 --- a/arch/powerpc/platforms/pseries/ibmebus.c +++ b/arch/powerpc/platforms/pseries/ibmebus.c @@ -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); diff --git a/arch/powerpc/platforms/pseries/mobility.c b/arch/powerpc/platforms/pseries/mobility.c index 5a0c7ba429ce..2da4851eff99 100644 --- a/arch/powerpc/platforms/pseries/mobility.c +++ b/arch/powerpc/platforms/pseries/mobility.c @@ -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) diff --git a/arch/powerpc/platforms/pseries/vio.c b/arch/powerpc/platforms/pseries/vio.c index 28b09fd797ec..117beb9e8786 100644 --- a/arch/powerpc/platforms/pseries/vio.c +++ b/arch/powerpc/platforms/pseries/vio.c @@ -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, diff --git a/arch/sparc/kernel/vio.c b/arch/sparc/kernel/vio.c index 075d38980dee..7dd9b57f3a61 100644 --- a/arch/sparc/kernel/vio.c +++ b/arch/sparc/kernel/vio.c @@ -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, diff --git a/drivers/amba/bus.c b/drivers/amba/bus.c index a56fa2a1e9aa..e0f74ddc22b7 100644 --- a/drivers/amba/bus.c +++ b/drivers/amba/bus.c @@ -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, diff --git a/drivers/base/Kconfig b/drivers/base/Kconfig index d718ae4b907a..f046d21de57d 100644 --- a/drivers/base/Kconfig +++ b/drivers/base/Kconfig @@ -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 diff --git a/drivers/base/Makefile b/drivers/base/Makefile index f2816f6ff76a..397e5c344e6a 100644 --- a/drivers/base/Makefile +++ b/drivers/base/Makefile @@ -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/ diff --git a/drivers/base/arch_topology.c b/drivers/base/arch_topology.c new file mode 100644 index 000000000000..d1c33a85059e --- /dev/null +++ b/drivers/base/arch_topology.c @@ -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 diff --git a/drivers/base/bus.c b/drivers/base/bus.c index 6470eb8088f4..e162c9a789ba 100644 --- a/drivers/base/bus.c +++ b/drivers/base/bus.c @@ -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); diff --git a/drivers/base/class.c b/drivers/base/class.c index a2b2896693d6..52eb8e644acd 100644 --- a/drivers/base/class.c +++ b/drivers/base/class.c @@ -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); } diff --git a/drivers/base/core.c b/drivers/base/core.c index c3064ff09af5..8dde934f8d15 100644 --- a/drivers/base/core.c +++ b/drivers/base/core.c @@ -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); diff --git a/drivers/base/dma-mapping.c b/drivers/base/dma-mapping.c index f3deb6af42ad..9dbef4d1baa4 100644 --- a/drivers/base/dma-mapping.c +++ b/drivers/base/dma-mapping.c @@ -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; } /* diff --git a/drivers/base/firmware_class.c b/drivers/base/firmware_class.c index ac350c518e0c..b9f907eedbf7 100644 --- a/drivers/base/firmware_class.c +++ b/drivers/base/firmware_class.c @@ -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,23 +632,19 @@ 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) { + struct firmware_buf *buf; + struct firmware_buf *next; + mutex_lock(&fw_lock); - while (!list_empty(&pending_fw_head)) - __fw_load_abort(list_first_entry(&pending_fw_head, - struct firmware_buf, - pending_list)); + 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); - return NOTIFY_DONE; } -static struct notifier_block fw_shutdown_nb = { - .notifier_call = fw_shutdown_notify, -}; - 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 } diff --git a/drivers/base/platform.c b/drivers/base/platform.c index a102152301c8..97332d094fe2 100644 --- a/drivers/base/platform.c +++ b/drivers/base/platform.c @@ -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); diff --git a/drivers/block/pktcdvd.c b/drivers/block/pktcdvd.c index 467beca397a2..6b8b097abbb9 100644 --- a/drivers/block/pktcdvd.c +++ b/drivers/block/pktcdvd.c @@ -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); diff --git a/drivers/block/zram/zram_drv.c b/drivers/block/zram/zram_drv.c index debee952dcc1..558e245fab0c 100644 --- a/drivers/block/zram/zram_drv.c +++ b/drivers/block/zram/zram_drv.c @@ -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) diff --git a/drivers/gpio/gpiolib-sysfs.c b/drivers/gpio/gpiolib-sysfs.c index 4b44dd97c07f..16fe9742597b 100644 --- a/drivers/gpio/gpiolib-sysfs.c +++ b/drivers/gpio/gpiolib-sysfs.c @@ -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, }; diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c index 6e040692f1d8..2241e7913c0d 100644 --- a/drivers/hid/hid-core.c +++ b/drivers/hid/hid-core.c @@ -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); } diff --git a/drivers/hid/intel-ish-hid/ishtp/bus.c b/drivers/hid/intel-ish-hid/ishtp/bus.c index 5f382fedc2ab..f272cdd9bd55 100644 --- a/drivers/hid/intel-ish-hid/ishtp/bus.c +++ b/drivers/hid/intel-ish-hid/ishtp/bus.c @@ -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, diff --git a/drivers/hwtracing/intel_th/core.c b/drivers/hwtracing/intel_th/core.c index 7563eceeaaea..8da567abc0ce 100644 --- a/drivers/hwtracing/intel_th/core.c +++ b/drivers/hwtracing/intel_th/core.c @@ -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, diff --git a/drivers/infiniband/hw/nes/nes.c b/drivers/infiniband/hw/nes/nes.c index 5b9601014f0c..a30aa6527f7e 100644 --- a/drivers/infiniband/hw/nes/nes.c +++ b/drivers/infiniband/hw/nes/nes.c @@ -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) { diff --git a/drivers/macintosh/macio_asic.c b/drivers/macintosh/macio_asic.c index f757cef293f8..62f541f968f6 100644 --- a/drivers/macintosh/macio_asic.c +++ b/drivers/macintosh/macio_asic.c @@ -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) diff --git a/drivers/macintosh/macio_sysfs.c b/drivers/macintosh/macio_sysfs.c index 0b1f9c76c68d..2445274f7e4b 100644 --- a/drivers/macintosh/macio_sysfs.c +++ b/drivers/macintosh/macio_sysfs.c @@ -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, }; diff --git a/drivers/mtd/ubi/build.c b/drivers/mtd/ubi/build.c index 93e5d251a9e4..d854521962ef 100644 --- a/drivers/mtd/ubi/build.c +++ b/drivers/mtd/ubi/build.c @@ -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, diff --git a/drivers/net/caif/caif_spi.c b/drivers/net/caif/caif_spi.c index fc21afe852b9..cb0dcc99fb4f 100644 --- a/drivers/net/caif/caif_spi.c +++ b/drivers/net/caif/caif_spi.c @@ -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) { diff --git a/drivers/net/ethernet/ibm/ehea/ehea_main.c b/drivers/net/ethernet/ibm/ehea/ehea_main.c index 1e53d7a82675..b9d310f20bcc 100644 --- a/drivers/net/ethernet/ibm/ehea/ehea_main.c +++ b/drivers/net/ethernet/ibm/ehea/ehea_main.c @@ -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) { diff --git a/drivers/net/wireless/intel/ipw2x00/ipw2100.c b/drivers/net/wireless/intel/ipw2x00/ipw2100.c index f922859acf40..aaaca4d08e2b 100644 --- a/drivers/net/wireless/intel/ipw2x00/ipw2100.c +++ b/drivers/net/wireless/intel/ipw2x00/ipw2100.c @@ -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, diff --git a/drivers/net/wireless/intel/ipw2x00/ipw2200.c b/drivers/net/wireless/intel/ipw2x00/ipw2200.c index bbc579b647b6..5b79e2ec3a16 100644 --- a/drivers/net/wireless/intel/ipw2x00/ipw2200.c +++ b/drivers/net/wireless/intel/ipw2x00/ipw2200.c @@ -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) { diff --git a/drivers/pci/pci-driver.c b/drivers/pci/pci-driver.c index fe6be6382505..00e10bf7f6a2 100644 --- a/drivers/pci/pci-driver.c +++ b/drivers/pci/pci-driver.c @@ -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, diff --git a/drivers/pcmcia/ds.c b/drivers/pcmcia/ds.c index 69b5e811ea2b..a9258f641cee 100644 --- a/drivers/pcmcia/ds.c +++ b/drivers/pcmcia/ds.c @@ -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) diff --git a/drivers/platform/x86/thinkpad_acpi.c b/drivers/platform/x86/thinkpad_acpi.c index 7b6cb0c69b02..f6861b551178 100644 --- a/drivers/platform/x86/thinkpad_acpi.c +++ b/drivers/platform/x86/thinkpad_acpi.c @@ -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[] = { diff --git a/drivers/rpmsg/rpmsg_core.c b/drivers/rpmsg/rpmsg_core.c index 600f5f9f7431..ad3d2a9df287 100644 --- a/drivers/rpmsg/rpmsg_core.c +++ b/drivers/rpmsg/rpmsg_core.c @@ -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 struct device_attribute rpmsg_dev_attrs[] = { - __ATTR_RO(name), - __ATTR_RO(modalias), - __ATTR_RO(dst), - __ATTR_RO(src), - __ATTR_RO(announce), - __ATTR_NULL +static DEVICE_ATTR_RO(modalias); + +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, diff --git a/drivers/s390/char/sclp.c b/drivers/s390/char/sclp.c index 9c471ea1b99c..6111c1fa2d1e 100644 --- a/drivers/s390/char/sclp.c +++ b/drivers/s390/char/sclp.c @@ -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, diff --git a/drivers/s390/char/vmlogrdr.c b/drivers/s390/char/vmlogrdr.c index 57974a1e0e03..b19020b9efff 100644 --- a/drivers/s390/char/vmlogrdr.c +++ b/drivers/s390/char/vmlogrdr.c @@ -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, diff --git a/drivers/s390/net/ctcm_main.c b/drivers/s390/net/ctcm_main.c index 198842ce6876..b1fa38a6733f 100644 --- a/drivers/s390/net/ctcm_main.c +++ b/drivers/s390/net/ctcm_main.c @@ -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, diff --git a/drivers/s390/net/lcs.c b/drivers/s390/net/lcs.c index 211b31d9f157..589dba69db17 100644 --- a/drivers/s390/net/lcs.c +++ b/drivers/s390/net/lcs.c @@ -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, diff --git a/drivers/s390/net/netiucv.c b/drivers/s390/net/netiucv.c index fa732bd86729..f1f6eb112531 100644 --- a/drivers/s390/net/netiucv.c +++ b/drivers/s390/net/netiucv.c @@ -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, diff --git a/drivers/s390/net/qeth_core_main.c b/drivers/s390/net/qeth_core_main.c index fc6d85f2b38d..462b82eb17a9 100644 --- a/drivers/s390/net/qeth_core_main.c +++ b/drivers/s390/net/qeth_core_main.c @@ -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, diff --git a/drivers/scsi/ibmvscsi_tgt/ibmvscsi_tgt.c b/drivers/scsi/ibmvscsi_tgt/ibmvscsi_tgt.c index abf6026645dd..659ab483d716 100644 --- a/drivers/scsi/ibmvscsi_tgt/ibmvscsi_tgt.c +++ b/drivers/scsi/ibmvscsi_tgt/ibmvscsi_tgt.c @@ -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, }; diff --git a/drivers/sh/superhyway/superhyway-sysfs.c b/drivers/sh/superhyway/superhyway-sysfs.c index 55434330867b..774f31b564f8 100644 --- a/drivers/sh/superhyway/superhyway-sysfs.c +++ b/drivers/sh/superhyway/superhyway-sysfs.c @@ -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, +}; diff --git a/drivers/sh/superhyway/superhyway.c b/drivers/sh/superhyway/superhyway.c index bb1fb7712134..348836b90605 100644 --- a/drivers/sh/superhyway/superhyway.c +++ b/drivers/sh/superhyway/superhyway.c @@ -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, diff --git a/drivers/tty/hvc/hvcs.c b/drivers/tty/hvc/hvcs.c index 423e28ec27fb..79cc5beea2da 100644 --- a/drivers/tty/hvc/hvcs.c +++ b/drivers/tty/hvc/hvcs.c @@ -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) { diff --git a/drivers/tty/serdev/core.c b/drivers/tty/serdev/core.c index f71b47334149..ae1aaa0075d1 100644 --- a/drivers/tty/serdev/core.c +++ b/drivers/tty/serdev/core.c @@ -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, }; /** diff --git a/drivers/usb/usbip/stub_main.c b/drivers/usb/usbip/stub_main.c index af10f7b131a4..660180a5d5c4 100644 --- a/drivers/usb/usbip/stub_main.c +++ b/drivers/usb/usbip/stub_main.c @@ -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) diff --git a/drivers/uwb/driver.c b/drivers/uwb/driver.c index 776bcb3c2140..ff2d4240b24a 100644 --- a/drivers/uwb/driver.c +++ b/drivers/uwb/driver.c @@ -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, }; diff --git a/include/linux/arch_topology.h b/include/linux/arch_topology.h new file mode 100644 index 000000000000..9af3c174c03a --- /dev/null +++ b/include/linux/arch_topology.h @@ -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_ */ diff --git a/include/linux/device.h b/include/linux/device.h index 60ab00b13095..6baa1238f158 100644 --- a/include/linux/device.h +++ b/include/linux/device.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) \ diff --git a/include/linux/kobject.h b/include/linux/kobject.h index ca85cb80e99a..eeab34b0f589 100644 --- a/include/linux/kobject.h +++ b/include/linux/kobject.h @@ -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_ */ diff --git a/include/linux/superhyway.h b/include/linux/superhyway.h index 17ea468fa362..8d3376775813 100644 --- a/include/linux/superhyway.h +++ b/include/linux/superhyway.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 */ diff --git a/include/linux/sysfs.h b/include/linux/sysfs.h index c6f0f0d0e17e..aa02c328dff5 100644 --- a/include/linux/sysfs.h +++ b/include/linux/sysfs.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); } diff --git a/kernel/module.c b/kernel/module.c index 4a3665f8f837..d7eb41d772c4 100644 --- a/kernel/module.c +++ b/kernel/module.c @@ -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; } diff --git a/lib/kobject_uevent.c b/lib/kobject_uevent.c index 9a2b811966eb..719c155fce20 100644 --- a/lib/kobject_uevent.c +++ b/lib/kobject_uevent.c @@ -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) { |