Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/arch/powerpc/platforms/cell/spufs/hw_ops.c
26498 views
1
// SPDX-License-Identifier: GPL-2.0-or-later
2
/* hw_ops.c - query/set operations on active SPU context.
3
*
4
* Copyright (C) IBM 2005
5
* Author: Mark Nutter <[email protected]>
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
24
static 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
41
static u32 spu_hw_mbox_stat_read(struct spu_context *ctx)
42
{
43
return in_be32(&ctx->spu->problem->mb_stat_R);
44
}
45
46
static __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
/* if the requested event is there, return the poll
56
mask, otherwise enable the interrupt to get notified,
57
but first mark any pending interrupts as done so
58
we don't get woken up unnecessarily */
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
82
static 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
/* read the first available word */
92
*data = in_be64(&priv2->puint_mb_R);
93
ret = 4;
94
} else {
95
/* make sure we get woken up by the interrupt */
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
103
static 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
/* we have space to write wbox_data to */
112
out_be32(&prob->spu_mb_W, data);
113
ret = 4;
114
} else {
115
/* make sure we get woken up by the interrupt when space
116
becomes available */
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
124
static void spu_hw_signal1_write(struct spu_context *ctx, u32 data)
125
{
126
out_be32(&ctx->spu->problem->signal_notify1, data);
127
}
128
129
static void spu_hw_signal2_write(struct spu_context *ctx, u32 data)
130
{
131
out_be32(&ctx->spu->problem->signal_notify2, data);
132
}
133
134
static 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
150
static 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
155
static 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
171
static 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
176
static u32 spu_hw_npc_read(struct spu_context *ctx)
177
{
178
return in_be32(&ctx->spu->problem->spu_npc_RW);
179
}
180
181
static void spu_hw_npc_write(struct spu_context *ctx, u32 val)
182
{
183
out_be32(&ctx->spu->problem->spu_npc_RW, val);
184
}
185
186
static u32 spu_hw_status_read(struct spu_context *ctx)
187
{
188
return in_be32(&ctx->spu->problem->spu_status_R);
189
}
190
191
static char *spu_hw_get_ls(struct spu_context *ctx)
192
{
193
return ctx->spu->local_store;
194
}
195
196
static void spu_hw_privcntl_write(struct spu_context *ctx, u64 val)
197
{
198
out_be64(&ctx->spu->priv2->spu_privcntl_RW, val);
199
}
200
201
static u32 spu_hw_runcntl_read(struct spu_context *ctx)
202
{
203
return in_be32(&ctx->spu->problem->spu_runcntl_RW);
204
}
205
206
static 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
216
static 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
225
static 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
236
static 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
247
static 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);
259
out:
260
spin_unlock_irq(&ctx->spu->register_lock);
261
return ret;
262
}
263
264
static u32 spu_hw_read_mfc_tagstatus(struct spu_context * ctx)
265
{
266
return in_be32(&ctx->spu->problem->dma_tagstatus_R);
267
}
268
269
static u32 spu_hw_get_mfc_free_elements(struct spu_context *ctx)
270
{
271
return in_be32(&ctx->spu->problem->dma_qstatus_R);
272
}
273
274
static 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
300
static 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
308
struct 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
337