Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

ARM: 8318/1: treat CPU feature register fields as signed quantities

The various CPU feature registers consist of 4-bit blocks that
represent signed quantities, whose positive values represent
incremental features, and whose negative values are reserved.

To improve forward compatibility, update the feature detection
code to take possible future higher values into account, but
ignore negative values.

Signed-off-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>

authored by

Ard Biesheuvel and committed by
Russell King
b8c9592b eb765c1c

+25 -13
+16
arch/arm/include/asm/cputype.h
··· 253 253 #else 254 254 #define cpu_is_pj4() 0 255 255 #endif 256 + 257 + static inline int __attribute_const__ cpuid_feature_extract_field(u32 features, 258 + int field) 259 + { 260 + int feature = (features >> field) & 15; 261 + 262 + /* feature registers are signed values */ 263 + if (feature > 8) 264 + feature -= 16; 265 + 266 + return feature; 267 + } 268 + 269 + #define cpuid_feature_extract(reg, field) \ 270 + cpuid_feature_extract_field(read_cpuid_ext(reg), field) 271 + 256 272 #endif
+9 -13
arch/arm/kernel/setup.c
··· 375 375 376 376 static void __init cpuid_init_hwcaps(void) 377 377 { 378 - unsigned int divide_instrs, vmsa; 378 + int block; 379 379 380 380 if (cpu_architecture() < CPU_ARCH_ARMv7) 381 381 return; 382 382 383 - divide_instrs = (read_cpuid_ext(CPUID_EXT_ISAR0) & 0x0f000000) >> 24; 384 - 385 - switch (divide_instrs) { 386 - case 2: 383 + block = cpuid_feature_extract(CPUID_EXT_ISAR0, 24); 384 + if (block >= 2) 387 385 elf_hwcap |= HWCAP_IDIVA; 388 - case 1: 386 + if (block >= 1) 389 387 elf_hwcap |= HWCAP_IDIVT; 390 - } 391 388 392 389 /* LPAE implies atomic ldrd/strd instructions */ 393 - vmsa = (read_cpuid_ext(CPUID_EXT_MMFR0) & 0xf) >> 0; 394 - if (vmsa >= 5) 390 + block = cpuid_feature_extract(CPUID_EXT_MMFR0, 0); 391 + if (block >= 5) 395 392 elf_hwcap |= HWCAP_LPAE; 396 393 } 397 394 398 395 static void __init elf_hwcap_fixup(void) 399 396 { 400 397 unsigned id = read_cpuid_id(); 401 - unsigned sync_prim; 402 398 403 399 /* 404 400 * HWCAP_TLS is available only on 1136 r1p0 and later, ··· 415 419 * avoid advertising SWP; it may not be atomic with 416 420 * multiprocessing cores. 417 421 */ 418 - sync_prim = ((read_cpuid_ext(CPUID_EXT_ISAR3) >> 8) & 0xf0) | 419 - ((read_cpuid_ext(CPUID_EXT_ISAR4) >> 20) & 0x0f); 420 - if (sync_prim >= 0x13) 422 + if (cpuid_feature_extract(CPUID_EXT_ISAR3, 12) > 1 || 423 + (cpuid_feature_extract(CPUID_EXT_ISAR3, 12) == 1 && 424 + cpuid_feature_extract(CPUID_EXT_ISAR3, 20) >= 3)) 421 425 elf_hwcap &= ~HWCAP_SWP; 422 426 } 423 427