162306a36Sopenharmony_ci/*
262306a36Sopenharmony_ci * Copyright 2012 Red Hat Inc.
362306a36Sopenharmony_ci *
462306a36Sopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a
562306a36Sopenharmony_ci * copy of this software and associated documentation files (the "Software"),
662306a36Sopenharmony_ci * to deal in the Software without restriction, including without limitation
762306a36Sopenharmony_ci * the rights to use, copy, modify, merge, publish, distribute, sublicense,
862306a36Sopenharmony_ci * and/or sell copies of the Software, and to permit persons to whom the
962306a36Sopenharmony_ci * Software is furnished to do so, subject to the following conditions:
1062306a36Sopenharmony_ci *
1162306a36Sopenharmony_ci * The above copyright notice and this permission notice shall be included in
1262306a36Sopenharmony_ci * all copies or substantial portions of the Software.
1362306a36Sopenharmony_ci *
1462306a36Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
1562306a36Sopenharmony_ci * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
1662306a36Sopenharmony_ci * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
1762306a36Sopenharmony_ci * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
1862306a36Sopenharmony_ci * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
1962306a36Sopenharmony_ci * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
2062306a36Sopenharmony_ci * OTHER DEALINGS IN THE SOFTWARE.
2162306a36Sopenharmony_ci *
2262306a36Sopenharmony_ci * Authors: Ben Skeggs
2362306a36Sopenharmony_ci */
2462306a36Sopenharmony_ci#include "nouveau_drv.h"
2562306a36Sopenharmony_ci#include "nouveau_dma.h"
2662306a36Sopenharmony_ci#include "nouveau_fence.h"
2762306a36Sopenharmony_ci
2862306a36Sopenharmony_ci#include <nvif/if0004.h>
2962306a36Sopenharmony_ci#include <nvif/push006c.h>
3062306a36Sopenharmony_ci
3162306a36Sopenharmony_cistruct nv04_fence_chan {
3262306a36Sopenharmony_ci	struct nouveau_fence_chan base;
3362306a36Sopenharmony_ci};
3462306a36Sopenharmony_ci
3562306a36Sopenharmony_cistruct nv04_fence_priv {
3662306a36Sopenharmony_ci	struct nouveau_fence_priv base;
3762306a36Sopenharmony_ci};
3862306a36Sopenharmony_ci
3962306a36Sopenharmony_cistatic int
4062306a36Sopenharmony_cinv04_fence_emit(struct nouveau_fence *fence)
4162306a36Sopenharmony_ci{
4262306a36Sopenharmony_ci	struct nvif_push *push = unrcu_pointer(fence->channel)->chan.push;
4362306a36Sopenharmony_ci	int ret = PUSH_WAIT(push, 2);
4462306a36Sopenharmony_ci	if (ret == 0) {
4562306a36Sopenharmony_ci		PUSH_NVSQ(push, NV_SW, 0x0150, fence->base.seqno);
4662306a36Sopenharmony_ci		PUSH_KICK(push);
4762306a36Sopenharmony_ci	}
4862306a36Sopenharmony_ci	return ret;
4962306a36Sopenharmony_ci}
5062306a36Sopenharmony_ci
5162306a36Sopenharmony_cistatic int
5262306a36Sopenharmony_cinv04_fence_sync(struct nouveau_fence *fence,
5362306a36Sopenharmony_ci		struct nouveau_channel *prev, struct nouveau_channel *chan)
5462306a36Sopenharmony_ci{
5562306a36Sopenharmony_ci	return -ENODEV;
5662306a36Sopenharmony_ci}
5762306a36Sopenharmony_ci
5862306a36Sopenharmony_cistatic u32
5962306a36Sopenharmony_cinv04_fence_read(struct nouveau_channel *chan)
6062306a36Sopenharmony_ci{
6162306a36Sopenharmony_ci	struct nv04_nvsw_get_ref_v0 args = {};
6262306a36Sopenharmony_ci	WARN_ON(nvif_object_mthd(&chan->nvsw, NV04_NVSW_GET_REF,
6362306a36Sopenharmony_ci				 &args, sizeof(args)));
6462306a36Sopenharmony_ci	return args.ref;
6562306a36Sopenharmony_ci}
6662306a36Sopenharmony_ci
6762306a36Sopenharmony_cistatic void
6862306a36Sopenharmony_cinv04_fence_context_del(struct nouveau_channel *chan)
6962306a36Sopenharmony_ci{
7062306a36Sopenharmony_ci	struct nv04_fence_chan *fctx = chan->fence;
7162306a36Sopenharmony_ci	nouveau_fence_context_del(&fctx->base);
7262306a36Sopenharmony_ci	chan->fence = NULL;
7362306a36Sopenharmony_ci	nouveau_fence_context_free(&fctx->base);
7462306a36Sopenharmony_ci}
7562306a36Sopenharmony_ci
7662306a36Sopenharmony_cistatic int
7762306a36Sopenharmony_cinv04_fence_context_new(struct nouveau_channel *chan)
7862306a36Sopenharmony_ci{
7962306a36Sopenharmony_ci	struct nv04_fence_chan *fctx = kzalloc(sizeof(*fctx), GFP_KERNEL);
8062306a36Sopenharmony_ci	if (fctx) {
8162306a36Sopenharmony_ci		nouveau_fence_context_new(chan, &fctx->base);
8262306a36Sopenharmony_ci		fctx->base.emit = nv04_fence_emit;
8362306a36Sopenharmony_ci		fctx->base.sync = nv04_fence_sync;
8462306a36Sopenharmony_ci		fctx->base.read = nv04_fence_read;
8562306a36Sopenharmony_ci		chan->fence = fctx;
8662306a36Sopenharmony_ci		return 0;
8762306a36Sopenharmony_ci	}
8862306a36Sopenharmony_ci	return -ENOMEM;
8962306a36Sopenharmony_ci}
9062306a36Sopenharmony_ci
9162306a36Sopenharmony_cistatic void
9262306a36Sopenharmony_cinv04_fence_destroy(struct nouveau_drm *drm)
9362306a36Sopenharmony_ci{
9462306a36Sopenharmony_ci	struct nv04_fence_priv *priv = drm->fence;
9562306a36Sopenharmony_ci	drm->fence = NULL;
9662306a36Sopenharmony_ci	kfree(priv);
9762306a36Sopenharmony_ci}
9862306a36Sopenharmony_ci
9962306a36Sopenharmony_ciint
10062306a36Sopenharmony_cinv04_fence_create(struct nouveau_drm *drm)
10162306a36Sopenharmony_ci{
10262306a36Sopenharmony_ci	struct nv04_fence_priv *priv;
10362306a36Sopenharmony_ci
10462306a36Sopenharmony_ci	priv = drm->fence = kzalloc(sizeof(*priv), GFP_KERNEL);
10562306a36Sopenharmony_ci	if (!priv)
10662306a36Sopenharmony_ci		return -ENOMEM;
10762306a36Sopenharmony_ci
10862306a36Sopenharmony_ci	priv->base.dtor = nv04_fence_destroy;
10962306a36Sopenharmony_ci	priv->base.context_new = nv04_fence_context_new;
11062306a36Sopenharmony_ci	priv->base.context_del = nv04_fence_context_del;
11162306a36Sopenharmony_ci	return 0;
11262306a36Sopenharmony_ci}
113