aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/base/cpu.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/base/cpu.c')
-rw-r--r--drivers/base/cpu.c106
1 files changed, 65 insertions, 41 deletions
diff --git a/drivers/base/cpu.c b/drivers/base/cpu.c
index e62a4ccea54d..f35719aab3c1 100644
--- a/drivers/base/cpu.c
+++ b/drivers/base/cpu.c
@@ -10,11 +10,15 @@
10#include <linux/topology.h> 10#include <linux/topology.h>
11#include <linux/device.h> 11#include <linux/device.h>
12#include <linux/node.h> 12#include <linux/node.h>
13#include <linux/gfp.h>
13 14
14#include "base.h" 15#include "base.h"
15 16
17static struct sysdev_class_attribute *cpu_sysdev_class_attrs[];
18
16struct sysdev_class cpu_sysdev_class = { 19struct sysdev_class cpu_sysdev_class = {
17 .name = "cpu", 20 .name = "cpu",
21 .attrs = cpu_sysdev_class_attrs,
18}; 22};
19EXPORT_SYMBOL(cpu_sysdev_class); 23EXPORT_SYMBOL(cpu_sysdev_class);
20 24
@@ -35,6 +39,7 @@ static ssize_t __ref store_online(struct sys_device *dev, struct sysdev_attribut
35 struct cpu *cpu = container_of(dev, struct cpu, sysdev); 39 struct cpu *cpu = container_of(dev, struct cpu, sysdev);
36 ssize_t ret; 40 ssize_t ret;
37 41
42 cpu_hotplug_driver_lock();
38 switch (buf[0]) { 43 switch (buf[0]) {
39 case '0': 44 case '0':
40 ret = cpu_down(cpu->sysdev.id); 45 ret = cpu_down(cpu->sysdev.id);
@@ -49,6 +54,7 @@ static ssize_t __ref store_online(struct sys_device *dev, struct sysdev_attribut
49 default: 54 default:
50 ret = -EINVAL; 55 ret = -EINVAL;
51 } 56 }
57 cpu_hotplug_driver_unlock();
52 58
53 if (ret >= 0) 59 if (ret >= 0)
54 ret = count; 60 ret = count;
@@ -72,6 +78,28 @@ void unregister_cpu(struct cpu *cpu)
72 per_cpu(cpu_sys_devices, logical_cpu) = NULL; 78 per_cpu(cpu_sys_devices, logical_cpu) = NULL;
73 return; 79 return;
74} 80}
81
82#ifdef CONFIG_ARCH_CPU_PROBE_RELEASE
83static ssize_t cpu_probe_store(struct sysdev_class *class,
84 struct sysdev_class_attribute *attr,
85 const char *buf,
86 size_t count)
87{
88 return arch_cpu_probe(buf, count);
89}
90
91static ssize_t cpu_release_store(struct sysdev_class *class,
92 struct sysdev_class_attribute *attr,
93 const char *buf,
94 size_t count)
95{
96 return arch_cpu_release(buf, count);
97}
98
99static SYSDEV_CLASS_ATTR(probe, S_IWUSR, NULL, cpu_probe_store);
100static SYSDEV_CLASS_ATTR(release, S_IWUSR, NULL, cpu_release_store);
101#endif /* CONFIG_ARCH_CPU_PROBE_RELEASE */
102
75#else /* ... !CONFIG_HOTPLUG_CPU */ 103#else /* ... !CONFIG_HOTPLUG_CPU */
76static inline void register_cpu_control(struct cpu *cpu) 104static inline void register_cpu_control(struct cpu *cpu)
77{ 105{
@@ -97,7 +125,7 @@ static ssize_t show_crash_notes(struct sys_device *dev, struct sysdev_attribute
97 * boot up and this data does not change there after. Hence this 125 * boot up and this data does not change there after. Hence this
98 * operation should be safe. No locking required. 126 * operation should be safe. No locking required.
99 */ 127 */
100 addr = __pa(per_cpu_ptr(crash_notes, cpunum)); 128 addr = per_cpu_ptr_to_phys(per_cpu_ptr(crash_notes, cpunum));
101 rc = sprintf(buf, "%Lx\n", addr); 129 rc = sprintf(buf, "%Lx\n", addr);
102 return rc; 130 return rc;
103} 131}
@@ -107,31 +135,39 @@ static SYSDEV_ATTR(crash_notes, 0400, show_crash_notes, NULL);
107/* 135/*
108 * Print cpu online, possible, present, and system maps 136 * Print cpu online, possible, present, and system maps
109 */ 137 */
110static ssize_t print_cpus_map(char *buf, const struct cpumask *map) 138
139struct cpu_attr {
140 struct sysdev_class_attribute attr;
141 const struct cpumask *const * const map;
142};
143
144static ssize_t show_cpus_attr(struct sysdev_class *class,
145 struct sysdev_class_attribute *attr,
146 char *buf)
111{ 147{
112 int n = cpulist_scnprintf(buf, PAGE_SIZE-2, map); 148 struct cpu_attr *ca = container_of(attr, struct cpu_attr, attr);
149 int n = cpulist_scnprintf(buf, PAGE_SIZE-2, *(ca->map));
113 150
114 buf[n++] = '\n'; 151 buf[n++] = '\n';
115 buf[n] = '\0'; 152 buf[n] = '\0';
116 return n; 153 return n;
117} 154}
118 155
119#define print_cpus_func(type) \ 156#define _CPU_ATTR(name, map) \
120static ssize_t print_cpus_##type(struct sysdev_class *class, char *buf) \ 157 { _SYSDEV_CLASS_ATTR(name, 0444, show_cpus_attr, NULL), map }
121{ \
122 return print_cpus_map(buf, cpu_##type##_mask); \
123} \
124static struct sysdev_class_attribute attr_##type##_map = \
125 _SYSDEV_CLASS_ATTR(type, 0444, print_cpus_##type, NULL)
126 158
127print_cpus_func(online); 159/* Keep in sync with cpu_sysdev_class_attrs */
128print_cpus_func(possible); 160static struct cpu_attr cpu_attrs[] = {
129print_cpus_func(present); 161 _CPU_ATTR(online, &cpu_online_mask),
162 _CPU_ATTR(possible, &cpu_possible_mask),
163 _CPU_ATTR(present, &cpu_present_mask),
164};
130 165
131/* 166/*
132 * Print values for NR_CPUS and offlined cpus 167 * Print values for NR_CPUS and offlined cpus
133 */ 168 */
134static ssize_t print_cpus_kernel_max(struct sysdev_class *class, char *buf) 169static ssize_t print_cpus_kernel_max(struct sysdev_class *class,
170 struct sysdev_class_attribute *attr, char *buf)
135{ 171{
136 int n = snprintf(buf, PAGE_SIZE-2, "%d\n", NR_CPUS - 1); 172 int n = snprintf(buf, PAGE_SIZE-2, "%d\n", NR_CPUS - 1);
137 return n; 173 return n;
@@ -141,7 +177,8 @@ static SYSDEV_CLASS_ATTR(kernel_max, 0444, print_cpus_kernel_max, NULL);
141/* arch-optional setting to enable display of offline cpus >= nr_cpu_ids */ 177/* arch-optional setting to enable display of offline cpus >= nr_cpu_ids */
142unsigned int total_cpus; 178unsigned int total_cpus;
143 179
144static ssize_t print_cpus_offline(struct sysdev_class *class, char *buf) 180static ssize_t print_cpus_offline(struct sysdev_class *class,
181 struct sysdev_class_attribute *attr, char *buf)
145{ 182{
146 int n = 0, len = PAGE_SIZE-2; 183 int n = 0, len = PAGE_SIZE-2;
147 cpumask_var_t offline; 184 cpumask_var_t offline;
@@ -170,29 +207,6 @@ static ssize_t print_cpus_offline(struct sysdev_class *class, char *buf)
170} 207}
171static SYSDEV_CLASS_ATTR(offline, 0444, print_cpus_offline, NULL); 208static SYSDEV_CLASS_ATTR(offline, 0444, print_cpus_offline, NULL);
172 209
173static struct sysdev_class_attribute *cpu_state_attr[] = {
174 &attr_online_map,
175 &attr_possible_map,
176 &attr_present_map,
177 &attr_kernel_max,
178 &attr_offline,
179};
180
181static int cpu_states_init(void)
182{
183 int i;
184 int err = 0;
185
186 for (i = 0; i < ARRAY_SIZE(cpu_state_attr); i++) {
187 int ret;
188 ret = sysdev_class_create_file(&cpu_sysdev_class,
189 cpu_state_attr[i]);
190 if (!err)
191 err = ret;
192 }
193 return err;
194}
195
196/* 210/*
197 * register_cpu - Setup a sysfs device for a CPU. 211 * register_cpu - Setup a sysfs device for a CPU.
198 * @cpu - cpu->hotpluggable field set to 1 will generate a control file in 212 * @cpu - cpu->hotpluggable field set to 1 will generate a control file in
@@ -238,9 +252,6 @@ int __init cpu_dev_init(void)
238 int err; 252 int err;
239 253
240 err = sysdev_class_register(&cpu_sysdev_class); 254 err = sysdev_class_register(&cpu_sysdev_class);
241 if (!err)
242 err = cpu_states_init();
243
244#if defined(CONFIG_SCHED_MC) || defined(CONFIG_SCHED_SMT) 255#if defined(CONFIG_SCHED_MC) || defined(CONFIG_SCHED_SMT)
245 if (!err) 256 if (!err)
246 err = sched_create_sysfs_power_savings_entries(&cpu_sysdev_class); 257 err = sched_create_sysfs_power_savings_entries(&cpu_sysdev_class);
@@ -248,3 +259,16 @@ int __init cpu_dev_init(void)
248 259
249 return err; 260 return err;
250} 261}
262
263static struct sysdev_class_attribute *cpu_sysdev_class_attrs[] = {
264#ifdef CONFIG_ARCH_CPU_PROBE_RELEASE
265 &attr_probe,
266 &attr_release,
267#endif
268 &cpu_attrs[0].attr,
269 &cpu_attrs[1].attr,
270 &cpu_attrs[2].attr,
271 &attr_kernel_max,
272 &attr_offline,
273 NULL
274};