linux/drivers/gpu/drm/nouveau/nv84_fence.c
<<
>>
Prefs
   1/*
   2 * Copyright 2012 Red Hat Inc.
   3 *
   4 * Permission is hereby granted, free of charge, to any person obtaining a
   5 * copy of this software and associated documentation files (the "Software"),
   6 * to deal in the Software without restriction, including without limitation
   7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
   8 * and/or sell copies of the Software, and to permit persons to whom the
   9 * Software is furnished to do so, subject to the following conditions:
  10 *
  11 * The above copyright notice and this permission notice shall be included in
  12 * all copies or substantial portions of the Software.
  13 *
  14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
  17 * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
  18 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
  19 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
  20 * OTHER DEALINGS IN THE SOFTWARE.
  21 *
  22 * Authors: Ben Skeggs
  23 */
  24
  25#include <core/object.h>
  26#include <core/client.h>
  27#include <core/class.h>
  28
  29#include <engine/fifo.h>
  30
  31#include "nouveau_drm.h"
  32#include "nouveau_dma.h"
  33#include "nouveau_fence.h"
  34
  35#include "nv50_display.h"
  36
  37u64
  38nv84_fence_crtc(struct nouveau_channel *chan, int crtc)
  39{
  40        struct nv84_fence_chan *fctx = chan->fence;
  41        return fctx->dispc_vma[crtc].offset;
  42}
  43
  44static int
  45nv84_fence_emit32(struct nouveau_channel *chan, u64 virtual, u32 sequence)
  46{
  47        int ret = RING_SPACE(chan, 8);
  48        if (ret == 0) {
  49                BEGIN_NV04(chan, 0, NV11_SUBCHAN_DMA_SEMAPHORE, 1);
  50                OUT_RING  (chan, chan->vram);
  51                BEGIN_NV04(chan, 0, NV84_SUBCHAN_SEMAPHORE_ADDRESS_HIGH, 5);
  52                OUT_RING  (chan, upper_32_bits(virtual));
  53                OUT_RING  (chan, lower_32_bits(virtual));
  54                OUT_RING  (chan, sequence);
  55                OUT_RING  (chan, NV84_SUBCHAN_SEMAPHORE_TRIGGER_WRITE_LONG);
  56                OUT_RING  (chan, 0x00000000);
  57                FIRE_RING (chan);
  58        }
  59        return ret;
  60}
  61
  62static int
  63nv84_fence_sync32(struct nouveau_channel *chan, u64 virtual, u32 sequence)
  64{
  65        int ret = RING_SPACE(chan, 7);
  66        if (ret == 0) {
  67                BEGIN_NV04(chan, 0, NV11_SUBCHAN_DMA_SEMAPHORE, 1);
  68                OUT_RING  (chan, chan->vram);
  69                BEGIN_NV04(chan, 0, NV84_SUBCHAN_SEMAPHORE_ADDRESS_HIGH, 4);
  70                OUT_RING  (chan, upper_32_bits(virtual));
  71                OUT_RING  (chan, lower_32_bits(virtual));
  72                OUT_RING  (chan, sequence);
  73                OUT_RING  (chan, NV84_SUBCHAN_SEMAPHORE_TRIGGER_ACQUIRE_GEQUAL);
  74                FIRE_RING (chan);
  75        }
  76        return ret;
  77}
  78
  79static int
  80nv84_fence_emit(struct nouveau_fence *fence)
  81{
  82        struct nouveau_channel *chan = fence->channel;
  83        struct nv84_fence_chan *fctx = chan->fence;
  84        struct nouveau_fifo_chan *fifo = (void *)chan->object;
  85        u64 addr = fifo->chid * 16;
  86
  87        if (fence->sysmem)
  88                addr += fctx->vma_gart.offset;
  89        else
  90                addr += fctx->vma.offset;
  91
  92        return fctx->base.emit32(chan, addr, fence->sequence);
  93}
  94
  95static int
  96nv84_fence_sync(struct nouveau_fence *fence,
  97                struct nouveau_channel *prev, struct nouveau_channel *chan)
  98{
  99        struct nv84_fence_chan *fctx = chan->fence;
 100        struct nouveau_fifo_chan *fifo = (void *)prev->object;
 101        u64 addr = fifo->chid * 16;
 102
 103        if (fence->sysmem)
 104                addr += fctx->vma_gart.offset;
 105        else
 106                addr += fctx->vma.offset;
 107
 108        return fctx->base.sync32(chan, addr, fence->sequence);
 109}
 110
 111static u32
 112nv84_fence_read(struct nouveau_channel *chan)
 113{
 114        struct nouveau_fifo_chan *fifo = (void *)chan->object;
 115        struct nv84_fence_priv *priv = chan->drm->fence;
 116        return nouveau_bo_rd32(priv->bo, fifo->chid * 16/4);
 117}
 118
 119static void
 120nv84_fence_context_del(struct nouveau_channel *chan)
 121{
 122        struct drm_device *dev = chan->drm->dev;
 123        struct nv84_fence_priv *priv = chan->drm->fence;
 124        struct nv84_fence_chan *fctx = chan->fence;
 125        int i;
 126
 127        for (i = 0; i < dev->mode_config.num_crtc; i++) {
 128                struct nouveau_bo *bo = nv50_display_crtc_sema(dev, i);
 129                nouveau_bo_vma_del(bo, &fctx->dispc_vma[i]);
 130        }
 131
 132        nouveau_bo_vma_del(priv->bo, &fctx->vma_gart);
 133        nouveau_bo_vma_del(priv->bo, &fctx->vma);
 134        nouveau_fence_context_del(&fctx->base);
 135        chan->fence = NULL;
 136        kfree(fctx);
 137}
 138
 139int
 140nv84_fence_context_new(struct nouveau_channel *chan)
 141{
 142        struct nouveau_fifo_chan *fifo = (void *)chan->object;
 143        struct nouveau_client *client = nouveau_client(fifo);
 144        struct nv84_fence_priv *priv = chan->drm->fence;
 145        struct nv84_fence_chan *fctx;
 146        int ret, i;
 147
 148        fctx = chan->fence = kzalloc(sizeof(*fctx), GFP_KERNEL);
 149        if (!fctx)
 150                return -ENOMEM;
 151
 152        nouveau_fence_context_new(&fctx->base);
 153        fctx->base.emit = nv84_fence_emit;
 154        fctx->base.sync = nv84_fence_sync;
 155        fctx->base.read = nv84_fence_read;
 156        fctx->base.emit32 = nv84_fence_emit32;
 157        fctx->base.sync32 = nv84_fence_sync32;
 158
 159        ret = nouveau_bo_vma_add(priv->bo, client->vm, &fctx->vma);
 160        if (ret == 0) {
 161                ret = nouveau_bo_vma_add(priv->bo_gart, client->vm,
 162                                        &fctx->vma_gart);
 163        }
 164
 165        /* map display semaphore buffers into channel's vm */
 166        for (i = 0; !ret && i < chan->drm->dev->mode_config.num_crtc; i++) {
 167                struct nouveau_bo *bo = nv50_display_crtc_sema(chan->drm->dev, i);
 168                ret = nouveau_bo_vma_add(bo, client->vm, &fctx->dispc_vma[i]);
 169        }
 170
 171        nouveau_bo_wr32(priv->bo, fifo->chid * 16/4, 0x00000000);
 172
 173        if (ret)
 174                nv84_fence_context_del(chan);
 175        return ret;
 176}
 177
 178static bool
 179nv84_fence_suspend(struct nouveau_drm *drm)
 180{
 181        struct nouveau_fifo *pfifo = nouveau_fifo(drm->device);
 182        struct nv84_fence_priv *priv = drm->fence;
 183        int i;
 184
 185        priv->suspend = vmalloc((pfifo->max + 1) * sizeof(u32));
 186        if (priv->suspend) {
 187                for (i = 0; i <= pfifo->max; i++)
 188                        priv->suspend[i] = nouveau_bo_rd32(priv->bo, i*4);
 189        }
 190
 191        return priv->suspend != NULL;
 192}
 193
 194static void
 195nv84_fence_resume(struct nouveau_drm *drm)
 196{
 197        struct nouveau_fifo *pfifo = nouveau_fifo(drm->device);
 198        struct nv84_fence_priv *priv = drm->fence;
 199        int i;
 200
 201        if (priv->suspend) {
 202                for (i = 0; i <= pfifo->max; i++)
 203                        nouveau_bo_wr32(priv->bo, i*4, priv->suspend[i]);
 204                vfree(priv->suspend);
 205                priv->suspend = NULL;
 206        }
 207}
 208
 209static void
 210nv84_fence_destroy(struct nouveau_drm *drm)
 211{
 212        struct nv84_fence_priv *priv = drm->fence;
 213        nouveau_bo_unmap(priv->bo_gart);
 214        if (priv->bo_gart)
 215                nouveau_bo_unpin(priv->bo_gart);
 216        nouveau_bo_ref(NULL, &priv->bo_gart);
 217        nouveau_bo_unmap(priv->bo);
 218        if (priv->bo)
 219                nouveau_bo_unpin(priv->bo);
 220        nouveau_bo_ref(NULL, &priv->bo);
 221        drm->fence = NULL;
 222        kfree(priv);
 223}
 224
 225int
 226nv84_fence_create(struct nouveau_drm *drm)
 227{
 228        struct nouveau_fifo *pfifo = nouveau_fifo(drm->device);
 229        struct nv84_fence_priv *priv;
 230        int ret;
 231
 232        priv = drm->fence = kzalloc(sizeof(*priv), GFP_KERNEL);
 233        if (!priv)
 234                return -ENOMEM;
 235
 236        priv->base.dtor = nv84_fence_destroy;
 237        priv->base.suspend = nv84_fence_suspend;
 238        priv->base.resume = nv84_fence_resume;
 239        priv->base.context_new = nv84_fence_context_new;
 240        priv->base.context_del = nv84_fence_context_del;
 241
 242        init_waitqueue_head(&priv->base.waiting);
 243        priv->base.uevent = true;
 244
 245        ret = nouveau_bo_new(drm->dev, 16 * (pfifo->max + 1), 0,
 246                             TTM_PL_FLAG_VRAM, 0, 0, NULL, &priv->bo);
 247        if (ret == 0) {
 248                ret = nouveau_bo_pin(priv->bo, TTM_PL_FLAG_VRAM);
 249                if (ret == 0) {
 250                        ret = nouveau_bo_map(priv->bo);
 251                        if (ret)
 252                                nouveau_bo_unpin(priv->bo);
 253                }
 254                if (ret)
 255                        nouveau_bo_ref(NULL, &priv->bo);
 256        }
 257
 258        if (ret == 0)
 259                ret = nouveau_bo_new(drm->dev, 16 * (pfifo->max + 1), 0,
 260                                     TTM_PL_FLAG_TT, 0, 0, NULL,
 261                                     &priv->bo_gart);
 262        if (ret == 0) {
 263                ret = nouveau_bo_pin(priv->bo_gart, TTM_PL_FLAG_TT);
 264                if (ret == 0) {
 265                        ret = nouveau_bo_map(priv->bo_gart);
 266                        if (ret)
 267                                nouveau_bo_unpin(priv->bo_gart);
 268                }
 269                if (ret)
 270                        nouveau_bo_ref(NULL, &priv->bo_gart);
 271        }
 272
 273        if (ret)
 274                nv84_fence_destroy(drm);
 275        return ret;
 276}
 277