All of lore.kernel.org
 help / color / mirror / Atom feed
* Improved GPU reset
@ 2010-03-09 14:45 Jerome Glisse
  2010-03-09 14:45 ` [PATCH 1/3] drm/radeon/kms: fence cleanup + more reliable GPU lockup detection V4 Jerome Glisse
  0 siblings, 1 reply; 5+ messages in thread
From: Jerome Glisse @ 2010-03-09 14:45 UTC (permalink / raw)
  To: airlied; +Cc: dri-devel

This serie of patch fix the shortcoming of the previous one, their
shouldn't be any more false positive and resume should lead to
infinite look or other reinitialization issue on r6xx/r7xx.

Cheers,
Jerome


------------------------------------------------------------------------------
Download Intel® Parallel Studio Eval
Try the new software tools for yourself. Speed compiling, find bugs
proactively, and fine-tune applications for parallel performance.
See why Intel Parallel Studio got high marks during beta.
http://p.sf.net/sfu/intel-sw-dev
--

^ permalink raw reply	[flat|nested] 5+ messages in thread

* [PATCH 1/3] drm/radeon/kms: fence cleanup + more reliable GPU lockup detection V4
  2010-03-09 14:45 Improved GPU reset Jerome Glisse
@ 2010-03-09 14:45 ` Jerome Glisse
  2010-03-09 14:45   ` [PATCH 2/3] drm/radeon/kms: rename gpu_reset to asic_reset Jerome Glisse
  2010-03-10 10:34   ` [PATCH 1/3] drm/radeon/kms: fence cleanup + more reliable GPU lockup detection V4 Pauli Nieminen
  0 siblings, 2 replies; 5+ messages in thread
From: Jerome Glisse @ 2010-03-09 14:45 UTC (permalink / raw)
  To: airlied; +Cc: Jerome Glisse, dri-devel

This patch cleanup the fence code, it drops the timeout field of
fence as the time to complete each IB is unpredictable and shouldn't
be bound.

The fence cleanup lead to GPU lockup detection improvement, this
patch introduce a callback, allowing to do asic specific test for
lockup detection. In this patch the CP is use as a first indicator
of GPU lockup. If CP doesn't make progress during 1second we assume
we are facing a GPU lockup.

To avoid overhead of testing GPU lockup frequently due to fence
taking time to be signaled we query the lockup callback every
500msec. There is plenty code comment explaining the design & choise
inside the code.

This have been tested mostly on R3XX/R5XX hw, in normal running
destkop (compiz firefox, quake3 running) the lockup callback wasn't
call once (1 hour session). Also tested with forcing GPU lockup and
lockup was reported after the 1s CP activity timeout.

V2 switch to 500ms timeout so GPU lockup get call at least 2 times
   in less than 2sec.
V3 store last jiffies in fence struct so on ERESTART, EBUSY we keep
   track of how long we already wait for a given fence
V4 make sure we got up to date cp read pointer so we don't have
   false positive

Signed-off-by: Jerome Glisse <jglisse@redhat.com>
---
 drivers/gpu/drm/radeon/evergreen.c    |    6 ++
 drivers/gpu/drm/radeon/r100.c         |   86 +++++++++++++++++++++++++++
 drivers/gpu/drm/radeon/r300.c         |   28 ++++++++-
 drivers/gpu/drm/radeon/r600.c         |   34 ++++++++++-
 drivers/gpu/drm/radeon/radeon.h       |  104 +++++++++++++++++++--------------
 drivers/gpu/drm/radeon/radeon_asic.h  |   20 ++++++-
 drivers/gpu/drm/radeon/radeon_fence.c |  102 +++++++++++++++++---------------
 drivers/gpu/drm/radeon/rv770.c        |    6 --
 8 files changed, 280 insertions(+), 106 deletions(-)

diff --git a/drivers/gpu/drm/radeon/evergreen.c b/drivers/gpu/drm/radeon/evergreen.c
index bd2e7aa..8988df7 100644
--- a/drivers/gpu/drm/radeon/evergreen.c
+++ b/drivers/gpu/drm/radeon/evergreen.c
@@ -490,6 +490,12 @@ int evergreen_mc_init(struct radeon_device *rdev)
 	return 0;
 }
 
+bool evergreen_gpu_is_lockup(struct radeon_device *rdev)
+{
+	/* FIXME: implement for evergreen */
+	return false;
+}
+
 int evergreen_gpu_reset(struct radeon_device *rdev)
 {
 	/* FIXME: implement for evergreen */
diff --git a/drivers/gpu/drm/radeon/r100.c b/drivers/gpu/drm/radeon/r100.c
index 91eb762..e4487f3 100644
--- a/drivers/gpu/drm/radeon/r100.c
+++ b/drivers/gpu/drm/radeon/r100.c
@@ -1772,6 +1772,92 @@ int r100_rb2d_reset(struct radeon_device *rdev)
 	return -1;
 }
 
+void r100_gpu_lockup_update(struct r100_gpu_lockup *lockup, struct radeon_cp *cp)
+{
+	lockup->last_cp_rptr = cp->rptr;
+	lockup->last_jiffies = jiffies;
+}
+
+/**
+ * r100_gpu_cp_is_lockup() - check if CP is lockup by recording information
+ * @rdev:	radeon device structure
+ * @lockup:	r100_gpu_lockup structure holding CP lockup tracking informations
+ * @cp:		radeon_cp structure holding CP information
+ *
+ * We don't need to initialize the lockup tracking information as we will either
+ * have CP rptr to a different value of jiffies wrap around which will force
+ * initialization of the lockup tracking informations.
+ *
+ * A possible false positivie is if we get call after while and last_cp_rptr ==
+ * the current CP rptr, even if it's unlikely it might happen. To avoid this
+ * if the elapsed time since last call is bigger than 2 second than we return
+ * false and update the tracking information. Due to this the caller must call
+ * r100_gpu_cp_is_lockup several time in less than 2sec for lockup to be reported
+ * the fencing code should be cautious about that.
+ *
+ * Caller should write to the ring to force CP to do something so we don't get
+ * false positive when CP is just gived nothing to do.
+ *
+ **/
+bool r100_gpu_cp_is_lockup(struct radeon_device *rdev, struct r100_gpu_lockup *lockup, struct radeon_cp *cp)
+{
+	unsigned long cjiffies, elapsed;
+
+	cjiffies = jiffies;
+	if (!time_after(cjiffies, lockup->last_jiffies)) {
+		/* likely a wrap around */
+		lockup->last_cp_rptr = cp->rptr;
+		lockup->last_jiffies = jiffies;
+		return false;
+	}
+	if (cp->rptr != lockup->last_cp_rptr) {
+		/* CP is still working no lockup */
+		lockup->last_cp_rptr = cp->rptr;
+		lockup->last_jiffies = jiffies;
+		return false;
+	}
+	elapsed = jiffies_to_msecs(cjiffies - lockup->last_jiffies);
+	if (elapsed >= 3000) {
+		/* very likely the improbable case where current
+		 * rptr is equal to last recorded, a while ago, rptr
+		 * this is more likely a false positive update tracking
+		 * information which should force us to be recall at
+		 * latter point
+		 */
+		lockup->last_cp_rptr = cp->rptr;
+		lockup->last_jiffies = jiffies;
+		return false;
+	}
+	if (elapsed >= 1000) {
+		dev_err(rdev->dev, "GPU lockup CP stall for more than %lumsec\n", elapsed);
+		return true;
+	}
+	/* give a chance to the GPU ... */
+	return false;
+}
+
+bool r100_gpu_is_lockup(struct radeon_device *rdev)
+{
+	u32 rbbm_status;
+	int r;
+
+	rbbm_status = RREG32(R_000E40_RBBM_STATUS);
+	if (!G_000E40_GUI_ACTIVE(rbbm_status)) {
+		r100_gpu_lockup_update(&rdev->config.r100.lockup, &rdev->cp);
+		return false;
+	}
+	/* force CP activities */
+	r = radeon_ring_lock(rdev, 2);
+	if (!r) {
+		/* PACKET2 NOP */
+		radeon_ring_write(rdev, 0x80000000);
+		radeon_ring_write(rdev, 0x80000000);
+		radeon_ring_unlock_commit(rdev);
+	}
+	rdev->cp.rptr = RREG32(RADEON_CP_RB_RPTR);
+	return r100_gpu_cp_is_lockup(rdev, &rdev->config.r100.lockup, &rdev->cp);
+}
+
 int r100_gpu_reset(struct radeon_device *rdev)
 {
 	uint32_t status;
diff --git a/drivers/gpu/drm/radeon/r300.c b/drivers/gpu/drm/radeon/r300.c
index 4cef90c..23346f6 100644
--- a/drivers/gpu/drm/radeon/r300.c
+++ b/drivers/gpu/drm/radeon/r300.c
@@ -26,8 +26,9 @@
  *          Jerome Glisse
  */
 #include <linux/seq_file.h>
-#include "drmP.h"
-#include "drm.h"
+#include <drm/drmP.h>
+#include <drm/drm.h>
+#include <drm/drm_crtc_helper.h>
 #include "radeon_reg.h"
 #include "radeon.h"
 #include "radeon_drm.h"
@@ -424,12 +425,35 @@ int r300_ga_reset(struct radeon_device *rdev)
 	return -1;
 }
 
+bool r300_gpu_is_lockup(struct radeon_device *rdev)
+{
+	u32 rbbm_status;
+	int r;
+
+	rbbm_status = RREG32(R_000E40_RBBM_STATUS);
+	if (!G_000E40_GUI_ACTIVE(rbbm_status)) {
+		r100_gpu_lockup_update(&rdev->config.r300.lockup, &rdev->cp);
+		return false;
+	}
+	/* force CP activities */
+	r = radeon_ring_lock(rdev, 2);
+	if (!r) {
+		/* PACKET2 NOP */
+		radeon_ring_write(rdev, 0x80000000);
+		radeon_ring_write(rdev, 0x80000000);
+		radeon_ring_unlock_commit(rdev);
+	}
+	rdev->cp.rptr = RREG32(RADEON_CP_RB_RPTR);
+	return r100_gpu_cp_is_lockup(rdev, &rdev->config.r300.lockup, &rdev->cp);
+}
+
 int r300_gpu_reset(struct radeon_device *rdev)
 {
 	uint32_t status;
 
 	/* reset order likely matter */
 	status = RREG32(RADEON_RBBM_STATUS);
+	dev_info(rdev->dev, "(%s:%d) RBBM_STATUS=0x%08X\n", __func__, __LINE__, status);
 	/* reset HDP */
 	r100_hdp_reset(rdev);
 	/* reset rb2d */
diff --git a/drivers/gpu/drm/radeon/r600.c b/drivers/gpu/drm/radeon/r600.c
index c522901..4520685 100644
--- a/drivers/gpu/drm/radeon/r600.c
+++ b/drivers/gpu/drm/radeon/r600.c
@@ -788,7 +788,7 @@ int r600_gpu_soft_reset(struct radeon_device *rdev)
 		dev_info(rdev->dev, "  R_008020_GRBM_SOFT_RESET=0x%08X\n", tmp);
 		WREG32(R_008020_GRBM_SOFT_RESET, tmp);
 		(void)RREG32(R_008020_GRBM_SOFT_RESET);
-		udelay(50);
+		mdelay(1);
 		WREG32(R_008020_GRBM_SOFT_RESET, 0);
 		(void)RREG32(R_008020_GRBM_SOFT_RESET);
 	}
@@ -828,16 +828,16 @@ int r600_gpu_soft_reset(struct radeon_device *rdev)
 	dev_info(rdev->dev, "  R_000E60_SRBM_SOFT_RESET=0x%08X\n", srbm_reset);
 	WREG32(R_000E60_SRBM_SOFT_RESET, srbm_reset);
 	(void)RREG32(R_000E60_SRBM_SOFT_RESET);
-	udelay(50);
+	mdelay(1);
 	WREG32(R_000E60_SRBM_SOFT_RESET, 0);
 	(void)RREG32(R_000E60_SRBM_SOFT_RESET);
 	WREG32(R_000E60_SRBM_SOFT_RESET, srbm_reset);
 	(void)RREG32(R_000E60_SRBM_SOFT_RESET);
-	udelay(50);
+	mdelay(1);
 	WREG32(R_000E60_SRBM_SOFT_RESET, 0);
 	(void)RREG32(R_000E60_SRBM_SOFT_RESET);
 	/* Wait a little for things to settle down */
-	udelay(50);
+	mdelay(1);
 	dev_info(rdev->dev, "  R_008010_GRBM_STATUS=0x%08X\n",
 		RREG32(R_008010_GRBM_STATUS));
 	dev_info(rdev->dev, "  R_008014_GRBM_STATUS2=0x%08X\n",
@@ -852,6 +852,32 @@ int r600_gpu_soft_reset(struct radeon_device *rdev)
 	return 0;
 }
 
+bool r600_gpu_is_lockup(struct radeon_device *rdev)
+{
+	u32 srbm_status;
+	u32 grbm_status;
+	u32 grbm_status2;
+	int r;
+
+	srbm_status = RREG32(R_000E50_SRBM_STATUS);
+	grbm_status = RREG32(R_008010_GRBM_STATUS);
+	grbm_status2 = RREG32(R_008014_GRBM_STATUS2);
+	if (!G_008010_GUI_ACTIVE(grbm_status)) {
+		r100_gpu_lockup_update(&rdev->config.r300.lockup, &rdev->cp);
+		return false;
+	}
+	/* force CP activities */
+	r = radeon_ring_lock(rdev, 2);
+	if (!r) {
+		/* PACKET2 NOP */
+		radeon_ring_write(rdev, 0x80000000);
+		radeon_ring_write(rdev, 0x80000000);
+		radeon_ring_unlock_commit(rdev);
+	}
+	rdev->cp.rptr = RREG32(R600_CP_RB_RPTR);
+	return r100_gpu_cp_is_lockup(rdev, &rdev->config.r300.lockup, &rdev->cp);
+}
+
 int r600_gpu_reset(struct radeon_device *rdev)
 {
 	return r600_gpu_soft_reset(rdev);
diff --git a/drivers/gpu/drm/radeon/radeon.h b/drivers/gpu/drm/radeon/radeon.h
index 829e26e..e97a118 100644
--- a/drivers/gpu/drm/radeon/radeon.h
+++ b/drivers/gpu/drm/radeon/radeon.h
@@ -97,6 +97,7 @@ extern int radeon_audio;
  * symbol;
  */
 #define RADEON_MAX_USEC_TIMEOUT		100000	/* 100 ms */
+#define RADEON_FENCE_JIFFIES_TIMEOUT	(HZ / 2)
 /* RADEON_IB_POOL_SIZE must be a power of 2 */
 #define RADEON_IB_POOL_SIZE		16
 #define RADEON_DEBUGFS_MAX_NUM_FILES	32
@@ -179,7 +180,8 @@ struct radeon_fence_driver {
 	uint32_t			scratch_reg;
 	atomic_t			seq;
 	uint32_t			last_seq;
-	unsigned long			count_timeout;
+	unsigned long			last_jiffies;
+	unsigned long			last_timeout;
 	wait_queue_head_t		queue;
 	rwlock_t			lock;
 	struct list_head		created;
@@ -194,7 +196,6 @@ struct radeon_fence {
 	struct list_head		list;
 	/* protected by radeon_fence.lock */
 	uint32_t			seq;
-	unsigned long			timeout;
 	bool				emited;
 	bool				signaled;
 };
@@ -742,6 +743,7 @@ struct radeon_asic {
 	int (*resume)(struct radeon_device *rdev);
 	int (*suspend)(struct radeon_device *rdev);
 	void (*vga_set_state)(struct radeon_device *rdev, bool state);
+	bool (*gpu_is_lockup)(struct radeon_device *rdev);
 	int (*gpu_reset)(struct radeon_device *rdev);
 	void (*gart_tlb_flush)(struct radeon_device *rdev);
 	int (*gart_set_page)(struct radeon_device *rdev, int i, uint64_t addr);
@@ -800,59 +802,68 @@ struct radeon_asic {
 /*
  * Asic structures
  */
+struct r100_gpu_lockup {
+	unsigned long	last_jiffies;
+	u32		last_cp_rptr;
+};
+
 struct r100_asic {
-	const unsigned	*reg_safe_bm;
-	unsigned	reg_safe_bm_size;
-	u32		hdp_cntl;
+	const unsigned		*reg_safe_bm;
+	unsigned		reg_safe_bm_size;
+	u32			hdp_cntl;
+	struct r100_gpu_lockup	lockup;
 };
 
 struct r300_asic {
-	const unsigned	*reg_safe_bm;
-	unsigned	reg_safe_bm_size;
-	u32		resync_scratch;
-	u32		hdp_cntl;
+	const unsigned		*reg_safe_bm;
+	unsigned		reg_safe_bm_size;
+	u32			resync_scratch;
+	u32			hdp_cntl;
+	struct r100_gpu_lockup	lockup;
 };
 
 struct r600_asic {
-	unsigned max_pipes;
-	unsigned max_tile_pipes;
-	unsigned max_simds;
-	unsigned max_backends;
-	unsigned max_gprs;
-	unsigned max_threads;
-	unsigned max_stack_entries;
-	unsigned max_hw_contexts;
-	unsigned max_gs_threads;
-	unsigned sx_max_export_size;
-	unsigned sx_max_export_pos_size;
-	unsigned sx_max_export_smx_size;
-	unsigned sq_num_cf_insts;
-	unsigned tiling_nbanks;
-	unsigned tiling_npipes;
-	unsigned tiling_group_size;
+	unsigned		max_pipes;
+	unsigned		max_tile_pipes;
+	unsigned		max_simds;
+	unsigned		max_backends;
+	unsigned		max_gprs;
+	unsigned		max_threads;
+	unsigned		max_stack_entries;
+	unsigned		max_hw_contexts;
+	unsigned		max_gs_threads;
+	unsigned		sx_max_export_size;
+	unsigned		sx_max_export_pos_size;
+	unsigned		sx_max_export_smx_size;
+	unsigned		sq_num_cf_insts;
+	unsigned		tiling_nbanks;
+	unsigned		tiling_npipes;
+	unsigned		tiling_group_size;
+	struct r100_gpu_lockup	lockup;
 };
 
 struct rv770_asic {
-	unsigned max_pipes;
-	unsigned max_tile_pipes;
-	unsigned max_simds;
-	unsigned max_backends;
-	unsigned max_gprs;
-	unsigned max_threads;
-	unsigned max_stack_entries;
-	unsigned max_hw_contexts;
-	unsigned max_gs_threads;
-	unsigned sx_max_export_size;
-	unsigned sx_max_export_pos_size;
-	unsigned sx_max_export_smx_size;
-	unsigned sq_num_cf_insts;
-	unsigned sx_num_of_sets;
-	unsigned sc_prim_fifo_size;
-	unsigned sc_hiz_tile_fifo_size;
-	unsigned sc_earlyz_tile_fifo_fize;
-	unsigned tiling_nbanks;
-	unsigned tiling_npipes;
-	unsigned tiling_group_size;
+	unsigned		max_pipes;
+	unsigned		max_tile_pipes;
+	unsigned		max_simds;
+	unsigned		max_backends;
+	unsigned		max_gprs;
+	unsigned		max_threads;
+	unsigned		max_stack_entries;
+	unsigned		max_hw_contexts;
+	unsigned		max_gs_threads;
+	unsigned		sx_max_export_size;
+	unsigned		sx_max_export_pos_size;
+	unsigned		sx_max_export_smx_size;
+	unsigned		sq_num_cf_insts;
+	unsigned		sx_num_of_sets;
+	unsigned		sc_prim_fifo_size;
+	unsigned		sc_hiz_tile_fifo_size;
+	unsigned		sc_earlyz_tile_fifo_fize;
+	unsigned		tiling_nbanks;
+	unsigned		tiling_npipes;
+	unsigned		tiling_group_size;
+	struct r100_gpu_lockup	lockup;
 };
 
 union radeon_asic_config {
@@ -1135,6 +1146,7 @@ static inline void radeon_ring_write(struct radeon_device *rdev, uint32_t v)
 #define radeon_suspend(rdev) (rdev)->asic->suspend((rdev))
 #define radeon_cs_parse(p) rdev->asic->cs_parse((p))
 #define radeon_vga_set_state(rdev, state) (rdev)->asic->vga_set_state((rdev), (state))
+#define radeon_gpu_is_lockup(rdev) (rdev)->asic->gpu_is_lockup((rdev))
 #define radeon_gpu_reset(rdev) (rdev)->asic->gpu_reset((rdev))
 #define radeon_gart_tlb_flush(rdev) (rdev)->asic->gart_tlb_flush((rdev))
 #define radeon_gart_set_page(rdev, i, p) (rdev)->asic->gart_set_page((rdev), (i), (p))
@@ -1233,6 +1245,8 @@ extern int r100_cs_packet_parse(struct radeon_cs_parser *p,
 				unsigned idx);
 extern void r100_enable_bm(struct radeon_device *rdev);
 extern void r100_set_common_regs(struct radeon_device *rdev);
+extern void r100_gpu_lockup_update(struct r100_gpu_lockup *lockup, struct radeon_cp *cp);
+extern bool r100_gpu_cp_is_lockup(struct radeon_device *rdev, struct r100_gpu_lockup *lockup, struct radeon_cp *cp);
 
 /* rv200,rv250,rv280 */
 extern void r200_set_safe_registers(struct radeon_device *rdev);
diff --git a/drivers/gpu/drm/radeon/radeon_asic.h b/drivers/gpu/drm/radeon/radeon_asic.h
index d3a157b..cb1afb2 100644
--- a/drivers/gpu/drm/radeon/radeon_asic.h
+++ b/drivers/gpu/drm/radeon/radeon_asic.h
@@ -52,6 +52,7 @@ extern int r100_resume(struct radeon_device *rdev);
 uint32_t r100_mm_rreg(struct radeon_device *rdev, uint32_t reg);
 void r100_mm_wreg(struct radeon_device *rdev, uint32_t reg, uint32_t v);
 void r100_vga_set_state(struct radeon_device *rdev, bool state);
+bool r100_gpu_is_lockup(struct radeon_device *rdev);
 int r100_gpu_reset(struct radeon_device *rdev);
 u32 r100_get_vblank_counter(struct radeon_device *rdev, int crtc);
 void r100_pci_gart_tlb_flush(struct radeon_device *rdev);
@@ -89,6 +90,7 @@ static struct radeon_asic r100_asic = {
 	.suspend = &r100_suspend,
 	.resume = &r100_resume,
 	.vga_set_state = &r100_vga_set_state,
+	.gpu_is_lockup = &r100_gpu_is_lockup,
 	.gpu_reset = &r100_gpu_reset,
 	.gart_tlb_flush = &r100_pci_gart_tlb_flush,
 	.gart_set_page = &r100_pci_gart_set_page,
@@ -135,6 +137,7 @@ static struct radeon_asic r200_asic = {
 	.suspend = &r100_suspend,
 	.resume = &r100_resume,
 	.vga_set_state = &r100_vga_set_state,
+	.gpu_is_lockup = &r100_gpu_is_lockup,
 	.gpu_reset = &r100_gpu_reset,
 	.gart_tlb_flush = &r100_pci_gart_tlb_flush,
 	.gart_set_page = &r100_pci_gart_set_page,
@@ -174,6 +177,7 @@ extern int r300_init(struct radeon_device *rdev);
 extern void r300_fini(struct radeon_device *rdev);
 extern int r300_suspend(struct radeon_device *rdev);
 extern int r300_resume(struct radeon_device *rdev);
+extern bool r300_gpu_is_lockup(struct radeon_device *rdev);
 extern int r300_gpu_reset(struct radeon_device *rdev);
 extern void r300_ring_start(struct radeon_device *rdev);
 extern void r300_fence_ring_emit(struct radeon_device *rdev,
@@ -192,6 +196,7 @@ static struct radeon_asic r300_asic = {
 	.suspend = &r300_suspend,
 	.resume = &r300_resume,
 	.vga_set_state = &r100_vga_set_state,
+	.gpu_is_lockup = &r300_gpu_is_lockup,
 	.gpu_reset = &r300_gpu_reset,
 	.gart_tlb_flush = &r100_pci_gart_tlb_flush,
 	.gart_set_page = &r100_pci_gart_set_page,
@@ -231,6 +236,7 @@ static struct radeon_asic r300_asic_pcie = {
 	.suspend = &r300_suspend,
 	.resume = &r300_resume,
 	.vga_set_state = &r100_vga_set_state,
+	.gpu_is_lockup = &r300_gpu_is_lockup,
 	.gpu_reset = &r300_gpu_reset,
 	.gart_tlb_flush = &rv370_pcie_gart_tlb_flush,
 	.gart_set_page = &rv370_pcie_gart_set_page,
@@ -275,6 +281,7 @@ static struct radeon_asic r420_asic = {
 	.suspend = &r420_suspend,
 	.resume = &r420_resume,
 	.vga_set_state = &r100_vga_set_state,
+	.gpu_is_lockup = &r300_gpu_is_lockup,
 	.gpu_reset = &r300_gpu_reset,
 	.gart_tlb_flush = &rv370_pcie_gart_tlb_flush,
 	.gart_set_page = &rv370_pcie_gart_set_page,
@@ -325,6 +332,7 @@ static struct radeon_asic rs400_asic = {
 	.suspend = &rs400_suspend,
 	.resume = &rs400_resume,
 	.vga_set_state = &r100_vga_set_state,
+	.gpu_is_lockup = &r300_gpu_is_lockup,
 	.gpu_reset = &r300_gpu_reset,
 	.gart_tlb_flush = &rs400_gart_tlb_flush,
 	.gart_set_page = &rs400_gart_set_page,
@@ -385,6 +393,7 @@ static struct radeon_asic rs600_asic = {
 	.suspend = &rs600_suspend,
 	.resume = &rs600_resume,
 	.vga_set_state = &r100_vga_set_state,
+	.gpu_is_lockup = &r300_gpu_is_lockup,
 	.gpu_reset = &r300_gpu_reset,
 	.gart_tlb_flush = &rs600_gart_tlb_flush,
 	.gart_set_page = &rs600_gart_set_page,
@@ -434,6 +443,7 @@ static struct radeon_asic rs690_asic = {
 	.suspend = &rs690_suspend,
 	.resume = &rs690_resume,
 	.vga_set_state = &r100_vga_set_state,
+	.gpu_is_lockup = &r300_gpu_is_lockup,
 	.gpu_reset = &r300_gpu_reset,
 	.gart_tlb_flush = &rs400_gart_tlb_flush,
 	.gart_set_page = &rs400_gart_set_page,
@@ -487,6 +497,7 @@ static struct radeon_asic rv515_asic = {
 	.suspend = &rv515_suspend,
 	.resume = &rv515_resume,
 	.vga_set_state = &r100_vga_set_state,
+	.gpu_is_lockup = &r300_gpu_is_lockup,
 	.gpu_reset = &rv515_gpu_reset,
 	.gart_tlb_flush = &rv370_pcie_gart_tlb_flush,
 	.gart_set_page = &rv370_pcie_gart_set_page,
@@ -531,6 +542,7 @@ static struct radeon_asic r520_asic = {
 	.suspend = &rv515_suspend,
 	.resume = &r520_resume,
 	.vga_set_state = &r100_vga_set_state,
+	.gpu_is_lockup = &r300_gpu_is_lockup,
 	.gpu_reset = &rv515_gpu_reset,
 	.gart_tlb_flush = &rv370_pcie_gart_tlb_flush,
 	.gart_set_page = &rv370_pcie_gart_set_page,
@@ -587,6 +599,7 @@ int r600_copy_dma(struct radeon_device *rdev,
 		  struct radeon_fence *fence);
 int r600_irq_process(struct radeon_device *rdev);
 int r600_irq_set(struct radeon_device *rdev);
+bool r600_gpu_is_lockup(struct radeon_device *rdev);
 int r600_gpu_reset(struct radeon_device *rdev);
 int r600_set_surface_reg(struct radeon_device *rdev, int reg,
 			 uint32_t tiling_flags, uint32_t pitch,
@@ -611,6 +624,7 @@ static struct radeon_asic r600_asic = {
 	.resume = &r600_resume,
 	.cp_commit = &r600_cp_commit,
 	.vga_set_state = &r600_vga_set_state,
+	.gpu_is_lockup = &r600_gpu_is_lockup,
 	.gpu_reset = &r600_gpu_reset,
 	.gart_tlb_flush = &r600_pcie_gart_tlb_flush,
 	.gart_set_page = &rs600_gart_set_page,
@@ -648,7 +662,6 @@ int rv770_init(struct radeon_device *rdev);
 void rv770_fini(struct radeon_device *rdev);
 int rv770_suspend(struct radeon_device *rdev);
 int rv770_resume(struct radeon_device *rdev);
-int rv770_gpu_reset(struct radeon_device *rdev);
 
 static struct radeon_asic rv770_asic = {
 	.init = &rv770_init,
@@ -656,7 +669,8 @@ static struct radeon_asic rv770_asic = {
 	.suspend = &rv770_suspend,
 	.resume = &rv770_resume,
 	.cp_commit = &r600_cp_commit,
-	.gpu_reset = &rv770_gpu_reset,
+	.gpu_is_lockup = &r600_gpu_is_lockup,
+	.gpu_reset = &r600_gpu_reset,
 	.vga_set_state = &r600_vga_set_state,
 	.gart_tlb_flush = &r600_pcie_gart_tlb_flush,
 	.gart_set_page = &rs600_gart_set_page,
@@ -694,6 +708,7 @@ int evergreen_init(struct radeon_device *rdev);
 void evergreen_fini(struct radeon_device *rdev);
 int evergreen_suspend(struct radeon_device *rdev);
 int evergreen_resume(struct radeon_device *rdev);
+bool evergreen_gpu_is_lockup(struct radeon_device *rdev);
 int evergreen_gpu_reset(struct radeon_device *rdev);
 void evergreen_bandwidth_update(struct radeon_device *rdev);
 void evergreen_hpd_init(struct radeon_device *rdev);
@@ -708,6 +723,7 @@ static struct radeon_asic evergreen_asic = {
 	.suspend = &evergreen_suspend,
 	.resume = &evergreen_resume,
 	.cp_commit = NULL,
+	.gpu_is_lockup = &evergreen_gpu_is_lockup,
 	.gpu_reset = &evergreen_gpu_reset,
 	.vga_set_state = &r600_vga_set_state,
 	.gart_tlb_flush = &r600_pcie_gart_tlb_flush,
diff --git a/drivers/gpu/drm/radeon/radeon_fence.c b/drivers/gpu/drm/radeon/radeon_fence.c
index 8495d4e..3931542 100644
--- a/drivers/gpu/drm/radeon/radeon_fence.c
+++ b/drivers/gpu/drm/radeon/radeon_fence.c
@@ -57,7 +57,6 @@ int radeon_fence_emit(struct radeon_device *rdev, struct radeon_fence *fence)
 		radeon_fence_ring_emit(rdev, fence);
 
 	fence->emited = true;
-	fence->timeout = jiffies + ((2000 * HZ) / 1000);
 	list_del(&fence->list);
 	list_add_tail(&fence->list, &rdev->fence_drv.emited);
 	write_unlock_irqrestore(&rdev->fence_drv.lock, irq_flags);
@@ -70,15 +69,34 @@ static bool radeon_fence_poll_locked(struct radeon_device *rdev)
 	struct list_head *i, *n;
 	uint32_t seq;
 	bool wake = false;
+	unsigned long cjiffies;
 
-	if (rdev == NULL) {
-		return true;
-	}
-	if (rdev->shutdown) {
-		return true;
-	}
 	seq = RREG32(rdev->fence_drv.scratch_reg);
-	rdev->fence_drv.last_seq = seq;
+	if (seq != rdev->fence_drv.last_seq) {
+		rdev->fence_drv.last_seq = seq;
+		rdev->fence_drv.last_jiffies = jiffies;
+		rdev->fence_drv.last_timeout = RADEON_FENCE_JIFFIES_TIMEOUT;
+	} else {
+		cjiffies = jiffies;
+		if (time_after(cjiffies, rdev->fence_drv.last_jiffies)) {
+			cjiffies -= rdev->fence_drv.last_jiffies;
+			if (time_after(rdev->fence_drv.last_timeout, cjiffies)) {
+				/* update the timeout */
+				rdev->fence_drv.last_timeout -= cjiffies;
+			} else {
+				/* the 500ms timeout is elapsed we should test
+				 * for GPU lockup
+				 */
+				rdev->fence_drv.last_timeout = 1;
+			}
+		} else {
+			/* wrap around update last jiffies, we will just wait
+			 * a little longer
+			 */
+			rdev->fence_drv.last_jiffies = cjiffies;
+		}
+		return false;
+	}
 	n = NULL;
 	list_for_each(i, &rdev->fence_drv.emited) {
 		fence = list_entry(i, struct radeon_fence, list);
@@ -170,9 +188,8 @@ bool radeon_fence_signaled(struct radeon_fence *fence)
 int radeon_fence_wait(struct radeon_fence *fence, bool intr)
 {
 	struct radeon_device *rdev;
-	unsigned long cur_jiffies;
-	unsigned long timeout;
-	bool expired = false;
+	unsigned long irq_flags, timeout;
+	u32 seq;
 	int r;
 
 	if (fence == NULL) {
@@ -183,14 +200,10 @@ int radeon_fence_wait(struct radeon_fence *fence, bool intr)
 	if (radeon_fence_signaled(fence)) {
 		return 0;
 	}
-
+	timeout = rdev->fence_drv.last_timeout;
 retry:
-	cur_jiffies = jiffies;
-	timeout = HZ / 100;
-	if (time_after(fence->timeout, cur_jiffies)) {
-		timeout = fence->timeout - cur_jiffies;
-	}
-
+	/* save current sequence used to check for GPU lockup */
+	seq = rdev->fence_drv.last_seq;
 	if (intr) {
 		radeon_irq_kms_sw_irq_get(rdev);
 		r = wait_event_interruptible_timeout(rdev->fence_drv.queue,
@@ -205,38 +218,34 @@ retry:
 		radeon_irq_kms_sw_irq_put(rdev);
 	}
 	if (unlikely(!radeon_fence_signaled(fence))) {
-		if (unlikely(r == 0)) {
-			expired = true;
+		/* we were interrupted for some reason and fence isn't
+		 * isn't signaled yet, resume wait
+		 */
+		if (r) {
+			timeout = r;
+			goto retry;
 		}
-		if (unlikely(expired)) {
-			timeout = 1;
-			if (time_after(cur_jiffies, fence->timeout)) {
-				timeout = cur_jiffies - fence->timeout;
-			}
-			timeout = jiffies_to_msecs(timeout);
-			if (timeout > 500) {
-				DRM_ERROR("fence(%p:0x%08X) %lums timeout "
-					  "going to reset GPU\n",
-					  fence, fence->seq, timeout);
-				radeon_gpu_reset(rdev);
-				WREG32(rdev->fence_drv.scratch_reg, fence->seq);
-			}
+		/* don't protect read access to rdev->fence_drv.last_seq
+		 * if we experiencing a lockup the value doesn't change
+		 */
+		if (seq == rdev->fence_drv.last_seq && radeon_gpu_is_lockup(rdev)) {
+			/* good news we believe it's a lockup */
+			dev_warn(rdev->dev, "GPU lockup (last fence id 0x%08X)\n", seq);
+			r = radeon_gpu_reset(rdev);
+			if (r)
+				return r;
+			/* FIXME: what should we do ? marking everyone
+			 * as signaled for now
+			 */
+			WREG32(rdev->fence_drv.scratch_reg, fence->seq);
 		}
+		timeout = RADEON_FENCE_JIFFIES_TIMEOUT;
+		write_lock_irqsave(&rdev->fence_drv.lock, irq_flags);
+		rdev->fence_drv.last_timeout = RADEON_FENCE_JIFFIES_TIMEOUT;
+		rdev->fence_drv.last_jiffies = jiffies;
+		write_unlock_irqrestore(&rdev->fence_drv.lock, irq_flags);
 		goto retry;
 	}
-	if (unlikely(expired)) {
-		rdev->fence_drv.count_timeout++;
-		cur_jiffies = jiffies;
-		timeout = 1;
-		if (time_after(cur_jiffies, fence->timeout)) {
-			timeout = cur_jiffies - fence->timeout;
-		}
-		timeout = jiffies_to_msecs(timeout);
-		DRM_ERROR("fence(%p:0x%08X) %lums timeout\n",
-			  fence, fence->seq, timeout);
-		DRM_ERROR("last signaled fence(0x%08X)\n",
-			  rdev->fence_drv.last_seq);
-	}
 	return 0;
 }
 
@@ -332,7 +341,6 @@ int radeon_fence_driver_init(struct radeon_device *rdev)
 	INIT_LIST_HEAD(&rdev->fence_drv.created);
 	INIT_LIST_HEAD(&rdev->fence_drv.emited);
 	INIT_LIST_HEAD(&rdev->fence_drv.signaled);
-	rdev->fence_drv.count_timeout = 0;
 	init_waitqueue_head(&rdev->fence_drv.queue);
 	rdev->fence_drv.initialized = true;
 	write_unlock_irqrestore(&rdev->fence_drv.lock, irq_flags);
diff --git a/drivers/gpu/drm/radeon/rv770.c b/drivers/gpu/drm/radeon/rv770.c
index 37887de..16c793b 100644
--- a/drivers/gpu/drm/radeon/rv770.c
+++ b/drivers/gpu/drm/radeon/rv770.c
@@ -917,12 +917,6 @@ int rv770_mc_init(struct radeon_device *rdev)
 	return 0;
 }
 
-int rv770_gpu_reset(struct radeon_device *rdev)
-{
-	/* FIXME: implement any rv770 specific bits */
-	return r600_gpu_reset(rdev);
-}
-
 static int rv770_startup(struct radeon_device *rdev)
 {
 	int r;
-- 
1.6.6.1


------------------------------------------------------------------------------
Download Intel&#174; Parallel Studio Eval
Try the new software tools for yourself. Speed compiling, find bugs
proactively, and fine-tune applications for parallel performance.
See why Intel Parallel Studio got high marks during beta.
http://p.sf.net/sfu/intel-sw-dev
--

^ permalink raw reply related	[flat|nested] 5+ messages in thread

* [PATCH 2/3] drm/radeon/kms: rename gpu_reset to asic_reset
  2010-03-09 14:45 ` [PATCH 1/3] drm/radeon/kms: fence cleanup + more reliable GPU lockup detection V4 Jerome Glisse
@ 2010-03-09 14:45   ` Jerome Glisse
  2010-03-09 14:45     ` [PATCH 3/3] drm/radeon/kms: simplify & improve GPU reset V2 Jerome Glisse
  2010-03-10 10:34   ` [PATCH 1/3] drm/radeon/kms: fence cleanup + more reliable GPU lockup detection V4 Pauli Nieminen
  1 sibling, 1 reply; 5+ messages in thread
From: Jerome Glisse @ 2010-03-09 14:45 UTC (permalink / raw)
  To: airlied; +Cc: Jerome Glisse, dri-devel

Patch rename gpu_reset to asic_reset in prevision of having
gpu_reset doing more stuff than just basic asic reset.

Signed-off-by: Jerome Glisse <jglisse@redhat.com>
---
 drivers/gpu/drm/radeon/evergreen.c     |    2 +-
 drivers/gpu/drm/radeon/r100.c          |    6 ++--
 drivers/gpu/drm/radeon/r300.c          |    6 ++--
 drivers/gpu/drm/radeon/r420.c          |    4 +-
 drivers/gpu/drm/radeon/r520.c          |    4 +-
 drivers/gpu/drm/radeon/r600.c          |    2 +-
 drivers/gpu/drm/radeon/radeon.h        |    6 ++--
 drivers/gpu/drm/radeon/radeon_asic.h   |   36 ++++++++++++++++----------------
 drivers/gpu/drm/radeon/radeon_device.c |    2 +-
 drivers/gpu/drm/radeon/radeon_fence.c  |    2 +-
 drivers/gpu/drm/radeon/rs400.c         |    4 +-
 drivers/gpu/drm/radeon/rs600.c         |    4 +-
 drivers/gpu/drm/radeon/rs690.c         |    4 +-
 drivers/gpu/drm/radeon/rv515.c         |    8 +++---
 14 files changed, 45 insertions(+), 45 deletions(-)

diff --git a/drivers/gpu/drm/radeon/evergreen.c b/drivers/gpu/drm/radeon/evergreen.c
index 8988df7..f1a860c 100644
--- a/drivers/gpu/drm/radeon/evergreen.c
+++ b/drivers/gpu/drm/radeon/evergreen.c
@@ -496,7 +496,7 @@ bool evergreen_gpu_is_lockup(struct radeon_device *rdev)
 	return false;
 }
 
-int evergreen_gpu_reset(struct radeon_device *rdev)
+int evergreen_asic_reset(struct radeon_device *rdev)
 {
 	/* FIXME: implement for evergreen */
 	return 0;
diff --git a/drivers/gpu/drm/radeon/r100.c b/drivers/gpu/drm/radeon/r100.c
index e4487f3..5594e71 100644
--- a/drivers/gpu/drm/radeon/r100.c
+++ b/drivers/gpu/drm/radeon/r100.c
@@ -1858,7 +1858,7 @@ bool r100_gpu_is_lockup(struct radeon_device *rdev)
 	return r100_gpu_cp_is_lockup(rdev, &rdev->config.r100.lockup, &rdev->cp);
 }
 
-int r100_gpu_reset(struct radeon_device *rdev)
+int r100_asic_reset(struct radeon_device *rdev)
 {
 	uint32_t status;
 
@@ -3500,7 +3500,7 @@ int r100_resume(struct radeon_device *rdev)
 	/* Resume clock before doing reset */
 	r100_clock_startup(rdev);
 	/* Reset gpu before posting otherwise ATOM will enter infinite loop */
-	if (radeon_gpu_reset(rdev)) {
+	if (radeon_asic_reset(rdev)) {
 		dev_warn(rdev->dev, "GPU reset failed ! (0xE40=0x%08X, 0x7C0=0x%08X)\n",
 			RREG32(R_000E40_RBBM_STATUS),
 			RREG32(R_0007C0_CP_STAT));
@@ -3568,7 +3568,7 @@ int r100_init(struct radeon_device *rdev)
 			return r;
 	}
 	/* Reset gpu before posting otherwise ATOM will enter infinite loop */
-	if (radeon_gpu_reset(rdev)) {
+	if (radeon_asic_reset(rdev)) {
 		dev_warn(rdev->dev,
 			"GPU reset failed ! (0xE40=0x%08X, 0x7C0=0x%08X)\n",
 			RREG32(R_000E40_RBBM_STATUS),
diff --git a/drivers/gpu/drm/radeon/r300.c b/drivers/gpu/drm/radeon/r300.c
index 23346f6..75ab7b0 100644
--- a/drivers/gpu/drm/radeon/r300.c
+++ b/drivers/gpu/drm/radeon/r300.c
@@ -447,7 +447,7 @@ bool r300_gpu_is_lockup(struct radeon_device *rdev)
 	return r100_gpu_cp_is_lockup(rdev, &rdev->config.r300.lockup, &rdev->cp);
 }
 
-int r300_gpu_reset(struct radeon_device *rdev)
+int r300_asic_reset(struct radeon_device *rdev)
 {
 	uint32_t status;
 
@@ -1330,7 +1330,7 @@ int r300_resume(struct radeon_device *rdev)
 	/* Resume clock before doing reset */
 	r300_clock_startup(rdev);
 	/* Reset gpu before posting otherwise ATOM will enter infinite loop */
-	if (radeon_gpu_reset(rdev)) {
+	if (radeon_asic_reset(rdev)) {
 		dev_warn(rdev->dev, "GPU reset failed ! (0xE40=0x%08X, 0x7C0=0x%08X)\n",
 			RREG32(R_000E40_RBBM_STATUS),
 			RREG32(R_0007C0_CP_STAT));
@@ -1400,7 +1400,7 @@ int r300_init(struct radeon_device *rdev)
 			return r;
 	}
 	/* Reset gpu before posting otherwise ATOM will enter infinite loop */
-	if (radeon_gpu_reset(rdev)) {
+	if (radeon_asic_reset(rdev)) {
 		dev_warn(rdev->dev,
 			"GPU reset failed ! (0xE40=0x%08X, 0x7C0=0x%08X)\n",
 			RREG32(R_000E40_RBBM_STATUS),
diff --git a/drivers/gpu/drm/radeon/r420.c b/drivers/gpu/drm/radeon/r420.c
index c7593b8..3221855 100644
--- a/drivers/gpu/drm/radeon/r420.c
+++ b/drivers/gpu/drm/radeon/r420.c
@@ -233,7 +233,7 @@ int r420_resume(struct radeon_device *rdev)
 	/* Resume clock before doing reset */
 	r420_clock_resume(rdev);
 	/* Reset gpu before posting otherwise ATOM will enter infinite loop */
-	if (radeon_gpu_reset(rdev)) {
+	if (radeon_asic_reset(rdev)) {
 		dev_warn(rdev->dev, "GPU reset failed ! (0xE40=0x%08X, 0x7C0=0x%08X)\n",
 			RREG32(R_000E40_RBBM_STATUS),
 			RREG32(R_0007C0_CP_STAT));
@@ -313,7 +313,7 @@ int r420_init(struct radeon_device *rdev)
 		}
 	}
 	/* Reset gpu before posting otherwise ATOM will enter infinite loop */
-	if (radeon_gpu_reset(rdev)) {
+	if (radeon_asic_reset(rdev)) {
 		dev_warn(rdev->dev,
 			"GPU reset failed ! (0xE40=0x%08X, 0x7C0=0x%08X)\n",
 			RREG32(R_000E40_RBBM_STATUS),
diff --git a/drivers/gpu/drm/radeon/r520.c b/drivers/gpu/drm/radeon/r520.c
index 2b8a5dd..99ef6dc 100644
--- a/drivers/gpu/drm/radeon/r520.c
+++ b/drivers/gpu/drm/radeon/r520.c
@@ -214,7 +214,7 @@ int r520_resume(struct radeon_device *rdev)
 	/* Resume clock before doing reset */
 	rv515_clock_startup(rdev);
 	/* Reset gpu before posting otherwise ATOM will enter infinite loop */
-	if (radeon_gpu_reset(rdev)) {
+	if (radeon_asic_reset(rdev)) {
 		dev_warn(rdev->dev, "GPU reset failed ! (0xE40=0x%08X, 0x7C0=0x%08X)\n",
 			RREG32(R_000E40_RBBM_STATUS),
 			RREG32(R_0007C0_CP_STAT));
@@ -251,7 +251,7 @@ int r520_init(struct radeon_device *rdev)
 		return -EINVAL;
 	}
 	/* Reset gpu before posting otherwise ATOM will enter infinite loop */
-	if (radeon_gpu_reset(rdev)) {
+	if (radeon_asic_reset(rdev)) {
 		dev_warn(rdev->dev,
 			"GPU reset failed ! (0xE40=0x%08X, 0x7C0=0x%08X)\n",
 			RREG32(R_000E40_RBBM_STATUS),
diff --git a/drivers/gpu/drm/radeon/r600.c b/drivers/gpu/drm/radeon/r600.c
index 4520685..ce59456 100644
--- a/drivers/gpu/drm/radeon/r600.c
+++ b/drivers/gpu/drm/radeon/r600.c
@@ -878,7 +878,7 @@ bool r600_gpu_is_lockup(struct radeon_device *rdev)
 	return r100_gpu_cp_is_lockup(rdev, &rdev->config.r300.lockup, &rdev->cp);
 }
 
-int r600_gpu_reset(struct radeon_device *rdev)
+int r600_asic_reset(struct radeon_device *rdev)
 {
 	return r600_gpu_soft_reset(rdev);
 }
diff --git a/drivers/gpu/drm/radeon/radeon.h b/drivers/gpu/drm/radeon/radeon.h
index e97a118..a2ded38 100644
--- a/drivers/gpu/drm/radeon/radeon.h
+++ b/drivers/gpu/drm/radeon/radeon.h
@@ -744,7 +744,7 @@ struct radeon_asic {
 	int (*suspend)(struct radeon_device *rdev);
 	void (*vga_set_state)(struct radeon_device *rdev, bool state);
 	bool (*gpu_is_lockup)(struct radeon_device *rdev);
-	int (*gpu_reset)(struct radeon_device *rdev);
+	int (*asic_reset)(struct radeon_device *rdev);
 	void (*gart_tlb_flush)(struct radeon_device *rdev);
 	int (*gart_set_page)(struct radeon_device *rdev, int i, uint64_t addr);
 	int (*cp_init)(struct radeon_device *rdev, unsigned ring_size);
@@ -1147,7 +1147,7 @@ static inline void radeon_ring_write(struct radeon_device *rdev, uint32_t v)
 #define radeon_cs_parse(p) rdev->asic->cs_parse((p))
 #define radeon_vga_set_state(rdev, state) (rdev)->asic->vga_set_state((rdev), (state))
 #define radeon_gpu_is_lockup(rdev) (rdev)->asic->gpu_is_lockup((rdev))
-#define radeon_gpu_reset(rdev) (rdev)->asic->gpu_reset((rdev))
+#define radeon_asic_reset(rdev) (rdev)->asic->asic_reset((rdev))
 #define radeon_gart_tlb_flush(rdev) (rdev)->asic->gart_tlb_flush((rdev))
 #define radeon_gart_set_page(rdev, i, p) (rdev)->asic->gart_set_page((rdev), (i), (p))
 #define radeon_cp_commit(rdev) (rdev)->asic->cp_commit((rdev))
@@ -1323,7 +1323,7 @@ extern void r600_scratch_init(struct radeon_device *rdev);
 extern int r600_blit_init(struct radeon_device *rdev);
 extern void r600_blit_fini(struct radeon_device *rdev);
 extern int r600_init_microcode(struct radeon_device *rdev);
-extern int r600_gpu_reset(struct radeon_device *rdev);
+extern int r600_asic_reset(struct radeon_device *rdev);
 /* r600 irq */
 extern int r600_irq_init(struct radeon_device *rdev);
 extern void r600_irq_fini(struct radeon_device *rdev);
diff --git a/drivers/gpu/drm/radeon/radeon_asic.h b/drivers/gpu/drm/radeon/radeon_asic.h
index cb1afb2..8a9660d 100644
--- a/drivers/gpu/drm/radeon/radeon_asic.h
+++ b/drivers/gpu/drm/radeon/radeon_asic.h
@@ -53,7 +53,7 @@ uint32_t r100_mm_rreg(struct radeon_device *rdev, uint32_t reg);
 void r100_mm_wreg(struct radeon_device *rdev, uint32_t reg, uint32_t v);
 void r100_vga_set_state(struct radeon_device *rdev, bool state);
 bool r100_gpu_is_lockup(struct radeon_device *rdev);
-int r100_gpu_reset(struct radeon_device *rdev);
+int r100_asic_reset(struct radeon_device *rdev);
 u32 r100_get_vblank_counter(struct radeon_device *rdev, int crtc);
 void r100_pci_gart_tlb_flush(struct radeon_device *rdev);
 int r100_pci_gart_set_page(struct radeon_device *rdev, int i, uint64_t addr);
@@ -91,7 +91,7 @@ static struct radeon_asic r100_asic = {
 	.resume = &r100_resume,
 	.vga_set_state = &r100_vga_set_state,
 	.gpu_is_lockup = &r100_gpu_is_lockup,
-	.gpu_reset = &r100_gpu_reset,
+	.asic_reset = &r100_asic_reset,
 	.gart_tlb_flush = &r100_pci_gart_tlb_flush,
 	.gart_set_page = &r100_pci_gart_set_page,
 	.cp_commit = &r100_cp_commit,
@@ -138,7 +138,7 @@ static struct radeon_asic r200_asic = {
 	.resume = &r100_resume,
 	.vga_set_state = &r100_vga_set_state,
 	.gpu_is_lockup = &r100_gpu_is_lockup,
-	.gpu_reset = &r100_gpu_reset,
+	.asic_reset = &r100_asic_reset,
 	.gart_tlb_flush = &r100_pci_gart_tlb_flush,
 	.gart_set_page = &r100_pci_gart_set_page,
 	.cp_commit = &r100_cp_commit,
@@ -178,7 +178,7 @@ extern void r300_fini(struct radeon_device *rdev);
 extern int r300_suspend(struct radeon_device *rdev);
 extern int r300_resume(struct radeon_device *rdev);
 extern bool r300_gpu_is_lockup(struct radeon_device *rdev);
-extern int r300_gpu_reset(struct radeon_device *rdev);
+extern int r300_asic_reset(struct radeon_device *rdev);
 extern void r300_ring_start(struct radeon_device *rdev);
 extern void r300_fence_ring_emit(struct radeon_device *rdev,
 				struct radeon_fence *fence);
@@ -197,7 +197,7 @@ static struct radeon_asic r300_asic = {
 	.resume = &r300_resume,
 	.vga_set_state = &r100_vga_set_state,
 	.gpu_is_lockup = &r300_gpu_is_lockup,
-	.gpu_reset = &r300_gpu_reset,
+	.asic_reset = &r300_asic_reset,
 	.gart_tlb_flush = &r100_pci_gart_tlb_flush,
 	.gart_set_page = &r100_pci_gart_set_page,
 	.cp_commit = &r100_cp_commit,
@@ -237,7 +237,7 @@ static struct radeon_asic r300_asic_pcie = {
 	.resume = &r300_resume,
 	.vga_set_state = &r100_vga_set_state,
 	.gpu_is_lockup = &r300_gpu_is_lockup,
-	.gpu_reset = &r300_gpu_reset,
+	.asic_reset = &r300_asic_reset,
 	.gart_tlb_flush = &rv370_pcie_gart_tlb_flush,
 	.gart_set_page = &rv370_pcie_gart_set_page,
 	.cp_commit = &r100_cp_commit,
@@ -282,7 +282,7 @@ static struct radeon_asic r420_asic = {
 	.resume = &r420_resume,
 	.vga_set_state = &r100_vga_set_state,
 	.gpu_is_lockup = &r300_gpu_is_lockup,
-	.gpu_reset = &r300_gpu_reset,
+	.asic_reset = &r300_asic_reset,
 	.gart_tlb_flush = &rv370_pcie_gart_tlb_flush,
 	.gart_set_page = &rv370_pcie_gart_set_page,
 	.cp_commit = &r100_cp_commit,
@@ -333,7 +333,7 @@ static struct radeon_asic rs400_asic = {
 	.resume = &rs400_resume,
 	.vga_set_state = &r100_vga_set_state,
 	.gpu_is_lockup = &r300_gpu_is_lockup,
-	.gpu_reset = &r300_gpu_reset,
+	.asic_reset = &r300_asic_reset,
 	.gart_tlb_flush = &rs400_gart_tlb_flush,
 	.gart_set_page = &rs400_gart_set_page,
 	.cp_commit = &r100_cp_commit,
@@ -394,7 +394,7 @@ static struct radeon_asic rs600_asic = {
 	.resume = &rs600_resume,
 	.vga_set_state = &r100_vga_set_state,
 	.gpu_is_lockup = &r300_gpu_is_lockup,
-	.gpu_reset = &r300_gpu_reset,
+	.asic_reset = &r300_asic_reset,
 	.gart_tlb_flush = &rs600_gart_tlb_flush,
 	.gart_set_page = &rs600_gart_set_page,
 	.cp_commit = &r100_cp_commit,
@@ -444,7 +444,7 @@ static struct radeon_asic rs690_asic = {
 	.resume = &rs690_resume,
 	.vga_set_state = &r100_vga_set_state,
 	.gpu_is_lockup = &r300_gpu_is_lockup,
-	.gpu_reset = &r300_gpu_reset,
+	.asic_reset = &r300_asic_reset,
 	.gart_tlb_flush = &rs400_gart_tlb_flush,
 	.gart_set_page = &rs400_gart_set_page,
 	.cp_commit = &r100_cp_commit,
@@ -482,7 +482,7 @@ static struct radeon_asic rs690_asic = {
  */
 int rv515_init(struct radeon_device *rdev);
 void rv515_fini(struct radeon_device *rdev);
-int rv515_gpu_reset(struct radeon_device *rdev);
+int rv515_asic_reset(struct radeon_device *rdev);
 uint32_t rv515_mc_rreg(struct radeon_device *rdev, uint32_t reg);
 void rv515_mc_wreg(struct radeon_device *rdev, uint32_t reg, uint32_t v);
 void rv515_ring_start(struct radeon_device *rdev);
@@ -498,7 +498,7 @@ static struct radeon_asic rv515_asic = {
 	.resume = &rv515_resume,
 	.vga_set_state = &r100_vga_set_state,
 	.gpu_is_lockup = &r300_gpu_is_lockup,
-	.gpu_reset = &rv515_gpu_reset,
+	.asic_reset = &rv515_asic_reset,
 	.gart_tlb_flush = &rv370_pcie_gart_tlb_flush,
 	.gart_set_page = &rv370_pcie_gart_set_page,
 	.cp_commit = &r100_cp_commit,
@@ -543,7 +543,7 @@ static struct radeon_asic r520_asic = {
 	.resume = &r520_resume,
 	.vga_set_state = &r100_vga_set_state,
 	.gpu_is_lockup = &r300_gpu_is_lockup,
-	.gpu_reset = &rv515_gpu_reset,
+	.asic_reset = &rv515_asic_reset,
 	.gart_tlb_flush = &rv370_pcie_gart_tlb_flush,
 	.gart_set_page = &rv370_pcie_gart_set_page,
 	.cp_commit = &r100_cp_commit,
@@ -600,7 +600,7 @@ int r600_copy_dma(struct radeon_device *rdev,
 int r600_irq_process(struct radeon_device *rdev);
 int r600_irq_set(struct radeon_device *rdev);
 bool r600_gpu_is_lockup(struct radeon_device *rdev);
-int r600_gpu_reset(struct radeon_device *rdev);
+int r600_asic_reset(struct radeon_device *rdev);
 int r600_set_surface_reg(struct radeon_device *rdev, int reg,
 			 uint32_t tiling_flags, uint32_t pitch,
 			 uint32_t offset, uint32_t obj_size);
@@ -625,7 +625,7 @@ static struct radeon_asic r600_asic = {
 	.cp_commit = &r600_cp_commit,
 	.vga_set_state = &r600_vga_set_state,
 	.gpu_is_lockup = &r600_gpu_is_lockup,
-	.gpu_reset = &r600_gpu_reset,
+	.asic_reset = &r600_asic_reset,
 	.gart_tlb_flush = &r600_pcie_gart_tlb_flush,
 	.gart_set_page = &rs600_gart_set_page,
 	.ring_test = &r600_ring_test,
@@ -670,7 +670,7 @@ static struct radeon_asic rv770_asic = {
 	.resume = &rv770_resume,
 	.cp_commit = &r600_cp_commit,
 	.gpu_is_lockup = &r600_gpu_is_lockup,
-	.gpu_reset = &r600_gpu_reset,
+	.asic_reset = &r600_asic_reset,
 	.vga_set_state = &r600_vga_set_state,
 	.gart_tlb_flush = &r600_pcie_gart_tlb_flush,
 	.gart_set_page = &rs600_gart_set_page,
@@ -709,7 +709,7 @@ void evergreen_fini(struct radeon_device *rdev);
 int evergreen_suspend(struct radeon_device *rdev);
 int evergreen_resume(struct radeon_device *rdev);
 bool evergreen_gpu_is_lockup(struct radeon_device *rdev);
-int evergreen_gpu_reset(struct radeon_device *rdev);
+int evergreen_asic_reset(struct radeon_device *rdev);
 void evergreen_bandwidth_update(struct radeon_device *rdev);
 void evergreen_hpd_init(struct radeon_device *rdev);
 void evergreen_hpd_fini(struct radeon_device *rdev);
@@ -724,7 +724,7 @@ static struct radeon_asic evergreen_asic = {
 	.resume = &evergreen_resume,
 	.cp_commit = NULL,
 	.gpu_is_lockup = &evergreen_gpu_is_lockup,
-	.gpu_reset = &evergreen_gpu_reset,
+	.asic_reset = &evergreen_asic_reset,
 	.vga_set_state = &r600_vga_set_state,
 	.gart_tlb_flush = &r600_pcie_gart_tlb_flush,
 	.gart_set_page = &rs600_gart_set_page,
diff --git a/drivers/gpu/drm/radeon/radeon_device.c b/drivers/gpu/drm/radeon/radeon_device.c
index e28e4ed..54fa444 100644
--- a/drivers/gpu/drm/radeon/radeon_device.c
+++ b/drivers/gpu/drm/radeon/radeon_device.c
@@ -780,7 +780,7 @@ int radeon_device_init(struct radeon_device *rdev,
 		/* Acceleration not working on AGP card try again
 		 * with fallback to PCI or PCIE GART
 		 */
-		radeon_gpu_reset(rdev);
+		radeon_asic_reset(rdev);
 		radeon_fini(rdev);
 		radeon_agp_disable(rdev);
 		r = radeon_init(rdev);
diff --git a/drivers/gpu/drm/radeon/radeon_fence.c b/drivers/gpu/drm/radeon/radeon_fence.c
index 3931542..2560740 100644
--- a/drivers/gpu/drm/radeon/radeon_fence.c
+++ b/drivers/gpu/drm/radeon/radeon_fence.c
@@ -231,7 +231,7 @@ retry:
 		if (seq == rdev->fence_drv.last_seq && radeon_gpu_is_lockup(rdev)) {
 			/* good news we believe it's a lockup */
 			dev_warn(rdev->dev, "GPU lockup (last fence id 0x%08X)\n", seq);
-			r = radeon_gpu_reset(rdev);
+			r = radeon_asic_reset(rdev);
 			if (r)
 				return r;
 			/* FIXME: what should we do ? marking everyone
diff --git a/drivers/gpu/drm/radeon/rs400.c b/drivers/gpu/drm/radeon/rs400.c
index 626d518..1eaa11b 100644
--- a/drivers/gpu/drm/radeon/rs400.c
+++ b/drivers/gpu/drm/radeon/rs400.c
@@ -428,7 +428,7 @@ int rs400_resume(struct radeon_device *rdev)
 	/* setup MC before calling post tables */
 	rs400_mc_program(rdev);
 	/* Reset gpu before posting otherwise ATOM will enter infinite loop */
-	if (radeon_gpu_reset(rdev)) {
+	if (radeon_asic_reset(rdev)) {
 		dev_warn(rdev->dev, "GPU reset failed ! (0xE40=0x%08X, 0x7C0=0x%08X)\n",
 			RREG32(R_000E40_RBBM_STATUS),
 			RREG32(R_0007C0_CP_STAT));
@@ -491,7 +491,7 @@ int rs400_init(struct radeon_device *rdev)
 			return r;
 	}
 	/* Reset gpu before posting otherwise ATOM will enter infinite loop */
-	if (radeon_gpu_reset(rdev)) {
+	if (radeon_asic_reset(rdev)) {
 		dev_warn(rdev->dev,
 			"GPU reset failed ! (0xE40=0x%08X, 0x7C0=0x%08X)\n",
 			RREG32(R_000E40_RBBM_STATUS),
diff --git a/drivers/gpu/drm/radeon/rs600.c b/drivers/gpu/drm/radeon/rs600.c
index 47f046b..d10640d 100644
--- a/drivers/gpu/drm/radeon/rs600.c
+++ b/drivers/gpu/drm/radeon/rs600.c
@@ -573,7 +573,7 @@ int rs600_resume(struct radeon_device *rdev)
 	/* Resume clock before doing reset */
 	rv515_clock_startup(rdev);
 	/* Reset gpu before posting otherwise ATOM will enter infinite loop */
-	if (radeon_gpu_reset(rdev)) {
+	if (radeon_asic_reset(rdev)) {
 		dev_warn(rdev->dev, "GPU reset failed ! (0xE40=0x%08X, 0x7C0=0x%08X)\n",
 			RREG32(R_000E40_RBBM_STATUS),
 			RREG32(R_0007C0_CP_STAT));
@@ -635,7 +635,7 @@ int rs600_init(struct radeon_device *rdev)
 		return -EINVAL;
 	}
 	/* Reset gpu before posting otherwise ATOM will enter infinite loop */
-	if (radeon_gpu_reset(rdev)) {
+	if (radeon_asic_reset(rdev)) {
 		dev_warn(rdev->dev,
 			"GPU reset failed ! (0xE40=0x%08X, 0x7C0=0x%08X)\n",
 			RREG32(R_000E40_RBBM_STATUS),
diff --git a/drivers/gpu/drm/radeon/rs690.c b/drivers/gpu/drm/radeon/rs690.c
index 83b9174..acd2d8f 100644
--- a/drivers/gpu/drm/radeon/rs690.c
+++ b/drivers/gpu/drm/radeon/rs690.c
@@ -632,7 +632,7 @@ int rs690_resume(struct radeon_device *rdev)
 	/* Resume clock before doing reset */
 	rv515_clock_startup(rdev);
 	/* Reset gpu before posting otherwise ATOM will enter infinite loop */
-	if (radeon_gpu_reset(rdev)) {
+	if (radeon_asic_reset(rdev)) {
 		dev_warn(rdev->dev, "GPU reset failed ! (0xE40=0x%08X, 0x7C0=0x%08X)\n",
 			RREG32(R_000E40_RBBM_STATUS),
 			RREG32(R_0007C0_CP_STAT));
@@ -695,7 +695,7 @@ int rs690_init(struct radeon_device *rdev)
 		return -EINVAL;
 	}
 	/* Reset gpu before posting otherwise ATOM will enter infinite loop */
-	if (radeon_gpu_reset(rdev)) {
+	if (radeon_asic_reset(rdev)) {
 		dev_warn(rdev->dev,
 			"GPU reset failed ! (0xE40=0x%08X, 0x7C0=0x%08X)\n",
 			RREG32(R_000E40_RBBM_STATUS),
diff --git a/drivers/gpu/drm/radeon/rv515.c b/drivers/gpu/drm/radeon/rv515.c
index bea747d..6b3a697 100644
--- a/drivers/gpu/drm/radeon/rv515.c
+++ b/drivers/gpu/drm/radeon/rv515.c
@@ -226,7 +226,7 @@ int rv515_ga_reset(struct radeon_device *rdev)
 	return -1;
 }
 
-int rv515_gpu_reset(struct radeon_device *rdev)
+int rv515_asic_reset(struct radeon_device *rdev)
 {
 	uint32_t status;
 
@@ -339,7 +339,7 @@ static int rv515_debugfs_ga_info(struct seq_file *m, void *data)
 
 	tmp = RREG32(0x2140);
 	seq_printf(m, "VAP_CNTL_STATUS 0x%08x\n", tmp);
-	radeon_gpu_reset(rdev);
+	radeon_asic_reset(rdev);
 	tmp = RREG32(0x425C);
 	seq_printf(m, "GA_IDLE 0x%08x\n", tmp);
 	return 0;
@@ -507,7 +507,7 @@ int rv515_resume(struct radeon_device *rdev)
 	/* Resume clock before doing reset */
 	rv515_clock_startup(rdev);
 	/* Reset gpu before posting otherwise ATOM will enter infinite loop */
-	if (radeon_gpu_reset(rdev)) {
+	if (radeon_asic_reset(rdev)) {
 		dev_warn(rdev->dev, "GPU reset failed ! (0xE40=0x%08X, 0x7C0=0x%08X)\n",
 			RREG32(R_000E40_RBBM_STATUS),
 			RREG32(R_0007C0_CP_STAT));
@@ -576,7 +576,7 @@ int rv515_init(struct radeon_device *rdev)
 		return -EINVAL;
 	}
 	/* Reset gpu before posting otherwise ATOM will enter infinite loop */
-	if (radeon_gpu_reset(rdev)) {
+	if (radeon_asic_reset(rdev)) {
 		dev_warn(rdev->dev,
 			"GPU reset failed ! (0xE40=0x%08X, 0x7C0=0x%08X)\n",
 			RREG32(R_000E40_RBBM_STATUS),
-- 
1.6.6.1


------------------------------------------------------------------------------
Download Intel&#174; Parallel Studio Eval
Try the new software tools for yourself. Speed compiling, find bugs
proactively, and fine-tune applications for parallel performance.
See why Intel Parallel Studio got high marks during beta.
http://p.sf.net/sfu/intel-sw-dev
--

^ permalink raw reply related	[flat|nested] 5+ messages in thread

* [PATCH 3/3] drm/radeon/kms: simplify & improve GPU reset V2
  2010-03-09 14:45   ` [PATCH 2/3] drm/radeon/kms: rename gpu_reset to asic_reset Jerome Glisse
@ 2010-03-09 14:45     ` Jerome Glisse
  0 siblings, 0 replies; 5+ messages in thread
From: Jerome Glisse @ 2010-03-09 14:45 UTC (permalink / raw)
  To: airlied; +Cc: Jerome Glisse, dri-devel

This simplify and improve GPU reset for R1XX-R6XX hw, it's
not 100% reliable here are result:
- R1XX/R2XX works bunch of time in a row, sometimes it
  seems it can work indifinitly
- R3XX/R3XX the most unreliable one, sometimes you will be
  able to reset few times, sometimes not even once
- R5XX more reliable than previous hw, seems to work most
  of the times but once in a while it fails for no obvious
  reasons (same status than previous reset just no same
  happy ending)
- R6XX/R7XX are lot more reliable with this patch, still
  it seems that it can fail after a bunch (reset every
  2sec for 3hour bring down the GPU & computer)

This have been tested on various hw, for some odd reasons
i wasn't able to lockup RS480/RS690 (while they use to
love locking up).

Note that on R1XX-R5XX the cursor will disapear after
lockup haven't checked why, switch to console and back
to X will restore cursor.

Next step is to record the bogus command that leaded to
the lockup.

V2 Fix r6xx resume path to avoid reinitializing blit
module, use the gpu_lockup boolean to avoid entering
inifinite waiting loop on fence while reiniting the GPU

Signed-off-by: Jerome Glisse <jglisse@redhat.com>
---
 drivers/gpu/drm/radeon/r100.c          |  180 +++++++++++--------------------
 drivers/gpu/drm/radeon/r100d.h         |  128 ++++++++++++++++++++++
 drivers/gpu/drm/radeon/r300.c          |  134 +++++++++++-------------
 drivers/gpu/drm/radeon/r300d.h         |   47 ++++++++-
 drivers/gpu/drm/radeon/r520.c          |    1 -
 drivers/gpu/drm/radeon/r600.c          |   53 +---------
 drivers/gpu/drm/radeon/r600_blit_kms.c |    3 +
 drivers/gpu/drm/radeon/radeon.h        |    4 +-
 drivers/gpu/drm/radeon/radeon_asic.h   |   12 +-
 drivers/gpu/drm/radeon/radeon_cs.c     |    4 -
 drivers/gpu/drm/radeon/radeon_device.c |   22 ++++
 drivers/gpu/drm/radeon/radeon_fence.c  |   13 ++-
 drivers/gpu/drm/radeon/radeon_gart.c   |    2 +-
 drivers/gpu/drm/radeon/rs400.c         |    2 -
 drivers/gpu/drm/radeon/rs600.c         |   73 +++++++++++++-
 drivers/gpu/drm/radeon/rs600d.h        |   46 ++++++++
 drivers/gpu/drm/radeon/rs690.c         |    2 -
 drivers/gpu/drm/radeon/rv515.c         |   90 ----------------
 drivers/gpu/drm/radeon/rv515d.h        |   46 ++++++++
 19 files changed, 508 insertions(+), 354 deletions(-)

diff --git a/drivers/gpu/drm/radeon/r100.c b/drivers/gpu/drm/radeon/r100.c
index 5594e71..a57939a 100644
--- a/drivers/gpu/drm/radeon/r100.c
+++ b/drivers/gpu/drm/radeon/r100.c
@@ -659,26 +659,6 @@ int r100_cp_init(struct radeon_device *rdev, unsigned ring_size)
 	if (r100_debugfs_cp_init(rdev)) {
 		DRM_ERROR("Failed to register debugfs file for CP !\n");
 	}
-	/* Reset CP */
-	tmp = RREG32(RADEON_CP_CSQ_STAT);
-	if ((tmp & (1 << 31))) {
-		DRM_INFO("radeon: cp busy (0x%08X) resetting\n", tmp);
-		WREG32(RADEON_CP_CSQ_MODE, 0);
-		WREG32(RADEON_CP_CSQ_CNTL, 0);
-		WREG32(RADEON_RBBM_SOFT_RESET, RADEON_SOFT_RESET_CP);
-		tmp = RREG32(RADEON_RBBM_SOFT_RESET);
-		mdelay(2);
-		WREG32(RADEON_RBBM_SOFT_RESET, 0);
-		tmp = RREG32(RADEON_RBBM_SOFT_RESET);
-		mdelay(2);
-		tmp = RREG32(RADEON_CP_CSQ_STAT);
-		if ((tmp & (1 << 31))) {
-			DRM_INFO("radeon: cp reset failed (0x%08X)\n", tmp);
-		}
-	} else {
-		DRM_INFO("radeon: cp idle (0x%08X)\n", tmp);
-	}
-
 	if (!rdev->me_fw) {
 		r = r100_cp_init_microcode(rdev);
 		if (r) {
@@ -781,39 +761,6 @@ void r100_cp_disable(struct radeon_device *rdev)
 	}
 }
 
-int r100_cp_reset(struct radeon_device *rdev)
-{
-	uint32_t tmp;
-	bool reinit_cp;
-	int i;
-
-	reinit_cp = rdev->cp.ready;
-	rdev->cp.ready = false;
-	WREG32(RADEON_CP_CSQ_MODE, 0);
-	WREG32(RADEON_CP_CSQ_CNTL, 0);
-	WREG32(RADEON_RBBM_SOFT_RESET, RADEON_SOFT_RESET_CP);
-	(void)RREG32(RADEON_RBBM_SOFT_RESET);
-	udelay(200);
-	WREG32(RADEON_RBBM_SOFT_RESET, 0);
-	/* Wait to prevent race in RBBM_STATUS */
-	mdelay(1);
-	for (i = 0; i < rdev->usec_timeout; i++) {
-		tmp = RREG32(RADEON_RBBM_STATUS);
-		if (!(tmp & (1 << 16))) {
-			DRM_INFO("CP reset succeed (RBBM_STATUS=0x%08X)\n",
-				 tmp);
-			if (reinit_cp) {
-				return r100_cp_init(rdev, rdev->cp.ring_size);
-			}
-			return 0;
-		}
-		DRM_UDELAY(1);
-	}
-	tmp = RREG32(RADEON_RBBM_STATUS);
-	DRM_ERROR("Failed to reset CP (RBBM_STATUS=0x%08X)!\n", tmp);
-	return -1;
-}
-
 void r100_cp_commit(struct radeon_device *rdev)
 {
 	WREG32(RADEON_CP_RB_WPTR, rdev->cp.wptr);
@@ -1727,51 +1674,6 @@ int r100_mc_wait_for_idle(struct radeon_device *rdev)
 	return -1;
 }
 
-void r100_gpu_init(struct radeon_device *rdev)
-{
-	/* TODO: anythings to do here ? pipes ? */
-	r100_hdp_reset(rdev);
-}
-
-void r100_hdp_reset(struct radeon_device *rdev)
-{
-	uint32_t tmp;
-
-	tmp = RREG32(RADEON_HOST_PATH_CNTL) & RADEON_HDP_APER_CNTL;
-	tmp |= (7 << 28);
-	WREG32(RADEON_HOST_PATH_CNTL, tmp | RADEON_HDP_SOFT_RESET | RADEON_HDP_READ_BUFFER_INVALIDATE);
-	(void)RREG32(RADEON_HOST_PATH_CNTL);
-	udelay(200);
-	WREG32(RADEON_RBBM_SOFT_RESET, 0);
-	WREG32(RADEON_HOST_PATH_CNTL, tmp);
-	(void)RREG32(RADEON_HOST_PATH_CNTL);
-}
-
-int r100_rb2d_reset(struct radeon_device *rdev)
-{
-	uint32_t tmp;
-	int i;
-
-	WREG32(RADEON_RBBM_SOFT_RESET, RADEON_SOFT_RESET_E2);
-	(void)RREG32(RADEON_RBBM_SOFT_RESET);
-	udelay(200);
-	WREG32(RADEON_RBBM_SOFT_RESET, 0);
-	/* Wait to prevent race in RBBM_STATUS */
-	mdelay(1);
-	for (i = 0; i < rdev->usec_timeout; i++) {
-		tmp = RREG32(RADEON_RBBM_STATUS);
-		if (!(tmp & (1 << 26))) {
-			DRM_INFO("RB2D reset succeed (RBBM_STATUS=0x%08X)\n",
-				 tmp);
-			return 0;
-		}
-		DRM_UDELAY(1);
-	}
-	tmp = RREG32(RADEON_RBBM_STATUS);
-	DRM_ERROR("Failed to reset RB2D (RBBM_STATUS=0x%08X)!\n", tmp);
-	return -1;
-}
-
 void r100_gpu_lockup_update(struct r100_gpu_lockup *lockup, struct radeon_cp *cp)
 {
 	lockup->last_cp_rptr = cp->rptr;
@@ -1858,31 +1760,77 @@ bool r100_gpu_is_lockup(struct radeon_device *rdev)
 	return r100_gpu_cp_is_lockup(rdev, &rdev->config.r100.lockup, &rdev->cp);
 }
 
+void r100_bm_disable(struct radeon_device *rdev)
+{
+	u32 tmp;
+
+	/* disable bus mastering */
+	tmp = RREG32(R_000030_BUS_CNTL);
+	WREG32(R_000030_BUS_CNTL, (tmp & 0xFFFFFFFF) | 0x00000044);
+	mdelay(1);
+	WREG32(R_000030_BUS_CNTL, (tmp & 0xFFFFFFFF) | 0x00000042);
+	mdelay(1);
+	WREG32(R_000030_BUS_CNTL, (tmp & 0xFFFFFFFF) | 0x00000040);
+	tmp = RREG32(RADEON_BUS_CNTL);
+	mdelay(1);
+	pci_read_config_word(rdev->pdev, 0x4, (u16*)&tmp);
+	pci_write_config_word(rdev->pdev, 0x4, tmp & 0xFFFB);
+	mdelay(1);
+}
+
 int r100_asic_reset(struct radeon_device *rdev)
 {
-	uint32_t status;
+	struct r100_mc_save save;
+	u32 status, tmp;
 
-	/* reset order likely matter */
-	status = RREG32(RADEON_RBBM_STATUS);
-	/* reset HDP */
-	r100_hdp_reset(rdev);
-	/* reset rb2d */
-	if (status & ((1 << 17) | (1 << 18) | (1 << 27))) {
-		r100_rb2d_reset(rdev);
+	r100_mc_stop(rdev, &save);
+	status = RREG32(R_000E40_RBBM_STATUS);
+	if (!G_000E40_GUI_ACTIVE(status)) {
+		return 0;
 	}
-	/* TODO: reset 3D engine */
+	status = RREG32(R_000E40_RBBM_STATUS);
+	dev_info(rdev->dev, "(%s:%d) RBBM_STATUS=0x%08X\n", __func__, __LINE__, status);
+	/* stop CP */
+	WREG32(RADEON_CP_CSQ_CNTL, 0);
+	tmp = RREG32(RADEON_CP_RB_CNTL);
+	WREG32(RADEON_CP_RB_CNTL, tmp | RADEON_RB_RPTR_WR_ENA);
+	WREG32(RADEON_CP_RB_RPTR_WR, 0);
+	WREG32(RADEON_CP_RB_WPTR, 0);
+	WREG32(RADEON_CP_RB_CNTL, tmp);
+	/* save PCI state */
+	pci_save_state(rdev->pdev);
+	/* disable bus mastering */
+	r100_bm_disable(rdev);
+	WREG32(R_0000F0_RBBM_SOFT_RESET, S_0000F0_SOFT_RESET_SE(1) |
+					S_0000F0_SOFT_RESET_RE(1) |
+					S_0000F0_SOFT_RESET_PP(1) |
+					S_0000F0_SOFT_RESET_RB(1));
+	RREG32(R_0000F0_RBBM_SOFT_RESET);
+	mdelay(500);
+	WREG32(R_0000F0_RBBM_SOFT_RESET, 0);
+	mdelay(1);
+	status = RREG32(R_000E40_RBBM_STATUS);
+	dev_info(rdev->dev, "(%s:%d) RBBM_STATUS=0x%08X\n", __func__, __LINE__, status);
 	/* reset CP */
-	status = RREG32(RADEON_RBBM_STATUS);
-	if (status & (1 << 16)) {
-		r100_cp_reset(rdev);
-	}
+	WREG32(R_0000F0_RBBM_SOFT_RESET, S_0000F0_SOFT_RESET_CP(1));
+	RREG32(R_0000F0_RBBM_SOFT_RESET);
+	mdelay(500);
+	WREG32(R_0000F0_RBBM_SOFT_RESET, 0);
+	mdelay(1);
+	status = RREG32(R_000E40_RBBM_STATUS);
+	dev_info(rdev->dev, "(%s:%d) RBBM_STATUS=0x%08X\n", __func__, __LINE__, status);
+	/* restore PCI & busmastering */
+	pci_restore_state(rdev->pdev);
+	r100_enable_bm(rdev);
 	/* Check if GPU is idle */
-	status = RREG32(RADEON_RBBM_STATUS);
-	if (status & RADEON_RBBM_ACTIVE) {
-		DRM_ERROR("Failed to reset GPU (RBBM_STATUS=0x%08X)\n", status);
+	if (G_000E40_SE_BUSY(status) || G_000E40_RE_BUSY(status) ||
+		G_000E40_TAM_BUSY(status) || G_000E40_PB_BUSY(status)) {
+		dev_err(rdev->dev, "failed to reset GPU\n");
+		rdev->gpu_lockup = true;
 		return -1;
 	}
-	DRM_INFO("GPU reset succeed (RBBM_STATUS=0x%08X)\n", status);
+	r100_mc_resume(rdev, &save);
+	dev_info(rdev->dev, "GPU reset succeed\n");
 	return 0;
 }
 
@@ -3463,7 +3411,7 @@ static int r100_startup(struct radeon_device *rdev)
 	/* Resume clock */
 	r100_clock_startup(rdev);
 	/* Initialize GPU configuration (# pipes, ...) */
-	r100_gpu_init(rdev);
+//	r100_gpu_init(rdev);
 	/* Initialize GART (initialize after TTM so we can allocate
 	 * memory through TTM but finalize after TTM) */
 	r100_enable_bm(rdev);
diff --git a/drivers/gpu/drm/radeon/r100d.h b/drivers/gpu/drm/radeon/r100d.h
index df29a63..de8abd1 100644
--- a/drivers/gpu/drm/radeon/r100d.h
+++ b/drivers/gpu/drm/radeon/r100d.h
@@ -74,6 +74,134 @@
 #define CP_PACKET3_GET_OPCODE(h) (((h) >> 8) & 0xFF)
 
 /* Registers */
+#define R_0000F0_RBBM_SOFT_RESET                     0x0000F0
+#define   S_0000F0_SOFT_RESET_CP(x)                    (((x) & 0x1) << 0)
+#define   G_0000F0_SOFT_RESET_CP(x)                    (((x) >> 0) & 0x1)
+#define   C_0000F0_SOFT_RESET_CP                       0xFFFFFFFE
+#define   S_0000F0_SOFT_RESET_HI(x)                    (((x) & 0x1) << 1)
+#define   G_0000F0_SOFT_RESET_HI(x)                    (((x) >> 1) & 0x1)
+#define   C_0000F0_SOFT_RESET_HI                       0xFFFFFFFD
+#define   S_0000F0_SOFT_RESET_SE(x)                    (((x) & 0x1) << 2)
+#define   G_0000F0_SOFT_RESET_SE(x)                    (((x) >> 2) & 0x1)
+#define   C_0000F0_SOFT_RESET_SE                       0xFFFFFFFB
+#define   S_0000F0_SOFT_RESET_RE(x)                    (((x) & 0x1) << 3)
+#define   G_0000F0_SOFT_RESET_RE(x)                    (((x) >> 3) & 0x1)
+#define   C_0000F0_SOFT_RESET_RE                       0xFFFFFFF7
+#define   S_0000F0_SOFT_RESET_PP(x)                    (((x) & 0x1) << 4)
+#define   G_0000F0_SOFT_RESET_PP(x)                    (((x) >> 4) & 0x1)
+#define   C_0000F0_SOFT_RESET_PP                       0xFFFFFFEF
+#define   S_0000F0_SOFT_RESET_E2(x)                    (((x) & 0x1) << 5)
+#define   G_0000F0_SOFT_RESET_E2(x)                    (((x) >> 5) & 0x1)
+#define   C_0000F0_SOFT_RESET_E2                       0xFFFFFFDF
+#define   S_0000F0_SOFT_RESET_RB(x)                    (((x) & 0x1) << 6)
+#define   G_0000F0_SOFT_RESET_RB(x)                    (((x) >> 6) & 0x1)
+#define   C_0000F0_SOFT_RESET_RB                       0xFFFFFFBF
+#define   S_0000F0_SOFT_RESET_HDP(x)                   (((x) & 0x1) << 7)
+#define   G_0000F0_SOFT_RESET_HDP(x)                   (((x) >> 7) & 0x1)
+#define   C_0000F0_SOFT_RESET_HDP                      0xFFFFFF7F
+#define   S_0000F0_SOFT_RESET_MC(x)                    (((x) & 0x1) << 8)
+#define   G_0000F0_SOFT_RESET_MC(x)                    (((x) >> 8) & 0x1)
+#define   C_0000F0_SOFT_RESET_MC                       0xFFFFFEFF
+#define   S_0000F0_SOFT_RESET_AIC(x)                   (((x) & 0x1) << 9)
+#define   G_0000F0_SOFT_RESET_AIC(x)                   (((x) >> 9) & 0x1)
+#define   C_0000F0_SOFT_RESET_AIC                      0xFFFFFDFF
+#define   S_0000F0_SOFT_RESET_VIP(x)                   (((x) & 0x1) << 10)
+#define   G_0000F0_SOFT_RESET_VIP(x)                   (((x) >> 10) & 0x1)
+#define   C_0000F0_SOFT_RESET_VIP                      0xFFFFFBFF
+#define   S_0000F0_SOFT_RESET_DISP(x)                  (((x) & 0x1) << 11)
+#define   G_0000F0_SOFT_RESET_DISP(x)                  (((x) >> 11) & 0x1)
+#define   C_0000F0_SOFT_RESET_DISP                     0xFFFFF7FF
+#define   S_0000F0_SOFT_RESET_CG(x)                    (((x) & 0x1) << 12)
+#define   G_0000F0_SOFT_RESET_CG(x)                    (((x) >> 12) & 0x1)
+#define   C_0000F0_SOFT_RESET_CG                       0xFFFFEFFF
+#define R_000030_BUS_CNTL                            0x000030
+#define   S_000030_BUS_DBL_RESYNC(x)                   (((x) & 0x1) << 0)
+#define   G_000030_BUS_DBL_RESYNC(x)                   (((x) >> 0) & 0x1)
+#define   C_000030_BUS_DBL_RESYNC                      0xFFFFFFFE
+#define   S_000030_BUS_MSTR_RESET(x)                   (((x) & 0x1) << 1)
+#define   G_000030_BUS_MSTR_RESET(x)                   (((x) >> 1) & 0x1)
+#define   C_000030_BUS_MSTR_RESET                      0xFFFFFFFD
+#define   S_000030_BUS_FLUSH_BUF(x)                    (((x) & 0x1) << 2)
+#define   G_000030_BUS_FLUSH_BUF(x)                    (((x) >> 2) & 0x1)
+#define   C_000030_BUS_FLUSH_BUF                       0xFFFFFFFB
+#define   S_000030_BUS_STOP_REQ_DIS(x)                 (((x) & 0x1) << 3)
+#define   G_000030_BUS_STOP_REQ_DIS(x)                 (((x) >> 3) & 0x1)
+#define   C_000030_BUS_STOP_REQ_DIS                    0xFFFFFFF7
+#define   S_000030_BUS_PM4_READ_COMBINE_EN(x)          (((x) & 0x1) << 4)
+#define   G_000030_BUS_PM4_READ_COMBINE_EN(x)          (((x) >> 4) & 0x1)
+#define   C_000030_BUS_PM4_READ_COMBINE_EN             0xFFFFFFEF
+#define   S_000030_BUS_WRT_COMBINE_EN(x)               (((x) & 0x1) << 5)
+#define   G_000030_BUS_WRT_COMBINE_EN(x)               (((x) >> 5) & 0x1)
+#define   C_000030_BUS_WRT_COMBINE_EN                  0xFFFFFFDF
+#define   S_000030_BUS_MASTER_DIS(x)                   (((x) & 0x1) << 6)
+#define   G_000030_BUS_MASTER_DIS(x)                   (((x) >> 6) & 0x1)
+#define   C_000030_BUS_MASTER_DIS                      0xFFFFFFBF
+#define   S_000030_BIOS_ROM_WRT_EN(x)                  (((x) & 0x1) << 7)
+#define   G_000030_BIOS_ROM_WRT_EN(x)                  (((x) >> 7) & 0x1)
+#define   C_000030_BIOS_ROM_WRT_EN                     0xFFFFFF7F
+#define   S_000030_BM_DAC_CRIPPLE(x)                   (((x) & 0x1) << 8)
+#define   G_000030_BM_DAC_CRIPPLE(x)                   (((x) >> 8) & 0x1)
+#define   C_000030_BM_DAC_CRIPPLE                      0xFFFFFEFF
+#define   S_000030_BUS_NON_PM4_READ_COMBINE_EN(x)      (((x) & 0x1) << 9)
+#define   G_000030_BUS_NON_PM4_READ_COMBINE_EN(x)      (((x) >> 9) & 0x1)
+#define   C_000030_BUS_NON_PM4_READ_COMBINE_EN         0xFFFFFDFF
+#define   S_000030_BUS_XFERD_DISCARD_EN(x)             (((x) & 0x1) << 10)
+#define   G_000030_BUS_XFERD_DISCARD_EN(x)             (((x) >> 10) & 0x1)
+#define   C_000030_BUS_XFERD_DISCARD_EN                0xFFFFFBFF
+#define   S_000030_BUS_SGL_READ_DISABLE(x)             (((x) & 0x1) << 11)
+#define   G_000030_BUS_SGL_READ_DISABLE(x)             (((x) >> 11) & 0x1)
+#define   C_000030_BUS_SGL_READ_DISABLE                0xFFFFF7FF
+#define   S_000030_BIOS_DIS_ROM(x)                     (((x) & 0x1) << 12)
+#define   G_000030_BIOS_DIS_ROM(x)                     (((x) >> 12) & 0x1)
+#define   C_000030_BIOS_DIS_ROM                        0xFFFFEFFF
+#define   S_000030_BUS_PCI_READ_RETRY_EN(x)            (((x) & 0x1) << 13)
+#define   G_000030_BUS_PCI_READ_RETRY_EN(x)            (((x) >> 13) & 0x1)
+#define   C_000030_BUS_PCI_READ_RETRY_EN               0xFFFFDFFF
+#define   S_000030_BUS_AGP_AD_STEPPING_EN(x)           (((x) & 0x1) << 14)
+#define   G_000030_BUS_AGP_AD_STEPPING_EN(x)           (((x) >> 14) & 0x1)
+#define   C_000030_BUS_AGP_AD_STEPPING_EN              0xFFFFBFFF
+#define   S_000030_BUS_PCI_WRT_RETRY_EN(x)             (((x) & 0x1) << 15)
+#define   G_000030_BUS_PCI_WRT_RETRY_EN(x)             (((x) >> 15) & 0x1)
+#define   C_000030_BUS_PCI_WRT_RETRY_EN                0xFFFF7FFF
+#define   S_000030_BUS_RETRY_WS(x)                     (((x) & 0xF) << 16)
+#define   G_000030_BUS_RETRY_WS(x)                     (((x) >> 16) & 0xF)
+#define   C_000030_BUS_RETRY_WS                        0xFFF0FFFF
+#define   S_000030_BUS_MSTR_RD_MULT(x)                 (((x) & 0x1) << 20)
+#define   G_000030_BUS_MSTR_RD_MULT(x)                 (((x) >> 20) & 0x1)
+#define   C_000030_BUS_MSTR_RD_MULT                    0xFFEFFFFF
+#define   S_000030_BUS_MSTR_RD_LINE(x)                 (((x) & 0x1) << 21)
+#define   G_000030_BUS_MSTR_RD_LINE(x)                 (((x) >> 21) & 0x1)
+#define   C_000030_BUS_MSTR_RD_LINE                    0xFFDFFFFF
+#define   S_000030_BUS_SUSPEND(x)                      (((x) & 0x1) << 22)
+#define   G_000030_BUS_SUSPEND(x)                      (((x) >> 22) & 0x1)
+#define   C_000030_BUS_SUSPEND                         0xFFBFFFFF
+#define   S_000030_LAT_16X(x)                          (((x) & 0x1) << 23)
+#define   G_000030_LAT_16X(x)                          (((x) >> 23) & 0x1)
+#define   C_000030_LAT_16X                             0xFF7FFFFF
+#define   S_000030_BUS_RD_DISCARD_EN(x)                (((x) & 0x1) << 24)
+#define   G_000030_BUS_RD_DISCARD_EN(x)                (((x) >> 24) & 0x1)
+#define   C_000030_BUS_RD_DISCARD_EN                   0xFEFFFFFF
+#define   S_000030_ENFRCWRDY(x)                        (((x) & 0x1) << 25)
+#define   G_000030_ENFRCWRDY(x)                        (((x) >> 25) & 0x1)
+#define   C_000030_ENFRCWRDY                           0xFDFFFFFF
+#define   S_000030_BUS_MSTR_WS(x)                      (((x) & 0x1) << 26)
+#define   G_000030_BUS_MSTR_WS(x)                      (((x) >> 26) & 0x1)
+#define   C_000030_BUS_MSTR_WS                         0xFBFFFFFF
+#define   S_000030_BUS_PARKING_DIS(x)                  (((x) & 0x1) << 27)
+#define   G_000030_BUS_PARKING_DIS(x)                  (((x) >> 27) & 0x1)
+#define   C_000030_BUS_PARKING_DIS                     0xF7FFFFFF
+#define   S_000030_BUS_MSTR_DISCONNECT_EN(x)           (((x) & 0x1) << 28)
+#define   G_000030_BUS_MSTR_DISCONNECT_EN(x)           (((x) >> 28) & 0x1)
+#define   C_000030_BUS_MSTR_DISCONNECT_EN              0xEFFFFFFF
+#define   S_000030_SERR_EN(x)                          (((x) & 0x1) << 29)
+#define   G_000030_SERR_EN(x)                          (((x) >> 29) & 0x1)
+#define   C_000030_SERR_EN                             0xDFFFFFFF
+#define   S_000030_BUS_READ_BURST(x)                   (((x) & 0x1) << 30)
+#define   G_000030_BUS_READ_BURST(x)                   (((x) >> 30) & 0x1)
+#define   C_000030_BUS_READ_BURST                      0xBFFFFFFF
+#define   S_000030_BUS_RDY_READ_DLY(x)                 (((x) & 0x1) << 31)
+#define   G_000030_BUS_RDY_READ_DLY(x)                 (((x) >> 31) & 0x1)
+#define   C_000030_BUS_RDY_READ_DLY                    0x7FFFFFFF
 #define R_000040_GEN_INT_CNTL                        0x000040
 #define   S_000040_CRTC_VBLANK(x)                      (((x) & 0x1) << 0)
 #define   G_000040_CRTC_VBLANK(x)                      (((x) >> 0) & 0x1)
diff --git a/drivers/gpu/drm/radeon/r300.c b/drivers/gpu/drm/radeon/r300.c
index 75ab7b0..5f8f277 100644
--- a/drivers/gpu/drm/radeon/r300.c
+++ b/drivers/gpu/drm/radeon/r300.c
@@ -150,6 +150,10 @@ void rv370_pcie_gart_disable(struct radeon_device *rdev)
 	u32 tmp;
 	int r;
 
+	WREG32_PCIE(RADEON_PCIE_TX_GART_START_LO, 0);
+	WREG32_PCIE(RADEON_PCIE_TX_GART_END_LO, 0);
+	WREG32_PCIE(RADEON_PCIE_TX_GART_START_HI, 0);
+	WREG32_PCIE(RADEON_PCIE_TX_GART_END_HI, 0);
 	tmp = RREG32_PCIE(RADEON_PCIE_TX_GART_CNTL);
 	tmp |= RADEON_PCIE_TX_GART_UNMAPPED_ACCESS_DISCARD;
 	WREG32_PCIE(RADEON_PCIE_TX_GART_CNTL, tmp & ~RADEON_PCIE_TX_GART_EN);
@@ -322,7 +326,6 @@ void r300_gpu_init(struct radeon_device *rdev)
 {
 	uint32_t gb_tile_config, tmp;
 
-	r100_hdp_reset(rdev);
 	/* FIXME: rv380 one pipes ? */
 	if ((rdev->family == CHIP_R300) || (rdev->family == CHIP_R350)) {
 		/* r300,r350 */
@@ -374,57 +377,6 @@ void r300_gpu_init(struct radeon_device *rdev)
 		 rdev->num_gb_pipes, rdev->num_z_pipes);
 }
 
-int r300_ga_reset(struct radeon_device *rdev)
-{
-	uint32_t tmp;
-	bool reinit_cp;
-	int i;
-
-	reinit_cp = rdev->cp.ready;
-	rdev->cp.ready = false;
-	for (i = 0; i < rdev->usec_timeout; i++) {
-		WREG32(RADEON_CP_CSQ_MODE, 0);
-		WREG32(RADEON_CP_CSQ_CNTL, 0);
-		WREG32(RADEON_RBBM_SOFT_RESET, 0x32005);
-		(void)RREG32(RADEON_RBBM_SOFT_RESET);
-		udelay(200);
-		WREG32(RADEON_RBBM_SOFT_RESET, 0);
-		/* Wait to prevent race in RBBM_STATUS */
-		mdelay(1);
-		tmp = RREG32(RADEON_RBBM_STATUS);
-		if (tmp & ((1 << 20) | (1 << 26))) {
-			DRM_ERROR("VAP & CP still busy (RBBM_STATUS=0x%08X)", tmp);
-			/* GA still busy soft reset it */
-			WREG32(0x429C, 0x200);
-			WREG32(R300_VAP_PVS_STATE_FLUSH_REG, 0);
-			WREG32(R300_RE_SCISSORS_TL, 0);
-			WREG32(R300_RE_SCISSORS_BR, 0);
-			WREG32(0x24AC, 0);
-		}
-		/* Wait to prevent race in RBBM_STATUS */
-		mdelay(1);
-		tmp = RREG32(RADEON_RBBM_STATUS);
-		if (!(tmp & ((1 << 20) | (1 << 26)))) {
-			break;
-		}
-	}
-	for (i = 0; i < rdev->usec_timeout; i++) {
-		tmp = RREG32(RADEON_RBBM_STATUS);
-		if (!(tmp & ((1 << 20) | (1 << 26)))) {
-			DRM_INFO("GA reset succeed (RBBM_STATUS=0x%08X)\n",
-				 tmp);
-			if (reinit_cp) {
-				return r100_cp_init(rdev, rdev->cp.ring_size);
-			}
-			return 0;
-		}
-		DRM_UDELAY(1);
-	}
-	tmp = RREG32(RADEON_RBBM_STATUS);
-	DRM_ERROR("Failed to reset GA ! (RBBM_STATUS=0x%08X)\n", tmp);
-	return -1;
-}
-
 bool r300_gpu_is_lockup(struct radeon_device *rdev)
 {
 	u32 rbbm_status;
@@ -449,37 +401,69 @@ bool r300_gpu_is_lockup(struct radeon_device *rdev)
 
 int r300_asic_reset(struct radeon_device *rdev)
 {
-	uint32_t status;
+	struct r100_mc_save save;
+	u32 status, tmp;
 
-	/* reset order likely matter */
-	status = RREG32(RADEON_RBBM_STATUS);
-	dev_info(rdev->dev, "(%s:%d) RBBM_STATUS=0x%08X\n", __func__, __LINE__, status);
-	/* reset HDP */
-	r100_hdp_reset(rdev);
-	/* reset rb2d */
-	if (status & ((1 << 17) | (1 << 18) | (1 << 27))) {
-		r100_rb2d_reset(rdev);
-	}
-	/* reset GA */
-	if (status & ((1 << 20) | (1 << 26))) {
-		r300_ga_reset(rdev);
-	}
-	/* reset CP */
-	status = RREG32(RADEON_RBBM_STATUS);
-	if (status & (1 << 16)) {
-		r100_cp_reset(rdev);
+	r100_mc_stop(rdev, &save);
+	status = RREG32(R_000E40_RBBM_STATUS);
+	if (!G_000E40_GUI_ACTIVE(status)) {
+		return 0;
 	}
+	status = RREG32(R_000E40_RBBM_STATUS);
+	dev_info(rdev->dev, "(%s:%d) RBBM_STATUS=0x%08X\n", __func__, __LINE__, status);
+	/* stop CP */
+	WREG32(RADEON_CP_CSQ_CNTL, 0);
+	tmp = RREG32(RADEON_CP_RB_CNTL);
+	WREG32(RADEON_CP_RB_CNTL, tmp | RADEON_RB_RPTR_WR_ENA);
+	WREG32(RADEON_CP_RB_RPTR_WR, 0);
+	WREG32(RADEON_CP_RB_WPTR, 0);
+	WREG32(RADEON_CP_RB_CNTL, tmp);
+	/* save PCI state */
+	pci_save_state(rdev->pdev);
+	/* disable bus mastering */
+	r100_bm_disable(rdev);
+	WREG32(R_0000F0_RBBM_SOFT_RESET, S_0000F0_SOFT_RESET_VAP(1) |
+					S_0000F0_SOFT_RESET_GA(1));
+	RREG32(R_0000F0_RBBM_SOFT_RESET);
+	mdelay(500);
+	WREG32(R_0000F0_RBBM_SOFT_RESET, 0);
+	mdelay(1);
+	status = RREG32(R_000E40_RBBM_STATUS);
+	dev_info(rdev->dev, "(%s:%d) RBBM_STATUS=0x%08X\n", __func__, __LINE__, status);
+	/* resetting the CP seems to be problematic sometimes it end up
+	 * hard locking the computer, but it's necessary for successfull
+	 * reset more test & playing is needed on R3XX/R4XX to find a
+	 * reliable (if any solution)
+	 */
+	WREG32(R_0000F0_RBBM_SOFT_RESET, S_0000F0_SOFT_RESET_CP(1));
+	RREG32(R_0000F0_RBBM_SOFT_RESET);
+	mdelay(500);
+	WREG32(R_0000F0_RBBM_SOFT_RESET, 0);
+	mdelay(1);
+	status = RREG32(R_000E40_RBBM_STATUS);
+	dev_info(rdev->dev, "(%s:%d) RBBM_STATUS=0x%08X\n", __func__, __LINE__, status);
+	/* reset MC */
+	WREG32(R_0000F0_RBBM_SOFT_RESET, S_0000F0_SOFT_RESET_MC(1));
+	RREG32(R_0000F0_RBBM_SOFT_RESET);
+	mdelay(500);
+	WREG32(R_0000F0_RBBM_SOFT_RESET, 0);
+	mdelay(1);
+	status = RREG32(R_000E40_RBBM_STATUS);
+	dev_info(rdev->dev, "(%s:%d) RBBM_STATUS=0x%08X\n", __func__, __LINE__, status);
+	/* restore PCI & busmastering */
+	pci_restore_state(rdev->pdev);
+	r100_enable_bm(rdev);
 	/* Check if GPU is idle */
-	status = RREG32(RADEON_RBBM_STATUS);
-	if (status & RADEON_RBBM_ACTIVE) {
-		DRM_ERROR("Failed to reset GPU (RBBM_STATUS=0x%08X)\n", status);
+	if (G_000E40_GA_BUSY(status) || G_000E40_VAP_BUSY(status)) {
+		dev_err(rdev->dev, "failed to reset GPU\n");
+		rdev->gpu_lockup = true;
 		return -1;
 	}
-	DRM_INFO("GPU reset succeed (RBBM_STATUS=0x%08X)\n", status);
+	r100_mc_resume(rdev, &save);
+	dev_info(rdev->dev, "GPU reset succeed\n");
 	return 0;
 }
 
-
 /*
  * r300,r350,rv350,rv380 VRAM info
  */
diff --git a/drivers/gpu/drm/radeon/r300d.h b/drivers/gpu/drm/radeon/r300d.h
index 4c73114..968a333 100644
--- a/drivers/gpu/drm/radeon/r300d.h
+++ b/drivers/gpu/drm/radeon/r300d.h
@@ -209,7 +209,52 @@
 #define   S_000E40_GUI_ACTIVE(x)                       (((x) & 0x1) << 31)
 #define   G_000E40_GUI_ACTIVE(x)                       (((x) >> 31) & 0x1)
 #define   C_000E40_GUI_ACTIVE                          0x7FFFFFFF
-
+#define R_0000F0_RBBM_SOFT_RESET                     0x0000F0
+#define   S_0000F0_SOFT_RESET_CP(x)                    (((x) & 0x1) << 0)
+#define   G_0000F0_SOFT_RESET_CP(x)                    (((x) >> 0) & 0x1)
+#define   C_0000F0_SOFT_RESET_CP                       0xFFFFFFFE
+#define   S_0000F0_SOFT_RESET_HI(x)                    (((x) & 0x1) << 1)
+#define   G_0000F0_SOFT_RESET_HI(x)                    (((x) >> 1) & 0x1)
+#define   C_0000F0_SOFT_RESET_HI                       0xFFFFFFFD
+#define   S_0000F0_SOFT_RESET_VAP(x)                   (((x) & 0x1) << 2)
+#define   G_0000F0_SOFT_RESET_VAP(x)                   (((x) >> 2) & 0x1)
+#define   C_0000F0_SOFT_RESET_VAP                      0xFFFFFFFB
+#define   S_0000F0_SOFT_RESET_RE(x)                    (((x) & 0x1) << 3)
+#define   G_0000F0_SOFT_RESET_RE(x)                    (((x) >> 3) & 0x1)
+#define   C_0000F0_SOFT_RESET_RE                       0xFFFFFFF7
+#define   S_0000F0_SOFT_RESET_PP(x)                    (((x) & 0x1) << 4)
+#define   G_0000F0_SOFT_RESET_PP(x)                    (((x) >> 4) & 0x1)
+#define   C_0000F0_SOFT_RESET_PP                       0xFFFFFFEF
+#define   S_0000F0_SOFT_RESET_E2(x)                    (((x) & 0x1) << 5)
+#define   G_0000F0_SOFT_RESET_E2(x)                    (((x) >> 5) & 0x1)
+#define   C_0000F0_SOFT_RESET_E2                       0xFFFFFFDF
+#define   S_0000F0_SOFT_RESET_RB(x)                    (((x) & 0x1) << 6)
+#define   G_0000F0_SOFT_RESET_RB(x)                    (((x) >> 6) & 0x1)
+#define   C_0000F0_SOFT_RESET_RB                       0xFFFFFFBF
+#define   S_0000F0_SOFT_RESET_HDP(x)                   (((x) & 0x1) << 7)
+#define   G_0000F0_SOFT_RESET_HDP(x)                   (((x) >> 7) & 0x1)
+#define   C_0000F0_SOFT_RESET_HDP                      0xFFFFFF7F
+#define   S_0000F0_SOFT_RESET_MC(x)                    (((x) & 0x1) << 8)
+#define   G_0000F0_SOFT_RESET_MC(x)                    (((x) >> 8) & 0x1)
+#define   C_0000F0_SOFT_RESET_MC                       0xFFFFFEFF
+#define   S_0000F0_SOFT_RESET_AIC(x)                   (((x) & 0x1) << 9)
+#define   G_0000F0_SOFT_RESET_AIC(x)                   (((x) >> 9) & 0x1)
+#define   C_0000F0_SOFT_RESET_AIC                      0xFFFFFDFF
+#define   S_0000F0_SOFT_RESET_VIP(x)                   (((x) & 0x1) << 10)
+#define   G_0000F0_SOFT_RESET_VIP(x)                   (((x) >> 10) & 0x1)
+#define   C_0000F0_SOFT_RESET_VIP                      0xFFFFFBFF
+#define   S_0000F0_SOFT_RESET_DISP(x)                  (((x) & 0x1) << 11)
+#define   G_0000F0_SOFT_RESET_DISP(x)                  (((x) >> 11) & 0x1)
+#define   C_0000F0_SOFT_RESET_DISP                     0xFFFFF7FF
+#define   S_0000F0_SOFT_RESET_CG(x)                    (((x) & 0x1) << 12)
+#define   G_0000F0_SOFT_RESET_CG(x)                    (((x) >> 12) & 0x1)
+#define   C_0000F0_SOFT_RESET_CG                       0xFFFFEFFF
+#define   S_0000F0_SOFT_RESET_GA(x)                    (((x) & 0x1) << 13)
+#define   G_0000F0_SOFT_RESET_GA(x)                    (((x) >> 13) & 0x1)
+#define   C_0000F0_SOFT_RESET_GA                       0xFFFFDFFF
+#define   S_0000F0_SOFT_RESET_IDCT(x)                  (((x) & 0x1) << 14)
+#define   G_0000F0_SOFT_RESET_IDCT(x)                  (((x) >> 14) & 0x1)
+#define   C_0000F0_SOFT_RESET_IDCT                     0xFFFFBFFF
 
 #define R_00000D_SCLK_CNTL                           0x00000D
 #define   S_00000D_SCLK_SRC_SEL(x)                     (((x) & 0x7) << 0)
diff --git a/drivers/gpu/drm/radeon/r520.c b/drivers/gpu/drm/radeon/r520.c
index 99ef6dc..00069ee 100644
--- a/drivers/gpu/drm/radeon/r520.c
+++ b/drivers/gpu/drm/radeon/r520.c
@@ -52,7 +52,6 @@ static void r520_gpu_init(struct radeon_device *rdev)
 {
 	unsigned pipe_select_current, gb_pipe_select, tmp;
 
-	r100_hdp_reset(rdev);
 	rv515_vga_render_disable(rdev);
 	/*
 	 * DST_PIPE_CONFIG		0x170C
diff --git a/drivers/gpu/drm/radeon/r600.c b/drivers/gpu/drm/radeon/r600.c
index ce59456..3b485ce 100644
--- a/drivers/gpu/drm/radeon/r600.c
+++ b/drivers/gpu/drm/radeon/r600.c
@@ -753,7 +753,6 @@ int r600_gpu_soft_reset(struct radeon_device *rdev)
 			S_008014_DB2_BUSY(1) | S_008014_DB3_BUSY(1) |
 			S_008014_CB0_BUSY(1) | S_008014_CB1_BUSY(1) |
 			S_008014_CB2_BUSY(1) | S_008014_CB3_BUSY(1);
-	u32 srbm_reset = 0;
 	u32 tmp;
 
 	dev_info(rdev->dev, "GPU softreset \n");
@@ -768,7 +767,7 @@ int r600_gpu_soft_reset(struct radeon_device *rdev)
 		dev_warn(rdev->dev, "Wait for MC idle timedout !\n");
 	}
 	/* Disable CP parsing/prefetching */
-	WREG32(R_0086D8_CP_ME_CNTL, S_0086D8_CP_ME_HALT(0xff));
+	WREG32(R_0086D8_CP_ME_CNTL, S_0086D8_CP_ME_HALT(1));
 	/* Check if any of the rendering block is busy and reset it */
 	if ((RREG32(R_008010_GRBM_STATUS) & grbm_busy_mask) ||
 	    (RREG32(R_008014_GRBM_STATUS2) & grbm2_busy_mask)) {
@@ -787,55 +786,17 @@ int r600_gpu_soft_reset(struct radeon_device *rdev)
 			S_008020_SOFT_RESET_VGT(1);
 		dev_info(rdev->dev, "  R_008020_GRBM_SOFT_RESET=0x%08X\n", tmp);
 		WREG32(R_008020_GRBM_SOFT_RESET, tmp);
-		(void)RREG32(R_008020_GRBM_SOFT_RESET);
-		mdelay(1);
+		RREG32(R_008020_GRBM_SOFT_RESET);
+		mdelay(15);
 		WREG32(R_008020_GRBM_SOFT_RESET, 0);
-		(void)RREG32(R_008020_GRBM_SOFT_RESET);
 	}
 	/* Reset CP (we always reset CP) */
 	tmp = S_008020_SOFT_RESET_CP(1);
 	dev_info(rdev->dev, "R_008020_GRBM_SOFT_RESET=0x%08X\n", tmp);
 	WREG32(R_008020_GRBM_SOFT_RESET, tmp);
-	(void)RREG32(R_008020_GRBM_SOFT_RESET);
-	udelay(50);
+	RREG32(R_008020_GRBM_SOFT_RESET);
+	mdelay(15);
 	WREG32(R_008020_GRBM_SOFT_RESET, 0);
-	(void)RREG32(R_008020_GRBM_SOFT_RESET);
-	/* Reset others GPU block if necessary */
-	if (G_000E50_RLC_BUSY(RREG32(R_000E50_SRBM_STATUS)))
-		srbm_reset |= S_000E60_SOFT_RESET_RLC(1);
-	if (G_000E50_GRBM_RQ_PENDING(RREG32(R_000E50_SRBM_STATUS)))
-		srbm_reset |= S_000E60_SOFT_RESET_GRBM(1);
-	if (G_000E50_HI_RQ_PENDING(RREG32(R_000E50_SRBM_STATUS)))
-		srbm_reset |= S_000E60_SOFT_RESET_IH(1);
-	if (G_000E50_VMC_BUSY(RREG32(R_000E50_SRBM_STATUS)))
-		srbm_reset |= S_000E60_SOFT_RESET_VMC(1);
-	if (G_000E50_MCB_BUSY(RREG32(R_000E50_SRBM_STATUS)))
-		srbm_reset |= S_000E60_SOFT_RESET_MC(1);
-	if (G_000E50_MCDZ_BUSY(RREG32(R_000E50_SRBM_STATUS)))
-		srbm_reset |= S_000E60_SOFT_RESET_MC(1);
-	if (G_000E50_MCDY_BUSY(RREG32(R_000E50_SRBM_STATUS)))
-		srbm_reset |= S_000E60_SOFT_RESET_MC(1);
-	if (G_000E50_MCDX_BUSY(RREG32(R_000E50_SRBM_STATUS)))
-		srbm_reset |= S_000E60_SOFT_RESET_MC(1);
-	if (G_000E50_MCDW_BUSY(RREG32(R_000E50_SRBM_STATUS)))
-		srbm_reset |= S_000E60_SOFT_RESET_MC(1);
-	if (G_000E50_RLC_BUSY(RREG32(R_000E50_SRBM_STATUS)))
-		srbm_reset |= S_000E60_SOFT_RESET_RLC(1);
-	if (G_000E50_SEM_BUSY(RREG32(R_000E50_SRBM_STATUS)))
-		srbm_reset |= S_000E60_SOFT_RESET_SEM(1);
-	if (G_000E50_BIF_BUSY(RREG32(R_000E50_SRBM_STATUS)))
-		srbm_reset |= S_000E60_SOFT_RESET_BIF(1);
-	dev_info(rdev->dev, "  R_000E60_SRBM_SOFT_RESET=0x%08X\n", srbm_reset);
-	WREG32(R_000E60_SRBM_SOFT_RESET, srbm_reset);
-	(void)RREG32(R_000E60_SRBM_SOFT_RESET);
-	mdelay(1);
-	WREG32(R_000E60_SRBM_SOFT_RESET, 0);
-	(void)RREG32(R_000E60_SRBM_SOFT_RESET);
-	WREG32(R_000E60_SRBM_SOFT_RESET, srbm_reset);
-	(void)RREG32(R_000E60_SRBM_SOFT_RESET);
-	mdelay(1);
-	WREG32(R_000E60_SRBM_SOFT_RESET, 0);
-	(void)RREG32(R_000E60_SRBM_SOFT_RESET);
 	/* Wait a little for things to settle down */
 	mdelay(1);
 	dev_info(rdev->dev, "  R_008010_GRBM_STATUS=0x%08X\n",
@@ -844,10 +805,6 @@ int r600_gpu_soft_reset(struct radeon_device *rdev)
 		RREG32(R_008014_GRBM_STATUS2));
 	dev_info(rdev->dev, "  R_000E50_SRBM_STATUS=0x%08X\n",
 		RREG32(R_000E50_SRBM_STATUS));
-	/* After reset we need to reinit the asic as GPU often endup in an
-	 * incoherent state.
-	 */
-	atom_asic_init(rdev->mode_info.atom_context);
 	rv515_mc_resume(rdev, &save);
 	return 0;
 }
diff --git a/drivers/gpu/drm/radeon/r600_blit_kms.c b/drivers/gpu/drm/radeon/r600_blit_kms.c
index f6c6c77..d13622a 100644
--- a/drivers/gpu/drm/radeon/r600_blit_kms.c
+++ b/drivers/gpu/drm/radeon/r600_blit_kms.c
@@ -447,6 +447,9 @@ int r600_blit_init(struct radeon_device *rdev)
 	u32 packet2s[16];
 	int num_packet2s = 0;
 
+	/* don't reinitialize blit */
+	if (rdev->r600_blit.shader_obj)
+		return 0;
 	mutex_init(&rdev->r600_blit.mutex);
 	rdev->r600_blit.state_offset = 0;
 
diff --git a/drivers/gpu/drm/radeon/radeon.h b/drivers/gpu/drm/radeon/radeon.h
index a2ded38..56527e3 100644
--- a/drivers/gpu/drm/radeon/radeon.h
+++ b/drivers/gpu/drm/radeon/radeon.h
@@ -1178,6 +1178,7 @@ static inline void radeon_ring_write(struct radeon_device *rdev, uint32_t v)
 
 /* Common functions */
 /* AGP */
+extern int radeon_gpu_reset(struct radeon_device *rdev);
 extern void radeon_agp_disable(struct radeon_device *rdev);
 extern int radeon_gart_table_vram_pin(struct radeon_device *rdev);
 extern void radeon_gart_restore(struct radeon_device *rdev);
@@ -1217,6 +1218,7 @@ extern void r100_pci_gart_fini(struct radeon_device *rdev);
 extern int r100_pci_gart_enable(struct radeon_device *rdev);
 extern void r100_pci_gart_disable(struct radeon_device *rdev);
 extern int r100_pci_gart_set_page(struct radeon_device *rdev, int i, uint64_t addr);
+extern void r100_bm_disable(struct radeon_device *rdev);
 extern int r100_debugfs_mc_info_init(struct radeon_device *rdev);
 extern int r100_gui_wait_for_idle(struct radeon_device *rdev);
 extern void r100_ib_fini(struct radeon_device *rdev);
@@ -1229,8 +1231,6 @@ extern void r100_vram_init_sizes(struct radeon_device *rdev);
 extern void r100_wb_disable(struct radeon_device *rdev);
 extern void r100_wb_fini(struct radeon_device *rdev);
 extern int r100_wb_init(struct radeon_device *rdev);
-extern void r100_hdp_reset(struct radeon_device *rdev);
-extern int r100_rb2d_reset(struct radeon_device *rdev);
 extern int r100_cp_reset(struct radeon_device *rdev);
 extern void r100_vga_render_disable(struct radeon_device *rdev);
 extern int r100_cs_track_check_pkt3_indx_buffer(struct radeon_cs_parser *p,
diff --git a/drivers/gpu/drm/radeon/radeon_asic.h b/drivers/gpu/drm/radeon/radeon_asic.h
index 8a9660d..20419cf 100644
--- a/drivers/gpu/drm/radeon/radeon_asic.h
+++ b/drivers/gpu/drm/radeon/radeon_asic.h
@@ -369,6 +369,7 @@ static struct radeon_asic rs400_asic = {
 /*
  * rs600.
  */
+extern int rs600_asic_reset(struct radeon_device *rdev);
 extern int rs600_init(struct radeon_device *rdev);
 extern void rs600_fini(struct radeon_device *rdev);
 extern int rs600_suspend(struct radeon_device *rdev);
@@ -394,7 +395,7 @@ static struct radeon_asic rs600_asic = {
 	.resume = &rs600_resume,
 	.vga_set_state = &r100_vga_set_state,
 	.gpu_is_lockup = &r300_gpu_is_lockup,
-	.asic_reset = &r300_asic_reset,
+	.asic_reset = &rs600_asic_reset,
 	.gart_tlb_flush = &rs600_gart_tlb_flush,
 	.gart_set_page = &rs600_gart_set_page,
 	.cp_commit = &r100_cp_commit,
@@ -444,7 +445,7 @@ static struct radeon_asic rs690_asic = {
 	.resume = &rs690_resume,
 	.vga_set_state = &r100_vga_set_state,
 	.gpu_is_lockup = &r300_gpu_is_lockup,
-	.asic_reset = &r300_asic_reset,
+	.asic_reset = &rs600_asic_reset,
 	.gart_tlb_flush = &rs400_gart_tlb_flush,
 	.gart_set_page = &rs400_gart_set_page,
 	.cp_commit = &r100_cp_commit,
@@ -482,7 +483,6 @@ static struct radeon_asic rs690_asic = {
  */
 int rv515_init(struct radeon_device *rdev);
 void rv515_fini(struct radeon_device *rdev);
-int rv515_asic_reset(struct radeon_device *rdev);
 uint32_t rv515_mc_rreg(struct radeon_device *rdev, uint32_t reg);
 void rv515_mc_wreg(struct radeon_device *rdev, uint32_t reg, uint32_t v);
 void rv515_ring_start(struct radeon_device *rdev);
@@ -498,7 +498,7 @@ static struct radeon_asic rv515_asic = {
 	.resume = &rv515_resume,
 	.vga_set_state = &r100_vga_set_state,
 	.gpu_is_lockup = &r300_gpu_is_lockup,
-	.asic_reset = &rv515_asic_reset,
+	.asic_reset = &rs600_asic_reset,
 	.gart_tlb_flush = &rv370_pcie_gart_tlb_flush,
 	.gart_set_page = &rv370_pcie_gart_set_page,
 	.cp_commit = &r100_cp_commit,
@@ -539,11 +539,11 @@ int r520_resume(struct radeon_device *rdev);
 static struct radeon_asic r520_asic = {
 	.init = &r520_init,
 	.fini = &rv515_fini,
-	.suspend = &rv515_suspend,
+	.suspend = &rs600_suspend,
 	.resume = &r520_resume,
 	.vga_set_state = &r100_vga_set_state,
 	.gpu_is_lockup = &r300_gpu_is_lockup,
-	.asic_reset = &rv515_asic_reset,
+	.asic_reset = &rs600_asic_reset,
 	.gart_tlb_flush = &rv370_pcie_gart_tlb_flush,
 	.gart_set_page = &rv370_pcie_gart_set_page,
 	.cp_commit = &r100_cp_commit,
diff --git a/drivers/gpu/drm/radeon/radeon_cs.c b/drivers/gpu/drm/radeon/radeon_cs.c
index 70ba02e..8d99f70 100644
--- a/drivers/gpu/drm/radeon/radeon_cs.c
+++ b/drivers/gpu/drm/radeon/radeon_cs.c
@@ -218,10 +218,6 @@ int radeon_cs_ioctl(struct drm_device *dev, void *data, struct drm_file *filp)
 	int r;
 
 	mutex_lock(&rdev->cs_mutex);
-	if (rdev->gpu_lockup) {
-		mutex_unlock(&rdev->cs_mutex);
-		return -EINVAL;
-	}
 	/* initialize parser */
 	memset(&parser, 0, sizeof(struct radeon_cs_parser));
 	parser.filp = filp;
diff --git a/drivers/gpu/drm/radeon/radeon_device.c b/drivers/gpu/drm/radeon/radeon_device.c
index 54fa444..d68c41c 100644
--- a/drivers/gpu/drm/radeon/radeon_device.c
+++ b/drivers/gpu/drm/radeon/radeon_device.c
@@ -800,6 +800,8 @@ void radeon_device_fini(struct radeon_device *rdev)
 {
 	DRM_INFO("radeon: finishing device.\n");
 	rdev->shutdown = true;
+	/* evict vram memory */
+	radeon_bo_evict_vram(rdev);
 	radeon_fini(rdev);
 	destroy_workqueue(rdev->wq);
 	vga_switcheroo_unregister_client(rdev->pdev);
@@ -898,6 +900,26 @@ int radeon_resume_kms(struct drm_device *dev)
 	return 0;
 }
 
+int radeon_gpu_reset(struct radeon_device *rdev)
+{
+	int r;
+
+	radeon_save_bios_scratch_regs(rdev);
+	radeon_suspend(rdev);
+
+	r = radeon_asic_reset(rdev);
+	if (!r) {
+		dev_info(rdev->dev, "GPU reset succeed\n");
+		radeon_resume(rdev);
+		radeon_restore_bios_scratch_regs(rdev);
+		drm_helper_resume_force_mode(rdev->ddev);
+		return 0;
+	}
+	/* bad news, how to tell it to userspace ? */
+	dev_info(rdev->dev, "GPU reset failed\n");
+	return r;
+}
+
 
 /*
  * Debugfs
diff --git a/drivers/gpu/drm/radeon/radeon_fence.c b/drivers/gpu/drm/radeon/radeon_fence.c
index 2560740..fcd7802 100644
--- a/drivers/gpu/drm/radeon/radeon_fence.c
+++ b/drivers/gpu/drm/radeon/radeon_fence.c
@@ -209,8 +209,9 @@ retry:
 		r = wait_event_interruptible_timeout(rdev->fence_drv.queue,
 				radeon_fence_signaled(fence), timeout);
 		radeon_irq_kms_sw_irq_put(rdev);
-		if (unlikely(r < 0))
+		if (unlikely(r < 0)) {
 			return r;
+		}
 	} else {
 		radeon_irq_kms_sw_irq_get(rdev);
 		r = wait_event_timeout(rdev->fence_drv.queue,
@@ -230,14 +231,16 @@ retry:
 		 */
 		if (seq == rdev->fence_drv.last_seq && radeon_gpu_is_lockup(rdev)) {
 			/* good news we believe it's a lockup */
-			dev_warn(rdev->dev, "GPU lockup (last fence id 0x%08X)\n", seq);
-			r = radeon_asic_reset(rdev);
-			if (r)
-				return r;
+			WARN(1, "GPU lockup (waiting for 0x%08X last fence id 0x%08X)\n", fence->seq, seq);
 			/* FIXME: what should we do ? marking everyone
 			 * as signaled for now
 			 */
+			rdev->gpu_lockup = true;
 			WREG32(rdev->fence_drv.scratch_reg, fence->seq);
+			r = radeon_gpu_reset(rdev);
+			if (r)
+				return r;
+			rdev->gpu_lockup = false;
 		}
 		timeout = RADEON_FENCE_JIFFIES_TIMEOUT;
 		write_lock_irqsave(&rdev->fence_drv.lock, irq_flags);
diff --git a/drivers/gpu/drm/radeon/radeon_gart.c b/drivers/gpu/drm/radeon/radeon_gart.c
index 1770d3c..e65b903 100644
--- a/drivers/gpu/drm/radeon/radeon_gart.c
+++ b/drivers/gpu/drm/radeon/radeon_gart.c
@@ -173,7 +173,7 @@ int radeon_gart_bind(struct radeon_device *rdev, unsigned offset,
 	int i, j;
 
 	if (!rdev->gart.ready) {
-		DRM_ERROR("trying to bind memory to unitialized GART !\n");
+		WARN(1, "trying to bind memory to unitialized GART !\n");
 		return -EINVAL;
 	}
 	t = offset / RADEON_GPU_PAGE_SIZE;
diff --git a/drivers/gpu/drm/radeon/rs400.c b/drivers/gpu/drm/radeon/rs400.c
index 1eaa11b..131f685 100644
--- a/drivers/gpu/drm/radeon/rs400.c
+++ b/drivers/gpu/drm/radeon/rs400.c
@@ -241,8 +241,6 @@ int rs400_mc_wait_for_idle(struct radeon_device *rdev)
 
 void rs400_gpu_init(struct radeon_device *rdev)
 {
-	/* FIXME: HDP same place on rs400 ? */
-	r100_hdp_reset(rdev);
 	/* FIXME: is this correct ? */
 	r420_pipes_init(rdev);
 	if (rs400_mc_wait_for_idle(rdev)) {
diff --git a/drivers/gpu/drm/radeon/rs600.c b/drivers/gpu/drm/radeon/rs600.c
index d10640d..58f1a8c 100644
--- a/drivers/gpu/drm/radeon/rs600.c
+++ b/drivers/gpu/drm/radeon/rs600.c
@@ -146,6 +146,78 @@ void rs600_hpd_fini(struct radeon_device *rdev)
 	}
 }
 
+void rs600_bm_disable(struct radeon_device *rdev)
+{
+	u32 tmp;
+
+	/* disable bus mastering */
+	pci_read_config_word(rdev->pdev, 0x4, (u16*)&tmp);
+	pci_write_config_word(rdev->pdev, 0x4, tmp & 0xFFFB);
+	mdelay(1);
+}
+
+int rs600_asic_reset(struct radeon_device *rdev)
+{
+	u32 status, tmp;
+
+	struct rv515_mc_save save;
+
+	/* Stops all mc clients */
+	rv515_mc_stop(rdev, &save);
+	status = RREG32(R_000E40_RBBM_STATUS);
+	if (!G_000E40_GUI_ACTIVE(status)) {
+		return 0;
+	}
+	status = RREG32(R_000E40_RBBM_STATUS);
+	dev_info(rdev->dev, "(%s:%d) RBBM_STATUS=0x%08X\n", __func__, __LINE__, status);
+	/* stop CP */
+	WREG32(RADEON_CP_CSQ_CNTL, 0);
+	tmp = RREG32(RADEON_CP_RB_CNTL);
+	WREG32(RADEON_CP_RB_CNTL, tmp | RADEON_RB_RPTR_WR_ENA);
+	WREG32(RADEON_CP_RB_RPTR_WR, 0);
+	WREG32(RADEON_CP_RB_WPTR, 0);
+	WREG32(RADEON_CP_RB_CNTL, tmp);
+	pci_save_state(rdev->pdev);
+	/* disable bus mastering */
+	rs600_bm_disable(rdev);
+	/* reset GA+VAP */
+	WREG32(R_0000F0_RBBM_SOFT_RESET, S_0000F0_SOFT_RESET_VAP(1) |
+					S_0000F0_SOFT_RESET_GA(1));
+	RREG32(R_0000F0_RBBM_SOFT_RESET);
+	mdelay(500);
+	WREG32(R_0000F0_RBBM_SOFT_RESET, 0);
+	mdelay(1);
+	status = RREG32(R_000E40_RBBM_STATUS);
+	dev_info(rdev->dev, "(%s:%d) RBBM_STATUS=0x%08X\n", __func__, __LINE__, status);
+	/* reset CP */
+	WREG32(R_0000F0_RBBM_SOFT_RESET, S_0000F0_SOFT_RESET_CP(1));
+	RREG32(R_0000F0_RBBM_SOFT_RESET);
+	mdelay(500);
+	WREG32(R_0000F0_RBBM_SOFT_RESET, 0);
+	mdelay(1);
+	status = RREG32(R_000E40_RBBM_STATUS);
+	dev_info(rdev->dev, "(%s:%d) RBBM_STATUS=0x%08X\n", __func__, __LINE__, status);
+	/* reset MC */
+	WREG32(R_0000F0_RBBM_SOFT_RESET, S_0000F0_SOFT_RESET_MC(1));
+	RREG32(R_0000F0_RBBM_SOFT_RESET);
+	mdelay(500);
+	WREG32(R_0000F0_RBBM_SOFT_RESET, 0);
+	mdelay(1);
+	status = RREG32(R_000E40_RBBM_STATUS);
+	dev_info(rdev->dev, "(%s:%d) RBBM_STATUS=0x%08X\n", __func__, __LINE__, status);
+	/* restore PCI & busmastering */
+	pci_restore_state(rdev->pdev);
+	/* Check if GPU is idle */
+	if (G_000E40_GA_BUSY(status) || G_000E40_VAP_BUSY(status)) {
+		dev_err(rdev->dev, "failed to reset GPU\n");
+		rdev->gpu_lockup = true;
+		return -1;
+	}
+	rv515_mc_resume(rdev, &save);
+	dev_info(rdev->dev, "GPU reset succeed\n");
+	return 0;
+}
+
 /*
  * GART.
  */
@@ -451,7 +523,6 @@ int rs600_mc_wait_for_idle(struct radeon_device *rdev)
 
 void rs600_gpu_init(struct radeon_device *rdev)
 {
-	r100_hdp_reset(rdev);
 	r420_pipes_init(rdev);
 	/* Wait for mc idle */
 	if (rs600_mc_wait_for_idle(rdev))
diff --git a/drivers/gpu/drm/radeon/rs600d.h b/drivers/gpu/drm/radeon/rs600d.h
index c1c8f58..00896c5 100644
--- a/drivers/gpu/drm/radeon/rs600d.h
+++ b/drivers/gpu/drm/radeon/rs600d.h
@@ -178,6 +178,52 @@
 #define   S_000074_MC_IND_DATA(x)                      (((x) & 0xFFFFFFFF) << 0)
 #define   G_000074_MC_IND_DATA(x)                      (((x) >> 0) & 0xFFFFFFFF)
 #define   C_000074_MC_IND_DATA                         0x00000000
+#define R_0000F0_RBBM_SOFT_RESET                     0x0000F0
+#define   S_0000F0_SOFT_RESET_CP(x)                    (((x) & 0x1) << 0)
+#define   G_0000F0_SOFT_RESET_CP(x)                    (((x) >> 0) & 0x1)
+#define   C_0000F0_SOFT_RESET_CP                       0xFFFFFFFE
+#define   S_0000F0_SOFT_RESET_HI(x)                    (((x) & 0x1) << 1)
+#define   G_0000F0_SOFT_RESET_HI(x)                    (((x) >> 1) & 0x1)
+#define   C_0000F0_SOFT_RESET_HI                       0xFFFFFFFD
+#define   S_0000F0_SOFT_RESET_VAP(x)                   (((x) & 0x1) << 2)
+#define   G_0000F0_SOFT_RESET_VAP(x)                   (((x) >> 2) & 0x1)
+#define   C_0000F0_SOFT_RESET_VAP                      0xFFFFFFFB
+#define   S_0000F0_SOFT_RESET_RE(x)                    (((x) & 0x1) << 3)
+#define   G_0000F0_SOFT_RESET_RE(x)                    (((x) >> 3) & 0x1)
+#define   C_0000F0_SOFT_RESET_RE                       0xFFFFFFF7
+#define   S_0000F0_SOFT_RESET_PP(x)                    (((x) & 0x1) << 4)
+#define   G_0000F0_SOFT_RESET_PP(x)                    (((x) >> 4) & 0x1)
+#define   C_0000F0_SOFT_RESET_PP                       0xFFFFFFEF
+#define   S_0000F0_SOFT_RESET_E2(x)                    (((x) & 0x1) << 5)
+#define   G_0000F0_SOFT_RESET_E2(x)                    (((x) >> 5) & 0x1)
+#define   C_0000F0_SOFT_RESET_E2                       0xFFFFFFDF
+#define   S_0000F0_SOFT_RESET_RB(x)                    (((x) & 0x1) << 6)
+#define   G_0000F0_SOFT_RESET_RB(x)                    (((x) >> 6) & 0x1)
+#define   C_0000F0_SOFT_RESET_RB                       0xFFFFFFBF
+#define   S_0000F0_SOFT_RESET_HDP(x)                   (((x) & 0x1) << 7)
+#define   G_0000F0_SOFT_RESET_HDP(x)                   (((x) >> 7) & 0x1)
+#define   C_0000F0_SOFT_RESET_HDP                      0xFFFFFF7F
+#define   S_0000F0_SOFT_RESET_MC(x)                    (((x) & 0x1) << 8)
+#define   G_0000F0_SOFT_RESET_MC(x)                    (((x) >> 8) & 0x1)
+#define   C_0000F0_SOFT_RESET_MC                       0xFFFFFEFF
+#define   S_0000F0_SOFT_RESET_AIC(x)                   (((x) & 0x1) << 9)
+#define   G_0000F0_SOFT_RESET_AIC(x)                   (((x) >> 9) & 0x1)
+#define   C_0000F0_SOFT_RESET_AIC                      0xFFFFFDFF
+#define   S_0000F0_SOFT_RESET_VIP(x)                   (((x) & 0x1) << 10)
+#define   G_0000F0_SOFT_RESET_VIP(x)                   (((x) >> 10) & 0x1)
+#define   C_0000F0_SOFT_RESET_VIP                      0xFFFFFBFF
+#define   S_0000F0_SOFT_RESET_DISP(x)                  (((x) & 0x1) << 11)
+#define   G_0000F0_SOFT_RESET_DISP(x)                  (((x) >> 11) & 0x1)
+#define   C_0000F0_SOFT_RESET_DISP                     0xFFFFF7FF
+#define   S_0000F0_SOFT_RESET_CG(x)                    (((x) & 0x1) << 12)
+#define   G_0000F0_SOFT_RESET_CG(x)                    (((x) >> 12) & 0x1)
+#define   C_0000F0_SOFT_RESET_CG                       0xFFFFEFFF
+#define   S_0000F0_SOFT_RESET_GA(x)                    (((x) & 0x1) << 13)
+#define   G_0000F0_SOFT_RESET_GA(x)                    (((x) >> 13) & 0x1)
+#define   C_0000F0_SOFT_RESET_GA                       0xFFFFDFFF
+#define   S_0000F0_SOFT_RESET_IDCT(x)                  (((x) & 0x1) << 14)
+#define   G_0000F0_SOFT_RESET_IDCT(x)                  (((x) >> 14) & 0x1)
+#define   C_0000F0_SOFT_RESET_IDCT                     0xFFFFBFFF
 #define R_000134_HDP_FB_LOCATION                     0x000134
 #define   S_000134_HDP_FB_START(x)                     (((x) & 0xFFFF) << 0)
 #define   G_000134_HDP_FB_START(x)                     (((x) >> 0) & 0xFFFF)
diff --git a/drivers/gpu/drm/radeon/rs690.c b/drivers/gpu/drm/radeon/rs690.c
index acd2d8f..9c8f965 100644
--- a/drivers/gpu/drm/radeon/rs690.c
+++ b/drivers/gpu/drm/radeon/rs690.c
@@ -47,8 +47,6 @@ static int rs690_mc_wait_for_idle(struct radeon_device *rdev)
 
 static void rs690_gpu_init(struct radeon_device *rdev)
 {
-	/* FIXME: HDP same place on rs690 ? */
-	r100_hdp_reset(rdev);
 	/* FIXME: is this correct ? */
 	r420_pipes_init(rdev);
 	if (rs690_mc_wait_for_idle(rdev)) {
diff --git a/drivers/gpu/drm/radeon/rv515.c b/drivers/gpu/drm/radeon/rv515.c
index 6b3a697..c3ef420 100644
--- a/drivers/gpu/drm/radeon/rv515.c
+++ b/drivers/gpu/drm/radeon/rv515.c
@@ -145,16 +145,11 @@ void rv515_gpu_init(struct radeon_device *rdev)
 {
 	unsigned pipe_select_current, gb_pipe_select, tmp;
 
-	r100_hdp_reset(rdev);
-	r100_rb2d_reset(rdev);
-
 	if (r100_gui_wait_for_idle(rdev)) {
 		printk(KERN_WARNING "Failed to wait GUI idle while "
 		       "reseting GPU. Bad things might happen.\n");
 	}
-
 	rv515_vga_render_disable(rdev);
-
 	r420_pipes_init(rdev);
 	gb_pipe_select = RREG32(0x402C);
 	tmp = RREG32(0x170C);
@@ -172,91 +167,6 @@ void rv515_gpu_init(struct radeon_device *rdev)
 	}
 }
 
-int rv515_ga_reset(struct radeon_device *rdev)
-{
-	uint32_t tmp;
-	bool reinit_cp;
-	int i;
-
-	reinit_cp = rdev->cp.ready;
-	rdev->cp.ready = false;
-	for (i = 0; i < rdev->usec_timeout; i++) {
-		WREG32(CP_CSQ_MODE, 0);
-		WREG32(CP_CSQ_CNTL, 0);
-		WREG32(RBBM_SOFT_RESET, 0x32005);
-		(void)RREG32(RBBM_SOFT_RESET);
-		udelay(200);
-		WREG32(RBBM_SOFT_RESET, 0);
-		/* Wait to prevent race in RBBM_STATUS */
-		mdelay(1);
-		tmp = RREG32(RBBM_STATUS);
-		if (tmp & ((1 << 20) | (1 << 26))) {
-			DRM_ERROR("VAP & CP still busy (RBBM_STATUS=0x%08X)\n", tmp);
-			/* GA still busy soft reset it */
-			WREG32(0x429C, 0x200);
-			WREG32(VAP_PVS_STATE_FLUSH_REG, 0);
-			WREG32(0x43E0, 0);
-			WREG32(0x43E4, 0);
-			WREG32(0x24AC, 0);
-		}
-		/* Wait to prevent race in RBBM_STATUS */
-		mdelay(1);
-		tmp = RREG32(RBBM_STATUS);
-		if (!(tmp & ((1 << 20) | (1 << 26)))) {
-			break;
-		}
-	}
-	for (i = 0; i < rdev->usec_timeout; i++) {
-		tmp = RREG32(RBBM_STATUS);
-		if (!(tmp & ((1 << 20) | (1 << 26)))) {
-			DRM_INFO("GA reset succeed (RBBM_STATUS=0x%08X)\n",
-				 tmp);
-			DRM_INFO("GA_IDLE=0x%08X\n", RREG32(0x425C));
-			DRM_INFO("RB3D_RESET_STATUS=0x%08X\n", RREG32(0x46f0));
-			DRM_INFO("ISYNC_CNTL=0x%08X\n", RREG32(0x1724));
-			if (reinit_cp) {
-				return r100_cp_init(rdev, rdev->cp.ring_size);
-			}
-			return 0;
-		}
-		DRM_UDELAY(1);
-	}
-	tmp = RREG32(RBBM_STATUS);
-	DRM_ERROR("Failed to reset GA ! (RBBM_STATUS=0x%08X)\n", tmp);
-	return -1;
-}
-
-int rv515_asic_reset(struct radeon_device *rdev)
-{
-	uint32_t status;
-
-	/* reset order likely matter */
-	status = RREG32(RBBM_STATUS);
-	/* reset HDP */
-	r100_hdp_reset(rdev);
-	/* reset rb2d */
-	if (status & ((1 << 17) | (1 << 18) | (1 << 27))) {
-		r100_rb2d_reset(rdev);
-	}
-	/* reset GA */
-	if (status & ((1 << 20) | (1 << 26))) {
-		rv515_ga_reset(rdev);
-	}
-	/* reset CP */
-	status = RREG32(RBBM_STATUS);
-	if (status & (1 << 16)) {
-		r100_cp_reset(rdev);
-	}
-	/* Check if GPU is idle */
-	status = RREG32(RBBM_STATUS);
-	if (status & (1 << 31)) {
-		DRM_ERROR("Failed to reset GPU (RBBM_STATUS=0x%08X)\n", status);
-		return -1;
-	}
-	DRM_INFO("GPU reset succeed (RBBM_STATUS=0x%08X)\n", status);
-	return 0;
-}
-
 static void rv515_vram_get_type(struct radeon_device *rdev)
 {
 	uint32_t tmp;
diff --git a/drivers/gpu/drm/radeon/rv515d.h b/drivers/gpu/drm/radeon/rv515d.h
index fc216e4..590309a 100644
--- a/drivers/gpu/drm/radeon/rv515d.h
+++ b/drivers/gpu/drm/radeon/rv515d.h
@@ -217,6 +217,52 @@
 #define CP_PACKET3_GET_OPCODE(h) (((h) >> 8) & 0xFF)
 
 /* Registers */
+#define R_0000F0_RBBM_SOFT_RESET                     0x0000F0
+#define   S_0000F0_SOFT_RESET_CP(x)                    (((x) & 0x1) << 0)
+#define   G_0000F0_SOFT_RESET_CP(x)                    (((x) >> 0) & 0x1)
+#define   C_0000F0_SOFT_RESET_CP                       0xFFFFFFFE
+#define   S_0000F0_SOFT_RESET_HI(x)                    (((x) & 0x1) << 1)
+#define   G_0000F0_SOFT_RESET_HI(x)                    (((x) >> 1) & 0x1)
+#define   C_0000F0_SOFT_RESET_HI                       0xFFFFFFFD
+#define   S_0000F0_SOFT_RESET_VAP(x)                   (((x) & 0x1) << 2)
+#define   G_0000F0_SOFT_RESET_VAP(x)                   (((x) >> 2) & 0x1)
+#define   C_0000F0_SOFT_RESET_VAP                      0xFFFFFFFB
+#define   S_0000F0_SOFT_RESET_RE(x)                    (((x) & 0x1) << 3)
+#define   G_0000F0_SOFT_RESET_RE(x)                    (((x) >> 3) & 0x1)
+#define   C_0000F0_SOFT_RESET_RE                       0xFFFFFFF7
+#define   S_0000F0_SOFT_RESET_PP(x)                    (((x) & 0x1) << 4)
+#define   G_0000F0_SOFT_RESET_PP(x)                    (((x) >> 4) & 0x1)
+#define   C_0000F0_SOFT_RESET_PP                       0xFFFFFFEF
+#define   S_0000F0_SOFT_RESET_E2(x)                    (((x) & 0x1) << 5)
+#define   G_0000F0_SOFT_RESET_E2(x)                    (((x) >> 5) & 0x1)
+#define   C_0000F0_SOFT_RESET_E2                       0xFFFFFFDF
+#define   S_0000F0_SOFT_RESET_RB(x)                    (((x) & 0x1) << 6)
+#define   G_0000F0_SOFT_RESET_RB(x)                    (((x) >> 6) & 0x1)
+#define   C_0000F0_SOFT_RESET_RB                       0xFFFFFFBF
+#define   S_0000F0_SOFT_RESET_HDP(x)                   (((x) & 0x1) << 7)
+#define   G_0000F0_SOFT_RESET_HDP(x)                   (((x) >> 7) & 0x1)
+#define   C_0000F0_SOFT_RESET_HDP                      0xFFFFFF7F
+#define   S_0000F0_SOFT_RESET_MC(x)                    (((x) & 0x1) << 8)
+#define   G_0000F0_SOFT_RESET_MC(x)                    (((x) >> 8) & 0x1)
+#define   C_0000F0_SOFT_RESET_MC                       0xFFFFFEFF
+#define   S_0000F0_SOFT_RESET_AIC(x)                   (((x) & 0x1) << 9)
+#define   G_0000F0_SOFT_RESET_AIC(x)                   (((x) >> 9) & 0x1)
+#define   C_0000F0_SOFT_RESET_AIC                      0xFFFFFDFF
+#define   S_0000F0_SOFT_RESET_VIP(x)                   (((x) & 0x1) << 10)
+#define   G_0000F0_SOFT_RESET_VIP(x)                   (((x) >> 10) & 0x1)
+#define   C_0000F0_SOFT_RESET_VIP                      0xFFFFFBFF
+#define   S_0000F0_SOFT_RESET_DISP(x)                  (((x) & 0x1) << 11)
+#define   G_0000F0_SOFT_RESET_DISP(x)                  (((x) >> 11) & 0x1)
+#define   C_0000F0_SOFT_RESET_DISP                     0xFFFFF7FF
+#define   S_0000F0_SOFT_RESET_CG(x)                    (((x) & 0x1) << 12)
+#define   G_0000F0_SOFT_RESET_CG(x)                    (((x) >> 12) & 0x1)
+#define   C_0000F0_SOFT_RESET_CG                       0xFFFFEFFF
+#define   S_0000F0_SOFT_RESET_GA(x)                    (((x) & 0x1) << 13)
+#define   G_0000F0_SOFT_RESET_GA(x)                    (((x) >> 13) & 0x1)
+#define   C_0000F0_SOFT_RESET_GA                       0xFFFFDFFF
+#define   S_0000F0_SOFT_RESET_IDCT(x)                  (((x) & 0x1) << 14)
+#define   G_0000F0_SOFT_RESET_IDCT(x)                  (((x) >> 14) & 0x1)
+#define   C_0000F0_SOFT_RESET_IDCT                     0xFFFFBFFF
 #define R_0000F8_CONFIG_MEMSIZE                      0x0000F8
 #define   S_0000F8_CONFIG_MEMSIZE(x)                   (((x) & 0xFFFFFFFF) << 0)
 #define   G_0000F8_CONFIG_MEMSIZE(x)                   (((x) >> 0) & 0xFFFFFFFF)
-- 
1.6.6.1


------------------------------------------------------------------------------
Download Intel&#174; Parallel Studio Eval
Try the new software tools for yourself. Speed compiling, find bugs
proactively, and fine-tune applications for parallel performance.
See why Intel Parallel Studio got high marks during beta.
http://p.sf.net/sfu/intel-sw-dev
--

^ permalink raw reply related	[flat|nested] 5+ messages in thread

* Re: [PATCH 1/3] drm/radeon/kms: fence cleanup + more reliable GPU lockup detection V4
  2010-03-09 14:45 ` [PATCH 1/3] drm/radeon/kms: fence cleanup + more reliable GPU lockup detection V4 Jerome Glisse
  2010-03-09 14:45   ` [PATCH 2/3] drm/radeon/kms: rename gpu_reset to asic_reset Jerome Glisse
@ 2010-03-10 10:34   ` Pauli Nieminen
  1 sibling, 0 replies; 5+ messages in thread
From: Pauli Nieminen @ 2010-03-10 10:34 UTC (permalink / raw)
  To: Jerome Glisse; +Cc: dri-devel

On Tue, Mar 9, 2010 at 4:45 PM, Jerome Glisse <jglisse@redhat.com> wrote:
> This patch cleanup the fence code, it drops the timeout field of
> fence as the time to complete each IB is unpredictable and shouldn't
> be bound.
>
> The fence cleanup lead to GPU lockup detection improvement, this
> patch introduce a callback, allowing to do asic specific test for
> lockup detection. In this patch the CP is use as a first indicator
> of GPU lockup. If CP doesn't make progress during 1second we assume
> we are facing a GPU lockup.
>
> To avoid overhead of testing GPU lockup frequently due to fence
> taking time to be signaled we query the lockup callback every
> 500msec. There is plenty code comment explaining the design & choise
> inside the code.
>
> This have been tested mostly on R3XX/R5XX hw, in normal running
> destkop (compiz firefox, quake3 running) the lockup callback wasn't
> call once (1 hour session). Also tested with forcing GPU lockup and
> lockup was reported after the 1s CP activity timeout.
>
> V2 switch to 500ms timeout so GPU lockup get call at least 2 times
>   in less than 2sec.
> V3 store last jiffies in fence struct so on ERESTART, EBUSY we keep
>   track of how long we already wait for a given fence
> V4 make sure we got up to date cp read pointer so we don't have
>   false positive
>
> Signed-off-by: Jerome Glisse <jglisse@redhat.com>
> ---
>  drivers/gpu/drm/radeon/evergreen.c    |    6 ++
>  drivers/gpu/drm/radeon/r100.c         |   86 +++++++++++++++++++++++++++
>  drivers/gpu/drm/radeon/r300.c         |   28 ++++++++-
>  drivers/gpu/drm/radeon/r600.c         |   34 ++++++++++-
>  drivers/gpu/drm/radeon/radeon.h       |  104 +++++++++++++++++++--------------
>  drivers/gpu/drm/radeon/radeon_asic.h  |   20 ++++++-
>  drivers/gpu/drm/radeon/radeon_fence.c |  102 +++++++++++++++++---------------
>  drivers/gpu/drm/radeon/rv770.c        |    6 --
>  8 files changed, 280 insertions(+), 106 deletions(-)
>
> diff --git a/drivers/gpu/drm/radeon/evergreen.c b/drivers/gpu/drm/radeon/evergreen.c
> index bd2e7aa..8988df7 100644
> --- a/drivers/gpu/drm/radeon/evergreen.c
> +++ b/drivers/gpu/drm/radeon/evergreen.c
> @@ -490,6 +490,12 @@ int evergreen_mc_init(struct radeon_device *rdev)
>        return 0;
>  }
>
> +bool evergreen_gpu_is_lockup(struct radeon_device *rdev)
> +{
> +       /* FIXME: implement for evergreen */
> +       return false;
> +}
> +
>  int evergreen_gpu_reset(struct radeon_device *rdev)
>  {
>        /* FIXME: implement for evergreen */
> diff --git a/drivers/gpu/drm/radeon/r100.c b/drivers/gpu/drm/radeon/r100.c
> index 91eb762..e4487f3 100644
> --- a/drivers/gpu/drm/radeon/r100.c
> +++ b/drivers/gpu/drm/radeon/r100.c
> @@ -1772,6 +1772,92 @@ int r100_rb2d_reset(struct radeon_device *rdev)
>        return -1;
>  }
>
> +void r100_gpu_lockup_update(struct r100_gpu_lockup *lockup, struct radeon_cp *cp)
> +{
> +       lockup->last_cp_rptr = cp->rptr;
> +       lockup->last_jiffies = jiffies;
> +}
> +
> +/**
> + * r100_gpu_cp_is_lockup() - check if CP is lockup by recording information
> + * @rdev:      radeon device structure
> + * @lockup:    r100_gpu_lockup structure holding CP lockup tracking informations
> + * @cp:                radeon_cp structure holding CP information
> + *
> + * We don't need to initialize the lockup tracking information as we will either
> + * have CP rptr to a different value of jiffies wrap around which will force
> + * initialization of the lockup tracking informations.
> + *
> + * A possible false positivie is if we get call after while and last_cp_rptr ==
> + * the current CP rptr, even if it's unlikely it might happen. To avoid this
> + * if the elapsed time since last call is bigger than 2 second than we return
> + * false and update the tracking information. Due to this the caller must call
> + * r100_gpu_cp_is_lockup several time in less than 2sec for lockup to be reported
> + * the fencing code should be cautious about that.
> + *
> + * Caller should write to the ring to force CP to do something so we don't get
> + * false positive when CP is just gived nothing to do.
> + *
> + **/
> +bool r100_gpu_cp_is_lockup(struct radeon_device *rdev, struct r100_gpu_lockup *lockup, struct radeon_cp *cp)
> +{
> +       unsigned long cjiffies, elapsed;
> +
> +       cjiffies = jiffies;
> +       if (!time_after(cjiffies, lockup->last_jiffies)) {

time_after(0x00000010, 0xfeffffff) returns true. time_after macro is
defined to deal correctly with wrapping. Only time when it returns
false is when difference of times is more than the half of maximum
jiffies.

> +               /* likely a wrap around */
> +               lockup->last_cp_rptr = cp->rptr;
> +               lockup->last_jiffies = jiffies;
> +               return false;
> +       }
> +       if (cp->rptr != lockup->last_cp_rptr) {
> +               /* CP is still working no lockup */
> +               lockup->last_cp_rptr = cp->rptr;
> +               lockup->last_jiffies = jiffies;
> +               return false;
> +       }
> +       elapsed = jiffies_to_msecs(cjiffies - lockup->last_jiffies);

This handles the wrapping correctly. (small_jiffies - large_jiffies =
small_difference)

> +       if (elapsed >= 3000) {
> +               /* very likely the improbable case where current
> +                * rptr is equal to last recorded, a while ago, rptr
> +                * this is more likely a false positive update tracking
> +                * information which should force us to be recall at
> +                * latter point
> +                */
> +               lockup->last_cp_rptr = cp->rptr;
> +               lockup->last_jiffies = jiffies;
> +               return false;
> +       }
> +       if (elapsed >= 1000) {
> +               dev_err(rdev->dev, "GPU lockup CP stall for more than %lumsec\n", elapsed);
> +               return true;
> +       }
> +       /* give a chance to the GPU ... */
> +       return false;
> +}
> +
> +bool r100_gpu_is_lockup(struct radeon_device *rdev)
> +{
> +       u32 rbbm_status;
> +       int r;
> +
> +       rbbm_status = RREG32(R_000E40_RBBM_STATUS);
> +       if (!G_000E40_GUI_ACTIVE(rbbm_status)) {
> +               r100_gpu_lockup_update(&rdev->config.r100.lockup, &rdev->cp);
> +               return false;
> +       }
> +       /* force CP activities */
> +       r = radeon_ring_lock(rdev, 2);
> +       if (!r) {
> +               /* PACKET2 NOP */
> +               radeon_ring_write(rdev, 0x80000000);
> +               radeon_ring_write(rdev, 0x80000000);
> +               radeon_ring_unlock_commit(rdev);
> +       }
> +       rdev->cp.rptr = RREG32(RADEON_CP_RB_RPTR);
> +       return r100_gpu_cp_is_lockup(rdev, &rdev->config.r100.lockup, &rdev->cp);
> +}
> +
>  int r100_gpu_reset(struct radeon_device *rdev)
>  {
>        uint32_t status;
> diff --git a/drivers/gpu/drm/radeon/r300.c b/drivers/gpu/drm/radeon/r300.c
> index 4cef90c..23346f6 100644
> --- a/drivers/gpu/drm/radeon/r300.c
> +++ b/drivers/gpu/drm/radeon/r300.c
> @@ -26,8 +26,9 @@
>  *          Jerome Glisse
>  */
>  #include <linux/seq_file.h>
> -#include "drmP.h"
> -#include "drm.h"
> +#include <drm/drmP.h>
> +#include <drm/drm.h>
> +#include <drm/drm_crtc_helper.h>
>  #include "radeon_reg.h"
>  #include "radeon.h"
>  #include "radeon_drm.h"
> @@ -424,12 +425,35 @@ int r300_ga_reset(struct radeon_device *rdev)
>        return -1;
>  }
>
> +bool r300_gpu_is_lockup(struct radeon_device *rdev)
> +{
> +       u32 rbbm_status;
> +       int r;
> +
> +       rbbm_status = RREG32(R_000E40_RBBM_STATUS);
> +       if (!G_000E40_GUI_ACTIVE(rbbm_status)) {
> +               r100_gpu_lockup_update(&rdev->config.r300.lockup, &rdev->cp);
> +               return false;
> +       }
> +       /* force CP activities */
> +       r = radeon_ring_lock(rdev, 2);
> +       if (!r) {
> +               /* PACKET2 NOP */
> +               radeon_ring_write(rdev, 0x80000000);
> +               radeon_ring_write(rdev, 0x80000000);
> +               radeon_ring_unlock_commit(rdev);
> +       }
> +       rdev->cp.rptr = RREG32(RADEON_CP_RB_RPTR);
> +       return r100_gpu_cp_is_lockup(rdev, &rdev->config.r300.lockup, &rdev->cp);
> +}
> +

Is here any difference to r100 version?

>  int r300_gpu_reset(struct radeon_device *rdev)
>  {
>        uint32_t status;
>
>        /* reset order likely matter */
>        status = RREG32(RADEON_RBBM_STATUS);
> +       dev_info(rdev->dev, "(%s:%d) RBBM_STATUS=0x%08X\n", __func__, __LINE__, status);
>        /* reset HDP */
>        r100_hdp_reset(rdev);
>        /* reset rb2d */
> diff --git a/drivers/gpu/drm/radeon/r600.c b/drivers/gpu/drm/radeon/r600.c
> index c522901..4520685 100644
> --- a/drivers/gpu/drm/radeon/r600.c
> +++ b/drivers/gpu/drm/radeon/r600.c
> @@ -788,7 +788,7 @@ int r600_gpu_soft_reset(struct radeon_device *rdev)
>                dev_info(rdev->dev, "  R_008020_GRBM_SOFT_RESET=0x%08X\n", tmp);
>                WREG32(R_008020_GRBM_SOFT_RESET, tmp);
>                (void)RREG32(R_008020_GRBM_SOFT_RESET);
> -               udelay(50);
> +               mdelay(1);
>                WREG32(R_008020_GRBM_SOFT_RESET, 0);
>                (void)RREG32(R_008020_GRBM_SOFT_RESET);
>        }
> @@ -828,16 +828,16 @@ int r600_gpu_soft_reset(struct radeon_device *rdev)
>        dev_info(rdev->dev, "  R_000E60_SRBM_SOFT_RESET=0x%08X\n", srbm_reset);
>        WREG32(R_000E60_SRBM_SOFT_RESET, srbm_reset);
>        (void)RREG32(R_000E60_SRBM_SOFT_RESET);
> -       udelay(50);
> +       mdelay(1);
>        WREG32(R_000E60_SRBM_SOFT_RESET, 0);
>        (void)RREG32(R_000E60_SRBM_SOFT_RESET);
>        WREG32(R_000E60_SRBM_SOFT_RESET, srbm_reset);
>        (void)RREG32(R_000E60_SRBM_SOFT_RESET);
> -       udelay(50);
> +       mdelay(1);
>        WREG32(R_000E60_SRBM_SOFT_RESET, 0);
>        (void)RREG32(R_000E60_SRBM_SOFT_RESET);
>        /* Wait a little for things to settle down */
> -       udelay(50);
> +       mdelay(1);
>        dev_info(rdev->dev, "  R_008010_GRBM_STATUS=0x%08X\n",
>                RREG32(R_008010_GRBM_STATUS));
>        dev_info(rdev->dev, "  R_008014_GRBM_STATUS2=0x%08X\n",
> @@ -852,6 +852,32 @@ int r600_gpu_soft_reset(struct radeon_device *rdev)
>        return 0;
>  }
>
> +bool r600_gpu_is_lockup(struct radeon_device *rdev)
> +{
> +       u32 srbm_status;
> +       u32 grbm_status;
> +       u32 grbm_status2;
> +       int r;
> +
> +       srbm_status = RREG32(R_000E50_SRBM_STATUS);
> +       grbm_status = RREG32(R_008010_GRBM_STATUS);
> +       grbm_status2 = RREG32(R_008014_GRBM_STATUS2);
> +       if (!G_008010_GUI_ACTIVE(grbm_status)) {
> +               r100_gpu_lockup_update(&rdev->config.r300.lockup, &rdev->cp);
> +               return false;
> +       }
> +       /* force CP activities */
> +       r = radeon_ring_lock(rdev, 2);
> +       if (!r) {
> +               /* PACKET2 NOP */
> +               radeon_ring_write(rdev, 0x80000000);
> +               radeon_ring_write(rdev, 0x80000000);
> +               radeon_ring_unlock_commit(rdev);
> +       }
> +       rdev->cp.rptr = RREG32(R600_CP_RB_RPTR);
> +       return r100_gpu_cp_is_lockup(rdev, &rdev->config.r300.lockup, &rdev->cp);
> +}
> +
>  int r600_gpu_reset(struct radeon_device *rdev)
>  {
>        return r600_gpu_soft_reset(rdev);
> diff --git a/drivers/gpu/drm/radeon/radeon.h b/drivers/gpu/drm/radeon/radeon.h
> index 829e26e..e97a118 100644
> --- a/drivers/gpu/drm/radeon/radeon.h
> +++ b/drivers/gpu/drm/radeon/radeon.h
> @@ -97,6 +97,7 @@ extern int radeon_audio;
>  * symbol;
>  */
>  #define RADEON_MAX_USEC_TIMEOUT                100000  /* 100 ms */
> +#define RADEON_FENCE_JIFFIES_TIMEOUT   (HZ / 2)
>  /* RADEON_IB_POOL_SIZE must be a power of 2 */
>  #define RADEON_IB_POOL_SIZE            16
>  #define RADEON_DEBUGFS_MAX_NUM_FILES   32
> @@ -179,7 +180,8 @@ struct radeon_fence_driver {
>        uint32_t                        scratch_reg;
>        atomic_t                        seq;
>        uint32_t                        last_seq;
> -       unsigned long                   count_timeout;
> +       unsigned long                   last_jiffies;
> +       unsigned long                   last_timeout;
>        wait_queue_head_t               queue;
>        rwlock_t                        lock;
>        struct list_head                created;
> @@ -194,7 +196,6 @@ struct radeon_fence {
>        struct list_head                list;
>        /* protected by radeon_fence.lock */
>        uint32_t                        seq;
> -       unsigned long                   timeout;
>        bool                            emited;
>        bool                            signaled;
>  };
> @@ -742,6 +743,7 @@ struct radeon_asic {
>        int (*resume)(struct radeon_device *rdev);
>        int (*suspend)(struct radeon_device *rdev);
>        void (*vga_set_state)(struct radeon_device *rdev, bool state);
> +       bool (*gpu_is_lockup)(struct radeon_device *rdev);
>        int (*gpu_reset)(struct radeon_device *rdev);
>        void (*gart_tlb_flush)(struct radeon_device *rdev);
>        int (*gart_set_page)(struct radeon_device *rdev, int i, uint64_t addr);
> @@ -800,59 +802,68 @@ struct radeon_asic {
>  /*
>  * Asic structures
>  */
> +struct r100_gpu_lockup {
> +       unsigned long   last_jiffies;
> +       u32             last_cp_rptr;
> +};
> +
>  struct r100_asic {
> -       const unsigned  *reg_safe_bm;
> -       unsigned        reg_safe_bm_size;
> -       u32             hdp_cntl;
> +       const unsigned          *reg_safe_bm;
> +       unsigned                reg_safe_bm_size;
> +       u32                     hdp_cntl;
> +       struct r100_gpu_lockup  lockup;
>  };
>
>  struct r300_asic {
> -       const unsigned  *reg_safe_bm;
> -       unsigned        reg_safe_bm_size;
> -       u32             resync_scratch;
> -       u32             hdp_cntl;
> +       const unsigned          *reg_safe_bm;
> +       unsigned                reg_safe_bm_size;
> +       u32                     resync_scratch;
> +       u32                     hdp_cntl;
> +       struct r100_gpu_lockup  lockup;
>  };
>
>  struct r600_asic {
> -       unsigned max_pipes;
> -       unsigned max_tile_pipes;
> -       unsigned max_simds;
> -       unsigned max_backends;
> -       unsigned max_gprs;
> -       unsigned max_threads;
> -       unsigned max_stack_entries;
> -       unsigned max_hw_contexts;
> -       unsigned max_gs_threads;
> -       unsigned sx_max_export_size;
> -       unsigned sx_max_export_pos_size;
> -       unsigned sx_max_export_smx_size;
> -       unsigned sq_num_cf_insts;
> -       unsigned tiling_nbanks;
> -       unsigned tiling_npipes;
> -       unsigned tiling_group_size;
> +       unsigned                max_pipes;
> +       unsigned                max_tile_pipes;
> +       unsigned                max_simds;
> +       unsigned                max_backends;
> +       unsigned                max_gprs;
> +       unsigned                max_threads;
> +       unsigned                max_stack_entries;
> +       unsigned                max_hw_contexts;
> +       unsigned                max_gs_threads;
> +       unsigned                sx_max_export_size;
> +       unsigned                sx_max_export_pos_size;
> +       unsigned                sx_max_export_smx_size;
> +       unsigned                sq_num_cf_insts;
> +       unsigned                tiling_nbanks;
> +       unsigned                tiling_npipes;
> +       unsigned                tiling_group_size;
> +       struct r100_gpu_lockup  lockup;
>  };
>
>  struct rv770_asic {
> -       unsigned max_pipes;
> -       unsigned max_tile_pipes;
> -       unsigned max_simds;
> -       unsigned max_backends;
> -       unsigned max_gprs;
> -       unsigned max_threads;
> -       unsigned max_stack_entries;
> -       unsigned max_hw_contexts;
> -       unsigned max_gs_threads;
> -       unsigned sx_max_export_size;
> -       unsigned sx_max_export_pos_size;
> -       unsigned sx_max_export_smx_size;
> -       unsigned sq_num_cf_insts;
> -       unsigned sx_num_of_sets;
> -       unsigned sc_prim_fifo_size;
> -       unsigned sc_hiz_tile_fifo_size;
> -       unsigned sc_earlyz_tile_fifo_fize;
> -       unsigned tiling_nbanks;
> -       unsigned tiling_npipes;
> -       unsigned tiling_group_size;
> +       unsigned                max_pipes;
> +       unsigned                max_tile_pipes;
> +       unsigned                max_simds;
> +       unsigned                max_backends;
> +       unsigned                max_gprs;
> +       unsigned                max_threads;
> +       unsigned                max_stack_entries;
> +       unsigned                max_hw_contexts;
> +       unsigned                max_gs_threads;
> +       unsigned                sx_max_export_size;
> +       unsigned                sx_max_export_pos_size;
> +       unsigned                sx_max_export_smx_size;
> +       unsigned                sq_num_cf_insts;
> +       unsigned                sx_num_of_sets;
> +       unsigned                sc_prim_fifo_size;
> +       unsigned                sc_hiz_tile_fifo_size;
> +       unsigned                sc_earlyz_tile_fifo_fize;
> +       unsigned                tiling_nbanks;
> +       unsigned                tiling_npipes;
> +       unsigned                tiling_group_size;
> +       struct r100_gpu_lockup  lockup;
>  };
>
>  union radeon_asic_config {
> @@ -1135,6 +1146,7 @@ static inline void radeon_ring_write(struct radeon_device *rdev, uint32_t v)
>  #define radeon_suspend(rdev) (rdev)->asic->suspend((rdev))
>  #define radeon_cs_parse(p) rdev->asic->cs_parse((p))
>  #define radeon_vga_set_state(rdev, state) (rdev)->asic->vga_set_state((rdev), (state))
> +#define radeon_gpu_is_lockup(rdev) (rdev)->asic->gpu_is_lockup((rdev))
>  #define radeon_gpu_reset(rdev) (rdev)->asic->gpu_reset((rdev))
>  #define radeon_gart_tlb_flush(rdev) (rdev)->asic->gart_tlb_flush((rdev))
>  #define radeon_gart_set_page(rdev, i, p) (rdev)->asic->gart_set_page((rdev), (i), (p))
> @@ -1233,6 +1245,8 @@ extern int r100_cs_packet_parse(struct radeon_cs_parser *p,
>                                unsigned idx);
>  extern void r100_enable_bm(struct radeon_device *rdev);
>  extern void r100_set_common_regs(struct radeon_device *rdev);
> +extern void r100_gpu_lockup_update(struct r100_gpu_lockup *lockup, struct radeon_cp *cp);
> +extern bool r100_gpu_cp_is_lockup(struct radeon_device *rdev, struct r100_gpu_lockup *lockup, struct radeon_cp *cp);
>
>  /* rv200,rv250,rv280 */
>  extern void r200_set_safe_registers(struct radeon_device *rdev);
> diff --git a/drivers/gpu/drm/radeon/radeon_asic.h b/drivers/gpu/drm/radeon/radeon_asic.h
> index d3a157b..cb1afb2 100644
> --- a/drivers/gpu/drm/radeon/radeon_asic.h
> +++ b/drivers/gpu/drm/radeon/radeon_asic.h
> @@ -52,6 +52,7 @@ extern int r100_resume(struct radeon_device *rdev);
>  uint32_t r100_mm_rreg(struct radeon_device *rdev, uint32_t reg);
>  void r100_mm_wreg(struct radeon_device *rdev, uint32_t reg, uint32_t v);
>  void r100_vga_set_state(struct radeon_device *rdev, bool state);
> +bool r100_gpu_is_lockup(struct radeon_device *rdev);
>  int r100_gpu_reset(struct radeon_device *rdev);
>  u32 r100_get_vblank_counter(struct radeon_device *rdev, int crtc);
>  void r100_pci_gart_tlb_flush(struct radeon_device *rdev);
> @@ -89,6 +90,7 @@ static struct radeon_asic r100_asic = {
>        .suspend = &r100_suspend,
>        .resume = &r100_resume,
>        .vga_set_state = &r100_vga_set_state,
> +       .gpu_is_lockup = &r100_gpu_is_lockup,
>        .gpu_reset = &r100_gpu_reset,
>        .gart_tlb_flush = &r100_pci_gart_tlb_flush,
>        .gart_set_page = &r100_pci_gart_set_page,
> @@ -135,6 +137,7 @@ static struct radeon_asic r200_asic = {
>        .suspend = &r100_suspend,
>        .resume = &r100_resume,
>        .vga_set_state = &r100_vga_set_state,
> +       .gpu_is_lockup = &r100_gpu_is_lockup,
>        .gpu_reset = &r100_gpu_reset,
>        .gart_tlb_flush = &r100_pci_gart_tlb_flush,
>        .gart_set_page = &r100_pci_gart_set_page,
> @@ -174,6 +177,7 @@ extern int r300_init(struct radeon_device *rdev);
>  extern void r300_fini(struct radeon_device *rdev);
>  extern int r300_suspend(struct radeon_device *rdev);
>  extern int r300_resume(struct radeon_device *rdev);
> +extern bool r300_gpu_is_lockup(struct radeon_device *rdev);
>  extern int r300_gpu_reset(struct radeon_device *rdev);
>  extern void r300_ring_start(struct radeon_device *rdev);
>  extern void r300_fence_ring_emit(struct radeon_device *rdev,
> @@ -192,6 +196,7 @@ static struct radeon_asic r300_asic = {
>        .suspend = &r300_suspend,
>        .resume = &r300_resume,
>        .vga_set_state = &r100_vga_set_state,
> +       .gpu_is_lockup = &r300_gpu_is_lockup,
>        .gpu_reset = &r300_gpu_reset,
>        .gart_tlb_flush = &r100_pci_gart_tlb_flush,
>        .gart_set_page = &r100_pci_gart_set_page,
> @@ -231,6 +236,7 @@ static struct radeon_asic r300_asic_pcie = {
>        .suspend = &r300_suspend,
>        .resume = &r300_resume,
>        .vga_set_state = &r100_vga_set_state,
> +       .gpu_is_lockup = &r300_gpu_is_lockup,
>        .gpu_reset = &r300_gpu_reset,
>        .gart_tlb_flush = &rv370_pcie_gart_tlb_flush,
>        .gart_set_page = &rv370_pcie_gart_set_page,
> @@ -275,6 +281,7 @@ static struct radeon_asic r420_asic = {
>        .suspend = &r420_suspend,
>        .resume = &r420_resume,
>        .vga_set_state = &r100_vga_set_state,
> +       .gpu_is_lockup = &r300_gpu_is_lockup,
>        .gpu_reset = &r300_gpu_reset,
>        .gart_tlb_flush = &rv370_pcie_gart_tlb_flush,
>        .gart_set_page = &rv370_pcie_gart_set_page,
> @@ -325,6 +332,7 @@ static struct radeon_asic rs400_asic = {
>        .suspend = &rs400_suspend,
>        .resume = &rs400_resume,
>        .vga_set_state = &r100_vga_set_state,
> +       .gpu_is_lockup = &r300_gpu_is_lockup,
>        .gpu_reset = &r300_gpu_reset,
>        .gart_tlb_flush = &rs400_gart_tlb_flush,
>        .gart_set_page = &rs400_gart_set_page,
> @@ -385,6 +393,7 @@ static struct radeon_asic rs600_asic = {
>        .suspend = &rs600_suspend,
>        .resume = &rs600_resume,
>        .vga_set_state = &r100_vga_set_state,
> +       .gpu_is_lockup = &r300_gpu_is_lockup,
>        .gpu_reset = &r300_gpu_reset,
>        .gart_tlb_flush = &rs600_gart_tlb_flush,
>        .gart_set_page = &rs600_gart_set_page,
> @@ -434,6 +443,7 @@ static struct radeon_asic rs690_asic = {
>        .suspend = &rs690_suspend,
>        .resume = &rs690_resume,
>        .vga_set_state = &r100_vga_set_state,
> +       .gpu_is_lockup = &r300_gpu_is_lockup,
>        .gpu_reset = &r300_gpu_reset,
>        .gart_tlb_flush = &rs400_gart_tlb_flush,
>        .gart_set_page = &rs400_gart_set_page,
> @@ -487,6 +497,7 @@ static struct radeon_asic rv515_asic = {
>        .suspend = &rv515_suspend,
>        .resume = &rv515_resume,
>        .vga_set_state = &r100_vga_set_state,
> +       .gpu_is_lockup = &r300_gpu_is_lockup,
>        .gpu_reset = &rv515_gpu_reset,
>        .gart_tlb_flush = &rv370_pcie_gart_tlb_flush,
>        .gart_set_page = &rv370_pcie_gart_set_page,
> @@ -531,6 +542,7 @@ static struct radeon_asic r520_asic = {
>        .suspend = &rv515_suspend,
>        .resume = &r520_resume,
>        .vga_set_state = &r100_vga_set_state,
> +       .gpu_is_lockup = &r300_gpu_is_lockup,
>        .gpu_reset = &rv515_gpu_reset,
>        .gart_tlb_flush = &rv370_pcie_gart_tlb_flush,
>        .gart_set_page = &rv370_pcie_gart_set_page,
> @@ -587,6 +599,7 @@ int r600_copy_dma(struct radeon_device *rdev,
>                  struct radeon_fence *fence);
>  int r600_irq_process(struct radeon_device *rdev);
>  int r600_irq_set(struct radeon_device *rdev);
> +bool r600_gpu_is_lockup(struct radeon_device *rdev);
>  int r600_gpu_reset(struct radeon_device *rdev);
>  int r600_set_surface_reg(struct radeon_device *rdev, int reg,
>                         uint32_t tiling_flags, uint32_t pitch,
> @@ -611,6 +624,7 @@ static struct radeon_asic r600_asic = {
>        .resume = &r600_resume,
>        .cp_commit = &r600_cp_commit,
>        .vga_set_state = &r600_vga_set_state,
> +       .gpu_is_lockup = &r600_gpu_is_lockup,
>        .gpu_reset = &r600_gpu_reset,
>        .gart_tlb_flush = &r600_pcie_gart_tlb_flush,
>        .gart_set_page = &rs600_gart_set_page,
> @@ -648,7 +662,6 @@ int rv770_init(struct radeon_device *rdev);
>  void rv770_fini(struct radeon_device *rdev);
>  int rv770_suspend(struct radeon_device *rdev);
>  int rv770_resume(struct radeon_device *rdev);
> -int rv770_gpu_reset(struct radeon_device *rdev);
>
>  static struct radeon_asic rv770_asic = {
>        .init = &rv770_init,
> @@ -656,7 +669,8 @@ static struct radeon_asic rv770_asic = {
>        .suspend = &rv770_suspend,
>        .resume = &rv770_resume,
>        .cp_commit = &r600_cp_commit,
> -       .gpu_reset = &rv770_gpu_reset,
> +       .gpu_is_lockup = &r600_gpu_is_lockup,
> +       .gpu_reset = &r600_gpu_reset,
>        .vga_set_state = &r600_vga_set_state,
>        .gart_tlb_flush = &r600_pcie_gart_tlb_flush,
>        .gart_set_page = &rs600_gart_set_page,
> @@ -694,6 +708,7 @@ int evergreen_init(struct radeon_device *rdev);
>  void evergreen_fini(struct radeon_device *rdev);
>  int evergreen_suspend(struct radeon_device *rdev);
>  int evergreen_resume(struct radeon_device *rdev);
> +bool evergreen_gpu_is_lockup(struct radeon_device *rdev);
>  int evergreen_gpu_reset(struct radeon_device *rdev);
>  void evergreen_bandwidth_update(struct radeon_device *rdev);
>  void evergreen_hpd_init(struct radeon_device *rdev);
> @@ -708,6 +723,7 @@ static struct radeon_asic evergreen_asic = {
>        .suspend = &evergreen_suspend,
>        .resume = &evergreen_resume,
>        .cp_commit = NULL,
> +       .gpu_is_lockup = &evergreen_gpu_is_lockup,
>        .gpu_reset = &evergreen_gpu_reset,
>        .vga_set_state = &r600_vga_set_state,
>        .gart_tlb_flush = &r600_pcie_gart_tlb_flush,
> diff --git a/drivers/gpu/drm/radeon/radeon_fence.c b/drivers/gpu/drm/radeon/radeon_fence.c
> index 8495d4e..3931542 100644
> --- a/drivers/gpu/drm/radeon/radeon_fence.c
> +++ b/drivers/gpu/drm/radeon/radeon_fence.c
> @@ -57,7 +57,6 @@ int radeon_fence_emit(struct radeon_device *rdev, struct radeon_fence *fence)
>                radeon_fence_ring_emit(rdev, fence);
>
>        fence->emited = true;
> -       fence->timeout = jiffies + ((2000 * HZ) / 1000);
>        list_del(&fence->list);
>        list_add_tail(&fence->list, &rdev->fence_drv.emited);
>        write_unlock_irqrestore(&rdev->fence_drv.lock, irq_flags);
> @@ -70,15 +69,34 @@ static bool radeon_fence_poll_locked(struct radeon_device *rdev)
>        struct list_head *i, *n;
>        uint32_t seq;
>        bool wake = false;
> +       unsigned long cjiffies;
>
> -       if (rdev == NULL) {
> -               return true;
> -       }
> -       if (rdev->shutdown) {
> -               return true;
> -       }
>        seq = RREG32(rdev->fence_drv.scratch_reg);
> -       rdev->fence_drv.last_seq = seq;
> +       if (seq != rdev->fence_drv.last_seq) {
> +               rdev->fence_drv.last_seq = seq;
> +               rdev->fence_drv.last_jiffies = jiffies;
> +               rdev->fence_drv.last_timeout = RADEON_FENCE_JIFFIES_TIMEOUT;
> +       } else {
> +               cjiffies = jiffies;
> +               if (time_after(cjiffies, rdev->fence_drv.last_jiffies)) {
> +                       cjiffies -= rdev->fence_drv.last_jiffies;
> +                       if (time_after(rdev->fence_drv.last_timeout, cjiffies)) {
> +                               /* update the timeout */
> +                               rdev->fence_drv.last_timeout -= cjiffies;
> +                       } else {
> +                               /* the 500ms timeout is elapsed we should test
> +                                * for GPU lockup
> +                                */
> +                               rdev->fence_drv.last_timeout = 1;
> +                       }
> +               } else {
> +                       /* wrap around update last jiffies, we will just wait
> +                        * a little longer
> +                        */
> +                       rdev->fence_drv.last_jiffies = cjiffies;
> +               }
If we hit this else branch we were stalled for more than max_jiffies/2
time that would mean bad stuff in any case.
> +               return false;
> +       }
>        n = NULL;
>        list_for_each(i, &rdev->fence_drv.emited) {
>                fence = list_entry(i, struct radeon_fence, list);
> @@ -170,9 +188,8 @@ bool radeon_fence_signaled(struct radeon_fence *fence)
>  int radeon_fence_wait(struct radeon_fence *fence, bool intr)
>  {
>        struct radeon_device *rdev;
> -       unsigned long cur_jiffies;
> -       unsigned long timeout;
> -       bool expired = false;
> +       unsigned long irq_flags, timeout;
> +       u32 seq;
>        int r;
>
>        if (fence == NULL) {
> @@ -183,14 +200,10 @@ int radeon_fence_wait(struct radeon_fence *fence, bool intr)
>        if (radeon_fence_signaled(fence)) {
>                return 0;
>        }
> -
> +       timeout = rdev->fence_drv.last_timeout;
>  retry:
> -       cur_jiffies = jiffies;
> -       timeout = HZ / 100;
> -       if (time_after(fence->timeout, cur_jiffies)) {
> -               timeout = fence->timeout - cur_jiffies;
> -       }
> -
> +       /* save current sequence used to check for GPU lockup */
> +       seq = rdev->fence_drv.last_seq;
>        if (intr) {
>                radeon_irq_kms_sw_irq_get(rdev);
>                r = wait_event_interruptible_timeout(rdev->fence_drv.queue,
> @@ -205,38 +218,34 @@ retry:
>                radeon_irq_kms_sw_irq_put(rdev);
>        }
>        if (unlikely(!radeon_fence_signaled(fence))) {
> -               if (unlikely(r == 0)) {
> -                       expired = true;
> +               /* we were interrupted for some reason and fence isn't
> +                * isn't signaled yet, resume wait
> +                */
> +               if (r) {
> +                       timeout = r;
> +                       goto retry;
>                }
> -               if (unlikely(expired)) {
> -                       timeout = 1;
> -                       if (time_after(cur_jiffies, fence->timeout)) {
> -                               timeout = cur_jiffies - fence->timeout;
> -                       }
> -                       timeout = jiffies_to_msecs(timeout);
> -                       if (timeout > 500) {
> -                               DRM_ERROR("fence(%p:0x%08X) %lums timeout "
> -                                         "going to reset GPU\n",
> -                                         fence, fence->seq, timeout);
> -                               radeon_gpu_reset(rdev);
> -                               WREG32(rdev->fence_drv.scratch_reg, fence->seq);
> -                       }
> +               /* don't protect read access to rdev->fence_drv.last_seq
> +                * if we experiencing a lockup the value doesn't change
> +                */
> +               if (seq == rdev->fence_drv.last_seq && radeon_gpu_is_lockup(rdev)) {
> +                       /* good news we believe it's a lockup */
> +                       dev_warn(rdev->dev, "GPU lockup (last fence id 0x%08X)\n", seq);
> +                       r = radeon_gpu_reset(rdev);
> +                       if (r)
> +                               return r;
> +                       /* FIXME: what should we do ? marking everyone
> +                        * as signaled for now
> +                        */
> +                       WREG32(rdev->fence_drv.scratch_reg, fence->seq);
>                }
> +               timeout = RADEON_FENCE_JIFFIES_TIMEOUT;
> +               write_lock_irqsave(&rdev->fence_drv.lock, irq_flags);
> +               rdev->fence_drv.last_timeout = RADEON_FENCE_JIFFIES_TIMEOUT;
> +               rdev->fence_drv.last_jiffies = jiffies;
> +               write_unlock_irqrestore(&rdev->fence_drv.lock, irq_flags);
>                goto retry;
>        }
> -       if (unlikely(expired)) {
> -               rdev->fence_drv.count_timeout++;
> -               cur_jiffies = jiffies;
> -               timeout = 1;
> -               if (time_after(cur_jiffies, fence->timeout)) {
> -                       timeout = cur_jiffies - fence->timeout;
> -               }
> -               timeout = jiffies_to_msecs(timeout);
> -               DRM_ERROR("fence(%p:0x%08X) %lums timeout\n",
> -                         fence, fence->seq, timeout);
> -               DRM_ERROR("last signaled fence(0x%08X)\n",
> -                         rdev->fence_drv.last_seq);
> -       }
>        return 0;
>  }
>
> @@ -332,7 +341,6 @@ int radeon_fence_driver_init(struct radeon_device *rdev)
>        INIT_LIST_HEAD(&rdev->fence_drv.created);
>        INIT_LIST_HEAD(&rdev->fence_drv.emited);
>        INIT_LIST_HEAD(&rdev->fence_drv.signaled);
> -       rdev->fence_drv.count_timeout = 0;
>        init_waitqueue_head(&rdev->fence_drv.queue);
>        rdev->fence_drv.initialized = true;
>        write_unlock_irqrestore(&rdev->fence_drv.lock, irq_flags);
> diff --git a/drivers/gpu/drm/radeon/rv770.c b/drivers/gpu/drm/radeon/rv770.c
> index 37887de..16c793b 100644
> --- a/drivers/gpu/drm/radeon/rv770.c
> +++ b/drivers/gpu/drm/radeon/rv770.c
> @@ -917,12 +917,6 @@ int rv770_mc_init(struct radeon_device *rdev)
>        return 0;
>  }
>
> -int rv770_gpu_reset(struct radeon_device *rdev)
> -{
> -       /* FIXME: implement any rv770 specific bits */
> -       return r600_gpu_reset(rdev);
> -}
> -
>  static int rv770_startup(struct radeon_device *rdev)
>  {
>        int r;
> --
> 1.6.6.1
>

It would be good idea to check if jiffies are ticking anytime when we
can't run the driver code.(like suspend) I don't think there should be
any case but it would be better to be safe than sorry.

------------------------------------------------------------------------------
Download Intel&#174; Parallel Studio Eval
Try the new software tools for yourself. Speed compiling, find bugs
proactively, and fine-tune applications for parallel performance.
See why Intel Parallel Studio got high marks during beta.
http://p.sf.net/sfu/intel-sw-dev
--

^ permalink raw reply	[flat|nested] 5+ messages in thread

end of thread, other threads:[~2010-03-10 10:34 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2010-03-09 14:45 Improved GPU reset Jerome Glisse
2010-03-09 14:45 ` [PATCH 1/3] drm/radeon/kms: fence cleanup + more reliable GPU lockup detection V4 Jerome Glisse
2010-03-09 14:45   ` [PATCH 2/3] drm/radeon/kms: rename gpu_reset to asic_reset Jerome Glisse
2010-03-09 14:45     ` [PATCH 3/3] drm/radeon/kms: simplify & improve GPU reset V2 Jerome Glisse
2010-03-10 10:34   ` [PATCH 1/3] drm/radeon/kms: fence cleanup + more reliable GPU lockup detection V4 Pauli Nieminen

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.