From b45305fce5bb1abec263fcff9d81ebecd6306ede Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Mon, 17 Dec 2012 16:21:27 +0100 Subject: drm/i915: Implement workaround for broken CS tlb on i830/845 Now that Chris Wilson demonstrated that the key for stability on early gen 2 is to simple _never_ exchange the physical backing storage of batch buffers I've tried a stab at a kernel solution. Doesn't look too nefarious imho, now that I don't try to be too clever for my own good any more. v2: After discussing the various techniques, we've decided to always blit batches on the suspect devices, but allow userspace to opt out of the kernel workaround assume full responsibility for providing coherent batches. The principal reason is that avoiding the blit does improve performance in a few key microbenchmarks and also in cairo-trace replays. Signed-Off-by: Daniel Vetter Signed-off-by: Chris Wilson [danvet: - Drop the hunk which uses HAS_BROKEN_CS_TLB to implement the ring wrap w/a. Suggested by Chris Wilson. - Also add the ACTHD check from Chris Wilson for the error state dumping, so that we still catch batches when userspace opts out of the w/a.] Signed-off-by: Daniel Vetter --- include/uapi/drm/i915_drm.h | 10 ++++++++++ 1 file changed, 10 insertions(+) (limited to 'include') diff --git a/include/uapi/drm/i915_drm.h b/include/uapi/drm/i915_drm.h index b746a3cf5fa..c4d2e9c7400 100644 --- a/include/uapi/drm/i915_drm.h +++ b/include/uapi/drm/i915_drm.h @@ -307,6 +307,7 @@ typedef struct drm_i915_irq_wait { #define I915_PARAM_HAS_PRIME_VMAP_FLUSH 21 #define I915_PARAM_RSVD_FOR_FUTURE_USE 22 #define I915_PARAM_HAS_SECURE_BATCHES 23 +#define I915_PARAM_HAS_PINNED_BATCHES 24 typedef struct drm_i915_getparam { int param; @@ -677,6 +678,15 @@ struct drm_i915_gem_execbuffer2 { */ #define I915_EXEC_SECURE (1<<9) +/** Inform the kernel that the batch is and will always be pinned. This + * negates the requirement for a workaround to be performed to avoid + * an incoherent CS (such as can be found on 830/845). If this flag is + * not passed, the kernel will endeavour to make sure the batch is + * coherent with the CS before execution. If this flag is passed, + * userspace assumes the responsibility for ensuring the same. + */ +#define I915_EXEC_IS_PINNED (1<<10) + #define I915_EXEC_CONTEXT_ID_MASK (0xffffffff) #define i915_execbuffer2_set_context_id(eb2, context) \ (eb2).rsvd1 = context & I915_EXEC_CONTEXT_ID_MASK -- cgit v1.2.3-70-g09d2 From b81034506fc9b879cb726feb01342be0cdbe6e25 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Fri, 7 Dec 2012 20:37:06 +0000 Subject: drm: Export routines for inserting preallocated nodes into the mm manager Required by i915 in order to avoid the allocation in the middle of manipulating the drm_mm lists. Use a pair of stubs to preserve the existing EXPORT_SYMBOLs for backporting; to be removed later. Cc: Dave Airlie Cc: dri-devel@lists.freedesktop.org Signed-off-by: Chris Wilson Reviewed-by: Jani Nikula [danvet: bikeshedded-away the atomic parameter, it's not yet used anywhere.] Acked-by: Dave Airlie Signed-off-by: Daniel Vetter --- drivers/gpu/drm/drm_mm.c | 41 +++++++++++++++++++++++++++++------------ include/drm/drm_mm.h | 25 +++++++++++++++++++++---- 2 files changed, 50 insertions(+), 16 deletions(-) (limited to 'include') diff --git a/drivers/gpu/drm/drm_mm.c b/drivers/gpu/drm/drm_mm.c index 0761a03cdbb..2bf9670ba29 100644 --- a/drivers/gpu/drm/drm_mm.c +++ b/drivers/gpu/drm/drm_mm.c @@ -184,19 +184,27 @@ EXPORT_SYMBOL(drm_mm_get_block_generic); * -ENOSPC if no suitable free area is available. The preallocated memory node * must be cleared. */ -int drm_mm_insert_node(struct drm_mm *mm, struct drm_mm_node *node, - unsigned long size, unsigned alignment) +int drm_mm_insert_node_generic(struct drm_mm *mm, struct drm_mm_node *node, + unsigned long size, unsigned alignment, + unsigned long color) { struct drm_mm_node *hole_node; - hole_node = drm_mm_search_free(mm, size, alignment, false); + hole_node = drm_mm_search_free_generic(mm, size, alignment, + color, 0); if (!hole_node) return -ENOSPC; - drm_mm_insert_helper(hole_node, node, size, alignment, 0); - + drm_mm_insert_helper(hole_node, node, size, alignment, color); return 0; } +EXPORT_SYMBOL(drm_mm_insert_node_generic); + +int drm_mm_insert_node(struct drm_mm *mm, struct drm_mm_node *node, + unsigned long size, unsigned alignment) +{ + return drm_mm_insert_node_generic(mm, node, size, alignment, 0); +} EXPORT_SYMBOL(drm_mm_insert_node); static void drm_mm_insert_helper_range(struct drm_mm_node *hole_node, @@ -275,22 +283,31 @@ EXPORT_SYMBOL(drm_mm_get_block_range_generic); * -ENOSPC if no suitable free area is available. This is for range * restricted allocations. The preallocated memory node must be cleared. */ -int drm_mm_insert_node_in_range(struct drm_mm *mm, struct drm_mm_node *node, - unsigned long size, unsigned alignment, - unsigned long start, unsigned long end) +int drm_mm_insert_node_in_range_generic(struct drm_mm *mm, struct drm_mm_node *node, + unsigned long size, unsigned alignment, unsigned long color, + unsigned long start, unsigned long end) { struct drm_mm_node *hole_node; - hole_node = drm_mm_search_free_in_range(mm, size, alignment, - start, end, false); + hole_node = drm_mm_search_free_in_range_generic(mm, + size, alignment, color, + start, end, 0); if (!hole_node) return -ENOSPC; - drm_mm_insert_helper_range(hole_node, node, size, alignment, 0, + drm_mm_insert_helper_range(hole_node, node, + size, alignment, color, start, end); - return 0; } +EXPORT_SYMBOL(drm_mm_insert_node_in_range_generic); + +int drm_mm_insert_node_in_range(struct drm_mm *mm, struct drm_mm_node *node, + unsigned long size, unsigned alignment, + unsigned long start, unsigned long end) +{ + return drm_mm_insert_node_in_range_generic(mm, node, size, alignment, 0, start, end); +} EXPORT_SYMBOL(drm_mm_insert_node_in_range); /** diff --git a/include/drm/drm_mm.h b/include/drm/drm_mm.h index 06d7f798a08..0f4a366f6fa 100644 --- a/include/drm/drm_mm.h +++ b/include/drm/drm_mm.h @@ -158,12 +158,29 @@ static inline struct drm_mm_node *drm_mm_get_block_atomic_range( return drm_mm_get_block_range_generic(parent, size, alignment, 0, start, end, 1); } -extern int drm_mm_insert_node(struct drm_mm *mm, struct drm_mm_node *node, - unsigned long size, unsigned alignment); + +extern int drm_mm_insert_node(struct drm_mm *mm, + struct drm_mm_node *node, + unsigned long size, + unsigned alignment); extern int drm_mm_insert_node_in_range(struct drm_mm *mm, struct drm_mm_node *node, - unsigned long size, unsigned alignment, - unsigned long start, unsigned long end); + unsigned long size, + unsigned alignment, + unsigned long start, + unsigned long end); +extern int drm_mm_insert_node_generic(struct drm_mm *mm, + struct drm_mm_node *node, + unsigned long size, + unsigned alignment, + unsigned long color); +extern int drm_mm_insert_node_in_range_generic(struct drm_mm *mm, + struct drm_mm_node *node, + unsigned long size, + unsigned alignment, + unsigned long color, + unsigned long start, + unsigned long end); extern void drm_mm_put_block(struct drm_mm_node *cur); extern void drm_mm_remove_node(struct drm_mm_node *node); extern void drm_mm_replace_node(struct drm_mm_node *old, struct drm_mm_node *new); -- cgit v1.2.3-70-g09d2