[go: nahoru, domu]

nouveau_dma.c revision ba59953d281747b1f7518a60f0ba8ff671cd0d65
16ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs/*
26ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs * Copyright (C) 2007 Ben Skeggs.
36ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs * All Rights Reserved.
46ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs *
56ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs * Permission is hereby granted, free of charge, to any person obtaining
66ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs * a copy of this software and associated documentation files (the
76ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs * "Software"), to deal in the Software without restriction, including
86ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs * without limitation the rights to use, copy, modify, merge, publish,
96ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs * distribute, sublicense, and/or sell copies of the Software, and to
106ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs * permit persons to whom the Software is furnished to do so, subject to
116ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs * the following conditions:
126ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs *
136ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs * The above copyright notice and this permission notice (including the
146ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs * next paragraph) shall be included in all copies or substantial
156ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs * portions of the Software.
166ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs *
176ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
186ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
196ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
206ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs * IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS BE
216ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
226ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
236ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
246ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs *
256ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs */
266ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs
276ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs#include "drmP.h"
286ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs#include "drm.h"
296ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs#include "nouveau_drv.h"
306ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs#include "nouveau_dma.h"
316ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs
3275c99da6cdd0ec9d70747f9ced3e85b2dd955cdfBen Skeggsvoid
3375c99da6cdd0ec9d70747f9ced3e85b2dd955cdfBen Skeggsnouveau_dma_pre_init(struct nouveau_channel *chan)
3475c99da6cdd0ec9d70747f9ced3e85b2dd955cdfBen Skeggs{
3575c99da6cdd0ec9d70747f9ced3e85b2dd955cdfBen Skeggs	chan->dma.max  = (chan->pushbuf_bo->bo.mem.size >> 2) - 2;
3675c99da6cdd0ec9d70747f9ced3e85b2dd955cdfBen Skeggs	chan->dma.put  = 0;
3775c99da6cdd0ec9d70747f9ced3e85b2dd955cdfBen Skeggs	chan->dma.cur  = chan->dma.put;
3875c99da6cdd0ec9d70747f9ced3e85b2dd955cdfBen Skeggs	chan->dma.free = chan->dma.max - chan->dma.cur;
3975c99da6cdd0ec9d70747f9ced3e85b2dd955cdfBen Skeggs}
4075c99da6cdd0ec9d70747f9ced3e85b2dd955cdfBen Skeggs
416ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggsint
426ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggsnouveau_dma_init(struct nouveau_channel *chan)
436ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs{
446ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs	struct drm_device *dev = chan->dev;
456ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs	struct drm_nouveau_private *dev_priv = dev->dev_private;
466ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs	struct nouveau_gpuobj *m2mf = NULL;
47f03a314b4671407c4ff69a2d85e72413e8064c48Francisco Jerez	struct nouveau_gpuobj *nvsw = NULL;
486ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs	int ret, i;
496ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs
506ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs	/* Create NV_MEMORY_TO_MEMORY_FORMAT for buffer moves */
516ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs	ret = nouveau_gpuobj_gr_new(chan, dev_priv->card_type < NV_50 ?
526ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs				    0x0039 : 0x5039, &m2mf);
536ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs	if (ret)
546ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs		return ret;
556ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs
566ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs	ret = nouveau_gpuobj_ref_add(dev, chan, NvM2MF, m2mf, NULL);
576ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs	if (ret)
586ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs		return ret;
596ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs
60f03a314b4671407c4ff69a2d85e72413e8064c48Francisco Jerez	/* Create an NV_SW object for various sync purposes */
61f03a314b4671407c4ff69a2d85e72413e8064c48Francisco Jerez	ret = nouveau_gpuobj_sw_new(chan, NV_SW, &nvsw);
62f03a314b4671407c4ff69a2d85e72413e8064c48Francisco Jerez	if (ret)
63f03a314b4671407c4ff69a2d85e72413e8064c48Francisco Jerez		return ret;
64f03a314b4671407c4ff69a2d85e72413e8064c48Francisco Jerez
65f03a314b4671407c4ff69a2d85e72413e8064c48Francisco Jerez	ret = nouveau_gpuobj_ref_add(dev, chan, NvSw, nvsw, NULL);
66f03a314b4671407c4ff69a2d85e72413e8064c48Francisco Jerez	if (ret)
67f03a314b4671407c4ff69a2d85e72413e8064c48Francisco Jerez		return ret;
68f03a314b4671407c4ff69a2d85e72413e8064c48Francisco Jerez
696ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs	/* NV_MEMORY_TO_MEMORY_FORMAT requires a notifier object */
706ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs	ret = nouveau_notifier_alloc(chan, NvNotify0, 32, &chan->m2mf_ntfy);
716ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs	if (ret)
726ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs		return ret;
736ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs
746ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs	/* Map push buffer */
756ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs	ret = nouveau_bo_map(chan->pushbuf_bo);
766ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs	if (ret)
776ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs		return ret;
786ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs
796ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs	/* Map M2MF notifier object - fbcon. */
806ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs	if (drm_core_check_feature(dev, DRIVER_MODESET)) {
816ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs		ret = nouveau_bo_map(chan->notifier_bo);
826ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs		if (ret)
836ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs			return ret;
846ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs	}
856ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs
866ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs	/* Insert NOPS for NOUVEAU_DMA_SKIPS */
876ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs	ret = RING_SPACE(chan, NOUVEAU_DMA_SKIPS);
886ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs	if (ret)
896ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs		return ret;
906ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs
916ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs	for (i = 0; i < NOUVEAU_DMA_SKIPS; i++)
926ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs		OUT_RING(chan, 0);
936ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs
946ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs	/* Initialise NV_MEMORY_TO_MEMORY_FORMAT */
956ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs	ret = RING_SPACE(chan, 4);
966ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs	if (ret)
976ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs		return ret;
986ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs	BEGIN_RING(chan, NvSubM2MF, NV_MEMORY_TO_MEMORY_FORMAT_NAME, 1);
996ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs	OUT_RING(chan, NvM2MF);
1006ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs	BEGIN_RING(chan, NvSubM2MF, NV_MEMORY_TO_MEMORY_FORMAT_DMA_NOTIFY, 1);
1016ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs	OUT_RING(chan, NvNotify0);
1026ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs
103f03a314b4671407c4ff69a2d85e72413e8064c48Francisco Jerez	/* Initialise NV_SW */
104f03a314b4671407c4ff69a2d85e72413e8064c48Francisco Jerez	ret = RING_SPACE(chan, 2);
105f03a314b4671407c4ff69a2d85e72413e8064c48Francisco Jerez	if (ret)
106f03a314b4671407c4ff69a2d85e72413e8064c48Francisco Jerez		return ret;
107f03a314b4671407c4ff69a2d85e72413e8064c48Francisco Jerez	BEGIN_RING(chan, NvSubSw, 0, 1);
108f03a314b4671407c4ff69a2d85e72413e8064c48Francisco Jerez	OUT_RING(chan, NvSw);
109f03a314b4671407c4ff69a2d85e72413e8064c48Francisco Jerez
1106ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs	/* Sit back and pray the channel works.. */
1116ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs	FIRE_RING(chan);
1126ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs
1136ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs	return 0;
1146ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs}
1156ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs
1166ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggsvoid
1176ee738610f41b59733f63718f0bdbcba7d3a3f12Ben SkeggsOUT_RINGp(struct nouveau_channel *chan, const void *data, unsigned nr_dwords)
1186ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs{
1196ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs	bool is_iomem;
1206ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs	u32 *mem = ttm_kmap_obj_virtual(&chan->pushbuf_bo->kmap, &is_iomem);
1216ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs	mem = &mem[chan->dma.cur];
1226ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs	if (is_iomem)
1236ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs		memcpy_toio((void __force __iomem *)mem, data, nr_dwords * 4);
1246ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs	else
1256ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs		memcpy(mem, data, nr_dwords * 4);
1266ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs	chan->dma.cur += nr_dwords;
1276ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs}
1286ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs
129ba59953d281747b1f7518a60f0ba8ff671cd0d65Ben Skeggs/* Fetch and adjust GPU GET pointer
130ba59953d281747b1f7518a60f0ba8ff671cd0d65Ben Skeggs *
131ba59953d281747b1f7518a60f0ba8ff671cd0d65Ben Skeggs * Returns:
132ba59953d281747b1f7518a60f0ba8ff671cd0d65Ben Skeggs *  value >= 0, the adjusted GET pointer
133ba59953d281747b1f7518a60f0ba8ff671cd0d65Ben Skeggs *  -EINVAL if GET pointer currently outside main push buffer
134ba59953d281747b1f7518a60f0ba8ff671cd0d65Ben Skeggs *  -EBUSY if timeout exceeded
135ba59953d281747b1f7518a60f0ba8ff671cd0d65Ben Skeggs */
136ba59953d281747b1f7518a60f0ba8ff671cd0d65Ben Skeggsstatic inline int
137ba59953d281747b1f7518a60f0ba8ff671cd0d65Ben SkeggsREAD_GET(struct nouveau_channel *chan, uint32_t *prev_get, uint32_t *timeout)
1386ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs{
1396ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs	uint32_t val;
1406ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs
1416ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs	val = nvchan_rd32(chan, chan->user_get);
142ba59953d281747b1f7518a60f0ba8ff671cd0d65Ben Skeggs
143ba59953d281747b1f7518a60f0ba8ff671cd0d65Ben Skeggs	/* reset counter as long as GET is still advancing, this is
144ba59953d281747b1f7518a60f0ba8ff671cd0d65Ben Skeggs	 * to avoid misdetecting a GPU lockup if the GPU happens to
145ba59953d281747b1f7518a60f0ba8ff671cd0d65Ben Skeggs	 * just be processing an operation that takes a long time
146ba59953d281747b1f7518a60f0ba8ff671cd0d65Ben Skeggs	 */
147ba59953d281747b1f7518a60f0ba8ff671cd0d65Ben Skeggs	if (val != *prev_get) {
148ba59953d281747b1f7518a60f0ba8ff671cd0d65Ben Skeggs		*prev_get = val;
149ba59953d281747b1f7518a60f0ba8ff671cd0d65Ben Skeggs		*timeout = 0;
150ba59953d281747b1f7518a60f0ba8ff671cd0d65Ben Skeggs	}
151ba59953d281747b1f7518a60f0ba8ff671cd0d65Ben Skeggs
152ba59953d281747b1f7518a60f0ba8ff671cd0d65Ben Skeggs	if ((++*timeout & 0xff) == 0) {
153ba59953d281747b1f7518a60f0ba8ff671cd0d65Ben Skeggs		DRM_UDELAY(1);
154ba59953d281747b1f7518a60f0ba8ff671cd0d65Ben Skeggs		if (*timeout > 100000)
155ba59953d281747b1f7518a60f0ba8ff671cd0d65Ben Skeggs			return -EBUSY;
1566ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs	}
1576ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs
158ba59953d281747b1f7518a60f0ba8ff671cd0d65Ben Skeggs	if (val < chan->pushbuf_base ||
159ba59953d281747b1f7518a60f0ba8ff671cd0d65Ben Skeggs	    val > chan->pushbuf_base + (chan->dma.max << 2))
160ba59953d281747b1f7518a60f0ba8ff671cd0d65Ben Skeggs		return -EINVAL;
161ba59953d281747b1f7518a60f0ba8ff671cd0d65Ben Skeggs
162ba59953d281747b1f7518a60f0ba8ff671cd0d65Ben Skeggs	return (val - chan->pushbuf_base) >> 2;
1636ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs}
1646ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs
1656ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggsint
1666ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggsnouveau_dma_wait(struct nouveau_channel *chan, int size)
1676ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs{
168ba59953d281747b1f7518a60f0ba8ff671cd0d65Ben Skeggs	uint32_t prev_get = 0, cnt = 0;
169ba59953d281747b1f7518a60f0ba8ff671cd0d65Ben Skeggs	int get;
1706ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs
1716ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs	while (chan->dma.free < size) {
172ba59953d281747b1f7518a60f0ba8ff671cd0d65Ben Skeggs		get = READ_GET(chan, &prev_get, &cnt);
173ba59953d281747b1f7518a60f0ba8ff671cd0d65Ben Skeggs		if (unlikely(get == -EBUSY))
174ba59953d281747b1f7518a60f0ba8ff671cd0d65Ben Skeggs			return -EBUSY;
1756ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs
1766ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs		/* loop until we have a usable GET pointer.  the value
1776ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs		 * we read from the GPU may be outside the main ring if
1786ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs		 * PFIFO is processing a buffer called from the main ring,
1796ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs		 * discard these values until something sensible is seen.
1806ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs		 *
1816ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs		 * the other case we discard GET is while the GPU is fetching
1826ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs		 * from the SKIPS area, so the code below doesn't have to deal
1836ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs		 * with some fun corner cases.
1846ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs		 */
185ba59953d281747b1f7518a60f0ba8ff671cd0d65Ben Skeggs		if (unlikely(get == -EINVAL) || get < NOUVEAU_DMA_SKIPS)
1866ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs			continue;
1876ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs
1886ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs		if (get <= chan->dma.cur) {
1896ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs			/* engine is fetching behind us, or is completely
1906ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs			 * idle (GET == PUT) so we have free space up until
1916ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs			 * the end of the push buffer
1926ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs			 *
1936ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs			 * we can only hit that path once per call due to
1946ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs			 * looping back to the beginning of the push buffer,
1956ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs			 * we'll hit the fetching-ahead-of-us path from that
1966ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs			 * point on.
1976ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs			 *
1986ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs			 * the *one* exception to that rule is if we read
1996ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs			 * GET==PUT, in which case the below conditional will
2006ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs			 * always succeed and break us out of the wait loop.
2016ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs			 */
2026ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs			chan->dma.free = chan->dma.max - chan->dma.cur;
2036ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs			if (chan->dma.free >= size)
2046ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs				break;
2056ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs
2066ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs			/* not enough space left at the end of the push buffer,
2076ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs			 * instruct the GPU to jump back to the start right
2086ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs			 * after processing the currently pending commands.
2096ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs			 */
2106ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs			OUT_RING(chan, chan->pushbuf_base | 0x20000000);
211ba59953d281747b1f7518a60f0ba8ff671cd0d65Ben Skeggs
212ba59953d281747b1f7518a60f0ba8ff671cd0d65Ben Skeggs			/* wait for GET to depart from the skips area.
213ba59953d281747b1f7518a60f0ba8ff671cd0d65Ben Skeggs			 * prevents writing GET==PUT and causing a race
214ba59953d281747b1f7518a60f0ba8ff671cd0d65Ben Skeggs			 * condition that causes us to think the GPU is
215ba59953d281747b1f7518a60f0ba8ff671cd0d65Ben Skeggs			 * idle when it's not.
216ba59953d281747b1f7518a60f0ba8ff671cd0d65Ben Skeggs			 */
217ba59953d281747b1f7518a60f0ba8ff671cd0d65Ben Skeggs			do {
218ba59953d281747b1f7518a60f0ba8ff671cd0d65Ben Skeggs				get = READ_GET(chan, &prev_get, &cnt);
219ba59953d281747b1f7518a60f0ba8ff671cd0d65Ben Skeggs				if (unlikely(get == -EBUSY))
220ba59953d281747b1f7518a60f0ba8ff671cd0d65Ben Skeggs					return -EBUSY;
221ba59953d281747b1f7518a60f0ba8ff671cd0d65Ben Skeggs				if (unlikely(get == -EINVAL))
222ba59953d281747b1f7518a60f0ba8ff671cd0d65Ben Skeggs					continue;
223ba59953d281747b1f7518a60f0ba8ff671cd0d65Ben Skeggs			} while (get <= NOUVEAU_DMA_SKIPS);
2246ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs			WRITE_PUT(NOUVEAU_DMA_SKIPS);
2256ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs
2266ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs			/* we're now submitting commands at the start of
2276ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs			 * the push buffer.
2286ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs			 */
2296ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs			chan->dma.cur  =
2306ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs			chan->dma.put  = NOUVEAU_DMA_SKIPS;
2316ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs		}
2326ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs
2336ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs		/* engine fetching ahead of us, we have space up until the
2346ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs		 * current GET pointer.  the "- 1" is to ensure there's
2356ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs		 * space left to emit a jump back to the beginning of the
2366ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs		 * push buffer if we require it.  we can never get GET == PUT
2376ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs		 * here, so this is safe.
2386ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs		 */
2396ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs		chan->dma.free = get - chan->dma.cur - 1;
2406ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs	}
2416ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs
2426ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs	return 0;
2436ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs}
2446ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs
245