1 | // SPDX-License-Identifier: GPL-2.0-or-later |
2 | /* |
3 | * SPU file system -- SPU context management |
4 | * |
5 | * (C) Copyright IBM Deutschland Entwicklung GmbH 2005 |
6 | * |
7 | * Author: Arnd Bergmann <arndb@de.ibm.com> |
8 | */ |
9 | |
10 | #include <linux/fs.h> |
11 | #include <linux/mm.h> |
12 | #include <linux/slab.h> |
13 | #include <linux/atomic.h> |
14 | #include <linux/sched.h> |
15 | #include <linux/sched/mm.h> |
16 | |
17 | #include <asm/spu.h> |
18 | #include <asm/spu_csa.h> |
19 | #include "spufs.h" |
20 | #include "sputrace.h" |
21 | |
22 | |
23 | atomic_t nr_spu_contexts = ATOMIC_INIT(0); |
24 | |
25 | struct spu_context *alloc_spu_context(struct spu_gang *gang) |
26 | { |
27 | struct spu_context *ctx; |
28 | |
29 | ctx = kzalloc(size: sizeof *ctx, GFP_KERNEL); |
30 | if (!ctx) |
31 | goto out; |
32 | /* Binding to physical processor deferred |
33 | * until spu_activate(). |
34 | */ |
35 | if (spu_init_csa(csa: &ctx->csa)) |
36 | goto out_free; |
37 | spin_lock_init(&ctx->mmio_lock); |
38 | mutex_init(&ctx->mapping_lock); |
39 | kref_init(kref: &ctx->kref); |
40 | mutex_init(&ctx->state_mutex); |
41 | mutex_init(&ctx->run_mutex); |
42 | init_waitqueue_head(&ctx->ibox_wq); |
43 | init_waitqueue_head(&ctx->wbox_wq); |
44 | init_waitqueue_head(&ctx->stop_wq); |
45 | init_waitqueue_head(&ctx->mfc_wq); |
46 | init_waitqueue_head(&ctx->run_wq); |
47 | ctx->state = SPU_STATE_SAVED; |
48 | ctx->ops = &spu_backing_ops; |
49 | ctx->owner = get_task_mm(current); |
50 | INIT_LIST_HEAD(list: &ctx->rq); |
51 | INIT_LIST_HEAD(list: &ctx->aff_list); |
52 | if (gang) |
53 | spu_gang_add_ctx(gang, ctx); |
54 | |
55 | __spu_update_sched_info(ctx); |
56 | spu_set_timeslice(ctx); |
57 | ctx->stats.util_state = SPU_UTIL_IDLE_LOADED; |
58 | ctx->stats.tstamp = ktime_get_ns(); |
59 | |
60 | atomic_inc(v: &nr_spu_contexts); |
61 | goto out; |
62 | out_free: |
63 | kfree(objp: ctx); |
64 | ctx = NULL; |
65 | out: |
66 | return ctx; |
67 | } |
68 | |
69 | void destroy_spu_context(struct kref *kref) |
70 | { |
71 | struct spu_context *ctx; |
72 | ctx = container_of(kref, struct spu_context, kref); |
73 | spu_context_nospu_trace(destroy_spu_context__enter, ctx); |
74 | mutex_lock(&ctx->state_mutex); |
75 | spu_deactivate(ctx); |
76 | mutex_unlock(lock: &ctx->state_mutex); |
77 | spu_fini_csa(csa: &ctx->csa); |
78 | if (ctx->gang) |
79 | spu_gang_remove_ctx(gang: ctx->gang, ctx); |
80 | if (ctx->prof_priv_kref) |
81 | kref_put(kref: ctx->prof_priv_kref, release: ctx->prof_priv_release); |
82 | BUG_ON(!list_empty(&ctx->rq)); |
83 | atomic_dec(v: &nr_spu_contexts); |
84 | kfree(objp: ctx->switch_log); |
85 | kfree(objp: ctx); |
86 | } |
87 | |
88 | struct spu_context * get_spu_context(struct spu_context *ctx) |
89 | { |
90 | kref_get(kref: &ctx->kref); |
91 | return ctx; |
92 | } |
93 | |
94 | int put_spu_context(struct spu_context *ctx) |
95 | { |
96 | return kref_put(kref: &ctx->kref, release: &destroy_spu_context); |
97 | } |
98 | |
99 | /* give up the mm reference when the context is about to be destroyed */ |
100 | void spu_forget(struct spu_context *ctx) |
101 | { |
102 | struct mm_struct *mm; |
103 | |
104 | /* |
105 | * This is basically an open-coded spu_acquire_saved, except that |
106 | * we don't acquire the state mutex interruptible, and we don't |
107 | * want this context to be rescheduled on release. |
108 | */ |
109 | mutex_lock(&ctx->state_mutex); |
110 | if (ctx->state != SPU_STATE_SAVED) |
111 | spu_deactivate(ctx); |
112 | |
113 | mm = ctx->owner; |
114 | ctx->owner = NULL; |
115 | mmput(mm); |
116 | spu_release(ctx); |
117 | } |
118 | |
119 | void spu_unmap_mappings(struct spu_context *ctx) |
120 | { |
121 | mutex_lock(&ctx->mapping_lock); |
122 | if (ctx->local_store) |
123 | unmap_mapping_range(mapping: ctx->local_store, holebegin: 0, holelen: LS_SIZE, even_cows: 1); |
124 | if (ctx->mfc) |
125 | unmap_mapping_range(mapping: ctx->mfc, holebegin: 0, SPUFS_MFC_MAP_SIZE, even_cows: 1); |
126 | if (ctx->cntl) |
127 | unmap_mapping_range(mapping: ctx->cntl, holebegin: 0, SPUFS_CNTL_MAP_SIZE, even_cows: 1); |
128 | if (ctx->signal1) |
129 | unmap_mapping_range(mapping: ctx->signal1, holebegin: 0, SPUFS_SIGNAL_MAP_SIZE, even_cows: 1); |
130 | if (ctx->signal2) |
131 | unmap_mapping_range(mapping: ctx->signal2, holebegin: 0, SPUFS_SIGNAL_MAP_SIZE, even_cows: 1); |
132 | if (ctx->mss) |
133 | unmap_mapping_range(mapping: ctx->mss, holebegin: 0, SPUFS_MSS_MAP_SIZE, even_cows: 1); |
134 | if (ctx->psmap) |
135 | unmap_mapping_range(mapping: ctx->psmap, holebegin: 0, SPUFS_PS_MAP_SIZE, even_cows: 1); |
136 | mutex_unlock(lock: &ctx->mapping_lock); |
137 | } |
138 | |
139 | /** |
140 | * spu_acquire_saved - lock spu contex and make sure it is in saved state |
141 | * @ctx: spu contex to lock |
142 | */ |
143 | int spu_acquire_saved(struct spu_context *ctx) |
144 | { |
145 | int ret; |
146 | |
147 | spu_context_nospu_trace(spu_acquire_saved__enter, ctx); |
148 | |
149 | ret = spu_acquire(ctx); |
150 | if (ret) |
151 | return ret; |
152 | |
153 | if (ctx->state != SPU_STATE_SAVED) { |
154 | set_bit(nr: SPU_SCHED_WAS_ACTIVE, addr: &ctx->sched_flags); |
155 | spu_deactivate(ctx); |
156 | } |
157 | |
158 | return 0; |
159 | } |
160 | |
161 | /** |
162 | * spu_release_saved - unlock spu context and return it to the runqueue |
163 | * @ctx: context to unlock |
164 | */ |
165 | void spu_release_saved(struct spu_context *ctx) |
166 | { |
167 | BUG_ON(ctx->state != SPU_STATE_SAVED); |
168 | |
169 | if (test_and_clear_bit(nr: SPU_SCHED_WAS_ACTIVE, addr: &ctx->sched_flags) && |
170 | test_bit(SPU_SCHED_SPU_RUN, &ctx->sched_flags)) |
171 | spu_activate(ctx, flags: 0); |
172 | |
173 | spu_release(ctx); |
174 | } |
175 | |
176 | |