Commit b7f90a406ff72d6698b619210c205e3375dd099a

Authored by Masato Noguchi
Committed by Paul Mackerras
1 parent b21010ed64

[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>

Showing 2 changed files with 16 additions and 10 deletions Side-by-side Diff

arch/powerpc/platforms/cell/spu_base.c
... ... @@ -236,28 +236,35 @@
236 236 spu_irq_class_0(int irq, void *data)
237 237 {
238 238 struct spu *spu;
  239 + unsigned long stat, mask;
239 240  
240 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 251 spu->stop_callback(spu);
243 252  
  253 + spu_int_stat_clear(spu, 0, stat);
  254 +
244 255 return IRQ_HANDLED;
245 256 }
246 257  
247 258 int
248 259 spu_irq_class_0_bottom(struct spu *spu)
249 260 {
250   - unsigned long stat, mask;
251 261 unsigned long flags;
  262 + unsigned long stat;
252 263  
  264 + spin_lock_irqsave(&spu->register_lock, flags);
  265 + stat = spu->class_0_pending;
253 266 spu->class_0_pending = 0;
254 267  
255   - spin_lock_irqsave(&spu->register_lock, flags);
256   - mask = spu_int_mask_get(spu, 0);
257   - stat = spu_int_stat_get(spu, 0);
258   -
259   - stat &= mask;
260   -
261 268 if (stat & 1) /* invalid DMA alignment */
262 269 __spu_trap_dma_align(spu);
263 270  
... ... @@ -267,7 +274,6 @@
267 274 if (stat & 4) /* error on SPU */
268 275 __spu_trap_error(spu);
269 276  
270   - spu_int_stat_clear(spu, 0, stat);
271 277 spin_unlock_irqrestore(&spu->register_lock, flags);
272 278  
273 279 return (stat & 0x7) ? -EIO : 0;
include/asm-powerpc/spu.h
... ... @@ -130,6 +130,7 @@
130 130 u64 flags;
131 131 u64 dar;
132 132 u64 dsisr;
  133 + u64 class_0_pending;
133 134 size_t ls_size;
134 135 unsigned int slb_replace;
135 136 struct mm_struct *mm;
... ... @@ -138,7 +139,6 @@
138 139 unsigned long long timestamp;
139 140 pid_t pid;
140 141 pid_t tgid;
141   - int class_0_pending;
142 142 spinlock_t register_lock;
143 143  
144 144 void (* wbox_callback)(struct spu *spu);