linux/arch/powerpc/platforms/cell/spufs/spu_save.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-or-later
   2/*
   3 * spu_save.c
   4 *
   5 * (C) Copyright IBM Corp. 2005
   6 *
   7 * SPU-side context save sequence outlined in
   8 * Synergistic Processor Element Book IV
   9 *
  10 * Author: Mark Nutter <mnutter@us.ibm.com>
  11 */
  12
  13
  14#ifndef LS_SIZE
  15#define LS_SIZE                 0x40000 /* 256K (in bytes) */
  16#endif
  17
  18typedef unsigned int u32;
  19typedef unsigned long long u64;
  20
  21#include <spu_intrinsics.h>
  22#include <asm/spu_csa.h>
  23#include "spu_utils.h"
  24
  25static inline void save_event_mask(void)
  26{
  27        unsigned int offset;
  28
  29        /* Save, Step 2:
  30         *    Read the SPU_RdEventMsk channel and save to the LSCSA.
  31         */
  32        offset = LSCSA_QW_OFFSET(event_mask);
  33        regs_spill[offset].slot[0] = spu_readch(SPU_RdEventMask);
  34}
  35
  36static inline void save_tag_mask(void)
  37{
  38        unsigned int offset;
  39
  40        /* Save, Step 3:
  41         *    Read the SPU_RdTagMsk channel and save to the LSCSA.
  42         */
  43        offset = LSCSA_QW_OFFSET(tag_mask);
  44        regs_spill[offset].slot[0] = spu_readch(MFC_RdTagMask);
  45}
  46
  47static inline void save_upper_240kb(addr64 lscsa_ea)
  48{
  49        unsigned int ls = 16384;
  50        unsigned int list = (unsigned int)&dma_list[0];
  51        unsigned int size = sizeof(dma_list);
  52        unsigned int tag_id = 0;
  53        unsigned int cmd = 0x24;        /* PUTL */
  54
  55        /* Save, Step 7:
  56         *    Enqueue the PUTL command (tag 0) to the MFC SPU command
  57         *    queue to transfer the remaining 240 kb of LS to CSA.
  58         */
  59        spu_writech(MFC_LSA, ls);
  60        spu_writech(MFC_EAH, lscsa_ea.ui[0]);
  61        spu_writech(MFC_EAL, list);
  62        spu_writech(MFC_Size, size);
  63        spu_writech(MFC_TagID, tag_id);
  64        spu_writech(MFC_Cmd, cmd);
  65}
  66
  67static inline void save_fpcr(void)
  68{
  69        // vector unsigned int fpcr;
  70        unsigned int offset;
  71
  72        /* Save, Step 9:
  73         *    Issue the floating-point status and control register
  74         *    read instruction, and save to the LSCSA.
  75         */
  76        offset = LSCSA_QW_OFFSET(fpcr);
  77        regs_spill[offset].v = spu_mffpscr();
  78}
  79
  80static inline void save_decr(void)
  81{
  82        unsigned int offset;
  83
  84        /* Save, Step 10:
  85         *    Read and save the SPU_RdDec channel data to
  86         *    the LSCSA.
  87         */
  88        offset = LSCSA_QW_OFFSET(decr);
  89        regs_spill[offset].slot[0] = spu_readch(SPU_RdDec);
  90}
  91
  92static inline void save_srr0(void)
  93{
  94        unsigned int offset;
  95
  96        /* Save, Step 11:
  97         *    Read and save the SPU_WSRR0 channel data to
  98         *    the LSCSA.
  99         */
 100        offset = LSCSA_QW_OFFSET(srr0);
 101        regs_spill[offset].slot[0] = spu_readch(SPU_RdSRR0);
 102}
 103
 104static inline void spill_regs_to_mem(addr64 lscsa_ea)
 105{
 106        unsigned int ls = (unsigned int)&regs_spill[0];
 107        unsigned int size = sizeof(regs_spill);
 108        unsigned int tag_id = 0;
 109        unsigned int cmd = 0x20;        /* PUT */
 110
 111        /* Save, Step 13:
 112         *    Enqueue a PUT command (tag 0) to send the LSCSA
 113         *    to the CSA.
 114         */
 115        spu_writech(MFC_LSA, ls);
 116        spu_writech(MFC_EAH, lscsa_ea.ui[0]);
 117        spu_writech(MFC_EAL, lscsa_ea.ui[1]);
 118        spu_writech(MFC_Size, size);
 119        spu_writech(MFC_TagID, tag_id);
 120        spu_writech(MFC_Cmd, cmd);
 121}
 122
 123static inline void enqueue_sync(addr64 lscsa_ea)
 124{
 125        unsigned int tag_id = 0;
 126        unsigned int cmd = 0xCC;
 127
 128        /* Save, Step 14:
 129         *    Enqueue an MFC_SYNC command (tag 0).
 130         */
 131        spu_writech(MFC_TagID, tag_id);
 132        spu_writech(MFC_Cmd, cmd);
 133}
 134
 135static inline void save_complete(void)
 136{
 137        /* Save, Step 18:
 138         *    Issue a stop-and-signal instruction indicating
 139         *    "save complete".  Note: This function will not
 140         *    return!!
 141         */
 142        spu_stop(SPU_SAVE_COMPLETE);
 143}
 144
 145/**
 146 * main - entry point for SPU-side context save.
 147 *
 148 * This code deviates from the documented sequence as follows:
 149 *
 150 *      1. The EA for LSCSA is passed from PPE in the
 151 *         signal notification channels.
 152 *      2. All 128 registers are saved by crt0.o.
 153 */
 154int main()
 155{
 156        addr64 lscsa_ea;
 157
 158        lscsa_ea.ui[0] = spu_readch(SPU_RdSigNotify1);
 159        lscsa_ea.ui[1] = spu_readch(SPU_RdSigNotify2);
 160
 161        /* Step 1: done by exit(). */
 162        save_event_mask();      /* Step 2.  */
 163        save_tag_mask();        /* Step 3.  */
 164        set_event_mask();       /* Step 4.  */
 165        set_tag_mask();         /* Step 5.  */
 166        build_dma_list(lscsa_ea);       /* Step 6.  */
 167        save_upper_240kb(lscsa_ea);     /* Step 7.  */
 168        /* Step 8: done by exit(). */
 169        save_fpcr();            /* Step 9.  */
 170        save_decr();            /* Step 10. */
 171        save_srr0();            /* Step 11. */
 172        enqueue_putllc(lscsa_ea);       /* Step 12. */
 173        spill_regs_to_mem(lscsa_ea);    /* Step 13. */
 174        enqueue_sync(lscsa_ea); /* Step 14. */
 175        set_tag_update();       /* Step 15. */
 176        read_tag_status();      /* Step 16. */
 177        read_llar_status();     /* Step 17. */
 178        save_complete();        /* Step 18. */
 179
 180        return 0;
 181}
 182