[Cbe-oss-dev] PATCH [4/4] spusched: rework class0 and class1 exception handling

Luke Browning lukebr at linux.vnet.ibm.com
Sat Oct 27 00:24:54 EST 2007


Re-work spu exception handling such that the spu does not have to
be loaded. This should improve the concurrency of the spu scheduling
leading to greater spu utilization, when spus are overcommited.

Signed-off-by: Luke Browning <lukebr at linux.vnet.ibm.com>

---

Index: linux-2.6.22/arch/powerpc/platforms/cell/spu_base.c
===================================================================
--- linux-2.6.22.orig/arch/powerpc/platforms/cell/spu_base.c	2007-10-21 13:17:40.000000000 -0300
+++ linux-2.6.22/arch/powerpc/platforms/cell/spu_base.c	2007-10-26 10:24:10.000000000 -0300
@@ -114,27 +114,6 @@
 }
 EXPORT_SYMBOL_GPL(spu_associate_mm);
 
-static int __spu_trap_invalid_dma(struct spu *spu)
-{
-	pr_debug("%s\n", __FUNCTION__);
-	spu->dma_callback(spu, SPE_EVENT_INVALID_DMA);
-	return 0;
-}
-
-static int __spu_trap_dma_align(struct spu *spu)
-{
-	pr_debug("%s\n", __FUNCTION__);
-	spu->dma_callback(spu, SPE_EVENT_DMA_ALIGNMENT);
-	return 0;
-}
-
-static int __spu_trap_error(struct spu *spu)
-{
-	pr_debug("%s\n", __FUNCTION__);
-	spu->dma_callback(spu, SPE_EVENT_SPE_ERROR);
-	return 0;
-}
-
 static void spu_restart_dma(struct spu *spu)
 {
 	struct spu_priv2 __iomem *priv2 = spu->priv2;
@@ -225,10 +204,12 @@
 		return 1;
 	}
 
+	spu->class_0_pending = 0;
 	spu->dar = ea;
 	spu->dsisr = dsisr;
-	mb();
+
 	spu->stop_callback(spu);
+
 	return 0;
 }
 
@@ -246,6 +227,8 @@
 
 	spin_lock(&spu->register_lock);
 	spu->class_0_pending |= stat;
+	spu->dsisr = spu_mfc_dsisr_get(spu);
+	spu->dar = spu_mfc_dar_get(spu);
 	spin_unlock(&spu->register_lock);
 
 	spu->stop_callback(spu);
@@ -255,32 +238,6 @@
 	return IRQ_HANDLED;
 }
 
-int
-spu_irq_class_0_bottom(struct spu *spu)
-{
-	unsigned long flags;
-	unsigned long stat;
-
-	spin_lock_irqsave(&spu->register_lock, flags);
-	stat = spu->class_0_pending;
-	spu->class_0_pending = 0;
-
-	if (stat & 1) /* invalid DMA alignment */
-		__spu_trap_dma_align(spu);
-
-	if (stat & 2) /* invalid MFC DMA */
-		__spu_trap_invalid_dma(spu);
-
-	if (stat & 4) /* error on SPU */
-		__spu_trap_error(spu);
-
-	spu_int_stat_clear(spu, 0, stat);
-	spin_unlock_irqrestore(&spu->register_lock, flags);
-
-	return (stat & 0x7) ? -EIO : 0;
-}
-EXPORT_SYMBOL_GPL(spu_irq_class_0_bottom);
-
 static irqreturn_t
 spu_irq_class_1(int irq, void *data)
 {
Index: linux-2.6.22/arch/powerpc/platforms/cell/spufs/fault.c
===================================================================
--- linux-2.6.22.orig/arch/powerpc/platforms/cell/spufs/fault.c	2007-10-21 13:17:32.000000000 -0300
+++ linux-2.6.22/arch/powerpc/platforms/cell/spufs/fault.c	2007-10-26 10:25:53.000000000 -0300
@@ -136,11 +136,24 @@
 	}
 }
 
-void spufs_dma_callback(struct spu *spu, int type)
+int spu_handle_class0(struct spu_context *ctx)
 {
-	spufs_handle_dma_error(spu->ctx, spu->dar, type);
+	unsigned long stat = ctx->csa.class_0_pending;
+	unsigned long dar = ctx->csa.dar;
+
+	if (stat & 1) /* invalid DMA alignment */
+		spufs_handle_dma_error(ctx, dar, SPE_EVENT_DMA_ALIGNMENT);
+
+	if (stat & 2) /* invalid MFC DMA */
+		spufs_handle_dma_error(ctx, dar, SPE_EVENT_INVALID_DMA);
+
+	if (stat & 4) /* error on SPU */
+		spufs_handle_dma_error(ctx, dar, SPE_EVENT_SPE_ERROR);
+
+	ctx->csa.class_0_pending = 0;
+
+	return (stat & 0x7) ? -EIO : 0;
 }
-EXPORT_SYMBOL_GPL(spufs_dma_callback);
 
 /*
  * bottom half handler for page faults, we can't do this from
@@ -151,7 +164,7 @@
  * TODO: try calling hash_page from the interrupt handler first
  *       in order to speed up the easy case.
  */
-int spufs_handle_class1(struct spu_context *ctx)
+int spu_handle_class1(struct spu_context *ctx)
 {
 	u64 ea, dsisr, access;
 	unsigned long flags;
@@ -167,16 +180,9 @@
 	 * in time, we can still expect to get the same fault
 	 * the immediately after the context restore.
 	 */
-	if (ctx->state == SPU_STATE_RUNNABLE) {
-		ea = ctx->spu->dar;
-		dsisr = ctx->spu->dsisr;
-		ctx->spu->dar= ctx->spu->dsisr = 0;
-	} else {
-		ea = ctx->csa.priv1.mfc_dar_RW;
-		dsisr = ctx->csa.priv1.mfc_dsisr_RW;
-		ctx->csa.priv1.mfc_dar_RW = 0;
-		ctx->csa.priv1.mfc_dsisr_RW = 0;
-	}
+	ea = ctx->csa.dar;
+	dsisr = ctx->csa.dsisr;
+	ctx->csa.dar = ctx->csa.dsisr = 0;
 
 	if (!(dsisr & (MFC_DSISR_PTE_NOT_FOUND | MFC_DSISR_ACCESS_DENIED)))
 		return 0;
@@ -229,4 +235,3 @@
 	spuctx_switch_state(ctx, SPUCTX_UTIL_SYSTEM);
 	return ret;
 }
-EXPORT_SYMBOL_GPL(spufs_handle_class1);
Index: linux-2.6.22/arch/powerpc/platforms/cell/spufs/run.c
===================================================================
--- linux-2.6.22.orig/arch/powerpc/platforms/cell/spufs/run.c	2007-10-23 20:42:22.000000000 -0300
+++ linux-2.6.22/arch/powerpc/platforms/cell/spufs/run.c	2007-10-26 11:10:08.000000000 -0300
@@ -15,39 +15,50 @@
 {
 	struct spu_context *ctx = spu->ctx;
 
-	wake_up_all(&ctx->stop_wq);
+	/*
+	 * It should be impossible to preempt a context while an exception
+	 * is being processed, since the context switch code is specially
+	 * coded to deal with interrupts ... But, just in case, sanity check
+	 * the context pointer.  It is OK to return doing nothing since
+	 * the exception will be regenerated when the context is resumed.
+	 */
+	if (ctx) {
+		/* Copy exception arguments into module specific structure */
+		ctx->csa.class_0_pending = spu->class_0_pending;
+		ctx->csa.dsisr = spu->dsisr;
+		ctx->csa.dar = spu->dar;
+
+		wake_up_all(&ctx->stop_wq);
+	}
+
+	/* Clear callback arguments from spu structure */
+	spu->class_0_pending = 0;
+	spu->dsisr = 0;
+	spu->dar = 0;
 }
 
 static inline int spu_stopped(struct spu_context *ctx, u32 * stat)
 {
-	struct spu *spu;
-	u64 pte_fault, dsisr;
+	u64 dsisr;
 	u32 stopped;
 
+	*stat = ctx->ops->status_read(ctx);
+
 	if (test_bit(SPU_SCHED_NOTIFY_ACTIVE, &ctx->sched_flags))
 		return 1;
 
 	stopped = SPU_STATUS_INVALID_INSTR | SPU_STATUS_SINGLE_STEP |
 		SPU_STATUS_STOPPED_BY_HALT | SPU_STATUS_STOPPED_BY_STOP;
-
-	*stat = ctx->ops->status_read(ctx);
 	if (*stat & stopped)
 		return 1;
 
-	if (ctx->spu)
-		dsisr = ctx->spu->dsisr;
-	else
-		dsisr = ctx->csa.priv1.mfc_dsisr_RW;
-
-	pte_fault = dsisr & (MFC_DSISR_PTE_NOT_FOUND | MFC_DSISR_ACCESS_DENIED);
-	if (pte_fault)
+	dsisr = ctx->csa.dsisr;
+	if (dsisr & (MFC_DSISR_PTE_NOT_FOUND | MFC_DSISR_ACCESS_DENIED))
 		return 1;
 
-	spu = ctx->spu;
-	if (!spu)
-		return 0;
-	if (spu->class_0_pending)
+	if (ctx->csa.class_0_pending)
 		return 1;
+
 	return 0;
 }
 
@@ -220,9 +231,6 @@
 	spuctx_switch_state(ctx, SPUCTX_UTIL_LOADED);
 	spu_release(ctx);
 
-	if (signal_pending(current))
-		ret = -ERESTARTSYS;
-
 	return ret;
 }
 
@@ -330,15 +338,28 @@
 	return ret;
 }
 
-static inline int spu_process_events(struct spu_context *ctx)
+static inline int spu_handle_class0_events(struct spu_context *ctx)
 {
-	struct spu *spu = ctx->spu;
 	int ret = 0;
+	u64 stat = ctx->csa.class_0_pending;
+
+	if (stat) {
+		if (ctx->flags & SPU_CREATE_EVENTS_ENABLED) {
+			if (stat & 1) 		/* invalid DMA alignment */
+				ctx->event_return |= SPE_EVENT_DMA_ALIGNMENT;
+
+			if (stat & 2) 		/* invalid MFC DMA */
+				ctx->event_return |= SPE_EVENT_INVALID_DMA;
+
+			if (stat & 4) 		/* error on SPU */
+				ctx->event_return |= SPE_EVENT_SPE_ERROR;
+
+			wake_up_all(&ctx->stop_wq);
+		} else {
+			ret = spu_handle_class0(ctx);
+		}
+	}
 
-	if (spu->class_0_pending)
-		ret = spu_irq_class_0_bottom(spu);
-	if (!ret && signal_pending(current))
-		ret = -ERESTARTSYS;
 	return ret;
 }
 
@@ -381,6 +402,7 @@
 				continue;
 			}
 		}
+
 		if ((status & SPU_STATUS_STOPPED_BY_STOP) &&
 		    (status >> SPU_STOP_STATUS_SHIFT == 0x2104)) {
 			ret = spu_process_callback(ctx);
@@ -388,21 +410,31 @@
 				break;
 			status &= ~SPU_STATUS_STOPPED_BY_STOP;
 		}
-		ret = spufs_handle_class1(ctx);
+
+		ret = spu_handle_class1(ctx);
+		if (ret)
+			break;
+
+		ret = spu_handle_class0_events(ctx);
 		if (ret)
 			break;
 
+		if (status & (SPU_STATUS_STOPPED_BY_STOP |
+			      SPU_STATUS_STOPPED_BY_HALT |
+			      SPU_STATUS_SINGLE_STEP))
+			break;
+
+		if (signal_pending(current)) {
+			ret = -ERESTARTSYS;
+			break;
+		}
+
 		if (unlikely(ctx->state != SPU_STATE_RUNNABLE)) {
 			ret = spu_reacquire_runnable(ctx, npc, &status);
 			if (ret)
 				goto out2;
-			continue;
 		}
-		ret = spu_process_events(ctx);
-
-	} while (!ret && !(status & (SPU_STATUS_STOPPED_BY_STOP |
-				      SPU_STATUS_STOPPED_BY_HALT |
-				       SPU_STATUS_SINGLE_STEP)));
+	} while (1);
 
 	if ((status & SPU_STATUS_STOPPED_BY_STOP) &&
 	    (((status >> SPU_STOP_STATUS_SHIFT) & 0x3f00) == 0x2100) &&
Index: linux-2.6.22/arch/powerpc/platforms/cell/spufs/sched.c
===================================================================
--- linux-2.6.22.orig/arch/powerpc/platforms/cell/spufs/sched.c	2007-10-23 20:42:22.000000000 -0300
+++ linux-2.6.22/arch/powerpc/platforms/cell/spufs/sched.c	2007-10-26 10:51:25.000000000 -0300
@@ -400,7 +400,6 @@
 	spu->wbox_callback = spufs_wbox_callback;
 	spu->stop_callback = spufs_stop_callback;
 	spu->mfc_callback = spufs_mfc_callback;
-	spu->dma_callback = spufs_dma_callback;
 	mb();
 	spu_unmap_mappings(ctx);
 	spu_restore(&ctx->csa, spu);
@@ -443,7 +442,6 @@
 	spu->wbox_callback = NULL;
 	spu->stop_callback = NULL;
 	spu->mfc_callback = NULL;
-	spu->dma_callback = NULL;
 	spu_associate_mm(spu, NULL);
 	spu->pid = 0;
 	spu->tgid = 0;
Index: linux-2.6.22/arch/powerpc/platforms/cell/spufs/spufs.h
===================================================================
--- linux-2.6.22.orig/arch/powerpc/platforms/cell/spufs/spufs.h	2007-10-22 14:16:21.000000000 -0300
+++ linux-2.6.22/arch/powerpc/platforms/cell/spufs/spufs.h	2007-10-25 19:36:06.000000000 -0300
@@ -232,7 +232,8 @@
 void spu_gang_add_ctx(struct spu_gang *gang, struct spu_context *ctx);
 
 /* fault handling */
-int spufs_handle_class1(struct spu_context *ctx);
+int spu_handle_class1(struct spu_context *ctx);
+int spu_handle_class0(struct spu_context *ctx);
 
 /* affinity */
 struct spu *affinity_check(struct spu_context *ctx);
Index: linux-2.6.22/arch/powerpc/platforms/cell/spufs/switch.c
===================================================================
--- linux-2.6.22.orig/arch/powerpc/platforms/cell/spufs/switch.c	2007-10-21 13:17:38.000000000 -0300
+++ linux-2.6.22/arch/powerpc/platforms/cell/spufs/switch.c	2007-10-26 11:12:03.000000000 -0300
@@ -2103,10 +2103,6 @@
 	int rc;
 
 	acquire_spu_lock(spu);	        /* Step 1.     */
-	prev->dar = spu->dar;
-	prev->dsisr = spu->dsisr;
-	spu->dar = 0;
-	spu->dsisr = 0;
 	rc = __do_spu_save(prev, spu);	/* Steps 2-53. */
 	release_spu_lock(spu);
 	if (rc != 0 && rc != 2 && rc != 6) {
@@ -2133,9 +2129,6 @@
 	acquire_spu_lock(spu);
 	harvest(NULL, spu);
 	spu->slb_replace = 0;
-	new->dar = 0;
-	new->dsisr = 0;
-	spu->class_0_pending = 0;
 	rc = __do_spu_restore(new, spu);
 	release_spu_lock(spu);
 	if (rc) {
Index: linux-2.6.22/include/asm-powerpc/spu.h
===================================================================
--- linux-2.6.22.orig/include/asm-powerpc/spu.h	2007-10-21 13:17:40.000000000 -0300
+++ linux-2.6.22/include/asm-powerpc/spu.h	2007-10-25 19:36:06.000000000 -0300
@@ -151,7 +151,6 @@
 	void (* ibox_callback)(struct spu *spu);
 	void (* stop_callback)(struct spu *spu);
 	void (* mfc_callback)(struct spu *spu);
-	void (* dma_callback)(struct spu *spu, int type);
 
 	char irq_c0[8];
 	char irq_c1[8];
@@ -202,8 +201,6 @@
 extern struct cbe_spu_info cbe_spu_info[];
 
 void spu_init_channels(struct spu *spu);
-int spu_irq_class_0_bottom(struct spu *spu);
-int spu_irq_class_1_bottom(struct spu *spu);
 void spu_irq_setaffinity(struct spu *spu, int cpu);
 
 #ifdef CONFIG_KEXEC
Index: linux-2.6.22/include/asm-powerpc/spu_csa.h
===================================================================
--- linux-2.6.22.orig/include/asm-powerpc/spu_csa.h	2007-10-21 13:17:37.000000000 -0300
+++ linux-2.6.22/include/asm-powerpc/spu_csa.h	2007-10-25 19:36:06.000000000 -0300
@@ -254,7 +254,7 @@
 	u64 spu_chnldata_RW[32];
 	u32 spu_mailbox_data[4];
 	u32 pu_mailbox_data[1];
-	u64 dar, dsisr;
+	u64 dar, dsisr, class_0_pending;
 	unsigned long suspend_time;
 	spinlock_t register_lock;
 };
Index: linux-2.6.22/arch/powerpc/platforms/cell/spufs/file.c
===================================================================
--- linux-2.6.22.orig/arch/powerpc/platforms/cell/spufs/file.c	2007-10-26 10:44:30.000000000 -0300
+++ linux-2.6.22/arch/powerpc/platforms/cell/spufs/file.c	2007-10-26 10:50:15.000000000 -0300
@@ -572,6 +572,9 @@
 {
 	struct spu_context *ctx = spu->ctx;
 
+	if (!ctx)
+		return;
+
 	wake_up_all(&ctx->ibox_wq);
 	kill_fasync(&ctx->ibox_fasync, SIGIO, POLLIN);
 }
@@ -708,6 +711,9 @@
 {
 	struct spu_context *ctx = spu->ctx;
 
+	if (!ctx)
+		return;
+
 	wake_up_all(&ctx->wbox_wq);
 	kill_fasync(&ctx->wbox_fasync, SIGIO, POLLOUT);
 }
@@ -1320,6 +1326,9 @@
 {
 	struct spu_context *ctx = spu->ctx;
 
+	if (!ctx)
+		return;
+
 	wake_up_all(&ctx->mfc_wq);
 
 	pr_debug("%s %s\n", __FUNCTION__, spu->name);





More information about the cbe-oss-dev mailing list