diff options
author | Rob Herring <rob.herring@calxeda.com> | 2013-10-09 12:26:44 -0400 |
---|---|---|
committer | Russell King <rmk+kernel@arm.linux.org.uk> | 2013-10-29 07:06:13 -0400 |
commit | 92871b94a5f9892e324c31960678387922c75049 (patch) | |
tree | 8c47f2a0af3c2d21c71eeba12c843fb0eb7a4795 | |
parent | 0cbad9c9dfe0c38e8ec7385b39087c005a6dee3e (diff) |
ARM: 7855/1: Add check for Cortex-A15 errata 798181 ECO
The work-around for A15 errata 798181 is not needed if appropriate ECO
fixes have been applied to r3p2 and earlier core revisions. This can be
checked by reading REVIDR register bits 4 and 9. If only bit 4 is set,
then the IPI broadcast can be skipped.
Signed-off-by: Rob Herring <rob.herring@calxeda.com>
Reviewed-by: Will Deacon <will.deacon@arm.com>
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
-rw-r--r-- | arch/arm/include/asm/cputype.h | 1 | ||||
-rw-r--r-- | arch/arm/include/asm/tlbflush.h | 48 | ||||
-rw-r--r-- | arch/arm/kernel/setup.c | 2 | ||||
-rw-r--r-- | arch/arm/kernel/smp_tlb.c | 36 |
4 files changed, 54 insertions, 33 deletions
diff --git a/arch/arm/include/asm/cputype.h b/arch/arm/include/asm/cputype.h index 9672e978d50d..acdde76b39bb 100644 --- a/arch/arm/include/asm/cputype.h +++ b/arch/arm/include/asm/cputype.h | |||
@@ -10,6 +10,7 @@ | |||
10 | #define CPUID_TLBTYPE 3 | 10 | #define CPUID_TLBTYPE 3 |
11 | #define CPUID_MPUIR 4 | 11 | #define CPUID_MPUIR 4 |
12 | #define CPUID_MPIDR 5 | 12 | #define CPUID_MPIDR 5 |
13 | #define CPUID_REVIDR 6 | ||
13 | 14 | ||
14 | #ifdef CONFIG_CPU_V7M | 15 | #ifdef CONFIG_CPU_V7M |
15 | #define CPUID_EXT_PFR0 0x40 | 16 | #define CPUID_EXT_PFR0 0x40 |
diff --git a/arch/arm/include/asm/tlbflush.h b/arch/arm/include/asm/tlbflush.h index 38960264040c..def9e570199f 100644 --- a/arch/arm/include/asm/tlbflush.h +++ b/arch/arm/include/asm/tlbflush.h | |||
@@ -560,37 +560,6 @@ static inline void __flush_bp_all(void) | |||
560 | asm("mcr p15, 0, %0, c7, c1, 6" : : "r" (zero)); | 560 | asm("mcr p15, 0, %0, c7, c1, 6" : : "r" (zero)); |
561 | } | 561 | } |
562 | 562 | ||
563 | #include <asm/cputype.h> | ||
564 | #ifdef CONFIG_ARM_ERRATA_798181 | ||
565 | static inline int erratum_a15_798181(void) | ||
566 | { | ||
567 | unsigned int midr = read_cpuid_id(); | ||
568 | |||
569 | /* Cortex-A15 r0p0..r3p2 affected */ | ||
570 | if ((midr & 0xff0ffff0) != 0x410fc0f0 || midr > 0x413fc0f2) | ||
571 | return 0; | ||
572 | return 1; | ||
573 | } | ||
574 | |||
575 | static inline void dummy_flush_tlb_a15_erratum(void) | ||
576 | { | ||
577 | /* | ||
578 | * Dummy TLBIMVAIS. Using the unmapped address 0 and ASID 0. | ||
579 | */ | ||
580 | asm("mcr p15, 0, %0, c8, c3, 1" : : "r" (0)); | ||
581 | dsb(ish); | ||
582 | } | ||
583 | #else | ||
584 | static inline int erratum_a15_798181(void) | ||
585 | { | ||
586 | return 0; | ||
587 | } | ||
588 | |||
589 | static inline void dummy_flush_tlb_a15_erratum(void) | ||
590 | { | ||
591 | } | ||
592 | #endif | ||
593 | |||
594 | /* | 563 | /* |
595 | * flush_pmd_entry | 564 | * flush_pmd_entry |
596 | * | 565 | * |
@@ -697,4 +666,21 @@ extern void flush_bp_all(void); | |||
697 | 666 | ||
698 | #endif | 667 | #endif |
699 | 668 | ||
669 | #ifndef __ASSEMBLY__ | ||
670 | #ifdef CONFIG_ARM_ERRATA_798181 | ||
671 | extern void erratum_a15_798181_init(void); | ||
672 | #else | ||
673 | static inline void erratum_a15_798181_init(void) {} | ||
674 | #endif | ||
675 | extern bool (*erratum_a15_798181_handler)(void); | ||
676 | |||
677 | static inline bool erratum_a15_798181(void) | ||
678 | { | ||
679 | if (unlikely(IS_ENABLED(CONFIG_ARM_ERRATA_798181) && | ||
680 | erratum_a15_798181_handler)) | ||
681 | return erratum_a15_798181_handler(); | ||
682 | return false; | ||
683 | } | ||
684 | #endif | ||
685 | |||
700 | #endif | 686 | #endif |
diff --git a/arch/arm/kernel/setup.c b/arch/arm/kernel/setup.c index 0e1e2b3afa45..a4852dea088b 100644 --- a/arch/arm/kernel/setup.c +++ b/arch/arm/kernel/setup.c | |||
@@ -599,6 +599,8 @@ static void __init setup_processor(void) | |||
599 | elf_hwcap &= ~(HWCAP_THUMB | HWCAP_IDIVT); | 599 | elf_hwcap &= ~(HWCAP_THUMB | HWCAP_IDIVT); |
600 | #endif | 600 | #endif |
601 | 601 | ||
602 | erratum_a15_798181_init(); | ||
603 | |||
602 | feat_v6_fixup(); | 604 | feat_v6_fixup(); |
603 | 605 | ||
604 | cacheid_init(); | 606 | cacheid_init(); |
diff --git a/arch/arm/kernel/smp_tlb.c b/arch/arm/kernel/smp_tlb.c index 83ccca303df8..95d063620b76 100644 --- a/arch/arm/kernel/smp_tlb.c +++ b/arch/arm/kernel/smp_tlb.c | |||
@@ -70,6 +70,40 @@ static inline void ipi_flush_bp_all(void *ignored) | |||
70 | local_flush_bp_all(); | 70 | local_flush_bp_all(); |
71 | } | 71 | } |
72 | 72 | ||
73 | #ifdef CONFIG_ARM_ERRATA_798181 | ||
74 | bool (*erratum_a15_798181_handler)(void); | ||
75 | |||
76 | static bool erratum_a15_798181_partial(void) | ||
77 | { | ||
78 | asm("mcr p15, 0, %0, c8, c3, 1" : : "r" (0)); | ||
79 | dsb(ish); | ||
80 | return false; | ||
81 | } | ||
82 | |||
83 | static bool erratum_a15_798181_broadcast(void) | ||
84 | { | ||
85 | asm("mcr p15, 0, %0, c8, c3, 1" : : "r" (0)); | ||
86 | dsb(ish); | ||
87 | return true; | ||
88 | } | ||
89 | |||
90 | void erratum_a15_798181_init(void) | ||
91 | { | ||
92 | unsigned int midr = read_cpuid_id(); | ||
93 | unsigned int revidr = read_cpuid(CPUID_REVIDR); | ||
94 | |||
95 | /* Cortex-A15 r0p0..r3p2 w/o ECO fix affected */ | ||
96 | if ((midr & 0xff0ffff0) != 0x410fc0f0 || midr > 0x413fc0f2 || | ||
97 | (revidr & 0x210) == 0x210) { | ||
98 | return; | ||
99 | } | ||
100 | if (revidr & 0x10) | ||
101 | erratum_a15_798181_handler = erratum_a15_798181_partial; | ||
102 | else | ||
103 | erratum_a15_798181_handler = erratum_a15_798181_broadcast; | ||
104 | } | ||
105 | #endif | ||
106 | |||
73 | static void ipi_flush_tlb_a15_erratum(void *arg) | 107 | static void ipi_flush_tlb_a15_erratum(void *arg) |
74 | { | 108 | { |
75 | dmb(); | 109 | dmb(); |
@@ -80,7 +114,6 @@ static void broadcast_tlb_a15_erratum(void) | |||
80 | if (!erratum_a15_798181()) | 114 | if (!erratum_a15_798181()) |
81 | return; | 115 | return; |
82 | 116 | ||
83 | dummy_flush_tlb_a15_erratum(); | ||
84 | smp_call_function(ipi_flush_tlb_a15_erratum, NULL, 1); | 117 | smp_call_function(ipi_flush_tlb_a15_erratum, NULL, 1); |
85 | } | 118 | } |
86 | 119 | ||
@@ -92,7 +125,6 @@ static void broadcast_tlb_mm_a15_erratum(struct mm_struct *mm) | |||
92 | if (!erratum_a15_798181()) | 125 | if (!erratum_a15_798181()) |
93 | return; | 126 | return; |
94 | 127 | ||
95 | dummy_flush_tlb_a15_erratum(); | ||
96 | this_cpu = get_cpu(); | 128 | this_cpu = get_cpu(); |
97 | a15_erratum_get_cpumask(this_cpu, mm, &mask); | 129 | a15_erratum_get_cpumask(this_cpu, mm, &mask); |
98 | smp_call_function_many(&mask, ipi_flush_tlb_a15_erratum, NULL, 1); | 130 | smp_call_function_many(&mask, ipi_flush_tlb_a15_erratum, NULL, 1); |