Commit b61a40af authored by Huacai Chen's avatar Huacai Chen
Browse files

LoongArch: Refactor cache probe and flush methods



Current cache probe and flush methods have some drawbacks:
1, Assume there are 3 cache levels and only 3 levels;
2, Assume L1 = I + D, L2 = V, L3 = S, V is exclusive, S is inclusive.

However, the fact is I + D, I + D + V, I + D + S and I + D + V + S are
all valid. So, refactor the cache probe and flush methods to adapt more
types of cache hierarchy.

Signed-off-by: default avatarHuacai Chen <chenhuacai@loongson.cn>
parent a2a84e36
Loading
Loading
Loading
Loading
+48 −39
Original line number Diff line number Diff line
@@ -6,10 +6,33 @@
#define _ASM_CACHEFLUSH_H

#include <linux/mm.h>
#include <asm/cpu-features.h>
#include <asm/cpu-info.h>
#include <asm/cacheops.h>

extern void local_flush_icache_range(unsigned long start, unsigned long end);
static inline bool cache_present(struct cache_desc *cdesc)
{
	return cdesc->flags & CACHE_PRESENT;
}

static inline bool cache_private(struct cache_desc *cdesc)
{
	return cdesc->flags & CACHE_PRIVATE;
}

static inline bool cache_inclusive(struct cache_desc *cdesc)
{
	return cdesc->flags & CACHE_INCLUSIVE;
}

static inline unsigned int cpu_last_level_cache_line_size(void)
{
	int cache_present = boot_cpu_data.cache_leaves_present;

	return boot_cpu_data.cache_leaves[cache_present - 1].linesz;
}

asmlinkage void __flush_cache_all(void);
void local_flush_icache_range(unsigned long start, unsigned long end);

#define flush_icache_range	local_flush_icache_range
#define flush_icache_user_range	local_flush_icache_range
@@ -35,44 +58,30 @@ extern void local_flush_icache_range(unsigned long start, unsigned long end);
	:								\
	: "i" (op), "ZC" (*(unsigned char *)(addr)))

static inline void flush_icache_line_indexed(unsigned long addr)
static inline void flush_cache_line(int leaf, unsigned long addr)
{
	cache_op(Index_Invalidate_I, addr);
	switch (leaf) {
	case Cache_LEAF0:
		cache_op(Index_Writeback_Inv_LEAF0, addr);
		break;
	case Cache_LEAF1:
		cache_op(Index_Writeback_Inv_LEAF1, addr);
		break;
	case Cache_LEAF2:
		cache_op(Index_Writeback_Inv_LEAF2, addr);
		break;
	case Cache_LEAF3:
		cache_op(Index_Writeback_Inv_LEAF3, addr);
		break;
	case Cache_LEAF4:
		cache_op(Index_Writeback_Inv_LEAF4, addr);
		break;
	case Cache_LEAF5:
		cache_op(Index_Writeback_Inv_LEAF5, addr);
		break;
	default:
		break;
	}

static inline void flush_dcache_line_indexed(unsigned long addr)
{
	cache_op(Index_Writeback_Inv_D, addr);
}

static inline void flush_vcache_line_indexed(unsigned long addr)
{
	cache_op(Index_Writeback_Inv_V, addr);
}

static inline void flush_scache_line_indexed(unsigned long addr)
{
	cache_op(Index_Writeback_Inv_S, addr);
}

static inline void flush_icache_line(unsigned long addr)
{
	cache_op(Hit_Invalidate_I, addr);
}

static inline void flush_dcache_line(unsigned long addr)
{
	cache_op(Hit_Writeback_Inv_D, addr);
}

static inline void flush_vcache_line(unsigned long addr)
{
	cache_op(Hit_Writeback_Inv_V, addr);
}

static inline void flush_scache_line(unsigned long addr)
{
	cache_op(Hit_Writeback_Inv_S, addr);
}

#include <asm-generic/cacheflush.h>
+21 −15
Original line number Diff line number Diff line
@@ -8,16 +8,18 @@
#define __ASM_CACHEOPS_H

/*
 * Most cache ops are split into a 2 bit field identifying the cache, and a 3
 * Most cache ops are split into a 3 bit field identifying the cache, and a 2
 * bit field identifying the cache operation.
 */
#define CacheOp_Cache			0x03
#define CacheOp_Op			0x1c
#define CacheOp_Cache			0x07
#define CacheOp_Op			0x18

#define Cache_I				0x00
#define Cache_D				0x01
#define Cache_V				0x02
#define Cache_S				0x03
#define Cache_LEAF0			0x00
#define Cache_LEAF1			0x01
#define Cache_LEAF2			0x02
#define Cache_LEAF3			0x03
#define Cache_LEAF4			0x04
#define Cache_LEAF5			0x05

#define Index_Invalidate		0x08
#define Index_Writeback_Inv		0x08
@@ -25,13 +27,17 @@
#define Hit_Writeback_Inv		0x10
#define CacheOp_User_Defined		0x18

#define Index_Invalidate_I		(Cache_I | Index_Invalidate)
#define Index_Writeback_Inv_D		(Cache_D | Index_Writeback_Inv)
#define Index_Writeback_Inv_V		(Cache_V | Index_Writeback_Inv)
#define Index_Writeback_Inv_S		(Cache_S | Index_Writeback_Inv)
#define Hit_Invalidate_I		(Cache_I | Hit_Invalidate)
#define Hit_Writeback_Inv_D		(Cache_D | Hit_Writeback_Inv)
#define Hit_Writeback_Inv_V		(Cache_V | Hit_Writeback_Inv)
#define Hit_Writeback_Inv_S		(Cache_S | Hit_Writeback_Inv)
#define Index_Writeback_Inv_LEAF0	(Cache_LEAF0 | Index_Writeback_Inv)
#define Index_Writeback_Inv_LEAF1	(Cache_LEAF1 | Index_Writeback_Inv)
#define Index_Writeback_Inv_LEAF2	(Cache_LEAF2 | Index_Writeback_Inv)
#define Index_Writeback_Inv_LEAF3	(Cache_LEAF3 | Index_Writeback_Inv)
#define Index_Writeback_Inv_LEAF4	(Cache_LEAF4 | Index_Writeback_Inv)
#define Index_Writeback_Inv_LEAF5	(Cache_LEAF5 | Index_Writeback_Inv)
#define Hit_Writeback_Inv_LEAF0		(Cache_LEAF0 | Hit_Writeback_Inv)
#define Hit_Writeback_Inv_LEAF1		(Cache_LEAF1 | Hit_Writeback_Inv)
#define Hit_Writeback_Inv_LEAF2		(Cache_LEAF2 | Hit_Writeback_Inv)
#define Hit_Writeback_Inv_LEAF3		(Cache_LEAF3 | Hit_Writeback_Inv)
#define Hit_Writeback_Inv_LEAF4		(Cache_LEAF4 | Hit_Writeback_Inv)
#define Hit_Writeback_Inv_LEAF5		(Cache_LEAF5 | Hit_Writeback_Inv)

#endif	/* __ASM_CACHEOPS_H */
+0 −5
Original line number Diff line number Diff line
@@ -19,11 +19,6 @@
#define cpu_has_loongarch32		(cpu_data[0].isa_level & LOONGARCH_CPU_ISA_32BIT)
#define cpu_has_loongarch64		(cpu_data[0].isa_level & LOONGARCH_CPU_ISA_64BIT)

#define cpu_icache_line_size()		cpu_data[0].icache.linesz
#define cpu_dcache_line_size()		cpu_data[0].dcache.linesz
#define cpu_vcache_line_size()		cpu_data[0].vcache.linesz
#define cpu_scache_line_size()		cpu_data[0].scache.linesz

#ifdef CONFIG_32BIT
# define cpu_has_64bits			(cpu_data[0].isa_level & LOONGARCH_CPU_ISA_64BIT)
# define cpu_vabits			31
+14 −7
Original line number Diff line number Diff line
@@ -10,18 +10,28 @@

#include <asm/loongarch.h>

/* cache_desc->flags */
enum {
	CACHE_PRESENT	= (1 << 0),
	CACHE_PRIVATE	= (1 << 1),	/* core private cache */
	CACHE_INCLUSIVE	= (1 << 2),	/* include the inner level caches */
};

/*
 * Descriptor for a cache
 */
struct cache_desc {
	unsigned int waysize;	/* Bytes per way */
	unsigned char type;
	unsigned char level;
	unsigned short sets;	/* Number of lines per set */
	unsigned char ways;	/* Number of ways */
	unsigned char linesz;	/* Size of line in bytes */
	unsigned char waybit;	/* Bits to select in a cache set */
	unsigned char flags;	/* Flags describing cache properties */
};

#define CACHE_LEVEL_MAX		3
#define CACHE_LEAVES_MAX	6

struct cpuinfo_loongarch {
	u64			asid_cache;
	unsigned long		asid_mask;
@@ -40,11 +50,8 @@ struct cpuinfo_loongarch {
	int			tlbsizemtlb;
	int			tlbsizestlbsets;
	int			tlbsizestlbways;
	struct cache_desc	icache; /* Primary I-cache */
	struct cache_desc	dcache; /* Primary D or combined I/D cache */
	struct cache_desc	vcache; /* Victim cache, between pcache and scache */
	struct cache_desc	scache; /* Secondary cache */
	struct cache_desc	tcache; /* Tertiary/split secondary cache */
	int			cache_leaves_present; /* number of cache_leaves[] elements */
	struct cache_desc	cache_leaves[CACHE_LEAVES_MAX];
	int			core;   /* physical core number in package */
	int			package;/* physical package number */
	int			vabits; /* Virtual Address size in bits */
+6 −27
Original line number Diff line number Diff line
@@ -187,36 +187,15 @@ static inline u32 read_cpucfg(u32 reg)
#define  CPUCFG16_L3_DINCL		BIT(16)

#define LOONGARCH_CPUCFG17		0x11
#define  CPUCFG17_L1I_WAYS_M		GENMASK(15, 0)
#define  CPUCFG17_L1I_SETS_M		GENMASK(23, 16)
#define  CPUCFG17_L1I_SIZE_M		GENMASK(30, 24)
#define  CPUCFG17_L1I_WAYS		0
#define  CPUCFG17_L1I_SETS		16
#define  CPUCFG17_L1I_SIZE		24

#define LOONGARCH_CPUCFG18		0x12
#define  CPUCFG18_L1D_WAYS_M		GENMASK(15, 0)
#define  CPUCFG18_L1D_SETS_M		GENMASK(23, 16)
#define  CPUCFG18_L1D_SIZE_M		GENMASK(30, 24)
#define  CPUCFG18_L1D_WAYS		0
#define  CPUCFG18_L1D_SETS		16
#define  CPUCFG18_L1D_SIZE		24

#define LOONGARCH_CPUCFG19		0x13
#define  CPUCFG19_L2_WAYS_M		GENMASK(15, 0)
#define  CPUCFG19_L2_SETS_M		GENMASK(23, 16)
#define  CPUCFG19_L2_SIZE_M		GENMASK(30, 24)
#define  CPUCFG19_L2_WAYS		0
#define  CPUCFG19_L2_SETS		16
#define  CPUCFG19_L2_SIZE		24

#define LOONGARCH_CPUCFG20		0x14
#define  CPUCFG20_L3_WAYS_M		GENMASK(15, 0)
#define  CPUCFG20_L3_SETS_M		GENMASK(23, 16)
#define  CPUCFG20_L3_SIZE_M		GENMASK(30, 24)
#define  CPUCFG20_L3_WAYS		0
#define  CPUCFG20_L3_SETS		16
#define  CPUCFG20_L3_SIZE		24
#define  CPUCFG_CACHE_WAYS_M		GENMASK(15, 0)
#define  CPUCFG_CACHE_SETS_M		GENMASK(23, 16)
#define  CPUCFG_CACHE_LSIZE_M		GENMASK(30, 24)
#define  CPUCFG_CACHE_WAYS	 	0
#define  CPUCFG_CACHE_SETS		16
#define  CPUCFG_CACHE_LSIZE		24

#define LOONGARCH_CPUCFG48		0x30
#define  CPUCFG48_MCSR_LCK		BIT(0)
Loading