Commit fa09aa0a authored by Anton Blanchard's avatar Anton Blanchard

ppc64: update ppc64 tlb batch code

parent 4bc583b4
...@@ -46,6 +46,7 @@ ...@@ -46,6 +46,7 @@
#include <asm/abs_addr.h> #include <asm/abs_addr.h>
#include <asm/tlbflush.h> #include <asm/tlbflush.h>
#include <asm/eeh.h> #include <asm/eeh.h>
#include <asm/tlb.h>
/* /*
* Note: pte --> Linux PTE * Note: pte --> Linux PTE
...@@ -415,12 +416,11 @@ void flush_hash_range(unsigned long context, unsigned long number, int local) ...@@ -415,12 +416,11 @@ void flush_hash_range(unsigned long context, unsigned long number, int local)
ppc_md.flush_hash_range(context, number, local); ppc_md.flush_hash_range(context, number, local);
} else { } else {
int i; int i;
struct tlb_batch_data *ptes = struct ppc64_tlb_batch *batch =
&tlb_batch_array[smp_processor_id()][0]; &ppc64_tlb_batch[smp_processor_id()];
for (i = 0; i < number; i++) { for (i = 0; i < number; i++)
flush_hash_page(context, ptes->addr, ptes->pte, local); flush_hash_page(context, batch->addr[i], batch->pte[i],
ptes++; local);
}
} }
} }
...@@ -20,6 +20,7 @@ ...@@ -20,6 +20,7 @@
#include <asm/mmu_context.h> #include <asm/mmu_context.h>
#include <asm/pgtable.h> #include <asm/pgtable.h>
#include <asm/tlbflush.h> #include <asm/tlbflush.h>
#include <asm/tlb.h>
/* /*
* Create a pte. Used during initialization only. * Create a pte. Used during initialization only.
...@@ -372,31 +373,32 @@ static void pSeries_flush_hash_range(unsigned long context, ...@@ -372,31 +373,32 @@ static void pSeries_flush_hash_range(unsigned long context,
{ {
unsigned long vsid, vpn, va, hash, secondary, slot, flags, avpn; unsigned long vsid, vpn, va, hash, secondary, slot, flags, avpn;
int i, j; int i, j;
unsigned long va_array[MAX_BATCH_FLUSH];
HPTE *hptep; HPTE *hptep;
Hpte_dword0 dw0; Hpte_dword0 dw0;
struct tlb_batch_data *ptes = &tlb_batch_array[smp_processor_id()][0]; struct ppc64_tlb_batch *batch = &ppc64_tlb_batch[smp_processor_id()];
/* XXX fix for large ptes */ /* XXX fix for large ptes */
unsigned long large = 0; unsigned long large = 0;
j = 0; j = 0;
for (i = 0; i < number; i++) { for (i = 0; i < number; i++) {
if ((ptes->addr >= USER_START) && (ptes->addr <= USER_END)) if ((batch->addr[i] >= USER_START) &&
vsid = get_vsid(context, ptes->addr); (batch->addr[i] <= USER_END))
vsid = get_vsid(context, batch->addr[i]);
else else
vsid = get_kernel_vsid(ptes->addr); vsid = get_kernel_vsid(batch->addr[i]);
va = (vsid << 28) | (ptes->addr & 0x0fffffff); va = (vsid << 28) | (batch->addr[i] & 0x0fffffff);
va_array[j] = va; batch->vaddr[j] = va;
if (large) if (large)
vpn = va >> LARGE_PAGE_SHIFT; vpn = va >> LARGE_PAGE_SHIFT;
else else
vpn = va >> PAGE_SHIFT; vpn = va >> PAGE_SHIFT;
hash = hpt_hash(vpn, large); hash = hpt_hash(vpn, large);
secondary = (pte_val(ptes->pte) & _PAGE_SECONDARY) >> 15; secondary = (pte_val(batch->pte[i]) & _PAGE_SECONDARY) >> 15;
if (secondary) if (secondary)
hash = ~hash; hash = ~hash;
slot = (hash & htab_data.htab_hash_mask) * HPTES_PER_GROUP; slot = (hash & htab_data.htab_hash_mask) * HPTES_PER_GROUP;
slot += (pte_val(ptes->pte) & _PAGE_GROUP_IX) >> 12; slot += (pte_val(batch->pte[i]) & _PAGE_GROUP_IX) >> 12;
hptep = htab_data.htab + slot; hptep = htab_data.htab + slot;
avpn = vpn >> 11; avpn = vpn >> 11;
...@@ -405,8 +407,6 @@ static void pSeries_flush_hash_range(unsigned long context, ...@@ -405,8 +407,6 @@ static void pSeries_flush_hash_range(unsigned long context,
dw0 = hptep->dw0.dw0; dw0 = hptep->dw0.dw0;
ptes++;
if ((dw0.avpn != avpn) || !dw0.v) { if ((dw0.avpn != avpn) || !dw0.v) {
pSeries_unlock_hpte(hptep); pSeries_unlock_hpte(hptep);
udbg_printf("invalidate missed\n"); udbg_printf("invalidate missed\n");
...@@ -426,7 +426,7 @@ static void pSeries_flush_hash_range(unsigned long context, ...@@ -426,7 +426,7 @@ static void pSeries_flush_hash_range(unsigned long context,
asm volatile("\n\ asm volatile("\n\
clrldi %0,%0,16\n\ clrldi %0,%0,16\n\
tlbiel %0" tlbiel %0"
: : "r" (va_array[i]) : "memory" ); : : "r" (batch->vaddr[i]) : "memory" );
} }
asm volatile("ptesync":::"memory"); asm volatile("ptesync":::"memory");
...@@ -440,7 +440,7 @@ static void pSeries_flush_hash_range(unsigned long context, ...@@ -440,7 +440,7 @@ static void pSeries_flush_hash_range(unsigned long context,
asm volatile("\n\ asm volatile("\n\
clrldi %0,%0,16\n\ clrldi %0,%0,16\n\
tlbie %0" tlbie %0"
: : "r" (va_array[i]) : "memory" ); : : "r" (batch->vaddr[i]) : "memory" );
} }
asm volatile("eieio; tlbsync; ptesync":::"memory"); asm volatile("eieio; tlbsync; ptesync":::"memory");
......
...@@ -33,6 +33,7 @@ ...@@ -33,6 +33,7 @@
#include <linux/pci.h> #include <linux/pci.h>
#include <asm/naca.h> #include <asm/naca.h>
#include <asm/tlbflush.h> #include <asm/tlbflush.h>
#include <asm/tlb.h>
/* Status return values */ /* Status return values */
#define H_Success 0 #define H_Success 0
...@@ -775,15 +776,14 @@ void pSeries_lpar_flush_hash_range(unsigned long context, unsigned long number, ...@@ -775,15 +776,14 @@ void pSeries_lpar_flush_hash_range(unsigned long context, unsigned long number,
int local) int local)
{ {
int i; int i;
struct tlb_batch_data *ptes =
&tlb_batch_array[smp_processor_id()][0];
unsigned long flags; unsigned long flags;
struct ppc64_tlb_batch *batch = &ppc64_tlb_batch[smp_processor_id()];
spin_lock_irqsave(&pSeries_lpar_tlbie_lock, flags); spin_lock_irqsave(&pSeries_lpar_tlbie_lock, flags);
for (i = 0; i < number; i++) {
flush_hash_page(context, ptes->addr, ptes->pte, local); for (i = 0; i < number; i++)
ptes++; flush_hash_page(context, batch->addr[i], batch->pte[i], local);
}
spin_unlock_irqrestore(&pSeries_lpar_tlbie_lock, flags); spin_unlock_irqrestore(&pSeries_lpar_tlbie_lock, flags);
} }
......
...@@ -295,7 +295,7 @@ flush_tlb_page(struct vm_area_struct *vma, unsigned long vmaddr) ...@@ -295,7 +295,7 @@ flush_tlb_page(struct vm_area_struct *vma, unsigned long vmaddr)
} }
} }
struct tlb_batch_data tlb_batch_array[NR_CPUS][MAX_BATCH_FLUSH]; struct ppc64_tlb_batch ppc64_tlb_batch[NR_CPUS];
void void
__flush_tlb_range(struct mm_struct *mm, unsigned long start, unsigned long end) __flush_tlb_range(struct mm_struct *mm, unsigned long start, unsigned long end)
...@@ -305,81 +305,69 @@ __flush_tlb_range(struct mm_struct *mm, unsigned long start, unsigned long end) ...@@ -305,81 +305,69 @@ __flush_tlb_range(struct mm_struct *mm, unsigned long start, unsigned long end)
pte_t *ptep; pte_t *ptep;
pte_t pte; pte_t pte;
unsigned long pgd_end, pmd_end; unsigned long pgd_end, pmd_end;
unsigned long context; unsigned long context = 0;
int i = 0; struct ppc64_tlb_batch *batch = &ppc64_tlb_batch[smp_processor_id()];
struct tlb_batch_data *ptes = &tlb_batch_array[smp_processor_id()][0]; unsigned long i = 0;
int local = 0; int local = 0;
if ( start >= end ) switch(REGION_ID(start)) {
panic("flush_tlb_range: start (%016lx) greater than end (%016lx)\n", start, end );
if ( REGION_ID(start) != REGION_ID(end) )
panic("flush_tlb_range: start (%016lx) and end (%016lx) not in same region\n", start, end );
context = 0;
switch( REGION_ID(start) ) {
case VMALLOC_REGION_ID: case VMALLOC_REGION_ID:
pgd = pgd_offset_k( start ); pgd = pgd_offset_k(start);
break; break;
case IO_REGION_ID: case IO_REGION_ID:
pgd = pgd_offset_i( start ); pgd = pgd_offset_i(start);
break; break;
case USER_REGION_ID: case USER_REGION_ID:
pgd = pgd_offset( mm, start ); pgd = pgd_offset(mm, start);
context = mm->context; context = mm->context;
/* XXX are there races with checking cpu_vm_mask? - Anton */ /* XXX are there races with checking cpu_vm_mask? - Anton */
if (mm->cpu_vm_mask == (1 << smp_processor_id())) { if (mm->cpu_vm_mask == (1 << smp_processor_id()))
local = 1; local = 1;
}
break; break;
default: default:
panic("flush_tlb_range: invalid region for start (%016lx) and end (%016lx)\n", start, end); panic("flush_tlb_range: invalid region for start (%016lx) and end (%016lx)\n", start, end);
} }
do { do {
pgd_end = (start + PGDIR_SIZE) & PGDIR_MASK; pgd_end = (start + PGDIR_SIZE) & PGDIR_MASK;
if ( pgd_end > end ) if (pgd_end > end)
pgd_end = end; pgd_end = end;
if ( !pgd_none( *pgd ) ) { if (!pgd_none(*pgd)) {
pmd = pmd_offset( pgd, start ); pmd = pmd_offset(pgd, start);
do { do {
pmd_end = ( start + PMD_SIZE ) & PMD_MASK; pmd_end = (start + PMD_SIZE) & PMD_MASK;
if ( pmd_end > end ) if (pmd_end > end)
pmd_end = end; pmd_end = end;
if ( !pmd_none( *pmd ) ) { if (!pmd_none(*pmd)) {
ptep = pte_offset_kernel( pmd, start ); ptep = pte_offset_kernel(pmd, start);
do { do {
if ( pte_val(*ptep) & _PAGE_HASHPTE ) { if (pte_val(*ptep) & _PAGE_HASHPTE) {
pte = __pte(pte_update(ptep, _PAGE_HPTEFLAGS, 0)); pte = __pte(pte_update(ptep, _PAGE_HPTEFLAGS, 0));
if ( pte_val(pte) & _PAGE_HASHPTE ) { if (pte_val(pte) & _PAGE_HASHPTE) {
ptes->pte = pte; batch->pte[i] = pte;
ptes->addr = start; batch->addr[i] = start;
ptes++;
i++; i++;
if (i == MAX_BATCH_FLUSH) { if (i == PPC64_TLB_BATCH_NR) {
flush_hash_range(context, MAX_BATCH_FLUSH, local); flush_hash_range(context, i, local);
i = 0; i = 0;
ptes = &tlb_batch_array[smp_processor_id()][0];
} }
} }
} }
start += PAGE_SIZE; start += PAGE_SIZE;
++ptep; ++ptep;
} while ( start < pmd_end ); } while (start < pmd_end);
} } else {
else
start = pmd_end; start = pmd_end;
}
++pmd; ++pmd;
} while ( start < pgd_end ); } while (start < pgd_end);
} } else {
else
start = pgd_end; start = pgd_end;
}
++pgd; ++pgd;
} while ( start < end ); } while (start < end);
if (i) if (i)
flush_hash_range(context, i, local); flush_hash_range(context, i, local);
......
/*
* TLB shootdown specifics for PPC64
*
* Copyright (C) 2002 Anton Blanchard, IBM Corp.
* Copyright (C) 2002 Paul Mackerras, IBM Corp.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
*/
#ifndef _PPC64_TLB_H
#define _PPC64_TLB_H
#include <asm/pgtable.h>
#include <asm/tlbflush.h>
#include <asm/page.h>
#include <asm/mmu.h>
struct free_pte_ctx;
static inline void tlb_flush(struct free_pte_ctx *tlb);
/* Get the generic bits... */
#include <asm-generic/tlb.h> #include <asm-generic/tlb.h>
/* Nothing needed here in fact... */
#define tlb_start_vma(tlb, vma) do { } while (0)
#define tlb_end_vma(tlb, vma) do { } while (0)
/* Should make this at least as large as the generic batch size, but it
* takes up too much space */
#define PPC64_TLB_BATCH_NR 192
struct ppc64_tlb_batch {
unsigned long index;
pte_t pte[PPC64_TLB_BATCH_NR];
unsigned long addr[PPC64_TLB_BATCH_NR];
unsigned long vaddr[PPC64_TLB_BATCH_NR];
};
extern struct ppc64_tlb_batch ppc64_tlb_batch[NR_CPUS];
static inline void tlb_remove_tlb_entry(mmu_gather_t *tlb, pte_t *ptep,
unsigned long address)
{
int cpu = smp_processor_id();
struct ppc64_tlb_batch *batch = &ppc64_tlb_batch[cpu];
unsigned long i = batch->index;
pte_t pte;
if (pte_val(*ptep) & _PAGE_HASHPTE) {
pte = __pte(pte_update(ptep, _PAGE_HPTEFLAGS, 0));
if (pte_val(pte) & _PAGE_HASHPTE) {
int local = 0;
if (tlb->mm->cpu_vm_mask == (1 << cpu))
local = 1;
batch->pte[i] = pte;
batch->addr[i] = address;
i++;
if (i == PPC64_TLB_BATCH_NR) {
flush_hash_range(tlb->mm->context, i, local);
i = 0;
}
}
}
batch->index = i;
}
static inline void tlb_flush(struct free_pte_ctx *tlb)
{
int cpu = smp_processor_id();
struct ppc64_tlb_batch *batch = &ppc64_tlb_batch[cpu];
int local = 0;
if (tlb->mm->cpu_vm_mask == (1 << smp_processor_id()))
local = 1;
flush_hash_range(tlb->mm->context, batch->index, local);
batch->index = 0;
}
#endif /* _PPC64_TLB_H */
...@@ -35,12 +35,4 @@ extern void flush_hash_page(unsigned long context, unsigned long ea, pte_t pte, ...@@ -35,12 +35,4 @@ extern void flush_hash_page(unsigned long context, unsigned long ea, pte_t pte,
int local); int local);
void flush_hash_range(unsigned long context, unsigned long number, int local); void flush_hash_range(unsigned long context, unsigned long number, int local);
/* TLB flush batching */
#define MAX_BATCH_FLUSH 128
struct tlb_batch_data {
pte_t pte;
unsigned long addr;
};
extern struct tlb_batch_data tlb_batch_array[NR_CPUS][MAX_BATCH_FLUSH];
#endif /* _PPC64_TLBFLUSH_H */ #endif /* _PPC64_TLBFLUSH_H */
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