blob: 6653ddbed0483c4679755ee23b132fbc57091cb3 [file] [log] [blame]
Arnd Bergmann67207b92005-11-15 15:53:48 -05001/*
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
Arnd Bergmann8b3d6662005-11-15 15:53:52 -050023#include <linux/fs.h>
24#include <linux/mm.h>
Bob Nelson14748552007-07-20 21:39:53 +020025#include <linux/module.h>
Arnd Bergmann67207b92005-11-15 15:53:48 -050026#include <linux/slab.h>
Christoph Hellwig65de66f2007-06-29 10:58:02 +100027#include <asm/atomic.h>
Arnd Bergmann67207b92005-11-15 15:53:48 -050028#include <asm/spu.h>
Mark Nutter5473af02005-11-15 15:53:49 -050029#include <asm/spu_csa.h>
Arnd Bergmann67207b92005-11-15 15:53:48 -050030#include "spufs.h"
31
Christoph Hellwig65de66f2007-06-29 10:58:02 +100032
33atomic_t nr_spu_contexts = ATOMIC_INIT(0);
34
Arnd Bergmann62632032006-10-04 17:26:15 +020035struct spu_context *alloc_spu_context(struct spu_gang *gang)
Arnd Bergmann67207b92005-11-15 15:53:48 -050036{
37 struct spu_context *ctx;
Jeremy Kerrc5c45912006-04-28 16:37:47 +080038 ctx = kzalloc(sizeof *ctx, GFP_KERNEL);
Arnd Bergmann67207b92005-11-15 15:53:48 -050039 if (!ctx)
40 goto out;
Arnd Bergmann8b3d6662005-11-15 15:53:52 -050041 /* Binding to physical processor deferred
42 * until spu_activate().
Mark Nutter5473af02005-11-15 15:53:49 -050043 */
Benjamin Herrenschmidtf1fa74f2007-05-08 16:27:29 +100044 if (spu_init_csa(&ctx->csa))
Mark Nutter5473af02005-11-15 15:53:49 -050045 goto out_free;
Arnd Bergmann67207b92005-11-15 15:53:48 -050046 spin_lock_init(&ctx->mmio_lock);
Christoph Hellwig47d3a5f2007-06-04 23:26:51 +100047 mutex_init(&ctx->mapping_lock);
Arnd Bergmann67207b92005-11-15 15:53:48 -050048 kref_init(&ctx->kref);
Christoph Hellwig650f8b02007-02-13 21:36:50 +010049 mutex_init(&ctx->state_mutex);
Christoph Hellwige45d48a2007-04-23 21:08:17 +020050 mutex_init(&ctx->run_mutex);
Arnd Bergmann8b3d6662005-11-15 15:53:52 -050051 init_waitqueue_head(&ctx->ibox_wq);
52 init_waitqueue_head(&ctx->wbox_wq);
Arnd Bergmann51104592005-12-05 22:52:25 -050053 init_waitqueue_head(&ctx->stop_wq);
Arnd Bergmanna33a7d72006-03-23 00:00:11 +010054 init_waitqueue_head(&ctx->mfc_wq);
Arnd Bergmann33bfd7a2007-12-20 16:39:59 +090055 init_waitqueue_head(&ctx->run_wq);
Arnd Bergmann8b3d6662005-11-15 15:53:52 -050056 ctx->state = SPU_STATE_SAVED;
Arnd Bergmann8b3d6662005-11-15 15:53:52 -050057 ctx->ops = &spu_backing_ops;
58 ctx->owner = get_task_mm(current);
Christoph Hellwiga475c2f2007-04-23 21:08:11 +020059 INIT_LIST_HEAD(&ctx->rq);
Arnd Bergmann8e68e2f2007-07-20 21:39:47 +020060 INIT_LIST_HEAD(&ctx->aff_list);
Arnd Bergmann62632032006-10-04 17:26:15 +020061 if (gang)
62 spu_gang_add_ctx(gang, ctx);
Christoph Hellwig9d785922007-07-25 21:31:09 +100063
64 __spu_update_sched_info(ctx);
Christoph Hellwigfe443ef2007-06-29 10:57:52 +100065 spu_set_timeslice(ctx);
Andre Detsch27ec41d2007-07-20 21:39:33 +020066 ctx->stats.util_state = SPU_UTIL_IDLE_LOADED;
Christoph Hellwig65de66f2007-06-29 10:58:02 +100067
68 atomic_inc(&nr_spu_contexts);
Arnd Bergmann67207b92005-11-15 15:53:48 -050069 goto out;
70out_free:
71 kfree(ctx);
72 ctx = NULL;
73out:
74 return ctx;
75}
76
77void destroy_spu_context(struct kref *kref)
78{
79 struct spu_context *ctx;
80 ctx = container_of(kref, struct spu_context, kref);
Julio M. Merino Vidal53457882008-04-30 15:12:30 +100081 spu_context_nospu_trace(destroy_spu_context__enter, ctx);
Christoph Hellwig650f8b02007-02-13 21:36:50 +010082 mutex_lock(&ctx->state_mutex);
Arnd Bergmann8b3d6662005-11-15 15:53:52 -050083 spu_deactivate(ctx);
Christoph Hellwig650f8b02007-02-13 21:36:50 +010084 mutex_unlock(&ctx->state_mutex);
Mark Nutter5473af02005-11-15 15:53:49 -050085 spu_fini_csa(&ctx->csa);
Arnd Bergmann62632032006-10-04 17:26:15 +020086 if (ctx->gang)
87 spu_gang_remove_ctx(ctx->gang, ctx);
Bob Nelson14748552007-07-20 21:39:53 +020088 if (ctx->prof_priv_kref)
89 kref_put(ctx->prof_priv_kref, ctx->prof_priv_release);
Christoph Hellwiga475c2f2007-04-23 21:08:11 +020090 BUG_ON(!list_empty(&ctx->rq));
Christoph Hellwig65de66f2007-06-29 10:58:02 +100091 atomic_dec(&nr_spu_contexts);
Christoph Hellwig5158e9b2008-04-29 17:08:38 +100092 kfree(ctx->switch_log);
Arnd Bergmann67207b92005-11-15 15:53:48 -050093 kfree(ctx);
94}
95
96struct spu_context * get_spu_context(struct spu_context *ctx)
97{
98 kref_get(&ctx->kref);
99 return ctx;
100}
101
102int put_spu_context(struct spu_context *ctx)
103{
104 return kref_put(&ctx->kref, &destroy_spu_context);
105}
106
Arnd Bergmann8b3d6662005-11-15 15:53:52 -0500107/* give up the mm reference when the context is about to be destroyed */
108void spu_forget(struct spu_context *ctx)
109{
110 struct mm_struct *mm;
Christoph Hellwigc9101bd2007-12-20 16:39:59 +0900111
112 /*
113 * This is basically an open-coded spu_acquire_saved, except that
Jeremy Kerr0111a702008-02-27 19:08:13 +1100114 * we don't acquire the state mutex interruptible, and we don't
115 * want this context to be rescheduled on release.
Christoph Hellwigc9101bd2007-12-20 16:39:59 +0900116 */
117 mutex_lock(&ctx->state_mutex);
Jeremy Kerr0111a702008-02-27 19:08:13 +1100118 if (ctx->state != SPU_STATE_SAVED)
Christoph Hellwigc9101bd2007-12-20 16:39:59 +0900119 spu_deactivate(ctx);
Christoph Hellwigc9101bd2007-12-20 16:39:59 +0900120
Arnd Bergmann8b3d6662005-11-15 15:53:52 -0500121 mm = ctx->owner;
122 ctx->owner = NULL;
123 mmput(mm);
124 spu_release(ctx);
125}
Arnd Bergmann67207b92005-11-15 15:53:48 -0500126
Arnd Bergmann51104592005-12-05 22:52:25 -0500127void spu_unmap_mappings(struct spu_context *ctx)
Arnd Bergmann8b3d6662005-11-15 15:53:52 -0500128{
Christoph Hellwig47d3a5f2007-06-04 23:26:51 +1000129 mutex_lock(&ctx->mapping_lock);
Mark Nutter6df10a82006-03-23 00:00:12 +0100130 if (ctx->local_store)
131 unmap_mapping_range(ctx->local_store, 0, LS_SIZE, 1);
132 if (ctx->mfc)
Jeremy Kerr87ff6092008-07-01 10:22:50 +1000133 unmap_mapping_range(ctx->mfc, 0, SPUFS_MFC_MAP_SIZE, 1);
Mark Nutter6df10a82006-03-23 00:00:12 +0100134 if (ctx->cntl)
Jeremy Kerr87ff6092008-07-01 10:22:50 +1000135 unmap_mapping_range(ctx->cntl, 0, SPUFS_CNTL_MAP_SIZE, 1);
Mark Nutter6df10a82006-03-23 00:00:12 +0100136 if (ctx->signal1)
Jeremy Kerr87ff6092008-07-01 10:22:50 +1000137 unmap_mapping_range(ctx->signal1, 0, SPUFS_SIGNAL_MAP_SIZE, 1);
Mark Nutter6df10a82006-03-23 00:00:12 +0100138 if (ctx->signal2)
Jeremy Kerr87ff6092008-07-01 10:22:50 +1000139 unmap_mapping_range(ctx->signal2, 0, SPUFS_SIGNAL_MAP_SIZE, 1);
Benjamin Herrenschmidt17e0e272007-02-13 11:46:08 +1100140 if (ctx->mss)
Jeremy Kerr87ff6092008-07-01 10:22:50 +1000141 unmap_mapping_range(ctx->mss, 0, SPUFS_MSS_MAP_SIZE, 1);
Benjamin Herrenschmidt17e0e272007-02-13 11:46:08 +1100142 if (ctx->psmap)
Jeremy Kerr87ff6092008-07-01 10:22:50 +1000143 unmap_mapping_range(ctx->psmap, 0, SPUFS_PS_MAP_SIZE, 1);
Christoph Hellwig47d3a5f2007-06-04 23:26:51 +1000144 mutex_unlock(&ctx->mapping_lock);
Arnd Bergmann8b3d6662005-11-15 15:53:52 -0500145}
146
Christoph Hellwig6a0641e52007-02-13 21:54:21 +0100147/**
Christoph Hellwig6a0641e52007-02-13 21:54:21 +0100148 * spu_acquire_saved - lock spu contex and make sure it is in saved state
149 * @ctx: spu contex to lock
150 */
Christoph Hellwigc9101bd2007-12-20 16:39:59 +0900151int spu_acquire_saved(struct spu_context *ctx)
Arnd Bergmann8b3d6662005-11-15 15:53:52 -0500152{
Christoph Hellwigc9101bd2007-12-20 16:39:59 +0900153 int ret;
154
Julio M. Merino Vidal3734dfc2008-04-30 15:21:17 +1000155 spu_context_nospu_trace(spu_acquire_saved__enter, ctx);
156
Christoph Hellwigc9101bd2007-12-20 16:39:59 +0900157 ret = spu_acquire(ctx);
158 if (ret)
159 return ret;
160
Christoph Hellwig27b1ea02007-07-20 21:39:34 +0200161 if (ctx->state != SPU_STATE_SAVED) {
162 set_bit(SPU_SCHED_WAS_ACTIVE, &ctx->sched_flags);
Arnd Bergmann8b3d6662005-11-15 15:53:52 -0500163 spu_deactivate(ctx);
Christoph Hellwig27b1ea02007-07-20 21:39:34 +0200164 }
Christoph Hellwigc9101bd2007-12-20 16:39:59 +0900165
166 return 0;
Christoph Hellwig27b1ea02007-07-20 21:39:34 +0200167}
168
169/**
170 * spu_release_saved - unlock spu context and return it to the runqueue
171 * @ctx: context to unlock
172 */
173void spu_release_saved(struct spu_context *ctx)
174{
175 BUG_ON(ctx->state != SPU_STATE_SAVED);
176
Jeremy Kerrc3683922008-03-11 12:46:18 +1100177 if (test_and_clear_bit(SPU_SCHED_WAS_ACTIVE, &ctx->sched_flags) &&
178 test_bit(SPU_SCHED_SPU_RUN, &ctx->sched_flags))
Christoph Hellwig27b1ea02007-07-20 21:39:34 +0200179 spu_activate(ctx, 0);
180
181 spu_release(ctx);
Arnd Bergmann8b3d6662005-11-15 15:53:52 -0500182}
Bob Nelson14748552007-07-20 21:39:53 +0200183