File: /usr/src/linux/arch/parisc/kernel/cache.c

1     /* $Id: cache.c,v 1.4 2000/01/25 00:11:38 prumpf Exp $
2      *
3      * This file is subject to the terms and conditions of the GNU General Public
4      * License.  See the file "COPYING" in the main directory of this archive
5      * for more details.
6      *
7      * Copyright (C) 1999 Helge Deller (07-13-1999)
8      * Copyright (C) 1999 SuSE GmbH Nuernberg
9      * Copyright (C) 2000 Philipp Rumpf (prumpf@tux.org)
10      *
11      * Cache and TLB management
12      *
13      */
14      
15     #include <linux/init.h>
16     #include <linux/kernel.h>
17     #include <linux/mm.h>
18     
19     #include <asm/pdc.h>
20     #include <asm/cache.h>
21     #include <asm/system.h>
22     #include <asm/page.h>
23     #include <asm/pgalloc.h>
24     
25     struct pdc_cache_info cache_info;
26     #ifndef __LP64__
27     static struct pdc_btlb_info btlb_info;
28     #endif
29     
30     
31     void __flush_page_to_ram(unsigned long address)
32     {
33     	__flush_dcache_range(address, PAGE_SIZE);
34     	__flush_icache_range(address, PAGE_SIZE);
35     }
36     
37     
38     
39     void flush_data_cache(void)
40     {
41     	register unsigned long base   = cache_info.dc_base;
42     	register unsigned long count  = cache_info.dc_count;
43     	register unsigned long loop   = cache_info.dc_loop;
44     	register unsigned long stride = cache_info.dc_stride;
45     	register unsigned long addr;
46     	register long i, j;
47     
48     	for(i=0,addr=base; i<count; i++,addr+=stride)
49     		for(j=0; j<loop; j++)
50     			fdce(addr);
51     }
52     		
53     static inline void flush_data_tlb_space(void)
54     {
55     	unsigned long base   = cache_info.dt_off_base;
56     	unsigned long count  = cache_info.dt_off_count;
57     	unsigned long stride = cache_info.dt_off_stride;
58     	unsigned long loop   = cache_info.dt_loop;
59     
60     	unsigned long addr;
61     	long i,j;
62     	
63     	for(i=0,addr=base; i<count; i++,addr+=stride)
64     		for(j=0; j<loop; j++)
65     			pdtlbe(addr);
66     }
67     
68     
69     
70     void flush_data_tlb(void)
71     {
72     	unsigned long base   = cache_info.dt_sp_base;
73     	unsigned long count  = cache_info.dt_sp_count;
74     	unsigned long stride = cache_info.dt_sp_stride;
75     	unsigned long space;
76     	unsigned long old_sr1;
77     	long i;
78     	
79     	old_sr1 = mfsp(1);
80     	
81     	for(i=0,space=base; i<count; i++, space+=stride) {
82     		mtsp(space,1);
83     		flush_data_tlb_space();
84     	}
85     
86     	mtsp(old_sr1, 1);
87     }
88     
89     static inline void flush_instruction_tlb_space(void)
90     {
91     	unsigned long base   = cache_info.it_off_base;
92     	unsigned long count  = cache_info.it_off_count;
93     	unsigned long stride = cache_info.it_off_stride;
94     	unsigned long loop   = cache_info.it_loop;
95     
96     	unsigned long addr;
97     	long i,j;
98     	
99     	for(i=0,addr=base; i<count; i++,addr+=stride)
100     		for(j=0; j<loop; j++)
101     			pitlbe(addr);
102     }
103     
104     void flush_instruction_tlb(void)
105     {
106     	unsigned long base   = cache_info.it_sp_base;
107     	unsigned long count  = cache_info.it_sp_count;
108     	unsigned long stride = cache_info.it_sp_stride;
109     	unsigned long space;
110     	unsigned long old_sr1;
111     	unsigned int i;
112     	
113     	old_sr1 = mfsp(1);
114     	
115     	for(i=0,space=base; i<count; i++, space+=stride) {
116     		mtsp(space,1);
117     		flush_instruction_tlb_space();
118     	}
119     
120     	mtsp(old_sr1, 1);
121     }
122     
123     
124     void __flush_tlb_space(unsigned long space)
125     {
126     	unsigned long old_sr1;
127     
128     	old_sr1 = mfsp(1);
129     	mtsp(space, 1);
130     	
131     	flush_data_tlb_space();
132     	flush_instruction_tlb_space();
133     
134     	mtsp(old_sr1, 1);
135     }
136     
137     
138     void flush_instruction_cache(void)
139     {
140     	register unsigned long base   = cache_info.ic_base;
141     	register unsigned long count  = cache_info.ic_count;
142     	register unsigned long loop   = cache_info.ic_loop;
143     	register unsigned long stride = cache_info.ic_stride;
144     	register unsigned long addr;
145     	register long i, j;
146     	unsigned long old_sr1;
147     	
148     	old_sr1 = mfsp(1);
149     	mtsp(0,1);
150     
151     	/*
152     	 * Note: fice instruction has 3 bit space field, so one must
153     	 *       be specified (otherwise you are justing using whatever
154     	 *       happens to be in sr0).
155     	 */
156     
157     	for(i=0,addr=base; i<count; i++,addr+=stride)
158     		for(j=0; j<loop; j++)
159     			fice(addr);
160     
161     	mtsp(old_sr1, 1);
162     }
163     
164     /* not yet ... fdc() needs to be implemented in cache.h !
165     void flush_datacache_range( unsigned int base, unsigned int end )
166     {
167         register long offset,offset_add;
168         offset_add = ( (1<<(cache_info.dc_conf.cc_block-1)) * 
169     		    cache_info.dc_conf.cc_line ) << 4;
170         for (offset=base; offset<=end; offset+=offset_add)
171     	fdc(space,offset);
172         fdc(space,end);
173     }
174     */
175     
176     /* flushes code and data-cache */
177     void flush_all_caches(void)
178     {
179     	flush_instruction_cache();
180     	flush_data_cache();
181     
182     	flush_instruction_tlb();
183     	flush_data_tlb();
184     
185     	asm volatile("sync");
186     	asm volatile("syncdma");
187     	asm volatile("sync");
188     }
189     
190     int get_cache_info(char *buffer)
191     {
192     	char *p = buffer;
193     
194     	p += sprintf(p, "I-cache\t\t: %ld KB\n", 
195     		cache_info.ic_size/1024 );
196     	p += sprintf(p, "D-cache\t\t: %ld KB (%s)%s\n", 
197     		cache_info.dc_size/1024,
198     		(cache_info.dc_conf.cc_wt ? "WT":"WB"),
199     		(cache_info.dc_conf.cc_sh ? " - shared I/D":"")
200     	);
201     
202     	p += sprintf(p, "ITLB entries\t: %ld\n" "DTLB entries\t: %ld%s\n",
203     		cache_info.it_size,
204     		cache_info.dt_size,
205     		cache_info.dt_conf.tc_sh ? " - shared with ITLB":""
206     	);
207     		
208     #ifndef __LP64__
209     	/* BTLB - Block TLB */
210     	if (btlb_info.max_size==0) {
211     		p += sprintf(p, "BTLB\t\t: not supported\n" );
212     	} else {
213     		p += sprintf(p, 
214     		"BTLB fixed\t: max. %d pages, pagesize=%d (%dMB)\n"
215     		"BTLB fix-entr.\t: %d instruction, %d data (%d combined)\n"
216     		"BTLB var-entr.\t: %d instruction, %d data (%d combined)\n",
217     		btlb_info.max_size, (int)4096,
218     		btlb_info.max_size>>8,
219     		btlb_info.fixed_range_info.num_i,
220     		btlb_info.fixed_range_info.num_d,
221     		btlb_info.fixed_range_info.num_comb, 
222     		btlb_info.variable_range_info.num_i,
223     		btlb_info.variable_range_info.num_d,
224     		btlb_info.variable_range_info.num_comb
225     		);
226     	}
227     #endif
228     
229     	return p - buffer;
230     }
231     
232     
233     void __init 
234     cache_init(void)
235     {
236     	if(pdc_cache_info(&cache_info)<0)
237     		panic("cache_init: pdc_cache_info failed");
238     
239     #if 0
240     	printk("ic_size %lx dc_size %lx it_size %lx pdc_cache_info %d*long pdc_cache_cf %d\n",
241     	    cache_info.ic_size,
242     	    cache_info.dc_size,
243     	    cache_info.it_size,
244     	    sizeof (struct pdc_cache_info) / sizeof (long),
245     	    sizeof (struct pdc_cache_cf)
246     	);
247     #endif
248     #ifndef __LP64__
249     	if(pdc_btlb_info(&btlb_info)<0) {
250     		memset(&btlb_info, 0, sizeof btlb_info);
251     	}
252     #endif
253     }
254