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 = { |