Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /*
0003  *  linux/arch/sparc/mm/leon_m.c
0004  *
0005  * Copyright (C) 2004 Konrad Eisele (eiselekd@web.de, konrad@gaisler.com) Gaisler Research
0006  * Copyright (C) 2009 Daniel Hellstrom (daniel@gaisler.com) Aeroflex Gaisler AB
0007  * Copyright (C) 2009 Konrad Eisele (konrad@gaisler.com) Aeroflex Gaisler AB
0008  *
0009  * do srmmu probe in software
0010  *
0011  */
0012 
0013 #include <linux/kernel.h>
0014 #include <linux/mm.h>
0015 #include <asm/asi.h>
0016 #include <asm/leon.h>
0017 #include <asm/tlbflush.h>
0018 
0019 #include "mm_32.h"
0020 
0021 int leon_flush_during_switch = 1;
0022 static int srmmu_swprobe_trace;
0023 
0024 static inline unsigned long leon_get_ctable_ptr(void)
0025 {
0026     unsigned int retval;
0027 
0028     __asm__ __volatile__("lda [%1] %2, %0\n\t" :
0029                  "=r" (retval) :
0030                  "r" (SRMMU_CTXTBL_PTR),
0031                  "i" (ASI_LEON_MMUREGS));
0032     return (retval & SRMMU_CTX_PMASK) << 4;
0033 }
0034 
0035 
0036 unsigned long leon_swprobe(unsigned long vaddr, unsigned long *paddr)
0037 {
0038 
0039     unsigned int ctxtbl;
0040     unsigned int pgd, pmd, ped;
0041     unsigned int ptr;
0042     unsigned int lvl, pte, paddrbase;
0043     unsigned int ctx;
0044     unsigned int paddr_calc;
0045 
0046     paddrbase = 0;
0047 
0048     if (srmmu_swprobe_trace)
0049         printk(KERN_INFO "swprobe: trace on\n");
0050 
0051     ctxtbl = leon_get_ctable_ptr();
0052     if (!(ctxtbl)) {
0053         if (srmmu_swprobe_trace)
0054             printk(KERN_INFO "swprobe: leon_get_ctable_ptr returned 0=>0\n");
0055         return 0;
0056     }
0057     if (!_pfn_valid(PFN(ctxtbl))) {
0058         if (srmmu_swprobe_trace)
0059             printk(KERN_INFO
0060                    "swprobe: !_pfn_valid(%x)=>0\n",
0061                    PFN(ctxtbl));
0062         return 0;
0063     }
0064 
0065     ctx = srmmu_get_context();
0066     if (srmmu_swprobe_trace)
0067         printk(KERN_INFO "swprobe:  --- ctx (%x) ---\n", ctx);
0068 
0069     pgd = LEON_BYPASS_LOAD_PA(ctxtbl + (ctx * 4));
0070 
0071     if (((pgd & SRMMU_ET_MASK) == SRMMU_ET_PTE)) {
0072         if (srmmu_swprobe_trace)
0073             printk(KERN_INFO "swprobe: pgd is entry level 3\n");
0074         lvl = 3;
0075         pte = pgd;
0076         paddrbase = pgd & _SRMMU_PTE_PMASK_LEON;
0077         goto ready;
0078     }
0079     if (((pgd & SRMMU_ET_MASK) != SRMMU_ET_PTD)) {
0080         if (srmmu_swprobe_trace)
0081             printk(KERN_INFO "swprobe: pgd is invalid => 0\n");
0082         return 0;
0083     }
0084 
0085     if (srmmu_swprobe_trace)
0086         printk(KERN_INFO "swprobe:  --- pgd (%x) ---\n", pgd);
0087 
0088     ptr = (pgd & SRMMU_PTD_PMASK) << 4;
0089     ptr += ((((vaddr) >> LEON_PGD_SH) & LEON_PGD_M) * 4);
0090     if (!_pfn_valid(PFN(ptr)))
0091         return 0;
0092 
0093     pmd = LEON_BYPASS_LOAD_PA(ptr);
0094     if (((pmd & SRMMU_ET_MASK) == SRMMU_ET_PTE)) {
0095         if (srmmu_swprobe_trace)
0096             printk(KERN_INFO "swprobe: pmd is entry level 2\n");
0097         lvl = 2;
0098         pte = pmd;
0099         paddrbase = pmd & _SRMMU_PTE_PMASK_LEON;
0100         goto ready;
0101     }
0102     if (((pmd & SRMMU_ET_MASK) != SRMMU_ET_PTD)) {
0103         if (srmmu_swprobe_trace)
0104             printk(KERN_INFO "swprobe: pmd is invalid => 0\n");
0105         return 0;
0106     }
0107 
0108     if (srmmu_swprobe_trace)
0109         printk(KERN_INFO "swprobe:  --- pmd (%x) ---\n", pmd);
0110 
0111     ptr = (pmd & SRMMU_PTD_PMASK) << 4;
0112     ptr += (((vaddr >> LEON_PMD_SH) & LEON_PMD_M) * 4);
0113     if (!_pfn_valid(PFN(ptr))) {
0114         if (srmmu_swprobe_trace)
0115             printk(KERN_INFO "swprobe: !_pfn_valid(%x)=>0\n",
0116                    PFN(ptr));
0117         return 0;
0118     }
0119 
0120     ped = LEON_BYPASS_LOAD_PA(ptr);
0121 
0122     if (((ped & SRMMU_ET_MASK) == SRMMU_ET_PTE)) {
0123         if (srmmu_swprobe_trace)
0124             printk(KERN_INFO "swprobe: ped is entry level 1\n");
0125         lvl = 1;
0126         pte = ped;
0127         paddrbase = ped & _SRMMU_PTE_PMASK_LEON;
0128         goto ready;
0129     }
0130     if (((ped & SRMMU_ET_MASK) != SRMMU_ET_PTD)) {
0131         if (srmmu_swprobe_trace)
0132             printk(KERN_INFO "swprobe: ped is invalid => 0\n");
0133         return 0;
0134     }
0135 
0136     if (srmmu_swprobe_trace)
0137         printk(KERN_INFO "swprobe:  --- ped (%x) ---\n", ped);
0138 
0139     ptr = (ped & SRMMU_PTD_PMASK) << 4;
0140     ptr += (((vaddr >> LEON_PTE_SH) & LEON_PTE_M) * 4);
0141     if (!_pfn_valid(PFN(ptr)))
0142         return 0;
0143 
0144     ptr = LEON_BYPASS_LOAD_PA(ptr);
0145     if (((ptr & SRMMU_ET_MASK) == SRMMU_ET_PTE)) {
0146         if (srmmu_swprobe_trace)
0147             printk(KERN_INFO "swprobe: ptr is entry level 0\n");
0148         lvl = 0;
0149         pte = ptr;
0150         paddrbase = ptr & _SRMMU_PTE_PMASK_LEON;
0151         goto ready;
0152     }
0153     if (srmmu_swprobe_trace)
0154         printk(KERN_INFO "swprobe: ptr is invalid => 0\n");
0155     return 0;
0156 
0157 ready:
0158     switch (lvl) {
0159     case 0:
0160         paddr_calc =
0161             (vaddr & ~(-1 << LEON_PTE_SH)) | ((pte & ~0xff) << 4);
0162         break;
0163     case 1:
0164         paddr_calc =
0165             (vaddr & ~(-1 << LEON_PMD_SH)) | ((pte & ~0xff) << 4);
0166         break;
0167     case 2:
0168         paddr_calc =
0169             (vaddr & ~(-1 << LEON_PGD_SH)) | ((pte & ~0xff) << 4);
0170         break;
0171     default:
0172     case 3:
0173         paddr_calc = vaddr;
0174         break;
0175     }
0176     if (srmmu_swprobe_trace)
0177         printk(KERN_INFO "swprobe: padde %x\n", paddr_calc);
0178     if (paddr)
0179         *paddr = paddr_calc;
0180     return pte;
0181 }
0182 
0183 void leon_flush_icache_all(void)
0184 {
0185     __asm__ __volatile__(" flush ");    /*iflush*/
0186 }
0187 
0188 void leon_flush_dcache_all(void)
0189 {
0190     __asm__ __volatile__("sta %%g0, [%%g0] %0\n\t" : :
0191                  "i"(ASI_LEON_DFLUSH) : "memory");
0192 }
0193 
0194 void leon_flush_pcache_all(struct vm_area_struct *vma, unsigned long page)
0195 {
0196     if (vma->vm_flags & VM_EXEC)
0197         leon_flush_icache_all();
0198     leon_flush_dcache_all();
0199 }
0200 
0201 void leon_flush_cache_all(void)
0202 {
0203     __asm__ __volatile__(" flush ");    /*iflush*/
0204     __asm__ __volatile__("sta %%g0, [%%g0] %0\n\t" : :
0205                  "i"(ASI_LEON_DFLUSH) : "memory");
0206 }
0207 
0208 void leon_flush_tlb_all(void)
0209 {
0210     leon_flush_cache_all();
0211     __asm__ __volatile__("sta %%g0, [%0] %1\n\t" : : "r"(0x400),
0212                  "i"(ASI_LEON_MMUFLUSH) : "memory");
0213 }
0214 
0215 /* get all cache regs */
0216 void leon3_getCacheRegs(struct leon3_cacheregs *regs)
0217 {
0218     unsigned long ccr, iccr, dccr;
0219 
0220     if (!regs)
0221         return;
0222     /* Get Cache regs from "Cache ASI" address 0x0, 0x8 and 0xC */
0223     __asm__ __volatile__("lda [%%g0] %3, %0\n\t"
0224                  "mov 0x08, %%g1\n\t"
0225                  "lda [%%g1] %3, %1\n\t"
0226                  "mov 0x0c, %%g1\n\t"
0227                  "lda [%%g1] %3, %2\n\t"
0228                  : "=r"(ccr), "=r"(iccr), "=r"(dccr)
0229                    /* output */
0230                  : "i"(ASI_LEON_CACHEREGS)  /* input */
0231                  : "g1" /* clobber list */
0232         );
0233     regs->ccr = ccr;
0234     regs->iccr = iccr;
0235     regs->dccr = dccr;
0236 }
0237 
0238 /* Due to virtual cache we need to check cache configuration if
0239  * it is possible to skip flushing in some cases.
0240  *
0241  * Leon2 and Leon3 differ in their way of telling cache information
0242  *
0243  */
0244 int __init leon_flush_needed(void)
0245 {
0246     int flush_needed = -1;
0247     unsigned int ssize, sets;
0248     char *setStr[4] =
0249         { "direct mapped", "2-way associative", "3-way associative",
0250         "4-way associative"
0251     };
0252     /* leon 3 */
0253     struct leon3_cacheregs cregs;
0254     leon3_getCacheRegs(&cregs);
0255     sets = (cregs.dccr & LEON3_XCCR_SETS_MASK) >> 24;
0256     /* (ssize=>realsize) 0=>1k, 1=>2k, 2=>4k, 3=>8k ... */
0257     ssize = 1 << ((cregs.dccr & LEON3_XCCR_SSIZE_MASK) >> 20);
0258 
0259     printk(KERN_INFO "CACHE: %s cache, set size %dk\n",
0260            sets > 3 ? "unknown" : setStr[sets], ssize);
0261     if ((ssize <= (PAGE_SIZE / 1024)) && (sets == 0)) {
0262         /* Set Size <= Page size  ==>
0263            flush on every context switch not needed. */
0264         flush_needed = 0;
0265         printk(KERN_INFO "CACHE: not flushing on every context switch\n");
0266     }
0267     return flush_needed;
0268 }
0269 
0270 void leon_switch_mm(void)
0271 {
0272     flush_tlb_mm((void *)0);
0273     if (leon_flush_during_switch)
0274         leon_flush_cache_all();
0275 }
0276 
0277 static void leon_flush_cache_mm(struct mm_struct *mm)
0278 {
0279     leon_flush_cache_all();
0280 }
0281 
0282 static void leon_flush_cache_page(struct vm_area_struct *vma, unsigned long page)
0283 {
0284     leon_flush_pcache_all(vma, page);
0285 }
0286 
0287 static void leon_flush_cache_range(struct vm_area_struct *vma,
0288                    unsigned long start,
0289                    unsigned long end)
0290 {
0291     leon_flush_cache_all();
0292 }
0293 
0294 static void leon_flush_tlb_mm(struct mm_struct *mm)
0295 {
0296     leon_flush_tlb_all();
0297 }
0298 
0299 static void leon_flush_tlb_page(struct vm_area_struct *vma,
0300                 unsigned long page)
0301 {
0302     leon_flush_tlb_all();
0303 }
0304 
0305 static void leon_flush_tlb_range(struct vm_area_struct *vma,
0306                  unsigned long start,
0307                  unsigned long end)
0308 {
0309     leon_flush_tlb_all();
0310 }
0311 
0312 static void leon_flush_page_to_ram(unsigned long page)
0313 {
0314     leon_flush_cache_all();
0315 }
0316 
0317 static void leon_flush_sig_insns(struct mm_struct *mm, unsigned long page)
0318 {
0319     leon_flush_cache_all();
0320 }
0321 
0322 static void leon_flush_page_for_dma(unsigned long page)
0323 {
0324     leon_flush_dcache_all();
0325 }
0326 
0327 void __init poke_leonsparc(void)
0328 {
0329 }
0330 
0331 static const struct sparc32_cachetlb_ops leon_ops = {
0332     .cache_all  = leon_flush_cache_all,
0333     .cache_mm   = leon_flush_cache_mm,
0334     .cache_page = leon_flush_cache_page,
0335     .cache_range    = leon_flush_cache_range,
0336     .tlb_all    = leon_flush_tlb_all,
0337     .tlb_mm     = leon_flush_tlb_mm,
0338     .tlb_page   = leon_flush_tlb_page,
0339     .tlb_range  = leon_flush_tlb_range,
0340     .page_to_ram    = leon_flush_page_to_ram,
0341     .sig_insns  = leon_flush_sig_insns,
0342     .page_for_dma   = leon_flush_page_for_dma,
0343 };
0344 
0345 void __init init_leon(void)
0346 {
0347     srmmu_name = "LEON";
0348     sparc32_cachetlb_ops = &leon_ops;
0349     poke_srmmu = poke_leonsparc;
0350 
0351     leon_flush_during_switch = leon_flush_needed();
0352 }