| From b76b6f1d0b67532fdd33934addae3c3e30e8f8c1 Mon Sep 17 00:00:00 2001 |
| From: Paulo Zanoni <paulo.r.zanoni@intel.com> |
| Date: Wed, 12 Jun 2013 17:27:27 -0300 |
| Subject: drm/i915: fix the "ghost eDP" encoder unwind path |
| |
| Because calling intel_dp_encoder_destroy inside |
| intel_edp_init_connector is just wrong. This is the initialization |
| path, so we should properly unwind all the initialization through the |
| whole caller stack. |
| |
| On the intel_dp_encoder_destroy function we do the following: |
| 1 - Call i2c_del_adapter |
| 2 - Call drm_encoder_cleanup |
| 3 - If edp: |
| 3.1 - Cancel panel_vdd_work |
| 3.2 - Call ironlake_panel_vdd_of_sync |
| 4 - Free the encoder |
| |
| And here is how we unwind each specific step: |
| 1 - We have intel_dp_init_connector -> intel_dp_i2c_init -> |
| i2c_dp_aux_add_bus -> i2c_add_adapter, so we call |
| i2c_del_dapter at intel_dp_init_connector |
| 2 - Call it in the same function that called drm_encoder_init |
| 3 - Call it in the same function that called INIT_DELAYED_WORK |
| 4 - Free it in the same function that allocated it |
| |
| Signed-off-by: Paulo Zanoni <paulo.r.zanoni@intel.com> |
| Reviewed-by: Zoltan Nyul <zoltan.nyul@intel.com> |
| Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch> |
| (cherry picked from commit 15b1d171d87e86366266255462e6b11d21b61c1c) |
| Signed-off-by: Darren Hart <dvhart@linux.intel.com> |
| --- |
| drivers/gpu/drm/i915/intel_ddi.c | 2 ++ |
| drivers/gpu/drm/i915/intel_dp.c | 13 +++++++++++-- |
| 2 files changed, 13 insertions(+), 2 deletions(-) |
| |
| --- a/drivers/gpu/drm/i915/intel_ddi.c |
| +++ b/drivers/gpu/drm/i915/intel_ddi.c |
| @@ -1367,6 +1367,8 @@ void intel_ddi_init(struct drm_device *d |
| intel_encoder->hot_plug = intel_ddi_hot_plug; |
| |
| if (!intel_dp_init_connector(intel_dig_port, dp_connector)) { |
| + drm_encoder_cleanup(encoder); |
| + kfree(intel_dig_port); |
| kfree(dp_connector); |
| return; |
| } |
| --- a/drivers/gpu/drm/i915/intel_dp.c |
| +++ b/drivers/gpu/drm/i915/intel_dp.c |
| @@ -3013,7 +3013,6 @@ static bool intel_edp_init_connector(str |
| } else { |
| /* if this fails, presume the device is a ghost */ |
| DRM_INFO("failed to retrieve link info, disabling eDP\n"); |
| - intel_dp_encoder_destroy(&intel_dig_port->base.base); |
| return false; |
| } |
| |
| @@ -3173,6 +3172,13 @@ intel_dp_init_connector(struct intel_dig |
| intel_dp_i2c_init(intel_dp, intel_connector, name); |
| |
| if (!intel_edp_init_connector(intel_dp, intel_connector)) { |
| + i2c_del_adapter(&intel_dp->adapter); |
| + if (is_edp(intel_dp)) { |
| + cancel_delayed_work_sync(&intel_dp->panel_vdd_work); |
| + mutex_lock(&dev->mode_config.mutex); |
| + ironlake_panel_vdd_off_sync(intel_dp); |
| + mutex_unlock(&dev->mode_config.mutex); |
| + } |
| drm_sysfs_connector_remove(connector); |
| drm_connector_cleanup(connector); |
| return false; |
| @@ -3235,6 +3241,9 @@ intel_dp_init(struct drm_device *dev, in |
| intel_encoder->cloneable = false; |
| intel_encoder->hot_plug = intel_dp_hot_plug; |
| |
| - if (!intel_dp_init_connector(intel_dig_port, intel_connector)) |
| + if (!intel_dp_init_connector(intel_dig_port, intel_connector)) { |
| + drm_encoder_cleanup(encoder); |
| + kfree(intel_dig_port); |
| kfree(intel_connector); |
| + } |
| } |