cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

cache-tauros2.c (7301B)


      1/*
      2 * arch/arm/mm/cache-tauros2.c - Tauros2 L2 cache controller support
      3 *
      4 * Copyright (C) 2008 Marvell Semiconductor
      5 *
      6 * This file is licensed under the terms of the GNU General Public
      7 * License version 2.  This program is licensed "as is" without any
      8 * warranty of any kind, whether express or implied.
      9 *
     10 * References:
     11 * - PJ1 CPU Core Datasheet,
     12 *   Document ID MV-S104837-01, Rev 0.7, January 24 2008.
     13 * - PJ4 CPU Core Datasheet,
     14 *   Document ID MV-S105190-00, Rev 0.7, March 14 2008.
     15 */
     16
     17#include <linux/init.h>
     18#include <linux/of.h>
     19#include <linux/of_address.h>
     20#include <asm/cacheflush.h>
     21#include <asm/cp15.h>
     22#include <asm/cputype.h>
     23#include <asm/hardware/cache-tauros2.h>
     24
     25/* CP15 PJ4 Control configuration register */
     26#define CCR_L2C_PREFETCH_DISABLE	BIT(24)
     27#define CCR_L2C_ECC_ENABLE		BIT(23)
     28#define CCR_L2C_WAY7_4_DISABLE		BIT(21)
     29#define CCR_L2C_BURST8_ENABLE		BIT(20)
     30
     31/*
     32 * When Tauros2 is used on a CPU that supports the v7 hierarchical
     33 * cache operations, the cache handling code in proc-v7.S takes care
     34 * of everything, including handling DMA coherency.
     35 *
     36 * So, we only need to register outer cache operations here if we're
     37 * being used on a pre-v7 CPU, and we only need to build support for
     38 * outer cache operations into the kernel image if the kernel has been
     39 * configured to support a pre-v7 CPU.
     40 */
     41#ifdef CONFIG_CPU_32v5
     42/*
     43 * Low-level cache maintenance operations.
     44 */
     45static inline void tauros2_clean_pa(unsigned long addr)
     46{
     47	__asm__("mcr p15, 1, %0, c7, c11, 3" : : "r" (addr));
     48}
     49
     50static inline void tauros2_clean_inv_pa(unsigned long addr)
     51{
     52	__asm__("mcr p15, 1, %0, c7, c15, 3" : : "r" (addr));
     53}
     54
     55static inline void tauros2_inv_pa(unsigned long addr)
     56{
     57	__asm__("mcr p15, 1, %0, c7, c7, 3" : : "r" (addr));
     58}
     59
     60
     61/*
     62 * Linux primitives.
     63 *
     64 * Note that the end addresses passed to Linux primitives are
     65 * noninclusive.
     66 */
     67#define CACHE_LINE_SIZE		32
     68
     69static void tauros2_inv_range(unsigned long start, unsigned long end)
     70{
     71	/*
     72	 * Clean and invalidate partial first cache line.
     73	 */
     74	if (start & (CACHE_LINE_SIZE - 1)) {
     75		tauros2_clean_inv_pa(start & ~(CACHE_LINE_SIZE - 1));
     76		start = (start | (CACHE_LINE_SIZE - 1)) + 1;
     77	}
     78
     79	/*
     80	 * Clean and invalidate partial last cache line.
     81	 */
     82	if (end & (CACHE_LINE_SIZE - 1)) {
     83		tauros2_clean_inv_pa(end & ~(CACHE_LINE_SIZE - 1));
     84		end &= ~(CACHE_LINE_SIZE - 1);
     85	}
     86
     87	/*
     88	 * Invalidate all full cache lines between 'start' and 'end'.
     89	 */
     90	while (start < end) {
     91		tauros2_inv_pa(start);
     92		start += CACHE_LINE_SIZE;
     93	}
     94
     95	dsb();
     96}
     97
     98static void tauros2_clean_range(unsigned long start, unsigned long end)
     99{
    100	start &= ~(CACHE_LINE_SIZE - 1);
    101	while (start < end) {
    102		tauros2_clean_pa(start);
    103		start += CACHE_LINE_SIZE;
    104	}
    105
    106	dsb();
    107}
    108
    109static void tauros2_flush_range(unsigned long start, unsigned long end)
    110{
    111	start &= ~(CACHE_LINE_SIZE - 1);
    112	while (start < end) {
    113		tauros2_clean_inv_pa(start);
    114		start += CACHE_LINE_SIZE;
    115	}
    116
    117	dsb();
    118}
    119
    120static void tauros2_disable(void)
    121{
    122	__asm__ __volatile__ (
    123	"mcr	p15, 1, %0, c7, c11, 0 @L2 Cache Clean All\n\t"
    124	"mrc	p15, 0, %0, c1, c0, 0\n\t"
    125	"bic	%0, %0, #(1 << 26)\n\t"
    126	"mcr	p15, 0, %0, c1, c0, 0  @Disable L2 Cache\n\t"
    127	: : "r" (0x0));
    128}
    129
    130static void tauros2_resume(void)
    131{
    132	__asm__ __volatile__ (
    133	"mcr	p15, 1, %0, c7, c7, 0 @L2 Cache Invalidate All\n\t"
    134	"mrc	p15, 0, %0, c1, c0, 0\n\t"
    135	"orr	%0, %0, #(1 << 26)\n\t"
    136	"mcr	p15, 0, %0, c1, c0, 0 @Enable L2 Cache\n\t"
    137	: : "r" (0x0));
    138}
    139#endif
    140
    141static inline u32 __init read_extra_features(void)
    142{
    143	u32 u;
    144
    145	__asm__("mrc p15, 1, %0, c15, c1, 0" : "=r" (u));
    146
    147	return u;
    148}
    149
    150static inline void __init write_extra_features(u32 u)
    151{
    152	__asm__("mcr p15, 1, %0, c15, c1, 0" : : "r" (u));
    153}
    154
    155static inline int __init cpuid_scheme(void)
    156{
    157	return !!((processor_id & 0x000f0000) == 0x000f0000);
    158}
    159
    160static inline u32 __init read_mmfr3(void)
    161{
    162	u32 mmfr3;
    163
    164	__asm__("mrc p15, 0, %0, c0, c1, 7\n" : "=r" (mmfr3));
    165
    166	return mmfr3;
    167}
    168
    169static inline u32 __init read_actlr(void)
    170{
    171	u32 actlr;
    172
    173	__asm__("mrc p15, 0, %0, c1, c0, 1\n" : "=r" (actlr));
    174
    175	return actlr;
    176}
    177
    178static inline void __init write_actlr(u32 actlr)
    179{
    180	__asm__("mcr p15, 0, %0, c1, c0, 1\n" : : "r" (actlr));
    181}
    182
    183static void enable_extra_feature(unsigned int features)
    184{
    185	u32 u;
    186
    187	u = read_extra_features();
    188
    189	if (features & CACHE_TAUROS2_PREFETCH_ON)
    190		u &= ~CCR_L2C_PREFETCH_DISABLE;
    191	else
    192		u |= CCR_L2C_PREFETCH_DISABLE;
    193	pr_info("Tauros2: %s L2 prefetch.\n",
    194			(features & CACHE_TAUROS2_PREFETCH_ON)
    195			? "Enabling" : "Disabling");
    196
    197	if (features & CACHE_TAUROS2_LINEFILL_BURST8)
    198		u |= CCR_L2C_BURST8_ENABLE;
    199	else
    200		u &= ~CCR_L2C_BURST8_ENABLE;
    201	pr_info("Tauros2: %s burst8 line fill.\n",
    202			(features & CACHE_TAUROS2_LINEFILL_BURST8)
    203			? "Enabling" : "Disabling");
    204
    205	write_extra_features(u);
    206}
    207
    208static void __init tauros2_internal_init(unsigned int features)
    209{
    210	char *mode = NULL;
    211
    212	enable_extra_feature(features);
    213
    214#ifdef CONFIG_CPU_32v5
    215	if ((processor_id & 0xff0f0000) == 0x56050000) {
    216		u32 feat;
    217
    218		/*
    219		 * v5 CPUs with Tauros2 have the L2 cache enable bit
    220		 * located in the CPU Extra Features register.
    221		 */
    222		feat = read_extra_features();
    223		if (!(feat & 0x00400000)) {
    224			pr_info("Tauros2: Enabling L2 cache.\n");
    225			write_extra_features(feat | 0x00400000);
    226		}
    227
    228		mode = "ARMv5";
    229		outer_cache.inv_range = tauros2_inv_range;
    230		outer_cache.clean_range = tauros2_clean_range;
    231		outer_cache.flush_range = tauros2_flush_range;
    232		outer_cache.disable = tauros2_disable;
    233		outer_cache.resume = tauros2_resume;
    234	}
    235#endif
    236
    237#ifdef CONFIG_CPU_32v7
    238	/*
    239	 * Check whether this CPU has support for the v7 hierarchical
    240	 * cache ops.  (PJ4 is in its v7 personality mode if the MMFR3
    241	 * register indicates support for the v7 hierarchical cache
    242	 * ops.)
    243	 *
    244	 * (Although strictly speaking there may exist CPUs that
    245	 * implement the v7 cache ops but are only ARMv6 CPUs (due to
    246	 * not complying with all of the other ARMv7 requirements),
    247	 * there are no real-life examples of Tauros2 being used on
    248	 * such CPUs as of yet.)
    249	 */
    250	if (cpuid_scheme() && (read_mmfr3() & 0xf) == 1) {
    251		u32 actlr;
    252
    253		/*
    254		 * When Tauros2 is used in an ARMv7 system, the L2
    255		 * enable bit is located in the Auxiliary System Control
    256		 * Register (which is the only register allowed by the
    257		 * ARMv7 spec to contain fine-grained cache control bits).
    258		 */
    259		actlr = read_actlr();
    260		if (!(actlr & 0x00000002)) {
    261			pr_info("Tauros2: Enabling L2 cache.\n");
    262			write_actlr(actlr | 0x00000002);
    263		}
    264
    265		mode = "ARMv7";
    266	}
    267#endif
    268
    269	if (mode == NULL) {
    270		pr_crit("Tauros2: Unable to detect CPU mode.\n");
    271		return;
    272	}
    273
    274	pr_info("Tauros2: L2 cache support initialised "
    275			 "in %s mode.\n", mode);
    276}
    277
    278#ifdef CONFIG_OF
    279static const struct of_device_id tauros2_ids[] __initconst = {
    280	{ .compatible = "marvell,tauros2-cache"},
    281	{}
    282};
    283#endif
    284
    285void __init tauros2_init(unsigned int features)
    286{
    287#ifdef CONFIG_OF
    288	struct device_node *node;
    289	int ret;
    290	unsigned int f;
    291
    292	node = of_find_matching_node(NULL, tauros2_ids);
    293	if (!node) {
    294		pr_info("Not found marvell,tauros2-cache, disable it\n");
    295	} else {
    296		ret = of_property_read_u32(node, "marvell,tauros2-cache-features", &f);
    297		if (ret) {
    298			pr_info("Not found marvell,tauros-cache-features property, "
    299				"disable extra features\n");
    300			features = 0;
    301		} else
    302			features = f;
    303	}
    304#endif
    305	tauros2_internal_init(features);
    306}