[Cbe-oss-dev] [patch 07/10] spufs: add kernel support for spu task

Sebastian Siewior cbe-oss-dev at ml.breakpoint.cc
Wed Aug 29 23:35:41 EST 2007


* Arnd Bergmann | 2007-08-18 18:48:34 [+0200]:

>On Thursday 16 August 2007, Sebastian Siewior wrote:
>
>> +config KSPU
>> +	bool "Support for utilisation of SPU by the kernel"
>> +	depends on SPU_FS && EXPERIMENTAL
>> +	help
>> +	  With this option enabled, the kernel is able to utilize the SPUs for its
>> +	  own tasks.
>
>
>It might be better to not have this user-selectable at all, but to
>autoselect the option when it's used by other code.
okey

>> +out_archcoredump:
>> +	printk("kspu_init() failed\n");
>> +	unregister_arch_coredump_calls(&spufs_coredump_calls);
>>  out_syscalls:
>>  	unregister_spu_syscalls(&spufs_calls);
>>  out_fs:
>> @@ -804,12 +811,14 @@ out_sched:
>>  out_cache:
>>  	kmem_cache_destroy(spufs_inode_cache);
>>  out:
>> +	printk("spufs init not performed\n");
>>  	return ret;
>>  }
>
>The printk lines don't follow the convention of using KERN_*
>printk levels. I suggest you either remove them or turn them
>into pr_debug().
They should not be here (removed).

>> +
>> +#include <asm/spu_priv1.h>
>> +#include <asm/kspu/kspu.h>
>> +#include <asm/kspu/merged_code.h>
>> +#include <linux/kthread.h>
>> +#include <linux/module.h>
>> +#include <linux/init_task.h>
>> +#include <linux/hardirq.h>
>> +#include <linux/kernel.h>
>
>
>#include lines should be ordered alphabetically, and <asm/ lines come
>after <linux/ lines.
Okey.

>> +/*
>> + * based on run.c spufs_run_spu
>> + */
>> +static int spufs_run_kernel_spu(void *priv)
>> +{
>> +	struct kspu_context *kctx = (struct kspu_context *) priv;
>> +	struct spu_context *ctx = kctx->spu_ctx;
>> +	int ret;
>> +	u32 status;
>> +	unsigned int npc = 0;
>> +	int fastpath;
>> +	DEFINE_WAIT(wait_for_stop);
>> +	DEFINE_WAIT(wait_for_ibox);
>> +	DEFINE_WAIT(wait_for_newitem);
>> +
>> +	spu_enable_spu(ctx);
>> +	ctx->event_return = 0;
>> +	spu_acquire(ctx);
>> +	if (ctx->state == SPU_STATE_SAVED) {
>> +		__spu_update_sched_info(ctx);
>> +
>> +		ret = spu_activate(ctx, 0);
>> +		if (ret) {
>> +			spu_release(ctx);
>> +			printk(KERN_ERR "could not obtain runnable spu: %d\n",
>> +					ret);
>> +			BUG();
>> +		}
>> +	} else {
>> +		/*
>> +		 * We have to update the scheduling priority under active_mutex
>> +		 * to protect against find_victim().
>> +		 */
>> +		spu_update_sched_info(ctx);
>> +	}
>
>The code you have copied this from has recently been changed to also set an initial
>time slice, you should do the same change here.
adopted. 

>> +
>> +	spu_run_init(ctx, &npc);
>> +	do {
>> +		fastpath = 0;
>> +		prepare_to_wait(&ctx->stop_wq, &wait_for_stop,
>> +				TASK_INTERRUPTIBLE);
>> +		prepare_to_wait(&ctx->ibox_wq, &wait_for_ibox,
>> +				TASK_INTERRUPTIBLE);
>> +		prepare_to_wait(&kctx->newitem_wq, &wait_for_newitem,
>> +				TASK_INTERRUPTIBLE);
>> +
>> +		if (unlikely(test_and_clear_bit(SPU_SCHED_NOTIFY_ACTIVE,
>> +						&ctx->sched_flags))) {
>> +
>> +			if (!(status & SPU_STATUS_STOPPED_BY_STOP)) {
>> +				spu_switch_notify(ctx->spu, ctx);
>> +			}
>> +		}
>> +
>> +		spuctx_switch_state(ctx, SPU_UTIL_SYSTEM);
>> +
>> +		pr_debug("going to handle class1\n");
>> +		ret = spufs_handle_class1(ctx);
>> +		if (unlikely(ret)) {
>> +			/*
>> +			 * SPE_EVENT_SPE_DATA_STORAGE => refernce invalid memory
>> +			 */
>> +			printk(KERN_ERR "Invalid memory dereferenced by the"
>> +					"spu: %d\n", ret);
>> +			BUG();
>> +		}
>> +
>> +		/* FIXME BUG: We need a physical SPU to discover
>> +		 * ctx->spu->class_0_pending. It is not saved on context
>> +		 * switch. We may lose this on context switch.
>> +		 */
>> +		status = ctx->ops->status_read(ctx);
>> +		if (unlikely((ctx->spu && ctx->spu->class_0_pending) ||
>> +					status & SPU_STATUS_INVALID_INSTR)) {
>> +			printk(KERN_ERR "kspu error, status_register: 0x%08x\n",
>> +					status);
>> +			printk(KERN_ERR "event return: 0x%08lx, spu's npc: "
>> +					"0x%08x\n", kctx->spu_ctx->event_return,
>> +					kctx->spu_ctx->ops->npc_read(
>> +						kctx->spu_ctx));
>> +			printk(KERN_ERR "class_0_pending: 0x%lx\n", ctx->spu->class_0_pending);
>> +			print_kctx_debug(kctx);
>> +			BUG();
>> +		}
>> +
>> +		if (notify_done_reqs(kctx))
>> +			fastpath = 1;
>> +
>> +		if (queue_requests(kctx))
>> +			fastpath = 1;
>> +
>> +		if (!(status & SPU_STATUS_RUNNING)) {
>> +			/* spu is currently not running */
>> +			pr_debug("SPU not running, last stop code was: %08x\n",
>> +					status >> SPU_STOP_STATUS_SHIFT);
>> +			if (pending_spu_work(kctx)) {
>> +				/* spu should run again */
>> +				pr_debug("Activate SPU\n");
>> +				kspu_fill_dummy_reqs(kctx);
>> +
>> +				spu_run_fini(ctx, &npc, &status);
>> +				spu_acquire_runnable(ctx, 0);
>> +				spu_run_init(ctx, &npc);
>> +			} else {
>> +				/* spu finished work */
>> +				pr_debug("SPU will remain in stop state\n");
>> +				spu_run_fini(ctx, &npc, &status);
>> +				spu_yield(ctx);
>> +				spu_acquire(ctx);
>> +			}
>> +		} else {
>> +			pr_debug("SPU is running, switch state to util user\n");
>> +			spuctx_switch_state(ctx, SPU_UTIL_USER);
>> +		}
>> +
>> +		if (fastpath)
>> +			continue;
>> +
>> +		spu_release(ctx);
>> +		schedule();
>> +		spu_acquire(ctx);
>> +
>> +	} while (!kthread_should_stop() || !list_empty(&kctx->work_queue));
>
>The inner loop is rather long, in an already long function. Can you split out
>parts into separate functions here?

I tried. What about:

static void setup_spu_sched(struct spu_context *ctx)
{
	if (ctx->state == SPU_STATE_SAVED) {
		__spu_update_sched_info(ctx);
		spu_set_timeslice(ctx);
		spu_activate(ctx, 0);
	} else {
		/*
		 * We have to update the scheduling priority under active_mutex
		 * to protect against find_victim().
		 */
		spu_update_sched_info(ctx);
	}
}

static void check_spu_state(struct kspu_context *kctx, unsigned int *npc,
		unsigned int *status)
{
	if (!(*status & SPU_STATUS_RUNNING)) {
		/* spu is currently not running */
		pr_debug("SPU not running, last stop code was: %08x\n",
				*status >> SPU_STOP_STATUS_SHIFT);
		if (pending_spu_work(kctx)) {
			/* spu should run again */
			pr_debug("Activate SPU\n");
			kspu_fill_dummy_reqs(kctx);

			spu_run_fini(kctx->spu_ctx, npc, status);
			spu_acquire_runnable(kctx->spu_ctx, 0);
			spu_run_init(kctx->spu_ctx, npc);
		} else {
			/* spu finished work */
			pr_debug("SPU will remain in stop state\n");
			spu_run_fini(kctx->spu_ctx, npc, status);
			spu_yield(kctx->spu_ctx);
			spu_acquire(kctx->spu_ctx);
		}
	} else {
		pr_debug("SPU is running, switch state to util user\n");
		spuctx_switch_state(kctx->spu_ctx, SPU_UTIL_USER);
	}
}

/*
 * based on run.c spufs_run_spu
 */
static int spufs_run_kernel_spu(void *priv)
{
	struct kspu_context *kctx = (struct kspu_context *) priv;
	struct spu_context *ctx = kctx->spu_ctx;
	int ret;
	u32 status;
	unsigned int npc = 0;
	int fastpath;
	DEFINE_WAIT(wait_for_stop);
	DEFINE_WAIT(wait_for_ibox);
	DEFINE_WAIT(wait_for_newitem);

	ctx->event_return = 0;
	spu_acquire(ctx);
	ctx->ops->master_start(ctx);

	setup_spu_sched(ctx);

	spu_run_init(ctx, &npc);
	do {
		fastpath = 0;
		prepare_to_wait(&ctx->stop_wq, &wait_for_stop,
				TASK_INTERRUPTIBLE);
		prepare_to_wait(&ctx->ibox_wq, &wait_for_ibox,
				TASK_INTERRUPTIBLE);
		prepare_to_wait(&kctx->newitem_wq, &wait_for_newitem,
				TASK_INTERRUPTIBLE);

		if (unlikely(test_and_clear_bit(SPU_SCHED_NOTIFY_ACTIVE,
						&ctx->sched_flags))) {
			if (!(status & SPU_STATUS_STOPPED_BY_STOP)) {
				spu_switch_notify(ctx->spu, ctx);
			}
		}

		spuctx_switch_state(ctx, SPU_UTIL_SYSTEM);

		pr_debug("going to handle class1\n");
		ret = spufs_handle_class1(ctx);
		if (unlikely(ret)) {
			/*
			 * SPE_EVENT_SPE_DATA_STORAGE => refernce invalid memory
			 */
			printk(KERN_ERR "Invalid memory dereferenced by the"
					"spu: %d\n", ret);
			BUG();
		}

		/* FIXME BUG: We need a physical SPU to discover
		 * ctx->spu->class_0_pending. It is not saved on context
		 * switch. We may lose this on context switch.
		 */
		status = ctx->ops->status_read(ctx);
		if (unlikely((ctx->spu && ctx->spu->class_0_pending) ||
					status & SPU_STATUS_INVALID_INSTR)) {
			printk(KERN_ERR "kspu error, status_register: 0x%08x\n",
					status);
			printk(KERN_ERR "event return: 0x%08lx, spu's npc: "
					"0x%08x\n", kctx->spu_ctx->event_return,
					kctx->spu_ctx->ops->npc_read(
						kctx->spu_ctx));
			printk(KERN_ERR "class_0_pending: 0x%x\n", ctx->spu->class_0_pending);
			print_kctx_debug(kctx);
			BUG();
		}

		if (notify_done_reqs(kctx))
			fastpath = 1;

		if (queue_requests(kctx))
			fastpath = 1;

		check_spu_state(kctx, &npc, &status);

		if (fastpath)
			continue;

		spu_release(ctx);
		schedule();
		spu_acquire(ctx);

	} while (!kthread_should_stop() || !list_empty(&kctx->work_queue));

	finish_wait(&ctx->stop_wq, &wait_for_stop);
	finish_wait(&ctx->ibox_wq, &wait_for_ibox);
	finish_wait(&kctx->newitem_wq, &wait_for_newitem);

	ctx->ops->master_stop(ctx);
	spu_release(ctx);
	return 0;
}

>> --- a/arch/powerpc/platforms/cell/spufs/spufs.h
>> +++ b/arch/powerpc/platforms/cell/spufs/spufs.h
>> @@ -344,4 +344,18 @@ static inline void spuctx_switch_state(s
>>  	}
>>  }
>>  
>> +#ifdef CONFIG_KSPU
>> +int __init kspu_init(void);
>> +void __exit kspu_exit(void);
>
>The __init and __exit specifiers are not meaningful in the declaration,
>you only need them in the definition.

okey.

>	Arnd <><
>-

Sebastian



More information about the cbe-oss-dev mailing list