root/arch/sparc/mm/sun4c.c

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

DEFINITIONS

This source file includes following definitions.
  1. sun4c_v2p
  2. sun4c_p2v
  3. sun4c_flush_all
  4. sun4c_flush_context
  5. sun4c_flush_segment
  6. sun4c_flush_page
  7. sun4c_complete_all_stores
  8. sun4c_init_clean_segmap
  9. sun4c_init_clean_mmu
  10. sun4c_probe_vac
  11. sun4c_probe_mmu
  12. sun4c_init_ss2_cache_bug
  13. sun4c_init_alloc_dvma_pages
  14. sun4c_init_mmu_entry_pool
  15. fix_permissions
  16. sun4c_init_map_kernelprom
  17. sun4c_init_lock_area
  18. sun4c_init_rings
  19. add_ring
  20. remove_ring
  21. recycle_ring
  22. free_user_entry
  23. assign_user_entry
  24. free_kernel_entry
  25. assign_kernel_entry
  26. reassign_kernel_entry
  27. sun4c_init_fill_kernel_ring
  28. sun4c_init_fill_user_ring
  29. sun4c_kernel_unmap
  30. sun4c_kernel_map
  31. sun4c_user_unmap
  32. sun4c_user_map
  33. sun4c_demap_context
  34. sun4c_demap_one
  35. sun4c_user_strategy
  36. sun4c_kernel_strategy
  37. alloc_user_segment
  38. alloc_kernel_segment
  39. sun4c_update_mmu_cache
  40. sun4c_quick_kernel_fault
  41. get_task_segment
  42. free_task_segment
  43. garbage_collect
  44. sun4c_alloc_task_struct
  45. sun4c_alloc_kernel_stack
  46. sun4c_free_kernel_stack
  47. sun4c_free_task_struct
  48. sun4c_init_buckets
  49. sun4c_lockarea
  50. sun4c_unlockarea
  51. sun4c_get_scsi_one
  52. sun4c_get_scsi_sgl
  53. sun4c_release_scsi_one
  54. sun4c_release_scsi_sgl
  55. sun4c_init_lock_areas
  56. sun4c_flush_cache_all
  57. sun4c_flush_cache_mm
  58. sun4c_flush_cache_range
  59. sun4c_flush_cache_page
  60. sun4c_flush_page_to_ram
  61. sun4c_flush_tlb_all
  62. sun4c_flush_tlb_mm
  63. sun4c_flush_tlb_range
  64. sun4c_flush_tlb_page
  65. sun4c_set_pte
  66. sun4c_mapioaddr
  67. sun4c_alloc_context
  68. sun4c_switch_heuristic
  69. sun4c_switch_to_context
  70. sun4c_flush_hook
  71. sun4c_exit_hook
  72. sun4c_mmu_info
  73. sun4c_pmd_align
  74. sun4c_pgdir_align
  75. sun4c_vmalloc_start
  76. sun4c_pte_none
  77. sun4c_pte_present
  78. sun4c_pte_clear
  79. sun4c_pmd_none
  80. sun4c_pmd_bad
  81. sun4c_pmd_present
  82. sun4c_pmd_clear
  83. sun4c_pgd_none
  84. sun4c_pgd_bad
  85. sun4c_pgd_present
  86. sun4c_pgd_clear
  87. sun4c_pte_write
  88. sun4c_pte_dirty
  89. sun4c_pte_young
  90. sun4c_pte_wrprotect
  91. sun4c_pte_mkclean
  92. sun4c_pte_mkold
  93. sun4c_pte_mkwrite
  94. sun4c_pte_mkdirty
  95. sun4c_pte_mkyoung
  96. sun4c_mk_pte
  97. sun4c_mk_pte_io
  98. sun4c_pte_modify
  99. sun4c_pte_page
  100. sun4c_pmd_page
  101. sun4c_pgd_offset
  102. sun4c_pmd_offset
  103. sun4c_pte_offset
  104. sun4c_update_rootmmu_dir
  105. sun4c_pte_free_kernel
  106. sun4c_pte_alloc_kernel
  107. sun4c_pmd_free_kernel
  108. sun4c_pmd_alloc_kernel
  109. sun4c_pte_free
  110. sun4c_pte_alloc
  111. sun4c_pmd_free
  112. sun4c_pmd_alloc
  113. sun4c_pgd_free
  114. sun4c_pgd_alloc
  115. sun4c_paging_init
  116. ld_mmu_sun4c

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

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