public inbox for linux-kernel@vger.kernel.org
 help / color / mirror / Atom feed
From: Greg KH <gregkh@suse.de>
To: linux-kernel@vger.kernel.org, stable@kernel.org
Cc: stable-review@kernel.org, torvalds@linux-foundation.org,
	akpm@linux-foundation.org, alan@lxorguk.ukuu.org.uk,
	Jesse Barnes <jbarnes@virtuousgeek.org>,
	Eric Anholt <eric@anholt.net>
Subject: [13/39] drm/i915: use PIPE_CONTROL instruction on Ironlake and Sandy Bridge
Date: Mon, 24 May 2010 16:15:25 -0700	[thread overview]
Message-ID: <20100524231814.368901082@clark.site> (raw)
In-Reply-To: <20100524231840.GA17857@kroah.com>


2.6.33-stable review patch.  If anyone has any objections, please let us know.

------------------
From: Jesse Barnes <jbarnes@virtuousgeek.org>

commit e552eb7038a36d9b18860f525aa02875e313fe16 upstream.

Since 965, the hardware has supported the PIPE_CONTROL command, which
provides fine grained GPU cache flushing control.  On recent chipsets,
this instruction is required for reliable interrupt and sequence number
reporting in the driver.

So add support for this instruction, including workarounds, on Ironlake
and Sandy Bridge hardware.

https://bugs.freedesktop.org/show_bug.cgi?id=27108

Signed-off-by: Jesse Barnes <jbarnes@virtuousgeek.org>
Tested-by: Chris Wilson <chris@chris-wilson.co.uk>
Signed-off-by: Eric Anholt <eric@anholt.net>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>

---
 drivers/gpu/drm/i915/i915_drv.h |    4 +
 drivers/gpu/drm/i915/i915_gem.c |  145 ++++++++++++++++++++++++++++++++++++----
 drivers/gpu/drm/i915/i915_irq.c |    8 +-
 drivers/gpu/drm/i915/i915_reg.h |   11 +++
 4 files changed, 152 insertions(+), 16 deletions(-)

--- a/drivers/gpu/drm/i915/i915_drv.h
+++ b/drivers/gpu/drm/i915/i915_drv.h
@@ -206,11 +206,14 @@ typedef struct drm_i915_private {
 
 	drm_dma_handle_t *status_page_dmah;
 	void *hw_status_page;
+	void *seqno_page;
 	dma_addr_t dma_status_page;
 	uint32_t counter;
 	unsigned int status_gfx_addr;
+	unsigned int seqno_gfx_addr;
 	drm_local_map_t hws_map;
 	struct drm_gem_object *hws_obj;
+	struct drm_gem_object *seqno_obj;
 	struct drm_gem_object *pwrctx;
 
 	struct resource mch_res;
@@ -1090,6 +1093,7 @@ extern int i915_wait_ring(struct drm_dev
 
 #define HAS_PCH_SPLIT(dev) (IS_IRONLAKE(dev) ||	\
 			    IS_GEN6(dev))
+#define HAS_PIPE_CONTROL(dev) (IS_IRONLAKE(dev) || IS_GEN6(dev))
 
 #define PRIMARY_RINGBUFFER_SIZE         (128*1024)
 
--- a/drivers/gpu/drm/i915/i915_gem.c
+++ b/drivers/gpu/drm/i915/i915_gem.c
@@ -1559,6 +1559,13 @@ i915_gem_object_move_to_inactive(struct
 	i915_verify_inactive(dev, __FILE__, __LINE__);
 }
 
+#define PIPE_CONTROL_FLUSH(addr)					\
+	OUT_RING(GFX_OP_PIPE_CONTROL | PIPE_CONTROL_QW_WRITE |		\
+		 PIPE_CONTROL_DEPTH_STALL);				\
+	OUT_RING(addr | PIPE_CONTROL_GLOBAL_GTT);			\
+	OUT_RING(0);							\
+	OUT_RING(0);							\
+
 /**
  * Creates a new sequence number, emitting a write of it to the status page
  * plus an interrupt, which will trigger i915_user_interrupt_handler.
@@ -1593,13 +1600,47 @@ i915_add_request(struct drm_device *dev,
 	if (dev_priv->mm.next_gem_seqno == 0)
 		dev_priv->mm.next_gem_seqno++;
 
-	BEGIN_LP_RING(4);
-	OUT_RING(MI_STORE_DWORD_INDEX);
-	OUT_RING(I915_GEM_HWS_INDEX << MI_STORE_DWORD_INDEX_SHIFT);
-	OUT_RING(seqno);
+	if (HAS_PIPE_CONTROL(dev)) {
+		u32 scratch_addr = dev_priv->seqno_gfx_addr + 128;
 
-	OUT_RING(MI_USER_INTERRUPT);
-	ADVANCE_LP_RING();
+		/*
+		 * Workaround qword write incoherence by flushing the
+		 * PIPE_NOTIFY buffers out to memory before requesting
+		 * an interrupt.
+		 */
+		BEGIN_LP_RING(32);
+		OUT_RING(GFX_OP_PIPE_CONTROL | PIPE_CONTROL_QW_WRITE |
+			 PIPE_CONTROL_WC_FLUSH | PIPE_CONTROL_TC_FLUSH);
+		OUT_RING(dev_priv->seqno_gfx_addr | PIPE_CONTROL_GLOBAL_GTT);
+		OUT_RING(seqno);
+		OUT_RING(0);
+		PIPE_CONTROL_FLUSH(scratch_addr);
+		scratch_addr += 128; /* write to separate cachelines */
+		PIPE_CONTROL_FLUSH(scratch_addr);
+		scratch_addr += 128;
+		PIPE_CONTROL_FLUSH(scratch_addr);
+		scratch_addr += 128;
+		PIPE_CONTROL_FLUSH(scratch_addr);
+		scratch_addr += 128;
+		PIPE_CONTROL_FLUSH(scratch_addr);
+		scratch_addr += 128;
+		PIPE_CONTROL_FLUSH(scratch_addr);
+		OUT_RING(GFX_OP_PIPE_CONTROL | PIPE_CONTROL_QW_WRITE |
+			 PIPE_CONTROL_WC_FLUSH | PIPE_CONTROL_TC_FLUSH |
+			 PIPE_CONTROL_NOTIFY);
+		OUT_RING(dev_priv->seqno_gfx_addr | PIPE_CONTROL_GLOBAL_GTT);
+		OUT_RING(seqno);
+		OUT_RING(0);
+		ADVANCE_LP_RING();
+	} else {
+		BEGIN_LP_RING(4);
+		OUT_RING(MI_STORE_DWORD_INDEX);
+		OUT_RING(I915_GEM_HWS_INDEX << MI_STORE_DWORD_INDEX_SHIFT);
+		OUT_RING(seqno);
+
+		OUT_RING(MI_USER_INTERRUPT);
+		ADVANCE_LP_RING();
+	}
 
 	DRM_DEBUG_DRIVER("%d\n", seqno);
 
@@ -1744,7 +1785,10 @@ i915_get_gem_seqno(struct drm_device *de
 {
 	drm_i915_private_t *dev_priv = dev->dev_private;
 
-	return READ_HWSP(dev_priv, I915_GEM_HWS_INDEX);
+	if (IS_I965G(dev))
+		return ((volatile u32 *)(dev_priv->seqno_page))[0];
+	else
+		return READ_HWSP(dev_priv, I915_GEM_HWS_INDEX);
 }
 
 /**
@@ -4576,6 +4620,49 @@ i915_gem_idle(struct drm_device *dev)
 	return 0;
 }
 
+/*
+ * 965+ support PIPE_CONTROL commands, which provide finer grained control
+ * over cache flushing.
+ */
+static int
+i915_gem_init_pipe_control(struct drm_device *dev)
+{
+	drm_i915_private_t *dev_priv = dev->dev_private;
+	struct drm_gem_object *obj;
+	struct drm_i915_gem_object *obj_priv;
+	int ret;
+
+	obj = drm_gem_object_alloc(dev, 4096);
+	if (obj == NULL) {
+		DRM_ERROR("Failed to allocate seqno page\n");
+		ret = -ENOMEM;
+		goto err;
+	}
+	obj_priv = obj->driver_private;
+	obj_priv->agp_type = AGP_USER_CACHED_MEMORY;
+
+	ret = i915_gem_object_pin(obj, 4096);
+	if (ret)
+		goto err_unref;
+
+	dev_priv->seqno_gfx_addr = obj_priv->gtt_offset;
+	dev_priv->seqno_page =  kmap(obj_priv->pages[0]);
+	if (dev_priv->seqno_page == NULL)
+		goto err_unpin;
+
+	dev_priv->seqno_obj = obj;
+	memset(dev_priv->seqno_page, 0, PAGE_SIZE);
+
+	return 0;
+
+err_unpin:
+	i915_gem_object_unpin(obj);
+err_unref:
+	drm_gem_object_unreference(obj);
+err:
+	return ret;
+}
+
 static int
 i915_gem_init_hws(struct drm_device *dev)
 {
@@ -4593,7 +4680,8 @@ i915_gem_init_hws(struct drm_device *dev
 	obj = drm_gem_object_alloc(dev, 4096);
 	if (obj == NULL) {
 		DRM_ERROR("Failed to allocate status page\n");
-		return -ENOMEM;
+		ret = -ENOMEM;
+		goto err;
 	}
 	obj_priv = obj->driver_private;
 	obj_priv->agp_type = AGP_USER_CACHED_MEMORY;
@@ -4601,7 +4689,7 @@ i915_gem_init_hws(struct drm_device *dev
 	ret = i915_gem_object_pin(obj, 4096);
 	if (ret != 0) {
 		drm_gem_object_unreference(obj);
-		return ret;
+		goto err_unref;
 	}
 
 	dev_priv->status_gfx_addr = obj_priv->gtt_offset;
@@ -4610,10 +4698,16 @@ i915_gem_init_hws(struct drm_device *dev
 	if (dev_priv->hw_status_page == NULL) {
 		DRM_ERROR("Failed to map status page.\n");
 		memset(&dev_priv->hws_map, 0, sizeof(dev_priv->hws_map));
-		i915_gem_object_unpin(obj);
-		drm_gem_object_unreference(obj);
-		return -EINVAL;
+		ret = -EINVAL;
+		goto err_unpin;
 	}
+
+	if (HAS_PIPE_CONTROL(dev)) {
+		ret = i915_gem_init_pipe_control(dev);
+		if (ret)
+			goto err_unpin;
+	}
+
 	dev_priv->hws_obj = obj;
 	memset(dev_priv->hw_status_page, 0, PAGE_SIZE);
 	I915_WRITE(HWS_PGA, dev_priv->status_gfx_addr);
@@ -4621,6 +4715,30 @@ i915_gem_init_hws(struct drm_device *dev
 	DRM_DEBUG_DRIVER("hws offset: 0x%08x\n", dev_priv->status_gfx_addr);
 
 	return 0;
+
+err_unpin:
+	i915_gem_object_unpin(obj);
+err_unref:
+	drm_gem_object_unreference(obj);
+err:
+	return 0;
+}
+
+static void
+i915_gem_cleanup_pipe_control(struct drm_device *dev)
+{
+	drm_i915_private_t *dev_priv = dev->dev_private;
+	struct drm_gem_object *obj;
+	struct drm_i915_gem_object *obj_priv;
+
+	obj = dev_priv->seqno_obj;
+	obj_priv = obj->driver_private;
+	kunmap(obj_priv->pages[0]);
+	i915_gem_object_unpin(obj);
+	drm_gem_object_unreference(obj);
+	dev_priv->seqno_obj = NULL;
+
+	dev_priv->seqno_page = NULL;
 }
 
 static void
@@ -4644,6 +4762,9 @@ i915_gem_cleanup_hws(struct drm_device *
 	memset(&dev_priv->hws_map, 0, sizeof(dev_priv->hws_map));
 	dev_priv->hw_status_page = NULL;
 
+	if (HAS_PIPE_CONTROL(dev))
+		i915_gem_cleanup_pipe_control(dev);
+
 	/* Write high address into HWS_PGA when disabling. */
 	I915_WRITE(HWS_PGA, 0x1ffff000);
 }
--- a/drivers/gpu/drm/i915/i915_irq.c
+++ b/drivers/gpu/drm/i915/i915_irq.c
@@ -297,7 +297,7 @@ irqreturn_t ironlake_irq_handler(struct
 				READ_BREADCRUMB(dev_priv);
 	}
 
-	if (gt_iir & GT_USER_INTERRUPT) {
+	if (gt_iir & GT_PIPE_NOTIFY) {
 		u32 seqno = i915_get_gem_seqno(dev);
 		dev_priv->mm.irq_gem_seqno = seqno;
 		trace_i915_gem_request_complete(dev, seqno);
@@ -738,7 +738,7 @@ void i915_user_irq_get(struct drm_device
 	spin_lock_irqsave(&dev_priv->user_irq_lock, irqflags);
 	if (dev->irq_enabled && (++dev_priv->user_irq_refcount == 1)) {
 		if (HAS_PCH_SPLIT(dev))
-			ironlake_enable_graphics_irq(dev_priv, GT_USER_INTERRUPT);
+			ironlake_enable_graphics_irq(dev_priv, GT_PIPE_NOTIFY);
 		else
 			i915_enable_irq(dev_priv, I915_USER_INTERRUPT);
 	}
@@ -754,7 +754,7 @@ void i915_user_irq_put(struct drm_device
 	BUG_ON(dev->irq_enabled && dev_priv->user_irq_refcount <= 0);
 	if (dev->irq_enabled && (--dev_priv->user_irq_refcount == 0)) {
 		if (HAS_PCH_SPLIT(dev))
-			ironlake_disable_graphics_irq(dev_priv, GT_USER_INTERRUPT);
+			ironlake_disable_graphics_irq(dev_priv, GT_PIPE_NOTIFY);
 		else
 			i915_disable_irq(dev_priv, I915_USER_INTERRUPT);
 	}
@@ -1034,7 +1034,7 @@ static int ironlake_irq_postinstall(stru
 	/* enable kind of interrupts always enabled */
 	u32 display_mask = DE_MASTER_IRQ_CONTROL | DE_GSE | DE_PCH_EVENT |
 			   DE_PLANEA_FLIP_DONE | DE_PLANEB_FLIP_DONE;
-	u32 render_mask = GT_USER_INTERRUPT;
+	u32 render_mask = GT_PIPE_NOTIFY;
 	u32 hotplug_mask = SDE_CRT_HOTPLUG | SDE_PORTB_HOTPLUG |
 			   SDE_PORTC_HOTPLUG | SDE_PORTD_HOTPLUG;
 
--- a/drivers/gpu/drm/i915/i915_reg.h
+++ b/drivers/gpu/drm/i915/i915_reg.h
@@ -210,6 +210,16 @@
 #define   ASYNC_FLIP                (1<<22)
 #define   DISPLAY_PLANE_A           (0<<20)
 #define   DISPLAY_PLANE_B           (1<<20)
+#define GFX_OP_PIPE_CONTROL	((0x3<<29)|(0x3<<27)|(0x2<<24)|2)
+#define   PIPE_CONTROL_QW_WRITE	(1<<14)
+#define   PIPE_CONTROL_DEPTH_STALL (1<<13)
+#define   PIPE_CONTROL_WC_FLUSH	(1<<12)
+#define   PIPE_CONTROL_IS_FLUSH	(1<<11) /* MBZ on Ironlake */
+#define   PIPE_CONTROL_TC_FLUSH (1<<10) /* GM45+ only */
+#define   PIPE_CONTROL_ISP_DIS	(1<<9)
+#define   PIPE_CONTROL_NOTIFY	(1<<8)
+#define   PIPE_CONTROL_GLOBAL_GTT (1<<2) /* in addr dword */
+#define   PIPE_CONTROL_STALL_EN	(1<<1) /* in addr word, Ironlake+ only */
 
 /*
  * Fence registers
@@ -2111,6 +2121,7 @@
 #define DEIER   0x4400c
 
 /* GT interrupt */
+#define GT_PIPE_NOTIFY		(1 << 4)
 #define GT_SYNC_STATUS          (1 << 2)
 #define GT_USER_INTERRUPT       (1 << 0)
 



  parent reply	other threads:[~2010-05-24 23:30 UTC|newest]

Thread overview: 44+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2010-05-24 23:18 [00/39] 2.6.33.5-stable review Greg KH
2010-05-24 23:15 ` [01/39] ipv4: udp: fix short packet and bad checksum logging Greg KH
2010-05-24 23:15 ` [02/39] hp_accel: fix race in device removal Greg KH
2010-05-24 23:15 ` [03/39] fbdev: bfin-t350mcqb-fb: fix fbmem allocation with blanking lines Greg KH
2010-05-24 23:15 ` [04/39] hugetlbfs: kill applications that use MAP_NORESERVE with SIGBUS instead of OOM-killer Greg KH
2010-05-24 23:15 ` [05/39] dma-mapping: fix dma_sync_single_range_* Greg KH
2010-05-24 23:15 ` [06/39] ALSA: Revert "ALSA: hda/realtek: quirk for D945GCLF2 mainboard" Greg KH
2010-05-24 23:15 ` [07/39] revert "procfs: provide stack information for threads" and its fixup commits Greg KH
2010-05-24 23:15 ` [08/39] ALSA: hda - fix DG45ID SPDIF output Greg KH
2010-05-24 23:15 ` [09/39] ACPI: sleep: eliminate duplicate entries in acpisleep_dmi_table[] Greg KH
2010-05-24 23:15 ` [10/39] mmc: atmel-mci: fix two parameters swapped Greg KH
2010-05-24 23:15 ` [11/39] mmc: atmel-mci: prevent kernel oops while removing card Greg KH
2010-05-24 23:15 ` [12/39] mmc: atmel-mci: remove data error interrupt after xfer Greg KH
2010-05-24 23:15 ` Greg KH [this message]
2010-05-24 23:15 ` [14/39] drm/i915: fix non-Ironlake 965 class crashes Greg KH
2010-05-24 23:15 ` [15/39] [S390] ptrace: fix return value of do_syscall_trace_enter() Greg KH
2010-05-24 23:15 ` [16/39] [S390] dasd: fix race between tasklet and dasd_sleep_on Greg KH
2010-05-24 23:15 ` [17/39] powerpc/perf_event: Fix oops due to perf_event_do_pending call Greg KH
2010-05-24 23:15 ` [18/39] cifs: guard against hardlinking directories Greg KH
2010-05-24 23:15 ` [19/39] serial: imx.c: fix CTS trigger level lower to avoid lost chars Greg KH
2010-05-24 23:15 ` [20/39] tty: Fix unbalanced BKL handling in error path Greg KH
2010-05-24 23:15 ` [21/39] ALSA: ice1724 - Fix ESI Maya44 capture source control Greg KH
2010-05-24 23:15 ` [22/39] ALSA: virtuoso: fix Xonar D1/DX front panel microphone Greg KH
2010-05-24 23:15 ` [23/39] ALSA: hda: Fix 0 dB for Lenovo models using Conexant CX20549 (Venice) Greg KH
2010-05-24 23:15 ` [24/39] inotify: race use after free/double free in inotify inode marks Greg KH
2010-05-24 23:15 ` [25/39] inotify: dont leak user struct on inotify release Greg KH
2010-05-24 23:15 ` [26/39] profile: fix stats and data leakage Greg KH
2010-05-24 23:15 ` [27/39] x86, k8: Fix build error when K8_NB is disabled Greg KH
2010-05-24 23:15 ` [28/39] x86, cacheinfo: Turn off L3 cache index disable feature in virtualized environments Greg KH
2010-05-25  1:50   ` Hugh Dickins
2010-05-25 17:14     ` Greg KH
2010-05-25 20:41       ` Hugh Dickins
2010-05-25 20:50         ` Greg KH
2010-05-24 23:15 ` [29/39] x86, amd: Check X86_FEATURE_OSVW bit before accessing OSVW MSRs Greg KH
2010-05-24 23:15 ` [30/39] Btrfs: check for read permission on src file in the clone ioctl Greg KH
2010-05-24 23:15 ` [31/39] ALSA: hda - New Intel HDA controller Greg KH
2010-05-24 23:15 ` [32/39] drm/i915: Disable FBC on 915GM and 945GM Greg KH
2010-05-24 23:15 ` [33/39] iwlwifi: check for aggregation frame and queue Greg KH
2010-05-24 23:15 ` [34/39] iwlwifi: clear all the stop_queue flag after load firmware Greg KH
2010-05-24 23:15 ` [35/39] CacheFiles: Fix error handling in cachefiles_determine_cache_security() Greg KH
2010-05-24 23:15 ` [36/39] mmap_min_addr check CAP_SYS_RAWIO only for write Greg KH
2010-05-24 23:15 ` [37/39] nilfs2: fix sync silent failure Greg KH
2010-05-24 23:15 ` [38/39] Revert "ath9k: fix lockdep warning when unloading module" on stable kernels Greg KH
2010-05-24 23:15 ` [39/39] crypto: authenc - Add EINPROGRESS check Greg KH

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20100524231814.368901082@clark.site \
    --to=gregkh@suse.de \
    --cc=akpm@linux-foundation.org \
    --cc=alan@lxorguk.ukuu.org.uk \
    --cc=eric@anholt.net \
    --cc=jbarnes@virtuousgeek.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=stable-review@kernel.org \
    --cc=stable@kernel.org \
    --cc=torvalds@linux-foundation.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox