Path: blob/master/arch/powerpc/platforms/cell/spufs/hw_ops.c
26498 views
// SPDX-License-Identifier: GPL-2.0-or-later1/* hw_ops.c - query/set operations on active SPU context.2*3* Copyright (C) IBM 20054* Author: Mark Nutter <[email protected]>5*/67#include <linux/errno.h>8#include <linux/sched.h>9#include <linux/kernel.h>10#include <linux/mm.h>11#include <linux/poll.h>12#include <linux/smp.h>13#include <linux/stddef.h>14#include <linux/unistd.h>1516#include <asm/io.h>17#include <asm/spu.h>18#include <asm/spu_priv1.h>19#include <asm/spu_csa.h>20#include <asm/mmu_context.h>21#include "spufs.h"2223static int spu_hw_mbox_read(struct spu_context *ctx, u32 * data)24{25struct spu *spu = ctx->spu;26struct spu_problem __iomem *prob = spu->problem;27u32 mbox_stat;28int ret = 0;2930spin_lock_irq(&spu->register_lock);31mbox_stat = in_be32(&prob->mb_stat_R);32if (mbox_stat & 0x0000ff) {33*data = in_be32(&prob->pu_mb_R);34ret = 4;35}36spin_unlock_irq(&spu->register_lock);37return ret;38}3940static u32 spu_hw_mbox_stat_read(struct spu_context *ctx)41{42return in_be32(&ctx->spu->problem->mb_stat_R);43}4445static __poll_t spu_hw_mbox_stat_poll(struct spu_context *ctx, __poll_t events)46{47struct spu *spu = ctx->spu;48__poll_t ret = 0;49u32 stat;5051spin_lock_irq(&spu->register_lock);52stat = in_be32(&spu->problem->mb_stat_R);5354/* if the requested event is there, return the poll55mask, otherwise enable the interrupt to get notified,56but first mark any pending interrupts as done so57we don't get woken up unnecessarily */5859if (events & (EPOLLIN | EPOLLRDNORM)) {60if (stat & 0xff0000)61ret |= EPOLLIN | EPOLLRDNORM;62else {63spu_int_stat_clear(spu, 2, CLASS2_MAILBOX_INTR);64spu_int_mask_or(spu, 2, CLASS2_ENABLE_MAILBOX_INTR);65}66}67if (events & (EPOLLOUT | EPOLLWRNORM)) {68if (stat & 0x00ff00)69ret = EPOLLOUT | EPOLLWRNORM;70else {71spu_int_stat_clear(spu, 2,72CLASS2_MAILBOX_THRESHOLD_INTR);73spu_int_mask_or(spu, 2,74CLASS2_ENABLE_MAILBOX_THRESHOLD_INTR);75}76}77spin_unlock_irq(&spu->register_lock);78return ret;79}8081static int spu_hw_ibox_read(struct spu_context *ctx, u32 * data)82{83struct spu *spu = ctx->spu;84struct spu_problem __iomem *prob = spu->problem;85struct spu_priv2 __iomem *priv2 = spu->priv2;86int ret;8788spin_lock_irq(&spu->register_lock);89if (in_be32(&prob->mb_stat_R) & 0xff0000) {90/* read the first available word */91*data = in_be64(&priv2->puint_mb_R);92ret = 4;93} else {94/* make sure we get woken up by the interrupt */95spu_int_mask_or(spu, 2, CLASS2_ENABLE_MAILBOX_INTR);96ret = 0;97}98spin_unlock_irq(&spu->register_lock);99return ret;100}101102static int spu_hw_wbox_write(struct spu_context *ctx, u32 data)103{104struct spu *spu = ctx->spu;105struct spu_problem __iomem *prob = spu->problem;106int ret;107108spin_lock_irq(&spu->register_lock);109if (in_be32(&prob->mb_stat_R) & 0x00ff00) {110/* we have space to write wbox_data to */111out_be32(&prob->spu_mb_W, data);112ret = 4;113} else {114/* make sure we get woken up by the interrupt when space115becomes available */116spu_int_mask_or(spu, 2, CLASS2_ENABLE_MAILBOX_THRESHOLD_INTR);117ret = 0;118}119spin_unlock_irq(&spu->register_lock);120return ret;121}122123static void spu_hw_signal1_write(struct spu_context *ctx, u32 data)124{125out_be32(&ctx->spu->problem->signal_notify1, data);126}127128static void spu_hw_signal2_write(struct spu_context *ctx, u32 data)129{130out_be32(&ctx->spu->problem->signal_notify2, data);131}132133static void spu_hw_signal1_type_set(struct spu_context *ctx, u64 val)134{135struct spu *spu = ctx->spu;136struct spu_priv2 __iomem *priv2 = spu->priv2;137u64 tmp;138139spin_lock_irq(&spu->register_lock);140tmp = in_be64(&priv2->spu_cfg_RW);141if (val)142tmp |= 1;143else144tmp &= ~1;145out_be64(&priv2->spu_cfg_RW, tmp);146spin_unlock_irq(&spu->register_lock);147}148149static u64 spu_hw_signal1_type_get(struct spu_context *ctx)150{151return ((in_be64(&ctx->spu->priv2->spu_cfg_RW) & 1) != 0);152}153154static void spu_hw_signal2_type_set(struct spu_context *ctx, u64 val)155{156struct spu *spu = ctx->spu;157struct spu_priv2 __iomem *priv2 = spu->priv2;158u64 tmp;159160spin_lock_irq(&spu->register_lock);161tmp = in_be64(&priv2->spu_cfg_RW);162if (val)163tmp |= 2;164else165tmp &= ~2;166out_be64(&priv2->spu_cfg_RW, tmp);167spin_unlock_irq(&spu->register_lock);168}169170static u64 spu_hw_signal2_type_get(struct spu_context *ctx)171{172return ((in_be64(&ctx->spu->priv2->spu_cfg_RW) & 2) != 0);173}174175static u32 spu_hw_npc_read(struct spu_context *ctx)176{177return in_be32(&ctx->spu->problem->spu_npc_RW);178}179180static void spu_hw_npc_write(struct spu_context *ctx, u32 val)181{182out_be32(&ctx->spu->problem->spu_npc_RW, val);183}184185static u32 spu_hw_status_read(struct spu_context *ctx)186{187return in_be32(&ctx->spu->problem->spu_status_R);188}189190static char *spu_hw_get_ls(struct spu_context *ctx)191{192return ctx->spu->local_store;193}194195static void spu_hw_privcntl_write(struct spu_context *ctx, u64 val)196{197out_be64(&ctx->spu->priv2->spu_privcntl_RW, val);198}199200static u32 spu_hw_runcntl_read(struct spu_context *ctx)201{202return in_be32(&ctx->spu->problem->spu_runcntl_RW);203}204205static void spu_hw_runcntl_write(struct spu_context *ctx, u32 val)206{207spin_lock_irq(&ctx->spu->register_lock);208if (val & SPU_RUNCNTL_ISOLATE)209spu_hw_privcntl_write(ctx,210SPU_PRIVCNT_LOAD_REQUEST_ENABLE_MASK);211out_be32(&ctx->spu->problem->spu_runcntl_RW, val);212spin_unlock_irq(&ctx->spu->register_lock);213}214215static void spu_hw_runcntl_stop(struct spu_context *ctx)216{217spin_lock_irq(&ctx->spu->register_lock);218out_be32(&ctx->spu->problem->spu_runcntl_RW, SPU_RUNCNTL_STOP);219while (in_be32(&ctx->spu->problem->spu_status_R) & SPU_STATUS_RUNNING)220cpu_relax();221spin_unlock_irq(&ctx->spu->register_lock);222}223224static void spu_hw_master_start(struct spu_context *ctx)225{226struct spu *spu = ctx->spu;227u64 sr1;228229spin_lock_irq(&spu->register_lock);230sr1 = spu_mfc_sr1_get(spu) | MFC_STATE1_MASTER_RUN_CONTROL_MASK;231spu_mfc_sr1_set(spu, sr1);232spin_unlock_irq(&spu->register_lock);233}234235static void spu_hw_master_stop(struct spu_context *ctx)236{237struct spu *spu = ctx->spu;238u64 sr1;239240spin_lock_irq(&spu->register_lock);241sr1 = spu_mfc_sr1_get(spu) & ~MFC_STATE1_MASTER_RUN_CONTROL_MASK;242spu_mfc_sr1_set(spu, sr1);243spin_unlock_irq(&spu->register_lock);244}245246static int spu_hw_set_mfc_query(struct spu_context * ctx, u32 mask, u32 mode)247{248struct spu_problem __iomem *prob = ctx->spu->problem;249int ret;250251spin_lock_irq(&ctx->spu->register_lock);252ret = -EAGAIN;253if (in_be32(&prob->dma_querytype_RW))254goto out;255ret = 0;256out_be32(&prob->dma_querymask_RW, mask);257out_be32(&prob->dma_querytype_RW, mode);258out:259spin_unlock_irq(&ctx->spu->register_lock);260return ret;261}262263static u32 spu_hw_read_mfc_tagstatus(struct spu_context * ctx)264{265return in_be32(&ctx->spu->problem->dma_tagstatus_R);266}267268static u32 spu_hw_get_mfc_free_elements(struct spu_context *ctx)269{270return in_be32(&ctx->spu->problem->dma_qstatus_R);271}272273static int spu_hw_send_mfc_command(struct spu_context *ctx,274struct mfc_dma_command *cmd)275{276u32 status;277struct spu_problem __iomem *prob = ctx->spu->problem;278279spin_lock_irq(&ctx->spu->register_lock);280out_be32(&prob->mfc_lsa_W, cmd->lsa);281out_be64(&prob->mfc_ea_W, cmd->ea);282out_be32(&prob->mfc_union_W.by32.mfc_size_tag32,283cmd->size << 16 | cmd->tag);284out_be32(&prob->mfc_union_W.by32.mfc_class_cmd32,285cmd->class << 16 | cmd->cmd);286status = in_be32(&prob->mfc_union_W.by32.mfc_class_cmd32);287spin_unlock_irq(&ctx->spu->register_lock);288289switch (status & 0xffff) {290case 0:291return 0;292case 2:293return -EAGAIN;294default:295return -EINVAL;296}297}298299static void spu_hw_restart_dma(struct spu_context *ctx)300{301struct spu_priv2 __iomem *priv2 = ctx->spu->priv2;302303if (!test_bit(SPU_CONTEXT_SWITCH_PENDING, &ctx->spu->flags))304out_be64(&priv2->mfc_control_RW, MFC_CNTL_RESTART_DMA_COMMAND);305}306307struct spu_context_ops spu_hw_ops = {308.mbox_read = spu_hw_mbox_read,309.mbox_stat_read = spu_hw_mbox_stat_read,310.mbox_stat_poll = spu_hw_mbox_stat_poll,311.ibox_read = spu_hw_ibox_read,312.wbox_write = spu_hw_wbox_write,313.signal1_write = spu_hw_signal1_write,314.signal2_write = spu_hw_signal2_write,315.signal1_type_set = spu_hw_signal1_type_set,316.signal1_type_get = spu_hw_signal1_type_get,317.signal2_type_set = spu_hw_signal2_type_set,318.signal2_type_get = spu_hw_signal2_type_get,319.npc_read = spu_hw_npc_read,320.npc_write = spu_hw_npc_write,321.status_read = spu_hw_status_read,322.get_ls = spu_hw_get_ls,323.privcntl_write = spu_hw_privcntl_write,324.runcntl_read = spu_hw_runcntl_read,325.runcntl_write = spu_hw_runcntl_write,326.runcntl_stop = spu_hw_runcntl_stop,327.master_start = spu_hw_master_start,328.master_stop = spu_hw_master_stop,329.set_mfc_query = spu_hw_set_mfc_query,330.read_mfc_tagstatus = spu_hw_read_mfc_tagstatus,331.get_mfc_free_elements = spu_hw_get_mfc_free_elements,332.send_mfc_command = spu_hw_send_mfc_command,333.restart_dma = spu_hw_restart_dma,334};335336337