Commit c7ad40cc authored by Paul Mackerras's avatar Paul Mackerras

Add flush_tlb_kernel_range for PPC and clean up the PPC tlb

flushing code a little.
parent 22e962f9
...@@ -41,35 +41,86 @@ ...@@ -41,35 +41,86 @@
* - flush_tlb_mm(mm) flushes the specified mm context TLB's * - flush_tlb_mm(mm) flushes the specified mm context TLB's
* - flush_tlb_page(vma, vmaddr) flushes one page * - flush_tlb_page(vma, vmaddr) flushes one page
* - flush_tlb_range(vma, start, end) flushes a range of pages * - flush_tlb_range(vma, start, end) flushes a range of pages
* - flush_tlb_kernel_range(start, end) flushes kernel pages
* *
* since the hardware hash table functions as an extension of the * since the hardware hash table functions as an extension of the
* tlb as far as the linux tables are concerned, flush it too. * tlb as far as the linux tables are concerned, flush it too.
* -- Cort * -- Cort
*/ */
/*
* 750 SMP is a Bad Idea because the 750 doesn't broadcast all
* the cache operations on the bus. Hence we need to use an IPI
* to get the other CPU(s) to invalidate their TLBs.
*/
#ifdef CONFIG_SMP_750
#define FINISH_FLUSH smp_send_tlb_invalidate(0)
#else
#define FINISH_FLUSH do { } while (0)
#endif
static void flush_range(struct mm_struct *mm, unsigned long start,
unsigned long end)
{
pmd_t *pmd;
unsigned long pmd_end;
int count;
unsigned int ctx = mm->context;
if (Hash == 0) {
_tlbia();
return;
}
start &= PAGE_MASK;
if (start >= end)
return;
end = (end - 1) | ~PAGE_MASK;
pmd = pmd_offset(pgd_offset(mm, start), start);
for (;;) {
pmd_end = ((start + PGDIR_SIZE) & PGDIR_MASK) - 1;
if (pmd_end > end)
pmd_end = end;
if (!pmd_none(*pmd)) {
count = ((pmd_end - start) >> PAGE_SHIFT) + 1;
flush_hash_pages(ctx, start, pmd_val(*pmd), count);
}
if (pmd_end == end)
break;
start = pmd_end + 1;
++pmd;
}
}
/* /*
* Flush all tlb/hash table entries (except perhaps for those * Flush all tlb/hash table entries (except perhaps for those
* mapping RAM starting at PAGE_OFFSET, since they never change). * mapping RAM starting at PAGE_OFFSET, since they never change).
*/ */
void void
local_flush_tlb_all(void) flush_tlb_all(void)
{ {
struct vm_area_struct vma;
/* aargh!!! */
/* /*
* Just flush the kernel part of the address space, that's * Just flush the kernel part of the address space, that's
* all that the current callers of this require. * all that the current callers of this require.
* Eventually I hope to persuade the powers that be that * Eventually I hope to persuade the powers that be that
* we can and should dispense with flush_tlb_all(). * we can and should dispense with flush_tlb_all().
* -- paulus. * -- paulus.
*
* In fact this should never get called now that we
* have flush_tlb_kernel_range. -- paulus
*/ */
vma.vm_mm = &init_mm; printk(KERN_ERR "flush_tlb_all called from %p\n",
local_flush_tlb_range(&vma, TASK_SIZE, ~0UL); __builtin_return_address(0));
flush_range(&init_mm, TASK_SIZE, ~0UL);
FINISH_FLUSH;
}
#ifdef CONFIG_SMP /*
smp_send_tlb_invalidate(0); * Flush kernel TLB entries in the given range
#endif /* CONFIG_SMP */ */
void flush_tlb_kernel_range(unsigned long start, unsigned long end)
{
flush_range(&init_mm, start, end);
FINISH_FLUSH;
} }
/* /*
...@@ -77,8 +128,7 @@ local_flush_tlb_all(void) ...@@ -77,8 +128,7 @@ local_flush_tlb_all(void)
* by mm. We can't rely on mm->mmap describing all the entries * by mm. We can't rely on mm->mmap describing all the entries
* that might be in the hash table. * that might be in the hash table.
*/ */
void void flush_tlb_mm(struct mm_struct *mm)
local_flush_tlb_mm(struct mm_struct *mm)
{ {
if (Hash == 0) { if (Hash == 0) {
_tlbia(); _tlbia();
...@@ -88,20 +138,14 @@ local_flush_tlb_mm(struct mm_struct *mm) ...@@ -88,20 +138,14 @@ local_flush_tlb_mm(struct mm_struct *mm)
if (mm->map_count) { if (mm->map_count) {
struct vm_area_struct *mp; struct vm_area_struct *mp;
for (mp = mm->mmap; mp != NULL; mp = mp->vm_next) for (mp = mm->mmap; mp != NULL; mp = mp->vm_next)
local_flush_tlb_range(mp, mp->vm_start, mp->vm_end); flush_range(mp->vm_mm, mp->vm_start, mp->vm_end);
} else { } else {
struct vm_area_struct vma; flush_range(mm, 0, TASK_SIZE);
vma.vm_mm = mm;
local_flush_tlb_range(&vma, 0, TASK_SIZE);
} }
FINISH_FLUSH;
#ifdef CONFIG_SMP
smp_send_tlb_invalidate(0);
#endif
} }
void void flush_tlb_page(struct vm_area_struct *vma, unsigned long vmaddr)
local_flush_tlb_page(struct vm_area_struct *vma, unsigned long vmaddr)
{ {
struct mm_struct *mm; struct mm_struct *mm;
pmd_t *pmd; pmd_t *pmd;
...@@ -114,9 +158,7 @@ local_flush_tlb_page(struct vm_area_struct *vma, unsigned long vmaddr) ...@@ -114,9 +158,7 @@ local_flush_tlb_page(struct vm_area_struct *vma, unsigned long vmaddr)
pmd = pmd_offset(pgd_offset(mm, vmaddr), vmaddr); pmd = pmd_offset(pgd_offset(mm, vmaddr), vmaddr);
if (!pmd_none(*pmd)) if (!pmd_none(*pmd))
flush_hash_pages(mm->context, vmaddr, pmd_val(*pmd), 1); flush_hash_pages(mm->context, vmaddr, pmd_val(*pmd), 1);
#ifdef CONFIG_SMP FINISH_FLUSH;
smp_send_tlb_invalidate(0);
#endif
} }
...@@ -125,39 +167,9 @@ local_flush_tlb_page(struct vm_area_struct *vma, unsigned long vmaddr) ...@@ -125,39 +167,9 @@ local_flush_tlb_page(struct vm_area_struct *vma, unsigned long vmaddr)
* and check _PAGE_HASHPTE bit; if it is set, find and destroy * and check _PAGE_HASHPTE bit; if it is set, find and destroy
* the corresponding HPTE. * the corresponding HPTE.
*/ */
void void flush_tlb_range(struct vm_area_struct *vma, unsigned long start,
local_flush_tlb_range(struct vm_area_struct *vma, unsigned long start, unsigned long end) unsigned long end)
{ {
struct mm_struct *mm = vma->vm_mm; flush_range(vma->vm_mm, start, end);
pmd_t *pmd; FINISH_FLUSH;
unsigned long pmd_end;
int count;
unsigned int ctx = mm->context;
if (Hash == 0) {
_tlbia();
return;
}
start &= PAGE_MASK;
if (start >= end)
return;
end = (end - 1) | ~PAGE_MASK;
pmd = pmd_offset(pgd_offset(mm, start), start);
for (;;) {
pmd_end = ((start + PGDIR_SIZE) & PGDIR_MASK) - 1;
if (pmd_end > end)
pmd_end = end;
if (!pmd_none(*pmd)) {
count = ((pmd_end - start) >> PAGE_SHIFT) + 1;
flush_hash_pages(ctx, start, pmd_val(*pmd), count);
}
if (pmd_end == end)
break;
start = pmd_end + 1;
++pmd;
}
#ifdef CONFIG_SMP
smp_send_tlb_invalidate(0);
#endif
} }
...@@ -23,41 +23,48 @@ extern void _tlbia(void); ...@@ -23,41 +23,48 @@ extern void _tlbia(void);
#if defined(CONFIG_4xx) #if defined(CONFIG_4xx)
#define __tlbia() asm volatile ("tlbia; sync" : : : "memory") #define __tlbia() asm volatile ("tlbia; sync" : : : "memory")
static inline void local_flush_tlb_all(void) static inline void flush_tlb_all(void)
{ __tlbia(); } { __tlbia(); }
static inline void local_flush_tlb_mm(struct mm_struct *mm) static inline void flush_tlb_mm(struct mm_struct *mm)
{ __tlbia(); } { __tlbia(); }
static inline void local_flush_tlb_page(struct vm_area_struct *vma, static inline void flush_tlb_page(struct vm_area_struct *vma,
unsigned long vmaddr) unsigned long vmaddr)
{ _tlbie(vmaddr); } { _tlbie(vmaddr); }
static inline void local_flush_tlb_range(struct mm_struct *mm, static inline void flush_tlb_range(struct mm_struct *mm,
unsigned long start, unsigned long end) unsigned long start, unsigned long end)
{ __tlbia(); } { __tlbia(); }
static inline void flush_tlb_kernel_range(unsigned long start,
unsigned long end)
{ __tlbia(); }
#define update_mmu_cache(vma, addr, pte) do { } while (0) #define update_mmu_cache(vma, addr, pte) do { } while (0)
#elif defined(CONFIG_8xx) #elif defined(CONFIG_8xx)
#define __tlbia() asm volatile ("tlbia; sync" : : : "memory") #define __tlbia() asm volatile ("tlbia; sync" : : : "memory")
static inline void local_flush_tlb_all(void) static inline void flush_tlb_all(void)
{ __tlbia(); } { __tlbia(); }
static inline void local_flush_tlb_mm(struct mm_struct *mm) static inline void flush_tlb_mm(struct mm_struct *mm)
{ __tlbia(); } { __tlbia(); }
static inline void local_flush_tlb_page(struct vm_area_struct *vma, static inline void flush_tlb_page(struct vm_area_struct *vma,
unsigned long vmaddr) unsigned long vmaddr)
{ _tlbie(vmaddr); } { _tlbie(vmaddr); }
static inline void local_flush_tlb_range(struct mm_struct *mm, static inline void flush_tlb_range(struct mm_struct *mm,
unsigned long start, unsigned long end) unsigned long start, unsigned long end)
{ __tlbia(); } { __tlbia(); }
static inline void flush_tlb_kernel_range(unsigned long start,
unsigned long end)
{ __tlbia(); }
#define update_mmu_cache(vma, addr, pte) do { } while (0) #define update_mmu_cache(vma, addr, pte) do { } while (0)
#else /* 6xx, 7xx, 7xxx cpus */ #else /* 6xx, 7xx, 7xxx cpus */
struct mm_struct; struct mm_struct;
struct vm_area_struct; struct vm_area_struct;
extern void local_flush_tlb_all(void); extern void flush_tlb_all(void);
extern void local_flush_tlb_mm(struct mm_struct *mm); extern void flush_tlb_mm(struct mm_struct *mm);
extern void local_flush_tlb_page(struct vm_area_struct *vma, unsigned long vmaddr); extern void flush_tlb_page(struct vm_area_struct *vma, unsigned long vmaddr);
extern void local_flush_tlb_range(struct vm_area_struct *vma, unsigned long start, extern void flush_tlb_range(struct vm_area_struct *vma, unsigned long start,
unsigned long end); unsigned long end);
extern void flush_tlb_kernel_range(unsigned long start, unsigned long end);
/* /*
* This gets called at the end of handling a page fault, when * This gets called at the end of handling a page fault, when
...@@ -69,11 +76,6 @@ extern void local_flush_tlb_range(struct vm_area_struct *vma, unsigned long star ...@@ -69,11 +76,6 @@ extern void local_flush_tlb_range(struct vm_area_struct *vma, unsigned long star
extern void update_mmu_cache(struct vm_area_struct *, unsigned long, pte_t); extern void update_mmu_cache(struct vm_area_struct *, unsigned long, pte_t);
#endif #endif
#define flush_tlb_all local_flush_tlb_all
#define flush_tlb_mm local_flush_tlb_mm
#define flush_tlb_page local_flush_tlb_page
#define flush_tlb_range local_flush_tlb_range
/* /*
* This is called in munmap when we have freed up some page-table * This is called in munmap when we have freed up some page-table
* pages. We don't need to do anything here, there's nothing special * pages. We don't need to do anything here, there's nothing special
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment