drm/radeon/kms: add support for semaphores v3

They are used to sync between rings, while fences
sync between a ring and the cpu.

v2 Fix radeon_semaphore_driver_fini when no semaphore were
allocated.

v3 Initialize list early on to avoid issue in case or early
error

Signed-off-by: Christian König <deathsimple@vodafone.de>
Signed-off-by: Jerome Glisse <jglisse@redhat.com>
Signed-off-by: Dave Airlie <airlied@redhat.com>
This commit is contained in:
Christian König 2011-09-15 19:02:22 +02:00 committed by Dave Airlie
parent 7465280c07
commit 15d3332f31
13 changed files with 248 additions and 6 deletions

View File

@ -70,7 +70,8 @@ radeon-y += radeon_device.o radeon_asic.o radeon_kms.o \
r200.o radeon_legacy_tv.o r600_cs.o r600_blit.o r600_blit_shaders.o \
r600_blit_kms.o radeon_pm.o atombios_dp.o r600_audio.o r600_hdmi.o \
evergreen.o evergreen_cs.o evergreen_blit_shaders.o evergreen_blit_kms.o \
radeon_trace_points.o ni.o cayman_blit_shaders.o atombios_encoders.o
radeon_trace_points.o ni.o cayman_blit_shaders.o atombios_encoders.o \
radeon_semaphore.o
radeon-$(CONFIG_COMPAT) += radeon_ioc32.o
radeon-$(CONFIG_VGA_SWITCHEROO) += radeon_atpx_handler.o
@ -78,4 +79,4 @@ radeon-$(CONFIG_ACPI) += radeon_acpi.o
obj-$(CONFIG_DRM_RADEON)+= radeon.o
CFLAGS_radeon_trace_points.o := -I$(src)
CFLAGS_radeon_trace_points.o := -I$(src)

View File

@ -1448,7 +1448,7 @@ int evergreen_cp_resume(struct radeon_device *rdev)
tmp |= BUF_SWAP_32BIT;
#endif
WREG32(CP_RB_CNTL, tmp);
WREG32(CP_SEM_WAIT_TIMER, 0x4);
WREG32(CP_SEM_WAIT_TIMER, 0x0);
/* Set the write pointer delay */
WREG32(CP_RB_WPTR_DELAY, 0);
@ -3290,6 +3290,7 @@ void evergreen_fini(struct radeon_device *rdev)
evergreen_pcie_gart_fini(rdev);
r600_vram_scratch_fini(rdev);
radeon_gem_fini(rdev);
radeon_semaphore_driver_fini(rdev);
radeon_fence_driver_fini(rdev);
radeon_agp_fini(rdev);
radeon_bo_fini(rdev);

View File

@ -1136,7 +1136,7 @@ int cayman_cp_resume(struct radeon_device *rdev)
WREG32(GRBM_SOFT_RESET, 0);
RREG32(GRBM_SOFT_RESET);
WREG32(CP_SEM_WAIT_TIMER, 0x4);
WREG32(CP_SEM_WAIT_TIMER, 0x0);
/* Set the write pointer delay */
WREG32(CP_RB_WPTR_DELAY, 0);
@ -1557,6 +1557,7 @@ void cayman_fini(struct radeon_device *rdev)
cayman_pcie_gart_fini(rdev);
r600_vram_scratch_fini(rdev);
radeon_gem_fini(rdev);
radeon_semaphore_driver_fini(rdev);
radeon_fence_driver_fini(rdev);
radeon_bo_fini(rdev);
radeon_atombios_fini(rdev);

View File

@ -832,6 +832,14 @@ void r100_fence_ring_emit(struct radeon_device *rdev,
radeon_ring_write(rdev, RADEON_SW_INT_FIRE);
}
void r100_semaphore_ring_emit(struct radeon_device *rdev,
struct radeon_semaphore *semaphore,
unsigned ring, bool emit_wait)
{
/* Unused on older asics, since we don't have semaphores or multiple rings */
BUG();
}
int r100_copy_blit(struct radeon_device *rdev,
uint64_t src_offset,
uint64_t dst_offset,

View File

@ -2190,7 +2190,7 @@ int r600_cp_resume(struct radeon_device *rdev)
tmp |= BUF_SWAP_32BIT;
#endif
WREG32(CP_RB_CNTL, tmp);
WREG32(CP_SEM_WAIT_TIMER, 0x4);
WREG32(CP_SEM_WAIT_TIMER, 0x0);
/* Set the write pointer delay */
WREG32(CP_RB_WPTR_DELAY, 0);
@ -2357,6 +2357,18 @@ void r600_fence_ring_emit(struct radeon_device *rdev,
}
}
void r600_semaphore_ring_emit(struct radeon_device *rdev,
struct radeon_semaphore *semaphore,
unsigned ring, bool emit_wait)
{
uint64_t addr = semaphore->gpu_addr;
unsigned sel = emit_wait ? PACKET3_SEM_SEL_WAIT : PACKET3_SEM_SEL_SIGNAL;
radeon_ring_write(rdev, PACKET3(PACKET3_MEM_SEMAPHORE, 1));
radeon_ring_write(rdev, addr & 0xffffffff);
radeon_ring_write(rdev, (upper_32_bits(addr) & 0xff) | sel);
}
int r600_copy_blit(struct radeon_device *rdev,
uint64_t src_offset,
uint64_t dst_offset,
@ -2649,6 +2661,7 @@ void r600_fini(struct radeon_device *rdev)
r600_vram_scratch_fini(rdev);
radeon_agp_fini(rdev);
radeon_gem_fini(rdev);
radeon_semaphore_driver_fini(rdev);
radeon_fence_driver_fini(rdev);
radeon_bo_fini(rdev);
radeon_atombios_fini(rdev);

View File

@ -1815,7 +1815,7 @@ static void r600_cp_init_ring_buffer(struct drm_device *dev,
dev_priv->ring.size_l2qw);
#endif
RADEON_WRITE(R600_CP_SEM_WAIT_TIMER, 0x4);
RADEON_WRITE(R600_CP_SEM_WAIT_TIMER, 0x0);
/* Set the write pointer delay */
RADEON_WRITE(R600_CP_RB_WPTR_DELAY, 0);

View File

@ -831,6 +831,8 @@
#define PACKET3_STRMOUT_BUFFER_UPDATE 0x34
#define PACKET3_INDIRECT_BUFFER_MP 0x38
#define PACKET3_MEM_SEMAPHORE 0x39
# define PACKET3_SEM_SEL_SIGNAL (0x6 << 29)
# define PACKET3_SEM_SEL_WAIT (0x7 << 29)
#define PACKET3_MPEG_INDEX 0x3A
#define PACKET3_WAIT_REG_MEM 0x3C
#define PACKET3_MEM_WRITE 0x3D

View File

@ -227,6 +227,30 @@ int radeon_fence_wait_last(struct radeon_device *rdev, int ring);
struct radeon_fence *radeon_fence_ref(struct radeon_fence *fence);
void radeon_fence_unref(struct radeon_fence **fence);
/*
* Semaphores.
*/
struct radeon_semaphore_driver {
rwlock_t lock;
struct list_head free;
};
struct radeon_semaphore {
struct radeon_bo *robj;
struct list_head list;
uint64_t gpu_addr;
};
void radeon_semaphore_driver_fini(struct radeon_device *rdev);
int radeon_semaphore_create(struct radeon_device *rdev,
struct radeon_semaphore **semaphore);
void radeon_semaphore_emit_signal(struct radeon_device *rdev, int ring,
struct radeon_semaphore *semaphore);
void radeon_semaphore_emit_wait(struct radeon_device *rdev, int ring,
struct radeon_semaphore *semaphore);
void radeon_semaphore_free(struct radeon_device *rdev,
struct radeon_semaphore *semaphore);
/*
* Tiling registers
*/
@ -921,6 +945,9 @@ struct radeon_asic {
int (*irq_process)(struct radeon_device *rdev);
u32 (*get_vblank_counter)(struct radeon_device *rdev, int crtc);
void (*fence_ring_emit)(struct radeon_device *rdev, struct radeon_fence *fence);
void (*semaphore_ring_emit)(struct radeon_device *rdev,
struct radeon_semaphore *semaphore,
unsigned ring, bool emit_wait);
int (*cs_parse)(struct radeon_cs_parser *p);
int (*copy_blit)(struct radeon_device *rdev,
uint64_t src_offset,
@ -1250,6 +1277,7 @@ struct radeon_device {
struct radeon_mman mman;
rwlock_t fence_lock;
struct radeon_fence_driver fence_drv[RADEON_NUM_RINGS];
struct radeon_semaphore_driver semaphore_drv;
struct radeon_cp cp;
/* cayman compute rings */
struct radeon_cp cp1;
@ -1470,6 +1498,7 @@ void radeon_ring_write(struct radeon_device *rdev, uint32_t v);
#define radeon_irq_process(rdev) (rdev)->asic->irq_process((rdev))
#define radeon_get_vblank_counter(rdev, crtc) (rdev)->asic->get_vblank_counter((rdev), (crtc))
#define radeon_fence_ring_emit(rdev, fence) (rdev)->asic->fence_ring_emit((rdev), (fence))
#define radeon_semaphore_ring_emit(rdev, semaphore, ring, emit_wait) (rdev)->asic->semaphore_ring_emit((rdev), (semaphore), (ring), (emit_wait))
#define radeon_copy_blit(rdev, s, d, np, f) (rdev)->asic->copy_blit((rdev), (s), (d), (np), (f))
#define radeon_copy_dma(rdev, s, d, np, f) (rdev)->asic->copy_dma((rdev), (s), (d), (np), (f))
#define radeon_copy(rdev, s, d, np, f) (rdev)->asic->copy((rdev), (s), (d), (np), (f))

View File

@ -146,6 +146,7 @@ static struct radeon_asic r100_asic = {
.irq_process = &r100_irq_process,
.get_vblank_counter = &r100_get_vblank_counter,
.fence_ring_emit = &r100_fence_ring_emit,
.semaphore_ring_emit = &r100_semaphore_ring_emit,
.cs_parse = &r100_cs_parse,
.copy_blit = &r100_copy_blit,
.copy_dma = NULL,
@ -194,6 +195,7 @@ static struct radeon_asic r200_asic = {
.irq_process = &r100_irq_process,
.get_vblank_counter = &r100_get_vblank_counter,
.fence_ring_emit = &r100_fence_ring_emit,
.semaphore_ring_emit = &r100_semaphore_ring_emit,
.cs_parse = &r100_cs_parse,
.copy_blit = &r100_copy_blit,
.copy_dma = &r200_copy_dma,
@ -241,6 +243,7 @@ static struct radeon_asic r300_asic = {
.irq_process = &r100_irq_process,
.get_vblank_counter = &r100_get_vblank_counter,
.fence_ring_emit = &r300_fence_ring_emit,
.semaphore_ring_emit = &r100_semaphore_ring_emit,
.cs_parse = &r300_cs_parse,
.copy_blit = &r100_copy_blit,
.copy_dma = &r200_copy_dma,
@ -289,6 +292,7 @@ static struct radeon_asic r300_asic_pcie = {
.irq_process = &r100_irq_process,
.get_vblank_counter = &r100_get_vblank_counter,
.fence_ring_emit = &r300_fence_ring_emit,
.semaphore_ring_emit = &r100_semaphore_ring_emit,
.cs_parse = &r300_cs_parse,
.copy_blit = &r100_copy_blit,
.copy_dma = &r200_copy_dma,
@ -336,6 +340,7 @@ static struct radeon_asic r420_asic = {
.irq_process = &r100_irq_process,
.get_vblank_counter = &r100_get_vblank_counter,
.fence_ring_emit = &r300_fence_ring_emit,
.semaphore_ring_emit = &r100_semaphore_ring_emit,
.cs_parse = &r300_cs_parse,
.copy_blit = &r100_copy_blit,
.copy_dma = &r200_copy_dma,
@ -384,6 +389,7 @@ static struct radeon_asic rs400_asic = {
.irq_process = &r100_irq_process,
.get_vblank_counter = &r100_get_vblank_counter,
.fence_ring_emit = &r300_fence_ring_emit,
.semaphore_ring_emit = &r100_semaphore_ring_emit,
.cs_parse = &r300_cs_parse,
.copy_blit = &r100_copy_blit,
.copy_dma = &r200_copy_dma,
@ -432,6 +438,7 @@ static struct radeon_asic rs600_asic = {
.irq_process = &rs600_irq_process,
.get_vblank_counter = &rs600_get_vblank_counter,
.fence_ring_emit = &r300_fence_ring_emit,
.semaphore_ring_emit = &r100_semaphore_ring_emit,
.cs_parse = &r300_cs_parse,
.copy_blit = &r100_copy_blit,
.copy_dma = &r200_copy_dma,
@ -480,6 +487,7 @@ static struct radeon_asic rs690_asic = {
.irq_process = &rs600_irq_process,
.get_vblank_counter = &rs600_get_vblank_counter,
.fence_ring_emit = &r300_fence_ring_emit,
.semaphore_ring_emit = &r100_semaphore_ring_emit,
.cs_parse = &r300_cs_parse,
.copy_blit = &r100_copy_blit,
.copy_dma = &r200_copy_dma,
@ -528,6 +536,7 @@ static struct radeon_asic rv515_asic = {
.irq_process = &rs600_irq_process,
.get_vblank_counter = &rs600_get_vblank_counter,
.fence_ring_emit = &r300_fence_ring_emit,
.semaphore_ring_emit = &r100_semaphore_ring_emit,
.cs_parse = &r300_cs_parse,
.copy_blit = &r100_copy_blit,
.copy_dma = &r200_copy_dma,
@ -576,6 +585,7 @@ static struct radeon_asic r520_asic = {
.irq_process = &rs600_irq_process,
.get_vblank_counter = &rs600_get_vblank_counter,
.fence_ring_emit = &r300_fence_ring_emit,
.semaphore_ring_emit = &r100_semaphore_ring_emit,
.cs_parse = &r300_cs_parse,
.copy_blit = &r100_copy_blit,
.copy_dma = &r200_copy_dma,
@ -623,6 +633,7 @@ static struct radeon_asic r600_asic = {
.irq_process = &r600_irq_process,
.get_vblank_counter = &rs600_get_vblank_counter,
.fence_ring_emit = &r600_fence_ring_emit,
.semaphore_ring_emit = &r600_semaphore_ring_emit,
.cs_parse = &r600_cs_parse,
.copy_blit = &r600_copy_blit,
.copy_dma = NULL,
@ -670,6 +681,7 @@ static struct radeon_asic rs780_asic = {
.irq_process = &r600_irq_process,
.get_vblank_counter = &rs600_get_vblank_counter,
.fence_ring_emit = &r600_fence_ring_emit,
.semaphore_ring_emit = &r600_semaphore_ring_emit,
.cs_parse = &r600_cs_parse,
.copy_blit = &r600_copy_blit,
.copy_dma = NULL,
@ -717,6 +729,7 @@ static struct radeon_asic rv770_asic = {
.irq_process = &r600_irq_process,
.get_vblank_counter = &rs600_get_vblank_counter,
.fence_ring_emit = &r600_fence_ring_emit,
.semaphore_ring_emit = &r600_semaphore_ring_emit,
.cs_parse = &r600_cs_parse,
.copy_blit = &r600_copy_blit,
.copy_dma = NULL,
@ -764,6 +777,7 @@ static struct radeon_asic evergreen_asic = {
.irq_process = &evergreen_irq_process,
.get_vblank_counter = &evergreen_get_vblank_counter,
.fence_ring_emit = &r600_fence_ring_emit,
.semaphore_ring_emit = &r600_semaphore_ring_emit,
.cs_parse = &evergreen_cs_parse,
.copy_blit = &r600_copy_blit,
.copy_dma = NULL,
@ -811,6 +825,7 @@ static struct radeon_asic sumo_asic = {
.irq_process = &evergreen_irq_process,
.get_vblank_counter = &evergreen_get_vblank_counter,
.fence_ring_emit = &r600_fence_ring_emit,
.semaphore_ring_emit = &r600_semaphore_ring_emit,
.cs_parse = &evergreen_cs_parse,
.copy_blit = &r600_copy_blit,
.copy_dma = NULL,
@ -858,6 +873,7 @@ static struct radeon_asic btc_asic = {
.irq_process = &evergreen_irq_process,
.get_vblank_counter = &evergreen_get_vblank_counter,
.fence_ring_emit = &r600_fence_ring_emit,
.semaphore_ring_emit = &r600_semaphore_ring_emit,
.cs_parse = &evergreen_cs_parse,
.copy_blit = &r600_copy_blit,
.copy_dma = NULL,
@ -905,6 +921,7 @@ static struct radeon_asic cayman_asic = {
.irq_process = &evergreen_irq_process,
.get_vblank_counter = &evergreen_get_vblank_counter,
.fence_ring_emit = &r600_fence_ring_emit,
.semaphore_ring_emit = &r600_semaphore_ring_emit,
.cs_parse = &evergreen_cs_parse,
.copy_blit = &r600_copy_blit,
.copy_dma = NULL,

View File

@ -69,6 +69,9 @@ int r100_irq_set(struct radeon_device *rdev);
int r100_irq_process(struct radeon_device *rdev);
void r100_fence_ring_emit(struct radeon_device *rdev,
struct radeon_fence *fence);
void r100_semaphore_ring_emit(struct radeon_device *rdev,
struct radeon_semaphore *semaphore,
unsigned ring, bool emit_wait);
int r100_cs_parse(struct radeon_cs_parser *p);
void r100_pll_wreg(struct radeon_device *rdev, uint32_t reg, uint32_t v);
uint32_t r100_pll_rreg(struct radeon_device *rdev, uint32_t reg);
@ -300,6 +303,9 @@ void r600_pciep_wreg(struct radeon_device *rdev, uint32_t reg, uint32_t v);
int r600_cs_parse(struct radeon_cs_parser *p);
void r600_fence_ring_emit(struct radeon_device *rdev,
struct radeon_fence *fence);
void r600_semaphore_ring_emit(struct radeon_device *rdev,
struct radeon_semaphore *semaphore,
unsigned ring, bool emit_wait);
bool r600_gpu_is_lockup(struct radeon_device *rdev);
int r600_asic_reset(struct radeon_device *rdev);
int r600_set_surface_reg(struct radeon_device *rdev, int reg,

View File

@ -726,9 +726,11 @@ int radeon_device_init(struct radeon_device *rdev,
mutex_init(&rdev->pm.mutex);
mutex_init(&rdev->vram_mutex);
rwlock_init(&rdev->fence_lock);
rwlock_init(&rdev->semaphore_drv.lock);
INIT_LIST_HEAD(&rdev->gem.objects);
init_waitqueue_head(&rdev->irq.vblank_queue);
init_waitqueue_head(&rdev->irq.idle_queue);
INIT_LIST_HEAD(&rdev->semaphore_drv.free);
/* Set asic functions */
r = radeon_asic_init(rdev);

View File

@ -0,0 +1,161 @@
/*
* Copyright 2011 Christian König.
* All Rights Reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sub license, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
* THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
* OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
* USE OR OTHER DEALINGS IN THE SOFTWARE.
*
* The above copyright notice and this permission notice (including the
* next paragraph) shall be included in all copies or substantial portions
* of the Software.
*
*/
/*
* Authors:
* Christian König <deathsimple@vodafone.de>
*/
#include "drmP.h"
#include "drm.h"
#include "radeon.h"
static int allocate_semaphores(struct radeon_device *rdev)
{
const unsigned long bo_size = PAGE_SIZE * 4;
struct radeon_bo *bo;
struct list_head new_entrys;
unsigned long irq_flags;
uint64_t gpu_addr;
void *map;
int i, r;
r = radeon_bo_create(rdev, bo_size, RADEON_GPU_PAGE_SIZE, true,
RADEON_GEM_DOMAIN_GTT, &bo);
if (r) {
dev_err(rdev->dev, "(%d) failed to allocate semaphore bo\n", r);
return r;
}
r = radeon_bo_reserve(bo, false);
if (r) {
radeon_bo_unref(&bo);
dev_err(rdev->dev, "(%d) failed to reserve semaphore bo\n", r);
return r;
}
r = radeon_bo_kmap(bo, &map);
if (r) {
radeon_bo_unreserve(bo);
radeon_bo_unref(&bo);
dev_err(rdev->dev, "(%d) semaphore map failed\n", r);
return r;
}
memset(map, 0, bo_size);
radeon_bo_kunmap(bo);
r = radeon_bo_pin(bo, RADEON_GEM_DOMAIN_VRAM, &gpu_addr);
if (r) {
radeon_bo_unreserve(bo);
radeon_bo_unref(&bo);
dev_err(rdev->dev, "(%d) semaphore pin failed\n", r);
return r;
}
INIT_LIST_HEAD(&new_entrys);
for (i = 0; i < bo_size/8; ++i) {
struct radeon_semaphore *sem = kmalloc(sizeof(struct radeon_semaphore), GFP_KERNEL);
ttm_bo_reference(&bo->tbo);
sem->robj = bo;
sem->gpu_addr = gpu_addr;
gpu_addr += 8;
list_add_tail(&sem->list, &new_entrys);
}
radeon_bo_unreserve(bo);
radeon_bo_unref(&bo);
write_lock_irqsave(&rdev->semaphore_drv.lock, irq_flags);
list_splice_tail(&new_entrys, &rdev->semaphore_drv.free);
write_unlock_irqrestore(&rdev->semaphore_drv.lock, irq_flags);
DRM_INFO("%d new semaphores allocated\n", (int)(bo_size/8));
return 0;
}
int radeon_semaphore_create(struct radeon_device *rdev,
struct radeon_semaphore **semaphore)
{
unsigned long irq_flags;
write_lock_irqsave(&rdev->semaphore_drv.lock, irq_flags);
if (list_empty(&rdev->semaphore_drv.free)) {
int r;
write_unlock_irqrestore(&rdev->semaphore_drv.lock, irq_flags);
r = allocate_semaphores(rdev);
if (r)
return r;
write_lock_irqsave(&rdev->semaphore_drv.lock, irq_flags);
}
*semaphore = list_first_entry(&rdev->semaphore_drv.free, struct radeon_semaphore, list);
list_del(&(*semaphore)->list);
write_unlock_irqrestore(&rdev->semaphore_drv.lock, irq_flags);
return 0;
}
void radeon_semaphore_emit_signal(struct radeon_device *rdev, int ring,
struct radeon_semaphore *semaphore)
{
radeon_semaphore_ring_emit(rdev, semaphore, ring, false);
}
void radeon_semaphore_emit_wait(struct radeon_device *rdev, int ring,
struct radeon_semaphore *semaphore)
{
radeon_semaphore_ring_emit(rdev, semaphore, ring, true);
}
void radeon_semaphore_free(struct radeon_device *rdev,
struct radeon_semaphore *semaphore)
{
unsigned long irq_flags;
write_lock_irqsave(&rdev->semaphore_drv.lock, irq_flags);
list_add_tail(&semaphore->list, &rdev->semaphore_drv.free);
write_unlock_irqrestore(&rdev->semaphore_drv.lock, irq_flags);
}
void radeon_semaphore_driver_fini(struct radeon_device *rdev)
{
struct radeon_semaphore *i, *n;
struct list_head entrys;
unsigned long irq_flags;
INIT_LIST_HEAD(&entrys);
write_lock_irqsave(&rdev->semaphore_drv.lock, irq_flags);
if (!list_empty(&rdev->semaphore_drv.free)) {
list_splice(&rdev->semaphore_drv.free, &entrys);
}
INIT_LIST_HEAD(&rdev->semaphore_drv.free);
write_unlock_irqrestore(&rdev->semaphore_drv.lock, irq_flags);
list_for_each_entry_safe(i, n, &entrys, list) {
radeon_bo_unref(&i->robj);
kfree(i);
}
}

View File

@ -1270,6 +1270,7 @@ void rv770_fini(struct radeon_device *rdev)
rv770_pcie_gart_fini(rdev);
r600_vram_scratch_fini(rdev);
radeon_gem_fini(rdev);
radeon_semaphore_driver_fini(rdev);
radeon_fence_driver_fini(rdev);
radeon_agp_fini(rdev);
radeon_bo_fini(rdev);