0001
0002
0003
0004
0005
0006
0007
0008
0009
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 ");
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 ");
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
0216 void leon3_getCacheRegs(struct leon3_cacheregs *regs)
0217 {
0218 unsigned long ccr, iccr, dccr;
0219
0220 if (!regs)
0221 return;
0222
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
0230 : "i"(ASI_LEON_CACHEREGS)
0231 : "g1"
0232 );
0233 regs->ccr = ccr;
0234 regs->iccr = iccr;
0235 regs->dccr = dccr;
0236 }
0237
0238
0239
0240
0241
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
0253 struct leon3_cacheregs cregs;
0254 leon3_getCacheRegs(&cregs);
0255 sets = (cregs.dccr & LEON3_XCCR_SETS_MASK) >> 24;
0256
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
0263
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 }