135 lines
3.9 KiB
C
135 lines
3.9 KiB
C
/*
|
|
* $QNXLicenseC:
|
|
* Copyright 2007, QNX Software Systems. All Rights Reserved.
|
|
*
|
|
* You must obtain a written license from and pay applicable
|
|
* license fees to QNX Software Systems before you may reproduce,
|
|
* modify or distribute this software, or any work that includes
|
|
* all or part of this software. Free development licenses are
|
|
* available for evaluation and non-commercial purposes. For more
|
|
* information visit http://licensing.qnx.com or email
|
|
* licensing@qnx.com.
|
|
*
|
|
* This file may contain contributions from others. Please review
|
|
* this entire file for other proprietary rights or license notices,
|
|
* as well as the QNX Development Suite License Guide at
|
|
* http://licensing.qnx.com/license-guide/ for other information.
|
|
* $
|
|
*/
|
|
|
|
#include "kdebug.h"
|
|
|
|
static void
|
|
cache_one(struct cacheattr_entry *cache, uintptr_t base, size_t len, int flags) {
|
|
uintptr_t vaddr;
|
|
size_t cache_len;
|
|
|
|
vaddr = base & ~(cache->line_size-1);
|
|
cache_len = len + (base - vaddr);
|
|
while(cache_len != 0) {
|
|
unsigned lines;
|
|
paddr_t addr;
|
|
size_t valid_len;
|
|
|
|
valid_len = cache_len;
|
|
addr = vaddr;
|
|
if(cache->flags & CACHE_FLAG_CTRL_PHYS) {
|
|
if(vaddrinfo(NULL, vaddr, &addr, &valid_len) == PROT_NONE) {
|
|
unsigned page = SYSPAGE_ENTRY(system_private)->pagesize;
|
|
|
|
/* make vaddr skip to the next page boundary */
|
|
addr = (vaddr + page) & (~(page-1));
|
|
if(cache_len < (addr - vaddr)) {
|
|
cache_len = 0;
|
|
} else {
|
|
cache_len -= (addr - vaddr);
|
|
vaddr = addr;
|
|
}
|
|
continue;
|
|
}
|
|
}
|
|
lines = (valid_len + cache->line_size - 1) / cache->line_size;
|
|
while(lines != 0) {
|
|
unsigned done_lines;
|
|
size_t done_size;
|
|
|
|
//NYI: need to make handle 64 bit paddrs....
|
|
done_lines = cache->control((paddr32_t)addr, lines, flags, cache, _syspage_ptr);
|
|
if(done_lines == 0) return; /* whole cache handled */
|
|
done_size = done_lines * cache->line_size;
|
|
addr += done_size;
|
|
lines -= done_lines;
|
|
}
|
|
cache_len -= valid_len;
|
|
}
|
|
}
|
|
|
|
static void
|
|
cache_iterate(int cache_idx, uintptr_t base, size_t len, int flags, unsigned term_flag) {
|
|
struct cacheattr_entry *cache_base;
|
|
struct cacheattr_entry *cache;
|
|
struct cacheattr_entry *subset_cache;
|
|
|
|
subset_cache = NULL;
|
|
cache_base = SYSPAGE_ENTRY(cacheattr);
|
|
for(;;) {
|
|
if(cache_idx == CACHE_LIST_END) break;
|
|
cache = &cache_base[cache_idx];
|
|
if(cache->flags & term_flag) break;
|
|
if(cache->flags & CACHE_FLAG_SUBSET) {
|
|
//We'll get to it later
|
|
subset_cache = cache;
|
|
} else {
|
|
if(subset_cache != NULL) {
|
|
//
|
|
// We've skipped issuing control functions to some cache levels
|
|
// because they obey the 'subset' property. Have to issue one
|
|
// to the last level now.
|
|
//
|
|
cache_one(subset_cache, base, len, flags);
|
|
}
|
|
cache_one(cache, base, len, flags);
|
|
subset_cache = NULL;
|
|
}
|
|
cache_idx = cache->next;
|
|
}
|
|
if(subset_cache != NULL) {
|
|
//
|
|
// We've skipped issuing control functions to some cache levels
|
|
// because they obey the 'subset' property. Have to issue one
|
|
// to the last level now.
|
|
//
|
|
cache_one(subset_cache, base, len, flags);
|
|
}
|
|
}
|
|
|
|
int
|
|
cache_control(uintptr_t base, size_t len, int flags) {
|
|
struct cpuinfo_entry *cpu;
|
|
int data_flags;
|
|
int code_flags;
|
|
|
|
//NYI: deal with SMP issues
|
|
cpu = &SYSPAGE_ENTRY(cpuinfo)[0];
|
|
data_flags = flags & (MS_SYNC|MS_ASYNC|MS_INVALIDATE);
|
|
if(data_flags != 0) {
|
|
cache_iterate(cpu->data_cache, base, len, data_flags, 0);
|
|
}
|
|
code_flags = flags & (MS_INVALIDATE|MS_INVALIDATE_ICACHE);
|
|
if(code_flags != 0) {
|
|
if(data_flags == 0) {
|
|
//Push data towards main memory until we run into a unified
|
|
//cache. This is so that when the icache(s) refill, they'll
|
|
//get up-to-date data.
|
|
cache_iterate(cpu->data_cache, base, len, MS_SYNC, CACHE_FLAG_INSTR);
|
|
}
|
|
cache_iterate(cpu->ins_cache, base, len, code_flags, 0);
|
|
}
|
|
return(0);
|
|
}
|
|
|
|
void
|
|
cache_flush(uintptr_t base, size_t len) {
|
|
cache_control(base, len, MS_SYNC|MS_INVALIDATE_ICACHE);
|
|
}
|