* [PATCH 1/3] drm/i915: Check that the plane points to the pipe's framebuffer before enabling
2011-04-19 20:32 Modesetting fixes for pre-ILK, 915GM especially Chris Wilson
@ 2011-04-19 20:32 ` Chris Wilson
2011-04-19 20:40 ` Jesse Barnes
2011-04-19 20:32 ` [PATCH 2/3] drm/i915: Attach a fb to the load-detect pipe Chris Wilson
2011-04-19 20:32 ` [PATCH 3/3] drm/i915: Only enable the plane after setting the fb base (pre-ILK) Chris Wilson
2 siblings, 1 reply; 8+ messages in thread
From: Chris Wilson @ 2011-04-19 20:32 UTC (permalink / raw)
To: intel-gfx
Knut Petersen reported a GPU hang when he left x11perf running
overnight. The error state quite clearly indicates that plane A was
enabled without being fully setup:
PGTBL_ER: 0x00000010
Display A: Invalid GTT PTE
Plane [0]:
CNTR: c1000000
STRIDE: 00000c80
SIZE: 03ff04ff
POS: 00000000
ADDR: 00000000
[That GTT offset on his system being pinned for the ringbuffer.]
This is a simple debugging patch to assert that this cannot be so!
References: https://bugs.freedesktop.org/show_bug.cgi?id=36246
Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
Cc: Jesse Barnes <jbarnes@virtuousgeek.org>
---
drivers/gpu/drm/i915/intel_display.c | 29 +++++++++++++++++++++++++++++
1 files changed, 29 insertions(+), 0 deletions(-)
diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
index 73cec21..b7d63a5 100644
--- a/drivers/gpu/drm/i915/intel_display.c
+++ b/drivers/gpu/drm/i915/intel_display.c
@@ -1560,6 +1560,34 @@ static void intel_disable_pipe(struct drm_i915_private *dev_priv,
intel_wait_for_pipe_off(dev_priv->dev, pipe);
}
+/* Check that the display plane points to the pipe's framebuffer. */
+static void assert_fb_bound_to_plane(struct drm_i915_private *dev_priv,
+ enum pipe pipe, enum plane plane)
+{
+ struct drm_crtc *crtc;
+ struct intel_framebuffer *intel_fb;
+ u32 val, base, size;
+
+ crtc = intel_get_crtc_for_pipe(dev_priv->dev, pipe);
+ if (WARN(crtc->fb == NULL,
+ "no framebuffer attached to pipe %c\n",
+ pipe_name(pipe)))
+ return;
+
+ intel_fb = to_intel_framebuffer(crtc->fb);
+ base = intel_fb->obj->gtt_offset;
+ size = intel_fb->obj->base.size;
+
+ if (dev_priv->info->gen >= 4)
+ val = I915_READ(DSPSURF(plane));
+ else
+ val = I915_READ(DSPADDR(plane));
+ WARN(val < base || val >= base + size,
+ "mismatching framebuffer for plane %c attached to pipe %c, expected %x-%x found %x\n",
+ plane_name(plane), pipe_name(pipe),
+ base, base + size, val);
+}
+
/**
* intel_enable_plane - enable a display plane on a given pipe
* @dev_priv: i915 private structure
@@ -1576,6 +1604,7 @@ static void intel_enable_plane(struct drm_i915_private *dev_priv,
/* If the pipe isn't enabled, we can't pump pixels and may hang */
assert_pipe_enabled(dev_priv, pipe);
+ assert_fb_bound_to_plane(dev_priv, pipe, plane);
reg = DSPCNTR(plane);
val = I915_READ(reg);
--
1.7.4.1
^ permalink raw reply related [flat|nested] 8+ messages in thread
* [PATCH 2/3] drm/i915: Attach a fb to the load-detect pipe
2011-04-19 20:32 Modesetting fixes for pre-ILK, 915GM especially Chris Wilson
2011-04-19 20:32 ` [PATCH 1/3] drm/i915: Check that the plane points to the pipe's framebuffer before enabling Chris Wilson
@ 2011-04-19 20:32 ` Chris Wilson
2011-04-19 21:26 ` Keith Packard
2011-04-19 20:32 ` [PATCH 3/3] drm/i915: Only enable the plane after setting the fb base (pre-ILK) Chris Wilson
2 siblings, 1 reply; 8+ messages in thread
From: Chris Wilson @ 2011-04-19 20:32 UTC (permalink / raw)
To: intel-gfx
We need to ensure that we feed valid memory into the display plane
attached to the pipe when switching the pipe on. Otherwise, the display
engine may read through an invalid PTE and so throw an PGTBL_ER
exception.
For bonus amusement value, we perform the first load detect before even
establishing our fbdev.
Reported-by: Knut Petersen <Knut_Petersen@t-online.de>
References: https://bugs.freedesktop.org/show_bug.cgi?id=36246
Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
---
drivers/gpu/drm/i915/intel_crt.c | 24 ++---
drivers/gpu/drm/i915/intel_display.c | 182 +++++++++++++++++++---------------
drivers/gpu/drm/i915/intel_drv.h | 25 +++--
drivers/gpu/drm/i915/intel_tv.c | 11 +--
4 files changed, 132 insertions(+), 110 deletions(-)
diff --git a/drivers/gpu/drm/i915/intel_crt.c b/drivers/gpu/drm/i915/intel_crt.c
index d03fc05..2a32405 100644
--- a/drivers/gpu/drm/i915/intel_crt.c
+++ b/drivers/gpu/drm/i915/intel_crt.c
@@ -305,13 +305,11 @@ static bool intel_crt_detect_ddc(struct drm_connector *connector)
}
static enum drm_connector_status
-intel_crt_load_detect(struct drm_crtc *crtc, struct intel_crt *crt)
+intel_crt_load_detect(struct intel_crt *crt)
{
- struct drm_encoder *encoder = &crt->base.base;
- struct drm_device *dev = encoder->dev;
+ struct drm_device *dev = crt->base.base.dev;
struct drm_i915_private *dev_priv = dev->dev_private;
- struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
- uint32_t pipe = intel_crtc->pipe;
+ uint32_t pipe = to_intel_crtc(crt->base.base.crtc)->pipe;
uint32_t save_bclrpat;
uint32_t save_vtotal;
uint32_t vtotal, vactive;
@@ -432,7 +430,6 @@ intel_crt_detect(struct drm_connector *connector, bool force)
struct drm_device *dev = connector->dev;
struct intel_crt *crt = intel_attached_crt(connector);
struct drm_crtc *crtc;
- int dpms_mode;
enum drm_connector_status status;
if (I915_HAS_HOTPLUG(dev)) {
@@ -454,17 +451,18 @@ intel_crt_detect(struct drm_connector *connector, bool force)
/* for pre-945g platforms use load detect */
crtc = crt->base.base.crtc;
if (crtc && crtc->enabled) {
- status = intel_crt_load_detect(crtc, crt);
+ status = intel_crt_load_detect(crt);
} else {
- crtc = intel_get_load_detect_pipe(&crt->base, connector,
- NULL, &dpms_mode);
- if (crtc) {
+ struct intel_load_detect_pipe tmp;
+
+ if (intel_get_load_detect_pipe(&crt->base,
+ connector, NULL,
+ &tmp)) {
if (intel_crt_detect_ddc(connector))
status = connector_status_connected;
else
- status = intel_crt_load_detect(crtc, crt);
- intel_release_load_detect_pipe(&crt->base,
- connector, dpms_mode);
+ status = intel_crt_load_detect(crt);
+ intel_release_load_detect_pipe(&tmp);
} else
status = connector_status_unknown;
}
diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
index b7d63a5..b9bb20d 100644
--- a/drivers/gpu/drm/i915/intel_display.c
+++ b/drivers/gpu/drm/i915/intel_display.c
@@ -5541,115 +5541,133 @@ static struct drm_display_mode load_detect_mode = {
704, 832, 0, 480, 489, 491, 520, 0, DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC),
};
-struct drm_crtc *intel_get_load_detect_pipe(struct intel_encoder *intel_encoder,
- struct drm_connector *connector,
- struct drm_display_mode *mode,
- int *dpms_mode)
+bool intel_get_load_detect_pipe(struct intel_encoder *encoder,
+ struct drm_connector *connector,
+ struct drm_display_mode *mode,
+ struct intel_load_detect_pipe *old)
{
- struct intel_crtc *intel_crtc;
- struct drm_crtc *possible_crtc;
- struct drm_crtc *supported_crtc =NULL;
- struct drm_encoder *encoder = &intel_encoder->base;
- struct drm_crtc *crtc = NULL;
- struct drm_device *dev = encoder->dev;
- struct drm_encoder_helper_funcs *encoder_funcs = encoder->helper_private;
- struct drm_crtc_helper_funcs *crtc_funcs;
- int i = -1;
-
- /*
- * Algorithm gets a little messy:
- * - if the connector already has an assigned crtc, use it (but make
- * sure it's on first)
- * - try to find the first unused crtc that can drive this connector,
- * and use that if we find one
- * - if there are no unused crtcs available, try to use the first
- * one we found that supports the connector
- */
+ struct drm_device *dev = encoder->base.dev;
+ struct drm_crtc *crtc;
+ struct drm_framebuffer *fb, *old_fb;
+ int x, y;
/* See if we already have a CRTC for this connector */
- if (encoder->crtc) {
- crtc = encoder->crtc;
- /* Make sure the crtc and connector are running */
- intel_crtc = to_intel_crtc(crtc);
- *dpms_mode = intel_crtc->dpms_mode;
- if (intel_crtc->dpms_mode != DRM_MODE_DPMS_ON) {
- crtc_funcs = crtc->helper_private;
- crtc_funcs->dpms(crtc, DRM_MODE_DPMS_ON);
- encoder_funcs->dpms(encoder, DRM_MODE_DPMS_ON);
- }
- return crtc;
- }
+ crtc = NULL;
+ if (encoder->base.crtc)
+ crtc = encoder->base.crtc;
- /* Find an unused one (if possible) */
- list_for_each_entry(possible_crtc, &dev->mode_config.crtc_list, head) {
- i++;
- if (!(encoder->possible_crtcs & (1 << i)))
- continue;
- if (!possible_crtc->enabled) {
- crtc = possible_crtc;
- break;
+ if (crtc == NULL) {
+ struct drm_crtc *pos;
+ int i = 0;
+
+ /* Find an unused one (if possible) */
+ list_for_each_entry(pos, &dev->mode_config.crtc_list, head) {
+ if (!(encoder->base.possible_crtcs & (1 << i++)))
+ continue;
+
+ if (!pos->enabled) {
+ crtc = pos;
+ break;
+ }
}
- if (!supported_crtc)
- supported_crtc = possible_crtc;
}
/*
* If we didn't find an unused CRTC, don't use any.
*/
- if (!crtc) {
- return NULL;
- }
+ if (crtc == NULL)
+ return false;
- encoder->crtc = crtc;
- connector->encoder = encoder;
- intel_encoder->load_detect_temp = true;
+ /* Reuse the existing crtc->fb unless absent */
+ old_fb = crtc->fb;
+ if (old_fb == NULL || !crtc->enabled) {
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ struct intel_fbdev *ifbdev = dev_priv->fbdev;
- intel_crtc = to_intel_crtc(crtc);
- *dpms_mode = intel_crtc->dpms_mode;
+ fb = &ifbdev->ifb.base;
+ x = y = 0;
- if (!crtc->enabled) {
if (!mode)
mode = &load_detect_mode;
- drm_crtc_helper_set_mode(crtc, mode, 0, 0, crtc->fb);
} else {
- if (intel_crtc->dpms_mode != DRM_MODE_DPMS_ON) {
- crtc_funcs = crtc->helper_private;
- crtc_funcs->dpms(crtc, DRM_MODE_DPMS_ON);
- }
+ fb = crtc->fb;
+ x = crtc->x;
+ y = crtc->y;
+ mode = &crtc->mode;
+ }
+
+ /* We may be called during ifbdev init, before the fb is bound */
+ if (fb == NULL || to_intel_framebuffer(fb)->obj == NULL)
+ return false;
+
+ /* Save the current configuration to be restored after load-detect */
+ old->connector = connector;
+ old->encoder = connector->encoder;
+ old->crtc = connector->encoder ? connector->encoder->crtc : NULL;
+ if (old->crtc) {
+ struct intel_crtc *intel_crtc;
- /* Add this connector to the crtc */
- encoder_funcs->mode_set(encoder, &crtc->mode, &crtc->mode);
- encoder_funcs->commit(encoder);
+ intel_crtc = to_intel_crtc(connector->encoder->crtc);
+ old->crtc = &intel_crtc->base;
+ old->dpms_mode = intel_crtc->dpms_mode;
+ old->fb = intel_crtc->base.fb;
+ old->mode = intel_crtc->base.mode;
+ old->x = intel_crtc->base.x;
+ old->y = intel_crtc->base.y;
}
+
+ /* Set the new connector->encoder->crtc->fb configuration */
+ crtc->fb = fb;
+ encoder->base.crtc = crtc;
+ connector->encoder = &encoder->base;
+
+ if (!drm_crtc_helper_set_mode(crtc, mode, x, y, old_fb)) {
+ DRM_DEBUG_KMS("failed to set mode for load-detect\n");
+
+ old->connector->encoder = old->encoder;
+ old->encoder->crtc = old->crtc;
+ old->crtc->fb = old->fb;
+
+ crtc->fb = old_fb;
+
+ drm_helper_disable_unused_functions(dev);
+ return false;
+ }
+ connector->dpms = DRM_MODE_DPMS_ON;
+
/* let the connector get through one full cycle before testing */
- intel_wait_for_vblank(dev, intel_crtc->pipe);
+ intel_wait_for_vblank(dev, to_intel_crtc(crtc)->pipe);
- return crtc;
+ return true;
}
-void intel_release_load_detect_pipe(struct intel_encoder *intel_encoder,
- struct drm_connector *connector, int dpms_mode)
+void intel_release_load_detect_pipe(struct intel_load_detect_pipe *old)
{
- struct drm_encoder *encoder = &intel_encoder->base;
- struct drm_device *dev = encoder->dev;
- struct drm_crtc *crtc = encoder->crtc;
- struct drm_encoder_helper_funcs *encoder_funcs = encoder->helper_private;
- struct drm_crtc_helper_funcs *crtc_funcs = crtc->helper_private;
+ struct drm_crtc *crtc = old->crtc;
+
+ old->connector->encoder = old->encoder;
+ if (old->encoder != NULL)
+ old->encoder->crtc = crtc;
+ if (crtc != NULL) {
+ struct drm_framebuffer *fb;
+
+ fb = crtc->fb;
+ crtc->fb = old->fb;
- if (intel_encoder->load_detect_temp) {
- encoder->crtc = NULL;
- connector->encoder = NULL;
- intel_encoder->load_detect_temp = false;
crtc->enabled = drm_helper_crtc_in_use(crtc);
- drm_helper_disable_unused_functions(dev);
+ if (crtc->enabled) {
+ if (!drm_crtc_helper_set_mode(crtc, &old->mode,
+ old->x, old->y, fb))
+ DRM_ERROR("failed to restore mode after load-detect\n");
+
+ old->connector = DRM_MODE_DPMS_ON;
+ if (old->dpms_mode != DRM_MODE_DPMS_ON)
+ drm_helper_connector_dpms(old->connector,
+ old->dpms_mode);
+ }
}
- /* Switch crtc and encoder back off if necessary */
- if (crtc->enabled && dpms_mode != DRM_MODE_DPMS_ON) {
- if (encoder->crtc == crtc)
- encoder_funcs->dpms(encoder, dpms_mode);
- crtc_funcs->dpms(crtc, dpms_mode);
- }
+ drm_helper_disable_unused_functions(crtc->dev);
}
/* Returns the clock of the currently programmed mode of the given pipe. */
diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
index aeb1b98..64cfc88 100644
--- a/drivers/gpu/drm/i915/intel_drv.h
+++ b/drivers/gpu/drm/i915/intel_drv.h
@@ -140,7 +140,6 @@ struct intel_fbdev {
struct intel_encoder {
struct drm_encoder base;
int type;
- bool load_detect_temp;
bool needs_tv_clock;
void (*hot_plug)(struct intel_encoder *);
int crtc_mask;
@@ -298,13 +297,23 @@ static inline void intel_wait_for_crtc_vblank_safe(struct drm_crtc *crtc)
msleep(50);
}
extern void intel_wait_for_pipe_off(struct drm_device *dev, int pipe);
-extern struct drm_crtc *intel_get_load_detect_pipe(struct intel_encoder *intel_encoder,
- struct drm_connector *connector,
- struct drm_display_mode *mode,
- int *dpms_mode);
-extern void intel_release_load_detect_pipe(struct intel_encoder *intel_encoder,
- struct drm_connector *connector,
- int dpms_mode);
+
+struct intel_load_detect_pipe {
+ struct drm_connector *connector;
+ struct drm_encoder *encoder;
+ struct drm_crtc *crtc;
+
+ int dpms_mode;
+ struct drm_framebuffer *fb;
+ struct drm_display_mode mode;
+ int x, y;
+};
+
+extern bool intel_get_load_detect_pipe(struct intel_encoder *intel_encoder,
+ struct drm_connector *connector,
+ struct drm_display_mode *mode,
+ struct intel_load_detect_pipe *tmp);
+extern void intel_release_load_detect_pipe(struct intel_load_detect_pipe *tmp);
extern struct drm_connector* intel_sdvo_find(struct drm_device *dev, int sdvoB);
extern int intel_sdvo_supports_hotplug(struct drm_connector *connector);
diff --git a/drivers/gpu/drm/i915/intel_tv.c b/drivers/gpu/drm/i915/intel_tv.c
index 3047a66..1352acf 100644
--- a/drivers/gpu/drm/i915/intel_tv.c
+++ b/drivers/gpu/drm/i915/intel_tv.c
@@ -1370,15 +1370,12 @@ intel_tv_detect(struct drm_connector *connector, bool force)
if (intel_tv->base.base.crtc && intel_tv->base.base.crtc->enabled) {
type = intel_tv_detect_type(intel_tv, connector);
} else if (force) {
- struct drm_crtc *crtc;
- int dpms_mode;
+ struct intel_load_detect_pipe tmp;
- crtc = intel_get_load_detect_pipe(&intel_tv->base, connector,
- &mode, &dpms_mode);
- if (crtc) {
+ if (intel_get_load_detect_pipe(&intel_tv->base, connector,
+ &mode, &tmp)) {
type = intel_tv_detect_type(intel_tv, connector);
- intel_release_load_detect_pipe(&intel_tv->base, connector,
- dpms_mode);
+ intel_release_load_detect_pipe(&tmp);
} else
return connector_status_unknown;
} else
--
1.7.4.1
^ permalink raw reply related [flat|nested] 8+ messages in thread