18b3d6663SArnd Bergmann /* hw_ops.c - query/set operations on active SPU context.
28b3d6663SArnd Bergmann  *
38b3d6663SArnd Bergmann  * Copyright (C) IBM 2005
48b3d6663SArnd Bergmann  * Author: Mark Nutter <mnutter@us.ibm.com>
58b3d6663SArnd Bergmann  *
68b3d6663SArnd Bergmann  * This program is free software; you can redistribute it and/or modify
78b3d6663SArnd Bergmann  * it under the terms of the GNU General Public License as published by
88b3d6663SArnd Bergmann  * the Free Software Foundation; either version 2, or (at your option)
98b3d6663SArnd Bergmann  * any later version.
108b3d6663SArnd Bergmann  *
118b3d6663SArnd Bergmann  * This program is distributed in the hope that it will be useful,
128b3d6663SArnd Bergmann  * but WITHOUT ANY WARRANTY; without even the implied warranty of
138b3d6663SArnd Bergmann  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
148b3d6663SArnd Bergmann  * GNU General Public License for more details.
158b3d6663SArnd Bergmann  *
168b3d6663SArnd Bergmann  * You should have received a copy of the GNU General Public License
178b3d6663SArnd Bergmann  * along with this program; if not, write to the Free Software
188b3d6663SArnd Bergmann  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
198b3d6663SArnd Bergmann  */
208b3d6663SArnd Bergmann 
218b3d6663SArnd Bergmann #include <linux/config.h>
228b3d6663SArnd Bergmann #include <linux/module.h>
238b3d6663SArnd Bergmann #include <linux/errno.h>
248b3d6663SArnd Bergmann #include <linux/sched.h>
258b3d6663SArnd Bergmann #include <linux/kernel.h>
268b3d6663SArnd Bergmann #include <linux/mm.h>
278b3d6663SArnd Bergmann #include <linux/vmalloc.h>
288b3d6663SArnd Bergmann #include <linux/smp.h>
298b3d6663SArnd Bergmann #include <linux/smp_lock.h>
308b3d6663SArnd Bergmann #include <linux/stddef.h>
318b3d6663SArnd Bergmann #include <linux/unistd.h>
328b3d6663SArnd Bergmann 
338b3d6663SArnd Bergmann #include <asm/io.h>
348b3d6663SArnd Bergmann #include <asm/spu.h>
358b3d6663SArnd Bergmann #include <asm/spu_csa.h>
368b3d6663SArnd Bergmann #include <asm/mmu_context.h>
378b3d6663SArnd Bergmann #include "spufs.h"
388b3d6663SArnd Bergmann 
398b3d6663SArnd Bergmann static int spu_hw_mbox_read(struct spu_context *ctx, u32 * data)
408b3d6663SArnd Bergmann {
418b3d6663SArnd Bergmann 	struct spu *spu = ctx->spu;
428b3d6663SArnd Bergmann 	struct spu_problem __iomem *prob = spu->problem;
438b3d6663SArnd Bergmann 	u32 mbox_stat;
448b3d6663SArnd Bergmann 	int ret = 0;
458b3d6663SArnd Bergmann 
468b3d6663SArnd Bergmann 	spin_lock_irq(&spu->register_lock);
478b3d6663SArnd Bergmann 	mbox_stat = in_be32(&prob->mb_stat_R);
488b3d6663SArnd Bergmann 	if (mbox_stat & 0x0000ff) {
498b3d6663SArnd Bergmann 		*data = in_be32(&prob->pu_mb_R);
508b3d6663SArnd Bergmann 		ret = 4;
518b3d6663SArnd Bergmann 	}
528b3d6663SArnd Bergmann 	spin_unlock_irq(&spu->register_lock);
538b3d6663SArnd Bergmann 	return ret;
548b3d6663SArnd Bergmann }
558b3d6663SArnd Bergmann 
568b3d6663SArnd Bergmann static u32 spu_hw_mbox_stat_read(struct spu_context *ctx)
578b3d6663SArnd Bergmann {
588b3d6663SArnd Bergmann 	return in_be32(&ctx->spu->problem->mb_stat_R);
598b3d6663SArnd Bergmann }
608b3d6663SArnd Bergmann 
618b3d6663SArnd Bergmann static int spu_hw_ibox_read(struct spu_context *ctx, u32 * data)
628b3d6663SArnd Bergmann {
638b3d6663SArnd Bergmann 	struct spu *spu = ctx->spu;
648b3d6663SArnd Bergmann 	struct spu_problem __iomem *prob = spu->problem;
658b3d6663SArnd Bergmann 	struct spu_priv1 __iomem *priv1 = spu->priv1;
668b3d6663SArnd Bergmann 	struct spu_priv2 __iomem *priv2 = spu->priv2;
678b3d6663SArnd Bergmann 	int ret;
688b3d6663SArnd Bergmann 
698b3d6663SArnd Bergmann 	spin_lock_irq(&spu->register_lock);
708b3d6663SArnd Bergmann 	if (in_be32(&prob->mb_stat_R) & 0xff0000) {
718b3d6663SArnd Bergmann 		/* read the first available word */
728b3d6663SArnd Bergmann 		*data = in_be64(&priv2->puint_mb_R);
738b3d6663SArnd Bergmann 		ret = 4;
748b3d6663SArnd Bergmann 	} else {
758b3d6663SArnd Bergmann 		/* make sure we get woken up by the interrupt */
768b3d6663SArnd Bergmann 		out_be64(&priv1->int_mask_class2_RW,
778b3d6663SArnd Bergmann 			 in_be64(&priv1->int_mask_class2_RW) | 0x1);
788b3d6663SArnd Bergmann 		ret = 0;
798b3d6663SArnd Bergmann 	}
808b3d6663SArnd Bergmann 	spin_unlock_irq(&spu->register_lock);
818b3d6663SArnd Bergmann 	return ret;
828b3d6663SArnd Bergmann }
838b3d6663SArnd Bergmann 
848b3d6663SArnd Bergmann static int spu_hw_wbox_write(struct spu_context *ctx, u32 data)
858b3d6663SArnd Bergmann {
868b3d6663SArnd Bergmann 	struct spu *spu = ctx->spu;
878b3d6663SArnd Bergmann 	struct spu_problem __iomem *prob = spu->problem;
888b3d6663SArnd Bergmann 	struct spu_priv1 __iomem *priv1 = spu->priv1;
898b3d6663SArnd Bergmann 	int ret;
908b3d6663SArnd Bergmann 
918b3d6663SArnd Bergmann 	spin_lock_irq(&spu->register_lock);
928b3d6663SArnd Bergmann 	if (in_be32(&prob->mb_stat_R) & 0x00ff00) {
938b3d6663SArnd Bergmann 		/* we have space to write wbox_data to */
948b3d6663SArnd Bergmann 		out_be32(&prob->spu_mb_W, data);
958b3d6663SArnd Bergmann 		ret = 4;
968b3d6663SArnd Bergmann 	} else {
978b3d6663SArnd Bergmann 		/* make sure we get woken up by the interrupt when space
988b3d6663SArnd Bergmann 		   becomes available */
998b3d6663SArnd Bergmann 		out_be64(&priv1->int_mask_class2_RW,
1008b3d6663SArnd Bergmann 			 in_be64(&priv1->int_mask_class2_RW) | 0x10);
1018b3d6663SArnd Bergmann 		ret = 0;
1028b3d6663SArnd Bergmann 	}
1038b3d6663SArnd Bergmann 	spin_unlock_irq(&spu->register_lock);
1048b3d6663SArnd Bergmann 	return ret;
1058b3d6663SArnd Bergmann }
1068b3d6663SArnd Bergmann 
1078b3d6663SArnd Bergmann static u32 spu_hw_signal1_read(struct spu_context *ctx)
1088b3d6663SArnd Bergmann {
1098b3d6663SArnd Bergmann 	return in_be32(&ctx->spu->problem->signal_notify1);
1108b3d6663SArnd Bergmann }
1118b3d6663SArnd Bergmann 
1128b3d6663SArnd Bergmann static void spu_hw_signal1_write(struct spu_context *ctx, u32 data)
1138b3d6663SArnd Bergmann {
1148b3d6663SArnd Bergmann 	out_be32(&ctx->spu->problem->signal_notify1, data);
1158b3d6663SArnd Bergmann }
1168b3d6663SArnd Bergmann 
1178b3d6663SArnd Bergmann static u32 spu_hw_signal2_read(struct spu_context *ctx)
1188b3d6663SArnd Bergmann {
1198b3d6663SArnd Bergmann 	return in_be32(&ctx->spu->problem->signal_notify1);
1208b3d6663SArnd Bergmann }
1218b3d6663SArnd Bergmann 
1228b3d6663SArnd Bergmann static void spu_hw_signal2_write(struct spu_context *ctx, u32 data)
1238b3d6663SArnd Bergmann {
1248b3d6663SArnd Bergmann 	out_be32(&ctx->spu->problem->signal_notify2, data);
1258b3d6663SArnd Bergmann }
1268b3d6663SArnd Bergmann 
1278b3d6663SArnd Bergmann static void spu_hw_signal1_type_set(struct spu_context *ctx, u64 val)
1288b3d6663SArnd Bergmann {
1298b3d6663SArnd Bergmann 	struct spu *spu = ctx->spu;
1308b3d6663SArnd Bergmann 	struct spu_priv2 __iomem *priv2 = spu->priv2;
1318b3d6663SArnd Bergmann 	u64 tmp;
1328b3d6663SArnd Bergmann 
1338b3d6663SArnd Bergmann 	spin_lock_irq(&spu->register_lock);
1348b3d6663SArnd Bergmann 	tmp = in_be64(&priv2->spu_cfg_RW);
1358b3d6663SArnd Bergmann 	if (val)
1368b3d6663SArnd Bergmann 		tmp |= 1;
1378b3d6663SArnd Bergmann 	else
1388b3d6663SArnd Bergmann 		tmp &= ~1;
1398b3d6663SArnd Bergmann 	out_be64(&priv2->spu_cfg_RW, tmp);
1408b3d6663SArnd Bergmann 	spin_unlock_irq(&spu->register_lock);
1418b3d6663SArnd Bergmann }
1428b3d6663SArnd Bergmann 
1438b3d6663SArnd Bergmann static u64 spu_hw_signal1_type_get(struct spu_context *ctx)
1448b3d6663SArnd Bergmann {
1458b3d6663SArnd Bergmann 	return ((in_be64(&ctx->spu->priv2->spu_cfg_RW) & 1) != 0);
1468b3d6663SArnd Bergmann }
1478b3d6663SArnd Bergmann 
1488b3d6663SArnd Bergmann static void spu_hw_signal2_type_set(struct spu_context *ctx, u64 val)
1498b3d6663SArnd Bergmann {
1508b3d6663SArnd Bergmann 	struct spu *spu = ctx->spu;
1518b3d6663SArnd Bergmann 	struct spu_priv2 __iomem *priv2 = spu->priv2;
1528b3d6663SArnd Bergmann 	u64 tmp;
1538b3d6663SArnd Bergmann 
1548b3d6663SArnd Bergmann 	spin_lock_irq(&spu->register_lock);
1558b3d6663SArnd Bergmann 	tmp = in_be64(&priv2->spu_cfg_RW);
1568b3d6663SArnd Bergmann 	if (val)
1578b3d6663SArnd Bergmann 		tmp |= 2;
1588b3d6663SArnd Bergmann 	else
1598b3d6663SArnd Bergmann 		tmp &= ~2;
1608b3d6663SArnd Bergmann 	out_be64(&priv2->spu_cfg_RW, tmp);
1618b3d6663SArnd Bergmann 	spin_unlock_irq(&spu->register_lock);
1628b3d6663SArnd Bergmann }
1638b3d6663SArnd Bergmann 
1648b3d6663SArnd Bergmann static u64 spu_hw_signal2_type_get(struct spu_context *ctx)
1658b3d6663SArnd Bergmann {
1668b3d6663SArnd Bergmann 	return ((in_be64(&ctx->spu->priv2->spu_cfg_RW) & 2) != 0);
1678b3d6663SArnd Bergmann }
1688b3d6663SArnd Bergmann 
1698b3d6663SArnd Bergmann static u32 spu_hw_npc_read(struct spu_context *ctx)
1708b3d6663SArnd Bergmann {
1718b3d6663SArnd Bergmann 	return in_be32(&ctx->spu->problem->spu_npc_RW);
1728b3d6663SArnd Bergmann }
1738b3d6663SArnd Bergmann 
1748b3d6663SArnd Bergmann static void spu_hw_npc_write(struct spu_context *ctx, u32 val)
1758b3d6663SArnd Bergmann {
1768b3d6663SArnd Bergmann 	out_be32(&ctx->spu->problem->spu_npc_RW, val);
1778b3d6663SArnd Bergmann }
1788b3d6663SArnd Bergmann 
1798b3d6663SArnd Bergmann static u32 spu_hw_status_read(struct spu_context *ctx)
1808b3d6663SArnd Bergmann {
1818b3d6663SArnd Bergmann 	return in_be32(&ctx->spu->problem->spu_status_R);
1828b3d6663SArnd Bergmann }
1838b3d6663SArnd Bergmann 
1848b3d6663SArnd Bergmann static char *spu_hw_get_ls(struct spu_context *ctx)
1858b3d6663SArnd Bergmann {
1868b3d6663SArnd Bergmann 	return ctx->spu->local_store;
1878b3d6663SArnd Bergmann }
1888b3d6663SArnd Bergmann 
1895110459fSArnd Bergmann static void spu_hw_runcntl_write(struct spu_context *ctx, u32 val)
1905110459fSArnd Bergmann {
1915110459fSArnd Bergmann 	eieio();
1925110459fSArnd Bergmann 	out_be32(&ctx->spu->problem->spu_runcntl_RW, val);
1935110459fSArnd Bergmann }
1945110459fSArnd Bergmann 
1955110459fSArnd Bergmann static void spu_hw_runcntl_stop(struct spu_context *ctx)
1965110459fSArnd Bergmann {
1975110459fSArnd Bergmann 	spin_lock_irq(&ctx->spu->register_lock);
1985110459fSArnd Bergmann 	out_be32(&ctx->spu->problem->spu_runcntl_RW, SPU_RUNCNTL_STOP);
1995110459fSArnd Bergmann 	while (in_be32(&ctx->spu->problem->spu_status_R) & SPU_STATUS_RUNNING)
2005110459fSArnd Bergmann 		cpu_relax();
2015110459fSArnd Bergmann 	spin_unlock_irq(&ctx->spu->register_lock);
2025110459fSArnd Bergmann }
2035110459fSArnd Bergmann 
2048b3d6663SArnd Bergmann struct spu_context_ops spu_hw_ops = {
2058b3d6663SArnd Bergmann 	.mbox_read = spu_hw_mbox_read,
2068b3d6663SArnd Bergmann 	.mbox_stat_read = spu_hw_mbox_stat_read,
2078b3d6663SArnd Bergmann 	.ibox_read = spu_hw_ibox_read,
2088b3d6663SArnd Bergmann 	.wbox_write = spu_hw_wbox_write,
2098b3d6663SArnd Bergmann 	.signal1_read = spu_hw_signal1_read,
2108b3d6663SArnd Bergmann 	.signal1_write = spu_hw_signal1_write,
2118b3d6663SArnd Bergmann 	.signal2_read = spu_hw_signal2_read,
2128b3d6663SArnd Bergmann 	.signal2_write = spu_hw_signal2_write,
2138b3d6663SArnd Bergmann 	.signal1_type_set = spu_hw_signal1_type_set,
2148b3d6663SArnd Bergmann 	.signal1_type_get = spu_hw_signal1_type_get,
2158b3d6663SArnd Bergmann 	.signal2_type_set = spu_hw_signal2_type_set,
2168b3d6663SArnd Bergmann 	.signal2_type_get = spu_hw_signal2_type_get,
2178b3d6663SArnd Bergmann 	.npc_read = spu_hw_npc_read,
2188b3d6663SArnd Bergmann 	.npc_write = spu_hw_npc_write,
2198b3d6663SArnd Bergmann 	.status_read = spu_hw_status_read,
2208b3d6663SArnd Bergmann 	.get_ls = spu_hw_get_ls,
2215110459fSArnd Bergmann 	.runcntl_write = spu_hw_runcntl_write,
2225110459fSArnd Bergmann 	.runcntl_stop = spu_hw_runcntl_stop,
2238b3d6663SArnd Bergmann };
224