1
2
3
4
5
6
7
8#include <linux/errno.h>
9#include <linux/sched.h>
10#include <linux/kernel.h>
11#include <linux/mm.h>
12#include <linux/poll.h>
13#include <linux/smp.h>
14#include <linux/stddef.h>
15#include <linux/unistd.h>
16
17#include <asm/io.h>
18#include <asm/spu.h>
19#include <asm/spu_priv1.h>
20#include <asm/spu_csa.h>
21#include <asm/mmu_context.h>
22#include "spufs.h"
23
24static int spu_hw_mbox_read(struct spu_context *ctx, u32 * data)
25{
26 struct spu *spu = ctx->spu;
27 struct spu_problem __iomem *prob = spu->problem;
28 u32 mbox_stat;
29 int ret = 0;
30
31 spin_lock_irq(&spu->register_lock);
32 mbox_stat = in_be32(&prob->mb_stat_R);
33 if (mbox_stat & 0x0000ff) {
34 *data = in_be32(&prob->pu_mb_R);
35 ret = 4;
36 }
37 spin_unlock_irq(&spu->register_lock);
38 return ret;
39}
40
41static u32 spu_hw_mbox_stat_read(struct spu_context *ctx)
42{
43 return in_be32(&ctx->spu->problem->mb_stat_R);
44}
45
46static __poll_t spu_hw_mbox_stat_poll(struct spu_context *ctx, __poll_t events)
47{
48 struct spu *spu = ctx->spu;
49 __poll_t ret = 0;
50 u32 stat;
51
52 spin_lock_irq(&spu->register_lock);
53 stat = in_be32(&spu->problem->mb_stat_R);
54
55
56
57
58
59
60 if (events & (EPOLLIN | EPOLLRDNORM)) {
61 if (stat & 0xff0000)
62 ret |= EPOLLIN | EPOLLRDNORM;
63 else {
64 spu_int_stat_clear(spu, 2, CLASS2_MAILBOX_INTR);
65 spu_int_mask_or(spu, 2, CLASS2_ENABLE_MAILBOX_INTR);
66 }
67 }
68 if (events & (EPOLLOUT | EPOLLWRNORM)) {
69 if (stat & 0x00ff00)
70 ret = EPOLLOUT | EPOLLWRNORM;
71 else {
72 spu_int_stat_clear(spu, 2,
73 CLASS2_MAILBOX_THRESHOLD_INTR);
74 spu_int_mask_or(spu, 2,
75 CLASS2_ENABLE_MAILBOX_THRESHOLD_INTR);
76 }
77 }
78 spin_unlock_irq(&spu->register_lock);
79 return ret;
80}
81
82static int spu_hw_ibox_read(struct spu_context *ctx, u32 * data)
83{
84 struct spu *spu = ctx->spu;
85 struct spu_problem __iomem *prob = spu->problem;
86 struct spu_priv2 __iomem *priv2 = spu->priv2;
87 int ret;
88
89 spin_lock_irq(&spu->register_lock);
90 if (in_be32(&prob->mb_stat_R) & 0xff0000) {
91
92 *data = in_be64(&priv2->puint_mb_R);
93 ret = 4;
94 } else {
95
96 spu_int_mask_or(spu, 2, CLASS2_ENABLE_MAILBOX_INTR);
97 ret = 0;
98 }
99 spin_unlock_irq(&spu->register_lock);
100 return ret;
101}
102
103static int spu_hw_wbox_write(struct spu_context *ctx, u32 data)
104{
105 struct spu *spu = ctx->spu;
106 struct spu_problem __iomem *prob = spu->problem;
107 int ret;
108
109 spin_lock_irq(&spu->register_lock);
110 if (in_be32(&prob->mb_stat_R) & 0x00ff00) {
111
112 out_be32(&prob->spu_mb_W, data);
113 ret = 4;
114 } else {
115
116
117 spu_int_mask_or(spu, 2, CLASS2_ENABLE_MAILBOX_THRESHOLD_INTR);
118 ret = 0;
119 }
120 spin_unlock_irq(&spu->register_lock);
121 return ret;
122}
123
124static void spu_hw_signal1_write(struct spu_context *ctx, u32 data)
125{
126 out_be32(&ctx->spu->problem->signal_notify1, data);
127}
128
129static void spu_hw_signal2_write(struct spu_context *ctx, u32 data)
130{
131 out_be32(&ctx->spu->problem->signal_notify2, data);
132}
133
134static void spu_hw_signal1_type_set(struct spu_context *ctx, u64 val)
135{
136 struct spu *spu = ctx->spu;
137 struct spu_priv2 __iomem *priv2 = spu->priv2;
138 u64 tmp;
139
140 spin_lock_irq(&spu->register_lock);
141 tmp = in_be64(&priv2->spu_cfg_RW);
142 if (val)
143 tmp |= 1;
144 else
145 tmp &= ~1;
146 out_be64(&priv2->spu_cfg_RW, tmp);
147 spin_unlock_irq(&spu->register_lock);
148}
149
150static u64 spu_hw_signal1_type_get(struct spu_context *ctx)
151{
152 return ((in_be64(&ctx->spu->priv2->spu_cfg_RW) & 1) != 0);
153}
154
155static void spu_hw_signal2_type_set(struct spu_context *ctx, u64 val)
156{
157 struct spu *spu = ctx->spu;
158 struct spu_priv2 __iomem *priv2 = spu->priv2;
159 u64 tmp;
160
161 spin_lock_irq(&spu->register_lock);
162 tmp = in_be64(&priv2->spu_cfg_RW);
163 if (val)
164 tmp |= 2;
165 else
166 tmp &= ~2;
167 out_be64(&priv2->spu_cfg_RW, tmp);
168 spin_unlock_irq(&spu->register_lock);
169}
170
171static u64 spu_hw_signal2_type_get(struct spu_context *ctx)
172{
173 return ((in_be64(&ctx->spu->priv2->spu_cfg_RW) & 2) != 0);
174}
175
176static u32 spu_hw_npc_read(struct spu_context *ctx)
177{
178 return in_be32(&ctx->spu->problem->spu_npc_RW);
179}
180
181static void spu_hw_npc_write(struct spu_context *ctx, u32 val)
182{
183 out_be32(&ctx->spu->problem->spu_npc_RW, val);
184}
185
186static u32 spu_hw_status_read(struct spu_context *ctx)
187{
188 return in_be32(&ctx->spu->problem->spu_status_R);
189}
190
191static char *spu_hw_get_ls(struct spu_context *ctx)
192{
193 return ctx->spu->local_store;
194}
195
196static void spu_hw_privcntl_write(struct spu_context *ctx, u64 val)
197{
198 out_be64(&ctx->spu->priv2->spu_privcntl_RW, val);
199}
200
201static u32 spu_hw_runcntl_read(struct spu_context *ctx)
202{
203 return in_be32(&ctx->spu->problem->spu_runcntl_RW);
204}
205
206static void spu_hw_runcntl_write(struct spu_context *ctx, u32 val)
207{
208 spin_lock_irq(&ctx->spu->register_lock);
209 if (val & SPU_RUNCNTL_ISOLATE)
210 spu_hw_privcntl_write(ctx,
211 SPU_PRIVCNT_LOAD_REQUEST_ENABLE_MASK);
212 out_be32(&ctx->spu->problem->spu_runcntl_RW, val);
213 spin_unlock_irq(&ctx->spu->register_lock);
214}
215
216static void spu_hw_runcntl_stop(struct spu_context *ctx)
217{
218 spin_lock_irq(&ctx->spu->register_lock);
219 out_be32(&ctx->spu->problem->spu_runcntl_RW, SPU_RUNCNTL_STOP);
220 while (in_be32(&ctx->spu->problem->spu_status_R) & SPU_STATUS_RUNNING)
221 cpu_relax();
222 spin_unlock_irq(&ctx->spu->register_lock);
223}
224
225static void spu_hw_master_start(struct spu_context *ctx)
226{
227 struct spu *spu = ctx->spu;
228 u64 sr1;
229
230 spin_lock_irq(&spu->register_lock);
231 sr1 = spu_mfc_sr1_get(spu) | MFC_STATE1_MASTER_RUN_CONTROL_MASK;
232 spu_mfc_sr1_set(spu, sr1);
233 spin_unlock_irq(&spu->register_lock);
234}
235
236static void spu_hw_master_stop(struct spu_context *ctx)
237{
238 struct spu *spu = ctx->spu;
239 u64 sr1;
240
241 spin_lock_irq(&spu->register_lock);
242 sr1 = spu_mfc_sr1_get(spu) & ~MFC_STATE1_MASTER_RUN_CONTROL_MASK;
243 spu_mfc_sr1_set(spu, sr1);
244 spin_unlock_irq(&spu->register_lock);
245}
246
247static int spu_hw_set_mfc_query(struct spu_context * ctx, u32 mask, u32 mode)
248{
249 struct spu_problem __iomem *prob = ctx->spu->problem;
250 int ret;
251
252 spin_lock_irq(&ctx->spu->register_lock);
253 ret = -EAGAIN;
254 if (in_be32(&prob->dma_querytype_RW))
255 goto out;
256 ret = 0;
257 out_be32(&prob->dma_querymask_RW, mask);
258 out_be32(&prob->dma_querytype_RW, mode);
259out:
260 spin_unlock_irq(&ctx->spu->register_lock);
261 return ret;
262}
263
264static u32 spu_hw_read_mfc_tagstatus(struct spu_context * ctx)
265{
266 return in_be32(&ctx->spu->problem->dma_tagstatus_R);
267}
268
269static u32 spu_hw_get_mfc_free_elements(struct spu_context *ctx)
270{
271 return in_be32(&ctx->spu->problem->dma_qstatus_R);
272}
273
274static int spu_hw_send_mfc_command(struct spu_context *ctx,
275 struct mfc_dma_command *cmd)
276{
277 u32 status;
278 struct spu_problem __iomem *prob = ctx->spu->problem;
279
280 spin_lock_irq(&ctx->spu->register_lock);
281 out_be32(&prob->mfc_lsa_W, cmd->lsa);
282 out_be64(&prob->mfc_ea_W, cmd->ea);
283 out_be32(&prob->mfc_union_W.by32.mfc_size_tag32,
284 cmd->size << 16 | cmd->tag);
285 out_be32(&prob->mfc_union_W.by32.mfc_class_cmd32,
286 cmd->class << 16 | cmd->cmd);
287 status = in_be32(&prob->mfc_union_W.by32.mfc_class_cmd32);
288 spin_unlock_irq(&ctx->spu->register_lock);
289
290 switch (status & 0xffff) {
291 case 0:
292 return 0;
293 case 2:
294 return -EAGAIN;
295 default:
296 return -EINVAL;
297 }
298}
299
300static void spu_hw_restart_dma(struct spu_context *ctx)
301{
302 struct spu_priv2 __iomem *priv2 = ctx->spu->priv2;
303
304 if (!test_bit(SPU_CONTEXT_SWITCH_PENDING, &ctx->spu->flags))
305 out_be64(&priv2->mfc_control_RW, MFC_CNTL_RESTART_DMA_COMMAND);
306}
307
308struct spu_context_ops spu_hw_ops = {
309 .mbox_read = spu_hw_mbox_read,
310 .mbox_stat_read = spu_hw_mbox_stat_read,
311 .mbox_stat_poll = spu_hw_mbox_stat_poll,
312 .ibox_read = spu_hw_ibox_read,
313 .wbox_write = spu_hw_wbox_write,
314 .signal1_write = spu_hw_signal1_write,
315 .signal2_write = spu_hw_signal2_write,
316 .signal1_type_set = spu_hw_signal1_type_set,
317 .signal1_type_get = spu_hw_signal1_type_get,
318 .signal2_type_set = spu_hw_signal2_type_set,
319 .signal2_type_get = spu_hw_signal2_type_get,
320 .npc_read = spu_hw_npc_read,
321 .npc_write = spu_hw_npc_write,
322 .status_read = spu_hw_status_read,
323 .get_ls = spu_hw_get_ls,
324 .privcntl_write = spu_hw_privcntl_write,
325 .runcntl_read = spu_hw_runcntl_read,
326 .runcntl_write = spu_hw_runcntl_write,
327 .runcntl_stop = spu_hw_runcntl_stop,
328 .master_start = spu_hw_master_start,
329 .master_stop = spu_hw_master_stop,
330 .set_mfc_query = spu_hw_set_mfc_query,
331 .read_mfc_tagstatus = spu_hw_read_mfc_tagstatus,
332 .get_mfc_free_elements = spu_hw_get_mfc_free_elements,
333 .send_mfc_command = spu_hw_send_mfc_command,
334 .restart_dma = spu_hw_restart_dma,
335};
336