[Cbe-oss-dev] [PATCH 1/2] cell: clear SPU class 0 interrupts in handler

Jeremy Kerr jk at ozlabs.org
Fri Sep 7 18:28:27 EST 2007


From: Masato Noguchi <Masato.Noguchi at jp.sony.com>

Fix a bug that causes the PS3 to hang on the SPU Class 0 interrupt.

The Cell BE Architecture spec states that the SPU MFC Class 0 interrupt
is edge-triggered. The current spu interrupt handler assumes this
behavior and does not clear the interrupt status.

The PS3 hypervisor visualizes all SPU interrupts as level, and on return
from the interrupt handler the hypervisor will deliver a new virtual
interrupt for any unmasked interrupts which for which the status has not
been cleared.  This fix clears the interrupt status in the interrupt
handler.

Signed-off-by: Masato Noguchi <Masato.Noguchi at jp.sony.com>
Signed-off-by: Geoff Levand <geoffrey.levand at am.sony.com>
Signed-off-by: Jeremy Kerr <jk at ozlabs.org>
Acked-by: Arnd Bergmann <arnd.bergmann at de.ibm.com>

---
 arch/powerpc/platforms/cell/spu_base.c |   24 +++++++++++++++---------
 include/asm-powerpc/spu.h              |    2 +-
 2 files changed, 16 insertions(+), 10 deletions(-)

diff --git a/arch/powerpc/platforms/cell/spu_base.c b/arch/powerpc/platforms/cell/spu_base.c
index 095a303..106d292 100644
--- a/arch/powerpc/platforms/cell/spu_base.c
+++ b/arch/powerpc/platforms/cell/spu_base.c
@@ -236,27 +236,34 @@ static irqreturn_t
 spu_irq_class_0(int irq, void *data)
 {
 	struct spu *spu;
+	unsigned long stat, mask;
 
 	spu = data;
-	spu->class_0_pending = 1;
+
+	mask = spu_int_mask_get(spu, 0);
+	stat = spu_int_stat_get(spu, 0);
+	stat &= mask;
+
+	spin_lock(&spu->register_lock);
+	spu->class_0_pending |= stat;
+	spin_unlock(&spu->register_lock);
+
 	spu->stop_callback(spu);
 
+	spu_int_stat_clear(spu, 0, stat);
+
 	return IRQ_HANDLED;
 }
 
 int
 spu_irq_class_0_bottom(struct spu *spu)
 {
-	unsigned long stat, mask;
 	unsigned long flags;
-
-	spu->class_0_pending = 0;
+	unsigned long stat;
 
 	spin_lock_irqsave(&spu->register_lock, flags);
-	mask = spu_int_mask_get(spu, 0);
-	stat = spu_int_stat_get(spu, 0);
-
-	stat &= mask;
+	stat = spu->class_0_pending;
+	spu->class_0_pending = 0;
 
 	if (stat & 1) /* invalid DMA alignment */
 		__spu_trap_dma_align(spu);
@@ -267,7 +274,6 @@ spu_irq_class_0_bottom(struct spu *spu)
 	if (stat & 4) /* error on SPU */
 		__spu_trap_error(spu);
 
-	spu_int_stat_clear(spu, 0, stat);
 	spin_unlock_irqrestore(&spu->register_lock, flags);
 
 	return (stat & 0x7) ? -EIO : 0;
diff --git a/include/asm-powerpc/spu.h b/include/asm-powerpc/spu.h
index 8836c0f..5bde398 100644
--- a/include/asm-powerpc/spu.h
+++ b/include/asm-powerpc/spu.h
@@ -130,6 +130,7 @@ struct spu {
 	u64 flags;
 	u64 dar;
 	u64 dsisr;
+	u64 class_0_pending;
 	size_t ls_size;
 	unsigned int slb_replace;
 	struct mm_struct *mm;
@@ -138,7 +139,6 @@ struct spu {
 	unsigned long long timestamp;
 	pid_t pid;
 	pid_t tgid;
-	int class_0_pending;
 	spinlock_t register_lock;
 
 	void (* wbox_callback)(struct spu *spu);



More information about the cbe-oss-dev mailing list