From: Jesse Barnes Subject: [PATCH] drm/i915: use PIPE_CONTROL instruction on 965+ Date: Tue, 20 Apr 2010 15:35:08 -0700 Message-ID: <20100420153508.08d88361@virtuousgeek.org> Mime-Version: 1.0 Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit Return-path: Received: from outbound-mail-158.bluehost.com (cpoproxy2-pub.bluehost.com [67.222.39.38]) by gabe.freedesktop.org (Postfix) with SMTP id 523C49E794 for ; Tue, 20 Apr 2010 15:33:53 -0700 (PDT) Received: from [75.110.194.140] (helo=localhost) by box514.bluehost.com with esmtpsa (TLSv1:AES128-SHA:128) (Exim 4.69) (envelope-from ) id 1O4M0u-0003Ht-ES for intel-gfx@lists.freedesktop.org; Tue, 20 Apr 2010 16:33:52 -0600 List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: intel-gfx-bounces@lists.freedesktop.org Errors-To: intel-gfx-bounces@lists.freedesktop.org To: intel-gfx@lists.freedesktop.org List-Id: intel-gfx@lists.freedesktop.org ...and hang your box even faster. -- Jesse Barnes, Intel Open Source Technology Center diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 790fef3..11c25ab 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -240,11 +240,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; diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index b85727c..731eca5 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -1621,13 +1621,24 @@ i915_add_request(struct drm_device *dev, struct drm_file *file_priv, 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 (IS_I965G(dev)) { + BEGIN_LP_RING(4); + OUT_RING(GFX_OP_PIPE_CONTROL | PIPE_CONTROL_QW_WRITE | + PIPE_CONTROL_WC_FLUSH | PIPE_CONTROL_IS_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(); + OUT_RING(MI_USER_INTERRUPT); + ADVANCE_LP_RING(); + } DRM_DEBUG_DRIVER("%d\n", seqno); @@ -1666,17 +1677,24 @@ static uint32_t i915_retire_commands(struct drm_device *dev) { drm_i915_private_t *dev_priv = dev->dev_private; - uint32_t cmd = MI_FLUSH | MI_NO_WRITE_FLUSH; uint32_t flush_domains = 0; RING_LOCALS; /* The sampler always gets flushed on i965 (sigh) */ - if (IS_I965G(dev)) + if (IS_I965G(dev)) { flush_domains |= I915_GEM_DOMAIN_SAMPLER; - BEGIN_LP_RING(2); - OUT_RING(cmd); - OUT_RING(0); /* noop */ - ADVANCE_LP_RING(); + BEGIN_LP_RING(4); + OUT_RING(GFX_OP_PIPE_CONTROL); + OUT_RING(0); /* unused addr */ + OUT_RING(0); /* unused data */ + OUT_RING(0); /* unused data */ + ADVANCE_LP_RING(); + } else { + BEGIN_LP_RING(2); + OUT_RING(MI_FLUSH | MI_NO_WRITE_FLUSH); + OUT_RING(0); /* noop */ + ADVANCE_LP_RING(); + } return flush_domains; } @@ -1751,7 +1769,10 @@ i915_get_gem_seqno(struct drm_device *dev) { 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); } /** @@ -1930,29 +1951,45 @@ i915_gem_flush(struct drm_device *dev, * I915_GEM_DOMAIN_RENDER and I915_GEM_DOMAIN_SAMPLER * are flushed at any MI_FLUSH. */ - - cmd = MI_FLUSH | MI_NO_WRITE_FLUSH; - if ((invalidate_domains|flush_domains) & - I915_GEM_DOMAIN_RENDER) - cmd &= ~MI_NO_WRITE_FLUSH; - if (!IS_I965G(dev)) { + if (IS_I965G(dev)) { + cmd = GFX_OP_PIPE_CONTROL; + if ((invalidate_domains|flush_domains) & + I915_GEM_DOMAIN_RENDER) + cmd |= PIPE_CONTROL_WC_FLUSH; + if (invalidate_domains & I915_GEM_DOMAIN_SAMPLER) + cmd |= PIPE_CONTROL_TC_FLUSH; + if (IS_GEN6(dev) && + invalidate_domains & I915_GEM_DOMAIN_INSTRUCTION) + cmd |= PIPE_CONTROL_IS_FLUSH; + BEGIN_LP_RING(4); + OUT_RING(cmd); + OUT_RING(0); /* unused addr */ + OUT_RING(0); /* unused data */ + OUT_RING(0); /* unused data */ + ADVANCE_LP_RING(); + } else { + cmd = MI_FLUSH | MI_NO_WRITE_FLUSH; + if ((invalidate_domains|flush_domains) & + I915_GEM_DOMAIN_RENDER) + cmd &= ~MI_NO_WRITE_FLUSH; /* * On the 965, the sampler cache always gets flushed * and this bit is reserved. */ if (invalidate_domains & I915_GEM_DOMAIN_SAMPLER) cmd |= MI_READ_FLUSH; - } - if (invalidate_domains & I915_GEM_DOMAIN_INSTRUCTION) - cmd |= MI_EXE_FLUSH; + if (invalidate_domains & I915_GEM_DOMAIN_INSTRUCTION) + cmd |= MI_EXE_FLUSH; #if WATCH_EXEC - DRM_INFO("%s: queue flush %08x to ring\n", __func__, cmd); + DRM_INFO("%s: queue flush %08x to ring\n", __func__, + cmd); #endif - BEGIN_LP_RING(2); - OUT_RING(cmd); - OUT_RING(MI_NOOP); - ADVANCE_LP_RING(); + BEGIN_LP_RING(2); + OUT_RING(cmd); + OUT_RING(MI_NOOP); + ADVANCE_LP_RING(); + } } } @@ -4594,6 +4631,37 @@ i915_gem_init_hws(struct drm_device *dev) } DRM_DEBUG_DRIVER("hws offset: 0x%08x\n", dev_priv->status_gfx_addr); + /* Set up pipe control qword area */ + /* FIXME: cleanup hws above if this fails */ + if (IS_I965G(dev)) { + obj = drm_gem_object_alloc(dev, 4096); + if (obj == NULL) { + DRM_ERROR("Failed to allocate seqno page\n"); + return -ENOMEM; + } + obj_priv = to_intel_bo(obj); + obj_priv->agp_type = AGP_USER_CACHED_MEMORY; + + ret = i915_gem_object_pin(obj, 4096); + if (ret != 0) { + drm_gem_object_unreference(obj); + return ret; + } + + dev_priv->seqno_gfx_addr = obj_priv->gtt_offset; + dev_priv->seqno_page = kmap(obj_priv->pages[0]); + if (dev_priv->seqno_page == NULL) { + DRM_ERROR("Failed to map seqno page.\n"); + i915_gem_object_unpin(obj); + drm_gem_object_unreference(obj); + return -EINVAL; + } + dev_priv->seqno_obj = obj; + memset(dev_priv->seqno_page, 0, PAGE_SIZE); + DRM_ERROR("seqno gfx offset: 0x%08x, kmap: %p\n", + dev_priv->seqno_gfx_addr, dev_priv->seqno_page); + } + return 0; } @@ -4618,6 +4686,16 @@ i915_gem_cleanup_hws(struct drm_device *dev) memset(&dev_priv->hws_map, 0, sizeof(dev_priv->hws_map)); dev_priv->hw_status_page = NULL; + if (IS_I965G(dev)) { + obj = dev_priv->seqno_obj; + obj_priv = to_intel_bo(obj); + 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; + } /* Write high address into HWS_PGA when disabling. */ I915_WRITE(HWS_PGA, 0x1ffff000); } diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index 7701cbd..13283ed 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -51,9 +51,6 @@ I915_DISPLAY_PLANE_B_FLIP_PENDING_INTERRUPT | \ I915_RENDER_COMMAND_PARSER_ERROR_INTERRUPT) -/** Interrupts that we mask and unmask at runtime. */ -#define I915_INTERRUPT_ENABLE_VAR (I915_USER_INTERRUPT) - #define I915_PIPE_VBLANK_STATUS (PIPE_START_VBLANK_INTERRUPT_STATUS |\ PIPE_VBLANK_INTERRUPT_STATUS) @@ -352,7 +349,7 @@ irqreturn_t ironlake_irq_handler(struct drm_device *dev) 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); @@ -361,6 +358,9 @@ irqreturn_t ironlake_irq_handler(struct drm_device *dev) mod_timer(&dev_priv->hangcheck_timer, jiffies + DRM_I915_HANGCHECK_PERIOD); } + if (gt_iir & GT_SYNC_STATUS) + DRM_ERROR("sync status interrupt\n"); + if (de_iir & DE_GSE) ironlake_opregion_gse_intr(dev); @@ -1005,13 +1005,19 @@ void i915_user_irq_get(struct drm_device *dev) { drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; unsigned long irqflags; + u32 irq; + + if (IS_I965G(dev)) + irq = I915_PIPE_CONTROL_NOTIFY_INTERRUPT; + else + irq = I915_USER_INTERRUPT; 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_SYNC_STATUS | GT_PIPE_NOTIFY); else - i915_enable_irq(dev_priv, I915_USER_INTERRUPT); + i915_enable_irq(dev_priv, irq); } spin_unlock_irqrestore(&dev_priv->user_irq_lock, irqflags); } @@ -1020,14 +1026,20 @@ void i915_user_irq_put(struct drm_device *dev) { drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; unsigned long irqflags; + u32 irq; + + if (IS_I965G(dev)) + irq = I915_PIPE_CONTROL_NOTIFY_INTERRUPT; + else + irq = I915_USER_INTERRUPT; spin_lock_irqsave(&dev_priv->user_irq_lock, irqflags); 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_SYNC_STATUS | GT_PIPE_NOTIFY); else - i915_disable_irq(dev_priv, I915_USER_INTERRUPT); + i915_disable_irq(dev_priv, irq); } spin_unlock_irqrestore(&dev_priv->user_irq_lock, irqflags); } @@ -1309,7 +1321,7 @@ static int ironlake_irq_postinstall(struct drm_device *dev) /* 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_SYNC_STATUS | GT_PIPE_NOTIFY; u32 hotplug_mask = SDE_CRT_HOTPLUG | SDE_PORTB_HOTPLUG | SDE_PORTC_HOTPLUG | SDE_PORTD_HOTPLUG; @@ -1383,7 +1395,7 @@ void i915_driver_irq_preinstall(struct drm_device * dev) int i915_driver_irq_postinstall(struct drm_device *dev) { drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; - u32 enable_mask = I915_INTERRUPT_ENABLE_FIX | I915_INTERRUPT_ENABLE_VAR; + u32 enable_mask = I915_INTERRUPT_ENABLE_FIX; u32 error_mask; DRM_INIT_WAITQUEUE(&dev_priv->irq_queue); @@ -1393,6 +1405,11 @@ int i915_driver_irq_postinstall(struct drm_device *dev) if (HAS_PCH_SPLIT(dev)) return ironlake_irq_postinstall(dev); + if (IS_I965G(dev)) + enable_mask |= I915_PIPE_CONTROL_NOTIFY_INTERRUPT; + else + enable_mask |= I915_USER_INTERRUPT; + /* Unmask the interrupts that we always want on. */ dev_priv->irq_mask_reg = ~I915_INTERRUPT_ENABLE_FIX; diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 527d30a..6ecf53c 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -230,6 +230,14 @@ #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_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 */ /* * Fence registers @@ -2339,6 +2347,7 @@ #define DEIER 0x4400c /* GT interrupt */ +#define GT_PIPE_NOTIFY (1 << 4) #define GT_SYNC_STATUS (1 << 2) #define GT_USER_INTERRUPT (1 << 0)