Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 0d55ec6f authored by Linus Torvalds's avatar Linus Torvalds
Browse files
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
parents 44813aa6 24fe1b0e
Loading
Loading
Loading
Loading
+6 −1
Original line number Original line Diff line number Diff line
@@ -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           */ \
+1 −5
Original line number Original line Diff line number Diff line
@@ -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)
+44 −7
Original line number Original line Diff line number Diff line
@@ -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(&region, true);
		__apply_alternatives(&region, 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(&region, false);
	__apply_alternatives(&region, true);
}
}
#endif
+2 −3
Original line number Original line Diff line number Diff line
@@ -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))
+1 −1
Original line number Original line Diff line number Diff line
@@ -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: