aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMasato Noguchi <Masato.Noguchi@jp.sony.com>2007-09-07 04:28:27 -0400
committerPaul Mackerras <paulus@samba.org>2007-09-10 14:30:36 -0400
commitb7f90a406ff72d6698b619210c205e3375dd099a (patch)
tree04897cefacd9589699f99dcd50f6469a9cab687f
parentb21010ed6498391c0f359f2a89c907533fe07fec (diff)
[POWERPC] cell/PS3: 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@jp.sony.com> Signed-off-by: Geoff Levand <geoffrey.levand@am.sony.com> Signed-off-by: Jeremy Kerr <jk@ozlabs.org> Acked-by: Arnd Bergmann <arnd.bergmann@de.ibm.com> Signed-off-by: Paul Mackerras <paulus@samba.org>
-rw-r--r--arch/powerpc/platforms/cell/spu_base.c24
-rw-r--r--include/asm-powerpc/spu.h2
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 095a30304c56..106d2921e2d9 100644
--- a/arch/powerpc/platforms/cell/spu_base.c
+++ b/arch/powerpc/platforms/cell/spu_base.c
@@ -236,27 +236,34 @@ static irqreturn_t
236spu_irq_class_0(int irq, void *data) 236spu_irq_class_0(int irq, void *data)
237{ 237{
238 struct spu *spu; 238 struct spu *spu;
239 unsigned long stat, mask;
239 240
240 spu = data; 241 spu = data;
241 spu->class_0_pending = 1; 242
243 mask = spu_int_mask_get(spu, 0);
244 stat = spu_int_stat_get(spu, 0);
245 stat &= mask;
246
247 spin_lock(&spu->register_lock);
248 spu->class_0_pending |= stat;
249 spin_unlock(&spu->register_lock);
250
242 spu->stop_callback(spu); 251 spu->stop_callback(spu);
243 252
253 spu_int_stat_clear(spu, 0, stat);
254
244 return IRQ_HANDLED; 255 return IRQ_HANDLED;
245} 256}
246 257
247int 258int
248spu_irq_class_0_bottom(struct spu *spu) 259spu_irq_class_0_bottom(struct spu *spu)
249{ 260{
250 unsigned long stat, mask;
251 unsigned long flags; 261 unsigned long flags;
252 262 unsigned long stat;
253 spu->class_0_pending = 0;
254 263
255 spin_lock_irqsave(&spu->register_lock, flags); 264 spin_lock_irqsave(&spu->register_lock, flags);
256 mask = spu_int_mask_get(spu, 0); 265 stat = spu->class_0_pending;
257 stat = spu_int_stat_get(spu, 0); 266 spu->class_0_pending = 0;
258
259 stat &= mask;
260 267
261 if (stat & 1) /* invalid DMA alignment */ 268 if (stat & 1) /* invalid DMA alignment */
262 __spu_trap_dma_align(spu); 269 __spu_trap_dma_align(spu);
@@ -267,7 +274,6 @@ spu_irq_class_0_bottom(struct spu *spu)
267 if (stat & 4) /* error on SPU */ 274 if (stat & 4) /* error on SPU */
268 __spu_trap_error(spu); 275 __spu_trap_error(spu);
269 276
270 spu_int_stat_clear(spu, 0, stat);
271 spin_unlock_irqrestore(&spu->register_lock, flags); 277 spin_unlock_irqrestore(&spu->register_lock, flags);
272 278
273 return (stat & 0x7) ? -EIO : 0; 279 return (stat & 0x7) ? -EIO : 0;
diff --git a/include/asm-powerpc/spu.h b/include/asm-powerpc/spu.h
index 8836c0f1f2f7..5bde3980bf49 100644
--- a/include/asm-powerpc/spu.h
+++ b/include/asm-powerpc/spu.h
@@ -130,6 +130,7 @@ struct spu {
130 u64 flags; 130 u64 flags;
131 u64 dar; 131 u64 dar;
132 u64 dsisr; 132 u64 dsisr;
133 u64 class_0_pending;
133 size_t ls_size; 134 size_t ls_size;
134 unsigned int slb_replace; 135 unsigned int slb_replace;
135 struct mm_struct *mm; 136 struct mm_struct *mm;
@@ -138,7 +139,6 @@ struct spu {
138 unsigned long long timestamp; 139 unsigned long long timestamp;
139 pid_t pid; 140 pid_t pid;
140 pid_t tgid; 141 pid_t tgid;
141 int class_0_pending;
142 spinlock_t register_lock; 142 spinlock_t register_lock;
143 143
144 void (* wbox_callback)(struct spu *spu); 144 void (* wbox_callback)(struct spu *spu);