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 "drmP.h" 26 #include "nouveau_drv.h" 27 #include "nouveau_dma.h" 28 #include "nouveau_fifo.h" 29 #include "nouveau_ramht.h" 30 #include "nouveau_fence.h" 31 32 struct nvc0_fence_priv { 33 struct nouveau_fence_priv base; 34 struct nouveau_bo *bo; 35 }; 36 37 struct nvc0_fence_chan { 38 struct nouveau_fence_chan base; 39 struct nouveau_vma vma; 40 }; 41 42 static int 43 nvc0_fence_emit(struct nouveau_fence *fence) 44 { 45 struct nouveau_channel *chan = fence->channel; 46 struct nvc0_fence_chan *fctx = chan->engctx[NVOBJ_ENGINE_FENCE]; 47 u64 addr = fctx->vma.offset + chan->id * 16; 48 int ret; 49 50 ret = RING_SPACE(chan, 5); 51 if (ret == 0) { 52 BEGIN_NVC0(chan, 0, NV84_SUBCHAN_SEMAPHORE_ADDRESS_HIGH, 4); 53 OUT_RING (chan, upper_32_bits(addr)); 54 OUT_RING (chan, lower_32_bits(addr)); 55 OUT_RING (chan, fence->sequence); 56 OUT_RING (chan, NV84_SUBCHAN_SEMAPHORE_TRIGGER_WRITE_LONG); 57 FIRE_RING (chan); 58 } 59 60 return ret; 61 } 62 63 static int 64 nvc0_fence_sync(struct nouveau_fence *fence, 65 struct nouveau_channel *prev, struct nouveau_channel *chan) 66 { 67 struct nvc0_fence_chan *fctx = chan->engctx[NVOBJ_ENGINE_FENCE]; 68 u64 addr = fctx->vma.offset + prev->id * 16; 69 int ret; 70 71 ret = RING_SPACE(chan, 5); 72 if (ret == 0) { 73 BEGIN_NVC0(chan, 0, NV84_SUBCHAN_SEMAPHORE_ADDRESS_HIGH, 4); 74 OUT_RING (chan, upper_32_bits(addr)); 75 OUT_RING (chan, lower_32_bits(addr)); 76 OUT_RING (chan, fence->sequence); 77 OUT_RING (chan, NV84_SUBCHAN_SEMAPHORE_TRIGGER_ACQUIRE_GEQUAL | 78 NVC0_SUBCHAN_SEMAPHORE_TRIGGER_YIELD); 79 FIRE_RING (chan); 80 } 81 82 return ret; 83 } 84 85 static u32 86 nvc0_fence_read(struct nouveau_channel *chan) 87 { 88 struct nvc0_fence_priv *priv = nv_engine(chan->dev, NVOBJ_ENGINE_FENCE); 89 return nouveau_bo_rd32(priv->bo, chan->id * 16/4); 90 } 91 92 static void 93 nvc0_fence_context_del(struct nouveau_channel *chan, int engine) 94 { 95 struct nvc0_fence_priv *priv = nv_engine(chan->dev, engine); 96 struct nvc0_fence_chan *fctx = chan->engctx[engine]; 97 98 nouveau_bo_vma_del(priv->bo, &fctx->vma); 99 nouveau_fence_context_del(&fctx->base); 100 chan->engctx[engine] = NULL; 101 kfree(fctx); 102 } 103 104 static int 105 nvc0_fence_context_new(struct nouveau_channel *chan, int engine) 106 { 107 struct nvc0_fence_priv *priv = nv_engine(chan->dev, engine); 108 struct nvc0_fence_chan *fctx; 109 int ret; 110 111 fctx = chan->engctx[engine] = kzalloc(sizeof(*fctx), GFP_KERNEL); 112 if (!fctx) 113 return -ENOMEM; 114 115 nouveau_fence_context_new(&fctx->base); 116 117 ret = nouveau_bo_vma_add(priv->bo, chan->vm, &fctx->vma); 118 if (ret) 119 nvc0_fence_context_del(chan, engine); 120 121 nouveau_bo_wr32(priv->bo, chan->id * 16/4, 0x00000000); 122 return ret; 123 } 124 125 static int 126 nvc0_fence_fini(struct drm_device *dev, int engine, bool suspend) 127 { 128 return 0; 129 } 130 131 static int 132 nvc0_fence_init(struct drm_device *dev, int engine) 133 { 134 return 0; 135 } 136 137 static void 138 nvc0_fence_destroy(struct drm_device *dev, int engine) 139 { 140 struct drm_nouveau_private *dev_priv = dev->dev_private; 141 struct nvc0_fence_priv *priv = nv_engine(dev, engine); 142 143 nouveau_bo_unmap(priv->bo); 144 nouveau_bo_ref(NULL, &priv->bo); 145 dev_priv->eng[engine] = NULL; 146 kfree(priv); 147 } 148 149 int 150 nvc0_fence_create(struct drm_device *dev) 151 { 152 struct nouveau_fifo_priv *pfifo = nv_engine(dev, NVOBJ_ENGINE_FIFO); 153 struct drm_nouveau_private *dev_priv = dev->dev_private; 154 struct nvc0_fence_priv *priv; 155 int ret; 156 157 priv = kzalloc(sizeof(*priv), GFP_KERNEL); 158 if (!priv) 159 return -ENOMEM; 160 161 priv->base.engine.destroy = nvc0_fence_destroy; 162 priv->base.engine.init = nvc0_fence_init; 163 priv->base.engine.fini = nvc0_fence_fini; 164 priv->base.engine.context_new = nvc0_fence_context_new; 165 priv->base.engine.context_del = nvc0_fence_context_del; 166 priv->base.emit = nvc0_fence_emit; 167 priv->base.sync = nvc0_fence_sync; 168 priv->base.read = nvc0_fence_read; 169 dev_priv->eng[NVOBJ_ENGINE_FENCE] = &priv->base.engine; 170 171 ret = nouveau_bo_new(dev, 16 * pfifo->channels, 0, TTM_PL_FLAG_VRAM, 172 0, 0, NULL, &priv->bo); 173 if (ret == 0) { 174 ret = nouveau_bo_pin(priv->bo, TTM_PL_FLAG_VRAM); 175 if (ret == 0) 176 ret = nouveau_bo_map(priv->bo); 177 if (ret) 178 nouveau_bo_ref(NULL, &priv->bo); 179 } 180 181 if (ret) 182 nvc0_fence_destroy(dev, NVOBJ_ENGINE_FENCE); 183 return ret; 184 } 185