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