Commit fa2ce169 authored by James Morse's avatar James Morse Committed by Wupeng Ma
Browse files

arm64: cpufeature: Enable PBHA bits for stage1

maillist inclusion
category: feature
bugzilla: https://gitee.com/openeuler/kernel/issues/I7ZC0H

Reference: https://lore.kernel.org/all/20211015161416.2196-1-james.morse@arm.com/t/#u



--------------------------------

If the CPUs support HPDS2, and there is a DT description of PBHA values
that only affect performance, enable those bits for both TTBR0 and TTBR1.

Enabling PBHA requires the hierarchical-permissions to be disabled.
Commit 87143f40 ("arm64: mm: use XN table mapping attributes for
the linear region") used these, but only as an optimisation.

Only the necessary PBHA bits are enabled to reduce the risk of an
unsafe bit/value being used by accident.

Signed-off-by: default avatarJames Morse <james.morse@arm.com>
Signed-off-by: default avatarMa Wupeng <mawupeng1@huawei.com>
parent 41987e13
Loading
Loading
Loading
Loading
+13 −0
Original line number Diff line number Diff line
@@ -1691,6 +1691,19 @@ config ARM64_CNP
	  at runtime, and does not affect PEs that do not implement
	  this feature.

config ARM64_PBHA
	bool "Enable support for Page Based Hardware Attributes (PBHA)"
	default n
	help
	  Page Based Hardware Attributes (PBHA) allow the SoC hardware to
	  change behaviour depending on which mapping was used to access
	  a page of memory. e.g. access via one mapping may always result
	  in the data being cached, whereas using another mapping of the same
	  physical memory.

	  The behaviour of each PBHA bit is not defined. Say no unless you
	  are very sure you want this

endmenu

menu "ARMv8.3 architectural features"
+1 −0
Original line number Diff line number Diff line
@@ -77,6 +77,7 @@
#define ARM64_WORKAROUND_HISILICON_ERRATUM_162100125	69
#define ARM64_HAS_LDAPR                         70
#define ARM64_HAS_PBHA				71
#define ARM64_HAS_PBHA_STAGE1			72

#define ARM64_NCAPS				80

+4 −0
Original line number Diff line number Diff line
@@ -260,6 +260,10 @@
#define TCR_TBI1		(UL(1) << 38)
#define TCR_HA			(UL(1) << 39)
#define TCR_HD			(UL(1) << 40)
#define TCR_HPD0		(UL(1) << 41)
#define TCR_HPD1		(UL(1) << 42)
#define TCR_HWU0nn_MASK		(UL(0xf) << 43)
#define TCR_HWU1nn_MASK		(UL(0xf) << 47)
#define TCR_NFD0		(UL(1) << 53)
#define TCR_NFD1		(UL(1) << 54)
#define TCR_E0PD0		(UL(1) << 55)
+81 −0
Original line number Diff line number Diff line
@@ -70,6 +70,7 @@
#include <linux/stop_machine.h>
#include <linux/types.h>
#include <linux/mm.h>
#include <linux/of.h>
#include <linux/cpu.h>

#include <asm/cpu.h>
@@ -110,6 +111,8 @@ EXPORT_SYMBOL(arm64_use_ng_mappings);

DEFINE_PER_CPU_READ_MOSTLY(const char *, this_cpu_vector) = vectors;

unsigned long __ro_after_init arm64_pbha_perf_only_values;

/*
 * Flag to indicate if we have computed the system wide
 * capabilities based on the boot time active CPUs. This
@@ -1574,6 +1577,71 @@ static bool has_hw_dbm(const struct arm64_cpu_capabilities *cap,

#endif

#ifdef CONFIG_ARM64_PBHA
static u8 pbha_stage1_enable_bits;

static bool plat_can_use_pbha_stage1(const struct arm64_cpu_capabilities *cap,
				     int scope)
{
	u8 val;
	struct device_node *cpus;
	const u8 *perf_only_vals;
	int num_perf_only_vals, i;

	if (!has_cpuid_feature(cap, scope))
		return false;

	/*
	 * Calls with scope == SCOPE_LOCAL_CPU need only testing whether this
	 * cpu has the feature. A later 'system' scope call will check for a
	 * firmware description.
	 */
	if (scope == SCOPE_LOCAL_CPU)
		return true;

	cpus = of_find_node_by_path("/cpus");
	if (!cpus)
		goto done;

	perf_only_vals = of_get_property(cpus, "arm,pbha-performance-only",
					 &num_perf_only_vals);
	if (!perf_only_vals)
		goto done;

	/* any listed value is usable at stage 1 */
	for (i = 0 ; i < num_perf_only_vals; i++) {
		val = perf_only_vals[i];
		if (val > 0xf)
			continue;

		pbha_stage1_enable_bits |= val;
		set_bit(val, &arm64_pbha_perf_only_values);
	}

done:
	of_node_put(cpus);

	return !!pbha_stage1_enable_bits;
}

static void cpu_enable_pbha(struct arm64_cpu_capabilities const *cap)
{
	u64 tcr;

	if (!pbha_stage1_enable_bits)
		return;

	tcr = read_sysreg(tcr_el1);
	tcr |= FIELD_PREP(TCR_HWU0nn_MASK, pbha_stage1_enable_bits);
	tcr |= FIELD_PREP(TCR_HWU1nn_MASK, pbha_stage1_enable_bits);
	tcr |= FIELD_PREP(TCR_HPD0, 1) | FIELD_PREP(TCR_HPD1, 1);

	write_sysreg(tcr, tcr_el1);
	isb();
	local_flush_tlb_all();
}
#endif /* CONFIG_ARM64_PBHA */

#ifdef CONFIG_ARM64_AMU_EXTN

/*
@@ -2304,6 +2372,19 @@ static const struct arm64_cpu_capabilities arm64_features[] = {
		.matches = has_cpuid_feature,
		.min_field_value = 2,
	},
#ifdef CONFIG_ARM64_PBHA
	{
		.desc = "Page Based Hardware Attributes (PBHA)",
		.capability = ARM64_HAS_PBHA_STAGE1,
		.type = ARM64_CPUCAP_SYSTEM_FEATURE,
		.sys_reg = SYS_ID_AA64MMFR1_EL1,
		.sign = FTR_UNSIGNED,
		.field_pos = ID_AA64MMFR1_HPD_SHIFT,
		.matches = plat_can_use_pbha_stage1,
		.min_field_value = 2,
		.cpu_enable = cpu_enable_pbha,
	},
#endif
	{},
};