1/* 2 * Meta cache partition manipulation. 3 * 4 * Copyright 2010 Imagination Technologies Ltd. 5 */ 6 7#include <linux/kernel.h> 8#include <linux/io.h> 9#include <linux/errno.h> 10#include <asm/processor.h> 11#include <asm/cachepart.h> 12#include <asm/metag_isa.h> 13#include <asm/metag_mem.h> 14 15#define SYSC_DCPART(n) (SYSC_DCPART0 + SYSC_xCPARTn_STRIDE * (n)) 16#define SYSC_ICPART(n) (SYSC_ICPART0 + SYSC_xCPARTn_STRIDE * (n)) 17 18#define CACHE_ASSOCIATIVITY 4 /* 4 way set-assosiative */ 19#define ICACHE 0 20#define DCACHE 1 21 22/* The CORE_CONFIG2 register is not available on Meta 1 */ 23#ifdef CONFIG_METAG_META21 24unsigned int get_dcache_size(void) 25{ 26 unsigned int config2 = metag_in32(METAC_CORE_CONFIG2); 27 unsigned int sz = 0x1000 << ((config2 & METAC_CORECFG2_DCSZ_BITS) 28 >> METAC_CORECFG2_DCSZ_S); 29 if (config2 & METAC_CORECFG2_DCSMALL_BIT) 30 sz >>= 6; 31 return sz; 32} 33 34unsigned int get_icache_size(void) 35{ 36 unsigned int config2 = metag_in32(METAC_CORE_CONFIG2); 37 unsigned int sz = 0x1000 << ((config2 & METAC_CORE_C2ICSZ_BITS) 38 >> METAC_CORE_C2ICSZ_S); 39 if (config2 & METAC_CORECFG2_ICSMALL_BIT) 40 sz >>= 6; 41 return sz; 42} 43 44unsigned int get_global_dcache_size(void) 45{ 46 unsigned int cpart = metag_in32(SYSC_DCPART(hard_processor_id())); 47 unsigned int temp = cpart & SYSC_xCPARTG_AND_BITS; 48 return (get_dcache_size() * ((temp >> SYSC_xCPARTG_AND_S) + 1)) >> 4; 49} 50 51unsigned int get_global_icache_size(void) 52{ 53 unsigned int cpart = metag_in32(SYSC_ICPART(hard_processor_id())); 54 unsigned int temp = cpart & SYSC_xCPARTG_AND_BITS; 55 return (get_icache_size() * ((temp >> SYSC_xCPARTG_AND_S) + 1)) >> 4; 56} 57 58static int get_thread_cache_size(unsigned int cache, int thread_id) 59{ 60 unsigned int cache_size; 61 unsigned int t_cache_part; 62 unsigned int isEnabled; 63 unsigned int offset = 0; 64 isEnabled = (cache == DCACHE ? metag_in32(MMCU_DCACHE_CTRL_ADDR) & 0x1 : 65 metag_in32(MMCU_ICACHE_CTRL_ADDR) & 0x1); 66 if (!isEnabled) 67 return 0; 68#if PAGE_OFFSET >= LINGLOBAL_BASE 69 /* Checking for global cache */ 70 cache_size = (cache == DCACHE ? get_global_dcache_size() : 71 get_global_icache_size()); 72 offset = 8; 73#else 74 cache_size = (cache == DCACHE ? get_dcache_size() : 75 get_icache_size()); 76#endif 77 t_cache_part = (cache == DCACHE ? 78 (metag_in32(SYSC_DCPART(thread_id)) >> offset) & 0xF : 79 (metag_in32(SYSC_ICPART(thread_id)) >> offset) & 0xF); 80 switch (t_cache_part) { 81 case 0xF: 82 return cache_size; 83 case 0x7: 84 return cache_size / 2; 85 case 0x3: 86 return cache_size / 4; 87 case 0x1: 88 return cache_size / 8; 89 case 0: 90 return cache_size / 16; 91 } 92 return -1; 93} 94 95void check_for_cache_aliasing(int thread_id) 96{ 97 int thread_cache_size; 98 unsigned int cache_type; 99 for (cache_type = ICACHE; cache_type <= DCACHE; cache_type++) { 100 thread_cache_size = 101 get_thread_cache_size(cache_type, thread_id); 102 if (thread_cache_size < 0) 103 pr_emerg("Can't read %s cache size\n", 104 cache_type ? "DCACHE" : "ICACHE"); 105 else if (thread_cache_size == 0) 106 /* Cache is off. No need to check for aliasing */ 107 continue; 108 if (thread_cache_size / CACHE_ASSOCIATIVITY > PAGE_SIZE) { 109 pr_emerg("Potential cache aliasing detected in %s on Thread %d\n", 110 cache_type ? "DCACHE" : "ICACHE", thread_id); 111 pr_warn("Total %s size: %u bytes\n", 112 cache_type ? "DCACHE" : "ICACHE", 113 cache_type ? get_dcache_size() 114 : get_icache_size()); 115 pr_warn("Thread %s size: %d bytes\n", 116 cache_type ? "CACHE" : "ICACHE", 117 thread_cache_size); 118 pr_warn("Page Size: %lu bytes\n", PAGE_SIZE); 119 panic("Potential cache aliasing detected"); 120 } 121 } 122} 123 124#else 125 126void check_for_cache_aliasing(int thread_id) 127{ 128 return; 129} 130 131#endif 132