Merge by hand from Linus' tree.
[safe/jmp/linux-2.6] / arch / ppc64 / mm / hash_native.c
index 144657e..174d145 100644 (file)
@@ -27,9 +27,9 @@
 
 static DEFINE_SPINLOCK(native_tlbie_lock);
 
-static inline void native_lock_hpte(HPTE *hptep)
+static inline void native_lock_hpte(hpte_t *hptep)
 {
-       unsigned long *word = &hptep->dw0.dword0;
+       unsigned long *word = &hptep->v;
 
        while (1) {
                if (!test_and_set_bit(HPTE_LOCK_BIT, word))
@@ -39,32 +39,27 @@ static inline void native_lock_hpte(HPTE *hptep)
        }
 }
 
-static inline void native_unlock_hpte(HPTE *hptep)
+static inline void native_unlock_hpte(hpte_t *hptep)
 {
-       unsigned long *word = &hptep->dw0.dword0;
+       unsigned long *word = &hptep->v;
 
        asm volatile("lwsync":::"memory");
        clear_bit(HPTE_LOCK_BIT, word);
 }
 
 long native_hpte_insert(unsigned long hpte_group, unsigned long va,
-                       unsigned long prpn, int secondary,
-                       unsigned long hpteflags, int bolted, int large)
+                       unsigned long prpn, unsigned long vflags,
+                       unsigned long rflags)
 {
-       unsigned long arpn = physRpn_to_absRpn(prpn);
-       HPTE *hptep = htab_address + hpte_group;
-       Hpte_dword0 dw0;
-       HPTE lhpte;
+       hpte_t *hptep = htab_address + hpte_group;
+       unsigned long hpte_v, hpte_r;
        int i;
 
        for (i = 0; i < HPTES_PER_GROUP; i++) {
-               dw0 = hptep->dw0.dw0;
-
-               if (!dw0.v) {
+               if (! (hptep->v & HPTE_V_VALID)) {
                        /* retry with lock held */
                        native_lock_hpte(hptep);
-                       dw0 = hptep->dw0.dw0;
-                       if (!dw0.v)
+                       if (! (hptep->v & HPTE_V_VALID))
                                break;
                        native_unlock_hpte(hptep);
                }
@@ -75,56 +70,45 @@ long native_hpte_insert(unsigned long hpte_group, unsigned long va,
        if (i == HPTES_PER_GROUP)
                return -1;
 
-       lhpte.dw1.dword1      = 0;
-       lhpte.dw1.dw1.rpn     = arpn;
-       lhpte.dw1.flags.flags = hpteflags;
-
-       lhpte.dw0.dword0      = 0;
-       lhpte.dw0.dw0.avpn    = va >> 23;
-       lhpte.dw0.dw0.h       = secondary;
-       lhpte.dw0.dw0.bolted  = bolted;
-       lhpte.dw0.dw0.v       = 1;
-
-       if (large) {
-               lhpte.dw0.dw0.l = 1;
-               lhpte.dw0.dw0.avpn &= ~0x1UL;
-       }
-
-       hptep->dw1.dword1 = lhpte.dw1.dword1;
+       hpte_v = (va >> 23) << HPTE_V_AVPN_SHIFT | vflags | HPTE_V_VALID;
+       if (vflags & HPTE_V_LARGE)
+               va &= ~(1UL << HPTE_V_AVPN_SHIFT);
+       hpte_r = (prpn << HPTE_R_RPN_SHIFT) | rflags;
 
+       hptep->r = hpte_r;
        /* Guarantee the second dword is visible before the valid bit */
        __asm__ __volatile__ ("eieio" : : : "memory");
-
        /*
         * Now set the first dword including the valid bit
         * NOTE: this also unlocks the hpte
         */
-       hptep->dw0.dword0 = lhpte.dw0.dword0;
+       hptep->v = hpte_v;
 
        __asm__ __volatile__ ("ptesync" : : : "memory");
 
-       return i | (secondary << 3);
+       return i | (!!(vflags & HPTE_V_SECONDARY) << 3);
 }
 
 static long native_hpte_remove(unsigned long hpte_group)
 {
-       HPTE *hptep;
-       Hpte_dword0 dw0;
+       hpte_t *hptep;
        int i;
        int slot_offset;
+       unsigned long hpte_v;
 
        /* pick a random entry to start at */
        slot_offset = mftb() & 0x7;
 
        for (i = 0; i < HPTES_PER_GROUP; i++) {
                hptep = htab_address + hpte_group + slot_offset;
-               dw0 = hptep->dw0.dw0;
+               hpte_v = hptep->v;
 
-               if (dw0.v && !dw0.bolted) {
+               if ((hpte_v & HPTE_V_VALID) && !(hpte_v & HPTE_V_BOLTED)) {
                        /* retry with lock held */
                        native_lock_hpte(hptep);
-                       dw0 = hptep->dw0.dw0;
-                       if (dw0.v && !dw0.bolted)
+                       hpte_v = hptep->v;
+                       if ((hpte_v & HPTE_V_VALID)
+                           && !(hpte_v & HPTE_V_BOLTED))
                                break;
                        native_unlock_hpte(hptep);
                }
@@ -137,15 +121,15 @@ static long native_hpte_remove(unsigned long hpte_group)
                return -1;
 
        /* Invalidate the hpte. NOTE: this also unlocks it */
-       hptep->dw0.dword0 = 0;
+       hptep->v = 0;
 
        return i;
 }
 
-static inline void set_pp_bit(unsigned long pp, HPTE *addr)
+static inline void set_pp_bit(unsigned long pp, hpte_t *addr)
 {
        unsigned long old;
-       unsigned long *p = &addr->dw1.dword1;
+       unsigned long *p = &addr->r;
 
        __asm__ __volatile__(
        "1:     ldarx   %0,0,%3\n\
@@ -163,11 +147,11 @@ static inline void set_pp_bit(unsigned long pp, HPTE *addr)
  */
 static long native_hpte_find(unsigned long vpn)
 {
-       HPTE *hptep;
+       hpte_t *hptep;
        unsigned long hash;
        unsigned long i, j;
        long slot;
-       Hpte_dword0 dw0;
+       unsigned long hpte_v;
 
        hash = hpt_hash(vpn, 0);
 
@@ -175,10 +159,11 @@ static long native_hpte_find(unsigned long vpn)
                slot = (hash & htab_hash_mask) * HPTES_PER_GROUP;
                for (i = 0; i < HPTES_PER_GROUP; i++) {
                        hptep = htab_address + slot;
-                       dw0 = hptep->dw0.dw0;
+                       hpte_v = hptep->v;
 
-                       if ((dw0.avpn == (vpn >> 11)) && dw0.v &&
-                           (dw0.h == j)) {
+                       if ((HPTE_V_AVPN_VAL(hpte_v) == (vpn >> 11))
+                           && (hpte_v & HPTE_V_VALID)
+                           && ( !!(hpte_v & HPTE_V_SECONDARY) == j)) {
                                /* HPTE matches */
                                if (j)
                                        slot = -slot;
@@ -195,20 +180,21 @@ static long native_hpte_find(unsigned long vpn)
 static long native_hpte_updatepp(unsigned long slot, unsigned long newpp,
                                 unsigned long va, int large, int local)
 {
-       HPTE *hptep = htab_address + slot;
-       Hpte_dword0 dw0;
+       hpte_t *hptep = htab_address + slot;
+       unsigned long hpte_v;
        unsigned long avpn = va >> 23;
        int ret = 0;
 
        if (large)
-               avpn &= ~0x1UL;
+               avpn &= ~1;
 
        native_lock_hpte(hptep);
 
-       dw0 = hptep->dw0.dw0;
+       hpte_v = hptep->v;
 
        /* Even if we miss, we need to invalidate the TLB */
-       if ((dw0.avpn != avpn) || !dw0.v) {
+       if ((HPTE_V_AVPN_VAL(hpte_v) != avpn)
+           || !(hpte_v & HPTE_V_VALID)) {
                native_unlock_hpte(hptep);
                ret = -1;
        } else {
@@ -244,7 +230,7 @@ static void native_hpte_updateboltedpp(unsigned long newpp, unsigned long ea)
 {
        unsigned long vsid, va, vpn, flags = 0;
        long slot;
-       HPTE *hptep;
+       hpte_t *hptep;
        int lock_tlbie = !cpu_has_feature(CPU_FTR_LOCKLESS_TLBIE);
 
        vsid = get_kernel_vsid(ea);
@@ -269,26 +255,27 @@ static void native_hpte_updateboltedpp(unsigned long newpp, unsigned long ea)
 static void native_hpte_invalidate(unsigned long slot, unsigned long va,
                                    int large, int local)
 {
-       HPTE *hptep = htab_address + slot;
-       Hpte_dword0 dw0;
+       hpte_t *hptep = htab_address + slot;
+       unsigned long hpte_v;
        unsigned long avpn = va >> 23;
        unsigned long flags;
        int lock_tlbie = !cpu_has_feature(CPU_FTR_LOCKLESS_TLBIE);
 
        if (large)
-               avpn &= ~0x1UL;
+               avpn &= ~1;
 
        local_irq_save(flags);
        native_lock_hpte(hptep);
 
-       dw0 = hptep->dw0.dw0;
+       hpte_v = hptep->v;
 
        /* Even if we miss, we need to invalidate the TLB */
-       if ((dw0.avpn != avpn) || !dw0.v) {
+       if ((HPTE_V_AVPN_VAL(hpte_v) != avpn)
+           || !(hpte_v & HPTE_V_VALID)) {
                native_unlock_hpte(hptep);
        } else {
                /* Invalidate the hpte. NOTE: this also unlocks it */
-               hptep->dw0.dword0 = 0;
+               hptep->v = 0;
        }
 
        /* Invalidate the tlb */
@@ -304,30 +291,64 @@ static void native_hpte_invalidate(unsigned long slot, unsigned long va,
        local_irq_restore(flags);
 }
 
-static void native_flush_hash_range(unsigned long context,
-                                   unsigned long number, int local)
+/*
+ * clear all mappings on kexec.  All cpus are in real mode (or they will
+ * be when they isi), and we are the only one left.  We rely on our kernel
+ * mapping being 0xC0's and the hardware ignoring those two real bits.
+ *
+ * TODO: add batching support when enabled.  remember, no dynamic memory here,
+ * athough there is the control page available...
+ */
+static void native_hpte_clear(void)
 {
-       unsigned long vsid, vpn, va, hash, secondary, slot, flags, avpn;
+       unsigned long slot, slots, flags;
+       hpte_t *hptep = htab_address;
+       unsigned long hpte_v;
+       unsigned long pteg_count;
+
+       pteg_count = htab_hash_mask + 1;
+
+       local_irq_save(flags);
+
+       /* we take the tlbie lock and hold it.  Some hardware will
+        * deadlock if we try to tlbie from two processors at once.
+        */
+       spin_lock(&native_tlbie_lock);
+
+       slots = pteg_count * HPTES_PER_GROUP;
+
+       for (slot = 0; slot < slots; slot++, hptep++) {
+               /*
+                * we could lock the pte here, but we are the only cpu
+                * running,  right?  and for crash dump, we probably
+                * don't want to wait for a maybe bad cpu.
+                */
+               hpte_v = hptep->v;
+
+               if (hpte_v & HPTE_V_VALID) {
+                       hptep->v = 0;
+                       tlbie(slot2va(hpte_v, slot), hpte_v & HPTE_V_LARGE);
+               }
+       }
+
+       spin_unlock(&native_tlbie_lock);
+       local_irq_restore(flags);
+}
+
+static void native_flush_hash_range(unsigned long number, int local)
+{
+       unsigned long va, vpn, hash, secondary, slot, flags, avpn;
        int i, j;
-       HPTE *hptep;
-       Hpte_dword0 dw0;
+       hpte_t *hptep;
+       unsigned long hpte_v;
        struct ppc64_tlb_batch *batch = &__get_cpu_var(ppc64_tlb_batch);
-
-       /* XXX fix for large ptes */
-       unsigned long large = 0;
+       unsigned long large = batch->large;
 
        local_irq_save(flags);
 
        j = 0;
        for (i = 0; i < number; i++) {
-               if ((batch->addr[i] >= USER_START) &&
-                   (batch->addr[i] <= USER_END))
-                       vsid = get_vsid(context, batch->addr[i]);
-               else
-                       vsid = get_kernel_vsid(batch->addr[i]);
-
-               va = (vsid << 28) | (batch->addr[i] & 0x0fffffff);
-               batch->vaddr[j] = va;
+               va = batch->vaddr[j];
                if (large)
                        vpn = va >> HPAGE_SHIFT;
                else
@@ -347,14 +368,15 @@ static void native_flush_hash_range(unsigned long context,
 
                native_lock_hpte(hptep);
 
-               dw0 = hptep->dw0.dw0;
+               hpte_v = hptep->v;
 
                /* Even if we miss, we need to invalidate the TLB */
-               if ((dw0.avpn != avpn) || !dw0.v) {
+               if ((HPTE_V_AVPN_VAL(hpte_v) != avpn)
+                   || !(hpte_v & HPTE_V_VALID)) {
                        native_unlock_hpte(hptep);
                } else {
                        /* Invalidate the hpte. NOTE: this also unlocks it */
-                       hptep->dw0.dword0 = 0;
+                       hptep->v = 0;
                }
 
                j++;
@@ -376,7 +398,7 @@ static void native_flush_hash_range(unsigned long context,
                asm volatile("ptesync":::"memory");
 
                for (i = 0; i < j; i++)
-                       __tlbie(batch->vaddr[i], 0);
+                       __tlbie(batch->vaddr[i], large);
 
                asm volatile("eieio; tlbsync; ptesync":::"memory");
 
@@ -416,7 +438,8 @@ void hpte_init_native(void)
        ppc_md.hpte_updatepp    = native_hpte_updatepp;
        ppc_md.hpte_updateboltedpp = native_hpte_updateboltedpp;
        ppc_md.hpte_insert      = native_hpte_insert;
-       ppc_md.hpte_remove      = native_hpte_remove;
+       ppc_md.hpte_remove      = native_hpte_remove;
+       ppc_md.hpte_clear_all   = native_hpte_clear;
        if (tlb_batching_enabled())
                ppc_md.flush_hash_range = native_flush_hash_range;
        htab_finish_init();