1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
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>
26#include <linux/poll.h>
27#include <linux/smp.h>
28#include <linux/stddef.h>
29#include <linux/unistd.h>
30
31#include <asm/io.h>
32#include <asm/spu.h>
33#include <asm/spu_priv1.h>
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
60static unsigned int spu_hw_mbox_stat_poll(struct spu_context *ctx,
61 unsigned int events)
62{
63 struct spu *spu = ctx->spu;
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
71
72
73
74
75 if (events & (POLLIN | POLLRDNORM)) {
76 if (stat & 0xff0000)
77 ret |= POLLIN | POLLRDNORM;
78 else {
79 spu_int_stat_clear(spu, 2, CLASS2_MAILBOX_INTR);
80 spu_int_mask_or(spu, 2, CLASS2_ENABLE_MAILBOX_INTR);
81 }
82 }
83 if (events & (POLLOUT | POLLWRNORM)) {
84 if (stat & 0x00ff00)
85 ret = POLLOUT | POLLWRNORM;
86 else {
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);
91 }
92 }
93 spin_unlock_irq(&spu->register_lock);
94 return ret;
95}
96
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;
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
107 *data = in_be64(&priv2->puint_mb_R);
108 ret = 4;
109 } else {
110
111 spu_int_mask_or(spu, 2, CLASS2_ENABLE_MAILBOX_INTR);
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;
122 int ret;
123
124 spin_lock_irq(&spu->register_lock);
125 if (in_be32(&prob->mb_stat_R) & 0x00ff00) {
126
127 out_be32(&prob->spu_mb_W, data);
128 ret = 4;
129 } else {
130
131
132 spu_int_mask_or(spu, 2, CLASS2_ENABLE_MAILBOX_THRESHOLD_INTR);
133 ret = 0;
134 }
135 spin_unlock_irq(&spu->register_lock);
136 return ret;
137}
138
139static void spu_hw_signal1_write(struct spu_context *ctx, u32 data)
140{
141 out_be32(&ctx->spu->problem->signal_notify1, data);
142}
143
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
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
216static u32 spu_hw_runcntl_read(struct spu_context *ctx)
217{
218 return in_be32(&ctx->spu->problem->spu_runcntl_RW);
219}
220
221static void spu_hw_runcntl_write(struct spu_context *ctx, u32 val)
222{
223 spin_lock_irq(&ctx->spu->register_lock);
224 if (val & SPU_RUNCNTL_ISOLATE)
225 spu_hw_privcntl_write(ctx,
226 SPU_PRIVCNT_LOAD_REQUEST_ENABLE_MASK);
227 out_be32(&ctx->spu->problem->spu_runcntl_RW, val);
228 spin_unlock_irq(&ctx->spu->register_lock);
229}
230
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
240static void spu_hw_master_start(struct spu_context *ctx)
241{
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);
260}
261
262static int spu_hw_set_mfc_query(struct spu_context * ctx, u32 mask, u32 mode)
263{
264 struct spu_problem __iomem *prob = ctx->spu->problem;
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;
293 struct spu_problem __iomem *prob = ctx->spu->problem;
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
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
323struct spu_context_ops spu_hw_ops = {
324 .mbox_read = spu_hw_mbox_read,
325 .mbox_stat_read = spu_hw_mbox_stat_read,
326 .mbox_stat_poll = spu_hw_mbox_stat_poll,
327 .ibox_read = spu_hw_ibox_read,
328 .wbox_write = spu_hw_wbox_write,
329 .signal1_write = spu_hw_signal1_write,
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,
339 .privcntl_write = spu_hw_privcntl_write,
340 .runcntl_read = spu_hw_runcntl_read,
341 .runcntl_write = spu_hw_runcntl_write,
342 .runcntl_stop = spu_hw_runcntl_stop,
343 .master_start = spu_hw_master_start,
344 .master_stop = spu_hw_master_stop,
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,
349 .restart_dma = spu_hw_restart_dma,
350};
351