0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013 #include <linux/kernel.h>
0014 #include <linux/sched.h>
0015 #include <linux/smp.h>
0016 #include <linux/mm.h>
0017
0018 #include <asm/page.h>
0019 #include <asm/mmu_context.h>
0020 #include <asm/isadep.h>
0021 #include <asm/io.h>
0022 #include <asm/bootinfo.h>
0023 #include <asm/cpu.h>
0024
0025 static unsigned long icache_size, dcache_size;
0026 static unsigned long icache_lsize, dcache_lsize;
0027
0028 unsigned long r3k_cache_size(unsigned long ca_flags)
0029 {
0030 unsigned long flags, status, dummy, size;
0031 volatile unsigned long *p;
0032
0033 p = (volatile unsigned long *) KSEG0;
0034
0035 flags = read_c0_status();
0036
0037
0038 write_c0_status((ca_flags|flags)&~ST0_IEC);
0039
0040 *p = 0xa5a55a5a;
0041 dummy = *p;
0042 status = read_c0_status();
0043
0044 if (dummy != 0xa5a55a5a || (status & ST0_CM)) {
0045 size = 0;
0046 } else {
0047 for (size = 128; size <= 0x40000; size <<= 1)
0048 *(p + size) = 0;
0049 *p = -1;
0050 for (size = 128;
0051 (size <= 0x40000) && (*(p + size) == 0);
0052 size <<= 1)
0053 ;
0054 if (size > 0x40000)
0055 size = 0;
0056 }
0057
0058 write_c0_status(flags);
0059
0060 return size * sizeof(*p);
0061 }
0062
0063 unsigned long r3k_cache_lsize(unsigned long ca_flags)
0064 {
0065 unsigned long flags, status, lsize, i;
0066 volatile unsigned long *p;
0067
0068 p = (volatile unsigned long *) KSEG0;
0069
0070 flags = read_c0_status();
0071
0072
0073 write_c0_status((ca_flags|flags)&~ST0_IEC);
0074
0075 for (i = 0; i < 128; i++)
0076 *(p + i) = 0;
0077 *(volatile unsigned char *)p = 0;
0078 for (lsize = 1; lsize < 128; lsize <<= 1) {
0079 *(p + lsize);
0080 status = read_c0_status();
0081 if (!(status & ST0_CM))
0082 break;
0083 }
0084 for (i = 0; i < 128; i += lsize)
0085 *(volatile unsigned char *)(p + i) = 0;
0086
0087 write_c0_status(flags);
0088
0089 return lsize * sizeof(*p);
0090 }
0091
0092 static void r3k_probe_cache(void)
0093 {
0094 dcache_size = r3k_cache_size(ST0_ISC);
0095 if (dcache_size)
0096 dcache_lsize = r3k_cache_lsize(ST0_ISC);
0097
0098 icache_size = r3k_cache_size(ST0_ISC|ST0_SWC);
0099 if (icache_size)
0100 icache_lsize = r3k_cache_lsize(ST0_ISC|ST0_SWC);
0101 }
0102
0103 static void r3k_flush_icache_range(unsigned long start, unsigned long end)
0104 {
0105 unsigned long size, i, flags;
0106 volatile unsigned char *p;
0107
0108 size = end - start;
0109 if (size > icache_size || KSEGX(start) != KSEG0) {
0110 start = KSEG0;
0111 size = icache_size;
0112 }
0113 p = (char *)start;
0114
0115 flags = read_c0_status();
0116
0117
0118 write_c0_status((ST0_ISC|ST0_SWC|flags)&~ST0_IEC);
0119
0120 for (i = 0; i < size; i += 0x080) {
0121 asm( "sb\t$0, 0x000(%0)\n\t"
0122 "sb\t$0, 0x004(%0)\n\t"
0123 "sb\t$0, 0x008(%0)\n\t"
0124 "sb\t$0, 0x00c(%0)\n\t"
0125 "sb\t$0, 0x010(%0)\n\t"
0126 "sb\t$0, 0x014(%0)\n\t"
0127 "sb\t$0, 0x018(%0)\n\t"
0128 "sb\t$0, 0x01c(%0)\n\t"
0129 "sb\t$0, 0x020(%0)\n\t"
0130 "sb\t$0, 0x024(%0)\n\t"
0131 "sb\t$0, 0x028(%0)\n\t"
0132 "sb\t$0, 0x02c(%0)\n\t"
0133 "sb\t$0, 0x030(%0)\n\t"
0134 "sb\t$0, 0x034(%0)\n\t"
0135 "sb\t$0, 0x038(%0)\n\t"
0136 "sb\t$0, 0x03c(%0)\n\t"
0137 "sb\t$0, 0x040(%0)\n\t"
0138 "sb\t$0, 0x044(%0)\n\t"
0139 "sb\t$0, 0x048(%0)\n\t"
0140 "sb\t$0, 0x04c(%0)\n\t"
0141 "sb\t$0, 0x050(%0)\n\t"
0142 "sb\t$0, 0x054(%0)\n\t"
0143 "sb\t$0, 0x058(%0)\n\t"
0144 "sb\t$0, 0x05c(%0)\n\t"
0145 "sb\t$0, 0x060(%0)\n\t"
0146 "sb\t$0, 0x064(%0)\n\t"
0147 "sb\t$0, 0x068(%0)\n\t"
0148 "sb\t$0, 0x06c(%0)\n\t"
0149 "sb\t$0, 0x070(%0)\n\t"
0150 "sb\t$0, 0x074(%0)\n\t"
0151 "sb\t$0, 0x078(%0)\n\t"
0152 "sb\t$0, 0x07c(%0)\n\t"
0153 : : "r" (p) );
0154 p += 0x080;
0155 }
0156
0157 write_c0_status(flags);
0158 }
0159
0160 static void r3k_flush_dcache_range(unsigned long start, unsigned long end)
0161 {
0162 unsigned long size, i, flags;
0163 volatile unsigned char *p;
0164
0165 size = end - start;
0166 if (size > dcache_size || KSEGX(start) != KSEG0) {
0167 start = KSEG0;
0168 size = dcache_size;
0169 }
0170 p = (char *)start;
0171
0172 flags = read_c0_status();
0173
0174
0175 write_c0_status((ST0_ISC|flags)&~ST0_IEC);
0176
0177 for (i = 0; i < size; i += 0x080) {
0178 asm( "sb\t$0, 0x000(%0)\n\t"
0179 "sb\t$0, 0x004(%0)\n\t"
0180 "sb\t$0, 0x008(%0)\n\t"
0181 "sb\t$0, 0x00c(%0)\n\t"
0182 "sb\t$0, 0x010(%0)\n\t"
0183 "sb\t$0, 0x014(%0)\n\t"
0184 "sb\t$0, 0x018(%0)\n\t"
0185 "sb\t$0, 0x01c(%0)\n\t"
0186 "sb\t$0, 0x020(%0)\n\t"
0187 "sb\t$0, 0x024(%0)\n\t"
0188 "sb\t$0, 0x028(%0)\n\t"
0189 "sb\t$0, 0x02c(%0)\n\t"
0190 "sb\t$0, 0x030(%0)\n\t"
0191 "sb\t$0, 0x034(%0)\n\t"
0192 "sb\t$0, 0x038(%0)\n\t"
0193 "sb\t$0, 0x03c(%0)\n\t"
0194 "sb\t$0, 0x040(%0)\n\t"
0195 "sb\t$0, 0x044(%0)\n\t"
0196 "sb\t$0, 0x048(%0)\n\t"
0197 "sb\t$0, 0x04c(%0)\n\t"
0198 "sb\t$0, 0x050(%0)\n\t"
0199 "sb\t$0, 0x054(%0)\n\t"
0200 "sb\t$0, 0x058(%0)\n\t"
0201 "sb\t$0, 0x05c(%0)\n\t"
0202 "sb\t$0, 0x060(%0)\n\t"
0203 "sb\t$0, 0x064(%0)\n\t"
0204 "sb\t$0, 0x068(%0)\n\t"
0205 "sb\t$0, 0x06c(%0)\n\t"
0206 "sb\t$0, 0x070(%0)\n\t"
0207 "sb\t$0, 0x074(%0)\n\t"
0208 "sb\t$0, 0x078(%0)\n\t"
0209 "sb\t$0, 0x07c(%0)\n\t"
0210 : : "r" (p) );
0211 p += 0x080;
0212 }
0213
0214 write_c0_status(flags);
0215 }
0216
0217 static inline void r3k_flush_cache_all(void)
0218 {
0219 }
0220
0221 static inline void r3k___flush_cache_all(void)
0222 {
0223 r3k_flush_dcache_range(KSEG0, KSEG0 + dcache_size);
0224 r3k_flush_icache_range(KSEG0, KSEG0 + icache_size);
0225 }
0226
0227 static void r3k_flush_cache_mm(struct mm_struct *mm)
0228 {
0229 }
0230
0231 static void r3k_flush_cache_range(struct vm_area_struct *vma,
0232 unsigned long start, unsigned long end)
0233 {
0234 }
0235
0236 static void r3k_flush_cache_page(struct vm_area_struct *vma,
0237 unsigned long addr, unsigned long pfn)
0238 {
0239 unsigned long kaddr = KSEG0ADDR(pfn << PAGE_SHIFT);
0240 int exec = vma->vm_flags & VM_EXEC;
0241 struct mm_struct *mm = vma->vm_mm;
0242 pmd_t *pmdp;
0243 pte_t *ptep;
0244
0245 pr_debug("cpage[%08llx,%08lx]\n",
0246 cpu_context(smp_processor_id(), mm), addr);
0247
0248
0249 if (cpu_context(smp_processor_id(), mm) == 0)
0250 return;
0251
0252 pmdp = pmd_off(mm, addr);
0253 ptep = pte_offset_kernel(pmdp, addr);
0254
0255
0256 if (!(pte_val(*ptep) & _PAGE_PRESENT))
0257 return;
0258
0259 r3k_flush_dcache_range(kaddr, kaddr + PAGE_SIZE);
0260 if (exec)
0261 r3k_flush_icache_range(kaddr, kaddr + PAGE_SIZE);
0262 }
0263
0264 static void local_r3k_flush_data_cache_page(void *addr)
0265 {
0266 }
0267
0268 static void r3k_flush_data_cache_page(unsigned long addr)
0269 {
0270 }
0271
0272 static void r3k_flush_kernel_vmap_range(unsigned long vaddr, int size)
0273 {
0274 BUG();
0275 }
0276
0277 static void r3k_dma_cache_wback_inv(unsigned long start, unsigned long size)
0278 {
0279
0280 BUG_ON(size == 0);
0281
0282 iob();
0283 r3k_flush_dcache_range(start, start + size);
0284 }
0285
0286 void r3k_cache_init(void)
0287 {
0288 extern void build_clear_page(void);
0289 extern void build_copy_page(void);
0290
0291 r3k_probe_cache();
0292
0293 flush_cache_all = r3k_flush_cache_all;
0294 __flush_cache_all = r3k___flush_cache_all;
0295 flush_cache_mm = r3k_flush_cache_mm;
0296 flush_cache_range = r3k_flush_cache_range;
0297 flush_cache_page = r3k_flush_cache_page;
0298 flush_icache_range = r3k_flush_icache_range;
0299 local_flush_icache_range = r3k_flush_icache_range;
0300 __flush_icache_user_range = r3k_flush_icache_range;
0301 __local_flush_icache_user_range = r3k_flush_icache_range;
0302
0303 __flush_kernel_vmap_range = r3k_flush_kernel_vmap_range;
0304
0305 local_flush_data_cache_page = local_r3k_flush_data_cache_page;
0306 flush_data_cache_page = r3k_flush_data_cache_page;
0307
0308 _dma_cache_wback_inv = r3k_dma_cache_wback_inv;
0309 _dma_cache_wback = r3k_dma_cache_wback_inv;
0310 _dma_cache_inv = r3k_dma_cache_wback_inv;
0311
0312 pr_info("Primary instruction cache %ldkB, linesize %ld bytes.\n",
0313 icache_size >> 10, icache_lsize);
0314 pr_info("Primary data cache %ldkB, linesize %ld bytes.\n",
0315 dcache_size >> 10, dcache_lsize);
0316
0317 build_clear_page();
0318 build_copy_page();
0319 }