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