^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) // SPDX-License-Identifier: GPL-2.0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) * linux/arch/sparc/mm/leon_m.c
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) * Copyright (C) 2004 Konrad Eisele (eiselekd@web.de, konrad@gaisler.com) Gaisler Research
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) * Copyright (C) 2009 Daniel Hellstrom (daniel@gaisler.com) Aeroflex Gaisler AB
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) * Copyright (C) 2009 Konrad Eisele (konrad@gaisler.com) Aeroflex Gaisler AB
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) * do srmmu probe in software
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) #include <linux/kernel.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) #include <linux/mm.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) #include <asm/asi.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) #include <asm/leon.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) #include <asm/tlbflush.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) #include "mm_32.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) int leon_flush_during_switch = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) static int srmmu_swprobe_trace;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) static inline unsigned long leon_get_ctable_ptr(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) unsigned int retval;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) __asm__ __volatile__("lda [%1] %2, %0\n\t" :
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) "=r" (retval) :
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) "r" (SRMMU_CTXTBL_PTR),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) "i" (ASI_LEON_MMUREGS));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) return (retval & SRMMU_CTX_PMASK) << 4;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) unsigned long leon_swprobe(unsigned long vaddr, unsigned long *paddr)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) unsigned int ctxtbl;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) unsigned int pgd, pmd, ped;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) unsigned int ptr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) unsigned int lvl, pte, paddrbase;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) unsigned int ctx;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) unsigned int paddr_calc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) paddrbase = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) if (srmmu_swprobe_trace)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) printk(KERN_INFO "swprobe: trace on\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) ctxtbl = leon_get_ctable_ptr();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) if (!(ctxtbl)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) if (srmmu_swprobe_trace)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) printk(KERN_INFO "swprobe: leon_get_ctable_ptr returned 0=>0\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) if (!_pfn_valid(PFN(ctxtbl))) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) if (srmmu_swprobe_trace)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) printk(KERN_INFO
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) "swprobe: !_pfn_valid(%x)=>0\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) PFN(ctxtbl));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) ctx = srmmu_get_context();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) if (srmmu_swprobe_trace)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) printk(KERN_INFO "swprobe: --- ctx (%x) ---\n", ctx);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) pgd = LEON_BYPASS_LOAD_PA(ctxtbl + (ctx * 4));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) if (((pgd & SRMMU_ET_MASK) == SRMMU_ET_PTE)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) if (srmmu_swprobe_trace)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) printk(KERN_INFO "swprobe: pgd is entry level 3\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) lvl = 3;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) pte = pgd;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) paddrbase = pgd & _SRMMU_PTE_PMASK_LEON;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) goto ready;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) if (((pgd & SRMMU_ET_MASK) != SRMMU_ET_PTD)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) if (srmmu_swprobe_trace)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) printk(KERN_INFO "swprobe: pgd is invalid => 0\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) if (srmmu_swprobe_trace)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) printk(KERN_INFO "swprobe: --- pgd (%x) ---\n", pgd);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) ptr = (pgd & SRMMU_PTD_PMASK) << 4;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) ptr += ((((vaddr) >> LEON_PGD_SH) & LEON_PGD_M) * 4);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) if (!_pfn_valid(PFN(ptr)))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) pmd = LEON_BYPASS_LOAD_PA(ptr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) if (((pmd & SRMMU_ET_MASK) == SRMMU_ET_PTE)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) if (srmmu_swprobe_trace)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) printk(KERN_INFO "swprobe: pmd is entry level 2\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) lvl = 2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) pte = pmd;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) paddrbase = pmd & _SRMMU_PTE_PMASK_LEON;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) goto ready;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) if (((pmd & SRMMU_ET_MASK) != SRMMU_ET_PTD)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) if (srmmu_swprobe_trace)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) printk(KERN_INFO "swprobe: pmd is invalid => 0\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) if (srmmu_swprobe_trace)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) printk(KERN_INFO "swprobe: --- pmd (%x) ---\n", pmd);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) ptr = (pmd & SRMMU_PTD_PMASK) << 4;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) ptr += (((vaddr >> LEON_PMD_SH) & LEON_PMD_M) * 4);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) if (!_pfn_valid(PFN(ptr))) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) if (srmmu_swprobe_trace)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) printk(KERN_INFO "swprobe: !_pfn_valid(%x)=>0\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) PFN(ptr));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) ped = LEON_BYPASS_LOAD_PA(ptr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) if (((ped & SRMMU_ET_MASK) == SRMMU_ET_PTE)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) if (srmmu_swprobe_trace)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) printk(KERN_INFO "swprobe: ped is entry level 1\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) lvl = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) pte = ped;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) paddrbase = ped & _SRMMU_PTE_PMASK_LEON;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) goto ready;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) if (((ped & SRMMU_ET_MASK) != SRMMU_ET_PTD)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) if (srmmu_swprobe_trace)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) printk(KERN_INFO "swprobe: ped is invalid => 0\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) if (srmmu_swprobe_trace)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) printk(KERN_INFO "swprobe: --- ped (%x) ---\n", ped);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) ptr = (ped & SRMMU_PTD_PMASK) << 4;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) ptr += (((vaddr >> LEON_PTE_SH) & LEON_PTE_M) * 4);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) if (!_pfn_valid(PFN(ptr)))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) ptr = LEON_BYPASS_LOAD_PA(ptr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) if (((ptr & SRMMU_ET_MASK) == SRMMU_ET_PTE)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) if (srmmu_swprobe_trace)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) printk(KERN_INFO "swprobe: ptr is entry level 0\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) lvl = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) pte = ptr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) paddrbase = ptr & _SRMMU_PTE_PMASK_LEON;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) goto ready;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153) if (srmmu_swprobe_trace)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154) printk(KERN_INFO "swprobe: ptr is invalid => 0\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157) ready:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158) switch (lvl) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159) case 0:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) paddr_calc =
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161) (vaddr & ~(-1 << LEON_PTE_SH)) | ((pte & ~0xff) << 4);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163) case 1:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164) paddr_calc =
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165) (vaddr & ~(-1 << LEON_PMD_SH)) | ((pte & ~0xff) << 4);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167) case 2:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168) paddr_calc =
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169) (vaddr & ~(-1 << LEON_PGD_SH)) | ((pte & ~0xff) << 4);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172) case 3:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173) paddr_calc = vaddr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176) if (srmmu_swprobe_trace)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177) printk(KERN_INFO "swprobe: padde %x\n", paddr_calc);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178) if (paddr)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179) *paddr = paddr_calc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180) return pte;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183) void leon_flush_icache_all(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 185) __asm__ __volatile__(" flush "); /*iflush*/
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 186) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 187)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 188) void leon_flush_dcache_all(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 189) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 190) __asm__ __volatile__("sta %%g0, [%%g0] %0\n\t" : :
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 191) "i"(ASI_LEON_DFLUSH) : "memory");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 192) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 193)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 194) void leon_flush_pcache_all(struct vm_area_struct *vma, unsigned long page)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 195) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 196) if (vma->vm_flags & VM_EXEC)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 197) leon_flush_icache_all();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 198) leon_flush_dcache_all();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 199) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 200)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 201) void leon_flush_cache_all(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 202) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 203) __asm__ __volatile__(" flush "); /*iflush*/
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 204) __asm__ __volatile__("sta %%g0, [%%g0] %0\n\t" : :
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 205) "i"(ASI_LEON_DFLUSH) : "memory");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 206) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 207)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 208) void leon_flush_tlb_all(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 209) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 210) leon_flush_cache_all();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 211) __asm__ __volatile__("sta %%g0, [%0] %1\n\t" : : "r"(0x400),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 212) "i"(ASI_LEON_MMUFLUSH) : "memory");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 213) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 214)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 215) /* get all cache regs */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 216) void leon3_getCacheRegs(struct leon3_cacheregs *regs)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 217) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 218) unsigned long ccr, iccr, dccr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 219)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 220) if (!regs)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 221) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 222) /* Get Cache regs from "Cache ASI" address 0x0, 0x8 and 0xC */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 223) __asm__ __volatile__("lda [%%g0] %3, %0\n\t"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 224) "mov 0x08, %%g1\n\t"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 225) "lda [%%g1] %3, %1\n\t"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 226) "mov 0x0c, %%g1\n\t"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 227) "lda [%%g1] %3, %2\n\t"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 228) : "=r"(ccr), "=r"(iccr), "=r"(dccr)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 229) /* output */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 230) : "i"(ASI_LEON_CACHEREGS) /* input */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 231) : "g1" /* clobber list */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 232) );
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 233) regs->ccr = ccr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 234) regs->iccr = iccr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 235) regs->dccr = dccr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 236) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 237)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 238) /* Due to virtual cache we need to check cache configuration if
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 239) * it is possible to skip flushing in some cases.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 240) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 241) * Leon2 and Leon3 differ in their way of telling cache information
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 242) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 243) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 244) int __init leon_flush_needed(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 245) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 246) int flush_needed = -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 247) unsigned int ssize, sets;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 248) char *setStr[4] =
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 249) { "direct mapped", "2-way associative", "3-way associative",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 250) "4-way associative"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 251) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 252) /* leon 3 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 253) struct leon3_cacheregs cregs;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 254) leon3_getCacheRegs(&cregs);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 255) sets = (cregs.dccr & LEON3_XCCR_SETS_MASK) >> 24;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 256) /* (ssize=>realsize) 0=>1k, 1=>2k, 2=>4k, 3=>8k ... */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 257) ssize = 1 << ((cregs.dccr & LEON3_XCCR_SSIZE_MASK) >> 20);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 258)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 259) printk(KERN_INFO "CACHE: %s cache, set size %dk\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 260) sets > 3 ? "unknown" : setStr[sets], ssize);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 261) if ((ssize <= (PAGE_SIZE / 1024)) && (sets == 0)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 262) /* Set Size <= Page size ==>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 263) flush on every context switch not needed. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 264) flush_needed = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 265) printk(KERN_INFO "CACHE: not flushing on every context switch\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 266) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 267) return flush_needed;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 268) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 269)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 270) void leon_switch_mm(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 271) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 272) flush_tlb_mm((void *)0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 273) if (leon_flush_during_switch)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 274) leon_flush_cache_all();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 275) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 276)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 277) static void leon_flush_cache_mm(struct mm_struct *mm)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 278) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 279) leon_flush_cache_all();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 280) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 281)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 282) static void leon_flush_cache_page(struct vm_area_struct *vma, unsigned long page)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 283) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 284) leon_flush_pcache_all(vma, page);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 285) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 286)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 287) static void leon_flush_cache_range(struct vm_area_struct *vma,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 288) unsigned long start,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 289) unsigned long end)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 290) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 291) leon_flush_cache_all();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 292) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 293)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 294) static void leon_flush_tlb_mm(struct mm_struct *mm)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 295) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 296) leon_flush_tlb_all();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 297) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 298)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 299) static void leon_flush_tlb_page(struct vm_area_struct *vma,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 300) unsigned long page)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 301) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 302) leon_flush_tlb_all();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 303) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 304)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 305) static void leon_flush_tlb_range(struct vm_area_struct *vma,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 306) unsigned long start,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 307) unsigned long end)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 308) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 309) leon_flush_tlb_all();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 310) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 311)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 312) static void leon_flush_page_to_ram(unsigned long page)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 313) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 314) leon_flush_cache_all();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 315) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 316)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 317) static void leon_flush_sig_insns(struct mm_struct *mm, unsigned long page)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 318) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 319) leon_flush_cache_all();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 320) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 321)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 322) static void leon_flush_page_for_dma(unsigned long page)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 323) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 324) leon_flush_dcache_all();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 325) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 326)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 327) void __init poke_leonsparc(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 328) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 329) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 330)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 331) static const struct sparc32_cachetlb_ops leon_ops = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 332) .cache_all = leon_flush_cache_all,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 333) .cache_mm = leon_flush_cache_mm,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 334) .cache_page = leon_flush_cache_page,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 335) .cache_range = leon_flush_cache_range,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 336) .tlb_all = leon_flush_tlb_all,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 337) .tlb_mm = leon_flush_tlb_mm,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 338) .tlb_page = leon_flush_tlb_page,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 339) .tlb_range = leon_flush_tlb_range,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 340) .page_to_ram = leon_flush_page_to_ram,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 341) .sig_insns = leon_flush_sig_insns,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 342) .page_for_dma = leon_flush_page_for_dma,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 343) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 344)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 345) void __init init_leon(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 346) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 347) srmmu_name = "LEON";
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 348) sparc32_cachetlb_ops = &leon_ops;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 349) poke_srmmu = poke_leonsparc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 350)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 351) leon_flush_during_switch = leon_flush_needed();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 352) }