Skip to content

Commit

Permalink
arm64: cachetype: report weakest cache policy
Browse files Browse the repository at this point in the history
In big.LITTLE systems, the I-cache policy may differ across CPUs, and
thus we must always meet the most stringent maintenance requirements of
any I-cache in the system when performing maintenance to ensure
correctness. Unfortunately this requirement is not met as we always look
at the current CPU's cache type register to determine the maintenance
requirements.

This patch causes the I-cache policy of all CPUs to be taken into
account for icache_is_aliasing and icache_is_aivivt. If any I-cache in
the system is aliasing or AIVIVT, the respective function will return
true. At boot each CPU may set flags to identify that at least one
I-cache in the system is aliasing and/or AIVIVT.

The now unused and potentially misleading icache_policy function is
removed.

Signed-off-by: Mark Rutland <mark.rutland@arm.com>
Acked-by: Will Deacon <will.deacon@arm.com>
Reviewed-by: Will Deacon <will.deacon@arm.com>
Reviewed-by: Catalin Marinas <catalin.marinas@arm.com>
Signed-off-by: Catalin Marinas <catalin.marinas@arm.com>
  • Loading branch information
Mark Rutland authored and Catalin Marinas committed Jul 18, 2014
1 parent df85741 commit 59ccc0d
Show file tree
Hide file tree
Showing 2 changed files with 36 additions and 6 deletions.
16 changes: 10 additions & 6 deletions arch/arm64/include/asm/cachetype.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,23 +30,27 @@

#ifndef __ASSEMBLY__

static inline u32 icache_policy(void)
{
return (read_cpuid_cachetype() >> CTR_L1IP_SHIFT) & CTR_L1IP_MASK;
}
#include <linux/bitops.h>

#define CTR_L1IP(ctr) (((ctr) >> CTR_L1IP_SHIFT) & CTR_L1IP_MASK)

#define ICACHEF_ALIASING BIT(0)
#define ICACHEF_AIVIVT BIT(1)

extern unsigned long __icache_flags;

/*
* Whilst the D-side always behaves as PIPT on AArch64, aliasing is
* permitted in the I-cache.
*/
static inline int icache_is_aliasing(void)
{
return icache_policy() != ICACHE_POLICY_PIPT;
return test_bit(ICACHEF_ALIASING, &__icache_flags);
}

static inline int icache_is_aivivt(void)
{
return icache_policy() == ICACHE_POLICY_AIVIVT;
return test_bit(ICACHEF_AIVIVT, &__icache_flags);
}

static inline u32 cache_type_cwg(void)
Expand Down
26 changes: 26 additions & 0 deletions arch/arm64/kernel/cpuinfo.c
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,9 @@
#include <asm/cpu.h>
#include <asm/cputype.h>

#include <linux/bitops.h>
#include <linux/init.h>
#include <linux/printk.h>
#include <linux/smp.h>

/*
Expand All @@ -30,6 +32,28 @@
DEFINE_PER_CPU(struct cpuinfo_arm64, cpu_data);
static struct cpuinfo_arm64 boot_cpu_data;

static char *icache_policy_str[] = {
[ICACHE_POLICY_RESERVED] = "RESERVED/UNKNOWN",
[ICACHE_POLICY_AIVIVT] = "AIVIVT",
[ICACHE_POLICY_VIPT] = "VIPT",
[ICACHE_POLICY_PIPT] = "PIPT",
};

unsigned long __icache_flags;

static void cpuinfo_detect_icache_policy(struct cpuinfo_arm64 *info)
{
unsigned int cpu = smp_processor_id();
u32 l1ip = CTR_L1IP(info->reg_ctr);

if (l1ip != ICACHE_POLICY_PIPT)
set_bit(ICACHEF_ALIASING, &__icache_flags);
if (l1ip == ICACHE_POLICY_AIVIVT);
set_bit(ICACHEF_AIVIVT, &__icache_flags);

pr_info("Detected %s I-cache on CPU%d", icache_policy_str[l1ip], cpu);
}

static void __cpuinfo_store_cpu(struct cpuinfo_arm64 *info)
{
info->reg_cntfrq = arch_timer_get_cntfrq();
Expand All @@ -56,6 +80,8 @@ static void __cpuinfo_store_cpu(struct cpuinfo_arm64 *info)
info->reg_id_mmfr3 = read_cpuid(ID_MMFR3_EL1);
info->reg_id_pfr0 = read_cpuid(ID_PFR0_EL1);
info->reg_id_pfr1 = read_cpuid(ID_PFR1_EL1);

cpuinfo_detect_icache_policy(info);
}

void cpuinfo_store_cpu(void)
Expand Down

0 comments on commit 59ccc0d

Please sign in to comment.