aboutsummaryrefslogtreecommitdiffstats
path: root/arch/powerpc
diff options
context:
space:
mode:
Diffstat (limited to 'arch/powerpc')
-rw-r--r--arch/powerpc/kernel/asm-offsets.c4
-rw-r--r--arch/powerpc/kernel/rtas.c111
-rw-r--r--arch/powerpc/kernel/time.c5
-rw-r--r--arch/powerpc/kernel/vdso.c11
-rw-r--r--arch/powerpc/kernel/vdso32/cacheflush.S41
-rw-r--r--arch/powerpc/kernel/vdso64/cacheflush.S41
-rw-r--r--arch/powerpc/mm/stab.c1
-rw-r--r--arch/powerpc/platforms/40x/walnut.c3
-rw-r--r--arch/powerpc/platforms/44x/bamboo.c3
-rw-r--r--arch/powerpc/platforms/44x/ebony.c3
-rw-r--r--arch/powerpc/platforms/44x/sequoia.c3
-rw-r--r--arch/powerpc/platforms/cell/spufs/inode.c1
-rw-r--r--arch/powerpc/platforms/embedded6xx/prpmc2800.c1
-rw-r--r--arch/powerpc/platforms/pasemi/setup.c2
-rw-r--r--arch/powerpc/platforms/pseries/Kconfig2
-rw-r--r--arch/powerpc/platforms/pseries/setup.c3
-rw-r--r--arch/powerpc/sysdev/uic.c18
17 files changed, 172 insertions, 81 deletions
diff --git a/arch/powerpc/kernel/asm-offsets.c b/arch/powerpc/kernel/asm-offsets.c
index 2c8e756d19a3..d67bcd84f329 100644
--- a/arch/powerpc/kernel/asm-offsets.c
+++ b/arch/powerpc/kernel/asm-offsets.c
@@ -284,6 +284,10 @@ int main(void)
DEFINE(CFG_SYSCALL_MAP32, offsetof(struct vdso_data, syscall_map_32));
DEFINE(WTOM_CLOCK_SEC, offsetof(struct vdso_data, wtom_clock_sec));
DEFINE(WTOM_CLOCK_NSEC, offsetof(struct vdso_data, wtom_clock_nsec));
+ DEFINE(CFG_ICACHE_BLOCKSZ, offsetof(struct vdso_data, icache_block_size));
+ DEFINE(CFG_DCACHE_BLOCKSZ, offsetof(struct vdso_data, dcache_block_size));
+ DEFINE(CFG_ICACHE_LOGBLOCKSZ, offsetof(struct vdso_data, icache_log_block_size));
+ DEFINE(CFG_DCACHE_LOGBLOCKSZ, offsetof(struct vdso_data, dcache_log_block_size));
#ifdef CONFIG_PPC64
DEFINE(CFG_SYSCALL_MAP64, offsetof(struct vdso_data, syscall_map_64));
DEFINE(TVAL64_TV_SEC, offsetof(struct timeval, tv_sec));
diff --git a/arch/powerpc/kernel/rtas.c b/arch/powerpc/kernel/rtas.c
index 214780798289..053cac19f714 100644
--- a/arch/powerpc/kernel/rtas.c
+++ b/arch/powerpc/kernel/rtas.c
@@ -19,6 +19,9 @@
#include <linux/init.h>
#include <linux/capability.h>
#include <linux/delay.h>
+#include <linux/smp.h>
+#include <linux/completion.h>
+#include <linux/cpumask.h>
#include <asm/prom.h>
#include <asm/rtas.h>
@@ -34,6 +37,8 @@
#include <asm/lmb.h>
#include <asm/udbg.h>
#include <asm/syscalls.h>
+#include <asm/smp.h>
+#include <asm/atomic.h>
struct rtas_t rtas = {
.lock = SPIN_LOCK_UNLOCKED
@@ -41,8 +46,10 @@ struct rtas_t rtas = {
EXPORT_SYMBOL(rtas);
struct rtas_suspend_me_data {
- long waiting;
- struct rtas_args *args;
+ atomic_t working; /* number of cpus accessing this struct */
+ int token; /* ibm,suspend-me */
+ int error;
+ struct completion *complete; /* wait on this until working == 0 */
};
DEFINE_SPINLOCK(rtas_data_buf_lock);
@@ -631,18 +638,18 @@ void rtas_halt(void)
/* Must be in the RMO region, so we place it here */
static char rtas_os_term_buf[2048];
-void rtas_os_term(char *str)
+void rtas_panic_msg(char *str)
{
- int status;
+ snprintf(rtas_os_term_buf, 2048, "OS panic: %s", str);
+}
- if (panic_timeout)
- return;
+void rtas_os_term(void)
+{
+ int status;
if (RTAS_UNKNOWN_SERVICE == rtas_token("ibm,os-term"))
return;
- snprintf(rtas_os_term_buf, 2048, "OS panic: %s", str);
-
do {
status = rtas_call(rtas_token("ibm,os-term"), 1, 1, NULL,
__pa(rtas_os_term_buf));
@@ -657,50 +664,62 @@ static int ibm_suspend_me_token = RTAS_UNKNOWN_SERVICE;
#ifdef CONFIG_PPC_PSERIES
static void rtas_percpu_suspend_me(void *info)
{
- int i;
long rc;
- long flags;
+ unsigned long msr_save;
+ int cpu;
struct rtas_suspend_me_data *data =
(struct rtas_suspend_me_data *)info;
- /*
- * We use "waiting" to indicate our state. As long
- * as it is >0, we are still trying to all join up.
- * If it goes to 0, we have successfully joined up and
- * one thread got H_CONTINUE. If any error happens,
- * we set it to <0.
- */
- local_irq_save(flags);
- do {
- rc = plpar_hcall_norets(H_JOIN);
- smp_rmb();
- } while (rc == H_SUCCESS && data->waiting > 0);
- if (rc == H_SUCCESS)
- goto out;
+ atomic_inc(&data->working);
+
+ /* really need to ensure MSR.EE is off for H_JOIN */
+ msr_save = mfmsr();
+ mtmsr(msr_save & ~(MSR_EE));
+
+ rc = plpar_hcall_norets(H_JOIN);
- if (rc == H_CONTINUE) {
- data->waiting = 0;
- data->args->args[data->args->nargs] =
- rtas_call(ibm_suspend_me_token, 0, 1, NULL);
- for_each_possible_cpu(i)
- plpar_hcall_norets(H_PROD,i);
+ mtmsr(msr_save);
+
+ if (rc == H_SUCCESS) {
+ /* This cpu was prodded and the suspend is complete. */
+ goto out;
+ } else if (rc == H_CONTINUE) {
+ /* All other cpus are in H_JOIN, this cpu does
+ * the suspend.
+ */
+ 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)
+ printk(KERN_DEBUG "ibm,suspend-me returned %d\n",
+ data->error);
} else {
- data->waiting = -EBUSY;
- printk(KERN_ERR "Error on H_JOIN hypervisor call\n");
+ printk(KERN_ERR "H_JOIN on cpu %i failed with rc = %ld\n",
+ smp_processor_id(), rc);
+ data->error = rc;
}
-
+ /* This cpu did the suspend or got an error; in either case,
+ * we need to prod all other other cpus out of join state.
+ * Extra prods are harmless.
+ */
+ for_each_online_cpu(cpu)
+ plpar_hcall_norets(H_PROD, get_hard_smp_processor_id(cpu));
out:
- local_irq_restore(flags);
- return;
+ if (atomic_dec_return(&data->working) == 0)
+ complete(data->complete);
}
static int rtas_ibm_suspend_me(struct rtas_args *args)
{
- int i;
long state;
long rc;
unsigned long retbuf[PLPAR_HCALL_BUFSIZE];
struct rtas_suspend_me_data data;
+ DECLARE_COMPLETION_ONSTACK(done);
+
+ if (!rtas_service_present("ibm,suspend-me"))
+ return -ENOSYS;
/* Make sure the state is valid */
rc = plpar_hcall(H_VASI_STATE, retbuf,
@@ -721,25 +740,23 @@ static int rtas_ibm_suspend_me(struct rtas_args *args)
return 0;
}
- data.waiting = 1;
- data.args = args;
+ atomic_set(&data.working, 0);
+ data.token = rtas_token("ibm,suspend-me");
+ data.error = 0;
+ data.complete = &done;
/* Call function on all CPUs. One of us will make the
* rtas call
*/
if (on_each_cpu(rtas_percpu_suspend_me, &data, 1, 0))
- data.waiting = -EINVAL;
+ data.error = -EINVAL;
- if (data.waiting != 0)
- printk(KERN_ERR "Error doing global join\n");
+ wait_for_completion(&done);
- /* Prod each CPU. This won't hurt, and will wake
- * anyone we successfully put to sleep with H_JOIN.
- */
- for_each_possible_cpu(i)
- plpar_hcall_norets(H_PROD, i);
+ if (data.error != 0)
+ printk(KERN_ERR "Error doing global join\n");
- return data.waiting;
+ return data.error;
}
#else /* CONFIG_PPC_PSERIES */
static int rtas_ibm_suspend_me(struct rtas_args *args)
diff --git a/arch/powerpc/kernel/time.c b/arch/powerpc/kernel/time.c
index c0d77723ba11..a925a8eae121 100644
--- a/arch/powerpc/kernel/time.c
+++ b/arch/powerpc/kernel/time.c
@@ -241,8 +241,9 @@ void account_system_vtime(struct task_struct *tsk)
/* deltascaled includes both user and system time.
* Hence scale it based on the purr ratio to estimate
* the system time */
- deltascaled = deltascaled * get_paca()->system_time /
- (get_paca()->system_time + get_paca()->user_time);
+ if (get_paca()->user_time)
+ deltascaled = deltascaled * get_paca()->system_time /
+ (get_paca()->system_time + get_paca()->user_time);
delta += get_paca()->system_time;
get_paca()->system_time = 0;
}
diff --git a/arch/powerpc/kernel/vdso.c b/arch/powerpc/kernel/vdso.c
index 2322ba5cce4c..3702df7dc567 100644
--- a/arch/powerpc/kernel/vdso.c
+++ b/arch/powerpc/kernel/vdso.c
@@ -699,11 +699,22 @@ static int __init vdso_init(void)
vdso_data->icache_size = ppc64_caches.isize;
vdso_data->icache_line_size = ppc64_caches.iline_size;
+ /* XXXOJN: Blocks should be added to ppc64_caches and used instead */
+ vdso_data->dcache_block_size = ppc64_caches.dline_size;
+ vdso_data->icache_block_size = ppc64_caches.iline_size;
+ vdso_data->dcache_log_block_size = ppc64_caches.log_dline_size;
+ vdso_data->icache_log_block_size = ppc64_caches.log_iline_size;
+
/*
* Calculate the size of the 64 bits vDSO
*/
vdso64_pages = (&vdso64_end - &vdso64_start) >> PAGE_SHIFT;
DBG("vdso64_kbase: %p, 0x%x pages\n", vdso64_kbase, vdso64_pages);
+#else
+ vdso_data->dcache_block_size = L1_CACHE_BYTES;
+ vdso_data->dcache_log_block_size = L1_CACHE_SHIFT;
+ vdso_data->icache_block_size = L1_CACHE_BYTES;
+ vdso_data->icache_log_block_size = L1_CACHE_SHIFT;
#endif /* CONFIG_PPC64 */
diff --git a/arch/powerpc/kernel/vdso32/cacheflush.S b/arch/powerpc/kernel/vdso32/cacheflush.S
index 9cb319992c38..1ba6feb71b31 100644
--- a/arch/powerpc/kernel/vdso32/cacheflush.S
+++ b/arch/powerpc/kernel/vdso32/cacheflush.S
@@ -23,29 +23,46 @@
*
* Flushes the data cache & invalidate the instruction cache for the
* provided range [start, end[
- *
- * Note: all CPUs supported by this kernel have a 128 bytes cache
- * line size so we don't have to peek that info from the datapage
*/
V_FUNCTION_BEGIN(__kernel_sync_dicache)
.cfi_startproc
- li r5,127
- andc r6,r3,r5 /* round low to line bdy */
+ mflr r12
+ .cfi_register lr,r12
+ mr r11,r3
+ bl __get_datapage@local
+ mtlr r12
+ mr r10,r3
+
+ lwz r7,CFG_DCACHE_BLOCKSZ(r10)
+ addi r5,r7,-1
+ andc r6,r11,r5 /* round low to line bdy */
subf r8,r6,r4 /* compute length */
add r8,r8,r5 /* ensure we get enough */
- srwi. r8,r8,7 /* compute line count */
+ lwz r9,CFG_DCACHE_LOGBLOCKSZ(r10)
+ srw. r8,r8,r9 /* compute line count */
crclr cr0*4+so
beqlr /* nothing to do? */
mtctr r8
- mr r3,r6
-1: dcbst 0,r3
- addi r3,r3,128
+1: dcbst 0,r6
+ add r6,r6,r7
bdnz 1b
sync
+
+/* Now invalidate the instruction cache */
+
+ lwz r7,CFG_ICACHE_BLOCKSZ(r10)
+ addi r5,r7,-1
+ andc r6,r11,r5 /* round low to line bdy */
+ subf r8,r6,r4 /* compute length */
+ add r8,r8,r5
+ lwz r9,CFG_ICACHE_LOGBLOCKSZ(r10)
+ srw. r8,r8,r9 /* compute line count */
+ crclr cr0*4+so
+ beqlr /* nothing to do? */
mtctr r8
-1: icbi 0,r6
- addi r6,r6,128
- bdnz 1b
+2: icbi 0,r6
+ add r6,r6,r7
+ bdnz 2b
isync
li r3,0
blr
diff --git a/arch/powerpc/kernel/vdso64/cacheflush.S b/arch/powerpc/kernel/vdso64/cacheflush.S
index 66a36d3cc6ad..69c5af2b3c96 100644
--- a/arch/powerpc/kernel/vdso64/cacheflush.S
+++ b/arch/powerpc/kernel/vdso64/cacheflush.S
@@ -23,29 +23,46 @@
*
* Flushes the data cache & invalidate the instruction cache for the
* provided range [start, end[
- *
- * Note: all CPUs supported by this kernel have a 128 bytes cache
- * line size so we don't have to peek that info from the datapage
*/
V_FUNCTION_BEGIN(__kernel_sync_dicache)
.cfi_startproc
- li r5,127
- andc r6,r3,r5 /* round low to line bdy */
+ mflr r12
+ .cfi_register lr,r12
+ mr r11,r3
+ bl V_LOCAL_FUNC(__get_datapage)
+ mtlr r12
+ mr r10,r3
+
+ lwz r7,CFG_DCACHE_BLOCKSZ(r10)
+ addi r5,r7,-1
+ andc r6,r11,r5 /* round low to line bdy */
subf r8,r6,r4 /* compute length */
add r8,r8,r5 /* ensure we get enough */
- srwi. r8,r8,7 /* compute line count */
+ lwz r9,CFG_DCACHE_LOGBLOCKSZ(r10)
+ srw. r8,r8,r9 /* compute line count */
crclr cr0*4+so
beqlr /* nothing to do? */
mtctr r8
- mr r3,r6
-1: dcbst 0,r3
- addi r3,r3,128
+1: dcbst 0,r6
+ add r6,r6,r7
bdnz 1b
sync
+
+/* Now invalidate the instruction cache */
+
+ lwz r7,CFG_ICACHE_BLOCKSZ(r10)
+ addi r5,r7,-1
+ andc r6,r11,r5 /* round low to line bdy */
+ subf r8,r6,r4 /* compute length */
+ add r8,r8,r5
+ lwz r9,CFG_ICACHE_LOGBLOCKSZ(r10)
+ srw. r8,r8,r9 /* compute line count */
+ crclr cr0*4+so
+ beqlr /* nothing to do? */
mtctr r8
-1: icbi 0,r6
- addi r6,r6,128
- bdnz 1b
+2: icbi 0,r6
+ add r6,r6,r7
+ bdnz 2b
isync
li r3,0
blr
diff --git a/arch/powerpc/mm/stab.c b/arch/powerpc/mm/stab.c
index 9e85bda76216..50448d5de9d2 100644
--- a/arch/powerpc/mm/stab.c
+++ b/arch/powerpc/mm/stab.c
@@ -20,6 +20,7 @@
#include <asm/lmb.h>
#include <asm/abs_addr.h>
#include <asm/firmware.h>
+#include <asm/iseries/hv_call.h>
struct stab_entry {
unsigned long esid_data;
diff --git a/arch/powerpc/platforms/40x/walnut.c b/arch/powerpc/platforms/40x/walnut.c
index eb0c136b1c44..ff6db2431798 100644
--- a/arch/powerpc/platforms/40x/walnut.c
+++ b/arch/powerpc/platforms/40x/walnut.c
@@ -17,12 +17,13 @@
*/
#include <linux/init.h>
+#include <linux/of_platform.h>
+
#include <asm/machdep.h>
#include <asm/prom.h>
#include <asm/udbg.h>
#include <asm/time.h>
#include <asm/uic.h>
-#include <asm/of_platform.h>
static struct of_device_id walnut_of_bus[] = {
{ .compatible = "ibm,plb3", },
diff --git a/arch/powerpc/platforms/44x/bamboo.c b/arch/powerpc/platforms/44x/bamboo.c
index 470e1a3fd755..be23f112184f 100644
--- a/arch/powerpc/platforms/44x/bamboo.c
+++ b/arch/powerpc/platforms/44x/bamboo.c
@@ -14,12 +14,13 @@
* option) any later version.
*/
#include <linux/init.h>
+#include <linux/of_platform.h>
+
#include <asm/machdep.h>
#include <asm/prom.h>
#include <asm/udbg.h>
#include <asm/time.h>
#include <asm/uic.h>
-#include <asm/of_platform.h>
#include "44x.h"
static struct of_device_id bamboo_of_bus[] = {
diff --git a/arch/powerpc/platforms/44x/ebony.c b/arch/powerpc/platforms/44x/ebony.c
index 40e18fcb666c..6cd3476767cc 100644
--- a/arch/powerpc/platforms/44x/ebony.c
+++ b/arch/powerpc/platforms/44x/ebony.c
@@ -17,12 +17,13 @@
*/
#include <linux/init.h>
+#include <linux/of_platform.h>
+
#include <asm/machdep.h>
#include <asm/prom.h>
#include <asm/udbg.h>
#include <asm/time.h>
#include <asm/uic.h>
-#include <asm/of_platform.h>
#include "44x.h"
diff --git a/arch/powerpc/platforms/44x/sequoia.c b/arch/powerpc/platforms/44x/sequoia.c
index 30700b31d43b..21a9dd14f297 100644
--- a/arch/powerpc/platforms/44x/sequoia.c
+++ b/arch/powerpc/platforms/44x/sequoia.c
@@ -14,12 +14,13 @@
* option) any later version.
*/
#include <linux/init.h>
+#include <linux/of_platform.h>
+
#include <asm/machdep.h>
#include <asm/prom.h>
#include <asm/udbg.h>
#include <asm/time.h>
#include <asm/uic.h>
-#include <asm/of_platform.h>
#include "44x.h"
static struct of_device_id sequoia_of_bus[] = {
diff --git a/arch/powerpc/platforms/cell/spufs/inode.c b/arch/powerpc/platforms/cell/spufs/inode.c
index 0966d093db43..c0e968a4c211 100644
--- a/arch/powerpc/platforms/cell/spufs/inode.c
+++ b/arch/powerpc/platforms/cell/spufs/inode.c
@@ -171,6 +171,7 @@ static int spufs_rmdir(struct inode *parent, struct dentry *dir)
{
/* remove all entries */
spufs_prune_dir(dir);
+ d_drop(dir);
return simple_rmdir(parent, dir);
}
diff --git a/arch/powerpc/platforms/embedded6xx/prpmc2800.c b/arch/powerpc/platforms/embedded6xx/prpmc2800.c
index e484cac75095..653a5eb91c90 100644
--- a/arch/powerpc/platforms/embedded6xx/prpmc2800.c
+++ b/arch/powerpc/platforms/embedded6xx/prpmc2800.c
@@ -144,6 +144,7 @@ static int __init prpmc2800_probe(void)
strncpy(prpmc2800_platform_name, m,
min((int)len, PLATFORM_NAME_MAX - 1));
+ _set_L2CR(_get_L2CR() | L2CR_L2E);
return 1;
}
diff --git a/arch/powerpc/platforms/pasemi/setup.c b/arch/powerpc/platforms/pasemi/setup.c
index 3a5d112af5e0..3d62060498b4 100644
--- a/arch/powerpc/platforms/pasemi/setup.c
+++ b/arch/powerpc/platforms/pasemi/setup.c
@@ -214,7 +214,7 @@ static __init void pas_init_IRQ(void)
printk(KERN_DEBUG "OpenPIC addr: %lx\n", openpic_addr);
mpic = mpic_alloc(mpic_node, openpic_addr,
- MPIC_PRIMARY|MPIC_LARGE_VECTORS|MPIC_WANTS_RESET,
+ MPIC_PRIMARY|MPIC_LARGE_VECTORS,
0, 0, " PAS-OPIC ");
BUG_ON(!mpic);
diff --git a/arch/powerpc/platforms/pseries/Kconfig b/arch/powerpc/platforms/pseries/Kconfig
index 16e4e401b820..306a9d07491d 100644
--- a/arch/powerpc/platforms/pseries/Kconfig
+++ b/arch/powerpc/platforms/pseries/Kconfig
@@ -21,7 +21,7 @@ config PPC_SPLPAR
config EEH
bool "PCI Extended Error Handling (EEH)" if EMBEDDED
- depends on PPC_PSERIES
+ depends on PPC_PSERIES && PCI
default y if !EMBEDDED
config SCANLOG
diff --git a/arch/powerpc/platforms/pseries/setup.c b/arch/powerpc/platforms/pseries/setup.c
index fdb9b1c8f977..fdeefe54ea91 100644
--- a/arch/powerpc/platforms/pseries/setup.c
+++ b/arch/powerpc/platforms/pseries/setup.c
@@ -507,7 +507,8 @@ define_machine(pseries) {
.restart = rtas_restart,
.power_off = pSeries_power_off,
.halt = rtas_halt,
- .panic = rtas_os_term,
+ .panic = rtas_panic_msg,
+ .machine_shutdown = rtas_os_term,
.get_boot_time = rtas_get_boot_time,
.get_rtc_time = rtas_get_rtc_time,
.set_rtc_time = rtas_set_rtc_time,
diff --git a/arch/powerpc/sysdev/uic.c b/arch/powerpc/sysdev/uic.c
index 5149716c734d..847a5496b869 100644
--- a/arch/powerpc/sysdev/uic.c
+++ b/arch/powerpc/sysdev/uic.c
@@ -97,6 +97,22 @@ static void uic_ack_irq(unsigned int virq)
spin_unlock_irqrestore(&uic->lock, flags);
}
+static void uic_mask_ack_irq(unsigned int virq)
+{
+ struct uic *uic = get_irq_chip_data(virq);
+ unsigned int src = uic_irq_to_hw(virq);
+ unsigned long flags;
+ u32 er, sr;
+
+ sr = 1 << (31-src);
+ spin_lock_irqsave(&uic->lock, flags);
+ er = mfdcr(uic->dcrbase + UIC_ER);
+ er &= ~sr;
+ mtdcr(uic->dcrbase + UIC_ER, er);
+ mtdcr(uic->dcrbase + UIC_SR, sr);
+ spin_unlock_irqrestore(&uic->lock, flags);
+}
+
static int uic_set_irq_type(unsigned int virq, unsigned int flow_type)
{
struct uic *uic = get_irq_chip_data(virq);
@@ -152,7 +168,7 @@ static struct irq_chip uic_irq_chip = {
.typename = " UIC ",
.unmask = uic_unmask_irq,
.mask = uic_mask_irq,
-/* .mask_ack = uic_mask_irq_and_ack, */
+ .mask_ack = uic_mask_ack_irq,
.ack = uic_ack_irq,
.set_type = uic_set_irq_type,
};