1 /* 2 * SPU file system -- SPU context management 3 * 4 * (C) Copyright IBM Deutschland Entwicklung GmbH 2005 5 * 6 * Author: Arnd Bergmann <arndb@de.ibm.com> 7 * 8 * This program is free software; you can redistribute it and/or modify 9 * it under the terms of the GNU General Public License as published by 10 * the Free Software Foundation; either version 2, or (at your option) 11 * any later version. 12 * 13 * This program is distributed in the hope that it will be useful, 14 * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 * GNU General Public License for more details. 17 * 18 * You should have received a copy of the GNU General Public License 19 * along with this program; if not, write to the Free Software 20 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 21 */ 22 23 #include <linux/fs.h> 24 #include <linux/mm.h> 25 #include <linux/slab.h> 26 #include <asm/spu.h> 27 #include <asm/spu_csa.h> 28 #include "spufs.h" 29 30 struct spu_context *alloc_spu_context(struct spu_gang *gang) 31 { 32 struct spu_context *ctx; 33 ctx = kzalloc(sizeof *ctx, GFP_KERNEL); 34 if (!ctx) 35 goto out; 36 /* Binding to physical processor deferred 37 * until spu_activate(). 38 */ 39 if (spu_init_csa(&ctx->csa)) 40 goto out_free; 41 spin_lock_init(&ctx->mmio_lock); 42 mutex_init(&ctx->mapping_lock); 43 kref_init(&ctx->kref); 44 mutex_init(&ctx->state_mutex); 45 mutex_init(&ctx->run_mutex); 46 init_waitqueue_head(&ctx->ibox_wq); 47 init_waitqueue_head(&ctx->wbox_wq); 48 init_waitqueue_head(&ctx->stop_wq); 49 init_waitqueue_head(&ctx->mfc_wq); 50 ctx->state = SPU_STATE_SAVED; 51 ctx->ops = &spu_backing_ops; 52 ctx->owner = get_task_mm(current); 53 INIT_LIST_HEAD(&ctx->rq); 54 if (gang) 55 spu_gang_add_ctx(gang, ctx); 56 ctx->rt_priority = current->rt_priority; 57 ctx->policy = current->policy; 58 ctx->prio = current->prio; 59 INIT_DELAYED_WORK(&ctx->sched_work, spu_sched_tick); 60 goto out; 61 out_free: 62 kfree(ctx); 63 ctx = NULL; 64 out: 65 return ctx; 66 } 67 68 void destroy_spu_context(struct kref *kref) 69 { 70 struct spu_context *ctx; 71 ctx = container_of(kref, struct spu_context, kref); 72 mutex_lock(&ctx->state_mutex); 73 spu_deactivate(ctx); 74 mutex_unlock(&ctx->state_mutex); 75 spu_fini_csa(&ctx->csa); 76 if (ctx->gang) 77 spu_gang_remove_ctx(ctx->gang, ctx); 78 BUG_ON(!list_empty(&ctx->rq)); 79 kfree(ctx); 80 } 81 82 struct spu_context * get_spu_context(struct spu_context *ctx) 83 { 84 kref_get(&ctx->kref); 85 return ctx; 86 } 87 88 int put_spu_context(struct spu_context *ctx) 89 { 90 return kref_put(&ctx->kref, &destroy_spu_context); 91 } 92 93 /* give up the mm reference when the context is about to be destroyed */ 94 void spu_forget(struct spu_context *ctx) 95 { 96 struct mm_struct *mm; 97 spu_acquire_saved(ctx); 98 mm = ctx->owner; 99 ctx->owner = NULL; 100 mmput(mm); 101 spu_release(ctx); 102 } 103 104 void spu_unmap_mappings(struct spu_context *ctx) 105 { 106 mutex_lock(&ctx->mapping_lock); 107 if (ctx->local_store) 108 unmap_mapping_range(ctx->local_store, 0, LS_SIZE, 1); 109 if (ctx->mfc) 110 unmap_mapping_range(ctx->mfc, 0, 0x1000, 1); 111 if (ctx->cntl) 112 unmap_mapping_range(ctx->cntl, 0, 0x1000, 1); 113 if (ctx->signal1) 114 unmap_mapping_range(ctx->signal1, 0, PAGE_SIZE, 1); 115 if (ctx->signal2) 116 unmap_mapping_range(ctx->signal2, 0, PAGE_SIZE, 1); 117 if (ctx->mss) 118 unmap_mapping_range(ctx->mss, 0, 0x1000, 1); 119 if (ctx->psmap) 120 unmap_mapping_range(ctx->psmap, 0, 0x20000, 1); 121 mutex_unlock(&ctx->mapping_lock); 122 } 123 124 /** 125 * spu_acquire_runnable - lock spu contex and make sure it is in runnable state 126 * @ctx: spu contex to lock 127 * 128 * Note: 129 * Returns 0 and with the context locked on success 130 * Returns negative error and with the context _unlocked_ on failure. 131 */ 132 int spu_acquire_runnable(struct spu_context *ctx, unsigned long flags) 133 { 134 int ret = -EINVAL; 135 136 spu_acquire(ctx); 137 if (ctx->state == SPU_STATE_SAVED) { 138 /* 139 * Context is about to be freed, so we can't acquire it anymore. 140 */ 141 if (!ctx->owner) 142 goto out_unlock; 143 ret = spu_activate(ctx, flags); 144 if (ret) 145 goto out_unlock; 146 } 147 148 return 0; 149 150 out_unlock: 151 spu_release(ctx); 152 return ret; 153 } 154 155 /** 156 * spu_acquire_saved - lock spu contex and make sure it is in saved state 157 * @ctx: spu contex to lock 158 */ 159 void spu_acquire_saved(struct spu_context *ctx) 160 { 161 spu_acquire(ctx); 162 if (ctx->state != SPU_STATE_SAVED) 163 spu_deactivate(ctx); 164 } 165