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