18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * OpenRISC cache.c 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Linux architectural port borrowing liberally from similar works of 68c2ecf20Sopenharmony_ci * others. All original copyrights apply as per the original source 78c2ecf20Sopenharmony_ci * declaration. 88c2ecf20Sopenharmony_ci * 98c2ecf20Sopenharmony_ci * Modifications for the OpenRISC architecture: 108c2ecf20Sopenharmony_ci * Copyright (C) 2015 Jan Henrik Weinstock <jan.weinstock@rwth-aachen.de> 118c2ecf20Sopenharmony_ci */ 128c2ecf20Sopenharmony_ci 138c2ecf20Sopenharmony_ci#include <asm/spr.h> 148c2ecf20Sopenharmony_ci#include <asm/spr_defs.h> 158c2ecf20Sopenharmony_ci#include <asm/cache.h> 168c2ecf20Sopenharmony_ci#include <asm/cacheflush.h> 178c2ecf20Sopenharmony_ci#include <asm/tlbflush.h> 188c2ecf20Sopenharmony_ci 198c2ecf20Sopenharmony_cistatic __always_inline void cache_loop(struct page *page, const unsigned int reg) 208c2ecf20Sopenharmony_ci{ 218c2ecf20Sopenharmony_ci unsigned long paddr = page_to_pfn(page) << PAGE_SHIFT; 228c2ecf20Sopenharmony_ci unsigned long line = paddr & ~(L1_CACHE_BYTES - 1); 238c2ecf20Sopenharmony_ci 248c2ecf20Sopenharmony_ci while (line < paddr + PAGE_SIZE) { 258c2ecf20Sopenharmony_ci mtspr(reg, line); 268c2ecf20Sopenharmony_ci line += L1_CACHE_BYTES; 278c2ecf20Sopenharmony_ci } 288c2ecf20Sopenharmony_ci} 298c2ecf20Sopenharmony_ci 308c2ecf20Sopenharmony_civoid local_dcache_page_flush(struct page *page) 318c2ecf20Sopenharmony_ci{ 328c2ecf20Sopenharmony_ci cache_loop(page, SPR_DCBFR); 338c2ecf20Sopenharmony_ci} 348c2ecf20Sopenharmony_ciEXPORT_SYMBOL(local_dcache_page_flush); 358c2ecf20Sopenharmony_ci 368c2ecf20Sopenharmony_civoid local_icache_page_inv(struct page *page) 378c2ecf20Sopenharmony_ci{ 388c2ecf20Sopenharmony_ci cache_loop(page, SPR_ICBIR); 398c2ecf20Sopenharmony_ci} 408c2ecf20Sopenharmony_ciEXPORT_SYMBOL(local_icache_page_inv); 418c2ecf20Sopenharmony_ci 428c2ecf20Sopenharmony_civoid update_cache(struct vm_area_struct *vma, unsigned long address, 438c2ecf20Sopenharmony_ci pte_t *pte) 448c2ecf20Sopenharmony_ci{ 458c2ecf20Sopenharmony_ci unsigned long pfn = pte_val(*pte) >> PAGE_SHIFT; 468c2ecf20Sopenharmony_ci struct page *page = pfn_to_page(pfn); 478c2ecf20Sopenharmony_ci int dirty = !test_and_set_bit(PG_dc_clean, &page->flags); 488c2ecf20Sopenharmony_ci 498c2ecf20Sopenharmony_ci /* 508c2ecf20Sopenharmony_ci * Since icaches do not snoop for updated data on OpenRISC, we 518c2ecf20Sopenharmony_ci * must write back and invalidate any dirty pages manually. We 528c2ecf20Sopenharmony_ci * can skip data pages, since they will not end up in icaches. 538c2ecf20Sopenharmony_ci */ 548c2ecf20Sopenharmony_ci if ((vma->vm_flags & VM_EXEC) && dirty) 558c2ecf20Sopenharmony_ci sync_icache_dcache(page); 568c2ecf20Sopenharmony_ci} 578c2ecf20Sopenharmony_ci 58