mirror of https://gitee.com/openkylin/linux.git
arm64 fixes:
- 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 -----BEGIN PGP SIGNATURE----- iQIzBAABCAAdFiEE5RElWfyWxS+3PLO2a9axLQDIXvEFAls2afgACgkQa9axLQDI XvGITQ/9GoXffHxAn71oIQRxP+b0xTQ9JmH76/jcD/S4B3/wRynl5xY6nbU6WFLP r7D9ORXfMhNkQvfLt1GZcTCQzMEnhZ41hUUlNJ1+qy3taKVV45rTLU7zIRAN5h4C rhWwRzCYggZpd8XojnU6XfOUKKUx6NSlRYfrXteY7JmEiZFfg98fOleJjSWPTtOB dgqswx976kr2fdJ5R0uRG9+K8UlpEB2YrQDZsI1CFUf+CCig90WaWKTL45IksSYs ArjFGjiao74d5+9HvhR7S9mg87Gj7Ym6K7TlhKYiJ86wGoaxslHXXiZgX1zP/Gb+ PSKvlO6kkZLYBmSqeOAvRVPrdzW+V+oFG+XkBXiRZXgeDvYsf6Ug9bwpjJ9wo+un +aOorLF9IE+jlz7cclA+A4BywQYP7hAWomcLcYBRxFLCinu0G8eX0MIOUR6XDgzr jVWkaVgBAL25bFY3sE9QpF3nffqcyu50pvBDxM0TzE5+H9QxxyHMpDcud85MFO6l cxuXj/AnZVxplcaGkKFOrGM9CslZfZ1txuwRU/1P5J00HN82ORhlOLfnpd6B45ET VoHUrpQZB7FpLRQlT7dBKGbpU2Xq7I9JP901wo5f4Psd/25ouqp3sRBRWb0hzXCQ 0LJIS3Rt7KZ+w44NhU6Bk4Y9aqKvNqga8/gUcs4h8rwf+07MjBk= =211T -----END PGP SIGNATURE----- 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
This commit is contained in:
commit
0d55ec6f3e
|
@ -28,7 +28,12 @@ typedef void (*alternative_cb_t)(struct alt_instr *alt,
|
||||||
__le32 *origptr, __le32 *updptr, int nr_inst);
|
__le32 *origptr, __le32 *updptr, int nr_inst);
|
||||||
|
|
||||||
void __init apply_alternatives_all(void);
|
void __init apply_alternatives_all(void);
|
||||||
void apply_alternatives(void *start, size_t length);
|
|
||||||
|
#ifdef CONFIG_MODULES
|
||||||
|
void apply_alternatives_module(void *start, size_t length);
|
||||||
|
#else
|
||||||
|
static inline void apply_alternatives_module(void *start, size_t length) { }
|
||||||
|
#endif
|
||||||
|
|
||||||
#define ALTINSTR_ENTRY(feature,cb) \
|
#define ALTINSTR_ENTRY(feature,cb) \
|
||||||
" .word 661b - .\n" /* label */ \
|
" .word 661b - .\n" /* label */ \
|
||||||
|
|
|
@ -224,10 +224,8 @@ static inline void set_pte(pte_t *ptep, pte_t pte)
|
||||||
* Only if the new pte is valid and kernel, otherwise TLB maintenance
|
* Only if the new pte is valid and kernel, otherwise TLB maintenance
|
||||||
* or update_mmu_cache() have the necessary barriers.
|
* or update_mmu_cache() have the necessary barriers.
|
||||||
*/
|
*/
|
||||||
if (pte_valid_not_user(pte)) {
|
if (pte_valid_not_user(pte))
|
||||||
dsb(ishst);
|
dsb(ishst);
|
||||||
isb();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
extern void __sync_icache_dcache(pte_t pteval);
|
extern void __sync_icache_dcache(pte_t pteval);
|
||||||
|
@ -434,7 +432,6 @@ static inline void set_pmd(pmd_t *pmdp, pmd_t pmd)
|
||||||
{
|
{
|
||||||
WRITE_ONCE(*pmdp, pmd);
|
WRITE_ONCE(*pmdp, pmd);
|
||||||
dsb(ishst);
|
dsb(ishst);
|
||||||
isb();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void pmd_clear(pmd_t *pmdp)
|
static inline void pmd_clear(pmd_t *pmdp)
|
||||||
|
@ -485,7 +482,6 @@ static inline void set_pud(pud_t *pudp, pud_t pud)
|
||||||
{
|
{
|
||||||
WRITE_ONCE(*pudp, pud);
|
WRITE_ONCE(*pudp, pud);
|
||||||
dsb(ishst);
|
dsb(ishst);
|
||||||
isb();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void pud_clear(pud_t *pudp)
|
static inline void pud_clear(pud_t *pudp)
|
||||||
|
|
|
@ -122,7 +122,30 @@ static void patch_alternative(struct alt_instr *alt,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void __apply_alternatives(void *alt_region, bool use_linear_alias)
|
/*
|
||||||
|
* We provide our own, private D-cache cleaning function so that we don't
|
||||||
|
* accidentally call into the cache.S code, which is patched by us at
|
||||||
|
* runtime.
|
||||||
|
*/
|
||||||
|
static void clean_dcache_range_nopatch(u64 start, u64 end)
|
||||||
|
{
|
||||||
|
u64 cur, d_size, ctr_el0;
|
||||||
|
|
||||||
|
ctr_el0 = read_sanitised_ftr_reg(SYS_CTR_EL0);
|
||||||
|
d_size = 4 << cpuid_feature_extract_unsigned_field(ctr_el0,
|
||||||
|
CTR_DMINLINE_SHIFT);
|
||||||
|
cur = start & ~(d_size - 1);
|
||||||
|
do {
|
||||||
|
/*
|
||||||
|
* We must clean+invalidate to the PoC in order to avoid
|
||||||
|
* Cortex-A53 errata 826319, 827319, 824069 and 819472
|
||||||
|
* (this corresponds to ARM64_WORKAROUND_CLEAN_CACHE)
|
||||||
|
*/
|
||||||
|
asm volatile("dc civac, %0" : : "r" (cur) : "memory");
|
||||||
|
} while (cur += d_size, cur < end);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void __apply_alternatives(void *alt_region, bool is_module)
|
||||||
{
|
{
|
||||||
struct alt_instr *alt;
|
struct alt_instr *alt;
|
||||||
struct alt_region *region = alt_region;
|
struct alt_region *region = alt_region;
|
||||||
|
@ -145,7 +168,7 @@ static void __apply_alternatives(void *alt_region, bool use_linear_alias)
|
||||||
pr_info_once("patching kernel code\n");
|
pr_info_once("patching kernel code\n");
|
||||||
|
|
||||||
origptr = ALT_ORIG_PTR(alt);
|
origptr = ALT_ORIG_PTR(alt);
|
||||||
updptr = use_linear_alias ? lm_alias(origptr) : origptr;
|
updptr = is_module ? origptr : lm_alias(origptr);
|
||||||
nr_inst = alt->orig_len / AARCH64_INSN_SIZE;
|
nr_inst = alt->orig_len / AARCH64_INSN_SIZE;
|
||||||
|
|
||||||
if (alt->cpufeature < ARM64_CB_PATCH)
|
if (alt->cpufeature < ARM64_CB_PATCH)
|
||||||
|
@ -155,8 +178,20 @@ static void __apply_alternatives(void *alt_region, bool use_linear_alias)
|
||||||
|
|
||||||
alt_cb(alt, origptr, updptr, nr_inst);
|
alt_cb(alt, origptr, updptr, nr_inst);
|
||||||
|
|
||||||
flush_icache_range((uintptr_t)origptr,
|
if (!is_module) {
|
||||||
(uintptr_t)(origptr + nr_inst));
|
clean_dcache_range_nopatch((u64)origptr,
|
||||||
|
(u64)(origptr + nr_inst));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The core module code takes care of cache maintenance in
|
||||||
|
* flush_module_icache().
|
||||||
|
*/
|
||||||
|
if (!is_module) {
|
||||||
|
dsb(ish);
|
||||||
|
__flush_icache_all();
|
||||||
|
isb();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -178,7 +213,7 @@ static int __apply_alternatives_multi_stop(void *unused)
|
||||||
isb();
|
isb();
|
||||||
} else {
|
} else {
|
||||||
BUG_ON(alternatives_applied);
|
BUG_ON(alternatives_applied);
|
||||||
__apply_alternatives(®ion, true);
|
__apply_alternatives(®ion, false);
|
||||||
/* Barriers provided by the cache flushing */
|
/* Barriers provided by the cache flushing */
|
||||||
WRITE_ONCE(alternatives_applied, 1);
|
WRITE_ONCE(alternatives_applied, 1);
|
||||||
}
|
}
|
||||||
|
@ -192,12 +227,14 @@ void __init apply_alternatives_all(void)
|
||||||
stop_machine(__apply_alternatives_multi_stop, NULL, cpu_online_mask);
|
stop_machine(__apply_alternatives_multi_stop, NULL, cpu_online_mask);
|
||||||
}
|
}
|
||||||
|
|
||||||
void apply_alternatives(void *start, size_t length)
|
#ifdef CONFIG_MODULES
|
||||||
|
void apply_alternatives_module(void *start, size_t length)
|
||||||
{
|
{
|
||||||
struct alt_region region = {
|
struct alt_region region = {
|
||||||
.begin = start,
|
.begin = start,
|
||||||
.end = start + length,
|
.end = start + length,
|
||||||
};
|
};
|
||||||
|
|
||||||
__apply_alternatives(®ion, false);
|
__apply_alternatives(®ion, true);
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
|
@ -448,9 +448,8 @@ int module_finalize(const Elf_Ehdr *hdr,
|
||||||
const char *secstrs = (void *)hdr + sechdrs[hdr->e_shstrndx].sh_offset;
|
const char *secstrs = (void *)hdr + sechdrs[hdr->e_shstrndx].sh_offset;
|
||||||
|
|
||||||
for (s = sechdrs, se = sechdrs + hdr->e_shnum; s < se; s++) {
|
for (s = sechdrs, se = sechdrs + hdr->e_shnum; s < se; s++) {
|
||||||
if (strcmp(".altinstructions", secstrs + s->sh_name) == 0) {
|
if (strcmp(".altinstructions", secstrs + s->sh_name) == 0)
|
||||||
apply_alternatives((void *)s->sh_addr, s->sh_size);
|
apply_alternatives_module((void *)s->sh_addr, s->sh_size);
|
||||||
}
|
|
||||||
#ifdef CONFIG_ARM64_MODULE_PLTS
|
#ifdef CONFIG_ARM64_MODULE_PLTS
|
||||||
if (IS_ENABLED(CONFIG_DYNAMIC_FTRACE) &&
|
if (IS_ENABLED(CONFIG_DYNAMIC_FTRACE) &&
|
||||||
!strcmp(".text.ftrace_trampoline", secstrs + s->sh_name))
|
!strcmp(".text.ftrace_trampoline", secstrs + s->sh_name))
|
||||||
|
|
|
@ -1463,7 +1463,7 @@ static char *xgene_pmu_dev_name(struct device *dev, u32 type, int id)
|
||||||
case PMU_TYPE_IOB:
|
case PMU_TYPE_IOB:
|
||||||
return devm_kasprintf(dev, GFP_KERNEL, "iob%d", id);
|
return devm_kasprintf(dev, GFP_KERNEL, "iob%d", id);
|
||||||
case PMU_TYPE_IOB_SLOW:
|
case PMU_TYPE_IOB_SLOW:
|
||||||
return devm_kasprintf(dev, GFP_KERNEL, "iob-slow%d", id);
|
return devm_kasprintf(dev, GFP_KERNEL, "iob_slow%d", id);
|
||||||
case PMU_TYPE_MCB:
|
case PMU_TYPE_MCB:
|
||||||
return devm_kasprintf(dev, GFP_KERNEL, "mcb%d", id);
|
return devm_kasprintf(dev, GFP_KERNEL, "mcb%d", id);
|
||||||
case PMU_TYPE_MC:
|
case PMU_TYPE_MC:
|
||||||
|
|
Loading…
Reference in New Issue