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