Skip to content

Commit 8e1f80c

Browse files
committed
Merge tag 'drm-intel-fixes-2013-09-19' of git://people.freedesktop.org/~danvet/drm-intel into drm-fixes
Some more dealock fixes around pageflips and gpu hangs, fixes for hsw hangs when doing modesets/dpms. And a few minor things to rectify issues with our modeset state tracking which the checker spotted. * tag 'drm-intel-fixes-2013-09-19' of git://people.freedesktop.org/~danvet/drm-intel: drm/i915: Don't enable the cursor on a disable pipe drm/i915: do not update cursor in crtc mode set drm/i915: kill set_need_resched drm/i915/dvo: set crtc timings again for panel fixed modes drm/i915/sdvo: Robustify the dtd<->drm_mode conversions drm/i915/sdvo: Fully translate sync flags in the dtd->mode conversion drm/i915: Use proper print format for debug prints drm/i915: fix wait_for_pending_flips vs gpu hang deadlock drm/i915: Track pfit enable state separately from size
2 parents c21eb21 + f2f5f77 commit 8e1f80c

File tree

9 files changed

+122
-74
lines changed

9 files changed

+122
-74
lines changed

drivers/gpu/drm/i915/i915_gem.c

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1390,14 +1390,11 @@ int i915_gem_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
13901390
if (i915_terminally_wedged(&dev_priv->gpu_error))
13911391
return VM_FAULT_SIGBUS;
13921392
case -EAGAIN:
1393-
/* Give the error handler a chance to run and move the
1394-
* objects off the GPU active list. Next time we service the
1395-
* fault, we should be able to transition the page into the
1396-
* GTT without touching the GPU (and so avoid further
1397-
* EIO/EGAIN). If the GPU is wedged, then there is no issue
1398-
* with coherency, just lost writes.
1393+
/*
1394+
* EAGAIN means the gpu is hung and we'll wait for the error
1395+
* handler to reset everything when re-faulting in
1396+
* i915_mutex_lock_interruptible.
13991397
*/
1400-
set_need_resched();
14011398
case 0:
14021399
case -ERESTARTSYS:
14031400
case -EINTR:

drivers/gpu/drm/i915/i915_irq.c

Lines changed: 54 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1469,6 +1469,34 @@ static irqreturn_t ironlake_irq_handler(int irq, void *arg)
14691469
return ret;
14701470
}
14711471

1472+
static void i915_error_wake_up(struct drm_i915_private *dev_priv,
1473+
bool reset_completed)
1474+
{
1475+
struct intel_ring_buffer *ring;
1476+
int i;
1477+
1478+
/*
1479+
* Notify all waiters for GPU completion events that reset state has
1480+
* been changed, and that they need to restart their wait after
1481+
* checking for potential errors (and bail out to drop locks if there is
1482+
* a gpu reset pending so that i915_error_work_func can acquire them).
1483+
*/
1484+
1485+
/* Wake up __wait_seqno, potentially holding dev->struct_mutex. */
1486+
for_each_ring(ring, dev_priv, i)
1487+
wake_up_all(&ring->irq_queue);
1488+
1489+
/* Wake up intel_crtc_wait_for_pending_flips, holding crtc->mutex. */
1490+
wake_up_all(&dev_priv->pending_flip_queue);
1491+
1492+
/*
1493+
* Signal tasks blocked in i915_gem_wait_for_error that the pending
1494+
* reset state is cleared.
1495+
*/
1496+
if (reset_completed)
1497+
wake_up_all(&dev_priv->gpu_error.reset_queue);
1498+
}
1499+
14721500
/**
14731501
* i915_error_work_func - do process context error handling work
14741502
* @work: work struct
@@ -1483,11 +1511,10 @@ static void i915_error_work_func(struct work_struct *work)
14831511
drm_i915_private_t *dev_priv = container_of(error, drm_i915_private_t,
14841512
gpu_error);
14851513
struct drm_device *dev = dev_priv->dev;
1486-
struct intel_ring_buffer *ring;
14871514
char *error_event[] = { I915_ERROR_UEVENT "=1", NULL };
14881515
char *reset_event[] = { I915_RESET_UEVENT "=1", NULL };
14891516
char *reset_done_event[] = { I915_ERROR_UEVENT "=0", NULL };
1490-
int i, ret;
1517+
int ret;
14911518

14921519
kobject_uevent_env(&dev->primary->kdev.kobj, KOBJ_CHANGE, error_event);
14931520

@@ -1506,8 +1533,16 @@ static void i915_error_work_func(struct work_struct *work)
15061533
kobject_uevent_env(&dev->primary->kdev.kobj, KOBJ_CHANGE,
15071534
reset_event);
15081535

1536+
/*
1537+
* All state reset _must_ be completed before we update the
1538+
* reset counter, for otherwise waiters might miss the reset
1539+
* pending state and not properly drop locks, resulting in
1540+
* deadlocks with the reset work.
1541+
*/
15091542
ret = i915_reset(dev);
15101543

1544+
intel_display_handle_reset(dev);
1545+
15111546
if (ret == 0) {
15121547
/*
15131548
* After all the gem state is reset, increment the reset
@@ -1528,12 +1563,11 @@ static void i915_error_work_func(struct work_struct *work)
15281563
atomic_set(&error->reset_counter, I915_WEDGED);
15291564
}
15301565

1531-
for_each_ring(ring, dev_priv, i)
1532-
wake_up_all(&ring->irq_queue);
1533-
1534-
intel_display_handle_reset(dev);
1535-
1536-
wake_up_all(&dev_priv->gpu_error.reset_queue);
1566+
/*
1567+
* Note: The wake_up also serves as a memory barrier so that
1568+
* waiters see the update value of the reset counter atomic_t.
1569+
*/
1570+
i915_error_wake_up(dev_priv, true);
15371571
}
15381572
}
15391573

@@ -1642,8 +1676,6 @@ static void i915_report_and_clear_eir(struct drm_device *dev)
16421676
void i915_handle_error(struct drm_device *dev, bool wedged)
16431677
{
16441678
struct drm_i915_private *dev_priv = dev->dev_private;
1645-
struct intel_ring_buffer *ring;
1646-
int i;
16471679

16481680
i915_capture_error_state(dev);
16491681
i915_report_and_clear_eir(dev);
@@ -1653,11 +1685,19 @@ void i915_handle_error(struct drm_device *dev, bool wedged)
16531685
&dev_priv->gpu_error.reset_counter);
16541686

16551687
/*
1656-
* Wakeup waiting processes so that the reset work item
1657-
* doesn't deadlock trying to grab various locks.
1688+
* Wakeup waiting processes so that the reset work function
1689+
* i915_error_work_func doesn't deadlock trying to grab various
1690+
* locks. By bumping the reset counter first, the woken
1691+
* processes will see a reset in progress and back off,
1692+
* releasing their locks and then wait for the reset completion.
1693+
* We must do this for _all_ gpu waiters that might hold locks
1694+
* that the reset work needs to acquire.
1695+
*
1696+
* Note: The wake_up serves as the required memory barrier to
1697+
* ensure that the waiters see the updated value of the reset
1698+
* counter atomic_t.
16581699
*/
1659-
for_each_ring(ring, dev_priv, i)
1660-
wake_up_all(&ring->irq_queue);
1700+
i915_error_wake_up(dev_priv, false);
16611701
}
16621702

16631703
/*

drivers/gpu/drm/i915/intel_ddi.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -778,7 +778,7 @@ void intel_ddi_enable_transcoder_func(struct drm_crtc *crtc)
778778
/* Can only use the always-on power well for eDP when
779779
* not using the panel fitter, and when not using motion
780780
* blur mitigation (which we don't support). */
781-
if (intel_crtc->config.pch_pfit.size)
781+
if (intel_crtc->config.pch_pfit.enabled)
782782
temp |= TRANS_DDI_EDP_INPUT_A_ONOFF;
783783
else
784784
temp |= TRANS_DDI_EDP_INPUT_A_ON;

drivers/gpu/drm/i915/intel_display.c

Lines changed: 20 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -2249,7 +2249,7 @@ intel_pipe_set_base(struct drm_crtc *crtc, int x, int y,
22492249
I915_WRITE(PIPESRC(intel_crtc->pipe),
22502250
((crtc->mode.hdisplay - 1) << 16) |
22512251
(crtc->mode.vdisplay - 1));
2252-
if (!intel_crtc->config.pch_pfit.size &&
2252+
if (!intel_crtc->config.pch_pfit.enabled &&
22532253
(intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS) ||
22542254
intel_pipe_has_type(crtc, INTEL_OUTPUT_EDP))) {
22552255
I915_WRITE(PF_CTL(intel_crtc->pipe), 0);
@@ -3203,7 +3203,7 @@ static void ironlake_pfit_enable(struct intel_crtc *crtc)
32033203
struct drm_i915_private *dev_priv = dev->dev_private;
32043204
int pipe = crtc->pipe;
32053205

3206-
if (crtc->config.pch_pfit.size) {
3206+
if (crtc->config.pch_pfit.enabled) {
32073207
/* Force use of hard-coded filter coefficients
32083208
* as some pre-programmed values are broken,
32093209
* e.g. x201.
@@ -3428,7 +3428,7 @@ static void ironlake_pfit_disable(struct intel_crtc *crtc)
34283428

34293429
/* To avoid upsetting the power well on haswell only disable the pfit if
34303430
* it's in use. The hw state code will make sure we get this right. */
3431-
if (crtc->config.pch_pfit.size) {
3431+
if (crtc->config.pch_pfit.enabled) {
34323432
I915_WRITE(PF_CTL(pipe), 0);
34333433
I915_WRITE(PF_WIN_POS(pipe), 0);
34343434
I915_WRITE(PF_WIN_SZ(pipe), 0);
@@ -4877,9 +4877,6 @@ static int i9xx_crtc_mode_set(struct drm_crtc *crtc,
48774877
return -EINVAL;
48784878
}
48794879

4880-
/* Ensure that the cursor is valid for the new mode before changing... */
4881-
intel_crtc_update_cursor(crtc, true);
4882-
48834880
if (is_lvds && dev_priv->lvds_downclock_avail) {
48844881
/*
48854882
* Ensure we match the reduced clock's P to the target clock.
@@ -5768,9 +5765,6 @@ static int ironlake_crtc_mode_set(struct drm_crtc *crtc,
57685765
intel_crtc->config.dpll.p2 = clock.p2;
57695766
}
57705767

5771-
/* Ensure that the cursor is valid for the new mode before changing... */
5772-
intel_crtc_update_cursor(crtc, true);
5773-
57745768
/* CPU eDP is the only output that doesn't need a PCH PLL of its own. */
57755769
if (intel_crtc->config.has_pch_encoder) {
57765770
fp = i9xx_dpll_compute_fp(&intel_crtc->config.dpll);
@@ -5859,6 +5853,7 @@ static void ironlake_get_pfit_config(struct intel_crtc *crtc,
58595853
tmp = I915_READ(PF_CTL(crtc->pipe));
58605854

58615855
if (tmp & PF_ENABLE) {
5856+
pipe_config->pch_pfit.enabled = true;
58625857
pipe_config->pch_pfit.pos = I915_READ(PF_WIN_POS(crtc->pipe));
58635858
pipe_config->pch_pfit.size = I915_READ(PF_WIN_SZ(crtc->pipe));
58645859

@@ -6236,7 +6231,7 @@ static void haswell_modeset_global_resources(struct drm_device *dev)
62366231
if (!crtc->base.enabled)
62376232
continue;
62386233

6239-
if (crtc->pipe != PIPE_A || crtc->config.pch_pfit.size ||
6234+
if (crtc->pipe != PIPE_A || crtc->config.pch_pfit.enabled ||
62406235
crtc->config.cpu_transcoder != TRANSCODER_EDP)
62416236
enable = true;
62426237
}
@@ -6259,9 +6254,6 @@ static int haswell_crtc_mode_set(struct drm_crtc *crtc,
62596254
if (!intel_ddi_pll_mode_set(crtc))
62606255
return -EINVAL;
62616256

6262-
/* Ensure that the cursor is valid for the new mode before changing... */
6263-
intel_crtc_update_cursor(crtc, true);
6264-
62656257
if (intel_crtc->config.has_dp_encoder)
62666258
intel_dp_set_m_n(intel_crtc);
62676259

@@ -6494,15 +6486,15 @@ static void haswell_write_eld(struct drm_connector *connector,
64946486

64956487
/* Set ELD valid state */
64966488
tmp = I915_READ(aud_cntrl_st2);
6497-
DRM_DEBUG_DRIVER("HDMI audio: pin eld vld status=0x%8x\n", tmp);
6489+
DRM_DEBUG_DRIVER("HDMI audio: pin eld vld status=0x%08x\n", tmp);
64986490
tmp |= (AUDIO_ELD_VALID_A << (pipe * 4));
64996491
I915_WRITE(aud_cntrl_st2, tmp);
65006492
tmp = I915_READ(aud_cntrl_st2);
6501-
DRM_DEBUG_DRIVER("HDMI audio: eld vld status=0x%8x\n", tmp);
6493+
DRM_DEBUG_DRIVER("HDMI audio: eld vld status=0x%08x\n", tmp);
65026494

65036495
/* Enable HDMI mode */
65046496
tmp = I915_READ(aud_config);
6505-
DRM_DEBUG_DRIVER("HDMI audio: audio conf: 0x%8x\n", tmp);
6497+
DRM_DEBUG_DRIVER("HDMI audio: audio conf: 0x%08x\n", tmp);
65066498
/* clear N_programing_enable and N_value_index */
65076499
tmp &= ~(AUD_CONFIG_N_VALUE_INDEX | AUD_CONFIG_N_PROG_ENABLE);
65086500
I915_WRITE(aud_config, tmp);
@@ -6937,7 +6929,8 @@ static int intel_crtc_cursor_set(struct drm_crtc *crtc,
69376929
intel_crtc->cursor_width = width;
69386930
intel_crtc->cursor_height = height;
69396931

6940-
intel_crtc_update_cursor(crtc, intel_crtc->cursor_bo != NULL);
6932+
if (intel_crtc->active)
6933+
intel_crtc_update_cursor(crtc, intel_crtc->cursor_bo != NULL);
69416934

69426935
return 0;
69436936
fail_unpin:
@@ -6956,7 +6949,8 @@ static int intel_crtc_cursor_move(struct drm_crtc *crtc, int x, int y)
69566949
intel_crtc->cursor_x = x;
69576950
intel_crtc->cursor_y = y;
69586951

6959-
intel_crtc_update_cursor(crtc, intel_crtc->cursor_bo != NULL);
6952+
if (intel_crtc->active)
6953+
intel_crtc_update_cursor(crtc, intel_crtc->cursor_bo != NULL);
69606954

69616955
return 0;
69626956
}
@@ -8205,9 +8199,10 @@ static void intel_dump_pipe_config(struct intel_crtc *crtc,
82058199
pipe_config->gmch_pfit.control,
82068200
pipe_config->gmch_pfit.pgm_ratios,
82078201
pipe_config->gmch_pfit.lvds_border_bits);
8208-
DRM_DEBUG_KMS("pch pfit: pos: 0x%08x, size: 0x%08x\n",
8202+
DRM_DEBUG_KMS("pch pfit: pos: 0x%08x, size: 0x%08x, %s\n",
82098203
pipe_config->pch_pfit.pos,
8210-
pipe_config->pch_pfit.size);
8204+
pipe_config->pch_pfit.size,
8205+
pipe_config->pch_pfit.enabled ? "enabled" : "disabled");
82118206
DRM_DEBUG_KMS("ips: %i\n", pipe_config->ips_enabled);
82128207
}
82138208

@@ -8603,8 +8598,11 @@ intel_pipe_config_compare(struct drm_device *dev,
86038598
if (INTEL_INFO(dev)->gen < 4)
86048599
PIPE_CONF_CHECK_I(gmch_pfit.pgm_ratios);
86058600
PIPE_CONF_CHECK_I(gmch_pfit.lvds_border_bits);
8606-
PIPE_CONF_CHECK_I(pch_pfit.pos);
8607-
PIPE_CONF_CHECK_I(pch_pfit.size);
8601+
PIPE_CONF_CHECK_I(pch_pfit.enabled);
8602+
if (current_config->pch_pfit.enabled) {
8603+
PIPE_CONF_CHECK_I(pch_pfit.pos);
8604+
PIPE_CONF_CHECK_I(pch_pfit.size);
8605+
}
86088606

86098607
PIPE_CONF_CHECK_I(ips_enabled);
86108608

drivers/gpu/drm/i915/intel_drv.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -280,6 +280,7 @@ struct intel_crtc_config {
280280
struct {
281281
u32 pos;
282282
u32 size;
283+
bool enabled;
283284
} pch_pfit;
284285

285286
/* FDI configuration, only valid if has_pch_encoder is set. */

drivers/gpu/drm/i915/intel_dvo.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -263,6 +263,8 @@ static bool intel_dvo_compute_config(struct intel_encoder *encoder,
263263
C(vtotal);
264264
C(clock);
265265
#undef C
266+
267+
drm_mode_set_crtcinfo(adjusted_mode, 0);
266268
}
267269

268270
if (intel_dvo->dev.dev_ops->mode_fixup)

drivers/gpu/drm/i915/intel_panel.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,7 @@ intel_pch_panel_fitting(struct intel_crtc *intel_crtc,
112112
done:
113113
pipe_config->pch_pfit.pos = (x << 16) | y;
114114
pipe_config->pch_pfit.size = (width << 16) | height;
115+
pipe_config->pch_pfit.enabled = pipe_config->pch_pfit.size != 0;
115116
}
116117

117118
static void

drivers/gpu/drm/i915/intel_pm.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2096,16 +2096,16 @@ static uint32_t ilk_pipe_pixel_rate(struct drm_device *dev,
20962096
struct drm_crtc *crtc)
20972097
{
20982098
struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
2099-
uint32_t pixel_rate, pfit_size;
2099+
uint32_t pixel_rate;
21002100

21012101
pixel_rate = intel_crtc->config.adjusted_mode.clock;
21022102

21032103
/* We only use IF-ID interlacing. If we ever use PF-ID we'll need to
21042104
* adjust the pixel_rate here. */
21052105

2106-
pfit_size = intel_crtc->config.pch_pfit.size;
2107-
if (pfit_size) {
2106+
if (intel_crtc->config.pch_pfit.enabled) {
21082107
uint64_t pipe_w, pipe_h, pfit_w, pfit_h;
2108+
uint32_t pfit_size = intel_crtc->config.pch_pfit.size;
21092109

21102110
pipe_w = intel_crtc->config.requested_mode.hdisplay;
21112111
pipe_h = intel_crtc->config.requested_mode.vdisplay;

0 commit comments

Comments
 (0)