18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci// Copyright (C) 2018 Hangzhou C-SKY Microsystems co.,ltd. 38c2ecf20Sopenharmony_ci 48c2ecf20Sopenharmony_ci#include <linux/cache.h> 58c2ecf20Sopenharmony_ci#include <linux/highmem.h> 68c2ecf20Sopenharmony_ci#include <linux/mm.h> 78c2ecf20Sopenharmony_ci#include <asm/cache.h> 88c2ecf20Sopenharmony_ci 98c2ecf20Sopenharmony_civoid update_mmu_cache(struct vm_area_struct *vma, unsigned long address, 108c2ecf20Sopenharmony_ci pte_t *pte) 118c2ecf20Sopenharmony_ci{ 128c2ecf20Sopenharmony_ci unsigned long addr; 138c2ecf20Sopenharmony_ci struct page *page; 148c2ecf20Sopenharmony_ci 158c2ecf20Sopenharmony_ci page = pfn_to_page(pte_pfn(*pte)); 168c2ecf20Sopenharmony_ci if (page == ZERO_PAGE(0)) 178c2ecf20Sopenharmony_ci return; 188c2ecf20Sopenharmony_ci 198c2ecf20Sopenharmony_ci if (test_and_set_bit(PG_dcache_clean, &page->flags)) 208c2ecf20Sopenharmony_ci return; 218c2ecf20Sopenharmony_ci 228c2ecf20Sopenharmony_ci addr = (unsigned long) kmap_atomic(page); 238c2ecf20Sopenharmony_ci 248c2ecf20Sopenharmony_ci dcache_wb_range(addr, addr + PAGE_SIZE); 258c2ecf20Sopenharmony_ci 268c2ecf20Sopenharmony_ci if (vma->vm_flags & VM_EXEC) 278c2ecf20Sopenharmony_ci icache_inv_range(addr, addr + PAGE_SIZE); 288c2ecf20Sopenharmony_ci 298c2ecf20Sopenharmony_ci kunmap_atomic((void *) addr); 308c2ecf20Sopenharmony_ci} 318c2ecf20Sopenharmony_ci 328c2ecf20Sopenharmony_civoid flush_icache_deferred(struct mm_struct *mm) 338c2ecf20Sopenharmony_ci{ 348c2ecf20Sopenharmony_ci unsigned int cpu = smp_processor_id(); 358c2ecf20Sopenharmony_ci cpumask_t *mask = &mm->context.icache_stale_mask; 368c2ecf20Sopenharmony_ci 378c2ecf20Sopenharmony_ci if (cpumask_test_cpu(cpu, mask)) { 388c2ecf20Sopenharmony_ci cpumask_clear_cpu(cpu, mask); 398c2ecf20Sopenharmony_ci /* 408c2ecf20Sopenharmony_ci * Ensure the remote hart's writes are visible to this hart. 418c2ecf20Sopenharmony_ci * This pairs with a barrier in flush_icache_mm. 428c2ecf20Sopenharmony_ci */ 438c2ecf20Sopenharmony_ci smp_mb(); 448c2ecf20Sopenharmony_ci local_icache_inv_all(NULL); 458c2ecf20Sopenharmony_ci } 468c2ecf20Sopenharmony_ci} 478c2ecf20Sopenharmony_ci 488c2ecf20Sopenharmony_civoid flush_icache_mm_range(struct mm_struct *mm, 498c2ecf20Sopenharmony_ci unsigned long start, unsigned long end) 508c2ecf20Sopenharmony_ci{ 518c2ecf20Sopenharmony_ci unsigned int cpu; 528c2ecf20Sopenharmony_ci cpumask_t others, *mask; 538c2ecf20Sopenharmony_ci 548c2ecf20Sopenharmony_ci preempt_disable(); 558c2ecf20Sopenharmony_ci 568c2ecf20Sopenharmony_ci#ifdef CONFIG_CPU_HAS_ICACHE_INS 578c2ecf20Sopenharmony_ci if (mm == current->mm) { 588c2ecf20Sopenharmony_ci icache_inv_range(start, end); 598c2ecf20Sopenharmony_ci preempt_enable(); 608c2ecf20Sopenharmony_ci return; 618c2ecf20Sopenharmony_ci } 628c2ecf20Sopenharmony_ci#endif 638c2ecf20Sopenharmony_ci 648c2ecf20Sopenharmony_ci /* Mark every hart's icache as needing a flush for this MM. */ 658c2ecf20Sopenharmony_ci mask = &mm->context.icache_stale_mask; 668c2ecf20Sopenharmony_ci cpumask_setall(mask); 678c2ecf20Sopenharmony_ci 688c2ecf20Sopenharmony_ci /* Flush this hart's I$ now, and mark it as flushed. */ 698c2ecf20Sopenharmony_ci cpu = smp_processor_id(); 708c2ecf20Sopenharmony_ci cpumask_clear_cpu(cpu, mask); 718c2ecf20Sopenharmony_ci local_icache_inv_all(NULL); 728c2ecf20Sopenharmony_ci 738c2ecf20Sopenharmony_ci /* 748c2ecf20Sopenharmony_ci * Flush the I$ of other harts concurrently executing, and mark them as 758c2ecf20Sopenharmony_ci * flushed. 768c2ecf20Sopenharmony_ci */ 778c2ecf20Sopenharmony_ci cpumask_andnot(&others, mm_cpumask(mm), cpumask_of(cpu)); 788c2ecf20Sopenharmony_ci 798c2ecf20Sopenharmony_ci if (mm != current->active_mm || !cpumask_empty(&others)) { 808c2ecf20Sopenharmony_ci on_each_cpu_mask(&others, local_icache_inv_all, NULL, 1); 818c2ecf20Sopenharmony_ci cpumask_clear(mask); 828c2ecf20Sopenharmony_ci } 838c2ecf20Sopenharmony_ci 848c2ecf20Sopenharmony_ci preempt_enable(); 858c2ecf20Sopenharmony_ci} 86