From 0391359ddf79b52bb7e7bb9ace08e34fb08b0e76 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Mon, 8 Dec 2014 22:55:22 +0100 Subject: drm/dp-mst: Remove branches before dropping the reference When we unplug a dp mst branch we unreference the entire tree from the root towards the leaves. Which is ok, since that's the way the pointers and so also the refcounts go. But when we drop the reference we must make sure that we remove the branches/ports from the lists/pointers before dropping the reference. Otherwise the get_validated functions will still return it instead of returning NULL (which indicates a potentially on-going unplug). The mst branch destroy gets this right for ports: First it deletes the port from the ports list, then it unrefs. But the ports destroy function gets it wrong: First it unrefs, then it drops the ref. Which means a zombie mst branch can still be validate with get_validated_mstb_ref when it shouldn't. Fix this. This should address a backtrace Dave dug out somewhere on unplug: [] drm_dp_mst_get_validated_mstb_ref_locked+0x92/0xa0 [drm_kms_helper] [] drm_dp_mst_get_validated_mstb_ref_locked+0x41/0xa0 [drm_kms_helper] [] drm_dp_get_validated_mstb_ref+0x3a/0x60 [drm_kms_helper] [] drm_dp_payload_send_msg.isra.14+0x2b/0x100 [drm_kms_helper] [] drm_dp_update_payload_part1+0x177/0x360 [drm_kms_helper] [] intel_mst_disable_dp+0x3e/0x80 [i915] [] haswell_crtc_disable+0x1cb/0x340 [i915] [] intel_crtc_control+0x49/0x100 [i915] [] intel_crtc_update_dpms+0x67/0x80 [i915] [] intel_connector_dpms+0x59/0x70 [i915] [] intel_dp_destroy_mst_connector+0x32/0xc0 [i915] [] drm_dp_destroy_port+0x6b/0xa0 [drm_kms_helper] [] drm_dp_destroy_mst_branch_device+0x108/0x130 [drm_kms_helper] [] drm_dp_port_teardown_pdt+0x3d/0x50 [drm_kms_helper] [] drm_dp_mst_handle_up_req+0x499/0x540 [drm_kms_helper] [] ? trace_hardirqs_on_caller+0x15d/0x200 [] drm_dp_mst_hpd_irq+0x53/0xa00 [drm_kms_helper] [] ? drm_dp_dpcd_read+0x1b/0x20 [drm_kms_helper] [] ? intel_dp_dpcd_read_wake+0x38/0x70 [i915] [] intel_dp_check_mst_status+0xb5/0x250 [i915] [] intel_dp_hpd_pulse+0x181/0x210 [i915] [] i915_digport_work_func+0x96/0x120 [i915] Signed-off-by: Daniel Vetter Cc: stable@vger.kernel.org Signed-off-by: Dave Airlie --- drivers/gpu/drm/drm_dp_mst_topology.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'drivers/gpu/drm/drm_dp_mst_topology.c') diff --git a/drivers/gpu/drm/drm_dp_mst_topology.c b/drivers/gpu/drm/drm_dp_mst_topology.c index 5682d7e9f1ec..9798bb79fe59 100644 --- a/drivers/gpu/drm/drm_dp_mst_topology.c +++ b/drivers/gpu/drm/drm_dp_mst_topology.c @@ -839,6 +839,8 @@ static void drm_dp_put_mst_branch_device(struct drm_dp_mst_branch *mstb) static void drm_dp_port_teardown_pdt(struct drm_dp_mst_port *port, int old_pdt) { + struct drm_dp_mst_branch *mstb; + switch (old_pdt) { case DP_PEER_DEVICE_DP_LEGACY_CONV: case DP_PEER_DEVICE_SST_SINK: @@ -846,8 +848,9 @@ static void drm_dp_port_teardown_pdt(struct drm_dp_mst_port *port, int old_pdt) drm_dp_mst_unregister_i2c_bus(&port->aux); break; case DP_PEER_DEVICE_MST_BRANCHING: - drm_dp_put_mst_branch_device(port->mstb); + mstb = port->mstb; port->mstb = NULL; + drm_dp_put_mst_branch_device(mstb); break; } } -- cgit From c6a0aed4d493936f61cd153db84531026705c94d Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Mon, 20 Oct 2014 16:28:02 +1000 Subject: drm/mst: cached EDID for logical ports (v2) Logical ports are never going to have EDID changes, they are used for the internal ports on MST monitors. We cache the EDIDs from these to save time at MST probe. v2: drop misplace tile property line, meant for other patch. Signed-off-by: Dave Airlie --- drivers/gpu/drm/drm_dp_mst_topology.c | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) (limited to 'drivers/gpu/drm/drm_dp_mst_topology.c') diff --git a/drivers/gpu/drm/drm_dp_mst_topology.c b/drivers/gpu/drm/drm_dp_mst_topology.c index 9798bb79fe59..0a9d3aad3cba 100644 --- a/drivers/gpu/drm/drm_dp_mst_topology.c +++ b/drivers/gpu/drm/drm_dp_mst_topology.c @@ -861,6 +861,8 @@ static void drm_dp_destroy_port(struct kref *kref) struct drm_dp_mst_topology_mgr *mgr = port->mgr; if (!port->input) { port->vcpi.num_slots = 0; + + kfree(port->cached_edid); if (port->connector) (*port->mgr->cbs->destroy_connector)(mgr, port->connector); drm_dp_port_teardown_pdt(port, port->pdt); @@ -1100,6 +1102,10 @@ static void drm_dp_add_port(struct drm_dp_mst_branch *mstb, char proppath[255]; build_mst_prop_path(port, mstb, proppath, sizeof(proppath)); port->connector = (*mstb->mgr->cbs->add_connector)(mstb->mgr, port, proppath); + + if (port->port_num >= 8) { + port->cached_edid = drm_get_edid(port->connector, &port->aux.ddc); + } } /* put reference to this port */ @@ -2170,7 +2176,8 @@ EXPORT_SYMBOL(drm_dp_mst_hpd_irq); * This returns the current connection state for a port. It validates the * port pointer still exists so the caller doesn't require a reference */ -enum drm_connector_status drm_dp_mst_detect_port(struct drm_dp_mst_topology_mgr *mgr, struct drm_dp_mst_port *port) +enum drm_connector_status drm_dp_mst_detect_port(struct drm_connector *connector, + struct drm_dp_mst_topology_mgr *mgr, struct drm_dp_mst_port *port) { enum drm_connector_status status = connector_status_disconnected; @@ -2189,6 +2196,10 @@ enum drm_connector_status drm_dp_mst_detect_port(struct drm_dp_mst_topology_mgr case DP_PEER_DEVICE_SST_SINK: status = connector_status_connected; + /* for logical ports - cache the EDID */ + if (port->port_num >= 8 && !port->cached_edid) { + port->cached_edid = drm_get_edid(connector, &port->aux.ddc); + } break; case DP_PEER_DEVICE_DP_LEGACY_CONV: if (port->ldps) @@ -2220,7 +2231,11 @@ struct edid *drm_dp_mst_get_edid(struct drm_connector *connector, struct drm_dp_ if (!port) return NULL; - edid = drm_get_edid(connector, &port->aux.ddc); + if (port->cached_edid) + edid = drm_edid_duplicate(port->cached_edid); + else + edid = drm_get_edid(connector, &port->aux.ddc); + drm_dp_put_port(port); return edid; } -- cgit From 6f134d7bb4347ab4c66ef123efb838fedb54186f Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Mon, 20 Oct 2014 16:30:50 +1000 Subject: drm/tile: expose the tile property to userspace (v3) This takes the tiling info from the connector and exposes it to userspace, as a blob object in a connector property. The contents of the blob is ABI. v2: add property + function documentation. v3: move property setup from previous patch. add boilerplate + fix long line (Daniel) Reviewed-by: Daniel Vetter Signed-off-by: Dave Airlie --- drivers/gpu/drm/drm_dp_mst_topology.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/gpu/drm/drm_dp_mst_topology.c') diff --git a/drivers/gpu/drm/drm_dp_mst_topology.c b/drivers/gpu/drm/drm_dp_mst_topology.c index 0a9d3aad3cba..9a5b68717ec8 100644 --- a/drivers/gpu/drm/drm_dp_mst_topology.c +++ b/drivers/gpu/drm/drm_dp_mst_topology.c @@ -2236,6 +2236,7 @@ struct edid *drm_dp_mst_get_edid(struct drm_connector *connector, struct drm_dp_ else edid = drm_get_edid(connector, &port->aux.ddc); + drm_mode_connector_set_tile_property(connector); drm_dp_put_port(port); return edid; } -- cgit