[Cbe-oss-dev] [PATCH 3/3] spufs context switch - fix interrupt routing

Luke Browning lukebr at linux.vnet.ibm.com
Sun Apr 13 04:20:14 EST 2008


Fix routing of spu interrupts.

Interrupt routing must be programmed when mfc queue is in a quiescent state, 
either empty or stopped with no pending interrupts.  Otherwise, multiple
cpus could be interrupted for a given spu.  This is problematic for several
reasons.  The state of the mfc queue, the dma restart, needs to be performed
after virtual memory operations take place.  There is nothing to prevent 
concurrent exception handling in the slih and the thread level.  Also,
there is only one set of fields for dealing with exceptions in the csa, so
you could have exception data being over-written while it is being processed.
Many things could go wrong. 

Signed-Off-By: Luke Browning <lukebrowning at us.ibm.com>

---

Index: public_git/arch/powerpc/platforms/cell/spufs/switch.c
===================================================================
--- public_git.orig/arch/powerpc/platforms/cell/spufs/switch.c
+++ public_git/arch/powerpc/platforms/cell/spufs/switch.c
@@ -762,6 +762,7 @@ static inline void enable_interrupts(str
 	spu_int_mask_set(spu, 0, 0ul);
 	spu_int_mask_set(spu, 1, class1_mask);
 	spu_int_mask_set(spu, 2, 0ul);
+	eieio();
 	spin_unlock_irq(&spu->register_lock);
 }
 
@@ -1701,6 +1702,16 @@ static inline void restore_mfc_sr1(struc
 	eieio();
 }
 
+static inline void set_int_route(struct spu_state *csa, struct spu *spu)
+{
+	/*
+	 * FIX ME: this is wrong with asynchronous spu scheduling.  If the
+	 * caller is the time slicer, all interrupts will be steered to
+	 * the same cpu.  It also needs to be made NUMA aware.
+	 */
+	spu_cpu_affinity_set(spu, raw_smp_processor_id());
+}
+
 static inline void restore_other_spu_access(struct spu_state *csa,
 					    struct spu *spu)
 {
@@ -1989,7 +2000,7 @@ static void restore_csa(struct spu_state
 	wait_suspend_mfc_complete(next, spu);	/* Step 47. */
 	issue_mfc_tlbie(next, spu);	        /* Step 48. */
 	clear_interrupts(next, spu);	        /* Step 49. */	/* PENDING */
-	set_switch_pending(next, spu);	        /* Step 74. */
+	set_switch_pending(next, spu);	        /* NEW      */
 	restore_mfc_queues(next, spu);	        /* Step 50. */
 	restore_ppu_querymask(next, spu);	/* Step 51. */
 	restore_ppu_querytype(next, spu);	/* Step 52. */
@@ -2010,11 +2021,12 @@ static void restore_csa(struct spu_state
 	check_ppuint_mb_stat(next, spu);	/* Step 67. */
 	spu_invalidate_slbs(spu);		/* Modified Step 68. */
 	restore_mfc_sr1(next, spu);	        /* Step 69. */
+	set_int_route(next, spu);		/* NEW	    */
 	restore_other_spu_access(next, spu);	/* Step 70. */
 	restore_spu_runcntl(next, spu);	        /* Step 71. */
 	restore_mfc_cntl(next, spu);	        /* Step 72. */
 	enable_user_access(next, spu);	        /* Step 73. */
-	reset_switch_active(next, spu);	        /* Step 74. */
+	reset_switch_active(next, spu);	        /* NEW 	    */
 	reenable_interrupts(next, spu);	        /* Step 75. */	/* ~PENDING */
 }
 
Index: public_git/arch/powerpc/platforms/cell/spufs/sched.c
===================================================================
--- public_git.orig/arch/powerpc/platforms/cell/spufs/sched.c
+++ public_git/arch/powerpc/platforms/cell/spufs/sched.c
@@ -242,7 +242,6 @@ static void spu_bind_context(struct spu 
 	spu_unmap_mappings(ctx);
 	spu_restore(&ctx->csa, spu);
 	spu->timestamp = jiffies;
-	spu_cpu_affinity_set(spu, raw_smp_processor_id());
 	spu_switch_notify(spu, ctx);
 	ctx->state = SPU_STATE_RUNNABLE;
 
Index: public_git/arch/powerpc/platforms/cell/spu_base.c
===================================================================
--- public_git.orig/arch/powerpc/platforms/cell/spu_base.c
+++ public_git/arch/powerpc/platforms/cell/spu_base.c
@@ -315,6 +315,10 @@ spu_irq_class_0(int irq, void *data)
 
 	spu = data;
 
+	BUG_ON(spu->class_0_pending);
+	BUG_ON(spu->dar);
+	BUG_ON(spu->dsisr);
+
 	spin_lock(&spu->register_lock);
 	mask = spu_int_mask_get(spu, 0);
 	stat = spu_int_stat_get(spu, 0) & mask;
@@ -339,6 +343,10 @@ spu_irq_class_1(int irq, void *data)
 
 	spu = data;
 
+	BUG_ON(spu->class_0_pending);
+	BUG_ON(spu->dar);
+	BUG_ON(spu->dsisr);
+
 	/* atomically read & clear class1 status. */
 	spin_lock(&spu->register_lock);
 	mask  = spu_int_mask_get(spu, 1);
@@ -378,6 +386,11 @@ spu_irq_class_2(int irq, void *data)
 		CLASS2_MAILBOX_THRESHOLD_INTR | CLASS2_MAILBOX_INTR;
 
 	spu = data;
+
+	BUG_ON(spu->class_0_pending);
+	BUG_ON(spu->dar);
+	BUG_ON(spu->dsisr);
+
 	spin_lock(&spu->register_lock);
 	stat = spu_int_stat_get(spu, 2);
 	mask = spu_int_mask_get(spu, 2);





More information about the cbe-oss-dev mailing list