Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/arch/powerpc/platforms/cell/spufs/backing_ops.c
26498 views
1
// SPDX-License-Identifier: GPL-2.0-or-later
2
/* backing_ops.c - query/set operations on saved SPU context.
3
*
4
* Copyright (C) IBM 2005
5
* Author: Mark Nutter <[email protected]>
6
*
7
* These register operations allow SPUFS to operate on saved
8
* SPU contexts rather than hardware.
9
*/
10
11
#include <linux/errno.h>
12
#include <linux/sched.h>
13
#include <linux/kernel.h>
14
#include <linux/mm.h>
15
#include <linux/vmalloc.h>
16
#include <linux/smp.h>
17
#include <linux/stddef.h>
18
#include <linux/unistd.h>
19
#include <linux/poll.h>
20
21
#include <asm/io.h>
22
#include <asm/spu.h>
23
#include <asm/spu_csa.h>
24
#include <asm/spu_info.h>
25
#include <asm/mmu_context.h>
26
#include "spufs.h"
27
28
/*
29
* Reads/writes to various problem and priv2 registers require
30
* state changes, i.e. generate SPU events, modify channel
31
* counts, etc.
32
*/
33
34
static void gen_spu_event(struct spu_context *ctx, u32 event)
35
{
36
u64 ch0_cnt;
37
u64 ch0_data;
38
u64 ch1_data;
39
40
ch0_cnt = ctx->csa.spu_chnlcnt_RW[0];
41
ch0_data = ctx->csa.spu_chnldata_RW[0];
42
ch1_data = ctx->csa.spu_chnldata_RW[1];
43
ctx->csa.spu_chnldata_RW[0] |= event;
44
if ((ch0_cnt == 0) && !(ch0_data & event) && (ch1_data & event)) {
45
ctx->csa.spu_chnlcnt_RW[0] = 1;
46
}
47
}
48
49
static int spu_backing_mbox_read(struct spu_context *ctx, u32 * data)
50
{
51
u32 mbox_stat;
52
int ret = 0;
53
54
spin_lock(&ctx->csa.register_lock);
55
mbox_stat = ctx->csa.prob.mb_stat_R;
56
if (mbox_stat & 0x0000ff) {
57
/* Read the first available word.
58
* Implementation note: the depth
59
* of pu_mb_R is currently 1.
60
*/
61
*data = ctx->csa.prob.pu_mb_R;
62
ctx->csa.prob.mb_stat_R &= ~(0x0000ff);
63
ctx->csa.spu_chnlcnt_RW[28] = 1;
64
gen_spu_event(ctx, MFC_PU_MAILBOX_AVAILABLE_EVENT);
65
ret = 4;
66
}
67
spin_unlock(&ctx->csa.register_lock);
68
return ret;
69
}
70
71
static u32 spu_backing_mbox_stat_read(struct spu_context *ctx)
72
{
73
return ctx->csa.prob.mb_stat_R;
74
}
75
76
static __poll_t spu_backing_mbox_stat_poll(struct spu_context *ctx,
77
__poll_t events)
78
{
79
__poll_t ret;
80
u32 stat;
81
82
ret = 0;
83
spin_lock_irq(&ctx->csa.register_lock);
84
stat = ctx->csa.prob.mb_stat_R;
85
86
/* if the requested event is there, return the poll
87
mask, otherwise enable the interrupt to get notified,
88
but first mark any pending interrupts as done so
89
we don't get woken up unnecessarily */
90
91
if (events & (EPOLLIN | EPOLLRDNORM)) {
92
if (stat & 0xff0000)
93
ret |= EPOLLIN | EPOLLRDNORM;
94
else {
95
ctx->csa.priv1.int_stat_class2_RW &=
96
~CLASS2_MAILBOX_INTR;
97
ctx->csa.priv1.int_mask_class2_RW |=
98
CLASS2_ENABLE_MAILBOX_INTR;
99
}
100
}
101
if (events & (EPOLLOUT | EPOLLWRNORM)) {
102
if (stat & 0x00ff00)
103
ret = EPOLLOUT | EPOLLWRNORM;
104
else {
105
ctx->csa.priv1.int_stat_class2_RW &=
106
~CLASS2_MAILBOX_THRESHOLD_INTR;
107
ctx->csa.priv1.int_mask_class2_RW |=
108
CLASS2_ENABLE_MAILBOX_THRESHOLD_INTR;
109
}
110
}
111
spin_unlock_irq(&ctx->csa.register_lock);
112
return ret;
113
}
114
115
static int spu_backing_ibox_read(struct spu_context *ctx, u32 * data)
116
{
117
int ret;
118
119
spin_lock(&ctx->csa.register_lock);
120
if (ctx->csa.prob.mb_stat_R & 0xff0000) {
121
/* Read the first available word.
122
* Implementation note: the depth
123
* of puint_mb_R is currently 1.
124
*/
125
*data = ctx->csa.priv2.puint_mb_R;
126
ctx->csa.prob.mb_stat_R &= ~(0xff0000);
127
ctx->csa.spu_chnlcnt_RW[30] = 1;
128
gen_spu_event(ctx, MFC_PU_INT_MAILBOX_AVAILABLE_EVENT);
129
ret = 4;
130
} else {
131
/* make sure we get woken up by the interrupt */
132
ctx->csa.priv1.int_mask_class2_RW |= CLASS2_ENABLE_MAILBOX_INTR;
133
ret = 0;
134
}
135
spin_unlock(&ctx->csa.register_lock);
136
return ret;
137
}
138
139
static int spu_backing_wbox_write(struct spu_context *ctx, u32 data)
140
{
141
int ret;
142
143
spin_lock(&ctx->csa.register_lock);
144
if ((ctx->csa.prob.mb_stat_R) & 0x00ff00) {
145
int slot = ctx->csa.spu_chnlcnt_RW[29];
146
int avail = (ctx->csa.prob.mb_stat_R & 0x00ff00) >> 8;
147
148
/* We have space to write wbox_data.
149
* Implementation note: the depth
150
* of spu_mb_W is currently 4.
151
*/
152
BUG_ON(avail != (4 - slot));
153
ctx->csa.spu_mailbox_data[slot] = data;
154
ctx->csa.spu_chnlcnt_RW[29] = ++slot;
155
ctx->csa.prob.mb_stat_R &= ~(0x00ff00);
156
ctx->csa.prob.mb_stat_R |= (((4 - slot) & 0xff) << 8);
157
gen_spu_event(ctx, MFC_SPU_MAILBOX_WRITTEN_EVENT);
158
ret = 4;
159
} else {
160
/* make sure we get woken up by the interrupt when space
161
becomes available */
162
ctx->csa.priv1.int_mask_class2_RW |=
163
CLASS2_ENABLE_MAILBOX_THRESHOLD_INTR;
164
ret = 0;
165
}
166
spin_unlock(&ctx->csa.register_lock);
167
return ret;
168
}
169
170
static u32 spu_backing_signal1_read(struct spu_context *ctx)
171
{
172
return ctx->csa.spu_chnldata_RW[3];
173
}
174
175
static void spu_backing_signal1_write(struct spu_context *ctx, u32 data)
176
{
177
spin_lock(&ctx->csa.register_lock);
178
if (ctx->csa.priv2.spu_cfg_RW & 0x1)
179
ctx->csa.spu_chnldata_RW[3] |= data;
180
else
181
ctx->csa.spu_chnldata_RW[3] = data;
182
ctx->csa.spu_chnlcnt_RW[3] = 1;
183
gen_spu_event(ctx, MFC_SIGNAL_1_EVENT);
184
spin_unlock(&ctx->csa.register_lock);
185
}
186
187
static u32 spu_backing_signal2_read(struct spu_context *ctx)
188
{
189
return ctx->csa.spu_chnldata_RW[4];
190
}
191
192
static void spu_backing_signal2_write(struct spu_context *ctx, u32 data)
193
{
194
spin_lock(&ctx->csa.register_lock);
195
if (ctx->csa.priv2.spu_cfg_RW & 0x2)
196
ctx->csa.spu_chnldata_RW[4] |= data;
197
else
198
ctx->csa.spu_chnldata_RW[4] = data;
199
ctx->csa.spu_chnlcnt_RW[4] = 1;
200
gen_spu_event(ctx, MFC_SIGNAL_2_EVENT);
201
spin_unlock(&ctx->csa.register_lock);
202
}
203
204
static void spu_backing_signal1_type_set(struct spu_context *ctx, u64 val)
205
{
206
u64 tmp;
207
208
spin_lock(&ctx->csa.register_lock);
209
tmp = ctx->csa.priv2.spu_cfg_RW;
210
if (val)
211
tmp |= 1;
212
else
213
tmp &= ~1;
214
ctx->csa.priv2.spu_cfg_RW = tmp;
215
spin_unlock(&ctx->csa.register_lock);
216
}
217
218
static u64 spu_backing_signal1_type_get(struct spu_context *ctx)
219
{
220
return ((ctx->csa.priv2.spu_cfg_RW & 1) != 0);
221
}
222
223
static void spu_backing_signal2_type_set(struct spu_context *ctx, u64 val)
224
{
225
u64 tmp;
226
227
spin_lock(&ctx->csa.register_lock);
228
tmp = ctx->csa.priv2.spu_cfg_RW;
229
if (val)
230
tmp |= 2;
231
else
232
tmp &= ~2;
233
ctx->csa.priv2.spu_cfg_RW = tmp;
234
spin_unlock(&ctx->csa.register_lock);
235
}
236
237
static u64 spu_backing_signal2_type_get(struct spu_context *ctx)
238
{
239
return ((ctx->csa.priv2.spu_cfg_RW & 2) != 0);
240
}
241
242
static u32 spu_backing_npc_read(struct spu_context *ctx)
243
{
244
return ctx->csa.prob.spu_npc_RW;
245
}
246
247
static void spu_backing_npc_write(struct spu_context *ctx, u32 val)
248
{
249
ctx->csa.prob.spu_npc_RW = val;
250
}
251
252
static u32 spu_backing_status_read(struct spu_context *ctx)
253
{
254
return ctx->csa.prob.spu_status_R;
255
}
256
257
static char *spu_backing_get_ls(struct spu_context *ctx)
258
{
259
return ctx->csa.lscsa->ls;
260
}
261
262
static void spu_backing_privcntl_write(struct spu_context *ctx, u64 val)
263
{
264
ctx->csa.priv2.spu_privcntl_RW = val;
265
}
266
267
static u32 spu_backing_runcntl_read(struct spu_context *ctx)
268
{
269
return ctx->csa.prob.spu_runcntl_RW;
270
}
271
272
static void spu_backing_runcntl_write(struct spu_context *ctx, u32 val)
273
{
274
spin_lock(&ctx->csa.register_lock);
275
ctx->csa.prob.spu_runcntl_RW = val;
276
if (val & SPU_RUNCNTL_RUNNABLE) {
277
ctx->csa.prob.spu_status_R &=
278
~SPU_STATUS_STOPPED_BY_STOP &
279
~SPU_STATUS_STOPPED_BY_HALT &
280
~SPU_STATUS_SINGLE_STEP &
281
~SPU_STATUS_INVALID_INSTR &
282
~SPU_STATUS_INVALID_CH;
283
ctx->csa.prob.spu_status_R |= SPU_STATUS_RUNNING;
284
} else {
285
ctx->csa.prob.spu_status_R &= ~SPU_STATUS_RUNNING;
286
}
287
spin_unlock(&ctx->csa.register_lock);
288
}
289
290
static void spu_backing_runcntl_stop(struct spu_context *ctx)
291
{
292
spu_backing_runcntl_write(ctx, SPU_RUNCNTL_STOP);
293
}
294
295
static void spu_backing_master_start(struct spu_context *ctx)
296
{
297
struct spu_state *csa = &ctx->csa;
298
u64 sr1;
299
300
spin_lock(&csa->register_lock);
301
sr1 = csa->priv1.mfc_sr1_RW | MFC_STATE1_MASTER_RUN_CONTROL_MASK;
302
csa->priv1.mfc_sr1_RW = sr1;
303
spin_unlock(&csa->register_lock);
304
}
305
306
static void spu_backing_master_stop(struct spu_context *ctx)
307
{
308
struct spu_state *csa = &ctx->csa;
309
u64 sr1;
310
311
spin_lock(&csa->register_lock);
312
sr1 = csa->priv1.mfc_sr1_RW & ~MFC_STATE1_MASTER_RUN_CONTROL_MASK;
313
csa->priv1.mfc_sr1_RW = sr1;
314
spin_unlock(&csa->register_lock);
315
}
316
317
static int spu_backing_set_mfc_query(struct spu_context * ctx, u32 mask,
318
u32 mode)
319
{
320
struct spu_problem_collapsed *prob = &ctx->csa.prob;
321
int ret;
322
323
spin_lock(&ctx->csa.register_lock);
324
ret = -EAGAIN;
325
if (prob->dma_querytype_RW)
326
goto out;
327
ret = 0;
328
/* FIXME: what are the side-effects of this? */
329
prob->dma_querymask_RW = mask;
330
prob->dma_querytype_RW = mode;
331
/* In the current implementation, the SPU context is always
332
* acquired in runnable state when new bits are added to the
333
* mask (tagwait), so it's sufficient just to mask
334
* dma_tagstatus_R with the 'mask' parameter here.
335
*/
336
ctx->csa.prob.dma_tagstatus_R &= mask;
337
out:
338
spin_unlock(&ctx->csa.register_lock);
339
340
return ret;
341
}
342
343
static u32 spu_backing_read_mfc_tagstatus(struct spu_context * ctx)
344
{
345
return ctx->csa.prob.dma_tagstatus_R;
346
}
347
348
static u32 spu_backing_get_mfc_free_elements(struct spu_context *ctx)
349
{
350
return ctx->csa.prob.dma_qstatus_R;
351
}
352
353
static int spu_backing_send_mfc_command(struct spu_context *ctx,
354
struct mfc_dma_command *cmd)
355
{
356
int ret;
357
358
spin_lock(&ctx->csa.register_lock);
359
ret = -EAGAIN;
360
/* FIXME: set up priv2->puq */
361
spin_unlock(&ctx->csa.register_lock);
362
363
return ret;
364
}
365
366
static void spu_backing_restart_dma(struct spu_context *ctx)
367
{
368
ctx->csa.priv2.mfc_control_RW |= MFC_CNTL_RESTART_DMA_COMMAND;
369
}
370
371
struct spu_context_ops spu_backing_ops = {
372
.mbox_read = spu_backing_mbox_read,
373
.mbox_stat_read = spu_backing_mbox_stat_read,
374
.mbox_stat_poll = spu_backing_mbox_stat_poll,
375
.ibox_read = spu_backing_ibox_read,
376
.wbox_write = spu_backing_wbox_write,
377
.signal1_read = spu_backing_signal1_read,
378
.signal1_write = spu_backing_signal1_write,
379
.signal2_read = spu_backing_signal2_read,
380
.signal2_write = spu_backing_signal2_write,
381
.signal1_type_set = spu_backing_signal1_type_set,
382
.signal1_type_get = spu_backing_signal1_type_get,
383
.signal2_type_set = spu_backing_signal2_type_set,
384
.signal2_type_get = spu_backing_signal2_type_get,
385
.npc_read = spu_backing_npc_read,
386
.npc_write = spu_backing_npc_write,
387
.status_read = spu_backing_status_read,
388
.get_ls = spu_backing_get_ls,
389
.privcntl_write = spu_backing_privcntl_write,
390
.runcntl_read = spu_backing_runcntl_read,
391
.runcntl_write = spu_backing_runcntl_write,
392
.runcntl_stop = spu_backing_runcntl_stop,
393
.master_start = spu_backing_master_start,
394
.master_stop = spu_backing_master_stop,
395
.set_mfc_query = spu_backing_set_mfc_query,
396
.read_mfc_tagstatus = spu_backing_read_mfc_tagstatus,
397
.get_mfc_free_elements = spu_backing_get_mfc_free_elements,
398
.send_mfc_command = spu_backing_send_mfc_command,
399
.restart_dma = spu_backing_restart_dma,
400
};
401
402