root/arch/sparc/mm/sun4c.c

/* [previous][next][first][last][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. sun4c_pmd_align
  2. sun4c_pgdir_align
  3. sun4c_vmalloc_start
  4. sun4c_update_rootmmu_dir
  5. sun4c_pte_none
  6. sun4c_pte_present
  7. sun4c_pte_inuse
  8. sun4c_pte_clear
  9. sun4c_pte_reuse
  10. sun4c_pmd_none
  11. sun4c_pmd_bad
  12. sun4c_pmd_present
  13. sun4c_pmd_inuse
  14. sun4c_pmd_clear
  15. sun4c_pmd_reuse
  16. sun4c_pgd_none
  17. sun4c_pgd_bad
  18. sun4c_pgd_present
  19. sun4c_pgd_inuse
  20. sun4c_pgd_clear
  21. sun4c_pte_read
  22. sun4c_pte_write
  23. sun4c_pte_exec
  24. sun4c_pte_dirty
  25. sun4c_pte_young
  26. sun4c_pte_cow
  27. sun4c_pte_wrprotect
  28. sun4c_pte_rdprotect
  29. sun4c_pte_exprotect
  30. sun4c_pte_mkclean
  31. sun4c_pte_mkold
  32. sun4c_pte_uncow
  33. sun4c_pte_mkwrite
  34. sun4c_pte_mkread
  35. sun4c_pte_mkexec
  36. sun4c_pte_mkdirty
  37. sun4c_pte_mkyoung
  38. sun4c_pte_mkcow
  39. sun4c_mk_pte
  40. sun4c_pte_modify
  41. sun4c_pte_page
  42. sun4c_pmd_page
  43. sun4c_pgd_offset
  44. sun4c_pmd_offset
  45. sun4c_pte_offset
  46. add_pseg_list
  47. remove_pseg_list
  48. add_pseg_ctxlist
  49. remove_pseg_ctxlist
  50. sun4c_init_pseg_lists
  51. sun4c_distribute_kernel_mapping
  52. sun4c_delete_kernel_mapping
  53. sun4c_lock_tlb_entry
  54. sun4c_unlock_tlb_entry
  55. sun4c_unload_context_from_tlb
  56. sun4c_unload_page_from_tlb
  57. sun4c_invalidate
  58. sun4c_set_pte
  59. sun4c_pte_free_kernel
  60. sun4c_pte_alloc_kernel
  61. sun4c_pmd_free_kernel
  62. sun4c_pmd_alloc_kernel
  63. sun4c_pte_free
  64. sun4c_pte_alloc
  65. sun4c_pmd_free
  66. sun4c_pmd_alloc
  67. sun4c_pgd_free
  68. sun4c_pgd_alloc
  69. sun4c_switch_to_context
  70. sun4c_mapioaddr
  71. sun4c_lockarea
  72. sun4c_unlockarea
  73. sun4c_get_scsi_buffer
  74. sun4c_release_scsi_buffer
  75. sun4c_get_fault_info
  76. sun4c_alloc_pseg
  77. sun4c_update_mmu_cache
  78. sun4c_free_all_nonlocked_psegs
  79. sun4c_alloc_pseg_from_free_list
  80. sun4c_init_lock_area
  81. sun4c_check_for_ss2_cache_bug
  82. sun4c_paging_init
  83. sun4c_test_wp
  84. sun4c_lock_entire_kernel
  85. sun4c_fork_hook
  86. sun4c_release_hook
  87. sun4c_flush_hook
  88. sun4c_task_cacheflush
  89. sun4c_exit_hook
  90. ld_mmu_sun4c

   1 /* $Id: sun4c.c,v 1.56 1995/11/25 00:59:39 davem Exp $
   2  * sun4c.c:  Sun4C specific mm routines.
   3  *
   4  * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
   5  */
   6 
   7 /* The SUN4C has an MMU based upon a Translation Lookaside Buffer scheme
   8  * where only so many translations can be loaded at once.  As Linus said
   9  * in Boston, this is a broken way of doing things.
  10  */
  11 
  12 #include <linux/kernel.h>
  13 #include <linux/sched.h>
  14 
  15 #include <asm/processor.h>
  16 #include <asm/page.h>
  17 #include <asm/pgtable.h>
  18 #include <asm/vac-ops.h>
  19 #include <asm/vaddrs.h>
  20 #include <asm/asi.h>
  21 #include <asm/system.h>
  22 #include <asm/contregs.h>
  23 #include <asm/oplib.h>
  24 #include <asm/idprom.h>
  25 #include <asm/machines.h>
  26 #include <asm/memreg.h>
  27 #include <asm/kdebug.h>
  28 
  29 /* Pseg allocation structures. */
  30 static struct pseg_list s4cpseg_pool[256];
  31 
  32 struct pseg_list s4cpseg_free;
  33 struct pseg_list s4cpseg_used;
  34 static struct pseg_list s4cpseg_locked;
  35 static struct pseg_list s4cpseg_per_context[16];
  36 
  37 static unsigned char pseg_count_per_context[16];
  38 
  39 unsigned int sun4c_pmd_align(unsigned int addr) { return SUN4C_PMD_ALIGN(addr); }
     /* [previous][next][first][last][top][bottom][index][help] */
  40 unsigned int sun4c_pgdir_align(unsigned int addr) { return SUN4C_PGDIR_ALIGN(addr); }
     /* [previous][next][first][last][top][bottom][index][help] */
  41 
  42 extern int num_segmaps, num_contexts;
  43 
  44 /* First the functions which the mid-level code uses to directly
  45  * manipulate the software page tables.  Some defines since we are
  46  * emulating the i386 page directory layout.
  47  */
  48 #define PGD_PRESENT  0x001
  49 #define PGD_RW       0x002
  50 #define PGD_USER     0x004
  51 #define PGD_ACCESSED 0x020
  52 #define PGD_DIRTY    0x040
  53 #define PGD_TABLE    (PGD_PRESENT | PGD_RW | PGD_USER | PGD_ACCESSED | PGD_DIRTY)
  54 
  55 unsigned long sun4c_vmalloc_start(void)
     /* [previous][next][first][last][top][bottom][index][help] */
  56 {
  57         return SUN4C_VMALLOC_START;
  58 }
  59 
  60 /* Update the root mmu directory on the sun4c mmu. */
  61 void sun4c_update_rootmmu_dir(struct task_struct *tsk, pgd_t *pgdir)
     /* [previous][next][first][last][top][bottom][index][help] */
  62 {
  63         (tsk)->tss.pgd_ptr = (unsigned long) (pgdir);
  64 }
  65 
  66 int sun4c_pte_none(pte_t pte)           { return !pte_val(pte); }
     /* [previous][next][first][last][top][bottom][index][help] */
  67 int sun4c_pte_present(pte_t pte)        { return pte_val(pte) & _SUN4C_PAGE_VALID; }
     /* [previous][next][first][last][top][bottom][index][help] */
  68 int sun4c_pte_inuse(pte_t *ptep)        { return mem_map[MAP_NR(ptep)].reserved || mem_map[MAP_NR(ptep)].count != 1; }
     /* [previous][next][first][last][top][bottom][index][help] */
  69 void sun4c_pte_clear(pte_t *ptep)       { pte_val(*ptep) = 0; }
     /* [previous][next][first][last][top][bottom][index][help] */
  70 void sun4c_pte_reuse(pte_t *ptep)
     /* [previous][next][first][last][top][bottom][index][help] */
  71 {
  72         if(!mem_map[MAP_NR(ptep)].reserved)
  73                 mem_map[MAP_NR(ptep)].count++;
  74 }
  75 
  76 int sun4c_pmd_none(pmd_t pmd)           { return !pmd_val(pmd); }
     /* [previous][next][first][last][top][bottom][index][help] */
  77 int sun4c_pmd_bad(pmd_t pmd)
     /* [previous][next][first][last][top][bottom][index][help] */
  78 {
  79         return (pmd_val(pmd) & ~PAGE_MASK) != PGD_TABLE || pmd_val(pmd) > high_memory;
  80 }
  81 
  82 int sun4c_pmd_present(pmd_t pmd)        { return pmd_val(pmd) & PGD_PRESENT; }
     /* [previous][next][first][last][top][bottom][index][help] */
  83 int sun4c_pmd_inuse(pmd_t *pmdp)        { return 0; }
     /* [previous][next][first][last][top][bottom][index][help] */
  84 void sun4c_pmd_clear(pmd_t *pmdp)       { pmd_val(*pmdp) = 0; }
     /* [previous][next][first][last][top][bottom][index][help] */
  85 void sun4c_pmd_reuse(pmd_t * pmdp)      { }
     /* [previous][next][first][last][top][bottom][index][help] */
  86 
  87 int sun4c_pgd_none(pgd_t pgd)           { return 0; }
     /* [previous][next][first][last][top][bottom][index][help] */
  88 int sun4c_pgd_bad(pgd_t pgd)            { return 0; }
     /* [previous][next][first][last][top][bottom][index][help] */
  89 int sun4c_pgd_present(pgd_t pgd)        { return 1; }
     /* [previous][next][first][last][top][bottom][index][help] */
  90 int sun4c_pgd_inuse(pgd_t *pgdp)        { return mem_map[MAP_NR(pgdp)].reserved; }
     /* [previous][next][first][last][top][bottom][index][help] */
  91 void sun4c_pgd_clear(pgd_t * pgdp)      { }
     /* [previous][next][first][last][top][bottom][index][help] */
  92 
  93 /*
  94  * The following only work if pte_present() is true.
  95  * Undefined behaviour if not..
  96  */
  97 int sun4c_pte_read(pte_t pte)           { return !(pte_val(pte) & _SUN4C_PAGE_PRIV); }
     /* [previous][next][first][last][top][bottom][index][help] */
  98 int sun4c_pte_write(pte_t pte)          { return pte_val(pte) & _SUN4C_PAGE_WRITE; }
     /* [previous][next][first][last][top][bottom][index][help] */
  99 int sun4c_pte_exec(pte_t pte)           { return !(pte_val(pte) & _SUN4C_PAGE_PRIV); }
     /* [previous][next][first][last][top][bottom][index][help] */
 100 int sun4c_pte_dirty(pte_t pte)          { return pte_val(pte) & _SUN4C_PAGE_DIRTY; }
     /* [previous][next][first][last][top][bottom][index][help] */
 101 int sun4c_pte_young(pte_t pte)          { return pte_val(pte) & _SUN4C_PAGE_REF; }
     /* [previous][next][first][last][top][bottom][index][help] */
 102 int sun4c_pte_cow(pte_t pte)            { return pte_val(pte) & _SUN4C_PAGE_COW; }
     /* [previous][next][first][last][top][bottom][index][help] */
 103 
 104 pte_t sun4c_pte_wrprotect(pte_t pte)    { pte_val(pte) &= ~_SUN4C_PAGE_WRITE; return pte; }
     /* [previous][next][first][last][top][bottom][index][help] */
 105 pte_t sun4c_pte_rdprotect(pte_t pte)    { pte_val(pte) |= _SUN4C_PAGE_PRIV; return pte; }
     /* [previous][next][first][last][top][bottom][index][help] */
 106 pte_t sun4c_pte_exprotect(pte_t pte)    { pte_val(pte) |= _SUN4C_PAGE_PRIV; return pte; }
     /* [previous][next][first][last][top][bottom][index][help] */
 107 pte_t sun4c_pte_mkclean(pte_t pte)      { pte_val(pte) &= ~_SUN4C_PAGE_DIRTY; return pte; }
     /* [previous][next][first][last][top][bottom][index][help] */
 108 pte_t sun4c_pte_mkold(pte_t pte)        { pte_val(pte) &= ~_SUN4C_PAGE_REF; return pte; }
     /* [previous][next][first][last][top][bottom][index][help] */
 109 pte_t sun4c_pte_uncow(pte_t pte)        { pte_val(pte) &= ~_SUN4C_PAGE_COW; return pte; }
     /* [previous][next][first][last][top][bottom][index][help] */
 110 pte_t sun4c_pte_mkwrite(pte_t pte)      { pte_val(pte) |= _SUN4C_PAGE_WRITE; return pte; }
     /* [previous][next][first][last][top][bottom][index][help] */
 111 pte_t sun4c_pte_mkread(pte_t pte)       { pte_val(pte) &= ~_SUN4C_PAGE_PRIV; return pte; }
     /* [previous][next][first][last][top][bottom][index][help] */
 112 pte_t sun4c_pte_mkexec(pte_t pte)       { pte_val(pte) &= ~_SUN4C_PAGE_PRIV; return pte; }
     /* [previous][next][first][last][top][bottom][index][help] */
 113 pte_t sun4c_pte_mkdirty(pte_t pte)      { pte_val(pte) |= _SUN4C_PAGE_DIRTY; return pte; }
     /* [previous][next][first][last][top][bottom][index][help] */
 114 pte_t sun4c_pte_mkyoung(pte_t pte)      { pte_val(pte) |= _SUN4C_PAGE_REF; return pte; }
     /* [previous][next][first][last][top][bottom][index][help] */
 115 pte_t sun4c_pte_mkcow(pte_t pte)        { pte_val(pte) |= _SUN4C_PAGE_COW; return pte; }
     /* [previous][next][first][last][top][bottom][index][help] */
 116 
 117 /*
 118  * Conversion functions: convert a page and protection to a page entry,
 119  * and a page entry and page directory to the page they refer to.
 120  */
 121 pte_t sun4c_mk_pte(unsigned long page, pgprot_t pgprot)
     /* [previous][next][first][last][top][bottom][index][help] */
 122 {
 123         return __pte(((page - PAGE_OFFSET) >> PAGE_SHIFT) | pgprot_val(pgprot));
 124 }
 125 
 126 pte_t sun4c_pte_modify(pte_t pte, pgprot_t newprot)
     /* [previous][next][first][last][top][bottom][index][help] */
 127 {
 128         return __pte((pte_val(pte) & _SUN4C_PAGE_CHG_MASK) | pgprot_val(newprot));
 129 }
 130 
 131 unsigned long sun4c_pte_page(pte_t pte)
     /* [previous][next][first][last][top][bottom][index][help] */
 132 {
 133         return (PAGE_OFFSET + ((pte_val(pte) & 0xffff) << (PAGE_SHIFT)));
 134 }
 135 
 136 unsigned long sun4c_pmd_page(pmd_t pmd)
     /* [previous][next][first][last][top][bottom][index][help] */
 137 {
 138         return (pmd_val(pmd) & PAGE_MASK);
 139 }
 140 
 141 /* to find an entry in a page-table-directory */
 142 pgd_t *sun4c_pgd_offset(struct mm_struct * mm, unsigned long address)
     /* [previous][next][first][last][top][bottom][index][help] */
 143 {
 144         return mm->pgd + (address >> SUN4C_PGDIR_SHIFT);
 145 }
 146 
 147 /* Find an entry in the second-level page table.. */
 148 pmd_t *sun4c_pmd_offset(pgd_t * dir, unsigned long address)
     /* [previous][next][first][last][top][bottom][index][help] */
 149 {
 150         return (pmd_t *) dir;
 151 }
 152 
 153 /* Find an entry in the third-level page table.. */ 
 154 pte_t *sun4c_pte_offset(pmd_t * dir, unsigned long address)
     /* [previous][next][first][last][top][bottom][index][help] */
 155 {
 156         return (pte_t *) sun4c_pmd_page(*dir) + ((address >> PAGE_SHIFT) & (SUN4C_PTRS_PER_PTE - 1));
 157 }
 158 
 159 /* Here comes the sun4c mmu-tlb management engine.  It is here because
 160  * some of the mid-level mm support needs to be able to lock down
 161  * critical areas of kernel memory into the tlb.
 162  */
 163 static inline void add_pseg_list(struct pseg_list *head, struct pseg_list *entry)
     /* [previous][next][first][last][top][bottom][index][help] */
 164 {
 165         entry->next = head;
 166         (entry->prev = head->prev)->next = entry;
 167         head->prev = entry;
 168 }
 169 #define add_to_used_pseg_list(entry) add_pseg_list(&s4cpseg_used, entry)
 170 #define add_to_free_pseg_list(entry) add_pseg_list(&s4cpseg_free, entry)
 171 #define add_to_locked_pseg_list(entry) add_pseg_list(&s4cpseg_locked, entry)
 172 
 173 static inline void remove_pseg_list(struct pseg_list *entry)
     /* [previous][next][first][last][top][bottom][index][help] */
 174 {
 175         entry->next->prev = entry->prev;
 176         entry->prev->next = entry->next;
 177 }
 178 
 179 static inline void add_pseg_ctxlist(struct pseg_list *entry, int ctx)
     /* [previous][next][first][last][top][bottom][index][help] */
 180 {
 181         struct pseg_list *head = &s4cpseg_per_context[ctx];
 182 
 183         entry->ctx_next = head;
 184         (entry->ctx_prev = head->ctx_prev)->ctx_next = entry;
 185         head->ctx_prev = entry;
 186         pseg_count_per_context[ctx]++;
 187 }
 188 
 189 static inline void remove_pseg_ctxlist(struct pseg_list *entry, int ctx)
     /* [previous][next][first][last][top][bottom][index][help] */
 190 {
 191         entry->ctx_next->ctx_prev = entry->ctx_prev;
 192         entry->ctx_prev->ctx_next = entry->ctx_next;
 193         pseg_count_per_context[ctx]--;
 194 }
 195 
 196 static inline void sun4c_init_pseg_lists(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 197 {
 198         int i;
 199 
 200         s4cpseg_free.prev = s4cpseg_free.next = &s4cpseg_free;
 201         s4cpseg_used.prev = s4cpseg_used.next = &s4cpseg_used;
 202         s4cpseg_locked.prev = s4cpseg_locked.next = &s4cpseg_locked;
 203         for(i = 0; i < num_contexts; i++) {
 204                 s4cpseg_per_context[i].ctx_prev = s4cpseg_per_context[i].ctx_next =
 205                         &s4cpseg_per_context[i];
 206         }
 207         for(i = 0; i <= invalid_segment; i++) {
 208                 s4cpseg_pool[i].vaddr = 0;
 209                 s4cpseg_pool[i].context = 0;
 210                 s4cpseg_pool[i].ref_cnt = 0;
 211                 s4cpseg_pool[i].hardlock = 0;
 212                 s4cpseg_pool[i].pseg = i;
 213         }
 214         s4cpseg_pool[invalid_segment].hardlock = 1;
 215 }
 216 
 217 static inline void sun4c_distribute_kernel_mapping(unsigned long address,
     /* [previous][next][first][last][top][bottom][index][help] */
 218                                                    unsigned char pseg)
 219 {
 220         unsigned int flags;
 221         int ctx, save_ctx;
 222 
 223         save_flags(flags); cli();
 224         save_ctx = get_context();
 225         flush_user_windows();
 226         for(ctx = 0; ctx < num_contexts; ctx++) {
 227                 set_context(ctx);
 228                 put_segmap(address, pseg);
 229         }
 230         set_context(save_ctx);
 231         restore_flags(flags);
 232 }
 233 
 234 static inline void sun4c_delete_kernel_mapping(unsigned long address)
     /* [previous][next][first][last][top][bottom][index][help] */
 235 {
 236         unsigned int flags;
 237         int ctx, save_ctx;
 238 
 239         save_flags(flags); cli();
 240         save_ctx = get_context();
 241         flush_user_windows();
 242 
 243         /* Flush only needed in one context for kernel mappings. */
 244         sun4c_flush_segment(address);
 245         for(ctx = 0; ctx < num_contexts; ctx++) {
 246                 set_context(ctx);
 247                 put_segmap(address, invalid_segment);
 248         }
 249         set_context(save_ctx);
 250         restore_flags(flags);
 251 }
 252 
 253 /* NOTE: You can only lock kernel tlb entries, attempts to lock
 254  *       pages in user vm will bolix the entire system.
 255  */
 256 static inline void sun4c_lock_tlb_entry(unsigned long address)
     /* [previous][next][first][last][top][bottom][index][help] */
 257 {
 258         unsigned long flags;
 259         unsigned char pseg;
 260 
 261         save_flags(flags); cli();
 262         /* Fault it in. */
 263         __asm__ __volatile__("ldub [%0], %%g0\n\t" : : "r" (address));
 264         address &= SUN4C_REAL_PGDIR_MASK;
 265         pseg = get_segmap(address);
 266         if(address < KERNBASE)
 267                 panic("locking user address space into tlb!");
 268         if(pseg == invalid_segment)
 269                 panic("cannot lock kernel tlb entry...");
 270         if(!s4cpseg_pool[pseg].ref_cnt++ && !s4cpseg_pool[pseg].hardlock) {
 271                 /* Move from used to locked list. */
 272                 remove_pseg_list(&s4cpseg_pool[pseg]);
 273                 add_to_locked_pseg_list(&s4cpseg_pool[pseg]);
 274         }
 275         restore_flags(flags);
 276 }
 277 
 278 static inline void sun4c_unlock_tlb_entry(unsigned long address)
     /* [previous][next][first][last][top][bottom][index][help] */
 279 {
 280         unsigned long flags;
 281         struct pseg_list *psegp;
 282         unsigned char pseg;
 283 
 284         save_flags(flags); cli();
 285         address &= SUN4C_REAL_PGDIR_MASK;
 286         pseg = get_segmap(address);
 287         if(address < KERNBASE)
 288                 panic("unlocking user tlb entry!");
 289         if(pseg == invalid_segment)
 290                 panic("unlocking non-locked kernel tlb entry...");
 291         psegp = &s4cpseg_pool[pseg];
 292         if(!--psegp->ref_cnt && !psegp->hardlock) {
 293                 /* Move from locked list to used list. */
 294                 remove_pseg_list(psegp);
 295                 add_to_used_pseg_list(psegp);
 296         }
 297         restore_flags(flags);
 298 }
 299 
 300 /* Anyone who calls this must turn _all_ interrupts off and flush
 301  * any necessary user windows beforehand.
 302  */
 303 static inline void sun4c_unload_context_from_tlb(unsigned char ctx)
     /* [previous][next][first][last][top][bottom][index][help] */
 304 {
 305         struct pseg_list *psegp, *pnextp;
 306 
 307         if(pseg_count_per_context[ctx]) {
 308                 sun4c_flush_context(); /* Most efficient */
 309                 psegp = s4cpseg_per_context[ctx].ctx_next;
 310                 while(psegp != &s4cpseg_per_context[ctx]) {
 311                         pnextp = psegp->ctx_next;
 312                         if(psegp->vaddr >= KERNBASE)
 313                                 panic("Unloading kernel from tlb, not good.");
 314                         put_segmap(psegp->vaddr, invalid_segment);
 315                         remove_pseg_ctxlist(psegp, ctx);
 316                         remove_pseg_list(psegp);
 317                         add_to_free_pseg_list(psegp);
 318                         psegp = pnextp;
 319                 }
 320                 if(pseg_count_per_context[ctx])
 321                         panic("pseg_count_per_context inconsistant after "
 322                               "invalidate.");
 323         }
 324 }
 325 
 326 /* This page must be a page in user vma... again all IRQ's gotta be off. */
 327 static inline void sun4c_unload_page_from_tlb(unsigned long addr,
     /* [previous][next][first][last][top][bottom][index][help] */
 328                                               struct task_struct *tsk)
 329 {
 330         unsigned char save_ctx;
 331 
 332         if(tsk->tss.context != -1) {
 333                 save_ctx = get_context();
 334                 flush_user_windows();
 335                 set_context(tsk->tss.context);
 336                 sun4c_flush_page(addr);
 337                 put_pte(addr, 0);
 338                 set_context(save_ctx);
 339         }
 340 }
 341 
 342 /* NOTE: When we have finer grained invalidate()'s (RSN) this
 343  *       whole scheme will be much more efficient and need to
 344  *       be re-written.  Also note that this routine only
 345  *       unloads user page translations, this may need to
 346  *       be changed at some point.
 347  */
 348 void sun4c_invalidate(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 349 {
 350         int orig_ctx, cur_ctx, flags;
 351 
 352         save_flags(flags); cli();
 353         flush_user_windows();
 354         orig_ctx = get_context();
 355         for(cur_ctx = 0; cur_ctx < num_contexts; cur_ctx++) {
 356                 set_context(cur_ctx);
 357                 sun4c_unload_context_from_tlb(cur_ctx);
 358         }
 359         set_context(orig_ctx);
 360         restore_flags(flags);
 361 }
 362 
 363 /* We're only updating software tables on the sun4c. */
 364 void sun4c_set_pte(pte_t *ptep, pte_t pteval)
     /* [previous][next][first][last][top][bottom][index][help] */
 365 {
 366         *ptep = pteval;
 367 }
 368 
 369 /* Now back to the mid-level interface code:
 370  *
 371  * Allocate and free page tables. The xxx_kernel() versions are
 372  * used to allocate a kernel page table - this turns on ASN bits
 373  * if any, and marks the page tables reserved.
 374  */
 375 void sun4c_pte_free_kernel(pte_t *pte)
     /* [previous][next][first][last][top][bottom][index][help] */
 376 {
 377         mem_map[MAP_NR(pte)].reserved = 0;
 378         free_page((unsigned long) pte);
 379 }
 380 
 381 pte_t *sun4c_pte_alloc_kernel(pmd_t *pmd, unsigned long address)
     /* [previous][next][first][last][top][bottom][index][help] */
 382 {
 383         address = (address >> PAGE_SHIFT) & (SUN4C_PTRS_PER_PTE - 1);
 384         if (sun4c_pmd_none(*pmd)) {
 385                 pte_t *page = (pte_t *) get_free_page(GFP_KERNEL);
 386                 if (sun4c_pmd_none(*pmd)) {
 387                         if (page) {
 388                                 pmd_val(*pmd) = PGD_TABLE | (unsigned long) page;
 389                                 mem_map[MAP_NR(page)].reserved = 1;
 390                                 return page + address;
 391                         }
 392                         pmd_val(*pmd) = PGD_TABLE | (unsigned long) BAD_PAGETABLE;
 393                         return NULL;
 394                 }
 395                 free_page((unsigned long) page);
 396         }
 397         if (sun4c_pmd_bad(*pmd)) {
 398                 printk("Bad pmd in pte_alloc_kernel: %08lx\n", pmd_val(*pmd));
 399                 pmd_val(*pmd) = PGD_TABLE | (unsigned long) BAD_PAGETABLE;
 400                 return NULL;
 401         }
 402         return (pte_t *) sun4c_pmd_page(*pmd) + address;
 403 }
 404 
 405 /*
 406  * allocating and freeing a pmd is trivial: the 1-entry pmd is
 407  * inside the pgd, so has no extra memory associated with it.
 408  */
 409 void sun4c_pmd_free_kernel(pmd_t *pmd)
     /* [previous][next][first][last][top][bottom][index][help] */
 410 {
 411         pmd_val(*pmd) = 0;
 412 }
 413 
 414 pmd_t *sun4c_pmd_alloc_kernel(pgd_t *pgd, unsigned long address)
     /* [previous][next][first][last][top][bottom][index][help] */
 415 {
 416         return (pmd_t *) pgd;
 417 }
 418 
 419 void sun4c_pte_free(pte_t *pte)
     /* [previous][next][first][last][top][bottom][index][help] */
 420 {
 421         free_page((unsigned long) pte);
 422 }
 423 
 424 pte_t *sun4c_pte_alloc(pmd_t * pmd, unsigned long address)
     /* [previous][next][first][last][top][bottom][index][help] */
 425 {
 426         address = (address >> PAGE_SHIFT) & (SUN4C_PTRS_PER_PTE - 1);
 427         if (sun4c_pmd_none(*pmd)) {
 428                 pte_t *page = (pte_t *) get_free_page(GFP_KERNEL);
 429                 if (sun4c_pmd_none(*pmd)) {
 430                         if (page) {
 431                                 pmd_val(*pmd) = PGD_TABLE | (unsigned long) page;
 432                                 return page + address;
 433                         }
 434                         pmd_val(*pmd) = PGD_TABLE | (unsigned long) BAD_PAGETABLE;
 435                         return NULL;
 436                 }
 437                 free_page((unsigned long) page);
 438         }
 439         if (sun4c_pmd_bad(*pmd)) {
 440                 printk("Bad pmd in pte_alloc: %08lx\n", pmd_val(*pmd));
 441                 pmd_val(*pmd) = PGD_TABLE | (unsigned long) BAD_PAGETABLE;
 442                 return NULL;
 443         }
 444         return (pte_t *) sun4c_pmd_page(*pmd) + address;
 445 }
 446 
 447 /*
 448  * allocating and freeing a pmd is trivial: the 1-entry pmd is
 449  * inside the pgd, so has no extra memory associated with it.
 450  */
 451 void sun4c_pmd_free(pmd_t * pmd)
     /* [previous][next][first][last][top][bottom][index][help] */
 452 {
 453         pmd_val(*pmd) = 0;
 454 }
 455 
 456 pmd_t *sun4c_pmd_alloc(pgd_t * pgd, unsigned long address)
     /* [previous][next][first][last][top][bottom][index][help] */
 457 {
 458         return (pmd_t *) pgd;
 459 }
 460 
 461 void sun4c_pgd_free(pgd_t *pgd)
     /* [previous][next][first][last][top][bottom][index][help] */
 462 {
 463         free_page((unsigned long) pgd);
 464 }
 465 
 466 pgd_t *sun4c_pgd_alloc(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 467 {
 468         unsigned long new_pgd = get_free_page(GFP_KERNEL);
 469         return (pgd_t *) new_pgd;
 470 }
 471 
 472 /* Jumping to and fro different contexts, the modifying of the pseg lists
 473  * must be atomic during the switch, or else...
 474  */
 475 void sun4c_switch_to_context(void *new_task)
     /* [previous][next][first][last][top][bottom][index][help] */
 476 {
 477         struct task_struct *tsk = (struct task_struct *) new_task;
 478         struct task_struct *old_tsk;
 479         struct ctx_list *ctxp;
 480         unsigned long flags;
 481         int ctx = tsk->tss.context;
 482 
 483         /* Swapper can execute in any context, or this task
 484          * has already been allocated a piece of the mmu real-
 485          * estate.
 486          */
 487         if(tsk->pid == 0 || ctx != -1)
 488                 return;
 489         ctxp = ctx_free.next;
 490         if(ctxp != &ctx_free) {
 491                 save_flags(flags); cli();
 492                 ctx = ctxp->ctx_number;
 493                 remove_from_ctx_list(ctxp);
 494                 add_to_used_ctxlist(ctxp);
 495                 tsk->tss.context = ctx;
 496                 ctxp->ctx_task = tsk;
 497                 restore_flags(flags);
 498                 return;
 499         }
 500         save_flags(flags); cli();
 501         ctxp = ctx_used.prev;
 502         /* Don't steal from current, thank you. */
 503         if(ctxp->ctx_task == current)
 504                 ctxp = ctxp->prev;
 505         if(ctxp == &ctx_used)
 506                 panic("out of contexts");
 507         remove_from_ctx_list(ctxp);
 508         old_tsk = ctxp->ctx_task;
 509         old_tsk->tss.context = -1;
 510         ctxp->ctx_task = tsk;
 511         tsk->tss.context = ctxp->ctx_number;
 512         add_to_used_ctxlist(ctxp);
 513         /* User windows flushed already by switch_to(p) macro. */
 514         set_context(ctxp->ctx_number);
 515         sun4c_unload_context_from_tlb(ctxp->ctx_number);
 516         restore_flags(flags);
 517 }
 518 
 519 /* Low level IO area allocation on the Sun4c MMU.  This function is called
 520  * for each page of IO area you need.  Kernel code should not call this
 521  * routine directly, use sparc_alloc_io() instead.
 522  */
 523 void sun4c_mapioaddr(unsigned long physaddr, unsigned long virt_addr,
     /* [previous][next][first][last][top][bottom][index][help] */
 524                      int bus_type, int rdonly)
 525 {
 526         unsigned long page_entry;
 527 
 528         page_entry = ((physaddr >> PAGE_SHIFT) & 0xffff);
 529         page_entry |= (_SUN4C_PAGE_VALID | _SUN4C_PAGE_WRITE |
 530                        _SUN4C_PAGE_NOCACHE | _SUN4C_PAGE_IO);
 531         if(rdonly)
 532                 page_entry &= (~_SUN4C_PAGE_WRITE);
 533         sun4c_flush_page(virt_addr);
 534         put_pte(virt_addr, page_entry);
 535 }
 536 
 537 /* These routines are used to lock down and unlock data transfer
 538  * areas in the sun4c tlb.  If the pages need to be uncached the
 539  * caller must do that himself.
 540  */
 541 inline char *sun4c_lockarea(char *vaddr, unsigned long size)
     /* [previous][next][first][last][top][bottom][index][help] */
 542 {
 543         unsigned long flags;
 544         unsigned long orig_addr = (unsigned long) vaddr;
 545         unsigned long first_seg = (orig_addr & SUN4C_REAL_PGDIR_MASK);
 546         unsigned long last_seg = ((orig_addr + size) & SUN4C_REAL_PGDIR_MASK);
 547 
 548         save_flags(flags); cli();
 549         for(; first_seg <= last_seg; first_seg += SUN4C_REAL_PGDIR_SIZE)
 550                 sun4c_lock_tlb_entry(first_seg);
 551 
 552         restore_flags(flags);
 553         return vaddr;
 554 }
 555 
 556 /* Note that when calling unlockarea you pass as 'vaddr' the address that
 557  * was returned to you by lockarea for this pool above.
 558  */
 559 inline void sun4c_unlockarea(char *vaddr, unsigned long size)
     /* [previous][next][first][last][top][bottom][index][help] */
 560 {
 561         unsigned long flags;
 562         unsigned long orig_addr = (unsigned long) vaddr;
 563         unsigned long first_seg = (orig_addr & SUN4C_REAL_PGDIR_MASK);
 564         unsigned long last_seg = ((orig_addr + size) & SUN4C_REAL_PGDIR_MASK);
 565 
 566         save_flags(flags); cli();
 567         for(; first_seg <= last_seg; first_seg += SUN4C_REAL_PGDIR_SIZE)
 568                 sun4c_unlock_tlb_entry(first_seg);
 569 
 570         restore_flags(flags);
 571 }
 572 
 573 /* Getting and Releasing scsi dvma buffers. */
 574 char *sun4c_get_scsi_buffer(char *bufptr, unsigned long len)
     /* [previous][next][first][last][top][bottom][index][help] */
 575 {
 576         unsigned long first_page = ((unsigned long) bufptr) & PAGE_MASK;
 577         unsigned long last_page = (((unsigned long) bufptr) + len) & PAGE_MASK;
 578 
 579         /* First lock down the area. */
 580         bufptr = sun4c_lockarea(bufptr, len);
 581 
 582         /* Uncache and flush all the pages. */
 583         for(; first_page <= last_page; first_page += PAGE_SIZE) {
 584                 sun4c_flush_page(first_page);
 585                 put_pte(first_page, get_pte(first_page) | PTE_NC);
 586         }
 587         return bufptr;
 588 }
 589 
 590 void sun4c_release_scsi_buffer(char *bufptr, unsigned long len)
     /* [previous][next][first][last][top][bottom][index][help] */
 591 {
 592         unsigned long first_page = ((unsigned long) bufptr) & PAGE_MASK;
 593         unsigned long last_page = (((unsigned long) bufptr) + len) & PAGE_MASK;
 594 
 595 
 596         /* Recache all the pages. */
 597         for(; first_page <= last_page; first_page += PAGE_SIZE)
 598                 put_pte(first_page, get_pte(first_page) & ~PTE_NC);
 599 
 600         sun4c_unlockarea(bufptr, len);
 601 }
 602 
 603 /* Code to fill the sun4c tlb during a fault.  Plus fault helper routine. */
 604 int sun4c_get_fault_info(unsigned long *address, unsigned long *error_code,
     /* [previous][next][first][last][top][bottom][index][help] */
 605                          unsigned long from_user)
 606 {
 607         unsigned long faddr, fstatus, new_code;
 608 
 609         faddr = sun4c_get_synchronous_address();
 610         *address = faddr;
 611         if(faddr >= 0x20000000 && faddr < 0xe0000000) {
 612                 printk("SUN4C: Fault in vm hole at %08lx\n", faddr);
 613                 *error_code = from_user;
 614                 return 1;
 615         }
 616         fstatus = sun4c_get_synchronous_error();
 617         if(fstatus & SUN4C_SYNC_BOLIXED)
 618                 panic("SUN4C: Unrecoverable fault type.");
 619         new_code = 0;
 620         if(fstatus & SUN4C_SYNC_PROT)
 621                 new_code |= FAULT_CODE_PROT;
 622         if(fstatus & SUN4C_SYNC_BADWRITE)
 623                 new_code |= FAULT_CODE_WRITE;
 624         *error_code = (new_code | from_user);
 625         return 0;
 626 }
 627 
 628 static inline void sun4c_alloc_pseg(unsigned long address)
     /* [previous][next][first][last][top][bottom][index][help] */
 629 {
 630         struct pseg_list *psegp;
 631         unsigned char cur_ctx = get_context();
 632         int kernel_address = (address >= KERNBASE);
 633         int user_address = !kernel_address;
 634 
 635         psegp = s4cpseg_free.next;
 636         if(psegp != &s4cpseg_free) {
 637                 remove_pseg_list(psegp);
 638                 add_to_used_pseg_list(psegp);
 639                 if(user_address)
 640                         add_pseg_ctxlist(psegp, cur_ctx);
 641                 psegp->vaddr = address;
 642                 psegp->context = cur_ctx;
 643                 /* No cache flush needed */
 644                 if(kernel_address)
 645                         sun4c_distribute_kernel_mapping(address, psegp->pseg);
 646                 else
 647                         put_segmap(address, psegp->pseg);
 648                 return;
 649         }
 650         psegp = s4cpseg_used.prev; /* Take last used list entry. */
 651         if(psegp == &s4cpseg_used)
 652                 panic("Sun4c psegs have disappeared...");
 653         if(psegp->vaddr >= KERNBASE) {
 654                 sun4c_delete_kernel_mapping(psegp->vaddr);
 655         } else {
 656                 flush_user_windows();
 657                 set_context(psegp->context);
 658                 sun4c_flush_segment(psegp->vaddr);
 659                 put_segmap(psegp->vaddr, invalid_segment);
 660                 set_context(cur_ctx);
 661         }
 662         remove_pseg_list(psegp);
 663         if(psegp->vaddr < KERNBASE)
 664                 remove_pseg_ctxlist(psegp, psegp->context);
 665         psegp->vaddr = address;
 666         psegp->context = cur_ctx;
 667         if(kernel_address)
 668                 sun4c_distribute_kernel_mapping(address, psegp->pseg);
 669         else
 670                 put_segmap(address, psegp->pseg);
 671         add_to_used_pseg_list(psegp);
 672         if(user_address)
 673                 add_pseg_ctxlist(psegp, cur_ctx);
 674 }
 675 
 676 /*
 677  * handle_mm_fault() gets here so that we can update our 'view'
 678  * of a new address translation.  A lot of the time, mappings
 679  * don't change and we are just 'working the tlb cache'.
 680  */
 681 void sun4c_update_mmu_cache(struct vm_area_struct * vma,
     /* [previous][next][first][last][top][bottom][index][help] */
 682                             unsigned long address, pte_t pte)
 683 {
 684         unsigned long flags, segmap, segaddr, clean;
 685 
 686         save_flags(flags); cli();
 687         address &= PAGE_MASK;
 688         segaddr = address & SUN4C_REAL_PGDIR_MASK;
 689         segmap = get_segmap(segaddr);
 690         if(segmap == invalid_segment) {
 691                 sun4c_alloc_pseg(segaddr);
 692                 /* XXX make segmap freeing routines do this. XXX */
 693                 for(clean = segaddr; clean < (segaddr + SUN4C_REAL_PGDIR_SIZE);
 694                     clean += PAGE_SIZE)
 695                         put_pte(clean, 0);
 696         }
 697 
 698         /* If this is a user fault, only load the one pte so that
 699          * the kernel's ref/mod bits accurately reflect what is
 700          * in the tlb.  handle_pte_fault() causes this to work.
 701          */
 702         if(address < TASK_SIZE)
 703                 put_pte(address, pte_val(pte));
 704         else {
 705                 /* We have a kernel fault here, load entire segment. */
 706                 pgd_t *pgdp;
 707                 pte_t *ptable;
 708                 int pnum = 64;
 709 
 710                 pgdp = sun4c_pgd_offset(&init_mm, segaddr);
 711                 ptable = sun4c_pte_offset((pmd_t *)pgdp, segaddr);
 712                 while(pnum--) {
 713                         put_pte(segaddr, pte_val(*ptable++));
 714                         segaddr += PAGE_SIZE;
 715                 };
 716         }
 717         restore_flags(flags);
 718 }
 719 
 720 /* Paging initialization on the Sun4c. */
 721 static inline void sun4c_free_all_nonlocked_psegs(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 722 {
 723         struct pseg_list *plp;
 724         int i;
 725 
 726         for(i=0; i < invalid_segment; i++)
 727                 if(!s4cpseg_pool[i].hardlock)
 728                         add_to_free_pseg_list(&s4cpseg_pool[i]);
 729         /* Now for every free pseg, make all the ptes invalid. */
 730         plp = s4cpseg_free.next;
 731         while(plp != &s4cpseg_free) {
 732                 put_segmap(0x0, plp->pseg);
 733                 for(i=0; i<64; i++)
 734                         put_pte((i * PAGE_SIZE), 0x0);
 735                 plp = plp->next;
 736         }
 737         put_segmap(0x0, invalid_segment);
 738 }
 739 
 740 static inline struct pseg_list *sun4c_alloc_pseg_from_free_list(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 741 {
 742         struct pseg_list *psegp;
 743 
 744         psegp = s4cpseg_free.next;
 745         if(psegp != &s4cpseg_free) {
 746                 remove_pseg_list(psegp);
 747                 return psegp;
 748         }
 749         return 0;
 750 }
 751 
 752 static inline void sun4c_init_lock_area(unsigned long start_addr,
     /* [previous][next][first][last][top][bottom][index][help] */
 753                                         unsigned long end_addr)
 754 {
 755         struct pseg_list *psegp;
 756         unsigned long a;
 757         int ctx;
 758 
 759         for(a = start_addr; a < end_addr; a += SUN4C_REAL_PGDIR_SIZE) {
 760                 psegp = sun4c_alloc_pseg_from_free_list();
 761                 if(!psegp) {
 762                         prom_printf("whoops...");
 763                         prom_halt();
 764                 }
 765                 for(ctx=0;ctx<num_contexts;ctx++)
 766                         prom_putsegment(ctx,a,psegp->pseg);
 767                 add_to_locked_pseg_list(psegp);
 768                 psegp->hardlock = 1;
 769         }
 770 }
 771 
 772 static inline void sun4c_check_for_ss2_cache_bug(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 773 {
 774         extern unsigned long start;
 775 
 776         /* Well we've now got a problem, on the SS2 a cache bug
 777          * causes line entries to get severely corrupted if the
 778          * trap table is able to be cached.  A sane and simple
 779          * workaround, at least for now, is to mark the trap
 780          * table page as uncacheable.
 781          *
 782          * XXX Investigate other possible workarounds and see
 783          * XXX if they help performance enough to warrant using
 784          * XXX them.                      -- 8/6/95 davem
 785          */
 786         if(idprom->id_machtype == (SM_SUN4C | SM_4C_SS2)) {
 787                 /* Whee.. */
 788                 printk("SS2 cache bug detected, uncaching trap table page\n");
 789                 sun4c_flush_page((unsigned int) &start);
 790                 put_pte(((unsigned long) &start),
 791                         (get_pte((unsigned long) &start) | PTE_NC));
 792         }
 793 }
 794 
 795 extern unsigned long free_area_init(unsigned long, unsigned long);
 796 
 797 /* Whee, this is now *ultra* clean and more managable */
 798 extern unsigned long end;
 799 extern void probe_mmu(void);
 800 
 801 unsigned long sun4c_paging_init(unsigned long start_mem, unsigned long end_mem)
     /* [previous][next][first][last][top][bottom][index][help] */
 802 {
 803         unsigned long addr, vaddr, kern_begin, kern_end;
 804         unsigned long prom_begin, prom_end, kadb_begin;
 805         pgd_t *pgdp;
 806         pte_t *pg_table;
 807         int phys_seg, i, ctx;
 808 
 809         start_mem = PAGE_ALIGN(start_mem);
 810 
 811         probe_mmu();
 812         invalid_segment = (num_segmaps - 1);
 813         sun4c_init_pseg_lists();
 814         for(kern_begin = KERNBASE;
 815             kern_begin < (unsigned long) &end;
 816             kern_begin += SUN4C_REAL_PGDIR_SIZE) {
 817                 unsigned char pseg = get_segmap(kern_begin);
 818 
 819                 s4cpseg_pool[pseg].hardlock=1;
 820                 for(ctx=0; ctx<num_contexts;ctx++)
 821                         prom_putsegment(ctx,kern_begin,pseg);
 822         }
 823         for(kern_begin = SUN4C_REAL_PGDIR_ALIGN((unsigned long) &end);
 824             kern_begin < KADB_DEBUGGER_BEGVM;
 825             kern_begin += SUN4C_REAL_PGDIR_SIZE)
 826                 for(ctx=0; ctx<num_contexts;ctx++)
 827                         prom_putsegment(ctx, kern_begin, invalid_segment);
 828         for(prom_begin = KADB_DEBUGGER_BEGVM;
 829             prom_begin < LINUX_OPPROM_ENDVM;
 830             prom_begin += SUN4C_REAL_PGDIR_SIZE) {
 831                 unsigned long pseg = get_segmap(prom_begin);
 832 
 833                 if(pseg != invalid_segment) {
 834                         s4cpseg_pool[pseg].hardlock=1;
 835                         for(ctx=0; ctx<num_contexts; ctx++)
 836                                 prom_putsegment(ctx,prom_begin,pseg);
 837                 }
 838         }
 839         /* Clean the MMU of excess garbage... */
 840         for(ctx=0; ctx<num_contexts;ctx++) {
 841                 set_context(ctx);
 842                 for(vaddr = 0; vaddr < 0x20000000;
 843                     vaddr += SUN4C_REAL_PGDIR_SIZE)
 844                         put_segmap(vaddr,invalid_segment);
 845                 for(vaddr = 0xe0000000; vaddr < KERNBASE;
 846                     vaddr += SUN4C_REAL_PGDIR_SIZE)
 847                         put_segmap(vaddr,invalid_segment);
 848                 for(vaddr = LINUX_OPPROM_ENDVM; vaddr != 0;
 849                     vaddr += SUN4C_REAL_PGDIR_SIZE)
 850                         put_segmap(vaddr,invalid_segment);
 851         }
 852         set_context(0);
 853         sun4c_free_all_nonlocked_psegs();
 854         /* Lock I/O and DVMA areas for the system. */
 855         sun4c_init_lock_area(IOBASE_VADDR, IOBASE_END);
 856         sun4c_init_lock_area(DVMA_VADDR, DVMA_END);
 857         /* Zero out swapper_pg_dir and pg0 */
 858         memset(swapper_pg_dir, 0, PAGE_SIZE);
 859         memset(pg0, 0, PAGE_SIZE);
 860         /* This makes us Solaris boot-loader 'safe' */
 861         pgd_val(swapper_pg_dir[KERNBASE>>SUN4C_PGDIR_SHIFT]) =
 862                 PGD_TABLE | (unsigned long) pg0;
 863 
 864         /* Initialize swapper_pg_dir to map the kernel
 865          * addresses in high memory.  Note that as soon as we get past
 866          * the 4MB lower mapping and start using dynamic memory from
 867          * start_mem we can start faulting and this is ok since our
 868          * pseg free list and the lower 4MB of the kernel is mapped
 869          * properly in the software page tables.
 870          */
 871         pgdp = swapper_pg_dir;
 872         kern_end = PAGE_ALIGN(end_mem);
 873         kern_begin = KERNBASE;
 874         while(kern_begin < kern_end) {
 875                 unsigned long pte, tmp;
 876 
 877                 /* We only need _one_ mapping, the high address one. */
 878                 pg_table = (pte_t *) (PAGE_MASK & pgd_val(pgdp[KERNBASE>>SUN4C_PGDIR_SHIFT]));
 879                 if(!pg_table) {
 880                         pg_table = (pte_t *) start_mem;
 881                         start_mem += PAGE_SIZE;
 882                 }
 883                 pgd_val(pgdp[KERNBASE>>SUN4C_PGDIR_SHIFT]) =
 884                         PGD_TABLE | (unsigned long) pg_table;
 885                 pgdp++;
 886                 for(tmp = 0; tmp < SUN4C_PTRS_PER_PTE; tmp++, pg_table++) {
 887                         if(kern_begin < kern_end)
 888                                 sun4c_set_pte(pg_table,
 889                                               mk_pte(kern_begin,
 890                                                      SUN4C_PAGE_SHARED));
 891                         else
 892                                 sun4c_pte_clear(pg_table);
 893                         pte = get_pte(kern_begin);
 894                         if(pte & _SUN4C_PAGE_VALID) {
 895                                 pte &= ~(_SUN4C_PAGE_NOCACHE);
 896                                 pte |= (_SUN4C_PAGE_PRIV | _SUN4C_PAGE_WRITE |
 897                                         _SUN4C_PAGE_REF | _SUN4C_PAGE_DIRTY);
 898                                 put_pte(kern_begin, pte);
 899                         }
 900                         kern_begin += PAGE_SIZE;
 901                 }
 902         }
 903         sun4c_check_for_ss2_cache_bug();
 904         /* Fix kadb/prom permissions. */
 905         kadb_begin = KADB_DEBUGGER_BEGVM;
 906         prom_end = LINUX_OPPROM_ENDVM;
 907         for(; kadb_begin < prom_end; kadb_begin += PAGE_SIZE) {
 908                 unsigned long pte = get_pte(kadb_begin);
 909                 if(pte & _SUN4C_PAGE_VALID)
 910                         put_pte(kadb_begin, (pte | _SUN4C_PAGE_PRIV));
 911         }
 912         /* Allocate the DVMA pages */
 913         addr = DVMA_VADDR;
 914         start_mem = PAGE_ALIGN(start_mem);
 915         while(addr < DVMA_END) {
 916                 unsigned long dvmapte = start_mem - PAGE_OFFSET;
 917 
 918                 start_mem += PAGE_SIZE;
 919                 dvmapte = ((dvmapte>>PAGE_SHIFT) & 0xffff);
 920                 dvmapte |= (_SUN4C_PAGE_VALID |
 921                             _SUN4C_PAGE_WRITE |
 922                             _SUN4C_PAGE_NOCACHE);
 923                 put_pte(addr, dvmapte);
 924                 addr += PAGE_SIZE;
 925         }
 926         /* Tell the user our allocations */
 927         for(phys_seg=0, i=0; i<=invalid_segment; i++)
 928                 if(s4cpseg_pool[i].hardlock)
 929                         phys_seg++;
 930         printk("SUN4C: Hard locked %d boot-up psegs\n", phys_seg);
 931         /* Init the context pool and lists */
 932         ctx_list_pool = (struct ctx_list *) start_mem;
 933         start_mem += (num_contexts * sizeof(struct ctx_list));
 934         for(ctx = 0; ctx < num_contexts; ctx++) {
 935                 struct ctx_list *clist;
 936 
 937                 clist = (ctx_list_pool + ctx);
 938                 clist->ctx_number = ctx;
 939                 clist->ctx_task = 0;
 940         }
 941         ctx_free.next = ctx_free.prev = &ctx_free;
 942         ctx_used.next = ctx_used.prev = &ctx_used;
 943         for(ctx = 0; ctx < num_contexts; ctx++)
 944                 add_to_free_ctxlist(ctx_list_pool + ctx);
 945         start_mem = PAGE_ALIGN(start_mem);
 946         start_mem = free_area_init(start_mem, end_mem);
 947         start_mem = PAGE_ALIGN(start_mem);
 948         return start_mem;
 949 }
 950 
 951 /* Test the WP bit on the sun4c. */
 952 void sun4c_test_wp(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 953 {
 954         wp_works_ok = -1;
 955 
 956         /* Let it rip... */
 957         put_pte((unsigned long) 0x0, (PTE_V | PTE_P));
 958         __asm__ __volatile__("st %%g0, [0x0]\n\t": : :"memory");
 959         put_pte((unsigned long) 0x0, 0x0);
 960         if (wp_works_ok < 0)
 961                 wp_works_ok = 0;
 962 }
 963 
 964 void sun4c_lock_entire_kernel(unsigned long start_mem)
     /* [previous][next][first][last][top][bottom][index][help] */
 965 {
 966         unsigned long addr = (unsigned long) &end;
 967 
 968         addr = (addr & SUN4C_REAL_PGDIR_MASK);
 969         start_mem = SUN4C_REAL_PGDIR_ALIGN(start_mem);
 970         while(addr < start_mem) {
 971                 int pseg;
 972 
 973                 sun4c_lock_tlb_entry(addr);
 974                 pseg = get_segmap(addr);
 975                 if(!s4cpseg_pool[pseg].hardlock) {
 976                         s4cpseg_pool[pseg].hardlock = 1;
 977                         remove_pseg_list(&s4cpseg_pool[pseg]);
 978                 }
 979                 addr += SUN4C_REAL_PGDIR_SIZE;
 980         }
 981 }
 982 
 983 static void sun4c_fork_hook(void *vtask, unsigned long kthread_usp)
     /* [previous][next][first][last][top][bottom][index][help] */
 984 {
 985         struct task_struct *new_task = vtask;
 986 
 987         /* These pages must not cause a fault when traps
 988          * are off (such as in a window spill/fill) so
 989          * lock them down for the life of the task.
 990          */
 991         sun4c_lock_tlb_entry((unsigned long) new_task);
 992         sun4c_lock_tlb_entry(new_task->kernel_stack_page);
 993         if(kthread_usp)
 994                 sun4c_lock_tlb_entry(kthread_usp);
 995 }
 996 
 997 static void sun4c_release_hook(void *vtask)
     /* [previous][next][first][last][top][bottom][index][help] */
 998 {
 999         struct task_struct *old_task = vtask;
1000         struct ctx_list *ctx_old;
1001         struct pt_regs *regs;
1002         unsigned char this_ctx = get_context();
1003         unsigned long flags;
1004 
1005         save_flags(flags); cli();
1006         if(old_task == &init_task)
1007                 panic("AIEEE releasing swapper");
1008         if(old_task->tss.context != -1) {
1009 
1010                 /* Clear from the mmu, all notions of this dead task. */
1011                 flush_user_windows();
1012                 set_context(old_task->tss.context);
1013                 sun4c_unload_context_from_tlb(old_task->tss.context);
1014                 set_context(this_ctx);
1015 
1016                 ctx_old = ctx_list_pool + old_task->tss.context;
1017                 remove_from_ctx_list(ctx_old);
1018                 add_to_free_ctxlist(ctx_old);
1019                 old_task->tss.context = -1;
1020         }
1021         regs = (struct pt_regs *) 
1022                 (((old_task->tss.ksp & ~0xfff)) + (0x1000 - TRACEREG_SZ));
1023         if(regs->u_regs[UREG_FP] > KERNBASE)
1024                 sun4c_unlock_tlb_entry(regs->u_regs[UREG_FP] & PAGE_MASK);
1025         sun4c_unlock_tlb_entry(old_task->kernel_stack_page);
1026         sun4c_unlock_tlb_entry((unsigned long) old_task);
1027         restore_flags(flags);
1028         /* bye bye... */
1029 }
1030 
1031 static void sun4c_flush_hook(void *vtask)
     /* [previous][next][first][last][top][bottom][index][help] */
1032 {
1033         struct task_struct *dead_task = vtask;
1034 
1035         if(dead_task->tss.context != -1)
1036                 sun4c_flush_context();
1037 }
1038 
1039 static void sun4c_task_cacheflush(void *vtask)
     /* [previous][next][first][last][top][bottom][index][help] */
1040 {
1041         struct task_struct *flush_task = vtask;
1042 
1043         if(flush_task->tss.context != -1)
1044                 sun4c_flush_context();
1045 }
1046 
1047 static void sun4c_exit_hook(void *vtask)
     /* [previous][next][first][last][top][bottom][index][help] */
1048 {
1049 }
1050 
1051 /* Load up routines and constants for sun4c mmu */
1052 void ld_mmu_sun4c(void)
     /* [previous][next][first][last][top][bottom][index][help] */
1053 {
1054         printk("Loading sun4c MMU routines\n");
1055 
1056         /* First the constants */
1057         pmd_shift = SUN4C_PMD_SHIFT;
1058         pmd_size = SUN4C_PMD_SIZE;
1059         pmd_mask = SUN4C_PMD_MASK;
1060         pgdir_shift = SUN4C_PGDIR_SHIFT;
1061         pgdir_size = SUN4C_PGDIR_SIZE;
1062         pgdir_mask = SUN4C_PGDIR_MASK;
1063 
1064         ptrs_per_pte = SUN4C_PTRS_PER_PTE;
1065         ptrs_per_pmd = SUN4C_PTRS_PER_PMD;
1066         ptrs_per_pgd = SUN4C_PTRS_PER_PGD;
1067 
1068         page_none = SUN4C_PAGE_NONE;
1069         page_shared = SUN4C_PAGE_SHARED;
1070         page_copy = SUN4C_PAGE_COPY;
1071         page_readonly = SUN4C_PAGE_READONLY;
1072         page_kernel = SUN4C_PAGE_KERNEL;
1073         page_invalid = SUN4C_PAGE_INVALID;
1074         
1075         /* Functions */
1076         invalidate = sun4c_invalidate;
1077         set_pte = sun4c_set_pte;
1078         switch_to_context = sun4c_switch_to_context;
1079         pmd_align = sun4c_pmd_align;
1080         pgdir_align = sun4c_pgdir_align;
1081         vmalloc_start = sun4c_vmalloc_start;
1082 
1083         pte_page = sun4c_pte_page;
1084         pmd_page = sun4c_pmd_page;
1085 
1086         sparc_update_rootmmu_dir = sun4c_update_rootmmu_dir;
1087 
1088         pte_none = sun4c_pte_none;
1089         pte_present = sun4c_pte_present;
1090         pte_inuse = sun4c_pte_inuse;
1091         pte_clear = sun4c_pte_clear;
1092         pte_reuse = sun4c_pte_reuse;
1093 
1094         pmd_none = sun4c_pmd_none;
1095         pmd_bad = sun4c_pmd_bad;
1096         pmd_present = sun4c_pmd_present;
1097         pmd_inuse = sun4c_pmd_inuse;
1098         pmd_clear = sun4c_pmd_clear;
1099         pmd_reuse = sun4c_pmd_reuse;
1100 
1101         pgd_none = sun4c_pgd_none;
1102         pgd_bad = sun4c_pgd_bad;
1103         pgd_present = sun4c_pgd_present;
1104         pgd_inuse = sun4c_pgd_inuse;
1105         pgd_clear = sun4c_pgd_clear;
1106 
1107         mk_pte = sun4c_mk_pte;
1108         pte_modify = sun4c_pte_modify;
1109         pgd_offset = sun4c_pgd_offset;
1110         pmd_offset = sun4c_pmd_offset;
1111         pte_offset = sun4c_pte_offset;
1112         pte_free_kernel = sun4c_pte_free_kernel;
1113         pmd_free_kernel = sun4c_pmd_free_kernel;
1114         pte_alloc_kernel = sun4c_pte_alloc_kernel;
1115         pmd_alloc_kernel = sun4c_pmd_alloc_kernel;
1116         pte_free = sun4c_pte_free;
1117         pte_alloc = sun4c_pte_alloc;
1118         pmd_free = sun4c_pmd_free;
1119         pmd_alloc = sun4c_pmd_alloc;
1120         pgd_free = sun4c_pgd_free;
1121         pgd_alloc = sun4c_pgd_alloc;
1122 
1123         pte_read = sun4c_pte_read;
1124         pte_write = sun4c_pte_write;
1125         pte_exec = sun4c_pte_exec;
1126         pte_dirty = sun4c_pte_dirty;
1127         pte_young = sun4c_pte_young;
1128         pte_cow = sun4c_pte_cow;
1129         pte_wrprotect = sun4c_pte_wrprotect;
1130         pte_rdprotect = sun4c_pte_rdprotect;
1131         pte_exprotect = sun4c_pte_exprotect;
1132         pte_mkclean = sun4c_pte_mkclean;
1133         pte_mkold = sun4c_pte_mkold;
1134         pte_uncow = sun4c_pte_uncow;
1135         pte_mkwrite = sun4c_pte_mkwrite;
1136         pte_mkread = sun4c_pte_mkread;
1137         pte_mkexec = sun4c_pte_mkexec;
1138         pte_mkdirty = sun4c_pte_mkdirty;
1139         pte_mkyoung = sun4c_pte_mkyoung;
1140         pte_mkcow = sun4c_pte_mkcow;
1141         get_fault_info = sun4c_get_fault_info;
1142         update_mmu_cache = sun4c_update_mmu_cache;
1143         mmu_exit_hook = sun4c_exit_hook;
1144         mmu_fork_hook = sun4c_fork_hook;
1145         mmu_release_hook = sun4c_release_hook;
1146         mmu_flush_hook = sun4c_flush_hook;
1147         mmu_task_cacheflush = sun4c_task_cacheflush;
1148         mmu_lockarea = sun4c_lockarea;
1149         mmu_unlockarea = sun4c_unlockarea;
1150         mmu_get_scsi_buffer = sun4c_get_scsi_buffer;
1151         mmu_release_scsi_buffer = sun4c_release_scsi_buffer;
1152 
1153         /* These should _never_ get called with two level tables. */
1154         pgd_set = 0;
1155         pgd_reuse = 0;
1156         pgd_page = 0;
1157 }

/* [previous][next][first][last][top][bottom][index][help] */