diff options
25 files changed, 242 insertions, 130 deletions
diff --git a/drivers/gpu/drm/drm_crtc_helper.c b/drivers/gpu/drm/drm_crtc_helper.c index 738a4294d820..6a647493ca7f 100644 --- a/drivers/gpu/drm/drm_crtc_helper.c +++ b/drivers/gpu/drm/drm_crtc_helper.c | |||
| @@ -677,6 +677,11 @@ int drm_crtc_helper_set_config(struct drm_mode_set *set) | |||
| 677 | /* don't break so fail path works correct */ | 677 | /* don't break so fail path works correct */ |
| 678 | fail = 1; | 678 | fail = 1; |
| 679 | break; | 679 | break; |
| 680 | |||
| 681 | if (connector->dpms != DRM_MODE_DPMS_ON) { | ||
| 682 | DRM_DEBUG_KMS("connector dpms not on, full mode switch\n"); | ||
| 683 | mode_changed = true; | ||
| 684 | } | ||
| 680 | } | 685 | } |
| 681 | } | 686 | } |
| 682 | 687 | ||
| @@ -754,6 +759,12 @@ int drm_crtc_helper_set_config(struct drm_mode_set *set) | |||
| 754 | ret = -EINVAL; | 759 | ret = -EINVAL; |
| 755 | goto fail; | 760 | goto fail; |
| 756 | } | 761 | } |
| 762 | DRM_DEBUG_KMS("Setting connector DPMS state to on\n"); | ||
| 763 | for (i = 0; i < set->num_connectors; i++) { | ||
| 764 | DRM_DEBUG_KMS("\t[CONNECTOR:%d:%s] set DPMS on\n", set->connectors[i]->base.id, | ||
| 765 | drm_get_connector_name(set->connectors[i])); | ||
| 766 | set->connectors[i]->funcs->dpms(set->connectors[i], DRM_MODE_DPMS_ON); | ||
| 767 | } | ||
| 757 | } | 768 | } |
| 758 | drm_helper_disable_unused_functions(dev); | 769 | drm_helper_disable_unused_functions(dev); |
| 759 | } else if (fb_changed) { | 770 | } else if (fb_changed) { |
| @@ -771,22 +782,6 @@ int drm_crtc_helper_set_config(struct drm_mode_set *set) | |||
| 771 | } | 782 | } |
| 772 | } | 783 | } |
| 773 | 784 | ||
| 774 | /* | ||
| 775 | * crtc set_config helpers implicit set the crtc and all connected | ||
| 776 | * encoders to DPMS on for a full mode set. But for just an fb update it | ||
| 777 | * doesn't do that. To not confuse userspace, do an explicit DPMS_ON | ||
| 778 | * unconditionally. This will also ensure driver internal dpms state is | ||
| 779 | * consistent again. | ||
| 780 | */ | ||
| 781 | if (set->crtc->enabled) { | ||
| 782 | DRM_DEBUG_KMS("Setting connector DPMS state to on\n"); | ||
| 783 | for (i = 0; i < set->num_connectors; i++) { | ||
| 784 | DRM_DEBUG_KMS("\t[CONNECTOR:%d:%s] set DPMS on\n", set->connectors[i]->base.id, | ||
| 785 | drm_get_connector_name(set->connectors[i])); | ||
| 786 | set->connectors[i]->funcs->dpms(set->connectors[i], DRM_MODE_DPMS_ON); | ||
| 787 | } | ||
| 788 | } | ||
| 789 | |||
| 790 | kfree(save_connectors); | 785 | kfree(save_connectors); |
| 791 | kfree(save_encoders); | 786 | kfree(save_encoders); |
| 792 | kfree(save_crtcs); | 787 | kfree(save_crtcs); |
diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c index cf188ab7051a..67ec54f67afe 100644 --- a/drivers/gpu/drm/i915/i915_dma.c +++ b/drivers/gpu/drm/i915/i915_dma.c | |||
| @@ -1495,6 +1495,14 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags) | |||
| 1495 | dev_priv->dev = dev; | 1495 | dev_priv->dev = dev; |
| 1496 | dev_priv->info = info; | 1496 | dev_priv->info = info; |
| 1497 | 1497 | ||
| 1498 | spin_lock_init(&dev_priv->irq_lock); | ||
| 1499 | spin_lock_init(&dev_priv->gpu_error.lock); | ||
| 1500 | spin_lock_init(&dev_priv->rps.lock); | ||
| 1501 | spin_lock_init(&dev_priv->backlight.lock); | ||
| 1502 | mutex_init(&dev_priv->dpio_lock); | ||
| 1503 | mutex_init(&dev_priv->rps.hw_lock); | ||
| 1504 | mutex_init(&dev_priv->modeset_restore_lock); | ||
| 1505 | |||
| 1498 | i915_dump_device_info(dev_priv); | 1506 | i915_dump_device_info(dev_priv); |
| 1499 | 1507 | ||
| 1500 | if (i915_get_bridge_dev(dev)) { | 1508 | if (i915_get_bridge_dev(dev)) { |
| @@ -1585,6 +1593,7 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags) | |||
| 1585 | intel_detect_pch(dev); | 1593 | intel_detect_pch(dev); |
| 1586 | 1594 | ||
| 1587 | intel_irq_init(dev); | 1595 | intel_irq_init(dev); |
| 1596 | intel_gt_sanitize(dev); | ||
| 1588 | intel_gt_init(dev); | 1597 | intel_gt_init(dev); |
| 1589 | 1598 | ||
| 1590 | /* Try to make sure MCHBAR is enabled before poking at it */ | 1599 | /* Try to make sure MCHBAR is enabled before poking at it */ |
| @@ -1610,15 +1619,6 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags) | |||
| 1610 | if (!IS_I945G(dev) && !IS_I945GM(dev)) | 1619 | if (!IS_I945G(dev) && !IS_I945GM(dev)) |
| 1611 | pci_enable_msi(dev->pdev); | 1620 | pci_enable_msi(dev->pdev); |
| 1612 | 1621 | ||
| 1613 | spin_lock_init(&dev_priv->irq_lock); | ||
| 1614 | spin_lock_init(&dev_priv->gpu_error.lock); | ||
| 1615 | spin_lock_init(&dev_priv->rps.lock); | ||
| 1616 | spin_lock_init(&dev_priv->backlight.lock); | ||
| 1617 | mutex_init(&dev_priv->dpio_lock); | ||
| 1618 | |||
| 1619 | mutex_init(&dev_priv->rps.hw_lock); | ||
| 1620 | mutex_init(&dev_priv->modeset_restore_lock); | ||
| 1621 | |||
| 1622 | dev_priv->num_plane = 1; | 1622 | dev_priv->num_plane = 1; |
| 1623 | if (IS_VALLEYVIEW(dev)) | 1623 | if (IS_VALLEYVIEW(dev)) |
| 1624 | dev_priv->num_plane = 2; | 1624 | dev_priv->num_plane = 2; |
diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c index f4af1ca0fb62..45b3c030f483 100644 --- a/drivers/gpu/drm/i915/i915_drv.c +++ b/drivers/gpu/drm/i915/i915_drv.c | |||
| @@ -706,7 +706,7 @@ static int i915_drm_thaw(struct drm_device *dev) | |||
| 706 | { | 706 | { |
| 707 | int error = 0; | 707 | int error = 0; |
| 708 | 708 | ||
| 709 | intel_gt_reset(dev); | 709 | intel_gt_sanitize(dev); |
| 710 | 710 | ||
| 711 | if (drm_core_check_feature(dev, DRIVER_MODESET)) { | 711 | if (drm_core_check_feature(dev, DRIVER_MODESET)) { |
| 712 | mutex_lock(&dev->struct_mutex); | 712 | mutex_lock(&dev->struct_mutex); |
| @@ -732,7 +732,7 @@ int i915_resume(struct drm_device *dev) | |||
| 732 | 732 | ||
| 733 | pci_set_master(dev->pdev); | 733 | pci_set_master(dev->pdev); |
| 734 | 734 | ||
| 735 | intel_gt_reset(dev); | 735 | intel_gt_sanitize(dev); |
| 736 | 736 | ||
| 737 | /* | 737 | /* |
| 738 | * Platforms with opregion should have sane BIOS, older ones (gen3 and | 738 | * Platforms with opregion should have sane BIOS, older ones (gen3 and |
| @@ -1253,21 +1253,21 @@ hsw_unclaimed_reg_check(struct drm_i915_private *dev_priv, u32 reg) | |||
| 1253 | 1253 | ||
| 1254 | #define __i915_read(x, y) \ | 1254 | #define __i915_read(x, y) \ |
| 1255 | u##x i915_read##x(struct drm_i915_private *dev_priv, u32 reg) { \ | 1255 | u##x i915_read##x(struct drm_i915_private *dev_priv, u32 reg) { \ |
| 1256 | unsigned long irqflags; \ | ||
| 1256 | u##x val = 0; \ | 1257 | u##x val = 0; \ |
| 1258 | spin_lock_irqsave(&dev_priv->gt_lock, irqflags); \ | ||
| 1257 | if (IS_GEN5(dev_priv->dev)) \ | 1259 | if (IS_GEN5(dev_priv->dev)) \ |
| 1258 | ilk_dummy_write(dev_priv); \ | 1260 | ilk_dummy_write(dev_priv); \ |
| 1259 | if (NEEDS_FORCE_WAKE((dev_priv), (reg))) { \ | 1261 | if (NEEDS_FORCE_WAKE((dev_priv), (reg))) { \ |
| 1260 | unsigned long irqflags; \ | ||
| 1261 | spin_lock_irqsave(&dev_priv->gt_lock, irqflags); \ | ||
| 1262 | if (dev_priv->forcewake_count == 0) \ | 1262 | if (dev_priv->forcewake_count == 0) \ |
| 1263 | dev_priv->gt.force_wake_get(dev_priv); \ | 1263 | dev_priv->gt.force_wake_get(dev_priv); \ |
| 1264 | val = read##y(dev_priv->regs + reg); \ | 1264 | val = read##y(dev_priv->regs + reg); \ |
| 1265 | if (dev_priv->forcewake_count == 0) \ | 1265 | if (dev_priv->forcewake_count == 0) \ |
| 1266 | dev_priv->gt.force_wake_put(dev_priv); \ | 1266 | dev_priv->gt.force_wake_put(dev_priv); \ |
| 1267 | spin_unlock_irqrestore(&dev_priv->gt_lock, irqflags); \ | ||
| 1268 | } else { \ | 1267 | } else { \ |
| 1269 | val = read##y(dev_priv->regs + reg); \ | 1268 | val = read##y(dev_priv->regs + reg); \ |
| 1270 | } \ | 1269 | } \ |
| 1270 | spin_unlock_irqrestore(&dev_priv->gt_lock, irqflags); \ | ||
| 1271 | trace_i915_reg_rw(false, reg, val, sizeof(val)); \ | 1271 | trace_i915_reg_rw(false, reg, val, sizeof(val)); \ |
| 1272 | return val; \ | 1272 | return val; \ |
| 1273 | } | 1273 | } |
| @@ -1280,8 +1280,10 @@ __i915_read(64, q) | |||
| 1280 | 1280 | ||
| 1281 | #define __i915_write(x, y) \ | 1281 | #define __i915_write(x, y) \ |
| 1282 | void i915_write##x(struct drm_i915_private *dev_priv, u32 reg, u##x val) { \ | 1282 | void i915_write##x(struct drm_i915_private *dev_priv, u32 reg, u##x val) { \ |
| 1283 | unsigned long irqflags; \ | ||
| 1283 | u32 __fifo_ret = 0; \ | 1284 | u32 __fifo_ret = 0; \ |
| 1284 | trace_i915_reg_rw(true, reg, val, sizeof(val)); \ | 1285 | trace_i915_reg_rw(true, reg, val, sizeof(val)); \ |
| 1286 | spin_lock_irqsave(&dev_priv->gt_lock, irqflags); \ | ||
| 1285 | if (NEEDS_FORCE_WAKE((dev_priv), (reg))) { \ | 1287 | if (NEEDS_FORCE_WAKE((dev_priv), (reg))) { \ |
| 1286 | __fifo_ret = __gen6_gt_wait_for_fifo(dev_priv); \ | 1288 | __fifo_ret = __gen6_gt_wait_for_fifo(dev_priv); \ |
| 1287 | } \ | 1289 | } \ |
| @@ -1293,6 +1295,7 @@ void i915_write##x(struct drm_i915_private *dev_priv, u32 reg, u##x val) { \ | |||
| 1293 | gen6_gt_check_fifodbg(dev_priv); \ | 1295 | gen6_gt_check_fifodbg(dev_priv); \ |
| 1294 | } \ | 1296 | } \ |
| 1295 | hsw_unclaimed_reg_check(dev_priv, reg); \ | 1297 | hsw_unclaimed_reg_check(dev_priv, reg); \ |
| 1298 | spin_unlock_irqrestore(&dev_priv->gt_lock, irqflags); \ | ||
| 1296 | } | 1299 | } |
| 1297 | __i915_write(8, b) | 1300 | __i915_write(8, b) |
| 1298 | __i915_write(16, w) | 1301 | __i915_write(16, w) |
diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index a416645bcd23..d2ee3343c943 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h | |||
| @@ -555,6 +555,7 @@ enum intel_sbi_destination { | |||
| 555 | #define QUIRK_PIPEA_FORCE (1<<0) | 555 | #define QUIRK_PIPEA_FORCE (1<<0) |
| 556 | #define QUIRK_LVDS_SSC_DISABLE (1<<1) | 556 | #define QUIRK_LVDS_SSC_DISABLE (1<<1) |
| 557 | #define QUIRK_INVERT_BRIGHTNESS (1<<2) | 557 | #define QUIRK_INVERT_BRIGHTNESS (1<<2) |
| 558 | #define QUIRK_NO_PCH_PWM_ENABLE (1<<3) | ||
| 558 | 559 | ||
| 559 | struct intel_fbdev; | 560 | struct intel_fbdev; |
| 560 | struct intel_fbc_work; | 561 | struct intel_fbc_work; |
| @@ -1583,7 +1584,7 @@ void i915_handle_error(struct drm_device *dev, bool wedged); | |||
| 1583 | extern void intel_irq_init(struct drm_device *dev); | 1584 | extern void intel_irq_init(struct drm_device *dev); |
| 1584 | extern void intel_hpd_init(struct drm_device *dev); | 1585 | extern void intel_hpd_init(struct drm_device *dev); |
| 1585 | extern void intel_gt_init(struct drm_device *dev); | 1586 | extern void intel_gt_init(struct drm_device *dev); |
| 1586 | extern void intel_gt_reset(struct drm_device *dev); | 1587 | extern void intel_gt_sanitize(struct drm_device *dev); |
| 1587 | 1588 | ||
| 1588 | void i915_error_state_free(struct kref *error_ref); | 1589 | void i915_error_state_free(struct kref *error_ref); |
| 1589 | 1590 | ||
diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 97afd2639fb6..d9e2208cfe98 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c | |||
| @@ -2258,7 +2258,17 @@ void i915_gem_restore_fences(struct drm_device *dev) | |||
| 2258 | 2258 | ||
| 2259 | for (i = 0; i < dev_priv->num_fence_regs; i++) { | 2259 | for (i = 0; i < dev_priv->num_fence_regs; i++) { |
| 2260 | struct drm_i915_fence_reg *reg = &dev_priv->fence_regs[i]; | 2260 | struct drm_i915_fence_reg *reg = &dev_priv->fence_regs[i]; |
| 2261 | i915_gem_write_fence(dev, i, reg->obj); | 2261 | |
| 2262 | /* | ||
| 2263 | * Commit delayed tiling changes if we have an object still | ||
| 2264 | * attached to the fence, otherwise just clear the fence. | ||
| 2265 | */ | ||
| 2266 | if (reg->obj) { | ||
| 2267 | i915_gem_object_update_fence(reg->obj, reg, | ||
| 2268 | reg->obj->tiling_mode); | ||
| 2269 | } else { | ||
| 2270 | i915_gem_write_fence(dev, i, NULL); | ||
| 2271 | } | ||
| 2262 | } | 2272 | } |
| 2263 | } | 2273 | } |
| 2264 | 2274 | ||
| @@ -2795,6 +2805,10 @@ static void i915_gem_write_fence(struct drm_device *dev, int reg, | |||
| 2795 | if (i915_gem_object_needs_mb(dev_priv->fence_regs[reg].obj)) | 2805 | if (i915_gem_object_needs_mb(dev_priv->fence_regs[reg].obj)) |
| 2796 | mb(); | 2806 | mb(); |
| 2797 | 2807 | ||
| 2808 | WARN(obj && (!obj->stride || !obj->tiling_mode), | ||
| 2809 | "bogus fence setup with stride: 0x%x, tiling mode: %i\n", | ||
| 2810 | obj->stride, obj->tiling_mode); | ||
| 2811 | |||
| 2798 | switch (INTEL_INFO(dev)->gen) { | 2812 | switch (INTEL_INFO(dev)->gen) { |
| 2799 | case 7: | 2813 | case 7: |
| 2800 | case 6: | 2814 | case 6: |
| @@ -2836,6 +2850,7 @@ static void i915_gem_object_update_fence(struct drm_i915_gem_object *obj, | |||
| 2836 | fence->obj = NULL; | 2850 | fence->obj = NULL; |
| 2837 | list_del_init(&fence->lru_list); | 2851 | list_del_init(&fence->lru_list); |
| 2838 | } | 2852 | } |
| 2853 | obj->fence_dirty = false; | ||
| 2839 | } | 2854 | } |
| 2840 | 2855 | ||
| 2841 | static int | 2856 | static int |
| @@ -2965,7 +2980,6 @@ i915_gem_object_get_fence(struct drm_i915_gem_object *obj) | |||
| 2965 | return 0; | 2980 | return 0; |
| 2966 | 2981 | ||
| 2967 | i915_gem_object_update_fence(obj, reg, enable); | 2982 | i915_gem_object_update_fence(obj, reg, enable); |
| 2968 | obj->fence_dirty = false; | ||
| 2969 | 2983 | ||
| 2970 | return 0; | 2984 | return 0; |
| 2971 | } | 2985 | } |
diff --git a/drivers/gpu/drm/i915/intel_ddi.c b/drivers/gpu/drm/i915/intel_ddi.c index 324211ac9c55..b042ee5c4070 100644 --- a/drivers/gpu/drm/i915/intel_ddi.c +++ b/drivers/gpu/drm/i915/intel_ddi.c | |||
| @@ -301,7 +301,7 @@ static void intel_ddi_mode_set(struct drm_encoder *encoder, | |||
| 301 | struct intel_digital_port *intel_dig_port = | 301 | struct intel_digital_port *intel_dig_port = |
| 302 | enc_to_dig_port(encoder); | 302 | enc_to_dig_port(encoder); |
| 303 | 303 | ||
| 304 | intel_dp->DP = intel_dig_port->port_reversal | | 304 | intel_dp->DP = intel_dig_port->saved_port_bits | |
| 305 | DDI_BUF_CTL_ENABLE | DDI_BUF_EMP_400MV_0DB_HSW; | 305 | DDI_BUF_CTL_ENABLE | DDI_BUF_EMP_400MV_0DB_HSW; |
| 306 | intel_dp->DP |= DDI_PORT_WIDTH(intel_dp->lane_count); | 306 | intel_dp->DP |= DDI_PORT_WIDTH(intel_dp->lane_count); |
| 307 | 307 | ||
| @@ -1109,7 +1109,8 @@ static void intel_enable_ddi(struct intel_encoder *intel_encoder) | |||
| 1109 | * enabling the port. | 1109 | * enabling the port. |
| 1110 | */ | 1110 | */ |
| 1111 | I915_WRITE(DDI_BUF_CTL(port), | 1111 | I915_WRITE(DDI_BUF_CTL(port), |
| 1112 | intel_dig_port->port_reversal | DDI_BUF_CTL_ENABLE); | 1112 | intel_dig_port->saved_port_bits | |
| 1113 | DDI_BUF_CTL_ENABLE); | ||
| 1113 | } else if (type == INTEL_OUTPUT_EDP) { | 1114 | } else if (type == INTEL_OUTPUT_EDP) { |
| 1114 | struct intel_dp *intel_dp = enc_to_intel_dp(encoder); | 1115 | struct intel_dp *intel_dp = enc_to_intel_dp(encoder); |
| 1115 | 1116 | ||
| @@ -1347,8 +1348,9 @@ void intel_ddi_init(struct drm_device *dev, enum port port) | |||
| 1347 | intel_encoder->get_config = intel_ddi_get_config; | 1348 | intel_encoder->get_config = intel_ddi_get_config; |
| 1348 | 1349 | ||
| 1349 | intel_dig_port->port = port; | 1350 | intel_dig_port->port = port; |
| 1350 | intel_dig_port->port_reversal = I915_READ(DDI_BUF_CTL(port)) & | 1351 | intel_dig_port->saved_port_bits = I915_READ(DDI_BUF_CTL(port)) & |
| 1351 | DDI_BUF_PORT_REVERSAL; | 1352 | (DDI_BUF_PORT_REVERSAL | |
| 1353 | DDI_A_4_LANES); | ||
| 1352 | intel_dig_port->dp.output_reg = DDI_BUF_CTL(port); | 1354 | intel_dig_port->dp.output_reg = DDI_BUF_CTL(port); |
| 1353 | 1355 | ||
| 1354 | intel_encoder->type = INTEL_OUTPUT_UNKNOWN; | 1356 | intel_encoder->type = INTEL_OUTPUT_UNKNOWN; |
diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 85f3eb74d2b7..5fb305840db8 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c | |||
| @@ -4913,22 +4913,19 @@ static void i9xx_get_pfit_config(struct intel_crtc *crtc, | |||
| 4913 | uint32_t tmp; | 4913 | uint32_t tmp; |
| 4914 | 4914 | ||
| 4915 | tmp = I915_READ(PFIT_CONTROL); | 4915 | tmp = I915_READ(PFIT_CONTROL); |
| 4916 | if (!(tmp & PFIT_ENABLE)) | ||
| 4917 | return; | ||
| 4916 | 4918 | ||
| 4919 | /* Check whether the pfit is attached to our pipe. */ | ||
| 4917 | if (INTEL_INFO(dev)->gen < 4) { | 4920 | if (INTEL_INFO(dev)->gen < 4) { |
| 4918 | if (crtc->pipe != PIPE_B) | 4921 | if (crtc->pipe != PIPE_B) |
| 4919 | return; | 4922 | return; |
| 4920 | |||
| 4921 | /* gen2/3 store dither state in pfit control, needs to match */ | ||
| 4922 | pipe_config->gmch_pfit.control = tmp & PANEL_8TO6_DITHER_ENABLE; | ||
| 4923 | } else { | 4923 | } else { |
| 4924 | if ((tmp & PFIT_PIPE_MASK) != (crtc->pipe << PFIT_PIPE_SHIFT)) | 4924 | if ((tmp & PFIT_PIPE_MASK) != (crtc->pipe << PFIT_PIPE_SHIFT)) |
| 4925 | return; | 4925 | return; |
| 4926 | } | 4926 | } |
| 4927 | 4927 | ||
| 4928 | if (!(tmp & PFIT_ENABLE)) | 4928 | pipe_config->gmch_pfit.control = tmp; |
| 4929 | return; | ||
| 4930 | |||
| 4931 | pipe_config->gmch_pfit.control = I915_READ(PFIT_CONTROL); | ||
| 4932 | pipe_config->gmch_pfit.pgm_ratios = I915_READ(PFIT_PGM_RATIOS); | 4929 | pipe_config->gmch_pfit.pgm_ratios = I915_READ(PFIT_PGM_RATIOS); |
| 4933 | if (INTEL_INFO(dev)->gen < 5) | 4930 | if (INTEL_INFO(dev)->gen < 5) |
| 4934 | pipe_config->gmch_pfit.lvds_border_bits = | 4931 | pipe_config->gmch_pfit.lvds_border_bits = |
| @@ -8317,6 +8314,8 @@ check_shared_dpll_state(struct drm_device *dev) | |||
| 8317 | pll->active, pll->refcount); | 8314 | pll->active, pll->refcount); |
| 8318 | WARN(pll->active && !pll->on, | 8315 | WARN(pll->active && !pll->on, |
| 8319 | "pll in active use but not on in sw tracking\n"); | 8316 | "pll in active use but not on in sw tracking\n"); |
| 8317 | WARN(pll->on && !pll->active, | ||
| 8318 | "pll in on but not on in use in sw tracking\n"); | ||
| 8320 | WARN(pll->on != active, | 8319 | WARN(pll->on != active, |
| 8321 | "pll on state mismatch (expected %i, found %i)\n", | 8320 | "pll on state mismatch (expected %i, found %i)\n", |
| 8322 | pll->on, active); | 8321 | pll->on, active); |
| @@ -8541,15 +8540,20 @@ static void intel_set_config_restore_state(struct drm_device *dev, | |||
| 8541 | } | 8540 | } |
| 8542 | 8541 | ||
| 8543 | static bool | 8542 | static bool |
| 8544 | is_crtc_connector_off(struct drm_crtc *crtc, struct drm_connector *connectors, | 8543 | is_crtc_connector_off(struct drm_mode_set *set) |
| 8545 | int num_connectors) | ||
| 8546 | { | 8544 | { |
| 8547 | int i; | 8545 | int i; |
| 8548 | 8546 | ||
| 8549 | for (i = 0; i < num_connectors; i++) | 8547 | if (set->num_connectors == 0) |
| 8550 | if (connectors[i].encoder && | 8548 | return false; |
| 8551 | connectors[i].encoder->crtc == crtc && | 8549 | |
| 8552 | connectors[i].dpms != DRM_MODE_DPMS_ON) | 8550 | if (WARN_ON(set->connectors == NULL)) |
| 8551 | return false; | ||
| 8552 | |||
| 8553 | for (i = 0; i < set->num_connectors; i++) | ||
| 8554 | if (set->connectors[i]->encoder && | ||
| 8555 | set->connectors[i]->encoder->crtc == set->crtc && | ||
| 8556 | set->connectors[i]->dpms != DRM_MODE_DPMS_ON) | ||
| 8553 | return true; | 8557 | return true; |
| 8554 | 8558 | ||
| 8555 | return false; | 8559 | return false; |
| @@ -8562,10 +8566,8 @@ intel_set_config_compute_mode_changes(struct drm_mode_set *set, | |||
| 8562 | 8566 | ||
| 8563 | /* We should be able to check here if the fb has the same properties | 8567 | /* We should be able to check here if the fb has the same properties |
| 8564 | * and then just flip_or_move it */ | 8568 | * and then just flip_or_move it */ |
| 8565 | if (set->connectors != NULL && | 8569 | if (is_crtc_connector_off(set)) { |
| 8566 | is_crtc_connector_off(set->crtc, *set->connectors, | 8570 | config->mode_changed = true; |
| 8567 | set->num_connectors)) { | ||
| 8568 | config->mode_changed = true; | ||
| 8569 | } else if (set->crtc->fb != set->fb) { | 8571 | } else if (set->crtc->fb != set->fb) { |
| 8570 | /* If we have no fb then treat it as a full mode set */ | 8572 | /* If we have no fb then treat it as a full mode set */ |
| 8571 | if (set->crtc->fb == NULL) { | 8573 | if (set->crtc->fb == NULL) { |
| @@ -9398,6 +9400,17 @@ static void quirk_invert_brightness(struct drm_device *dev) | |||
| 9398 | DRM_INFO("applying inverted panel brightness quirk\n"); | 9400 | DRM_INFO("applying inverted panel brightness quirk\n"); |
| 9399 | } | 9401 | } |
| 9400 | 9402 | ||
| 9403 | /* | ||
| 9404 | * Some machines (Dell XPS13) suffer broken backlight controls if | ||
| 9405 | * BLM_PCH_PWM_ENABLE is set. | ||
| 9406 | */ | ||
| 9407 | static void quirk_no_pcm_pwm_enable(struct drm_device *dev) | ||
| 9408 | { | ||
| 9409 | struct drm_i915_private *dev_priv = dev->dev_private; | ||
| 9410 | dev_priv->quirks |= QUIRK_NO_PCH_PWM_ENABLE; | ||
| 9411 | DRM_INFO("applying no-PCH_PWM_ENABLE quirk\n"); | ||
| 9412 | } | ||
| 9413 | |||
| 9401 | struct intel_quirk { | 9414 | struct intel_quirk { |
| 9402 | int device; | 9415 | int device; |
| 9403 | int subsystem_vendor; | 9416 | int subsystem_vendor; |
| @@ -9467,6 +9480,11 @@ static struct intel_quirk intel_quirks[] = { | |||
| 9467 | 9480 | ||
| 9468 | /* Acer Aspire 4736Z */ | 9481 | /* Acer Aspire 4736Z */ |
| 9469 | { 0x2a42, 0x1025, 0x0260, quirk_invert_brightness }, | 9482 | { 0x2a42, 0x1025, 0x0260, quirk_invert_brightness }, |
| 9483 | |||
| 9484 | /* Dell XPS13 HD Sandy Bridge */ | ||
| 9485 | { 0x0116, 0x1028, 0x052e, quirk_no_pcm_pwm_enable }, | ||
| 9486 | /* Dell XPS13 HD and XPS13 FHD Ivy Bridge */ | ||
| 9487 | { 0x0166, 0x1028, 0x058b, quirk_no_pcm_pwm_enable }, | ||
| 9470 | }; | 9488 | }; |
| 9471 | 9489 | ||
| 9472 | static void intel_init_quirks(struct drm_device *dev) | 9490 | static void intel_init_quirks(struct drm_device *dev) |
| @@ -9817,8 +9835,8 @@ static void intel_modeset_readout_hw_state(struct drm_device *dev) | |||
| 9817 | } | 9835 | } |
| 9818 | pll->refcount = pll->active; | 9836 | pll->refcount = pll->active; |
| 9819 | 9837 | ||
| 9820 | DRM_DEBUG_KMS("%s hw state readout: refcount %i\n", | 9838 | DRM_DEBUG_KMS("%s hw state readout: refcount %i, on %i\n", |
| 9821 | pll->name, pll->refcount); | 9839 | pll->name, pll->refcount, pll->on); |
| 9822 | } | 9840 | } |
| 9823 | 9841 | ||
| 9824 | list_for_each_entry(encoder, &dev->mode_config.encoder_list, | 9842 | list_for_each_entry(encoder, &dev->mode_config.encoder_list, |
| @@ -9869,6 +9887,7 @@ void intel_modeset_setup_hw_state(struct drm_device *dev, | |||
| 9869 | struct drm_plane *plane; | 9887 | struct drm_plane *plane; |
| 9870 | struct intel_crtc *crtc; | 9888 | struct intel_crtc *crtc; |
| 9871 | struct intel_encoder *encoder; | 9889 | struct intel_encoder *encoder; |
| 9890 | int i; | ||
| 9872 | 9891 | ||
| 9873 | intel_modeset_readout_hw_state(dev); | 9892 | intel_modeset_readout_hw_state(dev); |
| 9874 | 9893 | ||
| @@ -9884,6 +9903,18 @@ void intel_modeset_setup_hw_state(struct drm_device *dev, | |||
| 9884 | intel_dump_pipe_config(crtc, &crtc->config, "[setup_hw_state]"); | 9903 | intel_dump_pipe_config(crtc, &crtc->config, "[setup_hw_state]"); |
| 9885 | } | 9904 | } |
| 9886 | 9905 | ||
| 9906 | for (i = 0; i < dev_priv->num_shared_dpll; i++) { | ||
| 9907 | struct intel_shared_dpll *pll = &dev_priv->shared_dplls[i]; | ||
| 9908 | |||
| 9909 | if (!pll->on || pll->active) | ||
| 9910 | continue; | ||
| 9911 | |||
| 9912 | DRM_DEBUG_KMS("%s enabled but not in use, disabling\n", pll->name); | ||
| 9913 | |||
| 9914 | pll->disable(dev_priv, pll); | ||
| 9915 | pll->on = false; | ||
| 9916 | } | ||
| 9917 | |||
| 9887 | if (force_restore) { | 9918 | if (force_restore) { |
| 9888 | /* | 9919 | /* |
| 9889 | * We need to use raw interfaces for restoring state to avoid | 9920 | * We need to use raw interfaces for restoring state to avoid |
diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index c8c9b6f48230..b7d6e09456ce 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h | |||
| @@ -504,7 +504,7 @@ struct intel_dp { | |||
| 504 | struct intel_digital_port { | 504 | struct intel_digital_port { |
| 505 | struct intel_encoder base; | 505 | struct intel_encoder base; |
| 506 | enum port port; | 506 | enum port port; |
| 507 | u32 port_reversal; | 507 | u32 saved_port_bits; |
| 508 | struct intel_dp dp; | 508 | struct intel_dp dp; |
| 509 | struct intel_hdmi hdmi; | 509 | struct intel_hdmi hdmi; |
| 510 | }; | 510 | }; |
diff --git a/drivers/gpu/drm/i915/intel_lvds.c b/drivers/gpu/drm/i915/intel_lvds.c index 021e8daa022d..61348eae2f04 100644 --- a/drivers/gpu/drm/i915/intel_lvds.c +++ b/drivers/gpu/drm/i915/intel_lvds.c | |||
| @@ -109,6 +109,13 @@ static void intel_lvds_get_config(struct intel_encoder *encoder, | |||
| 109 | flags |= DRM_MODE_FLAG_PVSYNC; | 109 | flags |= DRM_MODE_FLAG_PVSYNC; |
| 110 | 110 | ||
| 111 | pipe_config->adjusted_mode.flags |= flags; | 111 | pipe_config->adjusted_mode.flags |= flags; |
| 112 | |||
| 113 | /* gen2/3 store dither state in pfit control, needs to match */ | ||
| 114 | if (INTEL_INFO(dev)->gen < 4) { | ||
| 115 | tmp = I915_READ(PFIT_CONTROL); | ||
| 116 | |||
| 117 | pipe_config->gmch_pfit.control |= tmp & PANEL_8TO6_DITHER_ENABLE; | ||
| 118 | } | ||
| 112 | } | 119 | } |
| 113 | 120 | ||
| 114 | /* The LVDS pin pair needs to be on before the DPLLs are enabled. | 121 | /* The LVDS pin pair needs to be on before the DPLLs are enabled. |
| @@ -290,14 +297,11 @@ static bool intel_lvds_compute_config(struct intel_encoder *intel_encoder, | |||
| 290 | 297 | ||
| 291 | intel_pch_panel_fitting(intel_crtc, pipe_config, | 298 | intel_pch_panel_fitting(intel_crtc, pipe_config, |
| 292 | intel_connector->panel.fitting_mode); | 299 | intel_connector->panel.fitting_mode); |
| 293 | return true; | ||
| 294 | } else { | 300 | } else { |
| 295 | intel_gmch_panel_fitting(intel_crtc, pipe_config, | 301 | intel_gmch_panel_fitting(intel_crtc, pipe_config, |
| 296 | intel_connector->panel.fitting_mode); | 302 | intel_connector->panel.fitting_mode); |
| 297 | } | ||
| 298 | 303 | ||
| 299 | drm_mode_set_crtcinfo(adjusted_mode, 0); | 304 | } |
| 300 | pipe_config->timings_set = true; | ||
| 301 | 305 | ||
| 302 | /* | 306 | /* |
| 303 | * XXX: It would be nice to support lower refresh rates on the | 307 | * XXX: It would be nice to support lower refresh rates on the |
diff --git a/drivers/gpu/drm/i915/intel_panel.c b/drivers/gpu/drm/i915/intel_panel.c index 80bea1d3209f..67e2c1f1c9a8 100644 --- a/drivers/gpu/drm/i915/intel_panel.c +++ b/drivers/gpu/drm/i915/intel_panel.c | |||
| @@ -194,6 +194,9 @@ void intel_gmch_panel_fitting(struct intel_crtc *intel_crtc, | |||
| 194 | adjusted_mode->vdisplay == mode->vdisplay) | 194 | adjusted_mode->vdisplay == mode->vdisplay) |
| 195 | goto out; | 195 | goto out; |
| 196 | 196 | ||
| 197 | drm_mode_set_crtcinfo(adjusted_mode, 0); | ||
| 198 | pipe_config->timings_set = true; | ||
| 199 | |||
| 197 | switch (fitting_mode) { | 200 | switch (fitting_mode) { |
| 198 | case DRM_MODE_SCALE_CENTER: | 201 | case DRM_MODE_SCALE_CENTER: |
| 199 | /* | 202 | /* |
| @@ -580,7 +583,8 @@ void intel_panel_enable_backlight(struct drm_device *dev, | |||
| 580 | POSTING_READ(reg); | 583 | POSTING_READ(reg); |
| 581 | I915_WRITE(reg, tmp | BLM_PWM_ENABLE); | 584 | I915_WRITE(reg, tmp | BLM_PWM_ENABLE); |
| 582 | 585 | ||
| 583 | if (HAS_PCH_SPLIT(dev)) { | 586 | if (HAS_PCH_SPLIT(dev) && |
| 587 | !(dev_priv->quirks & QUIRK_NO_PCH_PWM_ENABLE)) { | ||
| 584 | tmp = I915_READ(BLC_PWM_PCH_CTL1); | 588 | tmp = I915_READ(BLC_PWM_PCH_CTL1); |
| 585 | tmp |= BLM_PCH_PWM_ENABLE; | 589 | tmp |= BLM_PCH_PWM_ENABLE; |
| 586 | tmp &= ~BLM_PCH_OVERRIDE_ENABLE; | 590 | tmp &= ~BLM_PCH_OVERRIDE_ENABLE; |
diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index d10e6735771f..6a347f54d39f 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c | |||
| @@ -5476,7 +5476,7 @@ static void vlv_force_wake_put(struct drm_i915_private *dev_priv) | |||
| 5476 | gen6_gt_check_fifodbg(dev_priv); | 5476 | gen6_gt_check_fifodbg(dev_priv); |
| 5477 | } | 5477 | } |
| 5478 | 5478 | ||
| 5479 | void intel_gt_reset(struct drm_device *dev) | 5479 | void intel_gt_sanitize(struct drm_device *dev) |
| 5480 | { | 5480 | { |
| 5481 | struct drm_i915_private *dev_priv = dev->dev_private; | 5481 | struct drm_i915_private *dev_priv = dev->dev_private; |
| 5482 | 5482 | ||
| @@ -5487,6 +5487,10 @@ void intel_gt_reset(struct drm_device *dev) | |||
| 5487 | if (IS_IVYBRIDGE(dev) || IS_HASWELL(dev)) | 5487 | if (IS_IVYBRIDGE(dev) || IS_HASWELL(dev)) |
| 5488 | __gen6_gt_force_wake_mt_reset(dev_priv); | 5488 | __gen6_gt_force_wake_mt_reset(dev_priv); |
| 5489 | } | 5489 | } |
| 5490 | |||
| 5491 | /* BIOS often leaves RC6 enabled, but disable it for hw init */ | ||
| 5492 | if (INTEL_INFO(dev)->gen >= 6) | ||
| 5493 | intel_disable_gt_powersave(dev); | ||
| 5490 | } | 5494 | } |
| 5491 | 5495 | ||
| 5492 | void intel_gt_init(struct drm_device *dev) | 5496 | void intel_gt_init(struct drm_device *dev) |
| @@ -5495,8 +5499,6 @@ void intel_gt_init(struct drm_device *dev) | |||
| 5495 | 5499 | ||
| 5496 | spin_lock_init(&dev_priv->gt_lock); | 5500 | spin_lock_init(&dev_priv->gt_lock); |
| 5497 | 5501 | ||
| 5498 | intel_gt_reset(dev); | ||
| 5499 | |||
| 5500 | if (IS_VALLEYVIEW(dev)) { | 5502 | if (IS_VALLEYVIEW(dev)) { |
| 5501 | dev_priv->gt.force_wake_get = vlv_force_wake_get; | 5503 | dev_priv->gt.force_wake_get = vlv_force_wake_get; |
| 5502 | dev_priv->gt.force_wake_put = vlv_force_wake_put; | 5504 | dev_priv->gt.force_wake_put = vlv_force_wake_put; |
diff --git a/drivers/gpu/drm/nouveau/core/engine/bsp/nvc0.c b/drivers/gpu/drm/nouveau/core/engine/bsp/nvc0.c index 262c9f5f5f60..ce860de43e61 100644 --- a/drivers/gpu/drm/nouveau/core/engine/bsp/nvc0.c +++ b/drivers/gpu/drm/nouveau/core/engine/bsp/nvc0.c | |||
| @@ -90,6 +90,7 @@ nvc0_bsp_ctor(struct nouveau_object *parent, struct nouveau_object *engine, | |||
| 90 | return ret; | 90 | return ret; |
| 91 | 91 | ||
| 92 | nv_subdev(priv)->unit = 0x00008000; | 92 | nv_subdev(priv)->unit = 0x00008000; |
| 93 | nv_subdev(priv)->intr = nouveau_falcon_intr; | ||
| 93 | nv_engine(priv)->cclass = &nvc0_bsp_cclass; | 94 | nv_engine(priv)->cclass = &nvc0_bsp_cclass; |
| 94 | nv_engine(priv)->sclass = nvc0_bsp_sclass; | 95 | nv_engine(priv)->sclass = nvc0_bsp_sclass; |
| 95 | return 0; | 96 | return 0; |
diff --git a/drivers/gpu/drm/nouveau/core/engine/bsp/nve0.c b/drivers/gpu/drm/nouveau/core/engine/bsp/nve0.c index c46882c83982..ba6aeca0285e 100644 --- a/drivers/gpu/drm/nouveau/core/engine/bsp/nve0.c +++ b/drivers/gpu/drm/nouveau/core/engine/bsp/nve0.c | |||
| @@ -90,6 +90,7 @@ nve0_bsp_ctor(struct nouveau_object *parent, struct nouveau_object *engine, | |||
| 90 | return ret; | 90 | return ret; |
| 91 | 91 | ||
| 92 | nv_subdev(priv)->unit = 0x00008000; | 92 | nv_subdev(priv)->unit = 0x00008000; |
| 93 | nv_subdev(priv)->intr = nouveau_falcon_intr; | ||
| 93 | nv_engine(priv)->cclass = &nve0_bsp_cclass; | 94 | nv_engine(priv)->cclass = &nve0_bsp_cclass; |
| 94 | nv_engine(priv)->sclass = nve0_bsp_sclass; | 95 | nv_engine(priv)->sclass = nve0_bsp_sclass; |
| 95 | return 0; | 96 | return 0; |
diff --git a/drivers/gpu/drm/nouveau/core/engine/falcon.c b/drivers/gpu/drm/nouveau/core/engine/falcon.c index 3c7a31f7590e..e03fc8e4dc1d 100644 --- a/drivers/gpu/drm/nouveau/core/engine/falcon.c +++ b/drivers/gpu/drm/nouveau/core/engine/falcon.c | |||
| @@ -23,6 +23,25 @@ | |||
| 23 | #include <engine/falcon.h> | 23 | #include <engine/falcon.h> |
| 24 | #include <subdev/timer.h> | 24 | #include <subdev/timer.h> |
| 25 | 25 | ||
| 26 | void | ||
| 27 | nouveau_falcon_intr(struct nouveau_subdev *subdev) | ||
| 28 | { | ||
| 29 | struct nouveau_falcon *falcon = (void *)subdev; | ||
| 30 | u32 dispatch = nv_ro32(falcon, 0x01c); | ||
| 31 | u32 intr = nv_ro32(falcon, 0x008) & dispatch & ~(dispatch >> 16); | ||
| 32 | |||
| 33 | if (intr & 0x00000010) { | ||
| 34 | nv_debug(falcon, "ucode halted\n"); | ||
| 35 | nv_wo32(falcon, 0x004, 0x00000010); | ||
| 36 | intr &= ~0x00000010; | ||
| 37 | } | ||
| 38 | |||
| 39 | if (intr) { | ||
| 40 | nv_error(falcon, "unhandled intr 0x%08x\n", intr); | ||
| 41 | nv_wo32(falcon, 0x004, intr); | ||
| 42 | } | ||
| 43 | } | ||
| 44 | |||
| 26 | u32 | 45 | u32 |
| 27 | _nouveau_falcon_rd32(struct nouveau_object *object, u64 addr) | 46 | _nouveau_falcon_rd32(struct nouveau_object *object, u64 addr) |
| 28 | { | 47 | { |
diff --git a/drivers/gpu/drm/nouveau/core/engine/ppp/nvc0.c b/drivers/gpu/drm/nouveau/core/engine/ppp/nvc0.c index 98072c1ff360..73719aaa62d6 100644 --- a/drivers/gpu/drm/nouveau/core/engine/ppp/nvc0.c +++ b/drivers/gpu/drm/nouveau/core/engine/ppp/nvc0.c | |||
| @@ -90,6 +90,7 @@ nvc0_ppp_ctor(struct nouveau_object *parent, struct nouveau_object *engine, | |||
| 90 | return ret; | 90 | return ret; |
| 91 | 91 | ||
| 92 | nv_subdev(priv)->unit = 0x00000002; | 92 | nv_subdev(priv)->unit = 0x00000002; |
| 93 | nv_subdev(priv)->intr = nouveau_falcon_intr; | ||
| 93 | nv_engine(priv)->cclass = &nvc0_ppp_cclass; | 94 | nv_engine(priv)->cclass = &nvc0_ppp_cclass; |
| 94 | nv_engine(priv)->sclass = nvc0_ppp_sclass; | 95 | nv_engine(priv)->sclass = nvc0_ppp_sclass; |
| 95 | return 0; | 96 | return 0; |
diff --git a/drivers/gpu/drm/nouveau/core/engine/vp/nvc0.c b/drivers/gpu/drm/nouveau/core/engine/vp/nvc0.c index 1879229b60eb..ac1f62aace72 100644 --- a/drivers/gpu/drm/nouveau/core/engine/vp/nvc0.c +++ b/drivers/gpu/drm/nouveau/core/engine/vp/nvc0.c | |||
| @@ -90,6 +90,7 @@ nvc0_vp_ctor(struct nouveau_object *parent, struct nouveau_object *engine, | |||
| 90 | return ret; | 90 | return ret; |
| 91 | 91 | ||
| 92 | nv_subdev(priv)->unit = 0x00020000; | 92 | nv_subdev(priv)->unit = 0x00020000; |
| 93 | nv_subdev(priv)->intr = nouveau_falcon_intr; | ||
| 93 | nv_engine(priv)->cclass = &nvc0_vp_cclass; | 94 | nv_engine(priv)->cclass = &nvc0_vp_cclass; |
| 94 | nv_engine(priv)->sclass = nvc0_vp_sclass; | 95 | nv_engine(priv)->sclass = nvc0_vp_sclass; |
| 95 | return 0; | 96 | return 0; |
diff --git a/drivers/gpu/drm/nouveau/core/engine/vp/nve0.c b/drivers/gpu/drm/nouveau/core/engine/vp/nve0.c index d28ecbf7bc49..d4c3108479c9 100644 --- a/drivers/gpu/drm/nouveau/core/engine/vp/nve0.c +++ b/drivers/gpu/drm/nouveau/core/engine/vp/nve0.c | |||
| @@ -90,6 +90,7 @@ nve0_vp_ctor(struct nouveau_object *parent, struct nouveau_object *engine, | |||
| 90 | return ret; | 90 | return ret; |
| 91 | 91 | ||
| 92 | nv_subdev(priv)->unit = 0x00020000; | 92 | nv_subdev(priv)->unit = 0x00020000; |
| 93 | nv_subdev(priv)->intr = nouveau_falcon_intr; | ||
| 93 | nv_engine(priv)->cclass = &nve0_vp_cclass; | 94 | nv_engine(priv)->cclass = &nve0_vp_cclass; |
| 94 | nv_engine(priv)->sclass = nve0_vp_sclass; | 95 | nv_engine(priv)->sclass = nve0_vp_sclass; |
| 95 | return 0; | 96 | return 0; |
diff --git a/drivers/gpu/drm/nouveau/core/include/engine/falcon.h b/drivers/gpu/drm/nouveau/core/include/engine/falcon.h index 1edec386ab36..181aa7da524d 100644 --- a/drivers/gpu/drm/nouveau/core/include/engine/falcon.h +++ b/drivers/gpu/drm/nouveau/core/include/engine/falcon.h | |||
| @@ -72,6 +72,8 @@ int nouveau_falcon_create_(struct nouveau_object *, struct nouveau_object *, | |||
| 72 | struct nouveau_oclass *, u32, bool, const char *, | 72 | struct nouveau_oclass *, u32, bool, const char *, |
| 73 | const char *, int, void **); | 73 | const char *, int, void **); |
| 74 | 74 | ||
| 75 | void nouveau_falcon_intr(struct nouveau_subdev *subdev); | ||
| 76 | |||
| 75 | #define _nouveau_falcon_dtor _nouveau_engine_dtor | 77 | #define _nouveau_falcon_dtor _nouveau_engine_dtor |
| 76 | int _nouveau_falcon_init(struct nouveau_object *); | 78 | int _nouveau_falcon_init(struct nouveau_object *); |
| 77 | int _nouveau_falcon_fini(struct nouveau_object *, bool); | 79 | int _nouveau_falcon_fini(struct nouveau_object *, bool); |
diff --git a/drivers/gpu/drm/nouveau/nouveau_bo.c b/drivers/gpu/drm/nouveau/nouveau_bo.c index 4b1afb131380..4e7ee5f4155c 100644 --- a/drivers/gpu/drm/nouveau/nouveau_bo.c +++ b/drivers/gpu/drm/nouveau/nouveau_bo.c | |||
| @@ -148,6 +148,7 @@ nouveau_bo_del_ttm(struct ttm_buffer_object *bo) | |||
| 148 | 148 | ||
| 149 | if (unlikely(nvbo->gem)) | 149 | if (unlikely(nvbo->gem)) |
| 150 | DRM_ERROR("bo %p still attached to GEM object\n", bo); | 150 | DRM_ERROR("bo %p still attached to GEM object\n", bo); |
| 151 | WARN_ON(nvbo->pin_refcnt > 0); | ||
| 151 | nv10_bo_put_tile_region(dev, nvbo->tile, NULL); | 152 | nv10_bo_put_tile_region(dev, nvbo->tile, NULL); |
| 152 | kfree(nvbo); | 153 | kfree(nvbo); |
| 153 | } | 154 | } |
| @@ -197,6 +198,12 @@ nouveau_bo_new(struct drm_device *dev, int size, int align, | |||
| 197 | size_t acc_size; | 198 | size_t acc_size; |
| 198 | int ret; | 199 | int ret; |
| 199 | int type = ttm_bo_type_device; | 200 | int type = ttm_bo_type_device; |
| 201 | int max_size = INT_MAX & ~((1 << drm->client.base.vm->vmm->lpg_shift) - 1); | ||
| 202 | |||
| 203 | if (size <= 0 || size > max_size) { | ||
| 204 | nv_warn(drm, "skipped size %x\n", (u32)size); | ||
| 205 | return -EINVAL; | ||
| 206 | } | ||
| 200 | 207 | ||
| 201 | if (sg) | 208 | if (sg) |
| 202 | type = ttm_bo_type_sg; | 209 | type = ttm_bo_type_sg; |
| @@ -340,13 +347,15 @@ nouveau_bo_unpin(struct nouveau_bo *nvbo) | |||
| 340 | { | 347 | { |
| 341 | struct nouveau_drm *drm = nouveau_bdev(nvbo->bo.bdev); | 348 | struct nouveau_drm *drm = nouveau_bdev(nvbo->bo.bdev); |
| 342 | struct ttm_buffer_object *bo = &nvbo->bo; | 349 | struct ttm_buffer_object *bo = &nvbo->bo; |
| 343 | int ret; | 350 | int ret, ref; |
| 344 | 351 | ||
| 345 | ret = ttm_bo_reserve(bo, false, false, false, 0); | 352 | ret = ttm_bo_reserve(bo, false, false, false, 0); |
| 346 | if (ret) | 353 | if (ret) |
| 347 | return ret; | 354 | return ret; |
| 348 | 355 | ||
| 349 | if (--nvbo->pin_refcnt) | 356 | ref = --nvbo->pin_refcnt; |
| 357 | WARN_ON_ONCE(ref < 0); | ||
| 358 | if (ref) | ||
| 350 | goto out; | 359 | goto out; |
| 351 | 360 | ||
| 352 | nouveau_bo_placement_set(nvbo, bo->mem.placement, 0); | 361 | nouveau_bo_placement_set(nvbo, bo->mem.placement, 0); |
| @@ -578,7 +587,7 @@ nve0_bo_move_init(struct nouveau_channel *chan, u32 handle) | |||
| 578 | int ret = RING_SPACE(chan, 2); | 587 | int ret = RING_SPACE(chan, 2); |
| 579 | if (ret == 0) { | 588 | if (ret == 0) { |
| 580 | BEGIN_NVC0(chan, NvSubCopy, 0x0000, 1); | 589 | BEGIN_NVC0(chan, NvSubCopy, 0x0000, 1); |
| 581 | OUT_RING (chan, handle); | 590 | OUT_RING (chan, handle & 0x0000ffff); |
| 582 | FIRE_RING (chan); | 591 | FIRE_RING (chan); |
| 583 | } | 592 | } |
| 584 | return ret; | 593 | return ret; |
| @@ -973,7 +982,7 @@ nouveau_bo_move_m2mf(struct ttm_buffer_object *bo, int evict, bool intr, | |||
| 973 | struct ttm_mem_reg *old_mem = &bo->mem; | 982 | struct ttm_mem_reg *old_mem = &bo->mem; |
| 974 | int ret; | 983 | int ret; |
| 975 | 984 | ||
| 976 | mutex_lock(&chan->cli->mutex); | 985 | mutex_lock_nested(&chan->cli->mutex, SINGLE_DEPTH_NESTING); |
| 977 | 986 | ||
| 978 | /* create temporary vmas for the transfer and attach them to the | 987 | /* create temporary vmas for the transfer and attach them to the |
| 979 | * old nouveau_mem node, these will get cleaned up after ttm has | 988 | * old nouveau_mem node, these will get cleaned up after ttm has |
| @@ -1014,7 +1023,7 @@ nouveau_bo_move_init(struct nouveau_drm *drm) | |||
| 1014 | struct ttm_mem_reg *, struct ttm_mem_reg *); | 1023 | struct ttm_mem_reg *, struct ttm_mem_reg *); |
| 1015 | int (*init)(struct nouveau_channel *, u32 handle); | 1024 | int (*init)(struct nouveau_channel *, u32 handle); |
| 1016 | } _methods[] = { | 1025 | } _methods[] = { |
| 1017 | { "COPY", 0, 0xa0b5, nve0_bo_move_copy, nve0_bo_move_init }, | 1026 | { "COPY", 4, 0xa0b5, nve0_bo_move_copy, nve0_bo_move_init }, |
| 1018 | { "GRCE", 0, 0xa0b5, nve0_bo_move_copy, nvc0_bo_move_init }, | 1027 | { "GRCE", 0, 0xa0b5, nve0_bo_move_copy, nvc0_bo_move_init }, |
| 1019 | { "COPY1", 5, 0x90b8, nvc0_bo_move_copy, nvc0_bo_move_init }, | 1028 | { "COPY1", 5, 0x90b8, nvc0_bo_move_copy, nvc0_bo_move_init }, |
| 1020 | { "COPY0", 4, 0x90b5, nvc0_bo_move_copy, nvc0_bo_move_init }, | 1029 | { "COPY0", 4, 0x90b5, nvc0_bo_move_copy, nvc0_bo_move_init }, |
| @@ -1034,7 +1043,7 @@ nouveau_bo_move_init(struct nouveau_drm *drm) | |||
| 1034 | struct nouveau_channel *chan; | 1043 | struct nouveau_channel *chan; |
| 1035 | u32 handle = (mthd->engine << 16) | mthd->oclass; | 1044 | u32 handle = (mthd->engine << 16) | mthd->oclass; |
| 1036 | 1045 | ||
| 1037 | if (mthd->init == nve0_bo_move_init) | 1046 | if (mthd->engine) |
| 1038 | chan = drm->cechan; | 1047 | chan = drm->cechan; |
| 1039 | else | 1048 | else |
| 1040 | chan = drm->channel; | 1049 | chan = drm->channel; |
diff --git a/drivers/gpu/drm/nouveau/nouveau_display.c b/drivers/gpu/drm/nouveau/nouveau_display.c index 708b2d1c0037..907d20ef6d4d 100644 --- a/drivers/gpu/drm/nouveau/nouveau_display.c +++ b/drivers/gpu/drm/nouveau/nouveau_display.c | |||
| @@ -138,7 +138,7 @@ nouveau_user_framebuffer_create(struct drm_device *dev, | |||
| 138 | { | 138 | { |
| 139 | struct nouveau_framebuffer *nouveau_fb; | 139 | struct nouveau_framebuffer *nouveau_fb; |
| 140 | struct drm_gem_object *gem; | 140 | struct drm_gem_object *gem; |
| 141 | int ret; | 141 | int ret = -ENOMEM; |
| 142 | 142 | ||
| 143 | gem = drm_gem_object_lookup(dev, file_priv, mode_cmd->handles[0]); | 143 | gem = drm_gem_object_lookup(dev, file_priv, mode_cmd->handles[0]); |
| 144 | if (!gem) | 144 | if (!gem) |
| @@ -146,15 +146,19 @@ nouveau_user_framebuffer_create(struct drm_device *dev, | |||
| 146 | 146 | ||
| 147 | nouveau_fb = kzalloc(sizeof(struct nouveau_framebuffer), GFP_KERNEL); | 147 | nouveau_fb = kzalloc(sizeof(struct nouveau_framebuffer), GFP_KERNEL); |
| 148 | if (!nouveau_fb) | 148 | if (!nouveau_fb) |
| 149 | return ERR_PTR(-ENOMEM); | 149 | goto err_unref; |
| 150 | 150 | ||
| 151 | ret = nouveau_framebuffer_init(dev, nouveau_fb, mode_cmd, nouveau_gem_object(gem)); | 151 | ret = nouveau_framebuffer_init(dev, nouveau_fb, mode_cmd, nouveau_gem_object(gem)); |
| 152 | if (ret) { | 152 | if (ret) |
| 153 | drm_gem_object_unreference(gem); | 153 | goto err; |
| 154 | return ERR_PTR(ret); | ||
| 155 | } | ||
| 156 | 154 | ||
| 157 | return &nouveau_fb->base; | 155 | return &nouveau_fb->base; |
| 156 | |||
| 157 | err: | ||
| 158 | kfree(nouveau_fb); | ||
| 159 | err_unref: | ||
| 160 | drm_gem_object_unreference(gem); | ||
| 161 | return ERR_PTR(ret); | ||
| 158 | } | 162 | } |
| 159 | 163 | ||
| 160 | static const struct drm_mode_config_funcs nouveau_mode_config_funcs = { | 164 | static const struct drm_mode_config_funcs nouveau_mode_config_funcs = { |
| @@ -524,9 +528,12 @@ nouveau_crtc_page_flip(struct drm_crtc *crtc, struct drm_framebuffer *fb, | |||
| 524 | struct nouveau_page_flip_state *s; | 528 | struct nouveau_page_flip_state *s; |
| 525 | struct nouveau_channel *chan = NULL; | 529 | struct nouveau_channel *chan = NULL; |
| 526 | struct nouveau_fence *fence; | 530 | struct nouveau_fence *fence; |
| 527 | struct list_head res; | 531 | struct ttm_validate_buffer resv[2] = { |
| 528 | struct ttm_validate_buffer res_val[2]; | 532 | { .bo = &old_bo->bo }, |
| 533 | { .bo = &new_bo->bo }, | ||
| 534 | }; | ||
| 529 | struct ww_acquire_ctx ticket; | 535 | struct ww_acquire_ctx ticket; |
| 536 | LIST_HEAD(res); | ||
| 530 | int ret; | 537 | int ret; |
| 531 | 538 | ||
| 532 | if (!drm->channel) | 539 | if (!drm->channel) |
| @@ -545,27 +552,19 @@ nouveau_crtc_page_flip(struct drm_crtc *crtc, struct drm_framebuffer *fb, | |||
| 545 | chan = drm->channel; | 552 | chan = drm->channel; |
| 546 | spin_unlock(&old_bo->bo.bdev->fence_lock); | 553 | spin_unlock(&old_bo->bo.bdev->fence_lock); |
| 547 | 554 | ||
| 548 | mutex_lock(&chan->cli->mutex); | ||
| 549 | |||
| 550 | if (new_bo != old_bo) { | 555 | if (new_bo != old_bo) { |
| 551 | ret = nouveau_bo_pin(new_bo, TTM_PL_FLAG_VRAM); | 556 | ret = nouveau_bo_pin(new_bo, TTM_PL_FLAG_VRAM); |
| 552 | if (likely(!ret)) { | 557 | if (ret) |
| 553 | res_val[0].bo = &old_bo->bo; | 558 | goto fail_free; |
| 554 | res_val[1].bo = &new_bo->bo; | ||
| 555 | INIT_LIST_HEAD(&res); | ||
| 556 | list_add_tail(&res_val[0].head, &res); | ||
| 557 | list_add_tail(&res_val[1].head, &res); | ||
| 558 | ret = ttm_eu_reserve_buffers(&ticket, &res); | ||
| 559 | if (ret) | ||
| 560 | nouveau_bo_unpin(new_bo); | ||
| 561 | } | ||
| 562 | } else | ||
| 563 | ret = ttm_bo_reserve(&new_bo->bo, false, false, false, 0); | ||
| 564 | 559 | ||
| 565 | if (ret) { | 560 | list_add(&resv[1].head, &res); |
| 566 | mutex_unlock(&chan->cli->mutex); | ||
| 567 | goto fail_free; | ||
| 568 | } | 561 | } |
| 562 | list_add(&resv[0].head, &res); | ||
| 563 | |||
| 564 | mutex_lock(&chan->cli->mutex); | ||
| 565 | ret = ttm_eu_reserve_buffers(&ticket, &res); | ||
| 566 | if (ret) | ||
| 567 | goto fail_unpin; | ||
| 569 | 568 | ||
| 570 | /* Initialize a page flip struct */ | 569 | /* Initialize a page flip struct */ |
| 571 | *s = (struct nouveau_page_flip_state) | 570 | *s = (struct nouveau_page_flip_state) |
| @@ -576,10 +575,8 @@ nouveau_crtc_page_flip(struct drm_crtc *crtc, struct drm_framebuffer *fb, | |||
| 576 | /* Emit a page flip */ | 575 | /* Emit a page flip */ |
| 577 | if (nv_device(drm->device)->card_type >= NV_50) { | 576 | if (nv_device(drm->device)->card_type >= NV_50) { |
| 578 | ret = nv50_display_flip_next(crtc, fb, chan, 0); | 577 | ret = nv50_display_flip_next(crtc, fb, chan, 0); |
| 579 | if (ret) { | 578 | if (ret) |
| 580 | mutex_unlock(&chan->cli->mutex); | ||
| 581 | goto fail_unreserve; | 579 | goto fail_unreserve; |
| 582 | } | ||
| 583 | } | 580 | } |
| 584 | 581 | ||
| 585 | ret = nouveau_page_flip_emit(chan, old_bo, new_bo, s, &fence); | 582 | ret = nouveau_page_flip_emit(chan, old_bo, new_bo, s, &fence); |
| @@ -590,22 +587,18 @@ nouveau_crtc_page_flip(struct drm_crtc *crtc, struct drm_framebuffer *fb, | |||
| 590 | /* Update the crtc struct and cleanup */ | 587 | /* Update the crtc struct and cleanup */ |
| 591 | crtc->fb = fb; | 588 | crtc->fb = fb; |
| 592 | 589 | ||
| 593 | if (old_bo != new_bo) { | 590 | ttm_eu_fence_buffer_objects(&ticket, &res, fence); |
| 594 | ttm_eu_fence_buffer_objects(&ticket, &res, fence); | 591 | if (old_bo != new_bo) |
| 595 | nouveau_bo_unpin(old_bo); | 592 | nouveau_bo_unpin(old_bo); |
| 596 | } else { | ||
| 597 | nouveau_bo_fence(new_bo, fence); | ||
| 598 | ttm_bo_unreserve(&new_bo->bo); | ||
| 599 | } | ||
| 600 | nouveau_fence_unref(&fence); | 593 | nouveau_fence_unref(&fence); |
| 601 | return 0; | 594 | return 0; |
| 602 | 595 | ||
| 603 | fail_unreserve: | 596 | fail_unreserve: |
| 604 | if (old_bo != new_bo) { | 597 | ttm_eu_backoff_reservation(&ticket, &res); |
| 605 | ttm_eu_backoff_reservation(&ticket, &res); | 598 | fail_unpin: |
| 599 | mutex_unlock(&chan->cli->mutex); | ||
| 600 | if (old_bo != new_bo) | ||
| 606 | nouveau_bo_unpin(new_bo); | 601 | nouveau_bo_unpin(new_bo); |
| 607 | } else | ||
| 608 | ttm_bo_unreserve(&new_bo->bo); | ||
| 609 | fail_free: | 602 | fail_free: |
| 610 | kfree(s); | 603 | kfree(s); |
| 611 | return ret; | 604 | return ret; |
diff --git a/drivers/gpu/drm/nouveau/nouveau_drm.c b/drivers/gpu/drm/nouveau/nouveau_drm.c index 218a4b522fe5..61972668fd05 100644 --- a/drivers/gpu/drm/nouveau/nouveau_drm.c +++ b/drivers/gpu/drm/nouveau/nouveau_drm.c | |||
| @@ -192,6 +192,18 @@ nouveau_accel_init(struct nouveau_drm *drm) | |||
| 192 | 192 | ||
| 193 | arg0 = NVE0_CHANNEL_IND_ENGINE_GR; | 193 | arg0 = NVE0_CHANNEL_IND_ENGINE_GR; |
| 194 | arg1 = 1; | 194 | arg1 = 1; |
| 195 | } else | ||
| 196 | if (device->chipset >= 0xa3 && | ||
| 197 | device->chipset != 0xaa && | ||
| 198 | device->chipset != 0xac) { | ||
| 199 | ret = nouveau_channel_new(drm, &drm->client, NVDRM_DEVICE, | ||
| 200 | NVDRM_CHAN + 1, NvDmaFB, NvDmaTT, | ||
| 201 | &drm->cechan); | ||
| 202 | if (ret) | ||
| 203 | NV_ERROR(drm, "failed to create ce channel, %d\n", ret); | ||
| 204 | |||
| 205 | arg0 = NvDmaFB; | ||
| 206 | arg1 = NvDmaTT; | ||
| 195 | } else { | 207 | } else { |
| 196 | arg0 = NvDmaFB; | 208 | arg0 = NvDmaFB; |
| 197 | arg1 = NvDmaTT; | 209 | arg1 = NvDmaTT; |
| @@ -284,8 +296,6 @@ static int nouveau_drm_probe(struct pci_dev *pdev, | |||
| 284 | return 0; | 296 | return 0; |
| 285 | } | 297 | } |
| 286 | 298 | ||
| 287 | static struct lock_class_key drm_client_lock_class_key; | ||
| 288 | |||
| 289 | static int | 299 | static int |
| 290 | nouveau_drm_load(struct drm_device *dev, unsigned long flags) | 300 | nouveau_drm_load(struct drm_device *dev, unsigned long flags) |
| 291 | { | 301 | { |
| @@ -297,7 +307,6 @@ nouveau_drm_load(struct drm_device *dev, unsigned long flags) | |||
| 297 | ret = nouveau_cli_create(pdev, "DRM", sizeof(*drm), (void**)&drm); | 307 | ret = nouveau_cli_create(pdev, "DRM", sizeof(*drm), (void**)&drm); |
| 298 | if (ret) | 308 | if (ret) |
| 299 | return ret; | 309 | return ret; |
| 300 | lockdep_set_class(&drm->client.mutex, &drm_client_lock_class_key); | ||
| 301 | 310 | ||
| 302 | dev->dev_private = drm; | 311 | dev->dev_private = drm; |
| 303 | drm->dev = dev; | 312 | drm->dev = dev; |
diff --git a/drivers/gpu/drm/nouveau/nouveau_fbcon.c b/drivers/gpu/drm/nouveau/nouveau_fbcon.c index 9352010030e9..4c1bc061fae2 100644 --- a/drivers/gpu/drm/nouveau/nouveau_fbcon.c +++ b/drivers/gpu/drm/nouveau/nouveau_fbcon.c | |||
| @@ -385,6 +385,7 @@ out_unlock: | |||
| 385 | mutex_unlock(&dev->struct_mutex); | 385 | mutex_unlock(&dev->struct_mutex); |
| 386 | if (chan) | 386 | if (chan) |
| 387 | nouveau_bo_vma_del(nvbo, &fbcon->nouveau_fb.vma); | 387 | nouveau_bo_vma_del(nvbo, &fbcon->nouveau_fb.vma); |
| 388 | nouveau_bo_unmap(nvbo); | ||
| 388 | out_unpin: | 389 | out_unpin: |
| 389 | nouveau_bo_unpin(nvbo); | 390 | nouveau_bo_unpin(nvbo); |
| 390 | out_unref: | 391 | out_unref: |
diff --git a/drivers/gpu/drm/nouveau/nouveau_fence.c b/drivers/gpu/drm/nouveau/nouveau_fence.c index 1680d9187bab..be3149932c2d 100644 --- a/drivers/gpu/drm/nouveau/nouveau_fence.c +++ b/drivers/gpu/drm/nouveau/nouveau_fence.c | |||
| @@ -143,7 +143,7 @@ nouveau_fence_emit(struct nouveau_fence *fence, struct nouveau_channel *chan) | |||
| 143 | int ret; | 143 | int ret; |
| 144 | 144 | ||
| 145 | fence->channel = chan; | 145 | fence->channel = chan; |
| 146 | fence->timeout = jiffies + (3 * DRM_HZ); | 146 | fence->timeout = jiffies + (15 * DRM_HZ); |
| 147 | fence->sequence = ++fctx->sequence; | 147 | fence->sequence = ++fctx->sequence; |
| 148 | 148 | ||
| 149 | ret = fctx->emit(fence); | 149 | ret = fctx->emit(fence); |
diff --git a/drivers/gpu/drm/nouveau/nouveau_gem.c b/drivers/gpu/drm/nouveau/nouveau_gem.c index e72d09c068a8..830cb7bad922 100644 --- a/drivers/gpu/drm/nouveau/nouveau_gem.c +++ b/drivers/gpu/drm/nouveau/nouveau_gem.c | |||
| @@ -50,12 +50,6 @@ nouveau_gem_object_del(struct drm_gem_object *gem) | |||
| 50 | return; | 50 | return; |
| 51 | nvbo->gem = NULL; | 51 | nvbo->gem = NULL; |
| 52 | 52 | ||
| 53 | /* Lockdep hates you for doing reserve with gem object lock held */ | ||
| 54 | if (WARN_ON_ONCE(nvbo->pin_refcnt)) { | ||
| 55 | nvbo->pin_refcnt = 1; | ||
| 56 | nouveau_bo_unpin(nvbo); | ||
| 57 | } | ||
| 58 | |||
| 59 | if (gem->import_attach) | 53 | if (gem->import_attach) |
| 60 | drm_prime_gem_destroy(gem, nvbo->bo.sg); | 54 | drm_prime_gem_destroy(gem, nvbo->bo.sg); |
| 61 | 55 | ||
diff --git a/drivers/gpu/drm/nouveau/nv50_display.c b/drivers/gpu/drm/nouveau/nv50_display.c index 54dc6355b0c2..8b40a36c1b57 100644 --- a/drivers/gpu/drm/nouveau/nv50_display.c +++ b/drivers/gpu/drm/nouveau/nv50_display.c | |||
| @@ -355,6 +355,7 @@ struct nv50_oimm { | |||
| 355 | 355 | ||
| 356 | struct nv50_head { | 356 | struct nv50_head { |
| 357 | struct nouveau_crtc base; | 357 | struct nouveau_crtc base; |
| 358 | struct nouveau_bo *image; | ||
| 358 | struct nv50_curs curs; | 359 | struct nv50_curs curs; |
| 359 | struct nv50_sync sync; | 360 | struct nv50_sync sync; |
| 360 | struct nv50_ovly ovly; | 361 | struct nv50_ovly ovly; |
| @@ -517,9 +518,10 @@ nv50_display_flip_next(struct drm_crtc *crtc, struct drm_framebuffer *fb, | |||
| 517 | { | 518 | { |
| 518 | struct nouveau_framebuffer *nv_fb = nouveau_framebuffer(fb); | 519 | struct nouveau_framebuffer *nv_fb = nouveau_framebuffer(fb); |
| 519 | struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc); | 520 | struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc); |
| 521 | struct nv50_head *head = nv50_head(crtc); | ||
| 520 | struct nv50_sync *sync = nv50_sync(crtc); | 522 | struct nv50_sync *sync = nv50_sync(crtc); |
| 521 | int head = nv_crtc->index, ret; | ||
| 522 | u32 *push; | 523 | u32 *push; |
| 524 | int ret; | ||
| 523 | 525 | ||
| 524 | swap_interval <<= 4; | 526 | swap_interval <<= 4; |
| 525 | if (swap_interval == 0) | 527 | if (swap_interval == 0) |
| @@ -537,7 +539,7 @@ nv50_display_flip_next(struct drm_crtc *crtc, struct drm_framebuffer *fb, | |||
| 537 | return ret; | 539 | return ret; |
| 538 | 540 | ||
| 539 | BEGIN_NV04(chan, 0, NV11_SUBCHAN_DMA_SEMAPHORE, 2); | 541 | BEGIN_NV04(chan, 0, NV11_SUBCHAN_DMA_SEMAPHORE, 2); |
| 540 | OUT_RING (chan, NvEvoSema0 + head); | 542 | OUT_RING (chan, NvEvoSema0 + nv_crtc->index); |
| 541 | OUT_RING (chan, sync->addr ^ 0x10); | 543 | OUT_RING (chan, sync->addr ^ 0x10); |
| 542 | BEGIN_NV04(chan, 0, NV11_SUBCHAN_SEMAPHORE_RELEASE, 1); | 544 | BEGIN_NV04(chan, 0, NV11_SUBCHAN_SEMAPHORE_RELEASE, 1); |
| 543 | OUT_RING (chan, sync->data + 1); | 545 | OUT_RING (chan, sync->data + 1); |
| @@ -546,7 +548,7 @@ nv50_display_flip_next(struct drm_crtc *crtc, struct drm_framebuffer *fb, | |||
| 546 | OUT_RING (chan, sync->data); | 548 | OUT_RING (chan, sync->data); |
| 547 | } else | 549 | } else |
| 548 | if (chan && nv_mclass(chan->object) < NVC0_CHANNEL_IND_CLASS) { | 550 | if (chan && nv_mclass(chan->object) < NVC0_CHANNEL_IND_CLASS) { |
| 549 | u64 addr = nv84_fence_crtc(chan, head) + sync->addr; | 551 | u64 addr = nv84_fence_crtc(chan, nv_crtc->index) + sync->addr; |
| 550 | ret = RING_SPACE(chan, 12); | 552 | ret = RING_SPACE(chan, 12); |
| 551 | if (ret) | 553 | if (ret) |
| 552 | return ret; | 554 | return ret; |
| @@ -565,7 +567,7 @@ nv50_display_flip_next(struct drm_crtc *crtc, struct drm_framebuffer *fb, | |||
| 565 | OUT_RING (chan, NV84_SUBCHAN_SEMAPHORE_TRIGGER_ACQUIRE_EQUAL); | 567 | OUT_RING (chan, NV84_SUBCHAN_SEMAPHORE_TRIGGER_ACQUIRE_EQUAL); |
| 566 | } else | 568 | } else |
| 567 | if (chan) { | 569 | if (chan) { |
| 568 | u64 addr = nv84_fence_crtc(chan, head) + sync->addr; | 570 | u64 addr = nv84_fence_crtc(chan, nv_crtc->index) + sync->addr; |
| 569 | ret = RING_SPACE(chan, 10); | 571 | ret = RING_SPACE(chan, 10); |
| 570 | if (ret) | 572 | if (ret) |
| 571 | return ret; | 573 | return ret; |
| @@ -630,6 +632,8 @@ nv50_display_flip_next(struct drm_crtc *crtc, struct drm_framebuffer *fb, | |||
| 630 | evo_mthd(push, 0x0080, 1); | 632 | evo_mthd(push, 0x0080, 1); |
| 631 | evo_data(push, 0x00000000); | 633 | evo_data(push, 0x00000000); |
| 632 | evo_kick(push, sync); | 634 | evo_kick(push, sync); |
| 635 | |||
| 636 | nouveau_bo_ref(nv_fb->nvbo, &head->image); | ||
| 633 | return 0; | 637 | return 0; |
| 634 | } | 638 | } |
| 635 | 639 | ||
| @@ -1038,18 +1042,17 @@ static int | |||
| 1038 | nv50_crtc_swap_fbs(struct drm_crtc *crtc, struct drm_framebuffer *old_fb) | 1042 | nv50_crtc_swap_fbs(struct drm_crtc *crtc, struct drm_framebuffer *old_fb) |
| 1039 | { | 1043 | { |
| 1040 | struct nouveau_framebuffer *nvfb = nouveau_framebuffer(crtc->fb); | 1044 | struct nouveau_framebuffer *nvfb = nouveau_framebuffer(crtc->fb); |
| 1045 | struct nv50_head *head = nv50_head(crtc); | ||
| 1041 | int ret; | 1046 | int ret; |
| 1042 | 1047 | ||
| 1043 | ret = nouveau_bo_pin(nvfb->nvbo, TTM_PL_FLAG_VRAM); | 1048 | ret = nouveau_bo_pin(nvfb->nvbo, TTM_PL_FLAG_VRAM); |
| 1044 | if (ret) | 1049 | if (ret == 0) { |
| 1045 | return ret; | 1050 | if (head->image) |
| 1046 | 1051 | nouveau_bo_unpin(head->image); | |
| 1047 | if (old_fb) { | 1052 | nouveau_bo_ref(nvfb->nvbo, &head->image); |
| 1048 | nvfb = nouveau_framebuffer(old_fb); | ||
| 1049 | nouveau_bo_unpin(nvfb->nvbo); | ||
| 1050 | } | 1053 | } |
| 1051 | 1054 | ||
| 1052 | return 0; | 1055 | return ret; |
| 1053 | } | 1056 | } |
| 1054 | 1057 | ||
| 1055 | static int | 1058 | static int |
| @@ -1198,6 +1201,15 @@ nv50_crtc_lut_load(struct drm_crtc *crtc) | |||
| 1198 | } | 1201 | } |
| 1199 | } | 1202 | } |
| 1200 | 1203 | ||
| 1204 | static void | ||
| 1205 | nv50_crtc_disable(struct drm_crtc *crtc) | ||
| 1206 | { | ||
| 1207 | struct nv50_head *head = nv50_head(crtc); | ||
| 1208 | if (head->image) | ||
| 1209 | nouveau_bo_unpin(head->image); | ||
| 1210 | nouveau_bo_ref(NULL, &head->image); | ||
| 1211 | } | ||
| 1212 | |||
| 1201 | static int | 1213 | static int |
| 1202 | nv50_crtc_cursor_set(struct drm_crtc *crtc, struct drm_file *file_priv, | 1214 | nv50_crtc_cursor_set(struct drm_crtc *crtc, struct drm_file *file_priv, |
| 1203 | uint32_t handle, uint32_t width, uint32_t height) | 1215 | uint32_t handle, uint32_t width, uint32_t height) |
| @@ -1271,18 +1283,29 @@ nv50_crtc_destroy(struct drm_crtc *crtc) | |||
| 1271 | struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc); | 1283 | struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc); |
| 1272 | struct nv50_disp *disp = nv50_disp(crtc->dev); | 1284 | struct nv50_disp *disp = nv50_disp(crtc->dev); |
| 1273 | struct nv50_head *head = nv50_head(crtc); | 1285 | struct nv50_head *head = nv50_head(crtc); |
| 1286 | |||
| 1274 | nv50_dmac_destroy(disp->core, &head->ovly.base); | 1287 | nv50_dmac_destroy(disp->core, &head->ovly.base); |
| 1275 | nv50_pioc_destroy(disp->core, &head->oimm.base); | 1288 | nv50_pioc_destroy(disp->core, &head->oimm.base); |
| 1276 | nv50_dmac_destroy(disp->core, &head->sync.base); | 1289 | nv50_dmac_destroy(disp->core, &head->sync.base); |
| 1277 | nv50_pioc_destroy(disp->core, &head->curs.base); | 1290 | nv50_pioc_destroy(disp->core, &head->curs.base); |
| 1291 | |||
| 1292 | /*XXX: this shouldn't be necessary, but the core doesn't call | ||
| 1293 | * disconnect() during the cleanup paths | ||
| 1294 | */ | ||
| 1295 | if (head->image) | ||
| 1296 | nouveau_bo_unpin(head->image); | ||
| 1297 | nouveau_bo_ref(NULL, &head->image); | ||
| 1298 | |||
| 1278 | nouveau_bo_unmap(nv_crtc->cursor.nvbo); | 1299 | nouveau_bo_unmap(nv_crtc->cursor.nvbo); |
| 1279 | if (nv_crtc->cursor.nvbo) | 1300 | if (nv_crtc->cursor.nvbo) |
| 1280 | nouveau_bo_unpin(nv_crtc->cursor.nvbo); | 1301 | nouveau_bo_unpin(nv_crtc->cursor.nvbo); |
| 1281 | nouveau_bo_ref(NULL, &nv_crtc->cursor.nvbo); | 1302 | nouveau_bo_ref(NULL, &nv_crtc->cursor.nvbo); |
| 1303 | |||
| 1282 | nouveau_bo_unmap(nv_crtc->lut.nvbo); | 1304 | nouveau_bo_unmap(nv_crtc->lut.nvbo); |
| 1283 | if (nv_crtc->lut.nvbo) | 1305 | if (nv_crtc->lut.nvbo) |
| 1284 | nouveau_bo_unpin(nv_crtc->lut.nvbo); | 1306 | nouveau_bo_unpin(nv_crtc->lut.nvbo); |
| 1285 | nouveau_bo_ref(NULL, &nv_crtc->lut.nvbo); | 1307 | nouveau_bo_ref(NULL, &nv_crtc->lut.nvbo); |
| 1308 | |||
| 1286 | drm_crtc_cleanup(crtc); | 1309 | drm_crtc_cleanup(crtc); |
| 1287 | kfree(crtc); | 1310 | kfree(crtc); |
| 1288 | } | 1311 | } |
| @@ -1296,6 +1319,7 @@ static const struct drm_crtc_helper_funcs nv50_crtc_hfunc = { | |||
| 1296 | .mode_set_base = nv50_crtc_mode_set_base, | 1319 | .mode_set_base = nv50_crtc_mode_set_base, |
| 1297 | .mode_set_base_atomic = nv50_crtc_mode_set_base_atomic, | 1320 | .mode_set_base_atomic = nv50_crtc_mode_set_base_atomic, |
| 1298 | .load_lut = nv50_crtc_lut_load, | 1321 | .load_lut = nv50_crtc_lut_load, |
| 1322 | .disable = nv50_crtc_disable, | ||
| 1299 | }; | 1323 | }; |
| 1300 | 1324 | ||
| 1301 | static const struct drm_crtc_funcs nv50_crtc_func = { | 1325 | static const struct drm_crtc_funcs nv50_crtc_func = { |
