aboutsummaryrefslogtreecommitdiffstats
path: root/arch/powerpc
diff options
context:
space:
mode:
Diffstat (limited to 'arch/powerpc')
-rw-r--r--arch/powerpc/kernel/rtas.c99
-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/embedded6xx/prpmc2800.c1
-rw-r--r--arch/powerpc/platforms/pseries/Kconfig2
-rw-r--r--arch/powerpc/sysdev/uic.c18
9 files changed, 86 insertions, 47 deletions
diff --git a/arch/powerpc/kernel/rtas.c b/arch/powerpc/kernel/rtas.c
index 214780798289..52e95c2158c0 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);
@@ -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);
+
+ mtmsr(msr_save);
- 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);
+ 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/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/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/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/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,
};