[POWERPC] spufs: block fault handlers in spu_acquire_runnable
[linux-2.6-block.git] / arch / powerpc / platforms / cell / spufs / hw_ops.c
CommitLineData
8b3d6663
AB
1/* hw_ops.c - query/set operations on active SPU context.
2 *
3 * Copyright (C) IBM 2005
4 * Author: Mark Nutter <mnutter@us.ibm.com>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2, or (at your option)
9 * any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19 */
20
8b3d6663
AB
21#include <linux/module.h>
22#include <linux/errno.h>
23#include <linux/sched.h>
24#include <linux/kernel.h>
25#include <linux/mm.h>
3a843d7c 26#include <linux/poll.h>
8b3d6663 27#include <linux/smp.h>
8b3d6663
AB
28#include <linux/stddef.h>
29#include <linux/unistd.h>
30
31#include <asm/io.h>
32#include <asm/spu.h>
540270d8 33#include <asm/spu_priv1.h>
8b3d6663
AB
34#include <asm/spu_csa.h>
35#include <asm/mmu_context.h>
36#include "spufs.h"
37
38static int spu_hw_mbox_read(struct spu_context *ctx, u32 * data)
39{
40 struct spu *spu = ctx->spu;
41 struct spu_problem __iomem *prob = spu->problem;
42 u32 mbox_stat;
43 int ret = 0;
44
45 spin_lock_irq(&spu->register_lock);
46 mbox_stat = in_be32(&prob->mb_stat_R);
47 if (mbox_stat & 0x0000ff) {
48 *data = in_be32(&prob->pu_mb_R);
49 ret = 4;
50 }
51 spin_unlock_irq(&spu->register_lock);
52 return ret;
53}
54
55static u32 spu_hw_mbox_stat_read(struct spu_context *ctx)
56{
57 return in_be32(&ctx->spu->problem->mb_stat_R);
58}
59
3a843d7c
AB
60static unsigned int spu_hw_mbox_stat_poll(struct spu_context *ctx,
61 unsigned int events)
62{
63 struct spu *spu = ctx->spu;
3a843d7c
AB
64 int ret = 0;
65 u32 stat;
66
67 spin_lock_irq(&spu->register_lock);
68 stat = in_be32(&spu->problem->mb_stat_R);
69
70 /* if the requested event is there, return the poll
71 mask, otherwise enable the interrupt to get notified,
72 but first mark any pending interrupts as done so
73 we don't get woken up unnecessarily */
74
75 if (events & (POLLIN | POLLRDNORM)) {
76 if (stat & 0xff0000)
77 ret |= POLLIN | POLLRDNORM;
78 else {
f0831acc
AB
79 spu_int_stat_clear(spu, 2, 0x1);
80 spu_int_mask_or(spu, 2, 0x1);
3a843d7c
AB
81 }
82 }
83 if (events & (POLLOUT | POLLWRNORM)) {
84 if (stat & 0x00ff00)
85 ret = POLLOUT | POLLWRNORM;
86 else {
f0831acc
AB
87 spu_int_stat_clear(spu, 2, 0x10);
88 spu_int_mask_or(spu, 2, 0x10);
3a843d7c
AB
89 }
90 }
91 spin_unlock_irq(&spu->register_lock);
92 return ret;
93}
94
8b3d6663
AB
95static int spu_hw_ibox_read(struct spu_context *ctx, u32 * data)
96{
97 struct spu *spu = ctx->spu;
98 struct spu_problem __iomem *prob = spu->problem;
8b3d6663
AB
99 struct spu_priv2 __iomem *priv2 = spu->priv2;
100 int ret;
101
102 spin_lock_irq(&spu->register_lock);
103 if (in_be32(&prob->mb_stat_R) & 0xff0000) {
104 /* read the first available word */
105 *data = in_be64(&priv2->puint_mb_R);
106 ret = 4;
107 } else {
108 /* make sure we get woken up by the interrupt */
f0831acc 109 spu_int_mask_or(spu, 2, 0x1);
8b3d6663
AB
110 ret = 0;
111 }
112 spin_unlock_irq(&spu->register_lock);
113 return ret;
114}
115
116static int spu_hw_wbox_write(struct spu_context *ctx, u32 data)
117{
118 struct spu *spu = ctx->spu;
119 struct spu_problem __iomem *prob = spu->problem;
8b3d6663
AB
120 int ret;
121
122 spin_lock_irq(&spu->register_lock);
123 if (in_be32(&prob->mb_stat_R) & 0x00ff00) {
124 /* we have space to write wbox_data to */
125 out_be32(&prob->spu_mb_W, data);
126 ret = 4;
127 } else {
128 /* make sure we get woken up by the interrupt when space
129 becomes available */
f0831acc 130 spu_int_mask_or(spu, 2, 0x10);
8b3d6663
AB
131 ret = 0;
132 }
133 spin_unlock_irq(&spu->register_lock);
134 return ret;
135}
136
8b3d6663
AB
137static void spu_hw_signal1_write(struct spu_context *ctx, u32 data)
138{
139 out_be32(&ctx->spu->problem->signal_notify1, data);
140}
141
8b3d6663
AB
142static void spu_hw_signal2_write(struct spu_context *ctx, u32 data)
143{
144 out_be32(&ctx->spu->problem->signal_notify2, data);
145}
146
147static void spu_hw_signal1_type_set(struct spu_context *ctx, u64 val)
148{
149 struct spu *spu = ctx->spu;
150 struct spu_priv2 __iomem *priv2 = spu->priv2;
151 u64 tmp;
152
153 spin_lock_irq(&spu->register_lock);
154 tmp = in_be64(&priv2->spu_cfg_RW);
155 if (val)
156 tmp |= 1;
157 else
158 tmp &= ~1;
159 out_be64(&priv2->spu_cfg_RW, tmp);
160 spin_unlock_irq(&spu->register_lock);
161}
162
163static u64 spu_hw_signal1_type_get(struct spu_context *ctx)
164{
165 return ((in_be64(&ctx->spu->priv2->spu_cfg_RW) & 1) != 0);
166}
167
168static void spu_hw_signal2_type_set(struct spu_context *ctx, u64 val)
169{
170 struct spu *spu = ctx->spu;
171 struct spu_priv2 __iomem *priv2 = spu->priv2;
172 u64 tmp;
173
174 spin_lock_irq(&spu->register_lock);
175 tmp = in_be64(&priv2->spu_cfg_RW);
176 if (val)
177 tmp |= 2;
178 else
179 tmp &= ~2;
180 out_be64(&priv2->spu_cfg_RW, tmp);
181 spin_unlock_irq(&spu->register_lock);
182}
183
184static u64 spu_hw_signal2_type_get(struct spu_context *ctx)
185{
186 return ((in_be64(&ctx->spu->priv2->spu_cfg_RW) & 2) != 0);
187}
188
189static u32 spu_hw_npc_read(struct spu_context *ctx)
190{
191 return in_be32(&ctx->spu->problem->spu_npc_RW);
192}
193
194static void spu_hw_npc_write(struct spu_context *ctx, u32 val)
195{
196 out_be32(&ctx->spu->problem->spu_npc_RW, val);
197}
198
199static u32 spu_hw_status_read(struct spu_context *ctx)
200{
201 return in_be32(&ctx->spu->problem->spu_status_R);
202}
203
204static char *spu_hw_get_ls(struct spu_context *ctx)
205{
206 return ctx->spu->local_store;
207}
208
3960c260
JK
209static u32 spu_hw_runcntl_read(struct spu_context *ctx)
210{
211 return in_be32(&ctx->spu->problem->spu_runcntl_RW);
212}
213
5110459f
AB
214static void spu_hw_runcntl_write(struct spu_context *ctx, u32 val)
215{
5737edd1
MN
216 spin_lock_irq(&ctx->spu->register_lock);
217 if (val & SPU_RUNCNTL_ISOLATE)
218 out_be64(&ctx->spu->priv2->spu_privcntl_RW, 4LL);
5110459f 219 out_be32(&ctx->spu->problem->spu_runcntl_RW, val);
5737edd1 220 spin_unlock_irq(&ctx->spu->register_lock);
5110459f
AB
221}
222
c25620d7
MN
223static void spu_hw_runcntl_stop(struct spu_context *ctx)
224{
225 spin_lock_irq(&ctx->spu->register_lock);
226 out_be32(&ctx->spu->problem->spu_runcntl_RW, SPU_RUNCNTL_STOP);
227 while (in_be32(&ctx->spu->problem->spu_status_R) & SPU_STATUS_RUNNING)
228 cpu_relax();
229 spin_unlock_irq(&ctx->spu->register_lock);
230}
231
ee2d7340 232static void spu_hw_master_start(struct spu_context *ctx)
5110459f 233{
ee2d7340
AB
234 struct spu *spu = ctx->spu;
235 u64 sr1;
236
237 spin_lock_irq(&spu->register_lock);
238 sr1 = spu_mfc_sr1_get(spu) | MFC_STATE1_MASTER_RUN_CONTROL_MASK;
239 spu_mfc_sr1_set(spu, sr1);
240 spin_unlock_irq(&spu->register_lock);
241}
242
243static void spu_hw_master_stop(struct spu_context *ctx)
244{
245 struct spu *spu = ctx->spu;
246 u64 sr1;
247
248 spin_lock_irq(&spu->register_lock);
249 sr1 = spu_mfc_sr1_get(spu) & ~MFC_STATE1_MASTER_RUN_CONTROL_MASK;
250 spu_mfc_sr1_set(spu, sr1);
251 spin_unlock_irq(&spu->register_lock);
5110459f
AB
252}
253
a33a7d73
AB
254static int spu_hw_set_mfc_query(struct spu_context * ctx, u32 mask, u32 mode)
255{
ed2bfcd2 256 struct spu_problem __iomem *prob = ctx->spu->problem;
a33a7d73
AB
257 int ret;
258
259 spin_lock_irq(&ctx->spu->register_lock);
260 ret = -EAGAIN;
261 if (in_be32(&prob->dma_querytype_RW))
262 goto out;
263 ret = 0;
264 out_be32(&prob->dma_querymask_RW, mask);
265 out_be32(&prob->dma_querytype_RW, mode);
266out:
267 spin_unlock_irq(&ctx->spu->register_lock);
268 return ret;
269}
270
271static u32 spu_hw_read_mfc_tagstatus(struct spu_context * ctx)
272{
273 return in_be32(&ctx->spu->problem->dma_tagstatus_R);
274}
275
276static u32 spu_hw_get_mfc_free_elements(struct spu_context *ctx)
277{
278 return in_be32(&ctx->spu->problem->dma_qstatus_R);
279}
280
281static int spu_hw_send_mfc_command(struct spu_context *ctx,
282 struct mfc_dma_command *cmd)
283{
284 u32 status;
ed2bfcd2 285 struct spu_problem __iomem *prob = ctx->spu->problem;
a33a7d73
AB
286
287 spin_lock_irq(&ctx->spu->register_lock);
288 out_be32(&prob->mfc_lsa_W, cmd->lsa);
289 out_be64(&prob->mfc_ea_W, cmd->ea);
290 out_be32(&prob->mfc_union_W.by32.mfc_size_tag32,
291 cmd->size << 16 | cmd->tag);
292 out_be32(&prob->mfc_union_W.by32.mfc_class_cmd32,
293 cmd->class << 16 | cmd->cmd);
294 status = in_be32(&prob->mfc_union_W.by32.mfc_class_cmd32);
295 spin_unlock_irq(&ctx->spu->register_lock);
296
297 switch (status & 0xffff) {
298 case 0:
299 return 0;
300 case 2:
301 return -EAGAIN;
302 default:
303 return -EINVAL;
304 }
305}
306
57dace23
AB
307static void spu_hw_restart_dma(struct spu_context *ctx)
308{
309 struct spu_priv2 __iomem *priv2 = ctx->spu->priv2;
310
311 if (!test_bit(SPU_CONTEXT_SWITCH_PENDING, &ctx->spu->flags))
312 out_be64(&priv2->mfc_control_RW, MFC_CNTL_RESTART_DMA_COMMAND);
313}
314
8b3d6663
AB
315struct spu_context_ops spu_hw_ops = {
316 .mbox_read = spu_hw_mbox_read,
317 .mbox_stat_read = spu_hw_mbox_stat_read,
3a843d7c 318 .mbox_stat_poll = spu_hw_mbox_stat_poll,
8b3d6663
AB
319 .ibox_read = spu_hw_ibox_read,
320 .wbox_write = spu_hw_wbox_write,
8b3d6663 321 .signal1_write = spu_hw_signal1_write,
8b3d6663
AB
322 .signal2_write = spu_hw_signal2_write,
323 .signal1_type_set = spu_hw_signal1_type_set,
324 .signal1_type_get = spu_hw_signal1_type_get,
325 .signal2_type_set = spu_hw_signal2_type_set,
326 .signal2_type_get = spu_hw_signal2_type_get,
327 .npc_read = spu_hw_npc_read,
328 .npc_write = spu_hw_npc_write,
329 .status_read = spu_hw_status_read,
330 .get_ls = spu_hw_get_ls,
3960c260 331 .runcntl_read = spu_hw_runcntl_read,
5110459f 332 .runcntl_write = spu_hw_runcntl_write,
c25620d7 333 .runcntl_stop = spu_hw_runcntl_stop,
ee2d7340
AB
334 .master_start = spu_hw_master_start,
335 .master_stop = spu_hw_master_stop,
a33a7d73
AB
336 .set_mfc_query = spu_hw_set_mfc_query,
337 .read_mfc_tagstatus = spu_hw_read_mfc_tagstatus,
338 .get_mfc_free_elements = spu_hw_get_mfc_free_elements,
339 .send_mfc_command = spu_hw_send_mfc_command,
57dace23 340 .restart_dma = spu_hw_restart_dma,
8b3d6663 341};