Home | History | Annotate | Line # | Download | only in nouveau
      1 /*	$NetBSD: nouveau_nv84_fence.c,v 1.8 2021/12/18 23:45:32 riastradh Exp $	*/
      2 
      3 /*
      4  * Copyright 2012 Red Hat Inc.
      5  *
      6  * Permission is hereby granted, free of charge, to any person obtaining a
      7  * copy of this software and associated documentation files (the "Software"),
      8  * to deal in the Software without restriction, including without limitation
      9  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
     10  * and/or sell copies of the Software, and to permit persons to whom the
     11  * Software is furnished to do so, subject to the following conditions:
     12  *
     13  * The above copyright notice and this permission notice shall be included in
     14  * all copies or substantial portions of the Software.
     15  *
     16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     17  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     18  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
     19  * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
     20  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
     21  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
     22  * OTHER DEALINGS IN THE SOFTWARE.
     23  *
     24  * Authors: Ben Skeggs
     25  */
     26 
     27 #include <sys/cdefs.h>
     28 __KERNEL_RCSID(0, "$NetBSD: nouveau_nv84_fence.c,v 1.8 2021/12/18 23:45:32 riastradh Exp $");
     29 
     30 #include "nouveau_drv.h"
     31 #include "nouveau_dma.h"
     32 #include "nouveau_fence.h"
     33 #include "nouveau_vmm.h"
     34 
     35 #include "nv50_display.h"
     36 
     37 #include <linux/nbsd-namespace.h>
     38 
     39 static int
     40 nv84_fence_emit32(struct nouveau_channel *chan, u64 virtual, u32 sequence)
     41 {
     42 	int ret = RING_SPACE(chan, 8);
     43 	if (ret == 0) {
     44 		BEGIN_NV04(chan, 0, NV11_SUBCHAN_DMA_SEMAPHORE, 1);
     45 		OUT_RING  (chan, chan->vram.handle);
     46 		BEGIN_NV04(chan, 0, NV84_SUBCHAN_SEMAPHORE_ADDRESS_HIGH, 5);
     47 		OUT_RING  (chan, upper_32_bits(virtual));
     48 		OUT_RING  (chan, lower_32_bits(virtual));
     49 		OUT_RING  (chan, sequence);
     50 		OUT_RING  (chan, NV84_SUBCHAN_SEMAPHORE_TRIGGER_WRITE_LONG);
     51 		OUT_RING  (chan, 0x00000000);
     52 		FIRE_RING (chan);
     53 	}
     54 	return ret;
     55 }
     56 
     57 static int
     58 nv84_fence_sync32(struct nouveau_channel *chan, u64 virtual, u32 sequence)
     59 {
     60 	int ret = RING_SPACE(chan, 7);
     61 	if (ret == 0) {
     62 		BEGIN_NV04(chan, 0, NV11_SUBCHAN_DMA_SEMAPHORE, 1);
     63 		OUT_RING  (chan, chan->vram.handle);
     64 		BEGIN_NV04(chan, 0, NV84_SUBCHAN_SEMAPHORE_ADDRESS_HIGH, 4);
     65 		OUT_RING  (chan, upper_32_bits(virtual));
     66 		OUT_RING  (chan, lower_32_bits(virtual));
     67 		OUT_RING  (chan, sequence);
     68 		OUT_RING  (chan, NV84_SUBCHAN_SEMAPHORE_TRIGGER_ACQUIRE_GEQUAL);
     69 		FIRE_RING (chan);
     70 	}
     71 	return ret;
     72 }
     73 
     74 static int
     75 nv84_fence_emit(struct nouveau_fence *fence)
     76 {
     77 	struct nouveau_channel *chan = fence->channel;
     78 	struct nv84_fence_chan *fctx = chan->fence;
     79 	u64 addr = fctx->vma->addr + chan->chid * 16;
     80 
     81 	return fctx->base.emit32(chan, addr, fence->base.seqno);
     82 }
     83 
     84 static int
     85 nv84_fence_sync(struct nouveau_fence *fence,
     86 		struct nouveau_channel *prev, struct nouveau_channel *chan)
     87 {
     88 	struct nv84_fence_chan *fctx = chan->fence;
     89 	u64 addr = fctx->vma->addr + prev->chid * 16;
     90 
     91 	return fctx->base.sync32(chan, addr, fence->base.seqno);
     92 }
     93 
     94 static u32
     95 nv84_fence_read(struct nouveau_channel *chan)
     96 {
     97 	struct nv84_fence_priv *priv = chan->drm->fence;
     98 	return nouveau_bo_rd32(priv->bo, chan->chid * 16/4);
     99 }
    100 
    101 static void
    102 nv84_fence_context_del(struct nouveau_channel *chan)
    103 {
    104 	struct nv84_fence_priv *priv = chan->drm->fence;
    105 	struct nv84_fence_chan *fctx = chan->fence;
    106 
    107 	nouveau_bo_wr32(priv->bo, chan->chid * 16 / 4, fctx->base.sequence);
    108 	mutex_lock(&priv->mutex);
    109 	nouveau_vma_del(&fctx->vma);
    110 	mutex_unlock(&priv->mutex);
    111 	nouveau_fence_context_del(&fctx->base);
    112 	chan->fence = NULL;
    113 	nouveau_fence_context_free(&fctx->base);
    114 }
    115 
    116 int
    117 nv84_fence_context_new(struct nouveau_channel *chan)
    118 {
    119 	struct nv84_fence_priv *priv = chan->drm->fence;
    120 	struct nv84_fence_chan *fctx;
    121 	int ret;
    122 
    123 	fctx = chan->fence = kzalloc(sizeof(*fctx), GFP_KERNEL);
    124 	if (!fctx)
    125 		return -ENOMEM;
    126 
    127 	nouveau_fence_context_new(chan, &fctx->base);
    128 	fctx->base.emit = nv84_fence_emit;
    129 	fctx->base.sync = nv84_fence_sync;
    130 	fctx->base.read = nv84_fence_read;
    131 	fctx->base.emit32 = nv84_fence_emit32;
    132 	fctx->base.sync32 = nv84_fence_sync32;
    133 	fctx->base.sequence = nv84_fence_read(chan);
    134 
    135 	mutex_lock(&priv->mutex);
    136 	ret = nouveau_vma_new(priv->bo, chan->vmm, &fctx->vma);
    137 	mutex_unlock(&priv->mutex);
    138 
    139 	if (ret)
    140 		nv84_fence_context_del(chan);
    141 	return ret;
    142 }
    143 
    144 static bool
    145 nv84_fence_suspend(struct nouveau_drm *drm)
    146 {
    147 	struct nv84_fence_priv *priv = drm->fence;
    148 	int i;
    149 
    150 	priv->suspend = vmalloc(array_size(sizeof(u32), drm->chan.nr));
    151 	if (priv->suspend) {
    152 		for (i = 0; i < drm->chan.nr; i++)
    153 			priv->suspend[i] = nouveau_bo_rd32(priv->bo, i*4);
    154 	}
    155 
    156 	return priv->suspend != NULL;
    157 }
    158 
    159 static void
    160 nv84_fence_resume(struct nouveau_drm *drm)
    161 {
    162 	struct nv84_fence_priv *priv = drm->fence;
    163 	int i;
    164 
    165 	if (priv->suspend) {
    166 		for (i = 0; i < drm->chan.nr; i++)
    167 			nouveau_bo_wr32(priv->bo, i*4, priv->suspend[i]);
    168 		vfree(priv->suspend);
    169 		priv->suspend = NULL;
    170 	}
    171 }
    172 
    173 static void
    174 nv84_fence_destroy(struct nouveau_drm *drm)
    175 {
    176 	struct nv84_fence_priv *priv = drm->fence;
    177 	nouveau_bo_unmap(priv->bo);
    178 	if (priv->bo)
    179 		nouveau_bo_unpin(priv->bo);
    180 	nouveau_bo_ref(NULL, &priv->bo);
    181 	drm->fence = NULL;
    182 	mutex_destroy(&priv->mutex);
    183 	kfree(priv);
    184 }
    185 
    186 int
    187 nv84_fence_create(struct nouveau_drm *drm)
    188 {
    189 	struct nv84_fence_priv *priv;
    190 	u32 domain;
    191 	int ret;
    192 
    193 	priv = drm->fence = kzalloc(sizeof(*priv), GFP_KERNEL);
    194 	if (!priv)
    195 		return -ENOMEM;
    196 
    197 	priv->base.dtor = nv84_fence_destroy;
    198 	priv->base.suspend = nv84_fence_suspend;
    199 	priv->base.resume = nv84_fence_resume;
    200 	priv->base.context_new = nv84_fence_context_new;
    201 	priv->base.context_del = nv84_fence_context_del;
    202 
    203 	priv->base.uevent = true;
    204 
    205 	mutex_init(&priv->mutex);
    206 
    207 	/* Use VRAM if there is any ; otherwise fallback to system memory */
    208 	domain = drm->client.device.info.ram_size != 0 ? TTM_PL_FLAG_VRAM :
    209 			 /*
    210 			  * fences created in sysmem must be non-cached or we
    211 			  * will lose CPU/GPU coherency!
    212 			  */
    213 			 TTM_PL_FLAG_TT | TTM_PL_FLAG_UNCACHED;
    214 	ret = nouveau_bo_new(&drm->client, 16 * drm->chan.nr, 0,
    215 			     domain, 0, 0, NULL, NULL, &priv->bo);
    216 	if (ret == 0) {
    217 		ret = nouveau_bo_pin(priv->bo, domain, false);
    218 		if (ret == 0) {
    219 			ret = nouveau_bo_map(priv->bo);
    220 			if (ret)
    221 				nouveau_bo_unpin(priv->bo);
    222 		}
    223 		if (ret)
    224 			nouveau_bo_ref(NULL, &priv->bo);
    225 	}
    226 
    227 	if (ret)
    228 		nv84_fence_destroy(drm);
    229 	return ret;
    230 }
    231