From: Olof Johansson <olof@austin.ibm.com>

RTAS on IBM pSeries runs in real mode, so all pointers being passed in to
it need to be in low memory.  There's two places in the RAS code that
passes in pointers to items on the stack, which might end up being above
the limit.

Below patch resolves this by creating a buffer in BSS + a lock for
serialization.  There's no reason to worry about contention on the lock,
since rtas_call() also serializes on a single spinlock and this is an
infrequent code path in the first place.


---

 25-akpm/arch/ppc64/kernel/ras.c |   19 +++++++++++++++++--
 1 files changed, 17 insertions(+), 2 deletions(-)

diff -puN arch/ppc64/kernel/ras.c~ppc64-move-epow-log-buffer-to-bss arch/ppc64/kernel/ras.c
--- 25/arch/ppc64/kernel/ras.c~ppc64-move-epow-log-buffer-to-bss	2004-04-10 02:44:40.589710928 -0700
+++ 25-akpm/arch/ppc64/kernel/ras.c	2004-04-10 02:44:40.593710320 -0700
@@ -110,6 +110,9 @@ static int __init init_ras_IRQ(void)
 }
 __initcall(init_ras_IRQ);
 
+static struct rtas_error_log log_buf;
+static spinlock_t log_lock = SPIN_LOCK_UNLOCKED;
+
 /*
  * Handle power subsystem events (EPOW).
  *
@@ -124,11 +127,17 @@ ras_epow_interrupt(int irq, void *dev_id
 	unsigned int size = sizeof(log_entry);
 	long status = 0xdeadbeef;
 
+	spin_lock(&log_lock);
+
 	status = rtas_call(rtas_token("check-exception"), 6, 1, NULL, 
 			   0x500, irq, 
 			   RTAS_EPOW_WARNING | RTAS_POWERMGM_EVENTS, 
 			   1,  /* Time Critical */
-			   __pa(&log_entry), size);
+			   __pa(&log_buf), size);
+
+	log_entry = log_buf;
+
+	spin_unlock(&log_lock);
 
 	udbg_printf("EPOW <0x%lx 0x%lx>\n", 
 		    *((unsigned long *)&log_entry), status); 
@@ -157,11 +166,17 @@ ras_error_interrupt(int irq, void *dev_i
 	long status = 0xdeadbeef;
 	int fatal;
 
+	spin_lock(&log_lock);
+
 	status = rtas_call(rtas_token("check-exception"), 6, 1, NULL, 
 			   0x500, irq, 
 			   RTAS_INTERNAL_ERROR, 
 			   1, /* Time Critical */
-			   __pa(&log_entry), size);
+			   __pa(&log_buf), size);
+
+	log_entry = log_buf;
+
+	spin_unlock(&log_lock);
 
 	if ((status == 0) && (log_entry.severity >= SEVERITY_ERROR_SYNC)) 
 		fatal = 1;

_