195584Sanholt/* r128_cce.c -- ATI Rage 128 driver -*- linux-c -*-
2152909Sanholt * Created: Wed Apr  5 19:24:19 2000 by kevin@precisioninsight.com
3152909Sanholt */
4139749Simp/*-
595584Sanholt * Copyright 2000 Precision Insight, Inc., Cedar Park, Texas.
695584Sanholt * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California.
795584Sanholt * All Rights Reserved.
895584Sanholt *
995584Sanholt * Permission is hereby granted, free of charge, to any person obtaining a
1095584Sanholt * copy of this software and associated documentation files (the "Software"),
1195584Sanholt * to deal in the Software without restriction, including without limitation
1295584Sanholt * the rights to use, copy, modify, merge, publish, distribute, sublicense,
1395584Sanholt * and/or sell copies of the Software, and to permit persons to whom the
1495584Sanholt * Software is furnished to do so, subject to the following conditions:
1595584Sanholt *
1695584Sanholt * The above copyright notice and this permission notice (including the next
1795584Sanholt * paragraph) shall be included in all copies or substantial portions of the
1895584Sanholt * Software.
1995584Sanholt *
2095584Sanholt * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
2195584Sanholt * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
2295584Sanholt * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
2395584Sanholt * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
2495584Sanholt * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
2595584Sanholt * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
2695584Sanholt * DEALINGS IN THE SOFTWARE.
2795584Sanholt *
2895584Sanholt * Authors:
2995584Sanholt *    Gareth Hughes <gareth@valinux.com>
3095584Sanholt */
3195584Sanholt
32152909Sanholt#include <sys/cdefs.h>
33152909Sanholt__FBSDID("$FreeBSD$");
34152909Sanholt
3595584Sanholt#include "dev/drm/drmP.h"
36112015Sanholt#include "dev/drm/drm.h"
3795746Sanholt#include "dev/drm/r128_drm.h"
3895584Sanholt#include "dev/drm/r128_drv.h"
3995584Sanholt
4095584Sanholt#define R128_FIFO_DEBUG		0
4195584Sanholt
4295584Sanholt/* CCE microcode (from ATI) */
4395584Sanholtstatic u32 r128_cce_microcode[] = {
4495584Sanholt	0, 276838400, 0, 268449792, 2, 142, 2, 145, 0, 1076765731, 0,
4595584Sanholt	1617039951, 0, 774592877, 0, 1987540286, 0, 2307490946U, 0,
4695584Sanholt	599558925, 0, 589505315, 0, 596487092, 0, 589505315, 1,
4795584Sanholt	11544576, 1, 206848, 1, 311296, 1, 198656, 2, 912273422, 11,
4895584Sanholt	262144, 0, 0, 1, 33559837, 1, 7438, 1, 14809, 1, 6615, 12, 28,
4995584Sanholt	1, 6614, 12, 28, 2, 23, 11, 18874368, 0, 16790922, 1, 409600, 9,
5095584Sanholt	30, 1, 147854772, 16, 420483072, 3, 8192, 0, 10240, 1, 198656,
5195584Sanholt	1, 15630, 1, 51200, 10, 34858, 9, 42, 1, 33559823, 2, 10276, 1,
5295584Sanholt	15717, 1, 15718, 2, 43, 1, 15936948, 1, 570480831, 1, 14715071,
5395584Sanholt	12, 322123831, 1, 33953125, 12, 55, 1, 33559908, 1, 15718, 2,
5495584Sanholt	46, 4, 2099258, 1, 526336, 1, 442623, 4, 4194365, 1, 509952, 1,
5595584Sanholt	459007, 3, 0, 12, 92, 2, 46, 12, 176, 1, 15734, 1, 206848, 1,
5695584Sanholt	18432, 1, 133120, 1, 100670734, 1, 149504, 1, 165888, 1,
5795584Sanholt	15975928, 1, 1048576, 6, 3145806, 1, 15715, 16, 2150645232U, 2,
5895584Sanholt	268449859, 2, 10307, 12, 176, 1, 15734, 1, 15735, 1, 15630, 1,
5995584Sanholt	15631, 1, 5253120, 6, 3145810, 16, 2150645232U, 1, 15864, 2, 82,
6095584Sanholt	1, 343310, 1, 1064207, 2, 3145813, 1, 15728, 1, 7817, 1, 15729,
6195584Sanholt	3, 15730, 12, 92, 2, 98, 1, 16168, 1, 16167, 1, 16002, 1, 16008,
6295584Sanholt	1, 15974, 1, 15975, 1, 15990, 1, 15976, 1, 15977, 1, 15980, 0,
6395584Sanholt	15981, 1, 10240, 1, 5253120, 1, 15720, 1, 198656, 6, 110, 1,
6495584Sanholt	180224, 1, 103824738, 2, 112, 2, 3145839, 0, 536885440, 1,
6595584Sanholt	114880, 14, 125, 12, 206975, 1, 33559995, 12, 198784, 0,
6695584Sanholt	33570236, 1, 15803, 0, 15804, 3, 294912, 1, 294912, 3, 442370,
6795584Sanholt	1, 11544576, 0, 811612160, 1, 12593152, 1, 11536384, 1,
6895584Sanholt	14024704, 7, 310382726, 0, 10240, 1, 14796, 1, 14797, 1, 14793,
6995584Sanholt	1, 14794, 0, 14795, 1, 268679168, 1, 9437184, 1, 268449792, 1,
7095584Sanholt	198656, 1, 9452827, 1, 1075854602, 1, 1075854603, 1, 557056, 1,
7195584Sanholt	114880, 14, 159, 12, 198784, 1, 1109409213, 12, 198783, 1,
7295584Sanholt	1107312059, 12, 198784, 1, 1109409212, 2, 162, 1, 1075854781, 1,
7395584Sanholt	1073757627, 1, 1075854780, 1, 540672, 1, 10485760, 6, 3145894,
7495584Sanholt	16, 274741248, 9, 168, 3, 4194304, 3, 4209949, 0, 0, 0, 256, 14,
7595584Sanholt	174, 1, 114857, 1, 33560007, 12, 176, 0, 10240, 1, 114858, 1,
7695584Sanholt	33560018, 1, 114857, 3, 33560007, 1, 16008, 1, 114874, 1,
7795584Sanholt	33560360, 1, 114875, 1, 33560154, 0, 15963, 0, 256, 0, 4096, 1,
7895584Sanholt	409611, 9, 188, 0, 10240, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
7995584Sanholt	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
8095584Sanholt	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
8195584Sanholt	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
8295584Sanholt	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
8395584Sanholt	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
8495584Sanholt	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
8595584Sanholt};
8695584Sanholt
87182080Srnolandstatic int R128_READ_PLL(struct drm_device * dev, int addr)
8895584Sanholt{
8995584Sanholt	drm_r128_private_t *dev_priv = dev->dev_private;
9095584Sanholt
9195584Sanholt	R128_WRITE8(R128_CLOCK_CNTL_INDEX, addr & 0x1f);
9295584Sanholt	return R128_READ(R128_CLOCK_CNTL_DATA);
9395584Sanholt}
9495584Sanholt
9595584Sanholt#if R128_FIFO_DEBUG
96145132Sanholtstatic void r128_status(drm_r128_private_t * dev_priv)
9795584Sanholt{
98145132Sanholt	printk("GUI_STAT           = 0x%08x\n",
99145132Sanholt	       (unsigned int)R128_READ(R128_GUI_STAT));
100145132Sanholt	printk("PM4_STAT           = 0x%08x\n",
101145132Sanholt	       (unsigned int)R128_READ(R128_PM4_STAT));
102145132Sanholt	printk("PM4_BUFFER_DL_WPTR = 0x%08x\n",
103145132Sanholt	       (unsigned int)R128_READ(R128_PM4_BUFFER_DL_WPTR));
104145132Sanholt	printk("PM4_BUFFER_DL_RPTR = 0x%08x\n",
105145132Sanholt	       (unsigned int)R128_READ(R128_PM4_BUFFER_DL_RPTR));
106145132Sanholt	printk("PM4_MICRO_CNTL     = 0x%08x\n",
107145132Sanholt	       (unsigned int)R128_READ(R128_PM4_MICRO_CNTL));
108145132Sanholt	printk("PM4_BUFFER_CNTL    = 0x%08x\n",
109145132Sanholt	       (unsigned int)R128_READ(R128_PM4_BUFFER_CNTL));
11095584Sanholt}
11195584Sanholt#endif
11295584Sanholt
11395584Sanholt/* ================================================================
11495584Sanholt * Engine, FIFO control
11595584Sanholt */
11695584Sanholt
117145132Sanholtstatic int r128_do_pixcache_flush(drm_r128_private_t * dev_priv)
11895584Sanholt{
11995584Sanholt	u32 tmp;
12095584Sanholt	int i;
12195584Sanholt
122145132Sanholt	tmp = R128_READ(R128_PC_NGUI_CTLSTAT) | R128_PC_FLUSH_ALL;
123145132Sanholt	R128_WRITE(R128_PC_NGUI_CTLSTAT, tmp);
12495584Sanholt
125145132Sanholt	for (i = 0; i < dev_priv->usec_timeout; i++) {
126145132Sanholt		if (!(R128_READ(R128_PC_NGUI_CTLSTAT) & R128_PC_BUSY)) {
12795584Sanholt			return 0;
12895584Sanholt		}
129145132Sanholt		DRM_UDELAY(1);
13095584Sanholt	}
13195584Sanholt
13295584Sanholt#if R128_FIFO_DEBUG
133145132Sanholt	DRM_ERROR("failed!\n");
13495584Sanholt#endif
135182080Srnoland	return -EBUSY;
13695584Sanholt}
13795584Sanholt
138145132Sanholtstatic int r128_do_wait_for_fifo(drm_r128_private_t * dev_priv, int entries)
13995584Sanholt{
14095584Sanholt	int i;
14195584Sanholt
142145132Sanholt	for (i = 0; i < dev_priv->usec_timeout; i++) {
143145132Sanholt		int slots = R128_READ(R128_GUI_STAT) & R128_GUI_FIFOCNT_MASK;
144145132Sanholt		if (slots >= entries)
145145132Sanholt			return 0;
146145132Sanholt		DRM_UDELAY(1);
14795584Sanholt	}
14895584Sanholt
14995584Sanholt#if R128_FIFO_DEBUG
150145132Sanholt	DRM_ERROR("failed!\n");
15195584Sanholt#endif
152182080Srnoland	return -EBUSY;
15395584Sanholt}
15495584Sanholt
155145132Sanholtstatic int r128_do_wait_for_idle(drm_r128_private_t * dev_priv)
15695584Sanholt{
15795584Sanholt	int i, ret;
15895584Sanholt
159145132Sanholt	ret = r128_do_wait_for_fifo(dev_priv, 64);
160145132Sanholt	if (ret)
161145132Sanholt		return ret;
16295584Sanholt
163145132Sanholt	for (i = 0; i < dev_priv->usec_timeout; i++) {
164145132Sanholt		if (!(R128_READ(R128_GUI_STAT) & R128_GUI_ACTIVE)) {
165145132Sanholt			r128_do_pixcache_flush(dev_priv);
16695584Sanholt			return 0;
16795584Sanholt		}
168145132Sanholt		DRM_UDELAY(1);
16995584Sanholt	}
17095584Sanholt
17195584Sanholt#if R128_FIFO_DEBUG
172145132Sanholt	DRM_ERROR("failed!\n");
17395584Sanholt#endif
174182080Srnoland	return -EBUSY;
17595584Sanholt}
17695584Sanholt
17795584Sanholt/* ================================================================
17895584Sanholt * CCE control, initialization
17995584Sanholt */
18095584Sanholt
18195584Sanholt/* Load the microcode for the CCE */
182145132Sanholtstatic void r128_cce_load_microcode(drm_r128_private_t * dev_priv)
18395584Sanholt{
18495584Sanholt	int i;
18595584Sanholt
186145132Sanholt	DRM_DEBUG("\n");
18795584Sanholt
188145132Sanholt	r128_do_wait_for_idle(dev_priv);
18995584Sanholt
190145132Sanholt	R128_WRITE(R128_PM4_MICROCODE_ADDR, 0);
191145132Sanholt	for (i = 0; i < 256; i++) {
192145132Sanholt		R128_WRITE(R128_PM4_MICROCODE_DATAH, r128_cce_microcode[i * 2]);
193145132Sanholt		R128_WRITE(R128_PM4_MICROCODE_DATAL,
194145132Sanholt			   r128_cce_microcode[i * 2 + 1]);
19595584Sanholt	}
19695584Sanholt}
19795584Sanholt
19895584Sanholt/* Flush any pending commands to the CCE.  This should only be used just
19995584Sanholt * prior to a wait for idle, as it informs the engine that the command
20095584Sanholt * stream is ending.
20195584Sanholt */
202145132Sanholtstatic void r128_do_cce_flush(drm_r128_private_t * dev_priv)
20395584Sanholt{
20495584Sanholt	u32 tmp;
20595584Sanholt
206145132Sanholt	tmp = R128_READ(R128_PM4_BUFFER_DL_WPTR) | R128_PM4_BUFFER_DL_DONE;
207145132Sanholt	R128_WRITE(R128_PM4_BUFFER_DL_WPTR, tmp);
20895584Sanholt}
20995584Sanholt
21095584Sanholt/* Wait for the CCE to go idle.
21195584Sanholt */
212145132Sanholtint r128_do_cce_idle(drm_r128_private_t * dev_priv)
21395584Sanholt{
21495584Sanholt	int i;
21595584Sanholt
216145132Sanholt	for (i = 0; i < dev_priv->usec_timeout; i++) {
217145132Sanholt		if (GET_RING_HEAD(dev_priv) == dev_priv->ring.tail) {
218145132Sanholt			int pm4stat = R128_READ(R128_PM4_STAT);
219145132Sanholt			if (((pm4stat & R128_PM4_FIFOCNT_MASK) >=
220145132Sanholt			     dev_priv->cce_fifo_size) &&
221145132Sanholt			    !(pm4stat & (R128_PM4_BUSY |
222145132Sanholt					 R128_PM4_GUI_ACTIVE))) {
223145132Sanholt				return r128_do_pixcache_flush(dev_priv);
22495584Sanholt			}
22595584Sanholt		}
226145132Sanholt		DRM_UDELAY(1);
22795584Sanholt	}
22895584Sanholt
22995584Sanholt#if R128_FIFO_DEBUG
230145132Sanholt	DRM_ERROR("failed!\n");
231145132Sanholt	r128_status(dev_priv);
23295584Sanholt#endif
233182080Srnoland	return -EBUSY;
23495584Sanholt}
23595584Sanholt
23695584Sanholt/* Start the Concurrent Command Engine.
23795584Sanholt */
238145132Sanholtstatic void r128_do_cce_start(drm_r128_private_t * dev_priv)
23995584Sanholt{
240145132Sanholt	r128_do_wait_for_idle(dev_priv);
24195584Sanholt
242145132Sanholt	R128_WRITE(R128_PM4_BUFFER_CNTL,
243145132Sanholt		   dev_priv->cce_mode | dev_priv->ring.size_l2qw
244145132Sanholt		   | R128_PM4_BUFFER_CNTL_NOUPDATE);
245145132Sanholt	R128_READ(R128_PM4_BUFFER_ADDR);	/* as per the sample code */
246145132Sanholt	R128_WRITE(R128_PM4_MICRO_CNTL, R128_PM4_MICRO_FREERUN);
24795584Sanholt
24895584Sanholt	dev_priv->cce_running = 1;
24995584Sanholt}
25095584Sanholt
25195584Sanholt/* Reset the Concurrent Command Engine.  This will not flush any pending
25295584Sanholt * commands, so you must wait for the CCE command stream to complete
25395584Sanholt * before calling this routine.
25495584Sanholt */
255145132Sanholtstatic void r128_do_cce_reset(drm_r128_private_t * dev_priv)
25695584Sanholt{
257145132Sanholt	R128_WRITE(R128_PM4_BUFFER_DL_WPTR, 0);
258145132Sanholt	R128_WRITE(R128_PM4_BUFFER_DL_RPTR, 0);
25995584Sanholt	dev_priv->ring.tail = 0;
26095584Sanholt}
26195584Sanholt
26295584Sanholt/* Stop the Concurrent Command Engine.  This will not flush any pending
26395584Sanholt * commands, so you must flush the command stream and wait for the CCE
26495584Sanholt * to go idle before calling this routine.
26595584Sanholt */
266145132Sanholtstatic void r128_do_cce_stop(drm_r128_private_t * dev_priv)
26795584Sanholt{
268145132Sanholt	R128_WRITE(R128_PM4_MICRO_CNTL, 0);
269145132Sanholt	R128_WRITE(R128_PM4_BUFFER_CNTL,
270145132Sanholt		   R128_PM4_NONPM4 | R128_PM4_BUFFER_CNTL_NOUPDATE);
27195584Sanholt
27295584Sanholt	dev_priv->cce_running = 0;
27395584Sanholt}
27495584Sanholt
27595584Sanholt/* Reset the engine.  This will stop the CCE if it is running.
27695584Sanholt */
277182080Srnolandstatic int r128_do_engine_reset(struct drm_device * dev)
27895584Sanholt{
27995584Sanholt	drm_r128_private_t *dev_priv = dev->dev_private;
28095584Sanholt	u32 clock_cntl_index, mclk_cntl, gen_reset_cntl;
28195584Sanholt
282145132Sanholt	r128_do_pixcache_flush(dev_priv);
28395584Sanholt
284145132Sanholt	clock_cntl_index = R128_READ(R128_CLOCK_CNTL_INDEX);
285145132Sanholt	mclk_cntl = R128_READ_PLL(dev, R128_MCLK_CNTL);
28695584Sanholt
287145132Sanholt	R128_WRITE_PLL(R128_MCLK_CNTL,
288145132Sanholt		       mclk_cntl | R128_FORCE_GCP | R128_FORCE_PIPE3D_CP);
28995584Sanholt
290145132Sanholt	gen_reset_cntl = R128_READ(R128_GEN_RESET_CNTL);
29195584Sanholt
29295584Sanholt	/* Taken from the sample code - do not change */
293145132Sanholt	R128_WRITE(R128_GEN_RESET_CNTL, gen_reset_cntl | R128_SOFT_RESET_GUI);
294145132Sanholt	R128_READ(R128_GEN_RESET_CNTL);
295145132Sanholt	R128_WRITE(R128_GEN_RESET_CNTL, gen_reset_cntl & ~R128_SOFT_RESET_GUI);
296145132Sanholt	R128_READ(R128_GEN_RESET_CNTL);
29795584Sanholt
298145132Sanholt	R128_WRITE_PLL(R128_MCLK_CNTL, mclk_cntl);
299145132Sanholt	R128_WRITE(R128_CLOCK_CNTL_INDEX, clock_cntl_index);
300145132Sanholt	R128_WRITE(R128_GEN_RESET_CNTL, gen_reset_cntl);
30195584Sanholt
30295584Sanholt	/* Reset the CCE ring */
303145132Sanholt	r128_do_cce_reset(dev_priv);
30495584Sanholt
30595584Sanholt	/* The CCE is no longer running after an engine reset */
30695584Sanholt	dev_priv->cce_running = 0;
30795584Sanholt
30895584Sanholt	/* Reset any pending vertex, indirect buffers */
309145132Sanholt	r128_freelist_reset(dev);
31095584Sanholt
31195584Sanholt	return 0;
31295584Sanholt}
31395584Sanholt
314182080Srnolandstatic void r128_cce_init_ring_buffer(struct drm_device * dev,
315145132Sanholt				      drm_r128_private_t * dev_priv)
31695584Sanholt{
31795584Sanholt	u32 ring_start;
31895584Sanholt	u32 tmp;
31995584Sanholt
320145132Sanholt	DRM_DEBUG("\n");
32195584Sanholt
32295584Sanholt	/* The manual (p. 2) says this address is in "VM space".  This
32395584Sanholt	 * means it's an offset from the start of AGP space.
32495584Sanholt	 */
325145132Sanholt#if __OS_HAS_AGP
326145132Sanholt	if (!dev_priv->is_pci)
32795584Sanholt		ring_start = dev_priv->cce_ring->offset - dev->agp->base;
32895584Sanholt	else
32995584Sanholt#endif
330207067Srnoland		ring_start = dev_priv->cce_ring->offset - dev->sg->vaddr;
33195584Sanholt
332145132Sanholt	R128_WRITE(R128_PM4_BUFFER_OFFSET, ring_start | R128_AGP_OFFSET);
33395584Sanholt
334145132Sanholt	R128_WRITE(R128_PM4_BUFFER_DL_WPTR, 0);
335145132Sanholt	R128_WRITE(R128_PM4_BUFFER_DL_RPTR, 0);
33695584Sanholt
33795584Sanholt	/* Set watermark control */
338145132Sanholt	R128_WRITE(R128_PM4_BUFFER_WM_CNTL,
339145132Sanholt		   ((R128_WATERMARK_L / 4) << R128_WMA_SHIFT)
340145132Sanholt		   | ((R128_WATERMARK_M / 4) << R128_WMB_SHIFT)
341145132Sanholt		   | ((R128_WATERMARK_N / 4) << R128_WMC_SHIFT)
342145132Sanholt		   | ((R128_WATERMARK_K / 64) << R128_WB_WM_SHIFT));
34395584Sanholt
34495584Sanholt	/* Force read.  Why?  Because it's in the examples... */
345145132Sanholt	R128_READ(R128_PM4_BUFFER_ADDR);
34695584Sanholt
34795584Sanholt	/* Turn on bus mastering */
348145132Sanholt	tmp = R128_READ(R128_BUS_CNTL) & ~R128_BUS_MASTER_DIS;
349145132Sanholt	R128_WRITE(R128_BUS_CNTL, tmp);
35095584Sanholt}
35195584Sanholt
352182080Srnolandstatic int r128_do_init_cce(struct drm_device * dev, drm_r128_init_t * init)
35395584Sanholt{
35495584Sanholt	drm_r128_private_t *dev_priv;
35595584Sanholt
356145132Sanholt	DRM_DEBUG("\n");
35795584Sanholt
358145132Sanholt	dev_priv = drm_alloc(sizeof(drm_r128_private_t), DRM_MEM_DRIVER);
359145132Sanholt	if (dev_priv == NULL)
360182080Srnoland		return -ENOMEM;
36195584Sanholt
362145132Sanholt	memset(dev_priv, 0, sizeof(drm_r128_private_t));
36395584Sanholt
36495584Sanholt	dev_priv->is_pci = init->is_pci;
36595584Sanholt
366145132Sanholt	if (dev_priv->is_pci && !dev->sg) {
367145132Sanholt		DRM_ERROR("PCI GART memory not allocated!\n");
36895584Sanholt		dev->dev_private = (void *)dev_priv;
369145132Sanholt		r128_do_cleanup_cce(dev);
370182080Srnoland		return -EINVAL;
37195584Sanholt	}
37295584Sanholt
37395584Sanholt	dev_priv->usec_timeout = init->usec_timeout;
374145132Sanholt	if (dev_priv->usec_timeout < 1 ||
375145132Sanholt	    dev_priv->usec_timeout > R128_MAX_USEC_TIMEOUT) {
376145132Sanholt		DRM_DEBUG("TIMEOUT problem!\n");
37795584Sanholt		dev->dev_private = (void *)dev_priv;
378145132Sanholt		r128_do_cleanup_cce(dev);
379182080Srnoland		return -EINVAL;
38095584Sanholt	}
38195584Sanholt
38295584Sanholt	dev_priv->cce_mode = init->cce_mode;
38395584Sanholt
38495584Sanholt	/* GH: Simple idle check.
38595584Sanholt	 */
386145132Sanholt	atomic_set(&dev_priv->idle_count, 0);
38795584Sanholt
38895584Sanholt	/* We don't support anything other than bus-mastering ring mode,
38995584Sanholt	 * but the ring can be in either AGP or PCI space for the ring
39095584Sanholt	 * read pointer.
39195584Sanholt	 */
392145132Sanholt	if ((init->cce_mode != R128_PM4_192BM) &&
393145132Sanholt	    (init->cce_mode != R128_PM4_128BM_64INDBM) &&
394145132Sanholt	    (init->cce_mode != R128_PM4_64BM_128INDBM) &&
395145132Sanholt	    (init->cce_mode != R128_PM4_64BM_64VCBM_64INDBM)) {
396145132Sanholt		DRM_DEBUG("Bad cce_mode!\n");
39795584Sanholt		dev->dev_private = (void *)dev_priv;
398145132Sanholt		r128_do_cleanup_cce(dev);
399182080Srnoland		return -EINVAL;
40095584Sanholt	}
40195584Sanholt
402145132Sanholt	switch (init->cce_mode) {
40395584Sanholt	case R128_PM4_NONPM4:
40495584Sanholt		dev_priv->cce_fifo_size = 0;
40595584Sanholt		break;
40695584Sanholt	case R128_PM4_192PIO:
40795584Sanholt	case R128_PM4_192BM:
40895584Sanholt		dev_priv->cce_fifo_size = 192;
40995584Sanholt		break;
41095584Sanholt	case R128_PM4_128PIO_64INDBM:
41195584Sanholt	case R128_PM4_128BM_64INDBM:
41295584Sanholt		dev_priv->cce_fifo_size = 128;
41395584Sanholt		break;
41495584Sanholt	case R128_PM4_64PIO_128INDBM:
41595584Sanholt	case R128_PM4_64BM_128INDBM:
41695584Sanholt	case R128_PM4_64PIO_64VCBM_64INDBM:
41795584Sanholt	case R128_PM4_64BM_64VCBM_64INDBM:
41895584Sanholt	case R128_PM4_64PIO_64VCPIO_64INDPIO:
41995584Sanholt		dev_priv->cce_fifo_size = 64;
42095584Sanholt		break;
42195584Sanholt	}
42295584Sanholt
423145132Sanholt	switch (init->fb_bpp) {
42495584Sanholt	case 16:
42595584Sanholt		dev_priv->color_fmt = R128_DATATYPE_RGB565;
42695584Sanholt		break;
42795584Sanholt	case 32:
42895584Sanholt	default:
42995584Sanholt		dev_priv->color_fmt = R128_DATATYPE_ARGB8888;
43095584Sanholt		break;
43195584Sanholt	}
432145132Sanholt	dev_priv->front_offset = init->front_offset;
433145132Sanholt	dev_priv->front_pitch = init->front_pitch;
434145132Sanholt	dev_priv->back_offset = init->back_offset;
435145132Sanholt	dev_priv->back_pitch = init->back_pitch;
43695584Sanholt
437145132Sanholt	switch (init->depth_bpp) {
43895584Sanholt	case 16:
43995584Sanholt		dev_priv->depth_fmt = R128_DATATYPE_RGB565;
44095584Sanholt		break;
44195584Sanholt	case 24:
44295584Sanholt	case 32:
44395584Sanholt	default:
44495584Sanholt		dev_priv->depth_fmt = R128_DATATYPE_ARGB8888;
44595584Sanholt		break;
44695584Sanholt	}
447145132Sanholt	dev_priv->depth_offset = init->depth_offset;
448145132Sanholt	dev_priv->depth_pitch = init->depth_pitch;
449145132Sanholt	dev_priv->span_offset = init->span_offset;
45095584Sanholt
451145132Sanholt	dev_priv->front_pitch_offset_c = (((dev_priv->front_pitch / 8) << 21) |
45295584Sanholt					  (dev_priv->front_offset >> 5));
453145132Sanholt	dev_priv->back_pitch_offset_c = (((dev_priv->back_pitch / 8) << 21) |
45495584Sanholt					 (dev_priv->back_offset >> 5));
455145132Sanholt	dev_priv->depth_pitch_offset_c = (((dev_priv->depth_pitch / 8) << 21) |
45695584Sanholt					  (dev_priv->depth_offset >> 5) |
45795584Sanholt					  R128_DST_TILE);
458145132Sanholt	dev_priv->span_pitch_offset_c = (((dev_priv->depth_pitch / 8) << 21) |
45995584Sanholt					 (dev_priv->span_offset >> 5));
46095584Sanholt
461182080Srnoland	dev_priv->sarea = drm_getsarea(dev);
462145132Sanholt	if (!dev_priv->sarea) {
46395584Sanholt		DRM_ERROR("could not find sarea!\n");
46495584Sanholt		dev->dev_private = (void *)dev_priv;
465145132Sanholt		r128_do_cleanup_cce(dev);
466182080Srnoland		return -EINVAL;
46795584Sanholt	}
46895584Sanholt
469145132Sanholt	dev_priv->mmio = drm_core_findmap(dev, init->mmio_offset);
470145132Sanholt	if (!dev_priv->mmio) {
47195584Sanholt		DRM_ERROR("could not find mmio region!\n");
47295584Sanholt		dev->dev_private = (void *)dev_priv;
473145132Sanholt		r128_do_cleanup_cce(dev);
474182080Srnoland		return -EINVAL;
47595584Sanholt	}
476145132Sanholt	dev_priv->cce_ring = drm_core_findmap(dev, init->ring_offset);
477145132Sanholt	if (!dev_priv->cce_ring) {
47895584Sanholt		DRM_ERROR("could not find cce ring region!\n");
47995584Sanholt		dev->dev_private = (void *)dev_priv;
480145132Sanholt		r128_do_cleanup_cce(dev);
481182080Srnoland		return -EINVAL;
48295584Sanholt	}
483145132Sanholt	dev_priv->ring_rptr = drm_core_findmap(dev, init->ring_rptr_offset);
484145132Sanholt	if (!dev_priv->ring_rptr) {
48595584Sanholt		DRM_ERROR("could not find ring read pointer!\n");
48695584Sanholt		dev->dev_private = (void *)dev_priv;
487145132Sanholt		r128_do_cleanup_cce(dev);
488182080Srnoland		return -EINVAL;
48995584Sanholt	}
490152909Sanholt	dev->agp_buffer_token = init->buffers_offset;
491145132Sanholt	dev->agp_buffer_map = drm_core_findmap(dev, init->buffers_offset);
492145132Sanholt	if (!dev->agp_buffer_map) {
49395584Sanholt		DRM_ERROR("could not find dma buffer region!\n");
49495584Sanholt		dev->dev_private = (void *)dev_priv;
495145132Sanholt		r128_do_cleanup_cce(dev);
496182080Srnoland		return -EINVAL;
49795584Sanholt	}
49895584Sanholt
499145132Sanholt	if (!dev_priv->is_pci) {
500145132Sanholt		dev_priv->agp_textures =
501145132Sanholt		    drm_core_findmap(dev, init->agp_textures_offset);
502145132Sanholt		if (!dev_priv->agp_textures) {
50395584Sanholt			DRM_ERROR("could not find agp texture region!\n");
50495584Sanholt			dev->dev_private = (void *)dev_priv;
505145132Sanholt			r128_do_cleanup_cce(dev);
506182080Srnoland			return -EINVAL;
50795584Sanholt		}
50895584Sanholt	}
50995584Sanholt
51095584Sanholt	dev_priv->sarea_priv =
511207066Srnoland	    (drm_r128_sarea_t *) ((u8 *) dev_priv->sarea->virtual +
512145132Sanholt				  init->sarea_priv_offset);
51395584Sanholt
514145132Sanholt#if __OS_HAS_AGP
515145132Sanholt	if (!dev_priv->is_pci) {
516145132Sanholt		drm_core_ioremap(dev_priv->cce_ring, dev);
517145132Sanholt		drm_core_ioremap(dev_priv->ring_rptr, dev);
518145132Sanholt		drm_core_ioremap(dev->agp_buffer_map, dev);
519207066Srnoland		if (!dev_priv->cce_ring->virtual ||
520207066Srnoland		    !dev_priv->ring_rptr->virtual ||
521207066Srnoland		    !dev->agp_buffer_map->virtual) {
52295584Sanholt			DRM_ERROR("Could not ioremap agp regions!\n");
52395584Sanholt			dev->dev_private = (void *)dev_priv;
524145132Sanholt			r128_do_cleanup_cce(dev);
525182080Srnoland			return -ENOMEM;
52695584Sanholt		}
527119098Sanholt	} else
528119098Sanholt#endif
529119098Sanholt	{
530207066Srnoland		dev_priv->cce_ring->virtual =
531207066Srnoland		    (void *)dev_priv->cce_ring->offset;
532207066Srnoland		dev_priv->ring_rptr->virtual =
533145132Sanholt		    (void *)dev_priv->ring_rptr->offset;
534207066Srnoland		dev->agp_buffer_map->virtual =
535145132Sanholt		    (void *)dev->agp_buffer_map->offset;
53695584Sanholt	}
53795584Sanholt
538145132Sanholt#if __OS_HAS_AGP
539145132Sanholt	if (!dev_priv->is_pci)
54095584Sanholt		dev_priv->cce_buffers_offset = dev->agp->base;
54195584Sanholt	else
54295584Sanholt#endif
543207067Srnoland		dev_priv->cce_buffers_offset = dev->sg->vaddr;
54495584Sanholt
545207066Srnoland	dev_priv->ring.start = (u32 *) dev_priv->cce_ring->virtual;
546207066Srnoland	dev_priv->ring.end = ((u32 *) dev_priv->cce_ring->virtual
54795584Sanholt			      + init->ring_size / sizeof(u32));
54895584Sanholt	dev_priv->ring.size = init->ring_size;
549145132Sanholt	dev_priv->ring.size_l2qw = drm_order(init->ring_size / 8);
55095584Sanholt
551145132Sanholt	dev_priv->ring.tail_mask = (dev_priv->ring.size / sizeof(u32)) - 1;
55295584Sanholt
55395584Sanholt	dev_priv->ring.high_mark = 128;
55495584Sanholt
55595584Sanholt	dev_priv->sarea_priv->last_frame = 0;
556145132Sanholt	R128_WRITE(R128_LAST_FRAME_REG, dev_priv->sarea_priv->last_frame);
55795584Sanholt
55895584Sanholt	dev_priv->sarea_priv->last_dispatch = 0;
559145132Sanholt	R128_WRITE(R128_LAST_DISPATCH_REG, dev_priv->sarea_priv->last_dispatch);
56095584Sanholt
561145132Sanholt#if __OS_HAS_AGP
562145132Sanholt	if (dev_priv->is_pci) {
563121447Sanholt#endif
564182080Srnoland		dev_priv->gart_info.table_mask = DMA_BIT_MASK(32);
565152909Sanholt		dev_priv->gart_info.gart_table_location = DRM_ATI_GART_MAIN;
566182080Srnoland		dev_priv->gart_info.table_size = R128_PCIGART_TABLE_SIZE;
567152909Sanholt		dev_priv->gart_info.addr = NULL;
568152909Sanholt		dev_priv->gart_info.bus_addr = 0;
569182080Srnoland		dev_priv->gart_info.gart_reg_if = DRM_ATI_GART_PCI;
570152909Sanholt		if (!drm_ati_pcigart_init(dev, &dev_priv->gart_info)) {
571145132Sanholt			DRM_ERROR("failed to init PCI GART!\n");
57295584Sanholt			dev->dev_private = (void *)dev_priv;
573145132Sanholt			r128_do_cleanup_cce(dev);
574182080Srnoland			return -ENOMEM;
57595584Sanholt		}
576152909Sanholt		R128_WRITE(R128_PCI_GART_PAGE, dev_priv->gart_info.bus_addr);
577145132Sanholt#if __OS_HAS_AGP
57895584Sanholt	}
57995584Sanholt#endif
58095584Sanholt
581145132Sanholt	r128_cce_init_ring_buffer(dev, dev_priv);
582145132Sanholt	r128_cce_load_microcode(dev_priv);
58395584Sanholt
58495584Sanholt	dev->dev_private = (void *)dev_priv;
58595584Sanholt
586145132Sanholt	r128_do_engine_reset(dev);
58795584Sanholt
58895584Sanholt	return 0;
58995584Sanholt}
59095584Sanholt
591182080Srnolandint r128_do_cleanup_cce(struct drm_device * dev)
59295584Sanholt{
593119098Sanholt
594119098Sanholt	/* Make sure interrupts are disabled here because the uninstall ioctl
595119098Sanholt	 * may not have been called from userspace and after dev_private
596119098Sanholt	 * is freed, it's too late.
597119098Sanholt	 */
598145132Sanholt	if (dev->irq_enabled)
599145132Sanholt		drm_irq_uninstall(dev);
600119098Sanholt
601145132Sanholt	if (dev->dev_private) {
60295584Sanholt		drm_r128_private_t *dev_priv = dev->dev_private;
60395584Sanholt
604145132Sanholt#if __OS_HAS_AGP
605145132Sanholt		if (!dev_priv->is_pci) {
606145132Sanholt			if (dev_priv->cce_ring != NULL)
607145132Sanholt				drm_core_ioremapfree(dev_priv->cce_ring, dev);
608145132Sanholt			if (dev_priv->ring_rptr != NULL)
609145132Sanholt				drm_core_ioremapfree(dev_priv->ring_rptr, dev);
610145132Sanholt			if (dev->agp_buffer_map != NULL) {
611145132Sanholt				drm_core_ioremapfree(dev->agp_buffer_map, dev);
612145132Sanholt				dev->agp_buffer_map = NULL;
613145132Sanholt			}
614119098Sanholt		} else
615119098Sanholt#endif
616119098Sanholt		{
617152909Sanholt			if (dev_priv->gart_info.bus_addr)
618152909Sanholt				if (!drm_ati_pcigart_cleanup(dev, &dev_priv->gart_info))
619152909Sanholt					DRM_ERROR("failed to cleanup PCI GART!\n");
62095584Sanholt		}
62195584Sanholt
622145132Sanholt		drm_free(dev->dev_private, sizeof(drm_r128_private_t),
623145132Sanholt			 DRM_MEM_DRIVER);
62495584Sanholt		dev->dev_private = NULL;
62595584Sanholt	}
62695584Sanholt
62795584Sanholt	return 0;
62895584Sanholt}
62995584Sanholt
630182080Srnolandint r128_cce_init(struct drm_device *dev, void *data, struct drm_file *file_priv)
63195584Sanholt{
632182080Srnoland	drm_r128_init_t *init = data;
63395584Sanholt
634145132Sanholt	DRM_DEBUG("\n");
63595584Sanholt
636182080Srnoland	LOCK_TEST_WITH_RETURN(dev, file_priv);
637119098Sanholt
638182080Srnoland	switch (init->func) {
63995584Sanholt	case R128_INIT_CCE:
640182080Srnoland		return r128_do_init_cce(dev, init);
64195584Sanholt	case R128_CLEANUP_CCE:
642145132Sanholt		return r128_do_cleanup_cce(dev);
64395584Sanholt	}
64495584Sanholt
645182080Srnoland	return -EINVAL;
64695584Sanholt}
64795584Sanholt
648182080Srnolandint r128_cce_start(struct drm_device *dev, void *data, struct drm_file *file_priv)
64995584Sanholt{
65095584Sanholt	drm_r128_private_t *dev_priv = dev->dev_private;
651145132Sanholt	DRM_DEBUG("\n");
65295584Sanholt
653182080Srnoland	LOCK_TEST_WITH_RETURN(dev, file_priv);
65495584Sanholt
655145132Sanholt	if (dev_priv->cce_running || dev_priv->cce_mode == R128_PM4_NONPM4) {
656182080Srnoland		DRM_DEBUG("while CCE running\n");
65795584Sanholt		return 0;
65895584Sanholt	}
65995584Sanholt
660145132Sanholt	r128_do_cce_start(dev_priv);
66195584Sanholt
66295584Sanholt	return 0;
66395584Sanholt}
66495584Sanholt
66595584Sanholt/* Stop the CCE.  The engine must have been idled before calling this
66695584Sanholt * routine.
66795584Sanholt */
668182080Srnolandint r128_cce_stop(struct drm_device *dev, void *data, struct drm_file *file_priv)
66995584Sanholt{
67095584Sanholt	drm_r128_private_t *dev_priv = dev->dev_private;
671182080Srnoland	drm_r128_cce_stop_t *stop = data;
67295584Sanholt	int ret;
673145132Sanholt	DRM_DEBUG("\n");
67495584Sanholt
675182080Srnoland	LOCK_TEST_WITH_RETURN(dev, file_priv);
67695584Sanholt
67795584Sanholt	/* Flush any pending CCE commands.  This ensures any outstanding
67895584Sanholt	 * commands are exectuted by the engine before we turn it off.
67995584Sanholt	 */
680182080Srnoland	if (stop->flush) {
681145132Sanholt		r128_do_cce_flush(dev_priv);
68295584Sanholt	}
68395584Sanholt
68495584Sanholt	/* If we fail to make the engine go idle, we return an error
68595584Sanholt	 * code so that the DRM ioctl wrapper can try again.
68695584Sanholt	 */
687182080Srnoland	if (stop->idle) {
688145132Sanholt		ret = r128_do_cce_idle(dev_priv);
689145132Sanholt		if (ret)
690145132Sanholt			return ret;
69195584Sanholt	}
69295584Sanholt
69395584Sanholt	/* Finally, we can turn off the CCE.  If the engine isn't idle,
69495584Sanholt	 * we will get some dropped triangles as they won't be fully
69595584Sanholt	 * rendered before the CCE is shut down.
69695584Sanholt	 */
697145132Sanholt	r128_do_cce_stop(dev_priv);
69895584Sanholt
69995584Sanholt	/* Reset the engine */
700145132Sanholt	r128_do_engine_reset(dev);
70195584Sanholt
70295584Sanholt	return 0;
70395584Sanholt}
70495584Sanholt
70595584Sanholt/* Just reset the CCE ring.  Called as part of an X Server engine reset.
70695584Sanholt */
707182080Srnolandint r128_cce_reset(struct drm_device *dev, void *data, struct drm_file *file_priv)
70895584Sanholt{
70995584Sanholt	drm_r128_private_t *dev_priv = dev->dev_private;
710145132Sanholt	DRM_DEBUG("\n");
71195584Sanholt
712182080Srnoland	LOCK_TEST_WITH_RETURN(dev, file_priv);
71395584Sanholt
714145132Sanholt	if (!dev_priv) {
715182080Srnoland		DRM_DEBUG("called before init done\n");
716182080Srnoland		return -EINVAL;
71795584Sanholt	}
71895584Sanholt
719145132Sanholt	r128_do_cce_reset(dev_priv);
72095584Sanholt
72195584Sanholt	/* The CCE is no longer running after an engine reset */
72295584Sanholt	dev_priv->cce_running = 0;
72395584Sanholt
72495584Sanholt	return 0;
72595584Sanholt}
72695584Sanholt
727182080Srnolandint r128_cce_idle(struct drm_device *dev, void *data, struct drm_file *file_priv)
72895584Sanholt{
72995584Sanholt	drm_r128_private_t *dev_priv = dev->dev_private;
730145132Sanholt	DRM_DEBUG("\n");
73195584Sanholt
732182080Srnoland	LOCK_TEST_WITH_RETURN(dev, file_priv);
73395584Sanholt
734145132Sanholt	if (dev_priv->cce_running) {
735145132Sanholt		r128_do_cce_flush(dev_priv);
73695584Sanholt	}
73795584Sanholt
738145132Sanholt	return r128_do_cce_idle(dev_priv);
73995584Sanholt}
74095584Sanholt
741182080Srnolandint r128_engine_reset(struct drm_device *dev, void *data, struct drm_file *file_priv)
74295584Sanholt{
743145132Sanholt	DRM_DEBUG("\n");
74495584Sanholt
745182080Srnoland	LOCK_TEST_WITH_RETURN(dev, file_priv);
74695584Sanholt
747145132Sanholt	return r128_do_engine_reset(dev);
74895584Sanholt}
74995584Sanholt
750182080Srnolandint r128_fullscreen(struct drm_device *dev, void *data, struct drm_file *file_priv)
75195584Sanholt{
752182080Srnoland	return -EINVAL;
75395584Sanholt}
75495584Sanholt
75595584Sanholt/* ================================================================
75695584Sanholt * Freelist management
75795584Sanholt */
75895584Sanholt#define R128_BUFFER_USED	0xffffffff
75995584Sanholt#define R128_BUFFER_FREE	0
76095584Sanholt
76195584Sanholt#if 0
762182080Srnolandstatic int r128_freelist_init(struct drm_device * dev)
76395584Sanholt{
764182080Srnoland	struct drm_device_dma *dma = dev->dma;
76595584Sanholt	drm_r128_private_t *dev_priv = dev->dev_private;
766182080Srnoland	struct drm_buf *buf;
76795584Sanholt	drm_r128_buf_priv_t *buf_priv;
76895584Sanholt	drm_r128_freelist_t *entry;
76995584Sanholt	int i;
77095584Sanholt
771145132Sanholt	dev_priv->head = drm_alloc(sizeof(drm_r128_freelist_t), DRM_MEM_DRIVER);
772145132Sanholt	if (dev_priv->head == NULL)
773182080Srnoland		return -ENOMEM;
77495584Sanholt
775145132Sanholt	memset(dev_priv->head, 0, sizeof(drm_r128_freelist_t));
77695584Sanholt	dev_priv->head->age = R128_BUFFER_USED;
77795584Sanholt
778145132Sanholt	for (i = 0; i < dma->buf_count; i++) {
77995584Sanholt		buf = dma->buflist[i];
78095584Sanholt		buf_priv = buf->dev_private;
78195584Sanholt
782145132Sanholt		entry = drm_alloc(sizeof(drm_r128_freelist_t), DRM_MEM_DRIVER);
783145132Sanholt		if (!entry)
784182080Srnoland			return -ENOMEM;
78595584Sanholt
78695584Sanholt		entry->age = R128_BUFFER_FREE;
78795584Sanholt		entry->buf = buf;
78895584Sanholt		entry->prev = dev_priv->head;
78995584Sanholt		entry->next = dev_priv->head->next;
790145132Sanholt		if (!entry->next)
79195584Sanholt			dev_priv->tail = entry;
79295584Sanholt
79395584Sanholt		buf_priv->discard = 0;
79495584Sanholt		buf_priv->dispatched = 0;
79595584Sanholt		buf_priv->list_entry = entry;
79695584Sanholt
79795584Sanholt		dev_priv->head->next = entry;
79895584Sanholt
799145132Sanholt		if (dev_priv->head->next)
80095584Sanholt			dev_priv->head->next->prev = entry;
80195584Sanholt	}
80295584Sanholt
80395584Sanholt	return 0;
80495584Sanholt
80595584Sanholt}
80695584Sanholt#endif
80795584Sanholt
808182080Srnolandstatic struct drm_buf *r128_freelist_get(struct drm_device * dev)
80995584Sanholt{
810182080Srnoland	struct drm_device_dma *dma = dev->dma;
81195584Sanholt	drm_r128_private_t *dev_priv = dev->dev_private;
81295584Sanholt	drm_r128_buf_priv_t *buf_priv;
813182080Srnoland	struct drm_buf *buf;
81495584Sanholt	int i, t;
81595584Sanholt
81695584Sanholt	/* FIXME: Optimize -- use freelist code */
81795584Sanholt
818145132Sanholt	for (i = 0; i < dma->buf_count; i++) {
81995584Sanholt		buf = dma->buflist[i];
82095584Sanholt		buf_priv = buf->dev_private;
821182080Srnoland		if (buf->file_priv == 0)
82295584Sanholt			return buf;
82395584Sanholt	}
82495584Sanholt
825145132Sanholt	for (t = 0; t < dev_priv->usec_timeout; t++) {
826145132Sanholt		u32 done_age = R128_READ(R128_LAST_DISPATCH_REG);
82795584Sanholt
828145132Sanholt		for (i = 0; i < dma->buf_count; i++) {
82995584Sanholt			buf = dma->buflist[i];
83095584Sanholt			buf_priv = buf->dev_private;
831145132Sanholt			if (buf->pending && buf_priv->age <= done_age) {
83295584Sanholt				/* The buffer has been processed, so it
83395584Sanholt				 * can now be used.
83495584Sanholt				 */
83595584Sanholt				buf->pending = 0;
83695584Sanholt				return buf;
83795584Sanholt			}
83895584Sanholt		}
839145132Sanholt		DRM_UDELAY(1);
84095584Sanholt	}
84195584Sanholt
842145132Sanholt	DRM_DEBUG("returning NULL!\n");
84395584Sanholt	return NULL;
84495584Sanholt}
84595584Sanholt
846182080Srnolandvoid r128_freelist_reset(struct drm_device * dev)
84795584Sanholt{
848182080Srnoland	struct drm_device_dma *dma = dev->dma;
84995584Sanholt	int i;
85095584Sanholt
851145132Sanholt	for (i = 0; i < dma->buf_count; i++) {
852182080Srnoland		struct drm_buf *buf = dma->buflist[i];
85395584Sanholt		drm_r128_buf_priv_t *buf_priv = buf->dev_private;
85495584Sanholt		buf_priv->age = 0;
85595584Sanholt	}
85695584Sanholt}
85795584Sanholt
85895584Sanholt/* ================================================================
85995584Sanholt * CCE command submission
86095584Sanholt */
86195584Sanholt
862145132Sanholtint r128_wait_ring(drm_r128_private_t * dev_priv, int n)
86395584Sanholt{
86495584Sanholt	drm_r128_ring_buffer_t *ring = &dev_priv->ring;
86595584Sanholt	int i;
86695584Sanholt
867145132Sanholt	for (i = 0; i < dev_priv->usec_timeout; i++) {
868145132Sanholt		r128_update_ring_snapshot(dev_priv);
869145132Sanholt		if (ring->space >= n)
87095584Sanholt			return 0;
871145132Sanholt		DRM_UDELAY(1);
87295584Sanholt	}
87395584Sanholt
87495584Sanholt	/* FIXME: This is being ignored... */
875145132Sanholt	DRM_ERROR("failed!\n");
876182080Srnoland	return -EBUSY;
87795584Sanholt}
87895584Sanholt
879182080Srnolandstatic int r128_cce_get_buffers(struct drm_device * dev,
880182080Srnoland				struct drm_file *file_priv,
881182080Srnoland				struct drm_dma * d)
88295584Sanholt{
88395584Sanholt	int i;
884182080Srnoland	struct drm_buf *buf;
88595584Sanholt
886145132Sanholt	for (i = d->granted_count; i < d->request_count; i++) {
887145132Sanholt		buf = r128_freelist_get(dev);
888145132Sanholt		if (!buf)
889182080Srnoland			return -EAGAIN;
89095584Sanholt
891182080Srnoland		buf->file_priv = file_priv;
89295584Sanholt
893145132Sanholt		if (DRM_COPY_TO_USER(&d->request_indices[i], &buf->idx,
894145132Sanholt				     sizeof(buf->idx)))
895182080Srnoland			return -EFAULT;
896145132Sanholt		if (DRM_COPY_TO_USER(&d->request_sizes[i], &buf->total,
897145132Sanholt				     sizeof(buf->total)))
898182080Srnoland			return -EFAULT;
899112015Sanholt
90095584Sanholt		d->granted_count++;
90195584Sanholt	}
90295584Sanholt	return 0;
90395584Sanholt}
90495584Sanholt
905182080Srnolandint r128_cce_buffers(struct drm_device *dev, void *data, struct drm_file *file_priv)
90695584Sanholt{
907182080Srnoland	struct drm_device_dma *dma = dev->dma;
90895584Sanholt	int ret = 0;
909182080Srnoland	struct drm_dma *d = data;
91095584Sanholt
911182080Srnoland	LOCK_TEST_WITH_RETURN(dev, file_priv);
91295584Sanholt
91395584Sanholt	/* Please don't send us buffers.
91495584Sanholt	 */
915182080Srnoland	if (d->send_count != 0) {
916145132Sanholt		DRM_ERROR("Process %d trying to send %d buffers via drmDMA\n",
917182080Srnoland			  DRM_CURRENTPID, d->send_count);
918182080Srnoland		return -EINVAL;
91995584Sanholt	}
92095584Sanholt
92195584Sanholt	/* We'll send you buffers.
92295584Sanholt	 */
923182080Srnoland	if (d->request_count < 0 || d->request_count > dma->buf_count) {
924145132Sanholt		DRM_ERROR("Process %d trying to get %d buffers (of %d max)\n",
925182080Srnoland			  DRM_CURRENTPID, d->request_count, dma->buf_count);
926182080Srnoland		return -EINVAL;
92795584Sanholt	}
92895584Sanholt
929182080Srnoland	d->granted_count = 0;
93095584Sanholt
931182080Srnoland	if (d->request_count) {
932182080Srnoland		ret = r128_cce_get_buffers(dev, file_priv, d);
93395584Sanholt	}
93495584Sanholt
93595584Sanholt	return ret;
93695584Sanholt}
937