Skip to content

Commit

Permalink
drm/i915: Allocate connector state together with the connectors
Browse files Browse the repository at this point in the history
Connector states were being allocated in intel_setup_outputs() in loop
over all connectors. That meant hot-added connectors would have a NULL
state. Since the change to use a struct drm_atomic_state for the legacy
modeset, connector states are necessary for the i915 driver to function
properly, so that would lead to oopses.

Broken by

commit 944b0c7
Author: Ander Conselvan de Oliveira <ander.conselvan.de.oliveira@intel.com>
Date:   Fri Mar 20 16:18:07 2015 +0200

    drm/i915: Copy the staged connector config to the legacy atomic state

v2: Fix test for intel_connector_init() success in lvds and sdvo (PRTS)

Signed-off-by: Ander Conselvan de Oliveira <ander.conselvan.de.oliveira@intel.com>
Reported-and-tested-by: Nicolas Kalkhof <nkalkhof@web.de>
Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
Signed-off-by: Jani Nikula <jani.nikula@intel.com>
  • Loading branch information
Ander Conselvan de Oliveira authored and Jani Nikula committed Apr 13, 2015
1 parent af8fcb9 commit 08d9bc9
Show file tree
Hide file tree
Showing 12 changed files with 64 additions and 46 deletions.
2 changes: 1 addition & 1 deletion drivers/gpu/drm/i915/intel_crt.c
Original file line number Diff line number Diff line change
Expand Up @@ -851,7 +851,7 @@ void intel_crt_init(struct drm_device *dev)
if (!crt)
return;

intel_connector = kzalloc(sizeof(*intel_connector), GFP_KERNEL);
intel_connector = intel_connector_alloc();
if (!intel_connector) {
kfree(crt);
return;
Expand Down
4 changes: 2 additions & 2 deletions drivers/gpu/drm/i915/intel_ddi.c
Original file line number Diff line number Diff line change
Expand Up @@ -2200,7 +2200,7 @@ 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);
connector = intel_connector_alloc();
if (!connector)
return NULL;

Expand All @@ -2219,7 +2219,7 @@ 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);
connector = intel_connector_alloc();
if (!connector)
return NULL;

Expand Down
62 changes: 28 additions & 34 deletions drivers/gpu/drm/i915/intel_display.c
Original file line number Diff line number Diff line change
Expand Up @@ -5636,6 +5636,34 @@ static void intel_connector_check_state(struct intel_connector *connector)
}
}

int intel_connector_init(struct intel_connector *connector)
{
struct drm_connector_state *connector_state;

connector_state = kzalloc(sizeof *connector_state, GFP_KERNEL);
if (!connector_state)
return -ENOMEM;

connector->base.state = connector_state;
return 0;
}

struct intel_connector *intel_connector_alloc(void)
{
struct intel_connector *connector;

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

if (intel_connector_init(connector) < 0) {
kfree(connector);
return NULL;
}

return connector;
}

/* Even simpler default implementation, if there's really no special case to
* consider. */
void intel_connector_dpms(struct drm_connector *connector, int mode)
Expand Down Expand Up @@ -13003,7 +13031,6 @@ static void intel_setup_outputs(struct drm_device *dev)
{
struct drm_i915_private *dev_priv = dev->dev_private;
struct intel_encoder *encoder;
struct drm_connector *connector;
bool dpd_is_edp = false;

intel_lvds_init(dev);
Expand Down Expand Up @@ -13139,39 +13166,6 @@ static void intel_setup_outputs(struct drm_device *dev)
if (SUPPORTS_TV(dev))
intel_tv_init(dev);

/*
* FIXME: We don't have full atomic support yet, but we want to be
* able to enable/test plane updates via the atomic interface in the
* meantime. However as soon as we flip DRIVER_ATOMIC on, the DRM core
* will take some atomic codepaths to lookup properties during
* drmModeGetConnector() that unconditionally dereference
* connector->state.
*
* We create a dummy connector state here for each connector to ensure
* the DRM core doesn't try to dereference a NULL connector->state.
* The actual connector properties will never be updated or contain
* useful information, but since we're doing this specifically for
* testing/debug of the plane operations (and only when a specific
* kernel module option is given), that shouldn't really matter.
*
* We are also relying on these states to convert the legacy mode set
* to use a drm_atomic_state struct. The states are kept consistent
* with actual state, so that it is safe to rely on that instead of
* the staged config.
*
* Once atomic support for crtc's + connectors lands, this loop should
* be removed since we'll be setting up real connector state, which
* will contain Intel-specific properties.
*/
list_for_each_entry(connector,
&dev->mode_config.connector_list,
head) {
if (!WARN_ON(connector->state)) {
connector->state = kzalloc(sizeof(*connector->state),
GFP_KERNEL);
}
}

intel_psr_init(dev);

for_each_intel_encoder(dev, encoder) {
Expand Down
2 changes: 1 addition & 1 deletion drivers/gpu/drm/i915/intel_dp.c
Original file line number Diff line number Diff line change
Expand Up @@ -5590,7 +5590,7 @@ intel_dp_init(struct drm_device *dev, int output_reg, enum port port)
if (!intel_dig_port)
return;

intel_connector = kzalloc(sizeof(*intel_connector), GFP_KERNEL);
intel_connector = intel_connector_alloc();
if (!intel_connector) {
kfree(intel_dig_port);
return;
Expand Down
2 changes: 1 addition & 1 deletion drivers/gpu/drm/i915/intel_dp_mst.c
Original file line number Diff line number Diff line change
Expand Up @@ -415,7 +415,7 @@ static struct drm_connector *intel_dp_add_mst_connector(struct drm_dp_mst_topolo
struct drm_connector *connector;
int i;

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

Expand Down
2 changes: 2 additions & 0 deletions drivers/gpu/drm/i915/intel_drv.h
Original file line number Diff line number Diff line change
Expand Up @@ -930,6 +930,8 @@ void intel_crtc_restore_mode(struct drm_crtc *crtc);
void intel_crtc_control(struct drm_crtc *crtc, bool enable);
void intel_crtc_update_dpms(struct drm_crtc *crtc);
void intel_encoder_destroy(struct drm_encoder *encoder);
int intel_connector_init(struct intel_connector *);
struct intel_connector *intel_connector_alloc(void);
void intel_connector_dpms(struct drm_connector *, int mode);
bool intel_connector_get_hw_state(struct intel_connector *connector);
void intel_modeset_check_state(struct drm_device *dev);
Expand Down
2 changes: 1 addition & 1 deletion drivers/gpu/drm/i915/intel_dsi.c
Original file line number Diff line number Diff line change
Expand Up @@ -1007,7 +1007,7 @@ void intel_dsi_init(struct drm_device *dev)
if (!intel_dsi)
return;

intel_connector = kzalloc(sizeof(*intel_connector), GFP_KERNEL);
intel_connector = intel_connector_alloc();
if (!intel_connector) {
kfree(intel_dsi);
return;
Expand Down
2 changes: 1 addition & 1 deletion drivers/gpu/drm/i915/intel_dvo.c
Original file line number Diff line number Diff line change
Expand Up @@ -469,7 +469,7 @@ void intel_dvo_init(struct drm_device *dev)
if (!intel_dvo)
return;

intel_connector = kzalloc(sizeof(*intel_connector), GFP_KERNEL);
intel_connector = intel_connector_alloc();
if (!intel_connector) {
kfree(intel_dvo);
return;
Expand Down
2 changes: 1 addition & 1 deletion drivers/gpu/drm/i915/intel_hdmi.c
Original file line number Diff line number Diff line change
Expand Up @@ -1750,7 +1750,7 @@ void intel_hdmi_init(struct drm_device *dev, int hdmi_reg, enum port port)
if (!intel_dig_port)
return;

intel_connector = kzalloc(sizeof(*intel_connector), GFP_KERNEL);
intel_connector = intel_connector_alloc();
if (!intel_connector) {
kfree(intel_dig_port);
return;
Expand Down
6 changes: 6 additions & 0 deletions drivers/gpu/drm/i915/intel_lvds.c
Original file line number Diff line number Diff line change
Expand Up @@ -946,6 +946,12 @@ void intel_lvds_init(struct drm_device *dev)
return;
}

if (intel_connector_init(&lvds_connector->base) < 0) {
kfree(lvds_connector);
kfree(lvds_encoder);
return;
}

lvds_encoder->attached_connector = lvds_connector;

intel_encoder = &lvds_encoder->base;
Expand Down
22 changes: 19 additions & 3 deletions drivers/gpu/drm/i915/intel_sdvo.c
Original file line number Diff line number Diff line change
Expand Up @@ -2426,6 +2426,22 @@ intel_sdvo_add_hdmi_properties(struct intel_sdvo *intel_sdvo,
}
}

static struct intel_sdvo_connector *intel_sdvo_connector_alloc(void)
{
struct intel_sdvo_connector *sdvo_connector;

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

if (intel_connector_init(&sdvo_connector->base) < 0) {
kfree(sdvo_connector);
return NULL;
}

return sdvo_connector;
}

static bool
intel_sdvo_dvi_init(struct intel_sdvo *intel_sdvo, int device)
{
Expand All @@ -2437,7 +2453,7 @@ intel_sdvo_dvi_init(struct intel_sdvo *intel_sdvo, int device)

DRM_DEBUG_KMS("initialising DVI device %d\n", device);

intel_sdvo_connector = kzalloc(sizeof(*intel_sdvo_connector), GFP_KERNEL);
intel_sdvo_connector = intel_sdvo_connector_alloc();
if (!intel_sdvo_connector)
return false;

Expand Down Expand Up @@ -2491,7 +2507,7 @@ intel_sdvo_tv_init(struct intel_sdvo *intel_sdvo, int type)

DRM_DEBUG_KMS("initialising TV type %d\n", type);

intel_sdvo_connector = kzalloc(sizeof(*intel_sdvo_connector), GFP_KERNEL);
intel_sdvo_connector = intel_sdvo_connector_alloc();
if (!intel_sdvo_connector)
return false;

Expand Down Expand Up @@ -2570,7 +2586,7 @@ intel_sdvo_lvds_init(struct intel_sdvo *intel_sdvo, int device)

DRM_DEBUG_KMS("initialising LVDS device %d\n", device);

intel_sdvo_connector = kzalloc(sizeof(*intel_sdvo_connector), GFP_KERNEL);
intel_sdvo_connector = intel_sdvo_connector_alloc();
if (!intel_sdvo_connector)
return false;

Expand Down
2 changes: 1 addition & 1 deletion drivers/gpu/drm/i915/intel_tv.c
Original file line number Diff line number Diff line change
Expand Up @@ -1621,7 +1621,7 @@ intel_tv_init(struct drm_device *dev)
return;
}

intel_connector = kzalloc(sizeof(*intel_connector), GFP_KERNEL);
intel_connector = intel_connector_alloc();
if (!intel_connector) {
kfree(intel_tv);
return;
Expand Down

0 comments on commit 08d9bc9

Please sign in to comment.