X-Git-Url: http://pilppa.org/gitweb/gitweb.cgi?a=blobdiff_plain;f=arch%2Fpowerpc%2Fmm%2Fhash_native_64.c;h=6ba9b47e55afbe746734761c672761dcea07e9f0;hb=605a494e4df0b2dabdebcdfee99536b0f6a22adc;hp=79aedaf36f2bd3cc91a893ce862bf8c00056a488;hpb=b643b0fdbc59cf6bbb086974b29d2571e9e9f646;p=linux-2.6-omap-h63xx.git diff --git a/arch/powerpc/mm/hash_native_64.c b/arch/powerpc/mm/hash_native_64.c index 79aedaf36f2..6ba9b47e55a 100644 --- a/arch/powerpc/mm/hash_native_64.c +++ b/arch/powerpc/mm/hash_native_64.c @@ -26,6 +26,7 @@ #include #include #include +#include #ifdef DEBUG_LOW #define DBG_LOW(fmt...) udbg_printf(fmt) @@ -103,7 +104,7 @@ static inline void tlbie(unsigned long va, int psize, int local) spin_unlock(&native_tlbie_lock); } -static inline void native_lock_hpte(hpte_t *hptep) +static inline void native_lock_hpte(struct hash_pte *hptep) { unsigned long *word = &hptep->v; @@ -115,7 +116,7 @@ static inline void native_lock_hpte(hpte_t *hptep) } } -static inline void native_unlock_hpte(hpte_t *hptep) +static inline void native_unlock_hpte(struct hash_pte *hptep) { unsigned long *word = &hptep->v; @@ -127,7 +128,7 @@ static long native_hpte_insert(unsigned long hpte_group, unsigned long va, unsigned long pa, unsigned long rflags, unsigned long vflags, int psize) { - hpte_t *hptep = htab_address + hpte_group; + struct hash_pte *hptep = htab_address + hpte_group; unsigned long hpte_v, hpte_r; int i; @@ -162,7 +163,7 @@ static long native_hpte_insert(unsigned long hpte_group, unsigned long va, hptep->r = hpte_r; /* Guarantee the second dword is visible before the valid bit */ - __asm__ __volatile__ ("eieio" : : : "memory"); + eieio(); /* * Now set the first dword including the valid bit * NOTE: this also unlocks the hpte @@ -176,7 +177,7 @@ static long native_hpte_insert(unsigned long hpte_group, unsigned long va, static long native_hpte_remove(unsigned long hpte_group) { - hpte_t *hptep; + struct hash_pte *hptep; int i; int slot_offset; unsigned long hpte_v; @@ -216,7 +217,7 @@ static long native_hpte_remove(unsigned long hpte_group) static long native_hpte_updatepp(unsigned long slot, unsigned long newpp, unsigned long va, int psize, int local) { - hpte_t *hptep = htab_address + slot; + struct hash_pte *hptep = htab_address + slot; unsigned long hpte_v, want_v; int ret = 0; @@ -232,15 +233,14 @@ static long native_hpte_updatepp(unsigned long slot, unsigned long newpp, /* Even if we miss, we need to invalidate the TLB */ if (!HPTE_V_COMPARE(hpte_v, want_v) || !(hpte_v & HPTE_V_VALID)) { DBG_LOW(" -> miss\n"); - native_unlock_hpte(hptep); ret = -1; } else { DBG_LOW(" -> hit\n"); /* Update the HPTE */ hptep->r = (hptep->r & ~(HPTE_R_PP | HPTE_R_N)) | (newpp & (HPTE_R_PP | HPTE_R_N | HPTE_R_C)); - native_unlock_hpte(hptep); } + native_unlock_hpte(hptep); /* Ensure it is out of the tlb too. */ tlbie(va, psize, local); @@ -250,7 +250,7 @@ static long native_hpte_updatepp(unsigned long slot, unsigned long newpp, static long native_hpte_find(unsigned long va, int psize) { - hpte_t *hptep; + struct hash_pte *hptep; unsigned long hash; unsigned long i, j; long slot; @@ -293,7 +293,7 @@ static void native_hpte_updateboltedpp(unsigned long newpp, unsigned long ea, { unsigned long vsid, va; long slot; - hpte_t *hptep; + struct hash_pte *hptep; vsid = get_kernel_vsid(ea); va = (vsid << 28) | (ea & 0x0fffffff); @@ -314,7 +314,7 @@ static void native_hpte_updateboltedpp(unsigned long newpp, unsigned long ea, static void native_hpte_invalidate(unsigned long slot, unsigned long va, int psize, int local) { - hpte_t *hptep = htab_address + slot; + struct hash_pte *hptep = htab_address + slot; unsigned long hpte_v; unsigned long want_v; unsigned long flags; @@ -340,31 +340,67 @@ static void native_hpte_invalidate(unsigned long slot, unsigned long va, local_irq_restore(flags); } -/* - * XXX This need fixing based on page size. It's only used by - * native_hpte_clear() for now which needs fixing too so they - * make a good pair... - */ -static unsigned long slot2va(unsigned long hpte_v, unsigned long slot) +#define LP_SHIFT 12 +#define LP_BITS 8 +#define LP_MASK(i) ((0xFF >> (i)) << LP_SHIFT) + +static void hpte_decode(struct hash_pte *hpte, unsigned long slot, + int *psize, unsigned long *va) { - unsigned long avpn = HPTE_V_AVPN_VAL(hpte_v); - unsigned long va; + unsigned long hpte_r = hpte->r; + unsigned long hpte_v = hpte->v; + unsigned long avpn; + int i, size, shift, penc; + + if (!(hpte_v & HPTE_V_LARGE)) + size = MMU_PAGE_4K; + else { + for (i = 0; i < LP_BITS; i++) { + if ((hpte_r & LP_MASK(i+1)) == LP_MASK(i+1)) + break; + } + penc = LP_MASK(i+1) >> LP_SHIFT; + for (size = 0; size < MMU_PAGE_COUNT; size++) { + + /* 4K pages are not represented by LP */ + if (size == MMU_PAGE_4K) + continue; + + /* valid entries have a shift value */ + if (!mmu_psize_defs[size].shift) + continue; + + if (penc == mmu_psize_defs[size].penc) + break; + } + } - va = avpn << 23; + /* This works for all page sizes, and for 256M and 1T segments */ + shift = mmu_psize_defs[size].shift; + avpn = (HPTE_V_AVPN_VAL(hpte_v) & ~mmu_psize_defs[size].avpnm) << 23; - if (! (hpte_v & HPTE_V_LARGE)) { - unsigned long vpi, pteg; + if (shift < 23) { + unsigned long vpi, vsid, pteg; pteg = slot / HPTES_PER_GROUP; if (hpte_v & HPTE_V_SECONDARY) pteg = ~pteg; - - vpi = ((va >> 28) ^ pteg) & htab_hash_mask; - - va |= vpi << PAGE_SHIFT; + switch (hpte_v >> HPTE_V_SSIZE_SHIFT) { + case MMU_SEGSIZE_256M: + vpi = ((avpn >> 28) ^ pteg) & htab_hash_mask; + break; + case MMU_SEGSIZE_1T: + vsid = avpn >> 40; + vpi = (vsid ^ (vsid << 25) ^ pteg) & htab_hash_mask; + break; + default: + avpn = vpi = size = 0; + } + avpn |= (vpi << mmu_psize_defs[size].shift); } - return va; + *va = avpn; + *psize = size; } /* @@ -374,15 +410,14 @@ static unsigned long slot2va(unsigned long hpte_v, unsigned long slot) * * TODO: add batching support when enabled. remember, no dynamic memory here, * athough there is the control page available... - * - * XXX FIXME: 4k only for now ! */ static void native_hpte_clear(void) { unsigned long slot, slots, flags; - hpte_t *hptep = htab_address; - unsigned long hpte_v; + struct hash_pte *hptep = htab_address; + unsigned long hpte_v, va; unsigned long pteg_count; + int psize; pteg_count = htab_hash_mask + 1; @@ -408,8 +443,9 @@ static void native_hpte_clear(void) * already hold the native_tlbie_lock. */ if (hpte_v & HPTE_V_VALID) { + hpte_decode(hptep, slot, &psize, &va); hptep->v = 0; - __tlbie(slot2va(hpte_v, slot), MMU_PAGE_4K); + __tlbie(va, psize); } } @@ -425,7 +461,7 @@ static void native_hpte_clear(void) static void native_flush_hash_range(unsigned long number, int local) { unsigned long va, hash, index, hidx, shift, slot; - hpte_t *hptep; + struct hash_pte *hptep; unsigned long hpte_v; unsigned long want_v; unsigned long flags;