diff options
Diffstat (limited to 'drivers/base/cpu.c')
-rw-r--r-- | drivers/base/cpu.c | 106 |
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 | ||
17 | static struct sysdev_class_attribute *cpu_sysdev_class_attrs[]; | ||
18 | |||
16 | struct sysdev_class cpu_sysdev_class = { | 19 | struct sysdev_class cpu_sysdev_class = { |
17 | .name = "cpu", | 20 | .name = "cpu", |
21 | .attrs = cpu_sysdev_class_attrs, | ||
18 | }; | 22 | }; |
19 | EXPORT_SYMBOL(cpu_sysdev_class); | 23 | EXPORT_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 | ||
83 | static 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 | |||
91 | static 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 | |||
99 | static SYSDEV_CLASS_ATTR(probe, S_IWUSR, NULL, cpu_probe_store); | ||
100 | static 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 */ |
76 | static inline void register_cpu_control(struct cpu *cpu) | 104 | static 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 | */ |
110 | static ssize_t print_cpus_map(char *buf, const struct cpumask *map) | 138 | |
139 | struct cpu_attr { | ||
140 | struct sysdev_class_attribute attr; | ||
141 | const struct cpumask *const * const map; | ||
142 | }; | ||
143 | |||
144 | static 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) \ |
120 | static 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 | } \ | ||
124 | static struct sysdev_class_attribute attr_##type##_map = \ | ||
125 | _SYSDEV_CLASS_ATTR(type, 0444, print_cpus_##type, NULL) | ||
126 | 158 | ||
127 | print_cpus_func(online); | 159 | /* Keep in sync with cpu_sysdev_class_attrs */ |
128 | print_cpus_func(possible); | 160 | static struct cpu_attr cpu_attrs[] = { |
129 | print_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 | */ |
134 | static ssize_t print_cpus_kernel_max(struct sysdev_class *class, char *buf) | 169 | static 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 */ |
142 | unsigned int total_cpus; | 178 | unsigned int total_cpus; |
143 | 179 | ||
144 | static ssize_t print_cpus_offline(struct sysdev_class *class, char *buf) | 180 | static 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 | } |
171 | static SYSDEV_CLASS_ATTR(offline, 0444, print_cpus_offline, NULL); | 208 | static SYSDEV_CLASS_ATTR(offline, 0444, print_cpus_offline, NULL); |
172 | 209 | ||
173 | static 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 | |||
181 | static 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 | |||
263 | static 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 | }; | ||