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); 4443c2bbd9SChristoph Hellwig spin_lock_init(&ctx->mapping_lock); 4567207b96SArnd Bergmann kref_init(&ctx->kref); 46650f8b02SChristoph Hellwig mutex_init(&ctx->state_mutex); 475ef8224aSArnd Bergmann init_MUTEX(&ctx->run_sema); 488b3d6663SArnd Bergmann init_waitqueue_head(&ctx->ibox_wq); 498b3d6663SArnd Bergmann init_waitqueue_head(&ctx->wbox_wq); 505110459fSArnd Bergmann init_waitqueue_head(&ctx->stop_wq); 51a33a7d73SArnd Bergmann init_waitqueue_head(&ctx->mfc_wq); 528b3d6663SArnd Bergmann ctx->state = SPU_STATE_SAVED; 538b3d6663SArnd Bergmann ctx->ops = &spu_backing_ops; 548b3d6663SArnd Bergmann ctx->owner = get_task_mm(current); 55a475c2f4SChristoph Hellwig INIT_LIST_HEAD(&ctx->rq); 566263203eSArnd Bergmann if (gang) 576263203eSArnd Bergmann spu_gang_add_ctx(gang, ctx); 5852f04fcfSChristoph Hellwig ctx->rt_priority = current->rt_priority; 592eb1b120SChristoph Hellwig ctx->policy = current->policy; 608389998aSChristoph Hellwig ctx->prio = current->prio; 612eb1b120SChristoph Hellwig INIT_DELAYED_WORK(&ctx->sched_work, spu_sched_tick); 6267207b96SArnd Bergmann goto out; 6367207b96SArnd Bergmann out_free: 6467207b96SArnd Bergmann kfree(ctx); 6567207b96SArnd Bergmann ctx = NULL; 6667207b96SArnd Bergmann out: 6767207b96SArnd Bergmann return ctx; 6867207b96SArnd Bergmann } 6967207b96SArnd Bergmann 7067207b96SArnd Bergmann void destroy_spu_context(struct kref *kref) 7167207b96SArnd Bergmann { 7267207b96SArnd Bergmann struct spu_context *ctx; 7367207b96SArnd Bergmann ctx = container_of(kref, struct spu_context, kref); 74650f8b02SChristoph Hellwig mutex_lock(&ctx->state_mutex); 758b3d6663SArnd Bergmann spu_deactivate(ctx); 76650f8b02SChristoph Hellwig mutex_unlock(&ctx->state_mutex); 775473af04SMark Nutter spu_fini_csa(&ctx->csa); 786263203eSArnd Bergmann if (ctx->gang) 796263203eSArnd Bergmann spu_gang_remove_ctx(ctx->gang, ctx); 80a475c2f4SChristoph Hellwig BUG_ON(!list_empty(&ctx->rq)); 8167207b96SArnd Bergmann kfree(ctx); 8267207b96SArnd Bergmann } 8367207b96SArnd Bergmann 8467207b96SArnd Bergmann struct spu_context * get_spu_context(struct spu_context *ctx) 8567207b96SArnd Bergmann { 8667207b96SArnd Bergmann kref_get(&ctx->kref); 8767207b96SArnd Bergmann return ctx; 8867207b96SArnd Bergmann } 8967207b96SArnd Bergmann 9067207b96SArnd Bergmann int put_spu_context(struct spu_context *ctx) 9167207b96SArnd Bergmann { 9267207b96SArnd Bergmann return kref_put(&ctx->kref, &destroy_spu_context); 9367207b96SArnd Bergmann } 9467207b96SArnd Bergmann 958b3d6663SArnd Bergmann /* give up the mm reference when the context is about to be destroyed */ 968b3d6663SArnd Bergmann void spu_forget(struct spu_context *ctx) 978b3d6663SArnd Bergmann { 988b3d6663SArnd Bergmann struct mm_struct *mm; 998b3d6663SArnd Bergmann spu_acquire_saved(ctx); 1008b3d6663SArnd Bergmann mm = ctx->owner; 1018b3d6663SArnd Bergmann ctx->owner = NULL; 1028b3d6663SArnd Bergmann mmput(mm); 1038b3d6663SArnd Bergmann spu_release(ctx); 1048b3d6663SArnd Bergmann } 10567207b96SArnd Bergmann 1065110459fSArnd Bergmann void spu_unmap_mappings(struct spu_context *ctx) 1078b3d6663SArnd Bergmann { 1086df10a82SMark Nutter if (ctx->local_store) 1098b3d6663SArnd Bergmann unmap_mapping_range(ctx->local_store, 0, LS_SIZE, 1); 1106df10a82SMark Nutter if (ctx->mfc) 11117e0e270SBenjamin Herrenschmidt unmap_mapping_range(ctx->mfc, 0, 0x1000, 1); 1126df10a82SMark Nutter if (ctx->cntl) 11317e0e270SBenjamin Herrenschmidt unmap_mapping_range(ctx->cntl, 0, 0x1000, 1); 1146df10a82SMark Nutter if (ctx->signal1) 11517e0e270SBenjamin Herrenschmidt unmap_mapping_range(ctx->signal1, 0, PAGE_SIZE, 1); 1166df10a82SMark Nutter if (ctx->signal2) 11717e0e270SBenjamin Herrenschmidt unmap_mapping_range(ctx->signal2, 0, PAGE_SIZE, 1); 11817e0e270SBenjamin Herrenschmidt if (ctx->mss) 11917e0e270SBenjamin Herrenschmidt unmap_mapping_range(ctx->mss, 0, 0x1000, 1); 12017e0e270SBenjamin Herrenschmidt if (ctx->psmap) 12117e0e270SBenjamin Herrenschmidt unmap_mapping_range(ctx->psmap, 0, 0x20000, 1); 1228b3d6663SArnd Bergmann } 1238b3d6663SArnd Bergmann 1246a0641e5SChristoph Hellwig /** 1256a0641e5SChristoph Hellwig * spu_acquire_exclusive - lock spu contex and protect against userspace access 1266a0641e5SChristoph Hellwig * @ctx: spu contex to lock 1276a0641e5SChristoph Hellwig * 1286a0641e5SChristoph Hellwig * Note: 1296a0641e5SChristoph Hellwig * Returns 0 and with the context locked on success 1306a0641e5SChristoph Hellwig * Returns negative error and with the context _unlocked_ on failure. 1316a0641e5SChristoph Hellwig */ 132099814bbSJeremy Kerr int spu_acquire_exclusive(struct spu_context *ctx) 133099814bbSJeremy Kerr { 1346a0641e5SChristoph Hellwig int ret = -EINVAL; 135099814bbSJeremy Kerr 1366a0641e5SChristoph Hellwig spu_acquire(ctx); 1376a0641e5SChristoph Hellwig /* 1386a0641e5SChristoph Hellwig * Context is about to be freed, so we can't acquire it anymore. 1396a0641e5SChristoph Hellwig */ 1406a0641e5SChristoph Hellwig if (!ctx->owner) 1416a0641e5SChristoph Hellwig goto out_unlock; 142099814bbSJeremy Kerr 143099814bbSJeremy Kerr if (ctx->state == SPU_STATE_SAVED) { 144099814bbSJeremy Kerr ret = spu_activate(ctx, 0); 145099814bbSJeremy Kerr if (ret) 1466a0641e5SChristoph Hellwig goto out_unlock; 147099814bbSJeremy Kerr } else { 1486a0641e5SChristoph Hellwig /* 1496a0641e5SChristoph Hellwig * We need to exclude userspace access to the context. 1506a0641e5SChristoph Hellwig * 1516a0641e5SChristoph Hellwig * To protect against memory access we invalidate all ptes 1526a0641e5SChristoph Hellwig * and make sure the pagefault handlers block on the mutex. 1536a0641e5SChristoph Hellwig */ 154099814bbSJeremy Kerr spu_unmap_mappings(ctx); 155099814bbSJeremy Kerr } 156099814bbSJeremy Kerr 1576a0641e5SChristoph Hellwig return 0; 1586a0641e5SChristoph Hellwig 1596a0641e5SChristoph Hellwig out_unlock: 1606a0641e5SChristoph Hellwig spu_release(ctx); 161099814bbSJeremy Kerr return ret; 162099814bbSJeremy Kerr } 163099814bbSJeremy Kerr 1646a0641e5SChristoph Hellwig /** 1656a0641e5SChristoph Hellwig * spu_acquire_runnable - lock spu contex and make sure it is in runnable state 1666a0641e5SChristoph Hellwig * @ctx: spu contex to lock 1676a0641e5SChristoph Hellwig * 1686a0641e5SChristoph Hellwig * Note: 1696a0641e5SChristoph Hellwig * Returns 0 and with the context locked on success 1706a0641e5SChristoph Hellwig * Returns negative error and with the context _unlocked_ on failure. 1716a0641e5SChristoph Hellwig */ 17226bec673SChristoph Hellwig int spu_acquire_runnable(struct spu_context *ctx, unsigned long flags) 1738b3d6663SArnd Bergmann { 1746a0641e5SChristoph Hellwig int ret = -EINVAL; 1758b3d6663SArnd Bergmann 1766a0641e5SChristoph Hellwig spu_acquire(ctx); 1778b3d6663SArnd Bergmann if (ctx->state == SPU_STATE_SAVED) { 1786a0641e5SChristoph Hellwig /* 1796a0641e5SChristoph Hellwig * Context is about to be freed, so we can't acquire it anymore. 1806a0641e5SChristoph Hellwig */ 1816a0641e5SChristoph Hellwig if (!ctx->owner) 1826a0641e5SChristoph Hellwig goto out_unlock; 18326bec673SChristoph Hellwig ret = spu_activate(ctx, flags); 1848b3d6663SArnd Bergmann if (ret) 1856a0641e5SChristoph Hellwig goto out_unlock; 1868389998aSChristoph Hellwig } 1878b3d6663SArnd Bergmann 1886a0641e5SChristoph Hellwig return 0; 1898b3d6663SArnd Bergmann 1906a0641e5SChristoph Hellwig out_unlock: 1916a0641e5SChristoph Hellwig spu_release(ctx); 1928b3d6663SArnd Bergmann return ret; 1938b3d6663SArnd Bergmann } 1948b3d6663SArnd Bergmann 1956a0641e5SChristoph Hellwig /** 1966a0641e5SChristoph Hellwig * spu_acquire_saved - lock spu contex and make sure it is in saved state 1976a0641e5SChristoph Hellwig * @ctx: spu contex to lock 1986a0641e5SChristoph Hellwig */ 1998b3d6663SArnd Bergmann void spu_acquire_saved(struct spu_context *ctx) 2008b3d6663SArnd Bergmann { 2016a0641e5SChristoph Hellwig spu_acquire(ctx); 2026a0641e5SChristoph Hellwig if (ctx->state != SPU_STATE_SAVED) 2038b3d6663SArnd Bergmann spu_deactivate(ctx); 2048b3d6663SArnd Bergmann } 205