[PATCH] ppc64 kexec: native hash clear
authorR Sharada <sharada@in.ibm.com>
Sat, 25 Jun 2005 21:58:08 +0000 (14:58 -0700)
committerLinus Torvalds <torvalds@ppc970.osdl.org>
Sat, 25 Jun 2005 23:24:51 +0000 (16:24 -0700)
Add code to clear the hash table and invalidate the tlb for native (SMP,
non-LPAR) mode.  Supports 16M and 4k pages.

Signed-off-by: Milton Miller <miltonm@bga.com>
Signed-off-by: R Sharada <sharada@in.ibm.com>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
arch/ppc64/mm/hash_native.c
include/asm-ppc64/mmu.h

index 52b6b9305341e3774b94bba7bca216cbd6ce3bd0..4fec05817d660bcb95db16380745f4f209bfd62e 100644 (file)
@@ -304,6 +304,50 @@ static void native_hpte_invalidate(unsigned long slot, unsigned long va,
        local_irq_restore(flags);
 }
 
+/*
+ * 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 slot, slots, flags;
+       HPTE *hptep = htab_address;
+       Hpte_dword0 dw0;
+       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.
+                */
+               dw0 = hptep->dw0.dw0;
+
+               if (dw0.v) {
+                       hptep->dw0.dword0 = 0;
+                       tlbie(slot2va(dw0.avpn, dw0.l, dw0.h, slot), dw0.l);
+               }
+       }
+
+       spin_unlock(&native_tlbie_lock);
+       local_irq_restore(flags);
+}
+
 static void native_flush_hash_range(unsigned long context,
                                    unsigned long number, int local)
 {
@@ -415,7 +459,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();
index 9d03a98a4fa3009ea04496d117649a0203a68a16..f373de5e3dd900964fbf2ac5f3b52e751eeab3a3 100644 (file)
@@ -181,6 +181,28 @@ static inline void tlbiel(unsigned long va)
        asm volatile("ptesync": : :"memory");
 }
 
+static inline unsigned long slot2va(unsigned long avpn, unsigned long large,
+               unsigned long secondary, unsigned long slot)
+{
+       unsigned long va;
+
+       va = avpn << 23;
+
+       if (!large) {
+               unsigned long vpi, pteg;
+
+               pteg = slot / HPTES_PER_GROUP;
+               if (secondary)
+                       pteg = ~pteg;
+
+               vpi = ((va >> 28) ^ pteg) & htab_hash_mask;
+
+               va |= vpi << PAGE_SHIFT;
+       }
+
+       return va;
+}
+
 /*
  * Handle a fault by adding an HPTE. If the address can't be determined
  * to be valid via Linux page tables, return 1. If handled return 0