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 1898b3d6663SArnd Bergmann struct spu_context_ops spu_hw_ops = { 1908b3d6663SArnd Bergmann .mbox_read = spu_hw_mbox_read, 1918b3d6663SArnd Bergmann .mbox_stat_read = spu_hw_mbox_stat_read, 1928b3d6663SArnd Bergmann .ibox_read = spu_hw_ibox_read, 1938b3d6663SArnd Bergmann .wbox_write = spu_hw_wbox_write, 1948b3d6663SArnd Bergmann .signal1_read = spu_hw_signal1_read, 1958b3d6663SArnd Bergmann .signal1_write = spu_hw_signal1_write, 1968b3d6663SArnd Bergmann .signal2_read = spu_hw_signal2_read, 1978b3d6663SArnd Bergmann .signal2_write = spu_hw_signal2_write, 1988b3d6663SArnd Bergmann .signal1_type_set = spu_hw_signal1_type_set, 1998b3d6663SArnd Bergmann .signal1_type_get = spu_hw_signal1_type_get, 2008b3d6663SArnd Bergmann .signal2_type_set = spu_hw_signal2_type_set, 2018b3d6663SArnd Bergmann .signal2_type_get = spu_hw_signal2_type_get, 2028b3d6663SArnd Bergmann .npc_read = spu_hw_npc_read, 2038b3d6663SArnd Bergmann .npc_write = spu_hw_npc_write, 2048b3d6663SArnd Bergmann .status_read = spu_hw_status_read, 2058b3d6663SArnd Bergmann .get_ls = spu_hw_get_ls, 2068b3d6663SArnd Bergmann }; 207