diff options
| -rw-r--r-- | drivers/gpu/drm/i915/i915_drv.h | 4 | ||||
| -rw-r--r-- | drivers/gpu/drm/i915/i915_gem.c | 145 | ||||
| -rw-r--r-- | drivers/gpu/drm/i915/i915_irq.c | 8 | ||||
| -rw-r--r-- | drivers/gpu/drm/i915/i915_reg.h | 11 |
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 | */ | ||
| 4603 | static int | ||
| 4604 | i915_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 | |||
| 4634 | err_unpin: | ||
| 4635 | i915_gem_object_unpin(obj); | ||
| 4636 | err_unref: | ||
| 4637 | drm_gem_object_unreference(obj); | ||
| 4638 | err: | ||
| 4639 | return ret; | ||
| 4640 | } | ||
| 4641 | |||
| 4555 | static int | 4642 | static int |
| 4556 | i915_gem_init_hws(struct drm_device *dev) | 4643 | i915_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 | |||
| 4700 | err_unpin: | ||
| 4701 | i915_gem_object_unpin(obj); | ||
| 4702 | err_unref: | ||
| 4703 | drm_gem_object_unreference(obj); | ||
| 4704 | err: | ||
| 4705 | return 0; | ||
| 4706 | } | ||
| 4707 | |||
| 4708 | static void | ||
| 4709 | i915_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 | ||
| 4607 | static void | 4725 | static 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 | ||
