diff options
Diffstat (limited to 'drivers/gpu/drm/i915/i915_gem.c')
-rw-r--r-- | drivers/gpu/drm/i915/i915_gem.c | 151 |
1 files changed, 139 insertions, 12 deletions
diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 3471dece13e7..666d75570502 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 (HAS_PIPE_CONTROL(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 | /** |
@@ -2362,6 +2406,12 @@ static void i915_write_fence_reg(struct drm_i915_fence_reg *reg) | |||
2362 | pitch_val = obj_priv->stride / tile_width; | 2406 | pitch_val = obj_priv->stride / tile_width; |
2363 | pitch_val = ffs(pitch_val) - 1; | 2407 | pitch_val = ffs(pitch_val) - 1; |
2364 | 2408 | ||
2409 | if (obj_priv->tiling_mode == I915_TILING_Y && | ||
2410 | HAS_128_BYTE_Y_TILING(dev)) | ||
2411 | WARN_ON(pitch_val > I830_FENCE_MAX_PITCH_VAL); | ||
2412 | else | ||
2413 | WARN_ON(pitch_val > I915_FENCE_MAX_PITCH_VAL); | ||
2414 | |||
2365 | val = obj_priv->gtt_offset; | 2415 | val = obj_priv->gtt_offset; |
2366 | if (obj_priv->tiling_mode == I915_TILING_Y) | 2416 | if (obj_priv->tiling_mode == I915_TILING_Y) |
2367 | val |= 1 << I830_FENCE_TILING_Y_SHIFT; | 2417 | val |= 1 << I830_FENCE_TILING_Y_SHIFT; |
@@ -4554,6 +4604,49 @@ i915_gem_idle(struct drm_device *dev) | |||
4554 | return 0; | 4604 | return 0; |
4555 | } | 4605 | } |
4556 | 4606 | ||
4607 | /* | ||
4608 | * 965+ support PIPE_CONTROL commands, which provide finer grained control | ||
4609 | * over cache flushing. | ||
4610 | */ | ||
4611 | static int | ||
4612 | i915_gem_init_pipe_control(struct drm_device *dev) | ||
4613 | { | ||
4614 | drm_i915_private_t *dev_priv = dev->dev_private; | ||
4615 | struct drm_gem_object *obj; | ||
4616 | struct drm_i915_gem_object *obj_priv; | ||
4617 | int ret; | ||
4618 | |||
4619 | obj = i915_gem_alloc_object(dev, 4096); | ||
4620 | if (obj == NULL) { | ||
4621 | DRM_ERROR("Failed to allocate seqno page\n"); | ||
4622 | ret = -ENOMEM; | ||
4623 | goto err; | ||
4624 | } | ||
4625 | obj_priv = to_intel_bo(obj); | ||
4626 | obj_priv->agp_type = AGP_USER_CACHED_MEMORY; | ||
4627 | |||
4628 | ret = i915_gem_object_pin(obj, 4096); | ||
4629 | if (ret) | ||
4630 | goto err_unref; | ||
4631 | |||
4632 | dev_priv->seqno_gfx_addr = obj_priv->gtt_offset; | ||
4633 | dev_priv->seqno_page = kmap(obj_priv->pages[0]); | ||
4634 | if (dev_priv->seqno_page == NULL) | ||
4635 | goto err_unpin; | ||
4636 | |||
4637 | dev_priv->seqno_obj = obj; | ||
4638 | memset(dev_priv->seqno_page, 0, PAGE_SIZE); | ||
4639 | |||
4640 | return 0; | ||
4641 | |||
4642 | err_unpin: | ||
4643 | i915_gem_object_unpin(obj); | ||
4644 | err_unref: | ||
4645 | drm_gem_object_unreference(obj); | ||
4646 | err: | ||
4647 | return ret; | ||
4648 | } | ||
4649 | |||
4557 | static int | 4650 | static int |
4558 | i915_gem_init_hws(struct drm_device *dev) | 4651 | i915_gem_init_hws(struct drm_device *dev) |
4559 | { | 4652 | { |
@@ -4571,7 +4664,8 @@ i915_gem_init_hws(struct drm_device *dev) | |||
4571 | obj = i915_gem_alloc_object(dev, 4096); | 4664 | obj = i915_gem_alloc_object(dev, 4096); |
4572 | if (obj == NULL) { | 4665 | if (obj == NULL) { |
4573 | DRM_ERROR("Failed to allocate status page\n"); | 4666 | DRM_ERROR("Failed to allocate status page\n"); |
4574 | return -ENOMEM; | 4667 | ret = -ENOMEM; |
4668 | goto err; | ||
4575 | } | 4669 | } |
4576 | obj_priv = to_intel_bo(obj); | 4670 | obj_priv = to_intel_bo(obj); |
4577 | obj_priv->agp_type = AGP_USER_CACHED_MEMORY; | 4671 | obj_priv->agp_type = AGP_USER_CACHED_MEMORY; |
@@ -4579,7 +4673,7 @@ i915_gem_init_hws(struct drm_device *dev) | |||
4579 | ret = i915_gem_object_pin(obj, 4096); | 4673 | ret = i915_gem_object_pin(obj, 4096); |
4580 | if (ret != 0) { | 4674 | if (ret != 0) { |
4581 | drm_gem_object_unreference(obj); | 4675 | drm_gem_object_unreference(obj); |
4582 | return ret; | 4676 | goto err_unref; |
4583 | } | 4677 | } |
4584 | 4678 | ||
4585 | dev_priv->status_gfx_addr = obj_priv->gtt_offset; | 4679 | dev_priv->status_gfx_addr = obj_priv->gtt_offset; |
@@ -4588,10 +4682,16 @@ i915_gem_init_hws(struct drm_device *dev) | |||
4588 | if (dev_priv->hw_status_page == NULL) { | 4682 | if (dev_priv->hw_status_page == NULL) { |
4589 | DRM_ERROR("Failed to map status page.\n"); | 4683 | DRM_ERROR("Failed to map status page.\n"); |
4590 | memset(&dev_priv->hws_map, 0, sizeof(dev_priv->hws_map)); | 4684 | memset(&dev_priv->hws_map, 0, sizeof(dev_priv->hws_map)); |
4591 | i915_gem_object_unpin(obj); | 4685 | ret = -EINVAL; |
4592 | drm_gem_object_unreference(obj); | 4686 | goto err_unpin; |
4593 | return -EINVAL; | ||
4594 | } | 4687 | } |
4688 | |||
4689 | if (HAS_PIPE_CONTROL(dev)) { | ||
4690 | ret = i915_gem_init_pipe_control(dev); | ||
4691 | if (ret) | ||
4692 | goto err_unpin; | ||
4693 | } | ||
4694 | |||
4595 | dev_priv->hws_obj = obj; | 4695 | dev_priv->hws_obj = obj; |
4596 | memset(dev_priv->hw_status_page, 0, PAGE_SIZE); | 4696 | memset(dev_priv->hw_status_page, 0, PAGE_SIZE); |
4597 | if (IS_GEN6(dev)) { | 4697 | if (IS_GEN6(dev)) { |
@@ -4604,6 +4704,30 @@ i915_gem_init_hws(struct drm_device *dev) | |||
4604 | DRM_DEBUG_DRIVER("hws offset: 0x%08x\n", dev_priv->status_gfx_addr); | 4704 | DRM_DEBUG_DRIVER("hws offset: 0x%08x\n", dev_priv->status_gfx_addr); |
4605 | 4705 | ||
4606 | return 0; | 4706 | return 0; |
4707 | |||
4708 | err_unpin: | ||
4709 | i915_gem_object_unpin(obj); | ||
4710 | err_unref: | ||
4711 | drm_gem_object_unreference(obj); | ||
4712 | err: | ||
4713 | return 0; | ||
4714 | } | ||
4715 | |||
4716 | static void | ||
4717 | i915_gem_cleanup_pipe_control(struct drm_device *dev) | ||
4718 | { | ||
4719 | drm_i915_private_t *dev_priv = dev->dev_private; | ||
4720 | struct drm_gem_object *obj; | ||
4721 | struct drm_i915_gem_object *obj_priv; | ||
4722 | |||
4723 | obj = dev_priv->seqno_obj; | ||
4724 | obj_priv = to_intel_bo(obj); | ||
4725 | kunmap(obj_priv->pages[0]); | ||
4726 | i915_gem_object_unpin(obj); | ||
4727 | drm_gem_object_unreference(obj); | ||
4728 | dev_priv->seqno_obj = NULL; | ||
4729 | |||
4730 | dev_priv->seqno_page = NULL; | ||
4607 | } | 4731 | } |
4608 | 4732 | ||
4609 | static void | 4733 | static void |
@@ -4627,6 +4751,9 @@ i915_gem_cleanup_hws(struct drm_device *dev) | |||
4627 | memset(&dev_priv->hws_map, 0, sizeof(dev_priv->hws_map)); | 4751 | memset(&dev_priv->hws_map, 0, sizeof(dev_priv->hws_map)); |
4628 | dev_priv->hw_status_page = NULL; | 4752 | dev_priv->hw_status_page = NULL; |
4629 | 4753 | ||
4754 | if (HAS_PIPE_CONTROL(dev)) | ||
4755 | i915_gem_cleanup_pipe_control(dev); | ||
4756 | |||
4630 | /* Write high address into HWS_PGA when disabling. */ | 4757 | /* Write high address into HWS_PGA when disabling. */ |
4631 | I915_WRITE(HWS_PGA, 0x1ffff000); | 4758 | I915_WRITE(HWS_PGA, 0x1ffff000); |
4632 | } | 4759 | } |