/* * Cache control for MicroBlaze cache memories * * Copyright (C) 2007-2009 Michal Simek <monstr@monstr.eu> * Copyright (C) 2007-2009 PetaLogix * Copyright (C) 2007-2009 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.
*/
/* Helper macro for computing the limits of cache range loops * * End address can be unaligned which is OK for C implementation. * ASM implementation align it in ASM macros
*/ #define CACHE_LOOP_LIMITS(start, end, cache_line_length, cache_size) \ do { \ int align = ~(cache_line_length - 1); \ if (start < UINT_MAX - cache_size) \
end = min(start + cache_size, end); \
start &= align; \
} while (0)
/* * Helper macro to loop over the specified cache_size/line_length and * execute 'op' on that cacheline
*/ #define CACHE_ALL_LOOP(cache_size, line_length, op) \ do { \ unsignedint len = cache_size - line_length; \ int step = -line_length; \
WARN_ON(step >= 0); \
\
__asm__ __volatile__ (" 1: "#op" %0, r0;" \ "bgtid %0, 1b;" \ "addk %0, %0, %1;" \
: : "r" (len), "r" (step) \
: "memory"); \
} while (0)
/* Used for wdc.flush/clear which can use rB for offset which is not possible * to use for simple wdc or wic. * * start address is cache aligned * end address is not aligned, if end is aligned then I have to subtract * cacheline length because I can't flush/invalidate the next cacheline. * If is not, I align it because I will flush/invalidate whole line.
*/ #define CACHE_RANGE_LOOP_2(start, end, line_length, op) \ do { \ int step = -line_length; \ int align = ~(line_length - 1); \ int count; \
end = ((end & align) == end) ? end - line_length : end & align; \
count = end - start; \
WARN_ON(count < 0); \
\
__asm__ __volatile__ (" 1: "#op" %0, %1;" \ "bgtid %1, 1b;" \ "addk %1, %1, %2;" \
: : "r" (start), "r" (count), \ "r" (step) : "memory"); \
} while (0)
/* It is used only first parameter for OP - for wic, wdc */ #define CACHE_RANGE_LOOP_1(start, end, line_length, op) \ do { \ unsignedintvolatile temp = 0; \ unsignedint align = ~(line_length - 1); \
end = ((end & align) == end) ? end - line_length : end & align; \
WARN_ON(end < start); \
\
__asm__ __volatile__ (" 1: "#op" %1, r0;" \ "cmpu %0, %1, %2;" \ "bgtid %0, 1b;" \ "addk %1, %1, %3;" \
: : "r" (temp), "r" (start), "r" (end), \ "r" (line_length) : "memory"); \
} while (0)
local_irq_save(flags);
__disable_dcache_nomsr(); #ifdef ASM_LOOP
CACHE_ALL_LOOP(cpuinfo.dcache_size, cpuinfo.dcache_line_length, wdc); #else for (i = 0; i < cpuinfo.dcache_size;
i += cpuinfo.dcache_line_length)
__asm__ __volatile__ ("wdc %0, r0;" \
: : "r" (i)); #endif
__enable_dcache_nomsr();
local_irq_restore(flags);
}
staticvoid __invalidate_dcache_all_noirq_wt(void)
{ #ifndef ASM_LOOP int i; #endif
pr_debug("%s\n", __func__); #ifdef ASM_LOOP
CACHE_ALL_LOOP(cpuinfo.dcache_size, cpuinfo.dcache_line_length, wdc); #else for (i = 0; i < cpuinfo.dcache_size;
i += cpuinfo.dcache_line_length)
__asm__ __volatile__ ("wdc %0, r0;" \
: : "r" (i)); #endif
}
/* * FIXME It is blindly invalidation as is expected * but can't be called on noMMU in microblaze_cache_init below * * MS: noMMU kernel won't boot if simple wdc is used * The reason should be that there are discared data which kernel needs
*/ staticvoid __invalidate_dcache_all_wb(void)
{ #ifndef ASM_LOOP int i; #endif
pr_debug("%s\n", __func__); #ifdef ASM_LOOP
CACHE_ALL_LOOP(cpuinfo.dcache_size, cpuinfo.dcache_line_length,
wdc); #else for (i = 0; i < cpuinfo.dcache_size;
i += cpuinfo.dcache_line_length)
__asm__ __volatile__ ("wdc %0, r0;" \
: : "r" (i)); #endif
}
staticvoid __invalidate_dcache_range_wb(unsignedlong start, unsignedlong end)
{ #ifndef ASM_LOOP int i; #endif
pr_debug("%s: start 0x%x, end 0x%x\n", __func__,
(unsignedint)start, (unsignedint) end);
CACHE_LOOP_LIMITS(start, end,
cpuinfo.dcache_line_length, cpuinfo.dcache_size); #ifdef ASM_LOOP
CACHE_RANGE_LOOP_2(start, end, cpuinfo.dcache_line_length, wdc.clear); #else for (i = start; i < end; i += cpuinfo.dcache_line_length)
__asm__ __volatile__ ("wdc.clear %0, r0;" \
: : "r" (i)); #endif
}
/* CPU version code for 7.20.c - see arch/microblaze/kernel/cpu/cpuinfo.c */ #define CPUVER_7_20_A 0x0c #define CPUVER_7_20_D 0x0f
void microblaze_cache_init(void)
{ if (cpuinfo.use_instr & PVR2_USE_MSR_INSTR) { if (cpuinfo.dcache_wb) {
pr_info("wb_msr\n");
mbc = (struct scache *)&wb_msr; if (cpuinfo.ver_code <= CPUVER_7_20_D) { /* MS: problem with signal handling - hw bug */
pr_info("WB won't work properly\n");
}
} else { if (cpuinfo.ver_code >= CPUVER_7_20_A) {
pr_info("wt_msr_noirq\n");
mbc = (struct scache *)&wt_msr_noirq;
} else {
pr_info("wt_msr\n");
mbc = (struct scache *)&wt_msr;
}
}
} else { if (cpuinfo.dcache_wb) {
pr_info("wb_nomsr\n");
mbc = (struct scache *)&wb_nomsr; if (cpuinfo.ver_code <= CPUVER_7_20_D) { /* MS: problem with signal handling - hw bug */
pr_info("WB won't work properly\n");
}
} else { if (cpuinfo.ver_code >= CPUVER_7_20_A) {
pr_info("wt_nomsr_noirq\n");
mbc = (struct scache *)&wt_nomsr_noirq;
} else {
pr_info("wt_nomsr\n");
mbc = (struct scache *)&wt_nomsr;
}
}
} /* * FIXME Invalidation is done in U-BOOT * WT cache: Data is already written to main memory * WB cache: Discard data on noMMU which caused that kernel doesn't boot
*/ /* invalidate_dcache(); */
enable_dcache();
invalidate_icache();
enable_icache();
}
Messung V0.5
¤ Dauer der Verarbeitung: 0.15 Sekunden
(vorverarbeitet)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.