256 lines
5.1 KiB
C
256 lines
5.1 KiB
C
/*
|
|
* Cache control for MicroBlaze cache memories
|
|
*
|
|
* Copyright (C) 2007-2009 Michal Simek <monstr@monstr.eu>
|
|
* Copyright (C) 2007-2009 PetaLogix
|
|
* Copyright (C) 2007 John Williams <john.williams@petalogix.com>
|
|
*
|
|
* This file is subject to the terms and conditions of the GNU General
|
|
* Public License. See the file COPYING in the main directory of this
|
|
* archive for more details.
|
|
*/
|
|
|
|
#include <asm/cacheflush.h>
|
|
#include <linux/cache.h>
|
|
#include <asm/cpuinfo.h>
|
|
|
|
/* Exported functions */
|
|
|
|
void _enable_icache(void)
|
|
{
|
|
if (cpuinfo.use_icache) {
|
|
#if CONFIG_XILINX_MICROBLAZE0_USE_MSR_INSTR
|
|
__asm__ __volatile__ (" \
|
|
msrset r0, %0; \
|
|
nop; " \
|
|
: \
|
|
: "i" (MSR_ICE) \
|
|
: "memory");
|
|
#else
|
|
__asm__ __volatile__ (" \
|
|
mfs r12, rmsr; \
|
|
nop; \
|
|
ori r12, r12, %0; \
|
|
mts rmsr, r12; \
|
|
nop; " \
|
|
: \
|
|
: "i" (MSR_ICE) \
|
|
: "memory", "r12");
|
|
#endif
|
|
}
|
|
}
|
|
|
|
void _disable_icache(void)
|
|
{
|
|
if (cpuinfo.use_icache) {
|
|
#if CONFIG_XILINX_MICROBLAZE0_USE_MSR_INSTR
|
|
__asm__ __volatile__ (" \
|
|
msrclr r0, %0; \
|
|
nop; " \
|
|
: \
|
|
: "i" (MSR_ICE) \
|
|
: "memory");
|
|
#else
|
|
__asm__ __volatile__ (" \
|
|
mfs r12, rmsr; \
|
|
nop; \
|
|
andi r12, r12, ~%0; \
|
|
mts rmsr, r12; \
|
|
nop; " \
|
|
: \
|
|
: "i" (MSR_ICE) \
|
|
: "memory", "r12");
|
|
#endif
|
|
}
|
|
}
|
|
|
|
void _invalidate_icache(unsigned int addr)
|
|
{
|
|
if (cpuinfo.use_icache) {
|
|
__asm__ __volatile__ (" \
|
|
wic %0, r0" \
|
|
: \
|
|
: "r" (addr));
|
|
}
|
|
}
|
|
|
|
void _enable_dcache(void)
|
|
{
|
|
if (cpuinfo.use_dcache) {
|
|
#if CONFIG_XILINX_MICROBLAZE0_USE_MSR_INSTR
|
|
__asm__ __volatile__ (" \
|
|
msrset r0, %0; \
|
|
nop; " \
|
|
: \
|
|
: "i" (MSR_DCE) \
|
|
: "memory");
|
|
#else
|
|
__asm__ __volatile__ (" \
|
|
mfs r12, rmsr; \
|
|
nop; \
|
|
ori r12, r12, %0; \
|
|
mts rmsr, r12; \
|
|
nop; " \
|
|
: \
|
|
: "i" (MSR_DCE) \
|
|
: "memory", "r12");
|
|
#endif
|
|
}
|
|
}
|
|
|
|
void _disable_dcache(void)
|
|
{
|
|
#if CONFIG_XILINX_MICROBLAZE0_USE_MSR_INSTR
|
|
__asm__ __volatile__ (" \
|
|
msrclr r0, %0; \
|
|
nop; " \
|
|
: \
|
|
: "i" (MSR_DCE) \
|
|
: "memory");
|
|
#else
|
|
__asm__ __volatile__ (" \
|
|
mfs r12, rmsr; \
|
|
nop; \
|
|
andi r12, r12, ~%0; \
|
|
mts rmsr, r12; \
|
|
nop; " \
|
|
: \
|
|
: "i" (MSR_DCE) \
|
|
: "memory", "r12");
|
|
#endif
|
|
}
|
|
|
|
void _invalidate_dcache(unsigned int addr)
|
|
{
|
|
__asm__ __volatile__ (" \
|
|
wdc %0, r0" \
|
|
: \
|
|
: "r" (addr));
|
|
}
|
|
|
|
void __invalidate_icache_all(void)
|
|
{
|
|
unsigned int i;
|
|
unsigned flags;
|
|
|
|
if (cpuinfo.use_icache) {
|
|
local_irq_save(flags);
|
|
__disable_icache();
|
|
|
|
/* Just loop through cache size and invalidate, no need to add
|
|
CACHE_BASE address */
|
|
for (i = 0; i < cpuinfo.icache_size;
|
|
i += cpuinfo.icache_line)
|
|
__invalidate_icache(i);
|
|
|
|
__enable_icache();
|
|
local_irq_restore(flags);
|
|
}
|
|
}
|
|
|
|
void __invalidate_icache_range(unsigned long start, unsigned long end)
|
|
{
|
|
unsigned int i;
|
|
unsigned flags;
|
|
unsigned int align;
|
|
|
|
if (cpuinfo.use_icache) {
|
|
/*
|
|
* No need to cover entire cache range,
|
|
* just cover cache footprint
|
|
*/
|
|
end = min(start + cpuinfo.icache_size, end);
|
|
align = ~(cpuinfo.icache_line - 1);
|
|
start &= align; /* Make sure we are aligned */
|
|
/* Push end up to the next cache line */
|
|
end = ((end & align) + cpuinfo.icache_line);
|
|
|
|
local_irq_save(flags);
|
|
__disable_icache();
|
|
|
|
for (i = start; i < end; i += cpuinfo.icache_line)
|
|
__invalidate_icache(i);
|
|
|
|
__enable_icache();
|
|
local_irq_restore(flags);
|
|
}
|
|
}
|
|
|
|
void __invalidate_icache_page(struct vm_area_struct *vma, struct page *page)
|
|
{
|
|
__invalidate_icache_all();
|
|
}
|
|
|
|
void __invalidate_icache_user_range(struct vm_area_struct *vma,
|
|
struct page *page, unsigned long adr,
|
|
int len)
|
|
{
|
|
__invalidate_icache_all();
|
|
}
|
|
|
|
void __invalidate_cache_sigtramp(unsigned long addr)
|
|
{
|
|
__invalidate_icache_range(addr, addr + 8);
|
|
}
|
|
|
|
void __invalidate_dcache_all(void)
|
|
{
|
|
unsigned int i;
|
|
unsigned flags;
|
|
|
|
if (cpuinfo.use_dcache) {
|
|
local_irq_save(flags);
|
|
__disable_dcache();
|
|
|
|
/*
|
|
* Just loop through cache size and invalidate,
|
|
* no need to add CACHE_BASE address
|
|
*/
|
|
for (i = 0; i < cpuinfo.dcache_size;
|
|
i += cpuinfo.dcache_line)
|
|
__invalidate_dcache(i);
|
|
|
|
__enable_dcache();
|
|
local_irq_restore(flags);
|
|
}
|
|
}
|
|
|
|
void __invalidate_dcache_range(unsigned long start, unsigned long end)
|
|
{
|
|
unsigned int i;
|
|
unsigned flags;
|
|
unsigned int align;
|
|
|
|
if (cpuinfo.use_dcache) {
|
|
/*
|
|
* No need to cover entire cache range,
|
|
* just cover cache footprint
|
|
*/
|
|
end = min(start + cpuinfo.dcache_size, end);
|
|
align = ~(cpuinfo.dcache_line - 1);
|
|
start &= align; /* Make sure we are aligned */
|
|
/* Push end up to the next cache line */
|
|
end = ((end & align) + cpuinfo.dcache_line);
|
|
local_irq_save(flags);
|
|
__disable_dcache();
|
|
|
|
for (i = start; i < end; i += cpuinfo.dcache_line)
|
|
__invalidate_dcache(i);
|
|
|
|
__enable_dcache();
|
|
local_irq_restore(flags);
|
|
}
|
|
}
|
|
|
|
void __invalidate_dcache_page(struct vm_area_struct *vma, struct page *page)
|
|
{
|
|
__invalidate_dcache_all();
|
|
}
|
|
|
|
void __invalidate_dcache_user_range(struct vm_area_struct *vma,
|
|
struct page *page, unsigned long adr,
|
|
int len)
|
|
{
|
|
__invalidate_dcache_all();
|
|
}
|