Merge git://git.infradead.org/mtd-2.6
[deliverable/linux.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 {
8af30675
JK
79 spu_int_stat_clear(spu, 2, CLASS2_MAILBOX_INTR);
80 spu_int_mask_or(spu, 2, CLASS2_ENABLE_MAILBOX_INTR);
3a843d7c
AB
81 }
82 }
83 if (events & (POLLOUT | POLLWRNORM)) {
84 if (stat & 0x00ff00)
85 ret = POLLOUT | POLLWRNORM;
86 else {
8af30675
JK
87 spu_int_stat_clear(spu, 2,
88 CLASS2_MAILBOX_THRESHOLD_INTR);
89 spu_int_mask_or(spu, 2,
90 CLASS2_ENABLE_MAILBOX_THRESHOLD_INTR);
3a843d7c
AB
91 }
92 }
93 spin_unlock_irq(&spu->register_lock);
94 return ret;
95}
96
8b3d6663
AB
97static int spu_hw_ibox_read(struct spu_context *ctx, u32 * data)
98{
99 struct spu *spu = ctx->spu;
100 struct spu_problem __iomem *prob = spu->problem;
8b3d6663
AB
101 struct spu_priv2 __iomem *priv2 = spu->priv2;
102 int ret;
103
104 spin_lock_irq(&spu->register_lock);
105 if (in_be32(&prob->mb_stat_R) & 0xff0000) {
106 /* read the first available word */
107 *data = in_be64(&priv2->puint_mb_R);
108 ret = 4;
109 } else {
110 /* make sure we get woken up by the interrupt */
8af30675 111 spu_int_mask_or(spu, 2, CLASS2_ENABLE_MAILBOX_INTR);
8b3d6663
AB
112 ret = 0;
113 }
114 spin_unlock_irq(&spu->register_lock);
115 return ret;
116}
117
118static int spu_hw_wbox_write(struct spu_context *ctx, u32 data)
119{
120 struct spu *spu = ctx->spu;
121 struct spu_problem __iomem *prob = spu->problem;
8b3d6663
AB
122 int ret;
123
124 spin_lock_irq(&spu->register_lock);
125 if (in_be32(&prob->mb_stat_R) & 0x00ff00) {
126 /* we have space to write wbox_data to */
127 out_be32(&prob->spu_mb_W, data);
128 ret = 4;
129 } else {
130 /* make sure we get woken up by the interrupt when space
131 becomes available */
8af30675 132 spu_int_mask_or(spu, 2, CLASS2_ENABLE_MAILBOX_THRESHOLD_INTR);
8b3d6663
AB
133 ret = 0;
134 }
135 spin_unlock_irq(&spu->register_lock);
136 return ret;
137}
138
8b3d6663
AB
139static void spu_hw_signal1_write(struct spu_context *ctx, u32 data)
140{
141 out_be32(&ctx->spu->problem->signal_notify1, data);
142}
143
8b3d6663
AB
144static void spu_hw_signal2_write(struct spu_context *ctx, u32 data)
145{
146 out_be32(&ctx->spu->problem->signal_notify2, data);
147}
148
149static void spu_hw_signal1_type_set(struct spu_context *ctx, u64 val)
150{
151 struct spu *spu = ctx->spu;
152 struct spu_priv2 __iomem *priv2 = spu->priv2;
153 u64 tmp;
154
155 spin_lock_irq(&spu->register_lock);
156 tmp = in_be64(&priv2->spu_cfg_RW);
157 if (val)
158 tmp |= 1;
159 else
160 tmp &= ~1;
161 out_be64(&priv2->spu_cfg_RW, tmp);
162 spin_unlock_irq(&spu->register_lock);
163}
164
165static u64 spu_hw_signal1_type_get(struct spu_context *ctx)
166{
167 return ((in_be64(&ctx->spu->priv2->spu_cfg_RW) & 1) != 0);
168}
169
170static void spu_hw_signal2_type_set(struct spu_context *ctx, u64 val)
171{
172 struct spu *spu = ctx->spu;
173 struct spu_priv2 __iomem *priv2 = spu->priv2;
174 u64 tmp;
175
176 spin_lock_irq(&spu->register_lock);
177 tmp = in_be64(&priv2->spu_cfg_RW);
178 if (val)
179 tmp |= 2;
180 else
181 tmp &= ~2;
182 out_be64(&priv2->spu_cfg_RW, tmp);
183 spin_unlock_irq(&spu->register_lock);
184}
185
186static u64 spu_hw_signal2_type_get(struct spu_context *ctx)
187{
188 return ((in_be64(&ctx->spu->priv2->spu_cfg_RW) & 2) != 0);
189}
190
191static u32 spu_hw_npc_read(struct spu_context *ctx)
192{
193 return in_be32(&ctx->spu->problem->spu_npc_RW);
194}
195
196static void spu_hw_npc_write(struct spu_context *ctx, u32 val)
197{
198 out_be32(&ctx->spu->problem->spu_npc_RW, val);
199}
200
201static u32 spu_hw_status_read(struct spu_context *ctx)
202{
203 return in_be32(&ctx->spu->problem->spu_status_R);
204}
205
206static char *spu_hw_get_ls(struct spu_context *ctx)
207{
208 return ctx->spu->local_store;
209}
210
cc210b3e
LB
211static void spu_hw_privcntl_write(struct spu_context *ctx, u64 val)
212{
213 out_be64(&ctx->spu->priv2->spu_privcntl_RW, val);
214}
215
3960c260
JK
216static u32 spu_hw_runcntl_read(struct spu_context *ctx)
217{
218 return in_be32(&ctx->spu->problem->spu_runcntl_RW);
219}
220
5110459f
AB
221static void spu_hw_runcntl_write(struct spu_context *ctx, u32 val)
222{
5737edd1
MN
223 spin_lock_irq(&ctx->spu->register_lock);
224 if (val & SPU_RUNCNTL_ISOLATE)
cc210b3e
LB
225 spu_hw_privcntl_write(ctx,
226 SPU_PRIVCNT_LOAD_REQUEST_ENABLE_MASK);
5110459f 227 out_be32(&ctx->spu->problem->spu_runcntl_RW, val);
5737edd1 228 spin_unlock_irq(&ctx->spu->register_lock);
5110459f
AB
229}
230
c25620d7
MN
231static void spu_hw_runcntl_stop(struct spu_context *ctx)
232{
233 spin_lock_irq(&ctx->spu->register_lock);
234 out_be32(&ctx->spu->problem->spu_runcntl_RW, SPU_RUNCNTL_STOP);
235 while (in_be32(&ctx->spu->problem->spu_status_R) & SPU_STATUS_RUNNING)
236 cpu_relax();
237 spin_unlock_irq(&ctx->spu->register_lock);
238}
239
ee2d7340 240static void spu_hw_master_start(struct spu_context *ctx)
5110459f 241{
ee2d7340
AB
242 struct spu *spu = ctx->spu;
243 u64 sr1;
244
245 spin_lock_irq(&spu->register_lock);
246 sr1 = spu_mfc_sr1_get(spu) | MFC_STATE1_MASTER_RUN_CONTROL_MASK;
247 spu_mfc_sr1_set(spu, sr1);
248 spin_unlock_irq(&spu->register_lock);
249}
250
251static void spu_hw_master_stop(struct spu_context *ctx)
252{
253 struct spu *spu = ctx->spu;
254 u64 sr1;
255
256 spin_lock_irq(&spu->register_lock);
257 sr1 = spu_mfc_sr1_get(spu) & ~MFC_STATE1_MASTER_RUN_CONTROL_MASK;
258 spu_mfc_sr1_set(spu, sr1);
259 spin_unlock_irq(&spu->register_lock);
5110459f
AB
260}
261
a33a7d73
AB
262static int spu_hw_set_mfc_query(struct spu_context * ctx, u32 mask, u32 mode)
263{
ed2bfcd2 264 struct spu_problem __iomem *prob = ctx->spu->problem;
a33a7d73
AB
265 int ret;
266
267 spin_lock_irq(&ctx->spu->register_lock);
268 ret = -EAGAIN;
269 if (in_be32(&prob->dma_querytype_RW))
270 goto out;
271 ret = 0;
272 out_be32(&prob->dma_querymask_RW, mask);
273 out_be32(&prob->dma_querytype_RW, mode);
274out:
275 spin_unlock_irq(&ctx->spu->register_lock);
276 return ret;
277}
278
279static u32 spu_hw_read_mfc_tagstatus(struct spu_context * ctx)
280{
281 return in_be32(&ctx->spu->problem->dma_tagstatus_R);
282}
283
284static u32 spu_hw_get_mfc_free_elements(struct spu_context *ctx)
285{
286 return in_be32(&ctx->spu->problem->dma_qstatus_R);
287}
288
289static int spu_hw_send_mfc_command(struct spu_context *ctx,
290 struct mfc_dma_command *cmd)
291{
292 u32 status;
ed2bfcd2 293 struct spu_problem __iomem *prob = ctx->spu->problem;
a33a7d73
AB
294
295 spin_lock_irq(&ctx->spu->register_lock);
296 out_be32(&prob->mfc_lsa_W, cmd->lsa);
297 out_be64(&prob->mfc_ea_W, cmd->ea);
298 out_be32(&prob->mfc_union_W.by32.mfc_size_tag32,
299 cmd->size << 16 | cmd->tag);
300 out_be32(&prob->mfc_union_W.by32.mfc_class_cmd32,
301 cmd->class << 16 | cmd->cmd);
302 status = in_be32(&prob->mfc_union_W.by32.mfc_class_cmd32);
303 spin_unlock_irq(&ctx->spu->register_lock);
304
305 switch (status & 0xffff) {
306 case 0:
307 return 0;
308 case 2:
309 return -EAGAIN;
310 default:
311 return -EINVAL;
312 }
313}
314
57dace23
AB
315static void spu_hw_restart_dma(struct spu_context *ctx)
316{
317 struct spu_priv2 __iomem *priv2 = ctx->spu->priv2;
318
319 if (!test_bit(SPU_CONTEXT_SWITCH_PENDING, &ctx->spu->flags))
320 out_be64(&priv2->mfc_control_RW, MFC_CNTL_RESTART_DMA_COMMAND);
321}
322
8b3d6663
AB
323struct spu_context_ops spu_hw_ops = {
324 .mbox_read = spu_hw_mbox_read,
325 .mbox_stat_read = spu_hw_mbox_stat_read,
3a843d7c 326 .mbox_stat_poll = spu_hw_mbox_stat_poll,
8b3d6663
AB
327 .ibox_read = spu_hw_ibox_read,
328 .wbox_write = spu_hw_wbox_write,
8b3d6663 329 .signal1_write = spu_hw_signal1_write,
8b3d6663
AB
330 .signal2_write = spu_hw_signal2_write,
331 .signal1_type_set = spu_hw_signal1_type_set,
332 .signal1_type_get = spu_hw_signal1_type_get,
333 .signal2_type_set = spu_hw_signal2_type_set,
334 .signal2_type_get = spu_hw_signal2_type_get,
335 .npc_read = spu_hw_npc_read,
336 .npc_write = spu_hw_npc_write,
337 .status_read = spu_hw_status_read,
338 .get_ls = spu_hw_get_ls,
cc210b3e 339 .privcntl_write = spu_hw_privcntl_write,
3960c260 340 .runcntl_read = spu_hw_runcntl_read,
5110459f 341 .runcntl_write = spu_hw_runcntl_write,
c25620d7 342 .runcntl_stop = spu_hw_runcntl_stop,
ee2d7340
AB
343 .master_start = spu_hw_master_start,
344 .master_stop = spu_hw_master_stop,
a33a7d73
AB
345 .set_mfc_query = spu_hw_set_mfc_query,
346 .read_mfc_tagstatus = spu_hw_read_mfc_tagstatus,
347 .get_mfc_free_elements = spu_hw_get_mfc_free_elements,
348 .send_mfc_command = spu_hw_send_mfc_command,
57dace23 349 .restart_dma = spu_hw_restart_dma,
8b3d6663 350};
This page took 0.458708 seconds and 5 git commands to generate.