radeon_cp.c revision 95746
195584Sanholt/* radeon_cp.c -- CP support for Radeon -*- linux-c -*-
295584Sanholt *
395584Sanholt * Copyright 2000 Precision Insight, Inc., Cedar Park, Texas.
495584Sanholt * Copyright 2000 VA Linux Systems, Inc., Fremont, California.
595584Sanholt * All Rights Reserved.
695584Sanholt *
795584Sanholt * Permission is hereby granted, free of charge, to any person obtaining a
895584Sanholt * copy of this software and associated documentation files (the "Software"),
995584Sanholt * to deal in the Software without restriction, including without limitation
1095584Sanholt * the rights to use, copy, modify, merge, publish, distribute, sublicense,
1195584Sanholt * and/or sell copies of the Software, and to permit persons to whom the
1295584Sanholt * Software is furnished to do so, subject to the following conditions:
1395584Sanholt *
1495584Sanholt * The above copyright notice and this permission notice (including the next
1595584Sanholt * paragraph) shall be included in all copies or substantial portions of the
1695584Sanholt * Software.
1795584Sanholt *
1895584Sanholt * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
1995584Sanholt * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
2095584Sanholt * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
2195584Sanholt * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
2295584Sanholt * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
2395584Sanholt * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
2495584Sanholt * DEALINGS IN THE SOFTWARE.
2595584Sanholt *
2695584Sanholt * Authors:
2795584Sanholt *    Kevin E. Martin <martin@valinux.com>
2895584Sanholt *    Gareth Hughes <gareth@valinux.com>
2995584Sanholt *
3095584Sanholt * $FreeBSD: head/sys/dev/drm/radeon_cp.c 95746 2002-04-29 18:18:42Z anholt $
3195584Sanholt */
3295584Sanholt
3395584Sanholt#include "dev/drm/radeon.h"
3495584Sanholt#include "dev/drm/drmP.h"
3595746Sanholt#include "dev/drm/radeon_drm.h"
3695584Sanholt#include "dev/drm/radeon_drv.h"
3795584Sanholt
3895584Sanholt#ifdef __linux__
3995584Sanholt#define __NO_VERSION__
4095584Sanholt#include <linux/interrupt.h>	/* For task queue support */
4195584Sanholt#include <linux/delay.h>
4295584Sanholt#endif /* __linux__ */
4395584Sanholt#ifdef __FreeBSD__
4495584Sanholt#include <vm/vm.h>
4595584Sanholt#include <vm/pmap.h>
4695584Sanholt#endif /* __FreeBSD__ */
4795584Sanholt
4895584Sanholt#define RADEON_FIFO_DEBUG	0
4995584Sanholt
5095584Sanholt#if defined(__alpha__)
5195584Sanholt# define PCIGART_ENABLED
5295584Sanholt#else
5395584Sanholt# undef PCIGART_ENABLED
5495584Sanholt#endif
5595584Sanholt
5695584Sanholt
5795584Sanholt/* CP microcode (from ATI) */
5895584Sanholtstatic u32 radeon_cp_microcode[][2] = {
5995584Sanholt	{ 0x21007000, 0000000000 },
6095584Sanholt	{ 0x20007000, 0000000000 },
6195584Sanholt	{ 0x000000b4, 0x00000004 },
6295584Sanholt	{ 0x000000b8, 0x00000004 },
6395584Sanholt	{ 0x6f5b4d4c, 0000000000 },
6495584Sanholt	{ 0x4c4c427f, 0000000000 },
6595584Sanholt	{ 0x5b568a92, 0000000000 },
6695584Sanholt	{ 0x4ca09c6d, 0000000000 },
6795584Sanholt	{ 0xad4c4c4c, 0000000000 },
6895584Sanholt	{ 0x4ce1af3d, 0000000000 },
6995584Sanholt	{ 0xd8afafaf, 0000000000 },
7095584Sanholt	{ 0xd64c4cdc, 0000000000 },
7195584Sanholt	{ 0x4cd10d10, 0000000000 },
7295584Sanholt	{ 0x000f0000, 0x00000016 },
7395584Sanholt	{ 0x362f242d, 0000000000 },
7495584Sanholt	{ 0x00000012, 0x00000004 },
7595584Sanholt	{ 0x000f0000, 0x00000016 },
7695584Sanholt	{ 0x362f282d, 0000000000 },
7795584Sanholt	{ 0x000380e7, 0x00000002 },
7895584Sanholt	{ 0x04002c97, 0x00000002 },
7995584Sanholt	{ 0x000f0001, 0x00000016 },
8095584Sanholt	{ 0x333a3730, 0000000000 },
8195584Sanholt	{ 0x000077ef, 0x00000002 },
8295584Sanholt	{ 0x00061000, 0x00000002 },
8395584Sanholt	{ 0x00000021, 0x0000001a },
8495584Sanholt	{ 0x00004000, 0x0000001e },
8595584Sanholt	{ 0x00061000, 0x00000002 },
8695584Sanholt	{ 0x00000021, 0x0000001a },
8795584Sanholt	{ 0x00004000, 0x0000001e },
8895584Sanholt	{ 0x00061000, 0x00000002 },
8995584Sanholt	{ 0x00000021, 0x0000001a },
9095584Sanholt	{ 0x00004000, 0x0000001e },
9195584Sanholt	{ 0x00000017, 0x00000004 },
9295584Sanholt	{ 0x0003802b, 0x00000002 },
9395584Sanholt	{ 0x040067e0, 0x00000002 },
9495584Sanholt	{ 0x00000017, 0x00000004 },
9595584Sanholt	{ 0x000077e0, 0x00000002 },
9695584Sanholt	{ 0x00065000, 0x00000002 },
9795584Sanholt	{ 0x000037e1, 0x00000002 },
9895584Sanholt	{ 0x040067e1, 0x00000006 },
9995584Sanholt	{ 0x000077e0, 0x00000002 },
10095584Sanholt	{ 0x000077e1, 0x00000002 },
10195584Sanholt	{ 0x000077e1, 0x00000006 },
10295584Sanholt	{ 0xffffffff, 0000000000 },
10395584Sanholt	{ 0x10000000, 0000000000 },
10495584Sanholt	{ 0x0003802b, 0x00000002 },
10595584Sanholt	{ 0x040067e0, 0x00000006 },
10695584Sanholt	{ 0x00007675, 0x00000002 },
10795584Sanholt	{ 0x00007676, 0x00000002 },
10895584Sanholt	{ 0x00007677, 0x00000002 },
10995584Sanholt	{ 0x00007678, 0x00000006 },
11095584Sanholt	{ 0x0003802c, 0x00000002 },
11195584Sanholt	{ 0x04002676, 0x00000002 },
11295584Sanholt	{ 0x00007677, 0x00000002 },
11395584Sanholt	{ 0x00007678, 0x00000006 },
11495584Sanholt	{ 0x0000002f, 0x00000018 },
11595584Sanholt	{ 0x0000002f, 0x00000018 },
11695584Sanholt	{ 0000000000, 0x00000006 },
11795584Sanholt	{ 0x00000030, 0x00000018 },
11895584Sanholt	{ 0x00000030, 0x00000018 },
11995584Sanholt	{ 0000000000, 0x00000006 },
12095584Sanholt	{ 0x01605000, 0x00000002 },
12195584Sanholt	{ 0x00065000, 0x00000002 },
12295584Sanholt	{ 0x00098000, 0x00000002 },
12395584Sanholt	{ 0x00061000, 0x00000002 },
12495584Sanholt	{ 0x64c0603e, 0x00000004 },
12595584Sanholt	{ 0x000380e6, 0x00000002 },
12695584Sanholt	{ 0x040025c5, 0x00000002 },
12795584Sanholt	{ 0x00080000, 0x00000016 },
12895584Sanholt	{ 0000000000, 0000000000 },
12995584Sanholt	{ 0x0400251d, 0x00000002 },
13095584Sanholt	{ 0x00007580, 0x00000002 },
13195584Sanholt	{ 0x00067581, 0x00000002 },
13295584Sanholt	{ 0x04002580, 0x00000002 },
13395584Sanholt	{ 0x00067581, 0x00000002 },
13495584Sanholt	{ 0x00000049, 0x00000004 },
13595584Sanholt	{ 0x00005000, 0000000000 },
13695584Sanholt	{ 0x000380e6, 0x00000002 },
13795584Sanholt	{ 0x040025c5, 0x00000002 },
13895584Sanholt	{ 0x00061000, 0x00000002 },
13995584Sanholt	{ 0x0000750e, 0x00000002 },
14095584Sanholt	{ 0x00019000, 0x00000002 },
14195584Sanholt	{ 0x00011055, 0x00000014 },
14295584Sanholt	{ 0x00000055, 0x00000012 },
14395584Sanholt	{ 0x0400250f, 0x00000002 },
14495584Sanholt	{ 0x0000504f, 0x00000004 },
14595584Sanholt	{ 0x000380e6, 0x00000002 },
14695584Sanholt	{ 0x040025c5, 0x00000002 },
14795584Sanholt	{ 0x00007565, 0x00000002 },
14895584Sanholt	{ 0x00007566, 0x00000002 },
14995584Sanholt	{ 0x00000058, 0x00000004 },
15095584Sanholt	{ 0x000380e6, 0x00000002 },
15195584Sanholt	{ 0x040025c5, 0x00000002 },
15295584Sanholt	{ 0x01e655b4, 0x00000002 },
15395584Sanholt	{ 0x4401b0e4, 0x00000002 },
15495584Sanholt	{ 0x01c110e4, 0x00000002 },
15595584Sanholt	{ 0x26667066, 0x00000018 },
15695584Sanholt	{ 0x040c2565, 0x00000002 },
15795584Sanholt	{ 0x00000066, 0x00000018 },
15895584Sanholt	{ 0x04002564, 0x00000002 },
15995584Sanholt	{ 0x00007566, 0x00000002 },
16095584Sanholt	{ 0x0000005d, 0x00000004 },
16195584Sanholt	{ 0x00401069, 0x00000008 },
16295584Sanholt	{ 0x00101000, 0x00000002 },
16395584Sanholt	{ 0x000d80ff, 0x00000002 },
16495584Sanholt	{ 0x0080006c, 0x00000008 },
16595584Sanholt	{ 0x000f9000, 0x00000002 },
16695584Sanholt	{ 0x000e00ff, 0x00000002 },
16795584Sanholt	{ 0000000000, 0x00000006 },
16895584Sanholt	{ 0x0000008f, 0x00000018 },
16995584Sanholt	{ 0x0000005b, 0x00000004 },
17095584Sanholt	{ 0x000380e6, 0x00000002 },
17195584Sanholt	{ 0x040025c5, 0x00000002 },
17295584Sanholt	{ 0x00007576, 0x00000002 },
17395584Sanholt	{ 0x00065000, 0x00000002 },
17495584Sanholt	{ 0x00009000, 0x00000002 },
17595584Sanholt	{ 0x00041000, 0x00000002 },
17695584Sanholt	{ 0x0c00350e, 0x00000002 },
17795584Sanholt	{ 0x00049000, 0x00000002 },
17895584Sanholt	{ 0x00051000, 0x00000002 },
17995584Sanholt	{ 0x01e785f8, 0x00000002 },
18095584Sanholt	{ 0x00200000, 0x00000002 },
18195584Sanholt	{ 0x0060007e, 0x0000000c },
18295584Sanholt	{ 0x00007563, 0x00000002 },
18395584Sanholt	{ 0x006075f0, 0x00000021 },
18495584Sanholt	{ 0x20007073, 0x00000004 },
18595584Sanholt	{ 0x00005073, 0x00000004 },
18695584Sanholt	{ 0x000380e6, 0x00000002 },
18795584Sanholt	{ 0x040025c5, 0x00000002 },
18895584Sanholt	{ 0x00007576, 0x00000002 },
18995584Sanholt	{ 0x00007577, 0x00000002 },
19095584Sanholt	{ 0x0000750e, 0x00000002 },
19195584Sanholt	{ 0x0000750f, 0x00000002 },
19295584Sanholt	{ 0x00a05000, 0x00000002 },
19395584Sanholt	{ 0x00600083, 0x0000000c },
19495584Sanholt	{ 0x006075f0, 0x00000021 },
19595584Sanholt	{ 0x000075f8, 0x00000002 },
19695584Sanholt	{ 0x00000083, 0x00000004 },
19795584Sanholt	{ 0x000a750e, 0x00000002 },
19895584Sanholt	{ 0x000380e6, 0x00000002 },
19995584Sanholt	{ 0x040025c5, 0x00000002 },
20095584Sanholt	{ 0x0020750f, 0x00000002 },
20195584Sanholt	{ 0x00600086, 0x00000004 },
20295584Sanholt	{ 0x00007570, 0x00000002 },
20395584Sanholt	{ 0x00007571, 0x00000002 },
20495584Sanholt	{ 0x00007572, 0x00000006 },
20595584Sanholt	{ 0x000380e6, 0x00000002 },
20695584Sanholt	{ 0x040025c5, 0x00000002 },
20795584Sanholt	{ 0x00005000, 0x00000002 },
20895584Sanholt	{ 0x00a05000, 0x00000002 },
20995584Sanholt	{ 0x00007568, 0x00000002 },
21095584Sanholt	{ 0x00061000, 0x00000002 },
21195584Sanholt	{ 0x00000095, 0x0000000c },
21295584Sanholt	{ 0x00058000, 0x00000002 },
21395584Sanholt	{ 0x0c607562, 0x00000002 },
21495584Sanholt	{ 0x00000097, 0x00000004 },
21595584Sanholt	{ 0x000380e6, 0x00000002 },
21695584Sanholt	{ 0x040025c5, 0x00000002 },
21795584Sanholt	{ 0x00600096, 0x00000004 },
21895584Sanholt	{ 0x400070e5, 0000000000 },
21995584Sanholt	{ 0x000380e6, 0x00000002 },
22095584Sanholt	{ 0x040025c5, 0x00000002 },
22195584Sanholt	{ 0x000380e5, 0x00000002 },
22295584Sanholt	{ 0x000000a8, 0x0000001c },
22395584Sanholt	{ 0x000650aa, 0x00000018 },
22495584Sanholt	{ 0x040025bb, 0x00000002 },
22595584Sanholt	{ 0x000610ab, 0x00000018 },
22695584Sanholt	{ 0x040075bc, 0000000000 },
22795584Sanholt	{ 0x000075bb, 0x00000002 },
22895584Sanholt	{ 0x000075bc, 0000000000 },
22995584Sanholt	{ 0x00090000, 0x00000006 },
23095584Sanholt	{ 0x00090000, 0x00000002 },
23195584Sanholt	{ 0x000d8002, 0x00000006 },
23295584Sanholt	{ 0x00007832, 0x00000002 },
23395584Sanholt	{ 0x00005000, 0x00000002 },
23495584Sanholt	{ 0x000380e7, 0x00000002 },
23595584Sanholt	{ 0x04002c97, 0x00000002 },
23695584Sanholt	{ 0x00007820, 0x00000002 },
23795584Sanholt	{ 0x00007821, 0x00000002 },
23895584Sanholt	{ 0x00007800, 0000000000 },
23995584Sanholt	{ 0x01200000, 0x00000002 },
24095584Sanholt	{ 0x20077000, 0x00000002 },
24195584Sanholt	{ 0x01200000, 0x00000002 },
24295584Sanholt	{ 0x20007000, 0x00000002 },
24395584Sanholt	{ 0x00061000, 0x00000002 },
24495584Sanholt	{ 0x0120751b, 0x00000002 },
24595584Sanholt	{ 0x8040750a, 0x00000002 },
24695584Sanholt	{ 0x8040750b, 0x00000002 },
24795584Sanholt	{ 0x00110000, 0x00000002 },
24895584Sanholt	{ 0x000380e5, 0x00000002 },
24995584Sanholt	{ 0x000000c6, 0x0000001c },
25095584Sanholt	{ 0x000610ab, 0x00000018 },
25195584Sanholt	{ 0x844075bd, 0x00000002 },
25295584Sanholt	{ 0x000610aa, 0x00000018 },
25395584Sanholt	{ 0x840075bb, 0x00000002 },
25495584Sanholt	{ 0x000610ab, 0x00000018 },
25595584Sanholt	{ 0x844075bc, 0x00000002 },
25695584Sanholt	{ 0x000000c9, 0x00000004 },
25795584Sanholt	{ 0x804075bd, 0x00000002 },
25895584Sanholt	{ 0x800075bb, 0x00000002 },
25995584Sanholt	{ 0x804075bc, 0x00000002 },
26095584Sanholt	{ 0x00108000, 0x00000002 },
26195584Sanholt	{ 0x01400000, 0x00000002 },
26295584Sanholt	{ 0x006000cd, 0x0000000c },
26395584Sanholt	{ 0x20c07000, 0x00000020 },
26495584Sanholt	{ 0x000000cf, 0x00000012 },
26595584Sanholt	{ 0x00800000, 0x00000006 },
26695584Sanholt	{ 0x0080751d, 0x00000006 },
26795584Sanholt	{ 0000000000, 0000000000 },
26895584Sanholt	{ 0x0000775c, 0x00000002 },
26995584Sanholt	{ 0x00a05000, 0x00000002 },
27095584Sanholt	{ 0x00661000, 0x00000002 },
27195584Sanholt	{ 0x0460275d, 0x00000020 },
27295584Sanholt	{ 0x00004000, 0000000000 },
27395584Sanholt	{ 0x01e00830, 0x00000002 },
27495584Sanholt	{ 0x21007000, 0000000000 },
27595584Sanholt	{ 0x6464614d, 0000000000 },
27695584Sanholt	{ 0x69687420, 0000000000 },
27795584Sanholt	{ 0x00000073, 0000000000 },
27895584Sanholt	{ 0000000000, 0000000000 },
27995584Sanholt	{ 0x00005000, 0x00000002 },
28095584Sanholt	{ 0x000380d0, 0x00000002 },
28195584Sanholt	{ 0x040025e0, 0x00000002 },
28295584Sanholt	{ 0x000075e1, 0000000000 },
28395584Sanholt	{ 0x00000001, 0000000000 },
28495584Sanholt	{ 0x000380e0, 0x00000002 },
28595584Sanholt	{ 0x04002394, 0x00000002 },
28695584Sanholt	{ 0x00005000, 0000000000 },
28795584Sanholt	{ 0000000000, 0000000000 },
28895584Sanholt	{ 0000000000, 0000000000 },
28995584Sanholt	{ 0x00000008, 0000000000 },
29095584Sanholt	{ 0x00000004, 0000000000 },
29195584Sanholt	{ 0000000000, 0000000000 },
29295584Sanholt	{ 0000000000, 0000000000 },
29395584Sanholt	{ 0000000000, 0000000000 },
29495584Sanholt	{ 0000000000, 0000000000 },
29595584Sanholt	{ 0000000000, 0000000000 },
29695584Sanholt	{ 0000000000, 0000000000 },
29795584Sanholt	{ 0000000000, 0000000000 },
29895584Sanholt	{ 0000000000, 0000000000 },
29995584Sanholt	{ 0000000000, 0000000000 },
30095584Sanholt	{ 0000000000, 0000000000 },
30195584Sanholt	{ 0000000000, 0000000000 },
30295584Sanholt	{ 0000000000, 0000000000 },
30395584Sanholt	{ 0000000000, 0000000000 },
30495584Sanholt	{ 0000000000, 0000000000 },
30595584Sanholt	{ 0000000000, 0000000000 },
30695584Sanholt	{ 0000000000, 0000000000 },
30795584Sanholt	{ 0000000000, 0000000000 },
30895584Sanholt	{ 0000000000, 0000000000 },
30995584Sanholt	{ 0000000000, 0000000000 },
31095584Sanholt	{ 0000000000, 0000000000 },
31195584Sanholt	{ 0000000000, 0000000000 },
31295584Sanholt	{ 0000000000, 0000000000 },
31395584Sanholt	{ 0000000000, 0000000000 },
31495584Sanholt	{ 0000000000, 0000000000 },
31595584Sanholt};
31695584Sanholt
31795584Sanholt
31895584Sanholtint RADEON_READ_PLL(drm_device_t *dev, int addr)
31995584Sanholt{
32095584Sanholt	drm_radeon_private_t *dev_priv = dev->dev_private;
32195584Sanholt
32295584Sanholt	RADEON_WRITE8(RADEON_CLOCK_CNTL_INDEX, addr & 0x1f);
32395584Sanholt	return RADEON_READ(RADEON_CLOCK_CNTL_DATA);
32495584Sanholt}
32595584Sanholt
32695584Sanholt#if RADEON_FIFO_DEBUG
32795584Sanholtstatic void radeon_status( drm_radeon_private_t *dev_priv )
32895584Sanholt{
32995584Sanholt	printk( "%s:\n", __FUNCTION__ );
33095584Sanholt	printk( "RBBM_STATUS = 0x%08x\n",
33195584Sanholt		(unsigned int)RADEON_READ( RADEON_RBBM_STATUS ) );
33295584Sanholt	printk( "CP_RB_RTPR = 0x%08x\n",
33395584Sanholt		(unsigned int)RADEON_READ( RADEON_CP_RB_RPTR ) );
33495584Sanholt	printk( "CP_RB_WTPR = 0x%08x\n",
33595584Sanholt		(unsigned int)RADEON_READ( RADEON_CP_RB_WPTR ) );
33695584Sanholt	printk( "AIC_CNTL = 0x%08x\n",
33795584Sanholt		(unsigned int)RADEON_READ( RADEON_AIC_CNTL ) );
33895584Sanholt	printk( "AIC_STAT = 0x%08x\n",
33995584Sanholt		(unsigned int)RADEON_READ( RADEON_AIC_STAT ) );
34095584Sanholt	printk( "AIC_PT_BASE = 0x%08x\n",
34195584Sanholt		(unsigned int)RADEON_READ( RADEON_AIC_PT_BASE ) );
34295584Sanholt	printk( "TLB_ADDR = 0x%08x\n",
34395584Sanholt		(unsigned int)RADEON_READ( RADEON_AIC_TLB_ADDR ) );
34495584Sanholt	printk( "TLB_DATA = 0x%08x\n",
34595584Sanholt		(unsigned int)RADEON_READ( RADEON_AIC_TLB_DATA ) );
34695584Sanholt}
34795584Sanholt#endif
34895584Sanholt
34995584Sanholt
35095584Sanholt/* ================================================================
35195584Sanholt * Engine, FIFO control
35295584Sanholt */
35395584Sanholt
35495584Sanholtstatic int radeon_do_pixcache_flush( drm_radeon_private_t *dev_priv )
35595584Sanholt{
35695584Sanholt	u32 tmp;
35795584Sanholt	int i;
35895584Sanholt
35995584Sanholt	tmp  = RADEON_READ( RADEON_RB2D_DSTCACHE_CTLSTAT );
36095584Sanholt	tmp |= RADEON_RB2D_DC_FLUSH_ALL;
36195584Sanholt	RADEON_WRITE( RADEON_RB2D_DSTCACHE_CTLSTAT, tmp );
36295584Sanholt
36395584Sanholt	for ( i = 0 ; i < dev_priv->usec_timeout ; i++ ) {
36495584Sanholt		if ( !(RADEON_READ( RADEON_RB2D_DSTCACHE_CTLSTAT )
36595584Sanholt		       & RADEON_RB2D_DC_BUSY) ) {
36695584Sanholt			return 0;
36795584Sanholt		}
36895584Sanholt		DRM_OS_DELAY( 1 );
36995584Sanholt	}
37095584Sanholt
37195584Sanholt#if RADEON_FIFO_DEBUG
37295584Sanholt	DRM_ERROR( "failed!\n" );
37395584Sanholt	radeon_status( dev_priv );
37495584Sanholt#endif
37595693Sanholt	return DRM_OS_ERR(EBUSY);
37695584Sanholt}
37795584Sanholt
37895584Sanholtstatic int radeon_do_wait_for_fifo( drm_radeon_private_t *dev_priv,
37995584Sanholt				    int entries )
38095584Sanholt{
38195584Sanholt	int i;
38295584Sanholt
38395584Sanholt	for ( i = 0 ; i < dev_priv->usec_timeout ; i++ ) {
38495584Sanholt		int slots = ( RADEON_READ( RADEON_RBBM_STATUS )
38595584Sanholt			      & RADEON_RBBM_FIFOCNT_MASK );
38695584Sanholt		if ( slots >= entries ) return 0;
38795584Sanholt		DRM_OS_DELAY( 1 );
38895584Sanholt	}
38995584Sanholt
39095584Sanholt#if RADEON_FIFO_DEBUG
39195584Sanholt	DRM_ERROR( "failed!\n" );
39295584Sanholt	radeon_status( dev_priv );
39395584Sanholt#endif
39495693Sanholt	return DRM_OS_ERR(EBUSY);
39595584Sanholt}
39695584Sanholt
39795584Sanholtstatic int radeon_do_wait_for_idle( drm_radeon_private_t *dev_priv )
39895584Sanholt{
39995584Sanholt	int i, ret;
40095584Sanholt
40195584Sanholt	ret = radeon_do_wait_for_fifo( dev_priv, 64 );
40295584Sanholt	if ( ret ) return ret;
40395584Sanholt	for ( i = 0 ; i < dev_priv->usec_timeout ; i++ ) {
40495584Sanholt		if ( !(RADEON_READ( RADEON_RBBM_STATUS )
40595584Sanholt		       & RADEON_RBBM_ACTIVE) ) {
40695584Sanholt			radeon_do_pixcache_flush( dev_priv );
40795584Sanholt			return 0;
40895584Sanholt		}
40995584Sanholt		DRM_OS_DELAY( 1 );
41095584Sanholt	}
41195584Sanholt
41295584Sanholt#if RADEON_FIFO_DEBUG
41395584Sanholt	DRM_ERROR( "failed!\n" );
41495584Sanholt	radeon_status( dev_priv );
41595584Sanholt#endif
41695693Sanholt	return DRM_OS_ERR(EBUSY);
41795584Sanholt}
41895584Sanholt
41995584Sanholt
42095584Sanholt/* ================================================================
42195584Sanholt * CP control, initialization
42295584Sanholt */
42395584Sanholt
42495584Sanholt/* Load the microcode for the CP */
42595584Sanholtstatic void radeon_cp_load_microcode( drm_radeon_private_t *dev_priv )
42695584Sanholt{
42795584Sanholt	int i;
42895584Sanholt	DRM_DEBUG( "%s\n", __FUNCTION__ );
42995584Sanholt
43095584Sanholt	radeon_do_wait_for_idle( dev_priv );
43195584Sanholt
43295584Sanholt	RADEON_WRITE( RADEON_CP_ME_RAM_ADDR, 0 );
43395584Sanholt	for ( i = 0 ; i < 256 ; i++ ) {
43495584Sanholt		RADEON_WRITE( RADEON_CP_ME_RAM_DATAH,
43595584Sanholt			      radeon_cp_microcode[i][1] );
43695584Sanholt		RADEON_WRITE( RADEON_CP_ME_RAM_DATAL,
43795584Sanholt			      radeon_cp_microcode[i][0] );
43895584Sanholt	}
43995584Sanholt}
44095584Sanholt
44195584Sanholt/* Flush any pending commands to the CP.  This should only be used just
44295584Sanholt * prior to a wait for idle, as it informs the engine that the command
44395584Sanholt * stream is ending.
44495584Sanholt */
44595584Sanholtstatic void radeon_do_cp_flush( drm_radeon_private_t *dev_priv )
44695584Sanholt{
44795584Sanholt	DRM_DEBUG( "%s\n", __FUNCTION__ );
44895584Sanholt#if 0
44995584Sanholt	u32 tmp;
45095584Sanholt
45195584Sanholt	tmp = RADEON_READ( RADEON_CP_RB_WPTR ) | (1 << 31);
45295584Sanholt	RADEON_WRITE( RADEON_CP_RB_WPTR, tmp );
45395584Sanholt#endif
45495584Sanholt}
45595584Sanholt
45695584Sanholt/* Wait for the CP to go idle.
45795584Sanholt */
45895584Sanholtint radeon_do_cp_idle( drm_radeon_private_t *dev_priv )
45995584Sanholt{
46095584Sanholt	RING_LOCALS;
46195584Sanholt	DRM_DEBUG( "%s\n", __FUNCTION__ );
46295584Sanholt
46395584Sanholt	BEGIN_RING( 6 );
46495584Sanholt
46595584Sanholt	RADEON_PURGE_CACHE();
46695584Sanholt	RADEON_PURGE_ZCACHE();
46795584Sanholt	RADEON_WAIT_UNTIL_IDLE();
46895584Sanholt
46995584Sanholt	ADVANCE_RING();
47095584Sanholt
47195584Sanholt	return radeon_do_wait_for_idle( dev_priv );
47295584Sanholt}
47395584Sanholt
47495584Sanholt/* Start the Command Processor.
47595584Sanholt */
47695584Sanholtstatic void radeon_do_cp_start( drm_radeon_private_t *dev_priv )
47795584Sanholt{
47895584Sanholt	RING_LOCALS;
47995584Sanholt	DRM_DEBUG( "%s\n", __FUNCTION__ );
48095584Sanholt
48195584Sanholt	radeon_do_wait_for_idle( dev_priv );
48295584Sanholt
48395584Sanholt	RADEON_WRITE( RADEON_CP_CSQ_CNTL, dev_priv->cp_mode );
48495584Sanholt
48595584Sanholt	dev_priv->cp_running = 1;
48695584Sanholt
48795584Sanholt	BEGIN_RING( 6 );
48895584Sanholt
48995584Sanholt	RADEON_PURGE_CACHE();
49095584Sanholt	RADEON_PURGE_ZCACHE();
49195584Sanholt	RADEON_WAIT_UNTIL_IDLE();
49295584Sanholt
49395584Sanholt	ADVANCE_RING();
49495584Sanholt}
49595584Sanholt
49695584Sanholt/* Reset the Command Processor.  This will not flush any pending
49795584Sanholt * commands, so you must wait for the CP command stream to complete
49895584Sanholt * before calling this routine.
49995584Sanholt */
50095584Sanholtstatic void radeon_do_cp_reset( drm_radeon_private_t *dev_priv )
50195584Sanholt{
50295584Sanholt	u32 cur_read_ptr;
50395584Sanholt	DRM_DEBUG( "%s\n", __FUNCTION__ );
50495584Sanholt
50595584Sanholt	cur_read_ptr = RADEON_READ( RADEON_CP_RB_RPTR );
50695584Sanholt	RADEON_WRITE( RADEON_CP_RB_WPTR, cur_read_ptr );
50795584Sanholt	*dev_priv->ring.head = cur_read_ptr;
50895584Sanholt	dev_priv->ring.tail = cur_read_ptr;
50995584Sanholt}
51095584Sanholt
51195584Sanholt/* Stop the Command Processor.  This will not flush any pending
51295584Sanholt * commands, so you must flush the command stream and wait for the CP
51395584Sanholt * to go idle before calling this routine.
51495584Sanholt */
51595584Sanholtstatic void radeon_do_cp_stop( drm_radeon_private_t *dev_priv )
51695584Sanholt{
51795584Sanholt	DRM_DEBUG( "%s\n", __FUNCTION__ );
51895584Sanholt
51995584Sanholt	RADEON_WRITE( RADEON_CP_CSQ_CNTL, RADEON_CSQ_PRIDIS_INDDIS );
52095584Sanholt
52195584Sanholt	dev_priv->cp_running = 0;
52295584Sanholt}
52395584Sanholt
52495584Sanholt/* Reset the engine.  This will stop the CP if it is running.
52595584Sanholt */
52695584Sanholtstatic int radeon_do_engine_reset( drm_device_t *dev )
52795584Sanholt{
52895584Sanholt	drm_radeon_private_t *dev_priv = dev->dev_private;
52995584Sanholt	u32 clock_cntl_index, mclk_cntl, rbbm_soft_reset;
53095584Sanholt	DRM_DEBUG( "%s\n", __FUNCTION__ );
53195584Sanholt
53295584Sanholt	radeon_do_pixcache_flush( dev_priv );
53395584Sanholt
53495584Sanholt	clock_cntl_index = RADEON_READ( RADEON_CLOCK_CNTL_INDEX );
53595584Sanholt	mclk_cntl = RADEON_READ_PLL( dev, RADEON_MCLK_CNTL );
53695584Sanholt
53795584Sanholt	RADEON_WRITE_PLL( RADEON_MCLK_CNTL, ( mclk_cntl |
53895584Sanholt					      RADEON_FORCEON_MCLKA |
53995584Sanholt					      RADEON_FORCEON_MCLKB |
54095584Sanholt 					      RADEON_FORCEON_YCLKA |
54195584Sanholt					      RADEON_FORCEON_YCLKB |
54295584Sanholt					      RADEON_FORCEON_MC |
54395584Sanholt					      RADEON_FORCEON_AIC ) );
54495584Sanholt
54595584Sanholt	rbbm_soft_reset = RADEON_READ( RADEON_RBBM_SOFT_RESET );
54695584Sanholt
54795584Sanholt	RADEON_WRITE( RADEON_RBBM_SOFT_RESET, ( rbbm_soft_reset |
54895584Sanholt						RADEON_SOFT_RESET_CP |
54995584Sanholt						RADEON_SOFT_RESET_HI |
55095584Sanholt						RADEON_SOFT_RESET_SE |
55195584Sanholt						RADEON_SOFT_RESET_RE |
55295584Sanholt						RADEON_SOFT_RESET_PP |
55395584Sanholt						RADEON_SOFT_RESET_E2 |
55495584Sanholt						RADEON_SOFT_RESET_RB ) );
55595584Sanholt	RADEON_READ( RADEON_RBBM_SOFT_RESET );
55695584Sanholt	RADEON_WRITE( RADEON_RBBM_SOFT_RESET, ( rbbm_soft_reset &
55795584Sanholt						~( RADEON_SOFT_RESET_CP |
55895584Sanholt						   RADEON_SOFT_RESET_HI |
55995584Sanholt						   RADEON_SOFT_RESET_SE |
56095584Sanholt						   RADEON_SOFT_RESET_RE |
56195584Sanholt						   RADEON_SOFT_RESET_PP |
56295584Sanholt						   RADEON_SOFT_RESET_E2 |
56395584Sanholt						   RADEON_SOFT_RESET_RB ) ) );
56495584Sanholt	RADEON_READ( RADEON_RBBM_SOFT_RESET );
56595584Sanholt
56695584Sanholt
56795584Sanholt	RADEON_WRITE_PLL( RADEON_MCLK_CNTL, mclk_cntl );
56895584Sanholt	RADEON_WRITE( RADEON_CLOCK_CNTL_INDEX, clock_cntl_index );
56995584Sanholt	RADEON_WRITE( RADEON_RBBM_SOFT_RESET,  rbbm_soft_reset );
57095584Sanholt
57195584Sanholt	/* Reset the CP ring */
57295584Sanholt	radeon_do_cp_reset( dev_priv );
57395584Sanholt
57495584Sanholt	/* The CP is no longer running after an engine reset */
57595584Sanholt	dev_priv->cp_running = 0;
57695584Sanholt
57795584Sanholt	/* Reset any pending vertex, indirect buffers */
57895584Sanholt	radeon_freelist_reset( dev );
57995584Sanholt
58095584Sanholt	return 0;
58195584Sanholt}
58295584Sanholt
58395584Sanholtstatic void radeon_cp_init_ring_buffer( drm_device_t *dev,
58495584Sanholt				        drm_radeon_private_t *dev_priv )
58595584Sanholt{
58695584Sanholt	u32 ring_start, cur_read_ptr;
58795584Sanholt	u32 tmp;
58895584Sanholt
58995584Sanholt	/* Initialize the memory controller */
59095584Sanholt	RADEON_WRITE( RADEON_MC_FB_LOCATION,
59195584Sanholt		      (dev_priv->agp_vm_start - 1) & 0xffff0000 );
59295584Sanholt
59395584Sanholt	if ( !dev_priv->is_pci ) {
59495584Sanholt		RADEON_WRITE( RADEON_MC_AGP_LOCATION,
59595584Sanholt			      (((dev_priv->agp_vm_start - 1 +
59695584Sanholt				 dev_priv->agp_size) & 0xffff0000) |
59795584Sanholt			       (dev_priv->agp_vm_start >> 16)) );
59895584Sanholt	}
59995584Sanholt
60095584Sanholt#if __REALLY_HAVE_AGP
60195584Sanholt	if ( !dev_priv->is_pci )
60295584Sanholt		ring_start = (dev_priv->cp_ring->offset
60395584Sanholt			      - dev->agp->base
60495584Sanholt			      + dev_priv->agp_vm_start);
60595584Sanholt       else
60695584Sanholt#endif
60795584Sanholt		ring_start = (dev_priv->cp_ring->offset
60895584Sanholt			      - dev->sg->handle
60995584Sanholt			      + dev_priv->agp_vm_start);
61095584Sanholt
61195584Sanholt	RADEON_WRITE( RADEON_CP_RB_BASE, ring_start );
61295584Sanholt
61395584Sanholt	/* Set the write pointer delay */
61495584Sanholt	RADEON_WRITE( RADEON_CP_RB_WPTR_DELAY, 0 );
61595584Sanholt
61695584Sanholt	/* Initialize the ring buffer's read and write pointers */
61795584Sanholt	cur_read_ptr = RADEON_READ( RADEON_CP_RB_RPTR );
61895584Sanholt	RADEON_WRITE( RADEON_CP_RB_WPTR, cur_read_ptr );
61995584Sanholt	*dev_priv->ring.head = cur_read_ptr;
62095584Sanholt	dev_priv->ring.tail = cur_read_ptr;
62195584Sanholt
62295584Sanholt#if __REALLY_HAVE_SG
62395584Sanholt	if ( !dev_priv->is_pci ) {
62495584Sanholt#endif
62595584Sanholt		RADEON_WRITE( RADEON_CP_RB_RPTR_ADDR,
62695584Sanholt			      dev_priv->ring_rptr->offset );
62795584Sanholt#if __REALLY_HAVE_SG
62895584Sanholt	} else {
62995584Sanholt		drm_sg_mem_t *entry = dev->sg;
63095584Sanholt		unsigned long tmp_ofs, page_ofs;
63195584Sanholt
63295584Sanholt		tmp_ofs = dev_priv->ring_rptr->offset - dev->sg->handle;
63395584Sanholt		page_ofs = tmp_ofs >> PAGE_SHIFT;
63495584Sanholt
63595584Sanholt		RADEON_WRITE( RADEON_CP_RB_RPTR_ADDR,
63695584Sanholt			     entry->busaddr[page_ofs]);
63795584Sanholt		DRM_DEBUG( "ring rptr: offset=0x%08x handle=0x%08lx\n",
63895584Sanholt			   entry->busaddr[page_ofs],
63995584Sanholt			   entry->handle + tmp_ofs );
64095584Sanholt	}
64195584Sanholt#endif
64295584Sanholt
64395584Sanholt	/* Set ring buffer size */
64495584Sanholt	RADEON_WRITE( RADEON_CP_RB_CNTL, dev_priv->ring.size_l2qw );
64595584Sanholt
64695584Sanholt	radeon_do_wait_for_idle( dev_priv );
64795584Sanholt
64895584Sanholt	/* Turn on bus mastering */
64995584Sanholt	tmp = RADEON_READ( RADEON_BUS_CNTL ) & ~RADEON_BUS_MASTER_DIS;
65095584Sanholt	RADEON_WRITE( RADEON_BUS_CNTL, tmp );
65195584Sanholt
65295584Sanholt	/* Sync everything up */
65395584Sanholt	RADEON_WRITE( RADEON_ISYNC_CNTL,
65495584Sanholt		      (RADEON_ISYNC_ANY2D_IDLE3D |
65595584Sanholt		       RADEON_ISYNC_ANY3D_IDLE2D |
65695584Sanholt		       RADEON_ISYNC_WAIT_IDLEGUI |
65795584Sanholt		       RADEON_ISYNC_CPSCRATCH_IDLEGUI) );
65895584Sanholt}
65995584Sanholt
66095584Sanholtstatic int radeon_do_init_cp( drm_device_t *dev, drm_radeon_init_t *init )
66195584Sanholt{
66295584Sanholt	drm_radeon_private_t *dev_priv;
66395584Sanholt#ifdef __linux__
66495584Sanholt	struct list_head *list;
66595584Sanholt#endif /* __linux__ */
66695584Sanholt#ifdef __FreeBSD__
66795584Sanholt	drm_map_list_entry_t *listentry;
66895584Sanholt#endif /* __FreeBSD__ */
66995584Sanholt	u32 tmp;
67095584Sanholt	DRM_DEBUG( "%s\n", __FUNCTION__ );
67195584Sanholt
67295584Sanholt	dev_priv = DRM(alloc)( sizeof(drm_radeon_private_t), DRM_MEM_DRIVER );
67395584Sanholt	if ( dev_priv == NULL )
67495693Sanholt		return DRM_OS_ERR(ENOMEM);
67595584Sanholt
67695584Sanholt	memset( dev_priv, 0, sizeof(drm_radeon_private_t) );
67795584Sanholt
67895584Sanholt	dev_priv->is_pci = init->is_pci;
67995584Sanholt
68095584Sanholt#if !defined(PCIGART_ENABLED)
68195584Sanholt	/* PCI support is not 100% working, so we disable it here.
68295584Sanholt	 */
68395584Sanholt	if ( dev_priv->is_pci ) {
68495584Sanholt		DRM_ERROR( "PCI GART not yet supported for Radeon!\n" );
68595584Sanholt		dev->dev_private = (void *)dev_priv;
68695584Sanholt		radeon_do_cleanup_cp(dev);
68795693Sanholt		return DRM_OS_ERR(EINVAL);
68895584Sanholt	}
68995584Sanholt#endif
69095584Sanholt
69195584Sanholt	if ( dev_priv->is_pci && !dev->sg ) {
69295584Sanholt		DRM_ERROR( "PCI GART memory not allocated!\n" );
69395584Sanholt		dev->dev_private = (void *)dev_priv;
69495584Sanholt		radeon_do_cleanup_cp(dev);
69595693Sanholt		return DRM_OS_ERR(EINVAL);
69695584Sanholt	}
69795584Sanholt
69895584Sanholt	dev_priv->usec_timeout = init->usec_timeout;
69995584Sanholt	if ( dev_priv->usec_timeout < 1 ||
70095584Sanholt	     dev_priv->usec_timeout > RADEON_MAX_USEC_TIMEOUT ) {
70195584Sanholt		DRM_DEBUG( "TIMEOUT problem!\n" );
70295584Sanholt		dev->dev_private = (void *)dev_priv;
70395584Sanholt		radeon_do_cleanup_cp(dev);
70495693Sanholt		return DRM_OS_ERR(EINVAL);
70595584Sanholt	}
70695584Sanholt
70795584Sanholt	dev_priv->cp_mode = init->cp_mode;
70895584Sanholt
70995584Sanholt	/* Simple idle check.
71095584Sanholt	 */
71195584Sanholt	atomic_set( &dev_priv->idle_count, 0 );
71295584Sanholt
71395584Sanholt	/* We don't support anything other than bus-mastering ring mode,
71495584Sanholt	 * but the ring can be in either AGP or PCI space for the ring
71595584Sanholt	 * read pointer.
71695584Sanholt	 */
71795584Sanholt	if ( ( init->cp_mode != RADEON_CSQ_PRIBM_INDDIS ) &&
71895584Sanholt	     ( init->cp_mode != RADEON_CSQ_PRIBM_INDBM ) ) {
71995584Sanholt		DRM_DEBUG( "BAD cp_mode (%x)!\n", init->cp_mode );
72095584Sanholt		dev->dev_private = (void *)dev_priv;
72195584Sanholt		radeon_do_cleanup_cp(dev);
72295693Sanholt		return DRM_OS_ERR(EINVAL);
72395584Sanholt	}
72495584Sanholt
72595584Sanholt	switch ( init->fb_bpp ) {
72695584Sanholt	case 16:
72795584Sanholt		dev_priv->color_fmt = RADEON_COLOR_FORMAT_RGB565;
72895584Sanholt		break;
72995584Sanholt	case 32:
73095584Sanholt	default:
73195584Sanholt		dev_priv->color_fmt = RADEON_COLOR_FORMAT_ARGB8888;
73295584Sanholt		break;
73395584Sanholt	}
73495584Sanholt	dev_priv->front_offset	= init->front_offset;
73595584Sanholt	dev_priv->front_pitch	= init->front_pitch;
73695584Sanholt	dev_priv->back_offset	= init->back_offset;
73795584Sanholt	dev_priv->back_pitch	= init->back_pitch;
73895584Sanholt
73995584Sanholt	switch ( init->depth_bpp ) {
74095584Sanholt	case 16:
74195584Sanholt		dev_priv->depth_fmt = RADEON_DEPTH_FORMAT_16BIT_INT_Z;
74295584Sanholt		break;
74395584Sanholt	case 32:
74495584Sanholt	default:
74595584Sanholt		dev_priv->depth_fmt = RADEON_DEPTH_FORMAT_24BIT_INT_Z;
74695584Sanholt		break;
74795584Sanholt	}
74895584Sanholt	dev_priv->depth_offset	= init->depth_offset;
74995584Sanholt	dev_priv->depth_pitch	= init->depth_pitch;
75095584Sanholt
75195584Sanholt	dev_priv->front_pitch_offset = (((dev_priv->front_pitch/64) << 22) |
75295584Sanholt					(dev_priv->front_offset >> 10));
75395584Sanholt	dev_priv->back_pitch_offset = (((dev_priv->back_pitch/64) << 22) |
75495584Sanholt				       (dev_priv->back_offset >> 10));
75595584Sanholt	dev_priv->depth_pitch_offset = (((dev_priv->depth_pitch/64) << 22) |
75695584Sanholt					(dev_priv->depth_offset >> 10));
75795584Sanholt
75895584Sanholt	/* Hardware state for depth clears.  Remove this if/when we no
75995584Sanholt	 * longer clear the depth buffer with a 3D rectangle.  Hard-code
76095584Sanholt	 * all values to prevent unwanted 3D state from slipping through
76195584Sanholt	 * and screwing with the clear operation.
76295584Sanholt	 */
76395584Sanholt	dev_priv->depth_clear.rb3d_cntl = (RADEON_PLANE_MASK_ENABLE |
76495584Sanholt					   RADEON_Z_ENABLE |
76595584Sanholt					   (dev_priv->color_fmt << 10) |
76695584Sanholt					   RADEON_ZBLOCK16);
76795584Sanholt
76895584Sanholt	dev_priv->depth_clear.rb3d_zstencilcntl = (dev_priv->depth_fmt |
76995584Sanholt						   RADEON_Z_TEST_ALWAYS |
77095584Sanholt						   RADEON_STENCIL_TEST_ALWAYS |
77195584Sanholt						   RADEON_STENCIL_S_FAIL_KEEP |
77295584Sanholt						   RADEON_STENCIL_ZPASS_KEEP |
77395584Sanholt						   RADEON_STENCIL_ZFAIL_KEEP |
77495584Sanholt						   RADEON_Z_WRITE_ENABLE);
77595584Sanholt
77695584Sanholt	dev_priv->depth_clear.se_cntl = (RADEON_FFACE_CULL_CW |
77795584Sanholt					 RADEON_BFACE_SOLID |
77895584Sanholt					 RADEON_FFACE_SOLID |
77995584Sanholt					 RADEON_FLAT_SHADE_VTX_LAST |
78095584Sanholt					 RADEON_DIFFUSE_SHADE_FLAT |
78195584Sanholt					 RADEON_ALPHA_SHADE_FLAT |
78295584Sanholt					 RADEON_SPECULAR_SHADE_FLAT |
78395584Sanholt					 RADEON_FOG_SHADE_FLAT |
78495584Sanholt					 RADEON_VTX_PIX_CENTER_OGL |
78595584Sanholt					 RADEON_ROUND_MODE_TRUNC |
78695584Sanholt					 RADEON_ROUND_PREC_8TH_PIX);
78795584Sanholt
78895584Sanholt#ifdef __linux__
78995584Sanholt	list_for_each(list, &dev->maplist->head) {
79095584Sanholt		drm_map_list_t *r_list = (drm_map_list_t *)list;
79195584Sanholt		if( r_list->map &&
79295584Sanholt		    r_list->map->type == _DRM_SHM &&
79395584Sanholt		    r_list->map->flags & _DRM_CONTAINS_LOCK ) {
79495584Sanholt			dev_priv->sarea = r_list->map;
79595584Sanholt 			break;
79695584Sanholt 		}
79795584Sanholt 	}
79895584Sanholt#endif /* __linux__ */
79995584Sanholt#ifdef __FreeBSD__
80095584Sanholt	TAILQ_FOREACH(listentry, dev->maplist, link) {
80195584Sanholt		drm_map_t *map = listentry->map;
80295584Sanholt		if (map->type == _DRM_SHM &&
80395584Sanholt			map->flags & _DRM_CONTAINS_LOCK) {
80495584Sanholt			dev_priv->sarea = map;
80595584Sanholt			break;
80695584Sanholt		}
80795584Sanholt	}
80895584Sanholt#endif /* __FreeBSD__ */
80995584Sanholt
81095584Sanholt	if(!dev_priv->sarea) {
81195584Sanholt		DRM_ERROR("could not find sarea!\n");
81295584Sanholt		dev->dev_private = (void *)dev_priv;
81395584Sanholt		radeon_do_cleanup_cp(dev);
81495693Sanholt		return DRM_OS_ERR(EINVAL);
81595584Sanholt	}
81695584Sanholt
81795584Sanholt	DRM_FIND_MAP( dev_priv->fb, init->fb_offset );
81895584Sanholt	if(!dev_priv->fb) {
81995584Sanholt		DRM_ERROR("could not find framebuffer!\n");
82095584Sanholt		dev->dev_private = (void *)dev_priv;
82195584Sanholt		radeon_do_cleanup_cp(dev);
82295693Sanholt		return DRM_OS_ERR(EINVAL);
82395584Sanholt	}
82495584Sanholt	DRM_FIND_MAP( dev_priv->mmio, init->mmio_offset );
82595584Sanholt	if(!dev_priv->mmio) {
82695584Sanholt		DRM_ERROR("could not find mmio region!\n");
82795584Sanholt		dev->dev_private = (void *)dev_priv;
82895584Sanholt		radeon_do_cleanup_cp(dev);
82995693Sanholt		return DRM_OS_ERR(EINVAL);
83095584Sanholt	}
83195584Sanholt	DRM_FIND_MAP( dev_priv->cp_ring, init->ring_offset );
83295584Sanholt	if(!dev_priv->cp_ring) {
83395584Sanholt		DRM_ERROR("could not find cp ring region!\n");
83495584Sanholt		dev->dev_private = (void *)dev_priv;
83595584Sanholt		radeon_do_cleanup_cp(dev);
83695693Sanholt		return DRM_OS_ERR(EINVAL);
83795584Sanholt	}
83895584Sanholt	DRM_FIND_MAP( dev_priv->ring_rptr, init->ring_rptr_offset );
83995584Sanholt	if(!dev_priv->ring_rptr) {
84095584Sanholt		DRM_ERROR("could not find ring read pointer!\n");
84195584Sanholt		dev->dev_private = (void *)dev_priv;
84295584Sanholt		radeon_do_cleanup_cp(dev);
84395693Sanholt		return DRM_OS_ERR(EINVAL);
84495584Sanholt	}
84595584Sanholt	DRM_FIND_MAP( dev_priv->buffers, init->buffers_offset );
84695584Sanholt	if(!dev_priv->buffers) {
84795584Sanholt		DRM_ERROR("could not find dma buffer region!\n");
84895584Sanholt		dev->dev_private = (void *)dev_priv;
84995584Sanholt		radeon_do_cleanup_cp(dev);
85095693Sanholt		return DRM_OS_ERR(EINVAL);
85195584Sanholt	}
85295584Sanholt
85395584Sanholt	if ( !dev_priv->is_pci ) {
85495584Sanholt		DRM_FIND_MAP( dev_priv->agp_textures,
85595584Sanholt			      init->agp_textures_offset );
85695584Sanholt		if(!dev_priv->agp_textures) {
85795584Sanholt			DRM_ERROR("could not find agp texture region!\n");
85895584Sanholt			dev->dev_private = (void *)dev_priv;
85995584Sanholt			radeon_do_cleanup_cp(dev);
86095693Sanholt			return DRM_OS_ERR(EINVAL);
86195584Sanholt		}
86295584Sanholt	}
86395584Sanholt
86495584Sanholt	dev_priv->sarea_priv =
86595584Sanholt		(drm_radeon_sarea_t *)((u8 *)dev_priv->sarea->handle +
86695584Sanholt				       init->sarea_priv_offset);
86795584Sanholt
86895584Sanholt	if ( !dev_priv->is_pci ) {
86995584Sanholt		DRM_IOREMAP( dev_priv->cp_ring );
87095584Sanholt		DRM_IOREMAP( dev_priv->ring_rptr );
87195584Sanholt		DRM_IOREMAP( dev_priv->buffers );
87295584Sanholt		if(!dev_priv->cp_ring->handle ||
87395584Sanholt		   !dev_priv->ring_rptr->handle ||
87495584Sanholt		   !dev_priv->buffers->handle) {
87595584Sanholt			DRM_ERROR("could not find ioremap agp regions!\n");
87695584Sanholt			dev->dev_private = (void *)dev_priv;
87795584Sanholt			radeon_do_cleanup_cp(dev);
87895693Sanholt			return DRM_OS_ERR(EINVAL);
87995584Sanholt		}
88095584Sanholt	} else {
88195584Sanholt		dev_priv->cp_ring->handle =
88295584Sanholt			(void *)dev_priv->cp_ring->offset;
88395584Sanholt		dev_priv->ring_rptr->handle =
88495584Sanholt			(void *)dev_priv->ring_rptr->offset;
88595584Sanholt		dev_priv->buffers->handle = (void *)dev_priv->buffers->offset;
88695584Sanholt
88795584Sanholt		DRM_DEBUG( "dev_priv->cp_ring->handle %p\n",
88895584Sanholt			   dev_priv->cp_ring->handle );
88995584Sanholt		DRM_DEBUG( "dev_priv->ring_rptr->handle %p\n",
89095584Sanholt			   dev_priv->ring_rptr->handle );
89195584Sanholt		DRM_DEBUG( "dev_priv->buffers->handle %p\n",
89295584Sanholt			   dev_priv->buffers->handle );
89395584Sanholt	}
89495584Sanholt
89595584Sanholt
89695584Sanholt	dev_priv->agp_size = init->agp_size;
89795584Sanholt	dev_priv->agp_vm_start = RADEON_READ( RADEON_CONFIG_APER_SIZE );
89895584Sanholt#if __REALLY_HAVE_AGP
89995584Sanholt	if ( !dev_priv->is_pci )
90095584Sanholt		dev_priv->agp_buffers_offset = (dev_priv->buffers->offset
90195584Sanholt						- dev->agp->base
90295584Sanholt						+ dev_priv->agp_vm_start);
90395584Sanholt	else
90495584Sanholt#endif
90595584Sanholt		dev_priv->agp_buffers_offset = (dev_priv->buffers->offset
90695584Sanholt						- dev->sg->handle
90795584Sanholt						+ dev_priv->agp_vm_start);
90895584Sanholt
90995584Sanholt	DRM_DEBUG( "dev_priv->agp_size %d\n",
91095584Sanholt		   dev_priv->agp_size );
91195584Sanholt	DRM_DEBUG( "dev_priv->agp_vm_start 0x%x\n",
91295584Sanholt		   dev_priv->agp_vm_start );
91395584Sanholt	DRM_DEBUG( "dev_priv->agp_buffers_offset 0x%lx\n",
91495584Sanholt		   dev_priv->agp_buffers_offset );
91595584Sanholt
91695584Sanholt	dev_priv->ring.head = ((__volatile__ u32 *)
91795584Sanholt			       dev_priv->ring_rptr->handle);
91895584Sanholt
91995584Sanholt	dev_priv->ring.start = (u32 *)dev_priv->cp_ring->handle;
92095584Sanholt	dev_priv->ring.end = ((u32 *)dev_priv->cp_ring->handle
92195584Sanholt			      + init->ring_size / sizeof(u32));
92295584Sanholt	dev_priv->ring.size = init->ring_size;
92395584Sanholt	dev_priv->ring.size_l2qw = DRM(order)( init->ring_size / 8 );
92495584Sanholt
92595584Sanholt	dev_priv->ring.tail_mask =
92695584Sanholt		(dev_priv->ring.size / sizeof(u32)) - 1;
92795584Sanholt
92895584Sanholt	dev_priv->ring.high_mark = RADEON_RING_HIGH_MARK;
92995584Sanholt
93095584Sanholt#if 0
93195584Sanholt	/* Initialize the scratch register pointer.  This will cause
93295584Sanholt	 * the scratch register values to be written out to memory
93395584Sanholt	 * whenever they are updated.
93495584Sanholt	 * FIXME: This doesn't quite work yet, so we're disabling it
93595584Sanholt	 * for the release.
93695584Sanholt	 */
93795584Sanholt	RADEON_WRITE( RADEON_SCRATCH_ADDR, (dev_priv->ring_rptr->offset +
93895584Sanholt					    RADEON_SCRATCH_REG_OFFSET) );
93995584Sanholt	RADEON_WRITE( RADEON_SCRATCH_UMSK, 0x7 );
94095584Sanholt#endif
94195584Sanholt
94295584Sanholt	dev_priv->scratch = ((__volatile__ u32 *)
94395584Sanholt			     dev_priv->ring_rptr->handle +
94495584Sanholt			     (RADEON_SCRATCH_REG_OFFSET / sizeof(u32)));
94595584Sanholt
94695584Sanholt	dev_priv->sarea_priv->last_frame = 0;
94795584Sanholt	RADEON_WRITE( RADEON_LAST_FRAME_REG,
94895584Sanholt		      dev_priv->sarea_priv->last_frame );
94995584Sanholt
95095584Sanholt	dev_priv->sarea_priv->last_dispatch = 0;
95195584Sanholt	RADEON_WRITE( RADEON_LAST_DISPATCH_REG,
95295584Sanholt		      dev_priv->sarea_priv->last_dispatch );
95395584Sanholt
95495584Sanholt	dev_priv->sarea_priv->last_clear = 0;
95595584Sanholt	RADEON_WRITE( RADEON_LAST_CLEAR_REG,
95695584Sanholt		      dev_priv->sarea_priv->last_clear );
95795584Sanholt
95895584Sanholt#if __REALLY_HAVE_SG
95995584Sanholt	if ( dev_priv->is_pci ) {
96095584Sanholt		if (!DRM(ati_pcigart_init)( dev, &dev_priv->phys_pci_gart,
96195584Sanholt					    &dev_priv->bus_pci_gart)) {
96295584Sanholt			DRM_ERROR( "failed to init PCI GART!\n" );
96395584Sanholt			dev->dev_private = (void *)dev_priv;
96495584Sanholt			radeon_do_cleanup_cp(dev);
96595693Sanholt			return DRM_OS_ERR(ENOMEM);
96695584Sanholt		}
96795584Sanholt		/* Turn on PCI GART
96895584Sanholt		 */
96995584Sanholt		tmp = RADEON_READ( RADEON_AIC_CNTL )
97095584Sanholt		      | RADEON_PCIGART_TRANSLATE_EN;
97195584Sanholt		RADEON_WRITE( RADEON_AIC_CNTL, tmp );
97295584Sanholt
97395584Sanholt		/* set PCI GART page-table base address
97495584Sanholt		 */
97595584Sanholt		RADEON_WRITE( RADEON_AIC_PT_BASE, dev_priv->bus_pci_gart );
97695584Sanholt
97795584Sanholt		/* set address range for PCI address translate
97895584Sanholt		 */
97995584Sanholt		RADEON_WRITE( RADEON_AIC_LO_ADDR, dev_priv->agp_vm_start );
98095584Sanholt		RADEON_WRITE( RADEON_AIC_HI_ADDR, dev_priv->agp_vm_start
98195584Sanholt						  + dev_priv->agp_size - 1);
98295584Sanholt
98395584Sanholt		/* Turn off AGP aperture -- is this required for PCIGART?
98495584Sanholt		 */
98595584Sanholt		RADEON_WRITE( RADEON_MC_AGP_LOCATION, 0xffffffc0 ); /* ?? */
98695584Sanholt		RADEON_WRITE( RADEON_AGP_COMMAND, 0 ); /* clear AGP_COMMAND */
98795584Sanholt	} else {
98895584Sanholt#endif
98995584Sanholt		/* Turn off PCI GART
99095584Sanholt		 */
99195584Sanholt		tmp = RADEON_READ( RADEON_AIC_CNTL )
99295584Sanholt		      & ~RADEON_PCIGART_TRANSLATE_EN;
99395584Sanholt		RADEON_WRITE( RADEON_AIC_CNTL, tmp );
99495584Sanholt#if __REALLY_HAVE_SG
99595584Sanholt	}
99695584Sanholt#endif
99795584Sanholt
99895584Sanholt	radeon_cp_load_microcode( dev_priv );
99995584Sanholt	radeon_cp_init_ring_buffer( dev, dev_priv );
100095584Sanholt
100195584Sanholt#if ROTATE_BUFS
100295584Sanholt	dev_priv->last_buf = 0;
100395584Sanholt#endif
100495584Sanholt
100595584Sanholt	dev->dev_private = (void *)dev_priv;
100695584Sanholt
100795584Sanholt	radeon_do_engine_reset( dev );
100895584Sanholt
100995584Sanholt	return 0;
101095584Sanholt}
101195584Sanholt
101295584Sanholtint radeon_do_cleanup_cp( drm_device_t *dev )
101395584Sanholt{
101495584Sanholt	DRM_DEBUG( "%s\n", __FUNCTION__ );
101595584Sanholt
101695584Sanholt	if ( dev->dev_private ) {
101795584Sanholt		drm_radeon_private_t *dev_priv = dev->dev_private;
101895584Sanholt
101995584Sanholt#if __REALLY_HAVE_SG
102095584Sanholt		if ( !dev_priv->is_pci ) {
102195584Sanholt#endif
102295584Sanholt			DRM_IOREMAPFREE( dev_priv->cp_ring );
102395584Sanholt			DRM_IOREMAPFREE( dev_priv->ring_rptr );
102495584Sanholt			DRM_IOREMAPFREE( dev_priv->buffers );
102595584Sanholt#if __REALLY_HAVE_SG
102695584Sanholt		} else {
102795584Sanholt			if (!DRM(ati_pcigart_cleanup)( dev,
102895584Sanholt						dev_priv->phys_pci_gart,
102995584Sanholt						dev_priv->bus_pci_gart ))
103095584Sanholt				DRM_ERROR( "failed to cleanup PCI GART!\n" );
103195584Sanholt		}
103295584Sanholt#endif
103395584Sanholt
103495584Sanholt		DRM(free)( dev->dev_private, sizeof(drm_radeon_private_t),
103595584Sanholt			   DRM_MEM_DRIVER );
103695584Sanholt		dev->dev_private = NULL;
103795584Sanholt	}
103895584Sanholt
103995584Sanholt	return 0;
104095584Sanholt}
104195584Sanholt
104295584Sanholtint radeon_cp_init( DRM_OS_IOCTL )
104395584Sanholt{
104495584Sanholt	DRM_OS_DEVICE;
104595584Sanholt	drm_radeon_init_t init;
104695584Sanholt
104795584Sanholt	DRM_OS_KRNFROMUSR( init, (drm_radeon_init_t *) data, sizeof(init) );
104895584Sanholt
104995584Sanholt	switch ( init.func ) {
105095584Sanholt	case RADEON_INIT_CP:
105195584Sanholt		return radeon_do_init_cp( dev, &init );
105295584Sanholt	case RADEON_CLEANUP_CP:
105395584Sanholt		return radeon_do_cleanup_cp( dev );
105495584Sanholt	}
105595584Sanholt
105695693Sanholt	return DRM_OS_ERR(EINVAL);
105795584Sanholt}
105895584Sanholt
105995584Sanholtint radeon_cp_start( DRM_OS_IOCTL )
106095584Sanholt{
106195584Sanholt 	DRM_OS_DEVICE;
106295584Sanholt	drm_radeon_private_t *dev_priv = dev->dev_private;
106395584Sanholt	DRM_DEBUG( "%s\n", __FUNCTION__ );
106495584Sanholt
106595584Sanholt	LOCK_TEST_WITH_RETURN( dev );
106695584Sanholt
106795584Sanholt	if ( dev_priv->cp_running ) {
106895584Sanholt		DRM_DEBUG( "%s while CP running\n", __FUNCTION__ );
106995584Sanholt		return 0;
107095584Sanholt	}
107195584Sanholt	if ( dev_priv->cp_mode == RADEON_CSQ_PRIDIS_INDDIS ) {
107295584Sanholt		DRM_DEBUG( "%s called with bogus CP mode (%d)\n",
107395584Sanholt			   __FUNCTION__, dev_priv->cp_mode );
107495584Sanholt		return 0;
107595584Sanholt	}
107695584Sanholt
107795584Sanholt	radeon_do_cp_start( dev_priv );
107895584Sanholt
107995584Sanholt	return 0;
108095584Sanholt}
108195584Sanholt
108295584Sanholt/* Stop the CP.  The engine must have been idled before calling this
108395584Sanholt * routine.
108495584Sanholt */
108595584Sanholtint radeon_cp_stop( DRM_OS_IOCTL )
108695584Sanholt{
108795584Sanholt	DRM_OS_DEVICE;
108895584Sanholt	drm_radeon_private_t *dev_priv = dev->dev_private;
108995584Sanholt	drm_radeon_cp_stop_t stop;
109095584Sanholt	int ret;
109195584Sanholt	DRM_DEBUG( "%s\n", __FUNCTION__ );
109295584Sanholt
109395584Sanholt	LOCK_TEST_WITH_RETURN( dev );
109495584Sanholt
109595584Sanholt	DRM_OS_KRNFROMUSR( stop, (drm_radeon_cp_stop_t *) data, sizeof(stop) );
109695584Sanholt
109795584Sanholt	/* Flush any pending CP commands.  This ensures any outstanding
109895584Sanholt	 * commands are exectuted by the engine before we turn it off.
109995584Sanholt	 */
110095584Sanholt	if ( stop.flush ) {
110195584Sanholt		radeon_do_cp_flush( dev_priv );
110295584Sanholt	}
110395584Sanholt
110495584Sanholt	/* If we fail to make the engine go idle, we return an error
110595584Sanholt	 * code so that the DRM ioctl wrapper can try again.
110695584Sanholt	 */
110795584Sanholt	if ( stop.idle ) {
110895584Sanholt		ret = radeon_do_cp_idle( dev_priv );
110995584Sanholt		if ( ret ) return ret;
111095584Sanholt	}
111195584Sanholt
111295584Sanholt	/* Finally, we can turn off the CP.  If the engine isn't idle,
111395584Sanholt	 * we will get some dropped triangles as they won't be fully
111495584Sanholt	 * rendered before the CP is shut down.
111595584Sanholt	 */
111695584Sanholt	radeon_do_cp_stop( dev_priv );
111795584Sanholt
111895584Sanholt	/* Reset the engine */
111995584Sanholt	radeon_do_engine_reset( dev );
112095584Sanholt
112195584Sanholt	return 0;
112295584Sanholt}
112395584Sanholt
112495584Sanholt/* Just reset the CP ring.  Called as part of an X Server engine reset.
112595584Sanholt */
112695584Sanholtint radeon_cp_reset( DRM_OS_IOCTL )
112795584Sanholt{
112895584Sanholt	DRM_OS_DEVICE;
112995584Sanholt	drm_radeon_private_t *dev_priv = dev->dev_private;
113095584Sanholt	DRM_DEBUG( "%s\n", __FUNCTION__ );
113195584Sanholt
113295584Sanholt	LOCK_TEST_WITH_RETURN( dev );
113395584Sanholt
113495584Sanholt	if ( !dev_priv ) {
113595584Sanholt		DRM_DEBUG( "%s called before init done\n", __FUNCTION__ );
113695693Sanholt		return DRM_OS_ERR(EINVAL);
113795584Sanholt	}
113895584Sanholt
113995584Sanholt	radeon_do_cp_reset( dev_priv );
114095584Sanholt
114195584Sanholt	/* The CP is no longer running after an engine reset */
114295584Sanholt	dev_priv->cp_running = 0;
114395584Sanholt
114495584Sanholt	return 0;
114595584Sanholt}
114695584Sanholt
114795584Sanholtint radeon_cp_idle( DRM_OS_IOCTL )
114895584Sanholt{
114995584Sanholt	DRM_OS_DEVICE;
115095584Sanholt	drm_radeon_private_t *dev_priv = dev->dev_private;
115195584Sanholt	DRM_DEBUG( "%s\n", __FUNCTION__ );
115295584Sanholt
115395584Sanholt	LOCK_TEST_WITH_RETURN( dev );
115495584Sanholt
115595584Sanholt	return radeon_do_cp_idle( dev_priv );
115695584Sanholt}
115795584Sanholt
115895584Sanholtint radeon_engine_reset( DRM_OS_IOCTL )
115995584Sanholt{
116095584Sanholt	DRM_OS_DEVICE;
116195584Sanholt	DRM_DEBUG( "%s\n", __FUNCTION__ );
116295584Sanholt
116395584Sanholt	LOCK_TEST_WITH_RETURN( dev );
116495584Sanholt
116595584Sanholt	return radeon_do_engine_reset( dev );
116695584Sanholt}
116795584Sanholt
116895584Sanholt
116995584Sanholt/* ================================================================
117095584Sanholt * Fullscreen mode
117195584Sanholt */
117295584Sanholt
117395584Sanholtstatic int radeon_do_init_pageflip( drm_device_t *dev )
117495584Sanholt{
117595584Sanholt	drm_radeon_private_t *dev_priv = dev->dev_private;
117695584Sanholt	DRM_DEBUG( "%s\n", __FUNCTION__ );
117795584Sanholt
117895584Sanholt	dev_priv->crtc_offset =      RADEON_READ( RADEON_CRTC_OFFSET );
117995584Sanholt	dev_priv->crtc_offset_cntl = RADEON_READ( RADEON_CRTC_OFFSET_CNTL );
118095584Sanholt
118195584Sanholt	RADEON_WRITE( RADEON_CRTC_OFFSET, dev_priv->front_offset );
118295584Sanholt	RADEON_WRITE( RADEON_CRTC_OFFSET_CNTL,
118395584Sanholt		      dev_priv->crtc_offset_cntl |
118495584Sanholt		      RADEON_CRTC_OFFSET_FLIP_CNTL );
118595584Sanholt
118695584Sanholt	dev_priv->page_flipping = 1;
118795584Sanholt	dev_priv->current_page = 0;
118895584Sanholt
118995584Sanholt	return 0;
119095584Sanholt}
119195584Sanholt
119295584Sanholtint radeon_do_cleanup_pageflip( drm_device_t *dev )
119395584Sanholt{
119495584Sanholt	drm_radeon_private_t *dev_priv = dev->dev_private;
119595584Sanholt	DRM_DEBUG( "%s\n", __FUNCTION__ );
119695584Sanholt
119795584Sanholt	RADEON_WRITE( RADEON_CRTC_OFFSET,      dev_priv->crtc_offset );
119895584Sanholt	RADEON_WRITE( RADEON_CRTC_OFFSET_CNTL, dev_priv->crtc_offset_cntl );
119995584Sanholt
120095584Sanholt	dev_priv->page_flipping = 0;
120195584Sanholt	dev_priv->current_page = 0;
120295584Sanholt
120395584Sanholt	return 0;
120495584Sanholt}
120595584Sanholt
120695584Sanholtint radeon_fullscreen( DRM_OS_IOCTL )
120795584Sanholt{
120895584Sanholt	DRM_OS_DEVICE;
120995584Sanholt	drm_radeon_fullscreen_t fs;
121095584Sanholt
121195584Sanholt	LOCK_TEST_WITH_RETURN( dev );
121295584Sanholt
121395584Sanholt	DRM_OS_KRNFROMUSR( fs, (drm_radeon_fullscreen_t *) data,
121495584Sanholt			     sizeof(fs) );
121595584Sanholt
121695584Sanholt	switch ( fs.func ) {
121795584Sanholt	case RADEON_INIT_FULLSCREEN:
121895584Sanholt		return radeon_do_init_pageflip( dev );
121995584Sanholt	case RADEON_CLEANUP_FULLSCREEN:
122095584Sanholt		return radeon_do_cleanup_pageflip( dev );
122195584Sanholt	}
122295584Sanholt
122395693Sanholt	return DRM_OS_ERR(EINVAL);
122495584Sanholt}
122595584Sanholt
122695584Sanholt
122795584Sanholt/* ================================================================
122895584Sanholt * Freelist management
122995584Sanholt */
123095584Sanholt#define RADEON_BUFFER_USED	0xffffffff
123195584Sanholt#define RADEON_BUFFER_FREE	0
123295584Sanholt
123395584Sanholt#if 0
123495584Sanholtstatic int radeon_freelist_init( drm_device_t *dev )
123595584Sanholt{
123695584Sanholt	drm_device_dma_t *dma = dev->dma;
123795584Sanholt	drm_radeon_private_t *dev_priv = dev->dev_private;
123895584Sanholt	drm_buf_t *buf;
123995584Sanholt	drm_radeon_buf_priv_t *buf_priv;
124095584Sanholt	drm_radeon_freelist_t *entry;
124195584Sanholt	int i;
124295584Sanholt
124395584Sanholt	dev_priv->head = DRM(alloc)( sizeof(drm_radeon_freelist_t),
124495584Sanholt				     DRM_MEM_DRIVER );
124595584Sanholt	if ( dev_priv->head == NULL )
124695693Sanholt		return DRM_OS_ERR(ENOMEM);
124795584Sanholt
124895584Sanholt	memset( dev_priv->head, 0, sizeof(drm_radeon_freelist_t) );
124995584Sanholt	dev_priv->head->age = RADEON_BUFFER_USED;
125095584Sanholt
125195584Sanholt	for ( i = 0 ; i < dma->buf_count ; i++ ) {
125295584Sanholt		buf = dma->buflist[i];
125395584Sanholt		buf_priv = buf->dev_private;
125495584Sanholt
125595584Sanholt		entry = DRM(alloc)( sizeof(drm_radeon_freelist_t),
125695584Sanholt				    DRM_MEM_DRIVER );
125795693Sanholt		if ( !entry ) return DRM_OS_ERR(ENOMEM);
125895584Sanholt
125995584Sanholt		entry->age = RADEON_BUFFER_FREE;
126095584Sanholt		entry->buf = buf;
126195584Sanholt		entry->prev = dev_priv->head;
126295584Sanholt		entry->next = dev_priv->head->next;
126395584Sanholt		if ( !entry->next )
126495584Sanholt			dev_priv->tail = entry;
126595584Sanholt
126695584Sanholt		buf_priv->discard = 0;
126795584Sanholt		buf_priv->dispatched = 0;
126895584Sanholt		buf_priv->list_entry = entry;
126995584Sanholt
127095584Sanholt		dev_priv->head->next = entry;
127195584Sanholt
127295584Sanholt		if ( dev_priv->head->next )
127395584Sanholt			dev_priv->head->next->prev = entry;
127495584Sanholt	}
127595584Sanholt
127695584Sanholt	return 0;
127795584Sanholt
127895584Sanholt}
127995584Sanholt#endif
128095584Sanholt
128195584Sanholtdrm_buf_t *radeon_freelist_get( drm_device_t *dev )
128295584Sanholt{
128395584Sanholt	drm_device_dma_t *dma = dev->dma;
128495584Sanholt	drm_radeon_private_t *dev_priv = dev->dev_private;
128595584Sanholt	drm_radeon_buf_priv_t *buf_priv;
128695584Sanholt	drm_buf_t *buf;
128795584Sanholt	int i, t;
128895584Sanholt#if ROTATE_BUFS
128995584Sanholt	int start;
129095584Sanholt#endif
129195584Sanholt
129295584Sanholt	/* FIXME: Optimize -- use freelist code */
129395584Sanholt
129495584Sanholt	for ( i = 0 ; i < dma->buf_count ; i++ ) {
129595584Sanholt		buf = dma->buflist[i];
129695584Sanholt		buf_priv = buf->dev_private;
129795584Sanholt		if ( buf->pid == 0 ) {
129895584Sanholt			DRM_DEBUG( "  ret buf=%d last=%d pid=0\n",
129995584Sanholt				   buf->idx, dev_priv->last_buf );
130095584Sanholt			return buf;
130195584Sanholt		}
130295584Sanholt		DRM_DEBUG( "    skipping buf=%d pid=%d\n",
130395584Sanholt			   buf->idx, buf->pid );
130495584Sanholt	}
130595584Sanholt
130695584Sanholt#if ROTATE_BUFS
130795584Sanholt	if ( ++dev_priv->last_buf >= dma->buf_count )
130895584Sanholt		dev_priv->last_buf = 0;
130995584Sanholt	start = dev_priv->last_buf;
131095584Sanholt#endif
131195584Sanholt	for ( t = 0 ; t < dev_priv->usec_timeout ; t++ ) {
131295584Sanholt#if 0
131395584Sanholt		/* FIXME: Disable this for now */
131495584Sanholt		u32 done_age = dev_priv->scratch[RADEON_LAST_DISPATCH];
131595584Sanholt#else
131695584Sanholt		u32 done_age = RADEON_READ( RADEON_LAST_DISPATCH_REG );
131795584Sanholt#endif
131895584Sanholt#if ROTATE_BUFS
131995584Sanholt		for ( i = start ; i < dma->buf_count ; i++ ) {
132095584Sanholt#else
132195584Sanholt		for ( i = 0 ; i < dma->buf_count ; i++ ) {
132295584Sanholt#endif
132395584Sanholt			buf = dma->buflist[i];
132495584Sanholt			buf_priv = buf->dev_private;
132595584Sanholt			if ( buf->pending && buf_priv->age <= done_age ) {
132695584Sanholt				/* The buffer has been processed, so it
132795584Sanholt				 * can now be used.
132895584Sanholt				 */
132995584Sanholt				buf->pending = 0;
133095584Sanholt				DRM_DEBUG( "  ret buf=%d last=%d age=%d done=%d\n", buf->idx, dev_priv->last_buf, buf_priv->age, done_age );
133195584Sanholt				return buf;
133295584Sanholt			}
133395584Sanholt			DRM_DEBUG( "    skipping buf=%d age=%d done=%d\n",
133495584Sanholt				   buf->idx, buf_priv->age,
133595584Sanholt				   done_age );
133695584Sanholt#if ROTATE_BUFS
133795584Sanholt			start = 0;
133895584Sanholt#endif
133995584Sanholt		}
134095584Sanholt		DRM_OS_DELAY( 1 );
134195584Sanholt	}
134295584Sanholt
134395584Sanholt	DRM_ERROR( "returning NULL!\n" );
134495584Sanholt	return NULL;
134595584Sanholt}
134695584Sanholt
134795584Sanholtvoid radeon_freelist_reset( drm_device_t *dev )
134895584Sanholt{
134995584Sanholt	drm_device_dma_t *dma = dev->dma;
135095584Sanholt#if ROTATE_BUFS
135195584Sanholt	drm_radeon_private_t *dev_priv = dev->dev_private;
135295584Sanholt#endif
135395584Sanholt	int i;
135495584Sanholt
135595584Sanholt#if ROTATE_BUFS
135695584Sanholt	dev_priv->last_buf = 0;
135795584Sanholt#endif
135895584Sanholt	for ( i = 0 ; i < dma->buf_count ; i++ ) {
135995584Sanholt		drm_buf_t *buf = dma->buflist[i];
136095584Sanholt		drm_radeon_buf_priv_t *buf_priv = buf->dev_private;
136195584Sanholt		buf_priv->age = 0;
136295584Sanholt	}
136395584Sanholt}
136495584Sanholt
136595584Sanholt
136695584Sanholt/* ================================================================
136795584Sanholt * CP command submission
136895584Sanholt */
136995584Sanholt
137095584Sanholtint radeon_wait_ring( drm_radeon_private_t *dev_priv, int n )
137195584Sanholt{
137295584Sanholt	drm_radeon_ring_buffer_t *ring = &dev_priv->ring;
137395584Sanholt	int i;
137495584Sanholt
137595584Sanholt	for ( i = 0 ; i < dev_priv->usec_timeout ; i++ ) {
137695584Sanholt		radeon_update_ring_snapshot( ring );
137795584Sanholt		if ( ring->space > n )
137895584Sanholt			return 0;
137995584Sanholt		DRM_OS_DELAY( 1 );
138095584Sanholt	}
138195584Sanholt
138295584Sanholt	/* FIXME: This return value is ignored in the BEGIN_RING macro! */
138395584Sanholt#if RADEON_FIFO_DEBUG
138495584Sanholt	radeon_status( dev_priv );
138595584Sanholt	DRM_ERROR( "failed!\n" );
138695584Sanholt#endif
138795693Sanholt	return DRM_OS_ERR(EBUSY);
138895584Sanholt}
138995584Sanholt
139095584Sanholtstatic int radeon_cp_get_buffers( drm_device_t *dev, drm_dma_t *d )
139195584Sanholt{
139295584Sanholt	int i;
139395584Sanholt	drm_buf_t *buf;
139495584Sanholt
139595584Sanholt	for ( i = d->granted_count ; i < d->request_count ; i++ ) {
139695584Sanholt		buf = radeon_freelist_get( dev );
139795693Sanholt		if ( !buf ) return DRM_OS_ERR(EAGAIN);
139895584Sanholt
139995584Sanholt		buf->pid = DRM_OS_CURRENTPID;
140095584Sanholt
140195584Sanholt		if (DRM_OS_COPYTOUSR( &d->request_indices[i], &buf->idx,
140295584Sanholt				   sizeof(buf->idx) ) )
140395693Sanholt			return DRM_OS_ERR(EFAULT);
140495584Sanholt		if (DRM_OS_COPYTOUSR( &d->request_sizes[i], &buf->total,
140595584Sanholt				   sizeof(buf->total) ) )
140695693Sanholt			return DRM_OS_ERR(EFAULT);
140795584Sanholt
140895584Sanholt		d->granted_count++;
140995584Sanholt	}
141095584Sanholt	return 0;
141195584Sanholt}
141295584Sanholt
141395584Sanholtint radeon_cp_buffers( DRM_OS_IOCTL )
141495584Sanholt{
141595584Sanholt	DRM_OS_DEVICE;
141695584Sanholt	drm_device_dma_t *dma = dev->dma;
141795584Sanholt	int ret = 0;
141895584Sanholt	drm_dma_t d;
141995584Sanholt
142095584Sanholt	LOCK_TEST_WITH_RETURN( dev );
142195584Sanholt
142295584Sanholt	DRM_OS_KRNFROMUSR( d, (drm_dma_t *) data, sizeof(d) );
142395584Sanholt
142495584Sanholt	/* Please don't send us buffers.
142595584Sanholt	 */
142695584Sanholt	if ( d.send_count != 0 ) {
142795584Sanholt		DRM_ERROR( "Process %d trying to send %d buffers via drmDMA\n",
142895584Sanholt			   DRM_OS_CURRENTPID, d.send_count );
142995693Sanholt		return DRM_OS_ERR(EINVAL);
143095584Sanholt	}
143195584Sanholt
143295584Sanholt	/* We'll send you buffers.
143395584Sanholt	 */
143495584Sanholt	if ( d.request_count < 0 || d.request_count > dma->buf_count ) {
143595584Sanholt		DRM_ERROR( "Process %d trying to get %d buffers (of %d max)\n",
143695584Sanholt			   DRM_OS_CURRENTPID, d.request_count, dma->buf_count );
143795693Sanholt		return DRM_OS_ERR(EINVAL);
143895584Sanholt	}
143995584Sanholt
144095584Sanholt	d.granted_count = 0;
144195584Sanholt
144295584Sanholt	if ( d.request_count ) {
144395584Sanholt		ret = radeon_cp_get_buffers( dev, &d );
144495584Sanholt	}
144595584Sanholt
144695584Sanholt	DRM_OS_KRNTOUSR( (drm_dma_t *) data, d, sizeof(d) );
144795584Sanholt
144895584Sanholt	return ret;
144995584Sanholt}
1450