aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/gpu/drm/i915/i915_drv.h4
-rw-r--r--drivers/gpu/drm/i915/i915_gem.c145
-rw-r--r--drivers/gpu/drm/i915/i915_irq.c8
-rw-r--r--drivers/gpu/drm/i915/i915_reg.h11
4 files changed, 152 insertions, 16 deletions
diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
index ec192ddc93ec..6e4790065d9e 100644
--- a/drivers/gpu/drm/i915/i915_drv.h
+++ b/drivers/gpu/drm/i915/i915_drv.h
@@ -236,11 +236,14 @@ typedef struct drm_i915_private {
236 236
237 drm_dma_handle_t *status_page_dmah; 237 drm_dma_handle_t *status_page_dmah;
238 void *hw_status_page; 238 void *hw_status_page;
239 void *seqno_page;
239 dma_addr_t dma_status_page; 240 dma_addr_t dma_status_page;
240 uint32_t counter; 241 uint32_t counter;
241 unsigned int status_gfx_addr; 242 unsigned int status_gfx_addr;
243 unsigned int seqno_gfx_addr;
242 drm_local_map_t hws_map; 244 drm_local_map_t hws_map;
243 struct drm_gem_object *hws_obj; 245 struct drm_gem_object *hws_obj;
246 struct drm_gem_object *seqno_obj;
244 struct drm_gem_object *pwrctx; 247 struct drm_gem_object *pwrctx;
245 248
246 struct resource mch_res; 249 struct resource mch_res;
@@ -1139,6 +1142,7 @@ extern int i915_wait_ring(struct drm_device * dev, int n, const char *caller);
1139 1142
1140#define HAS_PCH_SPLIT(dev) (IS_IRONLAKE(dev) || \ 1143#define HAS_PCH_SPLIT(dev) (IS_IRONLAKE(dev) || \
1141 IS_GEN6(dev)) 1144 IS_GEN6(dev))
1145#define HAS_PIPE_CONTROL(dev) (IS_IRONLAKE(dev) || IS_GEN6(dev))
1142 1146
1143#define PRIMARY_RINGBUFFER_SIZE (128*1024) 1147#define PRIMARY_RINGBUFFER_SIZE (128*1024)
1144 1148
diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c
index 8a8771711cef..7f52cc124cfe 100644
--- a/drivers/gpu/drm/i915/i915_gem.c
+++ b/drivers/gpu/drm/i915/i915_gem.c
@@ -1588,6 +1588,13 @@ i915_gem_process_flushing_list(struct drm_device *dev,
1588 } 1588 }
1589} 1589}
1590 1590
1591#define PIPE_CONTROL_FLUSH(addr) \
1592 OUT_RING(GFX_OP_PIPE_CONTROL | PIPE_CONTROL_QW_WRITE | \
1593 PIPE_CONTROL_DEPTH_STALL); \
1594 OUT_RING(addr | PIPE_CONTROL_GLOBAL_GTT); \
1595 OUT_RING(0); \
1596 OUT_RING(0); \
1597
1591/** 1598/**
1592 * Creates a new sequence number, emitting a write of it to the status page 1599 * Creates a new sequence number, emitting a write of it to the status page
1593 * plus an interrupt, which will trigger i915_user_interrupt_handler. 1600 * plus an interrupt, which will trigger i915_user_interrupt_handler.
@@ -1622,13 +1629,47 @@ i915_add_request(struct drm_device *dev, struct drm_file *file_priv,
1622 if (dev_priv->mm.next_gem_seqno == 0) 1629 if (dev_priv->mm.next_gem_seqno == 0)
1623 dev_priv->mm.next_gem_seqno++; 1630 dev_priv->mm.next_gem_seqno++;
1624 1631
1625 BEGIN_LP_RING(4); 1632 if (HAS_PIPE_CONTROL(dev)) {
1626 OUT_RING(MI_STORE_DWORD_INDEX); 1633 u32 scratch_addr = dev_priv->seqno_gfx_addr + 128;
1627 OUT_RING(I915_GEM_HWS_INDEX << MI_STORE_DWORD_INDEX_SHIFT);
1628 OUT_RING(seqno);
1629 1634
1630 OUT_RING(MI_USER_INTERRUPT); 1635 /*
1631 ADVANCE_LP_RING(); 1636 * Workaround qword write incoherence by flushing the
1637 * PIPE_NOTIFY buffers out to memory before requesting
1638 * an interrupt.
1639 */
1640 BEGIN_LP_RING(32);
1641 OUT_RING(GFX_OP_PIPE_CONTROL | PIPE_CONTROL_QW_WRITE |
1642 PIPE_CONTROL_WC_FLUSH | PIPE_CONTROL_TC_FLUSH);
1643 OUT_RING(dev_priv->seqno_gfx_addr | PIPE_CONTROL_GLOBAL_GTT);
1644 OUT_RING(seqno);
1645 OUT_RING(0);
1646 PIPE_CONTROL_FLUSH(scratch_addr);
1647 scratch_addr += 128; /* write to separate cachelines */
1648 PIPE_CONTROL_FLUSH(scratch_addr);
1649 scratch_addr += 128;
1650 PIPE_CONTROL_FLUSH(scratch_addr);
1651 scratch_addr += 128;
1652 PIPE_CONTROL_FLUSH(scratch_addr);
1653 scratch_addr += 128;
1654 PIPE_CONTROL_FLUSH(scratch_addr);
1655 scratch_addr += 128;
1656 PIPE_CONTROL_FLUSH(scratch_addr);
1657 OUT_RING(GFX_OP_PIPE_CONTROL | PIPE_CONTROL_QW_WRITE |
1658 PIPE_CONTROL_WC_FLUSH | PIPE_CONTROL_TC_FLUSH |
1659 PIPE_CONTROL_NOTIFY);
1660 OUT_RING(dev_priv->seqno_gfx_addr | PIPE_CONTROL_GLOBAL_GTT);
1661 OUT_RING(seqno);
1662 OUT_RING(0);
1663 ADVANCE_LP_RING();
1664 } else {
1665 BEGIN_LP_RING(4);
1666 OUT_RING(MI_STORE_DWORD_INDEX);
1667 OUT_RING(I915_GEM_HWS_INDEX << MI_STORE_DWORD_INDEX_SHIFT);
1668 OUT_RING(seqno);
1669
1670 OUT_RING(MI_USER_INTERRUPT);
1671 ADVANCE_LP_RING();
1672 }
1632 1673
1633 DRM_DEBUG_DRIVER("%d\n", seqno); 1674 DRM_DEBUG_DRIVER("%d\n", seqno);
1634 1675
@@ -1752,7 +1793,10 @@ i915_get_gem_seqno(struct drm_device *dev)
1752{ 1793{
1753 drm_i915_private_t *dev_priv = dev->dev_private; 1794 drm_i915_private_t *dev_priv = dev->dev_private;
1754 1795
1755 return READ_HWSP(dev_priv, I915_GEM_HWS_INDEX); 1796 if (IS_I965G(dev))
1797 return ((volatile u32 *)(dev_priv->seqno_page))[0];
1798 else
1799 return READ_HWSP(dev_priv, I915_GEM_HWS_INDEX);
1756} 1800}
1757 1801
1758/** 1802/**
@@ -4552,6 +4596,49 @@ i915_gem_idle(struct drm_device *dev)
4552 return 0; 4596 return 0;
4553} 4597}
4554 4598
4599/*
4600 * 965+ support PIPE_CONTROL commands, which provide finer grained control
4601 * over cache flushing.
4602 */
4603static int
4604i915_gem_init_pipe_control(struct drm_device *dev)
4605{
4606 drm_i915_private_t *dev_priv = dev->dev_private;
4607 struct drm_gem_object *obj;
4608 struct drm_i915_gem_object *obj_priv;
4609 int ret;
4610
4611 obj = drm_gem_object_alloc(dev, 4096);
4612 if (obj == NULL) {
4613 DRM_ERROR("Failed to allocate seqno page\n");
4614 ret = -ENOMEM;
4615 goto err;
4616 }
4617 obj_priv = to_intel_bo(obj);
4618 obj_priv->agp_type = AGP_USER_CACHED_MEMORY;
4619
4620 ret = i915_gem_object_pin(obj, 4096);
4621 if (ret)
4622 goto err_unref;
4623
4624 dev_priv->seqno_gfx_addr = obj_priv->gtt_offset;
4625 dev_priv->seqno_page = kmap(obj_priv->pages[0]);
4626 if (dev_priv->seqno_page == NULL)
4627 goto err_unpin;
4628
4629 dev_priv->seqno_obj = obj;
4630 memset(dev_priv->seqno_page, 0, PAGE_SIZE);
4631
4632 return 0;
4633
4634err_unpin:
4635 i915_gem_object_unpin(obj);
4636err_unref:
4637 drm_gem_object_unreference(obj);
4638err:
4639 return ret;
4640}
4641
4555static int 4642static int
4556i915_gem_init_hws(struct drm_device *dev) 4643i915_gem_init_hws(struct drm_device *dev)
4557{ 4644{
@@ -4569,7 +4656,8 @@ i915_gem_init_hws(struct drm_device *dev)
4569 obj = drm_gem_object_alloc(dev, 4096); 4656 obj = drm_gem_object_alloc(dev, 4096);
4570 if (obj == NULL) { 4657 if (obj == NULL) {
4571 DRM_ERROR("Failed to allocate status page\n"); 4658 DRM_ERROR("Failed to allocate status page\n");
4572 return -ENOMEM; 4659 ret = -ENOMEM;
4660 goto err;
4573 } 4661 }
4574 obj_priv = to_intel_bo(obj); 4662 obj_priv = to_intel_bo(obj);
4575 obj_priv->agp_type = AGP_USER_CACHED_MEMORY; 4663 obj_priv->agp_type = AGP_USER_CACHED_MEMORY;
@@ -4577,7 +4665,7 @@ i915_gem_init_hws(struct drm_device *dev)
4577 ret = i915_gem_object_pin(obj, 4096); 4665 ret = i915_gem_object_pin(obj, 4096);
4578 if (ret != 0) { 4666 if (ret != 0) {
4579 drm_gem_object_unreference(obj); 4667 drm_gem_object_unreference(obj);
4580 return ret; 4668 goto err_unref;
4581 } 4669 }
4582 4670
4583 dev_priv->status_gfx_addr = obj_priv->gtt_offset; 4671 dev_priv->status_gfx_addr = obj_priv->gtt_offset;
@@ -4586,10 +4674,16 @@ i915_gem_init_hws(struct drm_device *dev)
4586 if (dev_priv->hw_status_page == NULL) { 4674 if (dev_priv->hw_status_page == NULL) {
4587 DRM_ERROR("Failed to map status page.\n"); 4675 DRM_ERROR("Failed to map status page.\n");
4588 memset(&dev_priv->hws_map, 0, sizeof(dev_priv->hws_map)); 4676 memset(&dev_priv->hws_map, 0, sizeof(dev_priv->hws_map));
4589 i915_gem_object_unpin(obj); 4677 ret = -EINVAL;
4590 drm_gem_object_unreference(obj); 4678 goto err_unpin;
4591 return -EINVAL;
4592 } 4679 }
4680
4681 if (HAS_PIPE_CONTROL(dev)) {
4682 ret = i915_gem_init_pipe_control(dev);
4683 if (ret)
4684 goto err_unpin;
4685 }
4686
4593 dev_priv->hws_obj = obj; 4687 dev_priv->hws_obj = obj;
4594 memset(dev_priv->hw_status_page, 0, PAGE_SIZE); 4688 memset(dev_priv->hw_status_page, 0, PAGE_SIZE);
4595 if (IS_GEN6(dev)) { 4689 if (IS_GEN6(dev)) {
@@ -4602,6 +4696,30 @@ i915_gem_init_hws(struct drm_device *dev)
4602 DRM_DEBUG_DRIVER("hws offset: 0x%08x\n", dev_priv->status_gfx_addr); 4696 DRM_DEBUG_DRIVER("hws offset: 0x%08x\n", dev_priv->status_gfx_addr);
4603 4697
4604 return 0; 4698 return 0;
4699
4700err_unpin:
4701 i915_gem_object_unpin(obj);
4702err_unref:
4703 drm_gem_object_unreference(obj);
4704err:
4705 return 0;
4706}
4707
4708static void
4709i915_gem_cleanup_pipe_control(struct drm_device *dev)
4710{
4711 drm_i915_private_t *dev_priv = dev->dev_private;
4712 struct drm_gem_object *obj;
4713 struct drm_i915_gem_object *obj_priv;
4714
4715 obj = dev_priv->seqno_obj;
4716 obj_priv = to_intel_bo(obj);
4717 kunmap(obj_priv->pages[0]);
4718 i915_gem_object_unpin(obj);
4719 drm_gem_object_unreference(obj);
4720 dev_priv->seqno_obj = NULL;
4721
4722 dev_priv->seqno_page = NULL;
4605} 4723}
4606 4724
4607static void 4725static void
@@ -4625,6 +4743,9 @@ i915_gem_cleanup_hws(struct drm_device *dev)
4625 memset(&dev_priv->hws_map, 0, sizeof(dev_priv->hws_map)); 4743 memset(&dev_priv->hws_map, 0, sizeof(dev_priv->hws_map));
4626 dev_priv->hw_status_page = NULL; 4744 dev_priv->hw_status_page = NULL;
4627 4745
4746 if (HAS_PIPE_CONTROL(dev))
4747 i915_gem_cleanup_pipe_control(dev);
4748
4628 /* Write high address into HWS_PGA when disabling. */ 4749 /* Write high address into HWS_PGA when disabling. */
4629 I915_WRITE(HWS_PGA, 0x1ffff000); 4750 I915_WRITE(HWS_PGA, 0x1ffff000);
4630} 4751}
diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c
index 6421481d6222..2b8b969d0c15 100644
--- a/drivers/gpu/drm/i915/i915_irq.c
+++ b/drivers/gpu/drm/i915/i915_irq.c
@@ -349,7 +349,7 @@ irqreturn_t ironlake_irq_handler(struct drm_device *dev)
349 READ_BREADCRUMB(dev_priv); 349 READ_BREADCRUMB(dev_priv);
350 } 350 }
351 351
352 if (gt_iir & GT_USER_INTERRUPT) { 352 if (gt_iir & GT_PIPE_NOTIFY) {
353 u32 seqno = i915_get_gem_seqno(dev); 353 u32 seqno = i915_get_gem_seqno(dev);
354 dev_priv->mm.irq_gem_seqno = seqno; 354 dev_priv->mm.irq_gem_seqno = seqno;
355 trace_i915_gem_request_complete(dev, seqno); 355 trace_i915_gem_request_complete(dev, seqno);
@@ -1005,7 +1005,7 @@ void i915_user_irq_get(struct drm_device *dev)
1005 spin_lock_irqsave(&dev_priv->user_irq_lock, irqflags); 1005 spin_lock_irqsave(&dev_priv->user_irq_lock, irqflags);
1006 if (dev->irq_enabled && (++dev_priv->user_irq_refcount == 1)) { 1006 if (dev->irq_enabled && (++dev_priv->user_irq_refcount == 1)) {
1007 if (HAS_PCH_SPLIT(dev)) 1007 if (HAS_PCH_SPLIT(dev))
1008 ironlake_enable_graphics_irq(dev_priv, GT_USER_INTERRUPT); 1008 ironlake_enable_graphics_irq(dev_priv, GT_PIPE_NOTIFY);
1009 else 1009 else
1010 i915_enable_irq(dev_priv, I915_USER_INTERRUPT); 1010 i915_enable_irq(dev_priv, I915_USER_INTERRUPT);
1011 } 1011 }
@@ -1021,7 +1021,7 @@ void i915_user_irq_put(struct drm_device *dev)
1021 BUG_ON(dev->irq_enabled && dev_priv->user_irq_refcount <= 0); 1021 BUG_ON(dev->irq_enabled && dev_priv->user_irq_refcount <= 0);
1022 if (dev->irq_enabled && (--dev_priv->user_irq_refcount == 0)) { 1022 if (dev->irq_enabled && (--dev_priv->user_irq_refcount == 0)) {
1023 if (HAS_PCH_SPLIT(dev)) 1023 if (HAS_PCH_SPLIT(dev))
1024 ironlake_disable_graphics_irq(dev_priv, GT_USER_INTERRUPT); 1024 ironlake_disable_graphics_irq(dev_priv, GT_PIPE_NOTIFY);
1025 else 1025 else
1026 i915_disable_irq(dev_priv, I915_USER_INTERRUPT); 1026 i915_disable_irq(dev_priv, I915_USER_INTERRUPT);
1027 } 1027 }
@@ -1305,7 +1305,7 @@ static int ironlake_irq_postinstall(struct drm_device *dev)
1305 /* enable kind of interrupts always enabled */ 1305 /* enable kind of interrupts always enabled */
1306 u32 display_mask = DE_MASTER_IRQ_CONTROL | DE_GSE | DE_PCH_EVENT | 1306 u32 display_mask = DE_MASTER_IRQ_CONTROL | DE_GSE | DE_PCH_EVENT |
1307 DE_PLANEA_FLIP_DONE | DE_PLANEB_FLIP_DONE; 1307 DE_PLANEA_FLIP_DONE | DE_PLANEB_FLIP_DONE;
1308 u32 render_mask = GT_USER_INTERRUPT; 1308 u32 render_mask = GT_PIPE_NOTIFY;
1309 u32 hotplug_mask = SDE_CRT_HOTPLUG | SDE_PORTB_HOTPLUG | 1309 u32 hotplug_mask = SDE_CRT_HOTPLUG | SDE_PORTB_HOTPLUG |
1310 SDE_PORTC_HOTPLUG | SDE_PORTD_HOTPLUG; 1310 SDE_PORTC_HOTPLUG | SDE_PORTD_HOTPLUG;
1311 1311
diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h
index 773c1adb2541..4cbc5210fd30 100644
--- a/drivers/gpu/drm/i915/i915_reg.h
+++ b/drivers/gpu/drm/i915/i915_reg.h
@@ -230,6 +230,16 @@
230#define ASYNC_FLIP (1<<22) 230#define ASYNC_FLIP (1<<22)
231#define DISPLAY_PLANE_A (0<<20) 231#define DISPLAY_PLANE_A (0<<20)
232#define DISPLAY_PLANE_B (1<<20) 232#define DISPLAY_PLANE_B (1<<20)
233#define GFX_OP_PIPE_CONTROL ((0x3<<29)|(0x3<<27)|(0x2<<24)|2)
234#define PIPE_CONTROL_QW_WRITE (1<<14)
235#define PIPE_CONTROL_DEPTH_STALL (1<<13)
236#define PIPE_CONTROL_WC_FLUSH (1<<12)
237#define PIPE_CONTROL_IS_FLUSH (1<<11) /* MBZ on Ironlake */
238#define PIPE_CONTROL_TC_FLUSH (1<<10) /* GM45+ only */
239#define PIPE_CONTROL_ISP_DIS (1<<9)
240#define PIPE_CONTROL_NOTIFY (1<<8)
241#define PIPE_CONTROL_GLOBAL_GTT (1<<2) /* in addr dword */
242#define PIPE_CONTROL_STALL_EN (1<<1) /* in addr word, Ironlake+ only */
233 243
234/* 244/*
235 * Fence registers 245 * Fence registers
@@ -2285,6 +2295,7 @@
2285#define DEIER 0x4400c 2295#define DEIER 0x4400c
2286 2296
2287/* GT interrupt */ 2297/* GT interrupt */
2298#define GT_PIPE_NOTIFY (1 << 4)
2288#define GT_SYNC_STATUS (1 << 2) 2299#define GT_SYNC_STATUS (1 << 2)
2289#define GT_USER_INTERRUPT (1 << 0) 2300#define GT_USER_INTERRUPT (1 << 0)
2290 2301