]>
Commit | Line | Data |
---|---|---|
de6cc651 | 1 | // SPDX-License-Identifier: GPL-2.0-or-later |
8b3d6663 AB |
2 | /* hw_ops.c - query/set operations on active SPU context. |
3 | * | |
4 | * Copyright (C) IBM 2005 | |
5 | * Author: Mark Nutter <mnutter@us.ibm.com> | |
8b3d6663 AB |
6 | */ |
7 | ||
8b3d6663 AB |
8 | #include <linux/errno.h> |
9 | #include <linux/sched.h> | |
10 | #include <linux/kernel.h> | |
11 | #include <linux/mm.h> | |
3a843d7c | 12 | #include <linux/poll.h> |
8b3d6663 | 13 | #include <linux/smp.h> |
8b3d6663 AB |
14 | #include <linux/stddef.h> |
15 | #include <linux/unistd.h> | |
16 | ||
17 | #include <asm/io.h> | |
18 | #include <asm/spu.h> | |
540270d8 | 19 | #include <asm/spu_priv1.h> |
8b3d6663 AB |
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 | ||
8153a5ea | 46 | static __poll_t spu_hw_mbox_stat_poll(struct spu_context *ctx, __poll_t events) |
3a843d7c AB |
47 | { |
48 | struct spu *spu = ctx->spu; | |
8153a5ea | 49 | __poll_t ret = 0; |
3a843d7c AB |
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 | ||
a9a08845 | 60 | if (events & (EPOLLIN | EPOLLRDNORM)) { |
3a843d7c | 61 | if (stat & 0xff0000) |
a9a08845 | 62 | ret |= EPOLLIN | EPOLLRDNORM; |
3a843d7c | 63 | else { |
8af30675 JK |
64 | spu_int_stat_clear(spu, 2, CLASS2_MAILBOX_INTR); |
65 | spu_int_mask_or(spu, 2, CLASS2_ENABLE_MAILBOX_INTR); | |
3a843d7c AB |
66 | } |
67 | } | |
a9a08845 | 68 | if (events & (EPOLLOUT | EPOLLWRNORM)) { |
3a843d7c | 69 | if (stat & 0x00ff00) |
a9a08845 | 70 | ret = EPOLLOUT | EPOLLWRNORM; |
3a843d7c | 71 | else { |
8af30675 JK |
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); | |
3a843d7c AB |
76 | } |
77 | } | |
78 | spin_unlock_irq(&spu->register_lock); | |
79 | return ret; | |
80 | } | |
81 | ||
8b3d6663 AB |
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; | |
8b3d6663 AB |
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 */ | |
8af30675 | 96 | spu_int_mask_or(spu, 2, CLASS2_ENABLE_MAILBOX_INTR); |
8b3d6663 AB |
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; | |
8b3d6663 AB |
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 */ | |
8af30675 | 117 | spu_int_mask_or(spu, 2, CLASS2_ENABLE_MAILBOX_THRESHOLD_INTR); |
8b3d6663 AB |
118 | ret = 0; |
119 | } | |
120 | spin_unlock_irq(&spu->register_lock); | |
121 | return ret; | |
122 | } | |
123 | ||
8b3d6663 AB |
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 | ||
8b3d6663 AB |
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 | ||
cc210b3e LB |
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 | ||
3960c260 JK |
201 | static u32 spu_hw_runcntl_read(struct spu_context *ctx) |
202 | { | |
203 | return in_be32(&ctx->spu->problem->spu_runcntl_RW); | |
204 | } | |
205 | ||
5110459f AB |
206 | static void spu_hw_runcntl_write(struct spu_context *ctx, u32 val) |
207 | { | |
5737edd1 MN |
208 | spin_lock_irq(&ctx->spu->register_lock); |
209 | if (val & SPU_RUNCNTL_ISOLATE) | |
cc210b3e LB |
210 | spu_hw_privcntl_write(ctx, |
211 | SPU_PRIVCNT_LOAD_REQUEST_ENABLE_MASK); | |
5110459f | 212 | out_be32(&ctx->spu->problem->spu_runcntl_RW, val); |
5737edd1 | 213 | spin_unlock_irq(&ctx->spu->register_lock); |
5110459f AB |
214 | } |
215 | ||
c25620d7 MN |
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 | ||
ee2d7340 | 225 | static void spu_hw_master_start(struct spu_context *ctx) |
5110459f | 226 | { |
ee2d7340 AB |
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); | |
5110459f AB |
245 | } |
246 | ||
a33a7d73 AB |
247 | static int spu_hw_set_mfc_query(struct spu_context * ctx, u32 mask, u32 mode) |
248 | { | |
ed2bfcd2 | 249 | struct spu_problem __iomem *prob = ctx->spu->problem; |
a33a7d73 AB |
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; | |
ed2bfcd2 | 278 | struct spu_problem __iomem *prob = ctx->spu->problem; |
a33a7d73 AB |
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 | ||
57dace23 AB |
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 | ||
8b3d6663 AB |
308 | struct spu_context_ops spu_hw_ops = { |
309 | .mbox_read = spu_hw_mbox_read, | |
310 | .mbox_stat_read = spu_hw_mbox_stat_read, | |
3a843d7c | 311 | .mbox_stat_poll = spu_hw_mbox_stat_poll, |
8b3d6663 AB |
312 | .ibox_read = spu_hw_ibox_read, |
313 | .wbox_write = spu_hw_wbox_write, | |
8b3d6663 | 314 | .signal1_write = spu_hw_signal1_write, |
8b3d6663 AB |
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, | |
cc210b3e | 324 | .privcntl_write = spu_hw_privcntl_write, |
3960c260 | 325 | .runcntl_read = spu_hw_runcntl_read, |
5110459f | 326 | .runcntl_write = spu_hw_runcntl_write, |
c25620d7 | 327 | .runcntl_stop = spu_hw_runcntl_stop, |
ee2d7340 AB |
328 | .master_start = spu_hw_master_start, |
329 | .master_stop = spu_hw_master_stop, | |
a33a7d73 AB |
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, | |
57dace23 | 334 | .restart_dma = spu_hw_restart_dma, |
8b3d6663 | 335 | }; |