]> git.kernelconcepts.de Git - karo-tx-linux.git/commitdiff
powerpc/pseries: Fix to handle slb resize across migration
authorBrian King <brking@linux.vnet.ibm.com>
Fri, 28 Aug 2009 12:06:29 +0000 (12:06 +0000)
committerGreg Kroah-Hartman <gregkh@suse.de>
Thu, 24 Sep 2009 15:47:37 +0000 (08:47 -0700)
commit 46db2f86a3b2a94e0b33e0b4548fb7b7b6bdff66 upstream.

The SLB can change sizes across a live migration, which was not
being handled, resulting in possible machine crashes during
migration if migrating to a machine which has a smaller max SLB
size than the source machine. Fix this by first reducing the
SLB size to the minimum possible value, which is 32, prior to
migration. Then during the device tree update which occurs after
migration, we make the call to ensure the SLB gets updated. Also
add the slb_size to the lparcfg output so that the migration
tools can check to make sure the kernel has this capability
before allowing migration in scenarios where the SLB size will change.

BenH: Fixed #include <asm/mmu-hash64.h> -> <asm/mmu.h> to avoid
      breaking ppc32 build

Signed-off-by: Brian King <brking@linux.vnet.ibm.com>
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
arch/powerpc/include/asm/mmu-hash64.h
arch/powerpc/kernel/lparcfg.c
arch/powerpc/kernel/rtas.c
arch/powerpc/mm/slb.c
arch/powerpc/platforms/pseries/reconfig.c

index c2df53c5ceb9a253c7c4661731b67397b14afac3..cd1f7043078e6bab51c7c49990eeee1656257c1f 100644 (file)
@@ -41,6 +41,7 @@ extern char initial_stab[];
 
 #define SLB_NUM_BOLTED         3
 #define SLB_CACHE_ENTRIES      8
+#define SLB_MIN_SIZE           32
 
 /* Bits in the SLB ESID word */
 #define SLB_ESID_V             ASM_CONST(0x0000000008000000) /* valid */
@@ -299,6 +300,7 @@ extern void slb_flush_and_rebolt(void);
 extern void stab_initialize(unsigned long stab);
 
 extern void slb_vmalloc_update(void);
+extern void slb_set_size(u16 size);
 #endif /* __ASSEMBLY__ */
 
 /*
index b3eef30b5131a0d1eaf43551ae0d0aa2ccda6d92..c7299107a4b1b0744d359081554bc589d51f19a2 100644 (file)
@@ -35,6 +35,7 @@
 #include <asm/prom.h>
 #include <asm/vdso_datapage.h>
 #include <asm/vio.h>
+#include <asm/mmu.h>
 
 #define MODULE_VERS "1.8"
 #define MODULE_NAME "lparcfg"
@@ -485,6 +486,8 @@ static int pseries_lparcfg_data(struct seq_file *m, void *v)
 
        seq_printf(m, "shared_processor_mode=%d\n", lppaca[0].shared_proc);
 
+       seq_printf(m, "slb_size=%d\n", mmu_slb_size);
+
        return 0;
 }
 
index 1f8505c235482c5fea77a9f3fd1ec175a526a202..49e6d919362d1d160e2571fea95f3f337002eba6 100644 (file)
@@ -38,6 +38,7 @@
 #include <asm/syscalls.h>
 #include <asm/smp.h>
 #include <asm/atomic.h>
+#include <asm/mmu.h>
 
 struct rtas_t rtas = {
        .lock = SPIN_LOCK_UNLOCKED
@@ -665,6 +666,7 @@ static void rtas_percpu_suspend_me(void *info)
 {
        long rc;
        unsigned long msr_save;
+       u16 slb_size = mmu_slb_size;
        int cpu;
        struct rtas_suspend_me_data *data =
                (struct rtas_suspend_me_data *)info;
@@ -686,13 +688,16 @@ static void rtas_percpu_suspend_me(void *info)
                /* All other cpus are in H_JOIN, this cpu does
                 * the suspend.
                 */
+               slb_set_size(SLB_MIN_SIZE);
                printk(KERN_DEBUG "calling ibm,suspend-me on cpu %i\n",
                       smp_processor_id());
                data->error = rtas_call(data->token, 0, 1, NULL);
 
-               if (data->error)
+               if (data->error) {
                        printk(KERN_DEBUG "ibm,suspend-me returned %d\n",
                               data->error);
+                       slb_set_size(slb_size);
+               }
        } else {
                printk(KERN_ERR "H_JOIN on cpu %i failed with rc = %ld\n",
                       smp_processor_id(), rc);
index 89497fb04280ce6bb63b50af6603c513c942d872..4d73765866939dd791322278052375f60e69be1e 100644 (file)
@@ -247,14 +247,22 @@ void switch_slb(struct task_struct *tsk, struct mm_struct *mm)
 static inline void patch_slb_encoding(unsigned int *insn_addr,
                                      unsigned int immed)
 {
-       /* Assume the instruction had a "0" immediate value, just
-        * "or" in the new value
-        */
-       *insn_addr |= immed;
+       *insn_addr = (*insn_addr & 0xffff0000) | immed;
        flush_icache_range((unsigned long)insn_addr, 4+
                           (unsigned long)insn_addr);
 }
 
+void slb_set_size(u16 size)
+{
+       extern unsigned int *slb_compare_rr_to_size;
+
+       if (mmu_slb_size == size)
+               return;
+
+       mmu_slb_size = size;
+       patch_slb_encoding(slb_compare_rr_to_size, mmu_slb_size);
+}
+
 void slb_initialize(void)
 {
        unsigned long linear_llp, vmalloc_llp, io_llp;
index 7637bd38c7957d77d50d01c5f70a8597f3a4ddad..e67e18d147a75a9dddab03a75e18fc4057774cb2 100644 (file)
@@ -20,6 +20,7 @@
 #include <asm/machdep.h>
 #include <asm/uaccess.h>
 #include <asm/pSeries_reconfig.h>
+#include <asm/mmu.h>
 
 
 
@@ -439,9 +440,15 @@ static int do_update_property(char *buf, size_t bufsize)
        if (!newprop)
                return -ENOMEM;
 
+       if (!strcmp(name, "slb-size") || !strcmp(name, "ibm,slb-size"))
+               slb_set_size(*(int *)value);
+
        oldprop = of_find_property(np, name,NULL);
-       if (!oldprop)
+       if (!oldprop) {
+               if (strlen(name))
+                       return prom_add_property(np, newprop);
                return -ENODEV;
+       }
 
        rc = prom_update_property(np, newprop, oldprop);
        if (rc)