root/arch/powerpc/platforms/cell/spufs/backing_ops.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. gen_spu_event
  2. spu_backing_mbox_read
  3. spu_backing_mbox_stat_read
  4. spu_backing_mbox_stat_poll
  5. spu_backing_ibox_read
  6. spu_backing_wbox_write
  7. spu_backing_signal1_read
  8. spu_backing_signal1_write
  9. spu_backing_signal2_read
  10. spu_backing_signal2_write
  11. spu_backing_signal1_type_set
  12. spu_backing_signal1_type_get
  13. spu_backing_signal2_type_set
  14. spu_backing_signal2_type_get
  15. spu_backing_npc_read
  16. spu_backing_npc_write
  17. spu_backing_status_read
  18. spu_backing_get_ls
  19. spu_backing_privcntl_write
  20. spu_backing_runcntl_read
  21. spu_backing_runcntl_write
  22. spu_backing_runcntl_stop
  23. spu_backing_master_start
  24. spu_backing_master_stop
  25. spu_backing_set_mfc_query
  26. spu_backing_read_mfc_tagstatus
  27. spu_backing_get_mfc_free_elements
  28. spu_backing_send_mfc_command
  29. spu_backing_restart_dma

   1 // SPDX-License-Identifier: GPL-2.0-or-later
   2 /* backing_ops.c - query/set operations on saved SPU context.
   3  *
   4  * Copyright (C) IBM 2005
   5  * Author: Mark Nutter <mnutter@us.ibm.com>
   6  *
   7  * These register operations allow SPUFS to operate on saved
   8  * SPU contexts rather than hardware.
   9  */
  10 
  11 #include <linux/errno.h>
  12 #include <linux/sched.h>
  13 #include <linux/kernel.h>
  14 #include <linux/mm.h>
  15 #include <linux/vmalloc.h>
  16 #include <linux/smp.h>
  17 #include <linux/stddef.h>
  18 #include <linux/unistd.h>
  19 #include <linux/poll.h>
  20 
  21 #include <asm/io.h>
  22 #include <asm/spu.h>
  23 #include <asm/spu_csa.h>
  24 #include <asm/spu_info.h>
  25 #include <asm/mmu_context.h>
  26 #include "spufs.h"
  27 
  28 /*
  29  * Reads/writes to various problem and priv2 registers require
  30  * state changes, i.e.  generate SPU events, modify channel
  31  * counts, etc.
  32  */
  33 
  34 static void gen_spu_event(struct spu_context *ctx, u32 event)
  35 {
  36         u64 ch0_cnt;
  37         u64 ch0_data;
  38         u64 ch1_data;
  39 
  40         ch0_cnt = ctx->csa.spu_chnlcnt_RW[0];
  41         ch0_data = ctx->csa.spu_chnldata_RW[0];
  42         ch1_data = ctx->csa.spu_chnldata_RW[1];
  43         ctx->csa.spu_chnldata_RW[0] |= event;
  44         if ((ch0_cnt == 0) && !(ch0_data & event) && (ch1_data & event)) {
  45                 ctx->csa.spu_chnlcnt_RW[0] = 1;
  46         }
  47 }
  48 
  49 static int spu_backing_mbox_read(struct spu_context *ctx, u32 * data)
  50 {
  51         u32 mbox_stat;
  52         int ret = 0;
  53 
  54         spin_lock(&ctx->csa.register_lock);
  55         mbox_stat = ctx->csa.prob.mb_stat_R;
  56         if (mbox_stat & 0x0000ff) {
  57                 /* Read the first available word.
  58                  * Implementation note: the depth
  59                  * of pu_mb_R is currently 1.
  60                  */
  61                 *data = ctx->csa.prob.pu_mb_R;
  62                 ctx->csa.prob.mb_stat_R &= ~(0x0000ff);
  63                 ctx->csa.spu_chnlcnt_RW[28] = 1;
  64                 gen_spu_event(ctx, MFC_PU_MAILBOX_AVAILABLE_EVENT);
  65                 ret = 4;
  66         }
  67         spin_unlock(&ctx->csa.register_lock);
  68         return ret;
  69 }
  70 
  71 static u32 spu_backing_mbox_stat_read(struct spu_context *ctx)
  72 {
  73         return ctx->csa.prob.mb_stat_R;
  74 }
  75 
  76 static __poll_t spu_backing_mbox_stat_poll(struct spu_context *ctx,
  77                                           __poll_t events)
  78 {
  79         __poll_t ret;
  80         u32 stat;
  81 
  82         ret = 0;
  83         spin_lock_irq(&ctx->csa.register_lock);
  84         stat = ctx->csa.prob.mb_stat_R;
  85 
  86         /* if the requested event is there, return the poll
  87            mask, otherwise enable the interrupt to get notified,
  88            but first mark any pending interrupts as done so
  89            we don't get woken up unnecessarily */
  90 
  91         if (events & (EPOLLIN | EPOLLRDNORM)) {
  92                 if (stat & 0xff0000)
  93                         ret |= EPOLLIN | EPOLLRDNORM;
  94                 else {
  95                         ctx->csa.priv1.int_stat_class2_RW &=
  96                                 ~CLASS2_MAILBOX_INTR;
  97                         ctx->csa.priv1.int_mask_class2_RW |=
  98                                 CLASS2_ENABLE_MAILBOX_INTR;
  99                 }
 100         }
 101         if (events & (EPOLLOUT | EPOLLWRNORM)) {
 102                 if (stat & 0x00ff00)
 103                         ret = EPOLLOUT | EPOLLWRNORM;
 104                 else {
 105                         ctx->csa.priv1.int_stat_class2_RW &=
 106                                 ~CLASS2_MAILBOX_THRESHOLD_INTR;
 107                         ctx->csa.priv1.int_mask_class2_RW |=
 108                                 CLASS2_ENABLE_MAILBOX_THRESHOLD_INTR;
 109                 }
 110         }
 111         spin_unlock_irq(&ctx->csa.register_lock);
 112         return ret;
 113 }
 114 
 115 static int spu_backing_ibox_read(struct spu_context *ctx, u32 * data)
 116 {
 117         int ret;
 118 
 119         spin_lock(&ctx->csa.register_lock);
 120         if (ctx->csa.prob.mb_stat_R & 0xff0000) {
 121                 /* Read the first available word.
 122                  * Implementation note: the depth
 123                  * of puint_mb_R is currently 1.
 124                  */
 125                 *data = ctx->csa.priv2.puint_mb_R;
 126                 ctx->csa.prob.mb_stat_R &= ~(0xff0000);
 127                 ctx->csa.spu_chnlcnt_RW[30] = 1;
 128                 gen_spu_event(ctx, MFC_PU_INT_MAILBOX_AVAILABLE_EVENT);
 129                 ret = 4;
 130         } else {
 131                 /* make sure we get woken up by the interrupt */
 132                 ctx->csa.priv1.int_mask_class2_RW |= CLASS2_ENABLE_MAILBOX_INTR;
 133                 ret = 0;
 134         }
 135         spin_unlock(&ctx->csa.register_lock);
 136         return ret;
 137 }
 138 
 139 static int spu_backing_wbox_write(struct spu_context *ctx, u32 data)
 140 {
 141         int ret;
 142 
 143         spin_lock(&ctx->csa.register_lock);
 144         if ((ctx->csa.prob.mb_stat_R) & 0x00ff00) {
 145                 int slot = ctx->csa.spu_chnlcnt_RW[29];
 146                 int avail = (ctx->csa.prob.mb_stat_R & 0x00ff00) >> 8;
 147 
 148                 /* We have space to write wbox_data.
 149                  * Implementation note: the depth
 150                  * of spu_mb_W is currently 4.
 151                  */
 152                 BUG_ON(avail != (4 - slot));
 153                 ctx->csa.spu_mailbox_data[slot] = data;
 154                 ctx->csa.spu_chnlcnt_RW[29] = ++slot;
 155                 ctx->csa.prob.mb_stat_R &= ~(0x00ff00);
 156                 ctx->csa.prob.mb_stat_R |= (((4 - slot) & 0xff) << 8);
 157                 gen_spu_event(ctx, MFC_SPU_MAILBOX_WRITTEN_EVENT);
 158                 ret = 4;
 159         } else {
 160                 /* make sure we get woken up by the interrupt when space
 161                    becomes available */
 162                 ctx->csa.priv1.int_mask_class2_RW |=
 163                         CLASS2_ENABLE_MAILBOX_THRESHOLD_INTR;
 164                 ret = 0;
 165         }
 166         spin_unlock(&ctx->csa.register_lock);
 167         return ret;
 168 }
 169 
 170 static u32 spu_backing_signal1_read(struct spu_context *ctx)
 171 {
 172         return ctx->csa.spu_chnldata_RW[3];
 173 }
 174 
 175 static void spu_backing_signal1_write(struct spu_context *ctx, u32 data)
 176 {
 177         spin_lock(&ctx->csa.register_lock);
 178         if (ctx->csa.priv2.spu_cfg_RW & 0x1)
 179                 ctx->csa.spu_chnldata_RW[3] |= data;
 180         else
 181                 ctx->csa.spu_chnldata_RW[3] = data;
 182         ctx->csa.spu_chnlcnt_RW[3] = 1;
 183         gen_spu_event(ctx, MFC_SIGNAL_1_EVENT);
 184         spin_unlock(&ctx->csa.register_lock);
 185 }
 186 
 187 static u32 spu_backing_signal2_read(struct spu_context *ctx)
 188 {
 189         return ctx->csa.spu_chnldata_RW[4];
 190 }
 191 
 192 static void spu_backing_signal2_write(struct spu_context *ctx, u32 data)
 193 {
 194         spin_lock(&ctx->csa.register_lock);
 195         if (ctx->csa.priv2.spu_cfg_RW & 0x2)
 196                 ctx->csa.spu_chnldata_RW[4] |= data;
 197         else
 198                 ctx->csa.spu_chnldata_RW[4] = data;
 199         ctx->csa.spu_chnlcnt_RW[4] = 1;
 200         gen_spu_event(ctx, MFC_SIGNAL_2_EVENT);
 201         spin_unlock(&ctx->csa.register_lock);
 202 }
 203 
 204 static void spu_backing_signal1_type_set(struct spu_context *ctx, u64 val)
 205 {
 206         u64 tmp;
 207 
 208         spin_lock(&ctx->csa.register_lock);
 209         tmp = ctx->csa.priv2.spu_cfg_RW;
 210         if (val)
 211                 tmp |= 1;
 212         else
 213                 tmp &= ~1;
 214         ctx->csa.priv2.spu_cfg_RW = tmp;
 215         spin_unlock(&ctx->csa.register_lock);
 216 }
 217 
 218 static u64 spu_backing_signal1_type_get(struct spu_context *ctx)
 219 {
 220         return ((ctx->csa.priv2.spu_cfg_RW & 1) != 0);
 221 }
 222 
 223 static void spu_backing_signal2_type_set(struct spu_context *ctx, u64 val)
 224 {
 225         u64 tmp;
 226 
 227         spin_lock(&ctx->csa.register_lock);
 228         tmp = ctx->csa.priv2.spu_cfg_RW;
 229         if (val)
 230                 tmp |= 2;
 231         else
 232                 tmp &= ~2;
 233         ctx->csa.priv2.spu_cfg_RW = tmp;
 234         spin_unlock(&ctx->csa.register_lock);
 235 }
 236 
 237 static u64 spu_backing_signal2_type_get(struct spu_context *ctx)
 238 {
 239         return ((ctx->csa.priv2.spu_cfg_RW & 2) != 0);
 240 }
 241 
 242 static u32 spu_backing_npc_read(struct spu_context *ctx)
 243 {
 244         return ctx->csa.prob.spu_npc_RW;
 245 }
 246 
 247 static void spu_backing_npc_write(struct spu_context *ctx, u32 val)
 248 {
 249         ctx->csa.prob.spu_npc_RW = val;
 250 }
 251 
 252 static u32 spu_backing_status_read(struct spu_context *ctx)
 253 {
 254         return ctx->csa.prob.spu_status_R;
 255 }
 256 
 257 static char *spu_backing_get_ls(struct spu_context *ctx)
 258 {
 259         return ctx->csa.lscsa->ls;
 260 }
 261 
 262 static void spu_backing_privcntl_write(struct spu_context *ctx, u64 val)
 263 {
 264         ctx->csa.priv2.spu_privcntl_RW = val;
 265 }
 266 
 267 static u32 spu_backing_runcntl_read(struct spu_context *ctx)
 268 {
 269         return ctx->csa.prob.spu_runcntl_RW;
 270 }
 271 
 272 static void spu_backing_runcntl_write(struct spu_context *ctx, u32 val)
 273 {
 274         spin_lock(&ctx->csa.register_lock);
 275         ctx->csa.prob.spu_runcntl_RW = val;
 276         if (val & SPU_RUNCNTL_RUNNABLE) {
 277                 ctx->csa.prob.spu_status_R &=
 278                         ~SPU_STATUS_STOPPED_BY_STOP &
 279                         ~SPU_STATUS_STOPPED_BY_HALT &
 280                         ~SPU_STATUS_SINGLE_STEP &
 281                         ~SPU_STATUS_INVALID_INSTR &
 282                         ~SPU_STATUS_INVALID_CH;
 283                 ctx->csa.prob.spu_status_R |= SPU_STATUS_RUNNING;
 284         } else {
 285                 ctx->csa.prob.spu_status_R &= ~SPU_STATUS_RUNNING;
 286         }
 287         spin_unlock(&ctx->csa.register_lock);
 288 }
 289 
 290 static void spu_backing_runcntl_stop(struct spu_context *ctx)
 291 {
 292         spu_backing_runcntl_write(ctx, SPU_RUNCNTL_STOP);
 293 }
 294 
 295 static void spu_backing_master_start(struct spu_context *ctx)
 296 {
 297         struct spu_state *csa = &ctx->csa;
 298         u64 sr1;
 299 
 300         spin_lock(&csa->register_lock);
 301         sr1 = csa->priv1.mfc_sr1_RW | MFC_STATE1_MASTER_RUN_CONTROL_MASK;
 302         csa->priv1.mfc_sr1_RW = sr1;
 303         spin_unlock(&csa->register_lock);
 304 }
 305 
 306 static void spu_backing_master_stop(struct spu_context *ctx)
 307 {
 308         struct spu_state *csa = &ctx->csa;
 309         u64 sr1;
 310 
 311         spin_lock(&csa->register_lock);
 312         sr1 = csa->priv1.mfc_sr1_RW & ~MFC_STATE1_MASTER_RUN_CONTROL_MASK;
 313         csa->priv1.mfc_sr1_RW = sr1;
 314         spin_unlock(&csa->register_lock);
 315 }
 316 
 317 static int spu_backing_set_mfc_query(struct spu_context * ctx, u32 mask,
 318                                         u32 mode)
 319 {
 320         struct spu_problem_collapsed *prob = &ctx->csa.prob;
 321         int ret;
 322 
 323         spin_lock(&ctx->csa.register_lock);
 324         ret = -EAGAIN;
 325         if (prob->dma_querytype_RW)
 326                 goto out;
 327         ret = 0;
 328         /* FIXME: what are the side-effects of this? */
 329         prob->dma_querymask_RW = mask;
 330         prob->dma_querytype_RW = mode;
 331         /* In the current implementation, the SPU context is always
 332          * acquired in runnable state when new bits are added to the
 333          * mask (tagwait), so it's sufficient just to mask
 334          * dma_tagstatus_R with the 'mask' parameter here.
 335          */
 336         ctx->csa.prob.dma_tagstatus_R &= mask;
 337 out:
 338         spin_unlock(&ctx->csa.register_lock);
 339 
 340         return ret;
 341 }
 342 
 343 static u32 spu_backing_read_mfc_tagstatus(struct spu_context * ctx)
 344 {
 345         return ctx->csa.prob.dma_tagstatus_R;
 346 }
 347 
 348 static u32 spu_backing_get_mfc_free_elements(struct spu_context *ctx)
 349 {
 350         return ctx->csa.prob.dma_qstatus_R;
 351 }
 352 
 353 static int spu_backing_send_mfc_command(struct spu_context *ctx,
 354                                         struct mfc_dma_command *cmd)
 355 {
 356         int ret;
 357 
 358         spin_lock(&ctx->csa.register_lock);
 359         ret = -EAGAIN;
 360         /* FIXME: set up priv2->puq */
 361         spin_unlock(&ctx->csa.register_lock);
 362 
 363         return ret;
 364 }
 365 
 366 static void spu_backing_restart_dma(struct spu_context *ctx)
 367 {
 368         ctx->csa.priv2.mfc_control_RW |= MFC_CNTL_RESTART_DMA_COMMAND;
 369 }
 370 
 371 struct spu_context_ops spu_backing_ops = {
 372         .mbox_read = spu_backing_mbox_read,
 373         .mbox_stat_read = spu_backing_mbox_stat_read,
 374         .mbox_stat_poll = spu_backing_mbox_stat_poll,
 375         .ibox_read = spu_backing_ibox_read,
 376         .wbox_write = spu_backing_wbox_write,
 377         .signal1_read = spu_backing_signal1_read,
 378         .signal1_write = spu_backing_signal1_write,
 379         .signal2_read = spu_backing_signal2_read,
 380         .signal2_write = spu_backing_signal2_write,
 381         .signal1_type_set = spu_backing_signal1_type_set,
 382         .signal1_type_get = spu_backing_signal1_type_get,
 383         .signal2_type_set = spu_backing_signal2_type_set,
 384         .signal2_type_get = spu_backing_signal2_type_get,
 385         .npc_read = spu_backing_npc_read,
 386         .npc_write = spu_backing_npc_write,
 387         .status_read = spu_backing_status_read,
 388         .get_ls = spu_backing_get_ls,
 389         .privcntl_write = spu_backing_privcntl_write,
 390         .runcntl_read = spu_backing_runcntl_read,
 391         .runcntl_write = spu_backing_runcntl_write,
 392         .runcntl_stop = spu_backing_runcntl_stop,
 393         .master_start = spu_backing_master_start,
 394         .master_stop = spu_backing_master_stop,
 395         .set_mfc_query = spu_backing_set_mfc_query,
 396         .read_mfc_tagstatus = spu_backing_read_mfc_tagstatus,
 397         .get_mfc_free_elements = spu_backing_get_mfc_free_elements,
 398         .send_mfc_command = spu_backing_send_mfc_command,
 399         .restart_dma = spu_backing_restart_dma,
 400 };

/* [<][>][^][v][top][bottom][index][help] */