From 67bad2fdb754dbef14596c0b5d28b3a12c8dfe84 Mon Sep 17 00:00:00 2001 From: Ard Biesheuvel Date: Sat, 8 Feb 2014 13:34:09 +0100 Subject: cpu: add generic support for CPU feature based module autoloading This patch adds support for advertising optional CPU features over udev using the modalias, and for declaring compatibility with/dependency upon such a feature in a module. The mapping between feature numbers and actual features should be provided by the architecture in a file called which exports the following functions/macros: - cpu_feature(FEAT), a preprocessor macro that maps token FEAT to a numeric index; - bool cpu_have_feature(n), returning whether this CPU has support for feature #n; - MAX_CPU_FEATURES, an upper bound for 'n' in the previous function. The feature can then be enabled by setting CONFIG_GENERIC_CPU_AUTOPROBE for the architecture. For instance, a module that registers its module init function using module_cpu_feature_match(FEAT_X, module_init_function) will be probed automatically when the CPU's support for the 'FEAT_X' feature is advertised over udev, and will only allow the module to be loaded by hand if the 'FEAT_X' feature is supported. Signed-off-by: Ard Biesheuvel Signed-off-by: Greg Kroah-Hartman --- scripts/mod/file2alias.c | 10 ++++++++++ 1 file changed, 10 insertions(+) (limited to 'scripts/mod/file2alias.c') diff --git a/scripts/mod/file2alias.c b/scripts/mod/file2alias.c index 25e5cb0aaef..506146e5f4a 100644 --- a/scripts/mod/file2alias.c +++ b/scripts/mod/file2alias.c @@ -1135,6 +1135,16 @@ static int do_x86cpu_entry(const char *filename, void *symval, } ADD_TO_DEVTABLE("x86cpu", x86_cpu_id, do_x86cpu_entry); +/* LOOKS like cpu:type:*:feature:*FEAT* */ +static int do_cpu_entry(const char *filename, void *symval, char *alias) +{ + DEF_FIELD(symval, cpu_feature, feature); + + sprintf(alias, "cpu:type:*:feature:*%04X*", feature); + return 1; +} +ADD_TO_DEVTABLE("cpu", cpu_feature, do_cpu_entry); + /* Looks like: mei:S */ static int do_mei_entry(const char *filename, void *symval, char *alias) -- cgit v1.2.3-70-g09d2 From 2b9c1f03278ab7cd421f14ce24dee39091ecb064 Mon Sep 17 00:00:00 2001 From: Ard Biesheuvel Date: Sat, 8 Feb 2014 13:34:10 +0100 Subject: x86: align x86 arch with generic CPU modalias handling The x86 CPU feature modalias handling existed before it was reimplemented generically. This patch aligns the x86 handling so that it (a) reuses some more code that is now generic; (b) uses the generic format for the modalias module metadata entry, i.e., it now uses 'cpu:type:x86,venVVVVfamFFFFmodMMMM:feature:,XXXX,YYYY' instead of the 'x86cpu:vendor:VVVV:family:FFFF:model:MMMM:feature:,XXXX,YYYY' that was used before. Signed-off-by: Ard Biesheuvel Acked-by: H. Peter Anvin Signed-off-by: Greg Kroah-Hartman --- arch/x86/Kconfig | 4 +--- arch/x86/include/asm/cpufeature.h | 7 +++++++ arch/x86/kernel/cpu/match.c | 42 --------------------------------------- drivers/base/Kconfig | 5 ----- drivers/base/cpu.c | 10 +++------- include/linux/cpu.h | 7 ------- scripts/mod/file2alias.c | 10 +++++----- 7 files changed, 16 insertions(+), 69 deletions(-) (limited to 'scripts/mod/file2alias.c') diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig index 0af5250d914..7fab7e0b1a7 100644 --- a/arch/x86/Kconfig +++ b/arch/x86/Kconfig @@ -127,6 +127,7 @@ config X86 select HAVE_DEBUG_STACKOVERFLOW select HAVE_IRQ_EXIT_ON_IRQ_STACK if X86_64 select HAVE_CC_STACKPROTECTOR + select GENERIC_CPU_AUTOPROBE config INSTRUCTION_DECODER def_bool y @@ -195,9 +196,6 @@ config ARCH_HAS_CPU_RELAX config ARCH_HAS_CACHE_LINE_SIZE def_bool y -config ARCH_HAS_CPU_AUTOPROBE - def_bool y - config HAVE_SETUP_PER_CPU_AREA def_bool y diff --git a/arch/x86/include/asm/cpufeature.h b/arch/x86/include/asm/cpufeature.h index e099f9502ac..d86dc3deea6 100644 --- a/arch/x86/include/asm/cpufeature.h +++ b/arch/x86/include/asm/cpufeature.h @@ -541,6 +541,13 @@ static __always_inline __pure bool _static_cpu_has_safe(u16 bit) #define static_cpu_has_bug(bit) static_cpu_has((bit)) #define boot_cpu_has_bug(bit) cpu_has_bug(&boot_cpu_data, (bit)) +#define MAX_CPU_FEATURES (NCAPINTS * 32) +#define cpu_have_feature boot_cpu_has + +#define CPU_FEATURE_TYPEFMT "x86,ven%04Xfam%04Xmod%04X" +#define CPU_FEATURE_TYPEVAL boot_cpu_data.x86_vendor, boot_cpu_data.x86, \ + boot_cpu_data.x86_model + #endif /* defined(__KERNEL__) && !defined(__ASSEMBLY__) */ #endif /* _ASM_X86_CPUFEATURE_H */ diff --git a/arch/x86/kernel/cpu/match.c b/arch/x86/kernel/cpu/match.c index 36565373af8..afa9f0d487e 100644 --- a/arch/x86/kernel/cpu/match.c +++ b/arch/x86/kernel/cpu/match.c @@ -47,45 +47,3 @@ const struct x86_cpu_id *x86_match_cpu(const struct x86_cpu_id *match) return NULL; } EXPORT_SYMBOL(x86_match_cpu); - -ssize_t arch_print_cpu_modalias(struct device *dev, - struct device_attribute *attr, - char *bufptr) -{ - int size = PAGE_SIZE; - int i, n; - char *buf = bufptr; - - n = snprintf(buf, size, "x86cpu:vendor:%04X:family:%04X:" - "model:%04X:feature:", - boot_cpu_data.x86_vendor, - boot_cpu_data.x86, - boot_cpu_data.x86_model); - size -= n; - buf += n; - size -= 1; - for (i = 0; i < NCAPINTS*32; i++) { - if (boot_cpu_has(i)) { - n = snprintf(buf, size, ",%04X", i); - if (n >= size) { - WARN(1, "x86 features overflow page\n"); - break; - } - size -= n; - buf += n; - } - } - *buf++ = '\n'; - return buf - bufptr; -} - -int arch_cpu_uevent(struct device *dev, struct kobj_uevent_env *env) -{ - char *buf = kzalloc(PAGE_SIZE, GFP_KERNEL); - if (buf) { - arch_print_cpu_modalias(NULL, NULL, buf); - add_uevent_var(env, "MODALIAS=%s", buf); - kfree(buf); - } - return 0; -} diff --git a/drivers/base/Kconfig b/drivers/base/Kconfig index 3f0d3732df7..8fa8deab644 100644 --- a/drivers/base/Kconfig +++ b/drivers/base/Kconfig @@ -185,13 +185,8 @@ config GENERIC_CPU_DEVICES bool default n -config HAVE_CPU_AUTOPROBE - def_bool ARCH_HAS_CPU_AUTOPROBE - config GENERIC_CPU_AUTOPROBE bool - depends on !ARCH_HAS_CPU_AUTOPROBE - select HAVE_CPU_AUTOPROBE config SOC_BUS bool diff --git a/drivers/base/cpu.c b/drivers/base/cpu.c index 8a38bf8c792..006b1bc5297 100644 --- a/drivers/base/cpu.c +++ b/drivers/base/cpu.c @@ -287,7 +287,6 @@ static void cpu_device_release(struct device *dev) */ } -#ifdef CONFIG_HAVE_CPU_AUTOPROBE #ifdef CONFIG_GENERIC_CPU_AUTOPROBE static ssize_t print_cpu_modalias(struct device *dev, struct device_attribute *attr, @@ -310,9 +309,6 @@ static ssize_t print_cpu_modalias(struct device *dev, buf[n++] = '\n'; return n; } -#else -#define print_cpu_modalias arch_print_cpu_modalias -#endif static int cpu_uevent(struct device *dev, struct kobj_uevent_env *env) { @@ -346,7 +342,7 @@ int register_cpu(struct cpu *cpu, int num) cpu->dev.offline_disabled = !cpu->hotpluggable; cpu->dev.offline = !cpu_online(num); cpu->dev.of_node = of_get_cpu_node(num, NULL); -#ifdef CONFIG_HAVE_CPU_AUTOPROBE +#ifdef CONFIG_GENERIC_CPU_AUTOPROBE cpu->dev.bus->uevent = cpu_uevent; #endif cpu->dev.groups = common_cpu_attr_groups; @@ -370,7 +366,7 @@ struct device *get_cpu_device(unsigned cpu) } EXPORT_SYMBOL_GPL(get_cpu_device); -#ifdef CONFIG_HAVE_CPU_AUTOPROBE +#ifdef CONFIG_GENERIC_CPU_AUTOPROBE static DEVICE_ATTR(modalias, 0444, print_cpu_modalias, NULL); #endif @@ -384,7 +380,7 @@ static struct attribute *cpu_root_attrs[] = { &cpu_attrs[2].attr.attr, &dev_attr_kernel_max.attr, &dev_attr_offline.attr, -#ifdef CONFIG_HAVE_CPU_AUTOPROBE +#ifdef CONFIG_GENERIC_CPU_AUTOPROBE &dev_attr_modalias.attr, #endif NULL diff --git a/include/linux/cpu.h b/include/linux/cpu.h index 03e235ad1bb..03e962e23ea 100644 --- a/include/linux/cpu.h +++ b/include/linux/cpu.h @@ -46,13 +46,6 @@ extern ssize_t arch_cpu_release(const char *, size_t); #endif struct notifier_block; -#ifdef CONFIG_ARCH_HAS_CPU_AUTOPROBE -extern int arch_cpu_uevent(struct device *dev, struct kobj_uevent_env *env); -extern ssize_t arch_print_cpu_modalias(struct device *dev, - struct device_attribute *attr, - char *bufptr); -#endif - /* * CPU notifier priorities. */ diff --git a/scripts/mod/file2alias.c b/scripts/mod/file2alias.c index 506146e5f4a..25f6f597055 100644 --- a/scripts/mod/file2alias.c +++ b/scripts/mod/file2alias.c @@ -1110,7 +1110,7 @@ static int do_amba_entry(const char *filename, } ADD_TO_DEVTABLE("amba", amba_id, do_amba_entry); -/* LOOKS like x86cpu:vendor:VVVV:family:FFFF:model:MMMM:feature:*,FEAT,* +/* LOOKS like cpu:type:x86,venVVVVfamFFFFmodMMMM:feature:*,FEAT,* * All fields are numbers. It would be nicer to use strings for vendor * and feature, but getting those out of the build system here is too * complicated. @@ -1124,10 +1124,10 @@ static int do_x86cpu_entry(const char *filename, void *symval, DEF_FIELD(symval, x86_cpu_id, model); DEF_FIELD(symval, x86_cpu_id, vendor); - strcpy(alias, "x86cpu:"); - ADD(alias, "vendor:", vendor != X86_VENDOR_ANY, vendor); - ADD(alias, ":family:", family != X86_FAMILY_ANY, family); - ADD(alias, ":model:", model != X86_MODEL_ANY, model); + strcpy(alias, "cpu:type:x86,"); + ADD(alias, "ven", vendor != X86_VENDOR_ANY, vendor); + ADD(alias, "fam", family != X86_FAMILY_ANY, family); + ADD(alias, "mod", model != X86_MODEL_ANY, model); strcat(alias, ":feature:*"); if (feature != X86_FEATURE_ANY) sprintf(alias + strlen(alias), "%04X*", feature); -- cgit v1.2.3-70-g09d2 From 21bdd17b21b45ea48e06e23918d681afbe0622e9 Mon Sep 17 00:00:00 2001 From: Tom Gundersen Date: Mon, 3 Feb 2014 11:14:13 +1030 Subject: module: allow multiple calls to MODULE_DEVICE_TABLE() per module Commit 78551277e4df5: "Input: i8042 - add PNP modaliases" had a bug, where the second call to MODULE_DEVICE_TABLE() overrode the first resulting in not all the modaliases being exposed. This fixes the problem by including the name of the device_id table in the __mod_*_device_table alias, allowing us to export several device_id tables per module. Suggested-by: Kay Sievers Acked-by: Greg Kroah-Hartman Cc: Dmitry Torokhov Signed-off-by: Tom Gundersen Signed-off-by: Rusty Russell --- include/linux/module.h | 2 +- scripts/mod/file2alias.c | 14 +++++++++----- 2 files changed, 10 insertions(+), 6 deletions(-) (limited to 'scripts/mod/file2alias.c') diff --git a/include/linux/module.h b/include/linux/module.h index eaf60ff9ba9..ad18f6006f8 100644 --- a/include/linux/module.h +++ b/include/linux/module.h @@ -142,7 +142,7 @@ extern const struct gtype##_id __mod_##gtype##_table \ #define MODULE_DESCRIPTION(_description) MODULE_INFO(description, _description) #define MODULE_DEVICE_TABLE(type, name) \ - MODULE_GENERIC_TABLE(type##_device, name) + MODULE_GENERIC_TABLE(type##__##name##_device, name) /* Version of form [:][-]. * Or for CVS/RCS ID version, everything but the number is stripped. diff --git a/scripts/mod/file2alias.c b/scripts/mod/file2alias.c index 25e5cb0aaef..ce164044f0c 100644 --- a/scripts/mod/file2alias.c +++ b/scripts/mod/file2alias.c @@ -42,7 +42,7 @@ typedef unsigned char __u8; /* This array collects all instances that use the generic do_table */ struct devtable { - const char *device_id; /* name of table, __mod__device_table. */ + const char *device_id; /* name of table, __mod___*_device_table. */ unsigned long id_size; void *function; }; @@ -146,7 +146,8 @@ static void device_id_check(const char *modname, const char *device_id, if (size % id_size || size < id_size) { fatal("%s: sizeof(struct %s_device_id)=%lu is not a modulo " - "of the size of section __mod_%s_device_table=%lu.\n" + "of the size of " + "section __mod_%s___device_table=%lu.\n" "Fix definition of struct %s_device_id " "in mod_devicetable.h\n", modname, device_id, id_size, device_id, size, device_id); @@ -1206,7 +1207,7 @@ void handle_moddevtable(struct module *mod, struct elf_info *info, { void *symval; char *zeros = NULL; - const char *name; + const char *name, *identifier; unsigned int namelen; /* We're looking for a section relative symbol */ @@ -1217,7 +1218,7 @@ void handle_moddevtable(struct module *mod, struct elf_info *info, if (ELF_ST_TYPE(sym->st_info) != STT_OBJECT) return; - /* All our symbols are of form __mod_XXX_device_table. */ + /* All our symbols are of form __mod____device_table. */ name = strstr(symname, "__mod_"); if (!name) return; @@ -1227,7 +1228,10 @@ void handle_moddevtable(struct module *mod, struct elf_info *info, return; if (strcmp(name + namelen - strlen("_device_table"), "_device_table")) return; - namelen -= strlen("_device_table"); + identifier = strstr(name, "__"); + if (!identifier) + return; + namelen = identifier - name; /* Handle all-NULL symbols allocated into .bss */ if (info->sechdrs[get_secindex(info, sym)].sh_type & SHT_NOBITS) { -- cgit v1.2.3-70-g09d2