linux/arch/powerpc/platforms/cell/spufs/hw_ops.c
<<
>>
Prefs
   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/errno.h>
  22#include <linux/sched.h>
  23#include <linux/kernel.h>
  24#include <linux/mm.h>
  25#include <linux/poll.h>
  26#include <linux/smp.h>
  27#include <linux/stddef.h>
  28#include <linux/unistd.h>
  29
  30#include <asm/io.h>
  31#include <asm/spu.h>
  32#include <asm/spu_priv1.h>
  33#include <asm/spu_csa.h>
  34#include <asm/mmu_context.h>
  35#include "spufs.h"
  36
  37static int spu_hw_mbox_read(struct spu_context *ctx, u32 * data)
  38{
  39        struct spu *spu = ctx->spu;
  40        struct spu_problem __iomem *prob = spu->problem;
  41        u32 mbox_stat;
  42        int ret = 0;
  43
  44        spin_lock_irq(&spu->register_lock);
  45        mbox_stat = in_be32(&prob->mb_stat_R);
  46        if (mbox_stat & 0x0000ff) {
  47                *data = in_be32(&prob->pu_mb_R);
  48                ret = 4;
  49        }
  50        spin_unlock_irq(&spu->register_lock);
  51        return ret;
  52}
  53
  54static u32 spu_hw_mbox_stat_read(struct spu_context *ctx)
  55{
  56        return in_be32(&ctx->spu->problem->mb_stat_R);
  57}
  58
  59static unsigned int spu_hw_mbox_stat_poll(struct spu_context *ctx,
  60                                          unsigned int events)
  61{
  62        struct spu *spu = ctx->spu;
  63        int ret = 0;
  64        u32 stat;
  65
  66        spin_lock_irq(&spu->register_lock);
  67        stat = in_be32(&spu->problem->mb_stat_R);
  68
  69        /* if the requested event is there, return the poll
  70           mask, otherwise enable the interrupt to get notified,
  71           but first mark any pending interrupts as done so
  72           we don't get woken up unnecessarily */
  73
  74        if (events & (POLLIN | POLLRDNORM)) {
  75                if (stat & 0xff0000)
  76                        ret |= POLLIN | POLLRDNORM;
  77                else {
  78                        spu_int_stat_clear(spu, 2, CLASS2_MAILBOX_INTR);
  79                        spu_int_mask_or(spu, 2, CLASS2_ENABLE_MAILBOX_INTR);
  80                }
  81        }
  82        if (events & (POLLOUT | POLLWRNORM)) {
  83                if (stat & 0x00ff00)
  84                        ret = POLLOUT | POLLWRNORM;
  85                else {
  86                        spu_int_stat_clear(spu, 2,
  87                                        CLASS2_MAILBOX_THRESHOLD_INTR);
  88                        spu_int_mask_or(spu, 2,
  89                                        CLASS2_ENABLE_MAILBOX_THRESHOLD_INTR);
  90                }
  91        }
  92        spin_unlock_irq(&spu->register_lock);
  93        return ret;
  94}
  95
  96static int spu_hw_ibox_read(struct spu_context *ctx, u32 * data)
  97{
  98        struct spu *spu = ctx->spu;
  99        struct spu_problem __iomem *prob = spu->problem;
 100        struct spu_priv2 __iomem *priv2 = spu->priv2;
 101        int ret;
 102
 103        spin_lock_irq(&spu->register_lock);
 104        if (in_be32(&prob->mb_stat_R) & 0xff0000) {
 105                /* read the first available word */
 106                *data = in_be64(&priv2->puint_mb_R);
 107                ret = 4;
 108        } else {
 109                /* make sure we get woken up by the interrupt */
 110                spu_int_mask_or(spu, 2, CLASS2_ENABLE_MAILBOX_INTR);
 111                ret = 0;
 112        }
 113        spin_unlock_irq(&spu->register_lock);
 114        return ret;
 115}
 116
 117static int spu_hw_wbox_write(struct spu_context *ctx, u32 data)
 118{
 119        struct spu *spu = ctx->spu;
 120        struct spu_problem __iomem *prob = spu->problem;
 121        int ret;
 122
 123        spin_lock_irq(&spu->register_lock);
 124        if (in_be32(&prob->mb_stat_R) & 0x00ff00) {
 125                /* we have space to write wbox_data to */
 126                out_be32(&prob->spu_mb_W, data);
 127                ret = 4;
 128        } else {
 129                /* make sure we get woken up by the interrupt when space
 130                   becomes available */
 131                spu_int_mask_or(spu, 2, CLASS2_ENABLE_MAILBOX_THRESHOLD_INTR);
 132                ret = 0;
 133        }
 134        spin_unlock_irq(&spu->register_lock);
 135        return ret;
 136}
 137
 138static void spu_hw_signal1_write(struct spu_context *ctx, u32 data)
 139{
 140        out_be32(&ctx->spu->problem->signal_notify1, data);
 141}
 142
 143static void spu_hw_signal2_write(struct spu_context *ctx, u32 data)
 144{
 145        out_be32(&ctx->spu->problem->signal_notify2, data);
 146}
 147
 148static void spu_hw_signal1_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 |= 1;
 158        else
 159                tmp &= ~1;
 160        out_be64(&priv2->spu_cfg_RW, tmp);
 161        spin_unlock_irq(&spu->register_lock);
 162}
 163
 164static u64 spu_hw_signal1_type_get(struct spu_context *ctx)
 165{
 166        return ((in_be64(&ctx->spu->priv2->spu_cfg_RW) & 1) != 0);
 167}
 168
 169static void spu_hw_signal2_type_set(struct spu_context *ctx, u64 val)
 170{
 171        struct spu *spu = ctx->spu;
 172        struct spu_priv2 __iomem *priv2 = spu->priv2;
 173        u64 tmp;
 174
 175        spin_lock_irq(&spu->register_lock);
 176        tmp = in_be64(&priv2->spu_cfg_RW);
 177        if (val)
 178                tmp |= 2;
 179        else
 180                tmp &= ~2;
 181        out_be64(&priv2->spu_cfg_RW, tmp);
 182        spin_unlock_irq(&spu->register_lock);
 183}
 184
 185static u64 spu_hw_signal2_type_get(struct spu_context *ctx)
 186{
 187        return ((in_be64(&ctx->spu->priv2->spu_cfg_RW) & 2) != 0);
 188}
 189
 190static u32 spu_hw_npc_read(struct spu_context *ctx)
 191{
 192        return in_be32(&ctx->spu->problem->spu_npc_RW);
 193}
 194
 195static void spu_hw_npc_write(struct spu_context *ctx, u32 val)
 196{
 197        out_be32(&ctx->spu->problem->spu_npc_RW, val);
 198}
 199
 200static u32 spu_hw_status_read(struct spu_context *ctx)
 201{
 202        return in_be32(&ctx->spu->problem->spu_status_R);
 203}
 204
 205static char *spu_hw_get_ls(struct spu_context *ctx)
 206{
 207        return ctx->spu->local_store;
 208}
 209
 210static void spu_hw_privcntl_write(struct spu_context *ctx, u64 val)
 211{
 212        out_be64(&ctx->spu->priv2->spu_privcntl_RW, val);
 213}
 214
 215static u32 spu_hw_runcntl_read(struct spu_context *ctx)
 216{
 217        return in_be32(&ctx->spu->problem->spu_runcntl_RW);
 218}
 219
 220static void spu_hw_runcntl_write(struct spu_context *ctx, u32 val)
 221{
 222        spin_lock_irq(&ctx->spu->register_lock);
 223        if (val & SPU_RUNCNTL_ISOLATE)
 224                spu_hw_privcntl_write(ctx,
 225                        SPU_PRIVCNT_LOAD_REQUEST_ENABLE_MASK);
 226        out_be32(&ctx->spu->problem->spu_runcntl_RW, val);
 227        spin_unlock_irq(&ctx->spu->register_lock);
 228}
 229
 230static void spu_hw_runcntl_stop(struct spu_context *ctx)
 231{
 232        spin_lock_irq(&ctx->spu->register_lock);
 233        out_be32(&ctx->spu->problem->spu_runcntl_RW, SPU_RUNCNTL_STOP);
 234        while (in_be32(&ctx->spu->problem->spu_status_R) & SPU_STATUS_RUNNING)
 235                cpu_relax();
 236        spin_unlock_irq(&ctx->spu->register_lock);
 237}
 238
 239static void spu_hw_master_start(struct spu_context *ctx)
 240{
 241        struct spu *spu = ctx->spu;
 242        u64 sr1;
 243
 244        spin_lock_irq(&spu->register_lock);
 245        sr1 = spu_mfc_sr1_get(spu) | MFC_STATE1_MASTER_RUN_CONTROL_MASK;
 246        spu_mfc_sr1_set(spu, sr1);
 247        spin_unlock_irq(&spu->register_lock);
 248}
 249
 250static void spu_hw_master_stop(struct spu_context *ctx)
 251{
 252        struct spu *spu = ctx->spu;
 253        u64 sr1;
 254
 255        spin_lock_irq(&spu->register_lock);
 256        sr1 = spu_mfc_sr1_get(spu) & ~MFC_STATE1_MASTER_RUN_CONTROL_MASK;
 257        spu_mfc_sr1_set(spu, sr1);
 258        spin_unlock_irq(&spu->register_lock);
 259}
 260
 261static int spu_hw_set_mfc_query(struct spu_context * ctx, u32 mask, u32 mode)
 262{
 263        struct spu_problem __iomem *prob = ctx->spu->problem;
 264        int ret;
 265
 266        spin_lock_irq(&ctx->spu->register_lock);
 267        ret = -EAGAIN;
 268        if (in_be32(&prob->dma_querytype_RW))
 269                goto out;
 270        ret = 0;
 271        out_be32(&prob->dma_querymask_RW, mask);
 272        out_be32(&prob->dma_querytype_RW, mode);
 273out:
 274        spin_unlock_irq(&ctx->spu->register_lock);
 275        return ret;
 276}
 277
 278static u32 spu_hw_read_mfc_tagstatus(struct spu_context * ctx)
 279{
 280        return in_be32(&ctx->spu->problem->dma_tagstatus_R);
 281}
 282
 283static u32 spu_hw_get_mfc_free_elements(struct spu_context *ctx)
 284{
 285        return in_be32(&ctx->spu->problem->dma_qstatus_R);
 286}
 287
 288static int spu_hw_send_mfc_command(struct spu_context *ctx,
 289                                        struct mfc_dma_command *cmd)
 290{
 291        u32 status;
 292        struct spu_problem __iomem *prob = ctx->spu->problem;
 293
 294        spin_lock_irq(&ctx->spu->register_lock);
 295        out_be32(&prob->mfc_lsa_W, cmd->lsa);
 296        out_be64(&prob->mfc_ea_W, cmd->ea);
 297        out_be32(&prob->mfc_union_W.by32.mfc_size_tag32,
 298                                cmd->size << 16 | cmd->tag);
 299        out_be32(&prob->mfc_union_W.by32.mfc_class_cmd32,
 300                                cmd->class << 16 | cmd->cmd);
 301        status = in_be32(&prob->mfc_union_W.by32.mfc_class_cmd32);
 302        spin_unlock_irq(&ctx->spu->register_lock);
 303
 304        switch (status & 0xffff) {
 305        case 0:
 306                return 0;
 307        case 2:
 308                return -EAGAIN;
 309        default:
 310                return -EINVAL;
 311        }
 312}
 313
 314static void spu_hw_restart_dma(struct spu_context *ctx)
 315{
 316        struct spu_priv2 __iomem *priv2 = ctx->spu->priv2;
 317
 318        if (!test_bit(SPU_CONTEXT_SWITCH_PENDING, &ctx->spu->flags))
 319                out_be64(&priv2->mfc_control_RW, MFC_CNTL_RESTART_DMA_COMMAND);
 320}
 321
 322struct spu_context_ops spu_hw_ops = {
 323        .mbox_read = spu_hw_mbox_read,
 324        .mbox_stat_read = spu_hw_mbox_stat_read,
 325        .mbox_stat_poll = spu_hw_mbox_stat_poll,
 326        .ibox_read = spu_hw_ibox_read,
 327        .wbox_write = spu_hw_wbox_write,
 328        .signal1_write = spu_hw_signal1_write,
 329        .signal2_write = spu_hw_signal2_write,
 330        .signal1_type_set = spu_hw_signal1_type_set,
 331        .signal1_type_get = spu_hw_signal1_type_get,
 332        .signal2_type_set = spu_hw_signal2_type_set,
 333        .signal2_type_get = spu_hw_signal2_type_get,
 334        .npc_read = spu_hw_npc_read,
 335        .npc_write = spu_hw_npc_write,
 336        .status_read = spu_hw_status_read,
 337        .get_ls = spu_hw_get_ls,
 338        .privcntl_write = spu_hw_privcntl_write,
 339        .runcntl_read = spu_hw_runcntl_read,
 340        .runcntl_write = spu_hw_runcntl_write,
 341        .runcntl_stop = spu_hw_runcntl_stop,
 342        .master_start = spu_hw_master_start,
 343        .master_stop = spu_hw_master_stop,
 344        .set_mfc_query = spu_hw_set_mfc_query,
 345        .read_mfc_tagstatus = spu_hw_read_mfc_tagstatus,
 346        .get_mfc_free_elements = spu_hw_get_mfc_free_elements,
 347        .send_mfc_command = spu_hw_send_mfc_command,
 348        .restart_dma = spu_hw_restart_dma,
 349};
 350