aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorThomas Renninger <trenn@suse.de>2012-01-25 18:09:14 -0500
committerGreg Kroah-Hartman <gregkh@suse.de>2012-01-26 19:49:08 -0500
commitfad12ac8c8c2591c7f4e61d19b6a9d76cd49fafa (patch)
treee2a77737265a193bbec7ecfd08f4989931a0ba89
parent78ff123b05fb15beb1ad670372eea0d299d0b8af (diff)
CPU: Introduce ARCH_HAS_CPU_AUTOPROBE and X86 parts
This patch is based on Andi Kleen's work: Implement autoprobing/loading of modules serving CPU specific features (x86cpu autoloading). And Kay Siever's work to get rid of sysdev cpu structures and making use of struct device instead. Before, the cpuid driver had to be loaded to get the x86cpu autoloading feature. With this patch autoloading works through the /sys/devices/system/cpu object Cc: Kay Sievers <kay.sievers@vrfy.org> Cc: Dave Jones <davej@redhat.com> Cc: Jens Axboe <axboe@kernel.dk> Cc: Herbert Xu <herbert@gondor.apana.org.au> Cc: Huang Ying <ying.huang@intel.com> Cc: Len Brown <lenb@kernel.org> Acked-by: Andi Kleen <ak@linux.intel.com> Signed-off-by: Thomas Renninger <trenn@suse.de> Acked-by: H. Peter Anvin <hpa@zytor.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
-rw-r--r--arch/x86/Kconfig3
-rw-r--r--arch/x86/kernel/cpu/match.c44
-rw-r--r--arch/x86/kernel/cpuid.c59
-rw-r--r--drivers/base/cpu.c11
-rw-r--r--include/linux/cpu.h7
5 files changed, 66 insertions, 58 deletions
diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig
index 864cc6e6ac8..6baa1e66e1b 100644
--- a/arch/x86/Kconfig
+++ b/arch/x86/Kconfig
@@ -179,6 +179,9 @@ config ARCH_HAS_DEFAULT_IDLE
179config ARCH_HAS_CACHE_LINE_SIZE 179config ARCH_HAS_CACHE_LINE_SIZE
180 def_bool y 180 def_bool y
181 181
182config ARCH_HAS_CPU_AUTOPROBE
183 def_bool y
184
182config HAVE_SETUP_PER_CPU_AREA 185config HAVE_SETUP_PER_CPU_AREA
183 def_bool y 186 def_bool y
184 187
diff --git a/arch/x86/kernel/cpu/match.c b/arch/x86/kernel/cpu/match.c
index 7acc961422e..940e2d48307 100644
--- a/arch/x86/kernel/cpu/match.c
+++ b/arch/x86/kernel/cpu/match.c
@@ -2,6 +2,7 @@
2#include <asm/processor.h> 2#include <asm/processor.h>
3#include <linux/cpu.h> 3#include <linux/cpu.h>
4#include <linux/module.h> 4#include <linux/module.h>
5#include <linux/slab.h>
5 6
6/** 7/**
7 * x86_match_cpu - match current CPU again an array of x86_cpu_ids 8 * x86_match_cpu - match current CPU again an array of x86_cpu_ids
@@ -46,3 +47,46 @@ const struct x86_cpu_id *x86_match_cpu(const struct x86_cpu_id *match)
46 return NULL; 47 return NULL;
47} 48}
48EXPORT_SYMBOL(x86_match_cpu); 49EXPORT_SYMBOL(x86_match_cpu);
50
51ssize_t arch_print_cpu_modalias(struct device *dev,
52 struct device_attribute *attr,
53 char *bufptr)
54{
55 int size = PAGE_SIZE;
56 int i, n;
57 char *buf = bufptr;
58
59 n = snprintf(buf, size, "x86cpu:vendor:%04X:family:%04X:"
60 "model:%04X:feature:",
61 boot_cpu_data.x86_vendor,
62 boot_cpu_data.x86,
63 boot_cpu_data.x86_model);
64 size -= n;
65 buf += n;
66 size -= 2;
67 for (i = 0; i < NCAPINTS*32; i++) {
68 if (boot_cpu_has(i)) {
69 n = snprintf(buf, size, ",%04X", i);
70 if (n < 0) {
71 WARN(1, "x86 features overflow page\n");
72 break;
73 }
74 size -= n;
75 buf += n;
76 }
77 }
78 *buf++ = ',';
79 *buf++ = '\n';
80 return buf - bufptr;
81}
82
83int arch_cpu_uevent(struct device *dev, struct kobj_uevent_env *env)
84{
85 char *buf = kzalloc(PAGE_SIZE, GFP_KERNEL);
86 if (buf) {
87 arch_print_cpu_modalias(NULL, NULL, buf);
88 add_uevent_var(env, "MODALIAS=%s", buf);
89 kfree(buf);
90 }
91 return 0;
92}
diff --git a/arch/x86/kernel/cpuid.c b/arch/x86/kernel/cpuid.c
index 7c89880eefd..a524353d93f 100644
--- a/arch/x86/kernel/cpuid.c
+++ b/arch/x86/kernel/cpuid.c
@@ -40,7 +40,6 @@
40#include <linux/notifier.h> 40#include <linux/notifier.h>
41#include <linux/uaccess.h> 41#include <linux/uaccess.h>
42#include <linux/gfp.h> 42#include <linux/gfp.h>
43#include <linux/slab.h>
44 43
45#include <asm/processor.h> 44#include <asm/processor.h>
46#include <asm/msr.h> 45#include <asm/msr.h>
@@ -139,57 +138,13 @@ static const struct file_operations cpuid_fops = {
139 .open = cpuid_open, 138 .open = cpuid_open,
140}; 139};
141 140
142static ssize_t print_cpu_modalias(struct device *dev,
143 struct device_attribute *attr,
144 char *bufptr)
145{
146 int size = PAGE_SIZE;
147 int i, n;
148 char *buf = bufptr;
149
150 n = snprintf(buf, size, "x86cpu:vendor:%04X:family:"
151 "%04X:model:%04X:feature:",
152 boot_cpu_data.x86_vendor,
153 boot_cpu_data.x86,
154 boot_cpu_data.x86_model);
155 size -= n;
156 buf += n;
157 size -= 2;
158 for (i = 0; i < NCAPINTS*32; i++) {
159 if (boot_cpu_has(i)) {
160 n = snprintf(buf, size, ",%04X", i);
161 if (n < 0) {
162 WARN(1, "x86 features overflow page\n");
163 break;
164 }
165 size -= n;
166 buf += n;
167 }
168 }
169 *buf++ = ',';
170 *buf++ = '\n';
171 return buf - bufptr;
172}
173
174static DEVICE_ATTR(modalias, 0444, print_cpu_modalias, NULL);
175
176static __cpuinit int cpuid_device_create(int cpu) 141static __cpuinit int cpuid_device_create(int cpu)
177{ 142{
178 struct device *dev; 143 struct device *dev;
179 int err;
180 144
181 dev = device_create(cpuid_class, NULL, MKDEV(CPUID_MAJOR, cpu), NULL, 145 dev = device_create(cpuid_class, NULL, MKDEV(CPUID_MAJOR, cpu), NULL,
182 "cpu%d", cpu); 146 "cpu%d", cpu);
183 if (IS_ERR(dev)) 147 return IS_ERR(dev) ? PTR_ERR(dev) : 0;
184 return PTR_ERR(dev);
185
186 err = device_create_file(dev, &dev_attr_modalias);
187 if (err) {
188 /* keep device around on error. attribute is optional. */
189 err = 0;
190 }
191
192 return 0;
193} 148}
194 149
195static void cpuid_device_destroy(int cpu) 150static void cpuid_device_destroy(int cpu)
@@ -227,17 +182,6 @@ static char *cpuid_devnode(struct device *dev, umode_t *mode)
227 return kasprintf(GFP_KERNEL, "cpu/%u/cpuid", MINOR(dev->devt)); 182 return kasprintf(GFP_KERNEL, "cpu/%u/cpuid", MINOR(dev->devt));
228} 183}
229 184
230static int cpuid_dev_uevent(struct device *dev, struct kobj_uevent_env *env)
231{
232 char *buf = kzalloc(PAGE_SIZE, GFP_KERNEL);
233 if (buf) {
234 print_cpu_modalias(NULL, NULL, buf);
235 add_uevent_var(env, "MODALIAS=%s", buf);
236 kfree(buf);
237 }
238 return 0;
239}
240
241static int __init cpuid_init(void) 185static int __init cpuid_init(void)
242{ 186{
243 int i, err = 0; 187 int i, err = 0;
@@ -256,7 +200,6 @@ static int __init cpuid_init(void)
256 goto out_chrdev; 200 goto out_chrdev;
257 } 201 }
258 cpuid_class->devnode = cpuid_devnode; 202 cpuid_class->devnode = cpuid_devnode;
259 cpuid_class->dev_uevent = cpuid_dev_uevent;
260 for_each_online_cpu(i) { 203 for_each_online_cpu(i) {
261 err = cpuid_device_create(i); 204 err = cpuid_device_create(i);
262 if (err != 0) 205 if (err != 0)
diff --git a/drivers/base/cpu.c b/drivers/base/cpu.c
index db87e78d745..2a0c670c281 100644
--- a/drivers/base/cpu.c
+++ b/drivers/base/cpu.c
@@ -11,6 +11,7 @@
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#include <linux/gfp.h>
14#include <linux/slab.h>
14#include <linux/percpu.h> 15#include <linux/percpu.h>
15 16
16#include "base.h" 17#include "base.h"
@@ -223,6 +224,9 @@ int __cpuinit register_cpu(struct cpu *cpu, int num)
223 cpu->node_id = cpu_to_node(num); 224 cpu->node_id = cpu_to_node(num);
224 cpu->dev.id = num; 225 cpu->dev.id = num;
225 cpu->dev.bus = &cpu_subsys; 226 cpu->dev.bus = &cpu_subsys;
227#ifdef CONFIG_ARCH_HAS_CPU_AUTOPROBE
228 cpu->dev.bus->uevent = arch_cpu_uevent;
229#endif
226 error = device_register(&cpu->dev); 230 error = device_register(&cpu->dev);
227 if (!error && cpu->hotpluggable) 231 if (!error && cpu->hotpluggable)
228 register_cpu_control(cpu); 232 register_cpu_control(cpu);
@@ -247,6 +251,10 @@ struct device *get_cpu_device(unsigned cpu)
247} 251}
248EXPORT_SYMBOL_GPL(get_cpu_device); 252EXPORT_SYMBOL_GPL(get_cpu_device);
249 253
254#ifdef CONFIG_ARCH_HAS_CPU_AUTOPROBE
255static DEVICE_ATTR(modalias, 0444, arch_print_cpu_modalias, NULL);
256#endif
257
250static struct attribute *cpu_root_attrs[] = { 258static struct attribute *cpu_root_attrs[] = {
251#ifdef CONFIG_ARCH_CPU_PROBE_RELEASE 259#ifdef CONFIG_ARCH_CPU_PROBE_RELEASE
252 &dev_attr_probe.attr, 260 &dev_attr_probe.attr,
@@ -257,6 +265,9 @@ static struct attribute *cpu_root_attrs[] = {
257 &cpu_attrs[2].attr.attr, 265 &cpu_attrs[2].attr.attr,
258 &dev_attr_kernel_max.attr, 266 &dev_attr_kernel_max.attr,
259 &dev_attr_offline.attr, 267 &dev_attr_offline.attr,
268#ifdef CONFIG_ARCH_HAS_CPU_AUTOPROBE
269 &dev_attr_modalias.attr,
270#endif
260 NULL 271 NULL
261}; 272};
262 273
diff --git a/include/linux/cpu.h b/include/linux/cpu.h
index 1f6587590a1..6e53b4823d7 100644
--- a/include/linux/cpu.h
+++ b/include/linux/cpu.h
@@ -44,6 +44,13 @@ extern ssize_t arch_cpu_release(const char *, size_t);
44#endif 44#endif
45struct notifier_block; 45struct notifier_block;
46 46
47#ifdef CONFIG_ARCH_HAS_CPU_AUTOPROBE
48extern int arch_cpu_uevent(struct device *dev, struct kobj_uevent_env *env);
49extern ssize_t arch_print_cpu_modalias(struct device *dev,
50 struct device_attribute *attr,
51 char *bufptr);
52#endif
53
47/* 54/*
48 * CPU notifier priorities. 55 * CPU notifier priorities.
49 */ 56 */