| 
									
										
										
										
											2005-11-15 15:53:48 -05:00
										 |  |  | /*
 | 
					
						
							|  |  |  |  * SPU file system -- SPU context management | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * (C) Copyright IBM Deutschland Entwicklung GmbH 2005 | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * Author: Arnd Bergmann <arndb@de.ibm.com> | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * This program is free software; you can redistribute it and/or modify | 
					
						
							|  |  |  |  * it under the terms of the GNU General Public License as published by | 
					
						
							|  |  |  |  * the Free Software Foundation; either version 2, or (at your option) | 
					
						
							|  |  |  |  * any later version. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * This program is distributed in the hope that it will be useful, | 
					
						
							|  |  |  |  * but WITHOUT ANY WARRANTY; without even the implied warranty of | 
					
						
							|  |  |  |  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | 
					
						
							|  |  |  |  * GNU General Public License for more details. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * You should have received a copy of the GNU General Public License | 
					
						
							|  |  |  |  * along with this program; if not, write to the Free Software | 
					
						
							|  |  |  |  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2005-11-15 15:53:52 -05:00
										 |  |  | #include <linux/fs.h>
 | 
					
						
							|  |  |  | #include <linux/mm.h>
 | 
					
						
							| 
									
										
										
										
											2007-07-20 21:39:53 +02:00
										 |  |  | #include <linux/module.h>
 | 
					
						
							| 
									
										
										
										
											2005-11-15 15:53:48 -05:00
										 |  |  | #include <linux/slab.h>
 | 
					
						
							| 
									
										
										
										
											2007-06-29 10:58:02 +10:00
										 |  |  | #include <asm/atomic.h>
 | 
					
						
							| 
									
										
										
										
											2005-11-15 15:53:48 -05:00
										 |  |  | #include <asm/spu.h>
 | 
					
						
							| 
									
										
										
										
											2005-11-15 15:53:49 -05:00
										 |  |  | #include <asm/spu_csa.h>
 | 
					
						
							| 
									
										
										
										
											2005-11-15 15:53:48 -05:00
										 |  |  | #include "spufs.h"
 | 
					
						
							| 
									
										
										
										
											2009-06-12 04:31:52 +00:00
										 |  |  | #include "sputrace.h"
 | 
					
						
							| 
									
										
										
										
											2005-11-15 15:53:48 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-06-29 10:58:02 +10:00
										 |  |  | 
 | 
					
						
							|  |  |  | atomic_t nr_spu_contexts = ATOMIC_INIT(0); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-10-04 17:26:15 +02:00
										 |  |  | struct spu_context *alloc_spu_context(struct spu_gang *gang) | 
					
						
							| 
									
										
										
										
											2005-11-15 15:53:48 -05:00
										 |  |  | { | 
					
						
							|  |  |  | 	struct spu_context *ctx; | 
					
						
							| 
									
										
										
										
											2009-02-23 21:44:37 +00:00
										 |  |  | 	struct timespec ts; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-04-28 16:37:47 +08:00
										 |  |  | 	ctx = kzalloc(sizeof *ctx, GFP_KERNEL); | 
					
						
							| 
									
										
										
										
											2005-11-15 15:53:48 -05:00
										 |  |  | 	if (!ctx) | 
					
						
							|  |  |  | 		goto out; | 
					
						
							| 
									
										
										
										
											2005-11-15 15:53:52 -05:00
										 |  |  | 	/* Binding to physical processor deferred
 | 
					
						
							|  |  |  | 	 * until spu_activate(). | 
					
						
							| 
									
										
										
										
											2005-11-15 15:53:49 -05:00
										 |  |  | 	 */ | 
					
						
							| 
									
										
										
										
											2007-05-08 16:27:29 +10:00
										 |  |  | 	if (spu_init_csa(&ctx->csa)) | 
					
						
							| 
									
										
										
										
											2005-11-15 15:53:49 -05:00
										 |  |  | 		goto out_free; | 
					
						
							| 
									
										
										
										
											2005-11-15 15:53:48 -05:00
										 |  |  | 	spin_lock_init(&ctx->mmio_lock); | 
					
						
							| 
									
										
										
										
											2007-06-04 23:26:51 +10:00
										 |  |  | 	mutex_init(&ctx->mapping_lock); | 
					
						
							| 
									
										
										
										
											2005-11-15 15:53:48 -05:00
										 |  |  | 	kref_init(&ctx->kref); | 
					
						
							| 
									
										
										
										
											2007-02-13 21:36:50 +01:00
										 |  |  | 	mutex_init(&ctx->state_mutex); | 
					
						
							| 
									
										
										
										
											2007-04-23 21:08:17 +02:00
										 |  |  | 	mutex_init(&ctx->run_mutex); | 
					
						
							| 
									
										
										
										
											2005-11-15 15:53:52 -05:00
										 |  |  | 	init_waitqueue_head(&ctx->ibox_wq); | 
					
						
							|  |  |  | 	init_waitqueue_head(&ctx->wbox_wq); | 
					
						
							| 
									
										
										
										
											2005-12-05 22:52:25 -05:00
										 |  |  | 	init_waitqueue_head(&ctx->stop_wq); | 
					
						
							| 
									
										
										
										
											2006-03-23 00:00:11 +01:00
										 |  |  | 	init_waitqueue_head(&ctx->mfc_wq); | 
					
						
							| 
									
										
										
										
											2007-12-20 16:39:59 +09:00
										 |  |  | 	init_waitqueue_head(&ctx->run_wq); | 
					
						
							| 
									
										
										
										
											2005-11-15 15:53:52 -05:00
										 |  |  | 	ctx->state = SPU_STATE_SAVED; | 
					
						
							|  |  |  | 	ctx->ops = &spu_backing_ops; | 
					
						
							|  |  |  | 	ctx->owner = get_task_mm(current); | 
					
						
							| 
									
										
										
										
											2007-04-23 21:08:11 +02:00
										 |  |  | 	INIT_LIST_HEAD(&ctx->rq); | 
					
						
							| 
									
										
										
										
											2007-07-20 21:39:47 +02:00
										 |  |  | 	INIT_LIST_HEAD(&ctx->aff_list); | 
					
						
							| 
									
										
										
										
											2006-10-04 17:26:15 +02:00
										 |  |  | 	if (gang) | 
					
						
							|  |  |  | 		spu_gang_add_ctx(gang, ctx); | 
					
						
							| 
									
										
										
										
											2007-07-25 21:31:09 +10:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	__spu_update_sched_info(ctx); | 
					
						
							| 
									
										
										
										
											2007-06-29 10:57:52 +10:00
										 |  |  | 	spu_set_timeslice(ctx); | 
					
						
							| 
									
										
										
										
											2007-07-20 21:39:33 +02:00
										 |  |  | 	ctx->stats.util_state = SPU_UTIL_IDLE_LOADED; | 
					
						
							| 
									
										
										
										
											2009-02-23 21:44:37 +00:00
										 |  |  | 	ktime_get_ts(&ts); | 
					
						
							|  |  |  | 	ctx->stats.tstamp = timespec_to_ns(&ts); | 
					
						
							| 
									
										
										
										
											2007-06-29 10:58:02 +10:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	atomic_inc(&nr_spu_contexts); | 
					
						
							| 
									
										
										
										
											2005-11-15 15:53:48 -05:00
										 |  |  | 	goto out; | 
					
						
							|  |  |  | out_free: | 
					
						
							|  |  |  | 	kfree(ctx); | 
					
						
							|  |  |  | 	ctx = NULL; | 
					
						
							|  |  |  | out: | 
					
						
							|  |  |  | 	return ctx; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void destroy_spu_context(struct kref *kref) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	struct spu_context *ctx; | 
					
						
							|  |  |  | 	ctx = container_of(kref, struct spu_context, kref); | 
					
						
							| 
									
										
										
										
											2008-04-30 15:12:30 +10:00
										 |  |  | 	spu_context_nospu_trace(destroy_spu_context__enter, ctx); | 
					
						
							| 
									
										
										
										
											2007-02-13 21:36:50 +01:00
										 |  |  | 	mutex_lock(&ctx->state_mutex); | 
					
						
							| 
									
										
										
										
											2005-11-15 15:53:52 -05:00
										 |  |  | 	spu_deactivate(ctx); | 
					
						
							| 
									
										
										
										
											2007-02-13 21:36:50 +01:00
										 |  |  | 	mutex_unlock(&ctx->state_mutex); | 
					
						
							| 
									
										
										
										
											2005-11-15 15:53:49 -05:00
										 |  |  | 	spu_fini_csa(&ctx->csa); | 
					
						
							| 
									
										
										
										
											2006-10-04 17:26:15 +02:00
										 |  |  | 	if (ctx->gang) | 
					
						
							|  |  |  | 		spu_gang_remove_ctx(ctx->gang, ctx); | 
					
						
							| 
									
										
										
										
											2007-07-20 21:39:53 +02:00
										 |  |  | 	if (ctx->prof_priv_kref) | 
					
						
							|  |  |  | 		kref_put(ctx->prof_priv_kref, ctx->prof_priv_release); | 
					
						
							| 
									
										
										
										
											2007-04-23 21:08:11 +02:00
										 |  |  | 	BUG_ON(!list_empty(&ctx->rq)); | 
					
						
							| 
									
										
										
										
											2007-06-29 10:58:02 +10:00
										 |  |  | 	atomic_dec(&nr_spu_contexts); | 
					
						
							| 
									
										
										
										
											2008-04-29 17:08:38 +10:00
										 |  |  | 	kfree(ctx->switch_log); | 
					
						
							| 
									
										
										
										
											2005-11-15 15:53:48 -05:00
										 |  |  | 	kfree(ctx); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | struct spu_context * get_spu_context(struct spu_context *ctx) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	kref_get(&ctx->kref); | 
					
						
							|  |  |  | 	return ctx; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | int put_spu_context(struct spu_context *ctx) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	return kref_put(&ctx->kref, &destroy_spu_context); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2005-11-15 15:53:52 -05:00
										 |  |  | /* give up the mm reference when the context is about to be destroyed */ | 
					
						
							|  |  |  | void spu_forget(struct spu_context *ctx) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	struct mm_struct *mm; | 
					
						
							| 
									
										
										
										
											2007-12-20 16:39:59 +09:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	/*
 | 
					
						
							|  |  |  | 	 * This is basically an open-coded spu_acquire_saved, except that | 
					
						
							| 
									
										
										
										
											2008-02-27 19:08:13 +11:00
										 |  |  | 	 * we don't acquire the state mutex interruptible, and we don't | 
					
						
							|  |  |  | 	 * want this context to be rescheduled on release. | 
					
						
							| 
									
										
										
										
											2007-12-20 16:39:59 +09:00
										 |  |  | 	 */ | 
					
						
							|  |  |  | 	mutex_lock(&ctx->state_mutex); | 
					
						
							| 
									
										
										
										
											2008-02-27 19:08:13 +11:00
										 |  |  | 	if (ctx->state != SPU_STATE_SAVED) | 
					
						
							| 
									
										
										
										
											2007-12-20 16:39:59 +09:00
										 |  |  | 		spu_deactivate(ctx); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2005-11-15 15:53:52 -05:00
										 |  |  | 	mm = ctx->owner; | 
					
						
							|  |  |  | 	ctx->owner = NULL; | 
					
						
							|  |  |  | 	mmput(mm); | 
					
						
							|  |  |  | 	spu_release(ctx); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2005-12-05 22:52:25 -05:00
										 |  |  | void spu_unmap_mappings(struct spu_context *ctx) | 
					
						
							| 
									
										
										
										
											2005-11-15 15:53:52 -05:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2007-06-04 23:26:51 +10:00
										 |  |  | 	mutex_lock(&ctx->mapping_lock); | 
					
						
							| 
									
										
										
										
											2006-03-23 00:00:12 +01:00
										 |  |  | 	if (ctx->local_store) | 
					
						
							|  |  |  | 		unmap_mapping_range(ctx->local_store, 0, LS_SIZE, 1); | 
					
						
							|  |  |  | 	if (ctx->mfc) | 
					
						
							| 
									
										
										
										
											2008-07-01 10:22:50 +10:00
										 |  |  | 		unmap_mapping_range(ctx->mfc, 0, SPUFS_MFC_MAP_SIZE, 1); | 
					
						
							| 
									
										
										
										
											2006-03-23 00:00:12 +01:00
										 |  |  | 	if (ctx->cntl) | 
					
						
							| 
									
										
										
										
											2008-07-01 10:22:50 +10:00
										 |  |  | 		unmap_mapping_range(ctx->cntl, 0, SPUFS_CNTL_MAP_SIZE, 1); | 
					
						
							| 
									
										
										
										
											2006-03-23 00:00:12 +01:00
										 |  |  | 	if (ctx->signal1) | 
					
						
							| 
									
										
										
										
											2008-07-01 10:22:50 +10:00
										 |  |  | 		unmap_mapping_range(ctx->signal1, 0, SPUFS_SIGNAL_MAP_SIZE, 1); | 
					
						
							| 
									
										
										
										
											2006-03-23 00:00:12 +01:00
										 |  |  | 	if (ctx->signal2) | 
					
						
							| 
									
										
										
										
											2008-07-01 10:22:50 +10:00
										 |  |  | 		unmap_mapping_range(ctx->signal2, 0, SPUFS_SIGNAL_MAP_SIZE, 1); | 
					
						
							| 
									
										
										
										
											2007-02-13 11:46:08 +11:00
										 |  |  | 	if (ctx->mss) | 
					
						
							| 
									
										
										
										
											2008-07-01 10:22:50 +10:00
										 |  |  | 		unmap_mapping_range(ctx->mss, 0, SPUFS_MSS_MAP_SIZE, 1); | 
					
						
							| 
									
										
										
										
											2007-02-13 11:46:08 +11:00
										 |  |  | 	if (ctx->psmap) | 
					
						
							| 
									
										
										
										
											2008-07-01 10:22:50 +10:00
										 |  |  | 		unmap_mapping_range(ctx->psmap, 0, SPUFS_PS_MAP_SIZE, 1); | 
					
						
							| 
									
										
										
										
											2007-06-04 23:26:51 +10:00
										 |  |  | 	mutex_unlock(&ctx->mapping_lock); | 
					
						
							| 
									
										
										
										
											2005-11-15 15:53:52 -05:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-02-13 21:54:21 +01:00
										 |  |  | /**
 | 
					
						
							|  |  |  |  * spu_acquire_saved - lock spu contex and make sure it is in saved state | 
					
						
							|  |  |  |  * @ctx:	spu contex to lock | 
					
						
							|  |  |  |  */ | 
					
						
							| 
									
										
										
										
											2007-12-20 16:39:59 +09:00
										 |  |  | int spu_acquire_saved(struct spu_context *ctx) | 
					
						
							| 
									
										
										
										
											2005-11-15 15:53:52 -05:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2007-12-20 16:39:59 +09:00
										 |  |  | 	int ret; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-04-30 15:21:17 +10:00
										 |  |  | 	spu_context_nospu_trace(spu_acquire_saved__enter, ctx); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-12-20 16:39:59 +09:00
										 |  |  | 	ret = spu_acquire(ctx); | 
					
						
							|  |  |  | 	if (ret) | 
					
						
							|  |  |  | 		return ret; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-07-20 21:39:34 +02:00
										 |  |  | 	if (ctx->state != SPU_STATE_SAVED) { | 
					
						
							|  |  |  | 		set_bit(SPU_SCHED_WAS_ACTIVE, &ctx->sched_flags); | 
					
						
							| 
									
										
										
										
											2005-11-15 15:53:52 -05:00
										 |  |  | 		spu_deactivate(ctx); | 
					
						
							| 
									
										
										
										
											2007-07-20 21:39:34 +02:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2007-12-20 16:39:59 +09:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	return 0; | 
					
						
							| 
									
										
										
										
											2007-07-20 21:39:34 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /**
 | 
					
						
							|  |  |  |  * spu_release_saved - unlock spu context and return it to the runqueue | 
					
						
							|  |  |  |  * @ctx:	context to unlock | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | void spu_release_saved(struct spu_context *ctx) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	BUG_ON(ctx->state != SPU_STATE_SAVED); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-03-11 12:46:18 +11:00
										 |  |  | 	if (test_and_clear_bit(SPU_SCHED_WAS_ACTIVE, &ctx->sched_flags) && | 
					
						
							|  |  |  | 			test_bit(SPU_SCHED_SPU_RUN, &ctx->sched_flags)) | 
					
						
							| 
									
										
										
										
											2007-07-20 21:39:34 +02:00
										 |  |  | 		spu_activate(ctx, 0); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	spu_release(ctx); | 
					
						
							| 
									
										
										
										
											2005-11-15 15:53:52 -05:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2007-07-20 21:39:53 +02:00
										 |  |  | 
 |