diff options
| -rw-r--r-- | arch/x86/include/asm/cpu_device_id.h | 13 | ||||
| -rw-r--r-- | arch/x86/kernel/cpu/Makefile | 1 | ||||
| -rw-r--r-- | arch/x86/kernel/cpu/match.c | 48 | ||||
| -rw-r--r-- | arch/x86/kernel/cpuid.c | 59 | ||||
| -rw-r--r-- | include/linux/mod_devicetable.h | 21 | ||||
| -rw-r--r-- | scripts/mod/file2alias.c | 24 |
6 files changed, 165 insertions, 1 deletions
diff --git a/arch/x86/include/asm/cpu_device_id.h b/arch/x86/include/asm/cpu_device_id.h new file mode 100644 index 000000000000..ff501e511d91 --- /dev/null +++ b/arch/x86/include/asm/cpu_device_id.h | |||
| @@ -0,0 +1,13 @@ | |||
| 1 | #ifndef _CPU_DEVICE_ID | ||
| 2 | #define _CPU_DEVICE_ID 1 | ||
| 3 | |||
| 4 | /* | ||
| 5 | * Declare drivers belonging to specific x86 CPUs | ||
| 6 | * Similar in spirit to pci_device_id and related PCI functions | ||
| 7 | */ | ||
| 8 | |||
| 9 | #include <linux/mod_devicetable.h> | ||
| 10 | |||
| 11 | extern const struct x86_cpu_id *x86_match_cpu(const struct x86_cpu_id *match); | ||
| 12 | |||
| 13 | #endif | ||
diff --git a/arch/x86/kernel/cpu/Makefile b/arch/x86/kernel/cpu/Makefile index 25f24dccdcfa..6ab6aa2fdfdd 100644 --- a/arch/x86/kernel/cpu/Makefile +++ b/arch/x86/kernel/cpu/Makefile | |||
| @@ -16,6 +16,7 @@ obj-y := intel_cacheinfo.o scattered.o topology.o | |||
| 16 | obj-y += proc.o capflags.o powerflags.o common.o | 16 | obj-y += proc.o capflags.o powerflags.o common.o |
| 17 | obj-y += vmware.o hypervisor.o sched.o mshyperv.o | 17 | obj-y += vmware.o hypervisor.o sched.o mshyperv.o |
| 18 | obj-y += rdrand.o | 18 | obj-y += rdrand.o |
| 19 | obj-y += match.o | ||
| 19 | 20 | ||
| 20 | obj-$(CONFIG_X86_32) += bugs.o | 21 | obj-$(CONFIG_X86_32) += bugs.o |
| 21 | obj-$(CONFIG_X86_64) += bugs_64.o | 22 | obj-$(CONFIG_X86_64) += bugs_64.o |
diff --git a/arch/x86/kernel/cpu/match.c b/arch/x86/kernel/cpu/match.c new file mode 100644 index 000000000000..7acc961422e7 --- /dev/null +++ b/arch/x86/kernel/cpu/match.c | |||
| @@ -0,0 +1,48 @@ | |||
| 1 | #include <asm/cpu_device_id.h> | ||
| 2 | #include <asm/processor.h> | ||
| 3 | #include <linux/cpu.h> | ||
| 4 | #include <linux/module.h> | ||
| 5 | |||
| 6 | /** | ||
| 7 | * x86_match_cpu - match current CPU again an array of x86_cpu_ids | ||
| 8 | * @match: Pointer to array of x86_cpu_ids. Last entry terminated with | ||
| 9 | * {}. | ||
| 10 | * | ||
| 11 | * Return the entry if the current CPU matches the entries in the | ||
| 12 | * passed x86_cpu_id match table. Otherwise NULL. The match table | ||
| 13 | * contains vendor (X86_VENDOR_*), family, model and feature bits or | ||
| 14 | * respective wildcard entries. | ||
| 15 | * | ||
| 16 | * A typical table entry would be to match a specific CPU | ||
| 17 | * { X86_VENDOR_INTEL, 6, 0x12 } | ||
| 18 | * or to match a specific CPU feature | ||
| 19 | * { X86_FEATURE_MATCH(X86_FEATURE_FOOBAR) } | ||
| 20 | * | ||
| 21 | * Fields can be wildcarded with %X86_VENDOR_ANY, %X86_FAMILY_ANY, | ||
| 22 | * %X86_MODEL_ANY, %X86_FEATURE_ANY or 0 (except for vendor) | ||
| 23 | * | ||
| 24 | * Arrays used to match for this should also be declared using | ||
| 25 | * MODULE_DEVICE_TABLE(x86_cpu, ...) | ||
| 26 | * | ||
| 27 | * This always matches against the boot cpu, assuming models and features are | ||
| 28 | * consistent over all CPUs. | ||
| 29 | */ | ||
| 30 | const struct x86_cpu_id *x86_match_cpu(const struct x86_cpu_id *match) | ||
| 31 | { | ||
| 32 | const struct x86_cpu_id *m; | ||
| 33 | struct cpuinfo_x86 *c = &boot_cpu_data; | ||
| 34 | |||
| 35 | for (m = match; m->vendor | m->family | m->model | m->feature; m++) { | ||
| 36 | if (m->vendor != X86_VENDOR_ANY && c->x86_vendor != m->vendor) | ||
| 37 | continue; | ||
| 38 | if (m->family != X86_FAMILY_ANY && c->x86 != m->family) | ||
| 39 | continue; | ||
| 40 | if (m->model != X86_MODEL_ANY && c->x86_model != m->model) | ||
| 41 | continue; | ||
| 42 | if (m->feature != X86_FEATURE_ANY && !cpu_has(c, m->feature)) | ||
| 43 | continue; | ||
| 44 | return m; | ||
| 45 | } | ||
| 46 | return NULL; | ||
| 47 | } | ||
| 48 | EXPORT_SYMBOL(x86_match_cpu); | ||
diff --git a/arch/x86/kernel/cpuid.c b/arch/x86/kernel/cpuid.c index a524353d93f2..7c89880eefd0 100644 --- a/arch/x86/kernel/cpuid.c +++ b/arch/x86/kernel/cpuid.c | |||
| @@ -40,6 +40,7 @@ | |||
| 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> | ||
| 43 | 44 | ||
| 44 | #include <asm/processor.h> | 45 | #include <asm/processor.h> |
| 45 | #include <asm/msr.h> | 46 | #include <asm/msr.h> |
| @@ -138,13 +139,57 @@ static const struct file_operations cpuid_fops = { | |||
| 138 | .open = cpuid_open, | 139 | .open = cpuid_open, |
| 139 | }; | 140 | }; |
| 140 | 141 | ||
| 142 | static 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 | |||
| 174 | static DEVICE_ATTR(modalias, 0444, print_cpu_modalias, NULL); | ||
| 175 | |||
| 141 | static __cpuinit int cpuid_device_create(int cpu) | 176 | static __cpuinit int cpuid_device_create(int cpu) |
| 142 | { | 177 | { |
| 143 | struct device *dev; | 178 | struct device *dev; |
| 179 | int err; | ||
| 144 | 180 | ||
| 145 | dev = device_create(cpuid_class, NULL, MKDEV(CPUID_MAJOR, cpu), NULL, | 181 | dev = device_create(cpuid_class, NULL, MKDEV(CPUID_MAJOR, cpu), NULL, |
| 146 | "cpu%d", cpu); | 182 | "cpu%d", cpu); |
| 147 | return IS_ERR(dev) ? PTR_ERR(dev) : 0; | 183 | if (IS_ERR(dev)) |
| 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; | ||
| 148 | } | 193 | } |
| 149 | 194 | ||
| 150 | static void cpuid_device_destroy(int cpu) | 195 | static void cpuid_device_destroy(int cpu) |
| @@ -182,6 +227,17 @@ static char *cpuid_devnode(struct device *dev, umode_t *mode) | |||
| 182 | return kasprintf(GFP_KERNEL, "cpu/%u/cpuid", MINOR(dev->devt)); | 227 | return kasprintf(GFP_KERNEL, "cpu/%u/cpuid", MINOR(dev->devt)); |
| 183 | } | 228 | } |
| 184 | 229 | ||
| 230 | static 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 | |||
| 185 | static int __init cpuid_init(void) | 241 | static int __init cpuid_init(void) |
| 186 | { | 242 | { |
| 187 | int i, err = 0; | 243 | int i, err = 0; |
| @@ -200,6 +256,7 @@ static int __init cpuid_init(void) | |||
| 200 | goto out_chrdev; | 256 | goto out_chrdev; |
| 201 | } | 257 | } |
| 202 | cpuid_class->devnode = cpuid_devnode; | 258 | cpuid_class->devnode = cpuid_devnode; |
| 259 | cpuid_class->dev_uevent = cpuid_dev_uevent; | ||
| 203 | for_each_online_cpu(i) { | 260 | for_each_online_cpu(i) { |
| 204 | err = cpuid_device_create(i); | 261 | err = cpuid_device_create(i); |
| 205 | if (err != 0) | 262 | if (err != 0) |
diff --git a/include/linux/mod_devicetable.h b/include/linux/mod_devicetable.h index b29e7f6f8fa5..cff2cc08f45a 100644 --- a/include/linux/mod_devicetable.h +++ b/include/linux/mod_devicetable.h | |||
| @@ -571,4 +571,25 @@ struct amba_id { | |||
| 571 | #endif | 571 | #endif |
| 572 | }; | 572 | }; |
| 573 | 573 | ||
| 574 | /* | ||
| 575 | * Match x86 CPUs for CPU specific drivers. | ||
| 576 | * See documentation of "x86_match_cpu" for details. | ||
| 577 | */ | ||
| 578 | |||
