[PATCH] spufs: cooperative scheduler support
[pandora-kernel.git] / arch / powerpc / platforms / cell / spufs / backing_ops.c
1 /* backing_ops.c - query/set operations on saved SPU context.
2  *
3  * Copyright (C) IBM 2005
4  * Author: Mark Nutter <mnutter@us.ibm.com>
5  *
6  * These register operations allow SPUFS to operate on saved
7  * SPU contexts rather than hardware.
8  *
9  * This program is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 2, or (at your option)
12  * any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software
21  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22  */
23
24 #include <linux/config.h>
25 #include <linux/module.h>
26 #include <linux/errno.h>
27 #include <linux/sched.h>
28 #include <linux/kernel.h>
29 #include <linux/mm.h>
30 #include <linux/vmalloc.h>
31 #include <linux/smp.h>
32 #include <linux/smp_lock.h>
33 #include <linux/stddef.h>
34 #include <linux/unistd.h>
35
36 #include <asm/io.h>
37 #include <asm/spu.h>
38 #include <asm/spu_csa.h>
39 #include <asm/mmu_context.h>
40 #include "spufs.h"
41
42 /*
43  * Reads/writes to various problem and priv2 registers require
44  * state changes, i.e.  generate SPU events, modify channel
45  * counts, etc.
46  */
47
48 static void gen_spu_event(struct spu_context *ctx, u32 event)
49 {
50         u64 ch0_cnt;
51         u64 ch0_data;
52         u64 ch1_data;
53
54         ch0_cnt = ctx->csa.spu_chnlcnt_RW[0];
55         ch0_data = ctx->csa.spu_chnldata_RW[0];
56         ch1_data = ctx->csa.spu_chnldata_RW[1];
57         ctx->csa.spu_chnldata_RW[0] |= event;
58         if ((ch0_cnt == 0) && !(ch0_data & event) && (ch1_data & event)) {
59                 ctx->csa.spu_chnlcnt_RW[0] = 1;
60         }
61 }
62
63 static int spu_backing_mbox_read(struct spu_context *ctx, u32 * data)
64 {
65         u32 mbox_stat;
66         int ret = 0;
67
68         spin_lock(&ctx->csa.register_lock);
69         mbox_stat = ctx->csa.prob.mb_stat_R;
70         if (mbox_stat & 0x0000ff) {
71                 /* Read the first available word.
72                  * Implementation note: the depth
73                  * of pu_mb_R is currently 1.
74                  */
75                 *data = ctx->csa.prob.pu_mb_R;
76                 ctx->csa.prob.mb_stat_R &= ~(0x0000ff);
77                 ctx->csa.spu_chnlcnt_RW[28] = 1;
78                 gen_spu_event(ctx, MFC_PU_MAILBOX_AVAILABLE_EVENT);
79                 ret = 4;
80         }
81         spin_unlock(&ctx->csa.register_lock);
82         return ret;
83 }
84
85 static u32 spu_backing_mbox_stat_read(struct spu_context *ctx)
86 {
87         return ctx->csa.prob.mb_stat_R;
88 }
89
90 static int spu_backing_ibox_read(struct spu_context *ctx, u32 * data)
91 {
92         int ret;
93
94         spin_lock(&ctx->csa.register_lock);
95         if (ctx->csa.prob.mb_stat_R & 0xff0000) {
96                 /* Read the first available word.
97                  * Implementation note: the depth
98                  * of puint_mb_R is currently 1.
99                  */
100                 *data = ctx->csa.priv2.puint_mb_R;
101                 ctx->csa.prob.mb_stat_R &= ~(0xff0000);
102                 ctx->csa.spu_chnlcnt_RW[30] = 1;
103                 gen_spu_event(ctx, MFC_PU_INT_MAILBOX_AVAILABLE_EVENT);
104                 ret = 4;
105         } else {
106                 /* make sure we get woken up by the interrupt */
107                 ctx->csa.priv1.int_mask_class2_RW |= 0x1UL;
108                 ret = 0;
109         }
110         spin_unlock(&ctx->csa.register_lock);
111         return ret;
112 }
113
114 static int spu_backing_wbox_write(struct spu_context *ctx, u32 data)
115 {
116         int ret;
117
118         spin_lock(&ctx->csa.register_lock);
119         if ((ctx->csa.prob.mb_stat_R) & 0x00ff00) {
120                 int slot = ctx->csa.spu_chnlcnt_RW[29];
121                 int avail = (ctx->csa.prob.mb_stat_R & 0x00ff00) >> 8;
122
123                 /* We have space to write wbox_data.
124                  * Implementation note: the depth
125                  * of spu_mb_W is currently 4.
126                  */
127                 BUG_ON(avail != (4 - slot));
128                 ctx->csa.spu_mailbox_data[slot] = data;
129                 ctx->csa.spu_chnlcnt_RW[29] = ++slot;
130                 ctx->csa.prob.mb_stat_R = (((4 - slot) & 0xff) << 8);
131                 gen_spu_event(ctx, MFC_SPU_MAILBOX_WRITTEN_EVENT);
132                 ret = 4;
133         } else {
134                 /* make sure we get woken up by the interrupt when space
135                    becomes available */
136                 ctx->csa.priv1.int_mask_class2_RW |= 0x10;
137                 ret = 0;
138         }
139         spin_unlock(&ctx->csa.register_lock);
140         return ret;
141 }
142
143 static u32 spu_backing_signal1_read(struct spu_context *ctx)
144 {
145         return ctx->csa.spu_chnldata_RW[3];
146 }
147
148 static void spu_backing_signal1_write(struct spu_context *ctx, u32 data)
149 {
150         spin_lock(&ctx->csa.register_lock);
151         if (ctx->csa.priv2.spu_cfg_RW & 0x1)
152                 ctx->csa.spu_chnldata_RW[3] |= data;
153         else
154                 ctx->csa.spu_chnldata_RW[3] = data;
155         ctx->csa.spu_chnlcnt_RW[3] = 1;
156         gen_spu_event(ctx, MFC_SIGNAL_1_EVENT);
157         spin_unlock(&ctx->csa.register_lock);
158 }
159
160 static u32 spu_backing_signal2_read(struct spu_context *ctx)
161 {
162         return ctx->csa.spu_chnldata_RW[4];
163 }
164
165 static void spu_backing_signal2_write(struct spu_context *ctx, u32 data)
166 {
167         spin_lock(&ctx->csa.register_lock);
168         if (ctx->csa.priv2.spu_cfg_RW & 0x2)
169                 ctx->csa.spu_chnldata_RW[4] |= data;
170         else
171                 ctx->csa.spu_chnldata_RW[4] = data;
172         ctx->csa.spu_chnlcnt_RW[4] = 1;
173         gen_spu_event(ctx, MFC_SIGNAL_2_EVENT);
174         spin_unlock(&ctx->csa.register_lock);
175 }
176
177 static void spu_backing_signal1_type_set(struct spu_context *ctx, u64 val)
178 {
179         u64 tmp;
180
181         spin_lock(&ctx->csa.register_lock);
182         tmp = ctx->csa.priv2.spu_cfg_RW;
183         if (val)
184                 tmp |= 1;
185         else
186                 tmp &= ~1;
187         ctx->csa.priv2.spu_cfg_RW = tmp;
188         spin_unlock(&ctx->csa.register_lock);
189 }
190
191 static u64 spu_backing_signal1_type_get(struct spu_context *ctx)
192 {
193         return ((ctx->csa.priv2.spu_cfg_RW & 1) != 0);
194 }
195
196 static void spu_backing_signal2_type_set(struct spu_context *ctx, u64 val)
197 {
198         u64 tmp;
199
200         spin_lock(&ctx->csa.register_lock);
201         tmp = ctx->csa.priv2.spu_cfg_RW;
202         if (val)
203                 tmp |= 2;
204         else
205                 tmp &= ~2;
206         ctx->csa.priv2.spu_cfg_RW = tmp;
207         spin_unlock(&ctx->csa.register_lock);
208 }
209
210 static u64 spu_backing_signal2_type_get(struct spu_context *ctx)
211 {
212         return ((ctx->csa.priv2.spu_cfg_RW & 2) != 0);
213 }
214
215 static u32 spu_backing_npc_read(struct spu_context *ctx)
216 {
217         return ctx->csa.prob.spu_npc_RW;
218 }
219
220 static void spu_backing_npc_write(struct spu_context *ctx, u32 val)
221 {
222         ctx->csa.prob.spu_npc_RW = val;
223 }
224
225 static u32 spu_backing_status_read(struct spu_context *ctx)
226 {
227         return ctx->csa.prob.spu_status_R;
228 }
229
230 static char *spu_backing_get_ls(struct spu_context *ctx)
231 {
232         return ctx->csa.lscsa->ls;
233 }
234
235 struct spu_context_ops spu_backing_ops = {
236         .mbox_read = spu_backing_mbox_read,
237         .mbox_stat_read = spu_backing_mbox_stat_read,
238         .ibox_read = spu_backing_ibox_read,
239         .wbox_write = spu_backing_wbox_write,
240         .signal1_read = spu_backing_signal1_read,
241         .signal1_write = spu_backing_signal1_write,
242         .signal2_read = spu_backing_signal2_read,
243         .signal2_write = spu_backing_signal2_write,
244         .signal1_type_set = spu_backing_signal1_type_set,
245         .signal1_type_get = spu_backing_signal1_type_get,
246         .signal2_type_set = spu_backing_signal2_type_set,
247         .signal2_type_get = spu_backing_signal2_type_get,
248         .npc_read = spu_backing_npc_read,
249         .npc_write = spu_backing_npc_write,
250         .status_read = spu_backing_status_read,
251         .get_ls = spu_backing_get_ls,
252 };