[Cbe-oss-dev] [PATCH 2/2] MARS: kernel scheduler fix overwrite queue block

Yuji Mano Yuji.Mano at am.sony.com
Fri Aug 15 07:26:28 EST 2008


This fixes a bug inside the kernel scheduler that would cause the currently
checked workload queue block to be overwritten by a different workload queue
block if a workload waits for completion of a workload in another workload
queue block.

This also optimizes the checking for workload completion by only fetching the
workload queue block when the workload we are waiting for is in a workload
queue block that is different from the one currently being processed. 

Signed-off-by: Yuji Mano <yuji.mano at am.sony.com>

---
 src/mpu/kernel/mars_kernel_scheduler.c |   77 +++++++++++++++++++--------------
 1 file changed, 46 insertions(+), 31 deletions(-)

--- a/src/mpu/kernel/mars_kernel_scheduler.c
+++ b/src/mpu/kernel/mars_kernel_scheduler.c
@@ -51,7 +51,17 @@ uint64_t workload_ea;
 int reserve_workload(void);
 void release_workload(void);
 
-static int search_block(struct mars_workload_queue_block *block)
+static inline void get_block(int block, struct mars_workload_queue_block *dst)
+{
+	mars_dma_get_and_wait(dst,
+			queue_header.queue_ea +
+			offsetof(struct mars_workload_queue, block) +
+			sizeof(struct mars_workload_queue_block) * block,
+			sizeof(struct mars_workload_queue_block),
+			MARS_DMA_TAG);
+}
+
+static int search_block(int block)
 {
 	int i;
 	int index = -1;
@@ -63,50 +73,55 @@ static int search_block(struct mars_work
 	 * and pick the workload that has been waiting the longest
 	 */
 	for (i = 0; i < MARS_WORKLOAD_PER_BLOCK; i++) {
-		switch (block->state[i]) {
+		struct mars_workload_queue_block *p = &queue_block;
+
+		switch (p->state[i]) {
 		case MARS_WORKLOAD_STATE_READY:
 			/* priority greater than max priority so select */
-			if ((int)block->priority[i] > max_priority) {
+			if ((int)p->priority[i] > max_priority) {
 				index = i;
-				max_count = block->counter[i];
-				max_priority = block->priority[i];
+				max_count = p->counter[i];
+				max_priority = p->priority[i];
 			/* priority equal and wait counter greater so select */
-			} else if ((int)block->priority[i] == max_priority &&
-				(int)block->counter[i] > max_count) {
+			} else if ((int)p->priority[i] == max_priority &&
+				(int)p->counter[i] > max_count) {
 				index = i;
-				max_count = block->counter[i];
+				max_count = p->counter[i];
 			}
 			/* increment wait counter without overflowing */
-			if (block->counter[i] < MARS_WORKLOAD_COUNTER_MAX)
-				block->counter[i]++;
+			if (p->counter[i] < MARS_WORKLOAD_COUNTER_MAX)
+				p->counter[i]++;
 			break;
 		case MARS_WORKLOAD_STATE_WAITING:
 			/* waiting for workload to finish so check status */
-			if (block->wait[i] != MARS_WORKLOAD_ID_NONE) {
-				int bl = block->wait[i]/MARS_WORKLOAD_PER_BLOCK;
-				int id = block->wait[i]%MARS_WORKLOAD_PER_BLOCK;
-
-				/* fetch the necessary workload block */
-				mars_dma_get_and_wait(&queue_block,
-				  queue_header.queue_ea +
-				  offsetof(struct mars_workload_queue, block) +
-				  sizeof(struct mars_workload_queue_block) * bl,
-				  sizeof(struct mars_workload_queue_block),
-				  MARS_DMA_TAG);
+			if (p->wait[i] != MARS_WORKLOAD_ID_NONE) {
+				struct mars_workload_queue_block wait_block;
+				struct mars_workload_queue_block *p_wait_block;
+
+				int bl = p->wait[i] / MARS_WORKLOAD_PER_BLOCK;
+				int id = p->wait[i] % MARS_WORKLOAD_PER_BLOCK;
+
+				/* check if workload id is in the same block */
+				if (block != bl) {
+					/* fetch the necessary block */
+					get_block(bl, &wait_block);
+					/* set pointer to check fetched block */
+					p_wait_block = &wait_block;
+				} else {
+					/* set pointer to check current block */
+					p_wait_block = p;
+				}
 
 				/* check if workload is finished and reset */
-				if (queue_block.state[id] ==
+				if (p_wait_block->state[id] ==
 					MARS_WORKLOAD_STATE_FINISHED) {
-					block->wait[i] =
-						MARS_WORKLOAD_ID_NONE;
-					block->state[i] =
-						MARS_WORKLOAD_STATE_READY;
+					p->wait[i] = MARS_WORKLOAD_ID_NONE;
+					p->state[i] = MARS_WORKLOAD_STATE_READY;
 				}
 			/* waiting for signal so check signal bit and reset */
-			} else if (block->signal[i] ==
-				MARS_WORKLOAD_SIGNAL_ON) {
-				block->signal[i] = MARS_WORKLOAD_SIGNAL_OFF;
-				block->state[i] = MARS_WORKLOAD_STATE_READY;
+			} else if (p->signal[i] == MARS_WORKLOAD_SIGNAL_ON) {
+				p->signal[i] = MARS_WORKLOAD_SIGNAL_OFF;
+				p->state[i] = MARS_WORKLOAD_STATE_READY;
 				i--;
 			}
 			break;
@@ -135,7 +150,7 @@ static int reserve_block(int block)
 			sizeof(struct mars_workload_queue_block) * block);
 
 		/* set the workload index */
-		index = search_block(&queue_block);
+		index = search_block(block);
 		if (index >= 0) {
 			/* update the current state of the workload */
 			queue_block.state[index] = MARS_WORKLOAD_STATE_RUNNING;





More information about the cbe-oss-dev mailing list