aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLuke Browning <lukebr@linux.vnet.ibm.com>2008-04-27 14:41:55 -0400
committerJeremy Kerr <jk@ozlabs.org>2008-05-04 23:33:44 -0400
commitf3d69e0507f84903059d456c5d19f10b2df3ac69 (patch)
treef8aa4062bc1a0939d7bdb3a634c01869f2bb32a2
parent7a2142002f29a7b398c49da9bdec712dc57087c7 (diff)
[POWERPC] spufs: fix concurrent delivery of class 0 & 1 exceptions
SPU class 0 & 1 exceptions may occur in parallel, so we may end up overwriting csa.dsisr. This change adds dedicated fields for each class to the spu and the spu context so that fault data is not overwritten. Signed-off-by: Luke Browning <lukebr@linux.vnet.ibm.com> Signed-off-by: Jeremy Kerr <jk@ozlabs.org>
-rw-r--r--arch/powerpc/platforms/cell/spu_base.c27
-rw-r--r--arch/powerpc/platforms/cell/spufs/fault.c17
-rw-r--r--arch/powerpc/platforms/cell/spufs/run.c29
-rw-r--r--arch/powerpc/platforms/cell/spufs/spufs.h2
-rw-r--r--arch/powerpc/xmon/xmon.c6
-rw-r--r--include/asm-powerpc/spu.h8
-rw-r--r--include/asm-powerpc/spu_csa.h3
7 files changed, 60 insertions, 32 deletions
diff --git a/arch/powerpc/platforms/cell/spu_base.c b/arch/powerpc/platforms/cell/spu_base.c
index 6bab44b7716b..b9ae675640d0 100644
--- a/arch/powerpc/platforms/cell/spu_base.c
+++ b/arch/powerpc/platforms/cell/spu_base.c
@@ -226,11 +226,13 @@ static int __spu_trap_data_map(struct spu *spu, unsigned long ea, u64 dsisr)
226 return 0; 226 return 0;
227 } 227 }
228 228
229 spu->class_0_pending = 0; 229 spu->class_1_dar = ea;
230 spu->dar = ea; 230 spu->class_1_dsisr = dsisr;
231 spu->dsisr = dsisr; 231
232 spu->stop_callback(spu, 1);
232 233
233 spu->stop_callback(spu); 234 spu->class_1_dar = 0;
235 spu->class_1_dsisr = 0;
234 236
235 return 0; 237 return 0;
236} 238}
@@ -318,11 +320,15 @@ spu_irq_class_0(int irq, void *data)
318 stat = spu_int_stat_get(spu, 0) & mask; 320 stat = spu_int_stat_get(spu, 0) & mask;
319 321
320 spu->class_0_pending |= stat; 322 spu->class_0_pending |= stat;
321 spu->dsisr = spu_mfc_dsisr_get(spu); 323 spu->class_0_dsisr = spu_mfc_dsisr_get(spu);
322 spu->dar = spu_mfc_dar_get(spu); 324 spu->class_0_dar = spu_mfc_dar_get(spu);
323 spin_unlock(&spu->register_lock); 325 spin_unlock(&spu->register_lock);
324 326
325 spu->stop_callback(spu); 327 spu->stop_callback(spu, 0);
328
329 spu->class_0_pending = 0;
330 spu->class_0_dsisr = 0;
331 spu->class_0_dar = 0;
326 332
327 spu_int_stat_clear(spu, 0, stat); 333 spu_int_stat_clear(spu, 0, stat);
328 334
@@ -363,6 +369,9 @@ spu_irq_class_1(int irq, void *data)
363 if (stat & CLASS1_LS_COMPARE_SUSPEND_ON_PUT_INTR) 369 if (stat & CLASS1_LS_COMPARE_SUSPEND_ON_PUT_INTR)
364 ; 370 ;
365 371
372 spu->class_1_dsisr = 0;
373 spu->class_1_dar = 0;
374
366 return stat ? IRQ_HANDLED : IRQ_NONE; 375 return stat ? IRQ_HANDLED : IRQ_NONE;
367} 376}
368 377
@@ -396,10 +405,10 @@ spu_irq_class_2(int irq, void *data)
396 spu->ibox_callback(spu); 405 spu->ibox_callback(spu);
397 406
398 if (stat & CLASS2_SPU_STOP_INTR) 407 if (stat & CLASS2_SPU_STOP_INTR)
399 spu->stop_callback(spu); 408 spu->stop_callback(spu, 2);
400 409
401 if (stat & CLASS2_SPU_HALT_INTR) 410 if (stat & CLASS2_SPU_HALT_INTR)
402 spu->stop_callback(spu); 411 spu->stop_callback(spu, 2);
403 412
404 if (stat & CLASS2_SPU_DMA_TAG_GROUP_COMPLETE_INTR) 413 if (stat & CLASS2_SPU_DMA_TAG_GROUP_COMPLETE_INTR)
405 spu->mfc_callback(spu); 414 spu->mfc_callback(spu);
diff --git a/arch/powerpc/platforms/cell/spufs/fault.c b/arch/powerpc/platforms/cell/spufs/fault.c
index e46d300e21a5..f093a581ac74 100644
--- a/arch/powerpc/platforms/cell/spufs/fault.c
+++ b/arch/powerpc/platforms/cell/spufs/fault.c
@@ -83,13 +83,18 @@ int spufs_handle_class0(struct spu_context *ctx)
83 return 0; 83 return 0;
84 84
85 if (stat & CLASS0_DMA_ALIGNMENT_INTR) 85 if (stat & CLASS0_DMA_ALIGNMENT_INTR)
86 spufs_handle_event(ctx, ctx->csa.dar, SPE_EVENT_DMA_ALIGNMENT); 86 spufs_handle_event(ctx, ctx->csa.class_0_dar,
87 SPE_EVENT_DMA_ALIGNMENT);
87 88
88 if (stat & CLASS0_INVALID_DMA_COMMAND_INTR) 89 if (stat & CLASS0_INVALID_DMA_COMMAND_INTR)
89 spufs_handle_event(ctx, ctx->csa.dar, SPE_EVENT_INVALID_DMA); 90 spufs_handle_event(ctx, ctx->csa.class_0_dar,
91 SPE_EVENT_INVALID_DMA);
90 92
91 if (stat & CLASS0_SPU_ERROR_INTR) 93 if (stat & CLASS0_SPU_ERROR_INTR)
92 spufs_handle_event(ctx, ctx->csa.dar, SPE_EVENT_SPE_ERROR); 94 spufs_handle_event(ctx, ctx->csa.class_0_dar,
95 SPE_EVENT_SPE_ERROR);
96
97 ctx->csa.class_0_pending = 0;
93 98
94 return -EIO; 99 return -EIO;
95} 100}
@@ -119,8 +124,8 @@ int spufs_handle_class1(struct spu_context *ctx)
119 * in time, we can still expect to get the same fault 124 * in time, we can still expect to get the same fault
120 * the immediately after the context restore. 125 * the immediately after the context restore.
121 */ 126 */
122 ea = ctx->csa.dar; 127 ea = ctx->csa.class_1_dar;
123 dsisr = ctx->csa.dsisr; 128 dsisr = ctx->csa.class_1_dsisr;
124 129
125 if (!(dsisr & (MFC_DSISR_PTE_NOT_FOUND | MFC_DSISR_ACCESS_DENIED))) 130 if (!(dsisr & (MFC_DSISR_PTE_NOT_FOUND | MFC_DSISR_ACCESS_DENIED)))
126 return 0; 131 return 0;
@@ -158,7 +163,7 @@ int spufs_handle_class1(struct spu_context *ctx)
158 * time slicing will not preempt the context while the page fault 163 * time slicing will not preempt the context while the page fault
159 * handler is running. Context switch code removes mappings. 164 * handler is running. Context switch code removes mappings.
160 */ 165 */
161 ctx->csa.dar = ctx->csa.dsisr = 0; 166 ctx->csa.class_1_dar = ctx->csa.class_1_dsisr = 0;
162 167
163 /* 168 /*
164 * If we handled the fault successfully and are in runnable 169 * If we handled the fault successfully and are in runnable
diff --git a/arch/powerpc/platforms/cell/spufs/run.c b/arch/powerpc/platforms/cell/spufs/run.c
index e764a43b544e..b7493b865812 100644
--- a/arch/powerpc/platforms/cell/spufs/run.c
+++ b/arch/powerpc/platforms/cell/spufs/run.c
@@ -11,7 +11,7 @@
11#include "spufs.h" 11#include "spufs.h"
12 12
13/* interrupt-level stop callback function. */ 13/* interrupt-level stop callback function. */
14void spufs_stop_callback(struct spu *spu) 14void spufs_stop_callback(struct spu *spu, int irq)
15{ 15{
16 struct spu_context *ctx = spu->ctx; 16 struct spu_context *ctx = spu->ctx;
17 17
@@ -24,9 +24,19 @@ void spufs_stop_callback(struct spu *spu)
24 */ 24 */
25 if (ctx) { 25 if (ctx) {
26 /* Copy exception arguments into module specific structure */ 26 /* Copy exception arguments into module specific structure */
27 ctx->csa.class_0_pending = spu->class_0_pending; 27 switch(irq) {
28 ctx->csa.dsisr = spu->dsisr; 28 case 0 :
29 ctx->csa.dar = spu->dar; 29 ctx->csa.class_0_pending = spu->class_0_pending;
30 ctx->csa.class_0_dsisr = spu->class_0_dsisr;
31 ctx->csa.class_0_dar = spu->class_0_dar;
32 break;
33 case 1 :
34 ctx->csa.class_1_dsisr = spu->class_1_dsisr;
35 ctx->csa.class_1_dar = spu->class_1_dar;
36 break;
37 case 2 :
38 break;
39 }
30 40
31 /* ensure that the exception status has hit memory before a 41 /* ensure that the exception status has hit memory before a
32 * thread waiting on the context's stop queue is woken */ 42 * thread waiting on the context's stop queue is woken */
@@ -34,11 +44,6 @@ void spufs_stop_callback(struct spu *spu)
34 44
35 wake_up_all(&ctx->stop_wq); 45 wake_up_all(&ctx->stop_wq);
36 } 46 }
37
38 /* Clear callback arguments from spu structure */
39 spu->class_0_pending = 0;
40 spu->dsisr = 0;
41 spu->dar = 0;
42} 47}
43 48
44int spu_stopped(struct spu_context *ctx, u32 *stat) 49int spu_stopped(struct spu_context *ctx, u32 *stat)
@@ -56,7 +61,11 @@ int spu_stopped(struct spu_context *ctx, u32 *stat)
56 if (!(*stat & SPU_STATUS_RUNNING) && (*stat & stopped)) 61 if (!(*stat & SPU_STATUS_RUNNING) && (*stat & stopped))
57 return 1; 62 return 1;
58 63
59 dsisr = ctx->csa.dsisr; 64 dsisr = ctx->csa.class_0_dsisr;
65 if (dsisr & (MFC_DSISR_PTE_NOT_FOUND | MFC_DSISR_ACCESS_DENIED))
66 return 1;
67
68 dsisr = ctx->csa.class_1_dsisr;
60 if (dsisr & (MFC_DSISR_PTE_NOT_FOUND | MFC_DSISR_ACCESS_DENIED)) 69 if (dsisr & (MFC_DSISR_PTE_NOT_FOUND | MFC_DSISR_ACCESS_DENIED))
61 return 1; 70 return 1;
62 71
diff --git a/arch/powerpc/platforms/cell/spufs/spufs.h b/arch/powerpc/platforms/cell/spufs/spufs.h
index dc3a215a6a22..454c277c1457 100644
--- a/arch/powerpc/platforms/cell/spufs/spufs.h
+++ b/arch/powerpc/platforms/cell/spufs/spufs.h
@@ -332,7 +332,7 @@ size_t spu_ibox_read(struct spu_context *ctx, u32 *data);
332/* irq callback funcs. */ 332/* irq callback funcs. */
333void spufs_ibox_callback(struct spu *spu); 333void spufs_ibox_callback(struct spu *spu);
334void spufs_wbox_callback(struct spu *spu); 334void spufs_wbox_callback(struct spu *spu);
335void spufs_stop_callback(struct spu *spu); 335void spufs_stop_callback(struct spu *spu, int irq);
336void spufs_mfc_callback(struct spu *spu); 336void spufs_mfc_callback(struct spu *spu);
337void spufs_dma_callback(struct spu *spu, int type); 337void spufs_dma_callback(struct spu *spu, int type);
338 338
diff --git a/arch/powerpc/xmon/xmon.c b/arch/powerpc/xmon/xmon.c
index 52c74780f403..1702de9395ee 100644
--- a/arch/powerpc/xmon/xmon.c
+++ b/arch/powerpc/xmon/xmon.c
@@ -2842,9 +2842,11 @@ static void dump_spu_fields(struct spu *spu)
2842 DUMP_FIELD(spu, "0x%lx", ls_size); 2842 DUMP_FIELD(spu, "0x%lx", ls_size);
2843 DUMP_FIELD(spu, "0x%x", node); 2843 DUMP_FIELD(spu, "0x%x", node);
2844 DUMP_FIELD(spu, "0x%lx", flags); 2844 DUMP_FIELD(spu, "0x%lx", flags);
2845 DUMP_FIELD(spu, "0x%lx", dar);
2846 DUMP_FIELD(spu, "0x%lx", dsisr);
2847 DUMP_FIELD(spu, "%d", class_0_pending); 2845 DUMP_FIELD(spu, "%d", class_0_pending);
2846 DUMP_FIELD(spu, "0x%lx", class_0_dar);
2847 DUMP_FIELD(spu, "0x%lx", class_0_dsisr);
2848 DUMP_FIELD(spu, "0x%lx", class_1_dar);
2849 DUMP_FIELD(spu, "0x%lx", class_1_dsisr);
2848 DUMP_FIELD(spu, "0x%lx", irqs[0]); 2850 DUMP_FIELD(spu, "0x%lx", irqs[0]);
2849 DUMP_FIELD(spu, "0x%lx", irqs[1]); 2851 DUMP_FIELD(spu, "0x%lx", irqs[1]);
2850 DUMP_FIELD(spu, "0x%lx", irqs[2]); 2852 DUMP_FIELD(spu, "0x%lx", irqs[2]);
diff --git a/include/asm-powerpc/spu.h b/include/asm-powerpc/spu.h
index e3c845b0f764..882aa953968a 100644
--- a/include/asm-powerpc/spu.h
+++ b/include/asm-powerpc/spu.h
@@ -128,9 +128,11 @@ struct spu {
128 unsigned int irqs[3]; 128 unsigned int irqs[3];
129 u32 node; 129 u32 node;
130 u64 flags; 130 u64 flags;
131 u64 dar;
132 u64 dsisr;
133 u64 class_0_pending; 131 u64 class_0_pending;
132 u64 class_0_dar;
133 u64 class_0_dsisr;
134 u64 class_1_dar;
135 u64 class_1_dsisr;
134 size_t ls_size; 136 size_t ls_size;
135 unsigned int slb_replace; 137 unsigned int slb_replace;
136 struct mm_struct *mm; 138 struct mm_struct *mm;
@@ -143,7 +145,7 @@ struct spu {
143 145
144 void (* wbox_callback)(struct spu *spu); 146 void (* wbox_callback)(struct spu *spu);
145 void (* ibox_callback)(struct spu *spu); 147 void (* ibox_callback)(struct spu *spu);
146 void (* stop_callback)(struct spu *spu); 148 void (* stop_callback)(struct spu *spu, int irq);
147 void (* mfc_callback)(struct spu *spu); 149 void (* mfc_callback)(struct spu *spu);
148 150
149 char irq_c0[8]; 151 char irq_c0[8];
diff --git a/include/asm-powerpc/spu_csa.h b/include/asm-powerpc/spu_csa.h
index 0ab6bff86078..129ec148d451 100644
--- a/include/asm-powerpc/spu_csa.h
+++ b/include/asm-powerpc/spu_csa.h
@@ -254,7 +254,8 @@ struct spu_state {
254 u64 spu_chnldata_RW[32]; 254 u64 spu_chnldata_RW[32];
255 u32 spu_mailbox_data[4]; 255 u32 spu_mailbox_data[4];
256 u32 pu_mailbox_data[1]; 256 u32 pu_mailbox_data[1];
257 u64 dar, dsisr, class_0_pending; 257 u64 class_0_dar, class_0_dsisr, class_0_pending;
258 u64 class_1_dar, class_1_dsisr;
258 unsigned long suspend_time; 259 unsigned long suspend_time;
259 spinlock_t register_lock; 260 spinlock_t register_lock;
260}; 261};