Merge git://git.kernel.org/pub/scm/linux/kernel/git/paulus/powerpc
[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
21#include <linux/config.h>
22#include <linux/module.h>
23#include <linux/errno.h>
24#include <linux/sched.h>
25#include <linux/kernel.h>
26#include <linux/mm.h>
3a843d7c 27#include <linux/poll.h>
8b3d6663
AB
28#include <linux/smp.h>
29#include <linux/smp_lock.h>
30#include <linux/stddef.h>
31#include <linux/unistd.h>
32
33#include <asm/io.h>
34#include <asm/spu.h>
540270d8 35#include <asm/spu_priv1.h>
8b3d6663
AB
36#include <asm/spu_csa.h>
37#include <asm/mmu_context.h>
38#include "spufs.h"
39
40static int spu_hw_mbox_read(struct spu_context *ctx, u32 * data)
41{
42 struct spu *spu = ctx->spu;
43 struct spu_problem __iomem *prob = spu->problem;
44 u32 mbox_stat;
45 int ret = 0;
46
47 spin_lock_irq(&spu->register_lock);
48 mbox_stat = in_be32(&prob->mb_stat_R);
49 if (mbox_stat & 0x0000ff) {
50 *data = in_be32(&prob->pu_mb_R);
51 ret = 4;
52 }
53 spin_unlock_irq(&spu->register_lock);
54 return ret;
55}
56
57static u32 spu_hw_mbox_stat_read(struct spu_context *ctx)
58{
59 return in_be32(&ctx->spu->problem->mb_stat_R);
60}
61
3a843d7c
AB
62static unsigned int spu_hw_mbox_stat_poll(struct spu_context *ctx,
63 unsigned int events)
64{
65 struct spu *spu = ctx->spu;
3a843d7c
AB
66 int ret = 0;
67 u32 stat;
68
69 spin_lock_irq(&spu->register_lock);
70 stat = in_be32(&spu->problem->mb_stat_R);
71
72 /* if the requested event is there, return the poll
73 mask, otherwise enable the interrupt to get notified,
74 but first mark any pending interrupts as done so
75 we don't get woken up unnecessarily */
76
77 if (events & (POLLIN | POLLRDNORM)) {
78 if (stat & 0xff0000)
79 ret |= POLLIN | POLLRDNORM;
80 else {
f0831acc
AB
81 spu_int_stat_clear(spu, 2, 0x1);
82 spu_int_mask_or(spu, 2, 0x1);
3a843d7c
AB
83 }
84 }
85 if (events & (POLLOUT | POLLWRNORM)) {
86 if (stat & 0x00ff00)
87 ret = POLLOUT | POLLWRNORM;
88 else {
f0831acc
AB
89 spu_int_stat_clear(spu, 2, 0x10);
90 spu_int_mask_or(spu, 2, 0x10);
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 */
f0831acc 111 spu_int_mask_or(spu, 2, 0x1);
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 */
f0831acc 132 spu_int_mask_or(spu, 2, 0x10);
8b3d6663
AB
133 ret = 0;
134 }
135 spin_unlock_irq(&spu->register_lock);
136 return ret;
137}
138
139static u32 spu_hw_signal1_read(struct spu_context *ctx)
140{
141 return in_be32(&ctx->spu->problem->signal_notify1);
142}
143
144static void spu_hw_signal1_write(struct spu_context *ctx, u32 data)
145{
146 out_be32(&ctx->spu->problem->signal_notify1, data);
147}
148
149static u32 spu_hw_signal2_read(struct spu_context *ctx)
150{
151 return in_be32(&ctx->spu->problem->signal_notify1);
152}
153
154static void spu_hw_signal2_write(struct spu_context *ctx, u32 data)
155{
156 out_be32(&ctx->spu->problem->signal_notify2, data);
157}
158
159static void spu_hw_signal1_type_set(struct spu_context *ctx, u64 val)
160{
161 struct spu *spu = ctx->spu;
162 struct spu_priv2 __iomem *priv2 = spu->priv2;
163 u64 tmp;
164
165 spin_lock_irq(&spu->register_lock);
166 tmp = in_be64(&priv2->spu_cfg_RW);
167 if (val)
168 tmp |= 1;
169 else
170 tmp &= ~1;
171 out_be64(&priv2->spu_cfg_RW, tmp);
172 spin_unlock_irq(&spu->register_lock);
173}
174
175static u64 spu_hw_signal1_type_get(struct spu_context *ctx)
176{
177 return ((in_be64(&ctx->spu->priv2->spu_cfg_RW) & 1) != 0);
178}
179
180static void spu_hw_signal2_type_set(struct spu_context *ctx, u64 val)
181{
182 struct spu *spu = ctx->spu;
183 struct spu_priv2 __iomem *priv2 = spu->priv2;
184 u64 tmp;
185
186 spin_lock_irq(&spu->register_lock);
187 tmp = in_be64(&priv2->spu_cfg_RW);
188 if (val)
189 tmp |= 2;
190 else
191 tmp &= ~2;
192 out_be64(&priv2->spu_cfg_RW, tmp);
193 spin_unlock_irq(&spu->register_lock);
194}
195
196static u64 spu_hw_signal2_type_get(struct spu_context *ctx)
197{
198 return ((in_be64(&ctx->spu->priv2->spu_cfg_RW) & 2) != 0);
199}
200
201static u32 spu_hw_npc_read(struct spu_context *ctx)
202{
203 return in_be32(&ctx->spu->problem->spu_npc_RW);
204}
205
206static void spu_hw_npc_write(struct spu_context *ctx, u32 val)
207{
208 out_be32(&ctx->spu->problem->spu_npc_RW, val);
209}
210
211static u32 spu_hw_status_read(struct spu_context *ctx)
212{
213 return in_be32(&ctx->spu->problem->spu_status_R);
214}
215
216static char *spu_hw_get_ls(struct spu_context *ctx)
217{
218 return ctx->spu->local_store;
219}
220
5110459f
AB
221static void spu_hw_runcntl_write(struct spu_context *ctx, u32 val)
222{
223 eieio();
224 out_be32(&ctx->spu->problem->spu_runcntl_RW, val);
225}
226
227static void spu_hw_runcntl_stop(struct spu_context *ctx)
228{
229 spin_lock_irq(&ctx->spu->register_lock);
230 out_be32(&ctx->spu->problem->spu_runcntl_RW, SPU_RUNCNTL_STOP);
231 while (in_be32(&ctx->spu->problem->spu_status_R) & SPU_STATUS_RUNNING)
232 cpu_relax();
233 spin_unlock_irq(&ctx->spu->register_lock);
234}
235
a33a7d73
AB
236static int spu_hw_set_mfc_query(struct spu_context * ctx, u32 mask, u32 mode)
237{
238 struct spu_problem *prob = ctx->spu->problem;
239 int ret;
240
241 spin_lock_irq(&ctx->spu->register_lock);
242 ret = -EAGAIN;
243 if (in_be32(&prob->dma_querytype_RW))
244 goto out;
245 ret = 0;
246 out_be32(&prob->dma_querymask_RW, mask);
247 out_be32(&prob->dma_querytype_RW, mode);
248out:
249 spin_unlock_irq(&ctx->spu->register_lock);
250 return ret;
251}
252
253static u32 spu_hw_read_mfc_tagstatus(struct spu_context * ctx)
254{
255 return in_be32(&ctx->spu->problem->dma_tagstatus_R);
256}
257
258static u32 spu_hw_get_mfc_free_elements(struct spu_context *ctx)
259{
260 return in_be32(&ctx->spu->problem->dma_qstatus_R);
261}
262
263static int spu_hw_send_mfc_command(struct spu_context *ctx,
264 struct mfc_dma_command *cmd)
265{
266 u32 status;
267 struct spu_problem *prob = ctx->spu->problem;
268
269 spin_lock_irq(&ctx->spu->register_lock);
270 out_be32(&prob->mfc_lsa_W, cmd->lsa);
271 out_be64(&prob->mfc_ea_W, cmd->ea);
272 out_be32(&prob->mfc_union_W.by32.mfc_size_tag32,
273 cmd->size << 16 | cmd->tag);
274 out_be32(&prob->mfc_union_W.by32.mfc_class_cmd32,
275 cmd->class << 16 | cmd->cmd);
276 status = in_be32(&prob->mfc_union_W.by32.mfc_class_cmd32);
277 spin_unlock_irq(&ctx->spu->register_lock);
278
279 switch (status & 0xffff) {
280 case 0:
281 return 0;
282 case 2:
283 return -EAGAIN;
284 default:
285 return -EINVAL;
286 }
287}
288
8b3d6663
AB
289struct spu_context_ops spu_hw_ops = {
290 .mbox_read = spu_hw_mbox_read,
291 .mbox_stat_read = spu_hw_mbox_stat_read,
3a843d7c 292 .mbox_stat_poll = spu_hw_mbox_stat_poll,
8b3d6663
AB
293 .ibox_read = spu_hw_ibox_read,
294 .wbox_write = spu_hw_wbox_write,
295 .signal1_read = spu_hw_signal1_read,
296 .signal1_write = spu_hw_signal1_write,
297 .signal2_read = spu_hw_signal2_read,
298 .signal2_write = spu_hw_signal2_write,
299 .signal1_type_set = spu_hw_signal1_type_set,
300 .signal1_type_get = spu_hw_signal1_type_get,
301 .signal2_type_set = spu_hw_signal2_type_set,
302 .signal2_type_get = spu_hw_signal2_type_get,
303 .npc_read = spu_hw_npc_read,
304 .npc_write = spu_hw_npc_write,
305 .status_read = spu_hw_status_read,
306 .get_ls = spu_hw_get_ls,
5110459f
AB
307 .runcntl_write = spu_hw_runcntl_write,
308 .runcntl_stop = spu_hw_runcntl_stop,
a33a7d73
AB
309 .set_mfc_query = spu_hw_set_mfc_query,
310 .read_mfc_tagstatus = spu_hw_read_mfc_tagstatus,
311 .get_mfc_free_elements = spu_hw_get_mfc_free_elements,
312 .send_mfc_command = spu_hw_send_mfc_command,
8b3d6663 313};
This page took 0.080261 seconds and 5 git commands to generate.