167207b96SArnd Bergmann /* 267207b96SArnd Bergmann * SPU file system -- SPU context management 367207b96SArnd Bergmann * 467207b96SArnd Bergmann * (C) Copyright IBM Deutschland Entwicklung GmbH 2005 567207b96SArnd Bergmann * 667207b96SArnd Bergmann * Author: Arnd Bergmann <arndb@de.ibm.com> 767207b96SArnd Bergmann * 867207b96SArnd Bergmann * This program is free software; you can redistribute it and/or modify 967207b96SArnd Bergmann * it under the terms of the GNU General Public License as published by 1067207b96SArnd Bergmann * the Free Software Foundation; either version 2, or (at your option) 1167207b96SArnd Bergmann * any later version. 1267207b96SArnd Bergmann * 1367207b96SArnd Bergmann * This program is distributed in the hope that it will be useful, 1467207b96SArnd Bergmann * but WITHOUT ANY WARRANTY; without even the implied warranty of 1567207b96SArnd Bergmann * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 1667207b96SArnd Bergmann * GNU General Public License for more details. 1767207b96SArnd Bergmann * 1867207b96SArnd Bergmann * You should have received a copy of the GNU General Public License 1967207b96SArnd Bergmann * along with this program; if not, write to the Free Software 2067207b96SArnd Bergmann * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 2167207b96SArnd Bergmann */ 2267207b96SArnd Bergmann 238b3d6663SArnd Bergmann #include <linux/fs.h> 248b3d6663SArnd Bergmann #include <linux/mm.h> 2567207b96SArnd Bergmann #include <linux/slab.h> 2667207b96SArnd Bergmann #include <asm/spu.h> 275473af04SMark Nutter #include <asm/spu_csa.h> 2867207b96SArnd Bergmann #include "spufs.h" 2967207b96SArnd Bergmann 306263203eSArnd Bergmann struct spu_context *alloc_spu_context(struct spu_gang *gang) 3167207b96SArnd Bergmann { 3267207b96SArnd Bergmann struct spu_context *ctx; 33c5c45913SJeremy Kerr ctx = kzalloc(sizeof *ctx, GFP_KERNEL); 3467207b96SArnd Bergmann if (!ctx) 3567207b96SArnd Bergmann goto out; 368b3d6663SArnd Bergmann /* Binding to physical processor deferred 378b3d6663SArnd Bergmann * until spu_activate(). 385473af04SMark Nutter */ 395473af04SMark Nutter spu_init_csa(&ctx->csa); 405473af04SMark Nutter if (!ctx->csa.lscsa) { 415473af04SMark Nutter goto out_free; 425473af04SMark Nutter } 4367207b96SArnd Bergmann spin_lock_init(&ctx->mmio_lock); 4467207b96SArnd Bergmann kref_init(&ctx->kref); 458b3d6663SArnd Bergmann init_rwsem(&ctx->state_sema); 465ef8224aSArnd Bergmann init_MUTEX(&ctx->run_sema); 478b3d6663SArnd Bergmann init_waitqueue_head(&ctx->ibox_wq); 488b3d6663SArnd Bergmann init_waitqueue_head(&ctx->wbox_wq); 495110459fSArnd Bergmann init_waitqueue_head(&ctx->stop_wq); 50a33a7d73SArnd Bergmann init_waitqueue_head(&ctx->mfc_wq); 518b3d6663SArnd Bergmann ctx->state = SPU_STATE_SAVED; 528b3d6663SArnd Bergmann ctx->ops = &spu_backing_ops; 538b3d6663SArnd Bergmann ctx->owner = get_task_mm(current); 546263203eSArnd Bergmann if (gang) 556263203eSArnd Bergmann spu_gang_add_ctx(gang, ctx); 5667207b96SArnd Bergmann goto out; 5767207b96SArnd Bergmann out_free: 5867207b96SArnd Bergmann kfree(ctx); 5967207b96SArnd Bergmann ctx = NULL; 6067207b96SArnd Bergmann out: 6167207b96SArnd Bergmann return ctx; 6267207b96SArnd Bergmann } 6367207b96SArnd Bergmann 6467207b96SArnd Bergmann void destroy_spu_context(struct kref *kref) 6567207b96SArnd Bergmann { 6667207b96SArnd Bergmann struct spu_context *ctx; 6767207b96SArnd Bergmann ctx = container_of(kref, struct spu_context, kref); 688b3d6663SArnd Bergmann down_write(&ctx->state_sema); 698b3d6663SArnd Bergmann spu_deactivate(ctx); 708b3d6663SArnd Bergmann up_write(&ctx->state_sema); 715473af04SMark Nutter spu_fini_csa(&ctx->csa); 726263203eSArnd Bergmann if (ctx->gang) 736263203eSArnd Bergmann spu_gang_remove_ctx(ctx->gang, ctx); 7467207b96SArnd Bergmann kfree(ctx); 7567207b96SArnd Bergmann } 7667207b96SArnd Bergmann 7767207b96SArnd Bergmann struct spu_context * get_spu_context(struct spu_context *ctx) 7867207b96SArnd Bergmann { 7967207b96SArnd Bergmann kref_get(&ctx->kref); 8067207b96SArnd Bergmann return ctx; 8167207b96SArnd Bergmann } 8267207b96SArnd Bergmann 8367207b96SArnd Bergmann int put_spu_context(struct spu_context *ctx) 8467207b96SArnd Bergmann { 8567207b96SArnd Bergmann return kref_put(&ctx->kref, &destroy_spu_context); 8667207b96SArnd Bergmann } 8767207b96SArnd Bergmann 888b3d6663SArnd Bergmann /* give up the mm reference when the context is about to be destroyed */ 898b3d6663SArnd Bergmann void spu_forget(struct spu_context *ctx) 908b3d6663SArnd Bergmann { 918b3d6663SArnd Bergmann struct mm_struct *mm; 928b3d6663SArnd Bergmann spu_acquire_saved(ctx); 938b3d6663SArnd Bergmann mm = ctx->owner; 948b3d6663SArnd Bergmann ctx->owner = NULL; 958b3d6663SArnd Bergmann mmput(mm); 968b3d6663SArnd Bergmann spu_release(ctx); 978b3d6663SArnd Bergmann } 9867207b96SArnd Bergmann 998b3d6663SArnd Bergmann void spu_acquire(struct spu_context *ctx) 1008b3d6663SArnd Bergmann { 1018b3d6663SArnd Bergmann down_read(&ctx->state_sema); 1028b3d6663SArnd Bergmann } 1038b3d6663SArnd Bergmann 1048b3d6663SArnd Bergmann void spu_release(struct spu_context *ctx) 1058b3d6663SArnd Bergmann { 1068b3d6663SArnd Bergmann up_read(&ctx->state_sema); 1078b3d6663SArnd Bergmann } 1088b3d6663SArnd Bergmann 1095110459fSArnd Bergmann void spu_unmap_mappings(struct spu_context *ctx) 1108b3d6663SArnd Bergmann { 1116df10a82SMark Nutter if (ctx->local_store) 1128b3d6663SArnd Bergmann unmap_mapping_range(ctx->local_store, 0, LS_SIZE, 1); 1136df10a82SMark Nutter if (ctx->mfc) 1146df10a82SMark Nutter unmap_mapping_range(ctx->mfc, 0, 0x4000, 1); 1156df10a82SMark Nutter if (ctx->cntl) 1166df10a82SMark Nutter unmap_mapping_range(ctx->cntl, 0, 0x4000, 1); 1176df10a82SMark Nutter if (ctx->signal1) 1186df10a82SMark Nutter unmap_mapping_range(ctx->signal1, 0, 0x4000, 1); 1196df10a82SMark Nutter if (ctx->signal2) 1206df10a82SMark Nutter unmap_mapping_range(ctx->signal2, 0, 0x4000, 1); 1218b3d6663SArnd Bergmann } 1228b3d6663SArnd Bergmann 1238b3d6663SArnd Bergmann int spu_acquire_runnable(struct spu_context *ctx) 1248b3d6663SArnd Bergmann { 1258b3d6663SArnd Bergmann int ret = 0; 1268b3d6663SArnd Bergmann 1278b3d6663SArnd Bergmann down_read(&ctx->state_sema); 1282a911f0bSArnd Bergmann if (ctx->state == SPU_STATE_RUNNABLE) { 1292a911f0bSArnd Bergmann ctx->spu->prio = current->prio; 1308b3d6663SArnd Bergmann return 0; 1312a911f0bSArnd Bergmann } 132762cf6daSArnd Bergmann up_read(&ctx->state_sema); 133762cf6daSArnd Bergmann 134762cf6daSArnd Bergmann down_write(&ctx->state_sema); 1358b3d6663SArnd Bergmann /* ctx is about to be freed, can't acquire any more */ 1368b3d6663SArnd Bergmann if (!ctx->owner) { 1378b3d6663SArnd Bergmann ret = -EINVAL; 1388b3d6663SArnd Bergmann goto out; 1398b3d6663SArnd Bergmann } 1408b3d6663SArnd Bergmann 1418b3d6663SArnd Bergmann if (ctx->state == SPU_STATE_SAVED) { 1428b3d6663SArnd Bergmann ret = spu_activate(ctx, 0); 1438b3d6663SArnd Bergmann if (ret) 1448b3d6663SArnd Bergmann goto out; 14501062465SArnd Bergmann ctx->state = SPU_STATE_RUNNABLE; 14601062465SArnd Bergmann } 1478b3d6663SArnd Bergmann 148762cf6daSArnd Bergmann downgrade_write(&ctx->state_sema); 1498b3d6663SArnd Bergmann /* On success, we return holding the lock */ 150762cf6daSArnd Bergmann 1518b3d6663SArnd Bergmann return ret; 1528b3d6663SArnd Bergmann out: 1538b3d6663SArnd Bergmann /* Release here, to simplify calling code. */ 154762cf6daSArnd Bergmann up_write(&ctx->state_sema); 1558b3d6663SArnd Bergmann 1568b3d6663SArnd Bergmann return ret; 1578b3d6663SArnd Bergmann } 1588b3d6663SArnd Bergmann 1598b3d6663SArnd Bergmann void spu_acquire_saved(struct spu_context *ctx) 1608b3d6663SArnd Bergmann { 1618b3d6663SArnd Bergmann down_read(&ctx->state_sema); 1628b3d6663SArnd Bergmann 1638b3d6663SArnd Bergmann if (ctx->state == SPU_STATE_SAVED) 1648b3d6663SArnd Bergmann return; 1658b3d6663SArnd Bergmann 1668b3d6663SArnd Bergmann up_read(&ctx->state_sema); 1678b3d6663SArnd Bergmann down_write(&ctx->state_sema); 1688b3d6663SArnd Bergmann 1698b3d6663SArnd Bergmann if (ctx->state == SPU_STATE_RUNNABLE) { 1708b3d6663SArnd Bergmann spu_deactivate(ctx); 1718b3d6663SArnd Bergmann ctx->state = SPU_STATE_SAVED; 1728b3d6663SArnd Bergmann } 1738b3d6663SArnd Bergmann 1748b3d6663SArnd Bergmann downgrade_write(&ctx->state_sema); 1758b3d6663SArnd Bergmann } 176