summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--arch/powerpc/include/asm/mmu-hash64.h2
-rw-r--r--arch/powerpc/kernel/lparcfg.c3
-rw-r--r--arch/powerpc/kernel/rtas.c7
-rw-r--r--arch/powerpc/mm/slb.c16
-rw-r--r--arch/powerpc/platforms/pseries/reconfig.c9
5 files changed, 31 insertions, 6 deletions
diff --git a/arch/powerpc/include/asm/mmu-hash64.h b/arch/powerpc/include/asm/mmu-hash64.h
index 98c104a09961..edab67ee8e53 100644
--- a/arch/powerpc/include/asm/mmu-hash64.h
+++ b/arch/powerpc/include/asm/mmu-hash64.h
@@ -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 */
@@ -296,6 +297,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__ */
/*
diff --git a/arch/powerpc/kernel/lparcfg.c b/arch/powerpc/kernel/lparcfg.c
index 78b3f7840ade..f3bb5fb359c0 100644
--- a/arch/powerpc/kernel/lparcfg.c
+++ b/arch/powerpc/kernel/lparcfg.c
@@ -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"
@@ -501,6 +502,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;
}
diff --git a/arch/powerpc/kernel/rtas.c b/arch/powerpc/kernel/rtas.c
index ee4c7609b649..a36c6c32830f 100644
--- a/arch/powerpc/kernel/rtas.c
+++ b/arch/powerpc/kernel/rtas.c
@@ -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
@@ -692,6 +693,7 @@ static void rtas_percpu_suspend_me(void *info)
{
long rc = H_SUCCESS;
unsigned long msr_save;
+ u16 slb_size = mmu_slb_size;
int cpu;
struct rtas_suspend_me_data *data =
(struct rtas_suspend_me_data *)info;
@@ -714,13 +716,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);
diff --git a/arch/powerpc/mm/slb.c b/arch/powerpc/mm/slb.c
index 89497fb04280..4d7376586693 100644
--- a/arch/powerpc/mm/slb.c
+++ b/arch/powerpc/mm/slb.c
@@ -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;
diff --git a/arch/powerpc/platforms/pseries/reconfig.c b/arch/powerpc/platforms/pseries/reconfig.c
index b6f1b137d427..2e2bbe120b90 100644
--- a/arch/powerpc/platforms/pseries/reconfig.c
+++ b/arch/powerpc/platforms/pseries/reconfig.c
@@ -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)