0001
0002
0003
0004
0005
0006 #include <linux/init.h>
0007 #include <linux/kernel.h>
0008 #include <linux/sched.h>
0009 #include <linux/mm.h>
0010
0011 #include <asm/mipsregs.h>
0012 #include <asm/bcache.h>
0013 #include <asm/cacheops.h>
0014 #include <asm/page.h>
0015 #include <asm/mmu_context.h>
0016 #include <asm/r4kcache.h>
0017
0018
0019 static unsigned long scache_size;
0020
0021 #define SC_LINE 32
0022 #define SC_PAGE (128*SC_LINE)
0023
0024 static inline void blast_r5000_scache(void)
0025 {
0026 unsigned long start = INDEX_BASE;
0027 unsigned long end = start + scache_size;
0028
0029 while(start < end) {
0030 cache_op(R5K_Page_Invalidate_S, start);
0031 start += SC_PAGE;
0032 }
0033 }
0034
0035 static void r5k_dma_cache_inv_sc(unsigned long addr, unsigned long size)
0036 {
0037 unsigned long end, a;
0038
0039
0040 BUG_ON(size == 0);
0041
0042 if (size >= scache_size) {
0043 blast_r5000_scache();
0044 return;
0045 }
0046
0047
0048
0049
0050
0051 a = addr & ~(SC_PAGE - 1);
0052 end = (addr + size - 1) & ~(SC_PAGE - 1);
0053 while (a <= end) {
0054 cache_op(R5K_Page_Invalidate_S, a);
0055 a += SC_PAGE;
0056 }
0057 }
0058
0059 static void r5k_sc_enable(void)
0060 {
0061 unsigned long flags;
0062
0063 local_irq_save(flags);
0064 set_c0_config(R5K_CONF_SE);
0065 blast_r5000_scache();
0066 local_irq_restore(flags);
0067 }
0068
0069 static void r5k_sc_disable(void)
0070 {
0071 unsigned long flags;
0072
0073 local_irq_save(flags);
0074 blast_r5000_scache();
0075 clear_c0_config(R5K_CONF_SE);
0076 local_irq_restore(flags);
0077 }
0078
0079 static inline int __init r5k_sc_probe(void)
0080 {
0081 unsigned long config = read_c0_config();
0082
0083 if (config & CONF_SC)
0084 return 0;
0085
0086 scache_size = (512 * 1024) << ((config & R5K_CONF_SS) >> 20);
0087
0088 printk("R5000 SCACHE size %ldkB, linesize 32 bytes.\n",
0089 scache_size >> 10);
0090
0091 return 1;
0092 }
0093
0094 static struct bcache_ops r5k_sc_ops = {
0095 .bc_enable = r5k_sc_enable,
0096 .bc_disable = r5k_sc_disable,
0097 .bc_wback_inv = r5k_dma_cache_inv_sc,
0098 .bc_inv = r5k_dma_cache_inv_sc
0099 };
0100
0101 void r5k_sc_init(void)
0102 {
0103 if (r5k_sc_probe()) {
0104 r5k_sc_enable();
0105 bcops = &r5k_sc_ops;
0106 }
0107 }