1 /* backing_ops.c - query/set operations on saved SPU context.
3 * Copyright (C) IBM 2005
4 * Author: Mark Nutter <mnutter@us.ibm.com>
6 * These register operations allow SPUFS to operate on saved
7 * SPU contexts rather than hardware.
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2, or (at your option)
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 #include <linux/config.h>
25 #include <linux/module.h>
26 #include <linux/errno.h>
27 #include <linux/sched.h>
28 #include <linux/kernel.h>
30 #include <linux/vmalloc.h>
31 #include <linux/smp.h>
32 #include <linux/smp_lock.h>
33 #include <linux/stddef.h>
34 #include <linux/unistd.h>
38 #include <asm/spu_csa.h>
39 #include <asm/mmu_context.h>
43 * Reads/writes to various problem and priv2 registers require
44 * state changes, i.e. generate SPU events, modify channel
48 static void gen_spu_event(struct spu_context *ctx, u32 event)
54 ch0_cnt = ctx->csa.spu_chnlcnt_RW[0];
55 ch0_data = ctx->csa.spu_chnldata_RW[0];
56 ch1_data = ctx->csa.spu_chnldata_RW[1];
57 ctx->csa.spu_chnldata_RW[0] |= event;
58 if ((ch0_cnt == 0) && !(ch0_data & event) && (ch1_data & event)) {
59 ctx->csa.spu_chnlcnt_RW[0] = 1;
63 static int spu_backing_mbox_read(struct spu_context *ctx, u32 * data)
68 spin_lock(&ctx->csa.register_lock);
69 mbox_stat = ctx->csa.prob.mb_stat_R;
70 if (mbox_stat & 0x0000ff) {
71 /* Read the first available word.
72 * Implementation note: the depth
73 * of pu_mb_R is currently 1.
75 *data = ctx->csa.prob.pu_mb_R;
76 ctx->csa.prob.mb_stat_R &= ~(0x0000ff);
77 ctx->csa.spu_chnlcnt_RW[28] = 1;
78 gen_spu_event(ctx, MFC_PU_MAILBOX_AVAILABLE_EVENT);
81 spin_unlock(&ctx->csa.register_lock);
85 static u32 spu_backing_mbox_stat_read(struct spu_context *ctx)
87 return ctx->csa.prob.mb_stat_R;
90 static int spu_backing_ibox_read(struct spu_context *ctx, u32 * data)
94 spin_lock(&ctx->csa.register_lock);
95 if (ctx->csa.prob.mb_stat_R & 0xff0000) {
96 /* Read the first available word.
97 * Implementation note: the depth
98 * of puint_mb_R is currently 1.
100 *data = ctx->csa.priv2.puint_mb_R;
101 ctx->csa.prob.mb_stat_R &= ~(0xff0000);
102 ctx->csa.spu_chnlcnt_RW[30] = 1;
103 gen_spu_event(ctx, MFC_PU_INT_MAILBOX_AVAILABLE_EVENT);
106 /* make sure we get woken up by the interrupt */
107 ctx->csa.priv1.int_mask_class2_RW |= 0x1UL;
110 spin_unlock(&ctx->csa.register_lock);
114 static int spu_backing_wbox_write(struct spu_context *ctx, u32 data)
118 spin_lock(&ctx->csa.register_lock);
119 if ((ctx->csa.prob.mb_stat_R) & 0x00ff00) {
120 int slot = ctx->csa.spu_chnlcnt_RW[29];
121 int avail = (ctx->csa.prob.mb_stat_R & 0x00ff00) >> 8;
123 /* We have space to write wbox_data.
124 * Implementation note: the depth
125 * of spu_mb_W is currently 4.
127 BUG_ON(avail != (4 - slot));
128 ctx->csa.spu_mailbox_data[slot] = data;
129 ctx->csa.spu_chnlcnt_RW[29] = ++slot;
130 ctx->csa.prob.mb_stat_R = (((4 - slot) & 0xff) << 8);
131 gen_spu_event(ctx, MFC_SPU_MAILBOX_WRITTEN_EVENT);
134 /* make sure we get woken up by the interrupt when space
136 ctx->csa.priv1.int_mask_class2_RW |= 0x10;
139 spin_unlock(&ctx->csa.register_lock);
143 static u32 spu_backing_signal1_read(struct spu_context *ctx)
145 return ctx->csa.spu_chnldata_RW[3];
148 static void spu_backing_signal1_write(struct spu_context *ctx, u32 data)
150 spin_lock(&ctx->csa.register_lock);
151 if (ctx->csa.priv2.spu_cfg_RW & 0x1)
152 ctx->csa.spu_chnldata_RW[3] |= data;
154 ctx->csa.spu_chnldata_RW[3] = data;
155 ctx->csa.spu_chnlcnt_RW[3] = 1;
156 gen_spu_event(ctx, MFC_SIGNAL_1_EVENT);
157 spin_unlock(&ctx->csa.register_lock);
160 static u32 spu_backing_signal2_read(struct spu_context *ctx)
162 return ctx->csa.spu_chnldata_RW[4];
165 static void spu_backing_signal2_write(struct spu_context *ctx, u32 data)
167 spin_lock(&ctx->csa.register_lock);
168 if (ctx->csa.priv2.spu_cfg_RW & 0x2)
169 ctx->csa.spu_chnldata_RW[4] |= data;
171 ctx->csa.spu_chnldata_RW[4] = data;
172 ctx->csa.spu_chnlcnt_RW[4] = 1;
173 gen_spu_event(ctx, MFC_SIGNAL_2_EVENT);
174 spin_unlock(&ctx->csa.register_lock);
177 static void spu_backing_signal1_type_set(struct spu_context *ctx, u64 val)
181 spin_lock(&ctx->csa.register_lock);
182 tmp = ctx->csa.priv2.spu_cfg_RW;
187 ctx->csa.priv2.spu_cfg_RW = tmp;
188 spin_unlock(&ctx->csa.register_lock);
191 static u64 spu_backing_signal1_type_get(struct spu_context *ctx)
193 return ((ctx->csa.priv2.spu_cfg_RW & 1) != 0);
196 static void spu_backing_signal2_type_set(struct spu_context *ctx, u64 val)
200 spin_lock(&ctx->csa.register_lock);
201 tmp = ctx->csa.priv2.spu_cfg_RW;
206 ctx->csa.priv2.spu_cfg_RW = tmp;
207 spin_unlock(&ctx->csa.register_lock);
210 static u64 spu_backing_signal2_type_get(struct spu_context *ctx)
212 return ((ctx->csa.priv2.spu_cfg_RW & 2) != 0);
215 static u32 spu_backing_npc_read(struct spu_context *ctx)
217 return ctx->csa.prob.spu_npc_RW;
220 static void spu_backing_npc_write(struct spu_context *ctx, u32 val)
222 ctx->csa.prob.spu_npc_RW = val;
225 static u32 spu_backing_status_read(struct spu_context *ctx)
227 return ctx->csa.prob.spu_status_R;
230 static char *spu_backing_get_ls(struct spu_context *ctx)
232 return ctx->csa.lscsa->ls;
235 struct spu_context_ops spu_backing_ops = {
236 .mbox_read = spu_backing_mbox_read,
237 .mbox_stat_read = spu_backing_mbox_stat_read,
238 .ibox_read = spu_backing_ibox_read,
239 .wbox_write = spu_backing_wbox_write,
240 .signal1_read = spu_backing_signal1_read,
241 .signal1_write = spu_backing_signal1_write,
242 .signal2_read = spu_backing_signal2_read,
243 .signal2_write = spu_backing_signal2_write,
244 .signal1_type_set = spu_backing_signal1_type_set,
245 .signal1_type_get = spu_backing_signal1_type_get,
246 .signal2_type_set = spu_backing_signal2_type_set,
247 .signal2_type_get = spu_backing_signal2_type_get,
248 .npc_read = spu_backing_npc_read,
249 .npc_write = spu_backing_npc_write,
250 .status_read = spu_backing_status_read,
251 .get_ls = spu_backing_get_ls,