1 /* 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 
39 static 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 
56 static u32 spu_hw_mbox_stat_read(struct spu_context *ctx)
57 {
58 	return in_be32(&ctx->spu->problem->mb_stat_R);
59 }
60 
61 static 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 
84 static 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 
107 static u32 spu_hw_signal1_read(struct spu_context *ctx)
108 {
109 	return in_be32(&ctx->spu->problem->signal_notify1);
110 }
111 
112 static void spu_hw_signal1_write(struct spu_context *ctx, u32 data)
113 {
114 	out_be32(&ctx->spu->problem->signal_notify1, data);
115 }
116 
117 static u32 spu_hw_signal2_read(struct spu_context *ctx)
118 {
119 	return in_be32(&ctx->spu->problem->signal_notify1);
120 }
121 
122 static void spu_hw_signal2_write(struct spu_context *ctx, u32 data)
123 {
124 	out_be32(&ctx->spu->problem->signal_notify2, data);
125 }
126 
127 static 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 
143 static 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 
148 static 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 
164 static 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 
169 static u32 spu_hw_npc_read(struct spu_context *ctx)
170 {
171 	return in_be32(&ctx->spu->problem->spu_npc_RW);
172 }
173 
174 static void spu_hw_npc_write(struct spu_context *ctx, u32 val)
175 {
176 	out_be32(&ctx->spu->problem->spu_npc_RW, val);
177 }
178 
179 static u32 spu_hw_status_read(struct spu_context *ctx)
180 {
181 	return in_be32(&ctx->spu->problem->spu_status_R);
182 }
183 
184 static char *spu_hw_get_ls(struct spu_context *ctx)
185 {
186 	return ctx->spu->local_store;
187 }
188 
189 struct spu_context_ops spu_hw_ops = {
190 	.mbox_read = spu_hw_mbox_read,
191 	.mbox_stat_read = spu_hw_mbox_stat_read,
192 	.ibox_read = spu_hw_ibox_read,
193 	.wbox_write = spu_hw_wbox_write,
194 	.signal1_read = spu_hw_signal1_read,
195 	.signal1_write = spu_hw_signal1_write,
196 	.signal2_read = spu_hw_signal2_read,
197 	.signal2_write = spu_hw_signal2_write,
198 	.signal1_type_set = spu_hw_signal1_type_set,
199 	.signal1_type_get = spu_hw_signal1_type_get,
200 	.signal2_type_set = spu_hw_signal2_type_set,
201 	.signal2_type_get = spu_hw_signal2_type_get,
202 	.npc_read = spu_hw_npc_read,
203 	.npc_write = spu_hw_npc_write,
204 	.status_read = spu_hw_status_read,
205 	.get_ls = spu_hw_get_ls,
206 };
207