aboutsummaryrefslogtreecommitdiffstats
path: root/arch/sparc64/mm
diff options
context:
space:
mode:
authorDavid S. Miller <davem@sunset.davemloft.net>2006-02-17 21:01:02 -0500
committerDavid S. Miller <davem@sunset.davemloft.net>2006-03-20 04:13:34 -0500
commit8b234274418d6d79527c4ac3a72da446ca4cb35f (patch)
treeab4ab14fa7f1cab7889ecc2339f0261253a5d0e1 /arch/sparc64/mm
parent7adb37fe80d06cbd40de9b225b12a3a9ec40b6bb (diff)
[SPARC64]: More TLB/TSB handling fixes.
The SUN4V convention with non-shared TSBs is that the context bit of the TAG is clear. So we have to choose an "invalid" bit and initialize new TSBs appropriately. Otherwise a zero TAG looks "valid". Make sure, for the window fixup cases, that we use the right global registers and that we don't potentially trample on the live global registers in etrap/rtrap handling (%g2 and %g6) and that we put the missing virtual address properly in %g5. Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'arch/sparc64/mm')
-rw-r--r--arch/sparc64/mm/init.c4
-rw-r--r--arch/sparc64/mm/tsb.c25
2 files changed, 15 insertions, 14 deletions
diff --git a/arch/sparc64/mm/init.c b/arch/sparc64/mm/init.c
index bd9e3205674b..aa2aec6373c3 100644
--- a/arch/sparc64/mm/init.c
+++ b/arch/sparc64/mm/init.c
@@ -296,7 +296,7 @@ void update_mmu_cache(struct vm_area_struct *vma, unsigned long address, pte_t p
296 296
297 tsb = &mm->context.tsb[(address >> PAGE_SHIFT) & 297 tsb = &mm->context.tsb[(address >> PAGE_SHIFT) &
298 (mm->context.tsb_nentries - 1UL)]; 298 (mm->context.tsb_nentries - 1UL)];
299 tag = (address >> 22UL) | CTX_HWBITS(mm->context) << 48UL; 299 tag = (address >> 22UL);
300 tsb_insert(tsb, tag, pte_val(pte)); 300 tsb_insert(tsb, tag, pte_val(pte));
301 } 301 }
302} 302}
@@ -1110,6 +1110,8 @@ void __init paging_init(void)
1110 kern_base = (prom_boot_mapping_phys_low >> 22UL) << 22UL; 1110 kern_base = (prom_boot_mapping_phys_low >> 22UL) << 22UL;
1111 kern_size = (unsigned long)&_end - (unsigned long)KERNBASE; 1111 kern_size = (unsigned long)&_end - (unsigned long)KERNBASE;
1112 1112
1113 memset(swapper_tsb, 0x40, sizeof(swapper_tsb));
1114
1113 if (tlb_type == hypervisor) 1115 if (tlb_type == hypervisor)
1114 sun4v_pgprot_init(); 1116 sun4v_pgprot_init();
1115 else 1117 else
diff --git a/arch/sparc64/mm/tsb.c b/arch/sparc64/mm/tsb.c
index 3c1ff05038b1..353cb060561b 100644
--- a/arch/sparc64/mm/tsb.c
+++ b/arch/sparc64/mm/tsb.c
@@ -20,9 +20,9 @@ static inline unsigned long tsb_hash(unsigned long vaddr, unsigned long nentries
20 return vaddr & (nentries - 1); 20 return vaddr & (nentries - 1);
21} 21}
22 22
23static inline int tag_compare(unsigned long tag, unsigned long vaddr, unsigned long context) 23static inline int tag_compare(unsigned long tag, unsigned long vaddr)
24{ 24{
25 return (tag == ((vaddr >> 22) | (context << 48))); 25 return (tag == (vaddr >> 22));
26} 26}
27 27
28/* TSB flushes need only occur on the processor initiating the address 28/* TSB flushes need only occur on the processor initiating the address
@@ -38,8 +38,8 @@ void flush_tsb_kernel_range(unsigned long start, unsigned long end)
38 unsigned long hash = tsb_hash(v, KERNEL_TSB_NENTRIES); 38 unsigned long hash = tsb_hash(v, KERNEL_TSB_NENTRIES);
39 struct tsb *ent = &swapper_tsb[hash]; 39 struct tsb *ent = &swapper_tsb[hash];
40 40
41 if (tag_compare(ent->tag, v, 0)) { 41 if (tag_compare(ent->tag, v)) {
42 ent->tag = 0UL; 42 ent->tag = (1UL << TSB_TAG_INVALID_BIT);
43 membar_storeload_storestore(); 43 membar_storeload_storestore();
44 } 44 }
45 } 45 }
@@ -50,14 +50,9 @@ void flush_tsb_user(struct mmu_gather *mp)
50 struct mm_struct *mm = mp->mm; 50 struct mm_struct *mm = mp->mm;
51 struct tsb *tsb = mm->context.tsb; 51 struct tsb *tsb = mm->context.tsb;
52 unsigned long nentries = mm->context.tsb_nentries; 52 unsigned long nentries = mm->context.tsb_nentries;
53 unsigned long ctx, base; 53 unsigned long base;
54 int i; 54 int i;
55 55
56 if (unlikely(!CTX_VALID(mm->context)))
57 return;
58
59 ctx = CTX_HWBITS(mm->context);
60
61 if (tlb_type == cheetah_plus || tlb_type == hypervisor) 56 if (tlb_type == cheetah_plus || tlb_type == hypervisor)
62 base = __pa(tsb); 57 base = __pa(tsb);
63 else 58 else
@@ -71,7 +66,7 @@ void flush_tsb_user(struct mmu_gather *mp)
71 66
72 hash = tsb_hash(v, nentries); 67 hash = tsb_hash(v, nentries);
73 ent = base + (hash * sizeof(struct tsb)); 68 ent = base + (hash * sizeof(struct tsb));
74 tag = (v >> 22UL) | (ctx << 48UL); 69 tag = (v >> 22UL);
75 70
76 tsb_flush(ent, tag); 71 tsb_flush(ent, tag);
77 } 72 }
@@ -243,7 +238,8 @@ static void copy_tsb(struct tsb *old_tsb, unsigned long old_size,
243 "i" (ASI_NUCLEUS_QUAD_LDD)); 238 "i" (ASI_NUCLEUS_QUAD_LDD));
244 } 239 }
245 240
246 if (!tag || (tag & (1UL << TSB_TAG_LOCK_BIT))) 241 if (tag & ((1UL << TSB_TAG_LOCK_BIT) |
242 (1UL << TSB_TAG_INVALID_BIT)))
247 continue; 243 continue;
248 244
249 /* We only put base page size PTEs into the TSB, 245 /* We only put base page size PTEs into the TSB,
@@ -315,10 +311,13 @@ void tsb_grow(struct mm_struct *mm, unsigned long rss, gfp_t gfp_flags)
315 break; 311 break;
316 } 312 }
317 313
318 page = alloc_pages(gfp_flags | __GFP_ZERO, get_order(size)); 314 page = alloc_pages(gfp_flags, get_order(size));
319 if (unlikely(!page)) 315 if (unlikely(!page))
320 return; 316 return;
321 317
318 /* Mark all tags as invalid. */
319 memset(page_address(page), 0x40, size);
320
322 if (size == max_tsb_size) 321 if (size == max_tsb_size)
323 mm->context.tsb_rss_limit = ~0UL; 322 mm->context.tsb_rss_limit = ~0UL;
324 else 323 else