1 | // SPDX-License-Identifier: GPL-2.0-or-later |
2 | /* |
3 | * OpenRISC cache.c |
4 | * |
5 | * Linux architectural port borrowing liberally from similar works of |
6 | * others. All original copyrights apply as per the original source |
7 | * declaration. |
8 | * |
9 | * Modifications for the OpenRISC architecture: |
10 | * Copyright (C) 2015 Jan Henrik Weinstock <jan.weinstock@rwth-aachen.de> |
11 | */ |
12 | |
13 | #include <asm/spr.h> |
14 | #include <asm/spr_defs.h> |
15 | #include <asm/cache.h> |
16 | #include <asm/cacheflush.h> |
17 | #include <asm/tlbflush.h> |
18 | |
19 | static __always_inline void cache_loop(struct page *page, const unsigned int reg) |
20 | { |
21 | unsigned long paddr = page_to_pfn(page) << PAGE_SHIFT; |
22 | unsigned long line = paddr & ~(L1_CACHE_BYTES - 1); |
23 | |
24 | while (line < paddr + PAGE_SIZE) { |
25 | mtspr(reg, line); |
26 | line += L1_CACHE_BYTES; |
27 | } |
28 | } |
29 | |
30 | void local_dcache_page_flush(struct page *page) |
31 | { |
32 | cache_loop(page, reg: SPR_DCBFR); |
33 | } |
34 | EXPORT_SYMBOL(local_dcache_page_flush); |
35 | |
36 | void local_icache_page_inv(struct page *page) |
37 | { |
38 | cache_loop(page, reg: SPR_ICBIR); |
39 | } |
40 | EXPORT_SYMBOL(local_icache_page_inv); |
41 | |
42 | void update_cache(struct vm_area_struct *vma, unsigned long address, |
43 | pte_t *pte) |
44 | { |
45 | unsigned long pfn = pte_val(pte: *pte) >> PAGE_SHIFT; |
46 | struct folio *folio = page_folio(pfn_to_page(pfn)); |
47 | int dirty = !test_and_set_bit(nr: PG_dc_clean, addr: &folio->flags); |
48 | |
49 | /* |
50 | * Since icaches do not snoop for updated data on OpenRISC, we |
51 | * must write back and invalidate any dirty pages manually. We |
52 | * can skip data pages, since they will not end up in icaches. |
53 | */ |
54 | if ((vma->vm_flags & VM_EXEC) && dirty) { |
55 | unsigned int nr = folio_nr_pages(folio); |
56 | |
57 | while (nr--) |
58 | sync_icache_dcache(folio_page(folio, nr)); |
59 | } |
60 | } |
61 | |
62 | |