]> err.no Git - linux-2.6/blob - arch/powerpc/platforms/cell/spufs/hw_ops.c
[PATCH] spufs: Improved SPU preemptability.
[linux-2.6] / arch / powerpc / platforms / cell / spufs / hw_ops.c
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 static 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
195 static 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
204 struct 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,
221         .runcntl_write = spu_hw_runcntl_write,
222         .runcntl_stop = spu_hw_runcntl_stop,
223 };