diff options
| author | Ard Biesheuvel <ard.biesheuvel@linaro.org> | 2014-02-08 07:34:09 -0500 |
|---|---|---|
| committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2014-02-18 15:38:37 -0500 |
| commit | 67bad2fdb754dbef14596c0b5d28b3a12c8dfe84 (patch) | |
| tree | 05c3cd5f809618319346f9642549460f95149f02 /drivers/base | |
| parent | 91219a3b20325689eb80f7598cce2dc745db171d (diff) | |
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 <asm/cpufeature.h> 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 <ard.biesheuvel@linaro.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'drivers/base')
| -rw-r--r-- | drivers/base/Kconfig | 8 | ||||
| -rw-r--r-- | drivers/base/cpu.c | 50 |
2 files changed, 53 insertions, 5 deletions
diff --git a/drivers/base/Kconfig b/drivers/base/Kconfig index ec36e7772e57..3f0d3732df7f 100644 --- a/drivers/base/Kconfig +++ b/drivers/base/Kconfig | |||
| @@ -185,6 +185,14 @@ config GENERIC_CPU_DEVICES | |||
| 185 | bool | 185 | bool |
| 186 | default n | 186 | default n |
| 187 | 187 | ||
| 188 | config HAVE_CPU_AUTOPROBE | ||
| 189 | def_bool ARCH_HAS_CPU_AUTOPROBE | ||
| 190 | |||
| 191 | config GENERIC_CPU_AUTOPROBE | ||
| 192 | bool | ||
| 193 | depends on !ARCH_HAS_CPU_AUTOPROBE | ||
| 194 | select HAVE_CPU_AUTOPROBE | ||
| 195 | |||
| 188 | config SOC_BUS | 196 | config SOC_BUS |
| 189 | bool | 197 | bool |
| 190 | 198 | ||
diff --git a/drivers/base/cpu.c b/drivers/base/cpu.c index f48370dfc908..8a38bf8c792f 100644 --- a/drivers/base/cpu.c +++ b/drivers/base/cpu.c | |||
| @@ -15,6 +15,7 @@ | |||
| 15 | #include <linux/percpu.h> | 15 | #include <linux/percpu.h> |
| 16 | #include <linux/acpi.h> | 16 | #include <linux/acpi.h> |
| 17 | #include <linux/of.h> | 17 | #include <linux/of.h> |
| 18 | #include <linux/cpufeature.h> | ||
| 18 | 19 | ||
| 19 | #include "base.h" | 20 | #include "base.h" |
| 20 | 21 | ||
| @@ -286,6 +287,45 @@ static void cpu_device_release(struct device *dev) | |||
| 286 | */ | 287 | */ |
| 287 | } | 288 | } |
| 288 | 289 | ||
| 290 | #ifdef CONFIG_HAVE_CPU_AUTOPROBE | ||
| 291 | #ifdef CONFIG_GENERIC_CPU_AUTOPROBE | ||
| 292 | static ssize_t print_cpu_modalias(struct device *dev, | ||
| 293 | struct device_attribute *attr, | ||
| 294 | char *buf) | ||
| 295 | { | ||
| 296 | ssize_t n; | ||
| 297 | u32 i; | ||
| 298 | |||
| 299 | n = sprintf(buf, "cpu:type:" CPU_FEATURE_TYPEFMT ":feature:", | ||
| 300 | CPU_FEATURE_TYPEVAL); | ||
| 301 | |||
| 302 | for (i = 0; i < MAX_CPU_FEATURES; i++) | ||
| 303 | if (cpu_have_feature(i)) { | ||
| 304 | if (PAGE_SIZE < n + sizeof(",XXXX\n")) { | ||
| 305 | WARN(1, "CPU features overflow page\n"); | ||
| 306 | break; | ||
| 307 | } | ||
| 308 | n += sprintf(&buf[n], ",%04X", i); | ||
| 309 | } | ||
| 310 | buf[n++] = '\n'; | ||
| 311 | return n; | ||
| 312 | } | ||
| 313 | #else | ||
| 314 | #define print_cpu_modalias arch_print_cpu_modalias | ||
| 315 | #endif | ||
| 316 | |||
| 317 | static int cpu_uevent(struct device *dev, struct kobj_uevent_env *env) | ||
| 318 | { | ||
| 319 | char *buf = kzalloc(PAGE_SIZE, GFP_KERNEL); | ||
| 320 | if (buf) { | ||
| 321 | print_cpu_modalias(NULL, NULL, buf); | ||
| 322 | add_uevent_var(env, "MODALIAS=%s", buf); | ||
| 323 | kfree(buf); | ||
| 324 | } | ||
| 325 | return 0; | ||
| 326 | } | ||
| 327 | #endif | ||
| 328 | |||
| 289 | /* | 329 | /* |
| 290 | * register_cpu - Setup a sysfs device for a CPU. | 330 | * register_cpu - Setup a sysfs device for a CPU. |
| 291 | * @cpu - cpu->hotpluggable field set to 1 will generate a control file in | 331 | * @cpu - cpu->hotpluggable field set to 1 will generate a control file in |
| @@ -306,8 +346,8 @@ int register_cpu(struct cpu *cpu, int num) | |||
| 306 | cpu->dev.offline_disabled = !cpu->hotpluggable; | 346 | cpu->dev.offline_disabled = !cpu->hotpluggable; |
| 307 | cpu->dev.offline = !cpu_online(num); | 347 | cpu->dev.offline = !cpu_online(num); |
| 308 | cpu->dev.of_node = of_get_cpu_node(num, NULL); | 348 | cpu->dev.of_node = of_get_cpu_node(num, NULL); |
| 309 | #ifdef CONFIG_ARCH_HAS_CPU_AUTOPROBE | 349 | #ifdef CONFIG_HAVE_CPU_AUTOPROBE |
| 310 | cpu->dev.bus->uevent = arch_cpu_uevent; | 350 | cpu->dev.bus->uevent = cpu_uevent; |
| 311 | #endif | 351 | #endif |
| 312 | cpu->dev.groups = common_cpu_attr_groups; | 352 | cpu->dev.groups = common_cpu_attr_groups; |
| 313 | if (cpu->hotpluggable) | 353 | if (cpu->hotpluggable) |
| @@ -330,8 +370,8 @@ struct device *get_cpu_device(unsigned cpu) | |||
| 330 | } | 370 | } |
| 331 | EXPORT_SYMBOL_GPL(get_cpu_device); | 371 | EXPORT_SYMBOL_GPL(get_cpu_device); |
| 332 | 372 | ||
| 333 | #ifdef CONFIG_ARCH_HAS_CPU_AUTOPROBE | 373 | #ifdef CONFIG_HAVE_CPU_AUTOPROBE |
| 334 | static DEVICE_ATTR(modalias, 0444, arch_print_cpu_modalias, NULL); | 374 | static DEVICE_ATTR(modalias, 0444, print_cpu_modalias, NULL); |
| 335 | #endif | 375 | #endif |
| 336 | 376 | ||
| 337 | static struct attribute *cpu_root_attrs[] = { | 377 | static struct attribute *cpu_root_attrs[] = { |
| @@ -344,7 +384,7 @@ static struct attribute *cpu_root_attrs[] = { | |||
| 344 | &cpu_attrs[2].attr.attr, | 384 | &cpu_attrs[2].attr.attr, |
| 345 | &dev_attr_kernel_max.attr, | 385 | &dev_attr_kernel_max.attr, |
| 346 | &dev_attr_offline.attr, | 386 | &dev_attr_offline.attr, |
| 347 | #ifdef CONFIG_ARCH_HAS_CPU_AUTOPROBE | 387 | #ifdef CONFIG_HAVE_CPU_AUTOPROBE |
| 348 | &dev_attr_modalias.attr, | 388 | &dev_attr_modalias.attr, |
| 349 | #endif | 389 | #endif |
| 350 | NULL | 390 | NULL |
