![Jan Henrik Weinstock](/assets/img/avatar_default.png)
On OpenRISC the icache does not snoop data stores. This can cause aliasing as reported by Jan. This patch fixes the issue to ensure icache is properly synchronized when code is written to memory. It supports both SMP and UP flushing. This supports dcache flush as well for architectures that do not support write-through caches; most OpenRISC implementations do implement write-through cache however. Dcache flushes are done only on a single core as OpenRISC dcaches all support snooping of bus stores. Signed-off-by: Jan Henrik Weinstock <jan.weinstock@ice.rwth-aachen.de> [shorne@gmail.com: Squashed patches and wrote commit message] Signed-off-by: Stafford Horne <shorne@gmail.com>
62 lines
1.7 KiB
C
62 lines
1.7 KiB
C
/*
|
|
* OpenRISC cache.c
|
|
*
|
|
* Linux architectural port borrowing liberally from similar works of
|
|
* others. All original copyrights apply as per the original source
|
|
* declaration.
|
|
*
|
|
* Modifications for the OpenRISC architecture:
|
|
* Copyright (C) 2015 Jan Henrik Weinstock <jan.weinstock@rwth-aachen.de>
|
|
*
|
|
* This program is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU General Public License
|
|
* as published by the Free Software Foundation; either version
|
|
* 2 of the License, or (at your option) any later version.
|
|
*/
|
|
|
|
#include <asm/spr.h>
|
|
#include <asm/spr_defs.h>
|
|
#include <asm/cache.h>
|
|
#include <asm/cacheflush.h>
|
|
#include <asm/tlbflush.h>
|
|
|
|
static void cache_loop(struct page *page, const unsigned int reg)
|
|
{
|
|
unsigned long paddr = page_to_pfn(page) << PAGE_SHIFT;
|
|
unsigned long line = paddr & ~(L1_CACHE_BYTES - 1);
|
|
|
|
while (line < paddr + PAGE_SIZE) {
|
|
mtspr(reg, line);
|
|
line += L1_CACHE_BYTES;
|
|
}
|
|
}
|
|
|
|
void local_dcache_page_flush(struct page *page)
|
|
{
|
|
cache_loop(page, SPR_DCBFR);
|
|
}
|
|
EXPORT_SYMBOL(local_dcache_page_flush);
|
|
|
|
void local_icache_page_inv(struct page *page)
|
|
{
|
|
cache_loop(page, SPR_ICBIR);
|
|
}
|
|
EXPORT_SYMBOL(local_icache_page_inv);
|
|
|
|
void update_cache(struct vm_area_struct *vma, unsigned long address,
|
|
pte_t *pte)
|
|
{
|
|
unsigned long pfn = pte_val(*pte) >> PAGE_SHIFT;
|
|
struct page *page = pfn_to_page(pfn);
|
|
int dirty = !test_and_set_bit(PG_dc_clean, &page->flags);
|
|
|
|
/*
|
|
* Since icaches do not snoop for updated data on OpenRISC, we
|
|
* must write back and invalidate any dirty pages manually. We
|
|
* can skip data pages, since they will not end up in icaches.
|
|
*/
|
|
if ((vma->vm_flags & VM_EXEC) && dirty)
|
|
sync_icache_dcache(page);
|
|
}
|
|
|