diff mbox

[023/165] drm/radeon/cik: fill in startup/shutdown callbacks (v4)

Message ID 1372253045-17042-24-git-send-email-alexdeucher@gmail.com (mailing list archive)
State New, archived
Headers show

Commit Message

Alex Deucher June 26, 2013, 1:21 p.m. UTC
From: Alex Deucher <alexander.deucher@amd.com>

v2: update to latest driver changes
v3: properly tear down vm on suspend
v4: fix up irq init ordering

Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
---
 drivers/gpu/drm/radeon/cik.c |  340 ++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 340 insertions(+), 0 deletions(-)

Comments

Christian König June 26, 2013, 3:03 p.m. UTC | #1
Am 26.06.2013 15:21, schrieb alexdeucher@gmail.com:
> From: Alex Deucher <alexander.deucher@amd.com>
>
> v2: update to latest driver changes
> v3: properly tear down vm on suspend
> v4: fix up irq init ordering
>
> Signed-off-by: Alex Deucher <alexander.deucher@amd.com>

Just a copy&paste error, but some comments are referring to cayman and 
r500/r700 generations.

With that fixed the patch is:

Reviewed-by: Christian König <christian.koenig@amd.com>


> ---
>   drivers/gpu/drm/radeon/cik.c |  340 ++++++++++++++++++++++++++++++++++++++++++
>   1 files changed, 340 insertions(+), 0 deletions(-)
>
> diff --git a/drivers/gpu/drm/radeon/cik.c b/drivers/gpu/drm/radeon/cik.c
> index cf1e0b1..cbc64a2 100644
> --- a/drivers/gpu/drm/radeon/cik.c
> +++ b/drivers/gpu/drm/radeon/cik.c
> @@ -73,6 +73,8 @@ extern void r600_ih_ring_fini(struct radeon_device *rdev);
>   extern void evergreen_mc_stop(struct radeon_device *rdev, struct evergreen_mc_save *save);
>   extern void evergreen_mc_resume(struct radeon_device *rdev, struct evergreen_mc_save *save);
>   extern void si_vram_gtt_location(struct radeon_device *rdev, struct radeon_mc *mc);
> +extern void si_rlc_fini(struct radeon_device *rdev);
> +extern int si_rlc_init(struct radeon_device *rdev);
>   
>   #define BONAIRE_IO_MC_REGS_SIZE 36
>   
> @@ -4681,3 +4683,341 @@ restart_ih:
>   
>   	return IRQ_HANDLED;
>   }
> +
> +/*
> + * startup/shutdown callbacks
> + */
> +/**
> + * cik_startup - program the asic to a functional state
> + *
> + * @rdev: radeon_device pointer
> + *
> + * Programs the asic to a functional state (CIK).
> + * Called by cik_init() and cik_resume().
> + * Returns 0 for success, error for failure.
> + */
> +static int cik_startup(struct radeon_device *rdev)
> +{
> +	struct radeon_ring *ring;
> +	int r;
> +
> +	if (rdev->flags & RADEON_IS_IGP) {
> +		if (!rdev->me_fw || !rdev->pfp_fw || !rdev->ce_fw ||
> +		    !rdev->mec_fw || !rdev->sdma_fw || !rdev->rlc_fw) {
> +			r = cik_init_microcode(rdev);
> +			if (r) {
> +				DRM_ERROR("Failed to load firmware!\n");
> +				return r;
> +			}
> +		}
> +	} else {
> +		if (!rdev->me_fw || !rdev->pfp_fw || !rdev->ce_fw ||
> +		    !rdev->mec_fw || !rdev->sdma_fw || !rdev->rlc_fw ||
> +		    !rdev->mc_fw) {
> +			r = cik_init_microcode(rdev);
> +			if (r) {
> +				DRM_ERROR("Failed to load firmware!\n");
> +				return r;
> +			}
> +		}
> +
> +		r = ci_mc_load_microcode(rdev);
> +		if (r) {
> +			DRM_ERROR("Failed to load MC firmware!\n");
> +			return r;
> +		}
> +	}
> +
> +	r = r600_vram_scratch_init(rdev);
> +	if (r)
> +		return r;
> +
> +	cik_mc_program(rdev);
> +	r = cik_pcie_gart_enable(rdev);
> +	if (r)
> +		return r;
> +	cik_gpu_init(rdev);
> +
> +	/* allocate rlc buffers */
> +	r = si_rlc_init(rdev);
> +	if (r) {
> +		DRM_ERROR("Failed to init rlc BOs!\n");
> +		return r;
> +	}
> +
> +	/* allocate wb buffer */
> +	r = radeon_wb_init(rdev);
> +	if (r)
> +		return r;
> +
> +	r = radeon_fence_driver_start_ring(rdev, RADEON_RING_TYPE_GFX_INDEX);
> +	if (r) {
> +		dev_err(rdev->dev, "failed initializing CP fences (%d).\n", r);
> +		return r;
> +	}
> +
> +	r = radeon_fence_driver_start_ring(rdev, R600_RING_TYPE_DMA_INDEX);
> +	if (r) {
> +		dev_err(rdev->dev, "failed initializing DMA fences (%d).\n", r);
> +		return r;
> +	}
> +
> +	r = radeon_fence_driver_start_ring(rdev, CAYMAN_RING_TYPE_DMA1_INDEX);
> +	if (r) {
> +		dev_err(rdev->dev, "failed initializing DMA fences (%d).\n", r);
> +		return r;
> +	}
> +
> +	/* Enable IRQ */
> +	if (!rdev->irq.installed) {
> +		r = radeon_irq_kms_init(rdev);
> +		if (r)
> +			return r;
> +	}
> +
> +	r = cik_irq_init(rdev);
> +	if (r) {
> +		DRM_ERROR("radeon: IH init failed (%d).\n", r);
> +		radeon_irq_kms_fini(rdev);
> +		return r;
> +	}
> +	cik_irq_set(rdev);
> +
> +	ring = &rdev->ring[RADEON_RING_TYPE_GFX_INDEX];
> +	r = radeon_ring_init(rdev, ring, ring->ring_size, RADEON_WB_CP_RPTR_OFFSET,
> +			     CP_RB0_RPTR, CP_RB0_WPTR,
> +			     0, 0xfffff, RADEON_CP_PACKET2);
> +	if (r)
> +		return r;
> +
> +	ring = &rdev->ring[R600_RING_TYPE_DMA_INDEX];
> +	r = radeon_ring_init(rdev, ring, ring->ring_size, R600_WB_DMA_RPTR_OFFSET,
> +			     SDMA0_GFX_RB_RPTR + SDMA0_REGISTER_OFFSET,
> +			     SDMA0_GFX_RB_WPTR + SDMA0_REGISTER_OFFSET,
> +			     2, 0xfffffffc, SDMA_PACKET(SDMA_OPCODE_NOP, 0, 0));
> +	if (r)
> +		return r;
> +
> +	ring = &rdev->ring[CAYMAN_RING_TYPE_DMA1_INDEX];
> +	r = radeon_ring_init(rdev, ring, ring->ring_size, CAYMAN_WB_DMA1_RPTR_OFFSET,
> +			     SDMA0_GFX_RB_RPTR + SDMA1_REGISTER_OFFSET,
> +			     SDMA0_GFX_RB_WPTR + SDMA1_REGISTER_OFFSET,
> +			     2, 0xfffffffc, SDMA_PACKET(SDMA_OPCODE_NOP, 0, 0));
> +	if (r)
> +		return r;
> +
> +	r = cik_cp_resume(rdev);
> +	if (r)
> +		return r;
> +
> +	r = cik_sdma_resume(rdev);
> +	if (r)
> +		return r;
> +
> +	r = radeon_ib_pool_init(rdev);
> +	if (r) {
> +		dev_err(rdev->dev, "IB initialization failed (%d).\n", r);
> +		return r;
> +	}
> +
> +	r = radeon_vm_manager_init(rdev);
> +	if (r) {
> +		dev_err(rdev->dev, "vm manager initialization failed (%d).\n", r);
> +		return r;
> +	}
> +
> +	return 0;
> +}
> +
> +/**
> + * cik_resume - resume the asic to a functional state
> + *
> + * @rdev: radeon_device pointer
> + *
> + * Programs the asic to a functional state (CIK).
> + * Called at resume.
> + * Returns 0 for success, error for failure.
> + */
> +int cik_resume(struct radeon_device *rdev)
> +{
> +	int r;
> +
> +	/* Do not reset GPU before posting, on rv770 hw unlike on r500 hw,
> +	 * posting will perform necessary task to bring back GPU into good
> +	 * shape.
> +	 */
> +	/* post card */
> +	atom_asic_init(rdev->mode_info.atom_context);
> +
> +	rdev->accel_working = true;
> +	r = cik_startup(rdev);
> +	if (r) {
> +		DRM_ERROR("cik startup failed on resume\n");
> +		rdev->accel_working = false;
> +		return r;
> +	}
> +
> +	return r;
> +
> +}
> +
> +/**
> + * cik_suspend - suspend the asic
> + *
> + * @rdev: radeon_device pointer
> + *
> + * Bring the chip into a state suitable for suspend (CIK).
> + * Called at suspend.
> + * Returns 0 for success.
> + */
> +int cik_suspend(struct radeon_device *rdev)
> +{
> +	radeon_vm_manager_fini(rdev);
> +	cik_cp_enable(rdev, false);
> +	cik_sdma_enable(rdev, false);
> +	cik_irq_suspend(rdev);
> +	radeon_wb_disable(rdev);
> +	cik_pcie_gart_disable(rdev);
> +	return 0;
> +}
> +
> +/* Plan is to move initialization in that function and use
> + * helper function so that radeon_device_init pretty much
> + * do nothing more than calling asic specific function. This
> + * should also allow to remove a bunch of callback function
> + * like vram_info.
> + */
> +/**
> + * cik_init - asic specific driver and hw init
> + *
> + * @rdev: radeon_device pointer
> + *
> + * Setup asic specific driver variables and program the hw
> + * to a functional state (CIK).
> + * Called at driver startup.
> + * Returns 0 for success, errors for failure.
> + */
> +int cik_init(struct radeon_device *rdev)
> +{
> +	struct radeon_ring *ring;
> +	int r;
> +
> +	/* Read BIOS */
> +	if (!radeon_get_bios(rdev)) {
> +		if (ASIC_IS_AVIVO(rdev))
> +			return -EINVAL;
> +	}
> +	/* Must be an ATOMBIOS */
> +	if (!rdev->is_atom_bios) {
> +		dev_err(rdev->dev, "Expecting atombios for cayman GPU\n");
> +		return -EINVAL;
> +	}
> +	r = radeon_atombios_init(rdev);
> +	if (r)
> +		return r;
> +
> +	/* Post card if necessary */
> +	if (!radeon_card_posted(rdev)) {
> +		if (!rdev->bios) {
> +			dev_err(rdev->dev, "Card not posted and no BIOS - ignoring\n");
> +			return -EINVAL;
> +		}
> +		DRM_INFO("GPU not posted. posting now...\n");
> +		atom_asic_init(rdev->mode_info.atom_context);
> +	}
> +	/* Initialize scratch registers */
> +	cik_scratch_init(rdev);
> +	/* Initialize surface registers */
> +	radeon_surface_init(rdev);
> +	/* Initialize clocks */
> +	radeon_get_clock_info(rdev->ddev);
> +
> +	/* Fence driver */
> +	r = radeon_fence_driver_init(rdev);
> +	if (r)
> +		return r;
> +
> +	/* initialize memory controller */
> +	r = cik_mc_init(rdev);
> +	if (r)
> +		return r;
> +	/* Memory manager */
> +	r = radeon_bo_init(rdev);
> +	if (r)
> +		return r;
> +
> +	ring = &rdev->ring[RADEON_RING_TYPE_GFX_INDEX];
> +	ring->ring_obj = NULL;
> +	r600_ring_init(rdev, ring, 1024 * 1024);
> +
> +	ring = &rdev->ring[R600_RING_TYPE_DMA_INDEX];
> +	ring->ring_obj = NULL;
> +	r600_ring_init(rdev, ring, 256 * 1024);
> +
> +	ring = &rdev->ring[CAYMAN_RING_TYPE_DMA1_INDEX];
> +	ring->ring_obj = NULL;
> +	r600_ring_init(rdev, ring, 256 * 1024);
> +
> +	rdev->ih.ring_obj = NULL;
> +	r600_ih_ring_init(rdev, 64 * 1024);
> +
> +	r = r600_pcie_gart_init(rdev);
> +	if (r)
> +		return r;
> +
> +	rdev->accel_working = true;
> +	r = cik_startup(rdev);
> +	if (r) {
> +		dev_err(rdev->dev, "disabling GPU acceleration\n");
> +		cik_cp_fini(rdev);
> +		cik_sdma_fini(rdev);
> +		cik_irq_fini(rdev);
> +		si_rlc_fini(rdev);
> +		radeon_wb_fini(rdev);
> +		radeon_ib_pool_fini(rdev);
> +		radeon_vm_manager_fini(rdev);
> +		radeon_irq_kms_fini(rdev);
> +		cik_pcie_gart_fini(rdev);
> +		rdev->accel_working = false;
> +	}
> +
> +	/* Don't start up if the MC ucode is missing.
> +	 * The default clocks and voltages before the MC ucode
> +	 * is loaded are not suffient for advanced operations.
> +	 */
> +	if (!rdev->mc_fw && !(rdev->flags & RADEON_IS_IGP)) {
> +		DRM_ERROR("radeon: MC ucode required for NI+.\n");
> +		return -EINVAL;
> +	}
> +
> +	return 0;
> +}
> +
> +/**
> + * cik_fini - asic specific driver and hw fini
> + *
> + * @rdev: radeon_device pointer
> + *
> + * Tear down the asic specific driver variables and program the hw
> + * to an idle state (CIK).
> + * Called at driver unload.
> + */
> +void cik_fini(struct radeon_device *rdev)
> +{
> +	cik_cp_fini(rdev);
> +	cik_sdma_fini(rdev);
> +	cik_irq_fini(rdev);
> +	si_rlc_fini(rdev);
> +	radeon_wb_fini(rdev);
> +	radeon_vm_manager_fini(rdev);
> +	radeon_ib_pool_fini(rdev);
> +	radeon_irq_kms_fini(rdev);
> +	cik_pcie_gart_fini(rdev);
> +	r600_vram_scratch_fini(rdev);
> +	radeon_gem_fini(rdev);
> +	radeon_fence_driver_fini(rdev);
> +	radeon_bo_fini(rdev);
> +	radeon_atombios_fini(rdev);
> +	kfree(rdev->bios);
> +	rdev->bios = NULL;
> +}
diff mbox

Patch

diff --git a/drivers/gpu/drm/radeon/cik.c b/drivers/gpu/drm/radeon/cik.c
index cf1e0b1..cbc64a2 100644
--- a/drivers/gpu/drm/radeon/cik.c
+++ b/drivers/gpu/drm/radeon/cik.c
@@ -73,6 +73,8 @@  extern void r600_ih_ring_fini(struct radeon_device *rdev);
 extern void evergreen_mc_stop(struct radeon_device *rdev, struct evergreen_mc_save *save);
 extern void evergreen_mc_resume(struct radeon_device *rdev, struct evergreen_mc_save *save);
 extern void si_vram_gtt_location(struct radeon_device *rdev, struct radeon_mc *mc);
+extern void si_rlc_fini(struct radeon_device *rdev);
+extern int si_rlc_init(struct radeon_device *rdev);
 
 #define BONAIRE_IO_MC_REGS_SIZE 36
 
@@ -4681,3 +4683,341 @@  restart_ih:
 
 	return IRQ_HANDLED;
 }
+
+/*
+ * startup/shutdown callbacks
+ */
+/**
+ * cik_startup - program the asic to a functional state
+ *
+ * @rdev: radeon_device pointer
+ *
+ * Programs the asic to a functional state (CIK).
+ * Called by cik_init() and cik_resume().
+ * Returns 0 for success, error for failure.
+ */
+static int cik_startup(struct radeon_device *rdev)
+{
+	struct radeon_ring *ring;
+	int r;
+
+	if (rdev->flags & RADEON_IS_IGP) {
+		if (!rdev->me_fw || !rdev->pfp_fw || !rdev->ce_fw ||
+		    !rdev->mec_fw || !rdev->sdma_fw || !rdev->rlc_fw) {
+			r = cik_init_microcode(rdev);
+			if (r) {
+				DRM_ERROR("Failed to load firmware!\n");
+				return r;
+			}
+		}
+	} else {
+		if (!rdev->me_fw || !rdev->pfp_fw || !rdev->ce_fw ||
+		    !rdev->mec_fw || !rdev->sdma_fw || !rdev->rlc_fw ||
+		    !rdev->mc_fw) {
+			r = cik_init_microcode(rdev);
+			if (r) {
+				DRM_ERROR("Failed to load firmware!\n");
+				return r;
+			}
+		}
+
+		r = ci_mc_load_microcode(rdev);
+		if (r) {
+			DRM_ERROR("Failed to load MC firmware!\n");
+			return r;
+		}
+	}
+
+	r = r600_vram_scratch_init(rdev);
+	if (r)
+		return r;
+
+	cik_mc_program(rdev);
+	r = cik_pcie_gart_enable(rdev);
+	if (r)
+		return r;
+	cik_gpu_init(rdev);
+
+	/* allocate rlc buffers */
+	r = si_rlc_init(rdev);
+	if (r) {
+		DRM_ERROR("Failed to init rlc BOs!\n");
+		return r;
+	}
+
+	/* allocate wb buffer */
+	r = radeon_wb_init(rdev);
+	if (r)
+		return r;
+
+	r = radeon_fence_driver_start_ring(rdev, RADEON_RING_TYPE_GFX_INDEX);
+	if (r) {
+		dev_err(rdev->dev, "failed initializing CP fences (%d).\n", r);
+		return r;
+	}
+
+	r = radeon_fence_driver_start_ring(rdev, R600_RING_TYPE_DMA_INDEX);
+	if (r) {
+		dev_err(rdev->dev, "failed initializing DMA fences (%d).\n", r);
+		return r;
+	}
+
+	r = radeon_fence_driver_start_ring(rdev, CAYMAN_RING_TYPE_DMA1_INDEX);
+	if (r) {
+		dev_err(rdev->dev, "failed initializing DMA fences (%d).\n", r);
+		return r;
+	}
+
+	/* Enable IRQ */
+	if (!rdev->irq.installed) {
+		r = radeon_irq_kms_init(rdev);
+		if (r)
+			return r;
+	}
+
+	r = cik_irq_init(rdev);
+	if (r) {
+		DRM_ERROR("radeon: IH init failed (%d).\n", r);
+		radeon_irq_kms_fini(rdev);
+		return r;
+	}
+	cik_irq_set(rdev);
+
+	ring = &rdev->ring[RADEON_RING_TYPE_GFX_INDEX];
+	r = radeon_ring_init(rdev, ring, ring->ring_size, RADEON_WB_CP_RPTR_OFFSET,
+			     CP_RB0_RPTR, CP_RB0_WPTR,
+			     0, 0xfffff, RADEON_CP_PACKET2);
+	if (r)
+		return r;
+
+	ring = &rdev->ring[R600_RING_TYPE_DMA_INDEX];
+	r = radeon_ring_init(rdev, ring, ring->ring_size, R600_WB_DMA_RPTR_OFFSET,
+			     SDMA0_GFX_RB_RPTR + SDMA0_REGISTER_OFFSET,
+			     SDMA0_GFX_RB_WPTR + SDMA0_REGISTER_OFFSET,
+			     2, 0xfffffffc, SDMA_PACKET(SDMA_OPCODE_NOP, 0, 0));
+	if (r)
+		return r;
+
+	ring = &rdev->ring[CAYMAN_RING_TYPE_DMA1_INDEX];
+	r = radeon_ring_init(rdev, ring, ring->ring_size, CAYMAN_WB_DMA1_RPTR_OFFSET,
+			     SDMA0_GFX_RB_RPTR + SDMA1_REGISTER_OFFSET,
+			     SDMA0_GFX_RB_WPTR + SDMA1_REGISTER_OFFSET,
+			     2, 0xfffffffc, SDMA_PACKET(SDMA_OPCODE_NOP, 0, 0));
+	if (r)
+		return r;
+
+	r = cik_cp_resume(rdev);
+	if (r)
+		return r;
+
+	r = cik_sdma_resume(rdev);
+	if (r)
+		return r;
+
+	r = radeon_ib_pool_init(rdev);
+	if (r) {
+		dev_err(rdev->dev, "IB initialization failed (%d).\n", r);
+		return r;
+	}
+
+	r = radeon_vm_manager_init(rdev);
+	if (r) {
+		dev_err(rdev->dev, "vm manager initialization failed (%d).\n", r);
+		return r;
+	}
+
+	return 0;
+}
+
+/**
+ * cik_resume - resume the asic to a functional state
+ *
+ * @rdev: radeon_device pointer
+ *
+ * Programs the asic to a functional state (CIK).
+ * Called at resume.
+ * Returns 0 for success, error for failure.
+ */
+int cik_resume(struct radeon_device *rdev)
+{
+	int r;
+
+	/* Do not reset GPU before posting, on rv770 hw unlike on r500 hw,
+	 * posting will perform necessary task to bring back GPU into good
+	 * shape.
+	 */
+	/* post card */
+	atom_asic_init(rdev->mode_info.atom_context);
+
+	rdev->accel_working = true;
+	r = cik_startup(rdev);
+	if (r) {
+		DRM_ERROR("cik startup failed on resume\n");
+		rdev->accel_working = false;
+		return r;
+	}
+
+	return r;
+
+}
+
+/**
+ * cik_suspend - suspend the asic
+ *
+ * @rdev: radeon_device pointer
+ *
+ * Bring the chip into a state suitable for suspend (CIK).
+ * Called at suspend.
+ * Returns 0 for success.
+ */
+int cik_suspend(struct radeon_device *rdev)
+{
+	radeon_vm_manager_fini(rdev);
+	cik_cp_enable(rdev, false);
+	cik_sdma_enable(rdev, false);
+	cik_irq_suspend(rdev);
+	radeon_wb_disable(rdev);
+	cik_pcie_gart_disable(rdev);
+	return 0;
+}
+
+/* Plan is to move initialization in that function and use
+ * helper function so that radeon_device_init pretty much
+ * do nothing more than calling asic specific function. This
+ * should also allow to remove a bunch of callback function
+ * like vram_info.
+ */
+/**
+ * cik_init - asic specific driver and hw init
+ *
+ * @rdev: radeon_device pointer
+ *
+ * Setup asic specific driver variables and program the hw
+ * to a functional state (CIK).
+ * Called at driver startup.
+ * Returns 0 for success, errors for failure.
+ */
+int cik_init(struct radeon_device *rdev)
+{
+	struct radeon_ring *ring;
+	int r;
+
+	/* Read BIOS */
+	if (!radeon_get_bios(rdev)) {
+		if (ASIC_IS_AVIVO(rdev))
+			return -EINVAL;
+	}
+	/* Must be an ATOMBIOS */
+	if (!rdev->is_atom_bios) {
+		dev_err(rdev->dev, "Expecting atombios for cayman GPU\n");
+		return -EINVAL;
+	}
+	r = radeon_atombios_init(rdev);
+	if (r)
+		return r;
+
+	/* Post card if necessary */
+	if (!radeon_card_posted(rdev)) {
+		if (!rdev->bios) {
+			dev_err(rdev->dev, "Card not posted and no BIOS - ignoring\n");
+			return -EINVAL;
+		}
+		DRM_INFO("GPU not posted. posting now...\n");
+		atom_asic_init(rdev->mode_info.atom_context);
+	}
+	/* Initialize scratch registers */
+	cik_scratch_init(rdev);
+	/* Initialize surface registers */
+	radeon_surface_init(rdev);
+	/* Initialize clocks */
+	radeon_get_clock_info(rdev->ddev);
+
+	/* Fence driver */
+	r = radeon_fence_driver_init(rdev);
+	if (r)
+		return r;
+
+	/* initialize memory controller */
+	r = cik_mc_init(rdev);
+	if (r)
+		return r;
+	/* Memory manager */
+	r = radeon_bo_init(rdev);
+	if (r)
+		return r;
+
+	ring = &rdev->ring[RADEON_RING_TYPE_GFX_INDEX];
+	ring->ring_obj = NULL;
+	r600_ring_init(rdev, ring, 1024 * 1024);
+
+	ring = &rdev->ring[R600_RING_TYPE_DMA_INDEX];
+	ring->ring_obj = NULL;
+	r600_ring_init(rdev, ring, 256 * 1024);
+
+	ring = &rdev->ring[CAYMAN_RING_TYPE_DMA1_INDEX];
+	ring->ring_obj = NULL;
+	r600_ring_init(rdev, ring, 256 * 1024);
+
+	rdev->ih.ring_obj = NULL;
+	r600_ih_ring_init(rdev, 64 * 1024);
+
+	r = r600_pcie_gart_init(rdev);
+	if (r)
+		return r;
+
+	rdev->accel_working = true;
+	r = cik_startup(rdev);
+	if (r) {
+		dev_err(rdev->dev, "disabling GPU acceleration\n");
+		cik_cp_fini(rdev);
+		cik_sdma_fini(rdev);
+		cik_irq_fini(rdev);
+		si_rlc_fini(rdev);
+		radeon_wb_fini(rdev);
+		radeon_ib_pool_fini(rdev);
+		radeon_vm_manager_fini(rdev);
+		radeon_irq_kms_fini(rdev);
+		cik_pcie_gart_fini(rdev);
+		rdev->accel_working = false;
+	}
+
+	/* Don't start up if the MC ucode is missing.
+	 * The default clocks and voltages before the MC ucode
+	 * is loaded are not suffient for advanced operations.
+	 */
+	if (!rdev->mc_fw && !(rdev->flags & RADEON_IS_IGP)) {
+		DRM_ERROR("radeon: MC ucode required for NI+.\n");
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+/**
+ * cik_fini - asic specific driver and hw fini
+ *
+ * @rdev: radeon_device pointer
+ *
+ * Tear down the asic specific driver variables and program the hw
+ * to an idle state (CIK).
+ * Called at driver unload.
+ */
+void cik_fini(struct radeon_device *rdev)
+{
+	cik_cp_fini(rdev);
+	cik_sdma_fini(rdev);
+	cik_irq_fini(rdev);
+	si_rlc_fini(rdev);
+	radeon_wb_fini(rdev);
+	radeon_vm_manager_fini(rdev);
+	radeon_ib_pool_fini(rdev);
+	radeon_irq_kms_fini(rdev);
+	cik_pcie_gart_fini(rdev);
+	r600_vram_scratch_fini(rdev);
+	radeon_gem_fini(rdev);
+	radeon_fence_driver_fini(rdev);
+	radeon_bo_fini(rdev);
+	radeon_atombios_fini(rdev);
+	kfree(rdev->bios);
+	rdev->bios = NULL;
+}