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