This source file includes following definitions.
- sun4c_v2p
- sun4c_p2v
- sun4c_flush_all
- sun4c_flush_context
- sun4c_flush_segment
- sun4c_flush_page
- sun4c_complete_all_stores
- sun4c_init_clean_segmap
- sun4c_init_clean_mmu
- sun4c_probe_vac
- sun4c_probe_mmu
- sun4c_init_ss2_cache_bug
- sun4c_init_alloc_dvma_pages
- sun4c_init_mmu_entry_pool
- fix_permissions
- sun4c_init_map_kernelprom
- sun4c_init_lock_area
- sun4c_init_rings
- add_ring
- remove_ring
- recycle_ring
- free_user_entry
- assign_user_entry
- free_kernel_entry
- assign_kernel_entry
- reassign_kernel_entry
- sun4c_init_fill_kernel_ring
- sun4c_init_fill_user_ring
- sun4c_kernel_unmap
- sun4c_kernel_map
- sun4c_user_unmap
- sun4c_user_map
- sun4c_demap_context
- sun4c_demap_one
- sun4c_user_strategy
- sun4c_kernel_strategy
- alloc_user_segment
- alloc_kernel_segment
- sun4c_update_mmu_cache
- sun4c_quick_kernel_fault
- get_task_segment
- free_task_segment
- garbage_collect
- sun4c_alloc_task_struct
- sun4c_alloc_kernel_stack
- sun4c_free_kernel_stack
- sun4c_free_task_struct
- sun4c_init_buckets
- sun4c_lockarea
- sun4c_unlockarea
- sun4c_get_scsi_one
- sun4c_get_scsi_sgl
- sun4c_release_scsi_one
- sun4c_release_scsi_sgl
- sun4c_init_lock_areas
- sun4c_flush_cache_all
- sun4c_flush_cache_mm
- sun4c_flush_cache_range
- sun4c_flush_cache_page
- sun4c_flush_page_to_ram
- sun4c_flush_tlb_all
- sun4c_flush_tlb_mm
- sun4c_flush_tlb_range
- sun4c_flush_tlb_page
- sun4c_set_pte
- sun4c_mapioaddr
- sun4c_alloc_context
- sun4c_switch_heuristic
- sun4c_switch_to_context
- sun4c_flush_hook
- sun4c_exit_hook
- sun4c_mmu_info
- sun4c_pmd_align
- sun4c_pgdir_align
- sun4c_vmalloc_start
- sun4c_pte_none
- sun4c_pte_present
- sun4c_pte_clear
- sun4c_pmd_none
- sun4c_pmd_bad
- sun4c_pmd_present
- sun4c_pmd_clear
- sun4c_pgd_none
- sun4c_pgd_bad
- sun4c_pgd_present
- sun4c_pgd_clear
- sun4c_pte_write
- sun4c_pte_dirty
- sun4c_pte_young
- sun4c_pte_wrprotect
- sun4c_pte_mkclean
- sun4c_pte_mkold
- sun4c_pte_mkwrite
- sun4c_pte_mkdirty
- sun4c_pte_mkyoung
- sun4c_mk_pte
- sun4c_mk_pte_io
- sun4c_pte_modify
- sun4c_pte_page
- sun4c_pmd_page
- sun4c_pgd_offset
- sun4c_pmd_offset
- sun4c_pte_offset
- sun4c_update_rootmmu_dir
- sun4c_pte_free_kernel
- sun4c_pte_alloc_kernel
- sun4c_pmd_free_kernel
- sun4c_pmd_alloc_kernel
- sun4c_pte_free
- sun4c_pte_alloc
- sun4c_pmd_free
- sun4c_pmd_alloc
- sun4c_pgd_free
- sun4c_pgd_alloc
- sun4c_paging_init
- ld_mmu_sun4c
1
2
3
4
5
6 #include <linux/kernel.h>
7 #include <linux/mm.h>
8
9 #include <asm/page.h>
10 #include <asm/pgtable.h>
11 #include <asm/vaddrs.h>
12 #include <asm/idprom.h>
13 #include <asm/machines.h>
14 #include <asm/memreg.h>
15 #include <asm/processor.h>
16
17 extern int num_segmaps, num_contexts;
18
19
20 struct sun4c_vac_props sun4c_vacinfo;
21 static int ctxflushes, segflushes, pageflushes;
22
23
24
25 static unsigned long sun4c_v2p(unsigned long vaddr)
26 {
27 return(vaddr - PAGE_OFFSET);
28 }
29
30 static unsigned long sun4c_p2v(unsigned long vaddr)
31 {
32 return(vaddr + PAGE_OFFSET);
33 }
34
35
36
37 void sun4c_flush_all(void)
38 {
39 unsigned long begin, end;
40
41 if(sun4c_vacinfo.on)
42 panic("SUN4C: AIEEE, trying to invalidate vac while"
43 " it is on.");
44
45
46 begin = AC_CACHETAGS;
47 end = (AC_CACHETAGS + sun4c_vacinfo.num_bytes);
48 while(begin < end) {
49 __asm__ __volatile__("sta %%g0, [%0] %1\n\t" : :
50 "r" (begin), "i" (ASI_CONTROL));
51 begin += sun4c_vacinfo.linesize;
52 }
53 }
54
55
56 static inline void sun4c_flush_context(void)
57 {
58 unsigned long vaddr;
59
60 ctxflushes++;
61 if(sun4c_vacinfo.do_hwflushes) {
62 for(vaddr=0; vaddr < sun4c_vacinfo.num_bytes; vaddr+=PAGE_SIZE)
63 __asm__ __volatile__("sta %%g0, [%0] %1\n\t" : :
64 "r" (vaddr), "i" (ASI_HWFLUSHCONTEXT));
65 } else {
66 int incr = sun4c_vacinfo.linesize;
67 for(vaddr=0; vaddr < sun4c_vacinfo.num_bytes; vaddr+=incr)
68 __asm__ __volatile__("sta %%g0, [%0] %1\n\t" : :
69 "r" (vaddr), "i" (ASI_FLUSHCTX));
70 }
71 }
72
73
74 static inline void sun4c_flush_segment(unsigned long addr)
75 {
76 unsigned long end;
77
78 segflushes++;
79 addr &= SUN4C_REAL_PGDIR_MASK;
80 end = (addr + sun4c_vacinfo.num_bytes);
81 if(sun4c_vacinfo.do_hwflushes) {
82 for( ; addr < end; addr += PAGE_SIZE)
83 __asm__ __volatile__("sta %%g0, [%0] %1\n\t" : :
84 "r" (addr), "i" (ASI_HWFLUSHSEG));
85 } else {
86 int incr = sun4c_vacinfo.linesize;
87 for( ; addr < end; addr += incr)
88 __asm__ __volatile__("sta %%g0, [%0] %1\n\t" : :
89 "r" (addr), "i" (ASI_FLUSHSEG));
90 }
91 }
92
93
94 static inline void sun4c_flush_page(unsigned long addr)
95 {
96 addr &= PAGE_MASK;
97
98 pageflushes++;
99 if(sun4c_vacinfo.do_hwflushes) {
100 __asm__ __volatile__("sta %%g0, [%0] %1\n\t" : :
101 "r" (addr), "i" (ASI_HWFLUSHPAGE));
102 } else {
103 unsigned long end = addr + PAGE_SIZE;
104 int incr = sun4c_vacinfo.linesize;
105
106 for( ; addr < end; addr += incr)
107 __asm__ __volatile__("sta %%g0, [%0] %1\n\t" : :
108 "r" (addr), "i" (ASI_FLUSHPG));
109 }
110 }
111
112
113
114
115
116
117
118
119 void sun4c_complete_all_stores(void)
120 {
121 volatile int _unused;
122
123 _unused = sun4c_get_context();
124 sun4c_set_context(_unused);
125 nop(); nop(); nop(); nop();
126 nop(); nop(); nop(); nop();
127
128 }
129
130
131 static inline void sun4c_init_clean_segmap(unsigned char pseg)
132 {
133 unsigned long vaddr;
134
135 sun4c_put_segmap(0, pseg);
136 for(vaddr = 0; vaddr < SUN4C_REAL_PGDIR_SIZE; vaddr+=PAGE_SIZE)
137 sun4c_put_pte(vaddr, 0);
138 sun4c_put_segmap(0, invalid_segment);
139 }
140
141 static inline void sun4c_init_clean_mmu(unsigned long kernel_end)
142 {
143 unsigned long vaddr;
144 unsigned char savectx, ctx;
145
146 savectx = sun4c_get_context();
147 kernel_end = SUN4C_REAL_PGDIR_ALIGN(kernel_end);
148 for(ctx = 0; ctx < num_contexts; ctx++) {
149 sun4c_set_context(ctx);
150 for(vaddr = 0; vaddr < 0x20000000; vaddr += SUN4C_REAL_PGDIR_SIZE)
151 sun4c_put_segmap(vaddr, invalid_segment);
152 for(vaddr = 0xe0000000; vaddr < KERNBASE; vaddr += SUN4C_REAL_PGDIR_SIZE)
153 sun4c_put_segmap(vaddr, invalid_segment);
154 for(vaddr = kernel_end; vaddr < KADB_DEBUGGER_BEGVM; vaddr += SUN4C_REAL_PGDIR_SIZE)
155 sun4c_put_segmap(vaddr, invalid_segment);
156 for(vaddr = LINUX_OPPROM_ENDVM; vaddr; vaddr += SUN4C_REAL_PGDIR_SIZE)
157 sun4c_put_segmap(vaddr, invalid_segment);
158 }
159 sun4c_set_context(ctx);
160 }
161
162 void sun4c_probe_vac(void)
163 {
164 int propval;
165
166 sun4c_disable_vac();
167 sun4c_vacinfo.num_bytes = prom_getintdefault(prom_root_node,
168 "vac-size", 65536);
169 sun4c_vacinfo.linesize = prom_getintdefault(prom_root_node,
170 "vac-linesize", 16);
171 sun4c_vacinfo.num_lines =
172 (sun4c_vacinfo.num_bytes / sun4c_vacinfo.linesize);
173 switch(sun4c_vacinfo.linesize) {
174 case 16:
175 sun4c_vacinfo.log2lsize = 4;
176 break;
177 case 32:
178 sun4c_vacinfo.log2lsize = 5;
179 break;
180 default:
181 prom_printf("probe_vac: Didn't expect vac-linesize of %d, halting\n",
182 sun4c_vacinfo.linesize);
183 prom_halt();
184 };
185
186 propval = prom_getintdefault(prom_root_node, "vac_hwflush", -1);
187 sun4c_vacinfo.do_hwflushes = (propval == -1 ?
188 prom_getintdefault(prom_root_node,
189 "vac-hwflush", 0) :
190 propval);
191
192 if(sun4c_vacinfo.num_bytes != 65536) {
193 prom_printf("WEIRD Sun4C VAC cache size, tell davem");
194 prom_halt();
195 }
196
197 sun4c_flush_all();
198 sun4c_enable_vac();
199 }
200
201 static void sun4c_probe_mmu(void)
202 {
203 num_segmaps = prom_getintdefault(prom_root_node, "mmu-npmg", 128);
204 num_contexts = prom_getintdefault(prom_root_node, "mmu-nctx", 0x8);
205 }
206
207 static inline void sun4c_init_ss2_cache_bug(void)
208 {
209 extern unsigned long start;
210
211 if(idprom->id_machtype == (SM_SUN4C | SM_4C_SS2)) {
212
213 printk("SS2 cache bug detected, uncaching trap table page\n");
214 sun4c_flush_page((unsigned int) &start);
215 sun4c_put_pte(((unsigned long) &start),
216 (sun4c_get_pte((unsigned long) &start) | _SUN4C_PAGE_NOCACHE));
217 }
218 }
219
220 static inline unsigned long sun4c_init_alloc_dvma_pages(unsigned long start_mem)
221 {
222 unsigned long addr, pte;
223
224 for(addr = DVMA_VADDR; addr < DVMA_END; addr += PAGE_SIZE) {
225 pte = (start_mem - PAGE_OFFSET) >> PAGE_SHIFT;
226 pte |= (_SUN4C_PAGE_VALID | _SUN4C_PAGE_WRITE | _SUN4C_PAGE_NOCACHE);
227 sun4c_put_pte(addr, pte);
228 start_mem += PAGE_SIZE;
229 }
230 return start_mem;
231 }
232
233
234 struct sun4c_mmu_entry {
235 struct sun4c_mmu_entry *next;
236 struct sun4c_mmu_entry *prev;
237 unsigned long vaddr;
238 unsigned char pseg;
239 unsigned char locked;
240 };
241 static struct sun4c_mmu_entry mmu_entry_pool[256];
242
243 static void sun4c_init_mmu_entry_pool(void)
244 {
245 int i;
246
247 for(i=0; i < 256; i++) {
248 mmu_entry_pool[i].pseg = i;
249 mmu_entry_pool[i].next = 0;
250 mmu_entry_pool[i].prev = 0;
251 mmu_entry_pool[i].vaddr = 0;
252 mmu_entry_pool[i].locked = 0;
253 }
254 mmu_entry_pool[invalid_segment].locked = 1;
255 }
256
257 static inline void fix_permissions(unsigned long vaddr, unsigned long bits_on,
258 unsigned long bits_off)
259 {
260 unsigned long start, end;
261
262 end = vaddr + SUN4C_REAL_PGDIR_SIZE;
263 for(start = vaddr; start < end; start += PAGE_SIZE)
264 if(sun4c_get_pte(start) & _SUN4C_PAGE_VALID)
265 sun4c_put_pte(start, (sun4c_get_pte(start) | bits_on) &
266 ~bits_off);
267 }
268
269 static inline void sun4c_init_map_kernelprom(unsigned long kernel_end)
270 {
271 unsigned long vaddr;
272 unsigned char pseg, ctx;
273
274 for(vaddr = KADB_DEBUGGER_BEGVM;
275 vaddr < LINUX_OPPROM_ENDVM;
276 vaddr += SUN4C_REAL_PGDIR_SIZE) {
277 pseg = sun4c_get_segmap(vaddr);
278 if(pseg != invalid_segment) {
279 mmu_entry_pool[pseg].locked = 1;
280 for(ctx = 0; ctx < num_contexts; ctx++)
281 prom_putsegment(ctx, vaddr, pseg);
282 fix_permissions(vaddr, _SUN4C_PAGE_PRIV, 0);
283 }
284 }
285 for(vaddr = KERNBASE; vaddr < kernel_end; vaddr += SUN4C_REAL_PGDIR_SIZE) {
286 pseg = sun4c_get_segmap(vaddr);
287 mmu_entry_pool[pseg].locked = 1;
288 for(ctx = 0; ctx < num_contexts; ctx++)
289 prom_putsegment(ctx, vaddr, pseg);
290 fix_permissions(vaddr, _SUN4C_PAGE_PRIV, _SUN4C_PAGE_NOCACHE);
291 }
292 }
293
294 static void sun4c_init_lock_area(unsigned long start, unsigned long end)
295 {
296 int i, ctx;
297
298 while(start < end) {
299 for(i=0; i < invalid_segment; i++)
300 if(!mmu_entry_pool[i].locked)
301 break;
302 mmu_entry_pool[i].locked = 1;
303 sun4c_init_clean_segmap(i);
304 for(ctx = 0; ctx < num_contexts; ctx++)
305 prom_putsegment(ctx, start, mmu_entry_pool[i].pseg);
306 start += SUN4C_REAL_PGDIR_SIZE;
307 }
308 }
309
310 struct sun4c_mmu_ring {
311 struct sun4c_mmu_entry ringhd;
312 int num_entries;
313 };
314 static struct sun4c_mmu_ring sun4c_context_ring[16];
315 static struct sun4c_mmu_ring sun4c_ufree_ring;
316 static struct sun4c_mmu_ring sun4c_kernel_ring;
317 static struct sun4c_mmu_ring sun4c_kfree_ring;
318
319 static inline void sun4c_init_rings(void)
320 {
321 int i;
322 for(i=0; i<16; i++) {
323 sun4c_context_ring[i].ringhd.next =
324 sun4c_context_ring[i].ringhd.prev =
325 &sun4c_context_ring[i].ringhd;
326 sun4c_context_ring[i].num_entries = 0;
327 }
328 sun4c_ufree_ring.ringhd.next = sun4c_ufree_ring.ringhd.prev =
329 &sun4c_ufree_ring.ringhd;
330 sun4c_kernel_ring.ringhd.next = sun4c_kernel_ring.ringhd.prev =
331 &sun4c_kernel_ring.ringhd;
332 sun4c_kfree_ring.ringhd.next = sun4c_kfree_ring.ringhd.prev =
333 &sun4c_kfree_ring.ringhd;
334 sun4c_ufree_ring.num_entries = sun4c_kernel_ring.num_entries =
335 sun4c_kfree_ring.num_entries = 0;
336 }
337
338 static inline void add_ring(struct sun4c_mmu_ring *ring, struct sun4c_mmu_entry *entry)
339 {
340 struct sun4c_mmu_entry *head = &ring->ringhd;
341
342 entry->prev = head;
343 (entry->next = head->next)->prev = entry;
344 head->next = entry;
345 ring->num_entries++;
346 }
347
348 static inline void remove_ring(struct sun4c_mmu_ring *ring, struct sun4c_mmu_entry *entry)
349 {
350 struct sun4c_mmu_entry *next = entry->next;
351
352 (next->prev = entry->prev)->next = next;
353 ring->num_entries--;
354 }
355
356 static inline void recycle_ring(struct sun4c_mmu_ring *ring, struct sun4c_mmu_entry *entry)
357 {
358 struct sun4c_mmu_entry *head = &ring->ringhd;
359 struct sun4c_mmu_entry *next = entry->next;
360
361 (next->prev = entry->prev)->next = next;
362 entry->prev = head; (entry->next = head->next)->prev = entry;
363 head->next = entry;
364
365 }
366
367 static inline void free_user_entry(int ctx, struct sun4c_mmu_entry *entry)
368 {
369 remove_ring(sun4c_context_ring+ctx, entry);
370 add_ring(&sun4c_ufree_ring, entry);
371 }
372
373 static inline void assign_user_entry(int ctx, struct sun4c_mmu_entry *entry)
374 {
375 remove_ring(&sun4c_ufree_ring, entry);
376 add_ring(sun4c_context_ring+ctx, entry);
377 }
378
379 static inline void free_kernel_entry(struct sun4c_mmu_entry *entry, struct sun4c_mmu_ring *ring)
380 {
381 remove_ring(ring, entry);
382 add_ring(&sun4c_kfree_ring, entry);
383 }
384
385 static inline void assign_kernel_entry(struct sun4c_mmu_entry *entry, struct sun4c_mmu_ring *ring)
386 {
387 remove_ring(ring, entry);
388 add_ring(&sun4c_kernel_ring, entry);
389 }
390
391 static inline void reassign_kernel_entry(struct sun4c_mmu_entry *entry)
392 {
393 recycle_ring(&sun4c_kernel_ring, entry);
394 }
395
396 static void sun4c_init_fill_kernel_ring(int howmany)
397 {
398 int i;
399
400 while(howmany) {
401 for(i=0; i < invalid_segment; i++)
402 if(!mmu_entry_pool[i].locked)
403 break;
404 mmu_entry_pool[i].locked = 1;
405 sun4c_init_clean_segmap(i);
406 add_ring(&sun4c_kfree_ring, &mmu_entry_pool[i]);
407 howmany--;
408 }
409 }
410
411 static void sun4c_init_fill_user_ring(void)
412 {
413 int i;
414
415 for(i=0; i < invalid_segment; i++) {
416 if(mmu_entry_pool[i].locked)
417 continue;
418 sun4c_init_clean_segmap(i);
419 add_ring(&sun4c_ufree_ring, &mmu_entry_pool[i]);
420 }
421 }
422
423 static inline void sun4c_kernel_unmap(struct sun4c_mmu_entry *kentry)
424 {
425 int savectx, ctx;
426
427 savectx = sun4c_get_context();
428 flush_user_windows();
429 sun4c_flush_segment(kentry->vaddr);
430 for(ctx = 0; ctx < num_contexts; ctx++) {
431 sun4c_set_context(ctx);
432 sun4c_put_segmap(kentry->vaddr, invalid_segment);
433 }
434 sun4c_set_context(savectx);
435 }
436
437 static inline void sun4c_kernel_map(struct sun4c_mmu_entry *kentry)
438 {
439 int savectx, ctx;
440
441 savectx = sun4c_get_context();
442 flush_user_windows();
443 for(ctx = 0; ctx < num_contexts; ctx++) {
444 sun4c_set_context(ctx);
445 sun4c_put_segmap(kentry->vaddr, kentry->pseg);
446 }
447 sun4c_set_context(savectx);
448 }
449
450 static inline void sun4c_user_unmap(struct sun4c_mmu_entry *uentry)
451 {
452 sun4c_flush_segment(uentry->vaddr);
453 sun4c_put_segmap(uentry->vaddr, invalid_segment);
454 }
455
456 static inline void sun4c_user_map(struct sun4c_mmu_entry *uentry)
457 {
458 unsigned long start = uentry->vaddr;
459 unsigned long end = start + SUN4C_REAL_PGDIR_SIZE;
460
461 sun4c_put_segmap(uentry->vaddr, uentry->pseg);
462 while(start < end) {
463 sun4c_put_pte(start, 0);
464 start += PAGE_SIZE;
465 }
466 }
467
468 static inline void sun4c_demap_context(struct sun4c_mmu_ring *crp, unsigned char ctx)
469 {
470 struct sun4c_mmu_entry *this_entry, *next_entry;
471 int savectx = sun4c_get_context();
472
473 this_entry = crp->ringhd.next;
474 flush_user_windows();
475 sun4c_set_context(ctx);
476 while(crp->num_entries) {
477 next_entry = this_entry->next;
478 sun4c_user_unmap(this_entry);
479 free_user_entry(ctx, this_entry);
480 this_entry = next_entry;
481 }
482 sun4c_set_context(savectx);
483 }
484
485 static inline void sun4c_demap_one(struct sun4c_mmu_ring *crp, unsigned char ctx)
486 {
487 struct sun4c_mmu_entry *entry = crp->ringhd.next;
488 int savectx = sun4c_get_context();
489
490 flush_user_windows();
491 sun4c_set_context(ctx);
492 sun4c_user_unmap(entry);
493 free_user_entry(ctx, entry);
494 sun4c_set_context(savectx);
495 }
496
497
498
499
500
501 static inline struct sun4c_mmu_entry *sun4c_user_strategy(void)
502 {
503 struct sun4c_mmu_ring *rp = 0;
504 unsigned char mmuhog, i, ctx = 0;
505
506
507 if(sun4c_ufree_ring.num_entries)
508 return sun4c_ufree_ring.ringhd.next;
509
510
511 mmuhog = 0;
512 for(i=0; i < num_contexts; i++) {
513 if(sun4c_context_ring[i].num_entries > mmuhog) {
514 rp = &sun4c_context_ring[i];
515 mmuhog = rp->num_entries;
516 ctx = i;
517 }
518 }
519 sun4c_demap_one(rp, ctx);
520 return sun4c_ufree_ring.ringhd.next;
521 }
522
523 static inline struct sun4c_mmu_entry *sun4c_kernel_strategy(void)
524 {
525 struct sun4c_mmu_entry *this_entry;
526
527
528 if(sun4c_kfree_ring.num_entries)
529 return sun4c_kfree_ring.ringhd.next;
530
531
532 this_entry = sun4c_kernel_ring.ringhd.prev;
533 sun4c_kernel_unmap(this_entry);
534 free_kernel_entry(this_entry, &sun4c_kernel_ring);
535 return sun4c_kfree_ring.ringhd.next;
536 }
537
538 static inline void alloc_user_segment(unsigned long address, unsigned char ctx)
539 {
540 struct sun4c_mmu_entry *entry;
541
542 address &= SUN4C_REAL_PGDIR_MASK;
543 entry = sun4c_user_strategy();
544 assign_user_entry(ctx, entry);
545 entry->vaddr = address;
546 sun4c_user_map(entry);
547 }
548
549 static inline void alloc_kernel_segment(unsigned long address)
550 {
551 struct sun4c_mmu_entry *entry;
552
553 address &= SUN4C_REAL_PGDIR_MASK;
554 entry = sun4c_kernel_strategy();
555
556 assign_kernel_entry(entry, &sun4c_kfree_ring);
557 entry->vaddr = address;
558 sun4c_kernel_map(entry);
559 }
560
561
562
563
564
565
566
567
568 static void sun4c_update_mmu_cache(struct vm_area_struct *vma, unsigned long address, pte_t pte)
569 {
570 unsigned long flags;
571
572 save_flags(flags); cli();
573 address &= PAGE_MASK;
574 if(sun4c_get_segmap(address) == invalid_segment)
575 alloc_user_segment(address, sun4c_get_context());
576 sun4c_put_pte(address, pte_val(pte));
577 restore_flags(flags);
578 }
579
580
581
582
583
584
585
586
587
588
589
590 static void sun4c_quick_kernel_fault(unsigned long address)
591 {
592 unsigned long end, flags;
593
594 save_flags(flags); cli();
595 address &= SUN4C_REAL_PGDIR_MASK;
596 end = address + SUN4C_REAL_PGDIR_SIZE;
597 if(sun4c_get_segmap(address) == invalid_segment)
598 alloc_kernel_segment(address);
599
600 if(address < SUN4C_VMALLOC_START) {
601 unsigned long pte;
602 pte = (address - PAGE_OFFSET) >> PAGE_SHIFT;
603 pte |= pgprot_val(SUN4C_PAGE_KERNEL);
604
605 while(address < end) {
606 sun4c_put_pte(address, pte++);
607 address += PAGE_SIZE;
608 }
609 } else {
610 pte_t *ptep;
611
612 ptep = (pte_t *) (PAGE_MASK & pgd_val(swapper_pg_dir[address>>SUN4C_PGDIR_SHIFT]));
613 ptep = (ptep + ((address >> PAGE_SHIFT) & (SUN4C_PTRS_PER_PTE - 1)));
614 while(address < end) {
615 sun4c_put_pte(address, pte_val(*ptep++));
616 address += PAGE_SIZE;
617 }
618 }
619 restore_flags(flags);
620 }
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639 struct task_bucket {
640 struct task_struct task;
641 char _unused1[PAGE_SIZE - sizeof(struct task_struct)];
642 char kstack[(PAGE_SIZE*3)];
643 };
644
645 struct task_bucket *sun4c_bucket[NR_TASKS];
646
647 #define BUCKET_EMPTY ((struct task_bucket *) 0)
648 #define BUCKET_SIZE (PAGE_SIZE << 2)
649 #define BUCKET_SHIFT 14
650 #define BUCKET_NUM(addr) ((((addr) - SUN4C_LOCK_VADDR) >> BUCKET_SHIFT))
651 #define BUCKET_ADDR(num) (((num) << BUCKET_SHIFT) + SUN4C_LOCK_VADDR)
652 #define BUCKET_PTE(page) \
653 ((((page) - PAGE_OFFSET) >> PAGE_SHIFT) | pgprot_val(SUN4C_PAGE_KERNEL))
654 #define BUCKET_PTE_PAGE(pte) \
655 (PAGE_OFFSET + (((pte) & 0xffff) << PAGE_SHIFT))
656
657 static inline void get_task_segment(unsigned long addr)
658 {
659 struct sun4c_mmu_entry *stolen;
660 unsigned long flags;
661
662 save_flags(flags); cli();
663 addr &= SUN4C_REAL_PGDIR_MASK;
664 stolen = sun4c_user_strategy();
665 remove_ring(&sun4c_ufree_ring, stolen);
666 stolen->vaddr = addr;
667 sun4c_kernel_map(stolen);
668 restore_flags(flags);
669 }
670
671 static inline void free_task_segment(unsigned long addr)
672 {
673 struct sun4c_mmu_entry *entry;
674 unsigned long flags;
675 unsigned char pseg;
676
677 save_flags(flags); cli();
678 addr &= SUN4C_REAL_PGDIR_MASK;
679 pseg = sun4c_get_segmap(addr);
680 entry = &mmu_entry_pool[pseg];
681 sun4c_flush_segment(addr);
682 sun4c_kernel_unmap(entry);
683 add_ring(&sun4c_ufree_ring, entry);
684 restore_flags(flags);
685 }
686
687 static inline void garbage_collect(int entry)
688 {
689 int start, end;
690
691
692 entry &= ~15;
693 start = entry;
694 for(end = (start + 16); start < end; start++)
695 if(sun4c_bucket[start] != BUCKET_EMPTY)
696 return;
697
698 free_task_segment(BUCKET_ADDR(entry));
699 }
700
701 static struct task_struct *sun4c_alloc_task_struct(void)
702 {
703 unsigned long addr, page;
704 int entry;
705
706 page = get_free_page(GFP_KERNEL);
707 if(!page)
708 return (struct task_struct *) 0;
709
710
711
712
713
714 for(entry = 0; entry < NR_TASKS; entry++)
715 if(sun4c_bucket[entry] == BUCKET_EMPTY)
716 break;
717 if(entry == NR_TASKS) {
718 free_page(page);
719 return (struct task_struct *) 0;
720 }
721 addr = BUCKET_ADDR(entry);
722 sun4c_bucket[entry] = (struct task_bucket *) addr;
723 if(sun4c_get_segmap(addr) == invalid_segment)
724 get_task_segment(addr);
725 sun4c_put_pte(addr, BUCKET_PTE(page));
726 return (struct task_struct *) addr;
727 }
728
729 static unsigned long sun4c_alloc_kernel_stack(struct task_struct *tsk)
730 {
731 unsigned long saddr = (unsigned long) tsk;
732 unsigned long page[3];
733
734 if(!saddr)
735 return 0;
736 page[0] = get_free_page(GFP_KERNEL);
737 if(!page[0])
738 return 0;
739 page[1] = get_free_page(GFP_KERNEL);
740 if(!page[1]) {
741 free_page(page[0]);
742 return 0;
743 }
744 page[2] = get_free_page(GFP_KERNEL);
745 if(!page[2]) {
746 free_page(page[0]);
747 free_page(page[1]);
748 return 0;
749 }
750 saddr += PAGE_SIZE;
751 sun4c_put_pte(saddr, BUCKET_PTE(page[0]));
752 sun4c_put_pte(saddr + PAGE_SIZE, BUCKET_PTE(page[1]));
753 sun4c_put_pte(saddr + (PAGE_SIZE<<1), BUCKET_PTE(page[2]));
754 return saddr;
755 }
756
757 static void sun4c_free_kernel_stack(unsigned long stack)
758 {
759 unsigned long page[3];
760
761 page[0] = BUCKET_PTE_PAGE(sun4c_get_pte(stack));
762 page[1] = BUCKET_PTE_PAGE(sun4c_get_pte(stack+PAGE_SIZE));
763 page[2] = BUCKET_PTE_PAGE(sun4c_get_pte(stack+(PAGE_SIZE<<1)));
764 sun4c_flush_segment(stack & SUN4C_REAL_PGDIR_MASK);
765 sun4c_put_pte(stack, 0);
766 sun4c_put_pte(stack + PAGE_SIZE, 0);
767 sun4c_put_pte(stack + (PAGE_SIZE<<1), 0);
768 free_page(page[0]);
769 free_page(page[1]);
770 free_page(page[2]);
771 }
772
773 static void sun4c_free_task_struct(struct task_struct *tsk)
774 {
775 unsigned long tsaddr = (unsigned long) tsk;
776 unsigned long page = BUCKET_PTE_PAGE(sun4c_get_pte(tsaddr));
777 int entry = BUCKET_NUM(tsaddr);
778
779 sun4c_flush_segment(tsaddr & SUN4C_REAL_PGDIR_MASK);
780 sun4c_put_pte(tsaddr, 0);
781 sun4c_bucket[entry] = BUCKET_EMPTY;
782 free_page(page);
783 garbage_collect(entry);
784 }
785
786 static void sun4c_init_buckets(void)
787 {
788 int entry;
789
790 if(sizeof(struct task_bucket) != (PAGE_SIZE << 2)) {
791 prom_printf("task bucket not 4 pages!\n");
792 prom_halt();
793 }
794 for(entry = 0; entry < NR_TASKS; entry++)
795 sun4c_bucket[entry] = BUCKET_EMPTY;
796 }
797
798 static unsigned long sun4c_iobuffer_start;
799 static unsigned long sun4c_iobuffer_end;
800 static unsigned long *sun4c_iobuffer_map;
801 static int iobuffer_map_size;
802
803
804
805
806
807
808 static char *sun4c_lockarea(char *vaddr, unsigned long size)
809 {
810 unsigned long base, scan;
811 unsigned long npages;
812 unsigned long vpage;
813 unsigned long pte;
814 unsigned long apage;
815
816 npages = (((unsigned long)vaddr & ~PAGE_MASK) +
817 size + (PAGE_SIZE-1)) >> PAGE_SHIFT;
818
819 scan = 0;
820 for (;;) {
821 scan = find_next_zero_bit(sun4c_iobuffer_map,
822 iobuffer_map_size, scan);
823 if ((base = scan) + npages > iobuffer_map_size) goto abend;
824 for (;;) {
825 if (scan >= base + npages) goto found;
826 if (test_bit(scan, sun4c_iobuffer_map)) break;
827 scan++;
828 }
829 }
830
831 found:
832 vpage = ((unsigned long) vaddr) & PAGE_MASK;
833 for (scan = base; scan < base+npages; scan++) {
834 pte = ((vpage-PAGE_OFFSET) >> PAGE_SHIFT);
835 pte |= pgprot_val(SUN4C_PAGE_KERNEL);
836 pte |= _SUN4C_PAGE_NOCACHE;
837 set_bit(scan, sun4c_iobuffer_map);
838 apage = (scan << PAGE_SHIFT) + sun4c_iobuffer_start;
839 sun4c_flush_page(vpage);
840 sun4c_put_pte(apage, pte);
841 vpage += PAGE_SIZE;
842 }
843 return (char *) ((base << PAGE_SHIFT) + sun4c_iobuffer_start +
844 (((unsigned long) vaddr) & ~PAGE_MASK));
845
846 abend:
847 printk("DMA vaddr=0x%p size=%08lx\n", vaddr, size);
848 panic("Out of iobuffer table");
849 return 0;
850 }
851
852 static void sun4c_unlockarea(char *vaddr, unsigned long size)
853 {
854 unsigned long vpage, npages;
855
856 vpage = (unsigned long)vaddr & PAGE_MASK;
857 npages = (((unsigned long)vaddr & ~PAGE_MASK) +
858 size + (PAGE_SIZE-1)) >> PAGE_SHIFT;
859 while (npages != 0) {
860 --npages;
861 sun4c_put_pte(vpage, 0);
862 clear_bit((vpage - sun4c_iobuffer_start) >> PAGE_SHIFT,
863 sun4c_iobuffer_map);
864 vpage += PAGE_SIZE;
865 }
866 }
867
868
869
870
871
872
873 static char *sun4c_get_scsi_one(char *bufptr, unsigned long len, struct linux_sbus *sbus)
874 {
875 unsigned long page;
876
877 page = ((unsigned long) bufptr) & PAGE_MASK;
878 if(page > high_memory)
879 return bufptr;
880 return sun4c_lockarea(bufptr, len);
881 }
882
883 static void sun4c_get_scsi_sgl(struct mmu_sglist *sg, int sz, struct linux_sbus *sbus)
884 {
885 while(sz >= 0) {
886 sg[sz].alt_addr = sun4c_lockarea(sg[sz].addr, sg[sz].len);
887 sz--;
888 }
889 }
890
891 static void sun4c_release_scsi_one(char *bufptr, unsigned long len, struct linux_sbus *sbus)
892 {
893 unsigned long page = (unsigned long) bufptr;
894
895 if(page < sun4c_iobuffer_start)
896 return;
897 sun4c_unlockarea(bufptr, len);
898 }
899
900 static void sun4c_release_scsi_sgl(struct mmu_sglist *sg, int sz, struct linux_sbus *sbus)
901 {
902 while(sz >= 0) {
903 sun4c_unlockarea(sg[sz].alt_addr, sg[sz].len);
904 sg[sz].alt_addr = 0;
905 sz--;
906 }
907 }
908
909 #define TASK_ENTRY_SIZE BUCKET_SIZE
910 #define LONG_ALIGN(x) (((x)+(sizeof(long))-1)&~((sizeof(long))-1))
911
912 struct vm_area_struct sun4c_kstack_vma;
913
914 static unsigned long sun4c_init_lock_areas(unsigned long start_mem)
915 {
916 unsigned long sun4c_taskstack_start;
917 unsigned long sun4c_taskstack_end;
918 int bitmap_size;
919
920 sun4c_init_buckets();
921 sun4c_taskstack_start = SUN4C_LOCK_VADDR;
922 sun4c_taskstack_end = (sun4c_taskstack_start +
923 (TASK_ENTRY_SIZE * NR_TASKS));
924 if(sun4c_taskstack_end >= SUN4C_LOCK_END) {
925 prom_printf("Too many tasks, decrease NR_TASKS please.\n");
926 prom_halt();
927 }
928
929 sun4c_iobuffer_start = SUN4C_REAL_PGDIR_ALIGN(sun4c_taskstack_end);
930 sun4c_iobuffer_end = SUN4C_LOCK_END;
931 bitmap_size = (sun4c_iobuffer_end - sun4c_iobuffer_start) >> PAGE_SHIFT;
932 bitmap_size = (bitmap_size + 7) >> 3;
933 bitmap_size = LONG_ALIGN(bitmap_size);
934 iobuffer_map_size = bitmap_size << 3;
935 sun4c_iobuffer_map = (unsigned long *) start_mem;
936 memset((void *) start_mem, 0, bitmap_size);
937 start_mem += bitmap_size;
938
939
940 sun4c_init_lock_area(sun4c_iobuffer_start, sun4c_iobuffer_end);
941 sun4c_kstack_vma.vm_mm = init_task.mm;
942 sun4c_kstack_vma.vm_start = sun4c_taskstack_start;
943 sun4c_kstack_vma.vm_end = sun4c_taskstack_end;
944 sun4c_kstack_vma.vm_page_prot = PAGE_SHARED;
945 sun4c_kstack_vma.vm_flags = VM_READ | VM_WRITE | VM_EXEC;
946 insert_vm_struct(&init_task, &sun4c_kstack_vma);
947 return start_mem;
948 }
949
950
951 static void sun4c_flush_cache_all(void)
952 {
953 unsigned long start, end;
954
955
956
957
958 start = AC_CACHETAGS;
959 end = start + sun4c_vacinfo.num_bytes;
960 flush_user_windows();
961 while(start < end) {
962 __asm__ __volatile__("sta %%g0, [%0] %1\n\t" : :
963 "r" (start), "i" (ASI_CONTROL));
964 start += sun4c_vacinfo.linesize;
965 }
966 }
967
968 static void sun4c_flush_cache_mm(struct mm_struct *mm)
969 {
970 unsigned long flags;
971 int octx;
972
973 #ifndef __SMP__
974 if(mm->context != NO_CONTEXT) {
975 #endif
976 octx = sun4c_get_context();
977 save_flags(flags); cli();
978 flush_user_windows();
979 sun4c_set_context(mm->context);
980 sun4c_flush_context();
981 sun4c_set_context(octx);
982 restore_flags(flags);
983 #ifndef __SMP__
984 }
985 #endif
986 }
987
988 static void sun4c_flush_cache_range(struct mm_struct *mm, unsigned long start, unsigned long end)
989 {
990 unsigned long flags;
991 int size, octx;
992
993 #ifndef __SMP__
994 if(mm->context != NO_CONTEXT) {
995 #endif
996 size = start - end;
997
998 flush_user_windows();
999
1000 if(size >= sun4c_vacinfo.num_bytes)
1001 goto flush_it_all;
1002
1003 save_flags(flags); cli();
1004 octx = sun4c_get_context();
1005 sun4c_set_context(mm->context);
1006
1007 if(size <= (PAGE_SIZE << 1)) {
1008 start &= PAGE_MASK;
1009 while(start < end) {
1010 sun4c_flush_page(start);
1011 start += PAGE_SIZE;
1012 };
1013 } else {
1014 start &= SUN4C_REAL_PGDIR_MASK;
1015 while(start < end) {
1016 sun4c_flush_segment(start);
1017 start += SUN4C_REAL_PGDIR_SIZE;
1018 }
1019 }
1020 sun4c_set_context(octx);
1021 restore_flags(flags);
1022 #ifndef __SMP__
1023 }
1024 #endif
1025 return;
1026
1027 flush_it_all:
1028
1029 sun4c_flush_cache_all();
1030 }
1031
1032 static void sun4c_flush_cache_page(struct vm_area_struct *vma, unsigned long page)
1033 {
1034 unsigned long flags;
1035 int octx;
1036 struct mm_struct *mm = vma->vm_mm;
1037
1038
1039
1040
1041 #ifndef __SMP__
1042 if(mm->context != NO_CONTEXT) {
1043 #endif
1044 octx = sun4c_get_context();
1045 save_flags(flags); cli();
1046 flush_user_windows();
1047 sun4c_set_context(mm->context);
1048 sun4c_flush_page(page);
1049 sun4c_set_context(octx);
1050 restore_flags(flags);
1051 #ifndef __SMP__
1052 }
1053 #endif
1054 }
1055
1056
1057
1058
1059 static void sun4c_flush_page_to_ram(unsigned long page)
1060 {
1061 }
1062
1063
1064
1065
1066
1067
1068 static void sun4c_flush_tlb_all(void)
1069 {
1070 struct sun4c_mmu_entry *this_entry, *next_entry;
1071 unsigned long flags;
1072 int savectx, ctx;
1073
1074 save_flags(flags); cli();
1075 this_entry = sun4c_kernel_ring.ringhd.next;
1076 savectx = sun4c_get_context();
1077 while(sun4c_kernel_ring.num_entries) {
1078 next_entry = this_entry->next;
1079 for(ctx = 0; ctx < num_contexts; ctx++) {
1080 sun4c_set_context(ctx);
1081 sun4c_put_segmap(this_entry->vaddr, invalid_segment);
1082 }
1083 free_kernel_entry(this_entry, &sun4c_kernel_ring);
1084 this_entry = next_entry;
1085 }
1086 sun4c_set_context(savectx);
1087 restore_flags(flags);
1088 }
1089
1090 static void sun4c_flush_tlb_mm(struct mm_struct *mm)
1091 {
1092 struct sun4c_mmu_entry *this_entry, *next_entry;
1093 struct sun4c_mmu_ring *crp;
1094 int savectx, ctx;
1095
1096 #ifndef __SMP__
1097 if(mm->context != NO_CONTEXT) {
1098 #endif
1099 crp = &sun4c_context_ring[mm->context];
1100 savectx = sun4c_get_context();
1101 ctx = mm->context;
1102 this_entry = crp->ringhd.next;
1103 sun4c_set_context(mm->context);
1104 while(crp->num_entries) {
1105 next_entry = this_entry->next;
1106 sun4c_user_unmap(this_entry);
1107 free_user_entry(ctx, this_entry);
1108 this_entry = next_entry;
1109 }
1110 sun4c_set_context(savectx);
1111 #ifndef __SMP__
1112 }
1113 #endif
1114 }
1115
1116 static void sun4c_flush_tlb_range(struct mm_struct *mm, unsigned long start, unsigned long end)
1117 {
1118 struct sun4c_mmu_entry *this_entry;
1119 unsigned char pseg, savectx;
1120
1121 #ifndef __SMP__
1122 if(mm->context == NO_CONTEXT)
1123 return;
1124 #endif
1125 flush_user_windows();
1126 savectx = sun4c_get_context();
1127 sun4c_set_context(mm->context);
1128 start &= SUN4C_REAL_PGDIR_MASK;
1129 while(start < end) {
1130 pseg = sun4c_get_segmap(start);
1131 if(pseg == invalid_segment)
1132 goto next_one;
1133 this_entry = &mmu_entry_pool[pseg];
1134 sun4c_put_segmap(this_entry->vaddr, invalid_segment);
1135 free_user_entry(mm->context, this_entry);
1136 next_one:
1137 start += SUN4C_REAL_PGDIR_SIZE;
1138 }
1139 sun4c_set_context(savectx);
1140 }
1141
1142 static void sun4c_flush_tlb_page(struct vm_area_struct *vma, unsigned long page)
1143 {
1144 struct mm_struct *mm = vma->vm_mm;
1145 int savectx;
1146
1147 #ifndef __SMP__
1148 if(mm->context != NO_CONTEXT) {
1149 #endif
1150 savectx = sun4c_get_context();
1151 sun4c_set_context(mm->context);
1152 page &= PAGE_MASK;
1153 if(sun4c_get_pte(page) & _SUN4C_PAGE_VALID)
1154 sun4c_put_pte(page, 0);
1155 sun4c_set_context(savectx);
1156 #ifndef __SMP__
1157 }
1158 #endif
1159 }
1160
1161
1162
1163
1164 static void sun4c_set_pte(pte_t *ptep, pte_t pte)
1165 {
1166
1167 if((pte_val(pte) & (_SUN4C_PAGE_WRITE|_SUN4C_PAGE_DIRTY)) ==
1168 _SUN4C_PAGE_WRITE)
1169 pte_val(pte) |= _SUN4C_PAGE_DIRTY;
1170
1171 *ptep = pte;
1172 }
1173
1174 void sun4c_mapioaddr(unsigned long physaddr, unsigned long virt_addr,
1175 int bus_type, int rdonly)
1176 {
1177 unsigned long page_entry;
1178
1179 page_entry = ((physaddr >> PAGE_SHIFT) & 0xffff);
1180 page_entry |= (_SUN4C_PAGE_VALID | _SUN4C_PAGE_WRITE |
1181 _SUN4C_PAGE_NOCACHE | _SUN4C_PAGE_IO);
1182 if(rdonly)
1183 page_entry &= (~_SUN4C_PAGE_WRITE);
1184 sun4c_flush_page(virt_addr);
1185 sun4c_put_pte(virt_addr, page_entry);
1186 }
1187
1188 static inline void sun4c_alloc_context(struct mm_struct *mm)
1189 {
1190 struct ctx_list *ctxp;
1191
1192 ctxp = ctx_free.next;
1193 if(ctxp != &ctx_free) {
1194 remove_from_ctx_list(ctxp);
1195 add_to_used_ctxlist(ctxp);
1196 mm->context = ctxp->ctx_number;
1197 ctxp->ctx_mm = mm;
1198 return;
1199 }
1200 ctxp = ctx_used.next;
1201 if(ctxp->ctx_mm == current->mm)
1202 ctxp = ctxp->next;
1203 if(ctxp == &ctx_used)
1204 panic("out of mmu contexts");
1205 remove_from_ctx_list(ctxp);
1206 add_to_used_ctxlist(ctxp);
1207 ctxp->ctx_mm->context = NO_CONTEXT;
1208 ctxp->ctx_mm = mm;
1209 mm->context = ctxp->ctx_number;
1210 sun4c_demap_context(&sun4c_context_ring[ctxp->ctx_number], ctxp->ctx_number);
1211 }
1212
1213 #if some_day_soon
1214 extern void force_user_fault(unsigned long, int);
1215
1216 void sun4c_switch_heuristic(struct pt_regs *regs)
1217 {
1218 unsigned long sp = regs->u_regs[UREG_FP];
1219 unsigned long sp2 = sp + REGWIN_SZ - 0x8;
1220
1221 force_user_fault(regs->pc, 0);
1222 force_user_fault(sp, 0);
1223 if((sp&PAGE_MASK) != (sp2&PAGE_MASK))
1224 force_user_fault(sp2, 0);
1225 }
1226 #endif
1227
1228 static void sun4c_switch_to_context(struct task_struct *tsk)
1229 {
1230
1231
1232
1233
1234
1235 if((tsk->tss.flags & SPARC_FLAG_KTHREAD) ||
1236 (tsk->flags & PF_EXITING))
1237 return;
1238 if(tsk->mm->context == NO_CONTEXT)
1239 sun4c_alloc_context(tsk->mm);
1240
1241 sun4c_set_context(tsk->mm->context);
1242 }
1243
1244 static void sun4c_flush_hook(void)
1245 {
1246 if(current->tss.flags & SPARC_FLAG_KTHREAD) {
1247 sun4c_alloc_context(current->mm);
1248 sun4c_set_context(current->mm->context);
1249 }
1250 }
1251
1252 static void sun4c_exit_hook(void)
1253 {
1254 struct ctx_list *ctx_old;
1255 struct mm_struct *mm = current->mm;
1256
1257 if(mm->context != NO_CONTEXT) {
1258 sun4c_demap_context(&sun4c_context_ring[mm->context], mm->context);
1259 ctx_old = ctx_list_pool + mm->context;
1260 remove_from_ctx_list(ctx_old);
1261 add_to_free_ctxlist(ctx_old);
1262 mm->context = NO_CONTEXT;
1263 }
1264 }
1265
1266 static char s4cinfo[512];
1267
1268 static char *sun4c_mmu_info(void)
1269 {
1270 int used_user_entries, i;
1271
1272 used_user_entries = 0;
1273 for(i=0; i < num_contexts; i++)
1274 used_user_entries += sun4c_context_ring[i].num_entries;
1275
1276 sprintf(s4cinfo, "vacsize\t\t: %d bytes\n"
1277 "vachwflush\t: %s\n"
1278 "vaclinesize\t: %d bytes\n"
1279 "mmuctxs\t\t: %d\n"
1280 "mmupsegs\t: %d\n"
1281 "usedpsegs\t: %d\n"
1282 "ufreepsegs\t: %d\n"
1283 "context\t\t: %d flushes\n"
1284 "segment\t\t: %d flushes\n"
1285 "page\t\t: %d flushes\n",
1286 sun4c_vacinfo.num_bytes,
1287 (sun4c_vacinfo.do_hwflushes ? "yes" : "no"),
1288 sun4c_vacinfo.linesize,
1289 num_contexts,
1290 (invalid_segment + 1),
1291 used_user_entries,
1292 sun4c_ufree_ring.num_entries,
1293 ctxflushes, segflushes, pageflushes);
1294
1295 return s4cinfo;
1296 }
1297
1298
1299
1300
1301
1302 static unsigned int sun4c_pmd_align(unsigned int addr) { return SUN4C_PMD_ALIGN(addr); }
1303 static unsigned int sun4c_pgdir_align(unsigned int addr) { return SUN4C_PGDIR_ALIGN(addr); }
1304
1305
1306
1307
1308
1309 #define PGD_PRESENT 0x001
1310 #define PGD_RW 0x002
1311 #define PGD_USER 0x004
1312 #define PGD_ACCESSED 0x020
1313 #define PGD_DIRTY 0x040
1314 #define PGD_TABLE (PGD_PRESENT | PGD_RW | PGD_USER | PGD_ACCESSED | PGD_DIRTY)
1315
1316 static unsigned long sun4c_vmalloc_start(void)
1317 {
1318 return SUN4C_VMALLOC_START;
1319 }
1320
1321 static int sun4c_pte_none(pte_t pte) { return !pte_val(pte); }
1322 static int sun4c_pte_present(pte_t pte) { return pte_val(pte) & _SUN4C_PAGE_VALID; }
1323 static void sun4c_pte_clear(pte_t *ptep) { pte_val(*ptep) = 0; }
1324
1325 static int sun4c_pmd_none(pmd_t pmd) { return !pmd_val(pmd); }
1326 static int sun4c_pmd_bad(pmd_t pmd)
1327 {
1328 return (pmd_val(pmd) & ~PAGE_MASK) != PGD_TABLE || pmd_val(pmd) > high_memory;
1329 }
1330
1331 static int sun4c_pmd_present(pmd_t pmd) { return pmd_val(pmd) & PGD_PRESENT; }
1332 static void sun4c_pmd_clear(pmd_t *pmdp) { pmd_val(*pmdp) = 0; }
1333
1334 static int sun4c_pgd_none(pgd_t pgd) { return 0; }
1335 static int sun4c_pgd_bad(pgd_t pgd) { return 0; }
1336 static int sun4c_pgd_present(pgd_t pgd) { return 1; }
1337 static void sun4c_pgd_clear(pgd_t * pgdp) { }
1338
1339
1340
1341
1342
1343 static int sun4c_pte_write(pte_t pte) { return pte_val(pte) & _SUN4C_PAGE_WRITE; }
1344 static int sun4c_pte_dirty(pte_t pte) { return pte_val(pte) & _SUN4C_PAGE_DIRTY; }
1345 static int sun4c_pte_young(pte_t pte) { return pte_val(pte) & _SUN4C_PAGE_REF; }
1346
1347 static pte_t sun4c_pte_wrprotect(pte_t pte) { pte_val(pte) &= ~_SUN4C_PAGE_WRITE; return pte; }
1348 static pte_t sun4c_pte_mkclean(pte_t pte) { pte_val(pte) &= ~_SUN4C_PAGE_DIRTY; return pte; }
1349 static pte_t sun4c_pte_mkold(pte_t pte) { pte_val(pte) &= ~_SUN4C_PAGE_REF; return pte; }
1350 static pte_t sun4c_pte_mkwrite(pte_t pte) { pte_val(pte) |= _SUN4C_PAGE_WRITE; return pte; }
1351 static pte_t sun4c_pte_mkdirty(pte_t pte) { pte_val(pte) |= _SUN4C_PAGE_DIRTY; return pte; }
1352 static pte_t sun4c_pte_mkyoung(pte_t pte) { pte_val(pte) |= _SUN4C_PAGE_REF; return pte; }
1353
1354
1355
1356
1357
1358 static pte_t sun4c_mk_pte(unsigned long page, pgprot_t pgprot)
1359 {
1360 return __pte(((page - PAGE_OFFSET) >> PAGE_SHIFT) | pgprot_val(pgprot));
1361 }
1362
1363 static pte_t sun4c_mk_pte_io(unsigned long page, pgprot_t pgprot, int space)
1364 {
1365 return __pte(((page - PAGE_OFFSET) >> PAGE_SHIFT) | pgprot_val(pgprot));
1366 }
1367
1368 static pte_t sun4c_pte_modify(pte_t pte, pgprot_t newprot)
1369 {
1370 return __pte((pte_val(pte) & _SUN4C_PAGE_CHG_MASK) | pgprot_val(newprot));
1371 }
1372
1373 static unsigned long sun4c_pte_page(pte_t pte)
1374 {
1375 return (PAGE_OFFSET + ((pte_val(pte) & 0xffff) << (PAGE_SHIFT)));
1376 }
1377
1378 static unsigned long sun4c_pmd_page(pmd_t pmd)
1379 {
1380 return (pmd_val(pmd) & PAGE_MASK);
1381 }
1382
1383
1384 static pgd_t *sun4c_pgd_offset(struct mm_struct * mm, unsigned long address)
1385 {
1386 return mm->pgd + (address >> SUN4C_PGDIR_SHIFT);
1387 }
1388
1389
1390 static pmd_t *sun4c_pmd_offset(pgd_t * dir, unsigned long address)
1391 {
1392 return (pmd_t *) dir;
1393 }
1394
1395
1396 static pte_t *sun4c_pte_offset(pmd_t * dir, unsigned long address)
1397 {
1398 return (pte_t *) sun4c_pmd_page(*dir) + ((address >> PAGE_SHIFT) & (SUN4C_PTRS_PER_PTE - 1));
1399 }
1400
1401
1402 static void sun4c_update_rootmmu_dir(struct task_struct *tsk, pgd_t *pgdir)
1403 {
1404 }
1405
1406
1407
1408
1409
1410 static void sun4c_pte_free_kernel(pte_t *pte)
1411 {
1412 free_page((unsigned long) pte);
1413 }
1414
1415 static pte_t *sun4c_pte_alloc_kernel(pmd_t *pmd, unsigned long address)
1416 {
1417 address = (address >> PAGE_SHIFT) & (SUN4C_PTRS_PER_PTE - 1);
1418 if (sun4c_pmd_none(*pmd)) {
1419 pte_t *page = (pte_t *) get_free_page(GFP_KERNEL);
1420 if (sun4c_pmd_none(*pmd)) {
1421 if (page) {
1422 pmd_val(*pmd) = PGD_TABLE | (unsigned long) page;
1423 return page + address;
1424 }
1425 pmd_val(*pmd) = PGD_TABLE | (unsigned long) BAD_PAGETABLE;
1426 return NULL;
1427 }
1428 free_page((unsigned long) page);
1429 }
1430 if (sun4c_pmd_bad(*pmd)) {
1431 printk("Bad pmd in pte_alloc_kernel: %08lx\n", pmd_val(*pmd));
1432 pmd_val(*pmd) = PGD_TABLE | (unsigned long) BAD_PAGETABLE;
1433 return NULL;
1434 }
1435 return (pte_t *) sun4c_pmd_page(*pmd) + address;
1436 }
1437
1438
1439
1440
1441
1442 static void sun4c_pmd_free_kernel(pmd_t *pmd)
1443 {
1444 pmd_val(*pmd) = 0;
1445 }
1446
1447 static pmd_t *sun4c_pmd_alloc_kernel(pgd_t *pgd, unsigned long address)
1448 {
1449 return (pmd_t *) pgd;
1450 }
1451
1452 static void sun4c_pte_free(pte_t *pte)
1453 {
1454 free_page((unsigned long) pte);
1455 }
1456
1457 static pte_t *sun4c_pte_alloc(pmd_t * pmd, unsigned long address)
1458 {
1459 address = (address >> PAGE_SHIFT) & (SUN4C_PTRS_PER_PTE - 1);
1460 if (sun4c_pmd_none(*pmd)) {
1461 pte_t *page = (pte_t *) get_free_page(GFP_KERNEL);
1462 if (sun4c_pmd_none(*pmd)) {
1463 if (page) {
1464 pmd_val(*pmd) = PGD_TABLE | (unsigned long) page;
1465 return page + address;
1466 }
1467 pmd_val(*pmd) = PGD_TABLE | (unsigned long) BAD_PAGETABLE;
1468 return NULL;
1469 }
1470 free_page((unsigned long) page);
1471 }
1472 if (sun4c_pmd_bad(*pmd)) {
1473 printk("Bad pmd in pte_alloc: %08lx\n", pmd_val(*pmd));
1474 pmd_val(*pmd) = PGD_TABLE | (unsigned long) BAD_PAGETABLE;
1475 return NULL;
1476 }
1477 return (pte_t *) sun4c_pmd_page(*pmd) + address;
1478 }
1479
1480
1481
1482
1483
1484 static void sun4c_pmd_free(pmd_t * pmd)
1485 {
1486 pmd_val(*pmd) = 0;
1487 }
1488
1489 static pmd_t *sun4c_pmd_alloc(pgd_t * pgd, unsigned long address)
1490 {
1491 return (pmd_t *) pgd;
1492 }
1493
1494 static void sun4c_pgd_free(pgd_t *pgd)
1495 {
1496 free_page((unsigned long) pgd);
1497 }
1498
1499 static pgd_t *sun4c_pgd_alloc(void)
1500 {
1501 return (pgd_t *) get_free_page(GFP_KERNEL);
1502 }
1503
1504 #define SUN4C_KERNEL_BUCKETS 16
1505 extern unsigned long free_area_init(unsigned long, unsigned long);
1506 extern unsigned long sparc_context_init(unsigned long, int);
1507 extern unsigned long end;
1508
1509 unsigned long sun4c_paging_init(unsigned long start_mem, unsigned long end_mem)
1510 {
1511 int i, cnt;
1512 unsigned long kernel_end;
1513
1514 kernel_end = (unsigned long) &end;
1515 kernel_end += (SUN4C_REAL_PGDIR_SIZE * 3);
1516 kernel_end = SUN4C_REAL_PGDIR_ALIGN(kernel_end);
1517 sun4c_probe_mmu();
1518 invalid_segment = (num_segmaps - 1);
1519 sun4c_init_mmu_entry_pool();
1520 sun4c_init_rings();
1521 sun4c_init_map_kernelprom(kernel_end);
1522 sun4c_init_clean_mmu(kernel_end);
1523 sun4c_init_fill_kernel_ring(SUN4C_KERNEL_BUCKETS);
1524 sun4c_init_lock_area(IOBASE_VADDR, IOBASE_END);
1525 sun4c_init_lock_area(DVMA_VADDR, DVMA_END);
1526 start_mem = sun4c_init_lock_areas(start_mem);
1527 sun4c_init_fill_user_ring();
1528
1529 sun4c_set_context(0);
1530 memset(swapper_pg_dir, 0, PAGE_SIZE);
1531 memset(pg0, 0, PAGE_SIZE);
1532
1533 pgd_val(swapper_pg_dir[SUN4C_VMALLOC_START>>SUN4C_PGDIR_SHIFT]) =
1534 PGD_TABLE | (unsigned long) pg0;
1535 sun4c_init_ss2_cache_bug();
1536 start_mem = PAGE_ALIGN(start_mem);
1537 start_mem = sun4c_init_alloc_dvma_pages(start_mem);
1538 start_mem = sparc_context_init(start_mem, num_contexts);
1539 start_mem = free_area_init(start_mem, end_mem);
1540 cnt = 0;
1541 for(i = 0; i < num_segmaps; i++)
1542 if(mmu_entry_pool[i].locked)
1543 cnt++;
1544 printk("SUN4C: %d mmu entries for the kernel\n", cnt);
1545 return start_mem;
1546 }
1547
1548
1549 void ld_mmu_sun4c(void)
1550 {
1551 printk("Loading sun4c MMU routines\n");
1552
1553
1554 pmd_shift = SUN4C_PMD_SHIFT;
1555 pmd_size = SUN4C_PMD_SIZE;
1556 pmd_mask = SUN4C_PMD_MASK;
1557 pgdir_shift = SUN4C_PGDIR_SHIFT;
1558 pgdir_size = SUN4C_PGDIR_SIZE;
1559 pgdir_mask = SUN4C_PGDIR_MASK;
1560
1561 ptrs_per_pte = SUN4C_PTRS_PER_PTE;
1562 ptrs_per_pmd = SUN4C_PTRS_PER_PMD;
1563 ptrs_per_pgd = SUN4C_PTRS_PER_PGD;
1564
1565 page_none = SUN4C_PAGE_NONE;
1566 page_shared = SUN4C_PAGE_SHARED;
1567 page_copy = SUN4C_PAGE_COPY;
1568 page_readonly = SUN4C_PAGE_READONLY;
1569 page_kernel = SUN4C_PAGE_KERNEL;
1570 pg_iobits = _SUN4C_PAGE_NOCACHE | _SUN4C_PAGE_IO | _SUN4C_PAGE_VALID
1571 | _SUN4C_PAGE_WRITE | _SUN4C_PAGE_DIRTY;
1572
1573
1574 #ifndef __SMP__
1575 flush_cache_all = sun4c_flush_cache_all;
1576 flush_cache_mm = sun4c_flush_cache_mm;
1577 flush_cache_range = sun4c_flush_cache_range;
1578 flush_cache_page = sun4c_flush_cache_page;
1579
1580 flush_tlb_all = sun4c_flush_tlb_all;
1581 flush_tlb_mm = sun4c_flush_tlb_mm;
1582 flush_tlb_range = sun4c_flush_tlb_range;
1583 flush_tlb_page = sun4c_flush_tlb_page;
1584 #else
1585 local_flush_cache_all = sun4c_flush_cache_all;
1586 local_flush_cache_mm = sun4c_flush_cache_mm;
1587 local_flush_cache_range = sun4c_flush_cache_range;
1588 local_flush_cache_page = sun4c_flush_cache_page;
1589
1590 local_flush_tlb_all = sun4c_flush_tlb_all;
1591 local_flush_tlb_mm = sun4c_flush_tlb_mm;
1592 local_flush_tlb_range = sun4c_flush_tlb_range;
1593 local_flush_tlb_page = sun4c_flush_tlb_page;
1594
1595 flush_cache_all = smp_flush_cache_all;
1596 flush_cache_mm = smp_flush_cache_mm;
1597 flush_cache_range = smp_flush_cache_range;
1598 flush_cache_page = smp_flush_cache_page;
1599
1600 flush_tlb_all = smp_flush_tlb_all;
1601 flush_tlb_mm = smp_flush_tlb_mm;
1602 flush_tlb_range = smp_flush_tlb_range;
1603 flush_tlb_page = smp_flush_tlb_page;
1604 #endif
1605
1606 flush_page_to_ram = sun4c_flush_page_to_ram;
1607
1608 set_pte = sun4c_set_pte;
1609 switch_to_context = sun4c_switch_to_context;
1610 pmd_align = sun4c_pmd_align;
1611 pgdir_align = sun4c_pgdir_align;
1612 vmalloc_start = sun4c_vmalloc_start;
1613
1614 pte_page = sun4c_pte_page;
1615 pmd_page = sun4c_pmd_page;
1616
1617 sparc_update_rootmmu_dir = sun4c_update_rootmmu_dir;
1618
1619 pte_none = sun4c_pte_none;
1620 pte_present = sun4c_pte_present;
1621 pte_clear = sun4c_pte_clear;
1622
1623 pmd_none = sun4c_pmd_none;
1624 pmd_bad = sun4c_pmd_bad;
1625 pmd_present = sun4c_pmd_present;
1626 pmd_clear = sun4c_pmd_clear;
1627
1628 pgd_none = sun4c_pgd_none;
1629 pgd_bad = sun4c_pgd_bad;
1630 pgd_present = sun4c_pgd_present;
1631 pgd_clear = sun4c_pgd_clear;
1632
1633 mk_pte = sun4c_mk_pte;
1634 mk_pte_io = sun4c_mk_pte_io;
1635 pte_modify = sun4c_pte_modify;
1636 pgd_offset = sun4c_pgd_offset;
1637 pmd_offset = sun4c_pmd_offset;
1638 pte_offset = sun4c_pte_offset;
1639 pte_free_kernel = sun4c_pte_free_kernel;
1640 pmd_free_kernel = sun4c_pmd_free_kernel;
1641 pte_alloc_kernel = sun4c_pte_alloc_kernel;
1642 pmd_alloc_kernel = sun4c_pmd_alloc_kernel;
1643 pte_free = sun4c_pte_free;
1644 pte_alloc = sun4c_pte_alloc;
1645 pmd_free = sun4c_pmd_free;
1646 pmd_alloc = sun4c_pmd_alloc;
1647 pgd_free = sun4c_pgd_free;
1648 pgd_alloc = sun4c_pgd_alloc;
1649
1650 pte_write = sun4c_pte_write;
1651 pte_dirty = sun4c_pte_dirty;
1652 pte_young = sun4c_pte_young;
1653 pte_wrprotect = sun4c_pte_wrprotect;
1654 pte_mkclean = sun4c_pte_mkclean;
1655 pte_mkold = sun4c_pte_mkold;
1656 pte_mkwrite = sun4c_pte_mkwrite;
1657 pte_mkdirty = sun4c_pte_mkdirty;
1658 pte_mkyoung = sun4c_pte_mkyoung;
1659 update_mmu_cache = sun4c_update_mmu_cache;
1660 mmu_exit_hook = sun4c_exit_hook;
1661 mmu_flush_hook = sun4c_flush_hook;
1662 mmu_lockarea = sun4c_lockarea;
1663 mmu_unlockarea = sun4c_unlockarea;
1664
1665 mmu_get_scsi_one = sun4c_get_scsi_one;
1666 mmu_get_scsi_sgl = sun4c_get_scsi_sgl;
1667 mmu_release_scsi_one = sun4c_release_scsi_one;
1668 mmu_release_scsi_sgl = sun4c_release_scsi_sgl;
1669
1670 mmu_v2p = sun4c_v2p;
1671 mmu_p2v = sun4c_p2v;
1672
1673
1674 alloc_kernel_stack = sun4c_alloc_kernel_stack;
1675 alloc_task_struct = sun4c_alloc_task_struct;
1676 free_kernel_stack = sun4c_free_kernel_stack;
1677 free_task_struct = sun4c_free_task_struct;
1678
1679 quick_kernel_fault = sun4c_quick_kernel_fault;
1680 mmu_info = sun4c_mmu_info;
1681
1682
1683 pgd_set = 0;
1684 pgd_page = 0;
1685 }