blob: 68812415ee2978888d42446d723377b1e5caa08f [file] [log] [blame]
Arnd Bergmann8b3d6662005-11-15 15:53:52 -05001/* hw_ops.c - query/set operations on active SPU context.
2 *
3 * Copyright (C) IBM 2005
4 * Author: Mark Nutter <mnutter@us.ibm.com>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2, or (at your option)
9 * any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19 */
20
21#include <linux/config.h>
22#include <linux/module.h>
23#include <linux/errno.h>
24#include <linux/sched.h>
25#include <linux/kernel.h>
26#include <linux/mm.h>
27#include <linux/vmalloc.h>
28#include <linux/smp.h>
29#include <linux/smp_lock.h>
30#include <linux/stddef.h>
31#include <linux/unistd.h>
32
33#include <asm/io.h>
34#include <asm/spu.h>
35#include <asm/spu_csa.h>
36#include <asm/mmu_context.h>
37#include "spufs.h"
38
39static int spu_hw_mbox_read(struct spu_context *ctx, u32 * data)
40{
41 struct spu *spu = ctx->spu;
42 struct spu_problem __iomem *prob = spu->problem;
43 u32 mbox_stat;
44 int ret = 0;
45
46 spin_lock_irq(&spu->register_lock);
47 mbox_stat = in_be32(&prob->mb_stat_R);
48 if (mbox_stat & 0x0000ff) {
49 *data = in_be32(&prob->pu_mb_R);
50 ret = 4;
51 }
52 spin_unlock_irq(&spu->register_lock);
53 return ret;
54}
55
56static u32 spu_hw_mbox_stat_read(struct spu_context *ctx)
57{
58 return in_be32(&ctx->spu->problem->mb_stat_R);
59}
60
61static int spu_hw_ibox_read(struct spu_context *ctx, u32 * data)
62{
63 struct spu *spu = ctx->spu;
64 struct spu_problem __iomem *prob = spu->problem;
65 struct spu_priv1 __iomem *priv1 = spu->priv1;
66 struct spu_priv2 __iomem *priv2 = spu->priv2;
67 int ret;
68
69 spin_lock_irq(&spu->register_lock);
70 if (in_be32(&prob->mb_stat_R) & 0xff0000) {
71 /* read the first available word */
72 *data = in_be64(&priv2->puint_mb_R);
73 ret = 4;
74 } else {
75 /* make sure we get woken up by the interrupt */
76 out_be64(&priv1->int_mask_class2_RW,
77 in_be64(&priv1->int_mask_class2_RW) | 0x1);
78 ret = 0;
79 }
80 spin_unlock_irq(&spu->register_lock);
81 return ret;
82}
83
84static int spu_hw_wbox_write(struct spu_context *ctx, u32 data)
85{
86 struct spu *spu = ctx->spu;
87 struct spu_problem __iomem *prob = spu->problem;
88 struct spu_priv1 __iomem *priv1 = spu->priv1;
89 int ret;
90
91 spin_lock_irq(&spu->register_lock);
92 if (in_be32(&prob->mb_stat_R) & 0x00ff00) {
93 /* we have space to write wbox_data to */
94 out_be32(&prob->spu_mb_W, data);
95 ret = 4;
96 } else {
97 /* make sure we get woken up by the interrupt when space
98 becomes available */
99 out_be64(&priv1->int_mask_class2_RW,
100 in_be64(&priv1->int_mask_class2_RW) | 0x10);
101 ret = 0;
102 }
103 spin_unlock_irq(&spu->register_lock);
104 return ret;
105}
106
107static u32 spu_hw_signal1_read(struct spu_context *ctx)
108{
109 return in_be32(&ctx->spu->problem->signal_notify1);
110}
111
112static void spu_hw_signal1_write(struct spu_context *ctx, u32 data)
113{
114 out_be32(&ctx->spu->problem->signal_notify1, data);
115}
116
117static u32 spu_hw_signal2_read(struct spu_context *ctx)
118{
119 return in_be32(&ctx->spu->problem->signal_notify1);
120}
121
122static void spu_hw_signal2_write(struct spu_context *ctx, u32 data)
123{
124 out_be32(&ctx->spu->problem->signal_notify2, data);
125}
126
127static void spu_hw_signal1_type_set(struct spu_context *ctx, u64 val)
128{
129 struct spu *spu = ctx->spu;
130 struct spu_priv2 __iomem *priv2 = spu->priv2;
131 u64 tmp;
132
133 spin_lock_irq(&spu->register_lock);
134 tmp = in_be64(&priv2->spu_cfg_RW);
135 if (val)
136 tmp |= 1;
137 else
138 tmp &= ~1;
139 out_be64(&priv2->spu_cfg_RW, tmp);
140 spin_unlock_irq(&spu->register_lock);
141}
142
143static u64 spu_hw_signal1_type_get(struct spu_context *ctx)
144{
145 return ((in_be64(&ctx->spu->priv2->spu_cfg_RW) & 1) != 0);
146}
147
148static void spu_hw_signal2_type_set(struct spu_context *ctx, u64 val)
149{
150 struct spu *spu = ctx->spu;
151 struct spu_priv2 __iomem *priv2 = spu->priv2;
152 u64 tmp;
153
154 spin_lock_irq(&spu->register_lock);
155 tmp = in_be64(&priv2->spu_cfg_RW);
156 if (val)
157 tmp |= 2;
158 else
159 tmp &= ~2;
160 out_be64(&priv2->spu_cfg_RW, tmp);
161 spin_unlock_irq(&spu->register_lock);
162}
163
164static u64 spu_hw_signal2_type_get(struct spu_context *ctx)
165{
166 return ((in_be64(&ctx->spu->priv2->spu_cfg_RW) & 2) != 0);
167}
168
169static u32 spu_hw_npc_read(struct spu_context *ctx)
170{
171 return in_be32(&ctx->spu->problem->spu_npc_RW);
172}
173
174static void spu_hw_npc_write(struct spu_context *ctx, u32 val)
175{
176 out_be32(&ctx->spu->problem->spu_npc_RW, val);
177}
178
179static u32 spu_hw_status_read(struct spu_context *ctx)
180{
181 return in_be32(&ctx->spu->problem->spu_status_R);
182}
183
184static char *spu_hw_get_ls(struct spu_context *ctx)
185{
186 return ctx->spu->local_store;
187}
188
Arnd Bergmann51104592005-12-05 22:52:25 -0500189static void spu_hw_runcntl_write(struct spu_context *ctx, u32 val)
190{
191 eieio();
192 out_be32(&ctx->spu->problem->spu_runcntl_RW, val);
193}
194
195static void spu_hw_runcntl_stop(struct spu_context *ctx)
196{
197 spin_lock_irq(&ctx->spu->register_lock);
198 out_be32(&ctx->spu->problem->spu_runcntl_RW, SPU_RUNCNTL_STOP);
199 while (in_be32(&ctx->spu->problem->spu_status_R) & SPU_STATUS_RUNNING)
200 cpu_relax();
201 spin_unlock_irq(&ctx->spu->register_lock);
202}
203
Arnd Bergmann8b3d6662005-11-15 15:53:52 -0500204struct spu_context_ops spu_hw_ops = {
205 .mbox_read = spu_hw_mbox_read,
206 .mbox_stat_read = spu_hw_mbox_stat_read,
207 .ibox_read = spu_hw_ibox_read,
208 .wbox_write = spu_hw_wbox_write,
209 .signal1_read = spu_hw_signal1_read,
210 .signal1_write = spu_hw_signal1_write,
211 .signal2_read = spu_hw_signal2_read,
212 .signal2_write = spu_hw_signal2_write,
213 .signal1_type_set = spu_hw_signal1_type_set,
214 .signal1_type_get = spu_hw_signal1_type_get,
215 .signal2_type_set = spu_hw_signal2_type_set,
216 .signal2_type_get = spu_hw_signal2_type_get,
217 .npc_read = spu_hw_npc_read,
218 .npc_write = spu_hw_npc_write,
219 .status_read = spu_hw_status_read,
220 .get_ls = spu_hw_get_ls,
Arnd Bergmann51104592005-12-05 22:52:25 -0500221 .runcntl_write = spu_hw_runcntl_write,
222 .runcntl_stop = spu_hw_runcntl_stop,
Arnd Bergmann8b3d6662005-11-15 15:53:52 -0500223};