root/arch/mips/mm/c-r3k.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. r3k_cache_size
  2. r3k_cache_lsize
  3. r3k_probe_cache
  4. r3k_flush_icache_range
  5. r3k_flush_dcache_range
  6. r3k_flush_cache_all
  7. r3k___flush_cache_all
  8. r3k_flush_cache_mm
  9. r3k_flush_cache_range
  10. r3k_flush_cache_page
  11. local_r3k_flush_data_cache_page
  12. r3k_flush_data_cache_page
  13. r3k_flush_kernel_vmap_range
  14. r3k_dma_cache_wback_inv
  15. r3k_cache_init

   1 // SPDX-License-Identifier: GPL-2.0
   2 /*
   3  * r2300.c: R2000 and R3000 specific mmu/cache code.
   4  *
   5  * Copyright (C) 1996 David S. Miller (davem@davemloft.net)
   6  *
   7  * with a lot of changes to make this thing work for R3000s
   8  * Tx39XX R4k style caches added. HK
   9  * Copyright (C) 1998, 1999, 2000 Harald Koerfgen
  10  * Copyright (C) 1998 Gleb Raiko & Vladimir Roganov
  11  * Copyright (C) 2001, 2004, 2007  Maciej W. Rozycki
  12  */
  13 #include <linux/kernel.h>
  14 #include <linux/sched.h>
  15 #include <linux/smp.h>
  16 #include <linux/mm.h>
  17 
  18 #include <asm/page.h>
  19 #include <asm/pgtable.h>
  20 #include <asm/mmu_context.h>
  21 #include <asm/isadep.h>
  22 #include <asm/io.h>
  23 #include <asm/bootinfo.h>
  24 #include <asm/cpu.h>
  25 
  26 static unsigned long icache_size, dcache_size;          /* Size in bytes */
  27 static unsigned long icache_lsize, dcache_lsize;        /* Size in bytes */
  28 
  29 unsigned long r3k_cache_size(unsigned long ca_flags)
  30 {
  31         unsigned long flags, status, dummy, size;
  32         volatile unsigned long *p;
  33 
  34         p = (volatile unsigned long *) KSEG0;
  35 
  36         flags = read_c0_status();
  37 
  38         /* isolate cache space */
  39         write_c0_status((ca_flags|flags)&~ST0_IEC);
  40 
  41         *p = 0xa5a55a5a;
  42         dummy = *p;
  43         status = read_c0_status();
  44 
  45         if (dummy != 0xa5a55a5a || (status & ST0_CM)) {
  46                 size = 0;
  47         } else {
  48                 for (size = 128; size <= 0x40000; size <<= 1)
  49                         *(p + size) = 0;
  50                 *p = -1;
  51                 for (size = 128;
  52                      (size <= 0x40000) && (*(p + size) == 0);
  53                      size <<= 1)
  54                         ;
  55                 if (size > 0x40000)
  56                         size = 0;
  57         }
  58 
  59         write_c0_status(flags);
  60 
  61         return size * sizeof(*p);
  62 }
  63 
  64 unsigned long r3k_cache_lsize(unsigned long ca_flags)
  65 {
  66         unsigned long flags, status, lsize, i;
  67         volatile unsigned long *p;
  68 
  69         p = (volatile unsigned long *) KSEG0;
  70 
  71         flags = read_c0_status();
  72 
  73         /* isolate cache space */
  74         write_c0_status((ca_flags|flags)&~ST0_IEC);
  75 
  76         for (i = 0; i < 128; i++)
  77                 *(p + i) = 0;
  78         *(volatile unsigned char *)p = 0;
  79         for (lsize = 1; lsize < 128; lsize <<= 1) {
  80                 *(p + lsize);
  81                 status = read_c0_status();
  82                 if (!(status & ST0_CM))
  83                         break;
  84         }
  85         for (i = 0; i < 128; i += lsize)
  86                 *(volatile unsigned char *)(p + i) = 0;
  87 
  88         write_c0_status(flags);
  89 
  90         return lsize * sizeof(*p);
  91 }
  92 
  93 static void r3k_probe_cache(void)
  94 {
  95         dcache_size = r3k_cache_size(ST0_ISC);
  96         if (dcache_size)
  97                 dcache_lsize = r3k_cache_lsize(ST0_ISC);
  98 
  99         icache_size = r3k_cache_size(ST0_ISC|ST0_SWC);
 100         if (icache_size)
 101                 icache_lsize = r3k_cache_lsize(ST0_ISC|ST0_SWC);
 102 }
 103 
 104 static void r3k_flush_icache_range(unsigned long start, unsigned long end)
 105 {
 106         unsigned long size, i, flags;
 107         volatile unsigned char *p;
 108 
 109         size = end - start;
 110         if (size > icache_size || KSEGX(start) != KSEG0) {
 111                 start = KSEG0;
 112                 size = icache_size;
 113         }
 114         p = (char *)start;
 115 
 116         flags = read_c0_status();
 117 
 118         /* isolate cache space */
 119         write_c0_status((ST0_ISC|ST0_SWC|flags)&~ST0_IEC);
 120 
 121         for (i = 0; i < size; i += 0x080) {
 122                 asm(    "sb\t$0, 0x000(%0)\n\t"
 123                         "sb\t$0, 0x004(%0)\n\t"
 124                         "sb\t$0, 0x008(%0)\n\t"
 125                         "sb\t$0, 0x00c(%0)\n\t"
 126                         "sb\t$0, 0x010(%0)\n\t"
 127                         "sb\t$0, 0x014(%0)\n\t"
 128                         "sb\t$0, 0x018(%0)\n\t"
 129                         "sb\t$0, 0x01c(%0)\n\t"
 130                         "sb\t$0, 0x020(%0)\n\t"
 131                         "sb\t$0, 0x024(%0)\n\t"
 132                         "sb\t$0, 0x028(%0)\n\t"
 133                         "sb\t$0, 0x02c(%0)\n\t"
 134                         "sb\t$0, 0x030(%0)\n\t"
 135                         "sb\t$0, 0x034(%0)\n\t"
 136                         "sb\t$0, 0x038(%0)\n\t"
 137                         "sb\t$0, 0x03c(%0)\n\t"
 138                         "sb\t$0, 0x040(%0)\n\t"
 139                         "sb\t$0, 0x044(%0)\n\t"
 140                         "sb\t$0, 0x048(%0)\n\t"
 141                         "sb\t$0, 0x04c(%0)\n\t"
 142                         "sb\t$0, 0x050(%0)\n\t"
 143                         "sb\t$0, 0x054(%0)\n\t"
 144                         "sb\t$0, 0x058(%0)\n\t"
 145                         "sb\t$0, 0x05c(%0)\n\t"
 146                         "sb\t$0, 0x060(%0)\n\t"
 147                         "sb\t$0, 0x064(%0)\n\t"
 148                         "sb\t$0, 0x068(%0)\n\t"
 149                         "sb\t$0, 0x06c(%0)\n\t"
 150                         "sb\t$0, 0x070(%0)\n\t"
 151                         "sb\t$0, 0x074(%0)\n\t"
 152                         "sb\t$0, 0x078(%0)\n\t"
 153                         "sb\t$0, 0x07c(%0)\n\t"
 154                         : : "r" (p) );
 155                 p += 0x080;
 156         }
 157 
 158         write_c0_status(flags);
 159 }
 160 
 161 static void r3k_flush_dcache_range(unsigned long start, unsigned long end)
 162 {
 163         unsigned long size, i, flags;
 164         volatile unsigned char *p;
 165 
 166         size = end - start;
 167         if (size > dcache_size || KSEGX(start) != KSEG0) {
 168                 start = KSEG0;
 169                 size = dcache_size;
 170         }
 171         p = (char *)start;
 172 
 173         flags = read_c0_status();
 174 
 175         /* isolate cache space */
 176         write_c0_status((ST0_ISC|flags)&~ST0_IEC);
 177 
 178         for (i = 0; i < size; i += 0x080) {
 179                 asm(    "sb\t$0, 0x000(%0)\n\t"
 180                         "sb\t$0, 0x004(%0)\n\t"
 181                         "sb\t$0, 0x008(%0)\n\t"
 182                         "sb\t$0, 0x00c(%0)\n\t"
 183                         "sb\t$0, 0x010(%0)\n\t"
 184                         "sb\t$0, 0x014(%0)\n\t"
 185                         "sb\t$0, 0x018(%0)\n\t"
 186                         "sb\t$0, 0x01c(%0)\n\t"
 187                         "sb\t$0, 0x020(%0)\n\t"
 188                         "sb\t$0, 0x024(%0)\n\t"
 189                         "sb\t$0, 0x028(%0)\n\t"
 190                         "sb\t$0, 0x02c(%0)\n\t"
 191                         "sb\t$0, 0x030(%0)\n\t"
 192                         "sb\t$0, 0x034(%0)\n\t"
 193                         "sb\t$0, 0x038(%0)\n\t"
 194                         "sb\t$0, 0x03c(%0)\n\t"
 195                         "sb\t$0, 0x040(%0)\n\t"
 196                         "sb\t$0, 0x044(%0)\n\t"
 197                         "sb\t$0, 0x048(%0)\n\t"
 198                         "sb\t$0, 0x04c(%0)\n\t"
 199                         "sb\t$0, 0x050(%0)\n\t"
 200                         "sb\t$0, 0x054(%0)\n\t"
 201                         "sb\t$0, 0x058(%0)\n\t"
 202                         "sb\t$0, 0x05c(%0)\n\t"
 203                         "sb\t$0, 0x060(%0)\n\t"
 204                         "sb\t$0, 0x064(%0)\n\t"
 205                         "sb\t$0, 0x068(%0)\n\t"
 206                         "sb\t$0, 0x06c(%0)\n\t"
 207                         "sb\t$0, 0x070(%0)\n\t"
 208                         "sb\t$0, 0x074(%0)\n\t"
 209                         "sb\t$0, 0x078(%0)\n\t"
 210                         "sb\t$0, 0x07c(%0)\n\t"
 211                         : : "r" (p) );
 212                 p += 0x080;
 213         }
 214 
 215         write_c0_status(flags);
 216 }
 217 
 218 static inline void r3k_flush_cache_all(void)
 219 {
 220 }
 221 
 222 static inline void r3k___flush_cache_all(void)
 223 {
 224         r3k_flush_dcache_range(KSEG0, KSEG0 + dcache_size);
 225         r3k_flush_icache_range(KSEG0, KSEG0 + icache_size);
 226 }
 227 
 228 static void r3k_flush_cache_mm(struct mm_struct *mm)
 229 {
 230 }
 231 
 232 static void r3k_flush_cache_range(struct vm_area_struct *vma,
 233                                   unsigned long start, unsigned long end)
 234 {
 235 }
 236 
 237 static void r3k_flush_cache_page(struct vm_area_struct *vma,
 238                                  unsigned long addr, unsigned long pfn)
 239 {
 240         unsigned long kaddr = KSEG0ADDR(pfn << PAGE_SHIFT);
 241         int exec = vma->vm_flags & VM_EXEC;
 242         struct mm_struct *mm = vma->vm_mm;
 243         pgd_t *pgdp;
 244         pud_t *pudp;
 245         pmd_t *pmdp;
 246         pte_t *ptep;
 247 
 248         pr_debug("cpage[%08llx,%08lx]\n",
 249                  cpu_context(smp_processor_id(), mm), addr);
 250 
 251         /* No ASID => no such page in the cache.  */
 252         if (cpu_context(smp_processor_id(), mm) == 0)
 253                 return;
 254 
 255         pgdp = pgd_offset(mm, addr);
 256         pudp = pud_offset(pgdp, addr);
 257         pmdp = pmd_offset(pudp, addr);
 258         ptep = pte_offset(pmdp, addr);
 259 
 260         /* Invalid => no such page in the cache.  */
 261         if (!(pte_val(*ptep) & _PAGE_PRESENT))
 262                 return;
 263 
 264         r3k_flush_dcache_range(kaddr, kaddr + PAGE_SIZE);
 265         if (exec)
 266                 r3k_flush_icache_range(kaddr, kaddr + PAGE_SIZE);
 267 }
 268 
 269 static void local_r3k_flush_data_cache_page(void *addr)
 270 {
 271 }
 272 
 273 static void r3k_flush_data_cache_page(unsigned long addr)
 274 {
 275 }
 276 
 277 static void r3k_flush_kernel_vmap_range(unsigned long vaddr, int size)
 278 {
 279         BUG();
 280 }
 281 
 282 static void r3k_dma_cache_wback_inv(unsigned long start, unsigned long size)
 283 {
 284         /* Catch bad driver code */
 285         BUG_ON(size == 0);
 286 
 287         iob();
 288         r3k_flush_dcache_range(start, start + size);
 289 }
 290 
 291 void r3k_cache_init(void)
 292 {
 293         extern void build_clear_page(void);
 294         extern void build_copy_page(void);
 295 
 296         r3k_probe_cache();
 297 
 298         flush_cache_all = r3k_flush_cache_all;
 299         __flush_cache_all = r3k___flush_cache_all;
 300         flush_cache_mm = r3k_flush_cache_mm;
 301         flush_cache_range = r3k_flush_cache_range;
 302         flush_cache_page = r3k_flush_cache_page;
 303         flush_icache_range = r3k_flush_icache_range;
 304         local_flush_icache_range = r3k_flush_icache_range;
 305         __flush_icache_user_range = r3k_flush_icache_range;
 306         __local_flush_icache_user_range = r3k_flush_icache_range;
 307 
 308         __flush_kernel_vmap_range = r3k_flush_kernel_vmap_range;
 309 
 310         local_flush_data_cache_page = local_r3k_flush_data_cache_page;
 311         flush_data_cache_page = r3k_flush_data_cache_page;
 312 
 313         _dma_cache_wback_inv = r3k_dma_cache_wback_inv;
 314         _dma_cache_wback = r3k_dma_cache_wback_inv;
 315         _dma_cache_inv = r3k_dma_cache_wback_inv;
 316 
 317         printk("Primary instruction cache %ldkB, linesize %ld bytes.\n",
 318                 icache_size >> 10, icache_lsize);
 319         printk("Primary data cache %ldkB, linesize %ld bytes.\n",
 320                 dcache_size >> 10, dcache_lsize);
 321 
 322         build_clear_page();
 323         build_copy_page();
 324 }

/* [<][>][^][v][top][bottom][index][help] */