[Cbe-oss-dev] [PATCH 10:11] spufs: fix interaction between spu exception handling and time slicing

Luke Browning lukebr at linux.vnet.ibm.com
Fri May 23 06:11:11 EST 2008


Fix interaction between spu exception handling and time slicing 

Time slicing can occur atthe same time as spu exception handling
resulting in the wakeup of the wrong thread.  Add locking to spu bind / unbind
and spu exception handling so that they are mutually exclusive.

Signed-off-by: Luke Browning <lukebrowning at us.ibm.com>

---

Index: linux-2.6.25/arch/powerpc/platforms/cell/spu_base.c
===================================================================
--- linux-2.6.25.orig/arch/powerpc/platforms/cell/spu_base.c
+++ linux-2.6.25/arch/powerpc/platforms/cell/spu_base.c
@@ -219,15 +219,25 @@ static int __spu_trap_data_seg(struct sp
 extern int hash_page(unsigned long ea, unsigned long access, unsigned long trap); //XXX
 static int __spu_trap_data_map(struct spu *spu, unsigned long ea, u64 dsisr)
 {
+	int ret;
+
 	pr_debug("%s, %lx, %lx\n", __func__, dsisr, ea);
 
-	/* Handle kernel space hash faults immediately.
-	   User hash faults need to be deferred to process context. */
-	if ((dsisr & MFC_DSISR_PTE_NOT_FOUND)
-	    && REGION_ID(ea) != USER_REGION_ID
-	    && hash_page(ea, _PAGE_PRESENT, 0x300) == 0) {
-		spu_restart_dma(spu);
-		return 0;
+	/*
+	 * Handle kernel space hash faults immediately. User hash
+	 * faults need to be deferred to process context.
+	 */
+	if ((dsisr & MFC_DSISR_PTE_NOT_FOUND) &&
+	    (REGION_ID(ea) != USER_REGION_ID)) {
+
+		spin_unlock(&spu->register_lock);
+		ret = hash_page(ea, _PAGE_PRESENT, 0x300);
+		spin_lock(&spu->register_lock);
+
+		if (!ret) {
+			spu_restart_dma(spu);
+			return 0;
+		}
 	}
 
 	spu->class_1_dar = ea;
@@ -325,14 +335,12 @@ spu_irq_class_0(int irq, void *data)
 
 	spu->class_0_pending |= stat;
 	spu->class_0_dar = spu_mfc_dar_get(spu);
-	spin_unlock(&spu->register_lock);
-
 	spu->stop_callback(spu, 0);
-
 	spu->class_0_pending = 0;
 	spu->class_0_dar = 0;
 
 	spu_int_stat_clear(spu, 0, stat);
+	spin_unlock(&spu->register_lock);
 
 	return IRQ_HANDLED;
 }
@@ -355,13 +363,12 @@ spu_irq_class_1(int irq, void *data)
 		spu_mfc_dsisr_set(spu, 0ul);
 	spu_int_stat_clear(spu, 1, stat);
 
-	if (stat & CLASS1_SEGMENT_FAULT_INTR)
-		__spu_trap_data_seg(spu, dar);
-
-	spin_unlock(&spu->register_lock);
 	pr_debug("%s: %lx %lx %lx %lx\n", __func__, mask, stat,
 			dar, dsisr);
 
+	if (stat & CLASS1_SEGMENT_FAULT_INTR)
+		__spu_trap_data_seg(spu, dar);
+
 	if (stat & CLASS1_STORAGE_FAULT_INTR)
 		__spu_trap_data_map(spu, dar, dsisr);
 
@@ -371,6 +378,8 @@ spu_irq_class_1(int irq, void *data)
 	if (stat & CLASS1_LS_COMPARE_SUSPEND_ON_PUT_INTR)
 		;
 
+	spin_unlock(&spu->register_lock);
+
 	return stat ? IRQ_HANDLED : IRQ_NONE;
 }
 
@@ -389,14 +398,12 @@ spu_irq_class_2(int irq, void *data)
 	mask = spu_int_mask_get(spu, 2);
 	/* ignore interrupts we're not waiting for */
 	stat &= mask;
-
 	/* mailbox interrupts are level triggered. mask them now before
 	 * acknowledging */
 	if (stat & mailbox_intrs)
 		spu_int_mask_and(spu, 2, ~(stat & mailbox_intrs));
 	/* acknowledge all interrupts before the callbacks */
 	spu_int_stat_clear(spu, 2, stat);
-	spin_unlock(&spu->register_lock);
 
 	pr_debug("class 2 interrupt %d, %lx, %lx\n", irq, stat, mask);
 
@@ -416,6 +423,9 @@ spu_irq_class_2(int irq, void *data)
 		spu->wbox_callback(spu);
 
 	spu->stats.class2_intr++;
+
+	spin_unlock(&spu->register_lock);
+
 	return stat ? IRQ_HANDLED : IRQ_NONE;
 }
 
Index: linux-2.6.25/arch/powerpc/platforms/cell/spufs/sched.c
===================================================================
--- linux-2.6.25.orig/arch/powerpc/platforms/cell/spufs/sched.c
+++ linux-2.6.25/arch/powerpc/platforms/cell/spufs/sched.c
@@ -230,19 +230,23 @@ static void spu_bind_context(struct spu 
 	ctx->stats.slb_flt_base = spu->stats.slb_flt;
 	ctx->stats.class2_intr_base = spu->stats.class2_intr;
 
+	spu_associate_mm(spu, ctx->owner);
+
+	spin_lock_irq(&spu->register_lock);
 	spu->ctx = ctx;
 	spu->flags = 0;
 	ctx->spu = spu;
 	ctx->ops = &spu_hw_ops;
 	spu->pid = current->pid;
 	spu->tgid = current->tgid;
-	spu_associate_mm(spu, ctx->owner);
 	spu->ibox_callback = spufs_ibox_callback;
 	spu->wbox_callback = spufs_wbox_callback;
 	spu->stop_callback = spufs_stop_callback;
 	spu->mfc_callback = spufs_mfc_callback;
-	mb();
+	spin_unlock_irq(&spu->register_lock);
+
 	spu_unmap_mappings(ctx);
+
 	spu_switch_log_notify(spu, ctx, SWITCH_LOG_START, 0);
 	spu_restore(&ctx->csa, spu);
 	spu->timestamp = jiffies;
@@ -423,18 +427,22 @@ static void spu_unbind_context(struct sp
 	spu_unmap_mappings(ctx);
 	spu_save(&ctx->csa, spu);
 	spu_switch_log_notify(spu, ctx, SWITCH_LOG_STOP, 0);
+
+	spin_lock_irq(&spu->register_lock);
 	spu->timestamp = jiffies;
 	ctx->state = SPU_STATE_SAVED;
 	spu->ibox_callback = NULL;
 	spu->wbox_callback = NULL;
 	spu->stop_callback = NULL;
 	spu->mfc_callback = NULL;
-	spu_associate_mm(spu, NULL);
 	spu->pid = 0;
 	spu->tgid = 0;
 	ctx->ops = &spu_backing_ops;
 	spu->flags = 0;
 	spu->ctx = NULL;
+	spin_unlock_irq(&spu->register_lock);
+
+	spu_associate_mm(spu, NULL);
 
 	ctx->stats.slb_flt +=
 		(spu->stats.slb_flt - ctx->stats.slb_flt_base);





More information about the cbe-oss-dev mailing list