aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2018-06-29 15:25:26 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2018-06-29 15:25:26 -0400
commit0d55ec6f3eb727d937a94de8bd3828ef662f871b (patch)
tree0eb9762b368f42e40f134d9ecdabb81e0991b2d9
parent44813aa62aa2f6ac98ba3554cf8bc49087098b74 (diff)
parent24fe1b0efad4fcdd32ce46cffeab297f22581707 (diff)
Merge tag 'arm64-fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/arm64/linux
Pull arm64 fixes from Catalin Marinas: - The alternatives patching code uses flush_icache_range() which itself uses alternatives. Change the code to use an unpatched variant of cache maintenance - Remove unnecessary ISBs from set_{pte,pmd,pud} - perf: xgene_pmu: Fix IOB SLOW PMU parser error * tag 'arm64-fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/arm64/linux: arm64: Remove unnecessary ISBs from set_{pte,pmd,pud} arm64: Avoid flush_icache_range() in alternatives patching code drivers/perf: xgene_pmu: Fix IOB SLOW PMU parser error
-rw-r--r--arch/arm64/include/asm/alternative.h7
-rw-r--r--arch/arm64/include/asm/pgtable.h6
-rw-r--r--arch/arm64/kernel/alternative.c51
-rw-r--r--arch/arm64/kernel/module.c5
-rw-r--r--drivers/perf/xgene_pmu.c2
5 files changed, 54 insertions, 17 deletions
diff --git a/arch/arm64/include/asm/alternative.h b/arch/arm64/include/asm/alternative.h
index a91933b1e2e6..4b650ec1d7dd 100644
--- a/arch/arm64/include/asm/alternative.h
+++ b/arch/arm64/include/asm/alternative.h
@@ -28,7 +28,12 @@ typedef void (*alternative_cb_t)(struct alt_instr *alt,
28 __le32 *origptr, __le32 *updptr, int nr_inst); 28 __le32 *origptr, __le32 *updptr, int nr_inst);
29 29
30void __init apply_alternatives_all(void); 30void __init apply_alternatives_all(void);
31void apply_alternatives(void *start, size_t length); 31
32#ifdef CONFIG_MODULES
33void apply_alternatives_module(void *start, size_t length);
34#else
35static inline void apply_alternatives_module(void *start, size_t length) { }
36#endif
32 37
33#define ALTINSTR_ENTRY(feature,cb) \ 38#define ALTINSTR_ENTRY(feature,cb) \
34 " .word 661b - .\n" /* label */ \ 39 " .word 661b - .\n" /* label */ \
diff --git a/arch/arm64/include/asm/pgtable.h b/arch/arm64/include/asm/pgtable.h
index 9f82d6b53851..1bdeca8918a6 100644
--- a/arch/arm64/include/asm/pgtable.h
+++ b/arch/arm64/include/asm/pgtable.h
@@ -224,10 +224,8 @@ static inline void set_pte(pte_t *ptep, pte_t pte)
224 * Only if the new pte is valid and kernel, otherwise TLB maintenance 224 * Only if the new pte is valid and kernel, otherwise TLB maintenance
225 * or update_mmu_cache() have the necessary barriers. 225 * or update_mmu_cache() have the necessary barriers.
226 */ 226 */
227 if (pte_valid_not_user(pte)) { 227 if (pte_valid_not_user(pte))
228 dsb(ishst); 228 dsb(ishst);
229 isb();
230 }
231} 229}
232 230
233extern void __sync_icache_dcache(pte_t pteval); 231extern void __sync_icache_dcache(pte_t pteval);
@@ -434,7 +432,6 @@ static inline void set_pmd(pmd_t *pmdp, pmd_t pmd)
434{ 432{
435 WRITE_ONCE(*pmdp, pmd); 433 WRITE_ONCE(*pmdp, pmd);
436 dsb(ishst); 434 dsb(ishst);
437 isb();
438} 435}
439 436
440static inline void pmd_clear(pmd_t *pmdp) 437static inline void pmd_clear(pmd_t *pmdp)
@@ -485,7 +482,6 @@ static inline void set_pud(pud_t *pudp, pud_t pud)
485{ 482{
486 WRITE_ONCE(*pudp, pud); 483 WRITE_ONCE(*pudp, pud);
487 dsb(ishst); 484 dsb(ishst);
488 isb();
489} 485}
490 486
491static inline void pud_clear(pud_t *pudp) 487static inline void pud_clear(pud_t *pudp)
diff --git a/arch/arm64/kernel/alternative.c b/arch/arm64/kernel/alternative.c
index 5c4bce4ac381..36fb069fd049 100644
--- a/arch/arm64/kernel/alternative.c
+++ b/arch/arm64/kernel/alternative.c
@@ -122,7 +122,30 @@ static void patch_alternative(struct alt_instr *alt,
122 } 122 }
123} 123}
124 124
125static void __apply_alternatives(void *alt_region, bool use_linear_alias) 125/*
126 * We provide our own, private D-cache cleaning function so that we don't
127 * accidentally call into the cache.S code, which is patched by us at
128 * runtime.
129 */
130static void clean_dcache_range_nopatch(u64 start, u64 end)
131{
132 u64 cur, d_size, ctr_el0;
133
134 ctr_el0 = read_sanitised_ftr_reg(SYS_CTR_EL0);
135 d_size = 4 << cpuid_feature_extract_unsigned_field(ctr_el0,
136 CTR_DMINLINE_SHIFT);
137 cur = start & ~(d_size - 1);
138 do {
139 /*
140 * We must clean+invalidate to the PoC in order to avoid
141 * Cortex-A53 errata 826319, 827319, 824069 and 819472
142 * (this corresponds to ARM64_WORKAROUND_CLEAN_CACHE)
143 */
144 asm volatile("dc civac, %0" : : "r" (cur) : "memory");
145 } while (cur += d_size, cur < end);
146}
147
148static void __apply_alternatives(void *alt_region, bool is_module)
126{ 149{
127 struct alt_instr *alt; 150 struct alt_instr *alt;
128 struct alt_region *region = alt_region; 151 struct alt_region *region = alt_region;
@@ -145,7 +168,7 @@ static void __apply_alternatives(void *alt_region, bool use_linear_alias)
145 pr_info_once("patching kernel code\n"); 168 pr_info_once("patching kernel code\n");
146 169
147 origptr = ALT_ORIG_PTR(alt); 170 origptr = ALT_ORIG_PTR(alt);
148 updptr = use_linear_alias ? lm_alias(origptr) : origptr; 171 updptr = is_module ? origptr : lm_alias(origptr);
149 nr_inst = alt->orig_len / AARCH64_INSN_SIZE; 172 nr_inst = alt->orig_len / AARCH64_INSN_SIZE;
150 173
151 if (alt->cpufeature < ARM64_CB_PATCH) 174 if (alt->cpufeature < ARM64_CB_PATCH)
@@ -155,8 +178,20 @@ static void __apply_alternatives(void *alt_region, bool use_linear_alias)
155 178
156 alt_cb(alt, origptr, updptr, nr_inst); 179 alt_cb(alt, origptr, updptr, nr_inst);
157 180
158 flush_icache_range((uintptr_t)origptr, 181 if (!is_module) {
159 (uintptr_t)(origptr + nr_inst)); 182 clean_dcache_range_nopatch((u64)origptr,
183 (u64)(origptr + nr_inst));
184 }
185 }
186
187 /*
188 * The core module code takes care of cache maintenance in
189 * flush_module_icache().
190 */
191 if (!is_module) {
192 dsb(ish);
193 __flush_icache_all();
194 isb();
160 } 195 }
161} 196}
162 197
@@ -178,7 +213,7 @@ static int __apply_alternatives_multi_stop(void *unused)
178 isb(); 213 isb();
179 } else { 214 } else {
180 BUG_ON(alternatives_applied); 215 BUG_ON(alternatives_applied);
181 __apply_alternatives(&region, true); 216 __apply_alternatives(&region, false);
182 /* Barriers provided by the cache flushing */ 217 /* Barriers provided by the cache flushing */
183 WRITE_ONCE(alternatives_applied, 1); 218 WRITE_ONCE(alternatives_applied, 1);
184 } 219 }
@@ -192,12 +227,14 @@ void __init apply_alternatives_all(void)
192 stop_machine(__apply_alternatives_multi_stop, NULL, cpu_online_mask); 227 stop_machine(__apply_alternatives_multi_stop, NULL, cpu_online_mask);
193} 228}
194 229
195void apply_alternatives(void *start, size_t length) 230#ifdef CONFIG_MODULES
231void apply_alternatives_module(void *start, size_t length)
196{ 232{
197 struct alt_region region = { 233 struct alt_region region = {
198 .begin = start, 234 .begin = start,
199 .end = start + length, 235 .end = start + length,
200 }; 236 };
201 237
202 __apply_alternatives(&region, false); 238 __apply_alternatives(&region, true);
203} 239}
240#endif
diff --git a/arch/arm64/kernel/module.c b/arch/arm64/kernel/module.c
index 155fd91e78f4..f0f27aeefb73 100644
--- a/arch/arm64/kernel/module.c
+++ b/arch/arm64/kernel/module.c
@@ -448,9 +448,8 @@ int module_finalize(const Elf_Ehdr *hdr,
448 const char *secstrs = (void *)hdr + sechdrs[hdr->e_shstrndx].sh_offset; 448 const char *secstrs = (void *)hdr + sechdrs[hdr->e_shstrndx].sh_offset;
449 449
450 for (s = sechdrs, se = sechdrs + hdr->e_shnum; s < se; s++) { 450 for (s = sechdrs, se = sechdrs + hdr->e_shnum; s < se; s++) {
451 if (strcmp(".altinstructions", secstrs + s->sh_name) == 0) { 451 if (strcmp(".altinstructions", secstrs + s->sh_name) == 0)
452 apply_alternatives((void *)s->sh_addr, s->sh_size); 452 apply_alternatives_module((void *)s->sh_addr, s->sh_size);
453 }
454#ifdef CONFIG_ARM64_MODULE_PLTS 453#ifdef CONFIG_ARM64_MODULE_PLTS
455 if (IS_ENABLED(CONFIG_DYNAMIC_FTRACE) && 454 if (IS_ENABLED(CONFIG_DYNAMIC_FTRACE) &&
456 !strcmp(".text.ftrace_trampoline", secstrs + s->sh_name)) 455 !strcmp(".text.ftrace_trampoline", secstrs + s->sh_name))
diff --git a/drivers/perf/xgene_pmu.c b/drivers/perf/xgene_pmu.c
index 6bdb1dad805f..0e31f1392a53 100644
--- a/drivers/perf/xgene_pmu.c
+++ b/drivers/perf/xgene_pmu.c
@@ -1463,7 +1463,7 @@ static char *xgene_pmu_dev_name(struct device *dev, u32 type, int id)
1463 case PMU_TYPE_IOB: 1463 case PMU_TYPE_IOB:
1464 return devm_kasprintf(dev, GFP_KERNEL, "iob%d", id); 1464 return devm_kasprintf(dev, GFP_KERNEL, "iob%d", id);
1465 case PMU_TYPE_IOB_SLOW: 1465 case PMU_TYPE_IOB_SLOW:
1466 return devm_kasprintf(dev, GFP_KERNEL, "iob-slow%d", id); 1466 return devm_kasprintf(dev, GFP_KERNEL, "iob_slow%d", id);
1467 case PMU_TYPE_MCB: 1467 case PMU_TYPE_MCB:
1468 return devm_kasprintf(dev, GFP_KERNEL, "mcb%d", id); 1468 return devm_kasprintf(dev, GFP_KERNEL, "mcb%d", id);
1469 case PMU_TYPE_MC: 1469 case PMU_TYPE_MC: