[PATCH 2/2] ARM: kernel: add outer cache support for cacheinfo implementation
Sudeep Holla
sudeep.holla at arm.com
Mon Feb 23 10:28:11 PST 2015
In order to support outer cache in the cacheinfo infrastructure, a new
function 'get_info' is added to outer_cache_fns. This function is used
to get the outer cache information namely: line size, number of ways of
associativity and number of sets.
This patch adds 'get_info' supports to all L2 cache implementations on
ARM except Marvell's Feroceon L2 cache.
Signed-off-by: Sudeep Holla <sudeep.holla at arm.com>
Cc: Russell King <linux at arm.linux.org.uk>
Cc: Will Deacon <will.deacon at arm.com>
Cc: linux-arm-kernel at lists.infradead.org
---
arch/arm/include/asm/outercache.h | 9 +++++++++
arch/arm/kernel/cacheinfo.c | 14 +++++++++++++-
arch/arm/mm/cache-l2x0.c | 35 ++++++++++++++++++++++++++++++++++-
arch/arm/mm/cache-tauros2.c | 36 ++++++++++++++++++++++++++++++++++++
arch/arm/mm/cache-xsc3l2.c | 17 +++++++++++++++++
5 files changed, 109 insertions(+), 2 deletions(-)
diff --git a/arch/arm/include/asm/outercache.h b/arch/arm/include/asm/outercache.h
index 563b92fc2f41..ba16c7e1661d 100644
--- a/arch/arm/include/asm/outercache.h
+++ b/arch/arm/include/asm/outercache.h
@@ -25,7 +25,10 @@
struct l2x0_regs;
+struct cacheinfo;
+
struct outer_cache_fns {
+ void (*get_info)(struct cacheinfo *);
void (*inv_range)(unsigned long, unsigned long);
void (*clean_range)(unsigned long, unsigned long);
void (*flush_range)(unsigned long, unsigned long);
@@ -115,6 +118,11 @@ static inline void outer_resume(void)
outer_cache.resume();
}
+static inline void outer_get_info(struct cacheinfo *this_leaf)
+{
+ if (outer_cache.get_info)
+ outer_cache.get_info(this_leaf);
+}
#else
static inline void outer_inv_range(phys_addr_t start, phys_addr_t end)
@@ -126,6 +134,7 @@ static inline void outer_flush_range(phys_addr_t start, phys_addr_t end)
static inline void outer_flush_all(void) { }
static inline void outer_disable(void) { }
static inline void outer_resume(void) { }
+static inline void outer_get_info(struct cacheinfo *this_leaf) { }
#endif
diff --git a/arch/arm/kernel/cacheinfo.c b/arch/arm/kernel/cacheinfo.c
index 0c4a67dcbcaf..c6c32fdb037e 100644
--- a/arch/arm/kernel/cacheinfo.c
+++ b/arch/arm/kernel/cacheinfo.c
@@ -24,6 +24,7 @@
#include <linux/of.h>
#include <asm/cputype.h>
+#include <asm/outercache.h>
#include <asm/processor.h>
#include <asm/system_info.h>
@@ -227,11 +228,19 @@ static inline enum cache_type get_cache_type(int level)
return __get_cache_type(level);
}
+static inline void __outer_ci_leaf_init(struct cacheinfo *this_leaf)
+{
+ outer_get_info(this_leaf);
+ BUG_ON(this_leaf->type == CACHE_TYPE_SEPARATE);
+}
+
static void ci_leaf_init(struct cacheinfo *this_leaf,
enum cache_type type, unsigned int level)
{
this_leaf->level = level;
- if (cache_is_armv7())
+ if (type == CACHE_TYPE_NOCACHE) /* must be outer cache */
+ __outer_ci_leaf_init(this_leaf);
+ else if (cache_is_armv7())
__armv7_ci_leaf_init(type, this_leaf);
else
__ci_leaf_init(type, this_leaf);
@@ -255,6 +264,9 @@ static int __init_cache_level(unsigned int cpu)
this_cpu_ci->num_levels = level;
this_cpu_ci->num_leaves = leaves;
+ if (IS_ENABLED(CONFIG_OUTER_CACHE) && outer_cache.get_info)
+ this_cpu_ci->num_leaves++, this_cpu_ci->num_levels++;
+
return 0;
}
diff --git a/arch/arm/mm/cache-l2x0.c b/arch/arm/mm/cache-l2x0.c
index c6c7696b8db9..9955635a1c77 100644
--- a/arch/arm/mm/cache-l2x0.c
+++ b/arch/arm/mm/cache-l2x0.c
@@ -17,6 +17,7 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <linux/cpu.h>
+#include <linux/cacheinfo.h>
#include <linux/err.h>
#include <linux/init.h>
#include <linux/smp.h>
@@ -121,6 +122,22 @@ static void l2c_configure(void __iomem *base)
l2c_write_sec(l2x0_saved_regs.aux_ctrl, base, L2X0_AUX_CTRL);
}
+static void __l2x0_getinfo(struct cacheinfo *this_leaf)
+{
+ unsigned int assoc = get_count_order(l2x0_way_mask);
+
+ this_leaf->size = l2x0_size;
+ this_leaf->coherency_line_size = CACHE_LINE_SIZE;
+ this_leaf->ways_of_associativity = assoc;
+ this_leaf->number_of_sets = l2x0_size / (assoc * CACHE_LINE_SIZE);
+}
+
+static void l2x0_getinfo(struct cacheinfo *this_leaf)
+{
+ this_leaf->type = CACHE_TYPE_UNIFIED;
+ __l2x0_getinfo(this_leaf);
+}
+
/*
* Enable the L2 cache controller. This function must only be
* called when the cache controller is known to be disabled.
@@ -260,6 +277,7 @@ static const struct l2c_init_data l2c210_data __initconst = {
.disable = l2c_disable,
.sync = l2c210_sync,
.resume = l2c_resume,
+ .get_info = l2x0_getinfo,
},
};
@@ -417,6 +435,7 @@ static const struct l2c_init_data l2c220_data = {
.disable = l2c_disable,
.sync = l2c220_sync,
.resume = l2c_resume,
+ .get_info = l2x0_getinfo,
},
};
@@ -771,6 +790,7 @@ static const struct l2c_init_data l2c310_init_fns __initconst = {
.disable = l2c310_disable,
.sync = l2c210_sync,
.resume = l2c310_resume,
+ .get_info = l2x0_getinfo,
},
};
@@ -860,7 +880,6 @@ static int __init __l2c_init(const struct l2c_init_data *data,
data->enable(l2x0_base, aux, data->num_lock);
outer_cache = fns;
-
/*
* It is strange to save the register state before initialisation,
* but hey, this is what the DT implementations decided to do.
@@ -1074,6 +1093,7 @@ static const struct l2c_init_data of_l2c210_data __initconst = {
.disable = l2c_disable,
.sync = l2c210_sync,
.resume = l2c_resume,
+ .get_info = l2x0_getinfo,
},
};
@@ -1092,6 +1112,7 @@ static const struct l2c_init_data of_l2c220_data __initconst = {
.disable = l2c_disable,
.sync = l2c220_sync,
.resume = l2c_resume,
+ .get_info = l2x0_getinfo,
},
};
@@ -1220,6 +1241,7 @@ static const struct l2c_init_data of_l2c310_data __initconst = {
.disable = l2c310_disable,
.sync = l2c210_sync,
.resume = l2c310_resume,
+ .get_info = l2x0_getinfo,
},
};
@@ -1248,6 +1270,7 @@ static const struct l2c_init_data of_l2c310_coherent_data __initconst = {
.flush_all = l2c210_flush_all,
.disable = l2c310_disable,
.resume = l2c310_resume,
+ .get_info = l2x0_getinfo,
},
};
@@ -1409,6 +1432,12 @@ static void __init aurora_of_parse(const struct device_node *np,
*aux_mask &= ~mask;
}
+static void aurora_no_outer_data_getinfo(struct cacheinfo *this_leaf)
+{
+ this_leaf->type = CACHE_TYPE_INST;
+ __l2x0_getinfo(this_leaf);
+}
+
static const struct l2c_init_data of_aurora_with_outer_data __initconst = {
.type = "Aurora",
.way_size_0 = SZ_4K,
@@ -1425,6 +1454,7 @@ static const struct l2c_init_data of_aurora_with_outer_data __initconst = {
.disable = aurora_disable,
.sync = aurora_cache_sync,
.resume = l2c_resume,
+ .get_info = l2x0_getinfo,
},
};
@@ -1438,6 +1468,7 @@ static const struct l2c_init_data of_aurora_no_outer_data __initconst = {
.save = aurora_save,
.outer_cache = {
.resume = l2c_resume,
+ .get_info = aurora_no_outer_data_getinfo,
},
};
@@ -1594,6 +1625,7 @@ static const struct l2c_init_data of_bcm_l2x0_data __initconst = {
.disable = l2c310_disable,
.sync = l2c210_sync,
.resume = l2c310_resume,
+ .get_info = l2x0_getinfo,
},
};
@@ -1625,6 +1657,7 @@ static const struct l2c_init_data of_tauros3_data __initconst = {
/* Tauros3 broadcasts L1 cache operations to L2 */
.outer_cache = {
.resume = l2c_resume,
+ .get_info = l2x0_getinfo,
},
};
diff --git a/arch/arm/mm/cache-tauros2.c b/arch/arm/mm/cache-tauros2.c
index 1e373d268c04..0cff878c588e 100644
--- a/arch/arm/mm/cache-tauros2.c
+++ b/arch/arm/mm/cache-tauros2.c
@@ -14,6 +14,7 @@
* Document ID MV-S105190-00, Rev 0.7, March 14 2008.
*/
+#include <linux/cacheinfo.h>
#include <linux/init.h>
#include <linux/of.h>
#include <linux/of_address.h>
@@ -60,6 +61,7 @@ static inline void tauros2_inv_pa(unsigned long addr)
* noninclusive.
*/
#define CACHE_LINE_SIZE 32
+#define CACHE_LINE_SHIFT 5
static void tauros2_inv_range(unsigned long start, unsigned long end)
{
@@ -131,6 +133,39 @@ static void tauros2_resume(void)
"mcr p15, 0, %0, c1, c0, 0 @Enable L2 Cache\n\t"
: : "r" (0x0));
}
+
+/*
+ * +----------------------------------------+
+ * | 11 10 9 8 | 7 6 5 4 3 | 2 | 1 0 |
+ * +----------------------------------------+
+ * | way size | associativity | - |line_sz|
+ * +----------------------------------------+
+ */
+#define L2CTR_ASSOCIAT_SHIFT 3
+#define L2CTR_ASSOCIAT_MASK 0x1F
+#define L2CTR_WAYSIZE_SHIFT 8
+#define L2CTR_WAYSIZE_MASK 0xF
+#define CACHE_WAY_PER_SET(l2ctr) \
+ (((l2_ctr) >> L2CTR_ASSOCIAT_SHIFT) & L2CTR_ASSOCIAT_MASK)
+#define CACHE_WAY_SIZE(l2ctr) \
+ (8192 << (((l2ctr) >> L2CTR_WAYSIZE_SHIFT) & L2CTR_WAYSIZE_MASK))
+#define CACHE_SET_SIZE(l2ctr) (CACHE_WAY_SIZE(l2ctr) >> CACHE_LINE_SHIFT)
+
+static void tauros2_getinfo(struct cacheinfo *this_leaf)
+{
+ unsigned int l2_ctr;
+
+ __asm__("mrc p15, 1, %0, c0, c0, 1" : "=r" (l2_ctr));
+
+ this_leaf->type = CACHE_TYPE_UNIFIED;
+ this_leaf->coherency_line_size = CACHE_LINE_SIZE;
+ this_leaf->ways_of_associativity = CACHE_WAY_PER_SET(l2_ctr);
+ this_leaf->number_of_sets = CACHE_SET_SIZE(l2_ctr);
+ this_leaf->size = this_leaf->coherency_line_size *
+ this_leaf->number_of_sets *
+ this_leaf->ways_of_associativity;
+}
+
#endif
static inline u32 __init read_extra_features(void)
@@ -226,6 +261,7 @@ static void __init tauros2_internal_init(unsigned int features)
outer_cache.flush_range = tauros2_flush_range;
outer_cache.disable = tauros2_disable;
outer_cache.resume = tauros2_resume;
+ outer_cache.get_info = tauros2_getinfo;
}
#endif
diff --git a/arch/arm/mm/cache-xsc3l2.c b/arch/arm/mm/cache-xsc3l2.c
index 6c3edeb66e74..175bf44eb039 100644
--- a/arch/arm/mm/cache-xsc3l2.c
+++ b/arch/arm/mm/cache-xsc3l2.c
@@ -16,6 +16,7 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
+#include <linux/cacheinfo.h>
#include <linux/init.h>
#include <linux/highmem.h>
#include <asm/cp15.h>
@@ -201,6 +202,21 @@ static void xsc3_l2_flush_range(unsigned long start, unsigned long end)
dsb();
}
+static void xsc3_l2_getinfo(struct cacheinfo *this_leaf)
+{
+ unsigned long l2ctype;
+
+ __asm__("mrc p15, 1, %0, c0, c0, 1" : "=r" (l2ctype));
+
+ this_leaf->type = CACHE_TYPE_UNIFIED;
+ this_leaf->coherency_line_size = CACHE_LINE_SIZE;
+ this_leaf->ways_of_associativity = CACHE_WAY_PER_SET;
+ this_leaf->number_of_sets = CACHE_SET_SIZE(l2ctype);
+ this_leaf->size = this_leaf->coherency_line_size *
+ this_leaf->number_of_sets *
+ this_leaf->ways_of_associativity;
+}
+
static int __init xsc3_l2_init(void)
{
if (!cpu_is_xsc3() || !xsc3_l2_present())
@@ -213,6 +229,7 @@ static int __init xsc3_l2_init(void)
outer_cache.inv_range = xsc3_l2_inv_range;
outer_cache.clean_range = xsc3_l2_clean_range;
outer_cache.flush_range = xsc3_l2_flush_range;
+ outer_cache.get_info = xsc3_l2_getinfo;
}
return 0;
--
1.9.1
More information about the linux-arm-kernel
mailing list