summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDietmar Eggemann <dietmar.eggemann@arm.com>2012-05-03 12:55:22 +0100
committerDietmar Eggemann <dietmar.eggemann@arm.com>2012-05-23 12:44:34 +0100
commitf085e47d3dc30aefb0e25129537ab35de56b3265 (patch)
tree81e35bcefdafde4ee0f21b9b56b28f0d435aee23
parent4f48994f7037b257b7f48bd9574db09d119e7cc4 (diff)
downloadswitcher-f085e47d3dc30aefb0e25129537ab35de56b3265.tar.gz
Hide differences in I-cache Topology.
The virtualization of the L1 instruction cache is introduced by this patch. The A7 CPU has a VIPT L1 instruction cache with a cache line length of 32 bytes whereas the A15 CPU has a PIPT L1 instruction cache with a cache line length of 64 bytes. Virtualization of the L1 instruction cache does not follow the approach of the already existing virtualization of the data/unified caches where cache operations are virtualized on the host cluster to use the values of the target cluster. Instead, this patch guarantees that for L1 instruction cache operations on the A15 CPU, the CCSIDR value of the A7 is used. The ccsidr member of the structure cache_geometry is now a two dimensional array being able to hold the appropriate values for the instruction and the data/unified caches. In order to be able to trap cache identification registers on the A15 CPU, regardless if it is on the host or target cluster, the TID2 bit in the HCR register is set in the A15 CPU specific trap setup function a15_trap_handle() as well as restored in the A15 CPU specific trap restore function a15_trap_restore(). This is of course only done if the sibling CPU is an A7. The default CP15 trap function trap_cp15_mrc_mcr_handle(), which runs before the CPU specific trap functions, sets the L1 instruction cache CCSIDR value incorrectly on A7 and A15 for Virtualizer configuration [BC=x, TC=A15, HC=A7]. This error is corrected in the A7 or A15 CPU specific trap handle function. Signed-off-by: Dietmar Eggemann <dietmar.eggemann@arm.com>
-rw-r--r--big-little/include/misc.h2
-rw-r--r--big-little/virtualisor/cache_geom.c65
-rw-r--r--big-little/virtualisor/cpus/a15/a15.c102
-rw-r--r--big-little/virtualisor/cpus/a7/a7.c29
-rw-r--r--big-little/virtualisor/include/cache_geom.h33
-rw-r--r--big-little/virtualisor/virt_handle.c29
6 files changed, 202 insertions, 58 deletions
diff --git a/big-little/include/misc.h b/big-little/include/misc.h
index e1957aa..0b15d5a 100644
--- a/big-little/include/misc.h
+++ b/big-little/include/misc.h
@@ -347,6 +347,8 @@
#define SMC_SEC_SHUTDOWN 0x2
#define MAX_CACHE_LEVELS 0x8
+/* Data/unified and instruction cache */
+#define MAX_CACHE_VARIANTS 0x2
#define CRN_C0 0x0
#define CRN_C7 0x7
#define CRN_C9 0x9
diff --git a/big-little/virtualisor/cache_geom.c b/big-little/virtualisor/cache_geom.c
index 17c3ee6..7bcb42b 100644
--- a/big-little/virtualisor/cache_geom.c
+++ b/big-little/virtualisor/cache_geom.c
@@ -36,51 +36,50 @@ static unsigned cm_ignline_cnt[NUM_CPUS][MAX_CACHE_LEVELS] = { 0 };
static unsigned cm_extline_cnt[NUM_CPUS][MAX_CACHE_LEVELS] = { 0 };
/*
- * Iterate through all the implemented cache
- * levels and save the geometry at each level.
+ * Iterate through all the implemented cache levels and save the geometry at
+ * each level.
*
*/
void find_cache_geometry(cache_geometry * cg_ptr)
{
- unsigned ctr, clidr, ccsidr, csselr, old_csselr;
+ unsigned ctr, csselr;
- /* Save Cache size selection register */
- old_csselr = read_csselr();
- clidr = read_clidr();
- cg_ptr->clidr = clidr;
+ /* Save cache size selection register */
+ csselr = read_csselr();
- for (ctr = 0; ctr < MAX_CACHE_LEVELS; ctr++) {
- unsigned cache_type = get_cache_type(clidr, ctr);
+ cg_ptr->clidr = read_clidr();
- /* Only seperate and Unifiied caches */
- if (cache_type >= 0x3) {
- /*
- * Choose the cache level & Data or Unified cache
- * as there are no set/way operations on the ICache
- */
- csselr = ctr << 1;
- write_csselr(csselr);
+ for (ctr = 0; ctr < MAX_CACHE_LEVELS; ctr++) {
+ unsigned cache_type = get_cache_type(cg_ptr->clidr, ctr);
+ if (cache_type == 0x03) {
+ /* instruction cache */
+ write_csselr((ctr << 1) | CIND_INST);
isb();
-
+ cg_ptr->ccsidr[ctr][CIND_INST] = read_ccsidr();
+ /* data cache */
+ write_csselr(ctr << 1);
+ isb();
+ cg_ptr->ccsidr[ctr][CIND_DATA] = read_ccsidr();
+ }
+ else if (cache_type == 0x04) {
+ /* unified cache */
+ write_csselr(ctr << 1);
+ isb();
+ cg_ptr->ccsidr[ctr][CIND_UNIF] = read_ccsidr();
+ }
+ else {
/*
- * Read the CCSIDR to record information about this
- * cache level.
- */
- ccsidr = read_ccsidr();
- cg_ptr->ccsidr[ctr] = ccsidr;
-
- } else {
- /*
- * Stop scanning at the first invalid/unsupported
- * cache level
+ * Stop scanning at the first invalid/unsupported cache
+ * level
*/
break;
}
+
}
- /* Restore Cache size selection register */
- write_csselr(old_csselr);
+ /* Restore cache size selection register */
+ write_csselr(csselr);
return;
}
@@ -203,7 +202,7 @@ unsigned map_cache_geometries(cache_geometry * hcg_ptr,
/*
* Enable bit for trapping set/way operations &
- * Cache identification regs
+ * cache identification registers
*/
hcr = read_hcr();
hcr |= HCR_TSW | HCR_TID2;
@@ -212,7 +211,6 @@ unsigned map_cache_geometries(cache_geometry * hcg_ptr,
isb();
} else {
-
/* Find the cache geometry on the target cpu */
find_cache_geometry(tcg_ptr);
@@ -235,7 +233,8 @@ unsigned map_cache_geometries(cache_geometry * hcg_ptr,
void handle_cm_op(unsigned reg,
void (*op_handler) (unsigned),
cache_geometry * hcg_ptr,
- cache_geometry * tcg_ptr, cache_diff * cd_ptr)
+ cache_geometry * tcg_ptr,
+ cache_diff * cd_ptr)
{
unsigned clvl = 0, cpu_id = read_cpuid();
unsigned tc_assoc = 0, tc_numsets = 0, tc_linesz = 0;
diff --git a/big-little/virtualisor/cpus/a15/a15.c b/big-little/virtualisor/cpus/a15/a15.c
index 17c91a4..213ae67 100644
--- a/big-little/virtualisor/cpus/a15/a15.c
+++ b/big-little/virtualisor/cpus/a15/a15.c
@@ -22,17 +22,56 @@
#include "bl.h"
#include "virtualisor.h"
+#include "cache_geom.h"
#include "a15.h"
/* Forward declaration */
static virt_descriptor a15_virt_desc;
+extern cache_geometry host_cache_geometry[];
+extern cache_geometry target_cache_geometry[];
+
/*
- * Dummy functions for setting up any cpu
- * specific traps.
+ * Functions to handle, save, restore and setup any CPU specific traps.
*/
unsigned a15_trap_handle(gp_regs * regs, unsigned hsr, unsigned sibling_cpu)
{
+ /*
+ * Correct the L1 instruction cache CCSIDR value which was incorrectly
+ * set in the default CP15 trap handle function.
+ */
+ if (hsr >> 26 == TRAP_CP15_32) {
+ unsigned Op1, Op2, CRn, CRm, Rt, csselr, level, ind;
+
+ Op2 = (hsr >> 17) & 0x7;
+ Op1 = (hsr >> 14) & 0x7;
+ CRn = (hsr >> 10) & 0xf;
+ Rt = (hsr >> 5) & 0xf;
+ CRm = (hsr >> 1) & 0xf;
+
+ csselr = read_csselr();
+ level = get_cache_level(csselr);
+ ind = get_cache_ind(csselr);
+
+ if (CRn == CRN_C0 && Op1 == 1 && CRm == 0 && Op2 == CCSIDR &&
+ level == 0 && ind == CIND_INST) {
+ unsigned cpu_id = read_cpuid();
+
+ /*
+ * Initialize cg_ptr to host_cache_geometry for system
+ * configuration [BC=x, TC=A15, HC=A7] and to
+ * target_cache_geometry for Virtualizer configuration
+ * [BC=x, TC=A7, HC=A15]
+ */
+
+ cache_geometry * cg_ptr = (IS_TGT_CLUSTER) ?
+ &host_cache_geometry[cpu_id] :
+ &target_cache_geometry[cpu_id];
+
+ regs->r[Rt] = cg_ptr->ccsidr[level][ind];
+ }
+ }
+
return 0;
}
@@ -43,6 +82,22 @@ unsigned a15_trap_save(unsigned first_cpu, unsigned sibling_cpu)
unsigned a15_trap_restore(unsigned first_cpu, unsigned sibling_cpu)
{
+ if (sibling_cpu == A7) {
+ unsigned hcr = read_hcr();
+
+ /*
+ * Restore (enable) bit for trapping cache identification
+ * registers. This is a necessary step on Virtualizer
+ * configuration [BC=x, TC=A15, HC=A7] and a redundant
+ * step on Virtualizer configuration
+ * [BC=x, TC=A7, HC=A15].
+ */
+
+ hcr |= HCR_TID2;
+ write_hcr(hcr);
+ dsb();
+ isb();
+ }
return 0;
}
@@ -50,6 +105,49 @@ unsigned a15_trap_setup(unsigned first_cpu, unsigned sibling_cpu)
{
if (switcher) {
+ if (sibling_cpu == A7) {
+ unsigned hcr = read_hcr();
+
+ /*
+ * Initialize the L1 instruction cache CSSIDR value on
+ * the boot cluster statically because the Virtualizer
+ * relies on this information even before the
+ * counterpart cluster is initialized dynamically.
+ */
+
+ if (IS_BOOT_CLUSTER) {
+ unsigned cpu_id = read_cpuid();
+
+ /*
+ * Initialize cg_ptr to host_cache_geometry for
+ * Virtualizer configuration
+ * [BC=x, TC=A15, HC=A7] and to
+ * target_cache_geometry for Virtualizer
+ * configuration [BC=x, TC=A7, HC=A15].
+ */
+
+ cache_geometry * cg_ptr = (IS_TGT_CLUSTER) ?
+ &host_cache_geometry[cpu_id] :
+ &target_cache_geometry[cpu_id];
+
+
+ cg_ptr->ccsidr[0][CIND_INST] =
+ CACHE_A7_L1_INST_CCSIDR;
+ }
+
+ /*
+ * Enable bit for trapping cache identification
+ * registers. This is a necessary step on Virtualizer
+ * configuration [BC=x, TC=A15, HC=A7] and a redundant
+ * step on Virtualizer configuration
+ * [BC=x, TC=A7, HC=A15].
+ */
+
+ hcr |= HCR_TID2;
+ write_hcr(hcr);
+ dsb();
+ isb();
+ }
} else {
/* Always on */
}
diff --git a/big-little/virtualisor/cpus/a7/a7.c b/big-little/virtualisor/cpus/a7/a7.c
index e9e16af..d39f857 100644
--- a/big-little/virtualisor/cpus/a7/a7.c
+++ b/big-little/virtualisor/cpus/a7/a7.c
@@ -22,17 +22,42 @@
#include "bl.h"
#include "virtualisor.h"
+#include "cache_geom.h"
#include "a7.h"
/* Forward declaration */
static virt_descriptor a7_virt_desc;
+extern cache_geometry host_cache_geometry[];
+extern cache_geometry target_cache_geometry[];
+
/*
- * Dummy functions for setting up any cpu
- * specific traps.
+ * Functions to handle, save, restore and setup any CPU specific traps.
*/
unsigned a7_trap_handle(gp_regs * regs, unsigned hsr, unsigned sibling_cpu)
{
+ /*
+ * Correct the L1 instruction cache CCSIDR value which was incorrectly
+ * set in the default CP15 trap handle function.
+ */
+ if (hsr >> 26 == TRAP_CP15_32) {
+ unsigned Op1, Op2, CRn, CRm, Rt, csselr, level, ind;
+
+ Op2 = (hsr >> 17) & 0x7;
+ Op1 = (hsr >> 14) & 0x7;
+ CRn = (hsr >> 10) & 0xf;
+ Rt = (hsr >> 5) & 0xf;
+ CRm = (hsr >> 1) & 0xf;
+
+ csselr = read_csselr();
+ level = get_cache_level(csselr);
+ ind = get_cache_ind(csselr);
+
+ if (CRn == CRN_C0 && Op1 == 1 && CRm == 0 && Op2 == CCSIDR &&
+ level == 0 && ind == CIND_INST)
+ regs->r[Rt] = read_ccsidr();
+ }
+
return 0;
}
diff --git a/big-little/virtualisor/include/cache_geom.h b/big-little/virtualisor/include/cache_geom.h
index 654a0f0..f162337 100644
--- a/big-little/virtualisor/include/cache_geom.h
+++ b/big-little/virtualisor/include/cache_geom.h
@@ -23,19 +23,28 @@
#ifndef __CACHE_GEOM_H__
#define __CACHE_GEOM_H__
-#define MAX_CACHE_LEVELS 0x8
+#include "misc.h"
/* Target cpu cache relative to host cpu cache size */
#define TCSZ_EQUAL 0x0
#define TCSZ_SMALL 0x1
#define TCSZ_BIG 0x2
+/* Cache Instruction not Data bit, CSSELR[0] */
+#define CIND_DATA 0x0 /* Data cache */
+#define CIND_UNIF CIND_DATA /* Unified cache */
+#define CIND_INST 0x1 /* Instruction cache */
+
+/* A7 L1 instruction cache CCSIDR value */
+#define CACHE_A7_L1_INST_CCSIDR 0x203FE009
+
#define get_setway_reg(a, b , c, d, e) ((a << __clz(b)) | (c << (d + 4)) | (e << 1))
#define get_cache_type(clidr, lvl) ((clidr >> (lvl * 0x3)) & 0x7)
-#define get_cache_level(reg) (reg >> 1) & 0x7
-#define get_cache_linesz(cg, lvl) (cg->ccsidr[lvl] & 0x7)
-#define get_cache_assoc(cg, lvl) ((cg->ccsidr[lvl] >> 3) & 0x3ff)
-#define get_cache_numsets(cg, lvl) ((cg->ccsidr[lvl] >> 13) & 0x7fff)
+#define get_cache_level(reg) ((reg >> 1) & 0x7)
+#define get_cache_ind(reg) (reg & 0x1)
+#define get_cache_linesz(cg, lvl) (cg->ccsidr[lvl][CIND_DATA] & 0x7)
+#define get_cache_assoc(cg, lvl) ((cg->ccsidr[lvl][CIND_DATA] >> 3) & 0x3ff)
+#define get_cache_numsets(cg, lvl) ((cg->ccsidr[lvl][CIND_DATA] >> 13) & 0x7fff)
/*
* Data structure that stores the foreseeable differences
@@ -76,8 +85,8 @@ typedef struct cache_geom {
* the OS thinks its operating on.
*/
unsigned csselr;
- /* One for each cache level */
- unsigned ccsidr[MAX_CACHE_LEVELS];
+ /* One for each cache level and variant */
+ unsigned ccsidr[MAX_CACHE_LEVELS][MAX_CACHE_VARIANTS];
} cache_geometry;
/*
@@ -91,12 +100,12 @@ typedef struct cache_stats {
unsigned cmpl_cmop_cnt;
} cache_stats;
-extern unsigned map_cache_geometries(cache_geometry *,
- cache_geometry *, cache_diff *);
+extern unsigned map_cache_geometries(cache_geometry *, cache_geometry *,
+ cache_diff *);
extern void find_cache_geometry(cache_geometry *);
extern void find_cache_diff(cache_geometry *, cache_geometry *, cache_diff *);
-extern void handle_cm_op(unsigned,
- void (*)(unsigned),
- cache_geometry *, cache_geometry *, cache_diff *);
+extern void handle_cm_op(unsigned, void (*)(unsigned), cache_geometry *,
+ cache_geometry *, cache_diff *);
+//extern void stat_init_host_cache_geometry(cache_geometry *);
#endif /* __CACHE_GEOM_H__ */
diff --git a/big-little/virtualisor/virt_handle.c b/big-little/virtualisor/virt_handle.c
index 092af67..da163cf 100644
--- a/big-little/virtualisor/virt_handle.c
+++ b/big-little/virtualisor/virt_handle.c
@@ -180,20 +180,32 @@ void trap_cp15_mrc_mcr_handle(unsigned hsr, gp_regs * regs)
switch (CRm) {
case 0:
switch (Op2) {
+ unsigned csselr, level, ind;
case CCSIDR:
if (write)
goto error;
+ /*
+ * The L1 instruction cache CCSIDR
+ * value is incorrectly set on A7 and
+ * A15 for Virtualizer configuration
+ * [BC=x, TC=A15, HC=A7].
+ * The error is later corrected in the
+ * A7 or A15 specific trap function.
+ */
+ csselr = target_cache_geometry[cpu_id].
+ csselr;
+ level = get_cache_level(csselr);
+ ind = get_cache_ind(csselr);
regs->r[Rt] =
- target_cache_geometry[cpu_id].ccsidr
- [get_cache_level
- (target_cache_geometry
- [cpu_id].csselr)];
+ target_cache_geometry[cpu_id].
+ ccsidr[level][ind];
break;
case CLIDR:
if (write)
goto error;
regs->r[Rt] =
- target_cache_geometry[cpu_id].clidr;
+ target_cache_geometry[cpu_id].
+ clidr;
break;
case AIDR:
if (write)
@@ -215,14 +227,13 @@ void trap_cp15_mrc_mcr_handle(unsigned hsr, gp_regs * regs)
case CSSELR:
if (write) {
target_cache_geometry
- [cpu_id].csselr =
- regs->r[Rt];
+ [cpu_id].csselr = regs->r[Rt];
write_csselr(regs->r[Rt]);
}
else
regs->r[Rt] =
- target_cache_geometry
- [cpu_id].csselr;
+ target_cache_geometry
+ [cpu_id].csselr;
break;
default:
goto error;