Skip to content

Commit

Permalink
drm/i915: don't leak dp_connector at intel_ddi_init
Browse files Browse the repository at this point in the history
Regression introduced by:
    commit 311a209
    Author: Paulo Zanoni <paulo.r.zanoni@intel.com>
        drm/i915: don't init DP or HDMI when not supported by DDI port

Since the commit above it is possible to have a DDI encoder that has
the HDMI connector but not the DP connector (in case the port doesn't
support DP). In this case, we must properly free the DP connector.

We just leak this once, so it's not a big deal.

Reported by kmemleak.

Signed-off-by: Paulo Zanoni <paulo.r.zanoni@intel.com>
Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
  • Loading branch information
Paulo Zanoni authored and Daniel Vetter committed Oct 10, 2013
1 parent 2cdfe6c commit 4a28ae5
Showing 1 changed file with 42 additions and 20 deletions.
62 changes: 42 additions & 20 deletions drivers/gpu/drm/i915/intel_ddi.c
Original file line number Diff line number Diff line change
Expand Up @@ -1345,6 +1345,41 @@ static const struct drm_encoder_funcs intel_ddi_funcs = {
.destroy = intel_ddi_destroy,
};

static struct intel_connector *
intel_ddi_init_dp_connector(struct intel_digital_port *intel_dig_port)
{
struct intel_connector *connector;
enum port port = intel_dig_port->port;

connector = kzalloc(sizeof(*connector), GFP_KERNEL);
if (!connector)
return NULL;

intel_dig_port->dp.output_reg = DDI_BUF_CTL(port);
if (!intel_dp_init_connector(intel_dig_port, connector)) {
kfree(connector);
return NULL;
}

return connector;
}

static struct intel_connector *
intel_ddi_init_hdmi_connector(struct intel_digital_port *intel_dig_port)
{
struct intel_connector *connector;
enum port port = intel_dig_port->port;

connector = kzalloc(sizeof(*connector), GFP_KERNEL);
if (!connector)
return NULL;

intel_dig_port->hdmi.hdmi_reg = DDI_BUF_CTL(port);
intel_hdmi_init_connector(intel_dig_port, connector);

return connector;
}

void intel_ddi_init(struct drm_device *dev, enum port port)
{
struct drm_i915_private *dev_priv = dev->dev_private;
Expand All @@ -1369,12 +1404,6 @@ void intel_ddi_init(struct drm_device *dev, enum port port)
if (!intel_dig_port)
return;

dp_connector = kzalloc(sizeof(*dp_connector), GFP_KERNEL);
if (!dp_connector) {
kfree(intel_dig_port);
return;
}

intel_encoder = &intel_dig_port->base;
encoder = &intel_encoder->base;

Expand All @@ -1394,29 +1423,22 @@ void intel_ddi_init(struct drm_device *dev, enum port port)
intel_dig_port->saved_port_bits = I915_READ(DDI_BUF_CTL(port)) &
(DDI_BUF_PORT_REVERSAL |
DDI_A_4_LANES);
intel_dig_port->dp.output_reg = DDI_BUF_CTL(port);

intel_encoder->type = INTEL_OUTPUT_UNKNOWN;
intel_encoder->crtc_mask = (1 << 0) | (1 << 1) | (1 << 2);
intel_encoder->cloneable = false;
intel_encoder->hot_plug = intel_ddi_hot_plug;

if (init_dp && !intel_dp_init_connector(intel_dig_port, dp_connector)) {
drm_encoder_cleanup(encoder);
kfree(intel_dig_port);
kfree(dp_connector);
return;
}
if (init_dp)
dp_connector = intel_ddi_init_dp_connector(intel_dig_port);

/* In theory we don't need the encoder->type check, but leave it just in
* case we have some really bad VBTs... */
if (intel_encoder->type != INTEL_OUTPUT_EDP && init_hdmi) {
hdmi_connector = kzalloc(sizeof(*hdmi_connector),
GFP_KERNEL);
if (!hdmi_connector)
return;
if (intel_encoder->type != INTEL_OUTPUT_EDP && init_hdmi)
hdmi_connector = intel_ddi_init_hdmi_connector(intel_dig_port);

intel_dig_port->hdmi.hdmi_reg = DDI_BUF_CTL(port);
intel_hdmi_init_connector(intel_dig_port, hdmi_connector);
if (!dp_connector && !hdmi_connector) {
drm_encoder_cleanup(encoder);
kfree(intel_dig_port);
}
}

0 comments on commit 4a28ae5

Please sign in to comment.