added function to flush only a portion of the caches

This commit is contained in:
Markus Fröschle
2014-09-24 16:02:20 +00:00
parent d913708130
commit 7ecd89ce10
3 changed files with 61 additions and 2 deletions

View File

@@ -54,6 +54,7 @@
#define CF_CACR_ICINVA (0x00000100) /* Instr Cache Invalidate All */ #define CF_CACR_ICINVA (0x00000100) /* Instr Cache Invalidate All */
#define CF_CACR_IDSP (0x00000080) /* Ins default supervisor-protect */ #define CF_CACR_IDSP (0x00000080) /* Ins default supervisor-protect */
#define CF_CACR_EUSP (0x00000020) /* Switch stacks in user mode */ #define CF_CACR_EUSP (0x00000020) /* Switch stacks in user mode */
#define CF_CACR_DF (0x00000010) /* Disable FPU */
#define _DCACHE_SET_MASK ((DCACHE_SIZE/64-1)<<CACHE_WAYS) #define _DCACHE_SET_MASK ((DCACHE_SIZE/64-1)<<CACHE_WAYS)
#define _ICACHE_SET_MASK ((ICACHE_SIZE/64-1)<<CACHE_WAYS) #define _ICACHE_SET_MASK ((ICACHE_SIZE/64-1)<<CACHE_WAYS)
@@ -83,7 +84,7 @@ extern uint32_t cacr_get(void);
extern void cacr_set(uint32_t); extern void cacr_set(uint32_t);
extern void flush_icache_range(void *address, size_t size); extern void flush_icache_range(void *address, size_t size);
extern void flush_dcache_range(void *address, size_t size); extern void flush_dcache_range(void *address, size_t size);
extern void flush_cache_range(void *address, size_t size);
#endif /* _CACHE_H_ */ #endif /* _CACHE_H_ */

View File

@@ -97,7 +97,8 @@ void flush_icache_range(void *address, size_t size)
if (start_set > end_set) { if (start_set > end_set) {
/* from the begining to the lowest address */ /* from the begining to the lowest address */
for (set = 0; set <= end_set; set += (0x10 - 3)) { for (set = 0; set <= end_set; set += (0x10 - 3))
{
__asm__ __volatile__( __asm__ __volatile__(
" cpushl ic,(%[set]) \n\t" " cpushl ic,(%[set]) \n\t"
" addq.l #1,%[set] \n\t" " addq.l #1,%[set] \n\t"
@@ -182,3 +183,57 @@ void flush_dcache_range(void *address, size_t size)
); );
} }
} }
/*
* flush and invalidate a specific region from the both caches. We do not know if the area is cached
* at all, we do not know in which of the four ways it is cached, but we know the index where they
* would be cached if they are, so we only need to flush and invalidate only a subset of the 512 index
* entries, but all four ways.
*/
void flush_cache_range(void *address, size_t size)
{
unsigned long set;
unsigned long start_set;
unsigned long end_set;
void *endaddr;
endaddr = address + size;
start_set = (uint32_t) address & _DCACHE_SET_MASK;
end_set = (uint32_t) endaddr & _DCACHE_SET_MASK;
if (start_set > end_set) {
/* from the begining to the lowest address */
for (set = 0; set <= end_set; set += (0x10 - 3))
{
__asm__ __volatile__(
" cpushl bc,(%[set]) \n\t"
" addq.l #1,%[set] \n\t"
" cpushl bc,(%[set]) \n\t"
" addq.l #1,%[set] \n\t"
" cpushl bc,(%[set]) \n\t"
" addq.l #1,%[set] \n\t"
" cpushl bc,(%[set]) \n\t"
: /* output parameters */
: [set] "a" (set)
: "cc" /* clobbered registers */
);
}
/* next loop will finish the cache ie pass the hole */
end_set = LAST_DCACHE_ADDR;
}
for (set = start_set; set <= end_set; set += (0x10 - 3))
{
__asm__ __volatile__(
" cpushl bc,(%[set]) \n\t"
" addq.l #1,%[set] \n\t"
" cpushl bc,(%[set]) \n\t"
" addq%.l #1,%[set] \n\t"
" cpushl bc,(%[set]) \n\t"
" addq.l #1,%[set] \n\t"
" cpushl bc,(%[set]) \n\t"
: /* output parameters */
: [set] "a" (set)
: "cc" /* clobbered registers */
);
}
}

View File

@@ -347,7 +347,10 @@ void mmu_init(void)
* video RAM: read write execute normal write true * video RAM: read write execute normal write true
*/ */
flags.cache_mode = CACHE_WRITETHROUGH; flags.cache_mode = CACHE_WRITETHROUGH;
flags.protection = SV_USER;
flags.page_id = SCA_PAGE_ID; flags.page_id = SCA_PAGE_ID;
flags.access = ACCESS_READ | ACCESS_WRITE | ACCESS_EXECUTE;
flags.locked = true;
mmu_map_page(0x00d00000, 0x60d00000, MMU_PAGE_SIZE_1M, &flags); mmu_map_page(0x00d00000, 0x60d00000, MMU_PAGE_SIZE_1M, &flags);
video_tlb = 0x2000; /* set page as video page */ video_tlb = 0x2000; /* set page as video page */